patch to import Jon Smirl's work from Bitkeeper
[mesa.git] / src / mesa / drivers / dri / radeon / radeon_subset_readpix.c
1 /**
2 * \file radeon_subset_readpix.c
3 * \brief Pixel reading.
4 *
5 * \author Keith Whitwell <keith@tungstengraphics.com>
6 * \author Brian Paul <brian@tungstengraphics.com>
7 */
8
9 /*
10 * Copyright 2003 ATI Technologies Inc., Ontario, Canada, and
11 * Tungsten Graphics Inc., Cedar Park, Texas.
12 *
13 * All Rights Reserved.
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * on the rights to use, copy, modify, merge, publish, distribute, sub
19 * license, and/or sell copies of the Software, and to permit persons to whom
20 * the Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice (including the next
23 * paragraph) shall be included in all copies or substantial portions of the
24 * Software.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
29 * ATI, TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
30 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
31 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
32 * USE OR OTHER DEALINGS IN THE SOFTWARE.
33 */
34
35 /* $XFree86$ */
36
37 #include "glheader.h"
38 #include "mtypes.h"
39 #include "colormac.h"
40 #include "context.h"
41 #include "enums.h"
42 #include "imports.h"
43 /*#include "mmath.h" */
44 #include "macros.h"
45 #include "state.h"
46
47 #include "radeon_context.h"
48 #include "radeon_ioctl.h"
49 #include "radeon_state.h"
50 #include "radeon_subset.h"
51
52 /**
53 * \brief Read pixel in RGBA format on a Radeon 16bpp frame buffer.
54 *
55 * \param rgba destination pointer.
56 * \param ptr pointer to the pixel in the frame buffer.
57 */
58 #define READ_RGBA_16( rgba, ptr ) \
59 do { \
60 GLushort p = *(GLushort *)ptr; \
61 rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \
62 rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \
63 rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \
64 rgba[3] = 0xff; \
65 } while (0)
66
67 /**
68 * \brief Read pixel in RGBA format on a Radeon 32bpp frame buffer.
69 *
70 * \param rgba destination pointer.
71 * \param ptr pointer to the pixel in the frame buffer.
72 */
73 #define READ_RGBA_32( rgba, ptr ) \
74 do { \
75 GLuint p = *(GLuint *)ptr; \
76 rgba[0] = (p >> 16) & 0xff; \
77 rgba[1] = (p >> 8) & 0xff; \
78 rgba[2] = (p >> 0) & 0xff; \
79 rgba[3] = (p >> 24) & 0xff; \
80 } while (0)
81
82 /**
83 * \brief Read a span in RGBA format.
84 *
85 * \param ctx GL context.
86 * \param n number of pixels in the span.
87 * \param x x position of the span start.
88 * \param y y position of the span.
89 * \param rgba destination buffer.
90 *
91 * Calculates the pointer to the span start in the frame buffer and uses either
92 * #READ_RGBA_16 or #READ_RGBA_32 macros to copy the values.
93 */
94 static void ReadRGBASpan( const GLcontext *ctx,
95 GLuint n, GLint x, GLint y,
96 GLubyte rgba[][4])
97 {
98 radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
99 radeonScreenPtr radeonScreen = rmesa->radeonScreen;
100 __DRIdrawablePrivate *dPriv = rmesa->dri.drawable;
101 GLuint cpp = radeonScreen->cpp;
102 GLuint pitch = radeonScreen->frontPitch * cpp;
103 GLint i;
104
105 if (ctx->_RotateMode) {
106 char *ptr = (char *)(rmesa->dri.screen->pFB +
107 rmesa->state.pixel.readOffset +
108 ((dPriv->x + (dPriv->w - y - 1)) * cpp) +
109 ((dPriv->y + (dPriv->h - x - 1)) * pitch));
110
111 if (cpp == 4)
112 for (i = 0; i < n; i++, ptr -= pitch)
113 READ_RGBA_32( rgba[i], ptr );
114 else
115 for (i = 0; i < n; i++, ptr -= pitch)
116 READ_RGBA_16( rgba[i], ptr );
117 }
118 else {
119 char *ptr = (char *)(rmesa->dri.screen->pFB +
120 rmesa->state.pixel.readOffset +
121 ((dPriv->x + x) * cpp) +
122 ((dPriv->y + (dPriv->h - y - 1)) * pitch));
123
124 if (cpp == 4)
125 for (i = 0; i < n; i++, ptr += cpp)
126 READ_RGBA_32( rgba[i], ptr );
127 else
128 for (i = 0; i < n; i++, ptr += cpp)
129 READ_RGBA_16( rgba[i], ptr );
130 }
131 }
132
133
134 /**
135 * \brief Optimized glReadPixels().
136 *
137 * To be used with particular pixel formats GL_UNSIGNED_BYTE and GL_RGBA, when pixel
138 * scaling, biasing and mapping are disabled.
139 *
140 * \param x x start position of the reading rectangle.
141 * \param y y start position of the reading rectangle.
142 * \param width width of the reading rectangle.
143 * \param height height of the reading rectangle.
144 * \param format pixel format. Must be GL_RGBA.
145 * \param type pixel type. Must be GL_UNSIGNED_BYTE.
146 * \param pixels pixel data.
147 *
148 * After asserting the above conditions, compensates for clipping and calls
149 * ReadRGBASpan() to read each row.
150 */
151 void radeonReadPixels( GLint x, GLint y,
152 GLsizei width, GLsizei height,
153 GLenum format, GLenum type,
154 GLvoid *pixels )
155 {
156 GET_CURRENT_CONTEXT(ctx);
157 GLint srcX = x;
158 GLint srcY = y;
159 GLint readWidth = width; /* actual width read */
160 GLint readHeight = height; /* actual height read */
161 const struct gl_pixelstore_attrib *packing = &ctx->Pack;
162 GLint skipRows = packing->SkipRows;
163 GLint skipPixels = packing->SkipPixels;
164 GLint rowLength;
165 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
166
167 {
168 GLint tmp, tmps;
169 tmp = x; x = y; y = tmp;
170 tmps = width; width = height; height = tmps;
171 }
172
173 if (width < 0 || height < 0) {
174 _mesa_error( ctx, GL_INVALID_VALUE,
175 "glReadPixels(width=%d height=%d)", width, height );
176 return;
177 }
178
179 if (!pixels) {
180 _mesa_error( ctx, GL_INVALID_VALUE, "glReadPixels(pixels)" );
181 return;
182 }
183
184 if (ctx->NewState)
185 _mesa_update_state(ctx);
186
187
188 /* can't do scale, bias, mapping, etc */
189 assert(!ctx->_ImageTransferState);
190
191 /* can't do fancy pixel packing */
192 assert (packing->Alignment == 1 &&
193 !packing->SwapBytes &&
194 !packing->LsbFirst);
195
196
197 if (packing->RowLength > 0)
198 rowLength = packing->RowLength;
199 else
200 rowLength = width;
201
202 /* horizontal clipping */
203 if (srcX < 0) {
204 skipPixels -= srcX;
205 readWidth += srcX;
206 srcX = 0;
207 }
208 if (srcX + readWidth > (GLint) ctx->ReadBuffer->Width)
209 readWidth -= (srcX + readWidth - (GLint) ctx->ReadBuffer->Width);
210 if (readWidth <= 0)
211 return;
212
213 /* vertical clipping */
214 if (srcY < 0) {
215 skipRows -= srcY;
216 readHeight += srcY;
217 srcY = 0;
218 }
219 if (srcY + readHeight > (GLint) ctx->ReadBuffer->Height)
220 readHeight -= (srcY + readHeight - (GLint) ctx->ReadBuffer->Height);
221 if (readHeight <= 0)
222 return;
223
224 /*
225 * Ready to read!
226 * The window region at (destX, destY) of size (readWidth, readHeight)
227 * will be read back.
228 * We'll write pixel data to buffer pointed to by "pixels" but we'll
229 * skip "skipRows" rows and skip "skipPixels" pixels/row.
230 */
231 if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) {
232 GLchan *dest = (GLchan *) pixels
233 + (skipRows * rowLength + skipPixels) * 4;
234 GLint row;
235
236 for (row=0; row<readHeight; row++) {
237 ReadRGBASpan(ctx, readWidth, srcX, srcY, (GLchan (*)[4]) dest);
238 dest += rowLength * 4;
239 srcY++;
240 }
241 }
242 else {
243 /* can't do this format/type combination */
244 assert(0);
245 }
246 }