author | Brindusan Cristian <cbrindusan@mozilla.com> |
Tue, 28 Apr 2020 21:33:46 +0300 | |
changeset 526531 | e2443fd2a90eefa69f90be194992a6a7bdcbd7b7 |
parent 526530 | 087beda838b249ad2c13941e7281fd2c319de018 |
child 526532 | c05ab5081644fb276cc8ddb76c6dca040a64747f |
push id | 37358 |
push user | opoprus@mozilla.com |
push date | Wed, 29 Apr 2020 03:05:14 +0000 |
treeherder | mozilla-central@6bb8423186c1 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1628175, 817019 |
milestone | 77.0a1 |
backs out | 8433832c8f09d6787fe9157fad5a08cd8de3ff44 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/CompositorTypes.h +++ b/gfx/layers/CompositorTypes.h @@ -74,23 +74,19 @@ enum class TextureFlags : uint32_t { // The texture is used for snapshot. SNAPSHOT = 1 << 14, // Enable a non blocking read lock. NON_BLOCKING_READ_LOCK = 1 << 15, // Enable a blocking read lock. BLOCKING_READ_LOCK = 1 << 16, // Keep TextureClient alive when host side is used WAIT_HOST_USAGE_END = 1 << 17, - // The texture is guaranteed to have alpha 1.0 everywhere; some backends - // have trouble with RGBX/BGRX formats, so we use RGBA/BGRA but set this - // hint when we know alpha is opaque (eg. WebGL) - IS_OPAQUE = 1 << 18, // OR union of all valid bits - ALL_BITS = (1 << 19) - 1, + ALL_BITS = (1 << 18) - 1, // the default flags DEFAULT = NO_FLAGS }; MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TextureFlags) static inline bool TextureRequiresLocking(TextureFlags aFlags) { // If we're not double buffered, or uploading // within a transaction, then we need to support
--- a/gfx/layers/ShareableCanvasRenderer.cpp +++ b/gfx/layers/ShareableCanvasRenderer.cpp @@ -46,19 +46,16 @@ void ShareableCanvasRenderer::Initialize auto forwarder = GetForwarder(); mFlags = TextureFlags::ORIGIN_BOTTOM_LEFT; if (!aData.mIsGLAlphaPremult) { mFlags |= TextureFlags::NON_PREMULTIPLIED; } - if (!aData.mHasAlpha) { - mFlags |= TextureFlags::IS_OPAQUE; - } UniquePtr<gl::SurfaceFactory> factory = gl::GLScreenBuffer::CreateFactory(mGLContext, caps, forwarder, mFlags); if (factory) { screen->Morph(std::move(factory)); } } void ShareableCanvasRenderer::ClearCachedResources() {
--- a/gfx/layers/client/ClientCanvasRenderer.cpp +++ b/gfx/layers/client/ClientCanvasRenderer.cpp @@ -17,20 +17,16 @@ CompositableForwarder* ClientCanvasRende bool ClientCanvasRenderer::CreateCompositable() { if (!mCanvasClient) { TextureFlags flags = TextureFlags::DEFAULT; if (mOriginPos == gl::OriginPos::BottomLeft) { flags |= TextureFlags::ORIGIN_BOTTOM_LEFT; } - if (IsOpaque()) { - flags |= TextureFlags::IS_OPAQUE; - } - if (!mIsAlphaPremultiplied) { flags |= TextureFlags::NON_PREMULTIPLIED; } mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(), GetForwarder(), flags); if (!mCanvasClient) { return false;
--- a/gfx/layers/wr/AsyncImagePipelineManager.cpp +++ b/gfx/layers/wr/AsyncImagePipelineManager.cpp @@ -391,24 +391,19 @@ void AsyncImagePipelineManager::ApplyAsy if (aPipeline->mScaleToSize.isSome()) { rect = LayoutDeviceRect(0, 0, aPipeline->mScaleToSize.value().width, aPipeline->mScaleToSize.value().height); } if (aPipeline->mUseExternalImage) { MOZ_ASSERT(aPipeline->mCurrentTexture->AsWebRenderTextureHost()); Range<wr::ImageKey> range_keys(&keys[0], keys.Length()); - bool prefer_compositor_surface = - IsOpaque(aPipeline->mCurrentTexture->GetFormat()) || - bool(aPipeline->mCurrentTexture->GetFlags() & - TextureFlags::IS_OPAQUE); aPipeline->mCurrentTexture->PushDisplayItems( builder, wr::ToLayoutRect(rect), wr::ToLayoutRect(rect), - aPipeline->mFilter, range_keys, - /* aPreferCompositorSurface */ prefer_compositor_surface); + aPipeline->mFilter, range_keys, /* aPreferCompositorSurface */ true); HoldExternalImage(aPipelineId, aEpoch, aPipeline->mCurrentTexture); } else { MOZ_ASSERT(keys.Length() == 1); builder.PushImage(wr::ToLayoutRect(rect), wr::ToLayoutRect(rect), true, aPipeline->mFilter, keys[0]); } }
--- a/gfx/layers/wr/WebRenderCanvasRenderer.cpp +++ b/gfx/layers/wr/WebRenderCanvasRenderer.cpp @@ -35,20 +35,16 @@ void WebRenderCanvasRendererAsync::Initi bool WebRenderCanvasRendererAsync::CreateCompositable() { if (!mCanvasClient) { TextureFlags flags = TextureFlags::DEFAULT; if (mOriginPos == gl::OriginPos::BottomLeft) { flags |= TextureFlags::ORIGIN_BOTTOM_LEFT; } - if (IsOpaque()) { - flags |= TextureFlags::IS_OPAQUE; - } - if (!mIsAlphaPremultiplied) { flags |= TextureFlags::NON_PREMULTIPLIED; } mCanvasClient = CanvasClient::CreateCanvasClient(GetCanvasClientType(), GetForwarder(), flags); if (!mCanvasClient) { return false;
--- a/gfx/wr/webrender/res/composite.glsl +++ b/gfx/wr/webrender/res/composite.glsl @@ -18,19 +18,16 @@ flat varying vec4 vUVBounds_u; flat varying vec4 vUVBounds_v; #else flat varying vec4 vColor; flat varying float vLayer; varying vec2 vUv; #endif #ifdef WR_VERTEX_SHADER -// CPU side data is in CompositeInstance (gpu_types.rs) and is -// converted to GPU data using desc::COMPOSITE (renderer.rs) by -// filling vaos.composite_vao with VertexArrayKind::Composite. PER_INSTANCE in vec4 aDeviceRect; PER_INSTANCE in vec4 aDeviceClipRect; PER_INSTANCE in vec4 aColor; PER_INSTANCE in vec4 aParams; PER_INSTANCE in vec3 aTextureLayers; #ifdef WR_FEATURE_YUV PER_INSTANCE in vec4 aUvRect0; @@ -106,18 +103,14 @@ void main(void) { vUV_u, vUV_v, vUVBounds_y, vUVBounds_u, vUVBounds_v ); #else // The color is just the texture sample modulated by a supplied color -# if defined(WR_FEATURE_TEXTURE_EXTERNAL) || defined(WR_FEATURE_TEXTURE_2D) || defined(WR_FEATURE_TEXTURE_RECT) - vec4 texel = TEX_SAMPLE(sColor0, vec3(vUv, vLayer)); -# else - vec4 texel = textureLod(sColor0, vec3(vUv, vLayer), 0.0); -# endif + vec4 texel = textureLod(sColor0, vec3(vUv, vLayer), 0.0); vec4 color = vColor * texel; #endif - write_output(color); + write_output(color); } #endif
--- a/gfx/wr/webrender/src/batch.rs +++ b/gfx/wr/webrender/src/batch.rs @@ -14,17 +14,17 @@ use crate::gpu_types::{BrushFlags, Brush use crate::gpu_types::{ClipMaskInstance, SplitCompositeInstance, BrushShaderKind}; use crate::gpu_types::{PrimitiveInstanceData, RasterizationSpace, GlyphInstance}; use crate::gpu_types::{PrimitiveHeader, PrimitiveHeaderIndex, TransformPaletteId, TransformPalette}; use crate::gpu_types::{ImageBrushData, get_shader_opacity}; use crate::internal_types::{FastHashMap, SavedTargetIndex, Swizzle, TextureSource, Filter}; use crate::picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive}; use crate::prim_store::{DeferredResolve, EdgeAaSegmentMask, PrimitiveInstanceKind, PrimitiveVisibilityIndex, PrimitiveVisibilityMask}; use crate::prim_store::{VisibleGradientTile, PrimitiveInstance, PrimitiveOpacity, SegmentInstanceIndex}; -use crate::prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, PrimitiveVisibility, PrimitiveVisibilityFlags}; +use crate::prim_store::{BrushSegment, ClipMaskKind, ClipTaskIndex, PrimitiveVisibilityFlags}; use crate::prim_store::{VECS_PER_SEGMENT, SpaceMapper}; use crate::prim_store::image::ImageSource; use crate::render_target::RenderTargetContext; use crate::render_task_graph::{RenderTaskId, RenderTaskGraph}; use crate::render_task::RenderTaskAddress; use crate::renderer::{BlendMode, ImageBufferKind, ShaderColorMode}; use crate::renderer::{BLOCKS_PER_UV_RECT, MAX_VERTEX_TEXTURE_WIDTH}; use crate::resource_cache::{CacheItem, GlyphFetchResult, ImageRequest, ResourceCache}; @@ -719,83 +719,16 @@ impl BatchBuilder { surface_spatial_node_index, z_generator, composite_state, ); } } } - // If an image is being drawn as a compositor surface, we don't want - // to draw the surface itself into the tile. Instead, we draw a transparent - // rectangle that writes to the z-buffer where this compositor surface is. - // That ensures we 'cut out' the part of the tile that has the compositor - // surface on it, allowing us to draw this tile as an overlay on top of - // the compositor surface. - // TODO(gw): There's a slight performance cost to doing this cutout rectangle - // if we end up not needing to use overlay mode. Consider skipping - // the cutout completely in this path. - fn emit_placeholder( - &mut self, - prim_rect: LayoutRect, - prim_info: &PrimitiveVisibility, - z_id: ZBufferId, - transform_id: TransformPaletteId, - batch_features: BatchFeatures, - ctx: &RenderTargetContext, - gpu_cache: &mut GpuCache, - render_tasks: &RenderTaskGraph, - prim_headers: &mut PrimitiveHeaders, - ) { - let batch_params = BrushBatchParameters::shared( - BrushBatchKind::Solid, - BatchTextures::no_texture(), - [get_shader_opacity(0.0), 0, 0, 0], - 0, - ); - - let prim_cache_address = gpu_cache.get_address( - &ctx.globals.default_transparent_rect_handle, - ); - - let prim_header = PrimitiveHeader { - local_rect: prim_rect, - local_clip_rect: prim_info.combined_local_clip_rect, - specific_prim_address: prim_cache_address, - transform_id, - }; - - let prim_header_index = prim_headers.push( - &prim_header, - z_id, - batch_params.prim_user_data, - ); - - let bounding_rect = &prim_info.clip_chain.pic_clip_rect; - let transform_kind = transform_id.transform_kind(); - let prim_vis_mask = prim_info.visibility_mask; - - self.add_segmented_prim_to_batch( - None, - PrimitiveOpacity::translucent(), - &batch_params, - BlendMode::None, - BlendMode::None, - batch_features, - prim_header_index, - bounding_rect, - transform_kind, - render_tasks, - z_id, - prim_info.clip_task_index, - prim_vis_mask, - ctx, - ); - } - // Adds a primitive to a batch. // It can recursively call itself in some situations, for // example if it encounters a picture where the items // in that picture are being drawn into the same target. fn add_prim_to_batch( &mut self, prim_instance: &PrimitiveInstance, prim_spatial_node_index: SpatialNodeIndex, @@ -1985,26 +1918,67 @@ impl BatchBuilder { render_tasks, z_id, prim_info.clip_task_index, prim_vis_mask, ctx, ); } PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, is_compositor_surface, .. } => { + // If this YUV image is being drawn as a compositor surface, we don't want + // to draw the YUV surface itself into the tile. Instead, we draw a transparent + // rectangle that writes to the z-buffer where this compositor surface is. + // That ensures we 'cut out' the part of the tile that has the compositor + // surface on it, allowing us to draw this tile as an overlay on top of + // the compositor surface. + // TODO(gw): There's a slight performance cost to doing this cutout rectangle + // if we end up not needing to use overlay mode. Consider skipping + // the cutout completely in this path. if is_compositor_surface { - self.emit_placeholder(prim_rect, - prim_info, - z_id, - transform_id, - batch_features, - ctx, - gpu_cache, - render_tasks, - prim_headers); + let batch_params = BrushBatchParameters::shared( + BrushBatchKind::Solid, + BatchTextures::no_texture(), + [get_shader_opacity(0.0), 0, 0, 0], + 0, + ); + + let prim_cache_address = gpu_cache.get_address( + &ctx.globals.default_transparent_rect_handle, + ); + + let prim_header = PrimitiveHeader { + local_rect: prim_rect, + local_clip_rect: prim_info.combined_local_clip_rect, + specific_prim_address: prim_cache_address, + transform_id, + }; + + let prim_header_index = prim_headers.push( + &prim_header, + z_id, + batch_params.prim_user_data, + ); + + self.add_segmented_prim_to_batch( + None, + PrimitiveOpacity::translucent(), + &batch_params, + BlendMode::None, + BlendMode::None, + batch_features, + prim_header_index, + bounding_rect, + transform_kind, + render_tasks, + z_id, + prim_info.clip_task_index, + prim_vis_mask, + ctx, + ); + return; } let yuv_image_data = &ctx.data_stores.yuv_image[data_handle].kind; let mut textures = BatchTextures::no_texture(); let mut uv_rect_addresses = [0; 3]; //yuv channel @@ -2107,29 +2081,17 @@ impl BatchBuilder { transform_kind, render_tasks, z_id, prim_info.clip_task_index, prim_vis_mask, ctx, ); } - PrimitiveInstanceKind::Image { data_handle, image_instance_index, is_compositor_surface, .. } => { - if is_compositor_surface { - self.emit_placeholder(prim_rect, - prim_info, - z_id, - transform_id, - batch_features, - ctx, - gpu_cache, - render_tasks, - prim_headers); - return; - } + PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { let image_data = &ctx.data_stores.image[data_handle].kind; let common_data = &ctx.data_stores.image[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 { AlphaType::PremultipliedAlpha => BlendMode::PremultipliedAlpha, AlphaType::Alpha => BlendMode::Alpha, };
--- a/gfx/wr/webrender/src/composite.rs +++ b/gfx/wr/webrender/src/composite.rs @@ -82,99 +82,78 @@ pub struct CompositeTile { pub surface: CompositeTileSurface, pub rect: DeviceRect, pub clip_rect: DeviceRect, pub dirty_rect: DeviceRect, pub valid_rect: DeviceRect, pub z_id: ZBufferId, } -pub enum ExternalSurfaceDependency { - Yuv { - image_dependencies: [ImageDependency; 3], - color_space: YuvColorSpace, - format: YuvFormat, - rescale: f32, - }, - Rgb { - image_dependency: ImageDependency, - }, -} - /// Describes information about drawing a primitive as a compositor surface. /// For now, we support only YUV images as compositor surfaces, but in future /// this will also support RGBA images. pub struct ExternalSurfaceDescriptor { pub local_rect: PictureRect, pub world_rect: WorldRect, pub device_rect: DeviceRect, pub local_clip_rect: PictureRect, pub clip_rect: DeviceRect, + pub image_dependencies: [ImageDependency; 3], pub image_rendering: ImageRendering, + pub yuv_color_space: YuvColorSpace, + pub yuv_format: YuvFormat, + pub yuv_rescale: f32, pub z_id: ZBufferId, - pub dependency: ExternalSurfaceDependency, /// If native compositing is enabled, the native compositor surface handle. /// Otherwise, this will be None pub native_surface_id: Option<NativeSurfaceId>, /// If the native surface needs to be updated, this will contain the size /// of the native surface as Some(size). If not dirty, this is None. pub update_params: Option<DeviceIntSize>, } -/// Information about a plane in a YUV or RGB surface. +/// Information about a plane in a YUV surface. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -#[derive(Debug, Copy, Clone)] -pub struct ExternalPlaneDescriptor { +pub struct YuvPlaneDescriptor { pub texture: TextureSource, pub texture_layer: i32, pub uv_rect: TexelRect, } -impl ExternalPlaneDescriptor { +impl YuvPlaneDescriptor { fn invalid() -> Self { - ExternalPlaneDescriptor { + YuvPlaneDescriptor { texture: TextureSource::Invalid, texture_layer: 0, uv_rect: TexelRect::invalid(), } } } #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Debug, Copy, Clone)] pub struct ResolvedExternalSurfaceIndex(pub usize); -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -pub enum ResolvedExternalSurfaceColorData { - Yuv { - // YUV specific information - image_dependencies: [ImageDependency; 3], - planes: [ExternalPlaneDescriptor; 3], - color_space: YuvColorSpace, - format: YuvFormat, - rescale: f32, - }, - Rgb { - image_dependency: ImageDependency, - plane: ExternalPlaneDescriptor, - }, -} - /// An ExternalSurfaceDescriptor that has had image keys /// resolved to texture handles. This contains all the /// information that the compositor step in renderer /// needs to know. #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] pub struct ResolvedExternalSurface { - pub color_data: ResolvedExternalSurfaceColorData, + // YUV specific information + pub image_dependencies: [ImageDependency; 3], + pub yuv_planes: [YuvPlaneDescriptor; 3], + pub yuv_color_space: YuvColorSpace, + pub yuv_format: YuvFormat, + pub yuv_rescale: f32, pub image_buffer_kind: ImageBufferKind, + // Update information for a native surface if it's dirty pub update_params: Option<(NativeSurfaceId, DeviceIntSize)>, } /// Public interface specified in `RendererOptions` that configures /// how WR compositing will operate. pub enum CompositorConfig { /// Let WR draw tiles via normal batching. This requires no special OS support. @@ -533,75 +512,57 @@ impl CompositeState { tile_descriptors: opaque_tile_descriptors, } ); } // For each compositor surface that was promoted, build the // information required for the compositor to draw it for external_surface in &tile_cache.external_surfaces { - - let mut planes = [ - ExternalPlaneDescriptor::invalid(), - ExternalPlaneDescriptor::invalid(), - ExternalPlaneDescriptor::invalid(), + let mut yuv_planes = [ + YuvPlaneDescriptor::invalid(), + YuvPlaneDescriptor::invalid(), + YuvPlaneDescriptor::invalid(), ]; - // Step through the image keys, and build a plane descriptor for each - let required_plane_count = - match external_surface.dependency { - ExternalSurfaceDependency::Yuv { format, .. } => { - format.get_plane_num() - }, - ExternalSurfaceDependency::Rgb { .. } => { - 1 - } - }; + // Step through the image keys, and build a yuv plane descriptor for each + let required_plane_count = external_surface.yuv_format.get_plane_num(); let mut valid_plane_count = 0; - let mut image_dependencies = [ImageDependency::INVALID; 3]; - for i in 0 .. required_plane_count { - let dependency = match external_surface.dependency { - ExternalSurfaceDependency::Yuv { image_dependencies, .. } => { - image_dependencies[i] - }, - ExternalSurfaceDependency::Rgb { image_dependency, .. } => { - image_dependency - } - }; - image_dependencies[i] = dependency; + let key = external_surface.image_dependencies[i].key; + let plane = &mut yuv_planes[i]; let request = ImageRequest { - key: dependency.key, + key, rendering: external_surface.image_rendering, tile: None, }; let cache_item = resolve_image( request, resource_cache, gpu_cache, deferred_resolves, ); if cache_item.texture_id != TextureSource::Invalid { valid_plane_count += 1; - let plane = &mut planes[i]; - *plane = ExternalPlaneDescriptor { + + *plane = YuvPlaneDescriptor { texture: cache_item.texture_id, texture_layer: cache_item.texture_layer, uv_rect: cache_item.uv_rect.into(), }; } } // Check if there are valid images added for each YUV plane if valid_plane_count < required_plane_count { - warn!("Warnings: skip a YUV/RGB compositor surface, found {}/{} valid images", + warn!("Warnings: skip a YUV compositor surface, found {}/{} valid images", valid_plane_count, required_plane_count, ); continue; } let clip_rect = external_surface .clip_rect @@ -620,47 +581,25 @@ impl CompositeState { // to use. let update_params = external_surface.update_params.map(|surface_size| { ( external_surface.native_surface_id.expect("bug: no native surface!"), surface_size ) }); - match external_surface.dependency { - ExternalSurfaceDependency::Yuv{ color_space, format, rescale, .. } => { - - let image_buffer_kind = get_buffer_kind(planes[0].texture); - - self.external_surfaces.push(ResolvedExternalSurface { - color_data: ResolvedExternalSurfaceColorData::Yuv { - image_dependencies, - planes, - color_space, - format, - rescale, - }, - image_buffer_kind, - update_params, - }); - }, - ExternalSurfaceDependency::Rgb{ .. } => { - - let image_buffer_kind = get_buffer_kind(planes[0].texture); - - self.external_surfaces.push(ResolvedExternalSurface { - color_data: ResolvedExternalSurfaceColorData::Rgb { - image_dependency: image_dependencies[0], - plane: planes[0], - }, - image_buffer_kind, - update_params, - }); - }, - } + self.external_surfaces.push(ResolvedExternalSurface { + yuv_color_space: external_surface.yuv_color_space, + yuv_format: external_surface.yuv_format, + yuv_rescale: external_surface.yuv_rescale, + image_buffer_kind: get_buffer_kind(yuv_planes[0].texture), + image_dependencies: external_surface.image_dependencies, + yuv_planes, + update_params, + }); let tile = CompositeTile { surface, rect: external_surface.device_rect, valid_rect: external_surface.device_rect.translate(-external_surface.device_rect.origin.to_vector()), dirty_rect: external_surface.device_rect.translate(-external_surface.device_rect.origin.to_vector()), clip_rect, z_id: external_surface.z_id, @@ -669,17 +608,17 @@ impl CompositeState { // Add a surface descriptor for each compositor surface. For the Draw // compositor, this is used to avoid composites being skipped by adding // a dependency on the compositor surface external image keys / generations. self.descriptor.surfaces.push( CompositeSurfaceDescriptor { surface_id: external_surface.native_surface_id, offset: tile.rect.origin, clip_rect: tile.clip_rect, - image_dependencies: image_dependencies, + image_dependencies: external_surface.image_dependencies, tile_descriptors: Vec::new(), } ); self.push_tile(tile, true); } // Add alpha / overlay tiles after compositor surfaces
--- a/gfx/wr/webrender/src/gpu_types.rs +++ b/gfx/wr/webrender/src/gpu_types.rs @@ -231,18 +231,16 @@ impl ResolveInstanceData { rect.size.width as f32, rect.size.height as f32, ], } } } /// Vertex format for picture cache composite shader. -/// When editing the members, update desc::COMPOSITE -/// so its list of instance_attributes matches: #[derive(Debug, Clone)] #[repr(C)] pub struct CompositeInstance { // Device space rectangle of surface rect: DeviceRect, // Device space clip rect for this surface clip_rect: DeviceRect, // Color for solid color tiles, white otherwise @@ -277,37 +275,16 @@ impl CompositeInstance { yuv_color_space: 0.0, yuv_format: 0.0, yuv_rescale: 0.0, texture_layers: [layer, 0.0, 0.0], uv_rects: [TexelRect::invalid(); 3], } } - pub fn new_rgb( - rect: DeviceRect, - clip_rect: DeviceRect, - color: PremultipliedColorF, - layer: f32, - z_id: ZBufferId, - uv_rect: TexelRect, - ) -> Self { - CompositeInstance { - rect, - clip_rect, - color, - z_id: z_id.0 as f32, - yuv_color_space: 0.0, - yuv_format: 0.0, - yuv_rescale: 0.0, - texture_layers: [layer, 0.0, 0.0], - uv_rects: [uv_rect, uv_rect, TexelRect::invalid()], - } - } - pub fn new_yuv( rect: DeviceRect, clip_rect: DeviceRect, z_id: ZBufferId, yuv_color_space: YuvColorSpace, yuv_format: YuvFormat, yuv_rescale: f32, texture_layers: [f32; 3],
--- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -92,25 +92,24 @@ //! path before the compositor surface is drawn. Use of the per-tile valid and //! dirty rects ensure that we do a minimal amount of per-pixel work here to //! blend the overlay tile (this is not always optimal right now, but will be //! improved as a follow up). use api::{MixBlendMode, PipelineId, PremultipliedColorF, FilterPrimitiveKind}; use api::{PropertyBinding, PropertyBindingId, FilterPrimitive, FontRenderMode}; use api::{DebugFlags, RasterSpace, ImageKey, ColorF, ColorU, PrimitiveFlags}; -use api::{ImageRendering, ColorDepth, YuvColorSpace, YuvFormat}; use api::units::*; use crate::box_shadow::BLUR_SAMPLE_SCALE; use crate::clip::{ClipStore, ClipChainInstance, ClipDataHandle, ClipChainId}; use crate::spatial_tree::{ROOT_SPATIAL_NODE_INDEX, SpatialTree, CoordinateSpaceMapping, SpatialNodeIndex, VisibleFace }; use crate::composite::{CompositorKind, CompositeState, NativeSurfaceId, NativeTileId}; -use crate::composite::{ExternalSurfaceDescriptor, ExternalSurfaceDependency}; +use crate::composite::{ExternalSurfaceDescriptor}; use crate::debug_colors; use euclid::{vec2, vec3, Point2D, Scale, Size2D, Vector2D, Rect, Transform3D, SideOffsets2D}; use euclid::approxeq::ApproxEq; use crate::filterdata::SFilterData; use crate::frame_builder::{FrameBuilderConfig, FrameVisibilityContext, FrameVisibilityState}; use crate::intern::ItemUid; use crate::internal_types::{FastHashMap, FastHashSet, PlaneSplitter, Filter, PlaneSplitAnchor, TextureSource}; use crate::frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState, PictureContext}; @@ -2248,17 +2247,17 @@ pub struct NativeSurface { pub opaque: NativeSurfaceId, /// Native surface for alpha tiles pub alpha: NativeSurfaceId, } /// Hash key for an external native compositor surface #[derive(PartialEq, Eq, Hash)] pub struct ExternalNativeSurfaceKey { - /// The YUV/RGB image keys that are used to draw this surface. + /// The YUV image keys that are used to draw this surface. pub image_keys: [ImageKey; 3], /// The current device size of the surface. pub size: DeviceIntSize, } /// Information about a native compositor surface cached between frames. pub struct ExternalNativeSurface { /// If true, the surface was used this frame. Used for a simple form @@ -2929,246 +2928,16 @@ impl TileCacheInstance { } } } } world_culling_rect } - fn can_promote_to_surface( - &mut self, - flags: PrimitiveFlags, - prim_clip_chain: &ClipChainInstance, - prim_spatial_node_index: SpatialNodeIndex, - on_picture_surface: bool, - frame_context: &FrameVisibilityContext, - ) -> bool { - // Check if this primitive _wants_ to be promoted to a compositor surface. - if !flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) { - return false; - } - - // For now, only support a small (arbitrary) number of compositor surfaces. - if self.external_surfaces.len() == MAX_COMPOSITOR_SURFACES { - return false; - } - - // If a complex clip is being applied to this primitive, it can't be - // promoted directly to a compositor surface (we might be able to - // do this in limited cases in future, some native compositors do - // support rounded rect clips, for example) - if prim_clip_chain.needs_mask { - return false; - } - - // If not on the same surface as the picture cache, it has some kind of - // complex effect (such as a filter, mix-blend-mode or 3d transform). - if !on_picture_surface { - return false; - } - - // If the primitive is not axis-aligned with the root coordinate system, - // it can't be promoted to a native compositor surface (could potentially - // be supported in future on some platforms). - let prim_spatial_node = &frame_context.spatial_tree - .spatial_nodes[prim_spatial_node_index.0 as usize]; - if prim_spatial_node.coordinate_system_id != CoordinateSystemId::root() { - return false; - } - - // If the transform has scale, we can't currently handle - // it in the native compositor - we can support this in future though. - if !self.map_local_to_surface.get_transform().is_simple_2d_translation() { - return false; - } - return true; - } - - fn setup_compositor_surfaces_yuv( - &mut self, - prim_info: &mut PrimitiveDependencyInfo, - prim_rect: PictureRect, - frame_context: &FrameVisibilityContext, - image_dependencies: &[ImageDependency;3], - api_keys: &[ImageKey; 3], - resource_cache: &mut ResourceCache, - composite_state: &mut CompositeState, - image_rendering: ImageRendering, - color_depth: ColorDepth, - color_space: YuvColorSpace, - format: YuvFormat, - ) { - self.setup_compositor_surfaces_impl( - prim_info, - prim_rect, - frame_context, - ExternalSurfaceDependency::Yuv { - image_dependencies: *image_dependencies, - color_space, - format, - rescale: color_depth.rescaling_factor(), - }, - api_keys, - resource_cache, - composite_state, - image_rendering, - ); - } - - fn setup_compositor_surfaces_rgb( - &mut self, - prim_info: &mut PrimitiveDependencyInfo, - prim_rect: PictureRect, - frame_context: &FrameVisibilityContext, - image_dependency: ImageDependency, - api_key: ImageKey, - resource_cache: &mut ResourceCache, - composite_state: &mut CompositeState, - image_rendering: ImageRendering, - ) { - let mut api_keys = [ImageKey::DUMMY; 3]; - api_keys[0] = api_key; - self.setup_compositor_surfaces_impl( - prim_info, - prim_rect, - frame_context, - ExternalSurfaceDependency::Rgb { - image_dependency, - }, - &api_keys, - resource_cache, - composite_state, - image_rendering, - ); - } - - fn setup_compositor_surfaces_impl( - &mut self, - prim_info: &mut PrimitiveDependencyInfo, - prim_rect: PictureRect, - frame_context: &FrameVisibilityContext, - dependency: ExternalSurfaceDependency, - api_keys: &[ImageKey; 3], - resource_cache: &mut ResourceCache, - composite_state: &mut CompositeState, - image_rendering: ImageRendering, - ) { - prim_info.is_compositor_surface = true; - - let pic_to_world_mapper = SpaceMapper::new_with_target( - ROOT_SPATIAL_NODE_INDEX, - self.spatial_node_index, - frame_context.global_screen_world_rect, - frame_context.spatial_tree, - ); - - let world_rect = pic_to_world_mapper - .map(&prim_rect) - .expect("bug: unable to map the primitive to world space"); - let world_clip_rect = pic_to_world_mapper - .map(&prim_info.prim_clip_rect) - .expect("bug: unable to map clip to world space"); - - let is_visible = world_clip_rect.intersects(&frame_context.global_screen_world_rect); - if !is_visible { - return; - } - - // TODO(gw): Is there any case where if the primitive ends up on a fractional - // boundary we want to _skip_ promoting to a compositor surface and - // draw it as part of the content? - let device_rect = (world_rect * frame_context.global_device_pixel_scale).round(); - let clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round(); - - // When using native compositing, we need to find an existing native surface - // handle to use, or allocate a new one. For existing native surfaces, we can - // also determine whether this needs to be updated, depending on whether the - // image generation(s) of the planes have changed since last composite. - let (native_surface_id, update_params) = match composite_state.compositor_kind { - CompositorKind::Draw { .. } => { - (None, None) - } - CompositorKind::Native { .. } => { - let native_surface_size = device_rect.size.round().to_i32(); - - let key = ExternalNativeSurfaceKey { - image_keys: *api_keys, - size: native_surface_size, - }; - - let native_surface = self.external_native_surface_cache - .entry(key) - .or_insert_with(|| { - // No existing surface, so allocate a new compositor surface and - // a single compositor tile that covers the entire compositor surface. - - let native_surface_id = resource_cache.create_compositor_surface( - DeviceIntPoint::zero(), - native_surface_size, - true, - ); - - let tile_id = NativeTileId { - surface_id: native_surface_id, - x: 0, - y: 0, - }; - - resource_cache.create_compositor_tile(tile_id); - - ExternalNativeSurface { - used_this_frame: true, - native_surface_id, - image_dependencies: [ImageDependency::INVALID; 3], - } - }); - - // Mark that the surface is referenced this frame so that the - // backing native surface handle isn't freed. - native_surface.used_this_frame = true; - - // If the image dependencies match, there is no need to update - // the backing native surface. - let update_params = match dependency { - ExternalSurfaceDependency::Yuv{ image_dependencies, .. } => { - if image_dependencies == native_surface.image_dependencies { - None - } else { - Some(native_surface_size) - } - }, - ExternalSurfaceDependency::Rgb{ image_dependency, .. } => { - if image_dependency == native_surface.image_dependencies[0] { - None - } else { - Some(native_surface_size) - } - }, - }; - - (Some(native_surface.native_surface_id), update_params) - } - }; - - // Each compositor surface allocates a unique z-id - self.external_surfaces.push(ExternalSurfaceDescriptor { - local_rect: prim_info.prim_clip_rect, - world_rect, - local_clip_rect: prim_info.prim_clip_rect, - dependency, - image_rendering, - device_rect, - clip_rect, - z_id: composite_state.z_generator.next(), - native_surface_id, - update_params, - }); - } - /// Update the dependencies for each tile for a given primitive instance. pub fn update_prim_dependencies( &mut self, prim_instance: &mut PrimitiveInstance, prim_spatial_node_index: SpatialNodeIndex, prim_clip_chain: Option<&ClipChainInstance>, local_prim_rect: LayoutRect, frame_context: &FrameVisibilityContext, @@ -3290,17 +3059,16 @@ impl TileCacheInstance { prim_info.spatial_nodes.push(clip_node.item.spatial_node_index); } } // Certain primitives may select themselves to be a backdrop candidate, which is // then applied below. let mut backdrop_candidate = None; - // For pictures, we don't (yet) know the valid clip rect, so we can't correctly // use it to calculate the local bounding rect for the tiles. If we include them // then we may calculate a bounding rect that is too large, since it won't include // the clip bounds of the picture. Excluding them from the bounding rect here // fixes any correctness issues (the clips themselves are considered when we // consider the bounds of the primitives that are *children* of the picture), // however it does potentially result in some un-necessary invalidations of a // tile (in cases where the picture local rect affects the tile, but the clip @@ -3340,34 +3108,21 @@ impl TileCacheInstance { } if color_binding_index != ColorBindingIndex::INVALID { prim_info.color_binding = Some(color_bindings[color_binding_index].into()); } prim_info.clip_by_tile = true; } - PrimitiveInstanceKind::Image { data_handle, image_instance_index, ref mut is_compositor_surface, .. } => { - let image_key = &data_stores.image[data_handle]; - let image_data = &image_key.kind; + PrimitiveInstanceKind::Image { data_handle, image_instance_index, .. } => { + let image_data = &data_stores.image[data_handle].kind; let image_instance = &image_instances[image_instance_index]; let opacity_binding_index = image_instance.opacity_binding_index; - let mut promote_to_surface = false; - // If picture caching is disabled, we can't support any compositor surfaces. - if composite_state.picture_caching_is_enabled && - self.can_promote_to_surface(image_key.common.flags, - prim_clip_chain, - prim_spatial_node_index, - on_picture_surface, - frame_context) { - promote_to_surface = true; - } - *is_compositor_surface = promote_to_surface; - if opacity_binding_index == OpacityBindingIndex::INVALID { if let Some(image_properties) = resource_cache.get_image_properties(image_data.key) { // For an image to be a possible opaque backdrop, it must: // - Have a valid, opaque image descriptor // - Not use tiling (since they can fail to draw) // - Not having any spacing / padding if image_properties.descriptor.is_opaque() && image_properties.tiling.is_none() && @@ -3380,91 +3135,195 @@ impl TileCacheInstance { } } else { let opacity_binding = &opacity_binding_store[opacity_binding_index]; for binding in &opacity_binding.bindings { prim_info.opacity_bindings.push(OpacityBinding::from(*binding)); } } - if promote_to_surface { - self.setup_compositor_surfaces_rgb( - &mut prim_info, - prim_rect, - frame_context, - ImageDependency { - key: image_data.key, - generation: resource_cache.get_image_generation(image_data.key), - }, - image_data.key, - resource_cache, - composite_state, - image_data.image_rendering, - ); - } else { - prim_info.images.push(ImageDependency { - key: image_data.key, - generation: resource_cache.get_image_generation(image_data.key), - }); - } + prim_info.images.push(ImageDependency { + key: image_data.key, + generation: resource_cache.get_image_generation(image_data.key), + }); } PrimitiveInstanceKind::YuvImage { data_handle, ref mut is_compositor_surface, .. } => { let prim_data = &data_stores.yuv_image[data_handle]; // TODO(gw): For now, we only support promoting YUV primitives to be compositor // surfaces. However, some videos are RGBA images. As a follow up, // extract the logic below and support RGBA compositor surfaces too. let mut promote_to_surface = false; + // If picture caching is disabled, we can't support any compositor surfaces. if composite_state.picture_caching_is_enabled { - promote_to_surface = self.can_promote_to_surface( - prim_data.common.flags, - prim_clip_chain, - prim_spatial_node_index, - on_picture_surface, - frame_context); - - // TODO(gw): When we support RGBA images for external surfaces, we also - // need to check if opaque (YUV images are implicitly opaque). + // Check if this primitive _wants_ to be promoted to a compositor surface. + if prim_data.common.flags.contains(PrimitiveFlags::PREFER_COMPOSITOR_SURFACE) { + promote_to_surface = true; + + // For now, only support a small (arbitrary) number of compositor surfaces. + if self.external_surfaces.len() == MAX_COMPOSITOR_SURFACES { + promote_to_surface = false; + } + + // If a complex clip is being applied to this primitive, it can't be + // promoted directly to a compositor surface (we might be able to + // do this in limited cases in future, some native compositors do + // support rounded rect clips, for example) + if prim_clip_chain.needs_mask { + promote_to_surface = false; + } + + // If not on the same surface as the picture cache, it has some kind of + // complex effect (such as a filter, mix-blend-mode or 3d transform). + if !on_picture_surface { + promote_to_surface = false; + } + + // If the primitive is not axis-aligned with the root coordinate system, + // it can't be promoted to a native compositor surface (could potentially + // be supported in future on some platforms). + let prim_spatial_node = &frame_context.spatial_tree + .spatial_nodes[prim_spatial_node_index.0 as usize]; + if prim_spatial_node.coordinate_system_id != CoordinateSystemId::root() { + promote_to_surface = false; + } + + // If the transform has scale, we can't currently handle + // it in the native compositor - we can support this in future though. + if !self.map_local_to_surface.get_transform().is_simple_2d_translation() { + promote_to_surface = false; + } + + // TODO(gw): When we support RGBA images for external surfaces, we also + // need to check if opaque (YUV images are implicitly opaque). + } } // Store on the YUV primitive instance whether this is a promoted surface. // This is used by the batching code to determine whether to draw the // image to the content tiles, or just a transparent z-write. *is_compositor_surface = promote_to_surface; // If this primitive is being promoted to a surface, construct an external // surface descriptor for use later during batching and compositing. We only // add the image keys for this primitive as a dependency if this is _not_ // a promoted surface, since we don't want the tiles to invalidate when the // video content changes, if it's a compositor surface! if promote_to_surface { - // Build dependency for each YUV plane, with current image generation for - // later detection of when the composited surface has changed. - let mut image_dependencies = [ImageDependency::INVALID; 3]; - for (key, dep) in prim_data.kind.yuv_key.iter().cloned().zip(image_dependencies.iter_mut()) { - *dep = ImageDependency { - key, - generation: resource_cache.get_image_generation(key), + prim_info.is_compositor_surface = true; + + let pic_to_world_mapper = SpaceMapper::new_with_target( + ROOT_SPATIAL_NODE_INDEX, + self.spatial_node_index, + frame_context.global_screen_world_rect, + frame_context.spatial_tree, + ); + + let world_rect = pic_to_world_mapper + .map(&prim_rect) + .expect("bug: unable to map the primitive to world space"); + let world_clip_rect = pic_to_world_mapper + .map(&prim_info.prim_clip_rect) + .expect("bug: unable to map clip to world space"); + + let is_visible = world_clip_rect.intersects(&frame_context.global_screen_world_rect); + if is_visible { + // TODO(gw): Is there any case where if the primitive ends up on a fractional + // boundary we want to _skip_ promoting to a compositor surface and + // draw it as part of the content? + let device_rect = (world_rect * frame_context.global_device_pixel_scale).round(); + let clip_rect = (world_clip_rect * frame_context.global_device_pixel_scale).round(); + + // Build dependency for each YUV plane, with current image generation for + // later detection of when the composited surface has changed. + let mut image_dependencies = [ImageDependency::INVALID; 3]; + for (key, dep) in prim_data.kind.yuv_key.iter().cloned().zip(image_dependencies.iter_mut()) { + *dep = ImageDependency { + key, + generation: resource_cache.get_image_generation(key), + } } + + // When using native compositing, we need to find an existing native surface + // handle to use, or allocate a new one. For existing native surfaces, we can + // also determine whether this needs to be updated, depending on whether the + // image generation(s) of the YUV planes have changed since last composite. + let (native_surface_id, update_params) = match composite_state.compositor_kind { + CompositorKind::Draw { .. } => { + (None, None) + } + CompositorKind::Native { .. } => { + let native_surface_size = device_rect.size.round().to_i32(); + + let key = ExternalNativeSurfaceKey { + image_keys: prim_data.kind.yuv_key, + size: native_surface_size, + }; + + let native_surface = self.external_native_surface_cache + .entry(key) + .or_insert_with(|| { + // No existing surface, so allocate a new compositor surface and + // a single compositor tile that covers the entire compositor surface. + + let native_surface_id = resource_cache.create_compositor_surface( + DeviceIntPoint::zero(), + native_surface_size, + true, + ); + + let tile_id = NativeTileId { + surface_id: native_surface_id, + x: 0, + y: 0, + }; + + resource_cache.create_compositor_tile(tile_id); + + ExternalNativeSurface { + used_this_frame: true, + native_surface_id, + image_dependencies: [ImageDependency::INVALID; 3], + } + }); + + // Mark that the surface is referenced this frame so that the + // backing native surface handle isn't freed. + native_surface.used_this_frame = true; + + // If the image dependencies match, there is no need to update + // the backing native surface. + let update_params = if image_dependencies == native_surface.image_dependencies { + None + } else { + Some(native_surface_size) + }; + + (Some(native_surface.native_surface_id), update_params) + } + }; + + // Each compositor surface allocates a unique z-id + self.external_surfaces.push(ExternalSurfaceDescriptor { + local_rect: prim_info.prim_clip_rect, + world_rect, + local_clip_rect: prim_info.prim_clip_rect, + image_dependencies, + image_rendering: prim_data.kind.image_rendering, + device_rect, + clip_rect, + yuv_color_space: prim_data.kind.color_space, + yuv_format: prim_data.kind.format, + yuv_rescale: prim_data.kind.color_depth.rescaling_factor(), + z_id: composite_state.z_generator.next(), + native_surface_id, + update_params, + }); } - - self.setup_compositor_surfaces_yuv( - &mut prim_info, - prim_rect, - frame_context, - &image_dependencies, - &prim_data.kind.yuv_key, - resource_cache, - composite_state, - prim_data.kind.image_rendering, - prim_data.kind.color_depth, - prim_data.kind.color_space, - prim_data.kind.format, - ); } else { prim_info.images.extend( prim_data.kind.yuv_key.iter().map(|key| { ImageDependency { key: *key, generation: resource_cache.get_image_generation(*key), } })
--- a/gfx/wr/webrender/src/prim_store/image.rs +++ b/gfx/wr/webrender/src/prim_store/image.rs @@ -327,17 +327,16 @@ impl InternablePrimitive for Image { segment_instance_index: SegmentInstanceIndex::INVALID, tight_local_clip_rect: LayoutRect::zero(), visible_tiles: Vec::new(), }); PrimitiveInstanceKind::Image { data_handle, image_instance_index, - is_compositor_surface: false, } } } impl CreateShadow for Image { fn create_shadow(&self, shadow: &Shadow) -> Self { Image { tile_spacing: self.tile_spacing,
--- a/gfx/wr/webrender/src/prim_store/mod.rs +++ b/gfx/wr/webrender/src/prim_store/mod.rs @@ -1423,17 +1423,16 @@ pub enum PrimitiveInstanceKind { data_handle: YuvImageDataHandle, segment_instance_index: SegmentInstanceIndex, is_compositor_surface: bool, }, Image { /// Handle to the common interned data for this primitive. data_handle: ImageDataHandle, image_instance_index: ImageInstanceIndex, - is_compositor_surface: bool, }, LinearGradient { /// Handle to the common interned data for this primitive. data_handle: LinearGradientDataHandle, gradient_index: LinearGradientIndex, }, RadialGradient { /// Handle to the common interned data for this primitive.
--- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -43,17 +43,17 @@ use api::{RenderApiSender, RenderNotifie #[cfg(feature = "replay")] use api::ExternalImage; use api::units::*; pub use api::DebugFlags; use crate::batch::{AlphaBatchContainer, BatchKind, BatchFeatures, BatchTextures, BrushBatchKind, ClipBatchList}; #[cfg(any(feature = "capture", feature = "replay"))] use crate::capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage}; use crate::composite::{CompositeState, CompositeTileSurface, CompositeTile, ResolvedExternalSurface}; -use crate::composite::{CompositorKind, Compositor, NativeTileId, CompositeSurfaceFormat, ResolvedExternalSurfaceColorData}; +use crate::composite::{CompositorKind, Compositor, NativeTileId, CompositeSurfaceFormat}; use crate::composite::{CompositorConfig, NativeSurfaceOperationDetails, NativeSurfaceId, NativeSurfaceOperation}; use crate::debug_colors; use crate::debug_render::{DebugItem, DebugRenderer}; use crate::device::{DepthFunction, Device, GpuFrameId, Program, UploadMethod, Texture, PBO}; use crate::device::{DrawTarget, ExternalTexture, FBOId, ReadTarget, TextureSlot}; use crate::device::{ShaderError, TextureFilter, TextureFlags, VertexUsageHint, VAO, VBO, CustomVAO}; use crate::device::ProgramCache; @@ -4525,100 +4525,64 @@ impl Renderer { 0.0, surface_size.width as f32, 0.0, surface_size.height as f32, self.device.ortho_near_plane(), self.device.ortho_far_plane(), ); - let ( textures, instance ) = match surface.color_data { - ResolvedExternalSurfaceColorData::Yuv{ - ref planes, color_space, format, rescale, .. } => { - - // Bind an appropriate YUV shader for the texture format kind - self.shaders - .borrow_mut() - .get_composite_shader( - CompositeSurfaceFormat::Yuv, - surface.image_buffer_kind, - ).bind( - &mut self.device, - &projection, - &mut self.renderer_errors - ); - - let textures = BatchTextures { - colors: [ - planes[0].texture, - planes[1].texture, - planes[2].texture, - ], - }; - - // When the texture is an external texture, the UV rect is not known when - // the external surface descriptor is created, because external textures - // are not resolved until the lock() callback is invoked at the start of - // the frame render. To handle this, query the texture resolver for the - // UV rect if it's an external texture, otherwise use the default UV rect. - let uv_rects = [ - self.texture_resolver.get_uv_rect(&textures.colors[0], planes[0].uv_rect), - self.texture_resolver.get_uv_rect(&textures.colors[1], planes[1].uv_rect), - self.texture_resolver.get_uv_rect(&textures.colors[2], planes[2].uv_rect), - ]; - - let instance = CompositeInstance::new_yuv( - surface_rect.to_f32(), - surface_rect.to_f32(), - // z-id is not relevant when updating a native compositor surface. - // TODO(gw): Support compositor surfaces without z-buffer, for memory / perf win here. - ZBufferId(0), - color_space, - format, - rescale, - [ - planes[0].texture_layer as f32, - planes[1].texture_layer as f32, - planes[2].texture_layer as f32, - ], - uv_rects, - ); - - ( textures, instance ) - }, - ResolvedExternalSurfaceColorData::Rgb{ ref plane, .. } => { - - self.shaders - .borrow_mut() - .get_composite_shader( - CompositeSurfaceFormat::Rgba, - surface.image_buffer_kind, - ).bind( - &mut self.device, - &projection, - &mut self.renderer_errors - ); - - let textures = BatchTextures::color(plane.texture); - - let uv_rect = self.texture_resolver.get_uv_rect(&textures.colors[0], plane.uv_rect); - - let instance = CompositeInstance::new_rgb( - surface_rect.to_f32(), - surface_rect.to_f32(), - PremultipliedColorF::WHITE, - plane.texture_layer as f32, - ZBufferId(0), - uv_rect, - ); - - ( textures, instance ) - }, + // Bind an appropriate YUV shader for the texture format kind + self.shaders + .borrow_mut() + .get_composite_shader( + CompositeSurfaceFormat::Yuv, + surface.image_buffer_kind, + ).bind( + &mut self.device, + &projection, + &mut self.renderer_errors + ); + + let textures = BatchTextures { + colors: [ + surface.yuv_planes[0].texture, + surface.yuv_planes[1].texture, + surface.yuv_planes[2].texture, + ], }; + // When the texture is an external texture, the UV rect is not known when + // the external surface descriptor is created, because external textures + // are not resolved until the lock() callback is invoked at the start of + // the frame render. To handle this, query the texture resolver for the + // UV rect if it's an external texture, otherwise use the default UV rect. + let uv_rects = [ + self.texture_resolver.get_uv_rect(&textures.colors[0], surface.yuv_planes[0].uv_rect), + self.texture_resolver.get_uv_rect(&textures.colors[1], surface.yuv_planes[1].uv_rect), + self.texture_resolver.get_uv_rect(&textures.colors[2], surface.yuv_planes[2].uv_rect), + ]; + + let instance = CompositeInstance::new_yuv( + surface_rect.to_f32(), + surface_rect.to_f32(), + // z-id is not relevant when updating a native compositor surface. + // TODO(gw): Support compositor surfaces without z-buffer, for memory / perf win here. + ZBufferId(0), + surface.yuv_color_space, + surface.yuv_format, + surface.yuv_rescale, + [ + surface.yuv_planes[0].texture_layer as f32, + surface.yuv_planes[1].texture_layer as f32, + surface.yuv_planes[2].texture_layer as f32, + ], + uv_rects, + ); + self.draw_instanced_batch( &[instance], VertexArrayKind::Composite, &textures, &mut results.stats, ); self.compositor_config @@ -4717,74 +4681,53 @@ impl Renderer { ), BatchTextures::color(texture), (CompositeSurfaceFormat::Rgba, ImageBufferKind::Texture2DArray), ) } CompositeTileSurface::ExternalSurface { external_surface_index } => { let surface = &external_surfaces[external_surface_index.0]; - match surface.color_data { - ResolvedExternalSurfaceColorData::Yuv{ ref planes, color_space, format, rescale, .. } => { - - let textures = BatchTextures { - colors: [ - planes[0].texture, - planes[1].texture, - planes[2].texture, - ], - }; - - // When the texture is an external texture, the UV rect is not known when - // the external surface descriptor is created, because external textures - // are not resolved until the lock() callback is invoked at the start of - // the frame render. To handle this, query the texture resolver for the - // UV rect if it's an external texture, otherwise use the default UV rect. - let uv_rects = [ - self.texture_resolver.get_uv_rect(&textures.colors[0], planes[0].uv_rect), - self.texture_resolver.get_uv_rect(&textures.colors[1], planes[1].uv_rect), - self.texture_resolver.get_uv_rect(&textures.colors[2], planes[2].uv_rect), - ]; - - ( - CompositeInstance::new_yuv( - tile.rect, - clip_rect, - tile.z_id, - color_space, - format, - rescale, - [ - planes[0].texture_layer as f32, - planes[1].texture_layer as f32, - planes[2].texture_layer as f32, - ], - uv_rects, - ), - textures, - (CompositeSurfaceFormat::Yuv, surface.image_buffer_kind), - ) - }, - ResolvedExternalSurfaceColorData::Rgb{ ref plane, .. } => { - let uv_rect = self.texture_resolver.get_uv_rect(&plane.texture, plane.uv_rect); - - ( - CompositeInstance::new_rgb( - tile.rect, - clip_rect, - PremultipliedColorF::WHITE, - plane.texture_layer as f32, - tile.z_id, - uv_rect, - ), - BatchTextures::color(plane.texture), - (CompositeSurfaceFormat::Rgba, surface.image_buffer_kind), - ) - }, - } + let textures = BatchTextures { + colors: [ + surface.yuv_planes[0].texture, + surface.yuv_planes[1].texture, + surface.yuv_planes[2].texture, + ], + }; + + // When the texture is an external texture, the UV rect is not known when + // the external surface descriptor is created, because external textures + // are not resolved until the lock() callback is invoked at the start of + // the frame render. To handle this, query the texture resolver for the + // UV rect if it's an external texture, otherwise use the default UV rect. + let uv_rects = [ + self.texture_resolver.get_uv_rect(&textures.colors[0], surface.yuv_planes[0].uv_rect), + self.texture_resolver.get_uv_rect(&textures.colors[1], surface.yuv_planes[1].uv_rect), + self.texture_resolver.get_uv_rect(&textures.colors[2], surface.yuv_planes[2].uv_rect), + ]; + + ( + CompositeInstance::new_yuv( + tile.rect, + clip_rect, + tile.z_id, + surface.yuv_color_space, + surface.yuv_format, + surface.yuv_rescale, + [ + surface.yuv_planes[0].texture_layer as f32, + surface.yuv_planes[1].texture_layer as f32, + surface.yuv_planes[2].texture_layer as f32, + ], + uv_rects, + ), + textures, + (CompositeSurfaceFormat::Yuv, surface.image_buffer_kind), + ) } CompositeTileSurface::Texture { surface: ResolvedSurfaceTexture::Native { .. } } => { unreachable!("bug: found native surface in simple composite path"); } }; // Flush batch if shader params or textures changed let flush_batch = !current_textures.is_compatible_with(&textures) ||
--- a/gfx/wr/webrender/src/shade.rs +++ b/gfx/wr/webrender/src/shade.rs @@ -574,21 +574,17 @@ pub struct Shaders { // Composite shaders. These are very simple shaders used to composite // picture cache tiles into the framebuffer on platforms that do not have an // OS Compositor (or we cannot use it). Such an OS Compositor (such as // DirectComposite or CoreAnimation) handles the composition of the picture // cache tiles at a lower level (e.g. in DWM for Windows); in that case we // directly hand the picture cache surfaces over to the OS Compositor, and // our own Composite shaders below never run. - // To composite external (RGB) surfaces we need various permutations of - // shaders with WR_FEATURE flags on or off based on the type of image - // buffer we're sourcing from (see IMAGE_BUFFER_KINDS). - pub composite_rgba: Vec<Option<LazilyCompiledShader>>, - // The same set of composite shaders but with WR_FEATURE_YUV added. + pub composite_rgba: LazilyCompiledShader, pub composite_yuv: Vec<Option<LazilyCompiledShader>>, } impl Shaders { pub fn new( device: &mut Device, gl_type: GlType, options: &RendererOptions, @@ -883,75 +879,60 @@ impl Shaders { use_pixel_local_storage, )?); image_features.clear(); } // All yuv_image configuration. let mut yuv_features = Vec::new(); - let mut rgba_features = Vec::new(); let yuv_shader_num = IMAGE_BUFFER_KINDS.len(); let mut brush_yuv_image = Vec::new(); let mut composite_yuv = Vec::new(); - let mut composite_rgba = Vec::new(); // PrimitiveShader is not clonable. Use push() to initialize the vec. for _ in 0 .. yuv_shader_num { brush_yuv_image.push(None); composite_yuv.push(None); - composite_rgba.push(None); } for image_buffer_kind in &IMAGE_BUFFER_KINDS { if image_buffer_kind.has_platform_support(&gl_type) { yuv_features.push("YUV"); let feature_string = image_buffer_kind.get_feature_string(); if feature_string != "" { yuv_features.push(feature_string); - rgba_features.push(feature_string); } let brush_shader = BrushShader::new( "brush_yuv_image", device, &yuv_features, options.precache_flags, &shader_list, false /* advanced blend */, false /* dual source */, use_pixel_local_storage, )?; - let composite_yuv_shader = LazilyCompiledShader::new( + let composite_shader = LazilyCompiledShader::new( ShaderKind::Composite, "composite", &yuv_features, device, options.precache_flags, &shader_list, )?; - let composite_rgba_shader = LazilyCompiledShader::new( - ShaderKind::Composite, - "composite", - &rgba_features, - device, - options.precache_flags, - &shader_list, - )?; - - let index = Self::get_compositing_shader_index( + let index = Self::get_yuv_shader_index( *image_buffer_kind, ); brush_yuv_image[index] = Some(brush_shader); - composite_yuv[index] = Some(composite_yuv_shader); - composite_rgba[index] = Some(composite_rgba_shader); + composite_yuv[index] = Some(composite_shader); yuv_features.clear(); - rgba_features.clear() } } let cs_line_decoration = LazilyCompiledShader::new( ShaderKind::Cache(VertexArrayKind::LineDecoration), "cs_line_decoration", &[], device, @@ -981,16 +962,25 @@ impl Shaders { ShaderKind::Cache(VertexArrayKind::Border), "cs_border_solid", &[], device, options.precache_flags, &shader_list, )?; + let composite_rgba = LazilyCompiledShader::new( + ShaderKind::Composite, + "composite", + &[], + device, + options.precache_flags, + &shader_list, + )?; + Ok(Shaders { cs_blur_a8, cs_blur_rgba8, cs_border_segment, cs_line_decoration, cs_gradient, cs_border_solid, cs_scale, @@ -1014,34 +1004,32 @@ impl Shaders { ps_text_run, ps_text_run_dual_source, ps_split_composite, composite_rgba, composite_yuv, }) } - fn get_compositing_shader_index(buffer_kind: ImageBufferKind) -> usize { + fn get_yuv_shader_index(buffer_kind: ImageBufferKind) -> usize { buffer_kind as usize } pub fn get_composite_shader( &mut self, format: CompositeSurfaceFormat, buffer_kind: ImageBufferKind, ) -> &mut LazilyCompiledShader { match format { CompositeSurfaceFormat::Rgba => { - let shader_index = Self::get_compositing_shader_index(buffer_kind); - self.composite_rgba[shader_index] - .as_mut() - .expect("bug: unsupported rgba shader requested") + debug_assert_eq!(buffer_kind, ImageBufferKind::Texture2DArray); + &mut self.composite_rgba } CompositeSurfaceFormat::Yuv => { - let shader_index = Self::get_compositing_shader_index(buffer_kind); + let shader_index = Self::get_yuv_shader_index(buffer_kind); self.composite_yuv[shader_index] .as_mut() .expect("bug: unsupported yuv shader requested") } } } pub fn get(&mut self, key: &BatchKey, features: BatchFeatures, debug_flags: DebugFlags) -> &mut LazilyCompiledShader { @@ -1079,17 +1067,17 @@ impl Shaders { BrushBatchKind::RadialGradient => { &mut self.brush_radial_gradient } BrushBatchKind::LinearGradient => { &mut self.brush_linear_gradient } BrushBatchKind::YuvImage(image_buffer_kind, ..) => { let shader_index = - Self::get_compositing_shader_index(image_buffer_kind); + Self::get_yuv_shader_index(image_buffer_kind); self.brush_yuv_image[shader_index] .as_mut() .expect("Unsupported YUV shader kind") } BrushBatchKind::Opacity => { &mut self.brush_opacity } }; @@ -1146,21 +1134,17 @@ impl Shaders { shader.deinit(device); } } self.cs_border_solid.deinit(device); self.cs_gradient.deinit(device); self.cs_line_decoration.deinit(device); self.cs_border_segment.deinit(device); self.ps_split_composite.deinit(device); - for shader in self.composite_rgba { - if let Some(shader) = shader { - shader.deinit(device); - } - } + self.composite_rgba.deinit(device); for shader in self.composite_yuv { if let Some(shader) = shader { shader.deinit(device); } } } }
--- a/gfx/wr/webrender_build/src/shader_features.rs +++ b/gfx/wr/webrender_build/src/shader_features.rs @@ -108,22 +108,18 @@ pub fn get_shader_features(flags: Shader if flags.contains(ShaderFeatureFlags::DUAL_SOURCE_BLENDING) { let dual_source_features = concat_features(&brush_alpha_features, "DUAL_SOURCE_BLENDING"); image_features.push(concat_features(&fast, &dual_source_features)); image_features.push(concat_features(&slow, &dual_source_features)); } } shaders.insert("brush_image", image_features); - let mut composite_features: Vec<String> = Vec::new(); - for texture_type in &texture_types { - let base = concat_features("", texture_type); - composite_features.push(base.clone()); - } // YUV image brush shaders + let mut composite_features: Vec<String> = vec!["".to_string()]; let mut yuv_features: Vec<String> = Vec::new(); for texture_type in &texture_types { let base = concat_features("YUV", texture_type); composite_features.push(base.clone()); yuv_features.push(base.clone()); yuv_features.push(concat_features(&base, &brush_alpha_features)); yuv_features.push(concat_features(&base, "DEBUG_OVERDRAW")); }