Bug 1957001 - Use FenceD3D11 for shnchronization in DXGIYCbCrTextureData r=media-playback-reviewers,gfx-reviewers,alwu,lsalzman

DXGIYCbCrTextureData uses keyed mutex for synchronization. But it is inefficient than FenceD3D11. And it caused the performance problem when DXGIYCbCrTextureData has multiple users like Bug 1956305

Differential Revision: https://phabricator.services.mozilla.com/D243622
This commit is contained in:
sotaro
2025-04-04 05:27:37 +00:00
parent b9e693610c
commit ceeb8ba7b7
35 changed files with 709 additions and 218 deletions

View File

@@ -10,6 +10,7 @@
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/UniquePtrExtensions.h"
#include "mozilla/layers/Fence.h"
#include "mozilla/webrender/WebRenderTypes.h"
#include "Units.h"
@@ -202,13 +203,7 @@ class RenderCompositor {
}
virtual bool MaybeProcessScreenshotQueue() { return false; }
// Returns FileDescriptor of release fence.
// Release fence is a fence that is used for waiting until usage/composite of
// AHardwareBuffer is ended. The fence is delivered to client side via
// ImageBridge. It is used only on android.
virtual UniqueFileHandle GetAndResetReleaseFence() {
return UniqueFileHandle();
}
virtual RefPtr<layers::Fence> GetAndResetReleaseFence() { return nullptr; }
virtual bool IsPaused() { return false; }

View File

@@ -13,6 +13,7 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/StackArray.h"
#include "mozilla/layers/FenceD3D11.h"
#include "mozilla/layers/TextureD3D11.h"
#include "mozilla/layers/HelpersD3D11.h"
#include "mozilla/layers/SyncObject.h"
@@ -124,11 +125,14 @@ bool RenderCompositorANGLE::Initialize(nsACString& aError) {
MOZ_ASSERT(mEGLConfig);
mDevice = GetDeviceOfEGLDisplay(aError);
if (!mDevice) {
return false;
}
if (layers::FenceD3D11::IsSupported(mDevice)) {
mFence = layers::FenceD3D11::Create(mDevice);
}
mDevice->GetImmediateContext(getter_AddRefs(mCtx));
if (!mCtx) {
aError.Assign("RcANGLE(get immediate context failed)"_ns);
@@ -462,6 +466,10 @@ RenderedFrameId RenderCompositorANGLE::EndFrame(
RenderedFrameId frameId = GetNextRenderFrameId();
InsertGraphicsCommandsFinishedWaitQuery(frameId);
if (mFence) {
mFence->IncrementAndSignal();
}
if (!UseCompositor()) {
auto start = TimeStamp::Now();
if (auto* fxrHandler = mWidget->AsWindows()->GetFxrOutputHandler()) {
@@ -564,6 +572,14 @@ RenderedFrameId RenderCompositorANGLE::EndFrame(
return frameId;
}
RefPtr<layers::Fence> RenderCompositorANGLE::GetAndResetReleaseFence() {
RefPtr<layers::Fence> fence;
if (mFence) {
fence = mFence->CloneFromHandle();
}
return fence.forget();
}
bool RenderCompositorANGLE::WaitForGPU() {
// Note: this waits on the query we inserted in the previous frame,
// not the one we just inserted now. Example:

View File

@@ -28,6 +28,10 @@ namespace gl {
class GLLibraryEGL;
} // namespace gl
namespace layers {
class FenceD3D11;
} // namespace layers
namespace wr {
class DCLayerTree;
@@ -113,6 +117,8 @@ class RenderCompositorANGLE final : public RenderCompositor {
bool RequestFullRender() override;
uint32_t GetMaxPartialPresentRects() override;
RefPtr<layers::Fence> GetAndResetReleaseFence() override;
bool MaybeReadback(const gfx::IntSize& aReadbackSize,
const wr::ImageFormat& aReadbackFormat,
const Range<uint8_t>& aReadbackBuffer,
@@ -169,6 +175,7 @@ class RenderCompositorANGLE final : public RenderCompositor {
bool mFirstPresent = true;
// Wether we're currently using alpha.
bool mSwapChainUsingAlpha = false;
RefPtr<layers::FenceD3D11> mFence;
};
} // namespace wr

View File

@@ -123,7 +123,7 @@ RenderedFrameId RenderCompositorEGL::EndFrame(
if (sync) {
int fenceFd = egl->fDupNativeFenceFDANDROID(sync);
if (fenceFd >= 0) {
mReleaseFenceFd = UniqueFileHandle(fenceFd);
mReleaseFence = new layers::FenceFileHandle(UniqueFileHandle(fenceFd));
}
egl->fDestroySync(sync);
sync = nullptr;
@@ -259,12 +259,12 @@ void RenderCompositorEGL::DestroyEGLSurface() {
}
}
UniqueFileHandle RenderCompositorEGL::GetAndResetReleaseFence() {
RefPtr<layers::Fence> RenderCompositorEGL::GetAndResetReleaseFence() {
#ifdef MOZ_WIDGET_ANDROID
MOZ_ASSERT(!layers::AndroidHardwareBufferApi::Get() || mReleaseFenceFd);
return std::move(mReleaseFenceFd);
MOZ_ASSERT(!layers::AndroidHardwareBufferApi::Get() || mReleaseFence);
return mReleaseFence.forget();
#else
return UniqueFileHandle();
return nullptr;
#endif
}

View File

@@ -46,7 +46,7 @@ class RenderCompositorEGL : public RenderCompositor {
void SetBufferDamageRegion(const wr::DeviceIntRect* aRects,
size_t aNumRects) override;
UniqueFileHandle GetAndResetReleaseFence() override;
RefPtr<layers::Fence> GetAndResetReleaseFence() override;
protected:
EGLSurface CreateEGLSurface();
@@ -66,7 +66,7 @@ class RenderCompositorEGL : public RenderCompositor {
// Release fence is a fence that is used for waiting until usage/composite of
// AHardwareBuffer is ended. The fence is delivered to client side via
// ImageBridge. It is used only on android.
UniqueFileHandle mReleaseFenceFd;
RefPtr<layers::Fence> mReleaseFence;
};
} // namespace wr

View File

@@ -18,6 +18,7 @@
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/FenceD3D11.h"
#include "mozilla/layers/GpuProcessD3D11TextureMap.h"
#include "mozilla/layers/GpuProcessD3D11FencesHolderMap.h"
#include "mozilla/layers/TextureD3D11.h"
namespace mozilla {
@@ -472,8 +473,10 @@ bool RenderDXGITextureHost::SyncObjectNeeded() {
RenderDXGIYCbCrTextureHost::RenderDXGIYCbCrTextureHost(
RefPtr<gfx::FileHandleWrapper> (&aHandles)[3],
gfx::YUVColorSpace aYUVColorSpace, gfx::ColorDepth aColorDepth,
gfx::ColorRange aColorRange, gfx::IntSize aSizeY, gfx::IntSize aSizeCbCr)
const gfx::YUVColorSpace aYUVColorSpace, const gfx::ColorDepth aColorDepth,
const gfx::ColorRange aColorRange, const gfx::IntSize aSizeY,
const gfx::IntSize aSizeCbCr,
const layers::GpuProcessFencesHolderId aFencesHolderId)
: mHandles{aHandles[0], aHandles[1], aHandles[2]},
mSurfaces{0},
mStreams{0},
@@ -483,7 +486,7 @@ RenderDXGIYCbCrTextureHost::RenderDXGIYCbCrTextureHost(
mColorRange(aColorRange),
mSizeY(aSizeY),
mSizeCbCr(aSizeCbCr),
mLocked(false) {
mFencesHolderId(aFencesHolderId) {
MOZ_COUNT_CTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost);
// Assume the chroma planes are rounded up if the luma plane is odd sized.
MOZ_ASSERT((mSizeCbCr.width == mSizeY.width ||
@@ -631,25 +634,20 @@ bool RenderDXGIYCbCrTextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) {
}
}
for (int i = 0; i < 3; ++i) {
mTextures[i]->QueryInterface(
(IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutexs[i]));
}
mDevice = aDevice;
return true;
}
bool RenderDXGIYCbCrTextureHost::LockInternal() {
if (!mLocked) {
if (mKeyedMutexs[0]) {
for (const auto& mutex : mKeyedMutexs) {
HRESULT hr = mutex->AcquireSync(0, 10000);
if (hr != S_OK) {
gfxCriticalError()
<< "RenderDXGIYCbCrTextureHost AcquireSync timeout, hr="
<< gfx::hexa(hr);
return false;
}
}
auto* fenceHolderMap = layers::GpuProcessD3D11FencesHolderMap::Get();
if (!fenceHolderMap) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return false;
}
if (!fenceHolderMap->WaitWriteFence(mFencesHolderId, mDevice)) {
return false;
}
mLocked = true;
}
@@ -688,11 +686,6 @@ wr::WrExternalImage RenderDXGIYCbCrTextureHost::Lock(uint8_t aChannelIndex,
void RenderDXGIYCbCrTextureHost::Unlock() {
if (mLocked) {
if (mKeyedMutexs[0]) {
for (const auto& mutex : mKeyedMutexs) {
mutex->ReleaseSync(0);
}
}
mLocked = false;
}
}
@@ -736,7 +729,6 @@ void RenderDXGIYCbCrTextureHost::DeleteTextureHandle() {
for (int i = 0; i < 3; ++i) {
mTextureHandles[i] = 0;
mTextures[i] = nullptr;
mKeyedMutexs[i] = nullptr;
if (mSurfaces[i]) {
egl->fDestroySurface(mSurfaces[i]);
@@ -748,6 +740,7 @@ void RenderDXGIYCbCrTextureHost::DeleteTextureHandle() {
}
}
}
mDevice = nullptr;
}
} // namespace wr

View File

@@ -139,8 +139,10 @@ class RenderDXGIYCbCrTextureHost final : public RenderTextureHostSWGL {
public:
explicit RenderDXGIYCbCrTextureHost(
RefPtr<gfx::FileHandleWrapper> (&aHandles)[3],
gfx::YUVColorSpace aYUVColorSpace, gfx::ColorDepth aColorDepth,
gfx::ColorRange aColorRange, gfx::IntSize aSizeY, gfx::IntSize aSizeCbCr);
const gfx::YUVColorSpace aYUVColorSpace,
const gfx::ColorDepth aColorDepth, const gfx::ColorRange aColorRange,
const gfx::IntSize aSizeY, const gfx::IntSize aSizeCbCr,
const layers::GpuProcessFencesHolderId aFencesHolderId);
RenderDXGIYCbCrTextureHost* AsRenderDXGIYCbCrTextureHost() override {
return this;
@@ -200,7 +202,7 @@ class RenderDXGIYCbCrTextureHost final : public RenderTextureHostSWGL {
RefPtr<gfx::FileHandleWrapper> mHandles[3];
RefPtr<ID3D11Texture2D> mTextures[3];
RefPtr<IDXGIKeyedMutex> mKeyedMutexs[3];
RefPtr<ID3D11Device> mDevice;
EGLSurface mSurfaces[3];
EGLStreamKHR mStreams[3];
@@ -212,13 +214,14 @@ class RenderDXGIYCbCrTextureHost final : public RenderTextureHostSWGL {
RefPtr<ID3D11DeviceContext> mDeviceContext;
RefPtr<ID3D11Texture2D> mCpuTexture[3];
gfx::YUVColorSpace mYUVColorSpace;
gfx::ColorDepth mColorDepth;
gfx::ColorRange mColorRange;
gfx::IntSize mSizeY;
gfx::IntSize mSizeCbCr;
const gfx::YUVColorSpace mYUVColorSpace;
const gfx::ColorDepth mColorDepth;
const gfx::ColorRange mColorRange;
const gfx::IntSize mSizeY;
const gfx::IntSize mSizeCbCr;
const layers::GpuProcessFencesHolderId mFencesHolderId;
bool mLocked;
bool mLocked = false;
};
} // namespace wr

View File

@@ -21,6 +21,7 @@
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorManagerParent.h"
#include "mozilla/layers/Fence.h"
#include "mozilla/layers/WebRenderBridgeParent.h"
#include "mozilla/layers/SharedSurfacesParent.h"
#include "mozilla/layers/SurfacePool.h"
@@ -866,10 +867,10 @@ void RenderThread::UpdateAndRender(
renderer->GetCompositorBridge(), info, aStartId,
aStartTime, start, end, aRender, *aStats));
UniqueFileHandle fenceFd;
RefPtr<layers::Fence> fence;
if (latestFrameId.IsValid()) {
fenceFd = renderer->GetAndResetReleaseFence();
fence = renderer->GetAndResetReleaseFence();
// Wait for GPU after posting NotifyDidRender, since the wait is not
// necessary for the NotifyDidRender.
@@ -898,7 +899,7 @@ void RenderThread::UpdateAndRender(
// this code at all; it would bail out at the mRenderers.find check above.
MOZ_ASSERT(pipelineMgr);
pipelineMgr->NotifyPipelinesUpdated(info, latestFrameId, lastCompletedFrameId,
std::move(fenceFd));
std::move(fence));
}
void RenderThread::Pause(wr::WindowId aWindowId) {

View File

@@ -36,6 +36,7 @@ class GLContext;
} // namespace gl
namespace layers {
class CompositorBridgeParent;
class Fence;
class ShaderProgramOGLsHolder;
class SurfacePool;
} // namespace layers

View File

@@ -13,6 +13,7 @@
#include "mozilla/gfx/Types.h"
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/Fence.h"
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/layers/ProfilerScreenshots.h"
#include "mozilla/webrender/RenderCompositor.h"
@@ -280,7 +281,7 @@ void RendererOGL::WaitForGPU() {
}
}
UniqueFileHandle RendererOGL::GetAndResetReleaseFence() {
RefPtr<layers::Fence> RendererOGL::GetAndResetReleaseFence() {
return mCompositor->GetAndResetReleaseFence();
}

View File

@@ -27,6 +27,7 @@ class GLContext;
namespace layers {
class CompositorBridgeParent;
class Fence;
class SyncObjectHost;
} // namespace layers
@@ -70,7 +71,7 @@ class RendererOGL {
void WaitForGPU();
/// This can be called on the render thread only.
UniqueFileHandle GetAndResetReleaseFence();
RefPtr<layers::Fence> GetAndResetReleaseFence();
/// This can be called on the render thread only.
RenderedFrameId GetLastCompletedFrameId();