Bug 1014614 - Add GLBlitHelper::BlitImageToFramebuffer and support SurfaceTexture images r=jgilbert
💩💩 backed out by 53e24fd12cd1 💩 💩
authorJames Willcox <snorp@snorp.net>
Fri, 17 Oct 2014 10:35:13 -0500
changeset 210953 8fbc3c85adfc
parent 210952 40dbd7c6ce65
child 210954 40f99ba7f616
push id50598
push userjwillcox@mozilla.com
push date2014-10-17 15:36 +0000
treeherdermozilla-inbound@40f99ba7f616 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1014614
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1014614 - Add GLBlitHelper::BlitImageToFramebuffer and support SurfaceTexture images r=jgilbert
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLBlitHelper.h
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -5,22 +5,27 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GLBlitHelper.h"
 #include "GLContext.h"
 #include "ScopedGLHelpers.h"
 #include "mozilla/Preferences.h"
 #include "ImageContainer.h"
 #include "HeapCopyOfStackArray.h"
+#include "mozilla/gfx/Matrix.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "GrallocImages.h"
 #include "GLLibraryEGL.h"
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+#include "GLImages.h"
+#endif
+
 using mozilla::layers::PlanarYCbCrImage;
 using mozilla::layers::PlanarYCbCrData;
 
 namespace mozilla {
 namespace gl {
 
 static void
 RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
@@ -139,16 +144,17 @@ GLBlitHelper::GLBlitHelper(GLContext* gl
     : mGL(gl)
     , mTexBlit_Buffer(0)
     , mTexBlit_VertShader(0)
     , mTex2DBlit_FragShader(0)
     , mTex2DRectBlit_FragShader(0)
     , mTex2DBlit_Program(0)
     , mTex2DRectBlit_Program(0)
     , mYFlipLoc(-1)
+    , mTextureTransformLoc(-1)
     , mTexExternalBlit_FragShader(0)
     , mTexYUVPlanarBlit_FragShader(0)
     , mTexExternalBlit_Program(0)
     , mTexYUVPlanarBlit_Program(0)
     , mFBO(0)
     , mSrcTexY(0)
     , mSrcTexCb(0)
     , mSrcTexCr(0)
@@ -233,31 +239,33 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
         varying vec2 vTexCoord;                                       \n\
                                                                       \n\
         void main(void)                                               \n\
         {                                                             \n\
             gl_FragColor = texture2DRect(uTexUnit,                    \n\
                                          vTexCoord * uTexCoordMult);  \n\
         }                                                             \n\
     ";
-#ifdef MOZ_WIDGET_GONK
+#ifdef ANDROID /* MOZ_WIDGET_ANDROID || MOZ_WIDGET_GONK */
     const char kTexExternalBlit_FragShaderSource[] = "\
-        #extension GL_OES_EGL_image_external : require      \n\
-        #ifdef GL_FRAGMENT_PRECISION_HIGH                   \n\
-            precision highp float;                          \n\
-        #else                                               \n\
-            precision mediump float;                        \n\
-        #endif                                              \n\
-        varying vec2 vTexCoord;                             \n\
-        uniform samplerExternalOES uTexUnit;                \n\
-                                                            \n\
-        void main()                                         \n\
-        {                                                   \n\
-            gl_FragColor = texture2D(uTexUnit, vTexCoord);  \n\
-        }                                                   \n\
+        #extension GL_OES_EGL_image_external : require                  \n\
+        #ifdef GL_FRAGMENT_PRECISION_HIGH                               \n\
+            precision highp float;                                      \n\
+        #else                                                           \n\
+            precision mediump float;                                    \n\
+        #endif                                                          \n\
+        varying vec2 vTexCoord;                                         \n\
+        uniform mat4 uTextureTransform;                                 \n\
+        uniform samplerExternalOES uTexUnit;                            \n\
+                                                                        \n\
+        void main()                                                     \n\
+        {                                                               \n\
+            gl_FragColor = texture2D(uTexUnit,                          \n\
+                (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy);    \n\
+        }                                                               \n\
     ";
 #endif
     /* From Rec601:
     [R] [1.1643835616438356, 0.0, 1.5960267857142858] [ Y - 16]
     [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708] x [Cb - 128]
     [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [Cr - 128]
 
     For [0,1] instead of [0,255], and to 5 places:
@@ -301,17 +309,18 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
         fragShaderPtr = &mTex2DBlit_FragShader;
         fragShaderSource = kTex2DBlit_FragShaderSource;
         break;
     case BlitTexRect:
         programPtr = &mTex2DRectBlit_Program;
         fragShaderPtr = &mTex2DRectBlit_FragShader;
         fragShaderSource = kTex2DRectBlit_FragShaderSource;
         break;
-#ifdef MOZ_WIDGET_GONK
+#ifdef ANDROID
+    case ConvertSurfaceTexture:
     case ConvertGralloc:
         programPtr = &mTexExternalBlit_Program;
         fragShaderPtr = &mTexExternalBlit_FragShader;
         fragShaderSource = kTexExternalBlit_FragShaderSource;
         break;
 #endif
     case ConvertPlanarYCbCr:
         programPtr = &mTexYUVPlanarBlit_Program;
@@ -436,18 +445,19 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
             break;
         }
 
         // Cache and set attribute and uniform
         mGL->fUseProgram(program);
         switch (target) {
             case BlitTex2D:
             case BlitTexRect:
+            case ConvertSurfaceTexture:
             case ConvertGralloc: {
-#ifdef MOZ_WIDGET_GONK
+#ifdef ANDROID
                 GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
                 MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
                 mGL->fUniform1i(texUnitLoc, 0);
                 break;
 #endif
             }
             case ConvertPlanarYCbCr: {
                 GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
@@ -467,16 +477,22 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
                 mGL->fUniform1i(texCb, Channel_Cb);
                 mGL->fUniform1i(texCr, Channel_Cr);
                 break;
             }
         }
         MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0);
         mYFlipLoc = mGL->fGetUniformLocation(program, "uYflip");
         MOZ_ASSERT(mYFlipLoc != -1, "uniform: uYflip not found");
+        mTextureTransformLoc = mGL->fGetUniformLocation(program, "uTextureTransform");
+        if (mTextureTransformLoc >= 0) {
+            // Set identity matrix as default
+            gfx::Matrix4x4 identity;
+            mGL->fUniformMatrix4fv(mTextureTransformLoc, 1, false, &identity._11);
+        }
         success = true;
     } while (false);
 
     if (!success) {
         // Clean up:
         DeleteTexBlitProgram();
         return false;
     }
@@ -695,16 +711,52 @@ GLBlitHelper::BlitGrallocImage(layers::G
     mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
 
     sEGLLibrary.fDestroyImage(sEGLLibrary.Display(), image);
     mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, oldBinding);
     return true;
 }
 #endif
 
+#ifdef MOZ_WIDGET_ANDROID
+
+bool
+GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage)
+{
+    AndroidSurfaceTexture* surfaceTexture = stImage->GetData()->mSurfTex;
+    bool yFlip = stImage->GetData()->mInverted;
+
+    ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
+    mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
+
+    if (!surfaceTexture->Attach(mGL)) {
+        return false;
+    }
+
+    // UpdateTexImage() changes the EXTERNAL binding, so save it here
+    // so we can restore it after.
+    int oldBinding = 0;
+    mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &oldBinding);
+
+    surfaceTexture->UpdateTexImage();
+
+    Matrix4x4 transform;
+    surfaceTexture->GetTransformMatrix(transform);
+
+    mGL->fUniformMatrix4fv(mTextureTransformLoc, 1, false, &transform._11);
+    mGL->fUniform1f(mYFlipLoc, yFlip ? 1.0f : 0.0f);
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+
+    surfaceTexture->Detach();
+
+    mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, oldBinding);
+    return true;
+}
+#endif
+
 bool
 GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage, bool yFlip)
 {
     ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
     const PlanarYCbCrData* yuvData = yuvImage->GetData();
 
     bool needsAllocation = false;
     if (mTexWidth != yuvData->mYStride || mTexHeight != yuvData->mYSize.height) {
@@ -733,53 +785,52 @@ GLBlitHelper::BlitPlanarYCbCrImage(layer
     for (int i = 0; i < 3; i++) {
         mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
         mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
     }
     return true;
 }
 
 bool
-GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
-                                 const gfx::IntSize& destSize,
-                                 GLuint destTex,
-                                 GLenum destTarget,
-                                 bool yFlip,
-                                 GLuint xoffset,
-                                 GLuint yoffset,
-                                 GLuint cropWidth,
-                                 GLuint cropHeight)
+GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
+                                     const gfx::IntSize& destSize,
+                                     GLuint destFB,
+                                     bool yFlip,
+                                     GLuint xoffset,
+                                     GLuint yoffset,
+                                     GLuint cropWidth,
+                                     GLuint cropHeight)
 {
     ScopedGLDrawState autoStates(mGL);
 
     BlitType type;
     switch (srcImage->GetFormat()) {
     case ImageFormat::PLANAR_YCBCR:
         type = ConvertPlanarYCbCr;
         break;
     case ImageFormat::GRALLOC_PLANAR_YCBCR:
 #ifdef MOZ_WIDGET_GONK
         type = ConvertGralloc;
         break;
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+    case ImageFormat::SURFACE_TEXTURE:
+        type = ConvertSurfaceTexture;
+        break;
+#endif
     default:
         return false;
     }
 
     bool init = InitTexQuadProgram(type);
     if (!init) {
         return false;
     }
 
-    if (!mFBO) {
-        mGL->fGenFramebuffers(1, &mFBO);
-    }
-
-    ScopedBindFramebuffer boundFB(mGL, mFBO);
-    mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, destTarget, destTex, 0);
+    ScopedBindFramebuffer boundFB(mGL, destFB);
     mGL->fColorMask(LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE);
     mGL->fViewport(0, 0, destSize.width, destSize.height);
     if (xoffset != 0 && yoffset != 0 && cropWidth != 0 && cropHeight != 0) {
         mGL->fEnable(LOCAL_GL_SCISSOR_TEST);
         mGL->fScissor(xoffset, yoffset, (GLsizei)cropWidth, (GLsizei)cropHeight);
     }
 
 #ifdef MOZ_WIDGET_GONK
@@ -788,20 +839,49 @@ GLBlitHelper::BlitImageToTexture(layers:
         return BlitGrallocImage(grallocImage, yFlip);
     }
 #endif
     if (type == ConvertPlanarYCbCr) {
         mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1);
         PlanarYCbCrImage* yuvImage = static_cast<PlanarYCbCrImage*>(srcImage);
         return BlitPlanarYCbCrImage(yuvImage, yFlip);
     }
+#ifdef MOZ_WIDGET_ANDROID
+    if (type == ConvertSurfaceTexture) {
+        layers::SurfaceTextureImage* stImage = static_cast<layers::SurfaceTextureImage*>(srcImage);
+        return BlitSurfaceTextureImage(stImage);
+    }
+#endif
 
     return false;
 }
 
+bool
+GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
+                                 const gfx::IntSize& destSize,
+                                 GLuint destTex,
+                                 GLenum destTarget,
+                                 bool yFlip,
+                                 GLuint xoffset,
+                                 GLuint yoffset,
+                                 GLuint cropWidth,
+                                 GLuint cropHeight)
+{
+    ScopedGLDrawState autoStates(mGL);
+
+    if (!mFBO) {
+        mGL->fGenFramebuffers(1, &mFBO);
+    }
+
+    ScopedBindFramebuffer boundFB(mGL, mFBO);
+    mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, destTarget, destTex, 0);
+    return BlitImageToFramebuffer(srcImage, destSize, mFBO, yFlip, xoffset, yoffset,
+                                  cropWidth, cropHeight);
+}
+
 void
 GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
                                        const gfx::IntSize& srcSize,
                                        const gfx::IntSize& destSize,
                                        GLenum srcTarget,
                                        bool internalFBs)
 {
     MOZ_ASSERT(mGL->fIsTexture(srcTex));
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -14,16 +14,17 @@
 #include "mozilla/gfx/Point.h"
 
 namespace mozilla {
 
 namespace layers {
 class Image;
 class PlanarYCbCrImage;
 class GrallocImage;
+class SurfaceTextureImage;
 }
 
 namespace gl {
 
 class GLContext;
 
 /**
  * Helper function that creates a 2D texture aSize.width x aSize.height with
@@ -92,29 +93,32 @@ class GLBlitHelper MOZ_FINAL
      * Convert type is created for canvas.
      */
     enum BlitType
     {
         BlitTex2D,
         BlitTexRect,
         ConvertGralloc,
         ConvertPlanarYCbCr,
+        ConvertSurfaceTexture
     };
     // The GLContext is the sole owner of the GLBlitHelper.
     GLContext* mGL;
 
     GLuint mTexBlit_Buffer;
     GLuint mTexBlit_VertShader;
     GLuint mTex2DBlit_FragShader;
     GLuint mTex2DRectBlit_FragShader;
     GLuint mTex2DBlit_Program;
     GLuint mTex2DRectBlit_Program;
 
     GLint mYFlipLoc;
 
+    GLint mTextureTransformLoc;
+
     // Data for image blit path
     GLuint mTexExternalBlit_FragShader;
     GLuint mTexYUVPlanarBlit_FragShader;
     GLuint mTexExternalBlit_Program;
     GLuint mTexYUVPlanarBlit_Program;
     GLuint mFBO;
     GLuint mSrcTexY;
     GLuint mSrcTexCb;
@@ -137,16 +141,19 @@ class GLBlitHelper MOZ_FINAL
     void DeleteTexBlitProgram();
     void BindAndUploadYUVTexture(Channel which, uint32_t width, uint32_t height, void* data, bool allocation);
 
 #ifdef MOZ_WIDGET_GONK
     void BindAndUploadExternalTexture(EGLImage image);
     bool BlitGrallocImage(layers::GrallocImage* grallocImage, bool yFlip = false);
 #endif
     bool BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage, bool yFlip = false);
+#ifdef MOZ_WIDGET_ANDROID
+    bool BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage);
+#endif
 
 public:
 
     explicit GLBlitHelper(GLContext* gl);
     ~GLBlitHelper();
 
     // If you don't have |srcFormats| for the 2nd definition,
     // then you'll need the framebuffer_blit extensions to use
@@ -170,16 +177,19 @@ public:
                                   const gfx::IntSize& destSize,
                                   GLenum destTarget = LOCAL_GL_TEXTURE_2D,
                                   bool internalFBs = false);
     void BlitTextureToTexture(GLuint srcTex, GLuint destTex,
                               const gfx::IntSize& srcSize,
                               const gfx::IntSize& destSize,
                               GLenum srcTarget = LOCAL_GL_TEXTURE_2D,
                               GLenum destTarget = LOCAL_GL_TEXTURE_2D);
+    bool BlitImageToFramebuffer(layers::Image* srcImage, const gfx::IntSize& destSize,
+                                GLuint destFB, bool yFlip = false, GLuint xoffset = 0,
+                                GLuint yoffset = 0, GLuint width = 0, GLuint height = 0);
     bool BlitImageToTexture(layers::Image* srcImage, const gfx::IntSize& destSize,
                             GLuint destTex, GLenum destTarget, bool yFlip = false, GLuint xoffset = 0,
                             GLuint yoffset = 0, GLuint width = 0, GLuint height = 0);
 };
 
 }
 }