Bug 1097116 - Fix readback for EGLImageImage r=jgilbert
authorJames Willcox <snorp@snorp.net>
Wed, 26 Nov 2014 15:16:08 -0600
changeset 233982 bdc78805d4ca212c3421a0f3d61b001318b6b673
parent 233981 493ea6a11a879f224ba51a77ebb9b0b7b483622c
child 233983 33108356e3d42037782356618268f1bd2fb15c15
push id7326
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:58:42 +0000
treeherdermozilla-aurora@d3a3b2a0f2f8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1097116
milestone36.0a1
Bug 1097116 - Fix readback for EGLImageImage r=jgilbert
gfx/gl/GLBlitHelper.cpp
gfx/gl/GLBlitHelper.h
gfx/layers/GLImages.cpp
gfx/layers/GLImages.h
--- a/gfx/gl/GLBlitHelper.cpp
+++ b/gfx/gl/GLBlitHelper.cpp
@@ -300,16 +300,17 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
     ";
 
     bool success = false;
 
     GLuint *programPtr;
     GLuint *fragShaderPtr;
     const char* fragShaderSource;
     switch (target) {
+    case ConvertEGLImage:
     case BlitTex2D:
         programPtr = &mTex2DBlit_Program;
         fragShaderPtr = &mTex2DBlit_FragShader;
         fragShaderSource = kTex2DBlit_FragShaderSource;
         break;
     case BlitTexRect:
         programPtr = &mTex2DRectBlit_Program;
         fragShaderPtr = &mTex2DRectBlit_FragShader;
@@ -446,16 +447,17 @@ GLBlitHelper::InitTexQuadProgram(BlitTyp
             break;
         }
 
         // Cache and set attribute and uniform
         mGL->fUseProgram(program);
         switch (target) {
             case BlitTex2D:
             case BlitTexRect:
+            case ConvertEGLImage:
             case ConvertSurfaceTexture:
             case ConvertGralloc: {
 #ifdef ANDROID
                 GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
                 MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
                 mGL->fUniform1i(texUnitLoc, 0);
                 break;
 #endif
@@ -661,35 +663,36 @@ GLBlitHelper::BindAndUploadYUVTexture(Ch
                          height,
                          0,
                          LOCAL_GL_LUMINANCE,
                          LOCAL_GL_UNSIGNED_BYTE,
                          data);
     }
 }
 
-#ifdef MOZ_WIDGET_GONK
 void
-GLBlitHelper::BindAndUploadExternalTexture(EGLImage image)
+GLBlitHelper::BindAndUploadEGLImage(EGLImage image, GLuint target)
 {
     MOZ_ASSERT(image != EGL_NO_IMAGE, "Bad EGLImage");
 
     if (!mSrcTexEGL) {
         mGL->fGenTextures(1, &mSrcTexEGL);
-        mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, mSrcTexEGL);
-        mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL_OES, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
-        mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL_OES, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
-        mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL_OES, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
-        mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL_OES, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
+        mGL->fBindTexture(target, mSrcTexEGL);
+        mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+        mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+        mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
+        mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
     } else {
-        mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, mSrcTexEGL);
+        mGL->fBindTexture(target, mSrcTexEGL);
     }
-    mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL_OES, image);
+    mGL->fEGLImageTargetTexture2D(target, image);
 }
 
+#ifdef MOZ_WIDGET_GONK
+
 bool
 GLBlitHelper::BlitGrallocImage(layers::GrallocImage* grallocImage, bool yFlip)
 {
     ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
     mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
 
     EGLint attrs[] = {
         LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE,
@@ -700,38 +703,39 @@ GLBlitHelper::BlitGrallocImage(layers::G
                                               LOCAL_EGL_NATIVE_BUFFER_ANDROID,
                                               grallocImage->GetNativeBuffer(), attrs);
     if (image == EGL_NO_IMAGE)
         return false;
 
     int oldBinding = 0;
     mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL_OES, &oldBinding);
 
-    BindAndUploadExternalTexture(image);
+    BindAndUploadEGLImage(image, LOCAL_GL_TEXTURE_EXTERNAL_OES);
 
     mGL->fUniform1f(mYFlipLoc, yFlip ? (float)1.0f : (float)0.0f);
 
     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)
+GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage, bool yFlip)
 {
     AndroidSurfaceTexture* surfaceTexture = stImage->GetData()->mSurfTex;
-    bool yFlip = stImage->GetData()->mInverted;
+    if (stImage->GetData()->mInverted) {
+        yFlip = !yFlip;
+    }
 
     ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
-    mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
 
     if (NS_FAILED(surfaceTexture->Attach(mGL))) {
         return false;
     }
 
     // UpdateTexImage() changes the EXTERNAL binding, so save it here
     // so we can restore it after.
     int oldBinding = 0;
@@ -746,16 +750,49 @@ GLBlitHelper::BlitSurfaceTextureImage(la
     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;
 }
+
+bool
+GLBlitHelper::BlitEGLImageImage(layers::EGLImageImage* image, bool yFlip)
+{
+    EGLImage eglImage = image->GetData()->mImage;
+    EGLSync eglSync = image->GetData()->mSync;
+
+    if (image->GetData()->mInverted) {
+        yFlip = !yFlip;
+    }
+
+    if (eglSync) {
+        EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), eglSync, 0, LOCAL_EGL_FOREVER);
+        if (status != LOCAL_EGL_CONDITION_SATISFIED) {
+            return false;
+        }
+    }
+
+    ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
+
+    int oldBinding = 0;
+    mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldBinding);
+
+    BindAndUploadEGLImage(eglImage, LOCAL_GL_TEXTURE_2D);
+
+    mGL->fUniform1f(mYFlipLoc, yFlip ? 1.0f : 0.0f);
+
+    mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
+
+    mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, oldBinding);
+    return true;
+}
+
 #endif
 
 bool
 GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage, bool yFlip)
 {
     ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
     const PlanarYCbCrData* yuvData = yuvImage->GetData();
 
@@ -811,16 +848,19 @@ GLBlitHelper::BlitImageToFramebuffer(lay
 #ifdef MOZ_WIDGET_GONK
         type = ConvertGralloc;
         break;
 #endif
 #ifdef MOZ_WIDGET_ANDROID
     case ImageFormat::SURFACE_TEXTURE:
         type = ConvertSurfaceTexture;
         break;
+    case ImageFormat::EGLIMAGE:
+        type = ConvertEGLImage;
+        break;
 #endif
     default:
         return false;
     }
 
     bool init = InitTexQuadProgram(type);
     if (!init) {
         return false;
@@ -843,17 +883,21 @@ GLBlitHelper::BlitImageToFramebuffer(lay
     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);
+        return BlitSurfaceTextureImage(stImage, yFlip);
+    }
+    if (type == ConvertEGLImage) {
+        layers::EGLImageImage* eglImage = static_cast<layers::EGLImageImage*>(srcImage);
+        return BlitEGLImageImage(eglImage, yFlip);
     }
 #endif
 
     return false;
 }
 
 bool
 GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
--- a/gfx/gl/GLBlitHelper.h
+++ b/gfx/gl/GLBlitHelper.h
@@ -15,16 +15,17 @@
 
 namespace mozilla {
 
 namespace layers {
 class Image;
 class PlanarYCbCrImage;
 class GrallocImage;
 class SurfaceTextureImage;
+class EGLImageImage;
 }
 
 namespace gl {
 
 class GLContext;
 
 /**
  * Helper function that creates a 2D texture aSize.width x aSize.height with
@@ -93,17 +94,18 @@ class GLBlitHelper MOZ_FINAL
      * Convert type is created for canvas.
      */
     enum BlitType
     {
         BlitTex2D,
         BlitTexRect,
         ConvertGralloc,
         ConvertPlanarYCbCr,
-        ConvertSurfaceTexture
+        ConvertSurfaceTexture,
+        ConvertEGLImage
     };
     // The GLContext is the sole owner of the GLBlitHelper.
     GLContext* mGL;
 
     GLuint mTexBlit_Buffer;
     GLuint mTexBlit_VertShader;
     GLuint mTex2DBlit_FragShader;
     GLuint mTex2DRectBlit_FragShader;
@@ -135,24 +137,25 @@ class GLBlitHelper MOZ_FINAL
 
     void UseBlitProgram();
     void SetBlitFramebufferForDestTexture(GLuint aTexture);
 
     bool UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize);
     bool InitTexQuadProgram(BlitType target = BlitTex2D);
     void DeleteTexBlitProgram();
     void BindAndUploadYUVTexture(Channel which, uint32_t width, uint32_t height, void* data, bool allocation);
+    void BindAndUploadEGLImage(EGLImage image, GLuint target);
 
 #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);
+    bool BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage, bool yFlip = false);
+    bool BlitEGLImageImage(layers::EGLImageImage* eglImage, bool yFlip = false);
 #endif
 
 public:
 
     explicit GLBlitHelper(GLContext* gl);
     ~GLBlitHelper();
 
     // If you don't have |srcFormats| for the 2nd definition,
--- a/gfx/layers/GLImages.cpp
+++ b/gfx/layers/GLImages.cpp
@@ -1,18 +1,16 @@
-#ifdef MOZ_WIDGET_ANDROID
 
 #include "GLImages.h"
 #include "GLContext.h"
 #include "GLContextProvider.h"
 #include "ScopedGLHelpers.h"
 #include "GLImages.h"
 #include "GLBlitHelper.h"
 #include "GLReadTexImageHelper.h"
-#include "AndroidSurfaceTexture.h"
 #include "GLLibraryEGL.h"
 
 using namespace mozilla;
 using namespace mozilla::gl;
 
 namespace mozilla {
 namespace layers {
 
@@ -30,52 +28,52 @@ EGLImageImage::~EGLImageImage()
   }
 
   if (mData.mSync) {
     sEGLLibrary.fDestroySync(EGL_DISPLAY(), mData.mSync);
     mData.mSync = nullptr;
   }
 }
 
-TemporaryRef<gfx::SourceSurface>
-SurfaceTextureImage::GetAsSourceSurface()
+TemporaryRef<SourceSurface>
+GLImage::GetAsSourceSurface()
 {
   MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread");
 
   if (!sSnapshotContext) {
-    SurfaceCaps caps = SurfaceCaps::ForRGBA();
-    sSnapshotContext = GLContextProvider::CreateOffscreen(gfxIntSize(16, 16), caps);
+    sSnapshotContext = GLContextProvider::CreateHeadless();
 
     if (!sSnapshotContext) {
+      NS_WARNING("Failed to create snapshot GLContext");
       return nullptr;
     }
   }
 
   sSnapshotContext->MakeCurrent();
   ScopedTexture scopedTex(sSnapshotContext);
   ScopedBindTexture boundTex(sSnapshotContext, scopedTex.Texture());
+
+  gfx::IntSize size = GetSize();
   sSnapshotContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA,
-                                mData.mSize.width, mData.mSize.height, 0,
+                                size.width, size.height, 0,
                                 LOCAL_GL_RGBA,
                                 LOCAL_GL_UNSIGNED_BYTE,
                                 nullptr);
 
   ScopedFramebufferForTexture fb(sSnapshotContext, scopedTex.Texture());
 
   GLBlitHelper helper(sSnapshotContext);
 
-  helper.BlitImageToFramebuffer(this, mData.mSize, fb.FB(), false);
+  helper.BlitImageToFramebuffer(this, size, fb.FB(), false);
   ScopedBindFramebuffer bind(sSnapshotContext, fb.FB());
 
   RefPtr<gfx::DataSourceSurface> source =
-        gfx::Factory::CreateDataSourceSurface(mData.mSize, gfx::SurfaceFormat::B8G8R8A8);
+        gfx::Factory::CreateDataSourceSurface(size, gfx::SurfaceFormat::B8G8R8A8);
   if (NS_WARN_IF(!source)) {
     return nullptr;
   }
 
   ReadPixelsIntoDataSurface(sSnapshotContext, source);
   return source.forget();
 }
 
 } // layers
 } // mozilla
-
-#endif
--- a/gfx/layers/GLImages.h
+++ b/gfx/layers/GLImages.h
@@ -13,17 +13,24 @@
 #include "mozilla/gfx/Point.h"          // for IntSize
 
 namespace mozilla {
 namespace gl {
 class AndroidSurfaceTexture;
 }
 namespace layers {
 
-class EGLImageImage : public Image {
+class GLImage : public Image {
+public:
+  GLImage(ImageFormat aFormat) : Image(nullptr, aFormat){}
+
+  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
+};
+
+class EGLImageImage : public GLImage {
 public:
   struct Data {
     EGLImage mImage;
     EGLSync mSync;
     gfx::IntSize mSize;
     bool mInverted;
     bool mOwns;
 
@@ -32,48 +39,41 @@ public:
     }
   };
 
   void SetData(const Data& aData) { mData = aData; }
   const Data* GetData() { return &mData; }
 
   gfx::IntSize GetSize() { return mData.mSize; }
 
-  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE
-  {
-    return nullptr;
-  }
-
-  EGLImageImage() : Image(nullptr, ImageFormat::EGLIMAGE) {}
+  EGLImageImage() : GLImage(ImageFormat::EGLIMAGE) {}
 
 protected:
   virtual ~EGLImageImage();
 
 private:
   Data mData;
 };
 
 #ifdef MOZ_WIDGET_ANDROID
 
-class SurfaceTextureImage : public Image {
+class SurfaceTextureImage : public GLImage {
 public:
   struct Data {
     mozilla::gl::AndroidSurfaceTexture* mSurfTex;
     gfx::IntSize mSize;
     bool mInverted;
   };
 
   void SetData(const Data& aData) { mData = aData; }
   const Data* GetData() { return &mData; }
 
   gfx::IntSize GetSize() { return mData.mSize; }
 
-  virtual TemporaryRef<gfx::SourceSurface> GetAsSourceSurface() MOZ_OVERRIDE;
-
-  SurfaceTextureImage() : Image(nullptr, ImageFormat::SURFACE_TEXTURE) {}
+  SurfaceTextureImage() : GLImage(ImageFormat::SURFACE_TEXTURE) {}
 
 private:
   Data mData;
 };
 
 #endif // MOZ_WIDGET_ANDROID
 
 } // layers