Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  
  3. Copyright 2002-2008 VMware, Inc.
  4.  
  5. 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. on the rights to use, copy, modify, merge, publish, distribute, sub
  11. license, and/or sell copies of the Software, and to permit persons to whom
  12. the Software is furnished to do so, subject to the following conditions:
  13.  
  14. The above copyright notice and this permission notice (including the next
  15. paragraph) shall be included in all copies or substantial portions of the
  16. Software.
  17.  
  18. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  21. VMWARE AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
  22. DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23. OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  24. USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  
  26. **************************************************************************/
  27.  
  28. /*
  29.  * Authors:
  30.  *   Keith Whitwell <keithw@vmware.com>
  31.  */
  32.  
  33.  
  34.  
  35. /* Display list compiler attempts to store lists of vertices with the
  36.  * same vertex layout.  Additionally it attempts to minimize the need
  37.  * for execute-time fixup of these vertex lists, allowing them to be
  38.  * cached on hardware.
  39.  *
  40.  * There are still some circumstances where this can be thwarted, for
  41.  * example by building a list that consists of one very long primitive
  42.  * (eg Begin(Triangles), 1000 vertices, End), and calling that list
  43.  * from inside a different begin/end object (Begin(Lines), CallList,
  44.  * End).
  45.  *
  46.  * In that case the code will have to replay the list as individual
  47.  * commands through the Exec dispatch table, or fix up the copied
  48.  * vertices at execute-time.
  49.  *
  50.  * The other case where fixup is required is when a vertex attribute
  51.  * is introduced in the middle of a primitive.  Eg:
  52.  *  Begin(Lines)
  53.  *  TexCoord1f()           Vertex2f()
  54.  *  TexCoord1f() Color3f() Vertex2f()
  55.  *  End()
  56.  *
  57.  *  If the current value of Color isn't known at compile-time, this
  58.  *  primitive will require fixup.
  59.  *
  60.  *
  61.  * The list compiler currently doesn't attempt to compile lists
  62.  * containing EvalCoord or EvalPoint commands.  On encountering one of
  63.  * these, compilation falls back to opcodes.
  64.  *
  65.  * This could be improved to fallback only when a mix of EvalCoord and
  66.  * Vertex commands are issued within a single primitive.
  67.  */
  68.  
  69.  
  70. #include "main/glheader.h"
  71. #include "main/bufferobj.h"
  72. #include "main/context.h"
  73. #include "main/dlist.h"
  74. #include "main/enums.h"
  75. #include "main/eval.h"
  76. #include "main/macros.h"
  77. #include "main/api_validate.h"
  78. #include "main/api_arrayelt.h"
  79. #include "main/vtxfmt.h"
  80. #include "main/dispatch.h"
  81.  
  82. #include "vbo_context.h"
  83. #include "vbo_noop.h"
  84.  
  85.  
  86. #ifdef ERROR
  87. #undef ERROR
  88. #endif
  89.  
  90.  
  91. /* An interesting VBO number/name to help with debugging */
  92. #define VBO_BUF_ID  12345
  93.  
  94.  
  95. /*
  96.  * NOTE: Old 'parity' issue is gone, but copying can still be
  97.  * wrong-footed on replay.
  98.  */
  99. static GLuint
  100. _save_copy_vertices(struct gl_context *ctx,
  101.                     const struct vbo_save_vertex_list *node,
  102.                     const fi_type * src_buffer)
  103. {
  104.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  105.    const struct _mesa_prim *prim = &node->prim[node->prim_count - 1];
  106.    GLuint nr = prim->count;
  107.    GLuint sz = save->vertex_size;
  108.    const fi_type *src = src_buffer + prim->start * sz;
  109.    fi_type *dst = save->copied.buffer;
  110.    GLuint ovf, i;
  111.  
  112.    if (prim->end)
  113.       return 0;
  114.  
  115.    switch (prim->mode) {
  116.    case GL_POINTS:
  117.       return 0;
  118.    case GL_LINES:
  119.       ovf = nr & 1;
  120.       for (i = 0; i < ovf; i++)
  121.          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
  122.                 sz * sizeof(GLfloat));
  123.       return i;
  124.    case GL_TRIANGLES:
  125.       ovf = nr % 3;
  126.       for (i = 0; i < ovf; i++)
  127.          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
  128.                 sz * sizeof(GLfloat));
  129.       return i;
  130.    case GL_QUADS:
  131.       ovf = nr & 3;
  132.       for (i = 0; i < ovf; i++)
  133.          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
  134.                 sz * sizeof(GLfloat));
  135.       return i;
  136.    case GL_LINE_STRIP:
  137.       if (nr == 0)
  138.          return 0;
  139.       else {
  140.          memcpy(dst, src + (nr - 1) * sz, sz * sizeof(GLfloat));
  141.          return 1;
  142.       }
  143.    case GL_LINE_LOOP:
  144.    case GL_TRIANGLE_FAN:
  145.    case GL_POLYGON:
  146.       if (nr == 0)
  147.          return 0;
  148.       else if (nr == 1) {
  149.          memcpy(dst, src + 0, sz * sizeof(GLfloat));
  150.          return 1;
  151.       }
  152.       else {
  153.          memcpy(dst, src + 0, sz * sizeof(GLfloat));
  154.          memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat));
  155.          return 2;
  156.       }
  157.    case GL_TRIANGLE_STRIP:
  158.    case GL_QUAD_STRIP:
  159.       switch (nr) {
  160.       case 0:
  161.          ovf = 0;
  162.          break;
  163.       case 1:
  164.          ovf = 1;
  165.          break;
  166.       default:
  167.          ovf = 2 + (nr & 1);
  168.          break;
  169.       }
  170.       for (i = 0; i < ovf; i++)
  171.          memcpy(dst + i * sz, src + (nr - ovf + i) * sz,
  172.                 sz * sizeof(GLfloat));
  173.       return i;
  174.    default:
  175.       assert(0);
  176.       return 0;
  177.    }
  178. }
  179.  
  180.  
  181. static struct vbo_save_vertex_store *
  182. alloc_vertex_store(struct gl_context *ctx)
  183. {
  184.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  185.    struct vbo_save_vertex_store *vertex_store =
  186.       CALLOC_STRUCT(vbo_save_vertex_store);
  187.  
  188.    /* obj->Name needs to be non-zero, but won't ever be examined more
  189.     * closely than that.  In particular these buffers won't be entered
  190.     * into the hash and can never be confused with ones visible to the
  191.     * user.  Perhaps there could be a special number for internal
  192.     * buffers:
  193.     */
  194.    vertex_store->bufferobj = ctx->Driver.NewBufferObject(ctx, VBO_BUF_ID);
  195.    if (vertex_store->bufferobj) {
  196.       save->out_of_memory =
  197.          !ctx->Driver.BufferData(ctx,
  198.                                  GL_ARRAY_BUFFER_ARB,
  199.                                  VBO_SAVE_BUFFER_SIZE * sizeof(GLfloat),
  200.                                  NULL, GL_STATIC_DRAW_ARB,
  201.                                  GL_MAP_WRITE_BIT |
  202.                                  GL_DYNAMIC_STORAGE_BIT,
  203.                                  vertex_store->bufferobj);
  204.    }
  205.    else {
  206.       save->out_of_memory = GL_TRUE;
  207.    }
  208.  
  209.    if (save->out_of_memory) {
  210.       _mesa_error(ctx, GL_OUT_OF_MEMORY, "internal VBO allocation");
  211.       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
  212.    }
  213.  
  214.    vertex_store->buffer = NULL;
  215.    vertex_store->used = 0;
  216.    vertex_store->refcount = 1;
  217.  
  218.    return vertex_store;
  219. }
  220.  
  221.  
  222. static void
  223. free_vertex_store(struct gl_context *ctx,
  224.                   struct vbo_save_vertex_store *vertex_store)
  225. {
  226.    assert(!vertex_store->buffer);
  227.  
  228.    if (vertex_store->bufferobj) {
  229.       _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL);
  230.    }
  231.  
  232.    free(vertex_store);
  233. }
  234.  
  235.  
  236. fi_type *
  237. vbo_save_map_vertex_store(struct gl_context *ctx,
  238.                           struct vbo_save_vertex_store *vertex_store)
  239. {
  240.    const GLbitfield access = (GL_MAP_WRITE_BIT |
  241.                               GL_MAP_INVALIDATE_RANGE_BIT |
  242.                               GL_MAP_UNSYNCHRONIZED_BIT |
  243.                               GL_MAP_FLUSH_EXPLICIT_BIT);
  244.  
  245.    assert(vertex_store->bufferobj);
  246.    assert(!vertex_store->buffer);  /* the buffer should not be mapped */
  247.  
  248.    if (vertex_store->bufferobj->Size > 0) {
  249.       /* Map the remaining free space in the VBO */
  250.       GLintptr offset = vertex_store->used * sizeof(GLfloat);
  251.       GLsizeiptr size = vertex_store->bufferobj->Size - offset;
  252.       fi_type *range = (fi_type *)
  253.          ctx->Driver.MapBufferRange(ctx, offset, size, access,
  254.                                     vertex_store->bufferobj,
  255.                                     MAP_INTERNAL);
  256.       if (range) {
  257.          /* compute address of start of whole buffer (needed elsewhere) */
  258.          vertex_store->buffer = range - vertex_store->used;
  259.          assert(vertex_store->buffer);
  260.          return range;
  261.       }
  262.       else {
  263.          vertex_store->buffer = NULL;
  264.          return NULL;
  265.       }
  266.    }
  267.    else {
  268.       /* probably ran out of memory for buffers */
  269.       return NULL;
  270.    }
  271. }
  272.  
  273.  
  274. void
  275. vbo_save_unmap_vertex_store(struct gl_context *ctx,
  276.                             struct vbo_save_vertex_store *vertex_store)
  277. {
  278.    if (vertex_store->bufferobj->Size > 0) {
  279.       GLintptr offset = 0;
  280.       GLsizeiptr length = vertex_store->used * sizeof(GLfloat)
  281.          - vertex_store->bufferobj->Mappings[MAP_INTERNAL].Offset;
  282.  
  283.       /* Explicitly flush the region we wrote to */
  284.       ctx->Driver.FlushMappedBufferRange(ctx, offset, length,
  285.                                          vertex_store->bufferobj,
  286.                                          MAP_INTERNAL);
  287.  
  288.       ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj, MAP_INTERNAL);
  289.    }
  290.    vertex_store->buffer = NULL;
  291. }
  292.  
  293.  
  294. static struct vbo_save_primitive_store *
  295. alloc_prim_store(struct gl_context *ctx)
  296. {
  297.    struct vbo_save_primitive_store *store =
  298.       CALLOC_STRUCT(vbo_save_primitive_store);
  299.    (void) ctx;
  300.    store->used = 0;
  301.    store->refcount = 1;
  302.    return store;
  303. }
  304.  
  305.  
  306. static void
  307. _save_reset_counters(struct gl_context *ctx)
  308. {
  309.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  310.  
  311.    save->prim = save->prim_store->buffer + save->prim_store->used;
  312.    save->buffer = save->vertex_store->buffer + save->vertex_store->used;
  313.  
  314.    assert(save->buffer == save->buffer_ptr);
  315.  
  316.    if (save->vertex_size)
  317.       save->max_vert = (VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
  318.                         save->vertex_size;
  319.    else
  320.       save->max_vert = 0;
  321.  
  322.    save->vert_count = 0;
  323.    save->prim_count = 0;
  324.    save->prim_max = VBO_SAVE_PRIM_SIZE - save->prim_store->used;
  325.    save->dangling_attr_ref = GL_FALSE;
  326. }
  327.  
  328. /**
  329.  * For a list of prims, try merging prims that can just be extensions of the
  330.  * previous prim.
  331.  */
  332. static void
  333. merge_prims(struct gl_context *ctx,
  334.             struct _mesa_prim *prim_list,
  335.             GLuint *prim_count)
  336. {
  337.    GLuint i;
  338.    struct _mesa_prim *prev_prim = prim_list;
  339.  
  340.    for (i = 1; i < *prim_count; i++) {
  341.       struct _mesa_prim *this_prim = prim_list + i;
  342.  
  343.       vbo_try_prim_conversion(this_prim);
  344.  
  345.       if (vbo_can_merge_prims(prev_prim, this_prim)) {
  346.          /* We've found a prim that just extend the previous one.  Tack it
  347.           * onto the previous one, and let this primitive struct get dropped.
  348.           */
  349.          vbo_merge_prims(prev_prim, this_prim);
  350.          continue;
  351.       }
  352.  
  353.       /* If any previous primitives have been dropped, then we need to copy
  354.        * this later one into the next available slot.
  355.        */
  356.       prev_prim++;
  357.       if (prev_prim != this_prim)
  358.          *prev_prim = *this_prim;
  359.    }
  360.  
  361.    *prim_count = prev_prim - prim_list + 1;
  362. }
  363.  
  364. /**
  365.  * Insert the active immediate struct onto the display list currently
  366.  * being built.
  367.  */
  368. static void
  369. _save_compile_vertex_list(struct gl_context *ctx)
  370. {
  371.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  372.    struct vbo_save_vertex_list *node;
  373.  
  374.    /* Allocate space for this structure in the display list currently
  375.     * being compiled.
  376.     */
  377.    node = (struct vbo_save_vertex_list *)
  378.       _mesa_dlist_alloc_aligned(ctx, save->opcode_vertex_list, sizeof(*node));
  379.  
  380.    if (!node)
  381.       return;
  382.  
  383.    /* Make sure the pointer is aligned to the size of a pointer */
  384.    assert((GLintptr) node % sizeof(void *) == 0);
  385.  
  386.    /* Duplicate our template, increment refcounts to the storage structs:
  387.     */
  388.    memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz));
  389.    memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype));
  390.    node->vertex_size = save->vertex_size;
  391.    node->buffer_offset =
  392.       (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat);
  393.    node->count = save->vert_count;
  394.    node->wrap_count = save->copied.nr;
  395.    node->dangling_attr_ref = save->dangling_attr_ref;
  396.    node->prim = save->prim;
  397.    node->prim_count = save->prim_count;
  398.    node->vertex_store = save->vertex_store;
  399.    node->prim_store = save->prim_store;
  400.  
  401.    node->vertex_store->refcount++;
  402.    node->prim_store->refcount++;
  403.  
  404.    if (node->prim[0].no_current_update) {
  405.       node->current_size = 0;
  406.       node->current_data = NULL;
  407.    }
  408.    else {
  409.       node->current_size = node->vertex_size - node->attrsz[0];
  410.       node->current_data = NULL;
  411.  
  412.       if (node->current_size) {
  413.          /* If the malloc fails, we just pull the data out of the VBO
  414.           * later instead.
  415.           */
  416.          node->current_data = malloc(node->current_size * sizeof(GLfloat));
  417.          if (node->current_data) {
  418.             const char *buffer = (const char *) save->vertex_store->buffer;
  419.             unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat);
  420.             unsigned vertex_offset = 0;
  421.  
  422.             if (node->count)
  423.                vertex_offset =
  424.                   (node->count - 1) * node->vertex_size * sizeof(GLfloat);
  425.  
  426.             memcpy(node->current_data,
  427.                    buffer + node->buffer_offset + vertex_offset + attr_offset,
  428.                    node->current_size * sizeof(GLfloat));
  429.          }
  430.       }
  431.    }
  432.  
  433.    assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0);
  434.  
  435.    if (save->dangling_attr_ref)
  436.       ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS;
  437.  
  438.    save->vertex_store->used += save->vertex_size * node->count;
  439.    save->prim_store->used += node->prim_count;
  440.  
  441.    /* Copy duplicated vertices
  442.     */
  443.    save->copied.nr = _save_copy_vertices(ctx, node, save->buffer);
  444.  
  445.    merge_prims(ctx, node->prim, &node->prim_count);
  446.  
  447.    /* Deal with GL_COMPILE_AND_EXECUTE:
  448.     */
  449.    if (ctx->ExecuteFlag) {
  450.       struct _glapi_table *dispatch = GET_DISPATCH();
  451.  
  452.       _glapi_set_dispatch(ctx->Exec);
  453.  
  454.       vbo_loopback_vertex_list(ctx,
  455.                                (const GLfloat *) ((const char *) save->
  456.                                                   vertex_store->buffer +
  457.                                                   node->buffer_offset),
  458.                                node->attrsz, node->prim, node->prim_count,
  459.                                node->wrap_count, node->vertex_size);
  460.  
  461.       _glapi_set_dispatch(dispatch);
  462.    }
  463.  
  464.    /* Decide whether the storage structs are full, or can be used for
  465.     * the next vertex lists as well.
  466.     */
  467.    if (save->vertex_store->used >
  468.        VBO_SAVE_BUFFER_SIZE - 16 * (save->vertex_size + 4)) {
  469.  
  470.       /* Unmap old store:
  471.        */
  472.       vbo_save_unmap_vertex_store(ctx, save->vertex_store);
  473.  
  474.       /* Release old reference:
  475.        */
  476.       save->vertex_store->refcount--;
  477.       assert(save->vertex_store->refcount != 0);
  478.       save->vertex_store = NULL;
  479.  
  480.       /* Allocate and map new store:
  481.        */
  482.       save->vertex_store = alloc_vertex_store(ctx);
  483.       save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
  484.       save->out_of_memory = save->buffer_ptr == NULL;
  485.    }
  486.  
  487.    if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) {
  488.       save->prim_store->refcount--;
  489.       assert(save->prim_store->refcount != 0);
  490.       save->prim_store = alloc_prim_store(ctx);
  491.    }
  492.  
  493.    /* Reset our structures for the next run of vertices:
  494.     */
  495.    _save_reset_counters(ctx);
  496. }
  497.  
  498.  
  499. /**
  500.  * This is called when we fill a vertex buffer before we hit a glEnd().
  501.  * We
  502.  * TODO -- If no new vertices have been stored, don't bother saving it.
  503.  */
  504. static void
  505. _save_wrap_buffers(struct gl_context *ctx)
  506. {
  507.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  508.    GLint i = save->prim_count - 1;
  509.    GLenum mode;
  510.    GLboolean weak;
  511.    GLboolean no_current_update;
  512.  
  513.    assert(i < (GLint) save->prim_max);
  514.    assert(i >= 0);
  515.  
  516.    /* Close off in-progress primitive.
  517.     */
  518.    save->prim[i].count = (save->vert_count - save->prim[i].start);
  519.    mode = save->prim[i].mode;
  520.    weak = save->prim[i].weak;
  521.    no_current_update = save->prim[i].no_current_update;
  522.  
  523.    /* store the copied vertices, and allocate a new list.
  524.     */
  525.    _save_compile_vertex_list(ctx);
  526.  
  527.    /* Restart interrupted primitive
  528.     */
  529.    save->prim[0].mode = mode;
  530.    save->prim[0].weak = weak;
  531.    save->prim[0].no_current_update = no_current_update;
  532.    save->prim[0].begin = 0;
  533.    save->prim[0].end = 0;
  534.    save->prim[0].pad = 0;
  535.    save->prim[0].start = 0;
  536.    save->prim[0].count = 0;
  537.    save->prim[0].num_instances = 1;
  538.    save->prim[0].base_instance = 0;
  539.    save->prim[0].is_indirect = 0;
  540.    save->prim_count = 1;
  541. }
  542.  
  543.  
  544. /**
  545.  * Called only when buffers are wrapped as the result of filling the
  546.  * vertex_store struct.
  547.  */
  548. static void
  549. _save_wrap_filled_vertex(struct gl_context *ctx)
  550. {
  551.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  552.    fi_type *data = save->copied.buffer;
  553.    GLuint i;
  554.  
  555.    /* Emit a glEnd to close off the last vertex list.
  556.     */
  557.    _save_wrap_buffers(ctx);
  558.  
  559.    /* Copy stored stored vertices to start of new list.
  560.     */
  561.    assert(save->max_vert - save->vert_count > save->copied.nr);
  562.  
  563.    for (i = 0; i < save->copied.nr; i++) {
  564.       memcpy(save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat));
  565.       data += save->vertex_size;
  566.       save->buffer_ptr += save->vertex_size;
  567.       save->vert_count++;
  568.    }
  569. }
  570.  
  571.  
  572. static void
  573. _save_copy_to_current(struct gl_context *ctx)
  574. {
  575.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  576.    GLuint i;
  577.  
  578.    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
  579.       if (save->attrsz[i]) {
  580.          save->currentsz[i][0] = save->attrsz[i];
  581.          COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i],
  582.                                      save->attrptr[i], save->attrtype[i]);
  583.       }
  584.    }
  585. }
  586.  
  587.  
  588. static void
  589. _save_copy_from_current(struct gl_context *ctx)
  590. {
  591.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  592.    GLint i;
  593.  
  594.    for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
  595.       switch (save->attrsz[i]) {
  596.       case 4:
  597.          save->attrptr[i][3] = save->current[i][3];
  598.       case 3:
  599.          save->attrptr[i][2] = save->current[i][2];
  600.       case 2:
  601.          save->attrptr[i][1] = save->current[i][1];
  602.       case 1:
  603.          save->attrptr[i][0] = save->current[i][0];
  604.       case 0:
  605.          break;
  606.       }
  607.    }
  608. }
  609.  
  610.  
  611. /**
  612.  * Called when we increase the size of a vertex attribute.  For example,
  613.  * if we've seen one or more glTexCoord2f() calls and now we get a
  614.  * glTexCoord3f() call.
  615.  * Flush existing data, set new attrib size, replay copied vertices.
  616.  */
  617. static void
  618. _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz)
  619. {
  620.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  621.    GLuint oldsz;
  622.    GLuint i;
  623.    fi_type *tmp;
  624.  
  625.    /* Store the current run of vertices, and emit a GL_END.  Emit a
  626.     * BEGIN in the new buffer.
  627.     */
  628.    if (save->vert_count)
  629.       _save_wrap_buffers(ctx);
  630.    else
  631.       assert(save->copied.nr == 0);
  632.  
  633.    /* Do a COPY_TO_CURRENT to ensure back-copying works for the case
  634.     * when the attribute already exists in the vertex and is having
  635.     * its size increased.
  636.     */
  637.    _save_copy_to_current(ctx);
  638.  
  639.    /* Fix up sizes:
  640.     */
  641.    oldsz = save->attrsz[attr];
  642.    save->attrsz[attr] = newsz;
  643.  
  644.    save->vertex_size += newsz - oldsz;
  645.    save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) /
  646.                      save->vertex_size);
  647.    save->vert_count = 0;
  648.  
  649.    /* Recalculate all the attrptr[] values:
  650.     */
  651.    for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) {
  652.       if (save->attrsz[i]) {
  653.          save->attrptr[i] = tmp;
  654.          tmp += save->attrsz[i];
  655.       }
  656.       else {
  657.          save->attrptr[i] = NULL;       /* will not be dereferenced. */
  658.       }
  659.    }
  660.  
  661.    /* Copy from current to repopulate the vertex with correct values.
  662.     */
  663.    _save_copy_from_current(ctx);
  664.  
  665.    /* Replay stored vertices to translate them to new format here.
  666.     *
  667.     * If there are copied vertices and the new (upgraded) attribute
  668.     * has not been defined before, this list is somewhat degenerate,
  669.     * and will need fixup at runtime.
  670.     */
  671.    if (save->copied.nr) {
  672.       const fi_type *data = save->copied.buffer;
  673.       fi_type *dest = save->buffer;
  674.       GLuint j;
  675.  
  676.       /* Need to note this and fix up at runtime (or loopback):
  677.        */
  678.       if (attr != VBO_ATTRIB_POS && save->currentsz[attr][0] == 0) {
  679.          assert(oldsz == 0);
  680.          save->dangling_attr_ref = GL_TRUE;
  681.       }
  682.  
  683.       for (i = 0; i < save->copied.nr; i++) {
  684.          for (j = 0; j < VBO_ATTRIB_MAX; j++) {
  685.             if (save->attrsz[j]) {
  686.                if (j == attr) {
  687.                   if (oldsz) {
  688.                      COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data,
  689.                                                  save->attrtype[j]);
  690.                      data += oldsz;
  691.                      dest += newsz;
  692.                   }
  693.                   else {
  694.                      COPY_SZ_4V(dest, newsz, save->current[attr]);
  695.                      dest += newsz;
  696.                   }
  697.                }
  698.                else {
  699.                   GLint sz = save->attrsz[j];
  700.                   COPY_SZ_4V(dest, sz, data);
  701.                   data += sz;
  702.                   dest += sz;
  703.                }
  704.             }
  705.          }
  706.       }
  707.  
  708.       save->buffer_ptr = dest;
  709.       save->vert_count += save->copied.nr;
  710.    }
  711. }
  712.  
  713.  
  714. /**
  715.  * This is called when the size of a vertex attribute changes.
  716.  * For example, after seeing one or more glTexCoord2f() calls we
  717.  * get a glTexCoord4f() or glTexCoord1f() call.
  718.  */
  719. static void
  720. save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz)
  721. {
  722.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  723.  
  724.    if (sz > save->attrsz[attr]) {
  725.       /* New size is larger.  Need to flush existing vertices and get
  726.        * an enlarged vertex format.
  727.        */
  728.       _save_upgrade_vertex(ctx, attr, sz);
  729.    }
  730.    else if (sz < save->active_sz[attr]) {
  731.       GLuint i;
  732.       const fi_type *id = vbo_get_default_vals_as_union(save->attrtype[attr]);
  733.  
  734.       /* New size is equal or smaller - just need to fill in some
  735.        * zeros.
  736.        */
  737.       for (i = sz; i <= save->attrsz[attr]; i++)
  738.          save->attrptr[attr][i - 1] = id[i - 1];
  739.    }
  740.  
  741.    save->active_sz[attr] = sz;
  742. }
  743.  
  744.  
  745. /**
  746.  * Reset the current size of all vertex attributes to the default
  747.  * value of 0.  This signals that we haven't yet seen any per-vertex
  748.  * commands such as glNormal3f() or glTexCoord2f().
  749.  */
  750. static void
  751. _save_reset_vertex(struct gl_context *ctx)
  752. {
  753.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  754.    GLuint i;
  755.  
  756.    for (i = 0; i < VBO_ATTRIB_MAX; i++) {
  757.       save->attrsz[i] = 0;
  758.       save->active_sz[i] = 0;
  759.    }
  760.  
  761.    save->vertex_size = 0;
  762. }
  763.  
  764.  
  765.  
  766. #define ERROR(err)   _mesa_compile_error(ctx, err, __func__);
  767.  
  768.  
  769. /* Only one size for each attribute may be active at once.  Eg. if
  770.  * Color3f is installed/active, then Color4f may not be, even if the
  771.  * vertex actually contains 4 color coordinates.  This is because the
  772.  * 3f version won't otherwise set color[3] to 1.0 -- this is the job
  773.  * of the chooser function when switching between Color4f and Color3f.
  774.  */
  775. #define ATTR_UNION(A, N, T, C, V0, V1, V2, V3)                  \
  776. do {                                                            \
  777.    struct vbo_save_context *save = &vbo_context(ctx)->save;     \
  778.                                                                 \
  779.    if (save->active_sz[A] != N)                                 \
  780.       save_fixup_vertex(ctx, A, N);                             \
  781.                                                                 \
  782.    {                                                            \
  783.       C *dest = (C *)save->attrptr[A];                          \
  784.       if (N>0) dest[0] = V0;                                    \
  785.       if (N>1) dest[1] = V1;                                    \
  786.       if (N>2) dest[2] = V2;                                    \
  787.       if (N>3) dest[3] = V3;                                    \
  788.       save->attrtype[A] = T;                                    \
  789.    }                                                            \
  790.                                                                 \
  791.    if ((A) == 0) {                                              \
  792.       GLuint i;                                                 \
  793.                                                                 \
  794.       for (i = 0; i < save->vertex_size; i++)                   \
  795.          save->buffer_ptr[i] = save->vertex[i];                 \
  796.                                                                 \
  797.       save->buffer_ptr += save->vertex_size;                    \
  798.                                                                 \
  799.       if (++save->vert_count >= save->max_vert)                 \
  800.          _save_wrap_filled_vertex(ctx);                         \
  801.    }                                                            \
  802. } while (0)
  803.  
  804. #define TAG(x) _save_##x
  805.  
  806. #include "vbo_attrib_tmp.h"
  807.  
  808.  
  809.  
  810. #define MAT( ATTR, N, face, params )                    \
  811. do {                                                    \
  812.    if (face != GL_BACK)                                 \
  813.       MAT_ATTR( ATTR, N, params ); /* front */          \
  814.    if (face != GL_FRONT)                                \
  815.       MAT_ATTR( ATTR + 1, N, params ); /* back */       \
  816. } while (0)
  817.  
  818.  
  819. /**
  820.  * Save a glMaterial call found between glBegin/End.
  821.  * glMaterial calls outside Begin/End are handled in dlist.c.
  822.  */
  823. static void GLAPIENTRY
  824. _save_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
  825. {
  826.    GET_CURRENT_CONTEXT(ctx);
  827.  
  828.    if (face != GL_FRONT && face != GL_BACK && face != GL_FRONT_AND_BACK) {
  829.       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(face)");
  830.       return;
  831.    }
  832.  
  833.    switch (pname) {
  834.    case GL_EMISSION:
  835.       MAT(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, face, params);
  836.       break;
  837.    case GL_AMBIENT:
  838.       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
  839.       break;
  840.    case GL_DIFFUSE:
  841.       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
  842.       break;
  843.    case GL_SPECULAR:
  844.       MAT(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params);
  845.       break;
  846.    case GL_SHININESS:
  847.       if (*params < 0 || *params > ctx->Const.MaxShininess) {
  848.          _mesa_compile_error(ctx, GL_INVALID_VALUE, "glMaterial(shininess)");
  849.       }
  850.       else {
  851.          MAT(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, face, params);
  852.       }
  853.       break;
  854.    case GL_COLOR_INDEXES:
  855.       MAT(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, face, params);
  856.       break;
  857.    case GL_AMBIENT_AND_DIFFUSE:
  858.       MAT(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params);
  859.       MAT(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params);
  860.       break;
  861.    default:
  862.       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMaterial(pname)");
  863.       return;
  864.    }
  865. }
  866.  
  867.  
  868. /* Cope with EvalCoord/CallList called within a begin/end object:
  869.  *     -- Flush current buffer
  870.  *     -- Fallback to opcodes for the rest of the begin/end object.
  871.  */
  872. static void
  873. dlist_fallback(struct gl_context *ctx)
  874. {
  875.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  876.  
  877.    if (save->vert_count || save->prim_count) {
  878.       if (save->prim_count > 0) {
  879.          /* Close off in-progress primitive. */
  880.          GLint i = save->prim_count - 1;
  881.          save->prim[i].count = save->vert_count - save->prim[i].start;
  882.       }
  883.  
  884.       /* Need to replay this display list with loopback,
  885.        * unfortunately, otherwise this primitive won't be handled
  886.        * properly:
  887.        */
  888.       save->dangling_attr_ref = GL_TRUE;
  889.  
  890.       _save_compile_vertex_list(ctx);
  891.    }
  892.  
  893.    _save_copy_to_current(ctx);
  894.    _save_reset_vertex(ctx);
  895.    _save_reset_counters(ctx);
  896.    if (save->out_of_memory) {
  897.       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
  898.    }
  899.    else {
  900.       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
  901.    }
  902.    ctx->Driver.SaveNeedFlush = GL_FALSE;
  903. }
  904.  
  905.  
  906. static void GLAPIENTRY
  907. _save_EvalCoord1f(GLfloat u)
  908. {
  909.    GET_CURRENT_CONTEXT(ctx);
  910.    dlist_fallback(ctx);
  911.    CALL_EvalCoord1f(ctx->Save, (u));
  912. }
  913.  
  914. static void GLAPIENTRY
  915. _save_EvalCoord1fv(const GLfloat * v)
  916. {
  917.    GET_CURRENT_CONTEXT(ctx);
  918.    dlist_fallback(ctx);
  919.    CALL_EvalCoord1fv(ctx->Save, (v));
  920. }
  921.  
  922. static void GLAPIENTRY
  923. _save_EvalCoord2f(GLfloat u, GLfloat v)
  924. {
  925.    GET_CURRENT_CONTEXT(ctx);
  926.    dlist_fallback(ctx);
  927.    CALL_EvalCoord2f(ctx->Save, (u, v));
  928. }
  929.  
  930. static void GLAPIENTRY
  931. _save_EvalCoord2fv(const GLfloat * v)
  932. {
  933.    GET_CURRENT_CONTEXT(ctx);
  934.    dlist_fallback(ctx);
  935.    CALL_EvalCoord2fv(ctx->Save, (v));
  936. }
  937.  
  938. static void GLAPIENTRY
  939. _save_EvalPoint1(GLint i)
  940. {
  941.    GET_CURRENT_CONTEXT(ctx);
  942.    dlist_fallback(ctx);
  943.    CALL_EvalPoint1(ctx->Save, (i));
  944. }
  945.  
  946. static void GLAPIENTRY
  947. _save_EvalPoint2(GLint i, GLint j)
  948. {
  949.    GET_CURRENT_CONTEXT(ctx);
  950.    dlist_fallback(ctx);
  951.    CALL_EvalPoint2(ctx->Save, (i, j));
  952. }
  953.  
  954. static void GLAPIENTRY
  955. _save_CallList(GLuint l)
  956. {
  957.    GET_CURRENT_CONTEXT(ctx);
  958.    dlist_fallback(ctx);
  959.    CALL_CallList(ctx->Save, (l));
  960. }
  961.  
  962. static void GLAPIENTRY
  963. _save_CallLists(GLsizei n, GLenum type, const GLvoid * v)
  964. {
  965.    GET_CURRENT_CONTEXT(ctx);
  966.    dlist_fallback(ctx);
  967.    CALL_CallLists(ctx->Save, (n, type, v));
  968. }
  969.  
  970.  
  971.  
  972. /**
  973.  * Called via ctx->Driver.NotifySaveBegin() when a glBegin is getting
  974.  * compiled into a display list.
  975.  * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
  976.  */
  977. GLboolean
  978. vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode)
  979. {
  980.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  981.    const GLuint i = save->prim_count++;
  982.  
  983.    assert(i < save->prim_max);
  984.    save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK;
  985.    save->prim[i].begin = 1;
  986.    save->prim[i].end = 0;
  987.    save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0;
  988.    save->prim[i].no_current_update =
  989.       (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0;
  990.    save->prim[i].pad = 0;
  991.    save->prim[i].start = save->vert_count;
  992.    save->prim[i].count = 0;
  993.    save->prim[i].num_instances = 1;
  994.    save->prim[i].base_instance = 0;
  995.    save->prim[i].is_indirect = 0;
  996.  
  997.    if (save->out_of_memory) {
  998.       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
  999.    }
  1000.    else {
  1001.       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt);
  1002.    }
  1003.  
  1004.    /* We need to call SaveFlushVertices() if there's state change */
  1005.    ctx->Driver.SaveNeedFlush = GL_TRUE;
  1006.  
  1007.    /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN
  1008.     * opcode into the display list.
  1009.     */
  1010.    return GL_TRUE;
  1011. }
  1012.  
  1013.  
  1014. static void GLAPIENTRY
  1015. _save_End(void)
  1016. {
  1017.    GET_CURRENT_CONTEXT(ctx);
  1018.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1019.    const GLint i = save->prim_count - 1;
  1020.  
  1021.    ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
  1022.    save->prim[i].end = 1;
  1023.    save->prim[i].count = (save->vert_count - save->prim[i].start);
  1024.  
  1025.    if (i == (GLint) save->prim_max - 1) {
  1026.       _save_compile_vertex_list(ctx);
  1027.       assert(save->copied.nr == 0);
  1028.    }
  1029.  
  1030.    /* Swap out this vertex format while outside begin/end.  Any color,
  1031.     * etc. received between here and the next begin will be compiled
  1032.     * as opcodes.
  1033.     */
  1034.    if (save->out_of_memory) {
  1035.       _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop);
  1036.    }
  1037.    else {
  1038.       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
  1039.    }
  1040. }
  1041.  
  1042.  
  1043. static void GLAPIENTRY
  1044. _save_Begin(GLenum mode)
  1045. {
  1046.    GET_CURRENT_CONTEXT(ctx);
  1047.    (void) mode;
  1048.    _mesa_compile_error(ctx, GL_INVALID_OPERATION, "Recursive glBegin");
  1049. }
  1050.  
  1051.  
  1052. static void GLAPIENTRY
  1053. _save_PrimitiveRestartNV(void)
  1054. {
  1055.    GLenum curPrim;
  1056.    GET_CURRENT_CONTEXT(ctx);
  1057.  
  1058.    curPrim = ctx->Driver.CurrentSavePrimitive;
  1059.  
  1060.    _save_End();
  1061.    _save_Begin(curPrim);
  1062. }
  1063.  
  1064.  
  1065. /* Unlike the functions above, these are to be hooked into the vtxfmt
  1066.  * maintained in ctx->ListState, active when the list is known or
  1067.  * suspected to be outside any begin/end primitive.
  1068.  * Note: OBE = Outside Begin/End
  1069.  */
  1070. static void GLAPIENTRY
  1071. _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
  1072. {
  1073.    GET_CURRENT_CONTEXT(ctx);
  1074.    vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK);
  1075.    CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
  1076.    CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
  1077.    CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
  1078.    CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
  1079.    CALL_End(GET_DISPATCH(), ());
  1080. }
  1081.  
  1082.  
  1083. static void GLAPIENTRY
  1084. _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
  1085. {
  1086.    GET_CURRENT_CONTEXT(ctx);
  1087.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1088.    GLint i;
  1089.  
  1090.    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
  1091.       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawArrays(mode)");
  1092.       return;
  1093.    }
  1094.    if (count < 0) {
  1095.       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawArrays(count<0)");
  1096.       return;
  1097.    }
  1098.  
  1099.    if (save->out_of_memory)
  1100.       return;
  1101.  
  1102.    _ae_map_vbos(ctx);
  1103.  
  1104.    vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK
  1105.                               | VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
  1106.  
  1107.    for (i = 0; i < count; i++)
  1108.       CALL_ArrayElement(GET_DISPATCH(), (start + i));
  1109.    CALL_End(GET_DISPATCH(), ());
  1110.  
  1111.    _ae_unmap_vbos(ctx);
  1112. }
  1113.  
  1114.  
  1115. /* Could do better by copying the arrays and element list intact and
  1116.  * then emitting an indexed prim at runtime.
  1117.  */
  1118. static void GLAPIENTRY
  1119. _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
  1120.                        const GLvoid * indices)
  1121. {
  1122.    GET_CURRENT_CONTEXT(ctx);
  1123.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1124.    struct gl_buffer_object *indexbuf = ctx->Array.VAO->IndexBufferObj;
  1125.    GLint i;
  1126.  
  1127.    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
  1128.       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawElements(mode)");
  1129.       return;
  1130.    }
  1131.    if (count < 0) {
  1132.       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
  1133.       return;
  1134.    }
  1135.    if (type != GL_UNSIGNED_BYTE &&
  1136.        type != GL_UNSIGNED_SHORT &&
  1137.        type != GL_UNSIGNED_INT) {
  1138.       _mesa_compile_error(ctx, GL_INVALID_VALUE, "glDrawElements(count<0)");
  1139.       return;
  1140.    }
  1141.  
  1142.    if (save->out_of_memory)
  1143.       return;
  1144.  
  1145.    _ae_map_vbos(ctx);
  1146.  
  1147.    if (_mesa_is_bufferobj(indexbuf))
  1148.       indices =
  1149.          ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices);
  1150.  
  1151.    vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK |
  1152.                               VBO_SAVE_PRIM_NO_CURRENT_UPDATE));
  1153.  
  1154.    switch (type) {
  1155.    case GL_UNSIGNED_BYTE:
  1156.       for (i = 0; i < count; i++)
  1157.          CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i]));
  1158.       break;
  1159.    case GL_UNSIGNED_SHORT:
  1160.       for (i = 0; i < count; i++)
  1161.          CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i]));
  1162.       break;
  1163.    case GL_UNSIGNED_INT:
  1164.       for (i = 0; i < count; i++)
  1165.          CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i]));
  1166.       break;
  1167.    default:
  1168.       _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)");
  1169.       break;
  1170.    }
  1171.  
  1172.    CALL_End(GET_DISPATCH(), ());
  1173.  
  1174.    _ae_unmap_vbos(ctx);
  1175. }
  1176.  
  1177.  
  1178. static void GLAPIENTRY
  1179. _save_OBE_DrawRangeElements(GLenum mode, GLuint start, GLuint end,
  1180.                             GLsizei count, GLenum type,
  1181.                             const GLvoid * indices)
  1182. {
  1183.    GET_CURRENT_CONTEXT(ctx);
  1184.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1185.  
  1186.    if (!_mesa_is_valid_prim_mode(ctx, mode)) {
  1187.       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(mode)");
  1188.       return;
  1189.    }
  1190.    if (count < 0) {
  1191.       _mesa_compile_error(ctx, GL_INVALID_VALUE,
  1192.                           "glDrawRangeElements(count<0)");
  1193.       return;
  1194.    }
  1195.    if (type != GL_UNSIGNED_BYTE &&
  1196.        type != GL_UNSIGNED_SHORT &&
  1197.        type != GL_UNSIGNED_INT) {
  1198.       _mesa_compile_error(ctx, GL_INVALID_ENUM, "glDrawRangeElements(type)");
  1199.       return;
  1200.    }
  1201.    if (end < start) {
  1202.       _mesa_compile_error(ctx, GL_INVALID_VALUE,
  1203.                           "glDrawRangeElements(end < start)");
  1204.       return;
  1205.    }
  1206.  
  1207.    if (save->out_of_memory)
  1208.       return;
  1209.  
  1210.    _save_OBE_DrawElements(mode, count, type, indices);
  1211. }
  1212.  
  1213.  
  1214. static void GLAPIENTRY
  1215. _save_OBE_MultiDrawElements(GLenum mode, const GLsizei *count, GLenum type,
  1216.                             const GLvoid * const *indices, GLsizei primcount)
  1217. {
  1218.    GLsizei i;
  1219.  
  1220.    for (i = 0; i < primcount; i++) {
  1221.       if (count[i] > 0) {
  1222.          CALL_DrawElements(GET_DISPATCH(), (mode, count[i], type, indices[i]));
  1223.       }
  1224.    }
  1225. }
  1226.  
  1227.  
  1228. static void GLAPIENTRY
  1229. _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count,
  1230.                                       GLenum type,
  1231.                                       const GLvoid * const *indices,
  1232.                                       GLsizei primcount,
  1233.                                       const GLint *basevertex)
  1234. {
  1235.    GLsizei i;
  1236.  
  1237.    for (i = 0; i < primcount; i++) {
  1238.       if (count[i] > 0) {
  1239.          CALL_DrawElementsBaseVertex(GET_DISPATCH(), (mode, count[i], type,
  1240.                                                       indices[i],
  1241.                                                       basevertex[i]));
  1242.       }
  1243.    }
  1244. }
  1245.  
  1246.  
  1247. static void
  1248. _save_vtxfmt_init(struct gl_context *ctx)
  1249. {
  1250.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1251.    GLvertexformat *vfmt = &save->vtxfmt;
  1252.  
  1253.    vfmt->ArrayElement = _ae_ArrayElement;
  1254.  
  1255.    vfmt->Color3f = _save_Color3f;
  1256.    vfmt->Color3fv = _save_Color3fv;
  1257.    vfmt->Color4f = _save_Color4f;
  1258.    vfmt->Color4fv = _save_Color4fv;
  1259.    vfmt->EdgeFlag = _save_EdgeFlag;
  1260.    vfmt->End = _save_End;
  1261.    vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV;
  1262.    vfmt->FogCoordfEXT = _save_FogCoordfEXT;
  1263.    vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
  1264.    vfmt->Indexf = _save_Indexf;
  1265.    vfmt->Indexfv = _save_Indexfv;
  1266.    vfmt->Materialfv = _save_Materialfv;
  1267.    vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
  1268.    vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
  1269.    vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
  1270.    vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
  1271.    vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
  1272.    vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
  1273.    vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
  1274.    vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
  1275.    vfmt->Normal3f = _save_Normal3f;
  1276.    vfmt->Normal3fv = _save_Normal3fv;
  1277.    vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
  1278.    vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
  1279.    vfmt->TexCoord1f = _save_TexCoord1f;
  1280.    vfmt->TexCoord1fv = _save_TexCoord1fv;
  1281.    vfmt->TexCoord2f = _save_TexCoord2f;
  1282.    vfmt->TexCoord2fv = _save_TexCoord2fv;
  1283.    vfmt->TexCoord3f = _save_TexCoord3f;
  1284.    vfmt->TexCoord3fv = _save_TexCoord3fv;
  1285.    vfmt->TexCoord4f = _save_TexCoord4f;
  1286.    vfmt->TexCoord4fv = _save_TexCoord4fv;
  1287.    vfmt->Vertex2f = _save_Vertex2f;
  1288.    vfmt->Vertex2fv = _save_Vertex2fv;
  1289.    vfmt->Vertex3f = _save_Vertex3f;
  1290.    vfmt->Vertex3fv = _save_Vertex3fv;
  1291.    vfmt->Vertex4f = _save_Vertex4f;
  1292.    vfmt->Vertex4fv = _save_Vertex4fv;
  1293.    vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
  1294.    vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
  1295.    vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
  1296.    vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
  1297.    vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
  1298.    vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
  1299.    vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
  1300.    vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
  1301.  
  1302.    vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
  1303.    vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
  1304.    vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
  1305.    vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
  1306.    vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
  1307.    vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
  1308.    vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
  1309.    vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
  1310.  
  1311.    /* integer-valued */
  1312.    vfmt->VertexAttribI1i = _save_VertexAttribI1i;
  1313.    vfmt->VertexAttribI2i = _save_VertexAttribI2i;
  1314.    vfmt->VertexAttribI3i = _save_VertexAttribI3i;
  1315.    vfmt->VertexAttribI4i = _save_VertexAttribI4i;
  1316.    vfmt->VertexAttribI2iv = _save_VertexAttribI2iv;
  1317.    vfmt->VertexAttribI3iv = _save_VertexAttribI3iv;
  1318.    vfmt->VertexAttribI4iv = _save_VertexAttribI4iv;
  1319.  
  1320.    /* unsigned integer-valued */
  1321.    vfmt->VertexAttribI1ui = _save_VertexAttribI1ui;
  1322.    vfmt->VertexAttribI2ui = _save_VertexAttribI2ui;
  1323.    vfmt->VertexAttribI3ui = _save_VertexAttribI3ui;
  1324.    vfmt->VertexAttribI4ui = _save_VertexAttribI4ui;
  1325.    vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv;
  1326.    vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv;
  1327.    vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv;
  1328.  
  1329.    vfmt->VertexP2ui = _save_VertexP2ui;
  1330.    vfmt->VertexP3ui = _save_VertexP3ui;
  1331.    vfmt->VertexP4ui = _save_VertexP4ui;
  1332.    vfmt->VertexP2uiv = _save_VertexP2uiv;
  1333.    vfmt->VertexP3uiv = _save_VertexP3uiv;
  1334.    vfmt->VertexP4uiv = _save_VertexP4uiv;
  1335.  
  1336.    vfmt->TexCoordP1ui = _save_TexCoordP1ui;
  1337.    vfmt->TexCoordP2ui = _save_TexCoordP2ui;
  1338.    vfmt->TexCoordP3ui = _save_TexCoordP3ui;
  1339.    vfmt->TexCoordP4ui = _save_TexCoordP4ui;
  1340.    vfmt->TexCoordP1uiv = _save_TexCoordP1uiv;
  1341.    vfmt->TexCoordP2uiv = _save_TexCoordP2uiv;
  1342.    vfmt->TexCoordP3uiv = _save_TexCoordP3uiv;
  1343.    vfmt->TexCoordP4uiv = _save_TexCoordP4uiv;
  1344.  
  1345.    vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui;
  1346.    vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui;
  1347.    vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui;
  1348.    vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui;
  1349.    vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv;
  1350.    vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv;
  1351.    vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv;
  1352.    vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv;
  1353.  
  1354.    vfmt->NormalP3ui = _save_NormalP3ui;
  1355.    vfmt->NormalP3uiv = _save_NormalP3uiv;
  1356.  
  1357.    vfmt->ColorP3ui = _save_ColorP3ui;
  1358.    vfmt->ColorP4ui = _save_ColorP4ui;
  1359.    vfmt->ColorP3uiv = _save_ColorP3uiv;
  1360.    vfmt->ColorP4uiv = _save_ColorP4uiv;
  1361.  
  1362.    vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui;
  1363.    vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv;
  1364.  
  1365.    vfmt->VertexAttribP1ui = _save_VertexAttribP1ui;
  1366.    vfmt->VertexAttribP2ui = _save_VertexAttribP2ui;
  1367.    vfmt->VertexAttribP3ui = _save_VertexAttribP3ui;
  1368.    vfmt->VertexAttribP4ui = _save_VertexAttribP4ui;
  1369.  
  1370.    vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv;
  1371.    vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv;
  1372.    vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv;
  1373.    vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv;
  1374.  
  1375.    vfmt->VertexAttribL1d = _save_VertexAttribL1d;
  1376.    vfmt->VertexAttribL2d = _save_VertexAttribL2d;
  1377.    vfmt->VertexAttribL3d = _save_VertexAttribL3d;
  1378.    vfmt->VertexAttribL4d = _save_VertexAttribL4d;
  1379.  
  1380.    vfmt->VertexAttribL1dv = _save_VertexAttribL1dv;
  1381.    vfmt->VertexAttribL2dv = _save_VertexAttribL2dv;
  1382.    vfmt->VertexAttribL3dv = _save_VertexAttribL3dv;
  1383.    vfmt->VertexAttribL4dv = _save_VertexAttribL4dv;
  1384.  
  1385.    /* This will all require us to fallback to saving the list as opcodes:
  1386.     */
  1387.    vfmt->CallList = _save_CallList;
  1388.    vfmt->CallLists = _save_CallLists;
  1389.  
  1390.    vfmt->EvalCoord1f = _save_EvalCoord1f;
  1391.    vfmt->EvalCoord1fv = _save_EvalCoord1fv;
  1392.    vfmt->EvalCoord2f = _save_EvalCoord2f;
  1393.    vfmt->EvalCoord2fv = _save_EvalCoord2fv;
  1394.    vfmt->EvalPoint1 = _save_EvalPoint1;
  1395.    vfmt->EvalPoint2 = _save_EvalPoint2;
  1396.  
  1397.    /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is
  1398.     * only used when we're inside a glBegin/End pair.
  1399.     */
  1400.    vfmt->Begin = _save_Begin;
  1401. }
  1402.  
  1403.  
  1404. /**
  1405.  * Initialize the dispatch table with the VBO functions for display
  1406.  * list compilation.
  1407.  */
  1408. void
  1409. vbo_initialize_save_dispatch(const struct gl_context *ctx,
  1410.                              struct _glapi_table *exec)
  1411. {
  1412.    SET_DrawArrays(exec, _save_OBE_DrawArrays);
  1413.    SET_DrawElements(exec, _save_OBE_DrawElements);
  1414.    SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements);
  1415.    SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements);
  1416.    SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex);
  1417.    SET_Rectf(exec, _save_OBE_Rectf);
  1418.    /* Note: other glDraw functins aren't compiled into display lists */
  1419. }
  1420.  
  1421.  
  1422.  
  1423. void
  1424. vbo_save_SaveFlushVertices(struct gl_context *ctx)
  1425. {
  1426.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1427.  
  1428.    /* Noop when we are actually active:
  1429.     */
  1430.    if (ctx->Driver.CurrentSavePrimitive <= PRIM_MAX)
  1431.       return;
  1432.  
  1433.    if (save->vert_count || save->prim_count)
  1434.       _save_compile_vertex_list(ctx);
  1435.  
  1436.    _save_copy_to_current(ctx);
  1437.    _save_reset_vertex(ctx);
  1438.    _save_reset_counters(ctx);
  1439.    ctx->Driver.SaveNeedFlush = GL_FALSE;
  1440. }
  1441.  
  1442.  
  1443. void
  1444. vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode)
  1445. {
  1446.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1447.  
  1448.    (void) list;
  1449.    (void) mode;
  1450.  
  1451.    if (!save->prim_store)
  1452.       save->prim_store = alloc_prim_store(ctx);
  1453.  
  1454.    if (!save->vertex_store)
  1455.       save->vertex_store = alloc_vertex_store(ctx);
  1456.  
  1457.    save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store);
  1458.  
  1459.    _save_reset_vertex(ctx);
  1460.    _save_reset_counters(ctx);
  1461.    ctx->Driver.SaveNeedFlush = GL_FALSE;
  1462. }
  1463.  
  1464.  
  1465. void
  1466. vbo_save_EndList(struct gl_context *ctx)
  1467. {
  1468.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1469.  
  1470.    /* EndList called inside a (saved) Begin/End pair?
  1471.     */
  1472.    if (_mesa_inside_dlist_begin_end(ctx)) {
  1473.       if (save->prim_count > 0) {
  1474.          GLint i = save->prim_count - 1;
  1475.          ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
  1476.          save->prim[i].end = 0;
  1477.          save->prim[i].count = save->vert_count - save->prim[i].start;
  1478.       }
  1479.  
  1480.       /* Make sure this vertex list gets replayed by the "loopback"
  1481.        * mechanism:
  1482.        */
  1483.       save->dangling_attr_ref = GL_TRUE;
  1484.       vbo_save_SaveFlushVertices(ctx);
  1485.  
  1486.       /* Swap out this vertex format while outside begin/end.  Any color,
  1487.        * etc. received between here and the next begin will be compiled
  1488.        * as opcodes.
  1489.        */
  1490.       _mesa_install_save_vtxfmt(ctx, &ctx->ListState.ListVtxfmt);
  1491.    }
  1492.  
  1493.    vbo_save_unmap_vertex_store(ctx, save->vertex_store);
  1494.  
  1495.    assert(save->vertex_size == 0);
  1496. }
  1497.  
  1498.  
  1499. void
  1500. vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist)
  1501. {
  1502.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1503.    save->replay_flags |= dlist->Flags;
  1504. }
  1505.  
  1506.  
  1507. void
  1508. vbo_save_EndCallList(struct gl_context *ctx)
  1509. {
  1510.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1511.  
  1512.    if (ctx->ListState.CallDepth == 1) {
  1513.       /* This is correct: want to keep only the VBO_SAVE_FALLBACK
  1514.        * flag, if it is set:
  1515.        */
  1516.       save->replay_flags &= VBO_SAVE_FALLBACK;
  1517.    }
  1518. }
  1519.  
  1520.  
  1521. static void
  1522. vbo_destroy_vertex_list(struct gl_context *ctx, void *data)
  1523. {
  1524.    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
  1525.    (void) ctx;
  1526.  
  1527.    if (--node->vertex_store->refcount == 0)
  1528.       free_vertex_store(ctx, node->vertex_store);
  1529.  
  1530.    if (--node->prim_store->refcount == 0)
  1531.       free(node->prim_store);
  1532.  
  1533.    free(node->current_data);
  1534.    node->current_data = NULL;
  1535. }
  1536.  
  1537.  
  1538. static void
  1539. vbo_print_vertex_list(struct gl_context *ctx, void *data, FILE *f)
  1540. {
  1541.    struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data;
  1542.    GLuint i;
  1543.    struct gl_buffer_object *buffer = node->vertex_store ?
  1544.       node->vertex_store->bufferobj : NULL;
  1545.    (void) ctx;
  1546.  
  1547.    fprintf(f, "VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize "
  1548.            "buffer %p\n",
  1549.            node->count, node->prim_count, node->vertex_size,
  1550.            buffer);
  1551.  
  1552.    for (i = 0; i < node->prim_count; i++) {
  1553.       struct _mesa_prim *prim = &node->prim[i];
  1554.       fprintf(f, "   prim %d: %s%s %d..%d %s %s\n",
  1555.              i,
  1556.              _mesa_lookup_prim_by_nr(prim->mode),
  1557.              prim->weak ? " (weak)" : "",
  1558.              prim->start,
  1559.              prim->start + prim->count,
  1560.              (prim->begin) ? "BEGIN" : "(wrap)",
  1561.              (prim->end) ? "END" : "(wrap)");
  1562.    }
  1563. }
  1564.  
  1565.  
  1566. /**
  1567.  * Called during context creation/init.
  1568.  */
  1569. static void
  1570. _save_current_init(struct gl_context *ctx)
  1571. {
  1572.    struct vbo_save_context *save = &vbo_context(ctx)->save;
  1573.    GLint i;
  1574.  
  1575.    for (i = VBO_ATTRIB_POS; i <= VBO_ATTRIB_GENERIC15; i++) {
  1576.       const GLuint j = i - VBO_ATTRIB_POS;
  1577.       assert(j < VERT_ATTRIB_MAX);
  1578.       save->currentsz[i] = &ctx->ListState.ActiveAttribSize[j];
  1579.       save->current[i] = (fi_type *) ctx->ListState.CurrentAttrib[j];
  1580.    }
  1581.  
  1582.    for (i = VBO_ATTRIB_FIRST_MATERIAL; i <= VBO_ATTRIB_LAST_MATERIAL; i++) {
  1583.       const GLuint j = i - VBO_ATTRIB_FIRST_MATERIAL;
  1584.       assert(j < MAT_ATTRIB_MAX);
  1585.       save->currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
  1586.       save->current[i] = (fi_type *) ctx->ListState.CurrentMaterial[j];
  1587.    }
  1588. }
  1589.  
  1590.  
  1591. /**
  1592.  * Initialize the display list compiler.  Called during context creation.
  1593.  */
  1594. void
  1595. vbo_save_api_init(struct vbo_save_context *save)
  1596. {
  1597.    struct gl_context *ctx = save->ctx;
  1598.    GLuint i;
  1599.  
  1600.    save->opcode_vertex_list =
  1601.       _mesa_dlist_alloc_opcode(ctx,
  1602.                                sizeof(struct vbo_save_vertex_list),
  1603.                                vbo_save_playback_vertex_list,
  1604.                                vbo_destroy_vertex_list,
  1605.                                vbo_print_vertex_list);
  1606.  
  1607.    ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin;
  1608.  
  1609.    _save_vtxfmt_init(ctx);
  1610.    _save_current_init(ctx);
  1611.    _mesa_noop_vtxfmt_init(&save->vtxfmt_noop);
  1612.  
  1613.    /* These will actually get set again when binding/drawing */
  1614.    for (i = 0; i < VBO_ATTRIB_MAX; i++)
  1615.       save->inputs[i] = &save->arrays[i];
  1616. }
  1617.