From dcba2bb0155025ffaaff187c810f512122bab418 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Mon, 22 Dec 2025 16:46:30 +0800 Subject: [PATCH] Synchronously requests current epoch. Signed-off-by: Shubham Gupta --- example-compositor/compositor/src/main.rs | 2 +- examples/common/boilerplate.rs | 2 +- webrender/src/internal_types.rs | 3 +- webrender/src/render_api.rs | 18 ++++++++ webrender/src/render_backend.rs | 34 +++------------ webrender/src/renderer/init.rs | 1 - webrender/src/renderer/mod.rs | 30 ++++--------- webrender/src/scene_builder_thread.rs | 52 +++++++++++++++-------- wrench/src/wrench.rs | 2 +- 9 files changed, 71 insertions(+), 73 deletions(-) diff --git a/example-compositor/compositor/src/main.rs b/example-compositor/compositor/src/main.rs index c5d9f1a8ed..d7d45c3052 100644 --- a/example-compositor/compositor/src/main.rs +++ b/example-compositor/compositor/src/main.rs @@ -498,7 +498,7 @@ fn main() { // as required. renderer.update(); renderer.render(device_size, 0).unwrap(); - let _ = renderer.flush_pipeline_info(); + let _ = api.flush_pipeline_info(); // Construct a simple display list that can be drawn and composited by DC. let mut txn = Transaction::new(); diff --git a/examples/common/boilerplate.rs b/examples/common/boilerplate.rs index 8a7d552535..a6d4247925 100644 --- a/examples/common/boilerplate.rs +++ b/examples/common/boilerplate.rs @@ -312,7 +312,7 @@ pub fn main_wrapper( renderer.update(); renderer.render(device_size, 0).unwrap(); - let _ = renderer.flush_pipeline_info(); + let _ = api.flush_pipeline_info(); example.draw_custom(&*gl); windowed_context.swap_buffers().ok(); diff --git a/webrender/src/internal_types.rs b/webrender/src/internal_types.rs index f18eef7968..e25c5de00a 100644 --- a/webrender/src/internal_types.rs +++ b/webrender/src/internal_types.rs @@ -9,7 +9,7 @@ use api::units::*; use crate::render_api::DebugCommand; use crate::composite::NativeSurfaceOperation; use crate::device::TextureFilter; -use crate::renderer::{FullFrameStats, PipelineInfo}; +use crate::renderer::FullFrameStats; use crate::gpu_cache::GpuCacheUpdateList; use crate::gpu_types::BlurEdgeMode; use crate::frame_builder::Frame; @@ -1366,7 +1366,6 @@ pub enum ResultMsg { resource_updates: ResourceUpdateList, memory_pressure: bool, }, - PublishPipelineInfo(PipelineInfo), PublishDocument( FramePublishId, DocumentId, diff --git a/webrender/src/render_api.rs b/webrender/src/render_api.rs index 48ee79cf8a..630f483f3b 100644 --- a/webrender/src/render_api.rs +++ b/webrender/src/render_api.rs @@ -25,6 +25,7 @@ use crate::api::DEFAULT_TILE_SIZE; use crate::api::units::*; use crate::api_resources::ApiResources; use glyph_rasterizer::SharedFontResources; +use crate::renderer::PipelineInfo; use crate::scene_builder_thread::{SceneBuilderRequest, SceneBuilderResult}; use crate::intern::InterningMemoryReport; use crate::profiler::{self, TransactionProfile}; @@ -1010,6 +1011,8 @@ pub enum ApiMsg { DebugCommand(DebugCommand), /// Message from the scene builder thread. SceneBuilderResult(SceneBuilderResult), + /// Request pipeline infos. + RequestPipelineInfo(Sender), } impl fmt::Debug for ApiMsg { @@ -1023,6 +1026,7 @@ impl fmt::Debug for ApiMsg { ApiMsg::ReportMemory(..) => "ApiMsg::ReportMemory", ApiMsg::DebugCommand(..) => "ApiMsg::DebugCommand", ApiMsg::SceneBuilderResult(..) => "ApiMsg::SceneBuilderResult", + ApiMsg::RequestPipelineInfo(..) => "ApiMsg::RequestPipelineInfo", }) } } @@ -1454,6 +1458,20 @@ impl RenderApi { SceneBuilderRequest::SetParameter(parameter) ); } + + /// Flush and return the current PipelineInfo. + pub fn flush_pipeline_info(&self) -> PipelineInfo { + let (tx, rx) = single_msg_channel(); + self.scene_sender.send(SceneBuilderRequest::FlushPipelineInfo(tx)).unwrap(); + rx.recv().unwrap() + } + + /// Returns the Epoch of the current frame in a pipeline. + pub fn current_epoch(&self, document_id: DocumentId, pipeline_id: PipelineId) -> Option { + let (tx, rx) = single_msg_channel(); + self.scene_sender.send(SceneBuilderRequest::CurrentEpoch(document_id, pipeline_id, tx)).unwrap(); + rx.recv().unwrap() + } } impl Drop for RenderApi { diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index 0806810eda..546bce19b1 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -10,7 +10,7 @@ use api::{DebugFlags, Parameter, BoolParameter, PrimitiveFlags, MinimapData}; use api::{DocumentId, ExternalScrollId, HitTestResult}; -use api::{IdNamespace, PipelineId, RenderNotifier, SampledScrollOffset}; +use api::{IdNamespace, RenderNotifier, SampledScrollOffset}; use api::{NotificationRequest, Checkpoint, QualitySettings}; use api::{FramePublishId, PrimitiveKeyKind, RenderReasons}; use api::units::*; @@ -44,7 +44,7 @@ use crate::prim_store::{PrimitiveInstanceKind, PrimTemplateCommonData}; use crate::prim_store::interned::*; use crate::profiler::{self, TransactionProfile}; use crate::render_task_graph::RenderTaskGraphBuilder; -use crate::renderer::{FullFrameStats, PipelineInfo}; +use crate::renderer::{FullFrameStats}; use crate::resource_cache::ResourceCache; #[cfg(feature = "replay")] use crate::resource_cache::PlainCacheOwn; @@ -330,13 +330,10 @@ impl ScratchBuffer { } struct Document { + #[allow(dead_code)] /// The id of this document id: DocumentId, - /// Temporary list of removed pipelines received from the scene builder - /// thread and forwarded to the renderer. - removed_pipelines: Vec<(PipelineId, DocumentId)>, - view: DocumentView, /// The id and time of the current frame. @@ -405,7 +402,6 @@ impl Document { ) -> Self { Document { id, - removed_pipelines: Vec::new(), view: DocumentView { scene: SceneView { device_rect: size.into(), @@ -650,15 +646,6 @@ impl Document { self.hit_tester_is_valid = true; } - pub fn updated_pipeline_info(&mut self) -> PipelineInfo { - let removed_pipelines = self.removed_pipelines.take_and_preallocate(); - PipelineInfo { - epochs: self.scene.pipeline_epochs.iter() - .map(|(&pipeline_id, &epoch)| ((pipeline_id, self.id), epoch)).collect(), - removed_pipelines, - } - } - /// Returns true if the node actually changed position or false otherwise. pub fn set_scroll_offsets( &mut self, @@ -939,7 +926,6 @@ impl RenderBackend { let has_built_scene = txn.built_scene.is_some(); if let Some(doc) = self.documents.get_mut(&txn.document_id) { - doc.removed_pipelines.append(&mut txn.removed_pipelines); doc.view.scene = txn.view; doc.profile.merge(&mut txn.profile); @@ -1308,6 +1294,9 @@ impl RenderBackend { ApiMsg::SceneBuilderResult(msg) => { return self.process_scene_builder_result(msg, frame_counter); } + ApiMsg::RequestPipelineInfo(tx) => { + self.send_backend_message(SceneBuilderRequest::RequestPipelineInfo(tx)); + } } // Now that we are likely out of the critical path, purge a few chunks @@ -1698,9 +1687,6 @@ impl RenderBackend { let update_doc_time = profiler::ns_to_ms(zeitstempel::now() - update_doc_start); rendered_document.profile.set(profiler::UPDATE_DOCUMENT_TIME, update_doc_time); - let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info()); - self.result_tx.send(msg).unwrap(); - // Publish the frame self.frame_publish_id.advance(); let msg = ResultMsg::PublishDocument( @@ -1710,13 +1696,6 @@ impl RenderBackend { pending_update, ); self.result_tx.send(msg).unwrap(); - } else if requested_frame { - // WR-internal optimization to avoid doing a bunch of render work if - // there's no pixels. We still want to pretend to render and request - // a render to make sure that the callbacks (particularly the - // new_frame_ready callback below) has the right flags. - let msg = ResultMsg::PublishPipelineInfo(doc.updated_pipeline_info()); - self.result_tx.send(msg).unwrap(); } drain_filter( @@ -2079,7 +2058,6 @@ impl RenderBackend { let doc = Document { id, scene: BuiltScene::empty(), - removed_pipelines: Vec::new(), view, stamp: FrameStamp::first(id), frame_builder: FrameBuilder::new(), diff --git a/webrender/src/renderer/init.rs b/webrender/src/renderer/init.rs index 54781c38e3..47e62303c9 100644 --- a/webrender/src/renderer/init.rs +++ b/webrender/src/renderer/init.rs @@ -802,7 +802,6 @@ pub fn create_webrender_instance( vaos, vertex_data_textures, current_vertex_data_textures: 0, - pipeline_info: PipelineInfo::default(), dither_matrix_texture, external_image_handler: None, size_of_ops: make_size_of_ops(), diff --git a/webrender/src/renderer/mod.rs b/webrender/src/renderer/mod.rs index 59583ffb9b..ec38af8dd5 100644 --- a/webrender/src/renderer/mod.rs +++ b/webrender/src/renderer/mod.rs @@ -44,7 +44,7 @@ use api::{PipelineId, ImageRendering, Checkpoint, NotificationRequest, ImageBuff use api::ExternalImage; use api::FramePublishId; use api::units::*; -use api::channel::{Sender, Receiver}; +use api::channel::{Sender, single_msg_channel, Receiver}; pub use api::DebugFlags; use core::time::Duration; @@ -867,8 +867,6 @@ pub struct Renderer { gpu_cache_frame_id: FrameId, gpu_cache_overflow: bool, - pipeline_info: PipelineInfo, - // Manages and resolves source textures IDs to real texture IDs. texture_resolver: TextureResolver, @@ -1017,15 +1015,6 @@ impl Renderer { self.clear_color = color; } - pub fn flush_pipeline_info(&mut self) -> PipelineInfo { - mem::replace(&mut self.pipeline_info, PipelineInfo::default()) - } - - /// Returns the Epoch of the current frame in a pipeline. - pub fn current_epoch(&self, document_id: DocumentId, pipeline_id: PipelineId) -> Option { - self.pipeline_info.epochs.get(&(pipeline_id, document_id)).cloned() - } - fn get_next_result_msg(&mut self) -> Option { if self.pending_result_msg.is_none() { if let Ok(msg) = self.result_rx.try_recv() { @@ -1054,12 +1043,6 @@ impl Renderer { // Pull any pending results and return the most recent. while let Some(msg) = self.get_next_result_msg() { match msg { - ResultMsg::PublishPipelineInfo(mut pipeline_info) => { - for ((pipeline_id, document_id), epoch) in pipeline_info.epochs { - self.pipeline_info.epochs.insert((pipeline_id, document_id), epoch); - } - self.pipeline_info.removed_pipelines.extend(pipeline_info.removed_pipelines.drain(..)); - } ResultMsg::PublishDocument( _, document_id, @@ -5894,7 +5877,12 @@ impl Renderer { let y0: f32 = 30.0; let mut y = y0; let mut text_width = 0.0; - for ((pipeline, document_id), epoch) in &self.pipeline_info.epochs { + + let (tx, rx) = single_msg_channel(); + self.api_tx.send(ApiMsg::RequestPipelineInfo(tx)).unwrap(); + let pipeline_info = rx.recv().unwrap(); + + for ((pipeline, document_id), epoch) in pipeline_info.epochs { y += dy; let w = debug_renderer.add_text( x0, y, @@ -6270,10 +6258,10 @@ impl ExternalImageHandler for DummyExternalImageHandler { fn unlock(&mut self, _key: ExternalImageId, _channel_index: u8) {} } -#[derive(Default)] +#[derive(Clone, Default)] pub struct PipelineInfo { pub epochs: FastHashMap<(PipelineId, DocumentId), Epoch>, - pub removed_pipelines: Vec<(PipelineId, DocumentId)>, + pub removed_pipelines: FastHashSet<(PipelineId, DocumentId)>, } impl Renderer { diff --git a/webrender/src/scene_builder_thread.rs b/webrender/src/scene_builder_thread.rs index 34e938b086..eabee25b44 100644 --- a/webrender/src/scene_builder_thread.rs +++ b/webrender/src/scene_builder_thread.rs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use api::{AsyncBlobImageRasterizer, BlobImageResult, DebugFlags, Parameter}; -use api::{DocumentId, PipelineId, ExternalEvent, BlobImageRequest}; +use api::{DocumentId, Epoch, PipelineId, ExternalEvent, BlobImageRequest}; use api::{NotificationRequest, Checkpoint, IdNamespace, QualitySettings}; use api::{PrimitiveKeyKind, GlyphDimensionRequest, GlyphIndexRequest}; use api::channel::{unbounded_channel, single_msg_channel, Receiver, Sender}; @@ -18,7 +18,7 @@ use crate::clip::{ClipIntern, PolygonIntern}; use crate::filterdata::FilterDataIntern; use glyph_rasterizer::SharedFontResources; use crate::intern::{Internable, Interner, UpdateList}; -use crate::internal_types::{FastHashMap, FastHashSet}; +use crate::internal_types::FastHashMap; use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use crate::prim_store::backdrop::{BackdropCapture, BackdropRender}; use crate::prim_store::borders::{ImageBorder, NormalBorderPrim}; @@ -34,9 +34,8 @@ use crate::scene::{BuiltScene, Scene, SceneStats}; use crate::spatial_tree::{SceneSpatialTree, SpatialTreeUpdates}; use crate::telemetry::Telemetry; use crate::SceneBuilderHooks; -use std::iter; use crate::util::drain_filter; -use std::thread; +use std::{iter, mem, thread}; use std::time::Duration; fn rasterize_blobs(txn: &mut TransactionMsg, is_low_priority: bool, tile_pool: &mut api::BlobTilePool) { @@ -64,7 +63,6 @@ pub struct BuiltTransaction { pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>, pub blob_rasterizer: Option>, pub frame_ops: Vec, - pub removed_pipelines: Vec<(PipelineId, DocumentId)>, pub notifications: Vec, pub interner_updates: Option, pub spatial_tree_updates: Option, @@ -97,8 +95,11 @@ pub struct LoadScene { /// Message to the scene builder thread. pub enum SceneBuilderRequest { Transactions(Vec>), + CurrentEpoch(DocumentId, PipelineId, Sender>), AddDocument(DocumentId, DeviceIntSize), DeleteDocument(DocumentId), + RequestPipelineInfo(Sender), + FlushPipelineInfo(Sender), GetGlyphDimensions(GlyphDimensionRequest), GetGlyphIndices(GlyphIndexRequest), ClearNamespace(IdNamespace), @@ -247,7 +248,7 @@ pub struct SceneBuilderThread { size_of_ops: Option, hooks: Option>, simulate_slow_ms: u32, - removed_pipelines: FastHashSet, + pipeline_info: PipelineInfo, #[cfg(feature = "capture")] capture_config: Option, debug_flags: DebugFlags, @@ -294,7 +295,7 @@ impl SceneBuilderThread { size_of_ops, hooks, simulate_slow_ms: 0, - removed_pipelines: FastHashSet::default(), + pipeline_info: PipelineInfo::default(), #[cfg(feature = "capture")] capture_config: None, debug_flags: DebugFlags::default(), @@ -344,6 +345,10 @@ impl SceneBuilderThread { self.recycler.recycle_built_scene(); self.tile_pool.cleanup(); } + Ok(SceneBuilderRequest::CurrentEpoch(document_id, pipeline_id, tx)) => { + let current_epoch = self.current_epoch(document_id, pipeline_id); + tx.send(current_epoch).unwrap(); + } Ok(SceneBuilderRequest::AddDocument(document_id, initial_size)) => { let old = self.documents.insert(document_id, Document::new( initial_size.into(), @@ -353,6 +358,14 @@ impl SceneBuilderThread { Ok(SceneBuilderRequest::DeleteDocument(document_id)) => { self.documents.remove(&document_id); self.send(SceneBuilderResult::DeleteDocument(document_id)); + self.pipeline_info.removed_pipelines.retain(|(_, doc_id)| *doc_id != document_id); + } + Ok(SceneBuilderRequest::RequestPipelineInfo(tx)) => { + tx.send(self.pipeline_info.clone()).unwrap(); + } + Ok(SceneBuilderRequest::FlushPipelineInfo(tx)) => { + let info = self.flush_pipeline_info(); + tx.send(info).unwrap(); } Ok(SceneBuilderRequest::ClearNamespace(id)) => { self.documents.retain(|doc_id, _doc| doc_id.namespace_id != id); @@ -495,7 +508,6 @@ impl SceneBuilderThread { rasterized_blobs: Vec::new(), blob_rasterizer: None, frame_ops: Vec::new(), - removed_pipelines: Vec::new(), notifications: Vec::new(), interner_updates, spatial_tree_updates, @@ -550,7 +562,6 @@ impl SceneBuilderThread { let mut profile = txn.profile.take(); let scene_build_start = zeitstempel::now(); - let mut removed_pipelines = Vec::new(); let mut rebuild_scene = false; let mut frame_stats = FullFrameStats::default(); let mut offscreen_scenes = Vec::new(); @@ -559,6 +570,7 @@ impl SceneBuilderThread { match message { SceneMsg::UpdateEpoch(pipeline_id, epoch) => { scene.update_epoch(pipeline_id, epoch); + self.pipeline_info.epochs.insert((pipeline_id, txn.document_id), epoch); } SceneMsg::SetQualitySettings { settings } => { doc.view.quality_settings = settings; @@ -584,7 +596,7 @@ impl SceneBuilderThread { frame_stats.gecko_display_list_time = gecko_display_list_time; frame_stats.wr_display_list_time += dl_build_time; - if self.removed_pipelines.contains(&pipeline_id) { + if self.pipeline_info.removed_pipelines.contains(&(pipeline_id, txn.document_id)) { continue; } @@ -598,6 +610,7 @@ impl SceneBuilderThread { epoch, display_list, ); + self.pipeline_info.epochs.insert((pipeline_id, txn.document_id), epoch); } SceneMsg::RenderOffscreen(pipeline_id) => { let mut interners = Interners::default(); @@ -630,14 +643,11 @@ impl SceneBuilderThread { } SceneMsg::RemovePipeline(pipeline_id) => { scene.remove_pipeline(pipeline_id); - self.removed_pipelines.insert(pipeline_id); - removed_pipelines.push((pipeline_id, txn.document_id)); + self.pipeline_info.removed_pipelines.insert((pipeline_id, txn.document_id)); } } } - self.removed_pipelines.clear(); - let mut built_scene = None; let mut interner_updates = None; let mut spatial_tree_updates = None; @@ -711,7 +721,6 @@ impl SceneBuilderThread { resource_updates: txn.resource_updates, blob_rasterizer: txn.blob_rasterizer, frame_ops: txn.frame_ops, - removed_pipelines, notifications: txn.notifications, interner_updates, spatial_tree_updates, @@ -734,9 +743,7 @@ impl SceneBuilderThread { .zip(iter::repeat(txn.document_id)) .map(|((&pipeline_id, &epoch), document_id)| ((pipeline_id, document_id), epoch)) }).flatten().collect(), - removed_pipelines: txns.iter() - .map(|txn| txn.removed_pipelines.clone()) - .flatten().collect(), + removed_pipelines: self.pipeline_info.removed_pipelines.clone(), }; let (tx, rx) = single_msg_channel(); @@ -813,6 +820,15 @@ impl SceneBuilderThread { report } + + fn flush_pipeline_info(&mut self) -> PipelineInfo { + mem::replace(&mut self.pipeline_info, PipelineInfo::default()) + } + + /// Returns the Epoch of the current frame in a pipeline. + fn current_epoch(&self, document_id: DocumentId, pipeline_id: PipelineId) -> Option { + self.pipeline_info.epochs.get(&(pipeline_id, document_id)).cloned() + } } /// A scene builder thread which executes expensive operations such as blob rasterization diff --git a/wrench/src/wrench.rs b/wrench/src/wrench.rs index ae29e731ee..9942aab57b 100644 --- a/wrench/src/wrench.rs +++ b/wrench/src/wrench.rs @@ -611,7 +611,7 @@ impl Wrench { pub fn render(&mut self) -> RenderResults { self.renderer.update(); - let _ = self.renderer.flush_pipeline_info(); + let _ = self.api.flush_pipeline_info(); self.renderer .render(self.window_size, 0) .expect("errors encountered during render!")