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 "GLReadTexImageHelper.h"
11 #include "GLContext.h"
12 #include "OGLShaderProgram.h"
13 #include "ScopedGLHelpers.h"
15 #include "mozilla/gfx/2D.h"
16 #include "mozilla/Move.h"
21 using namespace mozilla::gfx
;
23 GLReadTexImageHelper::GLReadTexImageHelper(GLContext
* gl
)
32 GLReadTexImageHelper::~GLReadTexImageHelper()
34 mGL
->fDeleteProgram(mPrograms
[0]);
35 mGL
->fDeleteProgram(mPrograms
[1]);
36 mGL
->fDeleteProgram(mPrograms
[2]);
37 mGL
->fDeleteProgram(mPrograms
[3]);
41 readTextureImageVS
[] =
42 "attribute vec2 aVertex;\n"
43 "attribute vec2 aTexCoord;\n"
44 "varying vec2 vTexCoord;\n"
45 "void main() { gl_Position = vec4(aVertex, 0, 1); vTexCoord = aTexCoord; }";
48 readTextureImageFS_TEXTURE_2D
[] =
50 "precision mediump float;\n"
52 "varying vec2 vTexCoord;\n"
53 "uniform sampler2D uTexture;\n"
54 "void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }";
58 readTextureImageFS_TEXTURE_2D_BGRA
[] =
60 "precision mediump float;\n"
62 "varying vec2 vTexCoord;\n"
63 "uniform sampler2D uTexture;\n"
64 "void main() { gl_FragColor = texture2D(uTexture, vTexCoord).bgra; }";
67 readTextureImageFS_TEXTURE_EXTERNAL
[] =
68 "#extension GL_OES_EGL_image_external : require\n"
70 "precision mediump float;\n"
72 "varying vec2 vTexCoord;\n"
73 "uniform samplerExternalOES uTexture;\n"
74 "void main() { gl_FragColor = texture2D(uTexture, vTexCoord); }";
77 readTextureImageFS_TEXTURE_RECTANGLE
[] =
78 "#extension GL_ARB_texture_rectangle\n"
80 "precision mediump float;\n"
82 "varying vec2 vTexCoord;\n"
83 "uniform sampler2DRect uTexture;\n"
84 "void main() { gl_FragColor = texture2DRect(uTexture, vTexCoord).bgra; }";
87 GLReadTexImageHelper::TextureImageProgramFor(GLenum aTextureTarget
,
91 const GLchar
* readTextureImageFS
= nullptr;
92 if (aTextureTarget
== LOCAL_GL_TEXTURE_2D
) {
93 if (aConfig
& mozilla::layers::ENABLE_TEXTURE_RB_SWAP
) {
94 // Need to swizzle R/B.
95 readTextureImageFS
= readTextureImageFS_TEXTURE_2D_BGRA
;
98 readTextureImageFS
= readTextureImageFS_TEXTURE_2D
;
101 } else if (aTextureTarget
== LOCAL_GL_TEXTURE_EXTERNAL
) {
102 readTextureImageFS
= readTextureImageFS_TEXTURE_EXTERNAL
;
104 } else if (aTextureTarget
== LOCAL_GL_TEXTURE_RECTANGLE
) {
105 readTextureImageFS
= readTextureImageFS_TEXTURE_RECTANGLE
;
109 /* This might be overkill, but assure that we don't access out-of-bounds */
110 MOZ_ASSERT((size_t) variant
< ArrayLength(mPrograms
));
111 if (!mPrograms
[variant
]) {
112 GLuint vs
= mGL
->fCreateShader(LOCAL_GL_VERTEX_SHADER
);
113 const GLchar
* vsSourcePtr
= &readTextureImageVS
[0];
114 mGL
->fShaderSource(vs
, 1, &vsSourcePtr
, nullptr);
115 mGL
->fCompileShader(vs
);
117 GLuint fs
= mGL
->fCreateShader(LOCAL_GL_FRAGMENT_SHADER
);
118 mGL
->fShaderSource(fs
, 1, &readTextureImageFS
, nullptr);
119 mGL
->fCompileShader(fs
);
121 GLuint program
= mGL
->fCreateProgram();
122 mGL
->fAttachShader(program
, vs
);
123 mGL
->fAttachShader(program
, fs
);
124 mGL
->fBindAttribLocation(program
, 0, "aVertex");
125 mGL
->fBindAttribLocation(program
, 1, "aTexCoord");
126 mGL
->fLinkProgram(program
);
129 mGL
->fGetProgramiv(program
, LOCAL_GL_LINK_STATUS
, &success
);
132 mGL
->fDeleteProgram(program
);
136 mGL
->fDeleteShader(vs
);
137 mGL
->fDeleteShader(fs
);
139 mPrograms
[variant
] = program
;
142 return mPrograms
[variant
];
146 GLReadTexImageHelper::DidGLErrorOccur(const char* str
)
148 GLenum error
= mGL
->fGetError();
149 if (error
!= LOCAL_GL_NO_ERROR
) {
150 printf_stderr("GL ERROR: %s (0x%04x) %s\n",
151 mGL
->GLErrorToString(error
), error
, str
);
159 GetActualReadFormats(GLContext
* gl
,
160 GLenum destFormat
, GLenum destType
,
161 GLenum
* out_readFormat
, GLenum
* out_readType
)
163 MOZ_ASSERT(out_readFormat
);
164 MOZ_ASSERT(out_readType
);
166 if (destFormat
== LOCAL_GL_RGBA
&&
167 destType
== LOCAL_GL_UNSIGNED_BYTE
)
169 *out_readFormat
= destFormat
;
170 *out_readType
= destType
;
174 bool fallback
= true;
176 GLenum auxFormat
= 0;
179 gl
->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT
, (GLint
*)&auxFormat
);
180 gl
->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE
, (GLint
*)&auxType
);
182 if (destFormat
== auxFormat
&&
188 switch (destFormat
) {
190 if (destType
== LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV
)
194 case LOCAL_GL_BGRA
: {
195 if (destType
== LOCAL_GL_UNSIGNED_BYTE
||
196 destType
== LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV
)
206 *out_readFormat
= LOCAL_GL_RGBA
;
207 *out_readType
= LOCAL_GL_UNSIGNED_BYTE
;
210 *out_readFormat
= destFormat
;
211 *out_readType
= destType
;
217 SwapRAndBComponents(DataSourceSurface
* surf
)
219 DataSourceSurface::MappedSurface map
;
220 MOZ_ALWAYS_TRUE( surf
->Map(DataSourceSurface::MapType::READ_WRITE
, &map
) );
221 MOZ_ASSERT(map
.mStride
>= 0);
223 const size_t rowBytes
= surf
->GetSize().width
*4;
224 const size_t rowHole
= map
.mStride
- rowBytes
;
226 uint8_t* row
= map
.mData
;
228 MOZ_ASSERT(false, "SwapRAndBComponents: Failed to get data from"
229 " DataSourceSurface.");
234 const size_t rows
= surf
->GetSize().height
;
235 for (size_t i
= 0; i
< rows
; i
++) {
236 const uint8_t* rowEnd
= row
+ rowBytes
;
238 while (row
!= rowEnd
) {
239 Swap(row
[0], row
[2]);
250 PackRGB565(uint8_t r
, uint8_t g
, uint8_t b
)
252 uint16_t pixel
= ((r
<< 11) & 0xf800) |
253 ((g
<< 5) & 0x07e0) |
260 CopyDataSourceSurface(DataSourceSurface
* aSource
,
261 DataSourceSurface
* aDest
)
263 // Don't worry too much about speed.
264 MOZ_ASSERT(aSource
->GetSize() == aDest
->GetSize());
265 MOZ_ASSERT(aSource
->GetFormat() == SurfaceFormat::R8G8B8A8
||
266 aSource
->GetFormat() == SurfaceFormat::R8G8B8X8
||
267 aSource
->GetFormat() == SurfaceFormat::B8G8R8A8
||
268 aSource
->GetFormat() == SurfaceFormat::B8G8R8X8
);
269 MOZ_ASSERT(aDest
->GetFormat() == SurfaceFormat::R8G8B8A8
||
270 aDest
->GetFormat() == SurfaceFormat::R8G8B8X8
||
271 aDest
->GetFormat() == SurfaceFormat::B8G8R8A8
||
272 aDest
->GetFormat() == SurfaceFormat::B8G8R8X8
||
273 aDest
->GetFormat() == SurfaceFormat::R5G6B5
);
275 const bool isSrcBGR
= aSource
->GetFormat() == SurfaceFormat::B8G8R8A8
||
276 aSource
->GetFormat() == SurfaceFormat::B8G8R8X8
;
277 const bool isDestBGR
= aDest
->GetFormat() == SurfaceFormat::B8G8R8A8
||
278 aDest
->GetFormat() == SurfaceFormat::B8G8R8X8
;
279 const bool needsSwap02
= isSrcBGR
!= isDestBGR
;
281 const bool srcHasAlpha
= aSource
->GetFormat() == SurfaceFormat::R8G8B8A8
||
282 aSource
->GetFormat() == SurfaceFormat::B8G8R8A8
;
283 const bool destHasAlpha
= aDest
->GetFormat() == SurfaceFormat::R8G8B8A8
||
284 aDest
->GetFormat() == SurfaceFormat::B8G8R8A8
;
285 const bool needsAlphaMask
= !srcHasAlpha
&& destHasAlpha
;
287 const bool needsConvertTo16Bits
= aDest
->GetFormat() == SurfaceFormat::R5G6B5
;
289 DataSourceSurface::MappedSurface srcMap
;
290 DataSourceSurface::MappedSurface destMap
;
291 MOZ_ALWAYS_TRUE( aSource
->Map(DataSourceSurface::MapType::READ
, &srcMap
) );
292 MOZ_ALWAYS_TRUE( aDest
->Map(DataSourceSurface::MapType::WRITE
, &destMap
) );
293 MOZ_ASSERT(srcMap
.mStride
>= 0);
294 MOZ_ASSERT(destMap
.mStride
>= 0);
296 const size_t srcBPP
= BytesPerPixel(aSource
->GetFormat());
297 const size_t srcRowBytes
= aSource
->GetSize().width
* srcBPP
;
298 const size_t srcRowHole
= srcMap
.mStride
- srcRowBytes
;
300 const size_t destBPP
= BytesPerPixel(aDest
->GetFormat());
301 const size_t destRowBytes
= aDest
->GetSize().width
* destBPP
;
302 const size_t destRowHole
= destMap
.mStride
- destRowBytes
;
304 uint8_t* srcRow
= srcMap
.mData
;
305 uint8_t* destRow
= destMap
.mData
;
306 const size_t rows
= aSource
->GetSize().height
;
307 for (size_t i
= 0; i
< rows
; i
++) {
308 const uint8_t* srcRowEnd
= srcRow
+ srcRowBytes
;
310 while (srcRow
!= srcRowEnd
) {
311 uint8_t d0
= needsSwap02
? srcRow
[2] : srcRow
[0];
312 uint8_t d1
= srcRow
[1];
313 uint8_t d2
= needsSwap02
? srcRow
[0] : srcRow
[2];
314 uint8_t d3
= needsAlphaMask
? 0xff : srcRow
[3];
316 if (needsConvertTo16Bits
) {
317 *(uint16_t*)destRow
= PackRGB565(d0
, d1
, d2
);
328 srcRow
+= srcRowHole
;
329 destRow
+= destRowHole
;
337 CalcRowStride(int width
, int pixelSize
, int alignment
)
339 MOZ_ASSERT(alignment
);
341 int rowStride
= width
* pixelSize
;
342 if (rowStride
% alignment
) { // Extra at the end of the line?
343 int alignmentCount
= rowStride
/ alignment
;
344 rowStride
= (alignmentCount
+1) * alignment
;
350 GuessAlignment(int width
, int pixelSize
, int rowStride
)
352 int alignment
= 8; // Max GLES allows.
353 while (CalcRowStride(width
, pixelSize
, alignment
) != rowStride
) {
356 NS_WARNING("Bad alignment for GLES. Will use temp surf for readback.");
364 ReadPixelsIntoDataSurface(GLContext
* gl
, DataSourceSurface
* dest
)
367 MOZ_ASSERT(dest
->GetSize().width
!= 0);
368 MOZ_ASSERT(dest
->GetSize().height
!= 0);
370 bool hasAlpha
= dest
->GetFormat() == SurfaceFormat::B8G8R8A8
||
371 dest
->GetFormat() == SurfaceFormat::R8G8B8A8
;
377 switch (dest
->GetFormat()) {
378 case SurfaceFormat::B8G8R8A8
:
379 case SurfaceFormat::B8G8R8X8
:
380 // Needs host (little) endian ARGB.
381 destFormat
= LOCAL_GL_BGRA
;
382 destType
= LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV
;
384 case SurfaceFormat::R8G8B8A8
:
385 case SurfaceFormat::R8G8B8X8
:
386 // Needs host (little) endian ABGR.
387 destFormat
= LOCAL_GL_RGBA
;
388 destType
= LOCAL_GL_UNSIGNED_BYTE
;
390 case SurfaceFormat::R5G6B5
:
391 destFormat
= LOCAL_GL_RGB
;
392 destType
= LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV
;
395 MOZ_CRASH("Bad format.");
397 destPixelSize
= BytesPerPixel(dest
->GetFormat());
398 MOZ_ASSERT(dest
->GetSize().width
* destPixelSize
<= dest
->Stride());
400 GLenum readFormat
= destFormat
;
401 GLenum readType
= destType
;
402 bool needsTempSurf
= !GetActualReadFormats(gl
,
403 destFormat
, destType
,
404 &readFormat
, &readType
);
406 RefPtr
<DataSourceSurface
> tempSurf
;
407 DataSourceSurface
* readSurf
= dest
;
408 int readAlignment
= GuessAlignment(dest
->GetSize().width
,
411 if (!readAlignment
) {
412 needsTempSurf
= true;
415 if (gl
->DebugMode()) {
416 NS_WARNING("Needing intermediary surface for ReadPixels. This will be slow!");
418 SurfaceFormat readFormatGFX
;
420 switch (readFormat
) {
421 case LOCAL_GL_RGBA
: {
422 readFormatGFX
= hasAlpha
? SurfaceFormat::R8G8B8A8
423 : SurfaceFormat::R8G8B8X8
;
426 case LOCAL_GL_BGRA
: {
427 readFormatGFX
= hasAlpha
? SurfaceFormat::B8G8R8A8
428 : SurfaceFormat::B8G8R8X8
;
432 MOZ_ASSERT(destPixelSize
== 2);
433 MOZ_ASSERT(readType
== LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV
);
434 readFormatGFX
= SurfaceFormat::R5G6B5
;
438 MOZ_CRASH("Bad read format.");
443 case LOCAL_GL_UNSIGNED_BYTE
: {
444 MOZ_ASSERT(readFormat
== LOCAL_GL_RGBA
);
448 case LOCAL_GL_UNSIGNED_INT_8_8_8_8_REV
: {
449 MOZ_ASSERT(readFormat
== LOCAL_GL_BGRA
);
453 case LOCAL_GL_UNSIGNED_SHORT_5_6_5_REV
: {
454 MOZ_ASSERT(readFormat
== LOCAL_GL_RGB
);
459 MOZ_CRASH("Bad read type.");
463 int32_t stride
= dest
->GetSize().width
* BytesPerPixel(readFormatGFX
);
464 tempSurf
= Factory::CreateDataSourceSurfaceWithStride(dest
->GetSize(),
467 if (NS_WARN_IF(!tempSurf
)) {
473 MOZ_ASSERT(readAlignment
);
474 MOZ_ASSERT(reinterpret_cast<uintptr_t>(readSurf
->GetData()) % readAlignment
== 0);
476 GLint currentPackAlignment
= 0;
477 gl
->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT
, ¤tPackAlignment
);
479 if (currentPackAlignment
!= readAlignment
)
480 gl
->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT
, readAlignment
);
482 GLsizei width
= dest
->GetSize().width
;
483 GLsizei height
= dest
->GetSize().height
;
485 gl
->fReadPixels(0, 0,
487 readFormat
, readType
,
488 readSurf
->GetData());
490 if (currentPackAlignment
!= readAlignment
)
491 gl
->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT
, currentPackAlignment
);
493 if (readSurf
!= dest
) {
494 MOZ_ASSERT(readFormat
== LOCAL_GL_RGBA
);
495 MOZ_ASSERT(readType
== LOCAL_GL_UNSIGNED_BYTE
);
496 CopyDataSourceSurface(readSurf
, dest
);
499 // Check if GL is giving back 1.0 alpha for
500 // RGBA reads to RGBA images from no-alpha buffers.
502 if (gl
->WorkAroundDriverBugs() &&
503 gl
->Vendor() == gl::GLVendor::NVIDIA
&&
508 gl
->fGetIntegerv(LOCAL_GL_ALPHA_BITS
, &alphaBits
);
510 const uint32_t alphaMask
= gfxPackedPixelNoPreMultiply(0xff,0,0,0);
512 MOZ_ASSERT(dest
->GetSize().width
* destPixelSize
== dest
->Stride());
514 uint32_t* itr
= (uint32_t*)dest
->GetData();
515 uint32_t testPixel
= *itr
;
516 if ((testPixel
& alphaMask
) != alphaMask
) {
517 // We need to set the alpha channel to 1.0 manually.
518 uint32_t* itrEnd
= itr
+ width
*height
; // Stride is guaranteed to be width*4.
520 for (; itr
!= itrEnd
; itr
++) {
529 static TemporaryRef
<DataSourceSurface
>
530 YInvertImageSurface(DataSourceSurface
* aSurf
)
532 RefPtr
<DataSourceSurface
> temp
=
533 Factory::CreateDataSourceSurfaceWithStride(aSurf
->GetSize(),
536 if (NS_WARN_IF(!temp
)) {
540 DataSourceSurface::MappedSurface map
;
541 if (!temp
->Map(DataSourceSurface::MapType::WRITE
, &map
)) {
545 RefPtr
<DrawTarget
> dt
=
546 Factory::CreateDrawTargetForData(BackendType::CAIRO
,
556 dt
->SetTransform(Matrix::Translation(0.0, aSurf
->GetSize().height
) *
557 Matrix::Scaling(1.0, -1.0));
558 Rect
rect(0, 0, aSurf
->GetSize().width
, aSurf
->GetSize().height
);
559 dt
->DrawSurface(aSurf
, rect
, rect
, DrawSurfaceOptions(),
560 DrawOptions(1.0, CompositionOp::OP_SOURCE
, AntialiasMode::NONE
));
562 return temp
.forget();
565 TemporaryRef
<DataSourceSurface
>
566 ReadBackSurface(GLContext
* gl
, GLuint aTexture
, bool aYInvert
, SurfaceFormat aFormat
)
569 gl
->GuaranteeResolve();
570 gl
->fActiveTexture(LOCAL_GL_TEXTURE0
);
571 gl
->fBindTexture(LOCAL_GL_TEXTURE_2D
, aTexture
);
574 gl
->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D
, 0, LOCAL_GL_TEXTURE_WIDTH
, &size
.width
);
575 gl
->fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D
, 0, LOCAL_GL_TEXTURE_HEIGHT
, &size
.height
);
577 RefPtr
<DataSourceSurface
> surf
=
578 Factory::CreateDataSourceSurfaceWithStride(size
, SurfaceFormat::B8G8R8A8
,
579 GetAlignedStride
<4>(size
.width
* BytesPerPixel(SurfaceFormat::B8G8R8A8
)));
581 if (NS_WARN_IF(!surf
)) {
585 uint32_t currentPackAlignment
= 0;
586 gl
->fGetIntegerv(LOCAL_GL_PACK_ALIGNMENT
, (GLint
*)¤tPackAlignment
);
587 if (currentPackAlignment
!= 4) {
588 gl
->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT
, 4);
591 gl
->fGetTexImage(LOCAL_GL_TEXTURE_2D
, 0, LOCAL_GL_RGBA
, LOCAL_GL_UNSIGNED_BYTE
, surf
->GetData());
593 if (currentPackAlignment
!= 4) {
594 gl
->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT
, currentPackAlignment
);
597 if (aFormat
== SurfaceFormat::R8G8B8A8
|| aFormat
== SurfaceFormat::R8G8B8X8
) {
598 SwapRAndBComponents(surf
);
602 surf
= YInvertImageSurface(surf
);
605 return surf
.forget();
608 #define CLEANUP_IF_GLERROR_OCCURRED(x) \
609 if (DidGLErrorOccur(x)) { \
614 TemporaryRef
<DataSourceSurface
>
615 GLReadTexImageHelper::ReadTexImage(GLuint aTextureId
,
616 GLenum aTextureTarget
,
617 const gfx::IntSize
& aSize
,
618 /* ShaderConfigOGL.mFeature */ int aConfig
,
621 MOZ_ASSERT(aTextureTarget
== LOCAL_GL_TEXTURE_2D
||
622 aTextureTarget
== LOCAL_GL_TEXTURE_EXTERNAL
||
623 aTextureTarget
== LOCAL_GL_TEXTURE_RECTANGLE_ARB
);
627 /* Allocate resulting image surface */
628 int32_t stride
= aSize
.width
* BytesPerPixel(SurfaceFormat::R8G8B8A8
);
629 RefPtr
<DataSourceSurface
> isurf
=
630 Factory::CreateDataSourceSurfaceWithStride(aSize
,
631 SurfaceFormat::R8G8B8A8
,
633 if (NS_WARN_IF(!isurf
)) {
637 GLint oldrb
, oldfb
, oldprog
, oldTexUnit
, oldTex
;
641 mGL
->fGetIntegerv(LOCAL_GL_RENDERBUFFER_BINDING
, &oldrb
);
642 mGL
->fGetIntegerv(LOCAL_GL_FRAMEBUFFER_BINDING
, &oldfb
);
643 mGL
->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM
, &oldprog
);
644 mGL
->fGetIntegerv(LOCAL_GL_ACTIVE_TEXTURE
, &oldTexUnit
);
645 mGL
->fActiveTexture(LOCAL_GL_TEXTURE0
);
646 switch (aTextureTarget
) {
647 case LOCAL_GL_TEXTURE_2D
:
648 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D
, &oldTex
);
650 case LOCAL_GL_TEXTURE_EXTERNAL
:
651 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL
, &oldTex
);
653 case LOCAL_GL_TEXTURE_RECTANGLE
:
654 mGL
->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_RECTANGLE
, &oldTex
);
656 default: /* Already checked above */
660 ScopedGLState
scopedScissorTestState(mGL
, LOCAL_GL_SCISSOR_TEST
, false);
661 ScopedGLState
scopedBlendState(mGL
, LOCAL_GL_BLEND
, false);
662 ScopedViewportRect
scopedViewportRect(mGL
, 0, 0, aSize
.width
, aSize
.height
);
664 /* Setup renderbuffer */
665 mGL
->fGenRenderbuffers(1, &rb
);
666 mGL
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, rb
);
668 GLenum rbInternalFormat
=
670 ? (mGL
->IsExtensionSupported(GLContext::OES_rgb8_rgba8
) ? LOCAL_GL_RGBA8
: LOCAL_GL_RGBA4
)
672 mGL
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
, rbInternalFormat
, aSize
.width
, aSize
.height
);
673 CLEANUP_IF_GLERROR_OCCURRED("when binding and creating renderbuffer");
675 /* Setup framebuffer */
676 mGL
->fGenFramebuffers(1, &fb
);
677 mGL
->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER
, fb
);
678 mGL
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
,
679 LOCAL_GL_RENDERBUFFER
, rb
);
680 CLEANUP_IF_GLERROR_OCCURRED("when binding and creating framebuffer");
682 MOZ_ASSERT(mGL
->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER
) == LOCAL_GL_FRAMEBUFFER_COMPLETE
);
684 /* Setup vertex and fragment shader */
685 GLuint program
= TextureImageProgramFor(aTextureTarget
, aConfig
);
688 mGL
->fUseProgram(program
);
689 CLEANUP_IF_GLERROR_OCCURRED("when using program");
690 mGL
->fUniform1i(mGL
->fGetUniformLocation(program
, "uTexture"), 0);
691 CLEANUP_IF_GLERROR_OCCURRED("when setting uniform location");
693 /* Setup quad geometry */
694 mGL
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, 0);
696 float w
= (aTextureTarget
== LOCAL_GL_TEXTURE_RECTANGLE
) ? (float) aSize
.width
: 1.0f
;
697 float h
= (aTextureTarget
== LOCAL_GL_TEXTURE_RECTANGLE
) ? (float) aSize
.height
: 1.0f
;
706 ScopedVertexAttribPointer
autoAttrib0(mGL
, 0, 2, LOCAL_GL_FLOAT
, LOCAL_GL_FALSE
, 0, 0, vertexArray
);
708 const float u0
= 0.0f
;
710 const float v0
= aYInvert
? h
: 0.0f
;
711 const float v1
= aYInvert
? 0.0f
: h
;
712 const float texCoordArray
[8] = { u0
, v0
,
716 ScopedVertexAttribPointer
autoAttrib1(mGL
, 1, 2, LOCAL_GL_FLOAT
, LOCAL_GL_FALSE
, 0, 0, texCoordArray
);
718 /* Bind the texture */
720 mGL
->fBindTexture(aTextureTarget
, aTextureId
);
721 CLEANUP_IF_GLERROR_OCCURRED("when binding texture");
725 mGL
->fClearColor(1.0f
, 0.0f
, 1.0f
, 1.0f
);
726 mGL
->fClear(LOCAL_GL_COLOR_BUFFER_BIT
);
727 CLEANUP_IF_GLERROR_OCCURRED("when clearing color buffer");
729 mGL
->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP
, 0, 4);
730 CLEANUP_IF_GLERROR_OCCURRED("when drawing texture");
732 /* Read-back draw results */
733 ReadPixelsIntoDataSurface(mGL
, isurf
);
734 CLEANUP_IF_GLERROR_OCCURRED("when reading pixels into surface");
737 /* Restore GL state */
738 mGL
->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER
, oldrb
);
739 mGL
->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER
, oldfb
);
740 mGL
->fUseProgram(oldprog
);
742 // note that deleting 0 has no effect in any of these calls
743 mGL
->fDeleteRenderbuffers(1, &rb
);
744 mGL
->fDeleteFramebuffers(1, &fb
);
747 mGL
->fBindTexture(aTextureTarget
, oldTex
);
749 if (oldTexUnit
!= LOCAL_GL_TEXTURE0
)
750 mGL
->fActiveTexture(oldTexUnit
);
752 return isurf
.forget();
755 #undef CLEANUP_IF_GLERROR_OCCURRED