X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fvbo%2Fvbo_save_api.c;h=4e138f25c5b2d32a40124f3b165779db973c86f1;hb=d88447d5ce47cfb2306a3ff58caa2e2610c653dc;hp=5927beeb33de1894ed2198d56cb438c93e1db707;hpb=e1231159bcd0b0fc9aaebeda0745ee38d13a7282;p=mesa.git diff --git a/src/mesa/vbo/vbo_save_api.c b/src/mesa/vbo/vbo_save_api.c index 5927beeb33d..4e138f25c5b 100644 --- a/src/mesa/vbo/vbo_save_api.c +++ b/src/mesa/vbo/vbo_save_api.c @@ -68,25 +68,35 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "main/glheader.h" +#include "main/arrayobj.h" #include "main/bufferobj.h" #include "main/context.h" #include "main/dlist.h" #include "main/enums.h" #include "main/eval.h" #include "main/macros.h" -#include "main/api_validate.h" +#include "main/draw_validate.h" #include "main/api_arrayelt.h" #include "main/vtxfmt.h" #include "main/dispatch.h" +#include "main/state.h" +#include "main/varray.h" +#include "util/bitscan.h" +#include "util/u_memory.h" -#include "vbo_context.h" #include "vbo_noop.h" +#include "vbo_private.h" #ifdef ERROR #undef ERROR #endif +/** + * Display list flag only used by this VBO code. + */ +#define DLIST_DANGLING_REFS 0x1 + /* An interesting VBO number/name to help with debugging */ #define VBO_BUF_ID 12345 @@ -97,84 +107,20 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. * wrong-footed on replay. */ static GLuint -_save_copy_vertices(struct gl_context *ctx, - const struct vbo_save_vertex_list *node, - const fi_type * src_buffer) +copy_vertices(struct gl_context *ctx, + const struct vbo_save_vertex_list *node, + const fi_type * src_buffer) { struct vbo_save_context *save = &vbo_context(ctx)->save; - const struct _mesa_prim *prim = &node->prim[node->prim_count - 1]; - GLuint nr = prim->count; + struct _mesa_prim *prim = &node->prims[node->prim_count - 1]; GLuint sz = save->vertex_size; const fi_type *src = src_buffer + prim->start * sz; fi_type *dst = save->copied.buffer; - GLuint ovf, i; if (prim->end) return 0; - switch (prim->mode) { - case GL_POINTS: - return 0; - case GL_LINES: - ovf = nr & 1; - for (i = 0; i < ovf; i++) - memcpy(dst + i * sz, src + (nr - ovf + i) * sz, - sz * sizeof(GLfloat)); - return i; - case GL_TRIANGLES: - ovf = nr % 3; - for (i = 0; i < ovf; i++) - memcpy(dst + i * sz, src + (nr - ovf + i) * sz, - sz * sizeof(GLfloat)); - return i; - case GL_QUADS: - ovf = nr & 3; - for (i = 0; i < ovf; i++) - memcpy(dst + i * sz, src + (nr - ovf + i) * sz, - sz * sizeof(GLfloat)); - return i; - case GL_LINE_STRIP: - if (nr == 0) - return 0; - else { - memcpy(dst, src + (nr - 1) * sz, sz * sizeof(GLfloat)); - return 1; - } - case GL_LINE_LOOP: - case GL_TRIANGLE_FAN: - case GL_POLYGON: - if (nr == 0) - return 0; - else if (nr == 1) { - memcpy(dst, src + 0, sz * sizeof(GLfloat)); - return 1; - } - else { - memcpy(dst, src + 0, sz * sizeof(GLfloat)); - memcpy(dst + sz, src + (nr - 1) * sz, sz * sizeof(GLfloat)); - return 2; - } - case GL_TRIANGLE_STRIP: - case GL_QUAD_STRIP: - switch (nr) { - case 0: - ovf = 0; - break; - case 1: - ovf = 1; - break; - default: - ovf = 2 + (nr & 1); - break; - } - for (i = 0; i < ovf; i++) - memcpy(dst + i * sz, src + (nr - ovf + i) * sz, - sz * sizeof(GLfloat)); - return i; - default: - assert(0); - return 0; - } + return vbo_copy_vertices(ctx, prim->mode, prim, sz, true, dst, src); } @@ -211,9 +157,8 @@ alloc_vertex_store(struct gl_context *ctx) _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); } - vertex_store->buffer = NULL; + vertex_store->buffer_map = NULL; vertex_store->used = 0; - vertex_store->refcount = 1; return vertex_store; } @@ -223,7 +168,7 @@ static void free_vertex_store(struct gl_context *ctx, struct vbo_save_vertex_store *vertex_store) { - assert(!vertex_store->buffer); + assert(!vertex_store->buffer_map); if (vertex_store->bufferobj) { _mesa_reference_buffer_object(ctx, &vertex_store->bufferobj, NULL); @@ -243,7 +188,7 @@ vbo_save_map_vertex_store(struct gl_context *ctx, GL_MAP_FLUSH_EXPLICIT_BIT); assert(vertex_store->bufferobj); - assert(!vertex_store->buffer); /* the buffer should not be mapped */ + assert(!vertex_store->buffer_map); /* the buffer should not be mapped */ if (vertex_store->bufferobj->Size > 0) { /* Map the remaining free space in the VBO */ @@ -255,12 +200,12 @@ vbo_save_map_vertex_store(struct gl_context *ctx, MAP_INTERNAL); if (range) { /* compute address of start of whole buffer (needed elsewhere) */ - vertex_store->buffer = range - vertex_store->used; - assert(vertex_store->buffer); + vertex_store->buffer_map = range - vertex_store->used; + assert(vertex_store->buffer_map); return range; } else { - vertex_store->buffer = NULL; + vertex_store->buffer_map = NULL; return NULL; } } @@ -287,16 +232,15 @@ vbo_save_unmap_vertex_store(struct gl_context *ctx, ctx->Driver.UnmapBuffer(ctx, vertex_store->bufferobj, MAP_INTERNAL); } - vertex_store->buffer = NULL; + vertex_store->buffer_map = NULL; } static struct vbo_save_primitive_store * -alloc_prim_store(struct gl_context *ctx) +alloc_prim_store(void) { struct vbo_save_primitive_store *store = CALLOC_STRUCT(vbo_save_primitive_store); - (void) ctx; store->used = 0; store->refcount = 1; return store; @@ -304,14 +248,14 @@ alloc_prim_store(struct gl_context *ctx) static void -_save_reset_counters(struct gl_context *ctx) +reset_counters(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; - save->prim = save->prim_store->buffer + save->prim_store->used; - save->buffer = save->vertex_store->buffer + save->vertex_store->used; + save->prims = save->prim_store->prims + save->prim_store->used; + save->buffer_map = save->vertex_store->buffer_map + save->vertex_store->used; - assert(save->buffer == save->buffer_ptr); + assert(save->buffer_map == save->buffer_ptr); if (save->vertex_size) save->max_vert = (VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / @@ -330,8 +274,7 @@ _save_reset_counters(struct gl_context *ctx) * previous prim. */ static void -merge_prims(struct gl_context *ctx, - struct _mesa_prim *prim_list, +merge_prims(struct gl_context *ctx, struct _mesa_prim *prim_list, GLuint *prim_count) { GLuint i; @@ -342,11 +285,10 @@ merge_prims(struct gl_context *ctx, vbo_try_prim_conversion(this_prim); - if (vbo_can_merge_prims(prev_prim, this_prim)) { + if (vbo_merge_draws(ctx, true, prev_prim, this_prim)) { /* We've found a prim that just extend the previous one. Tack it * onto the previous one, and let this primitive struct get dropped. */ - vbo_merge_prims(prev_prim, this_prim); continue; } @@ -361,12 +303,170 @@ merge_prims(struct gl_context *ctx, *prim_count = prev_prim - prim_list + 1; } + +/** + * Convert GL_LINE_LOOP primitive into GL_LINE_STRIP so that drivers + * don't have to worry about handling the _mesa_prim::begin/end flags. + * See https://bugs.freedesktop.org/show_bug.cgi?id=81174 + */ +static void +convert_line_loop_to_strip(struct vbo_save_context *save, + struct vbo_save_vertex_list *node) +{ + struct _mesa_prim *prim = &node->prims[node->prim_count - 1]; + + assert(prim->mode == GL_LINE_LOOP); + + if (prim->end) { + /* Copy the 0th vertex to end of the buffer and extend the + * vertex count by one to finish the line loop. + */ + const GLuint sz = save->vertex_size; + /* 0th vertex: */ + const fi_type *src = save->buffer_map + prim->start * sz; + /* end of buffer: */ + fi_type *dst = save->buffer_map + (prim->start + prim->count) * sz; + + memcpy(dst, src, sz * sizeof(float)); + + prim->count++; + node->vertex_count++; + save->vert_count++; + save->buffer_ptr += sz; + save->vertex_store->used += sz; + } + + if (!prim->begin) { + /* Drawing the second or later section of a long line loop. + * Skip the 0th vertex. + */ + prim->start++; + prim->count--; + } + + prim->mode = GL_LINE_STRIP; +} + + +/* Compare the present vao if it has the same setup. */ +static bool +compare_vao(gl_vertex_processing_mode mode, + const struct gl_vertex_array_object *vao, + const struct gl_buffer_object *bo, GLintptr buffer_offset, + GLuint stride, GLbitfield64 vao_enabled, + const GLubyte size[VBO_ATTRIB_MAX], + const GLenum16 type[VBO_ATTRIB_MAX], + const GLuint offset[VBO_ATTRIB_MAX]) +{ + if (!vao) + return false; + + /* If the enabled arrays are not the same we are not equal. */ + if (vao_enabled != vao->Enabled) + return false; + + /* Check the buffer binding at 0 */ + if (vao->BufferBinding[0].BufferObj != bo) + return false; + /* BufferBinding[0].Offset != buffer_offset is checked per attribute */ + if (vao->BufferBinding[0].Stride != stride) + return false; + assert(vao->BufferBinding[0].InstanceDivisor == 0); + + /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space */ + const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode]; + + /* Now check the enabled arrays */ + GLbitfield mask = vao_enabled; + while (mask) { + const int attr = u_bit_scan(&mask); + const unsigned char vbo_attr = vao_to_vbo_map[attr]; + const GLenum16 tp = type[vbo_attr]; + const GLintptr off = offset[vbo_attr] + buffer_offset; + const struct gl_array_attributes *attrib = &vao->VertexAttrib[attr]; + if (attrib->RelativeOffset + vao->BufferBinding[0].Offset != off) + return false; + if (attrib->Format.Type != tp) + return false; + if (attrib->Format.Size != size[vbo_attr]) + return false; + assert(attrib->Format.Format == GL_RGBA); + assert(attrib->Format.Normalized == GL_FALSE); + assert(attrib->Format.Integer == vbo_attrtype_to_integer_flag(tp)); + assert(attrib->Format.Doubles == vbo_attrtype_to_double_flag(tp)); + assert(attrib->BufferBindingIndex == 0); + } + + return true; +} + + +/* Create or reuse the vao for the vertex processing mode. */ +static void +update_vao(struct gl_context *ctx, + gl_vertex_processing_mode mode, + struct gl_vertex_array_object **vao, + struct gl_buffer_object *bo, GLintptr buffer_offset, + GLuint stride, GLbitfield64 vbo_enabled, + const GLubyte size[VBO_ATTRIB_MAX], + const GLenum16 type[VBO_ATTRIB_MAX], + const GLuint offset[VBO_ATTRIB_MAX]) +{ + /* Compute the bitmasks of vao_enabled arrays */ + GLbitfield vao_enabled = _vbo_get_vao_enabled_from_vbo(mode, vbo_enabled); + + /* + * Check if we can possibly reuse the exisiting one. + * In the long term we should reset them when something changes. + */ + if (compare_vao(mode, *vao, bo, buffer_offset, stride, + vao_enabled, size, type, offset)) + return; + + /* The initial refcount is 1 */ + _mesa_reference_vao(ctx, vao, NULL); + *vao = _mesa_new_vao(ctx, ~((GLuint)0)); + + /* + * assert(stride <= ctx->Const.MaxVertexAttribStride); + * MaxVertexAttribStride is not set for drivers that does not + * expose GL 44 or GLES 31. + */ + + /* Bind the buffer object at binding point 0 */ + _mesa_bind_vertex_buffer(ctx, *vao, 0, bo, buffer_offset, stride, false, + false); + + /* Retrieve the mapping from VBO_ATTRIB to VERT_ATTRIB space + * Note that the position/generic0 aliasing is done in the VAO. + */ + const GLubyte *const vao_to_vbo_map = _vbo_attribute_alias_map[mode]; + /* Now set the enable arrays */ + GLbitfield mask = vao_enabled; + while (mask) { + const int vao_attr = u_bit_scan(&mask); + const GLubyte vbo_attr = vao_to_vbo_map[vao_attr]; + assert(offset[vbo_attr] <= ctx->Const.MaxVertexAttribRelativeOffset); + + _vbo_set_attrib_format(ctx, *vao, vao_attr, buffer_offset, + size[vbo_attr], type[vbo_attr], offset[vbo_attr]); + _mesa_vertex_attrib_binding(ctx, *vao, vao_attr, 0); + } + _mesa_enable_vertex_array_attribs(ctx, *vao, vao_enabled); + assert(vao_enabled == (*vao)->Enabled); + assert((vao_enabled & ~(*vao)->VertexAttribBufferMask) == 0); + + /* Finalize and freeze the VAO */ + _mesa_set_vao_immutable(ctx, *vao); +} + + /** * Insert the active immediate struct onto the display list currently * being built. */ static void -_save_compile_vertex_list(struct gl_context *ctx) +compile_vertex_list(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; struct vbo_save_vertex_list *node; @@ -385,64 +485,110 @@ _save_compile_vertex_list(struct gl_context *ctx) /* Duplicate our template, increment refcounts to the storage structs: */ - memcpy(node->attrsz, save->attrsz, sizeof(node->attrsz)); - memcpy(node->attrtype, save->attrtype, sizeof(node->attrtype)); - node->vertex_size = save->vertex_size; - node->buffer_offset = - (save->buffer - save->vertex_store->buffer) * sizeof(GLfloat); - node->count = save->vert_count; + GLintptr old_offset = 0; + if (save->VAO[0]) { + old_offset = save->VAO[0]->BufferBinding[0].Offset + + save->VAO[0]->VertexAttrib[VERT_ATTRIB_POS].RelativeOffset; + } + const GLsizei stride = save->vertex_size*sizeof(GLfloat); + GLintptr buffer_offset = + (save->buffer_map - save->vertex_store->buffer_map) * sizeof(GLfloat); + assert(old_offset <= buffer_offset); + const GLintptr offset_diff = buffer_offset - old_offset; + GLuint start_offset = 0; + if (offset_diff > 0 && stride > 0 && offset_diff % stride == 0) { + /* The vertex size is an exact multiple of the buffer offset. + * This means that we can use zero-based vertex attribute pointers + * and specify the start of the primitive with the _mesa_prim::start + * field. This results in issuing several draw calls with identical + * vertex attribute information. This can result in fewer state + * changes in drivers. In particular, the Gallium CSO module will + * filter out redundant vertex buffer changes. + */ + /* We cannot immediately update the primitives as some methods below + * still need the uncorrected start vertices + */ + start_offset = offset_diff/stride; + assert(old_offset == buffer_offset - offset_diff); + buffer_offset = old_offset; + } + GLuint offsets[VBO_ATTRIB_MAX]; + for (unsigned i = 0, offset = 0; i < VBO_ATTRIB_MAX; ++i) { + offsets[i] = offset; + offset += save->attrsz[i] * sizeof(GLfloat); + } + node->vertex_count = save->vert_count; node->wrap_count = save->copied.nr; - node->dangling_attr_ref = save->dangling_attr_ref; - node->prim = save->prim; + node->prims = save->prims; node->prim_count = save->prim_count; - node->vertex_store = save->vertex_store; node->prim_store = save->prim_store; - node->vertex_store->refcount++; + /* Create a pair of VAOs for the possible VERTEX_PROCESSING_MODEs + * Note that this may reuse the previous one of possible. + */ + for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) { + /* create or reuse the vao */ + update_vao(ctx, vpm, &save->VAO[vpm], + save->vertex_store->bufferobj, buffer_offset, stride, + save->enabled, save->attrsz, save->attrtype, offsets); + /* Reference the vao in the dlist */ + node->VAO[vpm] = NULL; + _mesa_reference_vao(ctx, &node->VAO[vpm], save->VAO[vpm]); + } + node->prim_store->refcount++; - if (node->prim[0].no_current_update) { - node->current_size = 0; + if (save->no_current_update) { node->current_data = NULL; } else { - node->current_size = node->vertex_size - node->attrsz[0]; + GLuint current_size = save->vertex_size - save->attrsz[0]; node->current_data = NULL; - if (node->current_size) { - /* If the malloc fails, we just pull the data out of the VBO - * later instead. - */ - node->current_data = malloc(node->current_size * sizeof(GLfloat)); + if (current_size) { + node->current_data = malloc(current_size * sizeof(GLfloat)); if (node->current_data) { - const char *buffer = (const char *) save->vertex_store->buffer; - unsigned attr_offset = node->attrsz[0] * sizeof(GLfloat); + const char *buffer = (const char *)save->buffer_map; + unsigned attr_offset = save->attrsz[0] * sizeof(GLfloat); unsigned vertex_offset = 0; - if (node->count) - vertex_offset = - (node->count - 1) * node->vertex_size * sizeof(GLfloat); + if (node->vertex_count) + vertex_offset = (node->vertex_count - 1) * stride; - memcpy(node->current_data, - buffer + node->buffer_offset + vertex_offset + attr_offset, - node->current_size * sizeof(GLfloat)); + memcpy(node->current_data, buffer + vertex_offset + attr_offset, + current_size * sizeof(GLfloat)); + } else { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "Current value allocation"); } } } - assert(node->attrsz[VBO_ATTRIB_POS] != 0 || node->count == 0); + assert(save->attrsz[VBO_ATTRIB_POS] != 0 || node->vertex_count == 0); if (save->dangling_attr_ref) ctx->ListState.CurrentList->Flags |= DLIST_DANGLING_REFS; - save->vertex_store->used += save->vertex_size * node->count; + save->vertex_store->used += save->vertex_size * node->vertex_count; save->prim_store->used += node->prim_count; /* Copy duplicated vertices */ - save->copied.nr = _save_copy_vertices(ctx, node, save->buffer); + save->copied.nr = copy_vertices(ctx, node, save->buffer_map); - merge_prims(ctx, node->prim, &node->prim_count); + if (node->prims[node->prim_count - 1].mode == GL_LINE_LOOP) { + convert_line_loop_to_strip(save, node); + } + + merge_prims(ctx, node->prims, &node->prim_count); + + /* Correct the primitive starts, we can only do this here as copy_vertices + * and convert_line_loop_to_strip above consume the uncorrected starts. + * On the other hand the _vbo_loopback_vertex_list call below needs the + * primitves to be corrected already. + */ + for (unsigned i = 0; i < node->prim_count; i++) { + node->prims[i].start += start_offset; + } /* Deal with GL_COMPILE_AND_EXECUTE: */ @@ -451,12 +597,8 @@ _save_compile_vertex_list(struct gl_context *ctx) _glapi_set_dispatch(ctx->Exec); - vbo_loopback_vertex_list(ctx, - (const GLfloat *) ((const char *) save-> - vertex_store->buffer + - node->buffer_offset), - node->attrsz, node->prim, node->prim_count, - node->wrap_count, node->vertex_size); + /* Note that the range of referenced vertices must be mapped already */ + _vbo_loopback_vertex_list(ctx, node); _glapi_set_dispatch(dispatch); } @@ -473,9 +615,11 @@ _save_compile_vertex_list(struct gl_context *ctx) /* Release old reference: */ - save->vertex_store->refcount--; - assert(save->vertex_store->refcount != 0); + free_vertex_store(ctx, save->vertex_store); save->vertex_store = NULL; + /* When we have a new vbo, we will for sure need a new vao */ + for (gl_vertex_processing_mode vpm = 0; vpm < VP_MODE_MAX; ++vpm) + _mesa_reference_vao(ctx, &save->VAO[vpm], NULL); /* Allocate and map new store: */ @@ -483,16 +627,21 @@ _save_compile_vertex_list(struct gl_context *ctx) save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); save->out_of_memory = save->buffer_ptr == NULL; } + else { + /* update buffer_ptr for next vertex */ + save->buffer_ptr = save->vertex_store->buffer_map + + save->vertex_store->used; + } if (save->prim_store->used > VBO_SAVE_PRIM_SIZE - 6) { save->prim_store->refcount--; assert(save->prim_store->refcount != 0); - save->prim_store = alloc_prim_store(ctx); + save->prim_store = alloc_prim_store(); } /* Reset our structures for the next run of vertices: */ - _save_reset_counters(ctx); + reset_counters(ctx); } @@ -502,41 +651,31 @@ _save_compile_vertex_list(struct gl_context *ctx) * TODO -- If no new vertices have been stored, don't bother saving it. */ static void -_save_wrap_buffers(struct gl_context *ctx) +wrap_buffers(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; GLint i = save->prim_count - 1; GLenum mode; - GLboolean weak; - GLboolean no_current_update; assert(i < (GLint) save->prim_max); assert(i >= 0); /* Close off in-progress primitive. */ - save->prim[i].count = (save->vert_count - save->prim[i].start); - mode = save->prim[i].mode; - weak = save->prim[i].weak; - no_current_update = save->prim[i].no_current_update; + save->prims[i].count = (save->vert_count - save->prims[i].start); + mode = save->prims[i].mode; /* store the copied vertices, and allocate a new list. */ - _save_compile_vertex_list(ctx); + compile_vertex_list(ctx); /* Restart interrupted primitive */ - save->prim[0].mode = mode; - save->prim[0].weak = weak; - save->prim[0].no_current_update = no_current_update; - save->prim[0].begin = 0; - save->prim[0].end = 0; - save->prim[0].pad = 0; - save->prim[0].start = 0; - save->prim[0].count = 0; - save->prim[0].num_instances = 1; - save->prim[0].base_instance = 0; - save->prim[0].is_indirect = 0; + save->prims[0].mode = mode; + save->prims[0].begin = 0; + save->prims[0].end = 0; + save->prims[0].start = 0; + save->prims[0].count = 0; save->prim_count = 1; } @@ -546,63 +685,72 @@ _save_wrap_buffers(struct gl_context *ctx) * vertex_store struct. */ static void -_save_wrap_filled_vertex(struct gl_context *ctx) +wrap_filled_vertex(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; - fi_type *data = save->copied.buffer; - GLuint i; + unsigned numComponents; /* Emit a glEnd to close off the last vertex list. */ - _save_wrap_buffers(ctx); + wrap_buffers(ctx); /* Copy stored stored vertices to start of new list. */ assert(save->max_vert - save->vert_count > save->copied.nr); - for (i = 0; i < save->copied.nr; i++) { - memcpy(save->buffer_ptr, data, save->vertex_size * sizeof(GLfloat)); - data += save->vertex_size; - save->buffer_ptr += save->vertex_size; - save->vert_count++; - } + numComponents = save->copied.nr * save->vertex_size; + memcpy(save->buffer_ptr, + save->copied.buffer, + numComponents * sizeof(fi_type)); + save->buffer_ptr += numComponents; + save->vert_count += save->copied.nr; } static void -_save_copy_to_current(struct gl_context *ctx) +copy_to_current(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; - GLuint i; + GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); - for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { - if (save->attrsz[i]) { - save->currentsz[i][0] = save->attrsz[i]; + while (enabled) { + const int i = u_bit_scan64(&enabled); + assert(save->attrsz[i]); + + if (save->attrtype[i] == GL_DOUBLE || + save->attrtype[i] == GL_UNSIGNED_INT64_ARB) + memcpy(save->current[i], save->attrptr[i], save->attrsz[i] * sizeof(GLfloat)); + else COPY_CLEAN_4V_TYPE_AS_UNION(save->current[i], save->attrsz[i], save->attrptr[i], save->attrtype[i]); - } } } static void -_save_copy_from_current(struct gl_context *ctx) +copy_from_current(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; - GLint i; + GLbitfield64 enabled = save->enabled & (~BITFIELD64_BIT(VBO_ATTRIB_POS)); + + while (enabled) { + const int i = u_bit_scan64(&enabled); - for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { switch (save->attrsz[i]) { case 4: save->attrptr[i][3] = save->current[i][3]; + /* fallthrough */ case 3: save->attrptr[i][2] = save->current[i][2]; + /* fallthrough */ case 2: save->attrptr[i][1] = save->current[i][1]; + /* fallthrough */ case 1: save->attrptr[i][0] = save->current[i][0]; - case 0: break; + case 0: + unreachable("Unexpected vertex attribute size"); } } } @@ -615,7 +763,7 @@ _save_copy_from_current(struct gl_context *ctx) * Flush existing data, set new attrib size, replay copied vertices. */ static void -_save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) +upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) { struct vbo_save_context *save = &vbo_context(ctx)->save; GLuint oldsz; @@ -626,7 +774,7 @@ _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) * BEGIN in the new buffer. */ if (save->vert_count) - _save_wrap_buffers(ctx); + wrap_buffers(ctx); else assert(save->copied.nr == 0); @@ -634,12 +782,13 @@ _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) * when the attribute already exists in the vertex and is having * its size increased. */ - _save_copy_to_current(ctx); + copy_to_current(ctx); /* Fix up sizes: */ oldsz = save->attrsz[attr]; save->attrsz[attr] = newsz; + save->enabled |= BITFIELD64_BIT(attr); save->vertex_size += newsz - oldsz; save->max_vert = ((VBO_SAVE_BUFFER_SIZE - save->vertex_store->used) / @@ -648,7 +797,8 @@ _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) /* Recalculate all the attrptr[] values: */ - for (i = 0, tmp = save->vertex; i < VBO_ATTRIB_MAX; i++) { + tmp = save->vertex; + for (i = 0; i < VBO_ATTRIB_MAX; i++) { if (save->attrsz[i]) { save->attrptr[i] = tmp; tmp += save->attrsz[i]; @@ -660,7 +810,7 @@ _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) /* Copy from current to repopulate the vertex with correct values. */ - _save_copy_from_current(ctx); + copy_from_current(ctx); /* Replay stored vertices to translate them to new format here. * @@ -670,8 +820,7 @@ _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) */ if (save->copied.nr) { const fi_type *data = save->copied.buffer; - fi_type *dest = save->buffer; - GLuint j; + fi_type *dest = save->buffer_map; /* Need to note this and fix up at runtime (or loopback): */ @@ -681,27 +830,28 @@ _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) } for (i = 0; i < save->copied.nr; i++) { - for (j = 0; j < VBO_ATTRIB_MAX; j++) { - if (save->attrsz[j]) { - if (j == attr) { - if (oldsz) { - COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data, - save->attrtype[j]); - data += oldsz; - dest += newsz; - } - else { - COPY_SZ_4V(dest, newsz, save->current[attr]); - dest += newsz; - } + GLbitfield64 enabled = save->enabled; + while (enabled) { + const int j = u_bit_scan64(&enabled); + assert(save->attrsz[j]); + if (j == attr) { + if (oldsz) { + COPY_CLEAN_4V_TYPE_AS_UNION(dest, oldsz, data, + save->attrtype[j]); + data += oldsz; + dest += newsz; } else { - GLint sz = save->attrsz[j]; - COPY_SZ_4V(dest, sz, data); - data += sz; - dest += sz; + COPY_SZ_4V(dest, newsz, save->current[attr]); + dest += newsz; } } + else { + GLint sz = save->attrsz[j]; + COPY_SZ_4V(dest, sz, data); + data += sz; + dest += sz; + } } } @@ -717,15 +867,17 @@ _save_upgrade_vertex(struct gl_context *ctx, GLuint attr, GLuint newsz) * get a glTexCoord4f() or glTexCoord1f() call. */ static void -save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz) +fixup_vertex(struct gl_context *ctx, GLuint attr, + GLuint sz, GLenum newType) { struct vbo_save_context *save = &vbo_context(ctx)->save; - if (sz > save->attrsz[attr]) { + if (sz > save->attrsz[attr] || + newType != save->attrtype[attr]) { /* New size is larger. Need to flush existing vertices and get * an enlarged vertex format. */ - _save_upgrade_vertex(ctx, attr, sz); + upgrade_vertex(ctx, attr, sz); } else if (sz < save->active_sz[attr]) { GLuint i; @@ -748,12 +900,13 @@ save_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint sz) * commands such as glNormal3f() or glTexCoord2f(). */ static void -_save_reset_vertex(struct gl_context *ctx) +reset_vertex(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; - GLuint i; - for (i = 0; i < VBO_ATTRIB_MAX; i++) { + while (save->enabled) { + const int i = u_bit_scan64(&save->enabled); + assert(save->attrsz[i]); save->attrsz[i] = 0; save->active_sz[i] = 0; } @@ -762,6 +915,20 @@ _save_reset_vertex(struct gl_context *ctx) } +/** + * If index=0, does glVertexAttrib*() alias glVertex() to emit a vertex? + * It depends on a few things, including whether we're inside or outside + * of glBegin/glEnd. + */ +static inline bool +is_vertex_position(const struct gl_context *ctx, GLuint index) +{ + return (index == 0 && + _mesa_attr_zero_aliases_vertex(ctx) && + _mesa_inside_dlist_begin_end(ctx)); +} + + #define ERROR(err) _mesa_compile_error(ctx, err, __func__); @@ -772,15 +939,16 @@ _save_reset_vertex(struct gl_context *ctx) * 3f version won't otherwise set color[3] to 1.0 -- this is the job * of the chooser function when switching between Color4f and Color3f. */ -#define ATTR_UNION(A, N, T, V0, V1, V2, V3) \ +#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \ do { \ struct vbo_save_context *save = &vbo_context(ctx)->save; \ + int sz = (sizeof(C) / sizeof(GLfloat)); \ \ if (save->active_sz[A] != N) \ - save_fixup_vertex(ctx, A, N); \ + fixup_vertex(ctx, A, N * sz, T); \ \ { \ - fi_type *dest = save->attrptr[A]; \ + C *dest = (C *)save->attrptr[A]; \ if (N>0) dest[0] = V0; \ if (N>1) dest[1] = V1; \ if (N>2) dest[2] = V2; \ @@ -797,7 +965,7 @@ do { \ save->buffer_ptr += save->vertex_size; \ \ if (++save->vert_count >= save->max_vert) \ - _save_wrap_filled_vertex(ctx); \ + wrap_filled_vertex(ctx); \ } \ } while (0) @@ -878,7 +1046,7 @@ dlist_fallback(struct gl_context *ctx) if (save->prim_count > 0) { /* Close off in-progress primitive. */ GLint i = save->prim_count - 1; - save->prim[i].count = save->vert_count - save->prim[i].start; + save->prims[i].count = save->vert_count - save->prims[i].start; } /* Need to replay this display list with loopback, @@ -887,12 +1055,12 @@ dlist_fallback(struct gl_context *ctx) */ save->dangling_attr_ref = GL_TRUE; - _save_compile_vertex_list(ctx); + compile_vertex_list(ctx); } - _save_copy_to_current(ctx); - _save_reset_vertex(ctx); - _save_reset_counters(ctx); + copy_to_current(ctx); + reset_vertex(ctx); + reset_counters(ctx); if (save->out_of_memory) { _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); } @@ -970,29 +1138,26 @@ _save_CallLists(GLsizei n, GLenum type, const GLvoid * v) /** - * Called via ctx->Driver.NotifySaveBegin() when a glBegin is getting - * compiled into a display list. + * Called when a glBegin is getting compiled into a display list. * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of. */ -GLboolean -vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode) +void +vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode, + bool no_current_update) { struct vbo_save_context *save = &vbo_context(ctx)->save; const GLuint i = save->prim_count++; + ctx->Driver.CurrentSavePrimitive = mode; + assert(i < save->prim_max); - save->prim[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK; - save->prim[i].begin = 1; - save->prim[i].end = 0; - save->prim[i].weak = (mode & VBO_SAVE_PRIM_WEAK) ? 1 : 0; - save->prim[i].no_current_update = - (mode & VBO_SAVE_PRIM_NO_CURRENT_UPDATE) ? 1 : 0; - save->prim[i].pad = 0; - save->prim[i].start = save->vert_count; - save->prim[i].count = 0; - save->prim[i].num_instances = 1; - save->prim[i].base_instance = 0; - save->prim[i].is_indirect = 0; + save->prims[i].mode = mode & VBO_SAVE_PRIM_MODE_MASK; + save->prims[i].begin = 1; + save->prims[i].end = 0; + save->prims[i].start = save->vert_count; + save->prims[i].count = 0; + + save->no_current_update = no_current_update; if (save->out_of_memory) { _mesa_install_save_vtxfmt(ctx, &save->vtxfmt_noop); @@ -1001,13 +1166,8 @@ vbo_save_NotifyBegin(struct gl_context *ctx, GLenum mode) _mesa_install_save_vtxfmt(ctx, &save->vtxfmt); } - /* We need to call SaveFlushVertices() if there's state change */ + /* We need to call vbo_save_SaveFlushVertices() if there's state change */ ctx->Driver.SaveNeedFlush = GL_TRUE; - - /* GL_TRUE means we've handled this glBegin here; don't compile a BEGIN - * opcode into the display list. - */ - return GL_TRUE; } @@ -1019,11 +1179,11 @@ _save_End(void) const GLint i = save->prim_count - 1; ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; - save->prim[i].end = 1; - save->prim[i].count = (save->vert_count - save->prim[i].start); + save->prims[i].end = 1; + save->prims[i].count = (save->vert_count - save->prims[i].start); if (i == (GLint) save->prim_max - 1) { - _save_compile_vertex_list(ctx); + compile_vertex_list(ctx); assert(save->copied.nr == 0); } @@ -1052,13 +1212,24 @@ _save_Begin(GLenum mode) static void GLAPIENTRY _save_PrimitiveRestartNV(void) { - GLenum curPrim; GET_CURRENT_CONTEXT(ctx); + struct vbo_save_context *save = &vbo_context(ctx)->save; - curPrim = ctx->Driver.CurrentSavePrimitive; - - _save_End(); - _save_Begin(curPrim); + if (save->prim_count == 0) { + /* We're not inside a glBegin/End pair, so calling glPrimitiverRestartNV + * is an error. + */ + _mesa_compile_error(ctx, GL_INVALID_OPERATION, + "glPrimitiveRestartNV called outside glBegin/End"); + } else { + /* get current primitive mode */ + GLenum curPrim = save->prims[save->prim_count - 1].mode; + bool no_current_update = save->no_current_update; + + /* restart primitive */ + CALL_End(GET_DISPATCH(), ()); + vbo_save_NotifyBegin(ctx, curPrim, no_current_update); + } } @@ -1071,7 +1242,7 @@ static void GLAPIENTRY _save_OBE_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2) { GET_CURRENT_CONTEXT(ctx); - vbo_save_NotifyBegin(ctx, GL_QUADS | VBO_SAVE_PRIM_WEAK); + vbo_save_NotifyBegin(ctx, GL_QUADS, false); CALL_Vertex2f(GET_DISPATCH(), (x1, y1)); CALL_Vertex2f(GET_DISPATCH(), (x2, y1)); CALL_Vertex2f(GET_DISPATCH(), (x2, y2)); @@ -1084,6 +1255,7 @@ static void GLAPIENTRY _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) { GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao = ctx->Array.VAO; struct vbo_save_context *save = &vbo_context(ctx)->save; GLint i; @@ -1099,16 +1271,75 @@ _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) if (save->out_of_memory) return; - _ae_map_vbos(ctx); + /* Make sure to process any VBO binding changes */ + _mesa_update_state(ctx); - vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK - | VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); + _mesa_vao_map_arrays(ctx, vao, GL_MAP_READ_BIT); + + vbo_save_NotifyBegin(ctx, mode, true); for (i = 0; i < count; i++) - CALL_ArrayElement(GET_DISPATCH(), (start + i)); + _mesa_array_element(ctx, start + i); CALL_End(GET_DISPATCH(), ()); - _ae_unmap_vbos(ctx); + _mesa_vao_unmap_arrays(ctx, vao); +} + + +static void GLAPIENTRY +_save_OBE_MultiDrawArrays(GLenum mode, const GLint *first, + const GLsizei *count, GLsizei primcount) +{ + GET_CURRENT_CONTEXT(ctx); + GLint i; + + if (!_mesa_is_valid_prim_mode(ctx, mode)) { + _mesa_compile_error(ctx, GL_INVALID_ENUM, "glMultiDrawArrays(mode)"); + return; + } + + if (primcount < 0) { + _mesa_compile_error(ctx, GL_INVALID_VALUE, + "glMultiDrawArrays(primcount<0)"); + return; + } + + for (i = 0; i < primcount; i++) { + if (count[i] < 0) { + _mesa_compile_error(ctx, GL_INVALID_VALUE, + "glMultiDrawArrays(count[i]<0)"); + return; + } + } + + for (i = 0; i < primcount; i++) { + if (count[i] > 0) { + _save_OBE_DrawArrays(mode, first[i], count[i]); + } + } +} + + +static void +array_element(struct gl_context *ctx, + GLint basevertex, GLuint elt, unsigned index_size) +{ + /* Section 10.3.5 Primitive Restart: + * [...] + * When one of the *BaseVertex drawing commands specified in section 10.5 + * is used, the primitive restart comparison occurs before the basevertex + * offset is added to the array index. + */ + /* If PrimitiveRestart is enabled and the index is the RestartIndex + * then we call PrimitiveRestartNV and return. + */ + if (ctx->Array._PrimitiveRestart && + elt == ctx->Array._RestartIndex[index_size - 1]) { + CALL_PrimitiveRestartNV(GET_DISPATCH(), ()); + return; + } + + _mesa_array_element(ctx, basevertex + elt); } @@ -1116,12 +1347,13 @@ _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count) * then emitting an indexed prim at runtime. */ static void GLAPIENTRY -_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, - const GLvoid * indices) +_save_OBE_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type, + const GLvoid * indices, GLint basevertex) { GET_CURRENT_CONTEXT(ctx); struct vbo_save_context *save = &vbo_context(ctx)->save; - struct gl_buffer_object *indexbuf = ctx->Array.VAO->IndexBufferObj; + struct gl_vertex_array_object *vao = ctx->Array.VAO; + struct gl_buffer_object *indexbuf = vao->IndexBufferObj; GLint i; if (!_mesa_is_valid_prim_mode(ctx, mode)) { @@ -1142,27 +1374,29 @@ _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, if (save->out_of_memory) return; - _ae_map_vbos(ctx); + /* Make sure to process any VBO binding changes */ + _mesa_update_state(ctx); - if (_mesa_is_bufferobj(indexbuf)) + _mesa_vao_map(ctx, vao, GL_MAP_READ_BIT); + + if (indexbuf) indices = ADD_POINTERS(indexbuf->Mappings[MAP_INTERNAL].Pointer, indices); - vbo_save_NotifyBegin(ctx, (mode | VBO_SAVE_PRIM_WEAK | - VBO_SAVE_PRIM_NO_CURRENT_UPDATE)); + vbo_save_NotifyBegin(ctx, mode, true); switch (type) { case GL_UNSIGNED_BYTE: for (i = 0; i < count; i++) - CALL_ArrayElement(GET_DISPATCH(), (((GLubyte *) indices)[i])); + array_element(ctx, basevertex, ((GLubyte *) indices)[i], 1); break; case GL_UNSIGNED_SHORT: for (i = 0; i < count; i++) - CALL_ArrayElement(GET_DISPATCH(), (((GLushort *) indices)[i])); + array_element(ctx, basevertex, ((GLushort *) indices)[i], 2); break; case GL_UNSIGNED_INT: for (i = 0; i < count; i++) - CALL_ArrayElement(GET_DISPATCH(), (((GLuint *) indices)[i])); + array_element(ctx, basevertex, ((GLuint *) indices)[i], 4); break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glDrawElements(type)"); @@ -1171,7 +1405,14 @@ _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, CALL_End(GET_DISPATCH(), ()); - _ae_unmap_vbos(ctx); + _mesa_vao_unmap(ctx, vao); +} + +static void GLAPIENTRY +_save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type, + const GLvoid * indices) +{ + _save_OBE_DrawElementsBaseVertex(mode, count, type, indices, 0); } @@ -1245,149 +1486,17 @@ _save_OBE_MultiDrawElementsBaseVertex(GLenum mode, const GLsizei *count, static void -_save_vtxfmt_init(struct gl_context *ctx) +vtxfmt_init(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; GLvertexformat *vfmt = &save->vtxfmt; - vfmt->ArrayElement = _ae_ArrayElement; - - vfmt->Color3f = _save_Color3f; - vfmt->Color3fv = _save_Color3fv; - vfmt->Color4f = _save_Color4f; - vfmt->Color4fv = _save_Color4fv; - vfmt->EdgeFlag = _save_EdgeFlag; - vfmt->End = _save_End; - vfmt->PrimitiveRestartNV = _save_PrimitiveRestartNV; - vfmt->FogCoordfEXT = _save_FogCoordfEXT; - vfmt->FogCoordfvEXT = _save_FogCoordfvEXT; - vfmt->Indexf = _save_Indexf; - vfmt->Indexfv = _save_Indexfv; - vfmt->Materialfv = _save_Materialfv; - vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f; - vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv; - vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f; - vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv; - vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f; - vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv; - vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f; - vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv; - vfmt->Normal3f = _save_Normal3f; - vfmt->Normal3fv = _save_Normal3fv; - vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT; - vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT; - vfmt->TexCoord1f = _save_TexCoord1f; - vfmt->TexCoord1fv = _save_TexCoord1fv; - vfmt->TexCoord2f = _save_TexCoord2f; - vfmt->TexCoord2fv = _save_TexCoord2fv; - vfmt->TexCoord3f = _save_TexCoord3f; - vfmt->TexCoord3fv = _save_TexCoord3fv; - vfmt->TexCoord4f = _save_TexCoord4f; - vfmt->TexCoord4fv = _save_TexCoord4fv; - vfmt->Vertex2f = _save_Vertex2f; - vfmt->Vertex2fv = _save_Vertex2fv; - vfmt->Vertex3f = _save_Vertex3f; - vfmt->Vertex3fv = _save_Vertex3fv; - vfmt->Vertex4f = _save_Vertex4f; - vfmt->Vertex4fv = _save_Vertex4fv; - vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB; - vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB; - vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB; - vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB; - vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB; - vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB; - vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB; - vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB; - - vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV; - vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV; - vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV; - vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV; - vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV; - vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV; - vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV; - vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV; - - /* integer-valued */ - vfmt->VertexAttribI1i = _save_VertexAttribI1i; - vfmt->VertexAttribI2i = _save_VertexAttribI2i; - vfmt->VertexAttribI3i = _save_VertexAttribI3i; - vfmt->VertexAttribI4i = _save_VertexAttribI4i; - vfmt->VertexAttribI2iv = _save_VertexAttribI2iv; - vfmt->VertexAttribI3iv = _save_VertexAttribI3iv; - vfmt->VertexAttribI4iv = _save_VertexAttribI4iv; - - /* unsigned integer-valued */ - vfmt->VertexAttribI1ui = _save_VertexAttribI1ui; - vfmt->VertexAttribI2ui = _save_VertexAttribI2ui; - vfmt->VertexAttribI3ui = _save_VertexAttribI3ui; - vfmt->VertexAttribI4ui = _save_VertexAttribI4ui; - vfmt->VertexAttribI2uiv = _save_VertexAttribI2uiv; - vfmt->VertexAttribI3uiv = _save_VertexAttribI3uiv; - vfmt->VertexAttribI4uiv = _save_VertexAttribI4uiv; - - vfmt->VertexP2ui = _save_VertexP2ui; - vfmt->VertexP3ui = _save_VertexP3ui; - vfmt->VertexP4ui = _save_VertexP4ui; - vfmt->VertexP2uiv = _save_VertexP2uiv; - vfmt->VertexP3uiv = _save_VertexP3uiv; - vfmt->VertexP4uiv = _save_VertexP4uiv; - - vfmt->TexCoordP1ui = _save_TexCoordP1ui; - vfmt->TexCoordP2ui = _save_TexCoordP2ui; - vfmt->TexCoordP3ui = _save_TexCoordP3ui; - vfmt->TexCoordP4ui = _save_TexCoordP4ui; - vfmt->TexCoordP1uiv = _save_TexCoordP1uiv; - vfmt->TexCoordP2uiv = _save_TexCoordP2uiv; - vfmt->TexCoordP3uiv = _save_TexCoordP3uiv; - vfmt->TexCoordP4uiv = _save_TexCoordP4uiv; - - vfmt->MultiTexCoordP1ui = _save_MultiTexCoordP1ui; - vfmt->MultiTexCoordP2ui = _save_MultiTexCoordP2ui; - vfmt->MultiTexCoordP3ui = _save_MultiTexCoordP3ui; - vfmt->MultiTexCoordP4ui = _save_MultiTexCoordP4ui; - vfmt->MultiTexCoordP1uiv = _save_MultiTexCoordP1uiv; - vfmt->MultiTexCoordP2uiv = _save_MultiTexCoordP2uiv; - vfmt->MultiTexCoordP3uiv = _save_MultiTexCoordP3uiv; - vfmt->MultiTexCoordP4uiv = _save_MultiTexCoordP4uiv; - - vfmt->NormalP3ui = _save_NormalP3ui; - vfmt->NormalP3uiv = _save_NormalP3uiv; - - vfmt->ColorP3ui = _save_ColorP3ui; - vfmt->ColorP4ui = _save_ColorP4ui; - vfmt->ColorP3uiv = _save_ColorP3uiv; - vfmt->ColorP4uiv = _save_ColorP4uiv; - - vfmt->SecondaryColorP3ui = _save_SecondaryColorP3ui; - vfmt->SecondaryColorP3uiv = _save_SecondaryColorP3uiv; - - vfmt->VertexAttribP1ui = _save_VertexAttribP1ui; - vfmt->VertexAttribP2ui = _save_VertexAttribP2ui; - vfmt->VertexAttribP3ui = _save_VertexAttribP3ui; - vfmt->VertexAttribP4ui = _save_VertexAttribP4ui; - - vfmt->VertexAttribP1uiv = _save_VertexAttribP1uiv; - vfmt->VertexAttribP2uiv = _save_VertexAttribP2uiv; - vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv; - vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv; - - /* This will all require us to fallback to saving the list as opcodes: - */ - vfmt->CallList = _save_CallList; - vfmt->CallLists = _save_CallLists; - - vfmt->EvalCoord1f = _save_EvalCoord1f; - vfmt->EvalCoord1fv = _save_EvalCoord1fv; - vfmt->EvalCoord2f = _save_EvalCoord2f; - vfmt->EvalCoord2fv = _save_EvalCoord2fv; - vfmt->EvalPoint1 = _save_EvalPoint1; - vfmt->EvalPoint2 = _save_EvalPoint2; - - /* These calls all generate GL_INVALID_OPERATION since this vtxfmt is - * only used when we're inside a glBegin/End pair. - */ - vfmt->Begin = _save_Begin; +#define NAME_AE(x) _ae_##x +#define NAME_CALLLIST(x) _save_##x +#define NAME(x) _save_##x +#define NAME_ES(x) _save_##x##ARB + +#include "vbo_init_tmp.h" } @@ -1400,7 +1509,9 @@ vbo_initialize_save_dispatch(const struct gl_context *ctx, struct _glapi_table *exec) { SET_DrawArrays(exec, _save_OBE_DrawArrays); + SET_MultiDrawArrays(exec, _save_OBE_MultiDrawArrays); SET_DrawElements(exec, _save_OBE_DrawElements); + SET_DrawElementsBaseVertex(exec, _save_OBE_DrawElementsBaseVertex); SET_DrawRangeElements(exec, _save_OBE_DrawRangeElements); SET_MultiDrawElementsEXT(exec, _save_OBE_MultiDrawElements); SET_MultiDrawElementsBaseVertex(exec, _save_OBE_MultiDrawElementsBaseVertex); @@ -1421,15 +1532,18 @@ vbo_save_SaveFlushVertices(struct gl_context *ctx) return; if (save->vert_count || save->prim_count) - _save_compile_vertex_list(ctx); + compile_vertex_list(ctx); - _save_copy_to_current(ctx); - _save_reset_vertex(ctx); - _save_reset_counters(ctx); + copy_to_current(ctx); + reset_vertex(ctx); + reset_counters(ctx); ctx->Driver.SaveNeedFlush = GL_FALSE; } +/** + * Called from glNewList when we're starting to compile a display list. + */ void vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode) { @@ -1439,19 +1553,22 @@ vbo_save_NewList(struct gl_context *ctx, GLuint list, GLenum mode) (void) mode; if (!save->prim_store) - save->prim_store = alloc_prim_store(ctx); + save->prim_store = alloc_prim_store(); if (!save->vertex_store) save->vertex_store = alloc_vertex_store(ctx); save->buffer_ptr = vbo_save_map_vertex_store(ctx, save->vertex_store); - _save_reset_vertex(ctx); - _save_reset_counters(ctx); + reset_vertex(ctx); + reset_counters(ctx); ctx->Driver.SaveNeedFlush = GL_FALSE; } +/** + * Called from glEndList when we're finished compiling a display list. + */ void vbo_save_EndList(struct gl_context *ctx) { @@ -1463,8 +1580,8 @@ vbo_save_EndList(struct gl_context *ctx) if (save->prim_count > 0) { GLint i = save->prim_count - 1; ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END; - save->prim[i].end = 0; - save->prim[i].count = save->vert_count - save->prim[i].start; + save->prims[i].end = 0; + save->prims[i].count = save->vert_count - save->prims[i].start; } /* Make sure this vertex list gets replayed by the "loopback" @@ -1486,6 +1603,10 @@ vbo_save_EndList(struct gl_context *ctx) } +/** + * Called from the display list code when we're about to execute a + * display list. + */ void vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist) { @@ -1494,28 +1615,30 @@ vbo_save_BeginCallList(struct gl_context *ctx, struct gl_display_list *dlist) } +/** + * Called from the display list code when we're finished executing a + * display list. + */ void vbo_save_EndCallList(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; - if (ctx->ListState.CallDepth == 1) { - /* This is correct: want to keep only the VBO_SAVE_FALLBACK - * flag, if it is set: - */ - save->replay_flags &= VBO_SAVE_FALLBACK; - } + if (ctx->ListState.CallDepth == 1) + save->replay_flags = 0; } +/** + * Called by display list code when a display list is being deleted. + */ static void vbo_destroy_vertex_list(struct gl_context *ctx, void *data) { struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; - (void) ctx; - if (--node->vertex_store->refcount == 0) - free_vertex_store(ctx, node->vertex_store); + for (gl_vertex_processing_mode vpm = VP_MODE_FF; vpm < VP_MODE_MAX; ++vpm) + _mesa_reference_vao(ctx, &node->VAO[vpm], NULL); if (--node->prim_store->refcount == 0) free(node->prim_store); @@ -1530,21 +1653,20 @@ vbo_print_vertex_list(struct gl_context *ctx, void *data, FILE *f) { struct vbo_save_vertex_list *node = (struct vbo_save_vertex_list *) data; GLuint i; - struct gl_buffer_object *buffer = node->vertex_store ? - node->vertex_store->bufferobj : NULL; + struct gl_buffer_object *buffer = node->VAO[0]->BufferBinding[0].BufferObj; + const GLuint vertex_size = _vbo_save_get_stride(node)/sizeof(GLfloat); (void) ctx; - fprintf(f, "VBO-VERTEX-LIST, %u vertices %d primitives, %d vertsize " + fprintf(f, "VBO-VERTEX-LIST, %u vertices, %d primitives, %d vertsize, " "buffer %p\n", - node->count, node->prim_count, node->vertex_size, + node->vertex_count, node->prim_count, vertex_size, buffer); for (i = 0; i < node->prim_count; i++) { - struct _mesa_prim *prim = &node->prim[i]; - fprintf(f, " prim %d: %s%s %d..%d %s %s\n", + struct _mesa_prim *prim = &node->prims[i]; + fprintf(f, " prim %d: %s %d..%d %s %s\n", i, _mesa_lookup_prim_by_nr(prim->mode), - prim->weak ? " (weak)" : "", prim->start, prim->start + prim->count, (prim->begin) ? "BEGIN" : "(wrap)", @@ -1557,7 +1679,7 @@ vbo_print_vertex_list(struct gl_context *ctx, void *data, FILE *f) * Called during context creation/init. */ static void -_save_current_init(struct gl_context *ctx) +current_init(struct gl_context *ctx) { struct vbo_save_context *save = &vbo_context(ctx)->save; GLint i; @@ -1585,7 +1707,6 @@ void vbo_save_api_init(struct vbo_save_context *save) { struct gl_context *ctx = save->ctx; - GLuint i; save->opcode_vertex_list = _mesa_dlist_alloc_opcode(ctx, @@ -1594,13 +1715,7 @@ vbo_save_api_init(struct vbo_save_context *save) vbo_destroy_vertex_list, vbo_print_vertex_list); - ctx->Driver.NotifySaveBegin = vbo_save_NotifyBegin; - - _save_vtxfmt_init(ctx); - _save_current_init(ctx); - _mesa_noop_vtxfmt_init(&save->vtxfmt_noop); - - /* These will actually get set again when binding/drawing */ - for (i = 0; i < VBO_ATTRIB_MAX; i++) - save->inputs[i] = &save->arrays[i]; + vtxfmt_init(ctx); + current_init(ctx); + _mesa_noop_vtxfmt_init(ctx, &save->vtxfmt_noop); }