Moved software rasterizer functionality to new directory.
[mesa.git] / src / mesa / swrast / s_readpix.c
1 /* $Id: s_readpix.c,v 1.1 2000/10/31 18:00:04 keithw Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28 #include "glheader.h"
29 #include "colormac.h"
30 #include "convolve.h"
31 #include "context.h"
32 #include "feedback.h"
33 #include "image.h"
34 #include "macros.h"
35 #include "mem.h"
36 #include "pixel.h"
37
38 #include "s_alphabuf.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 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 GLint i, j, readWidth;
55
56 /* error checking */
57 if (ctx->Visual.RGBAflag) {
58 gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
59 return;
60 }
61
62 ASSERT(ctx->Driver.SetReadBuffer);
63 (*ctx->Driver.SetReadBuffer)(ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer);
64
65 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
66
67 /* process image row by row */
68 for (j=0;j<height;j++,y++) {
69 GLuint index[MAX_WIDTH];
70 GLvoid *dest;
71
72 (*ctx->Driver.ReadCI32Span)( ctx, readWidth, x, y, index );
73
74 if (ctx->Pixel.IndexShift!=0 || ctx->Pixel.IndexOffset!=0) {
75 _mesa_shift_and_offset_ci( ctx, readWidth, index);
76 }
77
78 if (ctx->Pixel.MapColorFlag) {
79 _mesa_map_ci(ctx, readWidth, index);
80 }
81
82 dest = _mesa_image_address(packing, pixels,
83 width, height, GL_COLOR_INDEX, type, 0, j, 0);
84
85 switch (type) {
86 case GL_UNSIGNED_BYTE:
87 {
88 GLubyte *dst = (GLubyte *) dest;
89 for (i=0;i<readWidth;i++) {
90 *dst++ = (GLubyte) index[i];
91 }
92 }
93 break;
94 case GL_BYTE:
95 {
96 GLbyte *dst = (GLbyte *) dest;
97 for (i=0;i<readWidth;i++) {
98 dst[i] = (GLbyte) index[i];
99 }
100 }
101 break;
102 case GL_UNSIGNED_SHORT:
103 {
104 GLushort *dst = (GLushort *) dest;
105 for (i=0;i<readWidth;i++) {
106 dst[i] = (GLushort) index[i];
107 }
108 if (packing->SwapBytes) {
109 _mesa_swap2( (GLushort *) dst, readWidth );
110 }
111 }
112 break;
113 case GL_SHORT:
114 {
115 GLshort *dst = (GLshort *) dest;
116 for (i=0;i<readWidth;i++) {
117 dst[i] = (GLshort) index[i];
118 }
119 if (packing->SwapBytes) {
120 _mesa_swap2( (GLushort *) dst, readWidth );
121 }
122 }
123 break;
124 case GL_UNSIGNED_INT:
125 {
126 GLuint *dst = (GLuint *) dest;
127 for (i=0;i<readWidth;i++) {
128 dst[i] = (GLuint) index[i];
129 }
130 if (packing->SwapBytes) {
131 _mesa_swap4( (GLuint *) dst, readWidth );
132 }
133 }
134 break;
135 case GL_INT:
136 {
137 GLint *dst = (GLint *) dest;
138 for (i=0;i<readWidth;i++) {
139 dst[i] = (GLint) index[i];
140 }
141 if (packing->SwapBytes) {
142 _mesa_swap4( (GLuint *) dst, readWidth );
143 }
144 }
145 break;
146 case GL_FLOAT:
147 {
148 GLfloat *dst = (GLfloat *) dest;
149 for (i=0;i<readWidth;i++) {
150 dst[i] = (GLfloat) index[i];
151 }
152 if (packing->SwapBytes) {
153 _mesa_swap4( (GLuint *) dst, readWidth );
154 }
155 }
156 break;
157 default:
158 gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
159 j = height + 1; /* exit loop */
160 }
161 }
162
163 (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
164 }
165
166
167
168 static void read_depth_pixels( GLcontext *ctx,
169 GLint x, GLint y,
170 GLsizei width, GLsizei height,
171 GLenum type, GLvoid *pixels,
172 const struct gl_pixelstore_attrib *packing )
173 {
174 GLint i, j, readWidth;
175 GLboolean bias_or_scale;
176
177 /* Error checking */
178 if (ctx->Visual.DepthBits <= 0) {
179 /* No depth buffer */
180 gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
181 return;
182 }
183
184 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
185
186 if (type != GL_BYTE &&
187 type != GL_UNSIGNED_BYTE &&
188 type != GL_SHORT &&
189 type != GL_UNSIGNED_SHORT &&
190 type != GL_INT &&
191 type != GL_UNSIGNED_INT &&
192 type != GL_FLOAT) {
193 gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels(depth type)");
194 return;
195 }
196
197 bias_or_scale = ctx->Pixel.DepthBias!=0.0 || ctx->Pixel.DepthScale!=1.0;
198
199 if (type==GL_UNSIGNED_SHORT && ctx->Visual.DepthBits == 16
200 && !bias_or_scale && !packing->SwapBytes) {
201 /* Special case: directly read 16-bit unsigned depth values. */
202 for (j=0;j<height;j++,y++) {
203 GLdepth depth[MAX_WIDTH];
204 GLushort *dst = (GLushort*) _mesa_image_address( packing, pixels,
205 width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
206 GLint i;
207 _mesa_read_depth_span(ctx, width, x, y, depth);
208 for (i = 0; i < width; i++)
209 dst[i] = depth[i];
210 }
211 }
212 else if (type==GL_UNSIGNED_INT && ctx->Visual.DepthBits == 32
213 && !bias_or_scale && !packing->SwapBytes) {
214 /* Special case: directly read 32-bit unsigned depth values. */
215 for (j=0;j<height;j++,y++) {
216 GLdepth *dst = (GLdepth *) _mesa_image_address( packing, pixels,
217 width, height, GL_DEPTH_COMPONENT, type, 0, j, 0 );
218 _mesa_read_depth_span(ctx, width, x, y, dst);
219 }
220 }
221 else {
222 /* General case (slower) */
223 for (j=0;j<height;j++,y++) {
224 GLfloat depth[MAX_WIDTH];
225 GLvoid *dest;
226
227 _mesa_read_depth_span_float(ctx, readWidth, x, y, depth);
228
229 if (bias_or_scale) {
230 for (i=0;i<readWidth;i++) {
231 GLfloat d;
232 d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
233 depth[i] = CLAMP( d, 0.0F, 1.0F );
234 }
235 }
236
237 dest = _mesa_image_address(packing, pixels,
238 width, height, GL_DEPTH_COMPONENT, type, 0, j, 0);
239
240 switch (type) {
241 case GL_UNSIGNED_BYTE:
242 {
243 GLubyte *dst = (GLubyte *) dest;
244 for (i=0;i<readWidth;i++) {
245 dst[i] = FLOAT_TO_UBYTE( depth[i] );
246 }
247 }
248 break;
249 case GL_BYTE:
250 {
251 GLbyte *dst = (GLbyte *) dest;
252 for (i=0;i<readWidth;i++) {
253 dst[i] = FLOAT_TO_BYTE( depth[i] );
254 }
255 }
256 break;
257 case GL_UNSIGNED_SHORT:
258 {
259 GLushort *dst = (GLushort *) dest;
260 for (i=0;i<readWidth;i++) {
261 dst[i] = FLOAT_TO_USHORT( depth[i] );
262 }
263 if (packing->SwapBytes) {
264 _mesa_swap2( (GLushort *) dst, readWidth );
265 }
266 }
267 break;
268 case GL_SHORT:
269 {
270 GLshort *dst = (GLshort *) dest;
271 for (i=0;i<readWidth;i++) {
272 dst[i] = FLOAT_TO_SHORT( depth[i] );
273 }
274 if (packing->SwapBytes) {
275 _mesa_swap2( (GLushort *) dst, readWidth );
276 }
277 }
278 break;
279 case GL_UNSIGNED_INT:
280 {
281 GLuint *dst = (GLuint *) dest;
282 for (i=0;i<readWidth;i++) {
283 dst[i] = FLOAT_TO_UINT( depth[i] );
284 }
285 if (packing->SwapBytes) {
286 _mesa_swap4( (GLuint *) dst, readWidth );
287 }
288 }
289 break;
290 case GL_INT:
291 {
292 GLint *dst = (GLint *) dest;
293 for (i=0;i<readWidth;i++) {
294 dst[i] = FLOAT_TO_INT( depth[i] );
295 }
296 if (packing->SwapBytes) {
297 _mesa_swap4( (GLuint *) dst, readWidth );
298 }
299 }
300 break;
301 case GL_FLOAT:
302 {
303 GLfloat *dst = (GLfloat *) dest;
304 for (i=0;i<readWidth;i++) {
305 dst[i] = depth[i];
306 }
307 if (packing->SwapBytes) {
308 _mesa_swap4( (GLuint *) dst, readWidth );
309 }
310 }
311 break;
312 default:
313 gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
314 }
315 }
316 }
317 }
318
319
320
321 static void read_stencil_pixels( GLcontext *ctx,
322 GLint x, GLint y,
323 GLsizei width, GLsizei height,
324 GLenum type, GLvoid *pixels,
325 const struct gl_pixelstore_attrib *packing )
326 {
327 GLboolean shift_or_offset;
328 GLint i, j, readWidth;
329
330 if (type != GL_BYTE &&
331 type != GL_UNSIGNED_BYTE &&
332 type != GL_SHORT &&
333 type != GL_UNSIGNED_SHORT &&
334 type != GL_INT &&
335 type != GL_UNSIGNED_INT &&
336 type != GL_FLOAT &&
337 type != GL_BITMAP) {
338 gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels(stencil type)");
339 return;
340 }
341
342 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
343
344 if (ctx->Visual.StencilBits<=0) {
345 /* No stencil buffer */
346 gl_error( ctx, GL_INVALID_OPERATION, "glReadPixels" );
347 return;
348 }
349
350 shift_or_offset = ctx->Pixel.IndexShift!=0 || ctx->Pixel.IndexOffset!=0;
351
352 /* process image row by row */
353 for (j=0;j<height;j++,y++) {
354 GLvoid *dest;
355 GLstencil stencil[MAX_WIDTH];
356
357 _mesa_read_stencil_span( ctx, readWidth, x, y, stencil );
358
359 if (shift_or_offset) {
360 _mesa_shift_and_offset_stencil( ctx, readWidth, stencil );
361 }
362
363 if (ctx->Pixel.MapStencilFlag) {
364 _mesa_map_stencil( ctx, readWidth, stencil );
365 }
366
367 dest = _mesa_image_address( packing, pixels,
368 width, height, GL_STENCIL_INDEX, type, 0, j, 0 );
369
370 switch (type) {
371 case GL_UNSIGNED_BYTE:
372 if (sizeof(GLstencil) == 8) {
373 MEMCPY( dest, stencil, readWidth );
374 }
375 else {
376 GLubyte *dst = (GLubyte *) dest;
377 for (i=0;i<readWidth;i++) {
378 dst[i] = (GLubyte) stencil[i];
379 }
380 }
381 break;
382 case GL_BYTE:
383 if (sizeof(GLstencil) == 8) {
384 MEMCPY( dest, stencil, readWidth );
385 }
386 else {
387 GLbyte *dst = (GLbyte *) dest;
388 for (i=0;i<readWidth;i++) {
389 dst[i] = (GLbyte) stencil[i];
390 }
391 }
392 break;
393 case GL_UNSIGNED_SHORT:
394 {
395 GLushort *dst = (GLushort *) dest;
396 for (i=0;i<readWidth;i++) {
397 dst[i] = (GLushort) stencil[i];
398 }
399 if (packing->SwapBytes) {
400 _mesa_swap2( (GLushort *) dst, readWidth );
401 }
402 }
403 break;
404 case GL_SHORT:
405 {
406 GLshort *dst = (GLshort *) dest;
407 for (i=0;i<readWidth;i++) {
408 dst[i] = (GLshort) stencil[i];
409 }
410 if (packing->SwapBytes) {
411 _mesa_swap2( (GLushort *) dst, readWidth );
412 }
413 }
414 break;
415 case GL_UNSIGNED_INT:
416 {
417 GLuint *dst = (GLuint *) dest;
418 for (i=0;i<readWidth;i++) {
419 dst[i] = (GLuint) stencil[i];
420 }
421 if (packing->SwapBytes) {
422 _mesa_swap4( (GLuint *) dst, readWidth );
423 }
424 }
425 break;
426 case GL_INT:
427 {
428 GLint *dst = (GLint *) dest;
429 for (i=0;i<readWidth;i++) {
430 *dst++ = (GLint) stencil[i];
431 }
432 if (packing->SwapBytes) {
433 _mesa_swap4( (GLuint *) dst, readWidth );
434 }
435 }
436 break;
437 case GL_FLOAT:
438 {
439 GLfloat *dst = (GLfloat *) dest;
440 for (i=0;i<readWidth;i++) {
441 dst[i] = (GLfloat) stencil[i];
442 }
443 if (packing->SwapBytes) {
444 _mesa_swap4( (GLuint *) dst, readWidth );
445 }
446 }
447 break;
448 case GL_BITMAP:
449 if (packing->LsbFirst) {
450 GLubyte *dst = (GLubyte*) dest;
451 GLint shift = 0;
452 for (i = 0; i < readWidth; i++) {
453 if (shift == 0)
454 *dst = 0;
455 *dst |= ((stencil != 0) << shift);
456 shift++;
457 if (shift == 8) {
458 shift = 0;
459 dst++;
460 }
461 }
462 }
463 else {
464 GLubyte *dst = (GLubyte*) dest;
465 GLint shift = 7;
466 for (i = 0; i < readWidth; i++) {
467 if (shift == 7)
468 *dst = 0;
469 *dst |= ((stencil != 0) << shift);
470 shift--;
471 if (shift < 0) {
472 shift = 7;
473 dst++;
474 }
475 }
476 }
477 break;
478 default:
479 gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
480 }
481 }
482 }
483
484
485
486 /*
487 * Optimized glReadPixels for particular pixel formats:
488 * GL_UNSIGNED_BYTE, GL_RGBA
489 * when pixel scaling, biasing and mapping are disabled.
490 */
491 static GLboolean
492 read_fast_rgba_pixels( GLcontext *ctx,
493 GLint x, GLint y,
494 GLsizei width, GLsizei height,
495 GLenum format, GLenum type,
496 GLvoid *pixels,
497 const struct gl_pixelstore_attrib *packing )
498 {
499 /* can't do scale, bias, mapping, etc */
500 if (ctx->ImageTransferState)
501 return GL_FALSE;
502
503 /* can't do fancy pixel packing */
504 if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
505 return GL_FALSE;
506
507 {
508 GLint srcX = x;
509 GLint srcY = y;
510 GLint readWidth = width; /* actual width read */
511 GLint readHeight = height; /* actual height read */
512 GLint skipPixels = packing->SkipPixels;
513 GLint skipRows = packing->SkipRows;
514 GLint rowLength;
515
516 if (packing->RowLength > 0)
517 rowLength = packing->RowLength;
518 else
519 rowLength = width;
520
521 /* horizontal clipping */
522 if (srcX < ctx->ReadBuffer->Xmin) {
523 skipPixels += (ctx->ReadBuffer->Xmin - srcX);
524 readWidth -= (ctx->ReadBuffer->Xmin - srcX);
525 srcX = ctx->ReadBuffer->Xmin;
526 }
527 if (srcX + readWidth > ctx->ReadBuffer->Xmax)
528 readWidth -= (srcX + readWidth - ctx->ReadBuffer->Xmax);
529 if (readWidth <= 0)
530 return GL_TRUE;
531
532 /* vertical clipping */
533 if (srcY < ctx->ReadBuffer->Ymin) {
534 skipRows += (ctx->ReadBuffer->Ymin - srcY);
535 readHeight -= (ctx->ReadBuffer->Ymin - srcY);
536 srcY = ctx->ReadBuffer->Ymin;
537 }
538 if (srcY + readHeight > ctx->ReadBuffer->Ymax)
539 readHeight -= (srcY + readHeight - ctx->ReadBuffer->Ymax);
540 if (readHeight <= 0)
541 return GL_TRUE;
542
543 /*
544 * Ready to read!
545 * The window region at (destX, destY) of size (readWidth, readHeight)
546 * will be read back.
547 * We'll write pixel data to buffer pointed to by "pixels" but we'll
548 * skip "skipRows" rows and skip "skipPixels" pixels/row.
549 */
550 #if CHAN_BITS == 8
551 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
552 #elif CHAN_BITS == 16
553 if (format == GL_RGBA && type == GL_UNSIGNED_SHORT) {
554 #else
555 if (0) {
556 #endif
557 GLchan *dest = (GLchan *) pixels
558 + (skipRows * rowLength + skipPixels) * 4;
559 GLint row;
560 for (row=0; row<readHeight; row++) {
561 (*ctx->Driver.ReadRGBASpan)(ctx, readWidth, srcX, srcY,
562 (GLchan (*)[4]) dest);
563 if (ctx->DrawBuffer->UseSoftwareAlphaBuffers) {
564 _mesa_read_alpha_span(ctx, readWidth, srcX, srcY,
565 (GLchan (*)[4]) dest);
566 }
567 dest += rowLength * 4;
568 srcY++;
569 }
570 return GL_TRUE;
571 }
572 else {
573 /* can't do this format/type combination */
574 return GL_FALSE;
575 }
576 }
577 }
578
579
580
581 /*
582 * Read R, G, B, A, RGB, L, or LA pixels.
583 */
584 static void read_rgba_pixels( GLcontext *ctx,
585 GLint x, GLint y,
586 GLsizei width, GLsizei height,
587 GLenum format, GLenum type, GLvoid *pixels,
588 const struct gl_pixelstore_attrib *packing )
589 {
590 GLint readWidth;
591
592 (*ctx->Driver.SetReadBuffer)(ctx, ctx->ReadBuffer, ctx->Pixel.DriverReadBuffer);
593
594 /* Try optimized path first */
595 if (read_fast_rgba_pixels( ctx, x, y, width, height,
596 format, type, pixels, packing )) {
597
598 (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
599 return; /* done! */
600 }
601
602 readWidth = (width > MAX_WIDTH) ? MAX_WIDTH : width;
603
604 /* do error checking on pixel type, format was already checked by caller */
605 switch (type) {
606 case GL_UNSIGNED_BYTE:
607 case GL_BYTE:
608 case GL_UNSIGNED_SHORT:
609 case GL_SHORT:
610 case GL_UNSIGNED_INT:
611 case GL_INT:
612 case GL_FLOAT:
613 case GL_UNSIGNED_BYTE_3_3_2:
614 case GL_UNSIGNED_BYTE_2_3_3_REV:
615 case GL_UNSIGNED_SHORT_5_6_5:
616 case GL_UNSIGNED_SHORT_5_6_5_REV:
617 case GL_UNSIGNED_SHORT_4_4_4_4:
618 case GL_UNSIGNED_SHORT_4_4_4_4_REV:
619 case GL_UNSIGNED_SHORT_5_5_5_1:
620 case GL_UNSIGNED_SHORT_1_5_5_5_REV:
621 case GL_UNSIGNED_INT_8_8_8_8:
622 case GL_UNSIGNED_INT_8_8_8_8_REV:
623 case GL_UNSIGNED_INT_10_10_10_2:
624 case GL_UNSIGNED_INT_2_10_10_10_REV:
625 /* valid pixel type */
626 break;
627 default:
628 gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(type)" );
629 return;
630 }
631
632 if (!_mesa_is_legal_format_and_type(format, type) ||
633 format == GL_INTENSITY) {
634 gl_error(ctx, GL_INVALID_OPERATION, "glReadPixels(format or type)");
635 return;
636 }
637
638 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
639 const GLuint transferOps = ctx->ImageTransferState;
640 GLfloat *dest, *src, *tmpImage, *convImage;
641 GLint row;
642
643 tmpImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
644 if (!tmpImage) {
645 gl_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
646 return;
647 }
648 convImage = (GLfloat *) MALLOC(width * height * 4 * sizeof(GLfloat));
649 if (!convImage) {
650 FREE(tmpImage);
651 gl_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
652 return;
653 }
654
655 /* read full RGBA, FLOAT image */
656 dest = tmpImage;
657 for (row = 0; row < height; row++, y++) {
658 GLchan rgba[MAX_WIDTH][4];
659 if (ctx->Visual.RGBAflag) {
660 gl_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
661 }
662 else {
663 GLuint index[MAX_WIDTH];
664 (*ctx->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
665 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
666 _mesa_map_ci(ctx, readWidth, index);
667 }
668 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
669 }
670 _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
671 GL_RGBA, GL_FLOAT, dest, &_mesa_native_packing,
672 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
673 dest += width * 4;
674 }
675
676 /* do convolution */
677 if (ctx->Pixel.Convolution2DEnabled) {
678 _mesa_convolve_2d_image(ctx, &readWidth, &height, tmpImage, convImage);
679 }
680 else {
681 ASSERT(ctx->Pixel.Separable2DEnabled);
682 _mesa_convolve_sep_image(ctx, &readWidth, &height, tmpImage, convImage);
683 }
684 FREE(tmpImage);
685
686 /* finish transfer ops and pack the resulting image */
687 src = convImage;
688 for (row = 0; row < height; row++) {
689 GLvoid *dest;
690 dest = _mesa_image_address(packing, pixels, width, height,
691 format, type, 0, row, 0);
692 _mesa_pack_float_rgba_span(ctx, readWidth,
693 (const GLfloat (*)[4]) src,
694 format, type, dest, packing,
695 transferOps & IMAGE_POST_CONVOLUTION_BITS);
696 src += readWidth * 4;
697 }
698 }
699 else {
700 /* no convolution */
701 GLint row;
702 for (row = 0; row < height; row++, y++) {
703 GLchan rgba[MAX_WIDTH][4];
704 GLvoid *dst;
705 if (ctx->Visual.RGBAflag) {
706 gl_read_rgba_span(ctx, ctx->ReadBuffer, readWidth, x, y, rgba);
707 }
708 else {
709 GLuint index[MAX_WIDTH];
710 (*ctx->Driver.ReadCI32Span)(ctx, readWidth, x, y, index);
711 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
712 _mesa_map_ci(ctx, readWidth, index);
713 }
714 _mesa_map_ci_to_rgba_chan(ctx, readWidth, index, rgba);
715 }
716 dst = _mesa_image_address(packing, pixels, width, height,
717 format, type, 0, row, 0);
718 _mesa_pack_rgba_span(ctx, readWidth, (const GLchan (*)[4]) rgba,
719 format, type, dst, packing,
720 ctx->ImageTransferState);
721 }
722 }
723
724 (*ctx->Driver.SetReadBuffer)(ctx, ctx->DrawBuffer, ctx->Color.DriverDrawBuffer);
725 }
726
727
728
729 void
730 _swrast_ReadPixels( GLcontext *ctx,
731 GLint x, GLint y, GLsizei width, GLsizei height,
732 GLenum format, GLenum type,
733 const struct gl_pixelstore_attrib *pack,
734 GLvoid *pixels )
735 {
736 (void) pack;
737
738 switch (format) {
739 case GL_COLOR_INDEX:
740 read_index_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
741 break;
742 case GL_STENCIL_INDEX:
743 read_stencil_pixels(ctx, x,y, width,height, type, pixels, &ctx->Pack);
744 break;
745 case GL_DEPTH_COMPONENT:
746 read_depth_pixels(ctx, x, y, width, height, type, pixels, &ctx->Pack);
747 break;
748 case GL_RED:
749 case GL_GREEN:
750 case GL_BLUE:
751 case GL_ALPHA:
752 case GL_RGB:
753 case GL_LUMINANCE:
754 case GL_LUMINANCE_ALPHA:
755 case GL_RGBA:
756 case GL_BGR:
757 case GL_BGRA:
758 case GL_ABGR_EXT:
759 read_rgba_pixels(ctx, x, y, width, height,
760 format, type, pixels, &ctx->Pack);
761 break;
762 default:
763 gl_error( ctx, GL_INVALID_ENUM, "glReadPixels(format)" );
764 }
765 }