Merge remote branch 'origin/master' into pipe-video
[mesa.git] / src / mesa / state_tracker / st_cb_readpixels.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28
29 /**
30 * glReadPixels interface to pipe
31 *
32 * \author Brian Paul
33 */
34
35
36 #include "main/imports.h"
37 #include "main/bufferobj.h"
38 #include "main/context.h"
39 #include "main/image.h"
40 #include "main/pack.h"
41 #include "main/pbo.h"
42
43 #include "pipe/p_context.h"
44 #include "pipe/p_defines.h"
45 #include "util/u_format.h"
46 #include "util/u_inlines.h"
47 #include "util/u_tile.h"
48
49 #include "st_debug.h"
50 #include "st_context.h"
51 #include "st_atom.h"
52 #include "st_cb_bitmap.h"
53 #include "st_cb_readpixels.h"
54 #include "st_cb_fbo.h"
55
56 /**
57 * Special case for reading stencil buffer.
58 * For color/depth we use get_tile(). For stencil, map the stencil buffer.
59 */
60 void
61 st_read_stencil_pixels(struct gl_context *ctx, GLint x, GLint y,
62 GLsizei width, GLsizei height,
63 GLenum format, GLenum type,
64 const struct gl_pixelstore_attrib *packing,
65 GLvoid *pixels)
66 {
67 struct gl_framebuffer *fb = ctx->ReadBuffer;
68 struct pipe_context *pipe = st_context(ctx)->pipe;
69 struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer);
70 struct pipe_transfer *pt;
71 ubyte *stmap;
72 GLint j;
73
74 if (strb->Base.Wrapped) {
75 strb = st_renderbuffer(strb->Base.Wrapped);
76 }
77
78 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
79 y = ctx->DrawBuffer->Height - y - height;
80 }
81
82 /* Create a read transfer from the renderbuffer's texture */
83
84 pt = pipe_get_transfer(pipe, strb->texture,
85 0, 0,
86 PIPE_TRANSFER_READ,
87 x, y, width, height);
88
89 /* map the stencil buffer */
90 stmap = pipe_transfer_map(pipe, pt);
91
92 /* width should never be > MAX_WIDTH since we did clipping earlier */
93 ASSERT(width <= MAX_WIDTH);
94
95 /* process image row by row */
96 for (j = 0; j < height; j++) {
97 GLvoid *dest;
98 GLstencil sValues[MAX_WIDTH];
99 GLfloat zValues[MAX_WIDTH];
100 GLint srcY;
101
102 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
103 srcY = height - j - 1;
104 }
105 else {
106 srcY = j;
107 }
108
109 /* get stencil (and Z) values */
110 switch (pt->resource->format) {
111 case PIPE_FORMAT_S8_USCALED:
112 {
113 const ubyte *src = stmap + srcY * pt->stride;
114 memcpy(sValues, src, width);
115 }
116 break;
117 case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
118 if (format == GL_DEPTH_STENCIL) {
119 const uint *src = (uint *) (stmap + srcY * pt->stride);
120 const GLfloat scale = 1.0f / (0xffffff);
121 GLint k;
122 for (k = 0; k < width; k++) {
123 sValues[k] = src[k] >> 24;
124 zValues[k] = (src[k] & 0xffffff) * scale;
125 }
126 }
127 else {
128 const uint *src = (uint *) (stmap + srcY * pt->stride);
129 GLint k;
130 for (k = 0; k < width; k++) {
131 sValues[k] = src[k] >> 24;
132 }
133 }
134 break;
135 case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
136 if (format == GL_DEPTH_STENCIL) {
137 const uint *src = (uint *) (stmap + srcY * pt->stride);
138 const GLfloat scale = 1.0f / (0xffffff);
139 GLint k;
140 for (k = 0; k < width; k++) {
141 sValues[k] = src[k] & 0xff;
142 zValues[k] = (src[k] >> 8) * scale;
143 }
144 }
145 else {
146 const uint *src = (uint *) (stmap + srcY * pt->stride);
147 GLint k;
148 for (k = 0; k < width; k++) {
149 sValues[k] = src[k] & 0xff;
150 }
151 }
152 break;
153 default:
154 assert(0);
155 }
156
157 /* store */
158 dest = _mesa_image_address2d(packing, pixels, width, height,
159 format, type, j, 0);
160 if (format == GL_DEPTH_STENCIL) {
161 _mesa_pack_depth_stencil_span(ctx, width, dest,
162 zValues, sValues, packing);
163 }
164 else {
165 _mesa_pack_stencil_span(ctx, width, type, dest, sValues, packing);
166 }
167 }
168
169 /* unmap the stencil buffer */
170 pipe_transfer_unmap(pipe, pt);
171 pipe->transfer_destroy(pipe, pt);
172 }
173
174
175 /**
176 * Return renderbuffer to use for reading color pixels for glRead/CopyPixel
177 * commands.
178 */
179 struct st_renderbuffer *
180 st_get_color_read_renderbuffer(struct gl_context *ctx)
181 {
182 struct gl_framebuffer *fb = ctx->ReadBuffer;
183 struct st_renderbuffer *strb =
184 st_renderbuffer(fb->_ColorReadBuffer);
185
186 return strb;
187 }
188
189
190 /**
191 * Try to do glReadPixels in a fast manner for common cases.
192 * \return GL_TRUE for success, GL_FALSE for failure
193 */
194 static GLboolean
195 st_fast_readpixels(struct gl_context *ctx, struct st_renderbuffer *strb,
196 GLint x, GLint y, GLsizei width, GLsizei height,
197 GLenum format, GLenum type,
198 const struct gl_pixelstore_attrib *pack,
199 GLvoid *dest)
200 {
201 GLubyte alphaORoperand;
202 enum combination {
203 A8R8G8B8_UNORM_TO_RGBA_UBYTE,
204 A8R8G8B8_UNORM_TO_RGB_UBYTE,
205 A8R8G8B8_UNORM_TO_BGRA_UINT,
206 A8R8G8B8_UNORM_TO_RGBA_UINT
207 } combo;
208
209 if (ctx->_ImageTransferState)
210 return GL_FALSE;
211
212 if (strb->format == PIPE_FORMAT_B8G8R8A8_UNORM) {
213 alphaORoperand = 0;
214 }
215 else if (strb->format == PIPE_FORMAT_B8G8R8X8_UNORM ) {
216 alphaORoperand = 0xff;
217 }
218 else {
219 return GL_FALSE;
220 }
221
222 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
223 combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE;
224 }
225 else if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
226 combo = A8R8G8B8_UNORM_TO_RGB_UBYTE;
227 }
228 else if (format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
229 combo = A8R8G8B8_UNORM_TO_BGRA_UINT;
230 }
231 else if (format == GL_RGBA && type == GL_UNSIGNED_INT_8_8_8_8) {
232 combo = A8R8G8B8_UNORM_TO_RGBA_UINT;
233 }
234 else {
235 return GL_FALSE;
236 }
237
238 /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/
239
240 {
241 struct pipe_context *pipe = st_context(ctx)->pipe;
242 struct pipe_transfer *trans;
243 const GLubyte *map;
244 GLubyte *dst;
245 GLint row, col, dy, dstStride;
246
247 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
248 /* convert GL Y to Gallium Y */
249 y = strb->texture->height0 - y - height;
250 }
251
252 trans = pipe_get_transfer(pipe, strb->texture,
253 0, 0,
254 PIPE_TRANSFER_READ,
255 x, y, width, height);
256 if (!trans) {
257 return GL_FALSE;
258 }
259
260 map = pipe_transfer_map(pipe, trans);
261 if (!map) {
262 pipe->transfer_destroy(pipe, trans);
263 return GL_FALSE;
264 }
265
266 /* We always write to the user/dest buffer from low addr to high addr
267 * but the read order depends on renderbuffer orientation
268 */
269 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
270 /* read source rows from bottom to top */
271 y = height - 1;
272 dy = -1;
273 }
274 else {
275 /* read source rows from top to bottom */
276 y = 0;
277 dy = 1;
278 }
279
280 dst = _mesa_image_address2d(pack, dest, width, height,
281 format, type, 0, 0);
282 dstStride = _mesa_image_row_stride(pack, width, format, type);
283
284 switch (combo) {
285 case A8R8G8B8_UNORM_TO_RGBA_UBYTE:
286 for (row = 0; row < height; row++) {
287 const GLubyte *src = map + y * trans->stride;
288 for (col = 0; col < width; col++) {
289 GLuint pixel = ((GLuint *) src)[col];
290 dst[col*4+0] = (pixel >> 16) & 0xff;
291 dst[col*4+1] = (pixel >> 8) & 0xff;
292 dst[col*4+2] = (pixel >> 0) & 0xff;
293 dst[col*4+3] = ((pixel >> 24) & 0xff) | alphaORoperand;
294 }
295 dst += dstStride;
296 y += dy;
297 }
298 break;
299 case A8R8G8B8_UNORM_TO_RGB_UBYTE:
300 for (row = 0; row < height; row++) {
301 const GLubyte *src = map + y * trans->stride;
302 for (col = 0; col < width; col++) {
303 GLuint pixel = ((GLuint *) src)[col];
304 dst[col*3+0] = (pixel >> 16) & 0xff;
305 dst[col*3+1] = (pixel >> 8) & 0xff;
306 dst[col*3+2] = (pixel >> 0) & 0xff;
307 }
308 dst += dstStride;
309 y += dy;
310 }
311 break;
312 case A8R8G8B8_UNORM_TO_BGRA_UINT:
313 for (row = 0; row < height; row++) {
314 const GLubyte *src = map + y * trans->stride;
315 memcpy(dst, src, 4 * width);
316 if (alphaORoperand) {
317 assert(alphaORoperand == 0xff);
318 for (col = 0; col < width; col++) {
319 dst[col*4+3] = 0xff;
320 }
321 }
322 dst += dstStride;
323 y += dy;
324 }
325 break;
326 case A8R8G8B8_UNORM_TO_RGBA_UINT:
327 for (row = 0; row < height; row++) {
328 const GLubyte *src = map + y * trans->stride;
329 for (col = 0; col < width; col++) {
330 GLuint pixel = ((GLuint *) src)[col];
331 dst[col*4+0] = ((pixel >> 24) & 0xff) | alphaORoperand;
332 dst[col*4+1] = (pixel >> 0) & 0xff;
333 dst[col*4+2] = (pixel >> 8) & 0xff;
334 dst[col*4+3] = (pixel >> 16) & 0xff;
335 }
336 dst += dstStride;
337 y += dy;
338 }
339 break;
340 default:
341 ; /* nothing */
342 }
343
344 pipe_transfer_unmap(pipe, trans);
345 pipe->transfer_destroy(pipe, trans);
346 }
347
348 return GL_TRUE;
349 }
350
351
352 /**
353 * Do glReadPixels by getting rows from the framebuffer transfer with
354 * get_tile(). Convert to requested format/type with Mesa image routines.
355 * Image transfer ops are done in software too.
356 */
357 static void
358 st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
359 GLenum format, GLenum type,
360 const struct gl_pixelstore_attrib *pack,
361 GLvoid *dest)
362 {
363 struct st_context *st = st_context(ctx);
364 struct pipe_context *pipe = st->pipe;
365 GLfloat (*temp)[4];
366 GLbitfield transferOps = ctx->_ImageTransferState;
367 GLsizei i, j;
368 GLint yStep, dfStride;
369 GLfloat *df;
370 struct st_renderbuffer *strb;
371 struct gl_pixelstore_attrib clippedPacking = *pack;
372 struct pipe_transfer *trans;
373 enum pipe_format pformat;
374
375 assert(ctx->ReadBuffer->Width > 0);
376
377 st_validate_state(st);
378
379 /* Do all needed clipping here, so that we can forget about it later */
380 if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
381 /* The ReadPixels transfer is totally outside the window bounds */
382 return;
383 }
384
385 st_flush_bitmap_cache(st);
386
387 dest = _mesa_map_pbo_dest(ctx, &clippedPacking, dest);
388 if (!dest)
389 return;
390
391 if (format == GL_STENCIL_INDEX ||
392 format == GL_DEPTH_STENCIL) {
393 st_read_stencil_pixels(ctx, x, y, width, height,
394 format, type, pack, dest);
395 return;
396 }
397 else if (format == GL_DEPTH_COMPONENT) {
398 strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
399 if (strb->Base.Wrapped) {
400 strb = st_renderbuffer(strb->Base.Wrapped);
401 }
402 }
403 else {
404 /* Read color buffer */
405 strb = st_get_color_read_renderbuffer(ctx);
406 }
407
408 if (!strb)
409 return;
410
411 /* try a fast-path readpixels before anything else */
412 if (st_fast_readpixels(ctx, strb, x, y, width, height,
413 format, type, pack, dest)) {
414 /* success! */
415 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
416 return;
417 }
418
419 /* allocate temp pixel row buffer */
420 temp = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
421 if (!temp) {
422 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
423 return;
424 }
425
426 if(ctx->Color._ClampReadColor)
427 transferOps |= IMAGE_CLAMP_BIT;
428
429 if (format == GL_RGBA && type == GL_FLOAT && !transferOps) {
430 /* write tile(row) directly into user's buffer */
431 df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
432 height, format, type, 0, 0);
433 dfStride = width * 4;
434 }
435 else {
436 /* write tile(row) into temp row buffer */
437 df = (GLfloat *) temp;
438 dfStride = 0;
439 }
440
441 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
442 /* convert GL Y to Gallium Y */
443 y = strb->Base.Height - y - height;
444 }
445
446 /* Create a read transfer from the renderbuffer's texture */
447 trans = pipe_get_transfer(pipe, strb->texture,
448 0, 0,
449 PIPE_TRANSFER_READ,
450 x, y, width, height);
451
452 /* determine bottom-to-top vs. top-to-bottom order */
453 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
454 y = height - 1;
455 yStep = -1;
456 }
457 else {
458 y = 0;
459 yStep = 1;
460 }
461
462 /* possibly convert sRGB format to linear RGB format */
463 pformat = util_format_linear(trans->resource->format);
464
465 if (ST_DEBUG & DEBUG_FALLBACK)
466 debug_printf("%s: fallback processing\n", __FUNCTION__);
467
468 /*
469 * Copy pixels from pipe_transfer to user memory
470 */
471 {
472 /* dest of first pixel in client memory */
473 GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width,
474 height, format, type, 0, 0);
475 /* dest row stride */
476 const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width,
477 format, type);
478
479 if (pformat == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
480 pformat == PIPE_FORMAT_Z24X8_UNORM) {
481 if (format == GL_DEPTH_COMPONENT) {
482 for (i = 0; i < height; i++) {
483 GLuint ztemp[MAX_WIDTH];
484 GLfloat zfloat[MAX_WIDTH];
485 const double scale = 1.0 / ((1 << 24) - 1);
486 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
487 y += yStep;
488 for (j = 0; j < width; j++) {
489 zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff));
490 }
491 _mesa_pack_depth_span(ctx, width, dst, type,
492 zfloat, &clippedPacking);
493 dst += dstStride;
494 }
495 }
496 else {
497 /* XXX: unreachable code -- should be before st_read_stencil_pixels */
498 assert(format == GL_DEPTH_STENCIL_EXT);
499 for (i = 0; i < height; i++) {
500 GLuint *zshort = (GLuint *)dst;
501 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0);
502 y += yStep;
503 /* Reverse into 24/8 */
504 for (j = 0; j < width; j++) {
505 zshort[j] = (zshort[j] << 8) | (zshort[j] >> 24);
506 }
507 dst += dstStride;
508 }
509 }
510 }
511 else if (pformat == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
512 pformat == PIPE_FORMAT_X8Z24_UNORM) {
513 if (format == GL_DEPTH_COMPONENT) {
514 for (i = 0; i < height; i++) {
515 GLuint ztemp[MAX_WIDTH];
516 GLfloat zfloat[MAX_WIDTH];
517 const double scale = 1.0 / ((1 << 24) - 1);
518 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
519 y += yStep;
520 for (j = 0; j < width; j++) {
521 zfloat[j] = (float) (scale * ((ztemp[j] >> 8) & 0xffffff));
522 }
523 _mesa_pack_depth_span(ctx, width, dst, type,
524 zfloat, &clippedPacking);
525 dst += dstStride;
526 }
527 }
528 else {
529 /* XXX: unreachable code -- should be before st_read_stencil_pixels */
530 assert(format == GL_DEPTH_STENCIL_EXT);
531 for (i = 0; i < height; i++) {
532 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0);
533 y += yStep;
534 dst += dstStride;
535 }
536 }
537 }
538 else if (pformat == PIPE_FORMAT_Z16_UNORM) {
539 for (i = 0; i < height; i++) {
540 GLushort ztemp[MAX_WIDTH];
541 GLfloat zfloat[MAX_WIDTH];
542 const double scale = 1.0 / 0xffff;
543 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
544 y += yStep;
545 for (j = 0; j < width; j++) {
546 zfloat[j] = (float) (scale * ztemp[j]);
547 }
548 _mesa_pack_depth_span(ctx, width, dst, type,
549 zfloat, &clippedPacking);
550 dst += dstStride;
551 }
552 }
553 else if (pformat == PIPE_FORMAT_Z32_UNORM) {
554 for (i = 0; i < height; i++) {
555 GLuint ztemp[MAX_WIDTH];
556 GLfloat zfloat[MAX_WIDTH];
557 const double scale = 1.0 / 0xffffffff;
558 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
559 y += yStep;
560 for (j = 0; j < width; j++) {
561 zfloat[j] = (float) (scale * ztemp[j]);
562 }
563 _mesa_pack_depth_span(ctx, width, dst, type,
564 zfloat, &clippedPacking);
565 dst += dstStride;
566 }
567 }
568 else {
569 /* RGBA format */
570 /* Do a row at a time to flip image data vertically */
571 for (i = 0; i < height; i++) {
572 pipe_get_tile_rgba_format(pipe, trans, 0, y, width, 1,
573 pformat, df);
574 y += yStep;
575 df += dfStride;
576 if (!dfStride) {
577 _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst,
578 &clippedPacking, transferOps);
579 dst += dstStride;
580 }
581 }
582 }
583 }
584
585 free(temp);
586
587 pipe->transfer_destroy(pipe, trans);
588
589 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
590 }
591
592
593 void st_init_readpixels_functions(struct dd_function_table *functions)
594 {
595 functions->ReadPixels = st_readpixels;
596 }