tor-browser

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

commit b5f886f686b8fae03056e01409c67b6ef64cb4e2
parent a144cd932b075502dbb655a085e2439f3741d717
Author: Sotaro Ikeda <sotaro.ikeda.g@gmail.com>
Date:   Wed, 29 Oct 2025 22:32:54 +0000

Bug 1958604 - Add a capability to use IDCompositionTexture with layer compositor r=gfx-reviewers,lsalzman

The change does rendering with full render.
Partial update is going to be supported by another bug.

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

Diffstat:
Mgfx/config/gfxVars.h | 3++-
Mgfx/thebes/gfxPlatform.cpp | 8++++++++
Mgfx/webrender_bindings/DCLayerTree.cpp | 240++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Mgfx/webrender_bindings/DCLayerTree.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mgfx/webrender_bindings/RenderCompositorANGLE.cpp | 8+++++++-
Mmodules/libpref/init/StaticPrefList.yaml | 5+++++
6 files changed, 313 insertions(+), 3 deletions(-)

diff --git a/gfx/config/gfxVars.h b/gfx/config/gfxVars.h @@ -117,7 +117,8 @@ class MOZ_STACK_CLASS gfxVarsCollectUpdates; _(GPUProcessEnabled, bool, false) \ _(DMABufModifiersP010, ArrayOfuint64_t, nsTArray<uint64_t>()) \ _(DMABufModifiersNV12, ArrayOfuint64_t, nsTArray<uint64_t>()) \ - _(AllowGLNorm16Textures, bool, false) + _(AllowGLNorm16Textures, bool, false) \ + _(WebRenderLayerCompositorDCompTexture, bool, false) /* Add new entries above this line. */ diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp @@ -2861,6 +2861,14 @@ void gfxPlatform::InitWebRenderConfig() { gfxVars::SetUseWebRenderTripleBufferingWin(true); } } + +# ifdef XP_WIN + if (StaticPrefs:: + gfx_webrender_layer_compositor_use_dcomp_texture_AtStartup() && + IsWin1122H2OrLater() && gfxVars::UseWebRenderDCompWin()) { + gfxVars::SetWebRenderLayerCompositorDCompTexture(true); + } +# endif #endif bool allowOverlayVpAutoHDR = false; diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp @@ -750,6 +750,9 @@ void DCLayerTree::PresentSwapChain(wr::NativeSurfaceId aId, size_t aNumDirtyRects) { auto surface = GetSurface(aId); surface->AsDCLayerSurface()->Present(aDirtyRects, aNumDirtyRects); + if (surface->AsDCLayerDCompositionTexture()) { + mPendingCommit = true; + } } void DCLayerTree::Bind(wr::NativeTileId aId, wr::DeviceIntPoint* aOffset, @@ -845,7 +848,15 @@ void DCLayerTree::CreateSwapChainSurface(wr::NativeSurfaceId aId, MOZ_RELEASE_ASSERT(it == mDCSurfaces.end()); UniquePtr<DCSurface> surface; - if (!mEnableAsyncScreenshot && + if (SupportsDCompositionTexture()) { + surface = MakeUnique<DCLayerDCompositionTexture>(aSize, aIsOpaque, this); + if (!surface->Initialize()) { + gfxCriticalNote << "Failed to initialize DCLayerDCompositionTexture: " + << wr::AsUint64(aId); + RenderThread::Get()->HandleWebRenderError(WebRenderError::NEW_SURFACE); + } + } else if ( + !mEnableAsyncScreenshot && (aNeedsSyncDcompCommit || StaticPrefs:: gfx_webrender_layer_compositor_force_composition_surface_AtStartup())) { @@ -1309,6 +1320,36 @@ bool DCLayerTree::SupportsSwapChainTearing() { return supported; } +bool DCLayerTree::SupportsDCompositionTexture() { + RefPtr<ID3D11Device> device = mDevice; + RefPtr<IDCompositionDevice2> compositionDevice = mCompositionDevice; + static const bool supported = [device, compositionDevice] { + const auto dcomp4 = QI<IDCompositionDevice4>::From(compositionDevice.get()); + if (!dcomp4) { + return false; + } + + BOOL supportCompositionTexture = FALSE; + HRESULT hr = dcomp4->CheckCompositionTextureSupport( + device, &supportCompositionTexture); + if (FAILED(hr)) { + return false; + } + + if (supportCompositionTexture == FALSE) { + return false; + } + + return true; + }(); + + if (!gfx::gfxVars::WebRenderLayerCompositorDCompTexture()) { + return false; + } + + return supported; +} + DXGI_FORMAT DCLayerTree::GetOverlayFormatForSDR() { return sGpuOverlayInfo->mOverlayFormatUsed; } @@ -1525,6 +1566,203 @@ DCTile* DCSurface::GetTile(int32_t aX, int32_t aY) const { return tile_it->second.get(); } +DCLayerDCompositionTexture::TextureHolder::TextureHolder( + ID3D11Texture2D* aTexture, IDCompositionTexture* aDCompositionTexture, + EGLSurface aEGLSurface) + : mTexture(aTexture), + mDCompositionTexture(aDCompositionTexture), + mEGLSurface(aEGLSurface) {} + +DCLayerDCompositionTexture::DCLayerDCompositionTexture( + wr::DeviceIntSize aSize, bool aIsOpaque, DCLayerTree* aDCLayerTree) + : DCLayerSurface(aIsOpaque, aDCLayerTree), + mSwapChainBufferCount(gfx::gfxVars::UseWebRenderTripleBufferingWin() ? 3 + : 2), + mSize(aSize) {} + +DCLayerDCompositionTexture::~DCLayerDCompositionTexture() { DestroyTextures(); } + +bool DCLayerDCompositionTexture::Initialize() { + DCSurface::Initialize(); + + if (!AllocateTextures()) { + return false; + } + return true; +} + +bool DCLayerDCompositionTexture::AllocateTextures() { + MOZ_ASSERT(mAvailableTextureHolders.empty()); + + HRESULT hr; + const auto device = mDCLayerTree->GetDevice(); + const auto dcomp = mDCLayerTree->GetCompositionDevice(); + const auto dcomp4 = QI<IDCompositionDevice4>::From(dcomp); + if (!dcomp4) { + return false; + } + + const auto gl = mDCLayerTree->GetGLContext(); + const auto& gle = gl::GLContextEGL::Cast(gl); + const auto& egl = gle->mEgl; + const EGLConfig eglConfig = mDCLayerTree->GetEGLConfig(); + + CD3D11_TEXTURE2D_DESC desc( + DXGI_FORMAT_B8G8R8A8_UNORM, mSize.width, mSize.height, 1, 1, + D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); + + desc.MiscFlags = + D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; + + for (size_t i = 0; i < mSwapChainBufferCount; i++) { + // Allocate ID3D11Texture2D + RefPtr<ID3D11Texture2D> texture; + hr = device->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture)); + if (FAILED(hr)) { + gfxCriticalNoteOnce << "CreateTexture2D failed: " << gfx::hexa(hr); + return false; + } + + // Allocate IDCompositionTexture + RefPtr<IDCompositionTexture> dcompTexture; + hr = + dcomp4->CreateCompositionTexture(texture, getter_AddRefs(dcompTexture)); + if (FAILED(hr)) { + gfxCriticalNoteOnce << "CreateCompositionTexture failed: " + << gfx::hexa(hr); + return false; + } + + const auto alphaMode = + mIsOpaque ? DXGI_ALPHA_MODE_IGNORE : DXGI_ALPHA_MODE_PREMULTIPLIED; + dcompTexture->SetAlphaMode(alphaMode); + // XXX + // dcompTexture->SetColorSpace(); + + // Allocate mEGLSurface + EGLSurface surface = EGL_NO_SURFACE; + const EGLint pbuffer_attribs[]{LOCAL_EGL_WIDTH, mSize.width, + LOCAL_EGL_HEIGHT, mSize.height, + LOCAL_EGL_NONE}; + const auto buffer = reinterpret_cast<EGLClientBuffer>(texture.get()); + + surface = egl->fCreatePbufferFromClientBuffer( + LOCAL_EGL_D3D_TEXTURE_ANGLE, buffer, eglConfig, pbuffer_attribs); + if (!surface) { + EGLint err = egl->mLib->fGetError(); + gfxCriticalNote << "Failed to create Pbuffer error: " << gfx::hexa(err) + << " Size : " + << LayoutDeviceIntSize(mSize.width, mSize.height); + return false; + } + + auto textureHolder = + MakeUnique<TextureHolder>(texture, dcompTexture, surface); + mAvailableTextureHolders.push_back(std::move(textureHolder)); + } + + MOZ_ASSERT(mAvailableTextureHolders.size() == mSwapChainBufferCount); + + return true; +} + +void DCLayerDCompositionTexture::DestroyTextures() { + const auto gl = mDCLayerTree->GetGLContext(); + const auto& gle = gl::GLContextEGL::Cast(gl); + const auto& egl = gle->mEgl; + + if (mCurrentTextureHolder) { + mAvailableTextureHolders.push_back(std::move(mCurrentTextureHolder)); + } + + if (mPresentingTextureHolder) { + mAvailableTextureHolders.push_back(std::move(mPresentingTextureHolder)); + } + + while (!mAvailableTextureHolders.empty()) { + auto& front = mAvailableTextureHolders.front(); + + if (front->mEGLSurface) { + if (gle->GetEGLSurfaceOverride() == front->mEGLSurface) { + gle->SetEGLSurfaceOverride(EGL_NO_SURFACE); + } + egl->fDestroySurface(front->mEGLSurface); + front->mEGLSurface = EGL_NO_SURFACE; + } + + mAvailableTextureHolders.pop_front(); + } + + MOZ_ASSERT(!mCurrentTextureHolder); + MOZ_ASSERT(!mPresentingTextureHolder); + MOZ_ASSERT(mAvailableTextureHolders.empty()); +} + +UniquePtr<DCLayerDCompositionTexture::TextureHolder> +DCLayerDCompositionTexture::GetNextTexture() { + MOZ_ASSERT(!mAvailableTextureHolders.empty()); + + if (mAvailableTextureHolders.empty()) { + return nullptr; + } + + UniquePtr<TextureHolder> textureHolder = + std::move(mAvailableTextureHolders.front()); + mAvailableTextureHolders.pop_front(); + + return textureHolder; +} + +void DCLayerDCompositionTexture::UpdateCurrentTexture() { + if (mCurrentTextureHolder) { + mAvailableTextureHolders.push_back(std::move(mCurrentTextureHolder)); + } + + MOZ_ASSERT(!mCurrentTextureHolder); + + mCurrentTextureHolder = GetNextTexture(); +} + +void DCLayerDCompositionTexture::Bind(const wr::DeviceIntRect* aDirtyRects, + size_t aNumDirtyRects) { + UpdateCurrentTexture(); + + if (!mCurrentTextureHolder || + (mCurrentTextureHolder->mEGLSurface == EGL_NO_SURFACE)) { + return; + } + + const auto gl = mDCLayerTree->GetGLContext(); + const auto& gle = gl::GLContextEGL::Cast(gl); + + gle->SetEGLSurfaceOverride(mCurrentTextureHolder->mEGLSurface); +} + +bool DCLayerDCompositionTexture::Resize(wr::DeviceIntSize aSize) { + DestroyTextures(); + mSize = aSize; + bool ret = AllocateTextures(); + return ret; +} + +void DCLayerDCompositionTexture::Present(const wr::DeviceIntRect* aDirtyRects, + size_t aNumDirtyRects) { + if (!mCurrentTextureHolder) { + return; + } + + if (mPresentingTextureHolder) { + mAvailableTextureHolders.push_back(std::move(mPresentingTextureHolder)); + } + MOZ_ASSERT(!mPresentingTextureHolder); + + mPresentingTextureHolder = std::move(mCurrentTextureHolder); + MOZ_ASSERT(!mCurrentTextureHolder); + MOZ_ASSERT(mPresentingTextureHolder); + + mContentVisual->SetContent(mPresentingTextureHolder->mDCompositionTexture); +} + DCSwapChain::DCSwapChain(wr::DeviceIntSize aSize, bool aIsOpaque, DCLayerTree* aDCLayerTree) : DCLayerSurface(aIsOpaque, aDCLayerTree), diff --git a/gfx/webrender_bindings/DCLayerTree.h b/gfx/webrender_bindings/DCLayerTree.h @@ -7,6 +7,7 @@ #ifndef MOZILLA_GFX_DCLAYER_TREE_H #define MOZILLA_GFX_DCLAYER_TREE_H +#include <deque> #include <dxgiformat.h> #include <unordered_map> #include <vector> @@ -24,6 +25,7 @@ struct ID3D11Device; struct ID3D11DeviceContext; +struct ID3D11Texture2D; struct ID3D11VideoDevice; struct ID3D11VideoContext; struct ID3D11VideoProcessor; @@ -32,6 +34,7 @@ struct ID3D11VideoProcessorOutputView; struct IDCompositionColorMatrixEffect; struct IDCompositionFilterEffect; struct IDCompositionTableTransferEffect; +struct IDCompositionTexture; struct IDCompositionDevice2; struct IDCompositionDevice3; struct IDCompositionSurface; @@ -61,6 +64,7 @@ namespace wr { class DCLayerSurface; class DCTile; +class DCLayerDCompositionTexture; class DCSurface; class DCSwapChain; class DCSurfaceVideo; @@ -195,6 +199,7 @@ class DCLayerTree { DXGI_FORMAT GetOverlayFormatForSDR(); bool SupportsSwapChainTearing(); + bool SupportsDCompositionTexture(); void SetUsedOverlayTypeInFrame(DCompOverlayTypes aTypes); @@ -352,6 +357,9 @@ class DCSurface { virtual DCSurfaceHandle* AsDCSurfaceHandle() { return nullptr; } virtual DCLayerSurface* AsDCLayerSurface() { return nullptr; } virtual DCSwapChain* AsDCSwapChain() { return nullptr; } + virtual DCLayerDCompositionTexture* AsDCLayerDCompositionTexture() { + return nullptr; + } bool IsUpdated(const wr::CompositorSurfaceTransform& aTransform, const wr::DeviceIntRect& aClipRect, @@ -429,6 +437,50 @@ class DCLayerSurface : public DCSurface { DCLayerSurface* AsDCLayerSurface() override { return this; } }; +class DCLayerDCompositionTexture : public DCLayerSurface { + public: + DCLayerDCompositionTexture(wr::DeviceIntSize aSize, bool aIsOpaque, + DCLayerTree* aDCLayerTree); + virtual ~DCLayerDCompositionTexture(); + + bool Initialize() override; + + void Bind(const wr::DeviceIntRect* aDirtyRects, + size_t aNumDirtyRects) override; + bool Resize(wr::DeviceIntSize aSize) override; + void Present(const wr::DeviceIntRect* aDirtyRects, + size_t aNumDirtyRects) override; + + DCLayerDCompositionTexture* AsDCLayerDCompositionTexture() override { + return this; + } + + const size_t mSwapChainBufferCount; + + private: + struct TextureHolder { + TextureHolder(ID3D11Texture2D* aTexture, + IDCompositionTexture* aDCompositionTexture, + EGLSurface aEGLSurface); + TextureHolder() = default; + + RefPtr<ID3D11Texture2D> mTexture; + RefPtr<IDCompositionTexture> mDCompositionTexture; + EGLSurface mEGLSurface; + }; + + bool AllocateTextures(); + void DestroyTextures(); + UniquePtr<TextureHolder> GetNextTexture(); + void UpdateCurrentTexture(); + + wr::DeviceIntSize mSize; + std::deque<UniquePtr<TextureHolder>> mAvailableTextureHolders; + + UniquePtr<TextureHolder> mCurrentTextureHolder; + UniquePtr<TextureHolder> mPresentingTextureHolder; +}; + class DCSwapChain : public DCLayerSurface { public: DCSwapChain(wr::DeviceIntSize aSize, bool aIsOpaque, diff --git a/gfx/webrender_bindings/RenderCompositorANGLE.cpp b/gfx/webrender_bindings/RenderCompositorANGLE.cpp @@ -1007,7 +1007,13 @@ void RenderCompositorANGLE::InitializeUsePartialPresent() { bool RenderCompositorANGLE::UsePartialPresent() { return mUsePartialPresent; } -bool RenderCompositorANGLE::RequestFullRender() { return mFullRender; } +bool RenderCompositorANGLE::RequestFullRender() { + // XXX Remove when partial update is supported. + if (UseLayerCompositor() && mDCLayerTree->SupportsDCompositionTexture()) { + return true; + } + return mFullRender; +} uint32_t RenderCompositorANGLE::GetMaxPartialPresentRects() { if (!mUsePartialPresent) { diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml @@ -7690,6 +7690,11 @@ type: bool value: false mirror: once + +- name: gfx.webrender.layer-compositor-use-dcomp-texture + type: bool + value: false + mirror: once #endif - name: gfx.webrender.scissored-cache-clears.enabled