Merge remote branch 'upstream/gallium-0.1' into nouveau-gallium-0.1
[mesa.git] / src / mesa / state_tracker / st_cb_accum.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 * Authors:
30 * Brian Paul
31 */
32
33 #include "main/imports.h"
34 #include "main/image.h"
35 #include "main/macros.h"
36
37 #include "st_context.h"
38 #include "st_cb_accum.h"
39 #include "st_cb_fbo.h"
40 #include "st_draw.h"
41 #include "st_format.h"
42 #include "pipe/p_context.h"
43 #include "pipe/p_defines.h"
44 #include "pipe/p_inlines.h"
45 #include "util/p_tile.h"
46
47
48 #define UNCLAMPED_FLOAT_TO_SHORT(us, f) \
49 us = ( (short) ( CLAMP((f), -1.0, 1.0) * 32767.0F) )
50
51
52 /**
53 * For hardware that supports deep color buffers, we could accelerate
54 * most/all the accum operations with blending/texturing.
55 * For now, just use the get/put_tile() functions and do things in software.
56 */
57
58
59 /**
60 * Wrapper for pipe_get_tile_rgba(). Do format/cpp override to make the
61 * tile util function think the surface is 16bit/channel, even if it's not.
62 * See also: st_renderbuffer_alloc_storage()
63 */
64 static void
65 acc_get_tile_rgba(struct pipe_context *pipe, struct pipe_surface *acc_ps,
66 uint x, uint y, uint w, uint h, float *p)
67 {
68 const enum pipe_format f = acc_ps->format;
69 const int cpp = acc_ps->cpp;
70
71 acc_ps->format = DEFAULT_ACCUM_PIPE_FORMAT;
72 acc_ps->cpp = 8;
73
74 pipe_get_tile_rgba(pipe, acc_ps, x, y, w, h, p);
75
76 acc_ps->format = f;
77 acc_ps->cpp = cpp;
78 }
79
80
81 /**
82 * Wrapper for pipe_put_tile_rgba(). Do format/cpp override to make the
83 * tile util function think the surface is 16bit/channel, even if it's not.
84 * See also: st_renderbuffer_alloc_storage()
85 */
86 static void
87 acc_put_tile_rgba(struct pipe_context *pipe, struct pipe_surface *acc_ps,
88 uint x, uint y, uint w, uint h, const float *p)
89 {
90 enum pipe_format f = acc_ps->format;
91 const int cpp = acc_ps->cpp;
92
93 acc_ps->format = DEFAULT_ACCUM_PIPE_FORMAT;
94 acc_ps->cpp = 8;
95
96 pipe_put_tile_rgba(pipe, acc_ps, x, y, w, h, p);
97
98 acc_ps->format = f;
99 acc_ps->cpp = cpp;
100 }
101
102
103
104 void
105 st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
106 {
107 struct st_renderbuffer *acc_strb = st_renderbuffer(rb);
108 struct pipe_surface *acc_ps = acc_strb->surface;
109 const GLint xpos = ctx->DrawBuffer->_Xmin;
110 const GLint ypos = ctx->DrawBuffer->_Ymin;
111 const GLint width = ctx->DrawBuffer->_Xmax - xpos;
112 const GLint height = ctx->DrawBuffer->_Ymax - ypos;
113 GLvoid *map;
114
115 map = pipe_surface_map(acc_ps);
116
117 /* note acc_strb->format might not equal acc_ps->format */
118 switch (acc_strb->format) {
119 case PIPE_FORMAT_R16G16B16A16_SNORM:
120 {
121 GLshort r = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]);
122 GLshort g = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]);
123 GLshort b = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]);
124 GLshort a = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]);
125 int i, j;
126 for (i = 0; i < height; i++) {
127 GLshort *dst = ((GLshort *) map
128 + ((ypos + i) * acc_ps->pitch + xpos) * 4);
129 for (j = 0; j < width; j++) {
130 dst[0] = r;
131 dst[1] = g;
132 dst[2] = b;
133 dst[3] = a;
134 dst += 4;
135 }
136 }
137 }
138 break;
139 default:
140 _mesa_problem(ctx, "unexpected format in st_clear_accum_buffer()");
141 }
142
143 pipe_surface_unmap(acc_ps);
144 }
145
146
147 /** For ADD/MULT */
148 static void
149 accum_mad(GLcontext *ctx, GLfloat scale, GLfloat bias,
150 GLint xpos, GLint ypos, GLint width, GLint height,
151 struct st_renderbuffer *acc_strb)
152 {
153 struct pipe_surface *acc_ps = acc_strb->surface;
154 GLvoid *map;
155
156 map = pipe_surface_map(acc_ps);
157
158 /* note acc_strb->format might not equal acc_ps->format */
159 switch (acc_strb->format) {
160 case PIPE_FORMAT_R16G16B16A16_SNORM:
161 {
162 int i, j;
163 for (i = 0; i < height; i++) {
164 GLshort *acc = ((GLshort *) map
165 + ((ypos + i) * acc_ps->pitch + xpos) * 4);
166 for (j = 0; j < width * 4; j++) {
167 float val = SHORT_TO_FLOAT(acc[j]) * scale + bias;
168 acc[j] = FLOAT_TO_SHORT(val);
169 }
170 }
171 }
172 break;
173 default:
174 _mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()");
175 }
176 }
177
178
179 static void
180 accum_accum(struct pipe_context *pipe, GLfloat value,
181 GLint xpos, GLint ypos, GLint width, GLint height,
182 struct pipe_surface *acc_ps,
183 struct pipe_surface *color_ps)
184 {
185 GLfloat *colorBuf, *accBuf;
186 GLint i;
187
188 colorBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
189 accBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
190
191 pipe_get_tile_rgba(pipe, color_ps, xpos, ypos, width, height, colorBuf);
192 acc_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
193
194 for (i = 0; i < 4 * width * height; i++) {
195 accBuf[i] = accBuf[i] + colorBuf[i] * value;
196 }
197
198 acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
199
200 free(colorBuf);
201 free(accBuf);
202 }
203
204
205 static void
206 accum_load(struct pipe_context *pipe, GLfloat value,
207 GLint xpos, GLint ypos, GLint width, GLint height,
208 struct pipe_surface *acc_ps,
209 struct pipe_surface *color_ps)
210 {
211 GLfloat *buf;
212 GLint i;
213
214 buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
215
216 pipe_get_tile_rgba(pipe, color_ps, xpos, ypos, width, height, buf);
217
218 for (i = 0; i < 4 * width * height; i++) {
219 buf[i] = buf[i] * value;
220 }
221
222 acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, buf);
223
224 free(buf);
225 }
226
227
228 static void
229 accum_return(GLcontext *ctx, GLfloat value,
230 GLint xpos, GLint ypos, GLint width, GLint height,
231 struct pipe_surface *acc_ps,
232 struct pipe_surface *color_ps)
233 {
234 struct pipe_context *pipe = ctx->st->pipe;
235 const GLubyte *colormask = ctx->Color.ColorMask;
236 GLfloat *abuf, *cbuf = NULL;
237 GLint i, ch;
238
239 abuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
240
241 acc_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, abuf);
242
243 if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3]) {
244 cbuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
245 pipe_get_tile_rgba(pipe, color_ps, xpos, ypos, width, height, cbuf);
246 }
247
248 for (i = 0; i < width * height; i++) {
249 for (ch = 0; ch < 4; ch++) {
250 if (colormask[ch]) {
251 GLfloat val = abuf[i * 4 + ch] * value;
252 abuf[i * 4 + ch] = CLAMP(val, 0.0, 1.0);
253 }
254 else {
255 abuf[i * 4 + ch] = cbuf[i * 4 + ch];
256 }
257 }
258 }
259
260 pipe_put_tile_rgba(pipe, color_ps, xpos, ypos, width, height, abuf);
261
262 free(abuf);
263 if (cbuf)
264 free(cbuf);
265 }
266
267
268 static void
269 st_Accum(GLcontext *ctx, GLenum op, GLfloat value)
270 {
271 struct st_context *st = ctx->st;
272 struct pipe_context *pipe = st->pipe;
273 struct st_renderbuffer *acc_strb
274 = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer);
275 struct st_renderbuffer *color_strb
276 = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
277 struct pipe_surface *acc_ps = acc_strb->surface;
278 struct pipe_surface *color_ps = color_strb->surface;
279
280 const GLint xpos = ctx->DrawBuffer->_Xmin;
281 const GLint ypos = ctx->DrawBuffer->_Ymin;
282 const GLint width = ctx->DrawBuffer->_Xmax - xpos;
283 const GLint height = ctx->DrawBuffer->_Ymax - ypos;
284
285 /* make sure color bufs aren't cached */
286 pipe->flush(pipe, PIPE_FLUSH_RENDER_CACHE, NULL);
287
288 switch (op) {
289 case GL_ADD:
290 if (value != 0.0F) {
291 accum_mad(ctx, 1.0, value, xpos, ypos, width, height, acc_strb);
292 }
293 break;
294 case GL_MULT:
295 if (value != 1.0F) {
296 accum_mad(ctx, value, 0.0, xpos, ypos, width, height, acc_strb);
297 }
298 break;
299 case GL_ACCUM:
300 if (value != 0.0F) {
301 accum_accum(pipe, value, xpos, ypos, width, height, acc_ps, color_ps);
302 }
303 break;
304 case GL_LOAD:
305 accum_load(pipe, value, xpos, ypos, width, height, acc_ps, color_ps);
306 break;
307 case GL_RETURN:
308 accum_return(ctx, value, xpos, ypos, width, height, acc_ps, color_ps);
309 break;
310 default:
311 assert(0);
312 }
313 }
314
315
316
317 void st_init_accum_functions(struct dd_function_table *functions)
318 {
319 functions->Accum = st_Accum;
320 }