TextureD3D11.cpp (67817B)
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 "TextureD3D11.h" 8 9 #include "CompositorD3D11.h" 10 #include "DXVA2Manager.h" 11 #include "Effects.h" 12 #include "MainThreadUtils.h" 13 #include "gfx2DGlue.h" 14 #include "gfxContext.h" 15 #include "gfxWindowsPlatform.h" 16 #include "mozilla/DataMutex.h" 17 #include "mozilla/StaticPrefs_gfx.h" 18 #include "mozilla/gfx/DataSurfaceHelpers.h" 19 #include "mozilla/gfx/DeviceManagerDx.h" 20 #include "mozilla/gfx/FileHandleWrapper.h" 21 #include "mozilla/gfx/Logging.h" 22 #include "mozilla/gfx/gfxVars.h" 23 #include "mozilla/gfx/SourceSurfaceD3D11.h" 24 #include "mozilla/ipc/FileDescriptor.h" 25 #include "mozilla/layers/CompositorBridgeChild.h" 26 #include "mozilla/layers/D3D11ZeroCopyTextureImage.h" 27 #include "mozilla/layers/FenceD3D11.h" 28 #include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h" 29 #include "mozilla/layers/GpuProcessD3D11TextureMap.h" 30 #include "mozilla/layers/HelpersD3D11.h" 31 #include "mozilla/webrender/RenderD3D11TextureHost.h" 32 #include "mozilla/webrender/RenderThread.h" 33 #include "mozilla/webrender/WebRenderAPI.h" 34 35 namespace mozilla { 36 37 using namespace gfx; 38 39 namespace layers { 40 41 gfx::DeviceResetReason DXGIErrorToDeviceResetReason(HRESULT aError) { 42 switch (aError) { 43 case S_OK: 44 return gfx::DeviceResetReason::OK; 45 case DXGI_ERROR_DEVICE_REMOVED: 46 return gfx::DeviceResetReason::REMOVED; 47 case DXGI_ERROR_DRIVER_INTERNAL_ERROR: 48 return gfx::DeviceResetReason::DRIVER_ERROR; 49 case DXGI_ERROR_DEVICE_HUNG: 50 return gfx::DeviceResetReason::HUNG; 51 case DXGI_ERROR_DEVICE_RESET: 52 return gfx::DeviceResetReason::RESET; 53 case DXGI_ERROR_INVALID_CALL: 54 return gfx::DeviceResetReason::INVALID_CALL; 55 default: 56 gfxCriticalNote << "Device reset with D3D11Device unexpected reason: " 57 << gfx::hexa(aError); 58 break; 59 } 60 return gfx::DeviceResetReason::UNKNOWN; 61 } 62 63 static const GUID sD3D11TextureUsage = { 64 0xd89275b0, 65 0x6c7d, 66 0x4038, 67 {0xb5, 0xfa, 0x4d, 0x87, 0x16, 0xd5, 0xcc, 0x4e}}; 68 69 /* This class gets its lifetime tied to a D3D texture 70 * and increments memory usage on construction and decrements 71 * on destruction */ 72 class TextureMemoryMeasurer final : public IUnknown { 73 public: 74 explicit TextureMemoryMeasurer(size_t aMemoryUsed) { 75 mMemoryUsed = aMemoryUsed; 76 gfxWindowsPlatform::sD3D11SharedTextures += mMemoryUsed; 77 mRefCnt = 0; 78 } 79 STDMETHODIMP_(ULONG) AddRef() { 80 mRefCnt++; 81 return mRefCnt; 82 } 83 STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) { 84 IUnknown* punk = nullptr; 85 if (riid == IID_IUnknown) { 86 punk = this; 87 } 88 *ppvObject = punk; 89 if (punk) { 90 punk->AddRef(); 91 return S_OK; 92 } else { 93 return E_NOINTERFACE; 94 } 95 } 96 97 STDMETHODIMP_(ULONG) Release() { 98 int refCnt = --mRefCnt; 99 if (refCnt == 0) { 100 gfxWindowsPlatform::sD3D11SharedTextures -= mMemoryUsed; 101 delete this; 102 } 103 return refCnt; 104 } 105 106 private: 107 int mRefCnt; 108 int mMemoryUsed; 109 110 ~TextureMemoryMeasurer() = default; 111 }; 112 113 static DXGI_FORMAT SurfaceFormatToDXGIFormat(gfx::SurfaceFormat aFormat) { 114 switch (aFormat) { 115 case SurfaceFormat::B8G8R8A8: 116 return DXGI_FORMAT_B8G8R8A8_UNORM; 117 case SurfaceFormat::B8G8R8X8: 118 return DXGI_FORMAT_B8G8R8A8_UNORM; 119 case SurfaceFormat::R8G8B8A8: 120 return DXGI_FORMAT_R8G8B8A8_UNORM; 121 case SurfaceFormat::R8G8B8X8: 122 return DXGI_FORMAT_R8G8B8A8_UNORM; 123 case SurfaceFormat::A8: 124 return DXGI_FORMAT_R8_UNORM; 125 case SurfaceFormat::A16: 126 return DXGI_FORMAT_R16_UNORM; 127 default: 128 MOZ_ASSERT(false, "unsupported format"); 129 return DXGI_FORMAT_UNKNOWN; 130 } 131 } 132 133 void ReportTextureMemoryUsage(ID3D11Texture2D* aTexture, size_t aBytes) { 134 aTexture->SetPrivateDataInterface(sD3D11TextureUsage, 135 new TextureMemoryMeasurer(aBytes)); 136 } 137 138 static uint32_t GetRequiredTilesD3D11(uint32_t aSize, uint32_t aMaxSize) { 139 uint32_t requiredTiles = aSize / aMaxSize; 140 if (aSize % aMaxSize) { 141 requiredTiles++; 142 } 143 return requiredTiles; 144 } 145 146 static IntRect GetTileRectD3D11(uint32_t aID, IntSize aSize, 147 uint32_t aMaxSize) { 148 uint32_t horizontalTiles = GetRequiredTilesD3D11(aSize.width, aMaxSize); 149 uint32_t verticalTiles = GetRequiredTilesD3D11(aSize.height, aMaxSize); 150 151 uint32_t verticalTile = aID / horizontalTiles; 152 uint32_t horizontalTile = aID % horizontalTiles; 153 154 return IntRect( 155 horizontalTile * aMaxSize, verticalTile * aMaxSize, 156 horizontalTile < (horizontalTiles - 1) ? aMaxSize 157 : aSize.width % aMaxSize, 158 verticalTile < (verticalTiles - 1) ? aMaxSize : aSize.height % aMaxSize); 159 } 160 161 AutoTextureLock::AutoTextureLock(IDXGIKeyedMutex* aMutex, HRESULT& aResult, 162 uint32_t aTimeout) { 163 mMutex = aMutex; 164 if (mMutex) { 165 mResult = mMutex->AcquireSync(0, aTimeout); 166 aResult = mResult; 167 } else { 168 aResult = E_INVALIDARG; 169 } 170 } 171 172 AutoTextureLock::~AutoTextureLock() { 173 if (mMutex && !FAILED(mResult) && mResult != WAIT_TIMEOUT && 174 mResult != WAIT_ABANDONED) { 175 mMutex->ReleaseSync(0); 176 } 177 } 178 179 ID3D11ShaderResourceView* TextureSourceD3D11::GetShaderResourceView() { 180 MOZ_ASSERT(mTexture == GetD3D11Texture(), 181 "You need to override GetShaderResourceView if you're overriding " 182 "GetD3D11Texture!"); 183 184 if (!mSRV && mTexture) { 185 RefPtr<ID3D11Device> device; 186 mTexture->GetDevice(getter_AddRefs(device)); 187 188 // see comment in CompositingRenderTargetD3D11 constructor 189 CD3D11_SHADER_RESOURCE_VIEW_DESC srvDesc(D3D11_SRV_DIMENSION_TEXTURE2D, 190 mFormatOverride); 191 D3D11_SHADER_RESOURCE_VIEW_DESC* desc = 192 mFormatOverride == DXGI_FORMAT_UNKNOWN ? nullptr : &srvDesc; 193 194 HRESULT hr = 195 device->CreateShaderResourceView(mTexture, desc, getter_AddRefs(mSRV)); 196 if (FAILED(hr)) { 197 gfxCriticalNote << "[D3D11] TextureSourceD3D11:GetShaderResourceView " 198 "CreateSRV failure " 199 << gfx::hexa(hr); 200 return nullptr; 201 } 202 } 203 return mSRV; 204 } 205 206 DataTextureSourceD3D11::DataTextureSourceD3D11(ID3D11Device* aDevice, 207 SurfaceFormat aFormat, 208 TextureFlags aFlags) 209 : mDevice(aDevice), 210 mFormat(aFormat), 211 mFlags(aFlags), 212 mCurrentTile(0), 213 mIsTiled(false), 214 mIterating(false), 215 mAllowTextureUploads(true) {} 216 217 DataTextureSourceD3D11::DataTextureSourceD3D11(ID3D11Device* aDevice, 218 SurfaceFormat aFormat, 219 ID3D11Texture2D* aTexture) 220 : mDevice(aDevice), 221 mFormat(aFormat), 222 mFlags(TextureFlags::NO_FLAGS), 223 mCurrentTile(0), 224 mIsTiled(false), 225 mIterating(false), 226 mAllowTextureUploads(false) { 227 mTexture = aTexture; 228 D3D11_TEXTURE2D_DESC desc; 229 aTexture->GetDesc(&desc); 230 231 mSize = IntSize(desc.Width, desc.Height); 232 } 233 234 DataTextureSourceD3D11::DataTextureSourceD3D11(gfx::SurfaceFormat aFormat, 235 TextureSourceProvider* aProvider, 236 ID3D11Texture2D* aTexture) 237 : DataTextureSourceD3D11(aProvider->GetD3D11Device(), aFormat, aTexture) {} 238 239 DataTextureSourceD3D11::DataTextureSourceD3D11(gfx::SurfaceFormat aFormat, 240 TextureSourceProvider* aProvider, 241 TextureFlags aFlags) 242 : DataTextureSourceD3D11(aProvider->GetD3D11Device(), aFormat, aFlags) {} 243 244 DataTextureSourceD3D11::~DataTextureSourceD3D11() {} 245 246 enum class SerializeWithMoz2D : bool { No, Yes }; 247 248 template <typename T> // ID3D10Texture2D or ID3D11Texture2D 249 static bool LockD3DTexture(T* aTexture) { 250 MOZ_ASSERT(aTexture); 251 RefPtr<IDXGIKeyedMutex> mutex; 252 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); 253 // Textures created by the DXVA decoders don't have a mutex for 254 // synchronization 255 if (mutex) { 256 HRESULT hr = mutex->AcquireSync(0, 10000); 257 if (hr == WAIT_TIMEOUT) { 258 RefPtr<ID3D11Device> device; 259 aTexture->GetDevice(getter_AddRefs(device)); 260 if (!device) { 261 gfxCriticalNote << "GFX: D3D11 lock mutex timeout - no device returned"; 262 } else if (device->GetDeviceRemovedReason() != S_OK) { 263 gfxCriticalNote << "GFX: D3D11 lock mutex timeout - device removed"; 264 } else { 265 gfxDevCrash(LogReason::D3DLockTimeout) 266 << "D3D lock mutex timeout - device not removed"; 267 } 268 } else if (hr == WAIT_ABANDONED) { 269 gfxCriticalNote << "GFX: D3D11 lock mutex abandoned"; 270 } 271 272 if (FAILED(hr)) { 273 NS_WARNING("Failed to lock the texture"); 274 return false; 275 } 276 } 277 return true; 278 } 279 280 template <typename T> 281 static bool HasKeyedMutex(T* aTexture) { 282 MOZ_ASSERT(aTexture); 283 RefPtr<IDXGIKeyedMutex> mutex; 284 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); 285 return !!mutex; 286 } 287 288 template <typename T> // ID3D10Texture2D or ID3D11Texture2D 289 static void UnlockD3DTexture(T* aTexture) { 290 MOZ_ASSERT(aTexture); 291 RefPtr<IDXGIKeyedMutex> mutex; 292 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mutex)); 293 if (mutex) { 294 HRESULT hr = mutex->ReleaseSync(0); 295 if (FAILED(hr)) { 296 NS_WARNING("Failed to unlock the texture"); 297 } 298 } 299 } 300 301 D3D11TextureData::D3D11TextureData( 302 ID3D11Device* aDevice, ID3D11Texture2D* aTexture, uint32_t aArrayIndex, 303 RefPtr<gfx::FileHandleWrapper> aSharedHandle, gfx::IntSize aSize, 304 gfx::SurfaceFormat aFormat, 305 const Maybe<CompositeProcessFencesHolderId> aFencesHolderId, 306 const RefPtr<FenceD3D11> aWriteFence, TextureAllocationFlags aFlags) 307 : mSize(aSize), 308 mFormat(aFormat), 309 mHasKeyedMutex(HasKeyedMutex(aTexture)), 310 mFencesHolderId(aFencesHolderId), 311 mWriteFence(aWriteFence), 312 mNeedsClear(aFlags & ALLOC_CLEAR_BUFFER), 313 mTexture(aTexture), 314 mSharedHandle(std::move(aSharedHandle)), 315 mArrayIndex(aArrayIndex), 316 mAllocationFlags(aFlags) { 317 MOZ_ASSERT(aTexture); 318 } 319 320 D3D11TextureData::~D3D11TextureData() { 321 if (mGpuProcessTextureId.isSome()) { 322 auto* textureMap = GpuProcessD3D11TextureMap::Get(); 323 if (textureMap) { 324 textureMap->Unregister(mGpuProcessTextureId.ref()); 325 } else { 326 gfxCriticalNoteOnce << "GpuProcessD3D11TextureMap does not exist"; 327 } 328 } 329 if (mFencesHolderId.isSome()) { 330 MOZ_ASSERT(mFencesHolderId->IsValid()); 331 auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 332 if (fencesHolderMap) { 333 fencesHolderMap->Unregister(mFencesHolderId.ref()); 334 } else { 335 gfxCriticalNoteOnce 336 << "CompositeProcessD3D11FencesHolderMap does not exist"; 337 } 338 } 339 } 340 341 bool D3D11TextureData::Lock(OpenMode aMode) { 342 if (mFencesHolderId.isSome()) { 343 MOZ_ASSERT(mFencesHolderId->IsValid()); 344 auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 345 fencesHolderMap->WaitAllFencesAndForget(mFencesHolderId.ref(), mDevice); 346 } 347 348 if (mHasKeyedMutex && !LockD3DTexture(mTexture.get())) { 349 return false; 350 } 351 352 return true; 353 } 354 355 void D3D11TextureData::Unlock() { 356 IncrementAndSignalWriteFence(); 357 if (mFencesHolderId.isSome()) { 358 MOZ_ASSERT(mFencesHolderId->IsValid()); 359 auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 360 fencesHolderMap->SetWriteFence(mFencesHolderId.ref(), mWriteFence); 361 } 362 if (mHasKeyedMutex) { 363 UnlockD3DTexture(mTexture.get()); 364 } 365 } 366 367 void D3D11TextureData::FillInfo(TextureData::Info& aInfo) const { 368 aInfo.size = mSize; 369 aInfo.format = mFormat; 370 aInfo.supportsMoz2D = false; 371 aInfo.hasSynchronization = mHasKeyedMutex; 372 } 373 374 void D3D11TextureData::SyncWithObject(RefPtr<SyncObjectClient> aSyncObject) { 375 if (!aSyncObject || mHasKeyedMutex) { 376 // When we have per texture synchronization we sync using the keyed mutex. 377 return; 378 } 379 380 MOZ_ASSERT(aSyncObject->GetSyncType() == SyncObjectClient::SyncType::D3D11); 381 SyncObjectD3D11Client* sync = 382 static_cast<SyncObjectD3D11Client*>(aSyncObject.get()); 383 sync->RegisterTexture(mTexture); 384 } 385 386 bool D3D11TextureData::SerializeSpecific( 387 SurfaceDescriptorD3D10* const aOutDesc) { 388 *aOutDesc = SurfaceDescriptorD3D10( 389 mSharedHandle, mGpuProcessTextureId, mArrayIndex, mFormat, mSize, 390 mColorSpace, mColorRange, mHasKeyedMutex, mFencesHolderId); 391 return true; 392 } 393 394 bool D3D11TextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { 395 SurfaceDescriptorD3D10 desc; 396 if (!SerializeSpecific(&desc)) return false; 397 398 aOutDescriptor = std::move(desc); 399 return true; 400 } 401 402 void D3D11TextureData::GetSubDescriptor( 403 RemoteDecoderVideoSubDescriptor* const aOutDesc) { 404 SurfaceDescriptorD3D10 ret; 405 if (!SerializeSpecific(&ret)) return; 406 407 *aOutDesc = std::move(ret); 408 } 409 410 /* static */ 411 already_AddRefed<TextureClient> D3D11TextureData::CreateTextureClient( 412 ID3D11Texture2D* aTexture, uint32_t aIndex, gfx::IntSize aSize, 413 gfx::SurfaceFormat aFormat, gfx::ColorSpace2 aColorSpace, 414 gfx::ColorRange aColorRange, KnowsCompositor* aKnowsCompositor, 415 RefPtr<ZeroCopyUsageInfo> aUsageInfo, 416 const RefPtr<FenceD3D11> aWriteFence) { 417 MOZ_ASSERT(aTexture); 418 419 RefPtr<ID3D11Device> device; 420 aTexture->GetDevice(getter_AddRefs(device)); 421 422 Maybe<CompositeProcessFencesHolderId> fencesHolderId; 423 if (aWriteFence) { 424 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 425 fencesHolderId = Some(CompositeProcessFencesHolderId::GetNext()); 426 fencesHolderMap->Register(fencesHolderId.ref()); 427 } 428 429 D3D11TextureData* data = new D3D11TextureData( 430 device, aTexture, aIndex, nullptr, aSize, aFormat, fencesHolderId, 431 aWriteFence, TextureAllocationFlags::ALLOC_MANUAL_SYNCHRONIZATION); 432 data->mColorSpace = aColorSpace; 433 data->SetColorRange(aColorRange); 434 435 RefPtr<TextureClient> textureClient = MakeAndAddRef<TextureClient>( 436 data, TextureFlags::NO_FLAGS, aKnowsCompositor->GetTextureForwarder()); 437 const auto textureId = GpuProcessD3D11TextureMap::GetNextTextureId(); 438 data->SetGpuProcessTextureId(textureId); 439 440 // Register ID3D11Texture2D to GpuProcessD3D11TextureMap 441 auto* textureMap = GpuProcessD3D11TextureMap::Get(); 442 if (textureMap) { 443 textureMap->Register(textureId, aTexture, aIndex, aSize, aUsageInfo); 444 } else { 445 gfxCriticalNoteOnce << "GpuProcessD3D11TextureMap does not exist"; 446 } 447 448 return textureClient.forget(); 449 } 450 451 D3D11TextureData* D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat, 452 TextureAllocationFlags aFlags, 453 ID3D11Device* aDevice) { 454 return Create(aSize, aFormat, nullptr, aFlags, aDevice); 455 } 456 457 D3D11TextureData* D3D11TextureData::Create(IntSize aSize, SurfaceFormat aFormat, 458 SourceSurface* aSurface, 459 TextureAllocationFlags aFlags, 460 ID3D11Device* aDevice) { 461 if (aFormat == SurfaceFormat::A8) { 462 // Currently we don't support A8 surfaces. Fallback. 463 return nullptr; 464 } 465 466 // Just grab any device. We never use the immediate context, so the devices 467 // are fine to use from any thread. 468 RefPtr<ID3D11Device> device = aDevice; 469 if (!device) { 470 device = DeviceManagerDx::Get()->GetContentDevice(); 471 if (!device) { 472 return nullptr; 473 } 474 } 475 476 CD3D11_TEXTURE2D_DESC newDesc( 477 DXGI_FORMAT_B8G8R8A8_UNORM, aSize.width, aSize.height, 1, 1, 478 D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE); 479 480 // This supported formats list matches DXGITextureHostD3D11::PushDisplayItems. 481 switch (aFormat) { 482 case gfx::SurfaceFormat::B8G8R8X8: 483 case gfx::SurfaceFormat::R8G8B8X8: 484 newDesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM; 485 break; 486 case gfx::SurfaceFormat::B8G8R8A8: 487 case gfx::SurfaceFormat::R8G8B8A8: 488 newDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; 489 break; 490 case gfx::SurfaceFormat::R10G10B10A2_UINT32: 491 case gfx::SurfaceFormat::R10G10B10X2_UINT32: 492 newDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM; 493 break; 494 case gfx::SurfaceFormat::R16G16B16A16F: 495 newDesc.Format = DXGI_FORMAT_R16G16B16A16_FLOAT; 496 break; 497 case gfx::SurfaceFormat::NV12: 498 newDesc.Format = DXGI_FORMAT_NV12; 499 break; 500 case gfx::SurfaceFormat::P010: 501 newDesc.Format = DXGI_FORMAT_P010; 502 break; 503 case gfx::SurfaceFormat::P016: 504 newDesc.Format = DXGI_FORMAT_P016; 505 break; 506 case gfx::SurfaceFormat::A8R8G8B8: 507 case gfx::SurfaceFormat::X8R8G8B8: 508 case gfx::SurfaceFormat::R8G8B8: 509 case gfx::SurfaceFormat::B8G8R8: 510 case gfx::SurfaceFormat::R5G6B5_UINT16: 511 case gfx::SurfaceFormat::A8: 512 case gfx::SurfaceFormat::A16: 513 case gfx::SurfaceFormat::R8G8: 514 case gfx::SurfaceFormat::R16G16: 515 case gfx::SurfaceFormat::YUV420: 516 case gfx::SurfaceFormat::YUV420P10: 517 case gfx::SurfaceFormat::YUV422P10: 518 case gfx::SurfaceFormat::NV16: 519 case gfx::SurfaceFormat::YUY2: 520 case gfx::SurfaceFormat::HSV: 521 case gfx::SurfaceFormat::Lab: 522 case gfx::SurfaceFormat::Depth: 523 case gfx::SurfaceFormat::UNKNOWN: 524 // Per advice from Sotaro, these formats are not supported for video. 525 gfxCriticalNoteOnce 526 << "D3D11TextureData::Create: Unsupported SurfaceFormat %u" 527 << static_cast<unsigned int>(aFormat); 528 return nullptr; 529 } 530 531 newDesc.MiscFlags = 532 D3D11_RESOURCE_MISC_SHARED_NTHANDLE | D3D11_RESOURCE_MISC_SHARED; 533 bool useFence = false; 534 bool useKeyedMutex = false; 535 if (!NS_IsMainThread()) { 536 // On the main thread we use the syncobject to handle synchronization. 537 if (!(aFlags & ALLOC_MANUAL_SYNCHRONIZATION)) { 538 if (!(aFlags & USE_D3D11_KEYED_MUTEX)) { 539 auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 540 useFence = fencesHolderMap && FenceD3D11::IsSupported(device); 541 } 542 if (!useFence) { 543 newDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | 544 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; 545 useKeyedMutex = true; 546 } 547 } 548 } 549 550 Maybe<CompositeProcessFencesHolderId> fencesHolderId; 551 RefPtr<FenceD3D11> fence; 552 if (useFence) { 553 fence = FenceD3D11::Create(device); 554 if (!fence) { 555 return nullptr; 556 } 557 fencesHolderId = Some(CompositeProcessFencesHolderId::GetNext()); 558 } 559 560 if (aSurface && useKeyedMutex && 561 !DeviceManagerDx::Get()->CanInitializeKeyedMutexTextures()) { 562 return nullptr; 563 } 564 565 D3D11_SUBRESOURCE_DATA uploadData; 566 D3D11_SUBRESOURCE_DATA* uploadDataPtr = nullptr; 567 RefPtr<DataSourceSurface> srcSurf; 568 569 if (aSurface) { 570 srcSurf = aSurface->GetDataSurface(); 571 572 if (!srcSurf) { 573 gfxCriticalError() 574 << "Failed to GetDataSurface in D3D11TextureData::Create"; 575 return nullptr; 576 } 577 578 DataSourceSurface::MappedSurface sourceMap; 579 if (!srcSurf->Map(DataSourceSurface::READ, &sourceMap)) { 580 gfxCriticalError() 581 << "Failed to map source surface for D3D11TextureData::Create"; 582 return nullptr; 583 } 584 585 uploadData.pSysMem = sourceMap.mData; 586 uploadData.SysMemPitch = sourceMap.mStride; 587 uploadData.SysMemSlicePitch = 0; // unused 588 589 uploadDataPtr = &uploadData; 590 } 591 592 // See bug 1397040 593 RefPtr<ID3D10Multithread> mt; 594 device->QueryInterface((ID3D10Multithread**)getter_AddRefs(mt)); 595 596 RefPtr<ID3D11Texture2D> texture11; 597 598 { 599 D3D11MTAutoEnter lock(mt.forget()); 600 601 HRESULT hr = device->CreateTexture2D(&newDesc, uploadDataPtr, 602 getter_AddRefs(texture11)); 603 604 if (FAILED(hr) || !texture11) { 605 gfxCriticalNote << "[D3D11] 2 CreateTexture2D failure Size: " << aSize 606 << "texture11: " << texture11 607 << " Code: " << gfx::hexa(hr); 608 return nullptr; 609 } 610 } 611 612 if (srcSurf) { 613 srcSurf->Unmap(); 614 } 615 616 // If we created the texture with a keyed mutex, then we expect all operations 617 // on it to be synchronized using it. If we did an initial upload using 618 // aSurface then bizarely this isn't covered, so we insert a manual 619 // lock/unlock pair to force this. 620 if (aSurface && useKeyedMutex) { 621 if (!LockD3DTexture(texture11.get())) { 622 return nullptr; 623 } 624 UnlockD3DTexture(texture11.get()); 625 } 626 627 RefPtr<IDXGIResource1> resource; 628 texture11->QueryInterface((IDXGIResource1**)getter_AddRefs(resource)); 629 if (!resource) { 630 gfxCriticalNoteOnce << "Failed to get IDXGIResource"; 631 return nullptr; 632 } 633 634 HANDLE sharedHandle; 635 HRESULT hr = resource->GetSharedHandle(&sharedHandle); 636 hr = resource->CreateSharedHandle( 637 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, 638 &sharedHandle); 639 if (FAILED(hr)) { 640 gfxCriticalNoteOnce << "GetSharedHandle failed: " << gfx::hexa(hr); 641 return nullptr; 642 } 643 644 texture11->SetPrivateDataInterface( 645 sD3D11TextureUsage, 646 new TextureMemoryMeasurer(newDesc.Width * newDesc.Height * 4)); 647 648 RefPtr<gfx::FileHandleWrapper> handle = 649 new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); 650 651 if (useFence) { 652 auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 653 fencesHolderMap->Register(fencesHolderId.ref()); 654 } 655 656 D3D11TextureData* data = 657 new D3D11TextureData(device, texture11, 0, handle, aSize, aFormat, 658 fencesHolderId, fence, aFlags); 659 660 texture11->GetDevice(getter_AddRefs(device)); 661 if (XRE_IsGPUProcess() && 662 device == gfx::DeviceManagerDx::Get()->GetCompositorDevice()) { 663 const auto textureId = GpuProcessD3D11TextureMap::GetNextTextureId(); 664 data->SetGpuProcessTextureId(textureId); 665 // Register ID3D11Texture2D to GpuProcessD3D11TextureMap 666 auto* textureMap = GpuProcessD3D11TextureMap::Get(); 667 if (textureMap) { 668 textureMap->Register(textureId, texture11, 0, aSize, nullptr, handle); 669 } else { 670 gfxCriticalNoteOnce << "GpuProcessD3D11TextureMap does not exist"; 671 } 672 } 673 674 return data; 675 } 676 677 void D3D11TextureData::Deallocate(LayersIPCChannel* aAllocator) { 678 mTexture = nullptr; 679 } 680 681 TextureData* D3D11TextureData::CreateSimilar( 682 LayersIPCChannel* aAllocator, LayersBackend aLayersBackend, 683 TextureFlags aFlags, TextureAllocationFlags aAllocFlags) const { 684 return D3D11TextureData::Create(mSize, mFormat, aAllocFlags); 685 } 686 687 TextureFlags D3D11TextureData::GetTextureFlags() const { 688 // With WebRender, resource open happens asynchronously on RenderThread. 689 // During opening the resource on host side, TextureClient needs to be alive. 690 // With WAIT_HOST_USAGE_END, keep TextureClient alive during host side usage. 691 return TextureFlags::WAIT_HOST_USAGE_END; 692 } 693 694 void D3D11TextureData::IncrementAndSignalWriteFence() { 695 if (mFencesHolderId.isNothing() || !mWriteFence) { 696 return; 697 } 698 699 MOZ_ASSERT(mFencesHolderId->IsValid()); 700 701 auto* fencesHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 702 if (!fencesHolderMap) { 703 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 704 return; 705 } 706 707 mWriteFence->IncrementAndSignal(); 708 fencesHolderMap->SetWriteFence(mFencesHolderId.ref(), mWriteFence); 709 } 710 711 DXGIYCbCrTextureData* DXGIYCbCrTextureData::Create( 712 ID3D11Texture2D* aTextureY, ID3D11Texture2D* aTextureCb, 713 ID3D11Texture2D* aTextureCr, const gfx::IntSize& aSize, 714 const gfx::IntSize& aSizeY, const gfx::IntSize& aSizeCbCr, 715 const gfx::ColorDepth aColorDepth, const YUVColorSpace aYUVColorSpace, 716 const gfx::ColorRange aColorRange) { 717 if (!aTextureY || !aTextureCb || !aTextureCr) { 718 return nullptr; 719 } 720 721 aTextureY->SetPrivateDataInterface( 722 sD3D11TextureUsage, 723 new TextureMemoryMeasurer(aSizeY.width * aSizeY.height)); 724 aTextureCb->SetPrivateDataInterface( 725 sD3D11TextureUsage, 726 new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height)); 727 aTextureCr->SetPrivateDataInterface( 728 sD3D11TextureUsage, 729 new TextureMemoryMeasurer(aSizeCbCr.width * aSizeCbCr.height)); 730 731 RefPtr<IDXGIResource1> resource; 732 733 aTextureY->QueryInterface((IDXGIResource1**)getter_AddRefs(resource)); 734 735 HANDLE handleY; 736 HRESULT hr = resource->CreateSharedHandle( 737 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, 738 &handleY); 739 if (FAILED(hr)) { 740 return nullptr; 741 } 742 const RefPtr<gfx::FileHandleWrapper> sharedHandleY = 743 new gfx::FileHandleWrapper(UniqueFileHandle(handleY)); 744 745 aTextureCb->QueryInterface((IDXGIResource1**)getter_AddRefs(resource)); 746 747 HANDLE handleCb; 748 hr = resource->CreateSharedHandle( 749 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, 750 &handleCb); 751 if (FAILED(hr)) { 752 return nullptr; 753 } 754 const RefPtr<gfx::FileHandleWrapper> sharedHandleCb = 755 new gfx::FileHandleWrapper(UniqueFileHandle(handleCb)); 756 757 aTextureCr->QueryInterface((IDXGIResource1**)getter_AddRefs(resource)); 758 HANDLE handleCr; 759 hr = resource->CreateSharedHandle( 760 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, 761 &handleCr); 762 if (FAILED(hr)) { 763 return nullptr; 764 } 765 const RefPtr<gfx::FileHandleWrapper> sharedHandleCr = 766 new gfx::FileHandleWrapper(UniqueFileHandle(handleCr)); 767 768 auto* fenceHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 769 if (!fenceHolderMap) { 770 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 771 return nullptr; 772 } 773 774 RefPtr<ID3D11Device> device; 775 aTextureY->GetDevice(getter_AddRefs(device)); 776 if (!device) { 777 return nullptr; 778 } 779 780 RefPtr<FenceD3D11> fence = FenceD3D11::Create(device); 781 if (!fence) { 782 return nullptr; 783 } 784 785 auto fencesHolderId = CompositeProcessFencesHolderId::GetNext(); 786 fenceHolderMap->Register(fencesHolderId); 787 788 RefPtr<ID3D11Texture2D> textures[3] = {aTextureY, aTextureCb, aTextureCr}; 789 RefPtr<gfx::FileHandleWrapper> handles[3] = {sharedHandleY, sharedHandleCb, 790 sharedHandleCr}; 791 792 DXGIYCbCrTextureData* texture = new DXGIYCbCrTextureData( 793 textures, handles, aSize, aSizeY, aSizeCbCr, aColorDepth, aYUVColorSpace, 794 aColorRange, fencesHolderId, fence); 795 return texture; 796 } 797 798 DXGIYCbCrTextureData::DXGIYCbCrTextureData( 799 RefPtr<ID3D11Texture2D> (&aD3D11Textures)[3], 800 RefPtr<gfx::FileHandleWrapper>(aHandles)[3], const gfx::IntSize& aSize, 801 const gfx::IntSize& aSizeY, const gfx::IntSize& aSizeCbCr, 802 const gfx::ColorDepth aColorDepth, const gfx::YUVColorSpace aYUVColorSpace, 803 const gfx::ColorRange aColorRange, 804 const CompositeProcessFencesHolderId aFencesHolderId, 805 const RefPtr<FenceD3D11> aWriteFence) 806 : mSize(aSize), 807 mSizeY(aSizeY), 808 mSizeCbCr(aSizeCbCr), 809 mColorDepth(aColorDepth), 810 mYUVColorSpace(aYUVColorSpace), 811 mColorRange(aColorRange), 812 mFencesHolderId(aFencesHolderId), 813 mWriteFence(aWriteFence), 814 mD3D11Textures{aD3D11Textures[0], aD3D11Textures[1], aD3D11Textures[2]}, 815 mHandles{aHandles[0], aHandles[1], aHandles[2]} {} 816 817 DXGIYCbCrTextureData::~DXGIYCbCrTextureData() { 818 auto* fenceHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 819 if (!fenceHolderMap) { 820 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 821 return; 822 } 823 fenceHolderMap->Unregister(mFencesHolderId); 824 } 825 826 void DXGIYCbCrTextureData::FillInfo(TextureData::Info& aInfo) const { 827 aInfo.size = mSize; 828 aInfo.format = gfx::SurfaceFormat::YUV420; 829 aInfo.supportsMoz2D = false; 830 aInfo.hasSynchronization = false; 831 } 832 833 void DXGIYCbCrTextureData::SerializeSpecific( 834 SurfaceDescriptorDXGIYCbCr* const aOutDesc) { 835 *aOutDesc = SurfaceDescriptorDXGIYCbCr( 836 mHandles[0], mHandles[1], mHandles[2], mSize, mSizeY, mSizeCbCr, 837 mColorDepth, mYUVColorSpace, mColorRange, mFencesHolderId); 838 } 839 840 bool DXGIYCbCrTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) { 841 SurfaceDescriptorDXGIYCbCr desc; 842 SerializeSpecific(&desc); 843 844 aOutDescriptor = std::move(desc); 845 return true; 846 } 847 848 void DXGIYCbCrTextureData::GetSubDescriptor( 849 RemoteDecoderVideoSubDescriptor* const aOutDesc) { 850 SurfaceDescriptorDXGIYCbCr desc; 851 SerializeSpecific(&desc); 852 853 *aOutDesc = std::move(desc); 854 } 855 856 void DXGIYCbCrTextureData::Deallocate(LayersIPCChannel*) { 857 mD3D11Textures[0] = nullptr; 858 mD3D11Textures[1] = nullptr; 859 mD3D11Textures[2] = nullptr; 860 } 861 862 TextureFlags DXGIYCbCrTextureData::GetTextureFlags() const { 863 // With WebRender, resource open happens asynchronously on RenderThread. 864 // During opening the resource on host side, TextureClient needs to be alive. 865 // With WAIT_HOST_USAGE_END, keep TextureClient alive during host side usage. 866 return TextureFlags::WAIT_HOST_USAGE_END; 867 } 868 869 already_AddRefed<TextureHost> CreateTextureHostD3D11( 870 const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator, 871 LayersBackend aBackend, TextureFlags aFlags) { 872 RefPtr<TextureHost> result; 873 switch (aDesc.type()) { 874 case SurfaceDescriptor::TSurfaceDescriptorD3D10: { 875 result = 876 new DXGITextureHostD3D11(aFlags, aDesc.get_SurfaceDescriptorD3D10()); 877 break; 878 } 879 case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: { 880 result = new DXGIYCbCrTextureHostD3D11( 881 aFlags, aDesc.get_SurfaceDescriptorDXGIYCbCr()); 882 break; 883 } 884 default: { 885 MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type"); 886 } 887 } 888 return result.forget(); 889 } 890 891 already_AddRefed<DrawTarget> D3D11TextureData::BorrowDrawTarget() { 892 MOZ_ASSERT(NS_IsMainThread() || NS_IsInCanvasThreadOrWorker()); 893 gfxCriticalNote << "Could not borrow DrawTarget (D3D11) " << (int)mFormat; 894 return nullptr; 895 } 896 897 bool D3D11TextureData::UpdateFromSurface(gfx::SourceSurface* aSurface) { 898 // Supporting texture updates after creation requires an ID3D11DeviceContext 899 // and those aren't threadsafe. We'd need to either lock, or have a device for 900 // whatever thread this runs on and we're trying to avoid extra devices (bug 901 // 1284672). 902 MOZ_ASSERT(false, 903 "UpdateFromSurface not supported for D3D11! Use CreateFromSurface " 904 "instead"); 905 return false; 906 } 907 908 static RefPtr<ID3D11Texture2D> OpenSharedD3D11Texture( 909 ID3D11Device* const aDevice, const HANDLE handle) { 910 MOZ_ASSERT(aDevice); 911 912 RefPtr<ID3D11Device1> device1; 913 aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1)); 914 if (!device1) { 915 gfxCriticalNoteOnce << "Failed to get ID3D11Device1"; 916 return nullptr; 917 } 918 919 RefPtr<ID3D11Texture2D> tex; 920 auto hr = device1->OpenSharedResource1( 921 (HANDLE)handle, __uuidof(ID3D11Texture2D), 922 (void**)(ID3D11Texture2D**)getter_AddRefs(tex)); 923 if (FAILED(hr)) { 924 gfxCriticalNote << "Error code from OpenSharedResource1: " << gfx::hexa(hr); 925 return nullptr; 926 } 927 928 return tex; 929 } 930 931 static RefPtr<ID3D11Texture2D> OpenSharedD3D11Texture( 932 DXGITextureHostD3D11* aTextureHost, ID3D11Device* const aDevice) { 933 MOZ_ASSERT(aDevice); 934 MOZ_ASSERT(aTextureHost); 935 936 const auto& handle = aTextureHost->mHandle; 937 const auto& gpuProcessTextureId = aTextureHost->mGpuProcessTextureId; 938 939 RefPtr<ID3D11Texture2D> texture; 940 if (gpuProcessTextureId.isSome()) { 941 auto* textureMap = GpuProcessD3D11TextureMap::Get(); 942 if (textureMap) { 943 texture = textureMap->GetTexture(gpuProcessTextureId.ref()); 944 } 945 } else if (handle) { 946 texture = OpenSharedD3D11Texture(aDevice, handle->GetHandle()); 947 } 948 949 if (!texture) { 950 return nullptr; 951 } 952 return texture; 953 } 954 955 DXGITextureHostD3D11::DXGITextureHostD3D11( 956 TextureFlags aFlags, const SurfaceDescriptorD3D10& aDescriptor) 957 : TextureHost(TextureHostType::DXGI, aFlags), 958 mHandle(aDescriptor.handle()), 959 mGpuProcessTextureId(aDescriptor.gpuProcessTextureId()), 960 mArrayIndex(aDescriptor.arrayIndex()), 961 mSize(aDescriptor.size()), 962 mFormat(aDescriptor.format()), 963 mHasKeyedMutex(aDescriptor.hasKeyedMutex()), 964 mFencesHolderId(aDescriptor.fencesHolderId()), 965 mColorSpace(aDescriptor.colorSpace()), 966 mColorRange(aDescriptor.colorRange()) { 967 if (!mFencesHolderId) { 968 return; 969 } 970 MOZ_ASSERT(mFencesHolderId->IsValid()); 971 if (auto* fenceHolderMap = CompositeProcessD3D11FencesHolderMap::Get()) { 972 fenceHolderMap->RegisterReference(mFencesHolderId.ref()); 973 } else { 974 MOZ_ASSERT_UNREACHABLE("FencesHolderMap not available"); 975 } 976 } 977 978 DXGITextureHostD3D11::~DXGITextureHostD3D11() { 979 if (!mFencesHolderId) { 980 return; 981 } 982 if (auto* fenceHolderMap = CompositeProcessD3D11FencesHolderMap::Get()) { 983 fenceHolderMap->Unregister(mFencesHolderId.ref()); 984 } else { 985 MOZ_ASSERT_UNREACHABLE("FencesHolderMap not available"); 986 } 987 } 988 989 already_AddRefed<gfx::DataSourceSurface> DXGITextureHostD3D11::GetAsSurface( 990 gfx::DataSourceSurface* aSurface) { 991 RefPtr<ID3D11Device> d3d11Device = 992 DeviceManagerDx::Get()->GetCompositorDevice(); 993 if (!d3d11Device) { 994 return nullptr; 995 } 996 997 RefPtr<ID3D11Texture2D> d3dTexture = 998 OpenSharedD3D11Texture(this, d3d11Device); 999 if (!d3dTexture) { 1000 return nullptr; 1001 } 1002 1003 bool isLocked = LockD3DTexture(d3dTexture.get()); 1004 if (!isLocked) { 1005 return nullptr; 1006 } 1007 1008 const auto onExit = 1009 mozilla::MakeScopeExit([&]() { UnlockD3DTexture(d3dTexture.get()); }); 1010 1011 bool isRGB = [&]() { 1012 switch (mFormat) { 1013 case gfx::SurfaceFormat::R8G8B8X8: 1014 case gfx::SurfaceFormat::R8G8B8A8: 1015 case gfx::SurfaceFormat::B8G8R8A8: 1016 case gfx::SurfaceFormat::B8G8R8X8: 1017 return true; 1018 default: 1019 break; 1020 } 1021 return false; 1022 }(); 1023 1024 if (!isRGB) { 1025 return nullptr; 1026 } 1027 1028 D3D11_TEXTURE2D_DESC textureDesc = {0}; 1029 d3dTexture->GetDesc(&textureDesc); 1030 1031 RefPtr<ID3D11DeviceContext> context; 1032 d3d11Device->GetImmediateContext(getter_AddRefs(context)); 1033 1034 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; 1035 textureDesc.Usage = D3D11_USAGE_STAGING; 1036 textureDesc.BindFlags = 0; 1037 textureDesc.MiscFlags = 0; 1038 textureDesc.MipLevels = 1; 1039 RefPtr<ID3D11Texture2D> cpuTexture; 1040 HRESULT hr = d3d11Device->CreateTexture2D(&textureDesc, nullptr, 1041 getter_AddRefs(cpuTexture)); 1042 if (FAILED(hr)) { 1043 return nullptr; 1044 } 1045 1046 context->CopyResource(cpuTexture, d3dTexture); 1047 1048 D3D11_MAPPED_SUBRESOURCE mappedSubresource; 1049 hr = context->Map(cpuTexture, 0, D3D11_MAP_READ, 0, &mappedSubresource); 1050 if (FAILED(hr)) { 1051 return nullptr; 1052 } 1053 1054 RefPtr<DataSourceSurface> surf = gfx::CreateDataSourceSurfaceFromData( 1055 IntSize(textureDesc.Width, textureDesc.Height), GetFormat(), 1056 (uint8_t*)mappedSubresource.pData, mappedSubresource.RowPitch); 1057 context->Unmap(cpuTexture, 0); 1058 return surf.forget(); 1059 } 1060 1061 already_AddRefed<gfx::DataSourceSurface> 1062 DXGITextureHostD3D11::GetAsSurfaceWithDevice(ID3D11Device* const aDevice) { 1063 if (!aDevice) { 1064 return nullptr; 1065 } 1066 1067 RefPtr<ID3D11Texture2D> d3dTexture = OpenSharedD3D11Texture(this, aDevice); 1068 if (!d3dTexture) { 1069 return nullptr; 1070 } 1071 1072 if (mGpuProcessTextureId.isSome()) { 1073 auto* textureMap = layers::GpuProcessD3D11TextureMap::Get(); 1074 if (textureMap) { 1075 textureMap->DisableZeroCopyNV12Texture(mGpuProcessTextureId.ref()); 1076 } 1077 } 1078 1079 RefPtr<gfx::SourceSurface> sourceSurface = gfx::SourceSurfaceD3D11::Create( 1080 d3dTexture, mArrayIndex, mColorSpace, mColorRange, mFencesHolderId); 1081 if (!sourceSurface) { 1082 return nullptr; 1083 } 1084 1085 RefPtr<DataSourceSurface> dataSurface = sourceSurface->GetDataSurface(); 1086 if (!dataSurface) { 1087 return nullptr; 1088 } 1089 1090 return dataSurface.forget(); 1091 } 1092 1093 void DXGITextureHostD3D11::CreateRenderTexture( 1094 const wr::ExternalImageId& aExternalImageId) { 1095 MOZ_ASSERT(mExternalImageId.isSome()); 1096 1097 RefPtr<wr::RenderDXGITextureHost> texture = new wr::RenderDXGITextureHost( 1098 mHandle, mGpuProcessTextureId, mArrayIndex, mFormat, mColorSpace, 1099 mColorRange, mSize, mHasKeyedMutex, mFencesHolderId); 1100 if (mFlags & TextureFlags::SOFTWARE_DECODED_VIDEO) { 1101 texture->SetIsSoftwareDecodedVideo(); 1102 } 1103 if (mFlags & TextureFlags::DRM_SOURCE) { 1104 texture->SetIsFromDRMSource(/* aIsFromDRMSource */ true); 1105 } 1106 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, 1107 texture.forget()); 1108 } 1109 1110 uint32_t DXGITextureHostD3D11::NumSubTextures() { 1111 switch (GetFormat()) { 1112 case gfx::SurfaceFormat::R8G8B8X8: 1113 case gfx::SurfaceFormat::R8G8B8A8: 1114 case gfx::SurfaceFormat::B8G8R8A8: 1115 case gfx::SurfaceFormat::B8G8R8X8: 1116 case gfx::SurfaceFormat::R10G10B10A2_UINT32: 1117 case gfx::SurfaceFormat::R10G10B10X2_UINT32: 1118 case gfx::SurfaceFormat::R16G16B16A16F: { 1119 return 1; 1120 } 1121 case gfx::SurfaceFormat::NV12: 1122 case gfx::SurfaceFormat::P010: 1123 case gfx::SurfaceFormat::P016: { 1124 return 2; 1125 } 1126 default: { 1127 MOZ_ASSERT_UNREACHABLE("unexpected format"); 1128 return 1; 1129 } 1130 } 1131 } 1132 1133 void DXGITextureHostD3D11::PushResourceUpdates( 1134 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, 1135 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) { 1136 if (!gfx::gfxVars::UseWebRenderANGLE()) { 1137 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE"); 1138 return; 1139 } 1140 1141 MOZ_ASSERT(mHandle || mGpuProcessTextureId.isSome()); 1142 auto method = aOp == TextureHost::ADD_IMAGE 1143 ? &wr::TransactionBuilder::AddExternalImage 1144 : &wr::TransactionBuilder::UpdateExternalImage; 1145 switch (mFormat) { 1146 case gfx::SurfaceFormat::R8G8B8X8: 1147 case gfx::SurfaceFormat::R8G8B8A8: 1148 case gfx::SurfaceFormat::B8G8R8A8: 1149 case gfx::SurfaceFormat::B8G8R8X8: 1150 case gfx::SurfaceFormat::R10G10B10A2_UINT32: 1151 case gfx::SurfaceFormat::R10G10B10X2_UINT32: 1152 case gfx::SurfaceFormat::R16G16B16A16F: { 1153 MOZ_ASSERT(aImageKeys.length() == 1); 1154 1155 wr::ImageDescriptor descriptor(mSize, GetFormat()); 1156 // Prefer TextureExternal unless the backend requires TextureRect. 1157 TextureHost::NativeTexturePolicy policy = 1158 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(), 1159 mSize); 1160 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE 1161 ? wr::ExternalImageType::TextureHandle( 1162 wr::ImageBufferKind::TextureRect) 1163 : wr::ExternalImageType::TextureHandle( 1164 wr::ImageBufferKind::TextureExternal); 1165 (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0, 1166 /* aNormalizedUvs */ false); 1167 break; 1168 } 1169 case gfx::SurfaceFormat::P010: 1170 case gfx::SurfaceFormat::P016: 1171 case gfx::SurfaceFormat::NV12: { 1172 MOZ_ASSERT(aImageKeys.length() == 2); 1173 MOZ_ASSERT(mSize.width % 2 == 0); 1174 MOZ_ASSERT(mSize.height % 2 == 0); 1175 1176 wr::ImageDescriptor descriptor0(mSize, mFormat == gfx::SurfaceFormat::NV12 1177 ? gfx::SurfaceFormat::A8 1178 : gfx::SurfaceFormat::A16); 1179 wr::ImageDescriptor descriptor1(mSize / 2, 1180 mFormat == gfx::SurfaceFormat::NV12 1181 ? gfx::SurfaceFormat::R8G8 1182 : gfx::SurfaceFormat::R16G16); 1183 // Prefer TextureExternal unless the backend requires TextureRect. 1184 TextureHost::NativeTexturePolicy policy = 1185 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(), 1186 mSize); 1187 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE 1188 ? wr::ExternalImageType::TextureHandle( 1189 wr::ImageBufferKind::TextureRect) 1190 : wr::ExternalImageType::TextureHandle( 1191 wr::ImageBufferKind::TextureExternal); 1192 (aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0, 1193 /* aNormalizedUvs */ false); 1194 (aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1, 1195 /* aNormalizedUvs */ false); 1196 break; 1197 } 1198 default: { 1199 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1200 } 1201 } 1202 } 1203 1204 void DXGITextureHostD3D11::PushDisplayItems( 1205 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, 1206 const wr::LayoutRect& aClip, wr::ImageRendering aFilter, 1207 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) { 1208 bool preferCompositorSurface = 1209 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE); 1210 if (!gfx::gfxVars::UseWebRenderANGLE()) { 1211 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE"); 1212 return; 1213 } 1214 1215 bool preferExternalCompositing = 1216 SupportsExternalCompositing(aBuilder.GetBackendType()); 1217 if (aFlags.contains(PushDisplayItemFlag::EXTERNAL_COMPOSITING_DISABLED)) { 1218 MOZ_ASSERT(aBuilder.GetBackendType() != WebRenderBackend::SOFTWARE); 1219 preferExternalCompositing = false; 1220 } 1221 1222 // This supported format list matches D3D11TextureData::Create. 1223 switch (GetFormat()) { 1224 case gfx::SurfaceFormat::R10G10B10A2_UINT32: 1225 case gfx::SurfaceFormat::R10G10B10X2_UINT32: 1226 case gfx::SurfaceFormat::R16G16B16A16F: { 1227 // WebRender isn't HDR ready so we have to push to the compositor. 1228 preferCompositorSurface = preferExternalCompositing = true; 1229 MOZ_ASSERT(aImageKeys.length() == 1); 1230 aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0], 1231 !(mFlags & TextureFlags::NON_PREMULTIPLIED), 1232 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, 1233 preferCompositorSurface, preferExternalCompositing); 1234 break; 1235 } 1236 case gfx::SurfaceFormat::R8G8B8X8: 1237 case gfx::SurfaceFormat::R8G8B8A8: 1238 case gfx::SurfaceFormat::B8G8R8A8: 1239 case gfx::SurfaceFormat::B8G8R8X8: { 1240 MOZ_ASSERT(aImageKeys.length() == 1); 1241 aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0], 1242 !(mFlags & TextureFlags::NON_PREMULTIPLIED), 1243 wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, 1244 preferCompositorSurface, preferExternalCompositing); 1245 break; 1246 } 1247 case gfx::SurfaceFormat::P010: 1248 case gfx::SurfaceFormat::P016: { 1249 // DXGI_FORMAT_P010 stores its 10 bit value in the most significant bits 1250 // of each 16 bit word with the unused lower bits cleared to zero so that 1251 // it may be handled as if it was DXGI_FORMAT_P016. This is approximately 1252 // perceptually correct. However, due to rounding error, the precise 1253 // quantized value after sampling may be off by 1. 1254 MOZ_ASSERT(aImageKeys.length() == 2); 1255 aBuilder.PushP010Image( 1256 aBounds, aClip, true, aImageKeys[0], aImageKeys[1], 1257 wr::ColorDepth::Color16, 1258 wr::ToWrYuvColorSpace(ToYUVColorSpace(mColorSpace)), 1259 wr::ToWrColorRange(mColorRange), aFilter, preferCompositorSurface, 1260 preferExternalCompositing); 1261 break; 1262 } 1263 case gfx::SurfaceFormat::NV12: { 1264 MOZ_ASSERT(aImageKeys.length() == 2); 1265 aBuilder.PushNV12Image( 1266 aBounds, aClip, true, aImageKeys[0], aImageKeys[1], 1267 GetFormat() == gfx::SurfaceFormat::NV12 ? wr::ColorDepth::Color8 1268 : wr::ColorDepth::Color16, 1269 wr::ToWrYuvColorSpace(ToYUVColorSpace(mColorSpace)), 1270 wr::ToWrColorRange(mColorRange), aFilter, preferCompositorSurface, 1271 preferExternalCompositing); 1272 break; 1273 } 1274 case gfx::SurfaceFormat::A8R8G8B8: 1275 case gfx::SurfaceFormat::X8R8G8B8: 1276 case gfx::SurfaceFormat::R8G8B8: 1277 case gfx::SurfaceFormat::B8G8R8: 1278 case gfx::SurfaceFormat::R5G6B5_UINT16: 1279 case gfx::SurfaceFormat::A8: 1280 case gfx::SurfaceFormat::A16: 1281 case gfx::SurfaceFormat::R8G8: 1282 case gfx::SurfaceFormat::R16G16: 1283 case gfx::SurfaceFormat::YUV420: 1284 case gfx::SurfaceFormat::YUV420P10: 1285 case gfx::SurfaceFormat::YUV422P10: 1286 case gfx::SurfaceFormat::NV16: 1287 case gfx::SurfaceFormat::YUY2: 1288 case gfx::SurfaceFormat::HSV: 1289 case gfx::SurfaceFormat::Lab: 1290 case gfx::SurfaceFormat::Depth: 1291 case gfx::SurfaceFormat::UNKNOWN: { 1292 // Per advice from Sotaro, these formats are not supported for video. 1293 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1294 } 1295 } 1296 } 1297 1298 bool DXGITextureHostD3D11::SupportsExternalCompositing( 1299 WebRenderBackend aBackend) { 1300 if (aBackend == WebRenderBackend::SOFTWARE) { 1301 return true; 1302 } 1303 if (GetFormat() == gfx::SurfaceFormat::NV12 || 1304 GetFormat() == gfx::SurfaceFormat::P010 || 1305 GetFormat() == gfx::SurfaceFormat::P016) { 1306 if ((mFlags & TextureFlags::SOFTWARE_DECODED_VIDEO) && 1307 (gfx::gfxVars::UseWebRenderDCompVideoSwOverlayWin())) { 1308 return true; 1309 } 1310 if (!(mFlags & TextureFlags::SOFTWARE_DECODED_VIDEO) && 1311 (gfx::gfxVars::UseWebRenderDCompVideoHwOverlayWin())) { 1312 return true; 1313 } 1314 } 1315 1316 bool useDcompTextureOverlay = 1317 wr::RenderDXGITextureHost::UseDCompositionTextureOverlay(GetFormat()) && 1318 mFencesHolderId.isSome() && 1319 !(mFlags & TextureFlags::ALLOC_BY_BUFFER_PROVIDER); 1320 if (useDcompTextureOverlay) { 1321 return true; 1322 } 1323 1324 return false; 1325 } 1326 1327 void DXGITextureHostD3D11::NotifyNotUsed() { 1328 if (!mReadFence || mFencesHolderId.isNothing()) { 1329 return; 1330 } 1331 1332 auto* fenceHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 1333 if (!fenceHolderMap) { 1334 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1335 return; 1336 } 1337 fenceHolderMap->SetReadFence(mFencesHolderId.ref(), mReadFence); 1338 mReadFence = nullptr; 1339 } 1340 1341 void DXGITextureHostD3D11::SetReadFence(Fence* aReadFence) { 1342 MOZ_ASSERT(aReadFence); 1343 MOZ_ASSERT(aReadFence->AsFenceD3D11()); 1344 1345 if (!aReadFence || !aReadFence->AsFenceD3D11() || 1346 mFencesHolderId.isNothing()) { 1347 return; 1348 } 1349 1350 mReadFence = aReadFence->AsFenceD3D11(); 1351 } 1352 1353 DXGIYCbCrTextureHostD3D11::DXGIYCbCrTextureHostD3D11( 1354 TextureFlags aFlags, const SurfaceDescriptorDXGIYCbCr& aDescriptor) 1355 : TextureHost(TextureHostType::DXGIYCbCr, aFlags), 1356 mHandles{aDescriptor.handleY(), aDescriptor.handleCb(), 1357 aDescriptor.handleCr()}, 1358 mSize(aDescriptor.size()), 1359 mSizeY(aDescriptor.sizeY()), 1360 mSizeCbCr(aDescriptor.sizeCbCr()), 1361 mColorDepth(aDescriptor.colorDepth()), 1362 mYUVColorSpace(aDescriptor.yUVColorSpace()), 1363 mColorRange(aDescriptor.colorRange()), 1364 mFencesHolderId(aDescriptor.fencesHolderId()) { 1365 if (auto* fenceHolderMap = CompositeProcessD3D11FencesHolderMap::Get()) { 1366 fenceHolderMap->RegisterReference(mFencesHolderId); 1367 } else { 1368 MOZ_ASSERT_UNREACHABLE("FencesHolderMap not available"); 1369 } 1370 } 1371 1372 DXGIYCbCrTextureHostD3D11::~DXGIYCbCrTextureHostD3D11() { 1373 if (auto* fenceHolderMap = CompositeProcessD3D11FencesHolderMap::Get()) { 1374 fenceHolderMap->Unregister(mFencesHolderId); 1375 } else { 1376 MOZ_ASSERT_UNREACHABLE("FencesHolderMap not available"); 1377 } 1378 } 1379 1380 void DXGIYCbCrTextureHostD3D11::CreateRenderTexture( 1381 const wr::ExternalImageId& aExternalImageId) { 1382 MOZ_ASSERT(mExternalImageId.isSome()); 1383 1384 RefPtr<wr::RenderTextureHost> texture = new wr::RenderDXGIYCbCrTextureHost( 1385 mHandles, mYUVColorSpace, mColorDepth, mColorRange, mSizeY, mSizeCbCr, 1386 mFencesHolderId); 1387 1388 wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, 1389 texture.forget()); 1390 } 1391 1392 uint32_t DXGIYCbCrTextureHostD3D11::NumSubTextures() { 1393 // ycbcr use 3 sub textures. 1394 return 3; 1395 } 1396 1397 void DXGIYCbCrTextureHostD3D11::PushResourceUpdates( 1398 wr::TransactionBuilder& aResources, ResourceUpdateOp aOp, 1399 const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) { 1400 if (!gfx::gfxVars::UseWebRenderANGLE()) { 1401 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE"); 1402 return; 1403 } 1404 1405 MOZ_ASSERT(mHandles[0] && mHandles[1] && mHandles[2]); 1406 MOZ_ASSERT(aImageKeys.length() == 3); 1407 // Assume the chroma planes are rounded up if the luma plane is odd sized. 1408 MOZ_ASSERT((mSizeCbCr.width == mSizeY.width || 1409 mSizeCbCr.width == (mSizeY.width + 1) >> 1) && 1410 (mSizeCbCr.height == mSizeY.height || 1411 mSizeCbCr.height == (mSizeY.height + 1) >> 1)); 1412 1413 auto method = aOp == TextureHost::ADD_IMAGE 1414 ? &wr::TransactionBuilder::AddExternalImage 1415 : &wr::TransactionBuilder::UpdateExternalImage; 1416 1417 // Prefer TextureExternal unless the backend requires TextureRect. 1418 // Use a size that is the maximum of the Y and CbCr sizes. 1419 IntSize textureSize = std::max(mSizeY, mSizeCbCr); 1420 TextureHost::NativeTexturePolicy policy = 1421 TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(), 1422 textureSize); 1423 auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE 1424 ? wr::ExternalImageType::TextureHandle( 1425 wr::ImageBufferKind::TextureRect) 1426 : wr::ExternalImageType::TextureHandle( 1427 wr::ImageBufferKind::TextureExternal); 1428 1429 // y 1430 wr::ImageDescriptor descriptor0(mSizeY, gfx::SurfaceFormat::A8); 1431 // cb and cr 1432 wr::ImageDescriptor descriptor1(mSizeCbCr, gfx::SurfaceFormat::A8); 1433 (aResources.*method)(aImageKeys[0], descriptor0, aExtID, imageType, 0, 1434 /* aNormalizedUvs */ false); 1435 (aResources.*method)(aImageKeys[1], descriptor1, aExtID, imageType, 1, 1436 /* aNormalizedUvs */ false); 1437 (aResources.*method)(aImageKeys[2], descriptor1, aExtID, imageType, 2, 1438 /* aNormalizedUvs */ false); 1439 } 1440 1441 void DXGIYCbCrTextureHostD3D11::PushDisplayItems( 1442 wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, 1443 const wr::LayoutRect& aClip, wr::ImageRendering aFilter, 1444 const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) { 1445 if (!gfx::gfxVars::UseWebRenderANGLE()) { 1446 MOZ_ASSERT_UNREACHABLE("unexpected to be called without ANGLE"); 1447 return; 1448 } 1449 1450 MOZ_ASSERT(aImageKeys.length() == 3); 1451 1452 aBuilder.PushYCbCrPlanarImage( 1453 aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2], 1454 wr::ToWrColorDepth(mColorDepth), wr::ToWrYuvColorSpace(mYUVColorSpace), 1455 wr::ToWrColorRange(mColorRange), aFilter, 1456 aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE), 1457 SupportsExternalCompositing(aBuilder.GetBackendType())); 1458 } 1459 1460 bool DXGIYCbCrTextureHostD3D11::SupportsExternalCompositing( 1461 WebRenderBackend aBackend) { 1462 return aBackend == WebRenderBackend::SOFTWARE; 1463 } 1464 1465 void DXGIYCbCrTextureHostD3D11::NotifyNotUsed() { 1466 if (!mReadFence) { 1467 return; 1468 } 1469 1470 auto* fenceHolderMap = CompositeProcessD3D11FencesHolderMap::Get(); 1471 if (!fenceHolderMap) { 1472 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 1473 return; 1474 } 1475 fenceHolderMap->SetReadFence(mFencesHolderId, mReadFence); 1476 mReadFence = nullptr; 1477 } 1478 1479 void DXGIYCbCrTextureHostD3D11::SetReadFence(Fence* aReadFence) { 1480 MOZ_ASSERT(aReadFence); 1481 MOZ_ASSERT(aReadFence->AsFenceD3D11()); 1482 1483 if (!aReadFence || !aReadFence->AsFenceD3D11()) { 1484 return; 1485 } 1486 1487 mReadFence = aReadFence->AsFenceD3D11(); 1488 } 1489 1490 bool DataTextureSourceD3D11::Update(DataSourceSurface* aSurface, 1491 nsIntRegion* aDestRegion, 1492 IntPoint* aSrcOffset, 1493 IntPoint* aDstOffset) { 1494 // Incremental update with a source offset is only used on Mac so it is not 1495 // clear that we ever will need to support it for D3D. 1496 MOZ_ASSERT(!aSrcOffset); 1497 MOZ_RELEASE_ASSERT(!aDstOffset); 1498 MOZ_ASSERT(aSurface); 1499 1500 MOZ_ASSERT(mAllowTextureUploads); 1501 if (!mAllowTextureUploads) { 1502 return false; 1503 } 1504 1505 HRESULT hr; 1506 1507 if (!mDevice) { 1508 return false; 1509 } 1510 1511 uint32_t bpp = BytesPerPixel(aSurface->GetFormat()); 1512 DXGI_FORMAT dxgiFormat = SurfaceFormatToDXGIFormat(aSurface->GetFormat()); 1513 1514 mSize = aSurface->GetSize(); 1515 mFormat = aSurface->GetFormat(); 1516 1517 CD3D11_TEXTURE2D_DESC desc(dxgiFormat, mSize.width, mSize.height, 1, 1); 1518 1519 int32_t maxSize = GetMaxTextureSizeFromDevice(mDevice); 1520 if ((mSize.width <= maxSize && mSize.height <= maxSize) || 1521 (mFlags & TextureFlags::DISALLOW_BIGIMAGE)) { 1522 if (mTexture) { 1523 D3D11_TEXTURE2D_DESC currentDesc; 1524 mTexture->GetDesc(¤tDesc); 1525 1526 // Make sure there's no size mismatch, if there is, recreate. 1527 if (static_cast<int32_t>(currentDesc.Width) != mSize.width || 1528 static_cast<int32_t>(currentDesc.Height) != mSize.height || 1529 currentDesc.Format != dxgiFormat) { 1530 mTexture = nullptr; 1531 // Make sure we upload the whole surface. 1532 aDestRegion = nullptr; 1533 } 1534 } 1535 1536 nsIntRegion* regionToUpdate = aDestRegion; 1537 if (!mTexture) { 1538 hr = mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(mTexture)); 1539 mIsTiled = false; 1540 if (FAILED(hr) || !mTexture) { 1541 Reset(); 1542 return false; 1543 } 1544 1545 if (mFlags & TextureFlags::COMPONENT_ALPHA) { 1546 regionToUpdate = nullptr; 1547 } 1548 } 1549 1550 DataSourceSurface::MappedSurface map; 1551 if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) { 1552 gfxCriticalError() << "Failed to map surface."; 1553 Reset(); 1554 return false; 1555 } 1556 1557 RefPtr<ID3D11DeviceContext> context; 1558 mDevice->GetImmediateContext(getter_AddRefs(context)); 1559 1560 if (regionToUpdate) { 1561 for (auto iter = regionToUpdate->RectIter(); !iter.Done(); iter.Next()) { 1562 const IntRect& rect = iter.Get(); 1563 D3D11_BOX box; 1564 box.front = 0; 1565 box.back = 1; 1566 box.left = rect.X(); 1567 box.top = rect.Y(); 1568 box.right = rect.XMost(); 1569 box.bottom = rect.YMost(); 1570 1571 void* data = map.mData + map.mStride * rect.Y() + 1572 BytesPerPixel(aSurface->GetFormat()) * rect.X(); 1573 1574 context->UpdateSubresource(mTexture, 0, &box, data, map.mStride, 1575 map.mStride * rect.Height()); 1576 } 1577 } else { 1578 context->UpdateSubresource(mTexture, 0, nullptr, map.mData, map.mStride, 1579 map.mStride * mSize.height); 1580 } 1581 1582 aSurface->Unmap(); 1583 } else { 1584 mIsTiled = true; 1585 uint32_t tileCount = GetRequiredTilesD3D11(mSize.width, maxSize) * 1586 GetRequiredTilesD3D11(mSize.height, maxSize); 1587 1588 mTileTextures.resize(tileCount); 1589 mTileSRVs.resize(tileCount); 1590 mTexture = nullptr; 1591 1592 DataSourceSurface::ScopedMap map(aSurface, DataSourceSurface::READ); 1593 if (!map.IsMapped()) { 1594 gfxCriticalError() << "Failed to map surface."; 1595 Reset(); 1596 return false; 1597 } 1598 1599 for (uint32_t i = 0; i < tileCount; i++) { 1600 IntRect tileRect = GetTileRect(i); 1601 1602 desc.Width = tileRect.Width(); 1603 desc.Height = tileRect.Height(); 1604 desc.Usage = D3D11_USAGE_IMMUTABLE; 1605 1606 D3D11_SUBRESOURCE_DATA initData; 1607 initData.pSysMem = 1608 map.GetData() + tileRect.Y() * map.GetStride() + tileRect.X() * bpp; 1609 initData.SysMemPitch = map.GetStride(); 1610 1611 hr = mDevice->CreateTexture2D(&desc, &initData, 1612 getter_AddRefs(mTileTextures[i])); 1613 if (FAILED(hr) || !mTileTextures[i]) { 1614 Reset(); 1615 return false; 1616 } 1617 } 1618 } 1619 return true; 1620 } 1621 1622 ID3D11Texture2D* DataTextureSourceD3D11::GetD3D11Texture() const { 1623 return mIterating ? mTileTextures[mCurrentTile] : mTexture; 1624 } 1625 1626 RefPtr<TextureSource> DataTextureSourceD3D11::ExtractCurrentTile() { 1627 MOZ_ASSERT(mIterating); 1628 return new DataTextureSourceD3D11(mDevice, mFormat, 1629 mTileTextures[mCurrentTile]); 1630 } 1631 1632 ID3D11ShaderResourceView* DataTextureSourceD3D11::GetShaderResourceView() { 1633 if (mIterating) { 1634 if (!mTileSRVs[mCurrentTile]) { 1635 if (!mTileTextures[mCurrentTile]) { 1636 return nullptr; 1637 } 1638 1639 RefPtr<ID3D11Device> device; 1640 mTileTextures[mCurrentTile]->GetDevice(getter_AddRefs(device)); 1641 HRESULT hr = device->CreateShaderResourceView( 1642 mTileTextures[mCurrentTile], nullptr, 1643 getter_AddRefs(mTileSRVs[mCurrentTile])); 1644 if (FAILED(hr)) { 1645 gfxCriticalNote 1646 << "[D3D11] DataTextureSourceD3D11:GetShaderResourceView CreateSRV " 1647 "failure " 1648 << gfx::hexa(hr); 1649 return nullptr; 1650 } 1651 } 1652 return mTileSRVs[mCurrentTile]; 1653 } 1654 1655 return TextureSourceD3D11::GetShaderResourceView(); 1656 } 1657 1658 void DataTextureSourceD3D11::Reset() { 1659 mTexture = nullptr; 1660 mTileSRVs.resize(0); 1661 mTileTextures.resize(0); 1662 mIsTiled = false; 1663 mSize.width = 0; 1664 mSize.height = 0; 1665 } 1666 1667 IntRect DataTextureSourceD3D11::GetTileRect(uint32_t aIndex) const { 1668 return GetTileRectD3D11(aIndex, mSize, GetMaxTextureSizeFromDevice(mDevice)); 1669 } 1670 1671 IntRect DataTextureSourceD3D11::GetTileRect() { 1672 IntRect rect = GetTileRect(mCurrentTile); 1673 return IntRect(rect.X(), rect.Y(), rect.Width(), rect.Height()); 1674 } 1675 1676 CompositingRenderTargetD3D11::CompositingRenderTargetD3D11( 1677 ID3D11Texture2D* aTexture, const gfx::IntPoint& aOrigin, 1678 DXGI_FORMAT aFormatOverride) 1679 : CompositingRenderTarget(aOrigin) { 1680 MOZ_ASSERT(aTexture); 1681 1682 mTexture = aTexture; 1683 1684 RefPtr<ID3D11Device> device; 1685 mTexture->GetDevice(getter_AddRefs(device)); 1686 1687 mFormatOverride = aFormatOverride; 1688 1689 // If we happen to have a typeless underlying DXGI surface, we need to be 1690 // explicit about the format here. (Such a surface could come from an external 1691 // source, such as the Oculus compositor) 1692 CD3D11_RENDER_TARGET_VIEW_DESC rtvDesc(D3D11_RTV_DIMENSION_TEXTURE2D, 1693 mFormatOverride); 1694 D3D11_RENDER_TARGET_VIEW_DESC* desc = 1695 aFormatOverride == DXGI_FORMAT_UNKNOWN ? nullptr : &rtvDesc; 1696 1697 HRESULT hr = 1698 device->CreateRenderTargetView(mTexture, desc, getter_AddRefs(mRTView)); 1699 1700 if (FAILED(hr)) { 1701 LOGD3D11("Failed to create RenderTargetView."); 1702 } 1703 } 1704 1705 void CompositingRenderTargetD3D11::BindRenderTarget( 1706 ID3D11DeviceContext* aContext) { 1707 if (mClearOnBind) { 1708 FLOAT clear[] = {0, 0, 0, 0}; 1709 aContext->ClearRenderTargetView(mRTView, clear); 1710 mClearOnBind = false; 1711 } 1712 ID3D11RenderTargetView* view = mRTView; 1713 aContext->OMSetRenderTargets(1, &view, nullptr); 1714 } 1715 1716 IntSize CompositingRenderTargetD3D11::GetSize() const { 1717 return TextureSourceD3D11::GetSize(); 1718 } 1719 1720 static inline bool ShouldDevCrashOnSyncInitFailure() { 1721 // Compositor shutdown does not wait for video decoding to finish, so it is 1722 // possible for the compositor to destroy the SyncObject before video has a 1723 // chance to initialize it. 1724 if (!NS_IsMainThread()) { 1725 return false; 1726 } 1727 1728 // Note: CompositorIsInGPUProcess is a main-thread-only function. 1729 return !CompositorBridgeChild::CompositorIsInGPUProcess() && 1730 !DeviceManagerDx::Get()->HasDeviceReset(); 1731 } 1732 1733 SyncObjectD3D11Host::SyncObjectD3D11Host(ID3D11Device* aDevice) 1734 : mSyncHandle(nullptr), mDevice(aDevice) { 1735 MOZ_ASSERT(aDevice); 1736 } 1737 1738 bool SyncObjectD3D11Host::Init() { 1739 CD3D11_TEXTURE2D_DESC desc( 1740 DXGI_FORMAT_B8G8R8A8_UNORM, 1, 1, 1, 1, 1741 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); 1742 desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE | 1743 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; 1744 1745 RefPtr<ID3D11Texture2D> texture; 1746 HRESULT hr = 1747 mDevice->CreateTexture2D(&desc, nullptr, getter_AddRefs(texture)); 1748 if (FAILED(hr) || !texture) { 1749 gfxWarning() << "Could not create a sync texture: " << gfx::hexa(hr); 1750 return false; 1751 } 1752 1753 hr = texture->QueryInterface((IDXGIResource1**)getter_AddRefs(mSyncTexture)); 1754 if (FAILED(hr) || !mSyncTexture) { 1755 gfxWarning() << "Could not QI sync texture: " << gfx::hexa(hr); 1756 return false; 1757 } 1758 1759 hr = mSyncTexture->QueryInterface( 1760 (IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutex)); 1761 if (FAILED(hr) || !mKeyedMutex) { 1762 gfxWarning() << "Could not QI keyed-mutex: " << gfx::hexa(hr); 1763 return false; 1764 } 1765 1766 HANDLE sharedHandle; 1767 hr = mSyncTexture->CreateSharedHandle( 1768 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, 1769 &sharedHandle); 1770 if (FAILED(hr)) { 1771 gfxWarning() << "Could not get sync texture shared handle: " 1772 << gfx::hexa(hr); 1773 return false; 1774 } 1775 mSyncHandle = new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); 1776 1777 return true; 1778 } 1779 1780 SyncHandle SyncObjectD3D11Host::GetSyncHandle() { return mSyncHandle; } 1781 1782 bool SyncObjectD3D11Host::Synchronize(bool aFallible) { 1783 HRESULT hr; 1784 AutoTextureLock lock(mKeyedMutex, hr, 10000); 1785 1786 if (hr == WAIT_TIMEOUT) { 1787 hr = mDevice->GetDeviceRemovedReason(); 1788 if (hr != S_OK) { 1789 // Since the timeout is related to the driver-removed. Return false for 1790 // error handling. 1791 gfxCriticalNote << "GFX: D3D11 timeout with device-removed:" 1792 << gfx::hexa(hr); 1793 } else if (aFallible) { 1794 gfxCriticalNote << "GFX: D3D11 timeout on the D3D11 sync lock."; 1795 } else { 1796 // There is no driver-removed event. Crash with this timeout. 1797 MOZ_CRASH("GFX: D3D11 normal status timeout"); 1798 } 1799 1800 return false; 1801 } 1802 if (hr == WAIT_ABANDONED) { 1803 gfxCriticalNote << "GFX: AL_D3D11 abandoned sync"; 1804 } 1805 1806 return true; 1807 } 1808 1809 SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle, 1810 ID3D11Device* aDevice) 1811 : mSyncLock("SyncObjectD3D11"), mSyncHandle(aSyncHandle), mDevice(aDevice) { 1812 MOZ_ASSERT(aDevice); 1813 } 1814 1815 SyncObjectD3D11Client::SyncObjectD3D11Client(SyncHandle aSyncHandle) 1816 : mSyncLock("SyncObjectD3D11"), mSyncHandle(aSyncHandle) {} 1817 1818 bool SyncObjectD3D11Client::Init(ID3D11Device* aDevice, bool aFallible) { 1819 if (mKeyedMutex) { 1820 return true; 1821 } 1822 1823 if (!mSyncHandle) { 1824 return false; 1825 } 1826 1827 RefPtr<ID3D11Device1> device1; 1828 aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1)); 1829 if (!device1) { 1830 gfxCriticalNoteOnce << "Failed to get ID3D11Device1"; 1831 return 0; 1832 } 1833 1834 HRESULT hr = device1->OpenSharedResource1( 1835 mSyncHandle->GetHandle(), __uuidof(ID3D11Texture2D), 1836 (void**)(ID3D11Texture2D**)getter_AddRefs(mSyncTexture)); 1837 if (FAILED(hr) || !mSyncTexture) { 1838 gfxCriticalNote << "Failed to OpenSharedResource1 for SyncObjectD3D11: " 1839 << hexa(hr); 1840 if (!aFallible && ShouldDevCrashOnSyncInitFailure()) { 1841 gfxDevCrash(LogReason::D3D11FinalizeFrame) 1842 << "Without device reset: " << hexa(hr); 1843 } 1844 return false; 1845 } 1846 1847 hr = mSyncTexture->QueryInterface(__uuidof(IDXGIKeyedMutex), 1848 getter_AddRefs(mKeyedMutex)); 1849 if (FAILED(hr) || !mKeyedMutex) { 1850 // Leave both the critical error and MOZ_CRASH for now; the critical error 1851 // lets us "save" the hr value. We will probably eventually replace this 1852 // with gfxDevCrash. 1853 if (!aFallible) { 1854 gfxCriticalError() << "Failed to get KeyedMutex (2): " << hexa(hr); 1855 MOZ_CRASH("GFX: Cannot get D3D11 KeyedMutex"); 1856 } else { 1857 gfxCriticalNote << "Failed to get KeyedMutex (3): " << hexa(hr); 1858 } 1859 return false; 1860 } 1861 1862 return true; 1863 } 1864 1865 void SyncObjectD3D11Client::RegisterTexture(ID3D11Texture2D* aTexture) { 1866 mSyncedTextures.push_back(aTexture); 1867 } 1868 1869 bool SyncObjectD3D11Client::IsSyncObjectValid() { 1870 MOZ_ASSERT(mDevice); 1871 return true; 1872 } 1873 1874 // We have only 1 sync object. As a thing that somehow works, 1875 // we copy each of the textures that need to be synced with the compositor 1876 // into our sync object and only use a lock for this sync object. 1877 // This way, we don't have to sync every texture we send to the compositor. 1878 // We only have to do this once per transaction. 1879 bool SyncObjectD3D11Client::Synchronize(bool aFallible) { 1880 MOZ_ASSERT(mDevice); 1881 // Since this can be called from either the Paint or Main thread. 1882 // We don't want this to race since we initialize the sync texture here 1883 // too. 1884 MutexAutoLock syncLock(mSyncLock); 1885 1886 if (!mSyncedTextures.size()) { 1887 return true; 1888 } 1889 if (!Init(mDevice, aFallible)) { 1890 return false; 1891 } 1892 1893 return SynchronizeInternal(mDevice, aFallible); 1894 } 1895 1896 bool SyncObjectD3D11Client::SynchronizeInternal(ID3D11Device* aDevice, 1897 bool aFallible) { 1898 mSyncLock.AssertCurrentThreadOwns(); 1899 1900 HRESULT hr; 1901 AutoTextureLock lock(mKeyedMutex, hr, 20000); 1902 1903 if (hr == WAIT_TIMEOUT) { 1904 if (DeviceManagerDx::Get()->HasDeviceReset()) { 1905 gfxWarning() << "AcquireSync timed out because of device reset."; 1906 return false; 1907 } 1908 if (aFallible) { 1909 gfxWarning() << "Timeout on the D3D11 sync lock."; 1910 } else { 1911 gfxDevCrash(LogReason::D3D11SyncLock) 1912 << "Timeout on the D3D11 sync lock."; 1913 } 1914 return false; 1915 } 1916 1917 D3D11_BOX box; 1918 box.front = box.top = box.left = 0; 1919 box.back = box.bottom = box.right = 1; 1920 1921 RefPtr<ID3D11DeviceContext> ctx; 1922 aDevice->GetImmediateContext(getter_AddRefs(ctx)); 1923 1924 for (auto iter = mSyncedTextures.begin(); iter != mSyncedTextures.end(); 1925 iter++) { 1926 ctx->CopySubresourceRegion(mSyncTexture, 0, 0, 0, 0, *iter, 0, &box); 1927 } 1928 1929 mSyncedTextures.clear(); 1930 1931 return true; 1932 } 1933 1934 uint32_t GetMaxTextureSizeFromDevice(ID3D11Device* aDevice) { 1935 return GetMaxTextureSizeForFeatureLevel(aDevice->GetFeatureLevel()); 1936 } 1937 1938 AutoLockD3D11Texture::AutoLockD3D11Texture(ID3D11Texture2D* aTexture) { 1939 aTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex)); 1940 if (!mMutex) { 1941 return; 1942 } 1943 HRESULT hr = mMutex->AcquireSync(0, 10000); 1944 if (hr == WAIT_TIMEOUT) { 1945 MOZ_CRASH("GFX: IMFYCbCrImage timeout"); 1946 } 1947 1948 if (FAILED(hr)) { 1949 NS_WARNING("Failed to lock the texture"); 1950 } 1951 } 1952 1953 AutoLockD3D11Texture::~AutoLockD3D11Texture() { 1954 if (!mMutex) { 1955 return; 1956 } 1957 HRESULT hr = mMutex->ReleaseSync(0); 1958 if (FAILED(hr)) { 1959 NS_WARNING("Failed to unlock the texture"); 1960 } 1961 } 1962 1963 SyncObjectD3D11ClientContentDevice::SyncObjectD3D11ClientContentDevice( 1964 SyncHandle aSyncHandle) 1965 : SyncObjectD3D11Client(aSyncHandle) {} 1966 1967 bool SyncObjectD3D11ClientContentDevice::Synchronize(bool aFallible) { 1968 // Since this can be called from either the Paint or Main thread. 1969 // We don't want this to race since we initialize the sync texture here 1970 // too. 1971 MutexAutoLock syncLock(mSyncLock); 1972 1973 MOZ_ASSERT(mContentDevice); 1974 1975 if (!mSyncedTextures.size()) { 1976 return true; 1977 } 1978 1979 if (!Init(mContentDevice, aFallible)) { 1980 return false; 1981 } 1982 1983 RefPtr<ID3D11Device> dev; 1984 mSyncTexture->GetDevice(getter_AddRefs(dev)); 1985 1986 if (dev == DeviceManagerDx::Get()->GetContentDevice()) { 1987 if (DeviceManagerDx::Get()->HasDeviceReset()) { 1988 return false; 1989 } 1990 } 1991 1992 if (dev != mContentDevice) { 1993 gfxWarning() << "Attempt to sync texture from invalid device."; 1994 return false; 1995 } 1996 1997 return SyncObjectD3D11Client::SynchronizeInternal(dev, aFallible); 1998 } 1999 2000 bool SyncObjectD3D11ClientContentDevice::IsSyncObjectValid() { 2001 RefPtr<ID3D11Device> dev; 2002 // There is a case that devices are not initialized yet with WebRender. 2003 if (gfxPlatform::GetPlatform()->DevicesInitialized()) { 2004 dev = DeviceManagerDx::Get()->GetContentDevice(); 2005 } 2006 2007 // Update mDevice if the ContentDevice initialization is detected. 2008 if (!mContentDevice && dev && NS_IsMainThread()) { 2009 mContentDevice = dev; 2010 } 2011 2012 if (!dev || (NS_IsMainThread() && dev != mContentDevice)) { 2013 return false; 2014 } 2015 return true; 2016 } 2017 2018 void SyncObjectD3D11ClientContentDevice::EnsureInitialized() { 2019 if (mContentDevice) { 2020 return; 2021 } 2022 2023 if (XRE_IsGPUProcess() || !gfxPlatform::GetPlatform()->DevicesInitialized()) { 2024 return; 2025 } 2026 2027 mContentDevice = DeviceManagerDx::Get()->GetContentDevice(); 2028 } 2029 2030 } // namespace layers 2031 } // namespace mozilla