9e80908ba1f40dc86f1d5f2ab7a185e19ba7c566
[mesa.git] / src / mesa / swrast / s_readpix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2005 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
26 #include "glheader.h"
27 #include "bufferobj.h"
28 #include "colormac.h"
29 #include "convolve.h"
30 #include "context.h"
31 #include "feedback.h"
32 #include "image.h"
33 #include "macros.h"
34 #include "imports.h"
35 #include "pixel.h"
36
37 #include "s_context.h"
38 #include "s_depth.h"
39 #include "s_span.h"
40 #include "s_stencil.h"
41
42
43
44 /*
45 * Read a block of color index pixels.
46 */
47 static void
48 read_index_pixels( GLcontext *ctx,
49 GLint x, GLint y,
50 GLsizei width, GLsizei height,
51 GLenum type, GLvoid *pixels,
52 const struct gl_pixelstore_attrib *packing )
53 {
54 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
55 GLint i;
56
57 /* error checking */
58 if (ctx->Visual.rgbMode) {
59 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
60 return;
61 }
62
63 if (type != GL_BYTE &&
64 type != GL_UNSIGNED_BYTE &&
65 type != GL_SHORT &&
66 type != GL_UNSIGNED_SHORT &&
67 type != GL_INT &&
68 type != GL_UNSIGNED_INT &&
69 type != GL_FLOAT) {
70 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(index type)");
71 return;
72 }
73
74 if (!rb) {
75 return; /* no readbuffer OK */
76 }
77
78 /* width should never be > MAX_WIDTH since we did clipping earlier */
79 ASSERT(width <= MAX_WIDTH);
80
81 /* process image row by row */
82 for (i = 0; i < height; i++) {
83 GLuint index[MAX_WIDTH];
84 GLvoid *dest;
85 ASSERT(rb->DataType == GL_UNSIGNED_INT);
86 rb->GetRow(ctx, rb, width, x, y + i, index);
87
88 dest = _mesa_image_address2d(packing, pixels, width, height,
89 GL_COLOR_INDEX, type, i, 0);
90
91 _mesa_pack_index_span(ctx, width, type, dest, index,
92 &ctx->Pack, ctx->_ImageTransferState);
93 }
94 }
95
96
97
98 /**
99 * Read pixels for format=GL_DEPTH_COMPONENT.
100 */
101 static void
102 read_depth_pixels( GLcontext *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 GLboolean bias_or_scale;
111
112 /* clipping should have been done already */
113 ASSERT(x >= 0);
114 ASSERT(y >= 0);
115 ASSERT(x + width <= rb->Width);
116 ASSERT(y + height <= rb->Height);
117 /* width should never be > MAX_WIDTH since we did clipping earlier */
118 ASSERT(width <= MAX_WIDTH);
119
120 /* Error checking */
121 if (fb->Visual.depthBits <= 0) {
122 /* No depth buffer */
123 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
124 return;
125 }
126
127 if (type != GL_BYTE &&
128 type != GL_UNSIGNED_BYTE &&
129 type != GL_SHORT &&
130 type != GL_UNSIGNED_SHORT &&
131 type != GL_INT &&
132 type != GL_UNSIGNED_INT &&
133 type != GL_FLOAT) {
134 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
135 return;
136 }
137
138 if (!rb) {
139 return; /* no readbuffer OK */
140 }
141
142 bias_or_scale = ctx->Pixel.DepthBias != 0.0 || ctx->Pixel.DepthScale != 1.0;
143
144 if (type == GL_UNSIGNED_SHORT && fb->Visual.depthBits == 16
145 && !bias_or_scale && !packing->SwapBytes) {
146 /* Special case: directly read 16-bit unsigned depth values. */
147 GLint j;
148 ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT16);
149 ASSERT(rb->DataType == GL_UNSIGNED_SHORT);
150 for (j = 0; j < height; j++, y++) {
151 void *dest =_mesa_image_address2d(packing, pixels, width, height,
152 GL_DEPTH_COMPONENT, type, j, 0);
153 rb->GetRow(ctx, rb, width, x, y, dest);
154 }
155 }
156 else if (type == GL_UNSIGNED_INT && fb->Visual.depthBits == 32
157 && !bias_or_scale && !packing->SwapBytes) {
158 /* Special case: directly read 32-bit unsigned depth values. */
159 GLint j;
160 ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT32);
161 ASSERT(rb->DataType == GL_UNSIGNED_INT);
162 for (j = 0; j < height; j++, y++) {
163 void *dest = _mesa_image_address2d(packing, pixels, width, height,
164 GL_DEPTH_COMPONENT, type, j, 0);
165 rb->GetRow(ctx, rb, width, x, y, dest);
166 }
167 }
168 else {
169 /* General case (slower) */
170 GLint j;
171 for (j = 0; j < height; j++, y++) {
172 GLfloat depthValues[MAX_WIDTH];
173 GLvoid *dest = _mesa_image_address2d(packing, pixels, width, height,
174 GL_DEPTH_COMPONENT, type, j, 0);
175 _swrast_read_depth_span_float(ctx, rb, width, x, y, depthValues);
176 _mesa_pack_depth_span(ctx, width, dest, type, depthValues, packing);
177 }
178 }
179 }
180
181
182 /**
183 * Read pixels for format=GL_STENCIL_INDEX.
184 */
185 static void
186 read_stencil_pixels( GLcontext *ctx,
187 GLint x, GLint y,
188 GLsizei width, GLsizei height,
189 GLenum type, GLvoid *pixels,
190 const struct gl_pixelstore_attrib *packing )
191 {
192 struct gl_framebuffer *fb = ctx->ReadBuffer;
193 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
194 GLint j;
195
196 if (!rb) {
197 /* no readbuffer - OK */
198 return;
199 }
200
201 if (type != GL_BYTE &&
202 type != GL_UNSIGNED_BYTE &&
203 type != GL_SHORT &&
204 type != GL_UNSIGNED_SHORT &&
205 type != GL_INT &&
206 type != GL_UNSIGNED_INT &&
207 type != GL_FLOAT &&
208 type != GL_BITMAP) {
209 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(stencil type)");
210 return;
211 }
212
213 if (fb->Visual.stencilBits <= 0) {
214 /* No stencil buffer */
215 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
216 return;
217 }
218
219 /* width should never be > MAX_WIDTH since we did clipping earlier */
220 ASSERT(width <= MAX_WIDTH);
221
222 /* process image row by row */
223 for (j=0;j<height;j++,y++) {
224 GLvoid *dest;
225 GLstencil stencil[MAX_WIDTH];
226
227 _swrast_read_stencil_span(ctx, rb, width, x, y, stencil);
228
229 dest = _mesa_image_address2d(packing, pixels, width, height,
230 GL_STENCIL_INDEX, type, j, 0);
231
232 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
233 }
234 }
235
236
237
238 /**
239 * Optimized glReadPixels for particular pixel formats:
240 * GL_UNSIGNED_BYTE, GL_RGBA
241 * when pixel scaling, biasing and mapping are disabled.
242 */
243 static GLboolean
244 read_fast_rgba_pixels( GLcontext *ctx,
245 GLint x, GLint y,
246 GLsizei width, GLsizei height,
247 GLenum format, GLenum type,
248 GLvoid *pixels,
249 const struct gl_pixelstore_attrib *packing )
250 {
251 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
252
253 /* can't do scale, bias, mapping, etc */
254 if (ctx->_ImageTransferState)
255 return GL_FALSE;
256
257 /* can't do fancy pixel packing */
258 if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
259 return GL_FALSE;
260
261 {
262 GLint srcX = x;
263 GLint srcY = y;
264 GLint readWidth = width; /* actual width read */
265 GLint readHeight = height; /* actual height read */
266 GLint skipPixels = packing->SkipPixels;
267 GLint skipRows = packing->SkipRows;
268 GLint rowLength;
269
270 if (packing->RowLength > 0)
271 rowLength = packing->RowLength;
272 else
273 rowLength = width;
274
275 /*
276 * Ready to read!
277 * The window region at (destX, destY) of size (readWidth, readHeight)
278 * will be read back.
279 * We'll write pixel data to buffer pointed to by "pixels" but we'll
280 * skip "skipRows" rows and skip "skipPixels" pixels/row.
281 */
282 #if CHAN_BITS == 8
283 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
284 #elif CHAN_BITS == 16
285 if (format == GL_RGBA && type == GL_UNSIGNED_SHORT) {
286 #else
287 if (0) {
288 #endif
289 GLchan *dest = (GLchan *) pixels
290 + (skipRows * rowLength + skipPixels) * 4;
291 GLint row;
292
293 if (packing->Invert) {
294 /* start at top and go down */
295 dest += (readHeight - 1) * rowLength * 4;
296 rowLength = -rowLength;
297 }
298
299 ASSERT(rb->GetRow);
300 for (row=0; row<readHeight; row++) {
301 rb->GetRow(ctx, rb, readWidth, srcX, srcY, dest);
302 dest += rowLength * 4;
303 srcY++;
304 }
305 return GL_TRUE;
306 }
307 else {
308 /* can't do this format/type combination */
309 return GL_FALSE;
310 }
311 }
312 }
313
314
315
316 /*
317 * Read R, G, B, A, RGB, L, or LA pixels.
318 */
319 static void
320 read_rgba_pixels( GLcontext *ctx,
321 GLint x, GLint y,
322 GLsizei width, GLsizei height,
323 GLenum format, GLenum type, GLvoid *pixels,
324 const struct gl_pixelstore_attrib *packing )
325 {
326 struct gl_framebuffer *fb = ctx->ReadBuffer;
327 struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
328
329 if (!rb) {
330 /* No readbuffer is OK with GL_EXT_framebuffer_object */
331 return;
332 }
333
334 /* do error checking on pixel type, format was already checked by caller */
335 switch (type) {
336 case GL_UNSIGNED_BYTE:
337 case GL_BYTE:
338 case GL_UNSIGNED_SHORT:
339 case GL_SHORT:
340 case GL_UNSIGNED_INT:
341 case GL_INT:
342 case GL_FLOAT:
343 case GL_UNSIGNED_BYTE_3_3_2:
344 case GL_UNSIGNED_BYTE_2_3_3_REV:
345 case GL_UNSIGNED_SHORT_5_6_5:
346 case GL_UNSIGNED_SHORT_5_6_5_REV:
347 case GL_UNSIGNED_SHORT_4_4_4_4:
348 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
349 case GL_UNSIGNED_SHORT_5_5_5_1:
350 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
351 case GL_UNSIGNED_INT_8_8_8_8:
352 case GL_UNSIGNED_INT_8_8_8_8_REV:
353 case GL_UNSIGNED_INT_10_10_10_2:
354 case GL_UNSIGNED_INT_2_10_10_10_REV:
355 /* valid pixel type */
356 break;
357 case GL_HALF_FLOAT_ARB:
358 if (!ctx->Extensions.ARB_half_float_pixel) {
359 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
360 return;
361 }
362 break;
363 default:
364 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
365 return;
366 }
367
368 if (!_mesa_is_legal_format_and_type(ctx, format, type) ||
369 format == GL_INTENSITY) {
370 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
371 return;
372 }
373
374 /* Try optimized path first */
375 if (read_fast_rgba_pixels( ctx, x, y, width, height,
376 format, type, pixels, packing )) {
377 return; /* done! */
378 }
379
380 /* width should never be > MAX_WIDTH since we did clipping earlier */
381 ASSERT(width <= MAX_WIDTH);
382
383 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
384 const GLuint transferOps = ctx->_ImageTransferState;
385 GLfloat *dest, *src, *tmpImage, *convImage;
386 GLint row;
387
388 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
389 if (!tmpImage) {
390 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
391 return;
392 }
393 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
394 if (!convImage) {
395 _mesa_free(tmpImage);
396 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
397 return;
398 }
399
400 /* read full RGBA, FLOAT image */
401 dest = tmpImage;
402 for (row = 0; row < height; row++, y++) {
403 GLchan rgba[MAX_WIDTH][4];
404 if (fb->Visual.rgbMode) {
405 _swrast_read_rgba_span(ctx, rb, width, x, y, rgba);
406 }
407 else {
408 GLuint index[MAX_WIDTH];
409 ASSERT(rb->DataType == GL_UNSIGNED_INT);
410 rb->GetRow(ctx, rb, width, x, y, index);
411 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
412 _mesa_map_ci(ctx, width, index);
413 }
414 _mesa_map_ci_to_rgba_chan(ctx, width, index, rgba);
415 }
416 _mesa_pack_rgba_span_chan(ctx, width, (const GLchan (*)[4]) rgba,
417 GL_RGBA, GL_FLOAT, dest, &ctx->DefaultPacking,
418 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
419 dest += width * 4;
420 }
421
422 /* do convolution */
423 if (ctx->Pixel.Convolution2DEnabled) {
424 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
425 }
426 else {
427 ASSERT(ctx->Pixel.Separable2DEnabled);
428 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
429 }
430 _mesa_free(tmpImage);
431
432 /* finish transfer ops and pack the resulting image */
433 src = convImage;
434 for (row = 0; row < height; row++) {
435 GLvoid *dest;
436 dest = _mesa_image_address2d(packing, pixels, width, height,
437 format, type, row, 0);
438 _mesa_pack_rgba_span_float(ctx, width,
439 (const GLfloat (*)[4]) src,
440 format, type, dest, packing,
441 transferOps & IMAGE_POST_CONVOLUTION_BITS);
442 src += width * 4;
443 }
444 }
445 else {
446 /* no convolution */
447 GLint row;
448 for (row = 0; row < height; row++, y++) {
449 GLchan rgba[MAX_WIDTH][4];
450 GLvoid *dst;
451 if (fb->Visual.rgbMode) {
452 _swrast_read_rgba_span(ctx, rb, width, x, y, rgba);
453 }
454 else {
455 GLuint index[MAX_WIDTH];
456 ASSERT(rb->DataType == GL_UNSIGNED_INT);
457 rb->GetRow(ctx, rb, width, x, y, index);
458 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
459 _mesa_map_ci(ctx, width, index);
460 }
461 _mesa_map_ci_to_rgba_chan(ctx, width, index, rgba);
462 }
463 dst = _mesa_image_address2d(packing, pixels, width, height,
464 format, type, row, 0);
465 if (fb->Visual.redBits < CHAN_BITS ||
466 fb->Visual.greenBits < CHAN_BITS ||
467 fb->Visual.blueBits < CHAN_BITS) {
468 /* Requantize the color values into floating point and go from
469 * there. This fixes conformance failures with 16-bit color
470 * buffers, for example.
471 */
472 GLfloat rgbaf[MAX_WIDTH][4];
473 _mesa_chan_to_float_span(ctx, width,
474 (CONST GLchan (*)[4]) rgba, rgbaf);
475 _mesa_pack_rgba_span_float(ctx, width,
476 (CONST GLfloat (*)[4]) rgbaf,
477 format, type, dst, packing,
478 ctx->_ImageTransferState);
479 }
480 else {
481 /* GLubytes are fine */
482 _mesa_pack_rgba_span_chan(ctx, width, (CONST GLchan (*)[4]) rgba,
483 format, type, dst, packing,
484 ctx->_ImageTransferState);
485 }
486 }
487 }
488 }
489
490
491 /**
492 * Software fallback routine for ctx->Driver.ReadPixels().
493 * We wind up using the swrast->ReadSpan() routines to do the job.
494 */
495 void
496 _swrast_ReadPixels( GLcontext *ctx,
497 GLint x, GLint y, GLsizei width, GLsizei height,
498 GLenum format, GLenum type,
499 const struct gl_pixelstore_attrib *packing,
500 GLvoid *pixels )
501 {
502 SWcontext *swrast = SWRAST_CONTEXT(ctx);
503 struct gl_pixelstore_attrib clippedPacking;
504
505 if (swrast->NewState)
506 _swrast_validate_derived( ctx );
507
508 /* Do all needed clipping here, so that we can forget about it later */
509 clippedPacking = *packing;
510 if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height,
511 &clippedPacking.SkipPixels,
512 &clippedPacking.SkipRows)) {
513 /* The ReadPixels region is totally outside the window bounds */
514 return;
515 }
516
517 if (clippedPacking.BufferObj->Name) {
518 /* pack into PBO */
519 GLubyte *buf;
520 if (!_mesa_validate_pbo_access(2, &clippedPacking, width, height, 1,
521 format, type, pixels)) {
522 _mesa_error(ctx, GL_INVALID_OPERATION,
523 "glReadPixels(invalid PBO access)");
524 return;
525 }
526 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
527 GL_WRITE_ONLY_ARB,
528 clippedPacking.BufferObj);
529 if (!buf) {
530 /* buffer is already mapped - that's an error */
531 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
532 return;
533 }
534 pixels = ADD_POINTERS(buf, pixels);
535 }
536
537 RENDER_START(swrast, ctx);
538
539 switch (format) {
540 case GL_COLOR_INDEX:
541 read_index_pixels(ctx, x, y, width, height, type, pixels,
542 &clippedPacking);
543 break;
544 case GL_STENCIL_INDEX:
545 read_stencil_pixels(ctx, x, y, width, height, type, pixels,
546 &clippedPacking);
547 break;
548 case GL_DEPTH_COMPONENT:
549 read_depth_pixels(ctx, x, y, width, height, type, pixels,
550 &clippedPacking);
551 break;
552 case GL_RED:
553 case GL_GREEN:
554 case GL_BLUE:
555 case GL_ALPHA:
556 case GL_RGB:
557 case GL_LUMINANCE:
558 case GL_LUMINANCE_ALPHA:
559 case GL_RGBA:
560 case GL_BGR:
561 case GL_BGRA:
562 case GL_ABGR_EXT:
563 read_rgba_pixels(ctx, x, y, width, height,
564 format, type, pixels, &clippedPacking);
565 break;
566 default:
567 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
568 /* don't return yet, clean-up */
569 }
570
571 RENDER_FINISH(swrast, ctx);
572
573 if (clippedPacking.BufferObj->Name) {
574 /* done with PBO so unmap it now */
575 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
576 clippedPacking.BufferObj);
577 }
578 }