From 98dde84b4f03a7d9b8b763ec6d5d687bd29ba8bd Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Sat, 11 Jun 2016 10:49:37 +1000 Subject: [PATCH 01/33] Initial tiling / wr2 code. --- src/aabbtree.rs | 151 +-- src/batch.rs | 331 +------ src/batch_builder.rs | 1923 +----------------------------------- src/bsptree.rs | 318 ++++++ src/cache_shared.glsl | 0 src/debug_render.rs | 18 +- src/device.rs | 394 ++++---- src/frame.rs | 927 ++++-------------- src/geometry.rs | 36 + src/internal_types.rs | 413 +------- src/kdtree.rs | 4 + src/layer.rs | 37 +- src/lib.rs | 7 +- src/node_compiler.rs | 165 ---- src/profiler.rs | 24 +- src/quadtree.rs | 222 +++++ src/render_backend.rs | 24 +- src/renderer.rs | 1544 ++++++++++++----------------- src/resource_cache.rs | 60 +- src/resource_list.rs | 265 +---- src/spring.rs | 2 - src/tessellator.rs | 113 --- src/texture_cache.rs | 205 +--- src/tiling.rs | 2147 +++++++++++++++++++++++++++++++++++++++++ src/util.rs | 193 ++-- 25 files changed, 3973 insertions(+), 5550 deletions(-) create mode 100644 src/bsptree.rs create mode 100644 src/cache_shared.glsl create mode 100644 src/kdtree.rs delete mode 100644 src/node_compiler.rs create mode 100644 src/quadtree.rs delete mode 100644 src/tessellator.rs create mode 100644 src/tiling.rs diff --git a/src/aabbtree.rs b/src/aabbtree.rs index 33ff4789d8..116c00b63e 100644 --- a/src/aabbtree.rs +++ b/src/aabbtree.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* use euclid::{Point2D, Rect, Size2D}; use internal_types::{CompiledNode, DrawListGroupId, DrawListId, DrawListItemIndex}; use resource_list::ResourceList; @@ -10,35 +11,12 @@ use util; #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct NodeIndex(pub u32); -pub struct DrawListIndexBuffer { - pub draw_list_id: DrawListId, - pub indices: Vec, -} - -pub struct DrawListGroupSegment { - pub draw_list_group_id: DrawListGroupId, - pub index_buffers: Vec, -} - -#[derive(Debug, Copy, Clone, PartialEq)] -enum TreeState { - Building, - Finalized, -} - pub struct AABBTreeNode { pub split_rect: Rect, pub actual_rect: Rect, - + pub primitives: Vec, // TODO: Use Option + NonZero here pub children: Option, - - pub is_visible: bool, - - pub draw_list_group_segments: Vec, - - pub resource_list: Option, - pub compiled_node: Option, } impl AABBTreeNode { @@ -46,82 +24,24 @@ impl AABBTreeNode { AABBTreeNode { split_rect: split_rect.clone(), actual_rect: Rect::zero(), + primitives: Vec::new(), children: None, - is_visible: false, - resource_list: None, - 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); + fn append_item(&mut self, prim_index: PrimitiveIndex, rect: &Rect) { + debug_assert!(self.split_rect.intersects(rect)); - 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 - } - None => { - true - } - }; - - if need_new_list { - self.draw_list_group_segments.last_mut().unwrap().index_buffers.push(DrawListIndexBuffer { - draw_list_id: draw_list_id, - indices: Vec::new(), - }); - } - - 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 group in &self.draw_list_group_segments { - for list in &group.index_buffers { - count += list.indices.len(); - } - } - count + self.actual_rect = self.actual_rect.union(rect); + self.primitives.push(prim_index); } } pub struct AABBTree { pub nodes: Vec, pub split_size: f32, - work_node_indices: Vec, - - state: TreeState, } impl AABBTree { @@ -131,7 +51,6 @@ impl AABBTree { nodes: Vec::new(), split_size: split_size, work_node_indices: Vec::new(), - state: TreeState::Building, }; let root_node = AABBTreeNode::new(local_bounds); @@ -140,11 +59,6 @@ impl AABBTree { tree } - pub fn finalize(&mut self) { - debug_assert!(self.state == TreeState::Building); - self.state = TreeState::Finalized; - } - #[allow(dead_code)] pub fn print(&self, node_index: NodeIndex, level: u32) { let mut indent = String::new(); @@ -153,14 +67,12 @@ impl AABBTree { } let node = self.node(node_index); - println!("{}n={:?} sr={:?} ar={:?} c={:?} lists={} segments={}", + println!("{}n={:?} sr={:?} ar={:?} c={:?}", indent, node_index, node.split_rect, node.actual_rect, - node.children, - node.draw_list_group_segments.len(), - node.item_count()); + node.children); if let Some(child_index) = node.children { let NodeIndex(child_index) = child_index; @@ -207,13 +119,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.state == TreeState::Building); - + pub fn insert(&mut self, rect: Rect, prim_index: PrimitiveIndex) { self.find_best_nodes(NodeIndex(0), &rect); if self.work_node_indices.is_empty() { // TODO(gw): If this happens, it it probably caused by items having @@ -223,14 +129,12 @@ impl AABBTree { // handled by the layout code! If it's not that, this is an // unexpected condition and should be investigated! debug!("WARNING: insert rect {:?} outside bounds, dropped.", rect); + self.work_node_indices.clear(); } else { 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_group_id, - draw_list_id, - item_index, - &rect); + node.append_item(prim_index, &rect); } } } @@ -274,16 +178,18 @@ impl AABBTree { } } - fn check_node_visibility(&mut self, +/* + fn check_node_visibility(&self, node_index: NodeIndex, - rect: &Rect) { + rect: &Rect, + vis_prims: &mut Vec) { let children = { - let node = self.node_mut(node_index); + let node = self.node(node_index); if node.split_rect.intersects(rect) { - if !node.draw_list_group_segments.is_empty() && + if !node.primitives.is_empty() && node.actual_rect.intersects(rect) { - debug_assert!(node.children.is_none()); - node.is_visible = true; + //node.is_visible = true; + vis_prims.extend_from_slice(&node.primitives); } node.children } else { @@ -293,19 +199,18 @@ impl AABBTree { if let Some(child_index) = children { let NodeIndex(child_index) = child_index; - self.check_node_visibility(NodeIndex(child_index+0), rect); - self.check_node_visibility(NodeIndex(child_index+1), rect); + self.check_node_visibility(NodeIndex(child_index+0), rect, vis_prims); + self.check_node_visibility(NodeIndex(child_index+1), rect, vis_prims); } } - pub fn cull(&mut self, rect: &Rect) { - let _pf = util::ProfileScope::new(" cull"); + pub fn vis_query(&self, rect: &Rect) -> Vec { debug_assert!(self.state == TreeState::Finalized); - for node in &mut self.nodes { - node.is_visible = false; - } + let mut vis_prims = Vec::new(); if !self.nodes.is_empty() { - self.check_node_visibility(NodeIndex(0), &rect); + self.check_node_visibility(NodeIndex(0), &rect, &mut vis_prims); } - } + vis_prims + }*/ } +*/ diff --git a/src/batch.rs b/src/batch.rs index 67676500da..c158d47871 100644 --- a/src/batch.rs +++ b/src/batch.rs @@ -4,18 +4,11 @@ use device::{ProgramId, TextureId}; use euclid::{Point2D, Rect, Size2D}; -use internal_types::{MAX_RECT, AxisDirection, PackedVertexColorMode, PackedVertexForQuad}; -use internal_types::{PackedVertexForTextureCacheUpdate, RectUv, DevicePixel}; +use internal_types::{AxisDirection}; +use internal_types::{PackedVertexForTextureCacheUpdate}; use std::sync::atomic::Ordering::SeqCst; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; use texture_cache::{BorderType, TexturePage}; -use webrender_traits::{ColorF, ComplexClipRegion}; - -pub const MAX_MATRICES_PER_BATCH: usize = 32; -pub const MAX_CLIP_RECTS_PER_BATCH: usize = 64; -pub const MAX_TILE_PARAMS_PER_BATCH: usize = 64; // TODO(gw): Constrain to max FS uniform vectors... -pub const INVALID_TILE_PARAM: u8 = 0; -pub const INVALID_CLIP_RECT_PARAM: usize = 0; static ID_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; @@ -30,25 +23,6 @@ pub struct VertexBufferId(pub usize); #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct MatrixIndex(pub u8); -#[derive(Clone, Debug)] -pub struct OffsetParams { - pub stacking_context_x0: f32, - pub stacking_context_y0: f32, - pub render_target_x0: f32, - pub render_target_y0: f32, -} - -impl OffsetParams { - pub fn identity() -> OffsetParams { - OffsetParams { - stacking_context_x0: 0.0, - stacking_context_y0: 0.0, - render_target_x0: 0.0, - render_target_y0: 0.0, - } - } -} - #[derive(Clone, Debug)] pub struct TileParams { pub u0: f32, @@ -57,307 +31,6 @@ pub struct TileParams { pub v_size: f32, } -impl VertexBufferId { - fn new() -> VertexBufferId { - VertexBufferId(new_id()) - } -} - -pub struct VertexBuffer { - pub id: VertexBufferId, - pub instance_count: u32, - pub vertices: Vec, -} - -impl VertexBuffer { - pub fn new() -> VertexBuffer { - VertexBuffer { - id: VertexBufferId::new(), - instance_count: 0, - vertices: vec![], - } - } -} - -#[derive(Debug)] -pub struct Batch { - pub color_texture_id: TextureId, - pub mask_texture_id: TextureId, - pub first_instance: u32, - pub instance_count: u32, - pub tile_params: Vec, - pub clip_rects: Vec>, -} - -impl Batch { - pub fn new(color_texture_id: TextureId, mask_texture_id: TextureId, first_instance: u32) - -> Batch { - let default_tile_params = vec![ - TileParams { - u0: 0.0, - v0: 0.0, - u_size: 1.0, - v_size: 1.0, - } - ]; - - let default_clip_rects = vec![ - Rect::new(Point2D::new(0.0, 0.0), Size2D::new(0.0, 0.0)), - ]; - - Batch { - color_texture_id: color_texture_id, - mask_texture_id: mask_texture_id, - first_instance: first_instance, - instance_count: 0, - tile_params: default_tile_params, - clip_rects: default_clip_rects, - } - } - - // TODO: This is quite inefficient - perhaps have a hashmap in addition to the vec... - fn clip_rect_index(&self, clip_rect: &Rect) -> Option { - self.clip_rects.iter().rposition(|existing_rect| { - existing_rect.origin.x == clip_rect.origin.x && - existing_rect.origin.y == clip_rect.origin.y && - existing_rect.size.width == clip_rect.size.width && - existing_rect.size.height == clip_rect.size.height - }) - } - - pub fn can_add_to_batch(&self, - color_texture_id: TextureId, - mask_texture_id: TextureId, - needs_tile_params: bool, - clip_in_rect: &Rect, - clip_out_rect: &Option>) -> bool { - let color_texture_ok = color_texture_id == self.color_texture_id; - let mask_texture_ok = mask_texture_id == self.mask_texture_id; - let tile_params_ok = !needs_tile_params || - self.tile_params.len() < MAX_TILE_PARAMS_PER_BATCH; - - let used_clip_count = self.clip_rects.len(); - - let clip_rects_ok = if used_clip_count + 2 < MAX_CLIP_RECTS_PER_BATCH { - true - } else { - let mut new_clip_count = 0; - - if self.clip_rect_index(clip_in_rect).is_none() { - new_clip_count += 1; - } - - if let &Some(ref clip_out_rect) = clip_out_rect { - if self.clip_rect_index(clip_out_rect).is_none() { - new_clip_count += 1; - } - } - - used_clip_count + new_clip_count < MAX_CLIP_RECTS_PER_BATCH - }; - - color_texture_ok && - mask_texture_ok && - tile_params_ok && - clip_rects_ok - } - - pub fn add_draw_item(&mut self, - tile_params: Option, - clip_in_rect: &Rect, - clip_out_rect: &Option>) -> (u8, u8, u8) { - self.instance_count += 1; - - let tile_params_index = tile_params.map_or(INVALID_TILE_PARAM, |tile_params| { - let index = self.tile_params.len(); - debug_assert!(index < MAX_TILE_PARAMS_PER_BATCH); - self.tile_params.push(tile_params); - index as u8 - }); - - let clip_in_rect_index = match self.clip_rect_index(clip_in_rect) { - Some(clip_in_rect_index) => { - clip_in_rect_index - } - None => { - let new_index = self.clip_rects.len(); - debug_assert!(new_index < MAX_CLIP_RECTS_PER_BATCH); - self.clip_rects.push(*clip_in_rect); - new_index - } - } as u8; - - let clip_out_rect_index = match clip_out_rect { - &Some(ref clip_out_rect) => { - match self.clip_rect_index(clip_out_rect) { - Some(clip_out_rect_index) => { - clip_out_rect_index - } - None => { - let new_index = self.clip_rects.len(); - debug_assert!(new_index < MAX_CLIP_RECTS_PER_BATCH); - self.clip_rects.push(*clip_out_rect); - new_index - } - } - } - &None => { - INVALID_CLIP_RECT_PARAM - } - } as u8; - - (tile_params_index, clip_in_rect_index, clip_out_rect_index) - } -} - -pub struct BatchBuilder<'a> { - vertex_buffer: &'a mut VertexBuffer, - batches: Vec, - current_matrix_index: u8, - - clip_offset: Point2D, - - clip_in_rect_stack: Vec>, - cached_clip_in_rect: Option>, - - clip_out_rect: Option>, - - // TODO(gw): Support nested complex clip regions! - pub complex_clip: Option, - - pub device_pixel_ratio: f32, -} - -impl<'a> BatchBuilder<'a> { - pub fn new(vertex_buffer: &mut VertexBuffer, - device_pixel_ratio: f32) -> BatchBuilder { - BatchBuilder { - vertex_buffer: vertex_buffer, - batches: Vec::new(), - current_matrix_index: 0, - clip_in_rect_stack: Vec::new(), - cached_clip_in_rect: Some(MAX_RECT), - clip_out_rect: None, - complex_clip: None, - clip_offset: Point2D::zero(), - device_pixel_ratio: device_pixel_ratio, - } - } - - pub fn finalize(self) -> Vec { - self.batches - } - - pub fn set_current_clip_rect_offset(&mut self, offset: Point2D) { - self.clip_offset = offset; - } - - pub fn next_draw_list(&mut self) { - debug_assert!((self.current_matrix_index as usize) < MAX_MATRICES_PER_BATCH); - self.current_matrix_index += 1; - } - - // TODO(gw): This is really inefficient to call this every push/pop... - fn update_clip_in_rect(&mut self) { - self.cached_clip_in_rect = Some(MAX_RECT); - - for rect in &self.clip_in_rect_stack { - self.cached_clip_in_rect = self.cached_clip_in_rect.unwrap().intersection(rect); - if self.cached_clip_in_rect.is_none() { - return; - } - } - } - - pub fn push_clip_in_rect(&mut self, rect: &Rect) { - let rect = rect.translate(&self.clip_offset); - self.clip_in_rect_stack.push(rect); - self.update_clip_in_rect(); - } - - pub fn pop_clip_in_rect(&mut self) { - self.clip_in_rect_stack.pop(); - self.update_clip_in_rect(); - } - - pub fn set_clip_out_rect(&mut self, rect: Option>) -> Option> { - let rect = rect.map(|rect| { - rect.translate(&self.clip_offset) - }); - let old_rect = self.clip_out_rect.take(); - self.clip_out_rect = rect; - old_rect - } - - pub fn push_complex_clip(&mut self, clip: &[ComplexClipRegion]) { - // TODO(gw): Handle nested complex clips! - if clip.len() > 0 { - self.complex_clip = Some(clip[0]); - } else { - self.complex_clip = None; - } - } - - pub fn pop_complex_clip(&mut self) { - self.complex_clip = None; - } - - // Colors are in the order: top left, top right, bottom right, bottom left. - pub fn add_rectangle(&mut self, - color_texture_id: TextureId, - mask_texture_id: TextureId, - pos_rect: &Rect, - uv_rect: &RectUv, - muv_rect: &RectUv, - colors: &[ColorF; 4], - color_mode: PackedVertexColorMode, - tile_params: Option) { - let (tile_params_index, - clip_in_rect_index, - clip_out_rect_index) = match self.cached_clip_in_rect { - None => return, - Some(ref clip_in_rect) => { - let need_new_batch = match self.batches.last_mut() { - Some(batch) => { - !batch.can_add_to_batch(color_texture_id, - mask_texture_id, - tile_params.is_some(), - clip_in_rect, - &self.clip_out_rect) - } - None => { - true - } - }; - - if need_new_batch { - self.batches.push(Batch::new(color_texture_id, - mask_texture_id, - self.vertex_buffer.instance_count)); - } - - self.batches.last_mut().unwrap().add_draw_item(tile_params, - clip_in_rect, - &self.clip_out_rect) - } - }; - - let mut vertex = PackedVertexForQuad::new(pos_rect, colors, uv_rect, muv_rect, color_mode); - vertex.matrix_index = self.current_matrix_index; - vertex.tile_params_index = vertex.tile_params_index | tile_params_index; - vertex.clip_in_rect_index = clip_in_rect_index; - vertex.clip_out_rect_index = clip_out_rect_index; - - self.push_vertex_for_rectangle(vertex); - - self.vertex_buffer.instance_count += 1 - } - - fn push_vertex_for_rectangle(&mut self, vertex: PackedVertexForQuad) { - self.vertex_buffer.vertices.push(vertex); - } -} - // Information needed to blit an item from a raster op batch target to final destination. pub struct BlitJob { pub dest_texture_id: TextureId, diff --git a/src/batch_builder.rs b/src/batch_builder.rs index cc81b8ba52..6abb5dbecf 100644 --- a/src/batch_builder.rs +++ b/src/batch_builder.rs @@ -2,1844 +2,14 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use app_units::Au; -use batch::{BatchBuilder, TileParams}; -use device::TextureId; -use euclid::{Rect, Point2D, Size2D}; -use fnv::FnvHasher; -use frame::FrameId; -use internal_types::{AxisDirection, BasicRotationAngle, BorderRadiusRasterOp, BoxShadowRasterOp}; -use internal_types::{GlyphKey, PackedVertexColorMode, RasterItem, RectColors, RectPolygon}; -use internal_types::{RectSide, RectUv, DevicePixel}; -use num_traits::Zero; -use renderer::BLUR_INFLATION_FACTOR; -use resource_cache::ResourceCache; -use std::cmp::Ordering; -use std::collections::HashMap; -use std::collections::hash_map::Entry::{Occupied, Vacant}; +use euclid::{Rect, Point2D}; use std::f32; -use std::hash::BuildHasherDefault; -use tessellator::{self, BorderCornerTessellation}; -use texture_cache::{TextureCacheItem}; -use util; -use util::RectVaryings; -use webrender_traits::{AuxiliaryLists, ColorF, ImageFormat, BorderStyle, BoxShadowClipMode}; -use webrender_traits::{BorderSide, FontKey, GlyphInstance, ImageKey}; -use webrender_traits::{BorderDisplayItem, GradientStop, ImageRendering}; -use webrender_traits::{WebGLContextId, ItemRange}; +use webrender_traits::{ColorF, BorderStyle}; +use webrender_traits::{BorderSide}; -const BORDER_DASH_SIZE: f32 = 3.0; +//const BORDER_DASH_SIZE: f32 = 3.0; -enum ClipState { - None, - ClipIn, - ClipOut(Option>) -} - -#[derive(Debug)] -struct GradientRect { - rect: Rect, - rect_uv: RectUv, - color0: ColorF, - color1: ColorF, -} - -impl<'a> BatchBuilder<'a> { - - // Colors are in the order: top left, top right, bottom right, bottom left. - pub fn add_simple_rectangle(&mut self, - color_texture_id: TextureId, - pos_rect: &Rect, - uv_rect: &RectUv, - mask_texture_id: TextureId, - muv_rect: &RectUv, - colors: &[ColorF; 4], - tile_params: Option) { - if pos_rect.size.width == 0.0 || pos_rect.size.height == 0.0 { - return - } - - self.add_rectangle(color_texture_id, - mask_texture_id, - pos_rect, - uv_rect, - muv_rect, - colors, - PackedVertexColorMode::Gradient, - tile_params); - } - - #[inline] - fn snap_value_to_device_pixel(&self, value: &mut f32) { - *value = (*value * self.device_pixel_ratio).round() / self.device_pixel_ratio; - } - - // Colors are in the order: top left, top right, bottom right, bottom left. - pub fn add_complex_clipped_rectangle(&mut self, - color_texture_id: TextureId, - pos_rect: &Rect, - uv_rect: &RectUv, - colors: &[ColorF; 4], - tile_params: Option, - resource_cache: &ResourceCache, - frame_id: FrameId) { - if pos_rect.size.width == 0.0 || pos_rect.size.height == 0.0 { - return - } - - match self.complex_clip { - Some(complex_clip) => { - // Get clip rect in local space of the display rect - let complex_clip_origin = complex_clip.rect.origin - pos_rect.origin; - let mut local_pos_rect = Rect::new(Point2D::zero(), pos_rect.size); - - // TODO(gw): Perhaps this should be caught higher up, or perhaps we - // can even remove this requirement. - self.snap_value_to_device_pixel(&mut local_pos_rect.size.width); - self.snap_value_to_device_pixel(&mut local_pos_rect.size.height); - - let mut tl_xr = complex_clip.radii.top_left.width; - let mut tl_yr = complex_clip.radii.top_left.height; - let mut tr_xr = complex_clip.radii.top_right.width; - let mut tr_yr = complex_clip.radii.top_right.height; - - let mut bl_xr = complex_clip.radii.bottom_left.width; - let mut bl_yr = complex_clip.radii.bottom_left.height; - let mut br_xr = complex_clip.radii.bottom_right.width; - let mut br_yr = complex_clip.radii.bottom_right.height; - - self.snap_value_to_device_pixel(&mut tl_xr); - self.snap_value_to_device_pixel(&mut tl_yr); - self.snap_value_to_device_pixel(&mut tr_xr); - self.snap_value_to_device_pixel(&mut tr_yr); - self.snap_value_to_device_pixel(&mut bl_xr); - self.snap_value_to_device_pixel(&mut bl_yr); - self.snap_value_to_device_pixel(&mut br_xr); - self.snap_value_to_device_pixel(&mut br_yr); - - // Generate all vertices for each line - let mut x_points = [ - complex_clip_origin.x + 0.0, - complex_clip_origin.x + complex_clip.radii.top_left.width, - complex_clip_origin.x + complex_clip.rect.size.width - complex_clip.radii.top_right.width, - complex_clip_origin.x + complex_clip.radii.bottom_left.width, - complex_clip_origin.x + complex_clip.rect.size.width - complex_clip.radii.bottom_right.width, - complex_clip_origin.x + complex_clip.rect.size.width, - ]; - - // Generate all vertices for each line - let mut y_points = [ - complex_clip_origin.y + 0.0, - complex_clip_origin.y + complex_clip.radii.top_left.height, - complex_clip_origin.y + complex_clip.radii.top_right.height, - complex_clip_origin.y + complex_clip.rect.size.height - complex_clip.radii.bottom_left.height, - complex_clip_origin.y + complex_clip.rect.size.height - complex_clip.radii.bottom_right.height, - complex_clip_origin.y + complex_clip.rect.size.height, - ]; - - for x_point in &mut x_points { - self.snap_value_to_device_pixel(x_point); - } - - for y_point in &mut y_points { - self.snap_value_to_device_pixel(y_point); - } - - let tl_clip = Rect::new(Point2D::new(x_points[0], y_points[0]), - Size2D::new(tl_xr, tl_yr)); - - let tr_clip = Rect::new(Point2D::new(x_points[2], y_points[0]), - Size2D::new(tr_xr, tr_yr)); - - let bl_clip = Rect::new(Point2D::new(x_points[0], y_points[3]), - Size2D::new(bl_xr, bl_yr)); - - let br_clip = Rect::new(Point2D::new(x_points[4], y_points[4]), - Size2D::new(br_xr, br_yr)); - - x_points.sort_by(|a, b| { - a.partial_cmp(b).unwrap() - }); - y_points.sort_by(|a, b| { - a.partial_cmp(b).unwrap() - }); - - for xi in 0..x_points.len()-1 { - for yi in 0..y_points.len()-1 { - let x0 = x_points[xi+0]; - let y0 = y_points[yi+0]; - let x1 = x_points[xi+1]; - let y1 = y_points[yi+1]; - - if x0 != x1 && y0 != y1 { - let sub_clip_rect = Rect::new(Point2D::new(x0, y0), - Size2D::new(x1-x0, y1-y0)); - - if let Some(clipped_pos_rect) = sub_clip_rect.intersection(&local_pos_rect) { - debug_assert!((clipped_pos_rect.origin.x * self.device_pixel_ratio).fract() == 0.0); - debug_assert!((clipped_pos_rect.origin.y * self.device_pixel_ratio).fract() == 0.0); - debug_assert!((clipped_pos_rect.size.width * self.device_pixel_ratio).fract() == 0.0); - debug_assert!((clipped_pos_rect.size.height * self.device_pixel_ratio).fract() == 0.0); - - let u0_f = clipped_pos_rect.origin.x / local_pos_rect.size.width; - let v0_f = clipped_pos_rect.origin.y / local_pos_rect.size.height; - let u1_f = (clipped_pos_rect.origin.x + clipped_pos_rect.size.width) / local_pos_rect.size.width; - let v1_f = (clipped_pos_rect.origin.y + clipped_pos_rect.size.height) / local_pos_rect.size.height; - - let u_size = uv_rect.top_right.x - uv_rect.top_left.x; - let v_size = uv_rect.bottom_right.y - uv_rect.top_left.y; - - let u0 = uv_rect.top_left.x + u0_f * u_size; - let v0 = uv_rect.top_left.y + v0_f * v_size; - let u1 = uv_rect.top_left.x + u1_f * u_size; - let v1 = uv_rect.top_left.y + v1_f * v_size; - - let uv_rect = RectUv { - top_left: Point2D::new(u0, v0), - top_right: Point2D::new(u1, v0), - bottom_left: Point2D::new(u0, v1), - bottom_right: Point2D::new(u1, v1), - }; - - // TODO(gw): There must be a more efficient way to to - // this (classifying which clip mask we need). - let (mask_info, angle) = if sub_clip_rect.intersects(&tl_clip) { - (Some(&tl_clip), BasicRotationAngle::Upright) - } else if sub_clip_rect.intersects(&tr_clip) { - (Some(&tr_clip), BasicRotationAngle::Clockwise90) - } else if sub_clip_rect.intersects(&bl_clip) { - (Some(&bl_clip), BasicRotationAngle::Clockwise270) - } else if sub_clip_rect.intersects(&br_clip) { - (Some(&br_clip), BasicRotationAngle::Clockwise180) - } else { - (None, BasicRotationAngle::Upright) - }; - - let (mask_texture_id, muv_rect) = match mask_info { - Some(clip_rect) => { - let op = RasterItem::BorderRadius(BorderRadiusRasterOp { - outer_radius_x: - DevicePixel::new(clip_rect.size.width, - self.device_pixel_ratio), - outer_radius_y: - DevicePixel::new(clip_rect.size.height, - self.device_pixel_ratio), - inner_radius_x: DevicePixel::zero(), - inner_radius_y: DevicePixel::zero(), - inverted: false, - index: None, - image_format: ImageFormat::A8, - }); - - let mask_image = resource_cache.get_raster(&op, frame_id); - - let mut x0_f = (x0 - clip_rect.origin.x) / clip_rect.size.width; - let mut x1_f = (x1 - clip_rect.origin.x) / clip_rect.size.width; - let mut y0_f = (y0 - clip_rect.origin.y) / clip_rect.size.height; - let mut y1_f = (y1 - clip_rect.origin.y) / clip_rect.size.height; - - match angle { - BasicRotationAngle::Upright => {} - BasicRotationAngle::Clockwise90 => { - x0_f = 1.0 - x0_f; - x1_f = 1.0 - x1_f; - } - BasicRotationAngle::Clockwise180 => { - x0_f = 1.0 - x0_f; - x1_f = 1.0 - x1_f; - y0_f = 1.0 - y0_f; - y1_f = 1.0 - y1_f; - } - BasicRotationAngle::Clockwise270 => { - y0_f = 1.0 - y0_f; - y1_f = 1.0 - y1_f; - } - } - - let mu0 = mask_image.pixel_rect.top_left.x.as_f32(); - let mu1 = mask_image.pixel_rect.top_right.x.as_f32(); - let mv0 = mask_image.pixel_rect.top_left.y.as_f32(); - let mv1 = mask_image.pixel_rect.bottom_left.y.as_f32(); - - let mu_size = mu1 - mu0; - let mv_size = mv1 - mv0; - let mu1 = mu0 + x1_f * mu_size; - let mu0 = mu0 + x0_f * mu_size; - let mv1 = mv0 + y1_f * mv_size; - let mv0 = mv0 + y0_f * mv_size; - - let mu0 = DevicePixel::from_f32(mu0); - let mv0 = DevicePixel::from_f32(mv0); - let mu1 = DevicePixel::from_f32(mu1); - let mv1 = DevicePixel::from_f32(mv1); - - let muv_rect = RectUv { - top_left: Point2D::new(mu0, mv0), - top_right: Point2D::new(mu1, mv0), - bottom_left: Point2D::new(mu0, mv1), - bottom_right: Point2D::new(mu1, mv1), - }; - - (mask_image.texture_id, muv_rect) - } - None => { - let mask_image = resource_cache.get_dummy_mask_image(); - (mask_image.texture_id, mask_image.pixel_rect) - } - }; - - // TODO(gw): Needless conversions here - just to make it - // easier to operate with existing bilerp code - clean this up! - let world_clipped_pos_rect = clipped_pos_rect.translate(&pos_rect.origin); - - let rect_colors = RectColors::from_elements(colors); - let rect_colors = util::bilerp_rect(&world_clipped_pos_rect, - &pos_rect, - &rect_colors); - - self.add_simple_rectangle(color_texture_id, - &world_clipped_pos_rect, - &uv_rect, - mask_texture_id, - &muv_rect, - &[rect_colors.top_left, - rect_colors.top_right, - rect_colors.bottom_right, - rect_colors.bottom_left, - ], - tile_params.clone()); - } - } - } - } - } - None => { - let dummy_mask_image = resource_cache.get_dummy_mask_image(); - - self.add_simple_rectangle(color_texture_id, - pos_rect, - uv_rect, - dummy_mask_image.texture_id, - &dummy_mask_image.pixel_rect, - colors, - tile_params); - } - } - } - - #[inline] - pub fn add_color_rectangle(&mut self, - rect: &Rect, - color: &ColorF, - resource_cache: &ResourceCache, - frame_id: FrameId) { - let white_image = resource_cache.get_dummy_color_image(); - self.add_complex_clipped_rectangle(white_image.texture_id, - rect, - &white_image.uv_rect(), - &[*color, *color, *color, *color], - None, - resource_cache, - frame_id); - } - - pub fn add_webgl_rectangle(&mut self, - rect: &Rect, - resource_cache: &ResourceCache, - webgl_context_id: &WebGLContextId, - frame_id: FrameId) { - let texture_id = resource_cache.get_webgl_texture(webgl_context_id); - let color = ColorF::new(1.0, 1.0, 1.0, 1.0); - - let uv = RectUv { - top_left: Point2D::new(0.0, 1.0), - top_right: Point2D::new(1.0, 1.0), - bottom_left: Point2D::zero(), - bottom_right: Point2D::new(1.0, 0.0), - }; - - self.add_complex_clipped_rectangle(texture_id, - rect, - &uv, - &[color, color, color, color], - None, - resource_cache, - frame_id); - } - - pub fn add_image(&mut self, - rect: &Rect, - stretch_size: &Size2D, - image_key: ImageKey, - image_rendering: ImageRendering, - resource_cache: &ResourceCache, - frame_id: FrameId) { - // Should be caught higher up - debug_assert!(stretch_size.width > 0.0 && stretch_size.height > 0.0); - let image_info = resource_cache.get_image(image_key, image_rendering, frame_id); - - let u1 = rect.size.width / stretch_size.width; - let v1 = rect.size.height / stretch_size.height; - - let uv = RectUv { - top_left: Point2D::zero(), - top_right: Point2D::new(u1, 0.0), - bottom_left: Point2D::new(0.0, v1), - bottom_right: Point2D::new(u1, v1), - }; - - let uv_rect = image_info.uv_rect(); - let uv_size = uv_rect.bottom_right - uv_rect.top_left; - - let tile_params = TileParams { - u0: image_info.uv_rect().top_left.x, - v0: image_info.uv_rect().top_left.y, - u_size: uv_size.x, - v_size: uv_size.y, - }; - - let color = ColorF::new(1.0, 1.0, 1.0, 1.0); - - self.add_complex_clipped_rectangle(image_info.texture_id, - rect, - &uv, - &[color, color, color, color], - Some(tile_params), - resource_cache, - frame_id); - } - - pub fn add_text(&mut self, - _rect: &Rect, - font_key: FontKey, - size: Au, - blur_radius: Au, - color: &ColorF, - glyphs: &[GlyphInstance], - resource_cache: &ResourceCache, - frame_id: FrameId, - device_pixel_ratio: f32) { - let dummy_mask_image = resource_cache.get_dummy_mask_image(); - - // Logic below to pick the primary render item depends on len > 0! - assert!(glyphs.len() > 0); - - let mut glyph_key = GlyphKey::new(font_key, size, blur_radius, glyphs[0].index); - let blur_offset = blur_radius.to_f32_px() * (BLUR_INFLATION_FACTOR as f32) / 2.0; - - let mut text_batches: HashMap>>, - BuildHasherDefault> = - HashMap::with_hasher(Default::default()); - - for glyph in glyphs { - glyph_key.index = glyph.index; - let image_info = resource_cache.get_glyph(&glyph_key, frame_id); - if let Some(image_info) = image_info { - let x = glyph.x + image_info.user_data.x0 as f32 / device_pixel_ratio - blur_offset; - let y = glyph.y - image_info.user_data.y0 as f32 / device_pixel_ratio - blur_offset; - - let width = image_info.requested_rect.size.width as f32 / device_pixel_ratio; - let height = image_info.requested_rect.size.height as f32 / device_pixel_ratio; - - let rect = RectPolygon { - pos: Rect::new(Point2D::new(x, y), - Size2D::new(width, height)), - varyings: image_info.uv_rect(), - }; - - let rect_buffer = match text_batches.entry(image_info.texture_id) { - Occupied(entry) => entry.into_mut(), - Vacant(entry) => entry.insert(Vec::new()), - }; - - rect_buffer.push(rect); - } - } - - for (texture_id, rect_buffer) in text_batches { - for rect in rect_buffer { - self.add_rectangle(texture_id, - dummy_mask_image.texture_id, - &rect.pos, - &rect.varyings, - &dummy_mask_image.pixel_rect, - &[*color, *color, *color, *color], - PackedVertexColorMode::Gradient, - None); - } - - } - } - - fn add_axis_aligned_gradient_with_stops(&mut self, - rect: &Rect, - direction: AxisDirection, - stops: &[GradientStop], - resource_cache: &ResourceCache, - frame_id: FrameId) { - let white_image = resource_cache.get_dummy_color_image(); - - for i in 0..(stops.len() - 1) { - let (prev_stop, next_stop) = (&stops[i], &stops[i + 1]); - let piece_rect; - let piece_colors; - match direction { - AxisDirection::Horizontal => { - let prev_x = util::lerp(rect.origin.x, rect.max_x(), prev_stop.offset); - let next_x = util::lerp(rect.origin.x, rect.max_x(), next_stop.offset); - piece_rect = Rect::new(Point2D::new(prev_x, rect.origin.y), - Size2D::new(next_x - prev_x, rect.size.height)); - piece_colors = [ - prev_stop.color, - next_stop.color, - next_stop.color, - prev_stop.color - ]; - } - AxisDirection::Vertical => { - let prev_y = util::lerp(rect.origin.y, rect.max_y(), prev_stop.offset); - let next_y = util::lerp(rect.origin.y, rect.max_y(), next_stop.offset); - piece_rect = Rect::new(Point2D::new(rect.origin.x, prev_y), - Size2D::new(rect.size.width, next_y - prev_y)); - piece_colors = [ - prev_stop.color, - prev_stop.color, - next_stop.color, - next_stop.color - ]; - } - } - - self.add_complex_clipped_rectangle(white_image.texture_id, - &piece_rect, - &white_image.uv_rect(), - &piece_colors, - None, - resource_cache, - frame_id); - } - } - - pub fn add_gradient(&mut self, - rect: &Rect, - start_point: &Point2D, - end_point: &Point2D, - stops: &ItemRange, - auxiliary_lists: &AuxiliaryLists, - resource_cache: &ResourceCache, - frame_id: FrameId) { - let stops = auxiliary_lists.gradient_stops(stops); - - // Fast paths for axis-aligned gradients: - if start_point.x == end_point.x { - let rect = Rect::new(Point2D::new(rect.origin.x, start_point.y), - Size2D::new(rect.size.width, end_point.y - start_point.y)); - self.add_axis_aligned_gradient_with_stops(&rect, - AxisDirection::Vertical, - stops, - resource_cache, - frame_id); - return - } - if start_point.y == end_point.y { - let rect = Rect::new(Point2D::new(start_point.x, rect.origin.y), - Size2D::new(end_point.x - start_point.x, rect.size.height)); - self.add_axis_aligned_gradient_with_stops(&rect, - AxisDirection::Horizontal, - stops, - resource_cache, - frame_id); - return - } - - let white_image = resource_cache.get_dummy_color_image(); - let dummy_mask_image = resource_cache.get_dummy_mask_image(); - - debug_assert!(stops.len() >= 2); - - let mut angle = ((end_point.y - start_point.y) / (end_point.x - start_point.x)).atan() + - f32::consts::FRAC_PI_2; - if angle < 0.0 { - angle += 2.0 * f32::consts::PI - } - - // A simple way to estimate the length of each strip we'll need. Providing a good estimate - // saves fragment shader invocations. - let length_0 = (rect.size.width * angle.sin()).abs() + - (rect.size.height * angle.cos()).abs(); - let length_1 = (rect.size.width * angle.cos()).abs() + - (rect.size.height * angle.sin()).abs(); - let length = if length_0 > length_1 { - length_0 - } else { - length_1 - }; - - let mut rectangles = Vec::new(); - let mut prev_color = stops[0].color; - let mut prev_offset = 0.0; - for next in &stops[..] { - let prev_point = util::lerp_points(start_point, end_point, prev_offset); - let next_point = util::lerp_points(start_point, end_point, next.offset); - let midpoint = util::lerp_points(&prev_point, &next_point, 0.5); - - let height = util::distance(&prev_point, &next_point); - let rect = - Rect::new(Point2D::new(-length / 2.0 + midpoint.x, midpoint.y - height / 2.0), - Size2D::new(length, height)); - let mut rect_uv = white_image.uv_rect(); - rect_uv.bottom_left.x = -angle; - - rectangles.push(GradientRect { - rect: rect, - rect_uv: rect_uv, - color0: next.color, - color1: prev_color - }); - - prev_color = next.color; - prev_offset = next.offset - } - - // This is a bit of a hack to pass reftests. In some cases of angled gradients, - // there is a one pixel overlap along the stop where two rectangles are drawn. - // To ensure that these are drawn the same in reftests, ensure the rectangles - // are always submitted in the same order no matter what angle they were - // generated from. - // TODO(gw): This probably deserves a bit more investigation to see if there - // is a better solution! - rectangles.sort_by(|a, b| { - match a.rect.origin.x.partial_cmp(&b.rect.origin.x).unwrap() { - Ordering::Equal => a.rect.origin.y.partial_cmp(&b.rect.origin.y).unwrap(), - ordering => ordering, - } - }); - - for gradient_rect in rectangles { - self.add_rectangle(white_image.texture_id, - dummy_mask_image.texture_id, - &gradient_rect.rect, - &gradient_rect.rect_uv, - &dummy_mask_image.pixel_rect, - &[gradient_rect.color0, - gradient_rect.color0, - gradient_rect.color1, - gradient_rect.color1 - ], - PackedVertexColorMode::Gradient, - None); - } - } - - pub fn add_box_shadow(&mut self, - box_bounds: &Rect, - box_offset: &Point2D, - color: &ColorF, - blur_radius: f32, - spread_radius: f32, - border_radius: f32, - clip_mode: BoxShadowClipMode, - resource_cache: &ResourceCache, - frame_id: FrameId) { - let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius, clip_mode); - - // Fast path. - if blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None { - self.add_color_rectangle(&rect, color, resource_cache, frame_id); - return; - } - - // Draw the corners. - self.add_box_shadow_corners(box_bounds, - box_offset, - color, - blur_radius, - spread_radius, - border_radius, - clip_mode, - resource_cache, - frame_id); - - // Draw the sides. - self.add_box_shadow_sides(box_bounds, - box_offset, - color, - blur_radius, - spread_radius, - border_radius, - clip_mode, - resource_cache, - frame_id); - - match clip_mode { - BoxShadowClipMode::None => { - // Fill the center area. - self.add_color_rectangle(box_bounds, color, resource_cache, frame_id); - } - BoxShadowClipMode::Outset => { - // Fill the center area. - let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); - if metrics.br_inner.x > metrics.tl_inner.x && - metrics.br_inner.y > metrics.tl_inner.y { - let center_rect = - Rect::new(metrics.tl_inner, - Size2D::new(metrics.br_inner.x - metrics.tl_inner.x, - metrics.br_inner.y - metrics.tl_inner.y)); - - // FIXME(pcwalton): This assumes the border radius is zero. That is not always - // the case! - let old_clip_out_rect = self.set_clip_out_rect(Some(*box_bounds)); - - self.add_color_rectangle(¢er_rect, color, resource_cache, frame_id); - - self.set_clip_out_rect(old_clip_out_rect); - } - } - BoxShadowClipMode::Inset => { - // Fill in the outsides. - self.fill_outside_area_of_inset_box_shadow(box_bounds, - box_offset, - color, - blur_radius, - spread_radius, - border_radius, - resource_cache, - frame_id); - } - } - } - - fn add_box_shadow_corners(&mut self, - box_bounds: &Rect, - box_offset: &Point2D, - color: &ColorF, - blur_radius: f32, - spread_radius: f32, - border_radius: f32, - clip_mode: BoxShadowClipMode, - resource_cache: &ResourceCache, - frame_id: FrameId) { - // Draw the corners. - // - // +--+------------------+--+ - // |##| |##| - // +--+------------------+--+ - // | | | | - // | | | | - // | | | | - // +--+------------------+--+ - // |##| |##| - // +--+------------------+--+ - - let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius, clip_mode); - let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); - - let clip_state = self.adjust_clip_for_box_shadow_clip_mode(box_bounds, - border_radius, - clip_mode); - - // Prevent overlap of the box shadow corners when the size of the blur is larger than the - // size of the box. - let center = Point2D::new(rect.origin.x + rect.size.width / 2.0, - rect.origin.y + rect.size.height / 2.0); - - 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, - ¢er, - &rect, - &color, - blur_radius, - border_radius, - clip_mode, - resource_cache, - frame_id, - BasicRotationAngle::Upright); - 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), - &Point2D::new(center.x, metrics.tr_outer.y), - &Point2D::new(metrics.tr_outer.x, center.y), - &rect, - &color, - blur_radius, - border_radius, - clip_mode, - resource_cache, - frame_id, - BasicRotationAngle::Clockwise90); - 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, - &metrics.br_outer, - &rect, - &color, - blur_radius, - border_radius, - clip_mode, - resource_cache, - frame_id, - BasicRotationAngle::Clockwise180); - 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), - &Point2D::new(metrics.bl_outer.x, center.y), - &Point2D::new(center.x, metrics.bl_outer.y), - &rect, - &color, - blur_radius, - border_radius, - clip_mode, - resource_cache, - frame_id, - BasicRotationAngle::Clockwise270); - - self.undo_clip_state(clip_state); - } - - fn add_box_shadow_sides(&mut self, - box_bounds: &Rect, - box_offset: &Point2D, - color: &ColorF, - blur_radius: f32, - spread_radius: f32, - border_radius: f32, - clip_mode: BoxShadowClipMode, - resource_cache: &ResourceCache, - frame_id: FrameId) { - let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius, clip_mode); - let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); - - let clip_state = self.adjust_clip_for_box_shadow_clip_mode(box_bounds, - border_radius, - clip_mode); - - if clip_mode == BoxShadowClipMode::Inset && blur_radius == 0.0 { - return; - } - - // Draw the sides. - // - // +--+------------------+--+ - // | |##################| | - // +--+------------------+--+ - // |##| |##| - // |##| |##| - // |##| |##| - // +--+------------------+--+ - // | |##################| | - // +--+------------------+--+ - - let horizontal_size = Size2D::new(metrics.br_inner.x - metrics.tl_inner.x, - metrics.edge_size); - let vertical_size = Size2D::new(metrics.edge_size, - metrics.br_inner.y - metrics.tl_inner.y); - let top_rect = Rect::new(metrics.tl_outer + Point2D::new(metrics.edge_size, 0.0), - horizontal_size); - let right_rect = - Rect::new(metrics.tr_outer + Point2D::new(-metrics.edge_size, metrics.edge_size), - vertical_size); - let bottom_rect = - Rect::new(metrics.bl_outer + Point2D::new(metrics.edge_size, -metrics.edge_size), - horizontal_size); - let left_rect = Rect::new(metrics.tl_outer + Point2D::new(0.0, metrics.edge_size), - vertical_size); - - // Prevent overlap of the box shadow edges when the size of the blur is larger than the - // size of the box. - let center = Point2D::new(rect.origin.x + rect.size.width / 2.0, - rect.origin.y + rect.size.height / 2.0); - - self.add_box_shadow_edge(&top_rect.origin, - &top_rect.bottom_right(), - &top_rect.origin, - &Point2D::new(metrics.tr_inner.x, center.y), - &rect, - color, - blur_radius, - border_radius, - clip_mode, - resource_cache, - frame_id, - BasicRotationAngle::Clockwise90); - self.add_box_shadow_edge(&right_rect.origin, - &right_rect.bottom_right(), - &Point2D::new(center.x, metrics.tr_inner.y), - &right_rect.bottom_right(), - &rect, - color, - blur_radius, - border_radius, - clip_mode, - resource_cache, - frame_id, - BasicRotationAngle::Clockwise180); - self.add_box_shadow_edge(&bottom_rect.origin, - &bottom_rect.bottom_right(), - &Point2D::new(metrics.bl_inner.x, center.y), - &bottom_rect.bottom_right(), - &rect, - color, - blur_radius, - border_radius, - clip_mode, - resource_cache, - frame_id, - BasicRotationAngle::Clockwise270); - self.add_box_shadow_edge(&left_rect.origin, - &left_rect.bottom_right(), - &left_rect.origin, - &Point2D::new(center.x, metrics.bl_inner.y), - &rect, - color, - blur_radius, - border_radius, - clip_mode, - resource_cache, - frame_id, - BasicRotationAngle::Upright); - - self.undo_clip_state(clip_state); - } - - fn fill_outside_area_of_inset_box_shadow(&mut self, - box_bounds: &Rect, - box_offset: &Point2D, - color: &ColorF, - blur_radius: f32, - spread_radius: f32, - border_radius: f32, - resource_cache: &ResourceCache, - frame_id: FrameId) { - let rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius, BoxShadowClipMode::Inset); - let metrics = BoxShadowMetrics::new(&rect, border_radius, blur_radius); - - let clip_state = self.adjust_clip_for_box_shadow_clip_mode(box_bounds, - border_radius, - BoxShadowClipMode::Inset); - - // Fill in the outside area of the box. - // - // +------------------------------+ - // A --> |##############################| - // +--+--+------------------+--+--+ - // |##| | | |##| - // |##+--+------------------+--+##| - // |##| | | |##| - // D --> |##| | | |##| <-- B - // |##| | | |##| - // |##+--+------------------+--+##| - // |##| | | |##| - // +--+--+------------------+--+--+ - // C --> |##############################| - // +------------------------------+ - - // A: - self.add_color_rectangle(&Rect::new(box_bounds.origin, - Size2D::new(box_bounds.size.width, - metrics.tl_outer.y - box_bounds.origin.y)), - color, - resource_cache, - frame_id); - - // B: - 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)), - color, - resource_cache, - frame_id); - - // C: - 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)), - color, - resource_cache, - frame_id); - - // D: - 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)), - color, - resource_cache, - frame_id); - - self.undo_clip_state(clip_state); - } - - fn undo_clip_state(&mut self, clip_state: ClipState) { - match clip_state { - ClipState::None => {} - ClipState::ClipIn => { - self.pop_clip_in_rect(); - } - ClipState::ClipOut(old_rect) => { - self.set_clip_out_rect(old_rect); - } - } - } - - fn adjust_clip_for_box_shadow_clip_mode(&mut self, - box_bounds: &Rect, - _border_radius: f32, - clip_mode: BoxShadowClipMode) -> ClipState { - //debug_assert!(border_radius == 0.0); // TODO(gw): !!! - - match clip_mode { - BoxShadowClipMode::None => { - ClipState::None - } - BoxShadowClipMode::Inset => { - self.push_clip_in_rect(box_bounds); - ClipState::ClipIn - } - BoxShadowClipMode::Outset => { - let old_clip_out_rect = self.set_clip_out_rect(Some(*box_bounds)); - ClipState::ClipOut(old_clip_out_rect) - } - } - } - - #[inline] - fn add_border_edge(&mut self, - rect: &Rect, - side: RectSide, - color: &ColorF, - border_style: BorderStyle, - resource_cache: &ResourceCache, - frame_id: FrameId) { - if color.a <= 0.0 { - return - } - if rect.size.width <= 0.0 || rect.size.height <= 0.0 { - return - } - - let dummy_mask_image = resource_cache.get_dummy_mask_image(); - let colors = [*color, *color, *color, *color]; - - match border_style { - BorderStyle::Dashed => { - let (extent, step) = match side { - RectSide::Top | RectSide::Bottom => { - (rect.size.width, rect.size.height * BORDER_DASH_SIZE) - } - RectSide::Left | RectSide::Right => { - (rect.size.height, rect.size.width * BORDER_DASH_SIZE) - } - }; - let mut origin = 0.0; - while origin < extent { - let dash_rect = match side { - RectSide::Top | RectSide::Bottom => { - Rect::new(Point2D::new(rect.origin.x + origin, rect.origin.y), - Size2D::new(f32::min(step, extent - origin), - rect.size.height)) - } - RectSide::Left | RectSide::Right => { - Rect::new(Point2D::new(rect.origin.x, rect.origin.y + origin), - Size2D::new(rect.size.width, - f32::min(step, extent - origin))) - } - }; - - self.add_color_rectangle(&dash_rect, color, resource_cache, frame_id); - - origin += step + step; - } - } - BorderStyle::Dotted => { - let (extent, step) = match side { - RectSide::Top | RectSide::Bottom => (rect.size.width, rect.size.height), - RectSide::Left | RectSide::Right => (rect.size.height, rect.size.width), - }; - let mut origin = 0.0; - while origin < extent { - let (dot_rect, mask_radius) = match side { - RectSide::Top | RectSide::Bottom => { - (Rect::new(Point2D::new(rect.origin.x + origin, rect.origin.y), - Size2D::new(f32::min(step, extent - origin), - rect.size.height)), - rect.size.height / 2.0) - } - RectSide::Left | RectSide::Right => { - (Rect::new(Point2D::new(rect.origin.x, rect.origin.y + origin), - Size2D::new(rect.size.width, - f32::min(step, extent - origin))), - rect.size.width / 2.0) - } - }; - - let mask_radius = DevicePixel::new(mask_radius, self.device_pixel_ratio); - - let raster_op = - BorderRadiusRasterOp::create(mask_radius, - mask_radius, - DevicePixel::zero(), - DevicePixel::zero(), - false, - None, - ImageFormat::RGBA8).expect( - "Didn't find border radius mask for dashed border!"); - let raster_item = RasterItem::BorderRadius(raster_op); - let color_image = resource_cache.get_raster(&raster_item, frame_id); - - // Top left: - self.add_simple_rectangle(color_image.texture_id, - &Rect::new(dot_rect.origin, - Size2D::new(dot_rect.size.width / 2.0, - dot_rect.size.height / 2.0)), - &color_image.uv_rect(), - dummy_mask_image.texture_id, - &dummy_mask_image.pixel_rect, - &colors, - None); - - // Top right: - self.add_simple_rectangle(color_image.texture_id, - &Rect::new(dot_rect.top_right(), - Size2D::new(-dot_rect.size.width / 2.0, - dot_rect.size.height / 2.0)), - &color_image.uv_rect(), - dummy_mask_image.texture_id, - &dummy_mask_image.pixel_rect, - &colors, - None); - - // Bottom right: - self.add_simple_rectangle(color_image.texture_id, - &Rect::new(dot_rect.bottom_right(), - Size2D::new(-dot_rect.size.width / 2.0, - -dot_rect.size.height / 2.0)), - &color_image.uv_rect(), - dummy_mask_image.texture_id, - &dummy_mask_image.pixel_rect, - &colors, - None); - - // Bottom left: - self.add_simple_rectangle(color_image.texture_id, - &Rect::new(dot_rect.bottom_left(), - Size2D::new(dot_rect.size.width / 2.0, - -dot_rect.size.height / 2.0)), - &color_image.uv_rect(), - dummy_mask_image.texture_id, - &dummy_mask_image.pixel_rect, - &colors, - None); - - origin += step + step; - } - } - BorderStyle::Double => { - let (outer_rect, inner_rect) = match side { - RectSide::Top | RectSide::Bottom => { - (Rect::new(rect.origin, - Size2D::new(rect.size.width, rect.size.height / 3.0)), - Rect::new(Point2D::new(rect.origin.x, - rect.origin.y + rect.size.height * 2.0 / 3.0), - Size2D::new(rect.size.width, rect.size.height / 3.0))) - } - RectSide::Left | RectSide::Right => { - (Rect::new(rect.origin, - Size2D::new(rect.size.width / 3.0, rect.size.height)), - Rect::new(Point2D::new(rect.origin.x + rect.size.width * 2.0 / 3.0, - rect.origin.y), - Size2D::new(rect.size.width / 3.0, rect.size.height))) - } - }; - self.add_color_rectangle(&outer_rect, color, resource_cache, frame_id); - self.add_color_rectangle(&inner_rect, color, resource_cache, frame_id); - } - BorderStyle::Groove | BorderStyle::Ridge => { - let (tl_rect, br_rect) = match side { - RectSide::Top | RectSide::Bottom => { - (Rect::new(rect.origin, - Size2D::new(rect.size.width, rect.size.height / 2.0)), - Rect::new(Point2D::new(rect.origin.x, - rect.origin.y + rect.size.height / 2.0), - Size2D::new(rect.size.width, rect.size.height / 2.0))) - } - RectSide::Left | RectSide::Right => { - (Rect::new(rect.origin, - Size2D::new(rect.size.width / 2.0, rect.size.height)), - Rect::new(Point2D::new(rect.origin.x + rect.size.width / 2.0, - rect.origin.y), - Size2D::new(rect.size.width / 2.0, rect.size.height))) - } - }; - let (tl_color, br_color) = groove_ridge_border_colors(color, border_style); - self.add_color_rectangle(&tl_rect, &tl_color, resource_cache, frame_id); - self.add_color_rectangle(&br_rect, &br_color, resource_cache, frame_id); - } - _ => { - self.add_color_rectangle(rect, color, resource_cache, frame_id); - } - } - } - - /// Draws a border corner. - /// - /// The following diagram attempts to explain the parameters to this function. It's an enlarged - /// version of a border corner that looks like this: - /// - /// ```notrust - /// ╭─ - /// │ - /// ``` - /// - /// The parameters are as follows: - /// - /// ```notrust - /// ⤹ corner_bounds.origin - /// ∙┈┈┈┈┈┬┈┈┈┈┈┬┈┈┈┈┈ - /// ┊ ╱ ┊ ┊ - /// ┊ ╱ ┊ ┊ - /// ┊ ╱╲ ┊ ←─┼── color1 - /// ┊╱ ╲ ┊ ┊ - /// ┊ ╲┊ ┊ - /// ├┈┈┈┈┈∙←────┼── radius_extent - /// ┊ ┊╲ ┊ - /// ┊ ┊ ╲ ┊ - /// ┊ ┊ ╲ ┊ - /// ┊ ↑ ┊ ╲ ┊ - /// ┊ │ ┊ ╲┊ - /// ├┈┈┼┈┈┴┈┈┈┈┈∙┈┈┈┈┈ - /// ┊ │ ┊↖︎ - /// ┊ ┊ corner_bounds.bottom_right() - /// ┊color0 ┊ - /// ``` - fn add_border_corner(&mut self, - border_style: BorderStyle, - corner_bounds: &Rect, - radius_extent: &Point2D, - color0: &ColorF, - color1: &ColorF, - outer_radius: &Size2D, - inner_radius: &Size2D, - resource_cache: &ResourceCache, - frame_id: FrameId, - can_tessellate: bool, - rotation_angle: BasicRotationAngle, - device_pixel_ratio: f32) { - if color0.a <= 0.0 && color1.a <= 0.0 { - return - } - - match border_style { - BorderStyle::Ridge | BorderStyle::Groove => { - let corner_center = util::rect_center(corner_bounds); - let (outer_corner_rect, inner_corner_rect, color1_rect, color0_rect) = - subdivide_border_corner(corner_bounds, &corner_center, rotation_angle); - - let (tl_color, br_color) = groove_ridge_border_colors(color0, border_style); - let (color0_outer, color1_outer, color0_inner, color1_inner) = - match rotation_angle { - BasicRotationAngle::Upright => { - (&tl_color, &tl_color, &br_color, &br_color) - } - BasicRotationAngle::Clockwise90 => { - (&br_color, &tl_color, &tl_color, &br_color) - } - BasicRotationAngle::Clockwise180 => { - (&br_color, &br_color, &tl_color, &tl_color) - } - BasicRotationAngle::Clockwise270 => { - (&tl_color, &br_color, &br_color, &tl_color) - } - }; - - // Draw the corner parts: - self.add_solid_border_corner(&outer_corner_rect, - radius_extent, - &color0_outer, - &color1_outer, - outer_radius, - inner_radius, - resource_cache, - frame_id, - can_tessellate, - rotation_angle, - device_pixel_ratio); - self.add_solid_border_corner(&inner_corner_rect, - radius_extent, - &color0_inner, - &color1_inner, - outer_radius, - inner_radius, - resource_cache, - frame_id, - can_tessellate, - rotation_angle, - device_pixel_ratio); - - // Draw the solid parts: - if util::rect_is_well_formed_and_nonempty(&color0_rect) { - self.add_color_rectangle(&color0_rect, &color0_outer, resource_cache, frame_id) - } - if util::rect_is_well_formed_and_nonempty(&color1_rect) { - self.add_color_rectangle(&color1_rect, &color1_outer, resource_cache, frame_id) - } - } - BorderStyle::Double => { - // ∙┈┈┈┈┈∙┈┈┈┈┈∙┈┈┈┈┈┐ - // ┊0 ┊1 ┊2 ┊ - // ┊ ┊ ┊ ┊ - // ┊ ┊ ┊ ┊ - // ∙┈┈┈┈┈∙┈┈┈┈┈∙┈┈┈┈┈┤ - // ┊3 ┊4 ┊5 ┊ - // ┊ ┊ ┊ ┊ - // ┊ ┊ ┊ ┊ - // ∙┈┈┈┈┈∙┈┈┈┈┈∙┈┈┈┈┈┤ - // ┊6 ┊7 ┊8 ┊ - // ┊ ┊ ┊ ┊ - // ┊ ┊ ┊ ┊ - // └┈┈┈┈┈┴┈┈┈┈┈┴┈┈┈┈┈┘ - - let width_1_3 = corner_bounds.size.width / 3.0; - let height_1_3 = corner_bounds.size.height / 3.0; - let width_2_3 = width_1_3 * 2.0; - let height_2_3 = height_1_3 * 2.0; - let size_1_3 = Size2D::new(width_1_3, height_1_3); - let size_width_2_3_height_1_3 = Size2D::new(width_2_3, height_1_3); - let size_width_1_3_height_2_3 = Size2D::new(width_1_3, height_2_3); - - let p0 = corner_bounds.origin; - let p1 = Point2D::new(corner_bounds.origin.x + width_1_3, corner_bounds.origin.y); - let p2 = Point2D::new(corner_bounds.origin.x + width_2_3, corner_bounds.origin.y); - let p3 = Point2D::new(corner_bounds.origin.x, corner_bounds.origin.y + height_1_3); - let p5 = Point2D::new(corner_bounds.origin.x + width_2_3, - corner_bounds.origin.y + height_1_3); - let p6 = Point2D::new(corner_bounds.origin.x, corner_bounds.origin.y + height_2_3); - let p7 = Point2D::new(corner_bounds.origin.x + width_1_3, - corner_bounds.origin.y + height_2_3); - let p8 = Point2D::new(corner_bounds.origin.x + width_2_3, - corner_bounds.origin.y + height_2_3); - - let outer_corner_rect; - let inner_corner_rect; - let outer_side_rect_0; - let outer_side_rect_1; - match rotation_angle { - BasicRotationAngle::Upright => { - outer_corner_rect = Rect::new(p0, size_1_3); - outer_side_rect_1 = Rect::new(p1, size_width_2_3_height_1_3); - inner_corner_rect = Rect::new(p8, size_1_3); - outer_side_rect_0 = Rect::new(p3, size_width_1_3_height_2_3) - } - BasicRotationAngle::Clockwise90 => { - outer_corner_rect = Rect::new(p2, size_1_3); - outer_side_rect_1 = Rect::new(p5, size_width_1_3_height_2_3); - inner_corner_rect = Rect::new(p6, size_1_3); - outer_side_rect_0 = Rect::new(p0, size_width_2_3_height_1_3) - } - BasicRotationAngle::Clockwise180 => { - outer_corner_rect = Rect::new(p8, size_1_3); - outer_side_rect_1 = Rect::new(p6, size_width_2_3_height_1_3); - inner_corner_rect = Rect::new(p0, size_1_3); - outer_side_rect_0 = Rect::new(p2, size_width_1_3_height_2_3) - } - BasicRotationAngle::Clockwise270 => { - outer_corner_rect = Rect::new(p6, size_1_3); - outer_side_rect_1 = Rect::new(p0, size_width_1_3_height_2_3); - inner_corner_rect = Rect::new(p2, size_1_3); - outer_side_rect_0 = Rect::new(p7, size_width_2_3_height_1_3) - } - } - - self.add_solid_border_corner(&outer_corner_rect, - radius_extent, - color0, - color1, - outer_radius, - &Size2D::new(0.0, 0.0), - resource_cache, - frame_id, - can_tessellate, - rotation_angle, - device_pixel_ratio); - - self.add_color_rectangle(&outer_side_rect_1, &color0, resource_cache, frame_id); - - self.add_solid_border_corner(&inner_corner_rect, - radius_extent, - color0, - color1, - &Size2D::new(0.0, 0.0), - inner_radius, - resource_cache, - frame_id, - can_tessellate, - rotation_angle, - device_pixel_ratio); - - self.add_color_rectangle(&outer_side_rect_0, &color1, resource_cache, frame_id); - } - _ => { - self.add_solid_border_corner(corner_bounds, - radius_extent, - color0, - color1, - outer_radius, - inner_radius, - resource_cache, - frame_id, - can_tessellate, - rotation_angle, - device_pixel_ratio) - } - } - } - - fn add_solid_border_corner(&mut self, - corner_bounds: &Rect, - radius_extent: &Point2D, - color0: &ColorF, - color1: &ColorF, - outer_radius: &Size2D, - inner_radius: &Size2D, - resource_cache: &ResourceCache, - frame_id: FrameId, - can_tessellate: bool, - rotation_angle: BasicRotationAngle, - _device_pixel_ratio: f32) { - // TODO: Check for zero width/height borders! - // FIXME(pcwalton): It's kind of messy to be matching on the rotation angle here to pick - // the right rect to draw the rounded corner in. Is there a more elegant way to do this? - let (outer_corner_rect, inner_corner_rect, color0_rect, color1_rect) = - subdivide_border_corner(corner_bounds, radius_extent, rotation_angle); - - let dummy_mask_image = resource_cache.get_dummy_mask_image(); - - // Draw the rounded part of the corner. - let quad_count = if can_tessellate { - tessellator::quad_count_for_border_corner(outer_radius, self.device_pixel_ratio) - } else { - 1 - }; - for rect_index in 0..quad_count { - let tessellated_rect; - let index; - if can_tessellate { - tessellated_rect = - outer_corner_rect.tessellate_border_corner(outer_radius, - inner_radius, - self.device_pixel_ratio, - rotation_angle, - rect_index); - index = Some(rect_index) - } else { - tessellated_rect = outer_corner_rect; - index = None - }; - - let outer_radius_x = DevicePixel::new(outer_radius.width, self.device_pixel_ratio); - let outer_radius_y = DevicePixel::new(outer_radius.height, self.device_pixel_ratio); - let inner_radius_x = DevicePixel::new(inner_radius.width, self.device_pixel_ratio); - let inner_radius_y = DevicePixel::new(inner_radius.height, self.device_pixel_ratio); - - let mask_image = match BorderRadiusRasterOp::create(outer_radius_x, - outer_radius_y, - inner_radius_x, - inner_radius_y, - false, - index, - ImageFormat::A8) { - Some(raster_item) => { - resource_cache.get_raster(&RasterItem::BorderRadius(raster_item), frame_id) - } - None => dummy_mask_image, - }; - - // FIXME(pcwalton): Either use RGBA8 textures instead of alpha masks here, or implement - // a mask combiner. - let mask_uv = RectUv::from_uv_rect_rotation_angle(&mask_image.pixel_rect, - rotation_angle, - true); - - let tessellated_rect = RectPolygon { - pos: tessellated_rect, - varyings: mask_uv, - }; - - self.add_border_corner_piece(tessellated_rect, - mask_image, - color0, - color1, - resource_cache, - rotation_angle); - } - - // Draw the inner rect. - self.add_border_corner_piece(RectPolygon { - pos: inner_corner_rect, - varyings: RectUv::zero(), - }, - dummy_mask_image, - color0, - color1, - resource_cache, - rotation_angle); - - // Draw the two solid rects. - if util::rect_is_well_formed_and_nonempty(&color0_rect) { - self.add_color_rectangle(&color0_rect, color0, resource_cache, frame_id) - } - if util::rect_is_well_formed_and_nonempty(&color1_rect) { - self.add_color_rectangle(&color1_rect, color1, resource_cache, frame_id) - } - } - - /// Draws one rectangle making up a border corner. - fn add_border_corner_piece(&mut self, - rect_pos_uv: RectPolygon>, - mask_image: &TextureCacheItem, - color0: &ColorF, - color1: &ColorF, - resource_cache: &ResourceCache, - rotation_angle: BasicRotationAngle) { - if !rect_pos_uv.is_well_formed_and_nonempty() { - return - } - - let white_image = resource_cache.get_dummy_color_image(); - - let v0; - let v1; - let muv; - match rotation_angle { - BasicRotationAngle::Upright => { - v0 = rect_pos_uv.pos.origin; - v1 = rect_pos_uv.pos.bottom_right(); - muv = RectUv { - top_left: rect_pos_uv.varyings.top_left, - top_right: rect_pos_uv.varyings.top_right, - bottom_right: rect_pos_uv.varyings.bottom_right, - bottom_left: rect_pos_uv.varyings.bottom_left, - } - } - BasicRotationAngle::Clockwise90 => { - v0 = rect_pos_uv.pos.top_right(); - v1 = rect_pos_uv.pos.bottom_left(); - muv = RectUv { - top_left: rect_pos_uv.varyings.top_right, - top_right: rect_pos_uv.varyings.top_left, - bottom_right: rect_pos_uv.varyings.bottom_left, - bottom_left: rect_pos_uv.varyings.bottom_right, - } - } - BasicRotationAngle::Clockwise180 => { - v0 = rect_pos_uv.pos.bottom_right(); - v1 = rect_pos_uv.pos.origin; - muv = RectUv { - top_left: rect_pos_uv.varyings.bottom_right, - top_right: rect_pos_uv.varyings.bottom_left, - bottom_right: rect_pos_uv.varyings.top_left, - bottom_left: rect_pos_uv.varyings.top_right, - } - } - BasicRotationAngle::Clockwise270 => { - v0 = rect_pos_uv.pos.bottom_left(); - v1 = rect_pos_uv.pos.top_right(); - muv = RectUv { - top_left: rect_pos_uv.varyings.bottom_left, - top_right: rect_pos_uv.varyings.bottom_right, - bottom_right: rect_pos_uv.varyings.top_right, - bottom_left: rect_pos_uv.varyings.top_left, - } - } - } - - self.add_rectangle(white_image.texture_id, - mask_image.texture_id, - &Rect::new(v0, Size2D::new(v1.x - v0.x, v1.y - v0.y)), - &RectUv::zero(), - &muv, - &[*color1, *color1, *color0, *color0], - PackedVertexColorMode::BorderCorner, - None) - } - - fn add_color_image_rectangle(&mut self, - v0: &Point2D, - v1: &Point2D, - color0: &ColorF, - color1: &ColorF, - color_image: &TextureCacheItem, - resource_cache: &ResourceCache, - rotation_angle: BasicRotationAngle, - flip: bool) { - if color0.a <= 0.0 || color1.a <= 0.0 { - return - } - - let vertices_rect = Rect::new(*v0, Size2D::new(v1.x - v0.x, v1.y - v0.y)); - - let color_uv = RectUv::from_uv_rect_rotation_angle(&color_image.uv_rect(), - rotation_angle, - flip); - - let dummy_mask_image = resource_cache.get_dummy_mask_image(); - - self.add_simple_rectangle(color_image.texture_id, - &vertices_rect, - &color_uv, - dummy_mask_image.texture_id, - &dummy_mask_image.pixel_rect, - &[*color0, *color0, *color1, *color1], - None); - } - - pub fn add_border(&mut self, - rect: &Rect, - info: &BorderDisplayItem, - resource_cache: &ResourceCache, - frame_id: FrameId, - device_pixel_ratio: f32) { - // TODO: If any border segment is alpha, place all in alpha pass. - // Is it ever worth batching at a per-segment level? - let radius = &info.radius; - let left = &info.left; - let right = &info.right; - let top = &info.top; - let bottom = &info.bottom; - - let tl_outer = Point2D::new(rect.origin.x, rect.origin.y); - let tl_inner = tl_outer + Point2D::new(radius.top_left.width.max(left.width), - radius.top_left.height.max(top.width)); - - let tr_outer = Point2D::new(rect.origin.x + rect.size.width, rect.origin.y); - let tr_inner = tr_outer + Point2D::new(-radius.top_right.width.max(right.width), - radius.top_right.height.max(top.width)); - - let bl_outer = Point2D::new(rect.origin.x, rect.origin.y + rect.size.height); - let bl_inner = bl_outer + Point2D::new(radius.bottom_left.width.max(left.width), - -radius.bottom_left.height.max(bottom.width)); - - let br_outer = Point2D::new(rect.origin.x + rect.size.width, - rect.origin.y + rect.size.height); - let br_inner = br_outer - Point2D::new(radius.bottom_right.width.max(right.width), - radius.bottom_right.height.max(bottom.width)); - - let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7); - let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7); - let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3); - let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3); - - let can_tessellate = tessellator::can_tessellate_border(info); - - // Edges - self.add_border_edge(&Rect::new(Point2D::new(tl_outer.x, tl_inner.y), - Size2D::new(left.width, bl_inner.y - tl_inner.y)), - RectSide::Left, - &left_color, - info.left.style, - resource_cache, - frame_id); - - 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)), - RectSide::Top, - &top_color, - info.top.style, - resource_cache, - frame_id); - - 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)), - RectSide::Right, - &right_color, - info.right.style, - resource_cache, - frame_id); - - 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)), - RectSide::Bottom, - &bottom_color, - info.bottom.style, - resource_cache, - frame_id); - - // Corners - self.add_border_corner(info.left.style, - &Rect::new(tl_outer, - Size2D::new(tl_inner.x - tl_outer.x, - tl_inner.y - tl_outer.y)), - &Point2D::new(tl_outer.x + radius.top_left.width, - tl_outer.y + radius.top_left.height), - &left_color, - &top_color, - &radius.top_left, - &info.top_left_inner_radius(), - resource_cache, - frame_id, - can_tessellate, - BasicRotationAngle::Upright, - device_pixel_ratio); - - self.add_border_corner(info.top.style, - &Rect::new(Point2D::new(tr_inner.x, tr_outer.y), - Size2D::new(tr_outer.x - tr_inner.x, - tr_inner.y - tr_outer.y)), - &Point2D::new(tr_outer.x - radius.top_right.width, - tl_outer.y + radius.top_right.height), - &right_color, - &top_color, - &radius.top_right, - &info.top_right_inner_radius(), - resource_cache, - frame_id, - can_tessellate, - BasicRotationAngle::Clockwise90, - device_pixel_ratio); - - self.add_border_corner(info.right.style, - &Rect::new(br_inner, - Size2D::new(br_outer.x - br_inner.x, - br_outer.y - br_inner.y)), - &Point2D::new(br_outer.x - radius.bottom_right.width, - br_outer.y - radius.bottom_right.height), - &right_color, - &bottom_color, - &radius.bottom_right, - &info.bottom_right_inner_radius(), - resource_cache, - frame_id, - can_tessellate, - BasicRotationAngle::Clockwise180, - device_pixel_ratio); - - self.add_border_corner(info.bottom.style, - &Rect::new(Point2D::new(bl_outer.x, bl_inner.y), - Size2D::new(bl_inner.x - bl_outer.x, - bl_outer.y - bl_inner.y)), - &Point2D::new(bl_outer.x + radius.bottom_left.width, - bl_outer.y - radius.bottom_left.height), - &left_color, - &bottom_color, - &radius.bottom_left, - &info.bottom_left_inner_radius(), - resource_cache, - frame_id, - can_tessellate, - BasicRotationAngle::Clockwise270, - device_pixel_ratio); - } - - // FIXME(pcwalton): Assumes rectangles are well-formed with origin in TL - fn add_box_shadow_corner(&mut self, - top_left: &Point2D, - bottom_right: &Point2D, - corner_area_top_left: &Point2D, - corner_area_bottom_right: &Point2D, - box_rect: &Rect, - color: &ColorF, - blur_radius: f32, - border_radius: f32, - clip_mode: BoxShadowClipMode, - resource_cache: &ResourceCache, - frame_id: FrameId, - rotation_angle: BasicRotationAngle) { - let corner_area_rect = - Rect::new(*corner_area_top_left, - Size2D::new(corner_area_bottom_right.x - corner_area_top_left.x, - corner_area_bottom_right.y - corner_area_top_left.y)); - - self.push_clip_in_rect(&corner_area_rect); - - let inverted = match clip_mode { - BoxShadowClipMode::Outset | BoxShadowClipMode::None => false, - BoxShadowClipMode::Inset => true, - }; - - let color_image = match BoxShadowRasterOp::create_corner(blur_radius, - border_radius, - box_rect, - inverted, - self.device_pixel_ratio) { - Some(raster_item) => { - let raster_item = RasterItem::BoxShadow(raster_item); - resource_cache.get_raster(&raster_item, frame_id) - } - None => resource_cache.get_dummy_color_image(), - }; - - self.add_color_image_rectangle(top_left, - bottom_right, - color, - color, - &color_image, - resource_cache, - rotation_angle, - true); - - self.pop_clip_in_rect(); - } - - fn add_box_shadow_edge(&mut self, - top_left: &Point2D, - bottom_right: &Point2D, - edge_area_top_left: &Point2D, - edge_area_bottom_right: &Point2D, - box_rect: &Rect, - color: &ColorF, - blur_radius: f32, - border_radius: f32, - clip_mode: BoxShadowClipMode, - resource_cache: &ResourceCache, - frame_id: FrameId, - rotation_angle: BasicRotationAngle) { - - if top_left.x >= bottom_right.x || top_left.y >= bottom_right.y { - return - } - - let edge_area_rect = - Rect::new(*edge_area_top_left, - Size2D::new(edge_area_bottom_right.x - edge_area_top_left.x, - edge_area_bottom_right.y - edge_area_top_left.y)); - - self.push_clip_in_rect(&edge_area_rect); - let inverted = match clip_mode { - BoxShadowClipMode::Outset | BoxShadowClipMode::None => false, - BoxShadowClipMode::Inset => true, - }; - - let color_image = match BoxShadowRasterOp::create_edge(blur_radius, - border_radius, - box_rect, - inverted, - self.device_pixel_ratio) { - Some(raster_item) => { - let raster_item = RasterItem::BoxShadow(raster_item); - resource_cache.get_raster(&raster_item, frame_id) - } - None => resource_cache.get_dummy_color_image(), - }; - - self.add_color_image_rectangle(top_left, - bottom_right, - color, - color, - &color_image, - resource_cache, - rotation_angle, - false); - self.pop_clip_in_rect(); - } -} - -trait BorderSideHelpers { +pub trait BorderSideHelpers { fn border_color(&self, scale_factor_0: f32, scale_factor_1: f32, @@ -1874,21 +44,21 @@ impl BorderSideHelpers for BorderSide { } #[derive(Debug)] -struct BoxShadowMetrics { - edge_size: f32, - tl_outer: Point2D, - tl_inner: Point2D, - tr_outer: Point2D, - tr_inner: Point2D, - bl_outer: Point2D, - bl_inner: Point2D, - br_outer: Point2D, - br_inner: Point2D, +pub struct BoxShadowMetrics { + pub edge_size: f32, + pub tl_outer: Point2D, + pub tl_inner: Point2D, + pub tr_outer: Point2D, + pub tr_inner: Point2D, + pub bl_outer: Point2D, + pub bl_inner: Point2D, + pub br_outer: Point2D, + pub br_inner: Point2D, } impl BoxShadowMetrics { - fn new(box_bounds: &Rect, border_radius: f32, blur_radius: f32) -> BoxShadowMetrics { - let outside_edge_size = 3.0 * blur_radius; + pub fn new(box_bounds: &Rect, border_radius: f32, blur_radius: f32) -> BoxShadowMetrics { + let outside_edge_size = 2.0 * blur_radius; let inside_edge_size = outside_edge_size.max(border_radius); let edge_size = outside_edge_size + inside_edge_size; let inner_rect = box_bounds.inflate(-inside_edge_size, -inside_edge_size); @@ -1907,62 +77,3 @@ impl BoxShadowMetrics { } } } - -pub fn compute_box_shadow_rect(box_bounds: &Rect, - box_offset: &Point2D, - mut spread_radius: f32, - clip_mode: BoxShadowClipMode) - -> Rect { - let mut rect = (*box_bounds).clone(); - rect.origin.x += box_offset.x; - rect.origin.y += box_offset.y; - - if clip_mode == BoxShadowClipMode::Inset { - spread_radius = -spread_radius; - }; - - rect.inflate(spread_radius, spread_radius) -} - -/// Returns the top/left and bottom/right colors respectively. -fn groove_ridge_border_colors(color: &ColorF, border_style: BorderStyle) -> (ColorF, ColorF) { - match (color, border_style) { - (&ColorF { - r: 0.0, - g: 0.0, - b: 0.0, - a: _ - }, BorderStyle::Groove) => { - // Handle black specially (matching the new browser consensus here). - (ColorF::new(0.3, 0.3, 0.3, color.a), ColorF::new(0.7, 0.7, 0.7, color.a)) - } - (&ColorF { - r: 0.0, - g: 0.0, - b: 0.0, - a: _ - }, BorderStyle::Ridge) => { - // As above. - (ColorF::new(0.7, 0.7, 0.7, color.a), ColorF::new(0.3, 0.3, 0.3, color.a)) - } - (_, BorderStyle::Groove) => (util::scale_color(color, 1.0 / 3.0), *color), - (_, _) => (*color, util::scale_color(color, 2.0 / 3.0)), - } -} - -/// Subdivides the border corner into four quadrants and returns them in the order of outer corner, -/// inner corner, color 0 and color 1, respectively. See the diagram in the documentation for -/// `add_border_corner` for more information on what these values represent. -fn subdivide_border_corner(corner_bounds: &Rect, - point: &Point2D, - rotation_angle: BasicRotationAngle) - -> (Rect, Rect, Rect, Rect) { - let (tl, tr, br, bl) = util::subdivide_rect_into_quadrants(corner_bounds, point); - match rotation_angle { - BasicRotationAngle::Upright => (tl, br, bl, tr), - BasicRotationAngle::Clockwise90 => (tr, bl, tl, br), - BasicRotationAngle::Clockwise180 => (br, tl, tr, bl), - BasicRotationAngle::Clockwise270 => (bl, tr, br, tl), - } -} - diff --git a/src/bsptree.rs b/src/bsptree.rs new file mode 100644 index 0000000000..be9b2c8f3e --- /dev/null +++ b/src/bsptree.rs @@ -0,0 +1,318 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use euclid::{Point2D, Rect}; +use internal_types::DevicePixel; +use std::i32; +use std::mem; +use util::{rect_contains_rect, rect_from_points}; + +// TODO(gw): Support enum type for rect that can be axis-aligned or a (projected) polygon. + +#[derive(Debug, Copy, Clone)] +struct BspNodeIndex(usize); + +#[derive(Debug, Copy, Clone)] +struct BspItemIndex(usize); + +#[derive(Debug, Copy, Clone)] +enum SplitKind { + Horizontal, + Vertical, +} + +pub struct BspItem { + rect: Rect, + pub data: T, +} + +pub struct BspNode { + rect: Rect, + cover_items: Vec, + partial_items: Vec, + child_index: Option, +} + +impl BspNode { + fn new(rect: Rect) -> BspNode { + BspNode { + rect: rect, + cover_items: Vec::new(), + partial_items: Vec::new(), + child_index: None, + } + } + + fn new_with_capacity(rect: Rect, capacity: usize) -> BspNode { + BspNode { + rect: rect, + cover_items: Vec::with_capacity(capacity), + partial_items: Vec::with_capacity(capacity), + child_index: None, + } + } + + fn add(&mut self, rect: &Rect, item_index: BspItemIndex) { + debug_assert!(self.rect.intersects(rect)); + if rect_contains_rect(rect, &self.rect) { + self.cover_items.push(item_index); + } else { + self.partial_items.push(item_index); + } + } +} + +pub struct BspTree { + nodes: Vec, + pub items: Vec>, +} + +impl BspTree { + pub fn new(bounding_rect: Rect) -> BspTree { + let root = BspNode::new(bounding_rect); + + BspTree { + nodes: vec![root], + items: Vec::new(), + } + } + + #[inline(always)] + fn node(&self, node_index: BspNodeIndex) -> &BspNode { + let BspNodeIndex(node_index) = node_index; + &self.nodes[node_index] + } + + #[inline(always)] + fn node_mut(&mut self, node_index: BspNodeIndex) -> &mut BspNode { + let BspNodeIndex(node_index) = node_index; + &mut self.nodes[node_index] + } + + pub fn add(&mut self, + rect: &Rect, + data: T) { + let item_index = BspItemIndex(self.items.len()); + self.items.push(BspItem { + rect: *rect, + data: data, + }); + let root = self.node_mut(BspNodeIndex(0)); + root.add(rect, item_index); + } + + fn split_internal(&mut self, + node_index: BspNodeIndex, + split_kind: SplitKind, + level: i32, + current_cover_items: &Vec, + cover_buffer: &mut Vec, + partial_buffer: &mut Vec, + device_pixel_ratio: f32, + f: &mut F) where F: FnMut(&Rect, &mut Vec, &mut Vec) { + let mut partial_items = mem::replace(&mut self.node_mut(node_index) + .partial_items, + Vec::new()); + + // TODO(gw): Optimize this by making cover items a stack! + let mut current_cover_items = current_cover_items.clone(); + for item_index in &self.node(node_index).cover_items { + let BspItemIndex(item_index) = *item_index; + let item = &self.items[item_index]; + current_cover_items.push(item.data); + } + + let node_rect = self.node(node_index).rect; + let mut do_split = true; + + if partial_items.is_empty() { + do_split = false; + } + + let min_size = 8; + if node_rect.size.width.0 <= min_size && + node_rect.size.height.0 <= min_size { + do_split = false; + } + + let min_area = 64 * 64; + if node_rect.size.width.0 * node_rect.size.height.0 <= min_area && + partial_items.len() > 2 && + partial_items.len() + current_cover_items.len() < 8 { + do_split = false; + } + + if !do_split { + let node = self.node(node_index); + + cover_buffer.clear(); + for item in ¤t_cover_items { + cover_buffer.push(*item); + } + + partial_buffer.clear(); + for item_index in &partial_items { + let BspItemIndex(item_index) = *item_index; + let item = &self.items[item_index]; + partial_buffer.push(item.data); + } + + f(&node_rect, cover_buffer, partial_buffer); + return; + } + + // Sort by split kind, find median. + // TODO(gw): Find a faster heuristic for splitting that gives good results? + let nx0 = node_rect.origin.x; + let ny0 = node_rect.origin.y; + let nx1 = nx0 + node_rect.size.width; + let ny1 = ny0 + node_rect.size.height; + + //let mut indent = String::new(); + //for _ in 0..level { + // indent.push_str(" "); + //} + + let cx = ((nx0.0 as f32 + nx1.0 as f32) * 0.5).round() as i32; + let cy = ((ny0.0 as f32 + ny1.0 as f32) * 0.5).round() as i32; + let center = Point2D::new(DevicePixel::from_i32(cx), DevicePixel::from_i32(cy)); + let mut best_distance = Point2D::new(i32::MAX, i32::MAX); + let mut split_pos = center; + + for item_index in &partial_items { + let BspItemIndex(item_index) = *item_index; + let item = &self.items[item_index]; + + // Only a valid split point if it sits exactly on a device pixel! + let x0 = item.rect.origin.x; + let x1 = x0 + item.rect.size.width; + + if x0 > nx0 && x0 < nx1 { + let d = (x0.0 - center.x.0).abs(); + if d < best_distance.x { + best_distance.x = d; + split_pos.x = x0; + } + } + if x1 > nx0 && x1 < nx1 { + let d = (x1.0 - center.x.0).abs(); + if d < best_distance.x { + best_distance.x = d; + split_pos.x = x1; + } + } + + let y0 = item.rect.origin.y; + let y1 = y0 + item.rect.size.height; + + if y0 > ny0 && y0 < ny1 { + let d = (y0.0 - center.y.0).abs(); + if d < best_distance.y { + best_distance.y = d; + split_pos.y = y0; + } + } + if y1 > ny0 && y1 < ny1 { + let d = (y1.0 - center.y.0).abs(); + if d < best_distance.y { + best_distance.y = d; + split_pos.y = y1; + } + } + } + + let (split_kind, split) = match split_kind { + SplitKind::Horizontal => { + if best_distance.y < i32::MAX { + (SplitKind::Horizontal, split_pos.y) + } else { + debug_assert!(best_distance.x != i32::MAX); + (SplitKind::Vertical, split_pos.x) + } + } + SplitKind::Vertical => { + if best_distance.x < i32::MAX { + (SplitKind::Vertical, split_pos.x) + } else { + debug_assert!(best_distance.y != i32::MAX); + (SplitKind::Horizontal, split_pos.y) + } + } + }; + + let (c0, c1, next_split) = match split_kind { + SplitKind::Horizontal => { + let r0 = rect_from_points(nx0, ny0, nx1, split); + let r1 = rect_from_points(nx0, split, nx1, ny1); + let mut c0 = BspNode::new_with_capacity(r0, partial_items.len()); + let mut c1 = BspNode::new_with_capacity(r1, partial_items.len()); + for key in partial_items.drain(..) { + let BspItemIndex(i) = key; + let item_rect = &self.items[i].rect; + if item_rect.origin.y < split { + c0.add(item_rect, key); + } + if item_rect.origin.y + item_rect.size.height > split { + c1.add(item_rect, key); + } + } + (c0, c1, SplitKind::Vertical) + } + SplitKind::Vertical => { + let r0 = rect_from_points(nx0, ny0, split, ny1); + let r1 = rect_from_points(split, ny0, nx1, ny1); + let mut c0 = BspNode::new_with_capacity(r0, partial_items.len()); + let mut c1 = BspNode::new_with_capacity(r1, partial_items.len()); + for key in partial_items.drain(..) { + let BspItemIndex(i) = key; + let item_rect = &self.items[i].rect; + if item_rect.origin.x < split { + c0.add(item_rect, key); + } + if item_rect.origin.x + item_rect.size.width > split { + c1.add(item_rect, key); + } + } + (c0, c1, SplitKind::Horizontal) + } + }; + + let ci0 = BspNodeIndex(self.nodes.len() + 0); + let ci1 = BspNodeIndex(self.nodes.len() + 1); + self.node_mut(node_index).child_index = Some(ci0); + self.nodes.push(c0); + self.nodes.push(c1); + self.split_internal(ci0, + next_split, + level+1, + ¤t_cover_items, + cover_buffer, + partial_buffer, + device_pixel_ratio, + f); + self.split_internal(ci1, + next_split, + level+1, + ¤t_cover_items, + cover_buffer, + partial_buffer, + device_pixel_ratio, + f); + } + + pub fn split(&mut self, + device_pixel_ratio: f32, + f: &mut F) where F: FnMut(&Rect, &mut Vec, &mut Vec) { + let mut cover_buffer = Vec::new(); + let mut partial_buffer = Vec::new(); + self.split_internal(BspNodeIndex(0), + SplitKind::Horizontal, + 0, + &Vec::new(), + &mut cover_buffer, + &mut partial_buffer, + device_pixel_ratio, + f); + } +} diff --git a/src/cache_shared.glsl b/src/cache_shared.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/debug_render.rs b/src/debug_render.rs index 50cf05f404..c3c3bce3c4 100644 --- a/src/debug_render.rs +++ b/src/debug_render.rs @@ -7,7 +7,7 @@ use device::{Device, ProgramId, VAOId, TextureId, VertexFormat}; use device::{TextureFilter, VertexUsageHint}; use euclid::{Matrix4D, Point2D, Size2D, Rect}; use gleam::gl; -use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE}; +use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, DevicePixel}; use internal_types::{DebugFontVertex, DebugColorVertex, RenderTargetMode, PackedColor}; use std::f32; use webrender_traits::{ColorF, ImageFormat}; @@ -29,8 +29,8 @@ pub struct DebugRenderer { impl DebugRenderer { pub fn new(device: &mut Device) -> DebugRenderer { - let font_program_id = device.create_program("debug_font"); - let color_program_id = device.create_program("debug_color"); + let font_program_id = device.create_program("debug_font", "shared_other"); + let color_program_id = device.create_program("debug_color", "shared_other"); let font_vao = device.create_vao(VertexFormat::DebugFont, None); let line_vao = device.create_vao(VertexFormat::DebugColor, None); @@ -147,16 +147,16 @@ impl DebugRenderer { #[allow(dead_code)] pub fn add_line(&mut self, - x0: f32, - y0: f32, + x0: DevicePixel, + y0: DevicePixel, color0: &ColorF, - x1: f32, - y1: f32, + x1: DevicePixel, + y1: DevicePixel, color1: &ColorF) { let color0 = PackedColor::from_color(color0); let color1 = PackedColor::from_color(color1); - self.line_vertices.push(DebugColorVertex::new(x0, y0, color0)); - self.line_vertices.push(DebugColorVertex::new(x1, y1, color1)); + self.line_vertices.push(DebugColorVertex::new(x0.0 as f32, y0.0 as f32, color0)); + self.line_vertices.push(DebugColorVertex::new(x1.0 as f32, y1.0 as f32, color1)); } pub fn render(&mut self, diff --git a/src/device.rs b/src/device.rs index 570be098af..eb93dd3d94 100644 --- a/src/device.rs +++ b/src/device.rs @@ -5,7 +5,7 @@ use euclid::Matrix4D; use fnv::FnvHasher; use gleam::gl; -use internal_types::{PackedColor, PackedVertex, PackedVertexForQuad}; +use internal_types::{PackedVertex, PackedVertexForQuad}; use internal_types::{PackedVertexForTextureCacheUpdate, RenderTargetMode, TextureSampler}; use internal_types::{VertexAttribute, DebugFontVertex, DebugColorVertex}; //use notify::{self, Watcher}; @@ -32,7 +32,7 @@ const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA; const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA_EXT; #[cfg(target_os = "linux")] -const SHADER_VERSION: &'static str = "#version 130\n"; +const SHADER_VERSION: &'static str = "#version 150\n"; #[cfg(target_os = "macos")] const SHADER_VERSION: &'static str = "#version 150\n"; @@ -43,9 +43,9 @@ const SHADER_VERSION: &'static str = "#version 150\n"; #[cfg(target_os = "android")] const SHADER_VERSION: &'static str = "#version 300 es\n"; -static FRAGMENT_SHADER_PREAMBLE: &'static str = "gl3_common.fs.glsl"; -static VERTEX_SHADER_PREAMBLE: &'static str = "gl3_common.vs.glsl"; +static SHADER_PREAMBLE: &'static str = "shared.glsl"; +/* static QUAD_VERTICES: [PackedVertex; 6] = [ PackedVertex { x: 0.0, y: 0.0, @@ -108,6 +108,7 @@ static QUAD_VERTICES: [PackedVertex; 6] = [ tile_params_index: 0, }, ]; +*/ lazy_static! { pub static ref MAX_TEXTURE_SIZE: gl::GLint = { @@ -284,11 +285,6 @@ impl VertexFormat { } VertexFormat::Triangles => { gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::ColorRectTL as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoordRectTop as - gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::MaskTexCoordRectTop as gl::GLuint); - gl::enable_vertex_attrib_array(VertexAttribute::Misc as gl::GLuint); self.set_divisors(0); @@ -300,30 +296,6 @@ impl VertexFormat { false, vertex_stride as gl::GLint, 0 + vertex_stride * offset); - gl::vertex_attrib_pointer(VertexAttribute::ColorRectTL as gl::GLuint, - 4, - gl::UNSIGNED_BYTE, - false, - vertex_stride as gl::GLint, - 8 + vertex_stride * offset); - gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoordRectTop as gl::GLuint, - 2, - gl::FLOAT, - false, - vertex_stride as gl::GLint, - 12 + vertex_stride * offset); - gl::vertex_attrib_pointer(VertexAttribute::MaskTexCoordRectTop as gl::GLuint, - 2, - gl::UNSIGNED_SHORT, - false, - vertex_stride as gl::GLint, - 20 + vertex_stride * offset); - gl::vertex_attrib_pointer(VertexAttribute::Misc as gl::GLuint, - 4, - gl::UNSIGNED_BYTE, - false, - vertex_stride as gl::GLint, - 24 + vertex_stride * offset); } VertexFormat::RasterOp => { gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint); @@ -415,7 +387,7 @@ impl VertexFormat { } impl TextureId { - fn bind(&self) { + pub fn bind(&self) { let TextureId(id) = *self; gl::bind_texture(gl::TEXTURE_2D, id); } @@ -478,6 +450,7 @@ struct Program { u_transform: gl::GLint, vs_path: PathBuf, fs_path: PathBuf, + prefix: Option, vs_id: Option, fs_id: Option, } @@ -545,6 +518,7 @@ impl Program { } false } else { + //println!("{}", gl::get_program_info_log(self.id)); true } } @@ -590,7 +564,7 @@ impl Drop for VAO { pub struct TextureId(pub gl::GLuint); // TODO: HACK: Should not be public! #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] -pub struct ProgramId(gl::GLuint); +pub struct ProgramId(pub gl::GLuint); #[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)] pub struct VAOId(gl::GLuint); @@ -606,23 +580,28 @@ struct IBOId(gl::GLuint); #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] pub struct GpuProfile { - active_query: usize, - gl_queries: Vec, - first_frame: bool, + next_query: usize, + qids: Vec, } #[cfg(target_os = "android")] pub struct GpuProfile; +const QUERY_COUNT: i32 = 4; + impl GpuProfile { #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] pub fn new() -> GpuProfile { - let queries = gl::gen_queries(4); + let queries = gl::gen_queries(QUERY_COUNT); + + for q in &queries { + gl::begin_query(gl::TIME_ELAPSED, *q); + gl::end_query(gl::TIME_ELAPSED); + } GpuProfile { - active_query: 0, - gl_queries: queries, - first_frame: true, + qids: queries, + next_query: 0, } } @@ -631,41 +610,29 @@ impl GpuProfile { GpuProfile } + #[cfg(any(target_os = "android", target_os = "gonk"))] + pub fn get(&mut self) -> u64 { + 0 + } + + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] + pub fn get(&mut self) -> u64 { + let qi = self.next_query; + gl::get_query_object_ui64v(self.qids[qi], gl::QUERY_RESULT) + } + #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] pub fn begin(&mut self) { - let qid = self.gl_queries[self.active_query]; - gl::begin_query(gl::TIME_ELAPSED, qid); + gl::begin_query(gl::TIME_ELAPSED, self.qids[self.next_query]); } #[cfg(target_os = "android")] pub fn begin(&mut self) {} #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] - pub fn end(&mut self) -> u64 { + pub fn end(&mut self) { gl::end_query(gl::TIME_ELAPSED); - - // Wait until the previous results are available - let last_qid = if self.active_query == 0 { - (self.gl_queries.len() - 1) as u32 - } else { - (self.active_query - 1) as u32 - }; - - self.active_query += 1; - if self.active_query == self.gl_queries.len() { - self.active_query = 0 - } - - if self.first_frame { - self.first_frame = false; - return 0 - } - - if gl::get_query_object_iv(last_qid, gl::QUERY_RESULT_AVAILABLE) == 1 { - gl::get_query_object_ui64v(last_qid, gl::QUERY_RESULT) - } else { - 0 - } + self.next_query = (self.next_query + 1) % QUERY_COUNT as usize; } #[cfg(target_os = "android")] @@ -675,7 +642,7 @@ impl GpuProfile { #[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))] impl Drop for GpuProfile { fn drop(&mut self) { - gl::delete_queries(&self.gl_queries); + gl::delete_queries(&self.qids); } } @@ -776,6 +743,8 @@ pub struct Device { // device state bound_color_texture: TextureId, bound_mask_texture: TextureId, + bound_layer_textures: [TextureId; 8], + bound_cache_texture: TextureId, bound_program: ProgramId, bound_vao: VAOId, bound_fbo: FBOId, @@ -793,8 +762,7 @@ pub struct Device { vaos: HashMap>, // misc. - vertex_shader_preamble: String, - fragment_shader_preamble: String, + shader_preamble: String, //file_watcher: FileWatcherThread, // Used on android only @@ -809,17 +777,10 @@ impl Device { //let file_watcher = FileWatcherThread::new(file_changed_handler); let mut path = resource_path.clone(); - path.push(VERTEX_SHADER_PREAMBLE); + path.push(SHADER_PREAMBLE); let mut f = File::open(&path).unwrap(); - let mut vertex_shader_preamble = String::new(); - f.read_to_string(&mut vertex_shader_preamble).unwrap(); - //file_watcher.add_watch(path); - - let mut path = resource_path.clone(); - path.push(FRAGMENT_SHADER_PREAMBLE); - let mut f = File::open(&path).unwrap(); - let mut fragment_shader_preamble = String::new(); - f.read_to_string(&mut fragment_shader_preamble).unwrap(); + let mut shader_preamble = String::new(); + f.read_to_string(&mut shader_preamble).unwrap(); //file_watcher.add_watch(path); Device { @@ -829,6 +790,16 @@ impl Device { bound_color_texture: TextureId(0), bound_mask_texture: TextureId(0), + bound_cache_texture: TextureId(0), + bound_layer_textures: [ TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + TextureId(0), + ], bound_program: ProgramId(0), bound_vao: VAOId(0), bound_fbo: FBOId(0), @@ -839,8 +810,7 @@ impl Device { programs: HashMap::with_hasher(Default::default()), vaos: HashMap::with_hasher(Default::default()), - vertex_shader_preamble: vertex_shader_preamble, - fragment_shader_preamble: fragment_shader_preamble, + shader_preamble: shader_preamble, next_vao_id: 1, //file_watcher: file_watcher, @@ -849,7 +819,7 @@ impl Device { pub fn compile_shader(path: &PathBuf, shader_type: gl::GLenum, - shader_preamble: &str, + shader_preamble: &[String], panic_on_fail: bool) -> Option { debug!("compile {:?}", path); @@ -857,7 +827,9 @@ impl Device { let mut f = File::open(&path).unwrap(); let mut s = String::new(); s.push_str(SHADER_VERSION); - s.push_str(shader_preamble); + for prefix in shader_preamble { + s.push_str(&prefix); + } f.read_to_string(&mut s).unwrap(); let id = gl::create_shader(shader_type); @@ -873,6 +845,7 @@ impl Device { None } else { + //println!("{}", gl::get_shader_info_log(id)); Some(id) } } @@ -894,6 +867,16 @@ impl Device { gl::active_texture(gl::TEXTURE1); gl::bind_texture(gl::TEXTURE_2D, 0); + self.bound_cache_texture = TextureId(0); + gl::active_texture(gl::TEXTURE2); + gl::bind_texture(gl::TEXTURE_2D, 0); + + for i in 0..self.bound_layer_textures.len() { + self.bound_layer_textures[i] = TextureId(0); + gl::active_texture(gl::TEXTURE3 + i as u32); + gl::bind_texture(gl::TEXTURE_2D, 0); + } + // Shader state self.bound_program = ProgramId(0); gl::use_program(0); @@ -932,6 +915,28 @@ impl Device { } } + pub fn bind_cache_texture(&mut self, texture_id: TextureId) { + debug_assert!(self.inside_frame); + + if self.bound_cache_texture != texture_id { + self.bound_cache_texture = texture_id; + gl::active_texture(gl::TEXTURE2); + texture_id.bind(); + gl::active_texture(gl::TEXTURE0); + } + } + + pub fn bind_layer_texture(&mut self, layer: usize, texture_id: TextureId) { + debug_assert!(self.inside_frame); + + if self.bound_layer_textures[layer] != texture_id { + self.bound_layer_textures[layer] = texture_id; + gl::active_texture(gl::TEXTURE3 + layer as u32); + texture_id.bind(); + gl::active_texture(gl::TEXTURE0); + } + } + pub fn bind_render_target(&mut self, texture_id: Option) { debug_assert!(self.inside_frame); @@ -1028,7 +1033,7 @@ impl Device { gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint); } - fn upload_2d_texture_image(&mut self, + fn upload_texture_image(&mut self, width: u32, height: u32, internal_format: u32, @@ -1044,15 +1049,6 @@ impl Device { pixels); } - fn upload_texture_image(&mut self, - width: u32, - height: u32, - internal_format: u32, - format: u32, - pixels: Option<&[u8]>) { - self.upload_2d_texture_image(width, height, internal_format, format, pixels) - } - fn deinit_texture_image(&mut self) { gl::tex_image_2d(gl::TEXTURE_2D, 0, @@ -1107,7 +1103,7 @@ impl Device { RenderTargetMode::RenderTarget => { self.bind_color_texture(texture_id); self.set_texture_parameters(filter); - self.upload_2d_texture_image(width, height, internal_format, gl_format, None); + self.upload_texture_image(width, height, internal_format, gl_format, None); self.create_fbo_for_texture_if_necessary(texture_id); } RenderTargetMode::None => { @@ -1208,28 +1204,16 @@ impl Device { texture.fbo_ids.clear(); } - pub fn init_texture_if_necessary(&mut self, - texture_id: TextureId, - width: u32, - height: u32, - format: ImageFormat, - filter: TextureFilter, - mode: RenderTargetMode) { - debug_assert!(self.inside_frame); - { - let texture = self.textures.get_mut(&texture_id).expect("Didn't find texture!"); - if texture.format == format && - texture.width == width && - texture.height == height && - texture.filter == filter && - texture.mode == mode { - return - } - } - self.init_texture(texture_id, width, height, format, filter, mode, None) + pub fn create_program(&mut self, + base_filename: &str, + include_filename: &str) -> ProgramId { + self.create_program_with_prefix(base_filename, include_filename, None) } - pub fn create_program(&mut self, base_filename: &str) -> ProgramId { + pub fn create_program_with_prefix(&mut self, + base_filename: &str, + include_filename: &str, + prefix: Option) -> ProgramId { debug_assert!(self.inside_frame); let pid = gl::create_program(); @@ -1242,11 +1226,26 @@ impl Device { fs_path.push(&format!("{}.fs.glsl", base_filename)); //self.file_watcher.add_watch(fs_path.clone()); + let mut include_path = self.resource_path.clone(); + include_path.push(&format!("{}.glsl", include_filename)); + let mut f = File::open(&include_path).unwrap(); + let mut include = String::new(); + f.read_to_string(&mut include).unwrap(); + + let mut shared_path = self.resource_path.clone(); + shared_path.push(&format!("{}.glsl", base_filename)); + if let Ok(mut f) = File::open(&shared_path) { + let mut shared_code = String::new(); + f.read_to_string(&mut shared_code).unwrap(); + include.push_str(&shared_code); + } + let program = Program { id: pid, u_transform: -1, vs_path: vs_path, fs_path: fs_path, + prefix: prefix, vs_id: None, fs_id: None, }; @@ -1256,26 +1255,44 @@ impl Device { debug_assert!(self.programs.contains_key(&program_id) == false); self.programs.insert(program_id, program); - self.load_program(program_id, true); + self.load_program(program_id, include, true); program_id } fn load_program(&mut self, program_id: ProgramId, + include: String, panic_on_fail: bool) { debug_assert!(self.inside_frame); let program = self.programs.get_mut(&program_id).unwrap(); + let mut vs_preamble = Vec::new(); + let mut fs_preamble = Vec::new(); + + vs_preamble.push("#define WR_VERTEX_SHADER\n".to_owned()); + fs_preamble.push("#define WR_FRAGMENT_SHADER\n".to_owned()); + + if let Some(ref prefix) = program.prefix { + vs_preamble.push(prefix.clone()); + fs_preamble.push(prefix.clone()); + } + + vs_preamble.push(self.shader_preamble.to_owned()); + fs_preamble.push(self.shader_preamble.to_owned()); + + vs_preamble.push(include.clone()); + fs_preamble.push(include); + // todo(gw): store shader ids so they can be freed! let vs_id = Device::compile_shader(&program.vs_path, gl::VERTEX_SHADER, - &*self.vertex_shader_preamble, + &vs_preamble, panic_on_fail); let fs_id = Device::compile_shader(&program.fs_path, gl::FRAGMENT_SHADER, - &*self.fragment_shader_preamble, + &fs_preamble, panic_on_fail); match (vs_id, fs_id) { @@ -1339,10 +1356,48 @@ impl Device { if u_device_pixel_ratio != -1 { gl::uniform_1f(u_device_pixel_ratio, self.device_pixel_ratio); } + + let u_layer0 = gl::get_uniform_location(program.id, "sLayer0"); + if u_layer0 != -1 { + gl::uniform_1i(u_layer0, TextureSampler::CompositeLayer0 as i32); + } + let u_layer1 = gl::get_uniform_location(program.id, "sLayer1"); + if u_layer1 != -1 { + gl::uniform_1i(u_layer1, TextureSampler::CompositeLayer1 as i32); + } + let u_layer2 = gl::get_uniform_location(program.id, "sLayer2"); + if u_layer2 != -1 { + gl::uniform_1i(u_layer2, TextureSampler::CompositeLayer2 as i32); + } + let u_layer3 = gl::get_uniform_location(program.id, "sLayer3"); + if u_layer3 != -1 { + gl::uniform_1i(u_layer3, TextureSampler::CompositeLayer3 as i32); + } + let u_layer4 = gl::get_uniform_location(program.id, "sLayer4"); + if u_layer4 != -1 { + gl::uniform_1i(u_layer4, TextureSampler::CompositeLayer4 as i32); + } + let u_layer5 = gl::get_uniform_location(program.id, "sLayer5"); + if u_layer5 != -1 { + gl::uniform_1i(u_layer5, TextureSampler::CompositeLayer5 as i32); + } + let u_layer6 = gl::get_uniform_location(program.id, "sLayer6"); + if u_layer6 != -1 { + gl::uniform_1i(u_layer6, TextureSampler::CompositeLayer6 as i32); + } + let u_layer7 = gl::get_uniform_location(program.id, "sLayer7"); + if u_layer7 != -1 { + gl::uniform_1i(u_layer7, TextureSampler::CompositeLayer7 as i32); + } + let u_cache = gl::get_uniform_location(program.id, "sCache"); + if u_cache != -1 { + gl::uniform_1i(u_cache, TextureSampler::Cache as i32); + } } } } +/* pub fn refresh_shader(&mut self, path: PathBuf) { let mut vs_preamble_path = self.resource_path.clone(); vs_preamble_path.push(VERTEX_SHADER_PREAMBLE); @@ -1377,67 +1432,34 @@ impl Device { for program_id in programs_to_update { self.load_program(program_id, false); } - } + }*/ pub fn get_uniform_location(&self, program_id: ProgramId, name: &str) -> UniformLocation { let ProgramId(program_id) = program_id; UniformLocation(gl::get_uniform_location(program_id, name)) } - pub fn set_uniform_2f(&self, uniform: UniformLocation, x: f32, y: f32) { +/* + pub fn set_uniform_1i(&self, uniform: UniformLocation, x: i32) { debug_assert!(self.inside_frame); let UniformLocation(location) = uniform; - gl::uniform_2f(location, x, y); - } - - pub fn set_uniform_4f(&self, - uniform: UniformLocation, - x: f32, - y: f32, - z: f32, - w: f32) { - debug_assert!(self.inside_frame); - let UniformLocation(location) = uniform; - gl::uniform_4f(location, x, y, z, w); + gl::uniform_1i(location, x); } +*/ - pub fn set_uniform_vec4_array(&self, - uniform: UniformLocation, - vectors: &[f32]) { + pub fn set_uniform_2f(&self, uniform: UniformLocation, x: f32, y: f32) { debug_assert!(self.inside_frame); let UniformLocation(location) = uniform; - gl::uniform_4fv(location, vectors); + gl::uniform_2f(location, x, y); } - pub fn set_uniform_mat4_array(&self, - uniform: UniformLocation, - matrices: &[Matrix4D]) { +/* + pub fn set_uniform_4f(&self, uniform: UniformLocation, x: f32, y: f32, z: f32, w: f32) { debug_assert!(self.inside_frame); let UniformLocation(location) = uniform; - - // TODO(gw): Avoid alloc here by storing as 3x3 matrices at a higher level... - let mut floats = Vec::new(); - for matrix in matrices { - floats.push(matrix.m11); - floats.push(matrix.m12); - floats.push(matrix.m13); - floats.push(matrix.m14); - floats.push(matrix.m21); - floats.push(matrix.m22); - floats.push(matrix.m23); - floats.push(matrix.m24); - floats.push(matrix.m31); - floats.push(matrix.m32); - floats.push(matrix.m33); - floats.push(matrix.m34); - floats.push(matrix.m41); - floats.push(matrix.m42); - floats.push(matrix.m43); - floats.push(matrix.m44); - } - - gl::uniform_matrix_4fv(location, false, &floats); + gl::uniform_4f(location, x, y, z, w); } +*/ fn set_uniforms(&self, program: &Program, transform: &Matrix4D) { debug_assert!(self.inside_frame); @@ -1589,28 +1611,6 @@ impl Device { self.create_vao_with_vbos(format, main_vbo_id, aux_vbo_id, ibo_id, 0, true) } - #[inline(never)] - pub fn create_similar_vao(&mut self, - format: VertexFormat, - source_vao_id: VAOId, - offset: gl::GLuint) - -> VAOId { - let &VAO { - main_vbo_id, - aux_vbo_id, - ibo_id, - .. - } = self.vaos.get(&source_vao_id).expect("Bad VAO ID in `create_similar_vao()`!"); - self.create_vao_with_vbos(format, main_vbo_id, aux_vbo_id, ibo_id, offset, false) - } - - pub fn create_quad_vertex_buffer(&mut self) -> VBOId { - let buffer_id = VBOId(gl::gen_buffers(1)[0]); - buffer_id.bind(); - gl::buffer_data(gl::ARRAY_BUFFER, &QUAD_VERTICES, gl::STATIC_DRAW); - buffer_id - } - pub fn update_vao_main_vertices(&mut self, vao_id: VAOId, vertices: &[V], @@ -1624,19 +1624,6 @@ impl Device { gl::buffer_data(gl::ARRAY_BUFFER, &vertices, usage_hint.to_gl()); } - pub fn update_vao_aux_vertices(&mut self, - vao_id: VAOId, - vertices: &[V], - usage_hint: VertexUsageHint) { - debug_assert!(self.inside_frame); - - let vao = self.vaos.get(&vao_id).unwrap(); - debug_assert!(self.bound_vao == vao_id); - - vao.aux_vbo_id.as_ref().unwrap().bind(); - gl::buffer_data(gl::ARRAY_BUFFER, &vertices, usage_hint.to_gl()); - } - pub fn update_vao_indices(&mut self, vao_id: VAOId, indices: &[I], @@ -1673,20 +1660,21 @@ impl Device { vertex_count); } - pub fn draw_triangles_instanced_u16(&mut self, - first_vertex: i32, - index_count: i32, - instance_count: i32) { + pub fn draw_indexed_triangles_instanced_u16(&mut self, + index_count: i32, + instance_count: i32) { debug_assert!(self.inside_frame); - gl::draw_arrays_instanced(gl::TRIANGLES, first_vertex as i32, index_count, instance_count); + gl::draw_elements_instanced(gl::TRIANGLES, index_count, gl::UNSIGNED_SHORT, 0, instance_count); } +/* pub fn delete_vao(&mut self, vao_id: VAOId) { self.vaos.remove(&vao_id).expect(&format!("unable to remove vao {:?}", vao_id)); if self.bound_vao == vao_id { self.bound_vao = VAOId(0); } } +*/ pub fn end_frame(&mut self) { self.bind_render_target(None); diff --git a/src/frame.rs b/src/frame.rs index 23bd6607c7..8179550987 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -3,34 +3,28 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use batch::{MAX_MATRICES_PER_BATCH, OffsetParams}; -use device::{TextureId}; use euclid::{Matrix4D, Point2D, Point3D, Point4D, Rect, Size2D}; use fnv::FnvHasher; use geometry::ray_intersects_rect; -use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection, BatchInfo, BatchUpdate}; -use internal_types::{BatchUpdateList, BatchUpdateOp, ChildLayerIndex, ClearInfo}; +use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection}; +use internal_types::{ChildLayerIndex, ClearInfo}; use internal_types::{CompositeBatchInfo, CompositeBatchJob, CompositionOp}; -use internal_types::{DrawCall, DrawCommand, DrawCompositeBatchInfo}; -use internal_types::{DrawCompositeBatchJob, DrawLayer, DrawListGroupId}; +use internal_types::{DrawCall}; +use internal_types::{DrawCompositeBatchJob, DrawListGroupId}; use internal_types::{DrawListId, DrawListItemIndex, LowLevelFilterOp, MAX_RECT}; -use internal_types::{MaskRegion, RenderTargetId, RendererFrame}; +use internal_types::{RenderTargetId, RendererFrame}; use internal_types::{StackingContextInfo, StackingContextIndex}; use layer::{Layer, ScrollingState}; -use node_compiler::NodeCompiler; -use renderer::CompositionOpHelpers; use resource_cache::ResourceCache; -use resource_list::BuildRequiredResources; use scene::{SceneStackingContext, ScenePipeline, Scene, SceneItem, SpecificSceneItem}; use scoped_threadpool; use std::collections::{HashMap, HashSet}; use std::hash::BuildHasherDefault; -use std::mem; -use texture_cache::TexturePage; -use util::{self, MatrixHelpers}; +use tiling::{Clip, FrameBuilder, FrameBuilderConfig}; +use util::{MatrixHelpers}; use webrender_traits::{AuxiliaryLists, PipelineId, Epoch, ScrollPolicy, ScrollLayerId}; -use webrender_traits::{StackingContext, FilterOp, ImageFormat, MixBlendMode}; -use webrender_traits::{ScrollEventPhase, ScrollLayerInfo, ScrollLayerState}; +use webrender_traits::{StackingContext, FilterOp, MixBlendMode}; +use webrender_traits::{ScrollEventPhase, ScrollLayerInfo, SpecificDisplayItem, ScrollLayerState}; #[cfg(target_os = "macos")] const CAN_OVERSCROLL: bool = true; @@ -41,54 +35,11 @@ const CAN_OVERSCROLL: bool = false; #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] pub struct FrameId(pub u32); -pub struct DrawListGroup { - pub 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! - pub scroll_layer_id: ScrollLayerId, - pub render_target_id: RenderTargetId, - - pub 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, pipeline_sizes: &'a mut HashMap>, - current_draw_list_group: Option, - device_pixel_ratio: f32, + builder: &'a mut FrameBuilder, } #[derive(Debug)] @@ -120,340 +71,6 @@ struct FlattenInfo { pipeline_id: PipelineId, } -#[derive(Debug)] -pub enum FrameRenderItem { - /// The extra boolean indicates whether a Z-buffer clear is needed. - CompositeBatch(CompositeBatchInfo, bool), - DrawListBatch(DrawListGroupId), -} - -pub struct RenderTarget { - id: RenderTargetId, - size: Size2D, - /// The origin in render target space. - origin: Point2D, - items: Vec, - texture_id: Option, - children: Vec, - - page_allocator: Option, - texture_id_list: Vec, -} - -impl RenderTarget { - fn new(id: RenderTargetId, - origin: Point2D, - size: Size2D, - texture_id: Option) -> RenderTarget { - RenderTarget { - id: id, - size: size, - origin: origin, - items: Vec::new(), - texture_id: texture_id, - children: Vec::new(), - texture_id_list: Vec::new(), - page_allocator: None, - } - } - - fn allocate_target_rect(&mut self, - width: f32, - height: f32, - device_pixel_ratio: f32, - resource_cache: &mut ResourceCache, - frame_id: FrameId) -> (Point2D, TextureId) { - // If the target is more than 512x512 (an arbitrary choice), assign it - // to an exact sized render target - assuming that there probably aren't - // many of them. This minimises GPU memory wastage if there are just a small - // number of large targets. Otherwise, attempt to allocate inside a shared render - // target texture - this allows composite batching to take place when - // there are a lot of small targets (which is more efficient). - if width < 512.0 && height < 512.0 { - if self.page_allocator.is_none() { - let texture_size = 2048; - let device_pixel_size = texture_size * device_pixel_ratio as u32; - - let texture_id = resource_cache.allocate_render_target(device_pixel_size, - device_pixel_size, - ImageFormat::RGBA8, - frame_id); - self.texture_id_list.push(texture_id); - self.page_allocator = Some(TexturePage::new(texture_id, texture_size)); - } - - // TODO(gw): This has accuracy issues if the size of a rendertarget is - // not scene pixel aligned! - let size = Size2D::new(width as u32, height as u32); - let allocated_origin = self.page_allocator - .as_mut() - .unwrap() - .allocate(&size); - if let Some(allocated_origin) = allocated_origin { - let origin = Point2D::new(allocated_origin.x as f32, - allocated_origin.y as f32); - return (origin, self.page_allocator.as_ref().unwrap().texture_id()) - } - } - - let device_pixel_width = width as u32 * device_pixel_ratio as u32; - let device_pixel_height = height as u32 * device_pixel_ratio as u32; - - let texture_id = resource_cache.allocate_render_target(device_pixel_width, - device_pixel_height, - ImageFormat::RGBA8, - frame_id); - self.texture_id_list.push(texture_id); - - (Point2D::zero(), texture_id) - } - - fn collect_and_sort_visible_batches(&mut self, - resource_cache: &mut ResourceCache, - draw_list_groups: &HashMap>, - layers: &HashMap>, - stacking_context_info: &[StackingContextInfo], - device_pixel_ratio: f32) -> DrawLayer { - let mut commands = vec![]; - for item in &self.items { - match item { - &FrameRenderItem::CompositeBatch(ref info, z_clear_needed) => { - let layer = &layers[&info.scroll_layer_id]; - let world_transform = layer.world_transform - .as_ref() - .expect("No world transform set!"); - - if z_clear_needed && !commands.is_empty() { - commands.push(DrawCommand::Clear(ClearInfo { - clear_color: false, - clear_z: true, - clear_stencil: true, - })) - } - - let mut draw_jobs = vec![]; - for job in &info.jobs { - draw_jobs.push(DrawCompositeBatchJob { - rect: job.rect, - local_transform: job.transform, - world_transform: job.transform.mul(world_transform), - child_layer_index: job.child_layer_index, - }) - } - - commands.push(DrawCommand::CompositeBatch(DrawCompositeBatchInfo { - operation: info.operation, - texture_id: info.texture_id, - scroll_layer_id: info.scroll_layer_id, - jobs: draw_jobs, - })) - } - &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![Matrix4D::identity(); draw_list_group.draw_list_ids.len()]; - let mut offset_palette = - vec![OffsetParams::identity(); draw_list_group.draw_list_ids.len()]; - - // Update batch matrices - let mut z_clear_needed = false; - 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); - - match draw_list.stacking_context_index { - Some(StackingContextIndex(stacking_context_id)) => { - let context = &stacking_context_info[stacking_context_id]; - if context.z_clear_needed { - z_clear_needed = true - } - - let mut world_transform_in_render_target_space = - layer.world_transform.expect("No world transform set!"); - if self.texture_id.is_some() { - // If we're rendering to a temporary target, the X/Y - // translation part of the transform will be applied by whoever - // composites us. - world_transform_in_render_target_space.m41 = 0.0; - world_transform_in_render_target_space.m42 = 0.0; - }; - let transform = - world_transform_in_render_target_space.mul(&context.transform); - matrix_palette[index] = transform; - - offset_palette[index].stacking_context_x0 = - context.offset_from_layer.x; - offset_palette[index].stacking_context_y0 = - context.offset_from_layer.y; - } - None => { - // This can happen if the root pipeline was set before any stacking - // context was set for it (during navigation, usually). In that - // case we just render nothing. - continue - } - } - } - - let mut batch_info = BatchInfo::new(matrix_palette, offset_palette); - - // Collect relevant draws from each node in the tree. - let mut any_were_visible = false; - for node in &layer.aabb_tree.nodes { - if node.is_visible { - any_were_visible = true; - - debug_assert!(node.compiled_node.is_some()); - let compiled_node = node.compiled_node.as_ref().unwrap(); - - let batch_list = compiled_node.batch_list.iter().find(|batch_list| { - batch_list.draw_list_group_id == draw_list_group_id - }); - - if let Some(batch_list) = batch_list { - let mut region = MaskRegion::new(); - - let vertex_buffer_id = compiled_node.vertex_buffer_id.unwrap(); - - // TODO(gw): Support mask regions for nested render targets - // with transforms. - if self.texture_id.is_none() { - // Mask out anything outside this AABB tree node. - // This is a requirement to ensure paint order is correctly - // maintained since the batches are built in parallel. - region.add_mask(node.split_rect, - layer.world_transform - .expect("No world transform set!")); - - // Mask out anything outside this viewport. This is used - // for things like clipping content that is outside a - // transformed iframe. - let mask_rect = layer.viewport_rect; - region.add_mask(mask_rect, layer.viewport_transform); - } - - for batch in &batch_list.batches { - region.draw_calls.push(DrawCall { - tile_params: batch.tile_params.clone(), // TODO(gw): Move this instead? - clip_rects: batch.clip_rects.clone(), - vertex_buffer_id: vertex_buffer_id, - color_texture_id: batch.color_texture_id, - mask_texture_id: batch.mask_texture_id, - first_instance: batch.first_instance, - instance_count: batch.instance_count, - }); - } - - batch_info.regions.push(region); - } - } - } - - if any_were_visible { - // Add a clear command if necessary. - if z_clear_needed && !commands.is_empty() { - commands.push(DrawCommand::Clear(ClearInfo { - clear_color: false, - clear_z: true, - clear_stencil: true, - })) - } - - // Finally, add the batch + draw calls - commands.push(DrawCommand::Batch(batch_info)); - } - } - } - } - - let mut child_layers = Vec::new(); - - for child in &mut self.children { - let child_layer = child.collect_and_sort_visible_batches(resource_cache, - draw_list_groups, - layers, - stacking_context_info, - device_pixel_ratio); - - child_layers.push(child_layer); - } - - DrawLayer::new(self.id, - self.origin, - self.size, - self.texture_id, - commands, - child_layers) - } - - fn reset(&mut self, - pending_updates: &mut BatchUpdateList, - resource_cache: &mut ResourceCache) { - self.texture_id_list.clear(); - resource_cache.free_old_render_targets(); - - for mut child in &mut self.children.drain(..) { - child.reset(pending_updates, - resource_cache); - } - - self.items.clear(); - self.page_allocator = None; - } - - fn push_composite(&mut self, - op: CompositionOp, - texture_id: TextureId, - target: Rect, - transform: &Matrix4D, - child_layer_index: ChildLayerIndex, - scroll_layer_id: ScrollLayerId, - z_clear_needed: bool) { - // 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 || info.texture_id != texture_id - } - Some(&FrameRenderItem::DrawListBatch(..)) | None => true, - }; - - if need_new_batch { - self.items.push(FrameRenderItem::CompositeBatch(CompositeBatchInfo { - operation: op, - texture_id: texture_id, - jobs: Vec::new(), - scroll_layer_id: scroll_layer_id, - }, z_clear_needed)); - } - - // TODO(gw): This seems a little messy - restructure how current batch works! - match self.items.last_mut().unwrap() { - &mut FrameRenderItem::CompositeBatch(ref mut batch, ref mut old_z_clear_needed) => { - let job = CompositeBatchJob { - rect: target, - transform: *transform, - child_layer_index: child_layer_index, - }; - batch.jobs.push(job); - - if !*old_z_clear_needed && z_clear_needed { - *old_z_clear_needed = true - } - } - _ => { - unreachable!(); - } - } - } - - fn push_draw_list_group(&mut self, draw_list_group_id: DrawListGroupId) { - self.items.push(FrameRenderItem::DrawListBatch(draw_list_group_id)); - } -} - pub type LayerMap = HashMap>; pub struct Frame { @@ -462,14 +79,11 @@ pub struct Frame { pub pipeline_auxiliary_lists: HashMap>, - pub pending_updates: BatchUpdateList, - pub root: Option, - pub stacking_context_info: Vec, - next_render_target_id: RenderTargetId, - next_draw_list_group_id: DrawListGroupId, - draw_list_groups: HashMap>, pub root_scroll_layer_id: Option, id: FrameId, + debug: bool, + frame_builder_config: FrameBuilderConfig, + frame_builder: Option, } enum SceneItemKind<'a> { @@ -597,37 +211,27 @@ impl StackingContextHelpers for StackingContext { } impl Frame { - pub fn new() -> Frame { + pub fn new(debug: bool, config: FrameBuilderConfig) -> Frame { Frame { pipeline_epoch_map: HashMap::with_hasher(Default::default()), - pending_updates: BatchUpdateList::new(), pipeline_auxiliary_lists: HashMap::with_hasher(Default::default()), - root: None, layers: HashMap::with_hasher(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_hasher(Default::default()), root_scroll_layer_id: None, id: FrameId(0), + debug: debug, + frame_builder: None, + frame_builder_config: config, } } pub fn reset(&mut self, resource_cache: &mut ResourceCache) -> HashMap> { - 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_scrolling_states = HashMap::with_hasher(Default::default()); - for (layer_id, mut old_layer) in &mut self.layers.drain() { - old_layer.reset(&mut self.pending_updates); + for (layer_id, old_layer) in &mut self.layers.drain() { old_layer_scrolling_states.insert(layer_id, old_layer.scrolling); } @@ -637,22 +241,6 @@ impl Frame { old_layer_scrolling_states } - 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 get_scroll_layer(&self, cursor: &Point2D, scroll_layer_id: ScrollLayerId) -> Option { self.layers.get(&scroll_layer_id).and_then(|layer| { @@ -817,13 +405,6 @@ impl Frame { .expect("root layer must be a scroll layer!"); self.root_scroll_layer_id = Some(root_scroll_layer_id); - let root_target_id = self.next_render_target_id(); - - let mut root_target = RenderTarget::new(root_target_id, - Point2D::zero(), - root_pipeline.viewport_size, - None); - // Insert global position: fixed elements layer debug_assert!(self.layers.is_empty()); let root_fixed_layer_id = ScrollLayerId::create_fixed(root_pipeline_id); @@ -840,41 +421,42 @@ impl Frame { // 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, - device_pixel_ratio: device_pixel_ratio, - }; + let mut frame_builder = FrameBuilder::new(root_pipeline.viewport_size, + device_pixel_ratio, + self.debug, + self.frame_builder_config); + + { + let mut context = FlattenContext { + resource_cache: resource_cache, + scene: scene, + pipeline_sizes: pipeline_sizes, + builder: &mut frame_builder, + }; - let parent_info = FlattenInfo { - viewport_rect: Rect::new(Point2D::zero(), root_pipeline.viewport_size), - viewport_transform: Matrix4D::identity(), - offset_from_origin: Point2D::zero(), - offset_from_current_layer: Point2D::zero(), - default_scroll_layer_id: root_scroll_layer_id, - actual_scroll_layer_id: root_scroll_layer_id, - fixed_scroll_layer_id: root_fixed_layer_id, - current_clip_rect: MAX_RECT, - local_transform: Matrix4D::identity(), - local_perspective: Matrix4D::identity(), - world_transform: Matrix4D::identity(), - pipeline_id: root_pipeline_id, - }; + let parent_info = FlattenInfo { + viewport_rect: Rect::new(Point2D::zero(), root_pipeline.viewport_size), + viewport_transform: Matrix4D::identity(), + offset_from_origin: Point2D::zero(), + offset_from_current_layer: Point2D::zero(), + default_scroll_layer_id: root_scroll_layer_id, + actual_scroll_layer_id: root_scroll_layer_id, + fixed_scroll_layer_id: root_fixed_layer_id, + current_clip_rect: MAX_RECT, + local_transform: Matrix4D::identity(), + local_perspective: Matrix4D::identity(), + world_transform: Matrix4D::identity(), + pipeline_id: root_pipeline_id, + }; - let root_pipeline = SceneItemKind::Pipeline(root_pipeline); - self.flatten(root_pipeline, - &parent_info, - &mut context, - &mut root_target, - 0); - 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 root_pipeline = SceneItemKind::Pipeline(root_pipeline); + self.flatten(root_pipeline, + &parent_info, + &mut context, + 0); } + + self.frame_builder = Some(frame_builder); } // TODO(gw): These are all independent - can be run through thread pool if it shows up in the profile! @@ -893,65 +475,98 @@ impl Frame { fn add_items_to_target(&mut self, scene_items: &[SceneItem], info: &FlattenInfo, - target: &mut RenderTarget, context: &mut FlattenContext, _level: i32, - z_clear_needed: bool) { - let stacking_context_index = StackingContextIndex(self.stacking_context_info.len()); - self.stacking_context_info.push(StackingContextInfo { - offset_from_layer: info.offset_from_current_layer, - local_clip_rect: info.current_clip_rect, - transform: info.world_transform, - z_clear_needed: z_clear_needed, - }); + sc_rect: Rect, + opacity: f32) { + context.builder.push_layer(sc_rect, + info.current_clip_rect, + info.local_transform, + opacity, + info.pipeline_id, + info.actual_scroll_layer_id, + info.offset_from_current_layer); 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 draw_list = context.resource_cache.get_draw_list(draw_list_id); + let builder = &mut context.builder; - let needs_new_draw_group = match context.current_draw_list_group { - Some(ref draw_list_group) => { - !draw_list_group.can_add(info.actual_scroll_layer_id, - target.id) - } - None => { - true - } + let auxiliary_lists = { + self.pipeline_auxiliary_lists + .get(&info.pipeline_id) + .expect("No auxiliary lists?!") }; - 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, - info.actual_scroll_layer_id, - target.id); - - target.push_draw_list_group(draw_list_group_id); - - context.current_draw_list_group = Some(new_draw_list_group); - } + for item in &draw_list.items { + let clips = auxiliary_lists.complex_clip_regions(&item.clip.complex); + let clip = if clips.is_empty() { + None + } else { + Some(Box::new(Clip::from_clip_region(&clips[0]))) + }; - context.current_draw_list_group.as_mut().unwrap().push(draw_list_id); - - let draw_list_group_id = context.current_draw_list_group.as_ref().unwrap().id; - let layer = self.layers.get_mut(&info.actual_scroll_layer_id).unwrap(); - for (item_index, item) in draw_list.items.iter().enumerate() { - let item_index = DrawListItemIndex(item_index as u32); - let rect = item.rect - .translate(&info.offset_from_current_layer); - layer.insert(rect, - draw_list_group_id, - draw_list_id, - item_index); + match item.item { + SpecificDisplayItem::WebGL(ref _info) => { + println!("TODO: WebGL"); + /* + builder.add_webgl_rectangle(&display_item.rect, + resource_cache, + &info.context_id, + frame_id); + */ + } + SpecificDisplayItem::Image(ref info) => { + builder.add_image(item.rect, + &item.clip.main, + clip, + &info.stretch_size, + info.image_key, + info.image_rendering); + } + SpecificDisplayItem::Text(ref text_info) => { + builder.add_text(item.rect, + &item.clip.main, + clip, + text_info.font_key, + text_info.size, + text_info.blur_radius, + &text_info.color, + text_info.glyphs); + } + SpecificDisplayItem::Rectangle(ref info) => { + builder.add_solid_rectangle(&item.rect, + &item.clip.main, + clip, + &info.color); + } + SpecificDisplayItem::Gradient(ref info) => { + builder.add_gradient(item.rect, + &item.clip.main, + clip, + info.start_point, + info.end_point, + info.stops); + } + SpecificDisplayItem::BoxShadow(ref box_shadow_info) => { + builder.add_box_shadow(&box_shadow_info.box_bounds, + &item.clip.main, + clip, + &box_shadow_info.offset, + &box_shadow_info.color, + box_shadow_info.blur_radius, + box_shadow_info.spread_radius, + box_shadow_info.border_radius, + box_shadow_info.clip_mode); + } + SpecificDisplayItem::Border(ref info) => { + builder.add_border(item.rect, + &item.clip.main, + clip, + info); + } + } } } SpecificSceneItem::StackingContext(id, pipeline_id) => { @@ -964,7 +579,6 @@ impl Frame { self.flatten(child, info, context, - target, _level+1); } SpecificSceneItem::Iframe(ref iframe_info) => { @@ -1033,21 +647,21 @@ impl Frame { self.flatten(iframe, &iframe_info, context, - target, _level+1); } } } } + + context.builder.pop_layer(); } fn flatten(&mut self, scene_item: SceneItemKind, parent_info: &FlattenInfo, context: &mut FlattenContext, - target: &mut RenderTarget, level: i32) { - let _pf = util::ProfileScope::new(" flatten"); + //let _pf = util::ProfileScope::new(" flatten"); let (stacking_context, pipeline_id) = match scene_item { SceneItemKind::StackingContext(stacking_context, pipeline_id) => { @@ -1107,12 +721,16 @@ impl Frame { // Build local and world space transform let origin = parent_info.offset_from_current_layer + stacking_context.bounds.origin; - let mut local_transform = Matrix4D::identity(); - if composition_operations.is_empty() { - local_transform = local_transform.translate(origin.x, origin.y, 0.0) - .mul(&stacking_context.transform) - .translate(-origin.x, -origin.y, 0.0) - } + //let local_transform = if composition_operations.is_empty() { + // Matrix4D::identity().translate(origin.x, origin.y, 0.0) + // .mul(&stacking_context.transform) + // .translate(-origin.x, -origin.y, 0.0) + //} else { + // Matrix4D::identity() + //}; + let local_transform = Matrix4D::identity().translate(origin.x, origin.y, 0.0) + .mul(&stacking_context.transform) + .translate(-origin.x, -origin.y, 0.0); // Build local space perspective transform let local_perspective = Matrix4D::identity().translate(origin.x, origin.y, 0.0) @@ -1123,11 +741,14 @@ impl Frame { let world_transform = parent_info.world_transform.mul(&local_perspective) .mul(&local_transform); + /* let viewport_rect = if composition_operations.is_empty() { parent_info.viewport_rect } else { Rect::new(Point2D::zero(), parent_info.viewport_rect.size) }; + */ + let viewport_rect = parent_info.viewport_rect; let mut info = FlattenInfo { viewport_rect: viewport_rect, @@ -1197,82 +818,28 @@ impl Frame { } } - // When establishing a new 3D context, clear Z. This is only needed if there - // are child stacking contexts, otherwise it is a redundant clear. - let z_clear_needed = stacking_context.establishes_3d_context && - stacking_context.has_stacking_contexts; - - // TODO: Account for scroll offset with transforms! - if composition_operations.is_empty() { - self.add_items_to_target(&scene_items, - &info, - target, - context, - level, - z_clear_needed); - } else { - // TODO(gw): This makes the reftests work (mix_blend_mode) and - // inline_stacking_context, but it seems wrong. - // Need to investigate those and see what the root - // issue is... - let empty_stacking_context = stacking_context.bounds.size.width == 0.0 || - stacking_context.bounds.size.height == 0.0; - let target_size = if empty_stacking_context { - stacking_context.overflow.size - } else { - stacking_context.bounds.size - }; - let target_origin = Point2D::new(info.offset_from_origin.x, - info.offset_from_origin.y); - let unfiltered_target_rect = Rect::new(target_origin, target_size); - let mut target_rect = unfiltered_target_rect; - for composition_operation in &composition_operations { - target_rect = composition_operation.target_rect(&target_rect); - } - - let child_layer_index = ChildLayerIndex(target.children.len() as u32); - - let render_target_size = Size2D::new(target_rect.size.width, - target_rect.size.height); - let render_target_id = self.next_render_target_id(); - - let (origin, texture_id) = - target.allocate_target_rect(target_rect.size.width, - target_rect.size.height, - context.device_pixel_ratio, - context.resource_cache, - self.id); - - let mut new_target = RenderTarget::new(render_target_id, - origin, - render_target_size, - Some(texture_id)); - - let local_transform = - Matrix4D::identity().translate(origin.x, origin.y, 0.0) - .mul(&stacking_context.transform) - .translate(-origin.x, -origin.y, 0.0); - for composition_operation in composition_operations { - target.push_composite(composition_operation, - texture_id, - target_rect, - &local_transform, - child_layer_index, - info.actual_scroll_layer_id, - z_clear_needed); + let mut opacity = 1.0; + for composition_op in composition_operations { + match composition_op { + CompositionOp::Filter(filter_op) => { + match filter_op { + LowLevelFilterOp::Opacity(o) => { + opacity = o.to_f32_px(); + } + _ => {} + } + } + _ => {} } - - info.offset_from_current_layer = Point2D::zero(); - - self.add_items_to_target(&scene_items, - &info, - &mut new_target, - context, - level, - z_clear_needed); - - target.children.push(new_target); } + + // TODO: Account for scroll offset with transforms! + self.add_items_to_target(&scene_items, + &info, + context, + level, + stacking_context.overflow, + opacity); } } } @@ -1282,34 +849,9 @@ impl Frame { thread_pool: &mut scoped_threadpool::Pool, device_pixel_ratio: f32) -> RendererFrame { - // Traverse layer trees to calculate visible nodes - for (_, layer) in &mut self.layers { - layer.cull(); - } - - // Build resource list for newly visible nodes - self.update_resource_lists(resource_cache, thread_pool); - - // Update texture cache and build list of raster jobs. - self.update_texture_cache_and_build_raster_jobs(resource_cache); - - // Rasterize needed glyphs on worker threads - self.raster_glyphs(thread_pool, resource_cache); - - // Compile nodes that have become visible - self.compile_visible_nodes(thread_pool, resource_cache, device_pixel_ratio); - - // Update the batch cache from newly compiled nodes - self.update_batch_cache(); - - // Update the layer transform matrices self.update_layer_transforms(); - - // Collect the visible batches into a frame - let frame = self.collect_and_sort_visible_batches(resource_cache, device_pixel_ratio); - + let frame = self.build_frame(resource_cache); resource_cache.expire_old_resources(self.id); - frame } @@ -1363,127 +905,20 @@ impl Frame { } } - pub fn update_resource_lists(&mut self, - resource_cache: &ResourceCache, - thread_pool: &mut scoped_threadpool::Pool) { - let _pf = util::ProfileScope::new(" update_resource_lists"); - - for (_, layer) in &mut self.layers { - let nodes = &mut layer.aabb_tree.nodes; - let pipeline_auxiliary_lists = &self.pipeline_auxiliary_lists; - - 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, pipeline_auxiliary_lists); - }); - } - } - }); - } - } - - 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"); - - let frame_id = self.id; - 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, frame_id); - } - } - } - } - - pub fn raster_glyphs(&mut self, - thread_pool: &mut scoped_threadpool::Pool, - resource_cache: &mut ResourceCache) { - let _pf = util::ProfileScope::new(" raster_glyphs"); - resource_cache.raster_pending_glyphs(thread_pool, self.id); - } - - pub fn compile_visible_nodes(&mut self, - thread_pool: &mut scoped_threadpool::Pool, - resource_cache: &ResourceCache, - device_pixel_ratio: f32) { - let _pf = util::ProfileScope::new(" compile_visible_nodes"); - - let layers = &mut self.layers; - let stacking_context_info = &self.stacking_context_info; - let draw_list_groups = &self.draw_list_groups; - let frame_id = self.id; - let pipeline_auxiliary_lists = &self.pipeline_auxiliary_lists; - - 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, - frame_id, - device_pixel_ratio, - stacking_context_info, - draw_list_groups, - pipeline_auxiliary_lists); - }); - } - } - } + fn build_frame(&mut self, + resource_cache: &mut ResourceCache) -> RendererFrame { + let frame_builder = self.frame_builder.take(); + let frame = frame_builder.map(|mut builder| { + builder.build(resource_cache, + self.id, + &self.pipeline_auxiliary_lists, + &self.layers) }); - } - - pub fn update_batch_cache(&mut self) { - let _pf = util::ProfileScope::new(" update_batch_cache"); - - // 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), - }); - - 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 = 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(RenderTargetId(0), - Point2D::zero(), - Size2D::zero(), - None, - Vec::new(), - Vec::new()) - } - }; let layers_bouncing_back = self.collect_layers_bouncing_back(); - RendererFrame::new(self.pipeline_epoch_map.clone(), layers_bouncing_back, root_layer) + RendererFrame::new(self.pipeline_epoch_map.clone(), + layers_bouncing_back, + frame) } fn collect_layers_bouncing_back(&self) diff --git a/src/geometry.rs b/src/geometry.rs index 7e5abaab96..2afa0d5c3e 100644 --- a/src/geometry.rs +++ b/src/geometry.rs @@ -83,3 +83,39 @@ pub fn ray_intersects_rect(ray_origin: Point3D, (tmin < t1) && (tmax > t0) */ } + +/* +pub fn circle_contains_rect(circle_center: &Point2D, + radius: f32, + rect: &Rect) -> bool { + let dx = (circle_center.x - rect.origin.x).max(rect.origin.x + rect.size.width - circle_center.x); + let dy = (circle_center.y - rect.origin.y).max(rect.origin.y + rect.size.height - circle_center.y); + radius * radius >= dx * dx + dy * dy +} + +pub fn rect_intersects_circle(circle_center: &Point2D, + radius: f32, + rect: &Rect) -> bool { + let circle_distance_x = (circle_center.x - (rect.origin.x + rect.size.width * 0.5)).abs(); + let circle_distance_y = (circle_center.y - (rect.origin.y + rect.size.height * 0.5)).abs(); + + if circle_distance_x > rect.size.width * 0.5 + radius { + return false + } + if circle_distance_y > rect.size.height * 0.5 + radius { + return false + } + + if circle_distance_x <= rect.size.width * 0.5 { + return true; + } + if circle_distance_y <= rect.size.height * 0.5 { + return true; + } + + let corner_distance_sq = (circle_distance_x - rect.size.width * 0.5) * (circle_distance_x - rect.size.width * 0.5) + + (circle_distance_y - rect.size.height * 0.5) * (circle_distance_y - rect.size.height * 0.5); + + corner_distance_sq <= radius * radius +} +*/ diff --git a/src/internal_types.rs b/src/internal_types.rs index 3ead001def..bf4867f782 100644 --- a/src/internal_types.rs +++ b/src/internal_types.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use batch::{VertexBuffer, Batch, VertexBufferId, OffsetParams, TileParams}; +use batch::{VertexBufferId, TileParams}; use device::{TextureId, TextureFilter}; use euclid::{Matrix4D, Point2D, Rect, Size2D}; use fnv::FnvHasher; @@ -18,30 +18,30 @@ use std::path::PathBuf; use std::sync::Arc; use texture_cache::BorderType; use util; +use tiling; use webrender_traits::{FontKey, Epoch, ColorF, PipelineId}; use webrender_traits::{ImageFormat, MixBlendMode, NativeFontHandle, DisplayItem, ScrollLayerId}; #[derive(Hash, Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct DevicePixel(i32); +pub struct DevicePixel(pub i32); impl DevicePixel { - pub fn from_u32(value: u32) -> DevicePixel { - DevicePixel(value as i32) + pub fn new(value: f32, device_pixel_ratio: f32) -> DevicePixel { + DevicePixel((value * device_pixel_ratio).round() as i32) } - pub fn from_f32(value: f32) -> DevicePixel { - debug_assert!(value.fract() == 0.0); - DevicePixel(value as i32) + pub fn from_i32(value: i32) -> DevicePixel { + DevicePixel(value) } - pub fn new(value: f32, device_pixel_ratio: f32) -> DevicePixel { - DevicePixel((value * device_pixel_ratio).round() as i32) + pub fn from_u32(value: u32) -> DevicePixel { + DevicePixel(value as i32) } // TODO(gw): Remove eventually... - pub fn as_u16(&self) -> u16 { + pub fn as_f32(&self) -> f32 { let DevicePixel(value) = *self; - value as u16 + value as f32 } // TODO(gw): Remove eventually... @@ -49,12 +49,6 @@ impl DevicePixel { let DevicePixel(value) = *self; value as u32 } - - // TODO(gw): Remove eventually... - pub fn as_f32(&self) -> f32 { - let DevicePixel(value) = *self; - value as f32 - } } impl Add for DevicePixel { @@ -114,6 +108,17 @@ pub type DrawListId = FreeListItemId; pub enum TextureSampler { Color, Mask, + + Cache, + + CompositeLayer0, + CompositeLayer1, + CompositeLayer2, + CompositeLayer3, + CompositeLayer4, + CompositeLayer5, + CompositeLayer6, + CompositeLayer7, } pub enum VertexAttribute { @@ -167,12 +172,6 @@ pub struct WorkVertex { pub v: f32, } -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum PackedVertexColorMode { - Gradient, - BorderCorner, -} - #[derive(Debug, Clone, Copy)] #[repr(C)] pub struct PackedVertexForQuad { @@ -206,65 +205,22 @@ pub struct PackedVertexForQuad { pub tile_params_index: u8, } -impl PackedVertexForQuad { - pub fn new(position: &Rect, - colors: &[ColorF; 4], - uv: &RectUv, - muv: &RectUv, - color_mode: PackedVertexColorMode) - -> PackedVertexForQuad { - PackedVertexForQuad { - x: position.origin.x, - y: position.origin.y, - width: position.size.width, - height: position.size.height, - color_tl: PackedColor::from_color(&colors[0]), - color_tr: PackedColor::from_color(&colors[1]), - color_br: PackedColor::from_color(&colors[2]), - color_bl: PackedColor::from_color(&colors[3]), - u_tl: uv.top_left.x, - v_tl: uv.top_left.y, - u_tr: uv.top_right.x, - v_tr: uv.top_right.y, - u_bl: uv.bottom_left.x, - v_bl: uv.bottom_left.y, - u_br: uv.bottom_right.x, - v_br: uv.bottom_right.y, - mu_tl: muv.top_left.x.as_u16(), - mv_tl: muv.top_left.y.as_u16(), - mu_tr: muv.top_right.x.as_u16(), - mv_tr: muv.top_right.y.as_u16(), - mu_bl: muv.bottom_left.x.as_u16(), - mv_bl: muv.bottom_left.y.as_u16(), - mu_br: muv.bottom_right.x.as_u16(), - mv_br: muv.bottom_right.y.as_u16(), - matrix_index: 0, - clip_in_rect_index: 0, - clip_out_rect_index: 0, - tile_params_index: match color_mode { - PackedVertexColorMode::Gradient => 0x00, - PackedVertexColorMode::BorderCorner => 0x80, - }, - } - } +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct PackedVertex { + pub pos: [f32; 2], } #[derive(Debug, Clone, Copy)] #[repr(C)] -pub struct PackedVertex { +pub struct FontVertex { pub x: f32, pub y: f32, - pub color: PackedColor, - pub u: f32, - pub v: f32, - pub mu: u16, - pub mv: u16, - pub matrix_index: u8, - pub clip_in_rect_index: u8, - pub clip_out_rect_index: u8, - pub tile_params_index: u8, + pub s: f32, + pub t: f32, } +/* impl PackedVertex { pub fn from_components(x: f32, y: f32, @@ -311,7 +267,7 @@ impl PackedVertex { tile_params_index: 0, } } -} +}*/ #[derive(Debug)] pub struct DebugFontVertex { @@ -361,8 +317,6 @@ pub enum TextureUpdateDetails { Raw, Blit(Vec), Blur(Vec, Size2D, Au, TextureImage, TextureImage, BorderType), - /// All four corners, the tessellation index, and whether inverted, respectively. - BorderRadius(DevicePixel, DevicePixel, DevicePixel, DevicePixel, Option, bool, BorderType), /// Blur radius, border radius, box size, raster origin, and whether inverted, respectively. BoxShadow(DevicePixel, DevicePixel, Size2D, Point2D, bool, BorderType), } @@ -402,33 +356,6 @@ impl TextureUpdateList { } } -pub enum BatchUpdateOp { - Create(Vec), - Destroy, -} - -pub struct BatchUpdate { - pub id: VertexBufferId, - pub op: BatchUpdateOp, -} - -pub struct BatchUpdateList { - pub updates: Vec, -} - -impl BatchUpdateList { - pub fn new() -> BatchUpdateList { - BatchUpdateList { - updates: Vec::new(), - } - } - - #[inline] - pub fn push(&mut self, update: BatchUpdate) { - self.updates.push(update); - } -} - // TODO(gw): Use bitflags crate for ClearInfo... // TODO(gw): Expand clear info to handle color, depth etc as needed. @@ -450,61 +377,6 @@ pub struct DrawCall { pub instance_count: u32, } -#[derive(Clone, Debug)] -pub struct OutputMask { - pub rect: Rect, - pub transform: Matrix4D, -} - -impl OutputMask { - pub fn new(rect: Rect, - transform: Matrix4D) -> OutputMask { - OutputMask { - rect: rect, - transform: transform, - } - } -} - -#[derive(Clone, Debug)] -pub struct MaskRegion { - pub masks: Vec, - pub draw_calls: Vec, -} - -impl MaskRegion { - pub fn new() -> MaskRegion { - MaskRegion { - masks: Vec::new(), - draw_calls: Vec::new(), - } - } - - pub fn add_mask(&mut self, - rect: Rect, - transform: Matrix4D) { - self.masks.push(OutputMask::new(rect, transform)); - } -} - -#[derive(Clone, Debug)] -pub struct BatchInfo { - pub matrix_palette: Vec>, - pub offset_palette: Vec, - pub regions: Vec, -} - -impl BatchInfo { - pub fn new(matrix_palette: Vec>, - offset_palette: Vec) -> BatchInfo { - BatchInfo { - matrix_palette: matrix_palette, - offset_palette: offset_palette, - regions: Vec::new(), - } - } -} - #[derive(Debug, Clone)] pub struct CompositeBatchJob { pub rect: Rect, @@ -528,71 +400,24 @@ pub struct CompositeBatchInfo { pub jobs: Vec, } -#[derive(Debug, Clone)] -pub struct DrawCompositeBatchInfo { - pub operation: CompositionOp, - pub texture_id: TextureId, - pub scroll_layer_id: ScrollLayerId, - pub jobs: Vec, -} - -#[derive(Clone, Debug)] -pub enum DrawCommand { - Batch(BatchInfo), - CompositeBatch(DrawCompositeBatchInfo), - Clear(ClearInfo), -} - #[derive(Clone, Copy, Debug, Ord, PartialOrd, PartialEq, Eq, Hash)] pub struct ChildLayerIndex(pub u32); -#[derive(Debug)] -pub struct DrawLayer { - // This layer - pub id: RenderTargetId, - pub commands: Vec, - pub texture_id: Option, - pub origin: Point2D, - pub size: Size2D, - - // Children - pub child_layers: Vec, -} - -impl DrawLayer { - pub fn new(id: RenderTargetId, - origin: Point2D, - size: Size2D, - texture_id: Option, - commands: Vec, - child_layers: Vec) - -> DrawLayer { - DrawLayer { - id: id, - origin: origin, - size: size, - texture_id: texture_id, - commands: commands, - child_layers: child_layers, - } - } -} - pub struct RendererFrame { pub pipeline_epoch_map: HashMap>, pub layers_bouncing_back: HashSet>, - pub root_layer: DrawLayer, + pub frame: Option, } impl RendererFrame { pub fn new(pipeline_epoch_map: HashMap>, layers_bouncing_back: HashSet>, - root_layer: DrawLayer) + frame: Option) -> RendererFrame { RendererFrame { pipeline_epoch_map: pipeline_epoch_map, layers_bouncing_back: layers_bouncing_back, - root_layer: root_layer, + frame: frame, } } } @@ -600,9 +425,10 @@ impl RendererFrame { pub enum ResultMsg { UpdateTextureCache(TextureUpdateList), RefreshShader(PathBuf), - NewFrame(RendererFrame, BatchUpdateList, BackendProfileCounters), + NewFrame(RendererFrame, BackendProfileCounters), } +#[repr(u32)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum AxisDirection { Horizontal, @@ -659,42 +485,12 @@ impl FreeListItem for DrawList { #[derive(Clone, Copy, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct DrawListItemIndex(pub u32); -#[derive(Debug)] -pub struct BatchList { - pub batches: Vec, - pub draw_list_group_id: DrawListGroupId, -} - -pub struct CompiledNode { - // TODO(gw): These are mutually exclusive - unify into an enum? - pub vertex_buffer: Option, - pub vertex_buffer_id: Option, - - pub batch_list: Vec, -} - -impl CompiledNode { - pub fn new() -> CompiledNode { - CompiledNode { - batch_list: Vec::new(), - vertex_buffer: None, - vertex_buffer_id: None, - } - } -} - #[derive(Clone, Copy, Debug)] pub struct RectPolygon { pub pos: Rect, pub varyings: Varyings, } -impl RectPolygon { - pub fn is_well_formed_and_nonempty(&self) -> bool { - util::rect_is_well_formed_and_nonempty(&self.pos) - } -} - #[derive(Clone, Copy, Debug)] pub struct RectColors { pub top_left: ColorF, @@ -711,72 +507,6 @@ pub struct RectUv { pub bottom_right: Point2D, } -impl RectUv { - pub fn zero() -> RectUv { - RectUv { - top_left: Point2D::zero(), - top_right: Point2D::zero(), - bottom_left: Point2D::zero(), - bottom_right: Point2D::zero(), - } - } - - pub fn from_uv_rect_rotation_angle(uv_rect: &RectUv, - rotation_angle: BasicRotationAngle, - flip_90_degree_rotations: bool) -> RectUv { - match (rotation_angle, flip_90_degree_rotations) { - (BasicRotationAngle::Upright, _) => { - RectUv { - top_left: uv_rect.top_left, - top_right: uv_rect.top_right, - bottom_right: uv_rect.bottom_right, - bottom_left: uv_rect.bottom_left, - } - } - (BasicRotationAngle::Clockwise90, true) => { - RectUv { - top_right: uv_rect.top_left, - top_left: uv_rect.top_right, - bottom_left: uv_rect.bottom_right, - bottom_right: uv_rect.bottom_left, - } - } - (BasicRotationAngle::Clockwise90, false) => { - RectUv { - top_right: uv_rect.top_left, - bottom_right: uv_rect.top_right, - bottom_left: uv_rect.bottom_right, - top_left: uv_rect.bottom_left, - } - } - (BasicRotationAngle::Clockwise180, _) => { - RectUv { - bottom_right: uv_rect.top_left, - bottom_left: uv_rect.top_right, - top_left: uv_rect.bottom_right, - top_right: uv_rect.bottom_left, - } - } - (BasicRotationAngle::Clockwise270, true) => { - RectUv { - bottom_left: uv_rect.top_left, - bottom_right: uv_rect.top_right, - top_right: uv_rect.bottom_right, - top_left: uv_rect.bottom_left, - } - } - (BasicRotationAngle::Clockwise270, false) => { - RectUv { - bottom_left: uv_rect.top_left, - top_left: uv_rect.top_right, - top_right: uv_rect.bottom_right, - bottom_right: uv_rect.bottom_left, - } - } - } - } -} - #[derive(Clone, Debug)] pub struct PolygonPosColorUv { pub vertices: Vec, @@ -866,43 +596,6 @@ impl PackedVertexForTextureCacheUpdate { } } -#[derive(Clone, Debug, Hash, Eq, PartialEq)] -pub struct BorderRadiusRasterOp { - pub outer_radius_x: DevicePixel, - pub outer_radius_y: DevicePixel, - pub inner_radius_x: DevicePixel, - pub inner_radius_y: DevicePixel, - pub index: Option, - pub image_format: ImageFormat, - pub inverted: bool, -} - -impl BorderRadiusRasterOp { - pub fn create(outer_radius_x: DevicePixel, - outer_radius_y: DevicePixel, - inner_radius_x: DevicePixel, - inner_radius_y: DevicePixel, - inverted: bool, - index: Option, - image_format: ImageFormat) - -> Option { - if outer_radius_x > DevicePixel::zero() || outer_radius_y > DevicePixel::zero() || - inner_radius_x > DevicePixel::zero() || inner_radius_y > DevicePixel::zero() { - Some(BorderRadiusRasterOp { - outer_radius_x: outer_radius_x, - outer_radius_y: outer_radius_y, - inner_radius_x: inner_radius_x, - inner_radius_y: inner_radius_y, - index: index, - inverted: inverted, - image_format: image_format, - }) - } else { - None - } - } -} - #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub struct BoxShadowRasterOp { pub blur_radius: DevicePixel, @@ -921,7 +614,7 @@ impl BoxShadowRasterOp { part: BoxShadowPart, box_rect: &Rect) -> Rect { - let outer_extent = 3.0 * blur_radius; + let outer_extent = blur_radius; let inner_extent = outer_extent.max(border_radius); let extent = outer_extent + inner_extent; match part { @@ -1030,18 +723,9 @@ impl GlyphKey { #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub enum RasterItem { - BorderRadius(BorderRadiusRasterOp), BoxShadow(BoxShadowRasterOp), } -#[derive(Clone, Copy, Debug)] -pub enum BasicRotationAngle { - Upright, - Clockwise90, - Clockwise180, - Clockwise270, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum LowLevelFilterOp { Blur(Au, AxisDirection), @@ -1061,26 +745,3 @@ pub enum CompositionOp { MixBlend(MixBlendMode), Filter(LowLevelFilterOp), } - -impl CompositionOp { - pub fn target_rect(&self, unfiltered_target_rect: &Rect) -> Rect { - match *self { - CompositionOp::Filter(LowLevelFilterOp::Blur(amount, AxisDirection::Horizontal)) => { - unfiltered_target_rect.inflate(amount.to_f32_px(), 0.0) - } - CompositionOp::Filter(LowLevelFilterOp::Blur(amount, AxisDirection::Vertical)) => { - unfiltered_target_rect.inflate(0.0, amount.to_f32_px()) - } - _ => *unfiltered_target_rect, - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum RectSide { - Top, - Right, - Bottom, - Left, -} - diff --git a/src/kdtree.rs b/src/kdtree.rs new file mode 100644 index 0000000000..b7e0a1d5ef --- /dev/null +++ b/src/kdtree.rs @@ -0,0 +1,4 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + diff --git a/src/layer.rs b/src/layer.rs index bd49d7f3b8..03be6862b0 100644 --- a/src/layer.rs +++ b/src/layer.rs @@ -2,16 +2,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use aabbtree::{AABBTree, NodeIndex}; use euclid::{Matrix4D, Point2D, Rect, Size2D}; -use internal_types::{BatchUpdate, BatchUpdateList, BatchUpdateOp}; -use internal_types::{DrawListItemIndex, DrawListId, DrawListGroupId}; use spring::{DAMPING, STIFFNESS, Spring}; use webrender_traits::{PipelineId, ScrollLayerId, ServoStackingContextId}; pub struct Layer { - // TODO: Remove pub from here if possible in the future - pub aabb_tree: AABBTree, pub scrolling: ScrollingState, /// The viewable region, in world coordinates. @@ -42,11 +37,7 @@ impl Layer { pipeline_id: PipelineId, stacking_context_id: ServoStackingContextId) -> Layer { - let rect = Rect::new(Point2D::zero(), layer_size); - let aabb_tree = AABBTree::new(8192.0, &rect); - Layer { - aabb_tree: aabb_tree, scrolling: ScrollingState::new(), viewport_rect: *viewport_rect, viewport_transform: *viewport_transform, @@ -65,35 +56,12 @@ impl Layer { self.children.push(child); } - pub fn reset(&mut self, pending_updates: &mut BatchUpdateList) { - for node in &mut self.aabb_tree.nodes { - if let Some(ref mut compiled_node) = node.compiled_node { - let vertex_buffer_id = compiled_node.vertex_buffer_id.take().unwrap(); - pending_updates.push(BatchUpdate { - id: vertex_buffer_id, - op: BatchUpdateOp::Destroy, - }); - } - } - } - - #[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_group_id, - draw_list_id, - item_index); - } - pub fn finalize(&mut self, scrolling: &ScrollingState) { self.scrolling = *scrolling; - self.aabb_tree.finalize(); + //self.aabb_tree.finalize(); } +/* pub fn cull(&mut self) { let viewport_rect = self.viewport_rect; let adjusted_viewport = viewport_rect.translate(&-self.world_origin) @@ -105,6 +73,7 @@ impl Layer { pub fn print(&self) { self.aabb_tree.print(NodeIndex(0), 0); } +*/ pub fn overscroll_amount(&self) -> Size2D { let overscroll_x = if self.scrolling.offset.x > 0.0 { diff --git a/src/lib.rs b/src/lib.rs index 53eed4865c..9955277e56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#![feature(step_by)] //#![feature(mpsc_select)] //! A GPU based Webrender. @@ -50,6 +51,7 @@ extern crate log; mod aabbtree; mod batch; mod batch_builder; +mod bsptree; mod debug_font_data; mod debug_render; mod device; @@ -58,15 +60,15 @@ mod freelist; mod geometry; mod internal_types; mod layer; -mod node_compiler; mod profiler; +mod quadtree; mod render_backend; mod resource_cache; mod resource_list; mod scene; mod spring; -mod tessellator; mod texture_cache; +mod tiling; mod util; mod platform { @@ -99,6 +101,7 @@ extern crate app_units; extern crate euclid; extern crate fnv; extern crate gleam; +//extern crate hprof; extern crate ipc_channel; extern crate num_traits; //extern crate notify; diff --git a/src/node_compiler.rs b/src/node_compiler.rs deleted file mode 100644 index e882e6ef0c..0000000000 --- a/src/node_compiler.rs +++ /dev/null @@ -1,165 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use aabbtree::AABBTreeNode; -use batch::{BatchBuilder, VertexBuffer}; -use fnv::FnvHasher; -use frame::{DrawListGroup, FrameId}; -use internal_types::{DrawListItemIndex, CompiledNode, StackingContextInfo}; -use internal_types::{BatchList, StackingContextIndex}; -use internal_types::{DrawListGroupId}; -use std::hash::BuildHasherDefault; -use resource_cache::ResourceCache; -use std::collections::HashMap; -use webrender_traits::{AuxiliaryLists, PipelineId, SpecificDisplayItem}; - -pub trait NodeCompiler { - fn compile(&mut self, - resource_cache: &ResourceCache, - frame_id: FrameId, - device_pixel_ratio: f32, - stacking_context_info: &[StackingContextInfo], - draw_list_groups: &HashMap>, - pipeline_auxiliary_lists: &HashMap>); -} - -impl NodeCompiler for AABBTreeNode { - fn compile(&mut self, - resource_cache: &ResourceCache, - frame_id: FrameId, - device_pixel_ratio: f32, - stacking_context_info: &[StackingContextInfo], - draw_list_groups: &HashMap>, - pipeline_auxiliary_lists: &HashMap>) { - let mut compiled_node = CompiledNode::new(); - let mut vertex_buffer = VertexBuffer::new(); - - for draw_list_group_segment in &self.draw_list_group_segments { - let mut builder = BatchBuilder::new(&mut vertex_buffer, device_pixel_ratio); - - // TODO(gw): This is a HACK to fix matrix palette index offsets - there needs to - // be no holes in this array to match the draw group matrix palette. It's - // noticeable on wikipedia. Find a better solution to this!!! - let draw_list_group = &draw_list_groups[&draw_list_group_segment.draw_list_group_id]; - - for draw_list_id in &draw_list_group.draw_list_ids { - let draw_list_index_buffer = draw_list_group_segment.index_buffers.iter().find(|ib| { - ib.draw_list_id == *draw_list_id - }); - - if let Some(draw_list_index_buffer) = draw_list_index_buffer { - let draw_list = resource_cache.get_draw_list(draw_list_index_buffer.draw_list_id); - let auxiliary_lists = - pipeline_auxiliary_lists.get(&draw_list.pipeline_id) - .expect("No auxiliary lists for pipeline?!"); - - let StackingContextIndex(stacking_context_id) = draw_list.stacking_context_index.unwrap(); - let context = &stacking_context_info[stacking_context_id]; - - let offset_from_layer = context.offset_from_layer; - builder.set_current_clip_rect_offset(offset_from_layer); - - 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_clip_rect); - - if let Some(ref clip_rect) = clip_rect { - builder.push_clip_in_rect(clip_rect); - builder.push_complex_clip( - auxiliary_lists.complex_clip_regions(&display_item.clip.complex)); - - match display_item.item { - SpecificDisplayItem::WebGL(ref info) => { - builder.add_webgl_rectangle(&display_item.rect, - resource_cache, - &info.context_id, - frame_id); - } - SpecificDisplayItem::Image(ref info) => { - builder.add_image(&display_item.rect, - &info.stretch_size, - info.image_key, - info.image_rendering, - resource_cache, - frame_id); - } - SpecificDisplayItem::Text(ref info) => { - let glyphs = auxiliary_lists.glyph_instances(&info.glyphs); - builder.add_text(&display_item.rect, - info.font_key, - info.size, - info.blur_radius, - &info.color, - &glyphs, - resource_cache, - frame_id, - device_pixel_ratio); - } - SpecificDisplayItem::Rectangle(ref info) => { - builder.add_color_rectangle(&display_item.rect, - &info.color, - resource_cache, - frame_id); - } - SpecificDisplayItem::Gradient(ref info) => { - builder.add_gradient(&display_item.rect, - &info.start_point, - &info.end_point, - &info.stops, - auxiliary_lists, - resource_cache, - frame_id); - } - SpecificDisplayItem::BoxShadow(ref info) => { - builder.add_box_shadow(&info.box_bounds, - &info.offset, - &info.color, - info.blur_radius, - info.spread_radius, - info.border_radius, - info.clip_mode, - resource_cache, - frame_id); - } - SpecificDisplayItem::Border(ref info) => { - builder.add_border(&display_item.rect, - info, - resource_cache, - frame_id, - device_pixel_ratio); - } - } - - builder.pop_complex_clip(); - builder.pop_clip_in_rect(); - } - } - } - - builder.next_draw_list(); - } - - let batches = builder.finalize(); - if !batches.is_empty() { - compiled_node.batch_list.push(BatchList { - batches: batches, - draw_list_group_id: draw_list_group_segment.draw_list_group_id, - }); - } - } - - compiled_node.vertex_buffer = Some(vertex_buffer); - self.compiled_node = Some(compiled_node); - } -} diff --git a/src/profiler.rs b/src/profiler.rs index cee9b3ad28..83610667dd 100644 --- a/src/profiler.rs +++ b/src/profiler.rs @@ -172,7 +172,9 @@ pub struct RendererProfileCounters { pub struct RendererProfileTimers { pub cpu_time: TimeProfileCounter, - pub gpu_time: TimeProfileCounter, + pub gpu_time_paint: TimeProfileCounter, + pub gpu_time_composite: TimeProfileCounter, + pub gpu_time_total: TimeProfileCounter, } impl RendererProfileCounters { @@ -196,7 +198,9 @@ impl RendererProfileTimers { pub fn new() -> RendererProfileTimers { RendererProfileTimers { cpu_time: TimeProfileCounter::new("Compositor CPU Time", false), - gpu_time: TimeProfileCounter::new("GPU Time", false), + gpu_time_paint: TimeProfileCounter::new("GPU Time (paint)", false), + gpu_time_composite: TimeProfileCounter::new("GPU Time (composite)", false), + gpu_time_total: TimeProfileCounter::new("GPU Time (total)", false), } } } @@ -432,20 +436,22 @@ impl Profiler { &backend_profile.image_templates, ], debug_renderer, true); - self.draw_counters(&[ - &backend_profile.total_time, - &renderer_timers.cpu_time, - &renderer_timers.gpu_time, - ], debug_renderer, false); - self.draw_counters(&[ &renderer_profile.draw_calls, &renderer_profile.vertices, + ], debug_renderer, true); + + self.draw_counters(&[ + &backend_profile.total_time, + &renderer_timers.cpu_time, + &renderer_timers.gpu_time_paint, + &renderer_timers.gpu_time_composite, + &renderer_timers.gpu_time_total, ], debug_renderer, false); self.backend_time.push(backend_profile.total_time.nanoseconds); self.compositor_time.push(renderer_timers.cpu_time.nanoseconds); - self.gpu_time.push(renderer_timers.gpu_time.nanoseconds); + self.gpu_time.push(renderer_timers.gpu_time_total.nanoseconds); let rect = self.backend_time.draw_graph(self.x_left, self.y_left, "CPU (backend)", debug_renderer); self.y_left += rect.size.height + 10.0; diff --git a/src/quadtree.rs b/src/quadtree.rs new file mode 100644 index 0000000000..092a993794 --- /dev/null +++ b/src/quadtree.rs @@ -0,0 +1,222 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +use euclid::{Point2D, Rect, Size2D}; +use std::fmt::Debug; +use util::{MatrixHelpers, rect_contains_rect, RectHelpers}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct NodeIndex(pub u32); + +pub struct Node { + pub rect: Rect, + pub items: Vec, + // TODO: Use Option + NonZero here + children: Option, +} + +impl Node { + fn new(rect: Rect) -> Node { + Node { + rect: rect, + items: Vec::new(), + children: None, + } + } + + #[inline] + pub fn is_leaf(&self) -> bool { + self.children.is_none() + } +} + +pub struct Quadtree { + pub nodes: Vec>, + pub bounds: Rect, + min_size: f32, + size_threshold: f32, + split_threshold: usize, +} + +impl Quadtree { + pub fn new(rect: Rect, + min_size: f32, + size_threshold: f32, + split_threshold: usize) -> Quadtree { + Quadtree { + bounds: rect, + min_size: min_size, + size_threshold: size_threshold, + split_threshold: split_threshold, + nodes: vec![Node::new(rect)], + } + } + + #[inline] + fn node(&self, node_index: NodeIndex) -> &Node { + let NodeIndex(node_index) = node_index; + let node_index = node_index as usize; + &self.nodes[node_index] + } + + #[inline] + fn node_mut(&mut self, node_index: NodeIndex) -> &mut Node { + let NodeIndex(node_index) = node_index; + let node_index = node_index as usize; + &mut self.nodes[node_index] + } + + #[inline] + fn node_info(&self, node_index: NodeIndex) -> (Rect, usize, bool) { + let NodeIndex(node_index) = node_index; + let node_index = node_index as usize; + let node = &self.nodes[node_index]; + (node.rect, node.items.len(), node.children.is_some()) + } + + fn print_internal(&self, node: NodeIndex, level: usize) { + let mut indent = String::new(); + for _ in 0..level { + indent.push_str(" "); + } + + let node = self.node(node); + println!("{}{:?} c={:?} i={:?}", indent, node.rect, node.children, node.items); + + if let Some(children) = node.children { + let NodeIndex(children) = children; + self.print_internal(NodeIndex(children + 0), level+1); + self.print_internal(NodeIndex(children + 1), level+1); + } + } + + pub fn print(&self) { + self.print_internal(NodeIndex(0), 0); + } + + fn insert_internal(&mut self, + node_index: NodeIndex, + item: T, + level: usize, + f: &F) where F: Fn(T) -> Rect { + let rect = f(item); + let (node_rect, item_count, has_children) = self.node_info(node_index); + debug_assert!(node_rect.intersects(&rect)); + + let can_split = !has_children && (node_rect.size.width > self.min_size || + node_rect.size.height > self.min_size); + let want_split = (item_count == self.split_threshold) || + (self.size_threshold > 0.0 && (node_rect.size.width > self.size_threshold || + node_rect.size.height > self.size_threshold)); + if can_split && want_split { + let x0 = node_rect.origin.x; + let y0 = node_rect.origin.y; + + let x1 = x0 + node_rect.size.width; + let y1 = y0 + node_rect.size.height; + + let (r0, r1) = if node_rect.size.width > node_rect.size.height { + let x_mid = x0 + node_rect.size.width * 0.5; + let r0 = Rect::from_points(x0, y0, x_mid, y1); + let r1 = Rect::from_points(x_mid, y0, x1, y1); + (r0, r1) + } else { + let y_mid = y0 + node_rect.size.height * 0.5; + let r0 = Rect::from_points(x0, y0, x1, y_mid); + let r1 = Rect::from_points(x0, y_mid, x1, y1); + (r0, r1) + }; + + let mut c0 = Node::new(r0); + let mut c1 = Node::new(r1); + //let mut c2 = Node::new(r2); + //let mut c3 = Node::new(r3); + + let mut retained_items = Vec::new(); + for move_item in self.node_mut(node_index).items.drain(..) { + let item_rect = f(move_item); + + let left_int = c0.rect.intersects(&item_rect); + let right_int = c1.rect.intersects(&item_rect); + + match (left_int, right_int) { + (true, true) => retained_items.push(move_item), + (true, false) => c0.items.push(move_item), + (false, true) => c1.items.push(move_item), + (false, false) => unreachable!(), + } + } + self.node_mut(node_index).items = retained_items; + self.node_mut(node_index).children = Some(NodeIndex(self.nodes.len() as u32)); + + self.nodes.push(c0); + self.nodes.push(c1); + } + + let child_index = self.node(node_index).children; + match child_index { + Some(child_index) => { + let NodeIndex(child_index) = child_index; + let child_index = child_index as u32; + + let ci0 = NodeIndex(child_index + 0); + let ci1 = NodeIndex(child_index + 1); + + let left_int = self.node(ci0).rect.intersects(&rect); + let right_int = self.node(ci1).rect.intersects(&rect); + + match (left_int, right_int) { + (true, true) => self.node_mut(node_index).items.push(item), + (true, false) => self.insert_internal(ci0, item, level+1, f), + (false, true) => self.insert_internal(ci1, item, level+1, f), + (false, false) => unreachable!(), + } + } + None => { + self.node_mut(node_index).items.push(item); + } + } + } + + pub fn insert(&mut self, + item: T, + f: &F) where F: Fn(T) -> Rect { + self.insert_internal(NodeIndex(0), item, 0, f); + } + + fn visit_node(&self, + node_index: NodeIndex, + query_rect: &Rect, + f: &mut F) where F: FnMut(&Rect, &Vec) { + let NodeIndex(node_index) = node_index; + let node_index = node_index as usize; + let node = &self.nodes[node_index]; + + if node.rect.intersects(query_rect) { + match node.children { + Some(child_index) => { + let NodeIndex(child_index) = child_index; + let child_index = child_index as u32; + + for i in 0..2 { + self.visit_node(NodeIndex(child_index + i), + query_rect, + f); + } + } + None => { + f(&node.rect, &node.items); + } + } + } + } + + pub fn visit(&self, + query_rect: &Rect, + f: &mut F) where F: FnMut(&Rect, &Vec) { + self.visit_node(NodeIndex(0), query_rect, f); + } +} +*/ diff --git a/src/render_backend.rs b/src/render_backend.rs index 6798324561..3804faee25 100644 --- a/src/render_backend.rs +++ b/src/render_backend.rs @@ -19,6 +19,7 @@ use webrender_traits::{ApiMsg, AuxiliaryLists, BuiltDisplayList, IdNamespace}; use webrender_traits::{PipelineId, RenderNotifier, WebGLContextId}; use batch::new_id; use device::TextureId; +use tiling::FrameBuilderConfig; use offscreen_gl_context::{ColorAttachmentType, GLContext}; use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle}; @@ -50,17 +51,17 @@ impl RenderBackend { result_tx: Sender, device_pixel_ratio: f32, white_image_id: TextureCacheItemId, - dummy_mask_image_id: TextureCacheItemId, texture_cache: TextureCache, enable_aa: bool, notifier: Arc>>>, - webrender_context_handle: Option) -> RenderBackend { + webrender_context_handle: Option, + config: FrameBuilderConfig, + debug: bool) -> RenderBackend { let mut thread_pool = scoped_threadpool::Pool::new(8); let resource_cache = ResourceCache::new(&mut thread_pool, texture_cache, white_image_id, - dummy_mask_image_id, device_pixel_ratio, enable_aa); @@ -73,7 +74,7 @@ impl RenderBackend { device_pixel_ratio: device_pixel_ratio, resource_cache: resource_cache, scene: Scene::new(), - frame: Frame::new(), + frame: Frame::new(debug, config), next_namespace_id: IdNamespace(1), notifier: notifier, webrender_context_handle: webrender_context_handle, @@ -184,7 +185,9 @@ impl RenderBackend { let auxiliary_lists = AuxiliaryLists::from_data(auxiliary_lists_data, auxiliary_lists_descriptor); +// hprof::start_frame(); let frame = profile_counters.total_time.profile(|| { +// let _pf = hprof::enter("root1"); self.scene.set_root_stacking_context(pipeline_id, epoch, stacking_context_id, @@ -196,27 +199,37 @@ impl RenderBackend { self.build_scene(); self.render() }); +// hprof::end_frame(); + //hprof::profiler().print_timing(); self.publish_frame_and_notify_compositor(frame, &mut profile_counters); } ApiMsg::SetRootPipeline(pipeline_id) => { +// hprof::start_frame(); let frame = profile_counters.total_time.profile(|| { +// let _pf = hprof::enter("root2"); self.scene.set_root_pipeline_id(pipeline_id); self.build_scene(); self.render() }); +// hprof::end_frame(); + //hprof::profiler().print_timing(); self.publish_frame(frame, &mut profile_counters); } ApiMsg::Scroll(delta, cursor, move_phase) => { +// hprof::start_frame(); let frame = profile_counters.total_time.profile(|| { if self.frame.scroll(delta, cursor, move_phase) { + self.build_scene(); Some(self.render()) } else { None } }); +// hprof::end_frame(); + //hprof::profiler().print_timing(); match frame { Some(frame) => { @@ -388,8 +401,7 @@ impl RenderBackend { fn publish_frame(&mut self, frame: RendererFrame, profile_counters: &mut BackendProfileCounters) { - let pending_updates = self.frame.pending_updates(); - let msg = ResultMsg::NewFrame(frame, pending_updates, profile_counters.clone()); + let msg = ResultMsg::NewFrame(frame, profile_counters.clone()); self.result_tx.send(msg).unwrap(); profile_counters.reset(); } diff --git a/src/renderer.rs b/src/renderer.rs index 608f7d3652..7d90533239 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -9,46 +9,44 @@ //! //! [renderer]: struct.Renderer.html -use batch::{RasterBatch, VertexBufferId}; -use bit_set::BitSet; +use batch::RasterBatch; use debug_render::DebugRenderer; use device::{Device, ProgramId, TextureId, UniformLocation, VertexFormat, GpuProfile}; -use device::{TextureFilter, VAOId, VBOId, VertexUsageHint, FileWatcherHandler}; -use euclid::{Matrix4D, Point2D, Point4D, Rect, Size2D}; -use fnv::FnvHasher; +use device::{TextureFilter, VAOId, VertexUsageHint, FileWatcherHandler}; +use euclid::{Matrix4D, Point2D, Rect, Size2D}; use gleam::gl; -use internal_types::{RendererFrame, ResultMsg, TextureUpdateOp, BatchUpdateOp, BatchUpdateList}; +use internal_types::{RendererFrame, ResultMsg, TextureUpdateOp}; use internal_types::{TextureUpdateDetails, TextureUpdateList, PackedVertex, RenderTargetMode}; use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, DevicePixel}; -use internal_types::{PackedVertexForTextureCacheUpdate, CompositionOp, ChildLayerIndex}; -use internal_types::{AxisDirection, LowLevelFilterOp, DrawCommand, DrawLayer, ANGLE_FLOAT_TO_FIXED}; -use internal_types::{BasicRotationAngle, RenderTargetId}; +use internal_types::{PackedVertexForTextureCacheUpdate, CompositionOp}; +use internal_types::{AxisDirection}; use ipc_channel::ipc; use profiler::{Profiler, BackendProfileCounters}; use profiler::{RendererProfileTimers, RendererProfileCounters}; use render_backend::RenderBackend; -use std::collections::HashMap; +use std::cmp; use std::f32; -use std::hash::BuildHasherDefault; use std::mem; use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; -use tessellator::BorderCornerTessellation; use texture_cache::{BorderType, TextureCache, TextureInsertOp}; +use tiling::{self, Frame, FrameBuilderConfig, PrimitiveBatchData, PackedTile}; +use tiling::{TransformedRectKind, RenderTarget, CompositeTile, ClearTile, PackedLayer}; use time::precise_time_ns; use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier}; use webrender_traits::{ImageFormat, MixBlendMode, RenderApiSender}; use offscreen_gl_context::{NativeGLContext, NativeGLContextMethods}; -use util::{MatrixHelpers, RectHelpers}; pub const BLUR_INFLATION_FACTOR: u32 = 3; pub const MAX_RASTER_OP_SIZE: u32 = 2048; -const MAX_CACHED_QUAD_VAOS: usize = 8; - -// TODO(gw): HACK! Need to support lighten/darken mix-blend-mode properly on android... +const UBO_BIND_LAYERS: u32 = 1; +const UBO_BIND_CLEAR_TILES: u32 = 2; +const UBO_BIND_PRIM_TILES: u32 = 3; +const UBO_BIND_COMPOSITE_TILES: u32 = 4; +const UBO_BIND_CACHE_ITEMS: u32 = 5; #[derive(Clone, Copy)] struct VertexBuffer { @@ -84,13 +82,6 @@ impl CompositionOpHelpers for CompositionOp { } } -struct RenderContext { - blend_program_id: ProgramId, - filter_program_id: ProgramId, - device_pixel_ratio: f32, - framebuffer_size: Size2D, -} - struct FileWatcher { notifier: Arc>>>, result_tx: Sender, @@ -104,44 +95,122 @@ impl FileWatcherHandler for FileWatcher { } } +fn get_ubo_max_len(max_ubo_size: usize) -> usize { + let item_size = mem::size_of::(); + let max_items = max_ubo_size / item_size; + + // TODO(gw): Clamping to 512 since some shader compilers + // seem to go very slow when you have high + // constants for array lengths. Investigate + // whether this clamping actually hurts performance! + cmp::min(max_items, 512) +} + +fn create_composite_shader(name: &'static str, + device: &mut Device, + max_composite_tiles: usize) -> ProgramId { + let prefix = format!("#define WR_MAX_COMPOSITE_TILES {}", max_composite_tiles); + + let program_id = device.create_program_with_prefix(name, + "composite_shared", + Some(prefix)); + + let tiles_index = gl::get_uniform_block_index(program_id.0, "Tiles"); + gl::uniform_block_binding(program_id.0, tiles_index, UBO_BIND_COMPOSITE_TILES); + + println!("CompositeShader {}: tiles={}/{}", name, tiles_index, max_composite_tiles); + + program_id +} + +fn create_prim_shader(name: &'static str, + device: &mut Device, + max_prim_tiles: usize, + max_prim_layers: usize, + max_prim_items: usize) -> ProgramId { + let prefix = format!("#define WR_MAX_PRIM_TILES {}\n#define WR_MAX_PRIM_LAYERS {}\n#define WR_MAX_PRIM_ITEMS {}\n", max_prim_tiles, + max_prim_layers, + max_prim_items); + + let program_id = device.create_program_with_prefix(name, + "prim_shared", + Some(prefix)); + + let tiles_index = gl::get_uniform_block_index(program_id.0, "Tiles"); + gl::uniform_block_binding(program_id.0, tiles_index, UBO_BIND_PRIM_TILES); + + let layer_index = gl::get_uniform_block_index(program_id.0, "Layers"); + gl::uniform_block_binding(program_id.0, layer_index, UBO_BIND_LAYERS); + + let item_index = gl::get_uniform_block_index(program_id.0, "Items"); + gl::uniform_block_binding(program_id.0, item_index, UBO_BIND_CACHE_ITEMS); + + println!("PrimShader {}: items={}/{} tiles={}/{} layers={}/{}", name, + item_index, + max_prim_items, + tiles_index, + max_prim_tiles, + layer_index, + max_prim_layers); + + program_id +} + +fn create_clear_shader(name: &'static str, + device: &mut Device, + max_clear_tiles: usize) -> ProgramId { + let prefix = format!("#define WR_MAX_CLEAR_TILES {}", max_clear_tiles); + + let program_id = device.create_program_with_prefix(name, + "shared_other", + Some(prefix)); + + let tile_index = gl::get_uniform_block_index(program_id.0, "Tiles"); + gl::uniform_block_binding(program_id.0, tile_index, UBO_BIND_CLEAR_TILES); + + println!("ClearShader {}: tiles={}/{}", name, tile_index, max_clear_tiles); + + program_id +} + pub struct Renderer { result_rx: Receiver, device: Device, pending_texture_updates: Vec, - pending_batch_updates: Vec, pending_shader_updates: Vec, current_frame: Option, device_pixel_ratio: f32, - vertex_buffers: HashMap, BuildHasherDefault>, raster_batches: Vec, - quad_vertex_buffer: Option, - cached_quad_vaos: Vec, - simple_triangles_vao: Option, raster_op_vao: Option, - quad_program_id: ProgramId, - u_quad_transform_array: UniformLocation, - u_quad_offset_array: UniformLocation, - u_tile_params: UniformLocation, - u_clip_rects: UniformLocation, - u_atlas_params: UniformLocation, - - blit_program_id: ProgramId, - - border_program_id: ProgramId, - - blend_program_id: ProgramId, - u_blend_params: UniformLocation, - - filter_program_id: ProgramId, - u_filter_params: UniformLocation, - box_shadow_program_id: ProgramId, blur_program_id: ProgramId, u_direction: UniformLocation, - mask_program_id: ProgramId, + ps_rectangle: ProgramId, + ps_rectangle_clip: ProgramId, + ps_text: ProgramId, + ps_image: ProgramId, + ps_border: ProgramId, + ps_box_shadow: ProgramId, + ps_gradient: ProgramId, + + ps_rectangle_transform: ProgramId, + ps_image_transform: ProgramId, + + composite_shaders: [ProgramId; 8], + tile_clear_shader: ProgramId, + + max_clear_tiles: usize, + max_prim_rectangles: usize, + max_prim_rectangles_clip: usize, + max_prim_texts: usize, + max_prim_images: usize, + max_prim_borders: usize, + max_prim_box_shadows: usize, + max_prim_gradients: usize, + max_composite_tiles: usize, notifier: Arc>>>, @@ -156,9 +225,11 @@ pub struct Renderer { max_raster_op_size: u32, raster_op_target_a8: TextureId, raster_op_target_rgba8: TextureId, - temporary_fb_texture: TextureId, + render_targets: [TextureId; 2], - gpu_profile: GpuProfile, + gpu_profile_paint: GpuProfile, + gpu_profile_composite: GpuProfile, + quad_vao_id: VAOId, } impl Renderer { @@ -198,16 +269,84 @@ impl Renderer { Box::new(file_watch_handler)); device.begin_frame(); - let quad_program_id = device.create_program("quad"); - let blit_program_id = device.create_program("blit"); - let border_program_id = device.create_program("border"); - let blend_program_id = device.create_program("blend"); - let filter_program_id = device.create_program("filter"); - let box_shadow_program_id = device.create_program("box_shadow"); - let blur_program_id = device.create_program("blur"); - let mask_program_id = device.create_program("mask"); + let box_shadow_program_id = device.create_program("box_shadow", "shared_other"); + let blur_program_id = device.create_program("blur", "shared_other"); let max_raster_op_size = MAX_RASTER_OP_SIZE * options.device_pixel_ratio as u32; + let max_ubo_size = gl::get_integer_v(gl::MAX_UNIFORM_BLOCK_SIZE) as usize; + let max_prim_tiles = get_ubo_max_len::(max_ubo_size); + let max_prim_layers = get_ubo_max_len::(max_ubo_size); + + let max_prim_rectangles = get_ubo_max_len::(max_ubo_size); + let max_prim_rectangles_clip = get_ubo_max_len::(max_ubo_size); + let max_prim_texts = get_ubo_max_len::(max_ubo_size); + let max_prim_images = get_ubo_max_len::(max_ubo_size); + let max_prim_borders = get_ubo_max_len::(max_ubo_size); + let max_prim_box_shadows = get_ubo_max_len::(max_ubo_size); + let max_prim_gradients = get_ubo_max_len::(max_ubo_size); + + let ps_rectangle = create_prim_shader("ps_rectangle", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_rectangles); + let ps_rectangle_clip = create_prim_shader("ps_rectangle_clip", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_rectangles_clip); + let ps_text = create_prim_shader("ps_text", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_texts); + let ps_image = create_prim_shader("ps_image", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_images); + let ps_border = create_prim_shader("ps_border", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_borders); + let ps_box_shadow = create_prim_shader("ps_box_shadow", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_box_shadows); + let ps_gradient = create_prim_shader("ps_gradient", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_gradients); + + let ps_rectangle_transform = create_prim_shader("ps_rectangle_transform", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_rectangles); + let ps_image_transform = create_prim_shader("ps_image_transform", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_images); + + let max_clear_tiles = get_ubo_max_len::(max_ubo_size); + let tile_clear_shader = create_clear_shader("ps_clear", &mut device, max_clear_tiles); + + let max_composite_tiles = get_ubo_max_len::(max_ubo_size); + let composite_shaders: [ProgramId; 8] = [ + create_composite_shader("cs_p1", &mut device, max_composite_tiles), + create_composite_shader("cs_p2", &mut device, max_composite_tiles), + create_composite_shader("cs_p3", &mut device, max_composite_tiles), + create_composite_shader("cs_p4", &mut device, max_composite_tiles), + create_composite_shader("cs_p5", &mut device, max_composite_tiles), + create_composite_shader("cs_p6", &mut device, max_composite_tiles), + create_composite_shader("cs_p7", &mut device, max_composite_tiles), + create_composite_shader("cs_p8", &mut device, max_composite_tiles), + ]; + let texture_ids = device.create_texture_ids(1024); let mut texture_cache = TextureCache::new(texture_ids); let white_pixels: Vec = vec![ @@ -263,7 +402,32 @@ impl Renderer { RenderTargetMode::RenderTarget, None); - let temporary_fb_texture = device.create_texture_ids(1)[0]; + let x0 = 0.0; + let y0 = 0.0; + let x1 = 1.0; + let y1 = 1.0; + + // TODO(gw): Consider separate VBO for quads vs border corners if VS ever shows up in profile! + let quad_indices: [u16; 6] = [ 0, 1, 2, 2, 1, 3 ]; + let quad_vertices = [ + PackedVertex { + pos: [x0, y0], + }, + PackedVertex { + pos: [x1, y0], + }, + PackedVertex { + pos: [x0, y1], + }, + PackedVertex { + pos: [x1, y1], + }, + ]; + + let quad_vao_id = device.create_vao(VertexFormat::Triangles, None); + device.bind_vao(quad_vao_id); + device.update_vao_indices(quad_vao_id, &quad_indices, VertexUsageHint::Static); + device.update_vao_main_vertices(quad_vao_id, &quad_vertices, VertexUsageHint::Static); device.end_frame(); @@ -273,6 +437,10 @@ impl Renderer { // texture ids let context_handle = NativeGLContext::current_handle(); + let config = FrameBuilderConfig::new(max_prim_layers, + max_prim_tiles); + + let debug = options.debug; let (device_pixel_ratio, enable_aa) = (options.device_pixel_ratio, options.enable_aa); let payload_tx_for_backend = payload_tx.clone(); thread::spawn(move || { @@ -282,11 +450,12 @@ impl Renderer { result_tx, device_pixel_ratio, white_image_id, - dummy_mask_image_id, texture_cache, enable_aa, backend_notifier, - context_handle); + context_handle, + config, + debug); backend.run(); }); @@ -294,32 +463,34 @@ impl Renderer { result_rx: result_rx, device: device, current_frame: None, - vertex_buffers: HashMap::with_hasher(Default::default()), raster_batches: Vec::new(), - quad_vertex_buffer: None, - simple_triangles_vao: None, raster_op_vao: None, - cached_quad_vaos: Vec::new(), pending_texture_updates: Vec::new(), - pending_batch_updates: Vec::new(), pending_shader_updates: Vec::new(), - border_program_id: border_program_id, device_pixel_ratio: options.device_pixel_ratio, - blend_program_id: blend_program_id, - filter_program_id: filter_program_id, - quad_program_id: quad_program_id, - blit_program_id: blit_program_id, box_shadow_program_id: box_shadow_program_id, blur_program_id: blur_program_id, - mask_program_id: mask_program_id, - u_blend_params: UniformLocation::invalid(), - u_filter_params: UniformLocation::invalid(), + tile_clear_shader: tile_clear_shader, + ps_rectangle: ps_rectangle, + ps_rectangle_clip: ps_rectangle_clip, + ps_text: ps_text, + ps_image: ps_image, + ps_border: ps_border, + ps_box_shadow: ps_box_shadow, + ps_gradient: ps_gradient, + ps_rectangle_transform: ps_rectangle_transform, + ps_image_transform: ps_image_transform, + max_clear_tiles: max_clear_tiles, + max_prim_rectangles: max_prim_rectangles, + max_prim_rectangles_clip: max_prim_rectangles_clip, + max_prim_texts: max_prim_texts, + max_prim_images: max_prim_images, + max_prim_borders: max_prim_borders, + max_prim_box_shadows: max_prim_box_shadows, + max_prim_gradients: max_prim_gradients, + max_composite_tiles: max_composite_tiles, + composite_shaders: composite_shaders, u_direction: UniformLocation::invalid(), - u_quad_offset_array: UniformLocation::invalid(), - u_quad_transform_array: UniformLocation::invalid(), - u_atlas_params: UniformLocation::invalid(), - u_tile_params: UniformLocation::invalid(), - u_clip_rects: UniformLocation::invalid(), notifier: notifier, debug: debug_renderer, backend_profile_counters: BackendProfileCounters::new(), @@ -330,9 +501,11 @@ impl Renderer { last_time: 0, raster_op_target_a8: raster_op_target_a8, raster_op_target_rgba8: raster_op_target_rgba8, - temporary_fb_texture: temporary_fb_texture, + render_targets: [TextureId(0), TextureId(0)], max_raster_op_size: max_raster_op_size, - gpu_profile: GpuProfile::new(), + gpu_profile_paint: GpuProfile::new(), + gpu_profile_composite: GpuProfile::new(), + quad_vao_id: quad_vao_id, }; renderer.update_uniform_locations(); @@ -357,13 +530,6 @@ impl Renderer { } fn update_uniform_locations(&mut self) { - self.u_quad_transform_array = self.device.get_uniform_location(self.quad_program_id, "uMatrixPalette"); - self.u_quad_offset_array = self.device.get_uniform_location(self.quad_program_id, "uOffsets"); - self.u_tile_params = self.device.get_uniform_location(self.quad_program_id, "uTileParams"); - self.u_clip_rects = self.device.get_uniform_location(self.quad_program_id, "uClipRects"); - self.u_atlas_params = self.device.get_uniform_location(self.quad_program_id, "uAtlasParams"); - self.u_blend_params = self.device.get_uniform_location(self.blend_program_id, "uBlendParams"); - self.u_filter_params = self.device.get_uniform_location(self.filter_program_id, "uFilterParams"); self.u_direction = self.device.get_uniform_location(self.blur_program_id, "uDirection"); } @@ -393,9 +559,8 @@ impl Renderer { ResultMsg::UpdateTextureCache(update_list) => { self.pending_texture_updates.push(update_list); } - ResultMsg::NewFrame(frame, update_list, profile_counters) => { + ResultMsg::NewFrame(frame, profile_counters) => { self.backend_profile_counters = profile_counters; - self.pending_batch_updates.push(update_list); self.current_frame = Some(frame); } ResultMsg::RefreshShader(path) => { @@ -412,17 +577,20 @@ impl Renderer { pub fn render(&mut self, framebuffer_size: Size2D) { let mut profile_timers = RendererProfileTimers::new(); - self.gpu_profile.begin(); + // Block CPU waiting for last frame's GPU profiles to arrive. + // In general this shouldn't block unless heavily GPU limited. + let paint_ns = self.gpu_profile_paint.get(); + let composite_ns = self.gpu_profile_composite.get(); profile_timers.cpu_time.profile(|| { self.device.begin_frame(); gl::disable(gl::SCISSOR_TEST); - gl::clear_color(1.0, 1.0, 1.0, 0.0); + //gl::clear_color(1.0, 1.0, 1.0, 0.0); + //gl::clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); - self.update_shaders(); + //self.update_shaders(); self.update_texture_cache(); - self.update_batches(); self.draw_frame(framebuffer_size); }); @@ -430,8 +598,11 @@ impl Renderer { let ns = current_time - self.last_time; self.profile_counters.frame_time.set(ns); - let gpu_ns = self.gpu_profile.end(); - profile_timers.gpu_time.set(gpu_ns); + profile_timers.gpu_time_paint.set(paint_ns); + profile_timers.gpu_time_composite.set(composite_ns); + + let gpu_ns = paint_ns + composite_ns; + profile_timers.gpu_time_total.set(gpu_ns); if self.enable_profiler { self.profiler.draw_profile(&self.backend_profile_counters, @@ -443,8 +614,8 @@ impl Renderer { self.profile_counters.reset(); self.profile_counters.frame_counter.inc(); - let debug_size = Size2D::new((framebuffer_size.width as f32 / self.device_pixel_ratio) as u32, - (framebuffer_size.height as f32 / self.device_pixel_ratio) as u32); + let debug_size = Size2D::new(framebuffer_size.width as u32, + framebuffer_size.height as u32); self.debug.render(&mut self.device, &debug_size); self.device.end_frame(); self.last_time = current_time; @@ -457,67 +628,20 @@ impl Renderer { } } - fn update_batches(&mut self) { - let mut pending_batch_updates = mem::replace(&mut self.pending_batch_updates, vec![]); - for update_list in pending_batch_updates.drain(..) { - for update in update_list.updates { - match update.op { - BatchUpdateOp::Create(vertices) => { - if self.quad_vertex_buffer.is_none() { - self.quad_vertex_buffer = Some(self.device.create_quad_vertex_buffer()) - } - - let vao_id = match self.cached_quad_vaos.pop() { - Some(quad_vao_id) => quad_vao_id, - None => { - self.device.create_vao(VertexFormat::Rectangles, - Some(self.quad_vertex_buffer.unwrap())) - } - }; - - self.device.bind_vao(vao_id); - - self.device.update_vao_aux_vertices(vao_id, - &vertices, - VertexUsageHint::Static); - - self.vertex_buffers.insert(update.id, vec![ - VertexBufferAndOffset { - buffer: VertexBuffer { - vao_id: vao_id, - }, - offset: 0, - } - ]); - } - BatchUpdateOp::Destroy => { - let vertex_buffers_and_offsets = - self.vertex_buffers.remove(&update.id).unwrap(); - for vertex_buffer_and_offset in vertex_buffers_and_offsets.into_iter() { - if self.cached_quad_vaos.len() < MAX_CACHED_QUAD_VAOS && - vertex_buffer_and_offset.offset == 0 { - self.cached_quad_vaos.push(vertex_buffer_and_offset.buffer.vao_id); - } else { - self.device.delete_vao(vertex_buffer_and_offset.buffer.vao_id); - } - } - } - } - } - } - } - +/* fn update_shaders(&mut self) { let update_uniforms = !self.pending_shader_updates.is_empty(); for path in self.pending_shader_updates.drain(..) { - self.device.refresh_shader(path); + panic!("todo"); + //self.device.refresh_shader(path); } if update_uniforms { self.update_uniform_locations(); } } +*/ fn update_texture_cache(&mut self) { let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]); @@ -713,108 +837,6 @@ impl Renderer { ] }); } - TextureUpdateDetails::BorderRadius(outer_rx, - outer_ry, - inner_rx, - inner_ry, - index, - inverted, - border_type) => { - // From here on out everything is in device coordinates. - let border_program_id = self.border_program_id; - let color = if inverted { - ColorF::new(0.0, 0.0, 0.0, 1.0) - } else { - ColorF::new(1.0, 1.0, 1.0, 1.0) - }; - - let border_radii_outer = Point2D::new(outer_rx.as_f32(), outer_ry.as_f32()); - let border_radii_inner = Point2D::new(inner_rx.as_f32(), inner_ry.as_f32()); - - let zero_point = Point2D::new(0.0, 0.0); - let zero_size = Size2D::new(0.0, 0.0); - - self.add_rect_to_raster_batch(update.id, - TextureId(0), - border_program_id, - None, - &Rect::new(Point2D::new(x as u32, y as u32), - Size2D::new(width as u32, height as u32)), - border_type, - |texture_rect| { - let border_radii_outer_size = - Size2D::new(border_radii_outer.x, - border_radii_outer.y); - let border_radii_inner_size = - Size2D::new(border_radii_inner.x, - border_radii_inner.y); - let untessellated_rect = - Rect::new(texture_rect.origin, border_radii_outer_size); - let tessellated_rect = - match index { - None => untessellated_rect, - Some(index) => { - untessellated_rect.tessellate_border_corner( - &border_radii_outer_size, - &border_radii_inner_size, - 1.0, - BasicRotationAngle::Upright, - index) - } - }; - - let border_position = - untessellated_rect.bottom_right() - - (tessellated_rect.origin - texture_rect.origin); - - [ - PackedVertexForTextureCacheUpdate::new( - &texture_rect.origin, - &color, - &zero_point, - &border_radii_outer, - &border_radii_inner, - &border_position, - &zero_point, - &zero_size, - &zero_size, - 0.0), - PackedVertexForTextureCacheUpdate::new( - &texture_rect.top_right(), - &color, - &zero_point, - &border_radii_outer, - &border_radii_inner, - &border_position, - &zero_point, - &zero_size, - &zero_size, - 0.0), - PackedVertexForTextureCacheUpdate::new( - &texture_rect.bottom_left(), - &color, - &zero_point, - &border_radii_outer, - &border_radii_inner, - &border_position, - &zero_point, - &zero_size, - &zero_size, - 0.0), - PackedVertexForTextureCacheUpdate::new( - &texture_rect.bottom_right(), - &color, - &zero_point, - &border_radii_outer, - &border_radii_inner, - &border_position, - &zero_point, - &zero_size, - &zero_size, - 0.0), - ] - }); - } TextureUpdateDetails::BoxShadow(blur_radius, border_radius, box_rect_size, @@ -1153,728 +1175,408 @@ impl Renderer { } } - fn compute_layer_viewport_in_render_target_space(&self, layer: &DrawLayer) -> Rect { - let layer_origin = Point2D::new(layer.origin.x * self.device_pixel_ratio, - layer.origin.y * self.device_pixel_ratio); - let layer_size = Size2D::new(layer.size.width * self.device_pixel_ratio, - layer.size.height * self.device_pixel_ratio); - Rect::new(layer_origin, layer_size) + fn add_debug_rect(&mut self, + p0: Point2D, + p1: Point2D, + label: &str, + c: &ColorF) { + let tile_x0 = p0.x; + let tile_y0 = p0.y; + let tile_x1 = p1.x; + let tile_y1 = p1.y; + + //let c = &ColorF::new(1.0, 0.0, 1.0, 1.0); + + self.debug.add_line(tile_x0, + tile_y0, + c,//&ColorF::new(0.0, 0.0, 0.0, 1.0), + tile_x1, + tile_y0, + c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + self.debug.add_line(tile_x0, + tile_y1, + c,//&ColorF::new(0.0, 0.0, 0.0, 1.0), + tile_x1, + tile_y1, + c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + self.debug.add_line(tile_x0, + tile_y0, + c,//&ColorF::new(0.0, 0.0, 0.0, 1.0), + tile_x0, + tile_y1, + c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + self.debug.add_line(tile_x1, + tile_y0, + c,//&ColorF::new(0.0, 0.0, 0.0, 1.0), + tile_x1, + tile_y1, + c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + if label.len() > 0 { + self.debug.add_text((tile_x0.0 as f32 + tile_x1.0 as f32) * 0.5, + (tile_y0.0 as f32 + tile_y1.0 as f32) * 0.5, + label, + c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + } } - fn calculate_layer_viewports(&self, - layer: &DrawLayer, - render_context: &RenderContext, - viewport: &Rect, - layer_viewports: &mut HashMap>) { - layer_viewports.insert(layer.id, *viewport); - - let mut indices_of_composited_children = BitSet::new(); - for command in &layer.commands { - match *command { - DrawCommand::CompositeBatch(ref info) => { - for job in &info.jobs { - indices_of_composited_children.insert(job.child_layer_index.0 as usize); - let child_layer = &layer.child_layers[job.child_layer_index.0 as usize]; - if let Some(ref new_viewport) = job.world_transform - .transform_rect(&job.rect) - .intersection(viewport) { - self.calculate_layer_viewports(child_layer, - render_context, - new_viewport, - layer_viewports) - } - } - } - DrawCommand::Batch(_) | DrawCommand::Clear(_) => {} - } + fn draw_target(&mut self, + render_target: Option, + target: &RenderTarget, + target_size: &Size2D, + cache_texture: TextureId, + should_clear: bool) { + self.device.bind_render_target(render_target); + gl::viewport(0, + 0, + target_size.width as i32, + target_size.height as i32); + + gl::disable(gl::BLEND); + + // TODO(gw): oops! + self.device.bind_cache_texture(cache_texture); + for i in 0..8 { + self.device.bind_layer_texture(i, cache_texture); } - for (index, child_layer) in layer.child_layers.iter().enumerate() { - if !indices_of_composited_children.contains(index) { - // FIXME(pcwalton): This is probably wrong for nested composites. - let layer_viewport = - self.compute_layer_viewport_in_render_target_space(child_layer); - println!("calculate_layer_viewports: child layer_viewport={:?}", layer_viewport); - if let Some(ref new_viewport) = layer_viewport.intersection(viewport) { - self.calculate_layer_viewports(child_layer, - render_context, - new_viewport, - layer_viewports) - } + let projection = match render_target { + Some(..) => { + // todo(gw): remove me! + gl::clear_color(0.0, 0.0, 0.0, 0.0); + + Matrix4D::ortho(0.0, + target_size.width as f32, + 0.0, + target_size.height as f32, + ORTHO_NEAR_PLANE, + ORTHO_FAR_PLANE) } - } - } + None => { + // todo(gw): remove me! + gl::clear_color(1.0, 1.0, 1.0, 1.0); + + Matrix4D::ortho(0.0, + target_size.width as f32, + target_size.height as f32, + 0.0, + ORTHO_NEAR_PLANE, + ORTHO_FAR_PLANE) + } + }; - fn draw_layer(&mut self, - layer: &DrawLayer, - render_context: &RenderContext, - layer_viewports: &HashMap>) { - // Draw child layers first, to ensure that dependent render targets - // have been built before they are read as a texture. - for child in &layer.child_layers { - self.draw_layer(child, render_context, layer_viewports) + // todo(gw): remove me! + if should_clear { + gl::clear(gl::COLOR_BUFFER_BIT); } - if !layer_viewports.contains_key(&layer.id) { - // Off screen. - return - } + for alpha_task in &target.alpha_batch_tasks { + let misc_ubos = gl::gen_buffers(2); + let layer_ubo = misc_ubos[0]; + let tile_ubo = misc_ubos[1]; - self.device.bind_render_target(layer.texture_id); + gl::bind_buffer(gl::UNIFORM_BUFFER, layer_ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &alpha_task.layer_ubo, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_LAYERS, layer_ubo); - // TODO(gw): This may not be needed in all cases... - let layer_viewport = self.compute_layer_viewport_in_render_target_space(layer); - let layer_viewport = - Rect::new(Point2D::new(layer_viewport.origin.x.round() as gl::GLint, - layer_viewport.origin.y.round() as gl::GLint), - Size2D::new(layer_viewport.size.width.round() as gl::GLint, - layer_viewport.size.height.round() as gl::GLint)); + gl::bind_buffer(gl::UNIFORM_BUFFER, tile_ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &alpha_task.tile_ubo, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_PRIM_TILES, tile_ubo); - set_scissor_or_viewport(&layer_viewport, render_context, layer.texture_id, gl::scissor); - set_scissor_or_viewport(&layer_viewport, render_context, layer.texture_id, gl::viewport); + gl::enable(gl::BLEND); + gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); + gl::blend_equation(gl::FUNC_ADD); + + for batch in &alpha_task.batches { + match &batch.data { + &PrimitiveBatchData::Rectangles(ref ubo_data) => { + let shader = match batch.transform_kind { + TransformedRectKind::AxisAligned => self.ps_rectangle, + TransformedRectKind::Complex => self.ps_rectangle_transform, + }; + self.device.bind_program(shader, &projection); + self.device.bind_vao(self.quad_vao_id); - gl::clear_color(1.0, 1.0, 1.0, 0.0); - gl::clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT); + for chunk in ubo_data.chunks(self.max_prim_rectangles) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; - let projection = Matrix4D::ortho(0.0, - layer.size.width, - layer.size.height, - 0.0, - ORTHO_NEAR_PLANE, - ORTHO_FAR_PLANE); + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); - for cmd in &layer.commands { - match cmd { - &DrawCommand::Clear(ref info) => { - let mut clear_bits = 0; - if info.clear_color { - clear_bits |= gl::COLOR_BUFFER_BIT; - } - if info.clear_z { - clear_bits |= gl::DEPTH_BUFFER_BIT; - } - if info.clear_stencil { - clear_bits |= gl::STENCIL_BUFFER_BIT; - } - gl::clear(clear_bits); - } - &DrawCommand::Batch(ref info) => { - // TODO: probably worth sorting front to back to minimize overdraw (if profiling shows fragment / rop bound) - - self.enable_msaa(true); - - gl::enable(gl::BLEND); - gl::blend_func_separate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, - gl::ONE, gl::ONE); - gl::blend_equation(gl::FUNC_ADD); - - self.device.bind_program(self.quad_program_id, &projection); - - if !info.offset_palette.is_empty() { - // TODO(gw): Avoid alloc here... - let mut floats = Vec::new(); - for vec in &info.offset_palette { - floats.push(vec.stacking_context_x0); - floats.push(vec.stacking_context_y0); - floats.push(vec.render_target_x0); - floats.push(vec.render_target_y0); - } + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); - self.device.set_uniform_vec4_array(self.u_quad_offset_array, - &floats); + gl::delete_buffers(&ubos); + } } + &PrimitiveBatchData::RectanglesClip(ref ubo_data) => { + self.device.bind_program(self.ps_rectangle_clip, &projection); + self.device.bind_vao(self.quad_vao_id); - self.device.set_uniform_mat4_array(self.u_quad_transform_array, - &info.matrix_palette); - - // Render any masks to the stencil buffer. - for region in &info.regions { - let mut valid_mask_count = 0; - let mut scissor_rect = layer_viewport; - for mask in ®ion.masks { - - // If we can represent the mask by just adjusting the scissor rect, - // don't draw it. - if mask.transform - .can_losslessly_transform_and_perspective_project_a_2d_rect() { - // Convert the mask rect to 4D points. - let top_left = to_point4d(&mask.rect.origin); - let top_right = to_point4d(&mask.rect.top_right()); - let bottom_right = to_point4d(&mask.rect.bottom_right()); - let bottom_left = to_point4d(&mask.rect.bottom_left()); - - // Transform in normalized device coordinates. - let transform = projection.mul(&mask.transform); - let top_left = - transform.transform_point_and_perspective_project(&top_left); - let top_right = - transform.transform_point_and_perspective_project(&top_right); - let bottom_right = - transform.transform_point_and_perspective_project( - &bottom_right); - let bottom_left = - transform.transform_point_and_perspective_project( - &bottom_left); - let transformed_mask_rect = Rect::from_points(&top_left, - &top_right, - &bottom_right, - &bottom_left); - - // Convert to window coordinates. - let transformed_mask_origin = Point2D::new( - (transformed_mask_rect.origin.x + 1.0) / 2.0 * - layer_viewport.size.width as f32 + - layer_viewport.origin.x as f32, - (1.0 - transformed_mask_rect.size.height - - transformed_mask_rect.origin.y) / 2.0 * - layer_viewport.size.height as f32 + - layer_viewport.origin.y as f32); - let transformed_mask_size = Size2D::new( - transformed_mask_rect.size.width / 2.0 * - layer_viewport.size.width as f32, - transformed_mask_rect.size.height / 2.0 * - layer_viewport.size.height as f32); - let transformed_mask_rect = Rect::new(transformed_mask_origin, - transformed_mask_size); - - // Round and convert to integers. - let transformed_mask_origin = - Point2D::new(transformed_mask_rect.origin.x.round() as i32, - transformed_mask_rect.origin.y.round() as i32); - let transformed_mask_size = - Size2D::new(transformed_mask_rect.size.width.round() as i32, - transformed_mask_rect.size.height.round() as i32); - let transformed_mask_rect = Rect::new(transformed_mask_origin, - transformed_mask_size); - - scissor_rect = transformed_mask_rect.intersection(&scissor_rect) - .unwrap_or(Rect::zero()); - continue - } + for chunk in ubo_data.chunks(self.max_prim_rectangles_clip) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; - // First time we find a valid mask, clear stencil and setup render states - if valid_mask_count == 0 { - // TODO(pcwalton): Don't clear stencil if already clear!!! - gl::clear(gl::STENCIL_BUFFER_BIT); - gl::enable(gl::STENCIL_TEST); - gl::color_mask(false, false, false, false); - gl::depth_mask(false); - gl::stencil_mask(0xff); - gl::stencil_func(gl::ALWAYS, 1, 0xff); - gl::stencil_op(gl::KEEP, gl::INCR, gl::INCR) - } + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); - // TODO(gw): The below is a copy pasta and can be trivially optimized. - let (mut indices, mut vertices) = (vec![], vec![]); - indices.push(0); - indices.push(1); - indices.push(2); - indices.push(2); - indices.push(3); - indices.push(1); - - let color = ColorF::new(0.0, 0.0, 0.0, 0.0); - - let x0 = mask.rect.origin.x; - let y0 = mask.rect.origin.y; - let x1 = x0 + mask.rect.size.width; - let y1 = y0 + mask.rect.size.height; - - vertices.extend_from_slice(&[ - PackedVertex::from_components( - x0, y0, - &color, - 0.0, 0.0, - 0.0, 0.0), - PackedVertex::from_components( - x1, y0, - &color, - 1.0, 0.0, - 1.0, 0.0), - PackedVertex::from_components( - x0, y1, - &color, - 0.0, 1.0, - 0.0, 1.0), - PackedVertex::from_components( - x1, y1, - &color, - 1.0, 1.0, - 1.0, 1.0), - ]); - - let wvp = projection.mul(&mask.transform); - self.device.bind_program(self.mask_program_id, &wvp); - - draw_simple_triangles(&mut self.simple_triangles_vao, - &mut self.device, - &mut self.profile_counters, - &indices[..], - &vertices[..], - TextureId(0)); - - valid_mask_count += 1; - } - - // If any masks were found, enable stencil test rejection. - // TODO(gw): This may be faster to switch the logic and - // rely on sfail! - if valid_mask_count > 0 { - gl::stencil_op(gl::KEEP, gl::KEEP, gl::KEEP); - gl::stencil_func(gl::EQUAL, valid_mask_count, 0xff); - gl::color_mask(true, true, true, true); - gl::depth_mask(true); - self.device.bind_program(self.quad_program_id, - &projection); - } + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); - // If the scissor rect was updated, scissor. - if scissor_rect != layer_viewport { - set_scissor_or_viewport(&scissor_rect, - render_context, - layer.texture_id, - gl::scissor) + gl::delete_buffers(&ubos); } + } + &PrimitiveBatchData::Image(ref ubo_data) => { + let shader = match batch.transform_kind { + TransformedRectKind::AxisAligned => self.ps_image, + TransformedRectKind::Complex => self.ps_image_transform, + }; + self.device.bind_program(shader, &projection); + self.device.bind_vao(self.quad_vao_id); + self.device.bind_color_texture(batch.color_texture_id); - for draw_call in ®ion.draw_calls { - let vao_id = self.get_or_create_similar_vao_with_offset( - draw_call.vertex_buffer_id, - VertexFormat::Rectangles, - draw_call.first_instance); - self.device.bind_vao(vao_id); - - if !draw_call.tile_params.is_empty() { - // TODO(gw): Avoid alloc here... - let mut floats = Vec::new(); - for vec in &draw_call.tile_params { - floats.push(vec.u0); - floats.push(vec.v0); - floats.push(vec.u_size); - floats.push(vec.v_size); - } - - self.device.set_uniform_vec4_array(self.u_tile_params, - &floats); - } - - if !draw_call.clip_rects.is_empty() { - // TODO(gw): Avoid alloc here... - let mut floats = Vec::new(); - for rect in &draw_call.clip_rects { - floats.push(rect.origin.x); - floats.push(rect.origin.y); - floats.push(rect.origin.x + rect.size.width); - floats.push(rect.origin.y + rect.size.height); - } - - self.device.set_uniform_vec4_array(self.u_clip_rects, - &floats); - } + for chunk in ubo_data.chunks(self.max_prim_images) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; - self.device.bind_mask_texture(draw_call.mask_texture_id); - self.device.bind_color_texture(draw_call.color_texture_id); - - // TODO(gw): Although a minor cost, this is an extra hashtable lookup for every - // draw call, when the batch textures are (almost) always the same. - // This could probably be cached or provided elsewhere. - let color_size = self.device - .get_texture_dimensions(draw_call.color_texture_id); - let mask_size = self.device - .get_texture_dimensions(draw_call.mask_texture_id); - self.device.set_uniform_4f(self.u_atlas_params, - color_size.0 as f32, - color_size.1 as f32, - mask_size.0 as f32, - mask_size.1 as f32); + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); self.profile_counters.draw_calls.inc(); - self.device - .draw_triangles_instanced_u16(0, 6, draw_call.instance_count as i32); + gl::delete_buffers(&ubos); } + } + &PrimitiveBatchData::Borders(ref ubo_data) => { + self.device.bind_program(self.ps_border, &projection); + self.device.bind_vao(self.quad_vao_id); - // Disable stencil test if it was used - if valid_mask_count > 0 { - gl::disable(gl::STENCIL_TEST); - } + for chunk in ubo_data.chunks(self.max_prim_borders) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; + + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); + + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); - // Reset scissor if it was used. - if scissor_rect != layer_viewport { - set_scissor_or_viewport(&layer_viewport, - render_context, - layer.texture_id, - gl::scissor); + gl::delete_buffers(&ubos); } } - } - &DrawCommand::CompositeBatch(ref info) => { - let mut any_jobs_were_visible = false; - for job in &info.jobs { - let ChildLayerIndex(child_layer_index) = job.child_layer_index; - let src_target = &layer.child_layers[child_layer_index as usize]; - if layer_viewports.contains_key(&src_target.id) { - any_jobs_were_visible = true; - break + &PrimitiveBatchData::BoxShadows(ref ubo_data) => { + self.device.bind_program(self.ps_box_shadow, &projection); + self.device.bind_vao(self.quad_vao_id); + + for chunk in ubo_data.chunks(self.max_prim_box_shadows) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; + + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); + + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); + + gl::delete_buffers(&ubos); } } - if !any_jobs_were_visible { - continue; - } + &PrimitiveBatchData::Text(ref ubo_data) => { + self.device.bind_program(self.ps_text, &projection); + self.device.bind_vao(self.quad_vao_id); + self.device.bind_color_texture(batch.color_texture_id); - let needs_fb = info.operation.needs_framebuffer(); - - let alpha; - if needs_fb { - match info.operation { - CompositionOp::MixBlend(blend_mode) => { - gl::disable(gl::BLEND); - self.device.bind_program(render_context.blend_program_id, - &projection); - self.device.set_uniform_4f(self.u_blend_params, - blend_mode as i32 as f32, - 0.0, - 0.0, - 0.0); - } - _ => unreachable!(), - } - self.device.bind_mask_texture(self.temporary_fb_texture); - alpha = 1.0; - } else { - gl::enable(gl::BLEND); - - let program; - let mut filter_params = None; - match info.operation { - CompositionOp::Filter(LowLevelFilterOp::Brightness( - amount)) => { - gl::blend_func(gl::CONSTANT_COLOR, gl::ZERO); - gl::blend_equation(gl::FUNC_ADD); - gl::blend_color(amount.to_f32_px(), - amount.to_f32_px(), - amount.to_f32_px(), - 1.0); - alpha = 1.0; - program = self.blit_program_id; - } - CompositionOp::Filter(LowLevelFilterOp::Opacity(amount)) => { - gl::blend_func_separate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA, - gl::ONE, gl::ONE); - gl::blend_equation(gl::FUNC_ADD); - alpha = amount.to_f32_px(); - program = self.blit_program_id; - } - CompositionOp::Filter(filter_op) => { - alpha = 1.0; - program = render_context.filter_program_id; - - let (opcode, amount, param0, param1) = match filter_op { - LowLevelFilterOp::Blur(radius, - AxisDirection::Horizontal) => { - gl::blend_func_separate(gl::SRC_ALPHA, - gl::ONE_MINUS_SRC_ALPHA, - gl::ONE, - gl::ONE); - (0.0, - radius.to_f32_px() * self.device_pixel_ratio, - 1.0, - 0.0) - } - LowLevelFilterOp::Blur(radius, - AxisDirection::Vertical) => { - gl::blend_func_separate(gl::SRC_ALPHA, - gl::ONE_MINUS_SRC_ALPHA, - gl::ONE, - gl::ONE); - (0.0, - radius.to_f32_px() * self.device_pixel_ratio, - 0.0, - 1.0) - } - LowLevelFilterOp::Contrast(amount) => { - gl::disable(gl::BLEND); - (1.0, amount.to_f32_px(), 0.0, 0.0) - } - LowLevelFilterOp::Grayscale(amount) => { - gl::disable(gl::BLEND); - (2.0, amount.to_f32_px(), 0.0, 0.0) - } - LowLevelFilterOp::HueRotate(angle) => { - gl::disable(gl::BLEND); - (3.0, - (angle as f32) / ANGLE_FLOAT_TO_FIXED, - 0.0, - 0.0) - } - LowLevelFilterOp::Invert(amount) => { - gl::disable(gl::BLEND); - (4.0, amount.to_f32_px(), 0.0, 0.0) - } - LowLevelFilterOp::Saturate(amount) => { - gl::disable(gl::BLEND); - (5.0, amount.to_f32_px(), 0.0, 0.0) - } - LowLevelFilterOp::Sepia(amount) => { - gl::disable(gl::BLEND); - (6.0, amount.to_f32_px(), 0.0, 0.0) - } - LowLevelFilterOp::Brightness(_) | - LowLevelFilterOp::Opacity(_) => { - // Expressible using GL blend modes, so not handled - // here. - unreachable!() - } - }; - - filter_params = Some((opcode, amount, param0, param1)); - } - CompositionOp::MixBlend(MixBlendMode::Multiply) => { - gl::blend_func(gl::DST_COLOR, gl::ZERO); - gl::blend_equation(gl::FUNC_ADD); - program = self.blit_program_id; - alpha = 1.0; - } - CompositionOp::MixBlend(MixBlendMode::Darken) => { - gl::blend_func(gl::ONE, gl::ONE); - gl::blend_equation(gl::MIN); - program = self.blit_program_id; - alpha = 1.0; - } - CompositionOp::MixBlend(MixBlendMode::Lighten) => { - gl::blend_func(gl::ONE, gl::ONE); - gl::blend_equation(gl::MAX); - program = self.blit_program_id; - alpha = 1.0; - } - _ => unreachable!(), - } + for chunk in ubo_data.chunks(self.max_prim_texts) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; + + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); - self.device.bind_program(program, &projection); + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); - if let Some(ref filter_params) = filter_params { - self.device.set_uniform_4f(self.u_filter_params, - filter_params.0, - filter_params.1, - filter_params.2, - filter_params.3); + gl::delete_buffers(&ubos); } } + &PrimitiveBatchData::Gradient(ref ubo_data) => { + self.device.bind_program(self.ps_gradient, &projection); + self.device.bind_vao(self.quad_vao_id); - let (mut indices, mut vertices) = (vec![], vec![]); - for job in &info.jobs { - let ChildLayerIndex(child_layer_index) = job.child_layer_index; - let src_target = &layer.child_layers[child_layer_index as usize]; - if !layer_viewports.contains_key(&src_target.id) { - continue - } + for chunk in ubo_data.chunks(self.max_prim_gradients) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; - let p0 = Point2D::new(job.rect.origin.x as f32, job.rect.origin.y as f32); - let p1 = Point2D::new(job.rect.max_x() as f32, job.rect.max_y() as f32); - - // TODO(glennw): No need to re-init this FB working copy texture - // every time... - if needs_fb { - let fb_rect_size = Size2D::new(job.rect.size.width as f32 * render_context.device_pixel_ratio, - job.rect.size.height as f32 * render_context.device_pixel_ratio); - - let inverted_y0 = layer.size.height - - job.rect.size.height as f32 - - p0.y; - let fb_rect_origin = Point2D::new( - p0.x * render_context.device_pixel_ratio, - inverted_y0 * render_context.device_pixel_ratio); - - self.device.init_texture_if_necessary(self.temporary_fb_texture, - fb_rect_size.width as u32, - fb_rect_size.height as u32, - ImageFormat::RGBA8, - TextureFilter::Nearest, - RenderTargetMode::None); - self.device.read_framebuffer_rect( - self.temporary_fb_texture, - 0, - 0, - fb_rect_origin.x as i32, - fb_rect_origin.y as i32, - fb_rect_size.width as i32, - fb_rect_size.height as i32); - } + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); + + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); - let vertex_count = vertices.len() as u16; - indices.push(vertex_count + 0); - indices.push(vertex_count + 1); - indices.push(vertex_count + 2); - indices.push(vertex_count + 2); - indices.push(vertex_count + 3); - indices.push(vertex_count + 1); - - let color = ColorF::new(1.0, 1.0, 1.0, alpha); - - debug_assert!(src_target.texture_id.unwrap() == info.texture_id); - - let pixel_uv = Rect::new( - Point2D::new(src_target.origin.x as u32, - src_target.origin.y as u32), - Size2D::new(src_target.size.width as u32, - src_target.size.height as u32)); - - let (texture_width, texture_height) = self.device.get_texture_dimensions(info.texture_id); - let texture_width = texture_width as f32 / self.device_pixel_ratio; - let texture_height = texture_height as f32 / self.device_pixel_ratio; - let texture_uv = Rect::new( - Point2D::new( - pixel_uv.origin.x as f32 / texture_width, - pixel_uv.origin.y as f32 / texture_height), - Size2D::new(pixel_uv.size.width as f32 / texture_width, - pixel_uv.size.height as f32 / texture_height)); - - let tl = job.world_transform.transform_point(&p0); - let tr = job.world_transform - .transform_point(&Point2D::new(p1.x, p0.y)); - let br = job.world_transform.transform_point(&p1); - let bl = job.world_transform - .transform_point(&Point2D::new(p0.x, p1.y)); - - if needs_fb { - vertices.extend_from_slice(&[ - PackedVertex::from_components( - tl.x, tl.y, - &color, - texture_uv.origin.x, texture_uv.max_y(), - 0.0, 1.0), - PackedVertex::from_components( - tr.x, tr.y, - &color, - texture_uv.max_x(), texture_uv.max_y(), - 1.0, 1.0), - PackedVertex::from_components( - bl.x, bl.y, - &color, - texture_uv.origin.x, texture_uv.origin.y, - 0.0, 0.0), - PackedVertex::from_components( - br.x, br.y, - &color, - texture_uv.max_x(), texture_uv.origin.y, - 1.0, 0.0), - ]); - } else { - vertices.extend_from_slice(&[ - PackedVertex::from_components_unscaled_muv( - tl.x, tl.y, - &color, - texture_uv.origin.x, texture_uv.max_y(), - texture_width as u16, texture_height as u16), - PackedVertex::from_components_unscaled_muv( - tr.x, tr.y, - &color, - texture_uv.max_x(), texture_uv.max_y(), - texture_width as u16, texture_height as u16), - PackedVertex::from_components_unscaled_muv( - bl.x, bl.y, - &color, - texture_uv.origin.x, texture_uv.origin.y, - texture_width as u16, texture_height as u16), - PackedVertex::from_components_unscaled_muv( - br.x, br.y, - &color, - texture_uv.max_x(), texture_uv.origin.y, - texture_width as u16, texture_height as u16), - ]); + gl::delete_buffers(&ubos); } } - - draw_simple_triangles(&mut self.simple_triangles_vao, - &mut self.device, - &mut self.profile_counters, - &indices[..], - &vertices[..], - info.texture_id); } } + + gl::disable(gl::BLEND); + gl::delete_buffers(&misc_ubos); } - fn set_scissor_or_viewport(rect: &Rect, - render_context: &RenderContext, - layer_texture_id: Option, - function: fn(gl::GLint, gl::GLint, gl::GLint, gl::GLint)) { - let y = match layer_texture_id { - Some(_) => rect.origin.y, - None => { - render_context.framebuffer_size.height as gl::GLint - rect.size.height - - rect.origin.y + for (key, tiles) in &target.composite_batches { + let shader = self.composite_shaders[key.shader as usize]; + self.device.bind_program(shader, &projection); + + for batch in tiles.chunks(self.max_composite_tiles) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; + + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &batch, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_COMPOSITE_TILES, ubo); + + self.device.draw_indexed_triangles_instanced_u16(6, batch.len() as i32); + self.profile_counters.vertices.add(6 * batch.len()); + self.profile_counters.draw_calls.inc(); + + gl::delete_buffers(&ubos); + } + } + } + + fn draw_tile_frame(&mut self, + frame: &Frame, + framebuffer_size: &Size2D) { + //println!("render {} debug rects", frame.debug_rects.len()); + self.gpu_profile_paint.begin(); + self.gpu_profile_paint.end(); + self.gpu_profile_composite.begin(); + + for debug_rect in frame.debug_rects.iter().rev() { + self.add_debug_rect(debug_rect.rect.origin, + debug_rect.rect.bottom_right(), + &debug_rect.label, + &debug_rect.color); + } + + gl::depth_mask(false); + gl::disable(gl::STENCIL_TEST); + gl::disable(gl::BLEND); + + let projection = Matrix4D::ortho(0.0, + framebuffer_size.width as f32, + framebuffer_size.height as f32, + 0.0, + ORTHO_NEAR_PLANE, + ORTHO_FAR_PLANE); + + if frame.phases.is_empty() { + gl::clear_color(0.3, 0.3, 0.3, 1.0); + gl::clear(gl::COLOR_BUFFER_BIT); + } else { + if self.render_targets[0] == TextureId(0) { + self.render_targets[0] = self.device.create_texture_ids(1)[0]; + self.render_targets[1] = self.device.create_texture_ids(1)[0]; + + self.device.init_texture(self.render_targets[0], + frame.cache_size.width as u32, + frame.cache_size.height as u32, + ImageFormat::RGBA8, + TextureFilter::Linear, + RenderTargetMode::RenderTarget, + None); + + self.device.init_texture(self.render_targets[1], + frame.cache_size.width as u32, + frame.cache_size.height as u32, + ImageFormat::RGBA8, + TextureFilter::Linear, + RenderTargetMode::RenderTarget, + None); + } + + for (phase_index, phase) in frame.phases.iter().enumerate() { + let mut render_target_index = 0; + + for target in &phase.targets { + if target.is_framebuffer { + let ct_index = self.render_targets[1 - render_target_index]; + self.draw_target(None, + target, + &Size2D::new(framebuffer_size.width as f32, framebuffer_size.height as f32), + ct_index, + phase_index == 0); + } else { + let rt_index = self.render_targets[render_target_index]; + let ct_index = self.render_targets[1 - render_target_index]; + self.draw_target(Some(rt_index), + target, + &frame.cache_size, + ct_index, + true); + render_target_index = 1 - render_target_index; + } } - }; - function(rect.origin.x, y, rect.size.width, rect.size.height) + } } - fn to_point4d(point: &Point2D) -> Point4D { - Point4D::new(point.x, point.y, 0.0, 1.0) + // Clear tiles with no items + if !frame.clear_tiles.is_empty() { + self.device.bind_program(self.tile_clear_shader, &projection); + self.device.bind_vao(self.quad_vao_id); + + for chunk in frame.clear_tiles.chunks(self.max_clear_tiles) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; + + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CLEAR_TILES, ubo); + + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); + + gl::delete_buffers(&ubos); + } } + + self.gpu_profile_composite.end(); } fn draw_frame(&mut self, framebuffer_size: Size2D) { if let Some(frame) = self.current_frame.take() { // TODO: cache render targets! - let render_context = RenderContext { - blend_program_id: self.blend_program_id, - filter_program_id: self.filter_program_id, - device_pixel_ratio: self.device_pixel_ratio, - framebuffer_size: framebuffer_size, - }; - - let mut layer_viewports = HashMap::new(); - let framebuffer_size = &render_context.framebuffer_size; - let framebuffer_rect = Rect::new(Point2D::zero(), - Size2D::new(framebuffer_size.width as f32, - framebuffer_size.height as f32)); - self.calculate_layer_viewports(&frame.root_layer, - &render_context, - &framebuffer_rect, - &mut layer_viewports); - // TODO(gw): Doesn't work well with transforms. // Look into this... gl::disable(gl::DEPTH_TEST); - gl::depth_func(gl::LEQUAL); - gl::enable(gl::SCISSOR_TEST); + gl::disable(gl::SCISSOR_TEST); + gl::disable(gl::BLEND); - self.draw_layer(&frame.root_layer, &render_context, &layer_viewports); + if let Some(ref frame) = frame.frame { + self.draw_tile_frame(frame, &framebuffer_size); + } // Restore frame - avoid borrow checker! self.current_frame = Some(frame); } } - - fn get_or_create_similar_vao_with_offset(&mut self, - source_vertex_buffer_id: VertexBufferId, - format: VertexFormat, - offset: u32) - -> VAOId { - let source_vertex_buffers_and_offsets = - self.vertex_buffers.get_mut(&source_vertex_buffer_id) - .expect("Didn't find source vertex buffer ID in \ - `get_or_create_similar_vao_with_offset()`!"); - if let Some(vertex_buffer_and_offset) = - source_vertex_buffers_and_offsets.iter().find(|vertex_buffer| { - vertex_buffer.offset == offset - }) { - return vertex_buffer_and_offset.buffer.vao_id - } - - let vao = - self.device.create_similar_vao(format, - source_vertex_buffers_and_offsets[0].buffer.vao_id, - offset); - source_vertex_buffers_and_offsets.push(VertexBufferAndOffset { - buffer: VertexBuffer { - vao_id: vao, - }, - offset: offset, - }); - vao - } } #[derive(Clone, Debug)] @@ -1884,35 +1586,5 @@ pub struct RendererOptions { pub enable_aa: bool, pub enable_msaa: bool, pub enable_profiler: bool, + pub debug: bool, } - -fn draw_simple_triangles(simple_triangles_vao: &mut Option, - device: &mut Device, - profile_counters: &mut RendererProfileCounters, - indices: &[u16], - vertices: &[PackedVertex], - texture: TextureId) { - let vao_id = match *simple_triangles_vao { - Some(ref mut vao_id) => *vao_id, - None => { - let vao_id = device.create_vao(VertexFormat::Triangles, None); - *simple_triangles_vao = Some(vao_id); - vao_id - } - }; - device.bind_color_texture(texture); - device.bind_vao(vao_id); - device.update_vao_indices(vao_id, &indices[..], VertexUsageHint::Dynamic); - device.update_vao_main_vertices(vao_id, &vertices[..], VertexUsageHint::Dynamic); - - profile_counters.vertices.add(indices.len()); - profile_counters.draw_calls.inc(); - - device.draw_triangles_u16(0, indices.len() as gl::GLint); -} - -struct VertexBufferAndOffset { - buffer: VertexBuffer, - offset: u32, -} - diff --git a/src/resource_cache.rs b/src/resource_cache.rs index 4c5f16c618..4187a04669 100644 --- a/src/resource_cache.rs +++ b/src/resource_cache.rs @@ -130,15 +130,13 @@ pub struct ResourceCache { pending_raster_jobs: Vec, - white_image_id: TextureCacheItemId, - dummy_mask_image_id: TextureCacheItemId, + //white_image_id: TextureCacheItemId, } impl ResourceCache { pub fn new(thread_pool: &mut scoped_threadpool::Pool, texture_cache: TextureCache, - white_image_id: TextureCacheItemId, - dummy_mask_image_id: TextureCacheItemId, + _white_image_id: TextureCacheItemId, device_pixel_ratio: f32, enable_aa: bool) -> ResourceCache { @@ -167,8 +165,6 @@ impl ResourceCache { texture_cache: texture_cache, pending_raster_jobs: Vec::new(), device_pixel_ratio: device_pixel_ratio, - white_image_id: white_image_id, - dummy_mask_image_id: dummy_mask_image_id, enable_aa: enable_aa, } } @@ -307,10 +303,10 @@ impl ResourceCache { } pub fn raster_pending_glyphs(&mut self, - thread_pool: &mut scoped_threadpool::Pool, + //thread_pool: &mut scoped_threadpool::Pool, frame_id: FrameId) { // Run raster jobs in parallel - run_raster_jobs(thread_pool, + run_raster_jobs(//thread_pool, &mut self.pending_raster_jobs, &self.font_templates, self.device_pixel_ratio, @@ -366,44 +362,14 @@ impl ResourceCache { self.draw_lists.get(draw_list_id) } - pub fn get_draw_list_mut(&mut self, draw_list_id: DrawListId) -> &mut DrawList { - self.draw_lists.get_mut(draw_list_id) - } - pub fn remove_draw_list(&mut self, draw_list_id: DrawListId) { self.draw_lists.free(draw_list_id); } - pub fn allocate_render_target(&mut self, - width: u32, - height: u32, - format: ImageFormat, - frame_id: FrameId) - -> TextureId { - self.texture_cache.allocate_render_target(width, - height, - format, - frame_id) - } - - pub fn free_old_render_targets(&mut self) { - self.texture_cache.free_old_render_targets() - } - pub fn pending_updates(&mut self) -> TextureUpdateList { self.texture_cache.pending_updates() } - #[inline] - pub fn get_dummy_mask_image(&self) -> &TextureCacheItem { - self.texture_cache.get(self.dummy_mask_image_id) - } - - #[inline] - pub fn get_dummy_color_image(&self) -> &TextureCacheItem { - self.texture_cache.get(self.white_image_id) - } - #[inline] pub fn get_glyph(&self, glyph_key: &GlyphKey, frame_id: FrameId) -> Option<&TextureCacheItem> { let image_id = self.cached_glyphs.get(glyph_key, frame_id); @@ -420,20 +386,20 @@ impl ResourceCache { self.texture_cache.get(image_info.texture_cache_id) } +/* #[inline] pub fn get_raster(&self, raster_item: &RasterItem, frame_id: FrameId) -> &TextureCacheItem { let image_id = self.cached_rasters.get(raster_item, frame_id); self.texture_cache.get(*image_id) } +*/ +/* #[inline] pub fn get_webgl_texture(&self, context_id: &WebGLContextId) -> TextureId { self.webgl_textures.get(context_id).unwrap().clone() } - - pub fn device_pixel_ratio(&self) -> f32 { - self.device_pixel_ratio - } +*/ pub fn expire_old_resources(&mut self, frame_id: FrameId) { self.cached_glyphs.expire_old_resources(&mut self.texture_cache, frame_id); @@ -442,7 +408,7 @@ impl ResourceCache { } } -fn run_raster_jobs(thread_pool: &mut scoped_threadpool::Pool, +fn run_raster_jobs(//thread_pool: &mut scoped_threadpool::Pool, pending_raster_jobs: &mut Vec, font_templates: &HashMap>, device_pixel_ratio: f32, @@ -452,9 +418,9 @@ fn run_raster_jobs(thread_pool: &mut scoped_threadpool::Pool, } // Run raster jobs in parallel - thread_pool.scoped(|scope| { + //thread_pool.scoped(|scope| { for job in pending_raster_jobs { - scope.execute(|| { + //scope.execute(|| { let font_template = &font_templates[&job.glyph_key.font_key]; FONT_CONTEXT.with(move |font_context| { let mut font_context = font_context.borrow_mut(); @@ -473,9 +439,9 @@ fn run_raster_jobs(thread_pool: &mut scoped_threadpool::Pool, device_pixel_ratio, enable_aa); }); - }); + //}); } - }); + //}); } pub trait Resource { diff --git a/src/resource_list.rs b/src/resource_list.rs index 7015c4d658..223783ea4e 100644 --- a/src/resource_list.rs +++ b/src/resource_list.rs @@ -2,20 +2,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use aabbtree::AABBTreeNode; use app_units::Au; -use batch_builder; -use euclid::{Rect, Size2D}; +use euclid::Rect; use fnv::FnvHasher; -use internal_types::{BorderRadiusRasterOp, BoxShadowRasterOp, DrawListItemIndex}; -use internal_types::{Glyph, GlyphKey, RasterItem, DevicePixel}; -use resource_cache::ResourceCache; +use internal_types::{Glyph, GlyphKey, RasterItem, BoxShadowRasterOp}; use std::collections::{HashMap, HashSet}; use std::hash::BuildHasherDefault; -use tessellator; -use webrender_traits::{AuxiliaryLists, BorderRadius, BorderStyle, BoxShadowClipMode}; -use webrender_traits::{FontKey, ImageFormat, ImageKey, ImageRendering, PipelineId}; -use webrender_traits::{SpecificDisplayItem}; +use webrender_traits::{FontKey, ImageKey, ImageRendering}; type RequiredImageSet = HashSet<(ImageKey, ImageRendering), BuildHasherDefault>; type RequiredGlyphMap = HashMap, BuildHasherDefault>; @@ -50,36 +43,6 @@ impl ResourceList { .insert(glyph); } - pub fn add_radius_raster(&mut self, - outer_radius: &Size2D, - inner_radius: &Size2D, - inverted: bool, - index: Option, - image_format: ImageFormat) { - let outer_radius_x = DevicePixel::new(outer_radius.width, self.device_pixel_ratio); - let outer_radius_y = DevicePixel::new(outer_radius.height, self.device_pixel_ratio); - let inner_radius_x = DevicePixel::new(inner_radius.width, self.device_pixel_ratio); - let inner_radius_y = DevicePixel::new(inner_radius.height, self.device_pixel_ratio); - if let Some(raster_item) = BorderRadiusRasterOp::create(outer_radius_x, - outer_radius_y, - inner_radius_x, - inner_radius_y, - inverted, - index, - image_format) { - self.required_rasters.insert(RasterItem::BorderRadius(raster_item)); - } - } - - /// NB: Only adds non-tessellated border radii. - pub fn add_radius_raster_for_border_radii(&mut self, radii: &BorderRadius) { - let zero_size = Size2D::new(0.0, 0.0); - self.add_radius_raster(&radii.top_left, &zero_size, false, None, ImageFormat::A8); - self.add_radius_raster(&radii.top_right, &zero_size, false, None, ImageFormat::A8); - self.add_radius_raster(&radii.bottom_left, &zero_size, false, None, ImageFormat::A8); - self.add_radius_raster(&radii.bottom_right, &zero_size, false, None, ImageFormat::A8); - } - pub fn add_box_shadow_corner(&mut self, blur_radius: f32, border_radius: f32, @@ -134,225 +97,3 @@ impl ResourceList { } } } - -pub trait BuildRequiredResources { - fn build_resource_list(&mut self, - resource_cache: &ResourceCache, - pipeline_auxiliary_lists: &HashMap>); -} - -impl BuildRequiredResources for AABBTreeNode { - fn build_resource_list(&mut self, - resource_cache: &ResourceCache, - pipeline_auxiliary_lists: &HashMap>) { - //let _pf = util::ProfileScope::new(" build_resource_list"); - let mut resource_list = ResourceList::new(resource_cache.device_pixel_ratio()); - - 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]; - let auxiliary_lists = - pipeline_auxiliary_lists.get(&draw_list.pipeline_id) - .expect("No auxiliary lists for pipeline?!"); - - // Handle border radius for complex clipping regions. - for complex_clip_region in - auxiliary_lists.complex_clip_regions(&display_item.clip.complex) { - 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); - } - SpecificDisplayItem::Text(ref info) => { - let glyphs = auxiliary_lists.glyph_instances(&info.glyphs); - for glyph in 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, - info.clip_mode); - 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 { - 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) => { - let can_tessellate = tessellator::can_tessellate_border(info); - add_border_radius_raster(&info.radius.top_left, - &info.top_left_inner_radius(), - can_tessellate, - resource_cache, - &mut resource_list); - add_border_radius_raster(&info.radius.top_right, - &info.top_right_inner_radius(), - can_tessellate, - resource_cache, - &mut resource_list); - add_border_radius_raster(&info.radius.bottom_right, - &info.bottom_right_inner_radius(), - can_tessellate, - resource_cache, - &mut resource_list); - add_border_radius_raster(&info.radius.bottom_left, - &info.bottom_left_inner_radius(), - can_tessellate, - resource_cache, - &mut resource_list); - - 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, - None, - 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, - None, - 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, - None, - 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, - None, - ImageFormat::RGBA8); - } - - if info.top.style == BorderStyle::Double { - resource_list.add_radius_raster(&info.radius.top_left, - &Size2D::zero(), - false, - None, - ImageFormat::A8); - - resource_list.add_radius_raster(&Size2D::zero(), - &info.top_left_inner_radius(), - false, - None, - ImageFormat::A8); - } - if info.right.style == BorderStyle::Double { - resource_list.add_radius_raster(&info.radius.top_right, - &Size2D::zero(), - false, - None, - ImageFormat::A8); - - resource_list.add_radius_raster(&Size2D::zero(), - &info.top_right_inner_radius(), - false, - None, - ImageFormat::A8); - } - if info.bottom.style == BorderStyle::Double { - resource_list.add_radius_raster(&info.radius.bottom_left, - &Size2D::zero(), - false, - None, - ImageFormat::A8); - - resource_list.add_radius_raster(&Size2D::zero(), - &info.bottom_left_inner_radius(), - false, - None, - ImageFormat::A8); - } - if info.left.style == BorderStyle::Double { - resource_list.add_radius_raster(&info.radius.bottom_right, - &Size2D::zero(), - false, - None, - ImageFormat::A8); - - resource_list.add_radius_raster(&Size2D::zero(), - &info.bottom_right_inner_radius(), - false, - None, - ImageFormat::A8); - } - - - } - } - } - } - } - - self.resource_list = Some(resource_list); - } -} - -fn add_border_radius_raster(outer_radius: &Size2D, - inner_radius: &Size2D, - can_tessellate: bool, - resource_cache: &ResourceCache, - resource_list: &mut ResourceList) { - let quad_count = if can_tessellate { - tessellator::quad_count_for_border_corner(outer_radius, - resource_cache.device_pixel_ratio()) - } else { - 1 - }; - for rect_index in 0..quad_count { - let index = if can_tessellate { - Some(rect_index) - } else { - None - }; - resource_list.add_radius_raster(outer_radius, - inner_radius, - false, - index, - ImageFormat::A8); - } -} - diff --git a/src/spring.rs b/src/spring.rs index 1fcbdfec4b..b8e333e05d 100644 --- a/src/spring.rs +++ b/src/spring.rs @@ -101,5 +101,3 @@ fn next(cur: f32, prev: f32, dest: f32, stiffness: f32, damping: f32) -> f32 { fn is_resting(cur: f32, prev: f32, dest: f32) -> bool { (cur - prev).abs() < EPSILON && (cur - dest).abs() < EPSILON } - - diff --git a/src/tessellator.rs b/src/tessellator.rs deleted file mode 100644 index 47824779db..0000000000 --- a/src/tessellator.rs +++ /dev/null @@ -1,113 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use euclid::{Point2D, Rect, Size2D}; -use internal_types::BasicRotationAngle; -use webrender_traits::BorderDisplayItem; - -pub fn quad_count_for_border_corner(outer_radius: &Size2D, - device_pixel_ratio: f32) -> u32 { - let max = 32.0 / device_pixel_ratio; - if outer_radius.width < max && outer_radius.height < max { - 1 - } else { - 4 - } -} - -pub trait BorderCornerTessellation { - fn tessellate_border_corner(&self, - outer_radius: &Size2D, - inner_radius: &Size2D, - device_pixel_ratio: f32, - rotation_angle: BasicRotationAngle, - index: u32) - -> Rect; -} - -impl BorderCornerTessellation for Rect { - fn tessellate_border_corner(&self, - outer_radius: &Size2D, - inner_radius: &Size2D, - device_pixel_ratio: f32, - rotation_angle: BasicRotationAngle, - index: u32) - -> Rect { - let quad_count = quad_count_for_border_corner(outer_radius, device_pixel_ratio); - if quad_count == 1 { - return *self - } - - /* - // FIXME(pcwalton): This is basically a hack to keep Acid2 working. We don't currently - // render border corners properly when the corner size is greater than zero but less than - // the radius, and we'll have to modify this when we do. - if self.size.width - outer_radius.width > EPSILON || - self.size.height - outer_radius.height > EPSILON { - return Rect::new(Point2D::new(self.origin.x + self.size.width / (quad_count as f32) * - (index as f32), - self.origin.y), - Size2D::new(self.size.width / (quad_count as f32), - self.size.height)) - }*/ - - let delta = outer_radius.width / (quad_count as f32); - let prev_x = (delta * (index as f32)).ceil(); - let prev_outer_y = ellipse_y_coordinate(prev_x, outer_radius); - - let next_x = (prev_x + delta).ceil(); - let next_inner_y = ellipse_y_coordinate(next_x, inner_radius); - - let top_left = Point2D::new(prev_x, prev_outer_y); - let bottom_right = Point2D::new(next_x, next_inner_y); - - let subrect = Rect::new(Point2D::new(top_left.x, bottom_right.y), - Size2D::new(bottom_right.x - top_left.x, - top_left.y - bottom_right.y)); - - let subrect = match rotation_angle { - BasicRotationAngle::Upright => { - Rect::new(Point2D::new(outer_radius.width - subrect.max_x(), - outer_radius.height - subrect.max_y()), - subrect.size) - } - BasicRotationAngle::Clockwise90 => { - Rect::new(Point2D::new(subrect.origin.x, - outer_radius.height - subrect.max_y()), - subrect.size) - } - BasicRotationAngle::Clockwise180 => { - subrect - } - BasicRotationAngle::Clockwise270 => { - Rect::new(Point2D::new(outer_radius.width - subrect.max_x(), - subrect.origin.y), - subrect.size) - } - }; - - subrect.translate(&self.origin) - } -} - -fn ellipse_y_coordinate(x: f32, radius: &Size2D) -> f32 { - if radius.width == 0.0 { - return x - } - let radicand = 1.0 - (x / radius.width) * (x / radius.width); - if radicand < 0.0 { - 0.0 - } else { - radius.height * radicand.sqrt() - } -} - -/// FIXME(pcwalton): For now, we don't tessellate multicolored border radii. -pub fn can_tessellate_border(border: &BorderDisplayItem) -> bool { - border.left.color == border.top.color && - border.top.color == border.right.color && - border.right.color == border.bottom.color && - border.bottom.color == border.left.color -} - diff --git a/src/texture_cache.rs b/src/texture_cache.rs index d8d5cc7494..e2bcc9031a 100644 --- a/src/texture_cache.rs +++ b/src/texture_cache.rs @@ -10,14 +10,13 @@ use frame::FrameId; use freelist::{FreeList, FreeListItem, FreeListItemId}; use internal_types::{TextureUpdate, TextureUpdateOp, TextureUpdateDetails}; use internal_types::{RasterItem, RenderTargetMode, TextureImage, TextureUpdateList}; -use internal_types::{RectUv, DevicePixel, BasicRotationAngle}; +use internal_types::{RectUv, DevicePixel}; use std::cmp::{self, Ordering}; use std::collections::HashMap; use std::collections::hash_map::Entry; use std::hash::BuildHasherDefault; use std::mem; use std::slice::Iter; -use tessellator::BorderCornerTessellation; use time; use util; use webrender_traits::ImageFormat; @@ -28,9 +27,6 @@ const MAX_BYTES_PER_TEXTURE: u32 = 1024 * 1024 * 256; // 256MB /// The number of RGBA pixels we're allowed to use for a texture. const MAX_RGBA_PIXELS_PER_TEXTURE: u32 = MAX_BYTES_PER_TEXTURE / 4; -/// The total number of RGBA pixels we're allowed to use for our render targets. -const MAX_RGBA_PIXELS_IN_CACHED_RENDER_TARGETS: u32 = 4096 * 4096 * 2; - /// The desired initial size of each texture, in pixels. const INITIAL_TEXTURE_SIZE: u32 = 1024; @@ -107,6 +103,12 @@ impl TexturePage { page } +/* + pub fn size(&self) -> u32 { + self.texture_size + } +*/ + pub fn texture_id(&self) -> TextureId { self.texture_id } @@ -317,7 +319,7 @@ impl TexturePage { self.dirty = changed } - fn clear(&mut self) { + pub fn clear(&mut self) { self.free_list = FreeRectList::new(); self.free_list.push(&Rect::new(Point2D::new(0, 0), Size2D::new(self.texture_size, self.texture_size))); @@ -460,6 +462,8 @@ pub struct TextureCacheItem { // bilinear filtering / texture bleeding purposes. pub allocated_rect: Rect, pub requested_rect: Rect, + + pub is_opaque: bool, } // Structure squat the width/height fields to maintain the free list information :) @@ -493,7 +497,8 @@ impl TextureCacheItem { user_x0: i32, user_y0: i32, allocated_rect: Rect, requested_rect: Rect, - texture_size: &Size2D) + texture_size: &Size2D, + is_opaque: bool) -> TextureCacheItem { TextureCacheItem { texture_id: texture_id, @@ -514,6 +519,7 @@ impl TextureCacheItem { }, allocated_rect: allocated_rect, requested_rect: requested_rect, + is_opaque: is_opaque, } } @@ -590,8 +596,6 @@ pub struct TextureCache { // Vec, // BuildHasherDefault>, items: FreeList, - cached_render_targets: Vec, - total_pixel_count_of_cached_render_targets: u32, arena: TextureCacheArena, pending_updates: TextureUpdateList, } @@ -614,9 +618,6 @@ impl TextureCache { free_texture_ids: free_texture_ids, free_texture_levels: HashMap::with_hasher(Default::default()), alternate_free_texture_levels: HashMap::with_hasher(Default::default()), - //render_target_free_texture_levels: HashMap::with_hasher(Default::default()), - cached_render_targets: vec![], - total_pixel_count_of_cached_render_targets: 0, items: FreeList::new(), pending_updates: TextureUpdateList::new(), arena: TextureCacheArena::new(), @@ -646,105 +647,11 @@ impl TextureCache { requested_rect: Rect::zero(), texture_size: Size2D::zero(), texture_id: TextureId::invalid(), + is_opaque: false, }; self.items.insert(new_item) } - /* - pub fn free(&mut self, - _texture_id: TextureId, - _uv: &Rect, - _kind: TextureCacheItemKind) { - panic!("can't free texture items yet!"); - } - */ - - pub fn allocate_render_target(&mut self, - width: u32, - height: u32, - format: ImageFormat, - frame_id: FrameId) - -> TextureId { - let mut cached_render_target_index = None; - for (i, cached_render_target) in self.cached_render_targets.iter().enumerate() { - if cached_render_target.width == width && - cached_render_target.height == height && - cached_render_target.format == format && - cached_render_target.frame_id != frame_id { - cached_render_target_index = Some(i); - break - } - } - if let Some(cached_render_target_index) = cached_render_target_index { - // Push to the end to mark as recently used. - let mut cached_render_target = self.cached_render_targets - .remove(cached_render_target_index); - cached_render_target.frame_id = frame_id; - self.cached_render_targets.push(cached_render_target); - return cached_render_target.texture_id - } - - self.total_pixel_count_of_cached_render_targets += width * height; - - let texture_id = self.free_texture_ids - .pop() - .expect("TODO: Handle running out of texture IDs!"); - let op = TextureUpdateOp::Create(width, - height, - format, - TextureFilter::Linear, - RenderTargetMode::RenderTarget, - None); - let update_op = TextureUpdate { - id: texture_id, - op: op, - }; - self.pending_updates.push(update_op); - - self.cached_render_targets.push(CachedRenderTarget { - texture_id: texture_id, - width: width, - height: height, - format: format, - frame_id: frame_id, - }); - - texture_id - } - - pub fn free_old_render_targets(&mut self) { - if self.total_pixel_count_of_cached_render_targets <= - MAX_RGBA_PIXELS_IN_CACHED_RENDER_TARGETS { - return - } - - let mut cached_render_targets_to_destroy = 0; - for cached_render_target in &self.cached_render_targets { - let op = TextureUpdateOp::Update(0, 0, 0, 0, - TextureUpdateDetails::Blit(Vec::new())); - let update_op = TextureUpdate { - id: cached_render_target.texture_id, - op: op, - }; - self.pending_updates.push(update_op); - self.free_texture_ids.push(cached_render_target.texture_id); - - cached_render_targets_to_destroy += 1; - - self.total_pixel_count_of_cached_render_targets -= cached_render_target.width * - cached_render_target.height; - if self.total_pixel_count_of_cached_render_targets < - MAX_RGBA_PIXELS_IN_CACHED_RENDER_TARGETS { - break - } - } - - self.cached_render_targets = self.cached_render_targets[cached_render_targets_to_destroy..] - .iter() - .cloned() - .collect() - } - pub fn allocate(&mut self, image_id: TextureCacheItemId, user_x0: i32, @@ -754,7 +661,8 @@ impl TextureCache { format: ImageFormat, kind: TextureCacheItemKind, border_type: BorderType, - filter: TextureFilter) + filter: TextureFilter, + is_opaque: bool) -> AllocationResult { let requested_size = Size2D::new(requested_width, requested_height); @@ -835,7 +743,8 @@ impl TextureCache { user_x0, user_y0, allocated_rect, requested_rect, - &Size2D::new(page.texture_size, page.texture_size)); + &Size2D::new(page.texture_size, page.texture_size), + is_opaque); *self.items.get_mut(image_id) = cache_item; return AllocationResult { @@ -900,55 +809,6 @@ impl TextureCache { item: &RasterItem, _device_pixel_ratio: f32) { let update_op = match item { - &RasterItem::BorderRadius(ref op) => { - let rect = Rect::new(Point2D::zero(), - Size2D::new(op.outer_radius_x.as_f32(), - op.outer_radius_y.as_f32())); - let tessellated_rect = match op.index { - Some(index) => { - rect.tessellate_border_corner( - &Size2D::new(op.outer_radius_x.as_f32(), - op.outer_radius_y.as_f32()), - &Size2D::new(op.inner_radius_x.as_f32(), - op.inner_radius_y.as_f32()), - 1.0, - BasicRotationAngle::Upright, - index) - } - None => rect, - }; - - let width = tessellated_rect.size.width.ceil() as u32; - let height = tessellated_rect.size.height.ceil() as u32; - - let allocation = self.allocate(image_id, - 0, - 0, - width, - height, - op.image_format, - TextureCacheItemKind::Standard, - BorderType::SinglePixel, - TextureFilter::Linear); - - assert!(allocation.kind == AllocationKind::TexturePage); // TODO: Handle large border radii not fitting in texture cache page - - TextureUpdate { - id: allocation.item.texture_id, - op: TextureUpdateOp::Update(allocation.item.requested_rect.origin.x, - allocation.item.requested_rect.origin.y, - width, - height, - TextureUpdateDetails::BorderRadius( - op.outer_radius_x, - op.outer_radius_y, - op.inner_radius_x, - op.inner_radius_y, - op.index, - op.inverted, - BorderType::SinglePixel)), - } - } &RasterItem::BoxShadow(ref op) => { let allocation = self.allocate(image_id, 0, @@ -958,7 +818,8 @@ impl TextureCache { ImageFormat::RGBA8, TextureCacheItemKind::Standard, BorderType::SinglePixel, - TextureFilter::Linear); + TextureFilter::Linear, + false); // TODO(pcwalton): Handle large box shadows not fitting in texture cache page. assert!(allocation.kind == AllocationKind::TexturePage); @@ -1033,6 +894,23 @@ impl TextureCache { insert_op: TextureInsertOp, border_type: BorderType) { + let is_opaque = match (&insert_op, format) { + (&TextureInsertOp::Blit(ref bytes), ImageFormat::RGBA8) => { + let mut is_opaque = true; + for i in (0..bytes.len()).step_by(4) { + if bytes[i + 3] != 255 { + is_opaque = false; + break; + } + } + is_opaque + } + (&TextureInsertOp::Blit(..), ImageFormat::RGB8) => true, + (&TextureInsertOp::Blit(..), ImageFormat::A8) => false, + (&TextureInsertOp::Blit(..), ImageFormat::Invalid) => unreachable!(), + (&TextureInsertOp::Blur(..), _) => false, + }; + let result = self.allocate(image_id, x0, y0, @@ -1041,7 +919,8 @@ impl TextureCache { format, TextureCacheItemKind::Standard, border_type, - filter); + filter, + is_opaque); let op = match (result.kind, insert_op) { (AllocationKind::TexturePage, TextureInsertOp::Blit(bytes)) => { @@ -1137,14 +1016,16 @@ impl TextureCache { ImageFormat::RGBA8, TextureCacheItemKind::Standard, BorderType::SinglePixel, - TextureFilter::Linear); + TextureFilter::Linear, + false); self.allocate(horizontal_blur_image_id, 0, 0, width, height, ImageFormat::RGBA8, TextureCacheItemKind::Alternate, BorderType::SinglePixel, - TextureFilter::Linear); + TextureFilter::Linear, + false); let unblurred_glyph_item = self.get(unblurred_glyph_image_id); let horizontal_blur_item = self.get(horizontal_blur_image_id); TextureUpdateOp::Update( diff --git a/src/tiling.rs b/src/tiling.rs new file mode 100644 index 0000000000..c3739af081 --- /dev/null +++ b/src/tiling.rs @@ -0,0 +1,2147 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use app_units::{Au}; +use batch_builder::{BorderSideHelpers, BoxShadowMetrics}; +use bsptree::BspTree; +use device::{TextureId, TextureFilter}; +use euclid::{Point2D, Rect, Matrix4D, Size2D, Point4D}; +use fnv::FnvHasher; +use frame::FrameId; +use internal_types::{AxisDirection, Glyph, GlyphKey, DevicePixel}; +use layer::Layer; +use renderer::{BLUR_INFLATION_FACTOR}; +use resource_cache::ResourceCache; +use resource_list::ResourceList; +use std::cmp; +use std::collections::{HashMap}; +use std::f32; +use std::mem; +use std::hash::{BuildHasherDefault}; +use texture_cache::{TexturePage, TextureCacheItem}; +use util::{self, rect_from_points, rect_from_points_f, MatrixHelpers, subtract_rect, RectHelpers, rect_contains_rect}; +use webrender_traits::{ColorF, FontKey, ImageKey, ImageRendering, ComplexClipRegion}; +use webrender_traits::{BorderDisplayItem, BorderStyle, ItemRange, AuxiliaryLists, BorderRadius}; +use webrender_traits::{BoxShadowClipMode, PipelineId, ScrollLayerId}; + +struct RenderTargetContext<'a> { + layers: &'a Vec, + resource_cache: &'a ResourceCache, + device_pixel_ratio: f32, + pipeline_auxiliary_lists: &'a HashMap>, + frame_id: FrameId, + alpha_batch_max_tiles: usize, + alpha_batch_max_layers: usize, +} + +pub struct AlphaBatchRenderTask { + pub batches: Vec, + pub layer_ubo: Vec, + pub tile_ubo: Vec, + screen_tile_layers: Vec, + layer_to_ubo_map: Vec>, +} + +impl AlphaBatchRenderTask { + fn new(ctx: &RenderTargetContext) -> AlphaBatchRenderTask { + let mut layer_to_ubo_map = Vec::new(); + for _ in 0..ctx.layers.len() { + layer_to_ubo_map.push(None); + } + + AlphaBatchRenderTask { + batches: Vec::new(), + layer_ubo: Vec::new(), + tile_ubo: Vec::new(), + screen_tile_layers: Vec::new(), + layer_to_ubo_map: layer_to_ubo_map, + } + } + + fn add_screen_tile_layer(&mut self, + target_rect: Rect, + screen_tile_layer: ScreenTileLayer, + ctx: &RenderTargetContext) -> Option { + if self.tile_ubo.len() == ctx.alpha_batch_max_tiles { + return Some(screen_tile_layer); + } + self.tile_ubo.push(PackedTile { + target_rect: target_rect, + actual_rect: screen_tile_layer.actual_rect, + }); + + let StackingContextIndex(si) = screen_tile_layer.layer_index; + match self.layer_to_ubo_map[si] { + Some(..) => {} + None => { + if self.layer_ubo.len() == ctx.alpha_batch_max_layers { + return Some(screen_tile_layer); + } + + let index = self.layer_ubo.len(); + let sc = &ctx.layers[si]; + self.layer_ubo.push(PackedLayer { + padding: [0, 0], + transform: sc.transform, + inv_transform: sc.transform.invert(), + screen_vertices: sc.xf_rect.as_ref().unwrap().vertices, + blend_info: [sc.opacity, 0.0], + }); + self.layer_to_ubo_map[si] = Some(index); + } + } + + self.screen_tile_layers.push(screen_tile_layer); + None + } + + fn build(&mut self, ctx: &RenderTargetContext) { + debug_assert!(self.layer_ubo.len() <= ctx.alpha_batch_max_layers); + debug_assert!(self.tile_ubo.len() <= ctx.alpha_batch_max_tiles); + + // Build batches + // TODO(gw): This batching code is fairly awful - rewrite it! + + loop { + // Pull next primitive + let mut batch = None; + + for (screen_tile_layer_index, screen_tile_layer) in self.screen_tile_layers + .iter_mut() + .enumerate() { + if let Some(next_prim_index) = screen_tile_layer.prim_indices.pop() { + let StackingContextIndex(si) = screen_tile_layer.layer_index; + let layer = &ctx.layers[si]; + let PrimitiveIndex(pi) = next_prim_index; + let prim = &layer.primitives[pi]; + let transform_kind = layer.xf_rect.as_ref().unwrap().kind; + let mut new_batch = PrimitiveBatch::new(prim, transform_kind); + let layer_index_in_ubo = self.layer_to_ubo_map[si].unwrap() as u32; + let tile_index_in_ubo = screen_tile_layer_index as u32; + let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id) + .expect("No auxiliary lists?!"); + let ok = prim.pack(&mut new_batch, + layer_index_in_ubo, + tile_index_in_ubo, + auxiliary_lists, + transform_kind, + ctx); + debug_assert!(ok); + batch = Some(new_batch); + break; + } + } + + match batch { + Some(mut batch) => { + for (screen_tile_layer_index, screen_tile_layer) in self.screen_tile_layers + .iter_mut() + .enumerate() { + loop { + match screen_tile_layer.prim_indices.pop() { + Some(next_prim_index) => { + let StackingContextIndex(si) = screen_tile_layer.layer_index; + let layer = &ctx.layers[si]; + let PrimitiveIndex(pi) = next_prim_index; + let next_prim = &layer.primitives[pi]; + let layer_index_in_ubo = self.layer_to_ubo_map[si].unwrap() as u32; + let tile_index_in_ubo = screen_tile_layer_index as u32; + let transform_kind = layer.xf_rect.as_ref().unwrap().kind; + let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id) + .expect("No auxiliary lists?!"); + if !next_prim.pack(&mut batch, + layer_index_in_ubo, + tile_index_in_ubo, + auxiliary_lists, + transform_kind, + ctx) { + screen_tile_layer.prim_indices.push(next_prim_index); + break; + } + } + None => { + break; + } + } + } + } + + self.batches.push(batch); + } + None => { + break; + } + } + } + } +} + +pub struct RenderTarget { + pub is_framebuffer: bool, + page_allocator: TexturePage, + tasks: Vec, + + pub alpha_batch_tasks: Vec, + pub composite_batches: HashMap, + BuildHasherDefault>, +} + +impl RenderTarget { + fn new(is_framebuffer: bool) -> RenderTarget { + RenderTarget { + is_framebuffer: is_framebuffer, + page_allocator: TexturePage::new(TextureId(0), RENDERABLE_CACHE_SIZE.0 as u32), + tasks: Vec::new(), + + alpha_batch_tasks: Vec::new(), + composite_batches: HashMap::with_hasher(Default::default()), + } + } + + fn add_render_task(&mut self, task: RenderTask) { + self.tasks.push(task); + } + + fn build(&mut self, ctx: &RenderTargetContext) { + // Step through each task, adding to batches as appropriate. + let mut alpha_batch_tasks = Vec::new(); + let mut current_alpha_batch_task = AlphaBatchRenderTask::new(ctx); + + for task in self.tasks.drain(..) { + let target_rect = task.get_target_rect(); + + match task.kind { + RenderTaskKind::AlphaBatch(screen_tile_layer) => { + match current_alpha_batch_task.add_screen_tile_layer(target_rect, + screen_tile_layer, + ctx) { + Some(screen_tile_layer) => { + let old_task = mem::replace(&mut current_alpha_batch_task, + AlphaBatchRenderTask::new(ctx)); + alpha_batch_tasks.push(old_task); + + let result = current_alpha_batch_task.add_screen_tile_layer(target_rect, + screen_tile_layer, + ctx); + debug_assert!(result.is_none()); + } + None => {} + } + } + RenderTaskKind::Composite(info) => { + let mut composite_tile = CompositeTile::new(&target_rect); + debug_assert!(info.layer_indices.len() == task.child_locations.len()); + for (i, (layer_index, location)) in info.layer_indices + .iter() + .zip(task.child_locations.iter()) + .enumerate() { + let opacity = layer_index.map_or(1.0, |layer_index| { + let StackingContextIndex(si) = layer_index; + ctx.layers[si].opacity + }); + composite_tile.src_rects[i] = *location; + composite_tile.blend_info[i] = opacity; + } + let shader = CompositeShader::from_cover(info.layer_indices.len()); + let key = CompositeBatchKey::new(shader); + let batch = self.composite_batches.entry(key).or_insert_with(|| { + Vec::new() + }); + batch.push(composite_tile); + } + } + } + + if !current_alpha_batch_task.screen_tile_layers.is_empty() { + alpha_batch_tasks.push(current_alpha_batch_task); + } + for task in &mut alpha_batch_tasks { + task.build(ctx); + } + self.alpha_batch_tasks = alpha_batch_tasks; + } +} + +pub struct RenderPhase { + pub targets: Vec, +} + +impl RenderPhase { + fn new(max_target_count: usize) -> RenderPhase { + let mut targets = Vec::with_capacity(max_target_count); + for index in 0..max_target_count { + targets.push(RenderTarget::new(index == max_target_count-1)); + } + + RenderPhase { + targets: targets, + } + } + + fn add_compiled_screen_tile(&mut self, + mut tile: CompiledScreenTile) -> Option { + debug_assert!(tile.required_target_count <= self.targets.len()); + + let ok = tile.main_render_task.alloc_if_required(self.targets.len() - 1, + &mut self.targets); + + if ok { + tile.main_render_task.assign_to_targets(self.targets.len() - 1, + &mut self.targets); + None + } else { + Some(tile) + } + } + + fn build(&mut self, ctx: &RenderTargetContext) { + for target in &mut self.targets { + target.build(ctx); + } + } +} + +#[derive(Debug)] +enum RenderTaskLocation { + Fixed(Rect), + Dynamic(Option>, Size2D), +} + +#[derive(Debug)] +enum RenderTaskKind { + AlphaBatch(ScreenTileLayer), + Composite(CompositeTileInfo), +} + +#[derive(Debug)] +struct RenderTask { + location: RenderTaskLocation, + children: Vec, + child_locations: Vec>, + kind: RenderTaskKind, +} + +impl RenderTask { + fn from_layer(layer: ScreenTileLayer, location: RenderTaskLocation) -> RenderTask { + RenderTask { + children: Vec::new(), + child_locations: Vec::new(), + location: location, + kind: RenderTaskKind::AlphaBatch(layer), + } + } + + fn composite(layers: Vec, + location: RenderTaskLocation, + layer_indices: Vec>) -> RenderTask { + RenderTask { + children: layers, + child_locations: Vec::new(), + location: location, + kind: RenderTaskKind::Composite(CompositeTileInfo { + layer_indices: layer_indices, + }), + } + } + + fn get_target_rect(&self) -> Rect { + match self.location { + RenderTaskLocation::Fixed(rect) => rect, + RenderTaskLocation::Dynamic(origin, size) => { + Rect::new(origin.expect("Should have been allocated by now!"), + size) + } + } + } + + fn assign_to_targets(mut self, + target_index: usize, + targets: &mut Vec) { + for child in self.children.drain(..) { + self.child_locations.push(child.get_target_rect()); + child.assign_to_targets(target_index - 1, targets); + } + + // Sanity check - can be relaxed if needed + match self.location { + RenderTaskLocation::Fixed(rect) => { + debug_assert!(target_index == targets.len() - 1); + } + RenderTaskLocation::Dynamic(origin, size) => { + debug_assert!(target_index < targets.len() - 1); + } + } + + let target = &mut targets[target_index]; + target.add_render_task(self); + } + + fn alloc_if_required(&mut self, + target_index: usize, + targets: &mut Vec) -> bool { + match self.location { + RenderTaskLocation::Fixed(..) => {} + RenderTaskLocation::Dynamic(ref mut origin, ref size) => { + let target = &mut targets[target_index]; + + let alloc_size = Size2D::new(size.width.0 as u32, + size.height.0 as u32); + + let alloc_origin = target.page_allocator + .allocate(&alloc_size, TextureFilter::Linear); + + match alloc_origin { + Some(alloc_origin) => { + *origin = Some(Point2D::new(DevicePixel(alloc_origin.x as i32), + DevicePixel(alloc_origin.y as i32))); + } + None => { + return false; + } + } + } + } + + for child in &mut self.children { + if !child.alloc_if_required(target_index - 1, + targets) { + return false; + } + } + + true + } + + fn add_child_task(&mut self, task: RenderTask) { + self.children.push(task); + } + + fn max_depth(&self, + depth: usize, + max_depth: &mut usize) { + let depth = depth + 1; + *max_depth = cmp::max(*max_depth, depth); + for child in &self.children { + child.max_depth(depth, max_depth); + } + } +} + +pub const SCREEN_TILE_SIZE: usize = 64; +pub const RENDERABLE_CACHE_SIZE: DevicePixel = DevicePixel(2048); +pub const MAX_LAYERS_PER_PASS: usize = 8; + +#[allow(non_camel_case_types)] +#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] +pub enum CompositeShader { + Prim1, + Prim2, + Prim3, + Prim4, + Prim5, + Prim6, + Prim7, + Prim8, +} + +impl CompositeShader { + fn from_cover(size: usize) -> CompositeShader { + match size { + 1 => CompositeShader::Prim1, + 2 => CompositeShader::Prim2, + 3 => CompositeShader::Prim3, + 4 => CompositeShader::Prim4, + 5 => CompositeShader::Prim5, + 6 => CompositeShader::Prim6, + 7 => CompositeShader::Prim7, + 8 => CompositeShader::Prim8, + _ => panic!("todo - other shader?"), + } + } +} + +#[derive(Debug, Clone)] +pub struct DebugRect { + pub label: String, + pub color: ColorF, + pub rect: Rect, +} + +#[derive(Debug, Copy, Clone)] +enum CacheSize { + None, + Fixed, + Variable(Size2D), +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +pub enum TransformedRectKind { + AxisAligned, + Complex, +} + +#[derive(Debug, Clone)] +struct TransformedRect { + local_rect: Rect, + bounding_rect: Rect, + vertices: [Point4D; 4], + kind: TransformedRectKind, +} + +impl TransformedRect { + fn new(rect: &Rect, + transform: &Matrix4D, + device_pixel_ratio: f32) -> TransformedRect { + + let kind = if transform.can_losslessly_transform_and_perspective_project_a_2d_rect() { + TransformedRectKind::AxisAligned + } else { + TransformedRectKind::Complex + }; + + match kind { + TransformedRectKind::AxisAligned => { + let v0 = transform.transform_point(&rect.origin); + let v1 = transform.transform_point(&rect.top_right()); + let v2 = transform.transform_point(&rect.bottom_left()); + let v3 = transform.transform_point(&rect.bottom_right()); + + let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32), + DevicePixel((v0.y * device_pixel_ratio).floor() as i32)); + let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32), + DevicePixel((v3.y * device_pixel_ratio).ceil() as i32)); + + let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x, + screen_max_dp.y - screen_min_dp.y)); + + TransformedRect { + local_rect: *rect, + vertices: [ + Point4D::new(v0.x, v0.y, 0.0, 1.0), + Point4D::new(v1.x, v1.y, 0.0, 1.0), + Point4D::new(v2.x, v2.y, 0.0, 1.0), + Point4D::new(v3.x, v3.y, 0.0, 1.0), + ], + bounding_rect: screen_rect_dp, + kind: kind, + } + } + TransformedRectKind::Complex => { + let vertices = [ + transform.transform_point4d(&Point4D::new(rect.origin.x, + rect.origin.y, + 0.0, + 1.0)), + transform.transform_point4d(&Point4D::new(rect.bottom_left().x, + rect.bottom_left().y, + 0.0, + 1.0)), + transform.transform_point4d(&Point4D::new(rect.bottom_right().x, + rect.bottom_right().y, + 0.0, + 1.0)), + transform.transform_point4d(&Point4D::new(rect.top_right().x, + rect.top_right().y, + 0.0, + 1.0)), + ]; + + let mut screen_min: Point2D = Point2D::new( 10000000.0, 10000000.0); + let mut screen_max: Point2D = Point2D::new(-10000000.0, -10000000.0); + + for vertex in &vertices { + let inv_w = 1.0 / vertex.w; + let vx = vertex.x * inv_w; + let vy = vertex.y * inv_w; + screen_min.x = screen_min.x.min(vx); + screen_min.y = screen_min.y.min(vy); + screen_max.x = screen_max.x.max(vx); + screen_max.y = screen_max.y.max(vy); + } + + let screen_min_dp = Point2D::new(DevicePixel((screen_min.x * device_pixel_ratio).floor() as i32), + DevicePixel((screen_min.y * device_pixel_ratio).floor() as i32)); + let screen_max_dp = Point2D::new(DevicePixel((screen_max.x * device_pixel_ratio).ceil() as i32), + DevicePixel((screen_max.y * device_pixel_ratio).ceil() as i32)); + + let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x, + screen_max_dp.y - screen_min_dp.y)); + + TransformedRect { + local_rect: *rect, + vertices: vertices, + bounding_rect: screen_rect_dp, + kind: kind, + } + } + } + } +} + +#[derive(Debug)] +struct RectanglePrimitive { + color: ColorF, +} + +#[derive(Debug)] +struct TextPrimitive { + color: ColorF, + font_key: FontKey, + size: Au, + blur_radius: Au, + glyph_range: ItemRange, +} + +#[derive(Debug)] +struct BoxShadowPrimitive { + src_rect: Rect, + bs_rect: Rect, + color: ColorF, + blur_radius: f32, + spread_radius: f32, + border_radius: f32, + clip_mode: BoxShadowClipMode, + metrics: BoxShadowMetrics, +} + +#[derive(Debug)] +struct BorderPrimitive { + tl_outer: Point2D, + tl_inner: Point2D, + tr_outer: Point2D, + tr_inner: Point2D, + bl_outer: Point2D, + bl_inner: Point2D, + br_outer: Point2D, + br_inner: Point2D, + left_width: f32, + top_width: f32, + right_width: f32, + bottom_width: f32, + radius: BorderRadius, + left_color: ColorF, + top_color: ColorF, + right_color: ColorF, + bottom_color: ColorF, +} + +#[derive(Debug)] +struct ImagePrimitive { + image_key: ImageKey, + image_rendering: ImageRendering, +} + +#[derive(Debug)] +struct GradientPrimitive { + stops_range: ItemRange, + dir: AxisDirection, +} + +#[derive(Debug)] +enum PrimitiveDetails { + Rectangle(RectanglePrimitive), + Text(TextPrimitive), + Image(ImagePrimitive), + Border(BorderPrimitive), + Gradient(GradientPrimitive), + BoxShadow(BoxShadowPrimitive), +} + +#[derive(Clone)] +enum PackedPrimitive { + Rectangle(PackedRectanglePrimitive), + RectangleClip(PackedRectanglePrimitiveClip), + Glyph(PackedGlyphPrimitive), + Image(PackedImagePrimitive), + Border(PackedBorderPrimitive), + BoxShadow(PackedBoxShadowPrimitive), + Gradient(PackedGradientPrimitive), +} + +struct PackedPrimList { + color_texture_id: TextureId, + primitives: Vec, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct PrimitiveIndex(usize); + +#[derive(Debug)] +struct Primitive { + rect: Rect, + local_clip_rect: Rect, + complex_clip: Option>, + xf_rect: Option, + details: PrimitiveDetails, +} + +impl Primitive { + #[inline(always)] + fn is_opaque(&self) -> bool { + match self.details { + PrimitiveDetails::Rectangle(ref details) => { + details.color.a == 1.0 + } + _ => { + false + } + } + } + + fn pack(&self, + batch: &mut PrimitiveBatch, + layer_index_in_ubo: u32, + tile_index_in_ubo: u32, + auxiliary_lists: &AuxiliaryLists, + transform_kind: TransformedRectKind, + ctx: &RenderTargetContext) -> bool { + if transform_kind != batch.transform_kind { + return false; + } + + match (&mut batch.data, &self.details) { + (&mut PrimitiveBatchData::Rectangles(ref mut data), &PrimitiveDetails::Rectangle(ref details)) => { + match self.complex_clip { + Some(..) => { + false + } + None => { + data.push(PackedRectanglePrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + }, + local_rect: self.rect, + color: details.color, + }); + true + } + } + } + (&mut PrimitiveBatchData::Rectangles(..), _) => false, + (&mut PrimitiveBatchData::RectanglesClip(ref mut data), &PrimitiveDetails::Rectangle(ref details)) => { + match self.complex_clip { + Some(ref clip) => { + data.push(PackedRectanglePrimitiveClip { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + }, + local_rect: self.rect, + color: details.color, + clip: (**clip).clone(), + }); + + true + } + None => { + false + } + } + } + (&mut PrimitiveBatchData::RectanglesClip(..), _) => false, + (&mut PrimitiveBatchData::Image(ref mut data), &PrimitiveDetails::Image(ref details)) => { + let image_info = ctx.resource_cache.get_image(details.image_key, + details.image_rendering, + ctx.frame_id); + let uv_rect = image_info.uv_rect(); + + // TODO(gw): Need a general solution to handle multiple texture pages per tile in WR2! + assert!(batch.color_texture_id == TextureId(0) || + batch.color_texture_id == image_info.texture_id); + batch.color_texture_id = image_info.texture_id; + + data.push(PackedImagePrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + }, + local_rect: self.rect, + st0: uv_rect.top_left, + st1: uv_rect.bottom_right, + }); + + true + } + (&mut PrimitiveBatchData::Image(..), _) => false, + (&mut PrimitiveBatchData::Borders(ref mut data), &PrimitiveDetails::Border(ref details)) => { + let inner_radius = BorderRadius { + top_left: Size2D::new(details.radius.top_left.width - details.left_width, + details.radius.top_left.width - details.left_width), + top_right: Size2D::new(details.radius.top_right.width - details.right_width, + details.radius.top_right.width - details.right_width), + bottom_left: Size2D::new(details.radius.bottom_left.width - details.left_width, + details.radius.bottom_left.width - details.left_width), + bottom_right: Size2D::new(details.radius.bottom_right.width - details.right_width, + details.radius.bottom_right.width - details.right_width), + }; + + let clip = Clip::from_border_radius(&self.rect, + &details.radius, + &inner_radius); + + data.push(PackedBorderPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::TopLeft, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect_from_points_f(details.tl_outer.x, + details.tl_outer.y, + details.tl_inner.x, + details.tl_inner.y), + color0: details.top_color, + color1: details.left_color, + outer_radius_x: details.radius.top_left.width, + outer_radius_y: details.radius.top_left.height, + inner_radius_x: inner_radius.top_left.width, + inner_radius_y: inner_radius.top_left.height, + }); + + data.push(PackedBorderPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::TopRight, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect_from_points_f(details.tr_inner.x, + details.tr_outer.y, + details.tr_outer.x, + details.tr_inner.y), + color0: details.right_color, + color1: details.top_color, + outer_radius_x: details.radius.top_right.width, + outer_radius_y: details.radius.top_right.height, + inner_radius_x: inner_radius.top_right.width, + inner_radius_y: inner_radius.top_right.height, + }); + + data.push(PackedBorderPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::BottomLeft, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect_from_points_f(details.bl_outer.x, + details.bl_inner.y, + details.bl_inner.x, + details.bl_outer.y), + color0: details.left_color, + color1: details.bottom_color, + outer_radius_x: details.radius.bottom_left.width, + outer_radius_y: details.radius.bottom_left.height, + inner_radius_x: inner_radius.bottom_left.width, + inner_radius_y: inner_radius.bottom_left.height, + }); + + data.push(PackedBorderPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::BottomRight, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect_from_points_f(details.br_inner.x, + details.br_inner.y, + details.br_outer.x, + details.br_outer.y), + color0: details.right_color, + color1: details.bottom_color, + outer_radius_x: details.radius.bottom_right.width, + outer_radius_y: details.radius.bottom_right.height, + inner_radius_x: inner_radius.bottom_right.width, + inner_radius_y: inner_radius.bottom_right.height, + }); + + data.push(PackedBorderPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Left, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect_from_points_f(details.tl_outer.x, + details.tl_inner.y, + details.tl_outer.x + details.left_width, + details.bl_inner.y), + color0: details.left_color, + color1: details.left_color, + outer_radius_x: 0.0, + outer_radius_y: 0.0, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }); + + data.push(PackedBorderPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Right, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect_from_points_f(details.tr_outer.x - details.right_width, + details.tr_inner.y, + details.br_outer.x, + details.br_inner.y), + color0: details.right_color, + color1: details.right_color, + outer_radius_x: 0.0, + outer_radius_y: 0.0, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }); + + data.push(PackedBorderPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Top, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect_from_points_f(details.tl_inner.x, + details.tl_outer.y, + details.tr_inner.x, + details.tr_outer.y + details.top_width), + color0: details.top_color, + color1: details.top_color, + outer_radius_x: 0.0, + outer_radius_y: 0.0, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }); + + data.push(PackedBorderPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Bottom, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect_from_points_f(details.bl_inner.x, + details.bl_outer.y - details.bottom_width, + details.br_inner.x, + details.br_outer.y), + color0: details.bottom_color, + color1: details.bottom_color, + outer_radius_x: 0.0, + outer_radius_y: 0.0, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }); + + true + } + (&mut PrimitiveBatchData::Borders(..), _) => false, + (&mut PrimitiveBatchData::Gradient(ref mut data), &PrimitiveDetails::Gradient(ref details)) => { + let stops = auxiliary_lists.gradient_stops(&details.stops_range); + for i in 0..(stops.len() - 1) { + let (prev_stop, next_stop) = (&stops[i], &stops[i + 1]); + let piece_origin; + let piece_size; + match details.dir { + AxisDirection::Horizontal => { + let prev_x = util::lerp(self.rect.origin.x, self.rect.max_x(), prev_stop.offset); + let next_x = util::lerp(self.rect.origin.x, self.rect.max_x(), next_stop.offset); + piece_origin = Point2D::new(prev_x, self.rect.origin.y); + piece_size = Size2D::new(next_x - prev_x, self.rect.size.height); + } + AxisDirection::Vertical => { + let prev_y = util::lerp(self.rect.origin.y, self.rect.max_y(), prev_stop.offset); + let next_y = util::lerp(self.rect.origin.y, self.rect.max_y(), next_stop.offset); + piece_origin = Point2D::new(self.rect.origin.x, prev_y); + piece_size = Size2D::new(self.rect.size.width, next_y - prev_y); + } + } + + let piece_rect = Rect::new(piece_origin, piece_size); + + data.push(PackedGradientPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Bottom, + local_clip_rect: self.local_clip_rect, + }, + local_rect: piece_rect, + color0: prev_stop.color, + color1: next_stop.color, + padding: [0, 0, 0], + dir: details.dir, + }); + } + + true + } + (&mut PrimitiveBatchData::Gradient(..), _) => false, + (&mut PrimitiveBatchData::BoxShadows(ref mut data), &PrimitiveDetails::BoxShadow(ref details)) => { + let mut rects = Vec::new(); + subtract_rect(&self.rect, &details.src_rect, &mut rects); + + for rect in rects { + data.push(PackedBoxShadowPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + }, + local_rect: rect, + color: details.color, + + border_radii: Point2D::new(details.border_radius, details.border_radius), + blur_radius: details.blur_radius, + inverted: 0.0, + bs_rect: details.bs_rect, + src_rect: details.src_rect, + }); + } + + true + } + (&mut PrimitiveBatchData::BoxShadows(..), _) => false, + (&mut PrimitiveBatchData::Text(ref mut data), &PrimitiveDetails::Text(ref details)) => { + let src_glyphs = auxiliary_lists.glyph_instances(&details.glyph_range); + let mut glyph_key = GlyphKey::new(details.font_key, + details.size, + details.blur_radius, + src_glyphs[0].index); + let blur_offset = details.blur_radius.to_f32_px() * (BLUR_INFLATION_FACTOR as f32) / 2.0; + + for glyph in src_glyphs { + glyph_key.index = glyph.index; + let image_info = ctx.resource_cache.get_glyph(&glyph_key, ctx.frame_id); + if let Some(image_info) = image_info { + // TODO(gw): Need a general solution to handle multiple texture pages per tile in WR2! + assert!(batch.color_texture_id == TextureId(0) || + batch.color_texture_id == image_info.texture_id); + batch.color_texture_id = image_info.texture_id; + + let x = glyph.x + image_info.user_data.x0 as f32 / ctx.device_pixel_ratio - blur_offset; + let y = glyph.y - image_info.user_data.y0 as f32 / ctx.device_pixel_ratio - blur_offset; + + let width = image_info.requested_rect.size.width as f32 / ctx.device_pixel_ratio; + let height = image_info.requested_rect.size.height as f32 / ctx.device_pixel_ratio; + + let uv_rect = image_info.uv_rect(); + + data.push(PackedGlyphPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + }, + local_rect: Rect::new(Point2D::new(x, y), + Size2D::new(width, height)), + color: details.color, + st0: uv_rect.top_left, + st1: uv_rect.bottom_right, + }); + } + } + + true + } + (&mut PrimitiveBatchData::Text(..), _) => false, + } + } +} + +#[repr(u32)] +#[derive(Debug, Copy, Clone)] +enum PrimitivePart { + Invalid = 0, + TopLeft, + TopRight, + BottomLeft, + BottomRight, + Top, + Left, + Bottom, + Right, +} + +#[derive(Debug, Clone)] +pub struct CompositeTile { + pub screen_rect: Rect, + pub src_rects: [Rect; MAX_LAYERS_PER_PASS], + pub blend_info: [f32; MAX_LAYERS_PER_PASS], +} + +impl CompositeTile { + fn new(rect: &Rect) -> CompositeTile { + CompositeTile { + screen_rect: *rect, + src_rects: unsafe { mem::uninitialized() }, + blend_info: [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ], + } + } +} + +#[derive(Debug, Eq, PartialEq, Hash, Clone)] +pub struct CompositeBatchKey { + pub shader: CompositeShader, + //pub samplers: [TextureId; MAX_PRIMS_PER_COMPOSITE], +} + +impl CompositeBatchKey { + fn new(shader: CompositeShader, + //samplers: [TextureId; MAX_PRIMS_PER_COMPOSITE] + ) -> CompositeBatchKey { + CompositeBatchKey { + shader: shader, + //samplers: samplers, + } + } +} + +#[derive(Debug)] +pub struct PackedTile { + actual_rect: Rect, + target_rect: Rect, +} + +#[derive(Debug)] +pub struct PackedLayer { + transform: Matrix4D, + inv_transform: Matrix4D, + screen_vertices: [Point4D; 4], + blend_info: [f32; 2], + padding: [u32; 2], +} + +#[derive(Debug)] +pub struct PackedRenderable { + transform: Matrix4D, + local_rect: Rect, + cache_rect: Rect, + screen_rect: Rect, + st0: Point2D, + st1: Point2D, + offset: Point2D, + blend_info: [f32; 2], +} + +#[derive(Debug, Clone)] +pub struct PackedPrimitiveInfo { + layer_index: u32, + tile_index: u32, + part: PrimitivePart, + padding: u32, + local_clip_rect: Rect, +} + +#[derive(Debug)] +pub struct PackedFixedRectangle { + common: PackedPrimitiveInfo, + color: ColorF, +} + +#[derive(Debug, Clone)] +pub struct PackedRectanglePrimitiveClip { + common: PackedPrimitiveInfo, + local_rect: Rect, + color: ColorF, + clip: Clip, +} + +#[derive(Debug, Clone)] +pub struct PackedRectanglePrimitive { + common: PackedPrimitiveInfo, + local_rect: Rect, + color: ColorF, +} + +#[derive(Debug, Clone)] +pub struct PackedGlyphPrimitive { + common: PackedPrimitiveInfo, + local_rect: Rect, + color: ColorF, + st0: Point2D, + st1: Point2D, +} + +#[derive(Debug, Clone)] +pub struct PackedImagePrimitive { + common: PackedPrimitiveInfo, + local_rect: Rect, + st0: Point2D, + st1: Point2D, +} + +#[derive(Debug, Clone)] +pub struct PackedGradientPrimitive { + common: PackedPrimitiveInfo, + local_rect: Rect, + color0: ColorF, + color1: ColorF, + dir: AxisDirection, + padding: [u32; 3], +} + +#[derive(Debug, Clone)] +pub struct PackedBorderPrimitive { + common: PackedPrimitiveInfo, + local_rect: Rect, + color0: ColorF, + color1: ColorF, + outer_radius_x: f32, + outer_radius_y: f32, + inner_radius_x: f32, + inner_radius_y: f32, +} + +#[derive(Debug, Clone)] +pub struct PackedBoxShadowPrimitive { + common: PackedPrimitiveInfo, + local_rect: Rect, + color: ColorF, + border_radii: Point2D, + blur_radius: f32, + inverted: f32, + bs_rect: Rect, + src_rect: Rect, +} + +#[derive(Debug)] +pub enum PrimitiveBatchData { + Rectangles(Vec), + RectanglesClip(Vec), + Borders(Vec), + BoxShadows(Vec), + Text(Vec), + Image(Vec), + Gradient(Vec), +} + +#[derive(Debug)] +pub struct PrimitiveBatch { + pub transform_kind: TransformedRectKind, + pub color_texture_id: TextureId, // TODO(gw): Expand to sampler array to handle all glyphs! + pub data: PrimitiveBatchData, +} + +impl PrimitiveBatch { + fn new(prim: &Primitive, transform_kind: TransformedRectKind) -> PrimitiveBatch { + let data = match prim.details { + PrimitiveDetails::Rectangle(..) => { + match prim.complex_clip { + Some(..) => PrimitiveBatchData::RectanglesClip(Vec::new()), + None => PrimitiveBatchData::Rectangles(Vec::new()), + } + } + PrimitiveDetails::Border(..) => { + PrimitiveBatchData::Borders(Vec::new()) + } + PrimitiveDetails::BoxShadow(..) => { + PrimitiveBatchData::BoxShadows(Vec::new()) + } + PrimitiveDetails::Text(..) => { + PrimitiveBatchData::Text(Vec::new()) + } + PrimitiveDetails::Image(..) => { + PrimitiveBatchData::Image(Vec::new()) + } + PrimitiveDetails::Gradient(..) => { + PrimitiveBatchData::Gradient(Vec::new()) + } + }; + + let mut this = PrimitiveBatch { + color_texture_id: TextureId(0), + transform_kind: transform_kind, + data: data, + }; + + this + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct StackingContextChunkIndex(usize); + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct StackingContextIndex(usize); + +struct StackingContext { + pipeline_id: PipelineId, + local_transform: Matrix4D, + local_rect: Rect, + local_offset: Point2D, + primitives: Vec, + scroll_layer_id: ScrollLayerId, + opacity: f32, + transform: Matrix4D, + xf_rect: Option, +} + +impl StackingContext { + fn build_resource_list(&self, + resource_list: &mut ResourceList, + //index_buffer: &Vec, + auxiliary_lists: &AuxiliaryLists) { +// for prim_index in index_buffer { +// let PrimitiveIndex(prim_index) = *prim_index; +// let prim = &self.primitives[prim_index]; + for prim in &self.primitives { + match prim.details { + PrimitiveDetails::Rectangle(..) => {} + PrimitiveDetails::Gradient(..) => {} + PrimitiveDetails::Border(..) => {} + PrimitiveDetails::BoxShadow(..) => {} + PrimitiveDetails::Image(ref details) => { + resource_list.add_image(details.image_key, + details.image_rendering); + } + PrimitiveDetails::Text(ref details) => { + let glyphs = auxiliary_lists.glyph_instances(&details.glyph_range); + for glyph in glyphs { + let glyph = Glyph::new(details.size, details.blur_radius, glyph.index); + resource_list.add_glyph(details.font_key, glyph); + } + } + } + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +struct ClipIndex(usize); + +#[derive(Debug, Clone)] +pub struct ClipCorner { + rect: Rect, + outer_radius_x: f32, + outer_radius_y: f32, + inner_radius_x: f32, + inner_radius_y: f32, +} + +#[derive(Debug, Clone)] +pub struct Clip { + rect: Rect, + top_left: ClipCorner, + top_right: ClipCorner, + bottom_left: ClipCorner, + bottom_right: ClipCorner, +} + +#[derive(Debug, Clone)] +pub struct ClearTile { + pub rect: Rect, +} + +#[derive(Clone, Copy)] +pub struct FrameBuilderConfig { + max_prim_layers: usize, + max_prim_tiles: usize, +} + +impl FrameBuilderConfig { + pub fn new(max_prim_layers: usize, + max_prim_tiles: usize) -> FrameBuilderConfig { + FrameBuilderConfig { + max_prim_layers: max_prim_layers, + max_prim_tiles: max_prim_tiles, + } + } +} + +pub struct FrameBuilder { + screen_rect: Rect, + layers: Vec, + layer_stack: Vec, + device_pixel_ratio: f32, + debug: bool, + config: FrameBuilderConfig, +} + +pub struct Frame { + pub debug_rects: Vec, + pub cache_size: Size2D, + pub phases: Vec, + pub clear_tiles: Vec, +} + +impl Clip { + pub fn from_clip_region(clip: &ComplexClipRegion) -> Clip { + Clip { + rect: clip.rect, + top_left: ClipCorner { + rect: Rect::new(Point2D::new(clip.rect.origin.x, clip.rect.origin.y), + Size2D::new(clip.radii.top_left.width, clip.radii.top_left.height)), + outer_radius_x: clip.radii.top_left.width, + outer_radius_y: clip.radii.top_left.height, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }, + top_right: ClipCorner { + rect: Rect::new(Point2D::new(clip.rect.origin.x + clip.rect.size.width - clip.radii.top_right.width, + clip.rect.origin.y), + Size2D::new(clip.radii.top_right.width, clip.radii.top_right.height)), + outer_radius_x: clip.radii.top_right.width, + outer_radius_y: clip.radii.top_right.height, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }, + bottom_left: ClipCorner { + rect: Rect::new(Point2D::new(clip.rect.origin.x, + clip.rect.origin.y + clip.rect.size.height - clip.radii.bottom_left.height), + Size2D::new(clip.radii.bottom_left.width, clip.radii.bottom_left.height)), + outer_radius_x: clip.radii.bottom_left.width, + outer_radius_y: clip.radii.bottom_left.height, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }, + bottom_right: ClipCorner { + rect: Rect::new(Point2D::new(clip.rect.origin.x + clip.rect.size.width - clip.radii.bottom_right.width, + clip.rect.origin.y + clip.rect.size.height - clip.radii.bottom_right.height), + Size2D::new(clip.radii.bottom_right.width, clip.radii.bottom_right.height)), + outer_radius_x: clip.radii.bottom_right.width, + outer_radius_y: clip.radii.bottom_right.height, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + }, + } + } + + pub fn from_border_radius(rect: &Rect, + outer_radius: &BorderRadius, + inner_radius: &BorderRadius) -> Clip { + Clip { + rect: *rect, + top_left: ClipCorner { + rect: Rect::new(Point2D::new(rect.origin.x, rect.origin.y), + Size2D::new(outer_radius.top_left.width, outer_radius.top_left.height)), + outer_radius_x: outer_radius.top_left.width, + outer_radius_y: outer_radius.top_left.height, + inner_radius_x: inner_radius.top_left.width, + inner_radius_y: inner_radius.top_left.height, + }, + top_right: ClipCorner { + rect: Rect::new(Point2D::new(rect.origin.x + rect.size.width - outer_radius.top_right.width, + rect.origin.y), + Size2D::new(outer_radius.top_right.width, outer_radius.top_right.height)), + outer_radius_x: outer_radius.top_right.width, + outer_radius_y: outer_radius.top_right.height, + inner_radius_x: inner_radius.top_right.width, + inner_radius_y: inner_radius.top_right.height, + }, + bottom_left: ClipCorner { + rect: Rect::new(Point2D::new(rect.origin.x, + rect.origin.y + rect.size.height - outer_radius.bottom_left.height), + Size2D::new(outer_radius.bottom_left.width, outer_radius.bottom_left.height)), + outer_radius_x: outer_radius.bottom_left.width, + outer_radius_y: outer_radius.bottom_left.height, + inner_radius_x: inner_radius.bottom_left.width, + inner_radius_y: inner_radius.bottom_left.height, + }, + bottom_right: ClipCorner { + rect: Rect::new(Point2D::new(rect.origin.x + rect.size.width - outer_radius.bottom_right.width, + rect.origin.y + rect.size.height - outer_radius.bottom_right.height), + Size2D::new(outer_radius.bottom_right.width, outer_radius.bottom_right.height)), + outer_radius_x: outer_radius.bottom_right.width, + outer_radius_y: outer_radius.bottom_right.height, + inner_radius_x: inner_radius.bottom_right.width, + inner_radius_y: inner_radius.bottom_right.height, + }, + } + } +} + +#[derive(Debug)] +struct CompositeTileInfo { + layer_indices: Vec>, +} + +#[derive(Debug)] +struct ScreenTileLayer { + actual_rect: Rect, + layer_index: StackingContextIndex, + prim_indices: Vec, // todo(gw): pre-build these into parts to save duplicated cpu time? + layer_opacity: f32, + is_opaque: bool, +} + +impl ScreenTileLayer { + fn compile(&mut self, + layer: &StackingContext, + screen_rect: &Rect) { + self.prim_indices.sort_by(|a, b| { + b.cmp(&a) + }); + self.prim_indices.dedup(); + +/* + // Intra-layer occlusion + let first_opaque_cover_index = self.prim_indices.iter().position(|i| { + let PrimitiveIndex(pi) = *i; + let prim = &layer.primitives[pi]; + prim.is_opaque() && + rect_contains_rect(&prim.xf_rect.as_ref().unwrap().bounding_rect, screen_rect) + }); + if let Some(first_opaque_cover_index) = first_opaque_cover_index { + self.prim_indices.truncate(first_opaque_cover_index); + } +*/ + + // Inter-layer occlusion + let PrimitiveIndex(pi) = *self.prim_indices.last().unwrap(); + let last_prim = &layer.primitives[pi]; + if layer.opacity == 1.0 && + last_prim.is_opaque() && + layer.xf_rect.as_ref().unwrap().kind == TransformedRectKind::AxisAligned && + rect_contains_rect(&last_prim.xf_rect.as_ref().unwrap().bounding_rect, + screen_rect) { + self.is_opaque = true; + } + } +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct ScreenTileIndex(usize); + +enum ScreenTileCompileResult { + Clear, + Unhandled, + Ok, +} + +#[derive(Debug)] +struct CompiledScreenTile { + main_render_task: RenderTask, + required_target_count: usize, +} + +impl CompiledScreenTile { + fn new(main_render_task: RenderTask) -> CompiledScreenTile { + let mut required_target_count = 0; + main_render_task.max_depth(0, &mut required_target_count); + + CompiledScreenTile { + main_render_task: main_render_task, + required_target_count: required_target_count, + } + } +} + +#[derive(Debug)] +struct ScreenTile { + rect: Rect, + layers: Vec, +} + +impl ScreenTile { + fn new(rect: Rect) -> ScreenTile { + ScreenTile { + rect: rect, + layers: Vec::new(), + } + } + + fn layer_count(&self) -> usize { + self.layers.len() + } + + fn compile(mut self) -> Option { + if self.layers.len() == 0 { + return None; + } + + // TODO(gw): If a single had blending, fall through to the + // compositing case below. Investigate if it's + // worth having a special path for this? + if self.layers.len() == 1 && self.layers[0].layer_opacity == 1.0 { + let task = RenderTask::from_layer(self.layers.pop().unwrap(), + RenderTaskLocation::Fixed(self.rect)); + Some(CompiledScreenTile::new(task)) + } else { + let mut layer_indices_in_current_layer = Vec::new(); + let mut tasks_in_current_layer = Vec::new(); + + for layer in self.layers.drain(..) { + if tasks_in_current_layer.len() == MAX_LAYERS_PER_PASS { + let composite_location = RenderTaskLocation::Dynamic(None, self.rect.size); + let tasks_to_composite = mem::replace(&mut tasks_in_current_layer, Vec::new()); + let layers_to_composite = mem::replace(&mut layer_indices_in_current_layer, + Vec::new()); + let composite_task = RenderTask::composite(tasks_to_composite, + composite_location, + layers_to_composite); + debug_assert!(tasks_in_current_layer.is_empty()); + tasks_in_current_layer.push(composite_task); + layer_indices_in_current_layer.push(None); + } + + layer_indices_in_current_layer.push(Some(layer.layer_index)); + let layer_task = RenderTask::from_layer(layer, + RenderTaskLocation::Dynamic(None, + self.rect.size)); + tasks_in_current_layer.push(layer_task); + } + + debug_assert!(!tasks_in_current_layer.is_empty()); + let main_task = RenderTask::composite(tasks_in_current_layer, + RenderTaskLocation::Fixed(self.rect), + layer_indices_in_current_layer); + + Some(CompiledScreenTile::new(main_task)) + } + + } +} + +impl FrameBuilder { + pub fn new(viewport_size: Size2D, + device_pixel_ratio: f32, + debug: bool, + config: FrameBuilderConfig) -> FrameBuilder { + let viewport_size = Size2D::new(viewport_size.width as i32, viewport_size.height as i32); + FrameBuilder { + screen_rect: Rect::new(Point2D::zero(), viewport_size), + layers: Vec::new(), + layer_stack: Vec::new(), + device_pixel_ratio: device_pixel_ratio, + debug: debug, + config: config, + } + } + + fn add_primitive(&mut self, + rect: &Rect, + clip_rect: &Rect, + clip: Option>, + details: PrimitiveDetails) { + let current_layer = *self.layer_stack.last().unwrap(); + let StackingContextIndex(layer_index) = current_layer; + let layer = &mut self.layers[layer_index as usize]; + + let prim = Primitive { + rect: *rect, + xf_rect: None, + complex_clip: clip, + local_clip_rect: *clip_rect, + details: details, + }; + layer.primitives.push(prim); + } + + pub fn push_layer(&mut self, + rect: Rect, + _clip_rect: Rect, + transform: Matrix4D, + opacity: f32, + pipeline_id: PipelineId, + scroll_layer_id: ScrollLayerId, + offset: Point2D) { + let sc = StackingContext { + primitives: Vec::new(), + local_rect: rect, + local_transform: transform, + local_offset: offset, + scroll_layer_id: scroll_layer_id, + opacity: opacity, + pipeline_id: pipeline_id, + xf_rect: None, + transform: Matrix4D::identity(), + }; + + self.layer_stack.push(StackingContextIndex(self.layers.len())); + self.layers.push(sc); + } + + pub fn pop_layer(&mut self) { + self.layer_stack.pop(); + } + + pub fn add_solid_rectangle(&mut self, + rect: &Rect, + clip_rect: &Rect, + clip: Option>, + color: &ColorF) { + if color.a == 0.0 { + return; + } + + let prim = RectanglePrimitive { + color: *color, + }; + + self.add_primitive(rect, + clip_rect, + clip, + PrimitiveDetails::Rectangle(prim)); + } + + pub fn add_border(&mut self, + rect: Rect, + clip_rect: &Rect, + clip: Option>, + border: &BorderDisplayItem) { + let radius = &border.radius; + let left = &border.left; + let right = &border.right; + let top = &border.top; + let bottom = &border.bottom; + + if (left.style != BorderStyle::Solid && left.style != BorderStyle::None) || + (top.style != BorderStyle::Solid && top.style != BorderStyle::None) || + (bottom.style != BorderStyle::Solid && bottom.style != BorderStyle::None) || + (right.style != BorderStyle::Solid && right.style != BorderStyle::None) { + println!("TODO: Other border styles {:?} {:?} {:?} {:?}", left.style, top.style, bottom.style, right.style); + return; + } + + let tl_outer = Point2D::new(rect.origin.x, rect.origin.y); + let tl_inner = tl_outer + Point2D::new(radius.top_left.width.max(left.width), + radius.top_left.height.max(top.width)); + + let tr_outer = Point2D::new(rect.origin.x + rect.size.width, rect.origin.y); + let tr_inner = tr_outer + Point2D::new(-radius.top_right.width.max(right.width), + radius.top_right.height.max(top.width)); + + let bl_outer = Point2D::new(rect.origin.x, rect.origin.y + rect.size.height); + let bl_inner = bl_outer + Point2D::new(radius.bottom_left.width.max(left.width), + -radius.bottom_left.height.max(bottom.width)); + + let br_outer = Point2D::new(rect.origin.x + rect.size.width, + rect.origin.y + rect.size.height); + let br_inner = br_outer - Point2D::new(radius.bottom_right.width.max(right.width), + radius.bottom_right.height.max(bottom.width)); + + let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7); + let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7); + let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3); + let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3); + + let prim = BorderPrimitive { + tl_outer: tl_outer, + tl_inner: tl_inner, + tr_outer: tr_outer, + tr_inner: tr_inner, + bl_outer: bl_outer, + bl_inner: bl_inner, + br_outer: br_outer, + br_inner: br_inner, + radius: radius.clone(), + left_width: left.width, + top_width: top.width, + bottom_width: bottom.width, + right_width: right.width, + left_color: left_color, + top_color: top_color, + bottom_color: bottom_color, + right_color: right_color, + }; + + self.add_primitive(&rect, + clip_rect, + clip, + PrimitiveDetails::Border(prim)); + } + + pub fn add_gradient(&mut self, + rect: Rect, + clip_rect: &Rect, + clip: Option>, + start_point: Point2D, + end_point: Point2D, + stops: ItemRange) { + // Fast paths for axis-aligned gradients: + if start_point.x == end_point.x { + let rect = Rect::new(Point2D::new(rect.origin.x, start_point.y), + Size2D::new(rect.size.width, end_point.y - start_point.y)); + let prim = GradientPrimitive { + stops_range: stops, + dir: AxisDirection::Vertical, + }; + self.add_primitive(&rect, + clip_rect, + clip, + PrimitiveDetails::Gradient(prim)); + } else if start_point.y == end_point.y { + let rect = Rect::new(Point2D::new(start_point.x, rect.origin.y), + Size2D::new(end_point.x - start_point.x, rect.size.height)); + let prim = GradientPrimitive { + stops_range: stops, + dir: AxisDirection::Horizontal, + }; + self.add_primitive(&rect, + clip_rect, + clip, + PrimitiveDetails::Gradient(prim)); + } else { + //println!("TODO: Angle gradients! {:?} {:?} {:?}", start_point, end_point, stops); + } + } + + pub fn add_text(&mut self, + rect: Rect, + clip_rect: &Rect, + clip: Option>, + font_key: FontKey, + size: Au, + blur_radius: Au, + color: &ColorF, + glyph_range: ItemRange) { + if color.a == 0.0 { + return + } + + let prim = TextPrimitive { + color: *color, + font_key: font_key, + size: size, + blur_radius: blur_radius, + glyph_range: glyph_range, + }; + + self.add_primitive(&rect, + clip_rect, + clip, + PrimitiveDetails::Text(prim)); + } + + pub fn add_box_shadow(&mut self, + box_bounds: &Rect, + clip_rect: &Rect, + clip: Option>, + box_offset: &Point2D, + color: &ColorF, + blur_radius: f32, + spread_radius: f32, + border_radius: f32, + clip_mode: BoxShadowClipMode) { + if color.a == 0.0 { + return + } + + let bs_rect = compute_box_shadow_rect(box_bounds, + box_offset, + spread_radius); + + let metrics = BoxShadowMetrics::new(&bs_rect, + border_radius, + blur_radius); + + let prim_rect = Rect::new(metrics.tl_outer, + Size2D::new(metrics.br_outer.x - metrics.tl_outer.x, + metrics.br_outer.y - metrics.tl_outer.y)); + + let prim = BoxShadowPrimitive { + metrics: metrics, + src_rect: *box_bounds, + bs_rect: bs_rect, + color: *color, + blur_radius: blur_radius, + spread_radius: spread_radius, + border_radius: border_radius, + clip_mode: clip_mode, + }; + + self.add_primitive(&prim_rect, + clip_rect, + clip, + PrimitiveDetails::BoxShadow(prim)); + } + + pub fn add_image(&mut self, + rect: Rect, + clip_rect: &Rect, + clip: Option>, + _stretch_size: &Size2D, + image_key: ImageKey, + image_rendering: ImageRendering) { + let prim = ImagePrimitive { + image_key: image_key, + image_rendering: image_rendering, + }; + + self.add_primitive(&rect, + clip_rect, + clip, + PrimitiveDetails::Image(prim)); + } + + fn cull_layers(&mut self, + screen_rect: &Rect, + layer_map: &HashMap>) { + // Remove layers that are transparent. + self.layers.retain(|layer| { + layer.opacity > 0.0 + }); + + // Build layer screen rects. + // TODO(gw): This can be done earlier once update_layer_transforms() is fixed. + for layer in &mut self.layers { + let scroll_layer = &layer_map[&layer.scroll_layer_id]; + let offset_transform = Matrix4D::identity().translate(layer.local_offset.x, + layer.local_offset.y, + 0.0); + let transform = scroll_layer.world_transform + .as_ref() + .unwrap() + .mul(&layer.local_transform) + .mul(&offset_transform); + layer.transform = transform; + layer.xf_rect = Some(TransformedRect::new(&layer.local_rect, + &transform, + self.device_pixel_ratio)); + } + + self.layers.retain(|layer| { + layer.xf_rect + .as_ref() + .unwrap() + .bounding_rect + .intersects(&screen_rect) + }); + + for layer in &mut self.layers { + for prim in &mut layer.primitives { + prim.xf_rect = Some(TransformedRect::new(&prim.rect, + &layer.transform, + self.device_pixel_ratio)); + } + + layer.primitives.retain(|prim| { + prim.xf_rect + .as_ref() + .unwrap() + .bounding_rect + .intersects(&screen_rect) + }); + } + } + + fn create_screen_tiles(&self) -> Vec { + let dp_size = Size2D::new(DevicePixel::new(self.screen_rect.size.width as f32, + self.device_pixel_ratio), + DevicePixel::new(self.screen_rect.size.height as f32, + self.device_pixel_ratio)); + + let x_tile_size = DevicePixel(SCREEN_TILE_SIZE as i32); + let y_tile_size = DevicePixel(SCREEN_TILE_SIZE as i32); + let x_tile_count = (dp_size.width + x_tile_size - DevicePixel(1)).0 / x_tile_size.0; + let y_tile_count = (dp_size.height + y_tile_size - DevicePixel(1)).0 / y_tile_size.0; + + // Build screen space tiles, which are individual BSP trees. + let mut screen_tiles = Vec::new(); + for y in 0..y_tile_count { + let y0 = DevicePixel(y * y_tile_size.0); + let y1 = y0 + y_tile_size; + + for x in 0..x_tile_count { + let x0 = DevicePixel(x * x_tile_size.0); + let x1 = x0 + x_tile_size; + + let tile_rect = rect_from_points(x0, y0, x1, y1); + + screen_tiles.push(ScreenTile::new(tile_rect)); + } + } + + screen_tiles + } + + fn assign_prims_to_screen_tiles(&self, + screen_tiles: &mut Vec, + debug_rects: &mut Vec) { //-> usize { + //let mut pass_count = 0; + + // TODO(gw): This can be made much faster - calculate tile indices and + // assign in a loop. + for screen_tile in screen_tiles { + let mut prim_count = 0; + for (layer_index, layer) in self.layers + .iter() + .enumerate() { + let layer_index = StackingContextIndex(layer_index); + let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; + + if layer_rect.intersects(&screen_tile.rect) { + let mut tile_layer = ScreenTileLayer { + actual_rect: screen_tile.rect, + layer_index: layer_index, + prim_indices: Vec::new(), + layer_opacity: layer.opacity, + is_opaque: false, + }; + for (prim_index, prim) in layer.primitives.iter().enumerate() { + let prim_rect = &prim.xf_rect.as_ref().unwrap().bounding_rect; + if prim_rect.intersects(&screen_tile.rect) { + prim_count += 1; + tile_layer.prim_indices.push(PrimitiveIndex(prim_index)); + } + } + if tile_layer.prim_indices.len() > 0 { + tile_layer.compile(layer, &screen_tile.rect); + if tile_layer.is_opaque { + screen_tile.layers.clear(); + } + screen_tile.layers.push(tile_layer); + } + } + } + + if self.debug { + debug_rects.push(DebugRect { + label: format!("{}|{}", screen_tile.layer_count(), prim_count), + color: ColorF::new(1.0, 0.0, 0.0, 1.0), + rect: screen_tile.rect, + }) + } + } + + //pass_count + } + + fn build_resource_list(&mut self, + resource_cache: &mut ResourceCache, + frame_id: FrameId, + pipeline_auxiliary_lists: &HashMap>) { + let mut resource_list = ResourceList::new(self.device_pixel_ratio); + + // Non-visible layers have been removed by now + for layer in &self.layers { + let auxiliary_lists = pipeline_auxiliary_lists.get(&layer.pipeline_id) + .expect("No auxiliary lists?!"); + + // Non-visible chunks have also been removed by now + layer.build_resource_list(&mut resource_list, + //&layer.primitives, + auxiliary_lists); + } + + resource_cache.add_resource_list(&resource_list, + frame_id); + resource_cache.raster_pending_glyphs(frame_id); + } + + pub fn build(&mut self, + resource_cache: &mut ResourceCache, + frame_id: FrameId, + pipeline_auxiliary_lists: &HashMap>, + layer_map: &HashMap>) -> Frame { + let screen_rect = Rect::new(Point2D::zero(), + Size2D::new(DevicePixel::new(self.screen_rect.size.width as f32, self.device_pixel_ratio), + DevicePixel::new(self.screen_rect.size.height as f32, self.device_pixel_ratio))); + + self.cull_layers(&screen_rect, layer_map); + + let mut debug_rects = Vec::new(); + let mut screen_tiles = self.create_screen_tiles(); + + self.assign_prims_to_screen_tiles(&mut screen_tiles, + &mut debug_rects); + + self.build_resource_list(resource_cache, + frame_id, + pipeline_auxiliary_lists); + + let mut clear_tiles = Vec::new(); + + // Build list of passes, target allocs that each tile needs. + let mut compiled_screen_tiles = Vec::new(); + for screen_tile in screen_tiles { + let rect = screen_tile.rect; // TODO(gw): Remove clone here + match screen_tile.compile() { + Some(compiled_screen_tile) => { + compiled_screen_tiles.push(compiled_screen_tile); + } + None => { + clear_tiles.push(ClearTile { + rect: rect, + }); + } + } + } + + let mut phases = Vec::new(); + + if !compiled_screen_tiles.is_empty() { + // Sort by pass count to minimize render target switches. + compiled_screen_tiles.sort_by(|a, b| { + let a_passes = a.required_target_count; + let b_passes = b.required_target_count; + b_passes.cmp(&a_passes) + }); + + // Do the allocations now, assigning each tile to a render + // phase as required. + + let mut current_phase = RenderPhase::new(compiled_screen_tiles[0].required_target_count); + + for compiled_screen_tile in compiled_screen_tiles { + if let Some(failed_tile) = current_phase.add_compiled_screen_tile(compiled_screen_tile) { + let full_phase = mem::replace(&mut current_phase, + RenderPhase::new(failed_tile.required_target_count)); + phases.push(full_phase); + + let result = current_phase.add_compiled_screen_tile(failed_tile); + assert!(result.is_none(), "TODO: Handle single tile not fitting in render phase."); + } + } + + phases.push(current_phase); + + let ctx = RenderTargetContext { + layers: &self.layers, + resource_cache: resource_cache, + device_pixel_ratio: self.device_pixel_ratio, + frame_id: frame_id, + pipeline_auxiliary_lists: pipeline_auxiliary_lists, + alpha_batch_max_layers: self.config.max_prim_layers, + alpha_batch_max_tiles: self.config.max_prim_tiles, + }; + + for phase in &mut phases { + phase.build(&ctx); + } + } + + Frame { + debug_rects: debug_rects, + phases: phases, + clear_tiles: clear_tiles, + cache_size: Size2D::new(RENDERABLE_CACHE_SIZE.0 as f32, + RENDERABLE_CACHE_SIZE.0 as f32), + } + } + +} + +fn compute_box_shadow_rect(box_bounds: &Rect, + box_offset: &Point2D, + spread_radius: f32) + -> Rect { + let mut rect = (*box_bounds).clone(); + rect.origin.x += box_offset.x; + rect.origin.y += box_offset.y; + rect.inflate(spread_radius, spread_radius) +} diff --git a/src/util.rs b/src/util.rs index eeda129405..01f4fbf134 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,10 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use euclid::{Matrix4D, Point2D, Point4D, Rect, Size2D}; -use internal_types::{RectColors}; +use internal_types::{DevicePixel}; use num_traits::Zero; use time::precise_time_ns; -use webrender_traits::ColorF; #[allow(dead_code)] pub struct ProfileScope { @@ -26,12 +25,9 @@ impl ProfileScope { impl Drop for ProfileScope { fn drop(&mut self) { - /* - if self.name.chars().next() != Some(' ') { let t1 = precise_time_ns(); let ms = (t1 - self.t0) as f64 / 1000000f64; println!("{} {}", self.name, ms); - }*/ } } @@ -88,6 +84,8 @@ impl MatrixHelpers for Matrix4D { pub trait RectHelpers { fn from_points(a: &Point2D, b: &Point2D, c: &Point2D, d: &Point2D) -> Self; fn contains_rect(&self, other: &Rect) -> bool; + fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Rect; + fn is_well_formed_and_nonempty(&self) -> bool; } impl RectHelpers for Rect { @@ -119,78 +117,14 @@ impl RectHelpers for Rect { self.max_x() >= other.max_x() && self.max_y() >= other.max_y() } -} - -pub fn lerp(a: f32, b: f32, t: f32) -> f32 { - (b - a) * t + a -} - -pub fn bilerp(point: &Point2D, quad: &Rect, varyings: &V) -> V::Element - where V: RectVaryings, V::Element: VaryingElement { - let (x1, y1, x2, y2) = (quad.origin.x, quad.origin.y, quad.max_x(), quad.max_y()); - let top_left = varyings.top_left().scale((x2 - point.x) * (y2 - point.y)); - let top_right = varyings.top_right().scale((point.x - x1) * (y2 - point.y)); - let bottom_left = varyings.bottom_left().scale((x2 - point.x) * (point.y - y1)); - let bottom_right = varyings.bottom_right().scale((point.x - x1) * (point.y - y1)); - let sum = VaryingElement::accumulate(&[top_left, top_right, bottom_left, bottom_right]); - sum.scale(1.0 / ((x2 - x1) * (y2 - y1))) -} - -pub fn bilerp_rect(clipped_rect: &Rect, quad: &Rect, varyings: &V) -> V - where V: RectVaryings, V::Element: VaryingElement { - let top_left = bilerp(&clipped_rect.origin, quad, varyings); - let top_right = bilerp(&clipped_rect.top_right(), quad, varyings); - let bottom_right = bilerp(&clipped_rect.bottom_right(), quad, varyings); - let bottom_left = bilerp(&clipped_rect.bottom_left(), quad, varyings); - V::from_elements(&[top_left, top_right, bottom_right, bottom_left]) -} -pub trait RectVaryings { - type Element; - fn top_left(&self) -> Self::Element; - fn top_right(&self) -> Self::Element; - fn bottom_right(&self) -> Self::Element; - fn bottom_left(&self) -> Self::Element; - fn from_elements(elements: &[Self::Element; 4]) -> Self; -} - -impl RectVaryings for RectColors { - type Element = ColorF; - fn top_left(&self) -> ColorF { self.top_left } - fn top_right(&self) -> ColorF { self.top_right } - fn bottom_right(&self) -> ColorF { self.bottom_right } - fn bottom_left(&self) -> ColorF { self.bottom_left } - fn from_elements(elements: &[ColorF; 4]) -> RectColors { - RectColors { - top_left: elements[0], - top_right: elements[1], - bottom_right: elements[2], - bottom_left: elements[3], - } + fn from_floats(x0: f32, y0: f32, x1: f32, y1: f32) -> Rect { + Rect::new(Point2D::new(x0, y0), + Size2D::new(x1 - x0, y1 - y0)) } -} -pub trait VaryingElement : Sized { - fn scale(&self, factor: f32) -> Self; - fn accumulate(values: &[Self; 4]) -> Self; -} - -impl VaryingElement for ColorF { - fn scale(&self, factor: f32) -> ColorF { - ColorF { - r: self.r * factor, - g: self.g * factor, - b: self.b * factor, - a: self.a * factor, - } - } - fn accumulate(values: &[ColorF; 4]) -> ColorF { - ColorF { - r: values[0].r + values[1].r + values[2].r + values[3].r, - g: values[0].g + values[1].g + values[2].g + values[3].g, - b: values[0].b + values[1].b + values[2].b + values[3].b, - a: values[0].a + values[1].a + values[2].a + values[3].a, - } + fn is_well_formed_and_nonempty(&self) -> bool { + self.size.width > 0.0 && self.size.height > 0.0 } } @@ -200,59 +134,78 @@ pub fn rect_is_empty(rect: &Rect) -> bool { rect.size.width == Zero::zero() || rect.size.height == Zero::zero() } -/// Returns true if the rectangle's width and height are both strictly positive and false -/// otherwise. -pub fn rect_is_well_formed_and_nonempty(rect: &Rect) -> bool { - rect.size.width > 0.0 && rect.size.height > 0.0 -} +/* +#[inline(always)] +pub fn rect_contains_rect(rect: &Rect, other: &Rect) -> bool { + rect.origin.x <= other.origin.x && + rect.origin.y <= other.origin.y && + rect.max_x() >= other.max_x() && + rect.max_y() >= other.max_y() +}*/ -/// Multiplies all non-alpha components of a color by the given value. -pub fn scale_color(color: &ColorF, factor: f32) -> ColorF { - ColorF { - r: color.r * factor, - g: color.g * factor, - b: color.b * factor, - a: color.a, - } +#[inline(always)] +pub fn rect_contains_rect(rect: &Rect, other: &Rect) -> bool { + rect.origin.x <= other.origin.x && + rect.origin.y <= other.origin.y && + rect.max_x() >= other.max_x() && + rect.max_y() >= other.max_y() } -/// Subdivides a rectangle into quadrants formed by a point. The quadrants are returned in the -/// order of: top left, top right, bottom right, and bottom left. -pub fn subdivide_rect_into_quadrants(rect: &Rect, point: &Point2D) -> (Rect, Rect, Rect, Rect) { - let point = Point2D::new(clamp(point.x, rect.origin.x, rect.max_x()), - clamp(point.y, rect.origin.y, rect.max_y())); - let tl_rect = Rect::new(rect.origin, - Size2D::new(point.x - rect.origin.x, point.y - rect.origin.y)); - let tr_rect = Rect::new(Point2D::new(point.x, rect.origin.y), - Size2D::new(rect.max_x() - point.x, point.y - rect.origin.y)); - let br_rect = Rect::new(point, - Size2D::new(rect.max_x() - point.x, rect.max_y() - point.y)); - let bl_rect = Rect::new(Point2D::new(rect.origin.x, point.y), - Size2D::new(point.x - rect.origin.x, rect.max_y() - point.y)); - return (tl_rect, tr_rect, br_rect, bl_rect); - - fn clamp(x: f32, lo: f32, hi: f32) -> f32 { - if x < lo { - lo - } else if x > hi { - hi - } else { - x - } - } +#[inline] +pub fn rect_from_points(x0: DevicePixel, + y0: DevicePixel, + x1: DevicePixel, + y1: DevicePixel) -> Rect { + Rect::new(Point2D::new(x0, y0), + Size2D::new(x1 - x0, y1 - y0)) } -/// Returns the center point of the given rect. -pub fn rect_center(rect: &Rect) -> Point2D { - Point2D::new(rect.origin.x + rect.size.width / 2.0, rect.origin.y + rect.size.height / 2.0) +#[inline] +pub fn rect_from_points_f(x0: f32, + y0: f32, + x1: f32, + y1: f32) -> Rect { + Rect::new(Point2D::new(x0, y0), + Size2D::new(x1 - x0, y1 - y0)) } -pub fn distance(a: &Point2D, b: &Point2D) -> f32 { - let (x, y) = (b.x - a.x, b.y - a.y); - (x * x + y * y).sqrt() +pub fn lerp(a: f32, b: f32, t: f32) -> f32 { + (b - a) * t + a } -pub fn lerp_points(a: &Point2D, b: &Point2D, t: f32) -> Point2D { - Point2D::new(lerp(a.x, b.x, t), lerp(a.y, b.y, t)) -} +pub fn subtract_rect(rect: &Rect, + other: &Rect, + results: &mut Vec>) { + results.clear(); + + if rect.intersects(other) { + let rx0 = rect.origin.x; + let ry0 = rect.origin.y; + let rx1 = rx0 + rect.size.width; + let ry1 = ry0 + rect.size.height; + let ox0 = other.origin.x; + let oy0 = other.origin.y; + let ox1 = ox0 + other.size.width; + let oy1 = oy0 + other.size.height; + + let r = rect_from_points_f(rx0, ry0, ox0, ry1); + if r.size.width > 0.0 && r.size.height > 0.0 { + results.push(r); + } + let r = rect_from_points_f(ox0, ry0, ox1, oy0); + if r.size.width > 0.0 && r.size.height > 0.0 { + results.push(r); + } + let r = rect_from_points_f(ox0, oy1, ox1, ry1); + if r.size.width > 0.0 && r.size.height > 0.0 { + results.push(r); + } + let r = rect_from_points_f(ox1, ry0, rx1, ry1); + if r.size.width > 0.0 && r.size.height > 0.0 { + results.push(r); + } + } else { + results.push(*rect); + } +} \ No newline at end of file From a3c06089474fea2d4e7aace6fb12f6ec9b60176e Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 15 Jul 2016 16:06:22 -0700 Subject: [PATCH 02/33] Pack image stretch size in image primitive --- src/tiling.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tiling.rs b/src/tiling.rs index c3739af081..95fa694f69 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -631,6 +631,7 @@ struct BorderPrimitive { struct ImagePrimitive { image_key: ImageKey, image_rendering: ImageRendering, + stretch_size: Size2D, } #[derive(Debug)] @@ -770,6 +771,8 @@ impl Primitive { local_rect: self.rect, st0: uv_rect.top_left, st1: uv_rect.bottom_right, + stretch_size: details.stretch_size, + padding: [0, 0], }); true @@ -1120,6 +1123,7 @@ impl CompositeBatchKey { } } +// All Pcked Primitives below must be 16 byte aligned. #[derive(Debug)] pub struct PackedTile { actual_rect: Rect, @@ -1192,6 +1196,8 @@ pub struct PackedImagePrimitive { local_rect: Rect, st0: Point2D, st1: Point2D, + stretch_size: Size2D, + padding: [u32; 2], } #[derive(Debug, Clone)] @@ -1874,12 +1880,13 @@ impl FrameBuilder { rect: Rect, clip_rect: &Rect, clip: Option>, - _stretch_size: &Size2D, + stretch_size: &Size2D, image_key: ImageKey, image_rendering: ImageRendering) { let prim = ImagePrimitive { image_key: image_key, image_rendering: image_rendering, + stretch_size: stretch_size.clone(), }; self.add_primitive(&rect, From 8ffc51fea194a36d9ea7f8a313efa72742f3f70f Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 15 Jul 2016 16:07:24 -0700 Subject: [PATCH 03/33] fix a typo --- src/tiling.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tiling.rs b/src/tiling.rs index 95fa694f69..032ad20d64 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -1123,7 +1123,7 @@ impl CompositeBatchKey { } } -// All Pcked Primitives below must be 16 byte aligned. +// All Packed Primitives below must be 16 byte aligned. #[derive(Debug)] pub struct PackedTile { actual_rect: Rect, From c499a3e7101f4cb002310ed8e6b7c395cc2ddaf8 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Mon, 18 Jul 2016 10:12:13 +1000 Subject: [PATCH 04/33] Fix various reftests. --- src/frame.rs | 8 +++++- src/texture_cache.rs | 3 ++- src/tiling.rs | 46 +++++++++++++++++++++++++++-------- src/util.rs | 58 +++++++++++++++++++++++--------------------- 4 files changed, 76 insertions(+), 39 deletions(-) diff --git a/src/frame.rs b/src/frame.rs index 8179550987..f9d0fad623 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -679,6 +679,12 @@ impl Frame { } }; + // TODO(gw): This is broken for 3d transforms ref test. + // Removing it fixes that but it needs a proper solution before + // merging which will coming when the clipping branch merges! + + let local_clip_rect = Some(MAX_RECT); + /* // FIXME(pcwalton): This is a not-great partial solution to servo/servo#10164. A better // solution would be to do this only if the transform consists of a translation+scale only // and fall back to stenciling if the object has a more complex transform. @@ -699,7 +705,7 @@ impl Frame { .translate(&-stacking_context.bounds.origin) .intersection(&stacking_context.overflow) } - }; + };*/ if let Some(local_clip_rect) = local_clip_rect { let scene_items = scene_item.collect_scene_items(&context.scene); diff --git a/src/texture_cache.rs b/src/texture_cache.rs index e2bcc9031a..923fdf2232 100644 --- a/src/texture_cache.rs +++ b/src/texture_cache.rs @@ -681,7 +681,8 @@ impl TextureCache { user_x0, user_y0, Rect::new(Point2D::zero(), requested_size), Rect::new(Point2D::zero(), requested_size), - &requested_size); + &requested_size, + is_opaque); *self.items.get_mut(image_id) = cache_item; return AllocationResult { diff --git a/src/tiling.rs b/src/tiling.rs index 032ad20d64..2c09bbebfa 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -389,8 +389,7 @@ impl RenderTask { let alloc_size = Size2D::new(size.width.0 as u32, size.height.0 as u32); - let alloc_origin = target.page_allocator - .allocate(&alloc_size, TextureFilter::Linear); + let alloc_origin = target.page_allocator.allocate(&alloc_size); match alloc_origin { Some(alloc_origin) => { @@ -755,9 +754,11 @@ impl Primitive { ctx.frame_id); let uv_rect = image_info.uv_rect(); - // TODO(gw): Need a general solution to handle multiple texture pages per tile in WR2! - assert!(batch.color_texture_id == TextureId(0) || - batch.color_texture_id == image_info.texture_id); + // TODO(gw): Tidy the support for batch breaks up... + if batch.color_texture_id != TextureId(0) && + batch.color_texture_id != image_info.texture_id { + return false; + } batch.color_texture_id = image_info.texture_id; data.push(PackedImagePrimitive { @@ -1001,7 +1002,16 @@ impl Primitive { (&mut PrimitiveBatchData::Gradient(..), _) => false, (&mut PrimitiveBatchData::BoxShadows(ref mut data), &PrimitiveDetails::BoxShadow(ref details)) => { let mut rects = Vec::new(); - subtract_rect(&self.rect, &details.src_rect, &mut rects); + let inverted = match details.clip_mode { + BoxShadowClipMode::None | BoxShadowClipMode::Outset => { + subtract_rect(&self.rect, &details.src_rect, &mut rects); + 0.0 + } + BoxShadowClipMode::Inset => { + subtract_rect(&self.rect, &details.bs_rect, &mut rects); + 1.0 + } + }; for rect in rects { data.push(PackedBoxShadowPrimitive { @@ -1017,7 +1027,7 @@ impl Primitive { border_radii: Point2D::new(details.border_radius, details.border_radius), blur_radius: details.blur_radius, - inverted: 0.0, + inverted: inverted, bs_rect: details.bs_rect, src_rect: details.src_rect, }); @@ -1847,6 +1857,15 @@ impl FrameBuilder { return } + // Fast path. + if blur_radius == 0.0 && spread_radius == 0.0 && clip_mode == BoxShadowClipMode::None { + self.add_solid_rectangle(&box_bounds, + clip_rect, + None, + color); + return; + } + let bs_rect = compute_box_shadow_rect(box_bounds, box_offset, spread_radius); @@ -1855,9 +1874,16 @@ impl FrameBuilder { border_radius, blur_radius); - let prim_rect = Rect::new(metrics.tl_outer, - Size2D::new(metrics.br_outer.x - metrics.tl_outer.x, - metrics.br_outer.y - metrics.tl_outer.y)); + let prim_rect = match clip_mode { + BoxShadowClipMode::Outset | BoxShadowClipMode::None => { + Rect::new(metrics.tl_outer, + Size2D::new(metrics.br_outer.x - metrics.tl_outer.x, + metrics.br_outer.y - metrics.tl_outer.y)) + } + BoxShadowClipMode::Inset => { + *box_bounds + } + }; let prim = BoxShadowPrimitive { metrics: metrics, diff --git a/src/util.rs b/src/util.rs index 01f4fbf134..ea30c8883c 100644 --- a/src/util.rs +++ b/src/util.rs @@ -178,34 +178,38 @@ pub fn subtract_rect(rect: &Rect, results: &mut Vec>) { results.clear(); - if rect.intersects(other) { - let rx0 = rect.origin.x; - let ry0 = rect.origin.y; - let rx1 = rx0 + rect.size.width; - let ry1 = ry0 + rect.size.height; - - let ox0 = other.origin.x; - let oy0 = other.origin.y; - let ox1 = ox0 + other.size.width; - let oy1 = oy0 + other.size.height; - - let r = rect_from_points_f(rx0, ry0, ox0, ry1); - if r.size.width > 0.0 && r.size.height > 0.0 { - results.push(r); - } - let r = rect_from_points_f(ox0, ry0, ox1, oy0); - if r.size.width > 0.0 && r.size.height > 0.0 { - results.push(r); - } - let r = rect_from_points_f(ox0, oy1, ox1, ry1); - if r.size.width > 0.0 && r.size.height > 0.0 { - results.push(r); + let int = rect.intersection(other); + match int { + Some(int) => { + let rx0 = rect.origin.x; + let ry0 = rect.origin.y; + let rx1 = rx0 + rect.size.width; + let ry1 = ry0 + rect.size.height; + + let ox0 = int.origin.x; + let oy0 = int.origin.y; + let ox1 = ox0 + int.size.width; + let oy1 = oy0 + int.size.height; + + let r = rect_from_points_f(rx0, ry0, ox0, ry1); + if r.size.width > 0.0 && r.size.height > 0.0 { + results.push(r); + } + let r = rect_from_points_f(ox0, ry0, ox1, oy0); + if r.size.width > 0.0 && r.size.height > 0.0 { + results.push(r); + } + let r = rect_from_points_f(ox0, oy1, ox1, ry1); + if r.size.width > 0.0 && r.size.height > 0.0 { + results.push(r); + } + let r = rect_from_points_f(ox1, ry0, rx1, ry1); + if r.size.width > 0.0 && r.size.height > 0.0 { + results.push(r); + } } - let r = rect_from_points_f(ox1, ry0, rx1, ry1); - if r.size.width > 0.0 && r.size.height > 0.0 { - results.push(r); + None => { + results.push(*rect); } - } else { - results.push(*rect); } } \ No newline at end of file From 21d5ffb5e6d06acd0b4cfc3742650769664a983d Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Tue, 19 Jul 2016 15:50:45 -0700 Subject: [PATCH 05/33] Pass border style data to the GPU --- src/tiling.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-) diff --git a/src/tiling.rs b/src/tiling.rs index 2c09bbebfa..7503f053da 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -22,7 +22,7 @@ use std::hash::{BuildHasherDefault}; use texture_cache::{TexturePage, TextureCacheItem}; use util::{self, rect_from_points, rect_from_points_f, MatrixHelpers, subtract_rect, RectHelpers, rect_contains_rect}; use webrender_traits::{ColorF, FontKey, ImageKey, ImageRendering, ComplexClipRegion}; -use webrender_traits::{BorderDisplayItem, BorderStyle, ItemRange, AuxiliaryLists, BorderRadius}; +use webrender_traits::{BorderDisplayItem, BorderStyle, ItemRange, AuxiliaryLists, BorderRadius, BorderSide}; use webrender_traits::{BoxShadowClipMode, PipelineId, ScrollLayerId}; struct RenderTargetContext<'a> { @@ -624,6 +624,10 @@ struct BorderPrimitive { top_color: ColorF, right_color: ColorF, bottom_color: ColorF, + left_style: BorderStyle, + top_style: BorderStyle, + right_style: BorderStyle, + bottom_style: BorderStyle, } #[derive(Debug)] @@ -813,6 +817,10 @@ impl Primitive { outer_radius_y: details.radius.top_left.height, inner_radius_x: inner_radius.top_left.width, inner_radius_y: inner_radius.top_left.height, + top_style: details.top_style as u32, + right_style: details.right_style as u32, + bottom_style: details.bottom_style as u32, + left_style: details.bottom_style as u32, }); data.push(PackedBorderPrimitive { @@ -833,6 +841,10 @@ impl Primitive { outer_radius_y: details.radius.top_right.height, inner_radius_x: inner_radius.top_right.width, inner_radius_y: inner_radius.top_right.height, + top_style: details.top_style as u32, + right_style: details.right_style as u32, + bottom_style: details.bottom_style as u32, + left_style: details.bottom_style as u32, }); data.push(PackedBorderPrimitive { @@ -853,6 +865,10 @@ impl Primitive { outer_radius_y: details.radius.bottom_left.height, inner_radius_x: inner_radius.bottom_left.width, inner_radius_y: inner_radius.bottom_left.height, + top_style: details.top_style as u32, + right_style: details.right_style as u32, + bottom_style: details.bottom_style as u32, + left_style: details.bottom_style as u32, }); data.push(PackedBorderPrimitive { @@ -873,6 +889,10 @@ impl Primitive { outer_radius_y: details.radius.bottom_right.height, inner_radius_x: inner_radius.bottom_right.width, inner_radius_y: inner_radius.bottom_right.height, + top_style: details.top_style as u32, + right_style: details.right_style as u32, + bottom_style: details.bottom_style as u32, + left_style: details.bottom_style as u32, }); data.push(PackedBorderPrimitive { @@ -893,6 +913,10 @@ impl Primitive { outer_radius_y: 0.0, inner_radius_x: 0.0, inner_radius_y: 0.0, + top_style: details.top_style as u32, + right_style: details.right_style as u32, + bottom_style: details.bottom_style as u32, + left_style: details.bottom_style as u32, }); data.push(PackedBorderPrimitive { @@ -913,6 +937,10 @@ impl Primitive { outer_radius_y: 0.0, inner_radius_x: 0.0, inner_radius_y: 0.0, + top_style: details.top_style as u32, + right_style: details.right_style as u32, + bottom_style: details.bottom_style as u32, + left_style: details.bottom_style as u32, }); data.push(PackedBorderPrimitive { @@ -933,6 +961,10 @@ impl Primitive { outer_radius_y: 0.0, inner_radius_x: 0.0, inner_radius_y: 0.0, + top_style: details.top_style as u32, + right_style: details.right_style as u32, + bottom_style: details.bottom_style as u32, + left_style: details.bottom_style as u32, }); data.push(PackedBorderPrimitive { @@ -953,6 +985,10 @@ impl Primitive { outer_radius_y: 0.0, inner_radius_x: 0.0, inner_radius_y: 0.0, + top_style: details.top_style as u32, + right_style: details.right_style as u32, + bottom_style: details.bottom_style as u32, + left_style: details.bottom_style as u32, }); true @@ -1230,6 +1266,10 @@ pub struct PackedBorderPrimitive { outer_radius_y: f32, inner_radius_x: f32, inner_radius_y: f32, + top_style: u32, + right_style: u32, + bottom_style: u32, + left_style: u32, } #[derive(Debug, Clone)] @@ -1714,6 +1754,20 @@ impl FrameBuilder { PrimitiveDetails::Rectangle(prim)); } + pub fn supported_style(&mut self, border: &BorderSide) -> bool { + match border.style { + BorderStyle::Solid | + BorderStyle::None | + BorderStyle::Dotted => { + return true; + } + _ => { + println!("TODO: Other border styles {:?}", border.style); + return false; + } + } + } + pub fn add_border(&mut self, rect: Rect, clip_rect: &Rect, @@ -1725,11 +1779,9 @@ impl FrameBuilder { let top = &border.top; let bottom = &border.bottom; - if (left.style != BorderStyle::Solid && left.style != BorderStyle::None) || - (top.style != BorderStyle::Solid && top.style != BorderStyle::None) || - (bottom.style != BorderStyle::Solid && bottom.style != BorderStyle::None) || - (right.style != BorderStyle::Solid && right.style != BorderStyle::None) { - println!("TODO: Other border styles {:?} {:?} {:?} {:?}", left.style, top.style, bottom.style, right.style); + if !self.supported_style(left) || !self.supported_style(right) || + !self.supported_style(top) || !self.supported_style(bottom) { + println!("Unsupported border style, not rendering border"); return; } @@ -1750,6 +1802,7 @@ impl FrameBuilder { let br_inner = br_outer - Point2D::new(radius.bottom_right.width.max(right.width), radius.bottom_right.height.max(bottom.width)); + // These don't seem to do anything right now. let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7); let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7); let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3); @@ -1773,6 +1826,10 @@ impl FrameBuilder { top_color: top_color, bottom_color: bottom_color, right_color: right_color, + left_style: left.style, + top_style: top.style, + right_style: right.style, + bottom_style: bottom.style, }; self.add_primitive(&rect, From 7448a58222b29ae143d2b41ce0168c5245a862d3 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Sat, 23 Jul 2016 08:26:58 +1000 Subject: [PATCH 06/33] Add various features and fixes for mozilla reftests. --- src/aabbtree.rs | 216 ----- src/bsptree.rs | 318 -------- src/cache_shared.glsl | 0 src/frame.rs | 70 +- src/internal_types.rs | 14 +- src/kdtree.rs | 4 - src/lib.rs | 4 - src/quadtree.rs | 222 ------ src/render_backend.rs | 2 +- src/renderer.rs | 246 ++++-- src/resource_cache.rs | 2 - src/resource_list.rs | 10 +- src/texture_cache.rs | 2 +- src/tiling.rs | 1759 +++++++++++++++++++++++++---------------- src/util.rs | 17 - 15 files changed, 1276 insertions(+), 1610 deletions(-) delete mode 100644 src/aabbtree.rs delete mode 100644 src/bsptree.rs delete mode 100644 src/cache_shared.glsl delete mode 100644 src/kdtree.rs delete mode 100644 src/quadtree.rs diff --git a/src/aabbtree.rs b/src/aabbtree.rs deleted file mode 100644 index 116c00b63e..0000000000 --- a/src/aabbtree.rs +++ /dev/null @@ -1,216 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* -use euclid::{Point2D, Rect, Size2D}; -use internal_types::{CompiledNode, DrawListGroupId, DrawListId, DrawListItemIndex}; -use resource_list::ResourceList; -use util; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct NodeIndex(pub u32); - -pub struct AABBTreeNode { - pub split_rect: Rect, - pub actual_rect: Rect, - pub primitives: Vec, - // TODO: Use Option + NonZero here - pub children: Option, -} - -impl AABBTreeNode { - fn new(split_rect: &Rect) -> AABBTreeNode { - AABBTreeNode { - split_rect: split_rect.clone(), - actual_rect: Rect::zero(), - primitives: Vec::new(), - children: None, - } - } - - #[inline] - fn append_item(&mut self, prim_index: PrimitiveIndex, rect: &Rect) { - debug_assert!(self.split_rect.intersects(rect)); - - self.actual_rect = self.actual_rect.union(rect); - self.primitives.push(prim_index); - } -} - -pub struct AABBTree { - pub nodes: Vec, - pub split_size: f32, - work_node_indices: Vec, -} - -impl AABBTree { - pub fn new(split_size: f32, - local_bounds: &Rect) -> AABBTree { - let mut tree = AABBTree { - nodes: Vec::new(), - split_size: split_size, - work_node_indices: Vec::new(), - }; - - let root_node = AABBTreeNode::new(local_bounds); - tree.nodes.push(root_node); - - tree - } - - #[allow(dead_code)] - pub fn print(&self, node_index: NodeIndex, level: u32) { - let mut indent = String::new(); - for _ in 0..level { - indent.push_str(" "); - } - - let node = self.node(node_index); - println!("{}n={:?} sr={:?} ar={:?} c={:?}", - indent, - node_index, - node.split_rect, - node.actual_rect, - node.children); - - if let Some(child_index) = node.children { - let NodeIndex(child_index) = child_index; - self.print(NodeIndex(child_index+0), level+1); - self.print(NodeIndex(child_index+1), level+1); - } - } - - #[inline(always)] - pub fn node(&self, index: NodeIndex) -> &AABBTreeNode { - let NodeIndex(index) = index; - &self.nodes[index as usize] - } - - #[inline(always)] - pub fn node_mut(&mut self, index: NodeIndex) -> &mut AABBTreeNode { - let NodeIndex(index) = index; - &mut self.nodes[index as usize] - } - - #[inline] - fn find_best_nodes(&mut self, - node_index: NodeIndex, - rect: &Rect) { - self.split_if_needed(node_index); - - if let Some(child_node_index) = self.node(node_index).children { - let NodeIndex(child_node_index) = child_node_index; - let left_node_index = NodeIndex(child_node_index + 0); - let right_node_index = NodeIndex(child_node_index + 1); - - let left_intersect = self.node(left_node_index).split_rect.intersects(rect); - if left_intersect { - self.find_best_nodes(left_node_index, rect); - } - - let right_intersect = self.node(right_node_index).split_rect.intersects(rect); - if right_intersect { - self.find_best_nodes(right_node_index, rect); - } - } else { - self.work_node_indices.push(node_index); - } - } - - #[inline] - pub fn insert(&mut self, rect: Rect, prim_index: PrimitiveIndex) { - self.find_best_nodes(NodeIndex(0), &rect); - if self.work_node_indices.is_empty() { - // TODO(gw): If this happens, it it probably caused by items having - // transforms that move them outside the local overflow. According - // to the transforms spec, the stacking context overflow should - // include transformed elements, however this isn't currently - // handled by the layout code! If it's not that, this is an - // unexpected condition and should be investigated! - debug!("WARNING: insert rect {:?} outside bounds, dropped.", rect); - self.work_node_indices.clear(); - } else { - 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(prim_index, &rect); - } - } - } - - fn split_if_needed(&mut self, node_index: NodeIndex) { - if self.node(node_index).children.is_none() { - let rect = self.node(node_index).split_rect.clone(); - - let child_rects = if rect.size.width > self.split_size && - rect.size.width > rect.size.height { - let new_width = rect.size.width * 0.5; - - let left = Rect::new(rect.origin, Size2D::new(new_width, rect.size.height)); - let right = Rect::new(rect.origin + Point2D::new(new_width, 0.0), - Size2D::new(rect.size.width - new_width, rect.size.height)); - - Some((left, right)) - } else if rect.size.height > self.split_size { - let new_height = rect.size.height * 0.5; - - let left = Rect::new(rect.origin, Size2D::new(rect.size.width, new_height)); - let right = Rect::new(rect.origin + Point2D::new(0.0, new_height), - Size2D::new(rect.size.width, rect.size.height - new_height)); - - Some((left, right)) - } else { - None - }; - - if let Some((left_rect, right_rect)) = child_rects { - let child_node_index = self.nodes.len() as u32; - - let left_node = AABBTreeNode::new(&left_rect); - self.nodes.push(left_node); - - let right_node = AABBTreeNode::new(&right_rect); - self.nodes.push(right_node); - - self.node_mut(node_index).children = Some(NodeIndex(child_node_index)); - } - } - } - -/* - fn check_node_visibility(&self, - node_index: NodeIndex, - rect: &Rect, - vis_prims: &mut Vec) { - let children = { - let node = self.node(node_index); - if node.split_rect.intersects(rect) { - if !node.primitives.is_empty() && - node.actual_rect.intersects(rect) { - //node.is_visible = true; - vis_prims.extend_from_slice(&node.primitives); - } - node.children - } else { - return; - } - }; - - if let Some(child_index) = children { - let NodeIndex(child_index) = child_index; - self.check_node_visibility(NodeIndex(child_index+0), rect, vis_prims); - self.check_node_visibility(NodeIndex(child_index+1), rect, vis_prims); - } - } - - pub fn vis_query(&self, rect: &Rect) -> Vec { - debug_assert!(self.state == TreeState::Finalized); - let mut vis_prims = Vec::new(); - if !self.nodes.is_empty() { - self.check_node_visibility(NodeIndex(0), &rect, &mut vis_prims); - } - vis_prims - }*/ -} -*/ diff --git a/src/bsptree.rs b/src/bsptree.rs deleted file mode 100644 index be9b2c8f3e..0000000000 --- a/src/bsptree.rs +++ /dev/null @@ -1,318 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -use euclid::{Point2D, Rect}; -use internal_types::DevicePixel; -use std::i32; -use std::mem; -use util::{rect_contains_rect, rect_from_points}; - -// TODO(gw): Support enum type for rect that can be axis-aligned or a (projected) polygon. - -#[derive(Debug, Copy, Clone)] -struct BspNodeIndex(usize); - -#[derive(Debug, Copy, Clone)] -struct BspItemIndex(usize); - -#[derive(Debug, Copy, Clone)] -enum SplitKind { - Horizontal, - Vertical, -} - -pub struct BspItem { - rect: Rect, - pub data: T, -} - -pub struct BspNode { - rect: Rect, - cover_items: Vec, - partial_items: Vec, - child_index: Option, -} - -impl BspNode { - fn new(rect: Rect) -> BspNode { - BspNode { - rect: rect, - cover_items: Vec::new(), - partial_items: Vec::new(), - child_index: None, - } - } - - fn new_with_capacity(rect: Rect, capacity: usize) -> BspNode { - BspNode { - rect: rect, - cover_items: Vec::with_capacity(capacity), - partial_items: Vec::with_capacity(capacity), - child_index: None, - } - } - - fn add(&mut self, rect: &Rect, item_index: BspItemIndex) { - debug_assert!(self.rect.intersects(rect)); - if rect_contains_rect(rect, &self.rect) { - self.cover_items.push(item_index); - } else { - self.partial_items.push(item_index); - } - } -} - -pub struct BspTree { - nodes: Vec, - pub items: Vec>, -} - -impl BspTree { - pub fn new(bounding_rect: Rect) -> BspTree { - let root = BspNode::new(bounding_rect); - - BspTree { - nodes: vec![root], - items: Vec::new(), - } - } - - #[inline(always)] - fn node(&self, node_index: BspNodeIndex) -> &BspNode { - let BspNodeIndex(node_index) = node_index; - &self.nodes[node_index] - } - - #[inline(always)] - fn node_mut(&mut self, node_index: BspNodeIndex) -> &mut BspNode { - let BspNodeIndex(node_index) = node_index; - &mut self.nodes[node_index] - } - - pub fn add(&mut self, - rect: &Rect, - data: T) { - let item_index = BspItemIndex(self.items.len()); - self.items.push(BspItem { - rect: *rect, - data: data, - }); - let root = self.node_mut(BspNodeIndex(0)); - root.add(rect, item_index); - } - - fn split_internal(&mut self, - node_index: BspNodeIndex, - split_kind: SplitKind, - level: i32, - current_cover_items: &Vec, - cover_buffer: &mut Vec, - partial_buffer: &mut Vec, - device_pixel_ratio: f32, - f: &mut F) where F: FnMut(&Rect, &mut Vec, &mut Vec) { - let mut partial_items = mem::replace(&mut self.node_mut(node_index) - .partial_items, - Vec::new()); - - // TODO(gw): Optimize this by making cover items a stack! - let mut current_cover_items = current_cover_items.clone(); - for item_index in &self.node(node_index).cover_items { - let BspItemIndex(item_index) = *item_index; - let item = &self.items[item_index]; - current_cover_items.push(item.data); - } - - let node_rect = self.node(node_index).rect; - let mut do_split = true; - - if partial_items.is_empty() { - do_split = false; - } - - let min_size = 8; - if node_rect.size.width.0 <= min_size && - node_rect.size.height.0 <= min_size { - do_split = false; - } - - let min_area = 64 * 64; - if node_rect.size.width.0 * node_rect.size.height.0 <= min_area && - partial_items.len() > 2 && - partial_items.len() + current_cover_items.len() < 8 { - do_split = false; - } - - if !do_split { - let node = self.node(node_index); - - cover_buffer.clear(); - for item in ¤t_cover_items { - cover_buffer.push(*item); - } - - partial_buffer.clear(); - for item_index in &partial_items { - let BspItemIndex(item_index) = *item_index; - let item = &self.items[item_index]; - partial_buffer.push(item.data); - } - - f(&node_rect, cover_buffer, partial_buffer); - return; - } - - // Sort by split kind, find median. - // TODO(gw): Find a faster heuristic for splitting that gives good results? - let nx0 = node_rect.origin.x; - let ny0 = node_rect.origin.y; - let nx1 = nx0 + node_rect.size.width; - let ny1 = ny0 + node_rect.size.height; - - //let mut indent = String::new(); - //for _ in 0..level { - // indent.push_str(" "); - //} - - let cx = ((nx0.0 as f32 + nx1.0 as f32) * 0.5).round() as i32; - let cy = ((ny0.0 as f32 + ny1.0 as f32) * 0.5).round() as i32; - let center = Point2D::new(DevicePixel::from_i32(cx), DevicePixel::from_i32(cy)); - let mut best_distance = Point2D::new(i32::MAX, i32::MAX); - let mut split_pos = center; - - for item_index in &partial_items { - let BspItemIndex(item_index) = *item_index; - let item = &self.items[item_index]; - - // Only a valid split point if it sits exactly on a device pixel! - let x0 = item.rect.origin.x; - let x1 = x0 + item.rect.size.width; - - if x0 > nx0 && x0 < nx1 { - let d = (x0.0 - center.x.0).abs(); - if d < best_distance.x { - best_distance.x = d; - split_pos.x = x0; - } - } - if x1 > nx0 && x1 < nx1 { - let d = (x1.0 - center.x.0).abs(); - if d < best_distance.x { - best_distance.x = d; - split_pos.x = x1; - } - } - - let y0 = item.rect.origin.y; - let y1 = y0 + item.rect.size.height; - - if y0 > ny0 && y0 < ny1 { - let d = (y0.0 - center.y.0).abs(); - if d < best_distance.y { - best_distance.y = d; - split_pos.y = y0; - } - } - if y1 > ny0 && y1 < ny1 { - let d = (y1.0 - center.y.0).abs(); - if d < best_distance.y { - best_distance.y = d; - split_pos.y = y1; - } - } - } - - let (split_kind, split) = match split_kind { - SplitKind::Horizontal => { - if best_distance.y < i32::MAX { - (SplitKind::Horizontal, split_pos.y) - } else { - debug_assert!(best_distance.x != i32::MAX); - (SplitKind::Vertical, split_pos.x) - } - } - SplitKind::Vertical => { - if best_distance.x < i32::MAX { - (SplitKind::Vertical, split_pos.x) - } else { - debug_assert!(best_distance.y != i32::MAX); - (SplitKind::Horizontal, split_pos.y) - } - } - }; - - let (c0, c1, next_split) = match split_kind { - SplitKind::Horizontal => { - let r0 = rect_from_points(nx0, ny0, nx1, split); - let r1 = rect_from_points(nx0, split, nx1, ny1); - let mut c0 = BspNode::new_with_capacity(r0, partial_items.len()); - let mut c1 = BspNode::new_with_capacity(r1, partial_items.len()); - for key in partial_items.drain(..) { - let BspItemIndex(i) = key; - let item_rect = &self.items[i].rect; - if item_rect.origin.y < split { - c0.add(item_rect, key); - } - if item_rect.origin.y + item_rect.size.height > split { - c1.add(item_rect, key); - } - } - (c0, c1, SplitKind::Vertical) - } - SplitKind::Vertical => { - let r0 = rect_from_points(nx0, ny0, split, ny1); - let r1 = rect_from_points(split, ny0, nx1, ny1); - let mut c0 = BspNode::new_with_capacity(r0, partial_items.len()); - let mut c1 = BspNode::new_with_capacity(r1, partial_items.len()); - for key in partial_items.drain(..) { - let BspItemIndex(i) = key; - let item_rect = &self.items[i].rect; - if item_rect.origin.x < split { - c0.add(item_rect, key); - } - if item_rect.origin.x + item_rect.size.width > split { - c1.add(item_rect, key); - } - } - (c0, c1, SplitKind::Horizontal) - } - }; - - let ci0 = BspNodeIndex(self.nodes.len() + 0); - let ci1 = BspNodeIndex(self.nodes.len() + 1); - self.node_mut(node_index).child_index = Some(ci0); - self.nodes.push(c0); - self.nodes.push(c1); - self.split_internal(ci0, - next_split, - level+1, - ¤t_cover_items, - cover_buffer, - partial_buffer, - device_pixel_ratio, - f); - self.split_internal(ci1, - next_split, - level+1, - ¤t_cover_items, - cover_buffer, - partial_buffer, - device_pixel_ratio, - f); - } - - pub fn split(&mut self, - device_pixel_ratio: f32, - f: &mut F) where F: FnMut(&Rect, &mut Vec, &mut Vec) { - let mut cover_buffer = Vec::new(); - let mut partial_buffer = Vec::new(); - self.split_internal(BspNodeIndex(0), - SplitKind::Horizontal, - 0, - &Vec::new(), - &mut cover_buffer, - &mut partial_buffer, - device_pixel_ratio, - f); - } -} diff --git a/src/cache_shared.glsl b/src/cache_shared.glsl deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/frame.rs b/src/frame.rs index f9d0fad623..5e5bbd59da 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -7,13 +7,9 @@ use euclid::{Matrix4D, Point2D, Point3D, Point4D, Rect, Size2D}; use fnv::FnvHasher; use geometry::ray_intersects_rect; use internal_types::{ANGLE_FLOAT_TO_FIXED, AxisDirection}; -use internal_types::{ChildLayerIndex, ClearInfo}; -use internal_types::{CompositeBatchInfo, CompositeBatchJob, CompositionOp}; -use internal_types::{DrawCall}; -use internal_types::{DrawCompositeBatchJob, DrawListGroupId}; -use internal_types::{DrawListId, DrawListItemIndex, LowLevelFilterOp, MAX_RECT}; -use internal_types::{RenderTargetId, RendererFrame}; -use internal_types::{StackingContextInfo, StackingContextIndex}; +use internal_types::{CompositionOp}; +use internal_types::{LowLevelFilterOp, MAX_RECT}; +use internal_types::{RendererFrame}; use layer::{Layer, ScrollingState}; use resource_cache::ResourceCache; use scene::{SceneStackingContext, ScenePipeline, Scene, SceneItem, SpecificSceneItem}; @@ -224,7 +220,7 @@ impl Frame { } } - pub fn reset(&mut self, resource_cache: &mut ResourceCache) + pub fn reset(&mut self) -> HashMap> { self.pipeline_epoch_map.clear(); @@ -392,7 +388,7 @@ impl Frame { device_pixel_ratio: f32) { 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_scrolling_states = self.reset(resource_cache); + let old_layer_scrolling_states = self.reset(); self.pipeline_auxiliary_lists = scene.pipeline_auxiliary_lists.clone(); @@ -452,8 +448,7 @@ impl Frame { let root_pipeline = SceneItemKind::Pipeline(root_pipeline); self.flatten(root_pipeline, &parent_info, - &mut context, - 0); + &mut context); } self.frame_builder = Some(frame_builder); @@ -476,16 +471,15 @@ impl Frame { scene_items: &[SceneItem], info: &FlattenInfo, context: &mut FlattenContext, - _level: i32, sc_rect: Rect, - opacity: f32) { + composition_ops: Vec) { context.builder.push_layer(sc_rect, info.current_clip_rect, info.local_transform, - opacity, info.pipeline_id, info.actual_scroll_layer_id, - info.offset_from_current_layer); + info.offset_from_current_layer, + composition_ops); for item in scene_items { match item.specific { @@ -508,14 +502,11 @@ impl Frame { }; match item.item { - SpecificDisplayItem::WebGL(ref _info) => { - println!("TODO: WebGL"); - /* - builder.add_webgl_rectangle(&display_item.rect, - resource_cache, - &info.context_id, - frame_id); - */ + SpecificDisplayItem::WebGL(ref info) => { + builder.add_webgl_rectangle(item.rect, + &item.clip.main, + clip, + info.context_id); } SpecificDisplayItem::Image(ref info) => { builder.add_image(item.rect, @@ -578,8 +569,7 @@ impl Frame { let child = SceneItemKind::StackingContext(stacking_context, pipeline_id); self.flatten(child, info, - context, - _level+1); + context); } SpecificSceneItem::Iframe(ref iframe_info) => { let pipeline = context.scene @@ -646,8 +636,7 @@ impl Frame { self.flatten(iframe, &iframe_info, - context, - _level+1); + context); } } } @@ -659,8 +648,7 @@ impl Frame { fn flatten(&mut self, scene_item: SceneItemKind, parent_info: &FlattenInfo, - context: &mut FlattenContext, - level: i32) { + context: &mut FlattenContext) { //let _pf = util::ProfileScope::new(" flatten"); let (stacking_context, pipeline_id) = match scene_item { @@ -683,7 +671,7 @@ impl Frame { // Removing it fixes that but it needs a proper solution before // merging which will coming when the clipping branch merges! - let local_clip_rect = Some(MAX_RECT); + let local_clip_rect = Some(stacking_context.overflow); /* // FIXME(pcwalton): This is a not-great partial solution to servo/servo#10164. A better // solution would be to do this only if the transform consists of a translation+scale only @@ -824,36 +812,20 @@ impl Frame { } } - let mut opacity = 1.0; - for composition_op in composition_operations { - match composition_op { - CompositionOp::Filter(filter_op) => { - match filter_op { - LowLevelFilterOp::Opacity(o) => { - opacity = o.to_f32_px(); - } - _ => {} - } - } - _ => {} - } - } - // TODO: Account for scroll offset with transforms! self.add_items_to_target(&scene_items, &info, context, - level, stacking_context.overflow, - opacity); + composition_operations); } } } pub fn build(&mut self, resource_cache: &mut ResourceCache, - thread_pool: &mut scoped_threadpool::Pool, - device_pixel_ratio: f32) + _thread_pool: &mut scoped_threadpool::Pool, + _device_pixel_ratio: f32) -> RendererFrame { self.update_layer_transforms(); let frame = self.build_frame(resource_cache); diff --git a/src/internal_types.rs b/src/internal_types.rs index bf4867f782..fe628b21a7 100644 --- a/src/internal_types.rs +++ b/src/internal_types.rs @@ -17,7 +17,6 @@ use std::ops::{Add, Sub}; use std::path::PathBuf; use std::sync::Arc; use texture_cache::BorderType; -use util; use tiling; use webrender_traits::{FontKey, Epoch, ColorF, PipelineId}; use webrender_traits::{ImageFormat, MixBlendMode, NativeFontHandle, DisplayItem, ScrollLayerId}; @@ -30,10 +29,6 @@ impl DevicePixel { DevicePixel((value * device_pixel_ratio).round() as i32) } - pub fn from_i32(value: i32) -> DevicePixel { - DevicePixel(value) - } - pub fn from_u32(value: u32) -> DevicePixel { DevicePixel(value as i32) } @@ -608,6 +603,7 @@ pub struct BoxShadowRasterOp { pub inverted: bool, } +/* impl BoxShadowRasterOp { pub fn raster_rect(blur_radius: f32, border_radius: f32, @@ -694,12 +690,12 @@ impl BoxShadowRasterOp { None } } -} +}*/ #[derive(Clone, Hash, PartialEq, Eq, Debug)] pub enum BoxShadowPart { - Corner, - Edge, + _Corner, + _Edge, } #[derive(Clone, Hash, PartialEq, Eq, Debug)] @@ -723,7 +719,7 @@ impl GlyphKey { #[derive(Clone, Debug, Hash, Eq, PartialEq)] pub enum RasterItem { - BoxShadow(BoxShadowRasterOp), + _BoxShadow(BoxShadowRasterOp), } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] diff --git a/src/kdtree.rs b/src/kdtree.rs deleted file mode 100644 index b7e0a1d5ef..0000000000 --- a/src/kdtree.rs +++ /dev/null @@ -1,4 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - diff --git a/src/lib.rs b/src/lib.rs index 9955277e56..f97112c33a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,10 +48,8 @@ extern crate lazy_static; #[macro_use] extern crate log; -mod aabbtree; mod batch; mod batch_builder; -mod bsptree; mod debug_font_data; mod debug_render; mod device; @@ -61,7 +59,6 @@ mod geometry; mod internal_types; mod layer; mod profiler; -mod quadtree; mod render_backend; mod resource_cache; mod resource_list; @@ -110,6 +107,5 @@ extern crate time; extern crate webrender_traits; extern crate offscreen_gl_context; extern crate byteorder; -extern crate bit_set; pub use renderer::{Renderer, RendererOptions}; diff --git a/src/quadtree.rs b/src/quadtree.rs deleted file mode 100644 index 092a993794..0000000000 --- a/src/quadtree.rs +++ /dev/null @@ -1,222 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* -use euclid::{Point2D, Rect, Size2D}; -use std::fmt::Debug; -use util::{MatrixHelpers, rect_contains_rect, RectHelpers}; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct NodeIndex(pub u32); - -pub struct Node { - pub rect: Rect, - pub items: Vec, - // TODO: Use Option + NonZero here - children: Option, -} - -impl Node { - fn new(rect: Rect) -> Node { - Node { - rect: rect, - items: Vec::new(), - children: None, - } - } - - #[inline] - pub fn is_leaf(&self) -> bool { - self.children.is_none() - } -} - -pub struct Quadtree { - pub nodes: Vec>, - pub bounds: Rect, - min_size: f32, - size_threshold: f32, - split_threshold: usize, -} - -impl Quadtree { - pub fn new(rect: Rect, - min_size: f32, - size_threshold: f32, - split_threshold: usize) -> Quadtree { - Quadtree { - bounds: rect, - min_size: min_size, - size_threshold: size_threshold, - split_threshold: split_threshold, - nodes: vec![Node::new(rect)], - } - } - - #[inline] - fn node(&self, node_index: NodeIndex) -> &Node { - let NodeIndex(node_index) = node_index; - let node_index = node_index as usize; - &self.nodes[node_index] - } - - #[inline] - fn node_mut(&mut self, node_index: NodeIndex) -> &mut Node { - let NodeIndex(node_index) = node_index; - let node_index = node_index as usize; - &mut self.nodes[node_index] - } - - #[inline] - fn node_info(&self, node_index: NodeIndex) -> (Rect, usize, bool) { - let NodeIndex(node_index) = node_index; - let node_index = node_index as usize; - let node = &self.nodes[node_index]; - (node.rect, node.items.len(), node.children.is_some()) - } - - fn print_internal(&self, node: NodeIndex, level: usize) { - let mut indent = String::new(); - for _ in 0..level { - indent.push_str(" "); - } - - let node = self.node(node); - println!("{}{:?} c={:?} i={:?}", indent, node.rect, node.children, node.items); - - if let Some(children) = node.children { - let NodeIndex(children) = children; - self.print_internal(NodeIndex(children + 0), level+1); - self.print_internal(NodeIndex(children + 1), level+1); - } - } - - pub fn print(&self) { - self.print_internal(NodeIndex(0), 0); - } - - fn insert_internal(&mut self, - node_index: NodeIndex, - item: T, - level: usize, - f: &F) where F: Fn(T) -> Rect { - let rect = f(item); - let (node_rect, item_count, has_children) = self.node_info(node_index); - debug_assert!(node_rect.intersects(&rect)); - - let can_split = !has_children && (node_rect.size.width > self.min_size || - node_rect.size.height > self.min_size); - let want_split = (item_count == self.split_threshold) || - (self.size_threshold > 0.0 && (node_rect.size.width > self.size_threshold || - node_rect.size.height > self.size_threshold)); - if can_split && want_split { - let x0 = node_rect.origin.x; - let y0 = node_rect.origin.y; - - let x1 = x0 + node_rect.size.width; - let y1 = y0 + node_rect.size.height; - - let (r0, r1) = if node_rect.size.width > node_rect.size.height { - let x_mid = x0 + node_rect.size.width * 0.5; - let r0 = Rect::from_points(x0, y0, x_mid, y1); - let r1 = Rect::from_points(x_mid, y0, x1, y1); - (r0, r1) - } else { - let y_mid = y0 + node_rect.size.height * 0.5; - let r0 = Rect::from_points(x0, y0, x1, y_mid); - let r1 = Rect::from_points(x0, y_mid, x1, y1); - (r0, r1) - }; - - let mut c0 = Node::new(r0); - let mut c1 = Node::new(r1); - //let mut c2 = Node::new(r2); - //let mut c3 = Node::new(r3); - - let mut retained_items = Vec::new(); - for move_item in self.node_mut(node_index).items.drain(..) { - let item_rect = f(move_item); - - let left_int = c0.rect.intersects(&item_rect); - let right_int = c1.rect.intersects(&item_rect); - - match (left_int, right_int) { - (true, true) => retained_items.push(move_item), - (true, false) => c0.items.push(move_item), - (false, true) => c1.items.push(move_item), - (false, false) => unreachable!(), - } - } - self.node_mut(node_index).items = retained_items; - self.node_mut(node_index).children = Some(NodeIndex(self.nodes.len() as u32)); - - self.nodes.push(c0); - self.nodes.push(c1); - } - - let child_index = self.node(node_index).children; - match child_index { - Some(child_index) => { - let NodeIndex(child_index) = child_index; - let child_index = child_index as u32; - - let ci0 = NodeIndex(child_index + 0); - let ci1 = NodeIndex(child_index + 1); - - let left_int = self.node(ci0).rect.intersects(&rect); - let right_int = self.node(ci1).rect.intersects(&rect); - - match (left_int, right_int) { - (true, true) => self.node_mut(node_index).items.push(item), - (true, false) => self.insert_internal(ci0, item, level+1, f), - (false, true) => self.insert_internal(ci1, item, level+1, f), - (false, false) => unreachable!(), - } - } - None => { - self.node_mut(node_index).items.push(item); - } - } - } - - pub fn insert(&mut self, - item: T, - f: &F) where F: Fn(T) -> Rect { - self.insert_internal(NodeIndex(0), item, 0, f); - } - - fn visit_node(&self, - node_index: NodeIndex, - query_rect: &Rect, - f: &mut F) where F: FnMut(&Rect, &Vec) { - let NodeIndex(node_index) = node_index; - let node_index = node_index as usize; - let node = &self.nodes[node_index]; - - if node.rect.intersects(query_rect) { - match node.children { - Some(child_index) => { - let NodeIndex(child_index) = child_index; - let child_index = child_index as u32; - - for i in 0..2 { - self.visit_node(NodeIndex(child_index + i), - query_rect, - f); - } - } - None => { - f(&node.rect, &node.items); - } - } - } - } - - pub fn visit(&self, - query_rect: &Rect, - f: &mut F) where F: FnMut(&Rect, &Vec) { - self.visit_node(NodeIndex(0), query_rect, f); - } -} -*/ diff --git a/src/render_backend.rs b/src/render_backend.rs index 3804faee25..f1ba62b391 100644 --- a/src/render_backend.rs +++ b/src/render_backend.rs @@ -250,7 +250,7 @@ impl RenderBackend { ApiMsg::TranslatePointToLayerSpace(point, tx) => { // First, find the specific layer that contains the point. let point = point / self.device_pixel_ratio; - if let (Some(root_pipeline_id), Some(root_scroll_layer_id)) = + if let (Some(..), Some(root_scroll_layer_id)) = (self.scene.root_pipeline_id, self.frame.root_scroll_layer_id) { if let Some(scroll_layer_id) = diff --git a/src/renderer.rs b/src/renderer.rs index 7d90533239..715d152158 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -33,7 +33,7 @@ use std::sync::mpsc::{channel, Receiver, Sender}; use std::thread; use texture_cache::{BorderType, TextureCache, TextureInsertOp}; use tiling::{self, Frame, FrameBuilderConfig, PrimitiveBatchData, PackedTile}; -use tiling::{TransformedRectKind, RenderTarget, CompositeTile, ClearTile, PackedLayer}; +use tiling::{TransformedRectKind, RenderTarget, ClearTile, PackedLayer}; use time::precise_time_ns; use webrender_traits::{ColorF, Epoch, PipelineId, RenderNotifier}; use webrender_traits::{ImageFormat, MixBlendMode, RenderApiSender}; @@ -45,8 +45,7 @@ pub const MAX_RASTER_OP_SIZE: u32 = 2048; const UBO_BIND_LAYERS: u32 = 1; const UBO_BIND_CLEAR_TILES: u32 = 2; const UBO_BIND_PRIM_TILES: u32 = 3; -const UBO_BIND_COMPOSITE_TILES: u32 = 4; -const UBO_BIND_CACHE_ITEMS: u32 = 5; +const UBO_BIND_CACHE_ITEMS: u32 = 4; #[derive(Clone, Copy)] struct VertexBuffer { @@ -99,28 +98,11 @@ fn get_ubo_max_len(max_ubo_size: usize) -> usize { let item_size = mem::size_of::(); let max_items = max_ubo_size / item_size; - // TODO(gw): Clamping to 512 since some shader compilers + // TODO(gw): Clamping to 1024 since some shader compilers // seem to go very slow when you have high // constants for array lengths. Investigate // whether this clamping actually hurts performance! - cmp::min(max_items, 512) -} - -fn create_composite_shader(name: &'static str, - device: &mut Device, - max_composite_tiles: usize) -> ProgramId { - let prefix = format!("#define WR_MAX_COMPOSITE_TILES {}", max_composite_tiles); - - let program_id = device.create_program_with_prefix(name, - "composite_shared", - Some(prefix)); - - let tiles_index = gl::get_uniform_block_index(program_id.0, "Tiles"); - gl::uniform_block_binding(program_id.0, tiles_index, UBO_BIND_COMPOSITE_TILES); - - println!("CompositeShader {}: tiles={}/{}", name, tiles_index, max_composite_tiles); - - program_id + cmp::min(max_items, 1024) } fn create_prim_shader(name: &'static str, @@ -189,17 +171,21 @@ pub struct Renderer { u_direction: UniformLocation, ps_rectangle: ProgramId, - ps_rectangle_clip: ProgramId, ps_text: ProgramId, ps_image: ProgramId, ps_border: ProgramId, ps_box_shadow: ProgramId, - ps_gradient: ProgramId, + ps_blend: ProgramId, + ps_composite: ProgramId, + ps_aligned_gradient: ProgramId, + ps_angle_gradient: ProgramId, + + ps_rectangle_clip: ProgramId, + ps_image_clip: ProgramId, ps_rectangle_transform: ProgramId, ps_image_transform: ProgramId, - composite_shaders: [ProgramId; 8], tile_clear_shader: ProgramId, max_clear_tiles: usize, @@ -207,10 +193,13 @@ pub struct Renderer { max_prim_rectangles_clip: usize, max_prim_texts: usize, max_prim_images: usize, + max_prim_images_clip: usize, max_prim_borders: usize, max_prim_box_shadows: usize, - max_prim_gradients: usize, - max_composite_tiles: usize, + max_prim_blends: usize, + max_prim_composites: usize, + max_prim_aligned_gradients: usize, + max_prim_angle_gradients: usize, notifier: Arc>>>, @@ -281,9 +270,13 @@ impl Renderer { let max_prim_rectangles_clip = get_ubo_max_len::(max_ubo_size); let max_prim_texts = get_ubo_max_len::(max_ubo_size); let max_prim_images = get_ubo_max_len::(max_ubo_size); + let max_prim_images_clip = get_ubo_max_len::(max_ubo_size); let max_prim_borders = get_ubo_max_len::(max_ubo_size); let max_prim_box_shadows = get_ubo_max_len::(max_ubo_size); - let max_prim_gradients = get_ubo_max_len::(max_ubo_size); + let max_prim_blends = get_ubo_max_len::(max_ubo_size); + let max_prim_composites = get_ubo_max_len::(max_ubo_size); + let max_prim_aligned_gradients = get_ubo_max_len::(max_ubo_size); + let max_prim_angle_gradients = get_ubo_max_len::(max_ubo_size); let ps_rectangle = create_prim_shader("ps_rectangle", &mut device, @@ -305,6 +298,12 @@ impl Renderer { max_prim_tiles, max_prim_layers, max_prim_images); + let ps_image_clip = create_prim_shader("ps_image_clip", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_images_clip); + let ps_border = create_prim_shader("ps_border", &mut device, max_prim_tiles, @@ -315,11 +314,16 @@ impl Renderer { max_prim_tiles, max_prim_layers, max_prim_box_shadows); - let ps_gradient = create_prim_shader("ps_gradient", - &mut device, - max_prim_tiles, - max_prim_layers, - max_prim_gradients); + let ps_aligned_gradient = create_prim_shader("ps_gradient", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_aligned_gradients); + let ps_angle_gradient = create_prim_shader("ps_angle_gradient", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_angle_gradients); let ps_rectangle_transform = create_prim_shader("ps_rectangle_transform", &mut device, @@ -331,22 +335,20 @@ impl Renderer { max_prim_tiles, max_prim_layers, max_prim_images); + let ps_blend = create_prim_shader("ps_blend", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_blends); + let ps_composite = create_prim_shader("ps_composite", + &mut device, + max_prim_tiles, + max_prim_layers, + max_prim_composites); let max_clear_tiles = get_ubo_max_len::(max_ubo_size); let tile_clear_shader = create_clear_shader("ps_clear", &mut device, max_clear_tiles); - let max_composite_tiles = get_ubo_max_len::(max_ubo_size); - let composite_shaders: [ProgramId; 8] = [ - create_composite_shader("cs_p1", &mut device, max_composite_tiles), - create_composite_shader("cs_p2", &mut device, max_composite_tiles), - create_composite_shader("cs_p3", &mut device, max_composite_tiles), - create_composite_shader("cs_p4", &mut device, max_composite_tiles), - create_composite_shader("cs_p5", &mut device, max_composite_tiles), - create_composite_shader("cs_p6", &mut device, max_composite_tiles), - create_composite_shader("cs_p7", &mut device, max_composite_tiles), - create_composite_shader("cs_p8", &mut device, max_composite_tiles), - ]; - let texture_ids = device.create_texture_ids(1024); let mut texture_cache = TextureCache::new(texture_ids); let white_pixels: Vec = vec![ @@ -473,11 +475,15 @@ impl Renderer { tile_clear_shader: tile_clear_shader, ps_rectangle: ps_rectangle, ps_rectangle_clip: ps_rectangle_clip, + ps_image_clip: ps_image_clip, ps_text: ps_text, ps_image: ps_image, ps_border: ps_border, ps_box_shadow: ps_box_shadow, - ps_gradient: ps_gradient, + ps_blend: ps_blend, + ps_composite: ps_composite, + ps_aligned_gradient: ps_aligned_gradient, + ps_angle_gradient: ps_angle_gradient, ps_rectangle_transform: ps_rectangle_transform, ps_image_transform: ps_image_transform, max_clear_tiles: max_clear_tiles, @@ -485,11 +491,13 @@ impl Renderer { max_prim_rectangles_clip: max_prim_rectangles_clip, max_prim_texts: max_prim_texts, max_prim_images: max_prim_images, + max_prim_images_clip: max_prim_images_clip, max_prim_borders: max_prim_borders, max_prim_box_shadows: max_prim_box_shadows, - max_prim_gradients: max_prim_gradients, - max_composite_tiles: max_composite_tiles, - composite_shaders: composite_shaders, + max_prim_blends: max_prim_blends, + max_prim_composites: max_prim_composites, + max_prim_aligned_gradients: max_prim_aligned_gradients, + max_prim_angle_gradients: max_prim_angle_gradients, u_direction: UniformLocation::invalid(), notifier: notifier, debug: debug_renderer, @@ -1269,25 +1277,77 @@ impl Renderer { gl::clear(gl::COLOR_BUFFER_BIT); } - for alpha_task in &target.alpha_batch_tasks { - let misc_ubos = gl::gen_buffers(2); - let layer_ubo = misc_ubos[0]; - let tile_ubo = misc_ubos[1]; + for batcher in &target.alpha_batchers { + let layer_ubos = gl::gen_buffers(batcher.layer_ubos.len() as i32); + let tile_ubos = gl::gen_buffers(batcher.tile_ubos.len() as i32); - gl::bind_buffer(gl::UNIFORM_BUFFER, layer_ubo); - gl::buffer_data(gl::UNIFORM_BUFFER, &alpha_task.layer_ubo, gl::STATIC_DRAW); - gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_LAYERS, layer_ubo); + for (ubo_data, ubo_id) in batcher.layer_ubos + .iter() + .zip(layer_ubos.iter()) { + gl::bind_buffer(gl::UNIFORM_BUFFER, *ubo_id); + gl::buffer_data(gl::UNIFORM_BUFFER, ubo_data, gl::STATIC_DRAW); + } - gl::bind_buffer(gl::UNIFORM_BUFFER, tile_ubo); - gl::buffer_data(gl::UNIFORM_BUFFER, &alpha_task.tile_ubo, gl::STATIC_DRAW); - gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_PRIM_TILES, tile_ubo); + for (ubo_data, ubo_id) in batcher.tile_ubos + .iter() + .zip(tile_ubos.iter()) { + gl::bind_buffer(gl::UNIFORM_BUFFER, *ubo_id); + gl::buffer_data(gl::UNIFORM_BUFFER, ubo_data, gl::STATIC_DRAW); + } gl::enable(gl::BLEND); gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); gl::blend_equation(gl::FUNC_ADD); - for batch in &alpha_task.batches { + for batch in &batcher.batches { match &batch.data { + &PrimitiveBatchData::Blend(..) => {} + &PrimitiveBatchData::Composite(..) => {} + _ => { + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_LAYERS, layer_ubos[batch.layer_ubo_index]); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_PRIM_TILES, tile_ubos[batch.tile_ubo_index]); + } + } + + match &batch.data { + &PrimitiveBatchData::Blend(ref ubo_data) => { + self.device.bind_program(self.ps_blend, &projection); + self.device.bind_vao(self.quad_vao_id); + + for chunk in ubo_data.chunks(self.max_prim_blends) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; + + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); + + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); + + gl::delete_buffers(&ubos); + } + } + &PrimitiveBatchData::Composite(ref ubo_data) => { + self.device.bind_program(self.ps_composite, &projection); + self.device.bind_vao(self.quad_vao_id); + + for chunk in ubo_data.chunks(self.max_prim_composites) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; + + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); + + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); + + gl::delete_buffers(&ubos); + } + } &PrimitiveBatchData::Rectangles(ref ubo_data) => { let shader = match batch.transform_kind { TransformedRectKind::AxisAligned => self.ps_rectangle, @@ -1354,6 +1414,26 @@ impl Renderer { gl::delete_buffers(&ubos); } } + &PrimitiveBatchData::ImageClip(ref ubo_data) => { + self.device.bind_program(self.ps_image_clip, &projection); + self.device.bind_vao(self.quad_vao_id); + self.device.bind_color_texture(batch.color_texture_id); + + for chunk in ubo_data.chunks(self.max_prim_images_clip) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; + + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); + + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); + + gl::delete_buffers(&ubos); + } + } &PrimitiveBatchData::Borders(ref ubo_data) => { self.device.bind_program(self.ps_border, &projection); self.device.bind_vao(self.quad_vao_id); @@ -1412,11 +1492,11 @@ impl Renderer { gl::delete_buffers(&ubos); } } - &PrimitiveBatchData::Gradient(ref ubo_data) => { - self.device.bind_program(self.ps_gradient, &projection); + &PrimitiveBatchData::AlignedGradient(ref ubo_data) => { + self.device.bind_program(self.ps_aligned_gradient, &projection); self.device.bind_vao(self.quad_vao_id); - for chunk in ubo_data.chunks(self.max_prim_gradients) { + for chunk in ubo_data.chunks(self.max_prim_aligned_gradients) { let ubos = gl::gen_buffers(1); let ubo = ubos[0]; @@ -1431,31 +1511,31 @@ impl Renderer { gl::delete_buffers(&ubos); } } - } - } - - gl::disable(gl::BLEND); - gl::delete_buffers(&misc_ubos); - } - - for (key, tiles) in &target.composite_batches { - let shader = self.composite_shaders[key.shader as usize]; - self.device.bind_program(shader, &projection); + &PrimitiveBatchData::AngleGradient(ref ubo_data) => { + self.device.bind_program(self.ps_angle_gradient, &projection); + self.device.bind_vao(self.quad_vao_id); - for batch in tiles.chunks(self.max_composite_tiles) { - let ubos = gl::gen_buffers(1); - let ubo = ubos[0]; + for chunk in ubo_data.chunks(self.max_prim_angle_gradients) { + let ubos = gl::gen_buffers(1); + let ubo = ubos[0]; - gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); - gl::buffer_data(gl::UNIFORM_BUFFER, &batch, gl::STATIC_DRAW); - gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_COMPOSITE_TILES, ubo); + gl::bind_buffer(gl::UNIFORM_BUFFER, ubo); + gl::buffer_data(gl::UNIFORM_BUFFER, &chunk, gl::STATIC_DRAW); + gl::bind_buffer_base(gl::UNIFORM_BUFFER, UBO_BIND_CACHE_ITEMS, ubo); - self.device.draw_indexed_triangles_instanced_u16(6, batch.len() as i32); - self.profile_counters.vertices.add(6 * batch.len()); - self.profile_counters.draw_calls.inc(); + self.device.draw_indexed_triangles_instanced_u16(6, chunk.len() as gl::GLint); + self.profile_counters.vertices.add(6 * chunk.len()); + self.profile_counters.draw_calls.inc(); - gl::delete_buffers(&ubos); + gl::delete_buffers(&ubos); + } + } + } } + + gl::disable(gl::BLEND); + gl::delete_buffers(&tile_ubos); + gl::delete_buffers(&layer_ubos); } } diff --git a/src/resource_cache.rs b/src/resource_cache.rs index 4187a04669..c8d43a6465 100644 --- a/src/resource_cache.rs +++ b/src/resource_cache.rs @@ -394,12 +394,10 @@ impl ResourceCache { } */ -/* #[inline] pub fn get_webgl_texture(&self, context_id: &WebGLContextId) -> TextureId { self.webgl_textures.get(context_id).unwrap().clone() } -*/ pub fn expire_old_resources(&mut self, frame_id: FrameId) { self.cached_glyphs.expire_old_resources(&mut self.texture_cache, frame_id); diff --git a/src/resource_list.rs b/src/resource_list.rs index 223783ea4e..b04114a668 100644 --- a/src/resource_list.rs +++ b/src/resource_list.rs @@ -3,9 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use euclid::Rect; use fnv::FnvHasher; -use internal_types::{Glyph, GlyphKey, RasterItem, BoxShadowRasterOp}; +use internal_types::{Glyph, GlyphKey, RasterItem}; use std::collections::{HashMap, HashSet}; use std::hash::BuildHasherDefault; use webrender_traits::{FontKey, ImageKey, ImageRendering}; @@ -18,7 +17,7 @@ pub struct ResourceList { required_images: RequiredImageSet, required_glyphs: RequiredGlyphMap, required_rasters: RequiredRasterSet, - device_pixel_ratio: f32, + _device_pixel_ratio: f32, } impl ResourceList { @@ -27,7 +26,7 @@ impl ResourceList { required_glyphs: HashMap::with_hasher(Default::default()), required_images: HashSet::with_hasher(Default::default()), required_rasters: HashSet::with_hasher(Default::default()), - device_pixel_ratio: device_pixel_ratio, + _device_pixel_ratio: device_pixel_ratio, } } @@ -43,6 +42,7 @@ impl ResourceList { .insert(glyph); } +/* pub fn add_box_shadow_corner(&mut self, blur_radius: f32, border_radius: f32, @@ -69,7 +69,7 @@ impl ResourceList { self.device_pixel_ratio) { self.required_rasters.insert(RasterItem::BoxShadow(raster_item)); } - } + }*/ pub fn for_each_image(&self, mut f: F) where F: FnMut(ImageKey, ImageRendering) { for &(image_id, image_rendering) in &self.required_images { diff --git a/src/texture_cache.rs b/src/texture_cache.rs index 923fdf2232..696930c43f 100644 --- a/src/texture_cache.rs +++ b/src/texture_cache.rs @@ -810,7 +810,7 @@ impl TextureCache { item: &RasterItem, _device_pixel_ratio: f32) { let update_op = match item { - &RasterItem::BoxShadow(ref op) => { + &RasterItem::_BoxShadow(ref op) => { let allocation = self.allocate(image_id, 0, 0, diff --git a/src/tiling.rs b/src/tiling.rs index 7503f053da..c8082f40d9 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -4,12 +4,12 @@ use app_units::{Au}; use batch_builder::{BorderSideHelpers, BoxShadowMetrics}; -use bsptree::BspTree; -use device::{TextureId, TextureFilter}; +use device::{TextureId}; use euclid::{Point2D, Rect, Matrix4D, Size2D, Point4D}; use fnv::FnvHasher; use frame::FrameId; -use internal_types::{AxisDirection, Glyph, GlyphKey, DevicePixel}; +use internal_types::{Glyph, GlyphKey, DevicePixel, CompositionOp}; +use internal_types::{ANGLE_FLOAT_TO_FIXED, LowLevelFilterOp, RectUv}; use layer::Layer; use renderer::{BLUR_INFLATION_FACTOR}; use resource_cache::ResourceCache; @@ -19,145 +19,239 @@ use std::collections::{HashMap}; use std::f32; use std::mem; use std::hash::{BuildHasherDefault}; -use texture_cache::{TexturePage, TextureCacheItem}; -use util::{self, rect_from_points, rect_from_points_f, MatrixHelpers, subtract_rect, RectHelpers, rect_contains_rect}; +use texture_cache::{TexturePage}; +use util::{self, rect_from_points, rect_from_points_f, MatrixHelpers, subtract_rect}; use webrender_traits::{ColorF, FontKey, ImageKey, ImageRendering, ComplexClipRegion}; use webrender_traits::{BorderDisplayItem, BorderStyle, ItemRange, AuxiliaryLists, BorderRadius, BorderSide}; -use webrender_traits::{BoxShadowClipMode, PipelineId, ScrollLayerId}; +use webrender_traits::{BoxShadowClipMode, PipelineId, ScrollLayerId, WebGLContextId}; -struct RenderTargetContext<'a> { - layers: &'a Vec, - resource_cache: &'a ResourceCache, - device_pixel_ratio: f32, - pipeline_auxiliary_lists: &'a HashMap>, - frame_id: FrameId, - alpha_batch_max_tiles: usize, - alpha_batch_max_layers: usize, +#[repr(u32)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum GradientType { + Horizontal, + Vertical, + Rotated, +} + +#[derive(Debug, Copy, Clone)] +struct TaskIndex(usize); + +struct AlphaBatchTask { + items: Vec, + target_rect: Rect, + actual_rect: Rect, + child_rects: Vec>, } -pub struct AlphaBatchRenderTask { +pub struct AlphaBatcher { + pub layer_ubos: Vec>, + pub tile_ubos: Vec>, pub batches: Vec, - pub layer_ubo: Vec, - pub tile_ubo: Vec, - screen_tile_layers: Vec, layer_to_ubo_map: Vec>, + tile_to_ubo_map: Vec>, + tasks: Vec, } -impl AlphaBatchRenderTask { - fn new(ctx: &RenderTargetContext) -> AlphaBatchRenderTask { - let mut layer_to_ubo_map = Vec::new(); - for _ in 0..ctx.layers.len() { - layer_to_ubo_map.push(None); - } - - AlphaBatchRenderTask { +impl AlphaBatcher { + fn new() -> AlphaBatcher { + AlphaBatcher { + layer_ubos: Vec::new(), + tile_ubos: Vec::new(), batches: Vec::new(), - layer_ubo: Vec::new(), - tile_ubo: Vec::new(), - screen_tile_layers: Vec::new(), - layer_to_ubo_map: layer_to_ubo_map, + layer_to_ubo_map: Vec::new(), + tile_to_ubo_map: Vec::new(), + tasks: Vec::new(), } } - fn add_screen_tile_layer(&mut self, - target_rect: Rect, - screen_tile_layer: ScreenTileLayer, - ctx: &RenderTargetContext) -> Option { - if self.tile_ubo.len() == ctx.alpha_batch_max_tiles { - return Some(screen_tile_layer); - } - self.tile_ubo.push(PackedTile { - target_rect: target_rect, - actual_rect: screen_tile_layer.actual_rect, - }); + fn add_tile_to_ubo(tile_ubos: &mut Vec>, + tile_to_ubo_map: &mut Vec>, + task_index: TaskIndex, + task: &AlphaBatchTask, + ctx: &RenderTargetContext) -> (usize, u32) { + let index_in_ubo = match tile_to_ubo_map[task_index.0] { + Some(index_in_ubo) => { + index_in_ubo + } + None => { + let need_new_ubo = tile_ubos.is_empty() || + tile_ubos.last().unwrap().len() == ctx.alpha_batch_max_tiles; + + if need_new_ubo { + for i in 0..tile_to_ubo_map.len() { + tile_to_ubo_map[i] = None; + } + tile_ubos.push(Vec::new()); + } - let StackingContextIndex(si) = screen_tile_layer.layer_index; - match self.layer_to_ubo_map[si] { - Some(..) => {} + let tile_ubo = tile_ubos.last_mut().unwrap(); + let index = tile_ubo.len(); + tile_ubo.push(PackedTile { + actual_rect: task.actual_rect, + target_rect: task.target_rect, + }); + tile_to_ubo_map[task_index.0] = Some(index); + index + } + }; + + (tile_ubos.len() - 1, index_in_ubo as u32) + } + + fn add_layer_to_ubo(layer_ubos: &mut Vec>, + layer_to_ubo_map: &mut Vec>, + layer_index: StackingContextIndex, + ctx: &RenderTargetContext) -> (usize, u32) { + let index_in_ubo = match layer_to_ubo_map[layer_index.0] { + Some(index_in_ubo) => { + index_in_ubo + } None => { - if self.layer_ubo.len() == ctx.alpha_batch_max_layers { - return Some(screen_tile_layer); + let need_new_ubo = layer_ubos.is_empty() || + layer_ubos.last().unwrap().len() == ctx.alpha_batch_max_layers; + + if need_new_ubo { + for i in 0..layer_to_ubo_map.len() { + layer_to_ubo_map[i] = None; + } + layer_ubos.push(Vec::new()); } - let index = self.layer_ubo.len(); - let sc = &ctx.layers[si]; - self.layer_ubo.push(PackedLayer { - padding: [0, 0], + let layer_ubo = layer_ubos.last_mut().unwrap(); + let index = layer_ubo.len(); + let sc = &ctx.layer_store[layer_index.0]; + layer_ubo.push(PackedLayer { transform: sc.transform, inv_transform: sc.transform.invert(), screen_vertices: sc.xf_rect.as_ref().unwrap().vertices, - blend_info: [sc.opacity, 0.0], + world_clip_rect: sc.world_clip_rect.unwrap(), }); - self.layer_to_ubo_map[si] = Some(index); + layer_to_ubo_map[layer_index.0] = Some(index); + index } - } + }; - self.screen_tile_layers.push(screen_tile_layer); - None + (layer_ubos.len() - 1, index_in_ubo as u32) } - fn build(&mut self, ctx: &RenderTargetContext) { - debug_assert!(self.layer_ubo.len() <= ctx.alpha_batch_max_layers); - debug_assert!(self.tile_ubo.len() <= ctx.alpha_batch_max_tiles); + fn add_task(&mut self, task: AlphaBatchTask) { + self.tasks.push(task); + } - // Build batches - // TODO(gw): This batching code is fairly awful - rewrite it! + fn build(&mut self, ctx: &RenderTargetContext) { + for _ in 0..ctx.layer_store.len() { + self.layer_to_ubo_map.push(None); + } + for _ in 0..self.tasks.len() { + self.tile_to_ubo_map.push(None); + } loop { // Pull next primitive let mut batch = None; - for (screen_tile_layer_index, screen_tile_layer) in self.screen_tile_layers - .iter_mut() - .enumerate() { - if let Some(next_prim_index) = screen_tile_layer.prim_indices.pop() { - let StackingContextIndex(si) = screen_tile_layer.layer_index; - let layer = &ctx.layers[si]; - let PrimitiveIndex(pi) = next_prim_index; - let prim = &layer.primitives[pi]; - let transform_kind = layer.xf_rect.as_ref().unwrap().kind; - let mut new_batch = PrimitiveBatch::new(prim, transform_kind); - let layer_index_in_ubo = self.layer_to_ubo_map[si].unwrap() as u32; - let tile_index_in_ubo = screen_tile_layer_index as u32; - let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id) - .expect("No auxiliary lists?!"); - let ok = prim.pack(&mut new_batch, - layer_index_in_ubo, - tile_index_in_ubo, - auxiliary_lists, - transform_kind, - ctx); - debug_assert!(ok); - batch = Some(new_batch); - break; + for (task_index, task) in self.tasks.iter_mut().enumerate() { + if let Some(next_item) = task.items.pop() { + match next_item { + AlphaRenderItem::Composite(info) => { + batch = Some(PrimitiveBatch::composite(task.child_rects[0], + task.child_rects[1], + task.target_rect, + info)); + break; + } + AlphaRenderItem::Blend(child_index, opacity) => { + batch = Some(PrimitiveBatch::blend(task.child_rects[child_index], + task.target_rect, + opacity)); + break; + } + AlphaRenderItem::Primitive(sc_index, prim_index) => { + // See if this task fits into the tile UBO + let layer = &ctx.layer_store[sc_index.0]; + let prim = &ctx.prim_store[prim_index.0]; + let transform_kind = layer.xf_rect.as_ref().unwrap().kind; + let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id) + .expect("No auxiliary lists?!"); + let (layer_ubo_index, index_in_layer_ubo) = AlphaBatcher::add_layer_to_ubo(&mut self.layer_ubos, + &mut self.layer_to_ubo_map, + sc_index, + ctx); + let (tile_ubo_index, index_in_tile_ubo) = AlphaBatcher::add_tile_to_ubo(&mut self.tile_ubos, + &mut self.tile_to_ubo_map, + TaskIndex(task_index), + task, + ctx); + let mut new_batch = PrimitiveBatch::new(prim, + transform_kind, + layer_ubo_index, + tile_ubo_index); + let ok = prim.pack(&mut new_batch, + index_in_layer_ubo, + index_in_tile_ubo, + auxiliary_lists, + transform_kind, + ctx); + debug_assert!(ok); + batch = Some(new_batch); + break; + } + } } } match batch { Some(mut batch) => { - for (screen_tile_layer_index, screen_tile_layer) in self.screen_tile_layers - .iter_mut() - .enumerate() { + for (task_index, task) in self.tasks.iter_mut().enumerate() { loop { - match screen_tile_layer.prim_indices.pop() { - Some(next_prim_index) => { - let StackingContextIndex(si) = screen_tile_layer.layer_index; - let layer = &ctx.layers[si]; - let PrimitiveIndex(pi) = next_prim_index; - let next_prim = &layer.primitives[pi]; - let layer_index_in_ubo = self.layer_to_ubo_map[si].unwrap() as u32; - let tile_index_in_ubo = screen_tile_layer_index as u32; - let transform_kind = layer.xf_rect.as_ref().unwrap().kind; - let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id) - .expect("No auxiliary lists?!"); - if !next_prim.pack(&mut batch, - layer_index_in_ubo, - tile_index_in_ubo, - auxiliary_lists, - transform_kind, - ctx) { - screen_tile_layer.prim_indices.push(next_prim_index); - break; + match task.items.pop() { + Some(next_item) => { + match next_item { + AlphaRenderItem::Composite(info) => { + if !batch.pack_composite(task.child_rects[0], + task.child_rects[1], + task.target_rect, + info) { + task.items.push(next_item); + break; + } + } + AlphaRenderItem::Blend(child_index, opacity) => { + if !batch.pack_blend(task.child_rects[child_index], + task.target_rect, + opacity) { + task.items.push(next_item); + break; + } + } + AlphaRenderItem::Primitive(sc_index, prim_index) => { + let layer = &ctx.layer_store[sc_index.0]; + let prim = &ctx.prim_store[prim_index.0]; + let transform_kind = layer.xf_rect.as_ref().unwrap().kind; + let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id) + .expect("No auxiliary lists?!"); + let (layer_ubo_index, index_in_layer_ubo) = AlphaBatcher::add_layer_to_ubo(&mut self.layer_ubos, + &mut self.layer_to_ubo_map, + sc_index, + ctx); + let (tile_ubo_index, index_in_tile_ubo) = AlphaBatcher::add_tile_to_ubo(&mut self.tile_ubos, + &mut self.tile_to_ubo_map, + TaskIndex(task_index), + task, + ctx); + + if layer_ubo_index != batch.layer_ubo_index || + tile_ubo_index != batch.tile_ubo_index || + !prim.pack(&mut batch, + index_in_layer_ubo, + index_in_tile_ubo, + auxiliary_lists, + transform_kind, + ctx) { + task.items.push(next_item); + break; + } + } } } None => { @@ -177,15 +271,23 @@ impl AlphaBatchRenderTask { } } +struct RenderTargetContext<'a> { + layer_store: &'a Vec, + prim_store: &'a Vec, + resource_cache: &'a ResourceCache, + device_pixel_ratio: f32, + pipeline_auxiliary_lists: &'a HashMap>, + frame_id: FrameId, + alpha_batch_max_tiles: usize, + alpha_batch_max_layers: usize, +} + pub struct RenderTarget { pub is_framebuffer: bool, page_allocator: TexturePage, tasks: Vec, - pub alpha_batch_tasks: Vec, - pub composite_batches: HashMap, - BuildHasherDefault>, + pub alpha_batchers: Vec, } impl RenderTarget { @@ -195,8 +297,7 @@ impl RenderTarget { page_allocator: TexturePage::new(TextureId(0), RENDERABLE_CACHE_SIZE.0 as u32), tasks: Vec::new(), - alpha_batch_tasks: Vec::new(), - composite_batches: HashMap::with_hasher(Default::default()), + alpha_batchers: Vec::new(), } } @@ -206,61 +307,32 @@ impl RenderTarget { fn build(&mut self, ctx: &RenderTargetContext) { // Step through each task, adding to batches as appropriate. - let mut alpha_batch_tasks = Vec::new(); - let mut current_alpha_batch_task = AlphaBatchRenderTask::new(ctx); for task in self.tasks.drain(..) { let target_rect = task.get_target_rect(); match task.kind { - RenderTaskKind::AlphaBatch(screen_tile_layer) => { - match current_alpha_batch_task.add_screen_tile_layer(target_rect, - screen_tile_layer, - ctx) { - Some(screen_tile_layer) => { - let old_task = mem::replace(&mut current_alpha_batch_task, - AlphaBatchRenderTask::new(ctx)); - alpha_batch_tasks.push(old_task); - - let result = current_alpha_batch_task.add_screen_tile_layer(target_rect, - screen_tile_layer, - ctx); - debug_assert!(result.is_none()); - } - None => {} - } - } - RenderTaskKind::Composite(info) => { - let mut composite_tile = CompositeTile::new(&target_rect); - debug_assert!(info.layer_indices.len() == task.child_locations.len()); - for (i, (layer_index, location)) in info.layer_indices - .iter() - .zip(task.child_locations.iter()) - .enumerate() { - let opacity = layer_index.map_or(1.0, |layer_index| { - let StackingContextIndex(si) = layer_index; - ctx.layers[si].opacity - }); - composite_tile.src_rects[i] = *location; - composite_tile.blend_info[i] = opacity; + RenderTaskKind::Alpha(info) => { + let need_new_batcher = self.alpha_batchers.is_empty() || + self.alpha_batchers.last().unwrap().tasks.len() == 64; + + if need_new_batcher { + self.alpha_batchers.push(AlphaBatcher::new()); } - let shader = CompositeShader::from_cover(info.layer_indices.len()); - let key = CompositeBatchKey::new(shader); - let batch = self.composite_batches.entry(key).or_insert_with(|| { - Vec::new() + + self.alpha_batchers.last_mut().unwrap().add_task(AlphaBatchTask { + target_rect: target_rect, + actual_rect: info.actual_rect, + items: info.items, + child_rects: task.child_locations.clone(), // TODO(gw): Remove clone somehow!? }); - batch.push(composite_tile); } } } - if !current_alpha_batch_task.screen_tile_layers.is_empty() { - alpha_batch_tasks.push(current_alpha_batch_task); + for ab in &mut self.alpha_batchers { + ab.build(ctx); } - for task in &mut alpha_batch_tasks { - task.build(ctx); - } - self.alpha_batch_tasks = alpha_batch_tasks; } } @@ -309,10 +381,35 @@ enum RenderTaskLocation { Dynamic(Option>, Size2D), } +#[derive(Debug)] +enum AlphaRenderItem { + Primitive(StackingContextIndex, PrimitiveIndex), + Blend(usize, f32), + Composite(PackedCompositeInfo), +} + +#[derive(Debug)] +struct AlphaRenderTask { + actual_rect: Rect, + items: Vec, + children: Vec, +} + +impl AlphaRenderTask { + fn new(actual_rect: Rect) -> AlphaRenderTask { + AlphaRenderTask { + actual_rect: actual_rect, + items: Vec::new(), + children: Vec::new(), + } + } +} + #[derive(Debug)] enum RenderTaskKind { - AlphaBatch(ScreenTileLayer), - Composite(CompositeTileInfo), + Alpha(AlphaRenderTask), + //AlphaBatch(ScreenTileLayer), + //Composite(CompositeTileInfo), } #[derive(Debug)] @@ -324,25 +421,22 @@ struct RenderTask { } impl RenderTask { - fn from_layer(layer: ScreenTileLayer, location: RenderTaskLocation) -> RenderTask { - RenderTask { - children: Vec::new(), - child_locations: Vec::new(), - location: location, - kind: RenderTaskKind::AlphaBatch(layer), + fn from_primitives(mut task: AlphaRenderTask, + location: RenderTaskLocation, + size: Size2D) -> RenderTask { + let mut children = Vec::new(); + for child in task.children.drain(..) { + let location = RenderTaskLocation::Dynamic(None, size); + children.push(RenderTask::from_primitives(child, location, size)); } - } - fn composite(layers: Vec, - location: RenderTaskLocation, - layer_indices: Vec>) -> RenderTask { + task.items.reverse(); + RenderTask { - children: layers, + children: children, child_locations: Vec::new(), location: location, - kind: RenderTaskKind::Composite(CompositeTileInfo { - layer_indices: layer_indices, - }), + kind: RenderTaskKind::Alpha(task), } } @@ -366,10 +460,10 @@ impl RenderTask { // Sanity check - can be relaxed if needed match self.location { - RenderTaskLocation::Fixed(rect) => { + RenderTaskLocation::Fixed(..) => { debug_assert!(target_index == targets.len() - 1); } - RenderTaskLocation::Dynamic(origin, size) => { + RenderTaskLocation::Dynamic(..) => { debug_assert!(target_index < targets.len() - 1); } } @@ -413,10 +507,6 @@ impl RenderTask { true } - fn add_child_task(&mut self, task: RenderTask) { - self.children.push(task); - } - fn max_depth(&self, depth: usize, max_depth: &mut usize) { @@ -428,38 +518,9 @@ impl RenderTask { } } -pub const SCREEN_TILE_SIZE: usize = 64; +pub const SCREEN_TILE_SIZE: i32 = 64; pub const RENDERABLE_CACHE_SIZE: DevicePixel = DevicePixel(2048); -pub const MAX_LAYERS_PER_PASS: usize = 8; - -#[allow(non_camel_case_types)] -#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] -pub enum CompositeShader { - Prim1, - Prim2, - Prim3, - Prim4, - Prim5, - Prim6, - Prim7, - Prim8, -} - -impl CompositeShader { - fn from_cover(size: usize) -> CompositeShader { - match size { - 1 => CompositeShader::Prim1, - 2 => CompositeShader::Prim2, - 3 => CompositeShader::Prim3, - 4 => CompositeShader::Prim4, - 5 => CompositeShader::Prim5, - 6 => CompositeShader::Prim6, - 7 => CompositeShader::Prim7, - 8 => CompositeShader::Prim8, - _ => panic!("todo - other shader?"), - } - } -} +const MAX_STOPS_PER_ANGLE_GRADIENT: usize = 8; #[derive(Debug, Clone)] pub struct DebugRect { @@ -468,13 +529,6 @@ pub struct DebugRect { pub rect: Rect, } -#[derive(Debug, Copy, Clone)] -enum CacheSize { - None, - Fixed, - Variable(Size2D), -} - #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum TransformedRectKind { AxisAligned, @@ -630,17 +684,23 @@ struct BorderPrimitive { bottom_style: BorderStyle, } +#[derive(Debug)] +enum ImagePrimitiveKind { + Image(ImageKey, ImageRendering, Size2D), + WebGL(WebGLContextId), +} + #[derive(Debug)] struct ImagePrimitive { - image_key: ImageKey, - image_rendering: ImageRendering, - stretch_size: Size2D, + kind: ImagePrimitiveKind, } #[derive(Debug)] struct GradientPrimitive { stops_range: ItemRange, - dir: AxisDirection, + kind: GradientType, + start_point: Point2D, + end_point: Point2D, } #[derive(Debug)] @@ -653,22 +713,6 @@ enum PrimitiveDetails { BoxShadow(BoxShadowPrimitive), } -#[derive(Clone)] -enum PackedPrimitive { - Rectangle(PackedRectanglePrimitive), - RectangleClip(PackedRectanglePrimitiveClip), - Glyph(PackedGlyphPrimitive), - Image(PackedImagePrimitive), - Border(PackedBorderPrimitive), - BoxShadow(PackedBoxShadowPrimitive), - Gradient(PackedGradientPrimitive), -} - -struct PackedPrimList { - color_texture_id: TextureId, - primitives: Vec, -} - #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct PrimitiveIndex(usize); @@ -677,23 +721,10 @@ struct Primitive { rect: Rect, local_clip_rect: Rect, complex_clip: Option>, - xf_rect: Option, details: PrimitiveDetails, } impl Primitive { - #[inline(always)] - fn is_opaque(&self) -> bool { - match self.details { - PrimitiveDetails::Rectangle(ref details) => { - details.color.a == 1.0 - } - _ => { - false - } - } - } - fn pack(&self, batch: &mut PrimitiveBatch, layer_index_in_ubo: u32, @@ -706,6 +737,8 @@ impl Primitive { } match (&mut batch.data, &self.details) { + (&mut PrimitiveBatchData::Blend(..), _) => false, + (&mut PrimitiveBatchData::Composite(..), _) => false, (&mut PrimitiveBatchData::Rectangles(ref mut data), &PrimitiveDetails::Rectangle(ref details)) => { match self.complex_clip { Some(..) => { @@ -719,8 +752,8 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, + local_rect: self.rect, }, - local_rect: self.rect, color: details.color, }); true @@ -738,8 +771,8 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, + local_rect: self.rect, }, - local_rect: self.rect, color: details.color, clip: (**clip).clone(), }); @@ -753,36 +786,110 @@ impl Primitive { } (&mut PrimitiveBatchData::RectanglesClip(..), _) => false, (&mut PrimitiveBatchData::Image(ref mut data), &PrimitiveDetails::Image(ref details)) => { - let image_info = ctx.resource_cache.get_image(details.image_key, - details.image_rendering, - ctx.frame_id); - let uv_rect = image_info.uv_rect(); - - // TODO(gw): Tidy the support for batch breaks up... - if batch.color_texture_id != TextureId(0) && - batch.color_texture_id != image_info.texture_id { - return false; - } - batch.color_texture_id = image_info.texture_id; + match self.complex_clip { + Some(..) => { + false + } + None => { + let (texture_id, uv_rect, stretch_size) = match details.kind { + ImagePrimitiveKind::Image(image_key, image_rendering, stretch_size) => { + let info = ctx.resource_cache.get_image(image_key, + image_rendering, + ctx.frame_id); + (info.texture_id, info.uv_rect(), stretch_size) + } + ImagePrimitiveKind::WebGL(context_id) => { + let texture_id = ctx.resource_cache.get_webgl_texture(&context_id); + let uv = RectUv { + top_left: Point2D::new(0.0, 1.0), + top_right: Point2D::new(1.0, 1.0), + bottom_left: Point2D::zero(), + bottom_right: Point2D::new(1.0, 0.0), + }; + (texture_id, uv, self.rect.size) + } + }; - data.push(PackedImagePrimitive { - common: PackedPrimitiveInfo { - padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, - part: PrimitivePart::Invalid, - local_clip_rect: self.local_clip_rect, - }, - local_rect: self.rect, - st0: uv_rect.top_left, - st1: uv_rect.bottom_right, - stretch_size: details.stretch_size, - padding: [0, 0], - }); + // TODO(gw): Tidy the support for batch breaks up... + if batch.color_texture_id != TextureId(0) && + batch.color_texture_id != texture_id { + return false; + } + batch.color_texture_id = texture_id; - true + data.push(PackedImagePrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + local_rect: self.rect, + }, + st0: uv_rect.top_left, + st1: uv_rect.bottom_right, + stretch_size: stretch_size, + padding: [0, 0], + }); + + true + } + } } (&mut PrimitiveBatchData::Image(..), _) => false, + (&mut PrimitiveBatchData::ImageClip(ref mut data), &PrimitiveDetails::Image(ref details)) => { + match self.complex_clip { + Some(ref clip) => { + let (texture_id, uv_rect, stretch_size) = match details.kind { + ImagePrimitiveKind::Image(image_key, image_rendering, stretch_size) => { + let info = ctx.resource_cache.get_image(image_key, + image_rendering, + ctx.frame_id); + (info.texture_id, info.uv_rect(), stretch_size) + } + ImagePrimitiveKind::WebGL(context_id) => { + let texture_id = ctx.resource_cache.get_webgl_texture(&context_id); + let uv = RectUv { + top_left: Point2D::new(0.0, 1.0), + top_right: Point2D::new(1.0, 1.0), + bottom_left: Point2D::zero(), + bottom_right: Point2D::new(1.0, 0.0), + }; + (texture_id, uv, self.rect.size) + } + }; + + // TODO(gw): Tidy the support for batch breaks up... + if batch.color_texture_id != TextureId(0) && + batch.color_texture_id != texture_id { + return false; + } + batch.color_texture_id = texture_id; + + data.push(PackedImagePrimitiveClip { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + local_rect: self.rect, + }, + st0: uv_rect.top_left, + st1: uv_rect.bottom_right, + stretch_size: stretch_size, + padding: [0, 0], + clip: (**clip).clone(), + }); + + true + } + None => { + false + } + } + } + (&mut PrimitiveBatchData::ImageClip(..), _) => false, (&mut PrimitiveBatchData::Borders(ref mut data), &PrimitiveDetails::Border(ref details)) => { let inner_radius = BorderRadius { top_left: Size2D::new(details.radius.top_left.width - details.left_width, @@ -795,10 +902,6 @@ impl Primitive { details.radius.bottom_right.width - details.right_width), }; - let clip = Clip::from_border_radius(&self.rect, - &details.radius, - &inner_radius); - data.push(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, @@ -806,11 +909,11 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::TopLeft, local_clip_rect: self.local_clip_rect, + local_rect: rect_from_points_f(details.tl_outer.x, + details.tl_outer.y, + details.tl_inner.x, + details.tl_inner.y), }, - local_rect: rect_from_points_f(details.tl_outer.x, - details.tl_outer.y, - details.tl_inner.x, - details.tl_inner.y), color0: details.top_color, color1: details.left_color, outer_radius_x: details.radius.top_left.width, @@ -830,11 +933,11 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::TopRight, local_clip_rect: self.local_clip_rect, + local_rect: rect_from_points_f(details.tr_inner.x, + details.tr_outer.y, + details.tr_outer.x, + details.tr_inner.y), }, - local_rect: rect_from_points_f(details.tr_inner.x, - details.tr_outer.y, - details.tr_outer.x, - details.tr_inner.y), color0: details.right_color, color1: details.top_color, outer_radius_x: details.radius.top_right.width, @@ -854,11 +957,11 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::BottomLeft, local_clip_rect: self.local_clip_rect, + local_rect: rect_from_points_f(details.bl_outer.x, + details.bl_inner.y, + details.bl_inner.x, + details.bl_outer.y), }, - local_rect: rect_from_points_f(details.bl_outer.x, - details.bl_inner.y, - details.bl_inner.x, - details.bl_outer.y), color0: details.left_color, color1: details.bottom_color, outer_radius_x: details.radius.bottom_left.width, @@ -878,11 +981,11 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::BottomRight, local_clip_rect: self.local_clip_rect, + local_rect: rect_from_points_f(details.br_inner.x, + details.br_inner.y, + details.br_outer.x, + details.br_outer.y), }, - local_rect: rect_from_points_f(details.br_inner.x, - details.br_inner.y, - details.br_outer.x, - details.br_outer.y), color0: details.right_color, color1: details.bottom_color, outer_radius_x: details.radius.bottom_right.width, @@ -902,11 +1005,11 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::Left, local_clip_rect: self.local_clip_rect, + local_rect: rect_from_points_f(details.tl_outer.x, + details.tl_inner.y, + details.tl_outer.x + details.left_width, + details.bl_inner.y), }, - local_rect: rect_from_points_f(details.tl_outer.x, - details.tl_inner.y, - details.tl_outer.x + details.left_width, - details.bl_inner.y), color0: details.left_color, color1: details.left_color, outer_radius_x: 0.0, @@ -926,11 +1029,11 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::Right, local_clip_rect: self.local_clip_rect, + local_rect: rect_from_points_f(details.tr_outer.x - details.right_width, + details.tr_inner.y, + details.br_outer.x, + details.br_inner.y), }, - local_rect: rect_from_points_f(details.tr_outer.x - details.right_width, - details.tr_inner.y, - details.br_outer.x, - details.br_inner.y), color0: details.right_color, color1: details.right_color, outer_radius_x: 0.0, @@ -950,11 +1053,11 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::Top, local_clip_rect: self.local_clip_rect, + local_rect: rect_from_points_f(details.tl_inner.x, + details.tl_outer.y, + details.tr_inner.x, + details.tr_outer.y + details.top_width), }, - local_rect: rect_from_points_f(details.tl_inner.x, - details.tl_outer.y, - details.tr_inner.x, - details.tr_outer.y + details.top_width), color0: details.top_color, color1: details.top_color, outer_radius_x: 0.0, @@ -974,11 +1077,11 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::Bottom, local_clip_rect: self.local_clip_rect, + local_rect: rect_from_points_f(details.bl_inner.x, + details.bl_outer.y - details.bottom_width, + details.br_inner.x, + details.br_outer.y), }, - local_rect: rect_from_points_f(details.bl_inner.x, - details.bl_outer.y - details.bottom_width, - details.br_inner.x, - details.br_outer.y), color0: details.bottom_color, color1: details.bottom_color, outer_radius_x: 0.0, @@ -994,48 +1097,92 @@ impl Primitive { true } (&mut PrimitiveBatchData::Borders(..), _) => false, - (&mut PrimitiveBatchData::Gradient(ref mut data), &PrimitiveDetails::Gradient(ref details)) => { + (&mut PrimitiveBatchData::AlignedGradient(ref mut data), &PrimitiveDetails::Gradient(ref details)) => { + if details.kind == GradientType::Rotated { + return false; + } + let stops = auxiliary_lists.gradient_stops(&details.stops_range); for i in 0..(stops.len() - 1) { let (prev_stop, next_stop) = (&stops[i], &stops[i + 1]); let piece_origin; let piece_size; - match details.dir { - AxisDirection::Horizontal => { - let prev_x = util::lerp(self.rect.origin.x, self.rect.max_x(), prev_stop.offset); - let next_x = util::lerp(self.rect.origin.x, self.rect.max_x(), next_stop.offset); + match details.kind { + GradientType::Horizontal => { + let prev_x = util::lerp(details.start_point.x, details.end_point.x, prev_stop.offset); + let next_x = util::lerp(details.start_point.x, details.end_point.x, next_stop.offset); piece_origin = Point2D::new(prev_x, self.rect.origin.y); piece_size = Size2D::new(next_x - prev_x, self.rect.size.height); } - AxisDirection::Vertical => { - let prev_y = util::lerp(self.rect.origin.y, self.rect.max_y(), prev_stop.offset); - let next_y = util::lerp(self.rect.origin.y, self.rect.max_y(), next_stop.offset); + GradientType::Vertical => { + let prev_y = util::lerp(details.start_point.y, details.end_point.y, prev_stop.offset); + let next_y = util::lerp(details.start_point.y, details.end_point.y, next_stop.offset); piece_origin = Point2D::new(self.rect.origin.x, prev_y); piece_size = Size2D::new(self.rect.size.width, next_y - prev_y); } + GradientType::Rotated => unreachable!(), } let piece_rect = Rect::new(piece_origin, piece_size); - data.push(PackedGradientPrimitive { + data.push(PackedAlignedGradientPrimitive { common: PackedPrimitiveInfo { padding: 0, tile_index: tile_index_in_ubo, layer_index: layer_index_in_ubo, part: PrimitivePart::Bottom, local_clip_rect: self.local_clip_rect, + local_rect: piece_rect, }, - local_rect: piece_rect, color0: prev_stop.color, color1: next_stop.color, padding: [0, 0, 0], - dir: details.dir, + kind: details.kind, + }); + } + + true + } + (&mut PrimitiveBatchData::AlignedGradient(..), _) => false, + (&mut PrimitiveBatchData::AngleGradient(ref mut data), &PrimitiveDetails::Gradient(ref details)) => { + if details.kind != GradientType::Rotated { + return false; + } + + let src_stops = auxiliary_lists.gradient_stops(&details.stops_range); + + if src_stops.len() > MAX_STOPS_PER_ANGLE_GRADIENT { + println!("TODO: Angle gradients with > {} stops", MAX_STOPS_PER_ANGLE_GRADIENT); + } else { + let mut stops: [f32; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { mem::uninitialized() }; + let mut colors: [ColorF; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { mem::uninitialized() }; + + for (stop_index, stop) in src_stops.iter().enumerate() { + stops[stop_index] = stop.offset; + colors[stop_index] = stop.color; + } + + data.push(PackedAngleGradientPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: tile_index_in_ubo, + layer_index: layer_index_in_ubo, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + local_rect: self.rect, + }, + padding: [0, 0, 0], + start_point: details.start_point, + end_point: details.end_point, + stop_count: src_stops.len() as u32, + stops: stops, + colors: colors, }); } true } - (&mut PrimitiveBatchData::Gradient(..), _) => false, + (&mut PrimitiveBatchData::AngleGradient(..), _) => false, (&mut PrimitiveBatchData::BoxShadows(ref mut data), &PrimitiveDetails::BoxShadow(ref details)) => { let mut rects = Vec::new(); let inverted = match details.clip_mode { @@ -1057,8 +1204,8 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, + local_rect: rect, }, - local_rect: rect, color: details.color, border_radii: Point2D::new(details.border_radius, details.border_radius), @@ -1104,9 +1251,9 @@ impl Primitive { layer_index: layer_index_in_ubo, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, + local_rect: Rect::new(Point2D::new(x, y), + Size2D::new(width, height)), }, - local_rect: Rect::new(Point2D::new(x, y), - Size2D::new(width, height)), color: details.color, st0: uv_rect.top_left, st1: uv_rect.bottom_right, @@ -1135,40 +1282,6 @@ enum PrimitivePart { Right, } -#[derive(Debug, Clone)] -pub struct CompositeTile { - pub screen_rect: Rect, - pub src_rects: [Rect; MAX_LAYERS_PER_PASS], - pub blend_info: [f32; MAX_LAYERS_PER_PASS], -} - -impl CompositeTile { - fn new(rect: &Rect) -> CompositeTile { - CompositeTile { - screen_rect: *rect, - src_rects: unsafe { mem::uninitialized() }, - blend_info: [ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ], - } - } -} - -#[derive(Debug, Eq, PartialEq, Hash, Clone)] -pub struct CompositeBatchKey { - pub shader: CompositeShader, - //pub samplers: [TextureId; MAX_PRIMS_PER_COMPOSITE], -} - -impl CompositeBatchKey { - fn new(shader: CompositeShader, - //samplers: [TextureId; MAX_PRIMS_PER_COMPOSITE] - ) -> CompositeBatchKey { - CompositeBatchKey { - shader: shader, - //samplers: samplers, - } - } -} - // All Packed Primitives below must be 16 byte aligned. #[derive(Debug)] pub struct PackedTile { @@ -1180,21 +1293,8 @@ pub struct PackedTile { pub struct PackedLayer { transform: Matrix4D, inv_transform: Matrix4D, + world_clip_rect: Rect, screen_vertices: [Point4D; 4], - blend_info: [f32; 2], - padding: [u32; 2], -} - -#[derive(Debug)] -pub struct PackedRenderable { - transform: Matrix4D, - local_rect: Rect, - cache_rect: Rect, - screen_rect: Rect, - st0: Point2D, - st1: Point2D, - offset: Point2D, - blend_info: [f32; 2], } #[derive(Debug, Clone)] @@ -1204,18 +1304,12 @@ pub struct PackedPrimitiveInfo { part: PrimitivePart, padding: u32, local_clip_rect: Rect, -} - -#[derive(Debug)] -pub struct PackedFixedRectangle { - common: PackedPrimitiveInfo, - color: ColorF, + local_rect: Rect, } #[derive(Debug, Clone)] pub struct PackedRectanglePrimitiveClip { common: PackedPrimitiveInfo, - local_rect: Rect, color: ColorF, clip: Clip, } @@ -1223,14 +1317,12 @@ pub struct PackedRectanglePrimitiveClip { #[derive(Debug, Clone)] pub struct PackedRectanglePrimitive { common: PackedPrimitiveInfo, - local_rect: Rect, color: ColorF, } #[derive(Debug, Clone)] pub struct PackedGlyphPrimitive { common: PackedPrimitiveInfo, - local_rect: Rect, color: ColorF, st0: Point2D, st1: Point2D, @@ -1239,7 +1331,6 @@ pub struct PackedGlyphPrimitive { #[derive(Debug, Clone)] pub struct PackedImagePrimitive { common: PackedPrimitiveInfo, - local_rect: Rect, st0: Point2D, st1: Point2D, stretch_size: Size2D, @@ -1247,19 +1338,40 @@ pub struct PackedImagePrimitive { } #[derive(Debug, Clone)] -pub struct PackedGradientPrimitive { +pub struct PackedImagePrimitiveClip { + common: PackedPrimitiveInfo, + st0: Point2D, + st1: Point2D, + stretch_size: Size2D, + padding: [u32; 2], + clip: Clip, +} + +#[derive(Debug, Clone)] +pub struct PackedAlignedGradientPrimitive { common: PackedPrimitiveInfo, - local_rect: Rect, color0: ColorF, color1: ColorF, - dir: AxisDirection, + kind: GradientType, + padding: [u32; 3], +} + +// TODO(gw): Angle gradient only support 8 stops due +// to limits of interpolators. FIXME! +#[derive(Debug, Clone)] +pub struct PackedAngleGradientPrimitive { + common: PackedPrimitiveInfo, + start_point: Point2D, + end_point: Point2D, + stop_count: u32, padding: [u32; 3], + colors: [ColorF; MAX_STOPS_PER_ANGLE_GRADIENT], + stops: [f32; MAX_STOPS_PER_ANGLE_GRADIENT], } #[derive(Debug, Clone)] pub struct PackedBorderPrimitive { common: PackedPrimitiveInfo, - local_rect: Rect, color0: ColorF, color1: ColorF, outer_radius_x: f32, @@ -1275,7 +1387,6 @@ pub struct PackedBorderPrimitive { #[derive(Debug, Clone)] pub struct PackedBoxShadowPrimitive { common: PackedPrimitiveInfo, - local_rect: Rect, color: ColorF, border_radii: Point2D, blur_radius: f32, @@ -1284,6 +1395,71 @@ pub struct PackedBoxShadowPrimitive { src_rect: Rect, } +#[derive(Debug, Clone)] +pub struct PackedBlendPrimitive { + target_rect: Rect, + src_rect: Rect, + opacity: f32, + padding: [u32; 3], +} + +#[derive(Debug, Copy, Clone)] +struct PackedCompositeInfo { + kind: u32, + op: u32, + padding: [u32; 2], + amount: f32, + padding1: [u32; 3], +} + +impl PackedCompositeInfo { + fn new(ops: &Vec) -> PackedCompositeInfo { + // TODO(gw): Support chained filters + let op = &ops[0]; + + let (kind, op, amount) = match op { + &CompositionOp::MixBlend(mode) => { + (0, mode as u32, 0.0) + } + &CompositionOp::Filter(filter) => { + let (filter_mode, amount) = match filter { + LowLevelFilterOp::Blur(..) => (0, 0.0), + LowLevelFilterOp::Contrast(amount) => (1, amount.to_f32_px()), + LowLevelFilterOp::Grayscale(amount) => (2, amount.to_f32_px()), + LowLevelFilterOp::HueRotate(angle) => (3, (angle as f32) / ANGLE_FLOAT_TO_FIXED), + LowLevelFilterOp::Invert(amount) => (4, amount.to_f32_px()), + LowLevelFilterOp::Saturate(amount) => (5, amount.to_f32_px()), + LowLevelFilterOp::Sepia(amount) => (6, amount.to_f32_px()), + LowLevelFilterOp::Brightness(_) | + LowLevelFilterOp::Opacity(_) => { + // Expressible using GL blend modes, so not handled + // here. + unreachable!() + } + }; + + (1, filter_mode, amount) + } + }; + + PackedCompositeInfo { + kind: kind, + op: op, + padding: [0, 0], + amount: amount, + padding1: [0, 0, 0], + } + } +} + +#[derive(Debug)] +pub struct PackedCompositePrimitive { + rect0: Rect, + rect1: Rect, + target_rect: Rect, + info: PackedCompositeInfo, +} + #[derive(Debug)] pub enum PrimitiveBatchData { Rectangles(Vec), @@ -1292,18 +1468,105 @@ pub enum PrimitiveBatchData { BoxShadows(Vec), Text(Vec), Image(Vec), - Gradient(Vec), + ImageClip(Vec), + Blend(Vec), + Composite(Vec), + AlignedGradient(Vec), + AngleGradient(Vec), } #[derive(Debug)] pub struct PrimitiveBatch { pub transform_kind: TransformedRectKind, pub color_texture_id: TextureId, // TODO(gw): Expand to sampler array to handle all glyphs! + pub layer_ubo_index: usize, + pub tile_ubo_index: usize, pub data: PrimitiveBatchData, } impl PrimitiveBatch { - fn new(prim: &Primitive, transform_kind: TransformedRectKind) -> PrimitiveBatch { + fn blend(src_rect: Rect, + target_rect: Rect, + opacity: f32) -> PrimitiveBatch { + let blend = PackedBlendPrimitive { + src_rect: src_rect, + target_rect: target_rect, + opacity: opacity, + padding: [0, 0, 0], + }; + + PrimitiveBatch { + color_texture_id: TextureId(0), + transform_kind: TransformedRectKind::AxisAligned, + layer_ubo_index: 0, + tile_ubo_index: 0, + data: PrimitiveBatchData::Blend(vec![blend]), + } + } + + fn composite(first_src_rect: Rect, + second_src_rect: Rect, + target_rect: Rect, + info: PackedCompositeInfo) -> PrimitiveBatch { + let composite = PackedCompositePrimitive { + rect0: first_src_rect, + rect1: second_src_rect, + target_rect: target_rect, + info: info, + }; + + PrimitiveBatch { + color_texture_id: TextureId(0), + transform_kind: TransformedRectKind::AxisAligned, + layer_ubo_index: 0, + tile_ubo_index: 0, + data: PrimitiveBatchData::Composite(vec![composite]), + } + } + + fn pack_blend(&mut self, + src_rect: Rect, + target_rect: Rect, + opacity: f32) -> bool { + match &mut self.data { + &mut PrimitiveBatchData::Blend(ref mut ubo_data) => { + ubo_data.push(PackedBlendPrimitive { + opacity: opacity, + padding: [0, 0, 0], + src_rect: src_rect, + target_rect: target_rect, + }); + + true + } + _ => false + } + } + + fn pack_composite(&mut self, + rect0: Rect, + rect1: Rect, + target_rect: Rect, + info: PackedCompositeInfo) -> bool { + match &mut self.data { + &mut PrimitiveBatchData::Composite(ref mut ubo_data) => { + ubo_data.push(PackedCompositePrimitive { + rect0: rect0, + rect1: rect1, + target_rect: target_rect, + info: info, + }); + + true + } + _ => false + } + } + + fn new(prim: &Primitive, + transform_kind: TransformedRectKind, + layer_ubo_index: usize, + tile_ubo_index: usize) -> PrimitiveBatch { let data = match prim.details { PrimitiveDetails::Rectangle(..) => { match prim.complex_clip { @@ -1321,68 +1584,149 @@ impl PrimitiveBatch { PrimitiveBatchData::Text(Vec::new()) } PrimitiveDetails::Image(..) => { - PrimitiveBatchData::Image(Vec::new()) + match prim.complex_clip { + Some(..) => PrimitiveBatchData::ImageClip(Vec::new()), + None => PrimitiveBatchData::Image(Vec::new()), + } } - PrimitiveDetails::Gradient(..) => { - PrimitiveBatchData::Gradient(Vec::new()) + PrimitiveDetails::Gradient(ref details) => { + match details.kind { + GradientType::Rotated => { + PrimitiveBatchData::AngleGradient(Vec::new()) + } + GradientType::Horizontal | GradientType::Vertical => { + PrimitiveBatchData::AlignedGradient(Vec::new()) + } + } } }; - let mut this = PrimitiveBatch { + PrimitiveBatch { color_texture_id: TextureId(0), transform_kind: transform_kind, + layer_ubo_index: layer_ubo_index, + tile_ubo_index: tile_ubo_index, data: data, - }; - - this + } } } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct StackingContextChunkIndex(usize); +pub struct ScreenTileLayerIndex(usize); -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct StackingContextIndex(usize); +enum StackingContextItem { + StackingContext(StackingContextIndex), + Primitive(PrimitiveIndex), +} + struct StackingContext { pipeline_id: PipelineId, local_transform: Matrix4D, local_rect: Rect, local_offset: Point2D, - primitives: Vec, + items: Vec, scroll_layer_id: ScrollLayerId, - opacity: f32, transform: Matrix4D, xf_rect: Option, + is_valid: bool, + composition_ops: Vec, + local_clip_rect: Rect, + world_clip_rect: Option>, + parent: Option, +} + +#[derive(Debug, Copy, Clone)] +enum CompositeKind { + None, + Simple(f32), + Complex(PackedCompositeInfo), } impl StackingContext { fn build_resource_list(&self, resource_list: &mut ResourceList, - //index_buffer: &Vec, - auxiliary_lists: &AuxiliaryLists) { -// for prim_index in index_buffer { -// let PrimitiveIndex(prim_index) = *prim_index; -// let prim = &self.primitives[prim_index]; - for prim in &self.primitives { - match prim.details { - PrimitiveDetails::Rectangle(..) => {} - PrimitiveDetails::Gradient(..) => {} - PrimitiveDetails::Border(..) => {} - PrimitiveDetails::BoxShadow(..) => {} - PrimitiveDetails::Image(ref details) => { - resource_list.add_image(details.image_key, - details.image_rendering); + auxiliary_lists: &AuxiliaryLists, + prim_store: &Vec) { + for item in &self.items { + match item { + &StackingContextItem::StackingContext(..) => {} + &StackingContextItem::Primitive(prim_index) => { + let prim = &prim_store[prim_index.0]; + match prim.details { + PrimitiveDetails::Rectangle(..) => {} + PrimitiveDetails::Gradient(..) => {} + PrimitiveDetails::Border(..) => {} + PrimitiveDetails::BoxShadow(..) => {} + PrimitiveDetails::Image(ref details) => { + match details.kind { + ImagePrimitiveKind::Image(image_key, image_rendering, _) => { + resource_list.add_image(image_key, image_rendering); + } + ImagePrimitiveKind::WebGL(..) => {} + } + } + PrimitiveDetails::Text(ref details) => { + let glyphs = auxiliary_lists.glyph_instances(&details.glyph_range); + for glyph in glyphs { + let glyph = Glyph::new(details.size, details.blur_radius, glyph.index); + resource_list.add_glyph(details.font_key, glyph); + } + } + } } - PrimitiveDetails::Text(ref details) => { - let glyphs = auxiliary_lists.glyph_instances(&details.glyph_range); - for glyph in glyphs { - let glyph = Glyph::new(details.size, details.blur_radius, glyph.index); - resource_list.add_glyph(details.font_key, glyph); + } + } + } + + fn can_contribute_to_scene(&self) -> bool { + for op in &self.composition_ops { + match op { + &CompositionOp::Filter(filter_op) => { + match filter_op { + LowLevelFilterOp::Opacity(opacity) => { + if opacity == Au(0) { + return false + } + } + _ => {} } } + _ => {} } } + + true + } + + fn composite_kind(&self) -> CompositeKind { + if self.composition_ops.is_empty() { + return CompositeKind::None; + } + + if self.composition_ops.len() == 1 { + match self.composition_ops.first().unwrap() { + &CompositionOp::Filter(filter_op) => { + match filter_op { + LowLevelFilterOp::Opacity(opacity) => { + let opacity = opacity.to_f32_px(); + if opacity == 1.0 { + return CompositeKind::None; + } else { + return CompositeKind::Simple(opacity); + } + } + _ => {} + } + } + _ => {} + } + } + + let info = PackedCompositeInfo::new(&self.composition_ops); + CompositeKind::Complex(info) } } @@ -1430,7 +1774,8 @@ impl FrameBuilderConfig { pub struct FrameBuilder { screen_rect: Rect, - layers: Vec, + prim_store: Vec, + layer_store: Vec, layer_stack: Vec, device_pixel_ratio: f32, debug: bool, @@ -1485,109 +1830,11 @@ impl Clip { }, } } - - pub fn from_border_radius(rect: &Rect, - outer_radius: &BorderRadius, - inner_radius: &BorderRadius) -> Clip { - Clip { - rect: *rect, - top_left: ClipCorner { - rect: Rect::new(Point2D::new(rect.origin.x, rect.origin.y), - Size2D::new(outer_radius.top_left.width, outer_radius.top_left.height)), - outer_radius_x: outer_radius.top_left.width, - outer_radius_y: outer_radius.top_left.height, - inner_radius_x: inner_radius.top_left.width, - inner_radius_y: inner_radius.top_left.height, - }, - top_right: ClipCorner { - rect: Rect::new(Point2D::new(rect.origin.x + rect.size.width - outer_radius.top_right.width, - rect.origin.y), - Size2D::new(outer_radius.top_right.width, outer_radius.top_right.height)), - outer_radius_x: outer_radius.top_right.width, - outer_radius_y: outer_radius.top_right.height, - inner_radius_x: inner_radius.top_right.width, - inner_radius_y: inner_radius.top_right.height, - }, - bottom_left: ClipCorner { - rect: Rect::new(Point2D::new(rect.origin.x, - rect.origin.y + rect.size.height - outer_radius.bottom_left.height), - Size2D::new(outer_radius.bottom_left.width, outer_radius.bottom_left.height)), - outer_radius_x: outer_radius.bottom_left.width, - outer_radius_y: outer_radius.bottom_left.height, - inner_radius_x: inner_radius.bottom_left.width, - inner_radius_y: inner_radius.bottom_left.height, - }, - bottom_right: ClipCorner { - rect: Rect::new(Point2D::new(rect.origin.x + rect.size.width - outer_radius.bottom_right.width, - rect.origin.y + rect.size.height - outer_radius.bottom_right.height), - Size2D::new(outer_radius.bottom_right.width, outer_radius.bottom_right.height)), - outer_radius_x: outer_radius.bottom_right.width, - outer_radius_y: outer_radius.bottom_right.height, - inner_radius_x: inner_radius.bottom_right.width, - inner_radius_y: inner_radius.bottom_right.height, - }, - } - } -} - -#[derive(Debug)] -struct CompositeTileInfo { - layer_indices: Vec>, -} - -#[derive(Debug)] -struct ScreenTileLayer { - actual_rect: Rect, - layer_index: StackingContextIndex, - prim_indices: Vec, // todo(gw): pre-build these into parts to save duplicated cpu time? - layer_opacity: f32, - is_opaque: bool, -} - -impl ScreenTileLayer { - fn compile(&mut self, - layer: &StackingContext, - screen_rect: &Rect) { - self.prim_indices.sort_by(|a, b| { - b.cmp(&a) - }); - self.prim_indices.dedup(); - -/* - // Intra-layer occlusion - let first_opaque_cover_index = self.prim_indices.iter().position(|i| { - let PrimitiveIndex(pi) = *i; - let prim = &layer.primitives[pi]; - prim.is_opaque() && - rect_contains_rect(&prim.xf_rect.as_ref().unwrap().bounding_rect, screen_rect) - }); - if let Some(first_opaque_cover_index) = first_opaque_cover_index { - self.prim_indices.truncate(first_opaque_cover_index); - } -*/ - - // Inter-layer occlusion - let PrimitiveIndex(pi) = *self.prim_indices.last().unwrap(); - let last_prim = &layer.primitives[pi]; - if layer.opacity == 1.0 && - last_prim.is_opaque() && - layer.xf_rect.as_ref().unwrap().kind == TransformedRectKind::AxisAligned && - rect_contains_rect(&last_prim.xf_rect.as_ref().unwrap().bounding_rect, - screen_rect) { - self.is_opaque = true; - } - } } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct ScreenTileIndex(usize); -enum ScreenTileCompileResult { - Clear, - Unhandled, - Ok, -} - #[derive(Debug)] struct CompiledScreenTile { main_render_task: RenderTask, @@ -1606,69 +1853,113 @@ impl CompiledScreenTile { } } +#[derive(Debug, Eq, PartialEq, Copy, Clone)] +enum TileCommand { + PushLayer(StackingContextIndex), + PopLayer, + DrawPrimitive(PrimitiveIndex), +} + #[derive(Debug)] struct ScreenTile { rect: Rect, - layers: Vec, + cmds: Vec, + prim_count: usize, } impl ScreenTile { fn new(rect: Rect) -> ScreenTile { ScreenTile { rect: rect, - layers: Vec::new(), + cmds: Vec::new(), + prim_count: 0, } } - fn layer_count(&self) -> usize { - self.layers.len() + #[inline(always)] + fn push_layer(&mut self, sc_index: StackingContextIndex) { + self.cmds.push(TileCommand::PushLayer(sc_index)); + } + + #[inline(always)] + fn push_primitive(&mut self, prim_index: PrimitiveIndex) { + self.cmds.push(TileCommand::DrawPrimitive(prim_index)); + self.prim_count += 1; } - fn compile(mut self) -> Option { - if self.layers.len() == 0 { + #[inline(always)] + fn pop_layer(&mut self, sc_index: StackingContextIndex) { + let last_cmd = *self.cmds.last().unwrap(); + if last_cmd == TileCommand::PushLayer(sc_index) { + self.cmds.pop(); + } else { + self.cmds.push(TileCommand::PopLayer); + } + } + + fn compile(self, + layer_store: &Vec) -> Option { + if self.prim_count == 0 { return None; } - // TODO(gw): If a single had blending, fall through to the - // compositing case below. Investigate if it's - // worth having a special path for this? - if self.layers.len() == 1 && self.layers[0].layer_opacity == 1.0 { - let task = RenderTask::from_layer(self.layers.pop().unwrap(), - RenderTaskLocation::Fixed(self.rect)); - Some(CompiledScreenTile::new(task)) - } else { - let mut layer_indices_in_current_layer = Vec::new(); - let mut tasks_in_current_layer = Vec::new(); - - for layer in self.layers.drain(..) { - if tasks_in_current_layer.len() == MAX_LAYERS_PER_PASS { - let composite_location = RenderTaskLocation::Dynamic(None, self.rect.size); - let tasks_to_composite = mem::replace(&mut tasks_in_current_layer, Vec::new()); - let layers_to_composite = mem::replace(&mut layer_indices_in_current_layer, - Vec::new()); - let composite_task = RenderTask::composite(tasks_to_composite, - composite_location, - layers_to_composite); - debug_assert!(tasks_in_current_layer.is_empty()); - tasks_in_current_layer.push(composite_task); - layer_indices_in_current_layer.push(None); + let mut sc_stack = Vec::new(); + let mut current_task = AlphaRenderTask::new(self.rect); + let mut alpha_task_stack = Vec::new(); + + for cmd in self.cmds { + match cmd { + TileCommand::PushLayer(sc_index) => { + sc_stack.push(sc_index); + + let layer = &layer_store[sc_index.0]; + match layer.composite_kind() { + CompositeKind::None => {} + CompositeKind::Simple(..) | CompositeKind::Complex(..) => { + let prev_task = mem::replace(&mut current_task, AlphaRenderTask::new(self.rect)); + alpha_task_stack.push(prev_task); + } + } } + TileCommand::PopLayer => { + let sc_index = sc_stack.pop().unwrap(); + + let layer = &layer_store[sc_index.0]; + match layer.composite_kind() { + CompositeKind::None => {} + CompositeKind::Simple(opacity) => { + let mut prev_task = alpha_task_stack.pop().unwrap(); + prev_task.items.push(AlphaRenderItem::Blend(prev_task.children.len(), + opacity)); + prev_task.children.push(current_task); + current_task = prev_task; + } + CompositeKind::Complex(info) => { + let backdrop = alpha_task_stack.pop().unwrap(); - layer_indices_in_current_layer.push(Some(layer.layer_index)); - let layer_task = RenderTask::from_layer(layer, - RenderTaskLocation::Dynamic(None, - self.rect.size)); - tasks_in_current_layer.push(layer_task); - } + let mut composite_task = AlphaRenderTask::new(self.rect); + composite_task.children.push(backdrop); + composite_task.children.push(current_task); - debug_assert!(!tasks_in_current_layer.is_empty()); - let main_task = RenderTask::composite(tasks_in_current_layer, - RenderTaskLocation::Fixed(self.rect), - layer_indices_in_current_layer); + composite_task.items.push(AlphaRenderItem::Composite(info)); - Some(CompiledScreenTile::new(main_task)) + current_task = composite_task; + } + } + } + TileCommand::DrawPrimitive(prim_index) => { + let sc_index = *sc_stack.last().unwrap(); + current_task.items.push(AlphaRenderItem::Primitive(sc_index, prim_index)); + } + } } + debug_assert!(alpha_task_stack.is_empty()); + + let task = RenderTask::from_primitives(current_task, + RenderTaskLocation::Fixed(self.rect), + self.rect.size); + Some(CompiledScreenTile::new(task)) } } @@ -1680,7 +1971,8 @@ impl FrameBuilder { let viewport_size = Size2D::new(viewport_size.width as i32, viewport_size.height as i32); FrameBuilder { screen_rect: Rect::new(Point2D::zero(), viewport_size), - layers: Vec::new(), + layer_store: Vec::new(), + prim_store: Vec::new(), layer_stack: Vec::new(), device_pixel_ratio: device_pixel_ratio, debug: debug, @@ -1695,40 +1987,55 @@ impl FrameBuilder { details: PrimitiveDetails) { let current_layer = *self.layer_stack.last().unwrap(); let StackingContextIndex(layer_index) = current_layer; - let layer = &mut self.layers[layer_index as usize]; + let layer = &mut self.layer_store[layer_index as usize]; let prim = Primitive { rect: *rect, - xf_rect: None, complex_clip: clip, local_clip_rect: *clip_rect, details: details, }; - layer.primitives.push(prim); + let prim_index = self.prim_store.len(); + self.prim_store.push(prim); + + layer.items.push(StackingContextItem::Primitive(PrimitiveIndex(prim_index))); } pub fn push_layer(&mut self, rect: Rect, - _clip_rect: Rect, + clip_rect: Rect, transform: Matrix4D, - opacity: f32, pipeline_id: PipelineId, scroll_layer_id: ScrollLayerId, - offset: Point2D) { + offset: Point2D, + composition_operations: Vec) { + let sc_index = StackingContextIndex(self.layer_store.len()); + let sc = StackingContext { - primitives: Vec::new(), + items: Vec::new(), local_rect: rect, local_transform: transform, local_offset: offset, scroll_layer_id: scroll_layer_id, - opacity: opacity, pipeline_id: pipeline_id, xf_rect: None, transform: Matrix4D::identity(), + is_valid: false, + composition_ops: composition_operations, + local_clip_rect: clip_rect, + world_clip_rect: None, + parent: self.layer_stack.last().map(|index| *index), }; + self.layer_store.push(sc); - self.layer_stack.push(StackingContextIndex(self.layers.len())); - self.layers.push(sc); + if !self.layer_stack.is_empty() { + let current_layer = *self.layer_stack.last().unwrap(); + let StackingContextIndex(layer_index) = current_layer; + let layer = &mut self.layer_store[layer_index as usize]; + layer.items.push(StackingContextItem::StackingContext(sc_index)); + } + + self.layer_stack.push(sc_index); } pub fn pop_layer(&mut self) { @@ -1847,29 +2154,38 @@ impl FrameBuilder { stops: ItemRange) { // Fast paths for axis-aligned gradients: if start_point.x == end_point.x { - let rect = Rect::new(Point2D::new(rect.origin.x, start_point.y), - Size2D::new(rect.size.width, end_point.y - start_point.y)); let prim = GradientPrimitive { stops_range: stops, - dir: AxisDirection::Vertical, + kind: GradientType::Vertical, + start_point: start_point, + end_point: end_point, }; self.add_primitive(&rect, clip_rect, clip, PrimitiveDetails::Gradient(prim)); } else if start_point.y == end_point.y { - let rect = Rect::new(Point2D::new(start_point.x, rect.origin.y), - Size2D::new(end_point.x - start_point.x, rect.size.height)); let prim = GradientPrimitive { stops_range: stops, - dir: AxisDirection::Horizontal, + kind: GradientType::Horizontal, + start_point: start_point, + end_point: end_point, }; self.add_primitive(&rect, clip_rect, clip, PrimitiveDetails::Gradient(prim)); } else { - //println!("TODO: Angle gradients! {:?} {:?} {:?}", start_point, end_point, stops); + let prim = GradientPrimitive { + stops_range: stops, + kind: GradientType::Rotated, + start_point: start_point, + end_point: end_point, + }; + self.add_primitive(&rect, + clip_rect, + clip, + PrimitiveDetails::Gradient(prim)); } } @@ -1959,6 +2275,21 @@ impl FrameBuilder { PrimitiveDetails::BoxShadow(prim)); } + pub fn add_webgl_rectangle(&mut self, + rect: Rect, + clip_rect: &Rect, + clip: Option>, + context_id: WebGLContextId) { + let prim = ImagePrimitive { + kind: ImagePrimitiveKind::WebGL(context_id), + }; + + self.add_primitive(&rect, + clip_rect, + clip, + PrimitiveDetails::Image(prim)); + } + pub fn add_image(&mut self, rect: Rect, clip_rect: &Rect, @@ -1967,9 +2298,9 @@ impl FrameBuilder { image_key: ImageKey, image_rendering: ImageRendering) { let prim = ImagePrimitive { - image_key: image_key, - image_rendering: image_rendering, - stretch_size: stretch_size.clone(), + kind: ImagePrimitiveKind::Image(image_key, + image_rendering, + stretch_size.clone()), }; self.add_primitive(&rect, @@ -1982,61 +2313,76 @@ impl FrameBuilder { screen_rect: &Rect, layer_map: &HashMap>) { // Remove layers that are transparent. - self.layers.retain(|layer| { - layer.opacity > 0.0 - }); // Build layer screen rects. // TODO(gw): This can be done earlier once update_layer_transforms() is fixed. - for layer in &mut self.layers { - let scroll_layer = &layer_map[&layer.scroll_layer_id]; - let offset_transform = Matrix4D::identity().translate(layer.local_offset.x, - layer.local_offset.y, - 0.0); - let transform = scroll_layer.world_transform - .as_ref() - .unwrap() - .mul(&layer.local_transform) - .mul(&offset_transform); - layer.transform = transform; - layer.xf_rect = Some(TransformedRect::new(&layer.local_rect, - &transform, - self.device_pixel_ratio)); - } - - self.layers.retain(|layer| { - layer.xf_rect - .as_ref() - .unwrap() - .bounding_rect - .intersects(&screen_rect) - }); - - for layer in &mut self.layers { - for prim in &mut layer.primitives { - prim.xf_rect = Some(TransformedRect::new(&prim.rect, - &layer.transform, - self.device_pixel_ratio)); - } - - layer.primitives.retain(|prim| { - prim.xf_rect - .as_ref() - .unwrap() - .bounding_rect - .intersects(&screen_rect) + for layer_index in 0..self.layer_store.len() { + let parent_index = self.layer_store[layer_index].parent; + let parent_clip_rect = parent_index.map_or(Some(*screen_rect), |parent_index| { + self.layer_store[parent_index.0].world_clip_rect }); + if parent_clip_rect.is_none() { + continue; + } + let layer = &mut self.layer_store[layer_index]; + + if layer.can_contribute_to_scene() { + let scroll_layer = &layer_map[&layer.scroll_layer_id]; + let offset_transform = Matrix4D::identity().translate(layer.local_offset.x, + layer.local_offset.y, + 0.0); + let transform = scroll_layer.world_transform + .as_ref() + .unwrap() + .mul(&layer.local_transform) + .mul(&offset_transform); + layer.transform = transform; + layer.xf_rect = Some(TransformedRect::new(&layer.local_rect, + &transform, + self.device_pixel_ratio)); + + let world_clip_rect = TransformedRect::new(&layer.local_clip_rect, + &transform, + self.device_pixel_ratio); + + // TODO(gw): This gets the iframe reftests passing but is questionable. + // Need to refactor the whole layer viewport_rect code once + // WR2 lands since it can be simplified now. + let origin = Point2D::new(DevicePixel::new(scroll_layer.viewport_rect.origin.x, + self.device_pixel_ratio), + DevicePixel::new(scroll_layer.viewport_rect.origin.y, + self.device_pixel_ratio)); + let size = Size2D::new(DevicePixel::new(scroll_layer.viewport_rect.size.width, + self.device_pixel_ratio), + DevicePixel::new(scroll_layer.viewport_rect.size.height, + self.device_pixel_ratio)); + let viewport_rect = Rect::new(origin, size); + + layer.world_clip_rect = world_clip_rect.bounding_rect + .intersection(&parent_clip_rect.unwrap()) + .and_then(|cr| { + cr.intersection(&viewport_rect) + }); + + if layer.world_clip_rect.is_some() { + layer.is_valid = layer.xf_rect + .as_ref() + .unwrap() + .bounding_rect + .intersects(&screen_rect); + } + } } } - fn create_screen_tiles(&self) -> Vec { + fn create_screen_tiles(&self) -> (i32, i32, Vec) { let dp_size = Size2D::new(DevicePixel::new(self.screen_rect.size.width as f32, self.device_pixel_ratio), DevicePixel::new(self.screen_rect.size.height as f32, self.device_pixel_ratio)); - let x_tile_size = DevicePixel(SCREEN_TILE_SIZE as i32); - let y_tile_size = DevicePixel(SCREEN_TILE_SIZE as i32); + let x_tile_size = DevicePixel(SCREEN_TILE_SIZE); + let y_tile_size = DevicePixel(SCREEN_TILE_SIZE); let x_tile_count = (dp_size.width + x_tile_size - DevicePixel(1)).0 / x_tile_size.0; let y_tile_count = (dp_size.height + y_tile_size - DevicePixel(1)).0 / y_tile_size.0; @@ -2056,59 +2402,96 @@ impl FrameBuilder { } } - screen_tiles + (x_tile_count, y_tile_count, screen_tiles) } fn assign_prims_to_screen_tiles(&self, - screen_tiles: &mut Vec, - debug_rects: &mut Vec) { //-> usize { - //let mut pass_count = 0; + stacking_context_index: StackingContextIndex, + x_tile_count: i32, + y_tile_count: i32, + screen_tiles: &mut Vec) { + let layer = &self.layer_store[stacking_context_index.0]; + if !layer.is_valid { + return; + } - // TODO(gw): This can be made much faster - calculate tile indices and - // assign in a loop. - for screen_tile in screen_tiles { - let mut prim_count = 0; - for (layer_index, layer) in self.layers - .iter() - .enumerate() { - let layer_index = StackingContextIndex(layer_index); - let layer_rect = layer.xf_rect.as_ref().unwrap().bounding_rect; - - if layer_rect.intersects(&screen_tile.rect) { - let mut tile_layer = ScreenTileLayer { - actual_rect: screen_tile.rect, - layer_index: layer_index, - prim_indices: Vec::new(), - layer_opacity: layer.opacity, - is_opaque: false, - }; - for (prim_index, prim) in layer.primitives.iter().enumerate() { - let prim_rect = &prim.xf_rect.as_ref().unwrap().bounding_rect; - if prim_rect.intersects(&screen_tile.rect) { - prim_count += 1; - tile_layer.prim_indices.push(PrimitiveIndex(prim_index)); - } - } - if tile_layer.prim_indices.len() > 0 { - tile_layer.compile(layer, &screen_tile.rect); - if tile_layer.is_opaque { - screen_tile.layers.clear(); + let l_rect = &layer.xf_rect.as_ref().unwrap().bounding_rect; + + let l_tile_x0 = l_rect.origin.x.0 / SCREEN_TILE_SIZE; + let l_tile_y0 = l_rect.origin.y.0 / SCREEN_TILE_SIZE; + let l_tile_x1 = (l_rect.origin.x.0 + l_rect.size.width.0 + SCREEN_TILE_SIZE - 1) / SCREEN_TILE_SIZE; + let l_tile_y1 = (l_rect.origin.y.0 + l_rect.size.height.0 + SCREEN_TILE_SIZE - 1) / SCREEN_TILE_SIZE; + + let l_tile_x0 = cmp::min(l_tile_x0, x_tile_count); + let l_tile_x0 = cmp::max(l_tile_x0, 0); + let l_tile_x1 = cmp::min(l_tile_x1, x_tile_count); + let l_tile_x1 = cmp::max(l_tile_x1, 0); + + let l_tile_y0 = cmp::min(l_tile_y0, y_tile_count); + let l_tile_y0 = cmp::max(l_tile_y0, 0); + let l_tile_y1 = cmp::min(l_tile_y1, y_tile_count); + let l_tile_y1 = cmp::max(l_tile_y1, 0); + + for ly in l_tile_y0..l_tile_y1 { + for lx in l_tile_x0..l_tile_x1 { + let tile = &mut screen_tiles[(ly * x_tile_count + lx) as usize]; + tile.push_layer(stacking_context_index); + } + } + + for item in &layer.items { + match item { + &StackingContextItem::StackingContext(sc_index) => { + self.assign_prims_to_screen_tiles(sc_index, + x_tile_count, + y_tile_count, + screen_tiles); + } + &StackingContextItem::Primitive(prim_index) => { + let prim = &self.prim_store[prim_index.0]; + + let p_rect = TransformedRect::new(&prim.rect, + &layer.transform, + self.device_pixel_ratio); + let p_rect = &p_rect.bounding_rect; + + // TODO(gw): Ensure that certain primitives (such as background-image) only get + // assigned to tiles where their containing layer intersects with. + // Does this cause any problems / demonstrate other bugs? + // Restrict the tiles by clamping to the layer tile indices... + //debug_assert!(rect_contains_rect(l_rect, p_rect), format!("layer={:?} prim={:?}", l_rect, p_rect)); + + let p_tile_x0 = p_rect.origin.x.0 / SCREEN_TILE_SIZE; + let p_tile_y0 = p_rect.origin.y.0 / SCREEN_TILE_SIZE; + let p_tile_x1 = (p_rect.origin.x.0 + p_rect.size.width.0 + SCREEN_TILE_SIZE - 1) / SCREEN_TILE_SIZE; + let p_tile_y1 = (p_rect.origin.y.0 + p_rect.size.height.0 + SCREEN_TILE_SIZE - 1) / SCREEN_TILE_SIZE; + + let p_tile_x0 = cmp::min(p_tile_x0, l_tile_x1); + let p_tile_x0 = cmp::max(p_tile_x0, l_tile_x0); + let p_tile_x1 = cmp::min(p_tile_x1, l_tile_x1); + let p_tile_x1 = cmp::max(p_tile_x1, l_tile_x0); + + let p_tile_y0 = cmp::min(p_tile_y0, l_tile_y1); + let p_tile_y0 = cmp::max(p_tile_y0, l_tile_y0); + let p_tile_y1 = cmp::min(p_tile_y1, l_tile_y1); + let p_tile_y1 = cmp::max(p_tile_y1, l_tile_y0); + + for py in p_tile_y0..p_tile_y1 { + for px in p_tile_x0..p_tile_x1 { + let tile = &mut screen_tiles[(py * x_tile_count + px) as usize]; + tile.push_primitive(prim_index); } - screen_tile.layers.push(tile_layer); } } } + } - if self.debug { - debug_rects.push(DebugRect { - label: format!("{}|{}", screen_tile.layer_count(), prim_count), - color: ColorF::new(1.0, 0.0, 0.0, 1.0), - rect: screen_tile.rect, - }) + for ly in l_tile_y0..l_tile_y1 { + for lx in l_tile_x0..l_tile_x1 { + let tile = &mut screen_tiles[(ly * x_tile_count + lx) as usize]; + tile.pop_layer(stacking_context_index); } } - - //pass_count } fn build_resource_list(&mut self, @@ -2117,15 +2500,17 @@ impl FrameBuilder { pipeline_auxiliary_lists: &HashMap>) { let mut resource_list = ResourceList::new(self.device_pixel_ratio); - // Non-visible layers have been removed by now - for layer in &self.layers { - let auxiliary_lists = pipeline_auxiliary_lists.get(&layer.pipeline_id) - .expect("No auxiliary lists?!"); + // Non-visible layers have been marked invalid by now + for layer in &self.layer_store { + if layer.is_valid { + let auxiliary_lists = pipeline_auxiliary_lists.get(&layer.pipeline_id) + .expect("No auxiliary lists?!"); - // Non-visible chunks have also been removed by now - layer.build_resource_list(&mut resource_list, - //&layer.primitives, - auxiliary_lists); + // Non-visible chunks have also been removed by now + layer.build_resource_list(&mut resource_list, + auxiliary_lists, + &self.prim_store); + } } resource_cache.add_resource_list(&resource_list, @@ -2145,10 +2530,25 @@ impl FrameBuilder { self.cull_layers(&screen_rect, layer_map); let mut debug_rects = Vec::new(); - let mut screen_tiles = self.create_screen_tiles(); + let (x_tile_count, y_tile_count, mut screen_tiles) = self.create_screen_tiles(); + + if !self.layer_store.is_empty() { + let root_sc_index = StackingContextIndex(0); + self.assign_prims_to_screen_tiles(root_sc_index, + x_tile_count, + y_tile_count, + &mut screen_tiles); + } - self.assign_prims_to_screen_tiles(&mut screen_tiles, - &mut debug_rects); + if self.debug { + for r in &screen_tiles { + debug_rects.push(DebugRect { + label: format!("{}|{}", r.cmds.len(), r.prim_count), + color: ColorF::new(1.0, 0.0, 0.0, 1.0), + rect: r.rect, + }); + } + } self.build_resource_list(resource_cache, frame_id, @@ -2160,7 +2560,7 @@ impl FrameBuilder { let mut compiled_screen_tiles = Vec::new(); for screen_tile in screen_tiles { let rect = screen_tile.rect; // TODO(gw): Remove clone here - match screen_tile.compile() { + match screen_tile.compile(&self.layer_store) { Some(compiled_screen_tile) => { compiled_screen_tiles.push(compiled_screen_tile); } @@ -2201,7 +2601,8 @@ impl FrameBuilder { phases.push(current_phase); let ctx = RenderTargetContext { - layers: &self.layers, + layer_store: &self.layer_store, + prim_store: &self.prim_store, resource_cache: resource_cache, device_pixel_ratio: self.device_pixel_ratio, frame_id: frame_id, diff --git a/src/util.rs b/src/util.rs index ea30c8883c..661b554356 100644 --- a/src/util.rs +++ b/src/util.rs @@ -134,23 +134,6 @@ pub fn rect_is_empty(rect: &Rect) -> bool { rect.size.width == Zero::zero() || rect.size.height == Zero::zero() } -/* -#[inline(always)] -pub fn rect_contains_rect(rect: &Rect, other: &Rect) -> bool { - rect.origin.x <= other.origin.x && - rect.origin.y <= other.origin.y && - rect.max_x() >= other.max_x() && - rect.max_y() >= other.max_y() -}*/ - -#[inline(always)] -pub fn rect_contains_rect(rect: &Rect, other: &Rect) -> bool { - rect.origin.x <= other.origin.x && - rect.origin.y <= other.origin.y && - rect.max_x() >= other.max_x() && - rect.max_y() >= other.max_y() -} - #[inline] pub fn rect_from_points(x0: DevicePixel, y0: DevicePixel, From f87fa6e612562ffa0666acd6f84d9c9b78afe2d7 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Tue, 26 Jul 2016 17:14:12 -0700 Subject: [PATCH 07/33] add support for dashed borders --- src/tiling.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tiling.rs b/src/tiling.rs index c8082f40d9..8968fcfd10 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -2065,7 +2065,8 @@ impl FrameBuilder { match border.style { BorderStyle::Solid | BorderStyle::None | - BorderStyle::Dotted => { + BorderStyle::Dotted | + BorderStyle::Dashed => { return true; } _ => { From 2c60532dd300964ba9724aebda156047fbb12d82 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 27 Jul 2016 12:07:33 +1000 Subject: [PATCH 08/33] Reftest fixes, b.html fixes. --- src/frame.rs | 2 +- src/tiling.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/src/frame.rs b/src/frame.rs index 5e5bbd59da..bd7f119e85 100644 --- a/src/frame.rs +++ b/src/frame.rs @@ -475,7 +475,7 @@ impl Frame { composition_ops: Vec) { context.builder.push_layer(sc_rect, info.current_clip_rect, - info.local_transform, + info.world_transform, info.pipeline_id, info.actual_scroll_layer_id, info.offset_from_current_layer, diff --git a/src/tiling.rs b/src/tiling.rs index 8968fcfd10..1cb0839ad3 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -554,6 +554,7 @@ impl TransformedRect { TransformedRectKind::Complex }; +/* match kind { TransformedRectKind::AxisAligned => { let v0 = transform.transform_point(&rect.origin); @@ -582,6 +583,7 @@ impl TransformedRect { } } TransformedRectKind::Complex => { + */ let vertices = [ transform.transform_point4d(&Point4D::new(rect.origin.x, rect.origin.y, @@ -628,8 +630,9 @@ impl TransformedRect { bounding_rect: screen_rect_dp, kind: kind, } + /* } - } + }*/ } } @@ -1124,6 +1127,43 @@ impl Primitive { } let piece_rect = Rect::new(piece_origin, piece_size); + let mut clip = Clip::invalid(piece_rect); + + if let Some(ref prim_clip) = self.complex_clip { + if i == 0 { + clip.top_left.outer_radius_x = prim_clip.top_left.outer_radius_x; + clip.top_left.outer_radius_y = prim_clip.top_left.outer_radius_y; + + match details.kind { + GradientType::Horizontal => { + clip.bottom_left.outer_radius_x = prim_clip.bottom_left.outer_radius_x; + clip.bottom_left.outer_radius_y = prim_clip.bottom_left.outer_radius_y; + } + GradientType::Vertical => { + clip.top_right.outer_radius_x = prim_clip.top_right.outer_radius_x; + clip.top_right.outer_radius_y = prim_clip.top_right.outer_radius_y; + } + GradientType::Rotated => unreachable!(), + } + } + + if i == stops.len() - 2 { + clip.bottom_right.outer_radius_x = prim_clip.bottom_right.outer_radius_x; + clip.bottom_right.outer_radius_y = prim_clip.bottom_right.outer_radius_y; + + match details.kind { + GradientType::Horizontal => { + clip.top_right.outer_radius_x = prim_clip.top_right.outer_radius_x; + clip.top_right.outer_radius_y = prim_clip.top_right.outer_radius_y; + } + GradientType::Vertical => { + clip.bottom_left.outer_radius_x = prim_clip.bottom_left.outer_radius_x; + clip.bottom_left.outer_radius_y = prim_clip.bottom_left.outer_radius_y; + } + GradientType::Rotated => unreachable!(), + } + } + } data.push(PackedAlignedGradientPrimitive { common: PackedPrimitiveInfo { @@ -1138,6 +1178,7 @@ impl Primitive { color1: next_stop.color, padding: [0, 0, 0], kind: details.kind, + clip: clip, }); } @@ -1157,10 +1198,24 @@ impl Primitive { let mut stops: [f32; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { mem::uninitialized() }; let mut colors: [ColorF; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { mem::uninitialized() }; - for (stop_index, stop) in src_stops.iter().enumerate() { - stops[stop_index] = stop.offset; - colors[stop_index] = stop.color; - } + let sx = details.start_point.x; + let ex = details.end_point.x; + + let (sp, ep) = if sx > ex { + for (stop_index, stop) in src_stops.iter().rev().enumerate() { + stops[stop_index] = 1.0 - stop.offset; + colors[stop_index] = stop.color; + } + + (details.end_point, details.start_point) + } else { + for (stop_index, stop) in src_stops.iter().enumerate() { + stops[stop_index] = stop.offset; + colors[stop_index] = stop.color; + } + + (details.start_point, details.end_point) + }; data.push(PackedAngleGradientPrimitive { common: PackedPrimitiveInfo { @@ -1172,8 +1227,8 @@ impl Primitive { local_rect: self.rect, }, padding: [0, 0, 0], - start_point: details.start_point, - end_point: details.end_point, + start_point: sp, + end_point: ep, stop_count: src_stops.len() as u32, stops: stops, colors: colors, @@ -1354,6 +1409,7 @@ pub struct PackedAlignedGradientPrimitive { color1: ColorF, kind: GradientType, padding: [u32; 3], + clip: Clip, } // TODO(gw): Angle gradient only support 8 stops due @@ -1742,6 +1798,18 @@ pub struct ClipCorner { inner_radius_y: f32, } +impl ClipCorner { + fn invalid(rect: Rect) -> ClipCorner { + ClipCorner { + rect: rect, + outer_radius_x: 0.0, + outer_radius_y: 0.0, + inner_radius_x: 0.0, + inner_radius_y: 0.0, + } + } +} + #[derive(Debug, Clone)] pub struct Clip { rect: Rect, @@ -1830,6 +1898,16 @@ impl Clip { }, } } + + fn invalid(rect: Rect) -> Clip { + Clip { + rect: rect, + top_left: ClipCorner::invalid(rect), + top_right: ClipCorner::invalid(rect), + bottom_left: ClipCorner::invalid(rect), + bottom_right: ClipCorner::invalid(rect), + } + } } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] From 6ab72b44e731f5cf8c800591cd6daa1b44e96291 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Thu, 28 Jul 2016 17:04:36 -0700 Subject: [PATCH 09/33] rename border style variables --- src/tiling.rs | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/tiling.rs b/src/tiling.rs index 1cb0839ad3..c73b4e85a7 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -917,8 +917,8 @@ impl Primitive { details.tl_inner.x, details.tl_inner.y), }, - color0: details.top_color, - color1: details.left_color, + vertical_color: details.top_color, + horizontal_color: details.left_color, outer_radius_x: details.radius.top_left.width, outer_radius_y: details.radius.top_left.height, inner_radius_x: inner_radius.top_left.width, @@ -941,8 +941,8 @@ impl Primitive { details.tr_outer.x, details.tr_inner.y), }, - color0: details.right_color, - color1: details.top_color, + vertical_color: details.top_color, + horizontal_color: details.right_color, outer_radius_x: details.radius.top_right.width, outer_radius_y: details.radius.top_right.height, inner_radius_x: inner_radius.top_right.width, @@ -965,8 +965,8 @@ impl Primitive { details.bl_inner.x, details.bl_outer.y), }, - color0: details.left_color, - color1: details.bottom_color, + vertical_color: details.bottom_color, + horizontal_color: details.left_color, outer_radius_x: details.radius.bottom_left.width, outer_radius_y: details.radius.bottom_left.height, inner_radius_x: inner_radius.bottom_left.width, @@ -989,8 +989,8 @@ impl Primitive { details.br_outer.x, details.br_outer.y), }, - color0: details.right_color, - color1: details.bottom_color, + vertical_color: details.bottom_color, + horizontal_color: details.right_color, outer_radius_x: details.radius.bottom_right.width, outer_radius_y: details.radius.bottom_right.height, inner_radius_x: inner_radius.bottom_right.width, @@ -1013,8 +1013,8 @@ impl Primitive { details.tl_outer.x + details.left_width, details.bl_inner.y), }, - color0: details.left_color, - color1: details.left_color, + vertical_color: details.left_color, + horizontal_color: details.left_color, outer_radius_x: 0.0, outer_radius_y: 0.0, inner_radius_x: 0.0, @@ -1037,8 +1037,8 @@ impl Primitive { details.br_outer.x, details.br_inner.y), }, - color0: details.right_color, - color1: details.right_color, + vertical_color: details.right_color, + horizontal_color: details.right_color, outer_radius_x: 0.0, outer_radius_y: 0.0, inner_radius_x: 0.0, @@ -1061,8 +1061,8 @@ impl Primitive { details.tr_inner.x, details.tr_outer.y + details.top_width), }, - color0: details.top_color, - color1: details.top_color, + vertical_color: details.top_color, + horizontal_color: details.top_color, outer_radius_x: 0.0, outer_radius_y: 0.0, inner_radius_x: 0.0, @@ -1085,8 +1085,8 @@ impl Primitive { details.br_inner.x, details.br_outer.y), }, - color0: details.bottom_color, - color1: details.bottom_color, + vertical_color: details.bottom_color, + horizontal_color: details.bottom_color, outer_radius_x: 0.0, outer_radius_y: 0.0, inner_radius_x: 0.0, @@ -1428,8 +1428,8 @@ pub struct PackedAngleGradientPrimitive { #[derive(Debug, Clone)] pub struct PackedBorderPrimitive { common: PackedPrimitiveInfo, - color0: ColorF, - color1: ColorF, + vertical_color: ColorF, + horizontal_color: ColorF, outer_radius_x: f32, outer_radius_y: f32, inner_radius_x: f32, @@ -2144,7 +2144,9 @@ impl FrameBuilder { BorderStyle::Solid | BorderStyle::None | BorderStyle::Dotted | - BorderStyle::Dashed => { + BorderStyle::Dashed | + BorderStyle::Inset | + BorderStyle::Outset => { return true; } _ => { @@ -2187,8 +2189,12 @@ impl FrameBuilder { rect.origin.y + rect.size.height); let br_inner = br_outer - Point2D::new(radius.bottom_right.width.max(right.width), radius.bottom_right.height.max(bottom.width)); + println!("Left color is: {:?}", left.color); + println!("Right color is: {:?}", right.color); + println!("Top color is: {:?}", top.color); + println!("Bottom color is: {:?}", bottom.color); - // These don't seem to do anything right now. + // These colors are used during inset/outset scaling. let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7); let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7); let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3); From 435f3eb3ef32b84474ed02f9938c82fd23eceadf Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Thu, 28 Jul 2016 17:27:24 -0700 Subject: [PATCH 10/33] rename color0 and color1 to vertical/horizontal colors. proper colors for inset/outset --- src/tiling.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/tiling.rs b/src/tiling.rs index c73b4e85a7..30a97a6d37 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -2189,16 +2189,12 @@ impl FrameBuilder { rect.origin.y + rect.size.height); let br_inner = br_outer - Point2D::new(radius.bottom_right.width.max(right.width), radius.bottom_right.height.max(bottom.width)); - println!("Left color is: {:?}", left.color); - println!("Right color is: {:?}", right.color); - println!("Top color is: {:?}", top.color); - println!("Bottom color is: {:?}", bottom.color); // These colors are used during inset/outset scaling. - let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7); - let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7); - let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3); - let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3); + let right_color = right.border_color(1.0, 2.0/3.0, 0.3, 0.7); + let bottom_color = bottom.border_color(1.0, 2.0/3.0, 0.3, 0.7); + let left_color = left.border_color(2.0/3.0, 1.0, 0.7, 0.3); + let top_color = top.border_color(2.0/3.0, 1.0, 0.7, 0.3); let prim = BorderPrimitive { tl_outer: tl_outer, From 8c2407d1d761e69dd9c702ec81d480106e0d1650 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 29 Jul 2016 15:42:16 -0700 Subject: [PATCH 11/33] proper colors for inset and outset border styles. fixed special case for black --- src/batch_builder.rs | 4 ++-- src/tiling.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/batch_builder.rs b/src/batch_builder.rs index 6abb5dbecf..5ac3c135c3 100644 --- a/src/batch_builder.rs +++ b/src/batch_builder.rs @@ -28,14 +28,14 @@ impl BorderSideHelpers for BorderSide { if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 { self.color.scale_rgb(scale_factor_1) } else { - ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a) + ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a) } } BorderStyle::Outset => { if self.color.r != 0.0 || self.color.g != 0.0 || self.color.b != 0.0 { self.color.scale_rgb(scale_factor_0) } else { - ColorF::new(black_color_0, black_color_0, black_color_0, self.color.a) + ColorF::new(black_color_1, black_color_1, black_color_1, self.color.a) } } _ => self.color, diff --git a/src/tiling.rs b/src/tiling.rs index 30a97a6d37..96464ba472 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -2191,10 +2191,10 @@ impl FrameBuilder { radius.bottom_right.height.max(bottom.width)); // These colors are used during inset/outset scaling. - let right_color = right.border_color(1.0, 2.0/3.0, 0.3, 0.7); - let bottom_color = bottom.border_color(1.0, 2.0/3.0, 0.3, 0.7); - let left_color = left.border_color(2.0/3.0, 1.0, 0.7, 0.3); - let top_color = top.border_color(2.0/3.0, 1.0, 0.7, 0.3); + let left_color = left.border_color(1.0, 2.0/3.0, 0.3, 0.7); + let top_color = top.border_color(1.0, 2.0/3.0, 0.3, 0.7); + let right_color = right.border_color(2.0/3.0, 1.0, 0.7, 0.3); + let bottom_color = bottom.border_color(2.0/3.0, 1.0, 0.7, 0.3); let prim = BorderPrimitive { tl_outer: tl_outer, From 4ddcf034244de274519a66b5ab550cd6343f9fd1 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 28 Jul 2016 17:36:55 -0700 Subject: [PATCH 12/33] Pack primitives once per frame instead of once per tile. --- src/tiling.rs | 1144 +++++++++++++++++++++++++++++-------------------- 1 file changed, 677 insertions(+), 467 deletions(-) diff --git a/src/tiling.rs b/src/tiling.rs index 96464ba472..bb2df3445c 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -138,7 +138,7 @@ impl AlphaBatcher { self.tasks.push(task); } - fn build(&mut self, ctx: &RenderTargetContext) { + fn build(&mut self, packed_primitive_cache: &PackedPrimitiveCache, ctx: &RenderTargetContext) { for _ in 0..ctx.layer_store.len() { self.layer_to_ubo_map.push(None); } @@ -149,124 +149,116 @@ impl AlphaBatcher { loop { // Pull next primitive let mut batch = None; + for (task_index, task) in self.tasks.iter_mut().enumerate() { + let next_item = match task.items.pop() { + Some(next_item) => next_item, + None => continue, + }; + match next_item { + AlphaRenderItem::Composite(info) => { + batch = Some(PrimitiveBatch::composite(task.child_rects[0], + task.child_rects[1], + task.target_rect, + info)); + break; + } + AlphaRenderItem::Blend(child_index, opacity) => { + batch = Some(PrimitiveBatch::blend(task.child_rects[child_index], + task.target_rect, + opacity)); + break; + } + AlphaRenderItem::Primitive(sc_index, prim_index) => { + // See if this task fits into the tile UBO + let layer = &ctx.layer_store[sc_index.0]; + let prim = &ctx.prim_store[prim_index.0]; + let transform_kind = layer.xf_rect.as_ref().unwrap().kind; + let (layer_ubo_index, index_in_layer_ubo) = + AlphaBatcher::add_layer_to_ubo(&mut self.layer_ubos, + &mut self.layer_to_ubo_map, + sc_index, + ctx); + let (tile_ubo_index, index_in_tile_ubo) = + AlphaBatcher::add_tile_to_ubo(&mut self.tile_ubos, + &mut self.tile_to_ubo_map, + TaskIndex(task_index), + task, + ctx); + let mut new_batch = PrimitiveBatch::new(prim, + transform_kind, + layer_ubo_index, + tile_ubo_index); + let ok = packed_primitive_cache.add_to_batch(prim_index, + &mut new_batch, + index_in_layer_ubo, + index_in_tile_ubo, + transform_kind); + debug_assert!(ok); + batch = Some(new_batch); + break; + } + } + } + let mut batch = match batch { + Some(batch) => batch, + None => break, + }; for (task_index, task) in self.tasks.iter_mut().enumerate() { - if let Some(next_item) = task.items.pop() { + loop { + let next_item = match task.items.pop() { + Some(next_item) => next_item, + None => break, + }; match next_item { AlphaRenderItem::Composite(info) => { - batch = Some(PrimitiveBatch::composite(task.child_rects[0], - task.child_rects[1], - task.target_rect, - info)); - break; + if !batch.pack_composite(task.child_rects[0], + task.child_rects[1], + task.target_rect, + info) { + task.items.push(next_item); + break; + } } AlphaRenderItem::Blend(child_index, opacity) => { - batch = Some(PrimitiveBatch::blend(task.child_rects[child_index], - task.target_rect, - opacity)); - break; + if !batch.pack_blend(task.child_rects[child_index], + task.target_rect, + opacity) { + task.items.push(next_item); + break; + } } AlphaRenderItem::Primitive(sc_index, prim_index) => { - // See if this task fits into the tile UBO let layer = &ctx.layer_store[sc_index.0]; - let prim = &ctx.prim_store[prim_index.0]; let transform_kind = layer.xf_rect.as_ref().unwrap().kind; - let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id) - .expect("No auxiliary lists?!"); - let (layer_ubo_index, index_in_layer_ubo) = AlphaBatcher::add_layer_to_ubo(&mut self.layer_ubos, - &mut self.layer_to_ubo_map, - sc_index, - ctx); - let (tile_ubo_index, index_in_tile_ubo) = AlphaBatcher::add_tile_to_ubo(&mut self.tile_ubos, - &mut self.tile_to_ubo_map, - TaskIndex(task_index), - task, - ctx); - let mut new_batch = PrimitiveBatch::new(prim, - transform_kind, - layer_ubo_index, - tile_ubo_index); - let ok = prim.pack(&mut new_batch, - index_in_layer_ubo, - index_in_tile_ubo, - auxiliary_lists, - transform_kind, - ctx); - debug_assert!(ok); - batch = Some(new_batch); - break; - } - } - } - } - - match batch { - Some(mut batch) => { - for (task_index, task) in self.tasks.iter_mut().enumerate() { - loop { - match task.items.pop() { - Some(next_item) => { - match next_item { - AlphaRenderItem::Composite(info) => { - if !batch.pack_composite(task.child_rects[0], - task.child_rects[1], - task.target_rect, - info) { - task.items.push(next_item); - break; - } - } - AlphaRenderItem::Blend(child_index, opacity) => { - if !batch.pack_blend(task.child_rects[child_index], - task.target_rect, - opacity) { - task.items.push(next_item); - break; - } - } - AlphaRenderItem::Primitive(sc_index, prim_index) => { - let layer = &ctx.layer_store[sc_index.0]; - let prim = &ctx.prim_store[prim_index.0]; - let transform_kind = layer.xf_rect.as_ref().unwrap().kind; - let auxiliary_lists = ctx.pipeline_auxiliary_lists.get(&layer.pipeline_id) - .expect("No auxiliary lists?!"); - let (layer_ubo_index, index_in_layer_ubo) = AlphaBatcher::add_layer_to_ubo(&mut self.layer_ubos, - &mut self.layer_to_ubo_map, - sc_index, - ctx); - let (tile_ubo_index, index_in_tile_ubo) = AlphaBatcher::add_tile_to_ubo(&mut self.tile_ubos, - &mut self.tile_to_ubo_map, - TaskIndex(task_index), - task, - ctx); - - if layer_ubo_index != batch.layer_ubo_index || - tile_ubo_index != batch.tile_ubo_index || - !prim.pack(&mut batch, - index_in_layer_ubo, - index_in_tile_ubo, - auxiliary_lists, - transform_kind, - ctx) { - task.items.push(next_item); - break; - } - } - } - } - None => { - break; - } + let (layer_ubo_index, index_in_layer_ubo) = + AlphaBatcher::add_layer_to_ubo(&mut self.layer_ubos, + &mut self.layer_to_ubo_map, + sc_index, + ctx); + let (tile_ubo_index, index_in_tile_ubo) = + AlphaBatcher::add_tile_to_ubo(&mut self.tile_ubos, + &mut self.tile_to_ubo_map, + TaskIndex(task_index), + task, + ctx); + + if layer_ubo_index != batch.layer_ubo_index || + tile_ubo_index != batch.tile_ubo_index || + !packed_primitive_cache.add_to_batch(prim_index, + &mut batch, + index_in_layer_ubo, + index_in_tile_ubo, + transform_kind) { + task.items.push(next_item); + break; } } } - - self.batches.push(batch); - } - None => { - break; } } + + self.batches.push(batch); } } } @@ -276,7 +268,6 @@ struct RenderTargetContext<'a> { prim_store: &'a Vec, resource_cache: &'a ResourceCache, device_pixel_ratio: f32, - pipeline_auxiliary_lists: &'a HashMap>, frame_id: FrameId, alpha_batch_max_tiles: usize, alpha_batch_max_layers: usize, @@ -305,7 +296,7 @@ impl RenderTarget { self.tasks.push(task); } - fn build(&mut self, ctx: &RenderTargetContext) { + fn build(&mut self, packed_primitive_cache: &PackedPrimitiveCache, ctx: &RenderTargetContext) { // Step through each task, adding to batches as appropriate. for task in self.tasks.drain(..) { @@ -331,7 +322,7 @@ impl RenderTarget { } for ab in &mut self.alpha_batchers { - ab.build(ctx); + ab.build(packed_primitive_cache, ctx); } } } @@ -368,9 +359,9 @@ impl RenderPhase { } } - fn build(&mut self, ctx: &RenderTargetContext) { + fn build(&mut self, packed_primitive_cache: &PackedPrimitiveCache, ctx: &RenderTargetContext) { for target in &mut self.targets { - target.build(ctx); + target.build(packed_primitive_cache, ctx); } } } @@ -716,6 +707,17 @@ enum PrimitiveDetails { BoxShadow(BoxShadowPrimitive), } +#[derive(Copy, Clone, Debug)] +struct LayerPackedPrimitiveRangeStartOffsets { + rectangles: usize, + rectangles_clip: usize, + borders: usize, + box_shadows: usize, + text: usize, + images: usize, + gradients: usize, +} + #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] pub struct PrimitiveIndex(usize); @@ -729,102 +731,73 @@ struct Primitive { impl Primitive { fn pack(&self, - batch: &mut PrimitiveBatch, - layer_index_in_ubo: u32, - tile_index_in_ubo: u32, + index: PrimitiveIndex, + cache: &mut PackedPrimitiveCache, auxiliary_lists: &AuxiliaryLists, - transform_kind: TransformedRectKind, - ctx: &RenderTargetContext) -> bool { - if transform_kind != batch.transform_kind { - return false; - } - - match (&mut batch.data, &self.details) { - (&mut PrimitiveBatchData::Blend(..), _) => false, - (&mut PrimitiveBatchData::Composite(..), _) => false, - (&mut PrimitiveBatchData::Rectangles(ref mut data), &PrimitiveDetails::Rectangle(ref details)) => { + ctx: &RenderTargetContext) { + // TODO(pcwalton): Only pack visible primitives! + cache.init_packed_primitive(index); + match self.details { + PrimitiveDetails::Rectangle(ref details) => { match self.complex_clip { - Some(..) => { - false - } - None => { - data.push(PackedRectanglePrimitive { + Some(ref clip) => { + let packed = PackedPrimitive::RectangleClip(PackedRectanglePrimitiveClip { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, local_rect: self.rect, }, color: details.color, + clip: (**clip).clone(), }); - true + cache.add_packed_primitive(index, packed, TextureId(0)) } - } - } - (&mut PrimitiveBatchData::Rectangles(..), _) => false, - (&mut PrimitiveBatchData::RectanglesClip(ref mut data), &PrimitiveDetails::Rectangle(ref details)) => { - match self.complex_clip { - Some(ref clip) => { - data.push(PackedRectanglePrimitiveClip { + None => { + let packed = PackedPrimitive::Rectangle(PackedRectanglePrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, local_rect: self.rect, }, color: details.color, - clip: (**clip).clone(), }); - - true - } - None => { - false + cache.add_packed_primitive(index, packed, TextureId(0)) } } } - (&mut PrimitiveBatchData::RectanglesClip(..), _) => false, - (&mut PrimitiveBatchData::Image(ref mut data), &PrimitiveDetails::Image(ref details)) => { - match self.complex_clip { - Some(..) => { - false + PrimitiveDetails::Image(ref details) => { + let (texture_id, uv_rect, stretch_size) = match details.kind { + ImagePrimitiveKind::Image(image_key, image_rendering, stretch_size) => { + let info = ctx.resource_cache.get_image(image_key, + image_rendering, + ctx.frame_id); + (info.texture_id, info.uv_rect(), stretch_size) } - None => { - let (texture_id, uv_rect, stretch_size) = match details.kind { - ImagePrimitiveKind::Image(image_key, image_rendering, stretch_size) => { - let info = ctx.resource_cache.get_image(image_key, - image_rendering, - ctx.frame_id); - (info.texture_id, info.uv_rect(), stretch_size) - } - ImagePrimitiveKind::WebGL(context_id) => { - let texture_id = ctx.resource_cache.get_webgl_texture(&context_id); - let uv = RectUv { - top_left: Point2D::new(0.0, 1.0), - top_right: Point2D::new(1.0, 1.0), - bottom_left: Point2D::zero(), - bottom_right: Point2D::new(1.0, 0.0), - }; - (texture_id, uv, self.rect.size) - } + ImagePrimitiveKind::WebGL(context_id) => { + let texture_id = ctx.resource_cache.get_webgl_texture(&context_id); + let uv = RectUv { + top_left: Point2D::new(0.0, 1.0), + top_right: Point2D::new(1.0, 1.0), + bottom_left: Point2D::zero(), + bottom_right: Point2D::new(1.0, 0.0), }; + (texture_id, uv, self.rect.size) + } + }; - // TODO(gw): Tidy the support for batch breaks up... - if batch.color_texture_id != TextureId(0) && - batch.color_texture_id != texture_id { - return false; - } - batch.color_texture_id = texture_id; - - data.push(PackedImagePrimitive { + let packed = match self.complex_clip { + Some(ref clip) => { + PackedPrimitive::ImageClip(PackedImagePrimitiveClip { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, local_rect: self.rect, @@ -833,47 +806,15 @@ impl Primitive { st1: uv_rect.bottom_right, stretch_size: stretch_size, padding: [0, 0], - }); - - true + clip: (**clip).clone(), + }) } - } - } - (&mut PrimitiveBatchData::Image(..), _) => false, - (&mut PrimitiveBatchData::ImageClip(ref mut data), &PrimitiveDetails::Image(ref details)) => { - match self.complex_clip { - Some(ref clip) => { - let (texture_id, uv_rect, stretch_size) = match details.kind { - ImagePrimitiveKind::Image(image_key, image_rendering, stretch_size) => { - let info = ctx.resource_cache.get_image(image_key, - image_rendering, - ctx.frame_id); - (info.texture_id, info.uv_rect(), stretch_size) - } - ImagePrimitiveKind::WebGL(context_id) => { - let texture_id = ctx.resource_cache.get_webgl_texture(&context_id); - let uv = RectUv { - top_left: Point2D::new(0.0, 1.0), - top_right: Point2D::new(1.0, 1.0), - bottom_left: Point2D::zero(), - bottom_right: Point2D::new(1.0, 0.0), - }; - (texture_id, uv, self.rect.size) - } - }; - - // TODO(gw): Tidy the support for batch breaks up... - if batch.color_texture_id != TextureId(0) && - batch.color_texture_id != texture_id { - return false; - } - batch.color_texture_id = texture_id; - - data.push(PackedImagePrimitiveClip { + None => { + PackedPrimitive::Image(PackedImagePrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, local_rect: self.rect, @@ -882,34 +823,31 @@ impl Primitive { st1: uv_rect.bottom_right, stretch_size: stretch_size, padding: [0, 0], - clip: (**clip).clone(), - }); - - true - } - None => { - false + }) } - } + }; + + cache.add_packed_primitive(index, packed, texture_id) } - (&mut PrimitiveBatchData::ImageClip(..), _) => false, - (&mut PrimitiveBatchData::Borders(ref mut data), &PrimitiveDetails::Border(ref details)) => { + PrimitiveDetails::Border(ref details) => { let inner_radius = BorderRadius { top_left: Size2D::new(details.radius.top_left.width - details.left_width, details.radius.top_left.width - details.left_width), top_right: Size2D::new(details.radius.top_right.width - details.right_width, details.radius.top_right.width - details.right_width), - bottom_left: Size2D::new(details.radius.bottom_left.width - details.left_width, - details.radius.bottom_left.width - details.left_width), - bottom_right: Size2D::new(details.radius.bottom_right.width - details.right_width, - details.radius.bottom_right.width - details.right_width), + bottom_left: + Size2D::new(details.radius.bottom_left.width - details.left_width, + details.radius.bottom_left.width - details.left_width), + bottom_right: + Size2D::new(details.radius.bottom_right.width - details.right_width, + details.radius.bottom_right.width - details.right_width), }; - data.push(PackedBorderPrimitive { + cache.add_packed_primitive(index, PackedPrimitive::Border(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::TopLeft, local_clip_rect: self.local_clip_rect, local_rect: rect_from_points_f(details.tl_outer.x, @@ -927,13 +865,13 @@ impl Primitive { right_style: details.right_style as u32, bottom_style: details.bottom_style as u32, left_style: details.bottom_style as u32, - }); + }), TextureId(0)); - data.push(PackedBorderPrimitive { + cache.add_packed_primitive(index, PackedPrimitive::Border(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::TopRight, local_clip_rect: self.local_clip_rect, local_rect: rect_from_points_f(details.tr_inner.x, @@ -951,13 +889,13 @@ impl Primitive { right_style: details.right_style as u32, bottom_style: details.bottom_style as u32, left_style: details.bottom_style as u32, - }); + }), TextureId(0)); - data.push(PackedBorderPrimitive { + cache.add_packed_primitive(index, PackedPrimitive::Border(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::BottomLeft, local_clip_rect: self.local_clip_rect, local_rect: rect_from_points_f(details.bl_outer.x, @@ -975,13 +913,13 @@ impl Primitive { right_style: details.right_style as u32, bottom_style: details.bottom_style as u32, left_style: details.bottom_style as u32, - }); + }), TextureId(0)); - data.push(PackedBorderPrimitive { + cache.add_packed_primitive(index, PackedPrimitive::Border(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::BottomRight, local_clip_rect: self.local_clip_rect, local_rect: rect_from_points_f(details.br_inner.x, @@ -999,13 +937,13 @@ impl Primitive { right_style: details.right_style as u32, bottom_style: details.bottom_style as u32, left_style: details.bottom_style as u32, - }); + }), TextureId(0)); - data.push(PackedBorderPrimitive { + cache.add_packed_primitive(index, PackedPrimitive::Border(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Left, local_clip_rect: self.local_clip_rect, local_rect: rect_from_points_f(details.tl_outer.x, @@ -1023,13 +961,13 @@ impl Primitive { right_style: details.right_style as u32, bottom_style: details.bottom_style as u32, left_style: details.bottom_style as u32, - }); + }), TextureId(0)); - data.push(PackedBorderPrimitive { + cache.add_packed_primitive(index, PackedPrimitive::Border(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Right, local_clip_rect: self.local_clip_rect, local_rect: rect_from_points_f(details.tr_outer.x - details.right_width, @@ -1047,13 +985,13 @@ impl Primitive { right_style: details.right_style as u32, bottom_style: details.bottom_style as u32, left_style: details.bottom_style as u32, - }); + }), TextureId(0)); - data.push(PackedBorderPrimitive { + cache.add_packed_primitive(index, PackedPrimitive::Border(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Top, local_clip_rect: self.local_clip_rect, local_rect: rect_from_points_f(details.tl_inner.x, @@ -1071,13 +1009,13 @@ impl Primitive { right_style: details.right_style as u32, bottom_style: details.bottom_style as u32, left_style: details.bottom_style as u32, - }); + }), TextureId(0)); - data.push(PackedBorderPrimitive { + cache.add_packed_primitive(index, PackedPrimitive::Border(PackedBorderPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Bottom, local_clip_rect: self.local_clip_rect, local_rect: rect_from_points_f(details.bl_inner.x, @@ -1095,150 +1033,169 @@ impl Primitive { right_style: details.right_style as u32, bottom_style: details.bottom_style as u32, left_style: details.bottom_style as u32, - }); - - true + }), TextureId(0)); } - (&mut PrimitiveBatchData::Borders(..), _) => false, - (&mut PrimitiveBatchData::AlignedGradient(ref mut data), &PrimitiveDetails::Gradient(ref details)) => { - if details.kind == GradientType::Rotated { - return false; - } - - let stops = auxiliary_lists.gradient_stops(&details.stops_range); - for i in 0..(stops.len() - 1) { - let (prev_stop, next_stop) = (&stops[i], &stops[i + 1]); - let piece_origin; - let piece_size; - match details.kind { - GradientType::Horizontal => { - let prev_x = util::lerp(details.start_point.x, details.end_point.x, prev_stop.offset); - let next_x = util::lerp(details.start_point.x, details.end_point.x, next_stop.offset); - piece_origin = Point2D::new(prev_x, self.rect.origin.y); - piece_size = Size2D::new(next_x - prev_x, self.rect.size.height); - } - GradientType::Vertical => { - let prev_y = util::lerp(details.start_point.y, details.end_point.y, prev_stop.offset); - let next_y = util::lerp(details.start_point.y, details.end_point.y, next_stop.offset); - piece_origin = Point2D::new(self.rect.origin.x, prev_y); - piece_size = Size2D::new(self.rect.size.width, next_y - prev_y); - } - GradientType::Rotated => unreachable!(), - } - - let piece_rect = Rect::new(piece_origin, piece_size); - let mut clip = Clip::invalid(piece_rect); - - if let Some(ref prim_clip) = self.complex_clip { - if i == 0 { - clip.top_left.outer_radius_x = prim_clip.top_left.outer_radius_x; - clip.top_left.outer_radius_y = prim_clip.top_left.outer_radius_y; - + PrimitiveDetails::Gradient(ref details) => { + match details.kind { + GradientType::Horizontal | GradientType::Vertical => { + let stops = auxiliary_lists.gradient_stops(&details.stops_range); + for i in 0..(stops.len() - 1) { + let (prev_stop, next_stop) = (&stops[i], &stops[i + 1]); + let piece_origin; + let piece_size; match details.kind { GradientType::Horizontal => { - clip.bottom_left.outer_radius_x = prim_clip.bottom_left.outer_radius_x; - clip.bottom_left.outer_radius_y = prim_clip.bottom_left.outer_radius_y; + let prev_x = util::lerp(details.start_point.x, + details.end_point.x, + prev_stop.offset); + let next_x = util::lerp(details.start_point.x, + details.end_point.x, + next_stop.offset); + piece_origin = Point2D::new(prev_x, self.rect.origin.y); + piece_size = Size2D::new(next_x - prev_x, + self.rect.size.height); } GradientType::Vertical => { - clip.top_right.outer_radius_x = prim_clip.top_right.outer_radius_x; - clip.top_right.outer_radius_y = prim_clip.top_right.outer_radius_y; + let prev_y = util::lerp(details.start_point.y, + details.end_point.y, + prev_stop.offset); + let next_y = util::lerp(details.start_point.y, + details.end_point.y, + next_stop.offset); + piece_origin = Point2D::new(self.rect.origin.x, prev_y); + piece_size = Size2D::new(self.rect.size.width, next_y - prev_y); } GradientType::Rotated => unreachable!(), } - } - - if i == stops.len() - 2 { - clip.bottom_right.outer_radius_x = prim_clip.bottom_right.outer_radius_x; - clip.bottom_right.outer_radius_y = prim_clip.bottom_right.outer_radius_y; - match details.kind { - GradientType::Horizontal => { - clip.top_right.outer_radius_x = prim_clip.top_right.outer_radius_x; - clip.top_right.outer_radius_y = prim_clip.top_right.outer_radius_y; + let piece_rect = Rect::new(piece_origin, piece_size); + let mut clip = Clip::invalid(piece_rect); + + if let Some(ref prim_clip) = self.complex_clip { + if i == 0 { + clip.top_left.outer_radius_x = prim_clip.top_left + .outer_radius_x; + clip.top_left.outer_radius_y = prim_clip.top_left + .outer_radius_y; + + match details.kind { + GradientType::Horizontal => { + clip.bottom_left.outer_radius_x = + prim_clip.bottom_left.outer_radius_x; + clip.bottom_left.outer_radius_y = + prim_clip.bottom_left.outer_radius_y; + } + GradientType::Vertical => { + clip.top_right.outer_radius_x = + prim_clip.top_right.outer_radius_x; + clip.top_right.outer_radius_y = + prim_clip.top_right.outer_radius_y; + } + GradientType::Rotated => unreachable!(), + } } - GradientType::Vertical => { - clip.bottom_left.outer_radius_x = prim_clip.bottom_left.outer_radius_x; - clip.bottom_left.outer_radius_y = prim_clip.bottom_left.outer_radius_y; + + if i == stops.len() - 2 { + clip.bottom_right.outer_radius_x = prim_clip.bottom_right + .outer_radius_x; + clip.bottom_right.outer_radius_y = prim_clip.bottom_right + .outer_radius_y; + + match details.kind { + GradientType::Horizontal => { + clip.top_right.outer_radius_x = + prim_clip.top_right.outer_radius_x; + clip.top_right.outer_radius_y = + prim_clip.top_right.outer_radius_y; + } + GradientType::Vertical => { + clip.bottom_left.outer_radius_x = + prim_clip.bottom_left.outer_radius_x; + clip.bottom_left.outer_radius_y = + prim_clip.bottom_left.outer_radius_y; + } + GradientType::Rotated => unreachable!(), + } } - GradientType::Rotated => unreachable!(), } + + cache.add_packed_primitive( + index, + PackedPrimitive::AlignedGradient(PackedAlignedGradientPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: 0, + layer_index: 0, + part: PrimitivePart::Bottom, + local_clip_rect: self.local_clip_rect, + local_rect: piece_rect, + }, + color0: prev_stop.color, + color1: next_stop.color, + padding: [0, 0, 0], + kind: details.kind, + clip: clip, + }), + TextureId(0)); } } + GradientType::Rotated => { + let src_stops = auxiliary_lists.gradient_stops(&details.stops_range); + if src_stops.len() > MAX_STOPS_PER_ANGLE_GRADIENT { + println!("TODO: Angle gradients with > {} stops", + MAX_STOPS_PER_ANGLE_GRADIENT); + return + } - data.push(PackedAlignedGradientPrimitive { - common: PackedPrimitiveInfo { - padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, - part: PrimitivePart::Bottom, - local_clip_rect: self.local_clip_rect, - local_rect: piece_rect, - }, - color0: prev_stop.color, - color1: next_stop.color, - padding: [0, 0, 0], - kind: details.kind, - clip: clip, - }); - } - - true - } - (&mut PrimitiveBatchData::AlignedGradient(..), _) => false, - (&mut PrimitiveBatchData::AngleGradient(ref mut data), &PrimitiveDetails::Gradient(ref details)) => { - if details.kind != GradientType::Rotated { - return false; - } - - let src_stops = auxiliary_lists.gradient_stops(&details.stops_range); - - if src_stops.len() > MAX_STOPS_PER_ANGLE_GRADIENT { - println!("TODO: Angle gradients with > {} stops", MAX_STOPS_PER_ANGLE_GRADIENT); - } else { - let mut stops: [f32; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { mem::uninitialized() }; - let mut colors: [ColorF; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { mem::uninitialized() }; + let mut stops: [f32; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { + mem::uninitialized() + }; + let mut colors: [ColorF; MAX_STOPS_PER_ANGLE_GRADIENT] = unsafe { + mem::uninitialized() + }; - let sx = details.start_point.x; - let ex = details.end_point.x; + let sx = details.start_point.x; + let ex = details.end_point.x; - let (sp, ep) = if sx > ex { - for (stop_index, stop) in src_stops.iter().rev().enumerate() { - stops[stop_index] = 1.0 - stop.offset; - colors[stop_index] = stop.color; - } + let (sp, ep) = if sx > ex { + for (stop_index, stop) in src_stops.iter().rev().enumerate() { + stops[stop_index] = 1.0 - stop.offset; + colors[stop_index] = stop.color; + } - (details.end_point, details.start_point) - } else { - for (stop_index, stop) in src_stops.iter().enumerate() { - stops[stop_index] = stop.offset; - colors[stop_index] = stop.color; - } + (details.end_point, details.start_point) + } else { + for (stop_index, stop) in src_stops.iter().enumerate() { + stops[stop_index] = stop.offset; + colors[stop_index] = stop.color; + } - (details.start_point, details.end_point) - }; + (details.start_point, details.end_point) + }; - data.push(PackedAngleGradientPrimitive { - common: PackedPrimitiveInfo { - padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, - part: PrimitivePart::Invalid, - local_clip_rect: self.local_clip_rect, - local_rect: self.rect, - }, - padding: [0, 0, 0], - start_point: sp, - end_point: ep, - stop_count: src_stops.len() as u32, - stops: stops, - colors: colors, - }); + cache.add_packed_primitive( + index, + PackedPrimitive::AngleGradient(PackedAngleGradientPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: 0, + layer_index: 0, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + local_rect: self.rect, + }, + padding: [0, 0, 0], + start_point: sp, + end_point: ep, + stop_count: src_stops.len() as u32, + stops: stops, + colors: colors, + }), + TextureId(0)); + } } - - true } - (&mut PrimitiveBatchData::AngleGradient(..), _) => false, - (&mut PrimitiveBatchData::BoxShadows(ref mut data), &PrimitiveDetails::BoxShadow(ref details)) => { + PrimitiveDetails::BoxShadow(ref details) => { let mut rects = Vec::new(); let inverted = match details.clip_mode { BoxShadowClipMode::None | BoxShadowClipMode::Outset => { @@ -1252,73 +1209,82 @@ impl Primitive { }; for rect in rects { - data.push(PackedBoxShadowPrimitive { - common: PackedPrimitiveInfo { - padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, - part: PrimitivePart::Invalid, - local_clip_rect: self.local_clip_rect, - local_rect: rect, - }, - color: details.color, - - border_radii: Point2D::new(details.border_radius, details.border_radius), - blur_radius: details.blur_radius, - inverted: inverted, - bs_rect: details.bs_rect, - src_rect: details.src_rect, - }); - } + cache.add_packed_primitive( + index, + PackedPrimitive::BoxShadow(PackedBoxShadowPrimitive { + common: PackedPrimitiveInfo { + padding: 0, + tile_index: 0, + layer_index: 0, + part: PrimitivePart::Invalid, + local_clip_rect: self.local_clip_rect, + local_rect: rect, + }, + color: details.color, - true + border_radii: Point2D::new(details.border_radius, + details.border_radius), + blur_radius: details.blur_radius, + inverted: inverted, + bs_rect: details.bs_rect, + src_rect: details.src_rect, + }), + TextureId(0)) + } } - (&mut PrimitiveBatchData::BoxShadows(..), _) => false, - (&mut PrimitiveBatchData::Text(ref mut data), &PrimitiveDetails::Text(ref details)) => { + PrimitiveDetails::Text(ref details) => { let src_glyphs = auxiliary_lists.glyph_instances(&details.glyph_range); let mut glyph_key = GlyphKey::new(details.font_key, details.size, details.blur_radius, src_glyphs[0].index); - let blur_offset = details.blur_radius.to_f32_px() * (BLUR_INFLATION_FACTOR as f32) / 2.0; + let blur_offset = details.blur_radius.to_f32_px() * + (BLUR_INFLATION_FACTOR as f32) / 2.0; for glyph in src_glyphs { glyph_key.index = glyph.index; - let image_info = ctx.resource_cache.get_glyph(&glyph_key, ctx.frame_id); - if let Some(image_info) = image_info { - // TODO(gw): Need a general solution to handle multiple texture pages per tile in WR2! - assert!(batch.color_texture_id == TextureId(0) || - batch.color_texture_id == image_info.texture_id); - batch.color_texture_id = image_info.texture_id; - let x = glyph.x + image_info.user_data.x0 as f32 / ctx.device_pixel_ratio - blur_offset; - let y = glyph.y - image_info.user_data.y0 as f32 / ctx.device_pixel_ratio - blur_offset; + let image_info = match ctx.resource_cache.get_glyph(&glyph_key, ctx.frame_id) { + None => continue, + Some(image_info) => image_info, + }; + + // TODO(gw): Need a general solution to handle multiple texture pages per tile + // in WR2! + let texture_id = image_info.texture_id; + assert!(texture_id == TextureId(0) || texture_id == image_info.texture_id); + + let x = glyph.x + image_info.user_data.x0 as f32 / ctx.device_pixel_ratio - + blur_offset; + let y = glyph.y - image_info.user_data.y0 as f32 / ctx.device_pixel_ratio - + blur_offset; - let width = image_info.requested_rect.size.width as f32 / ctx.device_pixel_ratio; - let height = image_info.requested_rect.size.height as f32 / ctx.device_pixel_ratio; + let width = image_info.requested_rect.size.width as f32 / + ctx.device_pixel_ratio; + let height = image_info.requested_rect.size.height as f32 / + ctx.device_pixel_ratio; - let uv_rect = image_info.uv_rect(); + let uv_rect = image_info.uv_rect(); + let local_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height)); - data.push(PackedGlyphPrimitive { + cache.add_packed_primitive( + index, + PackedPrimitive::Text(PackedGlyphPrimitive { common: PackedPrimitiveInfo { padding: 0, - tile_index: tile_index_in_ubo, - layer_index: layer_index_in_ubo, + tile_index: 0, + layer_index: 0, part: PrimitivePart::Invalid, local_clip_rect: self.local_clip_rect, - local_rect: Rect::new(Point2D::new(x, y), - Size2D::new(width, height)), + local_rect: local_rect, }, color: details.color, st0: uv_rect.top_left, st1: uv_rect.bottom_right, - }); - } + }), + texture_id) } - - true } - (&mut PrimitiveBatchData::Text(..), _) => false, } } } @@ -1531,6 +1497,18 @@ pub enum PrimitiveBatchData { AngleGradient(Vec), } +enum PackedPrimitive { + Rectangle(PackedRectanglePrimitive), + RectangleClip(PackedRectanglePrimitiveClip), + Border(PackedBorderPrimitive), + BoxShadow(PackedBoxShadowPrimitive), + Text(PackedGlyphPrimitive), + Image(PackedImagePrimitive), + ImageClip(PackedImagePrimitiveClip), + AlignedGradient(PackedAlignedGradientPrimitive), + AngleGradient(PackedAngleGradientPrimitive), +} + #[derive(Debug)] pub struct PrimitiveBatch { pub transform_kind: TransformedRectKind, @@ -1707,30 +1685,29 @@ impl StackingContext { auxiliary_lists: &AuxiliaryLists, prim_store: &Vec) { for item in &self.items { - match item { - &StackingContextItem::StackingContext(..) => {} - &StackingContextItem::Primitive(prim_index) => { - let prim = &prim_store[prim_index.0]; - match prim.details { - PrimitiveDetails::Rectangle(..) => {} - PrimitiveDetails::Gradient(..) => {} - PrimitiveDetails::Border(..) => {} - PrimitiveDetails::BoxShadow(..) => {} - PrimitiveDetails::Image(ref details) => { - match details.kind { - ImagePrimitiveKind::Image(image_key, image_rendering, _) => { - resource_list.add_image(image_key, image_rendering); - } - ImagePrimitiveKind::WebGL(..) => {} - } - } - PrimitiveDetails::Text(ref details) => { - let glyphs = auxiliary_lists.glyph_instances(&details.glyph_range); - for glyph in glyphs { - let glyph = Glyph::new(details.size, details.blur_radius, glyph.index); - resource_list.add_glyph(details.font_key, glyph); - } + let prim_index = match item { + &StackingContextItem::Primitive(prim_index) => prim_index, + &StackingContextItem::StackingContext(..) => continue, + }; + let prim = &prim_store[prim_index.0]; + match prim.details { + PrimitiveDetails::Rectangle(..) => {} + PrimitiveDetails::Gradient(..) => {} + PrimitiveDetails::Border(..) => {} + PrimitiveDetails::BoxShadow(..) => {} + PrimitiveDetails::Image(ref details) => { + match details.kind { + ImagePrimitiveKind::Image(image_key, image_rendering, _) => { + resource_list.add_image(image_key, image_rendering); } + ImagePrimitiveKind::WebGL(..) => {} + } + } + PrimitiveDetails::Text(ref details) => { + let glyphs = auxiliary_lists.glyph_instances(&details.glyph_range); + for glyph in glyphs { + let glyph = Glyph::new(details.size, details.blur_radius, glyph.index); + resource_list.add_glyph(details.font_key, glyph); } } } @@ -1975,8 +1952,7 @@ impl ScreenTile { } } - fn compile(self, - layer_store: &Vec) -> Option { + fn compile(self, layer_store: &Vec) -> Option { if self.prim_count == 0 { return None; } @@ -2486,6 +2462,7 @@ impl FrameBuilder { (x_tile_count, y_tile_count, screen_tiles) } + fn assign_prims_to_screen_tiles(&self, stacking_context_index: StackingContextIndex, x_tile_count: i32, @@ -2599,6 +2576,56 @@ impl FrameBuilder { resource_cache.raster_pending_glyphs(frame_id); } + fn pack_primitives_for_layer( + &self, + stacking_context_index: StackingContextIndex, + packed_primitive_cache: &mut PackedPrimitiveCache, + pipeline_auxiliary_lists: &HashMap>, + render_target_context: &RenderTargetContext) { + let layer = &self.layer_store[stacking_context_index.0]; + if !layer.is_valid { + return; + } + + for item in &layer.items { + match item { + &StackingContextItem::StackingContext(sc_index) => { + self.pack_primitives_for_layer(sc_index, + packed_primitive_cache, + pipeline_auxiliary_lists, + render_target_context) + } + &StackingContextItem::Primitive(prim_index) => { + let prim = &self.prim_store[prim_index.0]; + let auxiliary_lists = pipeline_auxiliary_lists.get(&layer.pipeline_id) + .expect("No auxiliary lists?!"); + prim.pack(prim_index, + packed_primitive_cache, + auxiliary_lists, + render_target_context) + } + } + } + } + + fn pack_primitives(&self, + pipeline_auxiliary_lists: &HashMap>, + render_target_context: &RenderTargetContext) + -> PackedPrimitiveCache { + let mut packed_primitive_cache = PackedPrimitiveCache::new(); + if !self.layer_store.is_empty() { + self.pack_primitives_for_layer(StackingContextIndex(0), + &mut packed_primitive_cache, + pipeline_auxiliary_lists, + render_target_context); + } + packed_primitive_cache + } + pub fn build(&mut self, resource_cache: &mut ResourceCache, frame_id: FrameId, @@ -2611,8 +2638,21 @@ impl FrameBuilder { self.cull_layers(&screen_rect, layer_map); let mut debug_rects = Vec::new(); + + self.build_resource_list(resource_cache, frame_id, pipeline_auxiliary_lists); let (x_tile_count, y_tile_count, mut screen_tiles) = self.create_screen_tiles(); + let ctx = RenderTargetContext { + layer_store: &self.layer_store, + prim_store: &self.prim_store, + resource_cache: resource_cache, + device_pixel_ratio: self.device_pixel_ratio, + frame_id: frame_id, + alpha_batch_max_layers: self.config.max_prim_layers, + alpha_batch_max_tiles: self.config.max_prim_tiles, + }; + + let packed_primitive_cache = self.pack_primitives(pipeline_auxiliary_lists, &ctx); if !self.layer_store.is_empty() { let root_sc_index = StackingContextIndex(0); self.assign_prims_to_screen_tiles(root_sc_index, @@ -2631,10 +2671,6 @@ impl FrameBuilder { } } - self.build_resource_list(resource_cache, - frame_id, - pipeline_auxiliary_lists); - let mut clear_tiles = Vec::new(); // Build list of passes, target allocs that each tile needs. @@ -2681,19 +2717,8 @@ impl FrameBuilder { phases.push(current_phase); - let ctx = RenderTargetContext { - layer_store: &self.layer_store, - prim_store: &self.prim_store, - resource_cache: resource_cache, - device_pixel_ratio: self.device_pixel_ratio, - frame_id: frame_id, - pipeline_auxiliary_lists: pipeline_auxiliary_lists, - alpha_batch_max_layers: self.config.max_prim_layers, - alpha_batch_max_tiles: self.config.max_prim_tiles, - }; - for phase in &mut phases { - phase.build(&ctx); + phase.build(&packed_primitive_cache, &ctx); } } @@ -2717,3 +2742,188 @@ fn compute_box_shadow_rect(box_bounds: &Rect, rect.origin.y += box_offset.y; rect.inflate(spread_radius, spread_radius) } + +#[derive(Clone, Copy, PartialEq, Debug)] +struct PackedPrimitiveMetadata { + start: usize, + end: usize, + texture_id: TextureId, +} + +impl PackedPrimitiveMetadata { + fn new(start: usize, end: usize, texture_id: TextureId) -> PackedPrimitiveMetadata { + PackedPrimitiveMetadata { + start: start, + end: end, + texture_id: texture_id, + } + } + + fn none() -> PackedPrimitiveMetadata { + PackedPrimitiveMetadata::new(0, 0, TextureId(0)) + } +} + +/// To find the packed primitives for a primitive index, first look up the metadata within the +/// `metadata` field, and then consult the indices defined by the range specified by that metadata +/// in the `primitives` field. +struct PackedPrimitiveCache { + /// A mapping from primitive index to range in the `primitives` vector below. + metadata: Vec, + /// A list of packed primitives. + primitives: Vec, +} + +impl PackedPrimitiveCache { + fn new() -> PackedPrimitiveCache { + PackedPrimitiveCache { + metadata: vec![], + primitives: vec![], + } + } + + /// Reserves space for the packed primitive with the given index. + /// + /// This must be called before `add_packed_primitive` below. + fn init_packed_primitive(&mut self, primitive_index: PrimitiveIndex) { + while self.metadata.len() < primitive_index.0 + 1 { + self.metadata.push(PackedPrimitiveMetadata::none()) + } + } + + fn add_packed_primitive(&mut self, + primitive_index: PrimitiveIndex, + packed_primitive: PackedPrimitive, + texture_id: TextureId) { + let mut metadata = &mut self.metadata[primitive_index.0]; + if *metadata == PackedPrimitiveMetadata::none() { + metadata.start = self.primitives.len(); + } else { + debug_assert!(metadata.end == self.primitives.len()); + } + metadata.end = self.primitives.len() + 1; + metadata.texture_id = texture_id; + + self.primitives.push(packed_primitive) + } + + fn add_to_batch(&self, + primitive_index: PrimitiveIndex, + batch: &mut PrimitiveBatch, + layer_index_in_ubo: u32, + tile_index_in_ubo: u32, + transform_kind: TransformedRectKind) + -> bool { + if transform_kind != batch.transform_kind { + return false + } + + // TODO(gw): Tidy the support for batch breaks up... + let metadata = self.metadata[primitive_index.0]; + if metadata.texture_id != TextureId(0) { + if batch.color_texture_id != TextureId(0) && + batch.color_texture_id != metadata.texture_id { + return false + } + batch.color_texture_id = metadata.texture_id; + } + + for packed_primitive_index in metadata.start..metadata.end { + match (&mut batch.data, &self.primitives[packed_primitive_index]) { + (&mut PrimitiveBatchData::Blend(..), _) => return false, + (&mut PrimitiveBatchData::Composite(..), _) => return false, + (&mut PrimitiveBatchData::Rectangles(ref mut data), + &PackedPrimitive::Rectangle(ref rectangle)) => { + // FIXME(pcwalton): Don't clone here! + // TODO(pcwalton): Check rect intersection. + let mut rectangle = (*rectangle).clone(); + rectangle.common.tile_index = tile_index_in_ubo; + rectangle.common.layer_index = layer_index_in_ubo; + data.push(rectangle) + } + (&mut PrimitiveBatchData::Rectangles(..), _) => return false, + (&mut PrimitiveBatchData::RectanglesClip(ref mut data), + &PackedPrimitive::RectangleClip(ref rectangle)) => { + // FIXME(pcwalton): Don't clone here! + // TODO(pcwalton): Check rect intersection. + let mut rectangle = (*rectangle).clone(); + rectangle.common.tile_index = tile_index_in_ubo; + rectangle.common.layer_index = layer_index_in_ubo; + data.push(rectangle) + } + (&mut PrimitiveBatchData::RectanglesClip(..), _) => return false, + (&mut PrimitiveBatchData::Image(ref mut data), + &PackedPrimitive::Image(ref image)) => { + // FIXME(pcwalton): Don't clone here! + let mut image = (*image).clone(); + image.common.tile_index = tile_index_in_ubo; + image.common.layer_index = layer_index_in_ubo; + data.push(image) + } + (&mut PrimitiveBatchData::Image(..), _) => return false, + (&mut PrimitiveBatchData::ImageClip(ref mut data), + &PackedPrimitive::ImageClip(ref image)) => { + // FIXME(pcwalton): Don't clone here! + // TODO(pcwalton): Check rect intersection. + let mut image = (*image).clone(); + image.common.tile_index = tile_index_in_ubo; + image.common.layer_index = layer_index_in_ubo; + data.push(image) + } + (&mut PrimitiveBatchData::ImageClip(..), _) => return false, + (&mut PrimitiveBatchData::Borders(ref mut data), + &PackedPrimitive::Border(ref border)) => { + // FIXME(pcwalton): Don't clone here! + // TODO(pcwalton): Check rect intersection. + let mut border = (*border).clone(); + border.common.tile_index = tile_index_in_ubo; + border.common.layer_index = layer_index_in_ubo; + data.push(border) + } + (&mut PrimitiveBatchData::Borders(..), _) => return false, + (&mut PrimitiveBatchData::AlignedGradient(ref mut data), + &PackedPrimitive::AlignedGradient(ref gradient)) => { + // FIXME(pcwalton): Don't clone here! + // TODO(pcwalton): Check rect intersection. + let mut gradient = (*gradient).clone(); + gradient.common.tile_index = tile_index_in_ubo; + gradient.common.layer_index = layer_index_in_ubo; + data.push(gradient) + } + (&mut PrimitiveBatchData::AlignedGradient(..), _) => return false, + (&mut PrimitiveBatchData::AngleGradient(ref mut data), + &PackedPrimitive::AngleGradient(ref gradient)) => { + // FIXME(pcwalton): Don't clone here! + let mut gradient = (*gradient).clone(); + gradient.common.tile_index = tile_index_in_ubo; + gradient.common.layer_index = layer_index_in_ubo; + data.push(gradient) + } + (&mut PrimitiveBatchData::AngleGradient(..), _) => return false, + (&mut PrimitiveBatchData::BoxShadows(ref mut data), + &PackedPrimitive::BoxShadow(ref shadow)) => { + // FIXME(pcwalton): Don't clone here! + // TODO(pcwalton): Check rect intersection. + let mut shadow = (*shadow).clone(); + shadow.common.tile_index = tile_index_in_ubo; + shadow.common.layer_index = layer_index_in_ubo; + data.push(shadow) + } + (&mut PrimitiveBatchData::BoxShadows(..), _) => return false, + (&mut PrimitiveBatchData::Text(ref mut data), + &PackedPrimitive::Text(ref glyph)) => { + // FIXME(pcwalton): Don't clone here! + // TODO(pcwalton): Check rect intersection. Binary search to find the start + // point, maybe? + let mut glyph = (*glyph).clone(); + glyph.common.tile_index = tile_index_in_ubo; + glyph.common.layer_index = layer_index_in_ubo; + data.push(glyph) + } + (&mut PrimitiveBatchData::Text(..), _) => return false, + } + } + true + } +} + From fd79416e335951f21b0cf289c9212c7c545380d0 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Sat, 11 Jun 2016 10:48:51 +1000 Subject: [PATCH 13/33] Reftest fixes and prim shaders. --- res/blur.fs.glsl | 2 +- res/border.fs.glsl | 41 ----- res/cache_shared.glsl | 98 ++++++++++++ res/composite_shared.glsl | 115 +++++++++++++ res/cs_p1.fs.glsl | 14 ++ res/cs_p1.glsl | 7 + res/cs_p1.vs.glsl | 12 ++ res/cs_p1_ic.fs.glsl | 34 ++++ res/cs_p1_ic.glsl | 10 ++ res/cs_p1_ic.vs.glsl | 44 +++++ res/cs_p1_partial.fs.glsl | 16 ++ res/cs_p1_partial.glsl | 9 ++ res/{border.vs.glsl => cs_p1_partial.vs.glsl} | 14 +- res/cs_p2.fs.glsl | 17 ++ res/cs_p2.glsl | 8 + res/cs_p2.vs.glsl | 13 ++ res/cs_p2_partial.fs.glsl | 32 ++++ res/cs_p2_partial.glsl | 10 ++ res/cs_p2_partial.vs.glsl | 27 ++++ res/cs_p3.fs.glsl | 19 +++ res/cs_p3.glsl | 9 ++ res/cs_p3.vs.glsl | 14 ++ res/cs_p3_partial.fs.glsl | 24 +++ res/cs_p3_partial.glsl | 11 ++ res/cs_p3_partial.vs.glsl | 14 ++ res/cs_p4.fs.glsl | 21 +++ res/cs_p4.glsl | 10 ++ res/cs_p4.vs.glsl | 15 ++ res/cs_p4_partial.fs.glsl | 28 ++++ res/cs_p4_partial.glsl | 12 ++ res/cs_p4_partial.vs.glsl | 15 ++ res/cs_p5.fs.glsl | 23 +++ res/cs_p5.glsl | 12 ++ res/cs_p5.vs.glsl | 16 ++ res/cs_p5_partial.fs.glsl | 32 ++++ res/cs_p5_partial.glsl | 15 ++ res/cs_p5_partial.vs.glsl | 16 ++ res/cs_p6.fs.glsl | 25 +++ res/cs_p6.glsl | 13 ++ res/cs_p6.vs.glsl | 17 ++ res/cs_p6_partial.fs.glsl | 35 ++++ res/cs_p6_partial.glsl | 16 ++ res/cs_p6_partial.vs.glsl | 17 ++ res/cs_p7.fs.glsl | 27 ++++ res/cs_p7.glsl | 14 ++ res/cs_p7.vs.glsl | 18 +++ res/cs_p7_partial.fs.glsl | 40 +++++ res/cs_p7_partial.glsl | 17 ++ res/cs_p7_partial.vs.glsl | 18 +++ res/cs_p8.fs.glsl | 29 ++++ res/cs_p8.glsl | 15 ++ res/cs_p8.vs.glsl | 19 +++ res/cs_p8_partial.fs.glsl | 44 +++++ res/cs_p8_partial.glsl | 18 +++ res/cs_p8_partial.vs.glsl | 19 +++ res/debug_color.fs.glsl | 2 +- res/debug_font.fs.glsl | 6 +- res/prim_shared.glsl | 117 ++++++++++++++ res/ps_angle_gradient.fs.glsl | 34 ++++ res/ps_angle_gradient.glsl | 13 ++ res/ps_angle_gradient.vs.glsl | 51 ++++++ res/ps_border.fs.glsl | 17 ++ res/ps_border.glsl | 13 ++ res/ps_border.vs.glsl | 92 +++++++++++ res/ps_box_shadow.fs.glsl | 151 ++++++++++++++++++ res/ps_box_shadow.glsl | 11 ++ res/ps_box_shadow.vs.glsl | 51 ++++++ res/{mask.vs.glsl => ps_clear.fs.glsl} | 6 +- res/ps_clear.glsl | 3 + res/ps_clear.vs.glsl | 21 +++ res/{clear.vs.glsl => ps_gradient.fs.glsl} | 6 +- res/ps_gradient.glsl | 7 + res/ps_gradient.vs.glsl | 57 +++++++ res/ps_image.fs.glsl | 8 + res/ps_image.glsl | 7 + res/ps_image.vs.glsl | 49 ++++++ res/ps_image_transform.fs.glsl | 13 ++ res/ps_image_transform.glsl | 8 + res/ps_image_transform.vs.glsl | 65 ++++++++ res/{mask.fs.glsl => ps_rectangle.fs.glsl} | 2 +- res/{clear.fs.glsl => ps_rectangle.glsl} | 5 +- res/ps_rectangle.vs.glsl | 42 +++++ res/ps_rectangle_clip.fs.glsl | 9 ++ res/{tile.vs.glsl => ps_rectangle_clip.glsl} | 13 +- res/ps_rectangle_clip.vs.glsl | 49 ++++++ res/ps_rectangle_transform.fs.glsl | 13 ++ res/ps_rectangle_transform.glsl | 8 + res/ps_rectangle_transform.vs.glsl | 60 +++++++ res/ps_text.fs.glsl | 8 + res/ps_text.glsl | 6 + res/ps_text.vs.glsl | 48 ++++++ res/quad.fs.glsl | 38 ----- res/quad.vs.glsl | 112 ------------- res/shared.glsl | 43 +++++ res/shared_other.glsl | 64 ++++++++ res/tile.fs.glsl | 11 -- 96 files changed, 2335 insertions(+), 234 deletions(-) delete mode 100644 res/border.fs.glsl create mode 100644 res/cache_shared.glsl create mode 100644 res/composite_shared.glsl create mode 100644 res/cs_p1.fs.glsl create mode 100644 res/cs_p1.glsl create mode 100644 res/cs_p1.vs.glsl create mode 100644 res/cs_p1_ic.fs.glsl create mode 100644 res/cs_p1_ic.glsl create mode 100644 res/cs_p1_ic.vs.glsl create mode 100644 res/cs_p1_partial.fs.glsl create mode 100644 res/cs_p1_partial.glsl rename res/{border.vs.glsl => cs_p1_partial.vs.glsl} (50%) create mode 100644 res/cs_p2.fs.glsl create mode 100644 res/cs_p2.glsl create mode 100644 res/cs_p2.vs.glsl create mode 100644 res/cs_p2_partial.fs.glsl create mode 100644 res/cs_p2_partial.glsl create mode 100644 res/cs_p2_partial.vs.glsl create mode 100644 res/cs_p3.fs.glsl create mode 100644 res/cs_p3.glsl create mode 100644 res/cs_p3.vs.glsl create mode 100644 res/cs_p3_partial.fs.glsl create mode 100644 res/cs_p3_partial.glsl create mode 100644 res/cs_p3_partial.vs.glsl create mode 100644 res/cs_p4.fs.glsl create mode 100644 res/cs_p4.glsl create mode 100644 res/cs_p4.vs.glsl create mode 100644 res/cs_p4_partial.fs.glsl create mode 100644 res/cs_p4_partial.glsl create mode 100644 res/cs_p4_partial.vs.glsl create mode 100644 res/cs_p5.fs.glsl create mode 100644 res/cs_p5.glsl create mode 100644 res/cs_p5.vs.glsl create mode 100644 res/cs_p5_partial.fs.glsl create mode 100644 res/cs_p5_partial.glsl create mode 100644 res/cs_p5_partial.vs.glsl create mode 100644 res/cs_p6.fs.glsl create mode 100644 res/cs_p6.glsl create mode 100644 res/cs_p6.vs.glsl create mode 100644 res/cs_p6_partial.fs.glsl create mode 100644 res/cs_p6_partial.glsl create mode 100644 res/cs_p6_partial.vs.glsl create mode 100644 res/cs_p7.fs.glsl create mode 100644 res/cs_p7.glsl create mode 100644 res/cs_p7.vs.glsl create mode 100644 res/cs_p7_partial.fs.glsl create mode 100644 res/cs_p7_partial.glsl create mode 100644 res/cs_p7_partial.vs.glsl create mode 100644 res/cs_p8.fs.glsl create mode 100644 res/cs_p8.glsl create mode 100644 res/cs_p8.vs.glsl create mode 100644 res/cs_p8_partial.fs.glsl create mode 100644 res/cs_p8_partial.glsl create mode 100644 res/cs_p8_partial.vs.glsl create mode 100644 res/prim_shared.glsl create mode 100644 res/ps_angle_gradient.fs.glsl create mode 100644 res/ps_angle_gradient.glsl create mode 100644 res/ps_angle_gradient.vs.glsl create mode 100644 res/ps_border.fs.glsl create mode 100644 res/ps_border.glsl create mode 100644 res/ps_border.vs.glsl create mode 100644 res/ps_box_shadow.fs.glsl create mode 100644 res/ps_box_shadow.glsl create mode 100644 res/ps_box_shadow.vs.glsl rename res/{mask.vs.glsl => ps_clear.fs.glsl} (66%) create mode 100644 res/ps_clear.glsl create mode 100644 res/ps_clear.vs.glsl rename res/{clear.vs.glsl => ps_gradient.fs.glsl} (66%) create mode 100644 res/ps_gradient.glsl create mode 100644 res/ps_gradient.vs.glsl create mode 100644 res/ps_image.fs.glsl create mode 100644 res/ps_image.glsl create mode 100644 res/ps_image.vs.glsl create mode 100644 res/ps_image_transform.fs.glsl create mode 100644 res/ps_image_transform.glsl create mode 100644 res/ps_image_transform.vs.glsl rename res/{mask.fs.glsl => ps_rectangle.fs.glsl} (89%) rename res/{clear.fs.glsl => ps_rectangle.glsl} (81%) create mode 100644 res/ps_rectangle.vs.glsl create mode 100644 res/ps_rectangle_clip.fs.glsl rename res/{tile.vs.glsl => ps_rectangle_clip.glsl} (57%) create mode 100644 res/ps_rectangle_clip.vs.glsl create mode 100644 res/ps_rectangle_transform.fs.glsl create mode 100644 res/ps_rectangle_transform.glsl create mode 100644 res/ps_rectangle_transform.vs.glsl create mode 100644 res/ps_text.fs.glsl create mode 100644 res/ps_text.glsl create mode 100644 res/ps_text.vs.glsl delete mode 100644 res/quad.fs.glsl delete mode 100644 res/quad.vs.glsl create mode 100644 res/shared.glsl create mode 100644 res/shared_other.glsl delete mode 100644 res/tile.fs.glsl diff --git a/res/blur.fs.glsl b/res/blur.fs.glsl index c20a774f48..2af2a7ebab 100644 --- a/res/blur.fs.glsl +++ b/res/blur.fs.glsl @@ -28,7 +28,7 @@ void main(void) { lColorTexCoord.x <= 1.0 && lColorTexCoord.y >= 0.0 && lColorTexCoord.y <= 1.0 ? - Texture(sDiffuse, lColorTexCoord * sourceTextureUvSize + sourceTextureUvOrigin) : + texture(sDiffuse, lColorTexCoord * sourceTextureUvSize + sourceTextureUvOrigin) : vec4(0.0); // Alpha must be premultiplied in order to properly blur the alpha channel. diff --git a/res/border.fs.glsl b/res/border.fs.glsl deleted file mode 100644 index 32d1930aa5..0000000000 --- a/res/border.fs.glsl +++ /dev/null @@ -1,41 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - Ellipse equation: - - (x-h)^2 (y-k)^2 - ------- + ------- <= 1 - rx^2 ry^2 - - */ - -float Value(vec2 position) { - float outer_rx = vBorderRadii.x; - float outer_ry = vBorderRadii.y; - float outer_dx = position.x * position.x / (outer_rx * outer_rx); - float outer_dy = position.y * position.y / (outer_ry * outer_ry); - if (outer_dx + outer_dy > 1.0) - return 0.0; - - float inner_rx = vBorderRadii.z; - float inner_ry = vBorderRadii.w; - if (inner_rx == 0.0 || inner_ry == 0.0) - return 1.0; - - float inner_dx = position.x * position.x / (inner_rx * inner_rx); - float inner_dy = position.y * position.y / (inner_ry * inner_ry); - return inner_dx + inner_dy >= 1.0 ? 1.0 : 0.0; -} - -void main(void) -{ - vec2 position = vPosition - vBorderPosition.xy; - vec4 pixelBounds = vec4(floor(position.x), floor(position.y), - ceil(position.x), ceil(position.y)); - float value = (Value(pixelBounds.xy) + Value(pixelBounds.zy) + - Value(pixelBounds.xw) + Value(pixelBounds.zw)) / 4.0; - SetFragColor(vec4(vColor.rgb, mix(1.0 - vColor.a, vColor.a, value))); -} - diff --git a/res/cache_shared.glsl b/res/cache_shared.glsl new file mode 100644 index 0000000000..a56f74ddd5 --- /dev/null +++ b/res/cache_shared.glsl @@ -0,0 +1,98 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define CORNER_TOP_LEFT uint(0) +#define CORNER_TOP_RIGHT uint(1) +#define CORNER_BOTTOM_LEFT uint(2) +#define CORNER_BOTTOM_RIGHT uint(3) + +struct ClipCorner { + vec4 rect; + vec4 outer_inner_radius; +}; + +struct Clip { + vec4 rect; + uvec4 clip_kind_layer_p2; + ClipCorner top_left; + ClipCorner top_right; + ClipCorner bottom_left; + ClipCorner bottom_right; +}; + +struct Layer { + mat4 transform; + mat4 inv_transform; + vec4 screen_vertices[4]; + vec4 blend_info; +}; + +layout(std140) uniform Layers { + Layer layers[256]; +}; + +bool ray_plane(vec3 normal, vec3 point, vec3 ray_origin, vec3 ray_dir, out float t) +{ + float denom = dot(normal, ray_dir); + if (denom > 1e-6) { + vec3 d = point - ray_origin; + t = dot(d, normal) / denom; + return t >= 0.0; + } + + return false; +} + +vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) { + vec3 p = vec3(ref, -10000.0); + vec3 d = vec3(0, 0, 1.0); + + float t; + ray_plane(n, a, p, d, t); + vec3 c = p + d * t; + + vec4 r = inv_transform * vec4(c, 1.0); + return r; +} + +vec3 get_layer_pos(vec2 pos, uint layer_index) { + Layer layer = layers[layer_index]; + vec3 a = layer.screen_vertices[0].xyz / layer.screen_vertices[0].w; + vec3 b = layer.screen_vertices[3].xyz / layer.screen_vertices[3].w; + vec3 c = layer.screen_vertices[2].xyz / layer.screen_vertices[2].w; + vec3 n = normalize(cross(b-a, c-a)); + vec4 local_pos = untransform(pos, n, a, layer.inv_transform); + return local_pos.xyw; +} + +float do_clip(vec2 pos, vec4 clip_rect, float radius) { + vec2 ref_tl = clip_rect.xy + vec2( radius, radius); + vec2 ref_tr = clip_rect.zy + vec2(-radius, radius); + vec2 ref_bl = clip_rect.xw + vec2( radius, -radius); + vec2 ref_br = clip_rect.zw + vec2(-radius, -radius); + + float d_tl = distance(pos, ref_tl); + float d_tr = distance(pos, ref_tr); + float d_bl = distance(pos, ref_bl); + float d_br = distance(pos, ref_br); + + bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > radius; + bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > radius; + bool out2 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > radius; + bool out3 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > radius; + + // TODO(gw): Alpha anti-aliasing based on edge distance! + if (out0 || out1 || out2 || out3) { + return 0.0; + } else { + return 1.0; + } +} + +bool point_in_rect(vec2 p, vec2 p0, vec2 p1) { + return p.x >= p0.x && + p.y >= p0.y && + p.x <= p1.x && + p.y <= p1.y; +} diff --git a/res/composite_shared.glsl b/res/composite_shared.glsl new file mode 100644 index 0000000000..8d357e4060 --- /dev/null +++ b/res/composite_shared.glsl @@ -0,0 +1,115 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define MAX_PRIMS_PER_COMPOSITE (8) + +#define INVALID_LAYER_INDEX uint(0xffffffff) + +uniform sampler2D sLayer0; +uniform sampler2D sLayer1; +uniform sampler2D sLayer2; +uniform sampler2D sLayer3; +uniform sampler2D sLayer4; +uniform sampler2D sLayer5; +uniform sampler2D sLayer6; +uniform sampler2D sLayer7; +uniform sampler2D sCache; + +struct CompositeTile { + ivec4 rect; + ivec4 src_rects[MAX_PRIMS_PER_COMPOSITE]; + vec4 blend_info[MAX_PRIMS_PER_COMPOSITE/4]; +}; + +layout(std140) uniform Tiles { + CompositeTile tiles[WR_MAX_COMPOSITE_TILES]; +}; + +#ifdef WR_VERTEX_SHADER + +/* +uint pack_rect(ivec4 rect, ivec2 ref_point) { + int x0 = max(0, rect.x - ref_point.x); + int y0 = max(0, rect.y - ref_point.y); + int x1 = min(rect.x + rect.z - ref_point.x, 255); // should never hit with right preconditions in bsp tree! + int y1 = min(rect.y + rect.w - ref_point.y, 255); + + uint x = uint(x0) << 0; + uint y = uint(y0) << 8; + uint z = uint(x1) << 16; + uint w = uint(y1) << 24; + return x | y | z | w; +} +*/ + +void write_prim(CompositeTile tile, + int index, + out vec2 uv, + out float blend_info) { + uv = mix(tile.src_rects[index].xy / 2048.0, + (tile.src_rects[index].xy + tile.src_rects[index].zw) / 2048.0, + aPosition.xy); + blend_info = tile.blend_info[index/4][index % 4]; +} + +/* +void write_partial_prim(vec2 pos, + uint prim_index, + CompositeTile tile, + out vec2 uv, + out uint partial_rect, + out float blend_info) { + Renderable ren = renderables[prim_index]; + vec4 prim_rect = ren.screen_rect; + vec2 f = (pos - prim_rect.xy) / prim_rect.zw; + uv = mix(ren.st_rect.xy, ren.st_rect.zw, f); + + partial_rect = pack_rect(ren.screen_rect, tile.rect.xy); + blend_info = ren.local_offset_blend_info.z; +} +*/ + +void write_vertex(CompositeTile tile) { + vec4 pos = vec4(mix(tile.rect.xy, + tile.rect.xy + tile.rect.zw, + aPosition.xy), + 0.0, + 1.0); + + //vTilePos = pos.xy - tile.rect.xy; + + gl_Position = uTransform * pos; + //return pos.xy; +} + +#endif + +#ifdef WR_FRAGMENT_SHADER + +/* +ivec4 unpack_rect(uint rect) { + int x = int(rect & uint(0x000000ff)); + int y = int((rect & uint(0x0000ff00)) >> 8); + int z = int((rect & uint(0x00ff0000)) >> 16); + int w = int((rect & uint(0xff000000)) >> 24); + return ivec4(x, y, z, w); +} + +bool is_prim_valid(uint packed_rect) { + ivec4 rect = unpack_rect(packed_rect); + + return vTilePos.x > rect.x && + vTilePos.x < rect.z && + vTilePos.y > rect.y && + vTilePos.y < rect.w; +} +*/ + +vec4 fetch_initial_color() { + return vec4(1, 1, 1, 0); +} + +#endif diff --git a/res/cs_p1.fs.glsl b/res/cs_p1.fs.glsl new file mode 100644 index 0000000000..deada98da4 --- /dev/null +++ b/res/cs_p1.fs.glsl @@ -0,0 +1,14 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 result = fetch_initial_color(); + + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues.x); + + oFragColor = result; +} diff --git a/res/cs_p1.glsl b/res/cs_p1.glsl new file mode 100644 index 0000000000..f788c978cc --- /dev/null +++ b/res/cs_p1.glsl @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; + +flat varying vec4 vLayerValues; diff --git a/res/cs_p1.vs.glsl b/res/cs_p1.vs.glsl new file mode 100644 index 0000000000..afac128130 --- /dev/null +++ b/res/cs_p1.vs.glsl @@ -0,0 +1,12 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + write_vertex(tile); + + write_prim(tile, 0, vUv0, vLayerValues.x); +} diff --git a/res/cs_p1_ic.fs.glsl b/res/cs_p1_ic.fs.glsl new file mode 100644 index 0000000000..15a84ecffa --- /dev/null +++ b/res/cs_p1_ic.fs.glsl @@ -0,0 +1,34 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 prim_colors[4]; + prim_colors[0] = texture(sLayer0, vUv0); + prim_colors[1] = texture(sLayer1, vUv1); + prim_colors[2] = texture(sLayer2, vUv2); + prim_colors[3] = texture(sLayer3, vUv3); + + vec4 result = vec4(1, 1, 1, 1); + vec4 layer_color = vec4(0, 0, 0, 0); + + layer_color = mix(layer_color, prim_colors[0], prim_colors[0].a); + result = mix(result, layer_color, layer_color.a * vLayerValues.x); + layer_color = mix(layer_color, vec4(0, 0, 0, 0), vec4(vLayerValues.x > 0.0)); + + layer_color = mix(layer_color, prim_colors[1], prim_colors[1].a); + result = mix(result, layer_color, layer_color.a * vLayerValues.y); + layer_color = mix(layer_color, vec4(0, 0, 0, 0), vec4(vLayerValues.y > 0.0)); + + layer_color = mix(layer_color, prim_colors[2], prim_colors[2].a); + result = mix(result, layer_color, layer_color.a * vLayerValues.z); + layer_color = mix(layer_color, vec4(0, 0, 0, 0), vec4(vLayerValues.z > 0.0)); + + layer_color = mix(layer_color, prim_colors[3], prim_colors[3].a); + result = mix(result, layer_color, layer_color.a * vLayerValues.w); + layer_color = mix(layer_color, vec4(0, 0, 0, 0), vec4(vLayerValues.w > 0.0)); + + oFragColor = result; +} diff --git a/res/cs_p1_ic.glsl b/res/cs_p1_ic.glsl new file mode 100644 index 0000000000..a2139f44b5 --- /dev/null +++ b/res/cs_p1_ic.glsl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; + +flat varying vec4 vLayerValues; diff --git a/res/cs_p1_ic.vs.glsl b/res/cs_p1_ic.vs.glsl new file mode 100644 index 0000000000..80c86c72a1 --- /dev/null +++ b/res/cs_p1_ic.vs.glsl @@ -0,0 +1,44 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + vec2 pos = write_vertex(tile); + + vUv0 = write_prim(pos, tile.prim_indices[0].x); + vUv1 = write_prim(pos, tile.prim_indices[0].y); + vUv2 = write_prim(pos, tile.prim_indices[0].z); + vUv3 = write_prim(pos, tile.prim_indices[0].w); + + uint li0 = tile.layer_indices[0].x; + uint li1 = tile.layer_indices[0].y; + uint li2 = tile.layer_indices[0].z; + uint li3 = tile.layer_indices[0].w; + + if (li0 == INVALID_LAYER_INDEX || li0 == li1) { + vLayerValues.x = 0.0; + } else { + vLayerValues.x = layers[li0].blend_info.x; + } + + if (li1 == INVALID_LAYER_INDEX || li1 == li2) { + vLayerValues.y = 0.0; + } else { + vLayerValues.y = layers[li1].blend_info.x; + } + + if (li2 == INVALID_LAYER_INDEX || li2 == li3) { + vLayerValues.z = 0.0; + } else { + vLayerValues.z = layers[li2].blend_info.x; + } + + if (li3 == INVALID_LAYER_INDEX) { + vLayerValues.w = 0.0; + } else { + vLayerValues.w = layers[li3].blend_info.x; + } +} diff --git a/res/cs_p1_partial.fs.glsl b/res/cs_p1_partial.fs.glsl new file mode 100644 index 0000000000..041939d57b --- /dev/null +++ b/res/cs_p1_partial.fs.glsl @@ -0,0 +1,16 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 result = fetch_initial_color(); + + if (is_prim_valid(vPartialRects0.x)) { + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues0.x); + } + + oFragColor = result; +} diff --git a/res/cs_p1_partial.glsl b/res/cs_p1_partial.glsl new file mode 100644 index 0000000000..b7f6ca95e0 --- /dev/null +++ b/res/cs_p1_partial.glsl @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; + +flat varying vec4 vLayerValues0; + +flat varying uvec4 vPartialRects0; diff --git a/res/border.vs.glsl b/res/cs_p1_partial.vs.glsl similarity index 50% rename from res/border.vs.glsl rename to res/cs_p1_partial.vs.glsl index cbd9cdcd0c..14476ae1df 100644 --- a/res/border.vs.glsl +++ b/res/cs_p1_partial.vs.glsl @@ -1,12 +1,12 @@ +#line 1 + /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -void main(void) -{ - vColor = aColorRectTL; - vPosition = aPosition.xy; - vBorderPosition = aBorderPosition; - vBorderRadii = aBorderRadii; - gl_Position = uTransform * vec4(aPosition, 1.0); +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + vec2 pos = write_vertex(tile); + + write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); } diff --git a/res/cs_p2.fs.glsl b/res/cs_p2.fs.glsl new file mode 100644 index 0000000000..9deeffc270 --- /dev/null +++ b/res/cs_p2.fs.glsl @@ -0,0 +1,17 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 prim_colors[2]; + prim_colors[0] = texture(sLayer0, vUv0); + prim_colors[1] = texture(sLayer1, vUv1); + + vec4 result = fetch_initial_color(); + result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues.x); + result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues.y); + + oFragColor = result; +} diff --git a/res/cs_p2.glsl b/res/cs_p2.glsl new file mode 100644 index 0000000000..51db06180f --- /dev/null +++ b/res/cs_p2.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; + +flat varying vec4 vLayerValues; diff --git a/res/cs_p2.vs.glsl b/res/cs_p2.vs.glsl new file mode 100644 index 0000000000..c0ecd579a6 --- /dev/null +++ b/res/cs_p2.vs.glsl @@ -0,0 +1,13 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + write_vertex(tile); + + write_prim(tile, 0, vUv0, vLayerValues.x); + write_prim(tile, 1, vUv1, vLayerValues.y); +} diff --git a/res/cs_p2_partial.fs.glsl b/res/cs_p2_partial.fs.glsl new file mode 100644 index 0000000000..abc754be25 --- /dev/null +++ b/res/cs_p2_partial.fs.glsl @@ -0,0 +1,32 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 p0 = texture(sLayer0, vUv0); + vec4 p1 = texture(sLayer1, vUv1); + + vec4 result = fetch_initial_color(); + + result = mix(result, p0, p0.a * vLayerValues0.x); + result = mix(result, p1, p1.a * vLayerValues0.y); + + oFragColor = result; + + //oFragColor = vec4(1, 0, 0, 1); + /* + vec4 result = fetch_initial_color(); + + if (is_prim_valid(vPartialRects0.x)) { + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues0.x); + } + if (is_prim_valid(vPartialRects0.y)) { + vec4 prim_color = texture(sLayer1, vUv1); + result = mix(result, prim_color, prim_color.a * vLayerValues0.y); + } + + oFragColor = result;*/ +} diff --git a/res/cs_p2_partial.glsl b/res/cs_p2_partial.glsl new file mode 100644 index 0000000000..f505aa9b46 --- /dev/null +++ b/res/cs_p2_partial.glsl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; + +flat varying vec4 vLayerValues0; + +flat varying uvec4 vPartialRects0; diff --git a/res/cs_p2_partial.vs.glsl b/res/cs_p2_partial.vs.glsl new file mode 100644 index 0000000000..535e48f22e --- /dev/null +++ b/res/cs_p2_partial.vs.glsl @@ -0,0 +1,27 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + + vUv0 = mix(tile.src_rects[0].xy / 4096.0, + (tile.src_rects[0].xy + tile.src_rects[0].zw) / 4096.0, + aPosition.xy); + + vUv1 = mix(tile.src_rects[1].xy / 4096.0, + (tile.src_rects[1].xy + tile.src_rects[1].zw) / 4096.0, + aPosition.xy); + + vLayerValues0 = vec4(1, 1, 1, 1); + + write_vertex(tile); + + /* + + write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); + write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); + */ +} diff --git a/res/cs_p3.fs.glsl b/res/cs_p3.fs.glsl new file mode 100644 index 0000000000..4829e5b212 --- /dev/null +++ b/res/cs_p3.fs.glsl @@ -0,0 +1,19 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 prim_colors[3]; + prim_colors[0] = texture(sLayer0, vUv0); + prim_colors[1] = texture(sLayer1, vUv1); + prim_colors[2] = texture(sLayer2, vUv2); + + vec4 result = fetch_initial_color(); + result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues.x); + result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues.y); + result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues.z); + + oFragColor = result; +} diff --git a/res/cs_p3.glsl b/res/cs_p3.glsl new file mode 100644 index 0000000000..410ab7d121 --- /dev/null +++ b/res/cs_p3.glsl @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; + +flat varying vec4 vLayerValues; diff --git a/res/cs_p3.vs.glsl b/res/cs_p3.vs.glsl new file mode 100644 index 0000000000..a15a6d4f51 --- /dev/null +++ b/res/cs_p3.vs.glsl @@ -0,0 +1,14 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + write_vertex(tile); + + write_prim(tile, 0, vUv0, vLayerValues.x); + write_prim(tile, 1, vUv1, vLayerValues.y); + write_prim(tile, 2, vUv2, vLayerValues.z); +} diff --git a/res/cs_p3_partial.fs.glsl b/res/cs_p3_partial.fs.glsl new file mode 100644 index 0000000000..0151c60b4b --- /dev/null +++ b/res/cs_p3_partial.fs.glsl @@ -0,0 +1,24 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 result = fetch_initial_color(); + + if (is_prim_valid(vPartialRects0.x)) { + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues0.x); + } + if (is_prim_valid(vPartialRects0.y)) { + vec4 prim_color = texture(sLayer1, vUv1); + result = mix(result, prim_color, prim_color.a * vLayerValues0.y); + } + if (is_prim_valid(vPartialRects0.z)) { + vec4 prim_color = texture(sLayer2, vUv2); + result = mix(result, prim_color, prim_color.a * vLayerValues0.z); + } + + oFragColor = result; +} diff --git a/res/cs_p3_partial.glsl b/res/cs_p3_partial.glsl new file mode 100644 index 0000000000..eb9416824a --- /dev/null +++ b/res/cs_p3_partial.glsl @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; + +flat varying vec4 vLayerValues0; + +flat varying uvec4 vPartialRects0; diff --git a/res/cs_p3_partial.vs.glsl b/res/cs_p3_partial.vs.glsl new file mode 100644 index 0000000000..271aa0668c --- /dev/null +++ b/res/cs_p3_partial.vs.glsl @@ -0,0 +1,14 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + vec2 pos = write_vertex(tile); + + write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); + write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); + write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); +} diff --git a/res/cs_p4.fs.glsl b/res/cs_p4.fs.glsl new file mode 100644 index 0000000000..4cc3e8d002 --- /dev/null +++ b/res/cs_p4.fs.glsl @@ -0,0 +1,21 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 prim_colors[4]; + prim_colors[0] = texture(sLayer0, vUv0); + prim_colors[1] = texture(sLayer1, vUv1); + prim_colors[2] = texture(sLayer2, vUv2); + prim_colors[3] = texture(sLayer3, vUv3); + + vec4 result = fetch_initial_color(); + result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues.x); + result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues.y); + result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues.z); + result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues.w); + + oFragColor = result; +} diff --git a/res/cs_p4.glsl b/res/cs_p4.glsl new file mode 100644 index 0000000000..a2139f44b5 --- /dev/null +++ b/res/cs_p4.glsl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; + +flat varying vec4 vLayerValues; diff --git a/res/cs_p4.vs.glsl b/res/cs_p4.vs.glsl new file mode 100644 index 0000000000..91acbe66d3 --- /dev/null +++ b/res/cs_p4.vs.glsl @@ -0,0 +1,15 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + write_vertex(tile); + + write_prim(tile, 0, vUv0, vLayerValues.x); + write_prim(tile, 1, vUv1, vLayerValues.y); + write_prim(tile, 2, vUv2, vLayerValues.z); + write_prim(tile, 3, vUv3, vLayerValues.w); +} diff --git a/res/cs_p4_partial.fs.glsl b/res/cs_p4_partial.fs.glsl new file mode 100644 index 0000000000..962bfe4331 --- /dev/null +++ b/res/cs_p4_partial.fs.glsl @@ -0,0 +1,28 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 result = fetch_initial_color(); + + if (is_prim_valid(vPartialRects0.x)) { + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues0.x); + } + if (is_prim_valid(vPartialRects0.y)) { + vec4 prim_color = texture(sLayer1, vUv1); + result = mix(result, prim_color, prim_color.a * vLayerValues0.y); + } + if (is_prim_valid(vPartialRects0.z)) { + vec4 prim_color = texture(sLayer2, vUv2); + result = mix(result, prim_color, prim_color.a * vLayerValues0.z); + } + if (is_prim_valid(vPartialRects0.w)) { + vec4 prim_color = texture(sLayer3, vUv3); + result = mix(result, prim_color, prim_color.a * vLayerValues0.w); + } + + oFragColor = result; +} diff --git a/res/cs_p4_partial.glsl b/res/cs_p4_partial.glsl new file mode 100644 index 0000000000..ee195ed9dc --- /dev/null +++ b/res/cs_p4_partial.glsl @@ -0,0 +1,12 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; + +flat varying vec4 vLayerValues0; + +flat varying uvec4 vPartialRects0; diff --git a/res/cs_p4_partial.vs.glsl b/res/cs_p4_partial.vs.glsl new file mode 100644 index 0000000000..ffab0d5cad --- /dev/null +++ b/res/cs_p4_partial.vs.glsl @@ -0,0 +1,15 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + vec2 pos = write_vertex(tile); + + write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); + write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); + write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); + write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); +} diff --git a/res/cs_p5.fs.glsl b/res/cs_p5.fs.glsl new file mode 100644 index 0000000000..02a1294000 --- /dev/null +++ b/res/cs_p5.fs.glsl @@ -0,0 +1,23 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 prim_colors[5]; + prim_colors[0] = texture(sLayer0, vUv0); + prim_colors[1] = texture(sLayer1, vUv1); + prim_colors[2] = texture(sLayer2, vUv2); + prim_colors[3] = texture(sLayer3, vUv3); + prim_colors[4] = texture(sLayer4, vUv4); + + vec4 result = fetch_initial_color(); + result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues0.x); + result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues0.y); + result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues0.z); + result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues0.w); + result = mix(result, prim_colors[4], prim_colors[4].a * vLayerValues1.x); + + oFragColor = result; +} diff --git a/res/cs_p5.glsl b/res/cs_p5.glsl new file mode 100644 index 0000000000..b4eed170cf --- /dev/null +++ b/res/cs_p5.glsl @@ -0,0 +1,12 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; +varying vec2 vUv4; + +flat varying vec4 vLayerValues0; +flat varying vec4 vLayerValues1; diff --git a/res/cs_p5.vs.glsl b/res/cs_p5.vs.glsl new file mode 100644 index 0000000000..af6bc801e6 --- /dev/null +++ b/res/cs_p5.vs.glsl @@ -0,0 +1,16 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + write_vertex(tile); + + write_prim(tile, 0, vUv0, vLayerValues0.x); + write_prim(tile, 1, vUv1, vLayerValues0.y); + write_prim(tile, 2, vUv2, vLayerValues0.z); + write_prim(tile, 3, vUv3, vLayerValues0.w); + write_prim(tile, 4, vUv4, vLayerValues1.x); +} diff --git a/res/cs_p5_partial.fs.glsl b/res/cs_p5_partial.fs.glsl new file mode 100644 index 0000000000..c8b0c429e3 --- /dev/null +++ b/res/cs_p5_partial.fs.glsl @@ -0,0 +1,32 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 result = fetch_initial_color(); + + if (is_prim_valid(vPartialRects0.x)) { + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues0.x); + } + if (is_prim_valid(vPartialRects0.y)) { + vec4 prim_color = texture(sLayer1, vUv1); + result = mix(result, prim_color, prim_color.a * vLayerValues0.y); + } + if (is_prim_valid(vPartialRects0.z)) { + vec4 prim_color = texture(sLayer2, vUv2); + result = mix(result, prim_color, prim_color.a * vLayerValues0.z); + } + if (is_prim_valid(vPartialRects0.w)) { + vec4 prim_color = texture(sLayer3, vUv3); + result = mix(result, prim_color, prim_color.a * vLayerValues0.w); + } + if (is_prim_valid(vPartialRects1.x)) { + vec4 prim_color = texture(sLayer4, vUv4); + result = mix(result, prim_color, prim_color.a * vLayerValues1.x); + } + + oFragColor = result; +} diff --git a/res/cs_p5_partial.glsl b/res/cs_p5_partial.glsl new file mode 100644 index 0000000000..7c67457a48 --- /dev/null +++ b/res/cs_p5_partial.glsl @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; +varying vec2 vUv4; + +flat varying vec4 vLayerValues0; +flat varying vec4 vLayerValues1; + +flat varying uvec4 vPartialRects0; +flat varying uvec4 vPartialRects1; diff --git a/res/cs_p5_partial.vs.glsl b/res/cs_p5_partial.vs.glsl new file mode 100644 index 0000000000..a61c6fe20c --- /dev/null +++ b/res/cs_p5_partial.vs.glsl @@ -0,0 +1,16 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + vec2 pos = write_vertex(tile); + + write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); + write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); + write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); + write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); + write_partial_prim(pos, tile.prim_indices[1].x, tile, vUv4, vPartialRects1.x, vLayerValues1.x); +} diff --git a/res/cs_p6.fs.glsl b/res/cs_p6.fs.glsl new file mode 100644 index 0000000000..977db8329d --- /dev/null +++ b/res/cs_p6.fs.glsl @@ -0,0 +1,25 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 prim_colors[6]; + prim_colors[0] = texture(sLayer0, vUv0); + prim_colors[1] = texture(sLayer1, vUv1); + prim_colors[2] = texture(sLayer2, vUv2); + prim_colors[3] = texture(sLayer3, vUv3); + prim_colors[4] = texture(sLayer4, vUv4); + prim_colors[5] = texture(sLayer5, vUv5); + + vec4 result = fetch_initial_color(); + result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues0.x); + result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues0.y); + result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues0.z); + result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues0.w); + result = mix(result, prim_colors[4], prim_colors[4].a * vLayerValues1.x); + result = mix(result, prim_colors[5], prim_colors[5].a * vLayerValues1.y); + + oFragColor = result; +} diff --git a/res/cs_p6.glsl b/res/cs_p6.glsl new file mode 100644 index 0000000000..c143622eab --- /dev/null +++ b/res/cs_p6.glsl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; +varying vec2 vUv4; +varying vec2 vUv5; + +flat varying vec4 vLayerValues0; +flat varying vec4 vLayerValues1; diff --git a/res/cs_p6.vs.glsl b/res/cs_p6.vs.glsl new file mode 100644 index 0000000000..0270adfd2f --- /dev/null +++ b/res/cs_p6.vs.glsl @@ -0,0 +1,17 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + write_vertex(tile); + + write_prim(tile, 0, vUv0, vLayerValues0.x); + write_prim(tile, 1, vUv1, vLayerValues0.y); + write_prim(tile, 2, vUv2, vLayerValues0.z); + write_prim(tile, 3, vUv3, vLayerValues0.w); + write_prim(tile, 4, vUv4, vLayerValues1.x); + write_prim(tile, 5, vUv5, vLayerValues1.y); +} diff --git a/res/cs_p6_partial.fs.glsl b/res/cs_p6_partial.fs.glsl new file mode 100644 index 0000000000..dd1bb4901e --- /dev/null +++ b/res/cs_p6_partial.fs.glsl @@ -0,0 +1,35 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 result = fetch_initial_color(); + + if (is_prim_valid(vPartialRects0.x)) { + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues0.x); + } + if (is_prim_valid(vPartialRects0.y)) { + vec4 prim_color = texture(sLayer1, vUv1); + result = mix(result, prim_color, prim_color.a * vLayerValues0.y); + } + if (is_prim_valid(vPartialRects0.z)) { + vec4 prim_color = texture(sLayer2, vUv2); + result = mix(result, prim_color, prim_color.a * vLayerValues0.z); + } + if (is_prim_valid(vPartialRects0.w)) { + vec4 prim_color = texture(sLayer3, vUv3); + result = mix(result, prim_color, prim_color.a * vLayerValues0.w); + } + if (is_prim_valid(vPartialRects1.x)) { + vec4 prim_color = texture(sLayer4, vUv4); + result = mix(result, prim_color, prim_color.a * vLayerValues1.x); + } + if (is_prim_valid(vPartialRects1.y)) { + vec4 prim_color = texture(sLayer5, vUv5); + result = mix(result, prim_color, prim_color.a * vLayerValues1.y); + } + oFragColor = result; +} diff --git a/res/cs_p6_partial.glsl b/res/cs_p6_partial.glsl new file mode 100644 index 0000000000..ef2b5d4869 --- /dev/null +++ b/res/cs_p6_partial.glsl @@ -0,0 +1,16 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; +varying vec2 vUv4; +varying vec2 vUv5; + +flat varying vec4 vLayerValues0; +flat varying vec4 vLayerValues1; + +flat varying uvec4 vPartialRects0; +flat varying uvec4 vPartialRects1; diff --git a/res/cs_p6_partial.vs.glsl b/res/cs_p6_partial.vs.glsl new file mode 100644 index 0000000000..989828f9ab --- /dev/null +++ b/res/cs_p6_partial.vs.glsl @@ -0,0 +1,17 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + vec2 pos = write_vertex(tile); + + write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); + write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); + write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); + write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); + write_partial_prim(pos, tile.prim_indices[1].x, tile, vUv4, vPartialRects1.x, vLayerValues1.x); + write_partial_prim(pos, tile.prim_indices[1].y, tile, vUv5, vPartialRects1.y, vLayerValues1.y); +} diff --git a/res/cs_p7.fs.glsl b/res/cs_p7.fs.glsl new file mode 100644 index 0000000000..214f514358 --- /dev/null +++ b/res/cs_p7.fs.glsl @@ -0,0 +1,27 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 prim_colors[7]; + prim_colors[0] = texture(sLayer0, vUv0); + prim_colors[1] = texture(sLayer1, vUv1); + prim_colors[2] = texture(sLayer2, vUv2); + prim_colors[3] = texture(sLayer3, vUv3); + prim_colors[4] = texture(sLayer4, vUv4); + prim_colors[5] = texture(sLayer5, vUv5); + prim_colors[6] = texture(sLayer6, vUv6); + + vec4 result = fetch_initial_color(); + result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues0.x); + result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues0.y); + result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues0.z); + result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues0.w); + result = mix(result, prim_colors[4], prim_colors[4].a * vLayerValues1.x); + result = mix(result, prim_colors[5], prim_colors[5].a * vLayerValues1.y); + result = mix(result, prim_colors[6], prim_colors[6].a * vLayerValues1.z); + + oFragColor = result; +} diff --git a/res/cs_p7.glsl b/res/cs_p7.glsl new file mode 100644 index 0000000000..50764754ff --- /dev/null +++ b/res/cs_p7.glsl @@ -0,0 +1,14 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; +varying vec2 vUv4; +varying vec2 vUv5; +varying vec2 vUv6; + +flat varying vec4 vLayerValues0; +flat varying vec4 vLayerValues1; diff --git a/res/cs_p7.vs.glsl b/res/cs_p7.vs.glsl new file mode 100644 index 0000000000..b5ccfe2b1d --- /dev/null +++ b/res/cs_p7.vs.glsl @@ -0,0 +1,18 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + write_vertex(tile); + + write_prim(tile, 0, vUv0, vLayerValues0.x); + write_prim(tile, 1, vUv1, vLayerValues0.y); + write_prim(tile, 2, vUv2, vLayerValues0.z); + write_prim(tile, 3, vUv3, vLayerValues0.w); + write_prim(tile, 4, vUv4, vLayerValues1.x); + write_prim(tile, 5, vUv5, vLayerValues1.y); + write_prim(tile, 6, vUv6, vLayerValues1.z); +} diff --git a/res/cs_p7_partial.fs.glsl b/res/cs_p7_partial.fs.glsl new file mode 100644 index 0000000000..23e4da8838 --- /dev/null +++ b/res/cs_p7_partial.fs.glsl @@ -0,0 +1,40 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 result = fetch_initial_color(); + + if (is_prim_valid(vPartialRects0.x)) { + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues0.x); + } + if (is_prim_valid(vPartialRects0.y)) { + vec4 prim_color = texture(sLayer1, vUv1); + result = mix(result, prim_color, prim_color.a * vLayerValues0.y); + } + if (is_prim_valid(vPartialRects0.z)) { + vec4 prim_color = texture(sLayer2, vUv2); + result = mix(result, prim_color, prim_color.a * vLayerValues0.z); + } + if (is_prim_valid(vPartialRects0.w)) { + vec4 prim_color = texture(sLayer3, vUv3); + result = mix(result, prim_color, prim_color.a * vLayerValues0.w); + } + if (is_prim_valid(vPartialRects1.x)) { + vec4 prim_color = texture(sLayer4, vUv4); + result = mix(result, prim_color, prim_color.a * vLayerValues1.x); + } + if (is_prim_valid(vPartialRects1.y)) { + vec4 prim_color = texture(sLayer5, vUv5); + result = mix(result, prim_color, prim_color.a * vLayerValues1.y); + } + if (is_prim_valid(vPartialRects1.z)) { + vec4 prim_color = texture(sLayer6, vUv6); + result = mix(result, prim_color, prim_color.a * vLayerValues1.z); + } + + oFragColor = result; +} diff --git a/res/cs_p7_partial.glsl b/res/cs_p7_partial.glsl new file mode 100644 index 0000000000..4e017baca5 --- /dev/null +++ b/res/cs_p7_partial.glsl @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; +varying vec2 vUv4; +varying vec2 vUv5; +varying vec2 vUv6; + +flat varying vec4 vLayerValues0; +flat varying vec4 vLayerValues1; + +flat varying uvec4 vPartialRects0; +flat varying uvec4 vPartialRects1; diff --git a/res/cs_p7_partial.vs.glsl b/res/cs_p7_partial.vs.glsl new file mode 100644 index 0000000000..cf7cee86fb --- /dev/null +++ b/res/cs_p7_partial.vs.glsl @@ -0,0 +1,18 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + vec2 pos = write_vertex(tile); + + write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); + write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); + write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); + write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); + write_partial_prim(pos, tile.prim_indices[1].x, tile, vUv4, vPartialRects1.x, vLayerValues1.x); + write_partial_prim(pos, tile.prim_indices[1].y, tile, vUv5, vPartialRects1.y, vLayerValues1.y); + write_partial_prim(pos, tile.prim_indices[1].z, tile, vUv6, vPartialRects1.z, vLayerValues1.z); +} diff --git a/res/cs_p8.fs.glsl b/res/cs_p8.fs.glsl new file mode 100644 index 0000000000..4d13190f7b --- /dev/null +++ b/res/cs_p8.fs.glsl @@ -0,0 +1,29 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 prim_colors[8]; + prim_colors[0] = texture(sLayer0, vUv0); + prim_colors[1] = texture(sLayer1, vUv1); + prim_colors[2] = texture(sLayer2, vUv2); + prim_colors[3] = texture(sLayer3, vUv3); + prim_colors[4] = texture(sLayer4, vUv4); + prim_colors[5] = texture(sLayer5, vUv5); + prim_colors[6] = texture(sLayer6, vUv6); + prim_colors[7] = texture(sLayer7, vUv7); + + vec4 result = fetch_initial_color(); + result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues0.x); + result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues0.y); + result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues0.z); + result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues0.w); + result = mix(result, prim_colors[4], prim_colors[4].a * vLayerValues1.x); + result = mix(result, prim_colors[5], prim_colors[5].a * vLayerValues1.y); + result = mix(result, prim_colors[6], prim_colors[6].a * vLayerValues1.z); + result = mix(result, prim_colors[7], prim_colors[7].a * vLayerValues1.w); + + oFragColor = result; +} diff --git a/res/cs_p8.glsl b/res/cs_p8.glsl new file mode 100644 index 0000000000..d23aad5dd0 --- /dev/null +++ b/res/cs_p8.glsl @@ -0,0 +1,15 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; +varying vec2 vUv4; +varying vec2 vUv5; +varying vec2 vUv6; +varying vec2 vUv7; + +flat varying vec4 vLayerValues0; +flat varying vec4 vLayerValues1; diff --git a/res/cs_p8.vs.glsl b/res/cs_p8.vs.glsl new file mode 100644 index 0000000000..6c79ad26b1 --- /dev/null +++ b/res/cs_p8.vs.glsl @@ -0,0 +1,19 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + write_vertex(tile); + + write_prim(tile, 0, vUv0, vLayerValues0.x); + write_prim(tile, 1, vUv1, vLayerValues0.y); + write_prim(tile, 2, vUv2, vLayerValues0.z); + write_prim(tile, 3, vUv3, vLayerValues0.w); + write_prim(tile, 4, vUv4, vLayerValues1.x); + write_prim(tile, 5, vUv5, vLayerValues1.y); + write_prim(tile, 6, vUv6, vLayerValues1.z); + write_prim(tile, 7, vUv7, vLayerValues1.w); +} diff --git a/res/cs_p8_partial.fs.glsl b/res/cs_p8_partial.fs.glsl new file mode 100644 index 0000000000..21685d14aa --- /dev/null +++ b/res/cs_p8_partial.fs.glsl @@ -0,0 +1,44 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec4 result = fetch_initial_color(); + + if (is_prim_valid(vPartialRects0.x)) { + vec4 prim_color = texture(sLayer0, vUv0); + result = mix(result, prim_color, prim_color.a * vLayerValues0.x); + } + if (is_prim_valid(vPartialRects0.y)) { + vec4 prim_color = texture(sLayer1, vUv1); + result = mix(result, prim_color, prim_color.a * vLayerValues0.y); + } + if (is_prim_valid(vPartialRects0.z)) { + vec4 prim_color = texture(sLayer2, vUv2); + result = mix(result, prim_color, prim_color.a * vLayerValues0.z); + } + if (is_prim_valid(vPartialRects0.w)) { + vec4 prim_color = texture(sLayer3, vUv3); + result = mix(result, prim_color, prim_color.a * vLayerValues0.w); + } + if (is_prim_valid(vPartialRects1.x)) { + vec4 prim_color = texture(sLayer4, vUv4); + result = mix(result, prim_color, prim_color.a * vLayerValues1.x); + } + if (is_prim_valid(vPartialRects1.y)) { + vec4 prim_color = texture(sLayer5, vUv5); + result = mix(result, prim_color, prim_color.a * vLayerValues1.y); + } + if (is_prim_valid(vPartialRects1.z)) { + vec4 prim_color = texture(sLayer6, vUv6); + result = mix(result, prim_color, prim_color.a * vLayerValues1.z); + } + if (is_prim_valid(vPartialRects1.w)) { + vec4 prim_color = texture(sLayer7, vUv7); + result = mix(result, prim_color, prim_color.a * vLayerValues1.w); + } + + oFragColor = result; +} diff --git a/res/cs_p8_partial.glsl b/res/cs_p8_partial.glsl new file mode 100644 index 0000000000..ddbdd9270b --- /dev/null +++ b/res/cs_p8_partial.glsl @@ -0,0 +1,18 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv0; +varying vec2 vUv1; +varying vec2 vUv2; +varying vec2 vUv3; +varying vec2 vUv4; +varying vec2 vUv5; +varying vec2 vUv6; +varying vec2 vUv7; + +flat varying vec4 vLayerValues0; +flat varying vec4 vLayerValues1; + +flat varying uvec4 vPartialRects0; +flat varying uvec4 vPartialRects1; diff --git a/res/cs_p8_partial.vs.glsl b/res/cs_p8_partial.vs.glsl new file mode 100644 index 0000000000..76fe311e32 --- /dev/null +++ b/res/cs_p8_partial.vs.glsl @@ -0,0 +1,19 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main() { + CompositeTile tile = tiles[gl_InstanceID]; + vec2 pos = write_vertex(tile); + + write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); + write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); + write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); + write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); + write_partial_prim(pos, tile.prim_indices[1].x, tile, vUv4, vPartialRects1.x, vLayerValues1.x); + write_partial_prim(pos, tile.prim_indices[1].y, tile, vUv5, vPartialRects1.y, vLayerValues1.y); + write_partial_prim(pos, tile.prim_indices[1].z, tile, vUv6, vPartialRects1.z, vLayerValues1.z); + write_partial_prim(pos, tile.prim_indices[1].w, tile, vUv7, vPartialRects1.w, vLayerValues1.w); +} diff --git a/res/debug_color.fs.glsl b/res/debug_color.fs.glsl index 658ac27488..e9aae64138 100644 --- a/res/debug_color.fs.glsl +++ b/res/debug_color.fs.glsl @@ -4,5 +4,5 @@ void main(void) { - SetFragColor(vColor); + oFragColor = vColor; } diff --git a/res/debug_font.fs.glsl b/res/debug_font.fs.glsl index 8b68e085cf..a10e0da4ce 100644 --- a/res/debug_font.fs.glsl +++ b/res/debug_font.fs.glsl @@ -5,9 +5,9 @@ void main(void) { #ifdef SERVO_ES2 - float alpha = Texture(sDiffuse, vColorTexCoord.xy).a; + float alpha = texture(sDiffuse, vColorTexCoord.xy).a; #else - float alpha = Texture(sDiffuse, vColorTexCoord.xy).r; + float alpha = texture(sDiffuse, vColorTexCoord.xy).r; #endif - SetFragColor(vec4(vColor.xyz, vColor.w * alpha)); + oFragColor = vec4(vColor.xyz, vColor.w * alpha); } diff --git a/res/prim_shared.glsl b/res/prim_shared.glsl new file mode 100644 index 0000000000..04bee0e335 --- /dev/null +++ b/res/prim_shared.glsl @@ -0,0 +1,117 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define PST_INVALID uint(0) +#define PST_TOP_LEFT uint(1) +#define PST_TOP_RIGHT uint(2) +#define PST_BOTTOM_LEFT uint(3) +#define PST_BOTTOM_RIGHT uint(4) +#define PST_TOP uint(5) +#define PST_LEFT uint(6) +#define PST_BOTTOM uint(7) +#define PST_RIGHT uint(8) + +struct Layer { + mat4 transform; + mat4 inv_transform; + vec4 screen_vertices[4]; + vec4 blend_info; +}; + +layout(std140) uniform Layers { + Layer layers[WR_MAX_PRIM_LAYERS]; +}; + +struct Tile { + uvec4 actual_rect; + uvec4 target_rect; +}; + +layout(std140) uniform Tiles { + Tile tiles[WR_MAX_PRIM_TILES]; +}; + +struct PrimitiveInfo { + uvec4 layer_tile_part; + vec4 local_clip_rect; +}; + +struct ClipCorner { + vec4 rect; + vec4 outer_inner_radius; +}; + +struct Clip { + vec4 rect; + ClipCorner top_left; + ClipCorner top_right; + ClipCorner bottom_left; + ClipCorner bottom_right; +}; + +bool ray_plane(vec3 normal, vec3 point, vec3 ray_origin, vec3 ray_dir, out float t) +{ + float denom = dot(normal, ray_dir); + if (denom > 1e-6) { + vec3 d = point - ray_origin; + t = dot(d, normal) / denom; + return t >= 0.0; + } + + return false; +} + +vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) { + vec3 p = vec3(ref, -10000.0); + vec3 d = vec3(0, 0, 1.0); + + float t; + ray_plane(n, a, p, d, t); + vec3 c = p + d * t; + + vec4 r = inv_transform * vec4(c, 1.0); + return r; +} + +vec3 get_layer_pos(vec2 pos, uint layer_index) { + Layer layer = layers[layer_index]; + vec3 a = layer.screen_vertices[0].xyz / layer.screen_vertices[0].w; + vec3 b = layer.screen_vertices[3].xyz / layer.screen_vertices[3].w; + vec3 c = layer.screen_vertices[2].xyz / layer.screen_vertices[2].w; + vec3 n = normalize(cross(b-a, c-a)); + vec4 local_pos = untransform(pos, n, a, layer.inv_transform); + return local_pos.xyw; +} + +#ifdef WR_FRAGMENT_SHADER +void do_clip(vec2 pos, vec4 clip_rect, float radius) { + vec2 ref_tl = clip_rect.xy + vec2( radius, radius); + vec2 ref_tr = clip_rect.zy + vec2(-radius, radius); + vec2 ref_bl = clip_rect.xw + vec2( radius, -radius); + vec2 ref_br = clip_rect.zw + vec2(-radius, -radius); + + float d_tl = distance(pos, ref_tl); + float d_tr = distance(pos, ref_tr); + float d_bl = distance(pos, ref_bl); + float d_br = distance(pos, ref_br); + + bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > radius; + bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > radius; + bool out2 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > radius; + bool out3 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > radius; + + // TODO(gw): Alpha anti-aliasing based on edge distance! + if (out0 || out1 || out2 || out3) { + discard; + } +} + +bool point_in_rect(vec2 p, vec2 p0, vec2 p1) { + return p.x >= p0.x && + p.y >= p0.y && + p.x <= p1.x && + p.y <= p1.y; +} +#endif diff --git a/res/ps_angle_gradient.fs.glsl b/res/ps_angle_gradient.fs.glsl new file mode 100644 index 0000000000..700e1be011 --- /dev/null +++ b/res/ps_angle_gradient.fs.glsl @@ -0,0 +1,34 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +float offset(int index) { + return vOffsets[index / 4][index % 4]; +} + +float linearStep(float lo, float hi, float x) { + return clamp((x - lo) / (hi - lo), 0.0, 1.0); +} + +void main(void) { + float angle = atan(-vEndPoint.y + vStartPoint.y, + vEndPoint.x - vStartPoint.x); + float sa = sin(angle); + float ca = cos(angle); + + float sx = vStartPoint.x * ca - vStartPoint.y * sa; + float ex = vEndPoint.x * ca - vEndPoint.y * sa; + float d = ex - sx; + + float x = vPos.x * ca - vPos.y * sa; + + oFragColor = mix(vColors[0], + vColors[1], + linearStep(sx + d * offset(0), sx + d * offset(1), x)); + + for (int i=1 ; i < vStopCount-1 ; ++i) { + oFragColor = mix(oFragColor, + vColors[i+1], + linearStep(sx + d * offset(i), sx + d * offset(i+1), x)); + } +} diff --git a/res/ps_angle_gradient.glsl b/res/ps_angle_gradient.glsl new file mode 100644 index 0000000000..fae2211af5 --- /dev/null +++ b/res/ps_angle_gradient.glsl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define MAX_STOPS_PER_ANGLE_GRADIENT 8 + +flat varying int vStopCount; +flat varying float vAngle; +flat varying vec2 vStartPoint; +flat varying vec2 vEndPoint; +varying vec2 vPos; +flat varying vec4 vColors[MAX_STOPS_PER_ANGLE_GRADIENT]; +flat varying vec4 vOffsets[MAX_STOPS_PER_ANGLE_GRADIENT/4]; diff --git a/res/ps_angle_gradient.vs.glsl b/res/ps_angle_gradient.vs.glsl new file mode 100644 index 0000000000..b8d845a2f7 --- /dev/null +++ b/res/ps_angle_gradient.vs.glsl @@ -0,0 +1,51 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct AngleGradient { + PrimitiveInfo info; + vec4 local_rect; + vec4 start_end_point; + uvec4 stop_count; + vec4 colors[MAX_STOPS_PER_ANGLE_GRADIENT]; + vec4 offsets[MAX_STOPS_PER_ANGLE_GRADIENT/4]; +}; + +layout(std140) uniform Items { + AngleGradient gradients[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + AngleGradient gradient = gradients[gl_InstanceID]; + Layer layer = layers[gradient.info.layer_tile_part.x]; + Tile tile = tiles[gradient.info.layer_tile_part.y]; + + vec2 local_pos = mix(gradient.local_rect.xy, + gradient.local_rect.xy + gradient.local_rect.zw, + aPosition.xy); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + vStopCount = int(gradient.stop_count.x); + vPos = local_clamped_pos.xy; + vStartPoint = gradient.start_end_point.xy; + vEndPoint = gradient.start_end_point.zw; + + for (int i=0 ; i < int(gradient.stop_count.x) ; ++i) { + vColors[i] = gradient.colors[i]; + vOffsets[i] = gradient.offsets[i]; + } + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl new file mode 100644 index 0000000000..9f0ae2a099 --- /dev/null +++ b/res/ps_border.fs.glsl @@ -0,0 +1,17 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + if (vRadii.x > 0.0 && + (distance(vRefPoint, vPos) > vRadii.x || + distance(vRefPoint, vPos) < vRadii.z)) { + discard; + } + + if (vF > 0.0) { + oFragColor = vColor0; + } else { + oFragColor = vColor1; + } +} diff --git a/res/ps_border.glsl b/res/ps_border.glsl new file mode 100644 index 0000000000..0a035f87d7 --- /dev/null +++ b/res/ps_border.glsl @@ -0,0 +1,13 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying float vF; +varying vec2 vPos; + +flat varying vec4 vColor0; +flat varying vec4 vColor1; +flat varying vec4 vRadii; +flat varying vec2 vRefPoint; diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl new file mode 100644 index 0000000000..3f6e4b2ff6 --- /dev/null +++ b/res/ps_border.vs.glsl @@ -0,0 +1,92 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Border { + PrimitiveInfo info; + vec4 local_rect; + vec4 color0; + vec4 color1; + vec4 radii; +}; + +layout(std140) uniform Items { + Border borders[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Border border = borders[gl_InstanceID]; + Layer layer = layers[border.info.layer_tile_part.x]; + Tile tile = tiles[border.info.layer_tile_part.y]; + + vec2 local_pos = mix(border.local_rect.xy, + border.local_rect.xy + border.local_rect.zw, + aPosition.xy); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); + + vRadii = border.radii; + + float w = border.local_rect.z; + float h = border.local_rect.w; + float x0, y0, x1, y1; + switch (border.info.layer_tile_part.z) { + case PST_TOP_LEFT: + x0 = border.local_rect.x; + y0 = border.local_rect.y; + x1 = border.local_rect.x + border.local_rect.z; + y1 = border.local_rect.y + border.local_rect.w; + vRefPoint = vec2(x0, y0) + vRadii.xy; + break; + case PST_TOP_RIGHT: + vRefPoint = border.local_rect.xy + vRadii.xy; + x0 = border.local_rect.x + border.local_rect.z; + y0 = border.local_rect.y; + x1 = border.local_rect.x; + y1 = border.local_rect.y + border.local_rect.w; + vRefPoint = vec2(x0, y0) + vec2(-vRadii.x, vRadii.y); + break; + case PST_BOTTOM_LEFT: + x0 = border.local_rect.x; + y0 = border.local_rect.y + border.local_rect.w; + x1 = border.local_rect.x + border.local_rect.z; + y1 = border.local_rect.y; + vRefPoint = vec2(x0, y0) + vec2(vRadii.x, -vRadii.y); + break; + case PST_BOTTOM_RIGHT: + x0 = border.local_rect.x; + y0 = border.local_rect.y; + x1 = border.local_rect.x + border.local_rect.z; + y1 = border.local_rect.y + border.local_rect.w; + vRefPoint = vec2(x1, y1) + vec2(-vRadii.x, -vRadii.y); + break; + case PST_TOP: + case PST_LEFT: + case PST_BOTTOM: + case PST_RIGHT: + vRefPoint = border.local_rect.xy; + x0 = border.local_rect.x; + y0 = border.local_rect.y; + x1 = border.local_rect.x + border.local_rect.z; + y1 = border.local_rect.y + border.local_rect.w; + break; + } + vF = (local_clamped_pos.x - x0) * (y1 - y0) - (local_clamped_pos.y - y0) * (x1 - x0); + + vColor0 = border.color0; + vColor1 = border.color1; + vPos = local_clamped_pos.xy; +} diff --git a/res/ps_box_shadow.fs.glsl b/res/ps_box_shadow.fs.glsl new file mode 100644 index 0000000000..3f7d15514c --- /dev/null +++ b/res/ps_box_shadow.fs.glsl @@ -0,0 +1,151 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// See http://asciimath.org to render the equations here. + +// The Gaussian function used for blurring: +// +// G_sigma(x) = 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) +float gauss(float x, float sigma) { + float sigmaPow2 = sigma * sigma; + return 1.0 / sqrt(6.283185307179586 * sigmaPow2) * exp(-(x * x) / (2.0 * sigmaPow2)); +} + +// An approximation of the error function, which is related to the integral of the Gaussian +// function: +// +// "erf"(x) = 2/sqrt(pi) int_0^x e^(-t^2) dt +// ~~ 1 - 1 / (1 + a_1 x + a_2 x^2 + a_3 x^3 + a_4 x^4)^4 +// +// where: +// +// a_1 = 0.278393, a_2 = 0.230389, a_3 = 0.000972, a_4 = 0.078108 +// +// This approximation is accurate to `5 xx 10^-4`, more than accurate enough for our purposes. +// +// See: https://en.wikipedia.org/wiki/Error_function#Approximation_with_elementary_functions +float erf(float x) { + bool negative = x < 0.0; + if (negative) + x = -x; + float x2 = x * x; + float x3 = x2 * x; + float x4 = x2 * x2; + float denom = 1.0 + 0.278393 * x + 0.230389 * x2 + 0.000972 * x3 + 0.078108 * x4; + float result = 1.0 - 1.0 / (denom * denom * denom * denom); + return negative ? -result : result; +} + +// A useful helper for calculating integrals of the Gaussian function via the error function: +// +// "erf"_sigma(x) = 2 int 1/sqrt(2 pi sigma^2) e^(-x^2/(2 sigma^2)) dx +// = "erf"(x/(sigma sqrt(2))) +float erfSigma(float x, float sigma) { + return erf(x / (sigma * 1.4142135623730951)); +} + +// Returns the blurred color value from the box itself (not counting any rounded corners). `p_0` is +// the vector distance to the top left corner of the box; `p_1` is the vector distance to its +// bottom right corner. +// +// "colorFromRect"_sigma(p_0, p_1) +// = int_{p_{0_y}}^{p_{1_y}} int_{p_{1_x}}^{p_{0_x}} G_sigma(y) G_sigma(x) dx dy +// = 1/4 ("erf"_sigma(p_{1_x}) - "erf"_sigma(p_{0_x})) +// ("erf"_sigma(p_{1_y}) - "erf"_sigma(p_{0_y})) +float colorFromRect(vec2 p0, vec2 p1, float sigma) { + return (erfSigma(p1.x, sigma) - erfSigma(p0.x, sigma)) * + (erfSigma(p1.y, sigma) - erfSigma(p0.y, sigma)) / 4.0; +} + +// Returns the `x` coordinate on the ellipse with the given radii for the given `y` coordinate: +// +// "ellipsePoint"(y, y_0, a, b) = a sqrt(1 - ((y - y_0) / b)^2) +float ellipsePoint(float y, float y0, vec2 radii) { + float bStep = (y - y0) / radii.y; + return radii.x * sqrt(1.0 - bStep * bStep); +} + +// A helper function to compute the value that needs to be subtracted to accommodate the border +// corners. +// +// "colorCutout"_sigma(x_{0_l}, x_{0_r}, y_0, y_{min}, y_{max}, a, b) +// = int_{y_{min}}^{y_{max}} +// int_{x_{0_r} + "ellipsePoint"(y, y_0, a, b)}^{x_{0_r} + a} G_sigma(y) G_sigma(x) dx +// + int_{x_{0_l} - a}^{x_{0_l} - "ellipsePoint"(y, y_0, a, b)} G_sigma(y) G_sigma(x) +// dx dy +// = int_{y_{min}}^{y_{max}} 1/2 G_sigma(y) +// ("erf"_sigma(x_{0_r} + a) - "erf"_sigma(x_{0_r} + "ellipsePoint"(y, y_0, a, b)) + +// "erf"_sigma(x_{0_l} - "ellipsePoint"(y, y_0, a, b)) - "erf"_sigma(x_{0_l} - a)) +// +// with the outer integral evaluated numerically. +float colorCutoutGeneral(float x0l, + float x0r, + float y0, + float yMin, + float yMax, + vec2 radii, + float sigma) { + float sum = 0.0; + for (float y = yMin; y <= yMax; y += 1.0) { + float xEllipsePoint = ellipsePoint(y, y0, radii); + sum += gauss(y, sigma) * + (erfSigma(x0r + radii.x, sigma) - erfSigma(x0r + xEllipsePoint, sigma) + + erfSigma(x0l - xEllipsePoint, sigma) - erfSigma(x0l - radii.x, sigma)); + } + return sum / 2.0; +} + +// The value that needs to be subtracted to accommodate the top border corners. +float colorCutoutTop(float x0l, float x0r, float y0, vec2 radii, float sigma) { + return colorCutoutGeneral(x0l, x0r, y0, y0, y0 + radii.y, radii, sigma); +} + +// The value that needs to be subtracted to accommodate the bottom border corners. +float colorCutoutBottom(float x0l, float x0r, float y0, vec2 radii, float sigma) { + return colorCutoutGeneral(x0l, x0r, y0, y0 - radii.y, y0, radii, sigma); +} + +// The blurred color value for the point at `pos` with the top left corner of the box at +// `p_{0_"rect"}` and the bottom right corner of the box at `p_{1_"rect"}`. +float color(vec2 pos, vec2 p0Rect, vec2 p1Rect, vec2 radii, float sigma) { + // Compute the vector distances `p_0` and `p_1`. + vec2 p0 = p0Rect - pos, p1 = p1Rect - pos; + + // Compute the basic color `"colorFromRect"_sigma(p_0, p_1)`. This is all we have to do if + // the box is unrounded. + float cRect = colorFromRect(p0, p1, sigma); + if (radii.x == 0.0 || radii.y == 0.0) + return cRect; + + // Compute the inner corners of the box, taking border radii into account: `x_{0_l}`, + // `y_{0_t}`, `x_{0_r}`, and `y_{0_b}`. + float x0l = p0.x + radii.x; + float y0t = p1.y - radii.y; + float x0r = p1.x - radii.x; + float y0b = p0.y + radii.y; + + // Compute the final color: + // + // "colorFromRect"_sigma(p_0, p_1) - + // ("colorCutoutTop"_sigma(x_{0_l}, x_{0_r}, y_{0_t}, a, b) + + // "colorCutoutBottom"_sigma(x_{0_l}, x_{0_r}, y_{0_b}, a, b)) + float cCutoutTop = colorCutoutTop(x0l, x0r, y0t, radii, sigma); + float cCutoutBottom = colorCutoutBottom(x0l, x0r, y0b, radii, sigma); + return cRect - (cCutoutTop + cCutoutBottom); +} + +void main(void) { + vec2 pos = vPos.xy; + vec2 p0Rect = vBoxShadowRect.xy, p1Rect = vBoxShadowRect.zw; + vec2 radii = vBorderRadii.xy; + float sigma = vBlurRadius / 2.0; + float value = color(pos, p0Rect, p1Rect, radii, sigma); + + value = max(value, 0.0); + oFragColor = vec4(vColor.rgb, vInverted == 1.0 ? 1.0 - value : value); +} diff --git a/res/ps_box_shadow.glsl b/res/ps_box_shadow.glsl new file mode 100644 index 0000000000..26fdba588f --- /dev/null +++ b/res/ps_box_shadow.glsl @@ -0,0 +1,11 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vPos; +flat varying vec4 vColor; +flat varying vec2 vBorderRadii; +flat varying float vBlurRadius; +flat varying vec4 vBoxShadowRect; +flat varying vec4 vSrcRect; +flat varying float vInverted; diff --git a/res/ps_box_shadow.vs.glsl b/res/ps_box_shadow.vs.glsl new file mode 100644 index 0000000000..212813ffec --- /dev/null +++ b/res/ps_box_shadow.vs.glsl @@ -0,0 +1,51 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct BoxShadow { + PrimitiveInfo info; + vec4 local_rect; + vec4 color; + vec4 border_radii_blur_radius_inverted; + vec4 bs_rect; + vec4 src_rect; +}; + +layout(std140) uniform Items { + BoxShadow boxshadows[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + BoxShadow bs = boxshadows[gl_InstanceID]; + Layer layer = layers[bs.info.layer_tile_part.x]; + Tile tile = tiles[bs.info.layer_tile_part.y]; + + vColor = bs.color; + + vec2 local_pos = mix(bs.local_rect.xy, + bs.local_rect.xy + bs.local_rect.zw, + aPosition.xy); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + + vPos = local_clamped_pos.xy; + vColor = bs.color; + vBorderRadii = bs.border_radii_blur_radius_inverted.xy; + vBlurRadius = bs.border_radii_blur_radius_inverted.z; + vBoxShadowRect = vec4(bs.bs_rect.xy, bs.bs_rect.xy + bs.bs_rect.zw); + vSrcRect = vec4(bs.src_rect.xy, bs.src_rect.xy + bs.src_rect.zw); + vInverted = bs.border_radii_blur_radius_inverted.w; + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/mask.vs.glsl b/res/ps_clear.fs.glsl similarity index 66% rename from res/mask.vs.glsl rename to res/ps_clear.fs.glsl index 491f3ea386..5ad3065f78 100644 --- a/res/mask.vs.glsl +++ b/res/ps_clear.fs.glsl @@ -2,8 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -void main(void) -{ - vColor = aColorRectTL / 255.0; - gl_Position = uTransform * vec4(aPosition, 1.0); +void main(void) { + oFragColor = vec4(1, 1, 1, 1); } diff --git a/res/ps_clear.glsl b/res/ps_clear.glsl new file mode 100644 index 0000000000..e0032240a4 --- /dev/null +++ b/res/ps_clear.glsl @@ -0,0 +1,3 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ diff --git a/res/ps_clear.vs.glsl b/res/ps_clear.vs.glsl new file mode 100644 index 0000000000..514f6fc716 --- /dev/null +++ b/res/ps_clear.vs.glsl @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct ClearTile { + uvec4 rect; +}; + +layout(std140) uniform Tiles { + ClearTile tiles[WR_MAX_CLEAR_TILES]; +}; + + +void main() { + ClearTile tile = tiles[gl_InstanceID]; + + vec4 rect = tile.rect; + + vec4 pos = vec4(mix(rect.xy, rect.xy + rect.zw, aPosition.xy), 0, 1); + gl_Position = uTransform * pos; +} diff --git a/res/clear.vs.glsl b/res/ps_gradient.fs.glsl similarity index 66% rename from res/clear.vs.glsl rename to res/ps_gradient.fs.glsl index 491f3ea386..2bf7e8c0a0 100644 --- a/res/clear.vs.glsl +++ b/res/ps_gradient.fs.glsl @@ -2,8 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -void main(void) -{ - vColor = aColorRectTL / 255.0; - gl_Position = uTransform * vec4(aPosition, 1.0); +void main(void) { + oFragColor = mix(vColor0, vColor1, vF); } diff --git a/res/ps_gradient.glsl b/res/ps_gradient.glsl new file mode 100644 index 0000000000..679b34b648 --- /dev/null +++ b/res/ps_gradient.glsl @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying float vF; +flat varying vec4 vColor0; +flat varying vec4 vColor1; diff --git a/res/ps_gradient.vs.glsl b/res/ps_gradient.vs.glsl new file mode 100644 index 0000000000..81d00b2861 --- /dev/null +++ b/res/ps_gradient.vs.glsl @@ -0,0 +1,57 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define DIR_HORIZONTAL uint(0) +#define DIR_VERTICAL uint(1) + +struct Gradient { + PrimitiveInfo info; + vec4 local_rect; + vec4 color0; + vec4 color1; + uvec4 dir; +}; + +layout(std140) uniform Items { + Gradient gradients[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Gradient gradient = gradients[gl_InstanceID]; + Layer layer = layers[gradient.info.layer_tile_part.x]; + Tile tile = tiles[gradient.info.layer_tile_part.y]; + + vec2 local_pos = mix(gradient.local_rect.xy, + gradient.local_rect.xy + gradient.local_rect.zw, + aPosition.xy); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + + vec2 f = (local_clamped_pos.xy - gradient.local_rect.xy) / gradient.local_rect.zw; + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); + + switch (gradient.dir.x) { + case DIR_HORIZONTAL: + vF = f.x; + break; + case DIR_VERTICAL: + vF = f.y; + break; + } + + vColor0 = gradient.color0; + vColor1 = gradient.color1; +} diff --git a/res/ps_image.fs.glsl b/res/ps_image.fs.glsl new file mode 100644 index 0000000000..a7d9685005 --- /dev/null +++ b/res/ps_image.fs.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec2 st = vTextureOffset + vTextureSize * fract(vUv); + oFragColor = texture(sDiffuse, st); +} diff --git a/res/ps_image.glsl b/res/ps_image.glsl new file mode 100644 index 0000000000..e2c59d9ff6 --- /dev/null +++ b/res/ps_image.glsl @@ -0,0 +1,7 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv; // Location within the CSS box to draw. +flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas. +flat varying vec2 vTextureSize; // Size of the image in the texture atlas. diff --git a/res/ps_image.vs.glsl b/res/ps_image.vs.glsl new file mode 100644 index 0000000000..1393e6c8df --- /dev/null +++ b/res/ps_image.vs.glsl @@ -0,0 +1,49 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Image { + PrimitiveInfo info; + vec4 local_rect; // Size of the box we need to fill with this image. + vec4 st_rect; // Location of the image texture in the texture atlas. + vec2 stretch_size; // Size of the actual image. +}; + +layout(std140) uniform Items { + Image images[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Image image = images[gl_InstanceID]; + Layer layer = layers[image.info.layer_tile_part.x]; + Tile tile = tiles[image.info.layer_tile_part.y]; + + // Our location within the image + vec2 local_pos = mix(image.local_rect.xy, + image.local_rect.xy + image.local_rect.zw, + aPosition.xy); + + local_pos = clamp(local_pos, + image.info.local_clip_rect.xy, + image.info.local_clip_rect.xy + image.info.local_clip_rect.zw); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + + // vUv will contain how many times this image has wrapped around the image size. + vUv = (local_clamped_pos.xy - image.local_rect.xy) / image.stretch_size.xy; + vTextureSize = image.st_rect.zw - image.st_rect.xy; + vTextureOffset = image.st_rect.xy; + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/ps_image_transform.fs.glsl b/res/ps_image_transform.fs.glsl new file mode 100644 index 0000000000..57fdc563ad --- /dev/null +++ b/res/ps_image_transform.fs.glsl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec2 pos = vPos.xy / vPos.z; + + if (!point_in_rect(pos, vRect.xy, vRect.xy + vRect.zw)) { + discard; + } + + oFragColor = texture(sDiffuse, vUv / vPos.z); +} diff --git a/res/ps_image_transform.glsl b/res/ps_image_transform.glsl new file mode 100644 index 0000000000..77c0eb2071 --- /dev/null +++ b/res/ps_image_transform.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv; + +varying vec3 vPos; +flat varying vec4 vRect; diff --git a/res/ps_image_transform.vs.glsl b/res/ps_image_transform.vs.glsl new file mode 100644 index 0000000000..a5c2836256 --- /dev/null +++ b/res/ps_image_transform.vs.glsl @@ -0,0 +1,65 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Image { + PrimitiveInfo info; + vec4 local_rect; + vec4 st_rect; +}; + +layout(std140) uniform Items { + Image images[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Image image = images[gl_InstanceID]; + Layer layer = layers[image.info.layer_tile_part.x]; + Tile tile = tiles[image.info.layer_tile_part.y]; + + vec2 p0 = image.local_rect.xy; + vec2 p1 = image.local_rect.xy + vec2(image.local_rect.z, 0.0); + vec2 p2 = image.local_rect.xy + vec2(0.0, image.local_rect.w); + vec2 p3 = image.local_rect.xy + image.local_rect.zw; + + vec4 t0 = layer.transform * vec4(p0, 0, 1); + vec4 t1 = layer.transform * vec4(p1, 0, 1); + vec4 t2 = layer.transform * vec4(p2, 0, 1); + vec4 t3 = layer.transform * vec4(p3, 0, 1); + + vec2 tp0 = t0.xy / t0.w; + vec2 tp1 = t1.xy / t1.w; + vec2 tp2 = t2.xy / t2.w; + vec2 tp3 = t3.xy / t3.w; + + vec2 min_pos = min(tp0.xy, min(tp1.xy, min(tp2.xy, tp3.xy))); + vec2 max_pos = max(tp0.xy, max(tp1.xy, max(tp2.xy, tp3.xy))); + + vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec2 clamped_pos = mix(min_pos_clamped, + max_pos_clamped, + aPosition.xy); + + vec3 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, image.info.layer_tile_part.x); + + vRect = image.local_rect; + vPos = layer_pos; + + vec2 f = (layer_pos.xy - image.local_rect.xy) / image.local_rect.zw; + + vUv = mix(image.st_rect.xy, + image.st_rect.zw, + f); + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/mask.fs.glsl b/res/ps_rectangle.fs.glsl similarity index 89% rename from res/mask.fs.glsl rename to res/ps_rectangle.fs.glsl index 658ac27488..e9aae64138 100644 --- a/res/mask.fs.glsl +++ b/res/ps_rectangle.fs.glsl @@ -4,5 +4,5 @@ void main(void) { - SetFragColor(vColor); + oFragColor = vColor; } diff --git a/res/clear.fs.glsl b/res/ps_rectangle.glsl similarity index 81% rename from res/clear.fs.glsl rename to res/ps_rectangle.glsl index 658ac27488..6fcfc4255b 100644 --- a/res/clear.fs.glsl +++ b/res/ps_rectangle.glsl @@ -2,7 +2,4 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -void main(void) -{ - SetFragColor(vColor); -} +varying vec4 vColor; diff --git a/res/ps_rectangle.vs.glsl b/res/ps_rectangle.vs.glsl new file mode 100644 index 0000000000..5f04ddc8c8 --- /dev/null +++ b/res/ps_rectangle.vs.glsl @@ -0,0 +1,42 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Rectangle { + PrimitiveInfo info; + vec4 local_rect; + vec4 color; +}; + +layout(std140) uniform Items { + Rectangle rects[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Rectangle rect = rects[gl_InstanceID]; + Layer layer = layers[rect.info.layer_tile_part.x]; + Tile tile = tiles[rect.info.layer_tile_part.y]; + + vColor = rect.color; + + vec2 local_pos = mix(rect.local_rect.xy, + rect.local_rect.xy + rect.local_rect.zw, + aPosition.xy); + + local_pos = clamp(local_pos, + rect.info.local_clip_rect.xy, + rect.info.local_clip_rect.xy + rect.info.local_clip_rect.zw); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/ps_rectangle_clip.fs.glsl b/res/ps_rectangle_clip.fs.glsl new file mode 100644 index 0000000000..fe3af9162a --- /dev/null +++ b/res/ps_rectangle_clip.fs.glsl @@ -0,0 +1,9 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + do_clip(vPos, vClipRect, vClipRadius); + + oFragColor = vColor; +} diff --git a/res/tile.vs.glsl b/res/ps_rectangle_clip.glsl similarity index 57% rename from res/tile.vs.glsl rename to res/ps_rectangle_clip.glsl index 7f57bf1e36..fcb151e49f 100644 --- a/res/tile.vs.glsl +++ b/res/ps_rectangle_clip.glsl @@ -1,11 +1,10 @@ +#line 1 + /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -void main(void) -{ - vColorTexCoord = aBorderRadii.xy; - vBorderPosition = aBorderPosition; - gl_Position = uTransform * vec4(aPosition, 1.0); -} - +varying vec4 vColor; +varying vec2 vPos; +flat varying vec4 vClipRect; +flat varying float vClipRadius; // TODO: Expand to handle irregular radii! diff --git a/res/ps_rectangle_clip.vs.glsl b/res/ps_rectangle_clip.vs.glsl new file mode 100644 index 0000000000..c08704136a --- /dev/null +++ b/res/ps_rectangle_clip.vs.glsl @@ -0,0 +1,49 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Rectangle { + PrimitiveInfo info; + vec4 local_rect; + vec4 color; + Clip clip; +}; + +layout(std140) uniform Items { + Rectangle rects[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Rectangle rect = rects[gl_InstanceID]; + Layer layer = layers[rect.info.layer_tile_part.x]; + Tile tile = tiles[rect.info.layer_tile_part.y]; + + vColor = rect.color; + + vec2 local_pos = mix(rect.local_rect.xy, + rect.local_rect.xy + rect.local_rect.zw, + aPosition.xy); + + local_pos = clamp(local_pos, + rect.info.local_clip_rect.xy, + rect.info.local_clip_rect.xy + rect.info.local_clip_rect.zw); + + vClipRect = rect.clip.rect; + vClipRadius = rect.clip.top_left.outer_inner_radius.x; + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + vPos = local_clamped_pos.xy; + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/ps_rectangle_transform.fs.glsl b/res/ps_rectangle_transform.fs.glsl new file mode 100644 index 0000000000..a8ac40a845 --- /dev/null +++ b/res/ps_rectangle_transform.fs.glsl @@ -0,0 +1,13 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + vec2 pos = vPos.xy / vPos.z; + + if (!point_in_rect(pos, vRect.xy, vRect.xy + vRect.zw)) { + discard; + } + + oFragColor = vColor; +} diff --git a/res/ps_rectangle_transform.glsl b/res/ps_rectangle_transform.glsl new file mode 100644 index 0000000000..0ae7f839aa --- /dev/null +++ b/res/ps_rectangle_transform.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec4 vColor; + +varying vec3 vPos; +flat varying vec4 vRect; diff --git a/res/ps_rectangle_transform.vs.glsl b/res/ps_rectangle_transform.vs.glsl new file mode 100644 index 0000000000..9d10cad7e9 --- /dev/null +++ b/res/ps_rectangle_transform.vs.glsl @@ -0,0 +1,60 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Rectangle { + PrimitiveInfo info; + vec4 local_rect; + vec4 color; +}; + +layout(std140) uniform Items { + Rectangle rects[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Rectangle rect = rects[gl_InstanceID]; + Layer layer = layers[rect.info.layer_tile_part.x]; + Tile tile = tiles[rect.info.layer_tile_part.y]; + + vec2 p0 = rect.local_rect.xy; + vec2 p1 = rect.local_rect.xy + vec2(rect.local_rect.z, 0.0); + vec2 p2 = rect.local_rect.xy + vec2(0.0, rect.local_rect.w); + vec2 p3 = rect.local_rect.xy + rect.local_rect.zw; + + vec4 t0 = layer.transform * vec4(p0, 0, 1); + vec4 t1 = layer.transform * vec4(p1, 0, 1); + vec4 t2 = layer.transform * vec4(p2, 0, 1); + vec4 t3 = layer.transform * vec4(p3, 0, 1); + + vec2 tp0 = t0.xy / t0.w; + vec2 tp1 = t1.xy / t1.w; + vec2 tp2 = t2.xy / t2.w; + vec2 tp3 = t3.xy / t3.w; + + vec2 min_pos = min(tp0.xy, min(tp1.xy, min(tp2.xy, tp3.xy))); + vec2 max_pos = max(tp0.xy, max(tp1.xy, max(tp2.xy, tp3.xy))); + + vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec2 clamped_pos = mix(min_pos_clamped, + max_pos_clamped, + aPosition.xy); + + vec3 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, rect.info.layer_tile_part.x); + + vRect = rect.local_rect; + vPos = layer_pos; + vColor = rect.color; + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/ps_text.fs.glsl b/res/ps_text.fs.glsl new file mode 100644 index 0000000000..175102f790 --- /dev/null +++ b/res/ps_text.fs.glsl @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +void main(void) { + float a = texture(sDiffuse, vUv).a; + oFragColor = vec4(vColor.rgb, vColor.a * a); +} diff --git a/res/ps_text.glsl b/res/ps_text.glsl new file mode 100644 index 0000000000..dad284fb0a --- /dev/null +++ b/res/ps_text.glsl @@ -0,0 +1,6 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +flat varying vec4 vColor; +varying vec2 vUv; diff --git a/res/ps_text.vs.glsl b/res/ps_text.vs.glsl new file mode 100644 index 0000000000..733f91bcbd --- /dev/null +++ b/res/ps_text.vs.glsl @@ -0,0 +1,48 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Glyph { + PrimitiveInfo info; + vec4 local_rect; + vec4 color; + vec4 st_rect; +}; + +layout(std140) uniform Items { + Glyph glyphs[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Glyph glyph = glyphs[gl_InstanceID]; + Layer layer = layers[glyph.info.layer_tile_part.x]; + Tile tile = tiles[glyph.info.layer_tile_part.y]; + + vColor = glyph.color; + + vec2 p0 = floor(0.5 + glyph.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = p0 + glyph.local_rect.zw; + + vec2 local_pos = mix(p0, p1, aPosition.xy); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + + vec2 f = (local_clamped_pos.xy - p0) / glyph.local_rect.zw; + + vUv = mix(glyph.st_rect.xy, + glyph.st_rect.zw, + f); + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/quad.fs.glsl b/res/quad.fs.glsl deleted file mode 100644 index 8909cd0755..0000000000 --- a/res/quad.fs.glsl +++ /dev/null @@ -1,38 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -// GLSL point in rect test. -// See: https://stackoverflow.com/questions/12751080/glsl-point-inside-box-test -bool PointInRect(vec2 p, vec2 p0, vec2 p1) -{ - vec2 s = step(p0, p) - step(p1, p); - return s.x * s.y != 0.0; -} - -void main(void) -{ - // Clip out. - if (PointInRect(vPosition, vClipOutRect.xy, vClipOutRect.zw)) { - discard; - } - - // Clip in. - if (!PointInRect(vPosition, vClipInRect.xy, vClipInRect.zw)) { - discard; - } - - // Apply image tiling parameters (offset and scale) to color UVs. - vec2 colorTexCoord = vTileParams.xy + fract(vColorTexCoord.xy) * vTileParams.zw; - vec2 maskTexCoord = vMaskTexCoord.xy; - - // Fetch the diffuse and mask texels. - vec4 diffuse = Texture(sDiffuse, colorTexCoord); - vec4 mask = Texture(sMask, maskTexCoord); - - // Extract alpha from the mask (component depends on platform) - float alpha = GetAlphaFromMask(mask); - - // Write the final fragment color. - SetFragColor(diffuse * vec4(vColor.rgb, vColor.a * alpha)); -} diff --git a/res/quad.vs.glsl b/res/quad.vs.glsl deleted file mode 100644 index 5b43fc539b..0000000000 --- a/res/quad.vs.glsl +++ /dev/null @@ -1,112 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -vec2 Bilerp2(vec2 tl, vec2 tr, vec2 br, vec2 bl, vec2 st) { - return mix(mix(tl, bl, st.y), mix(tr, br, st.y), st.x); -} - -vec4 Bilerp4(vec4 tl, vec4 tr, vec4 br, vec4 bl, vec2 st) { - return mix(mix(tl, bl, st.y), mix(tr, br, st.y), st.x); -} - -void main(void) -{ - // Extract the image tiling parameters. - // These are passed to the fragment shader, since - // the uv interpolation must be done per-fragment. - vTileParams = uTileParams[Bottom7Bits(int(aMisc.w))]; - - // Determine clip rects. - vClipOutRect = uClipRects[int(aMisc.z)]; - vec4 clipInRect = uClipRects[int(aMisc.y)]; - - // Extract the complete (stacking context + css transform) transform - // for this vertex. Transform the position by it. - vec2 offsetParams = uOffsets[Bottom7Bits(int(aMisc.x))].xy; - mat4 matrix = uMatrixPalette[Bottom7Bits(int(aMisc.x))]; - - vec2 p0 = aPositionRect.xy + offsetParams; - vec2 p1 = p0 + aPositionRect.zw; - - vec2 rect_origin = SnapToPixels(p0); - vec2 rect_size = SnapToPixels(p1) - rect_origin; - - // Determine the position, color, and mask texture coordinates of this vertex. - vec4 localPos = vec4(0.0, 0.0, 0.0, 1.0); - bool isBorderCorner = int(aMisc.w) >= 0x80; - bool isBottomTriangle = IsBottomTriangle(); - if (aPosition.y == 0.0) { - localPos.y = rect_origin.y; - if (aPosition.x == 0.0) { - localPos.x = rect_origin.x; - if (isBorderCorner) { - vColor = isBottomTriangle ? aColorRectBL : aColorRectTR; - } - } else { - localPos.x = rect_origin.x + rect_size.x; - if (isBorderCorner) { - vColor = aColorRectTR; - } - } - } else { - localPos.y = rect_origin.y + rect_size.y; - if (aPosition.x == 0.0) { - localPos.x = rect_origin.x; - if (isBorderCorner) { - vColor = aColorRectBL; - } - } else { - localPos.x = rect_origin.x + rect_size.x; - if (isBorderCorner) { - vColor = isBottomTriangle ? aColorRectBL : aColorRectTR; - } - } - } - - // Rotate or clip as necessary. If there is no rotation, we can clip here in the vertex shader - // and save a whole bunch of fragment shader invocations. If there is a rotation, we fall back - // to FS clipping. - // - // The rotation angle is encoded as a negative bottom left u coordinate. (uv coordinates should - // always be nonnegative normally, and gradients don't use color textures, so this is fine.) - vec4 colorTexCoordRectBottom = aColorTexCoordRectBottom; - vec2 localST; - if (colorTexCoordRectBottom.z < 0.0) { - float angle = -colorTexCoordRectBottom.z; - vec2 center = rect_origin + rect_size / 2.0; - vec2 translatedPos = localPos.xy - center; - localST = (localPos.xy - rect_origin) / rect_size; - localPos.xy = vec2(translatedPos.x * cos(angle) - translatedPos.y * sin(angle), - translatedPos.x * sin(angle) + translatedPos.y * cos(angle)) + center; - colorTexCoordRectBottom.z = aColorTexCoordRectTop.x; - vClipInRect = clipInRect; - } else { - localPos.x = clamp(localPos.x, clipInRect.x, clipInRect.z); - localPos.y = clamp(localPos.y, clipInRect.y, clipInRect.w); - localST = (localPos.xy - rect_origin) / rect_size; - vClipInRect = vec4(-1e37, -1e37, 1e38, 1e38); - } - - vColorTexCoord = Bilerp2(aColorTexCoordRectTop.xy, aColorTexCoordRectTop.zw, - colorTexCoordRectBottom.xy, colorTexCoordRectBottom.zw, - localST); - vMaskTexCoord = Bilerp2(aMaskTexCoordRectTop.xy, aMaskTexCoordRectTop.zw, - aMaskTexCoordRectBottom.xy, aMaskTexCoordRectBottom.zw, - localST); - if (!isBorderCorner) { - vColor = Bilerp4(aColorRectTL, aColorRectTR, aColorRectBR, aColorRectBL, localST); - } - - // Normalize the vertex color and mask texture coordinates. - vColor /= 255.0; - vMaskTexCoord /= uAtlasParams.zw; - - vPosition = localPos.xy; - - vec4 worldPos = matrix * localPos; - - // Transform by the orthographic projection into clip space. - gl_Position = uTransform * worldPos; -} - diff --git a/res/shared.glsl b/res/shared.glsl new file mode 100644 index 0000000000..b4d8cc14b0 --- /dev/null +++ b/res/shared.glsl @@ -0,0 +1,43 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//====================================================================================== +// Vertex shader attributes and uniforms +//====================================================================================== +#ifdef WR_VERTEX_SHADER + #define varying out + + // Uniform inputs + uniform mat4 uTransform; // Orthographic projection + uniform float uDevicePixelRatio; + + // Attribute inputs + in vec3 aPosition; +#endif + +//====================================================================================== +// Fragment shader attributes and uniforms +//====================================================================================== +#ifdef WR_FRAGMENT_SHADER + #define varying in + + // Uniform inputs + uniform sampler2D sDiffuse; + uniform sampler2D sMask; + + // Fragment shader outputs + out vec4 oFragColor; +#endif + +//====================================================================================== +// Interpolator definitions +//====================================================================================== + +//====================================================================================== +// VS only types and UBOs +//====================================================================================== + +//====================================================================================== +// VS only functions +//====================================================================================== diff --git a/res/shared_other.glsl b/res/shared_other.glsl new file mode 100644 index 0000000000..847fd1c143 --- /dev/null +++ b/res/shared_other.glsl @@ -0,0 +1,64 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//====================================================================================== +// Vertex shader attributes and uniforms +//====================================================================================== +#ifdef WR_VERTEX_SHADER + in vec4 aColorTexCoordRectTop; + in vec4 aColorRectTL; + + // box-shadow + in vec4 aBorderPosition; + in vec4 aBorderRadii; + in float aBlurRadius; + + // blur + in vec2 aDestTextureSize; + in vec2 aSourceTextureSize; +#endif + +//====================================================================================== +// Fragment shader attributes and uniforms +//====================================================================================== +#ifdef WR_FRAGMENT_SHADER + uniform vec2 uDirection; +#endif + +//====================================================================================== +// Interpolator definitions +//====================================================================================== + +// Hacks to be removed (needed for text etc) +varying vec2 vColorTexCoord; +varying vec4 vColor; + +// box_shadow +varying vec2 vPosition; +varying vec4 vBorderPosition; +varying vec4 vBorderRadii; +varying float vBlurRadius; + +// blur +varying vec2 vSourceTextureSize; +varying vec2 vDestTextureSize; + +//====================================================================================== +// VS only types and UBOs +//====================================================================================== + +//====================================================================================== +// VS only functions +//====================================================================================== + +//====================================================================================== +// FS only functions +//====================================================================================== +#ifdef WR_FRAGMENT_SHADER + +void SetFragColor(vec4 color) { + oFragColor = color; +} + +#endif diff --git a/res/tile.fs.glsl b/res/tile.fs.glsl deleted file mode 100644 index 3355ee4646..0000000000 --- a/res/tile.fs.glsl +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec2 textureSize = vBorderPosition.zw - vBorderPosition.xy; - vec2 colorTexCoord = vBorderPosition.xy + mod(vColorTexCoord.xy, 1.0) * textureSize; - vec4 diffuse = Texture(sDiffuse, colorTexCoord); - SetFragColor(diffuse); -} - From 901a783fcc7ad1f543eafa11a624c402f2756668 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Wed, 20 Jul 2016 08:27:41 -0700 Subject: [PATCH 14/33] Add first pass support for dotted box border styles --- res/prim_shared.glsl | 12 ++++++++++ res/ps_border.fs.glsl | 56 +++++++++++++++++++++++++++++++++++++++---- res/ps_border.glsl | 19 +++++++++++---- res/ps_border.vs.glsl | 40 +++++++++++++++++++++++++++---- res/shared.glsl | 2 +- 5 files changed, 114 insertions(+), 15 deletions(-) diff --git a/res/prim_shared.glsl b/res/prim_shared.glsl index 04bee0e335..26fb41935f 100644 --- a/res/prim_shared.glsl +++ b/res/prim_shared.glsl @@ -13,6 +13,18 @@ #define PST_BOTTOM uint(7) #define PST_RIGHT uint(8) +// Border styles as defined in webrender_traits/types.rs +#define BORDER_STYLE_NONE uint(0) +#define BORDER_STYLE_SOLID uint(1) +#define BORDER_STYLE_DOUBLE uint(2) +#define BORDER_STYLE_DOTTED uint(3) +#define BORDER_STYLE_DASHED uint(4) +#define BORDER_STYLE_HIDDEN uint(5) +#define BORDER_STYLE_GROOVE uint(6) +#define BORDER_STYLE_RIDGE uint(7) +#define BORDER_STYLE_INSET uint(8) +#define BORDER_STYLE_OUTSET uint(9) + struct Layer { mat4 transform; mat4 inv_transform; diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 9f0ae2a099..7f15af1ed1 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -2,6 +2,45 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +// draw a circle at position aDesiredPos with a aRadius +vec4 drawCircle(vec2 aPixel, vec2 aDesiredPos, float aRadius, vec3 aColor) { + float farFromCenter = length(aDesiredPos - aPixel) - aRadius; + float pixelInCircle = 1.00 - clamp(farFromCenter, 0.0, 1.0); + return vec4(aColor, pixelInCircle); +} + +void draw_dotted_border(void) { + // Everything here should be in device pixels. + float radius = 3; // Diameter of 20 + float diameter = radius * 2.0; + float circleSpacing = diameter * 2.0; + + vec2 size = vec2(vBorders.z - vBorders.x, vBorders.w - vBorders.y); + // Get our position within this specific segment + vec2 position = vPos - vBorders.xy; + + // Break our position into square tiles with circles in them. + vec2 circleCount = size / circleSpacing; + vec2 distBetweenCircles = size / circleCount; + vec2 circleCenter = distBetweenCircles / 2.0; + + // Find out which tile this pixel belongs to. + vec2 destTile = floor(position / distBetweenCircles); + destTile = destTile * distBetweenCircles; + vec2 tileCenter = destTile + circleCenter; + + // Find the position within the tile + vec2 positionInTile = mod(position, distBetweenCircles); + vec2 finalPosition = positionInTile + destTile; + + vec4 white = vec4(1.0, 1.0, 1.0, 1.0); + vec3 black = vec3(0.0, 0.0, 0.0); + // See if we should draw a circle or not + vec4 circleColor = drawCircle(finalPosition, tileCenter, radius, black); + + oFragColor = mix(white, circleColor, circleColor.a); +} + void main(void) { if (vRadii.x > 0.0 && (distance(vRefPoint, vPos) > vRadii.x || @@ -9,9 +48,18 @@ void main(void) { discard; } - if (vF > 0.0) { - oFragColor = vColor0; - } else { - oFragColor = vColor1; + switch (vBorderStyle) { + case BORDER_STYLE_DOTTED: + draw_dotted_border(); + break; + case BORDER_STYLE_NONE: + case BORDER_STYLE_SOLID: + { + float color = step(0.0, vF); + vec4 red = vec4(1, 0, 0, 1); + vec4 green = vec4(0, 1, 0, 1); + oFragColor = mix(green, red, color); + break; } + } } diff --git a/res/ps_border.glsl b/res/ps_border.glsl index 0a035f87d7..86b7819233 100644 --- a/res/ps_border.glsl +++ b/res/ps_border.glsl @@ -4,10 +4,19 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -varying float vF; -varying vec2 vPos; +// These two are interpolated +varying float vF; // This is a weighting as we get closer to the bottom right corner? -flat varying vec4 vColor0; -flat varying vec4 vColor1; -flat varying vec4 vRadii; +// These are not changing. +flat varying vec4 vColor0; // The border color +flat varying vec4 vColor1; // The border color +flat varying vec4 vRadii; // The border radius + +// These are in device space +varying vec2 vPos; // This is the clamped position of the current position. +flat varying vec4 vBorders; // The borders + +// for corners, this is the beginning of the corner. +// For the lines, this is the top left of the line. flat varying vec2 vRefPoint; +flat varying int vBorderStyle; diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index 3f6e4b2ff6..13a5f7023b 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -9,12 +9,26 @@ struct Border { vec4 color0; vec4 color1; vec4 radii; + ivec4 border_style_trbl; }; layout(std140) uniform Items { Border borders[WR_MAX_PRIM_ITEMS]; }; +int get_border_style(Border a_border, uint a_edge) { + switch (a_edge) { + case PST_TOP: + return a_border.border_style_trbl.x; + case PST_LEFT: + return a_border.border_style_trbl.z; + case PST_BOTTOM: + return a_border.border_style_trbl.w; + case PST_RIGHT: + return a_border.border_style_trbl.y; + } +} + void main(void) { Border border = borders[gl_InstanceID]; Layer layer = layers[border.info.layer_tile_part.x]; @@ -38,21 +52,25 @@ void main(void) { gl_Position = uTransform * vec4(final_pos, 0, 1); + // Just our boring radius position. vRadii = border.radii; - float w = border.local_rect.z; - float h = border.local_rect.w; float x0, y0, x1, y1; + vBorderStyle = 0; switch (border.info.layer_tile_part.z) { + // These are the layer tile part PrimitivePart as uploaded by the tiling.rs case PST_TOP_LEFT: x0 = border.local_rect.x; y0 = border.local_rect.y; + // These are width / heights x1 = border.local_rect.x + border.local_rect.z; y1 = border.local_rect.y + border.local_rect.w; + + // The radius here is the border-radius. This is 0, so vRefPoint will + // just be the top left (x,y) corner. vRefPoint = vec2(x0, y0) + vRadii.xy; break; case PST_TOP_RIGHT: - vRefPoint = border.local_rect.xy + vRadii.xy; x0 = border.local_rect.x + border.local_rect.z; y0 = border.local_rect.y; x1 = border.local_rect.x; @@ -84,9 +102,21 @@ void main(void) { y1 = border.local_rect.y + border.local_rect.w; break; } - vF = (local_clamped_pos.x - x0) * (y1 - y0) - (local_clamped_pos.y - y0) * (x1 - x0); + vBorderStyle = get_border_style(border, border.info.layer_tile_part.z); + + // y1 - y0 is the height of the corner / line + // x1 - x0 is the width of the corner / line. + float width = x1 - x0; + float height = y1 - y0; + // This is just a weighting of the pixel colors it seems? + vF = (local_clamped_pos.x - x0) * height - (local_clamped_pos.y - y0) * width; + + // This is what was currently sent. vColor0 = border.color0; vColor1 = border.color1; - vPos = local_clamped_pos.xy; + + // These are in device space + vPos = clamped_pos; + vBorders = vec4(x0, y0, x1, y1) * uDevicePixelRatio; } diff --git a/res/shared.glsl b/res/shared.glsl index b4d8cc14b0..ccc69e8e0a 100644 --- a/res/shared.glsl +++ b/res/shared.glsl @@ -10,7 +10,7 @@ // Uniform inputs uniform mat4 uTransform; // Orthographic projection - uniform float uDevicePixelRatio; + uniform float uDevicePixelRatio; // Attribute inputs in vec3 aPosition; From 71733df2086e68057a45d0cf3c5d6afbee948884 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 22 Jul 2016 15:51:06 -0700 Subject: [PATCH 15/33] Create dots based on size of border width. Make enough space to properly draw all the circle --- res/ps_border.fs.glsl | 34 ++++++++++++++++++++++++++++++---- res/ps_border.glsl | 7 ++++--- res/ps_border.vs.glsl | 8 ++++---- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 7f15af1ed1..8eab725fb3 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -9,9 +9,34 @@ vec4 drawCircle(vec2 aPixel, vec2 aDesiredPos, float aRadius, vec3 aColor) { return vec4(aColor, pixelInCircle); } +// We want to be in the center of the tile along the axis we're +// repeating the circle but at the top for X axis and left for Y axis. +// e.g. we only care about being equal spacing between circles for the edge we're drawing along +// and snap the other axis to the top or left. +vec2 adjust_dotted_padding(float radius) { + switch (vBorderPart) { + // These are the layer tile part PrimitivePart as uploaded by the tiling.rs + case PST_TOP_LEFT: + case PST_TOP_RIGHT: + case PST_BOTTOM_LEFT: + case PST_BOTTOM_RIGHT: + return vec2(0.0, 0.0); + case PST_BOTTOM: + case PST_TOP: + return vec2(0, -radius); + case PST_LEFT: + case PST_RIGHT: + return vec2(-radius, 0); + } +} + void draw_dotted_border(void) { // Everything here should be in device pixels. - float radius = 3; // Diameter of 20 + // We want the dot to be roughly the size of the whole border spacing + // 2.2 was picked because it's roughly what Firefox is using. + float spacing_fudge = 2.2; + float border_spacing = min(vBorders.z - vBorders.x, vBorders.w - vBorders.y); + float radius = floor(border_spacing / spacing_fudge); float diameter = radius * 2.0; float circleSpacing = diameter * 2.0; @@ -27,7 +52,10 @@ void draw_dotted_border(void) { // Find out which tile this pixel belongs to. vec2 destTile = floor(position / distBetweenCircles); destTile = destTile * distBetweenCircles; + + // Where we want to draw the actual circle. vec2 tileCenter = destTile + circleCenter; + tileCenter += adjust_dotted_padding(radius); // Find the position within the tile vec2 positionInTile = mod(position, distBetweenCircles); @@ -56,9 +84,7 @@ void main(void) { case BORDER_STYLE_SOLID: { float color = step(0.0, vF); - vec4 red = vec4(1, 0, 0, 1); - vec4 green = vec4(0, 1, 0, 1); - oFragColor = mix(green, red, color); + oFragColor = mix(vColor1, vColor0, color); break; } } diff --git a/res/ps_border.glsl b/res/ps_border.glsl index 86b7819233..16a34ffad5 100644 --- a/res/ps_border.glsl +++ b/res/ps_border.glsl @@ -10,13 +10,14 @@ varying float vF; // This is a weighting as we get closer to the bottom right // These are not changing. flat varying vec4 vColor0; // The border color flat varying vec4 vColor1; // The border color -flat varying vec4 vRadii; // The border radius +flat varying vec4 vRadii; // The border radius from CSS border-radius // These are in device space varying vec2 vPos; // This is the clamped position of the current position. -flat varying vec4 vBorders; // The borders +flat varying vec4 vBorders; // The borders sizes. // for corners, this is the beginning of the corner. // For the lines, this is the top left of the line. flat varying vec2 vRefPoint; -flat varying int vBorderStyle; +flat varying uint vBorderStyle; +flat varying uint vBorderPart; // Which part of the border we're drawing. diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index 13a5f7023b..e39f3b6e5c 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -9,14 +9,14 @@ struct Border { vec4 color0; vec4 color1; vec4 radii; - ivec4 border_style_trbl; + uvec4 border_style_trbl; }; layout(std140) uniform Items { Border borders[WR_MAX_PRIM_ITEMS]; }; -int get_border_style(Border a_border, uint a_edge) { +uint get_border_style(Border a_border, uint a_edge) { switch (a_edge) { case PST_TOP: return a_border.border_style_trbl.x; @@ -56,8 +56,8 @@ void main(void) { vRadii = border.radii; float x0, y0, x1, y1; - vBorderStyle = 0; - switch (border.info.layer_tile_part.z) { + vBorderPart = border.info.layer_tile_part.z; + switch (vBorderPart) { // These are the layer tile part PrimitivePart as uploaded by the tiling.rs case PST_TOP_LEFT: x0 = border.local_rect.x; From 3a8b93eea7fbc7ea3f2c4ae9fd01c461e351fb25 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 22 Jul 2016 16:21:42 -0700 Subject: [PATCH 16/33] dotted borders for corners --- res/ps_border.fs.glsl | 42 +++++++++++++++++++++++++++++++++++++----- res/ps_border.vs.glsl | 10 ++++++++-- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 8eab725fb3..0316ab9b6a 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -16,11 +16,11 @@ vec4 drawCircle(vec2 aPixel, vec2 aDesiredPos, float aRadius, vec3 aColor) { vec2 adjust_dotted_padding(float radius) { switch (vBorderPart) { // These are the layer tile part PrimitivePart as uploaded by the tiling.rs - case PST_TOP_LEFT: + case PST_BOTTOM_RIGHT: case PST_TOP_RIGHT: case PST_BOTTOM_LEFT: - case PST_BOTTOM_RIGHT: - return vec2(0.0, 0.0); + case PST_TOP_LEFT: + return vec2(-radius, -radius); case PST_BOTTOM: case PST_TOP: return vec2(0, -radius); @@ -30,7 +30,11 @@ vec2 adjust_dotted_padding(float radius) { } } -void draw_dotted_border(void) { +vec4 draw_dotted_corner() { + return vec4(1, 0, 0, 1.0); +} + +vec4 draw_dotted_edge() { // Everything here should be in device pixels. // We want the dot to be roughly the size of the whole border spacing // 2.2 was picked because it's roughly what Firefox is using. @@ -55,6 +59,9 @@ void draw_dotted_border(void) { // Where we want to draw the actual circle. vec2 tileCenter = destTile + circleCenter; + // Snap the tile back because we calculate the center + // based on the spacing but we need to make sure we have enough + // space to draw the actual circle. tileCenter += adjust_dotted_padding(radius); // Find the position within the tile @@ -66,7 +73,25 @@ void draw_dotted_border(void) { // See if we should draw a circle or not vec4 circleColor = drawCircle(finalPosition, tileCenter, radius, black); - oFragColor = mix(white, circleColor, circleColor.a); + return mix(white, circleColor, circleColor.a); +} + +void draw_dotted_border(void) { + switch (vBorderPart) { + // These are the layer tile part PrimitivePart as uploaded by the tiling.rs + case PST_TOP_LEFT: + case PST_TOP_RIGHT: + case PST_BOTTOM_LEFT: + case PST_BOTTOM_RIGHT: + oFragColor = draw_dotted_edge(); + break; + case PST_BOTTOM: + case PST_TOP: + case PST_LEFT: + case PST_RIGHT: + oFragColor = draw_dotted_edge(); + break; + } } void main(void) { @@ -78,8 +103,10 @@ void main(void) { switch (vBorderStyle) { case BORDER_STYLE_DOTTED: + { draw_dotted_border(); break; + } case BORDER_STYLE_NONE: case BORDER_STYLE_SOLID: { @@ -87,5 +114,10 @@ void main(void) { oFragColor = mix(vColor1, vColor0, color); break; } + default: + { + discard; + break; + } } } diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index e39f3b6e5c..e7cec7836c 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -19,11 +19,15 @@ layout(std140) uniform Items { uint get_border_style(Border a_border, uint a_edge) { switch (a_edge) { case PST_TOP: + case PST_TOP_LEFT: return a_border.border_style_trbl.x; + case PST_BOTTOM_LEFT: case PST_LEFT: return a_border.border_style_trbl.z; + case PST_BOTTOM_RIGHT: case PST_BOTTOM: return a_border.border_style_trbl.w; + case PST_TOP_RIGHT: case PST_RIGHT: return a_border.border_style_trbl.y; } @@ -103,7 +107,7 @@ void main(void) { break; } - vBorderStyle = get_border_style(border, border.info.layer_tile_part.z); + vBorderStyle = get_border_style(border, vBorderPart); // y1 - y0 is the height of the corner / line // x1 - x0 is the width of the corner / line. @@ -118,5 +122,7 @@ void main(void) { // These are in device space vPos = clamped_pos; - vBorders = vec4(x0, y0, x1, y1) * uDevicePixelRatio; + vBorders = vec4(border.local_rect.x, border.local_rect.y, + border.local_rect.x + border.local_rect.z, + border.local_rect.y + border.local_rect.w) * uDevicePixelRatio; } From 0194d3865deeddf85c0fe9fef2d7665112993e63 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 22 Jul 2016 16:26:52 -0700 Subject: [PATCH 17/33] mostly works --- res/ps_border.fs.glsl | 2 +- res/ps_border.glsl | 2 +- res/ps_border.vs.glsl | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 0316ab9b6a..500faf5728 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -39,7 +39,7 @@ vec4 draw_dotted_edge() { // We want the dot to be roughly the size of the whole border spacing // 2.2 was picked because it's roughly what Firefox is using. float spacing_fudge = 2.2; - float border_spacing = min(vBorders.z - vBorders.x, vBorders.w - vBorders.y); + float border_spacing = min(vBorders.w, vBorders.z); float radius = floor(border_spacing / spacing_fudge); float diameter = radius * 2.0; float circleSpacing = diameter * 2.0; diff --git a/res/ps_border.glsl b/res/ps_border.glsl index 16a34ffad5..52f633b5ee 100644 --- a/res/ps_border.glsl +++ b/res/ps_border.glsl @@ -14,7 +14,7 @@ flat varying vec4 vRadii; // The border radius from CSS border-radius // These are in device space varying vec2 vPos; // This is the clamped position of the current position. -flat varying vec4 vBorders; // The borders sizes. +flat varying vec4 vBorders; // the rect of the border in (x, y, width, height) form // for corners, this is the beginning of the corner. // For the lines, this is the top left of the line. diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index e7cec7836c..0f01ec5aa9 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -123,6 +123,6 @@ void main(void) { // These are in device space vPos = clamped_pos; vBorders = vec4(border.local_rect.x, border.local_rect.y, - border.local_rect.x + border.local_rect.z, - border.local_rect.y + border.local_rect.w) * uDevicePixelRatio; + border.local_rect.z, + border.local_rect.w) * uDevicePixelRatio; } From b42424c7c52b5ecc156e4876e9451f5a17d5bc54 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Fri, 22 Jul 2016 16:46:08 -0700 Subject: [PATCH 18/33] properly space circles in edges. Fixed up size of dots --- res/ps_border.fs.glsl | 44 +++++++++---------------------------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 500faf5728..13962d56d3 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -9,47 +9,24 @@ vec4 drawCircle(vec2 aPixel, vec2 aDesiredPos, float aRadius, vec3 aColor) { return vec4(aColor, pixelInCircle); } -// We want to be in the center of the tile along the axis we're -// repeating the circle but at the top for X axis and left for Y axis. -// e.g. we only care about being equal spacing between circles for the edge we're drawing along -// and snap the other axis to the top or left. -vec2 adjust_dotted_padding(float radius) { - switch (vBorderPart) { - // These are the layer tile part PrimitivePart as uploaded by the tiling.rs - case PST_BOTTOM_RIGHT: - case PST_TOP_RIGHT: - case PST_BOTTOM_LEFT: - case PST_TOP_LEFT: - return vec2(-radius, -radius); - case PST_BOTTOM: - case PST_TOP: - return vec2(0, -radius); - case PST_LEFT: - case PST_RIGHT: - return vec2(-radius, 0); - } -} - -vec4 draw_dotted_corner() { - return vec4(1, 0, 0, 1.0); -} - vec4 draw_dotted_edge() { // Everything here should be in device pixels. // We want the dot to be roughly the size of the whole border spacing - // 2.2 was picked because it's roughly what Firefox is using. - float spacing_fudge = 2.2; float border_spacing = min(vBorders.w, vBorders.z); - float radius = floor(border_spacing / spacing_fudge); + float radius = floor(border_spacing / 2.0); float diameter = radius * 2.0; - float circleSpacing = diameter * 2.0; + // The amount of space between dots. 2.2 was chosen because it looks kind of + // like firefox. + float circleSpacing = diameter * 2.2; - vec2 size = vec2(vBorders.z - vBorders.x, vBorders.w - vBorders.y); + vec2 size = vec2(vBorders.z, vBorders.w); // Get our position within this specific segment vec2 position = vPos - vBorders.xy; // Break our position into square tiles with circles in them. - vec2 circleCount = size / circleSpacing; + vec2 circleCount = floor(size / circleSpacing); + circleCount = max(circleCount, 1); + vec2 distBetweenCircles = size / circleCount; vec2 circleCenter = distBetweenCircles / 2.0; @@ -59,10 +36,6 @@ vec4 draw_dotted_edge() { // Where we want to draw the actual circle. vec2 tileCenter = destTile + circleCenter; - // Snap the tile back because we calculate the center - // based on the spacing but we need to make sure we have enough - // space to draw the actual circle. - tileCenter += adjust_dotted_padding(radius); // Find the position within the tile vec2 positionInTile = mod(position, distBetweenCircles); @@ -83,6 +56,7 @@ void draw_dotted_border(void) { case PST_TOP_RIGHT: case PST_BOTTOM_LEFT: case PST_BOTTOM_RIGHT: + // TODO: Fix for corners with a border-radius oFragColor = draw_dotted_edge(); break; case PST_BOTTOM: From d6ea0138dfe44dd2e066e9062696a4d7a4ff8e6d Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Sat, 23 Jul 2016 07:33:37 +1000 Subject: [PATCH 19/33] Various reftest, shader, snapping fixes. --- res/cache_shared.glsl | 98 ------ res/composite_shared.glsl | 115 ------- res/cs_p1.fs.glsl | 14 - res/cs_p1_ic.fs.glsl | 34 -- res/cs_p1_ic.vs.glsl | 44 --- res/cs_p1_partial.fs.glsl | 16 - res/cs_p1_partial.glsl | 9 - res/cs_p1_partial.vs.glsl | 12 - res/cs_p2.fs.glsl | 17 - res/cs_p2.vs.glsl | 13 - res/cs_p2_partial.fs.glsl | 32 -- res/cs_p2_partial.glsl | 10 - res/cs_p2_partial.vs.glsl | 27 -- res/cs_p3.fs.glsl | 19 -- res/cs_p3.glsl | 9 - res/cs_p3.vs.glsl | 14 - res/cs_p3_partial.fs.glsl | 24 -- res/cs_p3_partial.glsl | 11 - res/cs_p3_partial.vs.glsl | 14 - res/cs_p4.fs.glsl | 21 -- res/cs_p4.glsl | 10 - res/cs_p4.vs.glsl | 15 - res/cs_p4_partial.fs.glsl | 28 -- res/cs_p4_partial.glsl | 12 - res/cs_p4_partial.vs.glsl | 15 - res/cs_p5.fs.glsl | 23 -- res/cs_p5.glsl | 12 - res/cs_p5.vs.glsl | 16 - res/cs_p5_partial.fs.glsl | 32 -- res/cs_p5_partial.glsl | 15 - res/cs_p5_partial.vs.glsl | 16 - res/cs_p6.fs.glsl | 25 -- res/cs_p6.glsl | 13 - res/cs_p6.vs.glsl | 17 - res/cs_p6_partial.fs.glsl | 35 -- res/cs_p6_partial.glsl | 16 - res/cs_p6_partial.vs.glsl | 17 - res/cs_p7.fs.glsl | 27 -- res/cs_p7.glsl | 14 - res/cs_p7.vs.glsl | 18 -- res/cs_p7_partial.fs.glsl | 40 --- res/cs_p7_partial.glsl | 17 - res/cs_p7_partial.vs.glsl | 18 -- res/cs_p8.fs.glsl | 29 -- res/cs_p8.glsl | 15 - res/cs_p8.vs.glsl | 19 -- res/cs_p8_partial.fs.glsl | 44 --- res/cs_p8_partial.glsl | 18 -- res/cs_p8_partial.vs.glsl | 19 -- res/prim_shared.glsl | 2 +- res/{cs_p1_ic.glsl => ps_blend.fs.glsl} | 10 +- res/{cs_p1.glsl => ps_blend.glsl} | 5 +- res/ps_blend.vs.glsl | 29 ++ res/ps_border.vs.glsl | 16 +- res/ps_composite.fs.glsl | 320 +++++++++++++++++++ res/{cs_p2.glsl => ps_composite.glsl} | 4 +- res/ps_composite.vs.glsl | 37 +++ res/ps_image.vs.glsl | 15 +- res/{cs_p1.vs.glsl => ps_image_clip.fs.glsl} | 11 +- res/ps_image_clip.glsl | 10 + res/ps_image_clip.vs.glsl | 54 ++++ res/ps_rectangle.fs.glsl | 3 +- res/ps_rectangle.vs.glsl | 17 +- res/ps_rectangle_clip.vs.glsl | 2 +- 64 files changed, 497 insertions(+), 1186 deletions(-) delete mode 100644 res/cache_shared.glsl delete mode 100644 res/composite_shared.glsl delete mode 100644 res/cs_p1.fs.glsl delete mode 100644 res/cs_p1_ic.fs.glsl delete mode 100644 res/cs_p1_ic.vs.glsl delete mode 100644 res/cs_p1_partial.fs.glsl delete mode 100644 res/cs_p1_partial.glsl delete mode 100644 res/cs_p1_partial.vs.glsl delete mode 100644 res/cs_p2.fs.glsl delete mode 100644 res/cs_p2.vs.glsl delete mode 100644 res/cs_p2_partial.fs.glsl delete mode 100644 res/cs_p2_partial.glsl delete mode 100644 res/cs_p2_partial.vs.glsl delete mode 100644 res/cs_p3.fs.glsl delete mode 100644 res/cs_p3.glsl delete mode 100644 res/cs_p3.vs.glsl delete mode 100644 res/cs_p3_partial.fs.glsl delete mode 100644 res/cs_p3_partial.glsl delete mode 100644 res/cs_p3_partial.vs.glsl delete mode 100644 res/cs_p4.fs.glsl delete mode 100644 res/cs_p4.glsl delete mode 100644 res/cs_p4.vs.glsl delete mode 100644 res/cs_p4_partial.fs.glsl delete mode 100644 res/cs_p4_partial.glsl delete mode 100644 res/cs_p4_partial.vs.glsl delete mode 100644 res/cs_p5.fs.glsl delete mode 100644 res/cs_p5.glsl delete mode 100644 res/cs_p5.vs.glsl delete mode 100644 res/cs_p5_partial.fs.glsl delete mode 100644 res/cs_p5_partial.glsl delete mode 100644 res/cs_p5_partial.vs.glsl delete mode 100644 res/cs_p6.fs.glsl delete mode 100644 res/cs_p6.glsl delete mode 100644 res/cs_p6.vs.glsl delete mode 100644 res/cs_p6_partial.fs.glsl delete mode 100644 res/cs_p6_partial.glsl delete mode 100644 res/cs_p6_partial.vs.glsl delete mode 100644 res/cs_p7.fs.glsl delete mode 100644 res/cs_p7.glsl delete mode 100644 res/cs_p7.vs.glsl delete mode 100644 res/cs_p7_partial.fs.glsl delete mode 100644 res/cs_p7_partial.glsl delete mode 100644 res/cs_p7_partial.vs.glsl delete mode 100644 res/cs_p8.fs.glsl delete mode 100644 res/cs_p8.glsl delete mode 100644 res/cs_p8.vs.glsl delete mode 100644 res/cs_p8_partial.fs.glsl delete mode 100644 res/cs_p8_partial.glsl delete mode 100644 res/cs_p8_partial.vs.glsl rename res/{cs_p1_ic.glsl => ps_blend.fs.glsl} (59%) rename res/{cs_p1.glsl => ps_blend.glsl} (79%) create mode 100644 res/ps_blend.vs.glsl create mode 100644 res/ps_composite.fs.glsl rename res/{cs_p2.glsl => ps_composite.glsl} (81%) create mode 100644 res/ps_composite.vs.glsl rename res/{cs_p1.vs.glsl => ps_image_clip.fs.glsl} (56%) create mode 100644 res/ps_image_clip.glsl create mode 100644 res/ps_image_clip.vs.glsl diff --git a/res/cache_shared.glsl b/res/cache_shared.glsl deleted file mode 100644 index a56f74ddd5..0000000000 --- a/res/cache_shared.glsl +++ /dev/null @@ -1,98 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#define CORNER_TOP_LEFT uint(0) -#define CORNER_TOP_RIGHT uint(1) -#define CORNER_BOTTOM_LEFT uint(2) -#define CORNER_BOTTOM_RIGHT uint(3) - -struct ClipCorner { - vec4 rect; - vec4 outer_inner_radius; -}; - -struct Clip { - vec4 rect; - uvec4 clip_kind_layer_p2; - ClipCorner top_left; - ClipCorner top_right; - ClipCorner bottom_left; - ClipCorner bottom_right; -}; - -struct Layer { - mat4 transform; - mat4 inv_transform; - vec4 screen_vertices[4]; - vec4 blend_info; -}; - -layout(std140) uniform Layers { - Layer layers[256]; -}; - -bool ray_plane(vec3 normal, vec3 point, vec3 ray_origin, vec3 ray_dir, out float t) -{ - float denom = dot(normal, ray_dir); - if (denom > 1e-6) { - vec3 d = point - ray_origin; - t = dot(d, normal) / denom; - return t >= 0.0; - } - - return false; -} - -vec4 untransform(vec2 ref, vec3 n, vec3 a, mat4 inv_transform) { - vec3 p = vec3(ref, -10000.0); - vec3 d = vec3(0, 0, 1.0); - - float t; - ray_plane(n, a, p, d, t); - vec3 c = p + d * t; - - vec4 r = inv_transform * vec4(c, 1.0); - return r; -} - -vec3 get_layer_pos(vec2 pos, uint layer_index) { - Layer layer = layers[layer_index]; - vec3 a = layer.screen_vertices[0].xyz / layer.screen_vertices[0].w; - vec3 b = layer.screen_vertices[3].xyz / layer.screen_vertices[3].w; - vec3 c = layer.screen_vertices[2].xyz / layer.screen_vertices[2].w; - vec3 n = normalize(cross(b-a, c-a)); - vec4 local_pos = untransform(pos, n, a, layer.inv_transform); - return local_pos.xyw; -} - -float do_clip(vec2 pos, vec4 clip_rect, float radius) { - vec2 ref_tl = clip_rect.xy + vec2( radius, radius); - vec2 ref_tr = clip_rect.zy + vec2(-radius, radius); - vec2 ref_bl = clip_rect.xw + vec2( radius, -radius); - vec2 ref_br = clip_rect.zw + vec2(-radius, -radius); - - float d_tl = distance(pos, ref_tl); - float d_tr = distance(pos, ref_tr); - float d_bl = distance(pos, ref_bl); - float d_br = distance(pos, ref_br); - - bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > radius; - bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > radius; - bool out2 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > radius; - bool out3 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > radius; - - // TODO(gw): Alpha anti-aliasing based on edge distance! - if (out0 || out1 || out2 || out3) { - return 0.0; - } else { - return 1.0; - } -} - -bool point_in_rect(vec2 p, vec2 p0, vec2 p1) { - return p.x >= p0.x && - p.y >= p0.y && - p.x <= p1.x && - p.y <= p1.y; -} diff --git a/res/composite_shared.glsl b/res/composite_shared.glsl deleted file mode 100644 index 8d357e4060..0000000000 --- a/res/composite_shared.glsl +++ /dev/null @@ -1,115 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#define MAX_PRIMS_PER_COMPOSITE (8) - -#define INVALID_LAYER_INDEX uint(0xffffffff) - -uniform sampler2D sLayer0; -uniform sampler2D sLayer1; -uniform sampler2D sLayer2; -uniform sampler2D sLayer3; -uniform sampler2D sLayer4; -uniform sampler2D sLayer5; -uniform sampler2D sLayer6; -uniform sampler2D sLayer7; -uniform sampler2D sCache; - -struct CompositeTile { - ivec4 rect; - ivec4 src_rects[MAX_PRIMS_PER_COMPOSITE]; - vec4 blend_info[MAX_PRIMS_PER_COMPOSITE/4]; -}; - -layout(std140) uniform Tiles { - CompositeTile tiles[WR_MAX_COMPOSITE_TILES]; -}; - -#ifdef WR_VERTEX_SHADER - -/* -uint pack_rect(ivec4 rect, ivec2 ref_point) { - int x0 = max(0, rect.x - ref_point.x); - int y0 = max(0, rect.y - ref_point.y); - int x1 = min(rect.x + rect.z - ref_point.x, 255); // should never hit with right preconditions in bsp tree! - int y1 = min(rect.y + rect.w - ref_point.y, 255); - - uint x = uint(x0) << 0; - uint y = uint(y0) << 8; - uint z = uint(x1) << 16; - uint w = uint(y1) << 24; - return x | y | z | w; -} -*/ - -void write_prim(CompositeTile tile, - int index, - out vec2 uv, - out float blend_info) { - uv = mix(tile.src_rects[index].xy / 2048.0, - (tile.src_rects[index].xy + tile.src_rects[index].zw) / 2048.0, - aPosition.xy); - blend_info = tile.blend_info[index/4][index % 4]; -} - -/* -void write_partial_prim(vec2 pos, - uint prim_index, - CompositeTile tile, - out vec2 uv, - out uint partial_rect, - out float blend_info) { - Renderable ren = renderables[prim_index]; - vec4 prim_rect = ren.screen_rect; - vec2 f = (pos - prim_rect.xy) / prim_rect.zw; - uv = mix(ren.st_rect.xy, ren.st_rect.zw, f); - - partial_rect = pack_rect(ren.screen_rect, tile.rect.xy); - blend_info = ren.local_offset_blend_info.z; -} -*/ - -void write_vertex(CompositeTile tile) { - vec4 pos = vec4(mix(tile.rect.xy, - tile.rect.xy + tile.rect.zw, - aPosition.xy), - 0.0, - 1.0); - - //vTilePos = pos.xy - tile.rect.xy; - - gl_Position = uTransform * pos; - //return pos.xy; -} - -#endif - -#ifdef WR_FRAGMENT_SHADER - -/* -ivec4 unpack_rect(uint rect) { - int x = int(rect & uint(0x000000ff)); - int y = int((rect & uint(0x0000ff00)) >> 8); - int z = int((rect & uint(0x00ff0000)) >> 16); - int w = int((rect & uint(0xff000000)) >> 24); - return ivec4(x, y, z, w); -} - -bool is_prim_valid(uint packed_rect) { - ivec4 rect = unpack_rect(packed_rect); - - return vTilePos.x > rect.x && - vTilePos.x < rect.z && - vTilePos.y > rect.y && - vTilePos.y < rect.w; -} -*/ - -vec4 fetch_initial_color() { - return vec4(1, 1, 1, 0); -} - -#endif diff --git a/res/cs_p1.fs.glsl b/res/cs_p1.fs.glsl deleted file mode 100644 index deada98da4..0000000000 --- a/res/cs_p1.fs.glsl +++ /dev/null @@ -1,14 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 result = fetch_initial_color(); - - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues.x); - - oFragColor = result; -} diff --git a/res/cs_p1_ic.fs.glsl b/res/cs_p1_ic.fs.glsl deleted file mode 100644 index 15a84ecffa..0000000000 --- a/res/cs_p1_ic.fs.glsl +++ /dev/null @@ -1,34 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 prim_colors[4]; - prim_colors[0] = texture(sLayer0, vUv0); - prim_colors[1] = texture(sLayer1, vUv1); - prim_colors[2] = texture(sLayer2, vUv2); - prim_colors[3] = texture(sLayer3, vUv3); - - vec4 result = vec4(1, 1, 1, 1); - vec4 layer_color = vec4(0, 0, 0, 0); - - layer_color = mix(layer_color, prim_colors[0], prim_colors[0].a); - result = mix(result, layer_color, layer_color.a * vLayerValues.x); - layer_color = mix(layer_color, vec4(0, 0, 0, 0), vec4(vLayerValues.x > 0.0)); - - layer_color = mix(layer_color, prim_colors[1], prim_colors[1].a); - result = mix(result, layer_color, layer_color.a * vLayerValues.y); - layer_color = mix(layer_color, vec4(0, 0, 0, 0), vec4(vLayerValues.y > 0.0)); - - layer_color = mix(layer_color, prim_colors[2], prim_colors[2].a); - result = mix(result, layer_color, layer_color.a * vLayerValues.z); - layer_color = mix(layer_color, vec4(0, 0, 0, 0), vec4(vLayerValues.z > 0.0)); - - layer_color = mix(layer_color, prim_colors[3], prim_colors[3].a); - result = mix(result, layer_color, layer_color.a * vLayerValues.w); - layer_color = mix(layer_color, vec4(0, 0, 0, 0), vec4(vLayerValues.w > 0.0)); - - oFragColor = result; -} diff --git a/res/cs_p1_ic.vs.glsl b/res/cs_p1_ic.vs.glsl deleted file mode 100644 index 80c86c72a1..0000000000 --- a/res/cs_p1_ic.vs.glsl +++ /dev/null @@ -1,44 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - vec2 pos = write_vertex(tile); - - vUv0 = write_prim(pos, tile.prim_indices[0].x); - vUv1 = write_prim(pos, tile.prim_indices[0].y); - vUv2 = write_prim(pos, tile.prim_indices[0].z); - vUv3 = write_prim(pos, tile.prim_indices[0].w); - - uint li0 = tile.layer_indices[0].x; - uint li1 = tile.layer_indices[0].y; - uint li2 = tile.layer_indices[0].z; - uint li3 = tile.layer_indices[0].w; - - if (li0 == INVALID_LAYER_INDEX || li0 == li1) { - vLayerValues.x = 0.0; - } else { - vLayerValues.x = layers[li0].blend_info.x; - } - - if (li1 == INVALID_LAYER_INDEX || li1 == li2) { - vLayerValues.y = 0.0; - } else { - vLayerValues.y = layers[li1].blend_info.x; - } - - if (li2 == INVALID_LAYER_INDEX || li2 == li3) { - vLayerValues.z = 0.0; - } else { - vLayerValues.z = layers[li2].blend_info.x; - } - - if (li3 == INVALID_LAYER_INDEX) { - vLayerValues.w = 0.0; - } else { - vLayerValues.w = layers[li3].blend_info.x; - } -} diff --git a/res/cs_p1_partial.fs.glsl b/res/cs_p1_partial.fs.glsl deleted file mode 100644 index 041939d57b..0000000000 --- a/res/cs_p1_partial.fs.glsl +++ /dev/null @@ -1,16 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 result = fetch_initial_color(); - - if (is_prim_valid(vPartialRects0.x)) { - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues0.x); - } - - oFragColor = result; -} diff --git a/res/cs_p1_partial.glsl b/res/cs_p1_partial.glsl deleted file mode 100644 index b7f6ca95e0..0000000000 --- a/res/cs_p1_partial.glsl +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; - -flat varying vec4 vLayerValues0; - -flat varying uvec4 vPartialRects0; diff --git a/res/cs_p1_partial.vs.glsl b/res/cs_p1_partial.vs.glsl deleted file mode 100644 index 14476ae1df..0000000000 --- a/res/cs_p1_partial.vs.glsl +++ /dev/null @@ -1,12 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - vec2 pos = write_vertex(tile); - - write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); -} diff --git a/res/cs_p2.fs.glsl b/res/cs_p2.fs.glsl deleted file mode 100644 index 9deeffc270..0000000000 --- a/res/cs_p2.fs.glsl +++ /dev/null @@ -1,17 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 prim_colors[2]; - prim_colors[0] = texture(sLayer0, vUv0); - prim_colors[1] = texture(sLayer1, vUv1); - - vec4 result = fetch_initial_color(); - result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues.x); - result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues.y); - - oFragColor = result; -} diff --git a/res/cs_p2.vs.glsl b/res/cs_p2.vs.glsl deleted file mode 100644 index c0ecd579a6..0000000000 --- a/res/cs_p2.vs.glsl +++ /dev/null @@ -1,13 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - write_vertex(tile); - - write_prim(tile, 0, vUv0, vLayerValues.x); - write_prim(tile, 1, vUv1, vLayerValues.y); -} diff --git a/res/cs_p2_partial.fs.glsl b/res/cs_p2_partial.fs.glsl deleted file mode 100644 index abc754be25..0000000000 --- a/res/cs_p2_partial.fs.glsl +++ /dev/null @@ -1,32 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 p0 = texture(sLayer0, vUv0); - vec4 p1 = texture(sLayer1, vUv1); - - vec4 result = fetch_initial_color(); - - result = mix(result, p0, p0.a * vLayerValues0.x); - result = mix(result, p1, p1.a * vLayerValues0.y); - - oFragColor = result; - - //oFragColor = vec4(1, 0, 0, 1); - /* - vec4 result = fetch_initial_color(); - - if (is_prim_valid(vPartialRects0.x)) { - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues0.x); - } - if (is_prim_valid(vPartialRects0.y)) { - vec4 prim_color = texture(sLayer1, vUv1); - result = mix(result, prim_color, prim_color.a * vLayerValues0.y); - } - - oFragColor = result;*/ -} diff --git a/res/cs_p2_partial.glsl b/res/cs_p2_partial.glsl deleted file mode 100644 index f505aa9b46..0000000000 --- a/res/cs_p2_partial.glsl +++ /dev/null @@ -1,10 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; - -flat varying vec4 vLayerValues0; - -flat varying uvec4 vPartialRects0; diff --git a/res/cs_p2_partial.vs.glsl b/res/cs_p2_partial.vs.glsl deleted file mode 100644 index 535e48f22e..0000000000 --- a/res/cs_p2_partial.vs.glsl +++ /dev/null @@ -1,27 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - - vUv0 = mix(tile.src_rects[0].xy / 4096.0, - (tile.src_rects[0].xy + tile.src_rects[0].zw) / 4096.0, - aPosition.xy); - - vUv1 = mix(tile.src_rects[1].xy / 4096.0, - (tile.src_rects[1].xy + tile.src_rects[1].zw) / 4096.0, - aPosition.xy); - - vLayerValues0 = vec4(1, 1, 1, 1); - - write_vertex(tile); - - /* - - write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); - write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); - */ -} diff --git a/res/cs_p3.fs.glsl b/res/cs_p3.fs.glsl deleted file mode 100644 index 4829e5b212..0000000000 --- a/res/cs_p3.fs.glsl +++ /dev/null @@ -1,19 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 prim_colors[3]; - prim_colors[0] = texture(sLayer0, vUv0); - prim_colors[1] = texture(sLayer1, vUv1); - prim_colors[2] = texture(sLayer2, vUv2); - - vec4 result = fetch_initial_color(); - result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues.x); - result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues.y); - result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues.z); - - oFragColor = result; -} diff --git a/res/cs_p3.glsl b/res/cs_p3.glsl deleted file mode 100644 index 410ab7d121..0000000000 --- a/res/cs_p3.glsl +++ /dev/null @@ -1,9 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; - -flat varying vec4 vLayerValues; diff --git a/res/cs_p3.vs.glsl b/res/cs_p3.vs.glsl deleted file mode 100644 index a15a6d4f51..0000000000 --- a/res/cs_p3.vs.glsl +++ /dev/null @@ -1,14 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - write_vertex(tile); - - write_prim(tile, 0, vUv0, vLayerValues.x); - write_prim(tile, 1, vUv1, vLayerValues.y); - write_prim(tile, 2, vUv2, vLayerValues.z); -} diff --git a/res/cs_p3_partial.fs.glsl b/res/cs_p3_partial.fs.glsl deleted file mode 100644 index 0151c60b4b..0000000000 --- a/res/cs_p3_partial.fs.glsl +++ /dev/null @@ -1,24 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 result = fetch_initial_color(); - - if (is_prim_valid(vPartialRects0.x)) { - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues0.x); - } - if (is_prim_valid(vPartialRects0.y)) { - vec4 prim_color = texture(sLayer1, vUv1); - result = mix(result, prim_color, prim_color.a * vLayerValues0.y); - } - if (is_prim_valid(vPartialRects0.z)) { - vec4 prim_color = texture(sLayer2, vUv2); - result = mix(result, prim_color, prim_color.a * vLayerValues0.z); - } - - oFragColor = result; -} diff --git a/res/cs_p3_partial.glsl b/res/cs_p3_partial.glsl deleted file mode 100644 index eb9416824a..0000000000 --- a/res/cs_p3_partial.glsl +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; - -flat varying vec4 vLayerValues0; - -flat varying uvec4 vPartialRects0; diff --git a/res/cs_p3_partial.vs.glsl b/res/cs_p3_partial.vs.glsl deleted file mode 100644 index 271aa0668c..0000000000 --- a/res/cs_p3_partial.vs.glsl +++ /dev/null @@ -1,14 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - vec2 pos = write_vertex(tile); - - write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); - write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); - write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); -} diff --git a/res/cs_p4.fs.glsl b/res/cs_p4.fs.glsl deleted file mode 100644 index 4cc3e8d002..0000000000 --- a/res/cs_p4.fs.glsl +++ /dev/null @@ -1,21 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 prim_colors[4]; - prim_colors[0] = texture(sLayer0, vUv0); - prim_colors[1] = texture(sLayer1, vUv1); - prim_colors[2] = texture(sLayer2, vUv2); - prim_colors[3] = texture(sLayer3, vUv3); - - vec4 result = fetch_initial_color(); - result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues.x); - result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues.y); - result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues.z); - result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues.w); - - oFragColor = result; -} diff --git a/res/cs_p4.glsl b/res/cs_p4.glsl deleted file mode 100644 index a2139f44b5..0000000000 --- a/res/cs_p4.glsl +++ /dev/null @@ -1,10 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; - -flat varying vec4 vLayerValues; diff --git a/res/cs_p4.vs.glsl b/res/cs_p4.vs.glsl deleted file mode 100644 index 91acbe66d3..0000000000 --- a/res/cs_p4.vs.glsl +++ /dev/null @@ -1,15 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - write_vertex(tile); - - write_prim(tile, 0, vUv0, vLayerValues.x); - write_prim(tile, 1, vUv1, vLayerValues.y); - write_prim(tile, 2, vUv2, vLayerValues.z); - write_prim(tile, 3, vUv3, vLayerValues.w); -} diff --git a/res/cs_p4_partial.fs.glsl b/res/cs_p4_partial.fs.glsl deleted file mode 100644 index 962bfe4331..0000000000 --- a/res/cs_p4_partial.fs.glsl +++ /dev/null @@ -1,28 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 result = fetch_initial_color(); - - if (is_prim_valid(vPartialRects0.x)) { - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues0.x); - } - if (is_prim_valid(vPartialRects0.y)) { - vec4 prim_color = texture(sLayer1, vUv1); - result = mix(result, prim_color, prim_color.a * vLayerValues0.y); - } - if (is_prim_valid(vPartialRects0.z)) { - vec4 prim_color = texture(sLayer2, vUv2); - result = mix(result, prim_color, prim_color.a * vLayerValues0.z); - } - if (is_prim_valid(vPartialRects0.w)) { - vec4 prim_color = texture(sLayer3, vUv3); - result = mix(result, prim_color, prim_color.a * vLayerValues0.w); - } - - oFragColor = result; -} diff --git a/res/cs_p4_partial.glsl b/res/cs_p4_partial.glsl deleted file mode 100644 index ee195ed9dc..0000000000 --- a/res/cs_p4_partial.glsl +++ /dev/null @@ -1,12 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; - -flat varying vec4 vLayerValues0; - -flat varying uvec4 vPartialRects0; diff --git a/res/cs_p4_partial.vs.glsl b/res/cs_p4_partial.vs.glsl deleted file mode 100644 index ffab0d5cad..0000000000 --- a/res/cs_p4_partial.vs.glsl +++ /dev/null @@ -1,15 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - vec2 pos = write_vertex(tile); - - write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); - write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); - write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); - write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); -} diff --git a/res/cs_p5.fs.glsl b/res/cs_p5.fs.glsl deleted file mode 100644 index 02a1294000..0000000000 --- a/res/cs_p5.fs.glsl +++ /dev/null @@ -1,23 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 prim_colors[5]; - prim_colors[0] = texture(sLayer0, vUv0); - prim_colors[1] = texture(sLayer1, vUv1); - prim_colors[2] = texture(sLayer2, vUv2); - prim_colors[3] = texture(sLayer3, vUv3); - prim_colors[4] = texture(sLayer4, vUv4); - - vec4 result = fetch_initial_color(); - result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues0.x); - result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues0.y); - result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues0.z); - result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues0.w); - result = mix(result, prim_colors[4], prim_colors[4].a * vLayerValues1.x); - - oFragColor = result; -} diff --git a/res/cs_p5.glsl b/res/cs_p5.glsl deleted file mode 100644 index b4eed170cf..0000000000 --- a/res/cs_p5.glsl +++ /dev/null @@ -1,12 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; -varying vec2 vUv4; - -flat varying vec4 vLayerValues0; -flat varying vec4 vLayerValues1; diff --git a/res/cs_p5.vs.glsl b/res/cs_p5.vs.glsl deleted file mode 100644 index af6bc801e6..0000000000 --- a/res/cs_p5.vs.glsl +++ /dev/null @@ -1,16 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - write_vertex(tile); - - write_prim(tile, 0, vUv0, vLayerValues0.x); - write_prim(tile, 1, vUv1, vLayerValues0.y); - write_prim(tile, 2, vUv2, vLayerValues0.z); - write_prim(tile, 3, vUv3, vLayerValues0.w); - write_prim(tile, 4, vUv4, vLayerValues1.x); -} diff --git a/res/cs_p5_partial.fs.glsl b/res/cs_p5_partial.fs.glsl deleted file mode 100644 index c8b0c429e3..0000000000 --- a/res/cs_p5_partial.fs.glsl +++ /dev/null @@ -1,32 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 result = fetch_initial_color(); - - if (is_prim_valid(vPartialRects0.x)) { - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues0.x); - } - if (is_prim_valid(vPartialRects0.y)) { - vec4 prim_color = texture(sLayer1, vUv1); - result = mix(result, prim_color, prim_color.a * vLayerValues0.y); - } - if (is_prim_valid(vPartialRects0.z)) { - vec4 prim_color = texture(sLayer2, vUv2); - result = mix(result, prim_color, prim_color.a * vLayerValues0.z); - } - if (is_prim_valid(vPartialRects0.w)) { - vec4 prim_color = texture(sLayer3, vUv3); - result = mix(result, prim_color, prim_color.a * vLayerValues0.w); - } - if (is_prim_valid(vPartialRects1.x)) { - vec4 prim_color = texture(sLayer4, vUv4); - result = mix(result, prim_color, prim_color.a * vLayerValues1.x); - } - - oFragColor = result; -} diff --git a/res/cs_p5_partial.glsl b/res/cs_p5_partial.glsl deleted file mode 100644 index 7c67457a48..0000000000 --- a/res/cs_p5_partial.glsl +++ /dev/null @@ -1,15 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; -varying vec2 vUv4; - -flat varying vec4 vLayerValues0; -flat varying vec4 vLayerValues1; - -flat varying uvec4 vPartialRects0; -flat varying uvec4 vPartialRects1; diff --git a/res/cs_p5_partial.vs.glsl b/res/cs_p5_partial.vs.glsl deleted file mode 100644 index a61c6fe20c..0000000000 --- a/res/cs_p5_partial.vs.glsl +++ /dev/null @@ -1,16 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - vec2 pos = write_vertex(tile); - - write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); - write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); - write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); - write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); - write_partial_prim(pos, tile.prim_indices[1].x, tile, vUv4, vPartialRects1.x, vLayerValues1.x); -} diff --git a/res/cs_p6.fs.glsl b/res/cs_p6.fs.glsl deleted file mode 100644 index 977db8329d..0000000000 --- a/res/cs_p6.fs.glsl +++ /dev/null @@ -1,25 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 prim_colors[6]; - prim_colors[0] = texture(sLayer0, vUv0); - prim_colors[1] = texture(sLayer1, vUv1); - prim_colors[2] = texture(sLayer2, vUv2); - prim_colors[3] = texture(sLayer3, vUv3); - prim_colors[4] = texture(sLayer4, vUv4); - prim_colors[5] = texture(sLayer5, vUv5); - - vec4 result = fetch_initial_color(); - result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues0.x); - result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues0.y); - result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues0.z); - result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues0.w); - result = mix(result, prim_colors[4], prim_colors[4].a * vLayerValues1.x); - result = mix(result, prim_colors[5], prim_colors[5].a * vLayerValues1.y); - - oFragColor = result; -} diff --git a/res/cs_p6.glsl b/res/cs_p6.glsl deleted file mode 100644 index c143622eab..0000000000 --- a/res/cs_p6.glsl +++ /dev/null @@ -1,13 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; -varying vec2 vUv4; -varying vec2 vUv5; - -flat varying vec4 vLayerValues0; -flat varying vec4 vLayerValues1; diff --git a/res/cs_p6.vs.glsl b/res/cs_p6.vs.glsl deleted file mode 100644 index 0270adfd2f..0000000000 --- a/res/cs_p6.vs.glsl +++ /dev/null @@ -1,17 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - write_vertex(tile); - - write_prim(tile, 0, vUv0, vLayerValues0.x); - write_prim(tile, 1, vUv1, vLayerValues0.y); - write_prim(tile, 2, vUv2, vLayerValues0.z); - write_prim(tile, 3, vUv3, vLayerValues0.w); - write_prim(tile, 4, vUv4, vLayerValues1.x); - write_prim(tile, 5, vUv5, vLayerValues1.y); -} diff --git a/res/cs_p6_partial.fs.glsl b/res/cs_p6_partial.fs.glsl deleted file mode 100644 index dd1bb4901e..0000000000 --- a/res/cs_p6_partial.fs.glsl +++ /dev/null @@ -1,35 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 result = fetch_initial_color(); - - if (is_prim_valid(vPartialRects0.x)) { - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues0.x); - } - if (is_prim_valid(vPartialRects0.y)) { - vec4 prim_color = texture(sLayer1, vUv1); - result = mix(result, prim_color, prim_color.a * vLayerValues0.y); - } - if (is_prim_valid(vPartialRects0.z)) { - vec4 prim_color = texture(sLayer2, vUv2); - result = mix(result, prim_color, prim_color.a * vLayerValues0.z); - } - if (is_prim_valid(vPartialRects0.w)) { - vec4 prim_color = texture(sLayer3, vUv3); - result = mix(result, prim_color, prim_color.a * vLayerValues0.w); - } - if (is_prim_valid(vPartialRects1.x)) { - vec4 prim_color = texture(sLayer4, vUv4); - result = mix(result, prim_color, prim_color.a * vLayerValues1.x); - } - if (is_prim_valid(vPartialRects1.y)) { - vec4 prim_color = texture(sLayer5, vUv5); - result = mix(result, prim_color, prim_color.a * vLayerValues1.y); - } - oFragColor = result; -} diff --git a/res/cs_p6_partial.glsl b/res/cs_p6_partial.glsl deleted file mode 100644 index ef2b5d4869..0000000000 --- a/res/cs_p6_partial.glsl +++ /dev/null @@ -1,16 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; -varying vec2 vUv4; -varying vec2 vUv5; - -flat varying vec4 vLayerValues0; -flat varying vec4 vLayerValues1; - -flat varying uvec4 vPartialRects0; -flat varying uvec4 vPartialRects1; diff --git a/res/cs_p6_partial.vs.glsl b/res/cs_p6_partial.vs.glsl deleted file mode 100644 index 989828f9ab..0000000000 --- a/res/cs_p6_partial.vs.glsl +++ /dev/null @@ -1,17 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - vec2 pos = write_vertex(tile); - - write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); - write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); - write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); - write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); - write_partial_prim(pos, tile.prim_indices[1].x, tile, vUv4, vPartialRects1.x, vLayerValues1.x); - write_partial_prim(pos, tile.prim_indices[1].y, tile, vUv5, vPartialRects1.y, vLayerValues1.y); -} diff --git a/res/cs_p7.fs.glsl b/res/cs_p7.fs.glsl deleted file mode 100644 index 214f514358..0000000000 --- a/res/cs_p7.fs.glsl +++ /dev/null @@ -1,27 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 prim_colors[7]; - prim_colors[0] = texture(sLayer0, vUv0); - prim_colors[1] = texture(sLayer1, vUv1); - prim_colors[2] = texture(sLayer2, vUv2); - prim_colors[3] = texture(sLayer3, vUv3); - prim_colors[4] = texture(sLayer4, vUv4); - prim_colors[5] = texture(sLayer5, vUv5); - prim_colors[6] = texture(sLayer6, vUv6); - - vec4 result = fetch_initial_color(); - result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues0.x); - result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues0.y); - result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues0.z); - result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues0.w); - result = mix(result, prim_colors[4], prim_colors[4].a * vLayerValues1.x); - result = mix(result, prim_colors[5], prim_colors[5].a * vLayerValues1.y); - result = mix(result, prim_colors[6], prim_colors[6].a * vLayerValues1.z); - - oFragColor = result; -} diff --git a/res/cs_p7.glsl b/res/cs_p7.glsl deleted file mode 100644 index 50764754ff..0000000000 --- a/res/cs_p7.glsl +++ /dev/null @@ -1,14 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; -varying vec2 vUv4; -varying vec2 vUv5; -varying vec2 vUv6; - -flat varying vec4 vLayerValues0; -flat varying vec4 vLayerValues1; diff --git a/res/cs_p7.vs.glsl b/res/cs_p7.vs.glsl deleted file mode 100644 index b5ccfe2b1d..0000000000 --- a/res/cs_p7.vs.glsl +++ /dev/null @@ -1,18 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - write_vertex(tile); - - write_prim(tile, 0, vUv0, vLayerValues0.x); - write_prim(tile, 1, vUv1, vLayerValues0.y); - write_prim(tile, 2, vUv2, vLayerValues0.z); - write_prim(tile, 3, vUv3, vLayerValues0.w); - write_prim(tile, 4, vUv4, vLayerValues1.x); - write_prim(tile, 5, vUv5, vLayerValues1.y); - write_prim(tile, 6, vUv6, vLayerValues1.z); -} diff --git a/res/cs_p7_partial.fs.glsl b/res/cs_p7_partial.fs.glsl deleted file mode 100644 index 23e4da8838..0000000000 --- a/res/cs_p7_partial.fs.glsl +++ /dev/null @@ -1,40 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 result = fetch_initial_color(); - - if (is_prim_valid(vPartialRects0.x)) { - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues0.x); - } - if (is_prim_valid(vPartialRects0.y)) { - vec4 prim_color = texture(sLayer1, vUv1); - result = mix(result, prim_color, prim_color.a * vLayerValues0.y); - } - if (is_prim_valid(vPartialRects0.z)) { - vec4 prim_color = texture(sLayer2, vUv2); - result = mix(result, prim_color, prim_color.a * vLayerValues0.z); - } - if (is_prim_valid(vPartialRects0.w)) { - vec4 prim_color = texture(sLayer3, vUv3); - result = mix(result, prim_color, prim_color.a * vLayerValues0.w); - } - if (is_prim_valid(vPartialRects1.x)) { - vec4 prim_color = texture(sLayer4, vUv4); - result = mix(result, prim_color, prim_color.a * vLayerValues1.x); - } - if (is_prim_valid(vPartialRects1.y)) { - vec4 prim_color = texture(sLayer5, vUv5); - result = mix(result, prim_color, prim_color.a * vLayerValues1.y); - } - if (is_prim_valid(vPartialRects1.z)) { - vec4 prim_color = texture(sLayer6, vUv6); - result = mix(result, prim_color, prim_color.a * vLayerValues1.z); - } - - oFragColor = result; -} diff --git a/res/cs_p7_partial.glsl b/res/cs_p7_partial.glsl deleted file mode 100644 index 4e017baca5..0000000000 --- a/res/cs_p7_partial.glsl +++ /dev/null @@ -1,17 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; -varying vec2 vUv4; -varying vec2 vUv5; -varying vec2 vUv6; - -flat varying vec4 vLayerValues0; -flat varying vec4 vLayerValues1; - -flat varying uvec4 vPartialRects0; -flat varying uvec4 vPartialRects1; diff --git a/res/cs_p7_partial.vs.glsl b/res/cs_p7_partial.vs.glsl deleted file mode 100644 index cf7cee86fb..0000000000 --- a/res/cs_p7_partial.vs.glsl +++ /dev/null @@ -1,18 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - vec2 pos = write_vertex(tile); - - write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); - write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); - write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); - write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); - write_partial_prim(pos, tile.prim_indices[1].x, tile, vUv4, vPartialRects1.x, vLayerValues1.x); - write_partial_prim(pos, tile.prim_indices[1].y, tile, vUv5, vPartialRects1.y, vLayerValues1.y); - write_partial_prim(pos, tile.prim_indices[1].z, tile, vUv6, vPartialRects1.z, vLayerValues1.z); -} diff --git a/res/cs_p8.fs.glsl b/res/cs_p8.fs.glsl deleted file mode 100644 index 4d13190f7b..0000000000 --- a/res/cs_p8.fs.glsl +++ /dev/null @@ -1,29 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 prim_colors[8]; - prim_colors[0] = texture(sLayer0, vUv0); - prim_colors[1] = texture(sLayer1, vUv1); - prim_colors[2] = texture(sLayer2, vUv2); - prim_colors[3] = texture(sLayer3, vUv3); - prim_colors[4] = texture(sLayer4, vUv4); - prim_colors[5] = texture(sLayer5, vUv5); - prim_colors[6] = texture(sLayer6, vUv6); - prim_colors[7] = texture(sLayer7, vUv7); - - vec4 result = fetch_initial_color(); - result = mix(result, prim_colors[0], prim_colors[0].a * vLayerValues0.x); - result = mix(result, prim_colors[1], prim_colors[1].a * vLayerValues0.y); - result = mix(result, prim_colors[2], prim_colors[2].a * vLayerValues0.z); - result = mix(result, prim_colors[3], prim_colors[3].a * vLayerValues0.w); - result = mix(result, prim_colors[4], prim_colors[4].a * vLayerValues1.x); - result = mix(result, prim_colors[5], prim_colors[5].a * vLayerValues1.y); - result = mix(result, prim_colors[6], prim_colors[6].a * vLayerValues1.z); - result = mix(result, prim_colors[7], prim_colors[7].a * vLayerValues1.w); - - oFragColor = result; -} diff --git a/res/cs_p8.glsl b/res/cs_p8.glsl deleted file mode 100644 index d23aad5dd0..0000000000 --- a/res/cs_p8.glsl +++ /dev/null @@ -1,15 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; -varying vec2 vUv4; -varying vec2 vUv5; -varying vec2 vUv6; -varying vec2 vUv7; - -flat varying vec4 vLayerValues0; -flat varying vec4 vLayerValues1; diff --git a/res/cs_p8.vs.glsl b/res/cs_p8.vs.glsl deleted file mode 100644 index 6c79ad26b1..0000000000 --- a/res/cs_p8.vs.glsl +++ /dev/null @@ -1,19 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - write_vertex(tile); - - write_prim(tile, 0, vUv0, vLayerValues0.x); - write_prim(tile, 1, vUv1, vLayerValues0.y); - write_prim(tile, 2, vUv2, vLayerValues0.z); - write_prim(tile, 3, vUv3, vLayerValues0.w); - write_prim(tile, 4, vUv4, vLayerValues1.x); - write_prim(tile, 5, vUv5, vLayerValues1.y); - write_prim(tile, 6, vUv6, vLayerValues1.z); - write_prim(tile, 7, vUv7, vLayerValues1.w); -} diff --git a/res/cs_p8_partial.fs.glsl b/res/cs_p8_partial.fs.glsl deleted file mode 100644 index 21685d14aa..0000000000 --- a/res/cs_p8_partial.fs.glsl +++ /dev/null @@ -1,44 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main(void) { - vec4 result = fetch_initial_color(); - - if (is_prim_valid(vPartialRects0.x)) { - vec4 prim_color = texture(sLayer0, vUv0); - result = mix(result, prim_color, prim_color.a * vLayerValues0.x); - } - if (is_prim_valid(vPartialRects0.y)) { - vec4 prim_color = texture(sLayer1, vUv1); - result = mix(result, prim_color, prim_color.a * vLayerValues0.y); - } - if (is_prim_valid(vPartialRects0.z)) { - vec4 prim_color = texture(sLayer2, vUv2); - result = mix(result, prim_color, prim_color.a * vLayerValues0.z); - } - if (is_prim_valid(vPartialRects0.w)) { - vec4 prim_color = texture(sLayer3, vUv3); - result = mix(result, prim_color, prim_color.a * vLayerValues0.w); - } - if (is_prim_valid(vPartialRects1.x)) { - vec4 prim_color = texture(sLayer4, vUv4); - result = mix(result, prim_color, prim_color.a * vLayerValues1.x); - } - if (is_prim_valid(vPartialRects1.y)) { - vec4 prim_color = texture(sLayer5, vUv5); - result = mix(result, prim_color, prim_color.a * vLayerValues1.y); - } - if (is_prim_valid(vPartialRects1.z)) { - vec4 prim_color = texture(sLayer6, vUv6); - result = mix(result, prim_color, prim_color.a * vLayerValues1.z); - } - if (is_prim_valid(vPartialRects1.w)) { - vec4 prim_color = texture(sLayer7, vUv7); - result = mix(result, prim_color, prim_color.a * vLayerValues1.w); - } - - oFragColor = result; -} diff --git a/res/cs_p8_partial.glsl b/res/cs_p8_partial.glsl deleted file mode 100644 index ddbdd9270b..0000000000 --- a/res/cs_p8_partial.glsl +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; -varying vec2 vUv4; -varying vec2 vUv5; -varying vec2 vUv6; -varying vec2 vUv7; - -flat varying vec4 vLayerValues0; -flat varying vec4 vLayerValues1; - -flat varying uvec4 vPartialRects0; -flat varying uvec4 vPartialRects1; diff --git a/res/cs_p8_partial.vs.glsl b/res/cs_p8_partial.vs.glsl deleted file mode 100644 index 76fe311e32..0000000000 --- a/res/cs_p8_partial.vs.glsl +++ /dev/null @@ -1,19 +0,0 @@ -#line 1 - -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - vec2 pos = write_vertex(tile); - - write_partial_prim(pos, tile.prim_indices[0].x, tile, vUv0, vPartialRects0.x, vLayerValues0.x); - write_partial_prim(pos, tile.prim_indices[0].y, tile, vUv1, vPartialRects0.y, vLayerValues0.y); - write_partial_prim(pos, tile.prim_indices[0].z, tile, vUv2, vPartialRects0.z, vLayerValues0.z); - write_partial_prim(pos, tile.prim_indices[0].w, tile, vUv3, vPartialRects0.w, vLayerValues0.w); - write_partial_prim(pos, tile.prim_indices[1].x, tile, vUv4, vPartialRects1.x, vLayerValues1.x); - write_partial_prim(pos, tile.prim_indices[1].y, tile, vUv5, vPartialRects1.y, vLayerValues1.y); - write_partial_prim(pos, tile.prim_indices[1].z, tile, vUv6, vPartialRects1.z, vLayerValues1.z); - write_partial_prim(pos, tile.prim_indices[1].w, tile, vUv7, vPartialRects1.w, vLayerValues1.w); -} diff --git a/res/prim_shared.glsl b/res/prim_shared.glsl index 26fb41935f..55a1205d38 100644 --- a/res/prim_shared.glsl +++ b/res/prim_shared.glsl @@ -28,8 +28,8 @@ struct Layer { mat4 transform; mat4 inv_transform; + ivec4 world_clip_rect; vec4 screen_vertices[4]; - vec4 blend_info; }; layout(std140) uniform Layers { diff --git a/res/cs_p1_ic.glsl b/res/ps_blend.fs.glsl similarity index 59% rename from res/cs_p1_ic.glsl rename to res/ps_blend.fs.glsl index a2139f44b5..12ccbf0b6c 100644 --- a/res/cs_p1_ic.glsl +++ b/res/ps_blend.fs.glsl @@ -2,9 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -varying vec2 vUv0; -varying vec2 vUv1; -varying vec2 vUv2; -varying vec2 vUv3; +uniform sampler2D sCache; -flat varying vec4 vLayerValues; +void main(void) { + vec4 color = texture(sCache, vUv); + oFragColor = vec4(color.rgb, color.a * vOpacity); +} diff --git a/res/cs_p1.glsl b/res/ps_blend.glsl similarity index 79% rename from res/cs_p1.glsl rename to res/ps_blend.glsl index f788c978cc..773cf91e27 100644 --- a/res/cs_p1.glsl +++ b/res/ps_blend.glsl @@ -2,6 +2,5 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -varying vec2 vUv0; - -flat varying vec4 vLayerValues; +varying vec2 vUv; +varying float vOpacity; diff --git a/res/ps_blend.vs.glsl b/res/ps_blend.vs.glsl new file mode 100644 index 0000000000..c01430d4ce --- /dev/null +++ b/res/ps_blend.vs.glsl @@ -0,0 +1,29 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Blend { + uvec4 target_rect; + uvec4 src_rect; + vec4 opacity; +}; + +layout(std140) uniform Items { + Blend blends[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Blend blend = blends[gl_InstanceID]; + + vec2 local_pos = mix(blend.target_rect.xy, + blend.target_rect.xy + blend.target_rect.zw, + aPosition.xy); + + vec2 st0 = blend.src_rect.xy / 2048.0; + vec2 st1 = (blend.src_rect.xy + blend.src_rect.zw) / 2048.0; + vUv = mix(st0, st1, aPosition.xy); + vOpacity = blend.opacity.x; + + gl_Position = uTransform * vec4(local_pos, 0, 1); +} diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index 0f01ec5aa9..bb6dcbc992 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -38,9 +38,15 @@ void main(void) { Layer layer = layers[border.info.layer_tile_part.x]; Tile tile = tiles[border.info.layer_tile_part.y]; - vec2 local_pos = mix(border.local_rect.xy, - border.local_rect.xy + border.local_rect.zw, - aPosition.xy); + vec2 p0 = floor(0.5 + border.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = p0 + border.local_rect.zw; + + vec2 local_pos = mix(p0, p1, aPosition.xy); + + vec2 cp0 = floor(0.5 + border.info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 cp1 = cp0 + border.info.local_clip_rect.zw; + + local_pos = clamp(local_pos, cp0, cp1); vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); @@ -120,8 +126,10 @@ void main(void) { vColor0 = border.color0; vColor1 = border.color1; + // Local space + vPos = local_clamped_pos.xy; + // These are in device space - vPos = clamped_pos; vBorders = vec4(border.local_rect.x, border.local_rect.y, border.local_rect.z, border.local_rect.w) * uDevicePixelRatio; diff --git a/res/ps_composite.fs.glsl b/res/ps_composite.fs.glsl new file mode 100644 index 0000000000..c4e4099655 --- /dev/null +++ b/res/ps_composite.fs.glsl @@ -0,0 +1,320 @@ +#line 1 + +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#define COMPOSITE_KIND_MIX_BLEND_MODE 0 +#define COMPOSITE_KIND_FILTER 1 + +uniform sampler2D sCache; + +vec3 rgbToHsv(vec3 c) { + float value = max(max(c.r, c.g), c.b); + + float chroma = value - min(min(c.r, c.g), c.b); + if (chroma == 0.0) { + return vec3(0.0); + } + float saturation = chroma / value; + + float hue; + if (c.r == value) + hue = (c.g - c.b) / chroma; + else if (c.g == value) + hue = 2.0 + (c.b - c.r) / chroma; + else // if (c.b == value) + hue = 4.0 + (c.r - c.g) / chroma; + + hue *= 1.0/6.0; + if (hue < 0.0) + hue += 1.0; + return vec3(hue, saturation, value); +} + +vec3 hsvToRgb(vec3 c) { + if (c.s == 0.0) { + return vec3(c.z); + } + + float hue = c.x * 6.0; + int sector = int(hue); + float residualHue = hue - float(sector); + + vec3 pqt = c.z * vec3(1.0 - c.y, 1.0 - c.y * residualHue, 1.0 - c.y * (1.0 - residualHue)); + if (sector == 0) + return vec3(c.z, pqt.z, pqt.x); + if (sector == 1) + return vec3(pqt.y, c.z, pqt.x); + if (sector == 2) + return vec3(pqt.x, c.z, pqt.z); + if (sector == 3) + return vec3(pqt.x, pqt.y, c.z); + if (sector == 4) + return vec3(pqt.z, pqt.x, c.z); + return vec3(c.z, pqt.x, pqt.y); +} + +float gauss(float x, float sigma) { + if (sigma == 0.0) + return 1.0; + return (1.0 / sqrt(6.283185307179586 * sigma * sigma)) * exp(-(x * x) / (2.0 * sigma * sigma)); +} + +vec4 Blur(float radius, vec2 direction) { + // TODO(gw): Support blur in WR2! + return vec4(1, 1, 1, 1); +} + +vec4 Contrast(vec4 Cs, float amount) { + return vec4(Cs.rgb * amount - 0.5 * amount + 0.5, 1.0); +} + +vec4 Grayscale(vec4 Cs, float amount) { + float ia = 1.0 - amount; + return mat4(vec4(0.2126 + 0.7874 * ia, 0.2126 - 0.2126 * ia, 0.2126 - 0.2126 * ia, 0.0), + vec4(0.7152 - 0.7152 * ia, 0.7152 + 0.2848 * ia, 0.7152 - 0.7152 * ia, 0.0), + vec4(0.0722 - 0.0722 * ia, 0.0722 - 0.0722 * ia, 0.0722 + 0.9278 * ia, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)) * Cs; +} + +vec4 HueRotate(vec4 Cs, float amount) { + vec3 CsHsv = rgbToHsv(Cs.rgb); + CsHsv.x = mod(CsHsv.x + amount / 6.283185307179586, 1.0); + return vec4(hsvToRgb(CsHsv), Cs.a); +} + +vec4 Invert(vec4 Cs, float amount) { + return mix(Cs, vec4(1.0, 1.0, 1.0, Cs.a) - vec4(Cs.rgb, 0.0), amount); +} + +vec4 Saturate(vec4 Cs, float amount) { + return vec4(hsvToRgb(min(vec3(1.0, amount, 1.0) * rgbToHsv(Cs.rgb), vec3(1.0))), Cs.a); +} + +vec4 Sepia(vec4 Cs, float amount) { + float ia = 1.0 - amount; + return mat4(vec4(0.393 + 0.607 * ia, 0.349 - 0.349 * ia, 0.272 - 0.272 * ia, 0.0), + vec4(0.769 - 0.769 * ia, 0.686 + 0.314 * ia, 0.534 - 0.534 * ia, 0.0), + vec4(0.189 - 0.189 * ia, 0.168 - 0.168 * ia, 0.131 + 0.869 * ia, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)) * Cs; +} + +vec3 Multiply(vec3 Cb, vec3 Cs) { + return Cb * Cs; +} + +vec3 Screen(vec3 Cb, vec3 Cs) { + return Cb + Cs - (Cb * Cs); +} + +vec3 HardLight(vec3 Cb, vec3 Cs) { + vec3 m = Multiply(Cb, 2.0 * Cs); + vec3 s = Screen(Cb, 2.0 * Cs - 1.0); + vec3 edge = vec3(0.5, 0.5, 0.5); + return mix(m, s, step(edge, Cs)); +} + +// TODO: Worth doing with mix/step? Check GLSL output. +float ColorDodge(float Cb, float Cs) { + if (Cb == 0.0) + return 0.0; + else if (Cs == 1.0) + return 1.0; + else + return min(1.0, Cb / (1.0 - Cs)); +} + +// TODO: Worth doing with mix/step? Check GLSL output. +float ColorBurn(float Cb, float Cs) { + if (Cb == 1.0) + return 1.0; + else if (Cs == 0.0) + return 0.0; + else + return 1.0 - min(1.0, (1.0 - Cb) / Cs); +} + +float SoftLight(float Cb, float Cs) { + if (Cs <= 0.5) { + return Cb - (1.0 - 2.0 * Cs) * Cb * (1.0 - Cb); + } else { + float D; + + if (Cb <= 0.25) + D = ((16.0 * Cb - 12.0) * Cb + 4.0) * Cb; + else + D = sqrt(Cb); + + return Cb + (2.0 * Cs - 1.0) * (D - Cb); + } +} + +vec3 Difference(vec3 Cb, vec3 Cs) { + return abs(Cb - Cs); +} + +vec3 Exclusion(vec3 Cb, vec3 Cs) { + return Cb + Cs - 2.0 * Cb * Cs; +} + +// These functions below are taken from the spec. +// There's probably a much quicker way to implement +// them in GLSL... +float Sat(vec3 c) { + return max(c.r, max(c.g, c.b)) - min(c.r, min(c.g, c.b)); +} + +float Lum(vec3 c) { + vec3 f = vec3(0.3, 0.59, 0.11); + return dot(c, f); +} + +vec3 ClipColor(vec3 C) { + float L = Lum(C); + float n = min(C.r, min(C.g, C.b)); + float x = max(C.r, max(C.g, C.b)); + + if (n < 0.0) + C = L + (((C - L) * L) / (L - n)); + + if (x > 1.0) + C = L + (((C - L) * (1.0 - L)) / (x - L)); + + return C; +} + +vec3 SetLum(vec3 C, float l) { + float d = l - Lum(C); + return ClipColor(C + d); +} + +void SetSatInner(inout float Cmin, inout float Cmid, inout float Cmax, float s) { + if (Cmax > Cmin) { + Cmid = (((Cmid - Cmin) * s) / (Cmax - Cmin)); + Cmax = s; + } else { + Cmid = 0.0; + Cmax = 0.0; + } + Cmin = 0.0; +} + +vec3 SetSat(vec3 C, float s) { + if (C.r <= C.g) { + if (C.g <= C.b) { + SetSatInner(C.r, C.g, C.b, s); + } else { + if (C.r <= C.b) { + SetSatInner(C.r, C.b, C.g, s); + } else { + SetSatInner(C.b, C.r, C.g, s); + } + } + } else { + if (C.r <= C.b) { + SetSatInner(C.g, C.r, C.b, s); + } else { + if (C.g <= C.b) { + SetSatInner(C.g, C.b, C.r, s); + } else { + SetSatInner(C.b, C.g, C.r, s); + } + } + } + return C; +} + +vec3 Hue(vec3 Cb, vec3 Cs) { + return SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb)); +} + +vec3 Saturation(vec3 Cb, vec3 Cs) { + return SetLum(SetSat(Cb, Sat(Cs)), Lum(Cb)); +} + +vec3 Color(vec3 Cb, vec3 Cs) { + return SetLum(Cs, Lum(Cb)); +} + +vec3 Luminosity(vec3 Cb, vec3 Cs) { + return SetLum(Cb, Lum(Cs)); +} + +void main(void) { + vec4 Cs = texture(sCache, vUv1); + vec4 Cb = texture(sCache, vUv0); + + // TODO(gw): This is a hack that's (probably) wrong. + // Instead of drawing the tile rect, draw the + // stacking context bounds instead? + if (Cs.a == 0.0) { + oFragColor = Cb; + return; + } + + int kind = vInfo.x; + int op = vInfo.y; + float amount = vAmount; + + // Return yellow if none of the branches match (shouldn't happen). + vec4 result = vec4(1.0, 1.0, 0.0, 1.0); + + switch (kind) { + case COMPOSITE_KIND_MIX_BLEND_MODE: + if (op == 2) { + result.rgb = Screen(Cb.rgb, Cs.rgb); + } else if (op == 3) { + result.rgb = HardLight(Cs.rgb, Cb.rgb); // Overlay is inverse of Hardlight + } else if (op == 6) { + result.r = ColorDodge(Cb.r, Cs.r); + result.g = ColorDodge(Cb.g, Cs.g); + result.b = ColorDodge(Cb.b, Cs.b); + } else if (op == 7) { + result.r = ColorBurn(Cb.r, Cs.r); + result.g = ColorBurn(Cb.g, Cs.g); + result.b = ColorBurn(Cb.b, Cs.b); + } else if (op == 8) { + result.rgb = HardLight(Cb.rgb, Cs.rgb); + } else if (op == 9) { + result.r = SoftLight(Cb.r, Cs.r); + result.g = SoftLight(Cb.g, Cs.g); + result.b = SoftLight(Cb.b, Cs.b); + } else if (op == 10) { + result.rgb = Difference(Cb.rgb, Cs.rgb); + } else if (op == 11) { + result.rgb = Exclusion(Cb.rgb, Cs.rgb); + } else if (op == 12) { + result.rgb = Hue(Cb.rgb, Cs.rgb); + } else if (op == 13) { + result.rgb = Saturation(Cb.rgb, Cs.rgb); + } else if (op == 14) { + result.rgb = Color(Cb.rgb, Cs.rgb); + } else if (op == 15) { + result.rgb = Luminosity(Cb.rgb, Cs.rgb); + } + break; + case COMPOSITE_KIND_FILTER: + if (op == 0) { + // Gaussian blur is specially handled: + result = Cs;// Blur(amount, vec2(0,0)); + } else { + if (op == 1) { + result = Contrast(Cs, amount); + } else if (op == 2) { + result = Grayscale(Cs, amount); + } else if (op == 3) { + result = HueRotate(Cs, amount); + } else if (op == 4) { + result = Invert(Cs, amount); + } else if (op == 5) { + result = Saturate(Cs, amount); + } else if (op == 6) { + result = Sepia(Cs, amount); + } + } + break; + } + + oFragColor = result; +} diff --git a/res/cs_p2.glsl b/res/ps_composite.glsl similarity index 81% rename from res/cs_p2.glsl rename to res/ps_composite.glsl index 51db06180f..68a8f97810 100644 --- a/res/cs_p2.glsl +++ b/res/ps_composite.glsl @@ -4,5 +4,5 @@ varying vec2 vUv0; varying vec2 vUv1; - -flat varying vec4 vLayerValues; +flat varying ivec2 vInfo; +flat varying float vAmount; diff --git a/res/ps_composite.vs.glsl b/res/ps_composite.vs.glsl new file mode 100644 index 0000000000..c1279f3cd4 --- /dev/null +++ b/res/ps_composite.vs.glsl @@ -0,0 +1,37 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Composite { + uvec4 src0; + uvec4 src1; + uvec4 target_rect; + ivec4 info; + vec4 amount; +}; + +layout(std140) uniform Items { + Composite composites[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Composite composite = composites[gl_InstanceID]; + + vec2 local_pos = mix(composite.target_rect.xy, + composite.target_rect.xy + composite.target_rect.zw, + aPosition.xy); + + vec2 st0 = composite.src0.xy / 2048.0; + vec2 st1 = (composite.src0.xy + composite.src0.zw) / 2048.0; + vUv0 = mix(st0, st1, aPosition.xy); + + st0 = composite.src1.xy / 2048.0; + st1 = (composite.src1.xy + composite.src1.zw) / 2048.0; + vUv1 = mix(st0, st1, aPosition.xy); + + vInfo = composite.info.xy; + vAmount = composite.amount.x; + + gl_Position = uTransform * vec4(local_pos, 0, 1); +} diff --git a/res/ps_image.vs.glsl b/res/ps_image.vs.glsl index 1393e6c8df..f43f20c93d 100644 --- a/res/ps_image.vs.glsl +++ b/res/ps_image.vs.glsl @@ -20,13 +20,14 @@ void main(void) { Tile tile = tiles[image.info.layer_tile_part.y]; // Our location within the image - vec2 local_pos = mix(image.local_rect.xy, - image.local_rect.xy + image.local_rect.zw, - aPosition.xy); + vec2 p0 = floor(0.5 + image.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = floor(0.5 + (image.local_rect.xy + image.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; - local_pos = clamp(local_pos, - image.info.local_clip_rect.xy, - image.info.local_clip_rect.xy + image.info.local_clip_rect.zw); + vec2 local_pos = mix(p0, p1, aPosition.xy); + + vec2 cp0 = floor(0.5 + image.info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 cp1 = floor(0.5 + (image.info.local_clip_rect.xy + image.info.local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + local_pos = clamp(local_pos, cp0, cp1); vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); @@ -39,7 +40,7 @@ void main(void) { vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); // vUv will contain how many times this image has wrapped around the image size. - vUv = (local_clamped_pos.xy - image.local_rect.xy) / image.stretch_size.xy; + vUv = (local_clamped_pos.xy - p0) / image.stretch_size.xy; vTextureSize = image.st_rect.zw - image.st_rect.xy; vTextureOffset = image.st_rect.xy; diff --git a/res/cs_p1.vs.glsl b/res/ps_image_clip.fs.glsl similarity index 56% rename from res/cs_p1.vs.glsl rename to res/ps_image_clip.fs.glsl index afac128130..2ec824e441 100644 --- a/res/cs_p1.vs.glsl +++ b/res/ps_image_clip.fs.glsl @@ -1,12 +1,9 @@ -#line 1 - /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -void main() { - CompositeTile tile = tiles[gl_InstanceID]; - write_vertex(tile); - - write_prim(tile, 0, vUv0, vLayerValues.x); +void main(void) { + do_clip(vPos, vClipRect, vClipRadius); + vec2 st = vTextureOffset + vTextureSize * fract(vUv); + oFragColor = texture(sDiffuse, st); } diff --git a/res/ps_image_clip.glsl b/res/ps_image_clip.glsl new file mode 100644 index 0000000000..25bb29ca2f --- /dev/null +++ b/res/ps_image_clip.glsl @@ -0,0 +1,10 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +varying vec2 vUv; // Location within the CSS box to draw. +varying vec2 vPos; +flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas. +flat varying vec2 vTextureSize; // Size of the image in the texture atlas. +flat varying vec4 vClipRect; +flat varying float vClipRadius; // TODO: Expand to handle irregular radii! diff --git a/res/ps_image_clip.vs.glsl b/res/ps_image_clip.vs.glsl new file mode 100644 index 0000000000..748254a59c --- /dev/null +++ b/res/ps_image_clip.vs.glsl @@ -0,0 +1,54 @@ +#line 1 +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +struct Image { + PrimitiveInfo info; + vec4 local_rect; // Size of the box we need to fill with this image. + vec4 st_rect; // Location of the image texture in the texture atlas. + vec2 stretch_size; // Size of the actual image. + Clip clip; +}; + +layout(std140) uniform Items { + Image images[WR_MAX_PRIM_ITEMS]; +}; + +void main(void) { + Image image = images[gl_InstanceID]; + Layer layer = layers[image.info.layer_tile_part.x]; + Tile tile = tiles[image.info.layer_tile_part.y]; + + // Our location within the image + vec2 local_pos = mix(image.local_rect.xy, + image.local_rect.xy + image.local_rect.zw, + aPosition.xy); + + local_pos = clamp(local_pos, + image.info.local_clip_rect.xy, + image.info.local_clip_rect.xy + image.info.local_clip_rect.zw); + + vClipRect = vec4(image.clip.rect.xy, image.clip.rect.xy + image.clip.rect.zw); + vClipRadius = image.clip.top_left.outer_inner_radius.x; + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + vPos = local_clamped_pos.xy; + + // vUv will contain how many times this image has wrapped around the image size. + vUv = (local_clamped_pos.xy - image.local_rect.xy) / image.stretch_size.xy; + vTextureSize = image.st_rect.zw - image.st_rect.xy; + vTextureOffset = image.st_rect.xy; + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); +} diff --git a/res/ps_rectangle.fs.glsl b/res/ps_rectangle.fs.glsl index e9aae64138..61837732d3 100644 --- a/res/ps_rectangle.fs.glsl +++ b/res/ps_rectangle.fs.glsl @@ -2,7 +2,6 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -void main(void) -{ +void main(void) { oFragColor = vColor; } diff --git a/res/ps_rectangle.vs.glsl b/res/ps_rectangle.vs.glsl index 5f04ddc8c8..3f638feb42 100644 --- a/res/ps_rectangle.vs.glsl +++ b/res/ps_rectangle.vs.glsl @@ -20,13 +20,14 @@ void main(void) { vColor = rect.color; - vec2 local_pos = mix(rect.local_rect.xy, - rect.local_rect.xy + rect.local_rect.zw, - aPosition.xy); + vec2 p0 = floor(0.5 + rect.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = floor(0.5 + (rect.local_rect.xy + rect.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; - local_pos = clamp(local_pos, - rect.info.local_clip_rect.xy, - rect.info.local_clip_rect.xy + rect.info.local_clip_rect.zw); + vec2 local_pos = mix(p0, p1, aPosition.xy); + + vec2 cp0 = floor(0.5 + rect.info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 cp1 = floor(0.5 + (rect.info.local_clip_rect.xy + rect.info.local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + local_pos = clamp(local_pos, cp0, cp1); vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); @@ -36,6 +37,10 @@ void main(void) { tile.actual_rect.xy, tile.actual_rect.xy + tile.actual_rect.zw); + clamped_pos = clamp(clamped_pos, + layer.world_clip_rect.xy, + layer.world_clip_rect.xy + layer.world_clip_rect.zw); + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; gl_Position = uTransform * vec4(final_pos, 0, 1); diff --git a/res/ps_rectangle_clip.vs.glsl b/res/ps_rectangle_clip.vs.glsl index c08704136a..cb147aa572 100644 --- a/res/ps_rectangle_clip.vs.glsl +++ b/res/ps_rectangle_clip.vs.glsl @@ -29,7 +29,7 @@ void main(void) { rect.info.local_clip_rect.xy, rect.info.local_clip_rect.xy + rect.info.local_clip_rect.zw); - vClipRect = rect.clip.rect; + vClipRect = vec4(rect.clip.rect.xy, rect.clip.rect.xy + rect.clip.rect.zw); vClipRadius = rect.clip.top_left.outer_inner_radius.x; vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); From 76890b06473fbcb4762a4a9444230cd4ffab67b3 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Tue, 26 Jul 2016 15:49:20 -0700 Subject: [PATCH 20/33] add a global device position to border shaders --- res/ps_border.fs.glsl | 6 +++--- res/ps_border.glsl | 3 ++- res/ps_border.vs.glsl | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 13962d56d3..94dd1727e1 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -21,7 +21,7 @@ vec4 draw_dotted_edge() { vec2 size = vec2(vBorders.z, vBorders.w); // Get our position within this specific segment - vec2 position = vPos - vBorders.xy; + vec2 position = vDevicePos - vBorders.xy; // Break our position into square tiles with circles in them. vec2 circleCount = floor(size / circleSpacing); @@ -70,8 +70,8 @@ void draw_dotted_border(void) { void main(void) { if (vRadii.x > 0.0 && - (distance(vRefPoint, vPos) > vRadii.x || - distance(vRefPoint, vPos) < vRadii.z)) { + (distance(vRefPoint, vLocalPos) > vRadii.x || + distance(vRefPoint, vLocalPos) < vRadii.z)) { discard; } diff --git a/res/ps_border.glsl b/res/ps_border.glsl index 52f633b5ee..1ea1ba8bb3 100644 --- a/res/ps_border.glsl +++ b/res/ps_border.glsl @@ -13,7 +13,8 @@ flat varying vec4 vColor1; // The border color flat varying vec4 vRadii; // The border radius from CSS border-radius // These are in device space -varying vec2 vPos; // This is the clamped position of the current position. +varying vec2 vLocalPos; // The clamped position in local space. +varying vec2 vDevicePos; // The clamped position in device space. flat varying vec4 vBorders; // the rect of the border in (x, y, width, height) form // for corners, this is the beginning of the corner. diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index bb6dcbc992..65c8c0677f 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -127,7 +127,8 @@ void main(void) { vColor1 = border.color1; // Local space - vPos = local_clamped_pos.xy; + vLocalPos = local_clamped_pos.xy; + vDevicePos = clamped_pos; // These are in device space vBorders = vec4(border.local_rect.x, border.local_rect.y, From ac2e8da792069250c1d8d0d1201527696a66e7ce Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 27 Jul 2016 09:03:10 +1000 Subject: [PATCH 21/33] Move local_rect into the common primitive structure. --- res/prim_shared.glsl | 1 + res/ps_angle_gradient.vs.glsl | 5 ++- res/ps_border.vs.glsl | 53 +++++++++++++++--------------- res/ps_box_shadow.vs.glsl | 5 ++- res/ps_gradient.vs.glsl | 7 ++-- res/ps_image.vs.glsl | 5 ++- res/ps_image_clip.vs.glsl | 7 ++-- res/ps_image_transform.vs.glsl | 13 ++++---- res/ps_rectangle.vs.glsl | 5 ++- res/ps_rectangle_clip.vs.glsl | 9 +++-- res/ps_rectangle_transform.vs.glsl | 11 +++---- res/ps_text.vs.glsl | 7 ++-- 12 files changed, 59 insertions(+), 69 deletions(-) diff --git a/res/prim_shared.glsl b/res/prim_shared.glsl index 55a1205d38..09a9af8754 100644 --- a/res/prim_shared.glsl +++ b/res/prim_shared.glsl @@ -48,6 +48,7 @@ layout(std140) uniform Tiles { struct PrimitiveInfo { uvec4 layer_tile_part; vec4 local_clip_rect; + vec4 local_rect; }; struct ClipCorner { diff --git a/res/ps_angle_gradient.vs.glsl b/res/ps_angle_gradient.vs.glsl index b8d845a2f7..6281abcf60 100644 --- a/res/ps_angle_gradient.vs.glsl +++ b/res/ps_angle_gradient.vs.glsl @@ -5,7 +5,6 @@ struct AngleGradient { PrimitiveInfo info; - vec4 local_rect; vec4 start_end_point; uvec4 stop_count; vec4 colors[MAX_STOPS_PER_ANGLE_GRADIENT]; @@ -21,8 +20,8 @@ void main(void) { Layer layer = layers[gradient.info.layer_tile_part.x]; Tile tile = tiles[gradient.info.layer_tile_part.y]; - vec2 local_pos = mix(gradient.local_rect.xy, - gradient.local_rect.xy + gradient.local_rect.zw, + vec2 local_pos = mix(gradient.info.local_rect.xy, + gradient.info.local_rect.xy + gradient.info.local_rect.zw, aPosition.xy); vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index 65c8c0677f..923f0cd650 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -5,7 +5,6 @@ struct Border { PrimitiveInfo info; - vec4 local_rect; vec4 color0; vec4 color1; vec4 radii; @@ -38,8 +37,8 @@ void main(void) { Layer layer = layers[border.info.layer_tile_part.x]; Tile tile = tiles[border.info.layer_tile_part.y]; - vec2 p0 = floor(0.5 + border.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = p0 + border.local_rect.zw; + vec2 p0 = floor(0.5 + border.info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = p0 + border.info.local_rect.zw; vec2 local_pos = mix(p0, p1, aPosition.xy); @@ -70,46 +69,46 @@ void main(void) { switch (vBorderPart) { // These are the layer tile part PrimitivePart as uploaded by the tiling.rs case PST_TOP_LEFT: - x0 = border.local_rect.x; - y0 = border.local_rect.y; + x0 = border.info.local_rect.x; + y0 = border.info.local_rect.y; // These are width / heights - x1 = border.local_rect.x + border.local_rect.z; - y1 = border.local_rect.y + border.local_rect.w; + x1 = border.info.local_rect.x + border.info.local_rect.z; + y1 = border.info.local_rect.y + border.info.local_rect.w; // The radius here is the border-radius. This is 0, so vRefPoint will // just be the top left (x,y) corner. vRefPoint = vec2(x0, y0) + vRadii.xy; break; case PST_TOP_RIGHT: - x0 = border.local_rect.x + border.local_rect.z; - y0 = border.local_rect.y; - x1 = border.local_rect.x; - y1 = border.local_rect.y + border.local_rect.w; + x0 = border.info.local_rect.x + border.info.local_rect.z; + y0 = border.info.local_rect.y; + x1 = border.info.local_rect.x; + y1 = border.info.local_rect.y + border.info.local_rect.w; vRefPoint = vec2(x0, y0) + vec2(-vRadii.x, vRadii.y); break; case PST_BOTTOM_LEFT: - x0 = border.local_rect.x; - y0 = border.local_rect.y + border.local_rect.w; - x1 = border.local_rect.x + border.local_rect.z; - y1 = border.local_rect.y; + x0 = border.info.local_rect.x; + y0 = border.info.local_rect.y + border.info.local_rect.w; + x1 = border.info.local_rect.x + border.info.local_rect.z; + y1 = border.info.local_rect.y; vRefPoint = vec2(x0, y0) + vec2(vRadii.x, -vRadii.y); break; case PST_BOTTOM_RIGHT: - x0 = border.local_rect.x; - y0 = border.local_rect.y; - x1 = border.local_rect.x + border.local_rect.z; - y1 = border.local_rect.y + border.local_rect.w; + x0 = border.info.local_rect.x; + y0 = border.info.local_rect.y; + x1 = border.info.local_rect.x + border.info.local_rect.z; + y1 = border.info.local_rect.y + border.info.local_rect.w; vRefPoint = vec2(x1, y1) + vec2(-vRadii.x, -vRadii.y); break; case PST_TOP: case PST_LEFT: case PST_BOTTOM: case PST_RIGHT: - vRefPoint = border.local_rect.xy; - x0 = border.local_rect.x; - y0 = border.local_rect.y; - x1 = border.local_rect.x + border.local_rect.z; - y1 = border.local_rect.y + border.local_rect.w; + vRefPoint = border.info.local_rect.xy; + x0 = border.info.local_rect.x; + y0 = border.info.local_rect.y; + x1 = border.info.local_rect.x + border.info.local_rect.z; + y1 = border.info.local_rect.y + border.info.local_rect.w; break; } @@ -131,7 +130,7 @@ void main(void) { vDevicePos = clamped_pos; // These are in device space - vBorders = vec4(border.local_rect.x, border.local_rect.y, - border.local_rect.z, - border.local_rect.w) * uDevicePixelRatio; + vBorders = vec4(border.info.local_rect.x, border.info.local_rect.y, + border.info.local_rect.z, + border.info.local_rect.w) * uDevicePixelRatio; } diff --git a/res/ps_box_shadow.vs.glsl b/res/ps_box_shadow.vs.glsl index 212813ffec..59978224ed 100644 --- a/res/ps_box_shadow.vs.glsl +++ b/res/ps_box_shadow.vs.glsl @@ -5,7 +5,6 @@ struct BoxShadow { PrimitiveInfo info; - vec4 local_rect; vec4 color; vec4 border_radii_blur_radius_inverted; vec4 bs_rect; @@ -23,8 +22,8 @@ void main(void) { vColor = bs.color; - vec2 local_pos = mix(bs.local_rect.xy, - bs.local_rect.xy + bs.local_rect.zw, + vec2 local_pos = mix(bs.info.local_rect.xy, + bs.info.local_rect.xy + bs.info.local_rect.zw, aPosition.xy); vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); diff --git a/res/ps_gradient.vs.glsl b/res/ps_gradient.vs.glsl index 81d00b2861..58ff18794f 100644 --- a/res/ps_gradient.vs.glsl +++ b/res/ps_gradient.vs.glsl @@ -8,7 +8,6 @@ struct Gradient { PrimitiveInfo info; - vec4 local_rect; vec4 color0; vec4 color1; uvec4 dir; @@ -23,8 +22,8 @@ void main(void) { Layer layer = layers[gradient.info.layer_tile_part.x]; Tile tile = tiles[gradient.info.layer_tile_part.y]; - vec2 local_pos = mix(gradient.local_rect.xy, - gradient.local_rect.xy + gradient.local_rect.zw, + vec2 local_pos = mix(gradient.info.local_rect.xy, + gradient.info.local_rect.xy + gradient.info.local_rect.zw, aPosition.xy); vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); @@ -37,7 +36,7 @@ void main(void) { vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - vec2 f = (local_clamped_pos.xy - gradient.local_rect.xy) / gradient.local_rect.zw; + vec2 f = (local_clamped_pos.xy - gradient.info.local_rect.xy) / gradient.info.local_rect.zw; vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; diff --git a/res/ps_image.vs.glsl b/res/ps_image.vs.glsl index f43f20c93d..30f98ce709 100644 --- a/res/ps_image.vs.glsl +++ b/res/ps_image.vs.glsl @@ -5,7 +5,6 @@ struct Image { PrimitiveInfo info; - vec4 local_rect; // Size of the box we need to fill with this image. vec4 st_rect; // Location of the image texture in the texture atlas. vec2 stretch_size; // Size of the actual image. }; @@ -20,8 +19,8 @@ void main(void) { Tile tile = tiles[image.info.layer_tile_part.y]; // Our location within the image - vec2 p0 = floor(0.5 + image.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = floor(0.5 + (image.local_rect.xy + image.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p0 = floor(0.5 + image.info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = floor(0.5 + (image.info.local_rect.xy + image.info.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; vec2 local_pos = mix(p0, p1, aPosition.xy); diff --git a/res/ps_image_clip.vs.glsl b/res/ps_image_clip.vs.glsl index 748254a59c..d0c974172d 100644 --- a/res/ps_image_clip.vs.glsl +++ b/res/ps_image_clip.vs.glsl @@ -5,7 +5,6 @@ struct Image { PrimitiveInfo info; - vec4 local_rect; // Size of the box we need to fill with this image. vec4 st_rect; // Location of the image texture in the texture atlas. vec2 stretch_size; // Size of the actual image. Clip clip; @@ -21,8 +20,8 @@ void main(void) { Tile tile = tiles[image.info.layer_tile_part.y]; // Our location within the image - vec2 local_pos = mix(image.local_rect.xy, - image.local_rect.xy + image.local_rect.zw, + vec2 local_pos = mix(image.info.local_rect.xy, + image.info.local_rect.xy + image.info.local_rect.zw, aPosition.xy); local_pos = clamp(local_pos, @@ -44,7 +43,7 @@ void main(void) { vPos = local_clamped_pos.xy; // vUv will contain how many times this image has wrapped around the image size. - vUv = (local_clamped_pos.xy - image.local_rect.xy) / image.stretch_size.xy; + vUv = (local_clamped_pos.xy - image.info.local_rect.xy) / image.stretch_size.xy; vTextureSize = image.st_rect.zw - image.st_rect.xy; vTextureOffset = image.st_rect.xy; diff --git a/res/ps_image_transform.vs.glsl b/res/ps_image_transform.vs.glsl index a5c2836256..4a82b4bc67 100644 --- a/res/ps_image_transform.vs.glsl +++ b/res/ps_image_transform.vs.glsl @@ -5,7 +5,6 @@ struct Image { PrimitiveInfo info; - vec4 local_rect; vec4 st_rect; }; @@ -18,10 +17,10 @@ void main(void) { Layer layer = layers[image.info.layer_tile_part.x]; Tile tile = tiles[image.info.layer_tile_part.y]; - vec2 p0 = image.local_rect.xy; - vec2 p1 = image.local_rect.xy + vec2(image.local_rect.z, 0.0); - vec2 p2 = image.local_rect.xy + vec2(0.0, image.local_rect.w); - vec2 p3 = image.local_rect.xy + image.local_rect.zw; + vec2 p0 = image.info.local_rect.xy; + vec2 p1 = image.info.local_rect.xy + vec2(image.info.local_rect.z, 0.0); + vec2 p2 = image.info.local_rect.xy + vec2(0.0, image.info.local_rect.w); + vec2 p3 = image.info.local_rect.xy + image.info.local_rect.zw; vec4 t0 = layer.transform * vec4(p0, 0, 1); vec4 t1 = layer.transform * vec4(p1, 0, 1); @@ -50,10 +49,10 @@ void main(void) { vec3 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, image.info.layer_tile_part.x); - vRect = image.local_rect; + vRect = image.info.local_rect; vPos = layer_pos; - vec2 f = (layer_pos.xy - image.local_rect.xy) / image.local_rect.zw; + vec2 f = (layer_pos.xy - image.info.local_rect.xy) / image.info.local_rect.zw; vUv = mix(image.st_rect.xy, image.st_rect.zw, diff --git a/res/ps_rectangle.vs.glsl b/res/ps_rectangle.vs.glsl index 3f638feb42..e1840412b6 100644 --- a/res/ps_rectangle.vs.glsl +++ b/res/ps_rectangle.vs.glsl @@ -5,7 +5,6 @@ struct Rectangle { PrimitiveInfo info; - vec4 local_rect; vec4 color; }; @@ -20,8 +19,8 @@ void main(void) { vColor = rect.color; - vec2 p0 = floor(0.5 + rect.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = floor(0.5 + (rect.local_rect.xy + rect.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p0 = floor(0.5 + rect.info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = floor(0.5 + (rect.info.local_rect.xy + rect.info.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; vec2 local_pos = mix(p0, p1, aPosition.xy); diff --git a/res/ps_rectangle_clip.vs.glsl b/res/ps_rectangle_clip.vs.glsl index cb147aa572..de073c2db1 100644 --- a/res/ps_rectangle_clip.vs.glsl +++ b/res/ps_rectangle_clip.vs.glsl @@ -4,9 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ struct Rectangle { - PrimitiveInfo info; - vec4 local_rect; - vec4 color; + PrimitiveInfo info; + vec4 color; Clip clip; }; @@ -21,8 +20,8 @@ void main(void) { vColor = rect.color; - vec2 local_pos = mix(rect.local_rect.xy, - rect.local_rect.xy + rect.local_rect.zw, + vec2 local_pos = mix(rect.info.local_rect.xy, + rect.info.local_rect.xy + rect.info.local_rect.zw, aPosition.xy); local_pos = clamp(local_pos, diff --git a/res/ps_rectangle_transform.vs.glsl b/res/ps_rectangle_transform.vs.glsl index 9d10cad7e9..8bd3421366 100644 --- a/res/ps_rectangle_transform.vs.glsl +++ b/res/ps_rectangle_transform.vs.glsl @@ -5,7 +5,6 @@ struct Rectangle { PrimitiveInfo info; - vec4 local_rect; vec4 color; }; @@ -18,10 +17,10 @@ void main(void) { Layer layer = layers[rect.info.layer_tile_part.x]; Tile tile = tiles[rect.info.layer_tile_part.y]; - vec2 p0 = rect.local_rect.xy; - vec2 p1 = rect.local_rect.xy + vec2(rect.local_rect.z, 0.0); - vec2 p2 = rect.local_rect.xy + vec2(0.0, rect.local_rect.w); - vec2 p3 = rect.local_rect.xy + rect.local_rect.zw; + vec2 p0 = rect.info.local_rect.xy; + vec2 p1 = rect.info.local_rect.xy + vec2(rect.info.local_rect.z, 0.0); + vec2 p2 = rect.info.local_rect.xy + vec2(0.0, rect.info.local_rect.w); + vec2 p3 = rect.info.local_rect.xy + rect.info.local_rect.zw; vec4 t0 = layer.transform * vec4(p0, 0, 1); vec4 t1 = layer.transform * vec4(p1, 0, 1); @@ -50,7 +49,7 @@ void main(void) { vec3 layer_pos = get_layer_pos(clamped_pos / uDevicePixelRatio, rect.info.layer_tile_part.x); - vRect = rect.local_rect; + vRect = rect.info.local_rect; vPos = layer_pos; vColor = rect.color; diff --git a/res/ps_text.vs.glsl b/res/ps_text.vs.glsl index 733f91bcbd..677112b4f9 100644 --- a/res/ps_text.vs.glsl +++ b/res/ps_text.vs.glsl @@ -5,7 +5,6 @@ struct Glyph { PrimitiveInfo info; - vec4 local_rect; vec4 color; vec4 st_rect; }; @@ -21,8 +20,8 @@ void main(void) { vColor = glyph.color; - vec2 p0 = floor(0.5 + glyph.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = p0 + glyph.local_rect.zw; + vec2 p0 = floor(0.5 + glyph.info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = p0 + glyph.info.local_rect.zw; vec2 local_pos = mix(p0, p1, aPosition.xy); @@ -36,7 +35,7 @@ void main(void) { vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - vec2 f = (local_clamped_pos.xy - p0) / glyph.local_rect.zw; + vec2 f = (local_clamped_pos.xy - p0) / glyph.info.local_rect.zw; vUv = mix(glyph.st_rect.xy, glyph.st_rect.zw, From 90b67a94ddfbfb6133de6d7a62826343a480f1c6 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Tue, 26 Jul 2016 16:34:17 -0700 Subject: [PATCH 22/33] basic dashes work but they look too fat --- res/ps_border.fs.glsl | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 94dd1727e1..5db28a1823 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -9,6 +9,15 @@ vec4 drawCircle(vec2 aPixel, vec2 aDesiredPos, float aRadius, vec3 aColor) { return vec4(aColor, pixelInCircle); } +// Draw a rectangle at aRect fill it with aColor. Only works on non-rotated +// rects. +vec4 drawRect(vec2 aPixel, vec4 aRect, vec3 aColor) { + // GLSL origin is bottom left, positive Y is up + bool inRect = (aRect.x <= aPixel.x) && (aPixel.x <= aRect.x + aRect.z) && + (aPixel.y >= aRect.y) && (aPixel.y <= aRect.y + aRect.w); + return vec4(aColor, float(inRect)); +} + vec4 draw_dotted_edge() { // Everything here should be in device pixels. // We want the dot to be roughly the size of the whole border spacing @@ -49,6 +58,33 @@ vec4 draw_dotted_edge() { return mix(white, circleColor, circleColor.a); } +vec4 draw_dashed_edge() { + // Everything here should be in device pixels. + // We want the dot to be roughly the size of the whole border spacing + float dash_interval = min(vBorders.w, vBorders.z) * 2; + vec2 edge_size = vec2(vBorders.z, vBorders.w); + vec2 dash_size = vec2(dash_interval / 2.0, dash_interval / 2.0); + vec2 position = vDevicePos - vBorders.xy; + + vec2 dash_count = floor(edge_size/ dash_interval); + vec2 dist_between_dashes = edge_size / dash_count; + + vec2 target_rect_index = floor(position / dist_between_dashes); + vec2 target_rect_loc = target_rect_index * dist_between_dashes; + + // TODO correct for center spacing. + vec4 target_rect = vec4(target_rect_loc, dash_size); + + vec4 white = vec4(1.0, 1.0, 1.0, 1.0); + vec3 black = vec3(0.0, 0.0, 0.0); + vec4 target_colored_rect = drawRect(position, target_rect, black); + + return mix(white, target_colored_rect, target_colored_rect.a); + + //vec4 white = vec4(1.0, 1.0, 1.0, 1.0); + //return white; +} + void draw_dotted_border(void) { switch (vBorderPart) { // These are the layer tile part PrimitivePart as uploaded by the tiling.rs @@ -68,6 +104,25 @@ void draw_dotted_border(void) { } } +void draw_dashed_border(void) { + switch (vBorderPart) { + // These are the layer tile part PrimitivePart as uploaded by the tiling.rs + case PST_TOP_LEFT: + case PST_TOP_RIGHT: + case PST_BOTTOM_LEFT: + case PST_BOTTOM_RIGHT: + // TODO: Fix for corners with a border-radius + oFragColor = draw_dashed_edge(); + break; + case PST_BOTTOM: + case PST_TOP: + case PST_LEFT: + case PST_RIGHT: + oFragColor = draw_dashed_edge(); + break; + } +} + void main(void) { if (vRadii.x > 0.0 && (distance(vRefPoint, vLocalPos) > vRadii.x || @@ -76,6 +131,11 @@ void main(void) { } switch (vBorderStyle) { + case BORDER_STYLE_DASHED: + { + draw_dashed_border(); + break; + } case BORDER_STYLE_DOTTED: { draw_dotted_border(); From 559223a9a1fd62df528ef37dbf94bb231492a879 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Tue, 26 Jul 2016 16:35:17 -0700 Subject: [PATCH 23/33] basic dashes work but they look too fat --- res/ps_border.fs.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 5db28a1823..9d76f002ff 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -61,7 +61,7 @@ vec4 draw_dotted_edge() { vec4 draw_dashed_edge() { // Everything here should be in device pixels. // We want the dot to be roughly the size of the whole border spacing - float dash_interval = min(vBorders.w, vBorders.z) * 2; + float dash_interval = min(vBorders.w, vBorders.z) * 3; vec2 edge_size = vec2(vBorders.z, vBorders.w); vec2 dash_size = vec2(dash_interval / 2.0, dash_interval / 2.0); vec2 position = vDevicePos - vBorders.xy; From d53c8b057366bc3897130a7447e507af1fd8edb3 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 27 Jul 2016 09:51:04 +1000 Subject: [PATCH 24/33] Tidy up the (non-transform) vertex shaders, abstract common functionality. --- res/prim_shared.glsl | 47 +++++++++++++++++++++++++++++++++++ res/ps_angle_gradient.vs.glsl | 23 ++--------------- res/ps_border.vs.glsl | 29 ++------------------- res/ps_box_shadow.vs.glsl | 25 ++----------------- res/ps_gradient.vs.glsl | 23 ++--------------- res/ps_image.vs.glsl | 29 ++------------------- res/ps_image_clip.vs.glsl | 30 +++------------------- res/ps_rectangle.vs.glsl | 29 +-------------------- res/ps_rectangle_clip.vs.glsl | 29 +++------------------ res/ps_text.vs.glsl | 27 +++----------------- 10 files changed, 67 insertions(+), 224 deletions(-) diff --git a/res/prim_shared.glsl b/res/prim_shared.glsl index 09a9af8754..01a83e1974 100644 --- a/res/prim_shared.glsl +++ b/res/prim_shared.glsl @@ -25,6 +25,7 @@ #define BORDER_STYLE_INSET uint(8) #define BORDER_STYLE_OUTSET uint(9) +#ifdef WR_VERTEX_SHADER struct Layer { mat4 transform; mat4 inv_transform; @@ -98,6 +99,52 @@ vec3 get_layer_pos(vec2 pos, uint layer_index) { return local_pos.xyw; } +struct Rect { + vec2 p0; + vec2 p1; +}; + +struct VertexInfo { + Rect local_rect; + vec2 local_clamped_pos; +}; + +VertexInfo write_vertex(PrimitiveInfo info) { + Layer layer = layers[info.layer_tile_part.x]; + Tile tile = tiles[info.layer_tile_part.y]; + + vec2 p0 = floor(0.5 + info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 p1 = floor(0.5 + (info.local_rect.xy + info.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + + vec2 local_pos = mix(p0, p1, aPosition.xy); + + vec2 cp0 = floor(0.5 + info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; + vec2 cp1 = floor(0.5 + (info.local_clip_rect.xy + info.local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; + local_pos = clamp(local_pos, cp0, cp1); + + vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + + vec2 device_pos = world_pos.xy * uDevicePixelRatio; + + vec2 clamped_pos = clamp(device_pos, + tile.actual_rect.xy, + tile.actual_rect.xy + tile.actual_rect.zw); + + clamped_pos = clamp(clamped_pos, + layer.world_clip_rect.xy, + layer.world_clip_rect.xy + layer.world_clip_rect.zw); + + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + + vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + + gl_Position = uTransform * vec4(final_pos, 0, 1); + + VertexInfo vi = VertexInfo(Rect(p0, p1), local_clamped_pos.xy); + return vi; +} +#endif + #ifdef WR_FRAGMENT_SHADER void do_clip(vec2 pos, vec4 clip_rect, float radius) { vec2 ref_tl = clip_rect.xy + vec2( radius, radius); diff --git a/res/ps_angle_gradient.vs.glsl b/res/ps_angle_gradient.vs.glsl index 6281abcf60..4a1a9ac32b 100644 --- a/res/ps_angle_gradient.vs.glsl +++ b/res/ps_angle_gradient.vs.glsl @@ -17,27 +17,10 @@ layout(std140) uniform Items { void main(void) { AngleGradient gradient = gradients[gl_InstanceID]; - Layer layer = layers[gradient.info.layer_tile_part.x]; - Tile tile = tiles[gradient.info.layer_tile_part.y]; - - vec2 local_pos = mix(gradient.info.local_rect.xy, - gradient.info.local_rect.xy + gradient.info.local_rect.zw, - aPosition.xy); - - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + VertexInfo vi = write_vertex(gradient.info); vStopCount = int(gradient.stop_count.x); - vPos = local_clamped_pos.xy; + vPos = vi.local_clamped_pos; vStartPoint = gradient.start_end_point.xy; vEndPoint = gradient.start_end_point.zw; @@ -45,6 +28,4 @@ void main(void) { vColors[i] = gradient.colors[i]; vOffsets[i] = gradient.offsets[i]; } - - gl_Position = uTransform * vec4(final_pos, 0, 1); } diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index 923f0cd650..9abda5aa14 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -34,32 +34,7 @@ uint get_border_style(Border a_border, uint a_edge) { void main(void) { Border border = borders[gl_InstanceID]; - Layer layer = layers[border.info.layer_tile_part.x]; - Tile tile = tiles[border.info.layer_tile_part.y]; - - vec2 p0 = floor(0.5 + border.info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = p0 + border.info.local_rect.zw; - - vec2 local_pos = mix(p0, p1, aPosition.xy); - - vec2 cp0 = floor(0.5 + border.info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 cp1 = cp0 + border.info.local_clip_rect.zw; - - local_pos = clamp(local_pos, cp0, cp1); - - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; - - gl_Position = uTransform * vec4(final_pos, 0, 1); + VertexInfo vi = write_vertex(border.info); // Just our boring radius position. vRadii = border.radii; @@ -119,7 +94,7 @@ void main(void) { float width = x1 - x0; float height = y1 - y0; // This is just a weighting of the pixel colors it seems? - vF = (local_clamped_pos.x - x0) * height - (local_clamped_pos.y - y0) * width; + vF = (vi.local_clamped_pos.x - x0) * height - (vi.local_clamped_pos.y - y0) * width; // This is what was currently sent. vColor0 = border.color0; diff --git a/res/ps_box_shadow.vs.glsl b/res/ps_box_shadow.vs.glsl index 59978224ed..cfcdacfa67 100644 --- a/res/ps_box_shadow.vs.glsl +++ b/res/ps_box_shadow.vs.glsl @@ -17,34 +17,13 @@ layout(std140) uniform Items { void main(void) { BoxShadow bs = boxshadows[gl_InstanceID]; - Layer layer = layers[bs.info.layer_tile_part.x]; - Tile tile = tiles[bs.info.layer_tile_part.y]; + VertexInfo vi = write_vertex(bs.info); - vColor = bs.color; - - vec2 local_pos = mix(bs.info.local_rect.xy, - bs.info.local_rect.xy + bs.info.local_rect.zw, - aPosition.xy); - - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - - vPos = local_clamped_pos.xy; + vPos = vi.local_clamped_pos; vColor = bs.color; vBorderRadii = bs.border_radii_blur_radius_inverted.xy; vBlurRadius = bs.border_radii_blur_radius_inverted.z; vBoxShadowRect = vec4(bs.bs_rect.xy, bs.bs_rect.xy + bs.bs_rect.zw); vSrcRect = vec4(bs.src_rect.xy, bs.src_rect.xy + bs.src_rect.zw); vInverted = bs.border_radii_blur_radius_inverted.w; - - gl_Position = uTransform * vec4(final_pos, 0, 1); } diff --git a/res/ps_gradient.vs.glsl b/res/ps_gradient.vs.glsl index 58ff18794f..023f5eea2f 100644 --- a/res/ps_gradient.vs.glsl +++ b/res/ps_gradient.vs.glsl @@ -19,28 +19,9 @@ layout(std140) uniform Items { void main(void) { Gradient gradient = gradients[gl_InstanceID]; - Layer layer = layers[gradient.info.layer_tile_part.x]; - Tile tile = tiles[gradient.info.layer_tile_part.y]; + VertexInfo vi = write_vertex(gradient.info); - vec2 local_pos = mix(gradient.info.local_rect.xy, - gradient.info.local_rect.xy + gradient.info.local_rect.zw, - aPosition.xy); - - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - - vec2 f = (local_clamped_pos.xy - gradient.info.local_rect.xy) / gradient.info.local_rect.zw; - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; - - gl_Position = uTransform * vec4(final_pos, 0, 1); + vec2 f = (vi.local_clamped_pos - gradient.info.local_rect.xy) / gradient.info.local_rect.zw; switch (gradient.dir.x) { case DIR_HORIZONTAL: diff --git a/res/ps_image.vs.glsl b/res/ps_image.vs.glsl index 30f98ce709..ce2ef0b69a 100644 --- a/res/ps_image.vs.glsl +++ b/res/ps_image.vs.glsl @@ -15,35 +15,10 @@ layout(std140) uniform Items { void main(void) { Image image = images[gl_InstanceID]; - Layer layer = layers[image.info.layer_tile_part.x]; - Tile tile = tiles[image.info.layer_tile_part.y]; - - // Our location within the image - vec2 p0 = floor(0.5 + image.info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = floor(0.5 + (image.info.local_rect.xy + image.info.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; - - vec2 local_pos = mix(p0, p1, aPosition.xy); - - vec2 cp0 = floor(0.5 + image.info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 cp1 = floor(0.5 + (image.info.local_clip_rect.xy + image.info.local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; - local_pos = clamp(local_pos, cp0, cp1); - - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + VertexInfo vi = write_vertex(image.info); // vUv will contain how many times this image has wrapped around the image size. - vUv = (local_clamped_pos.xy - p0) / image.stretch_size.xy; + vUv = (vi.local_clamped_pos - vi.local_rect.p0) / image.stretch_size.xy; vTextureSize = image.st_rect.zw - image.st_rect.xy; vTextureOffset = image.st_rect.xy; - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; - - gl_Position = uTransform * vec4(final_pos, 0, 1); } diff --git a/res/ps_image_clip.vs.glsl b/res/ps_image_clip.vs.glsl index d0c974172d..70a57ed6e9 100644 --- a/res/ps_image_clip.vs.glsl +++ b/res/ps_image_clip.vs.glsl @@ -16,38 +16,14 @@ layout(std140) uniform Items { void main(void) { Image image = images[gl_InstanceID]; - Layer layer = layers[image.info.layer_tile_part.x]; - Tile tile = tiles[image.info.layer_tile_part.y]; - - // Our location within the image - vec2 local_pos = mix(image.info.local_rect.xy, - image.info.local_rect.xy + image.info.local_rect.zw, - aPosition.xy); - - local_pos = clamp(local_pos, - image.info.local_clip_rect.xy, - image.info.local_clip_rect.xy + image.info.local_clip_rect.zw); + VertexInfo vi = write_vertex(image.info); vClipRect = vec4(image.clip.rect.xy, image.clip.rect.xy + image.clip.rect.zw); vClipRadius = image.clip.top_left.outer_inner_radius.x; - - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - vPos = local_clamped_pos.xy; + vPos = vi.local_clamped_pos; // vUv will contain how many times this image has wrapped around the image size. - vUv = (local_clamped_pos.xy - image.info.local_rect.xy) / image.stretch_size.xy; + vUv = (vi.local_clamped_pos - image.info.local_rect.xy) / image.stretch_size.xy; vTextureSize = image.st_rect.zw - image.st_rect.xy; vTextureOffset = image.st_rect.xy; - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; - - gl_Position = uTransform * vec4(final_pos, 0, 1); } diff --git a/res/ps_rectangle.vs.glsl b/res/ps_rectangle.vs.glsl index e1840412b6..01a4e5dc18 100644 --- a/res/ps_rectangle.vs.glsl +++ b/res/ps_rectangle.vs.glsl @@ -14,33 +14,6 @@ layout(std140) uniform Items { void main(void) { Rectangle rect = rects[gl_InstanceID]; - Layer layer = layers[rect.info.layer_tile_part.x]; - Tile tile = tiles[rect.info.layer_tile_part.y]; - + write_vertex(rect.info); vColor = rect.color; - - vec2 p0 = floor(0.5 + rect.info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = floor(0.5 + (rect.info.local_rect.xy + rect.info.local_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; - - vec2 local_pos = mix(p0, p1, aPosition.xy); - - vec2 cp0 = floor(0.5 + rect.info.local_clip_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 cp1 = floor(0.5 + (rect.info.local_clip_rect.xy + rect.info.local_clip_rect.zw) * uDevicePixelRatio) / uDevicePixelRatio; - local_pos = clamp(local_pos, cp0, cp1); - - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - clamped_pos = clamp(clamped_pos, - layer.world_clip_rect.xy, - layer.world_clip_rect.xy + layer.world_clip_rect.zw); - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; - - gl_Position = uTransform * vec4(final_pos, 0, 1); } diff --git a/res/ps_rectangle_clip.vs.glsl b/res/ps_rectangle_clip.vs.glsl index de073c2db1..2b87eee4a9 100644 --- a/res/ps_rectangle_clip.vs.glsl +++ b/res/ps_rectangle_clip.vs.glsl @@ -15,34 +15,11 @@ layout(std140) uniform Items { void main(void) { Rectangle rect = rects[gl_InstanceID]; - Layer layer = layers[rect.info.layer_tile_part.x]; - Tile tile = tiles[rect.info.layer_tile_part.y]; - - vColor = rect.color; - - vec2 local_pos = mix(rect.info.local_rect.xy, - rect.info.local_rect.xy + rect.info.local_rect.zw, - aPosition.xy); - - local_pos = clamp(local_pos, - rect.info.local_clip_rect.xy, - rect.info.local_clip_rect.xy + rect.info.local_clip_rect.zw); + VertexInfo vi = write_vertex(rect.info); vClipRect = vec4(rect.clip.rect.xy, rect.clip.rect.xy + rect.clip.rect.zw); vClipRadius = rect.clip.top_left.outer_inner_radius.x; + vPos = vi.local_clamped_pos; - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - vPos = local_clamped_pos.xy; - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; - - gl_Position = uTransform * vec4(final_pos, 0, 1); + vColor = rect.color; } diff --git a/res/ps_text.vs.glsl b/res/ps_text.vs.glsl index 677112b4f9..39e72bf868 100644 --- a/res/ps_text.vs.glsl +++ b/res/ps_text.vs.glsl @@ -15,33 +15,12 @@ layout(std140) uniform Items { void main(void) { Glyph glyph = glyphs[gl_InstanceID]; - Layer layer = layers[glyph.info.layer_tile_part.x]; - Tile tile = tiles[glyph.info.layer_tile_part.y]; + VertexInfo vi = write_vertex(glyph.info); - vColor = glyph.color; - - vec2 p0 = floor(0.5 + glyph.info.local_rect.xy * uDevicePixelRatio) / uDevicePixelRatio; - vec2 p1 = p0 + glyph.info.local_rect.zw; - - vec2 local_pos = mix(p0, p1, aPosition.xy); - - vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); - - vec2 device_pos = world_pos.xy * uDevicePixelRatio; - - vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); - - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); - - vec2 f = (local_clamped_pos.xy - p0) / glyph.info.local_rect.zw; + vec2 f = (vi.local_clamped_pos - vi.local_rect.p0) / (vi.local_rect.p1 - vi.local_rect.p0); + vColor = glyph.color; vUv = mix(glyph.st_rect.xy, glyph.st_rect.zw, f); - - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; - - gl_Position = uTransform * vec4(final_pos, 0, 1); } From 7bf757ffaf368fa58a21cec84cf613de37942c57 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Tue, 26 Jul 2016 17:13:34 -0700 Subject: [PATCH 25/33] dashed lines work but corners look wrong --- res/ps_border.fs.glsl | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 9d76f002ff..97e8a8d2bf 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -58,10 +58,28 @@ vec4 draw_dotted_edge() { return mix(white, circleColor, circleColor.a); } -vec4 draw_dashed_edge() { +// Our current edge calculation is based only on +// the size of the border-size, but we need to draw +// the dashes in the center of the segment we're drawing. +// This calculates how much to nudge and which axis to nudge on. +vec2 get_dashed_nudge_factor(vec2 dash_size, bool is_corner) { + if (is_corner) { + return vec2(0.0, 0.0); + } + + bool xAxisFudge = vBorders.z > vBorders.w; + if (xAxisFudge) { + return vec2(dash_size.x / 2.0, 0); + } else { + return vec2(0.0, dash_size.y / 2.0); + } +} + +vec4 draw_dashed_edge(bool is_corner) { // Everything here should be in device pixels. // We want the dot to be roughly the size of the whole border spacing - float dash_interval = min(vBorders.w, vBorders.z) * 3; + // 5.5 here isn't a magic number, it's just what mostly looks like FF/Chrome + float dash_interval = min(vBorders.w, vBorders.z) * 5.5; vec2 edge_size = vec2(vBorders.z, vBorders.w); vec2 dash_size = vec2(dash_interval / 2.0, dash_interval / 2.0); vec2 position = vDevicePos - vBorders.xy; @@ -71,6 +89,7 @@ vec4 draw_dashed_edge() { vec2 target_rect_index = floor(position / dist_between_dashes); vec2 target_rect_loc = target_rect_index * dist_between_dashes; + target_rect_loc += get_dashed_nudge_factor(dash_size, is_corner); // TODO correct for center spacing. vec4 target_rect = vec4(target_rect_loc, dash_size); @@ -80,9 +99,6 @@ vec4 draw_dashed_edge() { vec4 target_colored_rect = drawRect(position, target_rect, black); return mix(white, target_colored_rect, target_colored_rect.a); - - //vec4 white = vec4(1.0, 1.0, 1.0, 1.0); - //return white; } void draw_dotted_border(void) { @@ -92,15 +108,19 @@ void draw_dotted_border(void) { case PST_TOP_RIGHT: case PST_BOTTOM_LEFT: case PST_BOTTOM_RIGHT: + { // TODO: Fix for corners with a border-radius oFragColor = draw_dotted_edge(); break; + } case PST_BOTTOM: case PST_TOP: case PST_LEFT: case PST_RIGHT: + { oFragColor = draw_dotted_edge(); break; + } } } @@ -111,15 +131,21 @@ void draw_dashed_border(void) { case PST_TOP_RIGHT: case PST_BOTTOM_LEFT: case PST_BOTTOM_RIGHT: + { // TODO: Fix for corners with a border-radius - oFragColor = draw_dashed_edge(); + bool is_corner = true; + oFragColor = draw_dashed_edge(is_corner); break; + } case PST_BOTTOM: case PST_TOP: case PST_LEFT: case PST_RIGHT: - oFragColor = draw_dashed_edge(); + { + bool is_corner = false; + oFragColor = draw_dashed_edge(is_corner); break; + } } } From b90c12b3250e1460fff6aea7748673b1a172826b Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Tue, 26 Jul 2016 17:27:26 -0700 Subject: [PATCH 26/33] append global clamped position to VertexInfo --- res/prim_shared.glsl | 3 ++- res/ps_border.vs.glsl | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/res/prim_shared.glsl b/res/prim_shared.glsl index 01a83e1974..832165efbd 100644 --- a/res/prim_shared.glsl +++ b/res/prim_shared.glsl @@ -107,6 +107,7 @@ struct Rect { struct VertexInfo { Rect local_rect; vec2 local_clamped_pos; + vec2 global_clamped_pos; }; VertexInfo write_vertex(PrimitiveInfo info) { @@ -140,7 +141,7 @@ VertexInfo write_vertex(PrimitiveInfo info) { gl_Position = uTransform * vec4(final_pos, 0, 1); - VertexInfo vi = VertexInfo(Rect(p0, p1), local_clamped_pos.xy); + VertexInfo vi = VertexInfo(Rect(p0, p1), local_clamped_pos.xy, clamped_pos.xy); return vi; } #endif diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index 9abda5aa14..a675866532 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -101,8 +101,10 @@ void main(void) { vColor1 = border.color1; // Local space - vLocalPos = local_clamped_pos.xy; - vDevicePos = clamped_pos; + vLocalPos = vi.local_clamped_pos.xy; + + // These are in device space + vDevicePos = vi.global_clamped_pos; // These are in device space vBorders = vec4(border.info.local_rect.x, border.info.local_rect.y, From f6c15f58f164468425065173963cd75015744145 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 27 Jul 2016 11:16:21 +1000 Subject: [PATCH 27/33] Fix angle gradients, image struct. --- res/prim_shared.glsl | 24 +++++++++++++----------- res/ps_angle_gradient.fs.glsl | 7 ++++++- res/ps_angle_gradient.vs.glsl | 11 +++++++++-- res/ps_gradient.fs.glsl | 1 + res/ps_gradient.glsl | 3 +++ res/ps_gradient.vs.glsl | 8 ++++++++ res/ps_image.vs.glsl | 2 +- res/ps_image_clip.glsl | 2 +- res/ps_image_clip.vs.glsl | 7 +++++-- res/ps_image_transform.vs.glsl | 1 + res/ps_rectangle_clip.glsl | 2 +- res/ps_rectangle_clip.vs.glsl | 5 ++++- 12 files changed, 53 insertions(+), 20 deletions(-) diff --git a/res/prim_shared.glsl b/res/prim_shared.glsl index 832165efbd..bc9774336a 100644 --- a/res/prim_shared.glsl +++ b/res/prim_shared.glsl @@ -124,6 +124,7 @@ VertexInfo write_vertex(PrimitiveInfo info) { local_pos = clamp(local_pos, cp0, cp1); vec4 world_pos = layer.transform * vec4(local_pos, 0, 1); + world_pos.xyz /= world_pos.w; vec2 device_pos = world_pos.xy * uDevicePixelRatio; @@ -135,7 +136,8 @@ VertexInfo write_vertex(PrimitiveInfo info) { layer.world_clip_rect.xy, layer.world_clip_rect.xy + layer.world_clip_rect.zw); - vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, 0, 1); + vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, world_pos.z, 1); + local_clamped_pos.xyz /= local_clamped_pos.w; vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; @@ -147,21 +149,21 @@ VertexInfo write_vertex(PrimitiveInfo info) { #endif #ifdef WR_FRAGMENT_SHADER -void do_clip(vec2 pos, vec4 clip_rect, float radius) { - vec2 ref_tl = clip_rect.xy + vec2( radius, radius); - vec2 ref_tr = clip_rect.zy + vec2(-radius, radius); - vec2 ref_bl = clip_rect.xw + vec2( radius, -radius); - vec2 ref_br = clip_rect.zw + vec2(-radius, -radius); +void do_clip(vec2 pos, vec4 clip_rect, vec4 radius) { + vec2 ref_tl = clip_rect.xy + vec2( radius.x, radius.x); + vec2 ref_tr = clip_rect.zy + vec2(-radius.y, radius.y); + vec2 ref_br = clip_rect.zw + vec2(-radius.z, -radius.z); + vec2 ref_bl = clip_rect.xw + vec2( radius.w, -radius.w); float d_tl = distance(pos, ref_tl); float d_tr = distance(pos, ref_tr); - float d_bl = distance(pos, ref_bl); float d_br = distance(pos, ref_br); + float d_bl = distance(pos, ref_bl); - bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > radius; - bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > radius; - bool out2 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > radius; - bool out3 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > radius; + bool out0 = pos.x < ref_tl.x && pos.y < ref_tl.y && d_tl > radius.x; + bool out1 = pos.x > ref_tr.x && pos.y < ref_tr.y && d_tr > radius.y; + bool out2 = pos.x > ref_br.x && pos.y > ref_br.y && d_br > radius.z; + bool out3 = pos.x < ref_bl.x && pos.y > ref_bl.y && d_bl > radius.w; // TODO(gw): Alpha anti-aliasing based on edge distance! if (out0 || out1 || out2 || out3) { diff --git a/res/ps_angle_gradient.fs.glsl b/res/ps_angle_gradient.fs.glsl index 700e1be011..944b90979f 100644 --- a/res/ps_angle_gradient.fs.glsl +++ b/res/ps_angle_gradient.fs.glsl @@ -7,7 +7,12 @@ float offset(int index) { } float linearStep(float lo, float hi, float x) { - return clamp((x - lo) / (hi - lo), 0.0, 1.0); + float d = hi - lo; + float v = x - lo; + if (d != 0.0) { + v /= d; + } + return clamp(v, 0.0, 1.0); } void main(void) { diff --git a/res/ps_angle_gradient.vs.glsl b/res/ps_angle_gradient.vs.glsl index 4a1a9ac32b..16296967bd 100644 --- a/res/ps_angle_gradient.vs.glsl +++ b/res/ps_angle_gradient.vs.glsl @@ -21,8 +21,15 @@ void main(void) { vStopCount = int(gradient.stop_count.x); vPos = vi.local_clamped_pos; - vStartPoint = gradient.start_end_point.xy; - vEndPoint = gradient.start_end_point.zw; + + // Snap the start/end points to device pixel units. + // I'm not sure this is entirely correct, but the + // old render path does this, and it is needed to + // make the angle gradient ref tests pass. It might + // be better to fix this higher up in DL construction + // and not snap here? + vStartPoint = floor(0.5 + gradient.start_end_point.xy * uDevicePixelRatio) / uDevicePixelRatio; + vEndPoint = floor(0.5 + gradient.start_end_point.zw * uDevicePixelRatio) / uDevicePixelRatio; for (int i=0 ; i < int(gradient.stop_count.x) ; ++i) { vColors[i] = gradient.colors[i]; diff --git a/res/ps_gradient.fs.glsl b/res/ps_gradient.fs.glsl index 2bf7e8c0a0..b25faec6f5 100644 --- a/res/ps_gradient.fs.glsl +++ b/res/ps_gradient.fs.glsl @@ -3,5 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ void main(void) { + do_clip(vPos, vClipRect, vClipRadius); oFragColor = mix(vColor0, vColor1, vF); } diff --git a/res/ps_gradient.glsl b/res/ps_gradient.glsl index 679b34b648..4b1efa7644 100644 --- a/res/ps_gradient.glsl +++ b/res/ps_gradient.glsl @@ -3,5 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ varying float vF; +varying vec2 vPos; flat varying vec4 vColor0; flat varying vec4 vColor1; +flat varying vec4 vClipRect; +flat varying vec4 vClipRadius; diff --git a/res/ps_gradient.vs.glsl b/res/ps_gradient.vs.glsl index 023f5eea2f..60977165a2 100644 --- a/res/ps_gradient.vs.glsl +++ b/res/ps_gradient.vs.glsl @@ -11,6 +11,7 @@ struct Gradient { vec4 color0; vec4 color1; uvec4 dir; + Clip clip; }; layout(std140) uniform Items { @@ -32,6 +33,13 @@ void main(void) { break; } + vClipRect = vec4(gradient.clip.rect.xy, gradient.clip.rect.xy + gradient.clip.rect.zw); + vClipRadius = vec4(gradient.clip.top_left.outer_inner_radius.x, + gradient.clip.top_right.outer_inner_radius.x, + gradient.clip.bottom_right.outer_inner_radius.x, + gradient.clip.bottom_left.outer_inner_radius.x); + vPos = vi.local_clamped_pos; + vColor0 = gradient.color0; vColor1 = gradient.color1; } diff --git a/res/ps_image.vs.glsl b/res/ps_image.vs.glsl index ce2ef0b69a..0f6bcba6eb 100644 --- a/res/ps_image.vs.glsl +++ b/res/ps_image.vs.glsl @@ -6,7 +6,7 @@ struct Image { PrimitiveInfo info; vec4 st_rect; // Location of the image texture in the texture atlas. - vec2 stretch_size; // Size of the actual image. + vec4 stretch_size; // Size of the actual image. }; layout(std140) uniform Items { diff --git a/res/ps_image_clip.glsl b/res/ps_image_clip.glsl index 25bb29ca2f..4ddd1a5329 100644 --- a/res/ps_image_clip.glsl +++ b/res/ps_image_clip.glsl @@ -7,4 +7,4 @@ varying vec2 vPos; flat varying vec2 vTextureOffset; // Offset of this image into the texture atlas. flat varying vec2 vTextureSize; // Size of the image in the texture atlas. flat varying vec4 vClipRect; -flat varying float vClipRadius; // TODO: Expand to handle irregular radii! +flat varying vec4 vClipRadius; diff --git a/res/ps_image_clip.vs.glsl b/res/ps_image_clip.vs.glsl index 70a57ed6e9..89c6198f99 100644 --- a/res/ps_image_clip.vs.glsl +++ b/res/ps_image_clip.vs.glsl @@ -6,7 +6,7 @@ struct Image { PrimitiveInfo info; vec4 st_rect; // Location of the image texture in the texture atlas. - vec2 stretch_size; // Size of the actual image. + vec4 stretch_size; // Size of the actual image. Clip clip; }; @@ -19,7 +19,10 @@ void main(void) { VertexInfo vi = write_vertex(image.info); vClipRect = vec4(image.clip.rect.xy, image.clip.rect.xy + image.clip.rect.zw); - vClipRadius = image.clip.top_left.outer_inner_radius.x; + vClipRadius = vec4(image.clip.top_left.outer_inner_radius.x, + image.clip.top_right.outer_inner_radius.x, + image.clip.bottom_right.outer_inner_radius.x, + image.clip.bottom_left.outer_inner_radius.x); vPos = vi.local_clamped_pos; // vUv will contain how many times this image has wrapped around the image size. diff --git a/res/ps_image_transform.vs.glsl b/res/ps_image_transform.vs.glsl index 4a82b4bc67..d6d23b27c3 100644 --- a/res/ps_image_transform.vs.glsl +++ b/res/ps_image_transform.vs.glsl @@ -6,6 +6,7 @@ struct Image { PrimitiveInfo info; vec4 st_rect; + vec4 stretch_size; // Size of the actual image. }; layout(std140) uniform Items { diff --git a/res/ps_rectangle_clip.glsl b/res/ps_rectangle_clip.glsl index fcb151e49f..3d50dd162a 100644 --- a/res/ps_rectangle_clip.glsl +++ b/res/ps_rectangle_clip.glsl @@ -7,4 +7,4 @@ varying vec4 vColor; varying vec2 vPos; flat varying vec4 vClipRect; -flat varying float vClipRadius; // TODO: Expand to handle irregular radii! +flat varying vec4 vClipRadius; diff --git a/res/ps_rectangle_clip.vs.glsl b/res/ps_rectangle_clip.vs.glsl index 2b87eee4a9..b181638d01 100644 --- a/res/ps_rectangle_clip.vs.glsl +++ b/res/ps_rectangle_clip.vs.glsl @@ -18,7 +18,10 @@ void main(void) { VertexInfo vi = write_vertex(rect.info); vClipRect = vec4(rect.clip.rect.xy, rect.clip.rect.xy + rect.clip.rect.zw); - vClipRadius = rect.clip.top_left.outer_inner_radius.x; + vClipRadius = vec4(rect.clip.top_left.outer_inner_radius.x, + rect.clip.top_right.outer_inner_radius.x, + rect.clip.bottom_right.outer_inner_radius.x, + rect.clip.bottom_left.outer_inner_radius.x); vPos = vi.local_clamped_pos; vColor = rect.color; From 673a4763b8a2612545b52451388f71232b0726a9 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Thu, 28 Jul 2016 17:03:58 -0700 Subject: [PATCH 28/33] add support for outset and inset box shadows --- res/ps_border.fs.glsl | 40 +++++++++++++++++++++++++++++++--------- res/ps_border.glsl | 6 +++--- res/ps_border.vs.glsl | 8 ++++---- 3 files changed, 38 insertions(+), 16 deletions(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 97e8a8d2bf..e8e91b79cc 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -51,10 +51,8 @@ vec4 draw_dotted_edge() { vec2 finalPosition = positionInTile + destTile; vec4 white = vec4(1.0, 1.0, 1.0, 1.0); - vec3 black = vec3(0.0, 0.0, 0.0); // See if we should draw a circle or not - vec4 circleColor = drawCircle(finalPosition, tileCenter, radius, black); - + vec4 circleColor = drawCircle(finalPosition, tileCenter, radius, vVerticalColor.xyz); return mix(white, circleColor, circleColor.a); } @@ -90,14 +88,10 @@ vec4 draw_dashed_edge(bool is_corner) { vec2 target_rect_index = floor(position / dist_between_dashes); vec2 target_rect_loc = target_rect_index * dist_between_dashes; target_rect_loc += get_dashed_nudge_factor(dash_size, is_corner); - - // TODO correct for center spacing. vec4 target_rect = vec4(target_rect_loc, dash_size); vec4 white = vec4(1.0, 1.0, 1.0, 1.0); - vec3 black = vec3(0.0, 0.0, 0.0); - vec4 target_colored_rect = drawRect(position, target_rect, black); - + vec4 target_colored_rect = drawRect(position, target_rect, vVerticalColor.xyz); return mix(white, target_colored_rect, target_colored_rect.a); } @@ -149,6 +143,28 @@ void draw_dashed_border(void) { } } +void draw_inset_border(void) { + switch (vBorderPart) { + // These are the layer tile part PrimitivePart as uploaded by the tiling.rs + case PST_TOP_LEFT: + case PST_TOP_RIGHT: + case PST_TOP: + case PST_LEFT: + { + oFragColor = vec4(0, 0, 0, 1.0); + break; + } + case PST_BOTTOM_LEFT: + case PST_BOTTOM_RIGHT: + case PST_BOTTOM: + case PST_RIGHT: + { + oFragColor = vec4(1, 0, 0, 1.0); + break; + } + } +} + void main(void) { if (vRadii.x > 0.0 && (distance(vRefPoint, vLocalPos) > vRadii.x || @@ -167,11 +183,17 @@ void main(void) { draw_dotted_border(); break; } + case BORDER_STYLE_OUTSET: + case BORDER_STYLE_INSET: + { + draw_inset_border(); + break; + } case BORDER_STYLE_NONE: case BORDER_STYLE_SOLID: { float color = step(0.0, vF); - oFragColor = mix(vColor1, vColor0, color); + oFragColor = mix(vHorizontalColor, vVerticalColor, color); break; } default: diff --git a/res/ps_border.glsl b/res/ps_border.glsl index 1ea1ba8bb3..26a1a6601e 100644 --- a/res/ps_border.glsl +++ b/res/ps_border.glsl @@ -8,9 +8,9 @@ varying float vF; // This is a weighting as we get closer to the bottom right corner? // These are not changing. -flat varying vec4 vColor0; // The border color -flat varying vec4 vColor1; // The border color -flat varying vec4 vRadii; // The border radius from CSS border-radius +flat varying vec4 vVerticalColor; // The vertical color, e.g. top/bottom +flat varying vec4 vHorizontalColor; // The horizontal color e.g. left/right +flat varying vec4 vRadii; // The border radius from CSS border-radius // These are in device space varying vec2 vLocalPos; // The clamped position in local space. diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index a675866532..99026b74ef 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -5,8 +5,8 @@ struct Border { PrimitiveInfo info; - vec4 color0; - vec4 color1; + vec4 verticalColor; + vec4 horizontalColor; vec4 radii; uvec4 border_style_trbl; }; @@ -97,8 +97,8 @@ void main(void) { vF = (vi.local_clamped_pos.x - x0) * height - (vi.local_clamped_pos.y - y0) * width; // This is what was currently sent. - vColor0 = border.color0; - vColor1 = border.color1; + vVerticalColor = border.verticalColor; + vHorizontalColor = border.horizontalColor; // Local space vLocalPos = vi.local_clamped_pos.xy; From 3442bad0fc09bceb44b284e3ce647843abf87c00 Mon Sep 17 00:00:00 2001 From: Mason Chang Date: Thu, 28 Jul 2016 17:26:39 -0700 Subject: [PATCH 29/33] support inset and outset borders --- res/ps_border.fs.glsl | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index e8e91b79cc..8ba85eaca0 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -143,28 +143,6 @@ void draw_dashed_border(void) { } } -void draw_inset_border(void) { - switch (vBorderPart) { - // These are the layer tile part PrimitivePart as uploaded by the tiling.rs - case PST_TOP_LEFT: - case PST_TOP_RIGHT: - case PST_TOP: - case PST_LEFT: - { - oFragColor = vec4(0, 0, 0, 1.0); - break; - } - case PST_BOTTOM_LEFT: - case PST_BOTTOM_RIGHT: - case PST_BOTTOM: - case PST_RIGHT: - { - oFragColor = vec4(1, 0, 0, 1.0); - break; - } - } -} - void main(void) { if (vRadii.x > 0.0 && (distance(vRefPoint, vLocalPos) > vRadii.x || @@ -186,7 +164,8 @@ void main(void) { case BORDER_STYLE_OUTSET: case BORDER_STYLE_INSET: { - draw_inset_border(); + float color = step(0.0, vF); + oFragColor = mix(vVerticalColor, vHorizontalColor, color); break; } case BORDER_STYLE_NONE: From e5ec9fde6f202e13bfc7af2b67340b120152a3f3 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Sat, 30 Jul 2016 16:38:53 +1000 Subject: [PATCH 30/33] Add explicit type casts, needed for compilation on android / es3 targets. --- res/prim_shared.glsl | 10 +++++----- res/ps_blend.vs.glsl | 8 ++++---- res/ps_border.fs.glsl | 2 +- res/ps_clear.vs.glsl | 4 +++- res/ps_composite.vs.glsl | 12 ++++++------ res/ps_image_transform.vs.glsl | 10 +++++----- res/ps_rectangle_transform.vs.glsl | 10 +++++----- res/shared.glsl | 2 ++ 8 files changed, 31 insertions(+), 27 deletions(-) diff --git a/res/prim_shared.glsl b/res/prim_shared.glsl index bc9774336a..7c21cada7f 100644 --- a/res/prim_shared.glsl +++ b/res/prim_shared.glsl @@ -129,17 +129,17 @@ VertexInfo write_vertex(PrimitiveInfo info) { vec2 device_pos = world_pos.xy * uDevicePixelRatio; vec2 clamped_pos = clamp(device_pos, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); clamped_pos = clamp(clamped_pos, - layer.world_clip_rect.xy, - layer.world_clip_rect.xy + layer.world_clip_rect.zw); + vec2(layer.world_clip_rect.xy), + vec2(layer.world_clip_rect.xy + layer.world_clip_rect.zw)); vec4 local_clamped_pos = layer.inv_transform * vec4(clamped_pos / uDevicePixelRatio, world_pos.z, 1); local_clamped_pos.xyz /= local_clamped_pos.w; - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + vec2 final_pos = clamped_pos + vec2(tile.target_rect.xy) - vec2(tile.actual_rect.xy); gl_Position = uTransform * vec4(final_pos, 0, 1); diff --git a/res/ps_blend.vs.glsl b/res/ps_blend.vs.glsl index c01430d4ce..eb61903b5c 100644 --- a/res/ps_blend.vs.glsl +++ b/res/ps_blend.vs.glsl @@ -16,12 +16,12 @@ layout(std140) uniform Items { void main(void) { Blend blend = blends[gl_InstanceID]; - vec2 local_pos = mix(blend.target_rect.xy, - blend.target_rect.xy + blend.target_rect.zw, + vec2 local_pos = mix(vec2(blend.target_rect.xy), + vec2(blend.target_rect.xy + blend.target_rect.zw), aPosition.xy); - vec2 st0 = blend.src_rect.xy / 2048.0; - vec2 st1 = (blend.src_rect.xy + blend.src_rect.zw) / 2048.0; + vec2 st0 = vec2(blend.src_rect.xy) / 2048.0; + vec2 st1 = vec2(blend.src_rect.xy + blend.src_rect.zw) / 2048.0; vUv = mix(st0, st1, aPosition.xy); vOpacity = blend.opacity.x; diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 8ba85eaca0..042b56f1d0 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -34,7 +34,7 @@ vec4 draw_dotted_edge() { // Break our position into square tiles with circles in them. vec2 circleCount = floor(size / circleSpacing); - circleCount = max(circleCount, 1); + circleCount = max(circleCount, 1.0); vec2 distBetweenCircles = size / circleCount; vec2 circleCenter = distBetweenCircles / 2.0; diff --git a/res/ps_clear.vs.glsl b/res/ps_clear.vs.glsl index 514f6fc716..5d3012fe46 100644 --- a/res/ps_clear.vs.glsl +++ b/res/ps_clear.vs.glsl @@ -1,3 +1,5 @@ +#line 1 + /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -14,7 +16,7 @@ layout(std140) uniform Tiles { void main() { ClearTile tile = tiles[gl_InstanceID]; - vec4 rect = tile.rect; + vec4 rect = vec4(tile.rect); vec4 pos = vec4(mix(rect.xy, rect.xy + rect.zw, aPosition.xy), 0, 1); gl_Position = uTransform * pos; diff --git a/res/ps_composite.vs.glsl b/res/ps_composite.vs.glsl index c1279f3cd4..c7f9cd0553 100644 --- a/res/ps_composite.vs.glsl +++ b/res/ps_composite.vs.glsl @@ -18,16 +18,16 @@ layout(std140) uniform Items { void main(void) { Composite composite = composites[gl_InstanceID]; - vec2 local_pos = mix(composite.target_rect.xy, - composite.target_rect.xy + composite.target_rect.zw, + vec2 local_pos = mix(vec2(composite.target_rect.xy), + vec2(composite.target_rect.xy + composite.target_rect.zw), aPosition.xy); - vec2 st0 = composite.src0.xy / 2048.0; - vec2 st1 = (composite.src0.xy + composite.src0.zw) / 2048.0; + vec2 st0 = vec2(composite.src0.xy) / 2048.0; + vec2 st1 = vec2(composite.src0.xy + composite.src0.zw) / 2048.0; vUv0 = mix(st0, st1, aPosition.xy); - st0 = composite.src1.xy / 2048.0; - st1 = (composite.src1.xy + composite.src1.zw) / 2048.0; + st0 = vec2(composite.src1.xy) / 2048.0; + st1 = vec2(composite.src1.xy + composite.src1.zw) / 2048.0; vUv1 = mix(st0, st1, aPosition.xy); vInfo = composite.info.xy; diff --git a/res/ps_image_transform.vs.glsl b/res/ps_image_transform.vs.glsl index d6d23b27c3..b9fcf7c24c 100644 --- a/res/ps_image_transform.vs.glsl +++ b/res/ps_image_transform.vs.glsl @@ -37,12 +37,12 @@ void main(void) { vec2 max_pos = max(tp0.xy, max(tp1.xy, max(tp2.xy, tp3.xy))); vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); vec2 clamped_pos = mix(min_pos_clamped, max_pos_clamped, @@ -59,7 +59,7 @@ void main(void) { image.st_rect.zw, f); - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + vec2 final_pos = clamped_pos + vec2(tile.target_rect.xy) - vec2(tile.actual_rect.xy); gl_Position = uTransform * vec4(final_pos, 0, 1); } diff --git a/res/ps_rectangle_transform.vs.glsl b/res/ps_rectangle_transform.vs.glsl index 8bd3421366..0df4671049 100644 --- a/res/ps_rectangle_transform.vs.glsl +++ b/res/ps_rectangle_transform.vs.glsl @@ -36,12 +36,12 @@ void main(void) { vec2 max_pos = max(tp0.xy, max(tp1.xy, max(tp2.xy, tp3.xy))); vec2 min_pos_clamped = clamp(min_pos * uDevicePixelRatio, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); vec2 max_pos_clamped = clamp(max_pos * uDevicePixelRatio, - tile.actual_rect.xy, - tile.actual_rect.xy + tile.actual_rect.zw); + vec2(tile.actual_rect.xy), + vec2(tile.actual_rect.xy + tile.actual_rect.zw)); vec2 clamped_pos = mix(min_pos_clamped, max_pos_clamped, @@ -53,7 +53,7 @@ void main(void) { vPos = layer_pos; vColor = rect.color; - vec2 final_pos = clamped_pos + tile.target_rect.xy - tile.actual_rect.xy; + vec2 final_pos = clamped_pos + vec2(tile.target_rect.xy) - vec2(tile.actual_rect.xy); gl_Position = uTransform * vec4(final_pos, 0, 1); } diff --git a/res/shared.glsl b/res/shared.glsl index ccc69e8e0a..4696272d0f 100644 --- a/res/shared.glsl +++ b/res/shared.glsl @@ -20,6 +20,8 @@ // Fragment shader attributes and uniforms //====================================================================================== #ifdef WR_FRAGMENT_SHADER + precision highp float; + #define varying in // Uniform inputs From c9258b7ffde69ab5591a1e71772d129f5a0ba6c8 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 1 Aug 2016 14:44:01 -0700 Subject: [PATCH 31/33] Fix overscroll in WR2. --- src/render_backend.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/render_backend.rs b/src/render_backend.rs index f1ba62b391..e4873a495f 100644 --- a/src/render_backend.rs +++ b/src/render_backend.rs @@ -242,6 +242,7 @@ impl RenderBackend { ApiMsg::TickScrollingBounce => { let frame = profile_counters.total_time.profile(|| { self.frame.tick_scrolling_bounce_animations(); + self.build_scene(); self.render() }); From 13738e7adad16fa2346a1e5ae222ec1930c5c955 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 1 Aug 2016 15:08:02 -0700 Subject: [PATCH 32/33] Fix box shadow alpha --- res/ps_box_shadow.fs.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/ps_box_shadow.fs.glsl b/res/ps_box_shadow.fs.glsl index 3f7d15514c..9c485cba9f 100644 --- a/res/ps_box_shadow.fs.glsl +++ b/res/ps_box_shadow.fs.glsl @@ -147,5 +147,5 @@ void main(void) { float value = color(pos, p0Rect, p1Rect, radii, sigma); value = max(value, 0.0); - oFragColor = vec4(vColor.rgb, vInverted == 1.0 ? 1.0 - value : value); + oFragColor = vColor * vec4(1.0, 1.0, 1.0, vInverted == 1.0 ? 1.0 - value : value); } From 9b552f5154beb15785a4c85bc0c2b2985386df79 Mon Sep 17 00:00:00 2001 From: Glenn Watson Date: Wed, 3 Aug 2016 08:35:41 +1000 Subject: [PATCH 33/33] Address review comments. --- res/ps_angle_gradient.fs.glsl | 2 +- res/ps_border.fs.glsl | 9 +++-- res/ps_border.vs.glsl | 4 +-- res/ps_box_shadow.vs.glsl | 4 +-- res/ps_gradient.vs.glsl | 2 +- res/shared.glsl | 6 ++-- res/shared_other.glsl | 4 +-- src/layer.rs | 15 -------- src/lib.rs | 1 - src/render_backend.rs | 15 +------- src/renderer.rs | 21 +++++------- src/resource_cache.rs | 64 +++++++++++++---------------------- src/resource_list.rs | 33 +----------------- src/texture_cache.rs | 6 ---- src/tiling.rs | 19 +++++++---- src/util.rs | 2 +- 16 files changed, 64 insertions(+), 143 deletions(-) diff --git a/res/ps_angle_gradient.fs.glsl b/res/ps_angle_gradient.fs.glsl index 944b90979f..70f42a1955 100644 --- a/res/ps_angle_gradient.fs.glsl +++ b/res/ps_angle_gradient.fs.glsl @@ -21,7 +21,7 @@ void main(void) { float sa = sin(angle); float ca = cos(angle); - float sx = vStartPoint.x * ca - vStartPoint.y * sa; + float sx = vStartPoint.x * ca - vStartPoint.y * sa; float ex = vEndPoint.x * ca - vEndPoint.y * sa; float d = ex - sx; diff --git a/res/ps_border.fs.glsl b/res/ps_border.fs.glsl index 042b56f1d0..350b8db702 100644 --- a/res/ps_border.fs.glsl +++ b/res/ps_border.fs.glsl @@ -28,7 +28,7 @@ vec4 draw_dotted_edge() { // like firefox. float circleSpacing = diameter * 2.2; - vec2 size = vec2(vBorders.z, vBorders.w); + vec2 size = vBorders.zw; // Get our position within this specific segment vec2 position = vDevicePos - vBorders.xy; @@ -68,15 +68,16 @@ vec2 get_dashed_nudge_factor(vec2 dash_size, bool is_corner) { bool xAxisFudge = vBorders.z > vBorders.w; if (xAxisFudge) { return vec2(dash_size.x / 2.0, 0); - } else { - return vec2(0.0, dash_size.y / 2.0); } + + return vec2(0.0, dash_size.y / 2.0); } vec4 draw_dashed_edge(bool is_corner) { // Everything here should be in device pixels. // We want the dot to be roughly the size of the whole border spacing // 5.5 here isn't a magic number, it's just what mostly looks like FF/Chrome + // TODO: Investigate exactly what FF does. float dash_interval = min(vBorders.w, vBorders.z) * 5.5; vec2 edge_size = vec2(vBorders.z, vBorders.w); vec2 dash_size = vec2(dash_interval / 2.0, dash_interval / 2.0); @@ -143,6 +144,8 @@ void draw_dashed_border(void) { } } +// TODO: Investigate performance of this shader and see +// if it's worthwhile splitting it / removing branches etc. void main(void) { if (vRadii.x > 0.0 && (distance(vRefPoint, vLocalPos) > vRadii.x || diff --git a/res/ps_border.vs.glsl b/res/ps_border.vs.glsl index 99026b74ef..ad34c02737 100644 --- a/res/ps_border.vs.glsl +++ b/res/ps_border.vs.glsl @@ -107,7 +107,5 @@ void main(void) { vDevicePos = vi.global_clamped_pos; // These are in device space - vBorders = vec4(border.info.local_rect.x, border.info.local_rect.y, - border.info.local_rect.z, - border.info.local_rect.w) * uDevicePixelRatio; + vBorders = border.info.local_rect * uDevicePixelRatio; } diff --git a/res/ps_box_shadow.vs.glsl b/res/ps_box_shadow.vs.glsl index cfcdacfa67..9662502e14 100644 --- a/res/ps_box_shadow.vs.glsl +++ b/res/ps_box_shadow.vs.glsl @@ -4,8 +4,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ struct BoxShadow { - PrimitiveInfo info; - vec4 color; + PrimitiveInfo info; + vec4 color; vec4 border_radii_blur_radius_inverted; vec4 bs_rect; vec4 src_rect; diff --git a/res/ps_gradient.vs.glsl b/res/ps_gradient.vs.glsl index 60977165a2..cee41fdf5d 100644 --- a/res/ps_gradient.vs.glsl +++ b/res/ps_gradient.vs.glsl @@ -7,7 +7,7 @@ #define DIR_VERTICAL uint(1) struct Gradient { - PrimitiveInfo info; + PrimitiveInfo info; vec4 color0; vec4 color1; uvec4 dir; diff --git a/res/shared.glsl b/res/shared.glsl index 4696272d0f..2eb73d6b46 100644 --- a/res/shared.glsl +++ b/res/shared.glsl @@ -9,11 +9,11 @@ #define varying out // Uniform inputs - uniform mat4 uTransform; // Orthographic projection - uniform float uDevicePixelRatio; + uniform mat4 uTransform; // Orthographic projection + uniform float uDevicePixelRatio; // Attribute inputs - in vec3 aPosition; + in vec3 aPosition; #endif //====================================================================================== diff --git a/res/shared_other.glsl b/res/shared_other.glsl index 847fd1c143..c6f8286b6f 100644 --- a/res/shared_other.glsl +++ b/res/shared_other.glsl @@ -11,8 +11,8 @@ // box-shadow in vec4 aBorderPosition; - in vec4 aBorderRadii; - in float aBlurRadius; + in vec4 aBorderRadii; + in float aBlurRadius; // blur in vec2 aDestTextureSize; diff --git a/src/layer.rs b/src/layer.rs index 03be6862b0..e749d06045 100644 --- a/src/layer.rs +++ b/src/layer.rs @@ -58,23 +58,8 @@ impl Layer { pub fn finalize(&mut self, scrolling: &ScrollingState) { self.scrolling = *scrolling; - //self.aabb_tree.finalize(); } -/* - pub fn cull(&mut self) { - let viewport_rect = self.viewport_rect; - let adjusted_viewport = viewport_rect.translate(&-self.world_origin) - .translate(&-self.scrolling.offset); - self.aabb_tree.cull(&adjusted_viewport); - } - - #[allow(dead_code)] - pub fn print(&self) { - self.aabb_tree.print(NodeIndex(0), 0); - } -*/ - pub fn overscroll_amount(&self) -> Size2D { let overscroll_x = if self.scrolling.offset.x > 0.0 { -self.scrolling.offset.x diff --git a/src/lib.rs b/src/lib.rs index f97112c33a..b15715ae53 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,6 @@ extern crate app_units; extern crate euclid; extern crate fnv; extern crate gleam; -//extern crate hprof; extern crate ipc_channel; extern crate num_traits; //extern crate notify; diff --git a/src/render_backend.rs b/src/render_backend.rs index e4873a495f..69220b16c3 100644 --- a/src/render_backend.rs +++ b/src/render_backend.rs @@ -14,7 +14,7 @@ use std::collections::HashMap; use std::io::{Cursor, Read}; use std::sync::{Arc, Mutex}; use std::sync::mpsc::Sender; -use texture_cache::{TextureCache, TextureCacheItemId}; +use texture_cache::TextureCache; use webrender_traits::{ApiMsg, AuxiliaryLists, BuiltDisplayList, IdNamespace}; use webrender_traits::{PipelineId, RenderNotifier, WebGLContextId}; use batch::new_id; @@ -50,7 +50,6 @@ impl RenderBackend { payload_tx: IpcBytesSender, result_tx: Sender, device_pixel_ratio: f32, - white_image_id: TextureCacheItemId, texture_cache: TextureCache, enable_aa: bool, notifier: Arc>>>, @@ -61,7 +60,6 @@ impl RenderBackend { let resource_cache = ResourceCache::new(&mut thread_pool, texture_cache, - white_image_id, device_pixel_ratio, enable_aa); @@ -185,9 +183,7 @@ impl RenderBackend { let auxiliary_lists = AuxiliaryLists::from_data(auxiliary_lists_data, auxiliary_lists_descriptor); -// hprof::start_frame(); let frame = profile_counters.total_time.profile(|| { -// let _pf = hprof::enter("root1"); self.scene.set_root_stacking_context(pipeline_id, epoch, stacking_context_id, @@ -199,27 +195,20 @@ impl RenderBackend { self.build_scene(); self.render() }); -// hprof::end_frame(); - //hprof::profiler().print_timing(); self.publish_frame_and_notify_compositor(frame, &mut profile_counters); } ApiMsg::SetRootPipeline(pipeline_id) => { -// hprof::start_frame(); let frame = profile_counters.total_time.profile(|| { -// let _pf = hprof::enter("root2"); self.scene.set_root_pipeline_id(pipeline_id); self.build_scene(); self.render() }); -// hprof::end_frame(); - //hprof::profiler().print_timing(); self.publish_frame(frame, &mut profile_counters); } ApiMsg::Scroll(delta, cursor, move_phase) => { -// hprof::start_frame(); let frame = profile_counters.total_time.profile(|| { if self.frame.scroll(delta, cursor, move_phase) { self.build_scene(); @@ -228,8 +217,6 @@ impl RenderBackend { None } }); -// hprof::end_frame(); - //hprof::profiler().print_timing(); match frame { Some(frame) => { diff --git a/src/renderer.rs b/src/renderer.rs index 715d152158..fc26312d4d 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -451,7 +451,6 @@ impl Renderer { payload_tx_for_backend, result_tx, device_pixel_ratio, - white_image_id, texture_cache, enable_aa, backend_notifier, @@ -1193,37 +1192,35 @@ impl Renderer { let tile_x1 = p1.x; let tile_y1 = p1.y; - //let c = &ColorF::new(1.0, 0.0, 1.0, 1.0); - self.debug.add_line(tile_x0, tile_y0, - c,//&ColorF::new(0.0, 0.0, 0.0, 1.0), + c, tile_x1, tile_y0, - c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + c); self.debug.add_line(tile_x0, tile_y1, - c,//&ColorF::new(0.0, 0.0, 0.0, 1.0), + c, tile_x1, tile_y1, - c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + c); self.debug.add_line(tile_x0, tile_y0, - c,//&ColorF::new(0.0, 0.0, 0.0, 1.0), + c, tile_x0, tile_y1, - c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + c); self.debug.add_line(tile_x1, tile_y0, - c,//&ColorF::new(0.0, 0.0, 0.0, 1.0), + c, tile_x1, tile_y1, - c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + c); if label.len() > 0 { self.debug.add_text((tile_x0.0 as f32 + tile_x1.0 as f32) * 0.5, (tile_y0.0 as f32 + tile_y1.0 as f32) * 0.5, label, - c);//&ColorF::new(0.0, 0.0, 0.0, 1.0)); + c); } } diff --git a/src/resource_cache.rs b/src/resource_cache.rs index c8d43a6465..72e86262f3 100644 --- a/src/resource_cache.rs +++ b/src/resource_cache.rs @@ -129,14 +129,11 @@ pub struct ResourceCache { texture_cache: TextureCache, pending_raster_jobs: Vec, - - //white_image_id: TextureCacheItemId, } impl ResourceCache { pub fn new(thread_pool: &mut scoped_threadpool::Pool, texture_cache: TextureCache, - _white_image_id: TextureCacheItemId, device_pixel_ratio: f32, enable_aa: bool) -> ResourceCache { @@ -303,11 +300,9 @@ impl ResourceCache { } pub fn raster_pending_glyphs(&mut self, - //thread_pool: &mut scoped_threadpool::Pool, frame_id: FrameId) { // Run raster jobs in parallel - run_raster_jobs(//thread_pool, - &mut self.pending_raster_jobs, + run_raster_jobs(&mut self.pending_raster_jobs, &self.font_templates, self.device_pixel_ratio, self.enable_aa); @@ -386,14 +381,6 @@ impl ResourceCache { self.texture_cache.get(image_info.texture_cache_id) } -/* - #[inline] - pub fn get_raster(&self, raster_item: &RasterItem, frame_id: FrameId) -> &TextureCacheItem { - let image_id = self.cached_rasters.get(raster_item, frame_id); - self.texture_cache.get(*image_id) - } -*/ - #[inline] pub fn get_webgl_texture(&self, context_id: &WebGLContextId) -> TextureId { self.webgl_textures.get(context_id).unwrap().clone() @@ -406,8 +393,7 @@ impl ResourceCache { } } -fn run_raster_jobs(//thread_pool: &mut scoped_threadpool::Pool, - pending_raster_jobs: &mut Vec, +fn run_raster_jobs(pending_raster_jobs: &mut Vec, font_templates: &HashMap>, device_pixel_ratio: f32, enable_aa: bool) { @@ -415,31 +401,27 @@ fn run_raster_jobs(//thread_pool: &mut scoped_threadpool::Pool, return } - // Run raster jobs in parallel - //thread_pool.scoped(|scope| { - for job in pending_raster_jobs { - //scope.execute(|| { - let font_template = &font_templates[&job.glyph_key.font_key]; - FONT_CONTEXT.with(move |font_context| { - let mut font_context = font_context.borrow_mut(); - match *font_template { - FontTemplate::Raw(ref bytes) => { - font_context.add_raw_font(&job.glyph_key.font_key, &**bytes); - } - FontTemplate::Native(ref native_font_handle) => { - font_context.add_native_font(&job.glyph_key.font_key, - (*native_font_handle).clone()); - } - } - job.result = font_context.get_glyph(job.glyph_key.font_key, - job.glyph_key.size, - job.glyph_key.index, - device_pixel_ratio, - enable_aa); - }); - //}); - } - //}); + // TODO(gw): Run raster jobs in parallel again + for job in pending_raster_jobs { + let font_template = &font_templates[&job.glyph_key.font_key]; + FONT_CONTEXT.with(move |font_context| { + let mut font_context = font_context.borrow_mut(); + match *font_template { + FontTemplate::Raw(ref bytes) => { + font_context.add_raw_font(&job.glyph_key.font_key, &**bytes); + } + FontTemplate::Native(ref native_font_handle) => { + font_context.add_native_font(&job.glyph_key.font_key, + (*native_font_handle).clone()); + } + } + job.result = font_context.get_glyph(job.glyph_key.font_key, + job.glyph_key.size, + job.glyph_key.index, + device_pixel_ratio, + enable_aa); + }); + } } pub trait Resource { diff --git a/src/resource_list.rs b/src/resource_list.rs index b04114a668..3af6906392 100644 --- a/src/resource_list.rs +++ b/src/resource_list.rs @@ -17,16 +17,14 @@ pub struct ResourceList { required_images: RequiredImageSet, required_glyphs: RequiredGlyphMap, required_rasters: RequiredRasterSet, - _device_pixel_ratio: f32, } impl ResourceList { - pub fn new(device_pixel_ratio: f32) -> ResourceList { + pub fn new() -> ResourceList { ResourceList { required_glyphs: HashMap::with_hasher(Default::default()), required_images: HashSet::with_hasher(Default::default()), required_rasters: HashSet::with_hasher(Default::default()), - _device_pixel_ratio: device_pixel_ratio, } } @@ -42,35 +40,6 @@ impl ResourceList { .insert(glyph); } -/* - pub fn add_box_shadow_corner(&mut self, - blur_radius: f32, - border_radius: f32, - box_rect: &Rect, - inverted: bool) { - if let Some(raster_item) = BoxShadowRasterOp::create_corner(blur_radius, - border_radius, - box_rect, - inverted, - self.device_pixel_ratio) { - self.required_rasters.insert(RasterItem::BoxShadow(raster_item)); - } - } - - pub fn add_box_shadow_edge(&mut self, - blur_radius: f32, - border_radius: f32, - box_rect: &Rect, - inverted: bool) { - if let Some(raster_item) = BoxShadowRasterOp::create_edge(blur_radius, - border_radius, - box_rect, - inverted, - self.device_pixel_ratio) { - self.required_rasters.insert(RasterItem::BoxShadow(raster_item)); - } - }*/ - pub fn for_each_image(&self, mut f: F) where F: FnMut(ImageKey, ImageRendering) { for &(image_id, image_rendering) in &self.required_images { f(image_id, image_rendering); diff --git a/src/texture_cache.rs b/src/texture_cache.rs index 696930c43f..c1411e495e 100644 --- a/src/texture_cache.rs +++ b/src/texture_cache.rs @@ -103,12 +103,6 @@ impl TexturePage { page } -/* - pub fn size(&self) -> u32 { - self.texture_size - } -*/ - pub fn texture_id(&self) -> TextureId { self.texture_id } diff --git a/src/tiling.rs b/src/tiling.rs index bb2df3445c..e046abd8d1 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -25,6 +25,16 @@ use webrender_traits::{ColorF, FontKey, ImageKey, ImageRendering, ComplexClipReg use webrender_traits::{BorderDisplayItem, BorderStyle, ItemRange, AuxiliaryLists, BorderRadius, BorderSide}; use webrender_traits::{BoxShadowClipMode, PipelineId, ScrollLayerId, WebGLContextId}; +pub static SCREEN_MIN: Point2D = Point2D { + x: 10000000.0, + y: 10000000.0, +}; + +pub static SCREEN_MAX: Point2D = Point2D { + x: -10000000.0, + y: -10000000.0, +}; + #[repr(u32)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum GradientType { @@ -399,8 +409,6 @@ impl AlphaRenderTask { #[derive(Debug)] enum RenderTaskKind { Alpha(AlphaRenderTask), - //AlphaBatch(ScreenTileLayer), - //Composite(CompositeTileInfo), } #[derive(Debug)] @@ -594,8 +602,8 @@ impl TransformedRect { 1.0)), ]; - let mut screen_min: Point2D = Point2D::new( 10000000.0, 10000000.0); - let mut screen_max: Point2D = Point2D::new(-10000000.0, -10000000.0); + let mut screen_min: Point2D = SCREEN_MIN; + let mut screen_max: Point2D = SCREEN_MAX; for vertex in &vertices { let inv_w = 1.0 / vertex.w; @@ -2517,7 +2525,6 @@ impl FrameBuilder { // assigned to tiles where their containing layer intersects with. // Does this cause any problems / demonstrate other bugs? // Restrict the tiles by clamping to the layer tile indices... - //debug_assert!(rect_contains_rect(l_rect, p_rect), format!("layer={:?} prim={:?}", l_rect, p_rect)); let p_tile_x0 = p_rect.origin.x.0 / SCREEN_TILE_SIZE; let p_tile_y0 = p_rect.origin.y.0 / SCREEN_TILE_SIZE; @@ -2556,7 +2563,7 @@ impl FrameBuilder { resource_cache: &mut ResourceCache, frame_id: FrameId, pipeline_auxiliary_lists: &HashMap>) { - let mut resource_list = ResourceList::new(self.device_pixel_ratio); + let mut resource_list = ResourceList::new(); // Non-visible layers have been marked invalid by now for layer in &self.layer_store { diff --git a/src/util.rs b/src/util.rs index 661b554356..729aa6c5db 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use euclid::{Matrix4D, Point2D, Point4D, Rect, Size2D}; -use internal_types::{DevicePixel}; +use internal_types::DevicePixel; use num_traits::Zero; use time::precise_time_ns;