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/. */
7 #include "RenderD3D11TextureHost.h"
9 #include "GLContextEGL.h"
10 #include "GLLibraryEGL.h"
11 #include "RenderThread.h"
12 #include "RenderCompositor.h"
13 #include "RenderCompositorD3D11SWGL.h"
14 #include "ScopedGLHelpers.h"
15 #include "mozilla/DebugOnly.h"
16 #include "mozilla/gfx/Logging.h"
17 #include "mozilla/layers/TextureD3D11.h"
22 RenderDXGITextureHost::RenderDXGITextureHost(
23 WindowsHandle aHandle
,
24 Maybe
<layers::GpuProcessTextureId
>& aGpuProcessTextureId
,
25 uint32_t aArrayIndex
, gfx::SurfaceFormat aFormat
,
26 gfx::ColorSpace2 aColorSpace
, gfx::ColorRange aColorRange
,
29 mGpuProcessTextureId(aGpuProcessTextureId
),
30 mArrayIndex(aArrayIndex
),
35 mColorSpace(aColorSpace
),
36 mColorRange(aColorRange
),
39 MOZ_COUNT_CTOR_INHERITED(RenderDXGITextureHost
, RenderTextureHost
);
40 MOZ_ASSERT((mFormat
!= gfx::SurfaceFormat::NV12
&&
41 mFormat
!= gfx::SurfaceFormat::P010
&&
42 mFormat
!= gfx::SurfaceFormat::P016
) ||
43 (mSize
.width
% 2 == 0 && mSize
.height
% 2 == 0));
44 MOZ_ASSERT((aHandle
&& aGpuProcessTextureId
.isNothing()) ||
45 (!aHandle
&& aGpuProcessTextureId
.isSome()));
48 RenderDXGITextureHost::~RenderDXGITextureHost() {
49 MOZ_COUNT_DTOR_INHERITED(RenderDXGITextureHost
, RenderTextureHost
);
50 DeleteTextureHandle();
53 ID3D11Texture2D
* RenderDXGITextureHost::GetD3D11Texture2DWithGL() {
59 // SingletonGL is always used on Windows with ANGLE.
60 mGL
= RenderThread::Get()->SingletonGL();
63 if (!EnsureD3D11Texture2DWithGL()) {
70 size_t RenderDXGITextureHost::GetPlaneCount() const {
71 if (mFormat
== gfx::SurfaceFormat::NV12
||
72 mFormat
== gfx::SurfaceFormat::P010
||
73 mFormat
== gfx::SurfaceFormat::P016
) {
80 static bool MapTexture(T
* aHost
, RenderCompositor
* aCompositor
,
81 RefPtr
<ID3D11Texture2D
>& aTexture
,
82 RefPtr
<ID3D11DeviceContext
>& aDeviceContext
,
83 RefPtr
<ID3D11Texture2D
>& aCpuTexture
,
84 D3D11_MAPPED_SUBRESOURCE
& aMappedSubresource
) {
89 RenderCompositorD3D11SWGL
* compositor
=
90 aCompositor
->AsRenderCompositorD3D11SWGL();
95 if (!aHost
->EnsureD3D11Texture2D(compositor
->GetDevice())) {
99 if (!aHost
->LockInternal()) {
103 D3D11_TEXTURE2D_DESC textureDesc
= {0};
104 aTexture
->GetDesc(&textureDesc
);
106 compositor
->GetDevice()->GetImmediateContext(getter_AddRefs(aDeviceContext
));
108 textureDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
109 textureDesc
.Usage
= D3D11_USAGE_STAGING
;
110 textureDesc
.BindFlags
= 0;
111 textureDesc
.MiscFlags
= 0;
112 textureDesc
.MipLevels
= 1;
113 HRESULT hr
= compositor
->GetDevice()->CreateTexture2D(
114 &textureDesc
, nullptr, getter_AddRefs(aCpuTexture
));
119 aDeviceContext
->CopyResource(aCpuTexture
, aTexture
);
122 hr
= aDeviceContext
->Map(aCpuTexture
, 0, D3D11_MAP_READ
, 0,
123 &aMappedSubresource
);
124 return SUCCEEDED(hr
);
127 bool RenderDXGITextureHost::MapPlane(RenderCompositor
* aCompositor
,
128 uint8_t aChannelIndex
,
129 PlaneInfo
& aPlaneInfo
) {
130 // TODO: We currently readback from the GPU texture into a new
131 // staging texture every time this is mapped. We might be better
132 // off retaining the mapped memory to trade performance for memory
134 if (!mCpuTexture
&& !MapTexture(this, aCompositor
, mTexture
, mDeviceContext
,
135 mCpuTexture
, mMappedSubresource
)) {
139 aPlaneInfo
.mSize
= GetSize(aChannelIndex
);
140 aPlaneInfo
.mStride
= mMappedSubresource
.RowPitch
;
141 aPlaneInfo
.mData
= mMappedSubresource
.pData
;
143 // If this is the second plane, then offset the data pointer by the
144 // size of the first plane.
145 if (aChannelIndex
== 1) {
147 (uint8_t*)aPlaneInfo
.mData
+ aPlaneInfo
.mStride
* GetSize(0).height
;
152 void RenderDXGITextureHost::UnmapPlanes() {
153 mMappedSubresource
.pData
= nullptr;
155 mDeviceContext
->Unmap(mCpuTexture
, 0);
156 mCpuTexture
= nullptr;
158 mDeviceContext
= nullptr;
161 bool RenderDXGITextureHost::EnsureD3D11Texture2DWithGL() {
166 if (mGpuProcessTextureId
.isSome()) {
167 auto* textureMap
= layers::GpuProcessD3D11TextureMap::Get();
169 RefPtr
<ID3D11Texture2D
> texture
;
170 mTexture
= textureMap
->GetTexture(mGpuProcessTextureId
.ref());
178 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
179 const auto& egl
= gle
->mEgl
;
181 // Fetch the D3D11 device.
182 EGLDeviceEXT eglDevice
= nullptr;
183 egl
->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT
, (EGLAttrib
*)&eglDevice
);
184 MOZ_ASSERT(eglDevice
);
185 ID3D11Device
* device
= nullptr;
186 egl
->mLib
->fQueryDeviceAttribEXT(eglDevice
, LOCAL_EGL_D3D11_DEVICE_ANGLE
,
187 (EGLAttrib
*)&device
);
188 // There's a chance this might fail if we end up on d3d9 angle for some
191 gfxCriticalNote
<< "RenderDXGITextureHost device is not available";
195 return EnsureD3D11Texture2D(device
);
198 bool RenderDXGITextureHost::EnsureD3D11Texture2D(ID3D11Device
* aDevice
) {
200 RefPtr
<ID3D11Device
> device
;
201 mTexture
->GetDevice(getter_AddRefs(device
));
202 if (aDevice
!= device
) {
203 gfxCriticalNote
<< "RenderDXGITextureHost uses obsoleted device";
209 // Get the D3D11 texture from shared handle.
210 HRESULT hr
= aDevice
->OpenSharedResource(
211 (HANDLE
)mHandle
, __uuidof(ID3D11Texture2D
),
212 (void**)(ID3D11Texture2D
**)getter_AddRefs(mTexture
));
215 "RenderDXGITextureHost::EnsureLockable(): Failed to open shared "
218 << "RenderDXGITextureHost Failed to open shared texture, hr="
222 MOZ_ASSERT(mTexture
.get());
223 mTexture
->QueryInterface((IDXGIKeyedMutex
**)getter_AddRefs(mKeyedMutex
));
227 bool RenderDXGITextureHost::EnsureLockable() {
228 if (mTextureHandle
[0]) {
232 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
233 const auto& egl
= gle
->mEgl
;
235 // We use EGLStream to get the converted gl handle from d3d texture. The
236 // NV_stream_consumer_gltexture_yuv and ANGLE_stream_producer_d3d_texture
237 // could support nv12 and rgb d3d texture format.
238 if (!egl
->IsExtensionSupported(
239 gl::EGLExtension::NV_stream_consumer_gltexture_yuv
) ||
240 !egl
->IsExtensionSupported(
241 gl::EGLExtension::ANGLE_stream_producer_d3d_texture
)) {
242 gfxCriticalNote
<< "RenderDXGITextureHost egl extensions are not suppored";
246 // Get the D3D11 texture from shared handle.
247 if (!EnsureD3D11Texture2DWithGL()) {
251 // Create the EGLStream.
252 mStream
= egl
->fCreateStreamKHR(nullptr);
256 if (mFormat
!= gfx::SurfaceFormat::NV12
&&
257 mFormat
!= gfx::SurfaceFormat::P010
&&
258 mFormat
!= gfx::SurfaceFormat::P016
) {
259 // The non-nv12 format.
261 mGL
->fGenTextures(1, mTextureHandle
);
262 ActivateBindAndTexParameteri(mGL
, LOCAL_GL_TEXTURE0
,
263 LOCAL_GL_TEXTURE_EXTERNAL_OES
,
266 bool(egl
->fStreamConsumerGLTextureExternalAttribsNV(mStream
, nullptr));
267 ok
&= bool(egl
->fCreateStreamProducerD3DTextureANGLE(mStream
, nullptr));
269 // The nv12/p016 format.
271 // Setup the NV12 stream consumer/producer.
272 EGLAttrib consumerAttributes
[] = {
273 LOCAL_EGL_COLOR_BUFFER_TYPE
,
274 LOCAL_EGL_YUV_BUFFER_EXT
,
275 LOCAL_EGL_YUV_NUMBER_OF_PLANES_EXT
,
277 LOCAL_EGL_YUV_PLANE0_TEXTURE_UNIT_NV
,
279 LOCAL_EGL_YUV_PLANE1_TEXTURE_UNIT_NV
,
283 mGL
->fGenTextures(2, mTextureHandle
);
284 ActivateBindAndTexParameteri(mGL
, LOCAL_GL_TEXTURE0
,
285 LOCAL_GL_TEXTURE_EXTERNAL_OES
,
287 ActivateBindAndTexParameteri(mGL
, LOCAL_GL_TEXTURE1
,
288 LOCAL_GL_TEXTURE_EXTERNAL_OES
,
290 ok
&= bool(egl
->fStreamConsumerGLTextureExternalAttribsNV(
291 mStream
, consumerAttributes
));
292 ok
&= bool(egl
->fCreateStreamProducerD3DTextureANGLE(mStream
, nullptr));
295 const EGLAttrib frameAttributes
[] = {
296 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE
,
297 static_cast<EGLAttrib
>(mArrayIndex
),
301 // Insert the d3d texture.
302 ok
&= bool(egl
->fStreamPostD3DTextureANGLE(mStream
, (void*)mTexture
.get(),
306 gfxCriticalNote
<< "RenderDXGITextureHost init stream failed";
307 DeleteTextureHandle();
311 // Now, we could get the gl handle from the stream.
312 MOZ_ALWAYS_TRUE(egl
->fStreamConsumerAcquireKHR(mStream
));
317 wr::WrExternalImage
RenderDXGITextureHost::Lock(uint8_t aChannelIndex
,
318 gl::GLContext
* aGL
) {
319 if (mGL
.get() != aGL
) {
320 // Release the texture handle in the previous gl context.
321 DeleteTextureHandle();
326 // XXX Software WebRender is not handled yet.
327 // Software WebRender does not provide GLContext
329 << "Software WebRender is not suppored by RenderDXGITextureHost.";
330 return InvalidToWrExternalImage();
333 if (!EnsureLockable()) {
334 return InvalidToWrExternalImage();
337 if (!LockInternal()) {
338 return InvalidToWrExternalImage();
341 const auto uvs
= GetUvCoords(GetSize(aChannelIndex
));
342 return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex
), uvs
.first
.x
,
343 uvs
.first
.y
, uvs
.second
.x
,
347 bool RenderDXGITextureHost::LockInternal() {
350 HRESULT hr
= mKeyedMutex
->AcquireSync(0, 10000);
352 gfxCriticalError() << "RenderDXGITextureHost AcquireSync timeout, hr="
362 void RenderDXGITextureHost::Unlock() {
365 mKeyedMutex
->ReleaseSync(0);
371 void RenderDXGITextureHost::ClearCachedResources() {
372 DeleteTextureHandle();
376 void RenderDXGITextureHost::DeleteTextureHandle() {
377 if (mTextureHandle
[0] == 0) {
381 MOZ_ASSERT(mGL
.get());
386 if (mGL
->MakeCurrent()) {
387 mGL
->fDeleteTextures(2, mTextureHandle
);
389 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
390 const auto& egl
= gle
->mEgl
;
392 egl
->fDestroySurface(mSurface
);
395 egl
->fDestroyStreamKHR(mStream
);
399 for (int i
= 0; i
< 2; ++i
) {
400 mTextureHandle
[i
] = 0;
404 mKeyedMutex
= nullptr;
409 GLuint
RenderDXGITextureHost::GetGLHandle(uint8_t aChannelIndex
) const {
410 MOZ_ASSERT(((mFormat
== gfx::SurfaceFormat::NV12
||
411 mFormat
== gfx::SurfaceFormat::P010
||
412 mFormat
== gfx::SurfaceFormat::P016
) &&
413 aChannelIndex
< 2) ||
415 return mTextureHandle
[aChannelIndex
];
418 gfx::IntSize
RenderDXGITextureHost::GetSize(uint8_t aChannelIndex
) const {
419 MOZ_ASSERT(((mFormat
== gfx::SurfaceFormat::NV12
||
420 mFormat
== gfx::SurfaceFormat::P010
||
421 mFormat
== gfx::SurfaceFormat::P016
) &&
422 aChannelIndex
< 2) ||
425 if (aChannelIndex
== 0) {
428 // The CbCr channel size is a half of Y channel size in NV12 format.
433 RenderDXGIYCbCrTextureHost::RenderDXGIYCbCrTextureHost(
434 WindowsHandle (&aHandles
)[3], gfx::YUVColorSpace aYUVColorSpace
,
435 gfx::ColorDepth aColorDepth
, gfx::ColorRange aColorRange
,
436 gfx::IntSize aSizeY
, gfx::IntSize aSizeCbCr
)
437 : mHandles
{aHandles
[0], aHandles
[1], aHandles
[2]},
441 mYUVColorSpace(aYUVColorSpace
),
442 mColorDepth(aColorDepth
),
443 mColorRange(aColorRange
),
445 mSizeCbCr(aSizeCbCr
),
447 MOZ_COUNT_CTOR_INHERITED(RenderDXGIYCbCrTextureHost
, RenderTextureHost
);
448 // Assume the chroma planes are rounded up if the luma plane is odd sized.
449 MOZ_ASSERT((mSizeCbCr
.width
== mSizeY
.width
||
450 mSizeCbCr
.width
== (mSizeY
.width
+ 1) >> 1) &&
451 (mSizeCbCr
.height
== mSizeY
.height
||
452 mSizeCbCr
.height
== (mSizeY
.height
+ 1) >> 1));
453 MOZ_ASSERT(aHandles
[0] && aHandles
[1] && aHandles
[2]);
456 bool RenderDXGIYCbCrTextureHost::MapPlane(RenderCompositor
* aCompositor
,
457 uint8_t aChannelIndex
,
458 PlaneInfo
& aPlaneInfo
) {
459 D3D11_MAPPED_SUBRESOURCE mappedSubresource
;
460 if (!MapTexture(this, aCompositor
, mTextures
[aChannelIndex
], mDeviceContext
,
461 mCpuTexture
[aChannelIndex
], mappedSubresource
)) {
465 aPlaneInfo
.mSize
= GetSize(aChannelIndex
);
466 aPlaneInfo
.mStride
= mappedSubresource
.RowPitch
;
467 aPlaneInfo
.mData
= mappedSubresource
.pData
;
471 void RenderDXGIYCbCrTextureHost::UnmapPlanes() {
472 for (uint32_t i
= 0; i
< 3; i
++) {
473 if (mCpuTexture
[i
]) {
474 mDeviceContext
->Unmap(mCpuTexture
[i
], 0);
475 mCpuTexture
[i
] = nullptr;
478 mDeviceContext
= nullptr;
481 RenderDXGIYCbCrTextureHost::~RenderDXGIYCbCrTextureHost() {
482 MOZ_COUNT_DTOR_INHERITED(RenderDXGIYCbCrTextureHost
, RenderTextureHost
);
483 DeleteTextureHandle();
486 bool RenderDXGIYCbCrTextureHost::EnsureLockable() {
487 if (mTextureHandles
[0]) {
491 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
492 const auto& egl
= gle
->mEgl
;
494 // The eglCreatePbufferFromClientBuffer doesn't support R8 format, so we
495 // use EGLStream to get the converted gl handle from d3d R8 texture.
497 if (!egl
->IsExtensionSupported(
498 gl::EGLExtension::NV_stream_consumer_gltexture_yuv
) ||
499 !egl
->IsExtensionSupported(
500 gl::EGLExtension::ANGLE_stream_producer_d3d_texture
)) {
502 << "RenderDXGIYCbCrTextureHost egl extensions are not suppored";
506 // Fetch the D3D11 device.
507 EGLDeviceEXT eglDevice
= nullptr;
508 egl
->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT
, (EGLAttrib
*)&eglDevice
);
509 MOZ_ASSERT(eglDevice
);
510 ID3D11Device
* device
= nullptr;
511 egl
->mLib
->fQueryDeviceAttribEXT(eglDevice
, LOCAL_EGL_D3D11_DEVICE_ANGLE
,
512 (EGLAttrib
*)&device
);
513 // There's a chance this might fail if we end up on d3d9 angle for some
516 gfxCriticalNote
<< "RenderDXGIYCbCrTextureHost device is not available";
520 EnsureD3D11Texture2D(device
);
522 mGL
->fGenTextures(3, mTextureHandles
);
524 for (int i
= 0; i
< 3; ++i
) {
525 ActivateBindAndTexParameteri(mGL
, LOCAL_GL_TEXTURE0
+ i
,
526 LOCAL_GL_TEXTURE_EXTERNAL_OES
,
529 // Create the EGLStream.
530 mStreams
[i
] = egl
->fCreateStreamKHR(nullptr);
531 MOZ_ASSERT(mStreams
[i
]);
534 egl
->fStreamConsumerGLTextureExternalAttribsNV(mStreams
[i
], nullptr));
535 ok
&= bool(egl
->fCreateStreamProducerD3DTextureANGLE(mStreams
[i
], nullptr));
537 // Insert the R8 texture.
538 ok
&= bool(egl
->fStreamPostD3DTextureANGLE(
539 mStreams
[i
], (void*)mTextures
[i
].get(), nullptr));
541 // Now, we could get the R8 gl handle from the stream.
542 MOZ_ALWAYS_TRUE(egl
->fStreamConsumerAcquireKHR(mStreams
[i
]));
546 gfxCriticalNote
<< "RenderDXGIYCbCrTextureHost init stream failed";
547 DeleteTextureHandle();
554 bool RenderDXGIYCbCrTextureHost::EnsureD3D11Texture2D(ID3D11Device
* aDevice
) {
556 RefPtr
<ID3D11Device
> device
;
557 mTextures
[0]->GetDevice(getter_AddRefs(device
));
558 if (aDevice
!= device
) {
559 gfxCriticalNote
<< "RenderDXGIYCbCrTextureHost uses obsoleted device";
564 if (mTextureHandles
[0]) {
568 for (int i
= 0; i
< 3; ++i
) {
569 // Get the R8 D3D11 texture from shared handle.
570 HRESULT hr
= aDevice
->OpenSharedResource(
571 (HANDLE
)mHandles
[i
], __uuidof(ID3D11Texture2D
),
572 (void**)(ID3D11Texture2D
**)getter_AddRefs(mTextures
[i
]));
575 "RenderDXGIYCbCrTextureHost::EnsureLockable(): Failed to open "
579 << "RenderDXGIYCbCrTextureHost Failed to open shared texture, hr="
585 for (int i
= 0; i
< 3; ++i
) {
586 mTextures
[i
]->QueryInterface(
587 (IDXGIKeyedMutex
**)getter_AddRefs(mKeyedMutexs
[i
]));
592 bool RenderDXGIYCbCrTextureHost::LockInternal() {
594 if (mKeyedMutexs
[0]) {
595 for (const auto& mutex
: mKeyedMutexs
) {
596 HRESULT hr
= mutex
->AcquireSync(0, 10000);
599 << "RenderDXGIYCbCrTextureHost AcquireSync timeout, hr="
610 wr::WrExternalImage
RenderDXGIYCbCrTextureHost::Lock(uint8_t aChannelIndex
,
611 gl::GLContext
* aGL
) {
612 if (mGL
.get() != aGL
) {
613 // Release the texture handle in the previous gl context.
614 DeleteTextureHandle();
619 // XXX Software WebRender is not handled yet.
620 // Software WebRender does not provide GLContext
621 gfxCriticalNoteOnce
<< "Software WebRender is not suppored by "
622 "RenderDXGIYCbCrTextureHost.";
623 return InvalidToWrExternalImage();
626 if (!EnsureLockable()) {
627 return InvalidToWrExternalImage();
630 if (!LockInternal()) {
631 return InvalidToWrExternalImage();
634 const auto uvs
= GetUvCoords(GetSize(aChannelIndex
));
635 return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex
), uvs
.first
.x
,
636 uvs
.first
.y
, uvs
.second
.x
,
640 void RenderDXGIYCbCrTextureHost::Unlock() {
642 if (mKeyedMutexs
[0]) {
643 for (const auto& mutex
: mKeyedMutexs
) {
644 mutex
->ReleaseSync(0);
651 void RenderDXGIYCbCrTextureHost::ClearCachedResources() {
652 DeleteTextureHandle();
656 GLuint
RenderDXGIYCbCrTextureHost::GetGLHandle(uint8_t aChannelIndex
) const {
657 MOZ_ASSERT(aChannelIndex
< 3);
659 return mTextureHandles
[aChannelIndex
];
662 gfx::IntSize
RenderDXGIYCbCrTextureHost::GetSize(uint8_t aChannelIndex
) const {
663 MOZ_ASSERT(aChannelIndex
< 3);
665 if (aChannelIndex
== 0) {
672 void RenderDXGIYCbCrTextureHost::DeleteTextureHandle() {
673 if (mTextureHandles
[0] == 0) {
677 MOZ_ASSERT(mGL
.get());
682 if (mGL
->MakeCurrent()) {
683 mGL
->fDeleteTextures(3, mTextureHandles
);
685 const auto& gle
= gl::GLContextEGL::Cast(mGL
);
686 const auto& egl
= gle
->mEgl
;
687 for (int i
= 0; i
< 3; ++i
) {
688 mTextureHandles
[i
] = 0;
689 mTextures
[i
] = nullptr;
690 mKeyedMutexs
[i
] = nullptr;
693 egl
->fDestroySurface(mSurfaces
[i
]);
697 egl
->fDestroyStreamKHR(mStreams
[i
]);
705 } // namespace mozilla