diff --git a/layers.rs b/layers.rs index 7b9b98d..8a51180 100644 --- a/layers.rs +++ b/layers.rs @@ -7,24 +7,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use texturegl::Texture; -use tiling::TileGrid; +use tiling::{Tile, TileGrid}; use geom::matrix::{Matrix4, identity}; use geom::size::Size2D; use geom::rect::Rect; -use platform::surface::{NativePaintingGraphicsContext, NativeSurfaceMethods, NativeSurface}; +use platform::surface::{NativeSurfaceMethods, NativeSurface}; +use platform::surface::{NativeCompositingGraphicsContext, NativePaintingGraphicsContext}; use std::cell::{RefCell, RefMut}; use std::rc::Rc; -pub enum Format { - ARGB32Format, - RGB24Format -} - pub struct Layer { pub children: RefCell>>>, - pub tiles: RefCell>>, pub transform: RefCell>, pub bounds: RefCell>, pub tile_size: uint, @@ -36,7 +30,6 @@ impl Layer { pub fn new(bounds: Rect, tile_size: uint, data: T) -> Layer { Layer { children: RefCell::new(vec!()), - tiles: RefCell::new(vec!()), transform: RefCell::new(identity()), bounds: RefCell::new(bounds), tile_size: tile_size, @@ -55,27 +48,23 @@ impl Layer { pub fn get_tile_rects_page(&self, window: Rect, scale: f32) -> (Vec, Vec>) { let mut tile_grid = self.tile_grid.borrow_mut(); - (tile_grid.get_buffer_requests_in_rect(window, scale), tile_grid.take_unused_tiles()) + (tile_grid.get_buffer_requests_in_rect(window, scale), tile_grid.take_unused_buffers()) } pub fn resize(&self, new_size: Size2D) { self.bounds.borrow_mut().size = new_size; } - pub fn do_for_all_tiles(&self, f: |&Box|) { - self.tile_grid.borrow().do_for_all_tiles(f); - } - - pub fn add_tile_pixel(&self, tile: Box) { - self.tile_grid.borrow_mut().add_tile(tile); + pub fn add_buffer(&self, tile: Box) { + self.tile_grid.borrow_mut().add_buffer(tile); } - pub fn collect_unused_tiles(&self) -> Vec> { - self.tile_grid.borrow_mut().take_unused_tiles() + pub fn collect_unused_buffers(&self) -> Vec> { + self.tile_grid.borrow_mut().take_unused_buffers() } - pub fn collect_tiles(&self) -> Vec> { - self.tile_grid.borrow_mut().collect_tiles() + pub fn collect_buffers(&self) -> Vec> { + self.tile_grid.borrow_mut().collect_buffers() } pub fn flush_pending_buffer_requests(&self) -> (Vec, f32) { @@ -85,36 +74,13 @@ impl Layer { pub fn contents_changed(&self) { self.tile_grid.borrow_mut().contents_changed() } -} - -/// Whether a texture should be flipped. -#[deriving(PartialEq)] -pub enum Flip { - /// The texture should not be flipped. - NoFlip, - /// The texture should be flipped vertically. - VerticalFlip, -} -pub struct TextureLayer { - /// A handle to the GPU texture. - pub texture: Texture, - /// The size of the texture in pixels. - size: Size2D, - /// Whether this texture is flipped vertically. - pub flip: Flip, - - pub transform: Matrix4, -} + pub fn create_textures(&self, graphics_context: &NativeCompositingGraphicsContext) { + self.tile_grid.borrow_mut().create_textures(graphics_context); + } -impl TextureLayer { - pub fn new(texture: Texture, size: Size2D, flip: Flip, transform: Matrix4) -> TextureLayer { - TextureLayer { - texture: texture, - size: size, - flip: flip, - transform: transform, - } + pub fn do_for_all_tiles(&self, f: |&Tile|) { + self.tile_grid.borrow().do_for_all_tiles(f); } } @@ -153,60 +119,52 @@ pub struct LayerBuffer { /// NB: stride is in pixels, like OpenGL GL_UNPACK_ROW_LENGTH. pub stride: uint, -} - -/// A set of layer buffers. This is an atomic unit used to switch between the front and back -/// buffers. -pub struct LayerBufferSet { - pub buffers: Vec> -} -impl LayerBufferSet { - /// Notes all buffer surfaces will leak if not destroyed via a call to `destroy`. - pub fn mark_will_leak(&mut self) { - for buffer in self.buffers.mut_iter() { - buffer.native_surface.mark_will_leak() - } - } + /// Whether or not this buffer was painted with the CPU rasterization. + pub painted_with_cpu: bool, } -/// The interface used by the BufferMap to get info about layer buffers. -pub trait Tile { +impl LayerBuffer { /// Returns the amount of memory used by the tile - fn get_mem(&self) -> uint; - - /// Returns true if the tile is displayable at the given scale - fn is_valid(&self, f32) -> bool; - - /// Returns the Size2D of the tile - fn get_size_2d(&self) -> Size2D; - - /// Marks the layer buffer as not leaking. See comments on - /// `NativeSurfaceMethods::mark_wont_leak` for how this is used. - fn mark_wont_leak(&mut self); - - /// Destroys the layer buffer. Painting task only. - fn destroy(self, graphics_context: &NativePaintingGraphicsContext); -} - -impl Tile for Box { - fn get_mem(&self) -> uint { + pub fn get_mem(&self) -> uint { // This works for now, but in the future we may want a better heuristic self.screen_pos.size.width * self.screen_pos.size.height } - fn is_valid(&self, scale: f32) -> bool { + + /// Returns true if the tile is displayable at the given scale + pub fn is_valid(&self, scale: f32) -> bool { (self.resolution - scale).abs() < 1.0e-6 } - fn get_size_2d(&self) -> Size2D { + + /// Returns the Size2D of the tile + pub fn get_size_2d(&self) -> Size2D { self.screen_pos.size } - fn mark_wont_leak(&mut self) { + + /// Marks the layer buffer as not leaking. See comments on + /// `NativeSurfaceMethods::mark_wont_leak` for how this is used. + pub fn mark_wont_leak(&mut self) { self.native_surface.mark_wont_leak() } - fn destroy(self, graphics_context: &NativePaintingGraphicsContext) { + + /// Destroys the layer buffer. Painting task only. + pub fn destroy(self, graphics_context: &NativePaintingGraphicsContext) { let mut this = self; this.native_surface.destroy(graphics_context) } } +/// A set of layer buffers. This is an atomic unit used to switch between the front and back +/// buffers. +pub struct LayerBufferSet { + pub buffers: Vec> +} +impl LayerBufferSet { + /// Notes all buffer surfaces will leak if not destroyed via a call to `destroy`. + pub fn mark_will_leak(&mut self) { + for buffer in self.buffers.mut_iter() { + buffer.native_surface.mark_will_leak() + } + } +} diff --git a/rendergl.rs b/rendergl.rs index 29932f0..dcf9c5a 100755 --- a/rendergl.rs +++ b/rendergl.rs @@ -7,10 +7,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use layers::{Layer, TextureLayer, Flip, NoFlip, VerticalFlip}; +use layers::Layer; use layers; use scene::Scene; +use texturegl::{Flip, NoFlip, VerticalFlip}; use texturegl::{Texture, TextureTarget2D, TextureTargetRectangle}; +use tiling::Tile; use geom::matrix::{Matrix4, ortho}; use geom::size::Size2D; @@ -272,7 +274,6 @@ fn bind_texture_coordinate_buffer(render_context: RenderContext, flip: Flip) { pub fn bind_and_render_quad(render_context: RenderContext, texture: &Texture, - flip: Flip, transform: &Matrix4, scene_size: Size2D) { let program_id = match texture.target { @@ -311,7 +312,7 @@ pub fn bind_and_render_quad(render_context: RenderContext, 0, 0); - bind_texture_coordinate_buffer(render_context, flip); + bind_texture_coordinate_buffer(render_context, texture.flip); vertex_attrib_pointer_f32(render_context.program_2d.unwrap().texture_coord_attr as GLuint, 2, false, @@ -338,7 +339,7 @@ pub fn bind_and_render_quad(render_context: RenderContext, 0, 0); - bind_texture_coordinate_buffer(render_context, flip); + bind_texture_coordinate_buffer(render_context, texture.flip); vertex_attrib_pointer_f32(render_context.program_rectangle.unwrap().texture_coord_attr as GLuint, 2, @@ -369,22 +370,24 @@ impl Render for layers::Layer { scene_size: Size2D) { let origin = self.bounds.borrow().origin; let transform = transform.translate(origin.x, origin.y, 0.0).mul(&*self.transform.borrow()); - for tile in self.tiles.borrow().iter() { + + self.do_for_all_tiles(|tile: &Tile| { tile.render(render_context, transform, scene_size) - } + }); + for child in self.children().iter() { child.render(render_context, transform, scene_size) } } } -impl Render for layers::TextureLayer { +impl Render for Tile { fn render(&self, render_context: RenderContext, transform: Matrix4, scene_size: Size2D) { let transform = transform.mul(&self.transform); - bind_and_render_quad(render_context, &self.texture, self.flip, &transform, scene_size); + bind_and_render_quad(render_context, &self.texture, &transform, scene_size); } } diff --git a/texturegl.rs b/texturegl.rs index 53c779b..e7fd6d9 100644 --- a/texturegl.rs +++ b/texturegl.rs @@ -9,7 +9,7 @@ //! OpenGL-specific implementation of texturing. -use layers::{ARGB32Format, Format, RGB24Format}; +use layers::LayerBuffer; use geom::size::Size2D; use opengles::gl2::{BGRA, CLAMP_TO_EDGE, GLenum, GLint, GLsizei, GLuint, LINEAR, RGB, RGBA}; @@ -18,6 +18,11 @@ use opengles::gl2::{TEXTURE_WRAP_S, TEXTURE_WRAP_T, UNSIGNED_BYTE, UNSIGNED_INT_ use opengles::gl2; use std::num::Zero; +pub enum Format { + ARGB32Format, + RGB24Format +} + /// Image data used when uploading to a texture. pub struct TextureImageData<'a> { size: Size2D, @@ -49,11 +54,16 @@ impl TextureTarget { pub struct Texture { /// The OpenGL texture ID. id: GLuint, + /// The texture target. pub target: TextureTarget, + /// Whether this texture is weak. Weak textures will not be cleaned up by /// the destructor. weak: bool, + + // Whether or not this texture needs to be flipped upon display. + pub flip: Flip, } impl Drop for Texture { @@ -78,6 +88,7 @@ impl Zero for Texture { id: 0, target: TextureTarget2D, weak: true, + flip: NoFlip, } } fn is_zero(&self) -> bool { @@ -104,11 +115,48 @@ impl Texture { id: *gl2::gen_textures(1).get(0), target: target, weak: false, + flip: NoFlip, }; this.set_default_params(); this } + pub fn new_with_buffer(buffer: &Box) -> Texture { + let (flip, target) = + Texture::texture_flip_and_target(buffer.painted_with_cpu, buffer.screen_pos.size); + let mut texture = Texture::new(target); + texture.flip = flip; + return texture; + } + + // Returns whether the layer should be vertically flipped. + #[cfg(target_os="macos")] + fn texture_flip_and_target(cpu_painting: bool, size: Size2D) -> (Flip, TextureTarget) { + let flip = if cpu_painting { + NoFlip + } else { + VerticalFlip + }; + + (flip, TextureTargetRectangle(size)) + } + + #[cfg(target_os="android")] + fn texture_flip_and_target(cpu_painting: bool, _: Size2D) -> (Flip, TextureTarget) { + let flip = if cpu_painting { + NoFlip + } else { + VerticalFlip + }; + + (flip, TextureTarget2D) + } + + #[cfg(target_os="linux")] + fn texture_flip_and_target(_: bool, _: Size2D) -> (Flip, TextureTarget) { + (NoFlip, TextureTarget2D) + } + /// Creates a texture from an existing OpenGL texture. The texture will be deleted when this /// `Texture` object goes out of scope. pub fn adopt_native_texture(native_texture_id: GLuint, target: TextureTarget) -> Texture { @@ -116,6 +164,7 @@ impl Texture { id: native_texture_id, target: target, weak: false, + flip: NoFlip, }; this } @@ -127,6 +176,7 @@ impl Texture { id: native_texture_id, target: target, weak: true, + flip: NoFlip, }; this.set_default_params(); this @@ -186,3 +236,11 @@ impl Texture { } } +/// Whether a texture should be flipped. +#[deriving(PartialEq)] +pub enum Flip { + /// The texture should not be flipped. + NoFlip, + /// The texture should be flipped vertically. + VerticalFlip, +} diff --git a/tiling.rs b/tiling.rs index 760e673..6abe168 100644 --- a/tiling.rs +++ b/tiling.rs @@ -7,28 +7,81 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use layers::BufferRequest; +use layers::LayerBuffer; +use platform::surface::{NativeCompositingGraphicsContext, NativeSurfaceMethods}; +use texturegl::Texture; + +use geom::matrix::{Matrix4, identity}; use geom::point::Point2D; use geom::size::Size2D; use geom::rect::Rect; -use layers::BufferRequest; -use layers::LayerBuffer; use std::collections::hashmap::HashMap; use std::iter::range_inclusive; use std::mem; +use std::num::Zero; + +pub struct Tile { + /// The buffer displayed by this tile. + buffer: Option>, + + /// A handle to the GPU texture. + pub texture: Texture, + + /// The transformation applied to this tiles texture. + pub transform: Matrix4, +} + +impl Tile { + fn new() -> Tile { + Tile { + buffer: None, + texture: Zero::zero(), + transform: identity(), + } + } + + fn replace_buffer(&mut self, buffer: Box) -> Option> { + let old_buffer = self.buffer.take(); + self.buffer = Some(buffer); + return old_buffer; + } + + fn create_texture(&mut self, graphics_context: &NativeCompositingGraphicsContext) { + match self.buffer { + Some(ref buffer) => { + let size = Size2D(buffer.screen_pos.size.width as int, + buffer.screen_pos.size.height as int); + + // Make a new texture and bind the LayerBuffer's surface to it. + self.texture = Texture::new_with_buffer(buffer); + debug!("Tile: binding to native surface {:d}", + buffer.native_surface.get_id() as int); + buffer.native_surface.bind_to_texture(graphics_context, &self.texture, size); + + // Set the layer's transform. + let rect = buffer.rect; + let transform = identity().translate(rect.origin.x, rect.origin.y, 0.0); + self.transform = transform.scale(rect.size.width, rect.size.height, 1.0); + }, + None => {}, + } + } +} pub struct TileGrid { - pub tiles: HashMap, Box>, + pub tiles: HashMap, Tile>, // The size of tiles in this grid in device pixels. tile_size: uint, - // Tiles that are currently unused or outside the last-known visible rectangle. - unused_tiles: Vec>, + // Buffers that are currently unused. + unused_buffers: Vec>, // Whether or not there are pending buffer requests. - waiting_on_tiles : bool, + waiting_on_buffers : bool, - // Once we know that we are waiting for tiles, track any later buffer requests. + // Once we know that we are waiting for buffers, track any later buffer requests. // FIXME: Replace with a per-tile state which better tracks epoch transitions. pending_buffer_request: Option<(Rect, f32)>, } @@ -43,8 +96,8 @@ impl TileGrid { TileGrid { tiles: HashMap::new(), tile_size: tile_size, - unused_tiles: Vec::new(), - waiting_on_tiles: false, + unused_buffers: Vec::new(), + waiting_on_buffers: false, pending_buffer_request: None, } } @@ -61,10 +114,17 @@ impl TileGrid { Size2D(self.tile_size, self.tile_size)) } - pub fn take_unused_tiles(&mut self) -> Vec> { - let mut unused_tiles = Vec::new(); - mem::swap(&mut unused_tiles, &mut self.unused_tiles); - return unused_tiles; + pub fn take_unused_buffers(&mut self) -> Vec> { + let mut unused_buffers = Vec::new(); + mem::swap(&mut unused_buffers, &mut self.unused_buffers); + return unused_buffers; + } + + pub fn add_unused_buffer(&mut self, buffer: Option>) { + match buffer { + Some(buffer) => self.unused_buffers.push(buffer), + None => {}, + } } pub fn mark_tiles_outside_of_rect_as_unused(&mut self, rect: Rect) { @@ -77,14 +137,14 @@ impl TileGrid { for tile_index in tile_indexes_to_take.iter() { match self.tiles.pop(tile_index) { - Some(tile) => self.unused_tiles.push(tile), + Some(ref mut tile) => self.add_unused_buffer(tile.buffer.take()), None => {}, } } } pub fn get_buffer_requests_in_rect(&mut self, screen_rect: Rect, scale: f32) -> Vec { - if self.waiting_on_tiles { + if self.waiting_on_buffers { self.pending_buffer_request = Some((screen_rect, scale)); return Vec::new(); } @@ -103,7 +163,7 @@ impl TileGrid { } self.mark_tiles_outside_of_rect_as_unused(rect_in_layer_pixels); - self.waiting_on_tiles = !buffer_requests.is_empty(); + self.waiting_on_buffers = !buffer_requests.is_empty(); return buffer_requests; } @@ -114,35 +174,37 @@ impl TileGrid { (point.y / self.tile_size) as uint) } - pub fn add_tile(&mut self, tile: Box) { - self.waiting_on_tiles = false; - let index = self.get_tile_index_for_point(tile.screen_pos.origin.clone()); - match self.tiles.swap(index, tile) { - Some(tile) => self.unused_tiles.push(tile), - None => {}, - } + pub fn add_buffer(&mut self, buffer: Box) { + self.waiting_on_buffers = false; + let index = self.get_tile_index_for_point(buffer.screen_pos.origin.clone()); + let replaced_buffer = + self.tiles.find_or_insert_with(index, |_| Tile::new()).replace_buffer(buffer); + self.add_unused_buffer(replaced_buffer); } - pub fn do_for_all_tiles(&self, f: |&Box|) { + pub fn do_for_all_tiles(&self, f: |&Tile|) { for tile in self.tiles.values() { f(tile); } } - pub fn collect_tiles(&mut self) -> Vec> { - let mut collected_tiles = Vec::new(); + pub fn collect_buffers(&mut self) -> Vec> { + let mut collected_buffers = Vec::new(); - collected_tiles.push_all_move(self.take_unused_tiles()); + collected_buffers.push_all_move(self.take_unused_buffers()); // We need to replace the HashMap since it cannot be used again after move_iter(). let mut tile_map = HashMap::new(); mem::swap(&mut tile_map, &mut self.tiles); - for (_, tile) in tile_map.move_iter() { - collected_tiles.push(tile); + for (_, mut tile) in tile_map.move_iter() { + match tile.buffer.take() { + Some(buffer) => collected_buffers.push(buffer), + None => {}, + } } - return collected_tiles; + return collected_buffers; } pub fn flush_pending_buffer_requests(&mut self) -> (Vec, f32) { @@ -154,6 +216,12 @@ impl TileGrid { pub fn contents_changed(&mut self) { self.pending_buffer_request = None; - self.waiting_on_tiles = false; + self.waiting_on_buffers = false; + } + + pub fn create_textures(&mut self, graphics_context: &NativeCompositingGraphicsContext) { + for (_, ref mut tile) in self.tiles.mut_iter() { + tile.create_texture(graphics_context); + } } }