Bug 1014614 - Add GLBlitHelper::BlitImageToFramebuffer and support SurfaceTexture images r=jgilbert a=lsblakk
authorJames Willcox <snorp@snorp.net>
Wed, 05 Nov 2014 10:50:04 -0600
changeset 225866 1ed1d7b0e4e3
parent 225865 147272ebeb7d
child 225867 dc39f1265c28
push id7210
push userjwillcox@mozilla.com
push date2014-11-05 16:57 +0000
treeherdermozilla-aurora@ba9a79c05e9a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, lsblakk
bugs1014614
milestone35.0a2
Bug 1014614 - Add GLBlitHelper::BlitImageToFramebuffer and support SurfaceTexture images r=jgilbert a=lsblakk
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLBlitHelper.h
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -5,22 +5,28 @@
  * 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 "AndroidSurfaceTexture.h"
+#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 +145,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 +240,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 +310,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 +446,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 +478,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 +712,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();
+
+    gfx::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 +786,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 +840,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);
 };
 
 }
 }