gfx/gl/GLBlitHelper.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial