#include "main/bufferobj.h"
#include "main/context.h"
#include "main/macros.h"
+#include "main/mfeatures.h"
#include "main/vtxfmt.h"
#include "main/dlist.h"
#include "main/eval.h"
#include "main/state.h"
#include "main/light.h"
#include "main/api_arrayelt.h"
-#include "main/api_noop.h"
+#include "main/api_validate.h"
#include "main/dispatch.h"
#include "vbo_context.h"
+#include "vbo_noop.h"
+
#ifdef ERROR
#undef ERROR
*/
vbo_exec_wrap_buffers( exec );
+ if (!exec->vtx.buffer_ptr) {
+ /* probably ran out of memory earlier when allocating the VBO */
+ return;
+ }
+
/* Copy stored stored vertices to start of new list.
*/
assert(exec->vtx.max_vert - exec->vtx.vert_count > exec->vtx.copied.nr);
GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
GLfloat tmp[4];
- COPY_CLEAN_4V(tmp,
- exec->vtx.attrsz[i],
- exec->vtx.attrptr[i]);
+ COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp,
+ exec->vtx.attrsz[i],
+ exec->vtx.attrptr[i],
+ exec->vtx.attrtype[i]);
- if (memcmp(current, tmp, sizeof(tmp)) != 0)
- {
+ if (exec->vtx.attrtype[i] != vbo->currval[i].Type ||
+ memcmp(current, tmp, sizeof(tmp)) != 0) {
memcpy(current, tmp, sizeof(tmp));
/* Given that we explicitly state size here, there is no need
* directly.
*/
vbo->currval[i].Size = exec->vtx.attrsz[i];
+ vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat);
+ vbo->currval[i].Type = exec->vtx.attrtype[i];
+ vbo->currval[i].Integer =
+ vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]);
/* This triggers rather too much recalculation of Mesa state
* that doesn't get used (eg light positions).
}
-static void vbo_exec_copy_from_current( struct vbo_exec_context *exec )
+/**
+ * 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++) {
- const GLfloat *current = (GLfloat *)vbo->currval[i].Ptr;
+ for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) {
+ const GLfloat *current = (GLfloat *) 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];
/**
* Flush existing data, set new attrib size, replay copied vertices.
+ * This is called when we transition from a small vertex attribute size
+ * to a larger one. Ex: glTexCoord2f -> glTexCoord4f.
+ * We need to go back over the previous 2-component texcoords and insert
+ * zero and one values.
*/
-static void vbo_exec_wrap_upgrade_vertex( struct vbo_exec_context *exec,
- GLuint attr,
- GLuint newsz )
+static void
+vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec,
+ GLuint attr, GLuint newSize )
{
struct gl_context *ctx = exec->ctx;
struct vbo_context *vbo = vbo_context(ctx);
- GLint lastcount = exec->vtx.vert_count;
+ const GLint lastcount = exec->vtx.vert_count;
GLfloat *old_attrptr[VBO_ATTRIB_MAX];
- GLuint old_vtx_size = exec->vtx.vertex_size;
- GLuint oldsz = exec->vtx.attrsz[attr];
+ const GLuint old_vtx_size = exec->vtx.vertex_size; /* floats per vertex */
+ const GLuint oldSize = exec->vtx.attrsz[attr];
GLuint i;
/* Run pipeline on current vertices, copy wrapped vertices
memcpy(old_attrptr, exec->vtx.attrptr, sizeof(old_attrptr));
}
- if (unlikely(oldsz)) {
+ 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.
* begin/end so that they don't bloat the vertices.
*/
if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
- !oldsz && lastcount > 8 && exec->vtx.vertex_size) {
+ !oldSize && lastcount > 8 && exec->vtx.vertex_size) {
vbo_exec_copy_to_current( exec );
reset_attrfv( exec );
}
/* Fix up sizes:
*/
- exec->vtx.attrsz[attr] = newsz;
- exec->vtx.vertex_size += newsz - oldsz;
+ exec->vtx.attrsz[attr] = newSize;
+ exec->vtx.vertex_size += newSize - oldSize;
exec->vtx.max_vert = ((VBO_VERT_BUFFER_SIZE - exec->vtx.buffer_used) /
(exec->vtx.vertex_size * sizeof(GLfloat)));
exec->vtx.vert_count = 0;
exec->vtx.buffer_ptr = exec->vtx.buffer_map;
- if (unlikely(oldsz)) {
+ if (unlikely(oldSize)) {
/* Size changed, recalculate all the attrptr[] values
*/
GLfloat *tmp = exec->vtx.vertex;
* values.
*/
vbo_exec_copy_from_current( exec );
-
- } else {
+ }
+ else {
/* Just have to append the new attribute at the end */
exec->vtx.attrptr[attr] = exec->vtx.vertex +
- exec->vtx.vertex_size - newsz;
+ exec->vtx.vertex_size - newSize;
}
/* Replay stored vertices to translate them
GLint new_offset = exec->vtx.attrptr[j] - exec->vtx.vertex;
if (j == attr) {
- if (oldsz) {
+ if (oldSize) {
GLfloat tmp[4];
- COPY_CLEAN_4V(tmp, oldsz, data + old_offset);
- COPY_SZ_4V(dest + new_offset, newsz, tmp);
+ COPY_CLEAN_4V_TYPE_AS_FLOAT(tmp, oldSize,
+ data + old_offset,
+ exec->vtx.attrtype[j]);
+ COPY_SZ_4V(dest + new_offset, newSize, tmp);
} else {
GLfloat *current = (GLfloat *)vbo->currval[j].Ptr;
COPY_SZ_4V(dest + new_offset, sz, current);
}
-static void vbo_exec_fixup_vertex( struct gl_context *ctx,
- GLuint attr, GLuint sz )
+/**
+ * This is when a vertex attribute transitions to a different size.
+ * For example, we saw a bunch of glTexCoord2f() calls and now we got a
+ * glTexCoord4f() call. We promote the array from size=2 to size=4.
+ */
+static void
+vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize)
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- int i;
- if (sz > exec->vtx.attrsz[attr]) {
+ if (newSize > exec->vtx.attrsz[attr]) {
/* New size is larger. Need to flush existing vertices and get
* an enlarged vertex format.
*/
- vbo_exec_wrap_upgrade_vertex( exec, attr, sz );
+ vbo_exec_wrap_upgrade_vertex( exec, attr, newSize );
}
- else if (sz < exec->vtx.active_sz[attr]) {
- static const GLfloat id[4] = { 0, 0, 0, 1 };
+ else if (newSize < exec->vtx.active_sz[attr]) {
+ GLuint i;
+ const GLfloat *id =
+ vbo_get_default_vals_as_float(exec->vtx.attrtype[attr]);
/* New size is smaller - just need to fill in some
* zeros. Don't need to flush or wrap.
*/
- for (i = sz ; i <= exec->vtx.attrsz[attr] ; i++)
+ for (i = newSize; i <= exec->vtx.attrsz[attr]; i++)
exec->vtx.attrptr[attr][i-1] = id[i-1];
}
- exec->vtx.active_sz[attr] = sz;
+ exec->vtx.active_sz[attr] = newSize;
/* Does setting NeedFlush belong here? Necessitates resetting
* vtxfmt on each flush (otherwise flags won't get reset
* afterwards).
*/
if (attr == 0)
- exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
+ ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
}
-/*
+/**
+ * This macro is used to implement all the glVertex, glColor, glTexCoord,
+ * glVertexAttrib, etc functions.
*/
-#define ATTR( A, N, V0, V1, V2, V3 ) \
-do { \
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
+#define ATTR( A, N, T, V0, V1, V2, V3 ) \
+do { \
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \
\
- if (unlikely(!(exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
- ctx->Driver.BeginVertices( ctx ); \
+ if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \
+ ctx->Driver.BeginVertices( ctx ); \
+ \
if (unlikely(exec->vtx.active_sz[A] != N)) \
vbo_exec_fixup_vertex(ctx, A, N); \
\
- { \
- GLfloat *dest = 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; \
- } \
- \
- if ((A) == 0) { \
- GLuint i; \
- \
- for (i = 0; i < exec->vtx.vertex_size; i++) \
- exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
- \
+ { \
+ GLfloat *dest = 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; \
+ exec->vtx.attrtype[A] = T; \
+ } \
+ \
+ if ((A) == 0) { \
+ /* This is a glVertex call */ \
+ GLuint i; \
+ \
+ for (i = 0; i < exec->vtx.vertex_size; i++) \
+ exec->vtx.buffer_ptr[i] = exec->vtx.vertex[i]; \
+ \
exec->vtx.buffer_ptr += exec->vtx.vertex_size; \
- exec->ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; \
- \
- if (++exec->vtx.vert_count >= exec->vtx.max_vert) \
- vbo_exec_vtx_wrap( exec ); \
- } \
+ \
+ /* 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 (++exec->vtx.vert_count >= exec->vtx.max_vert) \
+ vbo_exec_vtx_wrap( exec ); \
+ } \
} while (0)
-#define ERROR() _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ )
+#define ERROR(err) _mesa_error( ctx, err, __FUNCTION__ )
#define TAG(x) vbo_##x
#include "vbo_attrib_tmp.h"
-#if FEATURE_beginend
+/**
+ * Execute a glMaterial call. Note that if GL_COLOR_MATERIAL is enabled,
+ * this may be a (partial) no-op.
+ */
+static void GLAPIENTRY
+vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+{
+ GLbitfield updateMats;
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* This function should be a no-op when it tries to update material
+ * attributes which are currently tracking glColor via glColorMaterial.
+ * The updateMats var will be a mask of the MAT_BIT_FRONT/BACK_x bits
+ * indicating which material attributes can actually be updated below.
+ */
+ if (ctx->Light.ColorMaterialEnabled) {
+ updateMats = ~ctx->Light._ColorMaterialBitmask;
+ }
+ else {
+ /* GL_COLOR_MATERIAL is disabled so don't skip any material updates */
+ updateMats = ALL_MATERIAL_BITS;
+ }
+
+ if (ctx->API == API_OPENGL_COMPAT && face == GL_FRONT) {
+ updateMats &= FRONT_MATERIAL_BITS;
+ }
+ else if (ctx->API == API_OPENGL_COMPAT && face == GL_BACK) {
+ updateMats &= BACK_MATERIAL_BITS;
+ }
+ else if (face != GL_FRONT_AND_BACK) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glMaterial(invalid face)");
+ return;
+ }
+
+ switch (pname) {
+ case GL_EMISSION:
+ if (updateMats & MAT_BIT_FRONT_EMISSION)
+ MAT_ATTR(VBO_ATTRIB_MAT_FRONT_EMISSION, 4, params);
+ if (updateMats & MAT_BIT_BACK_EMISSION)
+ MAT_ATTR(VBO_ATTRIB_MAT_BACK_EMISSION, 4, params);
+ break;
+ case GL_AMBIENT:
+ if (updateMats & MAT_BIT_FRONT_AMBIENT)
+ MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
+ if (updateMats & MAT_BIT_BACK_AMBIENT)
+ MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
+ break;
+ case GL_DIFFUSE:
+ if (updateMats & MAT_BIT_FRONT_DIFFUSE)
+ MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
+ if (updateMats & MAT_BIT_BACK_DIFFUSE)
+ MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
+ break;
+ case GL_SPECULAR:
+ if (updateMats & MAT_BIT_FRONT_SPECULAR)
+ MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SPECULAR, 4, params);
+ if (updateMats & MAT_BIT_BACK_SPECULAR)
+ MAT_ATTR(VBO_ATTRIB_MAT_BACK_SPECULAR, 4, params);
+ break;
+ case GL_SHININESS:
+ if (*params < 0 || *params > ctx->Const.MaxShininess) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glMaterial(invalid shininess: %f out range [0, %f])",
+ *params, ctx->Const.MaxShininess);
+ return;
+ }
+ if (updateMats & MAT_BIT_FRONT_SHININESS)
+ MAT_ATTR(VBO_ATTRIB_MAT_FRONT_SHININESS, 1, params);
+ if (updateMats & MAT_BIT_BACK_SHININESS)
+ MAT_ATTR(VBO_ATTRIB_MAT_BACK_SHININESS, 1, params);
+ break;
+ case GL_COLOR_INDEXES:
+ if (ctx->API != API_OPENGL_COMPAT) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
+ return;
+ }
+ if (updateMats & MAT_BIT_FRONT_INDEXES)
+ MAT_ATTR(VBO_ATTRIB_MAT_FRONT_INDEXES, 3, params);
+ if (updateMats & MAT_BIT_BACK_INDEXES)
+ MAT_ATTR(VBO_ATTRIB_MAT_BACK_INDEXES, 3, params);
+ break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ if (updateMats & MAT_BIT_FRONT_AMBIENT)
+ MAT_ATTR(VBO_ATTRIB_MAT_FRONT_AMBIENT, 4, params);
+ if (updateMats & MAT_BIT_FRONT_DIFFUSE)
+ MAT_ATTR(VBO_ATTRIB_MAT_FRONT_DIFFUSE, 4, params);
+ if (updateMats & MAT_BIT_BACK_AMBIENT)
+ MAT_ATTR(VBO_ATTRIB_MAT_BACK_AMBIENT, 4, params);
+ if (updateMats & MAT_BIT_BACK_DIFFUSE)
+ MAT_ATTR(VBO_ATTRIB_MAT_BACK_DIFFUSE, 4, params);
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glMaterialfv(pname)");
+ return;
+ }
+}
+
+
+/**
+ * Flush (draw) vertices.
+ * \param unmap - leave VBO unmapped after flushing?
+ */
+static void
+vbo_exec_FlushVertices_internal(struct vbo_exec_context *exec, GLboolean unmap)
+{
+ if (exec->vtx.vert_count || unmap) {
+ vbo_exec_vtx_flush( exec, unmap );
+ }
+
+ if (exec->vtx.vertex_size) {
+ vbo_exec_copy_to_current( exec );
+ reset_attrfv( exec );
+ }
+}
-#if FEATURE_evaluators
static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u )
{
vbo_exec_EvalCoord2f( u, v );
}
-/* use noop eval mesh */
-#define vbo_exec_EvalMesh1 _mesa_noop_EvalMesh1
-#define vbo_exec_EvalMesh2 _mesa_noop_EvalMesh2
-#endif /* FEATURE_evaluators */
+static void GLAPIENTRY
+vbo_exec_EvalMesh1(GLenum mode, GLint i1, GLint i2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+ GLfloat u, du;
+ GLenum prim;
+
+ switch (mode) {
+ case GL_POINT:
+ prim = GL_POINTS;
+ break;
+ case GL_LINE:
+ prim = GL_LINE_STRIP;
+ break;
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh1(mode)" );
+ return;
+ }
+
+ /* No effect if vertex maps disabled.
+ */
+ if (!ctx->Eval.Map1Vertex4 &&
+ !ctx->Eval.Map1Vertex3)
+ return;
+
+ du = ctx->Eval.MapGrid1du;
+ u = ctx->Eval.MapGrid1u1 + i1 * du;
+
+ CALL_Begin(GET_DISPATCH(), (prim));
+ for (i=i1;i<=i2;i++,u+=du) {
+ CALL_EvalCoord1f(GET_DISPATCH(), (u));
+ }
+ CALL_End(GET_DISPATCH(), ());
+}
+
+
+static void GLAPIENTRY
+vbo_exec_EvalMesh2(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLfloat u, du, v, dv, v1, u1;
+ GLint i, j;
+
+ switch (mode) {
+ case GL_POINT:
+ case GL_LINE:
+ case GL_FILL:
+ break;
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glEvalMesh2(mode)" );
+ return;
+ }
+
+ /* No effect if vertex maps disabled.
+ */
+ if (!ctx->Eval.Map2Vertex4 &&
+ !ctx->Eval.Map2Vertex3)
+ return;
+
+ du = ctx->Eval.MapGrid2du;
+ dv = ctx->Eval.MapGrid2dv;
+ v1 = ctx->Eval.MapGrid2v1 + j1 * dv;
+ u1 = ctx->Eval.MapGrid2u1 + i1 * du;
+
+ switch (mode) {
+ case GL_POINT:
+ CALL_Begin(GET_DISPATCH(), (GL_POINTS));
+ for (v=v1,j=j1;j<=j2;j++,v+=dv) {
+ for (u=u1,i=i1;i<=i2;i++,u+=du) {
+ CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
+ }
+ }
+ CALL_End(GET_DISPATCH(), ());
+ break;
+ case GL_LINE:
+ for (v=v1,j=j1;j<=j2;j++,v+=dv) {
+ CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
+ for (u=u1,i=i1;i<=i2;i++,u+=du) {
+ CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
+ }
+ CALL_End(GET_DISPATCH(), ());
+ }
+ for (u=u1,i=i1;i<=i2;i++,u+=du) {
+ CALL_Begin(GET_DISPATCH(), (GL_LINE_STRIP));
+ for (v=v1,j=j1;j<=j2;j++,v+=dv) {
+ CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
+ }
+ CALL_End(GET_DISPATCH(), ());
+ }
+ break;
+ case GL_FILL:
+ for (v=v1,j=j1;j<j2;j++,v+=dv) {
+ CALL_Begin(GET_DISPATCH(), (GL_TRIANGLE_STRIP));
+ for (u=u1,i=i1;i<=i2;i++,u+=du) {
+ CALL_EvalCoord2f(GET_DISPATCH(), (u, v));
+ CALL_EvalCoord2f(GET_DISPATCH(), (u, v+dv));
+ }
+ CALL_End(GET_DISPATCH(), ());
+ }
+ break;
+ }
+}
+
+
+/**
+ * Execute a glRectf() function. This is not suitable for GL_COMPILE
+ * modes (as the test for outside begin/end is not compiled),
+ * but may be useful for drivers in circumstances which exclude
+ * display list interactions.
+ *
+ * (None of the functions in this file are suitable for GL_COMPILE
+ * modes).
+ */
+static void GLAPIENTRY
+vbo_exec_Rectf(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2)
+{
+ CALL_Begin(GET_DISPATCH(), (GL_QUADS));
+ CALL_Vertex2f(GET_DISPATCH(), (x1, y1));
+ CALL_Vertex2f(GET_DISPATCH(), (x2, y1));
+ CALL_Vertex2f(GET_DISPATCH(), (x2, y2));
+ CALL_Vertex2f(GET_DISPATCH(), (x1, y2));
+ CALL_End(GET_DISPATCH(), ());
+}
/**
static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
{
GET_CURRENT_CONTEXT( ctx );
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ int i;
- if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- int i;
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBegin");
+ return;
+ }
- if (ctx->NewState) {
- _mesa_update_state( ctx );
+ if (!_mesa_valid_prim_mode(ctx, mode, "glBegin")) {
+ return;
+ }
- CALL_Begin(ctx->Exec, (mode));
- return;
- }
+ vbo_draw_method(vbo_context(ctx), DRAW_BEGIN_END);
- if (!_mesa_valid_to_render(ctx, "glBegin")) {
- return;
- }
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
- /* Heuristic: attempt to isolate attributes occuring outside
- * begin/end pairs.
- */
- if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
- vbo_exec_FlushVertices_internal( ctx, GL_FALSE );
-
- 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;
-
- ctx->Driver.CurrentExecPrimitive = mode;
+ CALL_Begin(ctx->Exec, (mode));
+ return;
+ }
+
+ if (!_mesa_valid_to_render(ctx, "glBegin")) {
+ return;
+ }
+
+ /* Heuristic: attempt to isolate attributes occuring outside
+ * begin/end pairs.
+ */
+ if (exec->vtx.vertex_size && !exec->vtx.attrsz[0])
+ vbo_exec_FlushVertices_internal(exec, GL_FALSE);
+
+ 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;
+
+ 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->CurrentDispatch == ctx->OutsideBeginEnd) {
+ ctx->CurrentDispatch = ctx->BeginEnd;
+ _glapi_set_dispatch(ctx->CurrentDispatch);
+ } else {
+ assert(ctx->CurrentDispatch == ctx->Save);
}
- else
- _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
-
}
static void GLAPIENTRY vbo_exec_End( void )
{
GET_CURRENT_CONTEXT( ctx );
+ struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glEnd");
+ return;
+ }
+
+ ctx->Exec = ctx->OutsideBeginEnd;
+ if (ctx->CurrentDispatch == ctx->BeginEnd) {
+ ctx->CurrentDispatch = ctx->OutsideBeginEnd;
+ _glapi_set_dispatch(ctx->CurrentDispatch);
+ }
+
+ if (exec->vtx.prim_count > 0) {
+ /* close off current primitive */
int idx = exec->vtx.vert_count;
int i = exec->vtx.prim_count - 1;
- exec->vtx.prim[i].end = 1;
+ exec->vtx.prim[i].end = 1;
exec->vtx.prim[i].count = idx - exec->vtx.prim[i].start;
+ }
- ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
- if (exec->vtx.prim_count == VBO_MAX_PRIM)
- vbo_exec_vtx_flush( exec, GL_FALSE );
+ if (exec->vtx.prim_count == VBO_MAX_PRIM)
+ vbo_exec_vtx_flush( exec, GL_FALSE );
+
+ if (MESA_DEBUG_FLAGS & DEBUG_ALWAYS_FLUSH) {
+ _mesa_flush(ctx);
}
- else
- _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
}
static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
{
+ struct gl_context *ctx = exec->ctx;
GLvertexformat *vfmt = &exec->vtxfmt;
_MESA_INIT_ARRAYELT_VTXFMT(vfmt, _ae_);
_MESA_INIT_DLIST_VTXFMT(vfmt, _mesa_);
_MESA_INIT_EVAL_VTXFMT(vfmt, vbo_exec_);
- vfmt->Rectf = _mesa_noop_Rectf;
+ vfmt->Rectf = vbo_exec_Rectf;
/* from attrib_tmp.h:
*/
vfmt->Vertex4f = vbo_Vertex4f;
vfmt->Vertex4fv = vbo_Vertex4fv;
- 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;
+ 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;
+ }
+ /* 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->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;
}
-#else /* FEATURE_beginend */
-
-
-static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec )
-{
- /* silence warnings */
- (void) vbo_Color3f;
- (void) vbo_Color3fv;
- (void) vbo_Color4f;
- (void) vbo_Color4fv;
- (void) vbo_FogCoordfEXT;
- (void) vbo_FogCoordfvEXT;
- (void) vbo_MultiTexCoord1f;
- (void) vbo_MultiTexCoord1fv;
- (void) vbo_MultiTexCoord2f;
- (void) vbo_MultiTexCoord2fv;
- (void) vbo_MultiTexCoord3f;
- (void) vbo_MultiTexCoord3fv;
- (void) vbo_MultiTexCoord4f;
- (void) vbo_MultiTexCoord4fv;
- (void) vbo_Normal3f;
- (void) vbo_Normal3fv;
- (void) vbo_SecondaryColor3fEXT;
- (void) vbo_SecondaryColor3fvEXT;
- (void) vbo_TexCoord1f;
- (void) vbo_TexCoord1fv;
- (void) vbo_TexCoord2f;
- (void) vbo_TexCoord2fv;
- (void) vbo_TexCoord3f;
- (void) vbo_TexCoord3fv;
- (void) vbo_TexCoord4f;
- (void) vbo_TexCoord4fv;
- (void) vbo_Vertex2f;
- (void) vbo_Vertex2fv;
- (void) vbo_Vertex3f;
- (void) vbo_Vertex3fv;
- (void) vbo_Vertex4f;
- (void) vbo_Vertex4fv;
-
- (void) vbo_VertexAttrib1fARB;
- (void) vbo_VertexAttrib1fvARB;
- (void) vbo_VertexAttrib2fARB;
- (void) vbo_VertexAttrib2fvARB;
- (void) vbo_VertexAttrib3fARB;
- (void) vbo_VertexAttrib3fvARB;
- (void) vbo_VertexAttrib4fARB;
- (void) vbo_VertexAttrib4fvARB;
-
- (void) vbo_VertexAttrib1fNV;
- (void) vbo_VertexAttrib1fvNV;
- (void) vbo_VertexAttrib2fNV;
- (void) vbo_VertexAttrib2fvNV;
- (void) vbo_VertexAttrib3fNV;
- (void) vbo_VertexAttrib3fvNV;
- (void) vbo_VertexAttrib4fNV;
- (void) vbo_VertexAttrib4fvNV;
-
- (void) vbo_Materialfv;
-
- (void) vbo_EdgeFlag;
- (void) vbo_Indexf;
- (void) vbo_Indexfv;
-}
-
-
-#endif /* FEATURE_beginend */
-
-
/**
* Tell the VBO module to use a real OpenGL vertex buffer object to
* store accumulated immediate-mode vertex data.
/* Allocate a real buffer object now */
_mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
exec->vtx.bufferobj = ctx->Driver.NewBufferObject(ctx, bufName, target);
- ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj);
+ if (!ctx->Driver.BufferData(ctx, target, size, NULL, usage, exec->vtx.bufferobj)) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "VBO allocation");
+ }
}
+/**
+ * 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;
+}
+
void vbo_exec_vtx_init( struct vbo_exec_context *exec )
{
ctx->Shared->NullBufferObj);
ASSERT(!exec->vtx.buffer_map);
- exec->vtx.buffer_map = (GLfloat *)_mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
+ exec->vtx.buffer_map = _mesa_align_malloc(VBO_VERT_BUFFER_SIZE, 64);
exec->vtx.buffer_ptr = exec->vtx.buffer_map;
vbo_exec_vtxfmt_init( exec );
-
- /* Hook our functions into the dispatch table.
- */
- _mesa_install_exec_vtxfmt( exec->ctx, &exec->vtxfmt );
+ _mesa_noop_vtxfmt_init(&exec->vtxfmt_noop);
for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
ASSERT(i < Elements(exec->vtx.attrsz));
exec->vtx.attrsz[i] = 0;
+ ASSERT(i < Elements(exec->vtx.attrtype));
+ exec->vtx.attrtype[i] = GL_FLOAT;
ASSERT(i < Elements(exec->vtx.active_sz));
exec->vtx.active_sz[i] = 0;
}
struct gl_client_array *arrays = exec->vtx.arrays;
unsigned i;
- memcpy(arrays, vbo->legacy_currval, 16 * sizeof(arrays[0]));
- memcpy(arrays + 16, vbo->generic_currval, 16 * sizeof(arrays[0]));
+ 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_client_array *array;
+ array = &arrays[VERT_ATTRIB_FF(i)];
+ array->BufferObj = NULL;
+ _mesa_reference_buffer_object(ctx, &arrays->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 < 16; ++i) {
- arrays[i ].BufferObj = NULL;
- arrays[i + 16].BufferObj = NULL;
- _mesa_reference_buffer_object(ctx, &arrays[i ].BufferObj,
- vbo->legacy_currval[i].BufferObj);
- _mesa_reference_buffer_object(ctx, &arrays[i + 16].BufferObj,
- vbo->generic_currval[i].BufferObj);
+ for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; ++i) {
+ struct gl_client_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);
}
}
exec->vtx.vertex_size = 0;
+
+ exec->begin_vertices_flags = FLUSH_UPDATE_CURRENT;
}
/* Free the vertex buffer. Unmap first if needed.
*/
if (_mesa_bufferobj_mapped(exec->vtx.bufferobj)) {
- ctx->Driver.UnmapBuffer(ctx, GL_ARRAY_BUFFER, exec->vtx.bufferobj);
+ ctx->Driver.UnmapBuffer(ctx, exec->vtx.bufferobj);
}
_mesa_reference_buffer_object(ctx, &exec->vtx.bufferobj, NULL);
}
+
+/**
+ * Called upon first glVertex, glColor, glTexCoord, etc.
+ */
void vbo_exec_BeginVertices( struct gl_context *ctx )
{
struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
- if (0) printf("%s\n", __FUNCTION__);
- vbo_exec_vtx_map( exec );
-
- assert((exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
- exec->ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
-}
-void vbo_exec_FlushVertices_internal( struct gl_context *ctx, GLboolean unmap )
-{
- struct vbo_exec_context *exec = &vbo_context(ctx)->exec;
+ vbo_exec_vtx_map( exec );
- if (exec->vtx.vert_count || unmap) {
- vbo_exec_vtx_flush( exec, unmap );
- }
+ assert((ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) == 0);
+ assert(exec->begin_vertices_flags);
- if (exec->vtx.vertex_size) {
- vbo_exec_copy_to_current( exec );
- reset_attrfv( exec );
- }
+ ctx->Driver.NeedFlush |= exec->begin_vertices_flags;
}
/**
+ * Called via ctx->Driver.FlushVertices()
* \param flags bitmask of FLUSH_STORED_VERTICES, FLUSH_UPDATE_CURRENT
*/
void vbo_exec_FlushVertices( struct gl_context *ctx, GLuint flags )
assert(exec->flush_call_depth == 1);
#endif
- if (0) printf("%s\n", __FUNCTION__);
-
- if (exec->ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
- if (0) printf("%s - inside begin/end\n", __FUNCTION__);
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END) {
+ /* We've had glBegin but not glEnd! */
#ifdef DEBUG
exec->flush_call_depth--;
assert(exec->flush_call_depth == 0);
return;
}
- vbo_exec_FlushVertices_internal( ctx, GL_TRUE );
+ /* Flush (draw), and make sure VBO is left unmapped when done */
+ vbo_exec_FlushVertices_internal(exec, GL_TRUE);
/* Need to do this to ensure BeginVertices gets called again:
*/
- if (exec->ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT)
- exec->ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
-
- exec->ctx->Driver.NeedFlush &= ~flags;
+ ctx->Driver.NeedFlush &= ~(FLUSH_UPDATE_CURRENT | flags);
#ifdef DEBUG
exec->flush_call_depth--;
for (i = 0 ; i < VBO_ATTRIB_MAX ; i++) {
exec->vtx.attrsz[i] = 0;
+ exec->vtx.attrtype[i] = GL_FLOAT;
exec->vtx.active_sz[i] = 0;
}
void GLAPIENTRY
-_vbo_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
+_es_Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
{
vbo_Color4f(r, g, b, a);
}
void GLAPIENTRY
-_vbo_Normal3f(GLfloat x, GLfloat y, GLfloat z)
+_es_Normal3f(GLfloat x, GLfloat y, GLfloat z)
{
vbo_Normal3f(x, y, z);
}
void GLAPIENTRY
-_vbo_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+_es_MultiTexCoord4f(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
{
vbo_MultiTexCoord4f(target, s, t, r, q);
}
void GLAPIENTRY
-_vbo_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
+_es_Materialfv(GLenum face, GLenum pname, const GLfloat *params)
{
vbo_Materialfv(face, pname, params);
}
void GLAPIENTRY
-_vbo_Materialf(GLenum face, GLenum pname, GLfloat param)
+_es_Materialf(GLenum face, GLenum pname, GLfloat param)
{
GLfloat p[4];
p[0] = param;
}
+/**
+ * A special version of glVertexAttrib4f that does not treat index 0 as
+ * VBO_ATTRIB_POS.
+ */
+static void
+VertexAttrib4f_nopos(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (index < MAX_VERTEX_GENERIC_ATTRIBS)
+ ATTR(VBO_ATTRIB_GENERIC0 + index, 4, GL_FLOAT, x, y, z, w);
+ else
+ ERROR(GL_INVALID_VALUE);
+}
+
void GLAPIENTRY
-_vbo_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+_es_VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
- vbo_VertexAttrib4fARB(index, x, y, z, w);
+ VertexAttrib4f_nopos(index, x, y, z, w);
}
void GLAPIENTRY
-_vbo_VertexAttrib1f(GLuint indx, GLfloat x)
+_es_VertexAttrib1f(GLuint indx, GLfloat x)
{
- vbo_VertexAttrib1fARB(indx, x);
+ VertexAttrib4f_nopos(indx, x, 0.0f, 0.0f, 1.0f);
}
void GLAPIENTRY
-_vbo_VertexAttrib1fv(GLuint indx, const GLfloat* values)
+_es_VertexAttrib1fv(GLuint indx, const GLfloat* values)
{
- vbo_VertexAttrib1fvARB(indx, values);
+ VertexAttrib4f_nopos(indx, values[0], 0.0f, 0.0f, 1.0f);
}
void GLAPIENTRY
-_vbo_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+_es_VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
{
- vbo_VertexAttrib2fARB(indx, x, y);
+ VertexAttrib4f_nopos(indx, x, y, 0.0f, 1.0f);
}
void GLAPIENTRY
-_vbo_VertexAttrib2fv(GLuint indx, const GLfloat* values)
+_es_VertexAttrib2fv(GLuint indx, const GLfloat* values)
{
- vbo_VertexAttrib2fvARB(indx, values);
+ VertexAttrib4f_nopos(indx, values[0], values[1], 0.0f, 1.0f);
}
void GLAPIENTRY
-_vbo_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+_es_VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
{
- vbo_VertexAttrib3fARB(indx, x, y, z);
+ VertexAttrib4f_nopos(indx, x, y, z, 1.0f);
}
void GLAPIENTRY
-_vbo_VertexAttrib3fv(GLuint indx, const GLfloat* values)
+_es_VertexAttrib3fv(GLuint indx, const GLfloat* values)
{
- vbo_VertexAttrib3fvARB(indx, values);
+ VertexAttrib4f_nopos(indx, values[0], values[1], values[2], 1.0f);
}
void GLAPIENTRY
-_vbo_VertexAttrib4fv(GLuint indx, const GLfloat* values)
+_es_VertexAttrib4fv(GLuint indx, const GLfloat* values)
{
- vbo_VertexAttrib4fvARB(indx, values);
+ VertexAttrib4f_nopos(indx, values[0], values[1], values[2], values[3]);
}