bool EGLImageTextureHost::Lock() { if (!mCompositor) { return false; } EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER); if (status != LOCAL_EGL_CONDITION_SATISFIED) { return false; } if (!mTextureSource) { gfx::SurfaceFormat format = gfx::SurfaceFormat::R8G8B8A8; GLenum target = LOCAL_GL_TEXTURE_2D; GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; mTextureSource = new EGLImageTextureSource(mCompositor, mImage, format, target, wrapMode, mSize); } return true; }
bool EGLImageTextureHost::Lock() { if (!mCompositor) { return false; } EGLint status = LOCAL_EGL_CONDITION_SATISFIED; if (mSync) { MOZ_ASSERT(sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)); status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER); } if (status != LOCAL_EGL_CONDITION_SATISFIED) { MOZ_ASSERT(status != 0, "ClientWaitSync generated an error. Has mSync already been destroyed?"); return false; } if (!mTextureSource) { gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::R8G8B8X8; GLenum target = LOCAL_GL_TEXTURE_EXTERNAL; GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; mTextureSource = new EGLImageTextureSource(mCompositor, mImage, format, target, wrapMode, mSize); } return true; }
EGLImageImage::~EGLImageImage() { if (!mOwns) { return; } if (mImage) { sEGLLibrary.fDestroyImage(EGL_DISPLAY(), mImage); mImage = nullptr; } if (mSync) { sEGLLibrary.fDestroySync(EGL_DISPLAY(), mSync); mSync = nullptr; } }
EGLImage CopySurface(layers::Image* img) { mGLContext->MakeCurrent(); GLuint tex = CreateTextureForOffscreen(mGLContext, mGLContext->GetGLFormats(), img->GetSize()); auto helper = mGLContext->BlitHelper(); const gl::OriginPos destOrigin = gl::OriginPos::TopLeft; if (!helper->BlitImageToTexture(img, img->GetSize(), tex, LOCAL_GL_TEXTURE_2D, destOrigin)) { mGLContext->fDeleteTextures(1, &tex); return nullptr; } EGLint attribs[] = { LOCAL_EGL_IMAGE_PRESERVED_KHR, LOCAL_EGL_TRUE, LOCAL_EGL_NONE, LOCAL_EGL_NONE }; EGLContext eglContext = static_cast<GLContextEGL*>(mGLContext.get())->GetEGLContext(); EGLImage eglImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D_KHR, (EGLClientBuffer)tex, attribs); mGLContext->fDeleteTextures(1, &tex); return eglImage; }
void TextureImageEGL::DestroyEGLSurface(void) { if (!mSurface) return; sEGLLibrary.fDestroySurface(EGL_DISPLAY(), mSurface); mSurface = nullptr; }
void TextureHostOGL::WaitAcquireFenceSyncComplete() { if (!mAcquireFence.get() || !mAcquireFence->isValid()) { return; } int fenceFd = mAcquireFence->dup(); if (fenceFd == -1) { NS_WARNING("failed to dup fence fd"); return; } EGLint attribs[] = { LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, LOCAL_EGL_NONE }; EGLSync sync = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (!sync) { NS_WARNING("failed to create native fence sync"); return; } // Wait sync complete with timeout. // If a source of the fence becomes invalid because of error, // fene complete is not signaled. See Bug 1061435. EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), sync, 0, 400000000 /*400 usec*/); if (status != LOCAL_EGL_CONDITION_SATISFIED) { NS_ERROR("failed to wait native fence sync"); } MOZ_ALWAYS_TRUE( sEGLLibrary.fDestroySync(EGL_DISPLAY(), sync) ); mAcquireFence = nullptr; }
EGLImage CreateEGLImage(GLContext* gl, GLuint tex) { MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl)); EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex); EGLContext eglContext = GLContextEGL::Cast(gl)->mContext; EGLImage image = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext, LOCAL_EGL_GL_TEXTURE_2D, clientBuffer, nullptr); return image; }
void TextureHostOGL::WaitAcquireFenceSyncComplete() { if (!mAcquireFence.get() || !mAcquireFence->isValid()) { return; } int fenceFd = mAcquireFence->dup(); if (fenceFd == -1) { NS_WARNING("failed to dup fence fd"); return; } EGLint attribs[] = { LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, LOCAL_EGL_NONE }; EGLSync sync = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); if (!sync) { NS_WARNING("failed to create native fence sync"); return; } EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), sync, 0, LOCAL_EGL_FOREVER); if (status != LOCAL_EGL_CONDITION_SATISFIED) { NS_WARNING("failed to wait native fence sync"); } MOZ_ALWAYS_TRUE( sEGLLibrary.fDestroySync(EGL_DISPLAY(), sync) ); mAcquireFence = nullptr; }
bool TextureImageEGL::ReleaseTexImage() { if (!mBound) return true; EGLBoolean success = sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(), (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER); if (success == LOCAL_EGL_FALSE) return false; mBound = false; return true; }
/*static*/ EGLImageWrapper* EGLImageWrapper::Create(GLContext* gl, GLuint tex) { MOZ_ASSERT(DoesEGLContextSupportSharingWithEGLImage(gl)); GLLibraryEGL& library = sEGLLibrary; EGLDisplay display = EGL_DISPLAY(); EGLContext eglContext = GLContextEGL::Cast(gl)->mContext; EGLClientBuffer clientBuffer = (EGLClientBuffer)((uint64_t)tex); EGLImage image = library.fCreateImage(display, eglContext, LOCAL_EGL_GL_TEXTURE_2D, clientBuffer, nullptr); if (!image) { #ifdef DEBUG printf_stderr("Could not create EGL images: ERROR (0x%04x)\n", sEGLLibrary.fGetError()); #endif return nullptr; } return new EGLImageWrapper(library, display, image); }
bool EGLImageTextureHost::Lock() { GLContext* gl = this->gl(); if (!gl || !gl->MakeCurrent()) { return false; } EGLint status = LOCAL_EGL_CONDITION_SATISFIED; if (mSync) { MOZ_ASSERT(sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync)); status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), mSync, 0, LOCAL_EGL_FOREVER); } if (status != LOCAL_EGL_CONDITION_SATISFIED) { MOZ_ASSERT(status != 0, "ClientWaitSync generated an error. Has mSync already been destroyed?"); return false; } if (!mTextureSource) { gfx::SurfaceFormat format = mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::R8G8B8X8; GLenum target = gl->GetPreferredEGLImageTextureTarget(); GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE; mTextureSource = new EGLImageTextureSource(mProvider, mImage, format, target, wrapMode, mSize); } return true; }
virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat, const media::TimeUnit& aDuration) override { if (!EnsureGLContext()) { return NS_ERROR_FAILURE; } nsRefPtr<layers::Image> img = mImageContainer->CreateImage(ImageFormat::SURFACE_TEXTURE); layers::SurfaceTextureImage::Data data; data.mSurfTex = mSurfaceTexture.get(); data.mSize = mConfig.mDisplay; data.mOriginPos = gl::OriginPos::BottomLeft; layers::SurfaceTextureImage* stImg = static_cast<layers::SurfaceTextureImage*>(img.get()); stImg->SetData(data); if (WantCopy()) { EGLImage eglImage = CopySurface(img); if (!eglImage) { return NS_ERROR_FAILURE; } EGLSync eglSync = nullptr; if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_fence_sync) && mGLContext->IsExtensionSupported(GLContext::OES_EGL_sync)) { MOZ_ASSERT(mGLContext->IsCurrent()); eglSync = sEGLLibrary.fCreateSync(EGL_DISPLAY(), LOCAL_EGL_SYNC_FENCE, nullptr); MOZ_ASSERT(eglSync); mGLContext->fFlush(); } else { NS_WARNING("No EGL fence support detected, rendering artifacts may occur!"); } img = mImageContainer->CreateImage(ImageFormat::EGLIMAGE); layers::EGLImageImage::Data data; data.mImage = eglImage; data.mSync = eglSync; data.mOwns = true; data.mSize = mConfig.mDisplay; data.mOriginPos = gl::OriginPos::TopLeft; layers::EGLImageImage* typedImg = static_cast<layers::EGLImageImage*>(img.get()); typedImg->SetData(data); } nsresult rv; int32_t flags; NS_ENSURE_SUCCESS(rv = aInfo->Flags(&flags), rv); bool isSync = !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME); int32_t offset; NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv); int64_t presentationTimeUs; NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv); nsRefPtr<VideoData> v = VideoData::CreateFromImage(mConfig, mImageContainer, offset, presentationTimeUs, aDuration.ToMicroseconds(), img, isSync, presentationTimeUs, gfx::IntRect(0, 0, mConfig.mDisplay.width, mConfig.mDisplay.height)); ENVOKE_CALLBACK(Output, v); return NS_OK; }