SharedSurfaceANGLE.cpp (9029B)
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/. */ 5 6 #include "SharedSurfaceANGLE.h" 7 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/CompositeProcessD3D11FencesHolderMap.h" 14 #include "mozilla/layers/FenceD3D11.h" 15 #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc 16 17 namespace mozilla { 18 namespace gl { 19 20 static ID3D11Device* GetD3D11DeviceOfEGLDisplay(GLContextEGL* gle) { 21 const auto& egl = gle->mEgl; 22 MOZ_ASSERT(egl); 23 if (!egl || 24 !egl->mLib->IsExtensionSupported(gl::EGLLibExtension::EXT_device_query)) { 25 return nullptr; 26 } 27 28 // Fetch the D3D11 device. 29 EGLDeviceEXT eglDevice = nullptr; 30 egl->fQueryDisplayAttribEXT(LOCAL_EGL_DEVICE_EXT, (EGLAttrib*)&eglDevice); 31 MOZ_ASSERT(eglDevice); 32 ID3D11Device* device = nullptr; 33 egl->mLib->fQueryDeviceAttribEXT(eglDevice, LOCAL_EGL_D3D11_DEVICE_ANGLE, 34 (EGLAttrib*)&device); 35 if (!device) { 36 return nullptr; 37 } 38 return device; 39 } 40 41 // Returns `EGL_NO_SURFACE` (`0`) on error. 42 static EGLSurface CreatePBufferSurface(EglDisplay* egl, EGLConfig config, 43 const gfx::IntSize& size, 44 RefPtr<ID3D11Texture2D> texture2D) { 45 const EGLint attribs[] = {LOCAL_EGL_WIDTH, size.width, LOCAL_EGL_HEIGHT, 46 size.height, LOCAL_EGL_NONE}; 47 const auto buffer = reinterpret_cast<EGLClientBuffer>(texture2D.get()); 48 49 EGLSurface surface = egl->fCreatePbufferFromClientBuffer( 50 LOCAL_EGL_D3D_TEXTURE_ANGLE, buffer, config, attribs); 51 if (!surface) { 52 EGLint err = egl->mLib->fGetError(); 53 gfxCriticalError() << "Failed to create Pbuffer surface error: " 54 << gfx::hexa(err) << " Size : " << size; 55 return 0; 56 } 57 58 return surface; 59 } 60 61 /*static*/ 62 UniquePtr<SharedSurface_ANGLEShareHandle> 63 SharedSurface_ANGLEShareHandle::Create(const SharedSurfaceDesc& desc) { 64 const auto& gle = GLContextEGL::Cast(desc.gl); 65 const auto& egl = gle->mEgl; 66 MOZ_ASSERT(egl); 67 MOZ_ASSERT(egl->IsExtensionSupported( 68 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle)); 69 70 auto* device = GetD3D11DeviceOfEGLDisplay(gle); 71 if (!device) { 72 return nullptr; 73 } 74 75 // Create a texture in case we need to readback. 76 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 77 const bool useFence = 78 fencesHolderMap && layers::FenceD3D11::IsSupported(device); 79 const DXGI_FORMAT format = DXGI_FORMAT_B8G8R8A8_UNORM; 80 CD3D11_TEXTURE2D_DESC texDesc( 81 format, desc.size.width, desc.size.height, 1, 1, 82 D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); 83 texDesc.MiscFlags = D3D11_RESOURCE_MISC_SHARED_NTHANDLE; 84 if (useFence) { 85 texDesc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED; 86 } else { 87 texDesc.MiscFlags |= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX; 88 } 89 90 RefPtr<ID3D11Texture2D> texture2D; 91 auto hr = 92 device->CreateTexture2D(&texDesc, nullptr, getter_AddRefs(texture2D)); 93 if (FAILED(hr)) { 94 return nullptr; 95 } 96 97 RefPtr<IDXGIResource1> texDXGI; 98 hr = texture2D->QueryInterface(__uuidof(IDXGIResource1), 99 getter_AddRefs(texDXGI)); 100 if (FAILED(hr)) { 101 return nullptr; 102 } 103 104 HANDLE sharedHandle = nullptr; 105 texDXGI->CreateSharedHandle( 106 nullptr, DXGI_SHARED_RESOURCE_READ | DXGI_SHARED_RESOURCE_WRITE, nullptr, 107 &sharedHandle); 108 109 RefPtr<gfx::FileHandleWrapper> handle = 110 new gfx::FileHandleWrapper(UniqueFileHandle(sharedHandle)); 111 112 Maybe<layers::CompositeProcessFencesHolderId> fencesHolderId; 113 RefPtr<layers::FenceD3D11> fence; 114 RefPtr<IDXGIKeyedMutex> keyedMutex; 115 if (useFence) { 116 fence = layers::FenceD3D11::Create(device); 117 if (!fence) { 118 return nullptr; 119 } 120 fencesHolderId = Some(layers::CompositeProcessFencesHolderId::GetNext()); 121 } else { 122 texture2D->QueryInterface((IDXGIKeyedMutex**)getter_AddRefs(keyedMutex)); 123 if (!keyedMutex) { 124 return nullptr; 125 } 126 } 127 128 const auto& config = gle->mSurfaceConfig; 129 MOZ_ASSERT(config); 130 131 EGLSurface pbuffer = 132 CreatePBufferSurface(egl.get(), config, desc.size, texture2D); 133 if (!pbuffer) return nullptr; 134 135 if (useFence) { 136 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 137 fencesHolderMap->Register(fencesHolderId.ref()); 138 } 139 140 return AsUnique(new SharedSurface_ANGLEShareHandle( 141 desc, device, egl, pbuffer, std::move(handle), fencesHolderId, fence, 142 keyedMutex)); 143 } 144 145 SharedSurface_ANGLEShareHandle::SharedSurface_ANGLEShareHandle( 146 const SharedSurfaceDesc& desc, const RefPtr<ID3D11Device> aDevice, 147 const std::weak_ptr<EglDisplay>& egl, EGLSurface pbuffer, 148 RefPtr<gfx::FileHandleWrapper>&& aSharedHandle, 149 const Maybe<layers::CompositeProcessFencesHolderId> aFencesHolderId, 150 const RefPtr<layers::FenceD3D11>& aWriteFence, 151 const RefPtr<IDXGIKeyedMutex>& keyedMutex) 152 : SharedSurface(desc, nullptr), 153 mDevice(aDevice), 154 mEGL(egl), 155 mPBuffer(pbuffer), 156 mSharedHandle(std::move(aSharedHandle)), 157 mFencesHolderId(aFencesHolderId), 158 mWriteFence(std::move(aWriteFence)), 159 mKeyedMutex(keyedMutex) { 160 MOZ_ASSERT((mKeyedMutex && mFencesHolderId.isNothing()) || 161 (!mKeyedMutex && mFencesHolderId.isSome())); 162 MOZ_ASSERT_IF(mFencesHolderId.isSome(), mWriteFence); 163 } 164 165 SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() { 166 const auto& gl = mDesc.gl; 167 168 if (gl && GLContextEGL::Cast(gl)->GetEGLSurfaceOverride() == mPBuffer) { 169 GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(EGL_NO_SURFACE); 170 } 171 const auto egl = mEGL.lock(); 172 if (egl) { 173 egl->fDestroySurface(mPBuffer); 174 } 175 176 if (mFencesHolderId.isSome()) { 177 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 178 if (fencesHolderMap) { 179 fencesHolderMap->Unregister(mFencesHolderId.ref()); 180 } else { 181 gfxCriticalNoteOnce 182 << "CompositeProcessD3D11FencesHolderMap does not exist"; 183 } 184 } 185 } 186 187 void SharedSurface_ANGLEShareHandle::LockProdImpl() { 188 const auto& gl = mDesc.gl; 189 GLContextEGL::Cast(gl)->SetEGLSurfaceOverride(mPBuffer); 190 } 191 192 void SharedSurface_ANGLEShareHandle::UnlockProdImpl() {} 193 194 void SharedSurface_ANGLEShareHandle::ProducerAcquireImpl() { 195 if (mFencesHolderId.isSome()) { 196 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 197 fencesHolderMap->WaitAllFencesAndForget(mFencesHolderId.ref(), mDevice); 198 } 199 if (mKeyedMutex) { 200 HRESULT hr = mKeyedMutex->AcquireSync(0, 10000); 201 if (hr == WAIT_TIMEOUT) { 202 MOZ_CRASH("GFX: ANGLE share handle timeout"); 203 } 204 } 205 } 206 207 void SharedSurface_ANGLEShareHandle::ProducerReleaseImpl() { 208 const auto& gl = mDesc.gl; 209 // XXX: ReleaseSync() has an implicit flush of the D3D commands 210 // whether we need Flush() or not depends on the ANGLE semantics. 211 // For now, we'll just do it 212 gl->fFlush(); 213 if (mFencesHolderId.isSome()) { 214 mWriteFence->IncrementAndSignal(); 215 auto* fencesHolderMap = layers::CompositeProcessD3D11FencesHolderMap::Get(); 216 fencesHolderMap->SetWriteFence(mFencesHolderId.ref(), mWriteFence); 217 } 218 if (mKeyedMutex) { 219 mKeyedMutex->ReleaseSync(0); 220 } 221 } 222 223 void SharedSurface_ANGLEShareHandle::ProducerReadAcquireImpl() { 224 ProducerAcquireImpl(); 225 } 226 227 void SharedSurface_ANGLEShareHandle::ProducerReadReleaseImpl() { 228 if (mKeyedMutex) { 229 mKeyedMutex->ReleaseSync(0); 230 } 231 } 232 233 Maybe<layers::SurfaceDescriptor> 234 SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor() { 235 const auto format = gfx::SurfaceFormat::B8G8R8A8; 236 return Some(layers::SurfaceDescriptorD3D10( 237 mSharedHandle, /* gpuProcessTextureId */ Nothing(), 238 /* arrayIndex */ 0, format, mDesc.size, mDesc.colorSpace, 239 gfx::ColorRange::FULL, !!mKeyedMutex, mFencesHolderId)); 240 } 241 242 //////////////////////////////////////////////////////////////////////////////// 243 // Factory 244 245 /*static*/ 246 UniquePtr<SurfaceFactory_ANGLEShareHandle> 247 SurfaceFactory_ANGLEShareHandle::Create(GLContext& gl) { 248 if (!gl.IsANGLE()) return nullptr; 249 250 const auto& gle = *GLContextEGL::Cast(&gl); 251 const auto& egl = gle.mEgl; 252 253 if (!egl->IsExtensionSupported( 254 EGLExtension::ANGLE_surface_d3d_texture_2d_share_handle)) { 255 return nullptr; 256 } 257 258 if (XRE_IsContentProcess()) { 259 gfxPlatform::GetPlatform()->EnsureDevicesInitialized(); 260 } 261 262 gfx::DeviceManagerDx* dm = gfx::DeviceManagerDx::Get(); 263 MOZ_ASSERT(dm); 264 if (gl.IsWARP() != dm->IsWARP() || !dm->TextureSharingWorks()) { 265 return nullptr; 266 } 267 268 return AsUnique(new SurfaceFactory_ANGLEShareHandle( 269 {&gl, SharedSurfaceType::EGLSurfaceANGLE, layers::TextureType::D3D11, 270 true})); 271 } 272 273 } /* namespace gl */ 274 } /* namespace mozilla */