| |
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 } |