Bug 728524 - Render to shared EGLImage/Texture implementation. r=bgirard,vlad,jgilbert

This commit is contained in:
Oleg Romashin 2012-05-31 21:30:08 -04:00
parent ee5b6a2485
commit 5ec3a2efeb
2 changed files with 171 additions and 0 deletions

View File

@ -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<GLContextEGL*>(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<GLContext> 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)
{

View File

@ -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