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