aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/gfx/render_task.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/gfx/render_task.rs')
-rw-r--r--src/components/gfx/render_task.rs204
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);
}
}