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 "SharedSurfaceEGL.h" michael@0: #include "GLContextEGL.h" michael@0: #include "GLBlitHelper.h" michael@0: #include "ScopedGLHelpers.h" michael@0: #include "SharedSurfaceGL.h" michael@0: #include "SurfaceFactory.h" michael@0: #include "GLLibraryEGL.h" michael@0: #include "TextureGarbageBin.h" michael@0: #include "GLReadTexImageHelper.h" michael@0: michael@0: using namespace mozilla::gfx; michael@0: michael@0: namespace mozilla { michael@0: namespace gl { michael@0: michael@0: SharedSurface_EGLImage* michael@0: SharedSurface_EGLImage::Create(GLContext* prodGL, michael@0: const GLFormats& formats, michael@0: const gfx::IntSize& size, michael@0: bool hasAlpha, michael@0: EGLContext context) michael@0: { michael@0: GLLibraryEGL* egl = &sEGLLibrary; michael@0: MOZ_ASSERT(egl); michael@0: MOZ_ASSERT(context); michael@0: michael@0: if (!HasExtensions(egl, prodGL)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: MOZ_ALWAYS_TRUE(prodGL->MakeCurrent()); michael@0: GLuint prodTex = CreateTextureForOffscreen(prodGL, formats, size); michael@0: if (!prodTex) { michael@0: return nullptr; michael@0: } michael@0: michael@0: EGLClientBuffer buffer = reinterpret_cast(prodTex); michael@0: EGLImage image = egl->fCreateImage(egl->Display(), context, michael@0: LOCAL_EGL_GL_TEXTURE_2D, buffer, michael@0: nullptr); michael@0: if (!image) { michael@0: prodGL->fDeleteTextures(1, &prodTex); michael@0: return nullptr; michael@0: } michael@0: michael@0: return new SharedSurface_EGLImage(prodGL, egl, michael@0: size, hasAlpha, michael@0: formats, prodTex, image); michael@0: } michael@0: michael@0: michael@0: bool michael@0: SharedSurface_EGLImage::HasExtensions(GLLibraryEGL* egl, GLContext* gl) michael@0: { michael@0: return egl->HasKHRImageBase() && michael@0: egl->IsExtensionSupported(GLLibraryEGL::KHR_gl_texture_2D_image) && michael@0: gl->IsExtensionSupported(GLContext::OES_EGL_image_external); michael@0: } michael@0: michael@0: SharedSurface_EGLImage::SharedSurface_EGLImage(GLContext* gl, michael@0: GLLibraryEGL* egl, michael@0: const gfx::IntSize& size, michael@0: bool hasAlpha, michael@0: const GLFormats& formats, michael@0: GLuint prodTex, michael@0: EGLImage image) michael@0: : SharedSurface_GL(SharedSurfaceType::EGLImageShare, michael@0: AttachmentType::GLTexture, michael@0: gl, michael@0: size, michael@0: hasAlpha) michael@0: , mMutex("SharedSurface_EGLImage mutex") michael@0: , mEGL(egl) michael@0: , mFormats(formats) michael@0: , mProdTex(prodTex) michael@0: , mImage(image) michael@0: , mCurConsGL(nullptr) michael@0: , mConsTex(0) michael@0: , mSync(0) michael@0: {} michael@0: michael@0: SharedSurface_EGLImage::~SharedSurface_EGLImage() michael@0: { michael@0: mEGL->fDestroyImage(Display(), mImage); michael@0: mImage = 0; michael@0: michael@0: mGL->MakeCurrent(); michael@0: mGL->fDeleteTextures(1, &mProdTex); michael@0: mProdTex = 0; michael@0: michael@0: if (mConsTex) { michael@0: MOZ_ASSERT(mGarbageBin); michael@0: mGarbageBin->Trash(mConsTex); michael@0: mConsTex = 0; michael@0: } michael@0: michael@0: if (mSync) { michael@0: // We can't call this unless we have the ext, but we will always have michael@0: // the ext if we have something to destroy. michael@0: mEGL->fDestroySync(Display(), mSync); michael@0: mSync = 0; michael@0: } michael@0: } michael@0: michael@0: void michael@0: SharedSurface_EGLImage::Fence() michael@0: { michael@0: MutexAutoLock lock(mMutex); michael@0: mGL->MakeCurrent(); michael@0: michael@0: if (mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) && michael@0: mGL->IsExtensionSupported(GLContext::OES_EGL_sync)) michael@0: { michael@0: if (mSync) { michael@0: MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) ); michael@0: mSync = 0; michael@0: } michael@0: michael@0: mSync = mEGL->fCreateSync(Display(), michael@0: LOCAL_EGL_SYNC_FENCE, michael@0: nullptr); michael@0: if (mSync) { michael@0: mGL->fFlush(); michael@0: return; michael@0: } michael@0: } michael@0: michael@0: MOZ_ASSERT(!mSync); michael@0: mGL->fFinish(); michael@0: } michael@0: michael@0: bool michael@0: SharedSurface_EGLImage::WaitSync() michael@0: { michael@0: MutexAutoLock lock(mMutex); michael@0: if (!mSync) { michael@0: // We must not be needed. michael@0: return true; michael@0: } michael@0: MOZ_ASSERT(mEGL->IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)); michael@0: michael@0: // Wait FOREVER, primarily because some NVIDIA (at least Tegra) drivers michael@0: // have ClientWaitSync returning immediately if the timeout delay is anything michael@0: // else than FOREVER. michael@0: // michael@0: // FIXME: should we try to use a finite timeout delay where possible? michael@0: EGLint status = mEGL->fClientWaitSync(Display(), michael@0: mSync, michael@0: 0, michael@0: LOCAL_EGL_FOREVER); michael@0: michael@0: if (status != LOCAL_EGL_CONDITION_SATISFIED) { michael@0: return false; michael@0: } michael@0: michael@0: MOZ_ALWAYS_TRUE( mEGL->fDestroySync(Display(), mSync) ); michael@0: mSync = 0; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: michael@0: EGLDisplay michael@0: SharedSurface_EGLImage::Display() const michael@0: { michael@0: return mEGL->Display(); michael@0: } michael@0: michael@0: void michael@0: SharedSurface_EGLImage::AcquireConsumerTexture(GLContext* consGL, GLuint* out_texture, GLuint* out_target) michael@0: { michael@0: MutexAutoLock lock(mMutex); michael@0: MOZ_ASSERT(!mCurConsGL || consGL == mCurConsGL); michael@0: michael@0: if (!mConsTex) { michael@0: consGL->fGenTextures(1, &mConsTex); michael@0: MOZ_ASSERT(mConsTex); michael@0: michael@0: ScopedBindTexture autoTex(consGL, mConsTex, LOCAL_GL_TEXTURE_EXTERNAL); michael@0: consGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, mImage); michael@0: michael@0: mCurConsGL = consGL; michael@0: mGarbageBin = consGL->TexGarbageBin(); michael@0: } michael@0: michael@0: MOZ_ASSERT(consGL == mCurConsGL); michael@0: *out_texture = mConsTex; michael@0: *out_target = LOCAL_GL_TEXTURE_EXTERNAL; michael@0: } michael@0: michael@0: michael@0: SurfaceFactory_EGLImage* michael@0: SurfaceFactory_EGLImage::Create(GLContext* prodGL, michael@0: const SurfaceCaps& caps) michael@0: { michael@0: EGLContext context = GLContextEGL::Cast(prodGL)->GetEGLContext(); michael@0: michael@0: GLLibraryEGL* egl = &sEGLLibrary; michael@0: if (!SharedSurface_EGLImage::HasExtensions(egl, prodGL)) { michael@0: return nullptr; michael@0: } michael@0: michael@0: return new SurfaceFactory_EGLImage(prodGL, context, caps); michael@0: } michael@0: michael@0: } /* namespace gfx */ michael@0: } /* namespace mozilla */