Bug 1866777 - Disable test_race_cache_with_network.js on windows opt for frequent...
[gecko.git] / gfx / gl / SharedSurfaceANGLE.cpp
blob0b343d172afb0ad21d8bf606f14f956930f5420c
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/D3D11Checks.h"
12 #include "mozilla/gfx/DeviceManagerDx.h"
13 #include "mozilla/gfx/FileHandleWrapper.h"
14 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
16 namespace mozilla {
17 namespace gl {
19 static ID3D11Device* GetD3D11DeviceOfEGLDisplay(GLContextEGL* gle) {
20 const auto& egl = gle->mEgl;
21 MOZ_ASSERT(egl);
22 if (!egl ||
23 !egl->mLib->IsExtensionSupported(gl::EGLLibExtension::EXT_device_query)) {
24 return nullptr;
27 // Fetch the D3D11 device.
28 EGLDeviceEXT eglDevice = nullptr;
29 egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice);
30 MOZ_ASSERT(eglDevice);
31 ID3D11Device* device = nullptr;
32 egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE,
33 (EGLAttrib*)&device);
34 if (!device) {
35 return nullptr;
37 return device;
40 // Returns `EGL_NO_SURFACE` (`0`) on error.
41 static EGLSurface CreatePBufferSurface(EglDisplay* egl, EGLConfig config,
42 const gfx::IntSize& size,
43 RefPtr<ID3D11Texture2D> texture2D) {
44 const EGLint attribs[] = {LOCAL_EGL_WIDTH, size.width, LOCAL_EGL_HEIGHT,
45 size.height, LOCAL_EGL_NONE};
46 const auto buffer = reinterpret_cast<EGLClientBuffer>(texture2D.get());
48 EGLSurface surface = egl->fCreatePbufferFromClientBuffer(
49 LOCAL_EGL_D3D_TEXTURE_ANGLE, buffer, config, attribs);
50 if (!surface) {
51 EGLint err = egl->mLib->fGetError();
52 gfxCriticalError() << "Failed to create Pbuffer surface error: "
53 << gfx::hexa(err) << " Size : " << size;
54 return 0;
57 return surface;
60 /*static*/
61 UniquePtr<SharedSurface_ANGLEShareHandle>
62 SharedSurface_ANGLEShareHandle::Create(const SharedSurfaceDesc& desc) {
63 const auto& gle = GLContextEGL::Cast(desc.gl);
64 const auto& egl = gle->mEgl;
65 MOZ_ASSERT(egl);
66 MOZ_ASSERT(egl->IsExtensionSupported(
67 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle));
69 auto* device = GetD3D11DeviceOfEGLDisplay(gle);
70 if (!device) {
71 return nullptr;
74 // Create a texture in case we need to readback.
75 const DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM;
76 CD3D11_TEXTURE2D_DESC texDesc(
77 format, desc.size.width, desc.size.height, 1, 1,
78 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
79 texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE |
80 D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
82 RefPtr<ID3D11Texture2D> texture2D;
83 auto hr =
84 device->CreateTexture2D(&texDesc, nullptr, getter_AddRefs(texture2D));
85 if (FAILED(hr)) {
86 return nullptr;
89 RefPtr<IDXGIResource1> texDXGI;
90 hr = texture2D->QueryInterface(__uuidof(IDXGIResource1),
91 getter_AddRefs(texDXGI));
92 if (FAILED(hr)) {
93 return nullptr;
96 HANDLE sharedHandle = nullptr;
97 texDXGI->CreateSharedHandle(
98 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr,
99 &sharedHandle);
101 RefPtr<gfx::FileHandleWrapper> handle =
102 new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle));
104 RefPtr<IDXGIKeyedMutex> keyedMutex;
105 texture2D->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(keyedMutex));
106 if (!keyedMutex) {
107 return nullptr;
110 const auto& config = gle->mSurfaceConfig;
111 MOZ_ASSERT(config);
113 EGLSurface pbuffer =
114 CreatePBufferSurface(egl.get(), config, desc.size, texture2D);
115 if (!pbuffer) return nullptr;
117 return AsUnique(new SharedSurface_ANGLEShareHandle(
118 desc, egl, pbuffer, std::move(handle), keyedMutex));
121 SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle(
122 const SharedSurfaceDesc& desc, const std::weak_ptr<EglDisplay>& egl,
123 EGLSurface pbuffer, RefPtr<gfx::FileHandleWrapper>&& aSharedHandle,
124 const RefPtr<IDXGIKeyedMutex>& keyedMutex)
125 : SharedSurface(desc, nullptr),
126 mEGL(egl),
127 mPBuffer(pbuffer),
128 mSharedHandle(std::move(aSharedHandle)),
129 mKeyedMutex(keyedMutex) {}
131 SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() {
132 const auto& gl = mDesc.gl;
134 if (gl && GLContextEGL::Cast(gl)->GetEGLSurfaceOverride() == mPBuffer) {
135 GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(EGL_NO_SURFACE);
137 const auto egl = mEGL.lock();
138 if (egl) {
139 egl->fDestroySurface(mPBuffer);
143 void SharedSurface_ANGLEShareHandle::LockProdImpl() {
144 const auto& gl = mDesc.gl;
145 GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(mPBuffer);
148 void SharedSurface_ANGLEShareHandle::UnlockProdImpl() {}
150 bool SharedSurface_ANGLEShareHandle::ProducerAcquireImpl() {
151 HRESULT hr = mKeyedMutex->AcquireSync(0, 10000);
152 return gfx::D3D11Checks::DidAcquireSyncSucceed(__func__, hr);
155 void SharedSurface_ANGLEShareHandle::ProducerReleaseImpl() {
156 const auto& gl = mDesc.gl;
157 // XXX: ReleaseSync() has an implicit flush of the D3D commands
158 // whether we need Flush() or not depends on the ANGLE semantics.
159 // For now, we'll just do it
160 gl->fFlush();
161 mKeyedMutex->ReleaseSync(0);
164 bool SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl() {
165 return ProducerAcquireImpl();
168 void SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl() {
169 mKeyedMutex->ReleaseSync(0);
172 Maybe<layers::SurfaceDescriptor>
173 SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor() {
174 const auto format = gfx::SurfaceFormat::B8G8R8A8;
175 return Some(layers::SurfaceDescriptorD3D10(
176 mSharedHandle, /* gpuProcessTextureId */ Nothing(),
177 /* arrayIndex */ 0, format, mDesc.size, mDesc.colorSpace,
178 gfx::ColorRange::FULL, /* hasKeyedMutex */ true,
179 /* fenceInfo */ Nothing()));
182 ////////////////////////////////////////////////////////////////////////////////
183 // Factory
185 /*static*/
186 UniquePtr<SurfaceFactory_ANGLEShareHandle>
187 SurfaceFactory_ANGLEShareHandle::Create(GLContext& gl) {
188 if (!gl.IsANGLE()) return nullptr;
190 const auto& gle = *GLContextEGL::Cast(&gl);
191 const auto& egl = gle.mEgl;
193 if (!egl->IsExtensionSupported(
194 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle)) {
195 return nullptr;
198 if (XRE_IsContentProcess()) {
199 gfxPlatform::GetPlatform()->EnsureDevicesInitialized();
202 gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get();
203 MOZ_ASSERT(dm);
204 if (gl.IsWARP() != dm->IsWARP() || !dm->TextureSharingWorks()) {
205 return nullptr;
208 return AsUnique(new SurfaceFactory_ANGLEShareHandle(
209 {&gl, SharedSurfaceType::EGLSurfaceANGLE, layers::TextureType::D3D11,
210 true}));
213 } /* namespace gl */
214 } /* namespace mozilla */