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 "GLBlitHelper.h"
11 #include "GLContextEGL.h"
12 #include "GLLibraryEGL.h"
13 #include "GPUVideoImage.h"
14 #include "ScopedGLHelpers.h"
16 #include "mozilla/layers/D3D11ShareHandleImage.h"
17 #include "mozilla/layers/D3D11YCbCrImage.h"
18 #include "mozilla/layers/TextureD3D11.h"
23 #define NOTE_IF_FALSE(expr) \
26 gfxCriticalNote << "NOTE_IF_FALSE: " << #expr; \
30 static EGLStreamKHR
StreamFromD3DTexture(EglDisplay
* const egl
,
31 ID3D11Texture2D
* const texD3D
,
32 const EGLAttrib
* const postAttribs
) {
33 if (!egl
->IsExtensionSupported(
34 EGLExtension::NV_stream_consumer_gltexture_yuv
) ||
35 !egl
->IsExtensionSupported(
36 EGLExtension::ANGLE_stream_producer_d3d_texture
)) {
40 const auto stream
= egl
->fCreateStreamKHR(nullptr);
42 if (!stream
) return 0;
44 NOTE_IF_FALSE(ok
&= bool(egl
->fStreamConsumerGLTextureExternalAttribsNV(
47 ok
&= bool(egl
->fCreateStreamProducerD3DTextureANGLE(stream
, nullptr)));
49 ok
&= bool(egl
->fStreamPostD3DTextureANGLE(stream
, texD3D
, postAttribs
)));
50 if (ok
) return stream
;
52 (void)egl
->fDestroyStreamKHR(stream
);
56 static RefPtr
<ID3D11Texture2D
> OpenSharedTexture(ID3D11Device
* const d3d
,
57 const WindowsHandle handle
) {
58 RefPtr
<ID3D11Texture2D
> tex
;
60 d3d
->OpenSharedResource((HANDLE
)handle
, __uuidof(ID3D11Texture2D
),
61 (void**)(ID3D11Texture2D
**)getter_AddRefs(tex
));
63 gfxCriticalError() << "Error code from OpenSharedResource: "
70 // -------------------------------------
72 class BindAnglePlanes final
{
73 const GLBlitHelper
& mParent
;
74 const uint8_t mNumPlanes
;
75 const ScopedSaveMultiTex mMultiTex
;
77 EGLStreamKHR mStreams
[3];
78 RefPtr
<IDXGIKeyedMutex
> mMutexList
[3];
82 BindAnglePlanes(const GLBlitHelper
* const parent
, const uint8_t numPlanes
,
83 const RefPtr
<ID3D11Texture2D
>* const texD3DList
,
84 const EGLAttrib
* const* postAttribsList
= nullptr)
86 mNumPlanes(numPlanes
),
87 mMultiTex(mParent
.mGL
, mNumPlanes
, LOCAL_GL_TEXTURE_EXTERNAL
),
91 MOZ_RELEASE_ASSERT(numPlanes
>= 1 && numPlanes
<= 3);
93 const auto& gl
= mParent
.mGL
;
94 const auto& gle
= GLContextEGL::Cast(gl
);
95 const auto& egl
= gle
->mEgl
;
97 gl
->fGenTextures(numPlanes
, mTempTexs
);
99 for (uint8_t i
= 0; i
< mNumPlanes
; i
++) {
100 gl
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
101 gl
->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL
, mTempTexs
[i
]);
102 const EGLAttrib
* postAttribs
= nullptr;
103 if (postAttribsList
) {
104 postAttribs
= postAttribsList
[i
];
106 mStreams
[i
] = StreamFromD3DTexture(egl
.get(), texD3DList
[i
], postAttribs
);
107 mSuccess
&= bool(mStreams
[i
]);
111 for (uint8_t i
= 0; i
< mNumPlanes
; i
++) {
112 NOTE_IF_FALSE(egl
->fStreamConsumerAcquireKHR(mStreams
[i
]));
114 auto& mutex
= mMutexList
[i
];
115 texD3DList
[i
]->QueryInterface(IID_IDXGIKeyedMutex
,
116 (void**)getter_AddRefs(mutex
));
118 const auto hr
= mutex
->AcquireSync(0, 100);
120 NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex.");
129 const auto& gl
= mParent
.mGL
;
130 const auto& gle
= GLContextEGL::Cast(gl
);
131 const auto& egl
= gle
->mEgl
;
134 for (uint8_t i
= 0; i
< mNumPlanes
; i
++) {
135 NOTE_IF_FALSE(egl
->fStreamConsumerReleaseKHR(mStreams
[i
]));
137 mMutexList
[i
]->ReleaseSync(0);
142 for (uint8_t i
= 0; i
< mNumPlanes
; i
++) {
143 (void)egl
->fDestroyStreamKHR(mStreams
[i
]);
146 gl
->fDeleteTextures(mNumPlanes
, mTempTexs
);
149 const bool& Success() const { return mSuccess
; }
152 // -------------------------------------
154 ID3D11Device
* GLBlitHelper::GetD3D11() const {
155 if (mD3D11
) return mD3D11
;
157 if (!mGL
->IsANGLE()) return nullptr;
159 const auto& gle
= GLContextEGL::Cast(mGL
);
160 const auto& egl
= gle
->mEgl
;
161 EGLDeviceEXT deviceEGL
= 0;
162 NOTE_IF_FALSE(egl
->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT
,
163 (EGLAttrib
*)&deviceEGL
));
164 if (!egl
->mLib
->fQueryDeviceAttribEXT(
165 deviceEGL
, LOCAL_EGL_D3D11_DEVICE_ANGLE
,
166 (EGLAttrib
*)(ID3D11Device
**)getter_AddRefs(mD3D11
))) {
167 MOZ_ASSERT(false, "d3d9?");
173 // -------------------------------------
175 bool GLBlitHelper::BlitImage(layers::D3D11ShareHandleImage
* const srcImage
,
176 const gfx::IntSize
& destSize
,
177 const OriginPos destOrigin
) const {
178 const auto& data
= srcImage
->GetData();
179 if (!data
) return false;
181 layers::SurfaceDescriptorD3D10 desc
;
182 if (!data
->SerializeSpecific(&desc
)) return false;
184 return BlitDescriptor(desc
, destSize
, destOrigin
);
187 // -------------------------------------
189 bool GLBlitHelper::BlitImage(layers::D3D11YCbCrImage
* const srcImage
,
190 const gfx::IntSize
& destSize
,
191 const OriginPos destOrigin
) const {
192 const auto& data
= srcImage
->GetData();
193 if (!data
) return false;
195 const WindowsHandle handles
[3] = {(WindowsHandle
)data
->mHandles
[0],
196 (WindowsHandle
)data
->mHandles
[1],
197 (WindowsHandle
)data
->mHandles
[2]};
198 return BlitAngleYCbCr(handles
, srcImage
->mPictureRect
, srcImage
->mYSize
,
199 srcImage
->mCbCrSize
, srcImage
->mColorSpace
, destSize
,
203 // -------------------------------------
205 bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10
& desc
,
206 const gfx::IntSize
& destSize
,
207 const OriginPos destOrigin
) const {
208 const auto& d3d
= GetD3D11();
209 if (!d3d
) return false;
211 const auto& handle
= desc
.handle();
212 const auto& format
= desc
.format();
213 const auto& clipSize
= desc
.size();
215 const auto srcOrigin
= OriginPos::BottomLeft
;
216 const gfx::IntRect
clipRect(0, 0, clipSize
.width
, clipSize
.height
);
217 const auto colorSpace
= desc
.yUVColorSpace();
219 if (format
!= gfx::SurfaceFormat::NV12
&&
220 format
!= gfx::SurfaceFormat::P010
&&
221 format
!= gfx::SurfaceFormat::P016
) {
222 gfxCriticalError() << "Non-NV12 format for SurfaceDescriptorD3D10: "
227 const auto tex
= OpenSharedTexture(d3d
, handle
);
229 MOZ_GL_ASSERT(mGL
, false); // Get a nullptr from OpenSharedResource.
232 const RefPtr
<ID3D11Texture2D
> texList
[2] = {tex
, tex
};
233 const EGLAttrib postAttribs0
[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG
, 0,
235 const EGLAttrib postAttribs1
[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG
, 1,
237 const EGLAttrib
* const postAttribsList
[2] = {postAttribs0
, postAttribs1
};
238 // /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12.
239 // return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin);
241 const BindAnglePlanes
bindPlanes(this, 2, texList
, postAttribsList
);
242 if (!bindPlanes
.Success()) {
243 MOZ_GL_ASSERT(mGL
, false); // BindAnglePlanes failed.
247 D3D11_TEXTURE2D_DESC texDesc
= {0};
248 tex
->GetDesc(&texDesc
);
250 const gfx::IntSize
ySize(texDesc
.Width
, texDesc
.Height
);
251 const gfx::IntSize
divisors(2, 2);
252 MOZ_ASSERT(ySize
.width
% divisors
.width
== 0);
253 MOZ_ASSERT(ySize
.height
% divisors
.height
== 0);
254 const gfx::IntSize
uvSize(ySize
.width
/ divisors
.width
,
255 ySize
.height
/ divisors
.height
);
257 const bool yFlip
= destOrigin
!= srcOrigin
;
258 const DrawBlitProg::BaseArgs baseArgs
= {SubRectMat3(clipRect
, ySize
), yFlip
,
259 destSize
, Nothing()};
260 const DrawBlitProg::YUVArgs yuvArgs
= {
261 SubRectMat3(clipRect
, uvSize
, divisors
), colorSpace
};
263 const auto& prog
= GetDrawBlitProg({kFragHeader_TexExt
, kFragBody_NV12
});
264 prog
->Draw(baseArgs
, &yuvArgs
);
268 bool GLBlitHelper::BlitDescriptor(
269 const layers::SurfaceDescriptorDXGIYCbCr
& desc
,
270 const gfx::IntSize
& destSize
, const OriginPos destOrigin
) const {
271 const auto& clipSize
= desc
.size();
272 const auto& ySize
= desc
.sizeY();
273 const auto& uvSize
= desc
.sizeCbCr();
274 const auto& colorSpace
= desc
.yUVColorSpace();
276 const gfx::IntRect
clipRect(0, 0, clipSize
.width
, clipSize
.height
);
278 const WindowsHandle handles
[3] = {desc
.handleY(), desc
.handleCb(),
280 return BlitAngleYCbCr(handles
, clipRect
, ySize
, uvSize
, colorSpace
, destSize
,
286 bool GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList
)[3],
287 const gfx::IntRect
& clipRect
,
288 const gfx::IntSize
& ySize
,
289 const gfx::IntSize
& uvSize
,
290 const gfx::YUVColorSpace colorSpace
,
291 const gfx::IntSize
& destSize
,
292 const OriginPos destOrigin
) const {
293 const auto& d3d
= GetD3D11();
294 if (!d3d
) return false;
296 const auto srcOrigin
= OriginPos::BottomLeft
;
298 gfx::IntSize divisors
;
299 if (!GuessDivisors(ySize
, uvSize
, &divisors
)) return false;
301 const RefPtr
<ID3D11Texture2D
> texList
[3] = {
302 OpenSharedTexture(d3d
, handleList
[0]),
303 OpenSharedTexture(d3d
, handleList
[1]),
304 OpenSharedTexture(d3d
, handleList
[2])};
305 const BindAnglePlanes
bindPlanes(this, 3, texList
);
307 const bool yFlip
= destOrigin
!= srcOrigin
;
308 const DrawBlitProg::BaseArgs baseArgs
= {SubRectMat3(clipRect
, ySize
), yFlip
,
309 destSize
, Nothing()};
310 const DrawBlitProg::YUVArgs yuvArgs
= {
311 SubRectMat3(clipRect
, uvSize
, divisors
), colorSpace
};
313 const auto& prog
= GetDrawBlitProg({kFragHeader_TexExt
, kFragBody_PlanarYUV
});
314 prog
->Draw(baseArgs
, &yuvArgs
);
319 } // namespace mozilla