GLReadTexImageHelper.cpp (20179B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 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 "GLReadTexImageHelper.h" 8 9 #include <utility> 10 11 #include "GLContext.h" 12 #include "OGLShaderProgram.h" 13 #include "ScopedGLHelpers.h" 14 #include "gfx2DGlue.h" 15 #include "gfxColor.h" 16 #include "gfxTypes.h" 17 #include "mozilla/gfx/2D.h" 18 #include "mozilla/gfx/Swizzle.h" 19 20 namespace mozilla { 21 namespace gl { 22 23 using namespace mozilla::gfx; 24 25 GLReadTexImageHelper::GLReadTexImageHelper(GLContext* gl) : mGL(gl) { 26 mPrograms[0] = 0; 27 mPrograms[1] = 0; 28 mPrograms[2] = 0; 29 mPrograms[3] = 0; 30 } 31 32 GLReadTexImageHelper::~GLReadTexImageHelper() { 33 if (!mGL->MakeCurrent()) return; 34 35 mGL->fDeleteProgram(mPrograms[0]); 36 mGL->fDeleteProgram(mPrograms[1]); 37 mGL->fDeleteProgram(mPrograms[2]); 38 mGL->fDeleteProgram(mPrograms[3]); 39 } 40 41 static const GLchar readTextureImageVS[] = 42 "attribute vec2 aVertex;\n" 43 "attribute vec2 aTexCoord;\n" 44 "uniform mat4 uTexMatrix;\n" 45 "varying vec2 vTexCoord;\n" 46 "void main() {\n" 47 " gl_Position = vec4(aVertex, 0, 1);\n" 48 " vTexCoord = (uTexMatrix * vec4(aTexCoord, 0.0, 1.0)).xy;\n" 49 "}"; 50 51 static const GLchar readTextureImageFS_TEXTURE_2D[] = 52 "#ifdef GL_ES\n" 53 "precision mediump float;\n" 54 "#endif\n" 55 "varying vec2 vTexCoord;\n" 56 "uniform sampler2D uTexture;\n" 57 "void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }"; 58 59 static const GLchar readTextureImageFS_TEXTURE_2D_BGRA[] = 60 "#ifdef GL_ES\n" 61 "precision mediump float;\n" 62 "#endif\n" 63 "varying vec2 vTexCoord;\n" 64 "uniform sampler2D uTexture;\n" 65 "void main() { gl_FragColor = texture2D(uTexture, vTexCoord).bgra; }"; 66 67 static const GLchar readTextureImageFS_TEXTURE_EXTERNAL[] = 68 "#extension GL_OES_EGL_image_external : require\n" 69 "#ifdef GL_ES\n" 70 "precision mediump float;\n" 71 "#endif\n" 72 "varying vec2 vTexCoord;\n" 73 "uniform samplerExternalOES uTexture;\n" 74 "void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }"; 75 76 static const GLchar readTextureImageFS_TEXTURE_RECTANGLE[] = 77 "#extension GL_ARB_texture_rectangle\n" 78 "#ifdef GL_ES\n" 79 "precision mediump float;\n" 80 "#endif\n" 81 "varying vec2 vTexCoord;\n" 82 "uniform sampler2DRect uTexture;\n" 83 "void main() { gl_FragColor = texture2DRect(uTexture, vTexCoord).bgra; }"; 84 85 GLuint GLReadTexImageHelper::TextureImageProgramFor(GLenum aTextureTarget, 86 int aConfig) { 87 int variant = 0; 88 const GLchar* readTextureImageFS = nullptr; 89 if (aTextureTarget == LOCAL_GL_TEXTURE_2D) { 90 if (aConfig & mozilla::layers::ENABLE_TEXTURE_RB_SWAP) { 91 // Need to swizzle R/B. 92 readTextureImageFS = readTextureImageFS_TEXTURE_2D_BGRA; 93 variant = 1; 94 } else { 95 readTextureImageFS = readTextureImageFS_TEXTURE_2D; 96 variant = 0; 97 } 98 } else if (aTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL) { 99 readTextureImageFS = readTextureImageFS_TEXTURE_EXTERNAL; 100 variant = 2; 101 } else if (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) { 102 readTextureImageFS = readTextureImageFS_TEXTURE_RECTANGLE; 103 variant = 3; 104 } 105 106 /* This might be overkill, but assure that we don't access out-of-bounds */ 107 MOZ_ASSERT((size_t)variant < std::size(mPrograms)); 108 if (!mPrograms[variant]) { 109 GLuint vs = mGL->fCreateShader(LOCAL_GL_VERTEX_SHADER); 110 const GLchar* vsSourcePtr = &readTextureImageVS[0]; 111 mGL->fShaderSource(vs, 1, &vsSourcePtr, nullptr); 112 mGL->fCompileShader(vs); 113 114 GLuint fs = mGL->fCreateShader(LOCAL_GL_FRAGMENT_SHADER); 115 mGL->fShaderSource(fs, 1, &readTextureImageFS, nullptr); 116 mGL->fCompileShader(fs); 117 118 GLuint program = mGL->fCreateProgram(); 119 mGL->fAttachShader(program, vs); 120 mGL->fAttachShader(program, fs); 121 mGL->fBindAttribLocation(program, 0, "aVertex"); 122 mGL->fBindAttribLocation(program, 1, "aTexCoord"); 123 mGL->fLinkProgram(program); 124 125 GLint success; 126 mGL->fGetProgramiv(program, LOCAL_GL_LINK_STATUS, &success); 127 128 if (!success) { 129 mGL->fDeleteProgram(program); 130 program = 0; 131 } 132 133 mGL->fDeleteShader(vs); 134 mGL->fDeleteShader(fs); 135 136 mPrograms[variant] = program; 137 } 138 139 return mPrograms[variant]; 140 } 141 142 bool GLReadTexImageHelper::DidGLErrorOccur(const char* str) { 143 GLenum error = mGL->fGetError(); 144 if (error != LOCAL_GL_NO_ERROR) { 145 printf_stderr("GL ERROR: %s %s\n", 146 GLContext::GLErrorToString(error).c_str(), str); 147 return true; 148 } 149 150 return false; 151 } 152 153 bool GetActualReadFormats(GLContext* gl, GLenum destFormat, GLenum destType, 154 GLenum* out_readFormat, GLenum* out_readType) { 155 MOZ_ASSERT(out_readFormat); 156 MOZ_ASSERT(out_readType); 157 158 if (destFormat == LOCAL_GL_RGBA && destType == LOCAL_GL_UNSIGNED_BYTE) { 159 *out_readFormat = destFormat; 160 *out_readType = destType; 161 return true; 162 } 163 164 bool fallback = true; 165 if (gl->IsGLES()) { 166 GLenum auxFormat = 0; 167 GLenum auxType = 0; 168 169 gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT, 170 (GLint*)&auxFormat); 171 gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE, (GLint*)&auxType); 172 173 if (destFormat == auxFormat && destType == auxType) { 174 fallback = false; 175 } 176 } else { 177 switch (destFormat) { 178 case LOCAL_GL_RGB: { 179 if (destType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV) fallback = false; 180 break; 181 } 182 case LOCAL_GL_BGRA: { 183 if (destType == LOCAL_GL_UNSIGNED_BYTE || 184 destType == LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV) { 185 fallback = false; 186 } 187 break; 188 } 189 } 190 } 191 192 if (fallback) { 193 *out_readFormat = LOCAL_GL_RGBA; 194 *out_readType = LOCAL_GL_UNSIGNED_BYTE; 195 return false; 196 } else { 197 *out_readFormat = destFormat; 198 *out_readType = destType; 199 return true; 200 } 201 } 202 203 void SwapRAndBComponents(DataSourceSurface* surf) { 204 DataSourceSurface::MappedSurface map; 205 if (!surf->Map(DataSourceSurface::MapType::READ_WRITE, &map)) { 206 MOZ_ASSERT(false, "SwapRAndBComponents: Failed to map surface."); 207 return; 208 } 209 MOZ_ASSERT(map.mStride >= 0); 210 211 const size_t rowBytes = surf->GetSize().width * 4; 212 const size_t rowHole = map.mStride - rowBytes; 213 214 uint8_t* row = map.mData; 215 if (!row) { 216 MOZ_ASSERT(false, 217 "SwapRAndBComponents: Failed to get data from" 218 " DataSourceSurface."); 219 surf->Unmap(); 220 return; 221 } 222 223 const size_t rows = surf->GetSize().height; 224 for (size_t i = 0; i < rows; i++) { 225 const uint8_t* rowEnd = row + rowBytes; 226 227 while (row != rowEnd) { 228 std::swap(row[0], row[2]); 229 row += 4; 230 } 231 232 row += rowHole; 233 } 234 235 surf->Unmap(); 236 } 237 238 static int CalcRowStride(int width, int pixelSize, int alignment) { 239 MOZ_ASSERT(alignment); 240 241 int rowStride = width * pixelSize; 242 if (rowStride % alignment) { // Extra at the end of the line? 243 int alignmentCount = rowStride / alignment; 244 rowStride = (alignmentCount + 1) * alignment; 245 } 246 return rowStride; 247 } 248 249 static int GuessAlignment(int width, int pixelSize, int rowStride) { 250 int alignment = 8; // Max GLES allows. 251 while (CalcRowStride(width, pixelSize, alignment) != rowStride) { 252 alignment /= 2; 253 if (!alignment) { 254 NS_WARNING("Bad alignment for GLES. Will use temp surf for readback."); 255 return 0; 256 } 257 } 258 return alignment; 259 } 260 261 void ReadPixelsIntoBuffer(GLContext* gl, uint8_t* aData, int32_t aStride, 262 const IntSize& aSize, SurfaceFormat aFormat) { 263 gl->MakeCurrent(); 264 MOZ_ASSERT(aSize.width != 0); 265 MOZ_ASSERT(aSize.height != 0); 266 267 bool hasAlpha = 268 aFormat == SurfaceFormat::B8G8R8A8 || aFormat == SurfaceFormat::R8G8B8A8; 269 270 int destPixelSize; 271 GLenum destFormat; 272 GLenum destType; 273 274 switch (aFormat) { 275 case SurfaceFormat::B8G8R8A8: 276 case SurfaceFormat::B8G8R8X8: 277 // Needs host (little) endian ARGB. 278 destFormat = LOCAL_GL_BGRA; 279 destType = LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV; 280 break; 281 case SurfaceFormat::R8G8B8A8: 282 case SurfaceFormat::R8G8B8X8: 283 // Needs host (little) endian ABGR. 284 destFormat = LOCAL_GL_RGBA; 285 destType = LOCAL_GL_UNSIGNED_BYTE; 286 break; 287 case SurfaceFormat::R5G6B5_UINT16: 288 destFormat = LOCAL_GL_RGB; 289 destType = LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV; 290 break; 291 default: 292 MOZ_CRASH("GFX: Bad format, read pixels."); 293 } 294 destPixelSize = BytesPerPixel(aFormat); 295 296 MOZ_ASSERT(aSize.width * destPixelSize <= aStride); 297 298 GLenum readFormat = destFormat; 299 GLenum readType = destType; 300 bool needsTempSurf = 301 !GetActualReadFormats(gl, destFormat, destType, &readFormat, &readType); 302 303 RefPtr<DataSourceSurface> tempSurf; 304 Maybe<DataSourceSurface::ScopedMap> tempMap; 305 uint8_t* data = aData; 306 SurfaceFormat readFormatGFX; 307 308 int readAlignment = GuessAlignment(aSize.width, destPixelSize, aStride); 309 if (!readAlignment) { 310 needsTempSurf = true; 311 } 312 if (needsTempSurf) { 313 if (GLContext::ShouldSpew()) { 314 NS_WARNING( 315 "Needing intermediary surface for ReadPixels. This will be slow!"); 316 } 317 318 switch (readFormat) { 319 case LOCAL_GL_RGBA: { 320 readFormatGFX = 321 hasAlpha ? SurfaceFormat::R8G8B8A8 : SurfaceFormat::R8G8B8X8; 322 break; 323 } 324 case LOCAL_GL_BGRA: { 325 readFormatGFX = 326 hasAlpha ? SurfaceFormat::B8G8R8A8 : SurfaceFormat::B8G8R8X8; 327 break; 328 } 329 case LOCAL_GL_RGB: { 330 MOZ_ASSERT(destPixelSize == 2); 331 MOZ_ASSERT(readType == LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV); 332 readFormatGFX = SurfaceFormat::R5G6B5_UINT16; 333 break; 334 } 335 default: { 336 MOZ_CRASH("GFX: Bad read format, read format."); 337 } 338 } 339 340 switch (readType) { 341 case LOCAL_GL_UNSIGNED_BYTE: { 342 MOZ_ASSERT(readFormat == LOCAL_GL_RGBA); 343 readAlignment = 1; 344 break; 345 } 346 case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV: { 347 MOZ_ASSERT(readFormat == LOCAL_GL_BGRA); 348 readAlignment = 4; 349 break; 350 } 351 case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV: { 352 MOZ_ASSERT(readFormat == LOCAL_GL_RGB); 353 readAlignment = 2; 354 break; 355 } 356 default: { 357 MOZ_CRASH("GFX: Bad read type, read type."); 358 } 359 } 360 361 int32_t stride = aSize.width * BytesPerPixel(readFormatGFX); 362 tempSurf = Factory::CreateDataSourceSurfaceWithStride(aSize, readFormatGFX, 363 stride); 364 if (NS_WARN_IF(!tempSurf)) { 365 return; 366 } 367 368 tempMap.emplace(tempSurf, DataSourceSurface::READ_WRITE); 369 if (NS_WARN_IF(!tempMap->IsMapped())) { 370 return; 371 } 372 373 data = tempMap->GetData(); 374 } 375 376 MOZ_ASSERT(readAlignment); 377 MOZ_ASSERT(reinterpret_cast<uintptr_t>(data) % readAlignment == 0); 378 379 GLsizei width = aSize.width; 380 GLsizei height = aSize.height; 381 382 { 383 ScopedPackState safePackState(gl); 384 gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, readAlignment); 385 386 gl->fReadPixels(0, 0, width, height, readFormat, readType, data); 387 } 388 389 if (tempMap) { 390 SwizzleData(tempMap->GetData(), tempMap->GetStride(), readFormatGFX, aData, 391 aStride, aFormat, aSize); 392 } 393 } 394 395 void ReadPixelsIntoDataSurface(GLContext* gl, DataSourceSurface* dest) { 396 gl->MakeCurrent(); 397 398 DataSourceSurface::ScopedMap map(dest, DataSourceSurface::WRITE); 399 ReadPixelsIntoBuffer(gl, map.GetData(), map.GetStride(), dest->GetSize(), 400 dest->GetFormat()); 401 } 402 403 already_AddRefed<gfx::DataSourceSurface> YInvertImageSurface( 404 gfx::DataSourceSurface* aSurf, uint32_t aStride) { 405 RefPtr<DataSourceSurface> temp = Factory::CreateDataSourceSurfaceWithStride( 406 aSurf->GetSize(), aSurf->GetFormat(), aStride); 407 if (NS_WARN_IF(!temp)) { 408 return nullptr; 409 } 410 411 DataSourceSurface::MappedSurface map; 412 if (!temp->Map(DataSourceSurface::MapType::WRITE, &map)) { 413 return nullptr; 414 } 415 416 RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData( 417 BackendType::CAIRO, map.mData, temp->GetSize(), map.mStride, 418 temp->GetFormat()); 419 if (!dt) { 420 temp->Unmap(); 421 return nullptr; 422 } 423 424 dt->SetTransform(Matrix::Scaling(1.0, -1.0) * 425 Matrix::Translation(0.0, aSurf->GetSize().height)); 426 Rect rect(0, 0, aSurf->GetSize().width, aSurf->GetSize().height); 427 dt->DrawSurface( 428 aSurf, rect, rect, DrawSurfaceOptions(), 429 DrawOptions(1.0, CompositionOp::OP_SOURCE, AntialiasMode::NONE)); 430 temp->Unmap(); 431 return temp.forget(); 432 } 433 434 already_AddRefed<DataSourceSurface> ReadBackSurface(GLContext* gl, 435 GLuint aTexture, 436 bool aYInvert, 437 SurfaceFormat aFormat) { 438 gl->MakeCurrent(); 439 gl->fActiveTexture(LOCAL_GL_TEXTURE0); 440 gl->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); 441 442 IntSize size; 443 gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, 444 &size.width); 445 gl->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, 446 &size.height); 447 448 RefPtr<DataSourceSurface> surf = Factory::CreateDataSourceSurfaceWithStride( 449 size, SurfaceFormat::B8G8R8A8, 450 GetAlignedStride<4>(size.width, BytesPerPixel(SurfaceFormat::B8G8R8A8))); 451 452 if (NS_WARN_IF(!surf)) { 453 return nullptr; 454 } 455 456 uint32_t currentPackAlignment = 0; 457 gl->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT, (GLint*)¤tPackAlignment); 458 if (currentPackAlignment != 4) { 459 gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4); 460 } 461 462 DataSourceSurface::ScopedMap map(surf, DataSourceSurface::READ); 463 gl->fGetTexImage(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, 464 LOCAL_GL_UNSIGNED_BYTE, map.GetData()); 465 466 if (currentPackAlignment != 4) { 467 gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment); 468 } 469 470 if (aFormat == SurfaceFormat::R8G8B8A8 || 471 aFormat == SurfaceFormat::R8G8B8X8) { 472 SwapRAndBComponents(surf); 473 } 474 475 if (aYInvert) { 476 surf = YInvertImageSurface(surf, map.GetStride()); 477 } 478 479 return surf.forget(); 480 } 481 482 #define CLEANUP_IF_GLERROR_OCCURRED(x) \ 483 if (DidGLErrorOccur(x)) { \ 484 return false; \ 485 } 486 487 already_AddRefed<DataSourceSurface> GLReadTexImageHelper::ReadTexImage( 488 GLuint aTextureId, GLenum aTextureTarget, const gfx::IntSize& aSize, 489 const gfx::Matrix4x4& aTexMatrix, 490 /* ShaderConfigOGL.mFeature */ int aConfig, bool aYInvert) { 491 /* Allocate resulting image surface */ 492 int32_t stride = aSize.width * BytesPerPixel(SurfaceFormat::R8G8B8A8); 493 RefPtr<DataSourceSurface> isurf = Factory::CreateDataSourceSurfaceWithStride( 494 aSize, SurfaceFormat::R8G8B8A8, stride); 495 if (NS_WARN_IF(!isurf)) { 496 return nullptr; 497 } 498 499 if (!ReadTexImage(isurf, aTextureId, aTextureTarget, aSize, aTexMatrix, 500 aConfig, aYInvert)) { 501 return nullptr; 502 } 503 504 return isurf.forget(); 505 } 506 507 bool GLReadTexImageHelper::ReadTexImage( 508 DataSourceSurface* aDest, GLuint aTextureId, GLenum aTextureTarget, 509 const gfx::IntSize& aSize, const gfx::Matrix4x4& aTexMatrix, 510 /* ShaderConfigOGL.mFeature */ int aConfig, bool aYInvert) { 511 MOZ_ASSERT(aTextureTarget == LOCAL_GL_TEXTURE_2D || 512 aTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL || 513 aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB); 514 515 mGL->MakeCurrent(); 516 517 GLint oldrb, oldfb, oldprog, oldTexUnit, oldTex; 518 GLuint rb, fb; 519 520 do { 521 mGL->fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING, &oldrb); 522 mGL->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING, &oldfb); 523 mGL->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM, &oldprog); 524 mGL->fGetIntegerv(LOCAL_GL_ACTIVE_TEXTURE, &oldTexUnit); 525 mGL->fActiveTexture(LOCAL_GL_TEXTURE0); 526 switch (aTextureTarget) { 527 case LOCAL_GL_TEXTURE_2D: 528 mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex); 529 break; 530 case LOCAL_GL_TEXTURE_EXTERNAL: 531 mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &oldTex); 532 break; 533 case LOCAL_GL_TEXTURE_RECTANGLE: 534 mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE, &oldTex); 535 break; 536 default: /* Already checked above */ 537 break; 538 } 539 540 ScopedGLState scopedScissorTestState(mGL, LOCAL_GL_SCISSOR_TEST, false); 541 ScopedGLState scopedBlendState(mGL, LOCAL_GL_BLEND, false); 542 ScopedViewportRect scopedViewportRect(mGL, 0, 0, aSize.width, aSize.height); 543 544 /* Setup renderbuffer */ 545 mGL->fGenRenderbuffers(1, &rb); 546 mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, rb); 547 548 GLenum rbInternalFormat = 549 mGL->IsGLES() ? (mGL->IsExtensionSupported(GLContext::OES_rgb8_rgba8) 550 ? LOCAL_GL_RGBA8 551 : LOCAL_GL_RGBA4) 552 : LOCAL_GL_RGBA; 553 mGL->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, rbInternalFormat, 554 aSize.width, aSize.height); 555 CLEANUP_IF_GLERROR_OCCURRED("when binding and creating renderbuffer"); 556 557 /* Setup framebuffer */ 558 mGL->fGenFramebuffers(1, &fb); 559 mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb); 560 mGL->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, 561 LOCAL_GL_COLOR_ATTACHMENT0, 562 LOCAL_GL_RENDERBUFFER, rb); 563 CLEANUP_IF_GLERROR_OCCURRED("when binding and creating framebuffer"); 564 565 MOZ_ASSERT(mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER) == 566 LOCAL_GL_FRAMEBUFFER_COMPLETE); 567 568 /* Setup vertex and fragment shader */ 569 GLuint program = TextureImageProgramFor(aTextureTarget, aConfig); 570 MOZ_ASSERT(program); 571 572 mGL->fUseProgram(program); 573 CLEANUP_IF_GLERROR_OCCURRED("when using program"); 574 mGL->fUniform1i(mGL->fGetUniformLocation(program, "uTexture"), 0); 575 CLEANUP_IF_GLERROR_OCCURRED("when setting uniform uTexture"); 576 mGL->fUniformMatrix4fv(mGL->fGetUniformLocation(program, "uTexMatrix"), 1, 577 false, aTexMatrix.components); 578 CLEANUP_IF_GLERROR_OCCURRED("when setting uniform uTexMatrix"); 579 580 /* Setup quad geometry */ 581 mGL->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); 582 583 float w = (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) 584 ? (float)aSize.width 585 : 1.0f; 586 float h = (aTextureTarget == LOCAL_GL_TEXTURE_RECTANGLE) 587 ? (float)aSize.height 588 : 1.0f; 589 590 const float vertexArray[4 * 2] = {-1.0f, -1.0f, 1.0f, -1.0f, 591 -1.0f, 1.0f, 1.0f, 1.0f}; 592 ScopedVertexAttribPointer autoAttrib0(mGL, 0, 2, LOCAL_GL_FLOAT, 593 LOCAL_GL_FALSE, 0, 0, vertexArray); 594 595 const float u0 = 0.0f; 596 const float u1 = w; 597 const float v0 = aYInvert ? h : 0.0f; 598 const float v1 = aYInvert ? 0.0f : h; 599 const float texCoordArray[8] = {u0, v0, u1, v0, u0, v1, u1, v1}; 600 ScopedVertexAttribPointer autoAttrib1(mGL, 1, 2, LOCAL_GL_FLOAT, 601 LOCAL_GL_FALSE, 0, 0, texCoordArray); 602 603 /* Bind the texture */ 604 if (aTextureId) { 605 mGL->fBindTexture(aTextureTarget, aTextureId); 606 CLEANUP_IF_GLERROR_OCCURRED("when binding texture"); 607 } 608 609 mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); 610 CLEANUP_IF_GLERROR_OCCURRED("when drawing texture"); 611 612 /* Read-back draw results */ 613 ReadPixelsIntoDataSurface(mGL, aDest); 614 CLEANUP_IF_GLERROR_OCCURRED("when reading pixels into surface"); 615 } while (false); 616 617 /* Restore GL state */ 618 mGL->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, oldrb); 619 mGL->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, oldfb); 620 mGL->fUseProgram(oldprog); 621 622 // note that deleting 0 has no effect in any of these calls 623 mGL->fDeleteRenderbuffers(1, &rb); 624 mGL->fDeleteFramebuffers(1, &fb); 625 626 if (aTextureId) mGL->fBindTexture(aTextureTarget, oldTex); 627 628 if (oldTexUnit != LOCAL_GL_TEXTURE0) mGL->fActiveTexture(oldTexUnit); 629 630 return true; 631 } 632 633 #undef CLEANUP_IF_GLERROR_OCCURRED 634 635 } // namespace gl 636 } // namespace mozilla