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