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