mesa: add glformats integer type/format detection routines
[mesa.git] / src / mesa / main / readpix.c
1 /*
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"
29 #include "enums.h"
30 #include "readpix.h"
31 #include "framebuffer.h"
32 #include "formats.h"
33 #include "format_unpack.h"
34 #include "image.h"
35 #include "mtypes.h"
36 #include "pack.h"
37 #include "pbo.h"
38 #include "state.h"
39 #include "glformats.h"
40
41
42 /**
43 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
44 * mapping.
45 */
46 static GLboolean
47 fast_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
64 if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
65 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
74 if (!map) {
75 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
76 return GL_TRUE; /* don't bother trying the slow path */
77 }
78
79 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 */
102 static void
103 read_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;
114 GLfloat *depthValues;
115
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);
124
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);
134 if (!map) {
135 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
136 return;
137 }
138
139 depthValues = (GLfloat *) malloc(width * sizeof(GLfloat));
140
141 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 }
150 }
151 else {
152 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
153 }
154
155 free(depthValues);
156
157 ctx->Driver.UnmapRenderbuffer(ctx, rb);
158 }
159
160
161 /**
162 * Read pixels for format=GL_STENCIL_INDEX.
163 */
164 static void
165 read_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;
174 GLubyte *map, *stencil;
175 GLint stride;
176
177 if (!rb)
178 return;
179
180 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
181 &map, &stride);
182 if (!map) {
183 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
184 return;
185 }
186
187 stencil = (GLubyte *) malloc(width * sizeof(GLubyte));
188
189 if (stencil) {
190 /* process image row by row */
191 for (j = 0; j < height; j++) {
192 GLvoid *dest;
193
194 _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);
197
198 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
199
200 map += stride;
201 }
202 }
203 else {
204 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
205 }
206
207 free(stencil);
208
209 ctx->Driver.UnmapRenderbuffer(ctx, rb);
210 }
211
212
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 */
217 static GLboolean
218 fast_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;
229 GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE;
230
231 /* 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))
246 return GL_FALSE;
247
248 /* 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
258 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);
264 if (!map) {
265 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
266 return GL_TRUE; /* don't bother trying the slow path */
267 }
268
269 texelBytes = _mesa_get_format_bytes(rb->Format);
270
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 }
303 }
304
305 ctx->Driver.UnmapRenderbuffer(ctx, rb);
306
307 return GL_TRUE;
308 }
309
310 static void
311 slow_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);
321 void *rgba;
322 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);
331 if (!map) {
332 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
333 return;
334 }
335
336 rgba = malloc(width * MAX_PIXEL_BYTES);
337 if (!rgba)
338 goto done;
339
340 for (j = 0; j < height; j++) {
341 if (_mesa_is_enum_format_integer(format)) {
342 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
343 _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba,
344 rb->_BaseFormat);
345 _mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format,
346 type, dst);
347 } else {
348 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba);
349 _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba,
350 rb->_BaseFormat);
351 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
352 type, dst, packing, transferOps);
353 }
354 dst += dstStride;
355 map += stride;
356 }
357
358 free(rgba);
359
360 done:
361 ctx->Driver.UnmapRenderbuffer(ctx, rb);
362 }
363
364 /*
365 * Read R, G, B, A, RGB, L, or LA pixels.
366 */
367 static void
368 read_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) &&
382 !_mesa_is_enum_format_integer(format)) {
383 transferOps |= IMAGE_CLAMP_BIT;
384 }
385
386 /* 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;
391 }
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 */
401 static GLboolean
402 fast_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);
422 if (!map) {
423 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
424 return GL_TRUE; /* don't bother trying the slow path */
425 }
426
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 */
445 static GLboolean
446 fast_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;
454 GLubyte *depthMap, *stencilMap, *stencilVals;
455 int depthStride, stencilStride, i, j;
456
457 if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED)
458 return GL_FALSE;
459
460 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
461 GL_MAP_READ_BIT, &depthMap, &depthStride);
462 if (!depthMap) {
463 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
464 return GL_TRUE; /* don't bother trying the slow path */
465 }
466
467 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
468 GL_MAP_READ_BIT, &stencilMap, &stencilStride);
469 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 }
474
475 stencilVals = (GLubyte *) malloc(width * sizeof(GLubyte));
476
477 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);
482
483 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;
490 }
491 }
492 else {
493 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
494 }
495
496 free(stencilVals);
497
498 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
499 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
500
501 return GL_TRUE;
502 }
503
504 static void
505 slow_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;
517 GLubyte *stencilVals;
518 GLfloat *depthVals;
519
520
521 /* The depth and stencil buffers might be separate, or a single buffer.
522 * If one buffer, only map it once.
523 */
524 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
525 GL_MAP_READ_BIT, &depthMap, &depthStride);
526 if (!depthMap) {
527 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
528 return;
529 }
530
531 if (stencilRb != depthRb) {
532 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
533 GL_MAP_READ_BIT, &stencilMap,
534 &stencilStride);
535 if (!stencilMap) {
536 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
537 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
538 return;
539 }
540 }
541 else {
542 stencilMap = depthMap;
543 stencilStride = depthStride;
544 }
545
546 stencilVals = (GLubyte *) malloc(width * sizeof(GLubyte));
547 depthVals = (GLfloat *) malloc(width * sizeof(GLfloat));
548
549 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);
554
555 _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst,
556 depthVals, stencilVals, packing);
557
558 depthMap += depthStride;
559 stencilMap += stencilStride;
560 dst += dstStride;
561 }
562 }
563 else {
564 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
565 }
566
567 free(stencilVals);
568 free(depthVals);
569
570 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
571 if (stencilRb != depthRb) {
572 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
573 }
574 }
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 */
582 static void
583 read_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 */
626 void
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
669 void GLAPIENTRY
670 _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height,
671 GLenum format, GLenum type, GLsizei bufSize,
672 GLvoid *pixels )
673 {
674 GLenum err;
675
676 GET_CURRENT_CONTEXT(ctx);
677 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
678
679 FLUSH_CURRENT(ctx, 0);
680
681 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
688 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
697 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));
702 return;
703 }
704
705 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
711 /* 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;
716 const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
717 const GLboolean dstInteger = _mesa_is_enum_format_integer(format);
718 if (dstInteger != srcInteger) {
719 _mesa_error(ctx, GL_INVALID_OPERATION,
720 "glReadPixels(integer / non-integer format mismatch");
721 return;
722 }
723 }
724
725 if (ctx->ReadBuffer->Name != 0 && ctx->ReadBuffer->Visual.samples > 0) {
726 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
727 return;
728 }
729
730 if (!_mesa_source_buffer_exists(ctx, format)) {
731 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
732 return;
733 }
734
735 if (width == 0 || height == 0)
736 return; /* nothing to do */
737
738 if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
739 format, type, bufSize, pixels)) {
740 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
741 _mesa_error(ctx, GL_INVALID_OPERATION,
742 "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);
747 }
748 return;
749 }
750
751 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;
756 }
757
758 ctx->Driver.ReadPixels(ctx, x, y, width, height,
759 format, type, &ctx->Pack, pixels);
760 }
761
762 void 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 }