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

@@ -30,6 +30,7 @@
#include "mozilla/glean/DomMediaPlatformsWmfMetrics.h"
#include "mozilla/gfx/DeviceManagerDx.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/FenceD3D11.h"
#include "mozilla/layers/LayersTypes.h"
#include "nsPrintfCString.h"
#include "nsThreadUtils.h"
@@ -668,10 +669,18 @@ WMFVideoMFTManager::CreateBasicVideoFrame(IMFSample* aSample,
return S_OK;
}
RefPtr<layers::PlanarYCbCrImage> image =
new IMFYCbCrImage(buffer, twoDBuffer, mKnowsCompositor, mImageContainer);
RefPtr<layers::PlanarYCbCrImage> image;
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice();
if (XRE_IsGPUProcess() && layers::FenceD3D11::IsSupported(device)) {
// Store YCbCr to 3 ID3D11Texture2Ds
image = new IMFYCbCrImage(buffer, twoDBuffer, mKnowsCompositor,
mImageContainer);
VideoData::SetVideoDataToImage(image, mVideoInfo, b, pictureRegion, false);
} else {
// Store YCbCr to shmem
image = mImageContainer->CreatePlanarYCbCrImage();
VideoData::SetVideoDataToImage(image, mVideoInfo, b, pictureRegion, true);
}
RefPtr<VideoData> v = VideoData::CreateFromImage(
mVideoInfo.mDisplay, aStreamOffset, pts, duration, image.forget(), false,

View File

@@ -74,6 +74,7 @@
# include "gfxWindowsPlatform.h"
# include "mozilla/WindowsVersion.h"
# include "mozilla/gfx/DeviceManagerDx.h"
# include "mozilla/layers/GpuProcessD3D11FencesHolderMap.h"
# include "mozilla/layers/GpuProcessD3D11TextureMap.h"
# include "mozilla/layers/TextureD3D11.h"
# include "mozilla/widget/WinCompositorWindowThread.h"
@@ -214,6 +215,7 @@ bool GPUParent::Init(mozilla::ipc::UntypedEndpoint&& aEndpoint,
#if defined(XP_WIN)
gfxWindowsPlatform::InitMemoryReportersForGPUProcess();
DeviceManagerDx::Init();
GpuProcessD3D11FencesHolderMap::Init();
GpuProcessD3D11TextureMap::Init();
auto rv = wmf::MediaFoundationInitializer::HasInitialized();
if (!rv) {
@@ -804,6 +806,7 @@ void GPUParent::ActorDestroy(ActorDestroyReason aWhy) {
#if defined(XP_WIN)
GpuProcessD3D11TextureMap::Shutdown();
GpuProcessD3D11FencesHolderMap::Shutdown();
DeviceManagerDx::Shutdown();
#endif
LayerTreeOwnerTracker::Shutdown();

View File

@@ -19,50 +19,6 @@ using namespace mozilla::gfx;
namespace mozilla {
namespace layers {
class AutoCheckLockD3D11Texture final {
public:
explicit AutoCheckLockD3D11Texture(ID3D11Texture2D* aTexture)
: mIsLocked(false) {
aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex));
if (!mMutex) {
// If D3D11Texture does not have keyed mutex, we think that the
// D3D11Texture could be locked.
mIsLocked = true;
return;
}
// Test to see if the keyed mutex has been released
HRESULT hr = mMutex->AcquireSync(0, 0);
if (hr == S_OK || hr == WAIT_ABANDONED) {
mIsLocked = true;
// According to Microsoft documentation:
// WAIT_ABANDONED - The shared surface and keyed mutex are no longer in a
// consistent state. If AcquireSync returns this value, you should release
// and recreate both the keyed mutex and the shared surface
// So even if we do get WAIT_ABANDONED, the keyed mutex will have to be
// released.
mSyncAcquired = true;
}
}
~AutoCheckLockD3D11Texture() {
if (!mSyncAcquired) {
return;
}
HRESULT hr = mMutex->ReleaseSync(0);
if (FAILED(hr)) {
NS_WARNING("Failed to unlock the texture");
}
}
bool IsLocked() const { return mIsLocked; }
private:
bool mIsLocked;
bool mSyncAcquired = false;
RefPtr<IDXGIKeyedMutex> mMutex;
};
DXGIYCbCrTextureAllocationHelper::DXGIYCbCrTextureAllocationHelper(
const PlanarYCbCrData& aData, TextureFlags aTextureFlags,
ID3D11Device* aDevice)
@@ -87,8 +43,6 @@ bool DXGIYCbCrTextureAllocationHelper::IsCompatible(
}
ID3D11Texture2D* textureY = dxgiData->GetD3D11Texture(0);
ID3D11Texture2D* textureCb = dxgiData->GetD3D11Texture(1);
ID3D11Texture2D* textureCr = dxgiData->GetD3D11Texture(2);
RefPtr<ID3D11Device> device;
textureY->GetDevice(getter_AddRefs(device));
@@ -96,17 +50,6 @@ bool DXGIYCbCrTextureAllocationHelper::IsCompatible(
return false;
}
// Test to see if the keyed mutex has been released.
// If D3D11Texture failed to lock, do not recycle the DXGIYCbCrTextureData.
AutoCheckLockD3D11Texture lockY(textureY);
AutoCheckLockD3D11Texture lockCr(textureCr);
AutoCheckLockD3D11Texture lockCb(textureCb);
if (!lockY.IsLocked() || !lockCr.IsLocked() || !lockCb.IsLocked()) {
return false;
}
return true;
}
@@ -118,26 +61,13 @@ already_AddRefed<TextureClient> DXGIYCbCrTextureAllocationHelper::Allocate(
? DXGI_FORMAT_R8_UNORM
: DXGI_FORMAT_R16_UNORM,
ySize.width, ySize.height, 1, 1);
newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
RefPtr<ID3D10Multithread> mt;
HRESULT hr = mDevice->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
if (FAILED(hr) || !mt) {
gfxCriticalError() << "Multithread safety interface not supported. " << hr;
return nullptr;
}
if (!mt->GetMultithreadProtected()) {
gfxCriticalError() << "Device used not marked as multithread-safe.";
return nullptr;
}
D3D11MTAutoEnter mtAutoEnter(mt.forget());
// Use FenceD3D11 for synchronization.
newDesc.MiscFlags =
D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED;
RefPtr<ID3D11Texture2D> textureY;
hr = mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureY));
HRESULT hr =
mDevice->CreateTexture2D(&newDesc, nullptr, getter_AddRefs(textureY));
NS_ENSURE_TRUE(SUCCEEDED(hr), nullptr);
newDesc.Width = cbcrSize.width;

24
gfx/layers/Fence.cpp Normal file
View File

@@ -0,0 +1,24 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Fence.h"
namespace mozilla {
namespace layers {
FenceFileHandle::FenceFileHandle(UniqueFileHandle&& aFileHandle)
: mFileHandle(std::move(aFileHandle)) {
MOZ_ASSERT(mFileHandle);
}
FenceFileHandle::~FenceFileHandle() = default;
UniqueFileHandle FenceFileHandle::DuplicateFileHandle() {
return mozilla::DuplicateFileHandle(mFileHandle);
}
} // namespace layers
} // namespace mozilla

48
gfx/layers/Fence.h Normal file
View File

@@ -0,0 +1,48 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_GFX_Fence_H
#define MOZILLA_GFX_Fence_H
#include "mozilla/gfx/FileHandleWrapper.h"
#include "nsISupportsImpl.h"
namespace mozilla {
namespace layers {
class FenceD3D11;
class FenceFileHandle;
class Fence {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Fence);
virtual FenceD3D11* AsFenceD3D11() { return nullptr; }
virtual FenceFileHandle* AsFenceFileHandle() { return nullptr; }
protected:
virtual ~Fence() = default;
};
class FenceFileHandle final : public Fence {
public:
explicit FenceFileHandle(UniqueFileHandle&& aFileHandle);
FenceFileHandle* AsFenceFileHandle() override { return this; }
UniqueFileHandle DuplicateFileHandle();
protected:
virtual ~FenceFileHandle();
UniqueFileHandle mFileHandle;
};
} // namespace layers
} // namespace mozilla
#endif // MOZILLA_GFX_Fence_H

View File

@@ -12,6 +12,8 @@
#include "mozilla/layers/CompositableClient.h"
#include "mozilla/layers/CompositableForwarder.h"
#include "mozilla/layers/D3D11YCbCrImage.h"
#include "mozilla/layers/FenceD3D11.h"
#include "mozilla/layers/GpuProcessD3D11FencesHolderMap.h"
#include "mozilla/layers/TextureClient.h"
namespace mozilla {
@@ -39,18 +41,6 @@ bool IMFYCbCrImage::CopyDataToTexture(const Data& aData, ID3D11Device* aDevice,
DXGIYCbCrTextureData* aTextureData) {
MOZ_ASSERT(aTextureData);
HRESULT hr;
RefPtr<ID3D10Multithread> mt;
hr = aDevice->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt));
if (FAILED(hr)) {
return false;
}
if (!mt->GetMultithreadProtected()) {
return false;
}
if (!gfx::DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) {
return false;
}
@@ -59,8 +49,6 @@ bool IMFYCbCrImage::CopyDataToTexture(const Data& aData, ID3D11Device* aDevice,
ID3D11Texture2D* textureCb = aTextureData->GetD3D11Texture(1);
ID3D11Texture2D* textureCr = aTextureData->GetD3D11Texture(2);
D3D11MTAutoEnter mtAutoEnter(mt.forget());
RefPtr<ID3D11DeviceContext> ctx;
aDevice->GetImmediateContext(getter_AddRefs(ctx));
if (!ctx) {
@@ -68,26 +56,12 @@ bool IMFYCbCrImage::CopyDataToTexture(const Data& aData, ID3D11Device* aDevice,
return false;
}
// The documentation here seems to suggest using the immediate mode context
// on more than one thread is not allowed:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ff476891(v=vs.85).aspx
// The Debug Layer seems to imply it is though. When the ID3D10Multithread
// layer is on. The Enter/Leave of the critical section shouldn't even be
// required but were added for extra security.
{
AutoLockD3D11Texture lockY(textureY);
AutoLockD3D11Texture lockCr(textureCr);
AutoLockD3D11Texture lockCb(textureCb);
D3D11MTAutoEnter mtAutoEnter(mt.forget());
D3D11_BOX box;
box.front = box.top = box.left = 0;
box.back = 1;
box.right = aData.YDataSize().width;
box.bottom = aData.YDataSize().height;
ctx->UpdateSubresource(textureY, 0, &box, aData.mYChannel, aData.mYStride,
0);
ctx->UpdateSubresource(textureY, 0, &box, aData.mYChannel, aData.mYStride, 0);
box.right = aData.CbCrDataSize().width;
box.bottom = aData.CbCrDataSize().height;
@@ -95,8 +69,17 @@ bool IMFYCbCrImage::CopyDataToTexture(const Data& aData, ID3D11Device* aDevice,
aData.mCbCrStride, 0);
ctx->UpdateSubresource(textureCr, 0, &box, aData.mCrChannel,
aData.mCbCrStride, 0);
auto* fenceHolderMap = GpuProcessD3D11FencesHolderMap::Get();
if (!fenceHolderMap) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return false;
}
aTextureData->mWriteFence->IncrementAndSignal();
fenceHolderMap->SetWriteFence(aTextureData->mFencesHolderId,
aTextureData->mWriteFence);
return true;
}
@@ -106,6 +89,12 @@ TextureClient* IMFYCbCrImage::GetD3D11TextureClient(
return nullptr;
}
auto* fenceHolderMap = GpuProcessD3D11FencesHolderMap::Get();
if (!fenceHolderMap) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetImageDevice();
if (!device) {
return nullptr;
@@ -124,6 +113,10 @@ TextureClient* IMFYCbCrImage::GetD3D11TextureClient(
DXGIYCbCrTextureData* data =
mTextureClient->GetInternalData()->AsDXGIYCbCrTextureData();
if (!fenceHolderMap->WaitAllFencesAndForget(data->mFencesHolderId, device)) {
return nullptr;
}
if (!CopyDataToTexture(mData, device, data)) {
// Failed to copy data
mTextureClient = nullptr;

View File

@@ -86,6 +86,17 @@ GpuProcessTextureId GpuProcessTextureId::GetNext() {
return GpuProcessTextureId{++sCounter};
}
/* static */
GpuProcessFencesHolderId GpuProcessFencesHolderId::GetNext() {
if (!XRE_IsGPUProcess()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return GpuProcessFencesHolderId{};
}
static std::atomic<uint64_t> sCounter = 0;
return GpuProcessFencesHolderId{++sCounter};
}
std::ostream& operator<<(std::ostream& os, ScrollDirection aDirection) {
switch (aDirection) {
case ScrollDirection::eHorizontal:

View File

@@ -464,6 +464,36 @@ struct GpuProcessTextureId {
};
};
// FencesHolderId allocated in GPU process
struct GpuProcessFencesHolderId {
uint64_t mId = 0;
static GpuProcessFencesHolderId GetNext();
bool IsValid() const { return mId != 0; }
// Allow explicit cast to a uint64_t for now
explicit operator uint64_t() const { return mId; }
bool operator==(const GpuProcessFencesHolderId& aOther) const {
return mId == aOther.mId;
}
bool operator!=(const GpuProcessFencesHolderId& aOther) const {
return !(*this == aOther);
}
// Helper struct that allow this class to be used as a key in
// std::unordered_map like so:
// std::unordered_map<GpuProcessQueryId, ValueType,
// GpuProcessQueryId::HashFn> myMap;
struct HashFn {
std::size_t operator()(const GpuProcessFencesHolderId aKey) const {
return std::hash<uint64_t>{}(aKey.mId);
}
};
};
// clang-format off
MOZ_DEFINE_ENUM_CLASS_WITH_BASE(ScrollDirection, uint8_t, (
eVertical,

View File

@@ -223,6 +223,13 @@ DXGITextureHostD3D11* GPUVideoTextureHost::AsDXGITextureHostD3D11() {
return nullptr;
}
DXGIYCbCrTextureHostD3D11* GPUVideoTextureHost::AsDXGIYCbCrTextureHostD3D11() {
if (EnsureWrappedTextureHost()) {
return mWrappedTextureHost->AsDXGIYCbCrTextureHostD3D11();
}
return nullptr;
}
bool GPUVideoTextureHost::IsWrappingSurfaceTextureHost() {
if (EnsureWrappedTextureHost()) {
return EnsureWrappedTextureHost()->IsWrappingSurfaceTextureHost();

View File

@@ -69,6 +69,8 @@ class GPUVideoTextureHost : public TextureHost {
DXGITextureHostD3D11* AsDXGITextureHostD3D11() override;
DXGIYCbCrTextureHostD3D11* AsDXGIYCbCrTextureHostD3D11() override;
bool IsWrappingSurfaceTextureHost() override;
TextureHostType GetTextureHostType() override;

View File

@@ -63,6 +63,7 @@ class CompositableParentManager;
class ReadLockDescriptor;
class CompositorBridgeParent;
class DXGITextureHostD3D11;
class DXGIYCbCrTextureHostD3D11;
class SurfaceDescriptor;
class HostIPCAllocator;
class ISurfaceAllocator;
@@ -626,6 +627,10 @@ class TextureHost : public AtomicRefCountedWithFinalize<TextureHost> {
virtual DXGITextureHostD3D11* AsDXGITextureHostD3D11() { return nullptr; }
virtual DXGIYCbCrTextureHostD3D11* AsDXGIYCbCrTextureHostD3D11() {
return nullptr;
}
virtual bool IsWrappingSurfaceTextureHost() { return false; }
// Create the corresponding RenderTextureHost type of this texture, and

View File

@@ -9,6 +9,7 @@
#include <d3d11.h>
#include <d3d11_3.h>
#include <d3d11_4.h>
#include <dxgi1_6.h>
#include "mozilla/gfx/Logging.h"
@@ -36,7 +37,7 @@ RefPtr<FenceD3D11> FenceD3D11::Create(ID3D11Device* aDevice) {
RefPtr<ID3D11Fence> fenceD3D11;
d3d11_5->CreateFence(0, D3D11_FENCE_FLAG_SHARED,
IID_PPV_ARGS((ID3D11Fence**)getter_AddRefs(fenceD3D11)));
if (FAILED(hr)) {
if (FAILED(hr) || !fenceD3D11) {
gfxCriticalNoteOnce << "Fence creation failed: " << gfx::hexa(hr);
return nullptr;
}
@@ -68,13 +69,45 @@ RefPtr<FenceD3D11> FenceD3D11::CreateFromHandle(
/* static */
bool FenceD3D11::IsSupported(ID3D11Device* aDevice) {
MOZ_ASSERT(aDevice);
if (!aDevice) {
return false;
}
RefPtr<ID3D11Device5> d3d11_5;
auto hr =
aDevice->QueryInterface(__uuidof(ID3D11Device5), getter_AddRefs(d3d11_5));
auto hr = aDevice->QueryInterface((ID3D11Device5**)getter_AddRefs(d3d11_5));
if (FAILED(hr)) {
return false;
}
return true;
// Check for IDXGIAdapter4:
RefPtr<IDXGIDevice> dxgiDevice;
aDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice));
if (FAILED(hr)) {
return false;
}
RefPtr<IDXGIAdapter> dxgiAdapter;
hr = dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter));
if (FAILED(hr)) {
return false;
}
RefPtr<IDXGIAdapter4> dxgiAdapter4;
dxgiAdapter->QueryInterface((IDXGIAdapter4**)getter_AddRefs(dxgiAdapter4));
if (FAILED(hr)) {
gfxCriticalNoteOnce << "Failed to get IDXGIAdapter4: " << gfx::hexa(hr);
return false;
}
DXGI_ADAPTER_DESC3 adapterDesc;
hr = dxgiAdapter4->GetDesc3(&adapterDesc);
if (FAILED(hr)) {
return false;
}
// The adapter must support monitored fences.
return adapterDesc.Flags & DXGI_ADAPTER_FLAG3_SUPPORT_MONITORED_FENCES;
}
FenceD3D11::FenceD3D11(RefPtr<gfx::FileHandleWrapper>& aHandle)
@@ -84,6 +117,14 @@ FenceD3D11::FenceD3D11(RefPtr<gfx::FileHandleWrapper>& aHandle)
FenceD3D11::~FenceD3D11() {}
RefPtr<FenceD3D11> FenceD3D11::CloneFromHandle() {
RefPtr<FenceD3D11> fence = FenceD3D11::CreateFromHandle(mHandle);
if (fence) {
fence->Update(mFenceValue);
}
return fence;
}
gfx::FenceInfo FenceD3D11::GetFenceInfo() const {
return gfx::FenceInfo(mHandle, mFenceValue);
}

View File

@@ -10,13 +10,12 @@
#include <unordered_map>
#include "mozilla/gfx/FileHandleWrapper.h"
#include "nsISupportsImpl.h"
#include "mozilla/layers/Fence.h"
struct ID3D11Device;
struct ID3D11Fence;
namespace mozilla {
namespace layers {
//
@@ -36,17 +35,20 @@ namespace layers {
// For waiting fence, Update() is used to update the target value of the
// waiting. Wait() is then used to wait for the fence.
//
class FenceD3D11 final {
class FenceD3D11 final : public Fence {
public:
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FenceD3D11);
static RefPtr<FenceD3D11> Create(ID3D11Device* aDevice);
static RefPtr<FenceD3D11> CreateFromHandle(
RefPtr<gfx::FileHandleWrapper> aHandle);
FenceD3D11* AsFenceD3D11() override { return this; }
// Check if ID3D11Device suppors ID3D11Fence creation.
static bool IsSupported(ID3D11Device* aDevice);
RefPtr<FenceD3D11> CloneFromHandle();
// Updates mSignalFence to incremented value after all previous work has
// completed. Used only when FenceD3D11 is created by FenceD3D11::Create().
bool IncrementAndSignal();
@@ -66,7 +68,7 @@ class FenceD3D11 final {
protected:
explicit FenceD3D11(RefPtr<gfx::FileHandleWrapper>& aHandle);
~FenceD3D11();
virtual ~FenceD3D11();
// Device that is used for creating mSignalFence.
RefPtr<ID3D11Device> mDevice;

View File

@@ -0,0 +1,169 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GpuProcessD3D11FencesHolderMap.h"
#include "mozilla/layers/FenceD3D11.h"
namespace mozilla {
namespace layers {
StaticAutoPtr<GpuProcessD3D11FencesHolderMap>
GpuProcessD3D11FencesHolderMap::sInstance;
/* static */
void GpuProcessD3D11FencesHolderMap::Init() {
MOZ_ASSERT(XRE_IsGPUProcess());
sInstance = new GpuProcessD3D11FencesHolderMap();
}
/* static */
void GpuProcessD3D11FencesHolderMap::Shutdown() {
MOZ_ASSERT(XRE_IsGPUProcess());
sInstance = nullptr;
}
GpuProcessD3D11FencesHolderMap::GpuProcessD3D11FencesHolderMap()
: mMonitor("GpuProcessD3D11FencesHolderMap::mMonitor") {}
GpuProcessD3D11FencesHolderMap::~GpuProcessD3D11FencesHolderMap() {}
void GpuProcessD3D11FencesHolderMap::Register(
GpuProcessFencesHolderId aHolderId) {
MonitorAutoLock lock(mMonitor);
mFencesHolderById[aHolderId] = MakeUnique<FencesHolder>();
}
void GpuProcessD3D11FencesHolderMap::Unregister(
GpuProcessFencesHolderId aHolderId) {
MonitorAutoLock lock(mMonitor);
auto it = mFencesHolderById.find(aHolderId);
if (it == mFencesHolderById.end()) {
return;
}
mFencesHolderById.erase(it);
}
void GpuProcessD3D11FencesHolderMap::SetWriteFence(
GpuProcessFencesHolderId aHolderId, RefPtr<FenceD3D11> aWriteFence) {
MOZ_ASSERT(aWriteFence);
if (!aWriteFence) {
return;
}
MonitorAutoLock lock(mMonitor);
auto it = mFencesHolderById.find(aHolderId);
if (it == mFencesHolderById.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return;
}
RefPtr<FenceD3D11> fence = aWriteFence->CloneFromHandle();
if (!fence) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return;
}
MOZ_ASSERT(!it->second->mWriteFence);
MOZ_ASSERT(it->second->mReadFences.empty());
it->second->mWriteFence = fence;
}
void GpuProcessD3D11FencesHolderMap::SetReadFence(
GpuProcessFencesHolderId aHolderId, RefPtr<FenceD3D11> aReadFence) {
MOZ_ASSERT(aReadFence);
if (!aReadFence) {
return;
}
MonitorAutoLock lock(mMonitor);
auto it = mFencesHolderById.find(aHolderId);
if (it == mFencesHolderById.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return;
}
RefPtr<FenceD3D11> fence = aReadFence->CloneFromHandle();
if (!fence) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return;
}
it->second->mReadFences.push_back(fence);
}
bool GpuProcessD3D11FencesHolderMap::WaitWriteFence(
GpuProcessFencesHolderId aHolderId, ID3D11Device* aDevice) {
MOZ_ASSERT(aDevice);
if (!aDevice) {
return false;
}
RefPtr<FenceD3D11> writeFence;
{
MonitorAutoLock lock(mMonitor);
auto it = mFencesHolderById.find(aHolderId);
if (it == mFencesHolderById.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return false;
}
writeFence = it->second->mWriteFence;
}
if (!writeFence) {
return true;
}
return writeFence->Wait(aDevice);
}
bool GpuProcessD3D11FencesHolderMap::WaitAllFencesAndForget(
GpuProcessFencesHolderId aHolderId, ID3D11Device* aDevice) {
MOZ_ASSERT(aDevice);
if (!aDevice) {
return false;
}
RefPtr<FenceD3D11> writeFence;
std::vector<RefPtr<FenceD3D11>> readFences;
{
MonitorAutoLock lock(mMonitor);
auto it = mFencesHolderById.find(aHolderId);
if (it == mFencesHolderById.end()) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return false;
}
writeFence = it->second->mWriteFence.forget();
readFences.swap(it->second->mReadFences);
MOZ_ASSERT(!it->second->mWriteFence);
MOZ_ASSERT(it->second->mReadFences.empty());
}
if (writeFence) {
writeFence->Wait(aDevice);
}
for (auto& fence : readFences) {
fence->Wait(aDevice);
}
return true;
}
} // namespace layers
} // namespace mozilla

View File

@@ -0,0 +1,68 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef MOZILLA_GFX_GpuProcessD3D11FencesHolderMap_H
#define MOZILLA_GFX_GpuProcessD3D11FencesHolderMap_H
#include <d3d11.h>
#include <vector>
#include "mozilla/layers/LayersTypes.h"
#include "mozilla/Maybe.h"
#include "mozilla/Monitor.h"
#include "mozilla/StaticPtr.h"
namespace mozilla {
namespace layers {
class FenceD3D11;
/**
* A class to manage FenceD3D11 that is shared in GPU process.
*/
class GpuProcessD3D11FencesHolderMap {
public:
static void Init();
static void Shutdown();
static GpuProcessD3D11FencesHolderMap* Get() { return sInstance; }
GpuProcessD3D11FencesHolderMap();
~GpuProcessD3D11FencesHolderMap();
void Register(GpuProcessFencesHolderId aHolderId);
void Unregister(GpuProcessFencesHolderId aHolderId);
void SetWriteFence(GpuProcessFencesHolderId aHolderId,
RefPtr<FenceD3D11> aWriteFence);
void SetReadFence(GpuProcessFencesHolderId aHolderId,
RefPtr<FenceD3D11> aReadFence);
bool WaitWriteFence(GpuProcessFencesHolderId aHolderId,
ID3D11Device* aDevice);
bool WaitAllFencesAndForget(GpuProcessFencesHolderId aHolderId,
ID3D11Device* aDevice);
private:
struct FencesHolder {
FencesHolder() = default;
RefPtr<FenceD3D11> mWriteFence;
std::vector<RefPtr<FenceD3D11>> mReadFences;
};
mutable Monitor mMonitor MOZ_UNANNOTATED;
std::unordered_map<GpuProcessFencesHolderId, UniquePtr<FencesHolder>,
GpuProcessFencesHolderId::HashFn>
mFencesHolderById;
static StaticAutoPtr<GpuProcessD3D11FencesHolderMap> sInstance;
};
} // namespace layers
} // namespace mozilla
#endif /* MOZILLA_GFX_GpuProcessD3D11FencesHolderMap_H */

View File

@@ -23,6 +23,8 @@
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/D3D11ZeroCopyTextureImage.h"
#include "mozilla/layers/FenceD3D11.h"
#include "mozilla/layers/GpuProcessD3D11FencesHolderMap.h"
#include "mozilla/layers/GpuProcessD3D11TextureMap.h"
#include "mozilla/layers/HelpersD3D11.h"
#include "mozilla/layers/VideoProcessorD3D11.h"
@@ -661,8 +663,8 @@ DXGIYCbCrTextureData* DXGIYCbCrTextureData::Create(
ID3D11Texture2D* aTextureY, ID3D11Texture2D* aTextureCb,
ID3D11Texture2D* aTextureCr, const gfx::IntSize& aSize,
const gfx::IntSize& aSizeY, const gfx::IntSize& aSizeCbCr,
gfx::ColorDepth aColorDepth, YUVColorSpace aYUVColorSpace,
gfx::ColorRange aColorRange) {
const gfx::ColorDepth aColorDepth, const YUVColorSpace aYUVColorSpace,
const gfx::ColorRange aColorRange) {
if (!aTextureY || !aTextureCb || !aTextureCr) {
return nullptr;
}
@@ -714,13 +716,33 @@ DXGIYCbCrTextureData* DXGIYCbCrTextureData::Create(
const RefPtr<gfx::FileHandleWrapper> sharedHandleCr =
new gfx::FileHandleWrapper(UniqueFileHandle(handleCr));
auto* fenceHolderMap = GpuProcessD3D11FencesHolderMap::Get();
if (!fenceHolderMap) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return nullptr;
}
RefPtr<ID3D11Device> device;
aTextureY->GetDevice(getter_AddRefs(device));
if (!device) {
return nullptr;
}
RefPtr<FenceD3D11> fence = FenceD3D11::Create(device);
if (!fence) {
return nullptr;
}
auto fencesHolderId = GpuProcessFencesHolderId::GetNext();
fenceHolderMap->Register(fencesHolderId);
RefPtr<ID3D11Texture2D> textures[3] = {aTextureY, aTextureCb, aTextureCr};
RefPtr<gfx::FileHandleWrapper> handles[3] = {sharedHandleY, sharedHandleCb,
sharedHandleCr};
DXGIYCbCrTextureData* texture =
new DXGIYCbCrTextureData(textures, handles, aSize, aSizeY, aSizeCbCr,
aColorDepth, aYUVColorSpace, aColorRange);
DXGIYCbCrTextureData* texture = new DXGIYCbCrTextureData(
textures, handles, aSize, aSizeY, aSizeCbCr, aColorDepth, aYUVColorSpace,
aColorRange, fencesHolderId, fence);
return texture;
}
@@ -729,16 +751,29 @@ DXGIYCbCrTextureData::DXGIYCbCrTextureData(
RefPtr<gfx::FileHandleWrapper>(aHandles)[3], const gfx::IntSize& aSize,
const gfx::IntSize& aSizeY, const gfx::IntSize& aSizeCbCr,
const gfx::ColorDepth aColorDepth, const gfx::YUVColorSpace aYUVColorSpace,
const gfx::ColorRange aColorRange)
const gfx::ColorRange aColorRange,
const GpuProcessFencesHolderId aFencesHolderId,
const RefPtr<FenceD3D11> aWriteFence)
: mSize(aSize),
mSizeY(aSizeY),
mSizeCbCr(aSizeCbCr),
mColorDepth(aColorDepth),
mYUVColorSpace(aYUVColorSpace),
mColorRange(aColorRange),
mFencesHolderId(aFencesHolderId),
mWriteFence(aWriteFence),
mD3D11Textures{aD3D11Textures[0], aD3D11Textures[1], aD3D11Textures[2]},
mHandles{aHandles[0], aHandles[1], aHandles[2]} {}
DXGIYCbCrTextureData::~DXGIYCbCrTextureData() {
auto* fenceHolderMap = GpuProcessD3D11FencesHolderMap::Get();
if (!fenceHolderMap) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return;
}
fenceHolderMap->Unregister(mFencesHolderId);
}
void DXGIYCbCrTextureData::FillInfo(TextureData::Info& aInfo) const {
aInfo.size = mSize;
aInfo.format = gfx::SurfaceFormat::YUV420;
@@ -748,9 +783,9 @@ void DXGIYCbCrTextureData::FillInfo(TextureData::Info& aInfo) const {
void DXGIYCbCrTextureData::SerializeSpecific(
SurfaceDescriptorDXGIYCbCr* const aOutDesc) {
*aOutDesc = SurfaceDescriptorDXGIYCbCr(mHandles[0], mHandles[1], mHandles[2],
mSize, mSizeY, mSizeCbCr, mColorDepth,
mYUVColorSpace, mColorRange);
*aOutDesc = SurfaceDescriptorDXGIYCbCr(
mHandles[0], mHandles[1], mHandles[2], mSize, mSizeY, mSizeCbCr,
mColorDepth, mYUVColorSpace, mColorRange, mFencesHolderId);
}
bool DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
@@ -1325,10 +1360,10 @@ DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11(
mSize(aDescriptor.size()),
mSizeY(aDescriptor.sizeY()),
mSizeCbCr(aDescriptor.sizeCbCr()),
mIsLocked(false),
mColorDepth(aDescriptor.colorDepth()),
mYUVColorSpace(aDescriptor.yUVColorSpace()),
mColorRange(aDescriptor.colorRange()) {
mColorRange(aDescriptor.colorRange()),
mFencesHolderId(aDescriptor.fencesHolderId()) {
mHandles[0] = aDescriptor.handleY();
mHandles[1] = aDescriptor.handleCb();
mHandles[2] = aDescriptor.handleCr();
@@ -1339,7 +1374,8 @@ void DXGIYCbCrTextureHostD3D11::CreateRenderTexture(
MOZ_ASSERT(mExternalImageId.isSome());
RefPtr<wr::RenderTextureHost> texture = new wr::RenderDXGIYCbCrTextureHost(
mHandles, mYUVColorSpace, mColorDepth, mColorRange, mSizeY, mSizeCbCr);
mHandles, mYUVColorSpace, mColorDepth, mColorRange, mSizeY, mSizeCbCr,
mFencesHolderId);
wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
texture.forget());
@@ -1418,6 +1454,30 @@ bool DXGIYCbCrTextureHostD3D11::SupportsExternalCompositing(
return aBackend == WebRenderBackend::SOFTWARE;
}
void DXGIYCbCrTextureHostD3D11::NotifyNotUsed() {
if (!mReadFence) {
return;
}
auto* fenceHolderMap = GpuProcessD3D11FencesHolderMap::Get();
if (!fenceHolderMap) {
MOZ_ASSERT_UNREACHABLE("unexpected to be called");
return;
}
fenceHolderMap->SetReadFence(mFencesHolderId, mReadFence);
mReadFence = nullptr;
}
void DXGIYCbCrTextureHostD3D11::SetReadFence(RefPtr<FenceD3D11> aReadFence) {
MOZ_ASSERT(aReadFence);
if (!aReadFence) {
return;
}
mReadFence = aReadFence;
}
bool DataTextureSourceD3D11::Update(DataSourceSurface* aSurface,
nsIntRegion* aDestRegion,
IntPoint* aSrcOffset,

View File

@@ -35,6 +35,8 @@ class GLBlitHelper;
namespace layers {
class FenceD3D11;
gfx::DeviceResetReason DXGIErrorToDeviceResetReason(HRESULT aError);
already_AddRefed<TextureHost> CreateTextureHostD3D11(
@@ -164,12 +166,15 @@ class DXGIYCbCrTextureData : public TextureData {
friend class gl::GLBlitHelper;
public:
static DXGIYCbCrTextureData* Create(
ID3D11Texture2D* aTextureCb, ID3D11Texture2D* aTextureY,
ID3D11Texture2D* aTextureCr, const gfx::IntSize& aSize,
const gfx::IntSize& aSizeY, const gfx::IntSize& aSizeCbCr,
gfx::ColorDepth aColorDepth, gfx::YUVColorSpace aYUVColorSpace,
gfx::ColorRange aColorRange);
static DXGIYCbCrTextureData* Create(ID3D11Texture2D* aTextureCb,
ID3D11Texture2D* aTextureY,
ID3D11Texture2D* aTextureCr,
const gfx::IntSize& aSize,
const gfx::IntSize& aSizeY,
const gfx::IntSize& aSizeCbCr,
const gfx::ColorDepth aColorDepth,
const gfx::YUVColorSpace aYUVColorSpace,
const gfx::ColorRange aColorRange);
bool Lock(OpenMode) override { return true; }
@@ -203,6 +208,8 @@ class DXGIYCbCrTextureData : public TextureData {
const gfx::ColorDepth mColorDepth;
const gfx::YUVColorSpace mYUVColorSpace;
const gfx::ColorRange mColorRange;
const GpuProcessFencesHolderId mFencesHolderId;
const RefPtr<FenceD3D11> mWriteFence;
protected:
DXGIYCbCrTextureData(RefPtr<ID3D11Texture2D> (&aD3D11Textures)[3],
@@ -211,7 +218,10 @@ class DXGIYCbCrTextureData : public TextureData {
const gfx::IntSize& aSizeCbCr,
const gfx::ColorDepth aColorDepth,
const gfx::YUVColorSpace aYUVColorSpace,
const gfx::ColorRange aColorRange);
const gfx::ColorRange aColorRange,
const GpuProcessFencesHolderId aFencesHolderId,
const RefPtr<FenceD3D11> aWriteFence);
virtual ~DXGIYCbCrTextureData();
RefPtr<ID3D11Texture2D> mD3D11Textures[3];
RefPtr<gfx::FileHandleWrapper> mHandles[3];
@@ -435,19 +445,28 @@ class DXGIYCbCrTextureHostD3D11 : public TextureHost {
bool SupportsExternalCompositing(WebRenderBackend aBackend) override;
protected:
RefPtr<ID3D11Texture2D> mTextures[3];
void NotifyNotUsed() override;
gfx::IntSize mSize;
gfx::IntSize mSizeY;
gfx::IntSize mSizeCbCr;
DXGIYCbCrTextureHostD3D11* AsDXGIYCbCrTextureHostD3D11() override {
return this;
}
void SetReadFence(RefPtr<FenceD3D11> aReadFence);
const gfx::IntSize mSize;
const gfx::IntSize mSizeY;
const gfx::IntSize mSizeCbCr;
const gfx::ColorDepth mColorDepth;
const gfx::YUVColorSpace mYUVColorSpace;
const gfx::ColorRange mColorRange;
const GpuProcessFencesHolderId mFencesHolderId;
protected:
// Handles will be closed automatically when `UniqueFileHandle` gets
// destroyed.
RefPtr<gfx::FileHandleWrapper> mHandles[3];
bool mIsLocked;
gfx::ColorDepth mColorDepth;
gfx::YUVColorSpace mYUVColorSpace;
gfx::ColorRange mColorRange;
bool mIsLocked = false;
RefPtr<FenceD3D11> mReadFence;
};
class CompositingRenderTargetD3D11 : public CompositingRenderTarget,

View File

@@ -262,6 +262,18 @@ struct ParamTraits<mozilla::layers::GpuProcessTextureId> {
}
};
template <>
struct ParamTraits<mozilla::layers::GpuProcessFencesHolderId> {
typedef mozilla::layers::GpuProcessFencesHolderId paramType;
static void Write(MessageWriter* writer, const paramType& param) {
WriteParam(writer, param.mId);
}
static bool Read(MessageReader* reader, paramType* result) {
return ReadParam(reader, &result->mId);
}
};
template <>
struct ParamTraits<mozilla::layers::FrameMetrics>
: BitfieldHelper<mozilla::layers::FrameMetrics> {

View File

@@ -30,6 +30,7 @@ using mozilla::layers::RemoteTextureId from "mozilla/layers/LayersTypes.h";
using mozilla::layers::RemoteTextureOwnerId from "mozilla/layers/LayersTypes.h";
[RefCounted] using mozilla::layers::GpuFence from "mozilla/layers/GpuFence.h";
using mozilla::layers::GpuProcessTextureId from "mozilla/layers/LayersTypes.h";
using mozilla::layers::GpuProcessFencesHolderId from "mozilla/layers/LayersTypes.h";
using mozilla::wr::ExternalImageSource from "mozilla/webrender/WebRenderTypes.h";
using mozilla::wr::ExternalImageId from "mozilla/webrender/WebRenderTypes.h";
using mozilla::layers::SurfaceDescriptorRemoteDecoderId from "mozilla/layers/LayersTypes.h";
@@ -60,6 +61,7 @@ namespace layers {
ColorDepth colorDepth;
YUVColorSpace yUVColorSpace;
ColorRange colorRange;
GpuProcessFencesHolderId fencesHolderId;
};
[Comparable] struct SurfaceDescriptorMacIOSurface {

View File

@@ -38,6 +38,7 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
"d3d11/CompositorD3D11.h",
"d3d11/DeviceAttachmentsD3D11.h",
"d3d11/FenceD3D11.h",
"d3d11/GpuProcessD3D11FencesHolderMap.h",
"d3d11/GpuProcessD3D11TextureMap.h",
"d3d11/HelpersD3D11.h",
"d3d11/ShaderDefinitionsD3D11.h",
@@ -47,6 +48,7 @@ if CONFIG["MOZ_WIDGET_TOOLKIT"] == "windows":
]
UNIFIED_SOURCES += [
"d3d11/FenceD3D11.cpp",
"d3d11/GpuProcessD3D11FencesHolderMap.cpp",
"d3d11/GpuProcessD3D11TextureMap.cpp",
"d3d11/TextureD3D11.cpp",
"d3d11/TextureHostWrapperD3D11.cpp",
@@ -143,6 +145,7 @@ EXPORTS.mozilla.layers += [
"D3D11ZeroCopyTextureImage.h",
"DirectionUtils.h",
"Effects.h",
"Fence.h",
"GpuFence.h",
"ImageDataSerializer.h",
"ipc/ActiveResource.h",
@@ -368,6 +371,7 @@ UNIFIED_SOURCES += [
"CompositorAnimationStorage.cpp",
"CompositorTypes.cpp",
"Effects.cpp",
"Fence.cpp",
"FrameMetrics.cpp",
"GLImages.cpp",
"ImageDataSerializer.cpp",

View File

@@ -14,6 +14,7 @@
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/layers/AsyncImagePipelineOp.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/Fence.h"
#include "mozilla/layers/RemoteTextureHostWrapper.h"
#include "mozilla/layers/SharedSurfacesParent.h"
#include "mozilla/layers/WebRenderImageHost.h"
@@ -27,6 +28,11 @@
# include "mozilla/layers/TextureHostOGL.h"
#endif
#ifdef XP_WIN
# include "mozilla/layers/FenceD3D11.h"
# include "mozilla/layers/TextureD3D11.h"
#endif
namespace mozilla {
namespace layers {
@@ -658,7 +664,7 @@ void AsyncImagePipelineManager::HoldExternalImage(
void AsyncImagePipelineManager::NotifyPipelinesUpdated(
RefPtr<const wr::WebRenderPipelineInfo> aInfo,
wr::RenderedFrameId aLatestFrameId,
wr::RenderedFrameId aLastCompletedFrameId, UniqueFileHandle&& aFenceFd) {
wr::RenderedFrameId aLastCompletedFrameId, RefPtr<Fence>&& aFence) {
MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
MOZ_ASSERT(mLastCompletedFrameId <= aLastCompletedFrameId.mId);
MOZ_ASSERT(aLatestFrameId.IsValid());
@@ -673,7 +679,7 @@ void AsyncImagePipelineManager::NotifyPipelinesUpdated(
// Move the pending updates into the submitted ones.
mRenderSubmittedUpdates.emplace_back(
aLatestFrameId,
WebRenderPipelineInfoHolder(std::move(aInfo), std::move(aFenceFd)));
WebRenderPipelineInfoHolder(std::move(aInfo), std::move(aFence)));
}
// Queue a runnable on the compositor thread to process the updates.
@@ -705,7 +711,7 @@ void AsyncImagePipelineManager::ProcessPipelineUpdates() {
auto& holder = update.second;
const auto& info = holder.mInfo->Raw();
mReleaseFenceFd = std::move(holder.mFenceFd);
mReleaseFence = std::move(holder.mFence);
for (auto& epoch : info.epochs) {
ProcessPipelineRendered(epoch.pipeline_id, epoch.epoch, update.first);
@@ -736,8 +742,10 @@ void AsyncImagePipelineManager::ProcessPipelineRendered(
for (auto it = holder->mTextureHostsUntilRenderSubmitted.begin();
it != firstSubmittedHostToKeep; ++it) {
const auto& entry = it;
if (entry->mTexture->GetAndroidHardwareBuffer() && mReleaseFenceFd) {
entry->mTexture->SetReleaseFence(DuplicateFileHandle(mReleaseFenceFd));
if (entry->mTexture->GetAndroidHardwareBuffer() && mReleaseFence &&
mReleaseFence->AsFenceFileHandle()) {
entry->mTexture->SetReleaseFence(
mReleaseFence->AsFenceFileHandle()->DuplicateFileHandle());
}
}
#endif
@@ -753,6 +761,18 @@ void AsyncImagePipelineManager::ProcessPipelineRendered(
holder->mTextureHostsUntilRenderCompleted.begin(),
holder->mTextureHostsUntilRenderCompleted.end(),
[&aEpoch](const auto& entry) { return aEpoch <= entry->mEpoch; });
#ifdef XP_WIN
for (auto it = holder->mTextureHostsUntilRenderCompleted.begin();
it != firstCompletedHostToKeep; ++it) {
const auto& entry = *it;
auto* host = entry->mTexture->AsDXGIYCbCrTextureHostD3D11();
if (host && mReleaseFence && mReleaseFence->AsFenceD3D11()) {
host->SetReadFence(mReleaseFence->AsFenceD3D11());
}
}
#endif
if (firstCompletedHostToKeep !=
holder->mTextureHostsUntilRenderCompleted.begin()) {
std::vector<UniquePtr<ForwardingTextureHost>> hostsUntilCompleted(
@@ -824,8 +844,8 @@ wr::Epoch AsyncImagePipelineManager::GetNextImageEpoch() {
AsyncImagePipelineManager::WebRenderPipelineInfoHolder::
WebRenderPipelineInfoHolder(RefPtr<const wr::WebRenderPipelineInfo>&& aInfo,
UniqueFileHandle&& aFenceFd)
: mInfo(aInfo), mFenceFd(std::move(aFenceFd)) {}
RefPtr<Fence>&& aFence)
: mInfo(aInfo), mFence(std::move(aFence)) {}
AsyncImagePipelineManager::WebRenderPipelineInfoHolder::
~WebRenderPipelineInfoHolder() = default;

View File

@@ -32,6 +32,7 @@ namespace layers {
class CompositableHost;
class CompositorVsyncScheduler;
class Fence;
class WebRenderImageHost;
class WebRenderTextureHost;
@@ -71,7 +72,7 @@ class AsyncImagePipelineManager final {
void NotifyPipelinesUpdated(RefPtr<const wr::WebRenderPipelineInfo> aInfo,
wr::RenderedFrameId aLatestFrameId,
wr::RenderedFrameId aLastCompletedFrameId,
UniqueFileHandle&& aFenceFd);
RefPtr<Fence>&& aFence);
// This is run on the compositor thread to process mRenderSubmittedUpdates. We
// make this public because we need to invoke it from other places.
@@ -277,11 +278,11 @@ class AsyncImagePipelineManager final {
struct WebRenderPipelineInfoHolder {
WebRenderPipelineInfoHolder(RefPtr<const wr::WebRenderPipelineInfo>&& aInfo,
UniqueFileHandle&& aFenceFd);
RefPtr<Fence>&& aFence);
~WebRenderPipelineInfoHolder();
WebRenderPipelineInfoHolder(WebRenderPipelineInfoHolder&&) = default;
RefPtr<const wr::WebRenderPipelineInfo> mInfo;
UniqueFileHandle mFenceFd;
RefPtr<Fence> mFence;
};
std::vector<std::pair<wr::RenderedFrameId, WebRenderPipelineInfoHolder>>
@@ -292,7 +293,7 @@ class AsyncImagePipelineManager final {
std::vector<std::pair<wr::RenderedFrameId,
std::vector<UniquePtr<ForwardingTextureHost>>>>
mTexturesInUseByGPU;
UniqueFileHandle mReleaseFenceFd;
RefPtr<Fence> mReleaseFence;
};
} // namespace layers

View File

@@ -16,6 +16,10 @@
# include "mozilla/layers/TextureHostOGL.h"
#endif
#ifdef XP_WIN
# include "mozilla/layers/TextureD3D11.h"
#endif
namespace mozilla::layers {
class ScheduleHandleRenderTextureOps : public wr::NotificationHandler {
@@ -119,6 +123,11 @@ void WebRenderTextureHost::NotifyNotUsed() {
mWrappedTextureHost->AsTextureHostWrapperD3D11()) {
mWrappedTextureHost->NotifyNotUsed();
}
#ifdef XP_WIN
if (auto* host = AsDXGIYCbCrTextureHostD3D11()) {
host->NotifyNotUsed();
}
#endif
TextureHost::NotifyNotUsed();
}

View File

@@ -72,6 +72,10 @@ class WebRenderTextureHost : public TextureHost {
return mWrappedTextureHost->AsDXGITextureHostD3D11();
}
DXGIYCbCrTextureHostD3D11* AsDXGIYCbCrTextureHostD3D11() override {
return mWrappedTextureHost->AsDXGIYCbCrTextureHostD3D11();
}
bool IsWrappingSurfaceTextureHost() override;
virtual void PrepareForUse() override;

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);
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();