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"
23 #include "GLLibraryEGL.h"
26 using mozilla::layers::PlanarYCbCrImage
;
27 using mozilla::layers::PlanarYCbCrData
;
33 RenderbufferStorageBySamples(GLContext
* aGL
, GLsizei aSamples
,
34 GLenum aInternalFormat
, const gfx::IntSize
& aSize
)
37 aGL
->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER
,
40 aSize
.width
, aSize
.height
);
42 aGL
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
,
44 aSize
.width
, aSize
.height
);
49 CreateTexture(GLContext
* aGL
, GLenum aInternalFormat
, GLenum aFormat
,
50 GLenum aType
, const gfx::IntSize
& aSize
, bool linear
)
53 aGL
->fGenTextures(1, &tex
);
54 ScopedBindTexture
autoTex(aGL
, tex
);
56 aGL
->fTexParameteri(LOCAL_GL_TEXTURE_2D
,
57 LOCAL_GL_TEXTURE_MIN_FILTER
, linear
? LOCAL_GL_LINEAR
59 aGL
->fTexParameteri(LOCAL_GL_TEXTURE_2D
,
60 LOCAL_GL_TEXTURE_MAG_FILTER
, linear
? LOCAL_GL_LINEAR
62 aGL
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_S
,
63 LOCAL_GL_CLAMP_TO_EDGE
);
64 aGL
->fTexParameteri(LOCAL_GL_TEXTURE_2D
, LOCAL_GL_TEXTURE_WRAP_T
,
65 LOCAL_GL_CLAMP_TO_EDGE
);
67 aGL
->fTexImage2D(LOCAL_GL_TEXTURE_2D
,
70 aSize
.width
, aSize
.height
,
80 CreateTextureForOffscreen(GLContext
* aGL
, const GLFormats
& aFormats
,
81 const gfx::IntSize
& aSize
)
83 MOZ_ASSERT(aFormats
.color_texInternalFormat
);
84 MOZ_ASSERT(aFormats
.color_texFormat
);
85 MOZ_ASSERT(aFormats
.color_texType
);
87 return CreateTexture(aGL
,
88 aFormats
.color_texInternalFormat
,
89 aFormats
.color_texFormat
,
90 aFormats
.color_texType
,
96 CreateRenderbuffer(GLContext
* aGL
, GLenum aFormat
, GLsizei aSamples
,
97 const gfx::IntSize
& aSize
)
100 aGL
->fGenRenderbuffers(1, &rb
);
101 ScopedBindRenderbuffer
autoRB(aGL
, rb
);
103 RenderbufferStorageBySamples(aGL
, aSamples
, aFormat
, aSize
);
110 CreateRenderbuffersForOffscreen(GLContext
* aGL
, const GLFormats
& aFormats
,
111 const gfx::IntSize
& aSize
, bool aMultisample
,
112 GLuint
* aColorMSRB
, GLuint
* aDepthRB
,
115 GLsizei samples
= aMultisample
? aFormats
.samples
: 0;
117 MOZ_ASSERT(aFormats
.samples
> 0);
118 MOZ_ASSERT(aFormats
.color_rbFormat
);
120 *aColorMSRB
= CreateRenderbuffer(aGL
, aFormats
.color_rbFormat
, samples
, aSize
);
125 aFormats
.depthStencil
)
127 *aDepthRB
= CreateRenderbuffer(aGL
, aFormats
.depthStencil
, samples
, aSize
);
128 *aStencilRB
= *aDepthRB
;
131 MOZ_ASSERT(aFormats
.depth
);
133 *aDepthRB
= CreateRenderbuffer(aGL
, aFormats
.depth
, samples
, aSize
);
137 MOZ_ASSERT(aFormats
.stencil
);
139 *aStencilRB
= CreateRenderbuffer(aGL
, aFormats
.stencil
, samples
, aSize
);
145 GLBlitHelper::GLBlitHelper(GLContext
* gl
)
148 , mTexBlit_VertShader(0)
149 , mTex2DBlit_FragShader(0)
150 , mTex2DRectBlit_FragShader(0)
151 , mTex2DBlit_Program(0)
152 , mTex2DRectBlit_Program(0)
154 , mTextureTransformLoc(-1)
155 , mTexExternalBlit_FragShader(0)
156 , mTexYUVPlanarBlit_FragShader(0)
157 , mTexExternalBlit_Program(0)
158 , mTexYUVPlanarBlit_Program(0)
165 , mCbCrTexScaleLoc(-1)
169 , mCurCbCrScale(1.0f
)
173 GLBlitHelper::~GLBlitHelper()
175 DeleteTexBlitProgram();
184 mSrcTexY
= mSrcTexCb
= mSrcTexCr
= mSrcTexEGL
= 0;
185 mGL
->fDeleteTextures(ArrayLength(tex
), tex
);
188 mGL
->fDeleteFramebuffers(1, &mFBO
);
193 // Allowed to be destructive of state we restore in functions below.
195 GLBlitHelper::InitTexQuadProgram(BlitType target
)
197 const char kTexBlit_VertShaderSource
[] = "\
199 precision mediump float; \n\
201 attribute vec2 aPosition; \n\
203 uniform float uYflip; \n\
204 varying vec2 vTexCoord; \n\
208 vTexCoord = aPosition; \n\
209 vTexCoord.y = abs(vTexCoord.y - uYflip); \n\
210 vec2 vertPos = aPosition * 2.0 - 1.0; \n\
211 gl_Position = vec4(vertPos, 0.0, 1.0); \n\
215 const char kTex2DBlit_FragShaderSource
[] = "\
216 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
217 precision highp float; \n\
219 prevision mediump float; \n\
221 uniform sampler2D uTexUnit; \n\
223 varying vec2 vTexCoord; \n\
227 gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\
231 const char kTex2DRectBlit_FragShaderSource
[] = "\
232 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
233 precision highp float; \n\
235 precision mediump float; \n\
238 uniform sampler2D uTexUnit; \n\
239 uniform vec2 uTexCoordMult; \n\
241 varying vec2 vTexCoord; \n\
245 gl_FragColor = texture2DRect(uTexUnit, \n\
246 vTexCoord * uTexCoordMult); \n\
249 #ifdef ANDROID /* MOZ_WIDGET_ANDROID || MOZ_WIDGET_GONK */
250 const char kTexExternalBlit_FragShaderSource
[] = "\
251 #extension GL_OES_EGL_image_external : require \n\
252 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
253 precision highp float; \n\
255 precision mediump float; \n\
257 varying vec2 vTexCoord; \n\
258 uniform mat4 uTextureTransform; \n\
259 uniform samplerExternalOES uTexUnit; \n\
263 gl_FragColor = texture2D(uTexUnit, \n\
264 (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy); \n\
269 [R] [1.1643835616438356, 0.0, 1.5960267857142858] [ Y - 16]
270 [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708] x [Cb - 128]
271 [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [Cr - 128]
273 For [0,1] instead of [0,255], and to 5 places:
274 [R] [1.16438, 0.00000, 1.59603] [ Y - 0.06275]
275 [G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
276 [B] [1.16438, 2.01723, 0.00000] [Cr - 0.50196]
278 const char kTexYUVPlanarBlit_FragShaderSource
[] = "\
280 precision mediump float \n\
282 varying vec2 vTexCoord; \n\
283 uniform sampler2D uYTexture; \n\
284 uniform sampler2D uCbTexture; \n\
285 uniform sampler2D uCrTexture; \n\
286 uniform vec2 uYTexScale; \n\
287 uniform vec2 uCbCrTexScale; \n\
290 float y = texture2D(uYTexture, vTexCoord * uYTexScale).r; \n\
291 float cb = texture2D(uCbTexture, vTexCoord * uCbCrTexScale).r; \n\
292 float cr = texture2D(uCrTexture, vTexCoord * uCbCrTexScale).r; \n\
293 y = (y - 0.06275) * 1.16438; \n\
294 cb = cb - 0.50196; \n\
295 cr = cr - 0.50196; \n\
296 gl_FragColor.r = y + cr * 1.59603; \n\
297 gl_FragColor.g = y - 0.81297 * cr - 0.39176 * cb; \n\
298 gl_FragColor.b = y + cb * 2.01723; \n\
299 gl_FragColor.a = 1.0; \n\
303 bool success
= false;
306 GLuint
*fragShaderPtr
;
307 const char* fragShaderSource
;
309 case ConvertEGLImage
:
311 programPtr
= &mTex2DBlit_Program
;
312 fragShaderPtr
= &mTex2DBlit_FragShader
;
313 fragShaderSource
= kTex2DBlit_FragShaderSource
;
316 programPtr
= &mTex2DRectBlit_Program
;
317 fragShaderPtr
= &mTex2DRectBlit_FragShader
;
318 fragShaderSource
= kTex2DRectBlit_FragShaderSource
;
321 case ConvertSurfaceTexture
:
323 programPtr
= &mTexExternalBlit_Program
;
324 fragShaderPtr
= &mTexExternalBlit_FragShader
;
325 fragShaderSource
= kTexExternalBlit_FragShaderSource
;
328 case ConvertPlanarYCbCr
:
329 programPtr
= &mTexYUVPlanarBlit_Program
;
330 fragShaderPtr
= &mTexYUVPlanarBlit_FragShader
;
331 fragShaderSource
= kTexYUVPlanarBlit_FragShaderSource
;
337 GLuint
& program
= *programPtr
;
338 GLuint
& fragShader
= *fragShaderPtr
;
340 // Use do-while(false) to let us break on failure
343 // Already have it...
348 if (!mTexBlit_Buffer
) {
361 HeapCopyOfStackArray
<GLfloat
> vertsOnHeap(verts
);
363 MOZ_ASSERT(!mTexBlit_Buffer
);
364 mGL
->fGenBuffers(1, &mTexBlit_Buffer
);
365 mGL
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mTexBlit_Buffer
);
367 // Make sure we have a sane size.
368 mGL
->fBufferData(LOCAL_GL_ARRAY_BUFFER
, vertsOnHeap
.ByteLength(), vertsOnHeap
.Data(), LOCAL_GL_STATIC_DRAW
);
371 if (!mTexBlit_VertShader
) {
373 const char* vertShaderSource
= kTexBlit_VertShaderSource
;
375 mTexBlit_VertShader
= mGL
->fCreateShader(LOCAL_GL_VERTEX_SHADER
);
376 mGL
->fShaderSource(mTexBlit_VertShader
, 1, &vertShaderSource
, nullptr);
377 mGL
->fCompileShader(mTexBlit_VertShader
);
380 MOZ_ASSERT(!fragShader
);
381 fragShader
= mGL
->fCreateShader(LOCAL_GL_FRAGMENT_SHADER
);
382 mGL
->fShaderSource(fragShader
, 1, &fragShaderSource
, nullptr);
383 mGL
->fCompileShader(fragShader
);
385 program
= mGL
->fCreateProgram();
386 mGL
->fAttachShader(program
, mTexBlit_VertShader
);
387 mGL
->fAttachShader(program
, fragShader
);
388 mGL
->fBindAttribLocation(program
, 0, "aPosition");
389 mGL
->fLinkProgram(program
);
391 if (mGL
->DebugMode()) {
393 mGL
->fGetShaderiv(mTexBlit_VertShader
, LOCAL_GL_COMPILE_STATUS
, &status
);
394 if (status
!= LOCAL_GL_TRUE
) {
395 NS_ERROR("Vert shader compilation failed.");
398 mGL
->fGetShaderiv(mTexBlit_VertShader
, LOCAL_GL_INFO_LOG_LENGTH
, &length
);
400 printf_stderr("No shader info log available.\n");
404 nsAutoArrayPtr
<char> buffer(new char[length
]);
405 mGL
->fGetShaderInfoLog(mTexBlit_VertShader
, length
, nullptr, buffer
);
407 printf_stderr("Shader info log (%d bytes): %s\n", length
, buffer
.get());
412 mGL
->fGetShaderiv(fragShader
, LOCAL_GL_COMPILE_STATUS
, &status
);
413 if (status
!= LOCAL_GL_TRUE
) {
414 NS_ERROR("Frag shader compilation failed.");
417 mGL
->fGetShaderiv(fragShader
, LOCAL_GL_INFO_LOG_LENGTH
, &length
);
419 printf_stderr("No shader info log available.\n");
423 nsAutoArrayPtr
<char> buffer(new char[length
]);
424 mGL
->fGetShaderInfoLog(fragShader
, length
, nullptr, buffer
);
426 printf_stderr("Shader info log (%d bytes): %s\n", length
, buffer
.get());
432 mGL
->fGetProgramiv(program
, LOCAL_GL_LINK_STATUS
, &status
);
433 if (status
!= LOCAL_GL_TRUE
) {
434 if (mGL
->DebugMode()) {
435 NS_ERROR("Linking blit program failed.");
437 mGL
->fGetProgramiv(program
, LOCAL_GL_INFO_LOG_LENGTH
, &length
);
439 printf_stderr("No program info log available.\n");
443 nsAutoArrayPtr
<char> buffer(new char[length
]);
444 mGL
->fGetProgramInfoLog(program
, length
, nullptr, buffer
);
446 printf_stderr("Program info log (%d bytes): %s\n", length
, buffer
.get());
451 // Cache and set attribute and uniform
452 mGL
->fUseProgram(program
);
456 case ConvertEGLImage
:
457 case ConvertSurfaceTexture
:
458 case ConvertGralloc
: {
460 GLint texUnitLoc
= mGL
->fGetUniformLocation(program
, "uTexUnit");
461 MOZ_ASSERT(texUnitLoc
!= -1, "uniform uTexUnit not found");
462 mGL
->fUniform1i(texUnitLoc
, 0);
466 case ConvertPlanarYCbCr
: {
467 GLint texY
= mGL
->fGetUniformLocation(program
, "uYTexture");
468 GLint texCb
= mGL
->fGetUniformLocation(program
, "uCbTexture");
469 GLint texCr
= mGL
->fGetUniformLocation(program
, "uCrTexture");
470 mYTexScaleLoc
= mGL
->fGetUniformLocation(program
, "uYTexScale");
471 mCbCrTexScaleLoc
= mGL
->fGetUniformLocation(program
, "uCbCrTexScale");
473 DebugOnly
<bool> hasUniformLocations
= texY
!= -1 &&
476 mYTexScaleLoc
!= -1 &&
477 mCbCrTexScaleLoc
!= -1;
478 MOZ_ASSERT(hasUniformLocations
, "uniforms not found");
480 mGL
->fUniform1i(texY
, Channel_Y
);
481 mGL
->fUniform1i(texCb
, Channel_Cb
);
482 mGL
->fUniform1i(texCr
, Channel_Cr
);
486 MOZ_ASSERT(mGL
->fGetAttribLocation(program
, "aPosition") == 0);
487 mYFlipLoc
= mGL
->fGetUniformLocation(program
, "uYflip");
488 MOZ_ASSERT(mYFlipLoc
!= -1, "uniform: uYflip not found");
489 mTextureTransformLoc
= mGL
->fGetUniformLocation(program
, "uTextureTransform");
490 if (mTextureTransformLoc
>= 0) {
491 // Set identity matrix as default
492 gfx::Matrix4x4 identity
;
493 mGL
->fUniformMatrix4fv(mTextureTransformLoc
, 1, false, &identity
._11
);
500 DeleteTexBlitProgram();
504 mGL
->fUseProgram(program
);
505 mGL
->fEnableVertexAttribArray(0);
506 mGL
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mTexBlit_Buffer
);
507 mGL
->fVertexAttribPointer(0,
517 GLBlitHelper::UseTexQuadProgram(BlitType target
, const gfx::IntSize
& srcSize
)
519 if (!InitTexQuadProgram(target
)) {
523 if (target
== BlitTexRect
) {
524 GLint texCoordMultLoc
= mGL
->fGetUniformLocation(mTex2DRectBlit_Program
, "uTexCoordMult");
525 MOZ_ASSERT(texCoordMultLoc
!= -1, "uniform not found");
526 mGL
->fUniform2f(texCoordMultLoc
, srcSize
.width
, srcSize
.height
);
533 GLBlitHelper::DeleteTexBlitProgram()
535 if (mTexBlit_Buffer
) {
536 mGL
->fDeleteBuffers(1, &mTexBlit_Buffer
);
539 if (mTexBlit_VertShader
) {
540 mGL
->fDeleteShader(mTexBlit_VertShader
);
541 mTexBlit_VertShader
= 0;
543 if (mTex2DBlit_FragShader
) {
544 mGL
->fDeleteShader(mTex2DBlit_FragShader
);
545 mTex2DBlit_FragShader
= 0;
547 if (mTex2DRectBlit_FragShader
) {
548 mGL
->fDeleteShader(mTex2DRectBlit_FragShader
);
549 mTex2DRectBlit_FragShader
= 0;
551 if (mTex2DBlit_Program
) {
552 mGL
->fDeleteProgram(mTex2DBlit_Program
);
553 mTex2DBlit_Program
= 0;
555 if (mTex2DRectBlit_Program
) {
556 mGL
->fDeleteProgram(mTex2DRectBlit_Program
);
557 mTex2DRectBlit_Program
= 0;
559 if (mTexExternalBlit_FragShader
) {
560 mGL
->fDeleteShader(mTexExternalBlit_FragShader
);
561 mTexExternalBlit_FragShader
= 0;
563 if (mTexYUVPlanarBlit_FragShader
) {
564 mGL
->fDeleteShader(mTexYUVPlanarBlit_FragShader
);
565 mTexYUVPlanarBlit_FragShader
= 0;
567 if (mTexExternalBlit_Program
) {
568 mGL
->fDeleteProgram(mTexExternalBlit_Program
);
569 mTexExternalBlit_Program
= 0;
571 if (mTexYUVPlanarBlit_Program
) {
572 mGL
->fDeleteProgram(mTexYUVPlanarBlit_Program
);
573 mTexYUVPlanarBlit_Program
= 0;
578 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB
, GLuint destFB
,
579 const gfx::IntSize
& srcSize
,
580 const gfx::IntSize
& destSize
,
583 MOZ_ASSERT(!srcFB
|| mGL
->fIsFramebuffer(srcFB
));
584 MOZ_ASSERT(!destFB
|| mGL
->fIsFramebuffer(destFB
));
586 MOZ_ASSERT(mGL
->IsSupported(GLFeature::framebuffer_blit
));
588 ScopedBindFramebuffer
boundFB(mGL
);
589 ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
592 mGL
->Screen()->BindReadFB_Internal(srcFB
);
593 mGL
->Screen()->BindDrawFB_Internal(destFB
);
595 mGL
->BindReadFB(srcFB
);
596 mGL
->BindDrawFB(destFB
);
599 mGL
->fBlitFramebuffer(0, 0, srcSize
.width
, srcSize
.height
,
600 0, 0, destSize
.width
, destSize
.height
,
601 LOCAL_GL_COLOR_BUFFER_BIT
,
606 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB
, GLuint destFB
,
607 const gfx::IntSize
& srcSize
,
608 const gfx::IntSize
& destSize
,
609 const GLFormats
& srcFormats
,
612 MOZ_ASSERT(!srcFB
|| mGL
->fIsFramebuffer(srcFB
));
613 MOZ_ASSERT(!destFB
|| mGL
->fIsFramebuffer(destFB
));
615 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
616 BlitFramebufferToFramebuffer(srcFB
, destFB
,
622 GLuint tex
= CreateTextureForOffscreen(mGL
, srcFormats
, srcSize
);
625 BlitFramebufferToTexture(srcFB
, tex
, srcSize
, srcSize
, internalFBs
);
626 BlitTextureToFramebuffer(tex
, destFB
, srcSize
, destSize
, internalFBs
);
628 mGL
->fDeleteTextures(1, &tex
);
632 GLBlitHelper::BindAndUploadYUVTexture(Channel which
,
636 bool needsAllocation
)
638 MOZ_ASSERT(which
< Channel_Max
, "Invalid channel!");
639 GLuint
* srcTexArr
[3] = {&mSrcTexY
, &mSrcTexCb
, &mSrcTexCr
};
640 GLuint
& tex
= *srcTexArr
[which
];
642 MOZ_ASSERT(needsAllocation
);
643 tex
= CreateTexture(mGL
, LOCAL_GL_LUMINANCE
, LOCAL_GL_LUMINANCE
, LOCAL_GL_UNSIGNED_BYTE
,
644 gfx::IntSize(width
, height
), false);
646 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ which
);
648 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, tex
);
649 if (!needsAllocation
) {
650 mGL
->fTexSubImage2D(LOCAL_GL_TEXTURE_2D
,
657 LOCAL_GL_UNSIGNED_BYTE
,
660 mGL
->fTexImage2D(LOCAL_GL_TEXTURE_2D
,
667 LOCAL_GL_UNSIGNED_BYTE
,
673 GLBlitHelper::BindAndUploadEGLImage(EGLImage image
, GLuint target
)
675 MOZ_ASSERT(image
!= EGL_NO_IMAGE
, "Bad EGLImage");
678 mGL
->fGenTextures(1, &mSrcTexEGL
);
679 mGL
->fBindTexture(target
, mSrcTexEGL
);
680 mGL
->fTexParameteri(target
, LOCAL_GL_TEXTURE_WRAP_S
, LOCAL_GL_CLAMP_TO_EDGE
);
681 mGL
->fTexParameteri(target
, LOCAL_GL_TEXTURE_WRAP_T
, LOCAL_GL_CLAMP_TO_EDGE
);
682 mGL
->fTexParameteri(target
, LOCAL_GL_TEXTURE_MAG_FILTER
, LOCAL_GL_NEAREST
);
683 mGL
->fTexParameteri(target
, LOCAL_GL_TEXTURE_MIN_FILTER
, LOCAL_GL_NEAREST
);
685 mGL
->fBindTexture(target
, mSrcTexEGL
);
687 mGL
->fEGLImageTargetTexture2D(target
, image
);
690 #ifdef MOZ_WIDGET_GONK
693 GLBlitHelper::BlitGrallocImage(layers::GrallocImage
* grallocImage
, bool yflip
)
695 ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
696 mGL
->fClear(LOCAL_GL_COLOR_BUFFER_BIT
);
699 LOCAL_EGL_IMAGE_PRESERVED
, LOCAL_EGL_TRUE
,
700 LOCAL_EGL_NONE
, LOCAL_EGL_NONE
702 EGLImage image
= sEGLLibrary
.fCreateImage(sEGLLibrary
.Display(),
704 LOCAL_EGL_NATIVE_BUFFER_ANDROID
,
705 grallocImage
->GetNativeBuffer(), attrs
);
706 if (image
== EGL_NO_IMAGE
)
710 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL_OES
, &oldBinding
);
712 BindAndUploadEGLImage(image
, LOCAL_GL_TEXTURE_EXTERNAL_OES
);
714 mGL
->fUniform1f(mYFlipLoc
, yflip
? (float)1.0f
: (float)0.0f
);
716 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
718 sEGLLibrary
.fDestroyImage(sEGLLibrary
.Display(), image
);
719 mGL
->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES
, oldBinding
);
724 #ifdef MOZ_WIDGET_ANDROID
726 #define ATTACH_WAIT_MS 50
729 GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage
* stImage
, bool yflip
)
731 AndroidSurfaceTexture
* surfaceTexture
= stImage
->GetData()->mSurfTex
;
733 ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
735 if (NS_FAILED(surfaceTexture
->Attach(mGL
, PR_MillisecondsToInterval(ATTACH_WAIT_MS
))))
738 // UpdateTexImage() changes the EXTERNAL binding, so save it here
739 // so we can restore it after.
741 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL
, &oldBinding
);
743 surfaceTexture
->UpdateTexImage();
745 gfx::Matrix4x4 transform
;
746 surfaceTexture
->GetTransformMatrix(transform
);
748 mGL
->fUniformMatrix4fv(mTextureTransformLoc
, 1, false, &transform
._11
);
749 mGL
->fUniform1f(mYFlipLoc
, yflip
? 1.0f
: 0.0f
);
750 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
752 surfaceTexture
->Detach();
754 mGL
->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL
, oldBinding
);
759 GLBlitHelper::BlitEGLImageImage(layers::EGLImageImage
* image
, bool yflip
)
761 EGLImage eglImage
= image
->GetData()->mImage
;
762 EGLSync eglSync
= image
->GetData()->mSync
;
765 EGLint status
= sEGLLibrary
.fClientWaitSync(EGL_DISPLAY(), eglSync
, 0, LOCAL_EGL_FOREVER
);
766 if (status
!= LOCAL_EGL_CONDITION_SATISFIED
) {
771 ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
774 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D
, &oldBinding
);
776 BindAndUploadEGLImage(eglImage
, LOCAL_GL_TEXTURE_2D
);
778 mGL
->fUniform1f(mYFlipLoc
, yflip
? 1.0f
: 0.0f
);
780 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
782 mGL
->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES
, oldBinding
);
789 GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage
* yuvImage
, bool yflip
)
791 ScopedBindTextureUnit
boundTU(mGL
, LOCAL_GL_TEXTURE0
);
792 const PlanarYCbCrData
* yuvData
= yuvImage
->GetData();
794 bool needsAllocation
= false;
795 if (mTexWidth
!= yuvData
->mYStride
|| mTexHeight
!= yuvData
->mYSize
.height
) {
796 mTexWidth
= yuvData
->mYStride
;
797 mTexHeight
= yuvData
->mYSize
.height
;
798 needsAllocation
= true;
802 for (int i
= 0; i
< 3; i
++) {
803 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
804 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D
, &oldTex
[i
]);
806 BindAndUploadYUVTexture(Channel_Y
, yuvData
->mYStride
, yuvData
->mYSize
.height
, yuvData
->mYChannel
, needsAllocation
);
807 BindAndUploadYUVTexture(Channel_Cb
, yuvData
->mCbCrStride
, yuvData
->mCbCrSize
.height
, yuvData
->mCbChannel
, needsAllocation
);
808 BindAndUploadYUVTexture(Channel_Cr
, yuvData
->mCbCrStride
, yuvData
->mCbCrSize
.height
, yuvData
->mCrChannel
, needsAllocation
);
810 mGL
->fUniform1f(mYFlipLoc
, yflip
? (float)1.0 : (float)0.0);
812 if (needsAllocation
) {
813 mGL
->fUniform2f(mYTexScaleLoc
, (float)yuvData
->mYSize
.width
/yuvData
->mYStride
, 1.0f
);
814 mGL
->fUniform2f(mCbCrTexScaleLoc
, (float)yuvData
->mCbCrSize
.width
/yuvData
->mCbCrStride
, 1.0f
);
817 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
818 for (int i
= 0; i
< 3; i
++) {
819 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
820 mGL
->fBindTexture(LOCAL_GL_TEXTURE_2D
, oldTex
[i
]);
826 GLBlitHelper::BlitImageToFramebuffer(layers::Image
* srcImage
,
827 const gfx::IntSize
& destSize
,
835 ScopedGLDrawState
autoStates(mGL
);
838 switch (srcImage
->GetFormat()) {
839 case ImageFormat::PLANAR_YCBCR
:
840 type
= ConvertPlanarYCbCr
;
842 case ImageFormat::GRALLOC_PLANAR_YCBCR
:
843 #ifdef MOZ_WIDGET_GONK
844 type
= ConvertGralloc
;
847 #ifdef MOZ_WIDGET_ANDROID
848 case ImageFormat::SURFACE_TEXTURE
:
849 type
= ConvertSurfaceTexture
;
851 case ImageFormat::EGLIMAGE
:
852 type
= ConvertEGLImage
;
859 bool init
= InitTexQuadProgram(type
);
864 ScopedBindFramebuffer
boundFB(mGL
, destFB
);
865 mGL
->fColorMask(LOCAL_GL_TRUE
, LOCAL_GL_TRUE
, LOCAL_GL_TRUE
, LOCAL_GL_TRUE
);
866 mGL
->fViewport(0, 0, destSize
.width
, destSize
.height
);
867 if (xoffset
!= 0 && yoffset
!= 0 && cropWidth
!= 0 && cropHeight
!= 0) {
868 mGL
->fEnable(LOCAL_GL_SCISSOR_TEST
);
869 mGL
->fScissor(xoffset
, yoffset
, (GLsizei
)cropWidth
, (GLsizei
)cropHeight
);
872 #ifdef MOZ_WIDGET_GONK
873 if (type
== ConvertGralloc
) {
874 layers::GrallocImage
* grallocImage
= static_cast<layers::GrallocImage
*>(srcImage
);
875 return BlitGrallocImage(grallocImage
, yflip
);
878 if (type
== ConvertPlanarYCbCr
) {
879 mGL
->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT
, 1);
880 PlanarYCbCrImage
* yuvImage
= static_cast<PlanarYCbCrImage
*>(srcImage
);
881 return BlitPlanarYCbCrImage(yuvImage
, yflip
);
883 #ifdef MOZ_WIDGET_ANDROID
884 if (type
== ConvertSurfaceTexture
) {
885 layers::SurfaceTextureImage
* stImage
= static_cast<layers::SurfaceTextureImage
*>(srcImage
);
886 return BlitSurfaceTextureImage(stImage
, yflip
);
888 if (type
== ConvertEGLImage
) {
889 layers::EGLImageImage
* eglImage
= static_cast<layers::EGLImageImage
*>(srcImage
);
890 return BlitEGLImageImage(eglImage
, yflip
);
898 GLBlitHelper::BlitImageToTexture(layers::Image
* srcImage
,
899 const gfx::IntSize
& destSize
,
908 ScopedGLDrawState
autoStates(mGL
);
911 mGL
->fGenFramebuffers(1, &mFBO
);
913 ScopedBindFramebuffer
boundFB(mGL
, mFBO
);
914 mGL
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
,
915 destTarget
, destTex
, 0);
916 return BlitImageToFramebuffer(srcImage
, destSize
, mFBO
, yflip
, xoffset
, yoffset
,
917 cropWidth
, cropHeight
);
921 GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex
, GLuint destFB
,
922 const gfx::IntSize
& srcSize
,
923 const gfx::IntSize
& destSize
,
927 MOZ_ASSERT(mGL
->fIsTexture(srcTex
));
928 MOZ_ASSERT(!destFB
|| mGL
->fIsFramebuffer(destFB
));
930 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
931 ScopedFramebufferForTexture
srcWrapper(mGL
, srcTex
, srcTarget
);
932 MOZ_ASSERT(srcWrapper
.IsComplete());
934 BlitFramebufferToFramebuffer(srcWrapper
.FB(), destFB
,
943 case LOCAL_GL_TEXTURE_2D
:
946 case LOCAL_GL_TEXTURE_RECTANGLE_ARB
:
950 printf_stderr("Fatal Error: Failed to prepare to blit texture->framebuffer.\n");
955 ScopedGLDrawState
autoStates(mGL
);
957 mGL
->Screen()->BindFB_Internal(destFB
);
962 // Does destructive things to (only!) what we just saved above.
963 bool good
= UseTexQuadProgram(type
, srcSize
);
965 // We're up against the wall, so bail.
966 // This should really be MOZ_CRASH(why) or MOZ_RUNTIME_ASSERT(good).
967 printf_stderr("Fatal Error: Failed to prepare to blit texture->framebuffer.\n");
970 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
974 GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB
, GLuint destTex
,
975 const gfx::IntSize
& srcSize
,
976 const gfx::IntSize
& destSize
,
980 MOZ_ASSERT(!srcFB
|| mGL
->fIsFramebuffer(srcFB
));
981 MOZ_ASSERT(mGL
->fIsTexture(destTex
));
983 if (mGL
->IsSupported(GLFeature::framebuffer_blit
)) {
984 ScopedFramebufferForTexture
destWrapper(mGL
, destTex
, destTarget
);
986 BlitFramebufferToFramebuffer(srcFB
, destWrapper
.FB(),
992 ScopedBindTexture
autoTex(mGL
, destTex
, destTarget
);
994 ScopedBindFramebuffer
boundFB(mGL
);
996 mGL
->Screen()->BindFB_Internal(srcFB
);
1001 ScopedGLState
scissor(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
1002 mGL
->fCopyTexSubImage2D(destTarget
, 0,
1005 srcSize
.width
, srcSize
.height
);
1009 GLBlitHelper::BlitTextureToTexture(GLuint srcTex
, GLuint destTex
,
1010 const gfx::IntSize
& srcSize
,
1011 const gfx::IntSize
& destSize
,
1012 GLenum srcTarget
, GLenum destTarget
)
1014 MOZ_ASSERT(mGL
->fIsTexture(srcTex
));
1015 MOZ_ASSERT(mGL
->fIsTexture(destTex
));
1017 // Generally, just use the CopyTexSubImage path
1018 ScopedFramebufferForTexture
srcWrapper(mGL
, srcTex
, srcTarget
);
1020 BlitFramebufferToTexture(srcWrapper
.FB(), destTex
,
1021 srcSize
, destSize
, destTarget
);
1025 } // namespace mozilla