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