diff options
Diffstat (limited to 'src/components/gfx/render_task.rs')
-rw-r--r-- | src/components/gfx/render_task.rs | 204 |
1 files changed, 140 insertions, 64 deletions
diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs index 5cb8742d8b5..4f88465cf13 100644 --- a/src/components/gfx/render_task.rs +++ b/src/components/gfx/render_task.rs @@ -4,28 +4,31 @@ // The task that handles all rendering/painting. -use azure::{AzFloat, AzGLContext}; -use azure::azure_hl::{B8G8R8A8, DrawTarget}; -use display_list::DisplayList; -use servo_msg::compositor_msg::{RenderListener, IdleRenderState, RenderingRenderState, LayerBuffer}; -use servo_msg::compositor_msg::{LayerBufferSet, Epoch}; -use servo_msg::constellation_msg::{ConstellationChan, PipelineId, RendererReadyMsg}; -use font_context::FontContext; +use azure::azure_hl::{B8G8R8A8, DrawTarget, StolenGLResources}; +use azure::AzFloat; use geom::matrix2d::Matrix2D; -use geom::size::Size2D; use geom::rect::Rect; -use opts::Opts; -use render_context::RenderContext; +use geom::size::Size2D; +use layers::platform::surface::{NativePaintingGraphicsContext, NativeSurface}; +use layers::platform::surface::{NativeSurfaceMethods}; +use layers; +use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBuffer, LayerBufferSet}; +use servo_msg::compositor_msg::{RenderListener, RenderingRenderState}; +use servo_msg::constellation_msg::{ConstellationChan, PipelineId, RendererReadyMsg}; +use servo_msg::platform::surface::NativeSurfaceAzureMethods; +use servo_util::time::{ProfilerChan, profile}; +use servo_util::time; use std::comm::{Chan, Port, SharedChan}; use std::task::spawn_with; +use std::util; use extra::arc::Arc; -use servo_util::time::{ProfilerChan, profile}; -use servo_util::time; - use buffer_map::BufferMap; - +use display_list::DisplayList; +use font_context::FontContext; +use opts::Opts; +use render_context::RenderContext; pub struct RenderLayer<T> { display_list: Arc<DisplayList<T>>, @@ -82,6 +85,13 @@ impl<T: Send> GenericSmartChan<Msg<T>> for RenderChan<T> { } } +/// If we're using GPU rendering, this provides the metadata needed to create a GL context that +/// is compatible with that of the main thread. +enum GraphicsContext { + CpuGraphicsContext, + GpuGraphicsContext, +} + pub struct RenderTask<C,T> { id: PipelineId, port: Port<Msg<T>>, @@ -93,16 +103,21 @@ pub struct RenderTask<C,T> { /// A channel to the profiler. profiler_chan: ProfilerChan, - share_gl_context: AzGLContext, + /// The graphics context to use. + graphics_context: GraphicsContext, + + /// The native graphics context. + native_graphics_context: NativePaintingGraphicsContext, /// The layer to be rendered render_layer: Option<RenderLayer<T>>, + /// Permission to send paint messages to the compositor paint_permission: bool, - /// Cached copy of last layers rendered - last_paint_msg: Option<~LayerBufferSet>, + /// A counter for epoch messages epoch: Epoch, + /// A data structure to store unused LayerBuffers buffer_map: BufferMap<~LayerBuffer>, } @@ -114,11 +129,13 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { constellation_chan: ConstellationChan, opts: Opts, profiler_chan: ProfilerChan) { - do spawn_with((port, compositor, constellation_chan, opts, profiler_chan)) |(port, compositor, constellation_chan, opts, profiler_chan)| { - let share_gl_context = compositor.get_gl_context(); + let graphics_metadata = compositor.get_graphics_metadata(); + let cpu_painting = opts.cpu_painting; + let native_graphics_context = + NativePaintingGraphicsContext::from_metadata(&graphics_metadata); // FIXME: rust/#5967 let mut render_task = RenderTask { @@ -131,16 +148,26 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { profiler_chan.clone()), opts: opts, profiler_chan: profiler_chan, - share_gl_context: share_gl_context, + + graphics_context: if cpu_painting { + CpuGraphicsContext + } else { + GpuGraphicsContext + }, + + native_graphics_context: native_graphics_context, + render_layer: None, paint_permission: false, - last_paint_msg: None, epoch: Epoch(0), buffer_map: BufferMap::new(10000000), }; render_task.start(); + + // Destroy all the buffers. + render_task.buffer_map.clear(&render_task.native_graphics_context) } } @@ -157,7 +184,6 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { self.constellation_chan.send(RendererReadyMsg(self.id)); } self.render_layer = Some(render_layer); - self.last_paint_msg = None; } ReRenderMsg(tiles, scale, epoch) => { if self.epoch == epoch { @@ -169,7 +195,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { UnusedBufferMsg(unused_buffers) => { // move_rev_iter is more efficient for buffer in unused_buffers.move_rev_iter() { - self.buffer_map.insert(buffer); + self.buffer_map.insert(&self.native_graphics_context, buffer); } } PaintPermissionGranted => { @@ -181,16 +207,6 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { } None => {} } - // FIXME: This sends the last paint request, anticipating what - // the compositor will ask for. However, even if it sends the right - // tiles, the compositor still asks for them, and they will be - // re-rendered redundantly. - match self.last_paint_msg { - Some(ref layer_buffer_set) => { - self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch); - } - None => {} // Nothing to do - } } PaintPermissionRevoked => { self.paint_permission = false; @@ -221,7 +237,6 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { self.compositor.set_render_state(RenderingRenderState); do time::profile(time::RenderingCategory, self.profiler_chan.clone()) { - // FIXME: Try not to create a new array here. let mut new_buffers = ~[]; @@ -230,43 +245,42 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { for tile in tiles.iter() { let width = tile.screen_rect.size.width; let height = tile.screen_rect.size.height; - - let buffer = match self.buffer_map.find(tile.screen_rect.size) { - Some(buffer) => { - let mut buffer = buffer; - buffer.rect = tile.page_rect; - buffer.screen_pos = tile.screen_rect; - buffer.resolution = scale; - buffer + + let size = Size2D(width as i32, height as i32); + let draw_target = match self.graphics_context { + CpuGraphicsContext => { + DrawTarget::new(self.opts.render_backend, size, B8G8R8A8) } - None => ~LayerBuffer { - draw_target: DrawTarget::new_with_fbo(self.opts.render_backend, - self.share_gl_context, - Size2D(width as i32, height as i32), - B8G8R8A8), - rect: tile.page_rect, - screen_pos: tile.screen_rect, - resolution: scale, - stride: (width * 4) as uint + GpuGraphicsContext => { + // FIXME(pcwalton): Cache the components of draw targets + // (texture color buffer, renderbuffers) instead of recreating them. + let draw_target = + DrawTarget::new_with_fbo(self.opts.render_backend, + &self.native_graphics_context, + size, + B8G8R8A8); + draw_target.make_current(); + draw_target } }; - - + { // Build the render context. let ctx = RenderContext { - canvas: &buffer, + draw_target: &draw_target, font_ctx: self.font_ctx, - opts: &self.opts + opts: &self.opts, + page_rect: tile.page_rect, + screen_rect: tile.screen_rect, }; // Apply the translation to render the tile we want. let matrix: Matrix2D<AzFloat> = Matrix2D::identity(); let matrix = matrix.scale(scale as AzFloat, scale as AzFloat); - let matrix = matrix.translate(-(buffer.rect.origin.x) as AzFloat, - -(buffer.rect.origin.y) as AzFloat); + let matrix = matrix.translate(-(tile.page_rect.origin.x) as AzFloat, + -(tile.page_rect.origin.y) as AzFloat); - ctx.canvas.draw_target.set_transform(&matrix); + ctx.draw_target.set_transform(&matrix); // Clear the buffer. ctx.clear(); @@ -274,14 +288,78 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { // Draw the display list. do profile(time::RenderingDrawingCategory, self.profiler_chan.clone()) { render_layer.display_list.get().draw_into_context(&ctx); - ctx.canvas.draw_target.flush(); + ctx.draw_target.flush(); } } + + // Extract the texture from the draw target and place it into its slot in the + // buffer. If using CPU rendering, upload it first. + // + // FIXME(pcwalton): We should supply the texture and native surface *to* the + // draw target in GPU rendering mode, so that it doesn't have to recreate it. + let buffer = match self.graphics_context { + CpuGraphicsContext => { + let buffer = match self.buffer_map.find(tile.screen_rect.size) { + Some(buffer) => { + let mut buffer = buffer; + buffer.rect = tile.page_rect; + buffer.screen_pos = tile.screen_rect; + buffer.resolution = scale; + buffer.native_surface.mark_wont_leak(); + buffer + } + None => { + // Create an empty native surface. We mark it as not leaking + // in case it dies in transit to the compositor task. + let mut native_surface: NativeSurface = + layers::platform::surface::NativeSurfaceMethods::new( + &self.native_graphics_context, + Size2D(width as i32, height as i32), + width as i32 * 4); + native_surface.mark_wont_leak(); + + ~LayerBuffer { + native_surface: native_surface, + rect: tile.page_rect, + screen_pos: tile.screen_rect, + resolution: scale, + stride: (width * 4) as uint + } + } + }; + + do draw_target.snapshot().get_data_surface().with_data |data| { + buffer.native_surface.upload(&self.native_graphics_context, data); + debug!("RENDERER uploading to native surface %d", + buffer.native_surface.get_id() as int); + } + + buffer + } + GpuGraphicsContext => { + draw_target.make_current(); + let StolenGLResources { + surface: native_surface + } = draw_target.steal_gl_resources().unwrap(); + + // We mark the native surface as not leaking in case the surfaces + // die on their way to the compositor task. + let mut native_surface: NativeSurface = + NativeSurfaceAzureMethods::from_azure_surface(native_surface); + native_surface.mark_wont_leak(); + + ~LayerBuffer { + native_surface: native_surface, + rect: tile.page_rect, + screen_pos: tile.screen_rect, + resolution: scale, + stride: (width * 4) as uint + } + } + }; new_buffers.push(buffer); - } - } let layer_buffer_set = ~LayerBufferSet { @@ -290,12 +368,10 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> { debug!("render_task: returning surface"); if self.paint_permission { - self.compositor.paint(self.id, layer_buffer_set.clone(), self.epoch); + self.compositor.paint(self.id, layer_buffer_set, self.epoch); } else { self.constellation_chan.send(RendererReadyMsg(self.id)); } - debug!("caching paint msg"); - self.last_paint_msg = Some(layer_buffer_set); self.compositor.set_render_state(IdleRenderState); } } |