00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "main/imports.h"
00034 #include "main/image.h"
00035 #include "main/macros.h"
00036
00037 #include "st_context.h"
00038 #include "st_cb_accum.h"
00039 #include "st_cb_fbo.h"
00040 #include "st_draw.h"
00041 #include "st_public.h"
00042 #include "st_format.h"
00043 #include "pipe/p_context.h"
00044 #include "pipe/p_defines.h"
00045 #include "pipe/p_inlines.h"
00046 #include "util/u_tile.h"
00047
00048
00049 #define UNCLAMPED_FLOAT_TO_SHORT(us, f) \
00050 us = ( (short) ( CLAMP((f), -1.0, 1.0) * 32767.0F) )
00051
00052
00065 static void
00066 acc_get_tile_rgba(struct pipe_context *pipe, struct pipe_surface *acc_ps,
00067 uint x, uint y, uint w, uint h, float *p)
00068 {
00069 const enum pipe_format f = acc_ps->format;
00070 const struct pipe_format_block b = acc_ps->block;
00071
00072 acc_ps->format = DEFAULT_ACCUM_PIPE_FORMAT;
00073 acc_ps->block.size = 8;
00074 acc_ps->block.width = 1;
00075 acc_ps->block.height = 1;
00076
00077 pipe_get_tile_rgba(acc_ps, x, y, w, h, p);
00078
00079 acc_ps->format = f;
00080 acc_ps->block = b;
00081 }
00082
00083
00089 static void
00090 acc_put_tile_rgba(struct pipe_context *pipe, struct pipe_surface *acc_ps,
00091 uint x, uint y, uint w, uint h, const float *p)
00092 {
00093 enum pipe_format f = acc_ps->format;
00094 const struct pipe_format_block b = acc_ps->block;
00095
00096 acc_ps->format = DEFAULT_ACCUM_PIPE_FORMAT;
00097 acc_ps->block.size = 8;
00098 acc_ps->block.width = 1;
00099 acc_ps->block.height = 1;
00100
00101 pipe_put_tile_rgba(acc_ps, x, y, w, h, p);
00102
00103 acc_ps->format = f;
00104 acc_ps->block = b;
00105 }
00106
00107
00108
00109 void
00110 st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
00111 {
00112 struct st_renderbuffer *acc_strb = st_renderbuffer(rb);
00113 struct pipe_surface *acc_ps;
00114 struct pipe_screen *screen = ctx->st->pipe->screen;
00115 const GLint xpos = ctx->DrawBuffer->_Xmin;
00116 const GLint ypos = ctx->DrawBuffer->_Ymin;
00117 const GLint width = ctx->DrawBuffer->_Xmax - xpos;
00118 const GLint height = ctx->DrawBuffer->_Ymax - ypos;
00119 GLubyte *map;
00120
00121 acc_ps = screen->get_tex_surface(screen, acc_strb->texture, 0, 0, 0,
00122 PIPE_BUFFER_USAGE_CPU_WRITE);
00123 map = screen->surface_map(screen, acc_ps,
00124 PIPE_BUFFER_USAGE_CPU_WRITE);
00125
00126
00127 switch (acc_strb->format) {
00128 case PIPE_FORMAT_R16G16B16A16_SNORM:
00129 {
00130 GLshort r = FLOAT_TO_SHORT(ctx->Accum.ClearColor[0]);
00131 GLshort g = FLOAT_TO_SHORT(ctx->Accum.ClearColor[1]);
00132 GLshort b = FLOAT_TO_SHORT(ctx->Accum.ClearColor[2]);
00133 GLshort a = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]);
00134 int i, j;
00135 for (i = 0; i < height; i++) {
00136 GLshort *dst = (GLshort *) (map + (ypos + i) * acc_ps->stride + xpos * 8);
00137 for (j = 0; j < width; j++) {
00138 dst[0] = r;
00139 dst[1] = g;
00140 dst[2] = b;
00141 dst[3] = a;
00142 dst += 4;
00143 }
00144 }
00145 }
00146 break;
00147 default:
00148 _mesa_problem(ctx, "unexpected format in st_clear_accum_buffer()");
00149 }
00150
00151 screen->surface_unmap(screen, acc_ps);
00152 pipe_surface_reference(&acc_ps, NULL);
00153 }
00154
00155
00157 static void
00158 accum_mad(GLcontext *ctx, GLfloat scale, GLfloat bias,
00159 GLint xpos, GLint ypos, GLint width, GLint height,
00160 struct st_renderbuffer *acc_strb)
00161 {
00162 struct pipe_screen *screen = ctx->st->pipe->screen;
00163 struct pipe_surface *acc_ps = acc_strb->surface;
00164 GLubyte *map;
00165
00166 map = screen->surface_map(screen, acc_ps,
00167 PIPE_BUFFER_USAGE_CPU_WRITE);
00168
00169
00170 switch (acc_strb->format) {
00171 case PIPE_FORMAT_R16G16B16A16_SNORM:
00172 {
00173 int i, j;
00174 for (i = 0; i < height; i++) {
00175 GLshort *acc = (GLshort *) (map + (ypos + i) * acc_ps->stride + xpos * 8);
00176 for (j = 0; j < width * 4; j++) {
00177 float val = SHORT_TO_FLOAT(acc[j]) * scale + bias;
00178 acc[j] = FLOAT_TO_SHORT(val);
00179 }
00180 }
00181 }
00182 break;
00183 default:
00184 _mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()");
00185 }
00186
00187 screen->surface_unmap(screen, acc_ps);
00188 }
00189
00190
00191 static void
00192 accum_accum(struct pipe_context *pipe, GLfloat value,
00193 GLint xpos, GLint ypos, GLint width, GLint height,
00194 struct st_renderbuffer *acc_strb,
00195 struct st_renderbuffer *color_strb)
00196 {
00197 struct pipe_screen *screen = pipe->screen;
00198 struct pipe_surface *acc_surf, *color_surf;
00199 GLfloat *colorBuf, *accBuf;
00200 GLint i;
00201
00202 acc_surf = screen->get_tex_surface(screen, acc_strb->texture, 0, 0, 0,
00203 (PIPE_BUFFER_USAGE_CPU_WRITE |
00204 PIPE_BUFFER_USAGE_CPU_READ));
00205
00206 color_surf = screen->get_tex_surface(screen, color_strb->texture, 0, 0, 0,
00207 PIPE_BUFFER_USAGE_CPU_READ);
00208
00209 colorBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
00210 accBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
00211
00212 pipe_get_tile_rgba(color_surf, xpos, ypos, width, height, colorBuf);
00213 acc_get_tile_rgba(pipe, acc_surf, xpos, ypos, width, height, accBuf);
00214
00215 for (i = 0; i < 4 * width * height; i++) {
00216 accBuf[i] = accBuf[i] + colorBuf[i] * value;
00217 }
00218
00219 acc_put_tile_rgba(pipe, acc_surf, xpos, ypos, width, height, accBuf);
00220
00221 free(colorBuf);
00222 free(accBuf);
00223 pipe_surface_reference(&acc_surf, NULL);
00224 pipe_surface_reference(&color_surf, NULL);
00225 }
00226
00227
00228 static void
00229 accum_load(struct pipe_context *pipe, GLfloat value,
00230 GLint xpos, GLint ypos, GLint width, GLint height,
00231 struct st_renderbuffer *acc_strb,
00232 struct st_renderbuffer *color_strb)
00233 {
00234 struct pipe_screen *screen = pipe->screen;
00235 struct pipe_surface *acc_surf, *color_surf;
00236 GLfloat *buf;
00237 GLint i;
00238
00239 acc_surf = screen->get_tex_surface(screen, acc_strb->texture, 0, 0, 0,
00240 PIPE_BUFFER_USAGE_CPU_WRITE);
00241
00242 color_surf = screen->get_tex_surface(screen, color_strb->texture, 0, 0, 0,
00243 PIPE_BUFFER_USAGE_CPU_READ);
00244
00245 buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
00246
00247 pipe_get_tile_rgba(color_surf, xpos, ypos, width, height, buf);
00248
00249 for (i = 0; i < 4 * width * height; i++) {
00250 buf[i] = buf[i] * value;
00251 }
00252
00253 acc_put_tile_rgba(pipe, acc_surf, xpos, ypos, width, height, buf);
00254
00255 free(buf);
00256 pipe_surface_reference(&acc_surf, NULL);
00257 pipe_surface_reference(&color_surf, NULL);
00258 }
00259
00260
00261 static void
00262 accum_return(GLcontext *ctx, GLfloat value,
00263 GLint xpos, GLint ypos, GLint width, GLint height,
00264 struct st_renderbuffer *acc_strb,
00265 struct st_renderbuffer *color_strb)
00266 {
00267 struct pipe_context *pipe = ctx->st->pipe;
00268 struct pipe_screen *screen = pipe->screen;
00269 const GLubyte *colormask = ctx->Color.ColorMask;
00270 struct pipe_surface *acc_surf, *color_surf;
00271 GLfloat *abuf, *cbuf = NULL;
00272 GLint i, ch;
00273
00274 abuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
00275
00276 acc_surf = screen->get_tex_surface(screen, acc_strb->texture, 0, 0, 0,
00277 PIPE_BUFFER_USAGE_CPU_READ);
00278
00279 color_surf = screen->get_tex_surface(screen, color_strb->texture, 0, 0, 0,
00280 (PIPE_BUFFER_USAGE_CPU_READ |
00281 PIPE_BUFFER_USAGE_CPU_WRITE));
00282
00283 acc_get_tile_rgba(pipe, acc_surf, xpos, ypos, width, height, abuf);
00284
00285 if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3]) {
00286 cbuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
00287 pipe_get_tile_rgba(color_surf, xpos, ypos, width, height, cbuf);
00288 }
00289
00290 for (i = 0; i < width * height; i++) {
00291 for (ch = 0; ch < 4; ch++) {
00292 if (colormask[ch]) {
00293 GLfloat val = abuf[i * 4 + ch] * value;
00294 abuf[i * 4 + ch] = CLAMP(val, 0.0f, 1.0f);
00295 }
00296 else {
00297 abuf[i * 4 + ch] = cbuf[i * 4 + ch];
00298 }
00299 }
00300 }
00301
00302 pipe_put_tile_rgba(color_surf, xpos, ypos, width, height, abuf);
00303
00304 free(abuf);
00305 if (cbuf)
00306 free(cbuf);
00307 pipe_surface_reference(&acc_surf, NULL);
00308 pipe_surface_reference(&color_surf, NULL);
00309 }
00310
00311
00312 static void
00313 st_Accum(GLcontext *ctx, GLenum op, GLfloat value)
00314 {
00315 struct st_context *st = ctx->st;
00316 struct pipe_context *pipe = st->pipe;
00317 struct st_renderbuffer *acc_strb
00318 = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_ACCUM].Renderbuffer);
00319 struct st_renderbuffer *color_strb
00320 = st_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer);
00321
00322 const GLint xpos = ctx->DrawBuffer->_Xmin;
00323 const GLint ypos = ctx->DrawBuffer->_Ymin;
00324 const GLint width = ctx->DrawBuffer->_Xmax - xpos;
00325 const GLint height = ctx->DrawBuffer->_Ymax - ypos;
00326
00327
00328 st_flush( st, PIPE_FLUSH_RENDER_CACHE, NULL );
00329
00330 switch (op) {
00331 case GL_ADD:
00332 if (value != 0.0F) {
00333 accum_mad(ctx, 1.0, value, xpos, ypos, width, height, acc_strb);
00334 }
00335 break;
00336 case GL_MULT:
00337 if (value != 1.0F) {
00338 accum_mad(ctx, value, 0.0, xpos, ypos, width, height, acc_strb);
00339 }
00340 break;
00341 case GL_ACCUM:
00342 if (value != 0.0F) {
00343 accum_accum(pipe, value, xpos, ypos, width, height, acc_strb, color_strb);
00344 }
00345 break;
00346 case GL_LOAD:
00347 accum_load(pipe, value, xpos, ypos, width, height, acc_strb, color_strb);
00348 break;
00349 case GL_RETURN:
00350 accum_return(ctx, value, xpos, ypos, width, height, acc_strb, color_strb);
00351 break;
00352 default:
00353 assert(0);
00354 }
00355 }
00356
00357
00358
00359 void st_init_accum_functions(struct dd_function_table *functions)
00360 {
00361 functions->Accum = st_Accum;
00362 }