Bug 1703443 - pt 6. Move RunNextCollectorTimer() into CCGCScheduler r=smaug
[gecko.git] / gfx / gl / SharedSurfaceANGLE.cpp
blob980f2ca8774af4f1078eda6205f2c46b8db1d174
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"
8 #include <d3d11.h>
9 #include "GLContextEGL.h"
10 #include "GLLibraryEGL.h"
11 #include "mozilla/gfx/DeviceManagerDx.h"
12 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
14 namespace mozilla {
15 namespace gl {
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);
24 if (!surface) {
25 EGLint err = egl->mLib->fGetError();
26 gfxCriticalError() << "Failed to create Pbuffer surface error: "
27 << gfx::hexa(err) << " Size : " << size;
28 return 0;
31 return surface;
34 /*static*/
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;
39 MOZ_ASSERT(egl);
40 MOZ_ASSERT(egl->IsExtensionSupported(
41 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle));
43 const auto& config = gle->mConfig;
44 MOZ_ASSERT(config);
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);
53 if (!ok) {
54 egl->fDestroySurface(pbuffer);
55 return nullptr;
57 void* opaqueKeyedMutex = nullptr;
58 egl->fQuerySurfacePointerANGLE(pbuffer, LOCAL_EGL_DXGI_KEYED_MUTEX_ANGLE,
59 &opaqueKeyedMutex);
60 RefPtr<IDXGIKeyedMutex> keyedMutex =
61 static_cast<IDXGIKeyedMutex*>(opaqueKeyedMutex);
62 #ifdef DEBUG
63 if (!keyedMutex) {
64 std::string envStr("1");
65 static auto env = PR_GetEnv("MOZ_REQUIRE_KEYED_MUTEX");
66 if (env) {
67 envStr = env;
69 if (envStr != "0") {
70 MOZ_ASSERT(keyedMutex, "set MOZ_REQUIRE_KEYED_MUTEX=0 to allow");
73 #endif
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),
84 mEGL(egl),
85 mPBuffer(pbuffer),
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();
96 if (egl) {
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() {
109 if (mKeyedMutex) {
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;
119 if (mKeyedMutex) {
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
123 gl->fFlush();
124 mKeyedMutex->ReleaseSync(0);
125 return;
127 gl->fFinish();
130 void SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl() {
131 ProducerAcquireImpl();
134 void SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl() {
135 if (mKeyedMutex) {
136 mKeyedMutex->ReleaseSync(0);
137 return;
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 {
150 public:
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);
157 *succeeded = false;
159 HRESULT hr;
160 mTexture->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(mMutex));
161 if (mMutex) {
162 hr = mMutex->AcquireSync(0, 10000);
163 if (hr == WAIT_TIMEOUT) {
164 MOZ_CRASH("GFX: ANGLE scoped lock timeout");
167 if (FAILED(hr)) {
168 NS_WARNING("Failed to lock the texture");
169 return;
173 RefPtr<ID3D11Device> device =
174 gfx::DeviceManagerDx::Get()->GetContentDevice();
175 if (!device) {
176 return;
179 device->GetImmediateContext(getter_AddRefs(mDeviceContext));
181 mTexture->GetDesc(&mDesc);
182 mDesc.BindFlags = 0;
183 mDesc.Usage = D3D11_USAGE_STAGING;
184 mDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
185 mDesc.MiscFlags = 0;
187 hr = device->CreateTexture2D(&mDesc, nullptr,
188 getter_AddRefs(mCopiedTexture));
190 if (FAILED(hr)) {
191 return;
194 mDeviceContext->CopyResource(mCopiedTexture, mTexture);
196 hr = mDeviceContext->Map(mCopiedTexture, 0, D3D11_MAP_READ, 0,
197 &mSubresource);
198 if (FAILED(hr)) {
199 return;
202 *succeeded = true;
203 mIsLocked = true;
206 ~ScopedLockTexture() {
207 mDeviceContext->Unmap(mCopiedTexture, 0);
208 if (mMutex) {
209 HRESULT hr = mMutex->ReleaseSync(0);
210 if (FAILED(hr)) {
211 NS_WARNING("Failed to unlock the texture");
214 mIsLocked = false;
217 bool mIsLocked;
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 ////////////////////////////////////////////////////////////////////////////////
227 // Factory
229 /*static*/
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)) {
239 return nullptr;
242 if (XRE_IsContentProcess()) {
243 gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
246 gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
247 MOZ_ASSERT(dm);
248 if (gl.IsWARP() != dm->IsWARP() || !dm->TextureSharingWorks()) {
249 return nullptr;
252 return AsUnique(new SurfaceFactory_ANGLEShareHandle(
253 {&gl, SharedSurfaceType::EGLSurfaceANGLE, layers::TextureType::D3D11,
254 true}));
257 } /* namespace gl */
258 } /* namespace mozilla */