aboutsummaryrefslogtreecommitdiffstats
path: root/src/mesa/tnl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/tnl')
-rw-r--r--src/mesa/tnl/t_context.c21
-rw-r--r--src/mesa/tnl/t_context.h1
-rw-r--r--src/mesa/tnl/t_pipeline.c5
-rw-r--r--src/mesa/tnl/t_save_api.c1834
-rw-r--r--src/mesa/tnl/t_vb_arbprogram.c141
-rw-r--r--src/mesa/tnl/t_vb_arbprogram.h31
-rw-r--r--src/mesa/tnl/t_vb_arbprogram_sse.c2
-rw-r--r--src/mesa/tnl/t_vb_arbshader.c301
-rw-r--r--src/mesa/tnl/t_vb_cull.c5
-rw-r--r--src/mesa/tnl/t_vb_fog.c5
-rw-r--r--src/mesa/tnl/t_vb_light.c10
-rw-r--r--src/mesa/tnl/t_vb_normals.c7
-rw-r--r--src/mesa/tnl/t_vb_points.c5
-rw-r--r--src/mesa/tnl/t_vb_program.c244
-rw-r--r--src/mesa/tnl/t_vb_texgen.c10
-rw-r--r--src/mesa/tnl/t_vb_texmat.c5
-rw-r--r--src/mesa/tnl/t_vb_vertex.c5
-rw-r--r--src/mesa/tnl/t_vp_build.c96
-rw-r--r--src/mesa/tnl/tnl.h3
19 files changed, 2231 insertions, 500 deletions
diff --git a/src/mesa/tnl/t_context.c b/src/mesa/tnl/t_context.c
index d9458b74eca..f665485f422 100644
--- a/src/mesa/tnl/t_context.c
+++ b/src/mesa/tnl/t_context.c
@@ -60,7 +60,7 @@ _tnl_CreateContext( GLcontext *ctx )
/* Initialize tnl state.
*/
- if (ctx->_MaintainTnlProgram) {
+ if (ctx->VertexProgram._MaintainTnlProgram) {
_tnl_ProgramCacheInit( ctx );
_tnl_install_pipeline( ctx, _tnl_vp_pipeline );
} else {
@@ -90,7 +90,7 @@ _tnl_DestroyContext( GLcontext *ctx )
_tnl_destroy_pipeline( ctx );
- if (ctx->_MaintainTnlProgram)
+ if (ctx->VertexProgram._MaintainTnlProgram)
_tnl_ProgramCacheDestroy( ctx );
FREE(tnl);
@@ -134,7 +134,7 @@ _tnl_InvalidateState( GLcontext *ctx, GLuint new_state )
}
if (ctx->Fog.Enabled ||
- (ctx->FragmentProgram._Active &&
+ (ctx->FragmentProgram._Current &&
(ctx->FragmentProgram._Current->FogOption != GL_NONE ||
ctx->FragmentProgram._Current->Base.InputsRead & FRAG_BIT_FOGC)))
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_FOG );
@@ -150,8 +150,19 @@ _tnl_InvalidateState( GLcontext *ctx, GLuint new_state )
(ctx->VertexProgram._Enabled && ctx->VertexProgram.PointSizeEnabled))
RENDERINPUTS_SET( tnl->render_inputs_bitset, _TNL_ATTRIB_POINTSIZE );
- if (ctx->ShaderObjects._VertexShaderPresent || ctx->ShaderObjects._FragmentShaderPresent)
- RENDERINPUTS_SET_RANGE( tnl->render_inputs_bitset, _TNL_FIRST_GENERIC, _TNL_LAST_GENERIC );
+ /* check for varying vars which are written by the vertex program */
+ {
+ struct gl_vertex_program *vp = ctx->VertexProgram._Current;
+ if (vp) {
+ GLuint i;
+ for (i = 0; i < MAX_VARYING; i++) {
+ if (vp->Base.OutputsWritten & (1 << (VERT_RESULT_VAR0 + i))) {
+ RENDERINPUTS_SET(tnl->render_inputs_bitset,
+ _TNL_ATTRIB_GENERIC(i));
+ }
+ }
+ }
+ }
}
diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h
index a872f261775..31b89aca41f 100644
--- a/src/mesa/tnl/t_context.h
+++ b/src/mesa/tnl/t_context.h
@@ -217,7 +217,6 @@ struct vertex_buffer
GLvector4f *ColorPtr[2]; /* _TNL_BIT_COLOR0 */
GLvector4f *SecondaryColorPtr[2]; /* _TNL_BIT_COLOR1 */
GLvector4f *FogCoordPtr; /* _TNL_BIT_FOG */
- GLvector4f *VaryingPtr[MAX_VARYING_VECTORS];
const struct _mesa_prim *Primitive;
GLuint PrimitiveCount;
diff --git a/src/mesa/tnl/t_pipeline.c b/src/mesa/tnl/t_pipeline.c
index 2efe701a802..a50a3f0f2f2 100644
--- a/src/mesa/tnl/t_pipeline.c
+++ b/src/mesa/tnl/t_pipeline.c
@@ -132,7 +132,7 @@ void _tnl_run_pipeline( GLcontext *ctx )
* (ie const or non-const).
*/
if (check_input_changes( ctx ) || tnl->pipeline.new_state) {
- if (ctx->_MaintainTnlProgram)
+ if (ctx->VertexProgram._MaintainTnlProgram)
_tnl_UpdateFixedFunctionProgram( ctx );
for (i = 0; i < tnl->pipeline.nr_stages ; i++) {
@@ -208,9 +208,6 @@ const struct tnl_pipeline_stage *_tnl_default_pipeline[] = {
&_tnl_arb_vertex_program_stage,
&_tnl_vertex_program_stage,
#endif
-#if FEATURE_ARB_vertex_shader
- &_tnl_arb_vertex_shader_stage,
-#endif
&_tnl_render_stage,
NULL
};
diff --git a/src/mesa/tnl/t_save_api.c b/src/mesa/tnl/t_save_api.c
new file mode 100644
index 00000000000..b08f05374e4
--- /dev/null
+++ b/src/mesa/tnl/t_save_api.c
@@ -0,0 +1,1834 @@
+/**************************************************************************
+
+Copyright 2002 Tungsten Graphics Inc., Cedar Park, Texas.
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+/*
+ * Authors:
+ * Keith Whitwell <[email protected]>
+ */
+
+
+
+/**
+ * The display list compiler attempts to store lists of vertices with the
+ * same vertex layout. Additionally it attempts to minimize the need
+ * for execute-time fixup of these vertex lists, allowing them to be
+ * cached on hardware.
+ *
+ * There are still some circumstances where this can be thwarted, for
+ * example by building a list that consists of one very long primitive
+ * (eg Begin(Triangles), 1000 vertices, End), and calling that list
+ * from inside a different begin/end object (Begin(Lines), CallList,
+ * End).
+ *
+ * In that case the code will have to replay the list as individual
+ * commands through the Exec dispatch table, or fix up the copied
+ * vertices at execute-time.
+ *
+ * The other case where fixup is required is when a vertex attribute
+ * is introduced in the middle of a primitive. Eg:
+ * Begin(Lines)
+ * TexCoord1f() Vertex2f()
+ * TexCoord1f() Color3f() Vertex2f()
+ * End()
+ *
+ * If the current value of Color isn't known at compile-time, this
+ * primitive will require fixup.
+ *
+ *
+ * The list compiler currently doesn't attempt to compile lists
+ * containing EvalCoord or EvalPoint commands. On encountering one of
+ * these, compilation falls back to opcodes.
+ *
+ * This could be improved to fallback only when a mix of EvalCoord and
+ * Vertex commands are issued within a single primitive.
+ */
+
+
+#include "glheader.h"
+#include "context.h"
+#include "dlist.h"
+#include "enums.h"
+#include "macros.h"
+#include "api_validate.h"
+#include "api_arrayelt.h"
+#include "vtxfmt.h"
+#include "t_save_api.h"
+#include "dispatch.h"
+
+/*
+ * NOTE: Old 'parity' issue is gone, but copying can still be
+ * wrong-footed on replay.
+ */
+static GLuint _save_copy_vertices( GLcontext *ctx,
+ const struct tnl_vertex_list *node )
+{
+ TNLcontext *tnl = TNL_CONTEXT( ctx );
+ const struct tnl_prim *prim = &node->prim[node->prim_count-1];
+ GLuint nr = prim->count;
+ GLuint sz = tnl->save.vertex_size;
+ const GLfloat *src = node->buffer + prim->start * sz;
+ GLfloat *dst = tnl->save.copied.buffer;
+ GLuint ovf, i;
+
+ if (prim->mode & PRIM_END)
+ return 0;
+
+ switch( prim->mode & PRIM_MODE_MASK )
+ {
+ case GL_POINTS:
+ return 0;
+ case GL_LINES:
+ ovf = nr&1;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+ return i;
+ case GL_TRIANGLES:
+ ovf = nr%3;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+ return i;
+ case GL_QUADS:
+ ovf = nr&3;
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+ return i;
+ case GL_LINE_STRIP:
+ if (nr == 0)
+ return 0;
+ else {
+ _mesa_memcpy( dst, src+(nr-1)*sz, sz*sizeof(GLfloat) );
+ return 1;
+ }
+ case GL_LINE_LOOP:
+ case GL_TRIANGLE_FAN:
+ case GL_POLYGON:
+ if (nr == 0)
+ return 0;
+ else if (nr == 1) {
+ _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
+ return 1;
+ } else {
+ _mesa_memcpy( dst, src+0, sz*sizeof(GLfloat) );
+ _mesa_memcpy( dst+sz, src+(nr-1)*sz, sz*sizeof(GLfloat) );
+ return 2;
+ }
+ case GL_TRIANGLE_STRIP:
+ case GL_QUAD_STRIP:
+ switch (nr) {
+ case 0: ovf = 0; break;
+ case 1: ovf = 1; break;
+ default: ovf = 2 + (nr&1); break;
+ }
+ for (i = 0 ; i < ovf ; i++)
+ _mesa_memcpy( dst+i*sz, src+(nr-ovf+i)*sz, sz*sizeof(GLfloat) );
+ return i;
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+
+static void
+build_normal_lengths( struct tnl_vertex_list *node )
+{
+ GLuint i;
+ GLfloat *len;
+ GLfloat *n = node->buffer;
+ GLuint stride = node->vertex_size;
+ GLuint count = node->count;
+
+ len = node->normal_lengths = (GLfloat *) MALLOC( count * sizeof(GLfloat) );
+ if (!len)
+ return;
+
+ /* Find the normal of the first vertex:
+ */
+ for (i = 0 ; i < _TNL_ATTRIB_NORMAL ; i++)
+ n += node->attrsz[i];
+
+ for (i = 0 ; i < count ; i++, n += stride) {
+ len[i] = LEN_3FV( n );
+ if (len[i] > 0.0F) len[i] = 1.0F / len[i];
+ }
+}
+
+static struct tnl_vertex_store *alloc_vertex_store( GLcontext *ctx )
+{
+ struct tnl_vertex_store *store = MALLOC_STRUCT(tnl_vertex_store);
+ (void) ctx;
+ store->used = 0;
+ store->refcount = 1;
+ return store;
+}
+
+static struct tnl_primitive_store *alloc_prim_store( GLcontext *ctx )
+{
+ struct tnl_primitive_store *store = MALLOC_STRUCT(tnl_primitive_store);
+ (void) ctx;
+ store->used = 0;
+ store->refcount = 1;
+ return store;
+}
+
+static void _save_reset_counters( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ tnl->save.prim = tnl->save.prim_store->buffer + tnl->save.prim_store->used;
+ tnl->save.buffer = (tnl->save.vertex_store->buffer +
+ tnl->save.vertex_store->used);
+
+ if (tnl->save.vertex_size)
+ tnl->save.initial_counter = ((SAVE_BUFFER_SIZE -
+ tnl->save.vertex_store->used) /
+ tnl->save.vertex_size);
+ else
+ tnl->save.initial_counter = 0;
+
+ if (tnl->save.initial_counter > ctx->Const.MaxArrayLockSize )
+ tnl->save.initial_counter = ctx->Const.MaxArrayLockSize;
+
+ tnl->save.counter = tnl->save.initial_counter;
+ tnl->save.prim_count = 0;
+ tnl->save.prim_max = SAVE_PRIM_SIZE - tnl->save.prim_store->used;
+ tnl->save.copied.nr = 0;
+ tnl->save.dangling_attr_ref = 0;
+}
+
+
+/* Insert the active immediate struct onto the display list currently
+ * being built.
+ */
+static void _save_compile_vertex_list( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_vertex_list *node;
+
+ /* Allocate space for this structure in the display list currently
+ * being compiled.
+ */
+ node = (struct tnl_vertex_list *)
+ _mesa_alloc_instruction(ctx, tnl->save.opcode_vertex_list, sizeof(*node));
+
+ if (!node)
+ return;
+
+ /* Duplicate our template, increment refcounts to the storage structs:
+ */
+ _mesa_memcpy(node->attrsz, tnl->save.attrsz, sizeof(node->attrsz));
+ node->vertex_size = tnl->save.vertex_size;
+ node->buffer = tnl->save.buffer;
+ node->count = tnl->save.initial_counter - tnl->save.counter;
+ node->wrap_count = tnl->save.copied.nr;
+ node->have_materials = tnl->save.have_materials;
+ node->dangling_attr_ref = tnl->save.dangling_attr_ref;
+ node->normal_lengths = NULL;
+ node->prim = tnl->save.prim;
+ node->prim_count = tnl->save.prim_count;
+ node->vertex_store = tnl->save.vertex_store;
+ node->prim_store = tnl->save.prim_store;
+
+ node->vertex_store->refcount++;
+ node->prim_store->refcount++;
+
+ assert(node->attrsz[_TNL_ATTRIB_POS] != 0 ||
+ node->count == 0);
+
+ if (tnl->save.dangling_attr_ref)
+ ctx->ListState.CurrentList->flags |= MESA_DLIST_DANGLING_REFS;
+
+ /* Maybe calculate normal lengths:
+ */
+ if (tnl->CalcDListNormalLengths &&
+ node->attrsz[_TNL_ATTRIB_NORMAL] == 3 &&
+ !(ctx->ListState.CurrentList->flags & MESA_DLIST_DANGLING_REFS))
+ build_normal_lengths( node );
+
+
+ tnl->save.vertex_store->used += tnl->save.vertex_size * node->count;
+ tnl->save.prim_store->used += node->prim_count;
+
+ /* Decide whether the storage structs are full, or can be used for
+ * the next vertex lists as well.
+ */
+ if (tnl->save.vertex_store->used >
+ SAVE_BUFFER_SIZE - 16 * (tnl->save.vertex_size + 4)) {
+
+ tnl->save.vertex_store->refcount--;
+ assert(tnl->save.vertex_store->refcount != 0);
+ tnl->save.vertex_store = alloc_vertex_store( ctx );
+ tnl->save.vbptr = tnl->save.vertex_store->buffer;
+ }
+
+ if (tnl->save.prim_store->used > SAVE_PRIM_SIZE - 6) {
+ tnl->save.prim_store->refcount--;
+ assert(tnl->save.prim_store->refcount != 0);
+ tnl->save.prim_store = alloc_prim_store( ctx );
+ }
+
+ /* Reset our structures for the next run of vertices:
+ */
+ _save_reset_counters( ctx );
+
+ /* Copy duplicated vertices
+ */
+ tnl->save.copied.nr = _save_copy_vertices( ctx, node );
+
+
+ /* Deal with GL_COMPILE_AND_EXECUTE:
+ */
+ if (ctx->ExecuteFlag) {
+ _tnl_playback_vertex_list( ctx, (void *) node );
+ }
+}
+
+
+/* TODO -- If no new vertices have been stored, don't bother saving
+ * it.
+ */
+static void _save_wrap_buffers( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i = tnl->save.prim_count - 1;
+ GLenum mode;
+
+ assert(i < (GLint) tnl->save.prim_max);
+ assert(i >= 0);
+
+ /* Close off in-progress primitive.
+ */
+ tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) -
+ tnl->save.prim[i].start);
+ mode = tnl->save.prim[i].mode & ~(PRIM_BEGIN|PRIM_END);
+
+ /* store the copied vertices, and allocate a new list.
+ */
+ _save_compile_vertex_list( ctx );
+
+ /* Restart interrupted primitive
+ */
+ tnl->save.prim[0].mode = mode;
+ tnl->save.prim[0].start = 0;
+ tnl->save.prim[0].count = 0;
+ tnl->save.prim_count = 1;
+}
+
+
+
+/* Called only when buffers are wrapped as the result of filling the
+ * vertex_store struct.
+ */
+static void _save_wrap_filled_vertex( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLfloat *data = tnl->save.copied.buffer;
+ GLuint i;
+
+ /* Emit a glEnd to close off the last vertex list.
+ */
+ _save_wrap_buffers( ctx );
+
+ /* Copy stored stored vertices to start of new list.
+ */
+ assert(tnl->save.counter > tnl->save.copied.nr);
+
+ for (i = 0 ; i < tnl->save.copied.nr ; i++) {
+ _mesa_memcpy( tnl->save.vbptr, data, tnl->save.vertex_size * sizeof(GLfloat));
+ data += tnl->save.vertex_size;
+ tnl->save.vbptr += tnl->save.vertex_size;
+ tnl->save.counter--;
+ }
+}
+
+
+static void _save_copy_to_current( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ /* XXX Use _TNL_FIRST_* and _TNL_LAST_* values instead? */
+ for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_EDGEFLAG ; i++) {
+ if (tnl->save.attrsz[i]) {
+ tnl->save.currentsz[i][0] = tnl->save.attrsz[i];
+ COPY_CLEAN_4V(tnl->save.current[i],
+ tnl->save.attrsz[i],
+ tnl->save.attrptr[i]);
+ }
+ }
+
+ /* Edgeflag requires special treatment:
+ *
+ * TODO: change edgeflag to GLfloat in Mesa.
+ */
+ if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
+ ctx->ListState.ActiveEdgeFlag = 1;
+ tnl->save.CurrentFloatEdgeFlag =
+ tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0];
+ ctx->ListState.CurrentEdgeFlag =
+ (tnl->save.CurrentFloatEdgeFlag == 1.0);
+ }
+}
+
+
+static void _save_copy_from_current( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i;
+
+ for (i = _TNL_ATTRIB_POS+1 ; i <= _TNL_ATTRIB_EDGEFLAG ; i++)
+ switch (tnl->save.attrsz[i]) {
+ case 4: tnl->save.attrptr[i][3] = tnl->save.current[i][3];
+ case 3: tnl->save.attrptr[i][2] = tnl->save.current[i][2];
+ case 2: tnl->save.attrptr[i][1] = tnl->save.current[i][1];
+ case 1: tnl->save.attrptr[i][0] = tnl->save.current[i][0];
+ case 0: break;
+ }
+
+ /* Edgeflag requires special treatment:
+ */
+ if (tnl->save.attrsz[_TNL_ATTRIB_EDGEFLAG]) {
+ tnl->save.CurrentFloatEdgeFlag = (GLfloat)ctx->ListState.CurrentEdgeFlag;
+ tnl->save.attrptr[_TNL_ATTRIB_EDGEFLAG][0] = tnl->save.CurrentFloatEdgeFlag;
+ }
+}
+
+
+
+
+/* Flush existing data, set new attrib size, replay copied vertices.
+ */
+static void _save_upgrade_vertex( GLcontext *ctx,
+ GLuint attr,
+ GLuint newsz )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint oldsz;
+ GLuint i;
+ GLfloat *tmp;
+
+ /* Store the current run of vertices, and emit a GL_END. Emit a
+ * BEGIN in the new buffer.
+ */
+ if (tnl->save.initial_counter != tnl->save.counter)
+ _save_wrap_buffers( ctx );
+ else
+ assert( tnl->save.copied.nr == 0 );
+
+ /* 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.
+ */
+ _save_copy_to_current( ctx );
+
+ /* Fix up sizes:
+ */
+ oldsz = tnl->save.attrsz[attr];
+ tnl->save.attrsz[attr] = newsz;
+
+ tnl->save.vertex_size += newsz - oldsz;
+ tnl->save.counter = ((SAVE_BUFFER_SIZE - tnl->save.vertex_store->used) /
+ tnl->save.vertex_size);
+ if (tnl->save.counter > ctx->Const.MaxArrayLockSize )
+ tnl->save.counter = ctx->Const.MaxArrayLockSize;
+ tnl->save.initial_counter = tnl->save.counter;
+
+ /* Recalculate all the attrptr[] values:
+ */
+ for (i = 0, tmp = tnl->save.vertex ; i < _TNL_ATTRIB_MAX ; i++) {
+ if (tnl->save.attrsz[i]) {
+ tnl->save.attrptr[i] = tmp;
+ tmp += tnl->save.attrsz[i];
+ }
+ else
+ tnl->save.attrptr[i] = NULL; /* will not be dereferenced. */
+ }
+
+ /* Copy from current to repopulate the vertex with correct values.
+ */
+ _save_copy_from_current( ctx );
+
+ /* Replay stored vertices to translate them to new format here.
+ *
+ * If there are copied vertices and the new (upgraded) attribute
+ * has not been defined before, this list is somewhat degenerate,
+ * and will need fixup at runtime.
+ */
+ if (tnl->save.copied.nr)
+ {
+ GLfloat *data = tnl->save.copied.buffer;
+ GLfloat *dest = tnl->save.buffer;
+ GLuint j;
+
+ /* Need to note this and fix up at runtime (or loopback):
+ */
+ if (tnl->save.currentsz[attr][0] == 0) {
+ assert(oldsz == 0);
+ tnl->save.dangling_attr_ref = GL_TRUE;
+
+/* _mesa_debug(NULL, "_save_upgrade_vertex: dangling reference attr %d\n", */
+/* attr); */
+
+#if 0
+ /* The current strategy is to punt these degenerate cases
+ * through _tnl_loopback_vertex_list(), a lower-performance
+ * option. To minimize the impact of this, artificially
+ * reduce the size of this vertex_list.
+ */
+ if (t->save.counter > 10) {
+ t->save.initial_counter = 10;
+ t->save.counter = 10;
+ }
+#endif
+ }
+
+ for (i = 0 ; i < tnl->save.copied.nr ; i++) {
+ for (j = 0 ; j < _TNL_ATTRIB_MAX ; j++) {
+ if (tnl->save.attrsz[j]) {
+ if (j == attr) {
+ if (oldsz) {
+ COPY_CLEAN_4V( dest, oldsz, data );
+ data += oldsz;
+ dest += newsz;
+ }
+ else {
+ COPY_SZ_4V( dest, newsz, tnl->save.current[attr] );
+ dest += newsz;
+ }
+ }
+ else {
+ GLint sz = tnl->save.attrsz[j];
+ COPY_SZ_4V( dest, sz, data );
+ data += sz;
+ dest += sz;
+ }
+ }
+ }
+ }
+
+ tnl->save.vbptr = dest;
+ tnl->save.counter -= tnl->save.copied.nr;
+ }
+}
+
+
+
+
+/* Helper function for 'CHOOSE' macro. Do what's necessary when an
+ * entrypoint is called for the first time.
+ */
+static void do_choose( GLuint attr, GLuint sz,
+ void (*attr_func)( const GLfloat *),
+ void (*choose1)( const GLfloat *),
+ void (*choose2)( const GLfloat *),
+ void (*choose3)( const GLfloat *),
+ void (*choose4)( const GLfloat *),
+ const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ static GLfloat id[4] = { 0, 0, 0, 1 };
+ int i;
+
+ if (tnl->save.attrsz[attr] < sz) {
+ /* New size is larger. Need to flush existing vertices and get
+ * an enlarged vertex format.
+ */
+ _save_upgrade_vertex( ctx, attr, sz );
+ }
+ else {
+ /* New size is equal or smaller - just need to fill in some
+ * zeros.
+ */
+ for (i = sz ; i <= tnl->save.attrsz[attr] ; i++)
+ tnl->save.attrptr[attr][i-1] = id[i-1];
+ }
+
+ /* Reset any active pointers for this attribute
+ */
+ tnl->save.tabfv[attr][0] = choose1;
+ tnl->save.tabfv[attr][1] = choose2;
+ tnl->save.tabfv[attr][2] = choose3;
+ tnl->save.tabfv[attr][3] = choose4;
+
+ /* Update the secondary dispatch table with the new function
+ */
+ tnl->save.tabfv[attr][sz-1] = attr_func;
+
+ (*attr_func)(v);
+}
+
+
+
+/* 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 ATTRFV( ATTR, N ) \
+static void save_choose_##ATTR##_##N( const GLfloat *v ); \
+ \
+static void save_attrib_##ATTR##_##N( const GLfloat *v ) \
+{ \
+ GET_CURRENT_CONTEXT( ctx ); \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ \
+ if ((ATTR) == 0) { \
+ GLuint i; \
+ \
+ if (N>0) tnl->save.vbptr[0] = v[0]; \
+ if (N>1) tnl->save.vbptr[1] = v[1]; \
+ if (N>2) tnl->save.vbptr[2] = v[2]; \
+ if (N>3) tnl->save.vbptr[3] = v[3]; \
+ \
+ for (i = N; i < tnl->save.vertex_size; i++) \
+ tnl->save.vbptr[i] = tnl->save.vertex[i]; \
+ \
+ tnl->save.vbptr += tnl->save.vertex_size; \
+ \
+ if (--tnl->save.counter == 0) \
+ _save_wrap_filled_vertex( ctx ); \
+ } \
+ else { \
+ GLfloat *dest = tnl->save.attrptr[ATTR]; \
+ if (N>0) dest[0] = v[0]; \
+ if (N>1) dest[1] = v[1]; \
+ if (N>2) dest[2] = v[2]; \
+ if (N>3) dest[3] = v[3]; \
+ } \
+}
+
+#define CHOOSE( ATTR, N ) \
+static void save_choose_##ATTR##_##N( const GLfloat *v ) \
+{ \
+ do_choose(ATTR, N, \
+ save_attrib_##ATTR##_##N, \
+ save_choose_##ATTR##_1, \
+ save_choose_##ATTR##_2, \
+ save_choose_##ATTR##_3, \
+ save_choose_##ATTR##_4, \
+ v ); \
+}
+
+#define INIT(ATTR) \
+static void save_init_##ATTR( TNLcontext *tnl ) \
+{ \
+ tnl->save.tabfv[ATTR][0] = save_choose_##ATTR##_1; \
+ tnl->save.tabfv[ATTR][1] = save_choose_##ATTR##_2; \
+ tnl->save.tabfv[ATTR][2] = save_choose_##ATTR##_3; \
+ tnl->save.tabfv[ATTR][3] = save_choose_##ATTR##_4; \
+}
+
+#define ATTRS( ATTRIB ) \
+ ATTRFV( ATTRIB, 1 ) \
+ ATTRFV( ATTRIB, 2 ) \
+ ATTRFV( ATTRIB, 3 ) \
+ ATTRFV( ATTRIB, 4 ) \
+ CHOOSE( ATTRIB, 1 ) \
+ CHOOSE( ATTRIB, 2 ) \
+ CHOOSE( ATTRIB, 3 ) \
+ CHOOSE( ATTRIB, 4 ) \
+ INIT( ATTRIB ) \
+
+
+/* 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 )
+
+ATTRS( 16 )
+ATTRS( 17 )
+ATTRS( 18 )
+ATTRS( 19 )
+ATTRS( 20 )
+ATTRS( 21 )
+ATTRS( 22 )
+ATTRS( 23 )
+ATTRS( 24 )
+ATTRS( 25 )
+ATTRS( 26 )
+ATTRS( 27 )
+ATTRS( 28 )
+ATTRS( 29 )
+ATTRS( 30 )
+ATTRS( 31 )
+
+
+static void _save_reset_vertex( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLuint i;
+
+ /* conventional attributes */
+ save_init_0( tnl );
+ save_init_1( tnl );
+ save_init_2( tnl );
+ save_init_3( tnl );
+ save_init_4( tnl );
+ save_init_5( tnl );
+ save_init_6( tnl );
+ save_init_7( tnl );
+ save_init_8( tnl );
+ save_init_9( tnl );
+ save_init_10( tnl );
+ save_init_11( tnl );
+ save_init_12( tnl );
+ save_init_13( tnl );
+ save_init_14( tnl );
+ save_init_15( tnl );
+
+ /* generic attributes */
+ save_init_16( tnl );
+ save_init_17( tnl );
+ save_init_18( tnl );
+ save_init_19( tnl );
+ save_init_20( tnl );
+ save_init_21( tnl );
+ save_init_22( tnl );
+ save_init_23( tnl );
+ save_init_24( tnl );
+ save_init_25( tnl );
+ save_init_26( tnl );
+ save_init_27( tnl );
+ save_init_28( tnl );
+ save_init_29( tnl );
+ save_init_30( tnl );
+ save_init_31( tnl );
+
+ for (i = 0 ; i < _TNL_ATTRIB_MAX ; i++)
+ tnl->save.attrsz[i] = 0;
+
+ tnl->save.vertex_size = 0;
+ tnl->save.have_materials = 0;
+
+ _save_reset_counters( ctx );
+}
+
+
+
+/* Cope with aliasing of classic Vertex, Normal, etc. and the fan-out
+ * of glMultTexCoord and glProgramParamterNV by routing all these
+ * through a second level dispatch table.
+ */
+#define DISPATCH_ATTRFV( ATTR, COUNT, P ) \
+do { \
+ GET_CURRENT_CONTEXT( ctx ); \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ tnl->save.tabfv[ATTR][COUNT-1]( P ); \
+} while (0)
+
+#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 )
+
+#define DISPATCH_ATTR1F( ATTR, S ) DISPATCH_ATTRFV( ATTR, 1, &(S) )
+
+#if defined(USE_X86_ASM) && 0 /* will break register calling convention */
+/* 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 void enum_error( void )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ _mesa_compile_error( ctx, GL_INVALID_ENUM, "glVertexAttrib" );
+}
+
+static void GLAPIENTRY _save_Vertex2f( GLfloat x, GLfloat y )
+{
+ DISPATCH_ATTR2F( _TNL_ATTRIB_POS, x, y );
+}
+
+static void GLAPIENTRY _save_Vertex2fv( const GLfloat *v )
+{
+ DISPATCH_ATTR2FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _save_Vertex3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_POS, x, y, z );
+}
+
+static void GLAPIENTRY _save_Vertex3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _save_Vertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_POS, x, y, z, w );
+}
+
+static void GLAPIENTRY _save_Vertex4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_POS, v );
+}
+
+static void GLAPIENTRY _save_TexCoord1f( GLfloat x )
+{
+ DISPATCH_ATTR1F( _TNL_ATTRIB_TEX0, x );
+}
+
+static void GLAPIENTRY _save_TexCoord1fv( const GLfloat *v )
+{
+ DISPATCH_ATTR1FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _save_TexCoord2f( GLfloat x, GLfloat y )
+{
+ DISPATCH_ATTR2F( _TNL_ATTRIB_TEX0, x, y );
+}
+
+static void GLAPIENTRY _save_TexCoord2fv( const GLfloat *v )
+{
+ DISPATCH_ATTR2FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _save_TexCoord3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_TEX0, x, y, z );
+}
+
+static void GLAPIENTRY _save_TexCoord3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _save_TexCoord4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_TEX0, x, y, z, w );
+}
+
+static void GLAPIENTRY _save_TexCoord4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_TEX0, v );
+}
+
+static void GLAPIENTRY _save_Normal3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_NORMAL, x, y, z );
+}
+
+static void GLAPIENTRY _save_Normal3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_NORMAL, v );
+}
+
+static void GLAPIENTRY _save_FogCoordfEXT( GLfloat x )
+{
+ DISPATCH_ATTR1F( _TNL_ATTRIB_FOG, x );
+}
+
+static void GLAPIENTRY _save_FogCoordfvEXT( const GLfloat *v )
+{
+ DISPATCH_ATTR1FV( _TNL_ATTRIB_FOG, v );
+}
+
+static void GLAPIENTRY _save_Color3f( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR0, x, y, z );
+}
+
+static void GLAPIENTRY _save_Color3fv( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY _save_Color4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+ DISPATCH_ATTR4F( _TNL_ATTRIB_COLOR0, x, y, z, w );
+}
+
+static void GLAPIENTRY _save_Color4fv( const GLfloat *v )
+{
+ DISPATCH_ATTR4FV( _TNL_ATTRIB_COLOR0, v );
+}
+
+static void GLAPIENTRY _save_SecondaryColor3fEXT( GLfloat x, GLfloat y, GLfloat z )
+{
+ DISPATCH_ATTR3F( _TNL_ATTRIB_COLOR1, x, y, z );
+}
+
+static void GLAPIENTRY _save_SecondaryColor3fvEXT( const GLfloat *v )
+{
+ DISPATCH_ATTR3FV( _TNL_ATTRIB_COLOR1, v );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord1f( GLenum target, GLfloat x )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR1F( attr, x );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord1fv( GLenum target, const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR1FV( attr, v );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord2f( GLenum target, GLfloat x, GLfloat y )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR2F( attr, x, y );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord2fv( GLenum target, const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR2FV( attr, v );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord3f( GLenum target, GLfloat x, GLfloat y,
+ GLfloat z)
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR3F( attr, x, y, z );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord3fv( GLenum target, const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR3FV( attr, v );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord4f( GLenum target, GLfloat x, GLfloat y,
+ GLfloat z, GLfloat w )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR4F( attr, x, y, z, w );
+}
+
+static void GLAPIENTRY _save_MultiTexCoord4fv( GLenum target, const GLfloat *v )
+{
+ GLuint attr = (target & 0x7) + _TNL_ATTRIB_TEX0;
+ DISPATCH_ATTR4FV( attr, v );
+}
+
+
+
+static void GLAPIENTRY
+_save_VertexAttrib1fNV(GLuint index, GLfloat x)
+{
+ if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR1F( index, x );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib1fvNV(GLuint index, const GLfloat *v)
+{
+ if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR1FV( index, v );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib2fNV(GLuint index, GLfloat x, GLfloat y)
+{
+ if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR2F( index, x, y );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib2fvNV(GLuint index, const GLfloat *v)
+{
+ if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR2FV( index, v );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib3fNV(GLuint index, GLfloat x, GLfloat y, GLfloat z)
+{
+ if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR3F( index, x, y, z );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib3fvNV(GLuint index, const GLfloat *v)
+{
+ if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR3FV( index, v );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib4fNV(GLuint index, GLfloat x, GLfloat y,
+ GLfloat z, GLfloat w)
+{
+ if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR4F( index, x, y, z, w );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib4fvNV(GLuint index, const GLfloat *v)
+{
+ if (index < MAX_VERTEX_PROGRAM_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR4FV( index, v );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib1fARB(GLuint index, GLfloat x)
+{
+ if (index < MAX_VERTEX_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR1F( index, x );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib1fvARB(GLuint index, const GLfloat *v)
+{
+ if (index < MAX_VERTEX_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR1FV( index, v );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib2fARB(GLuint index, GLfloat x, GLfloat y)
+{
+ if (index < MAX_VERTEX_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR2F( index, x, y );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib2fvARB(GLuint index, const GLfloat *v)
+{
+ if (index < MAX_VERTEX_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR2FV( index, v );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib3fARB(GLuint index, GLfloat x, GLfloat y, GLfloat z)
+{
+ if (index < MAX_VERTEX_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR3F( index, x, y, z );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib3fvARB(GLuint index, const GLfloat *v)
+{
+ if (index < MAX_VERTEX_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR3FV( index, v );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib4fARB(GLuint index, GLfloat x, GLfloat y,
+ GLfloat z, GLfloat w)
+{
+ if (index < MAX_VERTEX_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR4F( index, x, y, z, w );
+ }
+ else
+ enum_error();
+}
+
+static void GLAPIENTRY
+_save_VertexAttrib4fvARB(GLuint index, const GLfloat *v)
+{
+ if (index < MAX_VERTEX_ATTRIBS) {
+ if (index > 0)
+ index += VERT_ATTRIB_GENERIC0;
+ DISPATCH_ATTR4FV( index, v );
+ }
+ else
+ enum_error();
+}
+
+
+/* Materials:
+ *
+ * These are treated as per-vertex attributes, at indices above where
+ * the NV_vertex_program leaves off. There are a lot of good things
+ * about treating materials this way.
+ *
+ * However: I don't want to double the number of generated functions
+ * 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 ) \
+do { \
+ if (tnl->save.attrsz[A] < N) { \
+ _save_upgrade_vertex( ctx, A, N ); \
+ tnl->save.have_materials = GL_TRUE; \
+ } \
+ \
+ { \
+ GLfloat *dest = tnl->save.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 */ \
+} while (0)
+
+
+/* NOTE: Have to remove/deal-with colormaterial crossovers, probably
+ * later on - in the meantime just store everything.
+ */
+static void GLAPIENTRY _save_Materialfv( GLenum face, GLenum pname,
+ const GLfloat *params )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ switch (pname) {
+ case GL_EMISSION:
+ MAT( _TNL_ATTRIB_MAT_FRONT_EMISSION, 4, face, params );
+ break;
+ case GL_AMBIENT:
+ MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ break;
+ case GL_DIFFUSE:
+ MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ break;
+ case GL_SPECULAR:
+ MAT( _TNL_ATTRIB_MAT_FRONT_SPECULAR, 4, face, params );
+ break;
+ case GL_SHININESS:
+ MAT( _TNL_ATTRIB_MAT_FRONT_SHININESS, 1, face, params );
+ break;
+ case GL_COLOR_INDEXES:
+ MAT( _TNL_ATTRIB_MAT_FRONT_INDEXES, 3, face, params );
+ break;
+ case GL_AMBIENT_AND_DIFFUSE:
+ MAT( _TNL_ATTRIB_MAT_FRONT_AMBIENT, 4, face, params );
+ MAT( _TNL_ATTRIB_MAT_FRONT_DIFFUSE, 4, face, params );
+ break;
+ default:
+ _mesa_compile_error( ctx, GL_INVALID_ENUM, "glMaterialfv" );
+ return;
+ }
+}
+
+
+#define IDX_ATTR( A, IDX ) \
+do { \
+ GET_CURRENT_CONTEXT( ctx ); \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ \
+ if (tnl->save.attrsz[A] < 1) { \
+ _save_upgrade_vertex( ctx, A, 1 ); \
+ } \
+ \
+ { \
+ GLfloat *dest = tnl->save.attrptr[A]; \
+ dest[0] = IDX; \
+ } \
+} while (0)
+
+
+static void GLAPIENTRY _save_EdgeFlag( GLboolean b )
+{
+ IDX_ATTR( _TNL_ATTRIB_EDGEFLAG, (GLfloat)b );
+}
+
+
+static void GLAPIENTRY _save_Indexf( GLfloat f )
+{
+ IDX_ATTR( _TNL_ATTRIB_COLOR_INDEX, f );
+}
+
+static void GLAPIENTRY _save_Indexfv( const GLfloat *f )
+{
+ IDX_ATTR( _TNL_ATTRIB_COLOR_INDEX, f[0] );
+}
+
+
+
+
+/* Cope with EvalCoord/CallList called within a begin/end object:
+ * -- Flush current buffer
+ * -- Fallback to opcodes for the rest of the begin/end object.
+ */
+#define FALLBACK(ctx) \
+do { \
+ TNLcontext *tnl = TNL_CONTEXT(ctx); \
+ \
+ if (tnl->save.initial_counter != tnl->save.counter || \
+ tnl->save.prim_count) \
+ _save_compile_vertex_list( ctx ); \
+ \
+ _save_copy_to_current( ctx ); \
+ _save_reset_vertex( ctx ); \
+ _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt ); \
+ ctx->Driver.SaveNeedFlush = 0; \
+} while (0)
+
+static void GLAPIENTRY _save_EvalCoord1f( GLfloat u )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ CALL_EvalCoord1f(ctx->Save, ( u ));
+}
+
+static void GLAPIENTRY _save_EvalCoord1fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ CALL_EvalCoord1fv(ctx->Save, ( v ));
+}
+
+static void GLAPIENTRY _save_EvalCoord2f( GLfloat u, GLfloat v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ CALL_EvalCoord2f(ctx->Save, ( u, v ));
+}
+
+static void GLAPIENTRY _save_EvalCoord2fv( const GLfloat *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ CALL_EvalCoord2fv(ctx->Save, ( v ));
+}
+
+static void GLAPIENTRY _save_EvalPoint1( GLint i )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ CALL_EvalPoint1(ctx->Save, ( i ));
+}
+
+static void GLAPIENTRY _save_EvalPoint2( GLint i, GLint j )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ CALL_EvalPoint2(ctx->Save, ( i, j ));
+}
+
+static void GLAPIENTRY _save_CallList( GLuint l )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ CALL_CallList(ctx->Save, ( l ));
+}
+
+static void GLAPIENTRY _save_CallLists( GLsizei n, GLenum type, const GLvoid *v )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ FALLBACK(ctx);
+ CALL_CallLists(ctx->Save, ( n, type, v ));
+}
+
+
+
+
+/**
+ * Called via ctx->Driver.NotifySaveBegin(ctx, mode) when we get a
+ * glBegin() call while compiling a display list.
+ * See save_Begin() in dlist.c
+ *
+ * This plugs in our special TNL-related display list functions.
+ * All subsequent glBegin/glVertex/glEnd()s found while compiling a
+ * display list will get routed to the functions in this file.
+ *
+ * Updating of ctx->Driver.CurrentSavePrimitive is already taken care of.
+ */
+static GLboolean _save_NotifyBegin( GLcontext *ctx, GLenum mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ if (1) {
+ GLuint i = tnl->save.prim_count++;
+
+ assert(i < tnl->save.prim_max);
+ tnl->save.prim[i].mode = mode | PRIM_BEGIN;
+ tnl->save.prim[i].start = tnl->save.initial_counter - tnl->save.counter;
+ tnl->save.prim[i].count = 0;
+
+ _mesa_install_save_vtxfmt( ctx, &tnl->save_vtxfmt );
+ ctx->Driver.SaveNeedFlush = 1;
+ return GL_TRUE;
+ }
+ else
+ return GL_FALSE;
+}
+
+
+
+static void GLAPIENTRY _save_End( void )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i = tnl->save.prim_count - 1;
+
+ ctx->Driver.CurrentSavePrimitive = PRIM_OUTSIDE_BEGIN_END;
+ if (ctx->ExecuteFlag)
+ ctx->Driver.CurrentExecPrimitive = PRIM_OUTSIDE_BEGIN_END;
+
+ tnl->save.prim[i].mode |= PRIM_END;
+ tnl->save.prim[i].count = ((tnl->save.initial_counter - tnl->save.counter) -
+ tnl->save.prim[i].start);
+
+ if (i == (GLint) tnl->save.prim_max - 1) {
+ _save_compile_vertex_list( ctx );
+ assert(tnl->save.copied.nr == 0);
+ }
+
+ /* Swap out this vertex format while outside begin/end. Any color,
+ * etc. received between here and the next begin will be compiled
+ * as opcodes.
+ */
+ _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
+}
+
+
+/* These are all errors as this vtxfmt is only installed inside
+ * begin/end pairs.
+ */
+static void GLAPIENTRY _save_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) count; (void) type; (void) indices;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawElements" );
+}
+
+
+static void GLAPIENTRY _save_DrawRangeElements(GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) start; (void) end; (void) count; (void) type; (void) indices;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawRangeElements" );
+}
+
+static void GLAPIENTRY _save_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) start; (void) count;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glDrawArrays" );
+}
+
+static void GLAPIENTRY _save_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) x1; (void) y1; (void) x2; (void) y2;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glRectf" );
+}
+
+static void GLAPIENTRY _save_EvalMesh1( GLenum mode, GLint i1, GLint i2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) i1; (void) i2;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh1" );
+}
+
+static void GLAPIENTRY _save_EvalMesh2( GLenum mode, GLint i1, GLint i2,
+ GLint j1, GLint j2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ (void) mode; (void) i1; (void) i2; (void) j1; (void) j2;
+ _mesa_compile_error( ctx, GL_INVALID_OPERATION, "glEvalMesh2" );
+}
+
+/**
+ * This is only called if someone tries to compile nested glBegin()s
+ * in their display list.
+ */
+static void GLAPIENTRY _save_Begin( GLenum mode )
+{
+ GET_CURRENT_CONTEXT( ctx );
+ (void) mode;
+ _mesa_compile_error(ctx, GL_INVALID_OPERATION,
+ "glBegin(called inside glBegin/End)");
+}
+
+
+/* Unlike the functions above, these are to be hooked into the vtxfmt
+ * maintained in ctx->ListState, active when the list is known or
+ * suspected to be outside any begin/end primitive.
+ */
+static void GLAPIENTRY _save_OBE_Rectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _save_NotifyBegin( ctx, GL_QUADS | PRIM_WEAK );
+ 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 _save_OBE_DrawArrays(GLenum mode, GLint start, GLsizei count)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ if (!_mesa_validate_DrawArrays( ctx, mode, start, count ))
+ return;
+
+ _ae_map_vbos( ctx );
+
+ _save_NotifyBegin( ctx, mode | PRIM_WEAK );
+ for (i = 0; i < count; i++)
+ CALL_ArrayElement(GET_DISPATCH(), (start + i));
+ CALL_End(GET_DISPATCH(), ());
+
+ _ae_unmap_vbos( ctx );
+}
+
+
+static void GLAPIENTRY _save_OBE_DrawElements(GLenum mode, GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ if (!_mesa_validate_DrawElements( ctx, mode, count, type, indices ))
+ return;
+
+ _ae_map_vbos( ctx );
+
+ _save_NotifyBegin( ctx, mode | PRIM_WEAK );
+
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ for (i = 0 ; i < count ; i++)
+ CALL_ArrayElement(GET_DISPATCH(), ( ((GLubyte *)indices)[i] ));
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (i = 0 ; i < count ; i++)
+ CALL_ArrayElement(GET_DISPATCH(), ( ((GLushort *)indices)[i] ));
+ break;
+ case GL_UNSIGNED_INT:
+ for (i = 0 ; i < count ; i++)
+ CALL_ArrayElement(GET_DISPATCH(), ( ((GLuint *)indices)[i] ));
+ break;
+ default:
+ _mesa_error( ctx, GL_INVALID_ENUM, "glDrawElements(type)" );
+ break;
+ }
+
+ CALL_End(GET_DISPATCH(), ());
+
+ _ae_unmap_vbos( ctx );
+}
+
+static void GLAPIENTRY _save_OBE_DrawRangeElements(GLenum mode,
+ GLuint start, GLuint end,
+ GLsizei count, GLenum type,
+ const GLvoid *indices)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ if (_mesa_validate_DrawRangeElements( ctx, mode,
+ start, end,
+ count, type, indices ))
+ _save_OBE_DrawElements( mode, count, type, indices );
+}
+
+
+
+
+
+static void _save_vtxfmt_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLvertexformat *vfmt = &tnl->save_vtxfmt;
+
+ vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */
+ vfmt->Begin = _save_Begin;
+ vfmt->Color3f = _save_Color3f;
+ vfmt->Color3fv = _save_Color3fv;
+ vfmt->Color4f = _save_Color4f;
+ vfmt->Color4fv = _save_Color4fv;
+ vfmt->EdgeFlag = _save_EdgeFlag;
+ vfmt->End = _save_End;
+ vfmt->FogCoordfEXT = _save_FogCoordfEXT;
+ vfmt->FogCoordfvEXT = _save_FogCoordfvEXT;
+ vfmt->Indexf = _save_Indexf;
+ vfmt->Indexfv = _save_Indexfv;
+ vfmt->Materialfv = _save_Materialfv;
+ vfmt->MultiTexCoord1fARB = _save_MultiTexCoord1f;
+ vfmt->MultiTexCoord1fvARB = _save_MultiTexCoord1fv;
+ vfmt->MultiTexCoord2fARB = _save_MultiTexCoord2f;
+ vfmt->MultiTexCoord2fvARB = _save_MultiTexCoord2fv;
+ vfmt->MultiTexCoord3fARB = _save_MultiTexCoord3f;
+ vfmt->MultiTexCoord3fvARB = _save_MultiTexCoord3fv;
+ vfmt->MultiTexCoord4fARB = _save_MultiTexCoord4f;
+ vfmt->MultiTexCoord4fvARB = _save_MultiTexCoord4fv;
+ vfmt->Normal3f = _save_Normal3f;
+ vfmt->Normal3fv = _save_Normal3fv;
+ vfmt->SecondaryColor3fEXT = _save_SecondaryColor3fEXT;
+ vfmt->SecondaryColor3fvEXT = _save_SecondaryColor3fvEXT;
+ vfmt->TexCoord1f = _save_TexCoord1f;
+ vfmt->TexCoord1fv = _save_TexCoord1fv;
+ vfmt->TexCoord2f = _save_TexCoord2f;
+ vfmt->TexCoord2fv = _save_TexCoord2fv;
+ vfmt->TexCoord3f = _save_TexCoord3f;
+ vfmt->TexCoord3fv = _save_TexCoord3fv;
+ vfmt->TexCoord4f = _save_TexCoord4f;
+ vfmt->TexCoord4fv = _save_TexCoord4fv;
+ vfmt->Vertex2f = _save_Vertex2f;
+ vfmt->Vertex2fv = _save_Vertex2fv;
+ vfmt->Vertex3f = _save_Vertex3f;
+ vfmt->Vertex3fv = _save_Vertex3fv;
+ vfmt->Vertex4f = _save_Vertex4f;
+ vfmt->Vertex4fv = _save_Vertex4fv;
+ vfmt->VertexAttrib1fNV = _save_VertexAttrib1fNV;
+ vfmt->VertexAttrib1fvNV = _save_VertexAttrib1fvNV;
+ vfmt->VertexAttrib2fNV = _save_VertexAttrib2fNV;
+ vfmt->VertexAttrib2fvNV = _save_VertexAttrib2fvNV;
+ vfmt->VertexAttrib3fNV = _save_VertexAttrib3fNV;
+ vfmt->VertexAttrib3fvNV = _save_VertexAttrib3fvNV;
+ vfmt->VertexAttrib4fNV = _save_VertexAttrib4fNV;
+ vfmt->VertexAttrib4fvNV = _save_VertexAttrib4fvNV;
+ vfmt->VertexAttrib1fARB = _save_VertexAttrib1fARB;
+ vfmt->VertexAttrib1fvARB = _save_VertexAttrib1fvARB;
+ vfmt->VertexAttrib2fARB = _save_VertexAttrib2fARB;
+ vfmt->VertexAttrib2fvARB = _save_VertexAttrib2fvARB;
+ vfmt->VertexAttrib3fARB = _save_VertexAttrib3fARB;
+ vfmt->VertexAttrib3fvARB = _save_VertexAttrib3fvARB;
+ vfmt->VertexAttrib4fARB = _save_VertexAttrib4fARB;
+ vfmt->VertexAttrib4fvARB = _save_VertexAttrib4fvARB;
+
+ /* This will all require us to fallback to saving the list as opcodes:
+ */
+ vfmt->CallList = _save_CallList; /* inside begin/end */
+ vfmt->CallLists = _save_CallLists; /* inside begin/end */
+ vfmt->EvalCoord1f = _save_EvalCoord1f;
+ vfmt->EvalCoord1fv = _save_EvalCoord1fv;
+ vfmt->EvalCoord2f = _save_EvalCoord2f;
+ vfmt->EvalCoord2fv = _save_EvalCoord2fv;
+ vfmt->EvalPoint1 = _save_EvalPoint1;
+ vfmt->EvalPoint2 = _save_EvalPoint2;
+
+ /* These are all errors as we at least know we are in some sort of
+ * begin/end pair:
+ */
+ vfmt->EvalMesh1 = _save_EvalMesh1;
+ vfmt->EvalMesh2 = _save_EvalMesh2;
+ vfmt->Begin = _save_Begin;
+ vfmt->Rectf = _save_Rectf;
+ vfmt->DrawArrays = _save_DrawArrays;
+ vfmt->DrawElements = _save_DrawElements;
+ vfmt->DrawRangeElements = _save_DrawRangeElements;
+
+}
+
+
+void _tnl_SaveFlushVertices( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* Noop when we are actually active:
+ */
+ if (ctx->Driver.CurrentSavePrimitive == PRIM_INSIDE_UNKNOWN_PRIM ||
+ ctx->Driver.CurrentSavePrimitive <= GL_POLYGON)
+ return;
+
+ if (tnl->save.initial_counter != tnl->save.counter ||
+ tnl->save.prim_count)
+ _save_compile_vertex_list( ctx );
+
+ _save_copy_to_current( ctx );
+ _save_reset_vertex( ctx );
+ ctx->Driver.SaveNeedFlush = 0;
+}
+
+void _tnl_NewList( GLcontext *ctx, GLuint list, GLenum mode )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ (void) list; (void) mode;
+
+ if (!tnl->save.prim_store)
+ tnl->save.prim_store = alloc_prim_store( ctx );
+
+ if (!tnl->save.vertex_store) {
+ tnl->save.vertex_store = alloc_vertex_store( ctx );
+ tnl->save.vbptr = tnl->save.vertex_store->buffer;
+ }
+
+ _save_reset_vertex( ctx );
+ ctx->Driver.SaveNeedFlush = 0;
+}
+
+void _tnl_EndList( GLcontext *ctx )
+{
+ (void) ctx;
+ assert(TNL_CONTEXT(ctx)->save.vertex_size == 0);
+}
+
+void _tnl_BeginCallList( GLcontext *ctx, struct mesa_display_list *dlist )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ tnl->save.replay_flags |= dlist->flags;
+ tnl->save.replay_flags |= tnl->LoopbackDListCassettes;
+}
+
+void _tnl_EndCallList( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ if (ctx->ListState.CallDepth == 1)
+ tnl->save.replay_flags = 0;
+}
+
+
+static void _tnl_destroy_vertex_list( GLcontext *ctx, void *data )
+{
+ struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
+ (void) ctx;
+
+ if ( --node->vertex_store->refcount == 0 )
+ FREE( node->vertex_store );
+
+ if ( --node->prim_store->refcount == 0 )
+ FREE( node->prim_store );
+
+ if ( node->normal_lengths )
+ FREE( node->normal_lengths );
+}
+
+
+static void _tnl_print_vertex_list( GLcontext *ctx, void *data )
+{
+ struct tnl_vertex_list *node = (struct tnl_vertex_list *)data;
+ GLuint i;
+ (void) ctx;
+
+ _mesa_debug(NULL, "TNL-VERTEX-LIST, %u vertices %d primitives, %d vertsize\n",
+ node->count,
+ node->prim_count,
+ node->vertex_size);
+
+ for (i = 0 ; i < node->prim_count ; i++) {
+ struct tnl_prim *prim = &node->prim[i];
+ _mesa_debug(NULL, " prim %d: %s %d..%d %s %s\n",
+ i,
+ _mesa_lookup_enum_by_nr(prim->mode & PRIM_MODE_MASK),
+ prim->start,
+ prim->start + prim->count,
+ (prim->mode & PRIM_BEGIN) ? "BEGIN" : "(wrap)",
+ (prim->mode & PRIM_END) ? "END" : "(wrap)");
+ }
+}
+
+
+static void _save_current_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ GLint i;
+
+ for (i = 0; i < _TNL_ATTRIB_MAT_FRONT_AMBIENT; i++) {
+ ASSERT(i < VERT_ATTRIB_MAX);
+ tnl->save.currentsz[i] = &ctx->ListState.ActiveAttribSize[i];
+ tnl->save.current[i] = ctx->ListState.CurrentAttrib[i];
+ }
+
+ for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) {
+ const GLuint j = i - _TNL_FIRST_MAT;
+ ASSERT(j < MAT_ATTRIB_MAX);
+ tnl->save.currentsz[i] = &ctx->ListState.ActiveMaterialSize[j];
+ tnl->save.current[i] = ctx->ListState.CurrentMaterial[j];
+ }
+
+ tnl->save.currentsz[_TNL_ATTRIB_EDGEFLAG] = &ctx->ListState.ActiveEdgeFlag;
+ tnl->save.current[_TNL_ATTRIB_EDGEFLAG] = &tnl->save.CurrentFloatEdgeFlag;
+}
+
+/**
+ * Initialize the display list compiler
+ */
+void _tnl_save_init( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+ struct tnl_vertex_arrays *tmp = &tnl->save_inputs;
+ GLuint i;
+
+
+ for (i = 0; i < _TNL_ATTRIB_MAX; i++)
+ _mesa_vector4f_init( &tmp->Attribs[i], 0, NULL);
+
+ tnl->save.opcode_vertex_list =
+ _mesa_alloc_opcode( ctx,
+ sizeof(struct tnl_vertex_list),
+ _tnl_playback_vertex_list,
+ _tnl_destroy_vertex_list,
+ _tnl_print_vertex_list );
+
+ ctx->Driver.NotifySaveBegin = _save_NotifyBegin;
+
+ _save_vtxfmt_init( ctx );
+ _save_current_init( ctx );
+
+ /* Hook our array functions into the outside-begin-end vtxfmt in
+ * ctx->ListState.
+ */
+ ctx->ListState.ListVtxfmt.Rectf = _save_OBE_Rectf;
+ ctx->ListState.ListVtxfmt.DrawArrays = _save_OBE_DrawArrays;
+ ctx->ListState.ListVtxfmt.DrawElements = _save_OBE_DrawElements;
+ ctx->ListState.ListVtxfmt.DrawRangeElements = _save_OBE_DrawRangeElements;
+ _mesa_install_save_vtxfmt( ctx, &ctx->ListState.ListVtxfmt );
+}
+
+
+/**
+ * Deallocate the immediate-mode buffer for the given context, if
+ * its reference count goes to zero.
+ */
+void _tnl_save_destroy( GLcontext *ctx )
+{
+ TNLcontext *tnl = TNL_CONTEXT(ctx);
+
+ /* Decrement the refcounts. References may still be held by
+ * display lists yet to be destroyed, so it may not yet be time to
+ * free these items.
+ */
+ if (tnl->save.prim_store &&
+ --tnl->save.prim_store->refcount == 0 )
+ FREE( tnl->save.prim_store );
+
+ if (tnl->save.vertex_store &&
+ --tnl->save.vertex_store->refcount == 0 )
+ FREE( tnl->save.vertex_store );
+}
diff --git a/src/mesa/tnl/t_vb_arbprogram.c b/src/mesa/tnl/t_vb_arbprogram.c
index 4c8f967fdff..b322d48b231 100644
--- a/src/mesa/tnl/t_vb_arbprogram.c
+++ b/src/mesa/tnl/t_vb_arbprogram.c
@@ -1,8 +1,8 @@
/*
* Mesa 3-D graphics library
- * Version: 6.5.1
+ * Version: 6.5.3
*
- * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -37,12 +37,15 @@
#include "arbprogparse.h"
#include "light.h"
#include "program.h"
+#include "prog_instruction.h"
+#include "prog_parameter.h"
+#include "prog_statevars.h"
+#include "programopt.h"
#include "math/m_matrix.h"
#include "t_context.h"
#include "t_pipeline.h"
#include "t_vb_arbprogram.h"
#include "tnl.h"
-#include "program_instruction.h"
#define DISASSEM 0
@@ -292,7 +295,7 @@ static void do_EX2( struct arb_vp_machine *m, union instruction op )
GLfloat *result = m->File[0][op.alu.dst];
const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
- result[0] = (GLfloat)ApproxExp2(arg0[0]);
+ result[0] = ApproxExp2(arg0[0]);
PUFF(result);
}
@@ -335,6 +338,17 @@ static void do_FRC( struct arb_vp_machine *m, union instruction op )
result[3] = arg0[3] - FLOORF(arg0[3]);
}
+static void do_INT( struct arb_vp_machine *m, union instruction op )
+{
+ GLfloat *result = m->File[0][op.alu.dst];
+ const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
+
+ result[0] = (GLfloat) (GLint) arg0[0];
+ result[1] = (GLfloat) (GLint) arg0[1];
+ result[2] = (GLfloat) (GLint) arg0[2];
+ result[3] = (GLfloat) (GLint) arg0[3];
+}
+
/* High precision log base 2:
*/
static void do_LG2( struct arb_vp_machine *m, union instruction op )
@@ -566,7 +580,7 @@ static void print_reg( GLuint file, GLuint reg )
_mesa_printf("TMP%d", reg - REG_TMP0);
else if (reg >= REG_IN0 && reg <= REG_IN31)
_mesa_printf("IN%d", reg - REG_IN0);
- else if (reg >= REG_OUT0 && reg <= REG_OUT14)
+ else if (reg >= REG_OUT0 && reg <= REG_OUT23)
_mesa_printf("OUT%d", reg - REG_OUT0);
else if (reg == REG_ADDR)
_mesa_printf("ADDR");
@@ -662,6 +676,7 @@ _tnl_disassem_vba_insn( union instruction op )
case OPCODE_EXP:
case OPCODE_FLR:
case OPCODE_FRC:
+ case OPCODE_INT:
case OPCODE_LG2:
case OPCODE_LIT:
case OPCODE_LOG:
@@ -711,18 +726,24 @@ _tnl_disassem_vba_insn( union instruction op )
}
}
+typedef void (*gpu_function)(struct arb_vp_machine *m, union instruction op);
-static void (* const opcode_func[MAX_OPCODE+3])(struct arb_vp_machine *, union instruction) =
+static gpu_function opcode_func[MAX_OPCODE+3] =
{
+ do_NOP,
do_ABS,
do_ADD,
do_NOP,/*ARA*/
do_NOP,/*ARL*/
do_NOP,/*ARL_NV*/
do_NOP,/*ARR*/
+ do_NOP,/*BGNLOOP*/
+ do_NOP,/*BGNSUB*/
do_NOP,/*BRA*/
+ do_NOP,/*BRK*/
do_NOP,/*CAL*/
do_NOP,/*CMP*/
+ do_NOP,/*CONT*/
do_NOP,/*COS*/
do_NOP,/*DDX*/
do_NOP,/*DDY*/
@@ -730,11 +751,17 @@ static void (* const opcode_func[MAX_OPCODE+3])(struct arb_vp_machine *, union i
do_DP4,
do_DPH,
do_DST,
- do_NOP,
+ do_NOP,/*ELSE*/
+ do_NOP,/*END*/
+ do_NOP,/*ENDIF*/
+ do_NOP,/*ENDLOOP*/
+ do_NOP,/*ENDSUB*/
do_EX2,
do_EXP,
do_FLR,
do_FRC,
+ do_NOP,/*IF*/
+ do_INT,
do_NOP,/*KIL*/
do_NOP,/*KIL_NV*/
do_LG2,
@@ -746,6 +773,10 @@ static void (* const opcode_func[MAX_OPCODE+3])(struct arb_vp_machine *, union i
do_MIN,
do_MOV,
do_MUL,
+ do_NOP,/*NOISE1*/
+ do_NOP,/*NOISE2*/
+ do_NOP,/*NOISE3*/
+ do_NOP,/*NOISE4*/
do_NOP,/*PK2H*/
do_NOP,/*PK2US*/
do_NOP,/*PK4B*/
@@ -828,6 +859,7 @@ static struct reg cvp_load_reg( struct compilation *cp,
switch (file) {
case PROGRAM_TEMPORARY:
+ assert(REG_TMP0 + index <= REG_TMP11);
return cvp_make_reg(FILE_REG, REG_TMP0 + index);
case PROGRAM_INPUT:
@@ -853,6 +885,8 @@ static struct reg cvp_load_reg( struct compilation *cp,
return reg;
case PROGRAM_STATE_VAR:
+ case PROGRAM_CONSTANT:
+ case PROGRAM_UNIFORM:
reg = cvp_make_reg(FILE_STATE_PARAM, index);
if (rel)
return cvp_emit_rel(cp, reg, tmpreg);
@@ -864,7 +898,7 @@ static struct reg cvp_load_reg( struct compilation *cp,
case PROGRAM_WRITE_ONLY:
case PROGRAM_ADDRESS:
default:
- _mesa_problem(NULL, "Invalid register file %d in cvp_load_reg()");
+ _mesa_problem(NULL, "Invalid register file %d in cvp_load_reg()", file);
assert(0);
return tmpreg; /* can't happen */
}
@@ -925,7 +959,10 @@ static GLuint cvp_choose_result( struct compilation *cp,
idx = REG_OUT0 + dst->Index;
break;
default:
+#if 0
+ /* IF/ELSE/ENDIF instructions will hit this */
assert(0);
+#endif
return REG_RES; /* can't happen */
}
@@ -1020,6 +1057,13 @@ static void cvp_emit_inst( struct compilation *cp,
}
break;
+ case OPCODE_NOP:
+ break;
+
+ case OPCODE_BRA:
+ /* XXX implement */
+ break;
+
default:
result = cvp_choose_result( cp, &inst->DstReg, &fixup );
nr_args = _mesa_num_inst_src_regs(inst->Opcode);
@@ -1058,6 +1102,16 @@ static void compile_vertex_program( struct gl_vertex_program *program,
struct tnl_compiled_program *p = CALLOC_STRUCT(tnl_compiled_program);
GLint i;
+#if 1
+ if (!program->IsNVProgram && program->IsPositionInvariant) {
+ printf("Adding MVP code\n");
+ if (!program->Base.Parameters)
+ program->Base.Parameters = _mesa_new_parameter_list();
+ _mesa_insert_mvp_code(NULL, program);
+ program->IsPositionInvariant = 0;
+ }
+#endif
+
if (program->TnlData)
free_tnl_data( program );
@@ -1097,7 +1151,6 @@ static void compile_vertex_program( struct gl_vertex_program *program,
-
/* ----------------------------------------------------------------------
* Execution
*/
@@ -1182,6 +1235,7 @@ do_ndc_cliptest(GLcontext *ctx, struct arb_vp_machine *m)
/* Test userclip planes. This contributes to VB->ClipMask.
*/
+ /** XXX NEW_SLANG _Enabled ??? */
if (ctx->Transform.ClipPlanesEnabled && (!ctx->VertexProgram._Enabled ||
ctx->VertexProgram.Current->IsPositionInvariant)) {
userclip( ctx,
@@ -1209,6 +1263,7 @@ static INLINE void call_func( struct tnl_compiled_program *p,
p->compiled_func(m);
}
+
/**
* Execute the given vertex program.
*
@@ -1221,22 +1276,20 @@ static INLINE void call_func( struct tnl_compiled_program *p,
static GLboolean
run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
{
- const struct gl_vertex_program *program;
+ const struct gl_vertex_program *program = ctx->VertexProgram._Current;
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
struct tnl_compiled_program *p;
GLuint i, j;
GLbitfield outputs;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- program = ctx->VertexProgram._Enabled ? ctx->VertexProgram.Current : NULL;
- if (!program && ctx->_MaintainTnlProgram) {
- program = ctx->_TnlProgram;
- }
- if (!program || program->IsNVProgram)
+#define FORCE_PROG_EXECUTE_C 1
+#if FORCE_PROG_EXECUTE_C
+ return GL_TRUE;
+#else
+ if (!program)
return GL_TRUE;
+#endif
if (program->Base.Parameters) {
_mesa_load_state_parameters(ctx, program->Base.Parameters);
@@ -1279,7 +1332,13 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
case 2: m->File[0][idx][1] = m->input[j].data[1];
case 1: m->File[0][idx][0] = m->input[j].data[0];
}
-
+#if 0
+ printf(" attr %d/%d: %g %g %g %g\n", j, idx-REG_IN0,
+ m->input[j].data[0],
+ m->input[j].data[1],
+ m->input[j].data[2],
+ m->input[j].data[3]);
+#endif
STRIDE_F(m->input[j].data, m->input[j].stride);
}
@@ -1288,9 +1347,9 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
call_func( p, m );
}
else {
- GLint j;
- for (j = 0; j < p->nr_instructions; j++) {
- union instruction inst = p->instructions[j];
+ GLint pc;
+ for (pc = 0; pc < p->nr_instructions; pc++) {
+ union instruction inst = p->instructions[pc];
opcode_func[inst.alu.opcode]( m, inst );
}
}
@@ -1384,6 +1443,14 @@ run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
}
}
+ for (i = 0; i < ctx->Const.MaxVarying; i++) {
+ if (outputs & (1 << (VERT_RESULT_VAR0 + i))) {
+ /* Note: varying results get put into the generic attributes */
+ VB->AttribPtr[VERT_ATTRIB_GENERIC0+i]
+ = &m->attribs[VERT_RESULT_VAR0 + i];
+ }
+ }
+
#if 0
for (i = 0; i < VB->Count; i++) {
printf("Out %d: %f %f %f %f %f %f %f %f\n", i,
@@ -1408,17 +1475,13 @@ static void
validate_vertex_program( GLcontext *ctx, struct tnl_pipeline_stage *stage )
{
struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
- struct gl_vertex_program *program;
-
- if (ctx->ShaderObjects._VertexShaderPresent)
- return;
-
- program = (ctx->VertexProgram._Enabled ? ctx->VertexProgram.Current : 0);
- if (!program && ctx->_MaintainTnlProgram) {
- program = ctx->_TnlProgram;
- }
+ struct gl_vertex_program *program = ctx->VertexProgram._Current;
+#if FORCE_OLD
+ if (0 &&program) {
+#else
if (program) {
+#endif
if (!program->TnlData)
compile_vertex_program( program, m->try_codegen );
@@ -1435,11 +1498,6 @@ validate_vertex_program( GLcontext *ctx, struct tnl_pipeline_stage *stage )
}
-
-
-
-
-
/**
* Called the first time stage->run is called. In effect, don't
* allocate data until the first time the stage is run.
@@ -1453,6 +1511,10 @@ static GLboolean init_vertex_program( GLcontext *ctx,
const GLuint size = VB->Size;
GLuint i;
+ /* spot checks to be sure the opcode table is correct */
+ assert(opcode_func[OPCODE_SGE] == do_SGE);
+ assert(opcode_func[OPCODE_XPD] == do_XPD);
+
stage->privatePtr = _mesa_calloc(sizeof(*m));
m = ARB_VP_MACHINE(stage);
if (!m)
@@ -1486,7 +1548,7 @@ static GLboolean init_vertex_program( GLcontext *ctx,
_mesa_vector4f_alloc( &m->ndcCoords, 0, size, 32 );
m->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
- if (ctx->_MaintainTnlProgram)
+ if (ctx->VertexProgram._MaintainTnlProgram)
_mesa_allow_light_in_model( ctx, GL_FALSE );
m->fpucntl_rnd_neg = RND_NEG_FPU; /* const value */
@@ -1496,8 +1558,6 @@ static GLboolean init_vertex_program( GLcontext *ctx,
}
-
-
/**
* Destructor for this pipeline stage.
*/
@@ -1522,6 +1582,7 @@ static void dtr( struct tnl_pipeline_stage *stage )
}
}
+
/**
* Public description of this pipeline stage.
*/
@@ -1543,7 +1604,7 @@ const struct tnl_pipeline_stage _tnl_arb_vertex_program_stage =
void
_tnl_program_string(GLcontext *ctx, GLenum target, struct gl_program *program)
{
- if (target == GL_VERTEX_PROGRAM_ARB) {
+ if (program->Target == GL_VERTEX_PROGRAM_ARB) {
/* free any existing tnl data hanging off the program */
struct gl_vertex_program *vprog = (struct gl_vertex_program *) program;
if (vprog->TnlData) {
diff --git a/src/mesa/tnl/t_vb_arbprogram.h b/src/mesa/tnl/t_vb_arbprogram.h
index 6de8dca328c..1bec2a411e8 100644
--- a/src/mesa/tnl/t_vb_arbprogram.h
+++ b/src/mesa/tnl/t_vb_arbprogram.h
@@ -56,6 +56,22 @@
#define REG_TMP0 5
#define REG_TMP11 16
#define REG_OUT0 17
+#define REG_OUT23 40
+#define REG_IN0 41
+#define REG_IN31 72
+#define REG_ID 73 /* 0,0,0,1 */
+#define REG_ONES 74 /* 1,1,1,1 */
+#define REG_SWZ 75 /* 1,-1,0,0 */
+#define REG_NEG 76 /* -1,-1,-1,-1 */
+#define REG_LIT 77 /* 1,0,0,1 */
+#define REG_LIT2 78 /* 1,0,0,1 */
+#define REG_SCRATCH 79 /* internal temporary. XXX we can't actually use this because 70 doesn't fit in the 5-bit 'dst' instruction field! */
+#define REG_UNDEF 127 /* special case - never used */
+#define REG_MAX 128
+#define REG_INVALID ~0
+
+
+#if 0
#define REG_OUT14 31
#define REG_IN0 32
#define REG_IN31 63
@@ -69,6 +85,7 @@
#define REG_UNDEF 127 /* special case - never used */
#define REG_MAX 128
#define REG_INVALID ~0
+#endif
/* ARB_vp instructions are broken down into one or more of the
* following micro-instructions, each representable in a 64 bit packed
@@ -76,16 +93,16 @@
*/
struct reg {
GLuint file:2;
- GLuint idx:7;
+ GLuint idx:8;
};
union instruction {
struct {
GLuint opcode:7;
- GLuint dst:5;
+ GLuint dst:6;
GLuint file0:2;
- GLuint idx0:7;
+ GLuint idx0:8;
GLuint file1:2;
GLuint idx1:7;
GLuint pad:2;
@@ -94,18 +111,18 @@ union instruction {
struct {
GLuint opcode:7;
- GLuint dst:5;
+ GLuint dst:6;
GLuint file0:2;
- GLuint idx0:7;
+ GLuint idx0:8;
GLuint neg:4;
GLuint swz:12; /* xyzw01 */
} rsw;
struct {
GLuint opcode:7;
- GLuint dst:5;
+ GLuint dst:6;
GLuint file:2;
- GLuint idx:7;
+ GLuint idx:8;
GLuint mask:4;
GLuint pad:7;
GLuint pad2;
diff --git a/src/mesa/tnl/t_vb_arbprogram_sse.c b/src/mesa/tnl/t_vb_arbprogram_sse.c
index b9126d6d886..d0f66fd6196 100644
--- a/src/mesa/tnl/t_vb_arbprogram_sse.c
+++ b/src/mesa/tnl/t_vb_arbprogram_sse.c
@@ -43,7 +43,7 @@
#include "mtypes.h"
#include "arbprogparse.h"
#include "program.h"
-#include "program_instruction.h"
+#include "prog_instruction.h"
#include "math/m_matrix.h"
#include "math/m_translate.h"
#include "t_context.h"
diff --git a/src/mesa/tnl/t_vb_arbshader.c b/src/mesa/tnl/t_vb_arbshader.c
deleted file mode 100644
index 13aa3ea9105..00000000000
--- a/src/mesa/tnl/t_vb_arbshader.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5
- *
- * Copyright (C) 2006 Brian Paul All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Michal Krol
- */
-
-#include "glheader.h"
-#include "imports.h"
-#include "macros.h"
-#include "shaderobjects.h"
-#include "shaderobjects_3dlabs.h"
-#include "t_pipeline.h"
-#include "slang_utility.h"
-#include "slang_link.h"
-
-#if FEATURE_ARB_vertex_shader
-
-typedef struct
-{
- GLvector4f outputs[VERT_RESULT_MAX];
- GLvector4f varyings[MAX_VARYING_VECTORS];
- GLvector4f ndc_coords;
- GLubyte *clipmask;
- GLubyte ormask;
- GLubyte andmask;
-} arbvs_stage_data;
-
-#define ARBVS_STAGE_DATA(stage) ((arbvs_stage_data *) stage->privatePtr)
-
-static GLboolean construct_arb_vertex_shader (GLcontext *ctx, struct tnl_pipeline_stage *stage)
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct vertex_buffer *vb = &tnl->vb;
- arbvs_stage_data *store;
- GLuint size = vb->Size;
- GLuint i;
-
- stage->privatePtr = _mesa_malloc (sizeof (arbvs_stage_data));
- store = ARBVS_STAGE_DATA(stage);
- if (store == NULL)
- return GL_FALSE;
-
- for (i = 0; i < VERT_RESULT_MAX; i++)
- {
- _mesa_vector4f_alloc (&store->outputs[i], 0, size, 32);
- store->outputs[i].size = 4;
- }
- for (i = 0; i < MAX_VARYING_VECTORS; i++)
- {
- _mesa_vector4f_alloc (&store->varyings[i], 0, size, 32);
- store->varyings[i].size = 4;
- }
- _mesa_vector4f_alloc (&store->ndc_coords, 0, size, 32);
- store->clipmask = (GLubyte *) ALIGN_MALLOC (size, 32);
-
- return GL_TRUE;
-}
-
-static void destruct_arb_vertex_shader (struct tnl_pipeline_stage *stage)
-{
- arbvs_stage_data *store = ARBVS_STAGE_DATA(stage);
-
- if (store != NULL)
- {
- GLuint i;
-
- for (i = 0; i < VERT_RESULT_MAX; i++)
- _mesa_vector4f_free (&store->outputs[i]);
- for (i = 0; i < MAX_VARYING_VECTORS; i++)
- _mesa_vector4f_free (&store->varyings[i]);
- _mesa_vector4f_free (&store->ndc_coords);
- ALIGN_FREE (store->clipmask);
-
- _mesa_free (store);
- stage->privatePtr = NULL;
- }
-}
-
-static void validate_arb_vertex_shader (GLcontext *ctx, struct tnl_pipeline_stage *stage)
-{
-}
-
-static GLvoid fetch_input_float (struct gl2_program_intf **pro, GLuint index, GLuint attr, GLuint i,
- struct vertex_buffer *vb)
-{
- const GLubyte *ptr = (const GLubyte *) vb->AttribPtr[attr]->data;
- const GLuint stride = vb->AttribPtr[attr]->stride;
- GLfloat *data = (GLfloat *) (ptr + stride * i);
-
- (**pro).UpdateFixedAttrib (pro, index, data, 0, sizeof (GLfloat), GL_TRUE);
-}
-
-static GLvoid fetch_input_vec3 (struct gl2_program_intf **pro, GLuint index, GLuint attr, GLuint i,
- struct vertex_buffer *vb)
-{
- const GLubyte *ptr = (const GLubyte *) vb->AttribPtr[attr]->data;
- const GLuint stride = vb->AttribPtr[attr]->stride;
- GLfloat *data = (GLfloat *) (ptr + stride * i);
-
- (**pro).UpdateFixedAttrib (pro, index, data, 0, 3 * sizeof (GLfloat), GL_TRUE);
-}
-
-static void fetch_input_vec4 (struct gl2_program_intf **pro, GLuint index, GLuint attr, GLuint i,
- struct vertex_buffer *vb)
-{
- const GLubyte *ptr = (const GLubyte *) vb->AttribPtr[attr]->data;
- const GLuint size = vb->AttribPtr[attr]->size;
- const GLuint stride = vb->AttribPtr[attr]->stride;
- const GLfloat *data = (const GLfloat *) (ptr + stride * i);
- GLfloat vec[4];
-
- switch (size)
- {
- case 2:
- vec[0] = data[0];
- vec[1] = data[1];
- vec[2] = 0.0f;
- vec[3] = 1.0f;
- break;
- case 3:
- vec[0] = data[0];
- vec[1] = data[1];
- vec[2] = data[2];
- vec[3] = 1.0f;
- break;
- case 4:
- vec[0] = data[0];
- vec[1] = data[1];
- vec[2] = data[2];
- vec[3] = data[3];
- break;
- }
- (**pro).UpdateFixedAttrib (pro, index, vec, 0, 4 * sizeof (GLfloat), GL_TRUE);
-}
-
-static GLvoid
-fetch_gen_attrib (struct gl2_program_intf **pro, GLuint index, GLuint i, struct vertex_buffer *vb)
-{
- const GLuint attr = _TNL_ATTRIB_GENERIC0 + index;
- const GLubyte *ptr = (const GLubyte *) (vb->AttribPtr[attr]->data);
- const GLuint stride = vb->AttribPtr[attr]->stride;
- const GLfloat *data = (const GLfloat *) (ptr + stride * i);
-
- (**pro).WriteAttrib (pro, index, data);
-}
-
-static GLvoid fetch_output_float (struct gl2_program_intf **pro, GLuint index, GLuint attr, GLuint i,
- arbvs_stage_data *store)
-{
- (**pro).UpdateFixedAttrib (pro, index, &store->outputs[attr].data[i], 0, sizeof (GLfloat),
- GL_FALSE);
-}
-
-static void fetch_output_vec4 (struct gl2_program_intf **pro, GLuint index, GLuint attr, GLuint i,
- GLuint offset, arbvs_stage_data *store)
-{
- (**pro).UpdateFixedAttrib (pro, index, &store->outputs[attr].data[i], offset,
- 4 * sizeof (GLfloat), GL_FALSE);
-}
-
-static GLboolean run_arb_vertex_shader (GLcontext *ctx, struct tnl_pipeline_stage *stage)
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct vertex_buffer *vb = &tnl->vb;
- arbvs_stage_data *store = ARBVS_STAGE_DATA(stage);
- struct gl2_program_intf **pro;
- GLsizei i, j;
-
- if (!ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- pro = ctx->ShaderObjects.CurrentProgram;
- (**pro).UpdateFixedUniforms (pro);
-
- for (i = 0; i < vb->Count; i++)
- {
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_VERTEX, _TNL_ATTRIB_POS, i, vb);
- fetch_input_vec3 (pro, SLANG_VERTEX_FIXED_NORMAL, _TNL_ATTRIB_NORMAL, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_COLOR, _TNL_ATTRIB_COLOR0, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_SECONDARYCOLOR, _TNL_ATTRIB_COLOR1, i, vb);
- fetch_input_float (pro, SLANG_VERTEX_FIXED_FOGCOORD, _TNL_ATTRIB_FOG, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_MULTITEXCOORD0, _TNL_ATTRIB_TEX0, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_MULTITEXCOORD1, _TNL_ATTRIB_TEX1, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_MULTITEXCOORD2, _TNL_ATTRIB_TEX2, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_MULTITEXCOORD3, _TNL_ATTRIB_TEX3, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_MULTITEXCOORD4, _TNL_ATTRIB_TEX4, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_MULTITEXCOORD5, _TNL_ATTRIB_TEX5, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_MULTITEXCOORD6, _TNL_ATTRIB_TEX6, i, vb);
- fetch_input_vec4 (pro, SLANG_VERTEX_FIXED_MULTITEXCOORD7, _TNL_ATTRIB_TEX7, i, vb);
- for (j = 0; j < MAX_VERTEX_ATTRIBS; j++)
- fetch_gen_attrib (pro, j, i, vb);
-
- _slang_exec_vertex_shader (pro);
-
- fetch_output_vec4 (pro, SLANG_VERTEX_FIXED_POSITION, VERT_RESULT_HPOS, i, 0, store);
- fetch_output_vec4 (pro, SLANG_VERTEX_FIXED_FRONTCOLOR, VERT_RESULT_COL0, i, 0, store);
- fetch_output_vec4 (pro, SLANG_VERTEX_FIXED_FRONTSECONDARYCOLOR, VERT_RESULT_COL1, i, 0, store);
- fetch_output_float (pro, SLANG_VERTEX_FIXED_FOGFRAGCOORD, VERT_RESULT_FOGC, i, store);
- for (j = 0; j < 8; j++)
- fetch_output_vec4 (pro, SLANG_VERTEX_FIXED_TEXCOORD, VERT_RESULT_TEX0 + j, i, j, store);
- fetch_output_float (pro, SLANG_VERTEX_FIXED_POINTSIZE, VERT_RESULT_PSIZ, i, store);
- fetch_output_vec4 (pro, SLANG_VERTEX_FIXED_BACKCOLOR, VERT_RESULT_BFC0, i, 0, store);
- fetch_output_vec4 (pro, SLANG_VERTEX_FIXED_BACKSECONDARYCOLOR, VERT_RESULT_BFC1, i, 0, store);
- /* XXX: fetch output SLANG_VERTEX_FIXED_CLIPVERTEX */
-
- for (j = 0; j < MAX_VARYING_VECTORS; j++)
- {
- GLuint k;
-
- for (k = 0; k < VARYINGS_PER_VECTOR; k++)
- {
- (**pro).UpdateVarying (pro, j * VARYINGS_PER_VECTOR + k,
- &store->varyings[j].data[i][k], GL_TRUE);
- }
- }
- }
-
- vb->ClipPtr = &store->outputs[VERT_RESULT_HPOS];
- vb->ClipPtr->count = vb->Count;
-
- vb->ColorPtr[0] = &store->outputs[VERT_RESULT_COL0];
- vb->AttribPtr[VERT_ATTRIB_COLOR0] = vb->ColorPtr[0];
- vb->ColorPtr[1] = &store->outputs[VERT_RESULT_BFC0];
-
- vb->SecondaryColorPtr[0] =
- vb->AttribPtr[VERT_ATTRIB_COLOR1] = &store->outputs[VERT_RESULT_COL1];
-
- vb->SecondaryColorPtr[1] = &store->outputs[VERT_RESULT_BFC1];
-
- for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
- vb->TexCoordPtr[i] =
- vb->AttribPtr[VERT_ATTRIB_TEX0 + i] = &store->outputs[VERT_RESULT_TEX0 + i];
- }
-
- vb->FogCoordPtr =
- vb->AttribPtr[VERT_ATTRIB_FOG] = &store->outputs[VERT_RESULT_FOGC];
-
- vb->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->outputs[VERT_RESULT_PSIZ];
-
- for (i = 0; i < MAX_VARYING_VECTORS; i++) {
- vb->VaryingPtr[i] = &store->varyings[i];
- vb->AttribPtr[_TNL_ATTRIB_GENERIC0 + i] = vb->VaryingPtr[i];
- }
-
- store->ormask = 0;
- store->andmask = CLIP_FRUSTUM_BITS;
-
- if (tnl->NeedNdcCoords)
- {
- vb->NdcPtr = _mesa_clip_tab[vb->ClipPtr->size] (vb->ClipPtr, &store->ndc_coords,
- store->clipmask, &store->ormask, &store->andmask);
- }
- else
- {
- vb->NdcPtr = NULL;
- _mesa_clip_np_tab[vb->ClipPtr->size] (vb->ClipPtr, NULL, store->clipmask, &store->ormask,
- &store->andmask);
- }
-
- if (store->andmask)
- return GL_FALSE;
-
- vb->ClipAndMask = store->andmask;
- vb->ClipOrMask = store->ormask;
- vb->ClipMask = store->clipmask;
-
- return GL_TRUE;
-}
-
-const struct tnl_pipeline_stage _tnl_arb_vertex_shader_stage = {
- "ARB_vertex_shader",
- NULL,
- construct_arb_vertex_shader,
- destruct_arb_vertex_shader,
- validate_arb_vertex_shader,
- run_arb_vertex_shader
-};
-
-#endif /* FEATURE_ARB_vertex_shader */
-
diff --git a/src/mesa/tnl/t_vb_cull.c b/src/mesa/tnl/t_vb_cull.c
index 8848dac10c1..21a32e5b1d8 100644
--- a/src/mesa/tnl/t_vb_cull.c
+++ b/src/mesa/tnl/t_vb_cull.c
@@ -57,10 +57,7 @@ static GLboolean run_cull_stage( GLcontext *ctx,
GLuint count = VB->Count;
GLuint i;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- if (ctx->VertexProgram._Enabled ||
+ if (ctx->VertexProgram._Current ||
!ctx->Transform.CullVertexFlag)
return GL_TRUE;
diff --git a/src/mesa/tnl/t_vb_fog.c b/src/mesa/tnl/t_vb_fog.c
index 51f28c4059f..5440ff7894d 100644
--- a/src/mesa/tnl/t_vb_fog.c
+++ b/src/mesa/tnl/t_vb_fog.c
@@ -148,10 +148,7 @@ run_fog_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
struct fog_stage_data *store = FOG_STAGE_DATA(stage);
GLvector4f *input;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- if (!ctx->Fog.Enabled || ctx->VertexProgram._Enabled)
+ if (!ctx->Fog.Enabled || ctx->VertexProgram._Current)
return GL_TRUE;
diff --git a/src/mesa/tnl/t_vb_light.c b/src/mesa/tnl/t_vb_light.c
index 47c5b400aae..12f2cc7735e 100644
--- a/src/mesa/tnl/t_vb_light.c
+++ b/src/mesa/tnl/t_vb_light.c
@@ -203,10 +203,7 @@ static GLboolean run_lighting( GLcontext *ctx,
GLvector4f *input = ctx->_NeedEyeCoords ? VB->EyePtr : VB->ObjPtr;
GLuint idx;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- if (!ctx->Light.Enabled || ctx->VertexProgram._Enabled)
+ if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
return GL_TRUE;
/* Make sure we can talk about position x,y and z:
@@ -264,10 +261,7 @@ static void validate_lighting( GLcontext *ctx,
{
light_func *tab;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return;
-
- if (!ctx->Light.Enabled || ctx->VertexProgram._Enabled)
+ if (!ctx->Light.Enabled || ctx->VertexProgram._Current)
return;
if (ctx->Visual.rgbMode) {
diff --git a/src/mesa/tnl/t_vb_normals.c b/src/mesa/tnl/t_vb_normals.c
index 0f91784e809..01fad0cee21 100644
--- a/src/mesa/tnl/t_vb_normals.c
+++ b/src/mesa/tnl/t_vb_normals.c
@@ -95,12 +95,7 @@ validate_normal_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
{
struct normal_stage_data *store = NORMAL_STAGE_DATA(stage);
- if (ctx->ShaderObjects._VertexShaderPresent) {
- store->NormalTransform = NULL;
- return;
- }
-
- if (ctx->VertexProgram._Enabled ||
+ if (ctx->VertexProgram._Current ||
(!ctx->Light.Enabled &&
!(ctx->Texture._GenFlags & TEXGEN_NEED_NORMALS))) {
store->NormalTransform = NULL;
diff --git a/src/mesa/tnl/t_vb_points.c b/src/mesa/tnl/t_vb_points.c
index 2f502d61d1d..9327f8c273c 100644
--- a/src/mesa/tnl/t_vb_points.c
+++ b/src/mesa/tnl/t_vb_points.c
@@ -47,10 +47,7 @@ struct point_stage_data {
static GLboolean
run_point_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
{
- if (ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- if (ctx->Point._Attenuated && !ctx->VertexProgram._Enabled) {
+ if (ctx->Point._Attenuated && !ctx->VertexProgram._Current) {
struct point_stage_data *store = POINT_STAGE_DATA(stage);
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
const GLfloat (*eye)[4] = (const GLfloat (*)[4]) VB->EyePtr->data;
diff --git a/src/mesa/tnl/t_vb_program.c b/src/mesa/tnl/t_vb_program.c
index f11ac616f16..17eefe70326 100644
--- a/src/mesa/tnl/t_vb_program.c
+++ b/src/mesa/tnl/t_vb_program.c
@@ -1,8 +1,8 @@
/*
* Mesa 3-D graphics library
- * Version: 6.5
+ * Version: 6.5.3
*
- * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
+ * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -31,20 +31,14 @@
#include "glheader.h"
-#include "api_noop.h"
-#include "colormac.h"
#include "context.h"
-#include "dlist.h"
-#include "hash.h"
-#include "light.h"
#include "macros.h"
#include "imports.h"
-#include "simple_list.h"
-#include "mtypes.h"
-#include "program_instruction.h"
-#include "nvvertexec.h"
-#include "nvprogram.h"
+#include "prog_instruction.h"
+#include "prog_statevars.h"
+#include "prog_execute.h"
+#include "tnl.h"
#include "t_context.h"
#include "t_pipeline.h"
@@ -55,7 +49,7 @@
*/
struct vp_stage_data {
/** The results of running the vertex program go into these arrays. */
- GLvector4f attribs[15];
+ GLvector4f results[VERT_RESULT_MAX];
GLvector4f ndcCoords; /**< normalized device coords */
GLubyte *clipmask; /**< clip flags */
@@ -67,6 +61,131 @@ struct vp_stage_data {
/**
+ * Initialize virtual machine state prior to executing vertex program.
+ */
+static void
+init_machine(GLcontext *ctx, struct gl_program_machine *machine)
+{
+ /* Input registers get initialized from the current vertex attribs */
+ MEMCPY(machine->VertAttribs, ctx->Current.Attrib,
+ MAX_VERTEX_PROGRAM_ATTRIBS * 4 * sizeof(GLfloat));
+
+ if (ctx->VertexProgram.Current->IsNVProgram) {
+ GLuint i;
+ /* Output/result regs are initialized to [0,0,0,1] */
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) {
+ ASSIGN_4V(machine->Outputs[i], 0.0F, 0.0F, 0.0F, 1.0F);
+ }
+ /* Temp regs are initialized to [0,0,0,0] */
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) {
+ ASSIGN_4V(machine->Temporaries[i], 0.0F, 0.0F, 0.0F, 0.0F);
+ }
+ for (i = 0; i < MAX_VERTEX_PROGRAM_ADDRESS_REGS; i++) {
+ ASSIGN_4V(machine->AddressReg[i], 0, 0, 0, 0);
+ }
+ }
+
+ /* init condition codes */
+ machine->CondCodes[0] = COND_EQ;
+ machine->CondCodes[1] = COND_EQ;
+ machine->CondCodes[2] = COND_EQ;
+ machine->CondCodes[3] = COND_EQ;
+}
+
+
+/**
+ * Copy the 16 elements of a matrix into four consecutive program
+ * registers starting at 'pos'.
+ */
+static void
+load_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16])
+{
+ GLuint i;
+ for (i = 0; i < 4; i++) {
+ registers[pos + i][0] = mat[0 + i];
+ registers[pos + i][1] = mat[4 + i];
+ registers[pos + i][2] = mat[8 + i];
+ registers[pos + i][3] = mat[12 + i];
+ }
+}
+
+
+/**
+ * As above, but transpose the matrix.
+ */
+static void
+load_transpose_matrix(GLfloat registers[][4], GLuint pos,
+ const GLfloat mat[16])
+{
+ MEMCPY(registers[pos], mat, 16 * sizeof(GLfloat));
+}
+
+
+/**
+ * Load current vertex program's parameter registers with tracked
+ * matrices (if NV program). This only needs to be done per
+ * glBegin/glEnd, not per-vertex.
+ */
+void
+_mesa_load_tracked_matrices(GLcontext *ctx)
+{
+ GLuint i;
+
+ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) {
+ /* point 'mat' at source matrix */
+ GLmatrix *mat;
+ if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) {
+ mat = ctx->ModelviewMatrixStack.Top;
+ }
+ else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) {
+ mat = ctx->ProjectionMatrixStack.Top;
+ }
+ else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) {
+ mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top;
+ }
+ else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) {
+ mat = ctx->ColorMatrixStack.Top;
+ }
+ else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) {
+ /* XXX verify the combined matrix is up to date */
+ mat = &ctx->_ModelProjectMatrix;
+ }
+ else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV &&
+ ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) {
+ GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV;
+ ASSERT(n < MAX_PROGRAM_MATRICES);
+ mat = ctx->ProgramMatrixStack[n].Top;
+ }
+ else {
+ /* no matrix is tracked, but we leave the register values as-is */
+ assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE);
+ continue;
+ }
+
+ /* load the matrix values into sequential registers */
+ if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) {
+ load_matrix(ctx->VertexProgram.Parameters, i*4, mat->m);
+ }
+ else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) {
+ _math_matrix_analyse(mat); /* update the inverse */
+ ASSERT(!_math_matrix_is_dirty(mat));
+ load_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv);
+ }
+ else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) {
+ load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->m);
+ }
+ else {
+ assert(ctx->VertexProgram.TrackMatrixTransform[i]
+ == GL_INVERSE_TRANSPOSE_NV);
+ _math_matrix_analyse(mat); /* update the inverse */
+ ASSERT(!_math_matrix_is_dirty(mat));
+ load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv);
+ }
+ }
+}
+
+
+/**
* This function executes vertex programs
*/
static GLboolean
@@ -75,24 +194,38 @@ run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vp_stage_data *store = VP_STAGE_DATA(stage);
struct vertex_buffer *VB = &tnl->vb;
- struct gl_vertex_program *program = ctx->VertexProgram.Current;
- struct vp_machine machine;
- GLuint i;
-
- if (ctx->ShaderObjects._VertexShaderPresent)
+ struct gl_vertex_program *program = ctx->VertexProgram._Current;
+ struct gl_program_machine machine;
+ GLuint outputs[VERT_RESULT_MAX], numOutputs;
+ GLuint i, j;
+
+#define FORCE_PROG_EXECUTE_C 1
+#if FORCE_PROG_EXECUTE_C
+ if (!program)
return GL_TRUE;
-
- if (!ctx->VertexProgram._Enabled ||
- !program->IsNVProgram)
+#else
+ if (!program || !program->IsNVProgram)
return GL_TRUE;
+#endif
- /* load program parameter registers (they're read-only) */
- _mesa_init_vp_per_primitive_registers(ctx);
+ if (ctx->VertexProgram.Current->IsNVProgram) {
+ _mesa_load_tracked_matrices(ctx);
+ }
+ else {
+ _mesa_load_state_parameters(ctx, program->Base.Parameters);
+ }
+
+ numOutputs = 0;
+ for (i = 0; i < VERT_RESULT_MAX; i++) {
+ if (program->Base.OutputsWritten & (1 << i)) {
+ outputs[numOutputs++] = i;
+ }
+ }
for (i = 0; i < VB->Count; i++) {
GLuint attr;
- _mesa_init_vp_per_vertex_registers(ctx, &machine);
+ init_machine(ctx, &machine);
#if 0
printf("Input %d: %f, %f, %f, %f\n", i,
@@ -119,13 +252,12 @@ run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
const GLuint size = VB->AttribPtr[attr]->size;
const GLuint stride = VB->AttribPtr[attr]->stride;
const GLfloat *data = (GLfloat *) (ptr + stride * i);
- COPY_CLEAN_4V(machine.Inputs[attr], size, data);
+ COPY_CLEAN_4V(machine.VertAttribs[attr], size, data);
}
}
/* execute the program */
- ASSERT(program);
- _mesa_exec_vertex_program(ctx, &machine, program);
+ _mesa_execute_program(ctx, &program->Base, &machine);
/* Fixup fog an point size results if needed */
if (ctx->Fog.Enabled &&
@@ -139,33 +271,48 @@ run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
}
/* copy the output registers into the VB->attribs arrays */
- /* XXX (optimize) could use a conditional and smaller loop limit here */
- for (attr = 0; attr < 15; attr++) {
- COPY_4V(store->attribs[attr].data[i], machine.Outputs[attr]);
+ for (j = 0; j < numOutputs; j++) {
+ const GLuint attr = outputs[j];
+ COPY_4V(store->results[attr].data[i], machine.Outputs[attr]);
}
+#if 0
+ printf("HPOS: %f %f %f %f\n",
+ machine.Outputs[0][0],
+ machine.Outputs[0][1],
+ machine.Outputs[0][2],
+ machine.Outputs[0][3]);
+#endif
}
/* Setup the VB pointers so that the next pipeline stages get
* their data from the right place (the program output arrays).
*/
- VB->ClipPtr = &store->attribs[VERT_RESULT_HPOS];
+ VB->ClipPtr = &store->results[VERT_RESULT_HPOS];
VB->ClipPtr->size = 4;
VB->ClipPtr->count = VB->Count;
- VB->ColorPtr[0] = &store->attribs[VERT_RESULT_COL0];
- VB->ColorPtr[1] = &store->attribs[VERT_RESULT_BFC0];
- VB->SecondaryColorPtr[0] = &store->attribs[VERT_RESULT_COL1];
- VB->SecondaryColorPtr[1] = &store->attribs[VERT_RESULT_BFC1];
- VB->FogCoordPtr = &store->attribs[VERT_RESULT_FOGC];
+ VB->ColorPtr[0] = &store->results[VERT_RESULT_COL0];
+ VB->ColorPtr[1] = &store->results[VERT_RESULT_BFC0];
+ VB->SecondaryColorPtr[0] = &store->results[VERT_RESULT_COL1];
+ VB->SecondaryColorPtr[1] = &store->results[VERT_RESULT_BFC1];
+ VB->FogCoordPtr = &store->results[VERT_RESULT_FOGC];
- VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->attribs[VERT_RESULT_COL0];
- VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->attribs[VERT_RESULT_COL1];
- VB->AttribPtr[VERT_ATTRIB_FOG] = &store->attribs[VERT_RESULT_FOGC];
- VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->attribs[VERT_RESULT_PSIZ];
+ VB->AttribPtr[VERT_ATTRIB_COLOR0] = &store->results[VERT_RESULT_COL0];
+ VB->AttribPtr[VERT_ATTRIB_COLOR1] = &store->results[VERT_RESULT_COL1];
+ VB->AttribPtr[VERT_ATTRIB_FOG] = &store->results[VERT_RESULT_FOGC];
+ VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->results[VERT_RESULT_PSIZ];
for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
VB->TexCoordPtr[i] =
VB->AttribPtr[_TNL_ATTRIB_TEX0 + i]
- = &store->attribs[VERT_RESULT_TEX0 + i];
+ = &store->results[VERT_RESULT_TEX0 + i];
+ }
+
+ for (i = 0; i < ctx->Const.MaxVarying; i++) {
+ if (program->Base.OutputsWritten & (1 << (VERT_RESULT_VAR0 + i))) {
+ /* Note: varying results get put into the generic attributes */
+ VB->AttribPtr[VERT_ATTRIB_GENERIC0+i]
+ = &store->results[VERT_RESULT_VAR0 + i];
+ }
}
/* Cliptest and perspective divide. Clip functions must clear
@@ -206,8 +353,6 @@ run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
}
-
-
/**
* Called the first time stage->run is called. In effect, don't
* allocate data until the first time the stage is run.
@@ -227,10 +372,9 @@ static GLboolean init_vp( GLcontext *ctx,
return GL_FALSE;
/* Allocate arrays of vertex output values */
- /* XXX change '15' to a named constant */
- for (i = 0; i < 15; i++) {
- _mesa_vector4f_alloc( &store->attribs[i], 0, size, 32 );
- store->attribs[i].size = 4;
+ for (i = 0; i < VERT_RESULT_MAX; i++) {
+ _mesa_vector4f_alloc( &store->results[i], 0, size, 32 );
+ store->results[i].size = 4;
}
/* a few other misc allocations */
@@ -241,9 +385,6 @@ static GLboolean init_vp( GLcontext *ctx,
}
-
-
-
/**
* Destructor for this pipeline stage.
*/
@@ -256,7 +397,7 @@ static void dtr( struct tnl_pipeline_stage *stage )
/* free the vertex program result arrays */
for (i = 0; i < VERT_RESULT_MAX; i++)
- _mesa_vector4f_free( &store->attribs[i] );
+ _mesa_vector4f_free( &store->results[i] );
/* free misc arrays */
_mesa_vector4f_free( &store->ndcCoords );
@@ -267,6 +408,7 @@ static void dtr( struct tnl_pipeline_stage *stage )
}
}
+
/**
* Public description of this pipeline stage.
*/
diff --git a/src/mesa/tnl/t_vb_texgen.c b/src/mesa/tnl/t_vb_texgen.c
index 5f7b2dccd8f..e98ab743c5e 100644
--- a/src/mesa/tnl/t_vb_texgen.c
+++ b/src/mesa/tnl/t_vb_texgen.c
@@ -488,10 +488,7 @@ static GLboolean run_texgen_stage( GLcontext *ctx,
struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
GLuint i;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Enabled)
+ if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current)
return GL_TRUE;
for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) {
@@ -516,10 +513,7 @@ static void validate_texgen_stage( GLcontext *ctx,
struct texgen_stage_data *store = TEXGEN_STAGE_DATA(stage);
GLuint i;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return;
-
- if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Enabled)
+ if (!ctx->Texture._TexGenEnabled || ctx->VertexProgram._Current)
return;
for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++) {
diff --git a/src/mesa/tnl/t_vb_texmat.c b/src/mesa/tnl/t_vb_texmat.c
index fa9222c0f14..674d36f8cbe 100644
--- a/src/mesa/tnl/t_vb_texmat.c
+++ b/src/mesa/tnl/t_vb_texmat.c
@@ -61,10 +61,7 @@ static GLboolean run_texmat_stage( GLcontext *ctx,
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
GLuint i;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- if (!ctx->Texture._TexMatEnabled || ctx->VertexProgram._Enabled)
+ if (!ctx->Texture._TexMatEnabled || ctx->VertexProgram._Current)
return GL_TRUE;
/* ENABLE_TEXMAT implies that the texture matrix is not the
diff --git a/src/mesa/tnl/t_vb_vertex.c b/src/mesa/tnl/t_vb_vertex.c
index 100fca2a226..276305b5e67 100644
--- a/src/mesa/tnl/t_vb_vertex.c
+++ b/src/mesa/tnl/t_vb_vertex.c
@@ -126,10 +126,7 @@ static GLboolean run_vertex_stage( GLcontext *ctx,
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
- if (ctx->ShaderObjects._VertexShaderPresent)
- return GL_TRUE;
-
- if (ctx->VertexProgram._Enabled)
+ if (ctx->VertexProgram._Current)
return GL_TRUE;
if (ctx->_NeedEyeCoords) {
diff --git a/src/mesa/tnl/t_vp_build.c b/src/mesa/tnl/t_vp_build.c
index 2663d993049..8b8bb3a173a 100644
--- a/src/mesa/tnl/t_vp_build.c
+++ b/src/mesa/tnl/t_vp_build.c
@@ -33,11 +33,14 @@
#include "glheader.h"
#include "macros.h"
#include "enums.h"
+#include "program.h"
+#include "prog_instruction.h"
+#include "prog_parameter.h"
+#include "prog_print.h"
+#include "prog_statevars.h"
#include "t_context.h" /* NOTE: very light dependency on this */
#include "t_vp_build.h"
-#include "shader/program.h"
-#include "shader/program_instruction.h"
struct state_key {
unsigned light_global_enabled:1;
@@ -382,11 +385,14 @@ static struct ureg register_const4f( struct tnl_program *p,
{
GLfloat values[4];
GLint idx;
+ GLuint swizzle;
values[0] = s0;
values[1] = s1;
values[2] = s2;
values[3] = s3;
- idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4 );
+ idx = _mesa_add_unnamed_constant( p->program->Base.Parameters, values, 4,
+ &swizzle );
+ ASSERT(swizzle == SWIZZLE_NOOP);
return make_ureg(PROGRAM_STATE_VAR, idx);
}
@@ -408,40 +414,37 @@ static struct ureg get_identity_param( struct tnl_program *p )
return p->identity;
}
-static struct ureg register_param6( struct tnl_program *p,
+static struct ureg register_param5(struct tnl_program *p,
GLint s0,
GLint s1,
GLint s2,
GLint s3,
- GLint s4,
- GLint s5)
+ GLint s4)
{
- GLint tokens[6];
+ gl_state_index tokens[STATE_LENGTH];
GLint idx;
tokens[0] = s0;
tokens[1] = s1;
tokens[2] = s2;
tokens[3] = s3;
tokens[4] = s4;
- tokens[5] = s5;
idx = _mesa_add_state_reference( p->program->Base.Parameters, tokens );
return make_ureg(PROGRAM_STATE_VAR, idx);
}
-#define register_param1(p,s0) register_param6(p,s0,0,0,0,0,0)
-#define register_param2(p,s0,s1) register_param6(p,s0,s1,0,0,0,0)
-#define register_param3(p,s0,s1,s2) register_param6(p,s0,s1,s2,0,0,0)
-#define register_param4(p,s0,s1,s2,s3) register_param6(p,s0,s1,s2,s3,0,0)
+#define register_param1(p,s0) register_param5(p,s0,0,0,0,0)
+#define register_param2(p,s0,s1) register_param5(p,s0,s1,0,0,0)
+#define register_param3(p,s0,s1,s2) register_param5(p,s0,s1,s2,0,0)
+#define register_param4(p,s0,s1,s2,s3) register_param5(p,s0,s1,s2,s3,0)
-static void register_matrix_param6( struct tnl_program *p,
- GLint s0,
- GLint s1,
- GLint s2,
- GLint s3,
- GLint s4,
- GLint s5,
+static void register_matrix_param5( struct tnl_program *p,
+ GLint s0, /* modelview, projection, etc */
+ GLint s1, /* texture matrix number */
+ GLint s2, /* first row */
+ GLint s3, /* last row */
+ GLint s4, /* inverse, transpose, etc */
struct ureg *matrix )
{
GLint i;
@@ -449,8 +452,8 @@ static void register_matrix_param6( struct tnl_program *p,
/* This is a bit sad as the support is there to pull the whole
* matrix out in one go:
*/
- for (i = 0; i <= s4 - s3; i++)
- matrix[i] = register_param6( p, s0, s1, s2, i, i, s5 );
+ for (i = 0; i <= s3 - s2; i++)
+ matrix[i] = register_param5( p, s0, s1, i, i, s4 );
}
@@ -630,13 +633,13 @@ static struct ureg get_eye_position( struct tnl_program *p )
p->eye_position = reserve_temp(p);
if (PREFER_DP4) {
- register_matrix_param6( p, STATE_MATRIX, STATE_MODELVIEW, 0, 0, 3,
- STATE_MATRIX, modelview );
+ register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3,
+ 0, modelview );
emit_matrix_transform_vec4(p, p->eye_position, modelview, pos);
}
else {
- register_matrix_param6( p, STATE_MATRIX, STATE_MODELVIEW, 0, 0, 3,
+ register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3,
STATE_MATRIX_TRANSPOSE, modelview );
emit_transpose_matrix_transform_vec4(p, p->eye_position, modelview, pos);
@@ -665,7 +668,7 @@ static struct ureg get_eye_normal( struct tnl_program *p )
struct ureg normal = register_input(p, VERT_ATTRIB_NORMAL );
struct ureg mvinv[3];
- register_matrix_param6( p, STATE_MATRIX, STATE_MODELVIEW, 0, 0, 2,
+ register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 2,
STATE_MATRIX_INVTRANS, mvinv );
p->eye_normal = reserve_temp(p);
@@ -700,12 +703,12 @@ static void build_hpos( struct tnl_program *p )
struct ureg mvp[4];
if (PREFER_DP4) {
- register_matrix_param6( p, STATE_MATRIX, STATE_MVP, 0, 0, 3,
- STATE_MATRIX, mvp );
+ register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3,
+ 0, mvp );
emit_matrix_transform_vec4( p, hpos, mvp, pos );
}
else {
- register_matrix_param6( p, STATE_MATRIX, STATE_MVP, 0, 0, 3,
+ register_matrix_param5( p, STATE_MVP_MATRIX, 0, 0, 3,
STATE_MATRIX_TRANSPOSE, mvp );
emit_transpose_matrix_transform_vec4( p, hpos, mvp, pos );
}
@@ -850,7 +853,7 @@ static struct ureg calculate_light_attenuation( struct tnl_program *p,
/* Need to add some addtional parameters to allow lighting in object
- * space - STATE_SPOT_DIRECTION and STATE_HALF implicitly assume eye
+ * space - STATE_SPOT_DIRECTION and STATE_HALF_VECTOR implicitly assume eye
* space lighting.
*/
static void build_lighting( struct tnl_program *p )
@@ -945,7 +948,7 @@ static void build_lighting( struct tnl_program *p )
emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat);
emit_normalize_vec3(p, half, half);
} else {
- half = register_param3(p, STATE_LIGHT, i, STATE_HALF);
+ half = register_param3(p, STATE_LIGHT, i, STATE_HALF_VECTOR);
}
}
else {
@@ -1211,7 +1214,7 @@ static void build_texture_transform( struct tnl_program *p )
for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
- if (!(p->state->fragprog_inputs_read & (FRAG_BIT_TEX0<<i)))
+ if (!(p->state->fragprog_inputs_read & FRAG_BIT_TEX(i)))
continue;
if (p->state->unit[i].texgen_enabled ||
@@ -1301,13 +1304,13 @@ static void build_texture_transform( struct tnl_program *p )
out_texgen :
register_input(p, VERT_ATTRIB_TEX0+i));
if (PREFER_DP4) {
- register_matrix_param6( p, STATE_MATRIX, STATE_TEXTURE, i,
- 0, 3, STATE_MATRIX, texmat );
+ register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3,
+ 0, texmat );
emit_matrix_transform_vec4( p, out, texmat, in );
}
else {
- register_matrix_param6( p, STATE_MATRIX, STATE_TEXTURE, i,
- 0, 3, STATE_MATRIX_TRANSPOSE, texmat );
+ register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3,
+ STATE_MATRIX_TRANSPOSE, texmat );
emit_transpose_matrix_transform_vec4( p, out, texmat, in );
}
}
@@ -1504,7 +1507,7 @@ void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx )
GLuint hash;
const struct gl_vertex_program *prev = ctx->VertexProgram._Current;
- if (ctx->VertexProgram._Enabled == GL_FALSE) {
+ if (!ctx->VertexProgram._Current) {
/* Grab all the relevent state and put it in a single structure:
*/
key = make_state_key(ctx);
@@ -1512,45 +1515,42 @@ void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx )
/* Look for an already-prepared program for this state:
*/
- ctx->_TnlProgram = (struct gl_vertex_program *)
+ ctx->VertexProgram._TnlProgram = (struct gl_vertex_program *)
search_cache( tnl->vp_cache, hash, key, sizeof(*key) );
/* OK, we'll have to build a new one:
*/
- if (!ctx->_TnlProgram) {
+ if (!ctx->VertexProgram._TnlProgram) {
if (0)
_mesa_printf("Build new TNL program\n");
- ctx->_TnlProgram = (struct gl_vertex_program *)
+ ctx->VertexProgram._TnlProgram = (struct gl_vertex_program *)
ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
- create_new_program( key, ctx->_TnlProgram,
+ create_new_program( key, ctx->VertexProgram._TnlProgram,
ctx->Const.VertexProgram.MaxTemps );
if (ctx->Driver.ProgramStringNotify)
ctx->Driver.ProgramStringNotify( ctx, GL_VERTEX_PROGRAM_ARB,
- &ctx->_TnlProgram->Base );
+ &ctx->VertexProgram._TnlProgram->Base );
- cache_item(tnl->vp_cache, hash, key, ctx->_TnlProgram );
+ cache_item(tnl->vp_cache, hash, key, ctx->VertexProgram._TnlProgram );
}
else {
FREE(key);
if (0)
_mesa_printf("Found existing TNL program for key %x\n", hash);
}
- ctx->VertexProgram._Current = ctx->_TnlProgram;
- }
- else {
- ctx->VertexProgram._Current = ctx->VertexProgram.Current;
+ ctx->VertexProgram._Current = ctx->VertexProgram._TnlProgram;
}
/* Tell the driver about the change. Could define a new target for
* this?
*/
- if (ctx->VertexProgram._Current != prev &&
- ctx->Driver.BindProgram)
+ if (ctx->VertexProgram._Current != prev && ctx->Driver.BindProgram) {
ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB,
(struct gl_program *) ctx->VertexProgram._Current);
+ }
}
void _tnl_ProgramCacheInit( GLcontext *ctx )
diff --git a/src/mesa/tnl/tnl.h b/src/mesa/tnl/tnl.h
index 17cb30adc76..20bed5546de 100644
--- a/src/mesa/tnl/tnl.h
+++ b/src/mesa/tnl/tnl.h
@@ -82,4 +82,7 @@ _tnl_draw_prims( GLcontext *ctx,
GLuint min_index,
GLuint max_index);
+extern void
+_mesa_load_tracked_matrices(GLcontext *ctx);
+
#endif