tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 1c47c07babba0438f1fcaa992fa530353a6c6c8a
parent 4bcd0de36d96bcfb977505cb0c430e9eea58dc94
Author: Sotaro Ikeda <sotaro.ikeda.g@gmail.com>
Date:   Fri,  9 Jan 2026 00:46:03 +0000

Bug 1958603 - Add overlay support of WebGL/WebGPU by using IDCompositionTexture with layer compositor on Windows r=gfx-reviewers,lsalzman

Overlay support of Canvas2D is not added, since it does not get performance improvement for now.

Differential Revision: https://phabricator.services.mozilla.com/D277392

Diffstat:
Mgfx/config/gfxVars.h | 3++-
Mgfx/ipc/GPUProcessManager.cpp | 7++++++-
Mgfx/layers/CompositorTypes.h | 4+++-
Mgfx/layers/ShareableCanvasRenderer.cpp | 3+++
Mgfx/layers/d3d11/TextureD3D11.cpp | 9+++++++++
Mgfx/layers/wr/AsyncImagePipelineManager.cpp | 16+++++++++++-----
Mgfx/layers/wr/AsyncImagePipelineManager.h | 1+
Mgfx/thebes/gfxPlatform.cpp | 7+++++--
Mgfx/webrender_bindings/DCLayerTree.cpp | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mgfx/webrender_bindings/DCLayerTree.h | 35++++++++++++++++++++++++++++++++++-
Mgfx/webrender_bindings/RenderCompositorANGLE.cpp | 2+-
Mgfx/webrender_bindings/RenderD3D11TextureHost.cpp | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mgfx/webrender_bindings/RenderD3D11TextureHost.h | 6++++++
Mgfx/webrender_bindings/WebRenderTypes.h | 1+
Mmodules/libpref/init/StaticPrefList.yaml | 5+++++
15 files changed, 231 insertions(+), 19 deletions(-)

diff --git a/gfx/config/gfxVars.h b/gfx/config/gfxVars.h @@ -119,7 +119,8 @@ class MOZ_STACK_CLASS gfxVarsCollectUpdates; _(DMABufModifiersNV12, ArrayOfuint64_t, nsTArray<uint64_t>()) \ _(AllowGLNorm16Textures, bool, false) \ _(WebRenderLayerCompositorDCompTexture, bool, false) \ - _(WebRenderOverlayHDR, bool, false) + _(WebRenderOverlayHDR, bool, false) \ + _(UseWebRenderDCompositionTextureOverlayWin, bool, false) /* Add new entries above this line. */ diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp @@ -796,10 +796,15 @@ void GPUProcessManager::NotifyWebRenderError(wr::WebRenderError aError) { gfxVars::SetUseWebRenderDCompVideoSwOverlayWin(false); return; } + if (aError == wr::WebRenderError::DCOMP_TEXTURE_OVERLAY) { + gfxVars::SetUseWebRenderDCompositionTextureOverlayWin(false); + return; + } #else if (aError == wr::WebRenderError::VIDEO_OVERLAY || aError == wr::WebRenderError::VIDEO_HW_OVERLAY || - aError == wr::WebRenderError::VIDEO_SW_OVERLAY) { + aError == wr::WebRenderError::VIDEO_SW_OVERLAY || + aError == wr::WebRenderError::DCOMP_TEXTURE_OVERLAY) { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return; } diff --git a/gfx/layers/CompositorTypes.h b/gfx/layers/CompositorTypes.h @@ -98,9 +98,11 @@ enum class TextureFlags : uint32_t { SOFTWARE_DECODED_VIDEO = 1 << 23, // Whether the remote texture must wait for its owner to be created. WAIT_FOR_REMOTE_TEXTURE_OWNER = 1 << 24, + // Buffer is allocated by buffer provider like Canvas2D + ALLOC_BY_BUFFER_PROVIDER = 1 << 25, // OR union of all valid bits - ALL_BITS = (1 << 25) - 1, + ALL_BITS = (1 << 26) - 1, // the default flags DEFAULT = NO_FLAGS }; diff --git a/gfx/layers/ShareableCanvasRenderer.cpp b/gfx/layers/ShareableCanvasRenderer.cpp @@ -116,6 +116,9 @@ void ShareableCanvasRenderer::UpdateCompositableClient() { if (IsOpaque()) { flags |= TextureFlags::IS_OPAQUE; } + if (provider) { + flags |= TextureFlags::ALLOC_BY_BUFFER_PROVIDER; + } // - diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp @@ -1312,6 +1312,15 @@ bool DXGITextureHostD3D11::SupportsExternalCompositing( return true; } } + + bool useDcompTextureOverlay = + wr::RenderDXGITextureHost::UseDCompositionTextureOverlay(GetFormat()) && + mFencesHolderId.isSome() && + !(mFlags & TextureFlags::ALLOC_BY_BUFFER_PROVIDER); + if (useDcompTextureOverlay) { + return true; + } + return false; } diff --git a/gfx/layers/wr/AsyncImagePipelineManager.cpp b/gfx/layers/wr/AsyncImagePipelineManager.cpp @@ -59,6 +59,8 @@ AsyncImagePipelineManager::AsyncImagePipelineManager( gfx::gfxVars::UseWebRenderDCompVideoHwOverlayWin()), mUseWebRenderDCompVideoSwOverlayWin( gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin()), + mUseWebRenderDCompositionTextureOverlayWin( + gfx::gfxVars::UseWebRenderDCompositionTextureOverlayWin()), #endif mRenderSubmittedUpdatesLock("SubmittedUpdatesLock"), mLastCompletedFrameId(0) { @@ -370,20 +372,24 @@ void AsyncImagePipelineManager::ApplyAsyncImagesOfImageBridge( } #ifdef XP_WIN - // UseWebRenderDCompVideoHwOverlayWin() and - // UseWebRenderDCompVideoSwOverlayWin() could be changed from true to false, - // when DCompVideoOverlay task is failed. In this case, DisplayItems need to - // be re-pushed to WebRender for disabling video overlay. + // UseWebRenderDCompVideoHwOverlayWin(), UseWebRenderDCompVideoSwOverlayWin() + // and gfxVars::UseWebRenderDCompositionTextureOverlayWin() could be changed + // from true to false, when overlay task is failed. In this case, DisplayItems + // need to be re-pushed to WebRender for disabling video overlay. bool isChanged = (mUseWebRenderDCompVideoHwOverlayWin != gfx::gfxVars::UseWebRenderDCompVideoHwOverlayWin()) || (mUseWebRenderDCompVideoSwOverlayWin != - gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin()); + gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin()) || + (mUseWebRenderDCompositionTextureOverlayWin != + gfx::gfxVars::UseWebRenderDCompositionTextureOverlayWin()); if (isChanged) { mUseWebRenderDCompVideoHwOverlayWin = gfx::gfxVars::UseWebRenderDCompVideoHwOverlayWin(); mUseWebRenderDCompVideoSwOverlayWin = gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin(); + mUseWebRenderDCompositionTextureOverlayWin = + gfx::gfxVars::UseWebRenderDCompositionTextureOverlayWin(); } #endif diff --git a/gfx/layers/wr/AsyncImagePipelineManager.h b/gfx/layers/wr/AsyncImagePipelineManager.h @@ -260,6 +260,7 @@ class AsyncImagePipelineManager final { #ifdef XP_WIN bool mUseWebRenderDCompVideoHwOverlayWin; bool mUseWebRenderDCompVideoSwOverlayWin; + bool mUseWebRenderDCompositionTextureOverlayWin; #endif // Render time for the current composition. diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp @@ -2875,13 +2875,16 @@ void gfxPlatform::InitWebRenderConfig() { } } -# ifdef XP_WIN if (StaticPrefs:: gfx_webrender_layer_compositor_use_dcomp_texture_AtStartup() && IsWin1122H2OrLater() && gfxVars::UseWebRenderDCompWin()) { gfxVars::SetWebRenderLayerCompositorDCompTexture(true); } -# endif + + if (StaticPrefs::gfx_webrender_dcomp_texture_overlay_win_AtStartup() && + IsWin1122H2OrLater() && gfxVars::UseWebRenderDCompWin()) { + gfxVars::SetUseWebRenderDCompositionTextureOverlayWin(true); + } #endif bool allowOverlayVpAutoHDR = false; diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp @@ -849,7 +849,7 @@ void DCLayerTree::CreateSwapChainSurface(wr::NativeSurfaceId aId, MOZ_RELEASE_ASSERT(it == mDCSurfaces.end()); UniquePtr<DCSurface> surface; - if (SupportsDCompositionTexture()) { + if (UseDCLayerDCompositionTexture()) { surface = MakeUnique<DCLayerDCompositionTexture>(aSize, aIsOpaque, this); if (!surface->Initialize()) { gfxCriticalNote << "Failed to initialize DCLayerDCompositionTexture: " @@ -962,11 +962,25 @@ DCSurface* DCExternalSurfaceWrapper::EnsureSurfaceForExternalImage( RenderTextureHost* texture = RenderThread::Get()->GetRenderTexture(aExternalImage); if (texture && texture->AsRenderDXGITextureHost()) { - mSurface.reset(new DCSurfaceVideo(mIsOpaque, mDCLayerTree)); - if (!mSurface->Initialize()) { - gfxCriticalNote << "Failed to initialize DCSurfaceVideo: " - << wr::AsUint64(aExternalImage); - mSurface = nullptr; + auto format = texture->GetFormat(); + if (format == gfx::SurfaceFormat::B8G8R8A8 || + format == gfx::SurfaceFormat::B8G8R8X8) { + MOZ_ASSERT(RenderDXGITextureHost::UseDCompositionTextureOverlay(format)); + mSurface.reset( + new DCSurfaceDCompositionTextureOverlay(mIsOpaque, mDCLayerTree)); + if (!mSurface->Initialize()) { + gfxCriticalNote + << "Failed to initialize DCSurfaceDCompositionTextureOverlay: " + << wr::AsUint64(aExternalImage); + mSurface = nullptr; + } + } else { + mSurface.reset(new DCSurfaceVideo(mIsOpaque, mDCLayerTree)); + if (!mSurface->Initialize()) { + gfxCriticalNote << "Failed to initialize DCSurfaceVideo: " + << wr::AsUint64(aExternalImage); + mSurface = nullptr; + } } } else if (texture && texture->AsRenderDcompSurfaceTextureHost()) { mSurface.reset(new DCSurfaceHandle(mIsOpaque, mDCLayerTree)); @@ -1098,6 +1112,9 @@ void DCExternalSurfaceWrapper::PresentExternalSurface(gfx::Matrix& aTransform) { } } else if (auto* surface = mSurface->AsDCSurfaceHandle()) { surface->PresentSurfaceHandle(); + } else if (auto* surface = + mSurface->AsDCSurfaceDCompositionTextureOverlay()) { + surface->Present(); } } @@ -1321,7 +1338,7 @@ bool DCLayerTree::SupportsSwapChainTearing() { return supported; } -bool DCLayerTree::SupportsDCompositionTexture() { +bool DCLayerTree::UseDCLayerDCompositionTexture() { if (!gfx::gfxVars::WebRenderLayerCompositorDCompTexture()) { return false; } @@ -2160,6 +2177,53 @@ void DCLayerCompositionSurface::Present(const wr::DeviceIntRect* aDirtyRects, mEGLSurface = EGL_NO_SURFACE; } +DCSurfaceDCompositionTextureOverlay::DCSurfaceDCompositionTextureOverlay( + bool aIsOpaque, DCLayerTree* aDCLayerTree) + : DCSurface(wr::DeviceIntSize{}, wr::DeviceIntPoint{}, false, aIsOpaque, + aDCLayerTree) {} + +DCSurfaceDCompositionTextureOverlay::~DCSurfaceDCompositionTextureOverlay() {} + +void DCSurfaceDCompositionTextureOverlay::AttachExternalImage( + wr::ExternalImageId aExternalImage) { + auto* texture = RenderThread::Get()->GetRenderTexture(aExternalImage); + if (!texture) { + return; + } + mRenderTextureHost = texture; +} + +void DCSurfaceDCompositionTextureOverlay::Present() { + if (!mRenderTextureHost) { + return; + } + + // Content is not updated + if (mPrevRenderTextureHost == mRenderTextureHost) { + return; + } + + const auto textureHost = mRenderTextureHost->AsRenderDXGITextureHost(); + RefPtr<IDCompositionTexture> dcompTexture = + textureHost->GetDCompositionTexture(); + if (!dcompTexture) { + gfxCriticalNote << "Failed to get DCompTexture"; + RenderThread::Get()->NotifyWebRenderError( + WebRenderError::DCOMP_TEXTURE_OVERLAY); + return; + } + + const auto alphaMode = + mIsOpaque ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED; + dcompTexture->SetAlphaMode(alphaMode); + // XXX + // dcompTexture->SetColorSpace(); + + mContentVisual->SetContent(dcompTexture); + mPrevRenderTextureHost = mRenderTextureHost; + mDCLayerTree->SetPendingCommet(); +} + DCSurfaceVideo::DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree) : DCSurface(wr::DeviceIntSize{}, wr::DeviceIntPoint{}, false, aIsOpaque, aDCLayerTree), diff --git a/gfx/webrender_bindings/DCLayerTree.h b/gfx/webrender_bindings/DCLayerTree.h @@ -67,6 +67,7 @@ class DCTile; class DCLayerDCompositionTexture; class DCSurface; class DCSwapChain; +class DCSurfaceDCompositionTextureOverlay; class DCSurfaceVideo; class DCSurfaceHandle; class RenderTextureHost; @@ -201,12 +202,14 @@ class DCLayerTree { DXGI_FORMAT GetOverlayFormatForSDR(); bool SupportsSwapChainTearing(); - bool SupportsDCompositionTexture(); + bool UseDCLayerDCompositionTexture(); void SetUsedOverlayTypeInFrame(DCompOverlayTypes aTypes); int GetFrameId() { return mCurrentFrame; } + void SetPendingCommet() { mPendingCommit = true; } + protected: bool Initialize(HWND aHwnd, nsACString& aError); bool InitializeVideoOverlaySupport(); @@ -362,6 +365,10 @@ class DCSurface { virtual DCLayerDCompositionTexture* AsDCLayerDCompositionTexture() { return nullptr; } + virtual DCSurfaceDCompositionTextureOverlay* + AsDCSurfaceDCompositionTextureOverlay() { + return nullptr; + } bool IsUpdated(const wr::CompositorSurfaceTransform& aTransform, const wr::DeviceIntRect& aClipRect, @@ -553,6 +560,12 @@ class DCExternalSurfaceWrapper : public DCSurface { return mSurface ? mSurface->AsDCSurfaceHandle() : nullptr; } + DCSurfaceDCompositionTextureOverlay* AsDCSurfaceDCompositionTextureOverlay() + override { + return mSurface ? mSurface->AsDCSurfaceDCompositionTextureOverlay() + : nullptr; + } + private: DCSurface* EnsureSurfaceForExternalImage(wr::ExternalImageId aExternalImage); @@ -561,6 +574,26 @@ class DCExternalSurfaceWrapper : public DCSurface { Maybe<ColorManagementChain> mCManageChain; }; +class DCSurfaceDCompositionTextureOverlay : public DCSurface { + public: + DCSurfaceDCompositionTextureOverlay(bool aIsOpaque, + DCLayerTree* aDCLayerTree); + + void AttachExternalImage(wr::ExternalImageId aExternalImage) override; + void Present(); + + DCSurfaceDCompositionTextureOverlay* AsDCSurfaceDCompositionTextureOverlay() + override { + return this; + } + + protected: + virtual ~DCSurfaceDCompositionTextureOverlay(); + + RefPtr<RenderTextureHost> mRenderTextureHost; + RefPtr<RenderTextureHost> mPrevRenderTextureHost; +}; + class DCSurfaceVideo : public DCSurface { public: DCSurfaceVideo(bool aIsOpaque, DCLayerTree* aDCLayerTree); diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.cpp b/gfx/webrender_bindings/RenderCompositorANGLE.cpp @@ -1008,7 +1008,7 @@ bool RenderCompositorANGLE::UsePartialPresent() { return mUsePartialPresent; } bool RenderCompositorANGLE::RequestFullRender() { // XXX Remove when partial update is supported. - if (UseLayerCompositor() && mDCLayerTree->SupportsDCompositionTexture()) { + if (UseLayerCompositor() && mDCLayerTree->UseDCLayerDCompositionTexture()) { return true; } return mFullRender; diff --git a/gfx/webrender_bindings/RenderD3D11TextureHost.cpp b/gfx/webrender_bindings/RenderD3D11TextureHost.cpp @@ -6,6 +6,8 @@ #include "RenderD3D11TextureHost.h" +#include <dcomp.h> + #include "GLContextEGL.h" #include "GLLibraryEGL.h" #include "RenderThread.h" @@ -14,6 +16,7 @@ #include "ScopedGLHelpers.h" #include "mozilla/gfx/CanvasManagerParent.h" #include "mozilla/gfx/DeviceManagerDx.h" +#include "mozilla/gfx/gfxVars.h" #include "mozilla/gfx/Logging.h" #include "mozilla/layers/FenceD3D11.h" #include "mozilla/layers/GpuProcessD3D11TextureMap.h" @@ -56,6 +59,76 @@ RenderDXGITextureHost::~RenderDXGITextureHost() { DeleteTextureHandle(); } +/* static */ +bool RenderDXGITextureHost::UseDCompositionTextureOverlay( + gfx::SurfaceFormat aFormat) { + if (!gfx::gfxVars::UseWebRenderDCompositionTextureOverlayWin()) { + return false; + } + + if (!gfx::DeviceManagerDx::Get()->CanUseDCompositionTexture()) { + return false; + } + + if (aFormat != gfx::SurfaceFormat::B8G8R8A8 && + aFormat != gfx::SurfaceFormat::B8G8R8X8) { + return false; + } + + return true; +} + +IDCompositionTexture* RenderDXGITextureHost::GetDCompositionTexture() { + if (mDCompositionTexture) { + return mDCompositionTexture; + } + + if (!UseDCompositionTextureOverlay(mFormat)) { + return nullptr; + } + + if (mFencesHolderId.isNothing()) { + MOZ_ASSERT_UNREACHABLE("Unexpected to be called!"); + return nullptr; + } + + HRESULT hr; + RefPtr<IDCompositionDevice2> dcomp = + gfx::DeviceManagerDx::Get()->GetDirectCompositionDevice(); + if (!dcomp) { + MOZ_ASSERT_UNREACHABLE("Unexpected to be called!"); + gfxCriticalNoteOnce << "Failed to get DirectCompositionDevice"; + return nullptr; + } + + RefPtr<IDCompositionDevice4> dcomp4; + hr = dcomp->QueryInterface((IDCompositionDevice4**)getter_AddRefs(dcomp4)); + if (FAILED(hr)) { + MOZ_ASSERT_UNREACHABLE("Unexpected to be called!"); + gfxCriticalNoteOnce << "Failed to get DCompositionDevice4"; + return nullptr; + } + + RefPtr<ID3D11Texture2D> texture2D = GetD3D11Texture2DWithGL(); + if (!texture2D) { + gfxCriticalNoteOnce << "Failed to get D3D11Texture"; + return nullptr; + } + + RefPtr<IDCompositionTexture> dcompTexture; + hr = + dcomp4->CreateCompositionTexture(texture2D, getter_AddRefs(dcompTexture)); + if (FAILED(hr)) { + gfxCriticalNoteOnce << "CreateCompositionTexture failed: " + << gfx::hexa(hr); + return nullptr; + } + + mDCompositionTexture = dcompTexture; + + return mDCompositionTexture; +} + ID3D11Texture2D* RenderDXGITextureHost::GetD3D11Texture2DWithGL() { if (mTexture) { return mTexture; diff --git a/gfx/webrender_bindings/RenderD3D11TextureHost.h b/gfx/webrender_bindings/RenderD3D11TextureHost.h @@ -14,6 +14,7 @@ #include "RenderTextureHostSWGL.h" struct ID3D11Texture2D; +struct IDCompositionTexture; struct IDXGIKeyedMutex; namespace mozilla { @@ -34,6 +35,8 @@ class RenderDXGITextureHost final : public RenderTextureHostSWGL { const gfx::IntSize aSize, const bool aHasKeyedMutex, const Maybe<layers::CompositeProcessFencesHolderId>& aFencesHolderId); + static bool UseDCompositionTextureOverlay(gfx::SurfaceFormat aFormat); + wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL) override; void Unlock() override; void ClearCachedResources() override; @@ -50,6 +53,8 @@ class RenderDXGITextureHost final : public RenderTextureHostSWGL { ID3D11Texture2D* GetD3D11Texture2DWithGL(); ID3D11Texture2D* GetD3D11Texture2D() { return mTexture; } + IDCompositionTexture* GetDCompositionTexture(); + // RenderTextureHostSWGL gfx::SurfaceFormat GetFormat() const override { return mFormat; } gfx::ColorDepth GetColorDepth() const override { @@ -106,6 +111,7 @@ class RenderDXGITextureHost final : public RenderTextureHostSWGL { RefPtr<ID3D11Texture2D> mTexture; const uint32_t mArrayIndex; RefPtr<IDXGIKeyedMutex> mKeyedMutex; + RefPtr<IDCompositionTexture> mDCompositionTexture; // Temporary state between MapPlane and UnmapPlanes. RefPtr<ID3D11DeviceContext> mDeviceContext; diff --git a/gfx/webrender_bindings/WebRenderTypes.h b/gfx/webrender_bindings/WebRenderTypes.h @@ -805,6 +805,7 @@ enum class WebRenderError : int8_t { VIDEO_OVERLAY, VIDEO_HW_OVERLAY, VIDEO_SW_OVERLAY, + DCOMP_TEXTURE_OVERLAY, EXCESSIVE_RESETS, Sentinel /* this must be last for serialization purposes. */ diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml @@ -7830,6 +7830,11 @@ mirror: once #endif +- name: gfx.webrender.dcomp-texture-overlay-win + type: bool + value: false + mirror: once + - name: gfx.webrender.scissored-cache-clears.enabled type: bool value: true