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:
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