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