From 7c029a322def27469a490b01870d95e944296546 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 25 Oct 2012 20:36:34 -0700 Subject: [PATCH] gfx: Implement tiled rendering --- src/servo/gfx/render_context.rs | 3 +- src/servo/gfx/render_layers.rs | 81 ++++++++++++++++++++++----------- src/servo/gfx/render_task.rs | 15 ++++-- src/servo/platform/osmain.rs | 17 ++++--- 4 files changed, 79 insertions(+), 37 deletions(-) diff --git a/src/servo/gfx/render_context.rs b/src/servo/gfx/render_context.rs index efa0db3f366..de864f5fa1c 100644 --- a/src/servo/gfx/render_context.rs +++ b/src/servo/gfx/render_context.rs @@ -78,7 +78,8 @@ impl RenderContext { fn clear(&self) { let pattern = ColorPattern(Color(1f as AzFloat, 1f as AzFloat, 1f as AzFloat, 1f as AzFloat)); - let rect = Rect(Point2D(0 as AzFloat, 0 as AzFloat), + let rect = Rect(Point2D(self.canvas.rect.origin.x as AzFloat, + self.canvas.rect.origin.y as AzFloat), Size2D(self.canvas.rect.size.width as AzFloat, self.canvas.rect.size.height as AzFloat)); self.canvas.draw_target.fill_rect(&rect, &pattern); diff --git a/src/servo/gfx/render_layers.rs b/src/servo/gfx/render_layers.rs index 0ff1f639dc5..21979a56a1d 100644 --- a/src/servo/gfx/render_layers.rs +++ b/src/servo/gfx/render_layers.rs @@ -11,6 +11,8 @@ use geom::point::Point2D; use geom::rect::Rect; use geom::size::Size2D; +const TILE_SIZE: uint = 512; + pub struct RenderLayer { display_list: DisplayList, size: Size2D @@ -24,36 +26,61 @@ pub fn render_layers(layer: &RenderLayer, buffer_set: LayerBufferSet, f: &fn(layer: &RenderLayer, buffer: &LayerBuffer) -> bool) -> LayerBufferSet { let mut buffers = match move buffer_set { LayerBufferSet { buffers: move b } => move b }; - let mut buffer = buffers.pop(); - if buffer.rect.size != layer.size { - // Create a new buffer. - // Round the width up the nearest 32 pixels for DMA on the Mac. - let mut stride = layer.size.width; - if stride % 32 != 0 { - stride = (stride & !(32 - 1)) + 32; + // FIXME: Try not to create a new array here. + let new_buffers = dvec::DVec(); + + // Divide up the layer into tiles. + let mut y = 0; + while y < layer.size.height { + let mut x = 0; + while x < layer.size.width { + // Figure out the dimension of this tile. + let right = uint::min(x + TILE_SIZE, layer.size.width); + let bottom = uint::min(y + TILE_SIZE, layer.size.height); + let width = right - x; + let height = bottom - y; + + // Round the width up the nearest 32 pixels for DMA on the Mac. + let mut stride = width; + if stride % 32 != 0 { + stride = (stride & !(32 - 1)) + 32; + } + assert stride % 32 == 0; + assert stride >= width; + + let tile_rect = Rect(Point2D(x, y), Size2D(width, height)); + + let buffer; + // FIXME: Try harder to search for a matching tile. + // FIXME: Don't use shift; it's bad for perf. Maybe reverse and pop. + if buffers.len() != 0 && buffers[0].rect == tile_rect { + debug!("reusing tile, (%u, %u)", x, y); + buffer = buffers.shift(); + } else { + // Create a new buffer. + debug!("creating tile, (%u, %u)", x, y); + + let cairo_surface = ImageSurface( + CAIRO_FORMAT_RGB24, stride as c_int, height as c_int); + let draw_target = DrawTarget(&cairo_surface); + + buffer = LayerBuffer { + cairo_surface: move cairo_surface, + draw_target: move draw_target, + rect: tile_rect, + stride: stride + }; + } + + let _ = f(layer, &buffer); + new_buffers.push(move buffer); + + x += TILE_SIZE; } - assert stride % 32 == 0; - assert stride >= layer.size.width; - - let cairo_surface = ImageSurface(CAIRO_FORMAT_RGB24, - stride as c_int, - layer.size.height as c_int); - let draw_target = DrawTarget(&cairo_surface); - - /*let matrix: Matrix2D = Matrix2D::identity(); - let matrix = matrix.translate(&(-32 as AzFloat), &(0 as AzFloat)); - draw_target.set_transform(&matrix);*/ - - buffer = LayerBuffer { - cairo_surface: move cairo_surface, - draw_target: move draw_target, - rect: Rect(Point2D(0u, 0u), copy layer.size), - stride: stride - }; + y += TILE_SIZE; } - let _ = f(layer, &buffer); - return LayerBufferSet { buffers: ~[ move buffer ] }; + return LayerBufferSet { buffers: move dvec::unwrap(move new_buffers) }; } diff --git a/src/servo/gfx/render_task.rs b/src/servo/gfx/render_task.rs index 52ab43717e4..3eae337ddbd 100644 --- a/src/servo/gfx/render_task.rs +++ b/src/servo/gfx/render_task.rs @@ -1,18 +1,20 @@ use au = gfx::geometry; use au::Au; +use azure::AzFloat; use comm::*; use compositor::{Compositor, LayerBufferSet}; use dl = display_list; -use mod gfx::render_layers; -use render_layers::render_layers; +use geom::matrix2d::Matrix2D; use gfx::render_layers::RenderLayer; use libc::size_t; use libc::types::common::c99::uint16_t; +use mod gfx::render_layers; use pipes::{Port, Chan}; use platform::osmain; +use render_context::RenderContext; +use render_layers::render_layers; use std::cell::Cell; use text::font_cache::FontCache; -use render_context::RenderContext; pub enum Msg { RenderMsg(RenderLayer), @@ -91,7 +93,14 @@ impl Renderer { font_cache: self.font_cache }; + // Apply the translation to render the tile we want. + let matrix: Matrix2D = Matrix2D::identity(); + let matrix = matrix.translate(&-(layer_buffer.rect.origin.x as AzFloat), + &-(layer_buffer.rect.origin.y as AzFloat)); + layer_buffer.draw_target.set_transform(&matrix); + ctx.clear(); + render_layer.display_list.draw_into_context(&ctx); }; diff --git a/src/servo/platform/osmain.rs b/src/servo/platform/osmain.rs index b4c220e9e97..44fc18389ee 100644 --- a/src/servo/platform/osmain.rs +++ b/src/servo/platform/osmain.rs @@ -116,7 +116,7 @@ fn mainloop(mode: Mode, po: comm::Port, dom_event_chan: pipes::SharedChan key_handlers.push(move key_ch), @@ -135,8 +135,12 @@ fn mainloop(mode: Mode, po: comm::Port, dom_event_chan: pipes::SharedChan, dom_event_chan: pipes::SharedChan { + debug!("osmain: adding new image layer"); image_layer = @layers::layers::ImageLayer(image); root_layer.add_child(layers::layers::ImageLayerKind(image_layer)); None @@ -191,7 +196,7 @@ fn mainloop(mode: Mode, po: comm::Port, dom_event_chan: pipes::SharedChan, dom_event_chan: pipes::SharedChan) { } fn return_surface(surfaces: &SurfaceSet, layer_buffer_set: LayerBufferSet) { - #debug("osmain: returning surface %?", layer_buffer_set); + //#debug("osmain: returning surface %?", layer_buffer_set); // We have room for a return assert surfaces.front.have; assert !surfaces.back.have;