michael@0: /* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40; -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "SharedSurfaceANGLE.h" michael@0: michael@0: #include "GLContextEGL.h" michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: michael@0: SurfaceFactory_ANGLEShareHandle* michael@0: SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, michael@0: ID3D10Device1* d3d, michael@0: const SurfaceCaps& caps) michael@0: { michael@0: GLLibraryEGL* egl = &sEGLLibrary; michael@0: if (!egl) michael@0: return nullptr; michael@0: michael@0: if (!egl->IsExtensionSupported( michael@0: GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)) michael@0: { michael@0: return nullptr; michael@0: } michael@0: michael@0: return new SurfaceFactory_ANGLEShareHandle(gl, egl, d3d, caps); michael@0: } michael@0: michael@0: EGLDisplay michael@0: SharedSurface_ANGLEShareHandle::Display() michael@0: { michael@0: return mEGL->Display(); michael@0: } michael@0: michael@0: michael@0: SharedSurface_ANGLEShareHandle::~SharedSurface_ANGLEShareHandle() michael@0: { michael@0: mEGL->fDestroySurface(Display(), mPBuffer); michael@0: } michael@0: michael@0: void michael@0: SharedSurface_ANGLEShareHandle::LockProdImpl() michael@0: { michael@0: GLContextEGL::Cast(mGL)->SetEGLSurfaceOverride(mPBuffer); michael@0: } michael@0: michael@0: void michael@0: SharedSurface_ANGLEShareHandle::UnlockProdImpl() michael@0: { michael@0: } michael@0: michael@0: michael@0: void michael@0: SharedSurface_ANGLEShareHandle::Fence() michael@0: { michael@0: mGL->fFinish(); michael@0: } michael@0: michael@0: bool michael@0: SharedSurface_ANGLEShareHandle::WaitSync() michael@0: { michael@0: // Since we glFinish in Fence(), we're always going to be resolved here. michael@0: return true; michael@0: } michael@0: michael@0: static void michael@0: FillPBufferAttribs_ByBits(nsTArray& aAttrs, michael@0: int redBits, int greenBits, michael@0: int blueBits, int alphaBits, michael@0: int depthBits, int stencilBits) michael@0: { michael@0: aAttrs.Clear(); michael@0: michael@0: #if defined(A1) || defined(A2) michael@0: #error The temp-macro names we want are already defined. michael@0: #endif michael@0: michael@0: #define A1(_x) do { aAttrs.AppendElement(_x); } while (0) michael@0: #define A2(_x,_y) do { A1(_x); A1(_y); } while (0) michael@0: michael@0: A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT); michael@0: A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT); michael@0: michael@0: A2(LOCAL_EGL_RED_SIZE, redBits); michael@0: A2(LOCAL_EGL_GREEN_SIZE, greenBits); michael@0: A2(LOCAL_EGL_BLUE_SIZE, blueBits); michael@0: A2(LOCAL_EGL_ALPHA_SIZE, alphaBits); michael@0: michael@0: A2(LOCAL_EGL_DEPTH_SIZE, depthBits); michael@0: A2(LOCAL_EGL_STENCIL_SIZE, stencilBits); michael@0: michael@0: A1(LOCAL_EGL_NONE); michael@0: #undef A1 michael@0: #undef A2 michael@0: } michael@0: michael@0: static void michael@0: FillPBufferAttribs_BySizes(nsTArray& attribs, michael@0: bool bpp16, bool hasAlpha, michael@0: int depthBits, int stencilBits) michael@0: { michael@0: int red = 0; michael@0: int green = 0; michael@0: int blue = 0; michael@0: int alpha = 0; michael@0: michael@0: if (bpp16) { michael@0: if (hasAlpha) { michael@0: red = green = blue = alpha = 4; michael@0: } else { michael@0: red = 5; michael@0: green = 6; michael@0: blue = 5; michael@0: } michael@0: } else { michael@0: red = green = blue = 8; michael@0: if (hasAlpha) michael@0: alpha = 8; michael@0: } michael@0: michael@0: FillPBufferAttribs_ByBits(attribs, michael@0: red, green, blue, alpha, michael@0: depthBits, stencilBits); michael@0: } michael@0: michael@0: static EGLConfig michael@0: ChooseConfig(GLContext* gl, michael@0: GLLibraryEGL* egl, michael@0: const SurfaceCaps& caps) michael@0: { michael@0: MOZ_ASSERT(egl); michael@0: MOZ_ASSERT(caps.color); michael@0: michael@0: // We might want 24-bit depth, but we're only (fairly) sure to get 16-bit. michael@0: int depthBits = caps.depth ? 16 : 0; michael@0: int stencilBits = caps.stencil ? 8 : 0; michael@0: michael@0: // Ok, now we have everything. michael@0: nsTArray attribs(32); michael@0: FillPBufferAttribs_BySizes(attribs, michael@0: caps.bpp16, caps.alpha, michael@0: depthBits, stencilBits); michael@0: michael@0: // Time to try to get this config: michael@0: EGLConfig configs[64]; michael@0: int numConfigs = sizeof(configs)/sizeof(EGLConfig); michael@0: int foundConfigs = 0; michael@0: michael@0: if (!egl->fChooseConfig(egl->Display(), michael@0: attribs.Elements(), michael@0: configs, numConfigs, michael@0: &foundConfigs) || michael@0: !foundConfigs) michael@0: { michael@0: NS_WARNING("No configs found for the requested formats."); michael@0: return EGL_NO_CONFIG; michael@0: } michael@0: michael@0: // TODO: Pick a config progamatically instead of hoping that michael@0: // the first config will be minimally matching our request. michael@0: EGLConfig config = configs[0]; michael@0: michael@0: if (gl->DebugMode()) { michael@0: egl->DumpEGLConfig(config); michael@0: } michael@0: michael@0: return config; michael@0: } michael@0: michael@0: michael@0: // Returns EGL_NO_SURFACE on error. michael@0: static EGLSurface CreatePBufferSurface(GLLibraryEGL* egl, michael@0: EGLDisplay display, michael@0: EGLConfig config, michael@0: const gfx::IntSize& size) michael@0: { michael@0: EGLint attribs[] = { michael@0: LOCAL_EGL_WIDTH, size.width, michael@0: LOCAL_EGL_HEIGHT, size.height, michael@0: LOCAL_EGL_NONE michael@0: }; michael@0: michael@0: EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs); michael@0: michael@0: return surface; michael@0: } michael@0: michael@0: SharedSurface_ANGLEShareHandle* michael@0: SharedSurface_ANGLEShareHandle::Create(GLContext* gl, ID3D10Device1* d3d, michael@0: EGLContext context, EGLConfig config, michael@0: const gfx::IntSize& size, bool hasAlpha) michael@0: { michael@0: GLLibraryEGL* egl = &sEGLLibrary; michael@0: MOZ_ASSERT(egl); michael@0: MOZ_ASSERT(egl->IsExtensionSupported( michael@0: GLLibraryEGL::ANGLE_surface_d3d_texture_2d_share_handle)); michael@0: michael@0: if (!context || !config) michael@0: return nullptr; michael@0: michael@0: EGLDisplay display = egl->Display(); michael@0: EGLSurface pbuffer = CreatePBufferSurface(egl, display, config, size); michael@0: if (!pbuffer) michael@0: return nullptr; michael@0: michael@0: michael@0: // Declare everything before 'goto's. michael@0: HANDLE shareHandle = nullptr; michael@0: nsRefPtr texture; michael@0: nsRefPtr srv; michael@0: michael@0: // On failure, goto CleanUpIfFailed. michael@0: // If |failed|, CleanUpIfFailed will clean up and return null. michael@0: bool failed = true; michael@0: HRESULT hr; michael@0: michael@0: // Off to the races! michael@0: if (!egl->fQuerySurfacePointerANGLE( michael@0: display, michael@0: pbuffer, michael@0: LOCAL_EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE, michael@0: &shareHandle)) michael@0: { michael@0: NS_ERROR("Failed to grab ShareHandle for PBuffer!"); michael@0: goto CleanUpIfFailed; michael@0: } michael@0: michael@0: // Ok, we have a valid PBuffer with ShareHandle. michael@0: // Let's attach it to D3D. michael@0: hr = d3d->OpenSharedResource(shareHandle, michael@0: __uuidof(ID3D10Texture2D), michael@0: getter_AddRefs(texture)); michael@0: if (FAILED(hr)) { michael@0: NS_ERROR("Failed to open shared resource!"); michael@0: goto CleanUpIfFailed; michael@0: } michael@0: michael@0: hr = d3d->CreateShaderResourceView(texture, nullptr, getter_AddRefs(srv)); michael@0: if (FAILED(hr)) { michael@0: NS_ERROR("Failed to create SRV!"); michael@0: goto CleanUpIfFailed; michael@0: } michael@0: michael@0: failed = false; michael@0: michael@0: CleanUpIfFailed: michael@0: if (failed) { michael@0: NS_WARNING("CleanUpIfFailed"); michael@0: egl->fDestroySurface(egl->Display(), pbuffer); michael@0: return nullptr; michael@0: } michael@0: michael@0: return new SharedSurface_ANGLEShareHandle(gl, egl, michael@0: size, hasAlpha, michael@0: context, pbuffer, michael@0: texture, srv); michael@0: } michael@0: michael@0: michael@0: SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl, michael@0: GLLibraryEGL* egl, michael@0: ID3D10Device1* d3d, michael@0: const SurfaceCaps& caps) michael@0: : SurfaceFactory_GL(gl, SharedSurfaceType::EGLSurfaceANGLE, caps) michael@0: , mProdGL(gl) michael@0: , mEGL(egl) michael@0: , mConsD3D(d3d) michael@0: { michael@0: mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps); michael@0: mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext(); michael@0: MOZ_ASSERT(mConfig && mContext); michael@0: } michael@0: michael@0: } /* namespace gl */ michael@0: } /* namespace mozilla */