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