FenceD3D11.cpp (6816B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "FenceD3D11.h" 8 9 #include <d3d11.h> 10 #include <d3d11_3.h> 11 #include <d3d11_4.h> 12 #include <dxgi1_6.h> 13 14 #include "mozilla/gfx/Logging.h" 15 16 namespace mozilla { 17 namespace layers { 18 19 constinit RefPtr<ID3D11Device> mDevice; 20 21 /* static */ 22 RefPtr<FenceD3D11> FenceD3D11::Create(ID3D11Device* aDevice) { 23 MOZ_ASSERT(aDevice); 24 25 if (!aDevice) { 26 return nullptr; 27 } 28 29 RefPtr<ID3D11Device5> d3d11_5; 30 auto hr = 31 aDevice->QueryInterface(__uuidof(ID3D11Device5), getter_AddRefs(d3d11_5)); 32 if (FAILED(hr)) { 33 gfxCriticalNoteOnce << "Failed to get ID3D11Device5: " << gfx::hexa(hr); 34 return nullptr; 35 } 36 37 RefPtr<ID3D11Fence> fenceD3D11; 38 d3d11_5->CreateFence(0, D3D11_FENCE_FLAG_SHARED, 39 IID_PPV_ARGS((ID3D11Fence**)getter_AddRefs(fenceD3D11))); 40 if (FAILED(hr) || !fenceD3D11) { 41 gfxCriticalNoteOnce << "Fence creation failed: " << gfx::hexa(hr); 42 return nullptr; 43 } 44 45 HANDLE sharedHandle = nullptr; 46 hr = fenceD3D11->CreateSharedHandle(nullptr, GENERIC_ALL, nullptr, 47 &sharedHandle); 48 if (FAILED(hr)) { 49 gfxCriticalNoteOnce << "Fence shared handle creation failed " 50 << gfx::hexa(hr); 51 return nullptr; 52 } 53 54 RefPtr<gfx::FileHandleWrapper> handle = 55 new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); 56 RefPtr<FenceD3D11> fence = 57 new FenceD3D11(OwnsFence::Yes, aDevice, fenceD3D11, handle); 58 return fence; 59 } 60 61 /* static */ 62 RefPtr<FenceD3D11> FenceD3D11::CreateFromHandle( 63 RefPtr<gfx::FileHandleWrapper> aHandle, 64 const RefPtr<ID3D11Device> aDevice) { 65 MOZ_ASSERT(aHandle); 66 67 if (!aHandle) { 68 return nullptr; 69 } 70 // Opening shared handle is deferred. 71 return new FenceD3D11(OwnsFence::No, aDevice, /* aSignalFence */ nullptr, 72 aHandle); 73 } 74 75 /* static */ 76 bool FenceD3D11::IsSupported(ID3D11Device* aDevice) { 77 MOZ_ASSERT(aDevice); 78 79 if (!aDevice) { 80 return false; 81 } 82 RefPtr<ID3D11Device5> d3d11_5; 83 auto hr = aDevice->QueryInterface((ID3D11Device5**)getter_AddRefs(d3d11_5)); 84 if (FAILED(hr)) { 85 return false; 86 } 87 88 // Check for IDXGIAdapter4: 89 RefPtr<IDXGIDevice> dxgiDevice; 90 aDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(dxgiDevice)); 91 if (FAILED(hr)) { 92 return false; 93 } 94 95 RefPtr<IDXGIAdapter> dxgiAdapter; 96 hr = dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter)); 97 if (FAILED(hr)) { 98 return false; 99 } 100 101 RefPtr<IDXGIAdapter4> dxgiAdapter4; 102 dxgiAdapter->QueryInterface((IDXGIAdapter4**)getter_AddRefs(dxgiAdapter4)); 103 if (FAILED(hr)) { 104 gfxCriticalNoteOnce << "Failed to get IDXGIAdapter4: " << gfx::hexa(hr); 105 return false; 106 } 107 108 DXGI_ADAPTER_DESC3 adapterDesc; 109 hr = dxgiAdapter4->GetDesc3(&adapterDesc); 110 if (FAILED(hr)) { 111 return false; 112 } 113 114 // The adapter must support monitored fences. 115 return adapterDesc.Flags & DXGI_ADAPTER_FLAG3_SUPPORT_MONITORED_FENCES; 116 } 117 118 FenceD3D11::FenceD3D11(const OwnsFence aOwnsFence, 119 const RefPtr<ID3D11Device> aDevice, 120 const RefPtr<ID3D11Fence> aSignalFence, 121 const RefPtr<gfx::FileHandleWrapper>& aHandle) 122 : mOwnsFence(aOwnsFence), 123 mDevice(aDevice), 124 mSignalFence(aSignalFence), 125 mHandle(aHandle) { 126 MOZ_ASSERT(mHandle); 127 MOZ_ASSERT_IF(mOwnsFence == OwnsFence::Yes, mDevice); 128 MOZ_ASSERT_IF(mOwnsFence == OwnsFence::Yes, mSignalFence); 129 MOZ_ASSERT_IF(mOwnsFence == OwnsFence::No, !mSignalFence); 130 } 131 132 FenceD3D11::~FenceD3D11() {} 133 134 RefPtr<FenceD3D11> FenceD3D11::CloneFromHandle() { 135 RefPtr<FenceD3D11> fence = FenceD3D11::CreateFromHandle(mHandle, mDevice); 136 if (fence) { 137 fence->Update(mFenceValue); 138 } 139 return fence; 140 } 141 142 bool FenceD3D11::IncrementAndSignal() { 143 MOZ_ASSERT(mOwnsFence == OwnsFence::Yes); 144 145 if (mOwnsFence != OwnsFence::Yes) { 146 return false; 147 } 148 149 RefPtr<ID3D11DeviceContext> context; 150 mDevice->GetImmediateContext(getter_AddRefs(context)); 151 RefPtr<ID3D11DeviceContext4> context4; 152 auto hr = context->QueryInterface(__uuidof(ID3D11DeviceContext4), 153 getter_AddRefs(context4)); 154 if (FAILED(hr)) { 155 gfxCriticalNoteOnce << "Failed to get D3D11DeviceContext4: " 156 << gfx::hexa(hr); 157 return false; 158 } 159 160 hr = context4->Signal(mSignalFence, mFenceValue + 1); 161 if (FAILED(hr)) { 162 gfxCriticalNoteOnce << "Signal fence failed: " << gfx::hexa(hr); 163 return false; 164 } 165 166 mFenceValue++; 167 return true; 168 } 169 170 void FenceD3D11::Update(uint64_t aFenceValue) { 171 MOZ_ASSERT(mOwnsFence == OwnsFence::No); 172 173 if (mOwnsFence != OwnsFence::No) { 174 return; 175 } 176 177 if (mFenceValue > aFenceValue) { 178 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 179 return; 180 } 181 mFenceValue = aFenceValue; 182 } 183 184 bool FenceD3D11::Wait(ID3D11Device* aDevice) { 185 MOZ_ASSERT(aDevice); 186 187 if (!aDevice) { 188 return false; 189 } 190 191 // Skip wait if passed device is the same as signaling device. 192 if (mDevice == aDevice) { 193 return true; 194 } 195 196 RefPtr<ID3D11Fence> fence; 197 auto it = mWaitFenceMap.find(aDevice); 198 if (it == mWaitFenceMap.end()) { 199 RefPtr<ID3D11Device5> d3d11_5; 200 auto hr = aDevice->QueryInterface(__uuidof(ID3D11Device5), 201 getter_AddRefs(d3d11_5)); 202 if (FAILED(hr)) { 203 gfxCriticalNoteOnce << "Failed to get ID3D11Device5: " << gfx::hexa(hr); 204 return false; 205 } 206 hr = d3d11_5->OpenSharedFence(mHandle->GetHandle(), __uuidof(ID3D11Fence), 207 (void**)(ID3D11Fence**)getter_AddRefs(fence)); 208 if (FAILED(hr)) { 209 gfxCriticalNoteOnce << "Opening fence shared handle failed " 210 << gfx::hexa(hr); 211 return false; 212 } 213 mWaitFenceMap.emplace(aDevice, fence); 214 } else { 215 fence = it->second; 216 } 217 218 if (!fence) { 219 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 220 return false; 221 } 222 223 RefPtr<ID3D11DeviceContext> context; 224 aDevice->GetImmediateContext(getter_AddRefs(context)); 225 RefPtr<ID3D11DeviceContext4> context4; 226 auto hr = context->QueryInterface(__uuidof(ID3D11DeviceContext4), 227 getter_AddRefs(context4)); 228 if (FAILED(hr)) { 229 gfxCriticalNoteOnce << "Failed to get D3D11DeviceContext4: " 230 << gfx::hexa(hr); 231 return false; 232 } 233 hr = context4->Wait(fence, mFenceValue); 234 if (FAILED(hr)) { 235 gfxCriticalNoteOnce << "Failed to wait fence: " << gfx::hexa(hr); 236 return false; 237 } 238 239 return true; 240 } 241 242 } // namespace layers 243 } // namespace mozilla