--- 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);
};
}
}