From b784ddb8cebe0711b8821d07f95dfe37d76c5a3d Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Tue, 22 Dec 2015 13:39:15 +1000 Subject: [PATCH] Refactoring in prep work for gpu clipping. This fixes the main performance regressions from the last round of refactoring. --- src/aabbtree.rs | 59 ++- src/batch.rs | 14 +- src/batch_builder.rs | 171 +++----- src/frame.rs | 987 +++++++++++++++++++++--------------------- src/internal_types.rs | 10 +- src/layer.rs | 8 +- src/node_compiler.rs | 206 ++++----- src/render_backend.rs | 15 +- src/renderer.rs | 3 +- src/resource_list.rs | 208 ++++----- 10 files changed, 825 insertions(+), 856 deletions(-) diff --git a/src/aabbtree.rs b/src/aabbtree.rs index 56b67d406f..3d1a9f713e 100644 --- a/src/aabbtree.rs +++ b/src/aabbtree.rs @@ -1,5 +1,5 @@ use euclid::{Point2D, Rect, Size2D}; -use internal_types::{CompiledNode, DrawListId, DrawListItemIndex}; +use internal_types::{CompiledNode, DrawListId, DrawListItemIndex, DrawListGroupId}; use resource_list::ResourceList; use util; @@ -11,6 +11,11 @@ pub struct DrawListIndexBuffer { pub indices: Vec, } +pub struct DrawListGroupSegment { + pub draw_list_group_id: DrawListGroupId, + pub index_buffers: Vec, +} + pub struct AABBTreeNode { pub split_rect: Rect, pub actual_rect: Rect, @@ -20,7 +25,7 @@ pub struct AABBTreeNode { pub is_visible: bool, - pub draw_lists: Vec, + pub draw_list_group_segments: Vec, pub resource_list: Option, pub compiled_node: Option, @@ -34,19 +39,36 @@ impl AABBTreeNode { children: None, is_visible: false, resource_list: None, - draw_lists: Vec::new(), + draw_list_group_segments: Vec::new(), compiled_node: None, } } #[inline] fn append_item(&mut self, + draw_list_group_id: DrawListGroupId, draw_list_id: DrawListId, item_index: DrawListItemIndex, rect: &Rect) { self.actual_rect = self.actual_rect.union(rect); - let need_new_list = match self.draw_lists.last_mut() { + let need_new_group = match self.draw_list_group_segments.last() { + Some(group) => { + group.draw_list_group_id != draw_list_group_id + } + None => { + true + } + }; + + if need_new_group { + self.draw_list_group_segments.push(DrawListGroupSegment { + draw_list_group_id: draw_list_group_id, + index_buffers: Vec::new(), + }) + } + + let need_new_list = match self.draw_list_group_segments.last().unwrap().index_buffers.last() { Some(draw_list) => { draw_list.draw_list_id != draw_list_id } @@ -56,19 +78,28 @@ impl AABBTreeNode { }; if need_new_list { - self.draw_lists.push(DrawListIndexBuffer { + self.draw_list_group_segments.last_mut().unwrap().index_buffers.push(DrawListIndexBuffer { draw_list_id: draw_list_id, indices: Vec::new(), }); } - self.draw_lists.last_mut().unwrap().indices.push(item_index); + self.draw_list_group_segments + .last_mut() + .unwrap() + .index_buffers + .last_mut() + .unwrap() + .indices + .push(item_index); } fn item_count(&self) -> usize { let mut count = 0; - for list in &self.draw_lists { - count += list.indices.len(); + for group in &self.draw_list_group_segments { + for list in &group.index_buffers { + count += list.indices.len(); + } } count } @@ -104,13 +135,13 @@ impl AABBTree { } let node = self.node(node_index); - println!("{}n={:?} sr={:?} ar={:?} c={:?} lists={} items={}", + println!("{}n={:?} sr={:?} ar={:?} c={:?} lists={} segments={}", indent, node_index, node.split_rect, node.actual_rect, node.children, - node.draw_lists.len(), + node.draw_list_group_segments.len(), node.item_count()); if let Some(child_index) = node.children { @@ -160,6 +191,7 @@ impl AABBTree { #[inline] pub fn insert(&mut self, rect: &Rect, + draw_list_group_id: DrawListGroupId, draw_list_id: DrawListId, item_index: DrawListItemIndex) { debug_assert!(self.work_node_indices.len() == 0); @@ -167,7 +199,10 @@ impl AABBTree { for node_index in self.work_node_indices.drain(..) { let NodeIndex(node_index) = node_index; let node = &mut self.nodes[node_index as usize]; - node.append_item(draw_list_id, item_index, rect); + node.append_item(draw_list_group_id, + draw_list_id, + item_index, + rect); } } @@ -216,7 +251,7 @@ impl AABBTree { let children = { let node = self.node_mut(node_index); if node.split_rect.intersects(rect) { - if node.draw_lists.len() > 0 && + if node.draw_list_group_segments.len() > 0 && node.actual_rect.intersects(rect) { debug_assert!(node.children.is_none()); node.is_visible = true; diff --git a/src/batch.rs b/src/batch.rs index 70654d2153..09397bc171 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -1,6 +1,5 @@ use device::{ProgramId, TextureId}; -use internal_types::{AxisDirection}; -use internal_types::{PackedVertex, PackedVertexForTextureCacheUpdate, Primitive}; +use internal_types::{AxisDirection, PackedVertex, PackedVertexForTextureCacheUpdate, Primitive}; use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; use std::u16; @@ -112,6 +111,7 @@ impl Batch { pub struct BatchBuilder<'a> { vertex_buffer: &'a mut VertexBuffer, batches: Vec, + current_matrix_index: u8, } impl<'a> BatchBuilder<'a> { @@ -119,6 +119,7 @@ impl<'a> BatchBuilder<'a> { BatchBuilder { vertex_buffer: vertex_buffer, batches: Vec::new(), + current_matrix_index: 0, } } @@ -126,8 +127,12 @@ impl<'a> BatchBuilder<'a> { self.batches } + pub fn next_draw_list(&mut self) { + debug_assert!((self.current_matrix_index as usize) < MAX_MATRICES_PER_BATCH); + self.current_matrix_index += 1; + } + pub fn add_draw_item(&mut self, - matrix_index: MatrixIndex, color_texture_id: TextureId, mask_texture_id: TextureId, primitive: Primitive, @@ -195,9 +200,8 @@ impl<'a> BatchBuilder<'a> { let tile_params_index = self.batches.last_mut().unwrap().add_draw_item(index_count, tile_params); - let MatrixIndex(matrix_index) = matrix_index; for vertex in vertices.iter_mut() { - vertex.matrix_index = matrix_index; + vertex.matrix_index = self.current_matrix_index; vertex.tile_params_index = tile_params_index; } diff --git a/src/batch_builder.rs b/src/batch_builder.rs index 05150635ba..35bb68c606 100644 --- a/src/batch_builder.rs +++ b/src/batch_builder.rs @@ -1,5 +1,5 @@ use app_units::Au; -use batch::{BatchBuilder, MatrixIndex, TileParams}; +use batch::{BatchBuilder, TileParams}; use clipper::{self, ClipBuffers, Polygon}; use device::TextureId; use euclid::{Rect, Point2D, Size2D}; @@ -27,15 +27,13 @@ const BORDER_DASH_SIZE: f32 = 3.0; impl<'a> BatchBuilder<'a> { #[inline] fn add_textured_rectangle(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, image_info: &TextureCacheItem, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, color: &ColorF) { - self.add_axis_aligned_gradient_with_texture(matrix_index, - rect, + self.add_axis_aligned_gradient_with_texture(rect, clip, image_info, resource_cache, @@ -45,14 +43,12 @@ impl<'a> BatchBuilder<'a> { #[inline] pub fn add_color_rectangle(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, color: &ColorF) { - self.add_axis_aligned_gradient(matrix_index, - rect, + self.add_axis_aligned_gradient(rect, clip, resource_cache, clip_buffers, @@ -60,7 +56,6 @@ impl<'a> BatchBuilder<'a> { } pub fn add_webgl_rectangle(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, resource_cache: &ResourceCache, @@ -95,8 +90,7 @@ impl<'a> BatchBuilder<'a> { let mask = mask_for_clip_region(resource_cache, &clip_region, false); let mut vertices = clip_region.make_packed_vertices_for_rect(mask); - self.add_draw_item(matrix_index, - texture_id, + self.add_draw_item(texture_id, mask.texture_id, Primitive::Rectangles, &mut vertices, @@ -105,7 +99,6 @@ impl<'a> BatchBuilder<'a> { } pub fn add_image(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, stretch_size: &Size2D, @@ -147,8 +140,7 @@ impl<'a> BatchBuilder<'a> { let mask = mask_for_clip_region(resource_cache, &clip_region, false); let mut vertices = clip_region.make_packed_vertices_for_rect(mask); - self.add_draw_item(matrix_index, - image_info.texture_id, + self.add_draw_item(image_info.texture_id, mask.texture_id, Primitive::Rectangles, &mut vertices, @@ -157,7 +149,6 @@ impl<'a> BatchBuilder<'a> { } pub fn add_text(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, font_key: FontKey, @@ -256,8 +247,7 @@ impl<'a> BatchBuilder<'a> { dummy_mask_image.uv_rect.bottom_right.y)); } - self.add_draw_item(matrix_index, - texture_id, + self.add_draw_item(texture_id, dummy_mask_image.texture_id, Primitive::Glyphs, &mut vertex_buffer, @@ -268,15 +258,13 @@ impl<'a> BatchBuilder<'a> { // Colors are in the order: top left, top right, bottom right, bottom left. #[inline] fn add_axis_aligned_gradient(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, resource_cache: &ResourceCache, clip_buffers: &mut ClipBuffers, colors: &[ColorF; 4]) { let white_image = resource_cache.get_dummy_color_image(); - self.add_axis_aligned_gradient_with_texture(matrix_index, - rect, + self.add_axis_aligned_gradient_with_texture(rect, clip, white_image, resource_cache, @@ -286,7 +274,6 @@ impl<'a> BatchBuilder<'a> { // Colors are in the order: top left, top right, bottom right, bottom left. fn add_axis_aligned_gradient_with_texture(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, image_info: &TextureCacheItem, @@ -313,8 +300,7 @@ impl<'a> BatchBuilder<'a> { .drain(..) { let mask = mask_for_clip_region(resource_cache, &clip_region, false); let mut vertices = clip_region.make_packed_vertices_for_rect(mask); - self.add_draw_item(matrix_index, - image_info.texture_id, + self.add_draw_item(image_info.texture_id, mask.texture_id, Primitive::Rectangles, &mut vertices, @@ -323,7 +309,6 @@ impl<'a> BatchBuilder<'a> { } fn add_axis_aligned_gradient_with_stops(&mut self, - matrix_index: MatrixIndex, clip: &CombinedClipRegion, rect: &Rect, direction: AxisDirection, @@ -360,8 +345,7 @@ impl<'a> BatchBuilder<'a> { ]; } } - self.add_axis_aligned_gradient(matrix_index, - &piece_rect, + self.add_axis_aligned_gradient(&piece_rect, clip, resource_cache, clip_buffers, @@ -370,7 +354,6 @@ impl<'a> BatchBuilder<'a> { } pub fn add_gradient(&mut self, - matrix_index: MatrixIndex, clip: &CombinedClipRegion, start_point: &Point2D, end_point: &Point2D, @@ -383,8 +366,7 @@ impl<'a> BatchBuilder<'a> { if start_point.x == end_point.x { let rect = Rect::new(Point2D::new(-10000.0, start_point.y), Size2D::new(20000.0, end_point.y - start_point.y)); - self.add_axis_aligned_gradient_with_stops(matrix_index, - clip, + self.add_axis_aligned_gradient_with_stops(clip, &rect, AxisDirection::Vertical, stops, @@ -395,8 +377,7 @@ impl<'a> BatchBuilder<'a> { if start_point.y == end_point.y { let rect = Rect::new(Point2D::new(start_point.x, -10000.0), Size2D::new(end_point.x - start_point.x, 20000.0)); - self.add_axis_aligned_gradient_with_stops(matrix_index, - clip, + self.add_axis_aligned_gradient_with_stops(clip, &rect, AxisDirection::Horizontal, stops, @@ -478,8 +459,7 @@ impl<'a> BatchBuilder<'a> { } if packed_vertices.len() > 0 { - self.add_draw_item(matrix_index, - white_image.texture_id, + self.add_draw_item(white_image.texture_id, mask.texture_id, Primitive::TriangleFan, &mut packed_vertices, @@ -491,7 +471,6 @@ impl<'a> BatchBuilder<'a> { } pub fn add_box_shadow(&mut self, - matrix_index: MatrixIndex, box_bounds: &Rect, clip: &CombinedClipRegion, box_offset: &Point2D, @@ -506,13 +485,16 @@ impl<'a> BatchBuilder<'a> { // Fast path. if blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None { - self.add_color_rectangle(matrix_index, &rect, clip, resource_cache, clip_buffers, color); + self.add_color_rectangle(&rect, + clip, + resource_cache, + clip_buffers, + color); return; } // Draw the corners. - self.add_box_shadow_corners(matrix_index, - box_bounds, + self.add_box_shadow_corners(box_bounds, box_offset, color, blur_radius, @@ -524,8 +506,7 @@ impl<'a> BatchBuilder<'a> { clip_buffers); // Draw the sides. - self.add_box_shadow_sides(matrix_index, - box_bounds, + self.add_box_shadow_sides(box_bounds, clip, box_offset, color, @@ -539,8 +520,7 @@ impl<'a> BatchBuilder<'a> { match clip_mode { BoxShadowClipMode::None => { // Fill the center area. - self.add_color_rectangle(matrix_index, - box_bounds, + self.add_color_rectangle(box_bounds, clip, resource_cache, clip_buffers, @@ -558,8 +538,7 @@ impl<'a> BatchBuilder<'a> { let mut clip = *clip; clip.clip_out(&ComplexClipRegion::new(*box_bounds, BorderRadius::uniform(border_radius))); - self.add_color_rectangle(matrix_index, - ¢er_rect, + self.add_color_rectangle(¢er_rect, &clip, resource_cache, clip_buffers, @@ -568,8 +547,7 @@ impl<'a> BatchBuilder<'a> { } BoxShadowClipMode::Inset => { // Fill in the outsides. - self.fill_outside_area_of_inset_box_shadow(matrix_index, - box_bounds, + self.fill_outside_area_of_inset_box_shadow(box_bounds, clip, box_offset, color, @@ -583,7 +561,6 @@ impl<'a> BatchBuilder<'a> { } fn add_box_shadow_corners(&mut self, - matrix_index: MatrixIndex, box_bounds: &Rect, box_offset: &Point2D, color: &ColorF, @@ -619,8 +596,7 @@ impl<'a> BatchBuilder<'a> { let center = Point2D::new(box_bounds.origin.x + box_bounds.size.width / 2.0, box_bounds.origin.y + box_bounds.size.height / 2.0); - self.add_box_shadow_corner(matrix_index, - &metrics.tl_outer, + self.add_box_shadow_corner(&metrics.tl_outer, &Point2D::new(metrics.tl_outer.x + metrics.edge_size, metrics.tl_outer.y + metrics.edge_size), &metrics.tl_outer, @@ -634,8 +610,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers, BasicRotationAngle::Upright); - self.add_box_shadow_corner(matrix_index, - &Point2D::new(metrics.tr_outer.x - metrics.edge_size, + self.add_box_shadow_corner(&Point2D::new(metrics.tr_outer.x - metrics.edge_size, metrics.tr_outer.y), &Point2D::new(metrics.tr_outer.x, metrics.tr_outer.y + metrics.edge_size), @@ -650,8 +625,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers, BasicRotationAngle::Clockwise90); - self.add_box_shadow_corner(matrix_index, - &Point2D::new(metrics.br_outer.x - metrics.edge_size, + self.add_box_shadow_corner(&Point2D::new(metrics.br_outer.x - metrics.edge_size, metrics.br_outer.y - metrics.edge_size), &Point2D::new(metrics.br_outer.x, metrics.br_outer.y), ¢er, @@ -665,8 +639,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers, BasicRotationAngle::Clockwise180); - self.add_box_shadow_corner(matrix_index, - &Point2D::new(metrics.bl_outer.x, + self.add_box_shadow_corner(&Point2D::new(metrics.bl_outer.x, metrics.bl_outer.y - metrics.edge_size), &Point2D::new(metrics.bl_outer.x + metrics.edge_size, metrics.bl_outer.y), @@ -684,7 +657,6 @@ impl<'a> BatchBuilder<'a> { } fn add_box_shadow_sides(&mut self, - matrix_index: MatrixIndex, box_bounds: &Rect, clip: &CombinedClipRegion, box_offset: &Point2D, @@ -730,8 +702,7 @@ impl<'a> BatchBuilder<'a> { let left_rect = Rect::new(metrics.tl_outer + Point2D::new(0.0, metrics.edge_size), vertical_size); - self.add_box_shadow_edge(matrix_index, - &top_rect.origin, + self.add_box_shadow_edge(&top_rect.origin, &top_rect.bottom_right(), &rect, color, @@ -742,8 +713,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers, BasicRotationAngle::Clockwise90); - self.add_box_shadow_edge(matrix_index, - &right_rect.origin, + self.add_box_shadow_edge(&right_rect.origin, &right_rect.bottom_right(), &rect, color, @@ -754,8 +724,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers, BasicRotationAngle::Clockwise180); - self.add_box_shadow_edge(matrix_index, - &bottom_rect.origin, + self.add_box_shadow_edge(&bottom_rect.origin, &bottom_rect.bottom_right(), &rect, color, @@ -766,8 +735,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers, BasicRotationAngle::Clockwise270); - self.add_box_shadow_edge(matrix_index, - &left_rect.origin, + self.add_box_shadow_edge(&left_rect.origin, &left_rect.bottom_right(), &rect, color, @@ -781,7 +749,6 @@ impl<'a> BatchBuilder<'a> { } fn fill_outside_area_of_inset_box_shadow(&mut self, - matrix_index: MatrixIndex, box_bounds: &Rect, clip: &CombinedClipRegion, box_offset: &Point2D, @@ -816,8 +783,7 @@ impl<'a> BatchBuilder<'a> { // +------------------------------+ // A: - self.add_color_rectangle(matrix_index, - &Rect::new(box_bounds.origin, + self.add_color_rectangle(&Rect::new(box_bounds.origin, Size2D::new(box_bounds.size.width, metrics.tl_outer.y - box_bounds.origin.y)), &clip, @@ -826,8 +792,7 @@ impl<'a> BatchBuilder<'a> { color); // B: - self.add_color_rectangle(matrix_index, - &Rect::new(metrics.tr_outer, + self.add_color_rectangle(&Rect::new(metrics.tr_outer, Size2D::new(box_bounds.max_x() - metrics.tr_outer.x, metrics.br_outer.y - metrics.tr_outer.y)), &clip, @@ -836,8 +801,7 @@ impl<'a> BatchBuilder<'a> { color); // C: - self.add_color_rectangle(matrix_index, - &Rect::new(Point2D::new(box_bounds.origin.x, metrics.bl_outer.y), + self.add_color_rectangle(&Rect::new(Point2D::new(box_bounds.origin.x, metrics.bl_outer.y), Size2D::new(box_bounds.size.width, box_bounds.max_y() - metrics.br_outer.y)), &clip, @@ -846,8 +810,7 @@ impl<'a> BatchBuilder<'a> { color); // D: - self.add_color_rectangle(matrix_index, - &Rect::new(Point2D::new(box_bounds.origin.x, metrics.tl_outer.y), + self.add_color_rectangle(&Rect::new(Point2D::new(box_bounds.origin.x, metrics.tl_outer.y), Size2D::new(metrics.tl_outer.x - box_bounds.origin.x, metrics.bl_outer.y - metrics.tl_outer.y)), &clip, @@ -881,7 +844,6 @@ impl<'a> BatchBuilder<'a> { #[inline] fn add_border_edge(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, direction: AxisDirection, @@ -921,8 +883,7 @@ impl<'a> BatchBuilder<'a> { } }; - self.add_color_rectangle(matrix_index, - &dash_rect, + self.add_color_rectangle(&dash_rect, clip, resource_cache, clip_buffers, @@ -964,8 +925,7 @@ impl<'a> BatchBuilder<'a> { let color_image = resource_cache.get_raster(&raster_item); // Top left: - self.add_textured_rectangle(matrix_index, - &Rect::new(dot_rect.origin, + self.add_textured_rectangle(&Rect::new(dot_rect.origin, Size2D::new(dot_rect.size.width / 2.0, dot_rect.size.height / 2.0)), clip, @@ -975,8 +935,7 @@ impl<'a> BatchBuilder<'a> { color); // Top right: - self.add_textured_rectangle(matrix_index, - &Rect::new(dot_rect.top_right(), + self.add_textured_rectangle(&Rect::new(dot_rect.top_right(), Size2D::new(-dot_rect.size.width / 2.0, dot_rect.size.height / 2.0)), clip, @@ -986,8 +945,7 @@ impl<'a> BatchBuilder<'a> { color); // Bottom right: - self.add_textured_rectangle(matrix_index, - &Rect::new(dot_rect.bottom_right(), + self.add_textured_rectangle(&Rect::new(dot_rect.bottom_right(), Size2D::new(-dot_rect.size.width / 2.0, -dot_rect.size.height / 2.0)), clip, @@ -997,8 +955,7 @@ impl<'a> BatchBuilder<'a> { color); // Bottom left: - self.add_textured_rectangle(matrix_index, - &Rect::new(dot_rect.bottom_left(), + self.add_textured_rectangle(&Rect::new(dot_rect.bottom_left(), Size2D::new(dot_rect.size.width / 2.0, -dot_rect.size.height / 2.0)), clip, @@ -1027,22 +984,19 @@ impl<'a> BatchBuilder<'a> { Size2D::new(rect.size.width / 3.0, rect.size.height))) } }; - self.add_color_rectangle(matrix_index, - &outer_rect, + self.add_color_rectangle(&outer_rect, clip, resource_cache, clip_buffers, color); - self.add_color_rectangle(matrix_index, - &inner_rect, + self.add_color_rectangle(&inner_rect, clip, resource_cache, clip_buffers, color); } _ => { - self.add_color_rectangle(matrix_index, - rect, + self.add_color_rectangle(rect, clip, resource_cache, clip_buffers, @@ -1053,7 +1007,6 @@ impl<'a> BatchBuilder<'a> { #[inline] fn add_border_corner(&mut self, - matrix_index: MatrixIndex, clip: &CombinedClipRegion, vertices_rect: &Rect, color0: &ColorF, @@ -1156,8 +1109,7 @@ impl<'a> BatchBuilder<'a> { PackedVertex::from_components(v1.x, v1.y, color1, 0.0, 0.0, muv2.x, muv2.y), ]; - self.add_draw_item(matrix_index, - white_image.texture_id, + self.add_draw_item(white_image.texture_id, mask_image.texture_id, Primitive::Triangles, &mut vertices, @@ -1167,7 +1119,6 @@ impl<'a> BatchBuilder<'a> { } fn add_color_image_rectangle(&mut self, - matrix_index: MatrixIndex, v0: &Point2D, v1: &Point2D, clip: &CombinedClipRegion, @@ -1203,8 +1154,7 @@ impl<'a> BatchBuilder<'a> { false); let mut vertices = clip_region.make_packed_vertices_for_rect(mask); - self.add_draw_item(matrix_index, - color_image.texture_id, + self.add_draw_item(color_image.texture_id, mask.texture_id, Primitive::Rectangles, &mut vertices, @@ -1213,7 +1163,6 @@ impl<'a> BatchBuilder<'a> { } pub fn add_border(&mut self, - matrix_index: MatrixIndex, rect: &Rect, clip: &CombinedClipRegion, info: &BorderDisplayItem, @@ -1250,8 +1199,7 @@ impl<'a> BatchBuilder<'a> { let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3); // Edges - self.add_border_edge(matrix_index, - &Rect::new(Point2D::new(tl_outer.x, tl_inner.y), + self.add_border_edge(&Rect::new(Point2D::new(tl_outer.x, tl_inner.y), Size2D::new(left.width, bl_inner.y - tl_inner.y)), clip, AxisDirection::Vertical, @@ -1260,8 +1208,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers); - self.add_border_edge(matrix_index, - &Rect::new(Point2D::new(tl_inner.x, tl_outer.y), + self.add_border_edge(&Rect::new(Point2D::new(tl_inner.x, tl_outer.y), Size2D::new(tr_inner.x - tl_inner.x, tr_outer.y + top.width - tl_outer.y)), clip, @@ -1271,8 +1218,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers); - self.add_border_edge(matrix_index, - &Rect::new(Point2D::new(br_outer.x - right.width, tr_inner.y), + self.add_border_edge(&Rect::new(Point2D::new(br_outer.x - right.width, tr_inner.y), Size2D::new(right.width, br_inner.y - tr_inner.y)), clip, AxisDirection::Vertical, @@ -1281,8 +1227,7 @@ impl<'a> BatchBuilder<'a> { resource_cache, clip_buffers); - self.add_border_edge(matrix_index, - &Rect::new(Point2D::new(bl_inner.x, bl_outer.y - bottom.width), + self.add_border_edge(&Rect::new(Point2D::new(bl_inner.x, bl_outer.y - bottom.width), Size2D::new(br_inner.x - bl_inner.x, br_outer.y - bl_outer.y + bottom.width)), clip, @@ -1293,8 +1238,7 @@ impl<'a> BatchBuilder<'a> { clip_buffers); // Corners - self.add_border_corner(matrix_index, - clip, + self.add_border_corner(clip, &Rect::new(tl_outer, Size2D::new(tl_inner.x - tl_outer.x, tl_inner.y - tl_outer.y)), @@ -1306,8 +1250,7 @@ impl<'a> BatchBuilder<'a> { clip_buffers, BasicRotationAngle::Upright); - self.add_border_corner(matrix_index, - clip, + self.add_border_corner(clip, &Rect::new(Point2D::new(tr_inner.x, tr_outer.y), Size2D::new(tr_outer.x - tr_inner.x, tr_inner.y - tr_outer.y)), @@ -1319,8 +1262,7 @@ impl<'a> BatchBuilder<'a> { clip_buffers, BasicRotationAngle::Clockwise90); - self.add_border_corner(matrix_index, - clip, + self.add_border_corner(clip, &Rect::new(br_inner, Size2D::new(br_outer.x - br_inner.x, br_outer.y - br_inner.y)), @@ -1332,8 +1274,7 @@ impl<'a> BatchBuilder<'a> { clip_buffers, BasicRotationAngle::Clockwise180); - self.add_border_corner(matrix_index, - clip, + self.add_border_corner(clip, &Rect::new(Point2D::new(bl_outer.x, bl_inner.y), Size2D::new(bl_inner.x - bl_outer.x, bl_outer.y - bl_inner.y)), @@ -1348,7 +1289,6 @@ impl<'a> BatchBuilder<'a> { // FIXME(pcwalton): Assumes rectangles are well-formed with origin in TL fn add_box_shadow_corner(&mut self, - matrix_index: MatrixIndex, top_left: &Point2D, bottom_right: &Point2D, corner_area_top_left: &Point2D, @@ -1385,8 +1325,7 @@ impl<'a> BatchBuilder<'a> { None => resource_cache.get_dummy_color_image(), }; - self.add_color_image_rectangle(matrix_index, - top_left, + self.add_color_image_rectangle(top_left, bottom_right, clip, color, @@ -1400,7 +1339,6 @@ impl<'a> BatchBuilder<'a> { } fn add_box_shadow_edge(&mut self, - matrix_index: MatrixIndex, top_left: &Point2D, bottom_right: &Point2D, box_rect: &Rect, @@ -1432,8 +1370,7 @@ impl<'a> BatchBuilder<'a> { None => resource_cache.get_dummy_color_image(), }; - self.add_color_image_rectangle(matrix_index, - top_left, + self.add_color_image_rectangle(top_left, bottom_right, clip, color, diff --git a/src/frame.rs b/src/frame.rs index 96e3bb0f9c..049188144c 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -8,7 +8,7 @@ use internal_types::{BatchUpdateList, RenderTargetIndex, DrawListId}; use internal_types::{CompositeBatchInfo, CompositeBatchJob}; use internal_types::{RendererFrame, StackingContextInfo, BatchInfo, DrawCall, StackingContextIndex}; use internal_types::{ANGLE_FLOAT_TO_FIXED, BatchUpdate, BatchUpdateOp, DrawLayer}; -use internal_types::{DrawCommand, ClearInfo, DrawTargetInfo}; +use internal_types::{DrawCommand, ClearInfo, DrawTargetInfo, RenderTargetId, DrawListGroupId}; use layer::Layer; use node_compiler::NodeCompiler; use renderer::CompositionOpHelpers; @@ -26,48 +26,68 @@ use util::MatrixHelpers; use webrender_traits::{PipelineId, Epoch, ScrollPolicy, ScrollLayerId, StackingContext}; use webrender_traits::{FilterOp, ImageFormat, MixBlendMode, StackingLevel}; +struct DrawListGroup { + id: DrawListGroupId, + + // Together, these define the granularity that batches + // can be created at. When compiling nodes, if either + // the scroll layer or render target are different from + // the current batch, it must be broken and a new batch started. + // This automatically handles the case of CompositeBatch, because + // for a composite batch to be present, the next draw list must be + // in a different render target! + scroll_layer_id: ScrollLayerId, + render_target_id: RenderTargetId, + + draw_list_ids: Vec, +} + +impl DrawListGroup { + fn new(id: DrawListGroupId, + scroll_layer_id: ScrollLayerId, + render_target_id: RenderTargetId) -> DrawListGroup { + DrawListGroup { + id: id, + scroll_layer_id: scroll_layer_id, + render_target_id: render_target_id, + draw_list_ids: Vec::new(), + } + } + + fn can_add(&self, + scroll_layer_id: ScrollLayerId, + render_target_id: RenderTargetId) -> bool { + let scroll_ok = scroll_layer_id == self.scroll_layer_id; + let target_ok = render_target_id == self.render_target_id; + let size_ok = self.draw_list_ids.len() < MAX_MATRICES_PER_BATCH; + scroll_ok && target_ok && size_ok + } + + fn push(&mut self, draw_list_id: DrawListId) { + self.draw_list_ids.push(draw_list_id); + } +} + struct FlattenContext<'a> { resource_cache: &'a mut ResourceCache, scene: &'a Scene, - old_layer_offsets: HashMap, DefaultState>, - scene_rect: Rect, pipeline_sizes: &'a mut HashMap>, - //device_pixel_ratio: f32, - pipeline_epoch_map: &'a mut HashMap>, -} - -#[derive(Debug)] -struct DrawListBatchInfo { - pub scroll_layer_id: ScrollLayerId, - pub draw_lists: Vec, + current_draw_list_group: Option, } #[derive(Debug)] pub enum FrameRenderItem { Clear(ClearInfo), CompositeBatch(CompositeBatchInfo), - DrawListBatch(DrawListBatchInfo), -} - -enum CurrentBatch { - Draw(DrawListBatchInfo), - Composite(CompositeBatchInfo), + DrawListBatch(DrawListGroupId), } pub struct RenderTarget { - // Draw context state - stacking_context_info: Vec, - - // Display items in culling trees - // TODO(gw) make private - pub layers: HashMap>, + id: RenderTargetId, // Child render targets children: Vec, - // Batch building - current_batch: Option, - // Outputs items: Vec, @@ -78,130 +98,21 @@ pub struct RenderTarget { } impl RenderTarget { - fn new(size: Size2D) -> RenderTarget { + fn new(id: RenderTargetId, size: Size2D) -> RenderTarget { RenderTarget { - layers: HashMap::with_hash_state(Default::default()), + id: id, children: Vec::new(), - stacking_context_info: Vec::new(), - current_batch: None, items: Vec::new(), child_texture_id: None, size: size, } } - fn cull(&mut self, viewport_rect: &Rect) { - for (_, layer) in &mut self.layers { - layer.cull(&viewport_rect); - } - - for child in &mut self.children { - child.cull(viewport_rect); - } - - //println!("todo - vis cull on child render targets"); - //println!("todo - vis cull on layers via rect!"); - } - - fn update_resource_lists(&mut self, - resource_cache: &ResourceCache, - thread_pool: &mut scoped_threadpool::Pool) { - for (_, layer) in &mut self.layers { - let nodes = &mut layer.aabb_tree.nodes; - - thread_pool.scoped(|scope| { - for node in nodes { - if node.is_visible && node.compiled_node.is_none() { - scope.execute(move || { - node.build_resource_list(resource_cache); - }); - } - } - }); - } - - for child in &mut self.children { - child.update_resource_lists(resource_cache, thread_pool); - } - } - - fn update_texture_cache_and_build_raster_jobs(&mut self, - resource_cache: &mut ResourceCache) { - let _pf = util::ProfileScope::new(" update_texture_cache_and_build_raster_jobs"); - - for (_, layer) in &self.layers { - for node in &layer.aabb_tree.nodes { - if node.is_visible { - let resource_list = node.resource_list.as_ref().unwrap(); - resource_cache.add_resource_list(resource_list); - } - } - } - - for child in &mut self.children { - child.update_texture_cache_and_build_raster_jobs(resource_cache); - } - } - - fn compile_visible_nodes(&mut self, - thread_pool: &mut scoped_threadpool::Pool, - resource_cache: &ResourceCache, - device_pixel_ratio: f32) { - let layers = &mut self.layers; - let items = &self.items; - let stacking_context_info = &self.stacking_context_info; - - thread_pool.scoped(|scope| { - for (_, layer) in layers { - let nodes = &mut layer.aabb_tree.nodes; - for node in nodes { - if node.is_visible && node.compiled_node.is_none() { - scope.execute(move || { - node.compile(resource_cache, - items, - device_pixel_ratio, - stacking_context_info); - }); - } - } - } - }); - - for child in &mut self.children { - child.compile_visible_nodes(thread_pool, - resource_cache, - device_pixel_ratio); - } - } - - fn update_batch_cache(&mut self, pending_updates: &mut BatchUpdateList) { - // Allocate and update VAOs - for (_, layer) in &mut self.layers { - for node in &mut layer.aabb_tree.nodes { - if node.is_visible { - let compiled_node = node.compiled_node.as_mut().unwrap(); - if let Some(vertex_buffer) = compiled_node.vertex_buffer.take() { - debug_assert!(compiled_node.vertex_buffer_id.is_none()); - - pending_updates.push(BatchUpdate { - id: vertex_buffer.id, - op: BatchUpdateOp::Create(vertex_buffer.vertices, - vertex_buffer.indices), - }); - - compiled_node.vertex_buffer_id = Some(vertex_buffer.id); - } - } - } - } - - for child in &mut self.children { - child.update_batch_cache(pending_updates); - } - } - fn collect_and_sort_visible_batches(&mut self, resource_cache: &mut ResourceCache, + draw_list_groups: &HashMap>, + layers: &HashMap>, + stacking_context_info: &Vec, device_pixel_ratio: f32) -> DrawLayer { let mut commands = vec![]; for item in &self.items { @@ -212,19 +123,20 @@ impl RenderTarget { &FrameRenderItem::CompositeBatch(ref info) => { commands.push(DrawCommand::CompositeBatch(info.clone())); } - &FrameRenderItem::DrawListBatch(ref batch_info) => { - let layer = &self.layers[&batch_info.scroll_layer_id]; - let first_draw_list_id = *batch_info.draw_lists.first().unwrap(); - debug_assert!(batch_info.draw_lists.len() <= MAX_MATRICES_PER_BATCH); + &FrameRenderItem::DrawListBatch(draw_list_group_id) => { + let draw_list_group = &draw_list_groups[&draw_list_group_id]; + debug_assert!(draw_list_group.draw_list_ids.len() <= MAX_MATRICES_PER_BATCH); + + let layer = &layers[&draw_list_group.scroll_layer_id]; let mut matrix_palette = - vec![Matrix4::identity(); batch_info.draw_lists.len()]; + vec![Matrix4::identity(); draw_list_group.draw_list_ids.len()]; // Update batch matrices - for (index, draw_list_id) in batch_info.draw_lists.iter().enumerate() { + for (index, draw_list_id) in draw_list_group.draw_list_ids.iter().enumerate() { let draw_list = resource_cache.get_draw_list(*draw_list_id); let StackingContextIndex(stacking_context_id) = draw_list.stacking_context_index.unwrap(); - let context = &self.stacking_context_info[stacking_context_id]; + let context = &stacking_context_info[stacking_context_id]; let mut transform = context.world_transform; transform = transform.translate(layer.scroll_offset.x, layer.scroll_offset.y, @@ -241,7 +153,7 @@ impl RenderTarget { let compiled_node = node.compiled_node.as_ref().unwrap(); let batch_list = compiled_node.batch_list.iter().find(|batch_list| { - batch_list.first_draw_list_id == first_draw_list_id + batch_list.draw_list_group_id == draw_list_group_id }); if let Some(batch_list) = batch_list { @@ -293,6 +205,9 @@ impl RenderTarget { for child in &mut self.children { let mut child_layer = child.collect_and_sort_visible_batches(resource_cache, + draw_list_groups, + layers, + stacking_context_info, device_pixel_ratio); child_layer.layer_origin = page.allocate(&child_layer.layer_size, @@ -314,31 +229,20 @@ impl RenderTarget { fn reset(&mut self, pending_updates: &mut BatchUpdateList, - resource_cache: &mut ResourceCache, - old_layer_offsets: &mut HashMap, DefaultState>) { - - for (layer_id, mut old_layer) in &mut self.layers.drain() { - old_layer.reset(pending_updates); - old_layer_offsets.insert(layer_id, old_layer.scroll_offset); - } - + resource_cache: &mut ResourceCache) { if let Some(child_texture_id) = self.child_texture_id.take() { resource_cache.free_render_target(child_texture_id); } for mut child in &mut self.children.drain(..) { child.reset(pending_updates, - resource_cache, - old_layer_offsets); + resource_cache); } - self.stacking_context_info.clear(); self.items.clear(); - debug_assert!(self.current_batch.is_none()); } fn push_clear(&mut self, clear_info: ClearInfo) { - self.flush(); self.items.push(FrameRenderItem::Clear(clear_info)); } @@ -346,103 +250,55 @@ impl RenderTarget { op: CompositionOp, target: Rect, render_target_index: RenderTargetIndex) { - let need_new_batch = match self.current_batch { - Some(ref batch) => { - match batch { - &CurrentBatch::Draw(..) => { - true - } - &CurrentBatch::Composite(ref batch) => { - batch.operation != op || op.needs_framebuffer() - } - } + // TODO(gw): Relax the restriction on batch breaks for FB reads + // once the proper render target allocation code is done! + let need_new_batch = op.needs_framebuffer() || match self.items.last() { + Some(&FrameRenderItem::CompositeBatch(ref info)) => { + info.operation != op } + Some(&FrameRenderItem::Clear(..)) | + Some(&FrameRenderItem::DrawListBatch(..)) | None => { true } }; if need_new_batch { - self.flush(); - - self.current_batch = Some(CurrentBatch::Composite(CompositeBatchInfo { + self.items.push(FrameRenderItem::CompositeBatch(CompositeBatchInfo { operation: op, jobs: Vec::new(), })); } // TODO(gw): This seems a little messy - restructure how current batch works! - match self.current_batch.as_mut().unwrap() { - &mut CurrentBatch::Draw(..) => { - unreachable!(); - } - &mut CurrentBatch::Composite(ref mut batch) => { - batch.jobs.push(CompositeBatchJob { + match self.items.last_mut().unwrap() { + &mut FrameRenderItem::CompositeBatch(ref mut batch) => { + let job = CompositeBatchJob { rect: target, render_target_index: render_target_index - }); - } - } - } - - fn push_draw_list(&mut self, - draw_list_id: DrawListId, - scroll_layer_id: ScrollLayerId) { - let need_new_batch = match self.current_batch { - Some(ref batch) => { - match batch { - &CurrentBatch::Draw(ref batch) => { - batch.scroll_layer_id != scroll_layer_id || - batch.draw_lists.len() == MAX_MATRICES_PER_BATCH - } - &CurrentBatch::Composite(..) => { - true - } - } - } - None => { - true - } - }; - - if need_new_batch { - self.flush(); - - self.current_batch = Some(CurrentBatch::Draw(DrawListBatchInfo { - scroll_layer_id: scroll_layer_id, - draw_lists: Vec::new(), - })); - } - - // TODO(gw): This seems a little messy - restructure how current batch works! - match self.current_batch.as_mut().unwrap() { - &mut CurrentBatch::Draw(ref mut batch) => { - batch.draw_lists.push(draw_list_id); + }; + batch.jobs.push(job); } - &mut CurrentBatch::Composite(..) => { + _ => { unreachable!(); } } } - fn flush(&mut self) { - if let Some(batch) = self.current_batch.take() { - match batch { - CurrentBatch::Draw(batch) => { - self.items.push(FrameRenderItem::DrawListBatch(batch)); - } - CurrentBatch::Composite(batch) => { - self.items.push(FrameRenderItem::CompositeBatch(batch)); - } - } - } + fn push_draw_list_group(&mut self, draw_list_group_id: DrawListGroupId) { + self.items.push(FrameRenderItem::DrawListBatch(draw_list_group_id)); } } pub struct Frame { + pub layers: HashMap>, pub pipeline_epoch_map: HashMap>, pub pending_updates: BatchUpdateList, - pub root: RenderTarget, + pub root: Option, + pub stacking_context_info: Vec, + next_render_target_id: RenderTargetId, + next_draw_list_group_id: DrawListGroupId, + draw_list_groups: HashMap>, } enum SceneItemKind<'a> { @@ -554,68 +410,322 @@ impl<'a> SceneItemKind<'a> { result.extend(outlines); result } +} - fn add_items_to_target(&self, - scene_items: &Vec, - target: &mut RenderTarget, - sc_info: StackingContextInfo, - context: &mut FlattenContext) { - let stacking_context_index = StackingContextIndex(target.stacking_context_info.len()); - target.stacking_context_info.push(sc_info.clone()); // TODO(gw): Avoid clone? - - for item in scene_items { - match item.specific { - SpecificSceneItem::DrawList(draw_list_id) => { - target.push_draw_list(draw_list_id, sc_info.scroll_layer); - - let layer = match target.layers.entry(sc_info.scroll_layer) { - Occupied(entry) => { - entry.into_mut() - } - Vacant(entry) => { - let scroll_offset = match context.old_layer_offsets - .get(&sc_info.scroll_layer) { - Some(old_offset) => *old_offset, - None => Point2D::zero(), - }; - - entry.insert(Layer::new(&context.scene_rect, &scroll_offset)) - } - }; - - let draw_list = context.resource_cache.get_draw_list_mut(draw_list_id); +trait StackingContextHelpers { + fn needs_composition_operation_for_mix_blend_mode(&self) -> bool; + fn composition_operations(&self) -> Vec; +} - // Store draw context - draw_list.stacking_context_index = Some(stacking_context_index); +impl StackingContextHelpers for StackingContext { + fn needs_composition_operation_for_mix_blend_mode(&self) -> bool { + match self.mix_blend_mode { + MixBlendMode::Normal => false, + MixBlendMode::Multiply | + MixBlendMode::Screen | + MixBlendMode::Overlay | + MixBlendMode::Darken | + MixBlendMode::Lighten | + MixBlendMode::ColorDodge | + MixBlendMode::ColorBurn | + MixBlendMode::HardLight | + MixBlendMode::SoftLight | + MixBlendMode::Difference | + MixBlendMode::Exclusion | + MixBlendMode::Hue | + MixBlendMode::Saturation | + MixBlendMode::Color | + MixBlendMode::Luminosity => true, + } + } - for (item_index, item) in draw_list.items.iter().enumerate() { - // Node index may already be Some(..). This can occur when a page has iframes - // and a new root stacking context is received. In this case, the node index - // may already be set for draw lists from other iframe(s) that weren't updated - // as part of this new stacking context. - let item_index = DrawListItemIndex(item_index as u32); - let rect = sc_info.world_transform.transform_rect(&item.rect); - layer.insert(&rect, draw_list_id, item_index); - } + fn composition_operations(&self) -> Vec { + let mut composition_operations = vec![]; + if self.needs_composition_operation_for_mix_blend_mode() { + composition_operations.push(CompositionOp::MixBlend(self.mix_blend_mode)); + } + for filter in self.filters.iter() { + match *filter { + FilterOp::Blur(radius) => { + composition_operations.push(CompositionOp::Filter(LowLevelFilterOp::Blur( + radius, + AxisDirection::Horizontal))); + composition_operations.push(CompositionOp::Filter(LowLevelFilterOp::Blur( + radius, + AxisDirection::Vertical))); } - SpecificSceneItem::StackingContext(id) => { - let stacking_context = context.scene - .stacking_context_map - .get(&id) - .unwrap(); - - let child = SceneItemKind::StackingContext(stacking_context); - child.flatten(&sc_info, - context, - target); + FilterOp::Brightness(amount) => { + composition_operations.push(CompositionOp::Filter( + LowLevelFilterOp::Brightness(Au::from_f32_px(amount)))); } - SpecificSceneItem::Iframe(ref iframe_info) => { - let pipeline = context.scene - .pipeline_map - .get(&iframe_info.id); + FilterOp::Contrast(amount) => { + composition_operations.push(CompositionOp::Filter( + LowLevelFilterOp::Contrast(Au::from_f32_px(amount)))); + } + FilterOp::Grayscale(amount) => { + composition_operations.push(CompositionOp::Filter( + LowLevelFilterOp::Grayscale(Au::from_f32_px(amount)))); + } + FilterOp::HueRotate(angle) => { + composition_operations.push(CompositionOp::Filter( + LowLevelFilterOp::HueRotate(f32::round( + angle * ANGLE_FLOAT_TO_FIXED) as i32))); + } + FilterOp::Invert(amount) => { + composition_operations.push(CompositionOp::Filter( + LowLevelFilterOp::Invert(Au::from_f32_px(amount)))); + } + FilterOp::Opacity(amount) => { + composition_operations.push(CompositionOp::Filter( + LowLevelFilterOp::Opacity(Au::from_f32_px(amount)))); + } + FilterOp::Saturate(amount) => { + composition_operations.push(CompositionOp::Filter( + LowLevelFilterOp::Saturate(Au::from_f32_px(amount)))); + } + FilterOp::Sepia(amount) => { + composition_operations.push(CompositionOp::Filter( + LowLevelFilterOp::Sepia(Au::from_f32_px(amount)))); + } + } + } - context.pipeline_sizes.insert(iframe_info.id, - iframe_info.bounds.size); + composition_operations + } +} + +impl Frame { + pub fn new() -> Frame { + Frame { + pipeline_epoch_map: HashMap::with_hash_state(Default::default()), + pending_updates: BatchUpdateList::new(), + root: None, + layers: HashMap::with_hash_state(Default::default()), + stacking_context_info: Vec::new(), + next_render_target_id: RenderTargetId(0), + next_draw_list_group_id: DrawListGroupId(0), + draw_list_groups: HashMap::with_hash_state(Default::default()), + } + } + + pub fn reset(&mut self, resource_cache: &mut ResourceCache) + -> HashMap, DefaultState> { + self.draw_list_groups.clear(); + self.pipeline_epoch_map.clear(); + self.stacking_context_info.clear(); + + if let Some(mut root) = self.root.take() { + root.reset(&mut self.pending_updates, resource_cache); + } + + // Free any render targets from last frame. + // TODO: This should really re-use existing targets here... + let mut old_layer_offsets = HashMap::with_hash_state(Default::default()); + for (layer_id, mut old_layer) in &mut self.layers.drain() { + old_layer.reset(&mut self.pending_updates); + old_layer_offsets.insert(layer_id, old_layer.scroll_offset); + } + + old_layer_offsets + } + + fn next_render_target_id(&mut self) -> RenderTargetId { + let RenderTargetId(render_target_id) = self.next_render_target_id; + self.next_render_target_id = RenderTargetId(render_target_id + 1); + RenderTargetId(render_target_id) + } + + fn next_draw_list_group_id(&mut self) -> DrawListGroupId { + let DrawListGroupId(draw_list_group_id) = self.next_draw_list_group_id; + self.next_draw_list_group_id = DrawListGroupId(draw_list_group_id + 1); + DrawListGroupId(draw_list_group_id) + } + + pub fn pending_updates(&mut self) -> BatchUpdateList { + mem::replace(&mut self.pending_updates, BatchUpdateList::new()) + } + + pub fn scroll(&mut self, delta: &Point2D, viewport_size: &Size2D) { + // TODO: Select other layers for scrolling! + let layer = self.layers.get_mut(&ScrollLayerId(0)); + + if let Some(layer) = layer { + layer.scroll_offset = layer.scroll_offset + *delta; + + layer.scroll_offset.x = layer.scroll_offset.x.min(0.0); + layer.scroll_offset.y = layer.scroll_offset.y.min(0.0); + + layer.scroll_offset.x = layer.scroll_offset.x.max(-layer.scroll_boundaries.width + + viewport_size.width); + layer.scroll_offset.y = layer.scroll_offset.y.max(-layer.scroll_boundaries.height + + viewport_size.height); + } else { + println!("unable to find root scroll layer (may be an empty stacking context)"); + } + } + + pub fn create(&mut self, + scene: &Scene, + resource_cache: &mut ResourceCache, + pipeline_sizes: &mut HashMap>, + framebuffer_size: Size2D) { + if let Some(root_pipeline_id) = scene.root_pipeline_id { + if let Some(root_pipeline) = scene.pipeline_map.get(&root_pipeline_id) { + let old_layer_offsets = self.reset(resource_cache); + + let root_stacking_context = scene.stacking_context_map + .get(&root_pipeline.root_stacking_context_id) + .unwrap(); + + let root_scroll_layer_id = root_stacking_context.stacking_context + .scroll_layer_id + .expect("root layer must be a scroll layer!"); + + let root_target_id = self.next_render_target_id(); + + let mut root_target = RenderTarget::new(root_target_id, framebuffer_size); + + // Work around borrow check on resource cache + { + let mut context = FlattenContext { + resource_cache: resource_cache, + scene: scene, + pipeline_sizes: pipeline_sizes, + current_draw_list_group: None, + }; + + let parent_info = StackingContextInfo { + world_origin: Point2D::zero(), + scroll_layer_id: root_scroll_layer_id, + world_perspective: Matrix4::identity(), + world_transform: Matrix4::identity(), + local_overflow: root_stacking_context.stacking_context.overflow, + }; + + let root_pipeline = SceneItemKind::Pipeline(root_pipeline); + self.flatten(root_pipeline, + &parent_info, + &mut context, + &mut root_target); + self.root = Some(root_target); + + if let Some(last_draw_list_group) = context.current_draw_list_group.take() { + self.draw_list_groups.insert(last_draw_list_group.id, + last_draw_list_group); + } + } + + let scene_rect = root_stacking_context.stacking_context.overflow; + + for (draw_list_group_id, draw_list_group) in &self.draw_list_groups { + let layer = match self.layers.entry(draw_list_group.scroll_layer_id) { + Occupied(entry) => { + entry.into_mut() + } + Vacant(entry) => { + let scroll_offset = match old_layer_offsets.get(&draw_list_group.scroll_layer_id) { + Some(old_offset) => *old_offset, + None => Point2D::zero(), + }; + + entry.insert(Layer::new(&scene_rect, &scroll_offset)) + } + }; + + for draw_list_id in &draw_list_group.draw_list_ids { + let draw_list_id = *draw_list_id; + let draw_list = resource_cache.get_draw_list(draw_list_id); + + let StackingContextIndex(stacking_context_id) = draw_list.stacking_context_index.unwrap(); + let sc_info = &self.stacking_context_info[stacking_context_id]; + + for (item_index, item) in draw_list.items.iter().enumerate() { + // Node index may already be Some(..). This can occur when a page has iframes + // and a new root stacking context is received. In this case, the node index + // may already be set for draw lists from other iframe(s) that weren't updated + // as part of this new stacking context. + let item_index = DrawListItemIndex(item_index as u32); + let rect = sc_info.world_transform.transform_rect(&item.rect); + layer.insert(&rect, + *draw_list_group_id, + draw_list_id, + item_index); + } + } + } + + // TODO(gw): This should be moved elsewhere! + if let Some(root_scroll_layer) = self.layers.get_mut(&root_scroll_layer_id) { + root_scroll_layer.scroll_boundaries = root_stacking_context.stacking_context.overflow.size; + } + } + } + } + + fn add_items_to_target(&mut self, + scene_items: &Vec, + target: &mut RenderTarget, + sc_info: StackingContextInfo, + context: &mut FlattenContext) { + let stacking_context_index = StackingContextIndex(self.stacking_context_info.len()); + self.stacking_context_info.push(sc_info.clone()); // TODO(gw): Avoid clone? + + for item in scene_items { + match item.specific { + SpecificSceneItem::DrawList(draw_list_id) => { + let draw_list = context.resource_cache.get_draw_list_mut(draw_list_id); + + // Store draw context + draw_list.stacking_context_index = Some(stacking_context_index); + + let needs_new_draw_group = match context.current_draw_list_group { + Some(ref draw_list_group) => { + !draw_list_group.can_add(sc_info.scroll_layer_id, + target.id) + } + None => { + true + } + }; + + if needs_new_draw_group { + if let Some(draw_list_group) = context.current_draw_list_group.take() { + self.draw_list_groups.insert(draw_list_group.id, + draw_list_group); + } + + let draw_list_group_id = self.next_draw_list_group_id(); + + let new_draw_list_group = DrawListGroup::new(draw_list_group_id, + sc_info.scroll_layer_id, + target.id); + + target.push_draw_list_group(draw_list_group_id); + + context.current_draw_list_group = Some(new_draw_list_group); + } + + context.current_draw_list_group.as_mut().unwrap().push(draw_list_id); + } + SpecificSceneItem::StackingContext(id) => { + let stacking_context = context.scene + .stacking_context_map + .get(&id) + .unwrap(); + + let child = SceneItemKind::StackingContext(stacking_context); + self.flatten(child, + &sc_info, + context, + target); + } + SpecificSceneItem::Iframe(ref iframe_info) => { + let pipeline = context.scene + .pipeline_map + .get(&iframe_info.id); + + context.pipeline_sizes.insert(iframe_info.id, + iframe_info.bounds.size); if let Some(pipeline) = pipeline { let iframe = SceneItemKind::Pipeline(pipeline); @@ -634,37 +744,39 @@ impl<'a> SceneItemKind<'a> { let overflow = overflow.translate(&-iframe_info.bounds.origin); let iframe_info = StackingContextInfo { - scroll_layer: sc_info.scroll_layer, + scroll_layer_id: sc_info.scroll_layer_id, world_origin: world_origin, world_transform: iframe_transform, local_overflow: overflow, world_perspective: Matrix4::identity(), }; - iframe.flatten(&iframe_info, - context, - target); + self.flatten(iframe, + &iframe_info, + context, + target); } } } } } - target.flush(); + //target.flush(); } - pub fn flatten(&self, + pub fn flatten(&mut self, + scene_item: SceneItemKind, parent: &StackingContextInfo, context: &mut FlattenContext, target: &mut RenderTarget) { let _pf = util::ProfileScope::new(" flatten"); - let stacking_context = match *self { + let stacking_context = match scene_item { SceneItemKind::StackingContext(stacking_context) => { &stacking_context.stacking_context } SceneItemKind::Pipeline(pipeline) => { - context.pipeline_epoch_map.insert(pipeline.pipeline_id, pipeline.epoch); + self.pipeline_epoch_map.insert(pipeline.pipeline_id, pipeline.epoch); &context.scene.stacking_context_map .get(&pipeline.root_stacking_context_id) @@ -675,8 +787,7 @@ impl<'a> SceneItemKind<'a> { let this_scroll_layer = match stacking_context.scroll_policy { ScrollPolicy::Scrollable => { - let scroll_layer = stacking_context.scroll_layer_id.unwrap_or(parent.scroll_layer); - scroll_layer + stacking_context.scroll_layer_id.unwrap_or(parent.scroll_layer_id) } ScrollPolicy::Fixed => { debug_assert!(stacking_context.scroll_layer_id.is_none()); @@ -690,7 +801,7 @@ impl<'a> SceneItemKind<'a> { .intersection(&stacking_context.overflow); if let Some(overflow) = overflow { - let scene_items = self.collect_scene_items(&context.scene); + let scene_items = scene_item.collect_scene_items(&context.scene); if !scene_items.is_empty() { // When establishing a new 3D context, clear Z. This is only needed if there @@ -722,7 +833,7 @@ impl<'a> SceneItemKind<'a> { let info = StackingContextInfo { world_origin: parent.world_origin + origin, - scroll_layer: this_scroll_layer, + scroll_layer_id: this_scroll_layer, local_overflow: overflow, world_transform: transform, world_perspective: perspective_transform, @@ -749,7 +860,9 @@ impl<'a> SceneItemKind<'a> { let render_target_size = Size2D::new(target_rect.size.width as u32, target_rect.size.height as u32); - let mut new_target = RenderTarget::new(render_target_size); + let render_target_id = self.next_render_target_id(); + let mut new_target = RenderTarget::new(render_target_id, + render_target_size); let world_origin = Point2D::new( (unfiltered_target_rect.origin.x - target_rect.origin.x) as f32, @@ -758,8 +871,8 @@ impl<'a> SceneItemKind<'a> { world_origin.y, 0.0); let info = StackingContextInfo { - world_origin: Point2D::new(0.0, 0.0), - scroll_layer: this_scroll_layer, + world_origin: Point2D::zero(), + scroll_layer_id: this_scroll_layer, local_overflow: overflow, world_transform: world_transform, world_perspective: stacking_context.perspective, @@ -782,183 +895,6 @@ impl<'a> SceneItemKind<'a> { } } } -} - -trait StackingContextHelpers { - fn needs_composition_operation_for_mix_blend_mode(&self) -> bool; - fn composition_operations(&self) -> Vec; -} - -impl StackingContextHelpers for StackingContext { - fn needs_composition_operation_for_mix_blend_mode(&self) -> bool { - match self.mix_blend_mode { - MixBlendMode::Normal => false, - MixBlendMode::Multiply | - MixBlendMode::Screen | - MixBlendMode::Overlay | - MixBlendMode::Darken | - MixBlendMode::Lighten | - MixBlendMode::ColorDodge | - MixBlendMode::ColorBurn | - MixBlendMode::HardLight | - MixBlendMode::SoftLight | - MixBlendMode::Difference | - MixBlendMode::Exclusion | - MixBlendMode::Hue | - MixBlendMode::Saturation | - MixBlendMode::Color | - MixBlendMode::Luminosity => true, - } - } - - fn composition_operations(&self) -> Vec { - let mut composition_operations = vec![]; - if self.needs_composition_operation_for_mix_blend_mode() { - composition_operations.push(CompositionOp::MixBlend(self.mix_blend_mode)); - } - for filter in self.filters.iter() { - match *filter { - FilterOp::Blur(radius) => { - composition_operations.push(CompositionOp::Filter(LowLevelFilterOp::Blur( - radius, - AxisDirection::Horizontal))); - composition_operations.push(CompositionOp::Filter(LowLevelFilterOp::Blur( - radius, - AxisDirection::Vertical))); - } - FilterOp::Brightness(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Brightness(Au::from_f32_px(amount)))); - } - FilterOp::Contrast(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Contrast(Au::from_f32_px(amount)))); - } - FilterOp::Grayscale(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Grayscale(Au::from_f32_px(amount)))); - } - FilterOp::HueRotate(angle) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::HueRotate(f32::round( - angle * ANGLE_FLOAT_TO_FIXED) as i32))); - } - FilterOp::Invert(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Invert(Au::from_f32_px(amount)))); - } - FilterOp::Opacity(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Opacity(Au::from_f32_px(amount)))); - } - FilterOp::Saturate(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Saturate(Au::from_f32_px(amount)))); - } - FilterOp::Sepia(amount) => { - composition_operations.push(CompositionOp::Filter( - LowLevelFilterOp::Sepia(Au::from_f32_px(amount)))); - } - } - } - - composition_operations - } -} - -impl Frame { - pub fn new(size: Size2D) -> Frame { - Frame { - pipeline_epoch_map: HashMap::with_hash_state(Default::default()), - pending_updates: BatchUpdateList::new(), - root: RenderTarget::new(size), - } - } - - pub fn reset(&mut self, resource_cache: &mut ResourceCache) - -> HashMap, DefaultState> { - self.pipeline_epoch_map.clear(); - - // Free any render targets from last frame. - // TODO: This should really re-use existing targets here... - let mut old_layer_offsets = HashMap::with_hash_state(Default::default()); - self.root.reset(&mut self.pending_updates, - resource_cache, - &mut old_layer_offsets); - old_layer_offsets - } - - pub fn pending_updates(&mut self) -> BatchUpdateList { - mem::replace(&mut self.pending_updates, BatchUpdateList::new()) - } - - pub fn scroll(&mut self, delta: &Point2D, viewport_size: &Size2D) { - // TODO: Select other layers for scrolling! - let layer = self.root.layers.get_mut(&ScrollLayerId(0)); - - if let Some(layer) = layer { - layer.scroll_offset = layer.scroll_offset + *delta; - - layer.scroll_offset.x = layer.scroll_offset.x.min(0.0); - layer.scroll_offset.y = layer.scroll_offset.y.min(0.0); - - layer.scroll_offset.x = layer.scroll_offset.x.max(-layer.scroll_boundaries.width + - viewport_size.width); - layer.scroll_offset.y = layer.scroll_offset.y.max(-layer.scroll_boundaries.height + - viewport_size.height); - } else { - println!("unable to find root scroll layer (may be an empty stacking context)"); - } - } - - pub fn create(&mut self, - scene: &Scene, - //viewport_size: Size2D, - //device_pixel_ratio: f32, - resource_cache: &mut ResourceCache, - pipeline_sizes: &mut HashMap>) { - if let Some(root_pipeline_id) = scene.root_pipeline_id { - if let Some(root_pipeline) = scene.pipeline_map.get(&root_pipeline_id) { - let old_layer_offsets = self.reset(resource_cache); - - let root_stacking_context = scene.stacking_context_map - .get(&root_pipeline.root_stacking_context_id) - .unwrap(); - - let root_scroll_layer_id = root_stacking_context.stacking_context - .scroll_layer_id - .expect("root layer must be a scroll layer!"); - - let parent_info = StackingContextInfo { - world_origin: Point2D::zero(), - scroll_layer: root_scroll_layer_id, - world_perspective: Matrix4::identity(), - world_transform: Matrix4::identity(), - local_overflow: root_stacking_context.stacking_context.overflow, - }; - - let mut context = FlattenContext { - resource_cache: resource_cache, - scene: scene, - scene_rect: root_stacking_context.stacking_context.overflow, - old_layer_offsets: old_layer_offsets, - pipeline_epoch_map: &mut self.pipeline_epoch_map, - //device_pixel_ratio: device_pixel_ratio, - pipeline_sizes: pipeline_sizes, - }; - - let root_pipeline = SceneItemKind::Pipeline(root_pipeline); - root_pipeline.flatten(&parent_info, - &mut context, - &mut self.root); - - // TODO(gw): This should be moved elsewhere! - if let Some(root_scroll_layer) = self.root.layers.get_mut(&root_scroll_layer_id) { - root_scroll_layer.scroll_boundaries = root_stacking_context.stacking_context.overflow.size; - } - } - } - } pub fn build(&mut self, viewport: &Rect, @@ -970,8 +906,10 @@ impl Frame { let size = Size2D::new(viewport.size.width as f32, viewport.size.height as f32); let viewport_rect = Rect::new(origin, size); - // Traverse render targets and layer trees to calculate visible nodes - self.root.cull(&viewport_rect); + // Traverse layer trees to calculate visible nodes + for (_, layer) in &mut self.layers { + layer.cull(&viewport_rect); + } // Build resource list for newly visible nodes self.update_resource_lists(resource_cache, thread_pool); @@ -1001,13 +939,34 @@ impl Frame { resource_cache: &ResourceCache, thread_pool: &mut scoped_threadpool::Pool) { let _pf = util::ProfileScope::new(" update_resource_lists"); - self.root.update_resource_lists(resource_cache, thread_pool); + + for (_, layer) in &mut self.layers { + let nodes = &mut layer.aabb_tree.nodes; + + thread_pool.scoped(|scope| { + for node in nodes { + if node.is_visible && node.compiled_node.is_none() { + scope.execute(move || { + node.build_resource_list(resource_cache); + }); + } + } + }); + } } pub fn update_texture_cache_and_build_raster_jobs(&mut self, resource_cache: &mut ResourceCache) { let _pf = util::ProfileScope::new(" update_texture_cache_and_build_raster_jobs"); - self.root.update_texture_cache_and_build_raster_jobs(resource_cache); + + for (_, layer) in &self.layers { + for node in &layer.aabb_tree.nodes { + if node.is_visible { + let resource_list = node.resource_list.as_ref().unwrap(); + resource_cache.add_resource_list(resource_list); + } + } + } } pub fn raster_glyphs(&mut self, @@ -1022,22 +981,72 @@ impl Frame { resource_cache: &ResourceCache, device_pixel_ratio: f32) { let _pf = util::ProfileScope::new(" compile_visible_nodes"); - self.root.compile_visible_nodes(thread_pool, - resource_cache, - device_pixel_ratio); + + let layers = &mut self.layers; + //let items = &self.items; + let stacking_context_info = &self.stacking_context_info; + + thread_pool.scoped(|scope| { + for (_, layer) in layers { + let nodes = &mut layer.aabb_tree.nodes; + for node in nodes { + if node.is_visible && node.compiled_node.is_none() { + scope.execute(move || { + node.compile(resource_cache, + //items, + device_pixel_ratio, + stacking_context_info); + }); + } + } + } + }); } pub fn update_batch_cache(&mut self) { let _pf = util::ProfileScope::new(" update_batch_cache"); - self.root.update_batch_cache(&mut self.pending_updates); + + // Allocate and update VAOs + for (_, layer) in &mut self.layers { + for node in &mut layer.aabb_tree.nodes { + if node.is_visible { + let compiled_node = node.compiled_node.as_mut().unwrap(); + if let Some(vertex_buffer) = compiled_node.vertex_buffer.take() { + debug_assert!(compiled_node.vertex_buffer_id.is_none()); + + self.pending_updates.push(BatchUpdate { + id: vertex_buffer.id, + op: BatchUpdateOp::Create(vertex_buffer.vertices, + vertex_buffer.indices), + }); + + compiled_node.vertex_buffer_id = Some(vertex_buffer.id); + } + } + } + } } pub fn collect_and_sort_visible_batches(&mut self, resource_cache: &mut ResourceCache, device_pixel_ratio: f32) -> RendererFrame { - let root_layer = self.root.collect_and_sort_visible_batches(resource_cache, - device_pixel_ratio); + let root_layer = match self.root { + Some(ref mut root) => { + root.collect_and_sort_visible_batches(resource_cache, + &self.draw_list_groups, + &self.layers, + &self.stacking_context_info, + device_pixel_ratio) + } + None => { + DrawLayer::new(None, + Vec::new(), + Vec::new(), + Size2D::zero()) + } + }; + RendererFrame::new(self.pipeline_epoch_map.clone(), root_layer) } } diff --git a/src/internal_types.rs b/src/internal_types.rs index 4851793a38..c57faade2e 100644 --- a/src/internal_types.rs +++ b/src/internal_types.rs @@ -527,6 +527,12 @@ pub enum AxisDirection { #[derive(Debug, Clone, Copy)] pub struct StackingContextIndex(pub usize); +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct DrawListGroupId(pub usize); + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct RenderTargetId(pub usize); + #[derive(Debug, Clone)] pub struct StackingContextInfo { pub world_origin: Point2D, @@ -536,7 +542,7 @@ pub struct StackingContextInfo { pub world_transform: Matrix4, pub world_perspective: Matrix4, - pub scroll_layer: ScrollLayerId, + pub scroll_layer_id: ScrollLayerId, } #[derive(Debug)] @@ -581,7 +587,7 @@ pub enum Primitive { #[derive(Debug)] pub struct BatchList { pub batches: Vec, - pub first_draw_list_id: DrawListId, + pub draw_list_group_id: DrawListGroupId, } pub struct CompiledNode { diff --git a/src/layer.rs b/src/layer.rs index 3be31d476a..65ab64fde2 100644 --- a/src/layer.rs +++ b/src/layer.rs @@ -1,7 +1,7 @@ use aabbtree::{AABBTree, NodeIndex}; use euclid::{Point2D, Rect, Size2D}; use internal_types::{BatchUpdate, BatchUpdateList, BatchUpdateOp}; -use internal_types::{DrawListItemIndex, DrawListId}; +use internal_types::{DrawListItemIndex, DrawListId, DrawListGroupId}; pub struct Layer { // TODO: Remove pub from here if possible in the future @@ -36,9 +36,13 @@ impl Layer { #[inline] pub fn insert(&mut self, rect: &Rect, + draw_list_group_id: DrawListGroupId, draw_list_id: DrawListId, item_index: DrawListItemIndex) { - self.aabb_tree.insert(rect, draw_list_id, item_index); + self.aabb_tree.insert(rect, + draw_list_group_id, + draw_list_id, + item_index); } pub fn cull(&mut self, viewport_rect: &Rect) { diff --git a/src/node_compiler.rs b/src/node_compiler.rs index 1719dc11b0..5029ccbb38 100644 --- a/src/node_compiler.rs +++ b/src/node_compiler.rs @@ -1,7 +1,6 @@ use aabbtree::AABBTreeNode; -use batch::{BatchBuilder, MatrixIndex, VertexBuffer}; +use batch::{BatchBuilder, VertexBuffer}; use clipper::{ClipBuffers}; -use frame::FrameRenderItem; use internal_types::{DrawListItemIndex, CompiledNode, StackingContextInfo}; use internal_types::{CombinedClipRegion, BatchList, StackingContextIndex}; use resource_cache::ResourceCache; @@ -10,7 +9,6 @@ use webrender_traits::SpecificDisplayItem; pub trait NodeCompiler { fn compile(&mut self, resource_cache: &ResourceCache, - render_items: &Vec, device_pixel_ratio: f32, stacking_context_info: &Vec); } @@ -18,136 +16,112 @@ pub trait NodeCompiler { impl NodeCompiler for AABBTreeNode { fn compile(&mut self, resource_cache: &ResourceCache, - render_items: &Vec, device_pixel_ratio: f32, stacking_context_info: &Vec) { let mut compiled_node = CompiledNode::new(); let mut vertex_buffer = VertexBuffer::new(); - let mut clip_buffers = ClipBuffers::new(); - for item in render_items { - match item { - &FrameRenderItem::Clear(..) => {} - &FrameRenderItem::CompositeBatch(..) => {} - &FrameRenderItem::DrawListBatch(ref batch_info) => { - // TODO: Move this to outer loop when combining with >1 draw list! - let mut builder = BatchBuilder::new(&mut vertex_buffer); - - for (index, draw_list_id) in batch_info.draw_lists.iter().enumerate() { - let draw_list_id = *draw_list_id; - let matrix_index = MatrixIndex(index as u8); + for draw_list_group in &self.draw_list_group_segments { + let mut builder = BatchBuilder::new(&mut vertex_buffer); - let draw_list_index_buffer = self.draw_lists.iter().find(|draw_list| { - draw_list.draw_list_id == draw_list_id - }); + for draw_list_index_buffer in &draw_list_group.index_buffers { + let draw_list = resource_cache.get_draw_list(draw_list_index_buffer.draw_list_id); - if let Some(draw_list_index_buffer) = draw_list_index_buffer { - let draw_list = resource_cache.get_draw_list(draw_list_id); + let StackingContextIndex(stacking_context_id) = draw_list.stacking_context_index.unwrap(); + let context = &stacking_context_info[stacking_context_id]; - let StackingContextIndex(stacking_context_id) = draw_list.stacking_context_index.unwrap(); - let context = &stacking_context_info[stacking_context_id]; + for index in &draw_list_index_buffer.indices { + let DrawListItemIndex(index) = *index; + let display_item = &draw_list.items[index as usize]; - for index in &draw_list_index_buffer.indices { - let DrawListItemIndex(index) = *index; - let display_item = &draw_list.items[index as usize]; - - let clip_rect = display_item.clip.main.intersection(&context.local_overflow); - let clip_rect = clip_rect.and_then(|clip_rect| { - let split_rect_local_space = self.split_rect.translate(&-context.world_origin); - clip_rect.intersection(&split_rect_local_space) - }); + let clip_rect = display_item.clip.main.intersection(&context.local_overflow); + let clip_rect = clip_rect.and_then(|clip_rect| { + let split_rect_local_space = self.split_rect.translate(&-context.world_origin); + clip_rect.intersection(&split_rect_local_space) + }); - if let Some(ref clip_rect) = clip_rect { - let mut clip = CombinedClipRegion::from_clip_in_rect_and_stack( - clip_rect, - &display_item.clip.complex[..]); + if let Some(ref clip_rect) = clip_rect { + let mut clip = CombinedClipRegion::from_clip_in_rect_and_stack( + clip_rect, + &display_item.clip.complex[..]); - match display_item.item { - SpecificDisplayItem::WebGL(ref info) => { - builder.add_webgl_rectangle(matrix_index, - &display_item.rect, - &clip, - resource_cache, - &mut clip_buffers, - &info.context_id); - } - SpecificDisplayItem::Image(ref info) => { - builder.add_image(matrix_index, - &display_item.rect, - &clip, - &info.stretch_size, - info.image_key, - info.image_rendering, - resource_cache, - &mut clip_buffers); - } - SpecificDisplayItem::Text(ref info) => { - builder.add_text(matrix_index, - &display_item.rect, - &clip, - info.font_key, - info.size, - info.blur_radius, - &info.color, - &info.glyphs, - resource_cache, - &mut clip_buffers, - device_pixel_ratio); - } - SpecificDisplayItem::Rectangle(ref info) => { - builder.add_color_rectangle(matrix_index, - &display_item.rect, - &clip, - resource_cache, - &mut clip_buffers, - &info.color); - } - SpecificDisplayItem::Gradient(ref info) => { - clip.clip_in_rect(&display_item.rect); - builder.add_gradient(matrix_index, - &clip, - &info.start_point, - &info.end_point, - &info.stops, - resource_cache, - &mut clip_buffers); - } - SpecificDisplayItem::BoxShadow(ref info) => { - builder.add_box_shadow(matrix_index, - &info.box_bounds, - &clip, - &info.offset, - &info.color, - info.blur_radius, - info.spread_radius, - info.border_radius, - info.clip_mode, - resource_cache, - &mut clip_buffers); - } - SpecificDisplayItem::Border(ref info) => { - builder.add_border(matrix_index, - &display_item.rect, - &clip, - info, - resource_cache, - &mut clip_buffers); - } - } - } + match display_item.item { + SpecificDisplayItem::WebGL(ref info) => { + builder.add_webgl_rectangle(&display_item.rect, + &clip, + resource_cache, + &mut clip_buffers, + &info.context_id); + } + SpecificDisplayItem::Image(ref info) => { + builder.add_image(&display_item.rect, + &clip, + &info.stretch_size, + info.image_key, + info.image_rendering, + resource_cache, + &mut clip_buffers); + } + SpecificDisplayItem::Text(ref info) => { + builder.add_text(&display_item.rect, + &clip, + info.font_key, + info.size, + info.blur_radius, + &info.color, + &info.glyphs, + resource_cache, + &mut clip_buffers, + device_pixel_ratio); + } + SpecificDisplayItem::Rectangle(ref info) => { + builder.add_color_rectangle(&display_item.rect, + &clip, + resource_cache, + &mut clip_buffers, + &info.color); + } + SpecificDisplayItem::Gradient(ref info) => { + clip.clip_in_rect(&display_item.rect); + builder.add_gradient(&clip, + &info.start_point, + &info.end_point, + &info.stops, + resource_cache, + &mut clip_buffers); + } + SpecificDisplayItem::BoxShadow(ref info) => { + builder.add_box_shadow(&info.box_bounds, + &clip, + &info.offset, + &info.color, + info.blur_radius, + info.spread_radius, + info.border_radius, + info.clip_mode, + resource_cache, + &mut clip_buffers); + } + SpecificDisplayItem::Border(ref info) => { + builder.add_border(&display_item.rect, + &clip, + info, + resource_cache, + &mut clip_buffers); } } } - - let batches = builder.finalize(); - - compiled_node.batch_list.push(BatchList { - batches: batches, - first_draw_list_id: *batch_info.draw_lists.first().unwrap(), - }); } + + builder.next_draw_list(); } + + let batches = builder.finalize(); + compiled_node.batch_list.push(BatchList { + batches: batches, + draw_list_group_id: draw_list_group.draw_list_group_id, + }); } compiled_node.vertex_buffer = Some(vertex_buffer); diff --git a/src/render_backend.rs b/src/render_backend.rs index 27513f89fb..8a17a6fcfc 100644 --- a/src/render_backend.rs +++ b/src/render_backend.rs @@ -55,8 +55,6 @@ impl RenderBackend { dummy_mask_image_id, device_pixel_ratio, enable_aa); - let viewport_size = Size2D::new(viewport.size.width as u32, - viewport.size.height as u32); let backend = RenderBackend { thread_pool: thread_pool, @@ -66,7 +64,7 @@ impl RenderBackend { device_pixel_ratio: device_pixel_ratio, resource_cache: resource_cache, scene: Scene::new(), - frame: Frame::new(viewport_size), + frame: Frame::new(), next_namespace_id: IdNamespace(1), notifier: notifier, webrender_context_handle: webrender_context_handle, @@ -177,7 +175,7 @@ impl RenderBackend { ApiMsg::TranslatePointToLayerSpace(point, tx) => { // TODO(pcwalton): Select other layers for mouse events. let point = point / self.device_pixel_ratio; - match self.frame.root.layers.get_mut(&ScrollLayerId(0)) { + match self.frame.layers.get_mut(&ScrollLayerId(0)) { None => tx.send(point).unwrap(), Some(layer) => tx.send(point - layer.scroll_offset).unwrap(), } @@ -233,12 +231,13 @@ impl RenderBackend { self.webgl_contexts.get(&id).unwrap().unbind().unwrap(); } + let framebuffer_size = Size2D::new(self.viewport.size.width as u32, + self.viewport.size.height as u32); + self.frame.create(&self.scene, - //Size2D::new(self.viewport.size.width as u32, - // self.viewport.size.height as u32), - //self.device_pixel_ratio, &mut self.resource_cache, - &mut new_pipeline_sizes); + &mut new_pipeline_sizes, + framebuffer_size); let mut updated_pipeline_sizes = HashMap::new(); diff --git a/src/renderer.rs b/src/renderer.rs index 8a24b3b83f..bc0a61b967 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -163,7 +163,7 @@ impl Renderer { let u_direction = device.get_uniform_location(blur_program_id, "uDirection"); - let texture_ids = device.create_texture_ids(16); + let texture_ids = device.create_texture_ids(1024); let mut texture_cache = TextureCache::new(texture_ids); let white_pixels: Vec = vec![ 0xff, 0xff, 0xff, 0xff, @@ -958,7 +958,6 @@ impl Renderer { mask_size.1 as f32); let index_count = draw_call.index_count as i32; - assert!(draw_call.first_vertex <= 65535); self.profile_counters.draw_calls.inc(); diff --git a/src/resource_list.rs b/src/resource_list.rs index ce81fc4d58..c2d7c84f96 100644 --- a/src/resource_list.rs +++ b/src/resource_list.rs @@ -136,122 +136,124 @@ impl BuildRequiredResources for AABBTreeNode { //let _pf = util::ProfileScope::new(" build_resource_list"); let mut resource_list = ResourceList::new(); - for draw_list_index_buffer in &self.draw_lists { - let draw_list = resource_cache.get_draw_list(draw_list_index_buffer.draw_list_id); + for group in &self.draw_list_group_segments { + for draw_list_index_buffer in &group.index_buffers { + let draw_list = resource_cache.get_draw_list(draw_list_index_buffer.draw_list_id); - for index in &draw_list_index_buffer.indices { - let DrawListItemIndex(index) = *index; - let display_item = &draw_list.items[index as usize]; + for index in &draw_list_index_buffer.indices { + let DrawListItemIndex(index) = *index; + let display_item = &draw_list.items[index as usize]; - // Handle border radius for complex clipping regions. - for complex_clip_region in display_item.clip.complex.iter() { - resource_list.add_radius_raster_for_border_radii(&complex_clip_region.radii); - } - - match display_item.item { - SpecificDisplayItem::Image(ref info) => { - resource_list.add_image(info.image_key, info.image_rendering); + // Handle border radius for complex clipping regions. + for complex_clip_region in display_item.clip.complex.iter() { + resource_list.add_radius_raster_for_border_radii(&complex_clip_region.radii); } - SpecificDisplayItem::Text(ref info) => { - for glyph in &info.glyphs { - let glyph = Glyph::new(info.size, info.blur_radius, glyph.index); - resource_list.add_glyph(info.font_key, glyph); + + match display_item.item { + SpecificDisplayItem::Image(ref info) => { + resource_list.add_image(info.image_key, info.image_rendering); } - } - SpecificDisplayItem::WebGL(..) => {} - SpecificDisplayItem::Rectangle(..) => {} - SpecificDisplayItem::Gradient(..) => {} - SpecificDisplayItem::BoxShadow(ref info) => { - resource_list.add_radius_raster_for_border_radii( - &BorderRadius::uniform(info.border_radius)); + SpecificDisplayItem::Text(ref info) => { + for glyph in &info.glyphs { + let glyph = Glyph::new(info.size, info.blur_radius, glyph.index); + resource_list.add_glyph(info.font_key, glyph); + } + } + SpecificDisplayItem::WebGL(..) => {} + SpecificDisplayItem::Rectangle(..) => {} + SpecificDisplayItem::Gradient(..) => {} + SpecificDisplayItem::BoxShadow(ref info) => { + resource_list.add_radius_raster_for_border_radii( + &BorderRadius::uniform(info.border_radius)); - let box_rect = batch_builder::compute_box_shadow_rect(&info.box_bounds, - &info.offset, - info.spread_radius); - resource_list.add_box_shadow_corner(info.blur_radius, - info.border_radius, - &box_rect, - false); - resource_list.add_box_shadow_edge(info.blur_radius, - info.border_radius, - &box_rect, - false); - if info.clip_mode == BoxShadowClipMode::Inset { + let box_rect = batch_builder::compute_box_shadow_rect(&info.box_bounds, + &info.offset, + info.spread_radius); resource_list.add_box_shadow_corner(info.blur_radius, info.border_radius, &box_rect, - true); + false); resource_list.add_box_shadow_edge(info.blur_radius, info.border_radius, &box_rect, - true); - } - } - SpecificDisplayItem::Border(ref info) => { - for rect_index in 0..tessellator::quad_count_for_border_corner( - &info.radius.top_left) { - resource_list.add_radius_raster(&info.radius.top_left, - &info.top_left_inner_radius(), - false, - rect_index, - ImageFormat::A8); - } - for rect_index in 0..tessellator::quad_count_for_border_corner( - &info.radius.top_right) { - resource_list.add_radius_raster(&info.radius.top_right, - &info.top_right_inner_radius(), - false, - rect_index, - ImageFormat::A8); - } - for rect_index in 0..tessellator::quad_count_for_border_corner( - &info.radius.bottom_left) { - resource_list.add_radius_raster(&info.radius.bottom_left, - &info.bottom_left_inner_radius(), - false, - rect_index, - ImageFormat::A8); - } - for rect_index in 0..tessellator::quad_count_for_border_corner( - &info.radius.bottom_right) { - resource_list.add_radius_raster(&info.radius.bottom_right, - &info.bottom_right_inner_radius(), - false, - rect_index, - ImageFormat::A8); + false); + if info.clip_mode == BoxShadowClipMode::Inset { + resource_list.add_box_shadow_corner(info.blur_radius, + info.border_radius, + &box_rect, + true); + resource_list.add_box_shadow_edge(info.blur_radius, + info.border_radius, + &box_rect, + true); + } } + SpecificDisplayItem::Border(ref info) => { + for rect_index in 0..tessellator::quad_count_for_border_corner( + &info.radius.top_left) { + resource_list.add_radius_raster(&info.radius.top_left, + &info.top_left_inner_radius(), + false, + rect_index, + ImageFormat::A8); + } + for rect_index in 0..tessellator::quad_count_for_border_corner( + &info.radius.top_right) { + resource_list.add_radius_raster(&info.radius.top_right, + &info.top_right_inner_radius(), + false, + rect_index, + ImageFormat::A8); + } + for rect_index in 0..tessellator::quad_count_for_border_corner( + &info.radius.bottom_left) { + resource_list.add_radius_raster(&info.radius.bottom_left, + &info.bottom_left_inner_radius(), + false, + rect_index, + ImageFormat::A8); + } + for rect_index in 0..tessellator::quad_count_for_border_corner( + &info.radius.bottom_right) { + resource_list.add_radius_raster(&info.radius.bottom_right, + &info.bottom_right_inner_radius(), + false, + rect_index, + ImageFormat::A8); + } - if info.top.style == BorderStyle::Dotted { - resource_list.add_radius_raster(&Size2D::new(info.top.width / 2.0, - info.top.width / 2.0), - &Size2D::new(0.0, 0.0), - false, - 0, - ImageFormat::RGBA8); - } - if info.right.style == BorderStyle::Dotted { - resource_list.add_radius_raster(&Size2D::new(info.right.width / 2.0, - info.right.width / 2.0), - &Size2D::new(0.0, 0.0), - false, - 0, - ImageFormat::RGBA8); - } - if info.bottom.style == BorderStyle::Dotted { - resource_list.add_radius_raster(&Size2D::new(info.bottom.width / 2.0, - info.bottom.width / 2.0), - &Size2D::new(0.0, 0.0), - false, - 0, - ImageFormat::RGBA8); - } - if info.left.style == BorderStyle::Dotted { - resource_list.add_radius_raster(&Size2D::new(info.left.width / 2.0, - info.left.width / 2.0), - &Size2D::new(0.0, 0.0), - false, - 0, - ImageFormat::RGBA8); + if info.top.style == BorderStyle::Dotted { + resource_list.add_radius_raster(&Size2D::new(info.top.width / 2.0, + info.top.width / 2.0), + &Size2D::new(0.0, 0.0), + false, + 0, + ImageFormat::RGBA8); + } + if info.right.style == BorderStyle::Dotted { + resource_list.add_radius_raster(&Size2D::new(info.right.width / 2.0, + info.right.width / 2.0), + &Size2D::new(0.0, 0.0), + false, + 0, + ImageFormat::RGBA8); + } + if info.bottom.style == BorderStyle::Dotted { + resource_list.add_radius_raster(&Size2D::new(info.bottom.width / 2.0, + info.bottom.width / 2.0), + &Size2D::new(0.0, 0.0), + false, + 0, + ImageFormat::RGBA8); + } + if info.left.style == BorderStyle::Dotted { + resource_list.add_radius_raster(&Size2D::new(info.left.width / 2.0, + info.left.width / 2.0), + &Size2D::new(0.0, 0.0), + false, + 0, + ImageFormat::RGBA8); + } } } }