/* -*- 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 "FenceD3D11.h" #include #include #include #include #include "mozilla/gfx/Logging.h" namespace mozilla { namespace layers { MOZ_RUNINIT RefPtr mDevice; /* static */ RefPtr FenceD3D11::Create(ID3D11Device* aDevice) { MOZ_ASSERT(aDevice); if (!aDevice) { return nullptr; } RefPtr d3d11_5; auto hr = aDevice->QueryInterface(__uuidof(ID3D11Device5), getter_AddRefs(d3d11_5)); if (FAILED(hr)) { gfxCriticalNoteOnce << "Failed to get ID3D11Device5: " << gfx::hexa(hr); return nullptr; } RefPtr fenceD3D11; d3d11_5->CreateFence(0, D3D11_FENCE_FLAG_SHARED, IID_PPV_ARGS((ID3D11Fence**)getter_AddRefs(fenceD3D11))); if (FAILED(hr) || !fenceD3D11) { gfxCriticalNoteOnce << "Fence creation failed: " << gfx::hexa(hr); return nullptr; } HANDLE sharedHandle = nullptr; hr = fenceD3D11->CreateSharedHandle(nullptr, GENERIC_ALL, nullptr, &sharedHandle); if (FAILED(hr)) { gfxCriticalNoteOnce << "Fence shared handle creation failed " << gfx::hexa(hr); return nullptr; } RefPtr handle = new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); RefPtr fence = new FenceD3D11(OwnsFence::Yes, aDevice, fenceD3D11, handle); return fence; } /* static */ RefPtr FenceD3D11::CreateFromHandle( RefPtr aHandle, const RefPtr aDevice) { MOZ_ASSERT(aHandle); if (!aHandle) { return nullptr; } // Opening shared handle is deferred. return new FenceD3D11(OwnsFence::No, aDevice, /* aSignalFence */ nullptr, aHandle); } /* static */ bool FenceD3D11::IsSupported(ID3D11Device* aDevice) { MOZ_ASSERT(aDevice); if (!aDevice) { return false; } RefPtr d3d11_5; auto hr = aDevice->QueryInterface((ID3D11Device5**)getter_AddRefs(d3d11_5)); if (FAILED(hr)) { return false; } // Check for IDXGIAdapter4: RefPtr dxgiDevice; aDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice)); if (FAILED(hr)) { return false; } RefPtr dxgiAdapter; hr = dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)); if (FAILED(hr)) { return false; } RefPtr 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(const OwnsFence aOwnsFence, const RefPtr aDevice, const RefPtr aSignalFence, const RefPtr& aHandle) : mOwnsFence(aOwnsFence), mDevice(aDevice), mSignalFence(aSignalFence), mHandle(aHandle) { MOZ_ASSERT(mHandle); MOZ_ASSERT_IF(mOwnsFence == OwnsFence::Yes, mDevice); MOZ_ASSERT_IF(mOwnsFence == OwnsFence::Yes, mSignalFence); MOZ_ASSERT_IF(mOwnsFence == OwnsFence::No, !mSignalFence); } FenceD3D11::~FenceD3D11() {} RefPtr FenceD3D11::CloneFromHandle() { RefPtr fence = FenceD3D11::CreateFromHandle(mHandle, mDevice); if (fence) { fence->Update(mFenceValue); } return fence; } bool FenceD3D11::IncrementAndSignal() { MOZ_ASSERT(mOwnsFence == OwnsFence::Yes); if (mOwnsFence != OwnsFence::Yes) { return false; } RefPtr context; mDevice->GetImmediateContext(getter_AddRefs(context)); RefPtr context4; auto hr = context->QueryInterface(__uuidof(ID3D11DeviceContext4), getter_AddRefs(context4)); if (FAILED(hr)) { gfxCriticalNoteOnce << "Failed to get D3D11DeviceContext4: " << gfx::hexa(hr); return false; } hr = context4->Signal(mSignalFence, mFenceValue + 1); if (FAILED(hr)) { gfxCriticalNoteOnce << "Signal fence failed: " << gfx::hexa(hr); return false; } mFenceValue++; return true; } void FenceD3D11::Update(uint64_t aFenceValue) { MOZ_ASSERT(mOwnsFence == OwnsFence::No); if (mOwnsFence != OwnsFence::No) { return; } if (mFenceValue > aFenceValue) { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return; } mFenceValue = aFenceValue; } bool FenceD3D11::Wait(ID3D11Device* aDevice) { MOZ_ASSERT(aDevice); if (!aDevice) { return false; } // Skip wait if passed device is the same as signaling device. if (mDevice == aDevice) { return true; } RefPtr fence; auto it = mWaitFenceMap.find(aDevice); if (it == mWaitFenceMap.end()) { RefPtr d3d11_5; auto hr = aDevice->QueryInterface(__uuidof(ID3D11Device5), getter_AddRefs(d3d11_5)); if (FAILED(hr)) { gfxCriticalNoteOnce << "Failed to get ID3D11Device5: " << gfx::hexa(hr); return false; } hr = d3d11_5->OpenSharedFence(mHandle->GetHandle(), __uuidof(ID3D11Fence), (void**)(ID3D11Fence**)getter_AddRefs(fence)); if (FAILED(hr)) { gfxCriticalNoteOnce << "Opening fence shared handle failed " << gfx::hexa(hr); return false; } mWaitFenceMap.emplace(aDevice, fence); } else { fence = it->second; } if (!fence) { MOZ_ASSERT_UNREACHABLE("unexpected to be called"); return false; } RefPtr context; aDevice->GetImmediateContext(getter_AddRefs(context)); RefPtr context4; auto hr = context->QueryInterface(__uuidof(ID3D11DeviceContext4), getter_AddRefs(context4)); if (FAILED(hr)) { gfxCriticalNoteOnce << "Failed to get D3D11DeviceContext4: " << gfx::hexa(hr); return false; } hr = context4->Wait(fence, mFenceValue); if (FAILED(hr)) { gfxCriticalNoteOnce << "Failed to wait fence: " << gfx::hexa(hr); return false; } return true; } } // namespace layers } // namespace mozilla