blob: d9c840e619727c52453b43cbb7000e64ef4a0f77 [file] [log] [blame]
Brian Paul28876dd2008-06-09 14:22:15 -06001/*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include "glheader.h"
26#include "imports.h"
27#include "bufferobj.h"
28#include "context.h"
Brian Paul6364d752011-02-18 09:53:29 -070029#include "enums.h"
Brian Paul28876dd2008-06-09 14:22:15 -060030#include "readpix.h"
31#include "framebuffer.h"
Brian Paul751e10f2010-10-25 19:07:33 -060032#include "formats.h"
Brian Pauld2a23d42011-11-12 11:50:31 -070033#include "format_unpack.h"
Brian Paul28876dd2008-06-09 14:22:15 -060034#include "image.h"
Vinson Lee0117da42011-01-05 23:11:54 -080035#include "mtypes.h"
Brian Pauld2a23d42011-11-12 11:50:31 -070036#include "pack.h"
Brian Paulb70610b2011-02-28 18:24:35 -070037#include "pbo.h"
Brian Paul28876dd2008-06-09 14:22:15 -060038#include "state.h"
Jordan Justen9ad8f432012-06-25 10:52:39 -070039#include "glformats.h"
Paul Berry284ad9c2012-07-18 12:54:48 -070040#include "fbobject.h"
Brian Paul28876dd2008-06-09 14:22:15 -060041
42
43/**
Brian Pauld2a23d42011-11-12 11:50:31 -070044 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
45 * mapping.
46 */
47static GLboolean
48fast_read_depth_pixels( struct gl_context *ctx,
49 GLint x, GLint y,
50 GLsizei width, GLsizei height,
51 GLenum type, GLvoid *pixels,
52 const struct gl_pixelstore_attrib *packing )
53{
54 struct gl_framebuffer *fb = ctx->ReadBuffer;
55 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
56 GLubyte *map, *dst;
57 int stride, dstStride, j;
58
59 if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0)
60 return GL_FALSE;
61
62 if (packing->SwapBytes)
63 return GL_FALSE;
64
Eric Anholt755f0a02011-11-17 13:56:30 -080065 if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
Brian Pauld2a23d42011-11-12 11:50:31 -070066 return GL_FALSE;
67
68 if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) ||
69 type == GL_UNSIGNED_INT))
70 return GL_FALSE;
71
72 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
73 &map, &stride);
74
Brian Paul038a7df2011-11-17 17:20:05 -070075 if (!map) {
76 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
77 return GL_TRUE; /* don't bother trying the slow path */
78 }
79
Brian Pauld2a23d42011-11-12 11:50:31 -070080 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
81 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
82 GL_DEPTH_COMPONENT, type, 0, 0);
83
84 for (j = 0; j < height; j++) {
85 if (type == GL_UNSIGNED_INT) {
86 _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
87 } else {
88 ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16);
89 memcpy(dst, map, width * 2);
90 }
91
92 map += stride;
93 dst += dstStride;
94 }
95 ctx->Driver.UnmapRenderbuffer(ctx, rb);
96
97 return GL_TRUE;
98}
99
100/**
101 * Read pixels for format=GL_DEPTH_COMPONENT.
102 */
103static void
104read_depth_pixels( struct gl_context *ctx,
105 GLint x, GLint y,
106 GLsizei width, GLsizei height,
107 GLenum type, GLvoid *pixels,
108 const struct gl_pixelstore_attrib *packing )
109{
110 struct gl_framebuffer *fb = ctx->ReadBuffer;
111 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
112 GLint j;
113 GLubyte *dst, *map;
114 int dstStride, stride;
Brian Paul531eaca2012-02-19 20:08:51 -0700115 GLfloat *depthValues;
Brian Pauld2a23d42011-11-12 11:50:31 -0700116
117 if (!rb)
118 return;
119
120 /* clipping should have been done already */
121 ASSERT(x >= 0);
122 ASSERT(y >= 0);
123 ASSERT(x + width <= (GLint) rb->Width);
124 ASSERT(y + height <= (GLint) rb->Height);
Brian Pauld2a23d42011-11-12 11:50:31 -0700125
126 if (fast_read_depth_pixels(ctx, x, y, width, height, type, pixels, packing))
127 return;
128
129 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
130 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
131 GL_DEPTH_COMPONENT, type, 0, 0);
132
133 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
134 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700135 if (!map) {
136 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
137 return;
138 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700139
Matt Turner2b7a9722012-09-03 19:44:00 -0700140 depthValues = malloc(width * sizeof(GLfloat));
Brian Pauld2a23d42011-11-12 11:50:31 -0700141
Brian Paul531eaca2012-02-19 20:08:51 -0700142 if (depthValues) {
143 /* General case (slower) */
144 for (j = 0; j < height; j++, y++) {
145 _mesa_unpack_float_z_row(rb->Format, width, map, depthValues);
146 _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing);
147
148 dst += dstStride;
149 map += stride;
150 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700151 }
Brian Paul531eaca2012-02-19 20:08:51 -0700152 else {
153 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
154 }
155
156 free(depthValues);
Brian Pauld2a23d42011-11-12 11:50:31 -0700157
158 ctx->Driver.UnmapRenderbuffer(ctx, rb);
159}
160
161
162/**
163 * Read pixels for format=GL_STENCIL_INDEX.
164 */
165static void
166read_stencil_pixels( struct gl_context *ctx,
167 GLint x, GLint y,
168 GLsizei width, GLsizei height,
169 GLenum type, GLvoid *pixels,
170 const struct gl_pixelstore_attrib *packing )
171{
172 struct gl_framebuffer *fb = ctx->ReadBuffer;
173 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
174 GLint j;
Brian Paul531eaca2012-02-19 20:08:51 -0700175 GLubyte *map, *stencil;
Brian Pauld2a23d42011-11-12 11:50:31 -0700176 GLint stride;
177
178 if (!rb)
179 return;
180
Brian Pauld2a23d42011-11-12 11:50:31 -0700181 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
182 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700183 if (!map) {
184 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
185 return;
186 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700187
Matt Turner2b7a9722012-09-03 19:44:00 -0700188 stencil = malloc(width * sizeof(GLubyte));
Brian Pauld2a23d42011-11-12 11:50:31 -0700189
Brian Paul531eaca2012-02-19 20:08:51 -0700190 if (stencil) {
191 /* process image row by row */
192 for (j = 0; j < height; j++) {
193 GLvoid *dest;
Brian Pauld2a23d42011-11-12 11:50:31 -0700194
Brian Paul531eaca2012-02-19 20:08:51 -0700195 _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil);
196 dest = _mesa_image_address2d(packing, pixels, width, height,
197 GL_STENCIL_INDEX, type, j, 0);
Brian Pauld2a23d42011-11-12 11:50:31 -0700198
Brian Paul531eaca2012-02-19 20:08:51 -0700199 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
200
201 map += stride;
202 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700203 }
Brian Paul531eaca2012-02-19 20:08:51 -0700204 else {
205 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
206 }
207
208 free(stencil);
Brian Pauld2a23d42011-11-12 11:50:31 -0700209
210 ctx->Driver.UnmapRenderbuffer(ctx, rb);
211}
212
Brian Paula5e95a42012-04-17 10:49:16 -0600213
214/**
215 * Try to do glReadPixels of RGBA data using a simple memcpy or swizzle.
216 * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
217 */
Brian Pauld2a23d42011-11-12 11:50:31 -0700218static GLboolean
219fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
220 GLint x, GLint y,
221 GLsizei width, GLsizei height,
222 GLenum format, GLenum type,
223 GLvoid *pixels,
224 const struct gl_pixelstore_attrib *packing,
225 GLbitfield transferOps )
226{
227 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
228 GLubyte *dst, *map;
229 int dstStride, stride, j, texelBytes;
Brian Paula5e95a42012-04-17 10:49:16 -0600230 GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE;
Brian Pauld2a23d42011-11-12 11:50:31 -0700231
Brian Paula5e95a42012-04-17 10:49:16 -0600232 /* XXX we could check for other swizzle/special cases here as needed */
233 if (rb->Format == MESA_FORMAT_RGBA8888_REV &&
234 format == GL_BGRA &&
235 type == GL_UNSIGNED_INT_8_8_8_8_REV &&
236 !ctx->Pack.SwapBytes) {
237 swizzle_rb = GL_TRUE;
238 }
239 else if (rb->Format == MESA_FORMAT_XRGB8888 &&
240 format == GL_BGRA &&
241 type == GL_UNSIGNED_INT_8_8_8_8_REV &&
242 !ctx->Pack.SwapBytes) {
243 copy_xrgb = GL_TRUE;
244 }
245 else if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
246 ctx->Pack.SwapBytes))
Brian Pauld2a23d42011-11-12 11:50:31 -0700247 return GL_FALSE;
248
Neil Robertsd9c420972012-02-26 01:33:40 +0000249 /* If the format is unsigned normalized then we can ignore clamping
250 * because the values are already in the range [0,1] so it won't
251 * have any effect anyway.
252 */
253 if (_mesa_get_format_datatype(rb->Format) == GL_UNSIGNED_NORMALIZED)
254 transferOps &= ~IMAGE_CLAMP_BIT;
255
256 if (transferOps)
257 return GL_FALSE;
258
Brian Pauld2a23d42011-11-12 11:50:31 -0700259 dstStride = _mesa_image_row_stride(packing, width, format, type);
260 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
261 format, type, 0, 0);
262
263 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
264 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700265 if (!map) {
266 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
267 return GL_TRUE; /* don't bother trying the slow path */
268 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700269
270 texelBytes = _mesa_get_format_bytes(rb->Format);
Brian Paula5e95a42012-04-17 10:49:16 -0600271
272 if (swizzle_rb) {
273 /* swap R/B */
274 for (j = 0; j < height; j++) {
275 int i;
276 for (i = 0; i < width; i++) {
277 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
278 GLuint pixel = map4[i];
279 dst4[i] = (pixel & 0xff00ff00)
280 | ((pixel & 0x00ff0000) >> 16)
281 | ((pixel & 0x000000ff) << 16);
282 }
283 dst += dstStride;
284 map += stride;
285 }
286 } else if (copy_xrgb) {
287 /* convert xrgb -> argb */
288 for (j = 0; j < height; j++) {
289 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
290 int i;
291 for (i = 0; i < width; i++) {
292 dst4[i] = map4[i] | 0xff000000; /* set A=0xff */
293 }
294 dst += dstStride;
295 map += stride;
296 }
297 } else {
298 /* just memcpy */
299 for (j = 0; j < height; j++) {
300 memcpy(dst, map, width * texelBytes);
301 dst += dstStride;
302 map += stride;
303 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700304 }
305
306 ctx->Driver.UnmapRenderbuffer(ctx, rb);
307
308 return GL_TRUE;
309}
310
Brian Paul72fb25c2011-11-18 17:39:01 -0700311static void
Brian Pauld2a23d42011-11-12 11:50:31 -0700312slow_read_rgba_pixels( struct gl_context *ctx,
313 GLint x, GLint y,
314 GLsizei width, GLsizei height,
315 GLenum format, GLenum type,
316 GLvoid *pixels,
317 const struct gl_pixelstore_attrib *packing,
318 GLbitfield transferOps )
319{
320 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
321 const gl_format rbFormat = _mesa_get_srgb_format_linear(rb->Format);
Brian Paulbf6aac22011-12-05 20:40:48 -0700322 void *rgba;
Brian Pauld2a23d42011-11-12 11:50:31 -0700323 GLubyte *dst, *map;
324 int dstStride, stride, j;
Jordan Justen6671d0d2012-06-25 14:14:25 -0700325 GLboolean dst_is_integer = _mesa_is_enum_format_integer(format);
326 GLboolean dst_is_uint = _mesa_is_format_unsigned(rbFormat);
Brian Pauld2a23d42011-11-12 11:50:31 -0700327
328 dstStride = _mesa_image_row_stride(packing, width, format, type);
329 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
330 format, type, 0, 0);
331
332 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
333 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700334 if (!map) {
335 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
336 return;
337 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700338
Brian Paulbf6aac22011-12-05 20:40:48 -0700339 rgba = malloc(width * MAX_PIXEL_BYTES);
340 if (!rgba)
341 goto done;
342
Brian Pauld2a23d42011-11-12 11:50:31 -0700343 for (j = 0; j < height; j++) {
Jordan Justen6671d0d2012-06-25 14:14:25 -0700344 if (dst_is_integer) {
Brian Paul301fba52012-01-09 08:11:33 -0700345 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
Brian Paulad897ff2012-02-29 20:55:50 -0700346 _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba,
347 rb->_BaseFormat);
Jordan Justen6671d0d2012-06-25 14:14:25 -0700348 if (dst_is_uint) {
349 _mesa_pack_rgba_span_from_uints(ctx, width, (GLuint (*)[4]) rgba, format,
350 type, dst);
351 } else {
352 _mesa_pack_rgba_span_from_ints(ctx, width, (GLint (*)[4]) rgba, format,
353 type, dst);
354 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700355 } else {
Brian Paulbf6aac22011-12-05 20:40:48 -0700356 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba);
Brian Paulad897ff2012-02-29 20:55:50 -0700357 _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba,
358 rb->_BaseFormat);
Brian Paulbf6aac22011-12-05 20:40:48 -0700359 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
360 type, dst, packing, transferOps);
Brian Pauld2a23d42011-11-12 11:50:31 -0700361 }
362 dst += dstStride;
363 map += stride;
364 }
365
Brian Paulbf6aac22011-12-05 20:40:48 -0700366 free(rgba);
367
368done:
Brian Pauld2a23d42011-11-12 11:50:31 -0700369 ctx->Driver.UnmapRenderbuffer(ctx, rb);
Brian Pauld2a23d42011-11-12 11:50:31 -0700370}
371
372/*
373 * Read R, G, B, A, RGB, L, or LA pixels.
374 */
375static void
376read_rgba_pixels( struct gl_context *ctx,
377 GLint x, GLint y,
378 GLsizei width, GLsizei height,
379 GLenum format, GLenum type, GLvoid *pixels,
380 const struct gl_pixelstore_attrib *packing )
381{
382 GLbitfield transferOps = ctx->_ImageTransferState;
383 struct gl_framebuffer *fb = ctx->ReadBuffer;
384 struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
385
386 if (!rb)
387 return;
388
389 if ((ctx->Color._ClampReadColor == GL_TRUE || type != GL_FLOAT) &&
Jordan Justen9ad8f432012-06-25 10:52:39 -0700390 !_mesa_is_enum_format_integer(format)) {
Brian Pauld2a23d42011-11-12 11:50:31 -0700391 transferOps |= IMAGE_CLAMP_BIT;
392 }
393
Neil Robertsd9c420972012-02-26 01:33:40 +0000394 /* Try the optimized paths first. */
395 if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height,
396 format, type, pixels, packing,
397 transferOps)) {
398 return;
Brian Pauld2a23d42011-11-12 11:50:31 -0700399 }
400
401 slow_read_rgba_pixels(ctx, x, y, width, height,
402 format, type, pixels, packing, transferOps);
403}
404
405/**
406 * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the
407 * data (possibly swapping 8/24 vs 24/8 as we go).
408 */
409static GLboolean
410fast_read_depth_stencil_pixels(struct gl_context *ctx,
411 GLint x, GLint y,
412 GLsizei width, GLsizei height,
413 GLubyte *dst, int dstStride)
414{
415 struct gl_framebuffer *fb = ctx->ReadBuffer;
416 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
417 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
418 GLubyte *map;
419 int stride, i;
420
421 if (rb != stencilRb)
422 return GL_FALSE;
423
424 if (rb->Format != MESA_FORMAT_Z24_S8 &&
425 rb->Format != MESA_FORMAT_S8_Z24)
426 return GL_FALSE;
427
428 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
429 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700430 if (!map) {
431 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
432 return GL_TRUE; /* don't bother trying the slow path */
433 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700434
435 for (i = 0; i < height; i++) {
436 _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width,
437 map, (GLuint *)dst);
438 map += stride;
439 dst += dstStride;
440 }
441
442 ctx->Driver.UnmapRenderbuffer(ctx, rb);
443
444 return GL_TRUE;
445}
446
447
448/**
449 * For non-float-depth and stencil buffers being read as 24/8 depth/stencil,
450 * copy the integer data directly instead of converting depth to float and
451 * re-packing.
452 */
453static GLboolean
454fast_read_depth_stencil_pixels_separate(struct gl_context *ctx,
455 GLint x, GLint y,
456 GLsizei width, GLsizei height,
457 uint32_t *dst, int dstStride)
458{
459 struct gl_framebuffer *fb = ctx->ReadBuffer;
460 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
461 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
Brian Paul531eaca2012-02-19 20:08:51 -0700462 GLubyte *depthMap, *stencilMap, *stencilVals;
Brian Pauld2a23d42011-11-12 11:50:31 -0700463 int depthStride, stencilStride, i, j;
464
Eric Anholt755f0a02011-11-17 13:56:30 -0800465 if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED)
Brian Pauld2a23d42011-11-12 11:50:31 -0700466 return GL_FALSE;
467
468 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
469 GL_MAP_READ_BIT, &depthMap, &depthStride);
Brian Paul038a7df2011-11-17 17:20:05 -0700470 if (!depthMap) {
471 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
472 return GL_TRUE; /* don't bother trying the slow path */
473 }
474
Brian Pauld2a23d42011-11-12 11:50:31 -0700475 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
476 GL_MAP_READ_BIT, &stencilMap, &stencilStride);
Brian Paul038a7df2011-11-17 17:20:05 -0700477 if (!stencilMap) {
478 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
479 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
480 return GL_TRUE; /* don't bother trying the slow path */
481 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700482
Matt Turner2b7a9722012-09-03 19:44:00 -0700483 stencilVals = malloc(width * sizeof(GLubyte));
Brian Pauld2a23d42011-11-12 11:50:31 -0700484
Brian Paul531eaca2012-02-19 20:08:51 -0700485 if (stencilVals) {
486 for (j = 0; j < height; j++) {
487 _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst);
488 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
489 stencilMap, stencilVals);
Brian Pauld2a23d42011-11-12 11:50:31 -0700490
Brian Paul531eaca2012-02-19 20:08:51 -0700491 for (i = 0; i < width; i++) {
492 dst[i] = (dst[i] & 0xffffff00) | stencilVals[i];
493 }
494
495 depthMap += depthStride;
496 stencilMap += stencilStride;
497 dst += dstStride / 4;
Brian Pauld2a23d42011-11-12 11:50:31 -0700498 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700499 }
Brian Paul531eaca2012-02-19 20:08:51 -0700500 else {
501 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
502 }
503
504 free(stencilVals);
Brian Pauld2a23d42011-11-12 11:50:31 -0700505
506 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
507 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
508
509 return GL_TRUE;
510}
511
512static void
513slow_read_depth_stencil_pixels_separate(struct gl_context *ctx,
514 GLint x, GLint y,
515 GLsizei width, GLsizei height,
516 GLenum type,
517 const struct gl_pixelstore_attrib *packing,
518 GLubyte *dst, int dstStride)
519{
520 struct gl_framebuffer *fb = ctx->ReadBuffer;
521 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
522 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
523 GLubyte *depthMap, *stencilMap;
524 int depthStride, stencilStride, j;
Brian Paul531eaca2012-02-19 20:08:51 -0700525 GLubyte *stencilVals;
526 GLfloat *depthVals;
527
Brian Pauld2a23d42011-11-12 11:50:31 -0700528
Brian Paulf6a50c02011-11-16 07:47:51 -0700529 /* The depth and stencil buffers might be separate, or a single buffer.
530 * If one buffer, only map it once.
531 */
Brian Pauld2a23d42011-11-12 11:50:31 -0700532 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
533 GL_MAP_READ_BIT, &depthMap, &depthStride);
Brian Paul038a7df2011-11-17 17:20:05 -0700534 if (!depthMap) {
535 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
536 return;
537 }
538
Brian Paulf6a50c02011-11-16 07:47:51 -0700539 if (stencilRb != depthRb) {
540 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
541 GL_MAP_READ_BIT, &stencilMap,
542 &stencilStride);
Brian Paul038a7df2011-11-17 17:20:05 -0700543 if (!stencilMap) {
544 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
545 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
546 return;
547 }
Brian Paulf6a50c02011-11-16 07:47:51 -0700548 }
Brian Paulf4c03da2011-11-16 09:58:45 -0700549 else {
550 stencilMap = depthMap;
551 stencilStride = depthStride;
552 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700553
Matt Turner2b7a9722012-09-03 19:44:00 -0700554 stencilVals = malloc(width * sizeof(GLubyte));
555 depthVals = malloc(width * sizeof(GLfloat));
Brian Pauld2a23d42011-11-12 11:50:31 -0700556
Brian Paul531eaca2012-02-19 20:08:51 -0700557 if (stencilVals && depthVals) {
558 for (j = 0; j < height; j++) {
559 _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals);
560 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
561 stencilMap, stencilVals);
Brian Pauld2a23d42011-11-12 11:50:31 -0700562
Brian Paul531eaca2012-02-19 20:08:51 -0700563 _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst,
564 depthVals, stencilVals, packing);
Brian Pauld2a23d42011-11-12 11:50:31 -0700565
Brian Paul531eaca2012-02-19 20:08:51 -0700566 depthMap += depthStride;
567 stencilMap += stencilStride;
568 dst += dstStride;
569 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700570 }
Brian Paul531eaca2012-02-19 20:08:51 -0700571 else {
572 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
573 }
574
575 free(stencilVals);
576 free(depthVals);
Brian Pauld2a23d42011-11-12 11:50:31 -0700577
578 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
Brian Paulf6a50c02011-11-16 07:47:51 -0700579 if (stencilRb != depthRb) {
580 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
581 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700582}
583
584
585/**
586 * Read combined depth/stencil values.
587 * We'll have already done error checking to be sure the expected
588 * depth and stencil buffers really exist.
589 */
590static void
591read_depth_stencil_pixels(struct gl_context *ctx,
592 GLint x, GLint y,
593 GLsizei width, GLsizei height,
594 GLenum type, GLvoid *pixels,
595 const struct gl_pixelstore_attrib *packing )
596{
597 const GLboolean scaleOrBias
598 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
599 const GLboolean stencilTransfer = ctx->Pixel.IndexShift
600 || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag;
601 GLubyte *dst;
602 int dstStride;
603
604 dst = (GLubyte *) _mesa_image_address2d(packing, pixels,
605 width, height,
606 GL_DEPTH_STENCIL_EXT,
607 type, 0, 0);
608 dstStride = _mesa_image_row_stride(packing, width,
609 GL_DEPTH_STENCIL_EXT, type);
610
611 /* Fast 24/8 reads. */
612 if (type == GL_UNSIGNED_INT_24_8 &&
613 !scaleOrBias && !stencilTransfer && !packing->SwapBytes) {
614 if (fast_read_depth_stencil_pixels(ctx, x, y, width, height,
615 dst, dstStride))
616 return;
617
618 if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
619 (uint32_t *)dst, dstStride))
620 return;
621 }
622
623 slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
624 type, packing,
625 dst, dstStride);
626}
627
628
629
630/**
631 * Software fallback routine for ctx->Driver.ReadPixels().
632 * By time we get here, all error checking will have been done.
633 */
634void
635_mesa_readpixels(struct gl_context *ctx,
636 GLint x, GLint y, GLsizei width, GLsizei height,
637 GLenum format, GLenum type,
638 const struct gl_pixelstore_attrib *packing,
639 GLvoid *pixels)
640{
641 struct gl_pixelstore_attrib clippedPacking = *packing;
642
643 if (ctx->NewState)
644 _mesa_update_state(ctx);
645
646 /* Do all needed clipping here, so that we can forget about it later */
647 if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
648
649 pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels);
650
651 if (pixels) {
652 switch (format) {
653 case GL_STENCIL_INDEX:
654 read_stencil_pixels(ctx, x, y, width, height, type, pixels,
655 &clippedPacking);
656 break;
657 case GL_DEPTH_COMPONENT:
658 read_depth_pixels(ctx, x, y, width, height, type, pixels,
659 &clippedPacking);
660 break;
661 case GL_DEPTH_STENCIL_EXT:
662 read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels,
663 &clippedPacking);
664 break;
665 default:
666 /* all other formats should be color formats */
667 read_rgba_pixels(ctx, x, y, width, height, format, type, pixels,
668 &clippedPacking);
669 }
670
671 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
672 }
673 }
674}
675
676
Jordan Justen8b0bc9d2012-12-28 11:24:37 -0800677static GLenum
678read_pixels_es3_error_check(GLenum format, GLenum type,
679 const struct gl_renderbuffer *rb)
680{
681 const GLenum internalFormat = rb->InternalFormat;
682 const GLenum data_type = _mesa_get_format_datatype(rb->Format);
683 GLboolean is_unsigned_int = GL_FALSE;
684 GLboolean is_signed_int = GL_FALSE;
685
686 if (!_mesa_is_color_format(internalFormat)) {
687 return GL_INVALID_OPERATION;
688 }
689
690 is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat);
691 if (!is_unsigned_int) {
692 is_signed_int = _mesa_is_enum_format_signed_int(internalFormat);
693 }
694
695 switch (format) {
696 case GL_RGBA:
697 if (type == GL_UNSIGNED_BYTE && data_type == GL_UNSIGNED_NORMALIZED)
698 return GL_NO_ERROR;
699 if (internalFormat == GL_RGB10_A2 &&
700 type == GL_UNSIGNED_INT_2_10_10_10_REV)
701 return GL_NO_ERROR;
702 if (internalFormat == GL_RGB10_A2UI && type == GL_UNSIGNED_BYTE)
703 return GL_NO_ERROR;
704 break;
705 case GL_BGRA:
706 /* GL_EXT_read_format_bgra */
707 if (type == GL_UNSIGNED_BYTE ||
708 type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
709 type == GL_UNSIGNED_SHORT_1_5_5_5_REV)
710 return GL_NO_ERROR;
711 break;
712 case GL_RGBA_INTEGER:
713 if ((is_signed_int && type == GL_INT) ||
714 (is_unsigned_int && type == GL_UNSIGNED_INT))
715 return GL_NO_ERROR;
716 break;
717 }
718
719 return GL_INVALID_OPERATION;
720}
721
722
Brian Paul28876dd2008-06-09 14:22:15 -0600723void GLAPIENTRY
Brian Paul6b329b92011-04-26 14:54:41 -0600724_mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height,
725 GLenum format, GLenum type, GLsizei bufSize,
726 GLvoid *pixels )
Brian Paul28876dd2008-06-09 14:22:15 -0600727{
Matt Turner112e3022012-11-30 15:07:54 -0800728 GLenum err = GL_NO_ERROR;
Jordan Justen8b0bc9d2012-12-28 11:24:37 -0800729 struct gl_renderbuffer *rb;
Brian Paulb8f7eef2012-02-07 07:42:33 -0700730
Brian Paul28876dd2008-06-09 14:22:15 -0600731 GET_CURRENT_CONTEXT(ctx);
732 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
733
734 FLUSH_CURRENT(ctx, 0);
735
Brian Paul6364d752011-02-18 09:53:29 -0700736 if (MESA_VERBOSE & VERBOSE_API)
737 _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
738 width, height,
739 _mesa_lookup_enum_by_nr(format),
740 _mesa_lookup_enum_by_nr(type),
741 pixels);
742
Brian Paul28876dd2008-06-09 14:22:15 -0600743 if (width < 0 || height < 0) {
744 _mesa_error( ctx, GL_INVALID_VALUE,
745 "glReadPixels(width=%d height=%d)", width, height );
746 return;
747 }
748
Jordan Justen8b0bc9d2012-12-28 11:24:37 -0800749 rb = _mesa_get_read_renderbuffer_for_format(ctx, format);
750 if (rb == NULL) {
751 _mesa_error(ctx, GL_INVALID_OPERATION,
752 "glReadPixels(read buffer)");
753 return;
754 }
755
Ian Romanickb7c7e5e2012-07-27 12:24:24 -0700756 /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
757 * combinations of format and type that can be used.
758 *
759 * Technically, only two combinations are actually allowed:
760 * GL_RGBA/GL_UNSIGNED_BYTE, and some implementation-specific internal
761 * preferred combination. This code doesn't know what that preferred
762 * combination is, and Mesa can handle anything valid. Just work instead.
763 */
Matt Turner112e3022012-11-30 15:07:54 -0800764 if (_mesa_is_gles(ctx)) {
765 if (ctx->Version < 30) {
766 err = _mesa_es_error_check_format_and_type(format, type, 2);
767 if (err == GL_NO_ERROR) {
768 if (type == GL_FLOAT || type == GL_HALF_FLOAT_OES) {
769 err = GL_INVALID_OPERATION;
770 }
Ian Romanickb7c7e5e2012-07-27 12:24:24 -0700771 }
Jordan Justen8b0bc9d2012-12-28 11:24:37 -0800772 } else {
773 err = read_pixels_es3_error_check(format, type, rb);
Ian Romanickb7c7e5e2012-07-27 12:24:24 -0700774 }
775
Matt Turner112e3022012-11-30 15:07:54 -0800776 if (err == GL_NO_ERROR && (format == GL_DEPTH_COMPONENT
777 || format == GL_DEPTH_STENCIL)) {
778 err = GL_INVALID_ENUM;
779 }
780
Ian Romanickb7c7e5e2012-07-27 12:24:24 -0700781 if (err != GL_NO_ERROR) {
782 _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
783 _mesa_lookup_enum_by_nr(format),
784 _mesa_lookup_enum_by_nr(type));
785 return;
786 }
787 }
788
Brian Paul28876dd2008-06-09 14:22:15 -0600789 if (ctx->NewState)
790 _mesa_update_state(ctx);
791
Brian Paulb8f7eef2012-02-07 07:42:33 -0700792 err = _mesa_error_check_format_and_type(ctx, format, type);
793 if (err != GL_NO_ERROR) {
794 _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
795 _mesa_lookup_enum_by_nr(format),
796 _mesa_lookup_enum_by_nr(type));
Brian Paul28876dd2008-06-09 14:22:15 -0600797 return;
798 }
799
Eric Anholt5a827d92012-05-14 10:18:23 -0700800 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
801 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
802 "glReadPixels(incomplete framebuffer)" );
803 return;
804 }
805
Eric Anholt5c996972012-11-13 13:39:37 -0800806 if (_mesa_is_user_fbo(ctx->ReadBuffer) &&
807 ctx->ReadBuffer->Visual.samples > 0) {
808 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
809 return;
810 }
811
812 if (!_mesa_source_buffer_exists(ctx, format)) {
813 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
814 return;
815 }
816
Brian Paul751e10f2010-10-25 19:07:33 -0600817 /* Check that the destination format and source buffer are both
818 * integer-valued or both non-integer-valued.
819 */
820 if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
821 const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
Brian Paul412b9602010-10-26 20:30:40 -0600822 const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
Jordan Justen9ad8f432012-06-25 10:52:39 -0700823 const GLboolean dstInteger = _mesa_is_enum_format_integer(format);
Brian Paul751e10f2010-10-25 19:07:33 -0600824 if (dstInteger != srcInteger) {
825 _mesa_error(ctx, GL_INVALID_OPERATION,
826 "glReadPixels(integer / non-integer format mismatch");
827 return;
828 }
829 }
830
Brian Paul7b9bf392009-04-02 13:05:55 -0600831 if (width == 0 || height == 0)
832 return; /* nothing to do */
833
Brian Paul6b329b92011-04-26 14:54:41 -0600834 if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
835 format, type, bufSize, pixels)) {
836 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
Brian Paul28876dd2008-06-09 14:22:15 -0600837 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul6b329b92011-04-26 14:54:41 -0600838 "glReadPixels(out of bounds PBO access)");
839 } else {
840 _mesa_error(ctx, GL_INVALID_OPERATION,
841 "glReadnPixelsARB(out of bounds access:"
842 " bufSize (%d) is too small)", bufSize);
Brian Paul28876dd2008-06-09 14:22:15 -0600843 }
Brian Paul6b329b92011-04-26 14:54:41 -0600844 return;
845 }
Brian Paul28876dd2008-06-09 14:22:15 -0600846
Brian Paul6b329b92011-04-26 14:54:41 -0600847 if (_mesa_is_bufferobj(ctx->Pack.BufferObj) &&
848 _mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
849 /* buffer is mapped - that's an error */
850 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
851 return;
Brian Paul28876dd2008-06-09 14:22:15 -0600852 }
853
854 ctx->Driver.ReadPixels(ctx, x, y, width, height,
855 format, type, &ctx->Pack, pixels);
856}
Brian Paul6b329b92011-04-26 14:54:41 -0600857
858void GLAPIENTRY
859_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
860 GLenum format, GLenum type, GLvoid *pixels )
861{
862 _mesa_ReadnPixelsARB(x, y, width, height, format, type, INT_MAX, pixels);
863}