diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 7b4aab9d8b1..63bdee58650 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -258,6 +258,7 @@ public: , mIsPBuffer(false) , mIsDoubleBuffered(false) , mCanBindToTexture(false) + , mShareWithEGLImage(false) { // any EGL contexts will always be GLESv2 SetIsGLES2(true); @@ -327,6 +328,10 @@ public: PR_STATIC_ASSERT(sizeof(GLint) >= sizeof(int32_t)); mMaxTextureImageSize = PR_INT32_MAX; + mShareWithEGLImage = sEGLLibrary.HasKHRImageBase() && + sEGLLibrary.HasKHRImageTexture2D() && + IsExtensionSupported(OES_EGL_image); + if (ok) InitFramebuffers(); @@ -584,6 +589,13 @@ public: return sEGLLibrary.HasKHRLockSurface(); } + virtual SharedTextureHandle CreateSharedHandle(TextureImage::TextureShareType aType); + virtual void UpdateSharedHandle(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle); + virtual void ReleaseSharedHandle(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle); + virtual bool AttachSharedHandle(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle); protected: friend class GLContextProviderEGL; @@ -597,6 +609,7 @@ protected: bool mIsPBuffer; bool mIsDoubleBuffered; bool mCanBindToTexture; + bool mShareWithEGLImage; static EGLSurface CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config, EGLenum bindToTextureFormat, @@ -642,6 +655,161 @@ protected: } }; +class EGLTextureWrapper +{ +public: + EGLTextureWrapper(GLContext* aContext, GLuint aTexture) + : mContext(aContext) + , mTexture(aTexture) + , mEGLImage(nsnull) + { + } + + bool CreateEGLImage() { + MOZ_ASSERT(!mEGLImage && mTexture && sEGLLibrary.HasKHRImageBase()); + static const EGLint eglAttributes[] = { + LOCAL_EGL_NONE + }; + GLContextEGL* ctx = static_cast(mContext.get()); + mEGLImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), ctx->Context(), LOCAL_EGL_GL_TEXTURE_2D, + (EGLClientBuffer)mTexture, 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 = nsnull; + } + } + + GLuint GetTextureID() { + return mTexture; + } + + GLContext* GetContext() { + return mContext.get(); + } + + const EGLImage GetEGLImage() { + return mEGLImage; + } + +private: + nsRefPtr mContext; + GLuint mTexture; + EGLImage mEGLImage; +}; + +void +GLContextEGL::UpdateSharedHandle(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle) +{ + if (aType != TextureImage::ThreadShared) { + NS_ERROR("Implementation not available for this sharing type"); + return; + } + + NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); + + EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle; + // We need to copy the current GLContext drawing buffer to the texture + // exported by the EGLImage. Need to save both the read FBO and the texture + // binding, because we're going to munge them to do this. + GLuint prevRead = GetUserBoundReadFBO(); + GLint oldtex = -1; + BindUserReadFBO(0); + fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldtex); + MOZ_ASSERT(oldtex != -1); + fBindTexture(LOCAL_GL_TEXTURE_2D, wrap->GetTextureID()); + + // CopyTexSubImage2D, is ~2x slower than simple FBO render to texture with draw quads, + // but render with draw quads require complex and hard to maintain context save/restore code + fCopyTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, 0, 0, + 0, 0, mOffscreenActualSize.width, + mOffscreenActualSize.height); + + fBindTexture(LOCAL_GL_TEXTURE_2D, oldtex); + BindUserReadFBO(prevRead); + + // Make Shared Handle fully resolved in order to + // guarantee content ready to draw in different thread GLContext + GuaranteeResolve(); +} + +SharedTextureHandle +GLContextEGL::CreateSharedHandle(TextureImage::TextureShareType aType) +{ + if (aType != TextureImage::ThreadShared) + return nsnull; + + if (!mShareWithEGLImage) + return nsnull; + + MakeCurrent(); + GLuint texture = 0; + ContextFormat fmt = ActualFormat(); + CreateTextureForOffscreen(ChooseGLFormats(fmt), mOffscreenSize, texture); + // texture ownership moved to EGLTextureWrapper after this point + // and texture will be deleted in EGLTextureWrapper dtor + EGLTextureWrapper* tex = new EGLTextureWrapper(this, texture); + if (!tex->CreateEGLImage()) { + NS_ERROR("EGLImage creation for EGLTextureWrapper failed"); + ReleaseSharedHandle(aType, (SharedTextureHandle)tex); + + // Stop trying to create shared image Handle + mShareWithEGLImage = false; + return nsnull; + } + // Raw pointer shared across threads + return (SharedTextureHandle)tex; +} + +void GLContextEGL::ReleaseSharedHandle(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle) +{ + if (aType != TextureImage::ThreadShared) { + NS_ERROR("Implementation not available for this sharing type"); + return; + } + + NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); + + EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle; + GLContext *ctx = wrap->GetContext(); + if (ctx->IsDestroyed() || !ctx->IsOwningThreadCurrent()) { + ctx = ctx->GetSharedContext(); + } + // If we have a context, then we need to delete the texture; + // if we don't have a context (either real or shared), + // then they went away when the contex was deleted, because it + // was the only one that had access to it. + if (ctx && !ctx->IsDestroyed() && ctx->MakeCurrent()) { + GLuint texture = wrap->GetTextureID(); + ctx->fDeleteTextures(1, &texture); + } + delete wrap; +} + +bool GLContextEGL::AttachSharedHandle(TextureImage::TextureShareType aType, + SharedTextureHandle aSharedHandle) +{ + if (aType != TextureImage::ThreadShared) + return false; + + NS_ASSERTION(mShareWithEGLImage, "EGLImage not supported or disabled in runtime"); + + EGLTextureWrapper* wrap = (EGLTextureWrapper*)aSharedHandle; + sEGLLibrary.fImageTargetTexture2DOES(LOCAL_GL_TEXTURE_2D, wrap->GetEGLImage()); + return true; +} + bool GLContextEGL::BindTex2DOffscreen(GLContext *aOffscreen) { diff --git a/gfx/gl/GLDefs.h b/gfx/gl/GLDefs.h index 352582bb872..e5849944e84 100644 --- a/gfx/gl/GLDefs.h +++ b/gfx/gl/GLDefs.h @@ -3253,6 +3253,9 @@ typedef void* GLeglImage; #define LOCAL_EGL_DRAW 0x3059 #define LOCAL_EGL_CONTEXT_LOST 0x300E +// EGL_KHR_gl_texture_2D_image +#define LOCAL_EGL_GL_TEXTURE_2D 0x30B1 + // EGL_KHR_fence_sync #define LOCAL_EGL_SYNC_FENCE 0x30F9 #define LOCAL_EGL_SYNC_TYPE 0x30F7