61ad2c252ea51f9fd4921000709defc166f6763f
[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 /*
56 SWcontext *swrast = SWRAST_CONTEXT(ctx);
57 */
58 GLint i, readWidth;
59
60 /* error checking */
61 if (ctx->Visual.rgbMode) {
62 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
63 return;
64 }
65
66 if (type != GL_BYTE &&
67 type != GL_UNSIGNED_BYTE &&
68 type != GL_SHORT &&
69 type != GL_UNSIGNED_SHORT &&
70 type != GL_INT &&
71 type != GL_UNSIGNED_INT &&
72 type != GL_FLOAT) {
73 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(index type)");
74 return;
75 }
76
77 /* XXX: width should never be > MAX_WIDTH since we did clipping earlier */
78 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
79
80 /* process image row by row */
81 for (i = 0; i < height; i++) {
82 GLuint index[MAX_WIDTH];
83 GLvoid *dest;
84 ASSERT(rb->DataType == GL_UNSIGNED_INT);
85 rb->GetRow(ctx, rb, readWidth, x, y + i, index);
86
87 dest = _mesa_image_address2d(packing, pixels, width, height,
88 GL_COLOR_INDEX, type, i, 0);
89
90 _mesa_pack_index_span(ctx, readWidth, type, dest, index,
91 &ctx->Pack, ctx->_ImageTransferState);
92 }
93 }
94
95
96
97 /**
98 * Read pixels for format=GL_DEPTH_COMPONENT.
99 */
100 static void
101 read_depth_pixels( GLcontext *ctx,
102 GLint x, GLint y,
103 GLsizei width, GLsizei height,
104 GLenum type, GLvoid *pixels,
105 const struct gl_pixelstore_attrib *packing )
106 {
107 struct gl_renderbuffer *rb
108 = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
109 GLint readWidth;
110 GLboolean bias_or_scale;
111
112 if (!rb) {
113 /* no readbuffer - OK */
114 return;
115 }
116
117 /* Error checking */
118 if (ctx->Visual.depthBits <= 0) {
119 /* No depth buffer */
120 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
121 return;
122 }
123
124 if (type != GL_BYTE &&
125 type != GL_UNSIGNED_BYTE &&
126 type != GL_SHORT &&
127 type != GL_UNSIGNED_SHORT &&
128 type != GL_INT &&
129 type != GL_UNSIGNED_INT &&
130 type != GL_FLOAT) {
131 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
132 return;
133 }
134
135 /* XXX: width should never be > MAX_WIDTH since we did clipping earlier */
136 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
137
138 bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
139
140 if (type==GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16
141 && !bias_or_scale && !packing->SwapBytes) {
142 /* Special case: directly read 16-bit unsigned depth values. */
143 GLint j;
144 for (j=0;j<height;j++,y++) {
145 GLdepth depth[MAX_WIDTH];
146 GLushort *dst = (GLushort*) _mesa_image_address2d(packing, pixels,
147 width, height, GL_DEPTH_COMPONENT, type, j, 0);
148 GLint i;
149 _swrast_read_depth_span(ctx, rb, width, x, y, depth);
150 for (i = 0; i < width; i++)
151 dst[i] = depth[i];
152 }
153 }
154 else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
155 && !bias_or_scale && !packing->SwapBytes) {
156 /* Special case: directly read 32-bit unsigned depth values. */
157 GLint j;
158 for (j=0;j<height;j++,y++) {
159 GLdepth *dst = (GLdepth *) _mesa_image_address2d(packing, pixels,
160 width, height, GL_DEPTH_COMPONENT, type, j, 0);
161 _swrast_read_depth_span(ctx, rb, width, x, y, dst);
162 }
163 }
164 else {
165 /* General case (slower) */
166 GLint j;
167 for (j=0;j<height;j++,y++) {
168 GLfloat depth[MAX_WIDTH];
169 GLvoid *dest;
170
171 _swrast_read_depth_span_float(ctx, rb, readWidth, x, y, depth);
172
173 dest = _mesa_image_address2d(packing, pixels, width, height,
174 GL_DEPTH_COMPONENT, type, j, 0);
175
176 _mesa_pack_depth_span(ctx, readWidth, (GLdepth *) dest, type,
177 depth, packing);
178 }
179 }
180 }
181
182
183 /**
184 * Read pixels for format=GL_STENCIL_INDEX.
185 */
186 static void
187 read_stencil_pixels( GLcontext *ctx,
188 GLint x, GLint y,
189 GLsizei width, GLsizei height,
190 GLenum type, GLvoid *pixels,
191 const struct gl_pixelstore_attrib *packing )
192 {
193 struct gl_renderbuffer *rb
194 = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
195 GLint j, readWidth;
196
197 if (!rb) {
198 /* no readbuffer - OK */
199 return;
200 }
201
202 if (type != GL_BYTE &&
203 type != GL_UNSIGNED_BYTE &&
204 type != GL_SHORT &&
205 type != GL_UNSIGNED_SHORT &&
206 type != GL_INT &&
207 type != GL_UNSIGNED_INT &&
208 type != GL_FLOAT &&
209 type != GL_BITMAP) {
210 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(stencil type)");
211 return;
212 }
213
214 if (ctx->Visual.stencilBits <= 0) {
215 /* No stencil buffer */
216 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
217 return;
218 }
219
220 /* XXX: width should never be > MAX_WIDTH since we did clipping earlier */
221 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
222
223 /* process image row by row */
224 for (j=0;j<height;j++,y++) {
225 GLvoid *dest;
226 GLstencil stencil[MAX_WIDTH];
227
228 _swrast_read_stencil_span(ctx, rb, readWidth, x, y, stencil);
229
230 dest = _mesa_image_address2d(packing, pixels, width, height,
231 GL_STENCIL_INDEX, type, j, 0);
232
233 _mesa_pack_stencil_span(ctx, readWidth, type, dest, stencil, packing);
234 }
235 }
236
237
238
239 /**
240 * Optimized glReadPixels for particular pixel formats:
241 * GL_UNSIGNED_BYTE, GL_RGBA
242 * when pixel scaling, biasing and mapping are disabled.
243 */
244 static GLboolean
245 read_fast_rgba_pixels( GLcontext *ctx,
246 GLint x, GLint y,
247 GLsizei width, GLsizei height,
248 GLenum format, GLenum type,
249 GLvoid *pixels,
250 const struct gl_pixelstore_attrib *packing )
251 {
252 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
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_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
327 /*
328 SWcontext *swrast = SWRAST_CONTEXT(ctx);
329 */
330 GLint readWidth;
331
332 if (!rb) {
333 /* No readbuffer is OK with GL_EXT_framebuffer_object */
334 return;
335 }
336
337 /* do error checking on pixel type, format was already checked by caller */
338 switch (type) {
339 case GL_UNSIGNED_BYTE:
340 case GL_BYTE:
341 case GL_UNSIGNED_SHORT:
342 case GL_SHORT:
343 case GL_UNSIGNED_INT:
344 case GL_INT:
345 case GL_FLOAT:
346 case GL_UNSIGNED_BYTE_3_3_2:
347 case GL_UNSIGNED_BYTE_2_3_3_REV:
348 case GL_UNSIGNED_SHORT_5_6_5:
349 case GL_UNSIGNED_SHORT_5_6_5_REV:
350 case GL_UNSIGNED_SHORT_4_4_4_4:
351 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
352 case GL_UNSIGNED_SHORT_5_5_5_1:
353 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
354 case GL_UNSIGNED_INT_8_8_8_8:
355 case GL_UNSIGNED_INT_8_8_8_8_REV:
356 case GL_UNSIGNED_INT_10_10_10_2:
357 case GL_UNSIGNED_INT_2_10_10_10_REV:
358 /* valid pixel type */
359 break;
360 case GL_HALF_FLOAT_ARB:
361 if (!ctx->Extensions.ARB_half_float_pixel) {
362 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
363 return;
364 }
365 break;
366 default:
367 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
368 return;
369 }
370
371 if (!_mesa_is_legal_format_and_type(ctx, format, type) ||
372 format == GL_INTENSITY) {
373 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
374 return;
375 }
376
377 /* Try optimized path first */
378 if (read_fast_rgba_pixels( ctx, x, y, width, height,
379 format, type, pixels, packing )) {
380 return; /* done! */
381 }
382
383 /* XXX: width should never be > MAX_WIDTH since we did clipping earlier */
384 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
385
386
387 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
388 const GLuint transferOps = ctx->_ImageTransferState;
389 GLfloat *dest, *src, *tmpImage, *convImage;
390 GLint row;
391
392 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
393 if (!tmpImage) {
394 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
395 return;
396 }
397 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
398 if (!convImage) {
399 _mesa_free(tmpImage);
400 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
401 return;
402 }
403
404 /* read full RGBA, FLOAT image */
405 dest = tmpImage;
406 for (row = 0; row < height; row++, y++) {
407 GLchan rgba[MAX_WIDTH][4];
408 if (ctx->Visual.rgbMode) {
409 _swrast_read_rgba_span(ctx, rb, readWidth, x, y, rgba);
410 }
411 else {
412 GLuint index[MAX_WIDTH];
413 ASSERT(rb->DataType == GL_UNSIGNED_INT);
414 rb->GetRow(ctx, rb, readWidth, x, y, index);
415 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
416 _mesa_map_ci(ctx, readWidth, index);
417 }
418 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
419 }
420 _mesa_pack_rgba_span_chan(ctx, readWidth, (const GLchan (*)[4]) rgba,
421 GL_RGBA, GL_FLOAT, dest, &ctx->DefaultPacking,
422 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
423 dest += width * 4;
424 }
425
426 /* do convolution */
427 if (ctx->Pixel.Convolution2DEnabled) {
428 _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
429 }
430 else {
431 ASSERT(ctx->Pixel.Separable2DEnabled);
432 _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
433 }
434 _mesa_free(tmpImage);
435
436 /* finish transfer ops and pack the resulting image */
437 src = convImage;
438 for (row = 0; row < height; row++) {
439 GLvoid *dest;
440 dest = _mesa_image_address2d(packing, pixels, readWidth, height,
441 format, type, row, 0);
442 _mesa_pack_rgba_span_float(ctx, readWidth,
443 (const GLfloat (*)[4]) src,
444 format, type, dest, packing,
445 transferOps & IMAGE_POST_CONVOLUTION_BITS);
446 src += readWidth * 4;
447 }
448 }
449 else {
450 /* no convolution */
451 GLint row;
452 for (row = 0; row < height; row++, y++) {
453 GLchan rgba[MAX_WIDTH][4];
454 GLvoid *dst;
455 if (ctx->Visual.rgbMode) {
456 _swrast_read_rgba_span(ctx, rb, readWidth, x, y, rgba);
457 }
458 else {
459 GLuint index[MAX_WIDTH];
460 ASSERT(rb->DataType == GL_UNSIGNED_INT);
461 rb->GetRow(ctx, rb, readWidth, x, y, index);
462 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
463 _mesa_map_ci(ctx, readWidth, index);
464 }
465 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
466 }
467 dst = _mesa_image_address2d(packing, pixels, width, height,
468 format, type, row, 0);
469 if (ctx->Visual.redBits < CHAN_BITS ||
470 ctx->Visual.greenBits < CHAN_BITS ||
471 ctx->Visual.blueBits < CHAN_BITS) {
472 /* Requantize the color values into floating point and go from
473 * there. This fixes conformance failures with 16-bit color
474 * buffers, for example.
475 */
476 GLfloat rgbaf[MAX_WIDTH][4];
477 _mesa_chan_to_float_span(ctx, readWidth,
478 (CONST GLchan (*)[4]) rgba, rgbaf);
479 _mesa_pack_rgba_span_float(ctx, readWidth,
480 (CONST GLfloat (*)[4]) rgbaf,
481 format, type, dst, packing,
482 ctx->_ImageTransferState);
483 }
484 else {
485 /* GLubytes are fine */
486 _mesa_pack_rgba_span_chan(ctx, readWidth, (CONST GLchan (*)[4]) rgba,
487 format, type, dst, packing,
488 ctx->_ImageTransferState);
489 }
490 }
491 }
492 }
493
494
495 /**
496 * Software fallback routine for ctx->Driver.ReadPixels().
497 * We wind up using the swrast->ReadSpan() routines to do the job.
498 */
499 void
500 _swrast_ReadPixels( GLcontext *ctx,
501 GLint x, GLint y, GLsizei width, GLsizei height,
502 GLenum format, GLenum type,
503 const struct gl_pixelstore_attrib *packing,
504 GLvoid *pixels )
505 {
506 SWcontext *swrast = SWRAST_CONTEXT(ctx);
507 struct gl_pixelstore_attrib clippedPacking;
508
509 if (swrast->NewState)
510 _swrast_validate_derived( ctx );
511
512 /* Do all needed clipping here, so that we can forget about it later */
513 clippedPacking = *packing;
514 if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height,
515 &clippedPacking.SkipPixels,
516 &clippedPacking.SkipRows)) {
517 /* The ReadPixels region is totally outside the window bounds */
518 return;
519 }
520
521 if (clippedPacking.BufferObj->Name) {
522 /* pack into PBO */
523 GLubyte *buf;
524 if (!_mesa_validate_pbo_access(2, &clippedPacking, width, height, 1,
525 format, type, pixels)) {
526 _mesa_error(ctx, GL_INVALID_OPERATION,
527 "glReadPixels(invalid PBO access)");
528 return;
529 }
530 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
531 GL_WRITE_ONLY_ARB,
532 clippedPacking.BufferObj);
533 if (!buf) {
534 /* buffer is already mapped - that's an error */
535 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
536 return;
537 }
538 pixels = ADD_POINTERS(buf, pixels);
539 }
540
541 RENDER_START(swrast, ctx);
542
543 switch (format) {
544 case GL_COLOR_INDEX:
545 read_index_pixels(ctx, x, y, width, height, type, pixels,
546 &clippedPacking);
547 break;
548 case GL_STENCIL_INDEX:
549 read_stencil_pixels(ctx, x,y, width,height, type, pixels,
550 &clippedPacking);
551 break;
552 case GL_DEPTH_COMPONENT:
553 read_depth_pixels(ctx, x, y, width, height, type, pixels,
554 &clippedPacking);
555 break;
556 case GL_RED:
557 case GL_GREEN:
558 case GL_BLUE:
559 case GL_ALPHA:
560 case GL_RGB:
561 case GL_LUMINANCE:
562 case GL_LUMINANCE_ALPHA:
563 case GL_RGBA:
564 case GL_BGR:
565 case GL_BGRA:
566 case GL_ABGR_EXT:
567 read_rgba_pixels(ctx, x, y, width, height,
568 format, type, pixels, &clippedPacking);
569 break;
570 default:
571 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
572 /* don't return yet, clean-up */
573 }
574
575 RENDER_FINISH(swrast, ctx);
576
577 if (clippedPacking.BufferObj->Name) {
578 /* done with PBO so unmap it now */
579 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
580 clippedPacking.BufferObj);
581 }
582 }