Home | History | Annotate | Download | only in vbo
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.2
      4  *
      5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a
      8  * copy of this software and associated documentation files (the "Software"),
      9  * to deal in the Software without restriction, including without limitation
     10  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11  * and/or sell copies of the Software, and to permit persons to whom the
     12  * Software is furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included
     15  * in all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     20  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     21  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 /* Author:
     26  *    Keith Whitwell <keith (at) tungstengraphics.com>
     27  */
     28 
     29 #include "main/glheader.h"
     30 #include "main/bufferobj.h"
     31 #include "main/context.h"
     32 #include "main/imports.h"
     33 #include "main/mfeatures.h"
     34 #include "main/mtypes.h"
     35 #include "main/macros.h"
     36 #include "main/light.h"
     37 #include "main/state.h"
     38 
     39 #include "vbo_context.h"
     40 
     41 
     42 #if FEATURE_dlist
     43 
     44 
     45 /**
     46  * After playback, copy everything but the position from the
     47  * last vertex to the saved state
     48  */
     49 static void
     50 _playback_copy_to_current(struct gl_context *ctx,
     51                           const struct vbo_save_vertex_list *node)
     52 {
     53    struct vbo_context *vbo = vbo_context(ctx);
     54    GLfloat vertex[VBO_ATTRIB_MAX * 4];
     55    GLfloat *data;
     56    GLuint i, offset;
     57 
     58    if (node->current_size == 0)
     59       return;
     60 
     61    if (node->current_data) {
     62       data = node->current_data;
     63    }
     64    else {
     65       data = vertex;
     66 
     67       if (node->count)
     68          offset = (node->buffer_offset +
     69                    (node->count-1) * node->vertex_size * sizeof(GLfloat));
     70       else
     71          offset = node->buffer_offset;
     72 
     73       ctx->Driver.GetBufferSubData( ctx, offset,
     74                                     node->vertex_size * sizeof(GLfloat),
     75                                     data, node->vertex_store->bufferobj );
     76 
     77       data += node->attrsz[0]; /* skip vertex position */
     78    }
     79 
     80    for (i = VBO_ATTRIB_POS+1 ; i < VBO_ATTRIB_MAX ; i++) {
     81       if (node->attrsz[i]) {
     82 	 GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
     83          GLfloat tmp[4];
     84 
     85          COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp,
     86                                      node->attrsz[i],
     87                                      data,
     88                                      node->attrtype[i]);
     89 
     90          if (node->attrtype[i] != vbo->currval[i].Type ||
     91              memcmp(current, tmp, 4 * sizeof(GLfloat)) != 0) {
     92             memcpy(current, tmp, 4 * sizeof(GLfloat));
     93 
     94             vbo->currval[i].Size = node->attrsz[i];
     95             vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
     96             vbo->currval[i].Type = node->attrtype[i];
     97             vbo->currval[i].Integer =
     98                   vbo_attrtype_to_integer_flag(node->attrtype[i]);
     99 
    100             if (i >= VBO_ATTRIB_FIRST_MATERIAL &&
    101                 i <= VBO_ATTRIB_LAST_MATERIAL)
    102                ctx->NewState |= _NEW_LIGHT;
    103 
    104             ctx->NewState |= _NEW_CURRENT_ATTRIB;
    105          }
    106 
    107 	 data += node->attrsz[i];
    108       }
    109    }
    110 
    111    /* Colormaterial -- this kindof sucks.
    112     */
    113    if (ctx->Light.ColorMaterialEnabled) {
    114       _mesa_update_color_material(ctx, ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
    115    }
    116 
    117    /* CurrentExecPrimitive
    118     */
    119    if (node->prim_count) {
    120       const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
    121       if (prim->end)
    122 	 ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
    123       else
    124 	 ctx->Driver.CurrentExecPrimitive = prim->mode;
    125    }
    126 }
    127 
    128 
    129 
    130 /**
    131  * Treat the vertex storage as a VBO, define vertex arrays pointing
    132  * into it:
    133  */
    134 static void vbo_bind_vertex_list(struct gl_context *ctx,
    135                                  const struct vbo_save_vertex_list *node)
    136 {
    137    struct vbo_context *vbo = vbo_context(ctx);
    138    struct vbo_save_context *save = &vbo->save;
    139    struct gl_client_array *arrays = save->arrays;
    140    GLuint buffer_offset = node->buffer_offset;
    141    const GLuint *map;
    142    GLuint attr;
    143    GLubyte node_attrsz[VBO_ATTRIB_MAX];  /* copy of node->attrsz[] */
    144    GLenum node_attrtype[VBO_ATTRIB_MAX];  /* copy of node->attrtype[] */
    145    GLbitfield64 varying_inputs = 0x0;
    146 
    147    memcpy(node_attrsz, node->attrsz, sizeof(node->attrsz));
    148    memcpy(node_attrtype, node->attrtype, sizeof(node->attrtype));
    149 
    150    /* Install the default (ie Current) attributes first, then overlay
    151     * all active ones.
    152     */
    153    switch (get_program_mode(ctx)) {
    154    case VP_NONE:
    155       for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
    156          save->inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
    157       }
    158       for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
    159          save->inputs[VERT_ATTRIB_GENERIC(attr)] =
    160             &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr];
    161       }
    162       map = vbo->map_vp_none;
    163       break;
    164    case VP_NV:
    165    case VP_ARB:
    166       /* The aliasing of attributes for NV vertex programs has already
    167        * occurred.  NV vertex programs cannot access material values,
    168        * nor attributes greater than VERT_ATTRIB_TEX7.
    169        */
    170       for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
    171          save->inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
    172       }
    173       for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) {
    174          save->inputs[VERT_ATTRIB_GENERIC(attr)] =
    175             &vbo->currval[VBO_ATTRIB_GENERIC0+attr];
    176       }
    177       map = vbo->map_vp_arb;
    178 
    179       /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
    180        * In that case we effectively need to route the data from
    181        * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
    182        */
    183       if ((ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_POS) == 0 &&
    184           (ctx->VertexProgram._Current->Base.InputsRead & VERT_BIT_GENERIC0)) {
    185          save->inputs[VERT_ATTRIB_GENERIC0] = save->inputs[0];
    186          node_attrsz[VERT_ATTRIB_GENERIC0] = node_attrsz[0];
    187          node_attrtype[VERT_ATTRIB_GENERIC0] = node_attrtype[0];
    188          node_attrsz[0] = 0;
    189       }
    190       break;
    191    default:
    192       assert(0);
    193    }
    194 
    195    for (attr = 0; attr < VERT_ATTRIB_MAX; attr++) {
    196       const GLuint src = map[attr];
    197 
    198       if (node_attrsz[src]) {
    199          /* override the default array set above */
    200          save->inputs[attr] = &arrays[attr];
    201 
    202 	 arrays[attr].Ptr = (const GLubyte *) NULL + buffer_offset;
    203 	 arrays[attr].Size = node_attrsz[src];
    204 	 arrays[attr].StrideB = node->vertex_size * sizeof(GLfloat);
    205 	 arrays[attr].Stride = node->vertex_size * sizeof(GLfloat);
    206          arrays[attr].Type = node_attrtype[src];
    207          arrays[attr].Integer =
    208                vbo_attrtype_to_integer_flag(node_attrtype[src]);
    209          arrays[attr].Format = GL_RGBA;
    210 	 arrays[attr].Enabled = 1;
    211          arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
    212          _mesa_reference_buffer_object(ctx,
    213                                        &arrays[attr].BufferObj,
    214                                        node->vertex_store->bufferobj);
    215 	 arrays[attr]._MaxElement = node->count; /* ??? */
    216 
    217 	 assert(arrays[attr].BufferObj->Name);
    218 
    219 	 buffer_offset += node_attrsz[src] * sizeof(GLfloat);
    220          varying_inputs |= VERT_BIT(attr);
    221       }
    222    }
    223 
    224    _mesa_set_varying_vp_inputs( ctx, varying_inputs );
    225    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
    226 }
    227 
    228 
    229 static void
    230 vbo_save_loopback_vertex_list(struct gl_context *ctx,
    231                               const struct vbo_save_vertex_list *list)
    232 {
    233    const char *buffer =
    234       ctx->Driver.MapBufferRange(ctx, 0,
    235 				 list->vertex_store->bufferobj->Size,
    236 				 GL_MAP_READ_BIT, /* ? */
    237 				 list->vertex_store->bufferobj);
    238 
    239    vbo_loopback_vertex_list(ctx,
    240                             (const GLfloat *)(buffer + list->buffer_offset),
    241                             list->attrsz,
    242                             list->prim,
    243                             list->prim_count,
    244                             list->wrap_count,
    245                             list->vertex_size);
    246 
    247    ctx->Driver.UnmapBuffer(ctx, list->vertex_store->bufferobj);
    248 }
    249 
    250 
    251 /**
    252  * Execute the buffer and save copied verts.
    253  * This is called from the display list code when executing
    254  * a drawing command.
    255  */
    256 void
    257 vbo_save_playback_vertex_list(struct gl_context *ctx, void *data)
    258 {
    259    const struct vbo_save_vertex_list *node =
    260       (const struct vbo_save_vertex_list *) data;
    261    struct vbo_save_context *save = &vbo_context(ctx)->save;
    262    GLboolean remap_vertex_store = GL_FALSE;
    263 
    264    if (save->vertex_store->buffer) {
    265       /* The vertex store is currently mapped but we're about to replay
    266        * a display list.  This can happen when a nested display list is
    267        * being build with GL_COMPILE_AND_EXECUTE.
    268        * We never want to have mapped vertex buffers when we're drawing.
    269        * Unmap the vertex store, execute the list, then remap the vertex
    270        * store.
    271        */
    272       vbo_save_unmap_vertex_store(ctx, save->vertex_store);
    273       remap_vertex_store = GL_TRUE;
    274    }
    275 
    276    FLUSH_CURRENT(ctx, 0);
    277 
    278    if (node->prim_count > 0) {
    279 
    280       if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END &&
    281 	  node->prim[0].begin) {
    282 
    283 	 /* Degenerate case: list is called inside begin/end pair and
    284 	  * includes operations such as glBegin or glDrawArrays.
    285 	  */
    286 	 if (0)
    287 	    printf("displaylist recursive begin");
    288 
    289 	 vbo_save_loopback_vertex_list( ctx, node );
    290 
    291          goto end;
    292       }
    293       else if (save->replay_flags) {
    294 	 /* Various degnerate cases: translate into immediate mode
    295 	  * calls rather than trying to execute in place.
    296 	  */
    297 	 vbo_save_loopback_vertex_list( ctx, node );
    298 
    299          goto end;
    300       }
    301 
    302       if (ctx->NewState)
    303 	 _mesa_update_state( ctx );
    304 
    305       /* XXX also need to check if shader enabled, but invalid */
    306       if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
    307           (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
    308          _mesa_error(ctx, GL_INVALID_OPERATION,
    309                      "glBegin (invalid vertex/fragment program)");
    310          return;
    311       }
    312 
    313       vbo_bind_vertex_list( ctx, node );
    314 
    315       vbo_draw_method(vbo_context(ctx), DRAW_DISPLAY_LIST);
    316 
    317       /* Again...
    318        */
    319       if (ctx->NewState)
    320 	 _mesa_update_state( ctx );
    321 
    322       if (node->count > 0) {
    323          vbo_context(ctx)->draw_prims(ctx,
    324                                       node->prim,
    325                                       node->prim_count,
    326                                       NULL,
    327                                       GL_TRUE,
    328                                       0,    /* Node is a VBO, so this is ok */
    329                                       node->count - 1,
    330                                       NULL);
    331       }
    332    }
    333 
    334    /* Copy to current?
    335     */
    336    _playback_copy_to_current( ctx, node );
    337 
    338 end:
    339    if (remap_vertex_store) {
    340       save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
    341    }
    342 }
    343 
    344 
    345 #endif /* FEATURE_dlist */
    346