From 3e71dbaae2e50fa0393ad5b6e0c9c500e41bb49f Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Thu, 6 Dec 2018 13:56:23 +1000 Subject: [PATCH 1/3] Extract Image --- webrender/src/batch.rs | 42 +-- webrender/src/display_list_flattener.rs | 17 +- webrender/src/picture.rs | 17 +- webrender/src/prim_store/image.rs | 457 ++++++++++++++++++++++++ webrender/src/prim_store/mod.rs | 389 +++----------------- webrender/src/profiler.rs | 3 + webrender/src/render_backend.rs | 12 +- webrender/src/render_task.rs | 3 +- webrender/src/scene_builder.rs | 52 +-- 9 files changed, 603 insertions(+), 389 deletions(-) create mode 100644 webrender/src/prim_store/image.rs diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index f4c1102aa4..243fdd8266 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -15,10 +15,12 @@ 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::{DeferredResolve, PrimitiveTemplateKind, PrimitiveDataStore}; -use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveInstanceKind}; +use prim_store::{DeferredResolve, PrimitiveTemplateKind}; +use prim_store::{EdgeAaSegmentMask, PrimitiveInstanceKind}; use prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex}; use prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex}; +use prim_store::image::ImageSource; +use render_backend::FrameResources; use render_task::{RenderTaskAddress, RenderTaskId, RenderTaskTree}; use renderer::{BlendMode, ImageBufferKind, ShaderColorMode}; use renderer::BLOCKS_PER_UV_RECT; @@ -1635,27 +1637,21 @@ impl AlphaBatchBuilder { ); } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { - let prim_data = &ctx.resources.prim_data_store[data_handle]; - let (source, alpha_type, key, image_rendering) = match prim_data.kind { - PrimitiveTemplateKind::Image { ref source, alpha_type, key, image_rendering, .. } => { - (source, alpha_type, key, image_rendering) - } - _ => unreachable!() - }; + let image_data = &ctx.resources.image_data_store[data_handle]; let image_instance = &ctx.prim_store.images[image_instance_index]; let opacity_binding = ctx.prim_store.get_opacity_binding(image_instance.opacity_binding_index); - let specified_blend_mode = match alpha_type { + let specified_blend_mode = match image_data.alpha_type { AlphaType::PremultipliedAlpha => BlendMode::PremultipliedAlpha, AlphaType::Alpha => BlendMode::Alpha, }; let request = ImageRequest { - key: key, - rendering: image_rendering, + key: image_data.key, + rendering: image_data.image_rendering, tile: None, }; if image_instance.visible_tiles.is_empty() { - let cache_item = match *source { + let cache_item = match image_data.source { ImageSource::Default => { resolve_image( request, @@ -1681,7 +1677,7 @@ impl AlphaBatchBuilder { let textures = BatchTextures::color(cache_item.texture_id); let opacity = PrimitiveOpacity::from_alpha(opacity_binding); - let opacity = opacity.combine(prim_data.opacity); + let opacity = opacity.combine(image_data.opacity); let non_segmented_blend_mode = if !opacity.is_opaque || prim_instance.clip_task_index != ClipTaskIndex::INVALID || @@ -1696,7 +1692,7 @@ impl AlphaBatchBuilder { BrushBatchKind::Image(get_buffer_kind(cache_item.texture_id)), textures, [ - ShaderColorMode::Image as i32 | ((alpha_type as i32) << 16), + ShaderColorMode::Image as i32 | ((image_data.alpha_type as i32) << 16), RasterizationSpace::Local as i32, get_shader_opacity(opacity_binding), ], @@ -1705,7 +1701,7 @@ impl AlphaBatchBuilder { debug_assert!(image_instance.segment_instance_index != SegmentInstanceIndex::INVALID); let (prim_cache_address, segments) = if image_instance.segment_instance_index == SegmentInstanceIndex::UNUSED { - (gpu_cache.get_address(&prim_data.gpu_cache_handle), None) + (gpu_cache.get_address(&image_data.gpu_cache_handle), None) } else { let segment_instance = &ctx.scratch.segment_instances[image_instance.segment_instance_index]; let segments = Some(&ctx.scratch.segments[segment_instance.segments_range]); @@ -1749,7 +1745,7 @@ impl AlphaBatchBuilder { gpu_cache, deferred_resolves, request.with_tile(tile.tile_offset), - alpha_type, + image_data.alpha_type, get_shader_opacity(opacity_binding), ) { let prim_cache_address = gpu_cache.get_address(&tile.handle); @@ -2271,20 +2267,20 @@ impl BrushBatchParameters { impl PrimitiveInstance { pub fn is_cacheable( &self, - prim_data_store: &PrimitiveDataStore, + resources: &FrameResources, resource_cache: &ResourceCache, ) -> bool { let image_key = match self.kind { - PrimitiveInstanceKind::Image { data_handle, .. } | + PrimitiveInstanceKind::Image { data_handle, .. } => { + let image_data = &resources.image_data_store[data_handle]; + image_data.key + } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { - let prim_data = &prim_data_store[data_handle]; + let prim_data = &resources.prim_data_store[data_handle]; match prim_data.kind { PrimitiveTemplateKind::YuvImage { ref yuv_key, .. } => { yuv_key[0] } - PrimitiveTemplateKind::Image { key, .. } => { - key - } _ => unreachable!(), } } diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index 2a7440a3c2..0b125ce00b 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -27,6 +27,7 @@ use prim_store::{PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind, NinePa use prim_store::{PrimitiveStore, PrimitiveStoreStats, LineDecorationCacheKey}; use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, get_line_decoration_sizes}; use prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams}; +use prim_store::image::Image; use prim_store::text_run::TextRun; use render_backend::{DocumentView}; use resource_cache::{FontInstanceMap, ImageRequest}; @@ -1820,7 +1821,9 @@ impl<'a> DisplayListFlattener<'a> { for item in &items { match item { - // TODO(djg): ugh. de-duplicate this code. + ShadowItem::Image(ref pending_image) => { + self.add_shadow_prim(&pending_shadow, pending_image, &mut prims) + } ShadowItem::Primitive(ref pending_primitive) => { self.add_shadow_prim(&pending_shadow, pending_primitive, &mut prims) } @@ -1897,6 +1900,9 @@ impl<'a> DisplayListFlattener<'a> { self.add_primitive_to_draw_list(shadow_prim_instance); } } + ShadowItem::Image(pending_image) => { + self.add_shadow_prim_to_draw_list(pending_image) + }, ShadowItem::Primitive(pending_primitive) => { self.add_shadow_prim_to_draw_list(pending_primitive) }, @@ -2415,7 +2421,7 @@ impl<'a> DisplayListFlattener<'a> { clip_and_scroll, &info, Vec::new(), - PrimitiveKeyKind::Image { + Image { key: image_key, tile_spacing: tile_spacing.into(), stretch_size: stretch_size.into(), @@ -2669,10 +2675,17 @@ pub struct PendingShadow { pub enum ShadowItem { Shadow(PendingShadow), + Image(PendingPrimitive), Primitive(PendingPrimitive), TextRun(PendingPrimitive), } +impl From> for ShadowItem { + fn from(image: PendingPrimitive) -> Self { + ShadowItem::Image(image) + } +} + impl From> for ShadowItem { fn from(container: PendingPrimitive) -> Self { ShadowItem::Primitive(container) diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index 5655cbfefc..e42a9ccfce 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -784,7 +784,7 @@ impl TileCache { // Some primitives can not be cached (e.g. external video images) let is_cacheable = prim_instance.is_cacheable( - &resources.prim_data_store, + &resources, resource_cache, ); @@ -809,7 +809,7 @@ impl TileCache { } } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { - let prim_data = &resources.prim_data_store[data_handle]; + let image_data = &resources.image_data_store[data_handle]; let image_instance = &image_instances[image_instance_index]; let opacity_binding_index = image_instance.opacity_binding_index; @@ -822,14 +822,7 @@ impl TileCache { } } - match prim_data.kind { - PrimitiveTemplateKind::Image { key, .. } => { - image_keys.push(key); - } - _ => { - unreachable!(); - } - } + image_keys.push(image_data.key); } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { let prim_data = &resources.prim_data_store[data_handle]; @@ -1411,10 +1404,12 @@ impl PrimitiveList { PrimitiveInstanceKind::ImageBorder { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | PrimitiveInstanceKind::YuvImage { data_handle, .. } | - PrimitiveInstanceKind::Image { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } => { &resources.prim_interner[data_handle] } + PrimitiveInstanceKind::Image { data_handle, .. } => { + &resources.image_interner[data_handle] + } PrimitiveInstanceKind::LinearGradient { data_handle, .. } => { &resources.linear_grad_interner[data_handle] } diff --git a/webrender/src/prim_store/image.rs b/webrender/src/prim_store/image.rs new file mode 100644 index 0000000000..1085bbfcfe --- /dev/null +++ b/webrender/src/prim_store/image.rs @@ -0,0 +1,457 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use api::{ + AlphaType, ColorF, ColorU, DeviceIntRect, DeviceIntSideOffsets, + DeviceIntSize, ImageRendering, LayoutRect, LayoutSize, LayoutPrimitiveInfo, + PremultipliedColorF, Shadow, TileOffset +}; +use api::ImageKey as ApiImageKey; +use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible}; +use frame_builder::FrameBuildingState; +use gpu_cache::{GpuCacheHandle, GpuDataRequest}; +use intern::{DataStore, Handle, Internable, Interner, InternDebug, UpdateList}; +use picture::SurfaceIndex; +use prim_store::{ + EdgeAaSegmentMask, OpacityBindingIndex, PrimitiveInstanceKind, + PrimitiveOpacity, PrimitiveSceneData, PrimKeyCommonData, + PrimTemplateCommonData, PrimitiveStore, SegmentInstanceIndex, SizeKey +}; +use render_task::{ + BlitSource, RenderTask, RenderTaskCacheEntryHandle, RenderTaskCacheKey, + RenderTaskCacheKeyKind +}; +use resource_cache::ImageRequest; +use std::ops::{Deref, DerefMut}; + +#[derive(Debug)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct VisibleImageTile { + pub tile_offset: TileOffset, + pub handle: GpuCacheHandle, + pub edge_flags: EdgeAaSegmentMask, + pub local_rect: LayoutRect, + pub local_clip_rect: LayoutRect, +} + +// Key that identifies a unique (partial) image that is being +// stored in the render task cache. +#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct ImageCacheKey { + pub request: ImageRequest, + pub texel_rect: Option, +} + +/// Instance specific fields for an image primitive. These are +/// currently stored in a separate array to avoid bloating the +/// size of PrimitiveInstance. In the future, we should be able +/// to remove this and store the information inline, by: +/// (a) Removing opacity collapse / binding support completely. +/// Once we have general picture caching, we don't need this. +/// (b) Change visible_tiles to use Storage in the primitive +/// scratch buffer. This will reduce the size of the +/// visible_tiles field here, and save memory allocation +/// when image tiling is used. I've left it as a Vec for +/// now to reduce the number of changes, and because image +/// tiling is very rare on real pages. +#[derive(Debug)] +pub struct ImageInstance { + pub opacity_binding_index: OpacityBindingIndex, + pub segment_instance_index: SegmentInstanceIndex, + pub visible_tiles: Vec, +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct ImageKey { + pub common: PrimKeyCommonData, + pub key: ApiImageKey, + pub stretch_size: SizeKey, + pub tile_spacing: SizeKey, + pub color: ColorU, + pub sub_rect: Option, + pub image_rendering: ImageRendering, + pub alpha_type: AlphaType, +} + +impl ImageKey { + pub fn new( + is_backface_visible: bool, + prim_size: LayoutSize, + prim_relative_clip_rect: LayoutRect, + image: Image, + ) -> Self { + + ImageKey { + common: PrimKeyCommonData { + is_backface_visible, + prim_size: prim_size.into(), + prim_relative_clip_rect: prim_relative_clip_rect.into(), + }, + key: image.key, + color: image.color.into(), + stretch_size: image.stretch_size.into(), + tile_spacing: image.tile_spacing.into(), + sub_rect: image.sub_rect, + image_rendering: image.image_rendering, + alpha_type: image.alpha_type, + } + } +} + +impl InternDebug for ImageKey {} + +impl AsInstanceKind for ImageKey { + /// Construct a primitive instance that matches the type + /// of primitive key. + fn as_instance_kind( + &self, + data_handle: ImageDataHandle, + prim_store: &mut PrimitiveStore, + ) -> PrimitiveInstanceKind { + // TODO(gw): Refactor this to not need a separate image + // instance (see ImageInstance struct). + let image_instance_index = prim_store.images.push(ImageInstance { + opacity_binding_index: OpacityBindingIndex::INVALID, + segment_instance_index: SegmentInstanceIndex::INVALID, + visible_tiles: Vec::new(), + }); + + PrimitiveInstanceKind::Image { + data_handle, + image_instance_index, + } + } +} + +// Where to find the texture data for an image primitive. +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug)] +pub enum ImageSource { + // A normal image - just reference the texture cache. + Default, + // An image that is pre-rendered into the texture cache + // via a render task. + Cache { + size: DeviceIntSize, + handle: Option, + }, +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct ImageTemplate { + pub common: PrimTemplateCommonData, + pub key: ApiImageKey, + pub stretch_size: LayoutSize, + pub tile_spacing: LayoutSize, + pub color: ColorF, + pub source: ImageSource, + pub image_rendering: ImageRendering, + pub sub_rect: Option, + pub alpha_type: AlphaType, +} + +impl From for ImageTemplate { + fn from(item: ImageKey) -> Self { + let common = PrimTemplateCommonData::with_key_common(item.common); + let color = item.color.into(); + let stretch_size = item.stretch_size.into(); + let tile_spacing = item.tile_spacing.into(); + + ImageTemplate { + common, + key: item.key, + color, + stretch_size, + tile_spacing, + source: ImageSource::Default, + sub_rect: item.sub_rect, + image_rendering: item.image_rendering, + alpha_type: item.alpha_type, + } + } +} + +impl Deref for ImageTemplate { + type Target = PrimTemplateCommonData; + fn deref(&self) -> &Self::Target { + &self.common + } +} + +impl DerefMut for ImageTemplate { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.common + } +} + +fn write_image_gpu_blocks( + request: &mut GpuDataRequest, + color: ColorF, + stretch_size: LayoutSize, + tile_spacing: LayoutSize, +) { + // Images are drawn as a white color, modulated by the total + // opacity coming from any collapsed property bindings. + request.push(color.premultiplied()); + request.push(PremultipliedColorF::WHITE); + request.push([ + stretch_size.width + tile_spacing.width, + stretch_size.height + tile_spacing.height, + 0.0, + 0.0, + ]); +} + +impl ImageTemplate { + /// 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 + /// template. The initial request call to the GPU cache ensures that work is only + /// done if the cache entry is invalid (due to first use or eviction). + pub fn update( + &mut self, + // TODO(gw): Passing in surface_index here is not ideal. The primitive template + // code shouldn't depend on current surface state. This is due to a + // limitation in how render task caching works. We should fix this by + // allowing render task caching to assign to surfaces implicitly + // during pass allocation. + surface_index: SurfaceIndex, + frame_state: &mut FrameBuildingState, + ) { + if let Some(mut request) = + frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) { + write_image_gpu_blocks( + &mut request, + self.color, + self.stretch_size, + self.tile_spacing + ); + + // write_segment_gpu_blocks + } + + self.opacity = { + let image_properties = frame_state + .resource_cache + .get_image_properties(self.key); + + match image_properties { + Some(image_properties) => { + let is_tiled = image_properties.tiling.is_some(); + + if self.tile_spacing != LayoutSize::zero() && !is_tiled { + self.source = ImageSource::Cache { + // Size in device-pixels we need to allocate in render task cache. + size: image_properties.descriptor.size.to_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) = self.sub_rect { + // We don't properly support this right now. + debug_assert!(!is_tiled); + self.source = ImageSource::Cache { + // Size in device-pixels we need to allocate in render task cache. + size: rect.size, + handle: None, + }; + } + + let mut request_source_image = false; + let mut is_opaque = image_properties.descriptor.is_opaque; + let request = ImageRequest { + key: self.key, + rendering: self.image_rendering, + tile: None, + }; + + // 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 self.source { + ImageSource::Cache { ref mut size, ref mut handle } => { + let padding = DeviceIntSideOffsets::new( + 0, + (self.tile_spacing.width * size.width as f32 / self.stretch_size.width) as i32, + (self.tile_spacing.height * size.height as f32 / self.stretch_size.height) as i32, + 0, + ); + + let inner_size = *size; + size.width += padding.horizontal(); + size.height += padding.vertical(); + + is_opaque &= padding == DeviceIntSideOffsets::zero(); + + let image_cache_key = ImageCacheKey { + request, + texel_rect: self.sub_rect, + }; + let surfaces = &mut frame_state.surfaces; + + // Request a pre-rendered image task. + *handle = Some(frame_state.resource_cache.request_render_task( + RenderTaskCacheKey { + size: *size, + kind: RenderTaskCacheKeyKind::Image(image_cache_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_with_padding( + inner_size, + &padding, + BlitSource::Image { key: image_cache_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. + surfaces[surface_index.0].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; + } + } + + if request_source_image && !is_tiled { + frame_state.resource_cache.request_image( + request, + frame_state.gpu_cache, + ); + } + + if is_opaque { + PrimitiveOpacity::from_alpha(self.color.a) + } else { + PrimitiveOpacity::translucent() + } + } + None => { + PrimitiveOpacity::opaque() + } + } + }; + } + + pub fn write_prim_gpu_blocks(&self, request: &mut GpuDataRequest) { + write_image_gpu_blocks( + request, + self.color, + self.stretch_size, + self.tile_spacing + ); + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub struct ImageDataMarker; + +pub type ImageDataStore = DataStore; +pub type ImageDataHandle = Handle; +pub type ImageDataUpdateList = UpdateList; +pub type ImageDataInterner = Interner; + +pub struct Image { + pub key: ApiImageKey, + pub stretch_size: SizeKey, + pub tile_spacing: SizeKey, + pub color: ColorU, + pub sub_rect: Option, + pub image_rendering: ImageRendering, + pub alpha_type: AlphaType, +} + +impl Internable for Image { + type Marker = ImageDataMarker; + type Source = ImageKey; + type StoreData = ImageTemplate; + type InternData = PrimitiveSceneData; + + /// Build a new key from self with `info`. + fn build_key( + self, + info: &LayoutPrimitiveInfo, + prim_relative_clip_rect: LayoutRect, + ) -> ImageKey { + ImageKey::new( + info.is_backface_visible, + info.rect.size, + prim_relative_clip_rect, + self + ) + } +} + +impl CreateShadow for Image { + fn create_shadow(&self, shadow: &Shadow) -> Self { + Image { + tile_spacing: self.tile_spacing, + stretch_size: self.stretch_size, + key: self.key, + sub_rect: self.sub_rect, + image_rendering: self.image_rendering, + alpha_type: self.alpha_type, + color: shadow.color.into(), + } + } +} + +impl IsVisible for Image { + fn is_visible(&self) -> bool { + true + } +} + +#[test] +#[cfg(target_os = "linux")] +fn test_struct_sizes() { + use std::mem; + // The sizes of these structures are critical for performance on a number of + // talos stress tests. If you get a failure here on CI, there's two possibilities: + // (a) You made a structure smaller than it currently is. Great work! Update the + // test expectations and move on. + // (b) You made a structure larger. This is not necessarily a problem, but should only + // be done with care, and after checking if talos performance regresses badly. + assert_eq!(mem::size_of::(), 56, "Image size changed"); + assert_eq!(mem::size_of::(), 144, "ImageTemplate size changed"); + assert_eq!(mem::size_of::(), 84, "ImageKey size changed"); +} diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index f4d01d2be5..f53398d822 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -2,12 +2,12 @@ * 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::{AlphaType, BorderRadius, ClipMode, ColorF, PictureRect, ColorU, LayoutVector2D}; -use api::{DeviceIntRect, DeviceIntSize, DevicePixelScale, DeviceRect, LayoutSideOffsetsAu}; +use api::{BorderRadius, ClipMode, ColorF, PictureRect, ColorU, LayoutVector2D}; +use api::{DeviceIntRect, DevicePixelScale, DeviceRect, LayoutSideOffsetsAu}; use api::{FilterOp, ImageKey, ImageRendering, TileOffset, RepeatMode, MixBlendMode}; use api::{LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, PropertyBindingId}; use api::{PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat}; -use api::{DeviceIntSideOffsets, WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale}; +use api::{WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale}; use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers}; use api::LayoutPrimitiveInfo; use app_units::Au; @@ -23,16 +23,17 @@ use frame_builder::PrimitiveContext; use glyph_rasterizer::GlyphKey; use gpu_cache::{GpuCache, GpuCacheAddress, GpuCacheHandle, GpuDataRequest, ToGpuBlocks}; use gpu_types::BrushFlags; -use image::{self, Repetition}; +use image::{Repetition}; use intern; use picture::{PictureCompositeMode, PicturePrimitive, PictureUpdateState, TileCacheUpdateState}; use picture::{ClusterRange, PrimitiveList, SurfaceIndex, SurfaceInfo, RetainedTiles, RasterConfig}; use prim_store::gradient::{LinearGradientDataHandle, RadialGradientDataHandle}; +use prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile}; use prim_store::text_run::{TextRunDataHandle, TextRunPrimitive}; #[cfg(debug_assertions)] use render_backend::{FrameId}; use render_backend::FrameResources; -use render_task::{BlitSource, RenderTask, RenderTaskCacheKey, to_cache_size}; +use render_task::{RenderTask, RenderTaskCacheKey, to_cache_size}; use render_task::{RenderTaskCacheKeyKind, RenderTaskId, RenderTaskCacheEntryHandle}; use renderer::{MAX_VERTEX_TEXTURE_WIDTH}; use resource_cache::{ImageProperties, ImageRequest, ResourceCache}; @@ -47,6 +48,7 @@ use util::{pack_as_float, project_rect, raster_rect_to_device_pixels}; use smallvec::SmallVec; pub mod gradient; +pub mod image; pub mod text_run; /// Counter for unique primitive IDs for debug tracing. @@ -487,15 +489,6 @@ pub enum PrimitiveKeyKind { color_space: YuvColorSpace, image_rendering: ImageRendering, }, - Image { - key: ImageKey, - stretch_size: SizeKey, - tile_spacing: SizeKey, - color: ColorU, - sub_rect: Option, - image_rendering: ImageRendering, - alpha_type: AlphaType, - }, Picture { composite_mode_key: PictureCompositeKey, }, @@ -761,7 +754,7 @@ impl AsInstanceKind for PrimitiveKey { fn as_instance_kind( &self, data_handle: PrimitiveDataHandle, - prim_store: &mut PrimitiveStore, + _: &mut PrimitiveStore, ) -> PrimitiveInstanceKind { match self.kind { PrimitiveKeyKind::LineDecoration { .. } => { @@ -799,20 +792,6 @@ impl AsInstanceKind for PrimitiveKey { segment_instance_index: SegmentInstanceIndex::INVALID } } - PrimitiveKeyKind::Image { .. } => { - // TODO(gw): Refactor this to not need a separate image - // instance (see ImageInstance struct). - let image_instance_index = prim_store.images.push(ImageInstance { - opacity_binding_index: OpacityBindingIndex::INVALID, - segment_instance_index: SegmentInstanceIndex::INVALID, - visible_tiles: Vec::new(), - }); - - PrimitiveInstanceKind::Image { - data_handle, - image_instance_index, - } - } PrimitiveKeyKind::Picture { .. } => { // Should never be hit as this method should not be // called for pictures. @@ -857,16 +836,6 @@ pub enum PrimitiveTemplateKind { color_space: YuvColorSpace, image_rendering: ImageRendering, }, - Image { - key: ImageKey, - stretch_size: LayoutSize, - tile_spacing: LayoutSize, - color: ColorF, - source: ImageSource, - image_rendering: ImageRendering, - sub_rect: Option, - alpha_type: AlphaType, - }, Clear, Picture { @@ -943,18 +912,6 @@ impl PrimitiveKeyKind { image_rendering, } } - PrimitiveKeyKind::Image { alpha_type, key, color, stretch_size, tile_spacing, image_rendering, sub_rect, .. } => { - PrimitiveTemplateKind::Image { - key, - color: color.into(), - stretch_size: stretch_size.into(), - tile_spacing: tile_spacing.into(), - source: ImageSource::Default, - sub_rect, - image_rendering, - alpha_type, - } - } PrimitiveKeyKind::LineDecoration { cache_key, color } => { PrimitiveTemplateKind::LineDecoration { cache_key, @@ -1086,18 +1043,6 @@ impl PrimitiveTemplateKind { 0.0 ]); } - PrimitiveTemplateKind::Image { stretch_size, tile_spacing, color, .. } => { - // Images are drawn as a white color, modulated by the total - // opacity coming from any collapsed property bindings. - request.push(color.premultiplied()); - request.push(PremultipliedColorF::WHITE); - request.push([ - stretch_size.width + tile_spacing.width, - stretch_size.height + tile_spacing.height, - 0.0, - 0.0, - ]); - } PrimitiveTemplateKind::Picture { .. } => {} } } @@ -1127,7 +1072,6 @@ impl PrimitiveTemplateKind { } PrimitiveTemplateKind::Clear | PrimitiveTemplateKind::LineDecoration { .. } | - PrimitiveTemplateKind::Image { .. } | PrimitiveTemplateKind::Rectangle { .. } | PrimitiveTemplateKind::YuvImage { .. } | PrimitiveTemplateKind::Picture { .. } => {} @@ -1142,12 +1086,6 @@ impl PrimitiveTemplate { /// done if the cache entry is invalid (due to first use or eviction). pub fn update( &mut self, - // TODO(gw): Passing in surface_index here is not ideal. The primitive template - // code shouldn't depend on current surface state. This is due to a - // limitation in how render task caching works. We should fix this by - // allowing render task caching to assign to surfaces implicitly - // during pass allocation. - surface_index: SurfaceIndex, frame_state: &mut FrameBuildingState, ) { if let Some(mut request) = frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) { @@ -1208,137 +1146,6 @@ impl PrimitiveTemplate { PrimitiveOpacity::translucent() } - PrimitiveTemplateKind::Image { key, stretch_size, ref color, tile_spacing, ref mut source, sub_rect, image_rendering, .. } => { - let image_properties = frame_state - .resource_cache - .get_image_properties(key); - - match image_properties { - Some(image_properties) => { - let is_tiled = image_properties.tiling.is_some(); - - if tile_spacing != LayoutSize::zero() && !is_tiled { - *source = ImageSource::Cache { - // Size in device-pixels we need to allocate in render task cache. - size: image_properties.descriptor.size.to_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 { - // We don't properly support this right now. - debug_assert!(!is_tiled); - *source = ImageSource::Cache { - // Size in device-pixels we need to allocate in render task cache. - size: rect.size, - handle: None, - }; - } - - let mut request_source_image = false; - let mut is_opaque = image_properties.descriptor.is_opaque; - let request = ImageRequest { - key, - rendering: image_rendering, - tile: None, - }; - - // 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 *source { - ImageSource::Cache { ref mut size, ref mut handle } => { - let padding = DeviceIntSideOffsets::new( - 0, - (tile_spacing.width * size.width as f32 / stretch_size.width) as i32, - (tile_spacing.height * size.height as f32 / stretch_size.height) as i32, - 0, - ); - - let inner_size = *size; - size.width += padding.horizontal(); - size.height += padding.vertical(); - - is_opaque &= padding == DeviceIntSideOffsets::zero(); - - let image_cache_key = ImageCacheKey { - request, - texel_rect: sub_rect, - }; - let surfaces = &mut frame_state.surfaces; - - // Request a pre-rendered image task. - *handle = Some(frame_state.resource_cache.request_render_task( - RenderTaskCacheKey { - size: *size, - kind: RenderTaskCacheKeyKind::Image(image_cache_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_with_padding( - inner_size, - &padding, - BlitSource::Image { key: image_cache_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. - surfaces[surface_index.0].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; - } - } - - if request_source_image && !is_tiled { - frame_state.resource_cache.request_image( - request, - frame_state.gpu_cache, - ); - } - - if is_opaque { - PrimitiveOpacity::from_alpha(color.a) - } else { - PrimitiveOpacity::translucent() - } - } - None => { - PrimitiveOpacity::opaque() - } - } - } PrimitiveTemplateKind::Picture { .. } => { PrimitiveOpacity::translucent() } @@ -1415,17 +1222,6 @@ impl OpacityBinding { } } -#[derive(Debug)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct VisibleImageTile { - pub tile_offset: TileOffset, - pub handle: GpuCacheHandle, - pub edge_flags: EdgeAaSegmentMask, - pub local_rect: LayoutRect, - pub local_clip_rect: LayoutRect, -} - #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -1562,16 +1358,6 @@ impl BrushSegment { } } -// Key that identifies a unique (partial) image that is being -// stored in the render task cache. -#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct ImageCacheKey { - pub request: ImageRequest, - pub texel_rect: Option, -} - #[derive(Clone, Debug, Hash, PartialEq, Eq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -1582,21 +1368,6 @@ pub struct LineDecorationCacheKey { pub size: LayoutSizeAu, } -// Where to find the texture data for an image primitive. -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug)] -pub enum ImageSource { - // A normal image - just reference the texture cache. - Default, - // An image that is pre-rendered into the texture cache - // via a render task. - Cache { - size: DeviceIntSize, - handle: Option, - }, -} - #[derive(Debug)] #[repr(C)] struct ClipRect { @@ -1833,7 +1604,6 @@ impl IsVisible for PrimitiveKeyKind { PrimitiveKeyKind::NormalBorder { .. } | PrimitiveKeyKind::ImageBorder { .. } | PrimitiveKeyKind::YuvImage { .. } | - PrimitiveKeyKind::Image { .. } | PrimitiveKeyKind::Clear | PrimitiveKeyKind::Picture { .. } => { true @@ -1873,17 +1643,6 @@ impl CreateShadow for PrimitiveKeyKind { widths, } } - PrimitiveKeyKind::Image { alpha_type, image_rendering, tile_spacing, stretch_size, key, sub_rect, .. } => { - PrimitiveKeyKind::Image { - tile_spacing, - stretch_size, - key, - sub_rect, - image_rendering, - alpha_type, - color: shadow.color.into(), - } - } PrimitiveKeyKind::ImageBorder { .. } | PrimitiveKeyKind::YuvImage { .. } | PrimitiveKeyKind::Picture { .. } | @@ -1894,25 +1653,6 @@ impl CreateShadow for PrimitiveKeyKind { } } -/// Instance specific fields for an image primitive. These are -/// currently stored in a separate array to avoid bloating the -/// size of PrimitiveInstance. In the future, we should be able -/// to remove this and store the information inline, by: -/// (a) Removing opacity collapse / binding support completely. -/// Once we have general picture caching, we don't need this. -/// (b) Change visible_tiles to use Storage in the primitive -/// scratch buffer. This will reduce the size of the -/// visible_tiles field here, and save memory allocation -/// when image tiling is used. I've left it as a Vec for -/// now to reduce the number of changes, and because image -/// tiling is very rare on real pages. -#[derive(Debug)] -pub struct ImageInstance { - pub opacity_binding_index: OpacityBindingIndex, - pub segment_instance_index: SegmentInstanceIndex, - pub visible_tiles: Vec, -} - #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] @@ -1970,7 +1710,7 @@ pub enum PrimitiveInstanceKind { }, Image { /// Handle to the common interned data for this primitive. - data_handle: PrimitiveDataHandle, + data_handle: ImageDataHandle, image_instance_index: ImageInstanceIndex, }, LinearGradient { @@ -2077,7 +1817,9 @@ impl PrimitiveInstance { PrimitiveInstanceKind::NormalBorder { data_handle, .. } | PrimitiveInstanceKind::ImageBorder { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | - PrimitiveInstanceKind::YuvImage { data_handle, .. } | + PrimitiveInstanceKind::YuvImage { data_handle, .. } => { + data_handle.uid() + } PrimitiveInstanceKind::Image { data_handle, .. } => { data_handle.uid() } @@ -2766,7 +2508,7 @@ impl PrimitiveStore { } pic_state.is_cacheable &= prim_instance.is_cacheable( - &resources.prim_data_store, + &resources, frame_state.resource_cache, ); @@ -2944,10 +2686,7 @@ impl PrimitiveStore { // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update( - pic_context.surface_index, - frame_state, - ); + prim_data.update(frame_state); match &prim_data.kind { PrimitiveTemplateKind::LineDecoration { ref cache_key, .. } => { @@ -3032,20 +2771,14 @@ impl PrimitiveStore { // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update( - pic_context.surface_index, - frame_state, - ); + prim_data.update(frame_state); } PrimitiveInstanceKind::NormalBorder { data_handle, ref mut cache_handles, .. } => { let prim_data = &mut resources.prim_data_store[*data_handle]; // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update( - pic_context.surface_index, - frame_state, - ); + prim_data.update(frame_state); let template = match prim_data.kind { PrimitiveTemplateKind::NormalBorder { ref template, .. } => template, @@ -3109,20 +2842,14 @@ impl PrimitiveStore { // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update( - pic_context.surface_index, - frame_state, - ); + prim_data.update(frame_state); } PrimitiveInstanceKind::Rectangle { data_handle, segment_instance_index, opacity_binding_index, .. } => { let prim_data = &mut resources.prim_data_store[*data_handle]; // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update( - pic_context.surface_index, - frame_state, - ); + prim_data.update(frame_state); update_opacity_binding( &mut self.opacity_bindings, @@ -3137,30 +2864,20 @@ impl PrimitiveStore { // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update( - pic_context.surface_index, - frame_state, - ); + prim_data.update(frame_state); write_segment(prim_data, *segment_instance_index, frame_state, scratch); } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { - let prim_data = &mut resources.prim_data_store[*data_handle]; + let image_data = &mut resources.image_data_store[*data_handle]; // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update( + image_data.update( pic_context.surface_index, frame_state, ); - let (key, stretch_size, tile_spacing, image_rendering) = match prim_data.kind { - PrimitiveTemplateKind::Image { ref key, ref stretch_size, ref tile_spacing, ref image_rendering, .. } => { - (key, stretch_size, tile_spacing, image_rendering) - } - _ => unreachable!() - }; - let image_instance = &mut self.images[*image_instance_index]; update_opacity_binding( @@ -3173,7 +2890,7 @@ impl PrimitiveStore { let image_properties = frame_state .resource_cache - .get_image_properties(*key); + .get_image_properties(image_data.key); if let Some(image_properties) = image_properties { if let Some(tile_size) = image_properties.tiling { @@ -3192,19 +2909,19 @@ impl PrimitiveStore { &tight_clip_rect ); - let base_edge_flags = edge_flags_for_tile_spacing(tile_spacing); + let base_edge_flags = edge_flags_for_tile_spacing(&image_data.tile_spacing); - let stride = *stretch_size + *tile_spacing; + let stride = image_data.stretch_size + image_data.tile_spacing; - let repetitions = image::repetitions( + let repetitions = ::image::repetitions( &prim_local_rect, &visible_rect, stride, ); let request = ImageRequest { - key: *key, - rendering: *image_rendering, + key: image_data.key, + rendering: image_data.image_rendering, tile: None, }; @@ -3213,10 +2930,10 @@ impl PrimitiveStore { let image_rect = LayoutRect { origin, - size: *stretch_size, + size: image_data.stretch_size, }; - let tiles = image::tiles( + let tiles = ::image::tiles( &image_rect, &visible_rect, &device_image_size, @@ -3257,7 +2974,24 @@ impl PrimitiveStore { } } - write_segment(prim_data, image_instance.segment_instance_index, frame_state, scratch); + //write_segment(image_data, image_instance.segment_instance_index, frame_state, scratch); + if image_instance.segment_instance_index != SegmentInstanceIndex::UNUSED { + let segment_instance = + &mut scratch.segment_instances[image_instance.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]; + + image_data.write_prim_gpu_blocks(&mut request); + + for segment in segments { + request.write_segment( + segment.local_rect, + [0.0; 4], + ); + } + } + } } PrimitiveInstanceKind::LinearGradient { data_handle, ref mut visible_tiles_range, .. } => { let prim_data = &mut resources.linear_grad_data_store[*data_handle]; @@ -3402,7 +3136,7 @@ fn decompose_repeated_primitive( ); let stride = *stretch_size + *tile_spacing; - let repetitions = image::repetitions(prim_local_rect, &visible_rect, stride); + let repetitions = ::image::repetitions(prim_local_rect, &visible_rect, stride); for Repetition { origin, .. } in repetitions { let mut handle = GpuCacheHandle::new(); let rect = LayoutRect { @@ -3622,22 +3356,17 @@ impl PrimitiveInstance { segment_instance_index } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { - let prim_data = &resources.prim_data_store[data_handle]; + let image_data = &resources.image_data_store[data_handle]; let image_instance = &mut prim_store.images[image_instance_index]; - match prim_data.kind { - PrimitiveTemplateKind::Image { key, .. } => { - // tiled images don't support segmentation - if frame_state - .resource_cache - .get_image_properties(key) - .and_then(|properties| properties.tiling) - .is_some() { - image_instance.segment_instance_index = SegmentInstanceIndex::UNUSED; - return; - } + // tiled images don't support segmentation + if frame_state + .resource_cache + .get_image_properties(image_data.key) + .and_then(|properties| properties.tiling) + .is_some() { + image_instance.segment_instance_index = SegmentInstanceIndex::UNUSED; + return; } - _ => unreachable!(), - } &mut image_instance.segment_instance_index } PrimitiveInstanceKind::Picture { .. } | @@ -4056,8 +3785,8 @@ fn test_struct_sizes() { // be done with care, and after checking if talos performance regresses badly. assert_eq!(mem::size_of::(), 128, "PrimitiveInstance size changed"); assert_eq!(mem::size_of::(), 40, "PrimitiveInstanceKind size changed"); - assert_eq!(mem::size_of::(), 144, "PrimitiveTemplate size changed"); - assert_eq!(mem::size_of::(), 88, "PrimitiveTemplateKind size changed"); + assert_eq!(mem::size_of::(), 112, "PrimitiveTemplate size changed"); + assert_eq!(mem::size_of::(), 56, "PrimitiveTemplateKind size changed"); assert_eq!(mem::size_of::(), 124, "PrimitiveKey size changed"); assert_eq!(mem::size_of::(), 96, "PrimitiveKeyKind size changed"); } diff --git a/webrender/src/profiler.rs b/webrender/src/profiler.rs index e8ad4e2cbd..066dca4bbd 100644 --- a/webrender/src/profiler.rs +++ b/webrender/src/profiler.rs @@ -404,6 +404,7 @@ pub struct IpcProfileCounters { #[derive(Clone)] pub struct InternProfileCounters { pub prims: ResourceProfileCounter, + pub images: ResourceProfileCounter, pub linear_gradients: ResourceProfileCounter, pub radial_gradients: ResourceProfileCounter, pub text_runs: ResourceProfileCounter, @@ -450,6 +451,7 @@ impl BackendProfileCounters { }, intern: InternProfileCounters { prims: ResourceProfileCounter::new("Interned primitives"), + images: ResourceProfileCounter::new("Interned images"), linear_gradients: ResourceProfileCounter::new("Interned linear gradients"), radial_gradients: ResourceProfileCounter::new("Interned radial gradients"), text_runs: ResourceProfileCounter::new("Interned text runs"), @@ -1103,6 +1105,7 @@ impl Profiler { &[ &backend_profile.intern.clips, &backend_profile.intern.prims, + &backend_profile.intern.images, &backend_profile.intern.linear_gradients, &backend_profile.intern.radial_gradients, &backend_profile.intern.text_runs, diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index 69e946288b..8eebae1488 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -34,6 +34,7 @@ use picture::RetainedTiles; use prim_store::{PrimitiveDataStore, PrimitiveScratchBuffer, PrimitiveInstance}; use prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData}; use prim_store::gradient::{LinearGradientDataStore, RadialGradientDataStore}; +use prim_store::image::ImageDataStore; use prim_store::text_run::TextRunDataStore; use profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters}; use record::ApiRecordingReceiver; @@ -205,6 +206,7 @@ pub struct FrameResources { /// Currently active / available primitives. Kept in sync with the /// primitive interner in the scene builder, per document. pub prim_data_store: PrimitiveDataStore, + pub image_data_store: ImageDataStore, pub linear_grad_data_store: LinearGradientDataStore, pub radial_grad_data_store: RadialGradientDataStore, pub text_run_data_store: TextRunDataStore, @@ -222,11 +224,14 @@ impl FrameResources { PrimitiveInstanceKind::ImageBorder { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | PrimitiveInstanceKind::YuvImage { data_handle, .. } | - PrimitiveInstanceKind::Image { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } => { let prim_data = &self.prim_data_store[data_handle]; &prim_data.common } + PrimitiveInstanceKind::Image { data_handle, .. } => { + let prim_data = &self.image_data_store[data_handle]; + &prim_data.common + } PrimitiveInstanceKind::LinearGradient { data_handle, .. } => { let prim_data = &self.linear_grad_data_store[data_handle]; &prim_data.common @@ -1221,6 +1226,10 @@ impl RenderBackend { updates.prim_updates, &mut profile_counters.intern.prims, ); + doc.resources.image_data_store.apply_updates( + updates.image_updates, + &mut profile_counters.intern.images, + ); doc.resources.linear_grad_data_store.apply_updates( updates.linear_grad_updates, &mut profile_counters.intern.linear_gradients, @@ -1712,4 +1721,3 @@ impl RenderBackend { } } } - diff --git a/webrender/src/render_task.rs b/webrender/src/render_task.rs index 433fc4ea0b..167eac94d8 100644 --- a/webrender/src/render_task.rs +++ b/webrender/src/render_task.rs @@ -21,7 +21,8 @@ use gpu_types::{BorderInstance, ImageSource, UvRectKind}; use internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex}; #[cfg(feature = "pathfinder")] use pathfinder_partitioner::mesh::Mesh; -use prim_store::{PictureIndex, ImageCacheKey, LineDecorationCacheKey}; +use prim_store::{PictureIndex, LineDecorationCacheKey}; +use prim_store::image::ImageCacheKey; #[cfg(feature = "debugger")] use print_tree::{PrintTreePrinter}; use render_backend::FrameId; diff --git a/webrender/src/scene_builder.rs b/webrender/src/scene_builder.rs index 13f0bd8b64..817167ddb7 100644 --- a/webrender/src/scene_builder.rs +++ b/webrender/src/scene_builder.rs @@ -20,6 +20,7 @@ use prim_store::gradient::{ LinearGradient, LinearGradientDataInterner, LinearGradientDataUpdateList, RadialGradient, RadialGradientDataInterner, RadialGradientDataUpdateList }; +use prim_store::image::{Image, ImageDataInterner, ImageDataUpdateList}; use prim_store::text_run::{TextRunDataInterner, TextRun, TextRunDataUpdateList}; use resource_cache::{BlobImageRasterizerEpoch, FontInstanceMap}; use render_backend::DocumentView; @@ -35,6 +36,7 @@ use std::time::Duration; pub struct DocumentResourceUpdates { pub clip_updates: ClipDataUpdateList, pub prim_updates: PrimitiveDataUpdateList, + pub image_updates: ImageDataUpdateList, pub linear_grad_updates: LinearGradientDataUpdateList, pub radial_grad_updates: RadialGradientDataUpdateList, pub text_run_updates: TextRunDataUpdateList, @@ -185,6 +187,7 @@ pub enum SceneSwapResult { pub struct DocumentResources { pub clip_interner: ClipDataInterner, pub prim_interner: PrimitiveDataInterner, + pub image_interner: ImageDataInterner, pub linear_grad_interner: LinearGradientDataInterner, pub radial_grad_interner: RadialGradientDataInterner, pub text_run_interner: TextRunDataInterner, @@ -196,31 +199,28 @@ pub trait InternerMut fn interner_mut(&mut self) -> &mut Interner; } -impl InternerMut for DocumentResources { - fn interner_mut(&mut self) -> &mut PrimitiveDataInterner { - &mut self.prim_interner - } -} - -impl InternerMut for DocumentResources { - fn interner_mut(&mut self) -> &mut LinearGradientDataInterner { - &mut self.linear_grad_interner - } -} - -impl InternerMut for DocumentResources { - fn interner_mut(&mut self) -> &mut RadialGradientDataInterner { - &mut self.radial_grad_interner +macro_rules! impl_internet_mut { + ($($ty:ident: $mem:ident,)*) => { + $(impl InternerMut<$ty> for DocumentResources { + fn interner_mut(&mut self) -> &mut Interner< + <$ty as Internable>::Source, + <$ty as Internable>::InternData, + <$ty as Internable>::Marker + > { + &mut self.$mem + } + })* } } -impl InternerMut for DocumentResources { - fn interner_mut(&mut self) -> &mut TextRunDataInterner { - &mut self.text_run_interner - } +impl_internet_mut! { + Image: image_interner, + LinearGradient: linear_grad_interner, + RadialGradient: radial_grad_interner, + TextRun: text_run_interner, + PrimitiveKeyKind: prim_interner, } - // A document in the scene builder contains the current scene, // as well as a persistent clip interner. This allows clips // to be de-duplicated, and persisted in the GPU cache between @@ -391,6 +391,11 @@ impl SceneBuilder { .prim_interner .end_frame_and_get_pending_updates(); + let image_updates = item + .doc_resources + .image_interner + .end_frame_and_get_pending_updates(); + let linear_grad_updates = item .doc_resources .linear_grad_interner @@ -410,6 +415,7 @@ impl SceneBuilder { DocumentResourceUpdates { clip_updates, prim_updates, + image_updates, linear_grad_updates, radial_grad_updates, text_run_updates, @@ -521,6 +527,11 @@ impl SceneBuilder { .prim_interner .end_frame_and_get_pending_updates(); + let image_updates = doc + .resources + .image_interner + .end_frame_and_get_pending_updates(); + let linear_grad_updates = doc .resources .linear_grad_interner @@ -540,6 +551,7 @@ impl SceneBuilder { DocumentResourceUpdates { clip_updates, prim_updates, + image_updates, linear_grad_updates, radial_grad_updates, text_run_updates, From 699dc87668ff9ce1e3883d734e3d7986dd33b470 Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Fri, 7 Dec 2018 14:51:08 +1000 Subject: [PATCH 2/3] Extract YuvImage --- webrender/src/batch.rs | 41 ++--- webrender/src/display_list_flattener.rs | 6 +- webrender/src/picture.rs | 17 +- webrender/src/prim_store/image.rs | 207 +++++++++++++++++++++++- webrender/src/prim_store/mod.rs | 106 +++++------- webrender/src/profiler.rs | 3 + webrender/src/render_backend.rs | 12 +- webrender/src/scene_builder.rs | 20 ++- 8 files changed, 300 insertions(+), 112 deletions(-) diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 243fdd8266..068b9cf45d 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -551,10 +551,10 @@ impl AlphaBatchBuilder { render_tasks, ).unwrap_or(OPAQUE_TASK_ADDRESS); - let prim_data = &ctx.resources.as_common_data(&prim_instance); + let prim_common_data = &ctx.resources.as_common_data(&prim_instance); let prim_rect = LayoutRect::new( prim_instance.prim_origin, - prim_data.prim_size, + prim_common_data.prim_size, ); match prim_instance.kind { @@ -1523,26 +1523,20 @@ impl AlphaBatchBuilder { ); } PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, .. } => { - let prim_data = &ctx.resources.prim_data_store[data_handle]; - let (format, yuv_key, image_rendering, color_depth, color_space) = match prim_data.kind { - PrimitiveTemplateKind::YuvImage { ref format, yuv_key, ref image_rendering, ref color_depth, ref color_space, .. } => { - (format, yuv_key, image_rendering, color_depth, color_space) - } - _ => unreachable!() - }; + let yuv_image_data = &ctx.resources.yuv_image_data_store[data_handle]; let mut textures = BatchTextures::no_texture(); let mut uv_rect_addresses = [0; 3]; //yuv channel - let channel_count = format.get_plane_num(); + let channel_count = yuv_image_data.format.get_plane_num(); debug_assert!(channel_count <= 3); for channel in 0 .. channel_count { - let image_key = yuv_key[channel]; + let image_key = yuv_image_data.yuv_key[channel]; let cache_item = resolve_image( ImageRequest { key: image_key, - rendering: *image_rendering, + rendering: yuv_image_data.image_rendering, tile: None, }, ctx.resource_cache, @@ -1562,16 +1556,16 @@ impl AlphaBatchBuilder { // 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()] + textures.colors[1 .. yuv_image_data.format.get_plane_num()] .iter() .all(|&tid| buffer_kind == get_buffer_kind(tid)) ); let kind = BrushBatchKind::YuvImage( buffer_kind, - *format, - *color_depth, - *color_space, + yuv_image_data.format, + yuv_image_data.color_depth, + yuv_image_data.color_space, ); let batch_params = BrushBatchParameters::shared( @@ -1587,7 +1581,7 @@ impl AlphaBatchBuilder { let specified_blend_mode = BlendMode::PremultipliedAlpha; - let non_segmented_blend_mode = if !prim_data.opacity.is_opaque || + let non_segmented_blend_mode = if !prim_common_data.opacity.is_opaque || prim_instance.clip_task_index != ClipTaskIndex::INVALID || transform_kind == TransformedRectKind::Complex { @@ -1598,7 +1592,7 @@ impl AlphaBatchBuilder { 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) + (gpu_cache.get_address(&prim_common_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]); @@ -1622,7 +1616,7 @@ impl AlphaBatchBuilder { self.add_segmented_prim_to_batch( segments, - prim_data.opacity, + prim_common_data.opacity, &batch_params, specified_blend_mode, non_segmented_blend_mode, @@ -2276,13 +2270,8 @@ impl PrimitiveInstance { image_data.key } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { - let prim_data = &resources.prim_data_store[data_handle]; - match prim_data.kind { - PrimitiveTemplateKind::YuvImage { ref yuv_key, .. } => { - yuv_key[0] - } - _ => unreachable!(), - } + let yuv_image_data = &resources.yuv_image_data_store[data_handle]; + yuv_image_data.yuv_key[0] } PrimitiveInstanceKind::Picture { .. } | PrimitiveInstanceKind::TextRun { .. } | diff --git a/webrender/src/display_list_flattener.rs b/webrender/src/display_list_flattener.rs index 0b125ce00b..ccdac6e6ba 100644 --- a/webrender/src/display_list_flattener.rs +++ b/webrender/src/display_list_flattener.rs @@ -27,7 +27,7 @@ use prim_store::{PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind, NinePa use prim_store::{PrimitiveStore, PrimitiveStoreStats, LineDecorationCacheKey}; use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, get_line_decoration_sizes}; use prim_store::gradient::{GradientStopKey, LinearGradient, RadialGradient, RadialGradientParams}; -use prim_store::image::Image; +use prim_store::image::{Image, YuvImage}; use prim_store::text_run::TextRun; use render_backend::{DocumentView}; use resource_cache::{FontInstanceMap, ImageRequest}; @@ -2449,11 +2449,11 @@ impl<'a> DisplayListFlattener<'a> { YuvData::InterleavedYCbCr(plane_0) => [plane_0, ImageKey::DUMMY, ImageKey::DUMMY], }; - self.add_primitive( + self.add_nonshadowable_primitive( clip_and_scroll, info, Vec::new(), - PrimitiveKeyKind::YuvImage { + YuvImage { color_depth, yuv_key, format, diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index e42a9ccfce..cc72381456 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -21,7 +21,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, CoordinateSpaceMapping, PointKey}; -use prim_store::{OpacityBindingStorage, PrimitiveTemplateKind, ImageInstanceStorage, OpacityBindingIndex, SizeKey}; +use prim_store::{OpacityBindingStorage, ImageInstanceStorage, OpacityBindingIndex, SizeKey}; use print_tree::PrintTreePrinter; use render_backend::FrameResources; use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle, TileBlit}; @@ -825,15 +825,8 @@ impl TileCache { image_keys.push(image_data.key); } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { - let prim_data = &resources.prim_data_store[data_handle]; - match prim_data.kind { - PrimitiveTemplateKind::YuvImage { ref yuv_key, .. } => { - image_keys.extend_from_slice(yuv_key); - } - _ => { - unreachable!(); - } - } + let yuv_image_data = &resources.yuv_image_data_store[data_handle]; + image_keys.extend_from_slice(&yuv_image_data.yuv_key); } PrimitiveInstanceKind::TextRun { .. } | PrimitiveInstanceKind::LineDecoration { .. } | @@ -1403,7 +1396,6 @@ impl PrimitiveList { PrimitiveInstanceKind::NormalBorder { data_handle, .. } | PrimitiveInstanceKind::ImageBorder { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | - PrimitiveInstanceKind::YuvImage { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } => { &resources.prim_interner[data_handle] } @@ -1419,6 +1411,9 @@ impl PrimitiveList { PrimitiveInstanceKind::TextRun { data_handle, .. } => { &resources.text_run_interner[data_handle] } + PrimitiveInstanceKind::YuvImage { data_handle, .. } => { + &resources.yuv_image_interner[data_handle] + } }; // Get the key for the cluster that this primitive should diff --git a/webrender/src/prim_store/image.rs b/webrender/src/prim_store/image.rs index 1085bbfcfe..d49038f332 100644 --- a/webrender/src/prim_store/image.rs +++ b/webrender/src/prim_store/image.rs @@ -3,9 +3,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{ - AlphaType, ColorF, ColorU, DeviceIntRect, DeviceIntSideOffsets, + AlphaType, ColorDepth, ColorF, ColorU, DeviceIntRect, DeviceIntSideOffsets, DeviceIntSize, ImageRendering, LayoutRect, LayoutSize, LayoutPrimitiveInfo, - PremultipliedColorF, Shadow, TileOffset + PremultipliedColorF, Shadow, TileOffset, YuvColorSpace, YuvFormat }; use api::ImageKey as ApiImageKey; use display_list_flattener::{AsInstanceKind, CreateShadow, IsVisible}; @@ -24,6 +24,7 @@ use render_task::{ }; use resource_cache::ImageRequest; use std::ops::{Deref, DerefMut}; +use util::pack_as_float; #[derive(Debug)] #[cfg_attr(feature = "capture", derive(Serialize))] @@ -441,6 +442,205 @@ impl IsVisible for Image { } } +//////////////////////////////////////////////////////////////////////////////// + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct YuvImageKey { + pub common: PrimKeyCommonData, + pub color_depth: ColorDepth, + pub yuv_key: [ApiImageKey; 3], + pub format: YuvFormat, + pub color_space: YuvColorSpace, + pub image_rendering: ImageRendering, +} + +impl YuvImageKey { + pub fn new( + is_backface_visible: bool, + prim_size: LayoutSize, + prim_relative_clip_rect: LayoutRect, + yuv_image: YuvImage, + ) -> Self { + + YuvImageKey { + common: PrimKeyCommonData { + is_backface_visible, + prim_size: prim_size.into(), + prim_relative_clip_rect: prim_relative_clip_rect.into(), + }, + color_depth: yuv_image.color_depth, + yuv_key: yuv_image.yuv_key, + format: yuv_image.format, + color_space: yuv_image.color_space, + image_rendering: yuv_image.image_rendering, + } + } +} + +impl InternDebug for YuvImageKey {} + +impl AsInstanceKind for YuvImageKey { + /// Construct a primitive instance that matches the type + /// of primitive key. + fn as_instance_kind( + &self, + data_handle: YuvImageDataHandle, + _prim_store: &mut PrimitiveStore, + ) -> PrimitiveInstanceKind { + PrimitiveInstanceKind::YuvImage { + data_handle, + segment_instance_index: SegmentInstanceIndex::INVALID + } + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct YuvImageTemplate { + pub common: PrimTemplateCommonData, + pub color_depth: ColorDepth, + pub yuv_key: [ApiImageKey; 3], + pub format: YuvFormat, + pub color_space: YuvColorSpace, + pub image_rendering: ImageRendering, +} + +impl From for YuvImageTemplate { + fn from(item: YuvImageKey) -> Self { + let common = PrimTemplateCommonData::with_key_common(item.common); + + YuvImageTemplate { + common, + color_depth: item.color_depth, + yuv_key: item.yuv_key, + format: item.format, + color_space: item.color_space, + image_rendering: item.image_rendering, + } + } +} + +impl Deref for YuvImageTemplate { + type Target = PrimTemplateCommonData; + fn deref(&self) -> &Self::Target { + &self.common + } +} + +impl DerefMut for YuvImageTemplate { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.common + } +} + +fn write_yuv_image_gpu_blocks( + request: &mut GpuDataRequest, + color_depth: ColorDepth, + format: YuvFormat, + color_space: YuvColorSpace, +) { + request.push([ + color_depth.rescaling_factor(), + pack_as_float(color_space as u32), + pack_as_float(format as u32), + 0.0 + ]); +} + +impl YuvImageTemplate { + /// 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 + /// template. The initial request call to the GPU cache ensures that work is only + /// done if the cache entry is invalid (due to first use or eviction). + pub fn update( + &mut self, + frame_state: &mut FrameBuildingState, + ) { + if let Some(mut request) = + frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) { + // write_prim_gpu_blocks + write_yuv_image_gpu_blocks( + &mut request, + self.color_depth, + self.format, + self.color_space + ); + // write_segment_gpu_blocks + } + + let channel_num = self.format.get_plane_num(); + debug_assert!(channel_num <= 3); + for channel in 0 .. channel_num { + frame_state.resource_cache.request_image( + ImageRequest { + key: self.yuv_key[channel], + rendering: self.image_rendering, + tile: None, + }, + frame_state.gpu_cache, + ); + } + + self.opacity = PrimitiveOpacity::translucent(); + } + + pub fn write_prim_gpu_blocks(&self, request: &mut GpuDataRequest) { + write_yuv_image_gpu_blocks( + request, + self.color_depth, + self.format, + self.color_space, + ); + } +} + +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)] +pub struct YuvImageDataMarker; + +pub type YuvImageDataStore = DataStore; +pub type YuvImageDataHandle = Handle; +pub type YuvImageDataUpdateList = UpdateList; +pub type YuvImageDataInterner = Interner; + +pub struct YuvImage { + pub color_depth: ColorDepth, + pub yuv_key: [ApiImageKey; 3], + pub format: YuvFormat, + pub color_space: YuvColorSpace, + pub image_rendering: ImageRendering, +} + +impl Internable for YuvImage { + type Marker = YuvImageDataMarker; + type Source = YuvImageKey; + type StoreData = YuvImageTemplate; + type InternData = PrimitiveSceneData; + + /// Build a new key from self with `info`. + fn build_key( + self, + info: &LayoutPrimitiveInfo, + prim_relative_clip_rect: LayoutRect, + ) -> YuvImageKey { + YuvImageKey::new( + info.is_backface_visible, + info.rect.size, + prim_relative_clip_rect, + self + ) + } +} + +impl IsVisible for YuvImage { + fn is_visible(&self) -> bool { + true + } +} + #[test] #[cfg(target_os = "linux")] fn test_struct_sizes() { @@ -454,4 +654,7 @@ fn test_struct_sizes() { assert_eq!(mem::size_of::(), 56, "Image size changed"); assert_eq!(mem::size_of::(), 144, "ImageTemplate size changed"); assert_eq!(mem::size_of::(), 84, "ImageKey size changed"); + assert_eq!(mem::size_of::(), 36, "YuvImage size changed"); + assert_eq!(mem::size_of::(), 96, "YuvImageTemplate size changed"); + assert_eq!(mem::size_of::(), 64, "YuvImageKey size changed"); } diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index f53398d822..1920e4abc1 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -4,11 +4,11 @@ use api::{BorderRadius, ClipMode, ColorF, PictureRect, ColorU, LayoutVector2D}; use api::{DeviceIntRect, DevicePixelScale, DeviceRect, LayoutSideOffsetsAu}; -use api::{FilterOp, ImageKey, ImageRendering, TileOffset, RepeatMode, MixBlendMode}; +use api::{FilterOp, ImageRendering, TileOffset, RepeatMode, MixBlendMode}; use api::{LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, PropertyBindingId}; -use api::{PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat}; +use api::{PremultipliedColorF, PropertyBinding, Shadow}; use api::{WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale}; -use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers}; +use api::{PicturePixel, RasterPixel, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers}; use api::LayoutPrimitiveInfo; use app_units::Au; use border::{get_max_scale_for_border, build_border_instances, create_border_segments}; @@ -28,7 +28,7 @@ use intern; use picture::{PictureCompositeMode, PicturePrimitive, PictureUpdateState, TileCacheUpdateState}; use picture::{ClusterRange, PrimitiveList, SurfaceIndex, SurfaceInfo, RetainedTiles, RasterConfig}; use prim_store::gradient::{LinearGradientDataHandle, RadialGradientDataHandle}; -use prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile}; +use prim_store::image::{ImageDataHandle, ImageInstance, VisibleImageTile, YuvImageDataHandle}; use prim_store::text_run::{TextRunDataHandle, TextRunPrimitive}; #[cfg(debug_assertions)] use render_backend::{FrameId}; @@ -482,13 +482,6 @@ pub enum PrimitiveKeyKind { Rectangle { color: ColorU, }, - YuvImage { - color_depth: ColorDepth, - yuv_key: [ImageKey; 3], - format: YuvFormat, - color_space: YuvColorSpace, - image_rendering: ImageRendering, - }, Picture { composite_mode_key: PictureCompositeKey, }, @@ -786,12 +779,6 @@ impl AsInstanceKind for PrimitiveKey { segment_instance_index: SegmentInstanceIndex::INVALID, } } - PrimitiveKeyKind::YuvImage { .. } => { - PrimitiveInstanceKind::YuvImage { - data_handle, - segment_instance_index: SegmentInstanceIndex::INVALID - } - } PrimitiveKeyKind::Picture { .. } => { // Should never be hit as this method should not be // called for pictures. @@ -829,13 +816,6 @@ pub enum PrimitiveTemplateKind { Rectangle { color: ColorF, }, - YuvImage { - color_depth: ColorDepth, - yuv_key: [ImageKey; 3], - format: YuvFormat, - color_space: YuvColorSpace, - image_rendering: ImageRendering, - }, Clear, Picture { @@ -903,15 +883,6 @@ 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, @@ -1035,14 +1006,6 @@ impl PrimitiveTemplateKind { } } } - PrimitiveTemplateKind::YuvImage { color_depth, format, color_space, .. } => { - request.push([ - color_depth.rescaling_factor(), - pack_as_float(color_space as u32), - pack_as_float(format as u32), - 0.0 - ]); - } PrimitiveTemplateKind::Picture { .. } => {} } } @@ -1073,7 +1036,6 @@ impl PrimitiveTemplateKind { PrimitiveTemplateKind::Clear | PrimitiveTemplateKind::LineDecoration { .. } | PrimitiveTemplateKind::Rectangle { .. } | - PrimitiveTemplateKind::YuvImage { .. } | PrimitiveTemplateKind::Picture { .. } => {} } } @@ -1130,22 +1092,6 @@ impl PrimitiveTemplate { None => PrimitiveOpacity::from_alpha(color.a), } } - 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() - } PrimitiveTemplateKind::Picture { .. } => { PrimitiveOpacity::translucent() } @@ -1603,7 +1549,6 @@ impl IsVisible for PrimitiveKeyKind { match *self { PrimitiveKeyKind::NormalBorder { .. } | PrimitiveKeyKind::ImageBorder { .. } | - PrimitiveKeyKind::YuvImage { .. } | PrimitiveKeyKind::Clear | PrimitiveKeyKind::Picture { .. } => { true @@ -1644,7 +1589,6 @@ impl CreateShadow for PrimitiveKeyKind { } } PrimitiveKeyKind::ImageBorder { .. } | - PrimitiveKeyKind::YuvImage { .. } | PrimitiveKeyKind::Picture { .. } | PrimitiveKeyKind::Clear => { panic!("bug: this prim is not supported in shadow contexts"); @@ -1705,7 +1649,7 @@ pub enum PrimitiveInstanceKind { }, YuvImage { /// Handle to the common interned data for this primitive. - data_handle: PrimitiveDataHandle, + data_handle: YuvImageDataHandle, segment_instance_index: SegmentInstanceIndex, }, Image { @@ -1816,8 +1760,7 @@ impl PrimitiveInstance { PrimitiveInstanceKind::Clear { data_handle, .. } | PrimitiveInstanceKind::NormalBorder { data_handle, .. } | PrimitiveInstanceKind::ImageBorder { data_handle, .. } | - PrimitiveInstanceKind::Rectangle { data_handle, .. } | - PrimitiveInstanceKind::YuvImage { data_handle, .. } => { + PrimitiveInstanceKind::Rectangle { data_handle, .. } => { data_handle.uid() } PrimitiveInstanceKind::Image { data_handle, .. } => { @@ -1832,6 +1775,9 @@ impl PrimitiveInstance { PrimitiveInstanceKind::TextRun { data_handle, .. } => { data_handle.uid() } + PrimitiveInstanceKind::YuvImage { data_handle, .. } => { + data_handle.uid() + } } } } @@ -2860,13 +2806,35 @@ impl PrimitiveStore { write_segment(prim_data, *segment_instance_index, frame_state, scratch); } PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, .. } => { - let prim_data = &mut resources.prim_data_store[*data_handle]; + let yuv_image_data = &mut resources.yuv_image_data_store[*data_handle]; // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - prim_data.update(frame_state); + yuv_image_data.update(frame_state); - write_segment(prim_data, *segment_instance_index, frame_state, scratch); + // write_segment(yuv_image_data, *segment_instance_index, frame_state, scratch); + 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]; + + yuv_image_data.write_prim_gpu_blocks(&mut request); + + for segment in segments { + request.write_segment( + segment.local_rect, + [0.0; 4], + ); + } + } + } } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { let image_data = &mut resources.image_data_store[*data_handle]; @@ -2979,7 +2947,11 @@ impl PrimitiveStore { let segment_instance = &mut scratch.segment_instances[image_instance.segment_instance_index]; - if let Some(mut request) = frame_state.gpu_cache.request(&mut segment_instance.gpu_cache_handle) { + if let Some(mut request) = + frame_state + .gpu_cache + .request(&mut segment_instance.gpu_cache_handle) + { let segments = &scratch.segments[segment_instance.segments_range]; image_data.write_prim_gpu_blocks(&mut request); diff --git a/webrender/src/profiler.rs b/webrender/src/profiler.rs index 066dca4bbd..d4767aeb6a 100644 --- a/webrender/src/profiler.rs +++ b/webrender/src/profiler.rs @@ -408,6 +408,7 @@ pub struct InternProfileCounters { pub linear_gradients: ResourceProfileCounter, pub radial_gradients: ResourceProfileCounter, pub text_runs: ResourceProfileCounter, + pub yuv_images: ResourceProfileCounter, pub clips: ResourceProfileCounter, } @@ -455,6 +456,7 @@ impl BackendProfileCounters { linear_gradients: ResourceProfileCounter::new("Interned linear gradients"), radial_gradients: ResourceProfileCounter::new("Interned radial gradients"), text_runs: ResourceProfileCounter::new("Interned text runs"), + yuv_images: ResourceProfileCounter::new("Interned YUV images"), clips: ResourceProfileCounter::new("Interned clips"), }, } @@ -1109,6 +1111,7 @@ impl Profiler { &backend_profile.intern.linear_gradients, &backend_profile.intern.radial_gradients, &backend_profile.intern.text_runs, + &backend_profile.intern.yuv_images, ], debug_renderer, true, diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index 8eebae1488..c01e2fbbda 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -34,7 +34,7 @@ use picture::RetainedTiles; use prim_store::{PrimitiveDataStore, PrimitiveScratchBuffer, PrimitiveInstance}; use prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData}; use prim_store::gradient::{LinearGradientDataStore, RadialGradientDataStore}; -use prim_store::image::ImageDataStore; +use prim_store::image::{ImageDataStore, YuvImageDataStore}; use prim_store::text_run::TextRunDataStore; use profiler::{BackendProfileCounters, IpcProfileCounters, ResourceProfileCounters}; use record::ApiRecordingReceiver; @@ -210,6 +210,7 @@ pub struct FrameResources { pub linear_grad_data_store: LinearGradientDataStore, pub radial_grad_data_store: RadialGradientDataStore, pub text_run_data_store: TextRunDataStore, + pub yuv_image_data_store: YuvImageDataStore, } impl FrameResources { @@ -223,7 +224,6 @@ impl FrameResources { PrimitiveInstanceKind::NormalBorder { data_handle, .. } | PrimitiveInstanceKind::ImageBorder { data_handle, .. } | PrimitiveInstanceKind::Rectangle { data_handle, .. } | - PrimitiveInstanceKind::YuvImage { data_handle, .. } | PrimitiveInstanceKind::Clear { data_handle, .. } => { let prim_data = &self.prim_data_store[data_handle]; &prim_data.common @@ -244,6 +244,10 @@ impl FrameResources { let prim_data = &self.text_run_data_store[data_handle]; &prim_data.common } + PrimitiveInstanceKind::YuvImage { data_handle, .. } => { + let prim_data = &self.yuv_image_data_store[data_handle]; + &prim_data.common + } } } } @@ -1242,6 +1246,10 @@ impl RenderBackend { updates.text_run_updates, &mut profile_counters.intern.text_runs, ); + doc.resources.yuv_image_data_store.apply_updates( + updates.yuv_image_updates, + &mut profile_counters.intern.yuv_images, + ); } // TODO: this scroll variable doesn't necessarily mean we scrolled. It is only used diff --git a/webrender/src/scene_builder.rs b/webrender/src/scene_builder.rs index 817167ddb7..040a9943d8 100644 --- a/webrender/src/scene_builder.rs +++ b/webrender/src/scene_builder.rs @@ -20,7 +20,10 @@ use prim_store::gradient::{ LinearGradient, LinearGradientDataInterner, LinearGradientDataUpdateList, RadialGradient, RadialGradientDataInterner, RadialGradientDataUpdateList }; -use prim_store::image::{Image, ImageDataInterner, ImageDataUpdateList}; +use prim_store::image::{ + Image, ImageDataInterner, ImageDataUpdateList, + YuvImage, YuvImageDataInterner, YuvImageDataUpdateList, +}; use prim_store::text_run::{TextRunDataInterner, TextRun, TextRunDataUpdateList}; use resource_cache::{BlobImageRasterizerEpoch, FontInstanceMap}; use render_backend::DocumentView; @@ -40,6 +43,7 @@ pub struct DocumentResourceUpdates { pub linear_grad_updates: LinearGradientDataUpdateList, pub radial_grad_updates: RadialGradientDataUpdateList, pub text_run_updates: TextRunDataUpdateList, + pub yuv_image_updates: YuvImageDataUpdateList, } /// Represents the work associated to a transaction before scene building. @@ -191,6 +195,7 @@ pub struct DocumentResources { pub linear_grad_interner: LinearGradientDataInterner, pub radial_grad_interner: RadialGradientDataInterner, pub text_run_interner: TextRunDataInterner, + pub yuv_image_interner: YuvImageDataInterner, } // Access to `DocumentResources` interners by `Internable` @@ -219,6 +224,7 @@ impl_internet_mut! { RadialGradient: radial_grad_interner, TextRun: text_run_interner, PrimitiveKeyKind: prim_interner, + YuvImage: yuv_image_interner, } // A document in the scene builder contains the current scene, @@ -411,6 +417,11 @@ impl SceneBuilder { .text_run_interner .end_frame_and_get_pending_updates(); + let yuv_image_updates = item + .doc_resources + .yuv_image_interner + .end_frame_and_get_pending_updates(); + doc_resource_updates = Some( DocumentResourceUpdates { clip_updates, @@ -419,6 +430,7 @@ impl SceneBuilder { linear_grad_updates, radial_grad_updates, text_run_updates, + yuv_image_updates, } ); @@ -547,6 +559,11 @@ impl SceneBuilder { .text_run_interner .end_frame_and_get_pending_updates(); + let yuv_image_updates = doc + .resources + .yuv_image_interner + .end_frame_and_get_pending_updates(); + doc_resource_updates = Some( DocumentResourceUpdates { clip_updates, @@ -555,6 +572,7 @@ impl SceneBuilder { linear_grad_updates, radial_grad_updates, text_run_updates, + yuv_image_updates, } ); From 0541e3c7eafc463bcfba7b1917fa2d5c9eca9eb4 Mon Sep 17 00:00:00 2001 From: Dan Glastonbury Date: Mon, 17 Dec 2018 11:22:45 +1000 Subject: [PATCH 3/3] Share common implementation of write_segment --- webrender/src/batch.rs | 14 +- webrender/src/picture.rs | 4 +- webrender/src/prim_store/image.rs | 249 ++++++++++-------------------- webrender/src/prim_store/mod.rs | 95 +++++------- 4 files changed, 133 insertions(+), 229 deletions(-) diff --git a/webrender/src/batch.rs b/webrender/src/batch.rs index 068b9cf45d..1e6225babc 100644 --- a/webrender/src/batch.rs +++ b/webrender/src/batch.rs @@ -1523,7 +1523,7 @@ impl AlphaBatchBuilder { ); } PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, .. } => { - let yuv_image_data = &ctx.resources.yuv_image_data_store[data_handle]; + let yuv_image_data = &ctx.resources.yuv_image_data_store[data_handle].kind; let mut textures = BatchTextures::no_texture(); let mut uv_rect_addresses = [0; 3]; @@ -1631,7 +1631,8 @@ impl AlphaBatchBuilder { ); } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { - let image_data = &ctx.resources.image_data_store[data_handle]; + let image_data = &ctx.resources.image_data_store[data_handle].kind; + let common_data = &ctx.resources.image_data_store[data_handle].common; let image_instance = &ctx.prim_store.images[image_instance_index]; let opacity_binding = ctx.prim_store.get_opacity_binding(image_instance.opacity_binding_index); let specified_blend_mode = match image_data.alpha_type { @@ -1671,7 +1672,7 @@ impl AlphaBatchBuilder { let textures = BatchTextures::color(cache_item.texture_id); let opacity = PrimitiveOpacity::from_alpha(opacity_binding); - let opacity = opacity.combine(image_data.opacity); + let opacity = opacity.combine(common_data.opacity); let non_segmented_blend_mode = if !opacity.is_opaque || prim_instance.clip_task_index != ClipTaskIndex::INVALID || @@ -1695,7 +1696,7 @@ impl AlphaBatchBuilder { debug_assert!(image_instance.segment_instance_index != SegmentInstanceIndex::INVALID); let (prim_cache_address, segments) = if image_instance.segment_instance_index == SegmentInstanceIndex::UNUSED { - (gpu_cache.get_address(&image_data.gpu_cache_handle), None) + (gpu_cache.get_address(&common_data.gpu_cache_handle), None) } else { let segment_instance = &ctx.scratch.segment_instances[image_instance.segment_instance_index]; let segments = Some(&ctx.scratch.segments[segment_instance.segments_range]); @@ -2266,11 +2267,12 @@ impl PrimitiveInstance { ) -> bool { let image_key = match self.kind { PrimitiveInstanceKind::Image { data_handle, .. } => { - let image_data = &resources.image_data_store[data_handle]; + let image_data = &resources.image_data_store[data_handle].kind; image_data.key } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { - let yuv_image_data = &resources.yuv_image_data_store[data_handle]; + let yuv_image_data = + &resources.yuv_image_data_store[data_handle].kind; yuv_image_data.yuv_key[0] } PrimitiveInstanceKind::Picture { .. } | diff --git a/webrender/src/picture.rs b/webrender/src/picture.rs index cc72381456..de351a8f9c 100644 --- a/webrender/src/picture.rs +++ b/webrender/src/picture.rs @@ -809,7 +809,7 @@ impl TileCache { } } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { - let image_data = &resources.image_data_store[data_handle]; + let image_data = &resources.image_data_store[data_handle].kind; let image_instance = &image_instances[image_instance_index]; let opacity_binding_index = image_instance.opacity_binding_index; @@ -825,7 +825,7 @@ impl TileCache { image_keys.push(image_data.key); } PrimitiveInstanceKind::YuvImage { data_handle, .. } => { - let yuv_image_data = &resources.yuv_image_data_store[data_handle]; + let yuv_image_data = &resources.yuv_image_data_store[data_handle].kind; image_keys.extend_from_slice(&yuv_image_data.yuv_key); } PrimitiveInstanceKind::TextRun { .. } | diff --git a/webrender/src/prim_store/image.rs b/webrender/src/prim_store/image.rs index d49038f332..883ed35faf 100644 --- a/webrender/src/prim_store/image.rs +++ b/webrender/src/prim_store/image.rs @@ -15,15 +15,15 @@ use intern::{DataStore, Handle, Internable, Interner, InternDebug, UpdateList}; use picture::SurfaceIndex; use prim_store::{ EdgeAaSegmentMask, OpacityBindingIndex, PrimitiveInstanceKind, - PrimitiveOpacity, PrimitiveSceneData, PrimKeyCommonData, - PrimTemplateCommonData, PrimitiveStore, SegmentInstanceIndex, SizeKey + PrimitiveOpacity, PrimitiveSceneData, PrimKey, PrimKeyCommonData, + PrimTemplate, PrimTemplateCommonData, PrimitiveStore, SegmentInstanceIndex, + SizeKey }; use render_task::{ BlitSource, RenderTask, RenderTaskCacheEntryHandle, RenderTaskCacheKey, RenderTaskCacheKeyKind }; use resource_cache::ImageRequest; -use std::ops::{Deref, DerefMut}; use util::pack_as_float; #[derive(Debug)] @@ -69,8 +69,7 @@ pub struct ImageInstance { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct ImageKey { - pub common: PrimKeyCommonData, +pub struct Image { pub key: ApiImageKey, pub stretch_size: SizeKey, pub tile_spacing: SizeKey, @@ -80,6 +79,8 @@ pub struct ImageKey { pub alpha_type: AlphaType, } +pub type ImageKey = PrimKey; + impl ImageKey { pub fn new( is_backface_visible: bool, @@ -94,13 +95,7 @@ impl ImageKey { prim_size: prim_size.into(), prim_relative_clip_rect: prim_relative_clip_rect.into(), }, - key: image.key, - color: image.color.into(), - stretch_size: image.stretch_size.into(), - tile_spacing: image.tile_spacing.into(), - sub_rect: image.sub_rect, - image_rendering: image.image_rendering, - alpha_type: image.alpha_type, + kind: image, } } } @@ -147,8 +142,7 @@ pub enum ImageSource { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct ImageTemplate { - pub common: PrimTemplateCommonData, +pub struct ImageData { pub key: ApiImageKey, pub stretch_size: LayoutSize, pub tile_spacing: LayoutSize, @@ -159,59 +153,22 @@ pub struct ImageTemplate { pub alpha_type: AlphaType, } -impl From for ImageTemplate { - fn from(item: ImageKey) -> Self { - let common = PrimTemplateCommonData::with_key_common(item.common); - let color = item.color.into(); - let stretch_size = item.stretch_size.into(); - let tile_spacing = item.tile_spacing.into(); - - ImageTemplate { - common, - key: item.key, - color, - stretch_size, - tile_spacing, +impl From for ImageData { + fn from(image: Image) -> Self { + ImageData { + key: image.key, + color: image.color.into(), + stretch_size: image.stretch_size.into(), + tile_spacing: image.tile_spacing.into(), source: ImageSource::Default, - sub_rect: item.sub_rect, - image_rendering: item.image_rendering, - alpha_type: item.alpha_type, + sub_rect: image.sub_rect, + image_rendering: image.image_rendering, + alpha_type: image.alpha_type, } } } -impl Deref for ImageTemplate { - type Target = PrimTemplateCommonData; - fn deref(&self) -> &Self::Target { - &self.common - } -} - -impl DerefMut for ImageTemplate { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.common - } -} - -fn write_image_gpu_blocks( - request: &mut GpuDataRequest, - color: ColorF, - stretch_size: LayoutSize, - tile_spacing: LayoutSize, -) { - // Images are drawn as a white color, modulated by the total - // opacity coming from any collapsed property bindings. - request.push(color.premultiplied()); - request.push(PremultipliedColorF::WHITE); - request.push([ - stretch_size.width + tile_spacing.width, - stretch_size.height + tile_spacing.height, - 0.0, - 0.0, - ]); -} - -impl ImageTemplate { +impl ImageData { /// 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 /// template. The initial request call to the GPU cache ensures that work is only @@ -224,21 +181,14 @@ impl ImageTemplate { // allowing render task caching to assign to surfaces implicitly // during pass allocation. surface_index: SurfaceIndex, + common: &mut PrimTemplateCommonData, frame_state: &mut FrameBuildingState, ) { - if let Some(mut request) = - frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) { - write_image_gpu_blocks( - &mut request, - self.color, - self.stretch_size, - self.tile_spacing - ); - - // write_segment_gpu_blocks - } + if let Some(mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) { + self.write_prim_gpu_blocks(&mut request); + } - self.opacity = { + common.opacity = { let image_properties = frame_state .resource_cache .get_image_properties(self.key); @@ -372,12 +322,29 @@ impl ImageTemplate { } pub fn write_prim_gpu_blocks(&self, request: &mut GpuDataRequest) { - write_image_gpu_blocks( - request, - self.color, - self.stretch_size, - self.tile_spacing - ); + // Images are drawn as a white color, modulated by the total + // opacity coming from any collapsed property bindings. + request.push(self.color.premultiplied()); + request.push(PremultipliedColorF::WHITE); + request.push([ + self.stretch_size.width + self.tile_spacing.width, + self.stretch_size.height + self.tile_spacing.height, + 0.0, + 0.0, + ]); + } +} + +pub type ImageTemplate = PrimTemplate; + +impl From for ImageTemplate { + fn from(image: ImageKey) -> Self { + let common = PrimTemplateCommonData::with_key_common(image.common); + + ImageTemplate { + common, + kind: image.kind.into(), + } } } @@ -391,16 +358,6 @@ pub type ImageDataHandle = Handle; pub type ImageDataUpdateList = UpdateList; pub type ImageDataInterner = Interner; -pub struct Image { - pub key: ApiImageKey, - pub stretch_size: SizeKey, - pub tile_spacing: SizeKey, - pub color: ColorU, - pub sub_rect: Option, - pub image_rendering: ImageRendering, - pub alpha_type: AlphaType, -} - impl Internable for Image { type Marker = ImageDataMarker; type Source = ImageKey; @@ -447,8 +404,7 @@ impl IsVisible for Image { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub struct YuvImageKey { - pub common: PrimKeyCommonData, +pub struct YuvImage { pub color_depth: ColorDepth, pub yuv_key: [ApiImageKey; 3], pub format: YuvFormat, @@ -456,6 +412,8 @@ pub struct YuvImageKey { pub image_rendering: ImageRendering, } +pub type YuvImageKey = PrimKey; + impl YuvImageKey { pub fn new( is_backface_visible: bool, @@ -470,11 +428,7 @@ impl YuvImageKey { prim_size: prim_size.into(), prim_relative_clip_rect: prim_relative_clip_rect.into(), }, - color_depth: yuv_image.color_depth, - yuv_key: yuv_image.yuv_key, - format: yuv_image.format, - color_space: yuv_image.color_space, - image_rendering: yuv_image.image_rendering, + kind: yuv_image, } } } @@ -498,8 +452,7 @@ impl AsInstanceKind for YuvImageKey { #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct YuvImageTemplate { - pub common: PrimTemplateCommonData, +pub struct YuvImageData { pub color_depth: ColorDepth, pub yuv_key: [ApiImageKey; 3], pub format: YuvFormat, @@ -507,68 +460,31 @@ pub struct YuvImageTemplate { pub image_rendering: ImageRendering, } -impl From for YuvImageTemplate { - fn from(item: YuvImageKey) -> Self { - let common = PrimTemplateCommonData::with_key_common(item.common); - - YuvImageTemplate { - common, - color_depth: item.color_depth, - yuv_key: item.yuv_key, - format: item.format, - color_space: item.color_space, - image_rendering: item.image_rendering, +impl From for YuvImageData { + fn from(image: YuvImage) -> Self { + YuvImageData { + color_depth: image.color_depth, + yuv_key: image.yuv_key, + format: image.format, + color_space: image.color_space, + image_rendering: image.image_rendering, } } } -impl Deref for YuvImageTemplate { - type Target = PrimTemplateCommonData; - fn deref(&self) -> &Self::Target { - &self.common - } -} - -impl DerefMut for YuvImageTemplate { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.common - } -} - -fn write_yuv_image_gpu_blocks( - request: &mut GpuDataRequest, - color_depth: ColorDepth, - format: YuvFormat, - color_space: YuvColorSpace, -) { - request.push([ - color_depth.rescaling_factor(), - pack_as_float(color_space as u32), - pack_as_float(format as u32), - 0.0 - ]); -} - -impl YuvImageTemplate { +impl YuvImageData { /// 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 /// template. The initial request call to the GPU cache ensures that work is only /// done if the cache entry is invalid (due to first use or eviction). pub fn update( &mut self, + common: &mut PrimTemplateCommonData, frame_state: &mut FrameBuildingState, ) { - if let Some(mut request) = - frame_state.gpu_cache.request(&mut self.common.gpu_cache_handle) { - // write_prim_gpu_blocks - write_yuv_image_gpu_blocks( - &mut request, - self.color_depth, - self.format, - self.color_space - ); - // write_segment_gpu_blocks - } + if let Some(mut request) = frame_state.gpu_cache.request(&mut common.gpu_cache_handle) { + self.write_prim_gpu_blocks(&mut request); + }; let channel_num = self.format.get_plane_num(); debug_assert!(channel_num <= 3); @@ -583,16 +499,29 @@ impl YuvImageTemplate { ); } - self.opacity = PrimitiveOpacity::translucent(); + common.opacity = PrimitiveOpacity::translucent(); } pub fn write_prim_gpu_blocks(&self, request: &mut GpuDataRequest) { - write_yuv_image_gpu_blocks( - request, - self.color_depth, - self.format, - self.color_space, - ); + request.push([ + self.color_depth.rescaling_factor(), + pack_as_float(self.color_space as u32), + pack_as_float(self.format as u32), + 0.0 + ]); + } +} + +pub type YuvImageTemplate = PrimTemplate; + +impl From for YuvImageTemplate { + fn from(image: YuvImageKey) -> Self { + let common = PrimTemplateCommonData::with_key_common(image.common); + + YuvImageTemplate { + common, + kind: image.kind.into(), + } } } @@ -606,14 +535,6 @@ pub type YuvImageDataHandle = Handle; pub type YuvImageDataUpdateList = UpdateList; pub type YuvImageDataInterner = Interner; -pub struct YuvImage { - pub color_depth: ColorDepth, - pub yuv_key: [ApiImageKey; 3], - pub format: YuvFormat, - pub color_space: YuvColorSpace, - pub image_rendering: ImageRendering, -} - impl Internable for YuvImage { type Marker = YuvImageDataMarker; type Source = YuvImageKey; diff --git a/webrender/src/prim_store/mod.rs b/webrender/src/prim_store/mod.rs index 1920e4abc1..af5fc61a83 100644 --- a/webrender/src/prim_store/mod.rs +++ b/webrender/src/prim_store/mod.rs @@ -713,6 +713,14 @@ impl PrimKeyCommonData { } } +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct PrimKey { + pub common: PrimKeyCommonData, + pub kind: T, +} + #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Debug, Clone, Eq, PartialEq, Hash)] @@ -919,6 +927,13 @@ impl PrimTemplateCommonData { } } +#[cfg_attr(feature = "capture", derive(Serialize))] +#[cfg_attr(feature = "replay", derive(Deserialize))] +pub struct PrimTemplate { + pub common: PrimTemplateCommonData, + pub kind: T, +} + #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct PrimitiveTemplate { @@ -2803,46 +2818,34 @@ impl PrimitiveStore { frame_context.scene_properties, ); - write_segment(prim_data, *segment_instance_index, frame_state, scratch); + write_segment(*segment_instance_index, frame_state, scratch, |request| { + prim_data.kind.write_prim_gpu_blocks( + request, + prim_data.prim_size, + ); + }); } PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, .. } => { let yuv_image_data = &mut resources.yuv_image_data_store[*data_handle]; // Update the template this instane references, which may refresh the GPU // cache with any shared template data. - yuv_image_data.update(frame_state); - - // write_segment(yuv_image_data, *segment_instance_index, frame_state, scratch); - 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]; - - yuv_image_data.write_prim_gpu_blocks(&mut request); - - for segment in segments { - request.write_segment( - segment.local_rect, - [0.0; 4], - ); - } - } - } + yuv_image_data.kind.update(&mut yuv_image_data.common, frame_state); + + write_segment(*segment_instance_index, frame_state, scratch, |request| { + yuv_image_data.kind.write_prim_gpu_blocks(request); + }); } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { - let image_data = &mut resources.image_data_store[*data_handle]; + let prim_data = &mut resources.image_data_store[*data_handle]; + let common_data = &mut prim_data.common; + let image_data = &mut prim_data.kind; // Update the template this instane references, which may refresh the GPU // cache with any shared template data. image_data.update( pic_context.surface_index, + common_data, frame_state, ); @@ -2942,28 +2945,9 @@ impl PrimitiveStore { } } - //write_segment(image_data, image_instance.segment_instance_index, frame_state, scratch); - if image_instance.segment_instance_index != SegmentInstanceIndex::UNUSED { - let segment_instance = - &mut scratch.segment_instances[image_instance.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]; - - image_data.write_prim_gpu_blocks(&mut request); - - for segment in segments { - request.write_segment( - segment.local_rect, - [0.0; 4], - ); - } - } - } + write_segment(image_instance.segment_instance_index, frame_state, scratch, |request| { + image_data.write_prim_gpu_blocks(request); + }); } PrimitiveInstanceKind::LinearGradient { data_handle, ref mut visible_tiles_range, .. } => { let prim_data = &mut resources.linear_grad_data_store[*data_handle]; @@ -3054,12 +3038,12 @@ impl PrimitiveStore { } } -fn write_segment( - prim_data: &PrimitiveTemplate, +fn write_segment( segment_instance_index: SegmentInstanceIndex, frame_state: &mut FrameBuildingState, scratch: &mut PrimitiveScratchBuffer, -) { + f: F, +) where F: Fn(&mut GpuDataRequest) { debug_assert!(segment_instance_index != SegmentInstanceIndex::INVALID); if segment_instance_index != SegmentInstanceIndex::UNUSED { let segment_instance = &mut scratch.segment_instances[segment_instance_index]; @@ -3067,10 +3051,7 @@ fn write_segment( 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_size, - ); + f(&mut request); for segment in segments { request.write_segment( @@ -3328,7 +3309,7 @@ impl PrimitiveInstance { segment_instance_index } PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { - let image_data = &resources.image_data_store[data_handle]; + let image_data = &resources.image_data_store[data_handle].kind; let image_instance = &mut prim_store.images[image_instance_index]; // tiled images don't support segmentation if frame_state