mesa: add a couple fast-paths to fast_read_rgba_pixels_memcpy()
[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
40
41 /**
42 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
43 * mapping.
44 */
45 static GLboolean
46 fast_read_depth_pixels( struct gl_context *ctx,
47 GLint x, GLint y,
48 GLsizei width, GLsizei height,
49 GLenum type, GLvoid *pixels,
50 const struct gl_pixelstore_attrib *packing )
51 {
52 struct gl_framebuffer *fb = ctx->ReadBuffer;
53 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
54 GLubyte *map, *dst;
55 int stride, dstStride, j;
56
57 if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0)
58 return GL_FALSE;
59
60 if (packing->SwapBytes)
61 return GL_FALSE;
62
63 if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
64 return GL_FALSE;
65
66 if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) ||
67 type == GL_UNSIGNED_INT))
68 return GL_FALSE;
69
70 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
71 &map, &stride);
72
73 if (!map) {
74 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
75 return GL_TRUE; /* don't bother trying the slow path */
76 }
77
78 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
79 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
80 GL_DEPTH_COMPONENT, type, 0, 0);
81
82 for (j = 0; j < height; j++) {
83 if (type == GL_UNSIGNED_INT) {
84 _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
85 } else {
86 ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16);
87 memcpy(dst, map, width * 2);
88 }
89
90 map += stride;
91 dst += dstStride;
92 }
93 ctx->Driver.UnmapRenderbuffer(ctx, rb);
94
95 return GL_TRUE;
96 }
97
98 /**
99 * Read pixels for format=GL_DEPTH_COMPONENT.
100 */
101 static void
102 read_depth_pixels( struct gl_context *ctx,
103 GLint x, GLint y,
104 GLsizei width, GLsizei height,
105 GLenum type, GLvoid *pixels,
106 const struct gl_pixelstore_attrib *packing )
107 {
108 struct gl_framebuffer *fb = ctx->ReadBuffer;
109 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
110 GLint j;
111 GLubyte *dst, *map;
112 int dstStride, stride;
113 GLfloat *depthValues;
114
115 if (!rb)
116 return;
117
118 /* clipping should have been done already */
119 ASSERT(x >= 0);
120 ASSERT(y >= 0);
121 ASSERT(x + width <= (GLint) rb->Width);
122 ASSERT(y + height <= (GLint) rb->Height);
123
124 if (fast_read_depth_pixels(ctx, x, y, width, height, type, pixels, packing))
125 return;
126
127 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
128 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
129 GL_DEPTH_COMPONENT, type, 0, 0);
130
131 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
132 &map, &stride);
133 if (!map) {
134 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
135 return;
136 }
137
138 depthValues = (GLfloat *) malloc(width * sizeof(GLfloat));
139
140 if (depthValues) {
141 /* General case (slower) */
142 for (j = 0; j < height; j++, y++) {
143 _mesa_unpack_float_z_row(rb->Format, width, map, depthValues);
144 _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing);
145
146 dst += dstStride;
147 map += stride;
148 }
149 }
150 else {
151 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
152 }
153
154 free(depthValues);
155
156 ctx->Driver.UnmapRenderbuffer(ctx, rb);
157 }
158
159
160 /**
161 * Read pixels for format=GL_STENCIL_INDEX.
162 */
163 static void
164 read_stencil_pixels( struct gl_context *ctx,
165 GLint x, GLint y,
166 GLsizei width, GLsizei height,
167 GLenum type, GLvoid *pixels,
168 const struct gl_pixelstore_attrib *packing )
169 {
170 struct gl_framebuffer *fb = ctx->ReadBuffer;
171 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
172 GLint j;
173 GLubyte *map, *stencil;
174 GLint stride;
175
176 if (!rb)
177 return;
178
179 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
180 &map, &stride);
181 if (!map) {
182 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
183 return;
184 }
185
186 stencil = (GLubyte *) malloc(width * sizeof(GLubyte));
187
188 if (stencil) {
189 /* process image row by row */
190 for (j = 0; j < height; j++) {
191 GLvoid *dest;
192
193 _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil);
194 dest = _mesa_image_address2d(packing, pixels, width, height,
195 GL_STENCIL_INDEX, type, j, 0);
196
197 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
198
199 map += stride;
200 }
201 }
202 else {
203 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
204 }
205
206 free(stencil);
207
208 ctx->Driver.UnmapRenderbuffer(ctx, rb);
209 }
210
211
212 /**
213 * Try to do glReadPixels of RGBA data using a simple memcpy or swizzle.
214 * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
215 */
216 static GLboolean
217 fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
218 GLint x, GLint y,
219 GLsizei width, GLsizei height,
220 GLenum format, GLenum type,
221 GLvoid *pixels,
222 const struct gl_pixelstore_attrib *packing,
223 GLbitfield transferOps )
224 {
225 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
226 GLubyte *dst, *map;
227 int dstStride, stride, j, texelBytes;
228 GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE;
229
230 /* XXX we could check for other swizzle/special cases here as needed */
231 if (rb->Format == MESA_FORMAT_RGBA8888_REV &&
232 format == GL_BGRA &&
233 type == GL_UNSIGNED_INT_8_8_8_8_REV &&
234 !ctx->Pack.SwapBytes) {
235 swizzle_rb = GL_TRUE;
236 }
237 else if (rb->Format == MESA_FORMAT_XRGB8888 &&
238 format == GL_BGRA &&
239 type == GL_UNSIGNED_INT_8_8_8_8_REV &&
240 !ctx->Pack.SwapBytes) {
241 copy_xrgb = GL_TRUE;
242 }
243 else if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
244 ctx->Pack.SwapBytes))
245 return GL_FALSE;
246
247 /* If the format is unsigned normalized then we can ignore clamping
248 * because the values are already in the range [0,1] so it won't
249 * have any effect anyway.
250 */
251 if (_mesa_get_format_datatype(rb->Format) == GL_UNSIGNED_NORMALIZED)
252 transferOps &= ~IMAGE_CLAMP_BIT;
253
254 if (transferOps)
255 return GL_FALSE;
256
257 dstStride = _mesa_image_row_stride(packing, width, format, type);
258 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
259 format, type, 0, 0);
260
261 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
262 &map, &stride);
263 if (!map) {
264 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
265 return GL_TRUE; /* don't bother trying the slow path */
266 }
267
268 texelBytes = _mesa_get_format_bytes(rb->Format);
269
270 if (swizzle_rb) {
271 /* swap R/B */
272 for (j = 0; j < height; j++) {
273 int i;
274 for (i = 0; i < width; i++) {
275 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
276 GLuint pixel = map4[i];
277 dst4[i] = (pixel & 0xff00ff00)
278 | ((pixel & 0x00ff0000) >> 16)
279 | ((pixel & 0x000000ff) << 16);
280 }
281 dst += dstStride;
282 map += stride;
283 }
284 } else if (copy_xrgb) {
285 /* convert xrgb -> argb */
286 for (j = 0; j < height; j++) {
287 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
288 int i;
289 for (i = 0; i < width; i++) {
290 dst4[i] = map4[i] | 0xff000000; /* set A=0xff */
291 }
292 dst += dstStride;
293 map += stride;
294 }
295 } else {
296 /* just memcpy */
297 for (j = 0; j < height; j++) {
298 memcpy(dst, map, width * texelBytes);
299 dst += dstStride;
300 map += stride;
301 }
302 }
303
304 ctx->Driver.UnmapRenderbuffer(ctx, rb);
305
306 return GL_TRUE;
307 }
308
309 static void
310 slow_read_rgba_pixels( struct gl_context *ctx,
311 GLint x, GLint y,
312 GLsizei width, GLsizei height,
313 GLenum format, GLenum type,
314 GLvoid *pixels,
315 const struct gl_pixelstore_attrib *packing,
316 GLbitfield transferOps )
317 {
318 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
319 const gl_format rbFormat = _mesa_get_srgb_format_linear(rb->Format);
320 void *rgba;
321 GLubyte *dst, *map;
322 int dstStride, stride, j;
323
324 dstStride = _mesa_image_row_stride(packing, width, format, type);
325 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
326 format, type, 0, 0);
327
328 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
329 &map, &stride);
330 if (!map) {
331 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
332 return;
333 }
334
335 rgba = malloc(width * MAX_PIXEL_BYTES);
336 if (!rgba)
337 goto done;
338
339 for (j = 0; j < height; j++) {
340 if (_mesa_is_integer_format(format)) {
341 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
342 _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba,
343 rb->_BaseFormat);
344 _mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format,
345 type, dst);
346 } else {
347 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba);
348 _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba,
349 rb->_BaseFormat);
350 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
351 type, dst, packing, transferOps);
352 }
353 dst += dstStride;
354 map += stride;
355 }
356
357 free(rgba);
358
359 done:
360 ctx->Driver.UnmapRenderbuffer(ctx, rb);
361 }
362
363 /*
364 * Read R, G, B, A, RGB, L, or LA pixels.
365 */
366 static void
367 read_rgba_pixels( struct gl_context *ctx,
368 GLint x, GLint y,
369 GLsizei width, GLsizei height,
370 GLenum format, GLenum type, GLvoid *pixels,
371 const struct gl_pixelstore_attrib *packing )
372 {
373 GLbitfield transferOps = ctx->_ImageTransferState;
374 struct gl_framebuffer *fb = ctx->ReadBuffer;
375 struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
376
377 if (!rb)
378 return;
379
380 if ((ctx->Color._ClampReadColor == GL_TRUE || type != GL_FLOAT) &&
381 !_mesa_is_integer_format(format)) {
382 transferOps |= IMAGE_CLAMP_BIT;
383 }
384
385 /* Try the optimized paths first. */
386 if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height,
387 format, type, pixels, packing,
388 transferOps)) {
389 return;
390 }
391
392 slow_read_rgba_pixels(ctx, x, y, width, height,
393 format, type, pixels, packing, transferOps);
394 }
395
396 /**
397 * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the
398 * data (possibly swapping 8/24 vs 24/8 as we go).
399 */
400 static GLboolean
401 fast_read_depth_stencil_pixels(struct gl_context *ctx,
402 GLint x, GLint y,
403 GLsizei width, GLsizei height,
404 GLubyte *dst, int dstStride)
405 {
406 struct gl_framebuffer *fb = ctx->ReadBuffer;
407 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
408 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
409 GLubyte *map;
410 int stride, i;
411
412 if (rb != stencilRb)
413 return GL_FALSE;
414
415 if (rb->Format != MESA_FORMAT_Z24_S8 &&
416 rb->Format != MESA_FORMAT_S8_Z24)
417 return GL_FALSE;
418
419 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
420 &map, &stride);
421 if (!map) {
422 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
423 return GL_TRUE; /* don't bother trying the slow path */
424 }
425
426 for (i = 0; i < height; i++) {
427 _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width,
428 map, (GLuint *)dst);
429 map += stride;
430 dst += dstStride;
431 }
432
433 ctx->Driver.UnmapRenderbuffer(ctx, rb);
434
435 return GL_TRUE;
436 }
437
438
439 /**
440 * For non-float-depth and stencil buffers being read as 24/8 depth/stencil,
441 * copy the integer data directly instead of converting depth to float and
442 * re-packing.
443 */
444 static GLboolean
445 fast_read_depth_stencil_pixels_separate(struct gl_context *ctx,
446 GLint x, GLint y,
447 GLsizei width, GLsizei height,
448 uint32_t *dst, int dstStride)
449 {
450 struct gl_framebuffer *fb = ctx->ReadBuffer;
451 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
452 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
453 GLubyte *depthMap, *stencilMap, *stencilVals;
454 int depthStride, stencilStride, i, j;
455
456 if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED)
457 return GL_FALSE;
458
459 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
460 GL_MAP_READ_BIT, &depthMap, &depthStride);
461 if (!depthMap) {
462 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
463 return GL_TRUE; /* don't bother trying the slow path */
464 }
465
466 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
467 GL_MAP_READ_BIT, &stencilMap, &stencilStride);
468 if (!stencilMap) {
469 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
470 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
471 return GL_TRUE; /* don't bother trying the slow path */
472 }
473
474 stencilVals = (GLubyte *) malloc(width * sizeof(GLubyte));
475
476 if (stencilVals) {
477 for (j = 0; j < height; j++) {
478 _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst);
479 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
480 stencilMap, stencilVals);
481
482 for (i = 0; i < width; i++) {
483 dst[i] = (dst[i] & 0xffffff00) | stencilVals[i];
484 }
485
486 depthMap += depthStride;
487 stencilMap += stencilStride;
488 dst += dstStride / 4;
489 }
490 }
491 else {
492 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
493 }
494
495 free(stencilVals);
496
497 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
498 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
499
500 return GL_TRUE;
501 }
502
503 static void
504 slow_read_depth_stencil_pixels_separate(struct gl_context *ctx,
505 GLint x, GLint y,
506 GLsizei width, GLsizei height,
507 GLenum type,
508 const struct gl_pixelstore_attrib *packing,
509 GLubyte *dst, int dstStride)
510 {
511 struct gl_framebuffer *fb = ctx->ReadBuffer;
512 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
513 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
514 GLubyte *depthMap, *stencilMap;
515 int depthStride, stencilStride, j;
516 GLubyte *stencilVals;
517 GLfloat *depthVals;
518
519
520 /* The depth and stencil buffers might be separate, or a single buffer.
521 * If one buffer, only map it once.
522 */
523 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
524 GL_MAP_READ_BIT, &depthMap, &depthStride);
525 if (!depthMap) {
526 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
527 return;
528 }
529
530 if (stencilRb != depthRb) {
531 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
532 GL_MAP_READ_BIT, &stencilMap,
533 &stencilStride);
534 if (!stencilMap) {
535 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
536 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
537 return;
538 }
539 }
540 else {
541 stencilMap = depthMap;
542 stencilStride = depthStride;
543 }
544
545 stencilVals = (GLubyte *) malloc(width * sizeof(GLubyte));
546 depthVals = (GLfloat *) malloc(width * sizeof(GLfloat));
547
548 if (stencilVals && depthVals) {
549 for (j = 0; j < height; j++) {
550 _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals);
551 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
552 stencilMap, stencilVals);
553
554 _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst,
555 depthVals, stencilVals, packing);
556
557 depthMap += depthStride;
558 stencilMap += stencilStride;
559 dst += dstStride;
560 }
561 }
562 else {
563 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
564 }
565
566 free(stencilVals);
567 free(depthVals);
568
569 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
570 if (stencilRb != depthRb) {
571 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
572 }
573 }
574
575
576 /**
577 * Read combined depth/stencil values.
578 * We'll have already done error checking to be sure the expected
579 * depth and stencil buffers really exist.
580 */
581 static void
582 read_depth_stencil_pixels(struct gl_context *ctx,
583 GLint x, GLint y,
584 GLsizei width, GLsizei height,
585 GLenum type, GLvoid *pixels,
586 const struct gl_pixelstore_attrib *packing )
587 {
588 const GLboolean scaleOrBias
589 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
590 const GLboolean stencilTransfer = ctx->Pixel.IndexShift
591 || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag;
592 GLubyte *dst;
593 int dstStride;
594
595 dst = (GLubyte *) _mesa_image_address2d(packing, pixels,
596 width, height,
597 GL_DEPTH_STENCIL_EXT,
598 type, 0, 0);
599 dstStride = _mesa_image_row_stride(packing, width,
600 GL_DEPTH_STENCIL_EXT, type);
601
602 /* Fast 24/8 reads. */
603 if (type == GL_UNSIGNED_INT_24_8 &&
604 !scaleOrBias && !stencilTransfer && !packing->SwapBytes) {
605 if (fast_read_depth_stencil_pixels(ctx, x, y, width, height,
606 dst, dstStride))
607 return;
608
609 if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
610 (uint32_t *)dst, dstStride))
611 return;
612 }
613
614 slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
615 type, packing,
616 dst, dstStride);
617 }
618
619
620
621 /**
622 * Software fallback routine for ctx->Driver.ReadPixels().
623 * By time we get here, all error checking will have been done.
624 */
625 void
626 _mesa_readpixels(struct gl_context *ctx,
627 GLint x, GLint y, GLsizei width, GLsizei height,
628 GLenum format, GLenum type,
629 const struct gl_pixelstore_attrib *packing,
630 GLvoid *pixels)
631 {
632 struct gl_pixelstore_attrib clippedPacking = *packing;
633
634 if (ctx->NewState)
635 _mesa_update_state(ctx);
636
637 /* Do all needed clipping here, so that we can forget about it later */
638 if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
639
640 pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels);
641
642 if (pixels) {
643 switch (format) {
644 case GL_STENCIL_INDEX:
645 read_stencil_pixels(ctx, x, y, width, height, type, pixels,
646 &clippedPacking);
647 break;
648 case GL_DEPTH_COMPONENT:
649 read_depth_pixels(ctx, x, y, width, height, type, pixels,
650 &clippedPacking);
651 break;
652 case GL_DEPTH_STENCIL_EXT:
653 read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels,
654 &clippedPacking);
655 break;
656 default:
657 /* all other formats should be color formats */
658 read_rgba_pixels(ctx, x, y, width, height, format, type, pixels,
659 &clippedPacking);
660 }
661
662 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
663 }
664 }
665 }
666
667
668 void GLAPIENTRY
669 _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height,
670 GLenum format, GLenum type, GLsizei bufSize,
671 GLvoid *pixels )
672 {
673 GLenum err;
674
675 GET_CURRENT_CONTEXT(ctx);
676 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
677
678 FLUSH_CURRENT(ctx, 0);
679
680 if (MESA_VERBOSE & VERBOSE_API)
681 _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
682 width, height,
683 _mesa_lookup_enum_by_nr(format),
684 _mesa_lookup_enum_by_nr(type),
685 pixels);
686
687 if (width < 0 || height < 0) {
688 _mesa_error( ctx, GL_INVALID_VALUE,
689 "glReadPixels(width=%d height=%d)", width, height );
690 return;
691 }
692
693 if (ctx->NewState)
694 _mesa_update_state(ctx);
695
696 err = _mesa_error_check_format_and_type(ctx, format, type);
697 if (err != GL_NO_ERROR) {
698 _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
699 _mesa_lookup_enum_by_nr(format),
700 _mesa_lookup_enum_by_nr(type));
701 return;
702 }
703
704 /* Check that the destination format and source buffer are both
705 * integer-valued or both non-integer-valued.
706 */
707 if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
708 const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
709 const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
710 const GLboolean dstInteger = _mesa_is_integer_format(format);
711 if (dstInteger != srcInteger) {
712 _mesa_error(ctx, GL_INVALID_OPERATION,
713 "glReadPixels(integer / non-integer format mismatch");
714 return;
715 }
716 }
717
718 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
719 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
720 "glReadPixels(incomplete framebuffer)" );
721 return;
722 }
723
724 if (ctx->ReadBuffer->Name != 0 && ctx->ReadBuffer->Visual.samples > 0) {
725 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
726 return;
727 }
728
729 if (!_mesa_source_buffer_exists(ctx, format)) {
730 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
731 return;
732 }
733
734 if (width == 0 || height == 0)
735 return; /* nothing to do */
736
737 if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
738 format, type, bufSize, pixels)) {
739 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
740 _mesa_error(ctx, GL_INVALID_OPERATION,
741 "glReadPixels(out of bounds PBO access)");
742 } else {
743 _mesa_error(ctx, GL_INVALID_OPERATION,
744 "glReadnPixelsARB(out of bounds access:"
745 " bufSize (%d) is too small)", bufSize);
746 }
747 return;
748 }
749
750 if (_mesa_is_bufferobj(ctx->Pack.BufferObj) &&
751 _mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
752 /* buffer is mapped - that's an error */
753 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
754 return;
755 }
756
757 ctx->Driver.ReadPixels(ctx, x, y, width, height,
758 format, type, &ctx->Pack, pixels);
759 }
760
761 void GLAPIENTRY
762 _mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
763 GLenum format, GLenum type, GLvoid *pixels )
764 {
765 _mesa_ReadnPixelsARB(x, y, width, height, format, type, INT_MAX, pixels);
766 }