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 }