Merge mozilla-central to autoland. CLOSED TREE
[gecko.git] / gfx / webrender_bindings / RenderD3D11TextureHost.cpp
blob451d0d9072cf669a8bc0f8ebecd699acfb266d8a
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/CanvasManagerParent.h"
17 #include "mozilla/gfx/DeviceManagerDx.h"
18 #include "mozilla/gfx/Logging.h"
19 #include "mozilla/layers/FenceD3D11.h"
20 #include "mozilla/layers/GpuProcessD3D11QueryMap.h"
21 #include "mozilla/layers/GpuProcessD3D11TextureMap.h"
22 #include "mozilla/layers/TextureD3D11.h"
24 namespace mozilla {
25 namespace wr {
27 RenderDXGITextureHost::RenderDXGITextureHost(
28 RefPtr<gfx::FileHandleWrapper> aHandle,
29 Maybe<layers::GpuProcessTextureId>& aGpuProcessTextureId,
30 uint32_t aArrayIndex, gfx::SurfaceFormat aFormat,
31 gfx::ColorSpace2 aColorSpace, gfx::ColorRange aColorRange,
32 gfx::IntSize aSize, bool aHasKeyedMutex, gfx::FenceInfo& aAcquireFenceInfo,
33 Maybe<layers::GpuProcessQueryId>& aGpuProcessQueryId)
34 : mHandle(aHandle),
35 mGpuProcessTextureId(aGpuProcessTextureId),
36 mGpuProcessQueryId(aGpuProcessQueryId),
37 mArrayIndex(aArrayIndex),
38 mSurface(0),
39 mStream(0),
40 mTextureHandle{0},
41 mFormat(aFormat),
42 mColorSpace(aColorSpace),
43 mColorRange(aColorRange),
44 mSize(aSize),
45 mHasKeyedMutex(aHasKeyedMutex),
46 mAcquireFenceInfo(aAcquireFenceInfo),
47 mLocked(false) {
48 MOZ_COUNT_CTOR_INHERITED(RenderDXGITextureHost, RenderTextureHost);
49 MOZ_ASSERT((mFormat != gfx::SurfaceFormat::NV12 &&
50 mFormat != gfx::SurfaceFormat::P010 &&
51 mFormat != gfx::SurfaceFormat::P016) ||
52 (mSize.width % 2 == 0 && mSize.height % 2 == 0));
53 MOZ_ASSERT((aHandle && aGpuProcessTextureId.isNothing()) ||
54 (!aHandle && aGpuProcessTextureId.isSome()));
57 RenderDXGITextureHost::~RenderDXGITextureHost() {
58 MOZ_COUNT_DTOR_INHERITED(RenderDXGITextureHost, RenderTextureHost);
59 DeleteTextureHandle();
62 RefPtr<ID3D11Query> RenderDXGITextureHost::GetQuery() {
63 if (mGpuProcessQueryId.isNothing()) {
64 return nullptr;
67 auto* queryMap = layers::GpuProcessD3D11QueryMap::Get();
68 if (!queryMap) {
69 return nullptr;
72 auto query = queryMap->GetQuery(mGpuProcessQueryId.ref());
73 if (!query) {
74 gfxCriticalNoteOnce << "Failed to get ID3D11Query";
77 return query;
80 ID3D11Texture2D* RenderDXGITextureHost::GetD3D11Texture2DWithGL() {
81 if (mTexture) {
82 return mTexture;
85 if (!mGL) {
86 // SingletonGL is always used on Windows with ANGLE.
87 mGL = RenderThread::Get()->SingletonGL();
90 if (!EnsureD3D11Texture2DWithGL()) {
91 return nullptr;
94 return mTexture;
97 size_t RenderDXGITextureHost::GetPlaneCount() const {
98 if (mFormat == gfx::SurfaceFormat::NV12 ||
99 mFormat == gfx::SurfaceFormat::P010 ||
100 mFormat == gfx::SurfaceFormat::P016) {
101 return 2;
103 return 1;
106 template <typename T>
107 static bool MapTexture(T* aHost, RenderCompositor* aCompositor,
108 RefPtr<ID3D11Texture2D>& aTexture,
109 RefPtr<ID3D11DeviceContext>& aDeviceContext,
110 RefPtr<ID3D11Texture2D>& aCpuTexture,
111 D3D11_MAPPED_SUBRESOURCE& aMappedSubresource) {
112 if (!aCompositor) {
113 return false;
116 RenderCompositorD3D11SWGL* compositor =
117 aCompositor->AsRenderCompositorD3D11SWGL();
118 if (!compositor) {
119 return false;
122 if (!aHost->EnsureD3D11Texture2D(compositor->GetDevice())) {
123 return false;
126 if (!aHost->LockInternal()) {
127 return false;
130 D3D11_TEXTURE2D_DESC textureDesc = {0};
131 aTexture->GetDesc(&textureDesc);
133 compositor->GetDevice()->GetImmediateContext(getter_AddRefs(aDeviceContext));
135 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
136 textureDesc.Usage = D3D11_USAGE_STAGING;
137 textureDesc.BindFlags = 0;
138 textureDesc.MiscFlags = 0;
139 textureDesc.MipLevels = 1;
140 HRESULT hr = compositor->GetDevice()->CreateTexture2D(
141 &textureDesc, nullptr, getter_AddRefs(aCpuTexture));
142 if (FAILED(hr)) {
143 return false;
146 aDeviceContext->CopyResource(aCpuTexture, aTexture);
147 aHost->Unlock();
149 hr = aDeviceContext->Map(aCpuTexture, 0, D3D11_MAP_READ, 0,
150 &aMappedSubresource);
151 return SUCCEEDED(hr);
154 bool RenderDXGITextureHost::MapPlane(RenderCompositor* aCompositor,
155 uint8_t aChannelIndex,
156 PlaneInfo& aPlaneInfo) {
157 // TODO: We currently readback from the GPU texture into a new
158 // staging texture every time this is mapped. We might be better
159 // off retaining the mapped memory to trade performance for memory
160 // usage.
161 if (!mCpuTexture && !MapTexture(this, aCompositor, mTexture, mDeviceContext,
162 mCpuTexture, mMappedSubresource)) {
163 return false;
166 aPlaneInfo.mSize = GetSize(aChannelIndex);
167 aPlaneInfo.mStride = mMappedSubresource.RowPitch;
168 aPlaneInfo.mData = mMappedSubresource.pData;
170 // If this is the second plane, then offset the data pointer by the
171 // size of the first plane.
172 if (aChannelIndex == 1) {
173 aPlaneInfo.mData =
174 (uint8_t*)aPlaneInfo.mData + aPlaneInfo.mStride * GetSize(0).height;
176 return true;
179 void RenderDXGITextureHost::UnmapPlanes() {
180 mMappedSubresource.pData = nullptr;
181 if (mCpuTexture) {
182 mDeviceContext->Unmap(mCpuTexture, 0);
183 mCpuTexture = nullptr;
185 mDeviceContext = nullptr;
188 bool RenderDXGITextureHost::EnsureD3D11Texture2DWithGL() {
189 if (mTexture) {
190 return true;
193 const auto& gle = gl::GLContextEGL::Cast(mGL);
194 const auto& egl = gle->mEgl;
196 // Fetch the D3D11 device.
197 EGLDeviceEXT eglDevice = nullptr;
198 egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
199 MOZ_ASSERT(eglDevice);
200 ID3D11Device* device = nullptr;
201 egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE,
202 (EGLAttrib*)&device);
203 // There's a chance this might fail if we end up on d3d9 angle for some
204 // reason.
205 if (!device) {
206 gfxCriticalNote << "RenderDXGITextureHost device is not available";
207 return false;
210 return EnsureD3D11Texture2D(device);
213 bool RenderDXGITextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) {
214 if (mTexture) {
215 RefPtr<ID3D11Device> device;
216 mTexture->GetDevice(getter_AddRefs(device));
217 if (aDevice != device) {
218 gfxCriticalNote << "RenderDXGITextureHost uses obsoleted device";
219 return false;
221 return true;
224 if (mGpuProcessTextureId.isSome()) {
225 auto* textureMap = layers::GpuProcessD3D11TextureMap::Get();
226 if (textureMap) {
227 RefPtr<ID3D11Texture2D> texture;
228 textureMap->WaitTextureReady(mGpuProcessTextureId.ref());
229 mTexture = textureMap->GetTexture(mGpuProcessTextureId.ref());
230 if (mTexture) {
231 return true;
232 } else {
233 gfxCriticalNote << "GpuProcessTextureId is not valid";
236 return false;
239 RefPtr<ID3D11Device1> device1;
240 aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
241 if (!device1) {
242 gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
243 return 0;
246 // Get the D3D11 texture from shared handle.
247 HRESULT hr = device1->OpenSharedResource1(
248 (HANDLE)mHandle->GetHandle(), __uuidof(ID3D11Texture2D),
249 (void**)(ID3D11Texture2D**)getter_AddRefs(mTexture));
250 if (FAILED(hr)) {
251 MOZ_ASSERT(false,
252 "RenderDXGITextureHost::EnsureLockable(): Failed to open shared "
253 "texture");
254 gfxCriticalNote
255 << "RenderDXGITextureHost Failed to open shared texture, hr="
256 << gfx::hexa(hr);
257 return false;
259 MOZ_ASSERT(mTexture.get());
260 mTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutex));
262 MOZ_ASSERT(mHasKeyedMutex == !!mKeyedMutex);
263 if (mHasKeyedMutex != !!mKeyedMutex) {
264 gfxCriticalNoteOnce << "KeyedMutex mismatch";
266 return true;
269 bool RenderDXGITextureHost::EnsureLockable() {
270 if (mTextureHandle[0]) {
271 return true;
274 const auto& gle = gl::GLContextEGL::Cast(mGL);
275 const auto& egl = gle->mEgl;
277 // We use EGLStream to get the converted gl handle from d3d texture. The
278 // NV_stream_consumer_gltexture_yuv and ANGLE_stream_producer_d3d_texture
279 // could support nv12 and rgb d3d texture format.
280 if (!egl->IsExtensionSupported(
281 gl::EGLExtension::NV_stream_consumer_gltexture_yuv) ||
282 !egl->IsExtensionSupported(
283 gl::EGLExtension::ANGLE_stream_producer_d3d_texture)) {
284 gfxCriticalNote << "RenderDXGITextureHost egl extensions are not suppored";
285 return false;
288 // Get the D3D11 texture from shared handle.
289 if (!EnsureD3D11Texture2DWithGL()) {
290 return false;
293 // Create the EGLStream.
294 mStream = egl->fCreateStreamKHR(nullptr);
295 MOZ_ASSERT(mStream);
297 bool ok = true;
298 if (mFormat != gfx::SurfaceFormat::NV12 &&
299 mFormat != gfx::SurfaceFormat::P010 &&
300 mFormat != gfx::SurfaceFormat::P016) {
301 // The non-nv12 format.
303 mGL->fGenTextures(1, mTextureHandle);
304 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
305 LOCAL_GL_TEXTURE_EXTERNAL_OES,
306 mTextureHandle[0]);
307 ok &=
308 bool(egl->fStreamConsumerGLTextureExternalAttribsNV(mStream, nullptr));
309 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStream, nullptr));
310 } else {
311 // The nv12/p016 format.
313 // Setup the NV12 stream consumer/producer.
314 EGLAttrib consumerAttributes[] = {
315 LOCAL_EGL_COLOR_BUFFER_TYPE,
316 LOCAL_EGL_YUV_BUFFER_EXT,
317 LOCAL_EGL_YUV_NUMBER_OF_PLANES_EXT,
319 LOCAL_EGL_YUV_PLANE0_TEXTURE_UNIT_NV,
321 LOCAL_EGL_YUV_PLANE1_TEXTURE_UNIT_NV,
323 LOCAL_EGL_NONE,
325 mGL->fGenTextures(2, mTextureHandle);
326 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
327 LOCAL_GL_TEXTURE_EXTERNAL_OES,
328 mTextureHandle[0]);
329 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE1,
330 LOCAL_GL_TEXTURE_EXTERNAL_OES,
331 mTextureHandle[1]);
332 ok &= bool(egl->fStreamConsumerGLTextureExternalAttribsNV(
333 mStream, consumerAttributes));
334 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStream, nullptr));
337 const EGLAttrib frameAttributes[] = {
338 LOCAL_EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE,
339 static_cast<EGLAttrib>(mArrayIndex),
340 LOCAL_EGL_NONE,
343 // Insert the d3d texture.
344 ok &= bool(egl->fStreamPostD3DTextureANGLE(mStream, (void*)mTexture.get(),
345 frameAttributes));
347 if (!ok) {
348 gfxCriticalNote << "RenderDXGITextureHost init stream failed";
349 DeleteTextureHandle();
350 return false;
353 // Now, we could get the gl handle from the stream.
354 MOZ_ALWAYS_TRUE(egl->fStreamConsumerAcquireKHR(mStream));
356 return true;
359 wr::WrExternalImage RenderDXGITextureHost::Lock(uint8_t aChannelIndex,
360 gl::GLContext* aGL) {
361 if (mGL.get() != aGL) {
362 // Release the texture handle in the previous gl context.
363 DeleteTextureHandle();
364 mGL = aGL;
367 if (!mGL) {
368 // XXX Software WebRender is not handled yet.
369 // Software WebRender does not provide GLContext
370 gfxCriticalNoteOnce
371 << "Software WebRender is not suppored by RenderDXGITextureHost.";
372 return InvalidToWrExternalImage();
375 if (!EnsureLockable()) {
376 return InvalidToWrExternalImage();
379 if (!LockInternal()) {
380 return InvalidToWrExternalImage();
383 const auto uvs = GetUvCoords(GetSize(aChannelIndex));
384 return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), uvs.first.x,
385 uvs.first.y, uvs.second.x,
386 uvs.second.y);
389 bool RenderDXGITextureHost::LockInternal() {
390 if (!mLocked) {
391 if (mAcquireFenceInfo.mFenceHandle) {
392 if (!mAcquireFence) {
393 mAcquireFence = layers::FenceD3D11::CreateFromHandle(
394 mAcquireFenceInfo.mFenceHandle);
396 if (mAcquireFence) {
397 MOZ_ASSERT(mAcquireFenceInfo.mFenceHandle == mAcquireFence->mHandle);
399 mAcquireFence->Update(mAcquireFenceInfo.mFenceValue);
400 RefPtr<ID3D11Device> d3d11Device =
401 gfx::DeviceManagerDx::Get()->GetCompositorDevice();
402 mAcquireFence->Wait(d3d11Device);
405 if (mKeyedMutex) {
406 HRESULT hr = mKeyedMutex->AcquireSync(0, 10000);
407 if (hr != S_OK) {
408 gfxCriticalError() << "RenderDXGITextureHost AcquireSync timeout, hr="
409 << gfx::hexa(hr);
410 return false;
413 mLocked = true;
415 return true;
418 void RenderDXGITextureHost::Unlock() {
419 if (mLocked) {
420 if (mKeyedMutex) {
421 mKeyedMutex->ReleaseSync(0);
423 mLocked = false;
427 void RenderDXGITextureHost::ClearCachedResources() {
428 DeleteTextureHandle();
429 mGL = nullptr;
432 void RenderDXGITextureHost::DeleteTextureHandle() {
433 if (mTextureHandle[0] == 0) {
434 return;
437 MOZ_ASSERT(mGL.get());
438 if (!mGL) {
439 return;
442 if (mGL->MakeCurrent()) {
443 mGL->fDeleteTextures(2, mTextureHandle);
445 const auto& gle = gl::GLContextEGL::Cast(mGL);
446 const auto& egl = gle->mEgl;
447 if (mSurface) {
448 egl->fDestroySurface(mSurface);
450 if (mStream) {
451 egl->fDestroyStreamKHR(mStream);
455 for (int i = 0; i < 2; ++i) {
456 mTextureHandle[i] = 0;
459 mTexture = nullptr;
460 mKeyedMutex = nullptr;
461 mSurface = 0;
462 mStream = 0;
465 GLuint RenderDXGITextureHost::GetGLHandle(uint8_t aChannelIndex) const {
466 MOZ_ASSERT(((mFormat == gfx::SurfaceFormat::NV12 ||
467 mFormat == gfx::SurfaceFormat::P010 ||
468 mFormat == gfx::SurfaceFormat::P016) &&
469 aChannelIndex < 2) ||
470 aChannelIndex < 1);
471 return mTextureHandle[aChannelIndex];
474 gfx::IntSize RenderDXGITextureHost::GetSize(uint8_t aChannelIndex) const {
475 MOZ_ASSERT(((mFormat == gfx::SurfaceFormat::NV12 ||
476 mFormat == gfx::SurfaceFormat::P010 ||
477 mFormat == gfx::SurfaceFormat::P016) &&
478 aChannelIndex < 2) ||
479 aChannelIndex < 1);
481 if (aChannelIndex == 0) {
482 return mSize;
483 } else {
484 // The CbCr channel size is a half of Y channel size in NV12 format.
485 return mSize / 2;
489 bool RenderDXGITextureHost::SyncObjectNeeded() {
490 return mGpuProcessTextureId.isNothing() && !mHasKeyedMutex &&
491 !mAcquireFenceInfo.mFenceHandle;
494 RenderDXGIYCbCrTextureHost::RenderDXGIYCbCrTextureHost(
495 RefPtr<gfx::FileHandleWrapper> (&aHandles)[3],
496 gfx::YUVColorSpace aYUVColorSpace, gfx::ColorDepth aColorDepth,
497 gfx::ColorRange aColorRange, gfx::IntSize aSizeY, gfx::IntSize aSizeCbCr)
498 : mHandles{aHandles[0], aHandles[1], aHandles[2]},
499 mSurfaces{0},
500 mStreams{0},
501 mTextureHandles{0},
502 mYUVColorSpace(aYUVColorSpace),
503 mColorDepth(aColorDepth),
504 mColorRange(aColorRange),
505 mSizeY(aSizeY),
506 mSizeCbCr(aSizeCbCr),
507 mLocked(false) {
508 MOZ_COUNT_CTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost);
509 // Assume the chroma planes are rounded up if the luma plane is odd sized.
510 MOZ_ASSERT((mSizeCbCr.width == mSizeY.width ||
511 mSizeCbCr.width == (mSizeY.width + 1) >> 1) &&
512 (mSizeCbCr.height == mSizeY.height ||
513 mSizeCbCr.height == (mSizeY.height + 1) >> 1));
514 MOZ_ASSERT(aHandles[0] && aHandles[1] && aHandles[2]);
517 bool RenderDXGIYCbCrTextureHost::MapPlane(RenderCompositor* aCompositor,
518 uint8_t aChannelIndex,
519 PlaneInfo& aPlaneInfo) {
520 D3D11_MAPPED_SUBRESOURCE mappedSubresource;
521 if (!MapTexture(this, aCompositor, mTextures[aChannelIndex], mDeviceContext,
522 mCpuTexture[aChannelIndex], mappedSubresource)) {
523 return false;
526 aPlaneInfo.mSize = GetSize(aChannelIndex);
527 aPlaneInfo.mStride = mappedSubresource.RowPitch;
528 aPlaneInfo.mData = mappedSubresource.pData;
529 return true;
532 void RenderDXGIYCbCrTextureHost::UnmapPlanes() {
533 for (uint32_t i = 0; i < 3; i++) {
534 if (mCpuTexture[i]) {
535 mDeviceContext->Unmap(mCpuTexture[i], 0);
536 mCpuTexture[i] = nullptr;
539 mDeviceContext = nullptr;
542 RenderDXGIYCbCrTextureHost::~RenderDXGIYCbCrTextureHost() {
543 MOZ_COUNT_DTOR_INHERITED(RenderDXGIYCbCrTextureHost, RenderTextureHost);
544 DeleteTextureHandle();
547 bool RenderDXGIYCbCrTextureHost::EnsureLockable() {
548 if (mTextureHandles[0]) {
549 return true;
552 const auto& gle = gl::GLContextEGL::Cast(mGL);
553 const auto& egl = gle->mEgl;
555 // The eglCreatePbufferFromClientBuffer doesn't support R8 format, so we
556 // use EGLStream to get the converted gl handle from d3d R8 texture.
558 if (!egl->IsExtensionSupported(
559 gl::EGLExtension::NV_stream_consumer_gltexture_yuv) ||
560 !egl->IsExtensionSupported(
561 gl::EGLExtension::ANGLE_stream_producer_d3d_texture)) {
562 gfxCriticalNote
563 << "RenderDXGIYCbCrTextureHost egl extensions are not suppored";
564 return false;
567 // Fetch the D3D11 device.
568 EGLDeviceEXT eglDevice = nullptr;
569 egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
570 MOZ_ASSERT(eglDevice);
571 ID3D11Device* device = nullptr;
572 egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE,
573 (EGLAttrib*)&device);
574 // There's a chance this might fail if we end up on d3d9 angle for some
575 // reason.
576 if (!device) {
577 gfxCriticalNote << "RenderDXGIYCbCrTextureHost device is not available";
578 return false;
581 if (!EnsureD3D11Texture2D(device)) {
582 return false;
585 mGL->fGenTextures(3, mTextureHandles);
586 bool ok = true;
587 for (int i = 0; i < 3; ++i) {
588 ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0 + i,
589 LOCAL_GL_TEXTURE_EXTERNAL_OES,
590 mTextureHandles[i]);
592 // Create the EGLStream.
593 mStreams[i] = egl->fCreateStreamKHR(nullptr);
594 MOZ_ASSERT(mStreams[i]);
596 ok &= bool(
597 egl->fStreamConsumerGLTextureExternalAttribsNV(mStreams[i], nullptr));
598 ok &= bool(egl->fCreateStreamProducerD3DTextureANGLE(mStreams[i], nullptr));
600 // Insert the R8 texture.
601 ok &= bool(egl->fStreamPostD3DTextureANGLE(
602 mStreams[i], (void*)mTextures[i].get(), nullptr));
604 // Now, we could get the R8 gl handle from the stream.
605 MOZ_ALWAYS_TRUE(egl->fStreamConsumerAcquireKHR(mStreams[i]));
608 if (!ok) {
609 gfxCriticalNote << "RenderDXGIYCbCrTextureHost init stream failed";
610 DeleteTextureHandle();
611 return false;
614 return true;
617 bool RenderDXGIYCbCrTextureHost::EnsureD3D11Texture2D(ID3D11Device* aDevice) {
618 RefPtr<ID3D11Device1> device1;
619 aDevice->QueryInterface((ID3D11Device1**)getter_AddRefs(device1));
620 if (!device1) {
621 gfxCriticalNoteOnce << "Failed to get ID3D11Device1";
622 return false;
625 if (mTextures[0]) {
626 RefPtr<ID3D11Device> device;
627 mTextures[0]->GetDevice(getter_AddRefs(device));
628 if (aDevice != device) {
629 gfxCriticalNote << "RenderDXGIYCbCrTextureHost uses obsoleted device";
630 return false;
634 if (mTextureHandles[0]) {
635 return true;
638 for (int i = 0; i < 3; ++i) {
639 // Get the R8 D3D11 texture from shared handle.
640 HRESULT hr = device1->OpenSharedResource1(
641 (HANDLE)mHandles[i]->GetHandle(), __uuidof(ID3D11Texture2D),
642 (void**)(ID3D11Texture2D**)getter_AddRefs(mTextures[i]));
643 if (FAILED(hr)) {
644 NS_WARNING(
645 "RenderDXGIYCbCrTextureHost::EnsureLockable(): Failed to open "
646 "shared "
647 "texture");
648 gfxCriticalNote
649 << "RenderDXGIYCbCrTextureHost Failed to open shared texture, hr="
650 << gfx::hexa(hr);
651 return false;
655 for (int i = 0; i < 3; ++i) {
656 mTextures[i]->QueryInterface(
657 (IDXGIKeyedMutex**)getter_AddRefs(mKeyedMutexs[i]));
659 return true;
662 bool RenderDXGIYCbCrTextureHost::LockInternal() {
663 if (!mLocked) {
664 if (mKeyedMutexs[0]) {
665 for (const auto& mutex : mKeyedMutexs) {
666 HRESULT hr = mutex->AcquireSync(0, 10000);
667 if (hr != S_OK) {
668 gfxCriticalError()
669 << "RenderDXGIYCbCrTextureHost AcquireSync timeout, hr="
670 << gfx::hexa(hr);
671 return false;
675 mLocked = true;
677 return true;
680 wr::WrExternalImage RenderDXGIYCbCrTextureHost::Lock(uint8_t aChannelIndex,
681 gl::GLContext* aGL) {
682 if (mGL.get() != aGL) {
683 // Release the texture handle in the previous gl context.
684 DeleteTextureHandle();
685 mGL = aGL;
688 if (!mGL) {
689 // XXX Software WebRender is not handled yet.
690 // Software WebRender does not provide GLContext
691 gfxCriticalNoteOnce << "Software WebRender is not suppored by "
692 "RenderDXGIYCbCrTextureHost.";
693 return InvalidToWrExternalImage();
696 if (!EnsureLockable()) {
697 return InvalidToWrExternalImage();
700 if (!LockInternal()) {
701 return InvalidToWrExternalImage();
704 const auto uvs = GetUvCoords(GetSize(aChannelIndex));
705 return NativeTextureToWrExternalImage(GetGLHandle(aChannelIndex), uvs.first.x,
706 uvs.first.y, uvs.second.x,
707 uvs.second.y);
710 void RenderDXGIYCbCrTextureHost::Unlock() {
711 if (mLocked) {
712 if (mKeyedMutexs[0]) {
713 for (const auto& mutex : mKeyedMutexs) {
714 mutex->ReleaseSync(0);
717 mLocked = false;
721 void RenderDXGIYCbCrTextureHost::ClearCachedResources() {
722 DeleteTextureHandle();
723 mGL = nullptr;
726 GLuint RenderDXGIYCbCrTextureHost::GetGLHandle(uint8_t aChannelIndex) const {
727 MOZ_ASSERT(aChannelIndex < 3);
729 return mTextureHandles[aChannelIndex];
732 gfx::IntSize RenderDXGIYCbCrTextureHost::GetSize(uint8_t aChannelIndex) const {
733 MOZ_ASSERT(aChannelIndex < 3);
735 if (aChannelIndex == 0) {
736 return mSizeY;
737 } else {
738 return mSizeCbCr;
742 void RenderDXGIYCbCrTextureHost::DeleteTextureHandle() {
743 if (mTextureHandles[0] == 0) {
744 return;
747 MOZ_ASSERT(mGL.get());
748 if (!mGL) {
749 return;
752 if (mGL->MakeCurrent()) {
753 mGL->fDeleteTextures(3, mTextureHandles);
755 const auto& gle = gl::GLContextEGL::Cast(mGL);
756 const auto& egl = gle->mEgl;
757 for (int i = 0; i < 3; ++i) {
758 mTextureHandles[i] = 0;
759 mTextures[i] = nullptr;
760 mKeyedMutexs[i] = nullptr;
762 if (mSurfaces[i]) {
763 egl->fDestroySurface(mSurfaces[i]);
764 mSurfaces[i] = 0;
766 if (mStreams[i]) {
767 egl->fDestroyStreamKHR(mStreams[i]);
768 mStreams[i] = 0;
774 } // namespace wr
775 } // namespace mozilla