|
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 "GLBlitHelper.h" |
|
8 #include "GLContext.h" |
|
9 #include "ScopedGLHelpers.h" |
|
10 #include "mozilla/Preferences.h" |
|
11 |
|
12 namespace mozilla { |
|
13 namespace gl { |
|
14 |
|
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 } |
|
30 |
|
31 |
|
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); |
|
39 |
|
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); |
|
44 |
|
45 aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, |
|
46 0, |
|
47 aInternalFormat, |
|
48 aSize.width, aSize.height, |
|
49 0, |
|
50 aFormat, |
|
51 aType, |
|
52 nullptr); |
|
53 |
|
54 return tex; |
|
55 } |
|
56 |
|
57 |
|
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); |
|
65 |
|
66 return CreateTexture(aGL, |
|
67 aFormats.color_texInternalFormat, |
|
68 aFormats.color_texFormat, |
|
69 aFormats.color_texType, |
|
70 aSize); |
|
71 } |
|
72 |
|
73 |
|
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); |
|
81 |
|
82 RenderbufferStorageBySamples(aGL, aSamples, aFormat, aSize); |
|
83 |
|
84 return rb; |
|
85 } |
|
86 |
|
87 |
|
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); |
|
98 |
|
99 *aColorMSRB = CreateRenderbuffer(aGL, aFormats.color_rbFormat, samples, aSize); |
|
100 } |
|
101 |
|
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); |
|
111 |
|
112 *aDepthRB = CreateRenderbuffer(aGL, aFormats.depth, samples, aSize); |
|
113 } |
|
114 |
|
115 if (aStencilRB) { |
|
116 MOZ_ASSERT(aFormats.stencil); |
|
117 |
|
118 *aStencilRB = CreateRenderbuffer(aGL, aFormats.stencil, samples, aSize); |
|
119 } |
|
120 } |
|
121 } |
|
122 |
|
123 |
|
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 } |
|
134 |
|
135 GLBlitHelper::~GLBlitHelper() |
|
136 { |
|
137 DeleteTexBlitProgram(); |
|
138 } |
|
139 |
|
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 "; |
|
155 |
|
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 "; |
|
171 |
|
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 "; |
|
189 |
|
190 MOZ_ASSERT(target == LOCAL_GL_TEXTURE_2D || |
|
191 target == LOCAL_GL_TEXTURE_RECTANGLE_ARB); |
|
192 bool success = false; |
|
193 |
|
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 } |
|
206 |
|
207 GLuint& program = *programPtr; |
|
208 GLuint& fragShader = *fragShaderPtr; |
|
209 |
|
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 } |
|
217 |
|
218 if (!mTexBlit_Buffer) { |
|
219 |
|
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 }; |
|
231 |
|
232 MOZ_ASSERT(!mTexBlit_Buffer); |
|
233 mGL->fGenBuffers(1, &mTexBlit_Buffer); |
|
234 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mTexBlit_Buffer); |
|
235 |
|
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 } |
|
241 |
|
242 if (!mTexBlit_VertShader) { |
|
243 |
|
244 const char* vertShaderSource = kTexBlit_VertShaderSource; |
|
245 |
|
246 mTexBlit_VertShader = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER); |
|
247 mGL->fShaderSource(mTexBlit_VertShader, 1, &vertShaderSource, nullptr); |
|
248 mGL->fCompileShader(mTexBlit_VertShader); |
|
249 } |
|
250 |
|
251 MOZ_ASSERT(!fragShader); |
|
252 fragShader = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER); |
|
253 mGL->fShaderSource(fragShader, 1, &fragShaderSource, nullptr); |
|
254 mGL->fCompileShader(fragShader); |
|
255 |
|
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); |
|
261 |
|
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."); |
|
267 |
|
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 } |
|
274 |
|
275 nsAutoArrayPtr<char> buffer(new char[length]); |
|
276 mGL->fGetShaderInfoLog(mTexBlit_VertShader, length, nullptr, buffer); |
|
277 |
|
278 printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get()); |
|
279 break; |
|
280 } |
|
281 |
|
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."); |
|
286 |
|
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 } |
|
293 |
|
294 nsAutoArrayPtr<char> buffer(new char[length]); |
|
295 mGL->fGetShaderInfoLog(fragShader, length, nullptr, buffer); |
|
296 |
|
297 printf_stderr("Shader info log (%d bytes): %s\n", length, buffer.get()); |
|
298 break; |
|
299 } |
|
300 } |
|
301 |
|
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 } |
|
313 |
|
314 nsAutoArrayPtr<char> buffer(new char[length]); |
|
315 mGL->fGetProgramInfoLog(program, length, nullptr, buffer); |
|
316 |
|
317 printf_stderr("Program info log (%d bytes): %s\n", length, buffer.get()); |
|
318 } |
|
319 break; |
|
320 } |
|
321 |
|
322 MOZ_ASSERT(mGL->fGetAttribLocation(program, "aPosition") == 0); |
|
323 GLint texUnitLoc = mGL->fGetUniformLocation(program, "uTexUnit"); |
|
324 MOZ_ASSERT(texUnitLoc != -1, "uniform not found"); |
|
325 |
|
326 // Set uniforms here: |
|
327 mGL->fUseProgram(program); |
|
328 mGL->fUniform1i(texUnitLoc, 0); |
|
329 |
|
330 success = true; |
|
331 } while (false); |
|
332 |
|
333 if (!success) { |
|
334 NS_ERROR("Creating program for texture blit failed!"); |
|
335 |
|
336 // Clean up: |
|
337 DeleteTexBlitProgram(); |
|
338 return false; |
|
339 } |
|
340 |
|
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 } |
|
352 |
|
353 bool |
|
354 GLBlitHelper::UseTexQuadProgram(GLenum target, const gfx::IntSize& srcSize) |
|
355 { |
|
356 if (!InitTexQuadProgram(target)) { |
|
357 return false; |
|
358 } |
|
359 |
|
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 } |
|
365 |
|
366 return true; |
|
367 } |
|
368 |
|
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 } |
|
397 |
|
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)); |
|
405 |
|
406 MOZ_ASSERT(mGL->IsSupported(GLFeature::framebuffer_blit)); |
|
407 |
|
408 ScopedBindFramebuffer boundFB(mGL); |
|
409 ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); |
|
410 |
|
411 mGL->BindReadFB(srcFB); |
|
412 mGL->BindDrawFB(destFB); |
|
413 |
|
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 } |
|
419 |
|
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)); |
|
428 |
|
429 if (mGL->IsSupported(GLFeature::framebuffer_blit)) { |
|
430 BlitFramebufferToFramebuffer(srcFB, destFB, |
|
431 srcSize, destSize); |
|
432 return; |
|
433 } |
|
434 |
|
435 GLuint tex = CreateTextureForOffscreen(mGL, srcFormats, srcSize); |
|
436 MOZ_ASSERT(tex); |
|
437 |
|
438 BlitFramebufferToTexture(srcFB, tex, srcSize, srcSize); |
|
439 BlitTextureToFramebuffer(tex, destFB, srcSize, destSize); |
|
440 |
|
441 mGL->fDeleteTextures(1, &tex); |
|
442 } |
|
443 |
|
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)); |
|
452 |
|
453 if (mGL->IsSupported(GLFeature::framebuffer_blit)) { |
|
454 ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); |
|
455 MOZ_ASSERT(srcWrapper.IsComplete()); |
|
456 |
|
457 BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB, |
|
458 srcSize, destSize); |
|
459 return; |
|
460 } |
|
461 |
|
462 |
|
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); |
|
468 |
|
469 GLuint boundProgram = 0; |
|
470 mGL->GetUIntegerv(LOCAL_GL_CURRENT_PROGRAM, &boundProgram); |
|
471 |
|
472 GLuint boundBuffer = 0; |
|
473 mGL->GetUIntegerv(LOCAL_GL_ARRAY_BUFFER_BINDING, &boundBuffer); |
|
474 |
|
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 */ |
|
490 |
|
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; |
|
498 |
|
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. |
|
507 |
|
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); |
|
517 |
|
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); |
|
524 |
|
525 GLint viewport[4]; |
|
526 mGL->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport); |
|
527 mGL->fViewport(0, 0, destSize.width, destSize.height); |
|
528 |
|
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); |
|
539 |
|
540 mGL->fViewport(viewport[0], viewport[1], |
|
541 viewport[2], viewport[3]); |
|
542 |
|
543 mGL->fColorMask(colorMask[0], |
|
544 colorMask[1], |
|
545 colorMask[2], |
|
546 colorMask[3]); |
|
547 |
|
548 if (attrib0_enabled) |
|
549 mGL->fEnableVertexAttribArray(0); |
|
550 |
|
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); |
|
558 |
|
559 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, boundBuffer); |
|
560 |
|
561 mGL->fUseProgram(boundProgram); |
|
562 } |
|
563 |
|
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)); |
|
572 |
|
573 if (mGL->IsSupported(GLFeature::framebuffer_blit)) { |
|
574 ScopedFramebufferForTexture destWrapper(mGL, destTex, destTarget); |
|
575 |
|
576 BlitFramebufferToFramebuffer(srcFB, destWrapper.FB(), |
|
577 srcSize, destSize); |
|
578 return; |
|
579 } |
|
580 |
|
581 ScopedBindTexture autoTex(mGL, destTex, destTarget); |
|
582 ScopedBindFramebuffer boundFB(mGL, srcFB); |
|
583 ScopedGLState scissor(mGL, LOCAL_GL_SCISSOR_TEST, false); |
|
584 |
|
585 mGL->fCopyTexSubImage2D(destTarget, 0, |
|
586 0, 0, |
|
587 0, 0, |
|
588 srcSize.width, srcSize.height); |
|
589 } |
|
590 |
|
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)); |
|
599 |
|
600 // Generally, just use the CopyTexSubImage path |
|
601 ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); |
|
602 |
|
603 BlitFramebufferToTexture(srcWrapper.FB(), destTex, |
|
604 srcSize, destSize, destTarget); |
|
605 } |
|
606 |
|
607 } |
|
608 } |