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