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  * Authors:
     25  *    Keith Whitwell <keithw (at) vmware.com>
     26  */
     27 
     28 #include <stdbool.h>
     29 #include <stdio.h>
     30 #include "main/glheader.h"
     31 #include "main/bufferobj.h"
     32 #include "main/compiler.h"
     33 #include "main/context.h"
     34 #include "main/enums.h"
     35 #include "main/state.h"
     36 #include "main/vtxfmt.h"
     37 
     38 #include "vbo_context.h"
     39 #include "vbo_noop.h"
     40 
     41 
     42 static void
     43 vbo_exec_debug_verts( struct vbo_exec_context *exec )
     44 {
     45    GLuint count = exec->vtx.vert_count;
     46    GLuint i;
     47 
     48    printf("%s: %u vertices %d primitives, %d vertsize\n",
     49 	  __func__,
     50 	  count,
     51 	  exec->vtx.prim_count,
     52 	  exec->vtx.vertex_size);
     53 
     54    for (i = 0 ; i < exec->vtx.prim_count ; i++) {
     55       struct _mesa_prim *prim = &exec->vtx.prim[i];
     56       printf("   prim %d: %s%s %d..%d %s %s\n",
     57 	     i,
     58 	     _mesa_lookup_prim_by_nr(prim->mode),
     59 	     prim->weak ? " (weak)" : "",
     60 	     prim->start,
     61 	     prim->start + prim->count,
     62 	     prim->begin ? "BEGIN" : "(wrap)",
     63 	     prim->end ? "END" : "(wrap)");
     64    }
     65 }
     66 
     67 
     68 /**
     69  * Copy zero, one or two vertices from the current vertex buffer into
     70  * the temporary "copy" buffer.
     71  * This is used when a single primitive overflows a vertex buffer and
     72  * we need to continue the primitive in a new vertex buffer.
     73  * The temporary "copy" buffer holds the vertices which need to get
     74  * copied from the old buffer to the new one.
     75  */
     76 static GLuint
     77 vbo_copy_vertices( struct vbo_exec_context *exec )
     78 {
     79    struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
     80    const GLuint nr = last_prim->count;
     81    GLuint ovf, i;
     82    const GLuint sz = exec->vtx.vertex_size;
     83    fi_type *dst = exec->vtx.copied.buffer;
     84    const fi_type *src = exec->vtx.buffer_map + last_prim->start * sz;
     85 
     86    switch (exec->ctx->Driver.CurrentExecPrimitive) {
     87    case GL_POINTS:
     88       return 0;
     89    case GL_LINES:
     90       ovf = nr&1;
     91       for (i = 0 ; i < ovf ; i++)
     92 	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
     93       return i;
     94    case GL_TRIANGLES:
     95       ovf = nr%3;
     96       for (i = 0 ; i < ovf ; i++)
     97 	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
     98       return i;
     99    case GL_QUADS:
    100       ovf = nr&3;
    101       for (i = 0 ; i < ovf ; i++)
    102 	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
    103       return i;
    104    case GL_LINE_STRIP:
    105       if (nr == 0) {
    106 	 return 0;
    107       }
    108       else {
    109 	 memcpy( dst, src+(nr-1)*sz, sz * sizeof(GLfloat) );
    110 	 return 1;
    111       }
    112    case GL_LINE_LOOP:
    113       if (last_prim->begin == 0) {
    114          /* We're dealing with the second or later section of a split/wrapped
    115           * GL_LINE_LOOP.  Since we're converting line loops to line strips,
    116           * we've already increment the last_prim->start counter by one to
    117           * skip the 0th vertex in the loop.  We need to undo that (effectively
    118           * subtract one from last_prim->start) so that we copy the 0th vertex
    119           * to the next vertex buffer.
    120           */
    121          assert(last_prim->start > 0);
    122          src -= sz;
    123       }
    124       /* fall-through */
    125    case GL_TRIANGLE_FAN:
    126    case GL_POLYGON:
    127       if (nr == 0) {
    128 	 return 0;
    129       }
    130       else if (nr == 1) {
    131 	 memcpy( dst, src+0, sz * sizeof(GLfloat) );
    132 	 return 1;
    133       }
    134       else {
    135 	 memcpy( dst, src+0, sz * sizeof(GLfloat) );
    136 	 memcpy( dst+sz, src+(nr-1)*sz, sz * sizeof(GLfloat) );
    137 	 return 2;
    138       }
    139    case GL_TRIANGLE_STRIP:
    140       /* no parity issue, but need to make sure the tri is not drawn twice */
    141       if (nr & 1) {
    142 	 last_prim->count--;
    143       }
    144       /* fallthrough */
    145    case GL_QUAD_STRIP:
    146       switch (nr) {
    147       case 0:
    148          ovf = 0;
    149          break;
    150       case 1:
    151          ovf = 1;
    152          break;
    153       default:
    154          ovf = 2 + (nr & 1);
    155          break;
    156       }
    157       for (i = 0 ; i < ovf ; i++)
    158 	 memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz * sizeof(GLfloat) );
    159       return i;
    160    case PRIM_OUTSIDE_BEGIN_END:
    161       return 0;
    162    default:
    163       assert(0);
    164       return 0;
    165    }
    166 }
    167 
    168 
    169 
    170 /* TODO: populate these as the vertex is defined:
    171  */
    172 static void
    173 vbo_exec_bind_arrays( struct gl_context *ctx )
    174 {
    175    struct vbo_context *vbo = vbo_context(ctx);
    176    struct vbo_exec_context *exec = &vbo->exec;
    177    struct gl_vertex_array *arrays = exec->vtx.arrays;
    178    const GLuint *map;
    179    GLuint attr;
    180    GLbitfield64 varying_inputs = 0x0;
    181    bool swap_pos = false;
    182 
    183    /* Install the default (ie Current) attributes first, then overlay
    184     * all active ones.
    185     */
    186    switch (get_program_mode(exec->ctx)) {
    187    case VP_NONE:
    188       for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
    189          exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
    190       }
    191       for (attr = 0; attr < MAT_ATTRIB_MAX; attr++) {
    192          assert(VERT_ATTRIB_GENERIC(attr) < ARRAY_SIZE(exec->vtx.inputs));
    193          exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] =
    194             &vbo->currval[VBO_ATTRIB_MAT_FRONT_AMBIENT+attr];
    195       }
    196       map = vbo->map_vp_none;
    197       break;
    198    case VP_ARB:
    199       for (attr = 0; attr < VERT_ATTRIB_FF_MAX; attr++) {
    200          exec->vtx.inputs[attr] = &vbo->currval[VBO_ATTRIB_POS+attr];
    201       }
    202       for (attr = 0; attr < VERT_ATTRIB_GENERIC_MAX; attr++) {
    203          assert(VERT_ATTRIB_GENERIC(attr) < ARRAY_SIZE(exec->vtx.inputs));
    204          exec->vtx.inputs[VERT_ATTRIB_GENERIC(attr)] =
    205             &vbo->currval[VBO_ATTRIB_GENERIC0+attr];
    206       }
    207       map = vbo->map_vp_arb;
    208 
    209       /* check if VERT_ATTRIB_POS is not read but VERT_BIT_GENERIC0 is read.
    210        * In that case we effectively need to route the data from
    211        * glVertexAttrib(0, val) calls to feed into the GENERIC0 input.
    212        * The original state gets essentially restored below.
    213        */
    214       if ((ctx->VertexProgram._Current->info.inputs_read &
    215            VERT_BIT_POS) == 0 &&
    216           (ctx->VertexProgram._Current->info.inputs_read &
    217            VERT_BIT_GENERIC0)) {
    218          swap_pos = true;
    219          exec->vtx.inputs[VERT_ATTRIB_GENERIC0] = exec->vtx.inputs[0];
    220          exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = exec->vtx.attrsz[0];
    221          exec->vtx.attrtype[VERT_ATTRIB_GENERIC0] = exec->vtx.attrtype[0];
    222          exec->vtx.attrptr[VERT_ATTRIB_GENERIC0] = exec->vtx.attrptr[0];
    223          exec->vtx.attrsz[0] = 0;
    224       }
    225       break;
    226    default:
    227       assert(0);
    228    }
    229 
    230    for (attr = 0; attr < VERT_ATTRIB_MAX ; attr++) {
    231       const GLuint src = map[attr];
    232 
    233       if (exec->vtx.attrsz[src]) {
    234 	 GLsizeiptr offset = (GLbyte *)exec->vtx.attrptr[src] -
    235 	    (GLbyte *)exec->vtx.vertex;
    236 
    237          /* override the default array set above */
    238          assert(attr < ARRAY_SIZE(exec->vtx.inputs));
    239          assert(attr < ARRAY_SIZE(exec->vtx.arrays)); /* arrays[] */
    240          exec->vtx.inputs[attr] = &arrays[attr];
    241 
    242          if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
    243             /* a real buffer obj: Ptr is an offset, not a pointer */
    244             assert(exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Pointer);
    245             assert(offset >= 0);
    246             arrays[attr].Ptr = (GLubyte *)
    247                exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset + offset;
    248          }
    249          else {
    250             /* Ptr into ordinary app memory */
    251             arrays[attr].Ptr = (GLubyte *)exec->vtx.buffer_map + offset;
    252          }
    253 	 arrays[attr].Size = exec->vtx.attrsz[src];
    254 	 arrays[attr].StrideB = exec->vtx.vertex_size * sizeof(GLfloat);
    255 	 arrays[attr].Type = exec->vtx.attrtype[src];
    256 	 arrays[attr].Integer =
    257                vbo_attrtype_to_integer_flag(exec->vtx.attrtype[src]);
    258          arrays[attr].Format = GL_RGBA;
    259          arrays[attr]._ElementSize = arrays[attr].Size * sizeof(GLfloat);
    260          _mesa_reference_buffer_object(ctx,
    261                                        &arrays[attr].BufferObj,
    262                                        exec->vtx.bufferobj);
    263 
    264          varying_inputs |= VERT_BIT(attr);
    265       }
    266    }
    267 
    268    /* In case we swapped the position and generic0 attribute.
    269     * Restore the original setting of the vtx.* variables.
    270     * They are still needed with the original order and settings in case
    271     * of a split primitive.
    272     */
    273    if (swap_pos) {
    274       exec->vtx.attrsz[0] = exec->vtx.attrsz[VERT_ATTRIB_GENERIC0];
    275       exec->vtx.attrsz[VERT_ATTRIB_GENERIC0] = 0;
    276    }
    277 
    278    _mesa_set_varying_vp_inputs( ctx, varying_inputs );
    279    ctx->NewDriverState |= ctx->DriverFlags.NewArray;
    280 }
    281 
    282 
    283 /**
    284  * Unmap the VBO.  This is called before drawing.
    285  */
    286 static void
    287 vbo_exec_vtx_unmap( struct vbo_exec_context *exec )
    288 {
    289    if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
    290       struct gl_context *ctx = exec->ctx;
    291 
    292       if (ctx->Driver.FlushMappedBufferRange) {
    293          GLintptr offset = exec->vtx.buffer_used -
    294                            exec->vtx.bufferobj->Mappings[MAP_INTERNAL].Offset;
    295          GLsizeiptr length = (exec->vtx.buffer_ptr - exec->vtx.buffer_map) *
    296                              sizeof(float);
    297 
    298          if (length)
    299             ctx->Driver.FlushMappedBufferRange(ctx, offset, length,
    300                                                exec->vtx.bufferobj,
    301                                                MAP_INTERNAL);
    302       }
    303 
    304       exec->vtx.buffer_used += (exec->vtx.buffer_ptr -
    305                                 exec->vtx.buffer_map) * sizeof(float);
    306 
    307       assert(exec->vtx.buffer_used <= VBO_VERT_BUFFER_SIZE);
    308       assert(exec->vtx.buffer_ptr != NULL);
    309 
    310       ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
    311       exec->vtx.buffer_map = NULL;
    312       exec->vtx.buffer_ptr = NULL;
    313       exec->vtx.max_vert = 0;
    314    }
    315 }
    316 
    317 
    318 /**
    319  * Map the vertex buffer to begin storing glVertex, glColor, etc data.
    320  */
    321 void
    322 vbo_exec_vtx_map( struct vbo_exec_context *exec )
    323 {
    324    struct gl_context *ctx = exec->ctx;
    325    const GLenum accessRange = GL_MAP_WRITE_BIT |  /* for MapBufferRange */
    326                               GL_MAP_INVALIDATE_RANGE_BIT |
    327                               GL_MAP_UNSYNCHRONIZED_BIT |
    328                               GL_MAP_FLUSH_EXPLICIT_BIT |
    329                               MESA_MAP_NOWAIT_BIT;
    330    const GLenum usage = GL_STREAM_DRAW_ARB;
    331 
    332    if (!_mesa_is_bufferobj(exec->vtx.bufferobj))
    333       return;
    334 
    335    assert(!exec->vtx.buffer_map);
    336    assert(!exec->vtx.buffer_ptr);
    337 
    338    if (VBO_VERT_BUFFER_SIZE > exec->vtx.buffer_used + 1024) {
    339       /* The VBO exists and there's room for more */
    340       if (exec->vtx.bufferobj->Size > 0) {
    341          exec->vtx.buffer_map =
    342             (fi_type *)ctx->Driver.MapBufferRange(ctx,
    343                                                   exec->vtx.buffer_used,
    344                                                   (VBO_VERT_BUFFER_SIZE -
    345                                                    exec->vtx.buffer_used),
    346                                                   accessRange,
    347                                                   exec->vtx.bufferobj,
    348                                                   MAP_INTERNAL);
    349          exec->vtx.buffer_ptr = exec->vtx.buffer_map;
    350       }
    351       else {
    352          exec->vtx.buffer_ptr = exec->vtx.buffer_map = NULL;
    353       }
    354    }
    355 
    356    if (!exec->vtx.buffer_map) {
    357       /* Need to allocate a new VBO */
    358       exec->vtx.buffer_used = 0;
    359 
    360       if (ctx->Driver.BufferData(ctx, GL_ARRAY_BUFFER_ARB,
    361                                  VBO_VERT_BUFFER_SIZE,
    362                                  NULL, usage,
    363                                  GL_MAP_WRITE_BIT |
    364                                  GL_DYNAMIC_STORAGE_BIT |
    365                                  GL_CLIENT_STORAGE_BIT,
    366                                  exec->vtx.bufferobj)) {
    367          /* buffer allocation worked, now map the buffer */
    368          exec->vtx.buffer_map =
    369             (fi_type *)ctx->Driver.MapBufferRange(ctx,
    370                                                   0, VBO_VERT_BUFFER_SIZE,
    371                                                   accessRange,
    372                                                   exec->vtx.bufferobj,
    373                                                   MAP_INTERNAL);
    374       }
    375       else {
    376          _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
    377          exec->vtx.buffer_map = NULL;
    378       }
    379    }
    380 
    381    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
    382 
    383    if (!exec->vtx.buffer_map) {
    384       /* out of memory */
    385       _mesa_install_exec_vtxfmt( ctx, &exec->vtxfmt_noop );
    386    }
    387    else {
    388       if (_mesa_using_noop_vtxfmt(ctx->Exec)) {
    389          /* The no-op functions are installed so switch back to regular
    390           * functions.  We do this test just to avoid frequent and needless
    391           * calls to _mesa_install_exec_vtxfmt().
    392           */
    393          _mesa_install_exec_vtxfmt(ctx, &exec->vtxfmt);
    394       }
    395    }
    396 
    397    if (0)
    398       printf("map %d..\n", exec->vtx.buffer_used);
    399 }
    400 
    401 
    402 
    403 /**
    404  * Execute the buffer and save copied verts.
    405  * \param keep_unmapped  if true, leave the VBO unmapped when we're done.
    406  */
    407 void
    408 vbo_exec_vtx_flush(struct vbo_exec_context *exec, GLboolean keepUnmapped)
    409 {
    410    if (0)
    411       vbo_exec_debug_verts( exec );
    412 
    413    if (exec->vtx.prim_count &&
    414        exec->vtx.vert_count) {
    415 
    416       exec->vtx.copied.nr = vbo_copy_vertices( exec );
    417 
    418       if (exec->vtx.copied.nr != exec->vtx.vert_count) {
    419 	 struct gl_context *ctx = exec->ctx;
    420 
    421 	 /* Before the update_state() as this may raise _NEW_VARYING_VP_INPUTS
    422           * from _mesa_set_varying_vp_inputs().
    423 	  */
    424 	 vbo_exec_bind_arrays( ctx );
    425 
    426          if (ctx->NewState)
    427             _mesa_update_state( ctx );
    428 
    429          if (_mesa_is_bufferobj(exec->vtx.bufferobj)) {
    430             vbo_exec_vtx_unmap( exec );
    431          }
    432 
    433          if (0)
    434             printf("%s %d %d\n", __func__, exec->vtx.prim_count,
    435 		   exec->vtx.vert_count);
    436 
    437 	 vbo_context(ctx)->draw_prims( ctx,
    438 				       exec->vtx.prim,
    439 				       exec->vtx.prim_count,
    440 				       NULL,
    441 				       GL_TRUE,
    442 				       0,
    443 				       exec->vtx.vert_count - 1,
    444 				       NULL, 0, NULL);
    445 
    446 	 /* If using a real VBO, get new storage -- unless asked not to.
    447           */
    448          if (_mesa_is_bufferobj(exec->vtx.bufferobj) && !keepUnmapped) {
    449             vbo_exec_vtx_map( exec );
    450          }
    451       }
    452    }
    453 
    454    /* May have to unmap explicitly if we didn't draw:
    455     */
    456    if (keepUnmapped &&
    457        _mesa_is_bufferobj(exec->vtx.bufferobj) &&
    458        exec->vtx.buffer_map) {
    459       vbo_exec_vtx_unmap( exec );
    460    }
    461 
    462    if (keepUnmapped || exec->vtx.vertex_size == 0)
    463       exec->vtx.max_vert = 0;
    464    else
    465       exec->vtx.max_vert = vbo_compute_max_verts(exec);
    466 
    467    exec->vtx.buffer_ptr = exec->vtx.buffer_map;
    468    exec->vtx.prim_count = 0;
    469    exec->vtx.vert_count = 0;
    470 }
    471