772bb3bb69e9184e320dcdcbe3e48ca788be4be9
[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
41 #include "pipe/p_context.h"
42 #include "pipe/p_defines.h"
43 #include "pipe/p_inlines.h"
44 #include "util/u_tile.h"
45
46 #include "st_debug.h"
47 #include "st_context.h"
48 #include "st_cb_bitmap.h"
49 #include "st_cb_readpixels.h"
50 #include "st_cb_fbo.h"
51 #include "st_format.h"
52 #include "st_public.h"
53 #include "st_texture.h"
54 #include "st_inlines.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(GLcontext *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_screen *screen = ctx->st->pipe->screen;
69 struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer);
70 struct pipe_transfer *pt;
71 ubyte *stmap;
72 GLint j;
73
74 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
75 y = ctx->DrawBuffer->Height - y - height;
76 }
77
78 /* Create a read transfer from the renderbuffer's texture */
79
80 pt = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture,
81 0, 0, 0,
82 PIPE_TRANSFER_READ, x, y,
83 width, height);
84
85 /* map the stencil buffer */
86 stmap = screen->transfer_map(screen, pt);
87
88 /* width should never be > MAX_WIDTH since we did clipping earlier */
89 ASSERT(width <= MAX_WIDTH);
90
91 /* process image row by row */
92 for (j = 0; j < height; j++) {
93 GLvoid *dest;
94 GLstencil sValues[MAX_WIDTH];
95 GLfloat zValues[MAX_WIDTH];
96 GLint srcY;
97
98 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
99 srcY = height - j - 1;
100 }
101 else {
102 srcY = j;
103 }
104
105 /* get stencil (and Z) values */
106 switch (pt->format) {
107 case PIPE_FORMAT_S8_UNORM:
108 {
109 const ubyte *src = stmap + srcY * pt->stride;
110 memcpy(sValues, src, width);
111 }
112 break;
113 case PIPE_FORMAT_S8Z24_UNORM:
114 if (format == GL_DEPTH_STENCIL) {
115 const uint *src = (uint *) (stmap + srcY * pt->stride);
116 const GLfloat scale = 1.0f / (0xffffff);
117 GLint k;
118 for (k = 0; k < width; k++) {
119 sValues[k] = src[k] >> 24;
120 zValues[k] = (src[k] & 0xffffff) * scale;
121 }
122 }
123 else {
124 const uint *src = (uint *) (stmap + srcY * pt->stride);
125 GLint k;
126 for (k = 0; k < width; k++) {
127 sValues[k] = src[k] >> 24;
128 }
129 }
130 break;
131 case PIPE_FORMAT_Z24S8_UNORM:
132 if (format == GL_DEPTH_STENCIL) {
133 const uint *src = (uint *) (stmap + srcY * pt->stride);
134 const GLfloat scale = 1.0f / (0xffffff);
135 GLint k;
136 for (k = 0; k < width; k++) {
137 sValues[k] = src[k] & 0xff;
138 zValues[k] = (src[k] >> 8) * scale;
139 }
140 }
141 else {
142 const uint *src = (uint *) (stmap + srcY * pt->stride);
143 GLint k;
144 for (k = 0; k < width; k++) {
145 sValues[k] = src[k] & 0xff;
146 }
147 }
148 break;
149 default:
150 assert(0);
151 }
152
153 /* store */
154 dest = _mesa_image_address2d(packing, pixels, width, height,
155 format, type, j, 0);
156 if (format == GL_DEPTH_STENCIL) {
157 _mesa_pack_depth_stencil_span(ctx, width, dest,
158 zValues, sValues, packing);
159 }
160 else {
161 _mesa_pack_stencil_span(ctx, width, type, dest, sValues, packing);
162 }
163 }
164
165 /* unmap the stencil buffer */
166 screen->transfer_unmap(screen, pt);
167 screen->tex_transfer_destroy(pt);
168 }
169
170
171 /**
172 * Return renderbuffer to use for reading color pixels for glRead/CopyPixel
173 * commands.
174 * Special care is needed for the front buffer.
175 */
176 struct st_renderbuffer *
177 st_get_color_read_renderbuffer(GLcontext *ctx)
178 {
179 struct gl_framebuffer *fb = ctx->ReadBuffer;
180 struct st_renderbuffer *strb =
181 st_renderbuffer(fb->_ColorReadBuffer);
182 struct st_renderbuffer *front =
183 st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
184
185 if (strb == front
186 && ctx->st->frontbuffer_status == FRONT_STATUS_COPY_OF_BACK) {
187 /* reading from front color buffer, which is a logical copy of the
188 * back color buffer.
189 */
190 struct st_renderbuffer *back =
191 st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
192 strb = back;
193 }
194
195 return strb;
196 }
197
198
199 /**
200 * Try to do glReadPixels in a fast manner for common cases.
201 * \return GL_TRUE for success, GL_FALSE for failure
202 */
203 static GLboolean
204 st_fast_readpixels(GLcontext *ctx, struct st_renderbuffer *strb,
205 GLint x, GLint y, GLsizei width, GLsizei height,
206 GLenum format, GLenum type,
207 const struct gl_pixelstore_attrib *pack,
208 GLvoid *dest)
209 {
210 enum combination {
211 A8R8G8B8_UNORM_TO_RGBA_UBYTE,
212 A8R8G8B8_UNORM_TO_RGB_UBYTE,
213 A8R8G8B8_UNORM_TO_BGRA_UINT
214 } combo;
215
216 if (ctx->_ImageTransferState)
217 return GL_FALSE;
218
219 if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
220 format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
221 combo = A8R8G8B8_UNORM_TO_RGBA_UBYTE;
222 }
223 else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
224 format == GL_RGB && type == GL_UNSIGNED_BYTE) {
225 combo = A8R8G8B8_UNORM_TO_RGB_UBYTE;
226 }
227 else if (strb->format == PIPE_FORMAT_A8R8G8B8_UNORM &&
228 format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV) {
229 combo = A8R8G8B8_UNORM_TO_BGRA_UINT;
230 }
231 else {
232 return GL_FALSE;
233 }
234
235 /*printf("st_fast_readpixels combo %d\n", (GLint) combo);*/
236
237 {
238 struct pipe_context *pipe = ctx->st->pipe;
239 struct pipe_screen *screen = pipe->screen;
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 y = strb->texture->height[0] - y - height;
247 }
248
249 trans = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture,
250 0, 0, 0,
251 PIPE_TRANSFER_READ, x, y,
252 width, height);
253 if (!trans) {
254 return GL_FALSE;
255 }
256
257 map = screen->transfer_map(screen, trans);
258 if (!map) {
259 screen->tex_transfer_destroy(trans);
260 return GL_FALSE;
261 }
262
263 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
264 y = height - 1;
265 dy = -1;
266 }
267 else {
268 y = 0;
269 dy = 1;
270 }
271
272 dst = _mesa_image_address2d(pack, dest, width, height,
273 format, type, 0, 0);
274 dstStride = _mesa_image_row_stride(pack, width, format, type);
275
276 switch (combo) {
277 case A8R8G8B8_UNORM_TO_RGBA_UBYTE:
278 for (row = 0; row < height; row++) {
279 const GLubyte *src = map + y * trans->stride;
280 for (col = 0; col < width; col++) {
281 GLuint pixel = ((GLuint *) src)[col];
282 dst[col*4+0] = (pixel >> 16) & 0xff;
283 dst[col*4+1] = (pixel >> 8) & 0xff;
284 dst[col*4+2] = (pixel >> 0) & 0xff;
285 dst[col*4+3] = (pixel >> 24) & 0xff;
286 }
287 dst += dstStride;
288 y += dy;
289 }
290 break;
291 case A8R8G8B8_UNORM_TO_RGB_UBYTE:
292 for (row = 0; row < height; row++) {
293 const GLubyte *src = map + y * trans->stride;
294 for (col = 0; col < width; col++) {
295 GLuint pixel = ((GLuint *) src)[col];
296 dst[col*3+0] = (pixel >> 16) & 0xff;
297 dst[col*3+1] = (pixel >> 8) & 0xff;
298 dst[col*3+2] = (pixel >> 0) & 0xff;
299 }
300 dst += dstStride;
301 y += dy;
302 }
303 break;
304 case A8R8G8B8_UNORM_TO_BGRA_UINT:
305 for (row = 0; row < height; row++) {
306 const GLubyte *src = map + y * trans->stride;
307 memcpy(dst, src, 4 * width);
308 dst += dstStride;
309 y += dy;
310 }
311 break;
312 default:
313 ; /* nothing */
314 }
315
316 screen->transfer_unmap(screen, trans);
317 screen->tex_transfer_destroy(trans);
318 }
319
320 return GL_TRUE;
321 }
322
323
324 /**
325 * Do glReadPixels by getting rows from the framebuffer transfer with
326 * get_tile(). Convert to requested format/type with Mesa image routines.
327 * Image transfer ops are done in software too.
328 */
329 static void
330 st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
331 GLenum format, GLenum type,
332 const struct gl_pixelstore_attrib *pack,
333 GLvoid *dest)
334 {
335 struct pipe_context *pipe = ctx->st->pipe;
336 struct pipe_screen *screen = pipe->screen;
337 GLfloat temp[MAX_WIDTH][4];
338 const GLbitfield transferOps = ctx->_ImageTransferState;
339 GLsizei i, j;
340 GLint yStep, dfStride;
341 GLfloat *df;
342 struct st_renderbuffer *strb;
343 struct gl_pixelstore_attrib clippedPacking = *pack;
344 struct pipe_transfer *trans;
345
346 assert(ctx->ReadBuffer->Width > 0);
347
348 /* XXX convolution not done yet */
349 assert((transferOps & IMAGE_CONVOLUTION_BIT) == 0);
350
351 /* Do all needed clipping here, so that we can forget about it later */
352 if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
353 /* The ReadPixels transfer is totally outside the window bounds */
354 return;
355 }
356
357 dest = _mesa_map_pbo_dest(ctx, &clippedPacking, dest);
358 if (!dest)
359 return;
360
361 st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
362
363 if (format == GL_STENCIL_INDEX ||
364 format == GL_DEPTH_STENCIL) {
365 st_read_stencil_pixels(ctx, x, y, width, height,
366 format, type, pack, dest);
367 return;
368 }
369 else if (format == GL_DEPTH_COMPONENT) {
370 strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
371 }
372 else {
373 /* Read color buffer */
374 strb = st_get_color_read_renderbuffer(ctx);
375 }
376
377 if (!strb)
378 return;
379
380 /* try a fast-path readpixels before anything else */
381 if (st_fast_readpixels(ctx, strb, x, y, width, height,
382 format, type, pack, dest)) {
383 /* success! */
384 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
385 return;
386 }
387
388 if (format == GL_RGBA && type == GL_FLOAT) {
389 /* write tile(row) directly into user's buffer */
390 df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
391 height, format, type, 0, 0);
392 dfStride = width * 4;
393 }
394 else {
395 /* write tile(row) into temp row buffer */
396 df = (GLfloat *) temp;
397 dfStride = 0;
398 }
399
400 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
401 y = strb->Base.Height - y - height;
402 }
403
404 /* Create a read transfer from the renderbuffer's texture */
405 trans = st_cond_flush_get_tex_transfer(st_context(ctx), strb->texture,
406 0, 0, 0,
407 PIPE_TRANSFER_READ, x, y,
408 width, height);
409
410 /* determine bottom-to-top vs. top-to-bottom order */
411 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
412 y = height - 1;
413 yStep = -1;
414 }
415 else {
416 y = 0;
417 yStep = 1;
418 }
419
420 if (ST_DEBUG & DEBUG_FALLBACK)
421 debug_printf("%s: fallback processing\n", __FUNCTION__);
422
423 /*
424 * Copy pixels from pipe_transfer to user memory
425 */
426 {
427 /* dest of first pixel in client memory */
428 GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width,
429 height, format, type, 0, 0);
430 /* dest row stride */
431 const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width,
432 format, type);
433
434 if (trans->format == PIPE_FORMAT_S8Z24_UNORM ||
435 trans->format == PIPE_FORMAT_X8Z24_UNORM) {
436 if (format == GL_DEPTH_COMPONENT) {
437 for (i = 0; i < height; i++) {
438 GLuint ztemp[MAX_WIDTH];
439 GLfloat zfloat[MAX_WIDTH];
440 const double scale = 1.0 / ((1 << 24) - 1);
441 pipe_get_tile_raw(trans, 0, y, width, 1, ztemp, 0);
442 y += yStep;
443 for (j = 0; j < width; j++) {
444 zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff));
445 }
446 _mesa_pack_depth_span(ctx, width, dst, type,
447 zfloat, &clippedPacking);
448 dst += dstStride;
449 }
450 }
451 else {
452 /* XXX: unreachable code -- should be before st_read_stencil_pixels */
453 assert(format == GL_DEPTH_STENCIL_EXT);
454 for (i = 0; i < height; i++) {
455 GLuint *zshort = (GLuint *)dst;
456 pipe_get_tile_raw(trans, 0, y, width, 1, dst, 0);
457 y += yStep;
458 /* Reverse into 24/8 */
459 for (j = 0; j < width; j++) {
460 zshort[j] = (zshort[j] << 8) | (zshort[j] >> 24);
461 }
462 dst += dstStride;
463 }
464 }
465 }
466 else if (trans->format == PIPE_FORMAT_Z24S8_UNORM ||
467 trans->format == PIPE_FORMAT_Z24X8_UNORM) {
468 if (format == GL_DEPTH_COMPONENT) {
469 for (i = 0; i < height; i++) {
470 GLuint ztemp[MAX_WIDTH];
471 GLfloat zfloat[MAX_WIDTH];
472 const double scale = 1.0 / ((1 << 24) - 1);
473 pipe_get_tile_raw(trans, 0, y, width, 1, ztemp, 0);
474 y += yStep;
475 for (j = 0; j < width; j++) {
476 zfloat[j] = (float) (scale * ((ztemp[j] >> 8) & 0xffffff));
477 }
478 _mesa_pack_depth_span(ctx, width, dst, type,
479 zfloat, &clippedPacking);
480 dst += dstStride;
481 }
482 }
483 else {
484 /* XXX: unreachable code -- should be before st_read_stencil_pixels */
485 assert(format == GL_DEPTH_STENCIL_EXT);
486 for (i = 0; i < height; i++) {
487 pipe_get_tile_raw(trans, 0, y, width, 1, dst, 0);
488 y += yStep;
489 dst += dstStride;
490 }
491 }
492 }
493 else if (trans->format == PIPE_FORMAT_Z16_UNORM) {
494 for (i = 0; i < height; i++) {
495 GLushort ztemp[MAX_WIDTH];
496 GLfloat zfloat[MAX_WIDTH];
497 const double scale = 1.0 / 0xffff;
498 pipe_get_tile_raw(trans, 0, y, width, 1, ztemp, 0);
499 y += yStep;
500 for (j = 0; j < width; j++) {
501 zfloat[j] = (float) (scale * ztemp[j]);
502 }
503 _mesa_pack_depth_span(ctx, width, dst, type,
504 zfloat, &clippedPacking);
505 dst += dstStride;
506 }
507 }
508 else if (trans->format == PIPE_FORMAT_Z32_UNORM) {
509 for (i = 0; i < height; i++) {
510 GLuint ztemp[MAX_WIDTH];
511 GLfloat zfloat[MAX_WIDTH];
512 const double scale = 1.0 / 0xffffffff;
513 pipe_get_tile_raw(trans, 0, y, width, 1, ztemp, 0);
514 y += yStep;
515 for (j = 0; j < width; j++) {
516 zfloat[j] = (float) (scale * ztemp[j]);
517 }
518 _mesa_pack_depth_span(ctx, width, dst, type,
519 zfloat, &clippedPacking);
520 dst += dstStride;
521 }
522 }
523 else {
524 /* RGBA format */
525 /* Do a row at a time to flip image data vertically */
526 for (i = 0; i < height; i++) {
527 pipe_get_tile_rgba(trans, 0, y, width, 1, df);
528 y += yStep;
529 df += dfStride;
530 if (!dfStride) {
531 _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst,
532 &clippedPacking, transferOps);
533 dst += dstStride;
534 }
535 }
536 }
537 }
538
539 screen->tex_transfer_destroy(trans);
540
541 _mesa_unmap_pbo_dest(ctx, &clippedPacking);
542 }
543
544
545 void st_init_readpixels_functions(struct dd_function_table *functions)
546 {
547 functions->ReadPixels = st_readpixels;
548 }