st/mesa: add handling for 'PIPE_FORMAT_B8G8R8X8_UNORM' in st_fast_readpixels
[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 } else if (strb->format == PIPE_FORMAT_B8G8R8X8_UNORM ) {
215 alphaORoperand = 0xff;
216 } else {
217 return GL_FALSE;
218 }
219
220 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
221 combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE;
222 }
223 else if (format == GL_RGB && type == GL_UNSIGNED_BYTE) {
224 combo = A8R8G8B8_UNORM_TO_RGB_UBYTE;
225 }
226 else if (format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
227 combo = A8R8G8B8_UNORM_TO_BGRA_UINT;
228 }
229 else if (format == GL_RGBA && type == GL_UNSIGNED_INT_8_8_8_8) {
230 combo = A8R8G8B8_UNORM_TO_RGBA_UINT;
231 }
232 else {
233 return GL_FALSE;
234 }
235
236 /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/
237
238 {
239 struct pipe_context *pipe = st_context(ctx)->pipe;
240 struct pipe_transfer *trans;
241 const GLubyte *map;
242 GLubyte *dst;
243 GLint row, col, dy, dstStride;
244
245 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
246 /* convert GL Y to Gallium Y */
247 y = strb->texture->height0 - y - height;
248 }
249
250 trans = pipe_get_transfer(pipe, strb->texture,
251 0, 0,
252 PIPE_TRANSFER_READ,
253 x, y, width, height);
254 if (!trans) {
255 return GL_FALSE;
256 }
257
258 map = pipe_transfer_map(pipe, trans);
259 if (!map) {
260 pipe->transfer_destroy(pipe, trans);
261 return GL_FALSE;
262 }
263
264 /* We always write to the user/dest buffer from low addr to high addr
265 * but the read order depends on renderbuffer orientation
266 */
267 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
268 /* read source rows from bottom to top */
269 y = height - 1;
270 dy = -1;
271 }
272 else {
273 /* read source rows from top to bottom */
274 y = 0;
275 dy = 1;
276 }
277
278 dst = _mesa_image_address2d(pack, dest, width, height,
279 format, type, 0, 0);
280 dstStride = _mesa_image_row_stride(pack, width, format, type);
281
282 switch (combo) {
283 case A8R8G8B8_UNORM_TO_RGBA_UBYTE:
284 for (row = 0; row < height; row++) {
285 const GLubyte *src = map + y * trans->stride;
286 for (col = 0; col < width; col++) {
287 GLuint pixel = ((GLuint *) src)[col];
288 dst[col*4+0] = (pixel >> 16) & 0xff;
289 dst[col*4+1] = (pixel >> 8) & 0xff;
290 dst[col*4+2] = (pixel >> 0) & 0xff;
291 dst[col*4+3] = ((pixel >> 24) & 0xff) | alphaORoperand;
292 }
293 dst += dstStride;
294 y += dy;
295 }
296 break;
297 case A8R8G8B8_UNORM_TO_RGB_UBYTE:
298 for (row = 0; row < height; row++) {
299 const GLubyte *src = map + y * trans->stride;
300 for (col = 0; col < width; col++) {
301 GLuint pixel = ((GLuint *) src)[col];
302 dst[col*3+0] = (pixel >> 16) & 0xff;
303 dst[col*3+1] = (pixel >> 8) & 0xff;
304 dst[col*3+2] = (pixel >> 0) & 0xff;
305 }
306 dst += dstStride;
307 y += dy;
308 }
309 break;
310 case A8R8G8B8_UNORM_TO_BGRA_UINT:
311 for (row = 0; row < height; row++) {
312 const GLubyte *src = map + y * trans->stride;
313 memcpy(dst, src, 4 * width);
314 if (alphaORoperand) {
315 for (col = 0; col < width; col++) {
316 dst[col*4+3] |= alphaORoperand;
317 }
318 }
319 dst += dstStride;
320 y += dy;
321 }
322 break;
323 case A8R8G8B8_UNORM_TO_RGBA_UINT:
324 for (row = 0; row < height; row++) {
325 const GLubyte *src = map + y * trans->stride;
326 for (col = 0; col < width; col++) {
327 GLuint pixel = ((GLuint *) src)[col];
328 dst[col*4+0] = ((pixel >> 24) & 0xff) | alphaORoperand;
329 dst[col*4+1] = (pixel >> 0) & 0xff;
330 dst[col*4+2] = (pixel >> 8) & 0xff;
331 dst[col*4+3] = (pixel >> 16) & 0xff;
332 }
333 dst += dstStride;
334 y += dy;
335 }
336 break;
337 default:
338 ; /* nothing */
339 }
340
341 pipe_transfer_unmap(pipe, trans);
342 pipe->transfer_destroy(pipe, trans);
343 }
344
345 return GL_TRUE;
346 }
347
348
349 /**
350 * Do glReadPixels by getting rows from the framebuffer transfer with
351 * get_tile(). Convert to requested format/type with Mesa image routines.
352 * Image transfer ops are done in software too.
353 */
354 static void
355 st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
356 GLenum format, GLenum type,
357 const struct gl_pixelstore_attrib *pack,
358 GLvoid *dest)
359 {
360 struct st_context *st = st_context(ctx);
361 struct pipe_context *pipe = st->pipe;
362 GLfloat (*temp)[4];
363 GLbitfield transferOps = ctx->_ImageTransferState;
364 GLsizei i, j;
365 GLint yStep, dfStride;
366 GLfloat *df;
367 struct st_renderbuffer *strb;
368 struct gl_pixelstore_attrib clippedPacking = *pack;
369 struct pipe_transfer *trans;
370 enum pipe_format pformat;
371
372 assert(ctx->ReadBuffer->Width > 0);
373
374 st_validate_state(st);
375
376 /* Do all needed clipping here, so that we can forget about it later */
377 if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
378 /* The ReadPixels transfer is totally outside the window bounds */
379 return;
380 }
381
382 st_flush_bitmap_cache(st);
383
384 dest = _mesa_map_pbo_dest(ctx, &clippedPacking, dest);
385 if (!dest)
386 return;
387
388 if (format == GL_STENCIL_INDEX ||
389 format == GL_DEPTH_STENCIL) {
390 st_read_stencil_pixels(ctx, x, y, width, height,
391 format, type, pack, dest);
392 return;
393 }
394 else if (format == GL_DEPTH_COMPONENT) {
395 strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
396 if (strb->Base.Wrapped) {
397 strb = st_renderbuffer(strb->Base.Wrapped);
398 }
399 }
400 else {
401 /* Read color buffer */
402 strb = st_get_color_read_renderbuffer(ctx);
403 }
404
405 if (!strb)
406 return;
407
408 /* try a fast-path readpixels before anything else */
409 if (st_fast_readpixels(ctx, strb, x, y, width, height,
410 format, type, pack, dest)) {
411 /* success! */
412 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
413 return;
414 }
415
416 /* allocate temp pixel row buffer */
417 temp = (GLfloat (*)[4]) malloc(4 * width * sizeof(GLfloat));
418 if (!temp) {
419 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glReadPixels");
420 return;
421 }
422
423 if(ctx->Color._ClampReadColor)
424 transferOps |= IMAGE_CLAMP_BIT;
425
426 if (format == GL_RGBA && type == GL_FLOAT && !transferOps) {
427 /* write tile(row) directly into user's buffer */
428 df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
429 height, format, type, 0, 0);
430 dfStride = width * 4;
431 }
432 else {
433 /* write tile(row) into temp row buffer */
434 df = (GLfloat *) temp;
435 dfStride = 0;
436 }
437
438 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
439 /* convert GL Y to Gallium Y */
440 y = strb->Base.Height - y - height;
441 }
442
443 /* Create a read transfer from the renderbuffer's texture */
444 trans = pipe_get_transfer(pipe, strb->texture,
445 0, 0,
446 PIPE_TRANSFER_READ,
447 x, y, width, height);
448
449 /* determine bottom-to-top vs. top-to-bottom order */
450 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
451 y = height - 1;
452 yStep = -1;
453 }
454 else {
455 y = 0;
456 yStep = 1;
457 }
458
459 /* possibly convert sRGB format to linear RGB format */
460 pformat = util_format_linear(trans->resource->format);
461
462 if (ST_DEBUG & DEBUG_FALLBACK)
463 debug_printf("%s: fallback processing\n", __FUNCTION__);
464
465 /*
466 * Copy pixels from pipe_transfer to user memory
467 */
468 {
469 /* dest of first pixel in client memory */
470 GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width,
471 height, format, type, 0, 0);
472 /* dest row stride */
473 const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width,
474 format, type);
475
476 if (pformat == PIPE_FORMAT_Z24_UNORM_S8_USCALED ||
477 pformat == PIPE_FORMAT_Z24X8_UNORM) {
478 if (format == GL_DEPTH_COMPONENT) {
479 for (i = 0; i < height; i++) {
480 GLuint ztemp[MAX_WIDTH];
481 GLfloat zfloat[MAX_WIDTH];
482 const double scale = 1.0 / ((1 << 24) - 1);
483 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
484 y += yStep;
485 for (j = 0; j < width; j++) {
486 zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff));
487 }
488 _mesa_pack_depth_span(ctx, width, dst, type,
489 zfloat, &clippedPacking);
490 dst += dstStride;
491 }
492 }
493 else {
494 /* XXX: unreachable code -- should be before st_read_stencil_pixels */
495 assert(format == GL_DEPTH_STENCIL_EXT);
496 for (i = 0; i < height; i++) {
497 GLuint *zshort = (GLuint *)dst;
498 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0);
499 y += yStep;
500 /* Reverse into 24/8 */
501 for (j = 0; j < width; j++) {
502 zshort[j] = (zshort[j] << 8) | (zshort[j] >> 24);
503 }
504 dst += dstStride;
505 }
506 }
507 }
508 else if (pformat == PIPE_FORMAT_S8_USCALED_Z24_UNORM ||
509 pformat == PIPE_FORMAT_X8Z24_UNORM) {
510 if (format == GL_DEPTH_COMPONENT) {
511 for (i = 0; i < height; i++) {
512 GLuint ztemp[MAX_WIDTH];
513 GLfloat zfloat[MAX_WIDTH];
514 const double scale = 1.0 / ((1 << 24) - 1);
515 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
516 y += yStep;
517 for (j = 0; j < width; j++) {
518 zfloat[j] = (float) (scale * ((ztemp[j] >> 8) & 0xffffff));
519 }
520 _mesa_pack_depth_span(ctx, width, dst, type,
521 zfloat, &clippedPacking);
522 dst += dstStride;
523 }
524 }
525 else {
526 /* XXX: unreachable code -- should be before st_read_stencil_pixels */
527 assert(format == GL_DEPTH_STENCIL_EXT);
528 for (i = 0; i < height; i++) {
529 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, dst, 0);
530 y += yStep;
531 dst += dstStride;
532 }
533 }
534 }
535 else if (pformat == PIPE_FORMAT_Z16_UNORM) {
536 for (i = 0; i < height; i++) {
537 GLushort ztemp[MAX_WIDTH];
538 GLfloat zfloat[MAX_WIDTH];
539 const double scale = 1.0 / 0xffff;
540 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
541 y += yStep;
542 for (j = 0; j < width; j++) {
543 zfloat[j] = (float) (scale * ztemp[j]);
544 }
545 _mesa_pack_depth_span(ctx, width, dst, type,
546 zfloat, &clippedPacking);
547 dst += dstStride;
548 }
549 }
550 else if (pformat == PIPE_FORMAT_Z32_UNORM) {
551 for (i = 0; i < height; i++) {
552 GLuint ztemp[MAX_WIDTH];
553 GLfloat zfloat[MAX_WIDTH];
554 const double scale = 1.0 / 0xffffffff;
555 pipe_get_tile_raw(pipe, trans, 0, y, width, 1, ztemp, 0);
556 y += yStep;
557 for (j = 0; j < width; j++) {
558 zfloat[j] = (float) (scale * ztemp[j]);
559 }
560 _mesa_pack_depth_span(ctx, width, dst, type,
561 zfloat, &clippedPacking);
562 dst += dstStride;
563 }
564 }
565 else {
566 /* RGBA format */
567 /* Do a row at a time to flip image data vertically */
568 for (i = 0; i < height; i++) {
569 pipe_get_tile_rgba_format(pipe, trans, 0, y, width, 1,
570 pformat, df);
571 y += yStep;
572 df += dfStride;
573 if (!dfStride) {
574 _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst,
575 &clippedPacking, transferOps);
576 dst += dstStride;
577 }
578 }
579 }
580 }
581
582 free(temp);
583
584 pipe->transfer_destroy(pipe, trans);
585
586 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
587 }
588
589
590 void st_init_readpixels_functions(struct dd_function_table *functions)
591 {
592 functions->ReadPixels = st_readpixels;
593 }