GLBlitHelperD3D.cpp (15304B)
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 "GLBlitHelper.h" 8 9 #include <d3d11.h> 10 #include <d3d11_1.h> 11 12 #include "GLContextEGL.h" 13 #include "GLLibraryEGL.h" 14 #include "GPUVideoImage.h" 15 #include "ScopedGLHelpers.h" 16 17 #include "mozilla/layers/CompositeProcessD3D11FencesHolderMap.h" 18 #include "mozilla/layers/D3D11ShareHandleImage.h" 19 #include "mozilla/layers/D3D11ZeroCopyTextureImage.h" 20 #include "mozilla/layers/D3D11YCbCrImage.h" 21 #include "mozilla/layers/GpuProcessD3D11TextureMap.h" 22 #include "mozilla/layers/TextureD3D11.h" 23 #include "mozilla/StaticPrefs_gl.h" 24 25 namespace mozilla { 26 namespace gl { 27 28 #define NOTE_IF_FALSE(expr) \ 29 do { \ 30 if (!(expr)) { \ 31 gfxCriticalNote << "NOTE_IF_FALSE: " << #expr; \ 32 } \ 33 } while (false) 34 35 static EGLStreamKHR StreamFromD3DTexture(EglDisplay* const egl, 36 ID3D11Texture2D* const texD3D, 37 const EGLAttrib* const postAttribs) { 38 if (!egl->IsExtensionSupported( 39 EGLExtension::NV_stream_consumer_gltexture_yuv) || 40 !egl->IsExtensionSupported( 41 EGLExtension::ANGLE_stream_producer_d3d_texture)) { 42 return 0; 43 } 44 45 const auto stream = egl->fCreateStreamKHR(nullptr); 46 MOZ_ASSERT(stream); 47 if (!stream) return 0; 48 bool ok = true; 49 NOTE_IF_FALSE(ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV( 50 stream, nullptr))); 51 NOTE_IF_FALSE( 52 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(stream, nullptr))); 53 NOTE_IF_FALSE( 54 ok &= bool(egl->fStreamPostD3DTextureANGLE(stream, texD3D, postAttribs))); 55 if (ok) return stream; 56 57 (void)egl->fDestroyStreamKHR(stream); 58 return 0; 59 } 60 61 static RefPtr<ID3D11Texture2D> OpenSharedTexture(ID3D11Device* const d3d, 62 const WindowsHandle handle) { 63 RefPtr<ID3D11Device1> device1; 64 d3d->QueryInterface((ID3D11Device1**)getter_AddRefs(device1)); 65 if (!device1) { 66 gfxCriticalNoteOnce << "Failed to get ID3D11Device1"; 67 return nullptr; 68 } 69 70 RefPtr<ID3D11Texture2D> tex; 71 auto hr = device1->OpenSharedResource1( 72 (HANDLE)handle, __uuidof(ID3D11Texture2D), 73 (void**)(ID3D11Texture2D**)getter_AddRefs(tex)); 74 if (FAILED(hr)) { 75 gfxCriticalError() << "Error code from OpenSharedResource1: " 76 << gfx::hexa(hr); 77 return nullptr; 78 } 79 return tex; 80 } 81 82 // ------------------------------------- 83 84 class BindAnglePlanes final { 85 const GLBlitHelper& mParent; 86 const uint8_t mNumPlanes; 87 const ScopedSaveMultiTex mMultiTex; 88 GLuint mTempTexs[3]; 89 EGLStreamKHR mStreams[3]; 90 RefPtr<IDXGIKeyedMutex> mMutexList[3]; 91 bool mSuccess; 92 93 public: 94 BindAnglePlanes(const GLBlitHelper* const parent, const uint8_t numPlanes, 95 const RefPtr<ID3D11Texture2D>* const texD3DList, 96 const EGLAttrib* const* postAttribsList = nullptr) 97 : mParent(*parent), 98 mNumPlanes(numPlanes), 99 mMultiTex(mParent.mGL, mNumPlanes, LOCAL_GL_TEXTURE_EXTERNAL), 100 mTempTexs{0}, 101 mStreams{0}, 102 mSuccess(true) { 103 MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3); 104 105 const auto& gl = mParent.mGL; 106 const auto& gle = GLContextEGL::Cast(gl); 107 const auto& egl = gle->mEgl; 108 109 gl->fGenTextures(numPlanes, mTempTexs); 110 111 for (uint8_t i = 0; i < mNumPlanes; i++) { 112 gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i); 113 gl->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTempTexs[i]); 114 const EGLAttrib* postAttribs = nullptr; 115 if (postAttribsList) { 116 postAttribs = postAttribsList[i]; 117 } 118 mStreams[i] = StreamFromD3DTexture(egl.get(), texD3DList[i], postAttribs); 119 mSuccess &= bool(mStreams[i]); 120 } 121 122 if (mSuccess) { 123 for (uint8_t i = 0; i < mNumPlanes; i++) { 124 NOTE_IF_FALSE(egl->fStreamConsumerAcquireKHR(mStreams[i])); 125 126 auto& mutex = mMutexList[i]; 127 texD3DList[i]->QueryInterface(IID_IDXGIKeyedMutex, 128 (void**)getter_AddRefs(mutex)); 129 if (mutex) { 130 const auto hr = mutex->AcquireSync(0, 100); 131 if (FAILED(hr)) { 132 NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex."); 133 mSuccess = false; 134 } 135 } 136 } 137 } 138 } 139 140 ~BindAnglePlanes() { 141 const auto& gl = mParent.mGL; 142 const auto& gle = GLContextEGL::Cast(gl); 143 const auto& egl = gle->mEgl; 144 145 if (mSuccess) { 146 for (uint8_t i = 0; i < mNumPlanes; i++) { 147 NOTE_IF_FALSE(egl->fStreamConsumerReleaseKHR(mStreams[i])); 148 if (mMutexList[i]) { 149 mMutexList[i]->ReleaseSync(0); 150 } 151 } 152 } 153 154 for (uint8_t i = 0; i < mNumPlanes; i++) { 155 (void)egl->fDestroyStreamKHR(mStreams[i]); 156 } 157 158 gl->fDeleteTextures(mNumPlanes, mTempTexs); 159 } 160 161 const bool& Success() const { return mSuccess; } 162 }; 163 164 // ------------------------------------- 165 166 ID3D11Device* GLBlitHelper::GetD3D11() const { 167 if (mD3D11) return mD3D11; 168 169 if (!mGL->IsANGLE()) return nullptr; 170 171 const auto& gle = GLContextEGL::Cast(mGL); 172 const auto& egl = gle->mEgl; 173 EGLDeviceEXT deviceEGL = 0; 174 NOTE_IF_FALSE(egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, 175 (EGLAttrib*)&deviceEGL)); 176 ID3D11Device* device = nullptr; 177 // ANGLE does not `AddRef` its returned pointer for `QueryDeviceAttrib`, so no 178 // `getter_AddRefs`. 179 if (!egl->mLib->fQueryDeviceAttribEXT(deviceEGL, LOCAL_EGL_D3D11_DEVICE_ANGLE, 180 (EGLAttrib*)&device)) { 181 MOZ_ASSERT(false, "d3d9?"); 182 return nullptr; 183 } 184 mD3D11 = device; 185 return mD3D11; 186 } 187 188 // ------------------------------------- 189 190 bool GLBlitHelper::BlitImage(layers::D3D11ShareHandleImage* const srcImage, 191 const gfx::IntRect& destRect, 192 const OriginPos destOrigin, 193 const gfx::IntSize& fbSize) const { 194 const auto& data = srcImage->GetData(); 195 if (!data) return false; 196 197 layers::SurfaceDescriptorD3D10 desc; 198 if (!data->SerializeSpecific(&desc)) return false; 199 200 return BlitDescriptor(desc, destRect, destOrigin, fbSize); 201 } 202 203 // ------------------------------------- 204 205 bool GLBlitHelper::BlitImage(layers::D3D11ZeroCopyTextureImage* const srcImage, 206 const gfx::IntRect& destRect, 207 const OriginPos destOrigin, 208 const gfx::IntSize& fbSize) const { 209 const auto& data = srcImage->GetData(); 210 if (!data) return false; 211 212 layers::SurfaceDescriptorD3D10 desc; 213 if (!data->SerializeSpecific(&desc)) return false; 214 215 return BlitDescriptor(desc, destRect, destOrigin, fbSize); 216 } 217 218 // ------------------------------------- 219 220 bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc, 221 const gfx::IntRect& destRect, 222 const OriginPos destOrigin, 223 const gfx::IntSize& fbSize, 224 Maybe<gfxAlphaType> convertAlpha) const { 225 const auto& d3d = GetD3D11(); 226 if (!d3d) return false; 227 228 const auto& gpuProcessTextureId = desc.gpuProcessTextureId(); 229 auto arrayIndex = desc.arrayIndex(); 230 const auto& format = desc.format(); 231 const auto& clipSize = desc.size(); 232 233 const auto srcOrigin = OriginPos::BottomLeft; 234 const bool yFlip = destOrigin != srcOrigin; 235 const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height); 236 const auto colorSpace = desc.colorSpace(); 237 const auto fencesHolderId = desc.fencesHolderId(); 238 239 bool yuv = true; 240 switch (format) { 241 case gfx::SurfaceFormat::B8G8R8A8: 242 case gfx::SurfaceFormat::B8G8R8X8: 243 case gfx::SurfaceFormat::R8G8B8A8: 244 case gfx::SurfaceFormat::R8G8B8X8: 245 case gfx::SurfaceFormat::R10G10B10A2_UINT32: 246 case gfx::SurfaceFormat::R10G10B10X2_UINT32: 247 case gfx::SurfaceFormat::R16G16B16A16F: 248 yuv = false; 249 break; 250 case gfx::SurfaceFormat::NV12: 251 case gfx::SurfaceFormat::P010: 252 case gfx::SurfaceFormat::P016: 253 break; 254 default: 255 gfxCriticalError() << "Non-RGBA/NV12 format for SurfaceDescriptorD3D10: " 256 << uint32_t(format); 257 return false; 258 } 259 260 RefPtr<ID3D11Texture2D> tex; 261 if (gpuProcessTextureId.isSome()) { 262 auto* textureMap = layers::GpuProcessD3D11TextureMap::Get(); 263 if (textureMap) { 264 Maybe<HANDLE> handle = 265 textureMap->GetSharedHandle(gpuProcessTextureId.ref()); 266 if (handle.isSome()) { 267 tex = OpenSharedTexture(d3d, (WindowsHandle)handle.ref()); 268 arrayIndex = 0; 269 } 270 } 271 } else if (desc.handle()) { 272 tex = OpenSharedTexture(d3d, (WindowsHandle)desc.handle()->GetHandle()); 273 } 274 if (!tex) { 275 MOZ_GL_ASSERT(mGL, false); // Get a nullptr from OpenSharedResource1. 276 return false; 277 } 278 279 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 280 MOZ_ASSERT(fencesHolderMap); 281 if (fencesHolderMap && fencesHolderId.isSome()) { 282 fencesHolderMap->WaitWriteFence(fencesHolderId.ref(), d3d); 283 } 284 285 if (!yuv) { 286 const RefPtr<ID3D11Texture2D> texList[1] = {tex}; 287 const EGLAttrib postAttribs0[] = { 288 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 289 static_cast<EGLAttrib>(arrayIndex), LOCAL_EGL_NONE}; 290 const EGLAttrib* const postAttribsList[1] = {postAttribs0}; 291 const BindAnglePlanes bindPlanes(this, 1, texList, 292 arrayIndex ? postAttribsList : nullptr); 293 if (!bindPlanes.Success()) { 294 MOZ_GL_ASSERT(mGL, false); // BindAnglePlanes failed. 295 return false; 296 } 297 298 D3D11_TEXTURE2D_DESC texDesc = {0}; 299 tex->GetDesc(&texDesc); 300 gfx::IntSize texSize(texDesc.Width, texDesc.Height); 301 302 const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, texSize), 303 yFlip, fbSize, destRect, clipSize}; 304 const auto& prog = 305 GetDrawBlitProg({kFragHeader_TexExt, 306 {kFragSample_OnePlane, kFragConvert_None, 307 GetAlphaMixin(convertAlpha)}}); 308 prog.Draw(baseArgs); 309 return true; 310 } 311 312 const RefPtr<ID3D11Texture2D> texList[2] = {tex, tex}; 313 const EGLAttrib postAttribs0[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0, 314 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 315 static_cast<EGLAttrib>(arrayIndex), 316 LOCAL_EGL_NONE}; 317 const EGLAttrib postAttribs1[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1, 318 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE, 319 static_cast<EGLAttrib>(arrayIndex), 320 LOCAL_EGL_NONE}; 321 const EGLAttrib* const postAttribsList[2] = {postAttribs0, postAttribs1}; 322 // /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12. 323 // return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin); 324 325 const BindAnglePlanes bindPlanes(this, 2, texList, postAttribsList); 326 if (!bindPlanes.Success()) { 327 MOZ_GL_ASSERT(mGL, false); // BindAnglePlanes failed. 328 return false; 329 } 330 331 D3D11_TEXTURE2D_DESC texDesc = {0}; 332 tex->GetDesc(&texDesc); 333 334 const gfx::IntSize ySize(texDesc.Width, texDesc.Height); 335 const gfx::IntSize divisors(2, 2); 336 MOZ_ASSERT(ySize.width % divisors.width == 0); 337 MOZ_ASSERT(ySize.height % divisors.height == 0); 338 const gfx::IntSize uvSize(ySize.width / divisors.width, 339 ySize.height / divisors.height); 340 341 const auto yuvColorSpace = [&]() { 342 switch (colorSpace) { 343 case gfx::ColorSpace2::UNKNOWN: 344 case gfx::ColorSpace2::SRGB: 345 case gfx::ColorSpace2::DISPLAY_P3: 346 MOZ_CRASH("Expected BT* colorspace"); 347 case gfx::ColorSpace2::BT601_525: 348 return gfx::YUVColorSpace::BT601; 349 case gfx::ColorSpace2::BT709: 350 return gfx::YUVColorSpace::BT709; 351 case gfx::ColorSpace2::BT2020: 352 return gfx::YUVColorSpace::BT2020; 353 } 354 MOZ_ASSERT_UNREACHABLE(); 355 }(); 356 357 const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip, 358 fbSize, destRect, clipSize}; 359 const DrawBlitProg::YUVArgs yuvArgs = { 360 SubRectMat3(clipRect, uvSize, divisors), Some(yuvColorSpace)}; 361 362 const auto& prog = 363 GetDrawBlitProg({kFragHeader_TexExt, 364 {kFragSample_TwoPlane, kFragConvert_ColorMatrix, 365 GetAlphaMixin(convertAlpha)}}); 366 prog.Draw(baseArgs, &yuvArgs); 367 return true; 368 } 369 370 bool GLBlitHelper::BlitDescriptor( 371 const layers::SurfaceDescriptorDXGIYCbCr& desc, 372 const gfx::IntRect& destRect, const OriginPos destOrigin, 373 const gfx::IntSize& fbSize, Maybe<gfxAlphaType> convertAlpha) const { 374 const auto& clipSize = desc.size(); 375 const auto& ySize = desc.sizeY(); 376 const auto& uvSize = desc.sizeCbCr(); 377 const auto& colorSpace = desc.yUVColorSpace(); 378 379 const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height); 380 381 auto handleY = desc.handleY() ? desc.handleY()->GetHandle() : nullptr; 382 auto handleCb = desc.handleCb() ? desc.handleCb()->GetHandle() : nullptr; 383 auto handleCr = desc.handleCr() ? desc.handleCr()->GetHandle() : nullptr; 384 385 const WindowsHandle handles[3] = { 386 (WindowsHandle)handleY, (WindowsHandle)handleCb, (WindowsHandle)handleCr}; 387 return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destRect, 388 destOrigin, fbSize, convertAlpha); 389 } 390 391 // -- 392 393 bool GLBlitHelper::BlitAngleYCbCr( 394 const WindowsHandle (&handleList)[3], const gfx::IntRect& clipRect, 395 const gfx::IntSize& ySize, const gfx::IntSize& uvSize, 396 const gfx::YUVColorSpace colorSpace, const gfx::IntRect& destRect, 397 const OriginPos destOrigin, const gfx::IntSize& fbSize, 398 Maybe<gfxAlphaType> convertAlpha) const { 399 const auto& d3d = GetD3D11(); 400 if (!d3d) return false; 401 402 const auto srcOrigin = OriginPos::BottomLeft; 403 404 gfx::IntSize divisors; 405 if (!GuessDivisors(ySize, uvSize, &divisors)) return false; 406 407 const RefPtr<ID3D11Texture2D> texList[3] = { 408 OpenSharedTexture(d3d, handleList[0]), 409 OpenSharedTexture(d3d, handleList[1]), 410 OpenSharedTexture(d3d, handleList[2])}; 411 const BindAnglePlanes bindPlanes(this, 3, texList); 412 413 const bool yFlip = destOrigin != srcOrigin; 414 const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip, 415 fbSize, destRect, clipRect.Size()}; 416 const DrawBlitProg::YUVArgs yuvArgs = { 417 SubRectMat3(clipRect, uvSize, divisors), Some(colorSpace)}; 418 419 const auto& prog = 420 GetDrawBlitProg({kFragHeader_TexExt, 421 {kFragSample_ThreePlane, kFragConvert_ColorMatrix, 422 GetAlphaMixin(convertAlpha)}}); 423 prog.Draw(baseArgs, &yuvArgs); 424 return true; 425 } 426 427 } // namespace gl 428 } // namespace mozilla