[QMGRPRXY]
[reactos.git] / reactos / dll / opengl / mesa / main / readpix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <precomp.h>
26
27 /**
28 * Tries to implement glReadPixels() of GL_DEPTH_COMPONENT using memcpy of the
29 * mapping.
30 */
31 static GLboolean
32 fast_read_depth_pixels( struct gl_context *ctx,
33 GLint x, GLint y,
34 GLsizei width, GLsizei height,
35 GLenum type, GLvoid *pixels,
36 const struct gl_pixelstore_attrib *packing )
37 {
38 struct gl_framebuffer *fb = ctx->ReadBuffer;
39 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
40 GLubyte *map, *dst;
41 int stride, dstStride, j;
42
43 if (ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0)
44 return GL_FALSE;
45
46 if (packing->SwapBytes)
47 return GL_FALSE;
48
49 if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED)
50 return GL_FALSE;
51
52 if (!((type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16) ||
53 type == GL_UNSIGNED_INT))
54 return GL_FALSE;
55
56 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
57 &map, &stride);
58
59 if (!map) {
60 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
61 return GL_TRUE; /* don't bother trying the slow path */
62 }
63
64 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
65 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
66 GL_DEPTH_COMPONENT, type, 0, 0);
67
68 for (j = 0; j < height; j++) {
69 if (type == GL_UNSIGNED_INT) {
70 _mesa_unpack_uint_z_row(rb->Format, width, map, (GLuint *)dst);
71 } else {
72 ASSERT(type == GL_UNSIGNED_SHORT && rb->Format == MESA_FORMAT_Z16);
73 memcpy(dst, map, width * 2);
74 }
75
76 map += stride;
77 dst += dstStride;
78 }
79 ctx->Driver.UnmapRenderbuffer(ctx, rb);
80
81 return GL_TRUE;
82 }
83
84 /**
85 * Read pixels for format=GL_DEPTH_COMPONENT.
86 */
87 static void
88 read_depth_pixels( struct gl_context *ctx,
89 GLint x, GLint y,
90 GLsizei width, GLsizei height,
91 GLenum type, GLvoid *pixels,
92 const struct gl_pixelstore_attrib *packing )
93 {
94 struct gl_framebuffer *fb = ctx->ReadBuffer;
95 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
96 GLint j;
97 GLubyte *dst, *map;
98 int dstStride, stride;
99
100 if (!rb)
101 return;
102
103 /* clipping should have been done already */
104 ASSERT(x >= 0);
105 ASSERT(y >= 0);
106 ASSERT(x + width <= (GLint) rb->Width);
107 ASSERT(y + height <= (GLint) rb->Height);
108 /* width should never be > MAX_WIDTH since we did clipping earlier */
109 ASSERT(width <= MAX_WIDTH);
110
111 if (fast_read_depth_pixels(ctx, x, y, width, height, type, pixels, packing))
112 return;
113
114 dstStride = _mesa_image_row_stride(packing, width, GL_DEPTH_COMPONENT, type);
115 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
116 GL_DEPTH_COMPONENT, type, 0, 0);
117
118 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
119 &map, &stride);
120 if (!map) {
121 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
122 return;
123 }
124
125 /* General case (slower) */
126 for (j = 0; j < height; j++, y++) {
127 GLfloat depthValues[MAX_WIDTH];
128 _mesa_unpack_float_z_row(rb->Format, width, map, depthValues);
129 _mesa_pack_depth_span(ctx, width, dst, type, depthValues, packing);
130
131 dst += dstStride;
132 map += stride;
133 }
134
135 ctx->Driver.UnmapRenderbuffer(ctx, rb);
136 }
137
138
139 /**
140 * Read pixels for format=GL_STENCIL_INDEX.
141 */
142 static void
143 read_stencil_pixels( struct gl_context *ctx,
144 GLint x, GLint y,
145 GLsizei width, GLsizei height,
146 GLenum type, GLvoid *pixels,
147 const struct gl_pixelstore_attrib *packing )
148 {
149 struct gl_framebuffer *fb = ctx->ReadBuffer;
150 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
151 GLint j;
152 GLubyte *map;
153 GLint stride;
154
155 if (!rb)
156 return;
157
158 /* width should never be > MAX_WIDTH since we did clipping earlier */
159 ASSERT(width <= MAX_WIDTH);
160
161 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
162 &map, &stride);
163 if (!map) {
164 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
165 return;
166 }
167
168 /* process image row by row */
169 for (j = 0; j < height; j++) {
170 GLvoid *dest;
171 GLubyte stencil[MAX_WIDTH];
172
173 _mesa_unpack_ubyte_stencil_row(rb->Format, width, map, stencil);
174 dest = _mesa_image_address2d(packing, pixels, width, height,
175 GL_STENCIL_INDEX, type, j, 0);
176
177 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
178
179 map += stride;
180 }
181
182 ctx->Driver.UnmapRenderbuffer(ctx, rb);
183 }
184
185
186 /**
187 * Try to do glReadPixels of RGBA data using a simple memcpy or swizzle.
188 * \return GL_TRUE if successful, GL_FALSE otherwise (use the slow path)
189 */
190 static GLboolean
191 fast_read_rgba_pixels_memcpy( struct gl_context *ctx,
192 GLint x, GLint y,
193 GLsizei width, GLsizei height,
194 GLenum format, GLenum type,
195 GLvoid *pixels,
196 const struct gl_pixelstore_attrib *packing,
197 GLbitfield transferOps )
198 {
199 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
200 GLubyte *dst, *map;
201 int dstStride, stride, j, texelBytes;
202 GLboolean swizzle_rb = GL_FALSE, copy_xrgb = GL_FALSE;
203
204 /* XXX we could check for other swizzle/special cases here as needed */
205 if (rb->Format == MESA_FORMAT_RGBA8888_REV &&
206 format == GL_BGRA &&
207 type == GL_UNSIGNED_INT_8_8_8_8_REV) {
208 swizzle_rb = GL_TRUE;
209 }
210 else if (rb->Format == MESA_FORMAT_XRGB8888 &&
211 format == GL_BGRA &&
212 type == GL_UNSIGNED_INT_8_8_8_8_REV) {
213 copy_xrgb = GL_TRUE;
214 }
215 else if (!_mesa_format_matches_format_and_type(rb->Format, format, type))
216 return GL_FALSE;
217
218 /* check for things we can't handle here */
219 if (packing->SwapBytes) {
220 return GL_FALSE;
221 }
222
223 /* If the format is unsigned normalized then we can ignore clamping
224 * because the values are already in the range [0,1] so it won't
225 * have any effect anyway.
226 */
227 if (_mesa_get_format_datatype(rb->Format) == GL_UNSIGNED_NORMALIZED)
228 transferOps &= ~IMAGE_CLAMP_BIT;
229
230 if (transferOps)
231 return GL_FALSE;
232
233 dstStride = _mesa_image_row_stride(packing, width, format, type);
234 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
235 format, type, 0, 0);
236
237 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
238 &map, &stride);
239 if (!map) {
240 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
241 return GL_TRUE; /* don't bother trying the slow path */
242 }
243
244 texelBytes = _mesa_get_format_bytes(rb->Format);
245
246 if (swizzle_rb) {
247 /* swap R/B */
248 for (j = 0; j < height; j++) {
249 int i;
250 for (i = 0; i < width; i++) {
251 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
252 GLuint pixel = map4[i];
253 dst4[i] = (pixel & 0xff00ff00)
254 | ((pixel & 0x00ff0000) >> 16)
255 | ((pixel & 0x000000ff) << 16);
256 }
257 dst += dstStride;
258 map += stride;
259 }
260 } else if (copy_xrgb) {
261 /* convert xrgb -> argb */
262 for (j = 0; j < height; j++) {
263 GLuint *dst4 = (GLuint *) dst, *map4 = (GLuint *) map;
264 int i;
265 for (i = 0; i < width; i++) {
266 dst4[i] = map4[i] | 0xff000000; /* set A=0xff */
267 }
268 dst += dstStride;
269 map += stride;
270 }
271 } else {
272 /* just memcpy */
273 for (j = 0; j < height; j++) {
274 memcpy(dst, map, width * texelBytes);
275 dst += dstStride;
276 map += stride;
277 }
278 }
279
280 ctx->Driver.UnmapRenderbuffer(ctx, rb);
281
282 return GL_TRUE;
283 }
284
285 static void
286 slow_read_rgba_pixels( struct gl_context *ctx,
287 GLint x, GLint y,
288 GLsizei width, GLsizei height,
289 GLenum format, GLenum type,
290 GLvoid *pixels,
291 const struct gl_pixelstore_attrib *packing,
292 GLbitfield transferOps )
293 {
294 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
295 const gl_format rbFormat = rb->Format;
296 void *rgba;
297 GLubyte *dst, *map;
298 int dstStride, stride, j;
299
300 dstStride = _mesa_image_row_stride(packing, width, format, type);
301 dst = (GLubyte *) _mesa_image_address2d(packing, pixels, width, height,
302 format, type, 0, 0);
303
304 ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height, GL_MAP_READ_BIT,
305 &map, &stride);
306 if (!map) {
307 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
308 return;
309 }
310
311 rgba = malloc(width * MAX_PIXEL_BYTES);
312 if (!rgba)
313 goto done;
314
315 for (j = 0; j < height; j++) {
316 if (_mesa_is_integer_format(format)) {
317 _mesa_unpack_uint_rgba_row(rbFormat, width, map, (GLuint (*)[4]) rgba);
318 _mesa_rebase_rgba_uint(width, (GLuint (*)[4]) rgba,
319 rb->_BaseFormat);
320 _mesa_pack_rgba_span_int(ctx, width, (GLuint (*)[4]) rgba, format,
321 type, dst);
322 } else {
323 _mesa_unpack_rgba_row(rbFormat, width, map, (GLfloat (*)[4]) rgba);
324 _mesa_rebase_rgba_float(width, (GLfloat (*)[4]) rgba,
325 rb->_BaseFormat);
326 _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format,
327 type, dst, packing, transferOps);
328 }
329 dst += dstStride;
330 map += stride;
331 }
332
333 free(rgba);
334
335 done:
336 ctx->Driver.UnmapRenderbuffer(ctx, rb);
337 }
338
339 /*
340 * Read R, G, B, A, RGB, L, or LA pixels.
341 */
342 static void
343 read_rgba_pixels( struct gl_context *ctx,
344 GLint x, GLint y,
345 GLsizei width, GLsizei height,
346 GLenum format, GLenum type, GLvoid *pixels,
347 const struct gl_pixelstore_attrib *packing )
348 {
349 GLbitfield transferOps = ctx->_ImageTransferState;
350 struct gl_framebuffer *fb = ctx->ReadBuffer;
351 struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
352
353 if (!rb)
354 return;
355
356 if (!_mesa_is_integer_format(format)) {
357 transferOps |= IMAGE_CLAMP_BIT;
358 }
359
360 /* Try the optimized paths first. */
361 if (fast_read_rgba_pixels_memcpy(ctx, x, y, width, height,
362 format, type, pixels, packing,
363 transferOps)) {
364 return;
365 }
366
367 slow_read_rgba_pixels(ctx, x, y, width, height,
368 format, type, pixels, packing, transferOps);
369 }
370
371 /**
372 * Software fallback routine for ctx->Driver.ReadPixels().
373 * By time we get here, all error checking will have been done.
374 */
375 void
376 _mesa_readpixels(struct gl_context *ctx,
377 GLint x, GLint y, GLsizei width, GLsizei height,
378 GLenum format, GLenum type,
379 const struct gl_pixelstore_attrib *packing,
380 GLvoid *pixels)
381 {
382 struct gl_pixelstore_attrib clippedPacking = *packing;
383
384 if (ctx->NewState)
385 _mesa_update_state(ctx);
386
387 /* Do all needed clipping here, so that we can forget about it later */
388 if (_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
389
390 if (pixels) {
391 switch (format) {
392 case GL_STENCIL_INDEX:
393 read_stencil_pixels(ctx, x, y, width, height, type, pixels,
394 &clippedPacking);
395 break;
396 case GL_DEPTH_COMPONENT:
397 read_depth_pixels(ctx, x, y, width, height, type, pixels,
398 &clippedPacking);
399 break;
400 default:
401 /* all other formats should be color formats */
402 read_rgba_pixels(ctx, x, y, width, height, format, type, pixels,
403 &clippedPacking);
404 }
405 }
406 }
407 }
408
409
410 /**
411 * Do error checking of the format/type parameters to glReadPixels and
412 * glDrawPixels.
413 * \param drawing if GL_TRUE do checking for DrawPixels, else do checking
414 * for ReadPixels.
415 * \return GL_TRUE if error detected, GL_FALSE if no errors
416 */
417 GLboolean
418 _mesa_error_check_format_type(struct gl_context *ctx, GLenum format,
419 GLenum type, GLboolean drawing)
420 {
421 const char *readDraw = drawing ? "Draw" : "Read";
422 const GLboolean reading = !drawing;
423 GLenum err;
424
425 /* state validation should have already been done */
426 ASSERT(ctx->NewState == 0x0);
427
428 /* basic combinations test */
429 err = _mesa_error_check_format_and_type(ctx, format, type);
430 if (err != GL_NO_ERROR) {
431 _mesa_error(ctx, err, "gl%sPixels(format or type)", readDraw);
432 return GL_TRUE;
433 }
434
435 /* additional checks */
436 switch (format) {
437 case GL_RG:
438 case GL_RED:
439 case GL_GREEN:
440 case GL_BLUE:
441 case GL_ALPHA:
442 case GL_LUMINANCE:
443 case GL_LUMINANCE_ALPHA:
444 case GL_RGB:
445 case GL_BGR:
446 case GL_RGBA:
447 case GL_BGRA:
448 case GL_ABGR_EXT:
449 case GL_RED_INTEGER_EXT:
450 case GL_GREEN_INTEGER_EXT:
451 case GL_BLUE_INTEGER_EXT:
452 case GL_ALPHA_INTEGER_EXT:
453 case GL_RGB_INTEGER_EXT:
454 case GL_RGBA_INTEGER_EXT:
455 case GL_BGR_INTEGER_EXT:
456 case GL_BGRA_INTEGER_EXT:
457 case GL_LUMINANCE_INTEGER_EXT:
458 case GL_LUMINANCE_ALPHA_INTEGER_EXT:
459 if (!drawing) {
460 /* reading */
461 if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) {
462 _mesa_error(ctx, GL_INVALID_OPERATION,
463 "glReadPixels(no color buffer)");
464 return GL_TRUE;
465 }
466 }
467 break;
468 case GL_COLOR_INDEX:
469 if (drawing) {
470 if (ctx->PixelMaps.ItoR.Size == 0 ||
471 ctx->PixelMaps.ItoG.Size == 0 ||
472 ctx->PixelMaps.ItoB.Size == 0) {
473 _mesa_error(ctx, GL_INVALID_OPERATION,
474 "glDrawPixels(drawing color index pixels into RGB buffer)");
475 return GL_TRUE;
476 }
477 }
478 else {
479 /* reading */
480 if (!_mesa_source_buffer_exists(ctx, GL_COLOR)) {
481 _mesa_error(ctx, GL_INVALID_OPERATION,
482 "glReadPixels(no color buffer)");
483 return GL_TRUE;
484 }
485 /* We no longer support CI-mode color buffers so trying to read
486 * GL_COLOR_INDEX pixels is always an error.
487 */
488 _mesa_error(ctx, GL_INVALID_OPERATION,
489 "glReadPixels(color buffer is RGB)");
490 return GL_TRUE;
491 }
492 break;
493 case GL_STENCIL_INDEX:
494 if ((drawing && !_mesa_dest_buffer_exists(ctx, format)) ||
495 (reading && !_mesa_source_buffer_exists(ctx, format))) {
496 _mesa_error(ctx, GL_INVALID_OPERATION,
497 "gl%sPixels(no stencil buffer)", readDraw);
498 return GL_TRUE;
499 }
500 break;
501 case GL_DEPTH_COMPONENT:
502 if ((drawing && !_mesa_dest_buffer_exists(ctx, format))) {
503 _mesa_error(ctx, GL_INVALID_OPERATION,
504 "gl%sPixels(no depth buffer)", readDraw);
505 return GL_TRUE;
506 }
507 break;
508 default:
509 /* this should have been caught in _mesa_error_check_format_type() */
510 _mesa_problem(ctx, "unexpected format in _mesa_%sPixels", readDraw);
511 return GL_TRUE;
512 }
513
514 /* no errors */
515 return GL_FALSE;
516 }
517
518
519
520 void GLAPIENTRY
521 _mesa_ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
522 GLenum format, GLenum type, GLvoid *pixels )
523 {
524 GET_CURRENT_CONTEXT(ctx);
525 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
526
527 FLUSH_CURRENT(ctx, 0);
528
529 if (MESA_VERBOSE & VERBOSE_API)
530 _mesa_debug(ctx, "glReadPixels(%d, %d, %s, %s, %p)\n",
531 width, height,
532 _mesa_lookup_enum_by_nr(format),
533 _mesa_lookup_enum_by_nr(type),
534 pixels);
535
536 if (width < 0 || height < 0) {
537 _mesa_error( ctx, GL_INVALID_VALUE,
538 "glReadPixels(width=%d height=%d)", width, height );
539 return;
540 }
541
542 if (ctx->NewState)
543 _mesa_update_state(ctx);
544
545 if (_mesa_error_check_format_type(ctx, format, type, GL_FALSE)) {
546 /* found an error */
547 return;
548 }
549
550 /* Check that the destination format and source buffer are both
551 * integer-valued or both non-integer-valued.
552 */
553 if (ctx->Extensions.EXT_texture_integer && _mesa_is_color_format(format)) {
554 const struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
555 const GLboolean srcInteger = _mesa_is_format_integer_color(rb->Format);
556 const GLboolean dstInteger = _mesa_is_integer_format(format);
557 if (dstInteger != srcInteger) {
558 _mesa_error(ctx, GL_INVALID_OPERATION,
559 "glReadPixels(integer / non-integer format mismatch");
560 return;
561 }
562 }
563
564 if (!_mesa_source_buffer_exists(ctx, format)) {
565 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(no readbuffer)");
566 return;
567 }
568
569 if (width == 0 || height == 0)
570 return; /* nothing to do */
571
572 ctx->Driver.ReadPixels(ctx, x, y, width, height,
573 format, type, &ctx->Pack, pixels);
574 }