Bug 1552984 - Refactor parts of the WR batching and flattening code, to support future picture caching improvements. r=kvark

This patch contains two isolated changes related to upcoming picture
caching improvements. Specifically:

 * Determine the blit reason for stacking contexts with clips
   earlier, during scene building. This simplifies the code and
   allows better detection of redundant stacking contexts.
 * Centralize the code for pushing batch instances into a small
   number of places. This will simplify the switch to adding
   a single primitive to multiple batch lists, in the case of
   dirty regions with different batchers.

Differential Revision: https://phabricator.services.mozilla.com/D31898

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Glenn Watson 2019-05-22 14:57:10 +00:00
Родитель 2e337923ae
Коммит 0f8cee5dd5
8 изменённых файлов: 319 добавлений и 388 удалений

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

@ -467,6 +467,7 @@ pub struct AlphaBatchBuilder {
screen_size: DeviceIntSize,
break_advanced_blend_batches: bool,
render_task_id: RenderTaskId,
render_task_address: RenderTaskAddress,
}
impl AlphaBatchBuilder {
@ -474,6 +475,7 @@ impl AlphaBatchBuilder {
screen_size: DeviceIntSize,
break_advanced_blend_batches: bool,
render_task_id: RenderTaskId,
render_task_address: RenderTaskAddress,
) -> Self {
let batch_lists = vec![
BatchList::new(
@ -489,6 +491,7 @@ impl AlphaBatchBuilder {
screen_size,
break_advanced_blend_batches,
render_task_id,
render_task_address,
}
}
@ -546,26 +549,97 @@ impl AlphaBatchBuilder {
/// Supports (recursively) adding a list of primitives and pictures to an alpha batch
/// builder. In future, it will support multiple dirty regions / slices, allowing the
/// contents of a picture to be spliced into multiple batch builders.
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BatchBuilder {
/// A temporary buffer that is used during glyph fetching, stored here
/// to reduce memory allocations.
glyph_fetch_buffer: Vec<GlyphFetchResult>,
/// The batchers that primitives will be added to as the
/// picture tree is traversed.
batcher: AlphaBatchBuilder,
}
impl BatchBuilder {
pub fn new() -> Self {
pub fn new(
batcher: AlphaBatchBuilder,
) -> Self {
BatchBuilder {
glyph_fetch_buffer: Vec::new(),
batcher,
}
}
pub fn finalize(self) -> AlphaBatchBuilder {
self.batcher
}
fn add_brush_instance_to_batches(
&mut self,
batch_key: BatchKey,
bounding_rect: &PictureRect,
z_id: ZBufferId,
segment_index: i32,
edge_flags: EdgeAaSegmentMask,
clip_task_address: RenderTaskAddress,
brush_flags: BrushFlags,
prim_header_index: PrimitiveHeaderIndex,
user_data: i32,
) {
// TODO(gw): In future, this will be a loop adding the primitive
// to multiple batch list(s), depending on the primitive
// visibility mask.
let render_task_address = self.batcher.render_task_address;
let instance = BrushInstance {
segment_index,
edge_flags,
clip_task_address,
render_task_address,
brush_flags,
prim_header_index,
user_data,
};
self.batcher.current_batch_list().push_single_instance(
batch_key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
);
}
fn add_split_composite_instance_to_batches(
&mut self,
batch_key: BatchKey,
bounding_rect: &PictureRect,
z_id: ZBufferId,
prim_header_index: PrimitiveHeaderIndex,
polygons_address: GpuCacheAddress,
) {
// TODO(gw): In future, this will be a loop adding the primitive
// to multiple batch list(s), depending on the primitive
// visibility mask.
let render_task_address = self.batcher.render_task_address;
self.batcher.current_batch_list().push_single_instance(
batch_key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(SplitCompositeInstance {
prim_header_index,
render_task_address,
polygons_address,
z: z_id,
}),
);
}
/// Add a picture to a given batch builder.
pub fn add_pic_to_batch(
&mut self,
pic: &PicturePrimitive,
batcher: &mut AlphaBatchBuilder,
ctx: &RenderTargetContext,
gpu_cache: &mut GpuCache,
render_tasks: &RenderTaskGraph,
@ -579,7 +653,6 @@ impl BatchBuilder {
for prim_instance in &pic.prim_list.prim_instances {
self.add_prim_to_batch(
prim_instance,
batcher,
ctx,
gpu_cache,
render_tasks,
@ -599,7 +672,6 @@ impl BatchBuilder {
fn add_prim_to_batch(
&mut self,
prim_instance: &PrimitiveInstance,
batcher: &mut AlphaBatchBuilder,
ctx: &RenderTargetContext,
gpu_cache: &mut GpuCache,
render_tasks: &RenderTaskGraph,
@ -641,7 +713,6 @@ impl BatchBuilder {
);
let snap_offsets = prim_info.snap_offsets;
let render_task_address = render_tasks.get_task_address(batcher.render_task_id);
if is_chased {
println!("\tbatch {:?} with bound {:?}", prim_rect, bounding_rect);
@ -681,21 +752,16 @@ impl BatchBuilder {
render_tasks,
).unwrap_or(OPAQUE_TASK_ADDRESS);
let instance = PrimitiveInstanceData::from(BrushInstance {
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::all(),
clip_task_address,
render_task_address,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
user_data: 0,
});
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
batch_key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::all(),
clip_task_address,
BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
0,
);
}
PrimitiveInstanceKind::NormalBorder { data_handle, ref cache_handles, .. } => {
@ -758,7 +824,6 @@ impl BatchBuilder {
let border_data = &prim_data.kind;
self.add_segmented_prim_to_batch(
batcher,
Some(border_data.brush_segments.as_slice()),
common_data.opacity,
&batch_params,
@ -769,7 +834,6 @@ impl BatchBuilder {
transform_kind,
render_tasks,
z_id,
render_task_address,
prim_info.clip_task_index,
ctx,
);
@ -781,7 +845,6 @@ impl BatchBuilder {
// The GPU cache data is stored in the template and reused across
// frames and display lists.
let prim_data = &ctx.data_stores.text_run[data_handle];
let alpha_batch_list = &mut batcher.batch_lists.last_mut().unwrap().alpha_batch_list;
let prim_cache_address = gpu_cache.get_address(&prim_data.gpu_cache_handle);
let prim_header = PrimitiveHeader {
@ -798,6 +861,28 @@ impl BatchBuilder {
).unwrap_or(OPAQUE_TASK_ADDRESS);
let glyph_keys = &ctx.scratch.glyph_keys[run.glyph_keys_range];
let rasterization_space = match run.raster_space {
RasterSpace::Screen => RasterizationSpace::Screen,
RasterSpace::Local(..) => RasterizationSpace::Local,
};
let raster_scale = run.raster_space.local_scale().unwrap_or(1.0).max(0.001);
let prim_header_index = prim_headers.push(
&prim_header,
z_id,
[
(run.reference_frame_relative_offset.x * 256.0) as i32,
(run.reference_frame_relative_offset.y * 256.0) as i32,
(raster_scale * 65535.0).round() as i32,
clip_task_address.0 as i32,
],
);
let base_instance = GlyphInstance::new(
prim_header_index,
);
let alpha_batch_list = &mut self.batcher.batch_lists.last_mut().unwrap().alpha_batch_list;
let render_task_address = render_tasks.get_task_address(
self.batcher.render_task_id,
);
ctx.resource_cache.fetch_glyphs(
run.used_font.clone(),
@ -865,31 +950,13 @@ impl BatchBuilder {
}
};
let raster_scale = run.raster_space.local_scale().unwrap_or(1.0).max(0.001);
let prim_header_index = prim_headers.push(
&prim_header,
z_id,
[
(run.reference_frame_relative_offset.x * 256.0) as i32,
(run.reference_frame_relative_offset.y * 256.0) as i32,
(raster_scale * 65535.0).round() as i32,
clip_task_address.0 as i32,
],
);
let key = BatchKey::new(kind, blend_mode, textures);
let base_instance = GlyphInstance::new(
prim_header_index,
);
let batch = alpha_batch_list.set_params_and_get_batch(
key,
bounding_rect,
z_id,
);
let rasterization_space = match run.raster_space {
RasterSpace::Screen => RasterizationSpace::Screen,
RasterSpace::Local(..) => RasterizationSpace::Local,
};
for glyph in glyphs {
batch.push(base_instance.build(
glyph.index_in_text_run | ((render_task_address.0 as i32) << 16),
@ -976,21 +1043,16 @@ impl BatchBuilder {
render_tasks,
).unwrap_or(OPAQUE_TASK_ADDRESS);
let instance = PrimitiveInstanceData::from(BrushInstance {
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::all(),
clip_task_address,
render_task_address,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
user_data: segment_user_data,
});
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
batch_key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::all(),
clip_task_address,
BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
segment_user_data,
);
}
PrimitiveInstanceKind::Picture { pic_index, segment_instance_index, .. } => {
@ -1074,18 +1136,12 @@ impl BatchBuilder {
BatchTextures::no_texture(),
);
let instance = SplitCompositeInstance::new(
prim_header_index,
child.gpu_address,
render_task_address,
z_id,
);
batcher.current_batch_list().push_single_instance(
self.add_split_composite_instance_to_batches(
key,
&prim_info.clip_chain.pic_clip_rect,
z_id,
PrimitiveInstanceData::from(instance),
prim_header_index,
child.gpu_address,
);
}
}
@ -1126,7 +1182,6 @@ impl BatchBuilder {
if !tile_cache.is_enabled {
self.add_pic_to_batch(
picture,
batcher,
ctx,
gpu_cache,
render_tasks,
@ -1199,27 +1254,17 @@ impl BatchBuilder {
.get_address(&cache_item.uv_rect_handle)
.as_int();
let instance = BrushInstance {
prim_header_index,
clip_task_address,
render_task_address,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags,
user_data: uv_rect_address,
};
// Instead of retrieving the batch once and adding each tile instance,
// use this API to get an appropriate batch for each tile, since
// the batch textures may be different. The batch list internally
// caches the current batch if the key hasn't changed.
let batch = batcher.current_batch_list().set_params_and_get_batch(
self.add_brush_instance_to_batches(
key,
bounding_rect,
z_id,
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
clip_task_address,
brush_flags,
prim_header_index,
uv_rect_address,
);
batch.push(PrimitiveInstanceData::from(instance));
}
// If there is a dirty rect for the tile cache, recurse into the
@ -1227,7 +1272,7 @@ impl BatchBuilder {
if !tile_cache.dirty_region.is_empty() {
let mut tile_blits = Vec::new();
let (target_rect, _) = render_tasks[batcher.render_task_id]
let (target_rect, _) = render_tasks[self.batcher.render_task_id]
.get_target_rect();
for blit in &tile_cache.pending_blits {
@ -1253,14 +1298,13 @@ impl BatchBuilder {
})
.collect();
batcher.push_new_batch_list(
self.batcher.push_new_batch_list(
batch_regions,
tile_blits,
);
self.add_pic_to_batch(
picture,
batcher,
ctx,
gpu_cache,
render_tasks,
@ -1271,7 +1315,7 @@ impl BatchBuilder {
z_generator,
);
batcher.push_new_batch_list(
self.batcher.push_new_batch_list(
Vec::new(),
Vec::new(),
);
@ -1301,21 +1345,16 @@ impl BatchBuilder {
0,
]);
let instance = BrushInstance {
prim_header_index,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags,
render_task_address,
clip_task_address,
user_data: uv_rect_address.as_int(),
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
clip_task_address,
brush_flags,
prim_header_index,
uv_rect_address.as_int(),
);
}
Filter::DropShadows(shadows) => {
@ -1376,21 +1415,16 @@ impl BatchBuilder {
0,
]);
let shadow_instance = BrushInstance {
prim_header_index: shadow_prim_header_index,
clip_task_address,
render_task_address,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags,
user_data: shadow_uv_rect_address,
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
shadow_key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(shadow_instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
clip_task_address,
brush_flags,
shadow_prim_header_index,
shadow_uv_rect_address,
);
}
let z_id_content = z_generator.next();
@ -1402,21 +1436,16 @@ impl BatchBuilder {
0,
]);
let content_instance = BrushInstance {
prim_header_index: content_prim_header_index,
clip_task_address,
render_task_address,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags,
user_data: content_uv_rect_address,
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
content_key,
bounding_rect,
z_id_content,
PrimitiveInstanceData::from(content_instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
clip_task_address,
brush_flags,
content_prim_header_index,
content_uv_rect_address,
);
}
_ => {
@ -1482,21 +1511,16 @@ impl BatchBuilder {
0,
]);
let instance = BrushInstance {
prim_header_index,
clip_task_address,
render_task_address,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags,
user_data: 0,
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
clip_task_address,
brush_flags,
prim_header_index,
0,
);
}
}
@ -1532,21 +1556,16 @@ impl BatchBuilder {
0,
]);
let instance = BrushInstance {
prim_header_index,
clip_task_address,
render_task_address,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags,
user_data: 0,
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
clip_task_address,
brush_flags,
prim_header_index,
0,
);
}
PictureCompositeMode::MixBlend(mode) if ctx.use_advanced_blending => {
@ -1568,21 +1587,16 @@ impl BatchBuilder {
0,
]);
let instance = BrushInstance {
prim_header_index,
clip_task_address,
render_task_address,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags,
user_data: uv_rect_address.as_int(),
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
clip_task_address,
brush_flags,
prim_header_index,
uv_rect_address.as_int(),
);
}
PictureCompositeMode::MixBlend(mode) => {
@ -1592,7 +1606,7 @@ impl BatchBuilder {
let key = BatchKey::new(
BatchKind::Brush(
BrushBatchKind::MixBlend {
task_id: batcher.render_task_id,
task_id: self.batcher.render_task_id,
source_id: cache_task_id,
backdrop_id,
},
@ -1609,21 +1623,16 @@ impl BatchBuilder {
0,
]);
let instance = BrushInstance {
prim_header_index,
clip_task_address,
render_task_address,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::empty(),
brush_flags,
user_data: 0,
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::empty(),
clip_task_address,
brush_flags,
prim_header_index,
0,
);
}
PictureCompositeMode::Blit(_) => {
@ -1679,7 +1688,6 @@ impl BatchBuilder {
let specified_blend_mode = BlendMode::PremultipliedAlpha;
self.add_segmented_prim_to_batch(
batcher,
segments,
opacity,
&batch_params,
@ -1690,7 +1698,6 @@ impl BatchBuilder {
transform_kind,
render_tasks,
z_id,
render_task_address,
prim_info.clip_task_index,
ctx,
);
@ -1702,7 +1709,6 @@ impl BatchBuilder {
// no composition operation), recurse and add to the current batch list.
self.add_pic_to_batch(
picture,
batcher,
ctx,
gpu_cache,
render_tasks,
@ -1769,7 +1775,6 @@ impl BatchBuilder {
);
self.add_segmented_prim_to_batch(
batcher,
Some(border_data.brush_segments.as_slice()),
common_data.opacity,
&batch_params,
@ -1780,7 +1785,6 @@ impl BatchBuilder {
transform_kind,
render_tasks,
z_id,
render_task_address,
prim_info.clip_task_index,
ctx,
);
@ -1832,7 +1836,6 @@ impl BatchBuilder {
);
self.add_segmented_prim_to_batch(
batcher,
segments,
opacity,
&batch_params,
@ -1843,7 +1846,6 @@ impl BatchBuilder {
transform_kind,
render_tasks,
z_id,
render_task_address,
prim_info.clip_task_index,
ctx,
);
@ -1941,7 +1943,6 @@ impl BatchBuilder {
);
self.add_segmented_prim_to_batch(
batcher,
segments,
prim_common_data.opacity,
&batch_params,
@ -1952,7 +1953,6 @@ impl BatchBuilder {
transform_kind,
render_tasks,
z_id,
render_task_address,
prim_info.clip_task_index,
ctx,
);
@ -2047,7 +2047,6 @@ impl BatchBuilder {
);
self.add_segmented_prim_to_batch(
batcher,
segments,
opacity,
&batch_params,
@ -2058,7 +2057,6 @@ impl BatchBuilder {
transform_kind,
render_tasks,
z_id,
render_task_address,
prim_info.clip_task_index,
ctx,
);
@ -2102,25 +2100,21 @@ impl BatchBuilder {
deferred_resolves,
request.with_tile(tile.tile_offset),
) {
let base_instance = BrushInstance {
prim_header_index,
clip_task_address,
render_task_address,
segment_index: i as i32,
edge_flags: tile.edge_flags,
brush_flags: BrushFlags::SEGMENT_RELATIVE | BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data: uv_rect_address.as_int(),
};
let batch_key = BatchKey {
blend_mode: specified_blend_mode,
kind: BatchKind::Brush(batch_kind),
textures,
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
batch_key,
bounding_rect,
z_id,
base_instance.into(),
i as i32,
tile.edge_flags,
clip_task_address,
BrushFlags::SEGMENT_RELATIVE | BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
uv_rect_address.as_int(),
);
}
}
@ -2187,21 +2181,16 @@ impl BatchBuilder {
render_tasks,
).unwrap_or(OPAQUE_TASK_ADDRESS);
let instance = PrimitiveInstanceData::from(BrushInstance {
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::all(),
clip_task_address,
render_task_address,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
user_data: segment_user_data,
});
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
batch_key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::all(),
clip_task_address,
BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
segment_user_data,
);
} else if gradient.visible_tiles_range.is_empty() {
let batch_params = BrushBatchParameters::shared(
@ -2231,7 +2220,6 @@ impl BatchBuilder {
};
self.add_segmented_prim_to_batch(
batcher,
segments,
prim_data.opacity,
&batch_params,
@ -2242,7 +2230,6 @@ impl BatchBuilder {
transform_kind,
render_tasks,
z_id,
render_task_address,
prim_info.clip_task_index,
ctx,
);
@ -2254,16 +2241,14 @@ impl BatchBuilder {
render_tasks,
).unwrap_or(OPAQUE_TASK_ADDRESS);
add_gradient_tiles(
self.add_gradient_tiles(
visible_tiles,
&prim_data.stops_handle,
BrushBatchKind::LinearGradient,
specified_blend_mode,
bounding_rect,
render_task_address,
clip_task_address,
gpu_cache,
batcher.current_batch_list(),
&prim_header,
prim_headers,
z_id,
@ -2319,7 +2304,6 @@ impl BatchBuilder {
};
self.add_segmented_prim_to_batch(
batcher,
segments,
prim_data.opacity,
&batch_params,
@ -2330,7 +2314,6 @@ impl BatchBuilder {
transform_kind,
render_tasks,
z_id,
render_task_address,
prim_info.clip_task_index,
ctx,
);
@ -2342,16 +2325,14 @@ impl BatchBuilder {
render_tasks,
).unwrap_or(OPAQUE_TASK_ADDRESS);
add_gradient_tiles(
self.add_gradient_tiles(
visible_tiles,
&prim_data.stops_handle,
BrushBatchKind::RadialGradient,
specified_blend_mode,
bounding_rect,
render_task_address,
clip_task_address,
gpu_cache,
batcher.current_batch_list(),
&prim_header,
prim_headers,
z_id,
@ -2364,7 +2345,6 @@ impl BatchBuilder {
/// Add a single segment instance to a batch.
fn add_segment_to_batch(
&mut self,
batcher: &mut AlphaBatchBuilder,
segment: &BrushSegment,
segment_data: &SegmentInstanceData,
segment_index: i32,
@ -2376,7 +2356,6 @@ impl BatchBuilder {
render_tasks: &RenderTaskGraph,
z_id: ZBufferId,
prim_opacity: PrimitiveOpacity,
render_task_address: RenderTaskAddress,
clip_task_index: ClipTaskIndex,
ctx: &RenderTargetContext,
) {
@ -2399,34 +2378,28 @@ impl BatchBuilder {
clip_task_address != OPAQUE_TASK_ADDRESS ||
(!is_inner && transform_kind == TransformedRectKind::Complex);
let instance = PrimitiveInstanceData::from(BrushInstance {
segment_index,
edge_flags: segment.edge_flags,
clip_task_address,
render_task_address,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION | segment.brush_flags,
prim_header_index,
user_data: segment_data.user_data,
});
let batch_key = BatchKey {
blend_mode: if needs_blending { alpha_blend_mode } else { BlendMode::None },
kind: BatchKind::Brush(batch_kind),
textures: segment_data.textures,
};
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
batch_key,
bounding_rect,
z_id,
instance,
segment_index,
segment.edge_flags,
clip_task_address,
BrushFlags::PERSPECTIVE_INTERPOLATION | segment.brush_flags,
prim_header_index,
segment_data.user_data,
);
}
/// Add any segment(s) from a brush to batches.
fn add_segmented_prim_to_batch(
&mut self,
batcher: &mut AlphaBatchBuilder,
brush_segments: Option<&[BrushSegment]>,
prim_opacity: PrimitiveOpacity,
params: &BrushBatchParameters,
@ -2437,7 +2410,6 @@ impl BatchBuilder {
transform_kind: TransformedRectKind,
render_tasks: &RenderTaskGraph,
z_id: ZBufferId,
render_task_address: RenderTaskAddress,
clip_task_index: ClipTaskIndex,
ctx: &RenderTargetContext,
) {
@ -2452,7 +2424,6 @@ impl BatchBuilder {
.enumerate()
{
self.add_segment_to_batch(
batcher,
segment,
segment_data,
segment_index as i32,
@ -2464,7 +2435,6 @@ impl BatchBuilder {
render_tasks,
z_id,
prim_opacity,
render_task_address,
clip_task_index,
ctx,
);
@ -2478,7 +2448,6 @@ impl BatchBuilder {
.enumerate()
{
self.add_segment_to_batch(
batcher,
segment,
segment_data,
segment_index as i32,
@ -2490,7 +2459,6 @@ impl BatchBuilder {
render_tasks,
z_id,
prim_opacity,
render_task_address,
clip_task_index,
ctx,
);
@ -2508,20 +2476,16 @@ impl BatchBuilder {
clip_task_index,
render_tasks,
).unwrap_or(OPAQUE_TASK_ADDRESS);
let instance = PrimitiveInstanceData::from(BrushInstance {
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::all(),
clip_task_address,
render_task_address,
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
user_data: segment_data.user_data,
});
batcher.current_batch_list().push_single_instance(
self.add_brush_instance_to_batches(
batch_key,
bounding_rect,
z_id,
PrimitiveInstanceData::from(instance),
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::all(),
clip_task_address,
BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
segment_data.user_data,
);
}
(None, SegmentDataKind::Instanced(..)) => {
@ -2531,62 +2495,57 @@ impl BatchBuilder {
}
}
}
}
fn add_gradient_tiles(
visible_tiles: &[VisibleGradientTile],
stops_handle: &GpuCacheHandle,
kind: BrushBatchKind,
blend_mode: BlendMode,
bounding_rect: &PictureRect,
render_task_address: RenderTaskAddress,
clip_task_address: RenderTaskAddress,
gpu_cache: &GpuCache,
batch_list: &mut BatchList,
base_prim_header: &PrimitiveHeader,
prim_headers: &mut PrimitiveHeaders,
z_id: ZBufferId,
) {
let batch = batch_list.set_params_and_get_batch(
BatchKey {
fn add_gradient_tiles(
&mut self,
visible_tiles: &[VisibleGradientTile],
stops_handle: &GpuCacheHandle,
kind: BrushBatchKind,
blend_mode: BlendMode,
bounding_rect: &PictureRect,
clip_task_address: RenderTaskAddress,
gpu_cache: &GpuCache,
base_prim_header: &PrimitiveHeader,
prim_headers: &mut PrimitiveHeaders,
z_id: ZBufferId,
) {
let key = BatchKey {
blend_mode: blend_mode,
kind: BatchKind::Brush(kind),
textures: BatchTextures::no_texture(),
},
bounding_rect,
z_id,
);
let user_data = [stops_handle.as_int(gpu_cache), 0, 0, 0];
for tile in visible_tiles {
// Adjust the snap offsets for the tile.
let snap_offsets = recompute_snap_offsets(
tile.local_rect,
base_prim_header.local_rect,
base_prim_header.snap_offsets,
);
let prim_header = PrimitiveHeader {
specific_prim_address: gpu_cache.get_address(&tile.handle),
local_rect: tile.local_rect,
local_clip_rect: tile.local_clip_rect,
snap_offsets,
..*base_prim_header
};
let prim_header_index = prim_headers.push(&prim_header, z_id, user_data);
batch.push(PrimitiveInstanceData::from(
BrushInstance {
prim_header_index,
let user_data = [stops_handle.as_int(gpu_cache), 0, 0, 0];
for tile in visible_tiles {
// Adjust the snap offsets for the tile.
let snap_offsets = recompute_snap_offsets(
tile.local_rect,
base_prim_header.local_rect,
base_prim_header.snap_offsets,
);
let prim_header = PrimitiveHeader {
specific_prim_address: gpu_cache.get_address(&tile.handle),
local_rect: tile.local_rect,
local_clip_rect: tile.local_clip_rect,
snap_offsets,
..*base_prim_header
};
let prim_header_index = prim_headers.push(&prim_header, z_id, user_data);
self.add_brush_instance_to_batches(
key,
bounding_rect,
z_id,
INVALID_SEGMENT_INDEX,
EdgeAaSegmentMask::all(),
clip_task_address,
render_task_address,
segment_index: INVALID_SEGMENT_INDEX,
edge_flags: EdgeAaSegmentMask::all(),
brush_flags: BrushFlags::PERSPECTIVE_INTERPOLATION,
user_data: 0,
}
));
BrushFlags::PERSPECTIVE_INTERPOLATION,
prim_header_index,
0,
);
}
}
}

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

@ -209,6 +209,7 @@ pub struct ClipChainNode {
pub local_pos: LayoutPoint,
pub spatial_node_index: SpatialNodeIndex,
pub parent_clip_chain_id: ClipChainId,
pub has_complex_clip: bool,
}
// When a clip node is found to be valid for a
@ -563,6 +564,7 @@ impl ClipStore {
local_pos: LayoutPoint,
spatial_node_index: SpatialNodeIndex,
parent_clip_chain_id: ClipChainId,
has_complex_clip: bool,
) -> ClipChainId {
let id = ClipChainId(self.clip_chain_nodes.len() as u32);
self.clip_chain_nodes.push(ClipChainNode {
@ -570,6 +572,7 @@ impl ClipStore {
spatial_node_index,
local_pos,
parent_clip_chain_id,
has_complex_clip,
});
id
}
@ -867,6 +870,17 @@ impl ClipItemKey {
clip_mode,
)
}
pub fn has_complex_clip(&self) -> bool {
match *self {
ClipItemKey::Rectangle(_, ClipMode::Clip) => false,
ClipItemKey::Rectangle(_, ClipMode::ClipOut) |
ClipItemKey::RoundedRectangle(..) |
ClipItemKey::ImageMask(..) |
ClipItemKey::BoxShadow(..) => true,
}
}
}
impl intern::InternDebug for ClipItemKey {}

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

@ -1220,14 +1220,19 @@ impl<'a> DisplayListFlattener<'a> {
for _ in 0 .. item_clip_node.count {
// Get the id of the clip sources entry for that clip chain node.
let (handle, spatial_node_index, local_pos) = {
let (handle, spatial_node_index, local_pos, has_complex_clip) = {
let clip_chain = self
.clip_store
.get_clip_chain(clip_node_clip_chain_id);
clip_node_clip_chain_id = clip_chain.parent_clip_chain_id;
(clip_chain.handle, clip_chain.spatial_node_index, clip_chain.local_pos)
(
clip_chain.handle,
clip_chain.spatial_node_index,
clip_chain.local_pos,
clip_chain.has_complex_clip,
)
};
// Add a new clip chain node, which references the same clip sources, and
@ -1239,6 +1244,7 @@ impl<'a> DisplayListFlattener<'a> {
local_pos,
spatial_node_index,
clip_chain_id,
has_complex_clip,
);
}
}
@ -1308,6 +1314,7 @@ impl<'a> DisplayListFlattener<'a> {
for (local_pos, item) in clip_items {
// Intern this clip item, and store the handle
// in the clip chain node.
let has_complex_clip = item.has_complex_clip();
let handle = self.interners
.clip
.intern(&item, || ());
@ -1317,6 +1324,7 @@ impl<'a> DisplayListFlattener<'a> {
local_pos,
spatial_node_index,
clip_chain_id,
has_complex_clip,
);
}
@ -1585,15 +1593,27 @@ impl<'a> DisplayListFlattener<'a> {
Picture3DContext::Out
};
// Force an intermediate surface if the stacking context
// has a clip node. In the future, we may decide during
// Force an intermediate surface if the stacking context has a
// complex clip node. In the future, we may decide during
// prepare step to skip the intermediate surface if the
// clip node doesn't affect the stacking context rect.
let blit_reason = if clip_chain_id == ClipChainId::NONE {
BlitReason::empty()
} else {
BlitReason::CLIP
};
let mut blit_reason = BlitReason::empty();
let mut current_clip_chain_id = clip_chain_id;
// Walk each clip in this chain, to see whether any of the clips
// require that we draw this to an intermediate surface.
while current_clip_chain_id != ClipChainId::NONE {
let clip_chain_node = &self
.clip_store
.clip_chain_nodes[current_clip_chain_id.0 as usize];
if clip_chain_node.has_complex_clip {
blit_reason = BlitReason::CLIP;
break;
}
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
}
// Push the SC onto the stack, so we know how to handle things in
// pop_stacking_context.
@ -2021,6 +2041,7 @@ impl<'a> DisplayListFlattener<'a> {
clip_region.main.origin,
spatial_node,
parent_clip_chain_index,
false,
);
clip_count += 1;
@ -2037,6 +2058,7 @@ impl<'a> DisplayListFlattener<'a> {
image_mask.rect.origin,
spatial_node,
parent_clip_chain_index,
true,
);
clip_count += 1;
}
@ -2054,6 +2076,7 @@ impl<'a> DisplayListFlattener<'a> {
region.rect.origin,
spatial_node,
parent_clip_chain_index,
true,
);
clip_count += 1;
}

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

@ -321,22 +321,6 @@ pub struct SplitCompositeInstance {
pub render_task_address: RenderTaskAddress,
}
impl SplitCompositeInstance {
pub fn new(
prim_header_index: PrimitiveHeaderIndex,
polygons_address: GpuCacheAddress,
render_task_address: RenderTaskAddress,
z: ZBufferId,
) -> Self {
SplitCompositeInstance {
prim_header_index,
polygons_address,
z,
render_task_address,
}
}
}
impl From<SplitCompositeInstance> for PrimitiveInstanceData {
fn from(instance: SplitCompositeInstance) -> Self {
PrimitiveInstanceData {

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

@ -1645,7 +1645,6 @@ impl<'a> PictureUpdateState<'a> {
state.update(
pic_index,
ClipChainId::NONE,
picture_primitives,
frame_context,
gpu_cache,
@ -1709,7 +1708,6 @@ impl<'a> PictureUpdateState<'a> {
fn update(
&mut self,
pic_index: PictureIndex,
clip_chain_id: ClipChainId,
picture_primitives: &mut [PicturePrimitive],
frame_context: &FrameBuildingContext,
gpu_cache: &mut GpuCache,
@ -1717,16 +1715,12 @@ impl<'a> PictureUpdateState<'a> {
clip_data_store: &ClipDataStore,
) {
if let Some(prim_list) = picture_primitives[pic_index.0].pre_update(
clip_chain_id,
self,
frame_context,
clip_store,
clip_data_store,
) {
for (child_pic_index, clip_chain_id) in &prim_list.pictures {
for child_pic_index in &prim_list.pictures {
self.update(
*child_pic_index,
*clip_chain_id,
picture_primitives,
frame_context,
gpu_cache,
@ -1768,7 +1762,7 @@ impl<'a> PictureUpdateState<'a> {
None => fallback_raster_spatial_node,
};
for (child_pic_index, _) in &picture.prim_list.pictures {
for child_pic_index in &picture.prim_list.pictures {
self.assign_raster_roots(*child_pic_index, picture_primitives, new_fallback);
}
}
@ -1995,7 +1989,7 @@ impl ClusterIndex {
/// A list of pictures, stored by the PrimitiveList to enable a
/// fast traversal of just the pictures.
pub type PictureList = SmallVec<[(PictureIndex, ClipChainId); 4]>;
pub type PictureList = SmallVec<[PictureIndex; 4]>;
/// A list of primitive instances that are added to a picture
/// This ensures we can keep a list of primitives that
@ -2044,7 +2038,7 @@ impl PrimitiveList {
// remove this match and embed this info directly in the primitive instance.
let is_pic = match prim_instance.kind {
PrimitiveInstanceKind::Picture { pic_index, .. } => {
pictures.push((pic_index, prim_instance.clip_chain_id));
pictures.push(pic_index);
true
}
_ => {
@ -2238,7 +2232,7 @@ impl PicturePrimitive {
pt.add_item(format!("raster_config: {:?}", self.raster_config));
pt.add_item(format!("requested_composite_mode: {:?}", self.requested_composite_mode));
for (index, _) in &self.prim_list.pictures {
for index in &self.prim_list.pictures {
pictures[index.0].print(pictures, *index, pt);
}
@ -2905,11 +2899,8 @@ impl PicturePrimitive {
/// surface / raster config now though.
fn pre_update(
&mut self,
clip_chain_id: ClipChainId,
state: &mut PictureUpdateState,
frame_context: &FrameBuildingContext,
clip_store: &ClipStore,
clip_data_store: &ClipDataStore,
) -> Option<PrimitiveList> {
// Reset raster config in case we early out below.
self.raster_config = None;
@ -2941,52 +2932,6 @@ impl PicturePrimitive {
// See if this picture actually needs a surface for compositing.
let actual_composite_mode = match self.requested_composite_mode {
Some(PictureCompositeMode::Filter(ref filter)) if filter.is_noop() => None,
Some(PictureCompositeMode::Blit(reason)) if reason == BlitReason::CLIP => {
// If the only reason a picture has requested a surface is due to the clip
// chain node, we might choose to skip drawing a surface, and instead apply
// the clips to each individual primitive. The logic below works out which
// option to choose.
// Assume that we will apply clips to individual items
let mut apply_clip_to_picture = false;
let mut current_clip_chain_id = clip_chain_id;
// Walk each clip in this chain, to see whether to allocate a surface and clip
// that, or whether to apply clips to each primitive.
while current_clip_chain_id != ClipChainId::NONE {
let clip_chain_node = &clip_store.clip_chain_nodes[current_clip_chain_id.0 as usize];
let clip_node = &clip_data_store[clip_chain_node.handle];
match clip_node.item {
ClipItem::Rectangle(_, ClipMode::Clip) => {
// Normal rectangle clips can be handled as per-item clips.
// TODO(gw): In future, we might want to consider selecting
// a surface in some situations here (e.g. if the
// stacking context is in a different coord system
// from the clip, and there are enough primitives
// in the stacking context to justify a surface).
}
ClipItem::Rectangle(_, ClipMode::ClipOut) |
ClipItem::RoundedRectangle(..) |
ClipItem::Image { .. } |
ClipItem::BoxShadow(..) => {
// Any of these clip types will require a surface.
apply_clip_to_picture = true;
break;
}
}
current_clip_chain_id = clip_chain_node.parent_clip_chain_id;
}
// If we decided not to use a surfce for clipping, then skip and draw straight
// into the parent surface.
if apply_clip_to_picture {
Some(PictureCompositeMode::Blit(reason))
} else {
None
}
}
ref mode => mode.clone(),
};

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

@ -374,10 +374,6 @@ pub struct ColorRenderTarget {
// we can set a scissor rect and only clear to the
// used portion of the target as an optimization.
pub used_rect: DeviceIntRect,
// This is used to build batches for this render target. In future,
// this will be used to support splitting a single picture primitive
// list into multiple batch sets.
batch_builder: BatchBuilder,
}
impl RenderTarget for ColorRenderTarget {
@ -396,7 +392,6 @@ impl RenderTarget for ColorRenderTarget {
alpha_tasks: Vec::new(),
screen_size,
used_rect: DeviceIntRect::zero(),
batch_builder: BatchBuilder::new(),
}
}
@ -436,15 +431,24 @@ impl RenderTarget for ColorRenderTarget {
Some(target_rect)
};
let mut alpha_batch_builder = AlphaBatchBuilder::new(
// TODO(gw): The type names of AlphaBatchBuilder and BatchBuilder
// are still confusing. Once more of the picture caching
// improvement code lands, the AlphaBatchBuilder and
// AlphaBatchList types will be collapsed into one, which
// should simplify coming up with better type names.
let alpha_batch_builder = AlphaBatchBuilder::new(
self.screen_size,
ctx.break_advanced_blend_batches,
*task_id,
render_tasks.get_task_address(*task_id),
);
self.batch_builder.add_pic_to_batch(
let mut batch_builder = BatchBuilder::new(
alpha_batch_builder,
);
batch_builder.add_pic_to_batch(
pic,
&mut alpha_batch_builder,
ctx,
gpu_cache,
render_tasks,
@ -455,6 +459,8 @@ impl RenderTarget for ColorRenderTarget {
z_generator,
);
let alpha_batch_builder = batch_builder.finalize();
alpha_batch_builder.build(
&mut self.alpha_batch_containers,
&mut merged_batches,

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

@ -1878,7 +1878,7 @@ fails-if(webrender) == 1059498-3.html 1059498-1-ref.html # WebRender: see bug 14
== 1069716-1.html 1069716-1-ref.html
== 1078262-1.html about:blank
test-pref(layout.testing.overlay-scrollbars.always-visible,false) == 1081072-1.html 1081072-1-ref.html
fuzzy-if(webrender,64-64,407-409) == 1081185-1.html 1081185-1-ref.html
fuzzy-if(webrender,64-64,407-486) == 1081185-1.html 1081185-1-ref.html
== 1097437-1.html 1097437-1-ref.html
== 1103258-1.html 1103258-1-ref.html # assertion crash test with layers culling test
== 1105137-1.html 1105137-1-ref.html

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

@ -47,8 +47,8 @@ fuzzy-if(d2d,0-1,0-24606) fuzzy-if(skiaContent,0-1,0-17000) == border-collapse-o
fuzzy-if(d2d,0-1,0-11000) fuzzy-if(skiaContent,0-1,0-11000) == border-collapse-opacity-table-row.html border-collapse-opacity-table-row-ref.html
fuzzy-if(d2d||skiaContent,0-1,0-60000) == border-collapse-opacity-table.html border-collapse-opacity-table-ref.html
fuzzy-if(d2d,0-1,0-2478) fuzzy-if(skiaContent,0-1,0-2500) == border-separate-opacity-table-cell.html border-separate-opacity-table-cell-ref.html
fuzzy-if(d2d,0-1,0-38000) == border-separate-opacity-table-column-group.html border-separate-opacity-table-column-group-ref.html
fuzzy-if(d2d,0-1,0-13000) == border-separate-opacity-table-column.html border-separate-opacity-table-column-ref.html
fuzzy-if(d2d,0-1,0-38000) fuzzy-if(webrender,0-1,0-4078) == border-separate-opacity-table-column-group.html border-separate-opacity-table-column-group-ref.html
fuzzy-if(d2d,0-1,0-13000) fuzzy-if(webrender,0-1,0-1329) == border-separate-opacity-table-column.html border-separate-opacity-table-column-ref.html
fuzzy-if(d2d,0-1,0-37170) fuzzy-if(skiaContent,0-1,0-38000) == border-separate-opacity-table-row-group.html border-separate-opacity-table-row-group-ref.html
fuzzy-if(d2d,0-1,0-12390) fuzzy-if(skiaContent,0-1,0-13000) == border-separate-opacity-table-row.html border-separate-opacity-table-row-ref.html
fuzzy-if(d2d||skiaContent,0-1,0-95000) == border-separate-opacity-table.html border-separate-opacity-table-ref.html