diff -r 000000000000 -r 6474c204b198 gfx/gl/GLSharedHandleHelpers.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gfx/gl/GLSharedHandleHelpers.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,330 @@ +/* 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 "GLContextEGL.h" +#include "GLSharedHandleHelpers.h" +#ifdef MOZ_WIDGET_ANDROID +#include "nsSurfaceTexture.h" +#endif + +namespace mozilla { +namespace gl { + +enum SharedHandleType { + SharedHandleType_Image +#ifdef MOZ_WIDGET_ANDROID + , SharedHandleType_SurfaceTexture +#endif +}; + +class SharedTextureHandleWrapper +{ +public: + SharedTextureHandleWrapper(SharedHandleType aHandleType) : mHandleType(aHandleType) + { + } + + virtual ~SharedTextureHandleWrapper() + { + } + + SharedHandleType Type() { return mHandleType; } + + SharedHandleType mHandleType; +}; + +#ifdef MOZ_WIDGET_ANDROID + +class SurfaceTextureWrapper: public SharedTextureHandleWrapper +{ +public: + SurfaceTextureWrapper(nsSurfaceTexture* aSurfaceTexture) : + SharedTextureHandleWrapper(SharedHandleType_SurfaceTexture) + , mSurfaceTexture(aSurfaceTexture) + { + } + + virtual ~SurfaceTextureWrapper() { + mSurfaceTexture = nullptr; + } + + nsSurfaceTexture* SurfaceTexture() { return mSurfaceTexture; } + + nsRefPtr mSurfaceTexture; +}; + +#endif // MOZ_WIDGET_ANDROID + +class EGLTextureWrapper : public SharedTextureHandleWrapper +{ +public: + EGLTextureWrapper() : + SharedTextureHandleWrapper(SharedHandleType_Image) + , mEGLImage(nullptr) + , mSyncObject(nullptr) + { + } + + // Args are the active GL context, and a texture in that GL + // context for which to create an EGLImage. After the EGLImage + // is created, the texture is unused by EGLTextureWrapper. + bool CreateEGLImage(GLContext *ctx, uintptr_t texture) { + MOZ_ASSERT(!mEGLImage && texture && sEGLLibrary.HasKHRImageBase()); + static const EGLint eglAttributes[] = { + LOCAL_EGL_NONE + }; + EGLContext eglContext = GLContextEGL::Cast(ctx)->GetEGLContext(); + mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D, + (EGLClientBuffer)texture, eglAttributes); + if (!mEGLImage) { +#ifdef DEBUG + printf_stderr("Could not create EGL images: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); +#endif + return false; + } + return true; + } + + virtual ~EGLTextureWrapper() { + if (mEGLImage) { + sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mEGLImage); + mEGLImage = nullptr; + } + } + + const EGLImage GetEGLImage() { + return mEGLImage; + } + + // Insert a sync point on the given context, which should be the current active + // context. + bool MakeSync(GLContext *ctx) { + MOZ_ASSERT(mSyncObject == nullptr); + + if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)) { + mSyncObject = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_FENCE, nullptr); + // We need to flush to make sure the sync object enters the command stream; + // we can't use EGL_SYNC_FLUSH_COMMANDS_BIT at wait time, because the wait + // happens on a different thread/context. + ctx->fFlush(); + } + + if (mSyncObject == EGL_NO_SYNC) { + // we failed to create one, so just do a finish + ctx->fFinish(); + } + + return true; + } + + bool WaitSync() { + if (!mSyncObject) { + // if we have no sync object, then we did a Finish() earlier + return true; + } + + // wait at most 1 second; this should really be never/rarely hit + const uint64_t ns_per_ms = 1000 * 1000; + EGLTime timeout = 1000 * ns_per_ms; + + EGLint result = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSyncObject, 0, timeout); + sEGLLibrary.fDestroySync(EGL_DISPLAY(), mSyncObject); + mSyncObject = nullptr; + + return result == LOCAL_EGL_CONDITION_SATISFIED; + } + +private: + EGLImage mEGLImage; + EGLSync mSyncObject; +}; + +static bool DoesEGLContextSupportSharingWithEGLImage(GLContext *gl) +{ + return sEGLLibrary.HasKHRImageBase() && + sEGLLibrary.HasKHRImageTexture2D() && + gl->IsExtensionSupported(GLContext::OES_EGL_image); +} + +SharedTextureHandle CreateSharedHandle(GLContext* gl, + SharedTextureShareType shareType, + void* buffer, + SharedTextureBufferType bufferType) +{ + // unimplemented outside of EGL + if (gl->GetContextType() != GLContextType::EGL) + return 0; + + // Both EGLImage and SurfaceTexture only support same-process currently, but + // it's possible to make SurfaceTexture work across processes. We should do that. + if (shareType != SharedTextureShareType::SameProcess) + return 0; + + switch (bufferType) { +#ifdef MOZ_WIDGET_ANDROID + case SharedTextureBufferType::SurfaceTexture: + if (!gl->IsExtensionSupported(GLContext::OES_EGL_image_external)) { + NS_WARNING("Missing GL_OES_EGL_image_external"); + return 0; + } + + return (SharedTextureHandle) new SurfaceTextureWrapper(reinterpret_cast(buffer)); +#endif + case SharedTextureBufferType::TextureID: { + if (!DoesEGLContextSupportSharingWithEGLImage(gl)) + return 0; + + GLuint texture = (uintptr_t)buffer; + EGLTextureWrapper* tex = new EGLTextureWrapper(); + if (!tex->CreateEGLImage(gl, texture)) { + NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); + delete tex; + return 0; + } + + return (SharedTextureHandle)tex; + } + default: + NS_ERROR("Unknown shared texture buffer type"); + return 0; + } +} + +void ReleaseSharedHandle(GLContext* gl, + SharedTextureShareType shareType, + SharedTextureHandle sharedHandle) +{ + // unimplemented outside of EGL + if (gl->GetContextType() != GLContextType::EGL) + return; + + if (shareType != SharedTextureShareType::SameProcess) { + NS_ERROR("Implementation not available for this sharing type"); + return; + } + + SharedTextureHandleWrapper* wrapper = reinterpret_cast(sharedHandle); + + switch (wrapper->Type()) { +#ifdef MOZ_WIDGET_ANDROID + case SharedHandleType_SurfaceTexture: + delete wrapper; + break; +#endif + + case SharedHandleType_Image: { + NS_ASSERTION(DoesEGLContextSupportSharingWithEGLImage(gl), "EGLImage not supported or disabled in runtime"); + + EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle; + delete wrap; + break; + } + + default: + NS_ERROR("Unknown shared handle type"); + return; + } +} + +bool GetSharedHandleDetails(GLContext* gl, + SharedTextureShareType shareType, + SharedTextureHandle sharedHandle, + SharedHandleDetails& details) +{ + // unimplemented outside of EGL + if (gl->GetContextType() != GLContextType::EGL) + return false; + + if (shareType != SharedTextureShareType::SameProcess) + return false; + + SharedTextureHandleWrapper* wrapper = reinterpret_cast(sharedHandle); + + switch (wrapper->Type()) { +#ifdef MOZ_WIDGET_ANDROID + case SharedHandleType_SurfaceTexture: { + SurfaceTextureWrapper* surfaceWrapper = reinterpret_cast(wrapper); + + details.mTarget = LOCAL_GL_TEXTURE_EXTERNAL; + details.mTextureFormat = gfx::SurfaceFormat::R8G8B8A8; + surfaceWrapper->SurfaceTexture()->GetTransformMatrix(details.mTextureTransform); + break; + } +#endif + + case SharedHandleType_Image: + details.mTarget = LOCAL_GL_TEXTURE_2D; + details.mTextureFormat = gfx::SurfaceFormat::R8G8B8A8; + break; + + default: + NS_ERROR("Unknown shared handle type"); + return false; + } + + return true; +} + +bool AttachSharedHandle(GLContext* gl, + SharedTextureShareType shareType, + SharedTextureHandle sharedHandle) +{ + // unimplemented outside of EGL + if (gl->GetContextType() != GLContextType::EGL) + return false; + + if (shareType != SharedTextureShareType::SameProcess) + return false; + + SharedTextureHandleWrapper* wrapper = reinterpret_cast(sharedHandle); + + switch (wrapper->Type()) { +#ifdef MOZ_WIDGET_ANDROID + case SharedHandleType_SurfaceTexture: { +#ifndef DEBUG + /* + * NOTE: SurfaceTexture spams us if there are any existing GL errors, so we'll clear + * them here in order to avoid that. + */ + gl->GetAndClearError(); +#endif + SurfaceTextureWrapper* surfaceTextureWrapper = reinterpret_cast(wrapper); + + // FIXME: SurfaceTexture provides a transform matrix which is supposed to + // be applied to the texture coordinates. We should return that here + // so we can render correctly. Bug 775083 + surfaceTextureWrapper->SurfaceTexture()->UpdateTexImage(); + break; + } +#endif // MOZ_WIDGET_ANDROID + + case SharedHandleType_Image: { + NS_ASSERTION(DoesEGLContextSupportSharingWithEGLImage(gl), "EGLImage not supported or disabled in runtime"); + + EGLTextureWrapper* wrap = (EGLTextureWrapper*)sharedHandle; + wrap->WaitSync(); + gl->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); + break; + } + + default: + NS_ERROR("Unknown shared handle type"); + return false; + } + + return true; +} + +/** + * Detach Shared GL Handle from GL_TEXTURE_2D target + */ +void DetachSharedHandle(GLContext*, + SharedTextureShareType, + SharedTextureHandle) +{ + // currently a no-operation +} + +} +}