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