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(¶ms);
447 params.DirtyRectsCount = mBackBufferInvalid.GetNumRects();
448 params.pDirtyRects = rects.data();
449 hr = mSwapChain1->Present1(0, 0, ¶ms);
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