#include "main/state.h"
#include "main/light.h"
#include "main/api_arrayelt.h"
-#include "main/api_validate.h"
+#include "main/draw_validate.h"
#include "main/dispatch.h"
#include "util/bitscan.h"
+#include "util/u_memory.h"
#include "vbo_noop.h"
#include "vbo_private.h"
/* Execute the buffer and save copied vertices.
*/
if (exec->vtx.vert_count)
- vbo_exec_vtx_flush(exec, GL_FALSE);
+ vbo_exec_vtx_flush(exec);
else {
exec->vtx.prim_count = 0;
exec->vtx.copied.nr = 0;
/* Note: the exec->vtx.current[i] pointers point into the
* ctx->Current.Attrib and ctx->Light.Material.Attrib arrays.
*/
- GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+ GLfloat *current = (GLfloat *)vbo->current[i].Ptr;
fi_type tmp[8]; /* space for doubles */
int dmul = 1;
- if (exec->vtx.attrtype[i] == GL_DOUBLE ||
- exec->vtx.attrtype[i] == GL_UNSIGNED_INT64_ARB)
+ if (exec->vtx.attr[i].type == GL_DOUBLE ||
+ exec->vtx.attr[i].type == GL_UNSIGNED_INT64_ARB)
dmul = 2;
- assert(exec->vtx.attrsz[i]);
+ assert(exec->vtx.attr[i].size);
- if (exec->vtx.attrtype[i] == GL_DOUBLE ||
- exec->vtx.attrtype[i] == GL_UNSIGNED_INT64_ARB) {
+ if (exec->vtx.attr[i].type == GL_DOUBLE ||
+ exec->vtx.attr[i].type == GL_UNSIGNED_INT64_ARB) {
memset(tmp, 0, sizeof(tmp));
- memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attrsz[i] * sizeof(GLfloat));
+ memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attr[i].size * sizeof(GLfloat));
} else {
COPY_CLEAN_4V_TYPE_AS_UNION(tmp,
- exec->vtx.attrsz[i],
+ exec->vtx.attr[i].size,
exec->vtx.attrptr[i],
- exec->vtx.attrtype[i]);
+ exec->vtx.attr[i].type);
}
- if (exec->vtx.attrtype[i] != vbo->currval[i].Type ||
+ if (exec->vtx.attr[i].type != vbo->current[i].Format.Type ||
memcmp(current, tmp, 4 * sizeof(GLfloat) * dmul) != 0) {
memcpy(current, tmp, 4 * sizeof(GLfloat) * dmul);
* directly.
*/
/* Size here is in components - not bytes */
- vbo->currval[i].Size = exec->vtx.attrsz[i] / dmul;
- vbo->currval[i]._ElementSize =
- vbo->currval[i].Size * sizeof(GLfloat) * dmul;
- vbo->currval[i].Type = exec->vtx.attrtype[i];
- vbo->currval[i].Integer =
- vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]);
- vbo->currval[i].Doubles =
- vbo_attrtype_to_double_flag(exec->vtx.attrtype[i]);
+ vbo_set_vertex_format(&vbo->current[i].Format,
+ exec->vtx.attr[i].size / dmul,
+ exec->vtx.attr[i].type);
/* This triggers rather too much recalculation of Mesa state
* that doesn't get used (eg light positions).
/* Colormaterial -- this kindof sucks.
*/
if (ctx->Light.ColorMaterialEnabled &&
- exec->vtx.attrsz[VBO_ATTRIB_COLOR0]) {
+ exec->vtx.attr[VBO_ATTRIB_COLOR0].size) {
_mesa_update_color_material(ctx,
ctx->Current.Attrib[VBO_ATTRIB_COLOR0]);
}
}
-/**
- * Copy current vertex attribute values into the current vertex.
- */
-static void
-vbo_exec_copy_from_current(struct vbo_exec_context *exec)
-{
- struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- GLint i;
-
- for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
- if (exec->vtx.attrtype[i] == GL_DOUBLE ||
- exec->vtx.attrtype[i] == GL_UNSIGNED_INT64_ARB) {
- memcpy(exec->vtx.attrptr[i], vbo->currval[i].Ptr,
- exec->vtx.attrsz[i] * sizeof(GLfloat));
- } else {
- const fi_type *current = (fi_type *) vbo->currval[i].Ptr;
- switch (exec->vtx.attrsz[i]) {
- case 4: exec->vtx.attrptr[i][3] = current[3];
- case 3: exec->vtx.attrptr[i][2] = current[2];
- case 2: exec->vtx.attrptr[i][1] = current[1];
- case 1: exec->vtx.attrptr[i][0] = current[0];
- break;
- }
- }
- }
-}
-
-
/**
* Flush existing data, set new attrib size, replay copied vertices.
* This is called when we transition from a small vertex attribute size
*/
static void
vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
- GLuint attr, GLuint newSize)
+ GLuint attr, GLuint newSize, GLenum newType)
{
struct gl_context *ctx = exec->ctx;
struct vbo_context *vbo = vbo_context(ctx);
const GLint lastcount = exec->vtx.vert_count;
fi_type *old_attrptr[VBO_ATTRIB_MAX];
+ const GLuint old_vtx_size_no_pos = exec->vtx.vertex_size_no_pos;
const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
- const GLuint oldSize = exec->vtx.attrsz[attr];
+ const GLuint oldSize = exec->vtx.attr[attr].size;
GLuint i;
assert(attr < VBO_ATTRIB_MAX);
memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
}
- if (unlikely(oldSize)) {
- /* Do a COPY_TO_CURRENT to ensure back-copying works for the
- * case when the attribute already exists in the vertex and is
- * having its size increased.
- */
- vbo_exec_copy_to_current(exec);
- }
-
/* Heuristic: Attempt to isolate attributes received outside
* begin/end so that they don't bloat the vertices.
*/
/* Fix up sizes:
*/
- exec->vtx.attrsz[attr] = newSize;
+ exec->vtx.attr[attr].size = newSize;
+ exec->vtx.attr[attr].active_size = newSize;
+ exec->vtx.attr[attr].type = newType;
exec->vtx.vertex_size += newSize - oldSize;
+ exec->vtx.vertex_size_no_pos = exec->vtx.vertex_size - exec->vtx.attr[0].size;
exec->vtx.max_vert = vbo_compute_max_verts(exec);
exec->vtx.vert_count = 0;
exec->vtx.buffer_ptr = exec->vtx.buffer_map;
exec->vtx.enabled |= BITFIELD64_BIT(attr);
- if (unlikely(oldSize)) {
- /* Size changed, recalculate all the attrptr[] values
- */
- fi_type *tmp = exec->vtx.vertex;
+ if (attr != 0) {
+ if (unlikely(oldSize)) {
+ unsigned offset = exec->vtx.attrptr[attr] - exec->vtx.vertex;
+
+ /* If there are attribs after the resized attrib... */
+ if (offset + oldSize < old_vtx_size_no_pos) {
+ int size_diff = newSize - oldSize;
+ fi_type *old_first = exec->vtx.attrptr[attr] + oldSize;
+ fi_type *new_first = exec->vtx.attrptr[attr] + newSize;
+ fi_type *old_last = exec->vtx.vertex + old_vtx_size_no_pos - 1;
+ fi_type *new_last = exec->vtx.vertex + exec->vtx.vertex_size_no_pos - 1;
+
+ if (size_diff < 0) {
+ /* Decreasing the size: Copy from first to last to move
+ * elements to the left.
+ */
+ fi_type *old_end = old_last + 1;
+ fi_type *old = old_first;
+ fi_type *new = new_first;
+
+ do {
+ *new++ = *old++;
+ } while (old != old_end);
+ } else {
+ /* Increasing the size: Copy from last to first to move
+ * elements to the right.
+ */
+ fi_type *old_end = old_first - 1;
+ fi_type *old = old_last;
+ fi_type *new = new_last;
+
+ do {
+ *new-- = *old--;
+ } while (old != old_end);
+ }
+
+ /* Update pointers to attribs, because we moved them. */
+ GLbitfield64 enabled = exec->vtx.enabled &
+ ~BITFIELD64_BIT(VBO_ATTRIB_POS) &
+ ~BITFIELD64_BIT(attr);
+ while (enabled) {
+ unsigned i = u_bit_scan64(&enabled);
- for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
- if (exec->vtx.attrsz[i]) {
- exec->vtx.attrptr[i] = tmp;
- tmp += exec->vtx.attrsz[i];
+ if (exec->vtx.attrptr[i] > exec->vtx.attrptr[attr])
+ exec->vtx.attrptr[i] += size_diff;
+ }
}
- else
- exec->vtx.attrptr[i] = NULL; /* will not be dereferenced */
+ } else {
+ /* Just have to append the new attribute at the end */
+ exec->vtx.attrptr[attr] = exec->vtx.vertex +
+ exec->vtx.vertex_size_no_pos - newSize;
}
-
- /* Copy from current to repopulate the vertex with correct
- * values.
- */
- vbo_exec_copy_from_current(exec);
- }
- else {
- /* Just have to append the new attribute at the end */
- exec->vtx.attrptr[attr] = exec->vtx.vertex +
- exec->vtx.vertex_size - newSize;
}
+ /* The position is always last. */
+ exec->vtx.attrptr[0] = exec->vtx.vertex + exec->vtx.vertex_size_no_pos;
+
/* Replay stored vertices to translate them
* to new format here.
*
GLbitfield64 enabled = exec->vtx.enabled;
while (enabled) {
const int j = u_bit_scan64(&enabled);
- GLuint sz = exec->vtx.attrsz[j];
+ GLuint sz = exec->vtx.attr[j].size;
GLint old_offset = old_attrptr[j] - exec->vtx.vertex;
GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
fi_type tmp[4];
COPY_CLEAN_4V_TYPE_AS_UNION(tmp, oldSize,
data + old_offset,
- exec->vtx.attrtype[j]);
+ exec->vtx.attr[j].type);
COPY_SZ_4V(dest + new_offset, newSize, tmp);
} else {
- fi_type *current = (fi_type *)vbo->currval[j].Ptr;
+ fi_type *current = (fi_type *)vbo->current[j].Ptr;
COPY_SZ_4V(dest + new_offset, sz, current);
}
}
assert(attr < VBO_ATTRIB_MAX);
- if (newSize > exec->vtx.attrsz[attr] ||
- newType != exec->vtx.attrtype[attr]) {
+ if (newSize > exec->vtx.attr[attr].size ||
+ newType != exec->vtx.attr[attr].type) {
/* New size is larger. Need to flush existing vertices and get
* an enlarged vertex format.
*/
- vbo_exec_wrap_upgrade_vertex(exec, attr, newSize);
+ vbo_exec_wrap_upgrade_vertex(exec, attr, newSize, newType);
}
- else if (newSize < exec->vtx.active_sz[attr]) {
+ else if (newSize < exec->vtx.attr[attr].active_size) {
GLuint i;
const fi_type *id =
- vbo_get_default_vals_as_union(exec->vtx.attrtype[attr]);
+ vbo_get_default_vals_as_union(exec->vtx.attr[attr].type);
/* New size is smaller - just need to fill in some
* zeros. Don't need to flush or wrap.
*/
- for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
+ for (i = newSize; i <= exec->vtx.attr[attr].size; i++)
exec->vtx.attrptr[attr][i-1] = id[i-1];
- }
-
- exec->vtx.active_sz[attr] = newSize;
- exec->vtx.attrtype[attr] = newType;
- /* Does setting NeedFlush belong here? Necessitates resetting
- * vtxfmt on each flush (otherwise flags won't get reset
- * afterwards).
- */
- if (attr == 0)
- ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ exec->vtx.attr[attr].active_size = newSize;
+ }
}
/**
- * Called upon first glVertex, glColor, glTexCoord, etc.
+ * 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 void
-vbo_exec_begin_vertices(struct gl_context *ctx)
+static inline bool
+is_vertex_position(const struct gl_context *ctx, GLuint index)
{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-
- vbo_exec_vtx_map(exec);
-
- assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
- assert(exec->begin_vertices_flags);
-
- ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
+ return (index == 0 &&
+ _mesa_attr_zero_aliases_vertex(ctx) &&
+ _mesa_inside_begin_end(ctx));
}
+/* Write a 64-bit value into a 32-bit pointer by preserving endianness. */
+#if UTIL_ARCH_LITTLE_ENDIAN
+ #define SET_64BIT(dst32, u64) do { \
+ *(dst32)++ = (u64); \
+ *(dst32)++ = (uint64_t)(u64) >> 32; \
+ } while (0)
+#else
+ #define SET_64BIT(dst32, u64) do { \
+ *(dst32)++ = (uint64_t)(u64) >> 32; \
+ *(dst32)++ = (u64); \
+ } while (0)
+#endif
+
/**
* This macro is used to implement all the glVertex, glColor, glTexCoord,
* \param A VBO_ATTRIB_x attribute index
* \param N attribute size (1..4)
* \param T type (GL_FLOAT, GL_DOUBLE, GL_INT, GL_UNSIGNED_INT)
- * \param C cast type (fi_type or double)
+ * \param C cast type (uint32_t or uint64_t)
* \param V0, V1, v2, V3 attribute value
*/
#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \
\
assert(sz == 1 || sz == 2); \
\
- /* check if attribute size or type is changing */ \
- if (unlikely(exec->vtx.active_sz[A] != N * sz) || \
- unlikely(exec->vtx.attrtype[A] != T)) { \
- vbo_exec_fixup_vertex(ctx, A, N * sz, T); \
- } \
+ /* store a copy of the attribute in exec except for glVertex */ \
+ if ((A) != 0) { \
+ /* Check if attribute size or type is changing. */ \
+ if (unlikely(exec->vtx.attr[A].active_size != N * sz || \
+ exec->vtx.attr[A].type != T)) { \
+ vbo_exec_fixup_vertex(ctx, A, N * sz, T); \
+ } \
\
- /* store vertex attribute in vertex buffer */ \
- { \
C *dest = (C *)exec->vtx.attrptr[A]; \
if (N>0) dest[0] = V0; \
if (N>1) dest[1] = V1; \
if (N>2) dest[2] = V2; \
if (N>3) dest[3] = V3; \
- assert(exec->vtx.attrtype[A] == T); \
- } \
+ assert(exec->vtx.attr[A].type == T); \
\
- if ((A) == 0) { \
+ /* we now have accumulated a per-vertex attribute */ \
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
+ } else { \
/* This is a glVertex call */ \
- GLuint i; \
+ int size = exec->vtx.attr[0].size; \
\
- if (unlikely((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0)) { \
- vbo_exec_begin_vertices(ctx); \
+ /* Check if attribute size or type is changing. */ \
+ if (unlikely(size < N * sz || \
+ exec->vtx.attr[0].type != T)) { \
+ vbo_exec_wrap_upgrade_vertex(exec, 0, N * sz, T); \
} \
\
- if (unlikely(!exec->vtx.buffer_ptr)) { \
- vbo_exec_vtx_map(exec); \
- } \
- assert(exec->vtx.buffer_ptr); \
+ uint32_t *dst = (uint32_t *)exec->vtx.buffer_ptr; \
+ uint32_t *src = (uint32_t *)exec->vtx.vertex; \
+ unsigned vertex_size_no_pos = exec->vtx.vertex_size_no_pos; \
\
- /* copy 32-bit words */ \
- for (i = 0; i < exec->vtx.vertex_size; i++) \
- exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
+ /* Copy over attributes from exec. */ \
+ for (unsigned i = 0; i < vertex_size_no_pos; i++) \
+ *dst++ = *src++; \
\
- exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
+ /* Store the position, which is always last and can have 32 or */ \
+ /* 64 bits per channel. */ \
+ if (sizeof(C) == 4) { \
+ if (N > 0) *dst++ = V0; \
+ if (N > 1) *dst++ = V1; \
+ if (N > 2) *dst++ = V2; \
+ if (N > 3) *dst++ = V3; \
\
- /* Set FLUSH_STORED_VERTICES to indicate that there's now */ \
- /* something to draw (not just updating a color or texcoord).*/ \
- ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
+ if (unlikely(N < size)) { \
+ if (N < 2 && size >= 2) *dst++ = V1; \
+ if (N < 3 && size >= 3) *dst++ = V2; \
+ if (N < 4 && size >= 4) *dst++ = V3; \
+ } \
+ } else { \
+ /* 64 bits: dst can be unaligned, so copy each 4-byte word */ \
+ /* separately */ \
+ if (N > 0) SET_64BIT(dst, V0); \
+ if (N > 1) SET_64BIT(dst, V1); \
+ if (N > 2) SET_64BIT(dst, V2); \
+ if (N > 3) SET_64BIT(dst, V3); \
\
- if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
+ if (unlikely(N * 2 < size)) { \
+ if (N < 2 && size >= 4) SET_64BIT(dst, V1); \
+ if (N < 3 && size >= 6) SET_64BIT(dst, V2); \
+ if (N < 4 && size >= 8) SET_64BIT(dst, V3); \
+ } \
+ } \
+ \
+ /* dst now points at the beginning of the next vertex */ \
+ exec->vtx.buffer_ptr = (fi_type*)dst; \
+ \
+ /* Don't set FLUSH_UPDATE_CURRENT because */ \
+ /* Current.Attrib[VBO_ATTRIB_POS] is never used. */ \
+ \
+ if (unlikely(++exec->vtx.vert_count >= exec->vtx.max_vert)) \
vbo_exec_vtx_wrap(exec); \
- } else { \
- /* we now have accumulated per-vertex attributes */ \
- ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
} \
} while (0)
#undef ERROR
#define ERROR(err) _mesa_error(ctx, err, __func__)
-#define TAG(x) vbo_##x
+#define TAG(x) vbo_exec_##x
#include "vbo_attrib_tmp.h"
* this may be a (partial) no-op.
*/
static void GLAPIENTRY
-vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+vbo_exec_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
{
GLbitfield updateMats;
GET_CURRENT_CONTEXT(ctx);
/**
* Flush (draw) vertices.
- * \param unmap - leave VBO unmapped after flushing?
+ *
+ * \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
*/
static void
-vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
+vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, unsigned flags)
{
- if (exec->vtx.vert_count || unmap) {
- vbo_exec_vtx_flush(exec, unmap);
- }
+ struct gl_context *ctx = exec->ctx;
+
+ if (flags & FLUSH_STORED_VERTICES) {
+ if (exec->vtx.vert_count) {
+ vbo_exec_vtx_flush(exec);
+ }
+
+ if (exec->vtx.vertex_size) {
+ vbo_exec_copy_to_current(exec);
+ vbo_reset_all_attr(exec);
+ }
- if (exec->vtx.vertex_size) {
+ /* All done. */
+ ctx->Driver.NeedFlush = 0;
+ } else {
+ assert(flags == FLUSH_UPDATE_CURRENT);
+
+ /* Note that the vertex size is unchanged.
+ * (vbo_reset_all_attr isn't called)
+ */
vbo_exec_copy_to_current(exec);
- vbo_reset_all_attr(exec);
+
+ /* Only FLUSH_UPDATE_CURRENT is done. */
+ ctx->Driver.NeedFlush = ~FLUSH_UPDATE_CURRENT;
}
}
for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
if (exec->eval.map1[i].map)
- if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz)
+ if (exec->vtx.attr[i].active_size != exec->eval.map1[i].sz)
vbo_exec_fixup_vertex(ctx, i, exec->eval.map1[i].sz, GL_FLOAT);
}
}
for (i = 0; i <= VBO_ATTRIB_TEX7; i++) {
if (exec->eval.map2[i].map)
- if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz)
+ if (exec->vtx.attr[i].active_size != exec->eval.map2[i].sz)
vbo_exec_fixup_vertex(ctx, i, exec->eval.map2[i].sz, GL_FLOAT);
}
if (ctx->Eval.AutoNormal)
- if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3)
+ if (exec->vtx.attr[VBO_ATTRIB_NORMAL].active_size != 3)
vbo_exec_fixup_vertex(ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT);
}
vbo_exec_Begin(GLenum mode)
{
GET_CURRENT_CONTEXT(ctx);
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ struct vbo_context *vbo = vbo_context(ctx);
+ struct vbo_exec_context *exec = &vbo->exec;
int i;
if (_mesa_inside_begin_end(ctx)) {
return;
}
- _mesa_set_drawing_arrays(ctx, exec->vtx.inputs);
-
- if (ctx->NewState) {
- _mesa_update_state(ctx);
-
- CALL_Begin(ctx->Exec, (mode));
- return;
- }
-
if (!_mesa_valid_to_render(ctx, "glBegin")) {
return;
}
/* Heuristic: attempt to isolate attributes occurring outside
* begin/end pairs.
+ *
+ * Use FLUSH_STORED_VERTICES, because it updates current attribs and
+ * sets vertex_size to 0. (FLUSH_UPDATE_CURRENT doesn't change vertex_size)
*/
- if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
- vbo_exec_FlushVertices_internal(exec, GL_FALSE);
+ if (exec->vtx.vertex_size && !exec->vtx.attr[VBO_ATTRIB_POS].size)
+ vbo_exec_FlushVertices_internal(exec, FLUSH_STORED_VERTICES);
i = exec->vtx.prim_count++;
exec->vtx.prim[i].mode = mode;
exec->vtx.prim[i].begin = 1;
exec->vtx.prim[i].end = 0;
- exec->vtx.prim[i].indexed = 0;
- exec->vtx.prim[i].weak = 0;
- exec->vtx.prim[i].pad = 0;
exec->vtx.prim[i].start = exec->vtx.vert_count;
exec->vtx.prim[i].count = 0;
- exec->vtx.prim[i].num_instances = 1;
- exec->vtx.prim[i].base_instance = 0;
- exec->vtx.prim[i].is_indirect = 0;
ctx->Driver.CurrentExecPrimitive = mode;
ctx->Exec = ctx->BeginEnd;
+
/* We may have been called from a display list, in which case we should
* leave dlist.c's dispatch table in place.
*/
- if (ctx->CurrentClientDispatch == ctx->OutsideBeginEnd) {
- ctx->CurrentClientDispatch = ctx->BeginEnd;
+ if (ctx->CurrentClientDispatch == ctx->MarshalExec) {
+ ctx->CurrentServerDispatch = ctx->Exec;
+ } else if (ctx->CurrentClientDispatch == ctx->OutsideBeginEnd) {
+ ctx->CurrentClientDispatch = ctx->Exec;
_glapi_set_dispatch(ctx->CurrentClientDispatch);
} else {
assert(ctx->CurrentClientDispatch == ctx->Save);
struct _mesa_prim *prev = &exec->vtx.prim[exec->vtx.prim_count - 2];
assert(prev == cur - 1);
- if (vbo_can_merge_prims(prev, cur)) {
- assert(cur->begin);
- assert(cur->end);
- assert(prev->begin);
- assert(prev->end);
- vbo_merge_prims(prev, cur);
+ if (vbo_merge_draws(exec->ctx, false, prev, cur))
exec->vtx.prim_count--; /* drop the last primitive */
- }
}
}
}
ctx->Exec = ctx->OutsideBeginEnd;
- if (ctx->CurrentClientDispatch == ctx->BeginEnd) {
- ctx->CurrentClientDispatch = ctx->OutsideBeginEnd;
+
+ if (ctx->CurrentClientDispatch == ctx->MarshalExec) {
+ ctx->CurrentServerDispatch = ctx->Exec;
+ } else if (ctx->CurrentClientDispatch == ctx->BeginEnd) {
+ ctx->CurrentClientDispatch = ctx->Exec;
_glapi_set_dispatch(ctx->CurrentClientDispatch);
}
if (exec->vtx.prim_count > 0) {
/* close off current primitive */
struct _mesa_prim *last_prim = &exec->vtx.prim[exec->vtx.prim_count - 1];
+ unsigned count = exec->vtx.vert_count - last_prim->start;
last_prim->end = 1;
- last_prim->count = exec->vtx.vert_count - last_prim->start;
+ last_prim->count = count;
+
+ if (count)
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
/* Special handling for GL_LINE_LOOP */
if (last_prim->mode == GL_LINE_LOOP && last_prim->begin == 0) {
ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
if (exec->vtx.prim_count == VBO_MAX_PRIM)
- vbo_exec_vtx_flush(exec, GL_FALSE);
+ vbo_exec_vtx_flush(exec);
if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
_mesa_flush(ctx);
struct gl_context *ctx = exec->ctx;
GLvertexformat *vfmt = &exec->vtxfmt;
- vfmt->ArrayElement = _ae_ArrayElement;
-
- vfmt->Begin = vbo_exec_Begin;
- vfmt->End = vbo_exec_End;
- vfmt->PrimitiveRestartNV = vbo_exec_PrimitiveRestartNV;
-
- vfmt->CallList = _mesa_CallList;
- vfmt->CallLists = _mesa_CallLists;
-
- vfmt->EvalCoord1f = vbo_exec_EvalCoord1f;
- vfmt->EvalCoord1fv = vbo_exec_EvalCoord1fv;
- vfmt->EvalCoord2f = vbo_exec_EvalCoord2f;
- vfmt->EvalCoord2fv = vbo_exec_EvalCoord2fv;
- vfmt->EvalPoint1 = vbo_exec_EvalPoint1;
- vfmt->EvalPoint2 = vbo_exec_EvalPoint2;
-
- /* from attrib_tmp.h:
- */
- vfmt->Color3f = vbo_Color3f;
- vfmt->Color3fv = vbo_Color3fv;
- vfmt->Color4f = vbo_Color4f;
- vfmt->Color4fv = vbo_Color4fv;
- vfmt->FogCoordfEXT = vbo_FogCoordfEXT;
- vfmt->FogCoordfvEXT = vbo_FogCoordfvEXT;
- vfmt->MultiTexCoord1fARB = vbo_MultiTexCoord1f;
- vfmt->MultiTexCoord1fvARB = vbo_MultiTexCoord1fv;
- vfmt->MultiTexCoord2fARB = vbo_MultiTexCoord2f;
- vfmt->MultiTexCoord2fvARB = vbo_MultiTexCoord2fv;
- vfmt->MultiTexCoord3fARB = vbo_MultiTexCoord3f;
- vfmt->MultiTexCoord3fvARB = vbo_MultiTexCoord3fv;
- vfmt->MultiTexCoord4fARB = vbo_MultiTexCoord4f;
- vfmt->MultiTexCoord4fvARB = vbo_MultiTexCoord4fv;
- vfmt->Normal3f = vbo_Normal3f;
- vfmt->Normal3fv = vbo_Normal3fv;
- vfmt->SecondaryColor3fEXT = vbo_SecondaryColor3fEXT;
- vfmt->SecondaryColor3fvEXT = vbo_SecondaryColor3fvEXT;
- vfmt->TexCoord1f = vbo_TexCoord1f;
- vfmt->TexCoord1fv = vbo_TexCoord1fv;
- vfmt->TexCoord2f = vbo_TexCoord2f;
- vfmt->TexCoord2fv = vbo_TexCoord2fv;
- vfmt->TexCoord3f = vbo_TexCoord3f;
- vfmt->TexCoord3fv = vbo_TexCoord3fv;
- vfmt->TexCoord4f = vbo_TexCoord4f;
- vfmt->TexCoord4fv = vbo_TexCoord4fv;
- vfmt->Vertex2f = vbo_Vertex2f;
- vfmt->Vertex2fv = vbo_Vertex2fv;
- vfmt->Vertex3f = vbo_Vertex3f;
- vfmt->Vertex3fv = vbo_Vertex3fv;
- vfmt->Vertex4f = vbo_Vertex4f;
- vfmt->Vertex4fv = vbo_Vertex4fv;
-
- if (ctx->API == API_OPENGLES2) {
- vfmt->VertexAttrib1fARB = _es_VertexAttrib1f;
- vfmt->VertexAttrib1fvARB = _es_VertexAttrib1fv;
- vfmt->VertexAttrib2fARB = _es_VertexAttrib2f;
- vfmt->VertexAttrib2fvARB = _es_VertexAttrib2fv;
- vfmt->VertexAttrib3fARB = _es_VertexAttrib3f;
- vfmt->VertexAttrib3fvARB = _es_VertexAttrib3fv;
- vfmt->VertexAttrib4fARB = _es_VertexAttrib4f;
- vfmt->VertexAttrib4fvARB = _es_VertexAttrib4fv;
- } else {
- vfmt->VertexAttrib1fARB = vbo_VertexAttrib1fARB;
- vfmt->VertexAttrib1fvARB = vbo_VertexAttrib1fvARB;
- vfmt->VertexAttrib2fARB = vbo_VertexAttrib2fARB;
- vfmt->VertexAttrib2fvARB = vbo_VertexAttrib2fvARB;
- vfmt->VertexAttrib3fARB = vbo_VertexAttrib3fARB;
- vfmt->VertexAttrib3fvARB = vbo_VertexAttrib3fvARB;
- vfmt->VertexAttrib4fARB = vbo_VertexAttrib4fARB;
- vfmt->VertexAttrib4fvARB = vbo_VertexAttrib4fvARB;
- }
+#define NAME_AE(x) _ae_##x
+#define NAME_CALLLIST(x) _mesa_##x
+#define NAME(x) vbo_exec_##x
+#define NAME_ES(x) _es_##x
- /* Note that VertexAttrib4fNV is used from dlist.c and api_arrayelt.c so
- * they can have a single entrypoint for updating any of the legacy
- * attribs.
- */
- vfmt->VertexAttrib1fNV = vbo_VertexAttrib1fNV;
- vfmt->VertexAttrib1fvNV = vbo_VertexAttrib1fvNV;
- vfmt->VertexAttrib2fNV = vbo_VertexAttrib2fNV;
- vfmt->VertexAttrib2fvNV = vbo_VertexAttrib2fvNV;
- vfmt->VertexAttrib3fNV = vbo_VertexAttrib3fNV;
- vfmt->VertexAttrib3fvNV = vbo_VertexAttrib3fvNV;
- vfmt->VertexAttrib4fNV = vbo_VertexAttrib4fNV;
- vfmt->VertexAttrib4fvNV = vbo_VertexAttrib4fvNV;
-
- /* integer-valued */
- vfmt->VertexAttribI1i = vbo_VertexAttribI1i;
- vfmt->VertexAttribI2i = vbo_VertexAttribI2i;
- vfmt->VertexAttribI3i = vbo_VertexAttribI3i;
- vfmt->VertexAttribI4i = vbo_VertexAttribI4i;
- vfmt->VertexAttribI2iv = vbo_VertexAttribI2iv;
- vfmt->VertexAttribI3iv = vbo_VertexAttribI3iv;
- vfmt->VertexAttribI4iv = vbo_VertexAttribI4iv;
-
- /* unsigned integer-valued */
- vfmt->VertexAttribI1ui = vbo_VertexAttribI1ui;
- vfmt->VertexAttribI2ui = vbo_VertexAttribI2ui;
- vfmt->VertexAttribI3ui = vbo_VertexAttribI3ui;
- vfmt->VertexAttribI4ui = vbo_VertexAttribI4ui;
- vfmt->VertexAttribI2uiv = vbo_VertexAttribI2uiv;
- vfmt->VertexAttribI3uiv = vbo_VertexAttribI3uiv;
- vfmt->VertexAttribI4uiv = vbo_VertexAttribI4uiv;
-
- vfmt->Materialfv = vbo_Materialfv;
-
- vfmt->EdgeFlag = vbo_EdgeFlag;
- vfmt->Indexf = vbo_Indexf;
- vfmt->Indexfv = vbo_Indexfv;
-
- /* ARB_vertex_type_2_10_10_10_rev */
- vfmt->VertexP2ui = vbo_VertexP2ui;
- vfmt->VertexP2uiv = vbo_VertexP2uiv;
- vfmt->VertexP3ui = vbo_VertexP3ui;
- vfmt->VertexP3uiv = vbo_VertexP3uiv;
- vfmt->VertexP4ui = vbo_VertexP4ui;
- vfmt->VertexP4uiv = vbo_VertexP4uiv;
-
- vfmt->TexCoordP1ui = vbo_TexCoordP1ui;
- vfmt->TexCoordP1uiv = vbo_TexCoordP1uiv;
- vfmt->TexCoordP2ui = vbo_TexCoordP2ui;
- vfmt->TexCoordP2uiv = vbo_TexCoordP2uiv;
- vfmt->TexCoordP3ui = vbo_TexCoordP3ui;
- vfmt->TexCoordP3uiv = vbo_TexCoordP3uiv;
- vfmt->TexCoordP4ui = vbo_TexCoordP4ui;
- vfmt->TexCoordP4uiv = vbo_TexCoordP4uiv;
-
- vfmt->MultiTexCoordP1ui = vbo_MultiTexCoordP1ui;
- vfmt->MultiTexCoordP1uiv = vbo_MultiTexCoordP1uiv;
- vfmt->MultiTexCoordP2ui = vbo_MultiTexCoordP2ui;
- vfmt->MultiTexCoordP2uiv = vbo_MultiTexCoordP2uiv;
- vfmt->MultiTexCoordP3ui = vbo_MultiTexCoordP3ui;
- vfmt->MultiTexCoordP3uiv = vbo_MultiTexCoordP3uiv;
- vfmt->MultiTexCoordP4ui = vbo_MultiTexCoordP4ui;
- vfmt->MultiTexCoordP4uiv = vbo_MultiTexCoordP4uiv;
-
- vfmt->NormalP3ui = vbo_NormalP3ui;
- vfmt->NormalP3uiv = vbo_NormalP3uiv;
-
- vfmt->ColorP3ui = vbo_ColorP3ui;
- vfmt->ColorP3uiv = vbo_ColorP3uiv;
- vfmt->ColorP4ui = vbo_ColorP4ui;
- vfmt->ColorP4uiv = vbo_ColorP4uiv;
-
- vfmt->SecondaryColorP3ui = vbo_SecondaryColorP3ui;
- vfmt->SecondaryColorP3uiv = vbo_SecondaryColorP3uiv;
-
- vfmt->VertexAttribP1ui = vbo_VertexAttribP1ui;
- vfmt->VertexAttribP1uiv = vbo_VertexAttribP1uiv;
- vfmt->VertexAttribP2ui = vbo_VertexAttribP2ui;
- vfmt->VertexAttribP2uiv = vbo_VertexAttribP2uiv;
- vfmt->VertexAttribP3ui = vbo_VertexAttribP3ui;
- vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv;
- vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui;
- vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv;
-
- vfmt->VertexAttribL1d = vbo_VertexAttribL1d;
- vfmt->VertexAttribL2d = vbo_VertexAttribL2d;
- vfmt->VertexAttribL3d = vbo_VertexAttribL3d;
- vfmt->VertexAttribL4d = vbo_VertexAttribL4d;
-
- vfmt->VertexAttribL1dv = vbo_VertexAttribL1dv;
- vfmt->VertexAttribL2dv = vbo_VertexAttribL2dv;
- vfmt->VertexAttribL3dv = vbo_VertexAttribL3dv;
- vfmt->VertexAttribL4dv = vbo_VertexAttribL4dv;
-
- vfmt->VertexAttribL1ui64ARB = vbo_VertexAttribL1ui64ARB;
- vfmt->VertexAttribL1ui64vARB = vbo_VertexAttribL1ui64vARB;
+#include "vbo_init_tmp.h"
}
-/**
- * Tell the VBO module to use a real OpenGL vertex buffer object to
- * store accumulated immediate-mode vertex data.
- * This replaces the malloced buffer which was created in
- * vb_exec_vtx_init() below.
- */
-void
-vbo_use_buffer_objects(struct gl_context *ctx)
+static void
+vbo_reset_all_attr(struct vbo_exec_context *exec)
{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- /* Any buffer name but 0 can be used here since this bufferobj won't
- * go into the bufferobj hashtable.
- */
- GLuint bufName = IMM_BUFFER_NAME;
- GLenum target = GL_ARRAY_BUFFER_ARB;
- GLenum usage = GL_STREAM_DRAW_ARB;
- GLsizei size = VBO_VERT_BUFFER_SIZE;
-
- /* Make sure this func is only used once */
- assert(exec->vtx.bufferobj == ctx->Shared->NullBufferObj);
-
- _mesa_align_free(exec->vtx.buffer_map);
- exec->vtx.buffer_map = NULL;
- exec->vtx.buffer_ptr = NULL;
+ while (exec->vtx.enabled) {
+ const int i = u_bit_scan64(&exec->vtx.enabled);
- /* Allocate a real buffer object now */
- _mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
- exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName);
- if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage,
- GL_MAP_WRITE_BIT |
- GL_DYNAMIC_STORAGE_BIT |
- GL_CLIENT_STORAGE_BIT,
- exec->vtx.bufferobj)) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
+ /* Reset the vertex attribute by setting its size to zero. */
+ exec->vtx.attr[i].size = 0;
+ exec->vtx.attr[i].type = GL_FLOAT;
+ exec->vtx.attr[i].active_size = 0;
+ exec->vtx.attrptr[i] = NULL;
}
-}
-
-/**
- * If this function is called, all VBO buffers will be unmapped when
- * we flush.
- * Otherwise, if a simple command like glColor3f() is called and we flush,
- * the current VBO may be left mapped.
- */
-void
-vbo_always_unmap_buffers(struct gl_context *ctx)
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- exec->begin_vertices_flags |= FLUSH_STORED_VERTICES;
+ exec->vtx.vertex_size = 0;
}
void
-vbo_exec_vtx_init(struct vbo_exec_context *exec)
+vbo_exec_vtx_init(struct vbo_exec_context *exec, bool use_buffer_objects)
{
struct gl_context *ctx = exec->ctx;
- struct vbo_context *vbo = vbo_context(ctx);
- GLuint i;
-
- /* Allocate a buffer object. Will just reuse this object
- * continuously, unless vbo_use_buffer_objects() is called to enable
- * use of real VBOs.
- */
- _mesa_reference_buffer_object(ctx,
- &exec->vtx.bufferobj,
- ctx->Shared->NullBufferObj);
- assert(!exec->vtx.buffer_map);
- exec->vtx.buffer_map = _mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
- exec->vtx.buffer_ptr = exec->vtx.buffer_map;
+ if (use_buffer_objects) {
+ /* Use buffer objects for immediate mode. */
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- vbo_exec_vtxfmt_init(exec);
- _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
-
- exec->vtx.enabled = 0;
- for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
- assert(i < ARRAY_SIZE(exec->vtx.attrsz));
- exec->vtx.attrsz[i] = 0;
- assert(i < ARRAY_SIZE(exec->vtx.attrtype));
- exec->vtx.attrtype[i] = GL_FLOAT;
- assert(i < ARRAY_SIZE(exec->vtx.active_sz));
- exec->vtx.active_sz[i] = 0;
- }
- for (i = 0 ; i < VERT_ATTRIB_MAX; i++) {
- assert(i < ARRAY_SIZE(exec->vtx.inputs));
- assert(i < ARRAY_SIZE(exec->vtx.arrays));
- exec->vtx.inputs[i] = &exec->vtx.arrays[i];
- }
+ exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, IMM_BUFFER_NAME);
- {
- struct gl_vertex_array *arrays = exec->vtx.arrays;
- unsigned i;
-
- memcpy(arrays, &vbo->currval[VBO_ATTRIB_POS],
- VERT_ATTRIB_FF_MAX * sizeof(arrays[0]));
- for (i = 0; i < VERT_ATTRIB_FF_MAX; ++i) {
- struct gl_vertex_array *array;
- array = &arrays[VERT_ATTRIB_FF(i)];
- array->BufferObj = NULL;
- _mesa_reference_buffer_object(ctx, &array->BufferObj,
- vbo->currval[VBO_ATTRIB_POS+i].BufferObj);
- }
-
- memcpy(arrays + VERT_ATTRIB_GENERIC(0),
- &vbo->currval[VBO_ATTRIB_GENERIC0],
- VERT_ATTRIB_GENERIC_MAX * sizeof(arrays[0]));
-
- for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) {
- struct gl_vertex_array *array;
- array = &arrays[VERT_ATTRIB_GENERIC(i)];
- array->BufferObj = NULL;
- _mesa_reference_buffer_object(ctx, &array->BufferObj,
- vbo->currval[VBO_ATTRIB_GENERIC0+i].BufferObj);
- }
+ /* Map the buffer. */
+ vbo_exec_vtx_map(exec);
+ assert(exec->vtx.buffer_ptr);
+ } else {
+ /* Use allocated memory for immediate mode. */
+ exec->vtx.bufferobj = NULL;
+ exec->vtx.buffer_map =
+ align_malloc(ctx->Const.glBeginEndBufferSize, 64);
+ exec->vtx.buffer_ptr = exec->vtx.buffer_map;
}
- exec->vtx.vertex_size = 0;
+ vbo_exec_vtxfmt_init(exec);
+ _mesa_noop_vtxfmt_init(ctx, &exec->vtxfmt_noop);
- exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
+ exec->vtx.enabled = u_bit_consecutive64(0, VBO_ATTRIB_MAX); /* reset all */
+ vbo_reset_all_attr(exec);
}
{
/* using a real VBO for vertex data */
struct gl_context *ctx = exec->ctx;
- unsigned i;
/* True VBOs should already be unmapped
*/
if (exec->vtx.buffer_map) {
- assert(exec->vtx.bufferobj->Name == 0 ||
+ assert(!exec->vtx.bufferobj ||
exec->vtx.bufferobj->Name == IMM_BUFFER_NAME);
- if (exec->vtx.bufferobj->Name == 0) {
- _mesa_align_free(exec->vtx.buffer_map);
+ if (!exec->vtx.bufferobj) {
+ align_free(exec->vtx.buffer_map);
exec->vtx.buffer_map = NULL;
exec->vtx.buffer_ptr = NULL;
}
}
- /* Drop any outstanding reference to the vertex buffer
- */
- for (i = 0; i < ARRAY_SIZE(exec->vtx.arrays); i++) {
- _mesa_reference_buffer_object(ctx,
- &exec->vtx.arrays[i].BufferObj,
- NULL);
- }
-
/* Free the vertex buffer. Unmap first if needed.
*/
- if (_mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
+ if (exec->vtx.bufferobj &&
+ _mesa_bufferobj_mapped(exec->vtx.bufferobj, MAP_INTERNAL)) {
ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj, MAP_INTERNAL);
}
_mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
-#ifdef DEBUG
+#ifndef NDEBUG
/* debug check: make sure we don't get called recursively */
exec->flush_call_depth++;
assert(exec->flush_call_depth == 1);
if (_mesa_inside_begin_end(ctx)) {
/* We've had glBegin but not glEnd! */
-#ifdef DEBUG
+#ifndef NDEBUG
exec->flush_call_depth--;
assert(exec->flush_call_depth == 0);
#endif
return;
}
- /* Flush (draw), and make sure VBO is left unmapped when done */
- vbo_exec_FlushVertices_internal(exec, GL_TRUE);
-
- /* Need to do this to ensure vbo_exec_begin_vertices gets called again:
- */
- ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
+ /* Flush (draw). */
+ vbo_exec_FlushVertices_internal(exec, flags);
-#ifdef DEBUG
+#ifndef NDEBUG
exec->flush_call_depth--;
assert(exec->flush_call_depth == 0);
#endif
}
-/**
- * Reset the vertex attribute by setting its size to zero.
- */
-static void
-vbo_reset_attr(struct vbo_exec_context *exec, GLuint attr)
-{
- exec->vtx.attrsz[attr] = 0;
- exec->vtx.attrtype[attr] = GL_FLOAT;
- exec->vtx.active_sz[attr] = 0;
-}
-
-
-static void
-vbo_reset_all_attr(struct vbo_exec_context *exec)
-{
- while (exec->vtx.enabled) {
- const int i = u_bit_scan64(&exec->vtx.enabled);
- vbo_reset_attr(exec, i);
- }
-
- exec->vtx.vertex_size = 0;
-}
-
-
void GLAPIENTRY
_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
- vbo_Color4f(r, g, b, a);
+ vbo_exec_Color4f(r, g, b, a);
}
void GLAPIENTRY
_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
{
- vbo_Normal3f(x, y, z);
+ vbo_exec_Normal3f(x, y, z);
}
void GLAPIENTRY
_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
{
- vbo_MultiTexCoord4f(target, s, t, r, q);
+ vbo_exec_MultiTexCoord4f(target, s, t, r, q);
}
void GLAPIENTRY
_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
{
- vbo_Materialfv(face, pname, params);
+ vbo_exec_Materialfv(face, pname, params);
}
GLfloat p[4];
p[0] = param;
p[1] = p[2] = p[3] = 0.0F;
- vbo_Materialfv(face, pname, p);
+ vbo_exec_Materialfv(face, pname, p);
}