Merge remote branch 'upstream/gallium-0.1' into nouveau-gallium-0.1
[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/p_tile.h"
45 #include "st_context.h"
46 #include "st_cb_bitmap.h"
47 #include "st_cb_readpixels.h"
48 #include "st_cb_fbo.h"
49 #include "st_format.h"
50 #include "st_public.h"
51
52
53 /**
54 * Special case for reading stencil buffer.
55 * For color/depth we use get_tile(). For stencil, map the stencil buffer.
56 */
57 void
58 st_read_stencil_pixels(GLcontext *ctx, GLint x, GLint y,
59 GLsizei width, GLsizei height, GLenum type,
60 const struct gl_pixelstore_attrib *packing,
61 GLvoid *pixels)
62 {
63 struct gl_framebuffer *fb = ctx->ReadBuffer;
64 struct st_renderbuffer *strb = st_renderbuffer(fb->_StencilBuffer);
65 struct pipe_surface *ps = strb->surface;
66 ubyte *stmap;
67 GLint j;
68
69 /* map the stencil buffer */
70 stmap = pipe_surface_map(ps);
71
72 /* width should never be > MAX_WIDTH since we did clipping earlier */
73 ASSERT(width <= MAX_WIDTH);
74
75 /* process image row by row */
76 for (j = 0; j < height; j++, y++) {
77 GLvoid *dest;
78 GLstencil values[MAX_WIDTH];
79 GLint srcY;
80
81 if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP) {
82 srcY = ctx->DrawBuffer->Height - y - 1;
83 }
84 else {
85 srcY = y;
86 }
87
88 /* get stencil values */
89 switch (ps->format) {
90 case PIPE_FORMAT_S8_UNORM:
91 {
92 const ubyte *src = stmap + srcY * ps->pitch + x;
93 memcpy(values, src, width);
94 }
95 break;
96 case PIPE_FORMAT_S8Z24_UNORM:
97 {
98 const uint *src = (uint *) stmap + srcY * ps->pitch + x;
99 GLint k;
100 for (k = 0; k < width; k++) {
101 values[k] = src[k] >> 24;
102 }
103 }
104 break;
105 case PIPE_FORMAT_Z24S8_UNORM:
106 {
107 const uint *src = (uint *) stmap + srcY * ps->pitch + x;
108 GLint k;
109 for (k = 0; k < width; k++) {
110 values[k] = src[k] & 0xff;
111 }
112 }
113 break;
114 default:
115 assert(0);
116 }
117
118 /* store */
119 dest = _mesa_image_address2d(packing, pixels, width, height,
120 GL_STENCIL_INDEX, type, j, 0);
121
122 _mesa_pack_stencil_span(ctx, width, type, dest, values, packing);
123 }
124
125
126 /* unmap the stencil buffer */
127 pipe_surface_unmap(ps);
128 }
129
130
131 /**
132 * Return renderbuffer to use for reading color pixels for glRead/CopyPixel
133 * commands.
134 * Special care is needed for the front buffer.
135 */
136 struct st_renderbuffer *
137 st_get_color_read_renderbuffer(GLcontext *ctx)
138 {
139 struct gl_framebuffer *fb = ctx->ReadBuffer;
140 struct st_renderbuffer *strb =
141 st_renderbuffer(fb->_ColorReadBuffer);
142 struct st_renderbuffer *front =
143 st_renderbuffer(fb->Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
144
145 if (strb == front
146 && ctx->st->frontbuffer_status == FRONT_STATUS_COPY_OF_BACK) {
147 /* reading from front color buffer, which is a logical copy of the
148 * back color buffer.
149 */
150 struct st_renderbuffer *back =
151 st_renderbuffer(fb->Attachment[BUFFER_BACK_LEFT].Renderbuffer);
152 strb = back;
153 }
154
155 return strb;
156 }
157
158
159 /**
160 * Do glReadPixels by getting rows from the framebuffer surface with
161 * get_tile(). Convert to requested format/type with Mesa image routines.
162 * Image transfer ops are done in software too.
163 */
164 static void
165 st_readpixels(GLcontext *ctx, GLint x, GLint y, GLsizei width, GLsizei height,
166 GLenum format, GLenum type,
167 const struct gl_pixelstore_attrib *pack,
168 GLvoid *dest)
169 {
170 struct pipe_context *pipe = ctx->st->pipe;
171 GLfloat temp[MAX_WIDTH][4];
172 const GLbitfield transferOps = ctx->_ImageTransferState;
173 GLint i, yStep, dfStride;
174 GLfloat *df;
175 struct st_renderbuffer *strb;
176 struct gl_pixelstore_attrib clippedPacking = *pack;
177
178 /* XXX convolution not done yet */
179 assert((transferOps & IMAGE_CONVOLUTION_BIT) == 0);
180
181 /* Do all needed clipping here, so that we can forget about it later */
182 if (!_mesa_clip_readpixels(ctx, &x, &y, &width, &height, &clippedPacking)) {
183 /* The ReadPixels surface is totally outside the window bounds */
184 return;
185 }
186
187 dest = _mesa_map_readpix_pbo(ctx, &clippedPacking, dest);
188 if (!dest)
189 return;
190
191 st_flush_bitmap_cache(ctx->st);
192
193 /* make sure rendering has completed */
194 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
195
196 if (format == GL_STENCIL_INDEX) {
197 st_read_stencil_pixels(ctx, x, y, width, height, type, pack, dest);
198 return;
199 }
200 else if (format == GL_DEPTH_COMPONENT) {
201 strb = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer);
202 }
203 else {
204 /* Read color buffer */
205 strb = st_get_color_read_renderbuffer(ctx);
206 }
207
208 if (!strb)
209 return;
210
211 if (format == GL_RGBA && type == GL_FLOAT) {
212 /* write tile(row) directly into user's buffer */
213 df = (GLfloat *) _mesa_image_address2d(&clippedPacking, dest, width,
214 height, format, type, 0, 0);
215 dfStride = width * 4;
216 }
217 else {
218 /* write tile(row) into temp row buffer */
219 df = (GLfloat *) temp;
220 dfStride = 0;
221 }
222
223 /* determine bottom-to-top vs. top-to-bottom order */
224 if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
225 y = strb->Base.Height - 1 - y;
226 yStep = -1;
227 }
228 else {
229 yStep = 1;
230 }
231
232 /*
233 * Copy pixels from pipe_surface to user memory
234 */
235 {
236 /* dest of first pixel in client memory */
237 GLubyte *dst = _mesa_image_address2d(&clippedPacking, dest, width,
238 height, format, type, 0, 0);
239 /* dest row stride */
240 const GLint dstStride = _mesa_image_row_stride(&clippedPacking, width,
241 format, type);
242
243 if (strb->surface->format == PIPE_FORMAT_S8Z24_UNORM ||
244 strb->surface->format == PIPE_FORMAT_X8Z24_UNORM) {
245 if (format == GL_DEPTH_COMPONENT) {
246 for (i = 0; i < height; i++) {
247 GLuint ztemp[MAX_WIDTH], j;
248 GLfloat zfloat[MAX_WIDTH];
249 const double scale = 1.0 / ((1 << 24) - 1);
250 pipe_get_tile_raw(pipe, strb->surface, x, y,
251 width, 1, ztemp, 0);
252 y += yStep;
253 for (j = 0; j < width; j++) {
254 zfloat[j] = (float) (scale * (ztemp[j] & 0xffffff));
255 }
256 _mesa_pack_depth_span(ctx, width, dst, type,
257 zfloat, &clippedPacking);
258 dst += dstStride;
259 }
260 }
261 else {
262 /* untested, but simple: */
263 assert(format == GL_DEPTH_STENCIL_EXT);
264 for (i = 0; i < height; i++) {
265 pipe_get_tile_raw(pipe, strb->surface, x, y, width, 1, dst, 0);
266 y += yStep;
267 dst += dstStride;
268 }
269 }
270 }
271 else if (strb->surface->format == PIPE_FORMAT_Z16_UNORM) {
272 for (i = 0; i < height; i++) {
273 GLushort ztemp[MAX_WIDTH], j;
274 GLfloat zfloat[MAX_WIDTH];
275 const double scale = 1.0 / 0xffff;
276 pipe_get_tile_raw(pipe, strb->surface, x, y, width, 1, ztemp, 0);
277 y += yStep;
278 for (j = 0; j < width; j++) {
279 zfloat[j] = (float) (scale * ztemp[j]);
280 }
281 _mesa_pack_depth_span(ctx, width, dst, type,
282 zfloat, &clippedPacking);
283 dst += dstStride;
284 }
285 }
286 else if (strb->surface->format == PIPE_FORMAT_Z32_UNORM) {
287 for (i = 0; i < height; i++) {
288 GLuint ztemp[MAX_WIDTH], j;
289 GLfloat zfloat[MAX_WIDTH];
290 const double scale = 1.0 / 0xffffffff;
291 pipe_get_tile_raw(pipe, strb->surface, x, y, width, 1, ztemp, 0);
292 y += yStep;
293 for (j = 0; j < width; j++) {
294 zfloat[j] = (float) (scale * ztemp[j]);
295 }
296 _mesa_pack_depth_span(ctx, width, dst, type,
297 zfloat, &clippedPacking);
298 dst += dstStride;
299 }
300 }
301 else {
302 /* RGBA format */
303 /* Do a row at a time to flip image data vertically */
304 for (i = 0; i < height; i++) {
305 pipe_get_tile_rgba(pipe, strb->surface, x, y, width, 1, df);
306 y += yStep;
307 df += dfStride;
308 if (!dfStride) {
309 _mesa_pack_rgba_span_float(ctx, width, temp, format, type, dst,
310 &clippedPacking, transferOps);
311 dst += dstStride;
312 }
313 }
314 }
315 }
316
317 _mesa_unmap_readpix_pbo(ctx, &clippedPacking);
318 }
319
320
321 void st_init_readpixels_functions(struct dd_function_table *functions)
322 {
323 functions->ReadPixels = st_readpixels;
324 }