tor-browser

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

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