Line data Source code
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/. */
6 :
7 : #include "gfxUtils.h"
8 : #include "GLBlitHelper.h"
9 : #include "GLContext.h"
10 : #include "GLScreenBuffer.h"
11 : #include "ScopedGLHelpers.h"
12 : #include "mozilla/Preferences.h"
13 : #include "ImageContainer.h"
14 : #include "HeapCopyOfStackArray.h"
15 : #include "mozilla/gfx/Matrix.h"
16 : #include "mozilla/UniquePtr.h"
17 :
18 : #ifdef MOZ_WIDGET_ANDROID
19 : #include "AndroidSurfaceTexture.h"
20 : #include "GLImages.h"
21 : #include "GLLibraryEGL.h"
22 : #endif
23 :
24 : #ifdef XP_MACOSX
25 : #include "MacIOSurfaceImage.h"
26 : #include "GLContextCGL.h"
27 : #endif
28 :
29 : using mozilla::layers::PlanarYCbCrImage;
30 : using mozilla::layers::PlanarYCbCrData;
31 :
32 : namespace mozilla {
33 : namespace gl {
34 :
35 0 : GLBlitHelper::GLBlitHelper(GLContext* gl)
36 : : mGL(gl)
37 : , mTexBlit_Buffer(0)
38 : , mTexBlit_VertShader(0)
39 : , mTex2DBlit_FragShader(0)
40 : , mTex2DRectBlit_FragShader(0)
41 : , mTex2DBlit_Program(0)
42 : , mTex2DRectBlit_Program(0)
43 : , mYFlipLoc(-1)
44 : , mTextureTransformLoc(-1)
45 : , mTexExternalBlit_FragShader(0)
46 : , mTexYUVPlanarBlit_FragShader(0)
47 : , mTexNV12PlanarBlit_FragShader(0)
48 : , mTexExternalBlit_Program(0)
49 : , mTexYUVPlanarBlit_Program(0)
50 : , mTexNV12PlanarBlit_Program(0)
51 : , mFBO(0)
52 : , mSrcTexY(0)
53 : , mSrcTexCb(0)
54 : , mSrcTexCr(0)
55 : , mSrcTexEGL(0)
56 : , mYTexScaleLoc(-1)
57 : , mCbCrTexScaleLoc(-1)
58 : , mYuvColorMatrixLoc(-1)
59 : , mTexWidth(0)
60 : , mTexHeight(0)
61 : , mCurYScale(1.0f)
62 0 : , mCurCbCrScale(1.0f)
63 : {
64 0 : }
65 :
66 0 : GLBlitHelper::~GLBlitHelper()
67 : {
68 0 : if (!mGL->MakeCurrent())
69 0 : return;
70 :
71 0 : DeleteTexBlitProgram();
72 :
73 : GLuint tex[] = {
74 0 : mSrcTexY,
75 0 : mSrcTexCb,
76 0 : mSrcTexCr,
77 0 : mSrcTexEGL,
78 0 : };
79 :
80 0 : mSrcTexY = mSrcTexCb = mSrcTexCr = mSrcTexEGL = 0;
81 0 : mGL->fDeleteTextures(ArrayLength(tex), tex);
82 :
83 0 : if (mFBO) {
84 0 : mGL->fDeleteFramebuffers(1, &mFBO);
85 : }
86 0 : mFBO = 0;
87 0 : }
88 :
89 : // Allowed to be destructive of state we restore in functions below.
90 : bool
91 0 : GLBlitHelper::InitTexQuadProgram(BlitType target)
92 : {
93 0 : const char kTexBlit_VertShaderSource[] = "\
94 : #version 100 \n\
95 : #ifdef GL_ES \n\
96 : precision mediump float; \n\
97 : #endif \n\
98 : attribute vec2 aPosition; \n\
99 : \n\
100 : uniform float uYflip; \n\
101 : varying vec2 vTexCoord; \n\
102 : \n\
103 : void main(void) \n\
104 : { \n\
105 : vTexCoord = aPosition; \n\
106 : vTexCoord.y = abs(vTexCoord.y - uYflip); \n\
107 : vec2 vertPos = aPosition * 2.0 - 1.0; \n\
108 : gl_Position = vec4(vertPos, 0.0, 1.0); \n\
109 : } \n\
110 : ";
111 :
112 0 : const char kTex2DBlit_FragShaderSource[] = "\
113 : #version 100 \n\
114 : #ifdef GL_ES \n\
115 : #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
116 : precision highp float; \n\
117 : #else \n\
118 : precision mediump float; \n\
119 : #endif \n\
120 : #endif \n\
121 : uniform sampler2D uTexUnit; \n\
122 : \n\
123 : varying vec2 vTexCoord; \n\
124 : \n\
125 : void main(void) \n\
126 : { \n\
127 : gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\
128 : } \n\
129 : ";
130 :
131 0 : const char kTex2DRectBlit_FragShaderSource[] = "\
132 : #version 100 \n\
133 : #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
134 : precision highp float; \n\
135 : #else \n\
136 : precision mediump float; \n\
137 : #endif \n\
138 : \n\
139 : uniform sampler2D uTexUnit; \n\
140 : uniform vec2 uTexCoordMult; \n\
141 : \n\
142 : varying vec2 vTexCoord; \n\
143 : \n\
144 : void main(void) \n\
145 : { \n\
146 : gl_FragColor = texture2DRect(uTexUnit, \n\
147 : vTexCoord * uTexCoordMult); \n\
148 : } \n\
149 : ";
150 : #ifdef ANDROID /* MOZ_WIDGET_ANDROID */
151 : const char kTexExternalBlit_FragShaderSource[] = "\
152 : #version 100 \n\
153 : #extension GL_OES_EGL_image_external : require \n\
154 : #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
155 : precision highp float; \n\
156 : #else \n\
157 : precision mediump float; \n\
158 : #endif \n\
159 : varying vec2 vTexCoord; \n\
160 : uniform mat4 uTextureTransform; \n\
161 : uniform samplerExternalOES uTexUnit; \n\
162 : \n\
163 : void main() \n\
164 : { \n\
165 : gl_FragColor = texture2D(uTexUnit, \n\
166 : (uTextureTransform * vec4(vTexCoord, 0.0, 1.0)).xy); \n\
167 : } \n\
168 : ";
169 : #endif
170 : /* From Rec601:
171 : [R] [1.1643835616438356, 0.0, 1.5960267857142858] [ Y - 16]
172 : [G] = [1.1643835616438358, -0.3917622900949137, -0.8129676472377708] x [Cb - 128]
173 : [B] [1.1643835616438356, 2.017232142857143, 8.862867620416422e-17] [Cr - 128]
174 :
175 : For [0,1] instead of [0,255], and to 5 places:
176 : [R] [1.16438, 0.00000, 1.59603] [ Y - 0.06275]
177 : [G] = [1.16438, -0.39176, -0.81297] x [Cb - 0.50196]
178 : [B] [1.16438, 2.01723, 0.00000] [Cr - 0.50196]
179 :
180 : From Rec709:
181 : [R] [1.1643835616438356, 4.2781193979771426e-17, 1.7927410714285714] [ Y - 16]
182 : [G] = [1.1643835616438358, -0.21324861427372963, -0.532909328559444] x [Cb - 128]
183 : [B] [1.1643835616438356, 2.1124017857142854, 0.0] [Cr - 128]
184 :
185 : For [0,1] instead of [0,255], and to 5 places:
186 : [R] [1.16438, 0.00000, 1.79274] [ Y - 0.06275]
187 : [G] = [1.16438, -0.21325, -0.53291] x [Cb - 0.50196]
188 : [B] [1.16438, 2.11240, 0.00000] [Cr - 0.50196]
189 : */
190 0 : const char kTexYUVPlanarBlit_FragShaderSource[] = "\
191 : #version 100 \n\
192 : #ifdef GL_ES \n\
193 : precision mediump float; \n\
194 : #endif \n\
195 : varying vec2 vTexCoord; \n\
196 : uniform sampler2D uYTexture; \n\
197 : uniform sampler2D uCbTexture; \n\
198 : uniform sampler2D uCrTexture; \n\
199 : uniform vec2 uYTexScale; \n\
200 : uniform vec2 uCbCrTexScale; \n\
201 : uniform mat3 uYuvColorMatrix; \n\
202 : void main() \n\
203 : { \n\
204 : float y = texture2D(uYTexture, vTexCoord * uYTexScale).r; \n\
205 : float cb = texture2D(uCbTexture, vTexCoord * uCbCrTexScale).r; \n\
206 : float cr = texture2D(uCrTexture, vTexCoord * uCbCrTexScale).r; \n\
207 : y = y - 0.06275; \n\
208 : cb = cb - 0.50196; \n\
209 : cr = cr - 0.50196; \n\
210 : vec3 yuv = vec3(y, cb, cr); \n\
211 : gl_FragColor.rgb = uYuvColorMatrix * yuv; \n\
212 : gl_FragColor.a = 1.0; \n\
213 : } \n\
214 : ";
215 :
216 : #ifdef XP_MACOSX
217 : const char kTexNV12PlanarBlit_FragShaderSource[] = "\
218 : #version 100 \n\
219 : #extension GL_ARB_texture_rectangle : require \n\
220 : #ifdef GL_ES \n\
221 : precision mediump float \n\
222 : #endif \n\
223 : varying vec2 vTexCoord; \n\
224 : uniform sampler2DRect uYTexture; \n\
225 : uniform sampler2DRect uCbCrTexture; \n\
226 : uniform vec2 uYTexScale; \n\
227 : uniform vec2 uCbCrTexScale; \n\
228 : void main() \n\
229 : { \n\
230 : float y = texture2DRect(uYTexture, vTexCoord * uYTexScale).r; \n\
231 : float cb = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).r; \n\
232 : float cr = texture2DRect(uCbCrTexture, vTexCoord * uCbCrTexScale).a; \n\
233 : y = (y - 0.06275) * 1.16438; \n\
234 : cb = cb - 0.50196; \n\
235 : cr = cr - 0.50196; \n\
236 : gl_FragColor.r = y + cr * 1.59603; \n\
237 : gl_FragColor.g = y - 0.81297 * cr - 0.39176 * cb; \n\
238 : gl_FragColor.b = y + cb * 2.01723; \n\
239 : gl_FragColor.a = 1.0; \n\
240 : } \n\
241 : ";
242 : #endif
243 :
244 0 : bool success = false;
245 :
246 : GLuint* programPtr;
247 : GLuint* fragShaderPtr;
248 : const char* fragShaderSource;
249 0 : switch (target) {
250 : case ConvertEGLImage:
251 : case BlitTex2D:
252 0 : programPtr = &mTex2DBlit_Program;
253 0 : fragShaderPtr = &mTex2DBlit_FragShader;
254 0 : fragShaderSource = kTex2DBlit_FragShaderSource;
255 0 : break;
256 : case BlitTexRect:
257 0 : programPtr = &mTex2DRectBlit_Program;
258 0 : fragShaderPtr = &mTex2DRectBlit_FragShader;
259 0 : fragShaderSource = kTex2DRectBlit_FragShaderSource;
260 0 : break;
261 : #ifdef ANDROID
262 : case ConvertSurfaceTexture:
263 : programPtr = &mTexExternalBlit_Program;
264 : fragShaderPtr = &mTexExternalBlit_FragShader;
265 : fragShaderSource = kTexExternalBlit_FragShaderSource;
266 : break;
267 : #endif
268 : case ConvertPlanarYCbCr:
269 0 : programPtr = &mTexYUVPlanarBlit_Program;
270 0 : fragShaderPtr = &mTexYUVPlanarBlit_FragShader;
271 0 : fragShaderSource = kTexYUVPlanarBlit_FragShaderSource;
272 0 : break;
273 : #ifdef XP_MACOSX
274 : case ConvertMacIOSurfaceImage:
275 : programPtr = &mTexNV12PlanarBlit_Program;
276 : fragShaderPtr = &mTexNV12PlanarBlit_FragShader;
277 : fragShaderSource = kTexNV12PlanarBlit_FragShaderSource;
278 : break;
279 : #endif
280 : default:
281 0 : return false;
282 : }
283 :
284 0 : GLuint& program = *programPtr;
285 0 : GLuint& fragShader = *fragShaderPtr;
286 :
287 : // Use do-while(false) to let us break on failure
288 : do {
289 0 : if (program) {
290 : // Already have it...
291 0 : success = true;
292 0 : break;
293 : }
294 :
295 0 : if (!mTexBlit_Buffer) {
296 :
297 : /* CCW tri-strip:
298 : * 2---3
299 : * | \ |
300 : * 0---1
301 : */
302 : GLfloat verts[] = {
303 : 0.0f, 0.0f,
304 : 1.0f, 0.0f,
305 : 0.0f, 1.0f,
306 : 1.0f, 1.0f
307 0 : };
308 0 : HeapCopyOfStackArray<GLfloat> vertsOnHeap(verts);
309 :
310 0 : MOZ_ASSERT(!mTexBlit_Buffer);
311 0 : mGL->fGenBuffers(1, &mTexBlit_Buffer);
312 0 : mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
313 :
314 : // Make sure we have a sane size.
315 0 : mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, vertsOnHeap.ByteLength(), vertsOnHeap.Data(), LOCAL_GL_STATIC_DRAW);
316 : }
317 :
318 0 : if (!mTexBlit_VertShader) {
319 :
320 0 : const char* vertShaderSource = kTexBlit_VertShaderSource;
321 :
322 0 : mTexBlit_VertShader = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER);
323 0 : mGL->fShaderSource(mTexBlit_VertShader, 1, &vertShaderSource, nullptr);
324 0 : mGL->fCompileShader(mTexBlit_VertShader);
325 : }
326 :
327 0 : MOZ_ASSERT(!fragShader);
328 0 : fragShader = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
329 0 : mGL->fShaderSource(fragShader, 1, &fragShaderSource, nullptr);
330 0 : mGL->fCompileShader(fragShader);
331 :
332 0 : program = mGL->fCreateProgram();
333 0 : mGL->fAttachShader(program, mTexBlit_VertShader);
334 0 : mGL->fAttachShader(program, fragShader);
335 0 : mGL->fBindAttribLocation(program, 0, "aPosition");
336 0 : mGL->fLinkProgram(program);
337 :
338 0 : if (GLContext::ShouldSpew()) {
339 0 : GLint status = 0;
340 0 : mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status);
341 0 : if (status != LOCAL_GL_TRUE) {
342 0 : NS_ERROR("Vert shader compilation failed.");
343 :
344 0 : GLint length = 0;
345 0 : mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
346 0 : if (!length) {
347 0 : printf_stderr("No shader info log available.\n");
348 0 : break;
349 : }
350 :
351 0 : auto buffer = MakeUnique<char[]>(length);
352 0 : mGL->fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer.get());
353 :
354 0 : printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
355 0 : break;
356 : }
357 :
358 0 : status = 0;
359 0 : mGL->fGetShaderiv(fragShader, LOCAL_GL_COMPILE_STATUS, &status);
360 0 : if (status != LOCAL_GL_TRUE) {
361 0 : NS_ERROR("Frag shader compilation failed.");
362 :
363 0 : GLint length = 0;
364 0 : mGL->fGetShaderiv(fragShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
365 0 : if (!length) {
366 0 : printf_stderr("No shader info log available.\n");
367 0 : break;
368 : }
369 :
370 0 : auto buffer = MakeUnique<char[]>(length);
371 0 : mGL->fGetShaderInfoLog(fragShader, length, nullptr, buffer.get());
372 :
373 0 : printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
374 0 : break;
375 : }
376 : }
377 :
378 0 : GLint status = 0;
379 0 : mGL->fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &status);
380 0 : if (status != LOCAL_GL_TRUE) {
381 0 : if (GLContext::ShouldSpew()) {
382 0 : NS_ERROR("Linking blit program failed.");
383 0 : GLint length = 0;
384 0 : mGL->fGetProgramiv(program, LOCAL_GL_INFO_LOG_LENGTH, &length);
385 0 : if (!length) {
386 0 : printf_stderr("No program info log available.\n");
387 0 : break;
388 : }
389 :
390 0 : auto buffer = MakeUnique<char[]>(length);
391 0 : mGL->fGetProgramInfoLog(program, length, nullptr, buffer.get());
392 :
393 0 : printf_stderr("Program info log (%d bytes): %s\n", length, buffer.get());
394 : }
395 0 : break;
396 : }
397 :
398 : // Cache and set attribute and uniform
399 0 : mGL->fUseProgram(program);
400 0 : switch (target) {
401 : #ifdef ANDROID
402 : case ConvertSurfaceTexture:
403 : #endif
404 : case BlitTex2D:
405 : case BlitTexRect:
406 : case ConvertEGLImage: {
407 0 : GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
408 0 : MOZ_ASSERT(texUnitLoc != -1, "uniform uTexUnit not found");
409 0 : mGL->fUniform1i(texUnitLoc, 0);
410 0 : break;
411 : }
412 : case ConvertPlanarYCbCr: {
413 0 : GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
414 0 : GLint texCb = mGL->fGetUniformLocation(program, "uCbTexture");
415 0 : GLint texCr = mGL->fGetUniformLocation(program, "uCrTexture");
416 0 : mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
417 0 : mCbCrTexScaleLoc = mGL->fGetUniformLocation(program, "uCbCrTexScale");
418 0 : mYuvColorMatrixLoc = mGL->fGetUniformLocation(program, "uYuvColorMatrix");
419 :
420 0 : DebugOnly<bool> hasUniformLocations = texY != -1 &&
421 0 : texCb != -1 &&
422 0 : texCr != -1 &&
423 0 : mYTexScaleLoc != -1 &&
424 0 : mCbCrTexScaleLoc != -1 &&
425 0 : mYuvColorMatrixLoc != -1;
426 0 : MOZ_ASSERT(hasUniformLocations, "uniforms not found");
427 :
428 0 : mGL->fUniform1i(texY, Channel_Y);
429 0 : mGL->fUniform1i(texCb, Channel_Cb);
430 0 : mGL->fUniform1i(texCr, Channel_Cr);
431 0 : break;
432 : }
433 : case ConvertMacIOSurfaceImage: {
434 : #ifdef XP_MACOSX
435 : GLint texY = mGL->fGetUniformLocation(program, "uYTexture");
436 : GLint texCbCr = mGL->fGetUniformLocation(program, "uCbCrTexture");
437 : mYTexScaleLoc = mGL->fGetUniformLocation(program, "uYTexScale");
438 : mCbCrTexScaleLoc= mGL->fGetUniformLocation(program, "uCbCrTexScale");
439 :
440 : DebugOnly<bool> hasUniformLocations = texY != -1 &&
441 : texCbCr != -1 &&
442 : mYTexScaleLoc != -1 &&
443 : mCbCrTexScaleLoc != -1;
444 : MOZ_ASSERT(hasUniformLocations, "uniforms not found");
445 :
446 : mGL->fUniform1i(texY, Channel_Y);
447 : mGL->fUniform1i(texCbCr, Channel_Cb);
448 : #endif
449 0 : break;
450 : }
451 : default:
452 0 : return false;
453 : }
454 0 : MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0);
455 0 : mYFlipLoc = mGL->fGetUniformLocation(program, "uYflip");
456 0 : MOZ_ASSERT(mYFlipLoc != -1, "uniform: uYflip not found");
457 0 : mTextureTransformLoc = mGL->fGetUniformLocation(program, "uTextureTransform");
458 0 : if (mTextureTransformLoc >= 0) {
459 : // Set identity matrix as default
460 0 : gfx::Matrix4x4 identity;
461 0 : mGL->fUniformMatrix4fv(mTextureTransformLoc, 1, false, &identity._11);
462 : }
463 0 : success = true;
464 : } while (false);
465 :
466 0 : if (!success) {
467 : // Clean up:
468 0 : DeleteTexBlitProgram();
469 0 : return false;
470 : }
471 :
472 0 : mGL->fUseProgram(program);
473 0 : mGL->fEnableVertexAttribArray(0);
474 0 : mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
475 0 : mGL->fVertexAttribPointer(0,
476 : 2,
477 : LOCAL_GL_FLOAT,
478 : false,
479 : 0,
480 0 : nullptr);
481 0 : return true;
482 : }
483 :
484 : bool
485 0 : GLBlitHelper::UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize)
486 : {
487 0 : if (!InitTexQuadProgram(target)) {
488 0 : return false;
489 : }
490 :
491 0 : if (target == BlitTexRect) {
492 0 : GLint texCoordMultLoc = mGL->fGetUniformLocation(mTex2DRectBlit_Program, "uTexCoordMult");
493 0 : MOZ_ASSERT(texCoordMultLoc != -1, "uniform not found");
494 0 : mGL->fUniform2f(texCoordMultLoc, srcSize.width, srcSize.height);
495 : }
496 :
497 0 : return true;
498 : }
499 :
500 : void
501 0 : GLBlitHelper::DeleteTexBlitProgram()
502 : {
503 0 : if (mTexBlit_Buffer) {
504 0 : mGL->fDeleteBuffers(1, &mTexBlit_Buffer);
505 0 : mTexBlit_Buffer = 0;
506 : }
507 0 : if (mTexBlit_VertShader) {
508 0 : mGL->fDeleteShader(mTexBlit_VertShader);
509 0 : mTexBlit_VertShader = 0;
510 : }
511 0 : if (mTex2DBlit_FragShader) {
512 0 : mGL->fDeleteShader(mTex2DBlit_FragShader);
513 0 : mTex2DBlit_FragShader = 0;
514 : }
515 0 : if (mTex2DRectBlit_FragShader) {
516 0 : mGL->fDeleteShader(mTex2DRectBlit_FragShader);
517 0 : mTex2DRectBlit_FragShader = 0;
518 : }
519 0 : if (mTex2DBlit_Program) {
520 0 : mGL->fDeleteProgram(mTex2DBlit_Program);
521 0 : mTex2DBlit_Program = 0;
522 : }
523 0 : if (mTex2DRectBlit_Program) {
524 0 : mGL->fDeleteProgram(mTex2DRectBlit_Program);
525 0 : mTex2DRectBlit_Program = 0;
526 : }
527 0 : if (mTexExternalBlit_FragShader) {
528 0 : mGL->fDeleteShader(mTexExternalBlit_FragShader);
529 0 : mTexExternalBlit_FragShader = 0;
530 : }
531 0 : if (mTexYUVPlanarBlit_FragShader) {
532 0 : mGL->fDeleteShader(mTexYUVPlanarBlit_FragShader);
533 0 : mTexYUVPlanarBlit_FragShader = 0;
534 : }
535 0 : if (mTexNV12PlanarBlit_FragShader) {
536 0 : mGL->fDeleteShader(mTexNV12PlanarBlit_FragShader);
537 0 : mTexNV12PlanarBlit_FragShader = 0;
538 : }
539 0 : if (mTexExternalBlit_Program) {
540 0 : mGL->fDeleteProgram(mTexExternalBlit_Program);
541 0 : mTexExternalBlit_Program = 0;
542 : }
543 0 : if (mTexYUVPlanarBlit_Program) {
544 0 : mGL->fDeleteProgram(mTexYUVPlanarBlit_Program);
545 0 : mTexYUVPlanarBlit_Program = 0;
546 : }
547 0 : if (mTexNV12PlanarBlit_Program) {
548 0 : mGL->fDeleteProgram(mTexNV12PlanarBlit_Program);
549 0 : mTexNV12PlanarBlit_Program = 0;
550 : }
551 0 : }
552 :
553 : void
554 0 : GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
555 : const gfx::IntSize& srcSize,
556 : const gfx::IntSize& destSize,
557 : bool internalFBs)
558 : {
559 0 : MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
560 0 : MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
561 :
562 0 : MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
563 :
564 0 : ScopedBindFramebuffer boundFB(mGL);
565 0 : ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
566 :
567 0 : if (internalFBs) {
568 0 : mGL->Screen()->BindReadFB_Internal(srcFB);
569 0 : mGL->Screen()->BindDrawFB_Internal(destFB);
570 : } else {
571 0 : mGL->BindReadFB(srcFB);
572 0 : mGL->BindDrawFB(destFB);
573 : }
574 :
575 0 : mGL->fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
576 0 : 0, 0, destSize.width, destSize.height,
577 : LOCAL_GL_COLOR_BUFFER_BIT,
578 0 : LOCAL_GL_NEAREST);
579 0 : }
580 :
581 : void
582 0 : GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
583 : const gfx::IntSize& srcSize,
584 : const gfx::IntSize& destSize,
585 : const GLFormats& srcFormats,
586 : bool internalFBs)
587 : {
588 0 : MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
589 0 : MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
590 :
591 0 : if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
592 0 : BlitFramebufferToFramebuffer(srcFB, destFB,
593 : srcSize, destSize,
594 0 : internalFBs);
595 0 : return;
596 : }
597 :
598 0 : GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize);
599 0 : MOZ_ASSERT(tex);
600 :
601 0 : BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize, internalFBs);
602 0 : BlitTextureToFramebuffer(tex, destFB, srcSize, destSize, internalFBs);
603 :
604 0 : mGL->fDeleteTextures(1, &tex);
605 : }
606 :
607 : void
608 0 : GLBlitHelper::BindAndUploadYUVTexture(Channel which,
609 : uint32_t width,
610 : uint32_t height,
611 : void* data,
612 : bool needsAllocation)
613 : {
614 0 : MOZ_ASSERT(which < Channel_Max, "Invalid channel!");
615 0 : GLuint* srcTexArr[3] = {&mSrcTexY, &mSrcTexCb, &mSrcTexCr};
616 0 : GLuint& tex = *srcTexArr[which];
617 :
618 : // RED textures aren't valid in GLES2, and ALPHA textures are not valid in desktop GL Core Profiles.
619 : // So use R8 textures on GL3.0+ and GLES3.0+, but LUMINANCE/LUMINANCE/UNSIGNED_BYTE otherwise.
620 : GLenum format;
621 : GLenum internalFormat;
622 0 : if (mGL->IsAtLeast(gl::ContextProfile::OpenGLCore, 300) ||
623 0 : mGL->IsAtLeast(gl::ContextProfile::OpenGLES, 300)) {
624 0 : format = LOCAL_GL_RED;
625 0 : internalFormat = LOCAL_GL_R8;
626 : } else {
627 0 : format = LOCAL_GL_LUMINANCE;
628 0 : internalFormat = LOCAL_GL_LUMINANCE;
629 : }
630 :
631 0 : if (!tex) {
632 0 : MOZ_ASSERT(needsAllocation);
633 0 : tex = CreateTexture(mGL, internalFormat, format, LOCAL_GL_UNSIGNED_BYTE,
634 0 : gfx::IntSize(width, height), false);
635 : }
636 0 : mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + which);
637 :
638 0 : mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
639 0 : if (!needsAllocation) {
640 0 : mGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D,
641 : 0,
642 : 0,
643 : 0,
644 : width,
645 : height,
646 : format,
647 : LOCAL_GL_UNSIGNED_BYTE,
648 0 : data);
649 : } else {
650 0 : mGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
651 : 0,
652 : internalFormat,
653 : width,
654 : height,
655 : 0,
656 : format,
657 : LOCAL_GL_UNSIGNED_BYTE,
658 0 : data);
659 : }
660 0 : }
661 :
662 : void
663 0 : GLBlitHelper::BindAndUploadEGLImage(EGLImage image, GLuint target)
664 : {
665 0 : MOZ_ASSERT(image != EGL_NO_IMAGE, "Bad EGLImage");
666 :
667 0 : if (!mSrcTexEGL) {
668 0 : mGL->fGenTextures(1, &mSrcTexEGL);
669 0 : mGL->fBindTexture(target, mSrcTexEGL);
670 0 : mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
671 0 : mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
672 0 : mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_NEAREST);
673 0 : mGL->fTexParameteri(target, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_NEAREST);
674 : } else {
675 0 : mGL->fBindTexture(target, mSrcTexEGL);
676 : }
677 0 : mGL->fEGLImageTargetTexture2D(target, image);
678 0 : }
679 :
680 : #ifdef MOZ_WIDGET_ANDROID
681 :
682 : #define ATTACH_WAIT_MS 50
683 :
684 : bool
685 : GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage)
686 : {
687 : // FIXME
688 : return false;
689 : }
690 :
691 : bool
692 : GLBlitHelper::BlitEGLImageImage(layers::EGLImageImage* image)
693 : {
694 : EGLImage eglImage = image->GetImage();
695 : EGLSync eglSync = image->GetSync();
696 :
697 : if (eglSync) {
698 : EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), eglSync, 0, LOCAL_EGL_FOREVER);
699 : if (status != LOCAL_EGL_CONDITION_SATISFIED) {
700 : return false;
701 : }
702 : }
703 :
704 : ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
705 :
706 : int oldBinding = 0;
707 : mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldBinding);
708 :
709 : BindAndUploadEGLImage(eglImage, LOCAL_GL_TEXTURE_2D);
710 :
711 : mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
712 :
713 : mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldBinding);
714 : return true;
715 : }
716 :
717 : #endif
718 :
719 : bool
720 0 : GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage)
721 : {
722 0 : ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
723 0 : const PlanarYCbCrData* yuvData = yuvImage->GetData();
724 :
725 0 : bool needsAllocation = false;
726 0 : if (mTexWidth != yuvData->mYStride || mTexHeight != yuvData->mYSize.height) {
727 0 : mTexWidth = yuvData->mYStride;
728 0 : mTexHeight = yuvData->mYSize.height;
729 0 : needsAllocation = true;
730 : }
731 :
732 : GLint oldTex[3];
733 0 : for (int i = 0; i < 3; i++) {
734 0 : mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
735 0 : mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
736 : }
737 :
738 : {
739 0 : const ResetUnpackState reset(mGL);
740 0 : BindAndUploadYUVTexture(Channel_Y, yuvData->mYStride, yuvData->mYSize.height, yuvData->mYChannel, needsAllocation);
741 0 : BindAndUploadYUVTexture(Channel_Cb, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCbChannel, needsAllocation);
742 0 : BindAndUploadYUVTexture(Channel_Cr, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCrChannel, needsAllocation);
743 : }
744 :
745 0 : if (needsAllocation) {
746 0 : mGL->fUniform2f(mYTexScaleLoc, (float)yuvData->mYSize.width/yuvData->mYStride, 1.0f);
747 0 : mGL->fUniform2f(mCbCrTexScaleLoc, (float)yuvData->mCbCrSize.width/yuvData->mCbCrStride, 1.0f);
748 : }
749 :
750 0 : const auto& yuvToRgb = gfxUtils::YuvToRgbMatrix3x3ColumnMajor(yuvData->mYUVColorSpace);
751 0 : mGL->fUniformMatrix3fv(mYuvColorMatrixLoc, 1, 0, yuvToRgb);
752 :
753 0 : mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
754 0 : for (int i = 0; i < 3; i++) {
755 0 : mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
756 0 : mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
757 : }
758 0 : return true;
759 : }
760 :
761 : #ifdef XP_MACOSX
762 : bool
763 : GLBlitHelper::BlitMacIOSurfaceImage(layers::MacIOSurfaceImage* ioImage)
764 : {
765 : ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
766 : MacIOSurface* surf = ioImage->GetSurface();
767 :
768 : GLint oldTex[2];
769 : for (int i = 0; i < 2; i++) {
770 : mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
771 : mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]);
772 : }
773 :
774 : GLuint textures[2];
775 : mGL->fGenTextures(2, textures);
776 :
777 : mGL->fActiveTexture(LOCAL_GL_TEXTURE0);
778 : mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[0]);
779 : mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
780 : mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
781 : surf->CGLTexImageIOSurface2D(mGL,
782 : gl::GLContextCGL::Cast(mGL)->GetCGLContext(),
783 : 0);
784 : mGL->fUniform2f(mYTexScaleLoc, surf->GetWidth(0), surf->GetHeight(0));
785 :
786 : mGL->fActiveTexture(LOCAL_GL_TEXTURE1);
787 : mGL->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textures[1]);
788 : mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
789 : mGL->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
790 : surf->CGLTexImageIOSurface2D(mGL,
791 : gl::GLContextCGL::Cast(mGL)->GetCGLContext(),
792 : 1);
793 : mGL->fUniform2f(mCbCrTexScaleLoc, surf->GetWidth(1), surf->GetHeight(1));
794 :
795 : mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
796 : for (int i = 0; i < 2; i++) {
797 : mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
798 : mGL->fBindTexture(LOCAL_GL_TEXTURE_2D, oldTex[i]);
799 : }
800 :
801 : mGL->fDeleteTextures(2, textures);
802 : return true;
803 : }
804 : #endif
805 :
806 : bool
807 0 : GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage,
808 : const gfx::IntSize& destSize,
809 : GLuint destFB,
810 : OriginPos destOrigin)
811 : {
812 0 : ScopedGLDrawState autoStates(mGL);
813 :
814 : BlitType type;
815 : OriginPos srcOrigin;
816 :
817 0 : switch (srcImage->GetFormat()) {
818 : case ImageFormat::PLANAR_YCBCR:
819 0 : type = ConvertPlanarYCbCr;
820 0 : srcOrigin = OriginPos::BottomLeft;
821 0 : break;
822 :
823 : #ifdef MOZ_WIDGET_ANDROID
824 : case ImageFormat::SURFACE_TEXTURE:
825 : type = ConvertSurfaceTexture;
826 : srcOrigin = srcImage->AsSurfaceTextureImage()->GetOriginPos();
827 : break;
828 : case ImageFormat::EGLIMAGE:
829 : type = ConvertEGLImage;
830 : srcOrigin = srcImage->AsEGLImageImage()->GetOriginPos();
831 : break;
832 : #endif
833 : #ifdef XP_MACOSX
834 : case ImageFormat::MAC_IOSURFACE:
835 : type = ConvertMacIOSurfaceImage;
836 : srcOrigin = OriginPos::TopLeft;
837 : break;
838 : #endif
839 :
840 : default:
841 0 : return false;
842 : }
843 :
844 0 : bool init = InitTexQuadProgram(type);
845 0 : if (!init) {
846 0 : return false;
847 : }
848 :
849 0 : const bool needsYFlip = (srcOrigin != destOrigin);
850 0 : mGL->fUniform1f(mYFlipLoc, needsYFlip ? (float)1.0 : (float)0.0);
851 :
852 0 : ScopedBindFramebuffer boundFB(mGL, destFB);
853 0 : mGL->fColorMask(LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE);
854 0 : mGL->fViewport(0, 0, destSize.width, destSize.height);
855 :
856 0 : switch (type) {
857 : case ConvertPlanarYCbCr:
858 0 : return BlitPlanarYCbCrImage(static_cast<PlanarYCbCrImage*>(srcImage));
859 :
860 : #ifdef MOZ_WIDGET_ANDROID
861 : case ConvertSurfaceTexture:
862 : return BlitSurfaceTextureImage(static_cast<layers::SurfaceTextureImage*>(srcImage));
863 :
864 : case ConvertEGLImage:
865 : return BlitEGLImageImage(static_cast<layers::EGLImageImage*>(srcImage));
866 : #endif
867 :
868 : #ifdef XP_MACOSX
869 : case ConvertMacIOSurfaceImage:
870 : return BlitMacIOSurfaceImage(srcImage->AsMacIOSurfaceImage());
871 : #endif
872 :
873 : default:
874 0 : return false;
875 : }
876 : }
877 :
878 : bool
879 0 : GLBlitHelper::BlitImageToTexture(layers::Image* srcImage,
880 : const gfx::IntSize& destSize,
881 : GLuint destTex,
882 : GLenum destTarget,
883 : OriginPos destOrigin)
884 : {
885 0 : ScopedFramebufferForTexture autoFBForTex(mGL, destTex, destTarget);
886 0 : if (!autoFBForTex.IsComplete())
887 0 : return false;
888 :
889 0 : return BlitImageToFramebuffer(srcImage, destSize, autoFBForTex.FB(), destOrigin);
890 : }
891 :
892 : void
893 0 : GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
894 : const gfx::IntSize& srcSize,
895 : const gfx::IntSize& destSize,
896 : GLenum srcTarget,
897 : bool internalFBs)
898 : {
899 0 : MOZ_ASSERT(mGL->fIsTexture(srcTex));
900 0 : MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
901 :
902 0 : if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
903 0 : ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
904 0 : MOZ_DIAGNOSTIC_ASSERT(srcWrapper.IsComplete());
905 :
906 0 : BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB,
907 : srcSize, destSize,
908 0 : internalFBs);
909 0 : return;
910 : }
911 :
912 0 : DrawBlitTextureToFramebuffer(srcTex, destFB, srcSize, destSize, srcTarget,
913 0 : internalFBs);
914 : }
915 :
916 :
917 : void
918 0 : GLBlitHelper::DrawBlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
919 : const gfx::IntSize& srcSize,
920 : const gfx::IntSize& destSize,
921 : GLenum srcTarget,
922 : bool internalFBs)
923 : {
924 : BlitType type;
925 0 : switch (srcTarget) {
926 : case LOCAL_GL_TEXTURE_2D:
927 0 : type = BlitTex2D;
928 0 : break;
929 : case LOCAL_GL_TEXTURE_RECTANGLE_ARB:
930 0 : type = BlitTexRect;
931 0 : break;
932 : default:
933 0 : MOZ_CRASH("GFX: Fatal Error: Bad `srcTarget`.");
934 : break;
935 : }
936 :
937 0 : ScopedGLDrawState autoStates(mGL);
938 0 : const ScopedBindFramebuffer bindFB(mGL);
939 0 : if (internalFBs) {
940 0 : mGL->Screen()->BindFB_Internal(destFB);
941 : } else {
942 0 : mGL->BindFB(destFB);
943 : }
944 :
945 : // Does destructive things to (only!) what we just saved above.
946 0 : bool good = UseTexQuadProgram(type, srcSize);
947 0 : if (!good) {
948 : // We're up against the wall, so bail.
949 0 : MOZ_DIAGNOSTIC_ASSERT(false,
950 : "Error: Failed to prepare to blit texture->framebuffer.\n");
951 : mGL->fScissor(0, 0, destSize.width, destSize.height);
952 : mGL->fColorMask(1, 1, 1, 1);
953 : mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT);
954 : return;
955 : }
956 :
957 0 : const ScopedBindTexture bindTex(mGL, srcTex, srcTarget);
958 0 : mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
959 : }
960 :
961 : void
962 0 : GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
963 : const gfx::IntSize& srcSize,
964 : const gfx::IntSize& destSize,
965 : GLenum destTarget,
966 : bool internalFBs)
967 : {
968 : // On the Android 4.3 emulator, IsFramebuffer may return false incorrectly.
969 0 : MOZ_ASSERT_IF(mGL->Renderer() != GLRenderer::AndroidEmulator, !srcFB || mGL->fIsFramebuffer(srcFB));
970 0 : MOZ_ASSERT(mGL->fIsTexture(destTex));
971 :
972 0 : if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
973 0 : ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
974 :
975 0 : BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(),
976 : srcSize, destSize,
977 0 : internalFBs);
978 0 : return;
979 : }
980 :
981 0 : ScopedBindTexture autoTex(mGL, destTex, destTarget);
982 :
983 0 : ScopedBindFramebuffer boundFB(mGL);
984 0 : if (internalFBs) {
985 0 : mGL->Screen()->BindFB_Internal(srcFB);
986 : } else {
987 0 : mGL->BindFB(srcFB);
988 : }
989 :
990 0 : ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
991 0 : mGL->fCopyTexSubImage2D(destTarget, 0,
992 : 0, 0,
993 : 0, 0,
994 0 : srcSize.width, srcSize.height);
995 : }
996 :
997 : void
998 0 : GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex,
999 : const gfx::IntSize& srcSize,
1000 : const gfx::IntSize& destSize,
1001 : GLenum srcTarget, GLenum destTarget)
1002 : {
1003 0 : MOZ_ASSERT(mGL->fIsTexture(srcTex));
1004 0 : MOZ_ASSERT(mGL->fIsTexture(destTex));
1005 :
1006 : // Generally, just use the CopyTexSubImage path
1007 0 : ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
1008 :
1009 0 : BlitFramebufferToTexture(srcWrapper.FB(), destTex,
1010 0 : srcSize, destSize, destTarget);
1011 0 : }
1012 :
1013 : } // namespace gl
1014 : } // namespace mozilla
|