From 41083ad982b820d77fa70b9bc9993d866b969677 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Fri, 13 Apr 2018 15:32:52 +0200 Subject: [PATCH 1/8] Simplify repeated primitive parameters when possible. --- webrender/src/display_list_flattener.rs | 41 ++++++++++++++++--------- webrender/src/image.rs | 22 +++++++++++++ 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index e669cd75e6..bcbafec92e 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -22,7 +22,7 @@ use euclid::{SideOffsets2D, vec2}; use frame_builder::{FrameBuilder, FrameBuilderConfig}; use glyph_rasterizer::FontInstance; use hit_test::{HitTestingItem, HitTestingRun}; -use image::{decompose_image, TiledImageInfo}; +use image::{decompose_image, TiledImageInfo, simplify_repeated_primitive}; use internal_types::{FastHashMap, FastHashSet}; use picture::PictureCompositeMode; use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient}; @@ -1892,11 +1892,18 @@ impl<'a> DisplayListFlattener<'a> { stops_count: usize, extend_mode: ExtendMode, stretch_size: LayoutSize, - tile_spacing: LayoutSize, + mut tile_spacing: LayoutSize, ) { let gradient_index = CachedGradientIndex(self.cached_gradients.len()); self.cached_gradients.push(CachedGradient::new()); + let mut prim_rect = info.rect; + simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); + let info = LayoutPrimitiveInfo { + rect: prim_rect, + .. *info + }; + if tile_spacing != LayoutSize::zero() { let prim_infos = info.decompose( stretch_size, @@ -1925,7 +1932,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_gradient_impl( clip_and_scroll, - info, + &info, start_point, end_point, stops, @@ -1982,11 +1989,18 @@ impl<'a> DisplayListFlattener<'a> { stops: ItemRange, extend_mode: ExtendMode, stretch_size: LayoutSize, - tile_spacing: LayoutSize, + mut tile_spacing: LayoutSize, ) { let gradient_index = CachedGradientIndex(self.cached_gradients.len()); self.cached_gradients.push(CachedGradient::new()); + let mut prim_rect = info.rect; + simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); + let info = LayoutPrimitiveInfo { + rect: prim_rect, + .. *info + }; + if tile_spacing != LayoutSize::zero() { let prim_infos = info.decompose( stretch_size, @@ -2016,7 +2030,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_radial_gradient_impl( clip_and_scroll, - info, + &info, center, start_radius, end_radius, @@ -2123,13 +2137,12 @@ impl<'a> DisplayListFlattener<'a> { alpha_type: AlphaType, tile_offset: Option, ) { - // If the tile spacing is the same as the rect size, - // then it is effectively zero. We use this later on - // in prim_store to detect if an image can be considered - // opaque. - if tile_spacing == info.rect.size { - tile_spacing = LayoutSize::zero(); - } + let mut prim_rect = info.rect; + simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); + let info = LayoutPrimitiveInfo { + rect: prim_rect, + .. *info + }; let request = ImageRequest { key: image_key, @@ -2170,7 +2183,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_primitive( clip_and_scroll, - info, + &info, Vec::new(), PrimitiveContainer::Brush(prim), ); @@ -2189,7 +2202,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_primitive( clip_and_scroll, - info, + &info, Vec::new(), PrimitiveContainer::Image(prim_cpu), ); diff --git a/webrender/src/image.rs b/webrender/src/image.rs index 4ada110452..dcf54877da 100644 --- a/webrender/src/image.rs +++ b/webrender/src/image.rs @@ -5,6 +5,28 @@ use api::{TileOffset, LayoutRect, LayoutSize, LayoutVector2D, DeviceUintSize}; use euclid::rect; +/// If repetitions are far enough apart that only one is within +/// the primitive rect, then we can simplify the parameters and +/// treat the primitive as not repeated. +/// This can let us avoid unnecessary work later to handle some +/// of the parameters. +pub fn simplify_repeated_primitive( + stretch_size: &LayoutSize, + tile_spacing: &mut LayoutSize, + prim_rect: &mut LayoutRect, +) { + let stride = *stretch_size + *tile_spacing; + + if stride.width >= prim_rect.size.width { + tile_spacing.width = 0.0; + prim_rect.size.width = f32::min(prim_rect.size.width, stretch_size.width); + } + if stride.height >= prim_rect.size.height { + tile_spacing.height = 0.0; + prim_rect.size.height = f32::min(prim_rect.size.height, stretch_size.height); + } +} + pub struct DecomposedTile { pub rect: LayoutRect, pub stretch_size: LayoutSize, From bdce7955fe06a27890ec2b88172847a5b9a06f08 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Mon, 16 Apr 2018 14:49:24 +0200 Subject: [PATCH 2/8] Bake repeated image spacing using a render task. --- webrender/src/device.rs | 4 +- webrender/src/display_list_flattener.rs | 3 +- webrender/src/prim_store.rs | 53 +++++++++++++++++++++---- webrender/src/renderer.rs | 3 +- 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/webrender/src/device.rs b/webrender/src/device.rs index 8bfcde406e..a49bf76ef7 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -1250,8 +1250,8 @@ impl Device { src_rect.origin.y + src_rect.size.height, dest_rect.origin.x, dest_rect.origin.y, - dest_rect.origin.x + dest_rect.size.width, - dest_rect.origin.y + dest_rect.size.height, + dest_rect.origin.x + src_rect.size.width, + dest_rect.origin.y + src_rect.size.height, gl::COLOR_BUFFER_BIT, gl::LINEAR, ); diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index bcbafec92e..da064b6eaa 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -2165,8 +2165,7 @@ impl<'a> DisplayListFlattener<'a> { // See if conditions are met to run through the new // image brush shader, which supports segments. - if tile_spacing == LayoutSize::zero() && - tile_offset.is_none() { + if tile_offset.is_none() { let prim = BrushPrimitive::new( BrushKind::Image { request, diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 6213cc5184..3e275b2e29 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -430,10 +430,15 @@ impl BrushPrimitive { } // Images are drawn as a white color, modulated by the total // opacity coming from any collapsed property bindings. - BrushKind::Image { stretch_size, ref opacity_binding, .. } => { + BrushKind::Image { stretch_size, tile_spacing, ref opacity_binding, .. } => { request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied()); request.push(PremultipliedColorF::WHITE); - request.push([stretch_size.width, stretch_size.height, 0.0, 0.0]); + request.push([ + stretch_size.width + tile_spacing.width, + stretch_size.height + tile_spacing.height, + 0.0, + 0.0, + ]); } // Solid rects also support opacity collapsing. BrushKind::Solid { color, ref opacity_binding, .. } => { @@ -1519,7 +1524,16 @@ impl PrimitiveStore { let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0]; match brush.kind { - BrushKind::Image { request, sub_rect, ref mut current_epoch, ref mut source, ref mut opacity_binding, .. } => { + BrushKind::Image { + request, + sub_rect, + stretch_size, + ref mut tile_spacing, + ref mut current_epoch, + ref mut source, + ref mut opacity_binding, + .. + } => { let image_properties = frame_state .resource_cache .get_image_properties(request.key); @@ -1540,6 +1554,17 @@ impl PrimitiveStore { image_properties.descriptor.is_opaque && opacity_binding.current == 1.0; + if *tile_spacing != LayoutSize::zero() { + *source = ImageSource::Cache { + // Size in device-pixels we need to allocate in render task cache. + size: DeviceIntSize::new( + image_properties.descriptor.width as i32, + image_properties.descriptor.height as i32 + ), + handle: None, + }; + } + // Work out whether this image is a normal / simple type, or if // we need to pre-render it to the render task cache. if let Some(rect) = sub_rect { @@ -1557,7 +1582,21 @@ impl PrimitiveStore { // time through, and any time the render task output has been // evicted from the texture cache. match *source { - ImageSource::Cache { size, ref mut handle } => { + ImageSource::Cache { ref mut size, ref mut handle } => { + let padding_x = (tile_spacing.width * size.width as f32 / + stretch_size.width) as i32; + let padding_y = (tile_spacing.height * size.height as f32 / + stretch_size.height) as i32; + + if padding_x > 0 { + metadata.opacity.is_opaque = false; + size.width += padding_x; + } + if padding_y > 0 { + metadata.opacity.is_opaque = false; + size.height += padding_y; + } + let image_cache_key = ImageCacheKey { request, texel_rect: sub_rect, @@ -1566,7 +1605,7 @@ impl PrimitiveStore { // Request a pre-rendered image task. *handle = Some(frame_state.resource_cache.request_render_task( RenderTaskCacheKey { - size, + size: *size, kind: RenderTaskCacheKeyKind::Image(image_cache_key), }, frame_state.gpu_cache, @@ -1582,7 +1621,7 @@ impl PrimitiveStore { // a normal transient render task surface. This will // copy only the sub-rect, if specified. let cache_to_target_task = RenderTask::new_blit( - size, + *size, BlitSource::Image { key: image_cache_key }, ); let cache_to_target_task_id = render_tasks.add(cache_to_target_task); @@ -1591,7 +1630,7 @@ impl PrimitiveStore { // task above back into the right spot in the persistent // render target cache. let target_to_cache_task = RenderTask::new_blit( - size, + *size, BlitSource::RenderTask { task_id: cache_to_target_task_id, }, diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index c7066108dc..8940e0b5ae 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -2696,7 +2696,8 @@ impl Renderer { source_rect } }; - debug_assert_eq!(source_rect.size, blit.target_rect.size); + debug_assert!(source_rect.size.width <= blit.target_rect.size.width); + debug_assert!(source_rect.size.height <= blit.target_rect.size.height); self.device.blit_render_target( source_rect, blit.target_rect, From 6fe8e93fc1045fcbd5f4246d53e2d80247826208 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Fri, 27 Apr 2018 17:26:37 +0200 Subject: [PATCH 3/8] Support padding in blit render tasks. --- webrender/src/device.rs | 4 ++-- webrender/src/prim_store.rs | 30 ++++++++++++++++-------------- webrender/src/render_task.rs | 15 ++++++++++++++- webrender/src/renderer.rs | 3 +-- webrender/src/tiling.rs | 4 ++-- webrender_api/src/units.rs | 3 ++- 6 files changed, 37 insertions(+), 22 deletions(-) diff --git a/webrender/src/device.rs b/webrender/src/device.rs index a49bf76ef7..8bfcde406e 100644 --- a/webrender/src/device.rs +++ b/webrender/src/device.rs @@ -1250,8 +1250,8 @@ impl Device { src_rect.origin.y + src_rect.size.height, dest_rect.origin.x, dest_rect.origin.y, - dest_rect.origin.x + src_rect.size.width, - dest_rect.origin.y + src_rect.size.height, + dest_rect.origin.x + dest_rect.size.width, + dest_rect.origin.y + dest_rect.size.height, gl::COLOR_BUFFER_BIT, gl::LINEAR, ); diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 3e275b2e29..b4577ff399 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -6,7 +6,7 @@ use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode}; use api::{FilterOp, GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag}; use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D}; -use api::{PipelineId, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat}; +use api::{PipelineId, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat, DeviceIntSideOffsets}; use border::{BorderCornerInstance, BorderEdgeKind}; use box_shadow::BLUR_SAMPLE_SCALE; use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId}; @@ -1583,18 +1583,19 @@ impl PrimitiveStore { // evicted from the texture cache. match *source { ImageSource::Cache { ref mut size, ref mut handle } => { - let padding_x = (tile_spacing.width * size.width as f32 / - stretch_size.width) as i32; - let padding_y = (tile_spacing.height * size.height as f32 / - stretch_size.height) as i32; + let padding = DeviceIntSideOffsets::new( + 0, + (tile_spacing.width * size.width as f32 / stretch_size.width) as i32, + (tile_spacing.height * size.height as f32 / stretch_size.height) as i32, + 0, + ); - if padding_x > 0 { - metadata.opacity.is_opaque = false; - size.width += padding_x; - } - if padding_y > 0 { + let inner_size = *size; + size.width += padding.horizontal(); + size.height += padding.vertical(); + + if padding != DeviceIntSideOffsets::zero() { metadata.opacity.is_opaque = false; - size.height += padding_y; } let image_cache_key = ImageCacheKey { @@ -1621,7 +1622,7 @@ impl PrimitiveStore { // a normal transient render task surface. This will // copy only the sub-rect, if specified. let cache_to_target_task = RenderTask::new_blit( - *size, + inner_size, BlitSource::Image { key: image_cache_key }, ); let cache_to_target_task_id = render_tasks.add(cache_to_target_task); @@ -1629,8 +1630,9 @@ impl PrimitiveStore { // Create a task to blit the rect from the child render // task above back into the right spot in the persistent // render target cache. - let target_to_cache_task = RenderTask::new_blit( - *size, + let target_to_cache_task = RenderTask::new_blit_with_padding( + inner_size, + &padding, BlitSource::RenderTask { task_id: cache_to_target_task_id, }, diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index da8eb19bfa..58228c5a87 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceSize, ImageDescriptor, ImageFormat}; +use api::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceSize, DeviceIntSideOffsets, ImageDescriptor, ImageFormat}; #[cfg(feature = "pathfinder")] use api::FontRenderMode; use box_shadow::{BoxShadowCacheKey}; @@ -254,6 +254,7 @@ pub enum BlitSource { #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct BlitTask { pub source: BlitSource, + pub padding: DeviceIntSideOffsets, } #[derive(Debug)] @@ -337,6 +338,14 @@ impl RenderTask { pub fn new_blit( size: DeviceIntSize, source: BlitSource, + ) -> Self { + RenderTask::new_blit_with_padding(size, &DeviceIntSideOffsets::zero(), source) + } + + pub fn new_blit_with_padding( + mut size: DeviceIntSize, + padding: &DeviceIntSideOffsets, + source: BlitSource, ) -> Self { let mut children = Vec::new(); @@ -349,11 +358,15 @@ impl RenderTask { children.push(task_id); } + size.width += padding.horizontal(); + size.height += padding.vertical(); + RenderTask { children, location: RenderTaskLocation::Dynamic(None, Some(size)), kind: RenderTaskKind::Blit(BlitTask { source, + padding: *padding, }), clear_mode: ClearMode::Transparent, saved_index: None, diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 8940e0b5ae..c7066108dc 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -2696,8 +2696,7 @@ impl Renderer { source_rect } }; - debug_assert!(source_rect.size.width <= blit.target_rect.size.width); - debug_assert!(source_rect.size.height <= blit.target_rect.size.height); + debug_assert_eq!(source_rect.size, blit.target_rect.size); self.device.blit_render_target( source_rect, blit.target_rect, diff --git a/webrender/src/tiling.rs b/webrender/src/tiling.rs index ebaf5721b8..a154961e33 100644 --- a/webrender/src/tiling.rs +++ b/webrender/src/tiling.rs @@ -484,7 +484,7 @@ impl RenderTarget for ColorRenderTarget { cache_item.texture_layer, source_rect, ), - target_rect, + target_rect: target_rect.inner_rect(task_info.padding) }); } BlitSource::RenderTask { .. } => { @@ -673,7 +673,7 @@ impl TextureCacheRenderTarget { // task to this target. self.blits.push(BlitJob { source: BlitJobSource::RenderTask(task_id), - target_rect: target_rect.0, + target_rect: target_rect.0.inner_rect(task_info.padding), }); } } diff --git a/webrender_api/src/units.rs b/webrender_api/src/units.rs index 7e4916a306..a1946f4a6c 100644 --- a/webrender_api/src/units.rs +++ b/webrender_api/src/units.rs @@ -14,7 +14,7 @@ use app_units::Au; use euclid::{Length, TypedRect, TypedScale, TypedSize2D, TypedTransform3D}; -use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D}; +use euclid::{TypedPoint2D, TypedPoint3D, TypedVector2D, TypedVector3D, TypedSideOffsets2D}; /// Geometry in the coordinate system of the render target (screen or intermediate /// surface) in physical pixels. @@ -25,6 +25,7 @@ pub type DeviceIntRect = TypedRect; pub type DeviceIntPoint = TypedPoint2D; pub type DeviceIntSize = TypedSize2D; pub type DeviceIntLength = Length; +pub type DeviceIntSideOffsets = TypedSideOffsets2D; pub type DeviceUintRect = TypedRect; pub type DeviceUintPoint = TypedPoint2D; From 421fd07a8ad7c9bab56c4e316e7b3c75171701a0 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Mon, 30 Apr 2018 17:48:53 +0200 Subject: [PATCH 4/8] Bake tile spacing in the first blit to avoid artifacts. It would seem more efficient to apply tile spacing in the second blit and avoid the memory overhead of baking the tile spacing in the first render task, but clearing seems to be handled differently on the two blits (absent in the second). --- webrender/src/prim_store.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index b4577ff399..e868ff6b18 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -1621,8 +1621,9 @@ impl PrimitiveStore { // Create a task to blit from the texture cache to // a normal transient render task surface. This will // copy only the sub-rect, if specified. - let cache_to_target_task = RenderTask::new_blit( + let cache_to_target_task = RenderTask::new_blit_with_padding( inner_size, + &padding, BlitSource::Image { key: image_cache_key }, ); let cache_to_target_task_id = render_tasks.add(cache_to_target_task); @@ -1630,9 +1631,8 @@ impl PrimitiveStore { // Create a task to blit the rect from the child render // task above back into the right spot in the persistent // render target cache. - let target_to_cache_task = RenderTask::new_blit_with_padding( - inner_size, - &padding, + let target_to_cache_task = RenderTask::new_blit( + *size, BlitSource::RenderTask { task_id: cache_to_target_task_id, }, From 48648d44704f72830627b17ba56e8f30f59767d7 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 18 Apr 2018 13:52:31 +0200 Subject: [PATCH 6/8] Decompose tiled images during frame building. --- webrender/src/batch.rs | 117 +++++++++++++- webrender/src/display_list_flattener.rs | 125 ++++---------- webrender/src/image.rs | 206 +++++++++++++++++++++++- webrender/src/prim_store.rs | 129 ++++++++++++++- webrender/src/resource_cache.rs | 10 ++ 5 files changed, 487 insertions(+), 100 deletions(-) diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 936e47a99f..ff88eb3f89 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -608,7 +608,26 @@ impl AlphaBatchBuilder { screen_rect.unclipped.size, ); - let prim_cache_address = gpu_cache.get_address(&prim_metadata.gpu_location); + // If the primitive is internally decomposed into multiple sub-primitives we may not + // use some of the per-primitive data typically stored in PrimitiveMetadata and get + // it from each sub-primitive instead. + let is_multiple_primitives = match prim_metadata.prim_kind { + PrimitiveKind::Brush => { + let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0]; + match brush.kind { + BrushKind::Image { ref visible_tiles, .. } => !visible_tiles.is_empty(), + _ => false, + } + } + _ => false, + }; + + let prim_cache_address = if is_multiple_primitives { + GpuCacheAddress::invalid() + } else { + gpu_cache.get_address(&prim_metadata.gpu_location) + }; + let no_textures = BatchTextures::no_texture(); let clip_task_address = prim_metadata .clip_task_id @@ -974,6 +993,32 @@ impl AlphaBatchBuilder { ); } } + BrushKind::Image { request, ref visible_tiles, .. } if !visible_tiles.is_empty() => { + for tile in visible_tiles { + if let Some((batch_kind, textures, user_data)) = get_image_tile_params( + ctx.resource_cache, + gpu_cache, + deferred_resolves, + request.with_tile(tile.tile_offset), + ) { + let prim_cache_address = gpu_cache.get_address(&tile.handle); + self.add_image_tile_to_batch( + batch_kind, + specified_blend_mode, + textures, + clip_chain_rect_index, + clip_task_address, + &task_relative_bounding_rect, + prim_cache_address, + scroll_id, + task_address, + z, + user_data, + tile.edge_flags + ); + } + } + } _ => { if let Some((batch_kind, textures, user_data)) = brush.get_batch_params( ctx.resource_cache, @@ -1210,6 +1255,45 @@ impl AlphaBatchBuilder { } } + fn add_image_tile_to_batch( + &mut self, + batch_kind: BrushBatchKind, + blend_mode: BlendMode, + textures: BatchTextures, + clip_chain_rect_index: ClipChainRectIndex, + clip_task_address: RenderTaskAddress, + task_relative_bounding_rect: &DeviceIntRect, + prim_cache_address: GpuCacheAddress, + scroll_id: ClipScrollNodeIndex, + task_address: RenderTaskAddress, + z: ZBufferId, + user_data: [i32; 3], + edge_flags: EdgeAaSegmentMask, + ) { + let base_instance = BrushInstance { + picture_address: task_address, + prim_address: prim_cache_address, + clip_chain_rect_index, + scroll_id, + clip_task_address, + z, + segment_index: 0, + edge_flags, + brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION, + user_data, + }; + + self.batch_list.add_bounding_rect(task_relative_bounding_rect); + + let batch_key = BatchKey { + blend_mode, + kind: BatchKind::Brush(batch_kind), + textures, + }; + let batch = self.batch_list.get_suitable_batch(batch_key, task_relative_bounding_rect); + batch.push(PrimitiveInstance::from(base_instance)); + } + fn add_brush_to_batch( &mut self, brush: &BrushPrimitive, @@ -1308,6 +1392,37 @@ impl AlphaBatchBuilder { } } +fn get_image_tile_params( + resource_cache: &ResourceCache, + gpu_cache: &mut GpuCache, + deferred_resolves: &mut Vec, + request: ImageRequest, +) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> { + + let cache_item = resolve_image( + request, + resource_cache, + gpu_cache, + deferred_resolves, + ); + + if cache_item.texture_id == SourceTexture::Invalid { + None + } else { + let textures = BatchTextures::color(cache_item.texture_id); + Some(( + BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), + textures, + [ + cache_item.uv_rect_handle.as_int(gpu_cache), + (ShaderColorMode::ColorBitmap as i32) << 16 | + RasterizationSpace::Local as i32, + 0, + ], + )) + } +} + impl BrushPrimitive { pub fn get_picture_index(&self) -> PictureIndex { match self.kind { diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index da064b6eaa..cfd4004bde 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -11,7 +11,7 @@ use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, LayoutPoint, L use api::{LayoutRect, LayoutVector2D, LayoutSize, LayoutTransform}; use api::{LineOrientation, LineStyle, LocalClip, PipelineId, PropertyBinding}; use api::{RepeatMode, ScrollFrameDisplayItem, ScrollPolicy, ScrollSensitivity, Shadow}; -use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect, TileOffset}; +use api::{SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect}; use api::{TransformStyle, YuvColorSpace, YuvData}; use app_units::Au; use border::ImageBorderSegment; @@ -22,11 +22,11 @@ use euclid::{SideOffsets2D, vec2}; use frame_builder::{FrameBuilder, FrameBuilderConfig}; use glyph_rasterizer::FontInstance; use hit_test::{HitTestingItem, HitTestingRun}; -use image::{decompose_image, TiledImageInfo, simplify_repeated_primitive}; +use image::simplify_repeated_primitive; use internal_types::{FastHashMap, FastHashSet}; use picture::PictureCompositeMode; use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, CachedGradient}; -use prim_store::{CachedGradientIndex, ImageCacheKey, ImagePrimitiveCpu, ImageSource}; +use prim_store::{CachedGradientIndex, ImageSource}; use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore}; use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitiveCpu}; use render_backend::{DocumentView}; @@ -635,49 +635,16 @@ impl<'a> DisplayListFlattener<'a> { let prim_info = item.get_layout_primitive_info(&reference_frame_relative_offset); match *item.item() { SpecificDisplayItem::Image(ref info) => { - match self.tiled_image_map.get(&info.image_key).cloned() { - Some(tiling) => { - // The image resource is tiled. We have to generate an image primitive - // for each tile. - decompose_image( - &TiledImageInfo { - rect: prim_info.rect, - tile_spacing: info.tile_spacing, - stretch_size: info.stretch_size, - device_image_size: tiling.image_size, - device_tile_size: tiling.tile_size as u32, - }, - &mut|tile| { - let mut prim_info = prim_info.clone(); - prim_info.rect = tile.rect; - self.add_image( - clip_and_scroll, - &prim_info, - tile.stretch_size, - info.tile_spacing, - None, - info.image_key, - info.image_rendering, - info.alpha_type, - Some(tile.tile_offset), - ); - } - ); - } - None => { - self.add_image( - clip_and_scroll, - &prim_info, - info.stretch_size, - info.tile_spacing, - None, - info.image_key, - info.image_rendering, - info.alpha_type, - None, - ); - } - } + self.add_image( + clip_and_scroll, + &prim_info, + info.stretch_size, + info.tile_spacing, + None, + info.image_key, + info.image_rendering, + info.alpha_type, + ); } SpecificDisplayItem::YuvImage(ref info) => { self.add_yuv_image( @@ -1786,7 +1753,6 @@ impl<'a> DisplayListFlattener<'a> { border.image_key, ImageRendering::Auto, AlphaType::PremultipliedAlpha, - None, ); } } @@ -2135,7 +2101,6 @@ impl<'a> DisplayListFlattener<'a> { image_key: ImageKey, image_rendering: ImageRendering, alpha_type: AlphaType, - tile_offset: Option, ) { let mut prim_rect = info.rect; simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); @@ -2144,12 +2109,6 @@ impl<'a> DisplayListFlattener<'a> { .. *info }; - let request = ImageRequest { - key: image_key, - rendering: image_rendering, - tile: tile_offset, - }; - let sub_rect = sub_rect.map(|texel_rect| { DeviceIntRect::new( DeviceIntPoint::new( @@ -2163,49 +2122,31 @@ impl<'a> DisplayListFlattener<'a> { ) }); - // See if conditions are met to run through the new - // image brush shader, which supports segments. - if tile_offset.is_none() { - let prim = BrushPrimitive::new( - BrushKind::Image { - request, - current_epoch: Epoch::invalid(), - alpha_type, - stretch_size, - tile_spacing, - source: ImageSource::Default, - sub_rect, - opacity_binding: OpacityBinding::new(), + let prim = BrushPrimitive::new( + BrushKind::Image { + request: ImageRequest { + key: image_key, + rendering: image_rendering, + tile: None, }, - None, - ); - - self.add_primitive( - clip_and_scroll, - &info, - Vec::new(), - PrimitiveContainer::Brush(prim), - ); - } else { - let prim_cpu = ImagePrimitiveCpu { - tile_spacing, + current_epoch: Epoch::invalid(), alpha_type, stretch_size, - current_epoch: Epoch::invalid(), + tile_spacing, source: ImageSource::Default, - key: ImageCacheKey { - request, - texel_rect: sub_rect, - }, - }; + sub_rect, + visible_tiles: Vec::new(), + opacity_binding: OpacityBinding::new(), + }, + None, + ); - self.add_primitive( - clip_and_scroll, - &info, - Vec::new(), - PrimitiveContainer::Image(prim_cpu), - ); - } + self.add_primitive( + clip_and_scroll, + &info, + Vec::new(), + PrimitiveContainer::Brush(prim), + ); } pub fn add_yuv_image( diff --git a/webrender/src/image.rs b/webrender/src/image.rs index dcf54877da..1d359bb925 100644 --- a/webrender/src/image.rs +++ b/webrender/src/image.rs @@ -2,8 +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/. */ -use api::{TileOffset, LayoutRect, LayoutSize, LayoutVector2D, DeviceUintSize}; -use euclid::rect; +use api::{TileOffset, LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D, DeviceUintSize}; +use euclid::{rect, vec2}; +use prim_store::EdgeAaSegmentMask; /// If repetitions are far enough apart that only one is within /// the primitive rect, then we can simplify the parameters and @@ -27,6 +28,207 @@ pub fn simplify_repeated_primitive( } } +pub fn for_each_repetition( + prim_rect: &LayoutRect, + visible_rect: &LayoutRect, + stride: &LayoutSize, + callback: &mut FnMut(&LayoutPoint, EdgeAaSegmentMask), +) { + assert!(stride.width > 0.0); + assert!(stride.height > 0.0); + + let visible_rect = match prim_rect.intersection(&visible_rect) { + Some(rect) => rect, + None => return, + }; + + let nx = if visible_rect.origin.x > prim_rect.origin.x { + f32::floor((visible_rect.origin.x - prim_rect.origin.x) / stride.width) + } else { + 0.0 + }; + + let ny = if visible_rect.origin.y > prim_rect.origin.y { + f32::floor((visible_rect.origin.y - prim_rect.origin.y) / stride.height) + } else { + 0.0 + }; + + let x0 = prim_rect.origin.x + nx * stride.width; + let y0 = prim_rect.origin.y + ny * stride.height; + + let mut p = LayoutPoint::new(x0, y0); + + let x_most = visible_rect.max_x(); + let y_most = visible_rect.max_y(); + + let x_count = f32::ceil((x_most - x0) / stride.width) as i32; + let y_count = f32::ceil((y_most - y0) / stride.height) as i32; + + for y in 0..y_count { + let mut row_flags = EdgeAaSegmentMask::empty(); + if y == 0 { + row_flags |= EdgeAaSegmentMask::TOP; + } + if y == y_count - 1 { + row_flags |= EdgeAaSegmentMask::BOTTOM; + } + + for x in 0..x_count { + let mut edge_flags = row_flags; + if x == 0 { + edge_flags |= EdgeAaSegmentMask::LEFT; + } + if x == x_count - 1 { + edge_flags |= EdgeAaSegmentMask::RIGHT; + } + + callback(&p, edge_flags); + + p.x += stride.width; + } + + p.x = x0; + p.y += stride.height; + } +} + +pub fn for_each_tile( + prim_rect: &LayoutRect, + visible_rect: &LayoutRect, + device_image_size: &DeviceUintSize, + device_tile_size: u32, + callback: &mut FnMut(&LayoutRect, TileOffset, EdgeAaSegmentMask), +) { + // The image resource is tiled. We have to generate an image primitive + // for each tile. + // We need to do this because the image is broken up into smaller tiles in the texture + // cache and the image shader is not able to work with this type of sparse representation. + + // The tiling logic works as follows: + // + // ###################-+ -+ + // # | | |//# | | image size + // # | | |//# | | + // #----+----+----+--#-+ | -+ + // # | | |//# | | | regular tile size + // # | | |//# | | | + // #----+----+----+--#-+ | -+-+ + // #////|////|////|//# | | | "leftover" height + // ################### | -+ ---+ + // #----+----+----+----+ + // + // In the ascii diagram above, a large image is split into tiles of almost regular size. + // The tiles on the right and bottom edges (hatched in the diagram) are smaller than + // the regular tiles and are handled separately in the code see leftover_width/height. + // each generated segment corresponds to a tile in the texture cache, with the + // assumption that the smaller tiles with leftover sizes are sized to fit their own + // irregular size in the texture cache. + + // Because we can have very large virtual images we iterate over the visible portion of + // the image in layer space intead of iterating over device tiles. + + let visible_rect = match prim_rect.intersection(&visible_rect) { + Some(rect) => rect, + None => return, + }; + + let device_tile_size_f32 = device_tile_size as f32; + + // Ratio between (image space) tile size and image size . + let tile_dw = device_tile_size_f32 / (device_image_size.width as f32); + let tile_dh = device_tile_size_f32 / (device_image_size.height as f32); + + // size of regular tiles in layout space. + let layer_tile_size = LayoutSize::new( + tile_dw * prim_rect.size.width, + tile_dh * prim_rect.size.height, + ); + + // The size in pixels of the tiles on the right and bottom edges, smaller + // than the regular tile size if the image is not a multiple of the tile size. + // Zero means the image size is a multiple of the tile size. + let leftover_device_size = DeviceUintSize::new( + device_image_size.width % device_tile_size, + device_image_size.height % device_tile_size + ); + + // The size in layer space of the tiles on the right and bottom edges. + let leftover_layer_size = LayoutSize::new( + layer_tile_size.width * leftover_device_size.width as f32 / device_tile_size_f32, + layer_tile_size.height * leftover_device_size.height as f32 / device_tile_size_f32, + ); + + // Offset of the row and column of tiles with leftover size. + let leftover_offset = TileOffset::new( + (device_image_size.width / device_tile_size) as u16, + (device_image_size.height / device_tile_size) as u16, + ); + + // Number of culled out tiles to skip before the first visible tile. + let t0 = TileOffset::new( + if visible_rect.origin.x > prim_rect.origin.x { + f32::floor((visible_rect.origin.x - prim_rect.origin.x) / layer_tile_size.width) as u16 + } else { + 0 + }, + if visible_rect.origin.y > prim_rect.origin.y { + f32::floor((visible_rect.origin.y - prim_rect.origin.y) / layer_tile_size.height) as u16 + } else { + 0 + }, + ); + + // Position of the first visible tile (top-left) in layer space. + let x0 = prim_rect.origin.x + t0.x as f32 * layer_tile_size.width; + let y0 = prim_rect.origin.y + t0.y as f32 * layer_tile_size.height; + + let x_count = f32::ceil((visible_rect.max_x() - x0) / layer_tile_size.width) as u16; + let y_count = f32::ceil((visible_rect.max_y() - y0) / layer_tile_size.height) as u16; + + for y in 0..y_count { + + let mut row_flags = EdgeAaSegmentMask::empty(); + if y == 0 { + row_flags |= EdgeAaSegmentMask::TOP; + } + if y == y_count - 1 { + row_flags |= EdgeAaSegmentMask::BOTTOM; + } + + for x in 0..x_count { + let tile_offset = t0 + vec2(x, y); + + + let mut segment_rect = LayoutRect { + origin: LayoutPoint::new( + x0 + tile_offset.x as f32 * layer_tile_size.width, + y0 + tile_offset.y as f32 * layer_tile_size.height, + ), + size: layer_tile_size, + }; + + if tile_offset.x == leftover_offset.x { + segment_rect.size.width = leftover_layer_size.width; + } + + if tile_offset.y == leftover_offset.y { + segment_rect.size.height = leftover_layer_size.height; + } + + let mut edge_flags = row_flags; + if x == 0 { + edge_flags |= EdgeAaSegmentMask::LEFT; + } + if x == x_count - 1 { + edge_flags |= EdgeAaSegmentMask::RIGHT; + } + + callback(&segment_rect, tile_offset, edge_flags); + } + } +} + pub struct DecomposedTile { pub rect: LayoutRect, pub stretch_size: LayoutSize, diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index e868ff6b18..e8d37c0ddd 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -3,8 +3,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{AlphaType, BorderRadius, BoxShadowClipMode, BuiltDisplayList, ClipMode, ColorF, ComplexClipRegion}; -use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode}; -use api::{FilterOp, GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag}; +use api::{DeviceIntRect, DeviceIntSize, DeviceUintSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode}; +use api::{FilterOp, GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag, TileOffset}; use api::{GlyphRasterSpace, LayoutPoint, LayoutRect, LayoutSize, LayoutToWorldTransform, LayoutVector2D}; use api::{PipelineId, PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat, DeviceIntSideOffsets}; use border::{BorderCornerInstance, BorderEdgeKind}; @@ -19,6 +19,7 @@ use glyph_rasterizer::{FontInstance, FontTransform}; use gpu_cache::{GpuBlockData, GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; use gpu_types::{ClipChainRectIndex}; +use image::{for_each_tile, for_each_repetition}; use picture::{PictureCompositeMode, PictureId, PicturePrimitive}; #[cfg(debug_assertions)] use render_backend::FrameId; @@ -242,6 +243,13 @@ impl OpacityBinding { } } +#[derive(Debug)] +pub struct VisibleImageTile { + pub tile_offset: TileOffset, + pub handle: GpuCacheHandle, + pub edge_flags: EdgeAaSegmentMask, +} + #[derive(Debug)] pub enum BrushKind { Solid { @@ -261,6 +269,7 @@ pub enum BrushKind { source: ImageSource, sub_rect: Option, opacity_binding: OpacityBinding, + visible_tiles: Vec, }, YuvImage { yuv_key: [ImageKey; 3], @@ -1389,6 +1398,7 @@ impl PrimitiveStore { frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, ) { + let mut is_tiled_image = false; let metadata = &mut self.cpu_metadata[prim_index.0]; #[cfg(debug_assertions)] { @@ -1532,15 +1542,18 @@ impl PrimitiveStore { ref mut current_epoch, ref mut source, ref mut opacity_binding, + ref mut visible_tiles, .. } => { let image_properties = frame_state .resource_cache .get_image_properties(request.key); + // Set if we need to request the source image from the cache this frame. if let Some(image_properties) = image_properties { *current_epoch = image_properties.epoch; + is_tiled_image = image_properties.tiling.is_some(); // If the opacity changed, invalidate the GPU cache so that // the new color for this primitive gets uploaded. @@ -1554,7 +1567,7 @@ impl PrimitiveStore { image_properties.descriptor.is_opaque && opacity_binding.current == 1.0; - if *tile_spacing != LayoutSize::zero() { + if *tile_spacing != LayoutSize::zero() && !is_tiled_image { *source = ImageSource::Cache { // Size in device-pixels we need to allocate in render task cache. size: DeviceIntSize::new( @@ -1568,6 +1581,8 @@ impl PrimitiveStore { // Work out whether this image is a normal / simple type, or if // we need to pre-render it to the render task cache. if let Some(rect) = sub_rect { + // We don't properly support this right now. + debug_assert!(!is_tiled_image); *source = ImageSource::Cache { // Size in device-pixels we need to allocate in render task cache. size: rect.size, @@ -1654,14 +1669,80 @@ impl PrimitiveStore { } } - if request_source_image { + if let Some(tile_size) = image_properties.tiling { + + let device_image_size = DeviceUintSize::new( + image_properties.descriptor.width, + image_properties.descriptor.height, + ); + + // Tighten the clip rect because decomposing the repeated image can + // produce primitives that are partially covering the original image + // rect and we want to clip these extra parts out. + let tight_clip_rect = metadata.local_clip_rect.intersection(&metadata.local_rect).unwrap(); + + let visible_rect = compute_conservative_visible_rect( + prim_run_context, + frame_context, + &tight_clip_rect + ); + + let base_edge_flags = edge_flags_for_tile_spacing(tile_spacing); + + let stride = stretch_size + *tile_spacing; + + visible_tiles.clear(); + + for_each_repetition( + &metadata.local_rect, + &visible_rect, + &stride, + &mut |origin, edge_flags| { + let edge_flags = base_edge_flags | edge_flags; + + let image_rect = LayoutRect { + origin: *origin, + size: stretch_size, + }; + + for_each_tile( + &image_rect, + &visible_rect, + &device_image_size, + tile_size as u32, + &mut |tile_rect, tile_offset, tile_flags| { + + frame_state.resource_cache.request_image( + request.with_tile(tile_offset), + frame_state.gpu_cache, + ); + + let mut handle = GpuCacheHandle::new(); + if let Some(mut request) = frame_state.gpu_cache.request(&mut handle) { + request.push(*tile_rect); + request.push(tight_clip_rect); + request.push(ColorF::new(1.0, 1.0, 1.0, opacity_binding.current).premultiplied()); + request.push(PremultipliedColorF::WHITE); + request.push([tile_rect.size.width, tile_rect.size.height, 0.0, 0.0]); + request.write_segment(*tile_rect); + } + + visible_tiles.push(VisibleImageTile { + tile_offset, + handle, + edge_flags: tile_flags & edge_flags, + }); + } + ); + } + ); + } else if request_source_image { frame_state.resource_cache.request_image( request, frame_state.gpu_cache, ); } } - } BrushKind::YuvImage { format, yuv_key, image_rendering, .. } => { let channel_num = format.get_plane_num(); @@ -1730,6 +1811,11 @@ impl PrimitiveStore { } } + if is_tiled_image { + // we already requested each tile's gpu data. + return; + } + // Mark this GPU resource as required for this frame. if let Some(mut request) = frame_state.gpu_cache.request(&mut metadata.gpu_location) { // has to match VECS_PER_BRUSH_PRIM @@ -2444,6 +2530,39 @@ impl PrimitiveStore { } } +fn compute_conservative_visible_rect( + prim_run_context: &PrimitiveRunContext, + frame_context: &FrameBuildingContext, + local_clip_rect: &LayoutRect, +) -> LayoutRect { + let world_screen_rect = prim_run_context + .clip_chain.combined_outer_screen_rect + .to_f32() / frame_context.device_pixel_scale; + + if let Some(layer_screen_rect) = prim_run_context + .scroll_node + .world_content_transform + .unapply(&world_screen_rect) { + + return local_clip_rect.intersection(&layer_screen_rect).unwrap_or(LayoutRect::zero()); + } + + *local_clip_rect +} + +fn edge_flags_for_tile_spacing(tile_spacing: &LayoutSize) -> EdgeAaSegmentMask { + let mut flags = EdgeAaSegmentMask::empty(); + + if tile_spacing.width > 0.0 { + flags |= EdgeAaSegmentMask::LEFT | EdgeAaSegmentMask::RIGHT; + } + if tile_spacing.height > 0.0 { + flags |= EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::BOTTOM; + } + + flags +} + //Test for one clip region contains another trait InsideTest { fn might_contain(&self, clip: &T) -> bool; diff --git a/webrender/src/resource_cache.rs b/webrender/src/resource_cache.rs index df035ea601..897d99b322 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -238,6 +238,16 @@ pub struct ImageRequest { pub tile: Option, } +impl ImageRequest { + pub fn with_tile(&self, offset: TileOffset) -> Self { + ImageRequest { + key: self.key, + rendering: self.rendering, + tile: Some(offset), + } + } +} + impl Into for ImageRequest { fn into(self) -> BlobImageRequest { BlobImageRequest { From 3721d8c5bf06c819b41a3777149cdf6e13f17b0b Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Mon, 30 Apr 2018 15:30:01 +0200 Subject: [PATCH 7/8] Ensure a tiled image isn't added to any batch if it doesn't end up showing any tile. --- webrender/src/prim_store.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index e8d37c0ddd..110128e36b 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -1736,6 +1736,15 @@ impl PrimitiveStore { ); } ); + + if visible_tiles.is_empty() { + // At this point if we don't have tiles to show it means we could probably + // have done a better a job at culling during an earlier stage. + // Clearing the screen rect has the effect of "culling out" the primitive + // from the point of view of the batch builder, and ensures we don't hit + // assertions later on because we didn't request any image. + metadata.screen_rect = None; + } } else if request_source_image { frame_state.resource_cache.request_image( request, From 90df6fd23084dec50734a386e98f6823e1ddc15a Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 26 Apr 2018 14:14:02 +0200 Subject: [PATCH 8/8] Remove the non-brush image primitive and shader. --- webrender/res/ps_image.glsl | 106 -------- webrender/src/batch.rs | 52 ---- webrender/src/display_list_flattener.rs | 8 +- webrender/src/image.rs | 278 +-------------------- webrender/src/prim_store.rs | 132 ---------- webrender/src/render_backend.rs | 2 - webrender/src/renderer.rs | 11 - webrender/src/resource_cache.rs | 24 -- webrender/src/scene_builder.rs | 3 +- webrender/src/shade.rs | 20 -- webrender/tests/angle_shader_validation.rs | 4 - 11 files changed, 4 insertions(+), 636 deletions(-) delete mode 100644 webrender/res/ps_image.glsl diff --git a/webrender/res/ps_image.glsl b/webrender/res/ps_image.glsl deleted file mode 100644 index 3f0c14c335..0000000000 --- a/webrender/res/ps_image.glsl +++ /dev/null @@ -1,106 +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/. */ - -#include shared,prim_shared - -// If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use non-normalized -// texture coordinates. Otherwise, it uses normalized texture coordinates. Please -// check GL_TEXTURE_RECTANGLE. -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 vec2 vTileSpacing; // Amount of space between tiled instances of this image. -flat varying vec4 vStRect; // Rectangle of valid texture rect. -flat varying float vLayer; - -#ifdef WR_FEATURE_TRANSFORM -flat varying vec4 vLocalRect; -#endif - -varying vec2 vLocalPos; -flat varying vec2 vStretchSize; - -#ifdef WR_VERTEX_SHADER -void main(void) { - Primitive prim = load_primitive(); - Image image = fetch_image(prim.specific_prim_address); - ImageResource res = fetch_image_resource(prim.user_data0); - -#ifdef WR_FEATURE_TRANSFORM - VertexInfo vi = write_transform_vertex_primitive(prim); - vLocalPos = vi.local_pos; - vLocalRect = vec4(prim.local_rect.p0, prim.local_rect.p0 + prim.local_rect.size); -#else - VertexInfo vi = write_vertex(prim.local_rect, - prim.local_clip_rect, - prim.z, - prim.scroll_node, - prim.task, - prim.local_rect); - vLocalPos = vi.local_pos - prim.local_rect.p0; -#endif - - write_clip(vi.screen_pos, prim.clip_area); - - // If this is in WR_FEATURE_TEXTURE_RECT mode, the rect and size use - // non-normalized texture coordinates. -#ifdef WR_FEATURE_TEXTURE_RECT - vec2 texture_size_normalization_factor = vec2(1, 1); -#else - vec2 texture_size_normalization_factor = vec2(textureSize(sColor0, 0)); -#endif - - vec2 uv0 = res.uv_rect.p0; - vec2 uv1 = res.uv_rect.p1; - - // vUv will contain how many times this image has wrapped around the image size. - vec2 st0 = uv0 / texture_size_normalization_factor; - vec2 st1 = uv1 / texture_size_normalization_factor; - - vLayer = res.layer; - vTextureSize = st1 - st0; - vTextureOffset = st0; - vTileSpacing = image.stretch_size_and_tile_spacing.zw; - vStretchSize = image.stretch_size_and_tile_spacing.xy; - - // We clamp the texture coordinates to the half-pixel offset from the borders - // in order to avoid sampling outside of the texture area. - vec2 half_texel = vec2(0.5) / texture_size_normalization_factor; - vStRect = vec4(min(st0, st1) + half_texel, max(st0, st1) - half_texel); -} -#endif - -#ifdef WR_FRAGMENT_SHADER -void main(void) { -#ifdef WR_FEATURE_TRANSFORM - float alpha = init_transform_fs(vLocalPos); - - // We clamp the texture coordinate calculation here to the local rectangle boundaries, - // which makes the edge of the texture stretch instead of repeat. - vec2 upper_bound_mask = step(vLocalRect.zw, vLocalPos); - vec2 relative_pos_in_rect = clamp(vLocalPos, vLocalRect.xy, vLocalRect.zw) - vLocalRect.xy; -#else - float alpha = 1.0; - vec2 relative_pos_in_rect = vLocalPos; - vec2 upper_bound_mask = vec2(0.0); -#endif - - alpha *= do_clip(); - - // We calculate the particular tile this fragment belongs to, taking into - // account the spacing in between tiles. We only paint if our fragment does - // not fall into that spacing. - // If the pixel is at the local rectangle upper bound, we force the current - // tile upper bound in order to avoid wrapping. - vec2 position_in_tile = mix( - mod(relative_pos_in_rect, vStretchSize + vTileSpacing), - vStretchSize, - upper_bound_mask); - vec2 st = vTextureOffset + ((position_in_tile / vStretchSize) * vTextureSize); - st = clamp(st, vStRect.xy, vStRect.zw); - - alpha = alpha * float(all(bvec2(step(position_in_tile, vStretchSize)))); - - oFragColor = vec4(alpha) * TEX_SAMPLE(sColor0, vec3(st, vLayer)); -} -#endif diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index ff88eb3f89..de27c5d8a3 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -40,7 +40,6 @@ const OPAQUE_TASK_ADDRESS: RenderTaskAddress = RenderTaskAddress(0x7fff); #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum TransformBatchKind { TextRun(GlyphFormat), - Image(ImageBufferKind), BorderCorner, BorderEdge, } @@ -1109,50 +1108,6 @@ impl AlphaBatchBuilder { } } } - PrimitiveKind::Image => { - let image_cpu = &ctx.prim_store.cpu_images[prim_metadata.cpu_prim_index.0]; - - let cache_item = match image_cpu.source { - ImageSource::Default => { - resolve_image( - image_cpu.key.request, - ctx.resource_cache, - gpu_cache, - deferred_resolves, - ) - } - ImageSource::Cache { ref handle, .. } => { - let rt_handle = handle - .as_ref() - .expect("bug: render task handle not allocated"); - let rt_cache_entry = ctx - .resource_cache - .get_cached_render_task(rt_handle); - ctx.resource_cache.get_texture_cache_item(&rt_cache_entry.handle) - } - }; - - if cache_item.texture_id == SourceTexture::Invalid { - warn!("Warnings: skip a PrimitiveKind::Image"); - debug!("at {:?}.", task_relative_bounding_rect); - return; - } - - let batch_kind = TransformBatchKind::Image(get_buffer_kind(cache_item.texture_id)); - let key = BatchKey::new( - BatchKind::Transformable(transform_kind, batch_kind), - non_segmented_blend_mode, - BatchTextures { - colors: [ - cache_item.texture_id, - SourceTexture::Invalid, - SourceTexture::Invalid, - ], - }, - ); - let batch = self.batch_list.get_suitable_batch(key, &task_relative_bounding_rect); - batch.push(base_instance.build(cache_item.uv_rect_handle.as_int(gpu_cache), 0, 0)); - } PrimitiveKind::TextRun => { let text_cpu = &ctx.prim_store.cpu_text_runs[prim_metadata.cpu_prim_index.0]; @@ -1616,13 +1571,6 @@ impl AlphaBatchHelpers for PrimitiveStore { } } } - PrimitiveKind::Image => { - let image_cpu = &self.cpu_images[metadata.cpu_prim_index.0]; - match image_cpu.alpha_type { - AlphaType::PremultipliedAlpha => BlendMode::PremultipliedAlpha, - AlphaType::Alpha => BlendMode::Alpha, - } - } } } } diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index cfd4004bde..46a2c3a8d1 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -30,7 +30,7 @@ use prim_store::{CachedGradientIndex, ImageSource}; use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore}; use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitiveCpu}; use render_backend::{DocumentView}; -use resource_cache::{FontInstanceMap, ImageRequest, TiledImageMap}; +use resource_cache::{FontInstanceMap, ImageRequest}; use scene::{Scene, ScenePipeline, StackingContextHelpers}; use scene_builder::{BuiltScene, SceneRequest}; use std::{f32, mem, usize}; @@ -150,9 +150,6 @@ pub struct DisplayListFlattener<'a> { /// The map of all font instances. font_instances: FontInstanceMap, - /// The map of tiled images. - tiled_image_map: TiledImageMap, - /// Used to track the latest flattened epoch for each pipeline. pipeline_epochs: Vec<(PipelineId, Epoch)>, @@ -207,7 +204,6 @@ impl<'a> DisplayListFlattener<'a> { scene: &Scene, clip_scroll_tree: &mut ClipScrollTree, font_instances: FontInstanceMap, - tiled_image_map: TiledImageMap, view: &DocumentView, output_pipelines: &FastHashSet, frame_builder_config: &FrameBuilderConfig, @@ -227,7 +223,6 @@ impl<'a> DisplayListFlattener<'a> { scene, clip_scroll_tree, font_instances, - tiled_image_map, config: *frame_builder_config, pipeline_epochs: Vec::new(), replacements: Vec::new(), @@ -2193,7 +2188,6 @@ pub fn build_scene(config: &FrameBuilderConfig, request: SceneRequest) -> BuiltS &request.scene, &mut clip_scroll_tree, request.font_instances, - request.tiled_image_map, &request.view, &request.output_pipelines, config, diff --git a/webrender/src/image.rs b/webrender/src/image.rs index 1d359bb925..181cb566fd 100644 --- a/webrender/src/image.rs +++ b/webrender/src/image.rs @@ -2,8 +2,8 @@ * 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 api::{TileOffset, LayoutPoint, LayoutRect, LayoutSize, LayoutVector2D, DeviceUintSize}; -use euclid::{rect, vec2}; +use api::{TileOffset, LayoutRect, LayoutSize, LayoutPoint, DeviceUintSize}; +use euclid::vec2; use prim_store::EdgeAaSegmentMask; /// If repetitions are far enough apart that only one is within @@ -228,277 +228,3 @@ pub fn for_each_tile( } } } - -pub struct DecomposedTile { - pub rect: LayoutRect, - pub stretch_size: LayoutSize, - pub tile_offset: TileOffset, -} - -pub struct TiledImageInfo { - /// The bounds of the item in layout space. - pub rect: LayoutRect, - /// The space between each repeated pattern in layout space. - pub tile_spacing: LayoutSize, - /// The size in layout space of each repetition of the image. - pub stretch_size: LayoutSize, - - /// The size the image occupies in the cache in device space. - pub device_image_size: DeviceUintSize, - /// The size of the tiles in the cache in device pixels. - pub device_tile_size: u32, -} - -/// Decomposes an image that is repeated into an image per individual repetition. -/// We need to do this when we are unable to perform the repetition in the shader, -/// for example if the image is tiled. -/// -/// In all of the "decompose" methods below, we independently handle horizontal and vertical -/// decomposition. This lets us generate the minimum amount of primitives by, for example, -/// decomposing the repetition horizontally while repeating vertically in the shader (for -/// an image where the width is too bug but the height is not). -/// -/// decompose_image and decompose_row handle image repetitions while decompose_cache_tiles -/// takes care of the decomposition required by the internal tiling of the image in the cache. -/// -/// Note that the term tiling is overloaded: There is the tiling we get from repeating images -/// in layout space, and the tiling that we do in the texture cache (to avoid hitting texture -/// size limits). The latter is referred to as "device" tiling here to disambiguate. -pub fn decompose_image(info: &TiledImageInfo, callback: &mut FnMut(&DecomposedTile)) { - - let no_vertical_tiling = info.device_image_size.height <= info.device_tile_size; - let no_vertical_spacing = info.tile_spacing.height == 0.0; - - if no_vertical_tiling && no_vertical_spacing { - decompose_row(&info.rect, info, callback); - return; - } - - // Decompose each vertical repetition into rows. - let layout_stride = info.stretch_size.height + info.tile_spacing.height; - let num_repetitions = (info.rect.size.height / layout_stride).ceil() as u32; - - for i in 0 .. num_repetitions { - let row_rect = rect( - info.rect.origin.x, - info.rect.origin.y + (i as f32) * layout_stride, - info.rect.size.width, - info.stretch_size.height, - ).intersection(&info.rect); - - if let Some(row_rect) = row_rect { - decompose_row(&row_rect, info, callback); - } - } -} - - -fn decompose_row(item_rect: &LayoutRect, info: &TiledImageInfo, callback: &mut FnMut(&DecomposedTile)) { - - let no_horizontal_tiling = info.device_image_size.width <= info.device_tile_size; - let no_horizontal_spacing = info.tile_spacing.width == 0.0; - - if no_horizontal_tiling && no_horizontal_spacing { - decompose_cache_tiles(item_rect, info, callback); - return; - } - - // Decompose each horizontal repetition. - let layout_stride = info.stretch_size.width + info.tile_spacing.width; - let num_repetitions = (item_rect.size.width / layout_stride).ceil() as u32; - - for i in 0 .. num_repetitions { - let decomposed_rect = rect( - item_rect.origin.x + (i as f32) * layout_stride, - item_rect.origin.y, - info.stretch_size.width, - item_rect.size.height, - ).intersection(item_rect); - - if let Some(decomposed_rect) = decomposed_rect { - decompose_cache_tiles(&decomposed_rect, info, callback); - } - } -} - -fn decompose_cache_tiles( - item_rect: &LayoutRect, - info: &TiledImageInfo, - callback: &mut FnMut(&DecomposedTile), -) { - // The image resource is tiled. We have to generate an image primitive - // for each tile. - // We need to do this because the image is broken up into smaller tiles in the texture - // cache and the image shader is not able to work with this type of sparse representation. - - // The tiling logic works as follows: - // - // ###################-+ -+ - // # | | |//# | | image size - // # | | |//# | | - // #----+----+----+--#-+ | -+ - // # | | |//# | | | regular tile size - // # | | |//# | | | - // #----+----+----+--#-+ | -+-+ - // #////|////|////|//# | | | "leftover" height - // ################### | -+ ---+ - // #----+----+----+----+ - // - // In the ascii diagram above, a large image is split into tiles of almost regular size. - // The tiles on the right and bottom edges (hatched in the diagram) are smaller than - // the regular tiles and are handled separately in the code see leftover_width/height. - // each generated image primitive corresponds to a tile in the texture cache, with the - // assumption that the smaller tiles with leftover sizes are sized to fit their own - // irregular size in the texture cache. - // - // For the case where we don't tile along an axis, we can still perform the repetition in - // the shader (for this particular axis), and it is worth special-casing for this to avoid - // generating many primitives. - // This can happen with very tall and thin images used as a repeating background. - // Apparently web authors do that... - - let needs_repeat_x = info.stretch_size.width < item_rect.size.width; - let needs_repeat_y = info.stretch_size.height < item_rect.size.height; - - let tiled_in_x = info.device_image_size.width > info.device_tile_size; - let tiled_in_y = info.device_image_size.height > info.device_tile_size; - - // If we don't actually tile in this dimension, repeating can be done in the shader. - let shader_repeat_x = needs_repeat_x && !tiled_in_x; - let shader_repeat_y = needs_repeat_y && !tiled_in_y; - - let tile_size_f32 = info.device_tile_size as f32; - - // Note: this rounds down so it excludes the partially filled tiles on the right and - // bottom edges (we handle them separately below). - let num_tiles_x = (info.device_image_size.width / info.device_tile_size) as u16; - let num_tiles_y = (info.device_image_size.height / info.device_tile_size) as u16; - - // Ratio between (image space) tile size and image size. - let img_dw = tile_size_f32 / (info.device_image_size.width as f32); - let img_dh = tile_size_f32 / (info.device_image_size.height as f32); - - // Stretched size of the tile in layout space. - let stretched_tile_size = LayoutSize::new( - img_dw * info.stretch_size.width, - img_dh * info.stretch_size.height, - ); - - // The size in pixels of the tiles on the right and bottom edges, smaller - // than the regular tile size if the image is not a multiple of the tile size. - // Zero means the image size is a multiple of the tile size. - let leftover = DeviceUintSize::new( - info.device_image_size.width % info.device_tile_size, - info.device_image_size.height % info.device_tile_size - ); - - for ty in 0 .. num_tiles_y { - for tx in 0 .. num_tiles_x { - add_device_tile( - item_rect, - stretched_tile_size, - TileOffset::new(tx, ty), - 1.0, - 1.0, - shader_repeat_x, - shader_repeat_y, - callback, - ); - } - if leftover.width != 0 { - // Tiles on the right edge that are smaller than the tile size. - add_device_tile( - item_rect, - stretched_tile_size, - TileOffset::new(num_tiles_x, ty), - (leftover.width as f32) / tile_size_f32, - 1.0, - shader_repeat_x, - shader_repeat_y, - callback, - ); - } - } - - if leftover.height != 0 { - for tx in 0 .. num_tiles_x { - // Tiles on the bottom edge that are smaller than the tile size. - add_device_tile( - item_rect, - stretched_tile_size, - TileOffset::new(tx, num_tiles_y), - 1.0, - (leftover.height as f32) / tile_size_f32, - shader_repeat_x, - shader_repeat_y, - callback, - ); - } - - if leftover.width != 0 { - // Finally, the bottom-right tile with a "leftover" size. - add_device_tile( - item_rect, - stretched_tile_size, - TileOffset::new(num_tiles_x, num_tiles_y), - (leftover.width as f32) / tile_size_f32, - (leftover.height as f32) / tile_size_f32, - shader_repeat_x, - shader_repeat_y, - callback, - ); - } - } -} - -fn add_device_tile( - item_rect: &LayoutRect, - stretched_tile_size: LayoutSize, - tile_offset: TileOffset, - tile_ratio_width: f32, - tile_ratio_height: f32, - shader_repeat_x: bool, - shader_repeat_y: bool, - callback: &mut FnMut(&DecomposedTile), -) { - // If the image is tiled along a given axis, we can't have the shader compute - // the image repetition pattern. In this case we base the primitive's rectangle size - // on the stretched tile size which effectively cancels the repetition (and repetition - // has to be emulated by generating more primitives). - // If the image is not tiled along this axis, we can perform the repetition in the - // shader. In this case we use the item's size in the primitive (on that particular - // axis). - // See the shader_repeat_x/y code below. - - let stretch_size = LayoutSize::new( - stretched_tile_size.width * tile_ratio_width, - stretched_tile_size.height * tile_ratio_height, - ); - - let mut prim_rect = LayoutRect::new( - item_rect.origin + LayoutVector2D::new( - tile_offset.x as f32 * stretched_tile_size.width, - tile_offset.y as f32 * stretched_tile_size.height, - ), - stretch_size, - ); - - if shader_repeat_x { - assert_eq!(tile_offset.x, 0); - prim_rect.size.width = item_rect.size.width; - } - - if shader_repeat_y { - assert_eq!(tile_offset.y, 0); - prim_rect.size.height = item_rect.size.height; - } - - // Fix up the primitive's rect if it overflows the original item rect. - if let Some(rect) = prim_rect.intersection(item_rect) { - callback(&DecomposedTile { - tile_offset, - rect, - stretch_size, - }); - } -} diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 110128e36b..04171ad289 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -147,7 +147,6 @@ pub struct PictureIndex(pub usize); #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrimitiveKind { TextRun, - Image, Border, Brush, } @@ -1018,7 +1017,6 @@ impl ClipData { #[derive(Debug)] pub enum PrimitiveContainer { TextRun(TextRunPrimitiveCpu), - Image(ImagePrimitiveCpu), Border(BorderPrimitiveCpu), Brush(BrushPrimitive), } @@ -1051,7 +1049,6 @@ impl PrimitiveContainer { } } } - PrimitiveContainer::Image(..) | PrimitiveContainer::Border(..) => { true } @@ -1102,7 +1099,6 @@ impl PrimitiveContainer { } } } - PrimitiveContainer::Image(..) | PrimitiveContainer::Border(..) => { panic!("bug: other primitive containers not expected here"); } @@ -1236,17 +1232,6 @@ impl PrimitiveStore { self.cpu_text_runs.push(text_cpu); metadata } - PrimitiveContainer::Image(image_cpu) => { - let metadata = PrimitiveMetadata { - opacity: PrimitiveOpacity::translucent(), - prim_kind: PrimitiveKind::Image, - cpu_prim_index: SpecificPrimitiveIndex(self.cpu_images.len()), - ..base_metadata - }; - - self.cpu_images.push(image_cpu); - metadata - } PrimitiveContainer::Border(border_cpu) => { let metadata = PrimitiveMetadata { opacity: PrimitiveOpacity::translucent(), @@ -1315,7 +1300,6 @@ impl PrimitiveStore { } } PrimitiveKind::TextRun | - PrimitiveKind::Image | PrimitiveKind::Border => {} } @@ -1365,7 +1349,6 @@ impl PrimitiveStore { }; } PrimitiveKind::TextRun | - PrimitiveKind::Image | PrimitiveKind::Border => { unreachable!("bug: invalid prim type for opacity collapse"); } @@ -1419,117 +1402,6 @@ impl PrimitiveStore { frame_state, ); } - PrimitiveKind::Image => { - let image_cpu = &mut self.cpu_images[metadata.cpu_prim_index.0]; - let image_properties = frame_state - .resource_cache - .get_image_properties(image_cpu.key.request.key); - - // TODO(gw): Add image.rs and move this code out to a separate - // source file as it gets more complicated, and we - // start pre-rendering images for other reasons. - - if let Some(image_properties) = image_properties { - // See if this image has been updated since we last hit this code path. - // If so, we need to (at least) update the opacity, and also rebuild - // and render task cached portions of this image. - if image_properties.epoch != image_cpu.current_epoch { - image_cpu.current_epoch = image_properties.epoch; - - // Update the opacity. - metadata.opacity.is_opaque = image_properties.descriptor.is_opaque && - image_cpu.tile_spacing.width == 0.0 && - image_cpu.tile_spacing.height == 0.0; - - // Work out whether this image is a normal / simple type, or if - // we need to pre-render it to the render task cache. - image_cpu.source = match image_cpu.key.texel_rect { - Some(texel_rect) => { - ImageSource::Cache { - // Size in device-pixels we need to allocate in render task cache. - size: texel_rect.size, - handle: None, - } - } - None => { - // Simple image - just use a normal texture cache entry. - ImageSource::Default - } - }; - } - - // Set if we need to request the source image from the cache this frame. - let mut request_source_image = false; - - // Every frame, for cached items, we need to request the render - // task cache item. The closure will be invoked on the first - // time through, and any time the render task output has been - // evicted from the texture cache. - match image_cpu.source { - ImageSource::Cache { size, ref mut handle } => { - let key = image_cpu.key; - - // Request a pre-rendered image task. - *handle = Some(frame_state.resource_cache.request_render_task( - RenderTaskCacheKey { - size, - kind: RenderTaskCacheKeyKind::Image(key), - }, - frame_state.gpu_cache, - frame_state.render_tasks, - None, - image_properties.descriptor.is_opaque, - |render_tasks| { - // We need to render the image cache this frame, - // so will need access to the source texture. - request_source_image = true; - - // Create a task to blit from the texture cache to - // a normal transient render task surface. This will - // copy only the sub-rect, if specified. - let cache_to_target_task = RenderTask::new_blit( - size, - BlitSource::Image { - key, - }, - ); - let cache_to_target_task_id = render_tasks.add(cache_to_target_task); - - // Create a task to blit the rect from the child render - // task above back into the right spot in the persistent - // render target cache. - let target_to_cache_task = RenderTask::new_blit( - size, - BlitSource::RenderTask { - task_id: cache_to_target_task_id, - }, - ); - let target_to_cache_task_id = render_tasks.add(target_to_cache_task); - - // Hook this into the render task tree at the right spot. - pic_state.tasks.push(target_to_cache_task_id); - - // Pass the image opacity, so that the cached render task - // item inherits the same opacity properties. - target_to_cache_task_id - } - )); - } - ImageSource::Default => { - // Normal images just reference the source texture each frame. - request_source_image = true; - } - } - - // Request source image from the texture cache, if required. - if request_source_image { - frame_state.resource_cache.request_image( - image_cpu.key.request, - frame_state.gpu_cache, - ); - } - } - } PrimitiveKind::Brush => { let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0]; @@ -1836,10 +1708,6 @@ impl PrimitiveStore { let border = &self.cpu_borders[metadata.cpu_prim_index.0]; border.write_gpu_blocks(request); } - PrimitiveKind::Image => { - let image = &self.cpu_images[metadata.cpu_prim_index.0]; - image.write_gpu_blocks(request); - } PrimitiveKind::TextRun => { let text = &self.cpu_text_runs[metadata.cpu_prim_index.0]; text.write_gpu_blocks(&mut request); diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index bbdd7c34f9..a5604819ff 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -206,7 +206,6 @@ impl Document { &self.pending.scene, &mut self.clip_scroll_tree, resource_cache.get_font_instances(), - resource_cache.get_tiled_image_map(), &self.view, &self.output_pipelines, &self.frame_builder_config, @@ -251,7 +250,6 @@ impl Document { removed_pipelines: replace(&mut self.pending.removed_pipelines, Vec::new()), view: self.view.clone(), font_instances: resource_cache.get_font_instances(), - tiled_image_map: resource_cache.get_tiled_image_map(), output_pipelines: self.output_pipelines.clone(), }) } else { diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index c7066108dc..badba837f0 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -136,10 +136,6 @@ const GPU_TAG_SETUP_DATA: GpuProfileTag = GpuProfileTag { label: "data init", color: debug_colors::LIGHTGREY, }; -const GPU_TAG_PRIM_IMAGE: GpuProfileTag = GpuProfileTag { - label: "Image", - color: debug_colors::GREEN, -}; const GPU_TAG_PRIM_SPLIT_COMPOSITE: GpuProfileTag = GpuProfileTag { label: "SplitComposite", color: debug_colors::DARKBLUE, @@ -183,12 +179,6 @@ impl TransformBatchKind { fn debug_name(&self) -> &'static str { match *self { TransformBatchKind::TextRun(..) => "TextRun", - TransformBatchKind::Image(image_buffer_kind, ..) => match image_buffer_kind { - ImageBufferKind::Texture2D => "Image (2D)", - ImageBufferKind::TextureRect => "Image (Rect)", - ImageBufferKind::TextureExternal => "Image (External)", - ImageBufferKind::Texture2DArray => "Image (Array)", - }, TransformBatchKind::BorderCorner => "BorderCorner", TransformBatchKind::BorderEdge => "BorderEdge", } @@ -197,7 +187,6 @@ impl TransformBatchKind { fn sampler_tag(&self) -> GpuProfileTag { match *self { TransformBatchKind::TextRun(..) => GPU_TAG_PRIM_TEXT_RUN, - TransformBatchKind::Image(..) => GPU_TAG_PRIM_IMAGE, TransformBatchKind::BorderCorner => GPU_TAG_PRIM_BORDER_CORNER, TransformBatchKind::BorderEdge => GPU_TAG_PRIM_BORDER_EDGE, } diff --git a/webrender/src/resource_cache.rs b/webrender/src/resource_cache.rs index 897d99b322..78d8d5aefb 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -110,8 +110,6 @@ pub struct ImageTiling { pub tile_size: TileSize, } -pub type TiledImageMap = FastHashMap; - #[derive(Default)] struct ImageTemplates { images: FastHashMap, @@ -889,28 +887,6 @@ impl ResourceCache { }) } - pub fn get_tiled_image_map(&self) -> TiledImageMap { - self.resources - .image_templates - .images - .iter() - .filter_map(|(&key, template)| { - template.tiling.map(|tile_size| { - ( - key, - ImageTiling { - image_size: DeviceUintSize::new( - template.descriptor.width, - template.descriptor.height, - ), - tile_size, - }, - ) - }) - }) - .collect() - } - pub fn begin_frame(&mut self, frame_id: FrameId) { debug_assert_eq!(self.state, State::Idle); self.state = State::AddResources; diff --git a/webrender/src/scene_builder.rs b/webrender/src/scene_builder.rs index be28a1b1ad..64cd1e9cb4 100644 --- a/webrender/src/scene_builder.rs +++ b/webrender/src/scene_builder.rs @@ -8,7 +8,7 @@ use display_list_flattener::build_scene; use frame_builder::{FrameBuilderConfig, FrameBuilder}; use clip_scroll_tree::ClipScrollTree; use internal_types::{FastHashMap, FastHashSet}; -use resource_cache::{FontInstanceMap, TiledImageMap}; +use resource_cache::FontInstanceMap; use render_backend::DocumentView; use renderer::{PipelineInfo, SceneBuilderHooks}; use scene::Scene; @@ -56,7 +56,6 @@ pub struct SceneRequest { pub scene: Scene, pub view: DocumentView, pub font_instances: FontInstanceMap, - pub tiled_image_map: TiledImageMap, pub output_pipelines: FastHashSet, pub removed_pipelines: Vec, } diff --git a/webrender/src/shade.rs b/webrender/src/shade.rs index 1b9eae7ea9..36ce26dcb9 100644 --- a/webrender/src/shade.rs +++ b/webrender/src/shade.rs @@ -492,7 +492,6 @@ pub struct Shaders { // a cache shader (e.g. blur) to the screen. pub ps_text_run: TextShader, pub ps_text_run_dual_source: TextShader, - ps_image: Vec>, ps_border_corner: PrimitiveShader, ps_border_edge: PrimitiveShader, @@ -632,11 +631,9 @@ impl Shaders { // All image configuration. let mut image_features = Vec::new(); - let mut ps_image = Vec::new(); let mut brush_image = Vec::new(); // PrimitiveShader is not clonable. Use push() to initialize the vec. for _ in 0 .. IMAGE_BUFFER_KINDS.len() { - ps_image.push(None); brush_image.push(None); } for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() { @@ -645,12 +642,6 @@ impl Shaders { if feature_string != "" { image_features.push(feature_string); } - ps_image[buffer_kind] = Some(PrimitiveShader::new( - "ps_image", - device, - &image_features, - options.precache_shaders, - )?); brush_image[buffer_kind] = Some(BrushShader::new( "brush_image", device, @@ -749,7 +740,6 @@ impl Shaders { cs_clip_line, ps_text_run, ps_text_run_dual_source, - ps_image, ps_border_corner, ps_border_edge, ps_split_composite, @@ -815,11 +805,6 @@ impl Shaders { }; return text_shader.get(glyph_format, transform_kind); } - TransformBatchKind::Image(image_buffer_kind) => { - self.ps_image[image_buffer_kind as usize] - .as_mut() - .expect("Unsupported image shader kind") - } TransformBatchKind::BorderCorner => { &mut self.ps_border_corner } @@ -852,11 +837,6 @@ impl Shaders { shader.deinit(device); } } - for shader in self.ps_image { - if let Some(shader) = shader { - shader.deinit(device); - } - } for shader in self.brush_yuv_image { if let Some(shader) = shader { shader.deinit(device); diff --git a/webrender/tests/angle_shader_validation.rs b/webrender/tests/angle_shader_validation.rs index e214bede42..bd49dcef5b 100644 --- a/webrender/tests/angle_shader_validation.rs +++ b/webrender/tests/angle_shader_validation.rs @@ -62,10 +62,6 @@ const SHADERS: &[Shader] = &[ name: "ps_split_composite", features: PRIM_FEATURES, }, - Shader { - name: "ps_image", - features: PRIM_FEATURES, - }, Shader { name: "ps_text_run", features: PRIM_FEATURES,