From 84357fecdcb7c9eb57aed117d166dd5a1657ed58 Mon Sep 17 00:00:00 2001 From: Stefan Hindli Date: Mon, 20 Apr 2020 17:22:53 +0300 Subject: [PATCH] Backed out changeset 419be9960357 (bug 1561367) for causing wrench bustages CLOSED TREE --- .../base/content/browser-graphics-utils.js | 10 - browser/base/content/browser-sets.inc | 8 - dom/base/nsDOMWindowUtils.cpp | 8 - dom/interfaces/base/nsIDOMWindowUtils.idl | 8 - gfx/layers/ipc/PWebRenderBridge.ipdl | 2 - gfx/layers/wr/WebRenderBridgeChild.cpp | 3 - gfx/layers/wr/WebRenderBridgeChild.h | 1 - gfx/layers/wr/WebRenderBridgeParent.cpp | 7 - gfx/layers/wr/WebRenderBridgeParent.h | 1 - gfx/webrender_bindings/WebRenderAPI.cpp | 14 +- gfx/webrender_bindings/WebRenderAPI.h | 4 - gfx/webrender_bindings/src/bindings.rs | 33 +- gfx/wr/webrender/src/capture.rs | 139 +---- gfx/wr/webrender/src/internal_types.rs | 2 +- gfx/wr/webrender/src/render_backend.rs | 507 ++++++------------ gfx/wr/webrender/src/renderer.rs | 137 ++--- gfx/wr/webrender/src/resource_cache.rs | 39 +- gfx/wr/webrender/src/scene_builder_thread.rs | 67 +-- gfx/wr/webrender_api/src/api.rs | 24 +- gfx/wr/wrench/src/args.yaml | 10 - gfx/wr/wrench/src/main.rs | 21 +- gfx/wr/wrench/src/rawtest.rs | 2 +- gfx/wr/wrench/src/wrench.rs | 65 --- 23 files changed, 247 insertions(+), 865 deletions(-) diff --git a/browser/base/content/browser-graphics-utils.js b/browser/base/content/browser-graphics-utils.js index 80e0e8b81096..3bba7394dac1 100644 --- a/browser/base/content/browser-graphics-utils.js +++ b/browser/base/content/browser-graphics-utils.js @@ -15,9 +15,6 @@ var gGfxUtils = { init() { if (Services.prefs.getBoolPref("gfx.webrender.enable-capture")) { document.getElementById("wrCaptureCmd").removeAttribute("disabled"); - document - .getElementById("wrToggleCaptureSequenceCmd") - .removeAttribute("disabled"); } }, @@ -34,13 +31,6 @@ var gGfxUtils = { webrenderCapture() { window.windowUtils.wrCapture(); }, - /** - * Trigger a WebRender capture of the current state and future state - * into a local folder. If called again, it will stop capturing. - */ - toggleWebrenderCaptureSequence() { - window.windowUtils.wrToggleCaptureSequence(); - }, /** * Toggle transaction logging to text file. diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc index 87e46fd80062..3838e3865aa0 100644 --- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -103,7 +103,6 @@ - #ifdef NIGHTLY_BUILD @@ -339,13 +338,6 @@ key="#" modifiers="control" #endif command="wrCaptureCmd"/> - #ifdef NIGHTLY_BUILD ToggleCaptureSequence(); - } - return NS_OK; -} - NS_IMETHODIMP nsDOMWindowUtils::SetCompositionRecording(bool aValue, Promise** aOutPromise) { return aValue ? StartCompositionRecording(aOutPromise) diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 88085bcbef53..509329d0f1f3 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1945,14 +1945,6 @@ interface nsIDOMWindowUtils : nsISupports { */ void wrCapture(); - /** - * Start capturing the contents of the current WebRender frame and - * save them to a folder relative to the current working directory, - * as well as any frames generated from this point onward. If called - * again, it will stop capturing. - */ - void wrToggleCaptureSequence(); - /** * Toggle recording of composition on and off. * diff --git a/gfx/layers/ipc/PWebRenderBridge.ipdl b/gfx/layers/ipc/PWebRenderBridge.ipdl index 4acb6b5ec7e4..949191192130 100644 --- a/gfx/layers/ipc/PWebRenderBridge.ipdl +++ b/gfx/layers/ipc/PWebRenderBridge.ipdl @@ -74,8 +74,6 @@ parent: async ScheduleComposite(); // Save the frame capture to disk async Capture(); - // Start capturing each frame and save to disk, and if already started, stop. - async ToggleCaptureSequence(); // Enable/Disable transaction logging async SetTransactionLogging(bool aValue); diff --git a/gfx/layers/wr/WebRenderBridgeChild.cpp b/gfx/layers/wr/WebRenderBridgeChild.cpp index 13980339becf..ea2b48f71cd9 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.cpp +++ b/gfx/layers/wr/WebRenderBridgeChild.cpp @@ -616,9 +616,6 @@ void WebRenderBridgeChild::DeallocResourceShmem(RefCountedShmem& aShm) { } void WebRenderBridgeChild::Capture() { this->SendCapture(); } -void WebRenderBridgeChild::ToggleCaptureSequence() { - this->SendToggleCaptureSequence(); -} void WebRenderBridgeChild::SetTransactionLogging(bool aValue) { this->SendSetTransactionLogging(aValue); diff --git a/gfx/layers/wr/WebRenderBridgeChild.h b/gfx/layers/wr/WebRenderBridgeChild.h index 8a8f464c69a1..aec7033bbd07 100644 --- a/gfx/layers/wr/WebRenderBridgeChild.h +++ b/gfx/layers/wr/WebRenderBridgeChild.h @@ -182,7 +182,6 @@ class WebRenderBridgeChild final : public PWebRenderBridgeChild, void DeallocResourceShmem(RefCountedShmem& aShm); void Capture(); - void ToggleCaptureSequence(); void SetTransactionLogging(bool aValue); private: diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index 4b4c280f3174..4254b68b3a93 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -2156,13 +2156,6 @@ mozilla::ipc::IPCResult WebRenderBridgeParent::RecvCapture() { return IPC_OK(); } -mozilla::ipc::IPCResult WebRenderBridgeParent::RecvToggleCaptureSequence() { - if (!mDestroyed) { - mApis[wr::RenderRoot::Default]->ToggleCaptureSequence(); - } - return IPC_OK(); -} - mozilla::ipc::IPCResult WebRenderBridgeParent::RecvSetTransactionLogging( const bool& aValue) { if (!mDestroyed) { diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index f8f09411a446..6e9c63a4ac6a 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -193,7 +193,6 @@ class WebRenderBridgeParent final mozilla::ipc::IPCResult RecvInvalidateRenderedFrame() override; mozilla::ipc::IPCResult RecvScheduleComposite() override; mozilla::ipc::IPCResult RecvCapture() override; - mozilla::ipc::IPCResult RecvToggleCaptureSequence() override; mozilla::ipc::IPCResult RecvSetTransactionLogging(const bool&) override; mozilla::ipc::IPCResult RecvSyncWithCompositor() override; diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index 5a53f7efadbb..d17dc0e2abea 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -375,7 +375,6 @@ WebRenderAPI::WebRenderAPI(wr::DocumentHandle* aHandle, wr::WindowId aId, mUseANGLE(aUseANGLE), mUseDComp(aUseDComp), mUseTripleBuffering(aUseTripleBuffering), - mCaptureSequence(false), mSyncHandle(aSyncHandle), mRenderRoot(aRenderRoot) {} @@ -649,22 +648,11 @@ void WebRenderAPI::WaitFlushed() { void WebRenderAPI::Capture() { // see CaptureBits // SCENE | FRAME | TILE_CACHE - uint8_t bits = 15; // TODO: get from JavaScript + uint8_t bits = 7; // TODO: get from JavaScript const char* path = "wr-capture"; // TODO: get from JavaScript wr_api_capture(mDocHandle, path, bits); } -void WebRenderAPI::ToggleCaptureSequence() { - mCaptureSequence = !mCaptureSequence; - if (mCaptureSequence) { - uint8_t bits = 9; // TODO: get from JavaScript - const char* path = "wr-capture-sequence"; // TODO: get from JavaScript - wr_api_start_capture_sequence(mDocHandle, path, bits); - } else { - wr_api_stop_capture_sequence(mDocHandle); - } -} - void WebRenderAPI::SetTransactionLogging(bool aValue) { wr_api_set_transaction_logging(mDocHandle, aValue); } diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index ec391e835e10..9e6d5cf018ab 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -279,9 +279,6 @@ class WebRenderAPI final { layers::SyncHandle GetSyncHandle() const { return mSyncHandle; } void Capture(); - - void ToggleCaptureSequence(); - void SetTransactionLogging(bool aValue); void SetCompositionRecorder( @@ -325,7 +322,6 @@ class WebRenderAPI final { bool mUseANGLE; bool mUseDComp; bool mUseTripleBuffering; - bool mCaptureSequence; layers::SyncHandle mSyncHandle; wr::RenderRoot mRenderRoot; diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index cabaffaca519..610d872d11ff 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -2003,8 +2003,9 @@ pub extern "C" fn wr_resource_updates_add_raw_font( txn.add_raw_font(key, bytes.flush_into_vec(), index); } -fn generate_capture_path(path: *const c_char) -> Option { - use std::fs::{File, create_dir_all}; +#[no_mangle] +pub extern "C" fn wr_api_capture(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32) { + use std::fs::{create_dir_all, File}; use std::io::Write; let cstr = unsafe { CStr::from_ptr(path) }; @@ -2052,34 +2053,12 @@ fn generate_capture_path(path: *const c_char) -> Option { } Err(e) => { warn!("Unable to create path '{:?}' for capture: {:?}", path, e); - return None + return; } } - Some(path) -} - -#[no_mangle] -pub extern "C" fn wr_api_capture(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32) { - if let Some(path) = generate_capture_path(path) { - let bits = CaptureBits::from_bits(bits_raw as _).unwrap(); - dh.api.save_capture(path, bits); - } -} - -#[no_mangle] -pub extern "C" fn wr_api_start_capture_sequence(dh: &mut DocumentHandle, path: *const c_char, bits_raw: u32) { - if let Some(path) = generate_capture_path(path) { - let bits = CaptureBits::from_bits(bits_raw as _).unwrap(); - dh.api.start_capture_sequence(path, bits); - } -} - -#[no_mangle] -pub extern "C" fn wr_api_stop_capture_sequence(dh: &mut DocumentHandle) { - let border = "--------------------------\n"; - warn!("{} Stop capturing WR state\n{}", &border, &border); - dh.api.stop_capture_sequence(); + let bits = CaptureBits::from_bits(bits_raw as _).unwrap(); + dh.api.save_capture(path, bits); } #[no_mangle] diff --git a/gfx/wr/webrender/src/capture.rs b/gfx/wr/webrender/src/capture.rs index 4f856b05141a..00e033bff026 100644 --- a/gfx/wr/webrender/src/capture.rs +++ b/gfx/wr/webrender/src/capture.rs @@ -21,12 +21,6 @@ use serde; pub struct CaptureConfig { pub root: PathBuf, pub bits: CaptureBits, - /// Scene sequence ID when capturing multiple frames. Zero for a single frame capture. - pub scene_id: u32, - /// Frame sequence ID when capturing multiple frames. Zero for a single frame capture. - pub frame_id: u32, - /// Resource sequence ID when capturing multiple frames. Zero for a single frame capture. - pub resource_id: u32, #[cfg(feature = "capture")] pretty: ron::ser::PrettyConfig, } @@ -37,9 +31,6 @@ impl CaptureConfig { CaptureConfig { root, bits, - scene_id: 0, - frame_id: 0, - resource_id: 0, #[cfg(feature = "capture")] pretty: ron::ser::PrettyConfig { enumerate_arrays: true, @@ -49,111 +40,35 @@ impl CaptureConfig { } #[cfg(feature = "capture")] - pub fn prepare_scene(&mut self) { - use std::fs::create_dir_all; - self.scene_id += 1; - let _ = create_dir_all(&self.scene_root()); - } - - #[cfg(feature = "capture")] - pub fn prepare_frame(&mut self) { - use std::fs::create_dir_all; - self.frame_id += 1; - let _ = create_dir_all(&self.frame_root()); - } - - #[cfg(feature = "capture")] - pub fn prepare_resource(&mut self) { - use std::fs::create_dir_all; - self.resource_id += 1; - let _ = create_dir_all(&self.resource_root()); - } - - #[cfg(any(feature = "capture", feature = "replay"))] - pub fn scene_root(&self) -> PathBuf { - if self.scene_id > 0 { - let path = format!("scenes/{:05}", self.scene_id); - self.root.join(path) - } else { - self.root.clone() - } - } - - #[cfg(any(feature = "capture", feature = "replay"))] - pub fn frame_root(&self) -> PathBuf { - if self.frame_id > 0 { - let path = format!("frames/{:05}", self.frame_id); - self.scene_root().join(path) - } else { - self.root.clone() - } - } - - #[cfg(any(feature = "capture", feature = "replay"))] - pub fn resource_root(&self) -> PathBuf { - if self.resource_id > 0 { - let path = format!("resources/{:05}", self.resource_id); - self.root.join(path) - } else { - self.root.clone() - } - } - - #[cfg(feature = "capture")] - pub fn serialize_for_scene(&self, data: &T, name: P) - where - T: serde::Serialize, - P: AsRef, - { - self.serialize(data, self.scene_root(), name) - } - - #[cfg(feature = "capture")] - pub fn serialize_for_frame(&self, data: &T, name: P) - where - T: serde::Serialize, - P: AsRef, - { - self.serialize(data, self.frame_root(), name) - } - - #[cfg(feature = "capture")] - pub fn serialize_for_resource(&self, data: &T, name: P) - where - T: serde::Serialize, - P: AsRef, - { - self.serialize(data, self.resource_root(), name) - } - - #[cfg(feature = "capture")] - pub fn file_path_for_frame

(&self, name: P, ext: &str) -> PathBuf + pub fn file_path

(&self, name: P, ext: &str) -> PathBuf where P: AsRef { - self.frame_root().join(name).with_extension(ext) + self.root.join(name).with_extension(ext) } #[cfg(feature = "capture")] - fn serialize(&self, data: &T, path: PathBuf, name: P) + pub fn serialize(&self, data: &T, name: P) where T: serde::Serialize, P: AsRef, { use std::io::Write; + let ron = ron::ser::to_string_pretty(data, self.pretty.clone()) .unwrap(); - let mut file = File::create(path.join(name).with_extension("ron")) + let path = self.file_path(name, "ron"); + let mut file = File::create(path) .unwrap(); write!(file, "{}\n", ron) .unwrap(); } #[cfg(feature = "capture")] - fn serialize_tree(data: &T, root: PathBuf, name: P) + pub fn serialize_tree(&self, data: &T, name: P) where T: PrintableTree, P: AsRef { - let path = root + let path = self.root .join(name) .with_extension("tree"); let file = File::create(path) @@ -162,17 +77,8 @@ impl CaptureConfig { data.print_with(&mut pt); } - #[cfg(feature = "capture")] - pub fn serialize_tree_for_frame(&self, data: &T, name: P) - where - T: PrintableTree, - P: AsRef - { - Self::serialize_tree(data, self.frame_root(), name) - } - #[cfg(feature = "replay")] - fn deserialize(root: &PathBuf, name: P) -> Option + pub fn deserialize(root: &PathBuf, name: P) -> Option where T: for<'a> serde::Deserialize<'a>, P: AsRef, @@ -193,33 +99,6 @@ impl CaptureConfig { } } - #[cfg(feature = "replay")] - pub fn deserialize_for_scene(&self, name: P) -> Option - where - T: for<'a> serde::Deserialize<'a>, - P: AsRef, - { - Self::deserialize(&self.scene_root(), name) - } - - #[cfg(feature = "replay")] - pub fn deserialize_for_frame(&self, name: P) -> Option - where - T: for<'a> serde::Deserialize<'a>, - P: AsRef, - { - Self::deserialize(&self.frame_root(), name) - } - - #[cfg(feature = "replay")] - pub fn deserialize_for_resource(&self, name: P) -> Option - where - T: for<'a> serde::Deserialize<'a>, - P: AsRef, - { - Self::deserialize(&self.resource_root(), name) - } - #[cfg(feature = "png")] pub fn save_png( path: PathBuf, size: DeviceIntSize, format: ImageFormat, stride: Option, data: &[u8], diff --git a/gfx/wr/webrender/src/internal_types.rs b/gfx/wr/webrender/src/internal_types.rs index e25f4428230d..11e760ac475f 100644 --- a/gfx/wr/webrender/src/internal_types.rs +++ b/gfx/wr/webrender/src/internal_types.rs @@ -540,7 +540,7 @@ pub enum DebugOutput { #[cfg(feature = "capture")] SaveCapture(CaptureConfig, Vec), #[cfg(feature = "replay")] - LoadCapture(CaptureConfig, Vec), + LoadCapture(PathBuf, Vec), } #[allow(dead_code)] diff --git a/gfx/wr/webrender/src/render_backend.rs b/gfx/wr/webrender/src/render_backend.rs index 94f358bf1a6f..a694949806fe 100644 --- a/gfx/wr/webrender/src/render_backend.rs +++ b/gfx/wr/webrender/src/render_backend.rs @@ -16,13 +16,11 @@ use api::{NotificationRequest, Checkpoint, QualitySettings}; use api::{ClipIntern, FilterDataIntern, PrimitiveKeyKind}; use api::channel::Payload; use api::units::*; -#[cfg(any(feature = "capture", feature = "replay"))] +#[cfg(feature = "capture")] use api::CaptureBits; #[cfg(feature = "replay")] use api::CapturedDocument; use crate::spatial_tree::SpatialNodeIndex; -#[cfg(any(feature = "capture", feature = "replay"))] -use crate::capture::CaptureConfig; use crate::composite::{CompositorKind, CompositeDescriptor}; #[cfg(feature = "debugger")] use crate::debug_server; @@ -45,7 +43,7 @@ use crate::renderer::{AsyncPropertySampler, PipelineInfo}; use crate::resource_cache::ResourceCache; #[cfg(feature = "replay")] use crate::resource_cache::PlainCacheOwn; -#[cfg(feature = "replay")] +#[cfg(any(feature = "capture", feature = "replay"))] use crate::resource_cache::PlainResources; #[cfg(feature = "replay")] use crate::scene::Scene; @@ -55,8 +53,6 @@ use crate::scene_builder_thread::*; use serde::{Serialize, Deserialize}; #[cfg(feature = "debugger")] use serde_json; -#[cfg(feature = "replay")] -use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::path::PathBuf; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -745,7 +741,7 @@ struct PlainRenderBackend { default_device_pixel_ratio: f32, frame_config: FrameBuilderConfig, documents: FastHashMap, - resource_sequence_id: u32, + resources: PlainResources, } /// The render backend is responsible for transforming high level display lists into @@ -778,10 +774,6 @@ pub struct RenderBackend { namespace_alloc_by_client: bool, recycler: Recycler, - #[cfg(feature = "capture")] - capture_config: Option, - #[cfg(feature = "replay")] - loaded_resource_sequence_id: u32, } impl RenderBackend { @@ -822,10 +814,6 @@ impl RenderBackend { debug_flags, namespace_alloc_by_client, recycler: Recycler::new(), - #[cfg(feature = "capture")] - capture_config: None, - #[cfg(feature = "replay")] - loaded_resource_sequence_id: 0, } } @@ -939,38 +927,97 @@ impl RenderBackend { while let Ok(msg) = self.scene_rx.try_recv() { match msg { - SceneBuilderResult::Transactions(txns, result_tx) => { - self.process_transaction( - txns, - result_tx, + SceneBuilderResult::Transactions(mut txns, result_tx) => { + self.prepare_for_frames(); + self.maybe_force_nop_documents( &mut frame_counter, &mut profile_counters, - ); - self.bookkeep_after_frames(); - }, - #[cfg(feature = "capture")] - SceneBuilderResult::CapturedTransactions(txns, capture_config, result_tx) => { - if let Some(ref mut old_config) = self.capture_config { - assert!(old_config.scene_id <= capture_config.scene_id); - if old_config.scene_id < capture_config.scene_id { - old_config.scene_id = capture_config.scene_id; - old_config.frame_id = 0; + |document_id| txns.iter().any(|txn| txn.document_id == document_id)); + + for mut txn in txns.drain(..) { + let has_built_scene = txn.built_scene.is_some(); + + if let Some(timings) = txn.timings { + if has_built_scene { + profile_counters.scene_changed = true; + } + + profile_counters.txn.set( + timings.builder_start_time_ns, + timings.builder_end_time_ns, + timings.send_time_ns, + timings.scene_build_start_time_ns, + timings.scene_build_end_time_ns, + timings.display_list_len, + ); } - } else { - self.capture_config = Some(capture_config); + + if let Some(doc) = self.documents.get_mut(&txn.document_id) { + + doc.removed_pipelines.append(&mut txn.removed_pipelines); + + if let Some(built_scene) = txn.built_scene.take() { + doc.new_async_scene_ready( + built_scene, + &mut self.recycler, + ); + } + + // If there are any additions or removals of clip modes + // during the scene build, apply them to the data store now. + // This needs to happen before we build the hit tester. + if let Some(updates) = txn.interner_updates.take() { + #[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, &mut profile_counters); + } + + + // Build the hit tester while the APZ lock is held so that its content + // is in sync with the gecko APZ tree. + if !doc.hit_tester_is_valid { + doc.rebuild_hit_tester(); + } + if let Some(ref tx) = result_tx { + let (resume_tx, resume_rx) = channel(); + tx.send(SceneSwapResult::Complete(resume_tx)).unwrap(); + // Block until the post-swap hook has completed on + // the scene builder thread. We need to do this before + // we can sample from the sampler hook which might happen + // in the update_document call below. + resume_rx.recv().ok(); + } + } else { + // The document was removed while we were building it, skip it. + // TODO: we might want to just ensure that removed documents are + // always forwarded to the scene builder thread to avoid this case. + if let Some(ref tx) = result_tx { + tx.send(SceneSwapResult::Aborted).unwrap(); + } + continue; + } + + self.resource_cache.add_rasterized_blob_images( + txn.rasterized_blobs.take(), + &mut profile_counters.resources.texture_cache, + ); + + self.update_document( + txn.document_id, + txn.resource_updates.take(), + txn.frame_ops.take(), + txn.notifications.take(), + txn.render_frame, + txn.invalidate_rendered_frame, + &mut frame_counter, + &mut profile_counters, + has_built_scene, + ); } - - let built_frame = self.process_transaction( - txns, - result_tx, - &mut frame_counter, - &mut profile_counters, - ); - - if built_frame { - self.save_capture_sequence(); - } - self.bookkeep_after_frames(); }, SceneBuilderResult::FlushComplete(tx) => { @@ -1041,107 +1088,6 @@ impl RenderBackend { } } - fn process_transaction( - &mut self, - mut txns: Vec>, - result_tx: Option>, - frame_counter: &mut u32, - profile_counters: &mut BackendProfileCounters, - ) -> bool { - self.prepare_for_frames(); - self.maybe_force_nop_documents( - frame_counter, - profile_counters, - |document_id| txns.iter().any(|txn| txn.document_id == document_id)); - - let mut built_frame = false; - for mut txn in txns.drain(..) { - let has_built_scene = txn.built_scene.is_some(); - - if let Some(timings) = txn.timings { - if has_built_scene { - profile_counters.scene_changed = true; - } - - profile_counters.txn.set( - timings.builder_start_time_ns, - timings.builder_end_time_ns, - timings.send_time_ns, - timings.scene_build_start_time_ns, - timings.scene_build_end_time_ns, - timings.display_list_len, - ); - } - - if let Some(doc) = self.documents.get_mut(&txn.document_id) { - doc.removed_pipelines.append(&mut txn.removed_pipelines); - - if let Some(built_scene) = txn.built_scene.take() { - doc.new_async_scene_ready( - built_scene, - &mut self.recycler, - ); - } - - // If there are any additions or removals of clip modes - // during the scene build, apply them to the data store now. - // This needs to happen before we build the hit tester. - if let Some(updates) = txn.interner_updates.take() { - #[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); - } - - // Build the hit tester while the APZ lock is held so that its content - // is in sync with the gecko APZ tree. - if !doc.hit_tester_is_valid { - doc.rebuild_hit_tester(); - } - - if let Some(ref tx) = result_tx { - let (resume_tx, resume_rx) = channel(); - tx.send(SceneSwapResult::Complete(resume_tx)).unwrap(); - // Block until the post-swap hook has completed on - // the scene builder thread. We need to do this before - // we can sample from the sampler hook which might happen - // in the update_document call below. - resume_rx.recv().ok(); - } - } else { - // The document was removed while we were building it, skip it. - // TODO: we might want to just ensure that removed documents are - // always forwarded to the scene builder thread to avoid this case. - if let Some(ref tx) = result_tx { - tx.send(SceneSwapResult::Aborted).unwrap(); - } - continue; - } - - self.resource_cache.add_rasterized_blob_images( - txn.rasterized_blobs.take(), - &mut profile_counters.resources.texture_cache, - ); - - built_frame |= self.update_document( - txn.document_id, - txn.resource_updates.take(), - txn.frame_ops.take(), - txn.notifications.take(), - txn.render_frame, - txn.invalidate_rendered_frame, - frame_counter, - profile_counters, - has_built_scene, - ); - } - - built_frame - } - fn process_api_msg( &mut self, msg: ApiMsg, @@ -1272,28 +1218,12 @@ impl RenderBackend { let output = self.save_capture(root, bits, profile_counters); ResultMsg::DebugOutput(output) }, - #[cfg(feature = "capture")] - DebugCommand::StartCaptureSequence(root, bits) => { - self.start_capture_sequence(root, bits); - return RenderBackendStatus::Continue; - }, - #[cfg(feature = "capture")] - DebugCommand::StopCaptureSequence => { - self.stop_capture_sequence(); - return RenderBackendStatus::Continue; - }, #[cfg(feature = "replay")] - DebugCommand::LoadCapture(path, ids, tx) => { + DebugCommand::LoadCapture(root, tx) => { NEXT_NAMESPACE_ID.fetch_add(1, Ordering::Relaxed); *frame_counter += 1; - let mut config = CaptureConfig::new(path, CaptureBits::all()); - if let Some((scene_id, frame_id)) = ids { - config.scene_id = scene_id; - config.frame_id = frame_id; - } - - self.load_capture(config, profile_counters); + self.load_capture(&root, profile_counters); for (id, doc) in &self.documents { let captured = CapturedDocument { @@ -1536,9 +1466,8 @@ impl RenderBackend { profile_counters, |document_id| txns.iter().any(|txn| txn.document_id == document_id)); - let mut built_frame = false; for mut txn in txns { - built_frame |= self.update_document( + self.update_document( txn.document_id, txn.resource_updates.take(), txn.frame_ops.take(), @@ -1550,10 +1479,7 @@ impl RenderBackend { false ); } - if built_frame { - #[cfg(feature = "capture")] - self.save_capture_sequence(); - } + self.bookkeep_after_frames(); return; } @@ -1583,10 +1509,8 @@ impl RenderBackend { .cloned() .filter(|key| !document_already_present(*key)) .collect(); - #[allow(unused_variables)] - let mut built_frame = false; for &document_id in &nop_documents { - built_frame |= self.update_document( + self.update_document( document_id, Vec::default(), Vec::default(), @@ -1597,11 +1521,6 @@ impl RenderBackend { profile_counters, false); } - #[cfg(feature = "capture")] - match built_frame { - true => self.save_capture_sequence(), - _ => {}, - } } } @@ -1616,7 +1535,7 @@ impl RenderBackend { frame_counter: &mut u32, profile_counters: &mut BackendProfileCounters, has_built_scene: bool, - ) -> bool { + ) { let requested_frame = render_frame; let requires_frame_build = self.requires_frame_build(); @@ -1738,26 +1657,6 @@ impl RenderBackend { } doc.prev_composite_descriptor = composite_descriptor; - #[cfg(feature = "capture")] - match self.capture_config { - Some(ref mut config) => { - // FIXME(aosmond): document splitting causes multiple prepare frames - config.prepare_frame(); - - if config.bits.contains(CaptureBits::FRAME) { - let file_name = format!("frame-{}-{}", document_id.namespace_id.0, document_id.id); - config.serialize_for_frame(&rendered_document.frame, file_name); - } - - let data_stores_name = format!("data-stores-{}-{}", document_id.namespace_id.0, document_id.id); - config.serialize_for_frame(&doc.data_stores, data_stores_name); - - let properties_name = format!("properties-{}-{}", document_id.namespace_id.0, document_id.id); - config.serialize_for_frame(&doc.dynamic_properties, properties_name); - }, - None => {}, - } - let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info()); self.result_tx.send(msg).unwrap(); @@ -1805,8 +1704,6 @@ impl RenderBackend { if !doc.hit_tester_is_valid { doc.rebuild_hit_tester(); } - - build_frame } #[cfg(not(feature = "debugger"))] @@ -1854,29 +1751,6 @@ impl RenderBackend { // thread waiting on the request. self.scene_tx.send(SceneBuilderRequest::ReportMemory(report, tx)).unwrap(); } - - #[cfg(feature = "capture")] - fn save_capture_sequence(&mut self) { - if let Some(ref mut config) = self.capture_config { - let deferred = self.resource_cache.save_capture_sequence(config); - - let backend = PlainRenderBackend { - default_device_pixel_ratio: self.default_device_pixel_ratio, - frame_config: self.frame_config.clone(), - resource_sequence_id: config.resource_id, - documents: self.documents - .iter() - .map(|(id, doc)| (*id, doc.view.clone())) - .collect(), - }; - config.serialize_for_frame(&backend, "backend"); - - if !deferred.is_empty() { - let msg = ResultMsg::DebugOutput(DebugOutput::SaveCapture(config.clone(), deferred)); - self.result_tx.send(msg).unwrap(); - } - } - } } fn get_blob_image_updates(updates: &[ResourceUpdate]) -> Vec { @@ -1909,6 +1783,7 @@ impl RenderBackend { profile_counters: &mut BackendProfileCounters, ) -> DebugOutput { use std::fs; + use crate::capture::CaptureConfig; use crate::render_task_graph::dump_render_tasks_as_svg; debug!("capture: saving {:?}", root); @@ -1942,17 +1817,19 @@ impl RenderBackend { // it has `pipeline_epoch_map`, // which may capture necessary details for some cases. let file_name = format!("frame-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_frame(&rendered_document.frame, file_name); + config.serialize(&rendered_document.frame, file_name); let file_name = format!("spatial-{}-{}", id.namespace_id.0, id.id); - config.serialize_tree_for_frame(&doc.scene.spatial_tree, file_name); + config.serialize_tree(&doc.scene.spatial_tree, file_name); let file_name = format!("built-primitives-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_frame(&doc.scene.prim_store, file_name); + config.serialize(&doc.scene.prim_store, file_name); let file_name = format!("built-clips-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_frame(&doc.scene.clip_store, file_name); + config.serialize(&doc.scene.clip_store, file_name); let file_name = format!("scratch-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_frame(&doc.scratch, file_name); + config.serialize(&doc.scratch, file_name); + let file_name = format!("properties-{}-{}", id.namespace_id.0, id.id); + config.serialize(&doc.dynamic_properties, file_name); let file_name = format!("render-tasks-{}-{}.svg", id.namespace_id.0, id.id); - let mut svg_file = fs::File::create(&config.file_path_for_frame(file_name, "svg")) + let mut svg_file = fs::File::create(&config.file_path(file_name, "svg")) .expect("Failed to open the SVG file."); dump_render_tasks_as_svg( &rendered_document.frame.render_tasks, @@ -1962,10 +1839,7 @@ impl RenderBackend { } let data_stores_name = format!("data-stores-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_frame(&doc.data_stores, data_stores_name); - - let properties_name = format!("properties-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_frame(&doc.dynamic_properties, properties_name); + config.serialize(&doc.data_stores, data_stores_name); } if config.bits.contains(CaptureBits::FRAME) { @@ -1991,15 +1865,14 @@ impl RenderBackend { let backend = PlainRenderBackend { default_device_pixel_ratio: self.default_device_pixel_ratio, frame_config: self.frame_config.clone(), - resource_sequence_id: 0, documents: self.documents .iter() .map(|(id, doc)| (*id, doc.view.clone())) .collect(), + resources, }; - config.serialize_for_frame(&backend, "backend"); - config.serialize_for_frame(&resources, "plain-resources"); + config.serialize(&backend, "backend"); if config.bits.contains(CaptureBits::FRAME) { let msg_update_resources = ResultMsg::UpdateResources { @@ -2010,86 +1883,47 @@ impl RenderBackend { // Save the texture/glyph/image caches. info!("\tresource cache"); let caches = self.resource_cache.save_caches(&config.root); - config.serialize_for_resource(&caches, "resource_cache"); + config.serialize(&caches, "resource_cache"); info!("\tgpu cache"); - config.serialize_for_resource(&self.gpu_cache, "gpu_cache"); + config.serialize(&self.gpu_cache, "gpu_cache"); } DebugOutput::SaveCapture(config, deferred) } - #[cfg(feature = "capture")] - fn start_capture_sequence( - &mut self, - root: PathBuf, - bits: CaptureBits, - ) { - self.scene_tx.send(SceneBuilderRequest::StartCaptureSequence(CaptureConfig::new(root, bits))).unwrap(); - } - - #[cfg(feature = "capture")] - fn stop_capture_sequence( - &mut self, - ) { - self.scene_tx.send(SceneBuilderRequest::StopCaptureSequence).unwrap(); - } - #[cfg(feature = "replay")] fn load_capture( &mut self, - mut config: CaptureConfig, + root: &PathBuf, profile_counters: &mut BackendProfileCounters, ) { - debug!("capture: loading {:?}", config.frame_root()); - let backend = config.deserialize_for_frame::("backend") + use crate::capture::CaptureConfig; + + debug!("capture: loading {:?}", root); + let backend = CaptureConfig::deserialize::(root, "backend") .expect("Unable to open backend.ron"); + let caches_maybe = CaptureConfig::deserialize::(root, "resource_cache"); - // If this is a capture sequence, then the ID will be non-zero, and won't - // match what is loaded, but for still captures, the ID will be zero. - let first_load = backend.resource_sequence_id == 0; - if self.loaded_resource_sequence_id != backend.resource_sequence_id || first_load { - // FIXME(aosmond): We clear the documents because when we update the - // resource cache, we actually wipe and reload, because we don't - // know what is the same and what has changed. If we were to keep as - // much of the resource cache state as possible, we could avoid - // flushing the document state (which has its own dependecies on the - // cache). - // - // FIXME(aosmond): If we try to load the next capture in the - // sequence too quickly, we may lose resources we depend on in the - // current frame. This can cause panics. Ideally we would not - // advance to the next frame until the FrameRendered event for all - // of the pipelines. - self.documents.clear(); + // Note: it would be great to have `RenderBackend` to be split + // rather explicitly on what's used before and after scene building + // so that, for example, we never miss anything in the code below: - config.resource_id = backend.resource_sequence_id; - self.loaded_resource_sequence_id = backend.resource_sequence_id; + let plain_externals = self.resource_cache.load_capture( + backend.resources, + caches_maybe, + root, + ); + let msg_load = ResultMsg::DebugOutput( + DebugOutput::LoadCapture(root.clone(), plain_externals) + ); + self.result_tx.send(msg_load).unwrap(); - let plain_resources = config.deserialize_for_resource::("plain-resources") - .expect("Unable to open plain-resources.ron"); - let caches_maybe = config.deserialize_for_resource::("resource_cache"); - - // Note: it would be great to have `RenderBackend` to be split - // rather explicitly on what's used before and after scene building - // so that, for example, we never miss anything in the code below: - - let plain_externals = self.resource_cache.load_capture( - plain_resources, - caches_maybe, - &config, - ); - - let msg_load = ResultMsg::DebugOutput( - DebugOutput::LoadCapture(config.clone(), plain_externals) - ); - self.result_tx.send(msg_load).unwrap(); - - self.gpu_cache = match config.deserialize_for_resource::("gpu_cache") { - Some(gpu_cache) => gpu_cache, - None => GpuCache::new(), - }; - } + self.gpu_cache = match CaptureConfig::deserialize::(root, "gpu_cache") { + Some(gpu_cache) => gpu_cache, + None => GpuCache::new(), + }; + self.documents.clear(); self.default_device_pixel_ratio = backend.default_device_pixel_ratio; self.frame_config = backend.frame_config; @@ -2098,64 +1932,41 @@ impl RenderBackend { for (id, view) in backend.documents { debug!("\tdocument {:?}", id); let scene_name = format!("scene-{}-{}", id.namespace_id.0, id.id); - let scene = config.deserialize_for_scene::(&scene_name) + let scene = CaptureConfig::deserialize::(root, &scene_name) .expect(&format!("Unable to open {}.ron", scene_name)); let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id); - let interners = config.deserialize_for_scene::(&interners_name) + let interners = CaptureConfig::deserialize::(root, &interners_name) .expect(&format!("Unable to open {}.ron", interners_name)); let data_stores_name = format!("data-stores-{}-{}", id.namespace_id.0, id.id); - let data_stores = config.deserialize_for_frame::(&data_stores_name) + let data_stores = CaptureConfig::deserialize::(root, &data_stores_name) .expect(&format!("Unable to open {}.ron", data_stores_name)); - let properties_name = format!("properties-{}-{}", id.namespace_id.0, id.id); - let properties = config.deserialize_for_frame::(&properties_name) - .expect(&format!("Unable to open {}.ron", properties_name)); - - // Update the document if it still exists, rather than replace it entirely. - // This allows us to preserve state information such as the frame stamp, - // which is necessary for cache sanity. - match self.documents.entry(id) { - Occupied(entry) => { - let doc = entry.into_mut(); - doc.view = view.clone(); - doc.loaded_scene = scene.clone(); - doc.data_stores = data_stores; - doc.dynamic_properties = properties; - doc.frame_is_valid = false; - doc.rendered_frame_is_valid = false; - doc.has_built_scene = false; - doc.hit_tester_is_valid = false; - } - Vacant(entry) => { - let doc = Document { - id, - scene: BuiltScene::empty(), - removed_pipelines: Vec::new(), - view: view.clone(), - stamp: FrameStamp::first(id), - frame_builder: FrameBuilder::new(), - output_pipelines: FastHashSet::default(), - dynamic_properties: properties, - hit_tester: None, - shared_hit_tester: Arc::new(SharedHitTester::new()), - frame_is_valid: false, - hit_tester_is_valid: false, - rendered_frame_is_valid: false, - has_built_scene: false, - data_stores, - scratch: PrimitiveScratchBuffer::new(), - render_task_counters: RenderTaskGraphCounters::new(), - loaded_scene: scene.clone(), - prev_composite_descriptor: CompositeDescriptor::empty(), - }; - entry.insert(doc); - } + let doc = Document { + id, + scene: BuiltScene::empty(), + removed_pipelines: Vec::new(), + view: view.clone(), + stamp: FrameStamp::first(id), + frame_builder: FrameBuilder::new(), + output_pipelines: FastHashSet::default(), + dynamic_properties: SceneProperties::new(), + hit_tester: None, + shared_hit_tester: Arc::new(SharedHitTester::new()), + frame_is_valid: false, + hit_tester_is_valid: false, + rendered_frame_is_valid: false, + has_built_scene: false, + data_stores, + scratch: PrimitiveScratchBuffer::new(), + render_task_counters: RenderTaskGraphCounters::new(), + loaded_scene: scene.clone(), + prev_composite_descriptor: CompositeDescriptor::empty(), }; let frame_name = format!("frame-{}-{}", id.namespace_id.0, id.id); - let frame = config.deserialize_for_frame::(frame_name); + let frame = CaptureConfig::deserialize::(root, frame_name); let build_frame = match frame { Some(frame) => { info!("\tloaded a built frame with {} passes", frame.passes.len()); @@ -2186,11 +1997,13 @@ impl RenderBackend { scene, view: view.clone(), config: self.frame_config.clone(), - output_pipelines: self.documents[&id].output_pipelines.clone(), + output_pipelines: doc.output_pipelines.clone(), font_instances: self.resource_cache.get_font_instances(), build_frame, interners, }); + + self.documents.insert(id, doc); } if !scenes_to_build.is_empty() { diff --git a/gfx/wr/webrender/src/renderer.rs b/gfx/wr/webrender/src/renderer.rs index 91bf1abcabe1..f92ce7f3e05c 100644 --- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -2890,9 +2890,9 @@ impl Renderer { self.save_capture(config, deferred); } #[cfg(feature = "replay")] - DebugOutput::LoadCapture(config, plain_externals) => { + DebugOutput::LoadCapture(root, plain_externals) => { self.active_documents.clear(); - self.load_capture(config, plain_externals); + self.load_capture(root, plain_externals); } }, ResultMsg::DebugCommand(command) => { @@ -3132,9 +3132,7 @@ impl Renderer { self.debug_server.send(json); } DebugCommand::SaveCapture(..) | - DebugCommand::LoadCapture(..) | - DebugCommand::StartCaptureSequence(..) | - DebugCommand::StopCaptureSequence => { + DebugCommand::LoadCapture(..) => { panic!("Capture commands are not welcome here! Did you build with 'capture' feature?") } DebugCommand::ClearCaches(_) @@ -6929,13 +6927,7 @@ struct PlainRenderer { gpu_cache: PlainTexture, gpu_cache_frame_id: FrameId, textures: FastHashMap, -} - -#[cfg(any(feature = "capture", feature = "replay"))] -#[cfg_attr(feature = "capture", derive(Serialize))] -#[cfg_attr(feature = "replay", derive(Deserialize))] -struct PlainExternalResources { - images: Vec + external_images: Vec } #[cfg(feature = "replay")] @@ -7083,13 +7075,11 @@ impl Renderer { use std::io::Write; use api::{CaptureBits, ExternalImageData}; - let root = config.resource_root(); - self.device.begin_frame(); let _gm = self.gpu_profile.start_marker("read GPU data"); self.device.bind_read_target_impl(self.read_fbo); - if config.bits.contains(CaptureBits::EXTERNAL_RESOURCES) && !deferred_images.is_empty() { + if !deferred_images.is_empty() { info!("saving external images"); let mut arc_map = FastHashMap::<*const u8, String>::default(); let mut tex_map = FastHashMap::::default(); @@ -7140,13 +7130,13 @@ impl Renderer { } }; if let Some(bytes) = data { - fs::File::create(root.join(&short_path)) + fs::File::create(config.root.join(&short_path)) .expect(&format!("Unable to create {}", short_path)) .write_all(&bytes) .unwrap(); #[cfg(feature = "png")] CaptureConfig::save_png( - root.join(&short_path).with_extension("png"), + config.root.join(&short_path).with_extension("png"), def.descriptor.size, def.descriptor.format, def.descriptor.stride, @@ -7158,19 +7148,15 @@ impl Renderer { external: def.external, uv: ext_image.uv, }; - config.serialize_for_resource(&plain, &def.short_path); + config.serialize(&plain, &def.short_path); } for def in &deferred_images { handler.unlock(def.external.id, def.external.channel_index); } - let plain_external = PlainExternalResources { - images: deferred_images, - }; - config.serialize_for_resource(&plain_external, "external_resources"); } if config.bits.contains(CaptureBits::FRAME) { - let path_textures = root.join("textures"); + let path_textures = config.root.join("textures"); if !path_textures.is_dir() { fs::create_dir(&path_textures).unwrap(); } @@ -7181,21 +7167,22 @@ impl Renderer { device_size: self.device_size, gpu_cache: Self::save_texture( &self.gpu_cache_texture.texture.as_ref().unwrap(), - "gpu", &root, &mut self.device, + "gpu", &config.root, &mut self.device, ), gpu_cache_frame_id: self.gpu_cache_frame_id, textures: FastHashMap::default(), + external_images: deferred_images, }; info!("saving cached textures"); for (id, texture) in &self.texture_resolver.texture_cache_map { let file_name = format!("cache-{}", plain_self.textures.len() + 1); info!("\t{}", file_name); - let plain = Self::save_texture(texture, &file_name, &root, &mut self.device); + let plain = Self::save_texture(texture, &file_name, &config.root, &mut self.device); plain_self.textures.insert(*id, plain); } - config.serialize_for_resource(&plain_self, "renderer"); + config.serialize(&plain_self, "renderer"); } self.device.reset_read_target(); @@ -7205,9 +7192,7 @@ impl Renderer { #[cfg(feature = "replay")] fn load_capture( - &mut self, - config: CaptureConfig, - plain_externals: Vec, + &mut self, root: PathBuf, plain_externals: Vec ) { use std::fs::File; use std::io::Read; @@ -7220,8 +7205,6 @@ impl Renderer { data: FastHashMap::default(), }; - let root = config.resource_root(); - // Note: this is a `SCENE` level population of the external image handlers // It would put both external buffers and texture into the map. // But latter are going to be overwritten later in this function @@ -7243,49 +7226,7 @@ impl Renderer { image_handler.data.insert((ext.id, ext.channel_index), value); } - if let Some(external_resources) = config.deserialize_for_resource::("external_resources") { - info!("loading external texture-backed images"); - let mut native_map = FastHashMap::::default(); - for ExternalCaptureImage { short_path, external, descriptor } in external_resources.images { - let target = match external.image_type { - ExternalImageType::TextureHandle(target) => target, - ExternalImageType::Buffer => continue, - }; - let plain_ext = config.deserialize_for_resource::(&short_path) - .expect(&format!("Unable to read {}.ron", short_path)); - let key = (external.id, external.channel_index); - - let tid = match native_map.entry(plain_ext.data) { - Entry::Occupied(e) => e.get().clone(), - Entry::Vacant(e) => { - //TODO: provide a way to query both the layer count and the filter from external images - let (layer_count, filter) = (1, TextureFilter::Linear); - let plain_tex = PlainTexture { - data: e.key().clone(), - size: (descriptor.size, layer_count), - format: descriptor.format, - filter, - has_depth: false, - }; - let t = Self::load_texture( - target, - &plain_tex, - None, - &root, - &mut self.device - ); - let extex = t.0.into_external(); - self.owned_external_images.insert(key, extex.clone()); - e.insert(extex.internal_id()).clone() - } - }; - - let value = (CapturedExternalImageData::NativeTexture(tid), plain_ext.uv); - image_handler.data.insert(key, value); - } - } - - if let Some(renderer) = config.deserialize_for_resource::("renderer") { + if let Some(renderer) = CaptureConfig::deserialize::(&root, "renderer") { info!("loading cached textures"); self.device_size = renderer.device_size; self.device.begin_frame(); @@ -7339,18 +7280,46 @@ impl Renderer { } self.gpu_cache_frame_id = renderer.gpu_cache_frame_id; - self.device.end_frame(); - } else { - info!("loading cached textures"); - self.device.begin_frame(); - for (_id, texture) in self.texture_resolver.texture_cache_map.drain() { - self.device.delete_texture(texture); + info!("loading external texture-backed images"); + let mut native_map = FastHashMap::::default(); + for ExternalCaptureImage { short_path, external, descriptor } in renderer.external_images { + let target = match external.image_type { + ExternalImageType::TextureHandle(target) => target, + ExternalImageType::Buffer => continue, + }; + let plain_ext = CaptureConfig::deserialize::(&root, &short_path) + .expect(&format!("Unable to read {}.ron", short_path)); + let key = (external.id, external.channel_index); + + let tid = match native_map.entry(plain_ext.data) { + Entry::Occupied(e) => e.get().clone(), + Entry::Vacant(e) => { + //TODO: provide a way to query both the layer count and the filter from external images + let (layer_count, filter) = (1, TextureFilter::Linear); + let plain_tex = PlainTexture { + data: e.key().clone(), + size: (descriptor.size, layer_count), + format: descriptor.format, + filter, + has_depth: false, + }; + let t = Self::load_texture( + target, + &plain_tex, + None, + &root, + &mut self.device + ); + let extex = t.0.into_external(); + self.owned_external_images.insert(key, extex.clone()); + e.insert(extex.internal_id()).clone() + } + }; + + let value = (CapturedExternalImageData::NativeTexture(tid), plain_ext.uv); + image_handler.data.insert(key, value); } - info!("loading gpu cache"); - if let Some(t) = self.gpu_cache_texture.texture.take() { - self.device.delete_texture(t); - } self.device.end_frame(); } diff --git a/gfx/wr/webrender/src/resource_cache.rs b/gfx/wr/webrender/src/resource_cache.rs index 1364e0c15204..501600c28506 100644 --- a/gfx/wr/webrender/src/resource_cache.rs +++ b/gfx/wr/webrender/src/resource_cache.rs @@ -15,7 +15,7 @@ use api::units::*; use crate::capture::ExternalCaptureImage; #[cfg(feature = "replay")] use crate::capture::PlainExternalImage; -#[cfg(any(feature = "replay", feature = "png", feature="capture"))] +#[cfg(any(feature = "replay", feature = "png"))] use crate::capture::CaptureConfig; use crate::composite::{NativeSurfaceId, NativeSurfaceOperation, NativeTileId, NativeSurfaceOperationDetails}; use crate::device::TextureFilter; @@ -459,12 +459,6 @@ pub struct ResourceCache { state: State, current_frame_id: FrameId, - #[cfg(feature = "capture")] - /// Used for capture sequences. If the resource cache is updated, then we - /// mark it as dirty. When the next frame is captured in the sequence, we - /// dump the state of the resource cache. - capture_dirty: bool, - pub texture_cache: TextureCache, /// TODO(gw): We should expire (parts of) this cache semi-regularly! @@ -512,8 +506,6 @@ impl ResourceCache { // We want to keep three frames worth of delete blob keys deleted_blob_keys: vec![Vec::new(), Vec::new(), Vec::new()].into(), pending_native_surface_updates: Vec::new(), - #[cfg(feature = "capture")] - capture_dirty: true, } } @@ -576,11 +568,6 @@ impl ResourceCache { // TODO, there is potential for optimization here, by processing updates in // bulk rather than one by one (for example by sorting allocations by size or // in a way that reduces fragmentation in the atlas). - #[cfg(feature = "capture")] - match updates.is_empty() { - false => self.capture_dirty = true, - _ => {}, - } for update in updates { match update { @@ -646,12 +633,6 @@ impl ResourceCache { updates: &mut Vec, profile_counters: &mut ResourceProfileCounters, ) { - #[cfg(feature = "capture")] - match updates.is_empty() { - false => self.capture_dirty = true, - _ => {}, - } - for update in updates.iter() { match *update { ResourceUpdate::AddBlobImage(ref img) => { @@ -2017,7 +1998,7 @@ impl ResourceCache { &mut self, resources: PlainResources, caches: Option, - config: &CaptureConfig, + root: &PathBuf, ) -> Vec { use std::{fs, path::Path}; @@ -2059,7 +2040,6 @@ impl ResourceCache { res.image_templates.images.clear(); info!("\tfont templates..."); - let root = config.resource_root(); let native_font_replacement = Arc::new(NATIVE_FONT.to_vec()); for (key, plain_template) in resources.font_templates { let arc = match raw_map.entry(plain_template.data) { @@ -2091,7 +2071,7 @@ impl ResourceCache { info!("\timage templates..."); let mut external_images = Vec::new(); for (key, template) in resources.image_templates { - let data = match config.deserialize_for_resource::(&template.data) { + let data = match CaptureConfig::deserialize::(root, &template.data) { Some(plain) => { let ext_data = plain.external; external_images.push(plain); @@ -2124,19 +2104,6 @@ impl ResourceCache { external_images } - - #[cfg(feature = "capture")] - pub fn save_capture_sequence(&mut self, config: &mut CaptureConfig) -> Vec { - if self.capture_dirty { - self.capture_dirty = false; - config.prepare_resource(); - let (resources, deferred) = self.save_capture(&config.resource_root()); - config.serialize_for_resource(&resources, "plain-resources.ron"); - deferred - } else { - Vec::new() - } - } } /// For now the blob's coordinate space have the same pixel sizes as the diff --git a/gfx/wr/webrender/src/scene_builder_thread.rs b/gfx/wr/webrender/src/scene_builder_thread.rs index 385fc226de16..180bcf091934 100644 --- a/gfx/wr/webrender/src/scene_builder_thread.rs +++ b/gfx/wr/webrender/src/scene_builder_thread.rs @@ -7,7 +7,7 @@ use api::{DocumentId, PipelineId, ApiMsg, FrameMsg, ResourceUpdate, ExternalEven use api::{BuiltDisplayList, ColorF, NotificationRequest, Checkpoint, IdNamespace}; use api::{ClipIntern, FilterDataIntern, MemoryReport, PrimitiveKeyKind}; use api::units::LayoutSize; -#[cfg(any(feature = "capture", feature = "replay"))] +#[cfg(feature = "capture")] use crate::capture::CaptureConfig; use crate::frame_builder::FrameBuilderConfig; use crate::scene_building::SceneBuilder; @@ -161,18 +161,12 @@ pub enum SceneBuilderRequest { SaveScene(CaptureConfig), #[cfg(feature = "replay")] LoadScenes(Vec), - #[cfg(feature = "capture")] - StartCaptureSequence(CaptureConfig), - #[cfg(feature = "capture")] - StopCaptureSequence, DocumentsForDebugger } // Message from scene builder to render backend. pub enum SceneBuilderResult { Transactions(Vec>, Option>), - #[cfg(feature = "capture")] - CapturedTransactions(Vec>, CaptureConfig, Option>), ExternalEvent(ExternalEvent), FlushComplete(Sender<()>), ClearNamespace(IdNamespace), @@ -273,9 +267,7 @@ pub struct SceneBuilderThread { size_of_ops: Option, hooks: Option>, simulate_slow_ms: u32, - removed_pipelines: FastHashSet, - #[cfg(feature = "capture")] - capture_config: Option, + removed_pipelines: FastHashSet } pub struct SceneBuilderThreadChannels { @@ -321,8 +313,6 @@ impl SceneBuilderThread { hooks, simulate_slow_ms: 0, removed_pipelines: FastHashSet::default(), - #[cfg(feature = "capture")] - capture_config: None, } } @@ -353,11 +343,6 @@ impl SceneBuilderThread { let built_txns : Vec> = txns.iter_mut() .map(|txn| self.process_transaction(txn)) .collect(); - #[cfg(feature = "capture")] - match built_txns.iter().any(|txn| txn.built_scene.is_some()) { - true => self.save_capture_sequence(), - _ => {}, - } self.forward_built_transactions(built_txns); } Ok(SceneBuilderRequest::DeleteDocument(document_id)) => { @@ -378,16 +363,6 @@ impl SceneBuilderThread { Ok(SceneBuilderRequest::SaveScene(config)) => { self.save_scene(config); } - #[cfg(feature = "capture")] - Ok(SceneBuilderRequest::StartCaptureSequence(config)) => { - self.start_capture_sequence(config); - } - #[cfg(feature = "capture")] - Ok(SceneBuilderRequest::StopCaptureSequence) => { - // FIXME(aosmond): clear config for frames and resource cache without scene - // rebuild? - self.capture_config = None; - } Ok(SceneBuilderRequest::DocumentsForDebugger) => { let json = self.get_docs_for_debugger(); self.send(SceneBuilderResult::DocumentsForDebugger(json)); @@ -431,11 +406,11 @@ impl SceneBuilderThread { fn save_scene(&mut self, config: CaptureConfig) { for (id, doc) in &self.documents { let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_scene(&doc.interners, interners_name); + config.serialize(&doc.interners, interners_name); if config.bits.contains(api::CaptureBits::SCENE) { let file_name = format!("scene-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_scene(&doc.scene, file_name); + config.serialize(&doc.scene, file_name); } } } @@ -496,33 +471,6 @@ impl SceneBuilderThread { } } - #[cfg(feature = "capture")] - fn save_capture_sequence( - &mut self, - ) { - if let Some(ref mut config) = self.capture_config { - config.prepare_scene(); - for (id, doc) in &self.documents { - let interners_name = format!("interners-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_scene(&doc.interners, interners_name); - - if config.bits.contains(api::CaptureBits::SCENE) { - let file_name = format!("scene-{}-{}", id.namespace_id.0, id.id); - config.serialize_for_scene(&doc.scene, file_name); - } - } - } - } - - #[cfg(feature = "capture")] - fn start_capture_sequence( - &mut self, - config: CaptureConfig, - ) { - self.capture_config = Some(config); - self.save_capture_sequence(); - } - #[cfg(feature = "debugger")] fn traverse_items<'a>( &self, @@ -740,13 +688,6 @@ impl SceneBuilderThread { Vec::new() }; - #[cfg(feature = "capture")] - match self.capture_config { - Some(ref config) => self.tx.send(SceneBuilderResult::CapturedTransactions(txns, config.clone(), result_tx)).unwrap(), - None => self.tx.send(SceneBuilderResult::Transactions(txns, result_tx)).unwrap(), - } - - #[cfg(not(feature = "capture"))] self.tx.send(SceneBuilderResult::Transactions(txns, result_tx)).unwrap(); let _ = self.api_tx.send(ApiMsg::WakeUp); diff --git a/gfx/wr/webrender_api/src/api.rs b/gfx/wr/webrender_api/src/api.rs index d86a4f823c40..045051f68e02 100644 --- a/gfx/wr/webrender_api/src/api.rs +++ b/gfx/wr/webrender_api/src/api.rs @@ -913,8 +913,6 @@ bitflags!{ const FRAME = 0x2; /// const TILE_CACHE = 0x4; - /// - const EXTERNAL_RESOURCES = 0x8; } } @@ -969,11 +967,7 @@ pub enum DebugCommand { SaveCapture(PathBuf, CaptureBits), /// Load a capture of all the documents state. #[serde(skip_serializing, skip_deserializing)] - LoadCapture(PathBuf, Option<(u32, u32)>, Sender), - /// Start capturing a sequence of scene/frame changes. - StartCaptureSequence(PathBuf, CaptureBits), - /// Stop capturing a sequence of scene/frame changes. - StopCaptureSequence, + LoadCapture(PathBuf, Sender), /// Clear cached resources, forcing them to be re-uploaded from templates. ClearCaches(ClearCache), /// Enable/disable native compositor usage @@ -1738,13 +1732,13 @@ impl RenderApi { } /// Load a capture of the current frame state for debugging. - pub fn load_capture(&self, path: PathBuf, ids: Option<(u32, u32)>) -> Vec { + pub fn load_capture(&self, path: PathBuf) -> Vec { // First flush the scene builder otherwise async scenes might clobber // the capture we are about to load. self.flush_scene_builder(); let (tx, rx) = channel(); - let msg = ApiMsg::DebugCommand(DebugCommand::LoadCapture(path, ids, tx)); + let msg = ApiMsg::DebugCommand(DebugCommand::LoadCapture(path, tx)); self.send_message(msg); let mut documents = Vec::new(); @@ -1754,18 +1748,6 @@ impl RenderApi { documents } - /// Start capturing a sequence of frames. - pub fn start_capture_sequence(&self, path: PathBuf, bits: CaptureBits) { - let msg = ApiMsg::DebugCommand(DebugCommand::StartCaptureSequence(path, bits)); - self.send_message(msg); - } - - /// Stop capturing sequences of frames. - pub fn stop_capture_sequence(&self) { - let msg = ApiMsg::DebugCommand(DebugCommand::StopCaptureSequence); - self.send_message(msg); - } - /// Update the state of builtin debugging facilities. pub fn send_debug_cmd(&self, cmd: DebugCommand) { let msg = ApiMsg::DebugCommand(cmd); diff --git a/gfx/wr/wrench/src/args.yaml b/gfx/wr/wrench/src/args.yaml index cc0262990236..b96b853b30d0 100644 --- a/gfx/wr/wrench/src/args.yaml +++ b/gfx/wr/wrench/src/args.yaml @@ -143,16 +143,6 @@ subcommands: long: keyframes takes_value: true help: Provide a keyframes file, that can be used to animate the yaml input file - - scene-id: - short: s - long: scene-id - takes_value: true - help: Select a starting scene sequence ID (YAML capture sequence only). - - frame-id: - short: f - long: frame-id - takes_value: true - help: Select a starting frame sequence ID (YAML capture sequence only). - INPUT: help: The input YAML, binary recording, or capture directory required: true diff --git a/gfx/wr/wrench/src/main.rs b/gfx/wr/wrench/src/main.rs index 55a138e0dc26..8150f5424851 100644 --- a/gfx/wr/wrench/src/main.rs +++ b/gfx/wr/wrench/src/main.rs @@ -54,7 +54,7 @@ use webrender::api::*; use webrender::api::units::*; use winit::dpi::{LogicalPosition, LogicalSize}; use winit::VirtualKeyCode; -use crate::wrench::{CapturedSequence, Wrench, WrenchThing}; +use crate::wrench::{Wrench, WrenchThing}; use crate::yaml_frame_reader::YamlFrameReader; pub const PLATFORM_DEFAULT_FACE_NAME: &str = "Arial"; @@ -764,18 +764,13 @@ fn render<'a>( let input_path = subargs.value_of("INPUT").map(PathBuf::from).unwrap(); // If the input is a directory, we are looking at a capture. - let mut thing = if input_path.join("scenes").as_path().is_dir() { - let scene_id = subargs.value_of("scene-id").map(|z| z.parse::().unwrap()); - let frame_id = subargs.value_of("frame-id").map(|z| z.parse::().unwrap()); - Box::new(CapturedSequence::new( - input_path, - scene_id.unwrap_or(1), - frame_id.unwrap_or(1), - )) - } else if input_path.as_path().is_dir() { - let mut documents = wrench.api.load_capture(input_path, None); + let mut thing = if input_path.as_path().is_dir() { + let mut documents = wrench.api.load_capture(input_path); println!("loaded {:?}", documents.iter().map(|cd| cd.document_id).collect::>()); let captured = documents.swap_remove(0); + if let Some(fb_size) = wrench.renderer.device_size() { + window.resize(fb_size); + } wrench.document_id = captured.document_id; Box::new(captured) as Box } else { @@ -799,10 +794,6 @@ fn render<'a>( window.update(wrench); thing.do_frame(wrench); - if let Some(fb_size) = wrench.renderer.device_size() { - window.resize(fb_size); - } - let mut debug_flags = DebugFlags::empty(); debug_flags.set(DebugFlags::DISABLE_BATCHING, no_batch); diff --git a/gfx/wr/wrench/src/rawtest.rs b/gfx/wr/wrench/src/rawtest.rs index ebdd2ea56eb4..bbd04eb25d9b 100644 --- a/gfx/wr/wrench/src/rawtest.rs +++ b/gfx/wr/wrench/src/rawtest.rs @@ -1288,7 +1288,7 @@ impl<'a> RawtestHarness<'a> { // 4. load the first one - let mut documents = self.wrench.api.load_capture(path.into(), None); + let mut documents = self.wrench.api.load_capture(path.into()); let captured = documents.swap_remove(0); // 5. render the built frame and compare diff --git a/gfx/wr/wrench/src/wrench.rs b/gfx/wr/wrench/src/wrench.rs index 061c7f0270e6..c5775e97ed1c 100644 --- a/gfx/wr/wrench/src/wrench.rs +++ b/gfx/wr/wrench/src/wrench.rs @@ -140,71 +140,6 @@ impl WrenchThing for CapturedDocument { } } -pub struct CapturedSequence { - root: PathBuf, - frame: usize, - frame_set: Vec<(u32, u32)>, -} - -impl CapturedSequence { - pub fn new(root: PathBuf, scene_start: u32, frame_start: u32) -> Self { - // Build set of a scene and frame IDs. - let mut scene = scene_start; - let mut frame = frame_start; - let mut frame_set = Vec::new(); - while Self::scene_root(&root, scene).as_path().is_dir() { - while Self::frame_root(&root, scene, frame).as_path().is_dir() { - frame_set.push((scene, frame)); - frame += 1; - } - scene += 1; - frame = 1; - } - - assert!(!frame_set.is_empty()); - - Self { - root, - frame: 0, - frame_set, - } - } - - fn scene_root(root: &PathBuf, scene: u32) -> PathBuf { - let path = format!("scenes/{:05}", scene); - root.join(path) - } - - fn frame_root(root: &PathBuf, scene: u32, frame: u32) -> PathBuf { - let path = format!("scenes/{:05}/frames/{:05}", scene, frame); - root.join(path) - } -} - -impl WrenchThing for CapturedSequence { - fn next_frame(&mut self) { - if self.frame + 1 < self.frame_set.len() { - self.frame += 1; - } - } - - fn prev_frame(&mut self) { - if self.frame > 0 { - self.frame -= 1; - } - } - - fn do_frame(&mut self, wrench: &mut Wrench) -> u32 { - let mut documents = wrench.api.load_capture(self.root.clone(), Some(self.frame_set[self.frame])); - println!("loaded {:?} from {:?}", - documents.iter().map(|cd| cd.document_id).collect::>(), - self.frame_set[self.frame]); - let captured = documents.swap_remove(0); - wrench.document_id = captured.document_id; - self.frame as u32 - } -} - pub struct Wrench { window_size: DeviceIntSize, pub device_pixel_ratio: f32,