tor-browser

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

CompositorD3D11.cpp (45303B)


      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 "CompositorD3D11.h"
      8 
      9 #include "TextureD3D11.h"
     10 
     11 #include "gfxWindowsPlatform.h"
     12 #include "nsIWidget.h"
     13 #include "mozilla/gfx/D3D11Checks.h"
     14 #include "mozilla/gfx/DeviceManagerDx.h"
     15 #include "mozilla/gfx/GPUParent.h"
     16 #include "mozilla/gfx/Swizzle.h"
     17 #include "mozilla/layers/Diagnostics.h"
     18 #include "mozilla/layers/Effects.h"
     19 #include "mozilla/layers/HelpersD3D11.h"
     20 #include "nsWindowsHelpers.h"
     21 #include "gfxConfig.h"
     22 #include "gfxCrashReporterUtils.h"
     23 #include "gfxUtils.h"
     24 #include "mozilla/gfx/StackArray.h"
     25 #include "mozilla/widget/WinCompositorWidget.h"
     26 
     27 #include "mozilla/ProfilerState.h"
     28 #include "mozilla/StaticPrefs_gfx.h"
     29 #include "mozilla/StaticPrefs_layers.h"
     30 
     31 #include "D3D11ShareHandleImage.h"
     32 #include "DeviceAttachmentsD3D11.h"
     33 #include "BlendShaderConstants.h"
     34 
     35 namespace mozilla {
     36 
     37 using namespace gfx;
     38 
     39 namespace layers {
     40 
     41 bool CanUsePartialPresents(ID3D11Device* aDevice);
     42 
     43 const FLOAT sBlendFactor[] = {0, 0, 0, 0};
     44 
     45 class AsyncReadbackBufferD3D11 final : public AsyncReadbackBuffer {
     46 public:
     47  AsyncReadbackBufferD3D11(ID3D11DeviceContext* aContext,
     48                           ID3D11Texture2D* aTexture, const IntSize& aSize);
     49 
     50  bool MapAndCopyInto(DataSourceSurface* aSurface,
     51                      const IntSize& aReadSize) const override;
     52 
     53  ID3D11Texture2D* GetTexture() { return mTexture; }
     54 
     55 private:
     56  RefPtr<ID3D11DeviceContext> mContext;
     57  RefPtr<ID3D11Texture2D> mTexture;
     58 };
     59 
     60 AsyncReadbackBufferD3D11::AsyncReadbackBufferD3D11(
     61    ID3D11DeviceContext* aContext, ID3D11Texture2D* aTexture,
     62    const IntSize& aSize)
     63    : AsyncReadbackBuffer(aSize), mContext(aContext), mTexture(aTexture) {}
     64 
     65 bool AsyncReadbackBufferD3D11::MapAndCopyInto(DataSourceSurface* aSurface,
     66                                              const IntSize& aReadSize) const {
     67  D3D11_MAPPED_SUBRESOURCE map;
     68  HRESULT hr = mContext->Map(mTexture, 0, D3D11_MAP_READ, 0, &map);
     69 
     70  if (FAILED(hr)) {
     71    return false;
     72  }
     73 
     74  RefPtr<DataSourceSurface> sourceSurface =
     75      Factory::CreateWrappingDataSourceSurface(static_cast<uint8_t*>(map.pData),
     76                                               map.RowPitch, mSize,
     77                                               SurfaceFormat::B8G8R8A8);
     78 
     79  bool result;
     80  {
     81    DataSourceSurface::ScopedMap sourceMap(sourceSurface,
     82                                           DataSourceSurface::READ);
     83    DataSourceSurface::ScopedMap destMap(aSurface, DataSourceSurface::WRITE);
     84 
     85    result = SwizzleData(sourceMap.GetData(), sourceMap.GetStride(),
     86                         SurfaceFormat::B8G8R8A8, destMap.GetData(),
     87                         destMap.GetStride(), aSurface->GetFormat(), aReadSize);
     88  }
     89 
     90  mContext->Unmap(mTexture, 0);
     91 
     92  return result;
     93 }
     94 
     95 CompositorD3D11::CompositorD3D11(widget::CompositorWidget* aWidget)
     96    : Compositor(aWidget),
     97      mWindowRTCopy(nullptr),
     98      mAttachments(nullptr),
     99      mHwnd(nullptr),
    100      mDisableSequenceForNextFrame(false),
    101      mAllowPartialPresents(false),
    102      mIsDoubleBuffered(false),
    103      mVerifyBuffersFailed(false),
    104      mUseMutexOnPresent(false) {
    105  mUseMutexOnPresent = StaticPrefs::gfx_use_mutex_on_present_AtStartup();
    106 }
    107 
    108 CompositorD3D11::~CompositorD3D11() {}
    109 
    110 template <typename VertexType>
    111 void CompositorD3D11::SetVertexBuffer(ID3D11Buffer* aBuffer) {
    112  UINT size = sizeof(VertexType);
    113  UINT offset = 0;
    114  mContext->IASetVertexBuffers(0, 1, &aBuffer, &size, &offset);
    115 }
    116 
    117 bool CompositorD3D11::Initialize(nsCString* const out_failureReason) {
    118  ScopedGfxFeatureReporter reporter("D3D11 Layers");
    119 
    120  HRESULT hr;
    121 
    122  DeviceManagerDx::Get()->GetCompositorDevices(&mDevice, &mAttachments);
    123  if (!mDevice) {
    124    gfxCriticalNote << "[D3D11] failed to get compositor device.";
    125    *out_failureReason = "FEATURE_FAILURE_D3D11_NO_DEVICE";
    126    return false;
    127  }
    128  if (!mAttachments || !mAttachments->IsValid()) {
    129    gfxCriticalNote << "[D3D11] failed to get compositor device attachments";
    130    *out_failureReason = mAttachments ? mAttachments->GetFailureId()
    131                                      : "FEATURE_FAILURE_NO_ATTACHMENTS"_ns;
    132    return false;
    133  }
    134 
    135  mDevice->GetImmediateContext(getter_AddRefs(mContext));
    136  if (!mContext) {
    137    gfxCriticalNote << "[D3D11] failed to get immediate context";
    138    *out_failureReason = "FEATURE_FAILURE_D3D11_CONTEXT";
    139    return false;
    140  }
    141 
    142  mFeatureLevel = mDevice->GetFeatureLevel();
    143 
    144  mHwnd = mWidget->AsWindows()->GetHwnd();
    145 
    146  memset(&mVSConstants, 0, sizeof(VertexShaderConstants));
    147 
    148  RefPtr<IDXGIDevice> dxgiDevice;
    149  RefPtr<IDXGIAdapter> dxgiAdapter;
    150 
    151  mDevice->QueryInterface(dxgiDevice.StartAssignment());
    152  dxgiDevice->GetAdapter(getter_AddRefs(dxgiAdapter));
    153 
    154  {
    155    RefPtr<IDXGIFactory> dxgiFactory;
    156    dxgiAdapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment()));
    157 
    158    RefPtr<IDXGIFactory2> dxgiFactory2;
    159    hr = dxgiFactory->QueryInterface(
    160        (IDXGIFactory2**)getter_AddRefs(dxgiFactory2));
    161 
    162    if (gfxVars::UseDoubleBufferingWithCompositor() && SUCCEEDED(hr) &&
    163        dxgiFactory2) {
    164      // DXGI_SCALING_NONE is not available on Windows 7 with Platform Update.
    165      // This looks awful for things like the awesome bar and browser window
    166      // resizing so we don't use a flip buffer chain here. When using
    167      // EFFECT_SEQUENTIAL it looks like windows doesn't stretch the surface
    168      // when resizing.
    169      RefPtr<IDXGISwapChain1> swapChain;
    170 
    171      DXGI_SWAP_CHAIN_DESC1 swapDesc;
    172      ::ZeroMemory(&swapDesc, sizeof(swapDesc));
    173      swapDesc.Width = 0;
    174      swapDesc.Height = 0;
    175      swapDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    176      swapDesc.SampleDesc.Count = 1;
    177      swapDesc.SampleDesc.Quality = 0;
    178      swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    179      swapDesc.BufferCount = 2;
    180      swapDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
    181      swapDesc.Scaling = DXGI_SCALING_NONE;
    182      mIsDoubleBuffered = true;
    183      swapDesc.Flags = 0;
    184 
    185      /**
    186       * Create a swap chain, this swap chain will contain the backbuffer for
    187       * the window we draw to. The front buffer is the full screen front
    188       * buffer.
    189       */
    190      hr = dxgiFactory2->CreateSwapChainForHwnd(mDevice, mHwnd, &swapDesc,
    191                                                nullptr, nullptr,
    192                                                getter_AddRefs(swapChain));
    193      if (SUCCEEDED(hr)) {
    194        DXGI_RGBA color = {1.0f, 1.0f, 1.0f, 1.0f};
    195        swapChain->SetBackgroundColor(&color);
    196 
    197        mSwapChain = swapChain;
    198      } else if (mWidget->AsWindows()->GetCompositorHwnd()) {
    199        // Destroy compositor window.
    200        mWidget->AsWindows()->DestroyCompositorWindow();
    201        mHwnd = mWidget->AsWindows()->GetHwnd();
    202      }
    203    }
    204 
    205    // In some configurations double buffering may have failed with an
    206    // ACCESS_DENIED error.
    207    if (!mSwapChain) {
    208      if (mWidget->AsWindows()->GetCompositorHwnd()) {
    209        // Destroy compositor window.
    210        mWidget->AsWindows()->DestroyCompositorWindow();
    211        mHwnd = mWidget->AsWindows()->GetHwnd();
    212      }
    213 
    214      DXGI_SWAP_CHAIN_DESC swapDesc;
    215      ::ZeroMemory(&swapDesc, sizeof(swapDesc));
    216      swapDesc.BufferDesc.Width = 0;
    217      swapDesc.BufferDesc.Height = 0;
    218      swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
    219      swapDesc.BufferDesc.RefreshRate.Numerator = 60;
    220      swapDesc.BufferDesc.RefreshRate.Denominator = 1;
    221      swapDesc.SampleDesc.Count = 1;
    222      swapDesc.SampleDesc.Quality = 0;
    223      swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    224      swapDesc.BufferCount = 1;
    225      swapDesc.OutputWindow = mHwnd;
    226      swapDesc.Windowed = TRUE;
    227      swapDesc.Flags = 0;
    228      swapDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
    229 
    230      /**
    231       * Create a swap chain, this swap chain will contain the backbuffer for
    232       * the window we draw to. The front buffer is the full screen front
    233       * buffer.
    234       */
    235      hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc,
    236                                        getter_AddRefs(mSwapChain));
    237      if (Failed(hr, "create swap chain")) {
    238        *out_failureReason = "FEATURE_FAILURE_D3D11_SWAP_CHAIN";
    239        return false;
    240      }
    241    }
    242 
    243    // We need this because we don't want DXGI to respond to Alt+Enter.
    244    dxgiFactory->MakeWindowAssociation(mHwnd, DXGI_MWA_NO_WINDOW_CHANGES);
    245  }
    246 
    247  if (!mWidget->InitCompositor(this)) {
    248    *out_failureReason = "FEATURE_FAILURE_D3D11_INIT_COMPOSITOR";
    249    return false;
    250  }
    251 
    252  mAllowPartialPresents = CanUsePartialPresents(mDevice);
    253 
    254  reporter.SetSuccessful();
    255  return true;
    256 }
    257 
    258 bool CanUsePartialPresents(ID3D11Device* aDevice) {
    259  if (StaticPrefs::gfx_partialpresent_force() > 0) {
    260    return true;
    261  }
    262  if (StaticPrefs::gfx_partialpresent_force() < 0) {
    263    return false;
    264  }
    265  if (DeviceManagerDx::Get()->IsWARP()) {
    266    return true;
    267  }
    268 
    269  DXGI_ADAPTER_DESC desc;
    270  if (!D3D11Checks::GetDxgiDesc(aDevice, &desc)) {
    271    return false;
    272  }
    273 
    274  // We have to disable partial presents on NVIDIA (bug 1189940).
    275  if (desc.VendorId == 0x10de) {
    276    return false;
    277  }
    278 
    279  return true;
    280 }
    281 
    282 already_AddRefed<DataTextureSource> CompositorD3D11::CreateDataTextureSource(
    283    TextureFlags aFlags) {
    284  RefPtr<DataTextureSource> result =
    285      new DataTextureSourceD3D11(gfx::SurfaceFormat::UNKNOWN, this, aFlags);
    286  return result.forget();
    287 }
    288 
    289 int32_t CompositorD3D11::GetMaxTextureSize() const {
    290  return GetMaxTextureSizeForFeatureLevel(mFeatureLevel);
    291 }
    292 
    293 already_AddRefed<CompositingRenderTarget> CompositorD3D11::CreateRenderTarget(
    294    const gfx::IntRect& aRect, SurfaceInitMode aInit) {
    295  MOZ_ASSERT(!aRect.IsZeroArea());
    296 
    297  if (aRect.IsZeroArea()) {
    298    return nullptr;
    299  }
    300 
    301  CD3D11_TEXTURE2D_DESC desc(
    302      DXGI_FORMAT_B8G8R8A8_UNORM, aRect.width, aRect.height, 1, 1,
    303      D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
    304 
    305  RefPtr<ID3D11Texture2D> texture;
    306  HRESULT hr =
    307      mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
    308  if (FAILED(hr) || !texture) {
    309    gfxCriticalNote << "Failed in CreateRenderTarget " << hexa(hr);
    310    return nullptr;
    311  }
    312 
    313  RefPtr<CompositingRenderTargetD3D11> rt =
    314      new CompositingRenderTargetD3D11(texture, aRect.TopLeft());
    315  rt->SetSize(IntSize(aRect.Width(), aRect.Height()));
    316 
    317  if (aInit == INIT_MODE_CLEAR) {
    318    FLOAT clear[] = {0, 0, 0, 0};
    319    mContext->ClearRenderTargetView(rt->mRTView, clear);
    320  }
    321 
    322  return rt.forget();
    323 }
    324 
    325 RefPtr<ID3D11Texture2D> CompositorD3D11::CreateTexture(
    326    const gfx::IntRect& aRect, const CompositingRenderTarget* aSource,
    327    const gfx::IntPoint& aSourcePoint) {
    328  MOZ_ASSERT(!aRect.IsZeroArea());
    329 
    330  if (aRect.IsZeroArea()) {
    331    return nullptr;
    332  }
    333 
    334  CD3D11_TEXTURE2D_DESC desc(
    335      DXGI_FORMAT_B8G8R8A8_UNORM, aRect.Width(), aRect.Height(), 1, 1,
    336      D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
    337 
    338  RefPtr<ID3D11Texture2D> texture;
    339  HRESULT hr =
    340      mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
    341 
    342  if (FAILED(hr) || !texture) {
    343    gfxCriticalNote << "Failed in CreateRenderTargetFromSource " << hexa(hr);
    344    HandleError(hr);
    345    return nullptr;
    346  }
    347 
    348  if (aSource) {
    349    const CompositingRenderTargetD3D11* sourceD3D11 =
    350        static_cast<const CompositingRenderTargetD3D11*>(aSource);
    351 
    352    const IntSize& srcSize = sourceD3D11->GetSize();
    353    MOZ_ASSERT(srcSize.width >= 0 && srcSize.height >= 0,
    354               "render targets should have nonnegative sizes");
    355 
    356    IntRect srcRect(IntPoint(), srcSize);
    357    IntRect copyRect(aSourcePoint, aRect.Size());
    358    if (!srcRect.Contains(copyRect)) {
    359      NS_WARNING("Could not copy the whole copy rect from the render target");
    360    }
    361 
    362    copyRect = copyRect.Intersect(srcRect);
    363 
    364    if (!copyRect.IsEmpty()) {
    365      D3D11_BOX copyBox;
    366      copyBox.front = 0;
    367      copyBox.back = 1;
    368      copyBox.left = copyRect.X();
    369      copyBox.top = copyRect.Y();
    370      copyBox.right = copyRect.XMost();
    371      copyBox.bottom = copyRect.YMost();
    372 
    373      mContext->CopySubresourceRegion(
    374          texture, 0, 0, 0, 0, sourceD3D11->GetD3D11Texture(), 0, &copyBox);
    375    }
    376  }
    377 
    378  return texture;
    379 }
    380 
    381 bool CompositorD3D11::ShouldAllowFrameRecording() const {
    382  return mAllowFrameRecording ||
    383         profiler_feature_active(ProfilerFeature::Screenshots);
    384 }
    385 
    386 already_AddRefed<CompositingRenderTarget>
    387 CompositorD3D11::GetWindowRenderTarget() const {
    388  if (!ShouldAllowFrameRecording()) {
    389    return nullptr;
    390  }
    391 
    392  if (!mDefaultRT) {
    393    return nullptr;
    394  }
    395 
    396  const IntSize size = mDefaultRT->GetSize();
    397 
    398  RefPtr<ID3D11Texture2D> rtTexture;
    399 
    400  if (!mWindowRTCopy || mWindowRTCopy->GetSize() != size) {
    401    /*
    402     * The compositor screenshots infrastructure is going to scale down the
    403     * render target returned by this method. However, mDefaultRT does not
    404     * contain a texture created wth the D3D11_BIND_SHADER_RESOURCE flag, so if
    405     * we were to simply return mDefaultRT then scaling would fail.
    406     */
    407    CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, size.width,
    408                               size.height, 1, 1, D3D11_BIND_SHADER_RESOURCE);
    409 
    410    HRESULT hr =
    411        mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(rtTexture));
    412    if (FAILED(hr)) {
    413      return nullptr;
    414    }
    415 
    416    mWindowRTCopy = MakeRefPtr<CompositingRenderTargetD3D11>(
    417        rtTexture, IntPoint(0, 0), DXGI_FORMAT_B8G8R8A8_UNORM);
    418    mWindowRTCopy->SetSize(size);
    419  } else {
    420    rtTexture = mWindowRTCopy->GetD3D11Texture();
    421  }
    422 
    423  const RefPtr<ID3D11Texture2D> sourceTexture = mDefaultRT->GetD3D11Texture();
    424  mContext->CopyResource(rtTexture, sourceTexture);
    425 
    426  return RefPtr<CompositingRenderTarget>(
    427             static_cast<CompositingRenderTarget*>(mWindowRTCopy))
    428      .forget();
    429 }
    430 
    431 bool CompositorD3D11::ReadbackRenderTarget(CompositingRenderTarget* aSource,
    432                                           AsyncReadbackBuffer* aDest) {
    433  RefPtr<CompositingRenderTargetD3D11> srcTexture =
    434      static_cast<CompositingRenderTargetD3D11*>(aSource);
    435  RefPtr<AsyncReadbackBufferD3D11> destBuffer =
    436      static_cast<AsyncReadbackBufferD3D11*>(aDest);
    437 
    438  mContext->CopyResource(destBuffer->GetTexture(),
    439                         srcTexture->GetD3D11Texture());
    440 
    441  return true;
    442 }
    443 
    444 already_AddRefed<AsyncReadbackBuffer>
    445 CompositorD3D11::CreateAsyncReadbackBuffer(const gfx::IntSize& aSize) {
    446  RefPtr<ID3D11Texture2D> texture;
    447 
    448  CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width,
    449                             aSize.height, 1, 1, 0, D3D11_USAGE_STAGING,
    450                             D3D11_CPU_ACCESS_READ);
    451 
    452  HRESULT hr =
    453      mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
    454 
    455  if (FAILED(hr)) {
    456    HandleError(hr);
    457    return nullptr;
    458  }
    459 
    460  return MakeAndAddRef<AsyncReadbackBufferD3D11>(mContext, texture, aSize);
    461 }
    462 
    463 bool CompositorD3D11::BlitRenderTarget(CompositingRenderTarget* aSource,
    464                                       const gfx::IntSize& aSourceSize,
    465                                       const gfx::IntSize& aDestSize) {
    466  RefPtr<CompositingRenderTargetD3D11> source =
    467      static_cast<CompositingRenderTargetD3D11*>(aSource);
    468 
    469  RefPtr<TexturedEffect> texturedEffect = CreateTexturedEffect(
    470      SurfaceFormat::B8G8R8A8, source, SamplingFilter::LINEAR, true);
    471  texturedEffect->mTextureCoords =
    472      Rect(0, 0, Float(aSourceSize.width) / Float(source->GetSize().width),
    473           Float(aSourceSize.height) / Float(source->GetSize().height));
    474 
    475  EffectChain effect;
    476  effect.mPrimaryEffect = texturedEffect;
    477 
    478  const Float scaleX = Float(aDestSize.width) / Float(aSourceSize.width);
    479  const Float scaleY = Float(aDestSize.height) / (aSourceSize.height);
    480  const Matrix4x4 transform = Matrix4x4::Scaling(scaleX, scaleY, 1.0f);
    481 
    482  const Rect sourceRect(0, 0, aSourceSize.width, aSourceSize.height);
    483 
    484  DrawQuad(sourceRect, IntRect(0, 0, aDestSize.width, aDestSize.height), effect,
    485           1.0f, transform, sourceRect);
    486 
    487  return true;
    488 }
    489 
    490 void CompositorD3D11::SetRenderTarget(CompositingRenderTarget* aRenderTarget) {
    491  MOZ_ASSERT(aRenderTarget);
    492  CompositingRenderTargetD3D11* newRT =
    493      static_cast<CompositingRenderTargetD3D11*>(aRenderTarget);
    494  if (mCurrentRT != newRT) {
    495    mCurrentRT = newRT;
    496    mCurrentRT->BindRenderTarget(mContext);
    497  }
    498 
    499  if (newRT->HasComplexProjection()) {
    500    gfx::Matrix4x4 projection;
    501    bool depthEnable;
    502    float zNear, zFar;
    503    newRT->GetProjection(projection, depthEnable, zNear, zFar);
    504    PrepareViewport(newRT->GetSize(), projection, zNear, zFar);
    505  } else {
    506    PrepareViewport(newRT->GetSize());
    507  }
    508 }
    509 
    510 ID3D11PixelShader* CompositorD3D11::GetPSForEffect(Effect* aEffect,
    511                                                   const ClipType aClipType) {
    512  switch (aEffect->mType) {
    513    case EffectTypes::RGB: {
    514      SurfaceFormat format =
    515          static_cast<TexturedEffect*>(aEffect)->mTexture->GetFormat();
    516      return (format == SurfaceFormat::B8G8R8A8 ||
    517              format == SurfaceFormat::R8G8B8A8)
    518                 ? mAttachments->mRGBAShader[aClipType]
    519                 : mAttachments->mRGBShader[aClipType];
    520    }
    521    case EffectTypes::NV12:
    522      return mAttachments->mNV12Shader[aClipType];
    523    case EffectTypes::YCBCR:
    524      return mAttachments->mYCbCrShader[aClipType];
    525    default:
    526      NS_WARNING("No shader to load");
    527      return nullptr;
    528  }
    529 }
    530 
    531 void CompositorD3D11::ClearRect(const gfx::Rect& aRect) {
    532  if (aRect.IsEmpty()) {
    533    return;
    534  }
    535 
    536  mContext->OMSetBlendState(mAttachments->mDisabledBlendState, sBlendFactor,
    537                            0xFFFFFFFF);
    538 
    539  Matrix4x4 identity;
    540  memcpy(&mVSConstants.layerTransform, &identity._11, 64);
    541 
    542  mVSConstants.layerQuad = aRect;
    543  mVSConstants.renderTargetOffset[0] = 0;
    544  mVSConstants.renderTargetOffset[1] = 0;
    545  mPSConstants.layerOpacity[0] = 1.0f;
    546 
    547  D3D11_RECT scissor;
    548  scissor.left = aRect.X();
    549  scissor.right = aRect.XMost();
    550  scissor.top = aRect.Y();
    551  scissor.bottom = aRect.YMost();
    552  mContext->RSSetScissorRects(1, &scissor);
    553  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
    554  mContext->VSSetShader(mAttachments->mVSQuadShader[ClipType::ClipNone],
    555                        nullptr, 0);
    556 
    557  mContext->PSSetShader(mAttachments->mSolidColorShader, nullptr, 0);
    558  mPSConstants.layerColor[0] = 0;
    559  mPSConstants.layerColor[1] = 0;
    560  mPSConstants.layerColor[2] = 0;
    561  mPSConstants.layerColor[3] = 0;
    562 
    563  if (!UpdateConstantBuffers()) {
    564    NS_WARNING("Failed to update shader constant buffers");
    565    return;
    566  }
    567 
    568  mContext->Draw(4, 0);
    569 
    570  // Restore the default blend state.
    571  mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor,
    572                            0xFFFFFFFF);
    573 }
    574 
    575 void CompositorD3D11::PrepareStaticVertexBuffer() {
    576  mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
    577  mContext->IASetInputLayout(mAttachments->mInputLayout);
    578  SetVertexBuffer<Vertex>(mAttachments->mVertexBuffer);
    579 }
    580 
    581 void CompositorD3D11::Draw(const gfx::Rect& aRect,
    582                           const gfx::Rect* aTexCoords) {
    583  Rect layerRects[4] = {aRect};
    584  Rect textureRects[4] = {};
    585  size_t rects = 1;
    586 
    587  if (aTexCoords) {
    588    rects = DecomposeIntoNoRepeatRects(aRect, *aTexCoords, &layerRects,
    589                                       &textureRects);
    590  }
    591 
    592  for (size_t i = 0; i < rects; i++) {
    593    mVSConstants.layerQuad = layerRects[i];
    594    mVSConstants.textureCoords = textureRects[i];
    595 
    596    if (!UpdateConstantBuffers()) {
    597      NS_WARNING("Failed to update shader constant buffers");
    598      break;
    599    }
    600 
    601    mContext->Draw(4, 0);
    602  }
    603 }
    604 
    605 void CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
    606                               const gfx::IntRect& aClipRect,
    607                               const EffectChain& aEffectChain,
    608                               gfx::Float aOpacity,
    609                               const gfx::Matrix4x4& aTransform,
    610                               const gfx::Rect& aVisibleRect) {
    611  if (mCurrentClip.IsEmpty()) {
    612    return;
    613  }
    614 
    615  MOZ_ASSERT(mCurrentRT, "No render target");
    616 
    617  memcpy(&mVSConstants.layerTransform, &aTransform._11, 64);
    618  IntPoint origin = mCurrentRT->GetOrigin();
    619  mVSConstants.renderTargetOffset[0] = origin.x;
    620  mVSConstants.renderTargetOffset[1] = origin.y;
    621 
    622  mPSConstants.layerOpacity[0] = aOpacity;
    623 
    624  D3D11_RECT scissor;
    625 
    626  IntRect clipRect(aClipRect.X(), aClipRect.Y(), aClipRect.Width(),
    627                   aClipRect.Height());
    628  if (mCurrentRT == mDefaultRT) {
    629    clipRect = clipRect.Intersect(mCurrentClip);
    630  }
    631 
    632  if (clipRect.IsEmpty()) {
    633    return;
    634  }
    635 
    636  scissor.left = clipRect.X();
    637  scissor.right = clipRect.XMost();
    638  scissor.top = clipRect.Y();
    639  scissor.bottom = clipRect.YMost();
    640 
    641  bool restoreBlendMode = false;
    642 
    643  mContext->RSSetScissorRects(1, &scissor);
    644 
    645  auto clipType = ClipType::ClipNone;
    646 
    647  if (aEffectChain.mRoundedClipEffect) {
    648    clipType = ClipType::RoundedRect;
    649 
    650    mVSConstants.roundedClipRect[0] = aEffectChain.mRoundedClipEffect->mRect.x;
    651    mVSConstants.roundedClipRect[1] = aEffectChain.mRoundedClipEffect->mRect.y;
    652    mVSConstants.roundedClipRect[2] =
    653        aEffectChain.mRoundedClipEffect->mRect.width;
    654    mVSConstants.roundedClipRect[3] =
    655        aEffectChain.mRoundedClipEffect->mRect.height;
    656 
    657    mPSConstants.roundedClipRadii[0] =
    658        aEffectChain.mRoundedClipEffect->mRadii[eCornerTopLeft].width;
    659    mPSConstants.roundedClipRadii[1] =
    660        aEffectChain.mRoundedClipEffect->mRadii[eCornerBottomLeft].width;
    661    mPSConstants.roundedClipRadii[2] =
    662        aEffectChain.mRoundedClipEffect->mRadii[eCornerTopRight].width;
    663    mPSConstants.roundedClipRadii[3] =
    664        aEffectChain.mRoundedClipEffect->mRadii[eCornerBottomRight].width;
    665  }
    666 
    667  RefPtr<ID3D11VertexShader> vertexShader =
    668      mAttachments->mVSQuadShader[clipType];
    669 
    670  RefPtr<ID3D11PixelShader> pixelShader =
    671      GetPSForEffect(aEffectChain.mPrimaryEffect, clipType);
    672 
    673  mContext->VSSetShader(vertexShader, nullptr, 0);
    674  mContext->PSSetShader(pixelShader, nullptr, 0);
    675 
    676  const Rect* pTexCoordRect = nullptr;
    677 
    678  switch (aEffectChain.mPrimaryEffect->mType) {
    679    case EffectTypes::RGB: {
    680      TexturedEffect* texturedEffect =
    681          static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
    682 
    683      pTexCoordRect = &texturedEffect->mTextureCoords;
    684 
    685      TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11();
    686 
    687      if (!source) {
    688        NS_WARNING("Missing texture source!");
    689        return;
    690      }
    691 
    692      ID3D11ShaderResourceView* srView = source->GetShaderResourceView();
    693      mContext->PSSetShaderResources(TexSlot::RGB, 1, &srView);
    694 
    695      if (texturedEffect->mPremultipliedCopy) {
    696        MOZ_RELEASE_ASSERT(texturedEffect->mPremultiplied);
    697        mContext->OMSetBlendState(mAttachments->mPremulCopyState, sBlendFactor,
    698                                  0xFFFFFFFF);
    699        restoreBlendMode = true;
    700      } else if (!texturedEffect->mPremultiplied) {
    701        mContext->OMSetBlendState(mAttachments->mNonPremulBlendState,
    702                                  sBlendFactor, 0xFFFFFFFF);
    703        restoreBlendMode = true;
    704      }
    705 
    706      SetSamplerForSamplingFilter(texturedEffect->mSamplingFilter);
    707    } break;
    708    case EffectTypes::NV12: {
    709      EffectNV12* effectNV12 =
    710          static_cast<EffectNV12*>(aEffectChain.mPrimaryEffect.get());
    711 
    712      pTexCoordRect = &effectNV12->mTextureCoords;
    713 
    714      TextureSourceD3D11* source = effectNV12->mTexture->AsSourceD3D11();
    715      if (!source) {
    716        NS_WARNING("Missing texture source!");
    717        return;
    718      }
    719 
    720      RefPtr<ID3D11Texture2D> texture = source->GetD3D11Texture();
    721      if (!texture) {
    722        NS_WARNING("No texture found in texture source!");
    723      }
    724 
    725      D3D11_TEXTURE2D_DESC sourceDesc;
    726      texture->GetDesc(&sourceDesc);
    727      MOZ_DIAGNOSTIC_ASSERT(sourceDesc.Format == DXGI_FORMAT_NV12 ||
    728                            sourceDesc.Format == DXGI_FORMAT_P010 ||
    729                            sourceDesc.Format == DXGI_FORMAT_P016);
    730 
    731      // Might want to cache these for efficiency.
    732      RefPtr<ID3D11ShaderResourceView> srViewY;
    733      RefPtr<ID3D11ShaderResourceView> srViewCbCr;
    734      D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc =
    735          CD3D11_SHADER_RESOURCE_VIEW_DESC(D3D11_SRV_DIMENSION_TEXTURE2D,
    736                                           sourceDesc.Format == DXGI_FORMAT_NV12
    737                                               ? DXGI_FORMAT_R8_UNORM
    738                                               : DXGI_FORMAT_R16_UNORM);
    739      mDevice->CreateShaderResourceView(texture, &srvDesc,
    740                                        getter_AddRefs(srViewY));
    741      srvDesc.Format = sourceDesc.Format == DXGI_FORMAT_NV12
    742                           ? DXGI_FORMAT_R8G8_UNORM
    743                           : DXGI_FORMAT_R16G16_UNORM;
    744      mDevice->CreateShaderResourceView(texture, &srvDesc,
    745                                        getter_AddRefs(srViewCbCr));
    746 
    747      ID3D11ShaderResourceView* views[] = {srViewY, srViewCbCr};
    748      mContext->PSSetShaderResources(TexSlot::Y, 2, views);
    749 
    750      const float* yuvToRgb =
    751          gfxUtils::YuvToRgbMatrix4x3RowMajor(effectNV12->mYUVColorSpace);
    752      memcpy(&mPSConstants.yuvColorMatrix, yuvToRgb,
    753             sizeof(mPSConstants.yuvColorMatrix));
    754      mPSConstants.vCoefficient[0] =
    755          RescalingFactorForColorDepth(effectNV12->mColorDepth);
    756 
    757      SetSamplerForSamplingFilter(effectNV12->mSamplingFilter);
    758    } break;
    759    case EffectTypes::YCBCR: {
    760      EffectYCbCr* ycbcrEffect =
    761          static_cast<EffectYCbCr*>(aEffectChain.mPrimaryEffect.get());
    762 
    763      SetSamplerForSamplingFilter(SamplingFilter::LINEAR);
    764 
    765      pTexCoordRect = &ycbcrEffect->mTextureCoords;
    766 
    767      const int Y = 0, Cb = 1, Cr = 2;
    768      TextureSource* source = ycbcrEffect->mTexture;
    769 
    770      if (!source) {
    771        NS_WARNING("No texture to composite");
    772        return;
    773      }
    774 
    775      if (!source->GetSubSource(Y) || !source->GetSubSource(Cb) ||
    776          !source->GetSubSource(Cr)) {
    777        // This can happen if we failed to upload the textures, most likely
    778        // because of unsupported dimensions (we don't tile YCbCr textures).
    779        return;
    780      }
    781 
    782      const float* yuvToRgb =
    783          gfxUtils::YuvToRgbMatrix4x3RowMajor(ycbcrEffect->mYUVColorSpace);
    784      memcpy(&mPSConstants.yuvColorMatrix, yuvToRgb,
    785             sizeof(mPSConstants.yuvColorMatrix));
    786 
    787      // Adjust range according to the bit depth.
    788      mPSConstants.vCoefficient[0] =
    789          RescalingFactorForColorDepth(ycbcrEffect->mColorDepth);
    790 
    791      TextureSourceD3D11* sourceY = source->GetSubSource(Y)->AsSourceD3D11();
    792      TextureSourceD3D11* sourceCb = source->GetSubSource(Cb)->AsSourceD3D11();
    793      TextureSourceD3D11* sourceCr = source->GetSubSource(Cr)->AsSourceD3D11();
    794 
    795      ID3D11ShaderResourceView* srViews[3] = {
    796          sourceY->GetShaderResourceView(), sourceCb->GetShaderResourceView(),
    797          sourceCr->GetShaderResourceView()};
    798      mContext->PSSetShaderResources(TexSlot::Y, 3, srViews);
    799    } break;
    800    default:
    801      NS_WARNING("Unknown shader type");
    802      return;
    803  }
    804 
    805  Draw(aRect, pTexCoordRect);
    806 
    807  if (restoreBlendMode) {
    808    mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor,
    809                              0xFFFFFFFF);
    810  }
    811 }
    812 
    813 Maybe<IntRect> CompositorD3D11::BeginFrameForWindow(
    814    const nsIntRegion& aInvalidRegion, const Maybe<IntRect>& aClipRect,
    815    const IntRect& aRenderBounds, const nsIntRegion& aOpaqueRegion) {
    816  MOZ_RELEASE_ASSERT(!mTarget, "mTarget not cleared properly");
    817  return BeginFrame(aInvalidRegion, aClipRect, aRenderBounds, aOpaqueRegion);
    818 }
    819 
    820 Maybe<IntRect> CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
    821                                           const Maybe<IntRect>& aClipRect,
    822                                           const IntRect& aRenderBounds,
    823                                           const nsIntRegion& aOpaqueRegion) {
    824  // Don't composite if we are minimised. Other than for the sake of efficency,
    825  // this is important because resizing our buffers when mimised will fail and
    826  // cause a crash when we're restored.
    827  NS_ASSERTION(mHwnd, "Couldn't find an HWND when initialising?");
    828  if (mWidget->IsHidden()) {
    829    // We are not going to render, and not going to call EndFrame so we have to
    830    // read-unlock our textures to prevent them from accumulating.
    831    return Nothing();
    832  }
    833 
    834  if (mDevice->GetDeviceRemovedReason() != S_OK) {
    835    if (!mAttachments->IsDeviceReset()) {
    836      gfxCriticalNote << "GFX: D3D11 skip BeginFrame with device-removed.";
    837      mAttachments->SetDeviceReset();
    838    }
    839    return Nothing();
    840  }
    841 
    842  LayoutDeviceIntSize oldSize = mSize;
    843 
    844  EnsureSize();
    845 
    846  IntRect rect = IntRect(IntPoint(0, 0), mSize.ToUnknownSize());
    847  // Sometimes the invalid region is larger than we want to draw.
    848  nsIntRegion invalidRegionSafe;
    849 
    850  if (mSize != oldSize) {
    851    invalidRegionSafe = rect;
    852  } else {
    853    invalidRegionSafe.And(aInvalidRegion, rect);
    854  }
    855 
    856  IntRect invalidRect = invalidRegionSafe.GetBounds();
    857 
    858  IntRect clipRect = invalidRect;
    859  if (aClipRect) {
    860    clipRect.IntersectRect(clipRect, *aClipRect);
    861  }
    862 
    863  if (clipRect.IsEmpty()) {
    864    CancelFrame();
    865    return Nothing();
    866  }
    867 
    868  PrepareStaticVertexBuffer();
    869 
    870  mBackBufferInvalid.OrWith(invalidRegionSafe);
    871  if (mIsDoubleBuffered) {
    872    mFrontBufferInvalid.OrWith(invalidRegionSafe);
    873  }
    874 
    875  // We have to call UpdateRenderTarget after we've determined the invalid regi
    876  // Failed to create a render target or the view.
    877  if (!UpdateRenderTarget() || !mDefaultRT || !mDefaultRT->mRTView ||
    878      mSize.width <= 0 || mSize.height <= 0) {
    879    return Nothing();
    880  }
    881 
    882  mCurrentClip = mBackBufferInvalid.GetBounds();
    883 
    884  mContext->RSSetState(mAttachments->mRasterizerState);
    885 
    886  SetRenderTarget(mDefaultRT);
    887 
    888  IntRegion regionToClear(mCurrentClip);
    889  regionToClear.Sub(regionToClear, aOpaqueRegion);
    890 
    891  ClearRect(Rect(regionToClear.GetBounds()));
    892 
    893  mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor,
    894                            0xFFFFFFFF);
    895 
    896  if (mAttachments->mSyncObject) {
    897    if (!mAttachments->mSyncObject->Synchronize()) {
    898      // It's timeout here. Since the timeout is related to the driver-removed,
    899      // skip this frame.
    900      return Nothing();
    901    }
    902  }
    903 
    904  return Some(rect);
    905 }
    906 
    907 void CompositorD3D11::EndFrame() {
    908  if (!profiler_feature_active(ProfilerFeature::Screenshots) && mWindowRTCopy) {
    909    mWindowRTCopy = nullptr;
    910  }
    911 
    912  if (!mDefaultRT) {
    913    Compositor::EndFrame();
    914    mTarget = nullptr;
    915    return;
    916  }
    917 
    918  if (XRE_IsParentProcess() && mDevice->GetDeviceRemovedReason() != S_OK) {
    919    gfxCriticalNote << "GFX: D3D11 skip EndFrame with device-removed.";
    920    Compositor::EndFrame();
    921    mTarget = nullptr;
    922    mCurrentRT = nullptr;
    923    return;
    924  }
    925 
    926  LayoutDeviceIntSize oldSize = mSize;
    927  EnsureSize();
    928  if (mSize.width <= 0 || mSize.height <= 0) {
    929    Compositor::EndFrame();
    930    mTarget = nullptr;
    931    return;
    932  }
    933 
    934  RefPtr<ID3D11Query> query;
    935  if (mRecycledQuery) {
    936    query = mRecycledQuery.forget();
    937  } else {
    938    CD3D11_QUERY_DESC desc(D3D11_QUERY_EVENT);
    939    mDevice->CreateQuery(&desc, getter_AddRefs(query));
    940  }
    941  if (query) {
    942    mContext->End(query);
    943  }
    944 
    945  if (oldSize == mSize) {
    946    Present();
    947  }
    948 
    949  // Block until the previous frame's work has been completed.
    950  if (mQuery) {
    951    BOOL result;
    952    WaitForFrameGPUQuery(mDevice, mContext, mQuery, &result);
    953    // Store the query for recycling
    954    mRecycledQuery = mQuery;
    955  }
    956  // Store the query for this frame so we can flush it next time.
    957  mQuery = query;
    958 
    959  Compositor::EndFrame();
    960  mTarget = nullptr;
    961  mCurrentRT = nullptr;
    962 }
    963 
    964 void CompositorD3D11::Present() {
    965  UINT presentInterval = 0;
    966 
    967  bool isWARP = DeviceManagerDx::Get()->IsWARP();
    968  if (isWARP) {
    969    // When we're using WARP we cannot present immediately as it causes us
    970    // to tear when rendering. When not using WARP it appears the DWM takes
    971    // care of tearing for us.
    972    presentInterval = 1;
    973  }
    974 
    975  // This must be called before present so our back buffer has the validated
    976  // window content.
    977  if (mTarget) {
    978    PaintToTarget();
    979  }
    980 
    981  RefPtr<IDXGISwapChain1> chain;
    982  HRESULT hr =
    983      mSwapChain->QueryInterface((IDXGISwapChain1**)getter_AddRefs(chain));
    984 
    985  RefPtr<IDXGIKeyedMutex> mutex;
    986  if (mUseMutexOnPresent && mAttachments->mSyncObject) {
    987    SyncObjectD3D11Host* d3dSyncObj =
    988        (SyncObjectD3D11Host*)mAttachments->mSyncObject.get();
    989    mutex = d3dSyncObj->GetKeyedMutex();
    990    MOZ_ASSERT(mutex);
    991  }
    992 
    993  if (SUCCEEDED(hr) && mAllowPartialPresents) {
    994    DXGI_PRESENT_PARAMETERS params;
    995    PodZero(&params);
    996    params.DirtyRectsCount = mBackBufferInvalid.GetNumRects();
    997    StackArray<RECT, 4> rects(params.DirtyRectsCount);
    998 
    999    uint32_t i = 0;
   1000    for (auto iter = mBackBufferInvalid.RectIter(); !iter.Done(); iter.Next()) {
   1001      const IntRect& r = iter.Get();
   1002      rects[i].left = r.X();
   1003      rects[i].top = r.Y();
   1004      rects[i].bottom = r.YMost();
   1005      rects[i].right = r.XMost();
   1006      i++;
   1007    }
   1008 
   1009    params.pDirtyRects = params.DirtyRectsCount ? rects.data() : nullptr;
   1010 
   1011    if (mutex) {
   1012      hr = mutex->AcquireSync(0, 2000);
   1013      NS_ENSURE_TRUE_VOID(SUCCEEDED(hr));
   1014    }
   1015 
   1016    chain->Present1(
   1017        presentInterval,
   1018        mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0,
   1019        &params);
   1020 
   1021    if (mutex) {
   1022      mutex->ReleaseSync(0);
   1023    }
   1024  } else {
   1025    if (mutex) {
   1026      hr = mutex->AcquireSync(0, 2000);
   1027      NS_ENSURE_TRUE_VOID(SUCCEEDED(hr));
   1028    }
   1029 
   1030    hr = mSwapChain->Present(
   1031        0, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0);
   1032 
   1033    if (mutex) {
   1034      mutex->ReleaseSync(0);
   1035    }
   1036 
   1037    if (FAILED(hr)) {
   1038      gfxCriticalNote << "D3D11 swap chain preset failed " << hexa(hr);
   1039      HandleError(hr);
   1040    }
   1041  }
   1042 
   1043  if (mIsDoubleBuffered) {
   1044    mBackBufferInvalid = mFrontBufferInvalid;
   1045    mFrontBufferInvalid.SetEmpty();
   1046  } else {
   1047    mBackBufferInvalid.SetEmpty();
   1048  }
   1049 
   1050  mDisableSequenceForNextFrame = false;
   1051 }
   1052 
   1053 void CompositorD3D11::CancelFrame(bool aNeedFlush) {
   1054  // Flush the context, otherwise the driver might hold some resources alive
   1055  // until the next flush or present.
   1056  if (aNeedFlush) {
   1057    mContext->Flush();
   1058  }
   1059 }
   1060 
   1061 void CompositorD3D11::PrepareViewport(const gfx::IntSize& aSize) {
   1062  // This view matrix translates coordinates from 0..width and 0..height to
   1063  // -1..1 on the X axis, and -1..1 on the Y axis (flips the Y coordinate)
   1064  Matrix viewMatrix = Matrix::Translation(-1.0, 1.0);
   1065  viewMatrix.PreScale(2.0f / float(aSize.width), 2.0f / float(aSize.height));
   1066  viewMatrix.PreScale(1.0f, -1.0f);
   1067 
   1068  Matrix4x4 projection = Matrix4x4::From2D(viewMatrix);
   1069  projection._33 = 0.0f;
   1070 
   1071  PrepareViewport(aSize, projection, 0.0f, 1.0f);
   1072 }
   1073 
   1074 void CompositorD3D11::PrepareViewport(const gfx::IntSize& aSize,
   1075                                      const gfx::Matrix4x4& aProjection,
   1076                                      float aZNear, float aZFar) {
   1077  D3D11_VIEWPORT viewport;
   1078  viewport.MaxDepth = aZFar;
   1079  viewport.MinDepth = aZNear;
   1080  viewport.Width = aSize.width;
   1081  viewport.Height = aSize.height;
   1082  viewport.TopLeftX = 0;
   1083  viewport.TopLeftY = 0;
   1084 
   1085  mContext->RSSetViewports(1, &viewport);
   1086 
   1087  memcpy(&mVSConstants.projection, &aProjection._11,
   1088         sizeof(mVSConstants.projection));
   1089 }
   1090 
   1091 void CompositorD3D11::EnsureSize() { mSize = mWidget->GetClientSize(); }
   1092 
   1093 bool CompositorD3D11::VerifyBufferSize() {
   1094  mWidget->AsWindows()->UpdateCompositorWndSizeIfNecessary();
   1095 
   1096  DXGI_SWAP_CHAIN_DESC swapDesc;
   1097  HRESULT hr;
   1098 
   1099  hr = mSwapChain->GetDesc(&swapDesc);
   1100  if (FAILED(hr)) {
   1101    gfxCriticalError() << "Failed to get the description " << hexa(hr) << ", "
   1102                       << mSize << ", " << (int)mVerifyBuffersFailed;
   1103    HandleError(hr);
   1104    return false;
   1105  }
   1106 
   1107  if (((static_cast<int32_t>(swapDesc.BufferDesc.Width) == mSize.width &&
   1108        static_cast<int32_t>(swapDesc.BufferDesc.Height) == mSize.height) ||
   1109       mSize.width <= 0 || mSize.height <= 0) &&
   1110      !mVerifyBuffersFailed) {
   1111    return true;
   1112  }
   1113 
   1114  ID3D11RenderTargetView* view = nullptr;
   1115  mContext->OMSetRenderTargets(1, &view, nullptr);
   1116 
   1117  if (mDefaultRT) {
   1118    RefPtr<ID3D11RenderTargetView> rtView = mDefaultRT->mRTView;
   1119    RefPtr<ID3D11ShaderResourceView> srView = mDefaultRT->mSRV;
   1120 
   1121    // Make sure the texture, which belongs to the swapchain, is destroyed
   1122    // before resizing the swapchain.
   1123    if (mCurrentRT == mDefaultRT) {
   1124      mCurrentRT = nullptr;
   1125    }
   1126 
   1127    MOZ_ASSERT(mDefaultRT->hasOneRef());
   1128    mDefaultRT = nullptr;
   1129 
   1130    RefPtr<ID3D11Resource> resource;
   1131    rtView->GetResource(getter_AddRefs(resource));
   1132 
   1133    ULONG newRefCnt = rtView.forget().take()->Release();
   1134 
   1135    if (newRefCnt > 0) {
   1136      gfxCriticalError() << "mRTView not destroyed on final release! RefCnt: "
   1137                         << newRefCnt;
   1138    }
   1139 
   1140    if (srView) {
   1141      newRefCnt = srView.forget().take()->Release();
   1142 
   1143      if (newRefCnt > 0) {
   1144        gfxCriticalError() << "mSRV not destroyed on final release! RefCnt: "
   1145                           << newRefCnt;
   1146      }
   1147    }
   1148 
   1149    newRefCnt = resource.forget().take()->Release();
   1150 
   1151    if (newRefCnt > 0) {
   1152      gfxCriticalError()
   1153          << "Unexpecting lingering references to backbuffer! RefCnt: "
   1154          << newRefCnt;
   1155    }
   1156  }
   1157 
   1158  hr = mSwapChain->ResizeBuffers(0, mSize.width, mSize.height,
   1159                                 DXGI_FORMAT_B8G8R8A8_UNORM, 0);
   1160 
   1161  mVerifyBuffersFailed = FAILED(hr);
   1162  if (mVerifyBuffersFailed) {
   1163    gfxCriticalNote << "D3D11 swap resize buffers failed " << hexa(hr) << " on "
   1164                    << mSize;
   1165    HandleError(hr);
   1166    mBufferSize = LayoutDeviceIntSize();
   1167  } else {
   1168    mBufferSize = mSize;
   1169  }
   1170 
   1171  mBackBufferInvalid = mFrontBufferInvalid =
   1172      IntRect(0, 0, mSize.width, mSize.height);
   1173 
   1174  return !mVerifyBuffersFailed;
   1175 }
   1176 
   1177 bool CompositorD3D11::UpdateRenderTarget() {
   1178  HRESULT hr;
   1179 
   1180  RefPtr<ID3D11Texture2D> backBuf;
   1181 
   1182  if (!VerifyBufferSize()) {
   1183    gfxCriticalNote << "Failed VerifyBufferSize in UpdateRenderTarget "
   1184                    << mSize;
   1185    return false;
   1186  }
   1187 
   1188  if (mSize.width <= 0 || mSize.height <= 0) {
   1189    gfxCriticalNote << "Invalid size in UpdateRenderTarget " << mSize << ", "
   1190                    << (int)mVerifyBuffersFailed;
   1191    return false;
   1192  }
   1193 
   1194  hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
   1195                             (void**)backBuf.StartAssignment());
   1196  if (hr == DXGI_ERROR_INVALID_CALL) {
   1197    // This happens on some GPUs/drivers when there's a TDR.
   1198    if (mDevice->GetDeviceRemovedReason() != S_OK) {
   1199      gfxCriticalError() << "GetBuffer returned invalid call! " << mSize << ", "
   1200                         << (int)mVerifyBuffersFailed;
   1201      return false;
   1202    }
   1203  }
   1204 
   1205  if (FAILED(hr)) {
   1206    gfxCriticalNote << "Failed in UpdateRenderTarget " << hexa(hr) << ", "
   1207                    << mSize << ", " << (int)mVerifyBuffersFailed;
   1208    HandleError(hr);
   1209    return false;
   1210  }
   1211 
   1212  IntRegion validFront;
   1213  validFront.Sub(mBackBufferInvalid, mFrontBufferInvalid);
   1214 
   1215  if (mIsDoubleBuffered && !validFront.IsEmpty()) {
   1216    RefPtr<ID3D11Texture2D> frontBuf;
   1217    hr = mSwapChain->GetBuffer(1, __uuidof(ID3D11Texture2D),
   1218                               (void**)frontBuf.StartAssignment());
   1219 
   1220    if (SUCCEEDED(hr)) {
   1221      for (auto iter = validFront.RectIter(); !iter.Done(); iter.Next()) {
   1222        const IntRect& rect = iter.Get();
   1223 
   1224        D3D11_BOX box;
   1225        box.back = 1;
   1226        box.front = 0;
   1227        box.left = rect.X();
   1228        box.right = rect.XMost();
   1229        box.top = rect.Y();
   1230        box.bottom = rect.YMost();
   1231        mContext->CopySubresourceRegion(backBuf, 0, rect.X(), rect.Y(), 0,
   1232                                        frontBuf, 0, &box);
   1233      }
   1234      mBackBufferInvalid = mFrontBufferInvalid;
   1235    }
   1236  }
   1237 
   1238  mDefaultRT = new CompositingRenderTargetD3D11(backBuf, IntPoint(0, 0));
   1239  mDefaultRT->SetSize(mSize.ToUnknownSize());
   1240 
   1241  return true;
   1242 }
   1243 
   1244 bool CompositorD3D11::UpdateConstantBuffers() {
   1245  HRESULT hr;
   1246  D3D11_MAPPED_SUBRESOURCE resource;
   1247  resource.pData = nullptr;
   1248 
   1249  hr = mContext->Map(mAttachments->mVSConstantBuffer, 0,
   1250                     D3D11_MAP_WRITE_DISCARD, 0, &resource);
   1251  if (FAILED(hr) || !resource.pData) {
   1252    gfxCriticalError() << "Failed to map VSConstantBuffer. Result: " << hexa(hr)
   1253                       << ", " << (int)mVerifyBuffersFailed;
   1254    HandleError(hr);
   1255    return false;
   1256  }
   1257  *(VertexShaderConstants*)resource.pData = mVSConstants;
   1258  mContext->Unmap(mAttachments->mVSConstantBuffer, 0);
   1259  resource.pData = nullptr;
   1260 
   1261  hr = mContext->Map(mAttachments->mPSConstantBuffer, 0,
   1262                     D3D11_MAP_WRITE_DISCARD, 0, &resource);
   1263  if (FAILED(hr) || !resource.pData) {
   1264    gfxCriticalError() << "Failed to map PSConstantBuffer. Result: " << hexa(hr)
   1265                       << ", " << (int)mVerifyBuffersFailed;
   1266    HandleError(hr);
   1267    return false;
   1268  }
   1269  *(PixelShaderConstants*)resource.pData = mPSConstants;
   1270  mContext->Unmap(mAttachments->mPSConstantBuffer, 0);
   1271 
   1272  ID3D11Buffer* buffer = mAttachments->mVSConstantBuffer;
   1273 
   1274  mContext->VSSetConstantBuffers(0, 1, &buffer);
   1275 
   1276  buffer = mAttachments->mPSConstantBuffer;
   1277  mContext->PSSetConstantBuffers(0, 1, &buffer);
   1278  return true;
   1279 }
   1280 
   1281 void CompositorD3D11::SetSamplerForSamplingFilter(
   1282    SamplingFilter aSamplingFilter) {
   1283  ID3D11SamplerState* sampler;
   1284  switch (aSamplingFilter) {
   1285    case SamplingFilter::POINT:
   1286      sampler = mAttachments->mPointSamplerState;
   1287      break;
   1288    case SamplingFilter::LINEAR:
   1289    default:
   1290      sampler = mAttachments->mLinearSamplerState;
   1291      break;
   1292  }
   1293 
   1294  mContext->PSSetSamplers(0, 1, &sampler);
   1295 }
   1296 
   1297 void CompositorD3D11::PaintToTarget() {
   1298  RefPtr<ID3D11Texture2D> backBuf;
   1299  HRESULT hr;
   1300 
   1301  hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
   1302                             (void**)backBuf.StartAssignment());
   1303  if (FAILED(hr)) {
   1304    gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false))
   1305        << "Failed in PaintToTarget 1";
   1306    HandleError(hr);
   1307    return;
   1308  }
   1309 
   1310  D3D11_TEXTURE2D_DESC bbDesc;
   1311  backBuf->GetDesc(&bbDesc);
   1312 
   1313  CD3D11_TEXTURE2D_DESC softDesc(bbDesc.Format, bbDesc.Width, bbDesc.Height);
   1314  softDesc.MipLevels = 1;
   1315  softDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
   1316  softDesc.Usage = D3D11_USAGE_STAGING;
   1317  softDesc.BindFlags = 0;
   1318 
   1319  RefPtr<ID3D11Texture2D> readTexture;
   1320 
   1321  hr =
   1322      mDevice->CreateTexture2D(&softDesc, nullptr, getter_AddRefs(readTexture));
   1323  if (FAILED(hr)) {
   1324    gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false))
   1325        << "Failed in PaintToTarget 2";
   1326    HandleError(hr);
   1327    return;
   1328  }
   1329  mContext->CopyResource(readTexture, backBuf);
   1330 
   1331  D3D11_MAPPED_SUBRESOURCE map;
   1332  hr = mContext->Map(readTexture, 0, D3D11_MAP_READ, 0, &map);
   1333  if (FAILED(hr)) {
   1334    gfxCriticalErrorOnce(gfxCriticalError::DefaultOptions(false))
   1335        << "Failed in PaintToTarget 3";
   1336    HandleError(hr);
   1337    return;
   1338  }
   1339  RefPtr<DataSourceSurface> sourceSurface =
   1340      Factory::CreateWrappingDataSourceSurface(
   1341          (uint8_t*)map.pData, map.RowPitch,
   1342          IntSize(bbDesc.Width, bbDesc.Height), SurfaceFormat::B8G8R8A8);
   1343  mTarget->CopySurface(sourceSurface,
   1344                       IntRect(0, 0, bbDesc.Width, bbDesc.Height),
   1345                       IntPoint(-mTargetBounds.X(), -mTargetBounds.Y()));
   1346 
   1347  mTarget->Flush();
   1348  mContext->Unmap(readTexture, 0);
   1349 }
   1350 
   1351 bool CompositorD3D11::Failed(HRESULT hr, const char* aContext) {
   1352  if (SUCCEEDED(hr)) return false;
   1353 
   1354  gfxCriticalNote << "[D3D11] " << aContext << " failed: " << hexa(hr) << ", "
   1355                  << (int)mVerifyBuffersFailed;
   1356  return true;
   1357 }
   1358 
   1359 SyncObjectHost* CompositorD3D11::GetSyncObject() {
   1360  if (mAttachments) {
   1361    return mAttachments->mSyncObject;
   1362  }
   1363  return nullptr;
   1364 }
   1365 
   1366 void CompositorD3D11::HandleError(HRESULT hr, Severity aSeverity) {
   1367  if (SUCCEEDED(hr)) {
   1368    return;
   1369  }
   1370 
   1371  if (aSeverity == Critical) {
   1372    MOZ_CRASH("GFX: Unrecoverable D3D11 error");
   1373  }
   1374 
   1375  if (mDevice && DeviceManagerDx::Get()->GetCompositorDevice() != mDevice) {
   1376    gfxCriticalNote << "Out of sync D3D11 devices in HandleError, "
   1377                    << (int)mVerifyBuffersFailed;
   1378  }
   1379 
   1380  HRESULT hrOnReset = S_OK;
   1381  bool deviceRemoved = hr == DXGI_ERROR_DEVICE_REMOVED;
   1382 
   1383  if (deviceRemoved && mDevice) {
   1384    hrOnReset = mDevice->GetDeviceRemovedReason();
   1385  } else if (hr == DXGI_ERROR_INVALID_CALL && mDevice) {
   1386    hrOnReset = mDevice->GetDeviceRemovedReason();
   1387    if (hrOnReset != S_OK) {
   1388      deviceRemoved = true;
   1389    }
   1390  }
   1391 
   1392  // Device reset may not be an error on our side, but can mess things up so
   1393  // it's useful to see it in the reports.
   1394  gfxCriticalError(CriticalLog::DefaultOptions(!deviceRemoved))
   1395      << (deviceRemoved ? "[CompositorD3D11] device removed with error code: "
   1396                        : "[CompositorD3D11] error code: ")
   1397      << hexa(hr) << ", " << hexa(hrOnReset) << ", "
   1398      << (int)mVerifyBuffersFailed;
   1399 
   1400  // Crash if we are making invalid calls outside of device removal
   1401  if (hr == DXGI_ERROR_INVALID_CALL) {
   1402    gfxDevCrash(deviceRemoved ? LogReason::D3D11InvalidCallDeviceRemoved
   1403                              : LogReason::D3D11InvalidCall)
   1404        << "Invalid D3D11 api call";
   1405  }
   1406 
   1407  if (aSeverity == Recoverable) {
   1408    NS_WARNING("Encountered a recoverable D3D11 error");
   1409  }
   1410 }
   1411 
   1412 }  // namespace layers
   1413 }  // namespace mozilla