зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1500466 - Update webrender to commit 15656cb497303703b4d541d3e14292259e4c5343. r=kats
Differential Revision: https://phabricator.services.mozilla.com/D9348 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
e96ba0d946
Коммит
ec100e51b3
|
@ -507,7 +507,7 @@ impl AlphaBatchBuilder {
|
|||
for poly in splitter.sort(vec3(0.0, 0.0, 1.0)) {
|
||||
let prim_instance = &pic.prim_instances[poly.anchor];
|
||||
let prim_index = prim_instance.prim_index;
|
||||
let pic_metadata = &ctx.prim_store.primitives[prim_index.0].metadata;
|
||||
let prim = &ctx.prim_store.primitives[prim_index.0];
|
||||
if cfg!(debug_assertions) && ctx.prim_store.chase_id == Some(prim_index) {
|
||||
println!("\t\tsplit polygon {:?}", poly.points);
|
||||
}
|
||||
|
@ -523,7 +523,7 @@ impl AlphaBatchBuilder {
|
|||
.map_or(OPAQUE_TASK_ADDRESS, |id| render_tasks.get_task_address(id));
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: pic_metadata.local_rect,
|
||||
local_rect: prim.local_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: GpuCacheAddress::invalid(),
|
||||
|
@ -531,7 +531,18 @@ impl AlphaBatchBuilder {
|
|||
transform_id,
|
||||
};
|
||||
|
||||
let pic = ctx.prim_store.get_pic(prim_index);
|
||||
let pic_index = match prim.details {
|
||||
PrimitiveDetails::Brush(ref brush) => {
|
||||
match brush.kind {
|
||||
BrushKind::Picture { pic_index, .. } => pic_index,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
PrimitiveDetails::TextRun(..) => {
|
||||
unreachable!();
|
||||
}
|
||||
};
|
||||
let pic = &ctx.prim_store.pictures[pic_index.0];
|
||||
|
||||
let (uv_rect_address, _) = pic
|
||||
.raster_config
|
||||
|
@ -607,7 +618,6 @@ impl AlphaBatchBuilder {
|
|||
plane_split_anchor: usize,
|
||||
) {
|
||||
let prim = &ctx.prim_store.primitives[prim_instance.prim_index.0];
|
||||
let prim_metadata = &prim.metadata;
|
||||
|
||||
if prim_instance.clipped_world_rect.is_none() {
|
||||
return;
|
||||
|
@ -632,8 +642,7 @@ impl AlphaBatchBuilder {
|
|||
.expect("bug");
|
||||
|
||||
// If the primitive is internally decomposed into multiple sub-primitives we may not
|
||||
// use some of the per-primitive data typically stored in PrimitiveMetadata and get
|
||||
// it from each sub-primitive instead.
|
||||
// use some of the per-primitive data and get it from each sub-primitive instead.
|
||||
let is_multiple_primitives = match prim.details {
|
||||
PrimitiveDetails::Brush(ref brush) => {
|
||||
match brush.kind {
|
||||
|
@ -667,7 +676,7 @@ impl AlphaBatchBuilder {
|
|||
};
|
||||
|
||||
let prim_header = PrimitiveHeader {
|
||||
local_rect: prim_metadata.local_rect,
|
||||
local_rect: prim.local_rect,
|
||||
local_clip_rect: prim_instance.combined_local_clip_rect,
|
||||
task_address,
|
||||
specific_prim_address: prim_cache_address,
|
||||
|
@ -683,7 +692,9 @@ impl AlphaBatchBuilder {
|
|||
match prim.details {
|
||||
PrimitiveDetails::Brush(ref brush) => {
|
||||
match brush.kind {
|
||||
BrushKind::Picture(ref picture) => {
|
||||
BrushKind::Picture { pic_index, .. } => {
|
||||
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
|
||||
// for it and add it to the current plane splitter.
|
||||
|
@ -698,8 +709,9 @@ impl AlphaBatchBuilder {
|
|||
// rather that rectangles. The interpolation still works correctly
|
||||
// since we determine the UVs by doing a bilerp with a factor
|
||||
// from the original local rect.
|
||||
let local_rect = prim_metadata.local_rect
|
||||
.intersection(&prim_instance.combined_local_clip_rect);
|
||||
let local_rect = prim
|
||||
.local_rect
|
||||
.intersection(&prim_instance.combined_local_clip_rect);
|
||||
|
||||
if let Some(local_rect) = local_rect {
|
||||
match transform.transform_kind() {
|
||||
|
@ -828,8 +840,8 @@ impl AlphaBatchBuilder {
|
|||
0,
|
||||
]);
|
||||
|
||||
let shadow_rect = prim_metadata.local_rect.translate(&offset);
|
||||
let shadow_clip_rect = prim_metadata.local_clip_rect.translate(&offset);
|
||||
let shadow_rect = prim.local_rect.translate(&offset);
|
||||
let shadow_clip_rect = prim.local_clip_rect.translate(&offset);
|
||||
|
||||
let shadow_prim_header = PrimitiveHeader {
|
||||
local_rect: shadow_rect,
|
||||
|
|
|
@ -26,8 +26,8 @@ use internal_types::{FastHashMap, FastHashSet};
|
|||
use picture::{PictureCompositeMode, PictureIdGenerator, PicturePrimitive};
|
||||
use prim_store::{BrushKind, BrushPrimitive, BrushSegmentDescriptor, PrimitiveInstance};
|
||||
use prim_store::{EdgeAaSegmentMask, ImageSource, PrimitiveOpacity, PrimitiveKey};
|
||||
use prim_store::{BorderSource, BrushSegment, BrushSegmentVec, PrimitiveContainer, PrimitiveIndex, PrimitiveStore};
|
||||
use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive};
|
||||
use prim_store::{BorderSource, BrushSegment, BrushSegmentVec, PrimitiveContainer, PrimitiveStore};
|
||||
use prim_store::{OpacityBinding, ScrollNodeAndClipChain, TextRunPrimitive, PictureIndex};
|
||||
use render_backend::{DocumentView};
|
||||
use resource_cache::{FontInstanceMap, ImageRequest};
|
||||
use scene::{Scene, ScenePipeline, StackingContextHelpers};
|
||||
|
@ -159,9 +159,9 @@ pub struct DisplayListFlattener<'a> {
|
|||
/// The estimated count of primtives we expect to encounter during flattening.
|
||||
prim_count_estimate: usize,
|
||||
|
||||
/// The root primitive index for this flattener. This is the primitive
|
||||
/// The root picture index for this flattener. This is the picture
|
||||
/// to start the culling phase from.
|
||||
pub root_prim_index: PrimitiveIndex,
|
||||
pub root_pic_index: PictureIndex,
|
||||
}
|
||||
|
||||
impl<'a> DisplayListFlattener<'a> {
|
||||
|
@ -201,7 +201,7 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
picture_id_generator,
|
||||
resources,
|
||||
prim_count_estimate: 0,
|
||||
root_prim_index: PrimitiveIndex(0),
|
||||
root_pic_index: PictureIndex(0),
|
||||
};
|
||||
|
||||
flattener.push_root(
|
||||
|
@ -1064,9 +1064,10 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
stacking_context.requested_raster_space,
|
||||
stacking_context.normal_primitives,
|
||||
);
|
||||
let leaf_pic_index = self.prim_store.create_picture(leaf_picture);
|
||||
|
||||
// Create a brush primitive that draws this picture.
|
||||
let leaf_prim = BrushPrimitive::new_picture(leaf_picture);
|
||||
let leaf_prim = BrushPrimitive::new_picture(leaf_pic_index);
|
||||
|
||||
// Add the brush to the parent picture.
|
||||
let leaf_prim_index = self.prim_store.add_primitive(
|
||||
|
@ -1078,6 +1079,7 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
// Create a chain of pictures based on presence of filters,
|
||||
// mix-blend-mode and/or 3d rendering context containers.
|
||||
let mut current_prim_index = leaf_prim_index;
|
||||
let mut current_pic_index = leaf_pic_index;
|
||||
|
||||
// For each filter, create a new image with that composite mode.
|
||||
for filter in &stacking_context.composite_ops.filters {
|
||||
|
@ -1100,8 +1102,10 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
),
|
||||
],
|
||||
);
|
||||
let filter_pic_index = self.prim_store.create_picture(filter_picture);
|
||||
current_pic_index = filter_pic_index;
|
||||
|
||||
let filter_prim = BrushPrimitive::new_picture(filter_picture);
|
||||
let filter_prim = BrushPrimitive::new_picture(filter_pic_index);
|
||||
|
||||
current_prim_index = self.prim_store.add_primitive(
|
||||
&LayoutRect::zero(),
|
||||
|
@ -1111,7 +1115,7 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
|
||||
// Run the optimize pass on this picture, to see if we can
|
||||
// collapse opacity and avoid drawing to an off-screen surface.
|
||||
self.prim_store.optimize_picture_if_possible(current_prim_index);
|
||||
self.prim_store.optimize_picture_if_possible(current_pic_index);
|
||||
}
|
||||
|
||||
// Same for mix-blend-mode.
|
||||
|
@ -1133,8 +1137,10 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
),
|
||||
],
|
||||
);
|
||||
let blend_pic_index = self.prim_store.create_picture(blend_picture);
|
||||
current_pic_index = blend_pic_index;
|
||||
|
||||
let blend_prim = BrushPrimitive::new_picture(blend_picture);
|
||||
let blend_prim = BrushPrimitive::new_picture(blend_pic_index);
|
||||
|
||||
current_prim_index = self.prim_store.add_primitive(
|
||||
&LayoutRect::zero(),
|
||||
|
@ -1167,8 +1173,10 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
stacking_context.requested_raster_space,
|
||||
prims,
|
||||
);
|
||||
let container_pic_index = self.prim_store.create_picture(container_picture);
|
||||
current_pic_index = container_pic_index;
|
||||
|
||||
let container_prim = BrushPrimitive::new_picture(container_picture);
|
||||
let container_prim = BrushPrimitive::new_picture(container_pic_index);
|
||||
|
||||
current_prim_index = self.prim_store.add_primitive(
|
||||
&LayoutRect::zero(),
|
||||
|
@ -1181,7 +1189,7 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
|
||||
if self.sc_stack.is_empty() {
|
||||
// This must be the root stacking context
|
||||
self.root_prim_index = current_prim_index;
|
||||
self.root_pic_index = current_pic_index;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1500,7 +1508,8 @@ impl<'a> DisplayListFlattener<'a> {
|
|||
);
|
||||
|
||||
// Create the primitive to draw the shadow picture into the scene.
|
||||
let shadow_prim = BrushPrimitive::new_picture(shadow_pic);
|
||||
let shadow_pic_index = self.prim_store.create_picture(shadow_pic);
|
||||
let shadow_prim = BrushPrimitive::new_picture(shadow_pic_index);
|
||||
let shadow_prim_index = self.prim_store.add_primitive(
|
||||
&LayoutRect::zero(),
|
||||
&max_clip,
|
||||
|
|
|
@ -13,7 +13,7 @@ use gpu_types::{PrimitiveHeaders, TransformPalette, UvRectKind};
|
|||
use hit_test::{HitTester, HitTestingRun};
|
||||
use internal_types::{FastHashMap};
|
||||
use picture::{PictureCompositeMode, PictureSurface, RasterConfig};
|
||||
use prim_store::{PrimitiveIndex, PrimitiveStore, SpaceMapper};
|
||||
use prim_store::{PrimitiveIndex, PrimitiveStore, SpaceMapper, PictureIndex};
|
||||
use profiler::{FrameProfileCounters, GpuCacheProfileCounters, TextureCacheProfileCounters};
|
||||
use render_backend::{FrameResources, FrameId};
|
||||
use render_task::{RenderTask, RenderTaskId, RenderTaskLocation, RenderTaskTree};
|
||||
|
@ -58,7 +58,7 @@ pub struct FrameBuilder {
|
|||
background_color: Option<ColorF>,
|
||||
window_size: DeviceUintSize,
|
||||
scene_id: u64,
|
||||
root_prim_index: PrimitiveIndex,
|
||||
root_pic_index: PictureIndex,
|
||||
pub prim_store: PrimitiveStore,
|
||||
pub clip_store: ClipStore,
|
||||
pub hit_testing_runs: Vec<HitTestingRun>,
|
||||
|
@ -88,6 +88,7 @@ pub struct FrameBuildingState<'a> {
|
|||
}
|
||||
|
||||
pub struct PictureContext {
|
||||
pub pic_index: PictureIndex,
|
||||
pub pipeline_id: PipelineId,
|
||||
pub apply_local_clip_rect: bool,
|
||||
pub inflation_factor: f32,
|
||||
|
@ -138,7 +139,7 @@ impl FrameBuilder {
|
|||
window_size: DeviceUintSize::zero(),
|
||||
background_color: None,
|
||||
scene_id: 0,
|
||||
root_prim_index: PrimitiveIndex(0),
|
||||
root_pic_index: PictureIndex(0),
|
||||
config: FrameBuilderConfig {
|
||||
default_font_render_mode: FontRenderMode::Mono,
|
||||
dual_source_blending_is_enabled: true,
|
||||
|
@ -159,7 +160,7 @@ impl FrameBuilder {
|
|||
hit_testing_runs: flattener.hit_testing_runs,
|
||||
prim_store: flattener.prim_store,
|
||||
clip_store: flattener.clip_store,
|
||||
root_prim_index: flattener.root_prim_index,
|
||||
root_pic_index: flattener.root_pic_index,
|
||||
screen_rect,
|
||||
background_color,
|
||||
window_size,
|
||||
|
@ -228,8 +229,9 @@ impl FrameBuilder {
|
|||
|
||||
let (pic_context, mut pic_state, mut instances) = self
|
||||
.prim_store
|
||||
.get_pic_mut(self.root_prim_index)
|
||||
.pictures[self.root_pic_index.0]
|
||||
.take_context(
|
||||
self.root_pic_index,
|
||||
&prim_context,
|
||||
root_spatial_node_index,
|
||||
root_spatial_node_index,
|
||||
|
@ -251,9 +253,7 @@ impl FrameBuilder {
|
|||
&mut pic_rect,
|
||||
);
|
||||
|
||||
let pic = self
|
||||
.prim_store
|
||||
.get_pic_mut(self.root_prim_index);
|
||||
let pic = &mut self.prim_store.pictures[self.root_pic_index.0];
|
||||
pic.restore_context(
|
||||
instances,
|
||||
pic_context,
|
||||
|
@ -267,7 +267,7 @@ impl FrameBuilder {
|
|||
let root_render_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Fixed(self.screen_rect.to_i32()),
|
||||
self.screen_rect.size.to_f32(),
|
||||
self.root_prim_index,
|
||||
self.root_pic_index,
|
||||
DeviceIntPoint::zero(),
|
||||
pic_state.tasks,
|
||||
UvRectKind::Rect,
|
||||
|
|
|
@ -14,8 +14,7 @@ use frame_builder::{FrameBuildingContext, FrameBuildingState, PictureState};
|
|||
use frame_builder::{PictureContext, PrimitiveContext};
|
||||
use gpu_cache::{GpuCacheHandle};
|
||||
use gpu_types::UvRectKind;
|
||||
use prim_store::{PrimitiveInstance, SpaceMapper};
|
||||
use prim_store::{PrimitiveMetadata, get_raster_rects};
|
||||
use prim_store::{PictureIndex, PrimitiveInstance, SpaceMapper, get_raster_rects};
|
||||
use render_task::{ClearMode, RenderTask, RenderTaskCacheEntryHandle};
|
||||
use render_task::{RenderTaskCacheKey, RenderTaskCacheKeyKind, RenderTaskId, RenderTaskLocation};
|
||||
use scene::{FilterOpHelpers, SceneProperties};
|
||||
|
@ -242,6 +241,7 @@ impl PicturePrimitive {
|
|||
|
||||
pub fn take_context(
|
||||
&mut self,
|
||||
pic_index: PictureIndex,
|
||||
prim_context: &PrimitiveContext,
|
||||
surface_spatial_node_index: SpatialNodeIndex,
|
||||
raster_spatial_node_index: SpatialNodeIndex,
|
||||
|
@ -366,6 +366,7 @@ impl PicturePrimitive {
|
|||
};
|
||||
|
||||
let context = PictureContext {
|
||||
pic_index,
|
||||
pipeline_id: self.pipeline_id,
|
||||
apply_local_clip_rect: self.apply_local_clip_rect,
|
||||
inflation_factor,
|
||||
|
@ -439,8 +440,9 @@ impl PicturePrimitive {
|
|||
|
||||
pub fn prepare_for_render(
|
||||
&mut self,
|
||||
pic_index: PictureIndex,
|
||||
prim_instance: &PrimitiveInstance,
|
||||
prim_metadata: &PrimitiveMetadata,
|
||||
prim_local_rect: &LayoutRect,
|
||||
pic_state: &mut PictureState,
|
||||
frame_context: &FrameBuildingContext,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
|
@ -455,7 +457,7 @@ impl PicturePrimitive {
|
|||
frame_context,
|
||||
);
|
||||
|
||||
let pic_rect = PictureRect::from_untyped(&prim_metadata.local_rect.to_untyped());
|
||||
let pic_rect = PictureRect::from_untyped(&prim_local_rect.to_untyped());
|
||||
|
||||
let (clipped, unclipped, transform) = match get_raster_rects(
|
||||
pic_rect,
|
||||
|
@ -511,7 +513,7 @@ impl PicturePrimitive {
|
|||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, device_rect.size),
|
||||
unclipped.size,
|
||||
prim_instance.prim_index,
|
||||
pic_index,
|
||||
device_rect.origin,
|
||||
pic_state_for_children.tasks,
|
||||
uv_rect_kind,
|
||||
|
@ -569,7 +571,7 @@ impl PicturePrimitive {
|
|||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, device_rect.size),
|
||||
unclipped.size,
|
||||
prim_instance.prim_index,
|
||||
pic_index,
|
||||
device_rect.origin,
|
||||
child_tasks,
|
||||
uv_rect_kind,
|
||||
|
@ -626,7 +628,7 @@ impl PicturePrimitive {
|
|||
let mut picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, device_rect.size),
|
||||
unclipped.size,
|
||||
prim_instance.prim_index,
|
||||
pic_index,
|
||||
device_rect.origin,
|
||||
pic_state_for_children.tasks,
|
||||
uv_rect_kind,
|
||||
|
@ -669,14 +671,14 @@ impl PicturePrimitive {
|
|||
// Basic brush primitive header is (see end of prepare_prim_for_render_inner in prim_store.rs)
|
||||
// [brush specific data]
|
||||
// [segment_rect, segment data]
|
||||
let shadow_rect = prim_metadata.local_rect.translate(&offset);
|
||||
let shadow_rect = prim_local_rect.translate(&offset);
|
||||
|
||||
// ImageBrush colors
|
||||
request.push(color.premultiplied());
|
||||
request.push(PremultipliedColorF::WHITE);
|
||||
request.push([
|
||||
prim_metadata.local_rect.size.width,
|
||||
prim_metadata.local_rect.size.height,
|
||||
prim_local_rect.size.width,
|
||||
prim_local_rect.size.height,
|
||||
0.0,
|
||||
0.0,
|
||||
]);
|
||||
|
@ -697,7 +699,7 @@ impl PicturePrimitive {
|
|||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
prim_instance.prim_index,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
pic_state_for_children.tasks,
|
||||
uv_rect_kind,
|
||||
|
@ -734,7 +736,7 @@ impl PicturePrimitive {
|
|||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
prim_instance.prim_index,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
pic_state_for_children.tasks,
|
||||
uv_rect_kind,
|
||||
|
@ -756,7 +758,7 @@ impl PicturePrimitive {
|
|||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
prim_instance.prim_index,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
pic_state_for_children.tasks,
|
||||
uv_rect_kind,
|
||||
|
|
|
@ -224,6 +224,11 @@ pub struct DeferredResolve {
|
|||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct PrimitiveIndex(pub usize);
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct PictureIndex(pub usize);
|
||||
|
||||
impl GpuCacheHandle {
|
||||
pub fn as_int(&self, gpu_cache: &GpuCache) -> i32 {
|
||||
gpu_cache.get_address(self).as_int()
|
||||
|
@ -281,13 +286,6 @@ pub type PrimitiveDataHandle = intern::Handle<PrimitiveDataMarker>;
|
|||
pub type PrimitiveDataUpdateList = intern::UpdateList<PrimitiveKey>;
|
||||
pub type PrimitiveDataInterner = intern::Interner<PrimitiveKey, PrimitiveDataMarker>;
|
||||
|
||||
// TODO(gw): Pack the fields here better!
|
||||
#[derive(Debug)]
|
||||
pub struct PrimitiveMetadata {
|
||||
pub local_rect: LayoutRect,
|
||||
pub local_clip_rect: LayoutRect,
|
||||
}
|
||||
|
||||
// Maintains a list of opacity bindings that have been collapsed into
|
||||
// the color of a single primitive. This is an important optimization
|
||||
// that avoids allocating an intermediate surface for most common
|
||||
|
@ -372,7 +370,9 @@ pub enum BrushKind {
|
|||
opacity_binding: OpacityBinding,
|
||||
},
|
||||
Clear,
|
||||
Picture(PicturePrimitive),
|
||||
Picture {
|
||||
pic_index: PictureIndex,
|
||||
},
|
||||
Image {
|
||||
request: ImageRequest,
|
||||
alpha_type: AlphaType,
|
||||
|
@ -638,20 +638,11 @@ impl BrushPrimitive {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn may_need_clip_mask(&self) -> bool {
|
||||
match self.kind {
|
||||
BrushKind::Picture(ref pic) => {
|
||||
pic.raster_config.is_some()
|
||||
}
|
||||
_ => {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_picture(prim: PicturePrimitive) -> Self {
|
||||
pub fn new_picture(pic_index: PictureIndex) -> Self {
|
||||
BrushPrimitive {
|
||||
kind: BrushKind::Picture(prim),
|
||||
kind: BrushKind::Picture {
|
||||
pic_index,
|
||||
},
|
||||
segment_desc: None,
|
||||
}
|
||||
}
|
||||
|
@ -1508,30 +1499,11 @@ pub enum PrimitiveDetails {
|
|||
}
|
||||
|
||||
pub struct Primitive {
|
||||
pub metadata: PrimitiveMetadata,
|
||||
pub local_rect: LayoutRect,
|
||||
pub local_clip_rect: LayoutRect,
|
||||
pub details: PrimitiveDetails,
|
||||
}
|
||||
|
||||
impl Primitive {
|
||||
pub fn as_pic(&self) -> &PicturePrimitive {
|
||||
match self.details {
|
||||
PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Picture(ref pic), .. }) => pic,
|
||||
_ => {
|
||||
panic!("bug: not a picture!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_pic_mut(&mut self) -> &mut PicturePrimitive {
|
||||
match self.details {
|
||||
PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Picture(ref mut pic), .. }) => pic,
|
||||
_ => {
|
||||
panic!("bug: not a picture!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct PrimitiveInstance {
|
||||
/// Index into the prim store containing information about
|
||||
|
@ -1602,6 +1574,7 @@ impl PrimitiveInstance {
|
|||
|
||||
pub struct PrimitiveStore {
|
||||
pub primitives: Vec<Primitive>,
|
||||
pub pictures: Vec<PicturePrimitive>,
|
||||
|
||||
/// A primitive index to chase through debugging.
|
||||
pub chase_id: Option<PrimitiveIndex>,
|
||||
|
@ -1611,16 +1584,18 @@ impl PrimitiveStore {
|
|||
pub fn new() -> PrimitiveStore {
|
||||
PrimitiveStore {
|
||||
primitives: Vec::new(),
|
||||
pictures: Vec::new(),
|
||||
chase_id: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_pic(&self, index: PrimitiveIndex) -> &PicturePrimitive {
|
||||
self.primitives[index.0].as_pic()
|
||||
}
|
||||
|
||||
pub fn get_pic_mut(&mut self, index: PrimitiveIndex) -> &mut PicturePrimitive {
|
||||
self.primitives[index.0].as_pic_mut()
|
||||
pub fn create_picture(
|
||||
&mut self,
|
||||
prim: PicturePrimitive,
|
||||
) -> PictureIndex {
|
||||
let index = PictureIndex(self.pictures.len());
|
||||
self.pictures.push(prim);
|
||||
index
|
||||
}
|
||||
|
||||
pub fn add_primitive(
|
||||
|
@ -1631,34 +1606,21 @@ impl PrimitiveStore {
|
|||
) -> PrimitiveIndex {
|
||||
let prim_index = self.primitives.len();
|
||||
|
||||
let base_metadata = PrimitiveMetadata {
|
||||
local_rect: *local_rect,
|
||||
local_clip_rect: *local_clip_rect,
|
||||
};
|
||||
|
||||
let prim = match container {
|
||||
let details = match container {
|
||||
PrimitiveContainer::Brush(brush) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
..base_metadata
|
||||
};
|
||||
|
||||
Primitive {
|
||||
metadata,
|
||||
details: PrimitiveDetails::Brush(brush),
|
||||
}
|
||||
PrimitiveDetails::Brush(brush)
|
||||
}
|
||||
PrimitiveContainer::TextRun(text_cpu) => {
|
||||
let metadata = PrimitiveMetadata {
|
||||
..base_metadata
|
||||
};
|
||||
|
||||
Primitive {
|
||||
metadata,
|
||||
details: PrimitiveDetails::TextRun(text_cpu),
|
||||
}
|
||||
PrimitiveDetails::TextRun(text_cpu)
|
||||
}
|
||||
};
|
||||
|
||||
let prim = Primitive {
|
||||
local_rect: *local_rect,
|
||||
local_clip_rect: *local_clip_rect,
|
||||
details,
|
||||
};
|
||||
|
||||
self.primitives.push(prim);
|
||||
|
||||
PrimitiveIndex(prim_index)
|
||||
|
@ -1668,9 +1630,9 @@ impl PrimitiveStore {
|
|||
// that can be the target for collapsing parent opacity filters into.
|
||||
fn get_opacity_collapse_prim(
|
||||
&self,
|
||||
pic_prim_index: PrimitiveIndex,
|
||||
pic_index: PictureIndex,
|
||||
) -> Option<PrimitiveIndex> {
|
||||
let pic = self.get_pic(pic_prim_index);
|
||||
let pic = &self.pictures[pic_index.0];
|
||||
|
||||
// We can only collapse opacity if there is a single primitive, otherwise
|
||||
// the opacity needs to be applied to the primitives as a group.
|
||||
|
@ -1688,12 +1650,14 @@ impl PrimitiveStore {
|
|||
match prim.details {
|
||||
PrimitiveDetails::Brush(ref brush) => {
|
||||
match brush.kind {
|
||||
BrushKind::Picture(ref pic) => {
|
||||
BrushKind::Picture { pic_index, .. } => {
|
||||
let pic = &self.pictures[pic_index.0];
|
||||
|
||||
// If we encounter a picture that is a pass-through
|
||||
// (i.e. no composite mode), then we can recurse into
|
||||
// that to try and find a primitive to collapse to.
|
||||
if pic.requested_composite_mode.is_none() {
|
||||
return self.get_opacity_collapse_prim(prim_instance.prim_index);
|
||||
return self.get_opacity_collapse_prim(pic_index);
|
||||
}
|
||||
}
|
||||
// If we find a single rect or image, we can use that
|
||||
|
@ -1721,10 +1685,10 @@ impl PrimitiveStore {
|
|||
// if that picture contains one compatible primitive.
|
||||
pub fn optimize_picture_if_possible(
|
||||
&mut self,
|
||||
pic_prim_index: PrimitiveIndex,
|
||||
pic_index: PictureIndex,
|
||||
) {
|
||||
// Only handle opacity filters for now.
|
||||
let binding = match self.get_pic(pic_prim_index).requested_composite_mode {
|
||||
let binding = match self.pictures[pic_index.0].requested_composite_mode {
|
||||
Some(PictureCompositeMode::Filter(FilterOp::Opacity(binding, _))) => {
|
||||
binding
|
||||
}
|
||||
|
@ -1735,7 +1699,7 @@ impl PrimitiveStore {
|
|||
|
||||
// See if this picture contains a single primitive that supports
|
||||
// opacity collapse.
|
||||
match self.get_opacity_collapse_prim(pic_prim_index) {
|
||||
match self.get_opacity_collapse_prim(pic_index) {
|
||||
Some(prim_index) => {
|
||||
let prim = &mut self.primitives[prim_index.0];
|
||||
match prim.details {
|
||||
|
@ -1773,7 +1737,7 @@ impl PrimitiveStore {
|
|||
// intermediate surface or incur an extra blend / blit. Instead,
|
||||
// the collapsed primitive will be drawn directly into the
|
||||
// parent picture.
|
||||
self.get_pic_mut(pic_prim_index).requested_composite_mode = None;
|
||||
self.pictures[pic_index.0].requested_composite_mode = None;
|
||||
}
|
||||
|
||||
pub fn prim_count(&self) -> usize {
|
||||
|
@ -1799,8 +1763,11 @@ impl PrimitiveStore {
|
|||
// picture target, if being composited.
|
||||
let pic_info = {
|
||||
match self.primitives[prim_instance.prim_index.0].details {
|
||||
PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Picture(ref mut pic), .. }) => {
|
||||
PrimitiveDetails::Brush(BrushPrimitive { kind: BrushKind::Picture { pic_index, .. }, .. }) => {
|
||||
let pic = &mut self.pictures[pic_index.0];
|
||||
|
||||
match pic.take_context(
|
||||
pic_index,
|
||||
prim_context,
|
||||
pic_state.surface_spatial_node_index,
|
||||
pic_state.raster_spatial_node_index,
|
||||
|
@ -1845,13 +1812,12 @@ impl PrimitiveStore {
|
|||
};
|
||||
|
||||
if !pic_state_for_children.is_cacheable {
|
||||
pic_state.is_cacheable = false;
|
||||
pic_state.is_cacheable = false;
|
||||
}
|
||||
|
||||
// Restore the dependencies (borrow check dance)
|
||||
let prim = &mut self.primitives[prim_instance.prim_index.0];
|
||||
let (new_local_rect, clip_node_collector) = prim
|
||||
.as_pic_mut()
|
||||
let (new_local_rect, clip_node_collector) = self
|
||||
.pictures[pic_context_for_children.pic_index.0]
|
||||
.restore_context(
|
||||
prim_instances,
|
||||
pic_context_for_children,
|
||||
|
@ -1860,8 +1826,9 @@ impl PrimitiveStore {
|
|||
frame_state,
|
||||
);
|
||||
|
||||
if new_local_rect != prim.metadata.local_rect {
|
||||
prim.metadata.local_rect = new_local_rect;
|
||||
let prim = &mut self.primitives[prim_instance.prim_index.0];
|
||||
if new_local_rect != prim.local_rect {
|
||||
prim.local_rect = new_local_rect;
|
||||
frame_state.gpu_cache.invalidate(&mut prim_instance.gpu_location);
|
||||
pic_state.local_rect_changed = true;
|
||||
}
|
||||
|
@ -1882,8 +1849,8 @@ impl PrimitiveStore {
|
|||
if is_passthrough {
|
||||
prim_instance.clipped_world_rect = Some(pic_state.map_pic_to_world.bounds);
|
||||
} else {
|
||||
if prim.metadata.local_rect.size.width <= 0.0 ||
|
||||
prim.metadata.local_rect.size.height <= 0.0 {
|
||||
if prim.local_rect.size.width <= 0.0 ||
|
||||
prim.local_rect.size.height <= 0.0 {
|
||||
if cfg!(debug_assertions) && is_chased {
|
||||
println!("\tculled for zero local rectangle");
|
||||
}
|
||||
|
@ -1895,16 +1862,15 @@ impl PrimitiveStore {
|
|||
// is not visible, any effects from the blur radius will be correctly
|
||||
// taken into account.
|
||||
let local_rect = prim
|
||||
.metadata
|
||||
.local_rect
|
||||
.inflate(pic_context.inflation_factor, pic_context.inflation_factor)
|
||||
.intersection(&prim.metadata.local_clip_rect);
|
||||
.intersection(&prim.local_clip_rect);
|
||||
let local_rect = match local_rect {
|
||||
Some(local_rect) => local_rect,
|
||||
None => {
|
||||
if cfg!(debug_assertions) && is_chased {
|
||||
println!("\tculled for being out of the local clip rectangle: {:?}",
|
||||
prim.metadata.local_clip_rect);
|
||||
prim.local_clip_rect);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1915,7 +1881,7 @@ impl PrimitiveStore {
|
|||
.build_clip_chain_instance(
|
||||
prim_instance.clip_chain_id,
|
||||
local_rect,
|
||||
prim.metadata.local_clip_rect,
|
||||
prim.local_clip_rect,
|
||||
prim_context.spatial_node_index,
|
||||
&pic_state.map_local_to_pic,
|
||||
&pic_state.map_pic_to_world,
|
||||
|
@ -1948,11 +1914,11 @@ impl PrimitiveStore {
|
|||
prim_instance.combined_local_clip_rect = if pic_context.apply_local_clip_rect {
|
||||
clip_chain.local_clip_rect
|
||||
} else {
|
||||
prim.metadata.local_clip_rect
|
||||
prim.local_clip_rect
|
||||
};
|
||||
|
||||
let pic_rect = match pic_state.map_local_to_pic
|
||||
.map(&prim.metadata.local_rect) {
|
||||
.map(&prim.local_rect) {
|
||||
Some(pic_rect) => pic_rect,
|
||||
None => return false,
|
||||
};
|
||||
|
@ -2001,6 +1967,7 @@ impl PrimitiveStore {
|
|||
prim_context,
|
||||
pic_context,
|
||||
pic_state,
|
||||
&mut self.pictures,
|
||||
frame_context,
|
||||
frame_state,
|
||||
display_list,
|
||||
|
@ -2118,7 +2085,7 @@ fn build_gradient_stops_request(
|
|||
fn decompose_repeated_primitive(
|
||||
visible_tiles: &mut Vec<VisibleGradientTile>,
|
||||
instance: &mut PrimitiveInstance,
|
||||
metadata: &mut PrimitiveMetadata,
|
||||
prim_local_rect: &LayoutRect,
|
||||
stretch_size: &LayoutSize,
|
||||
tile_spacing: &LayoutSize,
|
||||
prim_context: &PrimitiveContext,
|
||||
|
@ -2132,7 +2099,7 @@ fn decompose_repeated_primitive(
|
|||
// rect and we want to clip these extra parts out.
|
||||
let tight_clip_rect = instance
|
||||
.combined_local_clip_rect
|
||||
.intersection(&metadata.local_rect).unwrap();
|
||||
.intersection(prim_local_rect).unwrap();
|
||||
|
||||
let clipped_world_rect = &instance
|
||||
.clipped_world_rect
|
||||
|
@ -2146,7 +2113,7 @@ fn decompose_repeated_primitive(
|
|||
let stride = *stretch_size + *tile_spacing;
|
||||
|
||||
for_each_repetition(
|
||||
&metadata.local_rect,
|
||||
prim_local_rect,
|
||||
&visible_rect,
|
||||
&stride,
|
||||
&mut |origin, _| {
|
||||
|
@ -2220,165 +2187,168 @@ impl<'a> GpuDataRequest<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn write_brush_segment_description(
|
||||
brush: &mut BrushPrimitive,
|
||||
metadata: &PrimitiveMetadata,
|
||||
clip_chain: &ClipChainInstance,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
) {
|
||||
match brush.segment_desc {
|
||||
Some(..) => {
|
||||
// If we already have a segment descriptor, skip segment build.
|
||||
return;
|
||||
}
|
||||
None => {
|
||||
// If no segment descriptor built yet, see if it is a brush
|
||||
// type that wants to be segmented.
|
||||
if !brush.kind.supports_segments(frame_state.resource_cache) {
|
||||
impl BrushPrimitive {
|
||||
fn write_brush_segment_description(
|
||||
&mut self,
|
||||
prim_local_rect: LayoutRect,
|
||||
prim_local_clip_rect: LayoutRect,
|
||||
clip_chain: &ClipChainInstance,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
) {
|
||||
match self.segment_desc {
|
||||
Some(..) => {
|
||||
// If we already have a segment descriptor, skip segment build.
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the brush is small, we generally want to skip building segments
|
||||
// and just draw it as a single primitive with clip mask. However,
|
||||
// if the clips are purely rectangles that have no per-fragment
|
||||
// clip masks, we will segment anyway. This allows us to completely
|
||||
// skip allocating a clip mask in these cases.
|
||||
let is_large = metadata.local_rect.size.area() > MIN_BRUSH_SPLIT_AREA;
|
||||
|
||||
// TODO(gw): We should probably detect and store this on each
|
||||
// ClipSources instance, to avoid having to iterate
|
||||
// the clip sources here.
|
||||
let mut rect_clips_only = true;
|
||||
|
||||
let segment_builder = &mut frame_state.segment_builder;
|
||||
segment_builder.initialize(
|
||||
metadata.local_rect,
|
||||
None,
|
||||
metadata.local_clip_rect
|
||||
);
|
||||
|
||||
// Segment the primitive on all the local-space clip sources that we can.
|
||||
let mut local_clip_count = 0;
|
||||
for i in 0 .. clip_chain.clips_range.count {
|
||||
let clip_instance = frame_state
|
||||
.clip_store
|
||||
.get_instance_from_range(&clip_chain.clips_range, i);
|
||||
let clip_node = &frame_state.resources.clip_data_store[clip_instance.handle];
|
||||
|
||||
// If this clip item is positioned by another positioning node, its relative position
|
||||
// could change during scrolling. This means that we would need to resegment. Instead
|
||||
// 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_instance.flags.contains(ClipNodeFlags::SAME_SPATIAL_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
local_clip_count += 1;
|
||||
|
||||
let (local_clip_rect, radius, mode) = match clip_node.item {
|
||||
ClipItem::RoundedRectangle(rect, radii, clip_mode) => {
|
||||
rect_clips_only = false;
|
||||
(rect, Some(radii), clip_mode)
|
||||
}
|
||||
ClipItem::Rectangle(rect, mode) => {
|
||||
(rect, None, mode)
|
||||
}
|
||||
ClipItem::BoxShadow(ref info) => {
|
||||
rect_clips_only = false;
|
||||
|
||||
// For inset box shadows, we can clip out any
|
||||
// pixels that are inside the shadow region
|
||||
// and are beyond the inner rect, as they can't
|
||||
// be affected by the blur radius.
|
||||
let inner_clip_mode = match info.clip_mode {
|
||||
BoxShadowClipMode::Outset => None,
|
||||
BoxShadowClipMode::Inset => Some(ClipMode::ClipOut),
|
||||
};
|
||||
|
||||
// Push a region into the segment builder where the
|
||||
// box-shadow can have an effect on the result. This
|
||||
// ensures clip-mask tasks get allocated for these
|
||||
// pixel regions, even if no other clips affect them.
|
||||
segment_builder.push_mask_region(
|
||||
info.prim_shadow_rect,
|
||||
info.prim_shadow_rect.inflate(
|
||||
-0.5 * info.shadow_rect_alloc_size.width,
|
||||
-0.5 * info.shadow_rect_alloc_size.height,
|
||||
),
|
||||
inner_clip_mode,
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
ClipItem::Image(..) => {
|
||||
rect_clips_only = false;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
segment_builder.push_clip_rect(local_clip_rect, radius, mode);
|
||||
}
|
||||
|
||||
if is_large || rect_clips_only {
|
||||
// If there were no local clips, then we will subdivide the primitive into
|
||||
// a uniform grid (up to 8x8 segments). This will typically result in
|
||||
// a significant number of those segments either being completely clipped,
|
||||
// or determined to not need a clip mask for that segment.
|
||||
if local_clip_count == 0 && clip_chain.clips_range.count > 0 {
|
||||
let x_clip_count = cmp::min(8, (metadata.local_rect.size.width / 128.0).ceil() as i32);
|
||||
let y_clip_count = cmp::min(8, (metadata.local_rect.size.height / 128.0).ceil() as i32);
|
||||
|
||||
for y in 0 .. y_clip_count {
|
||||
let y0 = metadata.local_rect.size.height * y as f32 / y_clip_count as f32;
|
||||
let y1 = metadata.local_rect.size.height * (y+1) as f32 / y_clip_count as f32;
|
||||
|
||||
for x in 0 .. x_clip_count {
|
||||
let x0 = metadata.local_rect.size.width * x as f32 / x_clip_count as f32;
|
||||
let x1 = metadata.local_rect.size.width * (x+1) as f32 / x_clip_count as f32;
|
||||
|
||||
let rect = LayoutRect::new(
|
||||
LayoutPoint::new(
|
||||
x0 + metadata.local_rect.origin.x,
|
||||
y0 + metadata.local_rect.origin.y,
|
||||
),
|
||||
LayoutSize::new(
|
||||
x1 - x0,
|
||||
y1 - y0,
|
||||
),
|
||||
);
|
||||
|
||||
segment_builder.push_mask_region(rect, LayoutRect::zero(), None);
|
||||
None => {
|
||||
// If no segment descriptor built yet, see if it is a brush
|
||||
// type that wants to be segmented.
|
||||
if !self.kind.supports_segments(frame_state.resource_cache) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match brush.segment_desc {
|
||||
Some(..) => panic!("bug: should not already have descriptor"),
|
||||
None => {
|
||||
// TODO(gw): We can probably make the allocation
|
||||
// patterns of this and the segment
|
||||
// builder significantly better, by
|
||||
// retaining it across primitives.
|
||||
let mut segments = BrushSegmentVec::new();
|
||||
// If the brush is small, we generally want to skip building segments
|
||||
// and just draw it as a single primitive with clip mask. However,
|
||||
// if the clips are purely rectangles that have no per-fragment
|
||||
// clip masks, we will segment anyway. This allows us to completely
|
||||
// skip allocating a clip mask in these cases.
|
||||
let is_large = prim_local_rect.size.area() > MIN_BRUSH_SPLIT_AREA;
|
||||
|
||||
segment_builder.build(|segment| {
|
||||
segments.push(
|
||||
BrushSegment::new(
|
||||
segment.rect,
|
||||
segment.has_mask,
|
||||
segment.edge_flags,
|
||||
[0.0; 4],
|
||||
BrushFlags::empty(),
|
||||
// TODO(gw): We should probably detect and store this on each
|
||||
// ClipSources instance, to avoid having to iterate
|
||||
// the clip sources here.
|
||||
let mut rect_clips_only = true;
|
||||
|
||||
let segment_builder = &mut frame_state.segment_builder;
|
||||
segment_builder.initialize(
|
||||
prim_local_rect,
|
||||
None,
|
||||
prim_local_clip_rect
|
||||
);
|
||||
|
||||
// Segment the primitive on all the local-space clip sources that we can.
|
||||
let mut local_clip_count = 0;
|
||||
for i in 0 .. clip_chain.clips_range.count {
|
||||
let clip_instance = frame_state
|
||||
.clip_store
|
||||
.get_instance_from_range(&clip_chain.clips_range, i);
|
||||
let clip_node = &frame_state.resources.clip_data_store[clip_instance.handle];
|
||||
|
||||
// If this clip item is positioned by another positioning node, its relative position
|
||||
// could change during scrolling. This means that we would need to resegment. Instead
|
||||
// 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_instance.flags.contains(ClipNodeFlags::SAME_SPATIAL_NODE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
local_clip_count += 1;
|
||||
|
||||
let (local_clip_rect, radius, mode) = match clip_node.item {
|
||||
ClipItem::RoundedRectangle(rect, radii, clip_mode) => {
|
||||
rect_clips_only = false;
|
||||
(rect, Some(radii), clip_mode)
|
||||
}
|
||||
ClipItem::Rectangle(rect, mode) => {
|
||||
(rect, None, mode)
|
||||
}
|
||||
ClipItem::BoxShadow(ref info) => {
|
||||
rect_clips_only = false;
|
||||
|
||||
// For inset box shadows, we can clip out any
|
||||
// pixels that are inside the shadow region
|
||||
// and are beyond the inner rect, as they can't
|
||||
// be affected by the blur radius.
|
||||
let inner_clip_mode = match info.clip_mode {
|
||||
BoxShadowClipMode::Outset => None,
|
||||
BoxShadowClipMode::Inset => Some(ClipMode::ClipOut),
|
||||
};
|
||||
|
||||
// Push a region into the segment builder where the
|
||||
// box-shadow can have an effect on the result. This
|
||||
// ensures clip-mask tasks get allocated for these
|
||||
// pixel regions, even if no other clips affect them.
|
||||
segment_builder.push_mask_region(
|
||||
info.prim_shadow_rect,
|
||||
info.prim_shadow_rect.inflate(
|
||||
-0.5 * info.shadow_rect_alloc_size.width,
|
||||
-0.5 * info.shadow_rect_alloc_size.height,
|
||||
),
|
||||
inner_clip_mode,
|
||||
);
|
||||
});
|
||||
|
||||
brush.segment_desc = Some(BrushSegmentDescriptor {
|
||||
segments,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
ClipItem::Image(..) => {
|
||||
rect_clips_only = false;
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
segment_builder.push_clip_rect(local_clip_rect, radius, mode);
|
||||
}
|
||||
|
||||
if is_large || rect_clips_only {
|
||||
// If there were no local clips, then we will subdivide the primitive into
|
||||
// a uniform grid (up to 8x8 segments). This will typically result in
|
||||
// a significant number of those segments either being completely clipped,
|
||||
// or determined to not need a clip mask for that segment.
|
||||
if local_clip_count == 0 && clip_chain.clips_range.count > 0 {
|
||||
let x_clip_count = cmp::min(8, (prim_local_rect.size.width / 128.0).ceil() as i32);
|
||||
let y_clip_count = cmp::min(8, (prim_local_rect.size.height / 128.0).ceil() as i32);
|
||||
|
||||
for y in 0 .. y_clip_count {
|
||||
let y0 = prim_local_rect.size.height * y as f32 / y_clip_count as f32;
|
||||
let y1 = prim_local_rect.size.height * (y+1) as f32 / y_clip_count as f32;
|
||||
|
||||
for x in 0 .. x_clip_count {
|
||||
let x0 = prim_local_rect.size.width * x as f32 / x_clip_count as f32;
|
||||
let x1 = prim_local_rect.size.width * (x+1) as f32 / x_clip_count as f32;
|
||||
|
||||
let rect = LayoutRect::new(
|
||||
LayoutPoint::new(
|
||||
x0 + prim_local_rect.origin.x,
|
||||
y0 + prim_local_rect.origin.y,
|
||||
),
|
||||
LayoutSize::new(
|
||||
x1 - x0,
|
||||
y1 - y0,
|
||||
),
|
||||
);
|
||||
|
||||
segment_builder.push_mask_region(rect, LayoutRect::zero(), None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match self.segment_desc {
|
||||
Some(..) => panic!("bug: should not already have descriptor"),
|
||||
None => {
|
||||
// TODO(gw): We can probably make the allocation
|
||||
// patterns of this and the segment
|
||||
// builder significantly better, by
|
||||
// retaining it across primitives.
|
||||
let mut segments = BrushSegmentVec::new();
|
||||
|
||||
segment_builder.build(|segment| {
|
||||
segments.push(
|
||||
BrushSegment::new(
|
||||
segment.rect,
|
||||
segment.has_mask,
|
||||
segment.edge_flags,
|
||||
[0.0; 4],
|
||||
BrushFlags::empty(),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
self.segment_desc = Some(BrushSegmentDescriptor {
|
||||
segments,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2402,9 +2372,9 @@ impl Primitive {
|
|||
PrimitiveDetails::TextRun(..) => return false,
|
||||
};
|
||||
|
||||
write_brush_segment_description(
|
||||
brush,
|
||||
&self.metadata,
|
||||
brush.write_brush_segment_description(
|
||||
self.local_rect,
|
||||
self.local_clip_rect,
|
||||
prim_clip_chain,
|
||||
frame_state,
|
||||
);
|
||||
|
@ -2437,7 +2407,7 @@ impl Primitive {
|
|||
.build_clip_chain_instance(
|
||||
prim_instance.clip_chain_id,
|
||||
segment.local_rect,
|
||||
self.metadata.local_clip_rect,
|
||||
self.local_clip_rect,
|
||||
prim_context.spatial_node_index,
|
||||
&pic_state.map_local_to_pic,
|
||||
&pic_state.map_pic_to_world,
|
||||
|
@ -2467,10 +2437,7 @@ impl Primitive {
|
|||
// Returns true if the primitive *might* need a clip mask. If
|
||||
// false, there is no need to even check for clip masks for
|
||||
// this primitive.
|
||||
fn reset_clip_task(
|
||||
&mut self,
|
||||
prim_instance: &mut PrimitiveInstance,
|
||||
) -> bool {
|
||||
fn reset_clip_task(&mut self, prim_instance: &mut PrimitiveInstance) {
|
||||
prim_instance.clip_task_id = None;
|
||||
match self.details {
|
||||
PrimitiveDetails::Brush(ref mut brush) => {
|
||||
|
@ -2479,11 +2446,8 @@ impl Primitive {
|
|||
segment.clip_task_id = BrushSegmentTaskId::Opaque;
|
||||
}
|
||||
}
|
||||
brush.may_need_clip_mask()
|
||||
}
|
||||
PrimitiveDetails::TextRun(..) => {
|
||||
true
|
||||
}
|
||||
PrimitiveDetails::TextRun(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2493,13 +2457,13 @@ impl Primitive {
|
|||
prim_context: &PrimitiveContext,
|
||||
pic_context: &PictureContext,
|
||||
pic_state: &mut PictureState,
|
||||
pictures: &mut [PicturePrimitive],
|
||||
frame_context: &FrameBuildingContext,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
display_list: &BuiltDisplayList,
|
||||
is_chased: bool,
|
||||
) {
|
||||
let mut is_tiled = false;
|
||||
let metadata = &mut self.metadata;
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
prim_instance.prepared_frame_id = frame_state.render_tasks.frame_id();
|
||||
|
@ -2660,7 +2624,7 @@ impl Primitive {
|
|||
// rect and we want to clip these extra parts out.
|
||||
let tight_clip_rect = prim_instance
|
||||
.combined_local_clip_rect
|
||||
.intersection(&metadata.local_rect).unwrap();
|
||||
.intersection(&self.local_rect).unwrap();
|
||||
|
||||
let visible_rect = compute_conservative_visible_rect(
|
||||
prim_context,
|
||||
|
@ -2675,7 +2639,7 @@ impl Primitive {
|
|||
visible_tiles.clear();
|
||||
|
||||
for_each_repetition(
|
||||
&metadata.local_rect,
|
||||
&self.local_rect,
|
||||
&visible_rect,
|
||||
&stride,
|
||||
&mut |origin, edge_flags| {
|
||||
|
@ -2738,7 +2702,7 @@ impl Primitive {
|
|||
// Work out the device pixel size to be used to cache this line decoration.
|
||||
|
||||
let size = get_line_decoration_sizes(
|
||||
&metadata.local_rect.size,
|
||||
&self.local_rect.size,
|
||||
orientation,
|
||||
style,
|
||||
wavy_line_thickness,
|
||||
|
@ -2756,19 +2720,19 @@ impl Primitive {
|
|||
let clip_size = match orientation {
|
||||
LineOrientation::Horizontal => {
|
||||
LayoutSize::new(
|
||||
inline_size * (metadata.local_rect.size.width / inline_size).floor(),
|
||||
metadata.local_rect.size.height,
|
||||
inline_size * (self.local_rect.size.width / inline_size).floor(),
|
||||
self.local_rect.size.height,
|
||||
)
|
||||
}
|
||||
LineOrientation::Vertical => {
|
||||
LayoutSize::new(
|
||||
metadata.local_rect.size.width,
|
||||
inline_size * (metadata.local_rect.size.height / inline_size).floor(),
|
||||
self.local_rect.size.width,
|
||||
inline_size * (self.local_rect.size.height / inline_size).floor(),
|
||||
)
|
||||
}
|
||||
};
|
||||
let clip_rect = LayoutRect::new(
|
||||
metadata.local_rect.origin,
|
||||
self.local_rect.origin,
|
||||
clip_size,
|
||||
);
|
||||
prim_instance.combined_local_clip_rect = clip_rect
|
||||
|
@ -2918,7 +2882,7 @@ impl Primitive {
|
|||
decompose_repeated_primitive(
|
||||
visible_tiles,
|
||||
prim_instance,
|
||||
metadata,
|
||||
&self.local_rect,
|
||||
&stretch_size,
|
||||
&tile_spacing,
|
||||
prim_context,
|
||||
|
@ -2960,8 +2924,8 @@ impl Primitive {
|
|||
// then we just assume the gradient is translucent for now.
|
||||
// (In the future we could consider segmenting in some cases).
|
||||
let stride = stretch_size + tile_spacing;
|
||||
prim_instance.opacity = if stride.width >= metadata.local_rect.size.width &&
|
||||
stride.height >= metadata.local_rect.size.height {
|
||||
prim_instance.opacity = if stride.width >= self.local_rect.size.width &&
|
||||
stride.height >= self.local_rect.size.height {
|
||||
stops_opacity
|
||||
} else {
|
||||
PrimitiveOpacity::translucent()
|
||||
|
@ -2981,7 +2945,7 @@ impl Primitive {
|
|||
decompose_repeated_primitive(
|
||||
visible_tiles,
|
||||
prim_instance,
|
||||
metadata,
|
||||
&self.local_rect,
|
||||
&stretch_size,
|
||||
&tile_spacing,
|
||||
prim_context,
|
||||
|
@ -3004,10 +2968,12 @@ impl Primitive {
|
|||
);
|
||||
}
|
||||
}
|
||||
BrushKind::Picture(ref mut pic) => {
|
||||
BrushKind::Picture { pic_index, .. } => {
|
||||
let pic = &mut pictures[pic_index.0];
|
||||
if !pic.prepare_for_render(
|
||||
pic_index,
|
||||
prim_instance,
|
||||
metadata,
|
||||
&self.local_rect,
|
||||
pic_state,
|
||||
frame_context,
|
||||
frame_state,
|
||||
|
@ -3042,7 +3008,7 @@ impl Primitive {
|
|||
text.write_gpu_blocks(&mut request);
|
||||
}
|
||||
PrimitiveDetails::Brush(ref mut brush) => {
|
||||
brush.write_gpu_blocks(&mut request, metadata.local_rect);
|
||||
brush.write_gpu_blocks(&mut request, self.local_rect);
|
||||
|
||||
match brush.segment_desc {
|
||||
Some(ref segment_desc) => {
|
||||
|
@ -3059,7 +3025,7 @@ impl Primitive {
|
|||
}
|
||||
None => {
|
||||
request.write_segment(
|
||||
metadata.local_rect,
|
||||
self.local_rect,
|
||||
[0.0; 4],
|
||||
);
|
||||
}
|
||||
|
@ -3086,10 +3052,7 @@ impl Primitive {
|
|||
println!("\tupdating clip task with pic rect {:?}", clip_chain.pic_clip_rect);
|
||||
}
|
||||
// Reset clips from previous frames since we may clip differently each frame.
|
||||
// If this primitive never needs clip masks, just return straight away.
|
||||
if !self.reset_clip_task(prim_instance) {
|
||||
return;
|
||||
}
|
||||
self.reset_clip_task(prim_instance);
|
||||
|
||||
// First try to render this primitive's mask using optimized brush rendering.
|
||||
if self.update_clip_task_for_brush(
|
||||
|
|
|
@ -22,7 +22,7 @@ use internal_types::{CacheTextureId, FastHashMap, LayerIndex, SavedTargetIndex};
|
|||
#[cfg(feature = "pathfinder")]
|
||||
use pathfinder_partitioner::mesh::Mesh;
|
||||
use picture::PictureCacheKey;
|
||||
use prim_store::{PrimitiveIndex, ImageCacheKey, LineDecorationCacheKey};
|
||||
use prim_store::{PictureIndex, ImageCacheKey, LineDecorationCacheKey};
|
||||
#[cfg(feature = "debugger")]
|
||||
use print_tree::{PrintTreePrinter};
|
||||
use render_backend::FrameId;
|
||||
|
@ -222,7 +222,7 @@ pub struct ClipRegionTask {
|
|||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct PictureTask {
|
||||
pub prim_index: PrimitiveIndex,
|
||||
pub pic_index: PictureIndex,
|
||||
pub can_merge: bool,
|
||||
pub content_origin: DeviceIntPoint,
|
||||
pub uv_rect_handle: GpuCacheHandle,
|
||||
|
@ -384,7 +384,7 @@ impl RenderTask {
|
|||
pub fn new_picture(
|
||||
location: RenderTaskLocation,
|
||||
unclipped_size: DeviceSize,
|
||||
prim_index: PrimitiveIndex,
|
||||
pic_index: PictureIndex,
|
||||
content_origin: DeviceIntPoint,
|
||||
children: Vec<RenderTaskId>,
|
||||
uv_rect_kind: UvRectKind,
|
||||
|
@ -405,7 +405,7 @@ impl RenderTask {
|
|||
location,
|
||||
children,
|
||||
kind: RenderTaskKind::Picture(PictureTask {
|
||||
prim_index,
|
||||
pic_index,
|
||||
content_origin,
|
||||
can_merge,
|
||||
uv_rect_handle: GpuCacheHandle::new(),
|
||||
|
@ -992,7 +992,7 @@ impl RenderTask {
|
|||
pub fn print_with<T: PrintTreePrinter>(&self, pt: &mut T, tree: &RenderTaskTree) -> bool {
|
||||
match self.kind {
|
||||
RenderTaskKind::Picture(ref task) => {
|
||||
pt.new_level(format!("Picture of {:?}", task.prim_index));
|
||||
pt.new_level(format!("Picture of {:?}", task.pic_index));
|
||||
}
|
||||
RenderTaskKind::CacheMask(ref task) => {
|
||||
pt.new_level(format!("CacheMask with {} clips", task.clip_node_range.count));
|
||||
|
|
|
@ -407,7 +407,7 @@ impl RenderTarget for ColorRenderTarget {
|
|||
|
||||
match task.kind {
|
||||
RenderTaskKind::Picture(ref pic_task) => {
|
||||
let pic = ctx.prim_store.get_pic(pic_task.prim_index);
|
||||
let pic = &ctx.prim_store.pictures[pic_task.pic_index.0];
|
||||
|
||||
let (target_rect, _) = task.get_target_rect();
|
||||
|
||||
|
@ -472,7 +472,7 @@ impl RenderTarget for ColorRenderTarget {
|
|||
);
|
||||
}
|
||||
RenderTaskKind::Picture(ref task_info) => {
|
||||
let pic = ctx.prim_store.get_pic(task_info.prim_index);
|
||||
let pic = &ctx.prim_store.pictures[task_info.pic_index.0];
|
||||
self.alpha_tasks.push(task_id);
|
||||
|
||||
// If this pipeline is registered as a frame output
|
||||
|
|
|
@ -1 +1 @@
|
|||
c72754d72ddd0e9e198bb1edefe13f77d9a38f07
|
||||
15656cb497303703b4d541d3e14292259e4c5343
|
||||
|
|
Загрузка…
Ссылка в новой задаче