Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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"
12 namespace mozilla {
13 namespace gl {
15 static void
16 RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
17 GLenum aInternalFormat, const gfx::IntSize& aSize)
18 {
19 if (aSamples) {
20 aGL->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER,
21 aSamples,
22 aInternalFormat,
23 aSize.width, aSize.height);
24 } else {
25 aGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
26 aInternalFormat,
27 aSize.width, aSize.height);
28 }
29 }
32 GLuint
33 CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
34 GLenum aType, const gfx::IntSize& aSize)
35 {
36 GLuint tex = 0;
37 aGL->fGenTextures(1, &tex);
38 ScopedBindTexture autoTex(aGL, tex);
40 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR);
41 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR);
42 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
43 aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
45 aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
46 0,
47 aInternalFormat,
48 aSize.width, aSize.height,
49 0,
50 aFormat,
51 aType,
52 nullptr);
54 return tex;
55 }
58 GLuint
59 CreateTextureForOffscreen(GLContext* aGL, const GLFormats& aFormats,
60 const gfx::IntSize& aSize)
61 {
62 MOZ_ASSERT(aFormats.color_texInternalFormat);
63 MOZ_ASSERT(aFormats.color_texFormat);
64 MOZ_ASSERT(aFormats.color_texType);
66 return CreateTexture(aGL,
67 aFormats.color_texInternalFormat,
68 aFormats.color_texFormat,
69 aFormats.color_texType,
70 aSize);
71 }
74 GLuint
75 CreateRenderbuffer(GLContext* aGL, GLenum aFormat, GLsizei aSamples,
76 const gfx::IntSize& aSize)
77 {
78 GLuint rb = 0;
79 aGL->fGenRenderbuffers(1, &rb);
80 ScopedBindRenderbuffer autoRB(aGL, rb);
82 RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize);
84 return rb;
85 }
88 void
89 CreateRenderbuffersForOffscreen(GLContext* aGL, const GLFormats& aFormats,
90 const gfx::IntSize& aSize, bool aMultisample,
91 GLuint* aColorMSRB, GLuint* aDepthRB,
92 GLuint* aStencilRB)
93 {
94 GLsizei samples = aMultisample ? aFormats.samples : 0;
95 if (aColorMSRB) {
96 MOZ_ASSERT(aFormats.samples > 0);
97 MOZ_ASSERT(aFormats.color_rbFormat);
99 *aColorMSRB = CreateRenderbuffer(aGL, aFormats.color_rbFormat, samples, aSize);
100 }
102 if (aDepthRB &&
103 aStencilRB &&
104 aFormats.depthStencil)
105 {
106 *aDepthRB = CreateRenderbuffer(aGL, aFormats.depthStencil, samples, aSize);
107 *aStencilRB = *aDepthRB;
108 } else {
109 if (aDepthRB) {
110 MOZ_ASSERT(aFormats.depth);
112 *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize);
113 }
115 if (aStencilRB) {
116 MOZ_ASSERT(aFormats.stencil);
118 *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize);
119 }
120 }
121 }
124 GLBlitHelper::GLBlitHelper(GLContext* gl)
125 : mGL(gl)
126 , mTexBlit_Buffer(0)
127 , mTexBlit_VertShader(0)
128 , mTex2DBlit_FragShader(0)
129 , mTex2DRectBlit_FragShader(0)
130 , mTex2DBlit_Program(0)
131 , mTex2DRectBlit_Program(0)
132 {
133 }
135 GLBlitHelper::~GLBlitHelper()
136 {
137 DeleteTexBlitProgram();
138 }
140 // Allowed to be destructive of state we restore in functions below.
141 bool
142 GLBlitHelper::InitTexQuadProgram(GLenum target)
143 {
144 const char kTexBlit_VertShaderSource[] = "\
145 attribute vec2 aPosition; \n\
146 \n\
147 varying vec2 vTexCoord; \n\
148 \n\
149 void main(void) { \n\
150 vTexCoord = aPosition; \n\
151 vec2 vertPos = aPosition * 2.0 - 1.0; \n\
152 gl_Position = vec4(vertPos, 0.0, 1.0); \n\
153 } \n\
154 ";
156 const char kTex2DBlit_FragShaderSource[] = "\
157 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
158 precision highp float; \n\
159 #else \n\
160 precision mediump float; \n\
161 #endif \n\
162 \n\
163 uniform sampler2D uTexUnit; \n\
164 \n\
165 varying vec2 vTexCoord; \n\
166 \n\
167 void main(void) { \n\
168 gl_FragColor = texture2D(uTexUnit, vTexCoord); \n\
169 } \n\
170 ";
172 const char kTex2DRectBlit_FragShaderSource[] = "\
173 #ifdef GL_FRAGMENT_PRECISION_HIGH \n\
174 precision highp float; \n\
175 #else \n\
176 precision mediump float; \n\
177 #endif \n\
178 \n\
179 uniform sampler2D uTexUnit; \n\
180 uniform vec2 uTexCoordMult; \n\
181 \n\
182 varying vec2 vTexCoord; \n\
183 \n\
184 void main(void) { \n\
185 gl_FragColor = texture2DRect(uTexUnit, \n\
186 vTexCoord * uTexCoordMult); \n\
187 } \n\
188 ";
190 MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D ||
191 target == LOCAL_GL_TEXTURE_RECTANGLE_ARB);
192 bool success = false;
194 GLuint *programPtr;
195 GLuint *fragShaderPtr;
196 const char* fragShaderSource;
197 if (target == LOCAL_GL_TEXTURE_2D) {
198 programPtr = &mTex2DBlit_Program;
199 fragShaderPtr = &mTex2DBlit_FragShader;
200 fragShaderSource = kTex2DBlit_FragShaderSource;
201 } else {
202 programPtr = &mTex2DRectBlit_Program;
203 fragShaderPtr = &mTex2DRectBlit_FragShader;
204 fragShaderSource = kTex2DRectBlit_FragShaderSource;
205 }
207 GLuint& program = *programPtr;
208 GLuint& fragShader = *fragShaderPtr;
210 // Use do-while(false) to let us break on failure
211 do {
212 if (program) {
213 // Already have it...
214 success = true;
215 break;
216 }
218 if (!mTexBlit_Buffer) {
220 /* CCW tri-strip:
221 * 2---3
222 * | \ |
223 * 0---1
224 */
225 GLfloat verts[] = {
226 0.0f, 0.0f,
227 1.0f, 0.0f,
228 0.0f, 1.0f,
229 1.0f, 1.0f
230 };
232 MOZ_ASSERT(!mTexBlit_Buffer);
233 mGL->fGenBuffers(1, &mTexBlit_Buffer);
234 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
236 const size_t vertsSize = sizeof(verts);
237 // Make sure we have a sane size.
238 MOZ_ASSERT(vertsSize >= 3 * sizeof(GLfloat));
239 mGL->fBufferData(LOCAL_GL_ARRAY_BUFFER, vertsSize, verts, LOCAL_GL_STATIC_DRAW);
240 }
242 if (!mTexBlit_VertShader) {
244 const char* vertShaderSource = kTexBlit_VertShaderSource;
246 mTexBlit_VertShader = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER);
247 mGL->fShaderSource(mTexBlit_VertShader, 1, &vertShaderSource, nullptr);
248 mGL->fCompileShader(mTexBlit_VertShader);
249 }
251 MOZ_ASSERT(!fragShader);
252 fragShader = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
253 mGL->fShaderSource(fragShader, 1, &fragShaderSource, nullptr);
254 mGL->fCompileShader(fragShader);
256 program = mGL->fCreateProgram();
257 mGL->fAttachShader(program, mTexBlit_VertShader);
258 mGL->fAttachShader(program, fragShader);
259 mGL->fBindAttribLocation(program, 0, "aPosition");
260 mGL->fLinkProgram(program);
262 if (mGL->DebugMode()) {
263 GLint status = 0;
264 mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_COMPILE_STATUS, &status);
265 if (status != LOCAL_GL_TRUE) {
266 NS_ERROR("Vert shader compilation failed.");
268 GLint length = 0;
269 mGL->fGetShaderiv(mTexBlit_VertShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
270 if (!length) {
271 printf_stderr("No shader info log available.\n");
272 break;
273 }
275 nsAutoArrayPtr<char> buffer(new char[length]);
276 mGL->fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer);
278 printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
279 break;
280 }
282 status = 0;
283 mGL->fGetShaderiv(fragShader, LOCAL_GL_COMPILE_STATUS, &status);
284 if (status != LOCAL_GL_TRUE) {
285 NS_ERROR("Frag shader compilation failed.");
287 GLint length = 0;
288 mGL->fGetShaderiv(fragShader, LOCAL_GL_INFO_LOG_LENGTH, &length);
289 if (!length) {
290 printf_stderr("No shader info log available.\n");
291 break;
292 }
294 nsAutoArrayPtr<char> buffer(new char[length]);
295 mGL->fGetShaderInfoLog(fragShader, length, nullptr, buffer);
297 printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get());
298 break;
299 }
300 }
302 GLint status = 0;
303 mGL->fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &status);
304 if (status != LOCAL_GL_TRUE) {
305 if (mGL->DebugMode()) {
306 NS_ERROR("Linking blit program failed.");
307 GLint length = 0;
308 mGL->fGetProgramiv(program, LOCAL_GL_INFO_LOG_LENGTH, &length);
309 if (!length) {
310 printf_stderr("No program info log available.\n");
311 break;
312 }
314 nsAutoArrayPtr<char> buffer(new char[length]);
315 mGL->fGetProgramInfoLog(program, length, nullptr, buffer);
317 printf_stderr("Program info log (%d bytes): %s\n", length, buffer.get());
318 }
319 break;
320 }
322 MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0);
323 GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit");
324 MOZ_ASSERT(texUnitLoc != -1, "uniform not found");
326 // Set uniforms here:
327 mGL->fUseProgram(program);
328 mGL->fUniform1i(texUnitLoc, 0);
330 success = true;
331 } while (false);
333 if (!success) {
334 NS_ERROR("Creating program for texture blit failed!");
336 // Clean up:
337 DeleteTexBlitProgram();
338 return false;
339 }
341 mGL->fUseProgram(program);
342 mGL->fEnableVertexAttribArray(0);
343 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer);
344 mGL->fVertexAttribPointer(0,
345 2,
346 LOCAL_GL_FLOAT,
347 false,
348 0,
349 nullptr);
350 return true;
351 }
353 bool
354 GLBlitHelper::UseTexQuadProgram(GLenum target, const gfx::IntSize& srcSize)
355 {
356 if (!InitTexQuadProgram(target)) {
357 return false;
358 }
360 if (target == LOCAL_GL_TEXTURE_RECTANGLE_ARB) {
361 GLint texCoordMultLoc = mGL->fGetUniformLocation(mTex2DRectBlit_Program, "uTexCoordMult");
362 MOZ_ASSERT(texCoordMultLoc != -1, "uniform not found");
363 mGL->fUniform2f(texCoordMultLoc, srcSize.width, srcSize.height);
364 }
366 return true;
367 }
369 void
370 GLBlitHelper::DeleteTexBlitProgram()
371 {
372 if (mTexBlit_Buffer) {
373 mGL->fDeleteBuffers(1, &mTexBlit_Buffer);
374 mTexBlit_Buffer = 0;
375 }
376 if (mTexBlit_VertShader) {
377 mGL->fDeleteShader(mTexBlit_VertShader);
378 mTexBlit_VertShader = 0;
379 }
380 if (mTex2DBlit_FragShader) {
381 mGL->fDeleteShader(mTex2DBlit_FragShader);
382 mTex2DBlit_FragShader = 0;
383 }
384 if (mTex2DRectBlit_FragShader) {
385 mGL->fDeleteShader(mTex2DRectBlit_FragShader);
386 mTex2DRectBlit_FragShader = 0;
387 }
388 if (mTex2DBlit_Program) {
389 mGL->fDeleteProgram(mTex2DBlit_Program);
390 mTex2DBlit_Program = 0;
391 }
392 if (mTex2DRectBlit_Program) {
393 mGL->fDeleteProgram(mTex2DRectBlit_Program);
394 mTex2DRectBlit_Program = 0;
395 }
396 }
398 void
399 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
400 const gfx::IntSize& srcSize,
401 const gfx::IntSize& destSize)
402 {
403 MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
404 MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
406 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit));
408 ScopedBindFramebuffer boundFB(mGL);
409 ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
411 mGL->BindReadFB(srcFB);
412 mGL->BindDrawFB(destFB);
414 mGL->fBlitFramebuffer(0, 0, srcSize.width, srcSize.height,
415 0, 0, destSize.width, destSize.height,
416 LOCAL_GL_COLOR_BUFFER_BIT,
417 LOCAL_GL_NEAREST);
418 }
420 void
421 GLBlitHelper::BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB,
422 const gfx::IntSize& srcSize,
423 const gfx::IntSize& destSize,
424 const GLFormats& srcFormats)
425 {
426 MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
427 MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
429 if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
430 BlitFramebufferToFramebuffer(srcFB, destFB,
431 srcSize, destSize);
432 return;
433 }
435 GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize);
436 MOZ_ASSERT(tex);
438 BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize);
439 BlitTextureToFramebuffer(tex, destFB, srcSize, destSize);
441 mGL->fDeleteTextures(1, &tex);
442 }
444 void
445 GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB,
446 const gfx::IntSize& srcSize,
447 const gfx::IntSize& destSize,
448 GLenum srcTarget)
449 {
450 MOZ_ASSERT(mGL->fIsTexture(srcTex));
451 MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB));
453 if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
454 ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
455 MOZ_ASSERT(srcWrapper.IsComplete());
457 BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB,
458 srcSize, destSize);
459 return;
460 }
463 ScopedBindFramebuffer boundFB(mGL, destFB);
464 // UseTexQuadProgram initializes a shader that reads
465 // from texture unit 0.
466 ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0);
467 ScopedBindTexture boundTex(mGL, srcTex, srcTarget);
469 GLuint boundProgram = 0;
470 mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram);
472 GLuint boundBuffer = 0;
473 mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer);
475 /*
476 * mGL->fGetVertexAttribiv takes:
477 * VERTEX_ATTRIB_ARRAY_ENABLED
478 * VERTEX_ATTRIB_ARRAY_SIZE,
479 * VERTEX_ATTRIB_ARRAY_STRIDE,
480 * VERTEX_ATTRIB_ARRAY_TYPE,
481 * VERTEX_ATTRIB_ARRAY_NORMALIZED,
482 * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
483 * CURRENT_VERTEX_ATTRIB
484 *
485 * CURRENT_VERTEX_ATTRIB is vertex shader state. \o/
486 * Others appear to be vertex array state,
487 * or alternatively in the internal vertex array state
488 * for a buffer object.
489 */
491 GLint attrib0_enabled = 0;
492 GLint attrib0_size = 0;
493 GLint attrib0_stride = 0;
494 GLint attrib0_type = 0;
495 GLint attrib0_normalized = 0;
496 GLint attrib0_bufferBinding = 0;
497 void* attrib0_pointer = nullptr;
499 mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_ENABLED, &attrib0_enabled);
500 mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_SIZE, &attrib0_size);
501 mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_STRIDE, &attrib0_stride);
502 mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_TYPE, &attrib0_type);
503 mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &attrib0_normalized);
504 mGL->fGetVertexAttribiv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &attrib0_bufferBinding);
505 mGL->fGetVertexAttribPointerv(0, LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER, &attrib0_pointer);
506 // Note that uniform values are program state, so we don't need to rebind those.
508 ScopedGLState blend (mGL, LOCAL_GL_BLEND, false);
509 ScopedGLState cullFace (mGL, LOCAL_GL_CULL_FACE, false);
510 ScopedGLState depthTest (mGL, LOCAL_GL_DEPTH_TEST, false);
511 ScopedGLState dither (mGL, LOCAL_GL_DITHER, false);
512 ScopedGLState polyOffsFill(mGL, LOCAL_GL_POLYGON_OFFSET_FILL, false);
513 ScopedGLState sampleAToC (mGL, LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE, false);
514 ScopedGLState sampleCover (mGL, LOCAL_GL_SAMPLE_COVERAGE, false);
515 ScopedGLState scissor (mGL, LOCAL_GL_SCISSOR_TEST, false);
516 ScopedGLState stencil (mGL, LOCAL_GL_STENCIL_TEST, false);
518 realGLboolean colorMask[4];
519 mGL->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorMask);
520 mGL->fColorMask(LOCAL_GL_TRUE,
521 LOCAL_GL_TRUE,
522 LOCAL_GL_TRUE,
523 LOCAL_GL_TRUE);
525 GLint viewport[4];
526 mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
527 mGL->fViewport(0, 0, destSize.width, destSize.height);
529 // Does destructive things to (only!) what we just saved above.
530 bool good = UseTexQuadProgram(srcTarget, srcSize);
531 if (!good) {
532 // We're up against the wall, so bail.
533 // This should really be MOZ_CRASH(why) or MOZ_RUNTIME_ASSERT(good).
534 printf_stderr("[%s:%d] Fatal Error: Failed to prepare to blit texture->framebuffer.\n",
535 __FILE__, __LINE__);
536 MOZ_CRASH();
537 }
538 mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4);
540 mGL->fViewport(viewport[0], viewport[1],
541 viewport[2], viewport[3]);
543 mGL->fColorMask(colorMask[0],
544 colorMask[1],
545 colorMask[2],
546 colorMask[3]);
548 if (attrib0_enabled)
549 mGL->fEnableVertexAttribArray(0);
551 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0_bufferBinding);
552 mGL->fVertexAttribPointer(0,
553 attrib0_size,
554 attrib0_type,
555 attrib0_normalized,
556 attrib0_stride,
557 attrib0_pointer);
559 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer);
561 mGL->fUseProgram(boundProgram);
562 }
564 void
565 GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex,
566 const gfx::IntSize& srcSize,
567 const gfx::IntSize& destSize,
568 GLenum destTarget)
569 {
570 MOZ_ASSERT(!srcFB || mGL->fIsFramebuffer(srcFB));
571 MOZ_ASSERT(mGL->fIsTexture(destTex));
573 if (mGL->IsSupported(GLFeature::framebuffer_blit)) {
574 ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget);
576 BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(),
577 srcSize, destSize);
578 return;
579 }
581 ScopedBindTexture autoTex(mGL, destTex, destTarget);
582 ScopedBindFramebuffer boundFB(mGL, srcFB);
583 ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false);
585 mGL->fCopyTexSubImage2D(destTarget, 0,
586 0, 0,
587 0, 0,
588 srcSize.width, srcSize.height);
589 }
591 void
592 GLBlitHelper::BlitTextureToTexture(GLuint srcTex, GLuint destTex,
593 const gfx::IntSize& srcSize,
594 const gfx::IntSize& destSize,
595 GLenum srcTarget, GLenum destTarget)
596 {
597 MOZ_ASSERT(mGL->fIsTexture(srcTex));
598 MOZ_ASSERT(mGL->fIsTexture(destTex));
600 // Generally, just use the CopyTexSubImage path
601 ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget);
603 BlitFramebufferToTexture(srcWrapper.FB(), destTex,
604 srcSize, destSize, destTarget);
605 }
607 }
608 }