diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 68cd33c19c..4798781a52 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -15,10 +15,10 @@ use gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance}; use gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette}; use internal_types::{FastHashMap, SavedTargetIndex, TextureSource}; use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PictureSurface}; -use prim_store::{BrushKind, BrushPrimitive, DeferredResolve, PrimitiveTemplateKind}; +use prim_store::{BrushKind, BrushPrimitive, DeferredResolve, PrimitiveTemplateKind, PrimitiveDataStore}; use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveInstanceKind, PrimitiveStore}; use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex}; -use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, PrimitiveDetails}; +use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, PrimitiveDetails, Primitive}; use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree}; use renderer::{BlendMode, ImageBufferKind, ShaderColorMode}; use renderer::BLOCKS_PER_UV_RECT; @@ -906,6 +906,7 @@ impl AlphaBatchBuilder { PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::Rectangle { .. } | + PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::Clear => { unreachable!(); } @@ -1411,7 +1412,6 @@ impl AlphaBatchBuilder { BrushKind::Image { ref visible_tiles, .. } => !visible_tiles.is_empty(), BrushKind::LinearGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(), BrushKind::RadialGradient { ref visible_tiles, .. } => !visible_tiles.is_empty(), - _ => false, } } }; @@ -1683,6 +1683,116 @@ impl AlphaBatchBuilder { ctx, ); } + ( + PrimitiveInstanceKind::YuvImage { segment_instance_index, .. }, + PrimitiveTemplateKind::YuvImage { format, yuv_key, image_rendering, color_depth, color_space, .. } + ) => { + let mut textures = BatchTextures::no_texture(); + let mut uv_rect_addresses = [0; 3]; + + //yuv channel + let channel_count = format.get_plane_num(); + debug_assert!(channel_count <= 3); + for channel in 0 .. channel_count { + let image_key = yuv_key[channel]; + + let cache_item = resolve_image( + ImageRequest { + key: image_key, + rendering: *image_rendering, + tile: None, + }, + ctx.resource_cache, + gpu_cache, + deferred_resolves, + ); + + if cache_item.texture_id == TextureSource::Invalid { + warn!("Warnings: skip a PrimitiveKind::YuvImage"); + return; + } + + textures.colors[channel] = cache_item.texture_id; + uv_rect_addresses[channel] = cache_item.uv_rect_handle.as_int(gpu_cache); + } + + // All yuv textures should be the same type. + let buffer_kind = get_buffer_kind(textures.colors[0]); + assert!( + textures.colors[1 .. format.get_plane_num()] + .iter() + .all(|&tid| buffer_kind == get_buffer_kind(tid)) + ); + + let kind = BrushBatchKind::YuvImage( + buffer_kind, + *format, + *color_depth, + *color_space, + ); + + let batch_params = BrushBatchParameters::shared( + kind, + textures, + [ + uv_rect_addresses[0], + uv_rect_addresses[1], + uv_rect_addresses[2], + ], + 0, + ); + + let specified_blend_mode = BlendMode::PremultipliedAlpha; + + let non_segmented_blend_mode = if !prim_data.opacity.is_opaque || + prim_instance.clip_task_index != ClipTaskIndex::INVALID || + transform_kind == TransformedRectKind::Complex + { + specified_blend_mode + } else { + BlendMode::None + }; + + debug_assert!(*segment_instance_index != SegmentInstanceIndex::INVALID); + let (prim_cache_address, segments) = if *segment_instance_index == SegmentInstanceIndex::UNUSED { + (gpu_cache.get_address(&prim_data.gpu_cache_handle), None) + } else { + let segment_instance = &ctx.scratch.segment_instances[*segment_instance_index]; + let segments = Some(&ctx.scratch.segments[segment_instance.segments_range]); + (gpu_cache.get_address(&segment_instance.gpu_cache_handle), segments) + }; + + let prim_header = PrimitiveHeader { + local_rect: prim_data.prim_rect, + local_clip_rect: prim_instance.combined_local_clip_rect, + task_address, + specific_prim_address: prim_cache_address, + clip_task_address, + transform_id, + }; + + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + batch_params.prim_user_data, + ); + + self.add_segmented_prim_to_batch( + segments, + prim_data.opacity, + &batch_params, + specified_blend_mode, + non_segmented_blend_mode, + prim_header_index, + clip_task_address, + bounding_rect, + transform_kind, + render_tasks, + z_id, + prim_instance.clip_task_index, + ctx, + ); + } _ => { unreachable!(); } @@ -2089,62 +2199,6 @@ impl BrushPrimitive { 0, )) } - BrushKind::YuvImage { format, yuv_key, image_rendering, color_depth, color_space } => { - let mut textures = BatchTextures::no_texture(); - let mut uv_rect_addresses = [0; 3]; - - //yuv channel - let channel_count = format.get_plane_num(); - debug_assert!(channel_count <= 3); - for channel in 0 .. channel_count { - let image_key = yuv_key[channel]; - - let cache_item = resolve_image( - ImageRequest { - key: image_key, - rendering: image_rendering, - tile: None, - }, - resource_cache, - gpu_cache, - deferred_resolves, - ); - - if cache_item.texture_id == TextureSource::Invalid { - warn!("Warnings: skip a PrimitiveKind::YuvImage"); - return None; - } - - textures.colors[channel] = cache_item.texture_id; - uv_rect_addresses[channel] = cache_item.uv_rect_handle.as_int(gpu_cache); - } - - // All yuv textures should be the same type. - let buffer_kind = get_buffer_kind(textures.colors[0]); - assert!( - textures.colors[1 .. format.get_plane_num()] - .iter() - .all(|&tid| buffer_kind == get_buffer_kind(tid)) - ); - - let kind = BrushBatchKind::YuvImage( - buffer_kind, - format, - color_depth, - color_space, - ); - - Some(BrushBatchParameters::shared( - kind, - textures, - [ - uv_rect_addresses[0], - uv_rect_addresses[1], - uv_rect_addresses[2], - ], - 0, - )) - } } } } @@ -2163,7 +2217,6 @@ impl PrimitiveInstance { AlphaType::Alpha => BlendMode::Alpha, } } - BrushKind::YuvImage { .. } | BrushKind::RadialGradient { .. } | BrushKind::LinearGradient { .. } => { BlendMode::PremultipliedAlpha @@ -2175,18 +2228,39 @@ impl PrimitiveInstance { pub fn is_cacheable( &self, - details: &PrimitiveDetails, - resource_cache: &ResourceCache + primitives: &[Primitive], + prim_data_store: &PrimitiveDataStore, + resource_cache: &ResourceCache, ) -> bool { - let image_key = match *details { - PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Image{ request, .. }, .. }) => { - request.key + let image_key = match self.kind { + PrimitiveInstanceKind::LegacyPrimitive { prim_index, .. } => { + let prim = &primitives[prim_index.0]; + match prim.details { + PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Image{ request, .. }, .. }) => { + request.key + } + PrimitiveDetails::Brush(_) => { + return true + } + } } - PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::YuvImage{ yuv_key, .. }, .. }) => { - yuv_key[0] + PrimitiveInstanceKind::YuvImage { .. } => { + let prim_data = &prim_data_store[self.prim_data_handle]; + match prim_data.kind { + PrimitiveTemplateKind::YuvImage { ref yuv_key, .. } => { + yuv_key[0] + } + _ => unreachable!(), + } } - PrimitiveDetails::Brush(_) => { - return true + PrimitiveInstanceKind::Picture { .. } | + PrimitiveInstanceKind::TextRun { .. } | + PrimitiveInstanceKind::LineDecoration { .. } | + PrimitiveInstanceKind::NormalBorder { .. } | + PrimitiveInstanceKind::ImageBorder { .. } | + PrimitiveInstanceKind::Rectangle { .. } | + PrimitiveInstanceKind::Clear => { + return true; } }; match resource_cache.get_image_properties(image_key) { diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index 9c1412d1ca..35f2b14a3f 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -2093,22 +2093,17 @@ impl<'a> DisplayListFlattener<'a> { YuvData::InterleavedYCbCr(plane_0) => [plane_0, ImageKey::DUMMY, ImageKey::DUMMY], }; - let prim = BrushPrimitive::new( - BrushKind::YuvImage { + self.add_primitive( + clip_and_scroll, + info, + Vec::new(), + PrimitiveContainer::YuvImage { + color_depth, yuv_key, format, - color_depth, color_space, image_rendering, }, - None, - ); - - self.add_primitive( - clip_and_scroll, - info, - Vec::new(), - PrimitiveContainer::Brush(prim), ); } diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index d0cd30731e..c1581a61f4 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -20,7 +20,7 @@ use internal_types::FastHashSet; use plane_split::{Clipper, Polygon, Splitter}; use prim_store::{PictureIndex, PrimitiveInstance, SpaceMapper, VisibleFace, PrimitiveInstanceKind}; use prim_store::{get_raster_rects, PrimitiveDataInterner, PrimitiveDataStore, CoordinateSpaceMapping}; -use prim_store::{PrimitiveDetails, BrushKind, Primitive, OpacityBindingStorage}; +use prim_store::{PrimitiveDetails, BrushKind, Primitive, OpacityBindingStorage, PrimitiveTemplateKind}; use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle, TileBlit}; use render_task::{RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation}; use resource_cache::ResourceCache; @@ -382,12 +382,18 @@ impl TileCache { self.reconfigure_tiles_if_required(x0, y0, x1, y1); // Build the list of resources that this primitive has dependencies on. - let mut is_cacheable = true; let mut opacity_bindings: SmallVec<[(PropertyBindingId, f32); 4]> = SmallVec::new(); let mut clip_chain_spatial_nodes: SmallVec<[SpatialNodeIndex; 8]> = SmallVec::new(); let mut image_keys: SmallVec<[ImageKey; 8]> = SmallVec::new(); let mut current_clip_chain_id = prim_instance.clip_chain_id; + // Some primitives can not be cached (e.g. external video images) + let is_cacheable = prim_instance.is_cacheable( + primitives, + prim_data_store, + resource_cache, + ); + match prim_instance.kind { PrimitiveInstanceKind::Picture { pic_index } => { // Pictures can depend on animated opacity bindings. @@ -401,12 +407,6 @@ impl TileCache { PrimitiveInstanceKind::LegacyPrimitive { prim_index } => { let prim = &primitives[prim_index.0]; - // Some primitives can not be cached (e.g. external video images) - is_cacheable = prim_instance.is_cacheable( - &prim.details, - resource_cache, - ); - match prim.details { PrimitiveDetails::Brush(ref brush) => { match brush.kind { @@ -424,9 +424,6 @@ impl TileCache { image_keys.push(request.key); } - BrushKind::YuvImage { ref yuv_key, .. } => { - image_keys.extend_from_slice(yuv_key); - } BrushKind::RadialGradient { .. } | BrushKind::LinearGradient { .. } => { } @@ -442,6 +439,16 @@ impl TileCache { } } } + PrimitiveInstanceKind::YuvImage { .. } => { + match prim_data.kind { + PrimitiveTemplateKind::YuvImage { ref yuv_key, .. } => { + image_keys.extend_from_slice(yuv_key); + } + _ => { + unreachable!(); + } + } + } PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::Clear | diff --git a/webrender/src/prim_store.rs b/webrender/src/prim_store.rs index 102ab71f0a..2201b8470d 100644 --- a/webrender/src/prim_store.rs +++ b/webrender/src/prim_store.rs @@ -386,7 +386,14 @@ pub enum PrimitiveKeyKind { }, Rectangle { color: ColorU, - } + }, + YuvImage { + color_depth: ColorDepth, + yuv_key: [ImageKey; 3], + format: YuvFormat, + color_space: YuvColorSpace, + image_rendering: ImageRendering, + }, } #[cfg_attr(feature = "capture", derive(Serialize))] @@ -496,6 +503,11 @@ impl PrimitiveKey { segment_instance_index: SegmentInstanceIndex::INVALID, } } + PrimitiveKeyKind::YuvImage { .. } => { + PrimitiveInstanceKind::YuvImage { + segment_instance_index: SegmentInstanceIndex::INVALID, + } + } PrimitiveKeyKind::Unused => { // Should never be hit as this method should not be // called for old style primitives. @@ -538,6 +550,13 @@ pub enum PrimitiveTemplateKind { Rectangle { color: ColorF, }, + YuvImage { + color_depth: ColorDepth, + yuv_key: [ImageKey; 3], + format: YuvFormat, + color_space: YuvColorSpace, + image_rendering: ImageRendering, + }, Clear, Unused, } @@ -630,6 +649,15 @@ impl PrimitiveKeyKind { color: color.into(), } } + PrimitiveKeyKind::YuvImage { color_depth, yuv_key, format, color_space, image_rendering, .. } => { + PrimitiveTemplateKind::YuvImage { + color_depth, + yuv_key, + format, + color_space, + image_rendering, + } + } PrimitiveKeyKind::LineDecoration { cache_key, color } => { PrimitiveTemplateKind::LineDecoration { cache_key, @@ -672,6 +700,154 @@ impl From for PrimitiveTemplate { } } +impl PrimitiveTemplateKind { + /// Write any GPU blocks for the primitive template to the given request object. + fn write_prim_gpu_blocks( + &self, + request: &mut GpuDataRequest, + prim_rect: LayoutRect, + ) { + match *self { + PrimitiveTemplateKind::Clear => { + // Opaque black with operator dest out + request.push(PremultipliedColorF::BLACK); + } + PrimitiveTemplateKind::Rectangle { ref color, .. } => { + request.push(color.premultiplied()); + } + PrimitiveTemplateKind::NormalBorder { .. } => { + // Border primitives currently used for + // image borders, and run through the + // normal brush_image shader. + request.push(PremultipliedColorF::WHITE); + request.push(PremultipliedColorF::WHITE); + request.push([ + prim_rect.size.width, + prim_rect.size.height, + 0.0, + 0.0, + ]); + } + PrimitiveTemplateKind::ImageBorder { .. } => { + // Border primitives currently used for + // image borders, and run through the + // normal brush_image shader. + request.push(PremultipliedColorF::WHITE); + request.push(PremultipliedColorF::WHITE); + request.push([ + prim_rect.size.width, + prim_rect.size.height, + 0.0, + 0.0, + ]); + } + PrimitiveTemplateKind::LineDecoration { ref cache_key, ref color } => { + match cache_key { + Some(cache_key) => { + request.push(color.premultiplied()); + request.push(PremultipliedColorF::WHITE); + request.push([ + cache_key.size.width.to_f32_px(), + cache_key.size.height.to_f32_px(), + 0.0, + 0.0, + ]); + } + None => { + request.push(color.premultiplied()); + } + } + } + PrimitiveTemplateKind::TextRun { ref glyphs, ref font, ref offset, .. } => { + request.push(ColorF::from(font.color).premultiplied()); + // this is the only case where we need to provide plain color to GPU + let bg_color = ColorF::from(font.bg_color); + request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]); + request.push([ + offset.x.to_f32_px(), + offset.y.to_f32_px(), + 0.0, + 0.0, + ]); + + let mut gpu_block = [0.0; 4]; + for (i, src) in glyphs.iter().enumerate() { + // Two glyphs are packed per GPU block. + + if (i & 1) == 0 { + gpu_block[0] = src.point.x; + gpu_block[1] = src.point.y; + } else { + gpu_block[2] = src.point.x; + gpu_block[3] = src.point.y; + request.push(gpu_block); + } + } + + // Ensure the last block is added in the case + // of an odd number of glyphs. + if (glyphs.len() & 1) != 0 { + request.push(gpu_block); + } + + assert!(request.current_used_block_num() <= MAX_VERTEX_TEXTURE_WIDTH); + } + PrimitiveTemplateKind::YuvImage { color_depth, .. } => { + request.push([ + color_depth.rescaling_factor(), + 0.0, + 0.0, + 0.0 + ]); + } + PrimitiveTemplateKind::Unused => {} + } + } + + fn write_segment_gpu_blocks( + &self, + request: &mut GpuDataRequest, + prim_rect: LayoutRect, + ) { + match *self { + PrimitiveTemplateKind::Clear => { + request.write_segment( + prim_rect, + [0.0; 4], + ); + } + PrimitiveTemplateKind::NormalBorder { ref template, .. } => { + for segment in &template.brush_segments { + // has to match VECS_PER_SEGMENT + request.write_segment( + segment.local_rect, + segment.extra_data, + ); + } + } + PrimitiveTemplateKind::ImageBorder { ref brush_segments, .. } => { + for segment in brush_segments { + // has to match VECS_PER_SEGMENT + request.write_segment( + segment.local_rect, + segment.extra_data, + ); + } + } + PrimitiveTemplateKind::LineDecoration { .. } => { + request.write_segment( + prim_rect, + [0.0; 4], + ); + } + PrimitiveTemplateKind::Rectangle { .. } | + PrimitiveTemplateKind::TextRun { .. } | + PrimitiveTemplateKind::YuvImage { .. } | + PrimitiveTemplateKind::Unused => {} + } + } +} + impl PrimitiveTemplate { /// Update the GPU cache for a given primitive template. This may be called multiple /// times per frame, by each primitive reference that refers to this interned @@ -681,76 +857,23 @@ impl PrimitiveTemplate { &mut self, frame_state: &mut FrameBuildingState, ) { + if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { + self.kind.write_prim_gpu_blocks(&mut request, self.prim_rect); + self.kind.write_segment_gpu_blocks(&mut request, self.prim_rect); + } + self.opacity = match self.kind { PrimitiveTemplateKind::Clear => { - if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { - // Opaque black with operator dest out - request.push(PremultipliedColorF::BLACK); - - request.write_segment( - self.prim_rect, - [0.0; 4], - ); - } - PrimitiveOpacity::translucent() } PrimitiveTemplateKind::Rectangle { ref color, .. } => { - if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { - request.push(color.premultiplied()); - } - PrimitiveOpacity::from_alpha(color.a) } - PrimitiveTemplateKind::NormalBorder { ref template, .. } => { - if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { - // Border primitives currently used for - // image borders, and run through the - // normal brush_image shader. - request.push(PremultipliedColorF::WHITE); - request.push(PremultipliedColorF::WHITE); - request.push([ - self.prim_rect.size.width, - self.prim_rect.size.height, - 0.0, - 0.0, - ]); - - for segment in &template.brush_segments { - // has to match VECS_PER_SEGMENT - request.write_segment( - segment.local_rect, - segment.extra_data, - ); - } - } - + PrimitiveTemplateKind::NormalBorder { .. } => { // Shouldn't matter, since the segment opacity is used instead PrimitiveOpacity::translucent() } - PrimitiveTemplateKind::ImageBorder { request, ref brush_segments, .. } => { - if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { - // Border primitives currently used for - // image borders, and run through the - // normal brush_image shader. - request.push(PremultipliedColorF::WHITE); - request.push(PremultipliedColorF::WHITE); - request.push([ - self.prim_rect.size.width, - self.prim_rect.size.height, - 0.0, - 0.0, - ]); - - for segment in brush_segments { - // has to match VECS_PER_SEGMENT - request.write_segment( - segment.local_rect, - segment.extra_data, - ); - } - } - + PrimitiveTemplateKind::ImageBorder { request, .. } => { let image_properties = frame_state .resource_cache .get_image_properties(request.key); @@ -768,71 +891,26 @@ impl PrimitiveTemplate { } } PrimitiveTemplateKind::LineDecoration { ref cache_key, ref color } => { - if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { - // Work out the stretch parameters (for image repeat) based on the - // line decoration parameters. - - match cache_key { - Some(cache_key) => { - request.push(color.premultiplied()); - request.push(PremultipliedColorF::WHITE); - request.push([ - cache_key.size.width.to_f32_px(), - cache_key.size.height.to_f32_px(), - 0.0, - 0.0, - ]); - } - None => { - request.push(color.premultiplied()); - } - } - - request.write_segment( - self.prim_rect, - [0.0; 4], - ); - } - match cache_key { Some(..) => PrimitiveOpacity::translucent(), None => PrimitiveOpacity::from_alpha(color.a), } } - PrimitiveTemplateKind::TextRun { ref glyphs, ref font, ref offset, .. } => { - if let Some(mut request) = frame_state.gpu_cache.request(&mut self.gpu_cache_handle) { - request.push(ColorF::from(font.color).premultiplied()); - // this is the only case where we need to provide plain color to GPU - let bg_color = ColorF::from(font.bg_color); - request.push([bg_color.r, bg_color.g, bg_color.b, 1.0]); - request.push([ - offset.x.to_f32_px(), - offset.y.to_f32_px(), - 0.0, - 0.0, - ]); - - let mut gpu_block = [0.0; 4]; - for (i, src) in glyphs.iter().enumerate() { - // Two glyphs are packed per GPU block. - - if (i & 1) == 0 { - gpu_block[0] = src.point.x; - gpu_block[1] = src.point.y; - } else { - gpu_block[2] = src.point.x; - gpu_block[3] = src.point.y; - request.push(gpu_block); - } - } - - // Ensure the last block is added in the case - // of an odd number of glyphs. - if (glyphs.len() & 1) != 0 { - request.push(gpu_block); - } - - assert!(request.current_used_block_num() <= MAX_VERTEX_TEXTURE_WIDTH); + PrimitiveTemplateKind::TextRun { .. } => { + PrimitiveOpacity::translucent() + } + PrimitiveTemplateKind::YuvImage { format, yuv_key, image_rendering, .. } => { + let channel_num = format.get_plane_num(); + debug_assert!(channel_num <= 3); + for channel in 0 .. channel_num { + frame_state.resource_cache.request_image( + ImageRequest { + key: yuv_key[channel], + rendering: image_rendering, + tile: None, + }, + frame_state.gpu_cache, + ); } PrimitiveOpacity::translucent() @@ -942,13 +1020,6 @@ pub enum BrushKind { opacity_binding_index: OpacityBindingIndex, visible_tiles: Vec, }, - YuvImage { - yuv_key: [ImageKey; 3], - format: YuvFormat, - color_depth: ColorDepth, - color_space: YuvColorSpace, - image_rendering: ImageRendering, - }, RadialGradient { stops_handle: GpuCacheHandle, stops_range: ItemRange, @@ -986,7 +1057,6 @@ impl BrushKind { .is_none() } - BrushKind::YuvImage { .. } | BrushKind::RadialGradient { .. } | BrushKind::LinearGradient { .. } => true, } @@ -1159,14 +1229,6 @@ impl BrushPrimitive { if let Some(mut request) = gpu_cache.request(&mut self.gpu_location) { // has to match VECS_PER_SPECIFIC_BRUSH match self.kind { - BrushKind::YuvImage { color_depth, .. } => { - request.push([ - color_depth.rescaling_factor(), - 0.0, - 0.0, - 0.0 - ]); - } // Images are drawn as a white color, modulated by the total // opacity coming from any collapsed property bindings. BrushKind::Image { stretch_size, tile_spacing, color, .. } => { @@ -1786,6 +1848,13 @@ pub enum PrimitiveContainer { Rectangle { color: ColorF, }, + YuvImage { + color_depth: ColorDepth, + yuv_key: [ImageKey; 3], + format: YuvFormat, + color_space: YuvColorSpace, + image_rendering: ImageRendering, + }, } impl PrimitiveContainer { @@ -1804,7 +1873,6 @@ impl PrimitiveContainer { PrimitiveContainer::Brush(ref brush) => { match brush.kind { BrushKind::Image { .. } | - BrushKind::YuvImage { .. } | BrushKind::RadialGradient { .. } | BrushKind::LinearGradient { .. } => { true @@ -1813,6 +1881,7 @@ impl PrimitiveContainer { } PrimitiveContainer::NormalBorder { .. } | PrimitiveContainer::ImageBorder { .. } | + PrimitiveContainer::YuvImage { .. } | PrimitiveContainer::Clear => { true } @@ -1850,6 +1919,17 @@ impl PrimitiveContainer { (key, None) } + PrimitiveContainer::YuvImage { color_depth, yuv_key, format, color_space, image_rendering, .. } => { + let key = PrimitiveKeyKind::YuvImage { + color_depth, + yuv_key, + format, + color_space, + image_rendering, + }; + + (key, None) + } PrimitiveContainer::ImageBorder { request, widths, @@ -2008,18 +2088,16 @@ impl PrimitiveContainer { None, )) } - BrushKind::YuvImage { .. } | BrushKind::RadialGradient { .. } | BrushKind::LinearGradient { .. } => { panic!("bug: other brush kinds not expected here yet"); } } } - PrimitiveContainer::ImageBorder { .. } => { - panic!("bug: image borders are not supported in shadow contexts"); - } + PrimitiveContainer::ImageBorder { .. } | + PrimitiveContainer::YuvImage { .. } | PrimitiveContainer::Clear => { - panic!("bug: clear rects are not supported in shadow contexts"); + panic!("bug: this prim is not supported in shadow contexts"); } } } @@ -2077,6 +2155,9 @@ pub enum PrimitiveInstanceKind { opacity_binding_index: OpacityBindingIndex, segment_instance_index: SegmentInstanceIndex, }, + YuvImage { + segment_instance_index: SegmentInstanceIndex, + }, /// Clear out a rect, used for special effects. Clear, } @@ -2396,11 +2477,8 @@ impl PrimitiveStore { PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | - PrimitiveInstanceKind::LineDecoration { .. } => { - // TODO: Once rectangles and/or images are ported - // to use interned primitives, we will need - // to handle opacity collapse here. - } + PrimitiveInstanceKind::YuvImage { .. } | + PrimitiveInstanceKind::LineDecoration { .. } => {} PrimitiveInstanceKind::Picture { pic_index } => { let pic = &self.pictures[pic_index.0]; @@ -2421,7 +2499,6 @@ impl PrimitiveStore { BrushKind::Image { .. } => { return Some(pic_index) } - BrushKind::YuvImage { .. } | BrushKind::LinearGradient { .. } | BrushKind::RadialGradient { .. } => {} } @@ -2479,7 +2556,6 @@ impl PrimitiveStore { let opacity_binding = &mut self.opacity_bindings[*opacity_binding_index]; opacity_binding.push(binding); } - BrushKind::YuvImage { .. } | BrushKind::LinearGradient { .. } | BrushKind::RadialGradient { .. } => { unreachable!("bug: invalid prim type for opacity collapse"); @@ -2558,6 +2634,7 @@ impl PrimitiveStore { PrimitiveInstanceKind::LegacyPrimitive { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | + PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::Clear => { None } @@ -2610,6 +2687,7 @@ impl PrimitiveStore { PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | PrimitiveInstanceKind::Rectangle { .. } | + PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { let prim_data = &resources .prim_data_store[prim_instance.prim_data_handle]; @@ -2758,6 +2836,12 @@ impl PrimitiveStore { prim_instance.prepared_frame_id = frame_state.render_tasks.frame_id(); } + pic_state.is_cacheable &= prim_instance.is_cacheable( + &self.primitives, + &resources.prim_data_store, + frame_state.resource_cache, + ); + match prim_instance.kind { PrimitiveInstanceKind::Picture { pic_index } => { let pic = &mut self.pictures[pic_index.0]; @@ -2804,6 +2888,7 @@ impl PrimitiveStore { PrimitiveInstanceKind::Rectangle { .. } | PrimitiveInstanceKind::NormalBorder { .. } | PrimitiveInstanceKind::ImageBorder { .. } | + PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::LineDecoration { .. } => { self.prepare_interned_prim_for_render( prim_instance, @@ -2823,7 +2908,6 @@ impl PrimitiveStore { prim_details, prim_context, pic_context, - pic_state, frame_context, frame_state, display_list, @@ -2955,7 +3039,7 @@ impl PrimitiveStore { let is_chased = prim_instance.is_chased(); - match (&mut prim_instance.kind, &mut prim_data.kind) { + let segment_instance_index = match (&mut prim_instance.kind, &mut prim_data.kind) { ( PrimitiveInstanceKind::LineDecoration { ref mut cache_handle, .. }, PrimitiveTemplateKind::LineDecoration { ref cache_key, .. } @@ -3002,6 +3086,8 @@ impl PrimitiveStore { } )); } + + SegmentInstanceIndex::UNUSED } ( PrimitiveInstanceKind::TextRun { run_index, .. }, @@ -3027,6 +3113,8 @@ impl PrimitiveStore { frame_state.special_render_passes, scratch, ); + + SegmentInstanceIndex::UNUSED } ( PrimitiveInstanceKind::Clear, @@ -3034,6 +3122,7 @@ impl PrimitiveStore { ) => { // Nothing specific to prepare for clear rects, since the // GPU cache is updated by the template earlier. + SegmentInstanceIndex::UNUSED } ( PrimitiveInstanceKind::NormalBorder { ref mut cache_handles, .. }, @@ -3090,42 +3179,54 @@ impl PrimitiveStore { *cache_handles = scratch .border_cache_handles .extend(handles); + + SegmentInstanceIndex::UNUSED } ( PrimitiveInstanceKind::ImageBorder { .. }, PrimitiveTemplateKind::ImageBorder { .. } ) => { + SegmentInstanceIndex::UNUSED } ( PrimitiveInstanceKind::Rectangle { segment_instance_index, opacity_binding_index, .. }, - PrimitiveTemplateKind::Rectangle { ref color, .. } + PrimitiveTemplateKind::Rectangle { .. } ) => { - if *segment_instance_index != SegmentInstanceIndex::UNUSED { - let segment_instance = &mut scratch.segment_instances[*segment_instance_index]; - - if let Some(mut request) = frame_state.gpu_cache.request(&mut segment_instance.gpu_cache_handle) { - let segments = &scratch.segments[segment_instance.segments_range]; - - request.push(color.premultiplied()); - - for segment in segments { - request.write_segment( - segment.local_rect, - [0.0; 4], - ); - } - } - } - update_opacity_binding( &mut self.opacity_bindings, *opacity_binding_index, frame_context.scene_properties, ); + + *segment_instance_index + } + ( + PrimitiveInstanceKind::YuvImage { segment_instance_index, .. }, + PrimitiveTemplateKind::YuvImage { .. } + ) => { + *segment_instance_index } _ => { unreachable!(); } + }; + + debug_assert!(segment_instance_index != SegmentInstanceIndex::INVALID); + if segment_instance_index != SegmentInstanceIndex::UNUSED { + let segment_instance = &mut scratch.segment_instances[segment_instance_index]; + + if let Some(mut request) = frame_state.gpu_cache.request(&mut segment_instance.gpu_cache_handle) { + let segments = &scratch.segments[segment_instance.segments_range]; + + prim_data.kind.write_prim_gpu_blocks(&mut request, prim_data.prim_rect); + + for segment in segments { + request.write_segment( + segment.local_rect, + [0.0; 4], + ); + } + } } } } @@ -3386,7 +3487,8 @@ impl PrimitiveInstance { scratch: &mut PrimitiveScratchBuffer, ) { match self.kind { - PrimitiveInstanceKind::Rectangle { ref mut segment_instance_index, .. } => { + PrimitiveInstanceKind::Rectangle { ref mut segment_instance_index, .. } | + PrimitiveInstanceKind::YuvImage { ref mut segment_instance_index, .. } => { if *segment_instance_index == SegmentInstanceIndex::INVALID { let mut segments: SmallVec<[BrushSegment; 8]> = SmallVec::new(); @@ -3503,6 +3605,7 @@ impl PrimitiveInstance { PrimitiveInstanceKind::LineDecoration { .. } => { return false; } + PrimitiveInstanceKind::YuvImage { segment_instance_index, .. } | PrimitiveInstanceKind::Rectangle { segment_instance_index, .. } => { debug_assert!(segment_instance_index != SegmentInstanceIndex::INVALID); @@ -3632,7 +3735,6 @@ impl PrimitiveInstance { prim_details: &mut PrimitiveDetails, prim_context: &PrimitiveContext, pic_context: &PictureContext, - pic_state: &mut PictureState, frame_context: &FrameBuildingContext, frame_state: &mut FrameBuildingState, display_list: &BuiltDisplayList, @@ -3640,11 +3742,6 @@ impl PrimitiveInstance { ) { let mut is_tiled = false; - pic_state.is_cacheable &= self.is_cacheable( - prim_details, - frame_state.resource_cache, - ); - match *prim_details { PrimitiveDetails::Brush(ref mut brush) => { brush.opacity = match brush.kind { @@ -3863,22 +3960,6 @@ impl PrimitiveInstance { PrimitiveOpacity::opaque() } } - BrushKind::YuvImage { format, yuv_key, image_rendering, .. } => { - let channel_num = format.get_plane_num(); - debug_assert!(channel_num <= 3); - for channel in 0 .. channel_num { - frame_state.resource_cache.request_image( - ImageRequest { - key: yuv_key[channel], - rendering: image_rendering, - tile: None, - }, - frame_state.gpu_cache, - ); - } - - PrimitiveOpacity::opaque() - } BrushKind::RadialGradient { stops_range, center, diff --git a/webrender/src/surface.rs b/webrender/src/surface.rs index 9e90cac738..a858710524 100644 --- a/webrender/src/surface.rs +++ b/webrender/src/surface.rs @@ -240,6 +240,7 @@ impl SurfaceDescriptor { PrimitiveInstanceKind::LegacyPrimitive { .. } => { return None; } + PrimitiveInstanceKind::YuvImage { .. } | PrimitiveInstanceKind::LineDecoration { .. } | PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::NormalBorder { .. } |