Bumping gaia.json for 2 gaia revision(s) a=gaia-bump
[gecko.git] / gfx / gl / GLBlitHelper.cpp
blobb3208d4eb60d8c0fcfcc95bb07ad8cb5d118b9c9
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"
8 #include "GLContext.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"
18 #endif
20 #ifdef MOZ_WIDGET_ANDROID
21 #include "AndroidSurfaceTexture.h"
22 #include "GLImages.h"
23 #include "GLLibraryEGL.h"
24 #endif
26 using mozilla::layers::PlanarYCbCrImage;
27 using mozilla::layers::PlanarYCbCrData;
29 namespace mozilla {
30 namespace gl {
32 static void
33 RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
34 GLenum aInternalFormat, const gfx::IntSize& aSize)
36 if (aSamples) {
37 aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
38 aSamples,
39 aInternalFormat,
40 aSize.width, aSize.height);
41 } else {
42 aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
43 aInternalFormat,
44 aSize.width, aSize.height);
48 GLuint
49 CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
50 GLenum aType, const gfx::IntSize& aSize, bool linear)
52 GLuint tex = 0;
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
58 : LOCAL_GL_NEAREST);
59 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D,
60 LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR
61 : LOCAL_GL_NEAREST);
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,
69 aInternalFormat,
70 aSize.width, aSize.height,
72 aFormat,
73 aType,
74 nullptr);
76 return tex;
79 GLuint
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,
91 aSize);
95 GLuint
96 CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples,
97 const gfx::IntSize& aSize)
99 GLuint rb = 0;
100 aGL->fGenRenderbuffers(1, &rb);
101 ScopedBindRenderbuffer autoRB(aGL, rb);
103 RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize);
105 return rb;
109 void
110 CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats,
111 const gfx::IntSize& aSize, bool aMultisample,
112 GLuint* aColorMSRB, GLuint* aDepthRB,
113 GLuint* aStencilRB)
115 GLsizei samples = aMultisample ? aFormats.samples : 0;
116 if (aColorMSRB) {
117 MOZ_ASSERT(aFormats.samples > 0);
118 MOZ_ASSERT(aFormats.color_rbFormat);
120 *aColorMSRB = CreateRenderbuffer(aGL, aFormats.color_rbFormat, samples, aSize);
123 if (aDepthRB &&
124 aStencilRB &&
125 aFormats.depthStencil)
127 *aDepthRB = CreateRenderbuffer(aGL, aFormats.depthStencil, samples, aSize);
128 *aStencilRB = *aDepthRB;
129 } else {
130 if (aDepthRB) {
131 MOZ_ASSERT(aFormats.depth);
133 *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize);
136 if (aStencilRB) {
137 MOZ_ASSERT(aFormats.stencil);
139 *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize);
145 GLBlitHelper::GLBlitHelper(GLContext* gl)
146 : mGL(gl)
147 , mTexBlit_Buffer(0)
148 , mTexBlit_VertShader(0)
149 , mTex2DBlit_FragShader(0)
150 , mTex2DRectBlit_FragShader(0)
151 , mTex2DBlit_Program(0)
152 , mTex2DRectBlit_Program(0)
153 , mYFlipLoc(-1)
154 , mTextureTransformLoc(-1)
155 , mTexExternalBlit_FragShader(0)
156 , mTexYUVPlanarBlit_FragShader(0)
157 , mTexExternalBlit_Program(0)
158 , mTexYUVPlanarBlit_Program(0)
159 , mFBO(0)
160 , mSrcTexY(0)
161 , mSrcTexCb(0)
162 , mSrcTexCr(0)
163 , mSrcTexEGL(0)
164 , mYTexScaleLoc(-1)
165 , mCbCrTexScaleLoc(-1)
166 , mTexWidth(0)
167 , mTexHeight(0)
168 , mCurYScale(1.0f)
169 , mCurCbCrScale(1.0f)
173 GLBlitHelper::~GLBlitHelper()
175 DeleteTexBlitProgram();
177 GLuint tex[] = {
178 mSrcTexY,
179 mSrcTexCb,
180 mSrcTexCr,
181 mSrcTexEGL,
184 mSrcTexY = mSrcTexCb = mSrcTexCr = mSrcTexEGL = 0;
185 mGL->fDeleteTextures(ArrayLength(tex), tex);
187 if (mFBO) {
188 mGL->fDeleteFramebuffers(1, &mFBO);
190 mFBO = 0;
193 // Allowed to be destructive of state we restore in functions below.
194 bool
195 GLBlitHelper::InitTexQuadProgram(BlitType target)
197 const char kTexBlit_VertShaderSource[] = "\
198 #ifdef GL_ES \n\
199 precision mediump float; \n\
200 #endif \n\
201 attribute vec2 aPosition; \n\
203 uniform float uYflip; \n\
204 varying vec2 vTexCoord; \n\
206 void main(void) \n\
207 { \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\
212 } \n\
215 const char kTex2DBlit_FragShaderSource[] = "\
216 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
217 precision highp float; \n\
218 #else \n\
219 prevision mediump float; \n\
220 #endif \n\
221 uniform sampler2D uTexUnit; \n\
223 varying vec2 vTexCoord; \n\
225 void main(void) \n\
226 { \n\
227 gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\
228 } \n\
231 const char kTex2DRectBlit_FragShaderSource[] = "\
232 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
233 precision highp float; \n\
234 #else \n\
235 precision mediump float; \n\
236 #endif \n\
238 uniform sampler2D uTexUnit; \n\
239 uniform vec2 uTexCoordMult; \n\
241 varying vec2 vTexCoord; \n\
243 void main(void) \n\
244 { \n\
245 gl_FragColor = texture2DRect(uTexUnit, \n\
246 vTexCoord * uTexCoordMult); \n\
247 } \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\
254 #else \n\
255 precision mediump float; \n\
256 #endif \n\
257 varying vec2 vTexCoord; \n\
258 uniform mat4 uTextureTransform; \n\
259 uniform samplerExternalOES uTexUnit; \n\
261 void main() \n\
262 { \n\
263 gl_FragColor = texture2D(uTexUnit, \n\
264 (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy); \n\
265 } \n\
267 #endif
268 /* From Rec601:
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[] = "\
279 #ifdef GL_ES \n\
280 precision mediump float \n\
281 #endif \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\
288 void main() \n\
289 { \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\
300 } \n\
303 bool success = false;
305 GLuint *programPtr;
306 GLuint *fragShaderPtr;
307 const char* fragShaderSource;
308 switch (target) {
309 case ConvertEGLImage:
310 case BlitTex2D:
311 programPtr = &mTex2DBlit_Program;
312 fragShaderPtr = &mTex2DBlit_FragShader;
313 fragShaderSource = kTex2DBlit_FragShaderSource;
314 break;
315 case BlitTexRect:
316 programPtr = &mTex2DRectBlit_Program;
317 fragShaderPtr = &mTex2DRectBlit_FragShader;
318 fragShaderSource = kTex2DRectBlit_FragShaderSource;
319 break;
320 #ifdef ANDROID
321 case ConvertSurfaceTexture:
322 case ConvertGralloc:
323 programPtr = &mTexExternalBlit_Program;
324 fragShaderPtr = &mTexExternalBlit_FragShader;
325 fragShaderSource = kTexExternalBlit_FragShaderSource;
326 break;
327 #endif
328 case ConvertPlanarYCbCr:
329 programPtr = &mTexYUVPlanarBlit_Program;
330 fragShaderPtr = &mTexYUVPlanarBlit_FragShader;
331 fragShaderSource = kTexYUVPlanarBlit_FragShaderSource;
332 break;
333 default:
334 return false;
337 GLuint& program = *programPtr;
338 GLuint& fragShader = *fragShaderPtr;
340 // Use do-while(false) to let us break on failure
341 do {
342 if (program) {
343 // Already have it...
344 success = true;
345 break;
348 if (!mTexBlit_Buffer) {
350 /* CCW tri-strip:
351 * 2---3
352 * | \ |
353 * 0---1
355 GLfloat verts[] = {
356 0.0f, 0.0f,
357 1.0f, 0.0f,
358 0.0f, 1.0f,
359 1.0f, 1.0f
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()) {
392 GLint status = 0;
393 mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status);
394 if (status != LOCAL_GL_TRUE) {
395 NS_ERROR("Vert shader compilation failed.");
397 GLint length = 0;
398 mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
399 if (!length) {
400 printf_stderr("No shader info log available.\n");
401 break;
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());
408 break;
411 status = 0;
412 mGL->fGetShaderiv(fragShader, LOCAL_GL_COMPILE_STATUS, &status);
413 if (status != LOCAL_GL_TRUE) {
414 NS_ERROR("Frag shader compilation failed.");
416 GLint length = 0;
417 mGL->fGetShaderiv(fragShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
418 if (!length) {
419 printf_stderr("No shader info log available.\n");
420 break;
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());
427 break;
431 GLint status = 0;
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.");
436 GLint length = 0;
437 mGL->fGetProgramiv(program, LOCAL_GL_INFO_LOG_LENGTH, &length);
438 if (!length) {
439 printf_stderr("No program info log available.\n");
440 break;
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());
448 break;
451 // Cache and set attribute and uniform
452 mGL->fUseProgram(program);
453 switch (target) {
454 case BlitTex2D:
455 case BlitTexRect:
456 case ConvertEGLImage:
457 case ConvertSurfaceTexture:
458 case ConvertGralloc: {
459 #ifdef ANDROID
460 GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
461 MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
462 mGL->fUniform1i(texUnitLoc, 0);
463 break;
464 #endif
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 &&
474 texCb != -1 &&
475 texCr != -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);
483 break;
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);
495 success = true;
496 } while (false);
498 if (!success) {
499 // Clean up:
500 DeleteTexBlitProgram();
501 return false;
504 mGL->fUseProgram(program);
505 mGL->fEnableVertexAttribArray(0);
506 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
507 mGL->fVertexAttribPointer(0,
509 LOCAL_GL_FLOAT,
510 false,
512 nullptr);
513 return true;
516 bool
517 GLBlitHelper::UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize)
519 if (!InitTexQuadProgram(target)) {
520 return false;
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);
529 return true;
532 void
533 GLBlitHelper::DeleteTexBlitProgram()
535 if (mTexBlit_Buffer) {
536 mGL->fDeleteBuffers(1, &mTexBlit_Buffer);
537 mTexBlit_Buffer = 0;
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;
577 void
578 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
579 const gfx::IntSize& srcSize,
580 const gfx::IntSize& destSize,
581 bool internalFBs)
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);
591 if (internalFBs) {
592 mGL->Screen()->BindReadFB_Internal(srcFB);
593 mGL->Screen()->BindDrawFB_Internal(destFB);
594 } else {
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,
602 LOCAL_GL_NEAREST);
605 void
606 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
607 const gfx::IntSize& srcSize,
608 const gfx::IntSize& destSize,
609 const GLFormats& srcFormats,
610 bool internalFBs)
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,
617 srcSize, destSize,
618 internalFBs);
619 return;
622 GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize);
623 MOZ_ASSERT(tex);
625 BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize, internalFBs);
626 BlitTextureToFramebuffer(tex, destFB, srcSize, destSize, internalFBs);
628 mGL->fDeleteTextures(1, &tex);
631 void
632 GLBlitHelper::BindAndUploadYUVTexture(Channel which,
633 uint32_t width,
634 uint32_t height,
635 void* data,
636 bool needsAllocation)
638 MOZ_ASSERT(which < Channel_Max, "Invalid channel!");
639 GLuint* srcTexArr[3] = {&mSrcTexY, &mSrcTexCb, &mSrcTexCr};
640 GLuint& tex = *srcTexArr[which];
641 if (!tex) {
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,
654 width,
655 height,
656 LOCAL_GL_LUMINANCE,
657 LOCAL_GL_UNSIGNED_BYTE,
658 data);
659 } else {
660 mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
662 LOCAL_GL_LUMINANCE,
663 width,
664 height,
666 LOCAL_GL_LUMINANCE,
667 LOCAL_GL_UNSIGNED_BYTE,
668 data);
672 void
673 GLBlitHelper::BindAndUploadEGLImage(EGLImage image, GLuint target)
675 MOZ_ASSERT(image != EGL_NO_IMAGE, "Bad EGLImage");
677 if (!mSrcTexEGL) {
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);
684 } else {
685 mGL->fBindTexture(target, mSrcTexEGL);
687 mGL->fEGLImageTargetTexture2D(target, image);
690 #ifdef MOZ_WIDGET_GONK
692 bool
693 GLBlitHelper::BlitGrallocImage(layers::GrallocImage* grallocImage, bool yflip)
695 ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
696 mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
698 EGLint attrs[] = {
699 LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE,
700 LOCAL_EGL_NONE, LOCAL_EGL_NONE
702 EGLImage image = sEGLLibrary.fCreateImage(sEGLLibrary.Display(),
703 EGL_NO_CONTEXT,
704 LOCAL_EGL_NATIVE_BUFFER_ANDROID,
705 grallocImage->GetNativeBuffer(), attrs);
706 if (image == EGL_NO_IMAGE)
707 return false;
709 int oldBinding = 0;
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);
720 return true;
722 #endif
724 #ifdef MOZ_WIDGET_ANDROID
726 #define ATTACH_WAIT_MS 50
728 bool
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))))
736 return false;
738 // UpdateTexImage() changes the EXTERNAL binding, so save it here
739 // so we can restore it after.
740 int oldBinding = 0;
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);
755 return true;
758 bool
759 GLBlitHelper::BlitEGLImageImage(layers::EGLImageImage* image, bool yflip)
761 EGLImage eglImage = image->GetData()->mImage;
762 EGLSync eglSync = image->GetData()->mSync;
764 if (eglSync) {
765 EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), eglSync, 0, LOCAL_EGL_FOREVER);
766 if (status != LOCAL_EGL_CONDITION_SATISFIED) {
767 return false;
771 ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
773 int oldBinding = 0;
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);
783 return true;
786 #endif
788 bool
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;
801 GLint oldTex[3];
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]);
822 return true;
825 bool
826 GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
827 const gfx::IntSize& destSize,
828 GLuint destFB,
829 bool yflip,
830 GLuint xoffset,
831 GLuint yoffset,
832 GLuint cropWidth,
833 GLuint cropHeight)
835 ScopedGLDrawState autoStates(mGL);
837 BlitType type;
838 switch (srcImage->GetFormat()) {
839 case ImageFormat::PLANAR_YCBCR:
840 type = ConvertPlanarYCbCr;
841 break;
842 case ImageFormat::GRALLOC_PLANAR_YCBCR:
843 #ifdef MOZ_WIDGET_GONK
844 type = ConvertGralloc;
845 break;
846 #endif
847 #ifdef MOZ_WIDGET_ANDROID
848 case ImageFormat::SURFACE_TEXTURE:
849 type = ConvertSurfaceTexture;
850 break;
851 case ImageFormat::EGLIMAGE:
852 type = ConvertEGLImage;
853 break;
854 #endif
855 default:
856 return false;
859 bool init = InitTexQuadProgram(type);
860 if (!init) {
861 return false;
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);
877 #endif
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);
892 #endif
894 return false;
897 bool
898 GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
899 const gfx::IntSize& destSize,
900 GLuint destTex,
901 GLenum destTarget,
902 bool yflip,
903 GLuint xoffset,
904 GLuint yoffset,
905 GLuint cropWidth,
906 GLuint cropHeight)
908 ScopedGLDrawState autoStates(mGL);
910 if (!mFBO)
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);
920 void
921 GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
922 const gfx::IntSize& srcSize,
923 const gfx::IntSize& destSize,
924 GLenum srcTarget,
925 bool internalFBs)
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,
935 srcSize, destSize,
936 internalFBs);
937 return;
940 BlitType type;
941 switch (srcTarget)
943 case LOCAL_GL_TEXTURE_2D:
944 type = BlitTex2D;
945 break;
946 case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
947 type = BlitTexRect;
948 break;
949 default:
950 printf_stderr("Fatal Error: Failed to prepare to blit texture->framebuffer.\n");
951 MOZ_CRASH();
952 break;
955 ScopedGLDrawState autoStates(mGL);
956 if (internalFBs) {
957 mGL->Screen()->BindFB_Internal(destFB);
958 } else {
959 mGL->BindFB(destFB);
962 // Does destructive things to (only!) what we just saved above.
963 bool good = UseTexQuadProgram(type, srcSize);
964 if (!good) {
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");
968 MOZ_CRASH();
970 mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
973 void
974 GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
975 const gfx::IntSize& srcSize,
976 const gfx::IntSize& destSize,
977 GLenum destTarget,
978 bool internalFBs)
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(),
987 srcSize, destSize,
988 internalFBs);
989 return;
992 ScopedBindTexture autoTex(mGL, destTex, destTarget);
994 ScopedBindFramebuffer boundFB(mGL);
995 if (internalFBs) {
996 mGL->Screen()->BindFB_Internal(srcFB);
997 } else {
998 mGL->BindFB(srcFB);
1001 ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
1002 mGL->fCopyTexSubImage2D(destTarget, 0,
1003 0, 0,
1004 0, 0,
1005 srcSize.width, srcSize.height);
1008 void
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);
1024 } // namespace gl
1025 } // namespace mozilla