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> {
AttachCompositorMsg(C),
RenderMsg(RenderLayer),
ReRenderMsg(f32),
ExitMsg(Chan<()>),
}
@ -82,6 +83,7 @@ pub fn create_render_task<C: RenderListener + Owned>(port: Port<Msg<C>>,
opts: opts_cell.take(),
profiler_chan: profiler_chan_copy,
share_gl_context: share_gl_context,
render_layer: None,
};
renderer.start();
@ -98,6 +100,9 @@ priv struct Renderer<C> {
profiler_chan: ProfilerChan,
share_gl_context: AzGLContext,
/// The layer to be rendered
render_layer: Option<RenderLayer>,
}
impl<C: RenderListener + Owned> Renderer<C> {
@ -107,7 +112,13 @@ impl<C: RenderListener + Owned> Renderer<C> {
loop {
match self.port.recv() {
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) => {
response_ch.send(());
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");
let render_layer;
match (self.render_layer) {
None => return,
Some(ref r_layer) => {
render_layer = r_layer;
}
}
self.compositor.set_render_state(RenderingRenderState);
do profile(time::RenderingCategory, self.profiler_chan.clone()) {
let tile_size = self.opts.tile_size;
let scale = self.opts.zoom;
// FIXME: Try not to create a new array here.
let mut new_buffers = ~[];
@ -129,17 +148,17 @@ impl<C: RenderListener + Owned> Renderer<C> {
// Divide up the layer into tiles.
do time::profile(time::RenderingPrepBuffCategory, self.profiler_chan.clone()) {
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;
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.
let right = uint::min(x + tile_size, render_layer.size.width * scale);
let bottom = uint::min(y + tile_size, render_layer.size.height * 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 as f32 * scale).ceil() as uint);
let width = right - x;
let height = bottom - y;
let tile_rect = Rect(Point2D(x / scale, y / scale), Size2D(width, height)); //change this
let screen_rect = Rect(Point2D(x, y), 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));
let buffer = LayerBuffer {
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.
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 f32) as AzFloat,
-(buffer.rect.origin.y as f32) as AzFloat);
let matrix = matrix.translate(-(buffer.rect.origin.x) as AzFloat,
-(buffer.rect.origin.y) as AzFloat);
ctx.canvas.draw_target.set_transform(&matrix);

View file

@ -10,6 +10,7 @@ use windowing::{ApplicationMethods, WindowMethods, WindowMouseEvent, WindowClick
use windowing::{WindowMouseDownEvent, WindowMouseUpEvent};
use servo_msg::compositor::{RenderListener, LayerBufferSet, RenderState};
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::AzGLContext;
@ -29,6 +30,7 @@ use servo_util::{time, url};
use servo_util::time::profile;
use servo_util::time::ProfilerChan;
/// The implementation of the layers-based compositor.
#[deriving(Clone)]
pub struct CompositorChan {
@ -84,6 +86,8 @@ pub enum Msg {
ChangeRenderState(RenderState),
/// Sets the channel to the current layout task
SetLayoutChan(LayoutChan),
/// Sets the channel to the current renderer
SetRenderChan(RenderChan<CompositorChan>),
}
/// Azure surface wrapping to work with the layers infrastructure.
@ -166,6 +170,11 @@ impl CompositorTask {
// Keeps track of the current zoom factor
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 layout_chan_clone = layout_chan.clone();
@ -200,6 +209,16 @@ impl CompositorTask {
event = MouseDownEvent(button, world_mouse_point(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));
}
}
@ -220,6 +239,10 @@ impl CompositorTask {
update_layout_callbacks(layout_chan);
}
SetRenderChan(new_render_chan) => {
*render_chan = Some(new_render_chan);
}
GetGLContext(chan) => chan.send(current_gl_context()),
Paint(new_layer_buffer_set, new_size) => {
@ -248,7 +271,7 @@ impl CompositorTask {
None => {
debug!("osmain: adding new texture layer");
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));
None
}
@ -273,6 +296,21 @@ impl CompositorTask {
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
// it wishes.
@ -304,21 +342,22 @@ impl CompositorTask {
// Clamp the world offset to the screen size.
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);
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);
let mut scroll_transform = identity();
scroll_transform = scroll_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x,
window_size.height as f32 / 2f32 * *world_zoom - world_offset.y,
0.0);
scroll_transform = scroll_transform.scale(*world_zoom, *world_zoom, 1f32);
scroll_transform = scroll_transform.translate(window_size.width as f32 / 2f32 * *local_zoom - world_offset.x,
window_size.height as f32 / 2f32 * *local_zoom - world_offset.y,
0.0);
scroll_transform = scroll_transform.scale(*local_zoom, *local_zoom, 1f32);
scroll_transform = scroll_transform.translate(window_size.width as f32 / -2f32,
window_size.height as f32 / -2f32,
0.0);
window_size.height as f32 / -2f32,
0.0);
root_layer.common.set_transform(scroll_transform);
@ -333,6 +372,7 @@ impl CompositorTask {
// Determine zoom amount
*world_zoom = (*world_zoom * magnification).max(&1.0);
*local_zoom = *local_zoom * *world_zoom/old_world_zoom;
// Update world offset
let corner_to_center_x = world_offset.x + window_size.width as f32 / 2f32;
@ -345,17 +385,16 @@ impl CompositorTask {
// Clamp to page bounds when zooming out
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);
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
let mut zoom_transform = identity();
zoom_transform = zoom_transform.translate(window_size.width as f32 / 2f32 * *world_zoom - world_offset.x,
window_size.height as f32 / 2f32 * *world_zoom - world_offset.y,
zoom_transform = zoom_transform.translate(window_size.width as f32 / 2f32 * *local_zoom - world_offset.x,
window_size.height as f32 / 2f32 * *local_zoom - world_offset.y,
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,
window_size.height as f32 / -2f32,
0.0);

View file

@ -2,7 +2,7 @@
* 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/. */
use compositing::{CompositorChan, SetLayoutChan};
use compositing::{CompositorChan, SetLayoutChan, SetRenderChan};
use layout::layout_task;
use core::cell::Cell;
@ -62,6 +62,8 @@ impl Engine {
compositor_chan.send(SetLayoutChan(layout_chan.clone()));
compositor_chan.send(SetRenderChan(render_chan.clone()));
let compositor_chan = Cell(compositor_chan);
let opts = Cell(copy *opts);

View file

@ -11,8 +11,9 @@ pub struct LayerBuffer {
draw_target: DrawTarget,
// 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>,
// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH.

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