423661a872f05dd4713d7a50eed99f08577a8fdf
[mesa.git] / src / mesa / swrast / s_readpix.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2005 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 * Read a block of color index pixels.
45 */
46 static void
47 read_index_pixels( GLcontext *ctx,
48 GLint x, GLint y,
49 GLsizei width, GLsizei height,
50 GLenum type, GLvoid *pixels,
51 const struct gl_pixelstore_attrib *packing )
52 {
53 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
54 GLint i;
55
56 if (!rb) {
57 return; /* no readbuffer OK */
58 }
59
60 /* width should never be > MAX_WIDTH since we did clipping earlier */
61 ASSERT(width <= MAX_WIDTH);
62
63 /* process image row by row */
64 for (i = 0; i < height; i++) {
65 GLuint index[MAX_WIDTH];
66 GLvoid *dest;
67 ASSERT(rb->DataType == GL_UNSIGNED_INT);
68 rb->GetRow(ctx, rb, width, x, y + i, index);
69
70 dest = _mesa_image_address2d(packing, pixels, width, height,
71 GL_COLOR_INDEX, type, i, 0);
72
73 _mesa_pack_index_span(ctx, width, type, dest, index,
74 &ctx->Pack, ctx->_ImageTransferState);
75 }
76 }
77
78
79
80 /**
81 * Read pixels for format=GL_DEPTH_COMPONENT.
82 */
83 static void
84 read_depth_pixels( GLcontext *ctx,
85 GLint x, GLint y,
86 GLsizei width, GLsizei height,
87 GLenum type, GLvoid *pixels,
88 const struct gl_pixelstore_attrib *packing )
89 {
90 struct gl_framebuffer *fb = ctx->ReadBuffer;
91 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
92 GLboolean bias_or_scale;
93
94 /* clipping should have been done already */
95 ASSERT(x >= 0);
96 ASSERT(y >= 0);
97 ASSERT(x + width <= rb->Width);
98 ASSERT(y + height <= rb->Height);
99 /* width should never be > MAX_WIDTH since we did clipping earlier */
100 ASSERT(width <= MAX_WIDTH);
101
102 if (!rb) {
103 return; /* no readbuffer OK */
104 }
105
106 bias_or_scale = ctx->Pixel.DepthBias != 0.0 || ctx->Pixel.DepthScale != 1.0;
107
108 if (type == GL_UNSIGNED_SHORT && fb->Visual.depthBits == 16
109 && !bias_or_scale && !packing->SwapBytes) {
110 /* Special case: directly read 16-bit unsigned depth values. */
111 GLint j;
112 ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT16);
113 ASSERT(rb->DataType == GL_UNSIGNED_SHORT);
114 for (j = 0; j < height; j++, y++) {
115 void *dest =_mesa_image_address2d(packing, pixels, width, height,
116 GL_DEPTH_COMPONENT, type, j, 0);
117 rb->GetRow(ctx, rb, width, x, y, dest);
118 }
119 }
120 else if (type == GL_UNSIGNED_INT && fb->Visual.depthBits == 32
121 && !bias_or_scale && !packing->SwapBytes) {
122 /* Special case: directly read 32-bit unsigned depth values. */
123 GLint j;
124 ASSERT(rb->InternalFormat == GL_DEPTH_COMPONENT32);
125 ASSERT(rb->DataType == GL_UNSIGNED_INT);
126 for (j = 0; j < height; j++, y++) {
127 void *dest = _mesa_image_address2d(packing, pixels, width, height,
128 GL_DEPTH_COMPONENT, type, j, 0);
129 rb->GetRow(ctx, rb, width, x, y, dest);
130 }
131 }
132 else {
133 /* General case (slower) */
134 GLint j;
135 for (j = 0; j < height; j++, y++) {
136 GLfloat depthValues[MAX_WIDTH];
137 GLvoid *dest = _mesa_image_address2d(packing, pixels, width, height,
138 GL_DEPTH_COMPONENT, type, j, 0);
139 _swrast_read_depth_span_float(ctx, rb, width, x, y, depthValues);
140 _mesa_pack_depth_span(ctx, width, dest, type, depthValues, packing);
141 }
142 }
143 }
144
145
146 /**
147 * Read pixels for format=GL_STENCIL_INDEX.
148 */
149 static void
150 read_stencil_pixels( GLcontext *ctx,
151 GLint x, GLint y,
152 GLsizei width, GLsizei height,
153 GLenum type, GLvoid *pixels,
154 const struct gl_pixelstore_attrib *packing )
155 {
156 struct gl_framebuffer *fb = ctx->ReadBuffer;
157 struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
158 GLint j;
159
160 if (!rb) {
161 /* no readbuffer - OK */
162 return;
163 }
164
165 /* width should never be > MAX_WIDTH since we did clipping earlier */
166 ASSERT(width <= MAX_WIDTH);
167
168 /* process image row by row */
169 for (j=0;j<height;j++,y++) {
170 GLvoid *dest;
171 GLstencil stencil[MAX_WIDTH];
172
173 _swrast_read_stencil_span(ctx, rb, width, x, y, stencil);
174
175 dest = _mesa_image_address2d(packing, pixels, width, height,
176 GL_STENCIL_INDEX, type, j, 0);
177
178 _mesa_pack_stencil_span(ctx, width, type, dest, stencil, packing);
179 }
180 }
181
182
183
184 /**
185 * Optimized glReadPixels for particular pixel formats:
186 * GL_UNSIGNED_BYTE, GL_RGBA
187 * when pixel scaling, biasing and mapping are disabled.
188 */
189 static GLboolean
190 read_fast_rgba_pixels( GLcontext *ctx,
191 GLint x, GLint y,
192 GLsizei width, GLsizei height,
193 GLenum format, GLenum type,
194 GLvoid *pixels,
195 const struct gl_pixelstore_attrib *packing )
196 {
197 struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
198
199 /* can't do scale, bias, mapping, etc */
200 if (ctx->_ImageTransferState)
201 return GL_FALSE;
202
203 /* can't do fancy pixel packing */
204 if (packing->Alignment != 1 || packing->SwapBytes || packing->LsbFirst)
205 return GL_FALSE;
206
207 {
208 GLint srcX = x;
209 GLint srcY = y;
210 GLint readWidth = width; /* actual width read */
211 GLint readHeight = height; /* actual height read */
212 GLint skipPixels = packing->SkipPixels;
213 GLint skipRows = packing->SkipRows;
214 GLint rowLength;
215
216 if (packing->RowLength > 0)
217 rowLength = packing->RowLength;
218 else
219 rowLength = width;
220
221 /*
222 * Ready to read!
223 * The window region at (destX, destY) of size (readWidth, readHeight)
224 * will be read back.
225 * We'll write pixel data to buffer pointed to by "pixels" but we'll
226 * skip "skipRows" rows and skip "skipPixels" pixels/row.
227 */
228 #if CHAN_BITS == 8
229 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE)
230 #elif CHAN_BITS == 16
231 if (format == GL_RGBA && type == GL_UNSIGNED_SHORT)
232 #else
233 if (0)
234 #endif
235 {
236 GLchan *dest = (GLchan *) pixels
237 + (skipRows * rowLength + skipPixels) * 4;
238 GLint row;
239
240 if (packing->Invert) {
241 /* start at top and go down */
242 dest += (readHeight - 1) * rowLength * 4;
243 rowLength = -rowLength;
244 }
245
246 ASSERT(rb->GetRow);
247 for (row=0; row<readHeight; row++) {
248 rb->GetRow(ctx, rb, readWidth, srcX, srcY, dest);
249 dest += rowLength * 4;
250 srcY++;
251 }
252 return GL_TRUE;
253 }
254 else {
255 /* can't do this format/type combination */
256 return GL_FALSE;
257 }
258 }
259 }
260
261
262
263 /*
264 * Read R, G, B, A, RGB, L, or LA pixels.
265 */
266 static void
267 read_rgba_pixels( GLcontext *ctx,
268 GLint x, GLint y,
269 GLsizei width, GLsizei height,
270 GLenum format, GLenum type, GLvoid *pixels,
271 const struct gl_pixelstore_attrib *packing )
272 {
273 struct gl_framebuffer *fb = ctx->ReadBuffer;
274 struct gl_renderbuffer *rb = fb->_ColorReadBuffer;
275
276 if (!rb) {
277 /* No readbuffer is OK with GL_EXT_framebuffer_object */
278 return;
279 }
280
281 /* Try optimized path first */
282 if (read_fast_rgba_pixels( ctx, x, y, width, height,
283 format, type, pixels, packing )) {
284 return; /* done! */
285 }
286
287 /* width should never be > MAX_WIDTH since we did clipping earlier */
288 ASSERT(width <= MAX_WIDTH);
289
290 if (ctx->Pixel.Convolution2DEnabled || ctx->Pixel.Separable2DEnabled) {
291 const GLuint transferOps = ctx->_ImageTransferState;
292 GLfloat *dest, *src, *tmpImage, *convImage;
293 GLint row;
294
295 tmpImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
296 if (!tmpImage) {
297 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
298 return;
299 }
300 convImage = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
301 if (!convImage) {
302 _mesa_free(tmpImage);
303 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
304 return;
305 }
306
307 /* read full RGBA, FLOAT image */
308 dest = tmpImage;
309 for (row = 0; row < height; row++, y++) {
310 GLchan rgba[MAX_WIDTH][4];
311 if (fb->Visual.rgbMode) {
312 _swrast_read_rgba_span(ctx, rb, width, x, y, rgba);
313 }
314 else {
315 GLuint index[MAX_WIDTH];
316 ASSERT(rb->DataType == GL_UNSIGNED_INT);
317 rb->GetRow(ctx, rb, width, x, y, index);
318 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset !=0 ) {
319 _mesa_map_ci(ctx, width, index);
320 }
321 _mesa_map_ci_to_rgba_chan(ctx, width, index, rgba);
322 }
323 _mesa_pack_rgba_span_chan(ctx, width, (const GLchan (*)[4]) rgba,
324 GL_RGBA, GL_FLOAT, dest, &ctx->DefaultPacking,
325 transferOps & IMAGE_PRE_CONVOLUTION_BITS);
326 dest += width * 4;
327 }
328
329 /* do convolution */
330 if (ctx->Pixel.Convolution2DEnabled) {
331 _mesa_convolve_2d_image(ctx, &width, &height, tmpImage, convImage);
332 }
333 else {
334 ASSERT(ctx->Pixel.Separable2DEnabled);
335 _mesa_convolve_sep_image(ctx, &width, &height, tmpImage, convImage);
336 }
337 _mesa_free(tmpImage);
338
339 /* finish transfer ops and pack the resulting image */
340 src = convImage;
341 for (row = 0; row < height; row++) {
342 GLvoid *dest;
343 dest = _mesa_image_address2d(packing, pixels, width, height,
344 format, type, row, 0);
345 _mesa_pack_rgba_span_float(ctx, width,
346 (const GLfloat (*)[4]) src,
347 format, type, dest, packing,
348 transferOps & IMAGE_POST_CONVOLUTION_BITS);
349 src += width * 4;
350 }
351 }
352 else {
353 /* no convolution */
354 GLint row;
355 for (row = 0; row < height; row++, y++) {
356 GLchan rgba[MAX_WIDTH][4];
357 GLvoid *dst;
358 if (fb->Visual.rgbMode) {
359 _swrast_read_rgba_span(ctx, rb, width, x, y, rgba);
360 }
361 else {
362 GLuint index[MAX_WIDTH];
363 ASSERT(rb->DataType == GL_UNSIGNED_INT);
364 rb->GetRow(ctx, rb, width, x, y, index);
365 if (ctx->Pixel.IndexShift != 0 || ctx->Pixel.IndexOffset != 0) {
366 _mesa_map_ci(ctx, width, index);
367 }
368 _mesa_map_ci_to_rgba_chan(ctx, width, index, rgba);
369 }
370 dst = _mesa_image_address2d(packing, pixels, width, height,
371 format, type, row, 0);
372 if (fb->Visual.redBits < CHAN_BITS ||
373 fb->Visual.greenBits < CHAN_BITS ||
374 fb->Visual.blueBits < CHAN_BITS) {
375 /* Requantize the color values into floating point and go from
376 * there. This fixes conformance failures with 16-bit color
377 * buffers, for example.
378 */
379 GLfloat rgbaf[MAX_WIDTH][4];
380 _mesa_chan_to_float_span(ctx, width,
381 (CONST GLchan (*)[4]) rgba, rgbaf);
382 _mesa_pack_rgba_span_float(ctx, width,
383 (CONST GLfloat (*)[4]) rgbaf,
384 format, type, dst, packing,
385 ctx->_ImageTransferState);
386 }
387 else {
388 /* GLubytes are fine */
389 _mesa_pack_rgba_span_chan(ctx, width, (CONST GLchan (*)[4]) rgba,
390 format, type, dst, packing,
391 ctx->_ImageTransferState);
392 }
393 }
394 }
395 }
396
397
398 /**
399 * Software fallback routine for ctx->Driver.ReadPixels().
400 * By time we get here, all error checking will have been done.
401 */
402 void
403 _swrast_ReadPixels( GLcontext *ctx,
404 GLint x, GLint y, GLsizei width, GLsizei height,
405 GLenum format, GLenum type,
406 const struct gl_pixelstore_attrib *packing,
407 GLvoid *pixels )
408 {
409 SWcontext *swrast = SWRAST_CONTEXT(ctx);
410 struct gl_pixelstore_attrib clippedPacking;
411
412 if (swrast->NewState)
413 _swrast_validate_derived( ctx );
414
415 /* Do all needed clipping here, so that we can forget about it later */
416 clippedPacking = *packing;
417 if (clippedPacking.RowLength == 0) {
418 clippedPacking.RowLength = width;
419 }
420 if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height,
421 &clippedPacking.SkipPixels,
422 &clippedPacking.SkipRows)) {
423 /* The ReadPixels region is totally outside the window bounds */
424 return;
425 }
426
427 if (clippedPacking.BufferObj->Name) {
428 /* pack into PBO */
429 GLubyte *buf;
430 if (!_mesa_validate_pbo_access(2, &clippedPacking, width, height, 1,
431 format, type, pixels)) {
432 _mesa_error(ctx, GL_INVALID_OPERATION,
433 "glReadPixels(invalid PBO access)");
434 return;
435 }
436 buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
437 GL_WRITE_ONLY_ARB,
438 clippedPacking.BufferObj);
439 if (!buf) {
440 /* buffer is already mapped - that's an error */
441 _mesa_error(ctx, GL_INVALID_OPERATION, "glReadPixels(PBO is mapped)");
442 return;
443 }
444 pixels = ADD_POINTERS(buf, pixels);
445 }
446
447 RENDER_START(swrast, ctx);
448
449 switch (format) {
450 case GL_COLOR_INDEX:
451 read_index_pixels(ctx, x, y, width, height, type, pixels,
452 &clippedPacking);
453 break;
454 case GL_STENCIL_INDEX:
455 read_stencil_pixels(ctx, x, y, width, height, type, pixels,
456 &clippedPacking);
457 break;
458 case GL_DEPTH_COMPONENT:
459 read_depth_pixels(ctx, x, y, width, height, type, pixels,
460 &clippedPacking);
461 break;
462 case GL_RED:
463 case GL_GREEN:
464 case GL_BLUE:
465 case GL_ALPHA:
466 case GL_RGB:
467 case GL_LUMINANCE:
468 case GL_LUMINANCE_ALPHA:
469 case GL_RGBA:
470 case GL_BGR:
471 case GL_BGRA:
472 case GL_ABGR_EXT:
473 read_rgba_pixels(ctx, x, y, width, height,
474 format, type, pixels, &clippedPacking);
475 break;
476 default:
477 _mesa_problem(ctx, "unexpected format in _swrast_ReadPixels");
478 /* don't return yet, clean-up */
479 }
480
481 RENDER_FINISH(swrast, ctx);
482
483 if (clippedPacking.BufferObj->Name) {
484 /* done with PBO so unmap it now */
485 ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_PACK_BUFFER_EXT,
486 clippedPacking.BufferObj);
487 }
488 }