xref: /third_party/mesa3d/src/mesa/main/readpix.c (revision bf215546)
1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Mesa 3-D graphics library
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
8bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
9bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
11bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included
14bf215546Sopenharmony_ci * in all copies or substantial portions of the Software.
15bf215546Sopenharmony_ci *
16bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
23bf215546Sopenharmony_ci */
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ci#include "glheader.h"
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#include "blend.h"
28bf215546Sopenharmony_ci#include "bufferobj.h"
29bf215546Sopenharmony_ci#include "context.h"
30bf215546Sopenharmony_ci#include "enums.h"
31bf215546Sopenharmony_ci#include "readpix.h"
32bf215546Sopenharmony_ci#include "framebuffer.h"
33bf215546Sopenharmony_ci#include "formats.h"
34bf215546Sopenharmony_ci#include "format_unpack.h"
35bf215546Sopenharmony_ci#include "image.h"
36bf215546Sopenharmony_ci#include "mtypes.h"
37bf215546Sopenharmony_ci#include "pack.h"
38bf215546Sopenharmony_ci#include "pbo.h"
39bf215546Sopenharmony_ci#include "pixel.h"
40bf215546Sopenharmony_ci#include "renderbuffer.h"
41bf215546Sopenharmony_ci#include "state.h"
42bf215546Sopenharmony_ci#include "glformats.h"
43bf215546Sopenharmony_ci#include "fbobject.h"
44bf215546Sopenharmony_ci#include "format_utils.h"
45bf215546Sopenharmony_ci#include "pixeltransfer.h"
46bf215546Sopenharmony_ci#include "api_exec_decl.h"
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci#include "state_tracker/st_cb_readpixels.h"
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci/**
51bf215546Sopenharmony_ci * Return true if the conversion L=R+G+B is needed.
52bf215546Sopenharmony_ci */
53bf215546Sopenharmony_ciGLboolean
54bf215546Sopenharmony_ci_mesa_need_rgb_to_luminance_conversion(GLenum srcBaseFormat,
55bf215546Sopenharmony_ci                                       GLenum dstBaseFormat)
56bf215546Sopenharmony_ci{
57bf215546Sopenharmony_ci   return (srcBaseFormat == GL_RG ||
58bf215546Sopenharmony_ci           srcBaseFormat == GL_RGB ||
59bf215546Sopenharmony_ci           srcBaseFormat == GL_RGBA) &&
60bf215546Sopenharmony_ci          (dstBaseFormat == GL_LUMINANCE ||
61bf215546Sopenharmony_ci           dstBaseFormat == GL_LUMINANCE_ALPHA);
62bf215546Sopenharmony_ci}
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_ci/**
65bf215546Sopenharmony_ci * Return true if the conversion L,I to RGB conversion is needed.
66bf215546Sopenharmony_ci */
67bf215546Sopenharmony_ciGLboolean
68bf215546Sopenharmony_ci_mesa_need_luminance_to_rgb_conversion(GLenum srcBaseFormat,
69bf215546Sopenharmony_ci                                       GLenum dstBaseFormat)
70bf215546Sopenharmony_ci{
71bf215546Sopenharmony_ci   return (srcBaseFormat == GL_LUMINANCE ||
72bf215546Sopenharmony_ci           srcBaseFormat == GL_LUMINANCE_ALPHA ||
73bf215546Sopenharmony_ci           srcBaseFormat == GL_INTENSITY) &&
74bf215546Sopenharmony_ci          (dstBaseFormat == GL_GREEN ||
75bf215546Sopenharmony_ci           dstBaseFormat == GL_BLUE ||
76bf215546Sopenharmony_ci           dstBaseFormat == GL_RG ||
77bf215546Sopenharmony_ci           dstBaseFormat == GL_RGB ||
78bf215546Sopenharmony_ci           dstBaseFormat == GL_BGR ||
79bf215546Sopenharmony_ci           dstBaseFormat == GL_RGBA ||
80bf215546Sopenharmony_ci           dstBaseFormat == GL_BGRA);
81bf215546Sopenharmony_ci}
82bf215546Sopenharmony_ci
83bf215546Sopenharmony_ci/**
84bf215546Sopenharmony_ci * Return transfer op flags for this ReadPixels operation.
85bf215546Sopenharmony_ci */
86bf215546Sopenharmony_ciGLbitfield
87bf215546Sopenharmony_ci_mesa_get_readpixels_transfer_ops(const struct gl_context *ctx,
88bf215546Sopenharmony_ci                                  mesa_format texFormat,
89bf215546Sopenharmony_ci                                  GLenum format, GLenum type,
90bf215546Sopenharmony_ci                                  GLboolean uses_blit)
91bf215546Sopenharmony_ci{
92bf215546Sopenharmony_ci   GLbitfield transferOps = ctx->_ImageTransferState;
93bf215546Sopenharmony_ci   GLenum srcBaseFormat = _mesa_get_format_base_format(texFormat);
94bf215546Sopenharmony_ci   GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format);
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci   if (format == GL_DEPTH_COMPONENT ||
97bf215546Sopenharmony_ci       format == GL_DEPTH_STENCIL ||
98bf215546Sopenharmony_ci       format == GL_STENCIL_INDEX) {
99bf215546Sopenharmony_ci      return 0;
100bf215546Sopenharmony_ci   }
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_ci   /* Pixel transfer ops (scale, bias, table lookup) do not apply
103bf215546Sopenharmony_ci    * to integer formats.
104bf215546Sopenharmony_ci    */
105bf215546Sopenharmony_ci   if (_mesa_is_enum_format_integer(format)) {
106bf215546Sopenharmony_ci      return 0;
107bf215546Sopenharmony_ci   }
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci   if (uses_blit) {
110bf215546Sopenharmony_ci      /* For blit-based ReadPixels packing, the clamping is done automatically
111bf215546Sopenharmony_ci       * unless the type is float. */
112bf215546Sopenharmony_ci      if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) &&
113bf215546Sopenharmony_ci          (type == GL_FLOAT || type == GL_HALF_FLOAT ||
114bf215546Sopenharmony_ci           type == GL_UNSIGNED_INT_10F_11F_11F_REV)) {
115bf215546Sopenharmony_ci         transferOps |= IMAGE_CLAMP_BIT;
116bf215546Sopenharmony_ci      }
117bf215546Sopenharmony_ci   }
118bf215546Sopenharmony_ci   else {
119bf215546Sopenharmony_ci      /* For CPU-based ReadPixels packing, the clamping must always be done
120bf215546Sopenharmony_ci       * for non-float types, */
121bf215546Sopenharmony_ci      if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) ||
122bf215546Sopenharmony_ci          (type != GL_FLOAT && type != GL_HALF_FLOAT &&
123bf215546Sopenharmony_ci           type != GL_UNSIGNED_INT_10F_11F_11F_REV)) {
124bf215546Sopenharmony_ci         transferOps |= IMAGE_CLAMP_BIT;
125bf215546Sopenharmony_ci      }
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci      /* For SNORM formats we only clamp if `type` is signed and clamp is `true` */
128bf215546Sopenharmony_ci      if (!_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) &&
129bf215546Sopenharmony_ci          _mesa_get_format_datatype(texFormat) == GL_SIGNED_NORMALIZED &&
130bf215546Sopenharmony_ci          (type == GL_BYTE || type == GL_SHORT || type == GL_INT)) {
131bf215546Sopenharmony_ci         transferOps &= ~IMAGE_CLAMP_BIT;
132bf215546Sopenharmony_ci      }
133bf215546Sopenharmony_ci   }
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci   /* If the format is unsigned normalized, we can ignore clamping
136bf215546Sopenharmony_ci    * because the values are already in the range [0,1] so it won't
137bf215546Sopenharmony_ci    * have any effect anyway.
138bf215546Sopenharmony_ci    */
139bf215546Sopenharmony_ci   if (_mesa_get_format_datatype(texFormat) == GL_UNSIGNED_NORMALIZED &&
140bf215546Sopenharmony_ci       !_mesa_need_rgb_to_luminance_conversion(srcBaseFormat, dstBaseFormat)) {
141bf215546Sopenharmony_ci      transferOps &= ~IMAGE_CLAMP_BIT;
142bf215546Sopenharmony_ci   }
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci   return transferOps;
145bf215546Sopenharmony_ci}
146bf215546Sopenharmony_ci
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci/**
149bf215546Sopenharmony_ci * Return true if memcpy cannot be used for ReadPixels.
150bf215546Sopenharmony_ci *
151bf215546Sopenharmony_ci * If uses_blit is true, the function returns true if a simple 3D engine blit
152bf215546Sopenharmony_ci * cannot be used for ReadPixels packing.
153bf215546Sopenharmony_ci *
154bf215546Sopenharmony_ci * NOTE: This doesn't take swizzling and format conversions between
155bf215546Sopenharmony_ci *       the readbuffer and the pixel pack buffer into account.
156bf215546Sopenharmony_ci */
157bf215546Sopenharmony_ciGLboolean
158bf215546Sopenharmony_ci_mesa_readpixels_needs_slow_path(const struct gl_context *ctx, GLenum format,
159bf215546Sopenharmony_ci                                 GLenum type, GLboolean uses_blit)
160bf215546Sopenharmony_ci{
161bf215546Sopenharmony_ci   struct gl_renderbuffer *rb =
162bf215546Sopenharmony_ci         _mesa_get_read_renderbuffer_for_format(ctx, format);
163bf215546Sopenharmony_ci   GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format);
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci   assert(rb);
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_ci   /* There are different rules depending on the base format. */
168bf215546Sopenharmony_ci   switch (format) {
169bf215546Sopenharmony_ci   case GL_DEPTH_STENCIL:
170bf215546Sopenharmony_ci      return !_mesa_has_depthstencil_combined(ctx->ReadBuffer) ||
171bf215546Sopenharmony_ci             ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f ||
172bf215546Sopenharmony_ci             ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
173bf215546Sopenharmony_ci             ctx->Pixel.MapStencilFlag;
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci   case GL_DEPTH_COMPONENT:
176bf215546Sopenharmony_ci      return ctx->Pixel.DepthScale != 1.0f || ctx->Pixel.DepthBias != 0.0f;
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   case GL_STENCIL_INDEX:
179bf215546Sopenharmony_ci      return ctx->Pixel.IndexShift || ctx->Pixel.IndexOffset ||
180bf215546Sopenharmony_ci             ctx->Pixel.MapStencilFlag;
181bf215546Sopenharmony_ci
182bf215546Sopenharmony_ci   default:
183bf215546Sopenharmony_ci      /* Color formats. */
184bf215546Sopenharmony_ci      if (_mesa_need_rgb_to_luminance_conversion(rb->_BaseFormat,
185bf215546Sopenharmony_ci                                                 dstBaseFormat)) {
186bf215546Sopenharmony_ci         return GL_TRUE;
187bf215546Sopenharmony_ci      }
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci      /* And finally, see if there are any transfer ops. */
190bf215546Sopenharmony_ci      return _mesa_get_readpixels_transfer_ops(ctx, rb->Format, format, type,
191bf215546Sopenharmony_ci                                               uses_blit) != 0;
192bf215546Sopenharmony_ci   }
193bf215546Sopenharmony_ci   return GL_FALSE;
194bf215546Sopenharmony_ci}
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_cistatic GLboolean
198bf215546Sopenharmony_cireadpixels_can_use_memcpy(const struct gl_context *ctx, GLenum format, GLenum type,
199bf215546Sopenharmony_ci                          const struct gl_pixelstore_attrib *packing)
200bf215546Sopenharmony_ci{
201bf215546Sopenharmony_ci   struct gl_renderbuffer *rb =
202bf215546Sopenharmony_ci         _mesa_get_read_renderbuffer_for_format(ctx, format);
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   assert(rb);
205bf215546Sopenharmony_ci
206bf215546Sopenharmony_ci   if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_FALSE)) {
207bf215546Sopenharmony_ci      return GL_FALSE;
208bf215546Sopenharmony_ci   }
209bf215546Sopenharmony_ci
210bf215546Sopenharmony_ci   /* The base internal format and the base Mesa format must match. */
211bf215546Sopenharmony_ci   if (rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) {
212bf215546Sopenharmony_ci      return GL_FALSE;
213bf215546Sopenharmony_ci   }
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci   /* The Mesa format must match the input format and type. */
216bf215546Sopenharmony_ci   if (!_mesa_format_matches_format_and_type(rb->Format, format, type,
217bf215546Sopenharmony_ci                                             packing->SwapBytes, NULL)) {
218bf215546Sopenharmony_ci      return GL_FALSE;
219bf215546Sopenharmony_ci   }
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci   return GL_TRUE;
222bf215546Sopenharmony_ci}
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_cistatic GLboolean
226bf215546Sopenharmony_cireadpixels_memcpy(struct gl_context *ctx,
227bf215546Sopenharmony_ci                  GLint x, GLint y,
228bf215546Sopenharmony_ci                  GLsizei width, GLsizei height,
229bf215546Sopenharmony_ci                  GLenum format, GLenum type,
230bf215546Sopenharmony_ci                  GLvoid *pixels,
231bf215546Sopenharmony_ci                  const struct gl_pixelstore_attrib *packing)
232bf215546Sopenharmony_ci{
233bf215546Sopenharmony_ci   struct gl_renderbuffer *rb =
234bf215546Sopenharmony_ci         _mesa_get_read_renderbuffer_for_format(ctx, format);
235bf215546Sopenharmony_ci   GLubyte *dst, *map;
236bf215546Sopenharmony_ci   int dstStride, stride, j, texelBytes, bytesPerRow;
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   /* Fail if memcpy cannot be used. */
239bf215546Sopenharmony_ci   if (!readpixels_can_use_memcpy(ctx, format, type, packing)) {
240bf215546Sopenharmony_ci      return GL_FALSE;
241bf215546Sopenharmony_ci   }
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci   dstStride = _mesa_image_row_stride(packing, width, format, type);
244bf215546Sopenharmony_ci   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
245bf215546Sopenharmony_ci					   format, type, 0, 0);
246bf215546Sopenharmony_ci
247bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
248bf215546Sopenharmony_ci                      &map, &stride, ctx->ReadBuffer->FlipY);
249bf215546Sopenharmony_ci   if (!map) {
250bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
251bf215546Sopenharmony_ci      return GL_TRUE;  /* don't bother trying the slow path */
252bf215546Sopenharmony_ci   }
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   texelBytes = _mesa_get_format_bytes(rb->Format);
255bf215546Sopenharmony_ci   bytesPerRow = texelBytes * width;
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   /* memcpy*/
258bf215546Sopenharmony_ci   if (dstStride == stride && dstStride == bytesPerRow) {
259bf215546Sopenharmony_ci      memcpy(dst, map, bytesPerRow * height);
260bf215546Sopenharmony_ci   } else {
261bf215546Sopenharmony_ci      for (j = 0; j < height; j++) {
262bf215546Sopenharmony_ci         memcpy(dst, map, bytesPerRow);
263bf215546Sopenharmony_ci         dst += dstStride;
264bf215546Sopenharmony_ci         map += stride;
265bf215546Sopenharmony_ci      }
266bf215546Sopenharmony_ci   }
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, rb);
269bf215546Sopenharmony_ci   return GL_TRUE;
270bf215546Sopenharmony_ci}
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci/**
274bf215546Sopenharmony_ci * Optimized path for conversion of depth values to GL_DEPTH_COMPONENT,
275bf215546Sopenharmony_ci * GL_UNSIGNED_INT.
276bf215546Sopenharmony_ci */
277bf215546Sopenharmony_cistatic GLboolean
278bf215546Sopenharmony_ciread_uint_depth_pixels( struct gl_context *ctx,
279bf215546Sopenharmony_ci			GLint x, GLint y,
280bf215546Sopenharmony_ci			GLsizei width, GLsizei height,
281bf215546Sopenharmony_ci			GLenum type, GLvoid *pixels,
282bf215546Sopenharmony_ci			const struct gl_pixelstore_attrib *packing )
283bf215546Sopenharmony_ci{
284bf215546Sopenharmony_ci   struct gl_framebuffer *fb = ctx->ReadBuffer;
285bf215546Sopenharmony_ci   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
286bf215546Sopenharmony_ci   GLubyte *map, *dst;
287bf215546Sopenharmony_ci   int stride, dstStride, j;
288bf215546Sopenharmony_ci
289bf215546Sopenharmony_ci   if (ctx->Pixel.DepthScale != 1.0F || ctx->Pixel.DepthBias != 0.0F)
290bf215546Sopenharmony_ci      return GL_FALSE;
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   if (packing->SwapBytes)
293bf215546Sopenharmony_ci      return GL_FALSE;
294bf215546Sopenharmony_ci
295bf215546Sopenharmony_ci   if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
296bf215546Sopenharmony_ci      return GL_FALSE;
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
299bf215546Sopenharmony_ci                      &map, &stride, fb->FlipY);
300bf215546Sopenharmony_ci
301bf215546Sopenharmony_ci   if (!map) {
302bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
303bf215546Sopenharmony_ci      return GL_TRUE;  /* don't bother trying the slow path */
304bf215546Sopenharmony_ci   }
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ci   dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
307bf215546Sopenharmony_ci   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
308bf215546Sopenharmony_ci					   GL_DEPTH_COMPONENT, type, 0, 0);
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci   for (j = 0; j < height; j++) {
311bf215546Sopenharmony_ci      _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci      map += stride;
314bf215546Sopenharmony_ci      dst += dstStride;
315bf215546Sopenharmony_ci   }
316bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, rb);
317bf215546Sopenharmony_ci
318bf215546Sopenharmony_ci   return GL_TRUE;
319bf215546Sopenharmony_ci}
320bf215546Sopenharmony_ci
321bf215546Sopenharmony_ci/**
322bf215546Sopenharmony_ci * Read pixels for format=GL_DEPTH_COMPONENT.
323bf215546Sopenharmony_ci */
324bf215546Sopenharmony_cistatic void
325bf215546Sopenharmony_ciread_depth_pixels( struct gl_context *ctx,
326bf215546Sopenharmony_ci                   GLint x, GLint y,
327bf215546Sopenharmony_ci                   GLsizei width, GLsizei height,
328bf215546Sopenharmony_ci                   GLenum type, GLvoid *pixels,
329bf215546Sopenharmony_ci                   const struct gl_pixelstore_attrib *packing )
330bf215546Sopenharmony_ci{
331bf215546Sopenharmony_ci   struct gl_framebuffer *fb = ctx->ReadBuffer;
332bf215546Sopenharmony_ci   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
333bf215546Sopenharmony_ci   GLint j;
334bf215546Sopenharmony_ci   GLubyte *dst, *map;
335bf215546Sopenharmony_ci   int dstStride, stride;
336bf215546Sopenharmony_ci   GLfloat *depthValues;
337bf215546Sopenharmony_ci
338bf215546Sopenharmony_ci   if (!rb)
339bf215546Sopenharmony_ci      return;
340bf215546Sopenharmony_ci
341bf215546Sopenharmony_ci   /* clipping should have been done already */
342bf215546Sopenharmony_ci   assert(x >= 0);
343bf215546Sopenharmony_ci   assert(y >= 0);
344bf215546Sopenharmony_ci   assert(x + width <= (GLint) rb->Width);
345bf215546Sopenharmony_ci   assert(y + height <= (GLint) rb->Height);
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   if (type == GL_UNSIGNED_INT &&
348bf215546Sopenharmony_ci       read_uint_depth_pixels(ctx, x, y, width, height, type, pixels, packing)) {
349bf215546Sopenharmony_ci      return;
350bf215546Sopenharmony_ci   }
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci   dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
353bf215546Sopenharmony_ci   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
354bf215546Sopenharmony_ci					   GL_DEPTH_COMPONENT, type, 0, 0);
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
357bf215546Sopenharmony_ci                      &map, &stride, fb->FlipY);
358bf215546Sopenharmony_ci   if (!map) {
359bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
360bf215546Sopenharmony_ci      return;
361bf215546Sopenharmony_ci   }
362bf215546Sopenharmony_ci
363bf215546Sopenharmony_ci   depthValues = malloc(width * sizeof(GLfloat));
364bf215546Sopenharmony_ci
365bf215546Sopenharmony_ci   if (depthValues) {
366bf215546Sopenharmony_ci      /* General case (slower) */
367bf215546Sopenharmony_ci      for (j = 0; j < height; j++, y++) {
368bf215546Sopenharmony_ci         _mesa_unpack_float_z_row(rb->Format, width, map, depthValues);
369bf215546Sopenharmony_ci         _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing);
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci         dst += dstStride;
372bf215546Sopenharmony_ci         map += stride;
373bf215546Sopenharmony_ci      }
374bf215546Sopenharmony_ci   }
375bf215546Sopenharmony_ci   else {
376bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
377bf215546Sopenharmony_ci   }
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci   free(depthValues);
380bf215546Sopenharmony_ci
381bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, rb);
382bf215546Sopenharmony_ci}
383bf215546Sopenharmony_ci
384bf215546Sopenharmony_ci
385bf215546Sopenharmony_ci/**
386bf215546Sopenharmony_ci * Read pixels for format=GL_STENCIL_INDEX.
387bf215546Sopenharmony_ci */
388bf215546Sopenharmony_cistatic void
389bf215546Sopenharmony_ciread_stencil_pixels( struct gl_context *ctx,
390bf215546Sopenharmony_ci                     GLint x, GLint y,
391bf215546Sopenharmony_ci                     GLsizei width, GLsizei height,
392bf215546Sopenharmony_ci                     GLenum type, GLvoid *pixels,
393bf215546Sopenharmony_ci                     const struct gl_pixelstore_attrib *packing )
394bf215546Sopenharmony_ci{
395bf215546Sopenharmony_ci   struct gl_framebuffer *fb = ctx->ReadBuffer;
396bf215546Sopenharmony_ci   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
397bf215546Sopenharmony_ci   GLint j;
398bf215546Sopenharmony_ci   GLubyte *map, *stencil;
399bf215546Sopenharmony_ci   GLint stride;
400bf215546Sopenharmony_ci
401bf215546Sopenharmony_ci   if (!rb)
402bf215546Sopenharmony_ci      return;
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
405bf215546Sopenharmony_ci                      &map, &stride, fb->FlipY);
406bf215546Sopenharmony_ci   if (!map) {
407bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
408bf215546Sopenharmony_ci      return;
409bf215546Sopenharmony_ci   }
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci   stencil = malloc(width * sizeof(GLubyte));
412bf215546Sopenharmony_ci
413bf215546Sopenharmony_ci   if (stencil) {
414bf215546Sopenharmony_ci      /* process image row by row */
415bf215546Sopenharmony_ci      for (j = 0; j < height; j++) {
416bf215546Sopenharmony_ci         GLvoid *dest;
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci         _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil);
419bf215546Sopenharmony_ci         dest = _mesa_image_address2d(packing, pixels, width, height,
420bf215546Sopenharmony_ci                                      GL_STENCIL_INDEX, type, j, 0);
421bf215546Sopenharmony_ci
422bf215546Sopenharmony_ci         _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
423bf215546Sopenharmony_ci
424bf215546Sopenharmony_ci         map += stride;
425bf215546Sopenharmony_ci      }
426bf215546Sopenharmony_ci   }
427bf215546Sopenharmony_ci   else {
428bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
429bf215546Sopenharmony_ci   }
430bf215546Sopenharmony_ci
431bf215546Sopenharmony_ci   free(stencil);
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, rb);
434bf215546Sopenharmony_ci}
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci/*
437bf215546Sopenharmony_ci * Read R, G, B, A, RGB, L, or LA pixels.
438bf215546Sopenharmony_ci */
439bf215546Sopenharmony_cistatic void
440bf215546Sopenharmony_ciread_rgba_pixels( struct gl_context *ctx,
441bf215546Sopenharmony_ci                  GLint x, GLint y,
442bf215546Sopenharmony_ci                  GLsizei width, GLsizei height,
443bf215546Sopenharmony_ci                  GLenum format, GLenum type, GLvoid *pixels,
444bf215546Sopenharmony_ci                  const struct gl_pixelstore_attrib *packing )
445bf215546Sopenharmony_ci{
446bf215546Sopenharmony_ci   GLbitfield transferOps;
447bf215546Sopenharmony_ci   bool dst_is_integer, convert_rgb_to_lum, needs_rebase;
448bf215546Sopenharmony_ci   int dst_stride, src_stride, rb_stride;
449bf215546Sopenharmony_ci   uint32_t dst_format, src_format;
450bf215546Sopenharmony_ci   GLubyte *dst, *map;
451bf215546Sopenharmony_ci   mesa_format rb_format;
452bf215546Sopenharmony_ci   bool needs_rgba;
453bf215546Sopenharmony_ci   void *rgba, *src;
454bf215546Sopenharmony_ci   bool src_is_uint = false;
455bf215546Sopenharmony_ci   uint8_t rebase_swizzle[4];
456bf215546Sopenharmony_ci   struct gl_framebuffer *fb = ctx->ReadBuffer;
457bf215546Sopenharmony_ci   struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
458bf215546Sopenharmony_ci   GLenum dstBaseFormat = _mesa_unpack_format_to_base_format(format);
459bf215546Sopenharmony_ci
460bf215546Sopenharmony_ci   if (!rb)
461bf215546Sopenharmony_ci      return;
462bf215546Sopenharmony_ci
463bf215546Sopenharmony_ci   transferOps = _mesa_get_readpixels_transfer_ops(ctx, rb->Format, format,
464bf215546Sopenharmony_ci                                                   type, GL_FALSE);
465bf215546Sopenharmony_ci   /* Describe the dst format */
466bf215546Sopenharmony_ci   dst_is_integer = _mesa_is_enum_format_integer(format);
467bf215546Sopenharmony_ci   dst_stride = _mesa_image_row_stride(packing, width, format, type);
468bf215546Sopenharmony_ci   dst_format = _mesa_format_from_format_and_type(format, type);
469bf215546Sopenharmony_ci   convert_rgb_to_lum =
470bf215546Sopenharmony_ci      _mesa_need_rgb_to_luminance_conversion(rb->_BaseFormat, dstBaseFormat);
471bf215546Sopenharmony_ci   dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
472bf215546Sopenharmony_ci                                           format, type, 0, 0);
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   /* Map the source render buffer */
475bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
476bf215546Sopenharmony_ci                      &map, &rb_stride, fb->FlipY);
477bf215546Sopenharmony_ci   if (!map) {
478bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
479bf215546Sopenharmony_ci      return;
480bf215546Sopenharmony_ci   }
481bf215546Sopenharmony_ci   rb_format = _mesa_get_srgb_format_linear(rb->Format);
482bf215546Sopenharmony_ci
483bf215546Sopenharmony_ci   /*
484bf215546Sopenharmony_ci    * Depending on the base formats involved in the conversion we might need to
485bf215546Sopenharmony_ci    * rebase some values, so for these formats we compute a rebase swizzle.
486bf215546Sopenharmony_ci    */
487bf215546Sopenharmony_ci   if (rb->_BaseFormat == GL_LUMINANCE || rb->_BaseFormat == GL_INTENSITY) {
488bf215546Sopenharmony_ci      needs_rebase = true;
489bf215546Sopenharmony_ci      rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X;
490bf215546Sopenharmony_ci      rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
491bf215546Sopenharmony_ci      rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
492bf215546Sopenharmony_ci      rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_ONE;
493bf215546Sopenharmony_ci   } else if (rb->_BaseFormat == GL_LUMINANCE_ALPHA) {
494bf215546Sopenharmony_ci      needs_rebase = true;
495bf215546Sopenharmony_ci      rebase_swizzle[0] = MESA_FORMAT_SWIZZLE_X;
496bf215546Sopenharmony_ci      rebase_swizzle[1] = MESA_FORMAT_SWIZZLE_ZERO;
497bf215546Sopenharmony_ci      rebase_swizzle[2] = MESA_FORMAT_SWIZZLE_ZERO;
498bf215546Sopenharmony_ci      rebase_swizzle[3] = MESA_FORMAT_SWIZZLE_W;
499bf215546Sopenharmony_ci   } else if (_mesa_get_format_base_format(rb_format) != rb->_BaseFormat) {
500bf215546Sopenharmony_ci      needs_rebase =
501bf215546Sopenharmony_ci         _mesa_compute_rgba2base2rgba_component_mapping(rb->_BaseFormat,
502bf215546Sopenharmony_ci                                                        rebase_swizzle);
503bf215546Sopenharmony_ci   } else {
504bf215546Sopenharmony_ci      needs_rebase = false;
505bf215546Sopenharmony_ci   }
506bf215546Sopenharmony_ci
507bf215546Sopenharmony_ci   /* Since _mesa_format_convert does not handle transferOps we need to handle
508bf215546Sopenharmony_ci    * them before we call the function. This requires to convert to RGBA float
509bf215546Sopenharmony_ci    * first so we can call _mesa_apply_rgba_transfer_ops. If the dst format is
510bf215546Sopenharmony_ci    * integer transferOps do not apply.
511bf215546Sopenharmony_ci    *
512bf215546Sopenharmony_ci    * Converting to luminance also requires converting to RGBA first, so we can
513bf215546Sopenharmony_ci    * then compute luminance values as L=R+G+B. Notice that this is different
514bf215546Sopenharmony_ci    * from GetTexImage, where we compute L=R.
515bf215546Sopenharmony_ci    */
516bf215546Sopenharmony_ci   assert(!transferOps || (transferOps && !dst_is_integer));
517bf215546Sopenharmony_ci
518bf215546Sopenharmony_ci   needs_rgba = transferOps || convert_rgb_to_lum;
519bf215546Sopenharmony_ci   rgba = NULL;
520bf215546Sopenharmony_ci   if (needs_rgba) {
521bf215546Sopenharmony_ci      uint32_t rgba_format;
522bf215546Sopenharmony_ci      int rgba_stride;
523bf215546Sopenharmony_ci      bool need_convert;
524bf215546Sopenharmony_ci
525bf215546Sopenharmony_ci      /* Convert to RGBA float or int/uint depending on the type of the src */
526bf215546Sopenharmony_ci      if (dst_is_integer) {
527bf215546Sopenharmony_ci         src_is_uint = _mesa_is_format_unsigned(rb_format);
528bf215546Sopenharmony_ci         if (src_is_uint) {
529bf215546Sopenharmony_ci            rgba_format = RGBA32_UINT;
530bf215546Sopenharmony_ci            rgba_stride = width * 4 * sizeof(GLuint);
531bf215546Sopenharmony_ci         } else {
532bf215546Sopenharmony_ci            rgba_format = RGBA32_INT;
533bf215546Sopenharmony_ci            rgba_stride = width * 4 * sizeof(GLint);
534bf215546Sopenharmony_ci         }
535bf215546Sopenharmony_ci      } else {
536bf215546Sopenharmony_ci         rgba_format = RGBA32_FLOAT;
537bf215546Sopenharmony_ci         rgba_stride = width * 4 * sizeof(GLfloat);
538bf215546Sopenharmony_ci      }
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_ci      /* If we are lucky and the dst format matches the RGBA format we need to
541bf215546Sopenharmony_ci       * convert to, then we can convert directly into the dst buffer and avoid
542bf215546Sopenharmony_ci       * the final conversion/copy from the rgba buffer to the dst buffer.
543bf215546Sopenharmony_ci       */
544bf215546Sopenharmony_ci      if (dst_format == rgba_format &&
545bf215546Sopenharmony_ci          dst_stride == rgba_stride) {
546bf215546Sopenharmony_ci         need_convert = false;
547bf215546Sopenharmony_ci         rgba = dst;
548bf215546Sopenharmony_ci      } else {
549bf215546Sopenharmony_ci         need_convert = true;
550bf215546Sopenharmony_ci         rgba = malloc(height * rgba_stride);
551bf215546Sopenharmony_ci         if (!rgba) {
552bf215546Sopenharmony_ci            _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
553bf215546Sopenharmony_ci            goto done_unmap;
554bf215546Sopenharmony_ci         }
555bf215546Sopenharmony_ci      }
556bf215546Sopenharmony_ci
557bf215546Sopenharmony_ci      /* Convert to RGBA now */
558bf215546Sopenharmony_ci      _mesa_format_convert(rgba, rgba_format, rgba_stride,
559bf215546Sopenharmony_ci                           map, rb_format, rb_stride,
560bf215546Sopenharmony_ci                           width, height,
561bf215546Sopenharmony_ci                           needs_rebase ? rebase_swizzle : NULL);
562bf215546Sopenharmony_ci
563bf215546Sopenharmony_ci      /* Handle transfer ops if necessary */
564bf215546Sopenharmony_ci      if (transferOps)
565bf215546Sopenharmony_ci         _mesa_apply_rgba_transfer_ops(ctx, transferOps, width * height, rgba);
566bf215546Sopenharmony_ci
567bf215546Sopenharmony_ci      /* If we had to rebase, we have already taken care of that */
568bf215546Sopenharmony_ci      needs_rebase = false;
569bf215546Sopenharmony_ci
570bf215546Sopenharmony_ci      /* If we were lucky and our RGBA conversion matches the dst format, then
571bf215546Sopenharmony_ci       * we are done.
572bf215546Sopenharmony_ci       */
573bf215546Sopenharmony_ci      if (!need_convert)
574bf215546Sopenharmony_ci         goto done_swap;
575bf215546Sopenharmony_ci
576bf215546Sopenharmony_ci      /* Otherwise, we need to convert from RGBA to dst next */
577bf215546Sopenharmony_ci      src = rgba;
578bf215546Sopenharmony_ci      src_format = rgba_format;
579bf215546Sopenharmony_ci      src_stride = rgba_stride;
580bf215546Sopenharmony_ci   } else {
581bf215546Sopenharmony_ci      /* No RGBA conversion needed, convert directly to dst */
582bf215546Sopenharmony_ci      src = map;
583bf215546Sopenharmony_ci      src_format = rb_format;
584bf215546Sopenharmony_ci      src_stride = rb_stride;
585bf215546Sopenharmony_ci   }
586bf215546Sopenharmony_ci
587bf215546Sopenharmony_ci   /* Do the conversion.
588bf215546Sopenharmony_ci    *
589bf215546Sopenharmony_ci    * If the dst format is Luminance, we need to do the conversion by computing
590bf215546Sopenharmony_ci    * L=R+G+B values.
591bf215546Sopenharmony_ci    */
592bf215546Sopenharmony_ci   if (!convert_rgb_to_lum) {
593bf215546Sopenharmony_ci      _mesa_format_convert(dst, dst_format, dst_stride,
594bf215546Sopenharmony_ci                           src, src_format, src_stride,
595bf215546Sopenharmony_ci                           width, height,
596bf215546Sopenharmony_ci                           needs_rebase ? rebase_swizzle : NULL);
597bf215546Sopenharmony_ci   } else if (!dst_is_integer) {
598bf215546Sopenharmony_ci      /* Compute float Luminance values from RGBA float */
599bf215546Sopenharmony_ci      int luminance_stride, luminance_bytes;
600bf215546Sopenharmony_ci      void *luminance;
601bf215546Sopenharmony_ci      uint32_t luminance_format;
602bf215546Sopenharmony_ci
603bf215546Sopenharmony_ci      luminance_stride = width * sizeof(GLfloat);
604bf215546Sopenharmony_ci      if (format == GL_LUMINANCE_ALPHA)
605bf215546Sopenharmony_ci         luminance_stride *= 2;
606bf215546Sopenharmony_ci      luminance_bytes = height * luminance_stride;
607bf215546Sopenharmony_ci      luminance = malloc(luminance_bytes);
608bf215546Sopenharmony_ci      if (!luminance) {
609bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
610bf215546Sopenharmony_ci         free(rgba);
611bf215546Sopenharmony_ci         goto done_unmap;
612bf215546Sopenharmony_ci      }
613bf215546Sopenharmony_ci      _mesa_pack_luminance_from_rgba_float(width * height, src,
614bf215546Sopenharmony_ci                                           luminance, format, transferOps);
615bf215546Sopenharmony_ci
616bf215546Sopenharmony_ci      /* Convert from Luminance float to dst (this will hadle type conversion
617bf215546Sopenharmony_ci       * from float to the type of dst if necessary)
618bf215546Sopenharmony_ci       */
619bf215546Sopenharmony_ci      luminance_format = _mesa_format_from_format_and_type(format, GL_FLOAT);
620bf215546Sopenharmony_ci      _mesa_format_convert(dst, dst_format, dst_stride,
621bf215546Sopenharmony_ci                           luminance, luminance_format, luminance_stride,
622bf215546Sopenharmony_ci                           width, height, NULL);
623bf215546Sopenharmony_ci      free(luminance);
624bf215546Sopenharmony_ci   } else {
625bf215546Sopenharmony_ci      _mesa_pack_luminance_from_rgba_integer(width * height, src, !src_is_uint,
626bf215546Sopenharmony_ci                                             dst, format, type);
627bf215546Sopenharmony_ci   }
628bf215546Sopenharmony_ci
629bf215546Sopenharmony_ci   free(rgba);
630bf215546Sopenharmony_ci
631bf215546Sopenharmony_cidone_swap:
632bf215546Sopenharmony_ci   /* Handle byte swapping if required */
633bf215546Sopenharmony_ci   if (packing->SwapBytes) {
634bf215546Sopenharmony_ci      _mesa_swap_bytes_2d_image(format, type, packing,
635bf215546Sopenharmony_ci                                width, height, dst, dst);
636bf215546Sopenharmony_ci   }
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_cidone_unmap:
639bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, rb);
640bf215546Sopenharmony_ci}
641bf215546Sopenharmony_ci
642bf215546Sopenharmony_ci/**
643bf215546Sopenharmony_ci * For a packed depth/stencil buffer being read as depth/stencil, just memcpy the
644bf215546Sopenharmony_ci * data (possibly swapping 8/24 vs 24/8 as we go).
645bf215546Sopenharmony_ci */
646bf215546Sopenharmony_cistatic GLboolean
647bf215546Sopenharmony_cifast_read_depth_stencil_pixels(struct gl_context *ctx,
648bf215546Sopenharmony_ci			       GLint x, GLint y,
649bf215546Sopenharmony_ci			       GLsizei width, GLsizei height,
650bf215546Sopenharmony_ci			       GLubyte *dst, int dstStride)
651bf215546Sopenharmony_ci{
652bf215546Sopenharmony_ci   struct gl_framebuffer *fb = ctx->ReadBuffer;
653bf215546Sopenharmony_ci   struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
654bf215546Sopenharmony_ci   struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
655bf215546Sopenharmony_ci   GLubyte *map;
656bf215546Sopenharmony_ci   int stride, i;
657bf215546Sopenharmony_ci
658bf215546Sopenharmony_ci   if (rb != stencilRb)
659bf215546Sopenharmony_ci      return GL_FALSE;
660bf215546Sopenharmony_ci
661bf215546Sopenharmony_ci   if (rb->Format != MESA_FORMAT_S8_UINT_Z24_UNORM &&
662bf215546Sopenharmony_ci       rb->Format != MESA_FORMAT_Z24_UNORM_S8_UINT)
663bf215546Sopenharmony_ci      return GL_FALSE;
664bf215546Sopenharmony_ci
665bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
666bf215546Sopenharmony_ci                      &map, &stride, fb->FlipY);
667bf215546Sopenharmony_ci   if (!map) {
668bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
669bf215546Sopenharmony_ci      return GL_TRUE;  /* don't bother trying the slow path */
670bf215546Sopenharmony_ci   }
671bf215546Sopenharmony_ci
672bf215546Sopenharmony_ci   for (i = 0; i < height; i++) {
673bf215546Sopenharmony_ci      _mesa_unpack_uint_24_8_depth_stencil_row(rb->Format, width,
674bf215546Sopenharmony_ci					       map, (GLuint *)dst);
675bf215546Sopenharmony_ci      map += stride;
676bf215546Sopenharmony_ci      dst += dstStride;
677bf215546Sopenharmony_ci   }
678bf215546Sopenharmony_ci
679bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, rb);
680bf215546Sopenharmony_ci
681bf215546Sopenharmony_ci   return GL_TRUE;
682bf215546Sopenharmony_ci}
683bf215546Sopenharmony_ci
684bf215546Sopenharmony_ci
685bf215546Sopenharmony_ci/**
686bf215546Sopenharmony_ci * For non-float-depth and stencil buffers being read as 24/8 depth/stencil,
687bf215546Sopenharmony_ci * copy the integer data directly instead of converting depth to float and
688bf215546Sopenharmony_ci * re-packing.
689bf215546Sopenharmony_ci */
690bf215546Sopenharmony_cistatic GLboolean
691bf215546Sopenharmony_cifast_read_depth_stencil_pixels_separate(struct gl_context *ctx,
692bf215546Sopenharmony_ci					GLint x, GLint y,
693bf215546Sopenharmony_ci					GLsizei width, GLsizei height,
694bf215546Sopenharmony_ci					uint32_t *dst, int dstStride)
695bf215546Sopenharmony_ci{
696bf215546Sopenharmony_ci   struct gl_framebuffer *fb = ctx->ReadBuffer;
697bf215546Sopenharmony_ci   struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
698bf215546Sopenharmony_ci   struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
699bf215546Sopenharmony_ci   GLubyte *depthMap, *stencilMap, *stencilVals;
700bf215546Sopenharmony_ci   int depthStride, stencilStride, i, j;
701bf215546Sopenharmony_ci
702bf215546Sopenharmony_ci   if (_mesa_get_format_datatype(depthRb->Format) != GL_UNSIGNED_NORMALIZED)
703bf215546Sopenharmony_ci      return GL_FALSE;
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, depthRb, x, y, width, height,
706bf215546Sopenharmony_ci                      GL_MAP_READ_BIT, &depthMap, &depthStride, fb->FlipY);
707bf215546Sopenharmony_ci   if (!depthMap) {
708bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
709bf215546Sopenharmony_ci      return GL_TRUE;  /* don't bother trying the slow path */
710bf215546Sopenharmony_ci   }
711bf215546Sopenharmony_ci
712bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, stencilRb, x, y, width, height,
713bf215546Sopenharmony_ci                      GL_MAP_READ_BIT, &stencilMap, &stencilStride, fb->FlipY);
714bf215546Sopenharmony_ci   if (!stencilMap) {
715bf215546Sopenharmony_ci      _mesa_unmap_renderbuffer(ctx, depthRb);
716bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
717bf215546Sopenharmony_ci      return GL_TRUE;  /* don't bother trying the slow path */
718bf215546Sopenharmony_ci   }
719bf215546Sopenharmony_ci
720bf215546Sopenharmony_ci   stencilVals = malloc(width * sizeof(GLubyte));
721bf215546Sopenharmony_ci
722bf215546Sopenharmony_ci   if (stencilVals) {
723bf215546Sopenharmony_ci      for (j = 0; j < height; j++) {
724bf215546Sopenharmony_ci         _mesa_unpack_uint_z_row(depthRb->Format, width, depthMap, dst);
725bf215546Sopenharmony_ci         _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
726bf215546Sopenharmony_ci                                        stencilMap, stencilVals);
727bf215546Sopenharmony_ci
728bf215546Sopenharmony_ci         for (i = 0; i < width; i++) {
729bf215546Sopenharmony_ci            dst[i] = (dst[i] & 0xffffff00) | stencilVals[i];
730bf215546Sopenharmony_ci         }
731bf215546Sopenharmony_ci
732bf215546Sopenharmony_ci         depthMap += depthStride;
733bf215546Sopenharmony_ci         stencilMap += stencilStride;
734bf215546Sopenharmony_ci         dst += dstStride / 4;
735bf215546Sopenharmony_ci      }
736bf215546Sopenharmony_ci   }
737bf215546Sopenharmony_ci   else {
738bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
739bf215546Sopenharmony_ci   }
740bf215546Sopenharmony_ci
741bf215546Sopenharmony_ci   free(stencilVals);
742bf215546Sopenharmony_ci
743bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, depthRb);
744bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, stencilRb);
745bf215546Sopenharmony_ci
746bf215546Sopenharmony_ci   return GL_TRUE;
747bf215546Sopenharmony_ci}
748bf215546Sopenharmony_ci
749bf215546Sopenharmony_cistatic void
750bf215546Sopenharmony_cislow_read_depth_stencil_pixels_separate(struct gl_context *ctx,
751bf215546Sopenharmony_ci					GLint x, GLint y,
752bf215546Sopenharmony_ci					GLsizei width, GLsizei height,
753bf215546Sopenharmony_ci					GLenum type,
754bf215546Sopenharmony_ci					const struct gl_pixelstore_attrib *packing,
755bf215546Sopenharmony_ci					GLubyte *dst, int dstStride)
756bf215546Sopenharmony_ci{
757bf215546Sopenharmony_ci   struct gl_framebuffer *fb = ctx->ReadBuffer;
758bf215546Sopenharmony_ci   struct gl_renderbuffer *depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
759bf215546Sopenharmony_ci   struct gl_renderbuffer *stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
760bf215546Sopenharmony_ci   GLubyte *depthMap, *stencilMap;
761bf215546Sopenharmony_ci   int depthStride, stencilStride, j;
762bf215546Sopenharmony_ci   GLubyte *stencilVals;
763bf215546Sopenharmony_ci   GLfloat *depthVals;
764bf215546Sopenharmony_ci
765bf215546Sopenharmony_ci
766bf215546Sopenharmony_ci   /* The depth and stencil buffers might be separate, or a single buffer.
767bf215546Sopenharmony_ci    * If one buffer, only map it once.
768bf215546Sopenharmony_ci    */
769bf215546Sopenharmony_ci   _mesa_map_renderbuffer(ctx, depthRb, x, y, width, height,
770bf215546Sopenharmony_ci                      GL_MAP_READ_BIT, &depthMap, &depthStride, fb->FlipY);
771bf215546Sopenharmony_ci   if (!depthMap) {
772bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
773bf215546Sopenharmony_ci      return;
774bf215546Sopenharmony_ci   }
775bf215546Sopenharmony_ci
776bf215546Sopenharmony_ci   if (stencilRb != depthRb) {
777bf215546Sopenharmony_ci      _mesa_map_renderbuffer(ctx, stencilRb, x, y, width, height,
778bf215546Sopenharmony_ci                         GL_MAP_READ_BIT, &stencilMap,
779bf215546Sopenharmony_ci                         &stencilStride, fb->FlipY);
780bf215546Sopenharmony_ci      if (!stencilMap) {
781bf215546Sopenharmony_ci         _mesa_unmap_renderbuffer(ctx, depthRb);
782bf215546Sopenharmony_ci         _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
783bf215546Sopenharmony_ci         return;
784bf215546Sopenharmony_ci      }
785bf215546Sopenharmony_ci   }
786bf215546Sopenharmony_ci   else {
787bf215546Sopenharmony_ci      stencilMap = depthMap;
788bf215546Sopenharmony_ci      stencilStride = depthStride;
789bf215546Sopenharmony_ci   }
790bf215546Sopenharmony_ci
791bf215546Sopenharmony_ci   stencilVals = malloc(width * sizeof(GLubyte));
792bf215546Sopenharmony_ci   depthVals = malloc(width * sizeof(GLfloat));
793bf215546Sopenharmony_ci
794bf215546Sopenharmony_ci   if (stencilVals && depthVals) {
795bf215546Sopenharmony_ci      for (j = 0; j < height; j++) {
796bf215546Sopenharmony_ci         _mesa_unpack_float_z_row(depthRb->Format, width, depthMap, depthVals);
797bf215546Sopenharmony_ci         _mesa_unpack_ubyte_stencil_row(stencilRb->Format, width,
798bf215546Sopenharmony_ci                                        stencilMap, stencilVals);
799bf215546Sopenharmony_ci
800bf215546Sopenharmony_ci         _mesa_pack_depth_stencil_span(ctx, width, type, (GLuint *)dst,
801bf215546Sopenharmony_ci                                       depthVals, stencilVals, packing);
802bf215546Sopenharmony_ci
803bf215546Sopenharmony_ci         depthMap += depthStride;
804bf215546Sopenharmony_ci         stencilMap += stencilStride;
805bf215546Sopenharmony_ci         dst += dstStride;
806bf215546Sopenharmony_ci      }
807bf215546Sopenharmony_ci   }
808bf215546Sopenharmony_ci   else {
809bf215546Sopenharmony_ci      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
810bf215546Sopenharmony_ci   }
811bf215546Sopenharmony_ci
812bf215546Sopenharmony_ci   free(stencilVals);
813bf215546Sopenharmony_ci   free(depthVals);
814bf215546Sopenharmony_ci
815bf215546Sopenharmony_ci   _mesa_unmap_renderbuffer(ctx, depthRb);
816bf215546Sopenharmony_ci   if (stencilRb != depthRb) {
817bf215546Sopenharmony_ci      _mesa_unmap_renderbuffer(ctx, stencilRb);
818bf215546Sopenharmony_ci   }
819bf215546Sopenharmony_ci}
820bf215546Sopenharmony_ci
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci/**
823bf215546Sopenharmony_ci * Read combined depth/stencil values.
824bf215546Sopenharmony_ci * We'll have already done error checking to be sure the expected
825bf215546Sopenharmony_ci * depth and stencil buffers really exist.
826bf215546Sopenharmony_ci */
827bf215546Sopenharmony_cistatic void
828bf215546Sopenharmony_ciread_depth_stencil_pixels(struct gl_context *ctx,
829bf215546Sopenharmony_ci                          GLint x, GLint y,
830bf215546Sopenharmony_ci                          GLsizei width, GLsizei height,
831bf215546Sopenharmony_ci                          GLenum type, GLvoid *pixels,
832bf215546Sopenharmony_ci                          const struct gl_pixelstore_attrib *packing )
833bf215546Sopenharmony_ci{
834bf215546Sopenharmony_ci   const GLboolean scaleOrBias
835bf215546Sopenharmony_ci      = ctx->Pixel.DepthScale != 1.0F || ctx->Pixel.DepthBias != 0.0F;
836bf215546Sopenharmony_ci   const GLboolean stencilTransfer = ctx->Pixel.IndexShift
837bf215546Sopenharmony_ci      || ctx->Pixel.IndexOffset || ctx->Pixel.MapStencilFlag;
838bf215546Sopenharmony_ci   GLubyte *dst;
839bf215546Sopenharmony_ci   int dstStride;
840bf215546Sopenharmony_ci
841bf215546Sopenharmony_ci   dst = (GLubyte *) _mesa_image_address2d(packing, pixels,
842bf215546Sopenharmony_ci					   width, height,
843bf215546Sopenharmony_ci					   GL_DEPTH_STENCIL_EXT,
844bf215546Sopenharmony_ci					   type, 0, 0);
845bf215546Sopenharmony_ci   dstStride = _mesa_image_row_stride(packing, width,
846bf215546Sopenharmony_ci				      GL_DEPTH_STENCIL_EXT, type);
847bf215546Sopenharmony_ci
848bf215546Sopenharmony_ci   /* Fast 24/8 reads. */
849bf215546Sopenharmony_ci   if (type == GL_UNSIGNED_INT_24_8 &&
850bf215546Sopenharmony_ci       !scaleOrBias && !stencilTransfer && !packing->SwapBytes) {
851bf215546Sopenharmony_ci      if (fast_read_depth_stencil_pixels(ctx, x, y, width, height,
852bf215546Sopenharmony_ci					 dst, dstStride))
853bf215546Sopenharmony_ci	 return;
854bf215546Sopenharmony_ci
855bf215546Sopenharmony_ci      if (fast_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
856bf215546Sopenharmony_ci						  (uint32_t *)dst, dstStride))
857bf215546Sopenharmony_ci	 return;
858bf215546Sopenharmony_ci   }
859bf215546Sopenharmony_ci
860bf215546Sopenharmony_ci   slow_read_depth_stencil_pixels_separate(ctx, x, y, width, height,
861bf215546Sopenharmony_ci					   type, packing,
862bf215546Sopenharmony_ci					   dst, dstStride);
863bf215546Sopenharmony_ci}
864bf215546Sopenharmony_ci
865bf215546Sopenharmony_ci
866bf215546Sopenharmony_ci
867bf215546Sopenharmony_ci/**
868bf215546Sopenharmony_ci * Software fallback routine.
869bf215546Sopenharmony_ci * By time we get here, all error checking will have been done.
870bf215546Sopenharmony_ci */
871bf215546Sopenharmony_civoid
872bf215546Sopenharmony_ci_mesa_readpixels(struct gl_context *ctx,
873bf215546Sopenharmony_ci                 GLint x, GLint y, GLsizei width, GLsizei height,
874bf215546Sopenharmony_ci                 GLenum format, GLenum type,
875bf215546Sopenharmony_ci                 const struct gl_pixelstore_attrib *packing,
876bf215546Sopenharmony_ci                 GLvoid *pixels)
877bf215546Sopenharmony_ci{
878bf215546Sopenharmony_ci   if (ctx->NewState)
879bf215546Sopenharmony_ci      _mesa_update_state(ctx);
880bf215546Sopenharmony_ci
881bf215546Sopenharmony_ci   pixels = _mesa_map_pbo_dest(ctx, packing, pixels);
882bf215546Sopenharmony_ci
883bf215546Sopenharmony_ci   if (pixels) {
884bf215546Sopenharmony_ci      /* Try memcpy first. */
885bf215546Sopenharmony_ci      if (readpixels_memcpy(ctx, x, y, width, height, format, type,
886bf215546Sopenharmony_ci                            pixels, packing)) {
887bf215546Sopenharmony_ci         _mesa_unmap_pbo_dest(ctx, packing);
888bf215546Sopenharmony_ci         return;
889bf215546Sopenharmony_ci      }
890bf215546Sopenharmony_ci
891bf215546Sopenharmony_ci      /* Otherwise take the slow path. */
892bf215546Sopenharmony_ci      switch (format) {
893bf215546Sopenharmony_ci      case GL_STENCIL_INDEX:
894bf215546Sopenharmony_ci         read_stencil_pixels(ctx, x, y, width, height, type, pixels,
895bf215546Sopenharmony_ci                             packing);
896bf215546Sopenharmony_ci         break;
897bf215546Sopenharmony_ci      case GL_DEPTH_COMPONENT:
898bf215546Sopenharmony_ci         read_depth_pixels(ctx, x, y, width, height, type, pixels,
899bf215546Sopenharmony_ci                           packing);
900bf215546Sopenharmony_ci         break;
901bf215546Sopenharmony_ci      case GL_DEPTH_STENCIL_EXT:
902bf215546Sopenharmony_ci         read_depth_stencil_pixels(ctx, x, y, width, height, type, pixels,
903bf215546Sopenharmony_ci                                   packing);
904bf215546Sopenharmony_ci         break;
905bf215546Sopenharmony_ci      default:
906bf215546Sopenharmony_ci         /* all other formats should be color formats */
907bf215546Sopenharmony_ci         read_rgba_pixels(ctx, x, y, width, height, format, type, pixels,
908bf215546Sopenharmony_ci                          packing);
909bf215546Sopenharmony_ci      }
910bf215546Sopenharmony_ci
911bf215546Sopenharmony_ci      _mesa_unmap_pbo_dest(ctx, packing);
912bf215546Sopenharmony_ci   }
913bf215546Sopenharmony_ci}
914bf215546Sopenharmony_ci
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_cistatic GLenum
917bf215546Sopenharmony_ciread_pixels_es3_error_check(struct gl_context *ctx, GLenum format, GLenum type,
918bf215546Sopenharmony_ci                            const struct gl_renderbuffer *rb)
919bf215546Sopenharmony_ci{
920bf215546Sopenharmony_ci   const GLenum internalFormat = rb->InternalFormat;
921bf215546Sopenharmony_ci   const GLenum data_type = _mesa_get_format_datatype(rb->Format);
922bf215546Sopenharmony_ci   GLboolean is_unsigned_int = GL_FALSE;
923bf215546Sopenharmony_ci   GLboolean is_signed_int = GL_FALSE;
924bf215546Sopenharmony_ci   GLboolean is_float_depth = _mesa_has_depth_float_channel(internalFormat);
925bf215546Sopenharmony_ci
926bf215546Sopenharmony_ci   is_unsigned_int = _mesa_is_enum_format_unsigned_int(internalFormat);
927bf215546Sopenharmony_ci   if (!is_unsigned_int) {
928bf215546Sopenharmony_ci      is_signed_int = _mesa_is_enum_format_signed_int(internalFormat);
929bf215546Sopenharmony_ci   }
930bf215546Sopenharmony_ci
931bf215546Sopenharmony_ci   switch (format) {
932bf215546Sopenharmony_ci   case GL_RGBA:
933bf215546Sopenharmony_ci      if (type == GL_FLOAT && data_type == GL_FLOAT)
934bf215546Sopenharmony_ci         return GL_NO_ERROR; /* EXT_color_buffer_float */
935bf215546Sopenharmony_ci      if (type == GL_UNSIGNED_BYTE && data_type == GL_UNSIGNED_NORMALIZED)
936bf215546Sopenharmony_ci         return GL_NO_ERROR;
937bf215546Sopenharmony_ci      if (internalFormat == GL_RGB10_A2 &&
938bf215546Sopenharmony_ci          type == GL_UNSIGNED_INT_2_10_10_10_REV)
939bf215546Sopenharmony_ci         return GL_NO_ERROR;
940bf215546Sopenharmony_ci      if (internalFormat == GL_RGB10_A2UI && type == GL_UNSIGNED_BYTE)
941bf215546Sopenharmony_ci         return GL_NO_ERROR;
942bf215546Sopenharmony_ci      if (type == GL_UNSIGNED_SHORT) {
943bf215546Sopenharmony_ci         switch (internalFormat) {
944bf215546Sopenharmony_ci         case GL_R16:
945bf215546Sopenharmony_ci         case GL_RG16:
946bf215546Sopenharmony_ci         case GL_RGB16:
947bf215546Sopenharmony_ci         case GL_RGBA16:
948bf215546Sopenharmony_ci            if (_mesa_has_EXT_texture_norm16(ctx))
949bf215546Sopenharmony_ci               return GL_NO_ERROR;
950bf215546Sopenharmony_ci         }
951bf215546Sopenharmony_ci      }
952bf215546Sopenharmony_ci      if (type == GL_SHORT) {
953bf215546Sopenharmony_ci         switch (internalFormat) {
954bf215546Sopenharmony_ci         case GL_R16_SNORM:
955bf215546Sopenharmony_ci         case GL_RG16_SNORM:
956bf215546Sopenharmony_ci         case GL_RGBA16_SNORM:
957bf215546Sopenharmony_ci            if (_mesa_has_EXT_texture_norm16(ctx) &&
958bf215546Sopenharmony_ci                _mesa_has_EXT_render_snorm(ctx))
959bf215546Sopenharmony_ci               return GL_NO_ERROR;
960bf215546Sopenharmony_ci         }
961bf215546Sopenharmony_ci      }
962bf215546Sopenharmony_ci      if (type == GL_BYTE) {
963bf215546Sopenharmony_ci         switch (internalFormat) {
964bf215546Sopenharmony_ci         case GL_R8_SNORM:
965bf215546Sopenharmony_ci         case GL_RG8_SNORM:
966bf215546Sopenharmony_ci         case GL_RGBA8_SNORM:
967bf215546Sopenharmony_ci            if (_mesa_has_EXT_render_snorm(ctx))
968bf215546Sopenharmony_ci               return GL_NO_ERROR;
969bf215546Sopenharmony_ci         }
970bf215546Sopenharmony_ci      }
971bf215546Sopenharmony_ci      if (type == GL_UNSIGNED_BYTE) {
972bf215546Sopenharmony_ci         switch (internalFormat) {
973bf215546Sopenharmony_ci         case GL_R8_SNORM:
974bf215546Sopenharmony_ci         case GL_RG8_SNORM:
975bf215546Sopenharmony_ci         case GL_RGBA8_SNORM:
976bf215546Sopenharmony_ci            if (_mesa_has_EXT_render_snorm(ctx))
977bf215546Sopenharmony_ci               return GL_NO_ERROR;
978bf215546Sopenharmony_ci         }
979bf215546Sopenharmony_ci      }
980bf215546Sopenharmony_ci      break;
981bf215546Sopenharmony_ci   case GL_BGRA:
982bf215546Sopenharmony_ci      /* GL_EXT_read_format_bgra */
983bf215546Sopenharmony_ci      if (type == GL_UNSIGNED_BYTE ||
984bf215546Sopenharmony_ci          type == GL_UNSIGNED_SHORT_4_4_4_4_REV ||
985bf215546Sopenharmony_ci          type == GL_UNSIGNED_SHORT_1_5_5_5_REV)
986bf215546Sopenharmony_ci         return GL_NO_ERROR;
987bf215546Sopenharmony_ci      break;
988bf215546Sopenharmony_ci   case GL_RGBA_INTEGER:
989bf215546Sopenharmony_ci      if ((is_signed_int && type == GL_INT) ||
990bf215546Sopenharmony_ci          (is_unsigned_int && type == GL_UNSIGNED_INT))
991bf215546Sopenharmony_ci         return GL_NO_ERROR;
992bf215546Sopenharmony_ci      break;
993bf215546Sopenharmony_ci   case GL_DEPTH_STENCIL:
994bf215546Sopenharmony_ci      switch (type) {
995bf215546Sopenharmony_ci      case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
996bf215546Sopenharmony_ci         if (is_float_depth)
997bf215546Sopenharmony_ci            return GL_NO_ERROR;
998bf215546Sopenharmony_ci         break;
999bf215546Sopenharmony_ci      case GL_UNSIGNED_INT_24_8:
1000bf215546Sopenharmony_ci         if (!is_float_depth)
1001bf215546Sopenharmony_ci            return GL_NO_ERROR;
1002bf215546Sopenharmony_ci         break;
1003bf215546Sopenharmony_ci      default:
1004bf215546Sopenharmony_ci         return GL_INVALID_ENUM;
1005bf215546Sopenharmony_ci      }
1006bf215546Sopenharmony_ci      break;
1007bf215546Sopenharmony_ci   case GL_DEPTH_COMPONENT:
1008bf215546Sopenharmony_ci      switch (type) {
1009bf215546Sopenharmony_ci      case GL_FLOAT:
1010bf215546Sopenharmony_ci         if (is_float_depth)
1011bf215546Sopenharmony_ci            return GL_NO_ERROR;
1012bf215546Sopenharmony_ci         break;
1013bf215546Sopenharmony_ci      case GL_UNSIGNED_SHORT:
1014bf215546Sopenharmony_ci      case GL_UNSIGNED_INT:
1015bf215546Sopenharmony_ci      case GL_UNSIGNED_INT_24_8:
1016bf215546Sopenharmony_ci         if (!is_float_depth)
1017bf215546Sopenharmony_ci            return GL_NO_ERROR;
1018bf215546Sopenharmony_ci         break;
1019bf215546Sopenharmony_ci      default:
1020bf215546Sopenharmony_ci         return GL_INVALID_ENUM;
1021bf215546Sopenharmony_ci      }
1022bf215546Sopenharmony_ci      break;
1023bf215546Sopenharmony_ci   case GL_STENCIL_INDEX:
1024bf215546Sopenharmony_ci      switch (type) {
1025bf215546Sopenharmony_ci      case GL_UNSIGNED_BYTE:
1026bf215546Sopenharmony_ci         return GL_NO_ERROR;
1027bf215546Sopenharmony_ci      default:
1028bf215546Sopenharmony_ci         return GL_INVALID_ENUM;
1029bf215546Sopenharmony_ci      }
1030bf215546Sopenharmony_ci      break;
1031bf215546Sopenharmony_ci   }
1032bf215546Sopenharmony_ci
1033bf215546Sopenharmony_ci   return GL_INVALID_OPERATION;
1034bf215546Sopenharmony_ci}
1035bf215546Sopenharmony_ci
1036bf215546Sopenharmony_ci
1037bf215546Sopenharmony_cistatic ALWAYS_INLINE void
1038bf215546Sopenharmony_ciread_pixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
1039bf215546Sopenharmony_ci            GLenum type, GLsizei bufSize, GLvoid *pixels, bool no_error)
1040bf215546Sopenharmony_ci{
1041bf215546Sopenharmony_ci   GLenum err = GL_NO_ERROR;
1042bf215546Sopenharmony_ci   struct gl_renderbuffer *rb;
1043bf215546Sopenharmony_ci   struct gl_pixelstore_attrib clippedPacking;
1044bf215546Sopenharmony_ci
1045bf215546Sopenharmony_ci   GET_CURRENT_CONTEXT(ctx);
1046bf215546Sopenharmony_ci
1047bf215546Sopenharmony_ci   FLUSH_VERTICES(ctx, 0, 0);
1048bf215546Sopenharmony_ci
1049bf215546Sopenharmony_ci   if (MESA_VERBOSE & VERBOSE_API)
1050bf215546Sopenharmony_ci      _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
1051bf215546Sopenharmony_ci                  width, height,
1052bf215546Sopenharmony_ci                  _mesa_enum_to_string(format),
1053bf215546Sopenharmony_ci                  _mesa_enum_to_string(type),
1054bf215546Sopenharmony_ci                  pixels);
1055bf215546Sopenharmony_ci
1056bf215546Sopenharmony_ci   if (!no_error && (width < 0 || height < 0)) {
1057bf215546Sopenharmony_ci      _mesa_error( ctx, GL_INVALID_VALUE,
1058bf215546Sopenharmony_ci                   "glReadPixels(width=%d height=%d)", width, height );
1059bf215546Sopenharmony_ci      return;
1060bf215546Sopenharmony_ci   }
1061bf215546Sopenharmony_ci
1062bf215546Sopenharmony_ci   _mesa_update_pixel(ctx);
1063bf215546Sopenharmony_ci
1064bf215546Sopenharmony_ci   if (ctx->NewState)
1065bf215546Sopenharmony_ci      _mesa_update_state(ctx);
1066bf215546Sopenharmony_ci
1067bf215546Sopenharmony_ci   if (!no_error && ctx->ReadBuffer->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
1068bf215546Sopenharmony_ci      _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
1069bf215546Sopenharmony_ci                  "glReadPixels(incomplete framebuffer)" );
1070bf215546Sopenharmony_ci      return;
1071bf215546Sopenharmony_ci   }
1072bf215546Sopenharmony_ci
1073bf215546Sopenharmony_ci   rb = _mesa_get_read_renderbuffer_for_format(ctx, format);
1074bf215546Sopenharmony_ci   if (!no_error) {
1075bf215546Sopenharmony_ci      if (rb == NULL) {
1076bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION,
1077bf215546Sopenharmony_ci                     "glReadPixels(read buffer)");
1078bf215546Sopenharmony_ci         return;
1079bf215546Sopenharmony_ci      }
1080bf215546Sopenharmony_ci
1081bf215546Sopenharmony_ci      /* OpenGL ES 1.x and OpenGL ES 2.0 impose additional restrictions on the
1082bf215546Sopenharmony_ci       * combinations of format and type that can be used.
1083bf215546Sopenharmony_ci       *
1084bf215546Sopenharmony_ci       * Technically, only two combinations are actually allowed:
1085bf215546Sopenharmony_ci       * GL_RGBA/GL_UNSIGNED_BYTE, and some implementation-specific internal
1086bf215546Sopenharmony_ci       * preferred combination.  This code doesn't know what that preferred
1087bf215546Sopenharmony_ci       * combination is, and Mesa can handle anything valid.  Just work instead.
1088bf215546Sopenharmony_ci       */
1089bf215546Sopenharmony_ci      if (_mesa_is_gles(ctx)) {
1090bf215546Sopenharmony_ci         if (ctx->API == API_OPENGLES2 &&
1091bf215546Sopenharmony_ci             _mesa_is_color_format(format) &&
1092bf215546Sopenharmony_ci             _mesa_get_color_read_format(ctx, NULL, "glReadPixels") == format &&
1093bf215546Sopenharmony_ci             _mesa_get_color_read_type(ctx, NULL, "glReadPixels") == type) {
1094bf215546Sopenharmony_ci            err = GL_NO_ERROR;
1095bf215546Sopenharmony_ci         } else if (ctx->Version < 30) {
1096bf215546Sopenharmony_ci            err = _mesa_es_error_check_format_and_type(ctx, format, type, 2);
1097bf215546Sopenharmony_ci            if (err == GL_NO_ERROR) {
1098bf215546Sopenharmony_ci               if (type == GL_FLOAT || type == GL_HALF_FLOAT_OES) {
1099bf215546Sopenharmony_ci                  err = GL_INVALID_OPERATION;
1100bf215546Sopenharmony_ci               }
1101bf215546Sopenharmony_ci            }
1102bf215546Sopenharmony_ci         } else {
1103bf215546Sopenharmony_ci            err = read_pixels_es3_error_check(ctx, format, type, rb);
1104bf215546Sopenharmony_ci         }
1105bf215546Sopenharmony_ci
1106bf215546Sopenharmony_ci         if (err != GL_NO_ERROR) {
1107bf215546Sopenharmony_ci            _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
1108bf215546Sopenharmony_ci                        _mesa_enum_to_string(format),
1109bf215546Sopenharmony_ci                        _mesa_enum_to_string(type));
1110bf215546Sopenharmony_ci            return;
1111bf215546Sopenharmony_ci         }
1112bf215546Sopenharmony_ci      }
1113bf215546Sopenharmony_ci
1114bf215546Sopenharmony_ci      err = _mesa_error_check_format_and_type(ctx, format, type);
1115bf215546Sopenharmony_ci      if (err != GL_NO_ERROR) {
1116bf215546Sopenharmony_ci         _mesa_error(ctx, err, "glReadPixels(invalid format %s and/or type %s)",
1117bf215546Sopenharmony_ci                     _mesa_enum_to_string(format),
1118bf215546Sopenharmony_ci                     _mesa_enum_to_string(type));
1119bf215546Sopenharmony_ci         return;
1120bf215546Sopenharmony_ci      }
1121bf215546Sopenharmony_ci
1122bf215546Sopenharmony_ci      if (_mesa_is_user_fbo(ctx->ReadBuffer) &&
1123bf215546Sopenharmony_ci          ctx->ReadBuffer->Visual.samples > 0) {
1124bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(multisample FBO)");
1125bf215546Sopenharmony_ci         return;
1126bf215546Sopenharmony_ci      }
1127bf215546Sopenharmony_ci
1128bf215546Sopenharmony_ci      if (!_mesa_source_buffer_exists(ctx, format)) {
1129bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
1130bf215546Sopenharmony_ci         return;
1131bf215546Sopenharmony_ci      }
1132bf215546Sopenharmony_ci
1133bf215546Sopenharmony_ci      /* Check that the destination format and source buffer are both
1134bf215546Sopenharmony_ci       * integer-valued or both non-integer-valued.
1135bf215546Sopenharmony_ci       */
1136bf215546Sopenharmony_ci      if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
1137bf215546Sopenharmony_ci         const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
1138bf215546Sopenharmony_ci         const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
1139bf215546Sopenharmony_ci         const GLboolean dstInteger = _mesa_is_enum_format_integer(format);
1140bf215546Sopenharmony_ci         if (dstInteger != srcInteger) {
1141bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_OPERATION,
1142bf215546Sopenharmony_ci                        "glReadPixels(integer / non-integer format mismatch");
1143bf215546Sopenharmony_ci            return;
1144bf215546Sopenharmony_ci         }
1145bf215546Sopenharmony_ci      }
1146bf215546Sopenharmony_ci   }
1147bf215546Sopenharmony_ci
1148bf215546Sopenharmony_ci   /* Do all needed clipping here, so that we can forget about it later */
1149bf215546Sopenharmony_ci   clippedPacking = ctx->Pack;
1150bf215546Sopenharmony_ci   if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking))
1151bf215546Sopenharmony_ci      return; /* nothing to do */
1152bf215546Sopenharmony_ci
1153bf215546Sopenharmony_ci   if (!no_error) {
1154bf215546Sopenharmony_ci      if (!_mesa_validate_pbo_access(2, &ctx->Pack, width, height, 1,
1155bf215546Sopenharmony_ci                                     format, type, bufSize, pixels)) {
1156bf215546Sopenharmony_ci         if (ctx->Pack.BufferObj) {
1157bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_OPERATION,
1158bf215546Sopenharmony_ci                        "glReadPixels(out of bounds PBO access)");
1159bf215546Sopenharmony_ci         } else {
1160bf215546Sopenharmony_ci            _mesa_error(ctx, GL_INVALID_OPERATION,
1161bf215546Sopenharmony_ci                        "glReadnPixelsARB(out of bounds access:"
1162bf215546Sopenharmony_ci                        " bufSize (%d) is too small)", bufSize);
1163bf215546Sopenharmony_ci         }
1164bf215546Sopenharmony_ci         return;
1165bf215546Sopenharmony_ci      }
1166bf215546Sopenharmony_ci
1167bf215546Sopenharmony_ci      if (ctx->Pack.BufferObj &&
1168bf215546Sopenharmony_ci          _mesa_check_disallowed_mapping(ctx->Pack.BufferObj)) {
1169bf215546Sopenharmony_ci         /* buffer is mapped - that's an error */
1170bf215546Sopenharmony_ci         _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
1171bf215546Sopenharmony_ci         return;
1172bf215546Sopenharmony_ci      }
1173bf215546Sopenharmony_ci   }
1174bf215546Sopenharmony_ci
1175bf215546Sopenharmony_ci   if (ctx->Pack.BufferObj)
1176bf215546Sopenharmony_ci      ctx->Pack.BufferObj->UsageHistory |= USAGE_PIXEL_PACK_BUFFER;
1177bf215546Sopenharmony_ci
1178bf215546Sopenharmony_ci   st_ReadPixels(ctx, x, y, width, height,
1179bf215546Sopenharmony_ci                 format, type, &clippedPacking, pixels);
1180bf215546Sopenharmony_ci}
1181bf215546Sopenharmony_ci
1182bf215546Sopenharmony_civoid GLAPIENTRY
1183bf215546Sopenharmony_ci_mesa_ReadnPixelsARB_no_error(GLint x, GLint y, GLsizei width, GLsizei height,
1184bf215546Sopenharmony_ci                              GLenum format, GLenum type, GLsizei bufSize,
1185bf215546Sopenharmony_ci                              GLvoid *pixels)
1186bf215546Sopenharmony_ci{
1187bf215546Sopenharmony_ci   read_pixels(x, y, width, height, format, type, bufSize, pixels, true);
1188bf215546Sopenharmony_ci}
1189bf215546Sopenharmony_ci
1190bf215546Sopenharmony_civoid GLAPIENTRY
1191bf215546Sopenharmony_ci_mesa_ReadnPixelsARB(GLint x, GLint y, GLsizei width, GLsizei height,
1192bf215546Sopenharmony_ci                     GLenum format, GLenum type, GLsizei bufSize,
1193bf215546Sopenharmony_ci                     GLvoid *pixels)
1194bf215546Sopenharmony_ci{
1195bf215546Sopenharmony_ci   read_pixels(x, y, width, height, format, type, bufSize, pixels, false);
1196bf215546Sopenharmony_ci}
1197bf215546Sopenharmony_ci
1198bf215546Sopenharmony_civoid GLAPIENTRY
1199bf215546Sopenharmony_ci_mesa_ReadPixels_no_error(GLint x, GLint y, GLsizei width, GLsizei height,
1200bf215546Sopenharmony_ci                          GLenum format, GLenum type, GLvoid *pixels)
1201bf215546Sopenharmony_ci{
1202bf215546Sopenharmony_ci   _mesa_ReadnPixelsARB_no_error(x, y, width, height, format, type, INT_MAX,
1203bf215546Sopenharmony_ci                                 pixels);
1204bf215546Sopenharmony_ci}
1205bf215546Sopenharmony_ci
1206bf215546Sopenharmony_civoid GLAPIENTRY
1207bf215546Sopenharmony_ci_mesa_ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
1208bf215546Sopenharmony_ci                 GLenum format, GLenum type, GLvoid *pixels)
1209bf215546Sopenharmony_ci{
1210bf215546Sopenharmony_ci   _mesa_ReadnPixelsARB(x, y, width, height, format, type, INT_MAX, pixels);
1211bf215546Sopenharmony_ci}
1212