Bug 1703443 - pt 6. Move RunNextCollectorTimer() into CCGCScheduler r=smaug
[gecko.git] / gfx / gl / GLBlitHelperD3D.cpp
blob5ac297288d8551338ba6a1c38eefe5da1ca4295f
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>
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"
20 namespace mozilla {
21 namespace gl {
23 #define NOTE_IF_FALSE(expr) \
24 do { \
25 if (!(expr)) { \
26 gfxCriticalNote << "NOTE_IF_FALSE: " << #expr; \
27 } \
28 } while (false)
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)) {
37 return 0;
40 const auto stream = egl->fCreateStreamKHR(nullptr);
41 MOZ_ASSERT(stream);
42 if (!stream) return 0;
43 bool ok = true;
44 NOTE_IF_FALSE(ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV(
45 stream, nullptr)));
46 NOTE_IF_FALSE(
47 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(stream, nullptr)));
48 NOTE_IF_FALSE(
49 ok &= bool(egl->fStreamPostD3DTextureANGLE(stream, texD3D, postAttribs)));
50 if (ok) return stream;
52 (void)egl->fDestroyStreamKHR(stream);
53 return 0;
56 static RefPtr<ID3D11Texture2D> OpenSharedTexture(ID3D11Device* const d3d,
57 const WindowsHandle handle) {
58 RefPtr<ID3D11Texture2D> tex;
59 auto hr =
60 d3d->OpenSharedResource((HANDLE)handle, __uuidof(ID3D11Texture2D),
61 (void**)(ID3D11Texture2D**)getter_AddRefs(tex));
62 if (FAILED(hr)) {
63 gfxCriticalError() << "Error code from OpenSharedResource: "
64 << gfx::hexa(hr);
65 return nullptr;
67 return tex;
70 // -------------------------------------
72 class BindAnglePlanes final {
73 const GLBlitHelper& mParent;
74 const uint8_t mNumPlanes;
75 const ScopedSaveMultiTex mMultiTex;
76 GLuint mTempTexs[3];
77 EGLStreamKHR mStreams[3];
78 RefPtr<IDXGIKeyedMutex> mMutexList[3];
79 bool mSuccess;
81 public:
82 BindAnglePlanes(const GLBlitHelper* const parent, const uint8_t numPlanes,
83 const RefPtr<ID3D11Texture2D>* const texD3DList,
84 const EGLAttrib* const* postAttribsList = nullptr)
85 : mParent(*parent),
86 mNumPlanes(numPlanes),
87 mMultiTex(mParent.mGL, mNumPlanes, LOCAL_GL_TEXTURE_EXTERNAL),
88 mTempTexs{0},
89 mStreams{0},
90 mSuccess(true) {
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]);
110 if (mSuccess) {
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));
117 if (mutex) {
118 const auto hr = mutex->AcquireSync(0, 100);
119 if (FAILED(hr)) {
120 NS_WARNING("BindAnglePlanes failed to acquire KeyedMutex.");
121 mSuccess = false;
128 ~BindAnglePlanes() {
129 const auto& gl = mParent.mGL;
130 const auto& gle = GLContextEGL::Cast(gl);
131 const auto& egl = gle->mEgl;
133 if (mSuccess) {
134 for (uint8_t i = 0; i < mNumPlanes; i++) {
135 NOTE_IF_FALSE(egl->fStreamConsumerReleaseKHR(mStreams[i]));
136 if (mMutexList[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?");
168 return nullptr;
170 return mD3D11;
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,
200 destOrigin);
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: "
223 << uint32_t(format);
224 return false;
227 const auto tex = OpenSharedTexture(d3d, handle);
228 if (!tex) {
229 MOZ_GL_ASSERT(mGL, false); // Get a nullptr from OpenSharedResource.
230 return false;
232 const RefPtr<ID3D11Texture2D> texList[2] = {tex, tex};
233 const EGLAttrib postAttribs0[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 0,
234 LOCAL_EGL_NONE};
235 const EGLAttrib postAttribs1[] = {LOCAL_EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG, 1,
236 LOCAL_EGL_NONE};
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.
244 return false;
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);
265 return true;
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(),
279 desc.handleCr()};
280 return BlitAngleYCbCr(handles, clipRect, ySize, uvSize, colorSpace, destSize,
281 destOrigin);
284 // --
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);
315 return true;
318 } // namespace gl
319 } // namespace mozilla