RenderD3D11TextureHost.cpp (25528B)
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 "RenderD3D11TextureHost.h" 8 9 #include <dcomp.h> 10 11 #include "GLContextEGL.h" 12 #include "GLLibraryEGL.h" 13 #include "RenderThread.h" 14 #include "RenderCompositor.h" 15 #include "RenderCompositorD3D11SWGL.h" 16 #include "ScopedGLHelpers.h" 17 #include "mozilla/gfx/CanvasManagerParent.h" 18 #include "mozilla/gfx/DeviceManagerDx.h" 19 #include "mozilla/gfx/gfxVars.h" 20 #include "mozilla/gfx/Logging.h" 21 #include "mozilla/layers/FenceD3D11.h" 22 #include "mozilla/layers/GpuProcessD3D11TextureMap.h" 23 #include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h" 24 #include "mozilla/layers/TextureD3D11.h" 25 26 namespace mozilla { 27 namespace wr { 28 29 RenderDXGITextureHost::RenderDXGITextureHost( 30 const RefPtr<gfx::FileHandleWrapper> aHandle, 31 const Maybe<layers::GpuProcessTextureId>& aGpuProcessTextureId, 32 const uint32_t aArrayIndex, const gfx::SurfaceFormat aFormat, 33 const gfx::ColorSpace2 aColorSpace, const gfx::ColorRange aColorRange, 34 const gfx::IntSize aSize, bool aHasKeyedMutex, 35 const Maybe<layers::CompositeProcessFencesHolderId>& aFencesHolderId) 36 : mHandle(aHandle), 37 mGpuProcessTextureId(aGpuProcessTextureId), 38 mArrayIndex(aArrayIndex), 39 mSurface(0), 40 mStream(0), 41 mTextureHandle{0}, 42 mFormat(aFormat), 43 mColorSpace(aColorSpace), 44 mColorRange(aColorRange), 45 mSize(aSize), 46 mHasKeyedMutex(aHasKeyedMutex), 47 mFencesHolderId(aFencesHolderId), 48 mLocked(false) { 49 MOZ_COUNT_CTOR_INHERITED(RenderDXGITextureHost, RenderTextureHost); 50 MOZ_ASSERT((mFormat != gfx::SurfaceFormat::NV12 && 51 mFormat != gfx::SurfaceFormat::P010 && 52 mFormat != gfx::SurfaceFormat::P016) || 53 (mSize.width % 2 == 0 && mSize.height % 2 == 0)); 54 MOZ_ASSERT(!(!aHandle && aGpuProcessTextureId.isNothing())); 55 } 56 57 RenderDXGITextureHost::~RenderDXGITextureHost() { 58 MOZ_COUNT_DTOR_INHERITED(RenderDXGITextureHost, RenderTextureHost); 59 DeleteTextureHandle(); 60 } 61 62 /* static */ 63 bool RenderDXGITextureHost::UseDCompositionTextureOverlay( 64 gfx::SurfaceFormat aFormat) { 65 if (!gfx::gfxVars::UseWebRenderDCompositionTextureOverlayWin()) { 66 return false; 67 } 68 69 if (!gfx::DeviceManagerDx::Get()->CanUseDCompositionTexture()) { 70 return false; 71 } 72 73 if (aFormat != gfx::SurfaceFormat::B8G8R8A8 && 74 aFormat != gfx::SurfaceFormat::B8G8R8X8) { 75 return false; 76 } 77 78 return true; 79 } 80 81 IDCompositionTexture* RenderDXGITextureHost::GetDCompositionTexture() { 82 if (mDCompositionTexture) { 83 return mDCompositionTexture; 84 } 85 86 if (!UseDCompositionTextureOverlay(mFormat)) { 87 return nullptr; 88 } 89 90 if (mFencesHolderId.isNothing()) { 91 MOZ_ASSERT_UNREACHABLE("Unexpected to be called!"); 92 return nullptr; 93 } 94 95 HRESULT hr; 96 RefPtr<IDCompositionDevice2> dcomp = 97 gfx::DeviceManagerDx::Get()->GetDirectCompositionDevice(); 98 if (!dcomp) { 99 MOZ_ASSERT_UNREACHABLE("Unexpected to be called!"); 100 gfxCriticalNoteOnce << "Failed to get DirectCompositionDevice"; 101 return nullptr; 102 } 103 104 RefPtr<IDCompositionDevice4> dcomp4; 105 hr = dcomp->QueryInterface((IDCompositionDevice4**)getter_AddRefs(dcomp4)); 106 if (FAILED(hr)) { 107 MOZ_ASSERT_UNREACHABLE("Unexpected to be called!"); 108 gfxCriticalNoteOnce << "Failed to get DCompositionDevice4"; 109 return nullptr; 110 } 111 112 RefPtr<ID3D11Texture2D> texture2D = GetD3D11Texture2DWithGL(); 113 if (!texture2D) { 114 gfxCriticalNoteOnce << "Failed to get D3D11Texture"; 115 return nullptr; 116 } 117 118 RefPtr<IDCompositionTexture> dcompTexture; 119 hr = 120 dcomp4->CreateCompositionTexture(texture2D, getter_AddRefs(dcompTexture)); 121 if (FAILED(hr)) { 122 gfxCriticalNoteOnce << "CreateCompositionTexture failed: " 123 << gfx::hexa(hr); 124 return nullptr; 125 } 126 127 mDCompositionTexture = dcompTexture; 128 129 return mDCompositionTexture; 130 } 131 132 ID3D11Texture2D* RenderDXGITextureHost::GetD3D11Texture2DWithGL() { 133 if (mTexture) { 134 return mTexture; 135 } 136 137 if (!mGL) { 138 // SingletonGL is always used on Windows with ANGLE. 139 mGL = RenderThread::Get()->SingletonGL(); 140 } 141 142 if (!EnsureD3D11Texture2DWithGL()) { 143 return nullptr; 144 } 145 146 return mTexture; 147 } 148 149 size_t RenderDXGITextureHost::GetPlaneCount() const { 150 switch (mFormat) { 151 case gfx::SurfaceFormat::NV12: 152 case gfx::SurfaceFormat::P010: 153 case gfx::SurfaceFormat::P016: { 154 return 2; 155 } 156 case gfx::SurfaceFormat::B8G8R8A8: 157 case gfx::SurfaceFormat::B8G8R8X8: 158 case gfx::SurfaceFormat::R8G8B8A8: 159 case gfx::SurfaceFormat::R8G8B8X8: 160 case gfx::SurfaceFormat::A8R8G8B8: 161 case gfx::SurfaceFormat::X8R8G8B8: 162 case gfx::SurfaceFormat::R8G8B8: 163 case gfx::SurfaceFormat::B8G8R8: 164 case gfx::SurfaceFormat::R5G6B5_UINT16: 165 case gfx::SurfaceFormat::R10G10B10A2_UINT32: 166 case gfx::SurfaceFormat::R10G10B10X2_UINT32: 167 case gfx::SurfaceFormat::R16G16B16A16F: 168 case gfx::SurfaceFormat::A8: 169 case gfx::SurfaceFormat::A16: 170 case gfx::SurfaceFormat::R8G8: 171 case gfx::SurfaceFormat::R16G16: 172 case gfx::SurfaceFormat::YUV420: 173 case gfx::SurfaceFormat::YUV420P10: 174 case gfx::SurfaceFormat::YUV422P10: 175 case gfx::SurfaceFormat::NV16: 176 case gfx::SurfaceFormat::YUY2: 177 case gfx::SurfaceFormat::HSV: 178 case gfx::SurfaceFormat::Lab: 179 case gfx::SurfaceFormat::Depth: 180 case gfx::SurfaceFormat::UNKNOWN: 181 return 1; 182 } 183 MOZ_ASSERT_UNREACHABLE("unhandled enum value for gfx::SurfaceFormat"); 184 return 1; 185 } 186 187 template <typename T> 188 static bool MapTexture(T* aHost, RenderCompositor* aCompositor, 189 RefPtr<ID3D11Texture2D>& aTexture, 190 RefPtr<ID3D11DeviceContext>& aDeviceContext, 191 RefPtr<ID3D11Texture2D>& aCpuTexture, 192 D3D11_MAPPED_SUBRESOURCE& aMappedSubresource) { 193 if (!aCompositor) { 194 return false; 195 } 196 197 RenderCompositorD3D11SWGL* compositor = 198 aCompositor->AsRenderCompositorD3D11SWGL(); 199 if (!compositor) { 200 return false; 201 } 202 203 if (!aHost->EnsureD3D11Texture2D(compositor->GetDevice())) { 204 return false; 205 } 206 207 if (!aHost->LockInternal()) { 208 return false; 209 } 210 211 D3D11_TEXTURE2D_DESC textureDesc = {0}; 212 aTexture->GetDesc(&textureDesc); 213 214 compositor->GetDevice()->GetImmediateContext(getter_AddRefs(aDeviceContext)); 215 216 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; 217 textureDesc.Usage = D3D11_USAGE_STAGING; 218 textureDesc.BindFlags = 0; 219 textureDesc.MiscFlags = 0; 220 textureDesc.MipLevels = 1; 221 HRESULT hr = compositor->GetDevice()->CreateTexture2D( 222 &textureDesc, nullptr, getter_AddRefs(aCpuTexture)); 223 if (FAILED(hr)) { 224 return false; 225 } 226 227 aDeviceContext->CopyResource(aCpuTexture, aTexture); 228 aHost->Unlock(); 229 230 hr = aDeviceContext->Map(aCpuTexture, 0, D3D11_MAP_READ, 0, 231 &aMappedSubresource); 232 return SUCCEEDED(hr); 233 } 234 235 bool RenderDXGITextureHost::MapPlane(RenderCompositor* aCompositor, 236 uint8_t aChannelIndex, 237 PlaneInfo& aPlaneInfo) { 238 // TODO: We currently readback from the GPU texture into a new 239 // staging texture every time this is mapped. We might be better 240 // off retaining the mapped memory to trade performance for memory 241 // usage. 242 if (!mCpuTexture && !MapTexture(this, aCompositor, mTexture, mDeviceContext, 243 mCpuTexture, mMappedSubresource)) { 244 return false; 245 } 246 247 aPlaneInfo.mSize = GetSize(aChannelIndex); 248 aPlaneInfo.mStride = mMappedSubresource.RowPitch; 249 aPlaneInfo.mData = mMappedSubresource.pData; 250 251 // If this is the second plane, then offset the data pointer by the 252 // size of the first plane. 253 if (aChannelIndex == 1) { 254 aPlaneInfo.mData = 255 (uint8_t*)aPlaneInfo.mData + aPlaneInfo.mStride * GetSize(0).height; 256 } 257 return true; 258 } 259 260 void RenderDXGITextureHost::UnmapPlanes() { 261 mMappedSubresource.pData = nullptr; 262 if (mCpuTexture) { 263 mDeviceContext->Unmap(mCpuTexture, 0); 264 mCpuTexture = nullptr; 265 } 266 mDeviceContext = nullptr; 267 } 268 269 bool RenderDXGITextureHost::EnsureD3D11Texture2DWithGL() { 270 if (mTexture) { 271 return true; 272 } 273 274 const auto& gle = gl::GLContextEGL::Cast(mGL); 275 const auto& egl = gle->mEgl; 276 277 // Fetch the D3D11 device. 278 EGLDeviceEXT eglDevice = nullptr; 279 egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice); 280 MOZ_ASSERT(eglDevice); 281 ID3D11Device* device = nullptr; 282 egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, 283 (EGLAttrib*)&device); 284 // There's a chance this might fail if we end up on d3d9 angle for some 285 // reason. 286 if (!device) { 287 gfxCriticalNote << "RenderDXGITextureHost device is not available"; 288 return false; 289 } 290 291 return EnsureD3D11Texture2D(device); 292 } 293 294 bool RenderDXGITextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) { 295 if (mTexture) { 296 RefPtr<ID3D11Device> device; 297 mTexture->GetDevice(getter_AddRefs(device)); 298 if (aDevice != device) { 299 gfxCriticalNote << "RenderDXGITextureHost uses obsoleted device"; 300 return false; 301 } 302 return true; 303 } 304 305 if (mGpuProcessTextureId.isSome()) { 306 auto* textureMap = layers::GpuProcessD3D11TextureMap::Get(); 307 if (textureMap) { 308 RefPtr<ID3D11Texture2D> texture; 309 textureMap->WaitTextureReady(mGpuProcessTextureId.ref()); 310 mTexture = textureMap->GetTexture(mGpuProcessTextureId.ref()); 311 if (mTexture) { 312 return true; 313 } else { 314 gfxCriticalNote << "GpuProcessTextureId is not valid"; 315 } 316 } 317 return false; 318 } 319 320 RefPtr<ID3D11Device1> device1; 321 aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1)); 322 if (!device1) { 323 gfxCriticalNoteOnce << "Failed to get ID3D11Device1"; 324 return 0; 325 } 326 327 // Get the D3D11 texture from shared handle. 328 HRESULT hr = device1->OpenSharedResource1( 329 (HANDLE)mHandle->GetHandle(), __uuidof(ID3D11Texture2D), 330 (void**)(ID3D11Texture2D**)getter_AddRefs(mTexture)); 331 if (FAILED(hr)) { 332 MOZ_ASSERT(false, 333 "RenderDXGITextureHost::EnsureLockable(): Failed to open shared " 334 "texture"); 335 gfxCriticalNote 336 << "RenderDXGITextureHost Failed to open shared texture, hr=" 337 << gfx::hexa(hr); 338 return false; 339 } 340 MOZ_ASSERT(mTexture.get()); 341 mTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutex)); 342 343 MOZ_ASSERT(mHasKeyedMutex == !!mKeyedMutex); 344 if (mHasKeyedMutex != !!mKeyedMutex) { 345 gfxCriticalNoteOnce << "KeyedMutex mismatch"; 346 } 347 return true; 348 } 349 350 bool RenderDXGITextureHost::EnsureLockable() { 351 if (mTextureHandle[0]) { 352 return true; 353 } 354 355 const auto& gle = gl::GLContextEGL::Cast(mGL); 356 const auto& egl = gle->mEgl; 357 358 // We use EGLStream to get the converted gl handle from d3d texture. The 359 // NV_stream_consumer_gltexture_yuv and ANGLE_stream_producer_d3d_texture 360 // could support nv12 and rgb d3d texture format. 361 if (!egl->IsExtensionSupported( 362 gl::EGLExtension::NV_stream_consumer_gltexture_yuv) || 363 !egl->IsExtensionSupported( 364 gl::EGLExtension::ANGLE_stream_producer_d3d_texture)) { 365 gfxCriticalNote << "RenderDXGITextureHost egl extensions are not suppored"; 366 return false; 367 } 368 369 // Get the D3D11 texture from shared handle. 370 if (!EnsureD3D11Texture2DWithGL()) { 371 return false; 372 } 373 374 // Create the EGLStream. 375 mStream = egl->fCreateStreamKHR(nullptr); 376 MOZ_ASSERT(mStream); 377 378 bool ok = true; 379 if (mFormat != gfx::SurfaceFormat::NV12 && 380 mFormat != gfx::SurfaceFormat::P010 && 381 mFormat != gfx::SurfaceFormat::P016) { 382 // The non-nv12 format. 383 384 mGL->fGenTextures(1, mTextureHandle); 385 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, 386 LOCAL_GL_TEXTURE_EXTERNAL_OES, 387 mTextureHandle[0]); 388 ok &= 389 bool(egl->fStreamConsumerGLTextureExternalAttribsNV(mStream, nullptr)); 390 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStream, nullptr)); 391 } else { 392 // The nv12/p016 format. 393 394 // Setup the NV12 stream consumer/producer. 395 EGLAttrib consumerAttributes[] = { 396 LOCAL_EGL_COLOR_BUFFER_TYPE, 397 LOCAL_EGL_YUV_BUFFER_EXT, 398 LOCAL_EGL_YUV_NUMBER_OF_PLANES_EXT, 399 2, 400 LOCAL_EGL_YUV_PLANE0_TEXTURE_UNIT_NV, 401 0, 402 LOCAL_EGL_YUV_PLANE1_TEXTURE_UNIT_NV, 403 1, 404 LOCAL_EGL_NONE, 405 }; 406 mGL->fGenTextures(2, mTextureHandle); 407 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, 408 LOCAL_GL_TEXTURE_EXTERNAL_OES, 409 mTextureHandle[0]); 410 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE1, 411 LOCAL_GL_TEXTURE_EXTERNAL_OES, 412 mTextureHandle[1]); 413 ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV( 414 mStream, consumerAttributes)); 415 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStream, nullptr)); 416 } 417 418 const EGLAttrib frameAttributes[] = { 419 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 420 static_cast<EGLAttrib>(mArrayIndex), 421 LOCAL_EGL_NONE, 422 }; 423 424 // Insert the d3d texture. 425 ok &= bool(egl->fStreamPostD3DTextureANGLE(mStream, (void*)mTexture.get(), 426 frameAttributes)); 427 428 if (!ok) { 429 gfxCriticalNote << "RenderDXGITextureHost init stream failed"; 430 DeleteTextureHandle(); 431 return false; 432 } 433 434 // Now, we could get the gl handle from the stream. 435 MOZ_ALWAYS_TRUE(egl->fStreamConsumerAcquireKHR(mStream)); 436 437 return true; 438 } 439 440 wr::WrExternalImage RenderDXGITextureHost::Lock(uint8_t aChannelIndex, 441 gl::GLContext* aGL) { 442 if (mGL.get() != aGL) { 443 // Release the texture handle in the previous gl context. 444 DeleteTextureHandle(); 445 mGL = aGL; 446 } 447 448 if (!mGL) { 449 // XXX Software WebRender is not handled yet. 450 // Software WebRender does not provide GLContext 451 gfxCriticalNoteOnce 452 << "Software WebRender is not suppored by RenderDXGITextureHost."; 453 return InvalidToWrExternalImage(); 454 } 455 456 if (!EnsureLockable()) { 457 return InvalidToWrExternalImage(); 458 } 459 460 if (!LockInternal()) { 461 return InvalidToWrExternalImage(); 462 } 463 464 const gfx::IntSize size = GetSize(aChannelIndex); 465 return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), 0.0, 0.0, 466 static_cast<float>(size.width), 467 static_cast<float>(size.height)); 468 } 469 470 bool RenderDXGITextureHost::LockInternal() { 471 MOZ_ASSERT(mTexture); 472 473 if (!mLocked) { 474 if (mFencesHolderId.isSome()) { 475 auto* fencesHolderMap = 476 layers::CompositeProcessD3D11FencesHolderMap::Get(); 477 if (!fencesHolderMap) { 478 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 479 return false; 480 } 481 RefPtr<ID3D11Device> device; 482 mTexture->GetDevice(getter_AddRefs(device)); 483 484 if (!fencesHolderMap->WaitWriteFence(mFencesHolderId.ref(), device)) { 485 return false; 486 } 487 } 488 if (mKeyedMutex) { 489 HRESULT hr = mKeyedMutex->AcquireSync(0, 10000); 490 if (hr != S_OK) { 491 gfxCriticalError() << "RenderDXGITextureHost AcquireSync timeout, hr=" 492 << gfx::hexa(hr); 493 return false; 494 } 495 } 496 mLocked = true; 497 } 498 return true; 499 } 500 501 void RenderDXGITextureHost::Unlock() { 502 if (mLocked) { 503 if (mKeyedMutex) { 504 mKeyedMutex->ReleaseSync(0); 505 } 506 mLocked = false; 507 } 508 } 509 510 void RenderDXGITextureHost::ClearCachedResources() { 511 DeleteTextureHandle(); 512 mGL = nullptr; 513 } 514 515 void RenderDXGITextureHost::DeleteTextureHandle() { 516 if (mTextureHandle[0] == 0) { 517 return; 518 } 519 520 MOZ_ASSERT(mGL.get()); 521 if (!mGL) { 522 return; 523 } 524 525 if (mGL->MakeCurrent()) { 526 mGL->fDeleteTextures(2, mTextureHandle); 527 528 const auto& gle = gl::GLContextEGL::Cast(mGL); 529 const auto& egl = gle->mEgl; 530 if (mSurface) { 531 egl->fDestroySurface(mSurface); 532 } 533 if (mStream) { 534 egl->fDestroyStreamKHR(mStream); 535 } 536 } 537 538 for (int i = 0; i < 2; ++i) { 539 mTextureHandle[i] = 0; 540 } 541 542 mTexture = nullptr; 543 mKeyedMutex = nullptr; 544 mSurface = 0; 545 mStream = 0; 546 } 547 548 GLuint RenderDXGITextureHost::GetGLHandle(uint8_t aChannelIndex) const { 549 MOZ_ASSERT(((mFormat == gfx::SurfaceFormat::NV12 || 550 mFormat == gfx::SurfaceFormat::P010 || 551 mFormat == gfx::SurfaceFormat::P016) && 552 aChannelIndex < 2) || 553 aChannelIndex < 1); 554 return mTextureHandle[aChannelIndex]; 555 } 556 557 gfx::IntSize RenderDXGITextureHost::GetSize(uint8_t aChannelIndex) const { 558 MOZ_ASSERT(((mFormat == gfx::SurfaceFormat::NV12 || 559 mFormat == gfx::SurfaceFormat::P010 || 560 mFormat == gfx::SurfaceFormat::P016) && 561 aChannelIndex < 2) || 562 aChannelIndex < 1); 563 564 if (aChannelIndex == 0) { 565 return mSize; 566 } else { 567 // The CbCr channel size is a half of Y channel size in NV12 format. 568 return mSize / 2; 569 } 570 } 571 572 bool RenderDXGITextureHost::SyncObjectNeeded() { 573 return mGpuProcessTextureId.isNothing() && !mHasKeyedMutex && 574 mFencesHolderId.isNothing(); 575 } 576 577 RenderDXGIYCbCrTextureHost::RenderDXGIYCbCrTextureHost( 578 const RefPtr<gfx::FileHandleWrapper> (&aHandles)[3], 579 const gfx::YUVColorSpace aYUVColorSpace, const gfx::ColorDepth aColorDepth, 580 const gfx::ColorRange aColorRange, const gfx::IntSize aSizeY, 581 const gfx::IntSize aSizeCbCr, 582 const layers::CompositeProcessFencesHolderId aFencesHolderId) 583 : mHandles{aHandles[0], aHandles[1], aHandles[2]}, 584 mSurfaces{0}, 585 mStreams{0}, 586 mTextureHandles{0}, 587 mYUVColorSpace(aYUVColorSpace), 588 mColorDepth(aColorDepth), 589 mColorRange(aColorRange), 590 mSizeY(aSizeY), 591 mSizeCbCr(aSizeCbCr), 592 mFencesHolderId(aFencesHolderId) { 593 MOZ_COUNT_CTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost); 594 // Assume the chroma planes are rounded up if the luma plane is odd sized. 595 MOZ_ASSERT((mSizeCbCr.width == mSizeY.width || 596 mSizeCbCr.width == (mSizeY.width + 1) >> 1) && 597 (mSizeCbCr.height == mSizeY.height || 598 mSizeCbCr.height == (mSizeY.height + 1) >> 1)); 599 MOZ_ASSERT(aHandles[0] && aHandles[1] && aHandles[2]); 600 } 601 602 bool RenderDXGIYCbCrTextureHost::MapPlane(RenderCompositor* aCompositor, 603 uint8_t aChannelIndex, 604 PlaneInfo& aPlaneInfo) { 605 D3D11_MAPPED_SUBRESOURCE mappedSubresource; 606 if (!MapTexture(this, aCompositor, mTextures[aChannelIndex], mDeviceContext, 607 mCpuTexture[aChannelIndex], mappedSubresource)) { 608 return false; 609 } 610 611 aPlaneInfo.mSize = GetSize(aChannelIndex); 612 aPlaneInfo.mStride = mappedSubresource.RowPitch; 613 aPlaneInfo.mData = mappedSubresource.pData; 614 return true; 615 } 616 617 void RenderDXGIYCbCrTextureHost::UnmapPlanes() { 618 for (uint32_t i = 0; i < 3; i++) { 619 if (mCpuTexture[i]) { 620 mDeviceContext->Unmap(mCpuTexture[i], 0); 621 mCpuTexture[i] = nullptr; 622 } 623 } 624 mDeviceContext = nullptr; 625 } 626 627 RenderDXGIYCbCrTextureHost::~RenderDXGIYCbCrTextureHost() { 628 MOZ_COUNT_DTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost); 629 DeleteTextureHandle(); 630 } 631 632 bool RenderDXGIYCbCrTextureHost::EnsureLockable() { 633 if (mTextureHandles[0]) { 634 return true; 635 } 636 637 const auto& gle = gl::GLContextEGL::Cast(mGL); 638 const auto& egl = gle->mEgl; 639 640 // The eglCreatePbufferFromClientBuffer doesn't support R8 format, so we 641 // use EGLStream to get the converted gl handle from d3d R8 texture. 642 643 if (!egl->IsExtensionSupported( 644 gl::EGLExtension::NV_stream_consumer_gltexture_yuv) || 645 !egl->IsExtensionSupported( 646 gl::EGLExtension::ANGLE_stream_producer_d3d_texture)) { 647 gfxCriticalNote 648 << "RenderDXGIYCbCrTextureHost egl extensions are not suppored"; 649 return false; 650 } 651 652 // Fetch the D3D11 device. 653 EGLDeviceEXT eglDevice = nullptr; 654 egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice); 655 MOZ_ASSERT(eglDevice); 656 ID3D11Device* device = nullptr; 657 egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, 658 (EGLAttrib*)&device); 659 // There's a chance this might fail if we end up on d3d9 angle for some 660 // reason. 661 if (!device) { 662 gfxCriticalNote << "RenderDXGIYCbCrTextureHost device is not available"; 663 return false; 664 } 665 666 if (!EnsureD3D11Texture2D(device)) { 667 return false; 668 } 669 670 mGL->fGenTextures(3, mTextureHandles); 671 bool ok = true; 672 for (int i = 0; i < 3; ++i) { 673 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0 + i, 674 LOCAL_GL_TEXTURE_EXTERNAL_OES, 675 mTextureHandles[i]); 676 677 // Create the EGLStream. 678 mStreams[i] = egl->fCreateStreamKHR(nullptr); 679 MOZ_ASSERT(mStreams[i]); 680 681 ok &= bool( 682 egl->fStreamConsumerGLTextureExternalAttribsNV(mStreams[i], nullptr)); 683 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStreams[i], nullptr)); 684 685 // Insert the R8 texture. 686 ok &= bool(egl->fStreamPostD3DTextureANGLE( 687 mStreams[i], (void*)mTextures[i].get(), nullptr)); 688 689 // Now, we could get the R8 gl handle from the stream. 690 MOZ_ALWAYS_TRUE(egl->fStreamConsumerAcquireKHR(mStreams[i])); 691 } 692 693 if (!ok) { 694 gfxCriticalNote << "RenderDXGIYCbCrTextureHost init stream failed"; 695 DeleteTextureHandle(); 696 return false; 697 } 698 699 return true; 700 } 701 702 bool RenderDXGIYCbCrTextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) { 703 RefPtr<ID3D11Device1> device1; 704 aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1)); 705 if (!device1) { 706 gfxCriticalNoteOnce << "Failed to get ID3D11Device1"; 707 return false; 708 } 709 710 if (mTextures[0]) { 711 RefPtr<ID3D11Device> device; 712 mTextures[0]->GetDevice(getter_AddRefs(device)); 713 if (aDevice != device) { 714 gfxCriticalNote << "RenderDXGIYCbCrTextureHost uses obsoleted device"; 715 return false; 716 } 717 } 718 719 if (mTextureHandles[0]) { 720 return true; 721 } 722 723 for (int i = 0; i < 3; ++i) { 724 // Get the R8 D3D11 texture from shared handle. 725 HRESULT hr = device1->OpenSharedResource1( 726 (HANDLE)mHandles[i]->GetHandle(), __uuidof(ID3D11Texture2D), 727 (void**)(ID3D11Texture2D**)getter_AddRefs(mTextures[i])); 728 if (FAILED(hr)) { 729 NS_WARNING( 730 "RenderDXGIYCbCrTextureHost::EnsureLockable(): Failed to open " 731 "shared " 732 "texture"); 733 gfxCriticalNote 734 << "RenderDXGIYCbCrTextureHost Failed to open shared texture, hr=" 735 << gfx::hexa(hr); 736 return false; 737 } 738 } 739 740 mDevice = aDevice; 741 742 return true; 743 } 744 745 bool RenderDXGIYCbCrTextureHost::LockInternal() { 746 if (!mLocked) { 747 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 748 if (!fencesHolderMap) { 749 MOZ_ASSERT_UNREACHABLE("unexpected to be called"); 750 return false; 751 } 752 if (!fencesHolderMap->WaitWriteFence(mFencesHolderId, mDevice)) { 753 return false; 754 } 755 mLocked = true; 756 } 757 return true; 758 } 759 760 wr::WrExternalImage RenderDXGIYCbCrTextureHost::Lock(uint8_t aChannelIndex, 761 gl::GLContext* aGL) { 762 if (mGL.get() != aGL) { 763 // Release the texture handle in the previous gl context. 764 DeleteTextureHandle(); 765 mGL = aGL; 766 } 767 768 if (!mGL) { 769 // XXX Software WebRender is not handled yet. 770 // Software WebRender does not provide GLContext 771 gfxCriticalNoteOnce << "Software WebRender is not suppored by " 772 "RenderDXGIYCbCrTextureHost."; 773 return InvalidToWrExternalImage(); 774 } 775 776 if (!EnsureLockable()) { 777 return InvalidToWrExternalImage(); 778 } 779 780 if (!LockInternal()) { 781 return InvalidToWrExternalImage(); 782 } 783 784 const gfx::IntSize size = GetSize(aChannelIndex); 785 return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), 0.0, 0.0, 786 static_cast<float>(size.width), 787 static_cast<float>(size.height)); 788 } 789 790 void RenderDXGIYCbCrTextureHost::Unlock() { 791 if (mLocked) { 792 mLocked = false; 793 } 794 } 795 796 void RenderDXGIYCbCrTextureHost::ClearCachedResources() { 797 DeleteTextureHandle(); 798 mGL = nullptr; 799 } 800 801 GLuint RenderDXGIYCbCrTextureHost::GetGLHandle(uint8_t aChannelIndex) const { 802 MOZ_ASSERT(aChannelIndex < 3); 803 804 return mTextureHandles[aChannelIndex]; 805 } 806 807 gfx::IntSize RenderDXGIYCbCrTextureHost::GetSize(uint8_t aChannelIndex) const { 808 MOZ_ASSERT(aChannelIndex < 3); 809 810 if (aChannelIndex == 0) { 811 return mSizeY; 812 } else { 813 return mSizeCbCr; 814 } 815 } 816 817 void RenderDXGIYCbCrTextureHost::DeleteTextureHandle() { 818 if (mTextureHandles[0] == 0) { 819 return; 820 } 821 822 MOZ_ASSERT(mGL.get()); 823 if (!mGL) { 824 return; 825 } 826 827 if (mGL->MakeCurrent()) { 828 mGL->fDeleteTextures(3, mTextureHandles); 829 830 const auto& gle = gl::GLContextEGL::Cast(mGL); 831 const auto& egl = gle->mEgl; 832 for (int i = 0; i < 3; ++i) { 833 mTextureHandles[i] = 0; 834 mTextures[i] = nullptr; 835 836 if (mSurfaces[i]) { 837 egl->fDestroySurface(mSurfaces[i]); 838 mSurfaces[i] = 0; 839 } 840 if (mStreams[i]) { 841 egl->fDestroyStreamKHR(mStreams[i]); 842 mStreams[i] = 0; 843 } 844 } 845 } 846 mDevice = nullptr; 847 } 848 849 } // namespace wr 850 } // namespace mozilla