Bug 1477970 - Update webrender to commit 8a4fe66528aa362721e4048aac3cd5abf7faaf2c. r=jrmuizel

MozReview-Commit-ID: H40i6i2LmAl

--HG--
extra : rebase_source : 5bd5ea3be3463b3f91a2e64da4e2c99c55cecd45
This commit is contained in:
Kartikaya Gupta 2018-07-30 09:35:05 -04:00
parent 70da238a9a
commit 78157f60ff
17 changed files with 421 additions and 468 deletions

View File

@ -497,6 +497,9 @@ impl AlphaBatchBuilder {
// Z axis is directed at the screen, `sort` is ascending, and we need back-to-front order.
for poly in splitter.sort(vec3(0.0, 0.0, 1.0)) {
let prim_index = PrimitiveIndex(poly.anchor);
if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_index) {
println!("\t\tsplit polygon {:?}", poly.points);
}
debug!("process sorted poly {:?} {:?}", prim_index, poly.points);
let pp = &poly.points;
let gpu_blocks = [
@ -654,14 +657,18 @@ impl AlphaBatchBuilder {
transform_id,
};
if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_index) {
println!("\ttask target {:?}", self.target_rect);
println!("\t{:?}", prim_header);
}
match prim_metadata.prim_kind {
PrimitiveKind::Brush => {
let brush = &ctx.prim_store.cpu_brushes[prim_metadata.cpu_prim_index.0];
match brush.kind {
BrushKind::Picture { pic_index, .. } => {
let picture =
&ctx.prim_store.pictures[pic_index.0];
let picture = &ctx.prim_store.pictures[pic_index.0];
// If this picture is participating in a 3D rendering context,
// then don't add it to any batches here. Instead, create a polygon
@ -1056,8 +1063,13 @@ impl AlphaBatchBuilder {
ctx.resource_cache,
gpu_cache,
deferred_resolves,
ctx.prim_store.chase_id == Some(prim_index),
) {
let prim_header_index = prim_headers.push(&prim_header, user_data);
if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_index) {
println!("\t{:?} {:?}, task relative bounds {:?}",
batch_kind, prim_header_index, task_relative_bounding_rect);
}
self.add_brush_to_batch(
brush,
@ -1385,6 +1397,7 @@ impl BrushPrimitive {
resource_cache: &ResourceCache,
gpu_cache: &mut GpuCache,
deferred_resolves: &mut Vec<DeferredResolve>,
is_chased: bool,
) -> Option<(BrushBatchKind, BatchTextures, [i32; 3])> {
match self.kind {
BrushKind::Image { request, ref source, .. } => {
@ -1406,6 +1419,9 @@ impl BrushPrimitive {
resource_cache.get_texture_cache_item(&rt_cache_entry.handle)
}
};
if cfg!(debug_assertions) && is_chased {
println!("\tsource {:?}", cache_item);
}
if cache_item.texture_id == SourceTexture::Invalid {
None
@ -1751,7 +1767,7 @@ impl ClipBatcher {
) {
let instance = ClipMaskInstance {
render_task_address: task_address,
transform_id: TransformPaletteId::identity(),
transform_id: TransformPaletteId::IDENTITY,
segment: 0,
clip_data_address,
resource_address: GpuCacheAddress::invalid(),
@ -1772,16 +1788,14 @@ impl ClipBatcher {
) {
let mut coordinate_system_id = coordinate_system_id;
for work_item in clips.iter() {
let info = clip_store.get(work_item.clip_sources_index);
let instance = ClipMaskInstance {
render_task_address: task_address,
transform_id: transforms.get_id(work_item.spatial_node_index),
transform_id: transforms.get_id(info.spatial_node_index),
segment: 0,
clip_data_address: GpuCacheAddress::invalid(),
resource_address: GpuCacheAddress::invalid(),
};
let info = clip_store
.get_opt(&work_item.clip_sources)
.expect("bug: clip handle should be valid");
for &(ref source, ref handle) in &info.clips {
let gpu_address = gpu_cache.get_address(handle);

View File

@ -9,22 +9,51 @@ use border::{ensure_no_corner_overlap};
use box_shadow::{BLUR_SAMPLE_SCALE, BoxShadowClipSource, BoxShadowCacheKey};
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, SpatialNodeIndex};
use ellipse::Ellipse;
use freelist::{FreeList, FreeListHandle, WeakFreeListHandle};
use gpu_cache::{GpuCache, GpuCacheHandle, ToGpuBlocks};
use gpu_types::BoxShadowStretchMode;
use prim_store::{ClipData, ImageMaskData};
use render_task::to_cache_size;
use resource_cache::{ImageRequest, ResourceCache};
use util::{LayoutToWorldFastTransform, MaxRect, calculate_screen_bounding_rect};
use util::{extract_inner_rect_safe, pack_as_float};
use util::{extract_inner_rect_safe, pack_as_float, recycle_vec};
use std::sync::Arc;
#[derive(Debug)]
pub enum ClipStoreMarker {}
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ClipSourcesIndex(usize);
pub type ClipStore = FreeList<ClipSources, ClipStoreMarker>;
pub type ClipSourcesHandle = FreeListHandle<ClipStoreMarker>;
pub type ClipSourcesWeakHandle = WeakFreeListHandle<ClipStoreMarker>;
pub struct ClipStore {
clip_sources: Vec<ClipSources>,
}
impl ClipStore {
pub fn new() -> ClipStore {
ClipStore {
clip_sources: Vec::new(),
}
}
pub fn recycle(self) -> ClipStore {
ClipStore {
clip_sources: recycle_vec(self.clip_sources),
}
}
pub fn insert(&mut self, clip_sources: ClipSources) -> ClipSourcesIndex {
let index = ClipSourcesIndex(self.clip_sources.len());
self.clip_sources.push(clip_sources);
index
}
pub fn get(&self, index: ClipSourcesIndex) -> &ClipSources {
&self.clip_sources[index.0]
}
pub fn get_mut(&mut self, index: ClipSourcesIndex) -> &mut ClipSources {
&mut self.clip_sources[index.0]
}
}
#[derive(Debug)]
pub struct LineDecorationClipSource {
@ -91,28 +120,6 @@ pub enum ClipSource {
LineDecoration(LineDecorationClipSource),
}
impl From<ClipRegion> for ClipSources {
fn from(region: ClipRegion) -> ClipSources {
let mut clips = Vec::new();
if let Some(info) = region.image_mask {
clips.push(ClipSource::Image(info));
}
clips.push(ClipSource::Rectangle(region.main, ClipMode::Clip));
for complex in region.complex_clips {
clips.push(ClipSource::new_rounded_rect(
complex.rect,
complex.radii,
complex.mode,
));
}
ClipSources::new(clips)
}
}
impl ClipSource {
pub fn new_rounded_rect(
rect: LayoutRect,
@ -280,10 +287,14 @@ pub struct ClipSources {
pub local_outer_rect: Option<LayoutRect>,
pub only_rectangular_clips: bool,
pub has_image_or_line_decoration_clip: bool,
pub spatial_node_index: SpatialNodeIndex,
}
impl ClipSources {
pub fn new(clips: Vec<ClipSource>) -> Self {
pub fn new(
clips: Vec<ClipSource>,
spatial_node_index: SpatialNodeIndex,
) -> Self {
let (local_inner_rect, local_outer_rect) = Self::calculate_inner_and_outer_rects(&clips);
let has_image_or_line_decoration_clip =
@ -301,9 +312,33 @@ impl ClipSources {
local_outer_rect,
only_rectangular_clips,
has_image_or_line_decoration_clip,
spatial_node_index,
}
}
pub fn from_region(
region: ClipRegion,
spatial_node_index: SpatialNodeIndex,
) -> ClipSources {
let mut clips = Vec::new();
if let Some(info) = region.image_mask {
clips.push(ClipSource::Image(info));
}
clips.push(ClipSource::Rectangle(region.main, ClipMode::Clip));
for complex in region.complex_clips {
clips.push(ClipSource::new_rounded_rect(
complex.rect,
complex.radii,
complex.mode,
));
}
ClipSources::new(clips, spatial_node_index)
}
pub fn clips(&self) -> &[(ClipSource, GpuCacheHandle)] {
&self.clips
}
@ -647,8 +682,7 @@ impl Iterator for ClipChainNodeIter {
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct ClipWorkItem {
pub spatial_node_index: SpatialNodeIndex,
pub clip_sources: ClipSourcesWeakHandle,
pub clip_sources_index: ClipSourcesIndex,
pub coordinate_system_id: CoordinateSystemId,
}

View File

@ -3,19 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use api::DevicePixelScale;
use clip::{ClipChain, ClipChainNode, ClipSourcesHandle, ClipStore, ClipWorkItem};
use clip_scroll_tree::{ClipChainIndex, SpatialNodeIndex};
use clip::{ClipChain, ClipChainNode, ClipSourcesIndex, ClipStore, ClipWorkItem};
use clip_scroll_tree::{ClipChainIndex};
use gpu_cache::GpuCache;
use resource_cache::ResourceCache;
use spatial_node::SpatialNode;
#[derive(Debug)]
pub struct ClipNode {
/// The node that determines how this clip node is positioned.
pub spatial_node: SpatialNodeIndex,
/// A handle to this clip nodes clips in the ClipStore.
pub handle: Option<ClipSourcesHandle>,
pub clip_sources_index: ClipSourcesIndex,
/// An index to a ClipChain defined by this ClipNode's hiearchy in the display
/// list.
@ -31,35 +28,18 @@ pub struct ClipNode {
}
impl ClipNode {
const EMPTY: ClipNode = ClipNode {
spatial_node: SpatialNodeIndex(0),
handle: None,
clip_chain_index: ClipChainIndex::NO_CLIP,
parent_clip_chain_index: ClipChainIndex::NO_CLIP,
clip_chain_node: None,
};
pub fn empty() -> ClipNode {
ClipNode::EMPTY
}
pub fn update(
&mut self,
spatial_node: &SpatialNode,
device_pixel_scale: DevicePixelScale,
clip_store: &mut ClipStore,
resource_cache: &mut ResourceCache,
gpu_cache: &mut GpuCache,
clip_chains: &mut [ClipChain],
spatial_nodes: &[SpatialNode],
) {
let (clip_sources, weak_handle) = match self.handle {
Some(ref handle) => (clip_store.get_mut(handle), handle.weak()),
None => {
warn!("Tried to process an empty clip node");
return;
}
};
let clip_sources = clip_store.get_mut(self.clip_sources_index);
clip_sources.update(gpu_cache, resource_cache, device_pixel_scale);
let spatial_node = &spatial_nodes[clip_sources.spatial_node_index.0];
let (screen_inner_rect, screen_outer_rect) = clip_sources.get_screen_bounds(
&spatial_node.world_content_transform,
@ -77,8 +57,7 @@ impl ClipNode {
let new_node = ClipChainNode {
work_item: ClipWorkItem {
spatial_node_index: self.spatial_node,
clip_sources: weak_handle,
clip_sources_index: self.clip_sources_index,
coordinate_system_id: spatial_node.coordinate_system_id,
},
local_clip_rect: spatial_node

View File

@ -5,7 +5,7 @@
use api::{DeviceIntRect, DevicePixelScale, ExternalScrollId, LayoutPoint, LayoutRect, LayoutVector2D};
use api::{PipelineId, ScrollClamping, ScrollLocation, ScrollNodeState};
use api::{LayoutSize, LayoutTransform, PropertyBinding, ScrollSensitivity, WorldPoint};
use clip::{ClipChain, ClipSourcesHandle, ClipStore};
use clip::{ClipChain, ClipSourcesIndex, ClipStore};
use clip_node::ClipNode;
use gpu_cache::GpuCache;
use gpu_types::TransformPalette;
@ -256,14 +256,13 @@ impl ClipScrollTree {
);
for clip_node in &mut self.clip_nodes {
let spatial_node = &self.spatial_nodes[clip_node.spatial_node.0];
clip_node.update(
spatial_node,
device_pixel_scale,
clip_store,
resource_cache,
gpu_cache,
&mut self.clip_chains,
&self.spatial_nodes,
);
}
self.build_clip_chains(screen_rect);
@ -355,33 +354,29 @@ impl ClipScrollTree {
pub fn add_clip_node(
&mut self,
index: ClipNodeIndex,
parent_clip_chain_index: ClipChainIndex,
spatial_node: SpatialNodeIndex,
handle: ClipSourcesHandle,
) -> ClipChainIndex {
clip_sources_index: ClipSourcesIndex,
) -> (ClipNodeIndex, ClipChainIndex) {
let clip_chain_index = self.allocate_clip_chain();
let node = ClipNode {
parent_clip_chain_index,
spatial_node,
handle: Some(handle),
clip_sources_index,
clip_chain_index,
clip_chain_node: None,
};
self.push_clip_node(node, index);
clip_chain_index
let node_index = self.push_clip_node(node);
(node_index, clip_chain_index)
}
pub fn add_scroll_frame(
&mut self,
index: SpatialNodeIndex,
parent_index: SpatialNodeIndex,
external_id: Option<ExternalScrollId>,
pipeline_id: PipelineId,
frame_rect: &LayoutRect,
content_size: &LayoutSize,
scroll_sensitivity: ScrollSensitivity,
) {
) -> SpatialNodeIndex {
let node = SpatialNode::new_scroll_frame(
pipeline_id,
parent_index,
@ -390,18 +385,17 @@ impl ClipScrollTree {
content_size,
scroll_sensitivity,
);
self.add_spatial_node(node, index);
self.add_spatial_node(node)
}
pub fn add_reference_frame(
&mut self,
index: SpatialNodeIndex,
parent_index: Option<SpatialNodeIndex>,
source_transform: Option<PropertyBinding<LayoutTransform>>,
source_perspective: Option<LayoutTransform>,
origin_in_parent_reference_frame: LayoutVector2D,
pipeline_id: PipelineId,
) {
) -> SpatialNodeIndex {
let node = SpatialNode::new_reference_frame(
parent_index,
source_transform,
@ -409,22 +403,21 @@ impl ClipScrollTree {
origin_in_parent_reference_frame,
pipeline_id,
);
self.add_spatial_node(node, index);
self.add_spatial_node(node)
}
pub fn add_sticky_frame(
&mut self,
index: SpatialNodeIndex,
parent_index: SpatialNodeIndex,
sticky_frame_info: StickyFrameInfo,
pipeline_id: PipelineId,
) {
) -> SpatialNodeIndex {
let node = SpatialNode::new_sticky_frame(
parent_index,
sticky_frame_info,
pipeline_id,
);
self.add_spatial_node(node, index);
self.add_spatial_node(node)
}
pub fn add_clip_chain_descriptor(
@ -437,47 +430,22 @@ impl ClipScrollTree {
index
}
pub fn push_clip_node(&mut self, node: ClipNode, index: ClipNodeIndex) {
if index.0 == self.clip_nodes.len() {
self.clip_nodes.push(node);
return;
}
if let Some(empty_node) = self.clip_nodes.get_mut(index.0) {
*empty_node = node;
return
}
let length_to_reserve = index.0 + 1 - self.clip_nodes.len();
self.clip_nodes.reserve_exact(length_to_reserve);
// We would like to use `Vec::resize` here, but the Clone trait is not supported
// for ClipNodes. We can fix this either when support is added for something like
// `Vec::resize_default`.
let length_to_extend = self.clip_nodes.len() .. index.0;
self.clip_nodes.extend(length_to_extend.map(|_| ClipNode::empty()));
pub fn push_clip_node(&mut self, node: ClipNode) -> ClipNodeIndex {
let index = ClipNodeIndex(self.clip_nodes.len());
self.clip_nodes.push(node);
index
}
pub fn add_spatial_node(&mut self, node: SpatialNode, index: SpatialNodeIndex) {
pub fn add_spatial_node(&mut self, node: SpatialNode) -> SpatialNodeIndex {
let index = SpatialNodeIndex(self.spatial_nodes.len());
// When the parent node is None this means we are adding the root.
if let Some(parent_index) = node.parent {
self.spatial_nodes[parent_index.0].add_child(index);
}
if index.0 == self.spatial_nodes.len() {
self.spatial_nodes.push(node);
return;
}
if let Some(empty_node) = self.spatial_nodes.get_mut(index.0) {
*empty_node = node;
return
}
debug_assert!(index.0 > self.spatial_nodes.len() - 1);
self.spatial_nodes.resize(index.0, SpatialNode::empty());
self.spatial_nodes.push(node);
index
}
pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
@ -508,7 +476,6 @@ impl ClipScrollTree {
pt.new_level(format!("ReferenceFrame {:?}", info.resolved_transform));
pt.add_item(format!("index: {:?}", index));
}
SpatialNodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
}
pt.add_item(format!("world_viewport_transform: {:?}", node.world_viewport_transform));

View File

@ -13,7 +13,7 @@ use api::{LineOrientation, LineStyle, LocalClip, NinePatchBorderSource, Pipeline
use api::{PropertyBinding, ReferenceFrame, RepeatMode, ScrollFrameDisplayItem, ScrollSensitivity};
use api::{Shadow, SpecificDisplayItem, StackingContext, StickyFrameDisplayItem, TexelRect};
use api::{TransformStyle, YuvColorSpace, YuvData};
use clip::{ClipRegion, ClipSource, ClipSources, ClipStore};
use clip::{ClipRegion, ClipSource, ClipSources, ClipSourcesIndex, ClipStore};
use clip_scroll_tree::{ClipChainIndex, ClipNodeIndex, ClipScrollTree, SpatialNodeIndex};
use euclid::vec2;
use frame_builder::{ChasePrimitive, FrameBuilder, FrameBuilderConfig};
@ -33,7 +33,7 @@ use resource_cache::{FontInstanceMap, ImageRequest};
use scene::{Scene, ScenePipeline, StackingContextHelpers};
use scene_builder::{BuiltScene, SceneRequest};
use spatial_node::{SpatialNodeType, StickyFrameInfo};
use std::{f32, mem, usize};
use std::{f32, mem};
use tiling::{CompositeOps, ScrollbarPrimitive};
use util::{MaxRect, RectHelpers, recycle_vec};
@ -44,52 +44,20 @@ static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF {
a: 0.6,
};
#[derive(Clone, Copy)]
pub struct PipelineOffset {
pipeline: PipelineId,
spatial_offset: usize,
clip_offset: usize,
}
/// A data structure that keeps track of mapping between API ClipIds and the indices used
/// internally in the ClipScrollTree to avoid having to do HashMap lookups. ClipIdToIndexMapper is
/// responsible for mapping both ClipId to ClipChainIndex and ClipId to SpatialNodeIndex. We
/// also include two small LRU caches. Currently the caches are small (1 entry), but in the future
/// we could use uluru here to do something more involved.
/// responsible for mapping both ClipId to ClipChainIndex and ClipId to SpatialNodeIndex.
#[derive(Default)]
pub struct ClipIdToIndexMapper {
/// A map which converts a ClipId for a clipping node or an API-defined ClipChain into
/// a ClipChainIndex, which is the index used internally in the ClipScrollTree to
/// identify ClipChains.
clip_chain_map: FastHashMap<ClipId, ClipChainIndex>,
/// The last mapped ClipChainIndex, used to avoid having to do lots of consecutive
/// HashMap lookups.
cached_clip_chain_index: Option<(ClipId, ClipChainIndex)>,
/// The offset in the ClipScrollTree's array of SpatialNodes and ClipNodes for a particular
/// pipeline. This is used to convert ClipIds into SpatialNodeIndex or ClipNodeIndex.
pipeline_offsets: FastHashMap<PipelineId, PipelineOffset>,
/// The last mapped pipeline offset for this mapper. This is used to avoid having to
/// consult `pipeline_offsets` repeatedly when flattening the display list.
cached_pipeline_offset: Option<PipelineOffset>,
/// The next available pipeline offset for ClipNodeIndex. When we encounter a pipeline
/// we will use this value and increment it by the total number of clip nodes in the
/// pipeline's display list.
next_available_clip_offset: usize,
/// The next available pipeline offset for SpatialNodeIndex. When we encounter a pipeline
/// we will use this value and increment it by the total number of spatial nodes in the
/// pipeline's display list.
next_available_spatial_offset: usize,
clip_node_map: FastHashMap<ClipId, ClipNodeIndex>,
spatial_node_map: FastHashMap<ClipId, SpatialNodeIndex>,
}
impl ClipIdToIndexMapper {
pub fn add_clip_chain(&mut self, id: ClipId, index: ClipChainIndex) {
debug_assert!(!self.clip_chain_map.contains_key(&id));
self.clip_chain_map.insert(id, index);
let _old_value = self.clip_chain_map.insert(id, index);
debug_assert!(_old_value.is_none());
}
pub fn map_to_parent_clip_chain(&mut self, id: ClipId, parent_id: &ClipId) {
@ -97,53 +65,24 @@ impl ClipIdToIndexMapper {
self.add_clip_chain(id, parent_chain_index);
}
pub fn get_clip_chain_index(&mut self, id: &ClipId) -> ClipChainIndex {
match self.cached_clip_chain_index {
Some((cached_id, cached_clip_chain_index)) if cached_id == *id =>
return cached_clip_chain_index,
_ => {}
}
pub fn map_spatial_node(&mut self, id: ClipId, index: SpatialNodeIndex) {
let _old_value = self.spatial_node_map.insert(id, index);
debug_assert!(_old_value.is_none());
}
pub fn map_clip_node(&mut self, id: ClipId, index: ClipNodeIndex) {
let _old_value = self.clip_node_map.insert(id, index);
debug_assert!(_old_value.is_none());
}
pub fn get_clip_chain_index(&self, id: &ClipId) -> ClipChainIndex {
self.clip_chain_map[id]
}
pub fn get_clip_chain_index_and_cache_result(&mut self, id: &ClipId) -> ClipChainIndex {
let index = self.get_clip_chain_index(id);
self.cached_clip_chain_index = Some((*id, index));
index
}
pub fn initialize_for_pipeline(&mut self, pipeline: &ScenePipeline) {
debug_assert!(!self.pipeline_offsets.contains_key(&pipeline.pipeline_id));
self.pipeline_offsets.insert(
pipeline.pipeline_id,
PipelineOffset {
pipeline: pipeline.pipeline_id,
spatial_offset: self.next_available_spatial_offset,
clip_offset: self.next_available_clip_offset,
}
);
self.next_available_clip_offset += pipeline.display_list.total_clip_nodes();
self.next_available_spatial_offset += pipeline.display_list.total_spatial_nodes();
}
pub fn get_pipeline_offet<'a>(&'a mut self, id: PipelineId) -> &'a PipelineOffset {
match self.cached_pipeline_offset {
Some(ref offset) if offset.pipeline == id => offset,
_ => {
let offset = &self.pipeline_offsets[&id];
self.cached_pipeline_offset = Some(*offset);
offset
}
}
}
pub fn get_clip_node_index(&mut self, id: ClipId) -> ClipNodeIndex {
pub fn get_clip_node_index(&self, id: ClipId) -> ClipNodeIndex {
match id {
ClipId::Clip(index, pipeline_id) => {
let pipeline_offset = self.get_pipeline_offet(pipeline_id);
ClipNodeIndex(pipeline_offset.clip_offset + index)
ClipId::Clip(..) => {
self.clip_node_map[&id]
}
ClipId::Spatial(..) => {
// We could theoretically map back to the containing clip node with the current
@ -154,6 +93,16 @@ impl ClipIdToIndexMapper {
ClipId::ClipChain(_) => panic!("Tried to use ClipChain as scroll node."),
}
}
pub fn get_spatial_node_index(&self, id: ClipId) -> SpatialNodeIndex {
match id {
ClipId::Clip(..) |
ClipId::Spatial(..) => {
self.spatial_node_map[&id]
}
ClipId::ClipChain(_) => panic!("Tried to use ClipChain as scroll node."),
}
}
}
/// A structure that converts a serialized display list into a form that WebRender
@ -248,7 +197,6 @@ impl<'a> DisplayListFlattener<'a> {
clip_store: old_builder.clip_store.recycle(),
};
flattener.id_to_index_mapper.initialize_for_pipeline(root_pipeline);
flattener.push_root(
root_pipeline_id,
&root_pipeline.viewport_size,
@ -401,13 +349,12 @@ impl<'a> DisplayListFlattener<'a> {
info.previously_applied_offset,
);
let index = self.get_spatial_node_index_for_clip_id(info.id);
self.clip_scroll_tree.add_sticky_frame(
index,
let index = self.clip_scroll_tree.add_sticky_frame(
clip_and_scroll.spatial_node_index, /* parent id */
sticky_frame_info,
info.id.pipeline_id(),
);
self.id_to_index_mapper.map_spatial_node(info.id, index);
self.id_to_index_mapper.map_to_parent_clip_chain(info.id, parent_id);
}
@ -532,8 +479,6 @@ impl<'a> DisplayListFlattener<'a> {
},
};
self.id_to_index_mapper.initialize_for_pipeline(pipeline);
//TODO: use or assert on `clip_and_scroll_ids.clip_node_id` ?
let clip_chain_index = self.add_clip_node(
info.clip_id,
@ -791,23 +736,29 @@ impl<'a> DisplayListFlattener<'a> {
None
}
fn add_clip_sources(
&mut self,
clip_sources: Vec<ClipSource>,
spatial_node_index: SpatialNodeIndex,
) -> Option<ClipSourcesIndex> {
if clip_sources.is_empty() {
None
} else {
Some(self.clip_store.insert(ClipSources::new(clip_sources, spatial_node_index)))
}
}
/// 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(
&mut self,
info: &LayoutPrimitiveInfo,
clip_sources: Vec<ClipSource>,
clip_sources: Option<ClipSourcesIndex>,
container: PrimitiveContainer,
) -> PrimitiveIndex {
let stacking_context = self.sc_stack.last().expect("bug: no stacking context!");
let clip_sources = if clip_sources.is_empty() {
None
} else {
Some(self.clip_store.insert(ClipSources::new(clip_sources)))
};
self.prim_store.add_primitive(
&info.rect,
&info.clip_rect,
@ -877,6 +828,10 @@ impl<'a> DisplayListFlattener<'a> {
.iter()
.map(|cs| cs.offset(&shadow.offset))
.collect();
let clip_sources = self.add_clip_sources(
clip_sources,
clip_and_scroll.spatial_node_index,
);
// Construct and add a primitive for the given shadow.
let shadow_prim_index = self.create_primitive(
@ -893,6 +848,10 @@ impl<'a> DisplayListFlattener<'a> {
}
if container.is_visible() {
let clip_sources = self.add_clip_sources(
clip_sources,
clip_and_scroll.spatial_node_index,
);
let prim_index = self.create_primitive(info, clip_sources, container);
if cfg!(debug_assertions) && ChasePrimitive::LocalRect(info.rect) == self.config.chase_primitive {
println!("Chasing {:?}", prim_index);
@ -919,7 +878,7 @@ impl<'a> DisplayListFlattener<'a> {
None => ClipChainIndex::NO_CLIP,
};
let clip_and_scroll = ScrollNodeAndClipChain::new(
self.get_spatial_node_index_for_clip_id(spatial_node),
self.id_to_index_mapper.get_spatial_node_index(spatial_node),
clip_chain_id
);
@ -1219,10 +1178,8 @@ impl<'a> DisplayListFlattener<'a> {
source_perspective: Option<LayoutTransform>,
origin_in_parent_reference_frame: LayoutVector2D,
) -> SpatialNodeIndex {
let index = self.get_spatial_node_index_for_clip_id(reference_frame_id);
let parent_index = parent_id.map(|id| self.get_spatial_node_index_for_clip_id(id));
self.clip_scroll_tree.add_reference_frame(
index,
let parent_index = parent_id.map(|id| self.id_to_index_mapper.get_spatial_node_index(id));
let index = self.clip_scroll_tree.add_reference_frame(
parent_index,
source_transform,
source_perspective,
@ -1230,6 +1187,7 @@ impl<'a> DisplayListFlattener<'a> {
pipeline_id,
);
self.reference_frame_stack.push((reference_frame_id, index));
self.id_to_index_mapper.map_spatial_node(reference_frame_id, index);
match parent_id {
Some(ref parent_id) =>
@ -1289,19 +1247,18 @@ impl<'a> DisplayListFlattener<'a> {
parent_id: ClipId,
clip_region: ClipRegion,
) -> ClipChainIndex {
let clip_sources = ClipSources::from(clip_region);
let parent_clip_chain_index = self.id_to_index_mapper.get_clip_chain_index(&parent_id);
let spatial_node = self.id_to_index_mapper.get_spatial_node_index(parent_id);
let clip_sources = ClipSources::from_region(clip_region, spatial_node);
let handle = self.clip_store.insert(clip_sources);
let node_index = self.id_to_index_mapper.get_clip_node_index(new_node_id);
let parent_clip_chain_index =
self.id_to_index_mapper.get_clip_chain_index_and_cache_result(&parent_id);
let spatial_node = self.get_spatial_node_index_for_clip_id(parent_id);
let clip_chain_index = self.clip_scroll_tree.add_clip_node(
node_index,
let (node_index, clip_chain_index) = self.clip_scroll_tree.add_clip_node(
parent_clip_chain_index,
spatial_node,
handle,
);
self.id_to_index_mapper.map_spatial_node(new_node_id, spatial_node);
self.id_to_index_mapper.map_clip_node(new_node_id, node_index);
self.id_to_index_mapper.add_clip_chain(new_node_id, clip_chain_index);
clip_chain_index
}
@ -1316,10 +1273,8 @@ impl<'a> DisplayListFlattener<'a> {
content_size: &LayoutSize,
scroll_sensitivity: ScrollSensitivity,
) -> SpatialNodeIndex {
let node_index = self.get_spatial_node_index_for_clip_id(new_node_id);
let parent_node_index = self.get_spatial_node_index_for_clip_id(parent_id);
self.clip_scroll_tree.add_scroll_frame(
node_index,
let parent_node_index = self.id_to_index_mapper.get_spatial_node_index(parent_id);
let node_index = self.clip_scroll_tree.add_scroll_frame(
parent_node_index,
external_id,
pipeline_id,
@ -1327,6 +1282,7 @@ impl<'a> DisplayListFlattener<'a> {
content_size,
scroll_sensitivity,
);
self.id_to_index_mapper.map_spatial_node(new_node_id, node_index);
self.id_to_index_mapper.map_to_parent_clip_chain(new_node_id, &parent_id);
node_index
}
@ -1455,7 +1411,7 @@ impl<'a> DisplayListFlattener<'a> {
let prim_index = self.create_primitive(
info,
Vec::new(),
None,
PrimitiveContainer::Brush(prim),
);
@ -1967,28 +1923,14 @@ impl<'a> DisplayListFlattener<'a> {
pub fn map_clip_and_scroll(&mut self, info: &ClipAndScrollInfo) -> ScrollNodeAndClipChain {
ScrollNodeAndClipChain::new(
self.get_spatial_node_index_for_clip_id(info.scroll_node_id),
self.id_to_index_mapper.get_clip_chain_index_and_cache_result(&info.clip_node_id())
self.id_to_index_mapper.get_spatial_node_index(info.scroll_node_id),
self.id_to_index_mapper.get_clip_chain_index(&info.clip_node_id())
)
}
pub fn simple_scroll_and_clip_chain(&mut self, id: &ClipId) -> ScrollNodeAndClipChain {
self.map_clip_and_scroll(&ClipAndScrollInfo::simple(*id))
}
pub fn get_spatial_node_index_for_clip_id(&mut self, id: ClipId,) -> SpatialNodeIndex {
match id {
ClipId::Spatial(index, pipeline_id) => {
let pipeline_offset = self.id_to_index_mapper.get_pipeline_offet(pipeline_id);
SpatialNodeIndex(pipeline_offset.spatial_offset + index)
}
ClipId::Clip(..) => {
let clip_node_index = self.id_to_index_mapper.get_clip_node_index(id);
self.clip_scroll_tree.clip_nodes[clip_node_index.0].spatial_node
}
ClipId::ClipChain(_) => panic!("Tried to use ClipChain as scroll node."),
}
}
}
pub fn build_scene(config: &FrameBuilderConfig, request: SceneRequest) -> BuiltScene {

View File

@ -3,7 +3,6 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::marker::PhantomData;
use util::recycle_vec;
// TODO(gw): Add an occupied list head, for fast
// iteration of the occupied list to implement
@ -86,15 +85,6 @@ impl<T, M> FreeList<T, M> {
}
}
pub fn recycle(self) -> FreeList<T, M> {
FreeList {
slots: recycle_vec(self.slots),
free_list_head: None,
active_count: 0,
_marker: PhantomData,
}
}
pub fn clear(&mut self) {
self.slots.clear();
self.free_list_head = None;

View File

@ -195,6 +195,7 @@ impl PrimitiveHeaders {
// This is a convenience type used to make it easier to pass
// the common parts around during batching.
#[derive(Debug)]
pub struct PrimitiveHeader {
pub local_rect: LayoutRect,
pub local_clip_rect: LayoutRect,
@ -349,12 +350,15 @@ impl From<BrushInstance> for PrimitiveInstance {
pub struct TransformPaletteId(pub u32);
impl TransformPaletteId {
// Get the palette ID for an identity transform.
pub fn identity() -> TransformPaletteId {
TransformPaletteId(0)
/// Identity transform ID.
pub const IDENTITY: Self = TransformPaletteId(0);
/// Extract the spatial node index from the id.
pub fn _spatial_node_index(&self) -> SpatialNodeIndex {
SpatialNodeIndex(self.0 as usize & 0xFFFFFF)
}
// Extract the transform kind from the id.
/// Extract the transform kind from the id.
pub fn transform_kind(&self) -> TransformedRectKind {
if (self.0 >> 24) == 0 {
TransformedRectKind::AxisAligned

View File

@ -34,6 +34,29 @@ pub struct HitTestClipNode {
regions: Vec<HitTestRegion>,
}
impl HitTestClipNode {
fn new(node: &ClipNode, clip_store: &ClipStore) -> Self {
let clips = clip_store.get(node.clip_sources_index);
let regions = clips.clips().iter().map(|source| {
match source.0 {
ClipSource::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode),
ClipSource::RoundedRectangle(ref rect, ref radii, ref mode) =>
HitTestRegion::RoundedRectangle(*rect, *radii, *mode),
ClipSource::Image(ref mask) => HitTestRegion::Rectangle(mask.rect, ClipMode::Clip),
ClipSource::LineDecoration(_) |
ClipSource::BoxShadow(_) => {
unreachable!("Didn't expect to hit test against BorderCorner / BoxShadow / LineDecoration");
}
}
}).collect();
HitTestClipNode {
spatial_node: clips.spatial_node_index,
regions,
}
}
}
/// A description of a clip chain in the HitTester. This is used to describe
/// hierarchical clip scroll nodes as well as ClipChains, so that they can be
/// handled the same way during hit testing. Once we represent all ClipChains
@ -148,15 +171,11 @@ impl HitTester {
}
for (index, node) in clip_scroll_tree.clip_nodes.iter().enumerate() {
self.clip_nodes.push(HitTestClipNode {
spatial_node: node.spatial_node,
regions: get_regions_for_clip_node(node, clip_store),
});
let clip_chain = self.clip_chains.get_mut(node.clip_chain_index.0).unwrap();
clip_chain.parent =
clip_scroll_tree.get_clip_chain(node.clip_chain_index).parent_index;
clip_chain.clips = vec![ClipNodeIndex(index)];
self.clip_nodes.push(HitTestClipNode::new(node, clip_store));
let clip_chain = self.clip_chains.get_mut(node.clip_chain_index.0).unwrap();
clip_chain.parent =
clip_scroll_tree.get_clip_chain(node.clip_chain_index).parent_index;
clip_chain.clips = vec![ClipNodeIndex(index)];
}
for descriptor in &clip_scroll_tree.clip_chains_descriptors {
@ -346,33 +365,6 @@ impl HitTester {
}
}
fn get_regions_for_clip_node(
node: &ClipNode,
clip_store: &ClipStore
) -> Vec<HitTestRegion> {
let handle = match node.handle.as_ref() {
Some(handle) => handle,
None => {
warn!("Encountered an empty clip node unexpectedly.");
return Vec::new()
}
};
let clips = clip_store.get(handle).clips();
clips.iter().map(|source| {
match source.0 {
ClipSource::Rectangle(ref rect, mode) => HitTestRegion::Rectangle(*rect, mode),
ClipSource::RoundedRectangle(ref rect, ref radii, ref mode) =>
HitTestRegion::RoundedRectangle(*rect, *radii, *mode),
ClipSource::Image(ref mask) => HitTestRegion::Rectangle(mask.rect, ClipMode::Clip),
ClipSource::LineDecoration(_) |
ClipSource::BoxShadow(_) => {
unreachable!("Didn't expect to hit test against BorderCorner / BoxShadow / LineDecoration");
}
}
}).collect()
}
#[derive(Clone, Copy, PartialEq)]
enum ClippedIn {
ClippedIn,

View File

@ -13,7 +13,7 @@ use border::{BorderCacheKey, BorderRenderTaskInfo};
use box_shadow::BLUR_SAMPLE_SCALE;
use clip_scroll_tree::{ClipChainIndex, CoordinateSystemId, SpatialNodeIndex};
use clip::{ClipChain, ClipChainNode, ClipChainNodeIter, ClipChainNodeRef, ClipSource};
use clip::{ClipSourcesHandle, ClipWorkItem};
use clip::{ClipSourcesIndex, ClipWorkItem};
use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureContext, PictureState};
use frame_builder::PrimitiveRunContext;
use glyph_rasterizer::{FontInstance, FontTransform, GlyphKey, FONT_SIZE_LIMIT};
@ -188,7 +188,7 @@ pub struct ScreenRect {
#[derive(Debug)]
pub struct PrimitiveMetadata {
pub opacity: PrimitiveOpacity,
pub clip_sources: Option<ClipSourcesHandle>,
pub clip_sources_index: Option<ClipSourcesIndex>,
pub prim_kind: PrimitiveKind,
pub cpu_prim_index: SpecificPrimitiveIndex,
pub gpu_location: GpuCacheHandle,
@ -1281,14 +1281,14 @@ impl PrimitiveStore {
local_rect: &LayoutRect,
local_clip_rect: &LayoutRect,
is_backface_visible: bool,
clip_sources: Option<ClipSourcesHandle>,
clip_sources_index: Option<ClipSourcesIndex>,
tag: Option<ItemTag>,
container: PrimitiveContainer,
) -> PrimitiveIndex {
let prim_index = self.cpu_metadata.len();
let base_metadata = PrimitiveMetadata {
clip_sources,
clip_sources_index,
gpu_location: GpuCacheHandle::new(),
clip_task_id: None,
local_rect: *local_rect,
@ -1983,6 +1983,9 @@ impl PrimitiveStore {
match brush.segment_desc {
Some(ref segment_desc) => {
for segment in &segment_desc.segments {
if cfg!(debug_assertions) && self.chase_id == Some(prim_index) {
println!("\t\t{:?}", segment);
}
// has to match VECS_PER_SEGMENT
request.write_segment(
segment.local_rect,
@ -2059,7 +2062,7 @@ impl PrimitiveStore {
continue;
}
let local_clips = frame_state.clip_store.get_opt(&clip_item.clip_sources).expect("bug");
let local_clips = frame_state.clip_store.get(clip_item.clip_sources_index);
rect_clips_only = rect_clips_only && local_clips.only_rectangular_clips;
// TODO(gw): We can easily extend the segment builder to support these clip sources in
@ -2074,7 +2077,7 @@ impl PrimitiveStore {
// of doing that, only segment with clips that have the same positioning node.
// TODO(mrobinson, #2858): It may make sense to include these nodes, resegmenting only
// when necessary while scrolling.
if clip_item.spatial_node_index != prim_run_context.spatial_node_index {
if local_clips.spatial_node_index != prim_run_context.spatial_node_index {
// We don't need to generate a global clip mask for rectangle clips because we are
// in the same coordinate system and rectangular clips are handled by the local
// clip chain rectangle.
@ -2285,8 +2288,8 @@ impl PrimitiveStore {
let transform = &prim_run_context.scroll_node.world_content_transform;
let extra_clip = {
let metadata = &self.cpu_metadata[prim_index.0];
metadata.clip_sources.as_ref().map(|clip_sources| {
let prim_clips = frame_state.clip_store.get_mut(clip_sources);
metadata.clip_sources_index.map(|clip_sources_index| {
let prim_clips = frame_state.clip_store.get_mut(clip_sources_index);
prim_clips.update(
frame_state.gpu_cache,
frame_state.resource_cache,
@ -2307,8 +2310,7 @@ impl PrimitiveStore {
Arc::new(ClipChainNode {
work_item: ClipWorkItem {
spatial_node_index: prim_run_context.spatial_node_index,
clip_sources: clip_sources.weak(),
clip_sources_index,
coordinate_system_id: prim_coordinate_system_id,
},
// The local_clip_rect a property of ClipChain nodes that are ClipNodes.
@ -2643,10 +2645,6 @@ impl PrimitiveStore {
};
for run in &pic_context.prim_runs {
if run.is_chasing(self.chase_id) {
println!("\tpreparing a run of length {} in pipeline {:?}",
run.count, pic_context.pipeline_id);
}
// TODO(gw): Perhaps we can restructure this to not need to create
// a new primitive context for every run (if the hash
// lookups ever show up in a profile).
@ -2656,6 +2654,13 @@ impl PrimitiveStore {
let clip_chain = &frame_context
.clip_chains[run.clip_and_scroll.clip_chain_index.0];
if run.is_chasing(self.chase_id) {
println!("\tpreparing a run of length {} in pipeline {:?}",
run.count, pic_context.pipeline_id);
println!("\trun {:?}", run.clip_and_scroll);
println!("\ttransform {:?}", scroll_node.world_content_transform.to_transform());
}
// Mark whether this picture contains any complex coordinate
// systems, due to either the scroll node or the clip-chain.
pic_state.has_non_root_coord_system |=
@ -2716,7 +2721,12 @@ impl PrimitiveStore {
};
let local_clip_chain_rect = match clip_chain_rect {
Some(rect) if rect.is_empty() => continue,
Some(rect) if rect.is_empty() => {
if run.is_chasing(self.chase_id) {
println!("\tculled by empty chain rect");
}
continue
},
Some(rect) => rect,
None => frame_context.max_local_clip,
};
@ -2749,7 +2759,12 @@ impl PrimitiveStore {
let clipped_rect = match clip_chain_rect {
Some(ref chain_rect) => match prim_local_rect.intersection(chain_rect) {
Some(rect) => rect,
None => continue,
None => {
if cfg!(debug_assertions) && self.chase_id == Some(prim_index) {
println!("\tculled by chain rect {:?}", chain_rect);
}
continue
},
},
None => prim_local_rect,
};

View File

@ -169,6 +169,97 @@ impl Document {
!self.view.window_size.is_empty_or_negative()
}
fn process_frame_msg(
&mut self,
message: FrameMsg,
) -> DocumentOps {
match message {
FrameMsg::UpdateEpoch(pipeline_id, epoch) => {
self.current.scene.update_epoch(pipeline_id, epoch);
DocumentOps::nop()
}
FrameMsg::EnableFrameOutput(pipeline_id, enable) => {
if enable {
self.output_pipelines.insert(pipeline_id);
} else {
self.output_pipelines.remove(&pipeline_id);
}
DocumentOps::nop()
}
FrameMsg::Scroll(delta, cursor) => {
profile_scope!("Scroll");
let mut should_render = true;
let node_index = match self.hit_tester {
Some(ref hit_tester) => {
// Ideally we would call self.scroll_nearest_scrolling_ancestor here, but
// we need have to avoid a double-borrow.
let test = HitTest::new(None, cursor, HitTestFlags::empty());
hit_tester.find_node_under_point(test)
}
None => {
should_render = false;
None
}
};
let should_render =
should_render &&
self.scroll_nearest_scrolling_ancestor(delta, node_index) &&
self.render_on_scroll == Some(true);
DocumentOps {
scroll: true,
render: should_render,
composite: should_render,
..DocumentOps::nop()
}
}
FrameMsg::HitTest(pipeline_id, point, flags, tx) => {
let result = match self.hit_tester {
Some(ref hit_tester) => {
hit_tester.hit_test(HitTest::new(pipeline_id, point, flags))
}
None => HitTestResult { items: Vec::new() },
};
tx.send(result).unwrap();
DocumentOps::nop()
}
FrameMsg::SetPan(pan) => {
self.view.pan = pan;
DocumentOps::nop()
}
FrameMsg::ScrollNodeWithId(origin, id, clamp) => {
profile_scope!("ScrollNodeWithScrollId");
let should_render = self.scroll_node(origin, id, clamp)
&& self.render_on_scroll == Some(true);
DocumentOps {
scroll: true,
render: should_render,
composite: should_render,
..DocumentOps::nop()
}
}
FrameMsg::GetScrollNodeState(tx) => {
profile_scope!("GetScrollNodeState");
tx.send(self.get_scroll_node_state()).unwrap();
DocumentOps::nop()
}
FrameMsg::UpdateDynamicProperties(property_bindings) => {
self.dynamic_properties.set_properties(property_bindings);
DocumentOps::nop()
}
FrameMsg::AppendDynamicProperties(property_bindings) => {
self.dynamic_properties.add_properties(property_bindings);
DocumentOps::nop()
}
}
}
// TODO: We will probably get rid of this soon and always forward to the scene building thread.
fn build_scene(&mut self, resource_cache: &mut ResourceCache, scene_id: u64) {
let max_texture_size = resource_cache.max_texture_size();
@ -601,100 +692,6 @@ impl RenderBackend {
}
}
fn process_frame_msg(
&mut self,
document_id: DocumentId,
message: FrameMsg,
) -> DocumentOps {
let doc = self.documents.get_mut(&document_id).expect("No document?");
match message {
FrameMsg::UpdateEpoch(pipeline_id, epoch) => {
doc.current.scene.update_epoch(pipeline_id, epoch);
DocumentOps::nop()
}
FrameMsg::EnableFrameOutput(pipeline_id, enable) => {
if enable {
doc.output_pipelines.insert(pipeline_id);
} else {
doc.output_pipelines.remove(&pipeline_id);
}
DocumentOps::nop()
}
FrameMsg::Scroll(delta, cursor) => {
profile_scope!("Scroll");
let mut should_render = true;
let node_index = match doc.hit_tester {
Some(ref hit_tester) => {
// Ideally we would call doc.scroll_nearest_scrolling_ancestor here, but
// we need have to avoid a double-borrow.
let test = HitTest::new(None, cursor, HitTestFlags::empty());
hit_tester.find_node_under_point(test)
}
None => {
should_render = false;
None
}
};
let should_render =
should_render &&
doc.scroll_nearest_scrolling_ancestor(delta, node_index) &&
doc.render_on_scroll == Some(true);
DocumentOps {
scroll: true,
render: should_render,
composite: should_render,
..DocumentOps::nop()
}
}
FrameMsg::HitTest(pipeline_id, point, flags, tx) => {
let result = match doc.hit_tester {
Some(ref hit_tester) => {
hit_tester.hit_test(HitTest::new(pipeline_id, point, flags))
}
None => HitTestResult { items: Vec::new() },
};
tx.send(result).unwrap();
DocumentOps::nop()
}
FrameMsg::SetPan(pan) => {
doc.view.pan = pan;
DocumentOps::nop()
}
FrameMsg::ScrollNodeWithId(origin, id, clamp) => {
profile_scope!("ScrollNodeWithScrollId");
let should_render = doc.scroll_node(origin, id, clamp)
&& doc.render_on_scroll == Some(true);
DocumentOps {
scroll: true,
render: should_render,
composite: should_render,
..DocumentOps::nop()
}
}
FrameMsg::GetScrollNodeState(tx) => {
profile_scope!("GetScrollNodeState");
tx.send(doc.get_scroll_node_state()).unwrap();
DocumentOps::nop()
}
FrameMsg::UpdateDynamicProperties(property_bindings) => {
doc.dynamic_properties.set_properties(property_bindings);
DocumentOps::render()
}
FrameMsg::AppendDynamicProperties(property_bindings) => {
doc.dynamic_properties.add_properties(property_bindings);
DocumentOps::render()
}
}
}
fn next_namespace_id(&self) -> IdNamespace {
IdNamespace(NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed) as u32)
}
@ -1070,12 +1067,16 @@ impl RenderBackend {
}
}
let doc = self.documents.get_mut(&document_id).unwrap();
for frame_msg in transaction_msg.frame_ops {
let _timer = profile_counters.total_time.timer();
op.combine(self.process_frame_msg(document_id, frame_msg));
op.combine(doc.process_frame_msg(frame_msg));
}
let doc = self.documents.get_mut(&document_id).unwrap();
if doc.dynamic_properties.flush_pending_updates() {
op.render = true;
}
if transaction_msg.generate_frame {
if let Some(ref mut ros) = doc.render_on_scroll {

View File

@ -403,7 +403,7 @@ impl RenderTask {
// whether a ClipSources contains any box-shadows and skip
// this iteration for the majority of cases.
for clip_item in &clips {
let clip_sources = clip_store.get_opt_mut(&clip_item.clip_sources).expect("bug");
let clip_sources = clip_store.get_mut(clip_item.clip_sources_index);
for &mut (ref mut clip, _) in &mut clip_sources.clips {
match *clip {
ClipSource::BoxShadow(ref mut info) => {

View File

@ -1235,26 +1235,10 @@ impl ResourceCache {
}
#[inline]
pub fn get_cached_image(
&self,
request: ImageRequest,
) -> Result<CacheItem, ()> {
pub fn get_cached_image(&self, request: ImageRequest) -> Result<CacheItem, ()> {
debug_assert_eq!(self.state, State::QueryResources);
// TODO(Jerry): add a debug option to visualize the corresponding area for
// the Err() case of CacheItem.
match *self.cached_images.get(&request.key) {
ImageResult::UntiledAuto(ref image_info) => {
Ok(self.texture_cache.get(&image_info.texture_cache_handle))
}
ImageResult::Multi(ref entries) => {
let image_info = entries.get(&request.into());
Ok(self.texture_cache.get(&image_info.texture_cache_handle))
}
ImageResult::Err(_) => {
Err(())
}
}
let image_info = self.get_image_info(request)?;
Ok(self.get_texture_cache_item(&image_info.texture_cache_handle))
}
pub fn get_cached_render_task(
@ -1264,6 +1248,18 @@ impl ResourceCache {
self.cached_render_tasks.get_cache_entry(handle)
}
#[inline]
fn get_image_info(&self, request: ImageRequest) -> Result<&CachedImageInfo, ()> {
// TODO(Jerry): add a debug option to visualize the corresponding area for
// the Err() case of CacheItem.
match *self.cached_images.get(&request.key) {
ImageResult::UntiledAuto(ref image_info) => Ok(image_info),
ImageResult::Multi(ref entries) => Ok(entries.get(&request.into())),
ImageResult::Err(_) => Err(()),
}
}
#[inline]
pub fn get_texture_cache_item(&self, handle: &TextureCacheHandle) -> CacheItem {
self.texture_cache.get(handle)
}

View File

@ -13,10 +13,11 @@ use std::sync::Arc;
/// re-submitting the display list itself.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone)]
pub struct SceneProperties {
transform_properties: FastHashMap<PropertyBindingId, LayoutTransform>,
float_properties: FastHashMap<PropertyBindingId, f32>,
current_properties: DynamicProperties,
pending_properties: Option<DynamicProperties>,
}
impl SceneProperties {
@ -24,27 +25,60 @@ impl SceneProperties {
SceneProperties {
transform_properties: FastHashMap::default(),
float_properties: FastHashMap::default(),
current_properties: DynamicProperties::default(),
pending_properties: None,
}
}
/// Set the current property list for this display list.
pub fn set_properties(&mut self, properties: DynamicProperties) {
self.transform_properties.clear();
self.float_properties.clear();
self.add_properties(properties);
self.pending_properties = Some(properties);
}
/// Add to the current property list for this display list.
pub fn add_properties(&mut self, properties: DynamicProperties) {
for property in properties.transforms {
self.transform_properties
.insert(property.key.id, property.value);
let mut pending_properties = self.pending_properties
.take()
.unwrap_or_default();
pending_properties.transforms.extend(properties.transforms);
pending_properties.floats.extend(properties.floats);
self.pending_properties = Some(pending_properties);
}
/// Flush any pending updates to the scene properties. Returns
/// true if the properties have changed since the last flush
/// was called. This code allows properties to be changed by
/// multiple set_properties and add_properties calls during a
/// single transaction, and still correctly determine if any
/// properties have changed. This can have significant power
/// saving implications, allowing a frame build to be skipped
/// if the properties haven't changed in many cases.
pub fn flush_pending_updates(&mut self) -> bool {
let mut properties_changed = false;
if let Some(pending_properties) = self.pending_properties.take() {
if pending_properties != self.current_properties {
self.transform_properties.clear();
self.float_properties.clear();
for property in &pending_properties.transforms {
self.transform_properties
.insert(property.key.id, property.value);
}
for property in &pending_properties.floats {
self.float_properties
.insert(property.key.id, property.value);
}
self.current_properties = pending_properties;
properties_changed = true;
}
}
for property in properties.floats {
self.float_properties
.insert(property.key.id, property.value);
}
properties_changed
}
/// Get the current value for a transform property.

View File

@ -26,11 +26,6 @@ pub enum SpatialNodeType {
/// A reference frame establishes a new coordinate space in the tree.
ReferenceFrame(ReferenceFrameInfo),
/// An empty node, used to pad the ClipScrollTree's array of nodes so that
/// we can immediately use each assigned SpatialNodeIndex. After display
/// list flattening this node type should never be used.
Empty,
}
/// Contains information common among all types of ClipScrollTree nodes.
@ -94,10 +89,6 @@ impl SpatialNode {
}
}
pub fn empty() -> SpatialNode {
Self::new(PipelineId::dummy(), None, SpatialNodeType::Empty)
}
pub fn new_scroll_frame(
pipeline_id: PipelineId,
parent_index: SpatialNodeIndex,
@ -494,7 +485,6 @@ impl SpatialNode {
state.nearest_scrolling_ancestor_viewport
.translate(&translation);
}
SpatialNodeType::Empty => unreachable!("Empty node remaining in ClipScrollTree."),
}
}

View File

@ -1090,7 +1090,7 @@ impl<T> From<T> for PropertyBinding<T> {
/// The current value of an animated property. This is
/// supplied by the calling code.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq)]
pub struct PropertyValue<T> {
pub key: PropertyBindingKey<T>,
pub value: T,
@ -1099,7 +1099,7 @@ pub struct PropertyValue<T> {
/// When using `generate_frame()`, a list of `PropertyValue` structures
/// can optionally be supplied to provide the current value of any
/// animated properties.
#[derive(Clone, Deserialize, Serialize, Debug)]
#[derive(Clone, Deserialize, Serialize, Debug, PartialEq, Default)]
pub struct DynamicProperties {
pub transforms: Vec<PropertyValue<LayoutTransform>>,
pub floats: Vec<PropertyValue<f32>>,

View File

@ -1 +1 @@
e850fbd2e0e60a8de76c2d2464f0fa27316d5949
8a4fe66528aa362721e4048aac3cd5abf7faaf2c

View File

@ -182,23 +182,18 @@ impl WindowWrapper {
}
fn get_inner_size(&self) -> DeviceUintSize {
//HACK: `winit` needs to figure out its hidpi story...
#[cfg(target_os = "macos")]
fn inner_size(window: &winit::Window) -> LogicalSize {
let LogicalSize { width, height } = window.get_inner_size().unwrap();
let factor = window.get_hidpi_factor();
LogicalSize::new(width * factor, height * factor)
fn inner_size(window: &winit::Window) -> DeviceUintSize {
let size = window
.get_inner_size()
.unwrap()
.to_physical(window.get_hidpi_factor());
DeviceUintSize::new(size.width as u32, size.height as u32)
}
#[cfg(not(target_os = "macos"))]
fn inner_size(window: &winit::Window) -> LogicalSize {
window.get_inner_size().unwrap()
}
let LogicalSize { width, height } = match *self {
match *self {
WindowWrapper::Window(ref window, _) => inner_size(window.window()),
WindowWrapper::Angle(ref window, ..) => inner_size(window),
WindowWrapper::Headless(ref context, _) => LogicalSize::new(context.width as f64, context.height as f64),
};
DeviceUintSize::new(width as u32, height as u32)
WindowWrapper::Headless(ref context, _) => DeviceUintSize::new(context.width, context.height),
}
}
fn hidpi_factor(&self) -> f32 {