| author | Nicolas Silva <nsilva@mozilla.com> |
| Wed, 05 Feb 2020 09:51:14 +0000 | |
| changeset 512556 | a9dde10ff4b84810ca804e74caf30e221345d9ed |
| parent 512555 | a290c8f5c4595925a8f843cfc0701a8900a7af90 |
| child 512557 | 7554cfe059b4078b8b7e3a2d70d1363206cd3a21 |
| push id | 37092 |
| push user | apavel@mozilla.com |
| push date | Wed, 05 Feb 2020 16:27:17 +0000 |
| treeherder | mozilla-central@0fa466366383 [default view] [failures only] |
| perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
| reviewers | gw |
| bugs | 1613167 |
| milestone | 74.0a1 |
| 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/config/gfxVars.h +++ b/gfx/config/gfxVars.h @@ -40,16 +40,17 @@ class gfxVarReceiver; _(DXP016Blocked, bool, false) \ _(UseWebRender, bool, false) \ _(UseWebRenderANGLE, bool, false) \ _(UseWebRenderFlipSequentialWin, bool, false) \ _(UseWebRenderDCompWin, bool, false) \ _(UseWebRenderTripleBufferingWin, bool, false) \ _(UseWebRenderCompositor, bool, false) \ _(UseWebRenderProgramBinaryDisk, bool, false) \ + _(UseWebRenderMultithreading, bool, false) \ _(WebRenderMaxPartialPresentRects, int32_t, 0) \ _(WebRenderDebugFlags, int32_t, 0) \ _(ScreenDepth, int32_t, 0) \ _(GREDirectory, nsString, nsString()) \ _(ProfDirectory, nsString, nsString()) \ _(UseOMTP, bool, false) \ _(AllowD3D11KeyedMutex, bool, false) \ _(SystemTextQuality, int32_t, 5 /* CLEARTYPE_QUALITY */) \
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -2007,16 +2007,18 @@ void CompositorBridgeParent::AccumulateM } } } /*static*/ void CompositorBridgeParent::InitializeStatics() { gfxVars::SetAllowSacrificingSubpixelAAListener(&UpdateQualitySettings); gfxVars::SetWebRenderDebugFlagsListener(&UpdateDebugFlags); + gfxVars::SetUseWebRenderMultithreadingListener( + &UpdateWebRenderMultithreading); } /*static*/ void CompositorBridgeParent::UpdateQualitySettings() { if (!CompositorThreadHolder::IsInCompositorThread()) { if (CompositorLoop()) { CompositorLoop()->PostTask( NewRunnableFunction("CompositorBridgeParent::UpdateQualitySettings", @@ -2049,16 +2051,34 @@ void CompositorBridgeParent::UpdateDebug } MonitorAutoLock lock(*sIndirectLayerTreesLock); ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void { wrBridge->UpdateDebugFlags(); }); } +/*static*/ +void CompositorBridgeParent::UpdateWebRenderMultithreading() { + if (!CompositorThreadHolder::IsInCompositorThread()) { + if (CompositorLoop()) { + CompositorLoop()->PostTask(NewRunnableFunction( + "CompositorBridgeParent::UpdateWebRenderMultithreading", + &CompositorBridgeParent::UpdateWebRenderMultithreading)); + } + + return; + } + + MonitorAutoLock lock(*sIndirectLayerTreesLock); + ForEachWebRenderBridgeParent([&](WebRenderBridgeParent* wrBridge) -> void { + wrBridge->UpdateMultithreading(); + }); +} + RefPtr<WebRenderBridgeParent> CompositorBridgeParent::GetWebRenderBridgeParent() const { return mWrBridge; } Maybe<TimeStamp> CompositorBridgeParent::GetTestingTimeStamp() const { return mTestTime; }
--- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -730,16 +730,21 @@ class CompositorBridgeParent final : pub static void UpdateQualitySettings(); /** * Notify the compositor the debug flags have been updated. */ static void UpdateDebugFlags(); /** + * Notify the compositor the debug flags have been updated. + */ + static void UpdateWebRenderMultithreading(); + + /** * Wrap the data structure to be sent over IPC. */ Maybe<CollectedFramesParams> WrapCollectedFrames(CollectedFrames&& aFrames); protected: // Protected destructor, to discourage deletion outside of Release(): virtual ~CompositorBridgeParent();
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -1750,21 +1750,32 @@ void WebRenderBridgeParent::UpdateQualit } wr::TransactionBuilder txn; txn.UpdateQualitySettings(gfxVars::AllowSacrificingSubpixelAA()); api->SendTransaction(txn); } } void WebRenderBridgeParent::UpdateDebugFlags() { + auto flags = gfxVars::WebRenderDebugFlags(); for (auto& api : mApis) { if (!api) { continue; } - api->UpdateDebugFlags(gfxVars::WebRenderDebugFlags()); + api->UpdateDebugFlags(flags); + } +} + +void WebRenderBridgeParent::UpdateMultithreading() { + bool multithreading = gfxVars::UseWebRenderMultithreading(); + for (auto& api : mApis) { + if (!api) { + continue; + } + api->EnableMultithreading(multithreading); } } #if defined(MOZ_WIDGET_ANDROID) void WebRenderBridgeParent::RequestScreenPixels( UiCompositorControllerParent* aController) { mScreenPixelsTarget = aController; }
--- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -100,16 +100,17 @@ class WebRenderBridgeParent final return mCompositorScheduler.get(); } CompositorBridgeParentBase* GetCompositorBridge() { return mCompositorBridge; } void UpdateQualitySettings(); void UpdateDebugFlags(); + void UpdateMultithreading(); mozilla::ipc::IPCResult RecvEnsureConnected( TextureFactoryIdentifier* aTextureFactoryIdentifier, MaybeIdNamespace* aMaybeIdNamespace) override; mozilla::ipc::IPCResult RecvNewCompositable( const CompositableHandle& aHandle, const TextureInfo& aInfo) override; mozilla::ipc::IPCResult RecvReleaseCompositable(
--- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -610,16 +610,24 @@ static void WebRenderDebugPrefChangeCall gfx::gfxVars::SetWebRenderDebugFlags(flags.bits); } static void WebRenderQualityPrefChangeCallback(const char* aPref, void*) { gfxPlatform::GetPlatform()->UpdateAllowSacrificingSubpixelAA(); } +static void WebRenderMultithreadingPrefChangeCallback(const char* aPrefName, + void*) { + bool enable = Preferences::GetBool( + StaticPrefs::GetPrefName_gfx_webrender_enable_multithreading(), true); + + gfx::gfxVars::SetUseWebRenderMultithreading(enable); +} + #if defined(USE_SKIA) static uint32_t GetSkiaGlyphCacheSize() { // Only increase font cache size on non-android to save memory. # if !defined(MOZ_WIDGET_ANDROID) // 10mb as the default pref cache size on desktop due to talos perf tweaking. // Chromium uses 20mb and skia default uses 2mb. // We don't need to change the font cache count since we usually // cache thrash due to asian character sets in talos. @@ -3329,16 +3337,21 @@ void gfxPlatform::InitWebRenderConfig() if (XRE_IsParentProcess()) { Preferences::RegisterPrefixCallbackAndCall( WebRenderDebugPrefChangeCallback, WR_DEBUG_PREF); Preferences::RegisterCallback( WebRenderQualityPrefChangeCallback, nsDependentCString( StaticPrefs:: GetPrefName_gfx_webrender_quality_force_disable_sacrificing_subpixel_aa())); + Preferences::RegisterCallback( + WebRenderMultithreadingPrefChangeCallback, + nsDependentCString( + StaticPrefs::GetPrefName_gfx_webrender_enable_multithreading())); + UpdateAllowSacrificingSubpixelAA(); } } #if defined(MOZ_WIDGET_GTK) else { if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) { // Hardware compositing should be disabled by default if we aren't using // WebRender. We had to check if it is enabled at all, because it may
--- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -520,16 +520,20 @@ void WebRenderAPI::Readback(const TimeSt } void WebRenderAPI::ClearAllCaches() { wr_api_clear_all_caches(mDocHandle); } void WebRenderAPI::EnableNativeCompositor(bool aEnable) { wr_api_enable_native_compositor(mDocHandle, aEnable); } +void WebRenderAPI::EnableMultithreading(bool aEnable) { + wr_api_enable_multithreading(mDocHandle, aEnable); +} + void WebRenderAPI::Pause() { class PauseEvent : public RendererEvent { public: explicit PauseEvent(layers::SynchronousTask* aTask) : mTask(aTask) { MOZ_COUNT_CTOR(PauseEvent); } virtual ~PauseEvent() { MOZ_COUNT_DTOR(PauseEvent); }
--- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -243,16 +243,17 @@ class WebRenderAPI final { void RunOnRenderThread(UniquePtr<RendererEvent> aEvent); void Readback(const TimeStamp& aStartTime, gfx::IntSize aSize, const gfx::SurfaceFormat& aFormat, const Range<uint8_t>& aBuffer); void ClearAllCaches(); void EnableNativeCompositor(bool aEnable); + void EnableMultithreading(bool aEnable); void Pause(); bool Resume(); void WakeSceneBuilder(); void FlushSceneBuilder(); void NotifyMemoryPressure();
--- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -1598,16 +1598,21 @@ pub unsafe extern "C" fn wr_api_clear_al dh.api.send_debug_cmd(DebugCommand::ClearCaches(ClearCache::all())); } #[no_mangle] pub unsafe extern "C" fn wr_api_enable_native_compositor(dh: &mut DocumentHandle, enable: bool) { dh.api.send_debug_cmd(DebugCommand::EnableNativeCompositor(enable)); } +#[no_mangle] +pub unsafe extern "C" fn wr_api_enable_multithreading(dh: &mut DocumentHandle, enable: bool) { + dh.api.send_debug_cmd(DebugCommand::EnableMultithreading(enable)); +} + fn make_transaction(do_async: bool) -> Transaction { let mut transaction = Transaction::new(); // Ensure that we either use async scene building or not based on the // gecko pref, regardless of what the default is. We can remove this once // the scene builder thread is enabled everywhere and working well. if do_async { transaction.use_scene_builder_thread(); } else {
--- a/gfx/webrender_bindings/src/moz2d_renderer.rs +++ b/gfx/webrender_bindings/src/moz2d_renderer.rs @@ -74,16 +74,17 @@ fn dump_index(blob: &[u8]) -> () { /// Handles the interpretation and rasterization of gecko-based (moz2d) WR blob images. pub struct Moz2dBlobImageHandler { workers: Arc<ThreadPool>, workers_low_priority: Arc<ThreadPool>, blob_commands: HashMap<BlobImageKey, BlobCommand>, + enable_multithreading: bool, } /// Transmute some bytes into a value. /// /// FIXME: kill this with fire and/or do a super robust security audit unsafe fn convert_from_bytes<T: Copy>(slice: &[u8]) -> T { assert!(mem::size_of::<T>() <= slice.len()); ptr::read_unaligned(slice.as_ptr() as *const T) @@ -502,16 +503,18 @@ struct BlobCommand { /// Rasterizes gecko blob images. struct Moz2dBlobRasterizer { /// Pool of rasterizers. workers: Arc<ThreadPool>, /// Pool of low priority rasterizers. workers_low_priority: Arc<ThreadPool>, /// Blobs to rasterize. blob_commands: HashMap<BlobImageKey, BlobCommand>, + /// + enable_multithreading: bool, } struct GeckoProfilerMarker { name: &'static [u8], } impl GeckoProfilerMarker { pub fn new(name: &'static [u8]) -> GeckoProfilerMarker { @@ -544,17 +547,19 @@ impl AsyncBlobImageRasterizer for Moz2dB visible_rect: command.visible_rect, dirty_rect: params.dirty_rect, tile_size: command.tile_size, } }).collect(); // If we don't have a lot of blobs it is probably not worth the initial cost // of installing work on rayon's thread pool so we do it serially on this thread. - let should_parallelize = if low_priority { + let should_parallelize = if !self.enable_multithreading { + false + } else if low_priority { requests.len() > 2 } else { // For high priority requests we don't "risk" the potential priority inversion of // dispatching to a thread pool full of low priority jobs unless it is really // appealing. requests.len() > 4 }; @@ -658,16 +663,17 @@ impl BlobImageHandler for Moz2dBlobImage self.blob_commands.remove(&key); } fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobImageRasterizer> { Box::new(Moz2dBlobRasterizer { workers: Arc::clone(&self.workers), workers_low_priority: Arc::clone(&self.workers_low_priority), blob_commands: self.blob_commands.clone(), + enable_multithreading: self.enable_multithreading, }) } fn delete_font(&mut self, font: FontKey) { unsafe { DeleteFontData(font); } } fn delete_font_instance(&mut self, key: FontInstanceKey) { @@ -684,16 +690,20 @@ impl BlobImageHandler for Moz2dBlobImage requests: &[BlobImageParams] ) { for params in requests { let commands = &self.blob_commands[¶ms.request.key]; let blob = Arc::clone(&commands.data); self.prepare_request(&blob, resources); } } + + fn enable_multithreading(&mut self, enable: bool) { + self.enable_multithreading = enable; + } } use bindings::{WrFontKey, WrFontInstanceKey, WrIdNamespace}; #[allow(improper_ctypes)] // this is needed so that rustc doesn't complain about passing the &Arc<Vec> to an extern function extern "C" { fn AddFontData(key: WrFontKey, data: *const u8, size: usize, index: u32, vec: &ArcVecU8); fn AddNativeFontHandle(key: WrFontKey, handle: *mut c_void, index: u32); @@ -714,16 +724,17 @@ extern "C" { impl Moz2dBlobImageHandler { /// Create a new BlobImageHandler with the given thread pool. pub fn new(workers: Arc<ThreadPool>, workers_low_priority: Arc<ThreadPool>) -> Self { Moz2dBlobImageHandler { blob_commands: HashMap::new(), workers: workers, workers_low_priority: workers_low_priority, + enable_multithreading: true, } } /// Does early preprocessing of a blob's resources. /// /// Currently just sets up fonts found in the blob. fn prepare_request(&self, blob: &[u8], resources: &dyn BlobImageResources) { #[cfg(target_os = "windows")]
--- a/gfx/wr/examples/blob.rs +++ b/gfx/wr/examples/blob.rs @@ -155,16 +155,17 @@ impl api::BlobImageHandler for Checkerbo } fn prepare_resources( &mut self, _services: &dyn api::BlobImageResources, _requests: &[api::BlobImageParams], ) {} + fn enable_multithreading(&mut self, _: bool) {} fn delete_font(&mut self, _font: api::FontKey) {} fn delete_font_instance(&mut self, _instance: api::FontInstanceKey) {} fn clear_namespace(&mut self, _namespace: api::IdNamespace) {} fn create_blob_rasterizer(&mut self) -> Box<dyn api::AsyncBlobImageRasterizer> { Box::new(Rasterizer { workers: Arc::clone(&self.workers), image_cmds: self.image_cmds.clone(), })
--- a/gfx/wr/webrender/src/glyph_rasterizer/mod.rs +++ b/gfx/wr/webrender/src/glyph_rasterizer/mod.rs @@ -103,16 +103,20 @@ impl GlyphRasterizer { return; } self.pending_glyphs += 1; self.request_glyphs_from_backend(font, new_glyphs); } + pub fn enable_multithreading(&mut self, enable: bool) { + self.enable_multithreading = enable; + } + pub(in super) fn request_glyphs_from_backend(&mut self, font: FontInstance, glyphs: Vec<GlyphKey>) { let font_contexts = Arc::clone(&self.font_contexts); let glyph_tx = self.glyph_tx.clone(); fn process_glyph(key: &GlyphKey, font_contexts: &FontContexts, font: &FontInstance) -> GlyphRasterJob { profile_scope!("glyph-raster"); let mut context = font_contexts.lock_current_context(); let mut job = GlyphRasterJob { @@ -149,17 +153,17 @@ impl GlyphRasterizer { glyph.downscale_bitmap_if_required(&font); } job } // if the number of glyphs is small, do it inline to avoid the threading overhead; // send the result into glyph_tx so downstream code can't tell the difference. - if glyphs.len() < 8 { + if !self.enable_multithreading || glyphs.len() < 8 { let jobs = glyphs.iter() .map(|key: &GlyphKey| process_glyph(key, &font_contexts, &font)) .collect(); glyph_tx.send(GlyphRasterJobs { font, jobs }).unwrap(); } else { // spawn an async task to get off of the render backend thread as early as // possible and in that task use rayon's fork join dispatch to rasterize the // glyphs in the thread pool. @@ -875,16 +879,19 @@ pub struct GlyphRasterizer { // - we don't have to worry about the ordering of events if a font is used on // a frame where it is used (although it seems unlikely). fonts_to_remove: Vec<FontKey>, // Defer removal of font instances, as for fonts. font_instances_to_remove: Vec<FontInstance>, #[allow(dead_code)] next_gpu_glyph_cache_key: GpuGlyphCacheKey, + + // Whether to parallelize glyph rasterization with rayon. + enable_multithreading: bool, } impl GlyphRasterizer { pub fn new(workers: Arc<ThreadPool>) -> Result<Self, ResourceCacheError> { let (glyph_tx, glyph_rx) = channel(); let num_workers = workers.current_num_threads(); let mut contexts = Vec::with_capacity(num_workers); @@ -907,16 +914,17 @@ impl GlyphRasterizer { font_contexts: Arc::new(font_context), pending_glyphs: 0, glyph_rx, glyph_tx, workers, fonts_to_remove: Vec::new(), font_instances_to_remove: Vec::new(), next_gpu_glyph_cache_key: GpuGlyphCacheKey(0), + enable_multithreading: true, }) } pub fn add_font(&mut self, font_key: FontKey, template: FontTemplate) { self.font_contexts.async_for_each(move |mut context| { context.add_font(&font_key, &template); }); }
--- a/gfx/wr/webrender/src/render_backend.rs +++ b/gfx/wr/webrender/src/render_backend.rs @@ -1249,16 +1249,20 @@ impl RenderBackend { // Update config in SceneBuilder self.low_priority_scene_tx.send(SceneBuilderRequest::SetFrameBuilderConfig( self.frame_config.clone() )).unwrap(); // We don't want to forward this message to the renderer. return RenderBackendStatus::Continue; } + DebugCommand::EnableMultithreading(enable) => { + self.resource_cache.enable_multithreading(enable); + return RenderBackendStatus::Continue; + } DebugCommand::SimulateLongSceneBuild(time_ms) => { self.scene_tx.send(SceneBuilderRequest::SimulateLongSceneBuild(time_ms)).unwrap(); return RenderBackendStatus::Continue; } DebugCommand::SimulateLongLowPrioritySceneBuild(time_ms) => { self.low_priority_scene_tx.send( SceneBuilderRequest::SimulateLongLowPrioritySceneBuild(time_ms) ).unwrap();
--- a/gfx/wr/webrender/src/renderer.rs +++ b/gfx/wr/webrender/src/renderer.rs @@ -2280,16 +2280,17 @@ impl Renderer { } })?; low_priority_scene_tx } else { scene_tx.clone() }; + let enable_multithreading = options.enable_multithreading; 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 { thread_listener.thread_started(&rb_thread_name); } let texture_cache = TextureCache::new( max_texture_size, @@ -2301,23 +2302,25 @@ impl Renderer { }, start_size, color_cache_formats, swizzle_settings, ); let glyph_cache = GlyphCache::new(max_glyph_cache_size); - let resource_cache = ResourceCache::new( + let mut resource_cache = ResourceCache::new( texture_cache, glyph_rasterizer, glyph_cache, blob_image_handler, ); + resource_cache.enable_multithreading(enable_multithreading); + let mut backend = RenderBackend::new( api_rx, payload_rx_for_backend, result_tx, scene_tx, low_priority_scene_tx, scene_rx, device_pixel_ratio, @@ -2869,17 +2872,18 @@ impl Renderer { } DebugCommand::SaveCapture(..) | DebugCommand::LoadCapture(..) => { panic!("Capture commands are not welcome here! Did you build with 'capture' feature?") } DebugCommand::ClearCaches(_) | DebugCommand::SimulateLongSceneBuild(_) | DebugCommand::SimulateLongLowPrioritySceneBuild(_) - | DebugCommand::EnableNativeCompositor(_) => {} + | DebugCommand::EnableNativeCompositor(_) + | DebugCommand::EnableMultithreading(_) => {} DebugCommand::InvalidateGpuCache => { match self.gpu_cache_texture.bus { GpuCacheBus::PixelBuffer { ref mut rows, .. } => { info!("Invalidating GPU caches"); for row in rows { row.is_dirty = true; } } @@ -6217,16 +6221,17 @@ pub struct RendererOptions { pub force_subpixel_aa: bool, pub clear_color: Option<ColorF>, pub enable_clear_scissor: bool, pub max_texture_size: Option<i32>, pub max_glyph_cache_size: Option<usize>, pub scatter_gpu_cache_updates: bool, pub upload_method: UploadMethod, pub workers: Option<Arc<ThreadPool>>, + pub enable_multithreading: bool, pub blob_image_handler: Option<Box<dyn BlobImageHandler>>, pub recorder: Option<Box<dyn ApiRecordingReceiver>>, pub thread_listener: Option<Box<dyn ThreadListener + Send + Sync>>, pub size_of_op: Option<VoidPtrToSizeFn>, pub enclosing_size_of_op: Option<VoidPtrToSizeFn>, pub cached_programs: Option<Rc<ProgramCache>>, pub debug_flags: DebugFlags, pub renderer_id: Option<u64>, @@ -6290,16 +6295,17 @@ impl Default for RendererOptions { max_texture_size: None, max_glyph_cache_size: None, // Scattered GPU cache updates haven't met a test that would show their superiority yet. scatter_gpu_cache_updates: false, // This is best as `Immediate` on Angle, or `Pixelbuffer(Dynamic)` on GL, // but we are unable to make this decision here, so picking the reasonable medium. upload_method: UploadMethod::PixelBuffer(VertexUsageHint::Stream), workers: None, + enable_multithreading: true, blob_image_handler: None, recorder: None, thread_listener: None, size_of_op: None, enclosing_size_of_op: None, renderer_id: None, cached_programs: None, scene_builder_hooks: None,
--- a/gfx/wr/webrender/src/resource_cache.rs +++ b/gfx/wr/webrender/src/resource_cache.rs @@ -551,16 +551,23 @@ impl ResourceCache { pending_native_surface_updates: Vec::new(), } } pub fn max_texture_size(&self) -> i32 { self.texture_cache.max_texture_size() } + pub fn enable_multithreading(&mut self, enable: bool) { + self.glyph_rasterizer.enable_multithreading(enable); + if let Some(ref mut handler) = self.blob_image_handler { + handler.enable_multithreading(enable); + } + } + fn should_tile(limit: i32, descriptor: &ImageDescriptor, data: &CachedImageData) -> bool { let size_check = descriptor.size.width > limit || descriptor.size.height > limit; match *data { CachedImageData::Raw(_) | CachedImageData::Blob => size_check, CachedImageData::External(info) => { // External handles already represent existing textures so it does // not make sense to tile them into smaller ones. info.image_type == ExternalImageType::Buffer && size_check
--- a/gfx/wr/webrender_api/src/api.rs +++ b/gfx/wr/webrender_api/src/api.rs @@ -967,16 +967,18 @@ pub enum DebugCommand { /// Save a capture of all the documents state. SaveCapture(PathBuf, CaptureBits), /// Load a capture of all the documents state. LoadCapture(PathBuf, MsgSender<CapturedDocument>), /// Clear cached resources, forcing them to be re-uploaded from templates. ClearCaches(ClearCache), /// Enable/disable native compositor usage EnableNativeCompositor(bool), + /// Enable/disable parallel job execution with rayon. + EnableMultithreading(bool), /// Invalidate GPU cache, forcing the update from the CPU mirror. InvalidateGpuCache, /// Causes the scene builder to pause for a given amount of milliseconds each time it /// processes a transaction. SimulateLongSceneBuild(u32), /// Causes the low priority scene builder to pause for a given amount of milliseconds /// each time it processes a transaction. SimulateLongLowPrioritySceneBuild(u32),
--- a/gfx/wr/webrender_api/src/image.rs +++ b/gfx/wr/webrender_api/src/image.rs @@ -404,16 +404,19 @@ pub trait BlobImageHandler: Send { /// A hook to let the handler clean up any state related to a font instance which the /// resource cache is about to delete. fn delete_font_instance(&mut self, key: FontInstanceKey); /// A hook to let the handler clean up any state related a given namespace before the /// resource cache deletes them. fn clear_namespace(&mut self, namespace: IdNamespace); + + /// Whether to allow rendering blobs on multiple threads. + fn enable_multithreading(&mut self, enable: bool); } /// A group of rasterization requests to execute synchronously on the scene builder thread. pub trait AsyncBlobImageRasterizer : Send { /// Rasterize the requests. /// /// Gecko uses te priority hint to schedule work in a way that minimizes the risk /// of high priority work being blocked by (or enqued behind) low priority work.
--- a/gfx/wr/wrench/src/blob.rs +++ b/gfx/wr/wrench/src/blob.rs @@ -161,16 +161,18 @@ impl BlobImageHandler for CheckerboardRe if !requests.is_empty() { (self.callbacks.lock().unwrap().request)(&requests); } } fn create_blob_rasterizer(&mut self) -> Box<dyn AsyncBlobImageRasterizer> { Box::new(Rasterizer { image_cmds: self.image_cmds.clone() }) } + + fn enable_multithreading(&mut self, _enable: bool) {} } struct Command { request: BlobImageRequest, color: ColorU, descriptor: BlobImageDescriptor, tile: Option<(TileSize, TileOffset)>, dirty_rect: BlobDirtyRect,
--- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -3841,16 +3841,21 @@ value: true mirror: always - name: gfx.webrender.split-render-roots type: bool value: false mirror: once +- name: gfx.webrender.enable-multithreading + type: bool + value: true + mirror: always + - name: gfx.webrender.compositor type: bool #if defined(XP_WIN) || defined(XP_MACOSX) value: true #else value: false #endif mirror: once