Bug 1890689 accumulate input in LargerReceiverBlockSizeThanDesiredBuffering GTest...
[gecko.git] / gfx / gl / SharedSurfaceANGLE.cpp
blob8fae962b9f03367ae25837206e342b674e50715a
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/gfx/FileHandleWrapper.h"
13 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
15 namespace mozilla {
16 namespace gl {
18 static ID3D11Device* GetD3D11DeviceOfEGLDisplay(GLContextEGL* gle) {
19 const auto& egl = gle->mEgl;
20 MOZ_ASSERT(egl);
21 if (!egl ||
22 !egl->mLib->IsExtensionSupported(gl::EGLLibExtension::EXT_device_query)) {
23 return nullptr;
26 // Fetch the D3D11 device.
27 EGLDeviceEXT eglDevice = nullptr;
28 egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
29 MOZ_ASSERT(eglDevice);
30 ID3D11Device* device = nullptr;
31 egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE,
32 (EGLAttrib*)&device);
33 if (!device) {
34 return nullptr;
36 return device;
39 // Returns `EGL_NO_SURFACE` (`0`) on error.
40 static EGLSurface CreatePBufferSurface(EglDisplay* egl, EGLConfig config,
41 const gfx::IntSize& size,
42 RefPtr<ID3D11Texture2D> texture2D) {
43 const EGLint attribs[] = {LOCAL_EGL_WIDTH, size.width, LOCAL_EGL_HEIGHT,
44 size.height, LOCAL_EGL_NONE};
45 const auto buffer = reinterpret_cast<EGLClientBuffer>(texture2D.get());
47 EGLSurface surface = egl->fCreatePbufferFromClientBuffer(
48 LOCAL_EGL_D3D_TEXTURE_ANGLE, buffer, config, attribs);
49 if (!surface) {
50 EGLint err = egl->mLib->fGetError();
51 gfxCriticalError() << "Failed to create Pbuffer surface error: "
52 << gfx::hexa(err) << " Size : " << size;
53 return 0;
56 return surface;
59 /*static*/
60 UniquePtr<SharedSurface_ANGLEShareHandle>
61 SharedSurface_ANGLEShareHandle::Create(const SharedSurfaceDesc& desc) {
62 const auto& gle = GLContextEGL::Cast(desc.gl);
63 const auto& egl = gle->mEgl;
64 MOZ_ASSERT(egl);
65 MOZ_ASSERT(egl->IsExtensionSupported(
66 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle));
68 auto* device = GetD3D11DeviceOfEGLDisplay(gle);
69 if (!device) {
70 return nullptr;
73 // Create a texture in case we need to readback.
74 const DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM;
75 CD3D11_TEXTURE2D_DESC texDesc(
76 format, desc.size.width, desc.size.height, 1, 1,
77 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
78 texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
79 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
81 RefPtr<ID3D11Texture2D> texture2D;
82 auto hr =
83 device->CreateTexture2D(&texDesc, nullptr, getter_AddRefs(texture2D));
84 if (FAILED(hr)) {
85 return nullptr;
88 RefPtr<IDXGIResource1> texDXGI;
89 hr = texture2D->QueryInterface(__uuidof(IDXGIResource1),
90 getter_AddRefs(texDXGI));
91 if (FAILED(hr)) {
92 return nullptr;
95 HANDLE sharedHandle = nullptr;
96 texDXGI->CreateSharedHandle(
97 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
98 &sharedHandle);
100 RefPtr<gfx::FileHandleWrapper> handle =
101 new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle));
103 RefPtr<IDXGIKeyedMutex> keyedMutex;
104 texture2D->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(keyedMutex));
105 if (!keyedMutex) {
106 return nullptr;
109 const auto& config = gle->mSurfaceConfig;
110 MOZ_ASSERT(config);
112 EGLSurface pbuffer =
113 CreatePBufferSurface(egl.get(), config, desc.size, texture2D);
114 if (!pbuffer) return nullptr;
116 return AsUnique(new SharedSurface_ANGLEShareHandle(
117 desc, egl, pbuffer, std::move(handle), keyedMutex));
120 SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(
121 const SharedSurfaceDesc& desc, const std::weak_ptr<EglDisplay>& egl,
122 EGLSurface pbuffer, RefPtr<gfx::FileHandleWrapper>&& aSharedHandle,
123 const RefPtr<IDXGIKeyedMutex>& keyedMutex)
124 : SharedSurface(desc, nullptr),
125 mEGL(egl),
126 mPBuffer(pbuffer),
127 mSharedHandle(std::move(aSharedHandle)),
128 mKeyedMutex(keyedMutex) {}
130 SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() {
131 const auto& gl = mDesc.gl;
133 if (gl && GLContextEGL::Cast(gl)->GetEGLSurfaceOverride() == mPBuffer) {
134 GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(EGL_NO_SURFACE);
136 const auto egl = mEGL.lock();
137 if (egl) {
138 egl->fDestroySurface(mPBuffer);
142 void SharedSurface_ANGLEShareHandle::LockProdImpl() {
143 const auto& gl = mDesc.gl;
144 GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(mPBuffer);
147 void SharedSurface_ANGLEShareHandle::UnlockProdImpl() {}
149 void SharedSurface_ANGLEShareHandle::ProducerAcquireImpl() {
150 HRESULT hr = mKeyedMutex->AcquireSync(0, 10000);
151 if (hr == WAIT_TIMEOUT) {
152 MOZ_CRASH("GFX: ANGLE share handle timeout");
156 void SharedSurface_ANGLEShareHandle::ProducerReleaseImpl() {
157 const auto& gl = mDesc.gl;
158 // XXX: ReleaseSync() has an implicit flush of the D3D commands
159 // whether we need Flush() or not depends on the ANGLE semantics.
160 // For now, we'll just do it
161 gl->fFlush();
162 mKeyedMutex->ReleaseSync(0);
165 void SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl() {
166 ProducerAcquireImpl();
169 void SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl() {
170 mKeyedMutex->ReleaseSync(0);
173 Maybe<layers::SurfaceDescriptor>
174 SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor() {
175 const auto format = gfx::SurfaceFormat::B8G8R8A8;
176 return Some(layers::SurfaceDescriptorD3D10(
177 mSharedHandle, /* gpuProcessTextureId */ Nothing(),
178 /* arrayIndex */ 0, format, mDesc.size, mDesc.colorSpace,
179 gfx::ColorRange::FULL, /* hasKeyedMutex */ true,
180 /* fenceInfo */ Nothing(), /* gpuProcessQueryId */ Nothing()));
183 ////////////////////////////////////////////////////////////////////////////////
184 // Factory
186 /*static*/
187 UniquePtr<SurfaceFactory_ANGLEShareHandle>
188 SurfaceFactory_ANGLEShareHandle::Create(GLContext& gl) {
189 if (!gl.IsANGLE()) return nullptr;
191 const auto& gle = *GLContextEGL::Cast(&gl);
192 const auto& egl = gle.mEgl;
194 if (!egl->IsExtensionSupported(
195 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle)) {
196 return nullptr;
199 if (XRE_IsContentProcess()) {
200 gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
203 gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
204 MOZ_ASSERT(dm);
205 if (gl.IsWARP() != dm->IsWARP() || !dm->TextureSharingWorks()) {
206 return nullptr;
209 return AsUnique(new SurfaceFactory_ANGLEShareHandle(
210 {&gl, SharedSurfaceType::EGLSurfaceANGLE, layers::TextureType::D3D11,
211 true}));
214 } /* namespace gl */
215 } /* namespace mozilla */