Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate interning text run #3369

Merged
merged 10 commits into from Dec 6, 2018

Add support to generically add interned data to their interner.

Only used by Primitive currently.
  • Loading branch information
djg committed Dec 5, 2018
commit 280d07d2be630e03937b3e48caef9df5459f4994
@@ -20,16 +20,18 @@ use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
use glyph_rasterizer::FontInstance;
use hit_test::{HitTestingItem, HitTestingRun};
use image::simplify_repeated_primitive;
use intern::{Handle, Internable};
use internal_types::{FastHashMap, FastHashSet};
use picture::{Picture3DContext, PictureCompositeMode, PicturePrimitive, PrimitiveList};
use prim_store::{PrimitiveInstance, PrimitiveDataInterner, PrimitiveKeyKind, RadialGradientParams};
use prim_store::{PrimitiveKey, PrimitiveSceneData, PrimitiveInstanceKind, GradientStopKey, NinePatchDescriptor};
use prim_store::{PrimitiveDataHandle, PrimitiveStore, PrimitiveStoreStats, LineDecorationCacheKey};
use prim_store::{ScrollNodeAndClipChain, PictureIndex, register_prim_chase_id, get_line_decoration_sizes};
use prim_store::{PrimitiveDataMarker};
use render_backend::{DocumentView};
use resource_cache::{FontInstanceMap, ImageRequest};
use scene::{Scene, ScenePipeline, StackingContextHelpers};
use scene_builder::DocumentResources;
use scene_builder::{DocumentResources, InternerMut};
use spatial_node::{StickyFrameInfo, ScrollFrameKind, SpatialNodeType};
use std::{f32, mem, usize};
use std::collections::vec_deque::VecDeque;
@@ -1026,20 +1028,22 @@ impl<'a> DisplayListFlattener<'a> {
/// Create a primitive and add it to the prim store. This method doesn't
/// add the primitive to the draw list, so can be used for creating
/// sub-primitives.
pub fn create_primitive(
///
/// TODO(djg): Can this inline into `add_interned_prim_to_draw_list`
fn create_primitive<P>(
&mut self,
info: &LayoutPrimitiveInfo,
clip_chain_id: ClipChainId,
spatial_node_index: SpatialNodeIndex,
prim_key_kind: PrimitiveKeyKind,
) -> PrimitiveInstance {
prim: P,
) -> PrimitiveInstance
where
P: Internable<Marker=PrimitiveDataMarker, InternData=PrimitiveSceneData>,
P::Source: AsInstanceKind<Handle<P::Marker>> + BuildKey<P>,
DocumentResources: InternerMut<P>,
{
// Build a primitive key.
let prim_key = PrimitiveKey::new(
info.is_backface_visible,
info.rect,
info.clip_rect,
prim_key_kind,
);
let prim_key = P::Source::build_key(info, prim);

// Get a tight bounding / culling rect for this primitive
// from its local rect intersection with minimal local
@@ -1048,16 +1052,17 @@ impl<'a> DisplayListFlattener<'a> {
.intersection(&info.rect)
.unwrap_or(LayoutRect::zero());

let prim_data_handle = self.resources
.prim_interner
let interner = self.resources.interner_mut();
let prim_data_handle =
interner
.intern(&prim_key, || {
PrimitiveSceneData {
culling_rect,
is_backface_visible: info.is_backface_visible,
}
});

let instance_kind = prim_key.to_instance_kind(&mut self.prim_store);
let instance_kind = prim_key.as_instance_kind(&mut self.prim_store);

PrimitiveInstance::new(
instance_kind,
@@ -1105,48 +1110,74 @@ impl<'a> DisplayListFlattener<'a> {

/// Convenience interface that creates a primitive entry and adds it
/// to the draw list.
pub fn add_primitive(
pub fn add_primitive<P>(
&mut self,
clip_and_scroll: ScrollNodeAndClipChain,
info: &LayoutPrimitiveInfo,
clip_items: Vec<(LayoutPoint, ClipItemKey)>,
key_kind: PrimitiveKeyKind,
) {
prim: P,
)
where
P: Internable<Marker = PrimitiveDataMarker, InternData = PrimitiveSceneData> + IsVisible,
P::Source: AsInstanceKind<Handle<P::Marker>> + BuildKey<P>,
DocumentResources: InternerMut<P>,
PrimitiveKeyKind: From<P>,
{
// If a shadow context is not active, then add the primitive
// directly to the parent picture.
if self.pending_shadow_items.is_empty() {
if key_kind.is_visible() {
if prim.is_visible() {
let clip_chain_id = self.build_clip_chain(
clip_items,
clip_and_scroll.spatial_node_index,
clip_and_scroll.clip_chain_id,
);
let prim_instance = self.create_primitive(
self.add_prim_to_draw_list(
info,
clip_chain_id,
clip_and_scroll.spatial_node_index,
key_kind,
);
self.register_chase_primitive_by_rect(
&info.rect,
&prim_instance,
clip_and_scroll,
prim
);
self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
self.add_primitive_to_draw_list(prim_instance);
}
} else {
debug_assert!(clip_items.is_empty(), "No per-prim clips expected for shadowed primitives");

// There is an active shadow context. Store as a pending primitive
// for processing during pop_all_shadows.
self.pending_shadow_items.push_back(ShadowItem::Primitive(PendingPrimitive {
self.pending_shadow_items.push_back(PendingPrimitive {
clip_and_scroll,
info: *info,
key_kind,
}));
key_kind: prim.into(),
}.into());
}
}

fn add_prim_to_draw_list<P>(
&mut self,
info: &LayoutPrimitiveInfo,
clip_chain_id: ClipChainId,
clip_and_scroll: ScrollNodeAndClipChain,
prim: P,
)
where
P: Internable<Marker = PrimitiveDataMarker, InternData = PrimitiveSceneData>,
P::Source: AsInstanceKind<Handle<P::Marker>> + BuildKey<P>,
DocumentResources: InternerMut<P>,
{
let prim_instance = self.create_primitive(
info,
clip_chain_id,
clip_and_scroll.spatial_node_index,
prim,
);
self.register_chase_primitive_by_rect(
&info.rect,
&prim_instance,
);
self.add_primitive_to_hit_testing_list(info, clip_and_scroll);
self.add_primitive_to_draw_list(prim_instance);
}

pub fn push_stacking_context(
&mut self,
pipeline_id: PipelineId,
@@ -1826,18 +1857,12 @@ impl<'a> DisplayListFlattener<'a> {
// For a normal primitive, if it has alpha > 0, then we add this
// as a normal primitive to the parent picture.
if pending_primitive.key_kind.is_visible() {
let prim_instance = self.create_primitive(
self.add_prim_to_draw_list(
&pending_primitive.info,
pending_primitive.clip_and_scroll.clip_chain_id,
pending_primitive.clip_and_scroll.spatial_node_index,
pending_primitive.clip_and_scroll,
pending_primitive.key_kind,
);
self.register_chase_primitive_by_rect(
&pending_primitive.info.rect,
&prim_instance,
);
self.add_primitive_to_hit_testing_list(&pending_primitive.info, pending_primitive.clip_and_scroll);
self.add_primitive_to_draw_list(prim_instance);
}
}
}
@@ -2349,6 +2374,21 @@ impl<'a> DisplayListFlattener<'a> {
}
}

pub trait AsInstanceKind<H> {
fn as_instance_kind(
&self,
prim_store: &mut PrimitiveStore,
) -> PrimitiveInstanceKind;
}

pub trait BuildKey<S> {
fn build_key(info: &LayoutPrimitiveInfo, source: S) -> Self;
}

pub trait IsVisible {
fn is_visible(&self) -> bool;
}

/// Properties of a stacking context that are maintained
/// during creation of the scene. These structures are
/// not persisted after the initial scene build.
@@ -2510,3 +2550,9 @@ enum ShadowItem {
Shadow(PendingShadow),
Primitive(PendingPrimitive),
}

impl From<PendingPrimitive> for ShadowItem {
fn from(container: PendingPrimitive) -> Self {
ShadowItem::Primitive(container)
}
}
@@ -373,3 +373,13 @@ where
&item.data
}
}

/// Implement `Internable` for a type that wants participate in interning.
///
/// see DisplayListFlattener::add_interned_primitive<P>
pub trait Internable {
type Marker: Copy + Debug;
type Source: Eq + Hash + Clone + Debug;
type StoreData: From<Self::Source>;
type InternData;
}
@@ -9,12 +9,14 @@ use api::{RasterSpace, LayoutPoint, LayoutRect, LayoutSideOffsets, LayoutSize, L
use api::{PremultipliedColorF, PropertyBinding, Shadow, YuvColorSpace, YuvFormat};
use api::{DeviceIntSideOffsets, WorldPixel, BoxShadowClipMode, NormalBorder, WorldRect, LayoutToWorldScale};
use api::{PicturePixel, RasterPixel, ColorDepth, LineStyle, LineOrientation, LayoutSizeAu, AuHelpers, LayoutVector2DAu};
use api::LayoutPrimitiveInfo;
use app_units::Au;
use border::{get_max_scale_for_border, build_border_instances, create_border_segments};
use border::{BorderSegmentCacheKey, NormalBorderAu};
use clip::{ClipStore};
use clip_scroll_tree::{ClipScrollTree, SpatialNodeIndex};
use clip::{ClipDataStore, ClipNodeFlags, ClipChainId, ClipChainInstance, ClipItem, ClipNodeCollector};
use display_list_flattener::{AsInstanceKind, BuildKey, IsVisible};
use euclid::{SideOffsets2D, TypedTransform3D, TypedRect, TypedScale, TypedSize2D};
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
use frame_builder::PrimitiveContext;
@@ -647,10 +649,12 @@ impl PrimitiveKey {
kind,
}
}
}

impl AsInstanceKind<PrimitiveDataHandle> for PrimitiveKey {
/// Construct a primitive instance that matches the type
/// of primitive key.
pub fn to_instance_kind(
fn as_instance_kind(
&self,
prim_store: &mut PrimitiveStore,
) -> PrimitiveInstanceKind {
@@ -726,6 +730,20 @@ impl PrimitiveKey {
}
}

impl BuildKey<PrimitiveKeyKind> for PrimitiveKey {
fn build_key(
info: &LayoutPrimitiveInfo,
prim_key_kind: PrimitiveKeyKind,
) -> PrimitiveKey {
PrimitiveKey::new(
info.is_backface_visible,
info.rect,
info.clip_rect,
prim_key_kind,
)
}
}

#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct NormalBorderTemplate {
@@ -1468,6 +1486,13 @@ impl PrimitiveTemplate {
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
pub struct PrimitiveDataMarker;

impl intern::Internable for PrimitiveKeyKind {
type Marker = PrimitiveDataMarker;
type Source = PrimitiveKey;
type StoreData = PrimitiveTemplate;
type InternData = PrimitiveSceneData;
}

pub type PrimitiveDataStore = intern::DataStore<PrimitiveKey, PrimitiveTemplate, PrimitiveDataMarker>;
pub type PrimitiveDataHandle = intern::Handle<PrimitiveDataMarker>;
pub type PrimitiveDataUpdateList = intern::UpdateList<PrimitiveKey>;
@@ -2231,15 +2256,15 @@ pub struct NinePatchDescriptor {
pub widths: SideOffsetsKey,
}

impl PrimitiveKeyKind {
impl IsVisible for PrimitiveKeyKind {
// Return true if the primary primitive is visible.
// Used to trivially reject non-visible primitives.
// TODO(gw): Currently, primitives other than those
// listed here are handled before the
// add_primitive() call. In the future
// we should move the logic for all other
// primitive types to use this.
pub fn is_visible(&self) -> bool {
fn is_visible(&self) -> bool {
match *self {
PrimitiveKeyKind::TextRun { ref font, .. } => {
font.color.a > 0
@@ -2260,7 +2285,9 @@ impl PrimitiveKeyKind {
}
}
}
}

impl PrimitiveKeyKind {
// Create a clone of this PrimitiveContainer, applying whatever
// changes are necessary to the primitive to support rendering
// it as part of the supplied shadow.
@@ -12,8 +12,10 @@ use frame_builder::{FrameBuilderConfig, FrameBuilder};
use clip::{ClipDataInterner, ClipDataUpdateList};
use clip_scroll_tree::ClipScrollTree;
use display_list_flattener::DisplayListFlattener;
use intern::{Internable, Interner};
use internal_types::{FastHashMap, FastHashSet};
use prim_store::{PrimitiveDataInterner, PrimitiveDataUpdateList, PrimitiveStoreStats};
use prim_store::{PrimitiveDataInterner, PrimitiveDataUpdateList, PrimitiveKeyKind};
use prim_store::PrimitiveStoreStats;
use resource_cache::FontInstanceMap;
use render_backend::DocumentView;
use renderer::{PipelineInfo, SceneBuilderHooks};
@@ -165,6 +167,18 @@ pub struct DocumentResources {
pub prim_interner: PrimitiveDataInterner,
}

// Access to `DocumentResources` interners by `Internable`
pub trait InternerMut<I: Internable>
{
fn interner_mut(&mut self) -> &mut Interner<I::Source, I::InternData, I::Marker>;
}

impl InternerMut<PrimitiveKeyKind> for DocumentResources {
fn interner_mut(&mut self) -> &mut PrimitiveDataInterner {
&mut self.prim_interner
}
}

// A document in the scene builder contains the current scene,
// as well as a persistent clip interner. This allows clips
// to be de-duplicated, and persisted in the GPU cache between
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.