From ed8b3e4362322c59482f753225cb2ac24a3e3c9a Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 11 Apr 2018 12:34:02 +0200 Subject: [PATCH 1/9] Repeat linear gradients in the brush shader when there is no spacing. --- webrender/src/display_list_flattener.rs | 66 ++++++++++++++----------- webrender/src/prim_store.rs | 28 ++++++++--- 2 files changed, 57 insertions(+), 37 deletions(-) diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index 324a3d17f7..5d675c1051 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -1848,6 +1848,7 @@ impl<'a> DisplayListFlattener<'a> { stops_count: usize, extend_mode: ExtendMode, gradient_index: CachedGradientIndex, + stretch_size: LayerSize, ) { // Try to ensure that if the gradient is specified in reverse, then so long as the stops // are also supplied in reverse that the rendered result will be equivalent. To do this, @@ -1876,6 +1877,7 @@ impl<'a> DisplayListFlattener<'a> { start_point: sp, end_point: ep, gradient_index, + stretch_size, }, None, ); @@ -1894,43 +1896,49 @@ impl<'a> DisplayListFlattener<'a> { stops: ItemRange, stops_count: usize, extend_mode: ExtendMode, - tile_size: LayerSize, + stretch_size: LayerSize, tile_spacing: LayerSize, ) { let gradient_index = CachedGradientIndex(self.cached_gradients.len()); self.cached_gradients.push(CachedGradient::new()); - let prim_infos = info.decompose( - tile_size, - tile_spacing, - 64 * 64, - ); - - if prim_infos.is_empty() { - self.add_gradient_impl( - clip_and_scroll, - info, - start_point, - end_point, - stops, - stops_count, - extend_mode, - gradient_index, + if tile_spacing != LayerSize::zero() { + let prim_infos = info.decompose( + stretch_size, + tile_spacing, + 64 * 64, ); - } else { - for prim_info in prim_infos { - self.add_gradient_impl( - clip_and_scroll, - &prim_info, - start_point, - end_point, - stops, - stops_count, - extend_mode, - gradient_index, - ); + + if !prim_infos.is_empty() { + for prim_info in prim_infos { + self.add_gradient_impl( + clip_and_scroll, + &prim_info, + start_point, + end_point, + stops, + stops_count, + extend_mode, + gradient_index, + prim_info.rect.size, + ); + } + + return; } } + + self.add_gradient_impl( + clip_and_scroll, + info, + start_point, + end_point, + stops, + stops_count, + extend_mode, + gradient_index, + stretch_size, + ); } fn add_radial_gradient_impl( diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 14a5350383..419acbb740 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -234,6 +234,7 @@ pub enum BrushKind { reverse_stops: bool, start_point: LayerPoint, end_point: LayerPoint, + stretch_size: LayerSize, } } @@ -1470,15 +1471,30 @@ impl PrimitiveStore { PrimitiveKind::Brush => { let brush = &self.cpu_brushes[metadata.cpu_prim_index.0]; brush.write_gpu_blocks(&mut request); + + let repeat = match brush.kind { + BrushKind::LinearGradient { stretch_size, .. } => { + [ + metadata.local_rect.size.width / stretch_size.width, + metadata.local_rect.size.height / stretch_size.height, + 0.0, + 0.0, + ] + } + _ => { + [1.0, 1.0, 0.0, 0.0] + } + }; + match brush.segment_desc { Some(ref segment_desc) => { for segment in &segment_desc.segments { // has to match VECS_PER_SEGMENT - request.write_segment(segment.local_rect); + request.write_segment(segment.local_rect, repeat); } } None => { - request.write_segment(metadata.local_rect); + request.write_segment(metadata.local_rect, repeat); } } } @@ -2246,13 +2262,9 @@ impl<'a> GpuDataRequest<'a> { fn write_segment( &mut self, local_rect: LayerRect, + extra_params: [f32; 4], ) { self.push(local_rect); - self.push([ - 1.0, - 1.0, - 0.0, - 0.0 - ]); + self.push(extra_params); } } From e7e29fe896e5f585b3a436429ad1eaa3c3e7069b Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 11 Apr 2018 15:37:01 +0200 Subject: [PATCH 2/9] Repeat radial gradients in the brush shader when there is no spacing. --- webrender/src/display_list_flattener.rs | 70 ++++++++++++++----------- webrender/src/prim_store.rs | 4 +- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index 5d675c1051..bfa9a248bc 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -1952,6 +1952,7 @@ impl<'a> DisplayListFlattener<'a> { stops: ItemRange, extend_mode: ExtendMode, gradient_index: CachedGradientIndex, + stretch_size: LayerSize, ) { let prim = BrushPrimitive::new( BrushKind::RadialGradient { @@ -1962,6 +1963,7 @@ impl<'a> DisplayListFlattener<'a> { end_radius, ratio_xy, gradient_index, + stretch_size, }, None, ); @@ -1984,45 +1986,51 @@ impl<'a> DisplayListFlattener<'a> { ratio_xy: f32, stops: ItemRange, extend_mode: ExtendMode, - tile_size: LayerSize, + stretch_size: LayerSize, tile_spacing: LayerSize, ) { let gradient_index = CachedGradientIndex(self.cached_gradients.len()); self.cached_gradients.push(CachedGradient::new()); - let prim_infos = info.decompose( - tile_size, - tile_spacing, - 64 * 64, - ); - - if prim_infos.is_empty() { - self.add_radial_gradient_impl( - clip_and_scroll, - info, - center, - start_radius, - end_radius, - ratio_xy, - stops, - extend_mode, - gradient_index, + if tile_spacing != LayerSize::zero() { + let prim_infos = info.decompose( + stretch_size, + tile_spacing, + 64 * 64, ); - } else { - for prim_info in prim_infos { - self.add_radial_gradient_impl( - clip_and_scroll, - &prim_info, - center, - start_radius, - end_radius, - ratio_xy, - stops, - extend_mode, - gradient_index, - ); + + if !prim_infos.is_empty() { + for prim_info in prim_infos { + self.add_radial_gradient_impl( + clip_and_scroll, + &prim_info, + center, + start_radius, + end_radius, + ratio_xy, + stops, + extend_mode, + gradient_index, + stretch_size, + ); + } + + return; } } + + self.add_radial_gradient_impl( + clip_and_scroll, + info, + center, + start_radius, + end_radius, + ratio_xy, + stops, + extend_mode, + gradient_index, + stretch_size, + ); } pub fn add_text( diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 419acbb740..a178609264 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -225,6 +225,7 @@ pub enum BrushKind { start_radius: f32, end_radius: f32, ratio_xy: f32, + stretch_size: LayerSize, }, LinearGradient { gradient_index: CachedGradientIndex, @@ -1473,7 +1474,8 @@ impl PrimitiveStore { brush.write_gpu_blocks(&mut request); let repeat = match brush.kind { - BrushKind::LinearGradient { stretch_size, .. } => { + BrushKind::LinearGradient { stretch_size, .. } | + BrushKind::RadialGradient { stretch_size, .. } => { [ metadata.local_rect.size.width / stretch_size.width, metadata.local_rect.size.height / stretch_size.height, From 6bca533f3353256c6825fa2c4b4b97ac11f39002 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 11 Apr 2018 16:35:11 +0200 Subject: [PATCH 3/9] Repeat images in the brush shader when there is no spacing. --- webrender/src/display_list_flattener.rs | 1 - webrender/src/prim_store.rs | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index bfa9a248bc..404a657850 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -2167,7 +2167,6 @@ impl<'a> DisplayListFlattener<'a> { // See if conditions are met to run through the new // image brush shader, which supports segments. if tile_spacing == LayerSize::zero() && - stretch_size == info.rect.size && tile_offset.is_none() { let prim = BrushPrimitive::new( BrushKind::Image { diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index a178609264..36455286a9 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -1474,6 +1474,7 @@ impl PrimitiveStore { brush.write_gpu_blocks(&mut request); let repeat = match brush.kind { + BrushKind::Image { stretch_size, .. } | BrushKind::LinearGradient { stretch_size, .. } | BrushKind::RadialGradient { stretch_size, .. } => { [ From 157abb26709232acc745eb28aeceed1a12f5d266 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Fri, 13 Apr 2018 13:35:19 +0200 Subject: [PATCH 4/9] Update reftest reference. --- wrench/reftests/transforms/local-clip.png | Bin 2192 -> 2138 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/wrench/reftests/transforms/local-clip.png b/wrench/reftests/transforms/local-clip.png index 88fcc870f996e059c019f7e9017afb3e9e11aab4..92e25ec5e59cbdb0e6d8b6538f320927cfc3a333 100644 GIT binary patch literal 2138 zcmeH}?@t^>7{`~o(zy!h%pJ(q)Z)(e4r`jq0kx2NdeBOWNr5NDQV;)w6K`#)FWhj?20;)CgAII-AmqIdD~0l*@_X_AoFE`M$ZMbO9-f;#|JhWB zP}jD*zNmInqPD;&8lc}(x$xTy4Qk2QiQN99Z+wyNo%lGCTe!8+BXAwPnZSAdZYu0y z;uDRA(BLA%HhJBBUM_sFCaw+PzxgF37v`>4_55AYTw2p~;Sn7r|EOfQer~>+{`~5n zE8~*YsG}_l<*d@LJ%h;d>?pcyqr1!a{FN>;6ersojmV*({$f<@BXntYXjPSYXUHiX z_RxvBq*J;{`Ec6p7;ZEf)gOA5DvvT2$FZ6Nyu+tQQFjHb}M?$C^Nr`R0=#!R~x&c|e|7veDZCGl6M8C6w!*C4N@f^aXKeJ4m(NRn z?J^>PIy2&7;&(&|zl*Jqjh^-LPM2SsL}Xv187XFB8Y^LNor9wR=`O!^5s@1p5hnhH zm9f*<8ectxl<3z^yU6xBbK1wmkXsoW!qyKqI!k#fA13W0pMpf0c)+c64`A!Z)lsMJ z^lN1&wrU5*?neYcJh$P^18^wqu7K;=T z^)m6?V|IfchB%}iA3&oOvesrwAl<=4Wz#m5+NzG!N(Qb%7coCFf$;-V?03uS0J&bF zQqGOYt9u~^xk%O;0wv1CqoXQ#@({^>JqVS2nWuJzfRPMrZTZOq9m)ZEE#yF8ySCGT zygYUIqywG8773I9)XBv9+hKt2#k6|x7(j=ZG2QWtG=4;3S#9mk|9}1X{@GaGGW*hR RVq_8C3_`H3g`Z^+?OzJ+Q&Io` literal 2192 zcmeH}?@ts*7{?d0#W^d@%$<-0FXncaJ7SgS6;icImCZ05R>T@at)w1Dtk5&wU5)lk z73s3&=In)fR#Ss#QtS_2NXS*AX#CY}7u(RFRbnxzO^G2A0>yh_!8QatOUfV7lo$Kv z`F=mo^UXY)osDkVSeh{}XCB9K8D$>4nd8#VvL^}BS!E=%<~hfKt!22lGMxD1z8<>& z4p&n1)fWqjvrp(b!ln8C=B(}a*7I8+zzaj4++4JQgGk~wEBw0k zl=D~+w^*FxaANLD4K$vBX~(Ry;_M;(C*Oqd?TIISPyZY#Jp3#bY|IB}vd7*w@uYqD z*RJ}%pS>CL$_ig`(BAfupu05CFkY!;`S^1-DLi@wfDjKm#isCG4_w5 zwr=~`Ri1AH7Sx~IZGy`roY;xXwyZW(Me0P7S}H!eM(EE=IYHuu!MRurWdh|#VXgpFS#W3uEP6mayU~|^AjT3M;|-%TN=3Z zUbE0Ewl?t#twv$|!4EC>xB5L!I_8&uZq`f@CBy%lV?(Tm@@@bd|C;$Doe(WHZHug9~;r zMree3yn|JIP~l525a#(1Ap6}SHX&Wc!OAYv#IX2v7mVg1 zCR0X_I1St$46z1HP+ED~Ndmtgg%QW>&G7%a9;eb@sT!^yKey`}_NT#>m2AYFidX#y DK6PqH From 13ff5d75dd213ad4d844bd6b3279af72743aa612 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Fri, 13 Apr 2018 15:32:52 +0200 Subject: [PATCH 5/9] 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 404a657850..6a69d86a76 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}; @@ -1897,11 +1897,18 @@ impl<'a> DisplayListFlattener<'a> { stops_count: usize, extend_mode: ExtendMode, stretch_size: LayerSize, - tile_spacing: LayerSize, + mut tile_spacing: LayerSize, ) { 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 = LayerPrimitiveInfo { + rect: prim_rect, + .. *info + }; + if tile_spacing != LayerSize::zero() { let prim_infos = info.decompose( stretch_size, @@ -1930,7 +1937,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_gradient_impl( clip_and_scroll, - info, + &info, start_point, end_point, stops, @@ -1987,11 +1994,18 @@ impl<'a> DisplayListFlattener<'a> { stops: ItemRange, extend_mode: ExtendMode, stretch_size: LayerSize, - tile_spacing: LayerSize, + mut tile_spacing: LayerSize, ) { 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 = LayerPrimitiveInfo { + rect: prim_rect, + .. *info + }; + if tile_spacing != LayerSize::zero() { let prim_infos = info.decompose( stretch_size, @@ -2021,7 +2035,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_radial_gradient_impl( clip_and_scroll, - info, + &info, center, start_radius, end_radius, @@ -2137,13 +2151,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 = LayerSize::zero(); - } + let mut prim_rect = info.rect; + simplify_repeated_primitive(&stretch_size, &mut tile_spacing, &mut prim_rect); + let info = LayerPrimitiveInfo { + rect: prim_rect, + .. *info + }; let request = ImageRequest { key: image_key, @@ -2183,7 +2196,7 @@ impl<'a> DisplayListFlattener<'a> { self.add_primitive( clip_and_scroll, - info, + &info, Vec::new(), PrimitiveContainer::Brush(prim), ); @@ -2202,7 +2215,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 6126814140..8964305554 100644 --- a/webrender/src/image.rs +++ b/webrender/src/image.rs @@ -5,6 +5,28 @@ use api::{TileOffset, LayerRect, LayerSize, LayerVector2D, 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: &LayerSize, + tile_spacing: &mut LayerSize, + prim_rect: &mut LayerRect, +) { + 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.width >= 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: LayerRect, pub stretch_size: LayerSize, From 0e6db033caf9bd0c34ccb0d92aa9a8fa32e361cd Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Mon, 16 Apr 2018 14:49:24 +0200 Subject: [PATCH 6/9] 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 | 35 +++++++++++++++++++++---- webrender/src/renderer.rs | 3 ++- 4 files changed, 35 insertions(+), 10 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 6a69d86a76..385874a3fa 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -2179,8 +2179,7 @@ impl<'a> DisplayListFlattener<'a> { // See if conditions are met to run through the new // image brush shader, which supports segments. - if tile_spacing == LayerSize::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 36455286a9..04ea6a79fc 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -1297,7 +1297,7 @@ 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, .. } => { + BrushKind::Image { request, sub_rect, stretch_size, ref mut tile_spacing, ref mut current_epoch, ref mut source, .. } => { let image_properties = frame_state .resource_cache .get_image_properties(request.key); @@ -1311,6 +1311,17 @@ impl PrimitiveStore { metadata.opacity.is_opaque = image_properties.descriptor.is_opaque; } + if *tile_spacing != LayerSize::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 { @@ -1328,7 +1339,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, @@ -1337,7 +1362,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, @@ -1353,7 +1378,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); @@ -1362,7 +1387,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 fa1eb3913c..32639209c3 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -2693,7 +2693,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 e3f86462a22255b05892a7a730a0f1d0460eaada Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Wed, 18 Apr 2018 13:52:31 +0200 Subject: [PATCH 7/9] Decompose tiled images during frame building. --- webrender/src/batch.rs | 101 ++++++++- webrender/src/display_list_flattener.rs | 121 +++-------- webrender/src/gpu_cache.rs | 10 + webrender/src/image.rs | 206 ++++++++++++++++++- webrender/src/prim_store.rs | 137 +++++++++++- webrender/src/resource_cache.rs | 10 + wrench/reftests/image/tile-with-spacing.yaml | 2 +- 7 files changed, 487 insertions(+), 100 deletions(-) diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 82161f9e7f..3cb238e95d 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -613,7 +613,10 @@ impl AlphaBatchBuilder { screen_rect.unclipped.size, ); - let prim_cache_address = gpu_cache.get_address(&prim_metadata.gpu_location); + // Tiled images have a cache handle per visible tile and an invalid handle in the + // primitive metadata. + let prim_cache_address = gpu_cache.try_get_address(&prim_metadata.gpu_location); + let no_textures = BatchTextures::no_texture(); let clip_task_address = prim_metadata .clip_task_id @@ -980,6 +983,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, @@ -1191,6 +1220,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, @@ -1286,6 +1354,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), + (BrushImageSourceKind::Color 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 385874a3fa..ac7d73140d 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -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::{ScrollNodeAndClipChain, TextRunPrimitiveCpu}; use render_backend::{DocumentView}; @@ -633,49 +633,16 @@ impl<'a> DisplayListFlattener<'a> { let prim_info = item.get_layer_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( @@ -1791,7 +1758,6 @@ impl<'a> DisplayListFlattener<'a> { border.image_key, ImageRendering::Auto, AlphaType::PremultipliedAlpha, - None, ); } } @@ -2149,7 +2115,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); @@ -2158,12 +2123,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( @@ -2177,48 +2136,30 @@ 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, + 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(), + }, + 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/gpu_cache.rs b/webrender/src/gpu_cache.rs index 2e145e8a5c..af17cf1118 100644 --- a/webrender/src/gpu_cache.rs +++ b/webrender/src/gpu_cache.rs @@ -654,4 +654,14 @@ impl GpuCache { debug_assert_eq!(block.last_access_time, self.frame_id); block.address } + + /// Similar to get_address except that it accepts invalid cache handles in which case it + /// returns an invalid cache address. + pub fn try_get_address(&self, id: &GpuCacheHandle) -> GpuCacheAddress { + if id.location.is_none() { + return GpuCacheAddress::invalid(); + } + + self.get_address(id) + } } diff --git a/webrender/src/image.rs b/webrender/src/image.rs index 8964305554..f32a7ed69c 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, LayerRect, LayerSize, LayerVector2D, DeviceUintSize}; -use euclid::rect; +use api::{TileOffset, LayerRect, LayerSize, LayerPoint, LayerVector2D, DeviceUintSize}; +use euclid::{vec2, rect}; +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: &LayerRect, + visible_rect: &LayerRect, + stride: &LayerSize, + callback: &mut FnMut(&LayerPoint, 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 = LayerPoint::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: &LayerRect, + visible_rect: &LayerRect, + device_image_size: &DeviceUintSize, + device_tile_size: u32, + callback: &mut FnMut(&LayerRect, 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 = LayerSize::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 = LayerSize::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 = LayerRect { + origin: LayerPoint::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: LayerRect, pub stretch_size: LayerSize, diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 04ea6a79fc..303a2e1978 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -3,10 +3,10 @@ * 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::{DeviceIntRect, DeviceIntSize, DeviceUintSize, DevicePixelScale, Epoch, ExtendMode, FontRenderMode}; use api::{FilterOp, GlyphInstance, GlyphKey, GradientStop, ImageKey, ImageRendering, ItemRange, ItemTag}; use api::{LayerPoint, LayerRect, LayerSize, LayerToWorldTransform, LayerVector2D}; -use api::{PipelineId, PremultipliedColorF, Shadow, YuvColorSpace, YuvFormat}; +use api::{PipelineId, PremultipliedColorF, Shadow, YuvColorSpace, YuvFormat, TileOffset}; use border::{BorderCornerInstance, BorderEdgeKind}; use box_shadow::BLUR_SAMPLE_SCALE; use clip_scroll_tree::{ClipChainIndex, ClipScrollNodeIndex, CoordinateSystemId}; @@ -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}; use render_task::{BlitSource, RenderTask, RenderTaskCacheKey}; use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskCacheEntryHandle}; @@ -193,6 +194,13 @@ pub struct PrimitiveMetadata { pub tag: Option, } +#[derive(Debug)] +pub struct VisibleImageTile { + pub tile_offset: TileOffset, + pub handle: GpuCacheHandle, + pub edge_flags: EdgeAaSegmentMask, +} + #[derive(Debug)] pub enum BrushKind { Solid { @@ -210,6 +218,7 @@ pub enum BrushKind { tile_spacing: LayerSize, source: ImageSource, sub_rect: Option, + visible_tiles: Vec, }, YuvImage { yuv_key: [ImageKey; 3], @@ -1168,6 +1177,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]; match metadata.prim_kind { PrimitiveKind::Border => {} @@ -1297,7 +1307,16 @@ impl PrimitiveStore { let brush = &mut self.cpu_brushes[metadata.cpu_prim_index.0]; match brush.kind { - BrushKind::Image { request, sub_rect, stretch_size, ref mut tile_spacing, ref mut current_epoch, ref mut source, .. } => { + BrushKind::Image { + request, + sub_rect, + stretch_size, + ref mut tile_spacing, + ref mut current_epoch, + ref mut source, + ref mut visible_tiles, + .. + } => { let image_properties = frame_state .resource_cache .get_image_properties(request.key); @@ -1311,7 +1330,7 @@ impl PrimitiveStore { metadata.opacity.is_opaque = image_properties.descriptor.is_opaque; } - if *tile_spacing != LayerSize::zero() { + if *tile_spacing != LayerSize::zero() && image_properties.tiling.is_none() { *source = ImageSource::Cache { // Size in device-pixels we need to allocate in render task cache. size: DeviceIntSize::new( @@ -1325,6 +1344,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!(image_properties.tiling.is_none()); *source = ImageSource::Cache { // Size in device-pixels we need to allocate in render task cache. size: rect.size, @@ -1409,14 +1430,78 @@ impl PrimitiveStore { } } - if request_source_image { + if let Some(tile_size) = image_properties.tiling { + is_tiled_image = true; + + 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_conservatrive_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 = LayerRect { + 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.write_segment(*tile_rect, [1.0, 1.0, 0.0, 0.0]); + } + + 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(); @@ -1475,6 +1560,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 @@ -2199,6 +2289,41 @@ impl PrimitiveStore { } } +fn compute_conservatrive_visible_rect( + prim_run_context: &PrimitiveRunContext, + frame_context: &FrameBuildingContext, + local_clip_rect: &LayerRect, +) -> LayerRect { + 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(LayerRect::zero()); + } + + *local_clip_rect +} + +fn edge_flags_for_tile_spacing(tile_spacing: &LayerSize) -> EdgeAaSegmentMask { + // If the number of gpu blocks for the request changes we can't reuse + // the same gpu location. + 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 ba469e0282..019194f533 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -237,6 +237,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 { diff --git a/wrench/reftests/image/tile-with-spacing.yaml b/wrench/reftests/image/tile-with-spacing.yaml index 40bc5802d4..0a4493d7f6 100644 --- a/wrench/reftests/image/tile-with-spacing.yaml +++ b/wrench/reftests/image/tile-with-spacing.yaml @@ -5,7 +5,7 @@ root: # applied so that when an image is split into several primitives, so that the latter # all get snapped the same way rather than independently. #- image: xy-gradient(300, 300) - - image: solid-color(255, 0, 0, 255, 300, 300) + - image: xy-gradient(800, 800) bounds: 0 0 800 800 stretch-size: 200 200 tile-spacing: 10 10 From 61fcfd28aa34a487aeee003263d24785ddf458f9 Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 26 Apr 2018 14:14:02 +0200 Subject: [PATCH 8/9] Remove lots of code. --- webrender/src/batch.rs | 51 ----- webrender/src/display_list_flattener.rs | 10 +- webrender/src/image.rs | 278 +----------------------- webrender/src/prim_store.rs | 130 ----------- webrender/src/render_backend.rs | 2 - webrender/src/resource_cache.rs | 24 -- webrender/src/scene_builder.rs | 3 +- 7 files changed, 5 insertions(+), 493 deletions(-) diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 3cb238e95d..e64f15cb52 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -1099,50 +1099,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]; @@ -1578,13 +1534,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 ac7d73140d..6a2bef5e0c 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, LayerPoint, La use api::{LayerRect, LayerSize, LayerVector2D, LayoutRect, LayoutSize, LayoutTransform}; use api::{LayoutVector2D, 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; @@ -30,7 +30,7 @@ use prim_store::{CachedGradientIndex, ImageSource}; use prim_store::{PictureIndex, PrimitiveContainer, PrimitiveIndex, PrimitiveStore}; use prim_store::{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(), @@ -2206,7 +2201,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 f32a7ed69c..6f8b491b03 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, LayerRect, LayerSize, LayerPoint, LayerVector2D, DeviceUintSize}; -use euclid::{vec2, rect}; +use api::{TileOffset, LayerRect, LayerSize, LayerPoint, 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: LayerRect, - pub stretch_size: LayerSize, - pub tile_offset: TileOffset, -} - -pub struct TiledImageInfo { - /// The bounds of the item in layout space. - pub rect: LayerRect, - /// The space between each repeated pattern in layout space. - pub tile_spacing: LayerSize, - /// The size in layout space of each repetition of the image. - pub stretch_size: LayerSize, - - /// 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: &LayerRect, 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: &LayerRect, - 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 = LayerSize::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: &LayerRect, - stretched_tile_size: LayerSize, - 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 = LayerSize::new( - stretched_tile_size.width * tile_ratio_width, - stretched_tile_size.height * tile_ratio_height, - ); - - let mut prim_rect = LayerRect::new( - item_rect.origin + LayerVector2D::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 303a2e1978..89502d3605 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -144,7 +144,6 @@ pub struct PictureIndex(pub usize); #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum PrimitiveKind { TextRun, - Image, Border, Brush, } @@ -913,7 +912,6 @@ impl ClipData { #[derive(Debug)] pub enum PrimitiveContainer { TextRun(TextRunPrimitiveCpu), - Image(ImagePrimitiveCpu), Border(BorderPrimitiveCpu), Brush(BrushPrimitive), } @@ -946,7 +944,6 @@ impl PrimitiveContainer { } } } - PrimitiveContainer::Image(..) | PrimitiveContainer::Border(..) => { true } @@ -998,7 +995,6 @@ impl PrimitiveContainer { } } } - PrimitiveContainer::Image(..) | PrimitiveContainer::Border(..) => { panic!("bug: other primitive containers not expected here"); } @@ -1130,17 +1126,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(), @@ -1192,117 +1177,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]; @@ -1576,10 +1450,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 41dd893eeb..004e6b0fa8 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/resource_cache.rs b/webrender/src/resource_cache.rs index 019194f533..e8139ad690 100644 --- a/webrender/src/resource_cache.rs +++ b/webrender/src/resource_cache.rs @@ -109,8 +109,6 @@ pub struct ImageTiling { pub tile_size: TileSize, } -pub type TiledImageMap = FastHashMap; - #[derive(Default)] struct ImageTemplates { images: FastHashMap, @@ -888,28 +886,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 1c4f3f0196..6e1a637bbe 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; @@ -53,7 +53,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, } From 534631233626f5ad628b0d2b197381b99db7e19b Mon Sep 17 00:00:00 2001 From: Nicolas Silva Date: Thu, 26 Apr 2018 14:28:51 +0200 Subject: [PATCH 9/9] Remove the old image shader. --- webrender/res/ps_image.glsl | 106 ------------------------------------ webrender/src/batch.rs | 1 - webrender/src/renderer.rs | 11 ---- webrender/src/shade.rs | 20 ------- 4 files changed, 138 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 e64f15cb52..3c421b0b98 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -37,7 +37,6 @@ const OPAQUE_TASK_ADDRESS: RenderTaskAddress = RenderTaskAddress(0x7fff); #[cfg_attr(feature = "replay", derive(Deserialize))] pub enum TransformBatchKind { TextRun(GlyphFormat), - Image(ImageBufferKind), BorderCorner, BorderEdge, } diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 32639209c3..75454c14c6 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -137,10 +137,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, @@ -184,12 +180,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", } @@ -198,7 +188,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/shade.rs b/webrender/src/shade.rs index c9b0ed5522..f1d2bf064c 100644 --- a/webrender/src/shade.rs +++ b/webrender/src/shade.rs @@ -461,7 +461,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, @@ -596,11 +595,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() { @@ -609,12 +606,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, @@ -711,7 +702,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, @@ -769,11 +759,6 @@ impl Shaders { TransformBatchKind::TextRun(..) => { unreachable!("bug: text batches are special cased"); } - 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 } @@ -806,11 +791,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);