Merge commit 'origin/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_public.h"
42 #include "st_format.h"
43 #include "pipe/p_context.h"
44 #include "pipe/p_defines.h"
45 #include "pipe/p_inlines.h"
46 #include "util/u_tile.h"
47
48
49 #define UNCLAMPED_FLOAT_TO_SHORT(us, f) \
50 us = ( (short) ( CLAMP((f), -1.0, 1.0) * 32767.0F) )
51
52
53 /**
54 * For hardware that supports deep color buffers, we could accelerate
55 * most/all the accum operations with blending/texturing.
56 * For now, just use the get/put_tile() functions and do things in software.
57 */
58
59
60 /**
61 * Wrapper for pipe_get_tile_rgba(). Do format/cpp override to make the
62 * tile util function think the surface is 16bit/channel, even if it's not.
63 * See also: st_renderbuffer_alloc_storage()
64 */
65 static void
66 acc_get_tile_rgba(struct pipe_context *pipe, struct pipe_transfer *acc_pt,
67 uint x, uint y, uint w, uint h, float *p)
68 {
69 const enum pipe_format f = acc_pt->format;
70 const struct pipe_format_block b = acc_pt->block;
71
72 acc_pt->format = DEFAULT_ACCUM_PIPE_FORMAT;
73 acc_pt->block.size = 8;
74 acc_pt->block.width = 1;
75 acc_pt->block.height = 1;
76
77 pipe_get_tile_rgba(acc_pt, x, y, w, h, p);
78
79 acc_pt->format = f;
80 acc_pt->block = b;
81 }
82
83
84 /**
85 * Wrapper for pipe_put_tile_rgba(). Do format/cpp override to make the
86 * tile util function think the surface is 16bit/channel, even if it's not.
87 * See also: st_renderbuffer_alloc_storage()
88 */
89 static void
90 acc_put_tile_rgba(struct pipe_context *pipe, struct pipe_transfer *acc_pt,
91 uint x, uint y, uint w, uint h, const float *p)
92 {
93 enum pipe_format f = acc_pt->format;
94 const struct pipe_format_block b = acc_pt->block;
95
96 acc_pt->format = DEFAULT_ACCUM_PIPE_FORMAT;
97 acc_pt->block.size = 8;
98 acc_pt->block.width = 1;
99 acc_pt->block.height = 1;
100
101 pipe_put_tile_rgba(acc_pt, x, y, w, h, p);
102
103 acc_pt->format = f;
104 acc_pt->block = b;
105 }
106
107
108
109 void
110 st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
111 {
112 struct st_renderbuffer *acc_strb = st_renderbuffer(rb);
113 struct pipe_transfer *acc_pt;
114 struct pipe_screen *screen = ctx->st->pipe->screen;
115 const GLint xpos = ctx->DrawBuffer->_Xmin;
116 const GLint ypos = ctx->DrawBuffer->_Ymin;
117 const GLint width = ctx->DrawBuffer->_Xmax - xpos;
118 const GLint height = ctx->DrawBuffer->_Ymax - ypos;
119 GLubyte *map;
120
121 acc_pt = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
122 PIPE_TRANSFER_WRITE, xpos, ypos,
123 width, height);
124 map = screen->transfer_map(screen, acc_pt);
125
126 /* note acc_strb->format might not equal acc_pt->format */
127 switch (acc_strb->format) {
128 case PIPE_FORMAT_R16G16B16A16_SNORM:
129 {
130 GLshort r = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]);
131 GLshort g = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]);
132 GLshort b = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]);
133 GLshort a = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]);
134 int i, j;
135 for (i = 0; i < height; i++) {
136 GLshort *dst = (GLshort *) (map + i * acc_pt->stride + xpos * 8);
137 for (j = 0; j < width; j++) {
138 dst[0] = r;
139 dst[1] = g;
140 dst[2] = b;
141 dst[3] = a;
142 dst += 4;
143 }
144 }
145 }
146 break;
147 default:
148 _mesa_problem(ctx, "unexpected format in st_clear_accum_buffer()");
149 }
150
151 screen->transfer_unmap(screen, acc_pt);
152 screen->tex_transfer_release(screen, &acc_pt);
153 }
154
155
156 /** For ADD/MULT */
157 static void
158 accum_mad(GLcontext *ctx, GLfloat scale, GLfloat bias,
159 GLint xpos, GLint ypos, GLint width, GLint height,
160 struct st_renderbuffer *acc_strb)
161 {
162 struct pipe_screen *screen = ctx->st->pipe->screen;
163 struct pipe_transfer *acc_pt;
164 GLubyte *map;
165
166 acc_pt = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
167 PIPE_TRANSFER_READ_WRITE, xpos, ypos,
168 width, height);
169 map = screen->transfer_map(screen, acc_pt);
170
171 /* note acc_strb->format might not equal acc_pt->format */
172 switch (acc_strb->format) {
173 case PIPE_FORMAT_R16G16B16A16_SNORM:
174 {
175 int i, j;
176 for (i = 0; i < height; i++) {
177 GLshort *acc = (GLshort *) (map + (ypos + i) * acc_pt->stride + xpos * 8);
178 for (j = 0; j < width * 4; j++) {
179 float val = SHORT_TO_FLOAT(acc[j]) * scale + bias;
180 acc[j] = FLOAT_TO_SHORT(val);
181 }
182 }
183 }
184 break;
185 default:
186 _mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()");
187 }
188
189 screen->transfer_unmap(screen, acc_pt);
190 screen->tex_transfer_release(screen, &acc_pt);
191 }
192
193
194 static void
195 accum_accum(struct pipe_context *pipe, GLfloat value,
196 GLint xpos, GLint ypos, GLint width, GLint height,
197 struct st_renderbuffer *acc_strb,
198 struct st_renderbuffer *color_strb)
199 {
200 struct pipe_screen *screen = pipe->screen;
201 struct pipe_transfer *acc_trans, *color_trans;
202 GLfloat *colorBuf, *accBuf;
203 GLint i;
204
205 acc_trans = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
206 PIPE_TRANSFER_READ, xpos, ypos,
207 width, height);
208
209 color_trans = screen->get_tex_transfer(screen, color_strb->texture, 0, 0, 0,
210 PIPE_TRANSFER_READ, xpos, ypos,
211 width, height);
212
213 colorBuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
214 accBuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
215
216 pipe_get_tile_rgba(color_trans, 0, 0, width, height, colorBuf);
217 acc_get_tile_rgba(pipe, acc_trans, 0, 0, width, height, accBuf);
218
219 for (i = 0; i < 4 * width * height; i++) {
220 accBuf[i] = accBuf[i] + colorBuf[i] * value;
221 }
222
223 screen->tex_transfer_release(screen, &acc_trans);
224 acc_trans = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
225 PIPE_TRANSFER_WRITE, xpos, ypos,
226 width, height);
227
228 acc_put_tile_rgba(pipe, acc_trans, 0, 0, width, height, accBuf);
229
230 _mesa_free(colorBuf);
231 _mesa_free(accBuf);
232 screen->tex_transfer_release(screen, &acc_trans);
233 screen->tex_transfer_release(screen, &color_trans);
234 }
235
236
237 static void
238 accum_load(struct pipe_context *pipe, GLfloat value,
239 GLint xpos, GLint ypos, GLint width, GLint height,
240 struct st_renderbuffer *acc_strb,
241 struct st_renderbuffer *color_strb)
242 {
243 struct pipe_screen *screen = pipe->screen;
244 struct pipe_transfer *acc_trans, *color_trans;
245 GLfloat *buf;
246 GLint i;
247
248 acc_trans = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
249 PIPE_TRANSFER_WRITE, xpos, ypos,
250 width, height);
251
252 color_trans = screen->get_tex_transfer(screen, color_strb->texture, 0, 0, 0,
253 PIPE_TRANSFER_READ, xpos, ypos,
254 width, height);
255
256 buf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
257
258 pipe_get_tile_rgba(color_trans, 0, 0, width, height, buf);
259
260 for (i = 0; i < 4 * width * height; i++) {
261 buf[i] = buf[i] * value;
262 }
263
264 acc_put_tile_rgba(pipe, acc_trans, 0, 0, width, height, buf);
265
266 _mesa_free(buf);
267 screen->tex_transfer_release(screen, &acc_trans);
268 screen->tex_transfer_release(screen, &color_trans);
269 }
270
271
272 static void
273 accum_return(GLcontext *ctx, GLfloat value,
274 GLint xpos, GLint ypos, GLint width, GLint height,
275 struct st_renderbuffer *acc_strb,
276 struct st_renderbuffer *color_strb)
277 {
278 struct pipe_context *pipe = ctx->st->pipe;
279 struct pipe_screen *screen = pipe->screen;
280 const GLubyte *colormask = ctx->Color.ColorMask;
281 struct pipe_transfer *acc_trans, *color_trans;
282 GLfloat *abuf, *cbuf = NULL;
283 GLint i, ch;
284
285 abuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
286
287 acc_trans = screen->get_tex_transfer(screen, acc_strb->texture, 0, 0, 0,
288 PIPE_TRANSFER_READ, xpos, ypos,
289 width, height);
290
291 color_trans = screen->get_tex_transfer(screen, color_strb->texture, 0, 0, 0,
292 PIPE_TRANSFER_READ_WRITE, xpos, ypos,
293 width, height);
294
295 acc_get_tile_rgba(pipe, acc_trans, 0, 0, width, height, abuf);
296
297 if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3]) {
298 cbuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
299 pipe_get_tile_rgba(color_trans, 0, 0, width, height, cbuf);
300 }
301
302 for (i = 0; i < width * height; i++) {
303 for (ch = 0; ch < 4; ch++) {
304 if (colormask[ch]) {
305 GLfloat val = abuf[i * 4 + ch] * value;
306 abuf[i * 4 + ch] = CLAMP(val, 0.0f, 1.0f);
307 }
308 else {
309 abuf[i * 4 + ch] = cbuf[i * 4 + ch];
310 }
311 }
312 }
313
314 pipe_put_tile_rgba(color_trans, 0, 0, width, height, abuf);
315
316 _mesa_free(abuf);
317 if (cbuf)
318 _mesa_free(cbuf);
319 screen->tex_transfer_release(screen, &acc_trans);
320 screen->tex_transfer_release(screen, &color_trans);
321 }
322
323
324 static void
325 st_Accum(GLcontext *ctx, GLenum op, GLfloat value)
326 {
327 struct st_context *st = ctx->st;
328 struct pipe_context *pipe = st->pipe;
329 struct st_renderbuffer *acc_strb
330 = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer);
331 struct st_renderbuffer *color_strb
332 = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
333
334 const GLint xpos = ctx->DrawBuffer->_Xmin;
335 const GLint ypos = ctx->DrawBuffer->_Ymin;
336 const GLint width = ctx->DrawBuffer->_Xmax - xpos;
337 const GLint height = ctx->DrawBuffer->_Ymax - ypos;
338
339 /* make sure color bufs aren't cached */
340 st_flush( st, PIPE_FLUSH_RENDER_CACHE, NULL );
341
342 switch (op) {
343 case GL_ADD:
344 if (value != 0.0F) {
345 accum_mad(ctx, 1.0, value, xpos, ypos, width, height, acc_strb);
346 }
347 break;
348 case GL_MULT:
349 if (value != 1.0F) {
350 accum_mad(ctx, value, 0.0, xpos, ypos, width, height, acc_strb);
351 }
352 break;
353 case GL_ACCUM:
354 if (value != 0.0F) {
355 accum_accum(pipe, value, xpos, ypos, width, height, acc_strb, color_strb);
356 }
357 break;
358 case GL_LOAD:
359 accum_load(pipe, value, xpos, ypos, width, height, acc_strb, color_strb);
360 break;
361 case GL_RETURN:
362 accum_return(ctx, value, xpos, ypos, width, height, acc_strb, color_strb);
363 break;
364 default:
365 assert(0);
366 }
367 }
368
369
370
371 void st_init_accum_functions(struct dd_function_table *functions)
372 {
373 functions->Accum = st_Accum;
374 }