added program.c plus minor fixes
[mesa.git] / src / mesa / swrast / s_readpix.c
1
2 /*
3 * Mesa 3-D graphics library
4 * Version: 4.1
5 *
6 * Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26
27 #include "glheader.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_alphabuf.h"
38 #include "s_context.h"
39 #include "s_depth.h"
40 #include "s_span.h"
41 #include "s_stencil.h"
42
43
44
45 /*
46 * Read a block of color index pixels.
47 */
48 static void
49 read_index_pixels( GLcontext *ctx,
50 GLint x, GLint y,
51 GLsizei width, GLsizei height,
52 GLenum type, GLvoid *pixels,
53 const struct gl_pixelstore_attrib *packing )
54 {
55 SWcontext *swrast = SWRAST_CONTEXT(ctx);
56 GLint i, readWidth;
57
58 /* error checking */
59 if (ctx->Visual.rgbMode) {
60 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
61 return;
62 }
63
64 _swrast_use_read_buffer(ctx);
65
66 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
67
68 /* process image row by row */
69 for (i = 0; i < height; i++) {
70 GLuint index[MAX_WIDTH];
71 GLvoid *dest;
72
73 (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y + i, index);
74
75 dest = _mesa_image_address(packing, pixels, width, height,
76 GL_COLOR_INDEX, type, 0, i, 0);
77
78 _mesa_pack_index_span(ctx, readWidth, type, dest, index,
79 &ctx->Pack, ctx->_ImageTransferState);
80 }
81
82 _swrast_use_draw_buffer(ctx);
83 }
84
85
86
87 static void
88 read_depth_pixels( GLcontext *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 GLint readWidth;
95 GLboolean bias_or_scale;
96
97 /* Error checking */
98 if (ctx->Visual.depthBits <= 0) {
99 /* No depth buffer */
100 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
101 return;
102 }
103
104 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
105
106 if (type != GL_BYTE &&
107 type != GL_UNSIGNED_BYTE &&
108 type != GL_SHORT &&
109 type != GL_UNSIGNED_SHORT &&
110 type != GL_INT &&
111 type != GL_UNSIGNED_INT &&
112 type != GL_FLOAT) {
113 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
114 return;
115 }
116
117 bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
118
119 if (type==GL_UNSIGNED_SHORT && ctx->Visual.depthBits == 16
120 && !bias_or_scale && !packing->SwapBytes) {
121 /* Special case: directly read 16-bit unsigned depth values. */
122 GLint j;
123 for (j=0;j<height;j++,y++) {
124 GLdepth depth[MAX_WIDTH];
125 GLushort *dst = (GLushort*) _mesa_image_address( packing, pixels,
126 width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
127 GLint i;
128 _swrast_read_depth_span(ctx, width, x, y, depth);
129 for (i = 0; i < width; i++)
130 dst[i] = depth[i];
131 }
132 }
133 else if (type==GL_UNSIGNED_INT && ctx->Visual.depthBits == 32
134 && !bias_or_scale && !packing->SwapBytes) {
135 /* Special case: directly read 32-bit unsigned depth values. */
136 GLint j;
137 for (j=0;j<height;j++,y++) {
138 GLdepth *dst = (GLdepth *) _mesa_image_address( packing, pixels,
139 width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
140 _swrast_read_depth_span(ctx, width, x, y, dst);
141 }
142 }
143 else {
144 /* General case (slower) */
145 GLint j;
146 for (j=0;j<height;j++,y++) {
147 GLfloat depth[MAX_WIDTH];
148 GLvoid *dest;
149
150 _swrast_read_depth_span_float(ctx, readWidth, x, y, depth);
151
152 dest = _mesa_image_address(packing, pixels, width, height,
153 GL_DEPTH_COMPONENT, type, 0, j, 0);
154
155 _mesa_pack_depth_span(ctx, readWidth, (GLdepth *) dest, type,
156 depth, &ctx->Pack);
157 }
158 }
159 }
160
161
162
163 static void
164 read_stencil_pixels( GLcontext *ctx,
165 GLint x, GLint y,
166 GLsizei width, GLsizei height,
167 GLenum type, GLvoid *pixels,
168 const struct gl_pixelstore_attrib *packing )
169 {
170 GLint j, readWidth;
171
172 if (type != GL_BYTE &&
173 type != GL_UNSIGNED_BYTE &&
174 type != GL_SHORT &&
175 type != GL_UNSIGNED_SHORT &&
176 type != GL_INT &&
177 type != GL_UNSIGNED_INT &&
178 type != GL_FLOAT &&
179 type != GL_BITMAP) {
180 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels(stencil type)");
181 return;
182 }
183
184 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
185
186 if (ctx->Visual.stencilBits <= 0) {
187 /* No stencil buffer */
188 _mesa_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
189 return;
190 }
191
192 /* process image row by row */
193 for (j=0;j<height;j++,y++) {
194 GLvoid *dest;
195 GLstencil stencil[MAX_WIDTH];
196
197 _swrast_read_stencil_span(ctx, readWidth, x, y, stencil);
198
199 dest = _mesa_image_address(packing, pixels, width, height,
200 GL_STENCIL_INDEX, type, 0, j, 0);
201
202 _mesa_pack_stencil_span(ctx, readWidth, type, dest, stencil, &ctx->Pack);
203 }
204 }
205
206
207
208 /*
209 * Optimized glReadPixels for particular pixel formats:
210 * GL_UNSIGNED_BYTE, GL_RGBA
211 * when pixel scaling, biasing and mapping are disabled.
212 */
213 static GLboolean
214 read_fast_rgba_pixels( GLcontext *ctx,
215 GLint x, GLint y,
216 GLsizei width, GLsizei height,
217 GLenum format, GLenum type,
218 GLvoid *pixels,
219 const struct gl_pixelstore_attrib *packing )
220 {
221 SWcontext *swrast = SWRAST_CONTEXT(ctx);
222 /* can't do scale, bias, mapping, etc */
223 if (ctx->_ImageTransferState)
224 return GL_FALSE;
225
226 /* can't do fancy pixel packing */
227 if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
228 return GL_FALSE;
229
230 {
231 GLint srcX = x;
232 GLint srcY = y;
233 GLint readWidth = width; /* actual width read */
234 GLint readHeight = height; /* actual height read */
235 GLint skipPixels = packing->SkipPixels;
236 GLint skipRows = packing->SkipRows;
237 GLint rowLength;
238
239 if (packing->RowLength > 0)
240 rowLength = packing->RowLength;
241 else
242 rowLength = width;
243
244 /* horizontal clipping */
245 if (srcX < 0) {
246 skipPixels -= srcX;
247 readWidth += srcX;
248 srcX = 0;
249 }
250 if (srcX + readWidth > (GLint) ctx->ReadBuffer->Width)
251 readWidth -= (srcX + readWidth - (GLint) ctx->ReadBuffer->Width);
252 if (readWidth <= 0)
253 return GL_TRUE;
254
255 /* vertical clipping */
256 if (srcY < 0) {
257 skipRows -= srcY;
258 readHeight += srcY;
259 srcY = 0;
260 }
261 if (srcY + readHeight > (GLint) ctx->ReadBuffer->Height)
262 readHeight -= (srcY + readHeight - (GLint) ctx->ReadBuffer->Height);
263 if (readHeight <= 0)
264 return GL_TRUE;
265
266 /*
267 * Ready to read!
268 * The window region at (destX, destY) of size (readWidth, readHeight)
269 * will be read back.
270 * We'll write pixel data to buffer pointed to by "pixels" but we'll
271 * skip "skipRows" rows and skip "skipPixels" pixels/row.
272 */
273 #if CHAN_BITS == 8
274 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
275 #elif CHAN_BITS == 16
276 if (format == GL_RGBA && type == GL_UNSIGNED_SHORT) {
277 #else
278 if (0) {
279 #endif
280 GLchan *dest = (GLchan *) pixels
281 + (skipRows * rowLength + skipPixels) * 4;
282 GLint row;
283
284 if (packing->Invert) {
285 /* start at top and go down */
286 dest += (readHeight - 1) * rowLength * 4;
287 rowLength = -rowLength;
288 }
289
290 for (row=0; row<readHeight; row++) {
291 (*swrast->Driver.ReadRGBASpan)(ctx, readWidth, srcX, srcY,
292 (GLchan (*)[4]) dest);
293 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
294 _swrast_read_alpha_span(ctx, readWidth, srcX, srcY,
295 (GLchan (*)[4]) dest);
296 }
297 dest += rowLength * 4;
298 srcY++;
299 }
300 return GL_TRUE;
301 }
302 else {
303 /* can't do this format/type combination */
304 return GL_FALSE;
305 }
306 }
307 }
308
309
310
311 /*
312 * Read R, G, B, A, RGB, L, or LA pixels.
313 */
314 static void
315 read_rgba_pixels( GLcontext *ctx,
316 GLint x, GLint y,
317 GLsizei width, GLsizei height,
318 GLenum format, GLenum type, GLvoid *pixels,
319 const struct gl_pixelstore_attrib *packing )
320 {
321 SWcontext *swrast = SWRAST_CONTEXT(ctx);
322 GLint readWidth;
323
324 _swrast_use_read_buffer(ctx);
325
326 /* Try optimized path first */
327 if (read_fast_rgba_pixels( ctx, x, y, width, height,
328 format, type, pixels, packing )) {
329
330 _swrast_use_draw_buffer(ctx);
331 return; /* done! */
332 }
333
334 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
335
336 /* do error checking on pixel type, format was already checked by caller */
337 switch (type) {
338 case GL_UNSIGNED_BYTE:
339 case GL_BYTE:
340 case GL_UNSIGNED_SHORT:
341 case GL_SHORT:
342 case GL_UNSIGNED_INT:
343 case GL_INT:
344 case GL_FLOAT:
345 case GL_UNSIGNED_BYTE_3_3_2:
346 case GL_UNSIGNED_BYTE_2_3_3_REV:
347 case GL_UNSIGNED_SHORT_5_6_5:
348 case GL_UNSIGNED_SHORT_5_6_5_REV:
349 case GL_UNSIGNED_SHORT_4_4_4_4:
350 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
351 case GL_UNSIGNED_SHORT_5_5_5_1:
352 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
353 case GL_UNSIGNED_INT_8_8_8_8:
354 case GL_UNSIGNED_INT_8_8_8_8_REV:
355 case GL_UNSIGNED_INT_10_10_10_2:
356 case GL_UNSIGNED_INT_2_10_10_10_REV:
357 /* valid pixel type */
358 break;
359 default:
360 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
361 return;
362 }
363
364 if (!_mesa_is_legal_format_and_type(format, type) ||
365 format == GL_INTENSITY) {
366 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
367 return;
368 }
369
370 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
371 const GLuint transferOps = ctx->_ImageTransferState;
372 GLfloat *dest, *src, *tmpImage, *convImage;
373 GLint row;
374
375 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
376 if (!tmpImage) {
377 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
378 return;
379 }
380 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
381 if (!convImage) {
382 FREE(tmpImage);
383 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
384 return;
385 }
386
387 /* read full RGBA, FLOAT image */
388 dest = tmpImage;
389 for (row = 0; row < height; row++, y++) {
390 GLchan rgba[MAX_WIDTH][4];
391 if (ctx->Visual.rgbMode) {
392 _swrast_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
393 }
394 else {
395 GLuint index[MAX_WIDTH];
396 (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
397 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
398 _mesa_map_ci(ctx, readWidth, index);
399 }
400 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
401 }
402 _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
403 GL_RGBA, GL_FLOAT, dest, &_mesa_native_packing,
404 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
405 dest += width * 4;
406 }
407
408 /* do convolution */
409 if (ctx->Pixel.Convolution2DEnabled) {
410 _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
411 }
412 else {
413 ASSERT(ctx->Pixel.Separable2DEnabled);
414 _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
415 }
416 FREE(tmpImage);
417
418 /* finish transfer ops and pack the resulting image */
419 src = convImage;
420 for (row = 0; row < height; row++) {
421 GLvoid *dest;
422 dest = _mesa_image_address(packing, pixels, readWidth, height,
423 format, type, 0, row, 0);
424 _mesa_pack_float_rgba_span(ctx, readWidth,
425 (const GLfloat (*)[4]) src,
426 format, type, dest, packing,
427 transferOps & IMAGE_POST_CONVOLUTION_BITS);
428 src += readWidth * 4;
429 }
430 }
431 else {
432 /* no convolution */
433 GLint row;
434 for (row = 0; row < height; row++, y++) {
435 GLchan rgba[MAX_WIDTH][4];
436 GLvoid *dst;
437 if (ctx->Visual.rgbMode) {
438 _swrast_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
439 }
440 else {
441 GLuint index[MAX_WIDTH];
442 (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
443 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
444 _mesa_map_ci(ctx, readWidth, index);
445 }
446 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
447 }
448 dst = _mesa_image_address(packing, pixels, width, height,
449 format, type, 0, row, 0);
450 if (ctx->Visual.redBits < CHAN_BITS ||
451 ctx->Visual.greenBits < CHAN_BITS ||
452 ctx->Visual.blueBits < CHAN_BITS) {
453 /* Requantize the color values into floating point and go from
454 * there. This fixes conformance failures with 16-bit color
455 * buffers, for example.
456 */
457 DEFMARRAY(GLfloat, rgbaf, MAX_WIDTH, 4); /* mac 32k limitation */
458 CHECKARRAY(rgbaf, return); /* mac 32k limitation */
459 _mesa_chan_to_float_span(ctx, readWidth,
460 (CONST GLchan (*)[4]) rgba, rgbaf);
461 _mesa_pack_float_rgba_span(ctx, readWidth,
462 (CONST GLfloat (*)[4]) rgbaf,
463 format, type, dst, packing,
464 ctx->_ImageTransferState);
465 UNDEFARRAY(rgbaf); /* mac 32k limitation */
466 }
467 else {
468 /* GLubytes are fine */
469 _mesa_pack_rgba_span(ctx, readWidth, (CONST GLchan (*)[4]) rgba,
470 format, type, dst, packing,
471 ctx->_ImageTransferState);
472 }
473 }
474 }
475
476 _swrast_use_draw_buffer(ctx);
477 }
478
479
480
481 void
482 _swrast_ReadPixels( GLcontext *ctx,
483 GLint x, GLint y, GLsizei width, GLsizei height,
484 GLenum format, GLenum type,
485 const struct gl_pixelstore_attrib *pack,
486 GLvoid *pixels )
487 {
488 SWcontext *swrast = SWRAST_CONTEXT(ctx);
489 (void) pack;
490
491 if (swrast->NewState)
492 _swrast_validate_derived( ctx );
493
494 RENDER_START(swrast,ctx);
495
496 switch (format) {
497 case GL_COLOR_INDEX:
498 read_index_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
499 break;
500 case GL_STENCIL_INDEX:
501 read_stencil_pixels(ctx, x,y, width,height, type, pixels, &ctx->Pack);
502 break;
503 case GL_DEPTH_COMPONENT:
504 read_depth_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
505 break;
506 case GL_RED:
507 case GL_GREEN:
508 case GL_BLUE:
509 case GL_ALPHA:
510 case GL_RGB:
511 case GL_LUMINANCE:
512 case GL_LUMINANCE_ALPHA:
513 case GL_RGBA:
514 case GL_BGR:
515 case GL_BGRA:
516 case GL_ABGR_EXT:
517 read_rgba_pixels(ctx, x, y, width, height,
518 format, type, pixels, &ctx->Pack);
519 break;
520 default:
521 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
522 }
523
524 RENDER_FINISH(swrast,ctx);
525 }