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