1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "GLBlitHelper.h"
9 #include "ScopedGLHelpers.h"
10 #include "mozilla/Preferences.h"
11 #include "ImageContainer.h"
12 #include "HeapCopyOfStackArray.h"
13 #include "mozilla/gfx/Matrix.h"
15 #ifdef MOZ_WIDGET_GONK
16 #include "GrallocImages.h"
17 #include "GLLibraryEGL.h"
20 #ifdef MOZ_WIDGET_ANDROID
21 #include "AndroidSurfaceTexture.h"
25 using mozilla::layers::PlanarYCbCrImage
;
26 using mozilla::layers::PlanarYCbCrData
;
32 RenderbufferStorageBySamples(GLContext
* aGL
, GLsizei aSamples
,
33 GLenum aInternalFormat
, const gfx::IntSize
& aSize
)
36 aGL
->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER
,
39 aSize
.width
, aSize
.height
);
41 aGL
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
,
43 aSize
.width
, aSize
.height
);
48 CreateTexture(GLContext
* aGL
, GLenum aInternalFormat
, GLenum aFormat
,
49 GLenum aType
, const gfx::IntSize
& aSize
, bool linear
)
52 aGL
->fGenTextures(1, &tex
);
53 ScopedBindTexture
autoTex(aGL
, tex
);
55 aGL
->fTexParameteri(LOCAL_GL_TEXTURE_2D
,
56 LOCAL_GL_TEXTURE_MIN_FILTER
, linear
? LOCAL_GL_LINEAR
58 aGL
->fTexParameteri(LOCAL_GL_TEXTURE_2D
,
59 LOCAL_GL_TEXTURE_MAG_FILTER
, linear
? LOCAL_GL_LINEAR
61 aGL
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_S
,
62 LOCAL_GL_CLAMP_TO_EDGE
);
63 aGL
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_T
,
64 LOCAL_GL_CLAMP_TO_EDGE
);
66 aGL
->fTexImage2D(LOCAL_GL_TEXTURE_2D
,
69 aSize
.width
, aSize
.height
,
79 CreateTextureForOffscreen(GLContext
* aGL
, const GLFormats
& aFormats
,
80 const gfx::IntSize
& aSize
)
82 MOZ_ASSERT(aFormats
.color_texInternalFormat
);
83 MOZ_ASSERT(aFormats
.color_texFormat
);
84 MOZ_ASSERT(aFormats
.color_texType
);
86 return CreateTexture(aGL
,
87 aFormats
.color_texInternalFormat
,
88 aFormats
.color_texFormat
,
89 aFormats
.color_texType
,
95 CreateRenderbuffer(GLContext
* aGL
, GLenum aFormat
, GLsizei aSamples
,
96 const gfx::IntSize
& aSize
)
99 aGL
->fGenRenderbuffers(1, &rb
);
100 ScopedBindRenderbuffer
autoRB(aGL
, rb
);
102 RenderbufferStorageBySamples(aGL
, aSamples
, aFormat
, aSize
);
109 CreateRenderbuffersForOffscreen(GLContext
* aGL
, const GLFormats
& aFormats
,
110 const gfx::IntSize
& aSize
, bool aMultisample
,
111 GLuint
* aColorMSRB
, GLuint
* aDepthRB
,
114 GLsizei samples
= aMultisample
? aFormats
.samples
: 0;
116 MOZ_ASSERT(aFormats
.samples
> 0);
117 MOZ_ASSERT(aFormats
.color_rbFormat
);
119 *aColorMSRB
= CreateRenderbuffer(aGL
, aFormats
.color_rbFormat
, samples
, aSize
);
124 aFormats
.depthStencil
)
126 *aDepthRB
= CreateRenderbuffer(aGL
, aFormats
.depthStencil
, samples
, aSize
);
127 *aStencilRB
= *aDepthRB
;
130 MOZ_ASSERT(aFormats
.depth
);
132 *aDepthRB
= CreateRenderbuffer(aGL
, aFormats
.depth
, samples
, aSize
);
136 MOZ_ASSERT(aFormats
.stencil
);
138 *aStencilRB
= CreateRenderbuffer(aGL
, aFormats
.stencil
, samples
, aSize
);
144 GLBlitHelper::GLBlitHelper(GLContext
* gl
)
147 , mTexBlit_VertShader(0)
148 , mTex2DBlit_FragShader(0)
149 , mTex2DRectBlit_FragShader(0)
150 , mTex2DBlit_Program(0)
151 , mTex2DRectBlit_Program(0)
153 , mTextureTransformLoc(-1)
154 , mTexExternalBlit_FragShader(0)
155 , mTexYUVPlanarBlit_FragShader(0)
156 , mTexExternalBlit_Program(0)
157 , mTexYUVPlanarBlit_Program(0)
164 , mCbCrTexScaleLoc(-1)
168 , mCurCbCrScale(1.0f
)
172 GLBlitHelper::~GLBlitHelper()
174 DeleteTexBlitProgram();
183 mSrcTexY
= mSrcTexCb
= mSrcTexCr
= mSrcTexEGL
= 0;
184 mGL
->fDeleteTextures(ArrayLength(tex
), tex
);
187 mGL
->fDeleteFramebuffers(1, &mFBO
);
192 // Allowed to be destructive of state we restore in functions below.
194 GLBlitHelper::InitTexQuadProgram(BlitType target
)
196 const char kTexBlit_VertShaderSource
[] = "\
198 precision mediump float; \n\
200 attribute vec2 aPosition; \n\
202 uniform float uYflip; \n\
203 varying vec2 vTexCoord; \n\
207 vTexCoord = aPosition; \n\
208 vTexCoord.y = abs(vTexCoord.y - uYflip); \n\
209 vec2 vertPos = aPosition * 2.0 - 1.0; \n\
210 gl_Position = vec4(vertPos, 0.0, 1.0); \n\
214 const char kTex2DBlit_FragShaderSource
[] = "\
215 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
216 precision highp float; \n\
218 prevision mediump float; \n\
220 uniform sampler2D uTexUnit; \n\
222 varying vec2 vTexCoord; \n\
226 gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\
230 const char kTex2DRectBlit_FragShaderSource
[] = "\
231 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
232 precision highp float; \n\
234 precision mediump float; \n\
237 uniform sampler2D uTexUnit; \n\
238 uniform vec2 uTexCoordMult; \n\
240 varying vec2 vTexCoord; \n\
244 gl_FragColor = texture2DRect(uTexUnit, \n\
245 vTexCoord * uTexCoordMult); \n\
248 #ifdef ANDROID /* MOZ_WIDGET_ANDROID || MOZ_WIDGET_GONK */
249 const char kTexExternalBlit_FragShaderSource
[] = "\
250 #extension GL_OES_EGL_image_external : require \n\
251 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
252 precision highp float; \n\
254 precision mediump float; \n\
256 varying vec2 vTexCoord; \n\
257 uniform mat4 uTextureTransform; \n\
258 uniform samplerExternalOES uTexUnit; \n\
262 gl_FragColor = texture2D(uTexUnit, \n\
263 (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy); \n\
268 [R] [1.1643835616438356, 0.0, 1.5960267857142858] [ Y - 16]
269 [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708] x [Cb - 128]
270 [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [Cr - 128]
272 For [0,1] instead of [0,255], and to 5 places:
273 [R] [1.16438, 0.00000, 1.59603] [ Y - 0.06275]
274 [G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
275 [B] [1.16438, 2.01723, 0.00000] [Cr - 0.50196]
277 const char kTexYUVPlanarBlit_FragShaderSource
[] = "\
279 precision mediump float \n\
281 varying vec2 vTexCoord; \n\
282 uniform sampler2D uYTexture; \n\
283 uniform sampler2D uCbTexture; \n\
284 uniform sampler2D uCrTexture; \n\
285 uniform vec2 uYTexScale; \n\
286 uniform vec2 uCbCrTexScale; \n\
289 float y = texture2D(uYTexture, vTexCoord * uYTexScale).r; \n\
290 float cb = texture2D(uCbTexture, vTexCoord * uCbCrTexScale).r; \n\
291 float cr = texture2D(uCrTexture, vTexCoord * uCbCrTexScale).r; \n\
292 y = (y - 0.06275) * 1.16438; \n\
293 cb = cb - 0.50196; \n\
294 cr = cr - 0.50196; \n\
295 gl_FragColor.r = y + cr * 1.59603; \n\
296 gl_FragColor.g = y - 0.81297 * cr - 0.39176 * cb; \n\
297 gl_FragColor.b = y + cb * 2.01723; \n\
298 gl_FragColor.a = 1.0; \n\
302 bool success
= false;
305 GLuint
*fragShaderPtr
;
306 const char* fragShaderSource
;
309 programPtr
= &mTex2DBlit_Program
;
310 fragShaderPtr
= &mTex2DBlit_FragShader
;
311 fragShaderSource
= kTex2DBlit_FragShaderSource
;
314 programPtr
= &mTex2DRectBlit_Program
;
315 fragShaderPtr
= &mTex2DRectBlit_FragShader
;
316 fragShaderSource
= kTex2DRectBlit_FragShaderSource
;
319 case ConvertSurfaceTexture
:
321 programPtr
= &mTexExternalBlit_Program
;
322 fragShaderPtr
= &mTexExternalBlit_FragShader
;
323 fragShaderSource
= kTexExternalBlit_FragShaderSource
;
326 case ConvertPlanarYCbCr
:
327 programPtr
= &mTexYUVPlanarBlit_Program
;
328 fragShaderPtr
= &mTexYUVPlanarBlit_FragShader
;
329 fragShaderSource
= kTexYUVPlanarBlit_FragShaderSource
;
335 GLuint
& program
= *programPtr
;
336 GLuint
& fragShader
= *fragShaderPtr
;
338 // Use do-while(false) to let us break on failure
341 // Already have it...
346 if (!mTexBlit_Buffer
) {
359 HeapCopyOfStackArray
<GLfloat
> vertsOnHeap(verts
);
361 MOZ_ASSERT(!mTexBlit_Buffer
);
362 mGL
->fGenBuffers(1, &mTexBlit_Buffer
);
363 mGL
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mTexBlit_Buffer
);
365 // Make sure we have a sane size.
366 mGL
->fBufferData(LOCAL_GL_ARRAY_BUFFER
, vertsOnHeap
.ByteLength(), vertsOnHeap
.Data(), LOCAL_GL_STATIC_DRAW
);
369 if (!mTexBlit_VertShader
) {
371 const char* vertShaderSource
= kTexBlit_VertShaderSource
;
373 mTexBlit_VertShader
= mGL
->fCreateShader(LOCAL_GL_VERTEX_SHADER
);
374 mGL
->fShaderSource(mTexBlit_VertShader
, 1, &vertShaderSource
, nullptr);
375 mGL
->fCompileShader(mTexBlit_VertShader
);
378 MOZ_ASSERT(!fragShader
);
379 fragShader
= mGL
->fCreateShader(LOCAL_GL_FRAGMENT_SHADER
);
380 mGL
->fShaderSource(fragShader
, 1, &fragShaderSource
, nullptr);
381 mGL
->fCompileShader(fragShader
);
383 program
= mGL
->fCreateProgram();
384 mGL
->fAttachShader(program
, mTexBlit_VertShader
);
385 mGL
->fAttachShader(program
, fragShader
);
386 mGL
->fBindAttribLocation(program
, 0, "aPosition");
387 mGL
->fLinkProgram(program
);
389 if (mGL
->DebugMode()) {
391 mGL
->fGetShaderiv(mTexBlit_VertShader
, LOCAL_GL_COMPILE_STATUS
, &status
);
392 if (status
!= LOCAL_GL_TRUE
) {
393 NS_ERROR("Vert shader compilation failed.");
396 mGL
->fGetShaderiv(mTexBlit_VertShader
, LOCAL_GL_INFO_LOG_LENGTH
, &length
);
398 printf_stderr("No shader info log available.\n");
402 nsAutoArrayPtr
<char> buffer(new char[length
]);
403 mGL
->fGetShaderInfoLog(mTexBlit_VertShader
, length
, nullptr, buffer
);
405 printf_stderr("Shader info log (%d bytes): %s\n", length
, buffer
.get());
410 mGL
->fGetShaderiv(fragShader
, LOCAL_GL_COMPILE_STATUS
, &status
);
411 if (status
!= LOCAL_GL_TRUE
) {
412 NS_ERROR("Frag shader compilation failed.");
415 mGL
->fGetShaderiv(fragShader
, LOCAL_GL_INFO_LOG_LENGTH
, &length
);
417 printf_stderr("No shader info log available.\n");
421 nsAutoArrayPtr
<char> buffer(new char[length
]);
422 mGL
->fGetShaderInfoLog(fragShader
, length
, nullptr, buffer
);
424 printf_stderr("Shader info log (%d bytes): %s\n", length
, buffer
.get());
430 mGL
->fGetProgramiv(program
, LOCAL_GL_LINK_STATUS
, &status
);
431 if (status
!= LOCAL_GL_TRUE
) {
432 if (mGL
->DebugMode()) {
433 NS_ERROR("Linking blit program failed.");
435 mGL
->fGetProgramiv(program
, LOCAL_GL_INFO_LOG_LENGTH
, &length
);
437 printf_stderr("No program info log available.\n");
441 nsAutoArrayPtr
<char> buffer(new char[length
]);
442 mGL
->fGetProgramInfoLog(program
, length
, nullptr, buffer
);
444 printf_stderr("Program info log (%d bytes): %s\n", length
, buffer
.get());
449 // Cache and set attribute and uniform
450 mGL
->fUseProgram(program
);
454 case ConvertSurfaceTexture
:
455 case ConvertGralloc
: {
457 GLint texUnitLoc
= mGL
->fGetUniformLocation(program
, "uTexUnit");
458 MOZ_ASSERT(texUnitLoc
!= -1, "uniform uTexUnit not found");
459 mGL
->fUniform1i(texUnitLoc
, 0);
463 case ConvertPlanarYCbCr
: {
464 GLint texY
= mGL
->fGetUniformLocation(program
, "uYTexture");
465 GLint texCb
= mGL
->fGetUniformLocation(program
, "uCbTexture");
466 GLint texCr
= mGL
->fGetUniformLocation(program
, "uCrTexture");
467 mYTexScaleLoc
= mGL
->fGetUniformLocation(program
, "uYTexScale");
468 mCbCrTexScaleLoc
= mGL
->fGetUniformLocation(program
, "uCbCrTexScale");
470 DebugOnly
<bool> hasUniformLocations
= texY
!= -1 &&
473 mYTexScaleLoc
!= -1 &&
474 mCbCrTexScaleLoc
!= -1;
475 MOZ_ASSERT(hasUniformLocations
, "uniforms not found");
477 mGL
->fUniform1i(texY
, Channel_Y
);
478 mGL
->fUniform1i(texCb
, Channel_Cb
);
479 mGL
->fUniform1i(texCr
, Channel_Cr
);
483 MOZ_ASSERT(mGL
->fGetAttribLocation(program
, "aPosition") == 0);
484 mYFlipLoc
= mGL
->fGetUniformLocation(program
, "uYflip");
485 MOZ_ASSERT(mYFlipLoc
!= -1, "uniform: uYflip not found");
486 mTextureTransformLoc
= mGL
->fGetUniformLocation(program
, "uTextureTransform");
487 if (mTextureTransformLoc
>= 0) {
488 // Set identity matrix as default
489 gfx::Matrix4x4 identity
;
490 mGL
->fUniformMatrix4fv(mTextureTransformLoc
, 1, false, &identity
._11
);
497 DeleteTexBlitProgram();
501 mGL
->fUseProgram(program
);
502 mGL
->fEnableVertexAttribArray(0);
503 mGL
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mTexBlit_Buffer
);
504 mGL
->fVertexAttribPointer(0,
514 GLBlitHelper::UseTexQuadProgram(BlitType target
, const gfx::IntSize
& srcSize
)
516 if (!InitTexQuadProgram(target
)) {
520 if (target
== BlitTexRect
) {
521 GLint texCoordMultLoc
= mGL
->fGetUniformLocation(mTex2DRectBlit_Program
, "uTexCoordMult");
522 MOZ_ASSERT(texCoordMultLoc
!= -1, "uniform not found");
523 mGL
->fUniform2f(texCoordMultLoc
, srcSize
.width
, srcSize
.height
);
530 GLBlitHelper::DeleteTexBlitProgram()
532 if (mTexBlit_Buffer
) {
533 mGL
->fDeleteBuffers(1, &mTexBlit_Buffer
);
536 if (mTexBlit_VertShader
) {
537 mGL
->fDeleteShader(mTexBlit_VertShader
);
538 mTexBlit_VertShader
= 0;
540 if (mTex2DBlit_FragShader
) {
541 mGL
->fDeleteShader(mTex2DBlit_FragShader
);
542 mTex2DBlit_FragShader
= 0;
544 if (mTex2DRectBlit_FragShader
) {
545 mGL
->fDeleteShader(mTex2DRectBlit_FragShader
);
546 mTex2DRectBlit_FragShader
= 0;
548 if (mTex2DBlit_Program
) {
549 mGL
->fDeleteProgram(mTex2DBlit_Program
);
550 mTex2DBlit_Program
= 0;
552 if (mTex2DRectBlit_Program
) {
553 mGL
->fDeleteProgram(mTex2DRectBlit_Program
);
554 mTex2DRectBlit_Program
= 0;
556 if (mTexExternalBlit_FragShader
) {
557 mGL
->fDeleteShader(mTexExternalBlit_FragShader
);
558 mTexExternalBlit_FragShader
= 0;
560 if (mTexYUVPlanarBlit_FragShader
) {
561 mGL
->fDeleteShader(mTexYUVPlanarBlit_FragShader
);
562 mTexYUVPlanarBlit_FragShader
= 0;
564 if (mTexExternalBlit_Program
) {
565 mGL
->fDeleteProgram(mTexExternalBlit_Program
);
566 mTexExternalBlit_Program
= 0;
568 if (mTexYUVPlanarBlit_Program
) {
569 mGL
->fDeleteProgram(mTexYUVPlanarBlit_Program
);
570 mTexYUVPlanarBlit_Program
= 0;
575 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB
, GLuint destFB
,
576 const gfx::IntSize
& srcSize
,
577 const gfx::IntSize
& destSize
,
580 MOZ_ASSERT(!srcFB
|| mGL
->fIsFramebuffer(srcFB
));
581 MOZ_ASSERT(!destFB
|| mGL
->fIsFramebuffer(destFB
));
583 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
585 ScopedBindFramebuffer
boundFB(mGL
);
586 ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
589 mGL
->Screen()->BindReadFB_Internal(srcFB
);
590 mGL
->Screen()->BindDrawFB_Internal(destFB
);
592 mGL
->BindReadFB(srcFB
);
593 mGL
->BindDrawFB(destFB
);
596 mGL
->fBlitFramebuffer(0, 0, srcSize
.width
, srcSize
.height
,
597 0, 0, destSize
.width
, destSize
.height
,
598 LOCAL_GL_COLOR_BUFFER_BIT
,
603 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB
, GLuint destFB
,
604 const gfx::IntSize
& srcSize
,
605 const gfx::IntSize
& destSize
,
606 const GLFormats
& srcFormats
,
609 MOZ_ASSERT(!srcFB
|| mGL
->fIsFramebuffer(srcFB
));
610 MOZ_ASSERT(!destFB
|| mGL
->fIsFramebuffer(destFB
));
612 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
613 BlitFramebufferToFramebuffer(srcFB
, destFB
,
619 GLuint tex
= CreateTextureForOffscreen(mGL
, srcFormats
, srcSize
);
622 BlitFramebufferToTexture(srcFB
, tex
, srcSize
, srcSize
, internalFBs
);
623 BlitTextureToFramebuffer(tex
, destFB
, srcSize
, destSize
, internalFBs
);
625 mGL
->fDeleteTextures(1, &tex
);
629 GLBlitHelper::BindAndUploadYUVTexture(Channel which
,
633 bool needsAllocation
)
635 MOZ_ASSERT(which
< Channel_Max
, "Invalid channel!");
636 GLuint
* srcTexArr
[3] = {&mSrcTexY
, &mSrcTexCb
, &mSrcTexCr
};
637 GLuint
& tex
= *srcTexArr
[which
];
639 MOZ_ASSERT(needsAllocation
);
640 tex
= CreateTexture(mGL
, LOCAL_GL_LUMINANCE
, LOCAL_GL_LUMINANCE
, LOCAL_GL_UNSIGNED_BYTE
,
641 gfx::IntSize(width
, height
), false);
643 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ which
);
645 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, tex
);
646 if (!needsAllocation
) {
647 mGL
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
,
654 LOCAL_GL_UNSIGNED_BYTE
,
657 mGL
->fTexImage2D(LOCAL_GL_TEXTURE_2D
,
664 LOCAL_GL_UNSIGNED_BYTE
,
669 #ifdef MOZ_WIDGET_GONK
671 GLBlitHelper::BindAndUploadExternalTexture(EGLImage image
)
673 MOZ_ASSERT(image
!= EGL_NO_IMAGE
, "Bad EGLImage");
676 mGL
->fGenTextures(1, &mSrcTexEGL
);
677 mGL
->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES
, mSrcTexEGL
);
678 mGL
->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL_OES
, LOCAL_GL_TEXTURE_WRAP_S
, LOCAL_GL_CLAMP_TO_EDGE
);
679 mGL
->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL_OES
, LOCAL_GL_TEXTURE_WRAP_T
, LOCAL_GL_CLAMP_TO_EDGE
);
680 mGL
->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL_OES
, LOCAL_GL_TEXTURE_MAG_FILTER
, LOCAL_GL_NEAREST
);
681 mGL
->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL_OES
, LOCAL_GL_TEXTURE_MIN_FILTER
, LOCAL_GL_NEAREST
);
683 mGL
->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES
, mSrcTexEGL
);
685 mGL
->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL_OES
, image
);
689 GLBlitHelper::BlitGrallocImage(layers::GrallocImage
* grallocImage
, bool yFlip
)
691 ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
692 mGL
->fClear(LOCAL_GL_COLOR_BUFFER_BIT
);
695 LOCAL_EGL_IMAGE_PRESERVED
, LOCAL_EGL_TRUE
,
696 LOCAL_EGL_NONE
, LOCAL_EGL_NONE
698 EGLImage image
= sEGLLibrary
.fCreateImage(sEGLLibrary
.Display(),
700 LOCAL_EGL_NATIVE_BUFFER_ANDROID
,
701 grallocImage
->GetNativeBuffer(), attrs
);
702 if (image
== EGL_NO_IMAGE
)
706 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL_OES
, &oldBinding
);
708 BindAndUploadExternalTexture(image
);
710 mGL
->fUniform1f(mYFlipLoc
, yFlip
? (float)1.0f
: (float)0.0f
);
712 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
714 sEGLLibrary
.fDestroyImage(sEGLLibrary
.Display(), image
);
715 mGL
->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES
, oldBinding
);
720 #ifdef MOZ_WIDGET_ANDROID
723 GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage
* stImage
)
725 AndroidSurfaceTexture
* surfaceTexture
= stImage
->GetData()->mSurfTex
;
726 bool yFlip
= stImage
->GetData()->mInverted
;
728 ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
729 mGL
->fClear(LOCAL_GL_COLOR_BUFFER_BIT
);
731 if (NS_FAILED(surfaceTexture
->Attach(mGL
))) {
735 // UpdateTexImage() changes the EXTERNAL binding, so save it here
736 // so we can restore it after.
738 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL
, &oldBinding
);
740 surfaceTexture
->UpdateTexImage();
742 gfx::Matrix4x4 transform
;
743 surfaceTexture
->GetTransformMatrix(transform
);
745 mGL
->fUniformMatrix4fv(mTextureTransformLoc
, 1, false, &transform
._11
);
746 mGL
->fUniform1f(mYFlipLoc
, yFlip
? 1.0f
: 0.0f
);
747 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
749 surfaceTexture
->Detach();
751 mGL
->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL
, oldBinding
);
757 GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage
* yuvImage
, bool yFlip
)
759 ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
760 const PlanarYCbCrData
* yuvData
= yuvImage
->GetData();
762 bool needsAllocation
= false;
763 if (mTexWidth
!= yuvData
->mYStride
|| mTexHeight
!= yuvData
->mYSize
.height
) {
764 mTexWidth
= yuvData
->mYStride
;
765 mTexHeight
= yuvData
->mYSize
.height
;
766 needsAllocation
= true;
770 for (int i
= 0; i
< 3; i
++) {
771 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
772 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D
, &oldTex
[i
]);
774 BindAndUploadYUVTexture(Channel_Y
, yuvData
->mYStride
, yuvData
->mYSize
.height
, yuvData
->mYChannel
, needsAllocation
);
775 BindAndUploadYUVTexture(Channel_Cb
, yuvData
->mCbCrStride
, yuvData
->mCbCrSize
.height
, yuvData
->mCbChannel
, needsAllocation
);
776 BindAndUploadYUVTexture(Channel_Cr
, yuvData
->mCbCrStride
, yuvData
->mCbCrSize
.height
, yuvData
->mCrChannel
, needsAllocation
);
778 mGL
->fUniform1f(mYFlipLoc
, yFlip
? (float)1.0 : (float)0.0);
780 if (needsAllocation
) {
781 mGL
->fUniform2f(mYTexScaleLoc
, (float)yuvData
->mYSize
.width
/yuvData
->mYStride
, 1.0f
);
782 mGL
->fUniform2f(mCbCrTexScaleLoc
, (float)yuvData
->mCbCrSize
.width
/yuvData
->mCbCrStride
, 1.0f
);
785 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
786 for (int i
= 0; i
< 3; i
++) {
787 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
788 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, oldTex
[i
]);
794 GLBlitHelper::BlitImageToFramebuffer(layers::Image
* srcImage
,
795 const gfx::IntSize
& destSize
,
803 ScopedGLDrawState
autoStates(mGL
);
806 switch (srcImage
->GetFormat()) {
807 case ImageFormat::PLANAR_YCBCR
:
808 type
= ConvertPlanarYCbCr
;
810 case ImageFormat::GRALLOC_PLANAR_YCBCR
:
811 #ifdef MOZ_WIDGET_GONK
812 type
= ConvertGralloc
;
815 #ifdef MOZ_WIDGET_ANDROID
816 case ImageFormat::SURFACE_TEXTURE
:
817 type
= ConvertSurfaceTexture
;
824 bool init
= InitTexQuadProgram(type
);
829 ScopedBindFramebuffer
boundFB(mGL
, destFB
);
830 mGL
->fColorMask(LOCAL_GL_TRUE
, LOCAL_GL_TRUE
, LOCAL_GL_TRUE
, LOCAL_GL_TRUE
);
831 mGL
->fViewport(0, 0, destSize
.width
, destSize
.height
);
832 if (xoffset
!= 0 && yoffset
!= 0 && cropWidth
!= 0 && cropHeight
!= 0) {
833 mGL
->fEnable(LOCAL_GL_SCISSOR_TEST
);
834 mGL
->fScissor(xoffset
, yoffset
, (GLsizei
)cropWidth
, (GLsizei
)cropHeight
);
837 #ifdef MOZ_WIDGET_GONK
838 if (type
== ConvertGralloc
) {
839 layers::GrallocImage
* grallocImage
= static_cast<layers::GrallocImage
*>(srcImage
);
840 return BlitGrallocImage(grallocImage
, yFlip
);
843 if (type
== ConvertPlanarYCbCr
) {
844 mGL
->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT
, 1);
845 PlanarYCbCrImage
* yuvImage
= static_cast<PlanarYCbCrImage
*>(srcImage
);
846 return BlitPlanarYCbCrImage(yuvImage
, yFlip
);
848 #ifdef MOZ_WIDGET_ANDROID
849 if (type
== ConvertSurfaceTexture
) {
850 layers::SurfaceTextureImage
* stImage
= static_cast<layers::SurfaceTextureImage
*>(srcImage
);
851 return BlitSurfaceTextureImage(stImage
);
859 GLBlitHelper::BlitImageToTexture(layers::Image
* srcImage
,
860 const gfx::IntSize
& destSize
,
869 ScopedGLDrawState
autoStates(mGL
);
872 mGL
->fGenFramebuffers(1, &mFBO
);
875 ScopedBindFramebuffer
boundFB(mGL
, mFBO
);
876 mGL
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
, destTarget
, destTex
, 0);
877 return BlitImageToFramebuffer(srcImage
, destSize
, mFBO
, yFlip
, xoffset
, yoffset
,
878 cropWidth
, cropHeight
);
882 GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex
, GLuint destFB
,
883 const gfx::IntSize
& srcSize
,
884 const gfx::IntSize
& destSize
,
888 MOZ_ASSERT(mGL
->fIsTexture(srcTex
));
889 MOZ_ASSERT(!destFB
|| mGL
->fIsFramebuffer(destFB
));
891 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
892 ScopedFramebufferForTexture
srcWrapper(mGL
, srcTex
, srcTarget
);
893 MOZ_ASSERT(srcWrapper
.IsComplete());
895 BlitFramebufferToFramebuffer(srcWrapper
.FB(), destFB
,
904 case LOCAL_GL_TEXTURE_2D
:
907 case LOCAL_GL_TEXTURE_RECTANGLE_ARB
:
911 printf_stderr("Fatal Error: Failed to prepare to blit texture->framebuffer.\n");
916 ScopedGLDrawState
autoStates(mGL
);
918 mGL
->Screen()->BindFB_Internal(destFB
);
923 // Does destructive things to (only!) what we just saved above.
924 bool good
= UseTexQuadProgram(type
, srcSize
);
926 // We're up against the wall, so bail.
927 // This should really be MOZ_CRASH(why) or MOZ_RUNTIME_ASSERT(good).
928 printf_stderr("Fatal Error: Failed to prepare to blit texture->framebuffer.\n");
931 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
935 GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB
, GLuint destTex
,
936 const gfx::IntSize
& srcSize
,
937 const gfx::IntSize
& destSize
,
941 MOZ_ASSERT(!srcFB
|| mGL
->fIsFramebuffer(srcFB
));
942 MOZ_ASSERT(mGL
->fIsTexture(destTex
));
944 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
945 ScopedFramebufferForTexture
destWrapper(mGL
, destTex
, destTarget
);
947 BlitFramebufferToFramebuffer(srcFB
, destWrapper
.FB(),
953 ScopedBindTexture
autoTex(mGL
, destTex
, destTarget
);
955 ScopedBindFramebuffer
boundFB(mGL
);
957 mGL
->Screen()->BindFB_Internal(srcFB
);
962 ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
963 mGL
->fCopyTexSubImage2D(destTarget
, 0,
966 srcSize
.width
, srcSize
.height
);
970 GLBlitHelper::BlitTextureToTexture(GLuint srcTex
, GLuint destTex
,
971 const gfx::IntSize
& srcSize
,
972 const gfx::IntSize
& destSize
,
973 GLenum srcTarget
, GLenum destTarget
)
975 MOZ_ASSERT(mGL
->fIsTexture(srcTex
));
976 MOZ_ASSERT(mGL
->fIsTexture(destTex
));
978 // Generally, just use the CopyTexSubImage path
979 ScopedFramebufferForTexture
srcWrapper(mGL
, srcTex
, srcTarget
);
981 BlitFramebufferToTexture(srcWrapper
.FB(), destTex
,
982 srcSize
, destSize
, destTarget
);