1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 4; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "SharedSurfaceANGLE.h"
9 #include "GLContextEGL.h"
10 #include "GLLibraryEGL.h"
11 #include "mozilla/gfx/DeviceManagerDx.h"
12 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
17 // Returns `EGL_NO_SURFACE` (`0`) on error.
18 static EGLSurface
CreatePBufferSurface(EglDisplay
* egl
, EGLConfig config
,
19 const gfx::IntSize
& size
) {
20 const EGLint attribs
[] = {LOCAL_EGL_WIDTH
, size
.width
, LOCAL_EGL_HEIGHT
,
21 size
.height
, LOCAL_EGL_NONE
};
23 EGLSurface surface
= egl
->fCreatePbufferSurface(config
, attribs
);
25 EGLint err
= egl
->mLib
->fGetError();
26 gfxCriticalError() << "Failed to create Pbuffer surface error: "
27 << gfx::hexa(err
) << " Size : " << size
;
35 UniquePtr
<SharedSurface_ANGLEShareHandle
>
36 SharedSurface_ANGLEShareHandle::Create(const SharedSurfaceDesc
& desc
) {
37 const auto& gle
= GLContextEGL::Cast(desc
.gl
);
38 const auto& egl
= gle
->mEgl
;
40 MOZ_ASSERT(egl
->IsExtensionSupported(
41 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle
));
43 const auto& config
= gle
->mConfig
;
46 EGLSurface pbuffer
= CreatePBufferSurface(egl
.get(), config
, desc
.size
);
47 if (!pbuffer
) return nullptr;
49 // Declare everything before 'goto's.
50 HANDLE shareHandle
= nullptr;
51 bool ok
= egl
->fQuerySurfacePointerANGLE(
52 pbuffer
, LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE
, &shareHandle
);
54 egl
->fDestroySurface(pbuffer
);
57 void* opaqueKeyedMutex
= nullptr;
58 egl
->fQuerySurfacePointerANGLE(pbuffer
, LOCAL_EGL_DXGI_KEYED_MUTEX_ANGLE
,
60 RefPtr
<IDXGIKeyedMutex
> keyedMutex
=
61 static_cast<IDXGIKeyedMutex
*>(opaqueKeyedMutex
);
64 std::string
envStr("1");
65 static auto env
= PR_GetEnv("MOZ_REQUIRE_KEYED_MUTEX");
70 MOZ_ASSERT(keyedMutex
, "set MOZ_REQUIRE_KEYED_MUTEX=0 to allow");
75 return AsUnique(new SharedSurface_ANGLEShareHandle(desc
, egl
, pbuffer
,
76 shareHandle
, keyedMutex
));
79 SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(
80 const SharedSurfaceDesc
& desc
, const std::weak_ptr
<EglDisplay
>& egl
,
81 EGLSurface pbuffer
, HANDLE shareHandle
,
82 const RefPtr
<IDXGIKeyedMutex
>& keyedMutex
)
83 : SharedSurface(desc
, nullptr),
86 mShareHandle(shareHandle
),
87 mKeyedMutex(keyedMutex
) {}
89 SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() {
90 const auto& gl
= mDesc
.gl
;
92 if (gl
&& GLContextEGL::Cast(gl
)->GetEGLSurfaceOverride() == mPBuffer
) {
93 GLContextEGL::Cast(gl
)->SetEGLSurfaceOverride(EGL_NO_SURFACE
);
95 const auto egl
= mEGL
.lock();
97 egl
->fDestroySurface(mPBuffer
);
101 void SharedSurface_ANGLEShareHandle::LockProdImpl() {
102 const auto& gl
= mDesc
.gl
;
103 GLContextEGL::Cast(gl
)->SetEGLSurfaceOverride(mPBuffer
);
106 void SharedSurface_ANGLEShareHandle::UnlockProdImpl() {}
108 void SharedSurface_ANGLEShareHandle::ProducerAcquireImpl() {
110 HRESULT hr
= mKeyedMutex
->AcquireSync(0, 10000);
111 if (hr
== WAIT_TIMEOUT
) {
112 MOZ_CRASH("GFX: ANGLE share handle timeout");
117 void SharedSurface_ANGLEShareHandle::ProducerReleaseImpl() {
118 const auto& gl
= mDesc
.gl
;
120 // XXX: ReleaseSync() has an implicit flush of the D3D commands
121 // whether we need Flush() or not depends on the ANGLE semantics.
122 // For now, we'll just do it
124 mKeyedMutex
->ReleaseSync(0);
130 void SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl() {
131 ProducerAcquireImpl();
134 void SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl() {
136 mKeyedMutex
->ReleaseSync(0);
141 Maybe
<layers::SurfaceDescriptor
>
142 SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor() {
143 const auto format
= gfx::SurfaceFormat::B8G8R8A8
;
144 return Some(layers::SurfaceDescriptorD3D10(
145 (WindowsHandle
)mShareHandle
, format
, mDesc
.size
,
146 gfx::YUVColorSpace::Identity
, gfx::ColorRange::FULL
));
149 class ScopedLockTexture final
{
151 explicit ScopedLockTexture(ID3D11Texture2D
* texture
, bool* succeeded
)
152 : mIsLocked(false), mTexture(texture
) {
153 MOZ_ASSERT(NS_IsMainThread(),
154 "Must be on the main thread to use d3d11 immediate context");
155 MOZ_ASSERT(mTexture
);
156 MOZ_ASSERT(succeeded
);
160 mTexture
->QueryInterface((IDXGIKeyedMutex
**)getter_AddRefs(mMutex
));
162 hr
= mMutex
->AcquireSync(0, 10000);
163 if (hr
== WAIT_TIMEOUT
) {
164 MOZ_CRASH("GFX: ANGLE scoped lock timeout");
168 NS_WARNING("Failed to lock the texture");
173 RefPtr
<ID3D11Device
> device
=
174 gfx::DeviceManagerDx::Get()->GetContentDevice();
179 device
->GetImmediateContext(getter_AddRefs(mDeviceContext
));
181 mTexture
->GetDesc(&mDesc
);
183 mDesc
.Usage
= D3D11_USAGE_STAGING
;
184 mDesc
.CPUAccessFlags
= D3D11_CPU_ACCESS_READ
;
187 hr
= device
->CreateTexture2D(&mDesc
, nullptr,
188 getter_AddRefs(mCopiedTexture
));
194 mDeviceContext
->CopyResource(mCopiedTexture
, mTexture
);
196 hr
= mDeviceContext
->Map(mCopiedTexture
, 0, D3D11_MAP_READ
, 0,
206 ~ScopedLockTexture() {
207 mDeviceContext
->Unmap(mCopiedTexture
, 0);
209 HRESULT hr
= mMutex
->ReleaseSync(0);
211 NS_WARNING("Failed to unlock the texture");
218 RefPtr
<ID3D11Texture2D
> mTexture
;
219 RefPtr
<ID3D11Texture2D
> mCopiedTexture
;
220 RefPtr
<IDXGIKeyedMutex
> mMutex
;
221 RefPtr
<ID3D11DeviceContext
> mDeviceContext
;
222 D3D11_TEXTURE2D_DESC mDesc
;
223 D3D11_MAPPED_SUBRESOURCE mSubresource
;
226 ////////////////////////////////////////////////////////////////////////////////
230 UniquePtr
<SurfaceFactory_ANGLEShareHandle
>
231 SurfaceFactory_ANGLEShareHandle::Create(GLContext
& gl
) {
232 if (!gl
.IsANGLE()) return nullptr;
234 const auto& gle
= *GLContextEGL::Cast(&gl
);
235 const auto& egl
= gle
.mEgl
;
237 if (!egl
->IsExtensionSupported(
238 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle
)) {
242 if (XRE_IsContentProcess()) {
243 gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
246 gfx::DeviceManagerDx
* dm
= gfx::DeviceManagerDx::Get();
248 if (gl
.IsWARP() != dm
->IsWARP() || !dm
->TextureSharingWorks()) {
252 return AsUnique(new SurfaceFactory_ANGLEShareHandle(
253 {&gl
, SharedSurfaceType::EGLSurfaceANGLE
, layers::TextureType::D3D11
,
258 } /* namespace mozilla */