Bug 1876177 [wpt PR 44153] - [FedCM] Add a WPT test for authz, a=testonly
[gecko.git] / gfx / gl / GLBlitHelperD3D.cpp
blob2ed1beded042357c0b9b439aed01a8f194df961f
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/gfx/D3D11Checks.h"
18 #include "mozilla/layers/D3D11ShareHandleImage.h"
19 #include "mozilla/layers/D3D11TextureIMFSampleImage.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"
25 namespace mozilla {
26 namespace gl {
28 #define NOTE_IF_FALSE(expr) \
29 do { \
30 if (!(expr)) { \
31 gfxCriticalNote << "NOTE_IF_FALSE: " << #expr; \
32 } \
33 } while (false)
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;
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;
57 (void)egl->fDestroyStreamKHR(stream);
58 return 0;
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;
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;
79 return tex;
82 // -------------------------------------
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;
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(
100 mParent.mGL,
101 [&]() {
102 std::vector<uint8_t> ret;
103 for (int i = 0; i < numPlanes; i++) {
104 ret.push_back(i);
106 return ret;
107 }(),
108 LOCAL_GL_TEXTURE_EXTERNAL),
109 mTempTexs{0},
110 mStreams{0},
111 mSuccess(true) {
112 MOZ_RELEASE_ASSERT(numPlanes >= 1 && numPlanes <= 3);
114 const auto& gl = mParent.mGL;
115 const auto& gle = GLContextEGL::Cast(gl);
116 const auto& egl = gle->mEgl;
118 gl->fGenTextures(numPlanes, mTempTexs);
120 for (uint8_t i = 0; i < mNumPlanes; i++) {
121 gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
122 gl->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTempTexs[i]);
123 const EGLAttrib* postAttribs = nullptr;
124 if (postAttribsList) {
125 postAttribs = postAttribsList[i];
127 mStreams[i] = StreamFromD3DTexture(egl.get(), texD3DList[i], postAttribs);
128 mSuccess &= bool(mStreams[i]);
131 if (mSuccess) {
132 for (uint8_t i = 0; i < mNumPlanes; i++) {
133 NOTE_IF_FALSE(egl->fStreamConsumerAcquireKHR(mStreams[i]));
135 auto& mutex = mMutexList[i];
136 texD3DList[i]->QueryInterface(IID_IDXGIKeyedMutex,
137 (void**)getter_AddRefs(mutex));
138 if (mutex) {
139 const auto hr = mutex->AcquireSync(0, 100);
140 if (!gfx::D3D11Checks::DidAcquireSyncSucceed(__func__, hr)) {
141 NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex.");
142 NOTE_IF_FALSE(egl->fStreamConsumerReleaseKHR(mStreams[i]));
143 while (i > 0) {
144 --i;
145 NOTE_IF_FALSE(egl->fStreamConsumerReleaseKHR(mStreams[i]));
146 if (mMutexList[i]) {
147 mMutexList[i]->ReleaseSync(0);
150 mSuccess = false;
151 break;
158 ~BindAnglePlanes() {
159 const auto& gl = mParent.mGL;
160 const auto& gle = GLContextEGL::Cast(gl);
161 const auto& egl = gle->mEgl;
163 if (mSuccess) {
164 for (uint8_t i = 0; i < mNumPlanes; i++) {
165 NOTE_IF_FALSE(egl->fStreamConsumerReleaseKHR(mStreams[i]));
166 if (mMutexList[i]) {
167 mMutexList[i]->ReleaseSync(0);
172 for (uint8_t i = 0; i < mNumPlanes; i++) {
173 (void)egl->fDestroyStreamKHR(mStreams[i]);
176 gl->fDeleteTextures(mNumPlanes, mTempTexs);
179 const bool& Success() const { return mSuccess; }
182 // -------------------------------------
184 ID3D11Device* GLBlitHelper::GetD3D11() const {
185 if (mD3D11) return mD3D11;
187 if (!mGL->IsANGLE()) return nullptr;
189 const auto& gle = GLContextEGL::Cast(mGL);
190 const auto& egl = gle->mEgl;
191 EGLDeviceEXT deviceEGL = 0;
192 NOTE_IF_FALSE(egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT,
193 (EGLAttrib*)&deviceEGL));
194 ID3D11Device* device = nullptr;
195 // ANGLE does not `AddRef` its returned pointer for `QueryDeviceAttrib`, so no
196 // `getter_AddRefs`.
197 if (!egl->mLib->fQueryDeviceAttribEXT(deviceEGL, LOCAL_EGL_D3D11_DEVICE_ANGLE,
198 (EGLAttrib*)&device)) {
199 MOZ_ASSERT(false, "d3d9?");
200 return nullptr;
202 mD3D11 = device;
203 return mD3D11;
206 // -------------------------------------
208 bool GLBlitHelper::BlitImage(layers::D3D11ShareHandleImage* const srcImage,
209 const gfx::IntSize& destSize,
210 const OriginPos destOrigin) const {
211 const auto& data = srcImage->GetData();
212 if (!data) return false;
214 layers::SurfaceDescriptorD3D10 desc;
215 if (!data->SerializeSpecific(&desc)) return false;
217 return BlitDescriptor(desc, destSize, destOrigin);
220 // -------------------------------------
222 bool GLBlitHelper::BlitImage(layers::D3D11TextureIMFSampleImage* const srcImage,
223 const gfx::IntSize& destSize,
224 const OriginPos destOrigin) const {
225 const auto& data = srcImage->GetData();
226 if (!data) return false;
228 layers::SurfaceDescriptorD3D10 desc;
229 if (!data->SerializeSpecific(&desc)) return false;
231 return BlitDescriptor(desc, destSize, destOrigin);
234 // -------------------------------------
236 bool GLBlitHelper::BlitImage(layers::D3D11YCbCrImage* const srcImage,
237 const gfx::IntSize& destSize,
238 const OriginPos destOrigin) const {
239 const auto& data = srcImage->GetData();
240 if (!data) return false;
242 const WindowsHandle handles[3] = {
243 (WindowsHandle)(data->mHandles[0] ? data->mHandles[0]->GetHandle()
244 : nullptr),
245 (WindowsHandle)(data->mHandles[1] ? data->mHandles[1]->GetHandle()
246 : nullptr),
247 (WindowsHandle)(data->mHandles[2] ? data->mHandles[2]->GetHandle()
248 : nullptr)};
249 return BlitAngleYCbCr(handles, srcImage->mPictureRect, srcImage->GetYSize(),
250 srcImage->GetCbCrSize(), srcImage->mColorSpace,
251 destSize, destOrigin);
254 // -------------------------------------
256 bool GLBlitHelper::BlitDescriptor(const layers::SurfaceDescriptorD3D10& desc,
257 const gfx::IntSize& destSize,
258 const OriginPos destOrigin) const {
259 const auto& d3d = GetD3D11();
260 if (!d3d) return false;
262 const auto& gpuProcessTextureId = desc.gpuProcessTextureId();
263 const auto& arrayIndex = desc.arrayIndex();
264 const auto& format = desc.format();
265 const auto& clipSize = desc.size();
267 const auto srcOrigin = OriginPos::BottomLeft;
268 const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
269 const auto colorSpace = desc.colorSpace();
271 if (format != gfx::SurfaceFormat::NV12 &&
272 format != gfx::SurfaceFormat::P010 &&
273 format != gfx::SurfaceFormat::P016) {
274 gfxCriticalError() << "Non-NV12 format for SurfaceDescriptorD3D10: "
275 << uint32_t(format);
276 return false;
279 RefPtr<ID3D11Texture2D> tex;
280 if (gpuProcessTextureId.isSome()) {
281 auto* textureMap = layers::GpuProcessD3D11TextureMap::Get();
282 if (textureMap) {
283 Maybe<HANDLE> handle =
284 textureMap->GetSharedHandleOfCopiedTexture(gpuProcessTextureId.ref());
285 if (handle.isSome()) {
286 tex = OpenSharedTexture(d3d, (WindowsHandle)handle.ref());
289 } else if (desc.handle()) {
290 tex = OpenSharedTexture(d3d, (WindowsHandle)desc.handle()->GetHandle());
292 if (!tex) {
293 MOZ_GL_ASSERT(mGL, false); // Get a nullptr from OpenSharedResource1.
294 return false;
296 const RefPtr<ID3D11Texture2D> texList[2] = {tex, tex};
297 const EGLAttrib postAttribs0[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0,
298 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
299 static_cast<EGLAttrib>(arrayIndex),
300 LOCAL_EGL_NONE};
301 const EGLAttrib postAttribs1[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1,
302 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
303 static_cast<EGLAttrib>(arrayIndex),
304 LOCAL_EGL_NONE};
305 const EGLAttrib* const postAttribsList[2] = {postAttribs0, postAttribs1};
306 // /layers/d3d11/CompositorD3D11.cpp uses bt601 for EffectTypes::NV12.
307 // return BlitAngleNv12(tex, YUVColorSpace::BT601, destSize, destOrigin);
309 const BindAnglePlanes bindPlanes(this, 2, texList, postAttribsList);
310 if (!bindPlanes.Success()) {
311 MOZ_GL_ASSERT(mGL, false); // BindAnglePlanes failed.
312 return false;
315 D3D11_TEXTURE2D_DESC texDesc = {0};
316 tex->GetDesc(&texDesc);
318 const gfx::IntSize ySize(texDesc.Width, texDesc.Height);
319 const gfx::IntSize divisors(2, 2);
320 MOZ_ASSERT(ySize.width % divisors.width == 0);
321 MOZ_ASSERT(ySize.height % divisors.height == 0);
322 const gfx::IntSize uvSize(ySize.width / divisors.width,
323 ySize.height / divisors.height);
325 const auto yuvColorSpace = [&]() {
326 switch (colorSpace) {
327 case gfx::ColorSpace2::UNKNOWN:
328 case gfx::ColorSpace2::SRGB:
329 case gfx::ColorSpace2::DISPLAY_P3:
330 MOZ_CRASH("Expected BT* colorspace");
331 case gfx::ColorSpace2::BT601_525:
332 return gfx::YUVColorSpace::BT601;
333 case gfx::ColorSpace2::BT709:
334 return gfx::YUVColorSpace::BT709;
335 case gfx::ColorSpace2::BT2020:
336 return gfx::YUVColorSpace::BT2020;
338 MOZ_ASSERT_UNREACHABLE();
339 }();
341 const bool yFlip = destOrigin != srcOrigin;
342 const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip,
343 destSize, Nothing()};
344 const DrawBlitProg::YUVArgs yuvArgs = {
345 SubRectMat3(clipRect, uvSize, divisors), Some(yuvColorSpace)};
347 const auto& prog = GetDrawBlitProg(
348 {kFragHeader_TexExt, {kFragSample_TwoPlane, kFragConvert_ColorMatrix}});
349 prog->Draw(baseArgs, &yuvArgs);
350 return true;
353 bool GLBlitHelper::BlitDescriptor(
354 const layers::SurfaceDescriptorDXGIYCbCr& desc,
355 const gfx::IntSize& destSize, const OriginPos destOrigin) const {
356 const auto& clipSize = desc.size();
357 const auto& ySize = desc.sizeY();
358 const auto& uvSize = desc.sizeCbCr();
359 const auto& colorSpace = desc.yUVColorSpace();
361 const gfx::IntRect clipRect(0, 0, clipSize.width, clipSize.height);
363 auto handleY = desc.handleY() ? desc.handleY()->GetHandle() : nullptr;
364 auto handleCb = desc.handleCb() ? desc.handleCb()->GetHandle() : nullptr;
365 auto handleCr = desc.handleCr() ? desc.handleCr()->GetHandle() : nullptr;
367 const WindowsHandle handles[3] = {
368 (WindowsHandle)handleY, (WindowsHandle)handleCb, (WindowsHandle)handleCr};
369 return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destSize,
370 destOrigin);
373 // --
375 bool GLBlitHelper::BlitAngleYCbCr(const WindowsHandle (&handleList)[3],
376 const gfx::IntRect& clipRect,
377 const gfx::IntSize& ySize,
378 const gfx::IntSize& uvSize,
379 const gfx::YUVColorSpace colorSpace,
380 const gfx::IntSize& destSize,
381 const OriginPos destOrigin) const {
382 const auto& d3d = GetD3D11();
383 if (!d3d) return false;
385 const auto srcOrigin = OriginPos::BottomLeft;
387 gfx::IntSize divisors;
388 if (!GuessDivisors(ySize, uvSize, &divisors)) return false;
390 const RefPtr<ID3D11Texture2D> texList[3] = {
391 OpenSharedTexture(d3d, handleList[0]),
392 OpenSharedTexture(d3d, handleList[1]),
393 OpenSharedTexture(d3d, handleList[2])};
394 const BindAnglePlanes bindPlanes(this, 3, texList);
396 const bool yFlip = destOrigin != srcOrigin;
397 const DrawBlitProg::BaseArgs baseArgs = {SubRectMat3(clipRect, ySize), yFlip,
398 destSize, Nothing()};
399 const DrawBlitProg::YUVArgs yuvArgs = {
400 SubRectMat3(clipRect, uvSize, divisors), Some(colorSpace)};
402 const auto& prog = GetDrawBlitProg(
403 {kFragHeader_TexExt, {kFragSample_ThreePlane, kFragConvert_ColorMatrix}});
404 prog->Draw(baseArgs, &yuvArgs);
405 return true;
408 } // namespace gl
409 } // namespace mozilla