зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1821233 - Simplify and optimize how prims are pushed to command buffers r=gfx-reviewers,lsalzman
Previously, we would do a fine-grained visibility check for prims against the dirty rect stack (after coarse grained tile visibility), then prepare the primitive, then determine which command buffer(s) the prim should be added to, based on which tile(s) the prim affects. The patch changes this so that the fine-grained visibility check returns a list of command buffer(s) that the prim should be added to. This is passed to the prim prepare step, and then used to directly add prims to the buffers rather than checking which tiles are affected by the prim. The motivation for doing this will become apparent in follow up patches. We want to be able to encode multiple command buffer commands per-prim, whereas it was previously only possible to encode primitive commands. By allowing prim-prepare to write directly to the command buffers, rather than return a list of primitive commands, we can write whatever commands are needed. Future patches will use this to write segment rect streams, and other information. A side effect of this is that the `tile_rect` field in the `PrimitiveVisibility` struct is no longer required. This reduces the size of `PrimitiveInstance` from 104 bytes to 88 bytes, which is likely to be a reasonable performance win on pages that have high primitive counts. Differential Revision: https://phabricator.services.mozilla.com/D172081
This commit is contained in:
Родитель
e427011917
Коммит
a7e386d79f
|
@ -2,6 +2,7 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::units::PictureRect;
|
||||
use crate::{spatial_tree::SpatialNodeIndex, render_task_graph::RenderTaskId, surface::SurfaceTileDescriptor, picture::TileKey, renderer::GpuBufferAddress, FastHashMap, prim_store::PrimitiveInstanceIndex, gpu_cache::GpuCacheAddress};
|
||||
use crate::gpu_types::TransformPaletteId;
|
||||
use crate::segment::EdgeAaSegmentMask;
|
||||
|
@ -20,9 +21,9 @@ impl Command {
|
|||
/// Draw a complex (3d-split) primitive, that has multiple GPU cache addresses.
|
||||
const CMD_DRAW_COMPLEX_PRIM: u32 = 0x20000000;
|
||||
/// Draw a primitive, that has a single GPU buffer addresses.
|
||||
const CMD_DRAW_INSTANCE: u32 = 0x40000000;
|
||||
const CMD_DRAW_INSTANCE: u32 = 0x30000000;
|
||||
/// Draw a generic quad primitive
|
||||
const CMD_DRAW_QUAD: u32 = 0x80000000;
|
||||
const CMD_DRAW_QUAD: u32 = 0x40000000;
|
||||
|
||||
/// Bitmask for command bits of the command.
|
||||
const CMD_MASK: u32 = 0xf0000000;
|
||||
|
@ -63,7 +64,7 @@ bitflags! {
|
|||
#[repr(transparent)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct QuadFlags : u32 {
|
||||
pub struct QuadFlags : u8 {
|
||||
const IS_OPAQUE = 1 << 0;
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +196,7 @@ impl CommandBuffer {
|
|||
self.commands.push(Command::draw_quad(prim_instance_index));
|
||||
self.commands.push(Command::data((gpu_buffer_address.u as u32) << 16 | gpu_buffer_address.v as u32));
|
||||
self.commands.push(Command::data(transform_id.0));
|
||||
self.commands.push(Command::data(quad_flags.bits << 16 | edge_flags.bits() as u32));
|
||||
self.commands.push(Command::data((quad_flags.bits as u32) << 16 | edge_flags.bits() as u32));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +240,7 @@ impl CommandBuffer {
|
|||
let data = cmd_iter.next().unwrap();
|
||||
let transform_id = TransformPaletteId(cmd_iter.next().unwrap().0);
|
||||
let bits = cmd_iter.next().unwrap().0;
|
||||
let quad_flags = QuadFlags::from_bits(bits >> 16).unwrap();
|
||||
let quad_flags = QuadFlags::from_bits((bits >> 16) as u8).unwrap();
|
||||
let edge_flags = EdgeAaSegmentMask::from_bits((bits & 0xff) as u8).unwrap();
|
||||
let gpu_buffer_address = GpuBufferAddress {
|
||||
u: (data.0 >> 16) as u16,
|
||||
|
@ -290,6 +291,7 @@ pub enum CommandBufferBuilderKind {
|
|||
Simple {
|
||||
render_task_id: RenderTaskId,
|
||||
root_task_id: Option<RenderTaskId>,
|
||||
dirty_rect: PictureRect,
|
||||
},
|
||||
Invalid,
|
||||
}
|
||||
|
@ -342,11 +344,13 @@ impl CommandBufferBuilder {
|
|||
render_task_id: RenderTaskId,
|
||||
establishes_sub_graph: bool,
|
||||
root_task_id: Option<RenderTaskId>,
|
||||
dirty_rect: PictureRect,
|
||||
) -> Self {
|
||||
CommandBufferBuilder {
|
||||
kind: CommandBufferBuilderKind::Simple {
|
||||
render_task_id,
|
||||
root_task_id,
|
||||
dirty_rect,
|
||||
},
|
||||
establishes_sub_graph,
|
||||
resolve_source: None,
|
||||
|
|
|
@ -7,7 +7,7 @@ use api::units::*;
|
|||
use plane_split::BspSplitter;
|
||||
use crate::batch::{BatchBuilder, AlphaBatchBuilder, AlphaBatchContainer};
|
||||
use crate::clip::{ClipStore, ClipTree};
|
||||
use crate::command_buffer::CommandBufferList;
|
||||
use crate::command_buffer::{PrimitiveCommand, CommandBufferList, CommandBufferIndex};
|
||||
use crate::spatial_tree::{SpatialTree, SpatialNodeIndex};
|
||||
use crate::composite::{CompositorKind, CompositeState, CompositeStatePreallocator};
|
||||
use crate::debug_item::DebugItem;
|
||||
|
@ -188,6 +188,19 @@ impl<'a> FrameBuildingState<'a> {
|
|||
pub fn pop_dirty_region(&mut self) {
|
||||
self.dirty_region_stack.pop().unwrap();
|
||||
}
|
||||
|
||||
/// Push a primitive command to a set of command buffers
|
||||
pub fn push_prim(
|
||||
&mut self,
|
||||
cmd: &PrimitiveCommand,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
targets: &[CommandBufferIndex],
|
||||
) {
|
||||
for cmd_buffer_index in targets {
|
||||
let cmd_buffer = self.cmd_buffers.get_mut(*cmd_buffer_index);
|
||||
cmd_buffer.add_prim(cmd, spatial_node_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Immutable context of a picture when processing children.
|
||||
|
|
|
@ -257,7 +257,7 @@ pub type TileRect = Box2D<i32, TileCoordinate>;
|
|||
/// The maximum number of compositor surfaces that are allowed per picture cache. This
|
||||
/// is an arbitrary number that should be enough for common cases, but low enough to
|
||||
/// prevent performance and memory usage drastically degrading in pathological cases.
|
||||
const MAX_COMPOSITOR_SURFACES: usize = 4;
|
||||
pub const MAX_COMPOSITOR_SURFACES: usize = 4;
|
||||
|
||||
/// The size in device pixels of a normal cached tile.
|
||||
pub const TILE_SIZE_DEFAULT: DeviceIntSize = DeviceIntSize {
|
||||
|
@ -1643,6 +1643,11 @@ impl SubSliceIndex {
|
|||
pub fn is_primary(&self) -> bool {
|
||||
self.0 == 0
|
||||
}
|
||||
|
||||
/// Get an array index for this sub-slice
|
||||
pub fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
/// Wrapper struct around an external surface descriptor with a little more information
|
||||
|
@ -3429,7 +3434,6 @@ impl TileCacheInstance {
|
|||
|
||||
prim_instance.vis.state = VisibilityState::Visible {
|
||||
vis_flags,
|
||||
tile_rect: TileRect::new(p0, p1),
|
||||
sub_slice_index: SubSliceIndex::new(sub_slice_index),
|
||||
};
|
||||
}
|
||||
|
@ -4563,7 +4567,6 @@ impl PicturePrimitive {
|
|||
let tile_cache = tile_caches.get_mut(&slice_id).unwrap();
|
||||
let mut debug_info = SliceDebugInfo::new();
|
||||
let mut surface_render_tasks = FastHashMap::default();
|
||||
let mut surface_dirty_rects = Vec::new();
|
||||
let mut surface_local_dirty_rect = PictureRect::zero();
|
||||
let device_pixel_scale = frame_state
|
||||
.surfaces[surface_index.0]
|
||||
|
@ -4955,6 +4958,7 @@ impl PicturePrimitive {
|
|||
SurfaceTileDescriptor {
|
||||
current_task_id: render_task_id,
|
||||
composite_task_id: Some(composite_task_id),
|
||||
dirty_rect: tile.local_dirty_rect,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
|
@ -4988,11 +4992,10 @@ impl PicturePrimitive {
|
|||
SurfaceTileDescriptor {
|
||||
current_task_id: render_task_id,
|
||||
composite_task_id: None,
|
||||
dirty_rect: tile.local_dirty_rect,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
surface_dirty_rects.push(tile.local_dirty_rect);
|
||||
}
|
||||
|
||||
if frame_context.fb_config.testing {
|
||||
|
@ -5147,10 +5150,7 @@ impl PicturePrimitive {
|
|||
);
|
||||
}
|
||||
|
||||
let descriptor = SurfaceDescriptor::new_tiled(
|
||||
surface_render_tasks,
|
||||
surface_dirty_rects,
|
||||
);
|
||||
let descriptor = SurfaceDescriptor::new_tiled(surface_render_tasks);
|
||||
|
||||
frame_state.surface_builder.push_surface(
|
||||
surface_index,
|
||||
|
@ -5763,20 +5763,25 @@ impl PicturePrimitive {
|
|||
);
|
||||
|
||||
// Add the child prims to the relevant command buffers
|
||||
let mut cmd_buffer_targets = Vec::new();
|
||||
for child in list {
|
||||
let child_prim_instance = &prim_instances[child.anchor.instance_index.0 as usize];
|
||||
|
||||
let prim_cmd = PrimitiveCommand::complex(
|
||||
child.anchor.instance_index,
|
||||
child.gpu_address
|
||||
);
|
||||
|
||||
frame_state.surface_builder.push_prim(
|
||||
&prim_cmd,
|
||||
child.anchor.spatial_node_index,
|
||||
if frame_state.surface_builder.get_cmd_buffer_targets_for_prim(
|
||||
&child_prim_instance.vis,
|
||||
frame_state.cmd_buffers,
|
||||
);
|
||||
&mut cmd_buffer_targets,
|
||||
) {
|
||||
let prim_cmd = PrimitiveCommand::complex(
|
||||
child.anchor.instance_index,
|
||||
child.gpu_address
|
||||
);
|
||||
|
||||
frame_state.push_prim(
|
||||
&prim_cmd,
|
||||
child.anchor.spatial_node_index,
|
||||
&cmd_buffer_targets,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ use api::{BoxShadowClipMode, BorderStyle, ClipMode};
|
|||
use api::units::*;
|
||||
use euclid::Scale;
|
||||
use smallvec::SmallVec;
|
||||
use crate::command_buffer::{PrimitiveCommand, QuadFlags};
|
||||
use crate::command_buffer::{PrimitiveCommand, QuadFlags, CommandBufferIndex};
|
||||
use crate::image_tiling::{self, Repetition};
|
||||
use crate::border::{get_max_scale_for_border, build_border_instances};
|
||||
use crate::clip::{ClipStore};
|
||||
|
@ -54,6 +54,8 @@ pub fn prepare_primitives(
|
|||
prim_instances: &mut Vec<PrimitiveInstance>,
|
||||
) {
|
||||
profile_scope!("prepare_primitives");
|
||||
let mut cmd_buffer_targets = Vec::new();
|
||||
|
||||
for cluster in &mut prim_list.clusters {
|
||||
if !cluster.flags.contains(ClusterFlags::IS_VISIBLE) {
|
||||
continue;
|
||||
|
@ -65,7 +67,10 @@ pub fn prepare_primitives(
|
|||
);
|
||||
|
||||
for prim_instance_index in cluster.prim_range() {
|
||||
if frame_state.surface_builder.is_prim_visible_and_in_dirty_region(&prim_instances[prim_instance_index].vis) {
|
||||
if frame_state.surface_builder.get_cmd_buffer_targets_for_prim(
|
||||
&prim_instances[prim_instance_index].vis,
|
||||
&mut cmd_buffer_targets,
|
||||
) {
|
||||
let plane_split_anchor = PlaneSplitAnchor::new(
|
||||
cluster.spatial_node_index,
|
||||
PrimitiveInstanceIndex(prim_instance_index as u32),
|
||||
|
@ -84,21 +89,11 @@ pub fn prepare_primitives(
|
|||
scratch,
|
||||
tile_caches,
|
||||
prim_instances,
|
||||
&cmd_buffer_targets,
|
||||
);
|
||||
|
||||
if !scratch.prim_cmds.is_empty() {
|
||||
for prim_cmd in scratch.prim_cmds.drain(..) {
|
||||
frame_state.surface_builder.push_prim(
|
||||
&prim_cmd,
|
||||
cluster.spatial_node_index,
|
||||
&prim_instances[prim_instance_index].vis,
|
||||
frame_state.cmd_buffers,
|
||||
);
|
||||
}
|
||||
|
||||
frame_state.num_visible_primitives += 1;
|
||||
continue;
|
||||
}
|
||||
frame_state.num_visible_primitives += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(gw): Technically no need to clear visibility here, since from this point it
|
||||
|
@ -122,9 +117,9 @@ fn prepare_prim_for_render(
|
|||
scratch: &mut PrimitiveScratchBuffer,
|
||||
tile_caches: &mut FastHashMap<SliceId, Box<TileCacheInstance>>,
|
||||
prim_instances: &mut Vec<PrimitiveInstance>,
|
||||
targets: &[CommandBufferIndex],
|
||||
) {
|
||||
profile_scope!("prepare_prim_for_render");
|
||||
debug_assert!(scratch.prim_cmds.is_empty());
|
||||
|
||||
// If we have dependencies, we need to prepare them first, in order
|
||||
// to know the actual rect of this primitive.
|
||||
|
@ -237,6 +232,7 @@ fn prepare_prim_for_render(
|
|||
frame_state,
|
||||
data_stores,
|
||||
scratch,
|
||||
targets,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -254,6 +250,7 @@ fn prepare_interned_prim_for_render(
|
|||
frame_state: &mut FrameBuildingState,
|
||||
data_stores: &mut DataStores,
|
||||
scratch: &mut PrimitiveScratchBuffer,
|
||||
targets: &[CommandBufferIndex],
|
||||
) {
|
||||
let prim_spatial_node_index = cluster.spatial_node_index;
|
||||
let device_pixel_scale = frame_state.surfaces[pic_context.surface_index.0].device_pixel_scale;
|
||||
|
@ -620,15 +617,19 @@ fn prepare_interned_prim_for_render(
|
|||
frame_context.spatial_tree,
|
||||
);
|
||||
|
||||
scratch.prim_cmds.push(
|
||||
PrimitiveCommand::quad(
|
||||
frame_state.push_prim(
|
||||
&PrimitiveCommand::quad(
|
||||
prim_instance_index,
|
||||
prim_address,
|
||||
transform_id,
|
||||
quad_flags,
|
||||
aa_flags,
|
||||
)
|
||||
),
|
||||
prim_spatial_node_index,
|
||||
targets,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, .. } => {
|
||||
|
@ -740,7 +741,12 @@ fn prepare_interned_prim_for_render(
|
|||
|
||||
// TODO(gw): Consider whether it's worth doing segment building
|
||||
// for gradient primitives.
|
||||
scratch.prim_cmds.push(PrimitiveCommand::instance(prim_instance_index, stops_address));
|
||||
frame_state.push_prim(
|
||||
&PrimitiveCommand::instance(prim_instance_index, stops_address),
|
||||
prim_spatial_node_index,
|
||||
targets,
|
||||
);
|
||||
return;
|
||||
}
|
||||
PrimitiveInstanceKind::CachedLinearGradient { data_handle, ref mut visible_tiles_range, .. } => {
|
||||
profile_scope!("CachedLinearGradient");
|
||||
|
@ -914,8 +920,18 @@ fn prepare_interned_prim_for_render(
|
|||
}
|
||||
}
|
||||
|
||||
if scratch.prim_cmds.is_empty() {
|
||||
scratch.prim_cmds.push(PrimitiveCommand::simple(prim_instance_index));
|
||||
match prim_instance.vis.state {
|
||||
VisibilityState::Unset => {
|
||||
panic!("bug: invalid vis state");
|
||||
}
|
||||
VisibilityState::Visible { .. } => {
|
||||
frame_state.push_prim(
|
||||
&PrimitiveCommand::simple(prim_instance_index),
|
||||
prim_spatial_node_index,
|
||||
targets,
|
||||
);
|
||||
}
|
||||
VisibilityState::PassThrough | VisibilityState::Culled => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@ use api::{PrimitiveKeyKind, FillRule, POLYGON_CLIP_VERTEX_MAX};
|
|||
use api::units::*;
|
||||
use euclid::{SideOffsets2D, Size2D};
|
||||
use malloc_size_of::MallocSizeOf;
|
||||
use crate::command_buffer::PrimitiveCommand;
|
||||
use crate::clip::ClipLeafId;
|
||||
use crate::segment::EdgeAaSegmentMask;
|
||||
use crate::border::BorderSegmentCacheKey;
|
||||
|
@ -1213,9 +1212,6 @@ pub struct PrimitiveScratchBuffer {
|
|||
|
||||
/// Set of sub-graphs that are required, determined during visibility pass
|
||||
pub required_sub_graphs: FastHashSet<PictureIndex>,
|
||||
|
||||
/// Buffer for building primitive command lists during prepare pass
|
||||
pub prim_cmds: Vec<PrimitiveCommand>,
|
||||
}
|
||||
|
||||
impl Default for PrimitiveScratchBuffer {
|
||||
|
@ -1230,7 +1226,6 @@ impl Default for PrimitiveScratchBuffer {
|
|||
debug_items: Vec::new(),
|
||||
messages: Vec::new(),
|
||||
required_sub_graphs: FastHashSet::default(),
|
||||
prim_cmds: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1244,12 +1239,9 @@ impl PrimitiveScratchBuffer {
|
|||
self.segment_instances.recycle(recycler);
|
||||
self.gradient_tiles.recycle(recycler);
|
||||
recycler.recycle_vec(&mut self.debug_items);
|
||||
recycler.recycle_vec(&mut self.prim_cmds);
|
||||
}
|
||||
|
||||
pub fn begin_frame(&mut self) {
|
||||
assert!(self.prim_cmds.is_empty());
|
||||
|
||||
// Clear the clip mask tasks for the beginning of the frame. Append
|
||||
// a single kind representing no clip mask, at the ClipTaskIndex::INVALID
|
||||
// location.
|
||||
|
@ -1448,7 +1440,7 @@ fn test_struct_sizes() {
|
|||
// 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::<PrimitiveInstance>(), 104, "PrimitiveInstance size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveInstance>(), 88, "PrimitiveInstance size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveInstanceKind>(), 24, "PrimitiveInstanceKind size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveTemplate>(), 56, "PrimitiveTemplate size changed");
|
||||
assert_eq!(mem::size_of::<PrimitiveTemplateKind>(), 28, "PrimitiveTemplateKind size changed");
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use api::units::*;
|
||||
use crate::command_buffer::{CommandBufferBuilderKind, CommandBufferList, CommandBufferBuilder, CommandBufferIndex, PrimitiveCommand};
|
||||
use crate::command_buffer::{CommandBufferBuilderKind, CommandBufferList, CommandBufferBuilder, CommandBufferIndex};
|
||||
use crate::internal_types::FastHashMap;
|
||||
use crate::picture::{SurfaceInfo, SurfaceIndex, TileKey, SubSliceIndex};
|
||||
use crate::picture::{SurfaceInfo, SurfaceIndex, TileKey, SubSliceIndex, MAX_COMPOSITOR_SURFACES};
|
||||
use crate::prim_store::{PictureIndex};
|
||||
use crate::render_task_graph::{RenderTaskId, RenderTaskGraphBuilder};
|
||||
use crate::spatial_tree::SpatialNodeIndex;
|
||||
use crate::render_target::ResolveOp;
|
||||
use crate::render_task::{RenderTask, RenderTaskKind, RenderTaskLocation};
|
||||
use crate::visibility::{VisibilityState, PrimitiveVisibility};
|
||||
|
@ -31,6 +30,8 @@ pub struct SurfaceTileDescriptor {
|
|||
/// The compositing task for this tile, if required. This is only needed
|
||||
/// when a tile contains one or more sub-graphs.
|
||||
pub composite_task_id: Option<RenderTaskId>,
|
||||
/// Dirty rect for this tile
|
||||
pub dirty_rect: PictureRect,
|
||||
}
|
||||
|
||||
// Details of how a surface is rendered
|
||||
|
@ -42,31 +43,30 @@ pub enum SurfaceDescriptorKind {
|
|||
// A single surface (e.g. for an opacity filter)
|
||||
Simple {
|
||||
render_task_id: RenderTaskId,
|
||||
dirty_rect: PictureRect,
|
||||
},
|
||||
// A surface with 1+ intermediate tasks (e.g. blur)
|
||||
Chained {
|
||||
render_task_id: RenderTaskId,
|
||||
root_task_id: RenderTaskId,
|
||||
dirty_rect: PictureRect,
|
||||
},
|
||||
}
|
||||
|
||||
// Describes how a surface is rendered
|
||||
pub struct SurfaceDescriptor {
|
||||
kind: SurfaceDescriptorKind,
|
||||
dirty_rects: Vec<PictureRect>,
|
||||
}
|
||||
|
||||
impl SurfaceDescriptor {
|
||||
// Create a picture cache tiled surface
|
||||
pub fn new_tiled(
|
||||
tiles: FastHashMap<TileKey, SurfaceTileDescriptor>,
|
||||
dirty_rects: Vec<PictureRect>,
|
||||
) -> Self {
|
||||
SurfaceDescriptor {
|
||||
kind: SurfaceDescriptorKind::Tiled {
|
||||
tiles,
|
||||
},
|
||||
dirty_rects,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,8 +80,8 @@ impl SurfaceDescriptor {
|
|||
kind: SurfaceDescriptorKind::Chained {
|
||||
render_task_id,
|
||||
root_task_id,
|
||||
dirty_rect,
|
||||
},
|
||||
dirty_rects: vec![dirty_rect],
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,8 +93,8 @@ impl SurfaceDescriptor {
|
|||
SurfaceDescriptor {
|
||||
kind: SurfaceDescriptorKind::Simple {
|
||||
render_task_id,
|
||||
dirty_rect,
|
||||
},
|
||||
dirty_rects: vec![dirty_rect],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,93 +102,69 @@ impl SurfaceDescriptor {
|
|||
// Describes a list of command buffers that we are adding primitives to
|
||||
// for a given surface. These are created from a command buffer builder
|
||||
// as an optimization - skipping the indirection pic_task -> cmd_buffer_index
|
||||
enum CommandBufferTargets {
|
||||
// Picture cache targets target multiple command buffers
|
||||
Tiled {
|
||||
tiles: FastHashMap<TileKey, CommandBufferIndex>,
|
||||
},
|
||||
// Child surfaces target a single command buffer
|
||||
Simple {
|
||||
cmd_buffer_index: CommandBufferIndex,
|
||||
},
|
||||
struct CommandBufferTargets {
|
||||
available_cmd_buffers: Vec<Vec<(PictureRect, CommandBufferIndex)>>,
|
||||
}
|
||||
|
||||
impl CommandBufferTargets {
|
||||
// Initialize command buffer targets from a command buffer builder
|
||||
fn new() -> Self {
|
||||
CommandBufferTargets {
|
||||
available_cmd_buffers: vec![Vec::new(); MAX_COMPOSITOR_SURFACES+1],
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
&mut self,
|
||||
cb: &CommandBufferBuilder,
|
||||
rg_builder: &RenderTaskGraphBuilder,
|
||||
) {
|
||||
let new_target = match cb.kind {
|
||||
CommandBufferBuilderKind::Tiled { ref tiles, .. } => {
|
||||
let mut cb_tiles = FastHashMap::default();
|
||||
for available_cmd_buffers in &mut self.available_cmd_buffers {
|
||||
available_cmd_buffers.clear();
|
||||
}
|
||||
|
||||
match cb.kind {
|
||||
CommandBufferBuilderKind::Tiled { ref tiles, .. } => {
|
||||
for (key, desc) in tiles {
|
||||
let task = rg_builder.get_task(desc.current_task_id);
|
||||
match task.kind {
|
||||
RenderTaskKind::Picture(ref info) => {
|
||||
cb_tiles.insert(*key, info.cmd_buffer_index);
|
||||
let available_cmd_buffers = &mut self.available_cmd_buffers[key.sub_slice_index.as_usize()];
|
||||
available_cmd_buffers.push((desc.dirty_rect, info.cmd_buffer_index));
|
||||
}
|
||||
_ => unreachable!("bug: not a picture"),
|
||||
}
|
||||
}
|
||||
|
||||
CommandBufferTargets::Tiled { tiles: cb_tiles }
|
||||
}
|
||||
CommandBufferBuilderKind::Simple { render_task_id, .. } => {
|
||||
CommandBufferBuilderKind::Simple { render_task_id, dirty_rect, .. } => {
|
||||
let task = rg_builder.get_task(render_task_id);
|
||||
match task.kind {
|
||||
RenderTaskKind::Picture(ref info) => {
|
||||
CommandBufferTargets::Simple { cmd_buffer_index: info.cmd_buffer_index }
|
||||
for sub_slice_buffer in &mut self.available_cmd_buffers {
|
||||
sub_slice_buffer.push((dirty_rect, info.cmd_buffer_index));
|
||||
}
|
||||
}
|
||||
_ => unreachable!("bug: not a picture"),
|
||||
}
|
||||
}
|
||||
CommandBufferBuilderKind::Invalid => {
|
||||
CommandBufferTargets::Tiled { tiles: FastHashMap::default() }
|
||||
}
|
||||
CommandBufferBuilderKind::Invalid => {}
|
||||
};
|
||||
|
||||
*self = new_target;
|
||||
}
|
||||
|
||||
/// Push a new primitive in to the command buffer builder
|
||||
fn push_prim(
|
||||
/// For a given rect and sub-slice, get a list of command buffers to write commands to
|
||||
fn get_cmd_buffer_targets_for_rect(
|
||||
&mut self,
|
||||
prim_cmd: &PrimitiveCommand,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
tile_rect: crate::picture::TileRect,
|
||||
rect: &PictureRect,
|
||||
sub_slice_index: SubSliceIndex,
|
||||
cmd_buffers: &mut CommandBufferList,
|
||||
) {
|
||||
match self {
|
||||
CommandBufferTargets::Tiled { ref mut tiles } => {
|
||||
// For tiled builders, add the prim to the command buffer of each
|
||||
// tile that this primitive affects.
|
||||
for y in tile_rect.min.y .. tile_rect.max.y {
|
||||
for x in tile_rect.min.x .. tile_rect.max.x {
|
||||
let key = TileKey {
|
||||
tile_offset: crate::picture::TileOffset::new(x, y),
|
||||
sub_slice_index,
|
||||
};
|
||||
if let Some(cmd_buffer_index) = tiles.get(&key) {
|
||||
cmd_buffers.get_mut(*cmd_buffer_index).add_prim(
|
||||
prim_cmd,
|
||||
spatial_node_index,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CommandBufferTargets::Simple { cmd_buffer_index, .. } => {
|
||||
// For simple builders, just add the prim
|
||||
cmd_buffers.get_mut(*cmd_buffer_index).add_prim(
|
||||
prim_cmd,
|
||||
spatial_node_index,
|
||||
);
|
||||
targets: &mut Vec<CommandBufferIndex>,
|
||||
) -> bool {
|
||||
|
||||
for (dirty_rect, cmd_buffer_index) in &self.available_cmd_buffers[sub_slice_index.as_usize()] {
|
||||
if dirty_rect.intersects(rect) {
|
||||
targets.push(*cmd_buffer_index);
|
||||
}
|
||||
}
|
||||
|
||||
!targets.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,8 +175,6 @@ pub struct SurfaceBuilder {
|
|||
current_cmd_buffers: CommandBufferTargets,
|
||||
// Stack of surfaces that are parents to the current targets
|
||||
builder_stack: Vec<CommandBufferBuilder>,
|
||||
// Dirty rect stack used to reject adding primitives
|
||||
dirty_rect_stack: Vec<Vec<PictureRect>>,
|
||||
// A map of the output render tasks from any sub-graphs that haven't
|
||||
// been consumed by BackdropRender prims yet
|
||||
pub sub_graph_output_map: FastHashMap<PictureIndex, RenderTaskId>,
|
||||
|
@ -209,9 +183,8 @@ pub struct SurfaceBuilder {
|
|||
impl SurfaceBuilder {
|
||||
pub fn new() -> Self {
|
||||
SurfaceBuilder {
|
||||
current_cmd_buffers: CommandBufferTargets::Tiled { tiles: FastHashMap::default() },
|
||||
current_cmd_buffers: CommandBufferTargets::new(),
|
||||
builder_stack: Vec::new(),
|
||||
dirty_rect_stack: Vec::new(),
|
||||
sub_graph_output_map: FastHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
@ -251,26 +224,26 @@ impl SurfaceBuilder {
|
|||
// Init the surface
|
||||
surfaces[surface_index.0].clipping_rect = clipping_rect;
|
||||
|
||||
self.dirty_rect_stack.push(descriptor.dirty_rects);
|
||||
|
||||
let builder = match descriptor.kind {
|
||||
SurfaceDescriptorKind::Tiled { tiles } => {
|
||||
CommandBufferBuilder::new_tiled(
|
||||
tiles,
|
||||
)
|
||||
}
|
||||
SurfaceDescriptorKind::Simple { render_task_id } => {
|
||||
SurfaceDescriptorKind::Simple { render_task_id, dirty_rect, .. } => {
|
||||
CommandBufferBuilder::new_simple(
|
||||
render_task_id,
|
||||
is_sub_graph,
|
||||
None,
|
||||
dirty_rect,
|
||||
)
|
||||
}
|
||||
SurfaceDescriptorKind::Chained { render_task_id, root_task_id } => {
|
||||
SurfaceDescriptorKind::Chained { render_task_id, root_task_id, dirty_rect, .. } => {
|
||||
CommandBufferBuilder::new_simple(
|
||||
render_task_id,
|
||||
is_sub_graph,
|
||||
Some(root_task_id),
|
||||
dirty_rect,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
@ -321,12 +294,15 @@ impl SurfaceBuilder {
|
|||
.push(child_task_id);
|
||||
}
|
||||
|
||||
// Returns true if the given primitive is visible and also intersects the dirty
|
||||
// region of the current surface
|
||||
pub fn is_prim_visible_and_in_dirty_region(
|
||||
&self,
|
||||
// Get a list of command buffer indices that primitives should be pushed
|
||||
// to for a given current visbility / dirty state
|
||||
pub fn get_cmd_buffer_targets_for_prim(
|
||||
&mut self,
|
||||
vis: &PrimitiveVisibility,
|
||||
targets: &mut Vec<CommandBufferIndex>,
|
||||
) -> bool {
|
||||
targets.clear();
|
||||
|
||||
match vis.state {
|
||||
VisibilityState::Unset => {
|
||||
panic!("bug: invalid vis state");
|
||||
|
@ -334,14 +310,12 @@ impl SurfaceBuilder {
|
|||
VisibilityState::Culled => {
|
||||
false
|
||||
}
|
||||
VisibilityState::Visible { .. } => {
|
||||
self.dirty_rect_stack
|
||||
.last()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|dirty_rect| {
|
||||
dirty_rect.intersects(&vis.clip_chain.pic_coverage_rect)
|
||||
})
|
||||
VisibilityState::Visible { sub_slice_index, .. } => {
|
||||
self.current_cmd_buffers.get_cmd_buffer_targets_for_rect(
|
||||
&vis.clip_chain.pic_coverage_rect,
|
||||
sub_slice_index,
|
||||
targets,
|
||||
)
|
||||
}
|
||||
VisibilityState::PassThrough => {
|
||||
true
|
||||
|
@ -349,31 +323,6 @@ impl SurfaceBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
// Push a primitive to the current cmd buffer target(s)
|
||||
pub fn push_prim(
|
||||
&mut self,
|
||||
prim_cmd: &PrimitiveCommand,
|
||||
spatial_node_index: SpatialNodeIndex,
|
||||
vis: &PrimitiveVisibility,
|
||||
cmd_buffers: &mut CommandBufferList,
|
||||
) {
|
||||
match vis.state {
|
||||
VisibilityState::Unset => {
|
||||
panic!("bug: invalid vis state");
|
||||
}
|
||||
VisibilityState::Visible { tile_rect, sub_slice_index, .. } => {
|
||||
self.current_cmd_buffers.push_prim(
|
||||
prim_cmd,
|
||||
spatial_node_index,
|
||||
tile_rect,
|
||||
sub_slice_index,
|
||||
cmd_buffers,
|
||||
)
|
||||
}
|
||||
VisibilityState::PassThrough | VisibilityState::Culled => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Finish adding primitives and child tasks to a surface and pop it off the stack
|
||||
pub fn pop_surface(
|
||||
&mut self,
|
||||
|
@ -381,8 +330,6 @@ impl SurfaceBuilder {
|
|||
rg_builder: &mut RenderTaskGraphBuilder,
|
||||
cmd_buffers: &mut CommandBufferList,
|
||||
) {
|
||||
self.dirty_rect_stack.pop().unwrap();
|
||||
|
||||
let builder = self.builder_stack.pop().unwrap();
|
||||
|
||||
if builder.establishes_sub_graph {
|
||||
|
@ -391,7 +338,7 @@ impl SurfaceBuilder {
|
|||
CommandBufferBuilderKind::Tiled { .. } | CommandBufferBuilderKind::Invalid => {
|
||||
unreachable!("bug: sub-graphs can only be simple surfaces");
|
||||
}
|
||||
CommandBufferBuilderKind::Simple { render_task_id: child_render_task_id, root_task_id: child_root_task_id } => {
|
||||
CommandBufferBuilderKind::Simple { render_task_id: child_render_task_id, root_task_id: child_root_task_id, .. } => {
|
||||
// Get info about the resolve operation to copy from parent surface or tiles to the picture cache task
|
||||
if let Some(resolve_task_id) = builder.resolve_source {
|
||||
let mut src_task_ids = Vec::new();
|
||||
|
@ -601,7 +548,7 @@ impl SurfaceBuilder {
|
|||
}
|
||||
}
|
||||
}
|
||||
CommandBufferBuilderKind::Simple { render_task_id: child_task_id, root_task_id: child_root_task_id } => {
|
||||
CommandBufferBuilderKind::Simple { render_task_id: child_task_id, root_task_id: child_root_task_id, .. } => {
|
||||
match self.builder_stack.last().unwrap().kind {
|
||||
CommandBufferBuilderKind::Tiled { ref tiles } => {
|
||||
// For a tiled render task, add as a dependency to every tile.
|
||||
|
|
|
@ -17,7 +17,7 @@ use crate::clip::{ClipChainInstance, ClipTree};
|
|||
use crate::frame_builder::FrameBuilderConfig;
|
||||
use crate::gpu_cache::GpuCache;
|
||||
use crate::picture::{PictureCompositeMode, ClusterFlags, SurfaceInfo, TileCacheInstance};
|
||||
use crate::picture::{SurfaceIndex, RasterConfig, TileRect, SubSliceIndex};
|
||||
use crate::picture::{SurfaceIndex, RasterConfig, SubSliceIndex};
|
||||
use crate::prim_store::{ClipTaskIndex, PictureIndex, PrimitiveInstanceKind};
|
||||
use crate::prim_store::{PrimitiveStore, PrimitiveInstance};
|
||||
use crate::render_backend::{DataStores, ScratchBuffer};
|
||||
|
@ -94,9 +94,6 @@ pub enum VisibilityState {
|
|||
/// during batching of visible primitives.
|
||||
vis_flags: PrimitiveVisibilityFlags,
|
||||
|
||||
/// Tiles that this primitive intersects with
|
||||
tile_rect: TileRect,
|
||||
|
||||
/// Sub-slice within the picture cache that this prim exists on
|
||||
sub_slice_index: SubSliceIndex,
|
||||
},
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
root:
|
||||
items:
|
||||
- image: checkerboard(2,16,16)
|
||||
bounds: [50, 50, 262, 262]
|
||||
- type: stacking-context
|
||||
filters: [opacity(0.5)]
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [100, 100, 162, 162]
|
||||
color: green
|
|
@ -0,0 +1,15 @@
|
|||
# Verify that an off-screen surface that is placed over top
|
||||
# of a compositor surface selects the correct sub-slice when
|
||||
# adding to command buffers.
|
||||
---
|
||||
root:
|
||||
items:
|
||||
- image: checkerboard(2,16,16)
|
||||
bounds: [50, 50, 262, 262]
|
||||
prefer-compositor-surface: true
|
||||
- type: stacking-context
|
||||
filters: [opacity(0.5)]
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [100, 100, 162, 162]
|
||||
color: green
|
|
@ -3,3 +3,4 @@ skip_on(android) fuzzy(2,500) == basic.yaml basic-ref.yaml
|
|||
!= picture-passthrough.yaml blank.yaml
|
||||
fuzzy(2,1000) == mix-blend.yaml mix-blend-ref.yaml
|
||||
!= coord-systems.yaml blank.yaml
|
||||
fuzzy(2,2500) == filter-overlay.yaml filter-overlay-ref.yaml
|
||||
|
|
Загрузка…
Ссылка в новой задаче