Bumping manifests a=b2g-bump
[gecko.git] / gfx / gl / GLBlitHelper.cpp
blobfa44819869ad821bd3eb317701d033201027c518
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 #endif
25 using mozilla::layers::PlanarYCbCrImage;
26 using mozilla::layers::PlanarYCbCrData;
28 namespace mozilla {
29 namespace gl {
31 static void
32 RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
33 GLenum aInternalFormat, const gfx::IntSize& aSize)
35 if (aSamples) {
36 aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
37 aSamples,
38 aInternalFormat,
39 aSize.width, aSize.height);
40 } else {
41 aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
42 aInternalFormat,
43 aSize.width, aSize.height);
47 GLuint
48 CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
49 GLenum aType, const gfx::IntSize& aSize, bool linear)
51 GLuint tex = 0;
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
57 : LOCAL_GL_NEAREST);
58 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D,
59 LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR
60 : LOCAL_GL_NEAREST);
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,
68 aInternalFormat,
69 aSize.width, aSize.height,
71 aFormat,
72 aType,
73 nullptr);
75 return tex;
78 GLuint
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,
90 aSize);
94 GLuint
95 CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples,
96 const gfx::IntSize& aSize)
98 GLuint rb = 0;
99 aGL->fGenRenderbuffers(1, &rb);
100 ScopedBindRenderbuffer autoRB(aGL, rb);
102 RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize);
104 return rb;
108 void
109 CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats,
110 const gfx::IntSize& aSize, bool aMultisample,
111 GLuint* aColorMSRB, GLuint* aDepthRB,
112 GLuint* aStencilRB)
114 GLsizei samples = aMultisample ? aFormats.samples : 0;
115 if (aColorMSRB) {
116 MOZ_ASSERT(aFormats.samples > 0);
117 MOZ_ASSERT(aFormats.color_rbFormat);
119 *aColorMSRB = CreateRenderbuffer(aGL, aFormats.color_rbFormat, samples, aSize);
122 if (aDepthRB &&
123 aStencilRB &&
124 aFormats.depthStencil)
126 *aDepthRB = CreateRenderbuffer(aGL, aFormats.depthStencil, samples, aSize);
127 *aStencilRB = *aDepthRB;
128 } else {
129 if (aDepthRB) {
130 MOZ_ASSERT(aFormats.depth);
132 *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize);
135 if (aStencilRB) {
136 MOZ_ASSERT(aFormats.stencil);
138 *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize);
144 GLBlitHelper::GLBlitHelper(GLContext* gl)
145 : mGL(gl)
146 , mTexBlit_Buffer(0)
147 , mTexBlit_VertShader(0)
148 , mTex2DBlit_FragShader(0)
149 , mTex2DRectBlit_FragShader(0)
150 , mTex2DBlit_Program(0)
151 , mTex2DRectBlit_Program(0)
152 , mYFlipLoc(-1)
153 , mTextureTransformLoc(-1)
154 , mTexExternalBlit_FragShader(0)
155 , mTexYUVPlanarBlit_FragShader(0)
156 , mTexExternalBlit_Program(0)
157 , mTexYUVPlanarBlit_Program(0)
158 , mFBO(0)
159 , mSrcTexY(0)
160 , mSrcTexCb(0)
161 , mSrcTexCr(0)
162 , mSrcTexEGL(0)
163 , mYTexScaleLoc(-1)
164 , mCbCrTexScaleLoc(-1)
165 , mTexWidth(0)
166 , mTexHeight(0)
167 , mCurYScale(1.0f)
168 , mCurCbCrScale(1.0f)
172 GLBlitHelper::~GLBlitHelper()
174 DeleteTexBlitProgram();
176 GLuint tex[] = {
177 mSrcTexY,
178 mSrcTexCb,
179 mSrcTexCr,
180 mSrcTexEGL,
183 mSrcTexY = mSrcTexCb = mSrcTexCr = mSrcTexEGL = 0;
184 mGL->fDeleteTextures(ArrayLength(tex), tex);
186 if (mFBO) {
187 mGL->fDeleteFramebuffers(1, &mFBO);
189 mFBO = 0;
192 // Allowed to be destructive of state we restore in functions below.
193 bool
194 GLBlitHelper::InitTexQuadProgram(BlitType target)
196 const char kTexBlit_VertShaderSource[] = "\
197 #ifdef GL_ES \n\
198 precision mediump float; \n\
199 #endif \n\
200 attribute vec2 aPosition; \n\
202 uniform float uYflip; \n\
203 varying vec2 vTexCoord; \n\
205 void main(void) \n\
206 { \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\
211 } \n\
214 const char kTex2DBlit_FragShaderSource[] = "\
215 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
216 precision highp float; \n\
217 #else \n\
218 prevision mediump float; \n\
219 #endif \n\
220 uniform sampler2D uTexUnit; \n\
222 varying vec2 vTexCoord; \n\
224 void main(void) \n\
225 { \n\
226 gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\
227 } \n\
230 const char kTex2DRectBlit_FragShaderSource[] = "\
231 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
232 precision highp float; \n\
233 #else \n\
234 precision mediump float; \n\
235 #endif \n\
237 uniform sampler2D uTexUnit; \n\
238 uniform vec2 uTexCoordMult; \n\
240 varying vec2 vTexCoord; \n\
242 void main(void) \n\
243 { \n\
244 gl_FragColor = texture2DRect(uTexUnit, \n\
245 vTexCoord * uTexCoordMult); \n\
246 } \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\
253 #else \n\
254 precision mediump float; \n\
255 #endif \n\
256 varying vec2 vTexCoord; \n\
257 uniform mat4 uTextureTransform; \n\
258 uniform samplerExternalOES uTexUnit; \n\
260 void main() \n\
261 { \n\
262 gl_FragColor = texture2D(uTexUnit, \n\
263 (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy); \n\
264 } \n\
266 #endif
267 /* From Rec601:
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[] = "\
278 #ifdef GL_ES \n\
279 precision mediump float \n\
280 #endif \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\
287 void main() \n\
288 { \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\
299 } \n\
302 bool success = false;
304 GLuint *programPtr;
305 GLuint *fragShaderPtr;
306 const char* fragShaderSource;
307 switch (target) {
308 case BlitTex2D:
309 programPtr = &mTex2DBlit_Program;
310 fragShaderPtr = &mTex2DBlit_FragShader;
311 fragShaderSource = kTex2DBlit_FragShaderSource;
312 break;
313 case BlitTexRect:
314 programPtr = &mTex2DRectBlit_Program;
315 fragShaderPtr = &mTex2DRectBlit_FragShader;
316 fragShaderSource = kTex2DRectBlit_FragShaderSource;
317 break;
318 #ifdef ANDROID
319 case ConvertSurfaceTexture:
320 case ConvertGralloc:
321 programPtr = &mTexExternalBlit_Program;
322 fragShaderPtr = &mTexExternalBlit_FragShader;
323 fragShaderSource = kTexExternalBlit_FragShaderSource;
324 break;
325 #endif
326 case ConvertPlanarYCbCr:
327 programPtr = &mTexYUVPlanarBlit_Program;
328 fragShaderPtr = &mTexYUVPlanarBlit_FragShader;
329 fragShaderSource = kTexYUVPlanarBlit_FragShaderSource;
330 break;
331 default:
332 return false;
335 GLuint& program = *programPtr;
336 GLuint& fragShader = *fragShaderPtr;
338 // Use do-while(false) to let us break on failure
339 do {
340 if (program) {
341 // Already have it...
342 success = true;
343 break;
346 if (!mTexBlit_Buffer) {
348 /* CCW tri-strip:
349 * 2---3
350 * | \ |
351 * 0---1
353 GLfloat verts[] = {
354 0.0f, 0.0f,
355 1.0f, 0.0f,
356 0.0f, 1.0f,
357 1.0f, 1.0f
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()) {
390 GLint status = 0;
391 mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status);
392 if (status != LOCAL_GL_TRUE) {
393 NS_ERROR("Vert shader compilation failed.");
395 GLint length = 0;
396 mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
397 if (!length) {
398 printf_stderr("No shader info log available.\n");
399 break;
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());
406 break;
409 status = 0;
410 mGL->fGetShaderiv(fragShader, LOCAL_GL_COMPILE_STATUS, &status);
411 if (status != LOCAL_GL_TRUE) {
412 NS_ERROR("Frag shader compilation failed.");
414 GLint length = 0;
415 mGL->fGetShaderiv(fragShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
416 if (!length) {
417 printf_stderr("No shader info log available.\n");
418 break;
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());
425 break;
429 GLint status = 0;
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.");
434 GLint length = 0;
435 mGL->fGetProgramiv(program, LOCAL_GL_INFO_LOG_LENGTH, &length);
436 if (!length) {
437 printf_stderr("No program info log available.\n");
438 break;
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());
446 break;
449 // Cache and set attribute and uniform
450 mGL->fUseProgram(program);
451 switch (target) {
452 case BlitTex2D:
453 case BlitTexRect:
454 case ConvertSurfaceTexture:
455 case ConvertGralloc: {
456 #ifdef ANDROID
457 GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
458 MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
459 mGL->fUniform1i(texUnitLoc, 0);
460 break;
461 #endif
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 &&
471 texCb != -1 &&
472 texCr != -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);
480 break;
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);
492 success = true;
493 } while (false);
495 if (!success) {
496 // Clean up:
497 DeleteTexBlitProgram();
498 return false;
501 mGL->fUseProgram(program);
502 mGL->fEnableVertexAttribArray(0);
503 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
504 mGL->fVertexAttribPointer(0,
506 LOCAL_GL_FLOAT,
507 false,
509 nullptr);
510 return true;
513 bool
514 GLBlitHelper::UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize)
516 if (!InitTexQuadProgram(target)) {
517 return false;
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);
526 return true;
529 void
530 GLBlitHelper::DeleteTexBlitProgram()
532 if (mTexBlit_Buffer) {
533 mGL->fDeleteBuffers(1, &mTexBlit_Buffer);
534 mTexBlit_Buffer = 0;
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;
574 void
575 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
576 const gfx::IntSize& srcSize,
577 const gfx::IntSize& destSize,
578 bool internalFBs)
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);
588 if (internalFBs) {
589 mGL->Screen()->BindReadFB_Internal(srcFB);
590 mGL->Screen()->BindDrawFB_Internal(destFB);
591 } else {
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,
599 LOCAL_GL_NEAREST);
602 void
603 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
604 const gfx::IntSize& srcSize,
605 const gfx::IntSize& destSize,
606 const GLFormats& srcFormats,
607 bool internalFBs)
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,
614 srcSize, destSize,
615 internalFBs);
616 return;
619 GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize);
620 MOZ_ASSERT(tex);
622 BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize, internalFBs);
623 BlitTextureToFramebuffer(tex, destFB, srcSize, destSize, internalFBs);
625 mGL->fDeleteTextures(1, &tex);
628 void
629 GLBlitHelper::BindAndUploadYUVTexture(Channel which,
630 uint32_t width,
631 uint32_t height,
632 void* data,
633 bool needsAllocation)
635 MOZ_ASSERT(which < Channel_Max, "Invalid channel!");
636 GLuint* srcTexArr[3] = {&mSrcTexY, &mSrcTexCb, &mSrcTexCr};
637 GLuint& tex = *srcTexArr[which];
638 if (!tex) {
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,
651 width,
652 height,
653 LOCAL_GL_LUMINANCE,
654 LOCAL_GL_UNSIGNED_BYTE,
655 data);
656 } else {
657 mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
659 LOCAL_GL_LUMINANCE,
660 width,
661 height,
663 LOCAL_GL_LUMINANCE,
664 LOCAL_GL_UNSIGNED_BYTE,
665 data);
669 #ifdef MOZ_WIDGET_GONK
670 void
671 GLBlitHelper::BindAndUploadExternalTexture(EGLImage image)
673 MOZ_ASSERT(image != EGL_NO_IMAGE, "Bad EGLImage");
675 if (!mSrcTexEGL) {
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);
682 } else {
683 mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, mSrcTexEGL);
685 mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL_OES, image);
688 bool
689 GLBlitHelper::BlitGrallocImage(layers::GrallocImage* grallocImage, bool yFlip)
691 ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
692 mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
694 EGLint attrs[] = {
695 LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE,
696 LOCAL_EGL_NONE, LOCAL_EGL_NONE
698 EGLImage image = sEGLLibrary.fCreateImage(sEGLLibrary.Display(),
699 EGL_NO_CONTEXT,
700 LOCAL_EGL_NATIVE_BUFFER_ANDROID,
701 grallocImage->GetNativeBuffer(), attrs);
702 if (image == EGL_NO_IMAGE)
703 return false;
705 int oldBinding = 0;
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);
716 return true;
718 #endif
720 #ifdef MOZ_WIDGET_ANDROID
722 bool
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))) {
732 return false;
735 // UpdateTexImage() changes the EXTERNAL binding, so save it here
736 // so we can restore it after.
737 int oldBinding = 0;
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);
752 return true;
754 #endif
756 bool
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;
769 GLint oldTex[3];
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]);
790 return true;
793 bool
794 GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
795 const gfx::IntSize& destSize,
796 GLuint destFB,
797 bool yFlip,
798 GLuint xoffset,
799 GLuint yoffset,
800 GLuint cropWidth,
801 GLuint cropHeight)
803 ScopedGLDrawState autoStates(mGL);
805 BlitType type;
806 switch (srcImage->GetFormat()) {
807 case ImageFormat::PLANAR_YCBCR:
808 type = ConvertPlanarYCbCr;
809 break;
810 case ImageFormat::GRALLOC_PLANAR_YCBCR:
811 #ifdef MOZ_WIDGET_GONK
812 type = ConvertGralloc;
813 break;
814 #endif
815 #ifdef MOZ_WIDGET_ANDROID
816 case ImageFormat::SURFACE_TEXTURE:
817 type = ConvertSurfaceTexture;
818 break;
819 #endif
820 default:
821 return false;
824 bool init = InitTexQuadProgram(type);
825 if (!init) {
826 return false;
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);
842 #endif
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);
853 #endif
855 return false;
858 bool
859 GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
860 const gfx::IntSize& destSize,
861 GLuint destTex,
862 GLenum destTarget,
863 bool yFlip,
864 GLuint xoffset,
865 GLuint yoffset,
866 GLuint cropWidth,
867 GLuint cropHeight)
869 ScopedGLDrawState autoStates(mGL);
871 if (!mFBO) {
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);
881 void
882 GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
883 const gfx::IntSize& srcSize,
884 const gfx::IntSize& destSize,
885 GLenum srcTarget,
886 bool internalFBs)
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,
896 srcSize, destSize,
897 internalFBs);
898 return;
901 BlitType type;
902 switch (srcTarget)
904 case LOCAL_GL_TEXTURE_2D:
905 type = BlitTex2D;
906 break;
907 case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
908 type = BlitTexRect;
909 break;
910 default:
911 printf_stderr("Fatal Error: Failed to prepare to blit texture->framebuffer.\n");
912 MOZ_CRASH();
913 break;
916 ScopedGLDrawState autoStates(mGL);
917 if (internalFBs) {
918 mGL->Screen()->BindFB_Internal(destFB);
919 } else {
920 mGL->BindFB(destFB);
923 // Does destructive things to (only!) what we just saved above.
924 bool good = UseTexQuadProgram(type, srcSize);
925 if (!good) {
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");
929 MOZ_CRASH();
931 mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
934 void
935 GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
936 const gfx::IntSize& srcSize,
937 const gfx::IntSize& destSize,
938 GLenum destTarget,
939 bool internalFBs)
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(),
948 srcSize, destSize,
949 internalFBs);
950 return;
953 ScopedBindTexture autoTex(mGL, destTex, destTarget);
955 ScopedBindFramebuffer boundFB(mGL);
956 if (internalFBs) {
957 mGL->Screen()->BindFB_Internal(srcFB);
958 } else {
959 mGL->BindFB(srcFB);
962 ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
963 mGL->fCopyTexSubImage2D(destTarget, 0,
964 0, 0,
965 0, 0,
966 srcSize.width, srcSize.height);
969 void
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);