Bug 1724846 - Split DL spatial tree to separate payload r=gfx-reviewers,nical

This will allow experimenting with different representations of
the spatial tree (such as interning and/or providing stable
indices during display list building). It may also simplify
future changes to the public API to expose the spatial tree
directly.

As part of these changes, refactor how the debug representation
for the capture format is (de)serialized, to make it simpler to
add different payload vector types in future.

Differential Revision: https://phabricator.services.mozilla.com/D122183
This commit is contained in:
Glenn Watson 2021-08-15 20:44:03 +00:00
Родитель 114a7d296d
Коммит 2ae662cff6
13 изменённых файлов: 377 добавлений и 304 удалений

Просмотреть файл

@ -465,7 +465,7 @@ void AsyncImagePipelineManager::ApplyAsyncImageForPipeline(
aSceneBuilderTxn.SetDisplayList(gfx::DeviceColor(0.f, 0.f, 0.f, 0.f), aEpoch,
wr::ToLayoutSize(aPipeline->mScBounds.Size()),
aPipelineId, dl.dl_desc, dl.dl_items,
dl.dl_cache);
dl.dl_cache, dl.dl_spatial_tree);
}
void AsyncImagePipelineManager::ApplyAsyncImageForPipeline(
@ -520,7 +520,7 @@ void AsyncImagePipelineManager::SetEmptyDisplayList(
builder.Finalize(dl);
txn.SetDisplayList(gfx::DeviceColor(0.f, 0.f, 0.f, 0.f), epoch,
wr::ToLayoutSize(pipeline->mScBounds.Size()), aPipelineId,
dl.dl_desc, dl.dl_items, dl.dl_cache);
dl.dl_desc, dl.dl_items, dl.dl_cache, dl.dl_spatial_tree);
}
void AsyncImagePipelineManager::HoldExternalImage(

Просмотреть файл

@ -18,6 +18,7 @@ void IPDLParamTraits<mozilla::layers::DisplayListData>::Write(
WriteIPDLParam(aMsg, aActor, aParam.mCommands);
WriteIPDLParam(aMsg, aActor, std::move(aParam.mDLItems));
WriteIPDLParam(aMsg, aActor, std::move(aParam.mDLCache));
WriteIPDLParam(aMsg, aActor, std::move(aParam.mDLSpatialTree));
WriteIPDLParam(aMsg, aActor, aParam.mDLDesc);
WriteIPDLParam(aMsg, aActor, aParam.mRemotePipelineIds);
WriteIPDLParam(aMsg, aActor, aParam.mResourceUpdates);
@ -34,6 +35,7 @@ bool IPDLParamTraits<mozilla::layers::DisplayListData>::Read(
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mCommands) &&
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDLItems) &&
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDLCache) &&
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDLSpatialTree) &&
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mDLDesc) &&
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRemotePipelineIds) &&
ReadIPDLParam(aMsg, aIter, aActor, &aResult->mResourceUpdates) &&

Просмотреть файл

@ -22,6 +22,7 @@ struct DisplayListData {
nsTArray<WebRenderParentCommand> mCommands;
Maybe<mozilla::ipc::ByteBuf> mDLItems;
Maybe<mozilla::ipc::ByteBuf> mDLCache;
Maybe<mozilla::ipc::ByteBuf> mDLSpatialTree;
wr::BuiltDisplayListDescriptor mDLDesc;
nsTArray<wr::PipelineId> mRemotePipelineIds;
nsTArray<OpUpdateResource> mResourceUpdates;

Просмотреть файл

@ -1101,7 +1101,8 @@ void WebRenderBridgeParent::SetAPZSampleTime() {
bool WebRenderBridgeParent::SetDisplayList(
const LayoutDeviceRect& aRect, ipc::ByteBuf&& aDLItems,
ipc::ByteBuf&& aDLCache, const wr::BuiltDisplayListDescriptor& aDLDesc,
ipc::ByteBuf&& aDLCache, ipc::ByteBuf&& aSpatialTreeDL,
const wr::BuiltDisplayListDescriptor& aDLDesc,
const nsTArray<OpUpdateResource>& aResourceUpdates,
const nsTArray<RefCountedShmem>& aSmallShmems,
const nsTArray<ipc::Shmem>& aLargeShmems, const TimeStamp& aTxnStartTime,
@ -1114,6 +1115,7 @@ bool WebRenderBridgeParent::SetDisplayList(
wr::Vec<uint8_t> dlItems(std::move(aDLItems));
wr::Vec<uint8_t> dlCache(std::move(aDLCache));
wr::Vec<uint8_t> dlSpatialTreeData(std::move(aSpatialTreeDL));
if (IsRootWebRenderBridgeParent()) {
#ifdef MOZ_WIDGET_GTK
@ -1129,7 +1131,7 @@ bool WebRenderBridgeParent::SetDisplayList(
gfx::DeviceColor clearColor(0.f, 0.f, 0.f, 0.f);
aTxn.SetDisplayList(clearColor, aWrEpoch,
wr::ToLayoutSize(RoundedToInt(aRect).Size()), mPipelineId,
aDLDesc, dlItems, dlCache);
aDLDesc, dlItems, dlCache, dlSpatialTreeData);
if (aObserveLayersUpdate) {
aTxn.Notify(
@ -1175,10 +1177,12 @@ bool WebRenderBridgeParent::ProcessDisplayListData(
return false;
}
if (aDisplayList.mDLItems && aDisplayList.mDLCache && aValidTransaction &&
if (aDisplayList.mDLItems && aDisplayList.mDLCache &&
aDisplayList.mDLSpatialTree && aValidTransaction &&
!SetDisplayList(aDisplayList.mRect,
std::move(aDisplayList.mDLItems.ref()),
std::move(aDisplayList.mDLCache.ref()),
std::move(aDisplayList.mDLSpatialTree.ref()),
aDisplayList.mDLDesc, aDisplayList.mResourceUpdates,
aDisplayList.mSmallShmems, aDisplayList.mLargeShmems,
aTxnStartTime, txn, aWrEpoch, aObserveLayersUpdate)) {

Просмотреть файл

@ -332,7 +332,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent,
bool aObserveLayersUpdate);
bool SetDisplayList(const LayoutDeviceRect& aRect, ipc::ByteBuf&& aDLItems,
ipc::ByteBuf&& aDLCache,
ipc::ByteBuf&& aDLCache, ipc::ByteBuf&& aSpatialTreeDL,
const wr::BuiltDisplayListDescriptor& aDLDesc,
const nsTArray<OpUpdateResource>& aResourceUpdates,
const nsTArray<RefCountedShmem>& aSmallShmems,

Просмотреть файл

@ -455,6 +455,7 @@ void WebRenderLayerManager::EndTransactionWithoutLayer(
builder.Finalize(dlData);
mLastDisplayListSize.items_size = dlData.mDLItems->mCapacity;
mLastDisplayListSize.cache_size = dlData.mDLCache->mCapacity;
mLastDisplayListSize.spatial_tree_size = dlData.mDLSpatialTree->mCapacity;
resourceUpdates.Flush(dlData.mResourceUpdates, dlData.mSmallShmems,
dlData.mLargeShmems);
dlData.mRect =

Просмотреть файл

@ -263,10 +263,12 @@ void TransactionBuilder::SetDisplayList(
const gfx::DeviceColor& aBgColor, Epoch aEpoch,
const wr::LayoutSize& aViewportSize, wr::WrPipelineId pipeline_id,
wr::BuiltDisplayListDescriptor dl_descriptor,
wr::Vec<uint8_t>& dl_items_data, wr::Vec<uint8_t>& dl_cache_data) {
wr::Vec<uint8_t>& dl_items_data, wr::Vec<uint8_t>& dl_cache_data,
wr::Vec<uint8_t>& dl_spatial_tree) {
wr_transaction_set_display_list(mTxn, aEpoch, ToColorF(aBgColor),
aViewportSize, pipeline_id, dl_descriptor,
&dl_items_data.inner, &dl_cache_data.inner);
&dl_items_data.inner, &dl_cache_data.inner,
&dl_spatial_tree.inner);
}
void TransactionBuilder::ClearDisplayList(Epoch aEpoch,
@ -996,9 +998,9 @@ void DisplayListBuilder::DumpSerializedDisplayList() {
}
void DisplayListBuilder::Finalize(BuiltDisplayList& aOutDisplayList) {
wr_api_finalize_builder(mWrState, &aOutDisplayList.dl_desc,
&aOutDisplayList.dl_items.inner,
&aOutDisplayList.dl_cache.inner);
wr_api_finalize_builder(
mWrState, &aOutDisplayList.dl_desc, &aOutDisplayList.dl_items.inner,
&aOutDisplayList.dl_cache.inner, &aOutDisplayList.dl_spatial_tree.inner);
}
void DisplayListBuilder::Finalize(layers::DisplayListData& aOutTransaction) {
@ -1006,18 +1008,23 @@ void DisplayListBuilder::Finalize(layers::DisplayListData& aOutTransaction) {
wr_dp_set_cache_size(mWrState, mDisplayItemCache->CurrentSize());
}
wr::VecU8 dlItems, dlCache;
wr::VecU8 dlItems, dlCache, dlSpatialTree;
wr_api_finalize_builder(mWrState, &aOutTransaction.mDLDesc, &dlItems.inner,
&dlCache.inner);
&dlCache.inner, &dlSpatialTree.inner);
aOutTransaction.mDLItems.emplace(dlItems.inner.data, dlItems.inner.length,
dlItems.inner.capacity);
aOutTransaction.mDLCache.emplace(dlCache.inner.data, dlCache.inner.length,
dlCache.inner.capacity);
aOutTransaction.mDLSpatialTree.emplace(dlSpatialTree.inner.data,
dlSpatialTree.inner.length,
dlSpatialTree.inner.capacity);
aOutTransaction.mRemotePipelineIds = std::move(mRemotePipelineIds);
dlItems.inner.capacity = 0;
dlItems.inner.data = nullptr;
dlCache.inner.capacity = 0;
dlCache.inner.data = nullptr;
dlSpatialTree.inner.capacity = 0;
dlSpatialTree.inner.data = nullptr;
}
Maybe<wr::WrSpatialId> DisplayListBuilder::PushStackingContext(

Просмотреть файл

@ -113,7 +113,8 @@ class TransactionBuilder final {
wr::WrPipelineId pipeline_id,
wr::BuiltDisplayListDescriptor dl_descriptor,
wr::Vec<uint8_t>& dl_items_data,
wr::Vec<uint8_t>& dl_cache_data);
wr::Vec<uint8_t>& dl_cache_data,
wr::Vec<uint8_t>& dl_spatial_tree);
void ClearDisplayList(Epoch aEpoch, wr::WrPipelineId aPipeline);

Просмотреть файл

@ -740,6 +740,7 @@ struct ByteBuffer {
struct BuiltDisplayList {
wr::VecU8 dl_items;
wr::VecU8 dl_cache;
wr::VecU8 dl_spatial_tree;
wr::BuiltDisplayListDescriptor dl_desc;
};

Просмотреть файл

@ -1837,6 +1837,7 @@ pub extern "C" fn wr_transaction_set_display_list(
dl_descriptor: BuiltDisplayListDescriptor,
dl_items_data: &mut WrVecU8,
dl_cache_data: &mut WrVecU8,
dl_spatial_tree_data: &mut WrVecU8,
) {
let color = if background.a == 0.0 { None } else { Some(background) };
@ -1848,6 +1849,7 @@ pub extern "C" fn wr_transaction_set_display_list(
let payload = DisplayListPayload {
items_data: dl_items_data.flush_into_vec(),
cache_data: dl_cache_data.flush_into_vec(),
spatial_tree: dl_spatial_tree_data.flush_into_vec(),
};
let dl = BuiltDisplayList::from_data(payload, dl_descriptor);
@ -3779,12 +3781,14 @@ pub unsafe extern "C" fn wr_api_finalize_builder(
dl_descriptor: &mut BuiltDisplayListDescriptor,
dl_items_data: &mut WrVecU8,
dl_cache_data: &mut WrVecU8,
dl_spatial_tree: &mut WrVecU8,
) {
let frame_builder = mem::replace(&mut state.frame_builder, WebRenderFrameBuilder::new(state.pipeline_id));
let (_, dl) = frame_builder.dl_builder.finalize();
let (payload, descriptor) = dl.into_data();
*dl_items_data = WrVecU8::from_vec(payload.items_data);
*dl_cache_data = WrVecU8::from_vec(payload.cache_data);
*dl_spatial_tree = WrVecU8::from_vec(payload.spatial_tree);
*dl_descriptor = descriptor;
}

Просмотреть файл

@ -35,16 +35,16 @@
//! - backdrop filters (see add_backdrop_filter)
//!
use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, PrimitiveFlags};
use api::{AlphaType, BorderDetails, BorderDisplayItem, BuiltDisplayListIter, BuiltDisplayList, PrimitiveFlags};
use api::{ClipId, ColorF, CommonItemProperties, ComplexClipRegion, ComponentTransferFuncType, RasterSpace};
use api::{DisplayItem, DisplayItemRef, ExtendMode, ExternalScrollId, FilterData, SharedFontInstanceMap};
use api::{FilterOp, FilterPrimitive, FontInstanceKey, FontSize, GlyphInstance, GlyphOptions, GradientStop};
use api::{IframeDisplayItem, ImageKey, ImageRendering, ItemRange, ColorDepth, QualitySettings};
use api::{LineOrientation, LineStyle, NinePatchBorderSource, PipelineId, MixBlendMode, StackingContextFlags};
use api::{PropertyBinding, ReferenceFrameKind, ScrollFrameDisplayItem, ScrollSensitivity};
use api::{Shadow, SpaceAndClipInfo, SpatialId, StickyFrameDisplayItem, ImageMask, ItemTag};
use api::{PropertyBinding, ReferenceFrameKind, ScrollFrameDescriptor, ScrollSensitivity};
use api::{Shadow, SpaceAndClipInfo, SpatialId, StickyFrameDescriptor, ImageMask, ItemTag};
use api::{ClipMode, PrimitiveKeyKind, TransformStyle, YuvColorSpace, ColorRange, YuvData, TempFilterData};
use api::{ReferenceTransformBinding, Rotation, FillRule};
use api::{ReferenceTransformBinding, Rotation, FillRule, SpatialTreeItem, ReferenceFrameDescriptor};
use api::units::*;
use crate::image_tiling::simplify_repeated_primitive;
use crate::clip::{ClipChainId, ClipItemKey, ClipStore, ClipItemKeyKind};
@ -498,6 +498,43 @@ impl<'a> SceneBuilder<'a> {
}
}
fn build_spatial_tree_for_display_list(
&mut self,
dl: &BuiltDisplayList,
pipeline_id: PipelineId,
) {
dl.iter_spatial_tree(|item| {
match item {
SpatialTreeItem::ScrollFrame(descriptor) => {
let parent_space = self.get_space(descriptor.parent_space);
self.build_scroll_frame(
descriptor,
parent_space,
pipeline_id,
);
}
SpatialTreeItem::ReferenceFrame(descriptor) => {
let parent_space = self.get_space(descriptor.parent_spatial_id);
self.build_reference_frame(
descriptor,
parent_space,
pipeline_id,
);
}
SpatialTreeItem::StickyFrame(descriptor) => {
let parent_space = self.get_space(descriptor.parent_spatial_id);
self.build_sticky_frame(
descriptor,
parent_space,
);
}
SpatialTreeItem::Invalid => {
unreachable!();
}
}
});
}
fn build_all(&mut self, root_pipeline: &ScenePipeline) {
enum ContextKind<'a> {
Root,
@ -521,6 +558,10 @@ impl<'a> SceneBuilder<'a> {
root_pipeline.pipeline_id,
&root_pipeline.viewport_size,
);
self.build_spatial_tree_for_display_list(
&root_pipeline.display_list.display_list,
root_pipeline.pipeline_id,
);
let mut stack = vec![BuildContext {
pipeline_id: root_pipeline.pipeline_id,
@ -578,67 +619,10 @@ impl<'a> SceneBuilder<'a> {
traversal = subtraversal;
continue 'outer;
}
DisplayItem::PushReferenceFrame(ref info) => {
DisplayItem::PushReferenceFrame(..) => {
profile_scope!("build_reference_frame");
let parent_space = self.get_space(info.parent_spatial_id);
let mut subtraversal = item.sub_iter();
let transform = match info.reference_frame.transform {
ReferenceTransformBinding::Static { binding } => binding,
ReferenceTransformBinding::Computed { scale_from, vertical_flip, rotation } => {
let content_size = &self.iframe_size.last().unwrap();
let mut transform = if let Some(scale_from) = scale_from {
// If we have a 90/270 degree rotation, then scale_from
// and content_size are in different coordinate spaces and
// we need to swap width/height for them to be correct.
match rotation {
Rotation::Degree0 |
Rotation::Degree180 => {
LayoutTransform::scale(
content_size.width / scale_from.width,
content_size.height / scale_from.height,
1.0
)
},
Rotation::Degree90 |
Rotation::Degree270 => {
LayoutTransform::scale(
content_size.height / scale_from.width,
content_size.width / scale_from.height,
1.0
)
}
}
} else {
LayoutTransform::identity()
};
if vertical_flip {
let content_size = &self.iframe_size.last().unwrap();
transform = transform
.then_translate(LayoutVector3D::new(0.0, content_size.height, 0.0))
.pre_scale(1.0, -1.0, 1.0);
}
let rotate = rotation.to_matrix(**content_size);
let transform = transform.then(&rotate);
PropertyBinding::Value(transform)
},
};
self.push_reference_frame(
info.reference_frame.id,
Some(parent_space),
bc.pipeline_id,
info.reference_frame.transform_style,
transform,
info.reference_frame.kind,
info.origin.to_vector(),
);
let new_context = BuildContext {
pipeline_id: bc.pipeline_id,
kind: ContextKind::ReferenceFrame,
@ -656,28 +640,11 @@ impl<'a> SceneBuilder<'a> {
profile_scope!("iframe");
let space = self.get_space(info.space_and_clip.spatial_id);
let (size, subtraversal) = match self.push_iframe(info, space) {
let subtraversal = match self.push_iframe(info, space) {
Some(pair) => pair,
None => continue,
};
// Get a clip-chain id for the root clip for this pipeline. We will
// add that as an unconditional clip to any tile cache created within
// this iframe. This ensures these clips are handled by the tile cache
// compositing code, which is more efficient and accurate than applying
// these clips individually to each primitive.
let clip_id = ClipId::root(info.pipeline_id);
let clip_chain_id = self.get_clip_chain(clip_id);
// If this is a root iframe, force a new tile cache both before and after
// adding primitives for this iframe.
if self.iframe_size.is_empty() {
self.add_tile_cache_barrier_if_needed(SliceFlags::empty());
assert!(self.root_iframe_clip.is_none());
self.root_iframe_clip = Some(clip_chain_id);
}
self.iframe_size.push(size);
let new_context = BuildContext {
pipeline_id: info.pipeline_id,
kind: ContextKind::Iframe {
@ -736,7 +703,7 @@ impl<'a> SceneBuilder<'a> {
fn build_sticky_frame(
&mut self,
info: &StickyFrameDisplayItem,
info: &StickyFrameDescriptor,
parent_node_index: SpatialNodeIndex,
) {
let sticky_frame_info = StickyFrameInfo::new(
@ -755,9 +722,72 @@ impl<'a> SceneBuilder<'a> {
self.id_to_index_mapper.add_spatial_node(info.id, index);
}
fn build_reference_frame(
&mut self,
info: &ReferenceFrameDescriptor,
parent_space: SpatialNodeIndex,
pipeline_id: PipelineId,
) {
let transform = match info.reference_frame.transform {
ReferenceTransformBinding::Static { binding } => binding,
ReferenceTransformBinding::Computed { scale_from, vertical_flip, rotation } => {
let content_size = &self.iframe_size.last().unwrap();
let mut transform = if let Some(scale_from) = scale_from {
// If we have a 90/270 degree rotation, then scale_from
// and content_size are in different coordinate spaces and
// we need to swap width/height for them to be correct.
match rotation {
Rotation::Degree0 |
Rotation::Degree180 => {
LayoutTransform::scale(
content_size.width / scale_from.width,
content_size.height / scale_from.height,
1.0
)
},
Rotation::Degree90 |
Rotation::Degree270 => {
LayoutTransform::scale(
content_size.height / scale_from.width,
content_size.width / scale_from.height,
1.0
)
}
}
} else {
LayoutTransform::identity()
};
if vertical_flip {
let content_size = &self.iframe_size.last().unwrap();
transform = transform
.then_translate(LayoutVector3D::new(0.0, content_size.height, 0.0))
.pre_scale(1.0, -1.0, 1.0);
}
let rotate = rotation.to_matrix(**content_size);
let transform = transform.then(&rotate);
PropertyBinding::Value(transform)
},
};
self.push_reference_frame(
info.reference_frame.id,
Some(parent_space),
pipeline_id,
info.reference_frame.transform_style,
transform,
info.reference_frame.kind,
info.origin.to_vector(),
);
}
fn build_scroll_frame(
&mut self,
info: &ScrollFrameDisplayItem,
info: &ScrollFrameDescriptor,
parent_node_index: SpatialNodeIndex,
pipeline_id: PipelineId,
) {
@ -783,7 +813,7 @@ impl<'a> SceneBuilder<'a> {
&mut self,
info: &IframeDisplayItem,
spatial_node_index: SpatialNodeIndex,
) -> Option<(LayoutSize, BuiltDisplayListIter<'a>)> {
) -> Option<BuiltDisplayListIter<'a>> {
let iframe_pipeline_id = info.pipeline_id;
let pipeline = match self.scene.pipelines.get(&iframe_pipeline_id) {
Some(pipeline) => pipeline,
@ -834,7 +864,29 @@ impl<'a> SceneBuilder<'a> {
LayoutVector2D::zero(),
);
Some((info.bounds.size(), pipeline.display_list.iter()))
// Get a clip-chain id for the root clip for this pipeline. We will
// add that as an unconditional clip to any tile cache created within
// this iframe. This ensures these clips are handled by the tile cache
// compositing code, which is more efficient and accurate than applying
// these clips individually to each primitive.
let clip_id = ClipId::root(info.pipeline_id);
let clip_chain_id = self.get_clip_chain(clip_id);
// If this is a root iframe, force a new tile cache both before and after
// adding primitives for this iframe.
if self.iframe_size.is_empty() {
self.add_tile_cache_barrier_if_needed(SliceFlags::empty());
assert!(self.root_iframe_clip.is_none());
self.root_iframe_clip = Some(clip_chain_id);
}
self.iframe_size.push(info.bounds.size());
self.build_spatial_tree_for_display_list(
&pipeline.display_list.display_list,
iframe_pipeline_id,
);
Some(pipeline.display_list.iter())
}
fn get_space(
@ -1343,25 +1395,6 @@ impl<'a> SceneBuilder<'a> {
&clips,
);
},
DisplayItem::ScrollFrame(ref info) => {
profile_scope!("scrollframe");
let parent_space = self.get_space(info.parent_space);
self.build_scroll_frame(
info,
parent_space,
pipeline_id,
);
}
DisplayItem::StickyFrame(ref info) => {
profile_scope!("stickyframe");
let parent_space = self.get_space(info.parent_spatial_id);
self.build_sticky_frame(
info,
parent_space,
);
}
DisplayItem::BackdropFilter(ref info) => {
profile_scope!("backdrop");

Просмотреть файл

@ -115,6 +115,15 @@ impl SpaceAndClipInfo {
}
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
pub enum SpatialTreeItem {
ScrollFrame(ScrollFrameDescriptor),
ReferenceFrame(ReferenceFrameDescriptor),
StickyFrame(StickyFrameDescriptor),
Invalid,
}
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, PeekPoke)]
pub enum DisplayItem {
@ -142,8 +151,6 @@ pub enum DisplayItem {
ClipChain(ClipChainItem),
// Spaces and Frames that content can be scoped under.
ScrollFrame(ScrollFrameDisplayItem),
StickyFrame(StickyFrameDisplayItem),
Iframe(IframeDisplayItem),
PushReferenceFrame(ReferenceFrameDisplayListItem),
PushStackingContext(PushStackingContextDisplayItem),
@ -192,8 +199,6 @@ pub enum DebugDisplayItem {
RectClip(RectClipDisplayItem),
ClipChain(ClipChainItem, Vec<ClipId>),
ScrollFrame(ScrollFrameDisplayItem),
StickyFrame(StickyFrameDisplayItem),
Iframe(IframeDisplayItem),
PushReferenceFrame(ReferenceFrameDisplayListItem),
PushStackingContext(PushStackingContextDisplayItem),
@ -260,7 +265,7 @@ impl StickyOffsetBounds {
}
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
pub struct StickyFrameDisplayItem {
pub struct StickyFrameDescriptor {
pub id: SpatialId,
pub parent_spatial_id: SpatialId,
pub bounds: LayoutRect,
@ -297,7 +302,7 @@ pub enum ScrollSensitivity {
}
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
pub struct ScrollFrameDisplayItem {
pub struct ScrollFrameDescriptor {
/// The id of the space this scroll frame creates
pub scroll_frame_id: SpatialId,
/// The size of the contents this contains (so the backend knows how far it can scroll).
@ -742,6 +747,10 @@ pub struct BackdropFilterDisplayItem {
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
pub struct ReferenceFrameDisplayListItem {
}
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize, PeekPoke)]
pub struct ReferenceFrameDescriptor {
pub origin: LayoutPoint,
pub parent_spatial_id: SpatialId,
pub reference_frame: ReferenceFrame,
@ -1723,11 +1732,9 @@ impl DisplayItem {
DisplayItem::SetPoints => "set_points",
DisplayItem::RadialGradient(..) => "radial_gradient",
DisplayItem::Rectangle(..) => "rectangle",
DisplayItem::ScrollFrame(..) => "scroll_frame",
DisplayItem::SetGradientStops => "set_gradient_stops",
DisplayItem::ReuseItems(..) => "reuse_item",
DisplayItem::RetainedItems(..) => "retained_items",
DisplayItem::StickyFrame(..) => "sticky_frame",
DisplayItem::Text(..) => "text",
DisplayItem::YuvImage(..) => "yuv_image",
DisplayItem::BackdropFilter(..) => "backdrop_filter",

Просмотреть файл

@ -8,7 +8,7 @@ use peek_poke::{poke_inplace_slice, poke_into_vec, Poke};
#[cfg(feature = "deserialize")]
use serde::de::Deserializer;
#[cfg(feature = "serialize")]
use serde::ser::{Serializer, SerializeSeq};
use serde::ser::Serializer;
use serde::{Deserialize, Serialize};
use std::io::Write;
use std::marker::PhantomData;
@ -115,19 +115,35 @@ pub struct DisplayListPayload {
/// Serde encoded DisplayItemCache structs
pub cache_data: Vec<u8>,
/// Serde encoded SpatialTreeItem structs
pub spatial_tree: Vec<u8>,
}
impl DisplayListPayload {
fn size_in_bytes(&self) -> usize {
self.items_data.len() +
self.cache_data.len()
self.cache_data.len() +
self.spatial_tree.len()
}
#[cfg(feature = "serialize")]
fn create_debug_spatial_tree_items(&self) -> Vec<di::SpatialTreeItem> {
let mut items = Vec::new();
iter_spatial_tree(&self.spatial_tree, |item| {
items.push(*item);
});
items
}
}
impl MallocSizeOf for DisplayListPayload {
fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
self.items_data.size_of(ops) +
self.cache_data.size_of(ops)
self.cache_data.size_of(ops) +
self.spatial_tree.size_of(ops)
}
}
@ -175,7 +191,7 @@ pub struct BuiltDisplayListDescriptor {
#[derive(Clone)]
pub struct DisplayListWithCache {
display_list: BuiltDisplayList,
pub display_list: BuiltDisplayList,
cache: DisplayItemCache,
}
@ -218,13 +234,33 @@ impl MallocSizeOf for DisplayListWithCache {
}
}
/// A debug (human-readable) representation of a built display list that
/// can be used for capture and replay.
#[cfg(any(feature = "serialize", feature = "deserialize"))]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
struct DisplayListCapture {
display_items: Vec<di::DebugDisplayItem>,
spatial_tree_items: Vec<di::SpatialTreeItem>,
descriptor: BuiltDisplayListDescriptor,
}
#[cfg(feature = "serialize")]
impl Serialize for DisplayListWithCache {
fn serialize<S: Serializer>(
&self,
serializer: S
) -> Result<S::Ok, S::Error> {
BuiltDisplayList::serialize_with_iterator(serializer, self.iter())
let display_items = BuiltDisplayList::create_debug_display_items(self.iter());
let spatial_tree_items = self.display_list.payload.create_debug_spatial_tree_items();
let dl = DisplayListCapture {
display_items,
spatial_tree_items,
descriptor: self.display_list.descriptor,
};
dl.serialize(serializer)
}
}
@ -234,20 +270,112 @@ impl<'de> Deserialize<'de> for DisplayListWithCache {
where
D: Deserializer<'de>,
{
let display_list = BuiltDisplayList::deserialize(deserializer)?;
let cache = DisplayItemCache::new();
use crate::display_item::DisplayItem as Real;
use crate::display_item::DebugDisplayItem as Debug;
let capture = DisplayListCapture::deserialize(deserializer)?;
let mut spatial_tree = Vec::new();
for item in capture.spatial_tree_items {
poke_into_vec(&item, &mut spatial_tree);
}
ensure_red_zone::<di::SpatialTreeItem>(&mut spatial_tree);
let mut items_data = Vec::new();
let mut temp = Vec::new();
for complete in capture.display_items {
let item = match complete {
Debug::ClipChain(v, clip_chain_ids) => {
DisplayListBuilder::push_iter_impl(&mut temp, clip_chain_ids);
Real::ClipChain(v)
}
Debug::Text(v, glyphs) => {
DisplayListBuilder::push_iter_impl(&mut temp, glyphs);
Real::Text(v)
},
Debug::Iframe(v) => {
Real::Iframe(v)
}
Debug::PushReferenceFrame(v) => {
Real::PushReferenceFrame(v)
}
Debug::SetFilterOps(filters) => {
DisplayListBuilder::push_iter_impl(&mut temp, filters);
Real::SetFilterOps
},
Debug::SetFilterData(filter_data) => {
let func_types: Vec<di::ComponentTransferFuncType> =
[filter_data.func_r_type,
filter_data.func_g_type,
filter_data.func_b_type,
filter_data.func_a_type].to_vec();
DisplayListBuilder::push_iter_impl(&mut temp, func_types);
DisplayListBuilder::push_iter_impl(&mut temp, filter_data.r_values);
DisplayListBuilder::push_iter_impl(&mut temp, filter_data.g_values);
DisplayListBuilder::push_iter_impl(&mut temp, filter_data.b_values);
DisplayListBuilder::push_iter_impl(&mut temp, filter_data.a_values);
Real::SetFilterData
},
Debug::SetFilterPrimitives(filter_primitives) => {
DisplayListBuilder::push_iter_impl(&mut temp, filter_primitives);
Real::SetFilterPrimitives
}
Debug::SetGradientStops(stops) => {
DisplayListBuilder::push_iter_impl(&mut temp, stops);
Real::SetGradientStops
},
Debug::SetPoints(points) => {
DisplayListBuilder::push_iter_impl(&mut temp, points);
Real::SetPoints
},
Debug::RectClip(v) => Real::RectClip(v),
Debug::RoundedRectClip(v) => Real::RoundedRectClip(v),
Debug::ImageMaskClip(v) => Real::ImageMaskClip(v),
Debug::Rectangle(v) => Real::Rectangle(v),
Debug::ClearRectangle(v) => Real::ClearRectangle(v),
Debug::HitTest(v) => Real::HitTest(v),
Debug::Line(v) => Real::Line(v),
Debug::Image(v) => Real::Image(v),
Debug::RepeatingImage(v) => Real::RepeatingImage(v),
Debug::YuvImage(v) => Real::YuvImage(v),
Debug::Border(v) => Real::Border(v),
Debug::BoxShadow(v) => Real::BoxShadow(v),
Debug::Gradient(v) => Real::Gradient(v),
Debug::RadialGradient(v) => Real::RadialGradient(v),
Debug::ConicGradient(v) => Real::ConicGradient(v),
Debug::PushStackingContext(v) => Real::PushStackingContext(v),
Debug::PushShadow(v) => Real::PushShadow(v),
Debug::BackdropFilter(v) => Real::BackdropFilter(v),
Debug::PopStackingContext => Real::PopStackingContext,
Debug::PopReferenceFrame => Real::PopReferenceFrame,
Debug::PopAllShadows => Real::PopAllShadows,
};
poke_into_vec(&item, &mut items_data);
// the aux data is serialized after the item, hence the temporary
items_data.extend(temp.drain(..));
}
// Add `DisplayItem::max_size` zone of zeroes to the end of display list
// so there is at least this amount available in the display list during
// serialization.
ensure_red_zone::<di::DisplayItem>(&mut items_data);
Ok(DisplayListWithCache {
display_list,
cache,
display_list: BuiltDisplayList {
descriptor: capture.descriptor,
payload: DisplayListPayload {
cache_data: Vec::new(),
items_data,
spatial_tree,
},
},
cache: DisplayItemCache::new(),
})
}
}
impl BuiltDisplayListDescriptor {}
pub struct BuiltDisplayListIter<'a> {
list: &'a BuiltDisplayList,
data: &'a [u8],
cache: Option<&'a DisplayItemCache>,
pending_items: std::slice::Iter<'a, CachedDisplayItem>,
@ -336,10 +464,6 @@ pub struct DisplayItemRef<'a: 'b, 'b> {
// Some of these might just become ItemRanges
impl<'a, 'b> DisplayItemRef<'a, 'b> {
pub fn display_list(&self) -> &BuiltDisplayList {
self.iter.display_list()
}
// Creates a new iterator where this element's iterator is, to hack around borrowck.
pub fn sub_iter(&self) -> BuiltDisplayListIter<'a> {
self.iter.sub_iter()
@ -449,18 +573,18 @@ impl BuiltDisplayList {
}
pub fn iter(&self) -> BuiltDisplayListIter {
BuiltDisplayListIter::new(self, self.items_data(), None)
BuiltDisplayListIter::new(self.items_data(), None)
}
pub fn cache_data_iter(&self) -> BuiltDisplayListIter {
BuiltDisplayListIter::new(self, self.cache_data(), None)
BuiltDisplayListIter::new(self.cache_data(), None)
}
pub fn iter_with_cache<'a>(
&'a self,
cache: &'a DisplayItemCache
) -> BuiltDisplayListIter<'a> {
BuiltDisplayListIter::new(self, self.items_data(), Some(cache))
BuiltDisplayListIter::new(self.items_data(), Some(cache))
}
pub fn cache_size(&self) -> usize {
@ -471,15 +595,17 @@ impl BuiltDisplayList {
self.payload.size_in_bytes()
}
#[cfg(feature = "serialize")]
pub fn serialize_with_iterator<S: Serializer>(
serializer: S,
mut iterator: BuiltDisplayListIter,
) -> Result<S::Ok, S::Error> {
use crate::display_item::DisplayItem as Real;
use crate::display_item::DebugDisplayItem as Debug;
pub fn iter_spatial_tree<F>(&self, f: F) where F: FnMut(&di::SpatialTreeItem) {
iter_spatial_tree(&self.payload.spatial_tree, f)
}
let mut seq = serializer.serialize_seq(None)?;
#[cfg(feature = "serialize")]
pub fn create_debug_display_items(
mut iterator: BuiltDisplayListIter,
) -> Vec<di::DebugDisplayItem> {
use di::DisplayItem as Real;
use di::DebugDisplayItem as Debug;
let mut debug_items = Vec::new();
while let Some(item) = iterator.next_raw() {
let serial_di = match *item.item() {
@ -487,7 +613,6 @@ impl BuiltDisplayList {
v,
item.iter.cur_clip_chain_items.iter().collect()
),
Real::ScrollFrame(v) => Debug::ScrollFrame(v),
Real::Text(v) => Debug::Text(
v,
item.iter.cur_glyphs.iter().collect()
@ -527,7 +652,6 @@ impl BuiltDisplayList {
Real::RectClip(v) => Debug::RectClip(v),
Real::RoundedRectClip(v) => Debug::RoundedRectClip(v),
Real::ImageMaskClip(v) => Debug::ImageMaskClip(v),
Real::StickyFrame(v) => Debug::StickyFrame(v),
Real::Rectangle(v) => Debug::Rectangle(v),
Real::ClearRectangle(v) => Debug::ClearRectangle(v),
Real::HitTest(v) => Debug::HitTest(v),
@ -552,9 +676,10 @@ impl BuiltDisplayList {
Real::ReuseItems(_) |
Real::RetainedItems(_) => unreachable!("Unexpected item"),
};
seq.serialize_element(&serial_di)?
debug_items.push(serial_di);
}
seq.end()
debug_items
}
}
@ -575,12 +700,10 @@ fn skip_slice<'a, T: peek_poke::Peek>(data: &mut &'a [u8]) -> ItemRange<'a, T> {
impl<'a> BuiltDisplayListIter<'a> {
pub fn new(
list: &'a BuiltDisplayList,
data: &'a [u8],
cache: Option<&'a DisplayItemCache>,
) -> Self {
Self {
list,
data,
cache,
pending_items: [].iter(),
@ -603,16 +726,12 @@ impl<'a> BuiltDisplayListIter<'a> {
pub fn sub_iter(&self) -> Self {
let mut iter = BuiltDisplayListIter::new(
self.list, self.data, self.cache
self.data, self.cache
);
iter.pending_items = self.pending_items.clone();
iter
}
pub fn display_list(&self) -> &'a BuiltDisplayList {
self.list
}
pub fn current_item(&self) -> &di::DisplayItem {
match self.cur_cached_item {
Some(cached_item) => cached_item.display_item(),
@ -862,141 +981,6 @@ impl<'a, T: Copy + peek_poke::Peek> Iterator for AuxIter<'a, T> {
impl<'a, T: Copy + peek_poke::Peek> ::std::iter::ExactSizeIterator for AuxIter<'a, T> {}
#[cfg(feature = "serialize")]
impl Serialize for BuiltDisplayList {
fn serialize<S: Serializer>(
&self,
serializer: S
) -> Result<S::Ok, S::Error> {
Self::serialize_with_iterator(serializer, self.iter())
}
}
// The purpose of this implementation is to deserialize
// a display list from one format just to immediately
// serialize then into a "built" `Vec<u8>`.
#[cfg(feature = "deserialize")]
impl<'de> Deserialize<'de> for BuiltDisplayList {
fn deserialize<D: Deserializer<'de>>(
deserializer: D
) -> Result<Self, D::Error> {
use crate::display_item::DisplayItem as Real;
use crate::display_item::DebugDisplayItem as Debug;
let list = Vec::<Debug>::deserialize(deserializer)?;
let mut items_data = Vec::new();
let mut temp = Vec::new();
let mut total_clip_nodes = FIRST_CLIP_NODE_INDEX;
let mut total_spatial_nodes = FIRST_SPATIAL_NODE_INDEX;
for complete in list {
let item = match complete {
Debug::ClipChain(v, clip_chain_ids) => {
DisplayListBuilder::push_iter_impl(&mut temp, clip_chain_ids);
Real::ClipChain(v)
}
Debug::ScrollFrame(v) => {
total_spatial_nodes += 1;
total_clip_nodes += 1;
Real::ScrollFrame(v)
}
Debug::StickyFrame(v) => {
total_spatial_nodes += 1;
Real::StickyFrame(v)
}
Debug::Text(v, glyphs) => {
DisplayListBuilder::push_iter_impl(&mut temp, glyphs);
Real::Text(v)
},
Debug::Iframe(v) => {
total_clip_nodes += 1;
Real::Iframe(v)
}
Debug::PushReferenceFrame(v) => {
total_spatial_nodes += 1;
Real::PushReferenceFrame(v)
}
Debug::SetFilterOps(filters) => {
DisplayListBuilder::push_iter_impl(&mut temp, filters);
Real::SetFilterOps
},
Debug::SetFilterData(filter_data) => {
let func_types: Vec<di::ComponentTransferFuncType> =
[filter_data.func_r_type,
filter_data.func_g_type,
filter_data.func_b_type,
filter_data.func_a_type].to_vec();
DisplayListBuilder::push_iter_impl(&mut temp, func_types);
DisplayListBuilder::push_iter_impl(&mut temp, filter_data.r_values);
DisplayListBuilder::push_iter_impl(&mut temp, filter_data.g_values);
DisplayListBuilder::push_iter_impl(&mut temp, filter_data.b_values);
DisplayListBuilder::push_iter_impl(&mut temp, filter_data.a_values);
Real::SetFilterData
},
Debug::SetFilterPrimitives(filter_primitives) => {
DisplayListBuilder::push_iter_impl(&mut temp, filter_primitives);
Real::SetFilterPrimitives
}
Debug::SetGradientStops(stops) => {
DisplayListBuilder::push_iter_impl(&mut temp, stops);
Real::SetGradientStops
},
Debug::SetPoints(points) => {
DisplayListBuilder::push_iter_impl(&mut temp, points);
Real::SetPoints
},
Debug::RectClip(v) => Real::RectClip(v),
Debug::RoundedRectClip(v) => Real::RoundedRectClip(v),
Debug::ImageMaskClip(v) => Real::ImageMaskClip(v),
Debug::Rectangle(v) => Real::Rectangle(v),
Debug::ClearRectangle(v) => Real::ClearRectangle(v),
Debug::HitTest(v) => Real::HitTest(v),
Debug::Line(v) => Real::Line(v),
Debug::Image(v) => Real::Image(v),
Debug::RepeatingImage(v) => Real::RepeatingImage(v),
Debug::YuvImage(v) => Real::YuvImage(v),
Debug::Border(v) => Real::Border(v),
Debug::BoxShadow(v) => Real::BoxShadow(v),
Debug::Gradient(v) => Real::Gradient(v),
Debug::RadialGradient(v) => Real::RadialGradient(v),
Debug::ConicGradient(v) => Real::ConicGradient(v),
Debug::PushStackingContext(v) => Real::PushStackingContext(v),
Debug::PushShadow(v) => Real::PushShadow(v),
Debug::BackdropFilter(v) => Real::BackdropFilter(v),
Debug::PopStackingContext => Real::PopStackingContext,
Debug::PopReferenceFrame => Real::PopReferenceFrame,
Debug::PopAllShadows => Real::PopAllShadows,
};
poke_into_vec(&item, &mut items_data);
// the aux data is serialized after the item, hence the temporary
items_data.extend(temp.drain(..));
}
// Add `DisplayItem::max_size` zone of zeroes to the end of display list
// so there is at least this amount available in the display list during
// serialization.
ensure_red_zone::<di::DisplayItem>(&mut items_data);
Ok(BuiltDisplayList {
payload: DisplayListPayload {
items_data,
cache_data: Vec::new(),
},
descriptor: BuiltDisplayListDescriptor {
gecko_display_list_type: GeckoDisplayListType::None,
builder_start_time: 0,
builder_finish_time: 1,
send_start_time: 1,
total_clip_nodes,
total_spatial_nodes,
cache_size: 0,
},
})
}
}
#[derive(Clone, Debug)]
pub struct SaveState {
dl_items_len: usize,
@ -1066,6 +1050,7 @@ pub struct DisplayListBuilder {
pub struct DisplayListCapacity {
items_size: usize,
cache_size: usize,
spatial_tree_size: usize,
}
impl DisplayListCapacity {
@ -1073,6 +1058,7 @@ impl DisplayListCapacity {
DisplayListCapacity {
items_size: 0,
cache_size: 0,
spatial_tree_size: 0,
}
}
}
@ -1092,6 +1078,7 @@ impl DisplayListBuilder {
payload: DisplayListPayload {
items_data: Vec::with_capacity(capacity.items_size),
cache_data: Vec::with_capacity(capacity.cache_size),
spatial_tree: Vec::with_capacity(capacity.spatial_tree_size),
},
pipeline_id,
@ -1243,6 +1230,11 @@ impl DisplayListBuilder {
self.push_item_to_section(item, self.default_section());
}
#[inline]
pub fn push_spatial_tree_item(&mut self, item: &di::SpatialTreeItem) {
poke_into_vec(item, &mut self.payload.spatial_tree);
}
fn push_iter_impl<I>(data: &mut Vec<u8>, iter_source: I)
where
I: IntoIterator,
@ -1749,7 +1741,7 @@ impl DisplayListBuilder {
snapping_transform,
);
let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem {
let descriptor = di::SpatialTreeItem::ReferenceFrame(di::ReferenceFrameDescriptor {
parent_spatial_id,
origin,
reference_frame: di::ReferenceFrame {
@ -1761,9 +1753,14 @@ impl DisplayListBuilder {
id,
},
});
self.push_spatial_tree_item(&descriptor);
self.rf_mapper.push_scope();
let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem {
});
self.push_item(&item);
id
}
@ -1780,7 +1777,7 @@ impl DisplayListBuilder {
let current_offset = self.current_offset(parent_spatial_id);
let origin = origin + current_offset;
let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem {
let descriptor = di::SpatialTreeItem::ReferenceFrame(di::ReferenceFrameDescriptor {
parent_spatial_id,
origin,
reference_frame: di::ReferenceFrame {
@ -1797,8 +1794,12 @@ impl DisplayListBuilder {
id,
},
});
self.push_spatial_tree_item(&descriptor);
let item = di::DisplayItem::PushReferenceFrame(di::ReferenceFrameDisplayListItem {
});
self.push_item(&item);
id
}
@ -1982,7 +1983,7 @@ impl DisplayListBuilder {
parent.snapping_transform,
);
let item = di::DisplayItem::ScrollFrame(di::ScrollFrameDisplayItem {
let descriptor = di::SpatialTreeItem::ScrollFrame(di::ScrollFrameDescriptor {
content_rect,
frame_rect,
parent_space,
@ -1992,7 +1993,7 @@ impl DisplayListBuilder {
external_scroll_offset,
});
self.push_item(&item);
self.push_spatial_tree_item(&descriptor);
scroll_frame_id
}
@ -2115,7 +2116,7 @@ impl DisplayListBuilder {
parent.snapping_transform,
);
let item = di::DisplayItem::StickyFrame(di::StickyFrameDisplayItem {
let descriptor = di::SpatialTreeItem::StickyFrame(di::StickyFrameDescriptor {
parent_spatial_id,
id,
bounds: frame_rect,
@ -2125,7 +2126,7 @@ impl DisplayListBuilder {
previously_applied_offset,
});
self.push_item(&item);
self.push_spatial_tree_item(&descriptor);
id
}
@ -2250,6 +2251,7 @@ impl DisplayListBuilder {
// serialization.
ensure_red_zone::<di::DisplayItem>(&mut self.payload.items_data);
ensure_red_zone::<di::DisplayItem>(&mut self.payload.cache_data);
ensure_red_zone::<di::SpatialTreeItem>(&mut self.payload.spatial_tree);
let end_time = precise_time_ns();
(
@ -2389,3 +2391,13 @@ impl ReferenceFrameMapper {
*self.frames.last().unwrap().offsets.last().unwrap()
}
}
fn iter_spatial_tree<F>(spatial_tree: &[u8], mut f: F) where F: FnMut(&di::SpatialTreeItem) {
let mut src = spatial_tree;
let mut item = di::SpatialTreeItem::Invalid;
while src.len() > di::SpatialTreeItem::max_size() {
src = peek_from_slice(src, &mut item);
f(&item);
}
}