mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Render in parallel
This commit is contained in:
parent
bace9fb485
commit
95a57dfced
2 changed files with 238 additions and 146 deletions
|
@ -105,7 +105,6 @@ pub struct RenderTask<C> {
|
||||||
port: Receiver<Msg>,
|
port: Receiver<Msg>,
|
||||||
compositor: C,
|
compositor: C,
|
||||||
constellation_chan: ConstellationChan,
|
constellation_chan: ConstellationChan,
|
||||||
font_ctx: Box<FontContext>,
|
|
||||||
opts: Opts,
|
opts: Opts,
|
||||||
|
|
||||||
/// A channel to the profiler.
|
/// A channel to the profiler.
|
||||||
|
@ -114,9 +113,6 @@ pub struct RenderTask<C> {
|
||||||
/// The graphics context to use.
|
/// The graphics context to use.
|
||||||
graphics_context: GraphicsContext,
|
graphics_context: GraphicsContext,
|
||||||
|
|
||||||
/// The native graphics context.
|
|
||||||
native_graphics_context: Option<NativePaintingGraphicsContext>,
|
|
||||||
|
|
||||||
/// The layers to be rendered.
|
/// The layers to be rendered.
|
||||||
render_layers: SmallVec1<RenderLayer>,
|
render_layers: SmallVec1<RenderLayer>,
|
||||||
|
|
||||||
|
@ -126,8 +122,11 @@ pub struct RenderTask<C> {
|
||||||
/// A counter for epoch messages
|
/// A counter for epoch messages
|
||||||
epoch: Epoch,
|
epoch: Epoch,
|
||||||
|
|
||||||
/// A data structure to store unused LayerBuffers
|
/// Renderer workers
|
||||||
buffer_map: BufferMap<Box<LayerBuffer>>,
|
worker_txs: Vec<Sender<WorkerMsg>>,
|
||||||
|
|
||||||
|
/// The receiver on which we recieve rendered buffers from the workesr
|
||||||
|
worker_result_rx: Receiver<Box<LayerBuffer>>
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we implement this as a function, we get borrowck errors from borrowing
|
// If we implement this as a function, we get borrowck errors from borrowing
|
||||||
|
@ -138,6 +137,13 @@ macro_rules! native_graphics_context(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum WorkerMsg {
|
||||||
|
// This is tupled so all the data can be pulled out of the message as one variable
|
||||||
|
WorkerRender((BufferRequest, Arc<DisplayList>, uint, uint, f32)),
|
||||||
|
WorkerUnusedBuffer(Box<LayerBuffer>),
|
||||||
|
WorkerExit(Sender<()>)
|
||||||
|
}
|
||||||
|
|
||||||
fn initialize_layers<C:RenderListener>(
|
fn initialize_layers<C:RenderListener>(
|
||||||
compositor: &mut C,
|
compositor: &mut C,
|
||||||
pipeline_id: PipelineId,
|
pipeline_id: PipelineId,
|
||||||
|
@ -168,22 +174,17 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
||||||
send_on_failure(&mut builder, FailureMsg(failure_msg), c);
|
send_on_failure(&mut builder, FailureMsg(failure_msg), c);
|
||||||
builder.spawn(proc() {
|
builder.spawn(proc() {
|
||||||
|
|
||||||
{ // Ensures RenderTask and graphics context are destroyed before shutdown msg
|
{
|
||||||
let native_graphics_context = compositor.get_graphics_metadata().map(
|
|
||||||
|md| NativePaintingGraphicsContext::from_metadata(&md));
|
|
||||||
let cpu_painting = opts.cpu_painting;
|
let cpu_painting = opts.cpu_painting;
|
||||||
|
|
||||||
|
let (worker_result_tx, worker_result_rx) = channel();
|
||||||
|
|
||||||
// FIXME: rust/#5967
|
// FIXME: rust/#5967
|
||||||
let mut render_task = RenderTask {
|
let mut render_task = RenderTask {
|
||||||
id: id,
|
id: id,
|
||||||
port: port,
|
port: port,
|
||||||
compositor: compositor,
|
compositor: compositor,
|
||||||
constellation_chan: constellation_chan,
|
constellation_chan: constellation_chan,
|
||||||
font_ctx: box FontContext::new(FontContextInfo {
|
|
||||||
backend: opts.render_backend.clone(),
|
|
||||||
needs_font_list: false,
|
|
||||||
profiler_chan: profiler_chan.clone(),
|
|
||||||
}),
|
|
||||||
opts: opts,
|
opts: opts,
|
||||||
profiler_chan: profiler_chan,
|
profiler_chan: profiler_chan,
|
||||||
|
|
||||||
|
@ -193,22 +194,21 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
||||||
GpuGraphicsContext
|
GpuGraphicsContext
|
||||||
},
|
},
|
||||||
|
|
||||||
native_graphics_context: native_graphics_context,
|
|
||||||
|
|
||||||
render_layers: SmallVec1::new(),
|
render_layers: SmallVec1::new(),
|
||||||
|
|
||||||
paint_permission: false,
|
paint_permission: false,
|
||||||
epoch: Epoch(0),
|
epoch: Epoch(0),
|
||||||
buffer_map: BufferMap::new(10000000),
|
worker_txs: vec![],
|
||||||
|
worker_result_rx: worker_result_rx
|
||||||
};
|
};
|
||||||
|
|
||||||
render_task.start();
|
// Now spawn the workers. We're only doing this after creating
|
||||||
|
// the RenderTask object because spawn_workers was originally
|
||||||
|
// written to be run afterward, and was refactored like so.
|
||||||
|
let worker_txs = render_task.spawn_workers(worker_result_tx);
|
||||||
|
render_task.worker_txs = worker_txs;
|
||||||
|
|
||||||
// Destroy all the buffers.
|
render_task.start();
|
||||||
match render_task.native_graphics_context.as_ref() {
|
|
||||||
Some(ctx) => render_task.buffer_map.clear(ctx),
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!("render_task: shutdown_chan send");
|
debug!("render_task: shutdown_chan send");
|
||||||
|
@ -246,7 +246,7 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
||||||
}
|
}
|
||||||
UnusedBufferMsg(unused_buffers) => {
|
UnusedBufferMsg(unused_buffers) => {
|
||||||
for buffer in unused_buffers.move_iter().rev() {
|
for buffer in unused_buffers.move_iter().rev() {
|
||||||
self.buffer_map.insert(native_graphics_context!(self), buffer);
|
self.worker_txs.get(buffer.render_idx).send(WorkerUnusedBuffer(buffer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PaintPermissionGranted => {
|
PaintPermissionGranted => {
|
||||||
|
@ -267,6 +267,11 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
||||||
self.paint_permission = false;
|
self.paint_permission = false;
|
||||||
}
|
}
|
||||||
ExitMsg(response_ch) => {
|
ExitMsg(response_ch) => {
|
||||||
|
for worker_tx in self.worker_txs.iter() {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
worker_tx.send(WorkerExit(tx));
|
||||||
|
rx.recv();
|
||||||
|
}
|
||||||
debug!("render_task: exitmsg response send");
|
debug!("render_task: exitmsg response send");
|
||||||
response_ch.map(|ch| ch.send(()));
|
response_ch.map(|ch| ch.send(()));
|
||||||
break;
|
break;
|
||||||
|
@ -275,12 +280,205 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spawn_workers(&mut self, result_tx: Sender<Box<LayerBuffer>>) -> Vec<Sender<WorkerMsg>> {
|
||||||
|
// FIXME (rust/14707): This still isn't exposed publicly via std::rt??
|
||||||
|
// FIXME (rust/14704): Terrible name for this lint, which here is allowing
|
||||||
|
// Rust types, not C types
|
||||||
|
#[allow(ctypes)]
|
||||||
|
extern {
|
||||||
|
fn rust_get_num_cpus() -> uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
let num_workers = unsafe { rust_get_num_cpus() as uint };
|
||||||
|
let mut worker_chans = vec![];
|
||||||
|
for render_idx in range(0, num_workers) {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
let result_tx = result_tx.clone();
|
||||||
|
|
||||||
|
let opts = self.opts.clone();
|
||||||
|
let graphics_context = self.graphics_context;
|
||||||
|
let render_backend = self.opts.render_backend;
|
||||||
|
let native_graphics_context = self.compositor.get_graphics_metadata().map(
|
||||||
|
|md| NativePaintingGraphicsContext::from_metadata(&md));
|
||||||
|
let native_graphics_context = native_graphics_context.expect("need native graphics context");
|
||||||
|
let native_graphics_context = Some(native_graphics_context);
|
||||||
|
let font_ctx_info = FontContextInfo {
|
||||||
|
backend: self.opts.render_backend,
|
||||||
|
needs_font_list: false,
|
||||||
|
profiler_chan: self.profiler_chan.clone(),
|
||||||
|
};
|
||||||
|
let profiler_chan = self.profiler_chan.clone();
|
||||||
|
let buffer_map: BufferMap<Box<LayerBuffer>> = BufferMap::new(10000000);
|
||||||
|
|
||||||
|
spawn(proc() {
|
||||||
|
let mut buffer_map = buffer_map;
|
||||||
|
let mut native_graphics_context = native_graphics_context;
|
||||||
|
loop {
|
||||||
|
let render_msg: WorkerMsg = rx.recv();
|
||||||
|
let render_data = match render_msg {
|
||||||
|
WorkerRender(render_data) => render_data,
|
||||||
|
WorkerUnusedBuffer(buffer) => {
|
||||||
|
buffer_map.insert(native_graphics_context.get_ref(), buffer);
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
WorkerExit(tx) => {
|
||||||
|
// Cleanup and tell the RenderTask we're done
|
||||||
|
buffer_map.clear(native_graphics_context.get_ref());
|
||||||
|
drop(native_graphics_context.take_unwrap());
|
||||||
|
tx.send(());
|
||||||
|
break
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let (tile,
|
||||||
|
display_list,
|
||||||
|
layer_position_x,
|
||||||
|
layer_position_y,
|
||||||
|
scale) = render_data;
|
||||||
|
|
||||||
|
// Optimize the display list for this tile.
|
||||||
|
let page_rect_au = geometry::f32_rect_to_au_rect(tile.page_rect);
|
||||||
|
let optimizer = DisplayListOptimizer::new(display_list,
|
||||||
|
page_rect_au);
|
||||||
|
let display_list = optimizer.optimize();
|
||||||
|
|
||||||
|
let width = tile.screen_rect.size.width;
|
||||||
|
let height = tile.screen_rect.size.height;
|
||||||
|
|
||||||
|
let size = Size2D(width as i32, height as i32);
|
||||||
|
let draw_target = match graphics_context {
|
||||||
|
CpuGraphicsContext => {
|
||||||
|
DrawTarget::new(render_backend, size, B8G8R8A8)
|
||||||
|
}
|
||||||
|
GpuGraphicsContext => {
|
||||||
|
// FIXME(pcwalton): Cache the components of draw targets
|
||||||
|
// (texture color buffer, renderbuffers) instead of recreating them.
|
||||||
|
let draw_target =
|
||||||
|
DrawTarget::new_with_fbo(render_backend,
|
||||||
|
native_graphics_context.get_ref(),
|
||||||
|
size,
|
||||||
|
B8G8R8A8);
|
||||||
|
draw_target.make_current();
|
||||||
|
draw_target
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut font_ctx = box FontContext::new(font_ctx_info.clone());
|
||||||
|
// Build the render context.
|
||||||
|
let mut ctx = RenderContext {
|
||||||
|
draw_target: &draw_target,
|
||||||
|
font_ctx: &mut font_ctx,
|
||||||
|
opts: &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(-(tile.page_rect.origin.x) as AzFloat,
|
||||||
|
-(tile.page_rect.origin.y) as AzFloat);
|
||||||
|
let matrix = matrix.translate(-(layer_position_x as AzFloat),
|
||||||
|
-(layer_position_y as AzFloat));
|
||||||
|
|
||||||
|
ctx.draw_target.set_transform(&matrix);
|
||||||
|
|
||||||
|
// Clear the buffer.
|
||||||
|
ctx.clear();
|
||||||
|
|
||||||
|
// Draw the display list.
|
||||||
|
profile(time::RenderingDrawingCategory, profiler_chan.clone(), || {
|
||||||
|
display_list.draw_into_context(&mut ctx);
|
||||||
|
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 graphics_context {
|
||||||
|
CpuGraphicsContext => {
|
||||||
|
let maybe_buffer = buffer_map.find(tile.screen_rect.size);
|
||||||
|
let buffer = match maybe_buffer {
|
||||||
|
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(
|
||||||
|
native_graphics_context.get_ref(),
|
||||||
|
Size2D(width as i32, height as i32),
|
||||||
|
width as i32 * 4);
|
||||||
|
native_surface.mark_wont_leak();
|
||||||
|
|
||||||
|
box LayerBuffer {
|
||||||
|
native_surface: native_surface,
|
||||||
|
rect: tile.page_rect,
|
||||||
|
screen_pos: tile.screen_rect,
|
||||||
|
resolution: scale,
|
||||||
|
stride: (width * 4) as uint,
|
||||||
|
render_idx: render_idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
draw_target.snapshot().get_data_surface().with_data(|data| {
|
||||||
|
buffer.native_surface.upload(native_graphics_context.get_ref(), 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();
|
||||||
|
|
||||||
|
box LayerBuffer {
|
||||||
|
native_surface: native_surface,
|
||||||
|
rect: tile.page_rect,
|
||||||
|
screen_pos: tile.screen_rect,
|
||||||
|
resolution: scale,
|
||||||
|
stride: (width * 4) as uint,
|
||||||
|
render_idx: render_idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
result_tx.send(buffer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
worker_chans.push(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
return worker_chans;
|
||||||
|
}
|
||||||
|
|
||||||
/// Renders one layer and sends the tiles back to the layer.
|
/// Renders one layer and sends the tiles back to the layer.
|
||||||
///
|
///
|
||||||
/// FIXME(pcwalton): We will probably want to eventually send all layers belonging to a page in
|
/// FIXME(pcwalton): We will probably want to eventually send all layers belonging to a page in
|
||||||
/// one transaction, to avoid the user seeing inconsistent states.
|
/// one transaction, to avoid the user seeing inconsistent states.
|
||||||
fn render(&mut self, tiles: Vec<BufferRequest>, scale: f32, layer_id: LayerId) {
|
fn render(&mut self, tiles: Vec<BufferRequest>, scale: f32, layer_id: LayerId) {
|
||||||
|
let mut tiles = Some(tiles);
|
||||||
time::profile(time::RenderingCategory, self.profiler_chan.clone(), || {
|
time::profile(time::RenderingCategory, self.profiler_chan.clone(), || {
|
||||||
|
let tiles = tiles.take_unwrap();
|
||||||
// FIXME: Try not to create a new array here.
|
// FIXME: Try not to create a new array here.
|
||||||
let mut new_buffers = vec!();
|
let mut new_buffers = vec!();
|
||||||
|
|
||||||
|
@ -292,132 +490,24 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
||||||
|
|
||||||
self.compositor.set_render_state(RenderingRenderState);
|
self.compositor.set_render_state(RenderingRenderState);
|
||||||
|
|
||||||
// Divide up the layer into tiles.
|
// Distribute the tiles to the workers
|
||||||
for tile in tiles.iter() {
|
let num_tiles = tiles.len();
|
||||||
// Optimize the display list for this tile.
|
let mut worker_idx = 0;
|
||||||
let page_rect_au = geometry::f32_rect_to_au_rect(tile.page_rect);
|
|
||||||
let optimizer = DisplayListOptimizer::new(render_layer.display_list.clone(),
|
|
||||||
page_rect_au);
|
|
||||||
let display_list = optimizer.optimize();
|
|
||||||
|
|
||||||
let width = tile.screen_rect.size.width;
|
for tile in tiles.move_iter() {
|
||||||
let height = tile.screen_rect.size.height;
|
|
||||||
|
|
||||||
let size = Size2D(width as i32, height as i32);
|
let display_list = render_layer.display_list.clone();
|
||||||
let draw_target = match self.graphics_context {
|
let layer_position_x = render_layer.position.origin.x;
|
||||||
CpuGraphicsContext => {
|
let layer_position_y = render_layer.position.origin.y;
|
||||||
DrawTarget::new(self.opts.render_backend, size, B8G8R8A8)
|
|
||||||
}
|
|
||||||
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,
|
|
||||||
native_graphics_context!(self),
|
|
||||||
size,
|
|
||||||
B8G8R8A8);
|
|
||||||
draw_target.make_current();
|
|
||||||
draw_target
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
self.worker_txs.get(worker_idx).send(WorkerRender((tile, display_list, layer_position_x, layer_position_y, scale)));
|
||||||
// Build the render context.
|
|
||||||
let mut ctx = RenderContext {
|
|
||||||
draw_target: &draw_target,
|
|
||||||
font_ctx: &mut self.font_ctx,
|
|
||||||
opts: &self.opts,
|
|
||||||
page_rect: tile.page_rect,
|
|
||||||
screen_rect: tile.screen_rect,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply the translation to render the tile we want.
|
// Round-robin the work
|
||||||
let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
|
worker_idx = (worker_idx + 1) % self.worker_txs.len();
|
||||||
let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
|
}
|
||||||
let matrix = matrix.translate(-(tile.page_rect.origin.x) as AzFloat,
|
|
||||||
-(tile.page_rect.origin.y) as AzFloat);
|
|
||||||
let matrix = matrix.translate(-(render_layer.position.origin.x as AzFloat),
|
|
||||||
-(render_layer.position.origin.y as AzFloat));
|
|
||||||
|
|
||||||
ctx.draw_target.set_transform(&matrix);
|
for _ in range(0, num_tiles) {
|
||||||
|
new_buffers.push(self.worker_result_rx.recv());
|
||||||
// Clear the buffer.
|
|
||||||
ctx.clear();
|
|
||||||
|
|
||||||
// Draw the display list.
|
|
||||||
profile(time::RenderingDrawingCategory, self.profiler_chan.clone(), || {
|
|
||||||
display_list.draw_into_context(&mut ctx);
|
|
||||||
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(
|
|
||||||
native_graphics_context!(self),
|
|
||||||
Size2D(width as i32, height as i32),
|
|
||||||
width as i32 * 4);
|
|
||||||
native_surface.mark_wont_leak();
|
|
||||||
|
|
||||||
box LayerBuffer {
|
|
||||||
native_surface: native_surface,
|
|
||||||
rect: tile.page_rect,
|
|
||||||
screen_pos: tile.screen_rect,
|
|
||||||
resolution: scale,
|
|
||||||
stride: (width * 4) as uint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
draw_target.snapshot().get_data_surface().with_data(|data| {
|
|
||||||
buffer.native_surface.upload(native_graphics_context!(self), 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();
|
|
||||||
|
|
||||||
box 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 = box LayerBufferSet {
|
let layer_buffer_set = box LayerBufferSet {
|
||||||
|
@ -436,4 +526,3 @@ impl<C:RenderListener + Send> RenderTask<C> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,9 @@ pub struct LayerBuffer {
|
||||||
|
|
||||||
/// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
|
/// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.
|
||||||
pub stride: uint,
|
pub stride: uint,
|
||||||
|
|
||||||
|
/// Used by the RenderTask to route buffers to the correct graphics context for recycling
|
||||||
|
pub render_idx: uint
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
|
/// A set of layer buffers. This is an atomic unit used to switch between the front and back
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue