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