blob: 82d99fd21c94965bc0211ecf447077b2a5e9a32a [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"
Brian Paul28876dd2008-06-09 14:22:15 -060040
41
42/**
Brian Pauld2a23d42011-11-12 11:50:31 -070043 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
44 * mapping.
45 */
46static GLboolean
47fast_read_depth_pixels( struct gl_context *ctx,
48 GLint x, GLint y,
49 GLsizei width, GLsizei height,
50 GLenum type, GLvoid *pixels,
51 const struct gl_pixelstore_attrib *packing )
52{
53 struct gl_framebuffer *fb = ctx->ReadBuffer;
54 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
55 GLubyte *map, *dst;
56 int stride, dstStride, j;
57
58 if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0)
59 return GL_FALSE;
60
61 if (packing->SwapBytes)
62 return GL_FALSE;
63
Eric Anholt755f0a02011-11-17 13:56:30 -080064 if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
Brian Pauld2a23d42011-11-12 11:50:31 -070065 return GL_FALSE;
66
67 if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) ||
68 type == GL_UNSIGNED_INT))
69 return GL_FALSE;
70
71 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
72 &map, &stride);
73
Brian Paul038a7df2011-11-17 17:20:05 -070074 if (!map) {
75 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
76 return GL_TRUE; /* don't bother trying the slow path */
77 }
78
Brian Pauld2a23d42011-11-12 11:50:31 -070079 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
80 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
81 GL_DEPTH_COMPONENT, type, 0, 0);
82
83 for (j = 0; j < height; j++) {
84 if (type == GL_UNSIGNED_INT) {
85 _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
86 } else {
87 ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16);
88 memcpy(dst, map, width * 2);
89 }
90
91 map += stride;
92 dst += dstStride;
93 }
94 ctx->Driver.UnmapRenderbuffer(ctx, rb);
95
96 return GL_TRUE;
97}
98
99/**
100 * Read pixels for format=GL_DEPTH_COMPONENT.
101 */
102static void
103read_depth_pixels( struct gl_context *ctx,
104 GLint x, GLint y,
105 GLsizei width, GLsizei height,
106 GLenum type, GLvoid *pixels,
107 const struct gl_pixelstore_attrib *packing )
108{
109 struct gl_framebuffer *fb = ctx->ReadBuffer;
110 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
111 GLint j;
112 GLubyte *dst, *map;
113 int dstStride, stride;
Brian Paul531eaca2012-02-19 20:08:51 -0700114 GLfloat *depthValues;
Brian Pauld2a23d42011-11-12 11:50:31 -0700115
116 if (!rb)
117 return;
118
119 /* clipping should have been done already */
120 ASSERT(x >= 0);
121 ASSERT(y >= 0);
122 ASSERT(x + width <= (GLint) rb->Width);
123 ASSERT(y + height <= (GLint) rb->Height);
Brian Pauld2a23d42011-11-12 11:50:31 -0700124
125 if (fast_read_depth_pixels(ctx, x, y, width, height, type, pixels, packing))
126 return;
127
128 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
129 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
130 GL_DEPTH_COMPONENT, type, 0, 0);
131
132 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
133 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700134 if (!map) {
135 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
136 return;
137 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700138
Brian Paul531eaca2012-02-19 20:08:51 -0700139 depthValues = (GLfloat *) malloc(width * sizeof(GLfloat));
Brian Pauld2a23d42011-11-12 11:50:31 -0700140
Brian Paul531eaca2012-02-19 20:08:51 -0700141 if (depthValues) {
142 /* General case (slower) */
143 for (j = 0; j < height; j++, y++) {
144 _mesa_unpack_float_z_row(rb->Format, width, map, depthValues);
145 _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing);
146
147 dst += dstStride;
148 map += stride;
149 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700150 }
Brian Paul531eaca2012-02-19 20:08:51 -0700151 else {
152 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
153 }
154
155 free(depthValues);
Brian Pauld2a23d42011-11-12 11:50:31 -0700156
157 ctx->Driver.UnmapRenderbuffer(ctx, rb);
158}
159
160
161/**
162 * Read pixels for format=GL_STENCIL_INDEX.
163 */
164static void
165read_stencil_pixels( struct gl_context *ctx,
166 GLint x, GLint y,
167 GLsizei width, GLsizei height,
168 GLenum type, GLvoid *pixels,
169 const struct gl_pixelstore_attrib *packing )
170{
171 struct gl_framebuffer *fb = ctx->ReadBuffer;
172 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
173 GLint j;
Brian Paul531eaca2012-02-19 20:08:51 -0700174 GLubyte *map, *stencil;
Brian Pauld2a23d42011-11-12 11:50:31 -0700175 GLint stride;
176
177 if (!rb)
178 return;
179
Brian Pauld2a23d42011-11-12 11:50:31 -0700180 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
181 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700182 if (!map) {
183 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
184 return;
185 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700186
Brian Paul531eaca2012-02-19 20:08:51 -0700187 stencil = (GLubyte *) malloc(width * sizeof(GLubyte));
Brian Pauld2a23d42011-11-12 11:50:31 -0700188
Brian Paul531eaca2012-02-19 20:08:51 -0700189 if (stencil) {
190 /* process image row by row */
191 for (j = 0; j < height; j++) {
192 GLvoid *dest;
Brian Pauld2a23d42011-11-12 11:50:31 -0700193
Brian Paul531eaca2012-02-19 20:08:51 -0700194 _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil);
195 dest = _mesa_image_address2d(packing, pixels, width, height,
196 GL_STENCIL_INDEX, type, j, 0);
Brian Pauld2a23d42011-11-12 11:50:31 -0700197
Brian Paul531eaca2012-02-19 20:08:51 -0700198 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
199
200 map += stride;
201 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700202 }
Brian Paul531eaca2012-02-19 20:08:51 -0700203 else {
204 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
205 }
206
207 free(stencil);
Brian Pauld2a23d42011-11-12 11:50:31 -0700208
209 ctx->Driver.UnmapRenderbuffer(ctx, rb);
210}
211
Brian Paula5e95a42012-04-17 10:49:16 -0600212
213/**
214 * Try to do glReadPixels of RGBA data using a simple memcpy or swizzle.
215 * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
216 */
Brian Pauld2a23d42011-11-12 11:50:31 -0700217static GLboolean
218fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
219 GLint x, GLint y,
220 GLsizei width, GLsizei height,
221 GLenum format, GLenum type,
222 GLvoid *pixels,
223 const struct gl_pixelstore_attrib *packing,
224 GLbitfield transferOps )
225{
226 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
227 GLubyte *dst, *map;
228 int dstStride, stride, j, texelBytes;
Brian Paula5e95a42012-04-17 10:49:16 -0600229 GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE;
Brian Pauld2a23d42011-11-12 11:50:31 -0700230
Brian Paula5e95a42012-04-17 10:49:16 -0600231 /* XXX we could check for other swizzle/special cases here as needed */
232 if (rb->Format == MESA_FORMAT_RGBA8888_REV &&
233 format == GL_BGRA &&
234 type == GL_UNSIGNED_INT_8_8_8_8_REV &&
235 !ctx->Pack.SwapBytes) {
236 swizzle_rb = GL_TRUE;
237 }
238 else if (rb->Format == MESA_FORMAT_XRGB8888 &&
239 format == GL_BGRA &&
240 type == GL_UNSIGNED_INT_8_8_8_8_REV &&
241 !ctx->Pack.SwapBytes) {
242 copy_xrgb = GL_TRUE;
243 }
244 else if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
245 ctx->Pack.SwapBytes))
Brian Pauld2a23d42011-11-12 11:50:31 -0700246 return GL_FALSE;
247
Neil Robertsd9c420972012-02-26 01:33:40 +0000248 /* If the format is unsigned normalized then we can ignore clamping
249 * because the values are already in the range [0,1] so it won't
250 * have any effect anyway.
251 */
252 if (_mesa_get_format_datatype(rb->Format) == GL_UNSIGNED_NORMALIZED)
253 transferOps &= ~IMAGE_CLAMP_BIT;
254
255 if (transferOps)
256 return GL_FALSE;
257
Brian Pauld2a23d42011-11-12 11:50:31 -0700258 dstStride = _mesa_image_row_stride(packing, width, format, type);
259 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
260 format, type, 0, 0);
261
262 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
263 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700264 if (!map) {
265 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
266 return GL_TRUE; /* don't bother trying the slow path */
267 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700268
269 texelBytes = _mesa_get_format_bytes(rb->Format);
Brian Paula5e95a42012-04-17 10:49:16 -0600270
271 if (swizzle_rb) {
272 /* swap R/B */
273 for (j = 0; j < height; j++) {
274 int i;
275 for (i = 0; i < width; i++) {
276 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
277 GLuint pixel = map4[i];
278 dst4[i] = (pixel & 0xff00ff00)
279 | ((pixel & 0x00ff0000) >> 16)
280 | ((pixel & 0x000000ff) << 16);
281 }
282 dst += dstStride;
283 map += stride;
284 }
285 } else if (copy_xrgb) {
286 /* convert xrgb -> argb */
287 for (j = 0; j < height; j++) {
288 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
289 int i;
290 for (i = 0; i < width; i++) {
291 dst4[i] = map4[i] | 0xff000000; /* set A=0xff */
292 }
293 dst += dstStride;
294 map += stride;
295 }
296 } else {
297 /* just memcpy */
298 for (j = 0; j < height; j++) {
299 memcpy(dst, map, width * texelBytes);
300 dst += dstStride;
301 map += stride;
302 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700303 }
304
305 ctx->Driver.UnmapRenderbuffer(ctx, rb);
306
307 return GL_TRUE;
308}
309
Brian Paul72fb25c2011-11-18 17:39:01 -0700310static void
Brian Pauld2a23d42011-11-12 11:50:31 -0700311slow_read_rgba_pixels( struct gl_context *ctx,
312 GLint x, GLint y,
313 GLsizei width, GLsizei height,
314 GLenum format, GLenum type,
315 GLvoid *pixels,
316 const struct gl_pixelstore_attrib *packing,
317 GLbitfield transferOps )
318{
319 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
320 const gl_format rbFormat = _mesa_get_srgb_format_linear(rb->Format);
Brian Paulbf6aac22011-12-05 20:40:48 -0700321 void *rgba;
Brian Pauld2a23d42011-11-12 11:50:31 -0700322 GLubyte *dst, *map;
323 int dstStride, stride, j;
324
325 dstStride = _mesa_image_row_stride(packing, width, format, type);
326 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
327 format, type, 0, 0);
328
329 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
330 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700331 if (!map) {
332 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
333 return;
334 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700335
Brian Paulbf6aac22011-12-05 20:40:48 -0700336 rgba = malloc(width * MAX_PIXEL_BYTES);
337 if (!rgba)
338 goto done;
339
Brian Pauld2a23d42011-11-12 11:50:31 -0700340 for (j = 0; j < height; j++) {
Jordan Justen9ad8f432012-06-25 10:52:39 -0700341 if (_mesa_is_enum_format_integer(format)) {
Brian Paul301fba52012-01-09 08:11:33 -0700342 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
Brian Paulad897ff2012-02-29 20:55:50 -0700343 _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba,
344 rb->_BaseFormat);
Brian Paulbf6aac22011-12-05 20:40:48 -0700345 _mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format,
346 type, dst);
Brian Pauld2a23d42011-11-12 11:50:31 -0700347 } else {
Brian Paulbf6aac22011-12-05 20:40:48 -0700348 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba);
Brian Paulad897ff2012-02-29 20:55:50 -0700349 _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba,
350 rb->_BaseFormat);
Brian Paulbf6aac22011-12-05 20:40:48 -0700351 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
352 type, dst, packing, transferOps);
Brian Pauld2a23d42011-11-12 11:50:31 -0700353 }
354 dst += dstStride;
355 map += stride;
356 }
357
Brian Paulbf6aac22011-12-05 20:40:48 -0700358 free(rgba);
359
360done:
Brian Pauld2a23d42011-11-12 11:50:31 -0700361 ctx->Driver.UnmapRenderbuffer(ctx, rb);
Brian Pauld2a23d42011-11-12 11:50:31 -0700362}
363
364/*
365 * Read R, G, B, A, RGB, L, or LA pixels.
366 */
367static void
368read_rgba_pixels( struct gl_context *ctx,
369 GLint x, GLint y,
370 GLsizei width, GLsizei height,
371 GLenum format, GLenum type, GLvoid *pixels,
372 const struct gl_pixelstore_attrib *packing )
373{
374 GLbitfield transferOps = ctx->_ImageTransferState;
375 struct gl_framebuffer *fb = ctx->ReadBuffer;
376 struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
377
378 if (!rb)
379 return;
380
381 if ((ctx->Color._ClampReadColor == GL_TRUE || type != GL_FLOAT) &&
Jordan Justen9ad8f432012-06-25 10:52:39 -0700382 !_mesa_is_enum_format_integer(format)) {
Brian Pauld2a23d42011-11-12 11:50:31 -0700383 transferOps |= IMAGE_CLAMP_BIT;
384 }
385
Neil Robertsd9c420972012-02-26 01:33:40 +0000386 /* Try the optimized paths first. */
387 if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height,
388 format, type, pixels, packing,
389 transferOps)) {
390 return;
Brian Pauld2a23d42011-11-12 11:50:31 -0700391 }
392
393 slow_read_rgba_pixels(ctx, x, y, width, height,
394 format, type, pixels, packing, transferOps);
395}
396
397/**
398 * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the
399 * data (possibly swapping 8/24 vs 24/8 as we go).
400 */
401static GLboolean
402fast_read_depth_stencil_pixels(struct gl_context *ctx,
403 GLint x, GLint y,
404 GLsizei width, GLsizei height,
405 GLubyte *dst, int dstStride)
406{
407 struct gl_framebuffer *fb = ctx->ReadBuffer;
408 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
409 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
410 GLubyte *map;
411 int stride, i;
412
413 if (rb != stencilRb)
414 return GL_FALSE;
415
416 if (rb->Format != MESA_FORMAT_Z24_S8 &&
417 rb->Format != MESA_FORMAT_S8_Z24)
418 return GL_FALSE;
419
420 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
421 &map, &stride);
Brian Paul038a7df2011-11-17 17:20:05 -0700422 if (!map) {
423 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
424 return GL_TRUE; /* don't bother trying the slow path */
425 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700426
427 for (i = 0; i < height; i++) {
428 _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width,
429 map, (GLuint *)dst);
430 map += stride;
431 dst += dstStride;
432 }
433
434 ctx->Driver.UnmapRenderbuffer(ctx, rb);
435
436 return GL_TRUE;
437}
438
439
440/**
441 * For non-float-depth and stencil buffers being read as 24/8 depth/stencil,
442 * copy the integer data directly instead of converting depth to float and
443 * re-packing.
444 */
445static GLboolean
446fast_read_depth_stencil_pixels_separate(struct gl_context *ctx,
447 GLint x, GLint y,
448 GLsizei width, GLsizei height,
449 uint32_t *dst, int dstStride)
450{
451 struct gl_framebuffer *fb = ctx->ReadBuffer;
452 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
453 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
Brian Paul531eaca2012-02-19 20:08:51 -0700454 GLubyte *depthMap, *stencilMap, *stencilVals;
Brian Pauld2a23d42011-11-12 11:50:31 -0700455 int depthStride, stencilStride, i, j;
456
Eric Anholt755f0a02011-11-17 13:56:30 -0800457 if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED)
Brian Pauld2a23d42011-11-12 11:50:31 -0700458 return GL_FALSE;
459
460 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
461 GL_MAP_READ_BIT, &depthMap, &depthStride);
Brian Paul038a7df2011-11-17 17:20:05 -0700462 if (!depthMap) {
463 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
464 return GL_TRUE; /* don't bother trying the slow path */
465 }
466
Brian Pauld2a23d42011-11-12 11:50:31 -0700467 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
468 GL_MAP_READ_BIT, &stencilMap, &stencilStride);
Brian Paul038a7df2011-11-17 17:20:05 -0700469 if (!stencilMap) {
470 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
471 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
472 return GL_TRUE; /* don't bother trying the slow path */
473 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700474
Brian Paul531eaca2012-02-19 20:08:51 -0700475 stencilVals = (GLubyte *) malloc(width * sizeof(GLubyte));
Brian Pauld2a23d42011-11-12 11:50:31 -0700476
Brian Paul531eaca2012-02-19 20:08:51 -0700477 if (stencilVals) {
478 for (j = 0; j < height; j++) {
479 _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst);
480 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
481 stencilMap, stencilVals);
Brian Pauld2a23d42011-11-12 11:50:31 -0700482
Brian Paul531eaca2012-02-19 20:08:51 -0700483 for (i = 0; i < width; i++) {
484 dst[i] = (dst[i] & 0xffffff00) | stencilVals[i];
485 }
486
487 depthMap += depthStride;
488 stencilMap += stencilStride;
489 dst += dstStride / 4;
Brian Pauld2a23d42011-11-12 11:50:31 -0700490 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700491 }
Brian Paul531eaca2012-02-19 20:08:51 -0700492 else {
493 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
494 }
495
496 free(stencilVals);
Brian Pauld2a23d42011-11-12 11:50:31 -0700497
498 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
499 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
500
501 return GL_TRUE;
502}
503
504static void
505slow_read_depth_stencil_pixels_separate(struct gl_context *ctx,
506 GLint x, GLint y,
507 GLsizei width, GLsizei height,
508 GLenum type,
509 const struct gl_pixelstore_attrib *packing,
510 GLubyte *dst, int dstStride)
511{
512 struct gl_framebuffer *fb = ctx->ReadBuffer;
513 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
514 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
515 GLubyte *depthMap, *stencilMap;
516 int depthStride, stencilStride, j;
Brian Paul531eaca2012-02-19 20:08:51 -0700517 GLubyte *stencilVals;
518 GLfloat *depthVals;
519
Brian Pauld2a23d42011-11-12 11:50:31 -0700520
Brian Paulf6a50c02011-11-16 07:47:51 -0700521 /* The depth and stencil buffers might be separate, or a single buffer.
522 * If one buffer, only map it once.
523 */
Brian Pauld2a23d42011-11-12 11:50:31 -0700524 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
525 GL_MAP_READ_BIT, &depthMap, &depthStride);
Brian Paul038a7df2011-11-17 17:20:05 -0700526 if (!depthMap) {
527 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
528 return;
529 }
530
Brian Paulf6a50c02011-11-16 07:47:51 -0700531 if (stencilRb != depthRb) {
532 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
533 GL_MAP_READ_BIT, &stencilMap,
534 &stencilStride);
Brian Paul038a7df2011-11-17 17:20:05 -0700535 if (!stencilMap) {
536 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
537 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
538 return;
539 }
Brian Paulf6a50c02011-11-16 07:47:51 -0700540 }
Brian Paulf4c03da2011-11-16 09:58:45 -0700541 else {
542 stencilMap = depthMap;
543 stencilStride = depthStride;
544 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700545
Brian Paul531eaca2012-02-19 20:08:51 -0700546 stencilVals = (GLubyte *) malloc(width * sizeof(GLubyte));
547 depthVals = (GLfloat *) malloc(width * sizeof(GLfloat));
Brian Pauld2a23d42011-11-12 11:50:31 -0700548
Brian Paul531eaca2012-02-19 20:08:51 -0700549 if (stencilVals && depthVals) {
550 for (j = 0; j < height; j++) {
551 _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals);
552 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
553 stencilMap, stencilVals);
Brian Pauld2a23d42011-11-12 11:50:31 -0700554
Brian Paul531eaca2012-02-19 20:08:51 -0700555 _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst,
556 depthVals, stencilVals, packing);
Brian Pauld2a23d42011-11-12 11:50:31 -0700557
Brian Paul531eaca2012-02-19 20:08:51 -0700558 depthMap += depthStride;
559 stencilMap += stencilStride;
560 dst += dstStride;
561 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700562 }
Brian Paul531eaca2012-02-19 20:08:51 -0700563 else {
564 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
565 }
566
567 free(stencilVals);
568 free(depthVals);
Brian Pauld2a23d42011-11-12 11:50:31 -0700569
570 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
Brian Paulf6a50c02011-11-16 07:47:51 -0700571 if (stencilRb != depthRb) {
572 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
573 }
Brian Pauld2a23d42011-11-12 11:50:31 -0700574}
575
576
577/**
578 * Read combined depth/stencil values.
579 * We'll have already done error checking to be sure the expected
580 * depth and stencil buffers really exist.
581 */
582static void
583read_depth_stencil_pixels(struct gl_context *ctx,
584 GLint x, GLint y,
585 GLsizei width, GLsizei height,
586 GLenum type, GLvoid *pixels,
587 const struct gl_pixelstore_attrib *packing )
588{
589 const GLboolean scaleOrBias
590 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
591 const GLboolean stencilTransfer = ctx->Pixel.IndexShift
592 || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag;
593 GLubyte *dst;
594 int dstStride;
595
596 dst = (GLubyte *) _mesa_image_address2d(packing, pixels,
597 width, height,
598 GL_DEPTH_STENCIL_EXT,
599 type, 0, 0);
600 dstStride = _mesa_image_row_stride(packing, width,
601 GL_DEPTH_STENCIL_EXT, type);
602
603 /* Fast 24/8 reads. */
604 if (type == GL_UNSIGNED_INT_24_8 &&
605 !scaleOrBias && !stencilTransfer && !packing->SwapBytes) {
606 if (fast_read_depth_stencil_pixels(ctx, x, y, width, height,
607 dst, dstStride))
608 return;
609
610 if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
611 (uint32_t *)dst, dstStride))
612 return;
613 }
614
615 slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
616 type, packing,
617 dst, dstStride);
618}
619
620
621
622/**
623 * Software fallback routine for ctx->Driver.ReadPixels().
624 * By time we get here, all error checking will have been done.
625 */
626void
627_mesa_readpixels(struct gl_context *ctx,
628 GLint x, GLint y, GLsizei width, GLsizei height,
629 GLenum format, GLenum type,
630 const struct gl_pixelstore_attrib *packing,
631 GLvoid *pixels)
632{
633 struct gl_pixelstore_attrib clippedPacking = *packing;
634
635 if (ctx->NewState)
636 _mesa_update_state(ctx);
637
638 /* Do all needed clipping here, so that we can forget about it later */
639 if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
640
641 pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels);
642
643 if (pixels) {
644 switch (format) {
645 case GL_STENCIL_INDEX:
646 read_stencil_pixels(ctx, x, y, width, height, type, pixels,
647 &clippedPacking);
648 break;
649 case GL_DEPTH_COMPONENT:
650 read_depth_pixels(ctx, x, y, width, height, type, pixels,
651 &clippedPacking);
652 break;
653 case GL_DEPTH_STENCIL_EXT:
654 read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels,
655 &clippedPacking);
656 break;
657 default:
658 /* all other formats should be color formats */
659 read_rgba_pixels(ctx, x, y, width, height, format, type, pixels,
660 &clippedPacking);
661 }
662
663 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
664 }
665 }
666}
667
668
Brian Paul28876dd2008-06-09 14:22:15 -0600669void GLAPIENTRY
Brian Paul6b329b92011-04-26 14:54:41 -0600670_mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height,
671 GLenum format, GLenum type, GLsizei bufSize,
672 GLvoid *pixels )
Brian Paul28876dd2008-06-09 14:22:15 -0600673{
Brian Paulb8f7eef2012-02-07 07:42:33 -0700674 GLenum err;
675
Brian Paul28876dd2008-06-09 14:22:15 -0600676 GET_CURRENT_CONTEXT(ctx);
677 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
678
679 FLUSH_CURRENT(ctx, 0);
680
Brian Paul6364d752011-02-18 09:53:29 -0700681 if (MESA_VERBOSE & VERBOSE_API)
682 _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
683 width, height,
684 _mesa_lookup_enum_by_nr(format),
685 _mesa_lookup_enum_by_nr(type),
686 pixels);
687
Brian Paul28876dd2008-06-09 14:22:15 -0600688 if (width < 0 || height < 0) {
689 _mesa_error( ctx, GL_INVALID_VALUE,
690 "glReadPixels(width=%d height=%d)", width, height );
691 return;
692 }
693
694 if (ctx->NewState)
695 _mesa_update_state(ctx);
696
Brian Paulb8f7eef2012-02-07 07:42:33 -0700697 err = _mesa_error_check_format_and_type(ctx, format, type);
698 if (err != GL_NO_ERROR) {
699 _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
700 _mesa_lookup_enum_by_nr(format),
701 _mesa_lookup_enum_by_nr(type));
Brian Paul28876dd2008-06-09 14:22:15 -0600702 return;
703 }
704
Eric Anholt5a827d92012-05-14 10:18:23 -0700705 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
706 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
707 "glReadPixels(incomplete framebuffer)" );
708 return;
709 }
710
Brian Paul751e10f2010-10-25 19:07:33 -0600711 /* Check that the destination format and source buffer are both
712 * integer-valued or both non-integer-valued.
713 */
714 if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
715 const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
Brian Paul412b9602010-10-26 20:30:40 -0600716 const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
Jordan Justen9ad8f432012-06-25 10:52:39 -0700717 const GLboolean dstInteger = _mesa_is_enum_format_integer(format);
Brian Paul751e10f2010-10-25 19:07:33 -0600718 if (dstInteger != srcInteger) {
719 _mesa_error(ctx, GL_INVALID_OPERATION,
720 "glReadPixels(integer / non-integer format mismatch");
721 return;
722 }
723 }
724
Eric Anholt86b7c672012-01-11 13:54:53 -0800725 if (ctx->ReadBuffer->Name != 0 && ctx->ReadBuffer->Visual.samples > 0) {
726 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
727 return;
728 }
729
Brian Paul28876dd2008-06-09 14:22:15 -0600730 if (!_mesa_source_buffer_exists(ctx, format)) {
731 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
732 return;
733 }
734
Brian Paul7b9bf392009-04-02 13:05:55 -0600735 if (width == 0 || height == 0)
736 return; /* nothing to do */
737
Brian Paul6b329b92011-04-26 14:54:41 -0600738 if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
739 format, type, bufSize, pixels)) {
740 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
Brian Paul28876dd2008-06-09 14:22:15 -0600741 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul6b329b92011-04-26 14:54:41 -0600742 "glReadPixels(out of bounds PBO access)");
743 } else {
744 _mesa_error(ctx, GL_INVALID_OPERATION,
745 "glReadnPixelsARB(out of bounds access:"
746 " bufSize (%d) is too small)", bufSize);
Brian Paul28876dd2008-06-09 14:22:15 -0600747 }
Brian Paul6b329b92011-04-26 14:54:41 -0600748 return;
749 }
Brian Paul28876dd2008-06-09 14:22:15 -0600750
Brian Paul6b329b92011-04-26 14:54:41 -0600751 if (_mesa_is_bufferobj(ctx->Pack.BufferObj) &&
752 _mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
753 /* buffer is mapped - that's an error */
754 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
755 return;
Brian Paul28876dd2008-06-09 14:22:15 -0600756 }
757
758 ctx->Driver.ReadPixels(ctx, x, y, width, height,
759 format, type, &ctx->Pack, pixels);
760}
Brian Paul6b329b92011-04-26 14:54:41 -0600761
762void GLAPIENTRY
763_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
764 GLenum format, GLenum type, GLvoid *pixels )
765{
766 _mesa_ReadnPixelsARB(x, y, width, height, format, type, INT_MAX, pixels);
767}