* Authors:
* Keith Whitwell <keith@tungstengraphics.com>
*/
-#include "mtypes.h"
+
+#include "glheader.h"
#include "context.h"
-#include "colormac.h"
-#include "simple_list.h"
+#include "macros.h"
+#include "vtxfmt.h"
+#include "dlist.h"
+#include "state.h"
+#include "light.h"
#include "api_arrayelt.h"
-
-#include "t_context.h"
+#include "api_noop.h"
#include "t_vtx_api.h"
+#include "simple_list.h"
+#include "dispatch.h"
-/* Versions of all the entrypoints for situations where codegen isn't
- * available. This is slowed significantly by all the gumph necessary
- * to get to the tnl pointer, which can be avoided with codegen.
- *
- * Note: Only one size for each attribute may be active at once.
- * Eg. if Color3f is installed/active, then Color4f may not be, even
- * if the vertex actually contains 4 color coordinates. This is
- * because the 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 ATTRF( ATTR, N, A, B, C, D ) \
-{ \
- GET_CURRENT_CONTEXT( ctx ); \
- TNLcontext *tnl = TNL_CONTEXT(ctx); \
- \
- if ((ATTR) == 0) { \
- int i; \
- \
- if (N>0) tnl->vtx.vbptr[0].f = A; \
- if (N>1) tnl->vtx.vbptr[1].f = B; \
- if (N>2) tnl->vtx.vbptr[2].f = C; \
- if (N>3) tnl->vtx.vbptr[3].f = D; \
- \
- for (i = N; i < tnl->vtx.vertex_size; i++) \
- tnl->vtx.vbptr[i].ui = tnl->vtx.vertex[i].ui; \
- \
- tnl->vtx.vbptr += tnl->vtx.vertex_size; \
- \
- if (--tnl->vtx.counter == 0) \
- _tnl_FlushVertices( ctx, FLUSH_STORED_VERTICES ); \
- } \
- else { \
- union uif *dest = tnl->vtx.attrptr[ATTR]; \
- if (N>0) dest[0].f = A; \
- if (N>1) dest[1].f = B; \
- if (N>2) dest[2].f = C; \
- if (N>3) dest[3].f = D; \
- } \
-}
+static void reset_attrfv( TNLcontext *tnl );
-#define ATTR4F( ATTR, A, B, C, D ) ATTRF( ATTR, 4, A, B, C, D )
-#define ATTR3F( ATTR, A, B, C ) ATTRF( ATTR, 3, A, B, C, 1 )
-#define ATTR2F( ATTR, A, B ) ATTRF( ATTR, 2, A, B, 0, 1 )
-#define ATTR1F( ATTR, A ) ATTRF( ATTR, 1, A, 0, 0, 1 )
-
-#define ATTRS( ATTRIB ) \
-static void attrib_##ATTRIB##_1_0( GLfloat s ) \
-{ \
- ATTR1F( ATTRIB, s ); \
-} \
- \
-static void attrib_##ATTRIB##_1_1( const GLfloat *v ) \
-{ \
- ATTR1F( ATTRIB, v[0] ); \
-} \
- \
-static void attrib_##ATTRIB##_2_0( GLfloat s, GLfloat t ) \
-{ \
- ATTR2F( ATTRIB, s, t ); \
-} \
- \
-static void attrib_##ATTRIB##_2_1( const GLfloat *v ) \
-{ \
- ATTR2F( ATTRIB, v[0], v[1] ); \
-} \
- \
-static void attrib_##ATTRIB##_3_0( GLfloat s, GLfloat t, \
- GLfloat r ) \
-{ \
- ATTR3F( ATTRIB, s, t, r ); \
-} \
- \
-static void attrib_##ATTRIB##_3_1( const GLfloat *v ) \
-{ \
- ATTR3F( ATTRIB, v[0], v[1], v[2] ); \
-} \
- \
-static void attrib_##ATTRIB##_4_0( GLfloat s, GLfloat t, \
- GLfloat r, GLfloat q ) \
-{ \
- ATTR4F( ATTRIB, s, t, r, q ); \
-} \
- \
-static void attrib_##ATTRIB##_4_1( const GLfloat *v ) \
-{ \
- ATTR4F( ATTRIB, v[0], v[1], v[2], v[3] ); \
-}
+static tnl_attrfv_func choose[_TNL_MAX_ATTR_CODEGEN+1][4]; /* +1 for ERROR_ATTRIB */
+static tnl_attrfv_func generic_attr_func[_TNL_MAX_ATTR_CODEGEN][4];
-/* Generate a lot of functions. These are the actual worker
- * functions, which are equivalent to those generated via codegen
- * elsewhere.
- */
-ATTRS( 0 )
-ATTRS( 1 )
-ATTRS( 2 )
-ATTRS( 3 )
-ATTRS( 4 )
-ATTRS( 5 )
-ATTRS( 6 )
-ATTRS( 7 )
-ATTRS( 8 )
-ATTRS( 9 )
-ATTRS( 10 )
-ATTRS( 11 )
-ATTRS( 12 )
-ATTRS( 13 )
-ATTRS( 14 )
-ATTRS( 15 )
-/* Flush existing data, set new attrib size, replay copied vertices.
- */
-static void _tnl_upgrade_vertex( GLcontext *ctx,
- GLuint attr,
- GLuint newsz )
+/* Close off the last primitive, execute the buffer, restart the
+ * primitive.
+ */
+static void _tnl_wrap_buffers( GLcontext *ctx )
{
- GLuint oldsz = tnl->vtx.attrib[attr].sz;
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
- _tnl_flush_immediate( ctx );
+ if (tnl->vtx.prim_count == 0) {
+ tnl->vtx.copied.nr = 0;
+ tnl->vtx.counter = tnl->vtx.initial_counter;
+ tnl->vtx.vbptr = tnl->vtx.buffer;
+ }
+ else {
+ GLuint last_prim = tnl->vtx.prim[tnl->vtx.prim_count-1].mode;
+ GLuint last_count;
+
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ GLint i = tnl->vtx.prim_count - 1;
+ assert(i >= 0);
+ tnl->vtx.prim[i].count = ((tnl->vtx.initial_counter -
+ tnl->vtx.counter) -
+ tnl->vtx.prim[i].start);
+ }
- tnl->vtx.attrib[attr].sz = newsz;
- /* What else to do here?
- */
+ last_count = tnl->vtx.prim[tnl->vtx.prim_count-1].count;
- /* Replay stored vertices to translate them to new format: Use
- * bitmap and ffs() to speed inner loop:
- */
- for (i = 0 ; i < tnl->copied_verts.nr ; i++) {
- GLfloat *data = old_data + tnl->copied_verts.offset[i];
-
- for (j = 1 ; j < MAX_ATTRIB ; j++) {
- if (tnl->vtx.attrib[j].sz) {
- if (j == attr) {
- GLfloat tmp[4];
- COPY_4FV( tmp, id );
- COPY_SZ_4V( tmp, oldsz, data );
- data += oldsz;
- tnl->vtx.attrib[attr].fv( tmp );
- }
- else {
- GLfloat *tmp = data;
- data += tnl->vtx.attrib[j].sz;
- tnl->vtx.attrib[j].fv( tmp );
- }
- }
+ /* Execute the buffer and save copied vertices.
+ */
+ if (tnl->vtx.counter != tnl->vtx.initial_counter)
+ _tnl_flush_vtx( ctx );
+ else {
+ tnl->vtx.prim_count = 0;
+ tnl->vtx.copied.nr = 0;
}
- }
-}
-static void _tnl_wrap_buffers( GLcontext *ctx )
-{
- _tnl_flush_immediate( ctx );
+ /* Emit a glBegin to start the new list.
+ */
+ assert(tnl->vtx.prim_count == 0);
- /* Replay stored vertices - don't really need to do this, memcpy
- * would be fine.
- */
- for (i = 0 ; i < tnl->copied_verts.nr ; i++) {
- for (j = 1 ; j < MAX_ATTRIB ; j++) {
- GLfloat *tmp = data;
- data += tnl->vtx.attrib[j].sz;
- tnl->vtx.attrib[j].fv( tmp );
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ tnl->vtx.prim[0].mode = ctx->Driver.CurrentExecPrimitive;
+ tnl->vtx.prim[0].start = 0;
+ tnl->vtx.prim[0].count = 0;
+ tnl->vtx.prim_count++;
+
+ if (tnl->vtx.copied.nr == last_count)
+ tnl->vtx.prim[0].mode |= last_prim & PRIM_BEGIN;
}
}
}
-
-/* The functions defined below (CHOOSERS) are the initial state for
- * dispatch entries for all entrypoints except those requiring
- * double-dispatch (multitexcoord, material, vertexattrib).
+/* Deal with buffer wrapping where provoked by the vertex buffer
+ * filling up, as opposed to upgrade_vertex().
*
- * These may provoke a vertex-upgrade where the existing vertex buffer
- * is flushed and a new element is added to the active vertex layout.
- * This can happen between begin/end pairs.
+ * Make it GLAPIENTRY, so we can tail from the codegen'ed Vertex*fv
*/
+void GLAPIENTRY _tnl_wrap_filled_vertex( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLfloat *data = tnl->vtx.copied.buffer;
+ GLuint i;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to tnl->copied.
+ */
+ _tnl_wrap_buffers( ctx );
+
+ /* Copy stored stored vertices to start of new list.
+ */
+ assert(tnl->vtx.counter > tnl->vtx.copied.nr);
+
+ for (i = 0 ; i < tnl->vtx.copied.nr ; i++) {
+ _mesa_memcpy( tnl->vtx.vbptr, data,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
+ tnl->vtx.vbptr += tnl->vtx.vertex_size;
+ data += tnl->vtx.vertex_size;
+ tnl->vtx.counter--;
+ }
+
+ tnl->vtx.copied.nr = 0;
+}
-/* An active attribute has changed size.
+
+/*
+ * Copy the active vertex's values to the ctx->Current fields.
*/
-static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
+static void _tnl_copy_to_current( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ for (i = _TNL_ATTRIB_POS+1 ; i < _TNL_ATTRIB_INDEX ; i++) {
+ if (tnl->vtx.attrsz[i]) {
+ /* Note: the tnl->vtx.current[i] pointers points to
+ * the ctx->Current fields. The first 16 or so, anyway.
+ */
+ COPY_CLEAN_4V(tnl->vtx.current[i],
+ tnl->vtx.attrsz[i],
+ tnl->vtx.attrptr[i]);
+ }
+ }
- if (tnl->vtx.attrib_sz[attr] < sz) {
- /* New size is larger. Need to flush existing vertices and get
- * an enlarged vertex format.
- */
- _tnl_upgrade_vertex( tnl, attr, sz );
+ /* color index is special (it's not a float[4] so COPY_CLEAN_4V above
+ * will trash adjacent memory!)
+ */
+ if (tnl->vtx.attrsz[_TNL_ATTRIB_INDEX]) {
+ ctx->Current.Index = tnl->vtx.attrptr[_TNL_ATTRIB_INDEX][0];
}
- else {
- static float id[4] = { 0, 0, 0, 1 };
- int i;
- /* New size is smaller - just need to fill in some zeros.
- */
- for (i = sz ; i < tnl->vtx.attrib_sz[attr] ; i++)
- tnl->vtx.attrptr[attr][i].f = id[i];
+ /* Edgeflag requires additional treatment:
+ */
+ if (tnl->vtx.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
+ ctx->Current.EdgeFlag =
+ (tnl->vtx.CurrentFloatEdgeFlag == 1.0);
}
-
- /* Reset the dispatch table - aliasing entrypoints are invalidated.
+
+ /* Colormaterial -- this kindof sucks.
*/
- _tnl_reset_attr_dispatch_tab( ctx );
+ if (ctx->Light.ColorMaterialEnabled) {
+ _mesa_update_color_material(ctx,
+ ctx->Current.Attrib[VERT_ATTRIB_COLOR0]);
+ }
+
+ if (tnl->vtx.have_materials) {
+ tnl->Driver.NotifyMaterialChange( ctx );
+ }
+
+ ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT;
}
-static int dispatch_offset[TNL_ATTRIB_MAX][4][2];
+static void _tnl_copy_from_current( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i;
-static void *lookup_or_generate( GLuint attr, GLuint sz, GLuint v,
- void *fallback_attr_func )
-{
- GET_CURRENT_CONTEXT( ctx );
+ /* Edgeflag requires additional treatment:
+ */
+ tnl->vtx.CurrentFloatEdgeFlag =
+ (GLfloat)ctx->Current.EdgeFlag;
+
+ for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_MAX ; i++)
+ switch (tnl->vtx.attrsz[i]) {
+ case 4: tnl->vtx.attrptr[i][3] = tnl->vtx.current[i][3];
+ case 3: tnl->vtx.attrptr[i][2] = tnl->vtx.current[i][2];
+ case 2: tnl->vtx.attrptr[i][1] = tnl->vtx.current[i][1];
+ case 1: tnl->vtx.attrptr[i][0] = tnl->vtx.current[i][0];
+ break;
+ }
+
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+}
+
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */
+static void _tnl_wrap_upgrade_vertex( GLcontext *ctx,
+ GLuint attr,
+ GLuint newsz )
+{
TNLcontext *tnl = TNL_CONTEXT(ctx);
- void *ptr = 0;
- struct dynfn *dfn;
- int key;
-
- /* This will remove any installed handlers for attr with different
- * sz, will flush, copy and expand the copied vertices if sz won't
- * fit in the current vertex, or will clean the current vertex if
- * it already has this attribute in a larger size.
+ GLuint oldsz;
+ GLuint i;
+ GLfloat *tmp;
+ GLint lastcount = tnl->vtx.initial_counter - tnl->vtx.counter;
+
+ /* Run pipeline on current vertices, copy wrapped vertices
+ * to tnl->vtx.copied.
*/
- if (tnl->vtx.attrib_sz[attr] != sz)
- _tnl_fixup_vertex( ctx, attr, sz );
+ _tnl_wrap_buffers( ctx );
- if (attr == 0)
- key = tnl->vtx.vertex_size;
- else
- key = (GLuint)tnl->vtx.attrptr[attr];
+ /* 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.
+ */
+ _tnl_copy_to_current( ctx );
- for (dfn = tnl->vtx.generated[sz-1][v][isvertex]; dfn; dfn = dfn->next) {
- if (dfn->key == key) {
- ptr = dfn->code;
- break;
- }
+
+ /* Heuristic: Attempt to isolate attributes received outside
+ * begin/end so that they don't bloat the vertices.
+ */
+ if (ctx->Driver.CurrentExecPrimitive == PRIM_OUTSIDE_BEGIN_END &&
+ tnl->vtx.attrsz[attr] == 0 &&
+ lastcount > 8 &&
+ tnl->vtx.vertex_size) {
+ reset_attrfv( tnl );
}
- if (ptr == 0) {
- dfn = tnl->vtx.codegen[sz-1][v][isvertex]( ctx, key );
- if (dfn) {
- ptr = dfn->code;
- dfn->next = tnl->vtx.generated[sz-1][v][isvertex];
- tnl->vtx.generated[sz-1][v][isvertex] = dfn;
+ /* Fix up sizes:
+ */
+ oldsz = tnl->vtx.attrsz[attr];
+ tnl->vtx.attrsz[attr] = newsz;
+
+ tnl->vtx.vertex_size += newsz - oldsz;
+ tnl->vtx.counter = MIN2( VERT_BUFFER_SIZE / tnl->vtx.vertex_size,
+ ctx->Const.MaxArrayLockSize );
+ tnl->vtx.initial_counter = tnl->vtx.counter;
+ tnl->vtx.vbptr = tnl->vtx.buffer;
+
+
+ /* Recalculate all the attrptr[] values
+ */
+ for (i = 0, tmp = tnl->vtx.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
+ if (tnl->vtx.attrsz[i]) {
+ tnl->vtx.attrptr[i] = tmp;
+ tmp += tnl->vtx.attrsz[i];
}
+ else
+ tnl->vtx.attrptr[i] = NULL; /* will not be dereferenced */
}
-
- if (ptr == 0)
- ptr = fallback_attr_func;
- ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+ /* Copy from current to repopulate the vertex with correct values.
+ */
+ _tnl_copy_from_current( ctx );
- /* Need to set all the aliases to this function, too
+ /* Replay stored vertices to translate them
+ * to new format here.
+ *
+ * -- No need to replay - just copy piecewise
*/
- if (dispatch_offset[attr][sz-1][v])
- ((void **)tnl->Exec)[dispatch_offset[attr][sz-1][v]] = ptr;
+ if (tnl->vtx.copied.nr)
+ {
+ GLfloat *data = tnl->vtx.copied.buffer;
+ GLfloat *dest = tnl->vtx.buffer;
+ GLuint j;
+
+ for (i = 0 ; i < tnl->vtx.copied.nr ; i++) {
+ for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
+ if (tnl->vtx.attrsz[j]) {
+ if (j == attr) {
+ if (oldsz) {
+ COPY_CLEAN_4V( dest, oldsz, data );
+ data += oldsz;
+ dest += newsz;
+ } else {
+ COPY_SZ_4V( dest, newsz, tnl->vtx.current[j] );
+ dest += newsz;
+ }
+ }
+ else {
+ GLuint sz = tnl->vtx.attrsz[j];
+ COPY_SZ_4V( dest, sz, data );
+ dest += sz;
+ data += sz;
+ }
+ }
+ }
+ }
- return ptr;
-}
+ tnl->vtx.vbptr = dest;
+ tnl->vtx.counter -= tnl->vtx.copied.nr;
+ tnl->vtx.copied.nr = 0;
+ }
+ /* For codegen - attrptr's may have changed, so need to redo
+ * codegen. Might be a reasonable place to try & detect attributes
+ * in the vertex which aren't being submitted any more.
+ */
+ for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
+ if (tnl->vtx.attrsz[i]) {
+ GLuint j = tnl->vtx.attrsz[i] - 1;
+
+ if (i < _TNL_MAX_ATTR_CODEGEN)
+ tnl->vtx.tabfv[i][j] = choose[i][j];
+ }
-/* These functions choose one of the ATTR's generated above (or from
- * codegen). Like the ATTR functions, they live in the GL dispatch
- * table and in the second-level dispatch table for MultiTexCoord,
- * AttribNV, etc.
- *
- * Need ATTR1 for use in constructing name of 'attrib_x_y_z' function.
- */
-#define CHOOSE( ATTR1, ATTR2, SZ, V, FNTYPE, ARGS1, ARGS2 ) \
-static void choose_##ATTR2##_##SZ##_##V ARGS1 \
-{ \
- void *ptr = lookup_or_generate(ATTR1, SZ, V, \
- (void *)attrib_##ATTR1##_##SZ##_##V ); \
- \
- assert(ATTR1 == ATTR2); \
- ((FNTYPE) ptr) ARGS2; \
}
-#define afv (const GLfloat *v)
-#define a1f (GLfloat a)
-#define a2f (GLfloat a, GLfloat b)
-#define a3f (GLfloat a, GLfloat b, GLfloat c)
-#define a4f (GLfloat a, GLfloat b, GLfloat c, GLfloat d)
-/* Not that many entrypoints when it all boils down:
- */
-CHOOSE( 0, VERT_ATTRIB_POS, 2, 1, pfv, afv, (v) )
-CHOOSE( 0, VERT_ATTRIB_POS, 2, 0, p2f, a2f, (a,b) )
-CHOOSE( 0, VERT_ATTRIB_POS, 3, 1, pfv, afv, (v) )
-CHOOSE( 0, VERT_ATTRIB_POS, 3, 0, p3f, a3f, (a,b,c) )
-CHOOSE( 0, VERT_ATTRIB_POS, 4, 1, pfv, afv, (v) )
-CHOOSE( 0, VERT_ATTRIB_POS, 4, 0, p4f, a4f, (a,b,c,d) )
-CHOOSE( 2, VERT_ATTRIB_NORMAL, 3, 1, pfv, afv, (v) )
-CHOOSE( 2, VERT_ATTRIB_NORMAL, 3, 0, p3f, a3f, (a,b,c) )
-CHOOSE( 3, VERT_ATTRIB_COLOR0, 3, 1, pfv, afv, (v) )
-CHOOSE( 3, VERT_ATTRIB_COLOR0, 3, 0, p3f, a3f, (a,b,c) )
-CHOOSE( 3, VERT_ATTRIB_COLOR0, 4, 1, pfv, afv, (v) )
-CHOOSE( 3, VERT_ATTRIB_COLOR0, 4, 0, p4f, a4f, (a,b,c,d) )
-CHOOSE( 4, VERT_ATTRIB_COLOR1, 3, 1, pfv, afv, (v) )
-CHOOSE( 4, VERT_ATTRIB_COLOR1, 3, 0, p3f, a3f, (a,b,c) )
-CHOOSE( 5, VERT_ATTRIB_FOG, 1, 1, pfv, afv, (v) )
-CHOOSE( 5, VERT_ATTRIB_FOG, 1, 0, p1f, a1f, (a) )
-CHOOSE( 8, VERT_ATTRIB_TEX0, 1, 1, pfv, afv, (v) )
-CHOOSE( 8, VERT_ATTRIB_TEX0, 1, 0, p1f, a1f, (a) )
-CHOOSE( 8, VERT_ATTRIB_TEX0, 2, 1, pfv, afv, (v) )
-CHOOSE( 8, VERT_ATTRIB_TEX0, 2, 0, p2f, a2f, (a,b) )
-CHOOSE( 8, VERT_ATTRIB_TEX0, 3, 1, pfv, afv, (v) )
-CHOOSE( 8, VERT_ATTRIB_TEX0, 3, 0, p3f, a3f, (a,b,c) )
-CHOOSE( 8, VERT_ATTRIB_TEX0, 4, 1, pfv, afv, (v) )
-CHOOSE( 8, VERT_ATTRIB_TEX0, 4, 0, p4f, a4f, (a,b,c,d) )
-
-
-/* Gack. Need to do this without going through the
- * GET_CURRENT_CONTEXT hoohah. Could codegen this, I suppose...
- */
-#define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
-do { \
- GET_CURRENT_CONTEXT( ctx ); \
- TNLcontext *tnl = TNL_CONTEXT(ctx); \
- tnl->vtx.tabfv[COUNT-1][ATTR]( P ); \
-} while (0)
+static void _tnl_fixup_vertex( GLcontext *ctx, GLuint attr, GLuint sz )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ static const GLfloat id[4] = { 0, 0, 0, 1 };
+ int i;
-#define DISPATCH_ATTR1FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 1, V )
-#define DISPATCH_ATTR2FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 2, V )
-#define DISPATCH_ATTR3FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 3, V )
-#define DISPATCH_ATTR4FV( ATTR, V ) DISPATCH_ATTRFV( ATTR, 4, V )
+ if (tnl->vtx.attrsz[attr] < sz) {
+ /* New size is larger. Need to flush existing vertices and get
+ * an enlarged vertex format.
+ */
+ _tnl_wrap_upgrade_vertex( ctx, attr, sz );
+ }
+ else if (tnl->vtx.attrsz[attr] > sz) {
+ /* New size is smaller - just need to fill in some
+ * zeros. Don't need to flush or wrap.
+ */
+ for (i = sz ; i <= tnl->vtx.attrsz[attr] ; i++)
+ tnl->vtx.attrptr[attr][i-1] = id[i-1];
+ }
+
+ /* 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;
+ else
+ ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT;
+}
-#define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
#ifdef USE_X86_ASM
-/* Naughty cheat:
- */
-#define DISPATCH_ATTR2F( ATTR, S,T ) DISPATCH_ATTRFV( ATTR, 2, &(S) )
-#define DISPATCH_ATTR3F( ATTR, S,T,R ) DISPATCH_ATTRFV( ATTR, 3, &(S) )
-#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) DISPATCH_ATTRFV( ATTR, 4, &(S) )
-#else
-/* Safe:
- */
-#define DISPATCH_ATTR2F( ATTR, S,T ) \
-do { \
- GLfloat v[2]; \
- v[0] = S; v[1] = T; \
- DISPATCH_ATTR2FV( ATTR, v ); \
-} while (0)
-#define DISPATCH_ATTR3F( ATTR, S,T,R ) \
-do { \
- GLfloat v[3]; \
- v[0] = S; v[1] = T; v[2] = R; \
- DISPATCH_ATTR3FV( ATTR, v ); \
-} while (0)
-#define DISPATCH_ATTR4F( ATTR, S,T,R,Q ) \
-do { \
- GLfloat v[4]; \
- v[0] = S; v[1] = T; v[2] = R; v[3] = Q; \
- DISPATCH_ATTR4FV( ATTR, v ); \
-} while (0)
-#endif
+static struct _tnl_dynfn *lookup( struct _tnl_dynfn *l, GLuint key )
+{
+ struct _tnl_dynfn *f;
+ foreach( f, l ) {
+ if (f->key == key)
+ return f;
+ }
-static void enum_error( void )
-{
- GET_CURRENT_CONTEXT( ctx );
- _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
+ return NULL;
}
-static void op_error( void )
+
+static tnl_attrfv_func do_codegen( GLcontext *ctx, GLuint attr, GLuint sz )
{
- GET_CURRENT_CONTEXT( ctx );
- _mesa_error( ctx, GL_INVALID_OPERATION, __FUNCTION__ );
-}
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct _tnl_dynfn *dfn = NULL;
+ if (attr == 0) {
+ GLuint key = tnl->vtx.vertex_size;
-/* First level for MultiTexcoord: Send through second level dispatch.
- * These are permanently installed in the toplevel dispatch.
- *
- * Assembly can optimize the generation of arrays by using &s instead
- * of building 'v'.
- */
-static void _tnl_MultiTexCoord1f( GLenum target, GLfloat s )
-{
- GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
- DISPATCH_ATTR1FV( attr, &s );
-}
+ dfn = lookup( &tnl->vtx.cache.Vertex[sz-1], key );
-static void _tnl_MultiTexCoord1fv( GLenum target, const GLfloat *v )
-{
- GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
- DISPATCH_ATTR1FV( attr, v );
-}
+ if (!dfn)
+ dfn = tnl->vtx.gen.Vertex[sz-1]( ctx, key );
+ }
+ else {
+ GLuint key = (GLuint) tnl->vtx.attrptr[attr];
-static void _tnl_MultiTexCoord2f( GLenum target, GLfloat s, GLfloat t )
-{
- GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
- DISPATCH_ATTR2F( attr, s, t );
-}
+ dfn = lookup( &tnl->vtx.cache.Attribute[sz-1], key );
-static void _tnl_MultiTexCoord2fv( GLenum target, const GLfloat *v )
-{
- GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
- DISPATCH_ATTR2FV( attr, v );
-}
+ if (!dfn)
+ dfn = tnl->vtx.gen.Attribute[sz-1]( ctx, key );
+ }
-static void _tnl_MultiTexCoord3f( GLenum target, GLfloat s, GLfloat t,
- GLfloat r)
-{
- GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
- DISPATCH_ATTR3F( attr, s, t, r );
+ if (dfn)
+ return *(tnl_attrfv_func *) &dfn->code;
+ else
+ return NULL;
}
-static void _tnl_MultiTexCoord3fv( GLenum target, const GLfloat *v )
-{
- GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
- DISPATCH_ATTR3FV( attr, v );
-}
+#endif /* USE_X86_ASM */
-static void _tnl_MultiTexCoord4f( GLenum target, GLfloat s, GLfloat t,
- GLfloat r, GLfloat q )
-{
- GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
- DISPATCH_ATTR4F( attr, s, t, r, q );
-}
+/* Helper function for 'CHOOSE' macro. Do what's necessary when an
+ * entrypoint is called for the first time.
+ */
-static void _tnl_MultiTexCoord4fv( GLenum target, const GLfloat *v )
-{
- GLuint attr = (target & 0x7) + VERT_ATTRIB_TEX0;
- DISPATCH_ATTR4FV( attr, v );
-}
+static tnl_attrfv_func do_choose( GLuint attr, GLuint sz )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint oldsz = tnl->vtx.attrsz[attr];
+ assert(attr < _TNL_MAX_ATTR_CODEGEN);
-/* First level for NV_vertex_program:
- *
- * Check for errors & reroute through second dispatch layer to get
- * size tracking per-attribute.
- */
-static void _tnl_VertexAttrib1fNV( GLuint index, GLfloat s )
-{
- if (index < TNL_ATTRIB_MAX)
- DISPATCH_ATTR1F( index, s );
- else
- enum_error();
-}
+ if (oldsz != sz) {
+ /* Reset any active pointers for this attribute
+ */
+ if (oldsz)
+ tnl->vtx.tabfv[attr][oldsz-1] = choose[attr][oldsz-1];
+
+ _tnl_fixup_vertex( ctx, attr, sz );
+
+ }
-static void _tnl_VertexAttrib1fvNV( GLuint index, const GLfloat *v )
-{
- if (index < TNL_ATTRIB_MAX)
- DISPATCH_ATTR1FV( index, v );
- else
- enum_error();
-}
-static void _tnl_VertexAttrib2fNV( GLuint index, GLfloat s, GLfloat t )
-{
- if (index < TNL_ATTRIB_MAX)
- DISPATCH_ATTR2F( index, s, t );
+ /* Try to use codegen:
+ */
+#ifdef USE_X86_ASM
+ if (tnl->AllowCodegen)
+ tnl->vtx.tabfv[attr][sz-1] = do_codegen( ctx, attr, sz );
else
- enum_error();
-}
+#endif
+ tnl->vtx.tabfv[attr][sz-1] = NULL;
-static void _tnl_VertexAttrib2fvNV( GLuint index, const GLfloat *v )
-{
- if (index < TNL_ATTRIB_MAX)
- DISPATCH_ATTR2FV( index, v );
- else
- enum_error();
-}
+ /* Else use generic version:
+ */
+ if (!tnl->vtx.tabfv[attr][sz-1])
+ tnl->vtx.tabfv[attr][sz-1] = generic_attr_func[attr][sz-1];
-static void _tnl_VertexAttrib3fNV( GLuint index, GLfloat s, GLfloat t,
- GLfloat r )
-{
- if (index < TNL_ATTRIB_MAX)
- DISPATCH_ATTR3F( index, s, t, r );
- else
- enum_error();
+ return tnl->vtx.tabfv[attr][sz-1];
}
-static void _tnl_VertexAttrib3fvNV( GLuint index, const GLfloat *v )
-{
- if (index < TNL_ATTRIB_MAX)
- DISPATCH_ATTR3FV( index, v );
- else
- enum_error();
-}
-static void _tnl_VertexAttrib4fNV( GLuint index, GLfloat s, GLfloat t,
- GLfloat r, GLfloat q )
-{
- if (index < TNL_ATTRIB_MAX)
- DISPATCH_ATTR4F( index, s, t, r, q );
- else
- enum_error();
-}
-static void _tnl_VertexAttrib4fvNV( GLuint index, const GLfloat *v )
+#define CHOOSE( ATTR, N ) \
+static void choose_##ATTR##_##N( const GLfloat *v ) \
+{ \
+ tnl_attrfv_func f = do_choose(ATTR, N); \
+ f( v ); \
+}
+
+#define CHOOSERS( ATTRIB ) \
+ CHOOSE( ATTRIB, 1 ) \
+ CHOOSE( ATTRIB, 2 ) \
+ CHOOSE( ATTRIB, 3 ) \
+ CHOOSE( ATTRIB, 4 ) \
+
+
+#define INIT_CHOOSERS(ATTR) \
+ choose[ATTR][0] = choose_##ATTR##_1; \
+ choose[ATTR][1] = choose_##ATTR##_2; \
+ choose[ATTR][2] = choose_##ATTR##_3; \
+ choose[ATTR][3] = choose_##ATTR##_4;
+
+CHOOSERS( 0 )
+CHOOSERS( 1 )
+CHOOSERS( 2 )
+CHOOSERS( 3 )
+CHOOSERS( 4 )
+CHOOSERS( 5 )
+CHOOSERS( 6 )
+CHOOSERS( 7 )
+CHOOSERS( 8 )
+CHOOSERS( 9 )
+CHOOSERS( 10 )
+CHOOSERS( 11 )
+CHOOSERS( 12 )
+CHOOSERS( 13 )
+CHOOSERS( 14 )
+CHOOSERS( 15 )
+
+static void error_attrib( const GLfloat *unused )
{
- if (index < TNL_ATTRIB_MAX)
- DISPATCH_ATTR4FV( index, v );
- else
- enum_error();
+ GET_CURRENT_CONTEXT( ctx );
+ (void) unused;
+ _mesa_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
+}
+
+
+
+static void reset_attrfv( TNLcontext *tnl )
+{
+ GLuint i;
+
+ for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
+ if (tnl->vtx.attrsz[i]) {
+ GLint j = tnl->vtx.attrsz[i] - 1;
+ tnl->vtx.attrsz[i] = 0;
+
+ if (i < _TNL_MAX_ATTR_CODEGEN) {
+ while (j >= 0) {
+ tnl->vtx.tabfv[i][j] = choose[i][j];
+ j--;
+ }
+ }
+ }
+
+ tnl->vtx.vertex_size = 0;
+ tnl->vtx.have_materials = 0;
}
+
/* Materials:
* just to cope with this, so I unroll the 'C' varients of CHOOSE and
* ATTRF into this function, and dispense with codegen and
* second-level dispatch.
+ *
+ * There is no aliasing of material attributes with other entrypoints.
*/
-#define MAT_ATTR( A, N, params ) \
+#define OTHER_ATTR( A, N, params ) \
do { \
- if (tnl->vtx.attrib_sz[A] != N) { \
- tnl_fixup_vertex( ctx, A, N ); \
+ if (tnl->vtx.attrsz[A] != N) { \
+ _tnl_fixup_vertex( ctx, A, N ); \
} \
\
{ \
- union uif *dest = tnl->vtx.attrptr[A]; \
- if (N>0) dest[0].f = params[0]; \
- if (N>1) dest[1].f = params[1]; \
- if (N>2) dest[2].f = params[2]; \
- if (N>3) dest[3].f = params[3]; \
- ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
+ GLfloat *dest = tnl->vtx.attrptr[A]; \
+ if (N>0) dest[0] = (params)[0]; \
+ if (N>1) dest[1] = (params)[1]; \
+ if (N>2) dest[2] = (params)[2]; \
+ if (N>3) dest[3] = (params)[3]; \
} \
} while (0)
-#define MAT( ATTR, N, face, params ) \
-do { \
- if (face != GL_BACK) \
- MAT_ATTR( ATTR, N, params ); /* front */ \
- if (face != GL_FRONT) \
- MAT_ATTR( ATTR + 1, N, params ); /* back */ \
+#define MAT( ATTR, N, face, params ) \
+do { \
+ if (face != GL_BACK) \
+ OTHER_ATTR( ATTR, N, params ); /* front */ \
+ if (face != GL_FRONT) \
+ OTHER_ATTR( ATTR + 1, N, params ); /* back */ \
} while (0)
-/* NOTE: Have to remove/deal-with colormaterial crossovers, probably
- * later on - in the meantime just store everything.
+/* Colormaterial is dealt with later on.
*/
-static void _tnl_Materialfv( GLenum face, GLenum pname,
+static void GLAPIENTRY _tnl_Materialfv( GLenum face, GLenum pname,
const GLfloat *params )
{
GET_CURRENT_CONTEXT( ctx );
TNLcontext *tnl = TNL_CONTEXT(ctx);
+ switch (face) {
+ case GL_FRONT:
+ case GL_BACK:
+ case GL_FRONT_AND_BACK:
+ break;
+
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
+ return;
+ }
+
switch (pname) {
case GL_EMISSION:
- MAT( VERT_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
break;
case GL_AMBIENT:
- MAT( VERT_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
break;
case GL_DIFFUSE:
- MAT( VERT_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
break;
case GL_SPECULAR:
- MAT( VERT_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
break;
case GL_SHININESS:
- MAT( VERT_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
break;
case GL_COLOR_INDEXES:
- MAT( VERT_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
break;
case GL_AMBIENT_AND_DIFFUSE:
- MAT( VERT_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
- MAT( VERT_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
break;
default:
- _mesa_error( ctx, GL_INVALID_ENUM, __FUNCTION__ );
+ _mesa_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
return;
}
-}
-
-#define IDX_ATTR( A, IDX ) \
-do { \
- GET_CURRENT_CONTEXT( ctx ); \
- TNLcontext *tnl = TNL_CONTEXT(ctx); \
- \
- if (tnl->vtx.attrib_sz[A] != 1) { \
- tnl_fixup_vertex( ctx, A, 1 ); \
- } \
- \
- { \
- union uif *dest = tnl->vtx.attrptr[A]; \
- dest[0].ui = IDX; \
- ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \
- } \
-} while (0)
+ tnl->vtx.have_materials = GL_TRUE;
+}
-static void _tnl_EdgeFlag( GLboolean f )
+static void GLAPIENTRY _tnl_EdgeFlag( GLboolean b )
{
- IDX_ATTR( VERT_ATTRIB_EDGEFLAG, f );
-}
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLfloat f = (GLfloat)b;
-static void _tnl_EdgeFlagv( const GLboolean *f )
-{
- IDX_ATTR( VERT_ATTRIB_EDGEFLAG, f[0] );
+ OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
}
-static void _tnl_Indexi( GLint i )
+static void GLAPIENTRY _tnl_EdgeFlagv( const GLboolean *v )
{
- IDX_ATTR( VERT_ATTRIB_INDEX, i );
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLfloat f = (GLfloat)v[0];
+
+ OTHER_ATTR( _TNL_ATTRIB_EDGEFLAG, 1, &f );
}
-static void _tnl_Indexiv( const GLint *i )
+static void GLAPIENTRY _tnl_Indexf( GLfloat f )
{
- IDX_ATTR( VERT_ATTRIB_INDEX, i[0] );
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, &f );
}
+static void GLAPIENTRY _tnl_Indexfv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ OTHER_ATTR( _TNL_ATTRIB_INDEX, 1, v );
+}
-/* EvalCoord needs special treatment as ususal:
+/* Eval
*/
-static void evalcoord( GLfloat a, GLfloat b, GLuint type )
+static void GLAPIENTRY _tnl_EvalCoord1f( GLfloat u )
{
-#if 0
- GET_CURRENT_CONTEXT( ctx );
- TNLcontext *tnl = TNL_CONTEXT(ctx);
-
- /* Initialize the list of eval fixups:
- */
- if (!tnl->evalptr) {
- init_eval_ptr( ctx );
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* TODO: use a CHOOSE() function for this: */
+ {
+ GLint i;
+ if (tnl->vtx.eval.new_state)
+ _tnl_update_eval( ctx );
+
+ for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
+ if (tnl->vtx.eval.map1[i].map)
+ if (tnl->vtx.attrsz[i] != tnl->vtx.eval.map1[i].sz)
+ _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map1[i].sz );
+ }
}
- /* Note that this vertex will need to be fixed up:
- */
- tnl->evalptr[0].vert = tnl->initial_counter - tnl->counter;
- tnl->evalptr[0].type = type;
- /* Now emit the vertex with eval data in obj coordinates:
- */
- ATTRF( 0, 2, a, b, 0, 1 );
-#endif
-}
+ _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
+ _tnl_do_EvalCoord1f( ctx, u );
-static void _tnl_EvalCoord1f( GLfloat u )
-{
- evalcoord( u, 0, TNL_EVAL_COORD1 );
+ _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
}
-static void _tnl_EvalCoord1fv( const GLfloat *v )
+static void GLAPIENTRY _tnl_EvalCoord2f( GLfloat u, GLfloat v )
{
- evalcoord( v[0], 0, TNL_EVAL_COORD1 );
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* TODO: use a CHOOSE() function for this: */
+ {
+ GLint i;
+ if (tnl->vtx.eval.new_state)
+ _tnl_update_eval( ctx );
+
+ for (i = 0 ; i <= _TNL_ATTRIB_INDEX ; i++) {
+ if (tnl->vtx.eval.map2[i].map)
+ if (tnl->vtx.attrsz[i] != tnl->vtx.eval.map2[i].sz)
+ _tnl_fixup_vertex( ctx, i, tnl->vtx.eval.map2[i].sz );
+ }
+
+ if (ctx->Eval.AutoNormal)
+ if (tnl->vtx.attrsz[_TNL_ATTRIB_NORMAL] != 3)
+ _tnl_fixup_vertex( ctx, _TNL_ATTRIB_NORMAL, 3 );
+ }
+
+ _mesa_memcpy( tnl->vtx.copied.buffer, tnl->vtx.vertex,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
+
+ _tnl_do_EvalCoord2f( ctx, u, v );
+
+ _mesa_memcpy( tnl->vtx.vertex, tnl->vtx.copied.buffer,
+ tnl->vtx.vertex_size * sizeof(GLfloat));
}
-static void _tnl_EvalCoord2f( GLfloat u, GLfloat v )
+static void GLAPIENTRY _tnl_EvalCoord1fv( const GLfloat *u )
{
- evalcoord( u, v, TNL_EVAL_COORD2 );
+ _tnl_EvalCoord1f( u[0] );
}
-static void _tnl_EvalCoord2fv( const GLfloat *v )
+static void GLAPIENTRY _tnl_EvalCoord2fv( const GLfloat *u )
{
- evalcoord( v[0], v[1], TNL_EVAL_COORD2 );
+ _tnl_EvalCoord2f( u[0], u[1] );
}
-static void _tnl_EvalPoint1( GLint i )
+static void GLAPIENTRY _tnl_EvalPoint1( GLint i )
{
- evalcoord( (GLfloat)i, 0, TNL_EVAL_POINT1 );
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid1u2 - ctx->Eval.MapGrid1u1) /
+ (GLfloat) ctx->Eval.MapGrid1un);
+ GLfloat u = i * du + ctx->Eval.MapGrid1u1;
+
+ _tnl_EvalCoord1f( u );
}
-static void _tnl_EvalPoint2( GLint i, GLint j )
+
+static void GLAPIENTRY _tnl_EvalPoint2( GLint i, GLint j )
{
- evalcoord( (GLfloat)i, (GLfloat)j, TNL_EVAL_POINT2 );
+ GET_CURRENT_CONTEXT( ctx );
+ GLfloat du = ((ctx->Eval.MapGrid2u2 - ctx->Eval.MapGrid2u1) /
+ (GLfloat) ctx->Eval.MapGrid2un);
+ GLfloat dv = ((ctx->Eval.MapGrid2v2 - ctx->Eval.MapGrid2v1) /
+ (GLfloat) ctx->Eval.MapGrid2vn);
+ GLfloat u = i * du + ctx->Eval.MapGrid2u1;
+ GLfloat v = j * dv + ctx->Eval.MapGrid2v1;
+
+ _tnl_EvalCoord2f( u, v );
}
-/* Don't do a lot of processing here - errors are raised when this
- * list is scanned later on (perhaps in display list playback) to
- * build tnl_prim structs.
+
+/* Build a list of primitives on the fly. Keep
+ * ctx->Driver.CurrentExecPrimitive uptodate as well.
*/
-static void _tnl_Begin( GLenum mode )
+static void GLAPIENTRY _tnl_Begin( GLenum mode )
{
GET_CURRENT_CONTEXT( ctx );
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- int i;
- i = tnl->vtx.be_count++;
- tnl->vtx.be[i].type = TNL_BEGIN;
- tnl->vtx.be[i].idx = tnl->vtx.initial_counter - tnl->vtx.counter;
- tnl->vtx.be[i].mode = mode;
+ if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) {
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ int i;
- if (tnl->vtx.be_count == TNL_BE_MAX)
- _tnl_FlushVertices( ctx, FLUSH_STORED_VERTICES );
+ if (ctx->NewState) {
+ _mesa_update_state( ctx );
+
+ if ((ctx->VertexProgram.Enabled && !ctx->VertexProgram._Enabled) ||
+ (ctx->FragmentProgram.Enabled && !ctx->FragmentProgram._Enabled)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBegin (invalid vertex/fragment program)");
+ return;
+ }
+
+ if (!(tnl->Driver.NotifyBegin &&
+ tnl->Driver.NotifyBegin( ctx, mode )))
+ CALL_Begin(ctx->Exec, (mode));
+ return;
+ }
+
+ /* Heuristic: attempt to isolate attributes occuring outside
+ * begin/end pairs.
+ */
+ if (tnl->vtx.vertex_size && !tnl->vtx.attrsz[0])
+ _tnl_FlushVertices( ctx, ~0 );
+
+ i = tnl->vtx.prim_count++;
+ tnl->vtx.prim[i].mode = mode | PRIM_BEGIN;
+ tnl->vtx.prim[i].start = tnl->vtx.initial_counter - tnl->vtx.counter;
+ tnl->vtx.prim[i].count = 0;
+
+ ctx->Driver.CurrentExecPrimitive = mode;
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" );
+
}
-static void _tnl_End( void )
+static void GLAPIENTRY _tnl_End( void )
{
GET_CURRENT_CONTEXT( ctx );
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- int i;
- i = tnl->vtx.be_count++;
- tnl->vtx.be[i].type = TNL_END;
- tnl->vtx.be[i].idx = tnl->vtx.initial_counter - tnl->vtx.counter;
- tnl->vtx.be[i].mode = 0;
+ if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) {
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ int idx = tnl->vtx.initial_counter - tnl->vtx.counter;
+ int i = tnl->vtx.prim_count - 1;
- if (tnl->vtx.be_count == TNL_BE_MAX)
- _tnl_FlushVertices( ctx, FLUSH_STORED_VERTICES );
+ tnl->vtx.prim[i].mode |= PRIM_END;
+ tnl->vtx.prim[i].count = idx - tnl->vtx.prim[i].start;
+
+ ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1;
+
+ /* Two choices which effect the way vertex attributes are
+ * carried over (or not) between adjacent primitives.
+ */
+#if 0
+ if (tnl->vtx.prim_count == TNL_MAX_PRIM)
+ _tnl_FlushVertices( ctx, ~0 );
+#else
+ if (tnl->vtx.prim_count == TNL_MAX_PRIM)
+ _tnl_flush_vtx( ctx );
+#endif
+
+ }
+ else
+ _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" );
}
+static void _tnl_exec_vtxfmt_init( GLcontext *ctx )
+{
+ GLvertexformat *vfmt = &(TNL_CONTEXT(ctx)->exec_vtxfmt);
+ vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
+ vfmt->Begin = _tnl_Begin;
+ vfmt->CallList = _mesa_CallList;
+ vfmt->CallLists = _mesa_CallLists;
+ vfmt->EdgeFlag = _tnl_EdgeFlag;
+ vfmt->EdgeFlagv = _tnl_EdgeFlagv;
+ vfmt->End = _tnl_End;
+ vfmt->EvalCoord1f = _tnl_EvalCoord1f;
+ vfmt->EvalCoord1fv = _tnl_EvalCoord1fv;
+ vfmt->EvalCoord2f = _tnl_EvalCoord2f;
+ vfmt->EvalCoord2fv = _tnl_EvalCoord2fv;
+ vfmt->EvalPoint1 = _tnl_EvalPoint1;
+ vfmt->EvalPoint2 = _tnl_EvalPoint2;
+ vfmt->Indexf = _tnl_Indexf;
+ vfmt->Indexfv = _tnl_Indexfv;
+ vfmt->Materialfv = _tnl_Materialfv;
+ vfmt->Rectf = _mesa_noop_Rectf;
+ vfmt->EvalMesh1 = _mesa_noop_EvalMesh1;
+ vfmt->EvalMesh2 = _mesa_noop_EvalMesh2;
+}
-static void _tnl_InitDispatch( struct _glapi_table *tab )
+void _tnl_FlushVertices( GLcontext *ctx, GLuint flags )
{
- GLint i;
-
- /* Most operations boil down to error/transition behaviour.
- * However if we transition eagerly, all that's needed is a single
- * 'error' operation. This will do for now, but requires that the
- * old 'flush' stuff lives on in the state functions, and is
- * wasteful if swapping is expensive (threads?).
- */
- for (i = 0 ; i < sizeof(tab)/sizeof(void*) ; i++)
- ((void **)tab)[i] = (void *)op_error;
-
- tab->Begin = _tnl_Begin;
- tab->End = _tnl_End;
- tab->Color3f = choose_VERT_ATTRIB_COLOR0_3_0;
- tab->Color3fv = choose_VERT_ATTRIB_COLOR0_3_1;
- tab->Color4f = choose_VERT_ATTRIB_COLOR0_4_0;
- tab->Color4fv = choose_VERT_ATTRIB_COLOR0_4_1;
- tab->SecondaryColor3fEXT = choose_VERT_ATTRIB_COLOR1_3_0;
- tab->SecondaryColor3fvEXT = choose_VERT_ATTRIB_COLOR1_3_1;
- tab->MultiTexCoord1fARB = _tnl_MultiTexCoord1f;
- tab->MultiTexCoord1fvARB = _tnl_MultiTexCoord1fv;
- tab->MultiTexCoord2fARB = _tnl_MultiTexCoord2f;
- tab->MultiTexCoord2fvARB = _tnl_MultiTexCoord2fv;
- tab->MultiTexCoord3fARB = _tnl_MultiTexCoord3f;
- tab->MultiTexCoord3fvARB = _tnl_MultiTexCoord3fv;
- tab->MultiTexCoord4fARB = _tnl_MultiTexCoord4f;
- tab->MultiTexCoord4fvARB = _tnl_MultiTexCoord4fv;
- tab->Normal3f = choose_VERT_ATTRIB_NORMAL_3_0;
- tab->Normal3fv = choose_VERT_ATTRIB_NORMAL_3_1;
- tab->TexCoord1f = choose_VERT_ATTRIB_TEX0_1_0;
- tab->TexCoord1fv = choose_VERT_ATTRIB_TEX0_1_1;
- tab->TexCoord2f = choose_VERT_ATTRIB_TEX0_2_0;
- tab->TexCoord2fv = choose_VERT_ATTRIB_TEX0_2_1;
- tab->TexCoord3f = choose_VERT_ATTRIB_TEX0_3_0;
- tab->TexCoord3fv = choose_VERT_ATTRIB_TEX0_3_1;
- tab->TexCoord4f = choose_VERT_ATTRIB_TEX0_4_0;
- tab->TexCoord4fv = choose_VERT_ATTRIB_TEX0_4_1;
- tab->Vertex2f = choose_VERT_ATTRIB_POS_2_0;
- tab->Vertex2fv = choose_VERT_ATTRIB_POS_2_1;
- tab->Vertex3f = choose_VERT_ATTRIB_POS_3_0;
- tab->Vertex3fv = choose_VERT_ATTRIB_POS_3_1;
- tab->Vertex4f = choose_VERT_ATTRIB_POS_4_0;
- tab->Vertex4fv = choose_VERT_ATTRIB_POS_4_1;
- tab->FogCoordfEXT = choose_VERT_ATTRIB_FOG_1_0;
- tab->FogCoordfvEXT = choose_VERT_ATTRIB_FOG_1_1;
- tab->EdgeFlag = _tnl_EdgeFlag;
- tab->EdgeFlagv = _tnl_EdgeFlagv;
- tab->Indexi = _tnl_Indexi;
- tab->Indexiv = _tnl_Indexiv;
- tab->EvalCoord1f = _tnl_EvalCoord1f;
- tab->EvalCoord1fv = _tnl_EvalCoord1fv;
- tab->EvalCoord2f = _tnl_EvalCoord2f;
- tab->EvalCoord2fv = _tnl_EvalCoord2fv;
- tab->Materialfv = _tnl_Materialfv;
- tab->ArrayElement = _ae_loopback_array_elt; /* generic helper */
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ (void) flags;
+
+ if (ctx->Driver.CurrentExecPrimitive != PRIM_OUTSIDE_BEGIN_END)
+ return;
+
+ if (tnl->vtx.counter != tnl->vtx.initial_counter) {
+ _tnl_flush_vtx( ctx );
+ }
+
+ if (tnl->vtx.vertex_size) {
+ _tnl_copy_to_current( ctx );
+ reset_attrfv( tnl );
+ }
+
+ ctx->Driver.NeedFlush = 0;
}
+static void _tnl_current_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i;
+
+ /* setup the pointers for the typical 16 vertex attributes */
+ for (i = 0; i < VERT_ATTRIB_MAX; i++)
+ tnl->vtx.current[i] = ctx->Current.Attrib[i];
+
+ /* setup pointers for the 12 material attributes */
+ for (i = 0; i < MAT_ATTRIB_MAX; i++)
+ tnl->vtx.current[_TNL_ATTRIB_MAT_FRONT_AMBIENT + i] =
+ ctx->Light.Material.Attrib[i];
-static struct dynfn *codegen_noop( GLcontext *ctx, int key )
+ tnl->vtx.current[_TNL_ATTRIB_INDEX] = &ctx->Current.Index;
+ tnl->vtx.current[_TNL_ATTRIB_EDGEFLAG] = &tnl->vtx.CurrentFloatEdgeFlag;
+}
+
+static struct _tnl_dynfn *no_codegen( GLcontext *ctx, int key )
{
(void) ctx; (void) key;
- return 0;
+ return NULL;
}
-static void _tnl_InitCodegen( GLcontext *ctx )
+void _tnl_vtx_init( GLcontext *ctx )
{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- int sz, v, z;
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_vertex_arrays *tmp = &tnl->vtx_inputs;
+ GLuint i;
+ static int firsttime = 1;
+
+ if (firsttime) {
+ firsttime = 0;
+
+ INIT_CHOOSERS( 0 );
+ INIT_CHOOSERS( 1 );
+ INIT_CHOOSERS( 2 );
+ INIT_CHOOSERS( 3 );
+ INIT_CHOOSERS( 4 );
+ INIT_CHOOSERS( 5 );
+ INIT_CHOOSERS( 6 );
+ INIT_CHOOSERS( 7 );
+ INIT_CHOOSERS( 8 );
+ INIT_CHOOSERS( 9 );
+ INIT_CHOOSERS( 10 );
+ INIT_CHOOSERS( 11 );
+ INIT_CHOOSERS( 12 );
+ INIT_CHOOSERS( 13 );
+ INIT_CHOOSERS( 14 );
+ INIT_CHOOSERS( 15 );
+
+ choose[ERROR_ATTRIB][0] = error_attrib;
+ choose[ERROR_ATTRIB][1] = error_attrib;
+ choose[ERROR_ATTRIB][2] = error_attrib;
+ choose[ERROR_ATTRIB][3] = error_attrib;
- /* attr[n][v]
- * vertex[n][v]
- *
- * Generated functions parameterized by:
- * nr 1..4
- * v y/n
- * vertex y/n
- *
- * Vertex functions also parameterized by:
- * vertex_size
- *
- * Attr functions also parameterized by:
- * pointer (destination to receive data)
- */
- for (sz = 1 ; sz < 5 ; sz++) {
- for (v = 0 ; v < 2 ; v++) {
- for (z = 0 ; z < 2 ; z++) {
- tnl->vtx.codegen[sz-1][v][z] = codegen_noop;
- tnl->vtx.generated[sz-1][v][z] = 0;
- }
+#ifdef USE_X86_ASM
+ if (tnl->AllowCodegen) {
+ _tnl_x86choosers(choose, do_choose); /* x86 INIT_CHOOSERS */
}
+#endif
+
+ _tnl_generic_attr_table_init( generic_attr_func );
}
-#if 0
- if (!getenv("MESA_NO_CODEGEN")) {
-#if defined(USE_X86_ASM)
- _tnl_InitX86Codegen( gen );
-#endif
+ for (i = 0; i < _TNL_ATTRIB_INDEX; i++)
+ _mesa_vector4f_init( &tmp->Attribs[i], 0, NULL);
-#if defined(USE_SSE_ASM)
- _tnl_InitSSECodegen( gen );
-#endif
+ for (i = 0; i < 4; i++) {
+ make_empty_list( &tnl->vtx.cache.Vertex[i] );
+ make_empty_list( &tnl->vtx.cache.Attribute[i] );
+ tnl->vtx.gen.Vertex[i] = no_codegen;
+ tnl->vtx.gen.Attribute[i] = no_codegen;
+ }
-#if defined(USE_3DNOW_ASM)
+#ifdef USE_X86_ASM
+ _tnl_InitX86Codegen( &tnl->vtx.gen );
#endif
-#if defined(USE_SPARC_ASM)
-#endif
+ _tnl_current_init( ctx );
+ _tnl_exec_vtxfmt_init( ctx );
+ _tnl_generic_exec_vtxfmt_init( ctx );
+#ifdef USE_X86_ASM
+ if (tnl->AllowCodegen) {
+ _tnl_x86_exec_vtxfmt_init( ctx ); /* x86 DISPATCH_ATTRFV */
}
#endif
-}
+ _mesa_install_exec_vtxfmt( ctx, &tnl->exec_vtxfmt );
+ memcpy( tnl->vtx.tabfv, choose, sizeof(choose) );
+ for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
+ tnl->vtx.attrsz[i] = 0;
-void _tnl_vtx_init( GLcontext *ctx )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- _tnl_InitDispatch( tnl->Exec );
- _tnl_InitCodegen( ctx );
+ tnl->vtx.vertex_size = 0;
+ tnl->vtx.have_materials = 0;
}
+static void free_funcs( struct _tnl_dynfn *l )
+{
+ struct _tnl_dynfn *f, *tmp;
+ foreach_s (f, tmp, l) {
+ remove_from_list( f );
+ ALIGN_FREE( f->code );
+ FREE( f );
+ }
+}
void _tnl_vtx_destroy( GLcontext *ctx )
{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- int sz, v, z;
- struct dynfn *dfn, *next;
-
- for (sz = 1 ; sz <= 4 ; sz++) {
- for (v = 0 ; v <= 1 ; v++) {
- for (z = 0 ; z <= 1 ; z++) {
- dfn = tnl->vtx.generated[sz-1][v][z];
- while (dfn) {
- next = dfn->next;
- FREE(dfn);
- dfn = next;
- }
- }
- }
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ for (i = 0; i < 4; i++) {
+ free_funcs( &tnl->vtx.cache.Vertex[i] );
+ free_funcs( &tnl->vtx.cache.Attribute[i] );
}
}