diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index 31b9e64a892c..4f12477d35e8 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -1037,8 +1037,16 @@ public: } BeforeGLReadCall(); - raw_fCopyTexImage2D(target, level, internalformat, - x, y, width, height, border); + bool didCopyTexImage2D = false; + if (mScreen) { + didCopyTexImage2D = mScreen->CopyTexImage2D(target, level, internalformat, x, + y, width, height, border); + } + + if (!didCopyTexImage2D) { + raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height, + border); + } AfterGLReadCall(); } @@ -1932,6 +1940,9 @@ public: } private: + + friend class SharedSurface_IOSurface; + void raw_fCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) { BEFORE_GL_CALL; diff --git a/gfx/gl/GLScreenBuffer.cpp b/gfx/gl/GLScreenBuffer.cpp index 51145adc51d8..9abdd76052fb 100755 --- a/gfx/gl/GLScreenBuffer.cpp +++ b/gfx/gl/GLScreenBuffer.cpp @@ -313,6 +313,23 @@ GLScreenBuffer::BeforeReadCall() AssureBlitted(); } +bool +GLScreenBuffer::CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, + GLint y, GLsizei width, GLsizei height, GLint border) +{ + SharedSurface* surf; + if (GetReadFB() == 0) { + surf = SharedSurf(); + } else { + surf = mGL->mFBOMapping[GetReadFB()]; + } + if (surf) { + return surf->CopyTexImage2D(target, level, internalformat, x, y, width, height, border); + } + + return false; +} + bool GLScreenBuffer::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, diff --git a/gfx/gl/GLScreenBuffer.h b/gfx/gl/GLScreenBuffer.h index 89c6eae2c37f..965f068455a6 100644 --- a/gfx/gl/GLScreenBuffer.h +++ b/gfx/gl/GLScreenBuffer.h @@ -228,6 +228,9 @@ public: void AfterDrawCall(); void BeforeReadCall(); + bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, + GLint y, GLsizei width, GLsizei height, GLint border); + void SetReadBuffer(GLenum userMode); /** diff --git a/gfx/gl/SharedSurface.h b/gfx/gl/SharedSurface.h index 0f011c8030d0..094f61b5af1a 100644 --- a/gfx/gl/SharedSurface.h +++ b/gfx/gl/SharedSurface.h @@ -156,6 +156,12 @@ public: MOZ_CRASH("Did you forget to override this function?"); } + virtual bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, + GLint y, GLsizei width, GLsizei height, GLint border) + { + return false; + } + virtual bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, diff --git a/gfx/gl/SharedSurfaceIO.cpp b/gfx/gl/SharedSurfaceIO.cpp index de4de735c5da..d9ec0acc6995 100644 --- a/gfx/gl/SharedSurfaceIO.cpp +++ b/gfx/gl/SharedSurfaceIO.cpp @@ -35,6 +35,49 @@ SharedSurface_IOSurface::Fence() mGL->fFlush(); } +bool +SharedSurface_IOSurface::CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) +{ + /* Bug 896693 - OpenGL framebuffers that are backed by IOSurface on OSX expose a bug + * in glCopyTexImage2D --- internalformats GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA + * return the wrong results. To work around, copy framebuffer to a temporary texture + * using GL_RGBA (which works), attach as read framebuffer and glCopyTexImage2D + * instead. + */ + + // https://www.opengl.org/sdk/docs/man3/xhtml/glCopyTexImage2D.xml says that width or + // height set to 0 results in a NULL texture. Lets not do any work and punt to + // original glCopyTexImage2D, since the FBO below will fail when trying to attach a + // texture of 0 width or height. + if (width == 0 || height == 0) + return false; + + MOZ_ASSERT(mGL->IsCurrent()); + + ScopedTexture destTex(mGL); + { + ScopedBindTexture bindTex(mGL, destTex.Texture()); + mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, + LOCAL_GL_NEAREST); + mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, + LOCAL_GL_NEAREST); + mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, + LOCAL_GL_CLAMP_TO_EDGE); + mGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, + LOCAL_GL_CLAMP_TO_EDGE); + mGL->raw_fCopyTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, x, y, width, + height, 0); + } + + ScopedFramebufferForTexture tmpFB(mGL, destTex.Texture(), LOCAL_GL_TEXTURE_2D); + ScopedBindFramebuffer bindFB(mGL, tmpFB.FB()); + mGL->raw_fCopyTexImage2D(target, level, internalformat, x, y, width, height, border); + + return true; +} + bool SharedSurface_IOSurface::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels) diff --git a/gfx/gl/SharedSurfaceIO.h b/gfx/gl/SharedSurfaceIO.h index 1ce485cbe52e..d1a3724ebd81 100644 --- a/gfx/gl/SharedSurfaceIO.h +++ b/gfx/gl/SharedSurfaceIO.h @@ -30,6 +30,9 @@ public: virtual bool WaitSync() override { return true; } virtual bool PollSync() override { return true; } + virtual bool CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint border) override; virtual bool ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels) override;