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