| author | Daniel Varga <dvarga@mozilla.com> |
| Thu, 23 Jan 2020 08:46:54 +0200 | |
| changeset 511317 | 693c1fe229bc143776742206a9c4338aa01ae5db |
| parent 511316 | 7ed018d13880bee244338bf6e1c65ab17d58a870 |
| child 511318 | a1669b5990974f625d95260c059dcf8f87129a8d |
| child 511319 | b723d635ae0148cbfff9c4e9a17fbc9cfe65d6a1 |
| push id | 37047 |
| push user | malexandru@mozilla.com |
| push date | Thu, 23 Jan 2020 09:54:33 +0000 |
| treeherder | mozilla-central@a1669b599097 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| bugs | 1605283 |
| milestone | 74.0a1 |
| backs out | 7ed018d13880bee244338bf6e1c65ab17d58a870 |
| first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
| last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/wr/tileview/src/main.rs +++ b/gfx/wr/tileview/src/main.rs @@ -1,22 +1,20 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use webrender::{TileNode, TileNodeKind, InvalidationReason, TileOffset}; -use webrender::{TileSerializer, TileCacheInstanceSerializer, TileCacheLoggerUpdateLists}; +use webrender::{TileSerializer, TileCacheInstanceSerializer}; use serde::Deserialize; //use ron::de::from_reader; use std::fs::File; use std::io::prelude::*; use std::path::Path; use std::ffi::OsString; -use webrender::api::enumerate_interners; -use webrender::UpdateKind; #[derive(Deserialize)] pub struct Slice { pub x: f32, pub y: f32, pub tile_cache: TileCacheInstanceSerializer } @@ -229,17 +227,17 @@ fn slices_to_svg(slices: &[Slice], prev_ svg_width, svg_height) + "\n" + "<rect fill=\"black\" width=\"100%\" height=\"100%\"/>\n" + &svg + "\n</svg>\n" } -fn write_html(output_dir: &Path, svg_files: &[String], intern_files: &[String]) { +fn write_html(output_dir: &Path, svg_files: &[String]) { let html_head = "<!DOCTYPE html>\n\ <html>\n\ <head>\n\ <meta charset=\"UTF-8\">\n\ <link rel=\"stylesheet\" type=\"text/css\" href=\"tilecache.css\"></link>\n\ </head>\n" .to_string(); @@ -248,120 +246,76 @@ fn write_html(output_dir: &Path, svg_fil let mut script = "\n<script>\n".to_string(); script = format!("{}var svg_files = [\n", script); for svg_file in svg_files { script = format!("{} \"{}\",\n", script, svg_file); } - script = format!("{}];\n\n", script); - - script = format!("{}var intern_files = [\n", script); - for intern_file in intern_files { - script = format!("{} \"{}\",\n", script, intern_file); - } script = format!("{}];\n</script>\n\n", script); - //TODO this requires copying the js file from somewhere? script = format!("{}<script src=\"tilecache.js\" type=\"text/javascript\"></script>\n\n", script); let html_end = "</body>\n\ </html>\n" .to_string(); let html_body = format!( "{}\n\ - <div class=\"split left\">\n\ - <div>\n\ - <object id=\"svg_container0\" type=\"image/svg+xml\" data=\"{}\" class=\"tile_svg\" ></object>\n\ - <object id=\"svg_container1\" type=\"image/svg+xml\" data=\"{}\" class=\"tile_svg\" ></object>\n\ - </div>\n\ - </div>\n\ - \n\ - <div class=\"split right\">\n\ - <iframe width=\"100%\" id=\"intern\" src=\"{}\"></iframe>\n\ - </div>\n\ - \n\ + <object id=\"svg_container0\" type=\"image/svg+xml\" data=\"{}\" class=\"tile_svg\" ></object>\n\ + <object id=\"svg_container1\" type=\"image/svg+xml\" data=\"{}\" class=\"tile_svg\" ></object>\n\ <div id=\"svg_ui_overlay\">\n\ <div id=\"text_frame_counter\">{}</div>\n\ <div id=\"text_spacebar\">Spacebar to Play</div>\n\ <div>Use Left/Right to Step</div>\n\ <input id=\"frame_slider\" type=\"range\" min=\"0\" max=\"{}\" value=\"0\" class=\"svg_ui_slider\" /> </div>", html_body, svg_files[0], svg_files[0], - intern_files[0], svg_files[0], svg_files.len() ); let html = format!("{}{}{}{}", html_head, html_body, script, html_end); let output_file = output_dir.join("index.html"); let mut html_output = File::create(output_file).unwrap(); html_output.write_all(html.as_bytes()).unwrap(); } fn write_css(output_dir: &Path, max_slice_index: usize) { let mut css = ".tile_svg {\n\ - float: left;\n\ - }\n\ - \n\ - .split {\n\ - position: fixed;\n\ - z-index: 1;\n\ - top: 0;\n\ - padding-top: 20px;\n\ - }\n\ - \n\ - .left {\n\ - left: 0;\n\ - }\n\ - \n\ - .right {\n\ - right: 0;\n\ - width: 20%;\n\ - height: 100%;\n\ - opacity: 90%;\n\ - }\n\ - \n\ - #intern {\n\ - position:relative;\n\ - top:60px;\n\ - width: 100%;\n\ - height: 100%;\n\ - color: orange;\n\ - background-color:white;\n\ - }\n\ + position: fixed;\n\ + }\n\n\n\ .svg_invalidated {\n\ - fill: white;\n\ - font-family:monospace;\n\ + fill: white;\n\ + font-family:monospace;\n\ }\n\n\n\ #svg_ui_overlay {\n\ - position:absolute;\n\ - right:0; \n\ - top:0; \n\ - z-index:70; \n\ - color: rgb(255,255,100);\n\ - font-family:monospace;\n\ - background-color: #404040a0;\n\ + position:absolute;\n\ + right:0; \n\ + top:0; \n\ + z-index:70; \n\ + color: rgb(255,255,100);\n\ + font-family:monospace;\n\ + background-color: #404040a0;\n\ }\n\n\n\ .svg_quadtree {\n\ - fill: none;\n\ - stroke-width: 1;\n\ - stroke: orange;\n\ + fill: none;\n\ + stroke-width: 1;\n\ + stroke: orange;\n\ }\n\n\n\ .svg_changed_prim {\n\ - stroke: red;\n\ - stroke-width: 2.0;\n\ + stroke: red;\n\ + stroke-width: 2.0;\n\ }\n\n\n\ #svg_ui_slider {\n\ - width:90%;\n\ + width:90%;\n\ }\n\n".to_string(); for ix in 0..max_slice_index + 1 { let color = ( ix % 7 ) + 1; let rgb = format!("rgb({},{},{})", if color & 2 != 0 { 205 } else { 90 }, if color & 4 != 0 { 205 } else { 90 }, if color & 1 != 0 { 225 } else { 90 }); @@ -382,74 +336,16 @@ fn write_css(output_dir: &Path, max_slic rgb); } let output_file = output_dir.join("tilecache.css"); let mut css_output = File::create(output_file).unwrap(); css_output.write_all(css.as_bytes()).unwrap(); } -macro_rules! updatelist_to_html_macro { - ( $( $name:ident: $ty:ty, )+ ) => { - fn updatelist_to_html(update_lists: &TileCacheLoggerUpdateLists) -> String { - let mut html = String::new(); - $( - html += &format!("<h4 style=\"margin:5px;\">{}</h4>\n<font color=\"green\">\n", stringify!($name)); - let mut was_insert = true; - for update in &update_lists.$name.1 { - let is_insert = match update.kind { - UpdateKind::Insert => true, - _ => false - }; - if was_insert != is_insert { - html += &format!("</font><font color=\"{}\">", if is_insert { "green" } else { "red" }); - } - html += &format!("{}, \n", update.index); - was_insert = is_insert; - } - html += &"</font><hr/>\n"; - )+ - html - } - } -} -enumerate_interners!(updatelist_to_html_macro); - -fn write_tile_cache_visualizer_svg(entry: &std::fs::DirEntry, output_dir: &Path, - slices: &[Slice], prev_slices: Option<Vec<Slice>>, - svg_width: &mut i32, svg_height: &mut i32, - max_slice_index: &mut usize, - svg_files: &mut Vec::<String>) -{ - let svg = slices_to_svg(&slices, prev_slices, svg_width, svg_height, max_slice_index); - - let mut output_filename = OsString::from(entry.path().file_name().unwrap()); - output_filename.push(".svg"); - svg_files.push(output_filename.to_string_lossy().to_string()); - - output_filename = output_dir.join(output_filename).into_os_string(); - let mut svg_output = File::create(output_filename).unwrap(); - svg_output.write_all(svg.as_bytes()).unwrap(); -} - -fn write_update_list_html(entry: &std::fs::DirEntry, output_dir: &Path, - update_lists: &TileCacheLoggerUpdateLists, - html_files: &mut Vec::<String>) -{ - let html = updatelist_to_html(update_lists); - - let mut output_filename = OsString::from(entry.path().file_name().unwrap()); - output_filename.push(".html"); - html_files.push(output_filename.to_string_lossy().to_string()); - - output_filename = output_dir.join(output_filename).into_os_string(); - let mut html_output = File::create(output_filename).unwrap(); - html_output.write_all(html.as_bytes()).unwrap(); -} - fn main() { let args: Vec<String> = std::env::args().collect(); if args.len() != 3 { println!("Usage: tileview input_dir output_dir"); println!(" where input_dir is a tile_cache folder inside a wr-capture."); println!("\nexample: cargo run c:/Users/me/AppData/Local/wr-capture.6/tile_cache/ c:/temp/tilecache/"); std::process::exit(1); @@ -465,47 +361,44 @@ fn main() { let mut entries: Vec<_> = std::fs::read_dir(input_dir).unwrap() //.map(|r| r.unwrap()) .filter_map(|r| r.ok()) .collect(); entries.sort_by_key(|dir| dir.path()); let mut svg_files: Vec::<String> = Vec::new(); - let mut intern_files: Vec::<String> = Vec::new(); let mut prev_slices = None; for entry in &entries { if entry.path().is_dir() { continue; } print!("processing {:?}\t", entry.path()); - let file_data = std::fs::read_to_string(entry.path()).unwrap(); - let chunks: Vec<_> = file_data.split("// @@@ chunk @@@").collect(); - let slices: Vec<Slice> = match ron::de::from_str(&chunks[0]) { + let f = File::open(entry.path()).unwrap(); + let slices: Vec<Slice> = match ron::de::from_reader(f) { Ok(data) => { data } Err(e) => { - println!("ERROR: failed to deserialize slicesg {:?}\n{:?}", entry.path(), e); + println!("ERROR: failed to deserialize {:?}\n{:?}", entry.path(), e); prev_slices = None; continue; } }; - let mut update_lists = TileCacheLoggerUpdateLists::new(); - update_lists.from_ron(&chunks[1]); + + let svg = slices_to_svg(&slices, prev_slices, &mut svg_width, &mut svg_height, &mut max_slice_index); - write_tile_cache_visualizer_svg(&entry, &output_dir, - &slices, prev_slices, - &mut svg_width, &mut svg_height, - &mut max_slice_index, - &mut svg_files); + let mut output_filename = OsString::from(entry.path().file_name().unwrap()); + output_filename.push(".svg"); + svg_files.push(output_filename.to_string_lossy().to_string()); - write_update_list_html(&entry, &output_dir, &update_lists, - &mut intern_files); + output_filename = output_dir.join(output_filename).into_os_string(); + let mut svg_output = File::create(output_filename).unwrap(); + svg_output.write_all(svg.as_bytes()).unwrap(); print!("\r"); prev_slices = Some(slices); } - write_html(output_dir, &svg_files, &intern_files); + write_html(output_dir, &svg_files); write_css(output_dir, max_slice_index); println!("OK. For now, manually copy tilecache.js to the output folder please. "); }
--- a/gfx/wr/tileview/src/tilecache.js +++ b/gfx/wr/tileview/src/tilecache.js @@ -70,17 +70,16 @@ function go_to_svg(index) { frontbuffer.style.display = 'none'; var t = frontbuffer; frontbuffer = backbuffer; backbuffer = t; is_loading = false; } backbuffer.setAttribute('data', svg_files[svg_index]); - document.getElementById('intern').src = intern_files[svg_index]; // also see https://stackoverflow.com/a/29915275 } function load() { window.addEventListener('keypress', handle_keyboard_shortcut); window.addEventListener('keydown', handle_keydown);
--- a/gfx/wr/webrender/src/intern.rs +++ b/gfx/wr/webrender/src/intern.rs @@ -47,17 +47,17 @@ use crate::util::VecHelper; #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(Debug, Copy, Clone, MallocSizeOf, PartialEq)] struct Epoch(u64); /// A list of updates to be applied to the data store, /// provided by the interning structure. pub struct UpdateList<S> { /// The additions and removals to apply. - pub updates: Vec<Update>, + updates: Vec<Update>, /// Actual new data to insert. data: Vec<S>, } lazy_static! { static ref NEXT_UID: AtomicUsize = AtomicUsize::new(0); } @@ -117,18 +117,18 @@ pub enum UpdateKind { Insert, Remove, } #[cfg_attr(feature = "capture", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[derive(MallocSizeOf)] pub struct Update { - pub index: usize, - pub kind: UpdateKind, + index: usize, + kind: UpdateKind, } pub trait InternDebug { fn on_interned(&self, _uid: ItemUid) {} } /// The data store lives in the frame builder thread. It /// contains a free-list of items for fast access.
--- a/gfx/wr/webrender/src/lib.rs +++ b/gfx/wr/webrender/src/lib.rs @@ -217,10 +217,9 @@ pub use crate::renderer::{ RendererStats, SceneBuilderHooks, ThreadListener, ShaderPrecacheFlags, MAX_VERTEX_TEXTURE_WIDTH, }; pub use crate::screen_capture::{AsyncScreenshotHandle, RecordedFrameHandle}; pub use crate::shade::{Shaders, WrShaders}; pub use api as webrender_api; pub use webrender_build::shader::ProgramSourceDigest; pub use crate::picture::{TileDescriptor, TileId, InvalidationReason, PrimitiveCompareResult}; -pub use crate::picture::{TileNode, TileNodeKind, TileSerializer, TileCacheInstanceSerializer, TileOffset, TileCacheLoggerUpdateLists}; -pub use crate::intern::{Update,UpdateKind}; +pub use crate::picture::{TileNode, TileNodeKind, TileSerializer, TileCacheInstanceSerializer, TileOffset};
--- a/gfx/wr/webrender/src/picture.rs +++ b/gfx/wr/webrender/src/picture.rs @@ -104,21 +104,16 @@ use crate::scene::SceneProperties; use smallvec::SmallVec; use std::{mem, u8, marker, u32}; use std::sync::atomic::{AtomicUsize, Ordering}; use crate::texture_cache::TextureCacheHandle; use crate::util::{TransformedRectKind, MatrixHelpers, MaxRect, scale_factors, VecHelper, RectHelpers}; use crate::filterdata::{FilterDataHandle}; #[cfg(feature = "capture")] use ron; -#[cfg(feature = "capture")] -use crate::scene_builder_thread::InternerUpdates; -#[cfg(feature = "capture")] -use crate::intern::Update; - #[cfg(feature = "capture")] use std::fs::File; #[cfg(feature = "capture")] use std::io::prelude::*; #[cfg(feature = "capture")] use std::path::PathBuf; @@ -1493,196 +1488,65 @@ impl BackdropInfo { } #[derive(Clone)] pub struct TileCacheLoggerSlice { pub serialized_slice: String, pub local_to_world_transform: DeviceRect } -#[cfg(any(feature = "capture", feature = "replay"))] -macro_rules! declare_tile_cache_logger_updatelists { - ( $( $name:ident : $ty:ty, )+ ) => { - #[cfg_attr(feature = "capture", derive(Serialize))] - #[cfg_attr(feature = "replay", derive(Deserialize))] - struct TileCacheLoggerUpdateListsSerializer { - pub ron_string: Vec<String>, - } - - pub struct TileCacheLoggerUpdateLists { - $( - /// Generate storage, one per interner. - /// the tuple is a workaround to avoid the need for multiple - /// fields that start with $name (macro concatenation). - /// the string is .ron serialized updatelist at capture time; - /// the updates is the list of DataStore updates (avoid UpdateList - /// due to Default() requirements on the Keys) reconstructed at - /// load time. - pub $name: (String, Vec<Update>), - )+ - } - - impl TileCacheLoggerUpdateLists { - pub fn new() -> Self { - TileCacheLoggerUpdateLists { - $( - $name : ( String::new(), Vec::<Update>::new() ), - )+ - } - } - - /// serialize all interners in updates to .ron - fn serialize_updates( - &mut self, - updates: &InternerUpdates - ) { - $( - self.$name.0 = ron::ser::to_string_pretty(&updates.$name.updates, Default::default()).unwrap(); - )+ - } - - fn is_empty(&self) -> bool { - $( - if !self.$name.0.is_empty() { return false; } - )+ - true - } - - #[cfg(feature = "capture")] - fn to_ron(&self) -> String { - let mut serializer = - TileCacheLoggerUpdateListsSerializer { ron_string: Vec::new() }; - $( - serializer.ron_string.push( - if self.$name.0.is_empty() { - "[]".to_string() - } else { - self.$name.0.clone() - }); - )+ - ron::ser::to_string_pretty(&serializer, Default::default()).unwrap() - } - - #[cfg(feature = "replay")] - pub fn from_ron(&mut self, text: &str) { - let serializer : TileCacheLoggerUpdateListsSerializer = - match ron::de::from_str(&text) { - Ok(data) => { data } - Err(e) => { - println!("ERROR: failed to deserialize updatelist: {:?}\n{:?}", &text, e); - return; - } - }; - let mut index = 0; - $( - self.$name.1 = ron::de::from_str(&serializer.ron_string[index]).unwrap(); - index = index + 1; - )+ - // error: value assigned to `index` is never read - let _ = index; - } - } - } -} - -#[cfg(any(feature = "capture", feature = "replay"))] -enumerate_interners!(declare_tile_cache_logger_updatelists); - -#[cfg(not(feature = "capture"))] -#[derive(Clone)] -pub struct TileCacheLoggerUpdateLists { -} - -#[cfg(not(feature = "capture"))] -impl TileCacheLoggerUpdateLists { - pub fn new() -> Self { TileCacheLoggerUpdateLists {} } - fn is_empty(&self) -> bool { true } -} - -/// Log tile cache activity for one single frame. -/// Also stores the commands sent to the interning data_stores -/// so we can see which items were created or destroyed this frame, -/// and correlate that with tile invalidation activity. -pub struct TileCacheLoggerFrame { - /// slices in the frame, one per take_context call - pub slices: Vec<TileCacheLoggerSlice>, - /// interning activity - pub update_lists: TileCacheLoggerUpdateLists -} - -impl TileCacheLoggerFrame { - pub fn new() -> Self { - TileCacheLoggerFrame { - slices: Vec::new(), - update_lists: TileCacheLoggerUpdateLists::new() - } - } - - pub fn is_empty(&self) -> bool { - self.slices.is_empty() && self.update_lists.is_empty() - } -} - /// Log tile cache activity whenever anything happens in take_context. pub struct TileCacheLogger { /// next write pointer pub write_index : usize, /// ron serialization of tile caches; - pub frames: Vec<TileCacheLoggerFrame> + /// each frame consists of slices, one per take_context call + pub frames: Vec<Vec<TileCacheLoggerSlice>> } impl TileCacheLogger { pub fn new( num_frames: usize ) -> Self { let mut frames = Vec::with_capacity(num_frames); - for _i in 0..num_frames { // no Clone so no resize - frames.push(TileCacheLoggerFrame::new()); - } + let empty_element = Vec::new(); + frames.resize(num_frames, empty_element); TileCacheLogger { write_index: 0, frames } } pub fn is_enabled(&self) -> bool { !self.frames.is_empty() } #[cfg(feature = "capture")] pub fn add(&mut self, serialized_slice: String, local_to_world_transform: DeviceRect) { if !self.is_enabled() { return; } - self.frames[self.write_index].slices.push( + self.frames[self.write_index].push( TileCacheLoggerSlice { serialized_slice, local_to_world_transform }); } - #[cfg(feature = "capture")] - pub fn serialize_updates(&mut self, updates: &InternerUpdates) { - if !self.is_enabled() { - return; - } - self.frames[self.write_index].update_lists.serialize_updates(updates); - } - /// see if anything was written in this frame, and if so, /// advance the write index in a circular way and clear the /// recorded string. pub fn advance(&mut self) { if !self.is_enabled() || self.frames[self.write_index].is_empty() { return; } self.write_index = self.write_index + 1; if self.write_index >= self.frames.len() { self.write_index = 0; } - self.frames[self.write_index] = TileCacheLoggerFrame::new(); + self.frames[self.write_index] = Vec::new(); } #[cfg(feature = "capture")] pub fn save_capture( &self, root: &PathBuf ) { if !self.is_enabled() { return; @@ -1702,36 +1566,29 @@ impl TileCacheLogger { // save_capture, we've add()ed entries but haven't advance()d yet, // so the actual oldest entry is write_index + 1 let index = (self.write_index + 1 + ix) % self.frames.len(); if self.frames[index].is_empty() { continue; } let filename = path_tile_cache.join(format!("frame{:05}.ron", files_written)); + files_written = files_written + 1; let mut output = File::create(filename).unwrap(); - output.write_all(b"// slice data\n").unwrap(); output.write_all(b"[\n").unwrap(); - for item in &self.frames[index].slices { + for item in &self.frames[index] { output.write_all(format!("( x: {}, y: {},\n", item.local_to_world_transform.origin.x, item.local_to_world_transform.origin.y) .as_bytes()).unwrap(); output.write_all(b"tile_cache:\n").unwrap(); output.write_all(item.serialized_slice.as_bytes()).unwrap(); output.write_all(b"\n),\n").unwrap(); } - output.write_all(b"]\n\n").unwrap(); - - output.write_all(b"// @@@ chunk @@@\n\n").unwrap(); - - output.write_all(b"// interning data\n").unwrap(); - output.write_all(self.frames[index].update_lists.to_ron().as_bytes()).unwrap(); - - files_written = files_written + 1; + output.write_all(b"]\n").unwrap(); } } } /// Represents a cache of tiles that make up a picture primitives. pub struct TileCacheInstance { /// Index of the tile cache / slice for this frame builder. It's determined /// by the setup_picture_caching method during flattening, which splits the
--- a/gfx/wr/webrender/src/render_backend.rs +++ b/gfx/wr/webrender/src/render_backend.rs @@ -1461,22 +1461,16 @@ impl RenderBackend { let requires_frame_build = self.requires_frame_build(); let doc = self.documents.get_mut(&document_id).unwrap(); doc.has_built_scene |= has_built_scene; // If there are any additions or removals of clip modes // during the scene build, apply them to the data store now. if let Some(updates) = interner_updates { - #[cfg(feature = "capture")] - { - if self.debug_flags.contains(DebugFlags::TILE_CACHE_LOGGING_DBG) { - self.tile_cache_logger.serialize_updates(&updates); - } - } doc.data_stores.apply_updates(updates, profile_counters); } // TODO: this scroll variable doesn't necessarily mean we scrolled. It is only used // for something wrench specific and we should remove it. let mut scroll = false; for frame_msg in frame_ops { let _timer = profile_counters.total_time.timer();