test version of startmenu root with big icons
[reactos.git] / reactos / lib / mesa32 / src / swrast / s_readpix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.1
4 *
5 * Copyright (C) 1999-2004 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 case GL_HALF_FLOAT_ARB:
370 if (!ctx->Extensions.ARB_half_float_pixel) {
371 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
372 return;
373 }
374 break;
375 default:
376 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
377 return;
378 }
379
380 if (!_mesa_is_legal_format_and_type(ctx, format, type) ||
381 format == GL_INTENSITY) {
382 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
383 return;
384 }
385
386 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
387 const GLuint transferOps = ctx->_ImageTransferState;
388 GLfloat *dest, *src, *tmpImage, *convImage;
389 GLint row;
390
391 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
392 if (!tmpImage) {
393 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
394 return;
395 }
396 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
397 if (!convImage) {
398 _mesa_free(tmpImage);
399 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
400 return;
401 }
402
403 /* read full RGBA, FLOAT image */
404 dest = tmpImage;
405 for (row = 0; row < height; row++, y++) {
406 GLchan rgba[MAX_WIDTH][4];
407 if (ctx->Visual.rgbMode) {
408 _swrast_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
409 }
410 else {
411 GLuint index[MAX_WIDTH];
412 (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
413 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
414 _mesa_map_ci(ctx, readWidth, index);
415 }
416 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
417 }
418 _mesa_pack_rgba_span_chan(ctx, readWidth, (const GLchan (*)[4]) rgba,
419 GL_RGBA, GL_FLOAT, dest, &ctx->DefaultPacking,
420 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
421 dest += width * 4;
422 }
423
424 /* do convolution */
425 if (ctx->Pixel.Convolution2DEnabled) {
426 _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
427 }
428 else {
429 ASSERT(ctx->Pixel.Separable2DEnabled);
430 _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
431 }
432 _mesa_free(tmpImage);
433
434 /* finish transfer ops and pack the resulting image */
435 src = convImage;
436 for (row = 0; row < height; row++) {
437 GLvoid *dest;
438 dest = _mesa_image_address(packing, pixels, readWidth, height,
439 format, type, 0, row, 0);
440 _mesa_pack_rgba_span_float(ctx, readWidth,
441 (const GLfloat (*)[4]) src,
442 format, type, dest, packing,
443 transferOps & IMAGE_POST_CONVOLUTION_BITS);
444 src += readWidth * 4;
445 }
446 }
447 else {
448 /* no convolution */
449 GLint row;
450 for (row = 0; row < height; row++, y++) {
451 GLchan rgba[MAX_WIDTH][4];
452 GLvoid *dst;
453 if (ctx->Visual.rgbMode) {
454 _swrast_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
455 }
456 else {
457 GLuint index[MAX_WIDTH];
458 (*swrast->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
459 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
460 _mesa_map_ci(ctx, readWidth, index);
461 }
462 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
463 }
464 dst = _mesa_image_address(packing, pixels, width, height,
465 format, type, 0, row, 0);
466 if (ctx->Visual.redBits < CHAN_BITS ||
467 ctx->Visual.greenBits < CHAN_BITS ||
468 ctx->Visual.blueBits < CHAN_BITS) {
469 /* Requantize the color values into floating point and go from
470 * there. This fixes conformance failures with 16-bit color
471 * buffers, for example.
472 */
473 DEFMARRAY(GLfloat, rgbaf, MAX_WIDTH, 4); /* mac 32k limitation */
474 CHECKARRAY(rgbaf, return); /* mac 32k limitation */
475 _mesa_chan_to_float_span(ctx, readWidth,
476 (CONST GLchan (*)[4]) rgba, rgbaf);
477 _mesa_pack_rgba_span_float(ctx, readWidth,
478 (CONST GLfloat (*)[4]) rgbaf,
479 format, type, dst, packing,
480 ctx->_ImageTransferState);
481 UNDEFARRAY(rgbaf); /* mac 32k limitation */
482 }
483 else {
484 /* GLubytes are fine */
485 _mesa_pack_rgba_span_chan(ctx, readWidth, (CONST GLchan (*)[4]) rgba,
486 format, type, dst, packing,
487 ctx->_ImageTransferState);
488 }
489 }
490 }
491
492 _swrast_use_draw_buffer(ctx);
493 }
494
495
496
497 void
498 _swrast_ReadPixels( GLcontext *ctx,
499 GLint x, GLint y, GLsizei width, GLsizei height,
500 GLenum format, GLenum type,
501 const struct gl_pixelstore_attrib *pack,
502 GLvoid *pixels )
503 {
504 SWcontext *swrast = SWRAST_CONTEXT(ctx);
505 (void) pack;
506
507 if (swrast->NewState)
508 _swrast_validate_derived( ctx );
509
510 pixels = _swrast_validate_pbo_access(pack, width, height, 1,
511 format, type, (GLvoid *) pixels);
512
513 if (!pixels) {
514 _mesa_error( ctx, GL_INVALID_VALUE, "glReadPixels(pixels)" );
515 return;
516 }
517
518 RENDER_START(swrast,ctx);
519
520 switch (format) {
521 case GL_COLOR_INDEX:
522 read_index_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
523 break;
524 case GL_STENCIL_INDEX:
525 read_stencil_pixels(ctx, x,y, width,height, type, pixels, &ctx->Pack);
526 break;
527 case GL_DEPTH_COMPONENT:
528 read_depth_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
529 break;
530 case GL_RED:
531 case GL_GREEN:
532 case GL_BLUE:
533 case GL_ALPHA:
534 case GL_RGB:
535 case GL_LUMINANCE:
536 case GL_LUMINANCE_ALPHA:
537 case GL_RGBA:
538 case GL_BGR:
539 case GL_BGRA:
540 case GL_ABGR_EXT:
541 read_rgba_pixels(ctx, x, y, width, height,
542 format, type, pixels, &ctx->Pack);
543 break;
544 default:
545 _mesa_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
546 }
547
548 RENDER_FINISH(swrast,ctx);
549 }