fix typo
[mesa.git] / src / mesa / swrast / s_readpix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 5.1
4 *
5 * Copyright (C) 1999-2003 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 "colormac.h"
28 #include "convolve.h"
29 #include "context.h"
30 #include "feedback.h"
31 #include "image.h"
32 #include "macros.h"
33 #include "imports.h"
34 #include "pixel.h"
35
36 #include "s_alphabuf.h"
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 SWcontext *swrast = SWRAST_CONTEXT(ctx);
55 GLint i, readWidth;
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 _swrast_use_read_buffer(ctx);
75
76 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
77
78 /* process image row by row */
79 for (i = 0; i < height; i++) {
80 GLuint index[MAX_WIDTH];
81 GLvoid *dest;
82
83 (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y + i, index);
84
85 dest = _mesa_image_address(packing, pixels, width, height,
86 GL_COLOR_INDEX, type, 0, i, 0);
87
88 _mesa_pack_index_span(ctx, readWidth, type, dest, index,
89 &ctx->Pack, ctx->_ImageTransferState);
90 }
91
92 _swrast_use_draw_buffer(ctx);
93 }
94
95
96
97 static void
98 read_depth_pixels( GLcontext *ctx,
99 GLint x, GLint y,
100 GLsizei width, GLsizei height,
101 GLenum type, GLvoid *pixels,
102 const struct gl_pixelstore_attrib *packing )
103 {
104 GLint readWidth;
105 GLboolean bias_or_scale;
106
107 /* Error checking */
108 if (ctx->Visual.depthBits <= 0) {
109 /* No depth buffer */
110 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
111 return;
112 }
113
114 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
115
116 if (type != GL_BYTE &&
117 type != GL_UNSIGNED_BYTE &&
118 type != GL_SHORT &&
119 type != GL_UNSIGNED_SHORT &&
120 type != GL_INT &&
121 type != GL_UNSIGNED_INT &&
122 type != GL_FLOAT) {
123 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
124 return;
125 }
126
127 bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
128
129 if (type==GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16
130 && !bias_or_scale && !packing->SwapBytes) {
131 /* Special case: directly read 16-bit unsigned depth values. */
132 GLint j;
133 for (j=0;j<height;j++,y++) {
134 GLdepth depth[MAX_WIDTH];
135 GLushort *dst = (GLushort*) _mesa_image_address( packing, pixels,
136 width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
137 GLint i;
138 _swrast_read_depth_span(ctx, width, x, y, depth);
139 for (i = 0; i < width; i++)
140 dst[i] = depth[i];
141 }
142 }
143 else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
144 && !bias_or_scale && !packing->SwapBytes) {
145 /* Special case: directly read 32-bit unsigned depth values. */
146 GLint j;
147 for (j=0;j<height;j++,y++) {
148 GLdepth *dst = (GLdepth *) _mesa_image_address( packing, pixels,
149 width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
150 _swrast_read_depth_span(ctx, width, x, y, dst);
151 }
152 }
153 else {
154 /* General case (slower) */
155 GLint j;
156 for (j=0;j<height;j++,y++) {
157 GLfloat depth[MAX_WIDTH];
158 GLvoid *dest;
159
160 _swrast_read_depth_span_float(ctx, readWidth, x, y, depth);
161
162 dest = _mesa_image_address(packing, pixels, width, height,
163 GL_DEPTH_COMPONENT, type, 0, j, 0);
164
165 _mesa_pack_depth_span(ctx, readWidth, (GLdepth *) dest, type,
166 depth, &ctx->Pack);
167 }
168 }
169 }
170
171
172
173 static void
174 read_stencil_pixels( GLcontext *ctx,
175 GLint x, GLint y,
176 GLsizei width, GLsizei height,
177 GLenum type, GLvoid *pixels,
178 const struct gl_pixelstore_attrib *packing )
179 {
180 GLint j, readWidth;
181
182 if (type != GL_BYTE &&
183 type != GL_UNSIGNED_BYTE &&
184 type != GL_SHORT &&
185 type != GL_UNSIGNED_SHORT &&
186 type != GL_INT &&
187 type != GL_UNSIGNED_INT &&
188 type != GL_FLOAT &&
189 type != GL_BITMAP) {
190 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(stencil type)");
191 return;
192 }
193
194 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
195
196 if (ctx->Visual.stencilBits <= 0) {
197 /* No stencil buffer */
198 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
199 return;
200 }
201
202 /* process image row by row */
203 for (j=0;j<height;j++,y++) {
204 GLvoid *dest;
205 GLstencil stencil[MAX_WIDTH];
206
207 _swrast_read_stencil_span(ctx, readWidth, x, y, stencil);
208
209 dest = _mesa_image_address(packing, pixels, width, height,
210 GL_STENCIL_INDEX, type, 0, j, 0);
211
212 _mesa_pack_stencil_span(ctx, readWidth, type, dest, stencil, &ctx->Pack);
213 }
214 }
215
216
217
218 /*
219 * Optimized glReadPixels for particular pixel formats:
220 * GL_UNSIGNED_BYTE, GL_RGBA
221 * when pixel scaling, biasing and mapping are disabled.
222 */
223 static GLboolean
224 read_fast_rgba_pixels( GLcontext *ctx,
225 GLint x, GLint y,
226 GLsizei width, GLsizei height,
227 GLenum format, GLenum type,
228 GLvoid *pixels,
229 const struct gl_pixelstore_attrib *packing )
230 {
231 SWcontext *swrast = SWRAST_CONTEXT(ctx);
232 /* can't do scale, bias, mapping, etc */
233 if (ctx->_ImageTransferState)
234 return GL_FALSE;
235
236 /* can't do fancy pixel packing */
237 if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
238 return GL_FALSE;
239
240 {
241 GLint srcX = x;
242 GLint srcY = y;
243 GLint readWidth = width; /* actual width read */
244 GLint readHeight = height; /* actual height read */
245 GLint skipPixels = packing->SkipPixels;
246 GLint skipRows = packing->SkipRows;
247 GLint rowLength;
248
249 if (packing->RowLength > 0)
250 rowLength = packing->RowLength;
251 else
252 rowLength = width;
253
254 /* horizontal clipping */
255 if (srcX < 0) {
256 skipPixels -= srcX;
257 readWidth += srcX;
258 srcX = 0;
259 }
260 if (srcX + readWidth > (GLint) ctx->ReadBuffer->Width)
261 readWidth -= (srcX + readWidth - (GLint) ctx->ReadBuffer->Width);
262 if (readWidth <= 0)
263 return GL_TRUE;
264
265 /* vertical clipping */
266 if (srcY < 0) {
267 skipRows -= srcY;
268 readHeight += srcY;
269 srcY = 0;
270 }
271 if (srcY + readHeight > (GLint) ctx->ReadBuffer->Height)
272 readHeight -= (srcY + readHeight - (GLint) ctx->ReadBuffer->Height);
273 if (readHeight <= 0)
274 return GL_TRUE;
275
276 /*
277 * Ready to read!
278 * The window region at (destX, destY) of size (readWidth, readHeight)
279 * will be read back.
280 * We'll write pixel data to buffer pointed to by "pixels" but we'll
281 * skip "skipRows" rows and skip "skipPixels" pixels/row.
282 */
283 #if CHAN_BITS == 8
284 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
285 #elif CHAN_BITS == 16
286 if (format == GL_RGBA && type == GL_UNSIGNED_SHORT) {
287 #else
288 if (0) {
289 #endif
290 GLchan *dest = (GLchan *) pixels
291 + (skipRows * rowLength + skipPixels) * 4;
292 GLint row;
293
294 if (packing->Invert) {
295 /* start at top and go down */
296 dest += (readHeight - 1) * rowLength * 4;
297 rowLength = -rowLength;
298 }
299
300 for (row=0; row<readHeight; row++) {
301 (*swrast->Driver.ReadRGBASpan)(ctx, readWidth, srcX, srcY,
302 (GLchan (*)[4]) dest);
303 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
304 _swrast_read_alpha_span(ctx, readWidth, srcX, srcY,
305 (GLchan (*)[4]) dest);
306 }
307 dest += rowLength * 4;
308 srcY++;
309 }
310 return GL_TRUE;
311 }
312 else {
313 /* can't do this format/type combination */
314 return GL_FALSE;
315 }
316 }
317 }
318
319
320
321 /*
322 * Read R, G, B, A, RGB, L, or LA pixels.
323 */
324 static void
325 read_rgba_pixels( GLcontext *ctx,
326 GLint x, GLint y,
327 GLsizei width, GLsizei height,
328 GLenum format, GLenum type, GLvoid *pixels,
329 const struct gl_pixelstore_attrib *packing )
330 {
331 SWcontext *swrast = SWRAST_CONTEXT(ctx);
332 GLint readWidth;
333
334 _swrast_use_read_buffer(ctx);
335
336 /* Try optimized path first */
337 if (read_fast_rgba_pixels( ctx, x, y, width, height,
338 format, type, pixels, packing )) {
339
340 _swrast_use_draw_buffer(ctx);
341 return; /* done! */
342 }
343
344 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
345
346 /* do error checking on pixel type, format was already checked by caller */
347 switch (type) {
348 case GL_UNSIGNED_BYTE:
349 case GL_BYTE:
350 case GL_UNSIGNED_SHORT:
351 case GL_SHORT:
352 case GL_UNSIGNED_INT:
353 case GL_INT:
354 case GL_FLOAT:
355 case GL_UNSIGNED_BYTE_3_3_2:
356 case GL_UNSIGNED_BYTE_2_3_3_REV:
357 case GL_UNSIGNED_SHORT_5_6_5:
358 case GL_UNSIGNED_SHORT_5_6_5_REV:
359 case GL_UNSIGNED_SHORT_4_4_4_4:
360 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
361 case GL_UNSIGNED_SHORT_5_5_5_1:
362 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
363 case GL_UNSIGNED_INT_8_8_8_8:
364 case GL_UNSIGNED_INT_8_8_8_8_REV:
365 case GL_UNSIGNED_INT_10_10_10_2:
366 case GL_UNSIGNED_INT_2_10_10_10_REV:
367 /* valid pixel type */
368 break;
369 default:
370 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
371 return;
372 }
373
374 if (!_mesa_is_legal_format_and_type(format, type) ||
375 format == GL_INTENSITY) {
376 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
377 return;
378 }
379
380 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
381 const GLuint transferOps = ctx->_ImageTransferState;
382 GLfloat *dest, *src, *tmpImage, *convImage;
383 GLint row;
384
385 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
386 if (!tmpImage) {
387 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
388 return;
389 }
390 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
391 if (!convImage) {
392 FREE(tmpImage);
393 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
394 return;
395 }
396
397 /* read full RGBA, FLOAT image */
398 dest = tmpImage;
399 for (row = 0; row < height; row++, y++) {
400 GLchan rgba[MAX_WIDTH][4];
401 if (ctx->Visual.rgbMode) {
402 _swrast_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
403 }
404 else {
405 GLuint index[MAX_WIDTH];
406 (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
407 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
408 _mesa_map_ci(ctx, readWidth, index);
409 }
410 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
411 }
412 _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
413 GL_RGBA, GL_FLOAT, dest, &_mesa_native_packing,
414 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
415 dest += width * 4;
416 }
417
418 /* do convolution */
419 if (ctx->Pixel.Convolution2DEnabled) {
420 _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
421 }
422 else {
423 ASSERT(ctx->Pixel.Separable2DEnabled);
424 _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
425 }
426 FREE(tmpImage);
427
428 /* finish transfer ops and pack the resulting image */
429 src = convImage;
430 for (row = 0; row < height; row++) {
431 GLvoid *dest;
432 dest = _mesa_image_address(packing, pixels, readWidth, height,
433 format, type, 0, row, 0);
434 _mesa_pack_float_rgba_span(ctx, readWidth,
435 (const GLfloat (*)[4]) src,
436 format, type, dest, packing,
437 transferOps & IMAGE_POST_CONVOLUTION_BITS);
438 src += readWidth * 4;
439 }
440 }
441 else {
442 /* no convolution */
443 GLint row;
444 for (row = 0; row < height; row++, y++) {
445 GLchan rgba[MAX_WIDTH][4];
446 GLvoid *dst;
447 if (ctx->Visual.rgbMode) {
448 _swrast_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
449 }
450 else {
451 GLuint index[MAX_WIDTH];
452 (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
453 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
454 _mesa_map_ci(ctx, readWidth, index);
455 }
456 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
457 }
458 dst = _mesa_image_address(packing, pixels, width, height,
459 format, type, 0, row, 0);
460 if (ctx->Visual.redBits < CHAN_BITS ||
461 ctx->Visual.greenBits < CHAN_BITS ||
462 ctx->Visual.blueBits < CHAN_BITS) {
463 /* Requantize the color values into floating point and go from
464 * there. This fixes conformance failures with 16-bit color
465 * buffers, for example.
466 */
467 DEFMARRAY(GLfloat, rgbaf, MAX_WIDTH, 4); /* mac 32k limitation */
468 CHECKARRAY(rgbaf, return); /* mac 32k limitation */
469 _mesa_chan_to_float_span(ctx, readWidth,
470 (CONST GLchan (*)[4]) rgba, rgbaf);
471 _mesa_pack_float_rgba_span(ctx, readWidth,
472 (CONST GLfloat (*)[4]) rgbaf,
473 format, type, dst, packing,
474 ctx->_ImageTransferState);
475 UNDEFARRAY(rgbaf); /* mac 32k limitation */
476 }
477 else {
478 /* GLubytes are fine */
479 _mesa_pack_rgba_span(ctx, readWidth, (CONST GLchan (*)[4]) rgba,
480 format, type, dst, packing,
481 ctx->_ImageTransferState);
482 }
483 }
484 }
485
486 _swrast_use_draw_buffer(ctx);
487 }
488
489
490
491 void
492 _swrast_ReadPixels( GLcontext *ctx,
493 GLint x, GLint y, GLsizei width, GLsizei height,
494 GLenum format, GLenum type,
495 const struct gl_pixelstore_attrib *pack,
496 GLvoid *pixels )
497 {
498 SWcontext *swrast = SWRAST_CONTEXT(ctx);
499 (void) pack;
500
501 if (swrast->NewState)
502 _swrast_validate_derived( ctx );
503
504 RENDER_START(swrast,ctx);
505
506 switch (format) {
507 case GL_COLOR_INDEX:
508 read_index_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
509 break;
510 case GL_STENCIL_INDEX:
511 read_stencil_pixels(ctx, x,y, width,height, type, pixels, &ctx->Pack);
512 break;
513 case GL_DEPTH_COMPONENT:
514 read_depth_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
515 break;
516 case GL_RED:
517 case GL_GREEN:
518 case GL_BLUE:
519 case GL_ALPHA:
520 case GL_RGB:
521 case GL_LUMINANCE:
522 case GL_LUMINANCE_ALPHA:
523 case GL_RGBA:
524 case GL_BGR:
525 case GL_BGRA:
526 case GL_ABGR_EXT:
527 read_rgba_pixels(ctx, x, y, width, height,
528 format, type, pixels, &ctx->Pack);
529 break;
530 default:
531 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
532 }
533
534 RENDER_FINISH(swrast,ctx);
535 }