Implement dynamic resolution, messaging from compositor to renderer, delete unused texture layers

This commit is contained in:
eschweic 2013-06-20 17:37:47 -07:00
parent 0bb3fbdde0
commit d95988da80
5 changed files with 98 additions and 37 deletions

View file

@ -31,6 +31,7 @@ pub struct RenderLayer {
pub enum Msg<C> { pub enum Msg<C> {
AttachCompositorMsg(C), AttachCompositorMsg(C),
RenderMsg(RenderLayer), RenderMsg(RenderLayer),
ReRenderMsg(f32),
ExitMsg(Chan<()>), ExitMsg(Chan<()>),
} }
@ -82,6 +83,7 @@ pub fn create_render_task<C: RenderListener + Owned>(port: Port<Msg<C>>,
opts: opts_cell.take(), opts: opts_cell.take(),
profiler_chan: profiler_chan_copy, profiler_chan: profiler_chan_copy,
share_gl_context: share_gl_context, share_gl_context: share_gl_context,
render_layer: None,
}; };
renderer.start(); renderer.start();
@ -98,6 +100,9 @@ priv struct Renderer<C> {
profiler_chan: ProfilerChan, profiler_chan: ProfilerChan,
share_gl_context: AzGLContext, share_gl_context: AzGLContext,
/// The layer to be rendered
render_layer: Option<RenderLayer>,
} }
impl<C: RenderListener + Owned> Renderer<C> { impl<C: RenderListener + Owned> Renderer<C> {
@ -107,7 +112,13 @@ impl<C: RenderListener + Owned> Renderer<C> {
loop { loop {
match self.port.recv() { match self.port.recv() {
AttachCompositorMsg(compositor) => self.compositor = compositor, AttachCompositorMsg(compositor) => self.compositor = compositor,
RenderMsg(render_layer) => self.render(render_layer), RenderMsg(render_layer) => {
self.render_layer = Some(render_layer);
self.render(1.0);
}
ReRenderMsg(scale) => {
self.render(scale);
}
ExitMsg(response_ch) => { ExitMsg(response_ch) => {
response_ch.send(()); response_ch.send(());
break; break;
@ -116,12 +127,20 @@ impl<C: RenderListener + Owned> Renderer<C> {
} }
} }
fn render(&mut self, render_layer: RenderLayer) { fn render(&mut self, scale: f32) {
debug!("renderer: rendering"); debug!("renderer: rendering");
let render_layer;
match (self.render_layer) {
None => return,
Some(ref r_layer) => {
render_layer = r_layer;
}
}
self.compositor.set_render_state(RenderingRenderState); self.compositor.set_render_state(RenderingRenderState);
do profile(time::RenderingCategory, self.profiler_chan.clone()) { do profile(time::RenderingCategory, self.profiler_chan.clone()) {
let tile_size = self.opts.tile_size; let tile_size = self.opts.tile_size;
let scale = self.opts.zoom;
// FIXME: Try not to create a new array here. // FIXME: Try not to create a new array here.
let mut new_buffers = ~[]; let mut new_buffers = ~[];
@ -129,17 +148,17 @@ impl<C: RenderListener + Owned> Renderer<C> {
// Divide up the layer into tiles. // Divide up the layer into tiles.
do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) { do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
let mut y = 0; let mut y = 0;
while y < render_layer.size.height * scale { while y < (render_layer.size.height as f32 * scale).ceil() as uint {
let mut x = 0; let mut x = 0;
while x < render_layer.size.width * scale { while x < (render_layer.size.width as f32 * scale).ceil() as uint {
// Figure out the dimension of this tile. // Figure out the dimension of this tile.
let right = uint::min(x + tile_size, render_layer.size.width * scale); let right = uint::min(x + tile_size, (render_layer.size.width as f32 * scale).ceil() as uint);
let bottom = uint::min(y + tile_size, render_layer.size.height * scale); let bottom = uint::min(y + tile_size, (render_layer.size.height as f32 * scale).ceil() as uint);
let width = right - x; let width = right - x;
let height = bottom - y; let height = bottom - y;
let tile_rect = Rect(Point2D(x / scale, y / scale), Size2D(width, height)); //change this let tile_rect = Rect(Point2D(x as f32 / scale, y as f32 / scale), Size2D(width as f32, height as f32));
let screen_rect = Rect(Point2D(x, y), Size2D(width, height)); //change this let screen_rect = Rect(Point2D(x, y), Size2D(width, height));
let buffer = LayerBuffer { let buffer = LayerBuffer {
draw_target: DrawTarget::new_with_fbo(self.opts.render_backend, draw_target: DrawTarget::new_with_fbo(self.opts.render_backend,
@ -162,8 +181,8 @@ impl<C: RenderListener + Owned> Renderer<C> {
// Apply the translation to render the tile we want. // Apply the translation to render the tile we want.
let matrix: Matrix2D<AzFloat> = Matrix2D::identity(); let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
let matrix = matrix.scale(scale as AzFloat, scale as AzFloat); let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
let matrix = matrix.translate(-(buffer.rect.origin.x as f32) as AzFloat, let matrix = matrix.translate(-(buffer.rect.origin.x) as AzFloat,
-(buffer.rect.origin.y as f32) as AzFloat); -(buffer.rect.origin.y) as AzFloat);
ctx.canvas.draw_target.set_transform(&matrix); ctx.canvas.draw_target.set_transform(&matrix);

View file

@ -10,6 +10,7 @@ use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClick
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent}; use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
use servo_msg::compositor::{RenderListener, LayerBufferSet, RenderState}; use servo_msg::compositor::{RenderListener, LayerBufferSet, RenderState};
use servo_msg::compositor::{ReadyState, ScriptListener}; use servo_msg::compositor::{ReadyState, ScriptListener};
use gfx::render_task::{RenderChan, ReRenderMsg};
use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context}; use azure::azure_hl::{DataSourceSurface, DrawTarget, SourceSurfaceMethods, current_gl_context};
use azure::azure::AzGLContext; use azure::azure::AzGLContext;
@ -29,6 +30,7 @@ use servo_util::{time, url};
use servo_util::time::profile; use servo_util::time::profile;
use servo_util::time::ProfilerChan; use servo_util::time::ProfilerChan;
/// The implementation of the layers-based compositor. /// The implementation of the layers-based compositor.
#[deriving(Clone)] #[deriving(Clone)]
pub struct CompositorChan { pub struct CompositorChan {
@ -84,6 +86,8 @@ pub enum Msg {
ChangeRenderState(RenderState), ChangeRenderState(RenderState),
/// Sets the channel to the current layout task /// Sets the channel to the current layout task
SetLayoutChan(LayoutChan), SetLayoutChan(LayoutChan),
/// Sets the channel to the current renderer
SetRenderChan(RenderChan<CompositorChan>),
} }
/// Azure surface wrapping to work with the layers infrastructure. /// Azure surface wrapping to work with the layers infrastructure.
@ -166,6 +170,11 @@ impl CompositorTask {
// Keeps track of the current zoom factor // Keeps track of the current zoom factor
let world_zoom = @mut 1f32; let world_zoom = @mut 1f32;
// Keeps track of local zoom factor. Reset to 1 after a rerender event.
let local_zoom = @mut 1f32;
// Channel to the current renderer.
// FIXME: This probably shouldn't be stored like this.
let render_chan: @mut Option<RenderChan<CompositorChan>> = @mut None;
let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| { let update_layout_callbacks: @fn(LayoutChan) = |layout_chan: LayoutChan| {
let layout_chan_clone = layout_chan.clone(); let layout_chan_clone = layout_chan.clone();
@ -200,6 +209,16 @@ impl CompositorTask {
event = MouseDownEvent(button, world_mouse_point(layer_mouse_point)); event = MouseDownEvent(button, world_mouse_point(layer_mouse_point));
} }
WindowMouseUpEvent(button, layer_mouse_point) => { WindowMouseUpEvent(button, layer_mouse_point) => {
// rerender layer at new zoom level
// FIXME: this should happen when the user stops zooming, definitely not here
match *render_chan {
Some(ref r_chan) => {
r_chan.send(ReRenderMsg(*world_zoom));
}
None => {} // Nothing to do
}
event = MouseUpEvent(button, world_mouse_point(layer_mouse_point)); event = MouseUpEvent(button, world_mouse_point(layer_mouse_point));
} }
} }
@ -220,6 +239,10 @@ impl CompositorTask {
update_layout_callbacks(layout_chan); update_layout_callbacks(layout_chan);
} }
SetRenderChan(new_render_chan) => {
*render_chan = Some(new_render_chan);
}
GetGLContext(chan) => chan.send(current_gl_context()), GetGLContext(chan) => chan.send(current_gl_context()),
Paint(new_layer_buffer_set, new_size) => { Paint(new_layer_buffer_set, new_size) => {
@ -248,7 +271,7 @@ impl CompositorTask {
None => { None => {
debug!("osmain: adding new texture layer"); debug!("osmain: adding new texture layer");
texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager, texture_layer = @mut TextureLayer::new(@buffer.draw_target.clone() as @TextureManager,
buffer.rect.size); buffer.screen_pos.size);
root_layer.add_child(TextureLayerKind(texture_layer)); root_layer.add_child(TextureLayerKind(texture_layer));
None None
} }
@ -273,6 +296,21 @@ impl CompositorTask {
texture_layer.common.set_transform(transform); texture_layer.common.set_transform(transform);
} }
// Delete leftover layers
while current_layer_child.is_some() {
let trash = current_layer_child.get();
do current_layer_child.get().with_common |common| {
current_layer_child = common.next_sibling;
}
root_layer.remove_child(trash);
}
// Reset zoom
*local_zoom = 1f32;
root_layer.common.set_transform(identity().translate(-world_offset.x,
-world_offset.y,
0.0));
// TODO: Recycle the old buffers; send them back to the renderer to reuse if // TODO: Recycle the old buffers; send them back to the renderer to reuse if
// it wishes. // it wishes.
@ -304,24 +342,25 @@ impl CompositorTask {
// Clamp the world offset to the screen size. // Clamp the world offset to the screen size.
let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0); let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0);
world_offset.x = world_offset.x.clamp(&0.0, &max_x); world_offset.x = world_offset.x.clamp(&0.0, &max_x).round();
let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0); let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0);
world_offset.y = world_offset.y.clamp(&0.0, &max_y); world_offset.y = world_offset.y.clamp(&0.0, &max_y).round();
debug!("compositor: scrolled to %?", *world_offset); debug!("compositor: scrolled to %?", *world_offset);
let mut scroll_transform = identity(); let mut scroll_transform = identity();
scroll_transform = scroll_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x, scroll_transform = scroll_transform.translate(window_size.width as f32 / 2f32 * *local_zoom - world_offset.x,
window_size.height as f32 / 2f32 * *world_zoom - world_offset.y, window_size.height as f32 / 2f32 * *local_zoom - world_offset.y,
0.0); 0.0);
scroll_transform = scroll_transform.scale(*world_zoom, *world_zoom, 1f32); scroll_transform = scroll_transform.scale(*local_zoom, *local_zoom, 1f32);
scroll_transform = scroll_transform.translate(window_size.width as f32 / -2f32, scroll_transform = scroll_transform.translate(window_size.width as f32 / -2f32,
window_size.height as f32 / -2f32, window_size.height as f32 / -2f32,
0.0); 0.0);
root_layer.common.set_transform(scroll_transform); root_layer.common.set_transform(scroll_transform);
window.set_needs_display() window.set_needs_display()
} }
@ -333,6 +372,7 @@ impl CompositorTask {
// Determine zoom amount // Determine zoom amount
*world_zoom = (*world_zoom * magnification).max(&1.0); *world_zoom = (*world_zoom * magnification).max(&1.0);
*local_zoom = *local_zoom * *world_zoom/old_world_zoom;
// Update world offset // Update world offset
let corner_to_center_x = world_offset.x + window_size.width as f32 / 2f32; let corner_to_center_x = world_offset.x + window_size.width as f32 / 2f32;
@ -345,23 +385,22 @@ impl CompositorTask {
// Clamp to page bounds when zooming out // Clamp to page bounds when zooming out
let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0); let max_x = (page_size.width * *world_zoom - window_size.width as f32).max(&0.0);
world_offset.x = world_offset.x.clamp(&0.0, &max_x); world_offset.x = world_offset.x.clamp(&0.0, &max_x).round();
let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0); let max_y = (page_size.height * *world_zoom - window_size.height as f32).max(&0.0);
world_offset.y = world_offset.y.clamp(&0.0, &max_y); world_offset.y = world_offset.y.clamp(&0.0, &max_y).round();
// Apply transformations // Apply transformations
let mut zoom_transform = identity(); let mut zoom_transform = identity();
zoom_transform = zoom_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x, zoom_transform = zoom_transform.translate(window_size.width as f32 / 2f32 * *local_zoom - world_offset.x,
window_size.height as f32 / 2f32 * *world_zoom - world_offset.y, window_size.height as f32 / 2f32 * *local_zoom - world_offset.y,
0.0); 0.0);
zoom_transform = zoom_transform.scale(*world_zoom, *world_zoom, 1f32); zoom_transform = zoom_transform.scale(*local_zoom, *local_zoom, 1f32);
zoom_transform = zoom_transform.translate(window_size.width as f32 / -2f32, zoom_transform = zoom_transform.translate(window_size.width as f32 / -2f32,
window_size.height as f32 / -2f32, window_size.height as f32 / -2f32,
0.0); 0.0);
root_layer.common.set_transform(zoom_transform); root_layer.common.set_transform(zoom_transform);
window.set_needs_display() window.set_needs_display()
} }
// Enter the main event loop. // Enter the main event loop.

View file

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use compositing::{CompositorChan, SetLayoutChan}; use compositing::{CompositorChan, SetLayoutChan, SetRenderChan};
use layout::layout_task; use layout::layout_task;
use core::cell::Cell; use core::cell::Cell;
@ -62,6 +62,8 @@ impl Engine {
compositor_chan.send(SetLayoutChan(layout_chan.clone())); compositor_chan.send(SetLayoutChan(layout_chan.clone()));
compositor_chan.send(SetRenderChan(render_chan.clone()));
let compositor_chan = Cell(compositor_chan); let compositor_chan = Cell(compositor_chan);
let opts = Cell(copy *opts); let opts = Cell(copy *opts);

View file

@ -11,8 +11,9 @@ pub struct LayerBuffer {
draw_target: DrawTarget, draw_target: DrawTarget,
// The rect in the containing RenderLayer that this represents. // The rect in the containing RenderLayer that this represents.
rect: Rect<uint>, rect: Rect<f32>,
// The rect in pixels that will be drawn to the screen.
screen_pos: Rect<uint>, screen_pos: Rect<uint>,
// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH. // NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.

@ -1 +1 @@
Subproject commit e0898b8555261dc01485883486df13afbcbd4dd0 Subproject commit 1e1e359da32c9d0ddb4f93b505a658d669008426