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