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