diff --git a/webrender/src/render_backend.rs b/webrender/src/render_backend.rs index 6363fdf75f..7444adb4ba 100644 --- a/webrender/src/render_backend.rs +++ b/webrender/src/render_backend.rs @@ -241,7 +241,6 @@ impl Document { DocumentOps::nop() } - fn build_frame( &mut self, resource_cache: &mut ResourceCache, @@ -367,6 +366,7 @@ pub struct RenderBackend { payload_rx: Receiver, result_tx: Sender, scene_tx: Sender, + low_priority_scene_tx: Sender, scene_rx: Receiver, payload_buffer: Vec, @@ -393,6 +393,7 @@ impl RenderBackend { payload_rx: Receiver, result_tx: Sender, scene_tx: Sender, + low_priority_scene_tx: Sender, scene_rx: Receiver, default_device_pixel_ratio: f32, resource_cache: ResourceCache, @@ -410,6 +411,7 @@ impl RenderBackend { payload_rx, result_tx, scene_tx, + low_priority_scene_tx, scene_rx, payload_buffer: Vec::new(), default_device_pixel_ratio, @@ -597,7 +599,7 @@ impl RenderBackend { if txn.build_frame || !txn.resource_updates.is_empty() || !txn.frame_ops.is_empty() { self.update_document( - txn.document_id, + txn.document_id, replace(&mut txn.resource_updates, Vec::new()), replace(&mut txn.frame_ops, Vec::new()), txn.build_frame, @@ -628,7 +630,7 @@ impl RenderBackend { }; } - let _ = self.scene_tx.send(SceneBuilderRequest::Stop); + let _ = self.low_priority_scene_tx.send(SceneBuilderRequest::Stop); // Ensure we read everything the scene builder is sending us from // inflight messages, otherwise the scene builder might panic. while let Ok(msg) = self.scene_rx.recv() { @@ -665,7 +667,7 @@ impl RenderBackend { self.scene_tx.send(SceneBuilderRequest::WakeUp).unwrap(); } ApiMsg::FlushSceneBuilder(tx) => { - self.scene_tx.send(SceneBuilderRequest::Flush(tx)).unwrap(); + self.low_priority_scene_tx.send(SceneBuilderRequest::Flush(tx)).unwrap(); } ApiMsg::UpdateResources(mut updates) => { self.resource_cache.pre_scene_building_update( @@ -709,7 +711,7 @@ impl RenderBackend { } ApiMsg::DeleteDocument(document_id) => { self.documents.remove(&document_id); - self.scene_tx.send( + self.low_priority_scene_tx.send( SceneBuilderRequest::DeleteDocument(document_id) ).unwrap(); } @@ -754,7 +756,7 @@ impl RenderBackend { self.frame_config .dual_source_blending_is_enabled = enable; - self.scene_tx.send(SceneBuilderRequest::SetFrameBuilderConfig( + self.low_priority_scene_tx.send(SceneBuilderRequest::SetFrameBuilderConfig( self.frame_config.clone() )).unwrap(); @@ -835,6 +837,7 @@ impl RenderBackend { blob_requests: Vec::new(), resource_updates: transaction_msg.resource_updates, frame_ops: transaction_msg.frame_ops, + rasterized_blobs: Vec::new(), set_root_pipeline: None, build_frame: transaction_msg.generate_frame, render_frame: transaction_msg.generate_frame, @@ -892,7 +895,13 @@ impl RenderBackend { }); } - self.scene_tx.send(SceneBuilderRequest::Transaction(txn)).unwrap(); + let tx = if transaction_msg.low_priority { + &self.low_priority_scene_tx + } else { + &self.scene_tx + }; + + tx.send(SceneBuilderRequest::Transaction(txn)).unwrap(); } fn update_document( @@ -1345,7 +1354,7 @@ impl RenderBackend { } if !scenes_to_build.is_empty() { - self.scene_tx.send( + self.low_priority_scene_tx.send( SceneBuilderRequest::LoadScenes(scenes_to_build) ).unwrap(); } diff --git a/webrender/src/renderer.rs b/webrender/src/renderer.rs index 77b1b27aa8..77e67f98ce 100644 --- a/webrender/src/renderer.rs +++ b/webrender/src/renderer.rs @@ -44,7 +44,7 @@ use device::query::GpuProfiler; use rayon::{ThreadPool, ThreadPoolBuilder}; use record::ApiRecordingReceiver; use render_backend::RenderBackend; -use scene_builder::SceneBuilder; +use scene_builder::{SceneBuilder, LowPrioritySceneBuilder}; use shade::Shaders; use render_task::{RenderTask, RenderTaskKind, RenderTaskTree}; use resource_cache::ResourceCache; @@ -1714,9 +1714,11 @@ impl Renderer { let blob_image_handler = options.blob_image_handler.take(); let thread_listener_for_render_backend = thread_listener.clone(); let thread_listener_for_scene_builder = thread_listener.clone(); + let thread_listener_for_lp_scene_builder = thread_listener.clone(); let scene_builder_hooks = options.scene_builder_hooks; let rb_thread_name = format!("WRRenderBackend#{}", options.renderer_id.unwrap_or(0)); let scene_thread_name = format!("WRSceneBuilder#{}", options.renderer_id.unwrap_or(0)); + let lp_scene_thread_name = format!("WRSceneBuilderLP#{}", options.renderer_id.unwrap_or(0)); let glyph_rasterizer = GlyphRasterizer::new(workers)?; let (scene_builder, scene_tx, scene_rx) = SceneBuilder::new( @@ -1737,6 +1739,32 @@ impl Renderer { } })?; + let low_priority_scene_tx = if options.support_low_priority_transactions { + let (low_priority_scene_tx, low_priority_scene_rx) = channel(); + let lp_builder = LowPrioritySceneBuilder { + rx: low_priority_scene_rx, + tx: scene_tx.clone(), + }; + + thread::Builder::new().name(lp_scene_thread_name.clone()).spawn(move || { + register_thread_with_profiler(lp_scene_thread_name.clone()); + if let Some(ref thread_listener) = *thread_listener_for_lp_scene_builder { + thread_listener.thread_started(&lp_scene_thread_name); + } + + let mut scene_builder = lp_builder; + scene_builder.run(); + + if let Some(ref thread_listener) = *thread_listener_for_lp_scene_builder { + thread_listener.thread_stopped(&lp_scene_thread_name); + } + })?; + + low_priority_scene_tx + } else { + scene_tx.clone() + }; + thread::Builder::new().name(rb_thread_name.clone()).spawn(move || { register_thread_with_profiler(rb_thread_name.clone()); if let Some(ref thread_listener) = *thread_listener_for_render_backend { @@ -1755,6 +1783,7 @@ impl Renderer { payload_rx_for_backend, result_tx, scene_tx, + low_priority_scene_tx, scene_rx, device_pixel_ratio, resource_cache, @@ -4222,6 +4251,7 @@ pub struct RendererOptions { pub scene_builder_hooks: Option>, pub sampler: Option>, pub chase_primitive: ChasePrimitive, + pub support_low_priority_transactions: bool, } impl Default for RendererOptions { @@ -4256,6 +4286,7 @@ impl Default for RendererOptions { scene_builder_hooks: None, sampler: None, chase_primitive: ChasePrimitive::Nothing, + support_low_priority_transactions: false, } } } diff --git a/webrender/src/scene_builder.rs b/webrender/src/scene_builder.rs index 4ecec13963..830e9cfac8 100644 --- a/webrender/src/scene_builder.rs +++ b/webrender/src/scene_builder.rs @@ -27,6 +27,7 @@ pub struct Transaction { pub request_scene_build: Option, pub blob_requests: Vec, pub blob_rasterizer: Option>, + pub rasterized_blobs: Vec<(BlobImageRequest, BlobImageResult)>, pub resource_updates: Vec, pub frame_ops: Vec, pub set_root_pipeline: Option, @@ -315,18 +316,19 @@ impl SceneBuilder { } let blob_requests = replace(&mut txn.blob_requests, Vec::new()); - let rasterized_blobs = txn.blob_rasterizer.as_mut().map_or( + let mut rasterized_blobs = txn.blob_rasterizer.as_mut().map_or( Vec::new(), |rasterizer| rasterizer.rasterize(&blob_requests), ); + rasterized_blobs.append(&mut txn.rasterized_blobs); Box::new(BuiltTransaction { document_id: txn.document_id, build_frame: txn.build_frame || built_scene.is_some(), render_frame: txn.render_frame, built_scene, + rasterized_blobs, resource_updates: replace(&mut txn.resource_updates, Vec::new()), - rasterized_blobs: rasterized_blobs, blob_rasterizer: replace(&mut txn.blob_rasterizer, None), frame_ops: replace(&mut txn.frame_ops, Vec::new()), removed_pipelines: replace(&mut txn.removed_pipelines, Vec::new()), @@ -383,3 +385,50 @@ impl SceneBuilder { } } } + +/// A scene builder thread which executes expensive operations such as blob rasterization +/// with a lower priority than the normal scene builder thread. +/// +/// After rasterizing blobs, the secene building request is forwarded to the normal scene +/// builder where the FrameBuilder is generated. +pub struct LowPrioritySceneBuilder { + pub rx: Receiver, + pub tx: Sender, +} + +impl LowPrioritySceneBuilder { + pub fn run(&mut self) { + loop { + match self.rx.recv() { + Ok(SceneBuilderRequest::Transaction(txn)) => { + let txn = self.process_transaction(txn); + self.tx.send(SceneBuilderRequest::Transaction(txn)).unwrap(); + } + Ok(SceneBuilderRequest::DeleteDocument(document_id)) => { + self.tx.send(SceneBuilderRequest::DeleteDocument(document_id)).unwrap(); + } + Ok(SceneBuilderRequest::Stop) => { + self.tx.send(SceneBuilderRequest::Stop).unwrap(); + break; + } + Ok(other) => { + self.tx.send(other).unwrap(); + } + Err(_) => { + break; + } + } + } + } + + fn process_transaction(&mut self, mut txn: Box) -> Box { + let blob_requests = replace(&mut txn.blob_requests, Vec::new()); + let mut more_rasterized_blobs = txn.blob_rasterizer.as_mut().map_or( + Vec::new(), + |rasterizer| rasterizer.rasterize(&blob_requests), + ); + txn.rasterized_blobs.append(&mut more_rasterized_blobs); + + txn + } +} diff --git a/webrender_api/src/api.rs b/webrender_api/src/api.rs index acac37f62f..8cd4b160e2 100644 --- a/webrender_api/src/api.rs +++ b/webrender_api/src/api.rs @@ -56,6 +56,8 @@ pub struct Transaction { use_scene_builder_thread: bool, generate_frame: bool, + + low_priority: bool, } impl Transaction { @@ -67,6 +69,7 @@ impl Transaction { payloads: Vec::new(), use_scene_builder_thread: true, generate_frame: false, + low_priority: false, } } @@ -256,6 +259,7 @@ impl Transaction { resource_updates: self.resource_updates, use_scene_builder_thread: self.use_scene_builder_thread, generate_frame: self.generate_frame, + low_priority: self.low_priority, }, self.payloads, ) @@ -337,6 +341,18 @@ impl Transaction { self.resource_updates.push(ResourceUpdate::DeleteFontInstance(key)); } + // A hint that this transaction can be processed at a lower priority. High- + // priority transactions can jump ahead of regular-priority transactions, + // but both high- and regular-priority transactions are processed in order + // relative to other transactions of the same priority. + pub fn set_low_priority(&mut self, low_priority: bool) { + self.low_priority = low_priority; + } + + pub fn is_low_priority(&self) -> bool { + self.low_priority + } + pub fn merge(&mut self, mut other: Vec) { self.resource_updates.append(&mut other); } @@ -354,6 +370,7 @@ pub struct TransactionMsg { pub resource_updates: Vec, pub generate_frame: bool, pub use_scene_builder_thread: bool, + pub low_priority: bool, } impl TransactionMsg { @@ -372,6 +389,7 @@ impl TransactionMsg { resource_updates: Vec::new(), generate_frame: false, use_scene_builder_thread: false, + low_priority: false, } } @@ -382,6 +400,7 @@ impl TransactionMsg { resource_updates: Vec::new(), generate_frame: false, use_scene_builder_thread: false, + low_priority: false, } } }