Bug 1890689 accumulate input in LargerReceiverBlockSizeThanDesiredBuffering GTest...
[gecko.git] / gfx / gl / GLBlitHelperD3D.cpp
blobae6362e278e8a54399a86cf6b11d6eb51a2ca96e
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"
9 #include <d3d11.h>
10 #include <d3d11_1.h>
12 #include "GLContextEGL.h"
13 #include "GLLibraryEGL.h"
14 #include "GPUVideoImage.h"
15 #include "ScopedGLHelpers.h"
17 #include "mozilla/layers/D3D11ShareHandleImage.h"
18 #include "mozilla/layers/D3D11TextureIMFSampleImage.h"
19 #include "mozilla/layers/D3D11YCbCrImage.h"
20 #include "mozilla/layers/GpuProcessD3D11TextureMap.h"
21 #include "mozilla/layers/TextureD3D11.h"
22 #include "mozilla/StaticPrefs_gl.h"
24 namespace mozilla {
25 namespace gl {
27 #define NOTE_IF_FALSE(expr) \
28 do { \
29 if (!(expr)) { \
30 gfxCriticalNote << "NOTE_IF_FALSE: " << #expr; \
31 } \
32 } while (false)
34 static EGLStreamKHR StreamFromD3DTexture(EglDisplay* const egl,
35 ID3D11Texture2D* const texD3D,
36 const EGLAttrib* const postAttribs) {
37 if (!egl->IsExtensionSupported(
38 EGLExtension::NV_stream_consumer_gltexture_yuv) ||
39 !egl->IsExtensionSupported(
40 EGLExtension::ANGLE_stream_producer_d3d_texture)) {
41 return 0;
44 const auto stream = egl->fCreateStreamKHR(nullptr);
45 MOZ_ASSERT(stream);
46 if (!stream) return 0;
47 bool ok = true;
48 NOTE_IF_FALSE(ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV(
49 stream, nullptr)));
50 NOTE_IF_FALSE(
51 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(stream, nullptr)));
52 NOTE_IF_FALSE(
53 ok &= bool(egl->fStreamPostD3DTextureANGLE(stream, texD3D, postAttribs)));
54 if (ok) return stream;
56 (void)egl->fDestroyStreamKHR(stream);
57 return 0;
60 static RefPtr<ID3D11Texture2D> OpenSharedTexture(ID3D11Device* const d3d,
61 const WindowsHandle handle) {
62 RefPtr<ID3D11Device1> device1;
63 d3d->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
64 if (!device1) {
65 gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
66 return nullptr;
69 RefPtr<ID3D11Texture2D> tex;
70 auto hr = device1->OpenSharedResource1(
71 (HANDLE)handle, __uuidof(ID3D11Texture2D),
72 (void**)(ID3D11Texture2D**)getter_AddRefs(tex));
73 if (FAILED(hr)) {
74 gfxCriticalError() << "Error code from OpenSharedResource1: "
75 << gfx::hexa(hr);
76 return nullptr;
78 return tex;
81 // -------------------------------------
83 class BindAnglePlanes final {
84 const GLBlitHelper& mParent;
85 const uint8_t mNumPlanes;
86 const ScopedSaveMultiTex mMultiTex;
87 GLuint mTempTexs[3];
88 EGLStreamKHR mStreams[3];
89 RefPtr<IDXGIKeyedMutex> mMutexList[3];
90 bool mSuccess;
92 public:
93 BindAnglePlanes(const GLBlitHelper* const parent, const uint8_t numPlanes,
94 const RefPtr<ID3D11Texture2D>* const texD3DList,
95 const EGLAttrib* const* postAttribsList = nullptr)
96 : mParent(*parent),
97 mNumPlanes(numPlanes),
98 mMultiTex(
99 mParent.mGL,
100 [&]() {
101 std::vector<uint8_t> ret;
102 for (int i = 0; i < numPlanes; i++) {
103 ret.push_back(i);
105 return ret;
106 }(),
107 LOCAL_GL_TEXTURE_EXTERNAL),
108 mTempTexs{0},
109 mStreams{0},
110 mSuccess(true) {
111 MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3);
113 const auto& gl = mParent.mGL;
114 const auto& gle = GLContextEGL::Cast(gl);
115 const auto& egl = gle->mEgl;
117 gl->fGenTextures(numPlanes, mTempTexs);
119 for (uint8_t i = 0; i < mNumPlanes; i++) {
120 gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
121 gl->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTempTexs[i]);
122 const EGLAttrib* postAttribs = nullptr;
123 if (postAttribsList) {
124 postAttribs = postAttribsList[i];
126 mStreams[i] = StreamFromD3DTexture(egl.get(), texD3DList[i], postAttribs);
127 mSuccess &= bool(mStreams[i]);
130 if (mSuccess) {
131 for (uint8_t i = 0; i < mNumPlanes; i++) {
132 NOTE_IF_FALSE(egl->fStreamConsumerAcquireKHR(mStreams[i]));
134 auto& mutex = mMutexList[i];
135 texD3DList[i]->QueryInterface(IID_IDXGIKeyedMutex,
136 (void**)getter_AddRefs(mutex));
137 if (mutex) {
138 const auto hr = mutex->AcquireSync(0, 100);
139 if (FAILED(hr)) {
140 NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex.");
141 mSuccess = false;
148 ~BindAnglePlanes() {
149 const auto& gl = mParent.mGL;
150 const auto& gle = GLContextEGL::Cast(gl);
151 const auto& egl = gle->mEgl;
153 if (mSuccess) {
154 for (uint8_t i = 0; i < mNumPlanes; i++) {
155 NOTE_IF_FALSE(egl->fStreamConsumerReleaseKHR(mStreams[i]));
156 if (mMutexList[i]) {
157 mMutexList[i]->ReleaseSync(0);
162 for (uint8_t i = 0; i < mNumPlanes; i++) {
163 (void)egl->fDestroyStreamKHR(mStreams[i]);
166 gl->fDeleteTextures(mNumPlanes, mTempTexs);
169 const bool& Success() const { return mSuccess; }
172 // -------------------------------------
174 ID3D11Device* GLBlitHelper::GetD3D11() const {
175 if (mD3D11) return mD3D11;
177 if (!mGL->IsANGLE()) return nullptr;
179 const auto& gle = GLContextEGL::Cast(mGL);
180 const auto& egl = gle->mEgl;
181 EGLDeviceEXT deviceEGL = 0;
182 NOTE_IF_FALSE(egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT,
183 (EGLAttrib*)&deviceEGL));
184 ID3D11Device* device = nullptr;
185 // ANGLE does not `AddRef` its returned pointer for `QueryDeviceAttrib`, so no
186 // `getter_AddRefs`.
187 if (!egl->mLib->fQueryDeviceAttribEXT(deviceEGL, LOCAL_EGL_D3D11_DEVICE_ANGLE,
188 (EGLAttrib*)&device)) {
189 MOZ_ASSERT(false, "d3d9?");
190 return nullptr;
192 mD3D11 = device;
193 return mD3D11;
196 // -------------------------------------
198 bool GLBlitHelper::BlitImage(layers::D3D11ShareHandleImage* const srcImage,
199 const gfx::IntSize& destSize,
200 const OriginPos destOrigin) const {
201 const auto& data = srcImage->GetData();
202 if (!data) return false;
204 layers::SurfaceDescriptorD3D10 desc;
205 if (!data->SerializeSpecific(&desc)) return false;
207 return BlitDescriptor(desc, destSize, destOrigin);
210 // -------------------------------------
212 bool GLBlitHelper::BlitImage(layers::D3D11TextureIMFSampleImage* const srcImage,
213 const gfx::IntSize& destSize,
214 const OriginPos destOrigin) const {
215 const auto& data = srcImage->GetData();
216 if (!data) return false;
218 layers::SurfaceDescriptorD3D10 desc;
219 if (!data->SerializeSpecific(&desc)) return false;
221 return BlitDescriptor(desc, destSize, destOrigin);
224 // -------------------------------------
226 bool GLBlitHelper::BlitImage(layers::D3D11YCbCrImage* const srcImage,
227 const gfx::IntSize& destSize,
228 const OriginPos destOrigin) const {
229 const auto& data = srcImage->GetData();
230 if (!data) return false;
232 const WindowsHandle handles[3] = {
233 (WindowsHandle)(data->mHandles[0] ? data->mHandles[0]->GetHandle()
234 : nullptr),
235 (WindowsHandle)(data->mHandles[1] ? data->mHandles[1]->GetHandle()
236 : nullptr),
237 (WindowsHandle)(data->mHandles[2] ? data->mHandles[2]->GetHandle()
238 : nullptr)};
239 return BlitAngleYCbCr(handles, srcImage->mPictureRect, srcImage->GetYSize(),
240 srcImage->GetCbCrSize(), srcImage->mColorSpace,
241 destSize, destOrigin);
244 // -------------------------------------
246 bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
247 const gfx::IntSize& destSize,
248 const OriginPos destOrigin) const {
249 const auto& d3d = GetD3D11();
250 if (!d3d) return false;
252 const auto& gpuProcessTextureId = desc.gpuProcessTextureId();
253 const auto& arrayIndex = desc.arrayIndex();
254 const auto& format = desc.format();
255 const auto& clipSize = desc.size();
257 const auto srcOrigin = OriginPos::BottomLeft;
258 const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
259 const auto colorSpace = desc.colorSpace();
261 if (format != gfx::SurfaceFormat::NV12 &&
262 format != gfx::SurfaceFormat::P010 &&
263 format != gfx::SurfaceFormat::P016) {
264 gfxCriticalError() << "Non-NV12 format for SurfaceDescriptorD3D10: "
265 << uint32_t(format);
266 return false;
269 RefPtr<ID3D11Texture2D> tex;
270 if (gpuProcessTextureId.isSome()) {
271 auto* textureMap = layers::GpuProcessD3D11TextureMap::Get();
272 if (textureMap) {
273 Maybe<HANDLE> handle =
274 textureMap->GetSharedHandleOfCopiedTexture(gpuProcessTextureId.ref());
275 if (handle.isSome()) {
276 tex = OpenSharedTexture(d3d, (WindowsHandle)handle.ref());
279 } else if (desc.handle()) {
280 tex = OpenSharedTexture(d3d, (WindowsHandle)desc.handle()->GetHandle());
282 if (!tex) {
283 MOZ_GL_ASSERT(mGL, false); // Get a nullptr from OpenSharedResource1.
284 return false;
286 const RefPtr<ID3D11Texture2D> texList[2] = {tex, tex};
287 const EGLAttrib postAttribs0[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0,
288 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
289 static_cast<EGLAttrib>(arrayIndex),
290 LOCAL_EGL_NONE};
291 const EGLAttrib postAttribs1[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1,
292 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
293 static_cast<EGLAttrib>(arrayIndex),
294 LOCAL_EGL_NONE};
295 const EGLAttrib* const postAttribsList[2] = {postAttribs0, postAttribs1};
296 // /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12.
297 // return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin);
299 const BindAnglePlanes bindPlanes(this, 2, texList, postAttribsList);
300 if (!bindPlanes.Success()) {
301 MOZ_GL_ASSERT(mGL, false); // BindAnglePlanes failed.
302 return false;
305 D3D11_TEXTURE2D_DESC texDesc = {0};
306 tex->GetDesc(&texDesc);
308 const gfx::IntSize ySize(texDesc.Width, texDesc.Height);
309 const gfx::IntSize divisors(2, 2);
310 MOZ_ASSERT(ySize.width % divisors.width == 0);
311 MOZ_ASSERT(ySize.height % divisors.height == 0);
312 const gfx::IntSize uvSize(ySize.width / divisors.width,
313 ySize.height / divisors.height);
315 const auto yuvColorSpace = [&]() {
316 switch (colorSpace) {
317 case gfx::ColorSpace2::UNKNOWN:
318 case gfx::ColorSpace2::SRGB:
319 case gfx::ColorSpace2::DISPLAY_P3:
320 MOZ_CRASH("Expected BT* colorspace");
321 case gfx::ColorSpace2::BT601_525:
322 return gfx::YUVColorSpace::BT601;
323 case gfx::ColorSpace2::BT709:
324 return gfx::YUVColorSpace::BT709;
325 case gfx::ColorSpace2::BT2020:
326 return gfx::YUVColorSpace::BT2020;
328 MOZ_ASSERT_UNREACHABLE();
329 }();
331 const bool yFlip = destOrigin != srcOrigin;
332 const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip,
333 destSize, Nothing()};
334 const DrawBlitProg::YUVArgs yuvArgs = {
335 SubRectMat3(clipRect, uvSize, divisors), Some(yuvColorSpace)};
337 const auto& prog = GetDrawBlitProg(
338 {kFragHeader_TexExt, {kFragSample_TwoPlane, kFragConvert_ColorMatrix}});
339 prog->Draw(baseArgs, &yuvArgs);
340 return true;
343 bool GLBlitHelper::BlitDescriptor(
344 const layers::SurfaceDescriptorDXGIYCbCr& desc,
345 const gfx::IntSize& destSize, const OriginPos destOrigin) const {
346 const auto& clipSize = desc.size();
347 const auto& ySize = desc.sizeY();
348 const auto& uvSize = desc.sizeCbCr();
349 const auto& colorSpace = desc.yUVColorSpace();
351 const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
353 auto handleY = desc.handleY() ? desc.handleY()->GetHandle() : nullptr;
354 auto handleCb = desc.handleCb() ? desc.handleCb()->GetHandle() : nullptr;
355 auto handleCr = desc.handleCr() ? desc.handleCr()->GetHandle() : nullptr;
357 const WindowsHandle handles[3] = {
358 (WindowsHandle)handleY, (WindowsHandle)handleCb, (WindowsHandle)handleCr};
359 return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destSize,
360 destOrigin);
363 // --
365 bool GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
366 const gfx::IntRect& clipRect,
367 const gfx::IntSize& ySize,
368 const gfx::IntSize& uvSize,
369 const gfx::YUVColorSpace colorSpace,
370 const gfx::IntSize& destSize,
371 const OriginPos destOrigin) const {
372 const auto& d3d = GetD3D11();
373 if (!d3d) return false;
375 const auto srcOrigin = OriginPos::BottomLeft;
377 gfx::IntSize divisors;
378 if (!GuessDivisors(ySize, uvSize, &divisors)) return false;
380 const RefPtr<ID3D11Texture2D> texList[3] = {
381 OpenSharedTexture(d3d, handleList[0]),
382 OpenSharedTexture(d3d, handleList[1]),
383 OpenSharedTexture(d3d, handleList[2])};
384 const BindAnglePlanes bindPlanes(this, 3, texList);
386 const bool yFlip = destOrigin != srcOrigin;
387 const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip,
388 destSize, Nothing()};
389 const DrawBlitProg::YUVArgs yuvArgs = {
390 SubRectMat3(clipRect, uvSize, divisors), Some(colorSpace)};
392 const auto& prog = GetDrawBlitProg(
393 {kFragHeader_TexExt, {kFragSample_ThreePlane, kFragConvert_ColorMatrix}});
394 prog->Draw(baseArgs, &yuvArgs);
395 return true;
398 } // namespace gl
399 } // namespace mozilla