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 "MLGDeviceD3D11.h"
8 #include "mozilla/ArrayUtils.h"
9 #include "mozilla/Telemetry.h"
10 #include "mozilla/WindowsVersion.h"
11 #include "mozilla/gfx/GPUParent.h"
12 #include "mozilla/gfx/StackArray.h"
13 #include "mozilla/layers/DiagnosticsD3D11.h"
14 #include "mozilla/layers/HelpersD3D11.h"
15 #include "mozilla/layers/LayerMLGPU.h"
16 #include "mozilla/layers/MemoryReportingMLGPU.h"
17 #include "mozilla/layers/ShaderDefinitionsMLGPU.h"
18 #include "mozilla/layers/UtilityMLGPU.h"
19 #include "mozilla/widget/CompositorWidget.h"
20 #include "mozilla/widget/WinCompositorWidget.h"
21 #include "MLGShaders.h"
22 #include "LayersLogging.h"
23 #include "TextureD3D11.h"
24 #include "gfxConfig.h"
25 #include "mozilla/StaticPrefs_layers.h"
26 #include "FxROutputHandler.h"
27 
28 namespace mozilla {
29 namespace layers {
30 
31 using namespace mozilla::gfx;
32 using namespace mozilla::widget;
33 using namespace mozilla::layers::mlg;
34 
35 // Defined in CompositorD3D11.cpp.
36 bool CanUsePartialPresents(ID3D11Device* aDevice);
37 
38 static D3D11_BOX RectToBox(const gfx::IntRect& aRect);
39 
MLGRenderTargetD3D11(const gfx::IntSize & aSize,MLGRenderTargetFlags aFlags)40 MLGRenderTargetD3D11::MLGRenderTargetD3D11(const gfx::IntSize& aSize,
41                                            MLGRenderTargetFlags aFlags)
42     : MLGRenderTarget(aFlags), mSize(aSize) {}
43 
~MLGRenderTargetD3D11()44 MLGRenderTargetD3D11::~MLGRenderTargetD3D11() {
45   if (mDepthBuffer) {
46     sRenderTargetUsage -= mSize.width * mSize.height * 1;
47   }
48   ForgetTexture();
49 }
50 
Initialize(ID3D11Device * aDevice)51 bool MLGRenderTargetD3D11::Initialize(ID3D11Device* aDevice) {
52   D3D11_TEXTURE2D_DESC desc;
53   ::ZeroMemory(&desc, sizeof(desc));
54   desc.Width = mSize.width;
55   desc.Height = mSize.height;
56   desc.MipLevels = 1;
57   desc.ArraySize = 1;
58   desc.SampleDesc.Count = 1;
59   desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
60   desc.Usage = D3D11_USAGE_DEFAULT;
61   desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
62 
63   RefPtr<ID3D11Texture2D> texture;
64   HRESULT hr =
65       aDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
66   if (FAILED(hr) || !texture) {
67     gfxCriticalNote << "Failed to create render target texture: " << hexa(hr);
68     return false;
69   }
70 
71   return Initialize(aDevice, texture);
72 }
73 
Initialize(ID3D11Device * aDevice,ID3D11Texture2D * aTexture)74 bool MLGRenderTargetD3D11::Initialize(ID3D11Device* aDevice,
75                                       ID3D11Texture2D* aTexture) {
76   if (!UpdateTexture(aTexture)) {
77     return false;
78   }
79   if ((mFlags & MLGRenderTargetFlags::ZBuffer) && !CreateDepthBuffer(aDevice)) {
80     return false;
81   }
82   return true;
83 }
84 
UpdateTexture(ID3D11Texture2D * aTexture)85 bool MLGRenderTargetD3D11::UpdateTexture(ID3D11Texture2D* aTexture) {
86   // Save the view first, in case we can re-use it.
87   RefPtr<ID3D11RenderTargetView> view = mRTView.forget();
88 
89   ForgetTexture();
90 
91   if (!aTexture) {
92     return true;
93   }
94 
95 #ifdef DEBUG
96   D3D11_TEXTURE2D_DESC desc;
97   aTexture->GetDesc(&desc);
98   MOZ_ASSERT(desc.Width == mSize.width && desc.Height == mSize.height);
99 #endif
100 
101   RefPtr<ID3D11Device> device;
102   aTexture->GetDevice(getter_AddRefs(device));
103 
104   if (view) {
105     // Check that the view matches the backing texture.
106     RefPtr<ID3D11Resource> resource;
107     view->GetResource(getter_AddRefs(resource));
108     if (resource != aTexture) {
109       view = nullptr;
110     }
111   }
112 
113   // If we couldn't re-use a view from before, make one now.
114   if (!view) {
115     HRESULT hr =
116         device->CreateRenderTargetView(aTexture, nullptr, getter_AddRefs(view));
117     if (FAILED(hr) || !view) {
118       gfxCriticalNote << "Failed to create render target view: " << hexa(hr);
119       return false;
120     }
121   }
122 
123   mTexture = aTexture;
124   mRTView = view.forget();
125   sRenderTargetUsage += mSize.width * mSize.height * 4;
126   return true;
127 }
128 
ForgetTexture()129 void MLGRenderTargetD3D11::ForgetTexture() {
130   if (mTexture) {
131     sRenderTargetUsage -= mSize.width * mSize.height * 4;
132     mTexture = nullptr;
133   }
134   mRTView = nullptr;
135   mTextureSource = nullptr;
136 }
137 
CreateDepthBuffer(ID3D11Device * aDevice)138 bool MLGRenderTargetD3D11::CreateDepthBuffer(ID3D11Device* aDevice) {
139   D3D11_TEXTURE2D_DESC desc;
140   ::ZeroMemory(&desc, sizeof(desc));
141   desc.Width = mSize.width;
142   desc.Height = mSize.height;
143   desc.MipLevels = 1;
144   desc.ArraySize = 1;
145   desc.Format = DXGI_FORMAT_D32_FLOAT;
146   desc.SampleDesc.Count = 1;
147   desc.SampleDesc.Quality = 0;
148   desc.Usage = D3D11_USAGE_DEFAULT;
149   desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
150 
151   RefPtr<ID3D11Texture2D> buffer;
152   HRESULT hr = aDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(buffer));
153   if (FAILED(hr) || !buffer) {
154     gfxCriticalNote << "Could not create depth-stencil buffer: " << hexa(hr);
155     return false;
156   }
157 
158   D3D11_DEPTH_STENCIL_VIEW_DESC viewDesc;
159   ::ZeroMemory(&viewDesc, sizeof(viewDesc));
160   viewDesc.Format = DXGI_FORMAT_D32_FLOAT;
161   viewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
162 
163   RefPtr<ID3D11DepthStencilView> dsv;
164   hr = aDevice->CreateDepthStencilView(buffer, &viewDesc, getter_AddRefs(dsv));
165   if (FAILED(hr) || !dsv) {
166     gfxCriticalNote << "Could not create depth-stencil view: " << hexa(hr);
167     return false;
168   }
169 
170   mDepthBuffer = buffer;
171   mDepthStencilView = dsv;
172   sRenderTargetUsage += mSize.width * mSize.height * 1;
173   return true;
174 }
175 
GetDSV()176 ID3D11DepthStencilView* MLGRenderTargetD3D11::GetDSV() {
177   return mDepthStencilView;
178 }
179 
GetRenderTargetView()180 ID3D11RenderTargetView* MLGRenderTargetD3D11::GetRenderTargetView() {
181   return mRTView;
182 }
183 
GetSize() const184 IntSize MLGRenderTargetD3D11::GetSize() const { return mSize; }
185 
GetTexture()186 MLGTexture* MLGRenderTargetD3D11::GetTexture() {
187   if (!mTextureSource) {
188     mTextureSource = new MLGTextureD3D11(mTexture);
189   }
190   return mTextureSource;
191 }
192 
MLGSwapChainD3D11(MLGDeviceD3D11 * aParent,ID3D11Device * aDevice)193 MLGSwapChainD3D11::MLGSwapChainD3D11(MLGDeviceD3D11* aParent,
194                                      ID3D11Device* aDevice)
195     : mParent(aParent),
196       mDevice(aDevice),
197       mWidget(nullptr),
198       mCanUsePartialPresents(CanUsePartialPresents(aDevice)) {}
199 
~MLGSwapChainD3D11()200 MLGSwapChainD3D11::~MLGSwapChainD3D11() {}
201 
Destroy()202 void MLGSwapChainD3D11::Destroy() {
203   if (mRT == mParent->GetRenderTarget()) {
204     mParent->SetRenderTarget(nullptr);
205   }
206   mWidget = nullptr;
207   mRT = nullptr;
208   mSwapChain = nullptr;
209   mSwapChain1 = nullptr;
210 }
211 
Create(MLGDeviceD3D11 * aParent,ID3D11Device * aDevice,CompositorWidget * aWidget)212 RefPtr<MLGSwapChainD3D11> MLGSwapChainD3D11::Create(MLGDeviceD3D11* aParent,
213                                                     ID3D11Device* aDevice,
214                                                     CompositorWidget* aWidget) {
215   RefPtr<MLGSwapChainD3D11> swapChain = new MLGSwapChainD3D11(aParent, aDevice);
216   if (!swapChain->Initialize(aWidget)) {
217     return nullptr;
218   }
219   return swapChain.forget();
220 }
221 
Initialize(CompositorWidget * aWidget)222 bool MLGSwapChainD3D11::Initialize(CompositorWidget* aWidget) {
223   HWND hwnd = aWidget->AsWindows()->GetHwnd();
224 
225   RefPtr<IDXGIDevice> dxgiDevice;
226   mDevice->QueryInterface(dxgiDevice.StartAssignment());
227 
228   RefPtr<IDXGIFactory> dxgiFactory;
229   {
230     RefPtr<IDXGIAdapter> adapter;
231     dxgiDevice->GetAdapter(getter_AddRefs(adapter));
232 
233     adapter->GetParent(IID_PPV_ARGS(dxgiFactory.StartAssignment()));
234   }
235 
236   RefPtr<IDXGIFactory2> dxgiFactory2;
237   if (gfxVars::UseDoubleBufferingWithCompositor() &&
238       SUCCEEDED(dxgiFactory->QueryInterface(dxgiFactory2.StartAssignment())) &&
239       dxgiFactory2 && XRE_IsGPUProcess()) {
240     // DXGI_SCALING_NONE is not available on Windows 7 with the Platform Update:
241     // This looks awful for things like the awesome bar and browser window
242     // resizing, so we don't use a flip buffer chain here. (Note when using
243     // EFFECT_SEQUENTIAL Windows doesn't stretch the surface when resizing).
244     //
245     // We choose not to run this on platforms earlier than Windows 10 because
246     // it appears sometimes this breaks our ability to test ASAP compositing,
247     // which breaks Talos.
248     //
249     // When the GPU process is disabled we don't have a compositor window which
250     // can lead to issues with Window re-use so we don't use this.
251     DXGI_SWAP_CHAIN_DESC1 desc;
252     ::ZeroMemory(&desc, sizeof(desc));
253     desc.Width = 0;
254     desc.Height = 0;
255     desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
256     desc.SampleDesc.Count = 1;
257     desc.SampleDesc.Quality = 0;
258     desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
259     desc.BufferCount = 2;
260     desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
261     desc.Scaling = DXGI_SCALING_NONE;
262     desc.Flags = 0;
263 
264     HRESULT hr = dxgiFactory2->CreateSwapChainForHwnd(
265         mDevice, hwnd, &desc, nullptr, nullptr, getter_AddRefs(mSwapChain1));
266     if (SUCCEEDED(hr) && mSwapChain1) {
267       DXGI_RGBA color = {1.0f, 1.0f, 1.0f, 1.0f};
268       mSwapChain1->SetBackgroundColor(&color);
269       mSwapChain = mSwapChain1;
270       mIsDoubleBuffered = true;
271     } else if (aWidget->AsWindows()->GetCompositorHwnd()) {
272       // Destroy compositor window.
273       aWidget->AsWindows()->DestroyCompositorWindow();
274       hwnd = aWidget->AsWindows()->GetHwnd();
275     }
276   }
277 
278   if (!mSwapChain) {
279     DXGI_SWAP_CHAIN_DESC swapDesc;
280     ::ZeroMemory(&swapDesc, sizeof(swapDesc));
281     swapDesc.BufferDesc.Width = 0;
282     swapDesc.BufferDesc.Height = 0;
283     swapDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
284     swapDesc.BufferDesc.RefreshRate.Numerator = 60;
285     swapDesc.BufferDesc.RefreshRate.Denominator = 1;
286     swapDesc.SampleDesc.Count = 1;
287     swapDesc.SampleDesc.Quality = 0;
288     swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
289     swapDesc.BufferCount = 1;
290     swapDesc.OutputWindow = hwnd;
291     swapDesc.Windowed = TRUE;
292     swapDesc.Flags = 0;
293     swapDesc.SwapEffect = DXGI_SWAP_EFFECT_SEQUENTIAL;
294 
295     HRESULT hr = dxgiFactory->CreateSwapChain(dxgiDevice, &swapDesc,
296                                               getter_AddRefs(mSwapChain));
297     if (FAILED(hr)) {
298       gfxCriticalNote << "Could not create swap chain: " << hexa(hr);
299       return false;
300     }
301 
302     // Try to get an IDXGISwapChain1 if we can, for partial presents.
303     mSwapChain->QueryInterface(mSwapChain1.StartAssignment());
304   }
305 
306   // We need this because we don't want DXGI to respond to Alt+Enter.
307   dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_WINDOW_CHANGES);
308   mWidget = aWidget;
309   return true;
310 }
311 
AcquireBackBuffer()312 RefPtr<MLGRenderTarget> MLGSwapChainD3D11::AcquireBackBuffer() {
313   RefPtr<ID3D11Texture2D> texture;
314   HRESULT hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
315                                      getter_AddRefs(texture));
316   if (hr == DXGI_ERROR_INVALID_CALL &&
317       mDevice->GetDeviceRemovedReason() != S_OK) {
318     // This can happen on some drivers when there's a TDR.
319     mParent->HandleDeviceReset("SwapChain::GetBuffer");
320     return nullptr;
321   }
322   if (FAILED(hr)) {
323     gfxCriticalNote << "Failed to acquire swap chain's backbuffer: "
324                     << hexa(hr);
325     return nullptr;
326   }
327 
328   if (!mRT) {
329     MLGRenderTargetFlags flags = MLGRenderTargetFlags::Default;
330     if (StaticPrefs::layers_mlgpu_enable_depth_buffer_AtStartup()) {
331       flags |= MLGRenderTargetFlags::ZBuffer;
332     }
333 
334     mRT = new MLGRenderTargetD3D11(mSize, flags);
335     if (!mRT->Initialize(mDevice, nullptr)) {
336       return nullptr;
337     }
338   }
339 
340   if (!mRT->UpdateTexture(texture)) {
341     return nullptr;
342   }
343 
344   if (mIsDoubleBuffered) {
345     UpdateBackBufferContents(texture);
346   }
347   return mRT;
348 }
349 
UpdateBackBufferContents(ID3D11Texture2D * aBack)350 void MLGSwapChainD3D11::UpdateBackBufferContents(ID3D11Texture2D* aBack) {
351   MOZ_ASSERT(mIsDoubleBuffered);
352 
353   // The front region contains the newly invalid region for this frame. The
354   // back region contains that, plus the region that was only drawn into the
355   // back buffer on the previous frame. Thus by subtracting the two, we can
356   // find the region that needs to be copied from the front buffer to the
357   // back. We do this so we don't have to re-render those pixels.
358   nsIntRegion frontValid;
359   frontValid.Sub(mBackBufferInvalid, mFrontBufferInvalid);
360   if (frontValid.IsEmpty()) {
361     return;
362   }
363 
364   RefPtr<ID3D11Texture2D> front;
365   HRESULT hr = mSwapChain->GetBuffer(1, __uuidof(ID3D11Texture2D),
366                                      getter_AddRefs(front));
367   if (FAILED(hr) || !front) {
368     return;
369   }
370 
371   RefPtr<ID3D11DeviceContext> context;
372   mDevice->GetImmediateContext(getter_AddRefs(context));
373 
374   for (auto iter = frontValid.RectIter(); !iter.Done(); iter.Next()) {
375     const IntRect& rect = iter.Get();
376     D3D11_BOX box = RectToBox(rect);
377     context->CopySubresourceRegion(aBack, 0, rect.X(), rect.Y(), 0, front, 0,
378                                    &box);
379   }
380 
381   // The back and front buffers are now in sync.
382   mBackBufferInvalid = mFrontBufferInvalid;
383   MOZ_ASSERT(!mBackBufferInvalid.IsEmpty());
384 }
385 
ResizeBuffers(const IntSize & aSize)386 bool MLGSwapChainD3D11::ResizeBuffers(const IntSize& aSize) {
387   // We have to clear all references to the old backbuffer before resizing.
388   mRT = nullptr;
389 
390   // Clear the size before re-allocating. If allocation fails we want to try
391   // again, because we had to sacrifice our original backbuffer to try
392   // resizing.
393   mSize = IntSize(0, 0);
394 
395   HRESULT hr = mSwapChain->ResizeBuffers(0, aSize.width, aSize.height,
396                                          DXGI_FORMAT_B8G8R8A8_UNORM, 0);
397   if (hr == DXGI_ERROR_DEVICE_REMOVED) {
398     mParent->HandleDeviceReset("ResizeBuffers");
399     return false;
400   }
401   if (FAILED(hr)) {
402     gfxCriticalNote << "Failed to resize swap chain buffers: " << hexa(hr);
403     return false;
404   }
405 
406   mSize = aSize;
407   mBackBufferInvalid = IntRect(IntPoint(0, 0), mSize);
408   mFrontBufferInvalid = IntRect(IntPoint(0, 0), mSize);
409   return true;
410 }
411 
GetSize() const412 IntSize MLGSwapChainD3D11::GetSize() const { return mSize; }
413 
Present()414 void MLGSwapChainD3D11::Present() {
415   MOZ_ASSERT(!mBackBufferInvalid.IsEmpty());
416   MOZ_ASSERT(mBackBufferInvalid.GetNumRects() > 0);
417 
418   // See bug 1260611 comment #28 for why we do this.
419   mParent->InsertPresentWaitQuery();
420 
421   if (mWidget->AsWindows()->HasFxrOutputHandler()) {
422     // There is a Firefox Reality handler for this swapchain. Update this
423     // window's contents to the VR window.
424     FxROutputHandler* fxrHandler = mWidget->AsWindows()->GetFxrOutputHandler();
425     if (fxrHandler->TryInitialize(mSwapChain, mDevice)) {
426       RefPtr<ID3D11DeviceContext> context;
427       mDevice->GetImmediateContext(getter_AddRefs(context));
428       fxrHandler->UpdateOutput(context);
429     }
430   }
431 
432   HRESULT hr;
433   if (mCanUsePartialPresents && mSwapChain1) {
434     StackArray<RECT, 4> rects(mBackBufferInvalid.GetNumRects());
435     size_t i = 0;
436     for (auto iter = mBackBufferInvalid.RectIter(); !iter.Done(); iter.Next()) {
437       const IntRect& rect = iter.Get();
438       rects[i].left = rect.X();
439       rects[i].top = rect.Y();
440       rects[i].bottom = rect.YMost();
441       rects[i].right = rect.XMost();
442       i++;
443     }
444 
445     DXGI_PRESENT_PARAMETERS params;
446     PodZero(&params);
447     params.DirtyRectsCount = mBackBufferInvalid.GetNumRects();
448     params.pDirtyRects = rects.data();
449     hr = mSwapChain1->Present1(0, 0, &params);
450   } else {
451     hr = mSwapChain->Present(0, 0);
452   }
453 
454   if (hr == DXGI_ERROR_DEVICE_REMOVED) {
455     mParent->HandleDeviceReset("Present");
456   }
457 
458   if (FAILED(hr)) {
459     gfxCriticalNote << "D3D11 swap chain failed to present: " << hexa(hr);
460   }
461 
462   if (mIsDoubleBuffered) {
463     // Both the front and back buffer invalid regions are in sync, but now the
464     // presented buffer (the front buffer) is clean, so we clear its invalid
465     // region. The back buffer that will be used next frame however is now
466     // dirty.
467     MOZ_ASSERT(mFrontBufferInvalid.GetBounds() ==
468                mBackBufferInvalid.GetBounds());
469     mFrontBufferInvalid.SetEmpty();
470   } else {
471     mBackBufferInvalid.SetEmpty();
472   }
473   mLastPresentSize = mSize;
474 
475   // Note: this waits on the query we inserted in the previous frame,
476   // not the one we just inserted now. Example:
477   //   Insert query #1
478   //   Present #1
479   //   (first frame, no wait)
480   //   Insert query #2
481   //   Present #2
482   //   Wait for query #1.
483   //   Insert query #3
484   //   Present #3
485   //   Wait for query #2.
486   //
487   // This ensures we're done reading textures before swapping buffers.
488   mParent->WaitForPreviousPresentQuery();
489 }
490 
ForcePresent()491 void MLGSwapChainD3D11::ForcePresent() {
492   DXGI_SWAP_CHAIN_DESC desc;
493   mSwapChain->GetDesc(&desc);
494 
495   LayoutDeviceIntSize size = mWidget->GetClientSize();
496 
497   if (desc.BufferDesc.Width != size.width ||
498       desc.BufferDesc.Height != size.height) {
499     return;
500   }
501 
502   mSwapChain->Present(0, 0);
503   if (mIsDoubleBuffered) {
504     // Make sure we present the old front buffer since we know it is completely
505     // valid. This non-vsynced present should be pretty much 'free' for a flip
506     // chain.
507     mSwapChain->Present(0, 0);
508   }
509 
510   mLastPresentSize = mSize;
511 }
512 
CopyBackbuffer(gfx::DrawTarget * aTarget,const gfx::IntRect & aBounds)513 void MLGSwapChainD3D11::CopyBackbuffer(gfx::DrawTarget* aTarget,
514                                        const gfx::IntRect& aBounds) {
515   RefPtr<ID3D11DeviceContext> context;
516   mDevice->GetImmediateContext(getter_AddRefs(context));
517 
518   RefPtr<ID3D11Texture2D> backbuffer;
519   HRESULT hr = mSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
520                                      (void**)backbuffer.StartAssignment());
521   if (FAILED(hr)) {
522     gfxWarning() << "Failed to acquire swapchain backbuffer: " << hexa(hr);
523     return;
524   }
525 
526   D3D11_TEXTURE2D_DESC bbDesc;
527   backbuffer->GetDesc(&bbDesc);
528 
529   CD3D11_TEXTURE2D_DESC tempDesc(bbDesc.Format, bbDesc.Width, bbDesc.Height);
530   tempDesc.MipLevels = 1;
531   tempDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
532   tempDesc.Usage = D3D11_USAGE_STAGING;
533   tempDesc.BindFlags = 0;
534 
535   RefPtr<ID3D11Texture2D> temp;
536   hr = mDevice->CreateTexture2D(&tempDesc, nullptr, getter_AddRefs(temp));
537   if (FAILED(hr)) {
538     gfxWarning() << "Failed to create a temporary texture for PresentAndCopy: "
539                  << hexa(hr);
540     return;
541   }
542 
543   context->CopyResource(temp, backbuffer);
544 
545   D3D11_MAPPED_SUBRESOURCE map;
546   hr = context->Map(temp, 0, D3D11_MAP_READ, 0, &map);
547   if (FAILED(hr)) {
548     gfxWarning() << "Failed to map temporary texture for PresentAndCopy: "
549                  << hexa(hr);
550     return;
551   }
552 
553   RefPtr<DataSourceSurface> source = Factory::CreateWrappingDataSourceSurface(
554       (uint8_t*)map.pData, map.RowPitch, IntSize(bbDesc.Width, bbDesc.Height),
555       SurfaceFormat::B8G8R8A8);
556 
557   aTarget->CopySurface(source, IntRect(0, 0, bbDesc.Width, bbDesc.Height),
558                        IntPoint(-aBounds.X(), -aBounds.Y()));
559   aTarget->Flush();
560 
561   context->Unmap(temp, 0);
562 }
563 
Create(ID3D11Device * aDevice,MLGBufferType aType,uint32_t aSize,MLGUsage aUsage,const void * aInitialData)564 RefPtr<MLGBufferD3D11> MLGBufferD3D11::Create(ID3D11Device* aDevice,
565                                               MLGBufferType aType,
566                                               uint32_t aSize, MLGUsage aUsage,
567                                               const void* aInitialData) {
568   D3D11_BUFFER_DESC desc;
569   desc.ByteWidth = aSize;
570   desc.MiscFlags = 0;
571   desc.StructureByteStride = 0;
572 
573   switch (aUsage) {
574     case MLGUsage::Dynamic:
575       desc.Usage = D3D11_USAGE_DYNAMIC;
576       desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
577       break;
578     case MLGUsage::Immutable:
579       desc.Usage = D3D11_USAGE_IMMUTABLE;
580       desc.CPUAccessFlags = 0;
581       break;
582     default:
583       MOZ_ASSERT_UNREACHABLE("Unknown buffer usage type");
584       return nullptr;
585   }
586 
587   switch (aType) {
588     case MLGBufferType::Vertex:
589       desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
590       break;
591     case MLGBufferType::Constant:
592       desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
593       break;
594     default:
595       MOZ_ASSERT_UNREACHABLE("Unknown buffer type");
596       return nullptr;
597   }
598 
599   D3D11_SUBRESOURCE_DATA data;
600   data.pSysMem = aInitialData;
601   data.SysMemPitch = aSize;
602   data.SysMemSlicePitch = 0;
603 
604   RefPtr<ID3D11Buffer> buffer;
605   HRESULT hr = aDevice->CreateBuffer(&desc, aInitialData ? &data : nullptr,
606                                      getter_AddRefs(buffer));
607   if (FAILED(hr) || !buffer) {
608     gfxCriticalError() << "Failed to create ID3D11Buffer.";
609     return nullptr;
610   }
611 
612   return new MLGBufferD3D11(buffer, aType, aSize);
613 }
614 
MLGBufferD3D11(ID3D11Buffer * aBuffer,MLGBufferType aType,size_t aSize)615 MLGBufferD3D11::MLGBufferD3D11(ID3D11Buffer* aBuffer, MLGBufferType aType,
616                                size_t aSize)
617     : mBuffer(aBuffer), mType(aType), mSize(aSize) {
618   switch (mType) {
619     case MLGBufferType::Vertex:
620       mlg::sVertexBufferUsage += mSize;
621       break;
622     case MLGBufferType::Constant:
623       mlg::sConstantBufferUsage += mSize;
624       break;
625   }
626 }
627 
~MLGBufferD3D11()628 MLGBufferD3D11::~MLGBufferD3D11() {
629   switch (mType) {
630     case MLGBufferType::Vertex:
631       mlg::sVertexBufferUsage -= mSize;
632       break;
633     case MLGBufferType::Constant:
634       mlg::sConstantBufferUsage -= mSize;
635       break;
636   }
637 }
638 
MLGTextureD3D11(ID3D11Texture2D * aTexture)639 MLGTextureD3D11::MLGTextureD3D11(ID3D11Texture2D* aTexture)
640     : mTexture(aTexture) {
641   D3D11_TEXTURE2D_DESC desc;
642   aTexture->GetDesc(&desc);
643 
644   mSize.width = desc.Width;
645   mSize.height = desc.Height;
646 }
647 
648 /* static */
Create(ID3D11Device * aDevice,const gfx::IntSize & aSize,gfx::SurfaceFormat aFormat,MLGUsage aUsage,MLGTextureFlags aFlags)649 RefPtr<MLGTextureD3D11> MLGTextureD3D11::Create(ID3D11Device* aDevice,
650                                                 const gfx::IntSize& aSize,
651                                                 gfx::SurfaceFormat aFormat,
652                                                 MLGUsage aUsage,
653                                                 MLGTextureFlags aFlags) {
654   D3D11_TEXTURE2D_DESC desc;
655   ::ZeroMemory(&desc, sizeof(desc));
656   desc.Width = aSize.width;
657   desc.Height = aSize.height;
658   desc.MipLevels = 1;
659   desc.ArraySize = 1;
660   desc.SampleDesc.Count = 1;
661 
662   switch (aFormat) {
663     case SurfaceFormat::B8G8R8A8:
664       desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
665       break;
666     default:
667       MOZ_ASSERT_UNREACHABLE("Unsupported surface format");
668       return nullptr;
669   }
670 
671   switch (aUsage) {
672     case MLGUsage::Immutable:
673       desc.Usage = D3D11_USAGE_IMMUTABLE;
674       break;
675     case MLGUsage::Default:
676       desc.Usage = D3D11_USAGE_DEFAULT;
677       break;
678     case MLGUsage::Dynamic:
679       desc.Usage = D3D11_USAGE_DYNAMIC;
680       desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
681       break;
682     case MLGUsage::Staging:
683       desc.Usage = D3D11_USAGE_STAGING;
684       desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
685       break;
686     default:
687       MOZ_ASSERT_UNREACHABLE("Unsupported usage type");
688       break;
689   }
690 
691   if (aFlags & MLGTextureFlags::ShaderResource) {
692     desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
693   }
694   if (aFlags & MLGTextureFlags::RenderTarget) {
695     desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
696   }
697 
698   RefPtr<ID3D11Texture2D> texture;
699   HRESULT hr =
700       aDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture));
701   if (FAILED(hr) || !texture) {
702     gfxCriticalNote << "Failed to create 2D texture: " << hexa(hr);
703     return nullptr;
704   }
705 
706   ReportTextureMemoryUsage(texture, aSize.width * aSize.height * 4);
707 
708   return new MLGTextureD3D11(texture);
709 }
710 
GetShaderResourceView()711 ID3D11ShaderResourceView* MLGTextureD3D11::GetShaderResourceView() {
712   if (!mView) {
713     RefPtr<ID3D11Device> device;
714     mTexture->GetDevice(getter_AddRefs(device));
715 
716     HRESULT hr = device->CreateShaderResourceView(mTexture, nullptr,
717                                                   getter_AddRefs(mView));
718     if (FAILED(hr) || !mView) {
719       gfxWarning() << "Could not create shader resource view: " << hexa(hr);
720       return nullptr;
721     }
722   }
723   return mView;
724 }
725 
MLGDeviceD3D11(ID3D11Device * aDevice)726 MLGDeviceD3D11::MLGDeviceD3D11(ID3D11Device* aDevice)
727     : mDevice(aDevice), mScissored(false) {}
728 
~MLGDeviceD3D11()729 MLGDeviceD3D11::~MLGDeviceD3D11() {
730   // Caller should have unlocked all textures after presenting.
731   MOZ_ASSERT(mLockedTextures.IsEmpty());
732   MOZ_ASSERT(mLockAttemptedTextures.IsEmpty());
733 }
734 
Initialize()735 bool MLGDeviceD3D11::Initialize() {
736   if (!mDevice) {
737     return Fail("FEATURE_FAILURE_NO_DEVICE");
738   }
739 
740   if (mDevice->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) {
741     return Fail("FEATURE_FAILURE_NEED_LEVEL_10_0");
742   }
743 
744   mDevice->GetImmediateContext(getter_AddRefs(mCtx));
745   if (!mCtx) {
746     return Fail("FEATURE_FAILURE_NO_CONTEXT");
747   }
748 
749   mCtx->QueryInterface((ID3D11DeviceContext1**)getter_AddRefs(mCtx1));
750 
751   if (mCtx1) {
752     // Windows 7 can have Direct3D 11.1 if the platform update is installed,
753     // but according to some NVIDIA presentations it is known to be buggy.
754     // It's not clear whether that only refers to command list emulation,
755     // or whether it just has performance penalties. To be safe we only use
756     // it on Windows 8 or higher.
757     //
758     // https://docs.microsoft.com/en-us/windows-hardware/drivers/display/directx-feature-improvements-in-windows-8#buffers
759     D3D11_FEATURE_DATA_D3D11_OPTIONS options;
760     HRESULT hr = mDevice->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS,
761                                               &options, sizeof(options));
762     if (SUCCEEDED(hr)) {
763       if (IsWin8OrLater()) {
764         mCanUseConstantBufferOffsetBinding =
765             (options.ConstantBufferOffsetting != FALSE);
766       } else {
767         gfxConfig::EnableFallback(Fallback::NO_CONSTANT_BUFFER_OFFSETTING,
768                                   "Unsupported by driver");
769       }
770       mCanUseClearView = (options.ClearView != FALSE);
771     } else {
772       gfxCriticalNote << "Failed to query D3D11.1 feature support: "
773                       << hexa(hr);
774     }
775   }
776 
777   // Get capabilities.
778   switch (mDevice->GetFeatureLevel()) {
779     case D3D_FEATURE_LEVEL_11_1:
780     case D3D_FEATURE_LEVEL_11_0:
781       mMaxConstantBufferBindSize = D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16;
782       break;
783     case D3D_FEATURE_LEVEL_10_1:
784     case D3D_FEATURE_LEVEL_10_0:
785       mMaxConstantBufferBindSize = D3D10_REQ_CONSTANT_BUFFER_ELEMENT_COUNT * 16;
786       break;
787     default:
788       MOZ_ASSERT_UNREACHABLE("Unknown feature level");
789   }
790 
791   mDiagnostics = MakeUnique<DiagnosticsD3D11>(mDevice, mCtx);
792 
793   {
794     struct Vertex2D {
795       float x;
796       float y;
797     };
798     Vertex2D vertices[] = {{0, 0}, {1.0f, 0}, {0, 1.0f}, {1.0f, 1.0f}};
799     mUnitQuadVB = CreateBuffer(MLGBufferType::Vertex, sizeof(Vertex2D) * 4,
800                                MLGUsage::Immutable, &vertices);
801     if (!mUnitQuadVB) {
802       return Fail("FEATURE_FAILURE_UNIT_QUAD_BUFFER");
803     }
804   }
805 
806   {
807     struct Vertex3D {
808       float x;
809       float y;
810       float z;
811     };
812     Vertex3D vertices[3] = {
813         {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 1.0f}};
814     mUnitTriangleVB = CreateBuffer(MLGBufferType::Vertex, sizeof(Vertex3D) * 3,
815                                    MLGUsage::Immutable, &vertices);
816     if (!mUnitTriangleVB) {
817       return Fail("FEATURE_FAILURE_UNIT_TRIANGLE_BUFFER");
818     }
819   }
820 
821   // Define pixel shaders.
822 #define LAZY_PS(cxxName, enumName) \
823   mLazyPixelShaders[PixelShaderID::enumName] = &s##cxxName;
824   LAZY_PS(TexturedVertexRGB, TexturedVertexRGB);
825   LAZY_PS(TexturedVertexRGBA, TexturedVertexRGBA);
826   LAZY_PS(TexturedQuadRGB, TexturedQuadRGB);
827   LAZY_PS(TexturedQuadRGBA, TexturedQuadRGBA);
828   LAZY_PS(ColoredQuadPS, ColoredQuad);
829   LAZY_PS(ColoredVertexPS, ColoredVertex);
830   LAZY_PS(ComponentAlphaQuadPS, ComponentAlphaQuad);
831   LAZY_PS(ComponentAlphaVertexPS, ComponentAlphaVertex);
832   LAZY_PS(TexturedVertexIMC4, TexturedVertexIMC4);
833   LAZY_PS(TexturedVertexNV12, TexturedVertexNV12);
834   LAZY_PS(TexturedQuadIMC4, TexturedQuadIMC4);
835   LAZY_PS(TexturedQuadNV12, TexturedQuadNV12);
836   LAZY_PS(BlendMultiplyPS, BlendMultiply);
837   LAZY_PS(BlendScreenPS, BlendScreen);
838   LAZY_PS(BlendOverlayPS, BlendOverlay);
839   LAZY_PS(BlendDarkenPS, BlendDarken);
840   LAZY_PS(BlendLightenPS, BlendLighten);
841   LAZY_PS(BlendColorDodgePS, BlendColorDodge);
842   LAZY_PS(BlendColorBurnPS, BlendColorBurn);
843   LAZY_PS(BlendHardLightPS, BlendHardLight);
844   LAZY_PS(BlendSoftLightPS, BlendSoftLight);
845   LAZY_PS(BlendDifferencePS, BlendDifference);
846   LAZY_PS(BlendExclusionPS, BlendExclusion);
847   LAZY_PS(BlendHuePS, BlendHue);
848   LAZY_PS(BlendSaturationPS, BlendSaturation);
849   LAZY_PS(BlendColorPS, BlendColor);
850   LAZY_PS(BlendLuminosityPS, BlendLuminosity);
851   LAZY_PS(ClearPS, Clear);
852   LAZY_PS(MaskCombinerPS, MaskCombiner);
853   LAZY_PS(DiagnosticTextPS, DiagnosticText);
854 #undef LAZY_PS
855 
856   // Define vertex shaders.
857 #define LAZY_VS(cxxName, enumName) \
858   mLazyVertexShaders[VertexShaderID::enumName] = &s##cxxName;
859   LAZY_VS(TexturedQuadVS, TexturedQuad);
860   LAZY_VS(TexturedVertexVS, TexturedVertex);
861   LAZY_VS(BlendVertexVS, BlendVertex);
862   LAZY_VS(ColoredQuadVS, ColoredQuad);
863   LAZY_VS(ColoredVertexVS, ColoredVertex);
864   LAZY_VS(ClearVS, Clear);
865   LAZY_VS(MaskCombinerVS, MaskCombiner);
866   LAZY_VS(DiagnosticTextVS, DiagnosticText);
867 #undef LAZY_VS
868 
869   // Force critical shaders to initialize early.
870   if (!InitPixelShader(PixelShaderID::TexturedQuadRGB) ||
871       !InitPixelShader(PixelShaderID::TexturedQuadRGBA) ||
872       !InitPixelShader(PixelShaderID::ColoredQuad) ||
873       !InitPixelShader(PixelShaderID::ComponentAlphaQuad) ||
874       !InitPixelShader(PixelShaderID::Clear) ||
875       !InitVertexShader(VertexShaderID::TexturedQuad) ||
876       !InitVertexShader(VertexShaderID::ColoredQuad) ||
877       !InitVertexShader(VertexShaderID::Clear)) {
878     return Fail("FEATURE_FAILURE_CRITICAL_SHADER_FAILURE");
879   }
880 
881   // Common unit quad layout: vPos, vRect, vLayerIndex, vDepth
882 #define BASE_UNIT_QUAD_LAYOUT                                                  \
883   {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, \
884    0},                                                                         \
885       {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT,                          \
886        1,          0, D3D11_INPUT_PER_INSTANCE_DATA,                           \
887        1},                                                                     \
888       {"TEXCOORD",                                                             \
889        1,                                                                      \
890        DXGI_FORMAT_R32_UINT,                                                   \
891        1,                                                                      \
892        D3D11_APPEND_ALIGNED_ELEMENT,                                           \
893        D3D11_INPUT_PER_INSTANCE_DATA,                                          \
894        1},                                                                     \
895   {                                                                            \
896     "TEXCOORD", 2, DXGI_FORMAT_R32_SINT, 1, D3D11_APPEND_ALIGNED_ELEMENT,      \
897         D3D11_INPUT_PER_INSTANCE_DATA, 1                                       \
898   }
899 
900   // Common unit triangle layout: vUnitPos, vPos1-3, vLayerIndex, vDepth
901 #define BASE_UNIT_TRIANGLE_LAYOUT                    \
902   {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,       \
903    0,          0, D3D11_INPUT_PER_VERTEX_DATA,       \
904    0},                                               \
905       {"POSITION", 1, DXGI_FORMAT_R32G32_FLOAT,      \
906        1,          0, D3D11_INPUT_PER_INSTANCE_DATA, \
907        1},                                           \
908       {"POSITION",                                   \
909        2,                                            \
910        DXGI_FORMAT_R32G32_FLOAT,                     \
911        1,                                            \
912        D3D11_APPEND_ALIGNED_ELEMENT,                 \
913        D3D11_INPUT_PER_INSTANCE_DATA,                \
914        1},                                           \
915       {"POSITION",                                   \
916        3,                                            \
917        DXGI_FORMAT_R32G32_FLOAT,                     \
918        1,                                            \
919        D3D11_APPEND_ALIGNED_ELEMENT,                 \
920        D3D11_INPUT_PER_INSTANCE_DATA,                \
921        1},                                           \
922       {"TEXCOORD",                                   \
923        0,                                            \
924        DXGI_FORMAT_R32_UINT,                         \
925        1,                                            \
926        D3D11_APPEND_ALIGNED_ELEMENT,                 \
927        D3D11_INPUT_PER_INSTANCE_DATA,                \
928        1},                                           \
929       {"TEXCOORD",                                   \
930        1,                                            \
931        DXGI_FORMAT_R32_SINT,                         \
932        1,                                            \
933        D3D11_APPEND_ALIGNED_ELEMENT,                 \
934        D3D11_INPUT_PER_INSTANCE_DATA,                \
935        1}
936 
937   // Initialize input layouts.
938   {
939     D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
940         BASE_UNIT_QUAD_LAYOUT,
941         // vTexRect
942         {"TEXCOORD", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
943          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
944     if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
945                          sTexturedQuadVS, VertexShaderID::TexturedQuad)) {
946       return Fail("FEATURE_FAILURE_UNIT_QUAD_TEXTURED_LAYOUT");
947     }
948   }
949   {
950     D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
951         BASE_UNIT_QUAD_LAYOUT,
952         // vColor
953         {"TEXCOORD", 3, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
954          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
955     if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc), sColoredQuadVS,
956                          VertexShaderID::ColoredQuad)) {
957       return Fail("FEATURE_FAILURE_UNIT_QUAD_COLORED_LAYOUT");
958     }
959   }
960   {
961     D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
962         BASE_UNIT_TRIANGLE_LAYOUT,
963         // vTexCoord1, vTexCoord2, vTexCoord3
964         {"TEXCOORD", 2, DXGI_FORMAT_R32G32_FLOAT, 1,
965          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
966         {"TEXCOORD", 3, DXGI_FORMAT_R32G32_FLOAT, 1,
967          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
968         {"TEXCOORD", 4, DXGI_FORMAT_R32G32_FLOAT, 1,
969          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
970     if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
971                          sTexturedVertexVS, VertexShaderID::TexturedVertex)) {
972       return Fail("FEATURE_FAILURE_TEXTURED_INPUT_LAYOUT");
973     }
974     // Propagate the input layout to other vertex shaders that use the same.
975     mInputLayouts[VertexShaderID::BlendVertex] =
976         mInputLayouts[VertexShaderID::TexturedVertex];
977   }
978   {
979     D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
980         BASE_UNIT_TRIANGLE_LAYOUT,
981         {"TEXCOORD", 2, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
982          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
983     if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
984                          sColoredVertexVS, VertexShaderID::ColoredVertex)) {
985       return Fail("FEATURE_FAILURE_COLORED_INPUT_LAYOUT");
986     }
987   }
988 
989 #undef BASE_UNIT_QUAD_LAYOUT
990 #undef BASE_UNIT_TRIANGLE_LAYOUT
991 
992   // Ancillary shaders that are not used for batching.
993   {
994     D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
995         // vPos
996         {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
997          D3D11_INPUT_PER_VERTEX_DATA, 0},
998         // vRect
999         {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_SINT, 1, 0,
1000          D3D11_INPUT_PER_INSTANCE_DATA, 1},
1001         // vDepth
1002         {"TEXCOORD", 1, DXGI_FORMAT_R32_SINT, 1, D3D11_APPEND_ALIGNED_ELEMENT,
1003          D3D11_INPUT_PER_INSTANCE_DATA, 1},
1004     };
1005     if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc), sClearVS,
1006                          VertexShaderID::Clear)) {
1007       return Fail("FEATURE_FAILURE_CLEAR_INPUT_LAYOUT");
1008     }
1009   }
1010   {
1011     D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
1012         // vPos
1013         {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
1014          D3D11_INPUT_PER_VERTEX_DATA, 0},
1015         // vTexCoords
1016         {"POSITION", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
1017          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1}};
1018     if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
1019                          sMaskCombinerVS, VertexShaderID::MaskCombiner)) {
1020       return Fail("FEATURE_FAILURE_MASK_COMBINER_INPUT_LAYOUT");
1021     }
1022   }
1023   {
1024     D3D11_INPUT_ELEMENT_DESC inputDesc[] = {
1025         // vPos
1026         {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0,
1027          D3D11_INPUT_PER_VERTEX_DATA, 0},
1028         // vRect
1029         {"TEXCOORD", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 1, 0,
1030          D3D11_INPUT_PER_INSTANCE_DATA, 1},
1031         // vTexCoords
1032         {"TEXCOORD", 1, DXGI_FORMAT_R32G32B32A32_FLOAT, 1,
1033          D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_INSTANCE_DATA, 1},
1034     };
1035     if (!InitInputLayout(inputDesc, MOZ_ARRAY_LENGTH(inputDesc),
1036                          sDiagnosticTextVS, VertexShaderID::DiagnosticText)) {
1037       return Fail("FEATURE_FAILURE_DIAGNOSTIC_INPUT_LAYOUT");
1038     }
1039   }
1040 
1041   if (!InitRasterizerStates() || !InitDepthStencilState() ||
1042       !InitBlendStates() || !InitSamplerStates() || !InitSyncObject()) {
1043     return false;
1044   }
1045 
1046   mCtx->RSSetState(mRasterizerStateNoScissor);
1047 
1048   return MLGDevice::Initialize();
1049 }
1050 
InitPixelShader(PixelShaderID aShaderID)1051 bool MLGDeviceD3D11::InitPixelShader(PixelShaderID aShaderID) {
1052   const ShaderBytes* code = mLazyPixelShaders[aShaderID];
1053   HRESULT hr =
1054       mDevice->CreatePixelShader(code->mData, code->mLength, nullptr,
1055                                  getter_AddRefs(mPixelShaders[aShaderID]));
1056   if (FAILED(hr)) {
1057     gfxCriticalNote << "Could not create pixel shader "
1058                     << hexa(unsigned(aShaderID)) << ": " << hexa(hr);
1059     return false;
1060   }
1061   return true;
1062 }
1063 
InitRasterizerStates()1064 bool MLGDeviceD3D11::InitRasterizerStates() {
1065   {
1066     CD3D11_RASTERIZER_DESC desc = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
1067     desc.CullMode = D3D11_CULL_NONE;
1068     desc.FillMode = D3D11_FILL_SOLID;
1069     desc.ScissorEnable = TRUE;
1070     HRESULT hr = mDevice->CreateRasterizerState(
1071         &desc, getter_AddRefs(mRasterizerStateScissor));
1072     if (FAILED(hr)) {
1073       return Fail("FEATURE_FAILURE_SCISSOR_RASTERIZER",
1074                   "Could not create scissor rasterizer (%x)", hr);
1075     }
1076   }
1077   {
1078     CD3D11_RASTERIZER_DESC desc = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT());
1079     desc.CullMode = D3D11_CULL_NONE;
1080     desc.FillMode = D3D11_FILL_SOLID;
1081     HRESULT hr = mDevice->CreateRasterizerState(
1082         &desc, getter_AddRefs(mRasterizerStateNoScissor));
1083     if (FAILED(hr)) {
1084       return Fail("FEATURE_FAILURE_DEFAULT_RASTERIZER",
1085                   "Could not create default rasterizer (%x)", hr);
1086     }
1087   }
1088   return true;
1089 }
1090 
InitSamplerStates()1091 bool MLGDeviceD3D11::InitSamplerStates() {
1092   {
1093     CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
1094     HRESULT hr = mDevice->CreateSamplerState(
1095         &desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearClamp]));
1096     if (FAILED(hr)) {
1097       return Fail("FEATURE_FAILURE_LINEAR_CLAMP_SAMPLER",
1098                   "Could not create linear clamp sampler (%x)", hr);
1099     }
1100   }
1101   {
1102     CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
1103     desc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
1104     desc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
1105     desc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
1106     memset(desc.BorderColor, 0, sizeof(desc.BorderColor));
1107     HRESULT hr = mDevice->CreateSamplerState(
1108         &desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearClampToZero]));
1109     if (FAILED(hr)) {
1110       return Fail("FEATURE_FAILURE_LINEAR_CLAMP_ZERO_SAMPLER",
1111                   "Could not create linear clamp to zero sampler (%x)", hr);
1112     }
1113   }
1114   {
1115     CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
1116     desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
1117     desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
1118     desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
1119     HRESULT hr = mDevice->CreateSamplerState(
1120         &desc, getter_AddRefs(mSamplerStates[SamplerMode::LinearRepeat]));
1121     if (FAILED(hr)) {
1122       return Fail("FEATURE_FAILURE_LINEAR_CLAMP_ZERO_SAMPLER",
1123                   "Could not create linear clamp to zero sampler (%x)", hr);
1124     }
1125   }
1126 
1127   {
1128     CD3D11_SAMPLER_DESC desc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT());
1129     desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
1130     HRESULT hr = mDevice->CreateSamplerState(
1131         &desc, getter_AddRefs(mSamplerStates[SamplerMode::Point]));
1132     if (FAILED(hr)) {
1133       return Fail("FEATURE_FAILURE_POINT_SAMPLER",
1134                   "Could not create point sampler (%x)", hr);
1135     }
1136   }
1137   return true;
1138 }
1139 
InitBlendStates()1140 bool MLGDeviceD3D11::InitBlendStates() {
1141   {
1142     CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
1143     HRESULT hr = mDevice->CreateBlendState(
1144         &desc, getter_AddRefs(mBlendStates[MLGBlendState::Copy]));
1145     if (FAILED(hr)) {
1146       return Fail("FEATURE_FAILURE_COPY_BLEND_STATE",
1147                   "Could not create copy blend state (%x)", hr);
1148     }
1149   }
1150 
1151   {
1152     CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
1153     desc.RenderTarget[0].BlendEnable = TRUE;
1154     desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
1155     desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
1156     desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
1157     desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
1158     desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
1159     desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
1160     HRESULT hr = mDevice->CreateBlendState(
1161         &desc, getter_AddRefs(mBlendStates[MLGBlendState::Over]));
1162     if (FAILED(hr)) {
1163       return Fail("FEATURE_FAILURE_OVER_BLEND_STATE",
1164                   "Could not create over blend state (%x)", hr);
1165     }
1166   }
1167 
1168   {
1169     CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
1170     desc.RenderTarget[0].BlendEnable = TRUE;
1171     desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
1172     desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
1173     desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
1174     desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
1175     desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
1176     desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
1177     HRESULT hr = mDevice->CreateBlendState(
1178         &desc, getter_AddRefs(mBlendStates[MLGBlendState::OverAndPremultiply]));
1179     if (FAILED(hr)) {
1180       return Fail("FEATURE_FAILURE_OVER_BLEND_STATE",
1181                   "Could not create over blend state (%x)", hr);
1182     }
1183   }
1184 
1185   {
1186     CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
1187     desc.RenderTarget[0].BlendEnable = TRUE;
1188     desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
1189     desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE;
1190     desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_MIN;
1191     desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
1192     desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
1193     desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_MIN;
1194     HRESULT hr = mDevice->CreateBlendState(
1195         &desc, getter_AddRefs(mBlendStates[MLGBlendState::Min]));
1196     if (FAILED(hr)) {
1197       return Fail("FEATURE_FAILURE_MIN_BLEND_STATE",
1198                   "Could not create min blend state (%x)", hr);
1199     }
1200   }
1201 
1202   {
1203     CD3D11_BLEND_DESC desc = CD3D11_BLEND_DESC(CD3D11_DEFAULT());
1204     desc.RenderTarget[0].BlendEnable = TRUE;
1205     desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
1206     desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC1_COLOR;
1207     desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
1208     desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
1209     desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
1210     desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
1211     HRESULT hr = mDevice->CreateBlendState(
1212         &desc, getter_AddRefs(mBlendStates[MLGBlendState::ComponentAlpha]));
1213     if (FAILED(hr)) {
1214       return Fail("FEATURE_FAILURE_COMPONENT_ALPHA_BLEND_STATE",
1215                   "Could not create component alpha blend state (%x)", hr);
1216     }
1217   }
1218   return true;
1219 }
1220 
InitDepthStencilState()1221 bool MLGDeviceD3D11::InitDepthStencilState() {
1222   D3D11_DEPTH_STENCIL_DESC desc = CD3D11_DEPTH_STENCIL_DESC(D3D11_DEFAULT);
1223 
1224   HRESULT hr = mDevice->CreateDepthStencilState(
1225       &desc, getter_AddRefs(mDepthStencilStates[MLGDepthTestMode::Write]));
1226   if (FAILED(hr)) {
1227     return Fail("FEATURE_FAILURE_WRITE_DEPTH_STATE",
1228                 "Could not create write depth stencil state (%x)", hr);
1229   }
1230 
1231   desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
1232   hr = mDevice->CreateDepthStencilState(
1233       &desc, getter_AddRefs(mDepthStencilStates[MLGDepthTestMode::ReadOnly]));
1234   if (FAILED(hr)) {
1235     return Fail("FEATURE_FAILURE_READ_DEPTH_STATE",
1236                 "Could not create read depth stencil state (%x)", hr);
1237   }
1238 
1239   desc.DepthEnable = FALSE;
1240   hr = mDevice->CreateDepthStencilState(
1241       &desc, getter_AddRefs(mDepthStencilStates[MLGDepthTestMode::Disabled]));
1242   if (FAILED(hr)) {
1243     return Fail("FEATURE_FAILURE_DISABLED_DEPTH_STATE",
1244                 "Could not create disabled depth stencil state (%x)", hr);
1245   }
1246 
1247   desc = CD3D11_DEPTH_STENCIL_DESC(D3D11_DEFAULT);
1248   desc.DepthFunc = D3D11_COMPARISON_ALWAYS;
1249   hr = mDevice->CreateDepthStencilState(
1250       &desc,
1251       getter_AddRefs(mDepthStencilStates[MLGDepthTestMode::AlwaysWrite]));
1252   if (FAILED(hr)) {
1253     return Fail("FEATURE_FAILURE_WRITE_DEPTH_STATE",
1254                 "Could not create always-write depth stencil state (%x)", hr);
1255   }
1256 
1257   return true;
1258 }
1259 
InitVertexShader(VertexShaderID aShaderID)1260 bool MLGDeviceD3D11::InitVertexShader(VertexShaderID aShaderID) {
1261   const ShaderBytes* code = mLazyVertexShaders[aShaderID];
1262   HRESULT hr =
1263       mDevice->CreateVertexShader(code->mData, code->mLength, nullptr,
1264                                   getter_AddRefs(mVertexShaders[aShaderID]));
1265   if (FAILED(hr)) {
1266     gfxCriticalNote << "Could not create vertex shader "
1267                     << hexa(unsigned(aShaderID)) << ": " << hexa(hr);
1268     return false;
1269   }
1270   return true;
1271 }
1272 
InitInputLayout(D3D11_INPUT_ELEMENT_DESC * aDesc,size_t aNumElements,const ShaderBytes & aCode,VertexShaderID aShaderID)1273 bool MLGDeviceD3D11::InitInputLayout(D3D11_INPUT_ELEMENT_DESC* aDesc,
1274                                      size_t aNumElements,
1275                                      const ShaderBytes& aCode,
1276                                      VertexShaderID aShaderID) {
1277   HRESULT hr = mDevice->CreateInputLayout(
1278       aDesc, aNumElements, aCode.mData, aCode.mLength,
1279       getter_AddRefs(mInputLayouts[aShaderID]));
1280   if (FAILED(hr)) {
1281     gfxCriticalNote << "Could not create input layout for shader "
1282                     << hexa(unsigned(aShaderID)) << ": " << hexa(hr);
1283     return false;
1284   }
1285   return true;
1286 }
1287 
GetTextureFactoryIdentifier(widget::CompositorWidget * aWidget) const1288 TextureFactoryIdentifier MLGDeviceD3D11::GetTextureFactoryIdentifier(
1289     widget::CompositorWidget* aWidget) const {
1290   TextureFactoryIdentifier ident(GetLayersBackend(), XRE_GetProcessType(),
1291                                  GetMaxTextureSize());
1292   if (aWidget) {
1293     ident.mUseCompositorWnd = !!aWidget->AsWindows()->GetCompositorHwnd();
1294   }
1295   if (mSyncObject) {
1296     ident.mSyncHandle = mSyncObject->GetSyncHandle();
1297   }
1298 
1299   return ident;
1300 }
1301 
GetMaxTextureSizeForFeatureLevel1(D3D_FEATURE_LEVEL aFeatureLevel)1302 inline uint32_t GetMaxTextureSizeForFeatureLevel1(
1303     D3D_FEATURE_LEVEL aFeatureLevel) {
1304   int32_t maxTextureSize;
1305   switch (aFeatureLevel) {
1306     case D3D_FEATURE_LEVEL_11_1:
1307     case D3D_FEATURE_LEVEL_11_0:
1308       maxTextureSize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
1309       break;
1310     case D3D_FEATURE_LEVEL_10_1:
1311     case D3D_FEATURE_LEVEL_10_0:
1312       maxTextureSize = D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
1313       break;
1314     case D3D_FEATURE_LEVEL_9_3:
1315       maxTextureSize = D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION;
1316       break;
1317     default:
1318       maxTextureSize = D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION;
1319   }
1320   return maxTextureSize;
1321 }
1322 
GetLayersBackend() const1323 LayersBackend MLGDeviceD3D11::GetLayersBackend() const {
1324   return LayersBackend::LAYERS_D3D11;
1325 }
1326 
GetMaxTextureSize() const1327 int32_t MLGDeviceD3D11::GetMaxTextureSize() const {
1328   return GetMaxTextureSizeForFeatureLevel1(mDevice->GetFeatureLevel());
1329 }
1330 
CreateSwapChainForWidget(widget::CompositorWidget * aWidget)1331 RefPtr<MLGSwapChain> MLGDeviceD3D11::CreateSwapChainForWidget(
1332     widget::CompositorWidget* aWidget) {
1333   return MLGSwapChainD3D11::Create(this, mDevice, aWidget);
1334 }
1335 
CreateDataTextureSource(TextureFlags aFlags)1336 RefPtr<DataTextureSource> MLGDeviceD3D11::CreateDataTextureSource(
1337     TextureFlags aFlags) {
1338   return new DataTextureSourceD3D11(mDevice, gfx::SurfaceFormat::UNKNOWN,
1339                                     aFlags);
1340 }
1341 
ToD3D11Map(MLGMapType aType)1342 static inline D3D11_MAP ToD3D11Map(MLGMapType aType) {
1343   switch (aType) {
1344     case MLGMapType::READ:
1345       return D3D11_MAP_READ;
1346     case MLGMapType::READ_WRITE:
1347       return D3D11_MAP_READ_WRITE;
1348     case MLGMapType::WRITE:
1349       return D3D11_MAP_WRITE;
1350     case MLGMapType::WRITE_DISCARD:
1351       return D3D11_MAP_WRITE_DISCARD;
1352   }
1353   return D3D11_MAP_WRITE;
1354 }
1355 
Map(MLGResource * aResource,MLGMapType aType,MLGMappedResource * aMap)1356 bool MLGDeviceD3D11::Map(MLGResource* aResource, MLGMapType aType,
1357                          MLGMappedResource* aMap) {
1358   ID3D11Resource* resource = aResource->AsResourceD3D11()->GetResource();
1359   MOZ_ASSERT(resource);
1360 
1361   D3D11_MAPPED_SUBRESOURCE map;
1362   HRESULT hr = mCtx->Map(resource, 0, ToD3D11Map(aType), 0, &map);
1363 
1364   if (FAILED(hr)) {
1365     gfxWarning() << "Could not map MLG resource: " << hexa(hr);
1366     return false;
1367   }
1368 
1369   aMap->mData = reinterpret_cast<uint8_t*>(map.pData);
1370   aMap->mStride = map.RowPitch;
1371   return true;
1372 }
1373 
Unmap(MLGResource * aResource)1374 void MLGDeviceD3D11::Unmap(MLGResource* aResource) {
1375   ID3D11Resource* resource = aResource->AsResourceD3D11()->GetResource();
1376   mCtx->Unmap(resource, 0);
1377 }
1378 
UpdatePartialResource(MLGResource * aResource,const gfx::IntRect * aRect,void * aData,uint32_t aStride)1379 void MLGDeviceD3D11::UpdatePartialResource(MLGResource* aResource,
1380                                            const gfx::IntRect* aRect,
1381                                            void* aData, uint32_t aStride) {
1382   D3D11_BOX box;
1383   if (aRect) {
1384     box = RectToBox(*aRect);
1385   }
1386 
1387   ID3D11Resource* resource = aResource->AsResourceD3D11()->GetResource();
1388   mCtx->UpdateSubresource(resource, 0, aRect ? &box : nullptr, aData, aStride,
1389                           0);
1390 }
1391 
SetRenderTarget(MLGRenderTarget * aRT)1392 void MLGDeviceD3D11::SetRenderTarget(MLGRenderTarget* aRT) {
1393   ID3D11RenderTargetView* rtv = nullptr;
1394   ID3D11DepthStencilView* dsv = nullptr;
1395 
1396   if (aRT) {
1397     MLGRenderTargetD3D11* rt = aRT->AsD3D11();
1398     rtv = rt->GetRenderTargetView();
1399     dsv = rt->GetDSV();
1400   }
1401 
1402   mCtx->OMSetRenderTargets(1, &rtv, dsv);
1403   mCurrentRT = aRT;
1404 }
1405 
GetRenderTarget()1406 MLGRenderTarget* MLGDeviceD3D11::GetRenderTarget() { return mCurrentRT; }
1407 
SetViewport(const gfx::IntRect & aViewport)1408 void MLGDeviceD3D11::SetViewport(const gfx::IntRect& aViewport) {
1409   D3D11_VIEWPORT vp;
1410   vp.MaxDepth = 1.0f;
1411   vp.MinDepth = 0.0f;
1412   vp.TopLeftX = aViewport.X();
1413   vp.TopLeftY = aViewport.Y();
1414   vp.Width = aViewport.Width();
1415   vp.Height = aViewport.Height();
1416   mCtx->RSSetViewports(1, &vp);
1417 }
1418 
ToD3D11Rect(const gfx::IntRect & aRect)1419 static inline D3D11_RECT ToD3D11Rect(const gfx::IntRect& aRect) {
1420   D3D11_RECT rect;
1421   rect.left = aRect.X();
1422   rect.top = aRect.Y();
1423   rect.right = aRect.XMost();
1424   rect.bottom = aRect.YMost();
1425   return rect;
1426 }
1427 
SetScissorRect(const Maybe<gfx::IntRect> & aScissorRect)1428 void MLGDeviceD3D11::SetScissorRect(const Maybe<gfx::IntRect>& aScissorRect) {
1429   if (!aScissorRect) {
1430     if (mScissored) {
1431       mCtx->RSSetState(mRasterizerStateNoScissor);
1432       mScissored = false;
1433     }
1434     return;
1435   }
1436   D3D11_RECT rect = ToD3D11Rect(aScissorRect.value());
1437   mCtx->RSSetScissorRects(1, &rect);
1438   if (!mScissored) {
1439     mScissored = true;
1440     mCtx->RSSetState(mRasterizerStateScissor);
1441   }
1442 }
1443 
SetVertexShader(VertexShaderID aShader)1444 void MLGDeviceD3D11::SetVertexShader(VertexShaderID aShader) {
1445   if (!mVertexShaders[aShader]) {
1446     InitVertexShader(aShader);
1447     MOZ_ASSERT(mInputLayouts[aShader]);
1448   }
1449   SetVertexShader(mVertexShaders[aShader]);
1450   SetInputLayout(mInputLayouts[aShader]);
1451 }
1452 
SetInputLayout(ID3D11InputLayout * aLayout)1453 void MLGDeviceD3D11::SetInputLayout(ID3D11InputLayout* aLayout) {
1454   if (mCurrentInputLayout == aLayout) {
1455     return;
1456   }
1457   mCtx->IASetInputLayout(aLayout);
1458   mCurrentInputLayout = aLayout;
1459 }
1460 
SetVertexShader(ID3D11VertexShader * aShader)1461 void MLGDeviceD3D11::SetVertexShader(ID3D11VertexShader* aShader) {
1462   if (mCurrentVertexShader == aShader) {
1463     return;
1464   }
1465   mCtx->VSSetShader(aShader, nullptr, 0);
1466   mCurrentVertexShader = aShader;
1467 }
1468 
SetPixelShader(PixelShaderID aShader)1469 void MLGDeviceD3D11::SetPixelShader(PixelShaderID aShader) {
1470   if (!mPixelShaders[aShader]) {
1471     InitPixelShader(aShader);
1472   }
1473   if (mCurrentPixelShader != mPixelShaders[aShader]) {
1474     mCtx->PSSetShader(mPixelShaders[aShader], nullptr, 0);
1475     mCurrentPixelShader = mPixelShaders[aShader];
1476   }
1477 }
1478 
SetSamplerMode(uint32_t aIndex,SamplerMode aMode)1479 void MLGDeviceD3D11::SetSamplerMode(uint32_t aIndex, SamplerMode aMode) {
1480   ID3D11SamplerState* sampler = mSamplerStates[aMode];
1481   mCtx->PSSetSamplers(aIndex, 1, &sampler);
1482 }
1483 
SetBlendState(MLGBlendState aState)1484 void MLGDeviceD3D11::SetBlendState(MLGBlendState aState) {
1485   if (mCurrentBlendState != mBlendStates[aState]) {
1486     FLOAT blendFactor[4] = {0, 0, 0, 0};
1487     mCtx->OMSetBlendState(mBlendStates[aState], blendFactor, 0xFFFFFFFF);
1488     mCurrentBlendState = mBlendStates[aState];
1489   }
1490 }
1491 
SetVertexBuffer(uint32_t aSlot,MLGBuffer * aBuffer,uint32_t aStride,uint32_t aOffset)1492 void MLGDeviceD3D11::SetVertexBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
1493                                      uint32_t aStride, uint32_t aOffset) {
1494   ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
1495   mCtx->IASetVertexBuffers(aSlot, 1, &buffer, &aStride, &aOffset);
1496 }
1497 
SetVSConstantBuffer(uint32_t aSlot,MLGBuffer * aBuffer)1498 void MLGDeviceD3D11::SetVSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer) {
1499   MOZ_ASSERT(aSlot < kMaxVertexShaderConstantBuffers);
1500 
1501   ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
1502   mCtx->VSSetConstantBuffers(aSlot, 1, &buffer);
1503 }
1504 
SetPSConstantBuffer(uint32_t aSlot,MLGBuffer * aBuffer)1505 void MLGDeviceD3D11::SetPSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer) {
1506   MOZ_ASSERT(aSlot < kMaxPixelShaderConstantBuffers);
1507 
1508   ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
1509   mCtx->PSSetConstantBuffers(aSlot, 1, &buffer);
1510 }
1511 
SetVSConstantBuffer(uint32_t aSlot,MLGBuffer * aBuffer,uint32_t aFirstConstant,uint32_t aNumConstants)1512 void MLGDeviceD3D11::SetVSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
1513                                          uint32_t aFirstConstant,
1514                                          uint32_t aNumConstants) {
1515   MOZ_ASSERT(aSlot < kMaxVertexShaderConstantBuffers);
1516   MOZ_ASSERT(mCanUseConstantBufferOffsetBinding);
1517   MOZ_ASSERT(mCtx1);
1518   MOZ_ASSERT(aFirstConstant % 16 == 0);
1519 
1520   ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
1521   mCtx1->VSSetConstantBuffers1(aSlot, 1, &buffer, &aFirstConstant,
1522                                &aNumConstants);
1523 }
1524 
SetPSConstantBuffer(uint32_t aSlot,MLGBuffer * aBuffer,uint32_t aFirstConstant,uint32_t aNumConstants)1525 void MLGDeviceD3D11::SetPSConstantBuffer(uint32_t aSlot, MLGBuffer* aBuffer,
1526                                          uint32_t aFirstConstant,
1527                                          uint32_t aNumConstants) {
1528   MOZ_ASSERT(aSlot < kMaxPixelShaderConstantBuffers);
1529   MOZ_ASSERT(mCanUseConstantBufferOffsetBinding);
1530   MOZ_ASSERT(mCtx1);
1531   MOZ_ASSERT(aFirstConstant % 16 == 0);
1532 
1533   ID3D11Buffer* buffer = aBuffer ? aBuffer->AsD3D11()->GetBuffer() : nullptr;
1534   mCtx1->PSSetConstantBuffers1(aSlot, 1, &buffer, &aFirstConstant,
1535                                &aNumConstants);
1536 }
1537 
SetPrimitiveTopology(MLGPrimitiveTopology aTopology)1538 void MLGDeviceD3D11::SetPrimitiveTopology(MLGPrimitiveTopology aTopology) {
1539   D3D11_PRIMITIVE_TOPOLOGY topology;
1540   switch (aTopology) {
1541     case MLGPrimitiveTopology::TriangleStrip:
1542       topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
1543       break;
1544     case MLGPrimitiveTopology::TriangleList:
1545       topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
1546       break;
1547     case MLGPrimitiveTopology::UnitQuad:
1548       SetVertexBuffer(0, mUnitQuadVB, sizeof(float) * 2, 0);
1549       topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
1550       break;
1551     case MLGPrimitiveTopology::UnitTriangle:
1552       SetVertexBuffer(0, mUnitTriangleVB, sizeof(float) * 3, 0);
1553       topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
1554       break;
1555     default:
1556       MOZ_ASSERT_UNREACHABLE("Unknown topology");
1557       topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;
1558       break;
1559   }
1560 
1561   mCtx->IASetPrimitiveTopology(topology);
1562 }
1563 
CreateBuffer(MLGBufferType aType,uint32_t aSize,MLGUsage aUsage,const void * aInitialData)1564 RefPtr<MLGBuffer> MLGDeviceD3D11::CreateBuffer(MLGBufferType aType,
1565                                                uint32_t aSize, MLGUsage aUsage,
1566                                                const void* aInitialData) {
1567   return MLGBufferD3D11::Create(mDevice, aType, aSize, aUsage, aInitialData);
1568 }
1569 
CreateRenderTarget(const gfx::IntSize & aSize,MLGRenderTargetFlags aFlags)1570 RefPtr<MLGRenderTarget> MLGDeviceD3D11::CreateRenderTarget(
1571     const gfx::IntSize& aSize, MLGRenderTargetFlags aFlags) {
1572   RefPtr<MLGRenderTargetD3D11> rt = new MLGRenderTargetD3D11(aSize, aFlags);
1573   if (!rt->Initialize(mDevice)) {
1574     return nullptr;
1575   }
1576   return rt;
1577 }
1578 
Clear(MLGRenderTarget * aRT,const gfx::DeviceColor & aColor)1579 void MLGDeviceD3D11::Clear(MLGRenderTarget* aRT,
1580                            const gfx::DeviceColor& aColor) {
1581   MLGRenderTargetD3D11* rt = aRT->AsD3D11();
1582   FLOAT rgba[4] = {aColor.r, aColor.g, aColor.b, aColor.a};
1583   mCtx->ClearRenderTargetView(rt->GetRenderTargetView(), rgba);
1584   if (ID3D11DepthStencilView* dsv = rt->GetDSV()) {
1585     mCtx->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH, 1.0, 0);
1586   }
1587 }
1588 
ClearDepthBuffer(MLGRenderTarget * aRT)1589 void MLGDeviceD3D11::ClearDepthBuffer(MLGRenderTarget* aRT) {
1590   MLGRenderTargetD3D11* rt = aRT->AsD3D11();
1591   if (ID3D11DepthStencilView* dsv = rt->GetDSV()) {
1592     mCtx->ClearDepthStencilView(dsv, D3D11_CLEAR_DEPTH, 1.0, 0);
1593   }
1594 }
1595 
ClearView(MLGRenderTarget * aRT,const DeviceColor & aColor,const IntRect * aRects,size_t aNumRects)1596 void MLGDeviceD3D11::ClearView(MLGRenderTarget* aRT, const DeviceColor& aColor,
1597                                const IntRect* aRects, size_t aNumRects) {
1598   MOZ_ASSERT(mCanUseClearView);
1599   MOZ_ASSERT(mCtx1);
1600 
1601   MLGRenderTargetD3D11* rt = aRT->AsD3D11();
1602   FLOAT rgba[4] = {aColor.r, aColor.g, aColor.b, aColor.a};
1603 
1604   StackArray<D3D11_RECT, 8> rects(aNumRects);
1605   for (size_t i = 0; i < aNumRects; i++) {
1606     rects[i] = ToD3D11Rect(aRects[i]);
1607   }
1608 
1609   // Batch ClearView calls since too many will crash NVIDIA drivers.
1610   size_t remaining = aNumRects;
1611   size_t cursor = 0;
1612   while (remaining > 0) {
1613     size_t amount = std::min(remaining, kMaxClearViewRects);
1614     mCtx1->ClearView(rt->GetRenderTargetView(), rgba, rects.data() + cursor,
1615                      amount);
1616 
1617     remaining -= amount;
1618     cursor += amount;
1619   }
1620 }
1621 
Draw(uint32_t aVertexCount,uint32_t aOffset)1622 void MLGDeviceD3D11::Draw(uint32_t aVertexCount, uint32_t aOffset) {
1623   mCtx->Draw(aVertexCount, aOffset);
1624 }
1625 
DrawInstanced(uint32_t aVertexCountPerInstance,uint32_t aInstanceCount,uint32_t aVertexOffset,uint32_t aInstanceOffset)1626 void MLGDeviceD3D11::DrawInstanced(uint32_t aVertexCountPerInstance,
1627                                    uint32_t aInstanceCount,
1628                                    uint32_t aVertexOffset,
1629                                    uint32_t aInstanceOffset) {
1630   mCtx->DrawInstanced(aVertexCountPerInstance, aInstanceCount, aVertexOffset,
1631                       aInstanceOffset);
1632 }
1633 
SetPSTextures(uint32_t aSlot,uint32_t aNumTextures,TextureSource * const * aTextures)1634 void MLGDeviceD3D11::SetPSTextures(uint32_t aSlot, uint32_t aNumTextures,
1635                                    TextureSource* const* aTextures) {
1636   // TextureSource guarantees that the ID3D11ShaderResourceView will be cached,
1637   // so we don't hold a RefPtr here.
1638   StackArray<ID3D11ShaderResourceView*, 3> views(aNumTextures);
1639 
1640   for (size_t i = 0; i < aNumTextures; i++) {
1641     views[i] = ResolveTextureSourceForShader(aTextures[i]);
1642   }
1643 
1644   mCtx->PSSetShaderResources(aSlot, aNumTextures, views.data());
1645 }
1646 
ResolveTextureSourceForShader(TextureSource * aTexture)1647 ID3D11ShaderResourceView* MLGDeviceD3D11::ResolveTextureSourceForShader(
1648     TextureSource* aTexture) {
1649   if (!aTexture) {
1650     return nullptr;
1651   }
1652 
1653   if (TextureSourceD3D11* source = aTexture->AsSourceD3D11()) {
1654     ID3D11Texture2D* texture = source->GetD3D11Texture();
1655     if (!texture) {
1656       gfxWarning() << "No D3D11 texture present in SetPSTextures";
1657       return nullptr;
1658     }
1659 
1660     MaybeLockTexture(texture);
1661     return source->GetShaderResourceView();
1662   }
1663 
1664   gfxWarning() << "Unknown texture type in SetPSTextures";
1665   return nullptr;
1666 }
1667 
SetPSTexture(uint32_t aSlot,MLGTexture * aTexture)1668 void MLGDeviceD3D11::SetPSTexture(uint32_t aSlot, MLGTexture* aTexture) {
1669   RefPtr<ID3D11ShaderResourceView> view;
1670   if (aTexture) {
1671     MLGTextureD3D11* texture = aTexture->AsD3D11();
1672     view = texture->GetShaderResourceView();
1673   }
1674 
1675   ID3D11ShaderResourceView* viewPtr = view.get();
1676   mCtx->PSSetShaderResources(aSlot, 1, &viewPtr);
1677 }
1678 
MaybeLockTexture(ID3D11Texture2D * aTexture)1679 void MLGDeviceD3D11::MaybeLockTexture(ID3D11Texture2D* aTexture) {
1680   RefPtr<IDXGIKeyedMutex> mutex;
1681   HRESULT hr = aTexture->QueryInterface(__uuidof(IDXGIKeyedMutex),
1682                                         (void**)getter_AddRefs(mutex));
1683   if (FAILED(hr) || !mutex) {
1684     return;
1685   }
1686 
1687   hr = mutex->AcquireSync(0, 10000);
1688 
1689   if (hr == WAIT_TIMEOUT) {
1690     gfxDevCrash(LogReason::D3DLockTimeout) << "D3D lock mutex timeout";
1691     mLockAttemptedTextures.PutEntry(mutex);
1692   } else if (hr == WAIT_ABANDONED) {
1693     gfxCriticalNote << "GFX: D3D11 lock mutex abandoned";
1694     mLockAttemptedTextures.PutEntry(mutex);
1695   } else if (FAILED(hr)) {
1696     gfxCriticalNote << "D3D11 lock mutex failed: " << hexa(hr);
1697     mLockAttemptedTextures.PutEntry(mutex);
1698   } else {
1699     mLockedTextures.PutEntry(mutex);
1700   }
1701 }
1702 
SetPSTexturesNV12(uint32_t aSlot,TextureSource * aTexture)1703 void MLGDeviceD3D11::SetPSTexturesNV12(uint32_t aSlot,
1704                                        TextureSource* aTexture) {
1705   MOZ_ASSERT(aTexture->GetFormat() == SurfaceFormat::NV12 ||
1706              aTexture->GetFormat() == SurfaceFormat::P010 ||
1707              aTexture->GetFormat() == SurfaceFormat::P016);
1708 
1709   TextureSourceD3D11* source = aTexture->AsSourceD3D11();
1710   if (!source) {
1711     gfxWarning() << "Unknown texture type in SetPSCompoundTexture";
1712     return;
1713   }
1714 
1715   ID3D11Texture2D* texture = source->GetD3D11Texture();
1716   if (!texture) {
1717     gfxWarning() << "TextureSourceD3D11 does not have an ID3D11Texture";
1718     return;
1719   }
1720 
1721   MaybeLockTexture(texture);
1722 
1723   const bool isNV12 = aTexture->GetFormat() == SurfaceFormat::NV12;
1724 
1725   RefPtr<ID3D11ShaderResourceView> views[2];
1726   D3D11_SHADER_RESOURCE_VIEW_DESC desc = CD3D11_SHADER_RESOURCE_VIEW_DESC(
1727       D3D11_SRV_DIMENSION_TEXTURE2D,
1728       isNV12 ? DXGI_FORMAT_R8_UNORM : DXGI_FORMAT_R16_UNORM);
1729 
1730   HRESULT hr = mDevice->CreateShaderResourceView(texture, &desc,
1731                                                  getter_AddRefs(views[0]));
1732   if (FAILED(hr) || !views[0]) {
1733     gfxWarning() << "Could not bind an SRV for Y plane of NV12 texture: "
1734                  << hexa(hr);
1735     return;
1736   }
1737 
1738   desc.Format = isNV12 ? DXGI_FORMAT_R8G8_UNORM : DXGI_FORMAT_R16G16_UNORM;
1739   hr = mDevice->CreateShaderResourceView(texture, &desc,
1740                                          getter_AddRefs(views[1]));
1741   if (FAILED(hr) || !views[1]) {
1742     gfxWarning() << "Could not bind an SRV for CbCr plane of NV12 texture: "
1743                  << hexa(hr);
1744     return;
1745   }
1746 
1747   ID3D11ShaderResourceView* bind[2] = {views[0], views[1]};
1748   mCtx->PSSetShaderResources(aSlot, 2, bind);
1749 }
1750 
InitSyncObject()1751 bool MLGDeviceD3D11::InitSyncObject() {
1752   MOZ_ASSERT(!mSyncObject);
1753   MOZ_ASSERT(mDevice);
1754 
1755   mSyncObject = SyncObjectHost::CreateSyncObjectHost(mDevice);
1756   MOZ_ASSERT(mSyncObject);
1757 
1758   return mSyncObject->Init();
1759 }
1760 
StartDiagnostics(uint32_t aInvalidPixels)1761 void MLGDeviceD3D11::StartDiagnostics(uint32_t aInvalidPixels) {
1762   mDiagnostics->Start(aInvalidPixels);
1763 }
1764 
EndDiagnostics()1765 void MLGDeviceD3D11::EndDiagnostics() { mDiagnostics->End(); }
1766 
GetDiagnostics(GPUStats * aStats)1767 void MLGDeviceD3D11::GetDiagnostics(GPUStats* aStats) {
1768   mDiagnostics->Query(aStats);
1769 }
1770 
Synchronize()1771 bool MLGDeviceD3D11::Synchronize() {
1772   MOZ_ASSERT(mSyncObject);
1773 
1774   if (mSyncObject) {
1775     if (!mSyncObject->Synchronize()) {
1776       // It's timeout or other error. Handle the device-reset here.
1777       HandleDeviceReset("SyncObject");
1778       return false;
1779     }
1780   }
1781 
1782   return true;
1783 }
1784 
UnlockAllTextures()1785 void MLGDeviceD3D11::UnlockAllTextures() {
1786   for (auto iter = mLockedTextures.Iter(); !iter.Done(); iter.Next()) {
1787     RefPtr<IDXGIKeyedMutex> mutex = iter.Get()->GetKey();
1788     mutex->ReleaseSync(0);
1789   }
1790   mLockedTextures.Clear();
1791   mLockAttemptedTextures.Clear();
1792 }
1793 
SetDepthTestMode(MLGDepthTestMode aMode)1794 void MLGDeviceD3D11::SetDepthTestMode(MLGDepthTestMode aMode) {
1795   mCtx->OMSetDepthStencilState(mDepthStencilStates[aMode], 0xffffffff);
1796 }
1797 
InsertPresentWaitQuery()1798 void MLGDeviceD3D11::InsertPresentWaitQuery() {
1799   CD3D11_QUERY_DESC desc(D3D11_QUERY_EVENT);
1800   HRESULT hr =
1801       mDevice->CreateQuery(&desc, getter_AddRefs(mNextWaitForPresentQuery));
1802   if (FAILED(hr) || !mNextWaitForPresentQuery) {
1803     gfxWarning() << "Could not create D3D11_QUERY_EVENT: " << hexa(hr);
1804     return;
1805   }
1806 
1807   mCtx->End(mNextWaitForPresentQuery);
1808 }
1809 
WaitForPreviousPresentQuery()1810 void MLGDeviceD3D11::WaitForPreviousPresentQuery() {
1811   if (mWaitForPresentQuery) {
1812     BOOL result;
1813     WaitForFrameGPUQuery(mDevice, mCtx, mWaitForPresentQuery, &result);
1814   }
1815   mWaitForPresentQuery = mNextWaitForPresentQuery.forget();
1816 }
1817 
Flush()1818 void MLGDeviceD3D11::Flush() { mCtx->Flush(); }
1819 
EndFrame()1820 void MLGDeviceD3D11::EndFrame() {
1821   // On our Windows 8 x64 machines, we have observed a driver bug related to
1822   // XXSetConstantBuffers1. It appears binding the same buffer to multiple
1823   // slots, and potentially leaving slots bound for many frames (as can
1824   // happen if we bind a high slot, like for blending), can consistently
1825   // cause shaders to read wrong values much later. It is possible there is
1826   // a driver bug related to aliasing and partial binding.
1827   //
1828   // Configuration: GeForce GT 610 (0x104a), Driver 9.18.13.3523, 3-4-2014,
1829   // on Windows 8 x64.
1830   //
1831   // To alleviate this we unbind all buffers at the end of the frame.
1832   static ID3D11Buffer* nullBuffers[6] = {
1833       nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
1834   };
1835   MOZ_ASSERT(MOZ_ARRAY_LENGTH(nullBuffers) >= kMaxVertexShaderConstantBuffers);
1836   MOZ_ASSERT(MOZ_ARRAY_LENGTH(nullBuffers) >= kMaxPixelShaderConstantBuffers);
1837 
1838   mCtx->VSSetConstantBuffers(0, kMaxVertexShaderConstantBuffers, nullBuffers);
1839   mCtx->VSSetConstantBuffers(0, kMaxPixelShaderConstantBuffers, nullBuffers);
1840 
1841   MLGDevice::EndFrame();
1842 }
1843 
HandleDeviceReset(const char * aWhere)1844 void MLGDeviceD3D11::HandleDeviceReset(const char* aWhere) {
1845   if (!IsValid()) {
1846     return;
1847   }
1848 
1849   Fail(NS_LITERAL_CSTRING("FEATURE_FAILURE_DEVICE_RESET"), nullptr);
1850 
1851   gfxCriticalNote << "GFX: D3D11 detected a device reset in " << aWhere;
1852   if (XRE_IsGPUProcess()) {
1853     GPUParent::GetSingleton()->NotifyDeviceReset();
1854   }
1855 
1856   UnmapSharedBuffers();
1857   mIsValid = false;
1858 }
1859 
CreateTexture(const gfx::IntSize & aSize,gfx::SurfaceFormat aFormat,MLGUsage aUsage,MLGTextureFlags aFlags)1860 RefPtr<MLGTexture> MLGDeviceD3D11::CreateTexture(const gfx::IntSize& aSize,
1861                                                  gfx::SurfaceFormat aFormat,
1862                                                  MLGUsage aUsage,
1863                                                  MLGTextureFlags aFlags) {
1864   return MLGTextureD3D11::Create(mDevice, aSize, aFormat, aUsage, aFlags);
1865 }
1866 
CreateTexture(TextureSource * aSource)1867 RefPtr<MLGTexture> MLGDeviceD3D11::CreateTexture(TextureSource* aSource) {
1868   TextureSourceD3D11* source = aSource->AsSourceD3D11();
1869   if (!source) {
1870     gfxWarning() << "Attempted to wrap a non-D3D11 texture";
1871     return nullptr;
1872   }
1873   if (!source->GetD3D11Texture()) {
1874     return nullptr;
1875   }
1876   return new MLGTextureD3D11(source->GetD3D11Texture());
1877 }
1878 
CopyTexture(MLGTexture * aDest,const gfx::IntPoint & aTarget,MLGTexture * aSource,const gfx::IntRect & aRect)1879 void MLGDeviceD3D11::CopyTexture(MLGTexture* aDest,
1880                                  const gfx::IntPoint& aTarget,
1881                                  MLGTexture* aSource,
1882                                  const gfx::IntRect& aRect) {
1883   MLGTextureD3D11* dest = aDest->AsD3D11();
1884   MLGTextureD3D11* source = aSource->AsD3D11();
1885 
1886   // We check both the source and destination copy regions, because
1887   // CopySubresourceRegion is documented as causing a device reset if
1888   // the operation is out-of-bounds. And it's not lying.
1889   IntRect sourceBounds(IntPoint(0, 0), aSource->GetSize());
1890   if (!sourceBounds.Contains(aRect)) {
1891     gfxWarning() << "Attempt to read out-of-bounds in CopySubresourceRegion: "
1892                  << Stringify(sourceBounds) << ", " << Stringify(aRect);
1893     return;
1894   }
1895 
1896   IntRect destBounds(IntPoint(0, 0), aDest->GetSize());
1897   if (!destBounds.Contains(IntRect(aTarget, aRect.Size()))) {
1898     gfxWarning() << "Attempt to write out-of-bounds in CopySubresourceRegion: "
1899                  << Stringify(destBounds) << ", " << Stringify(aTarget) << ", "
1900                  << Stringify(aRect.Size());
1901     return;
1902   }
1903 
1904   D3D11_BOX box = RectToBox(aRect);
1905   mCtx->CopySubresourceRegion(dest->GetTexture(), 0, aTarget.x, aTarget.y, 0,
1906                               source->GetTexture(), 0, &box);
1907 }
1908 
VerifyConstantBufferOffsetting()1909 bool MLGDeviceD3D11::VerifyConstantBufferOffsetting() {
1910   RefPtr<ID3D11VertexShader> vs;
1911   HRESULT hr = mDevice->CreateVertexShader(sTestConstantBuffersVS.mData,
1912                                            sTestConstantBuffersVS.mLength,
1913                                            nullptr, getter_AddRefs(vs));
1914   if (FAILED(hr)) {
1915     gfxCriticalNote << "Failed creating vertex shader for buffer test: "
1916                     << hexa(hr);
1917     return false;
1918   }
1919 
1920   D3D11_INPUT_ELEMENT_DESC inputDesc[] = {{"POSITION", 0,
1921                                            DXGI_FORMAT_R32G32_FLOAT, 0, 0,
1922                                            D3D11_INPUT_PER_VERTEX_DATA, 0}};
1923 
1924   RefPtr<ID3D11InputLayout> layout;
1925   hr = mDevice->CreateInputLayout(
1926       inputDesc, sizeof(inputDesc) / sizeof(inputDesc[0]),
1927       sTestConstantBuffersVS.mData, sTestConstantBuffersVS.mLength,
1928       getter_AddRefs(layout));
1929   if (FAILED(hr)) {
1930     gfxCriticalNote << "Failed creating input layout for buffer test: "
1931                     << hexa(hr);
1932     return false;
1933   }
1934 
1935   RefPtr<MLGRenderTarget> rt =
1936       CreateRenderTarget(IntSize(2, 2), MLGRenderTargetFlags::Default);
1937   if (!rt) {
1938     return false;
1939   }
1940 
1941   static const size_t kConstantSize = 4 * sizeof(float);
1942   static const size_t kMinConstants = 16;
1943   static const size_t kNumBindings = 3;
1944 
1945   RefPtr<MLGBuffer> buffer = CreateBuffer(
1946       MLGBufferType::Constant, kConstantSize * kMinConstants * kNumBindings,
1947       MLGUsage::Dynamic, nullptr);
1948   if (!buffer) {
1949     return false;
1950   }
1951 
1952   // Populate the buffer. The shader will pick R from buffer 1, G from buffer
1953   // 2, and B from buffer 3.
1954   {
1955     MLGMappedResource map;
1956     if (!Map(buffer, MLGMapType::WRITE_DISCARD, &map)) {
1957       return false;
1958     }
1959 
1960     *reinterpret_cast<DeviceColor*>(map.mData) =
1961         DeviceColor(1.0f, 0.2f, 0.3f, 1.0f);
1962     *reinterpret_cast<DeviceColor*>(map.mData + kConstantSize * kMinConstants) =
1963         DeviceColor(0.4f, 0.0f, 0.5f, 1.0f);
1964     *reinterpret_cast<DeviceColor*>(map.mData +
1965                                     (kConstantSize * kMinConstants) * 2) =
1966         DeviceColor(0.6f, 0.7f, 1.0f, 1.0f);
1967 
1968     Unmap(buffer);
1969   }
1970 
1971   Clear(rt, DeviceColor(0.0f, 0.0f, 0.0f, 1.0f));
1972   SetRenderTarget(rt);
1973   SetViewport(IntRect(0, 0, 2, 2));
1974   SetScissorRect(Nothing());
1975   SetBlendState(MLGBlendState::Over);
1976 
1977   SetTopology(MLGPrimitiveTopology::UnitQuad);
1978   SetInputLayout(layout);
1979   SetVertexShader(vs);
1980   SetPixelShader(PixelShaderID::ColoredQuad);
1981 
1982   ID3D11Buffer* buffers[3] = {buffer->AsD3D11()->GetBuffer(),
1983                               buffer->AsD3D11()->GetBuffer(),
1984                               buffer->AsD3D11()->GetBuffer()};
1985   UINT offsets[3] = {0 * kMinConstants, 1 * kMinConstants, 2 * kMinConstants};
1986   UINT counts[3] = {kMinConstants, kMinConstants, kMinConstants};
1987 
1988   mCtx1->VSSetConstantBuffers1(0, 3, buffers, offsets, counts);
1989   mCtx->Draw(4, 0);
1990 
1991   // Kill bindings to resources.
1992   SetRenderTarget(nullptr);
1993 
1994   ID3D11Buffer* nulls[3] = {nullptr, nullptr, nullptr};
1995   mCtx->VSSetConstantBuffers(0, 3, nulls);
1996 
1997   RefPtr<MLGTexture> copy =
1998       CreateTexture(IntSize(2, 2), SurfaceFormat::B8G8R8A8, MLGUsage::Staging,
1999                     MLGTextureFlags::None);
2000   if (!copy) {
2001     return false;
2002   }
2003 
2004   CopyTexture(copy, IntPoint(0, 0), rt->GetTexture(), IntRect(0, 0, 2, 2));
2005 
2006   uint8_t r, g, b, a;
2007   {
2008     MLGMappedResource map;
2009     if (!Map(copy, MLGMapType::READ, &map)) {
2010       return false;
2011     }
2012     r = map.mData[0];
2013     g = map.mData[1];
2014     b = map.mData[2];
2015     a = map.mData[3];
2016     Unmap(copy);
2017   }
2018 
2019   return r == 255 && g == 0 && b == 255 && a == 255;
2020 }
2021 
RectToBox(const gfx::IntRect & aRect)2022 static D3D11_BOX RectToBox(const gfx::IntRect& aRect) {
2023   D3D11_BOX box;
2024   box.front = 0;
2025   box.back = 1;
2026   box.left = aRect.X();
2027   box.top = aRect.Y();
2028   box.right = aRect.XMost();
2029   box.bottom = aRect.YMost();
2030   return box;
2031 }
2032 
2033 }  // namespace layers
2034 }  // namespace mozilla
2035