From c45c3ac881084e8697f78774ef798b4148c3e860 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Tue, 8 Sep 2020 02:03:26 +0000 Subject: [PATCH] Bug 1662836 - Expose detailed initialization failure reason for WebRender. r=kvark We don't know why we see initialization failures in the telemetry which makes it hard to investigate why users aren't getting WebRender and instead fallback to basic. Let's expose the detailed error message WebRender already generates and puts in the critical log. Differential Revision: https://phabricator.services.mozilla.com/D89185 --- dom/ipc/BrowserChild.cpp | 3 ++- gfx/ipc/GPUProcessManager.cpp | 8 +++---- gfx/ipc/GPUProcessManager.h | 2 +- gfx/layers/ipc/CompositorBridgeParent.cpp | 7 +++++-- .../ipc/ContentCompositorBridgeParent.cpp | 3 ++- gfx/layers/ipc/PWebRenderBridge.ipdl | 2 +- gfx/layers/wr/WebRenderBridgeParent.cpp | 11 ++++++---- gfx/layers/wr/WebRenderBridgeParent.h | 7 ++++--- gfx/layers/wr/WebRenderLayerManager.cpp | 5 +++-- gfx/layers/wr/WebRenderLayerManager.h | 3 ++- gfx/webrender_bindings/WebRenderAPI.cpp | 21 ++++++++++++------- gfx/webrender_bindings/WebRenderAPI.h | 3 ++- gfx/webrender_bindings/src/bindings.rs | 9 ++++++++ widget/nsBaseWidget.cpp | 5 +++-- 14 files changed, 59 insertions(+), 30 deletions(-) diff --git a/dom/ipc/BrowserChild.cpp b/dom/ipc/BrowserChild.cpp index ea4e141f1a2b..badc96f24890 100644 --- a/dom/ipc/BrowserChild.cpp +++ b/dom/ipc/BrowserChild.cpp @@ -2700,9 +2700,10 @@ bool BrowserChild::CreateRemoteLayerManager( success = mPuppetWidget->CreateRemoteLayerManager( [&](LayerManager* aLayerManager) -> bool { MOZ_ASSERT(aLayerManager->AsWebRenderLayerManager()); + nsCString error; return aLayerManager->AsWebRenderLayerManager()->Initialize( aCompositorChild, wr::AsPipelineId(mLayersId), - &mTextureFactoryIdentifier); + &mTextureFactoryIdentifier, error); }); } else { nsTArray ignored; diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp index ebfc0773fc32..75ae993fc881 100644 --- a/gfx/ipc/GPUProcessManager.cpp +++ b/gfx/ipc/GPUProcessManager.cpp @@ -446,7 +446,8 @@ void GPUProcessManager::SimulateDeviceReset() { } } -void GPUProcessManager::DisableWebRender(wr::WebRenderError aError) { +void GPUProcessManager::DisableWebRender(wr::WebRenderError aError, + const nsCString& aMsg) { if (!gfx::gfxVars::UseWebRender()) { return; } @@ -454,8 +455,7 @@ void GPUProcessManager::DisableWebRender(wr::WebRenderError aError) { if (aError == wr::WebRenderError::INITIALIZE) { gfx::gfxConfig::GetFeature(gfx::Feature::WEBRENDER) .ForceDisable(gfx::FeatureStatus::Unavailable, - "WebRender initialization failed", - "FEATURE_FAILURE_WEBRENDER_INITIALIZE"_ns); + "WebRender initialization failed", aMsg); } else if (aError == wr::WebRenderError::MAKE_CURRENT) { gfx::gfxConfig::GetFeature(gfx::Feature::WEBRENDER) .ForceDisable(gfx::FeatureStatus::Unavailable, @@ -493,7 +493,7 @@ void GPUProcessManager::DisableWebRender(wr::WebRenderError aError) { } void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) { - DisableWebRender(aError); + DisableWebRender(aError, nsCString()); } void GPUProcessManager::OnInProcessDeviceReset() { diff --git a/gfx/ipc/GPUProcessManager.h b/gfx/ipc/GPUProcessManager.h index bbbadf1d0478..caa4da30938b 100644 --- a/gfx/ipc/GPUProcessManager.h +++ b/gfx/ipc/GPUProcessManager.h @@ -149,7 +149,7 @@ class GPUProcessManager final : public GPUProcessHost::Listener { void OnProcessLaunchComplete(GPUProcessHost* aHost) override; void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override; void SimulateDeviceReset(); - void DisableWebRender(wr::WebRenderError aError); + void DisableWebRender(wr::WebRenderError aError, const nsCString& aMsg); void NotifyWebRenderError(wr::WebRenderError aError); void OnInProcessDeviceReset(); void OnRemoteProcessDeviceReset(GPUProcessHost* aHost) override; diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index fc587520e030..81b03ad29f9e 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -1951,10 +1951,13 @@ PWebRenderBridgeParent* CompositorBridgeParent::AllocPWebRenderBridgeParent( // Same, but for the OMTA sampler. mOMTASampler->SetWebRenderWindowId(windowId); } + + nsCString error; RefPtr api = - wr::WebRenderAPI::Create(this, std::move(widget), windowId, aSize); + wr::WebRenderAPI::Create(this, std::move(widget), windowId, aSize, error); if (!api) { - mWrBridge = WebRenderBridgeParent::CreateDestroyed(aPipelineId); + mWrBridge = + WebRenderBridgeParent::CreateDestroyed(aPipelineId, std::move(error)); mWrBridge.get()->AddRef(); // IPDL reference return mWrBridge; } diff --git a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp index 37cad6d8c576..b56011b751f6 100644 --- a/gfx/layers/ipc/ContentCompositorBridgeParent.cpp +++ b/gfx/layers/ipc/ContentCompositorBridgeParent.cpp @@ -237,8 +237,9 @@ ContentCompositorBridgeParent::AllocPWebRenderBridgeParent( nsPrintfCString("Created child without a matching parent? root %p", root.get()) .get()); + nsCString error("NO_PARENT"); WebRenderBridgeParent* parent = - WebRenderBridgeParent::CreateDestroyed(aPipelineId); + WebRenderBridgeParent::CreateDestroyed(aPipelineId, std::move(error)); parent->AddRef(); // IPDL reference return parent; } diff --git a/gfx/layers/ipc/PWebRenderBridge.ipdl b/gfx/layers/ipc/PWebRenderBridge.ipdl index ce1525dbd0a4..f329cfcf3f21 100644 --- a/gfx/layers/ipc/PWebRenderBridge.ipdl +++ b/gfx/layers/ipc/PWebRenderBridge.ipdl @@ -41,7 +41,7 @@ sync protocol PWebRenderBridge parent: sync EnsureConnected() - returns (TextureFactoryIdentifier textureFactoryIdentifier, MaybeIdNamespace maybeIdNamespace); + returns (TextureFactoryIdentifier textureFactoryIdentifier, MaybeIdNamespace maybeIdNamespace, nsCString error); async NewCompositable(CompositableHandle handle, TextureInfo info); async ReleaseCompositable(CompositableHandle compositable); diff --git a/gfx/layers/wr/WebRenderBridgeParent.cpp b/gfx/layers/wr/WebRenderBridgeParent.cpp index f4198b85e6d3..06324c4b65e0 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.cpp +++ b/gfx/layers/wr/WebRenderBridgeParent.cpp @@ -365,13 +365,15 @@ WebRenderBridgeParent::WebRenderBridgeParent( UpdateQualitySettings(); } -WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId) +WebRenderBridgeParent::WebRenderBridgeParent(const wr::PipelineId& aPipelineId, + nsCString&& aError) : mCompositorBridge(nullptr), mPipelineId(aPipelineId), mChildLayersObserverEpoch{0}, mParentLayersObserverEpoch{0}, mWrEpoch{0}, mIdNamespace{0}, + mInitError(aError), mPaused(false), mDestroyed(true), mReceivedDisplayList(false), @@ -384,17 +386,18 @@ WebRenderBridgeParent::~WebRenderBridgeParent() {} /* static */ WebRenderBridgeParent* WebRenderBridgeParent::CreateDestroyed( - const wr::PipelineId& aPipelineId) { - return new WebRenderBridgeParent(aPipelineId); + const wr::PipelineId& aPipelineId, nsCString&& aError) { + return new WebRenderBridgeParent(aPipelineId, std::move(aError)); } mozilla::ipc::IPCResult WebRenderBridgeParent::RecvEnsureConnected( TextureFactoryIdentifier* aTextureFactoryIdentifier, - MaybeIdNamespace* aMaybeIdNamespace) { + MaybeIdNamespace* aMaybeIdNamespace, nsCString* aError) { if (mDestroyed) { *aTextureFactoryIdentifier = TextureFactoryIdentifier(LayersBackend::LAYERS_NONE); *aMaybeIdNamespace = Nothing(); + *aError = std::move(mInitError); return IPC_OK(); } diff --git a/gfx/layers/wr/WebRenderBridgeParent.h b/gfx/layers/wr/WebRenderBridgeParent.h index a9f6b93b932d..e78dfc5cebe7 100644 --- a/gfx/layers/wr/WebRenderBridgeParent.h +++ b/gfx/layers/wr/WebRenderBridgeParent.h @@ -113,7 +113,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent, TimeDuration aVsyncRate); static WebRenderBridgeParent* CreateDestroyed( - const wr::PipelineId& aPipelineId); + const wr::PipelineId& aPipelineId, nsCString&& aError); wr::PipelineId PipelineId() { return mPipelineId; } already_AddRefed GetWebRenderAPI() { @@ -134,7 +134,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent, mozilla::ipc::IPCResult RecvEnsureConnected( TextureFactoryIdentifier* aTextureFactoryIdentifier, - MaybeIdNamespace* aMaybeIdNamespace) override; + MaybeIdNamespace* aMaybeIdNamespace, nsCString* aError) override; mozilla::ipc::IPCResult RecvNewCompositable( const CompositableHandle& aHandle, const TextureInfo& aInfo) override; @@ -335,7 +335,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent, private: class ScheduleSharedSurfaceRelease; - explicit WebRenderBridgeParent(const wr::PipelineId& aPipelineId); + WebRenderBridgeParent(const wr::PipelineId& aPipelineId, nsCString&& aError); virtual ~WebRenderBridgeParent(); bool ProcessEmptyTransactionUpdates(TransactionData& aData, @@ -507,6 +507,7 @@ class WebRenderBridgeParent final : public PWebRenderBridgeParent, wr::Epoch mWrEpoch; wr::IdNamespace mIdNamespace; CompositionOpportunityId mCompositionOpportunityId; + nsCString mInitError; VsyncId mSkippedCompositeId; TimeStamp mMostRecentComposite; diff --git a/gfx/layers/wr/WebRenderLayerManager.cpp b/gfx/layers/wr/WebRenderLayerManager.cpp index bc6bed341a50..d30c98915571 100644 --- a/gfx/layers/wr/WebRenderLayerManager.cpp +++ b/gfx/layers/wr/WebRenderLayerManager.cpp @@ -58,7 +58,7 @@ KnowsCompositor* WebRenderLayerManager::AsKnowsCompositor() { return mWrChild; } bool WebRenderLayerManager::Initialize( PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId, - TextureFactoryIdentifier* aTextureFactoryIdentifier) { + TextureFactoryIdentifier* aTextureFactoryIdentifier, nsCString& aError) { MOZ_ASSERT(mWrChild == nullptr); MOZ_ASSERT(aTextureFactoryIdentifier); @@ -71,13 +71,14 @@ bool WebRenderLayerManager::Initialize( // reinitialization. We can expect to be notified again to reinitialize // (which may or may not be using WebRender). gfxCriticalNote << "Failed to create WebRenderBridgeChild."; + aError.AssignLiteral("FEATURE_FAILURE_WEBRENDER_INITIALIZE_IPDL"); return false; } TextureFactoryIdentifier textureFactoryIdentifier; wr::MaybeIdNamespace idNamespace; // Sync ipc - bridge->SendEnsureConnected(&textureFactoryIdentifier, &idNamespace); + bridge->SendEnsureConnected(&textureFactoryIdentifier, &idNamespace, &aError); if (textureFactoryIdentifier.mParentBackend == LayersBackend::LAYERS_NONE || idNamespace.isNothing()) { gfxCriticalNote << "Failed to connect WebRenderBridgeChild."; diff --git a/gfx/layers/wr/WebRenderLayerManager.h b/gfx/layers/wr/WebRenderLayerManager.h index 2b3ecd75500f..e2df09625bab 100644 --- a/gfx/layers/wr/WebRenderLayerManager.h +++ b/gfx/layers/wr/WebRenderLayerManager.h @@ -52,7 +52,8 @@ class WebRenderLayerManager final : public LayerManager { public: explicit WebRenderLayerManager(nsIWidget* aWidget); bool Initialize(PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId, - TextureFactoryIdentifier* aTextureFactoryIdentifier); + TextureFactoryIdentifier* aTextureFactoryIdentifier, + nsCString& aError); void Destroy() override; diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp index 178ffde22586..a9569e6bfc5d 100644 --- a/gfx/webrender_bindings/WebRenderAPI.cpp +++ b/gfx/webrender_bindings/WebRenderAPI.cpp @@ -63,7 +63,7 @@ class NewRenderer : public RendererEvent { bool* aUseANGLE, bool* aUseDComp, bool* aUseTripleBuffering, RefPtr&& aWidget, layers::SynchronousTask* aTask, LayoutDeviceIntSize aSize, - layers::SyncHandle* aHandle) + layers::SyncHandle* aHandle, nsACString* aError) : mDocHandle(aDocHandle), mMaxTextureSize(aMaxTextureSize), mUseANGLE(aUseANGLE), @@ -73,7 +73,8 @@ class NewRenderer : public RendererEvent { mCompositorWidget(std::move(aWidget)), mTask(aTask), mSize(aSize), - mSyncHandle(aHandle) { + mSyncHandle(aHandle), + mError(aError) { MOZ_COUNT_CTOR(NewRenderer); } @@ -110,6 +111,7 @@ class NewRenderer : public RendererEvent { StaticPrefs::gfx_webrender_enable_low_priority_pool(); bool supportPictureCaching = isMainWindow; wr::Renderer* wrRenderer = nullptr; + char* errorMessage = nullptr; if (!wr_window_new( aWindowId, mSize.width, mSize.height, supportLowPriorityTransactions, supportLowPriorityThreadpool, @@ -138,10 +140,13 @@ class NewRenderer : public RendererEvent { compositor->GetMaxUpdateRects(), compositor->GetMaxPartialPresentRects(), compositor->ShouldDrawPreviousPartialPresentRegions(), mDocHandle, - &wrRenderer, mMaxTextureSize, + &wrRenderer, mMaxTextureSize, &errorMessage, StaticPrefs::gfx_webrender_enable_gpu_markers_AtStartup(), panic_on_gl_error)) { // wr_window_new puts a message into gfxCriticalNote if it returns false + MOZ_ASSERT(errorMessage); + mError->AssignASCII(errorMessage); + wr_api_free_error_msg(errorMessage); return; } MOZ_ASSERT(wrRenderer); @@ -176,6 +181,7 @@ class NewRenderer : public RendererEvent { layers::SynchronousTask* mTask; LayoutDeviceIntSize mSize; layers::SyncHandle* mSyncHandle; + nsACString* mError; }; class RemoveRenderer : public RendererEvent { @@ -324,7 +330,7 @@ void TransactionWrapper::UpdateIsTransformAsyncZooming(uint64_t aAnimationId, already_AddRefed WebRenderAPI::Create( layers::CompositorBridgeParent* aBridge, RefPtr&& aWidget, const wr::WrWindowId& aWindowId, - LayoutDeviceIntSize aSize) { + LayoutDeviceIntSize aSize, nsACString& aError) { MOZ_ASSERT(aBridge); MOZ_ASSERT(aWidget); static_assert( @@ -342,9 +348,10 @@ already_AddRefed WebRenderAPI::Create( // created on the render thread. If need be we could delay waiting on this // task until the next time we need to access the DocumentHandle object. layers::SynchronousTask task("Create Renderer"); - auto event = MakeUnique( - &docHandle, aBridge, &maxTextureSize, &useANGLE, &useDComp, - &useTripleBuffering, std::move(aWidget), &task, aSize, &syncHandle); + auto event = MakeUnique(&docHandle, aBridge, &maxTextureSize, + &useANGLE, &useDComp, + &useTripleBuffering, std::move(aWidget), + &task, aSize, &syncHandle, &aError); RenderThread::Get()->RunEvent(aWindowId, std::move(event)); task.Wait(); diff --git a/gfx/webrender_bindings/WebRenderAPI.h b/gfx/webrender_bindings/WebRenderAPI.h index 2a8e29fd2977..1b451931603a 100644 --- a/gfx/webrender_bindings/WebRenderAPI.h +++ b/gfx/webrender_bindings/WebRenderAPI.h @@ -231,7 +231,8 @@ class WebRenderAPI final { static already_AddRefed Create( layers::CompositorBridgeParent* aBridge, RefPtr&& aWidget, - const wr::WrWindowId& aWindowId, LayoutDeviceIntSize aSize); + const wr::WrWindowId& aWindowId, LayoutDeviceIntSize aSize, + nsACString& aError); already_AddRefed Clone(); diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs index f707f5f1e4a1..72a22f8c260f 100644 --- a/gfx/webrender_bindings/src/bindings.rs +++ b/gfx/webrender_bindings/src/bindings.rs @@ -1430,6 +1430,7 @@ pub extern "C" fn wr_window_new( out_handle: &mut *mut DocumentHandle, out_renderer: &mut *mut Renderer, out_max_texture_size: *mut i32, + out_err: &mut *mut c_char, enable_gpu_markers: bool, panic_on_gl_error: bool, ) -> bool { @@ -1578,6 +1579,7 @@ pub extern "C" fn wr_window_new( unsafe { gfx_critical_note(msg.as_ptr()); } + *out_err = msg.into_raw(); return false; } }; @@ -1598,6 +1600,13 @@ pub extern "C" fn wr_window_new( return true; } +#[no_mangle] +pub unsafe extern "C" fn wr_api_free_error_msg(msg: *mut c_char) { + if msg != ptr::null_mut() { + CString::from_raw(msg); + } +} + #[no_mangle] pub unsafe extern "C" fn wr_api_delete_document(dh: &mut DocumentHandle) { dh.api.delete_document(dh.document_id); diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 98ab3731c439..d4e8500d9b24 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -1222,16 +1222,17 @@ already_AddRefed nsBaseWidget::CreateCompositorSession( if (lm->AsWebRenderLayerManager() && mCompositorSession) { TextureFactoryIdentifier textureFactoryIdentifier; + nsCString error; lm->AsWebRenderLayerManager()->Initialize( mCompositorSession->GetCompositorBridgeChild(), wr::AsPipelineId(mCompositorSession->RootLayerTreeId()), - &textureFactoryIdentifier); + &textureFactoryIdentifier, error); if (textureFactoryIdentifier.mParentBackend != LayersBackend::LAYERS_WR) { retry = true; DestroyCompositor(); // gfxVars::UseDoubleBufferingWithCompositor() is also disabled. gfx::GPUProcessManager::Get()->DisableWebRender( - wr::WebRenderError::INITIALIZE); + wr::WebRenderError::INITIALIZE, error); } } else if (lm->AsClientLayerManager() && mCompositorSession) { bool shouldAccelerate = ComputeShouldAccelerate();