mesa: added swapBytes parameter to _mesa_format_matches_format_and_type()
[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
114 if (!rb)
115 return;
116
117 /* clipping should have been done already */
118 ASSERT(x >= 0);
119 ASSERT(y >= 0);
120 ASSERT(x + width <= (GLint) rb->Width);
121 ASSERT(y + height <= (GLint) rb->Height);
122 /* width should never be > MAX_WIDTH since we did clipping earlier */
123 ASSERT(width <= MAX_WIDTH);
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 /* General case (slower) */
140 for (j = 0; j < height; j++, y++) {
141 GLfloat depthValues[MAX_WIDTH];
142 _mesa_unpack_float_z_row(rb->Format, width, map, depthValues);
143 _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing);
144
145 dst += dstStride;
146 map += stride;
147 }
148
149 ctx->Driver.UnmapRenderbuffer(ctx, rb);
150 }
151
152
153 /**
154 * Read pixels for format=GL_STENCIL_INDEX.
155 */
156 static void
157 read_stencil_pixels( struct gl_context *ctx,
158 GLint x, GLint y,
159 GLsizei width, GLsizei height,
160 GLenum type, GLvoid *pixels,
161 const struct gl_pixelstore_attrib *packing )
162 {
163 struct gl_framebuffer *fb = ctx->ReadBuffer;
164 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
165 GLint j;
166 GLubyte *map;
167 GLint stride;
168
169 if (!rb)
170 return;
171
172 /* width should never be > MAX_WIDTH since we did clipping earlier */
173 ASSERT(width <= MAX_WIDTH);
174
175 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
176 &map, &stride);
177 if (!map) {
178 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
179 return;
180 }
181
182 /* process image row by row */
183 for (j = 0; j < height; j++) {
184 GLvoid *dest;
185 GLubyte stencil[MAX_WIDTH];
186
187 _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil);
188 dest = _mesa_image_address2d(packing, pixels, width, height,
189 GL_STENCIL_INDEX, type, j, 0);
190
191 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
192
193 map += stride;
194 }
195
196 ctx->Driver.UnmapRenderbuffer(ctx, rb);
197 }
198
199 static GLboolean
200 fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
201 GLint x, GLint y,
202 GLsizei width, GLsizei height,
203 GLenum format, GLenum type,
204 GLvoid *pixels,
205 const struct gl_pixelstore_attrib *packing,
206 GLbitfield transferOps )
207 {
208 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
209 GLubyte *dst, *map;
210 int dstStride, stride, j, texelBytes;
211
212 if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
213 ctx->Pack.SwapBytes))
214 return GL_FALSE;
215
216 /* check for things we can't handle here */
217 if (packing->SwapBytes) {
218 return GL_FALSE;
219 }
220
221 dstStride = _mesa_image_row_stride(packing, width, format, type);
222 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
223 format, type, 0, 0);
224
225 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
226 &map, &stride);
227 if (!map) {
228 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
229 return GL_TRUE; /* don't bother trying the slow path */
230 }
231
232 texelBytes = _mesa_get_format_bytes(rb->Format);
233 for (j = 0; j < height; j++) {
234 memcpy(dst, map, width * texelBytes);
235 dst += dstStride;
236 map += stride;
237 }
238
239 ctx->Driver.UnmapRenderbuffer(ctx, rb);
240
241 return GL_TRUE;
242 }
243
244 static void
245 slow_read_rgba_pixels( struct gl_context *ctx,
246 GLint x, GLint y,
247 GLsizei width, GLsizei height,
248 GLenum format, GLenum type,
249 GLvoid *pixels,
250 const struct gl_pixelstore_attrib *packing,
251 GLbitfield transferOps )
252 {
253 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
254 const gl_format rbFormat = _mesa_get_srgb_format_linear(rb->Format);
255 void *rgba;
256 GLubyte *dst, *map;
257 int dstStride, stride, j;
258
259 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);
265 if (!map) {
266 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
267 return;
268 }
269
270 rgba = malloc(width * MAX_PIXEL_BYTES);
271 if (!rgba)
272 goto done;
273
274 for (j = 0; j < height; j++) {
275 if (_mesa_is_integer_format(format)) {
276 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
277 _mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format,
278 type, dst);
279 } else {
280 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba);
281 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
282 type, dst, packing, transferOps);
283 }
284 dst += dstStride;
285 map += stride;
286 }
287
288 free(rgba);
289
290 done:
291 ctx->Driver.UnmapRenderbuffer(ctx, rb);
292 }
293
294 /*
295 * Read R, G, B, A, RGB, L, or LA pixels.
296 */
297 static void
298 read_rgba_pixels( struct gl_context *ctx,
299 GLint x, GLint y,
300 GLsizei width, GLsizei height,
301 GLenum format, GLenum type, GLvoid *pixels,
302 const struct gl_pixelstore_attrib *packing )
303 {
304 GLbitfield transferOps = ctx->_ImageTransferState;
305 struct gl_framebuffer *fb = ctx->ReadBuffer;
306 struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
307
308 if (!rb)
309 return;
310
311 if ((ctx->Color._ClampReadColor == GL_TRUE || type != GL_FLOAT) &&
312 !_mesa_is_integer_format(format)) {
313 transferOps |= IMAGE_CLAMP_BIT;
314 }
315
316 if (!transferOps) {
317 /* Try the optimized paths first. */
318 if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height,
319 format, type, pixels, packing,
320 transferOps)) {
321 return;
322 }
323 }
324
325 slow_read_rgba_pixels(ctx, x, y, width, height,
326 format, type, pixels, packing, transferOps);
327 }
328
329 /**
330 * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the
331 * data (possibly swapping 8/24 vs 24/8 as we go).
332 */
333 static GLboolean
334 fast_read_depth_stencil_pixels(struct gl_context *ctx,
335 GLint x, GLint y,
336 GLsizei width, GLsizei height,
337 GLubyte *dst, int dstStride)
338 {
339 struct gl_framebuffer *fb = ctx->ReadBuffer;
340 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
341 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
342 GLubyte *map;
343 int stride, i;
344
345 if (rb != stencilRb)
346 return GL_FALSE;
347
348 if (rb->Format != MESA_FORMAT_Z24_S8 &&
349 rb->Format != MESA_FORMAT_S8_Z24)
350 return GL_FALSE;
351
352 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
353 &map, &stride);
354 if (!map) {
355 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
356 return GL_TRUE; /* don't bother trying the slow path */
357 }
358
359 for (i = 0; i < height; i++) {
360 _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width,
361 map, (GLuint *)dst);
362 map += stride;
363 dst += dstStride;
364 }
365
366 ctx->Driver.UnmapRenderbuffer(ctx, rb);
367
368 return GL_TRUE;
369 }
370
371
372 /**
373 * For non-float-depth and stencil buffers being read as 24/8 depth/stencil,
374 * copy the integer data directly instead of converting depth to float and
375 * re-packing.
376 */
377 static GLboolean
378 fast_read_depth_stencil_pixels_separate(struct gl_context *ctx,
379 GLint x, GLint y,
380 GLsizei width, GLsizei height,
381 uint32_t *dst, int dstStride)
382 {
383 struct gl_framebuffer *fb = ctx->ReadBuffer;
384 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
385 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
386 GLubyte *depthMap, *stencilMap;
387 int depthStride, stencilStride, i, j;
388
389 if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED)
390 return GL_FALSE;
391
392 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
393 GL_MAP_READ_BIT, &depthMap, &depthStride);
394 if (!depthMap) {
395 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
396 return GL_TRUE; /* don't bother trying the slow path */
397 }
398
399 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
400 GL_MAP_READ_BIT, &stencilMap, &stencilStride);
401 if (!stencilMap) {
402 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
403 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
404 return GL_TRUE; /* don't bother trying the slow path */
405 }
406
407 for (j = 0; j < height; j++) {
408 GLubyte stencilVals[MAX_WIDTH];
409
410 _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst);
411 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
412 stencilMap, stencilVals);
413
414 for (i = 0; i < width; i++) {
415 dst[i] = (dst[i] & 0xffffff00) | stencilVals[i];
416 }
417
418 depthMap += depthStride;
419 stencilMap += stencilStride;
420 dst += dstStride / 4;
421 }
422
423 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
424 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
425
426 return GL_TRUE;
427 }
428
429 static void
430 slow_read_depth_stencil_pixels_separate(struct gl_context *ctx,
431 GLint x, GLint y,
432 GLsizei width, GLsizei height,
433 GLenum type,
434 const struct gl_pixelstore_attrib *packing,
435 GLubyte *dst, int dstStride)
436 {
437 struct gl_framebuffer *fb = ctx->ReadBuffer;
438 struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
439 struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
440 GLubyte *depthMap, *stencilMap;
441 int depthStride, stencilStride, j;
442
443 /* The depth and stencil buffers might be separate, or a single buffer.
444 * If one buffer, only map it once.
445 */
446 ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
447 GL_MAP_READ_BIT, &depthMap, &depthStride);
448 if (!depthMap) {
449 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
450 return;
451 }
452
453 if (stencilRb != depthRb) {
454 ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
455 GL_MAP_READ_BIT, &stencilMap,
456 &stencilStride);
457 if (!stencilMap) {
458 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
459 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
460 return;
461 }
462 }
463 else {
464 stencilMap = depthMap;
465 stencilStride = depthStride;
466 }
467
468 for (j = 0; j < height; j++) {
469 GLubyte stencilVals[MAX_WIDTH];
470 GLfloat depthVals[MAX_WIDTH];
471
472 _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals);
473 _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
474 stencilMap, stencilVals);
475
476 _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst,
477 depthVals, stencilVals, packing);
478
479 depthMap += depthStride;
480 stencilMap += stencilStride;
481 dst += dstStride;
482 }
483
484 ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
485 if (stencilRb != depthRb) {
486 ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
487 }
488 }
489
490
491 /**
492 * Read combined depth/stencil values.
493 * We'll have already done error checking to be sure the expected
494 * depth and stencil buffers really exist.
495 */
496 static void
497 read_depth_stencil_pixels(struct gl_context *ctx,
498 GLint x, GLint y,
499 GLsizei width, GLsizei height,
500 GLenum type, GLvoid *pixels,
501 const struct gl_pixelstore_attrib *packing )
502 {
503 const GLboolean scaleOrBias
504 = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
505 const GLboolean stencilTransfer = ctx->Pixel.IndexShift
506 || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag;
507 GLubyte *dst;
508 int dstStride;
509
510 dst = (GLubyte *) _mesa_image_address2d(packing, pixels,
511 width, height,
512 GL_DEPTH_STENCIL_EXT,
513 type, 0, 0);
514 dstStride = _mesa_image_row_stride(packing, width,
515 GL_DEPTH_STENCIL_EXT, type);
516
517 /* Fast 24/8 reads. */
518 if (type == GL_UNSIGNED_INT_24_8 &&
519 !scaleOrBias && !stencilTransfer && !packing->SwapBytes) {
520 if (fast_read_depth_stencil_pixels(ctx, x, y, width, height,
521 dst, dstStride))
522 return;
523
524 if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
525 (uint32_t *)dst, dstStride))
526 return;
527 }
528
529 slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
530 type, packing,
531 dst, dstStride);
532 }
533
534
535
536 /**
537 * Software fallback routine for ctx->Driver.ReadPixels().
538 * By time we get here, all error checking will have been done.
539 */
540 void
541 _mesa_readpixels(struct gl_context *ctx,
542 GLint x, GLint y, GLsizei width, GLsizei height,
543 GLenum format, GLenum type,
544 const struct gl_pixelstore_attrib *packing,
545 GLvoid *pixels)
546 {
547 struct gl_pixelstore_attrib clippedPacking = *packing;
548
549 if (ctx->NewState)
550 _mesa_update_state(ctx);
551
552 /* Do all needed clipping here, so that we can forget about it later */
553 if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
554
555 pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels);
556
557 if (pixels) {
558 switch (format) {
559 case GL_STENCIL_INDEX:
560 read_stencil_pixels(ctx, x, y, width, height, type, pixels,
561 &clippedPacking);
562 break;
563 case GL_DEPTH_COMPONENT:
564 read_depth_pixels(ctx, x, y, width, height, type, pixels,
565 &clippedPacking);
566 break;
567 case GL_DEPTH_STENCIL_EXT:
568 read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels,
569 &clippedPacking);
570 break;
571 default:
572 /* all other formats should be color formats */
573 read_rgba_pixels(ctx, x, y, width, height, format, type, pixels,
574 &clippedPacking);
575 }
576
577 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
578 }
579 }
580 }
581
582
583 /**
584 * Do error checking of the format/type parameters to glReadPixels and
585 * glDrawPixels.
586 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking
587 * for ReadPixels.
588 * \return GL_TRUE if error detected, GL_FALSE if no errors
589 */
590 GLboolean
591 _mesa_error_check_format_type(struct gl_context *ctx, GLenum format,
592 GLenum type, GLboolean drawing)
593 {
594 const char *readDraw = drawing ? "Draw" : "Read";
595 const GLboolean reading = !drawing;
596
597 /* state validation should have already been done */
598 ASSERT(ctx->NewState == 0x0);
599
600 if (ctx->Extensions.EXT_packed_depth_stencil
601 && type == GL_UNSIGNED_INT_24_8_EXT
602 && format != GL_DEPTH_STENCIL_EXT) {
603 _mesa_error(ctx, GL_INVALID_OPERATION,
604 "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw);
605 return GL_TRUE;
606 }
607
608 if (ctx->Extensions.ARB_depth_buffer_float
609 && type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV
610 && format != GL_DEPTH_STENCIL_EXT) {
611 _mesa_error(ctx, GL_INVALID_OPERATION,
612 "gl%sPixels(format is not GL_DEPTH_STENCIL_EXT)", readDraw);
613 return GL_TRUE;
614 }
615
616 /* basic combinations test */
617 if (!_mesa_is_legal_format_and_type(ctx, format, type)) {
618 _mesa_error(ctx, GL_INVALID_ENUM,
619 "gl%sPixels(format or type)", readDraw);
620 return GL_TRUE;
621 }
622
623 /* additional checks */
624 switch (format) {
625 case GL_RG:
626 case GL_RED:
627 case GL_GREEN:
628 case GL_BLUE:
629 case GL_ALPHA:
630 case GL_LUMINANCE:
631 case GL_LUMINANCE_ALPHA:
632 case GL_RGB:
633 case GL_BGR:
634 case GL_RGBA:
635 case GL_BGRA:
636 case GL_ABGR_EXT:
637 case GL_RED_INTEGER_EXT:
638 case GL_GREEN_INTEGER_EXT:
639 case GL_BLUE_INTEGER_EXT:
640 case GL_ALPHA_INTEGER_EXT:
641 case GL_RGB_INTEGER_EXT:
642 case GL_RGBA_INTEGER_EXT:
643 case GL_BGR_INTEGER_EXT:
644 case GL_BGRA_INTEGER_EXT:
645 case GL_LUMINANCE_INTEGER_EXT:
646 case GL_LUMINANCE_ALPHA_INTEGER_EXT:
647 if (!drawing) {
648 /* reading */
649 if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) {
650 _mesa_error(ctx, GL_INVALID_OPERATION,
651 "glReadPixels(no color buffer)");
652 return GL_TRUE;
653 }
654 }
655 break;
656 case GL_COLOR_INDEX:
657 if (drawing) {
658 if (ctx->PixelMaps.ItoR.Size == 0 ||
659 ctx->PixelMaps.ItoG.Size == 0 ||
660 ctx->PixelMaps.ItoB.Size == 0) {
661 _mesa_error(ctx, GL_INVALID_OPERATION,
662 "glDrawPixels(drawing color index pixels into RGB buffer)");
663 return GL_TRUE;
664 }
665 }
666 else {
667 /* reading */
668 if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) {
669 _mesa_error(ctx, GL_INVALID_OPERATION,
670 "glReadPixels(no color buffer)");
671 return GL_TRUE;
672 }
673 /* We no longer support CI-mode color buffers so trying to read
674 * GL_COLOR_INDEX pixels is always an error.
675 */
676 _mesa_error(ctx, GL_INVALID_OPERATION,
677 "glReadPixels(color buffer is RGB)");
678 return GL_TRUE;
679 }
680 break;
681 case GL_STENCIL_INDEX:
682 if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) ||
683 (reading && !_mesa_source_buffer_exists(ctx, format))) {
684 _mesa_error(ctx, GL_INVALID_OPERATION,
685 "gl%sPixels(no stencil buffer)", readDraw);
686 return GL_TRUE;
687 }
688 break;
689 case GL_DEPTH_COMPONENT:
690 if ((drawing && !_mesa_dest_buffer_exists(ctx, format))) {
691 _mesa_error(ctx, GL_INVALID_OPERATION,
692 "gl%sPixels(no depth buffer)", readDraw);
693 return GL_TRUE;
694 }
695 break;
696 case GL_DEPTH_STENCIL_EXT:
697 /* Check validity of the type first. */
698 switch (type) {
699 case GL_UNSIGNED_INT_24_8_EXT:
700 if (!ctx->Extensions.EXT_packed_depth_stencil) {
701 _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw);
702 return GL_TRUE;
703 }
704 break;
705 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
706 if (!ctx->Extensions.ARB_depth_buffer_float) {
707 _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw);
708 return GL_TRUE;
709 }
710 break;
711 default:
712 _mesa_error(ctx, GL_INVALID_ENUM, "gl%sPixels(type)", readDraw);
713 return GL_TRUE;
714 }
715 if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) ||
716 (reading && !_mesa_source_buffer_exists(ctx, format))) {
717 _mesa_error(ctx, GL_INVALID_OPERATION,
718 "gl%sPixels(no depth or stencil buffer)", readDraw);
719 return GL_TRUE;
720 }
721 break;
722 default:
723 /* this should have been caught in _mesa_is_legal_format_type() */
724 _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw);
725 return GL_TRUE;
726 }
727
728 /* no errors */
729 return GL_FALSE;
730 }
731
732
733
734 void GLAPIENTRY
735 _mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height,
736 GLenum format, GLenum type, GLsizei bufSize,
737 GLvoid *pixels )
738 {
739 GET_CURRENT_CONTEXT(ctx);
740 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
741
742 FLUSH_CURRENT(ctx, 0);
743
744 if (MESA_VERBOSE & VERBOSE_API)
745 _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
746 width, height,
747 _mesa_lookup_enum_by_nr(format),
748 _mesa_lookup_enum_by_nr(type),
749 pixels);
750
751 if (width < 0 || height < 0) {
752 _mesa_error( ctx, GL_INVALID_VALUE,
753 "glReadPixels(width=%d height=%d)", width, height );
754 return;
755 }
756
757 if (ctx->NewState)
758 _mesa_update_state(ctx);
759
760 if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) {
761 /* found an error */
762 return;
763 }
764
765 /* Check that the destination format and source buffer are both
766 * integer-valued or both non-integer-valued.
767 */
768 if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
769 const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
770 const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
771 const GLboolean dstInteger = _mesa_is_integer_format(format);
772 if (dstInteger != srcInteger) {
773 _mesa_error(ctx, GL_INVALID_OPERATION,
774 "glReadPixels(integer / non-integer format mismatch");
775 return;
776 }
777 }
778
779 if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
780 _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
781 "glReadPixels(incomplete framebuffer)" );
782 return;
783 }
784
785 if (ctx->ReadBuffer->Name != 0 && ctx->ReadBuffer->Visual.samples > 0) {
786 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
787 return;
788 }
789
790 if (!_mesa_source_buffer_exists(ctx, format)) {
791 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
792 return;
793 }
794
795 if (width == 0 || height == 0)
796 return; /* nothing to do */
797
798 if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
799 format, type, bufSize, pixels)) {
800 if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
801 _mesa_error(ctx, GL_INVALID_OPERATION,
802 "glReadPixels(out of bounds PBO access)");
803 } else {
804 _mesa_error(ctx, GL_INVALID_OPERATION,
805 "glReadnPixelsARB(out of bounds access:"
806 " bufSize (%d) is too small)", bufSize);
807 }
808 return;
809 }
810
811 if (_mesa_is_bufferobj(ctx->Pack.BufferObj) &&
812 _mesa_bufferobj_mapped(ctx->Pack.BufferObj)) {
813 /* buffer is mapped - that's an error */
814 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
815 return;
816 }
817
818 ctx->Driver.ReadPixels(ctx, x, y, width, height,
819 format, type, &ctx->Pack, pixels);
820 }
821
822 void GLAPIENTRY
823 _mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
824 GLenum format, GLenum type, GLvoid *pixels )
825 {
826 _mesa_ReadnPixelsARB(x, y, width, height, format, type, INT_MAX, pixels);
827 }