readpix.c revision 848b8605
1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg#include "glheader.h"
26848b8605Smrg#include "imports.h"
27848b8605Smrg#include "blend.h"
28848b8605Smrg#include "bufferobj.h"
29848b8605Smrg#include "context.h"
30848b8605Smrg#include "enums.h"
31848b8605Smrg#include "readpix.h"
32848b8605Smrg#include "framebuffer.h"
33848b8605Smrg#include "formats.h"
34848b8605Smrg#include "format_unpack.h"
35848b8605Smrg#include "image.h"
36848b8605Smrg#include "mtypes.h"
37848b8605Smrg#include "pack.h"
38848b8605Smrg#include "pbo.h"
39848b8605Smrg#include "state.h"
40848b8605Smrg#include "glformats.h"
41848b8605Smrg#include "fbobject.h"
42848b8605Smrg
43848b8605Smrg
44848b8605Smrg/**
45848b8605Smrg * Return true if the conversion L=R+G+B is needed.
46848b8605Smrg */
47848b8605Smrgstatic GLboolean
48848b8605Smrgneed_rgb_to_luminance_conversion(mesa_format texFormat, GLenum format)
49848b8605Smrg{
50848b8605Smrg   GLenum baseTexFormat = _mesa_get_format_base_format(texFormat);
51848b8605Smrg
52848b8605Smrg   return (baseTexFormat == GL_RG ||
53848b8605Smrg           baseTexFormat == GL_RGB ||
54848b8605Smrg           baseTexFormat == GL_RGBA) &&
55848b8605Smrg          (format == GL_LUMINANCE || format == GL_LUMINANCE_ALPHA);
56848b8605Smrg}
57848b8605Smrg
58848b8605Smrg
59848b8605Smrg/**
60848b8605Smrg * Return transfer op flags for this ReadPixels operation.
61848b8605Smrg */
62848b8605Smrgstatic GLbitfield
63848b8605Smrgget_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat,
64848b8605Smrg                            GLenum format, GLenum type, GLboolean uses_blit)
65848b8605Smrg{
66848b8605Smrg   GLbitfield transferOps = ctx->_ImageTransferState;
67848b8605Smrg
68848b8605Smrg   if (format == GL_DEPTH_COMPONENT ||
69848b8605Smrg       format == GL_DEPTH_STENCIL ||
70848b8605Smrg       format == GL_STENCIL_INDEX) {
71848b8605Smrg      return 0;
72848b8605Smrg   }
73848b8605Smrg
74848b8605Smrg   /* Pixel transfer ops (scale, bias, table lookup) do not apply
75848b8605Smrg    * to integer formats.
76848b8605Smrg    */
77848b8605Smrg   if (_mesa_is_enum_format_integer(format)) {
78848b8605Smrg      return 0;
79848b8605Smrg   }
80848b8605Smrg
81848b8605Smrg   if (uses_blit) {
82848b8605Smrg      /* For blit-based ReadPixels packing, the clamping is done automatically
83848b8605Smrg       * unless the type is float. */
84848b8605Smrg      if (_mesa_get_clamp_read_color(ctx) &&
85848b8605Smrg          (type == GL_FLOAT || type == GL_HALF_FLOAT)) {
86848b8605Smrg         transferOps |= IMAGE_CLAMP_BIT;
87848b8605Smrg      }
88848b8605Smrg   }
89848b8605Smrg   else {
90848b8605Smrg      /* For CPU-based ReadPixels packing, the clamping must always be done
91848b8605Smrg       * for non-float types, */
92848b8605Smrg      if (_mesa_get_clamp_read_color(ctx) ||
93848b8605Smrg          (type != GL_FLOAT && type != GL_HALF_FLOAT)) {
94848b8605Smrg         transferOps |= IMAGE_CLAMP_BIT;
95848b8605Smrg      }
96848b8605Smrg   }
97848b8605Smrg
98848b8605Smrg   /* If the format is unsigned normalized, we can ignore clamping
99848b8605Smrg    * because the values are already in the range [0,1] so it won't
100848b8605Smrg    * have any effect anyway.
101848b8605Smrg    */
102848b8605Smrg   if (_mesa_get_format_datatype(texFormat) == GL_UNSIGNED_NORMALIZED &&
103848b8605Smrg       !need_rgb_to_luminance_conversion(texFormat, format)) {
104848b8605Smrg      transferOps &= ~IMAGE_CLAMP_BIT;
105848b8605Smrg   }
106848b8605Smrg
107848b8605Smrg   return transferOps;
108848b8605Smrg}
109848b8605Smrg
110848b8605Smrg
111848b8605Smrg/**
112848b8605Smrg * Return true if memcpy cannot be used for ReadPixels.
113848b8605Smrg *
114848b8605Smrg * If uses_blit is true, the function returns true if a simple 3D engine blit
115848b8605Smrg * cannot be used for ReadPixels packing.
116848b8605Smrg *
117848b8605Smrg * NOTE: This doesn't take swizzling and format conversions between
118848b8605Smrg *       the readbuffer and the pixel pack buffer into account.
119848b8605Smrg */
120848b8605SmrgGLboolean
121848b8605Smrg_mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format,
122848b8605Smrg                                 GLenum type, GLboolean uses_blit)
123848b8605Smrg{
124848b8605Smrg   struct gl_renderbuffer *rb =
125848b8605Smrg         _mesa_get_read_renderbuffer_for_format(ctx, format);
126848b8605Smrg   GLenum srcType;
127848b8605Smrg
128848b8605Smrg   ASSERT(rb);
129848b8605Smrg
130848b8605Smrg   /* There are different rules depending on the base format. */
131848b8605Smrg   switch (format) {
132848b8605Smrg   case GL_DEPTH_STENCIL:
133848b8605Smrg      return !_mesa_has_depthstencil_combined(ctx->ReadBuffer) ||
134848b8605Smrg             ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f ||
135848b8605Smrg             ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
136848b8605Smrg             ctx->Pixel.MapStencilFlag;
137848b8605Smrg
138848b8605Smrg   case GL_DEPTH_COMPONENT:
139848b8605Smrg      return ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f;
140848b8605Smrg
141848b8605Smrg   case GL_STENCIL_INDEX:
142848b8605Smrg      return ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
143848b8605Smrg             ctx->Pixel.MapStencilFlag;
144848b8605Smrg
145848b8605Smrg   default:
146848b8605Smrg      /* Color formats. */
147848b8605Smrg      if (need_rgb_to_luminance_conversion(rb->Format, format)) {
148848b8605Smrg         return GL_TRUE;
149848b8605Smrg      }
150848b8605Smrg
151848b8605Smrg      /* Conversion between signed and unsigned integers needs masking
152848b8605Smrg       * (it isn't just memcpy). */
153848b8605Smrg      srcType = _mesa_get_format_datatype(rb->Format);
154848b8605Smrg
155848b8605Smrg      if ((srcType == GL_INT &&
156848b8605Smrg           (type == GL_UNSIGNED_INT ||
157848b8605Smrg            type == GL_UNSIGNED_SHORT ||
158848b8605Smrg            type == GL_UNSIGNED_BYTE)) ||
159848b8605Smrg          (srcType == GL_UNSIGNED_INT &&
160848b8605Smrg           (type == GL_INT ||
161848b8605Smrg            type == GL_SHORT ||
162848b8605Smrg            type == GL_BYTE))) {
163848b8605Smrg         return GL_TRUE;
164848b8605Smrg      }
165848b8605Smrg
166848b8605Smrg      /* And finally, see if there are any transfer ops. */
167848b8605Smrg      return get_readpixels_transfer_ops(ctx, rb->Format, format, type,
168848b8605Smrg                                         uses_blit) != 0;
169848b8605Smrg   }
170848b8605Smrg   return GL_FALSE;
171848b8605Smrg}
172848b8605Smrg
173848b8605Smrg
174848b8605Smrgstatic GLboolean
175848b8605Smrgreadpixels_can_use_memcpy(const struct gl_context *ctx, GLenum format, GLenum type,
176848b8605Smrg                          const struct gl_pixelstore_attrib *packing)
177848b8605Smrg{
178848b8605Smrg   struct gl_renderbuffer *rb =
179848b8605Smrg         _mesa_get_read_renderbuffer_for_format(ctx, format);
180848b8605Smrg
181848b8605Smrg   ASSERT(rb);
182848b8605Smrg
183848b8605Smrg   if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_FALSE)) {
184848b8605Smrg      return GL_FALSE;
185848b8605Smrg   }
186848b8605Smrg
187848b8605Smrg   /* The base internal format and the base Mesa format must match. */
188848b8605Smrg   if (rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) {
189848b8605Smrg      return GL_FALSE;
190848b8605Smrg   }
191848b8605Smrg
192848b8605Smrg   /* The Mesa format must match the input format and type. */
193848b8605Smrg   if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
194848b8605Smrg                                             packing->SwapBytes)) {
195848b8605Smrg      return GL_FALSE;
196848b8605Smrg   }
197848b8605Smrg
198848b8605Smrg   return GL_TRUE;
199848b8605Smrg}
200848b8605Smrg
201848b8605Smrg
202848b8605Smrgstatic GLboolean
203848b8605Smrgreadpixels_memcpy(struct gl_context *ctx,
204848b8605Smrg                  GLint x, GLint y,
205848b8605Smrg                  GLsizei width, GLsizei height,
206848b8605Smrg                  GLenum format, GLenum type,
207848b8605Smrg                  GLvoid *pixels,
208848b8605Smrg                  const struct gl_pixelstore_attrib *packing)
209848b8605Smrg{
210848b8605Smrg   struct gl_renderbuffer *rb =
211848b8605Smrg         _mesa_get_read_renderbuffer_for_format(ctx, format);
212848b8605Smrg   GLubyte *dst, *map;
213848b8605Smrg   int dstStride, stride, j, texelBytes;
214848b8605Smrg
215848b8605Smrg   /* Fail if memcpy cannot be used. */
216848b8605Smrg   if (!readpixels_can_use_memcpy(ctx, format, type, packing)) {
217848b8605Smrg      return GL_FALSE;
218848b8605Smrg   }
219848b8605Smrg
220848b8605Smrg   dstStride = _mesa_image_row_stride(packing, width, format, type);
221848b8605Smrg   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
222848b8605Smrg					   format, type, 0, 0);
223848b8605Smrg
224848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
225848b8605Smrg			       &map, &stride);
226848b8605Smrg   if (!map) {
227848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
228848b8605Smrg      return GL_TRUE;  /* don't bother trying the slow path */
229848b8605Smrg   }
230848b8605Smrg
231848b8605Smrg   texelBytes = _mesa_get_format_bytes(rb->Format);
232848b8605Smrg
233848b8605Smrg   /* memcpy*/
234848b8605Smrg   for (j = 0; j < height; j++) {
235848b8605Smrg      memcpy(dst, map, width * texelBytes);
236848b8605Smrg      dst += dstStride;
237848b8605Smrg      map += stride;
238848b8605Smrg   }
239848b8605Smrg
240848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
241848b8605Smrg   return GL_TRUE;
242848b8605Smrg}
243848b8605Smrg
244848b8605Smrg
245848b8605Smrg/**
246848b8605Smrg * Optimized path for conversion of depth values to GL_DEPTH_COMPONENT,
247848b8605Smrg * GL_UNSIGNED_INT.
248848b8605Smrg */
249848b8605Smrgstatic GLboolean
250848b8605Smrgread_uint_depth_pixels( struct gl_context *ctx,
251848b8605Smrg			GLint x, GLint y,
252848b8605Smrg			GLsizei width, GLsizei height,
253848b8605Smrg			GLenum type, GLvoid *pixels,
254848b8605Smrg			const struct gl_pixelstore_attrib *packing )
255848b8605Smrg{
256848b8605Smrg   struct gl_framebuffer *fb = ctx->ReadBuffer;
257848b8605Smrg   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
258848b8605Smrg   GLubyte *map, *dst;
259848b8605Smrg   int stride, dstStride, j;
260848b8605Smrg
261848b8605Smrg   if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0)
262848b8605Smrg      return GL_FALSE;
263848b8605Smrg
264848b8605Smrg   if (packing->SwapBytes)
265848b8605Smrg      return GL_FALSE;
266848b8605Smrg
267848b8605Smrg   if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
268848b8605Smrg      return GL_FALSE;
269848b8605Smrg
270848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
271848b8605Smrg			       &map, &stride);
272848b8605Smrg
273848b8605Smrg   if (!map) {
274848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
275848b8605Smrg      return GL_TRUE;  /* don't bother trying the slow path */
276848b8605Smrg   }
277848b8605Smrg
278848b8605Smrg   dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
279848b8605Smrg   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
280848b8605Smrg					   GL_DEPTH_COMPONENT, type, 0, 0);
281848b8605Smrg
282848b8605Smrg   for (j = 0; j < height; j++) {
283848b8605Smrg      _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
284848b8605Smrg
285848b8605Smrg      map += stride;
286848b8605Smrg      dst += dstStride;
287848b8605Smrg   }
288848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
289848b8605Smrg
290848b8605Smrg   return GL_TRUE;
291848b8605Smrg}
292848b8605Smrg
293848b8605Smrg/**
294848b8605Smrg * Read pixels for format=GL_DEPTH_COMPONENT.
295848b8605Smrg */
296848b8605Smrgstatic void
297848b8605Smrgread_depth_pixels( struct gl_context *ctx,
298848b8605Smrg                   GLint x, GLint y,
299848b8605Smrg                   GLsizei width, GLsizei height,
300848b8605Smrg                   GLenum type, GLvoid *pixels,
301848b8605Smrg                   const struct gl_pixelstore_attrib *packing )
302848b8605Smrg{
303848b8605Smrg   struct gl_framebuffer *fb = ctx->ReadBuffer;
304848b8605Smrg   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
305848b8605Smrg   GLint j;
306848b8605Smrg   GLubyte *dst, *map;
307848b8605Smrg   int dstStride, stride;
308848b8605Smrg   GLfloat *depthValues;
309848b8605Smrg
310848b8605Smrg   if (!rb)
311848b8605Smrg      return;
312848b8605Smrg
313848b8605Smrg   /* clipping should have been done already */
314848b8605Smrg   ASSERT(x >= 0);
315848b8605Smrg   ASSERT(y >= 0);
316848b8605Smrg   ASSERT(x + width <= (GLint) rb->Width);
317848b8605Smrg   ASSERT(y + height <= (GLint) rb->Height);
318848b8605Smrg
319848b8605Smrg   if (type == GL_UNSIGNED_INT &&
320848b8605Smrg       read_uint_depth_pixels(ctx, x, y, width, height, type, pixels, packing)) {
321848b8605Smrg      return;
322848b8605Smrg   }
323848b8605Smrg
324848b8605Smrg   dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
325848b8605Smrg   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
326848b8605Smrg					   GL_DEPTH_COMPONENT, type, 0, 0);
327848b8605Smrg
328848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
329848b8605Smrg			       &map, &stride);
330848b8605Smrg   if (!map) {
331848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
332848b8605Smrg      return;
333848b8605Smrg   }
334848b8605Smrg
335848b8605Smrg   depthValues = malloc(width * sizeof(GLfloat));
336848b8605Smrg
337848b8605Smrg   if (depthValues) {
338848b8605Smrg      /* General case (slower) */
339848b8605Smrg      for (j = 0; j < height; j++, y++) {
340848b8605Smrg         _mesa_unpack_float_z_row(rb->Format, width, map, depthValues);
341848b8605Smrg         _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing);
342848b8605Smrg
343848b8605Smrg         dst += dstStride;
344848b8605Smrg         map += stride;
345848b8605Smrg      }
346848b8605Smrg   }
347848b8605Smrg   else {
348848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
349848b8605Smrg   }
350848b8605Smrg
351848b8605Smrg   free(depthValues);
352848b8605Smrg
353848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
354848b8605Smrg}
355848b8605Smrg
356848b8605Smrg
357848b8605Smrg/**
358848b8605Smrg * Read pixels for format=GL_STENCIL_INDEX.
359848b8605Smrg */
360848b8605Smrgstatic void
361848b8605Smrgread_stencil_pixels( struct gl_context *ctx,
362848b8605Smrg                     GLint x, GLint y,
363848b8605Smrg                     GLsizei width, GLsizei height,
364848b8605Smrg                     GLenum type, GLvoid *pixels,
365848b8605Smrg                     const struct gl_pixelstore_attrib *packing )
366848b8605Smrg{
367848b8605Smrg   struct gl_framebuffer *fb = ctx->ReadBuffer;
368848b8605Smrg   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
369848b8605Smrg   GLint j;
370848b8605Smrg   GLubyte *map, *stencil;
371848b8605Smrg   GLint stride;
372848b8605Smrg
373848b8605Smrg   if (!rb)
374848b8605Smrg      return;
375848b8605Smrg
376848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
377848b8605Smrg			       &map, &stride);
378848b8605Smrg   if (!map) {
379848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
380848b8605Smrg      return;
381848b8605Smrg   }
382848b8605Smrg
383848b8605Smrg   stencil = malloc(width * sizeof(GLubyte));
384848b8605Smrg
385848b8605Smrg   if (stencil) {
386848b8605Smrg      /* process image row by row */
387848b8605Smrg      for (j = 0; j < height; j++) {
388848b8605Smrg         GLvoid *dest;
389848b8605Smrg
390848b8605Smrg         _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil);
391848b8605Smrg         dest = _mesa_image_address2d(packing, pixels, width, height,
392848b8605Smrg                                      GL_STENCIL_INDEX, type, j, 0);
393848b8605Smrg
394848b8605Smrg         _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
395848b8605Smrg
396848b8605Smrg         map += stride;
397848b8605Smrg      }
398848b8605Smrg   }
399848b8605Smrg   else {
400848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
401848b8605Smrg   }
402848b8605Smrg
403848b8605Smrg   free(stencil);
404848b8605Smrg
405848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
406848b8605Smrg}
407848b8605Smrg
408848b8605Smrg
409848b8605Smrg/**
410848b8605Smrg * Try to do glReadPixels of RGBA data using swizzle.
411848b8605Smrg * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
412848b8605Smrg */
413848b8605Smrgstatic GLboolean
414848b8605Smrgread_rgba_pixels_swizzle(struct gl_context *ctx,
415848b8605Smrg                         GLint x, GLint y,
416848b8605Smrg                         GLsizei width, GLsizei height,
417848b8605Smrg                         GLenum format, GLenum type,
418848b8605Smrg                         GLvoid *pixels,
419848b8605Smrg                         const struct gl_pixelstore_attrib *packing)
420848b8605Smrg{
421848b8605Smrg   struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
422848b8605Smrg   GLubyte *dst, *map;
423848b8605Smrg   int dstStride, stride, j;
424848b8605Smrg   GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE;
425848b8605Smrg
426848b8605Smrg   /* XXX we could check for other swizzle/special cases here as needed */
427848b8605Smrg   if (rb->Format == MESA_FORMAT_R8G8B8A8_UNORM &&
428848b8605Smrg       format == GL_BGRA &&
429848b8605Smrg       type == GL_UNSIGNED_INT_8_8_8_8_REV &&
430848b8605Smrg       !ctx->Pack.SwapBytes) {
431848b8605Smrg      swizzle_rb = GL_TRUE;
432848b8605Smrg   }
433848b8605Smrg   else if (rb->Format == MESA_FORMAT_B8G8R8X8_UNORM &&
434848b8605Smrg       format == GL_BGRA &&
435848b8605Smrg       type == GL_UNSIGNED_INT_8_8_8_8_REV &&
436848b8605Smrg       !ctx->Pack.SwapBytes) {
437848b8605Smrg      copy_xrgb = GL_TRUE;
438848b8605Smrg   }
439848b8605Smrg   else {
440848b8605Smrg      return GL_FALSE;
441848b8605Smrg   }
442848b8605Smrg
443848b8605Smrg   dstStride = _mesa_image_row_stride(packing, width, format, type);
444848b8605Smrg   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
445848b8605Smrg					   format, type, 0, 0);
446848b8605Smrg
447848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
448848b8605Smrg			       &map, &stride);
449848b8605Smrg   if (!map) {
450848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
451848b8605Smrg      return GL_TRUE;  /* don't bother trying the slow path */
452848b8605Smrg   }
453848b8605Smrg
454848b8605Smrg   if (swizzle_rb) {
455848b8605Smrg      /* swap R/B */
456848b8605Smrg      for (j = 0; j < height; j++) {
457848b8605Smrg         int i;
458848b8605Smrg         for (i = 0; i < width; i++) {
459848b8605Smrg            GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
460848b8605Smrg            GLuint pixel = map4[i];
461848b8605Smrg            dst4[i] = (pixel & 0xff00ff00)
462848b8605Smrg                   | ((pixel & 0x00ff0000) >> 16)
463848b8605Smrg                   | ((pixel & 0x000000ff) << 16);
464848b8605Smrg         }
465848b8605Smrg         dst += dstStride;
466848b8605Smrg         map += stride;
467848b8605Smrg      }
468848b8605Smrg   } else if (copy_xrgb) {
469848b8605Smrg      /* convert xrgb -> argb */
470848b8605Smrg      for (j = 0; j < height; j++) {
471848b8605Smrg         GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
472848b8605Smrg         int i;
473848b8605Smrg         for (i = 0; i < width; i++) {
474848b8605Smrg            dst4[i] = map4[i] | 0xff000000;  /* set A=0xff */
475848b8605Smrg         }
476848b8605Smrg         dst += dstStride;
477848b8605Smrg         map += stride;
478848b8605Smrg      }
479848b8605Smrg   }
480848b8605Smrg
481848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
482848b8605Smrg
483848b8605Smrg   return GL_TRUE;
484848b8605Smrg}
485848b8605Smrg
486848b8605Smrgstatic void
487848b8605Smrgslow_read_rgba_pixels( struct gl_context *ctx,
488848b8605Smrg		       GLint x, GLint y,
489848b8605Smrg		       GLsizei width, GLsizei height,
490848b8605Smrg		       GLenum format, GLenum type,
491848b8605Smrg		       GLvoid *pixels,
492848b8605Smrg		       const struct gl_pixelstore_attrib *packing,
493848b8605Smrg		       GLbitfield transferOps )
494848b8605Smrg{
495848b8605Smrg   struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
496848b8605Smrg   const mesa_format rbFormat = _mesa_get_srgb_format_linear(rb->Format);
497848b8605Smrg   void *rgba;
498848b8605Smrg   GLubyte *dst, *map;
499848b8605Smrg   int dstStride, stride, j;
500848b8605Smrg   GLboolean dst_is_integer = _mesa_is_enum_format_integer(format);
501848b8605Smrg   GLboolean dst_is_uint = _mesa_is_format_unsigned(rbFormat);
502848b8605Smrg
503848b8605Smrg   dstStride = _mesa_image_row_stride(packing, width, format, type);
504848b8605Smrg   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
505848b8605Smrg					   format, type, 0, 0);
506848b8605Smrg
507848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
508848b8605Smrg			       &map, &stride);
509848b8605Smrg   if (!map) {
510848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
511848b8605Smrg      return;
512848b8605Smrg   }
513848b8605Smrg
514848b8605Smrg   rgba = malloc(width * MAX_PIXEL_BYTES);
515848b8605Smrg   if (!rgba)
516848b8605Smrg      goto done;
517848b8605Smrg
518848b8605Smrg   for (j = 0; j < height; j++) {
519848b8605Smrg      if (dst_is_integer) {
520848b8605Smrg	 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
521848b8605Smrg         _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba,
522848b8605Smrg                                rb->_BaseFormat);
523848b8605Smrg         if (dst_is_uint) {
524848b8605Smrg            _mesa_pack_rgba_span_from_uints(ctx, width, (GLuint (*)[4]) rgba, format,
525848b8605Smrg                                            type, dst);
526848b8605Smrg         } else {
527848b8605Smrg            _mesa_pack_rgba_span_from_ints(ctx, width, (GLint (*)[4]) rgba, format,
528848b8605Smrg                                           type, dst);
529848b8605Smrg         }
530848b8605Smrg      } else {
531848b8605Smrg	 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba);
532848b8605Smrg         _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba,
533848b8605Smrg                                 rb->_BaseFormat);
534848b8605Smrg	 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
535848b8605Smrg                                    type, dst, packing, transferOps);
536848b8605Smrg      }
537848b8605Smrg      dst += dstStride;
538848b8605Smrg      map += stride;
539848b8605Smrg   }
540848b8605Smrg
541848b8605Smrg   free(rgba);
542848b8605Smrg
543848b8605Smrgdone:
544848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
545848b8605Smrg}
546848b8605Smrg
547848b8605Smrg/*
548848b8605Smrg * Read R, G, B, A, RGB, L, or LA pixels.
549848b8605Smrg */
550848b8605Smrgstatic void
551848b8605Smrgread_rgba_pixels( struct gl_context *ctx,
552848b8605Smrg                  GLint x, GLint y,
553848b8605Smrg                  GLsizei width, GLsizei height,
554848b8605Smrg                  GLenum format, GLenum type, GLvoid *pixels,
555848b8605Smrg                  const struct gl_pixelstore_attrib *packing )
556848b8605Smrg{
557848b8605Smrg   GLbitfield transferOps;
558848b8605Smrg   struct gl_framebuffer *fb = ctx->ReadBuffer;
559848b8605Smrg   struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
560848b8605Smrg
561848b8605Smrg   if (!rb)
562848b8605Smrg      return;
563848b8605Smrg
564848b8605Smrg   transferOps = get_readpixels_transfer_ops(ctx, rb->Format, format, type,
565848b8605Smrg                                             GL_FALSE);
566848b8605Smrg
567848b8605Smrg   /* Try the optimized paths first. */
568848b8605Smrg   if (!transferOps &&
569848b8605Smrg       read_rgba_pixels_swizzle(ctx, x, y, width, height,
570848b8605Smrg                                    format, type, pixels, packing)) {
571848b8605Smrg      return;
572848b8605Smrg   }
573848b8605Smrg
574848b8605Smrg   slow_read_rgba_pixels(ctx, x, y, width, height,
575848b8605Smrg			 format, type, pixels, packing, transferOps);
576848b8605Smrg}
577848b8605Smrg
578848b8605Smrg/**
579848b8605Smrg * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the
580848b8605Smrg * data (possibly swapping 8/24 vs 24/8 as we go).
581848b8605Smrg */
582848b8605Smrgstatic GLboolean
583848b8605Smrgfast_read_depth_stencil_pixels(struct gl_context *ctx,
584848b8605Smrg			       GLint x, GLint y,
585848b8605Smrg			       GLsizei width, GLsizei height,
586848b8605Smrg			       GLubyte *dst, int dstStride)
587848b8605Smrg{
588848b8605Smrg   struct gl_framebuffer *fb = ctx->ReadBuffer;
589848b8605Smrg   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
590848b8605Smrg   struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
591848b8605Smrg   GLubyte *map;
592848b8605Smrg   int stride, i;
593848b8605Smrg
594848b8605Smrg   if (rb != stencilRb)
595848b8605Smrg      return GL_FALSE;
596848b8605Smrg
597848b8605Smrg   if (rb->Format != MESA_FORMAT_S8_UINT_Z24_UNORM &&
598848b8605Smrg       rb->Format != MESA_FORMAT_Z24_UNORM_S8_UINT)
599848b8605Smrg      return GL_FALSE;
600848b8605Smrg
601848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
602848b8605Smrg			       &map, &stride);
603848b8605Smrg   if (!map) {
604848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
605848b8605Smrg      return GL_TRUE;  /* don't bother trying the slow path */
606848b8605Smrg   }
607848b8605Smrg
608848b8605Smrg   for (i = 0; i < height; i++) {
609848b8605Smrg      _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width,
610848b8605Smrg					       map, (GLuint *)dst);
611848b8605Smrg      map += stride;
612848b8605Smrg      dst += dstStride;
613848b8605Smrg   }
614848b8605Smrg
615848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, rb);
616848b8605Smrg
617848b8605Smrg   return GL_TRUE;
618848b8605Smrg}
619848b8605Smrg
620848b8605Smrg
621848b8605Smrg/**
622848b8605Smrg * For non-float-depth and stencil buffers being read as 24/8 depth/stencil,
623848b8605Smrg * copy the integer data directly instead of converting depth to float and
624848b8605Smrg * re-packing.
625848b8605Smrg */
626848b8605Smrgstatic GLboolean
627848b8605Smrgfast_read_depth_stencil_pixels_separate(struct gl_context *ctx,
628848b8605Smrg					GLint x, GLint y,
629848b8605Smrg					GLsizei width, GLsizei height,
630848b8605Smrg					uint32_t *dst, int dstStride)
631848b8605Smrg{
632848b8605Smrg   struct gl_framebuffer *fb = ctx->ReadBuffer;
633848b8605Smrg   struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
634848b8605Smrg   struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
635848b8605Smrg   GLubyte *depthMap, *stencilMap, *stencilVals;
636848b8605Smrg   int depthStride, stencilStride, i, j;
637848b8605Smrg
638848b8605Smrg   if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED)
639848b8605Smrg      return GL_FALSE;
640848b8605Smrg
641848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
642848b8605Smrg			       GL_MAP_READ_BIT, &depthMap, &depthStride);
643848b8605Smrg   if (!depthMap) {
644848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
645848b8605Smrg      return GL_TRUE;  /* don't bother trying the slow path */
646848b8605Smrg   }
647848b8605Smrg
648848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
649848b8605Smrg			       GL_MAP_READ_BIT, &stencilMap, &stencilStride);
650848b8605Smrg   if (!stencilMap) {
651848b8605Smrg      ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
652848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
653848b8605Smrg      return GL_TRUE;  /* don't bother trying the slow path */
654848b8605Smrg   }
655848b8605Smrg
656848b8605Smrg   stencilVals = malloc(width * sizeof(GLubyte));
657848b8605Smrg
658848b8605Smrg   if (stencilVals) {
659848b8605Smrg      for (j = 0; j < height; j++) {
660848b8605Smrg         _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst);
661848b8605Smrg         _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
662848b8605Smrg                                        stencilMap, stencilVals);
663848b8605Smrg
664848b8605Smrg         for (i = 0; i < width; i++) {
665848b8605Smrg            dst[i] = (dst[i] & 0xffffff00) | stencilVals[i];
666848b8605Smrg         }
667848b8605Smrg
668848b8605Smrg         depthMap += depthStride;
669848b8605Smrg         stencilMap += stencilStride;
670848b8605Smrg         dst += dstStride / 4;
671848b8605Smrg      }
672848b8605Smrg   }
673848b8605Smrg   else {
674848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
675848b8605Smrg   }
676848b8605Smrg
677848b8605Smrg   free(stencilVals);
678848b8605Smrg
679848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
680848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
681848b8605Smrg
682848b8605Smrg   return GL_TRUE;
683848b8605Smrg}
684848b8605Smrg
685848b8605Smrgstatic void
686848b8605Smrgslow_read_depth_stencil_pixels_separate(struct gl_context *ctx,
687848b8605Smrg					GLint x, GLint y,
688848b8605Smrg					GLsizei width, GLsizei height,
689848b8605Smrg					GLenum type,
690848b8605Smrg					const struct gl_pixelstore_attrib *packing,
691848b8605Smrg					GLubyte *dst, int dstStride)
692848b8605Smrg{
693848b8605Smrg   struct gl_framebuffer *fb = ctx->ReadBuffer;
694848b8605Smrg   struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
695848b8605Smrg   struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
696848b8605Smrg   GLubyte *depthMap, *stencilMap;
697848b8605Smrg   int depthStride, stencilStride, j;
698848b8605Smrg   GLubyte *stencilVals;
699848b8605Smrg   GLfloat *depthVals;
700848b8605Smrg
701848b8605Smrg
702848b8605Smrg   /* The depth and stencil buffers might be separate, or a single buffer.
703848b8605Smrg    * If one buffer, only map it once.
704848b8605Smrg    */
705848b8605Smrg   ctx->Driver.MapRenderbuffer(ctx, depthRb, x, y, width, height,
706848b8605Smrg			       GL_MAP_READ_BIT, &depthMap, &depthStride);
707848b8605Smrg   if (!depthMap) {
708848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
709848b8605Smrg      return;
710848b8605Smrg   }
711848b8605Smrg
712848b8605Smrg   if (stencilRb != depthRb) {
713848b8605Smrg      ctx->Driver.MapRenderbuffer(ctx, stencilRb, x, y, width, height,
714848b8605Smrg                                  GL_MAP_READ_BIT, &stencilMap,
715848b8605Smrg                                  &stencilStride);
716848b8605Smrg      if (!stencilMap) {
717848b8605Smrg         ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
718848b8605Smrg         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
719848b8605Smrg         return;
720848b8605Smrg      }
721848b8605Smrg   }
722848b8605Smrg   else {
723848b8605Smrg      stencilMap = depthMap;
724848b8605Smrg      stencilStride = depthStride;
725848b8605Smrg   }
726848b8605Smrg
727848b8605Smrg   stencilVals = malloc(width * sizeof(GLubyte));
728848b8605Smrg   depthVals = malloc(width * sizeof(GLfloat));
729848b8605Smrg
730848b8605Smrg   if (stencilVals && depthVals) {
731848b8605Smrg      for (j = 0; j < height; j++) {
732848b8605Smrg         _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals);
733848b8605Smrg         _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
734848b8605Smrg                                        stencilMap, stencilVals);
735848b8605Smrg
736848b8605Smrg         _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst,
737848b8605Smrg                                       depthVals, stencilVals, packing);
738848b8605Smrg
739848b8605Smrg         depthMap += depthStride;
740848b8605Smrg         stencilMap += stencilStride;
741848b8605Smrg         dst += dstStride;
742848b8605Smrg      }
743848b8605Smrg   }
744848b8605Smrg   else {
745848b8605Smrg      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
746848b8605Smrg   }
747848b8605Smrg
748848b8605Smrg   free(stencilVals);
749848b8605Smrg   free(depthVals);
750848b8605Smrg
751848b8605Smrg   ctx->Driver.UnmapRenderbuffer(ctx, depthRb);
752848b8605Smrg   if (stencilRb != depthRb) {
753848b8605Smrg      ctx->Driver.UnmapRenderbuffer(ctx, stencilRb);
754848b8605Smrg   }
755848b8605Smrg}
756848b8605Smrg
757848b8605Smrg
758848b8605Smrg/**
759848b8605Smrg * Read combined depth/stencil values.
760848b8605Smrg * We'll have already done error checking to be sure the expected
761848b8605Smrg * depth and stencil buffers really exist.
762848b8605Smrg */
763848b8605Smrgstatic void
764848b8605Smrgread_depth_stencil_pixels(struct gl_context *ctx,
765848b8605Smrg                          GLint x, GLint y,
766848b8605Smrg                          GLsizei width, GLsizei height,
767848b8605Smrg                          GLenum type, GLvoid *pixels,
768848b8605Smrg                          const struct gl_pixelstore_attrib *packing )
769848b8605Smrg{
770848b8605Smrg   const GLboolean scaleOrBias
771848b8605Smrg      = ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
772848b8605Smrg   const GLboolean stencilTransfer = ctx->Pixel.IndexShift
773848b8605Smrg      || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag;
774848b8605Smrg   GLubyte *dst;
775848b8605Smrg   int dstStride;
776848b8605Smrg
777848b8605Smrg   dst = (GLubyte *) _mesa_image_address2d(packing, pixels,
778848b8605Smrg					   width, height,
779848b8605Smrg					   GL_DEPTH_STENCIL_EXT,
780848b8605Smrg					   type, 0, 0);
781848b8605Smrg   dstStride = _mesa_image_row_stride(packing, width,
782848b8605Smrg				      GL_DEPTH_STENCIL_EXT, type);
783848b8605Smrg
784848b8605Smrg   /* Fast 24/8 reads. */
785848b8605Smrg   if (type == GL_UNSIGNED_INT_24_8 &&
786848b8605Smrg       !scaleOrBias && !stencilTransfer && !packing->SwapBytes) {
787848b8605Smrg      if (fast_read_depth_stencil_pixels(ctx, x, y, width, height,
788848b8605Smrg					 dst, dstStride))
789848b8605Smrg	 return;
790848b8605Smrg
791848b8605Smrg      if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
792848b8605Smrg						  (uint32_t *)dst, dstStride))
793848b8605Smrg	 return;
794848b8605Smrg   }
795848b8605Smrg
796848b8605Smrg   slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
797848b8605Smrg					   type, packing,
798848b8605Smrg					   dst, dstStride);
799848b8605Smrg}
800848b8605Smrg
801848b8605Smrg
802848b8605Smrg
803848b8605Smrg/**
804848b8605Smrg * Software fallback routine for ctx->Driver.ReadPixels().
805848b8605Smrg * By time we get here, all error checking will have been done.
806848b8605Smrg */
807848b8605Smrgvoid
808848b8605Smrg_mesa_readpixels(struct gl_context *ctx,
809848b8605Smrg                 GLint x, GLint y, GLsizei width, GLsizei height,
810848b8605Smrg                 GLenum format, GLenum type,
811848b8605Smrg                 const struct gl_pixelstore_attrib *packing,
812848b8605Smrg                 GLvoid *pixels)
813848b8605Smrg{
814848b8605Smrg   struct gl_pixelstore_attrib clippedPacking = *packing;
815848b8605Smrg
816848b8605Smrg   if (ctx->NewState)
817848b8605Smrg      _mesa_update_state(ctx);
818848b8605Smrg
819848b8605Smrg   /* Do all needed clipping here, so that we can forget about it later */
820848b8605Smrg   if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
821848b8605Smrg
822848b8605Smrg      pixels = _mesa_map_pbo_dest(ctx, &clippedPacking, pixels);
823848b8605Smrg
824848b8605Smrg      if (pixels) {
825848b8605Smrg         /* Try memcpy first. */
826848b8605Smrg         if (readpixels_memcpy(ctx, x, y, width, height, format, type,
827848b8605Smrg                               pixels, packing)) {
828848b8605Smrg            _mesa_unmap_pbo_dest(ctx, &clippedPacking);
829848b8605Smrg            return;
830848b8605Smrg         }
831848b8605Smrg
832848b8605Smrg         /* Otherwise take the slow path. */
833848b8605Smrg         switch (format) {
834848b8605Smrg         case GL_STENCIL_INDEX:
835848b8605Smrg            read_stencil_pixels(ctx, x, y, width, height, type, pixels,
836848b8605Smrg                                &clippedPacking);
837848b8605Smrg            break;
838848b8605Smrg         case GL_DEPTH_COMPONENT:
839848b8605Smrg            read_depth_pixels(ctx, x, y, width, height, type, pixels,
840848b8605Smrg                              &clippedPacking);
841848b8605Smrg            break;
842848b8605Smrg         case GL_DEPTH_STENCIL_EXT:
843848b8605Smrg            read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels,
844848b8605Smrg                                      &clippedPacking);
845848b8605Smrg            break;
846848b8605Smrg         default:
847848b8605Smrg            /* all other formats should be color formats */
848848b8605Smrg            read_rgba_pixels(ctx, x, y, width, height, format, type, pixels,
849848b8605Smrg                             &clippedPacking);
850848b8605Smrg         }
851848b8605Smrg
852848b8605Smrg         _mesa_unmap_pbo_dest(ctx, &clippedPacking);
853848b8605Smrg      }
854848b8605Smrg   }
855848b8605Smrg}
856848b8605Smrg
857848b8605Smrg
858848b8605Smrgstatic GLenum
859848b8605Smrgread_pixels_es3_error_check(GLenum format, GLenum type,
860848b8605Smrg                            const struct gl_renderbuffer *rb)
861848b8605Smrg{
862848b8605Smrg   const GLenum internalFormat = rb->InternalFormat;
863848b8605Smrg   const GLenum data_type = _mesa_get_format_datatype(rb->Format);
864848b8605Smrg   GLboolean is_unsigned_int = GL_FALSE;
865848b8605Smrg   GLboolean is_signed_int = GL_FALSE;
866848b8605Smrg
867848b8605Smrg   if (!_mesa_is_color_format(internalFormat)) {
868848b8605Smrg      return GL_INVALID_OPERATION;
869848b8605Smrg   }
870848b8605Smrg
871848b8605Smrg   is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat);
872848b8605Smrg   if (!is_unsigned_int) {
873848b8605Smrg      is_signed_int = _mesa_is_enum_format_signed_int(internalFormat);
874848b8605Smrg   }
875848b8605Smrg
876848b8605Smrg   switch (format) {
877848b8605Smrg   case GL_RGBA:
878848b8605Smrg      if (type == GL_FLOAT && data_type == GL_FLOAT)
879848b8605Smrg         return GL_NO_ERROR; /* EXT_color_buffer_float */
880848b8605Smrg      if (type == GL_UNSIGNED_BYTE && data_type == GL_UNSIGNED_NORMALIZED)
881848b8605Smrg         return GL_NO_ERROR;
882848b8605Smrg      if (internalFormat == GL_RGB10_A2 &&
883848b8605Smrg          type == GL_UNSIGNED_INT_2_10_10_10_REV)
884848b8605Smrg         return GL_NO_ERROR;
885848b8605Smrg      if (internalFormat == GL_RGB10_A2UI && type == GL_UNSIGNED_BYTE)
886848b8605Smrg         return GL_NO_ERROR;
887848b8605Smrg      break;
888848b8605Smrg   case GL_BGRA:
889848b8605Smrg      /* GL_EXT_read_format_bgra */
890848b8605Smrg      if (type == GL_UNSIGNED_BYTE ||
891848b8605Smrg          type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
892848b8605Smrg          type == GL_UNSIGNED_SHORT_1_5_5_5_REV)
893848b8605Smrg         return GL_NO_ERROR;
894848b8605Smrg      break;
895848b8605Smrg   case GL_RGBA_INTEGER:
896848b8605Smrg      if ((is_signed_int && type == GL_INT) ||
897848b8605Smrg          (is_unsigned_int && type == GL_UNSIGNED_INT))
898848b8605Smrg         return GL_NO_ERROR;
899848b8605Smrg      break;
900848b8605Smrg   }
901848b8605Smrg
902848b8605Smrg   return GL_INVALID_OPERATION;
903848b8605Smrg}
904848b8605Smrg
905848b8605Smrg
906848b8605Smrgvoid GLAPIENTRY
907848b8605Smrg_mesa_ReadnPixelsARB( GLint x, GLint y, GLsizei width, GLsizei height,
908848b8605Smrg		      GLenum format, GLenum type, GLsizei bufSize,
909848b8605Smrg                      GLvoid *pixels )
910848b8605Smrg{
911848b8605Smrg   GLenum err = GL_NO_ERROR;
912848b8605Smrg   struct gl_renderbuffer *rb;
913848b8605Smrg
914848b8605Smrg   GET_CURRENT_CONTEXT(ctx);
915848b8605Smrg
916848b8605Smrg   FLUSH_VERTICES(ctx, 0);
917848b8605Smrg   FLUSH_CURRENT(ctx, 0);
918848b8605Smrg
919848b8605Smrg   if (MESA_VERBOSE & VERBOSE_API)
920848b8605Smrg      _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
921848b8605Smrg                  width, height,
922848b8605Smrg                  _mesa_lookup_enum_by_nr(format),
923848b8605Smrg                  _mesa_lookup_enum_by_nr(type),
924848b8605Smrg                  pixels);
925848b8605Smrg
926848b8605Smrg   if (width < 0 || height < 0) {
927848b8605Smrg      _mesa_error( ctx, GL_INVALID_VALUE,
928848b8605Smrg                   "glReadPixels(width=%d height=%d)", width, height );
929848b8605Smrg      return;
930848b8605Smrg   }
931848b8605Smrg
932848b8605Smrg   if (ctx->NewState)
933848b8605Smrg      _mesa_update_state(ctx);
934848b8605Smrg
935848b8605Smrg   if (ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
936848b8605Smrg      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
937848b8605Smrg                  "glReadPixels(incomplete framebuffer)" );
938848b8605Smrg      return;
939848b8605Smrg   }
940848b8605Smrg
941848b8605Smrg   rb = _mesa_get_read_renderbuffer_for_format(ctx, format);
942848b8605Smrg   if (rb == NULL) {
943848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION,
944848b8605Smrg                  "glReadPixels(read buffer)");
945848b8605Smrg      return;
946848b8605Smrg   }
947848b8605Smrg
948848b8605Smrg   /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
949848b8605Smrg    * combinations of format and type that can be used.
950848b8605Smrg    *
951848b8605Smrg    * Technically, only two combinations are actually allowed:
952848b8605Smrg    * GL_RGBA/GL_UNSIGNED_BYTE, and some implementation-specific internal
953848b8605Smrg    * preferred combination.  This code doesn't know what that preferred
954848b8605Smrg    * combination is, and Mesa can handle anything valid.  Just work instead.
955848b8605Smrg    */
956848b8605Smrg   if (_mesa_is_gles(ctx)) {
957848b8605Smrg      if (ctx->API == API_OPENGLES2 &&
958848b8605Smrg          _mesa_is_color_format(format) &&
959848b8605Smrg          _mesa_get_color_read_format(ctx) == format &&
960848b8605Smrg          _mesa_get_color_read_type(ctx) == type) {
961848b8605Smrg         err = GL_NO_ERROR;
962848b8605Smrg      } else if (ctx->Version < 30) {
963848b8605Smrg         err = _mesa_es_error_check_format_and_type(format, type, 2);
964848b8605Smrg         if (err == GL_NO_ERROR) {
965848b8605Smrg            if (type == GL_FLOAT || type == GL_HALF_FLOAT_OES) {
966848b8605Smrg               err = GL_INVALID_OPERATION;
967848b8605Smrg            }
968848b8605Smrg         }
969848b8605Smrg      } else {
970848b8605Smrg         err = read_pixels_es3_error_check(format, type, rb);
971848b8605Smrg      }
972848b8605Smrg
973848b8605Smrg      if (err == GL_NO_ERROR && (format == GL_DEPTH_COMPONENT
974848b8605Smrg          || format == GL_DEPTH_STENCIL)) {
975848b8605Smrg         err = GL_INVALID_ENUM;
976848b8605Smrg      }
977848b8605Smrg
978848b8605Smrg      if (err != GL_NO_ERROR) {
979848b8605Smrg         _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
980848b8605Smrg                     _mesa_lookup_enum_by_nr(format),
981848b8605Smrg                     _mesa_lookup_enum_by_nr(type));
982848b8605Smrg         return;
983848b8605Smrg      }
984848b8605Smrg   }
985848b8605Smrg
986848b8605Smrg   err = _mesa_error_check_format_and_type(ctx, format, type);
987848b8605Smrg   if (err != GL_NO_ERROR) {
988848b8605Smrg      _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
989848b8605Smrg                  _mesa_lookup_enum_by_nr(format),
990848b8605Smrg                  _mesa_lookup_enum_by_nr(type));
991848b8605Smrg      return;
992848b8605Smrg   }
993848b8605Smrg
994848b8605Smrg   if (_mesa_is_user_fbo(ctx->ReadBuffer) &&
995848b8605Smrg       ctx->ReadBuffer->Visual.samples > 0) {
996848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
997848b8605Smrg      return;
998848b8605Smrg   }
999848b8605Smrg
1000848b8605Smrg   if (!_mesa_source_buffer_exists(ctx, format)) {
1001848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
1002848b8605Smrg      return;
1003848b8605Smrg   }
1004848b8605Smrg
1005848b8605Smrg   /* Check that the destination format and source buffer are both
1006848b8605Smrg    * integer-valued or both non-integer-valued.
1007848b8605Smrg    */
1008848b8605Smrg   if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
1009848b8605Smrg      const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
1010848b8605Smrg      const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
1011848b8605Smrg      const GLboolean dstInteger = _mesa_is_enum_format_integer(format);
1012848b8605Smrg      if (dstInteger != srcInteger) {
1013848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
1014848b8605Smrg                     "glReadPixels(integer / non-integer format mismatch");
1015848b8605Smrg         return;
1016848b8605Smrg      }
1017848b8605Smrg   }
1018848b8605Smrg
1019848b8605Smrg   if (width == 0 || height == 0)
1020848b8605Smrg      return; /* nothing to do */
1021848b8605Smrg
1022848b8605Smrg   if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
1023848b8605Smrg                                  format, type, bufSize, pixels)) {
1024848b8605Smrg      if (_mesa_is_bufferobj(ctx->Pack.BufferObj)) {
1025848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
1026848b8605Smrg                     "glReadPixels(out of bounds PBO access)");
1027848b8605Smrg      } else {
1028848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION,
1029848b8605Smrg                     "glReadnPixelsARB(out of bounds access:"
1030848b8605Smrg                     " bufSize (%d) is too small)", bufSize);
1031848b8605Smrg      }
1032848b8605Smrg      return;
1033848b8605Smrg   }
1034848b8605Smrg
1035848b8605Smrg   if (_mesa_is_bufferobj(ctx->Pack.BufferObj) &&
1036848b8605Smrg       _mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1037848b8605Smrg      /* buffer is mapped - that's an error */
1038848b8605Smrg      _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
1039848b8605Smrg      return;
1040848b8605Smrg   }
1041848b8605Smrg
1042848b8605Smrg   ctx->Driver.ReadPixels(ctx, x, y, width, height,
1043848b8605Smrg			  format, type, &ctx->Pack, pixels);
1044848b8605Smrg}
1045848b8605Smrg
1046848b8605Smrgvoid GLAPIENTRY
1047848b8605Smrg_mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
1048848b8605Smrg		  GLenum format, GLenum type, GLvoid *pixels )
1049848b8605Smrg{
1050848b8605Smrg   _mesa_ReadnPixelsARB(x, y, width, height, format, type, INT_MAX, pixels);
1051848b8605Smrg}
1052