Bug 1536121 - cleanup display list code a little bit to prep for refactor. r=gw

* make all enums repr(u8) (compiler bug blocking this long fixed)
* add display list stats feature
* remove cache markers (abandoned design)
* don't always push empty SetFilters before PushStackingContext
* remove dead pub methods

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Alexis Beingessner 2019-04-23 02:32:48 +00:00
Родитель c29cf5f2aa
Коммит e16f06e3b9
10 изменённых файлов: 191 добавлений и 109 удалений

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

@ -14,6 +14,7 @@ profiler = ["thread_profiler/thread_profiler"]
debugger = ["ws", "serde_json", "serde", "image", "base64"]
capture = ["webrender_api/serialize", "ron", "serde", "smallvec/serde"]
replay = ["webrender_api/deserialize", "ron", "serde"]
display_list_stats = ["webrender_api/display_list_stats"]
pathfinder = ["pathfinder_font_renderer", "pathfinder_gfx_utils", "pathfinder_partitioner", "pathfinder_path_utils"]
serialize_program = ["serde", "webrender_build/serialize_program"]
no_static_freetype = []

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

@ -612,8 +612,8 @@ impl<'a> DisplayListFlattener<'a> {
};
match item.item() {
SpecificDisplayItem::PopReferenceFrame |
SpecificDisplayItem::PopStackingContext => return,
DisplayItem::PopReferenceFrame |
DisplayItem::PopStackingContext => return,
_ => (),
}
@ -626,10 +626,27 @@ impl<'a> DisplayListFlattener<'a> {
// If flatten_item created a sub-traversal, we need `traversal` to have the
// same state as the completed subtraversal, so we reinitialize it here.
if let Some(subtraversal) = subtraversal {
if let Some(mut subtraversal) = subtraversal {
subtraversal.merge_debug_stats_from(traversal);
*traversal = subtraversal;
}
}
// TODO: factor this out to be part of capture
if cfg!(feature = "display_list_stats") {
let stats = traversal.debug_stats();
let total_bytes: usize = stats.iter().map(|(_, stats)| stats.num_bytes).sum();
println!("item, total count, total bytes, % of DL bytes, bytes per item");
for (label, stats) in stats {
println!("{}, {}, {}kb, {}%, {}",
label,
stats.total_count,
stats.num_bytes / 1000,
((stats.num_bytes as f32 / total_bytes.max(1) as f32) * 100.0) as usize,
stats.num_bytes / stats.total_count.max(1));
}
println!("");
}
}
fn flatten_sticky_frame(
@ -1056,7 +1073,7 @@ impl<'a> DisplayListFlattener<'a> {
// refer to another user defined clip-chain. If none is specified,
// the parent is the root clip-chain for the given pipeline. This
// is used to provide a root clip chain for iframes.
let mut parent_clip_chain_id = match info.parent {
let parent_clip_chain_id = match info.parent {
Some(id) => {
self.id_to_index_mapper.get_clip_chain_id(ClipId::ClipChain(id))
}
@ -1151,10 +1168,6 @@ impl<'a> DisplayListFlattener<'a> {
SpecificDisplayItem::PopAllShadows => {
self.pop_all_shadows();
}
SpecificDisplayItem::PushCacheMarker(_marker) => {
}
SpecificDisplayItem::PopCacheMarker => {
}
}
None

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

@ -58,7 +58,7 @@ impl GlyphRasterizer {
// select glyphs that have not been requested yet.
for key in glyph_keys {
match glyph_key_cache.entry(key.clone()) {
Entry::Occupied(mut entry) => {
Entry::Occupied(entry) => {
let value = entry.into_mut();
match *value {
GlyphCacheEntry::Cached(ref glyph) => {

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

@ -1299,7 +1299,7 @@ impl RenderBackend {
frame_counter,
profile_counters,
false
);
);
}
self.resource_cache.after_frames();
@ -1528,7 +1528,7 @@ impl RenderBackend {
display_item @ SpecificDisplayItem::PushStackingContext(..) => {
let mut subtraversal = item.sub_iter();
let mut child_node =
debug_server::TreeNode::new(&display_item.debug_string());
debug_server::TreeNode::new(&display_item.debug_name().to_string());
self.traverse_items(&mut subtraversal, &mut child_node);
node.add_child(child_node);
Some(subtraversal)
@ -1537,7 +1537,7 @@ impl RenderBackend {
return;
}
display_item => {
node.add_item(&display_item.debug_string());
node.add_item(&display_item.debug_name().to_string());
None
}
}
@ -1633,46 +1633,6 @@ fn get_blob_image_updates(updates: &[ResourceUpdate]) -> Vec<BlobImageKey> {
requests
}
#[cfg(feature = "debugger")]
trait ToDebugString {
fn debug_string(&self) -> String;
}
#[cfg(feature = "debugger")]
impl ToDebugString for SpecificDisplayItem {
fn debug_string(&self) -> String {
match *self {
SpecificDisplayItem::Border(..) => String::from("border"),
SpecificDisplayItem::BoxShadow(..) => String::from("box_shadow"),
SpecificDisplayItem::ClearRectangle => String::from("clear_rectangle"),
SpecificDisplayItem::Clip(..) => String::from("clip"),
SpecificDisplayItem::ClipChain(..) => String::from("clip_chain"),
SpecificDisplayItem::Gradient(..) => String::from("gradient"),
SpecificDisplayItem::Iframe(..) => String::from("iframe"),
SpecificDisplayItem::Image(..) => String::from("image"),
SpecificDisplayItem::Line(..) => String::from("line"),
SpecificDisplayItem::PopAllShadows => String::from("pop_all_shadows"),
SpecificDisplayItem::PopReferenceFrame => String::from("pop_reference_frame"),
SpecificDisplayItem::PopStackingContext => String::from("pop_stacking_context"),
SpecificDisplayItem::PushShadow(..) => String::from("push_shadow"),
SpecificDisplayItem::PushReferenceFrame(..) => String::from("push_reference_frame"),
SpecificDisplayItem::PushStackingContext(..) => String::from("push_stacking_context"),
SpecificDisplayItem::SetFilterOps => String::from("set_filter_ops"),
SpecificDisplayItem::SetFilterData => String::from("set_filter_data"),
SpecificDisplayItem::RadialGradient(..) => String::from("radial_gradient"),
SpecificDisplayItem::Rectangle(..) => String::from("rectangle"),
SpecificDisplayItem::ScrollFrame(..) => String::from("scroll_frame"),
SpecificDisplayItem::SetGradientStops => String::from("set_gradient_stops"),
SpecificDisplayItem::StickyFrame(..) => String::from("sticky_frame"),
SpecificDisplayItem::Text(..) => String::from("text"),
SpecificDisplayItem::YuvImage(..) => String::from("yuv_image"),
SpecificDisplayItem::PushCacheMarker(..) => String::from("push_cache_marker"),
SpecificDisplayItem::PopCacheMarker => String::from("pop_cache_marker"),
}
}
}
impl RenderBackend {
#[cfg(feature = "capture")]
// Note: the mutable `self` is only needed here for resolving blob images

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

@ -2123,7 +2123,7 @@ impl Renderer {
21,
];
let mut texture = device.create_texture(
let texture = device.create_texture(
TextureTarget::Default,
ImageFormat::R8,
8,
@ -2477,7 +2477,7 @@ impl Renderer {
}
ResultMsg::PublishDocument(
document_id,
mut doc,
doc,
texture_update_list,
profile_counters,
) => {

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

@ -11,6 +11,7 @@ nightly = ["euclid/unstable", "serde/unstable"]
ipc = ["ipc-channel"]
serialize = []
deserialize = []
display_list_stats = []
[dependencies]
app_units = "0.7"

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

@ -100,7 +100,7 @@ impl SpaceAndClipInfo {
}
}
#[repr(u64)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum SpecificDisplayItem {
Clip(ClipDisplayItem),
@ -125,8 +125,6 @@ pub enum SpecificDisplayItem {
SetGradientStops,
PushShadow(Shadow),
PopAllShadows,
PushCacheMarker(CacheMarkerDisplayItem),
PopCacheMarker,
SetFilterOps,
SetFilterData,
}
@ -160,8 +158,6 @@ pub enum CompletelySpecificDisplayItem {
SetGradientStops(Vec<GradientStop>),
PushShadow(Shadow),
PopAllShadows,
PushCacheMarker(CacheMarkerDisplayItem),
PopCacheMarker,
SetFilterOps(Vec<FilterOp>),
SetFilterData(FilterData),
}
@ -337,7 +333,7 @@ impl NormalBorder {
}
}
#[repr(u32)]
#[repr(u8)]
#[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq, Serialize, Deserialize, Eq, Hash)]
pub enum RepeatMode {
Stretch,
@ -447,7 +443,7 @@ impl BorderStyle {
}
}
#[repr(u32)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum BoxShadowClipMode {
Outset = 0,
@ -529,12 +525,6 @@ pub struct ReferenceFrameDisplayListItem {
pub reference_frame: ReferenceFrame,
}
/// Provides a hint to WR that it should try to cache the items
/// within a cache marker context in an off-screen surface.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub struct CacheMarkerDisplayItem {
}
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
pub enum ReferenceFrameKind {
Transform,
@ -568,7 +558,7 @@ pub struct StackingContext {
pub cache_tiles: bool,
} // IMPLICIT: filters: Vec<FilterOp>, filter_datas: Vec<FilterData>
#[repr(u32)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum TransformStyle {
Flat = 0,
@ -582,7 +572,7 @@ pub enum TransformStyle {
/// important. Note that this is a performance hint only,
/// which WR may choose to ignore.
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
#[repr(u32)]
#[repr(u8)]
pub enum RasterSpace {
// Rasterize in local-space, applying supplied scale to primitives.
// Best performance, but lower quality.
@ -604,7 +594,7 @@ impl RasterSpace {
}
}
#[repr(u32)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum MixBlendMode {
Normal = 0,
@ -778,7 +768,7 @@ pub struct ImageDisplayItem {
pub color: ColorF,
}
#[repr(u32)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum ImageRendering {
Auto = 0,
@ -800,7 +790,7 @@ pub struct YuvImageDisplayItem {
pub image_rendering: ImageRendering,
}
#[repr(u32)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, MallocSizeOf, PartialEq, Serialize)]
pub enum YuvColorSpace {
Rec601 = 0,
@ -1070,3 +1060,34 @@ impl ExternalScrollId {
self.0 == 0
}
}
impl SpecificDisplayItem {
pub fn debug_name(&self) -> &'static str {
match *self {
SpecificDisplayItem::Border(..) => "border",
SpecificDisplayItem::BoxShadow(..) => "box_shadow",
SpecificDisplayItem::ClearRectangle => "clear_rectangle",
SpecificDisplayItem::Clip(..) => "clip",
SpecificDisplayItem::ClipChain(..) => "clip_chain",
SpecificDisplayItem::Gradient(..) => "gradient",
SpecificDisplayItem::Iframe(..) => "iframe",
SpecificDisplayItem::Image(..) => "image",
SpecificDisplayItem::Line(..) => "line",
SpecificDisplayItem::PopAllShadows => "pop_all_shadows",
SpecificDisplayItem::PopReferenceFrame => "pop_reference_frame",
SpecificDisplayItem::PopStackingContext => "pop_stacking_context",
SpecificDisplayItem::PushShadow(..) => "push_shadow",
SpecificDisplayItem::PushReferenceFrame(..) => "push_reference_frame",
SpecificDisplayItem::PushStackingContext(..) => "push_stacking_context",
SpecificDisplayItem::SetFilterOps => "set_filter_ops",
SpecificDisplayItem::SetFilterData => "set_filter_data",
SpecificDisplayItem::RadialGradient(..) => "radial_gradient",
SpecificDisplayItem::Rectangle(..) => "rectangle",
SpecificDisplayItem::ScrollFrame(..) => "scroll_frame",
SpecificDisplayItem::SetGradientStops => "set_gradient_stops",
SpecificDisplayItem::StickyFrame(..) => "sticky_frame",
SpecificDisplayItem::Text(..) => "text",
SpecificDisplayItem::YuvImage(..) => "yuv_image",
}
}
}

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

@ -13,6 +13,7 @@ use std::io::{Read, stdout, Write};
use std::marker::PhantomData;
use std::ops::Range;
use std::{io, mem, ptr, slice};
use std::collections::HashMap;
use time::precise_time_ns;
// local imports
use display_item as di;
@ -68,6 +69,7 @@ impl<T> ItemRange<T> {
}
}
#[derive(Copy, Clone)]
pub struct TempFilterData {
pub func_types: ItemRange<di::ComponentTransferFuncType>,
pub r_values: ItemRange<f32>,
@ -114,6 +116,24 @@ pub struct BuiltDisplayListIter<'a> {
cur_clip_chain_items: ItemRange<di::ClipId>,
cur_complex_clip: (ItemRange<di::ComplexClipRegion>, usize),
peeking: Peek,
/// Should just be initialized but never populated in release builds
debug_stats: DebugStats,
}
/// Internal info used for more detailed analysis of serialized display lists
struct DebugStats {
/// Last address in the buffer we pointed to, for computing serialized sizes
last_addr: usize,
stats: HashMap<&'static str, ItemStats>,
}
/// Stats for an individual item
#[derive(Copy, Clone, Debug, Default)]
pub struct ItemStats {
/// How many instances of this kind of item we deserialized
pub total_count: usize,
/// How many bytes we processed for this kind of item
pub num_bytes: usize,
}
pub struct DisplayItemRef<'a: 'b, 'b> {
@ -235,6 +255,10 @@ impl<'a> BuiltDisplayListIter<'a> {
cur_clip_chain_items: ItemRange::default(),
cur_complex_clip: (ItemRange::default(), 0),
peeking: Peek::NotPeeking,
debug_stats: DebugStats {
last_addr: data.as_ptr() as usize,
stats: HashMap::default(),
}
}
}
@ -298,12 +322,18 @@ impl<'a> BuiltDisplayListIter<'a> {
.expect("MEH: malicious process?");
}
self.log_item_stats();
match self.cur_item.item {
SetGradientStops => {
self.cur_stops = skip_slice::<di::GradientStop>(self.list, &mut self.data).0;
let temp = self.cur_stops;
self.log_slice_stats("set_gradient_stops.stops", temp);
}
SetFilterOps => {
self.cur_filters = skip_slice::<di::FilterOp>(self.list, &mut self.data).0;
let temp = self.cur_filters;
self.log_slice_stats("set_filter_ops.ops", temp);
}
SetFilterData => {
self.cur_filter_data.push(TempFilterData {
@ -313,14 +343,35 @@ impl<'a> BuiltDisplayListIter<'a> {
b_values: skip_slice::<f32>(self.list, &mut self.data).0,
a_values: skip_slice::<f32>(self.list, &mut self.data).0,
});
let data = *self.cur_filter_data.last().unwrap();
self.log_slice_stats("set_filter_data.func_types", data.func_types);
self.log_slice_stats("set_filter_data.r_values", data.r_values);
self.log_slice_stats("set_filter_data.g_values", data.g_values);
self.log_slice_stats("set_filter_data.b_values", data.b_values);
self.log_slice_stats("set_filter_data.a_values", data.a_values);
}
ClipChain(_) => {
self.cur_clip_chain_items = skip_slice::<di::ClipId>(self.list, &mut self.data).0;
let temp = self.cur_clip_chain_items;
self.log_slice_stats("clip_chain.clip_ids", temp);
}
Clip(_) | ScrollFrame(_) => {
self.cur_complex_clip = self.skip_slice::<di::ComplexClipRegion>()
self.cur_complex_clip = self.skip_slice::<di::ComplexClipRegion>();
let name = if let Clip(_) = self.cur_item.item {
"clip.complex_clips"
} else {
"scroll_frame.complex_clips"
};
let temp = self.cur_complex_clip.0;
self.log_slice_stats(name, temp);
}
Text(_) => {
self.cur_glyphs = self.skip_slice::<GlyphInstance>().0;
let temp = self.cur_glyphs;
self.log_slice_stats("text.glyphs", temp);
}
Text(_) => self.cur_glyphs = self.skip_slice::<GlyphInstance>().0,
_ => { /* do nothing */ }
}
@ -335,19 +386,6 @@ impl<'a> BuiltDisplayListIter<'a> {
DisplayItemRef { iter: self }
}
pub fn starting_stacking_context(
&mut self,
) -> Option<(di::StackingContext, LayoutRect, ItemRange<di::FilterOp>)> {
self.next().and_then(|item| match *item.item() {
di::SpecificDisplayItem::PushStackingContext(ref specific_item) => Some((
specific_item.stacking_context,
item.rect(),
item.filters(),
)),
_ => None,
})
}
pub fn skip_current_stacking_context(&mut self) {
let mut depth = 0;
while let Some(item) = self.next() {
@ -376,6 +414,68 @@ impl<'a> BuiltDisplayListIter<'a> {
Some(self.as_ref())
}
}
/// Get the debug stats for what this iterator has deserialized.
/// Should always be empty in release builds.
pub fn debug_stats(&mut self) -> Vec<(&'static str, ItemStats)> {
let mut result = self.debug_stats.stats.drain().collect::<Vec<_>>();
result.sort_by_key(|stats| stats.0);
result
}
/// Adds the debug stats from another to our own, assuming we are a sub-iter of the other
/// (so we can ignore where they were in the traversal).
pub fn merge_debug_stats_from(&mut self, other: &mut Self) {
for (key, other_entry) in other.debug_stats.stats.iter() {
let entry = self.debug_stats.stats.entry(key).or_default();
entry.total_count += other_entry.total_count;
entry.num_bytes += other_entry.num_bytes;
}
}
/// Logs stats for the last deserialized display item
#[cfg(feature = "display_list_stats")]
fn log_item_stats(&mut self) {
let num_bytes = self.debug_num_bytes();
let item_name = self.cur_item.item.debug_name();
let entry = self.debug_stats.stats.entry(item_name).or_default();
entry.total_count += 1;
entry.num_bytes += num_bytes;
}
/// Logs the stats for the given serialized slice
#[cfg(feature = "display_list_stats")]
fn log_slice_stats<T: for<'de> Deserialize<'de>>(&mut self, slice_name: &'static str, range: ItemRange<T>) {
// Run this so log_item_stats is accurate, but ignore its result
// because log_slice_stats may be called after multiple slices have been
// processed, and the `range` has everything we need.
self.debug_num_bytes();
let entry = self.debug_stats.stats.entry(slice_name).or_default();
entry.total_count += self.list.get(range).size_hint().0;
entry.num_bytes += range.length;
}
/// Computes the number of bytes we've processed since we last called
/// this method, so we can compute the serialized size of a display item.
#[cfg(feature = "display_list_stats")]
fn debug_num_bytes(&mut self) -> usize {
let old_addr = self.debug_stats.last_addr;
let new_addr = self.data.as_ptr() as usize;
let delta = new_addr - old_addr;
self.debug_stats.last_addr = new_addr;
delta
}
#[cfg(not(feature = "display_list_stats"))]
fn log_item_stats(&mut self) { /* no-op */ }
#[cfg(not(feature = "display_list_stats"))]
fn log_slice_stats<T>(&mut self, _slice_name: &str, _range: ItemRange<T>) { /* no-op */ }
}
// Some of these might just become ItemRanges
@ -556,8 +656,6 @@ impl Serialize for BuiltDisplayList {
),
di::SpecificDisplayItem::PushShadow(v) => PushShadow(v),
di::SpecificDisplayItem::PopAllShadows => PopAllShadows,
di::SpecificDisplayItem::PushCacheMarker(m) => PushCacheMarker(m),
di::SpecificDisplayItem::PopCacheMarker => PopCacheMarker,
},
layout: display_item.layout,
space_and_clip: display_item.space_and_clip,
@ -660,8 +758,6 @@ impl<'de> Deserialize<'de> for BuiltDisplayList {
},
PushShadow(specific_item) => di::SpecificDisplayItem::PushShadow(specific_item),
PopAllShadows => di::SpecificDisplayItem::PopAllShadows,
PushCacheMarker(marker) => di::SpecificDisplayItem::PushCacheMarker(marker),
PopCacheMarker => di::SpecificDisplayItem::PopCacheMarker,
},
layout: complete.layout,
space_and_clip: complete.space_and_clip,
@ -1349,19 +1445,6 @@ impl DisplayListBuilder {
id
}
pub fn push_cache_marker(&mut self) {
self.push_new_empty_item(&di::SpecificDisplayItem::PushCacheMarker(di::CacheMarkerDisplayItem {
// The display item itself is empty for now while we experiment with
// the API. In future it may contain extra information, such as details
// on whether the surface is known to be opaque and/or a background color
// hint that WR should clear the surface to.
}));
}
pub fn pop_cache_marker(&mut self) {
self.push_new_empty_item(&di::SpecificDisplayItem::PopCacheMarker);
}
pub fn pop_reference_frame(&mut self) {
self.push_new_empty_item(&di::SpecificDisplayItem::PopReferenceFrame);
}
@ -1378,8 +1461,11 @@ impl DisplayListBuilder {
raster_space: di::RasterSpace,
cache_tiles: bool,
) {
self.push_new_empty_item(&di::SpecificDisplayItem::SetFilterOps);
self.push_iter(filters);
if filters.len() > 0 {
self.push_new_empty_item(&di::SpecificDisplayItem::SetFilterOps);
self.push_iter(filters);
}
for filter_data in filter_datas {
let func_types = [

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

@ -96,7 +96,7 @@ pub enum FontTemplate {
Native(NativeFontHandle),
}
#[repr(u32)]
#[repr(u8)]
#[derive(Debug, Copy, Clone, Hash, Eq, MallocSizeOf, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
pub enum FontRenderMode {
Mono = 0,

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

@ -74,7 +74,7 @@ pub enum TextureTarget {
}
/// Storage format identifier for externally-managed images.
#[repr(u32)]
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum ExternalImageType {
/// The image is texture-backed.
@ -97,7 +97,7 @@ pub struct ExternalImageData {
}
/// Specifies the format of a series of pixels, in driver terms.
#[repr(u32)]
#[repr(u8)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum ImageFormat {
/// One-channel, byte storage. The "red" doesn't map to the color