summaryrefslogtreecommitdiff
path: root/src/mesa/tnl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/tnl')
-rw-r--r--src/mesa/tnl/t_draw.c5
-rw-r--r--src/mesa/tnl/t_pipeline.c10
-rw-r--r--src/mesa/tnl/t_pipeline.h9
-rw-r--r--src/mesa/tnl/t_save_api.c1834
-rw-r--r--src/mesa/tnl/t_vb_arbprogram.c1614
-rw-r--r--src/mesa/tnl/t_vb_arbprogram.h206
-rw-r--r--src/mesa/tnl/t_vb_arbprogram_sse.c1330
-rw-r--r--src/mesa/tnl/t_vb_fog.c29
-rw-r--r--src/mesa/tnl/t_vb_points.c10
-rw-r--r--src/mesa/tnl/t_vb_program.c106
-rw-r--r--src/mesa/tnl/t_vertex.c10
-rw-r--r--src/mesa/tnl/t_vp_build.c23
12 files changed, 143 insertions, 5043 deletions
diff --git a/src/mesa/tnl/t_draw.c b/src/mesa/tnl/t_draw.c
index c97cf5f7b2..5b2b2ae549 100644
--- a/src/mesa/tnl/t_draw.c
+++ b/src/mesa/tnl/t_draw.c
@@ -251,7 +251,10 @@ static void bind_inputs( GLcontext *ctx,
VB->AttribPtr[_TNL_ATTRIB_EDGEFLAG],
VB->Count );
}
-
+ else {
+ /* the data previously pointed to by EdgeFlag may have been freed */
+ VB->EdgeFlag = NULL;
+ }
}
diff --git a/src/mesa/tnl/t_pipeline.c b/src/mesa/tnl/t_pipeline.c
index a50a3f0f2f..c7188da34a 100644
--- a/src/mesa/tnl/t_pipeline.c
+++ b/src/mesa/tnl/t_pipeline.c
@@ -1,9 +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"),
@@ -204,16 +203,13 @@ const struct tnl_pipeline_stage *_tnl_default_pipeline[] = {
&_tnl_texgen_stage,
&_tnl_texture_transform_stage,
&_tnl_point_attenuation_stage,
-#if defined(FEATURE_NV_vertex_program) || defined(FEATURE_ARB_vertex_program)
- &_tnl_arb_vertex_program_stage,
&_tnl_vertex_program_stage,
-#endif
&_tnl_render_stage,
NULL
};
const struct tnl_pipeline_stage *_tnl_vp_pipeline[] = {
- &_tnl_arb_vertex_program_stage,
+ &_tnl_vertex_program_stage,
&_tnl_render_stage,
NULL
};
diff --git a/src/mesa/tnl/t_pipeline.h b/src/mesa/tnl/t_pipeline.h
index b987ba4116..0952854b85 100644
--- a/src/mesa/tnl/t_pipeline.h
+++ b/src/mesa/tnl/t_pipeline.h
@@ -1,9 +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"),
@@ -52,11 +51,7 @@ extern const struct tnl_pipeline_stage _tnl_fog_coordinate_stage;
extern const struct tnl_pipeline_stage _tnl_texgen_stage;
extern const struct tnl_pipeline_stage _tnl_texture_transform_stage;
extern const struct tnl_pipeline_stage _tnl_point_attenuation_stage;
-extern const struct tnl_pipeline_stage _tnl_arb_vertex_program_stage;
extern const struct tnl_pipeline_stage _tnl_vertex_program_stage;
-#if FEATURE_ARB_vertex_shader
-extern const struct tnl_pipeline_stage _tnl_arb_vertex_shader_stage;
-#endif
extern const struct tnl_pipeline_stage _tnl_render_stage;
/* Shorthand to plug in the default pipeline:
diff --git a/src/mesa/tnl/t_save_api.c b/src/mesa/tnl/t_save_api.c
deleted file mode 100644
index b08f05374e..0000000000
--- a/src/mesa/tnl/t_save_api.c
+++ /dev/null
@@ -1,1834 +0,0 @@
-/**************************************************************************
-
-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 <keith@tungstengraphics.com>
- */
-
-
-
-/**
- * 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
deleted file mode 100644
index 2edb1c5ac4..0000000000
--- a/src/mesa/tnl/t_vb_arbprogram.c
+++ /dev/null
@@ -1,1614 +0,0 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5.3
- *
- * 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"),
- * 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.
- */
-
-/**
- * \file t_arb_program.c
- * Compile vertex programs to an intermediate representation.
- * Execute vertex programs over a buffer of vertices.
- * \author Keith Whitwell, Brian Paul
- */
-
-#include "glheader.h"
-#include "context.h"
-#include "imports.h"
-#include "macros.h"
-#include "mtypes.h"
-#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"
-
-
-#define DISASSEM 0
-
-
-struct compilation {
- GLuint reg_active;
- union instruction *csr;
-};
-
-
-#define ARB_VP_MACHINE(stage) ((struct arb_vp_machine *)(stage->privatePtr))
-
-#define PUFF(x) ((x)[1] = (x)[2] = (x)[3] = (x)[0])
-
-
-
-/* Lower precision functions for the EXP, LOG and LIT opcodes. The
- * LOG2() implementation is probably not accurate enough, and the
- * attempted optimization for Exp2 is definitely not accurate
- * enough - it discards all of t's fractional bits!
- */
-static GLfloat RoughApproxLog2(GLfloat t)
-{
- return LOG2(t);
-}
-
-static GLfloat RoughApproxExp2(GLfloat t)
-{
-#if 0
- fi_type fi;
- fi.i = (GLint) t;
- fi.i = (fi.i << 23) + 0x3f800000;
- return fi.f;
-#else
- return (GLfloat) _mesa_pow(2.0, t);
-#endif
-}
-
-static GLfloat RoughApproxPower(GLfloat x, GLfloat y)
-{
- if (x == 0.0 && y == 0.0)
- return 1.0; /* spec requires this */
- else
- return RoughApproxExp2(y * RoughApproxLog2(x));
-}
-
-
-/* Higher precision functions for the EX2, LG2 and POW opcodes:
- */
-static GLfloat ApproxLog2(GLfloat t)
-{
- return (GLfloat) (LOGF(t) * 1.442695F);
-}
-
-static GLfloat ApproxExp2(GLfloat t)
-{
- return (GLfloat) _mesa_pow(2.0, t);
-}
-
-static GLfloat ApproxPower(GLfloat x, GLfloat y)
-{
- return (GLfloat) _mesa_pow(x, y);
-}
-
-
-/**
- * Perform a reduced swizzle:
- */
-static void do_RSW( struct arb_vp_machine *m, union instruction op )
-{
- GLfloat *result = m->File[0][op.rsw.dst];
- const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0];
- const GLuint swz = op.rsw.swz;
- const GLuint neg = op.rsw.neg;
- GLfloat tmp[4];
-
- /* Need a temporary to be correct in the case where result == arg0.
- */
- COPY_4V(tmp, arg0);
-
- result[0] = tmp[GET_SWZ(swz, 0)];
- result[1] = tmp[GET_SWZ(swz, 1)];
- result[2] = tmp[GET_SWZ(swz, 2)];
- result[3] = tmp[GET_SWZ(swz, 3)];
-
- if (neg) {
- if (neg & 0x1) result[0] = -result[0];
- if (neg & 0x2) result[1] = -result[1];
- if (neg & 0x4) result[2] = -result[2];
- if (neg & 0x8) result[3] = -result[3];
- }
-}
-
-/**
- * Perform a full swizzle
- */
-static void do_SWZ( struct arb_vp_machine *m, union instruction op )
-{
- GLfloat *result = m->File[0][op.rsw.dst];
- const GLfloat *arg0 = m->File[op.rsw.file0][op.rsw.idx0];
- const GLuint swz = op.rsw.swz;
- const GLuint neg = op.rsw.neg;
- GLfloat tmp[6];
- tmp[4] = 0.0;
- tmp[5] = 1.0;
-
- /* Need a temporary to be correct in the case where result == arg0.
- */
- COPY_4V(tmp, arg0);
-
- result[0] = tmp[GET_SWZ(swz, 0)];
- result[1] = tmp[GET_SWZ(swz, 1)];
- result[2] = tmp[GET_SWZ(swz, 2)];
- result[3] = tmp[GET_SWZ(swz, 3)];
-
- if (neg) {
- if (neg & 0x1) result[0] = -result[0];
- if (neg & 0x2) result[1] = -result[1];
- if (neg & 0x4) result[2] = -result[2];
- if (neg & 0x8) result[3] = -result[3];
- }
-}
-
-/* Used to implement write masking. To make things easier for the sse
- * generator I've gone back to a 1 argument version of this function
- * (dst.msk = arg), rather than the semantically cleaner (dst = SEL
- * arg0, arg1, msk)
- *
- * That means this is the only instruction which doesn't write a full
- * 4 dwords out. This would make such a program harder to analyse,
- * but it looks like analysis is going to take place on a higher level
- * anyway.
- */
-static void do_MSK( struct arb_vp_machine *m, union instruction op )
-{
- GLfloat *dst = m->File[0][op.msk.dst];
- const GLfloat *arg = m->File[op.msk.file][op.msk.idx];
-
- if (op.msk.mask & WRITEMASK_X) dst[0] = arg[0];
- if (op.msk.mask & WRITEMASK_Y) dst[1] = arg[1];
- if (op.msk.mask & WRITEMASK_Z) dst[2] = arg[2];
- if (op.msk.mask & WRITEMASK_W) dst[3] = arg[3];
-}
-
-
-static void do_PRT( struct arb_vp_machine *m, union instruction op )
-{
- const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
-
- _mesa_printf("%d: %f %f %f %f\n", m->vtx_nr,
- arg0[0], arg0[1], arg0[2], arg0[3]);
-}
-
-
-/**
- * The traditional ALU and texturing instructions. All operate on
- * internal registers and ignore write masks and swizzling issues.
- */
-
-static void do_ABS( 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] = (arg0[0] < 0.0) ? -arg0[0] : arg0[0];
- result[1] = (arg0[1] < 0.0) ? -arg0[1] : arg0[1];
- result[2] = (arg0[2] < 0.0) ? -arg0[2] : arg0[2];
- result[3] = (arg0[3] < 0.0) ? -arg0[3] : arg0[3];
-}
-
-static void do_ADD( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = arg0[0] + arg1[0];
- result[1] = arg0[1] + arg1[1];
- result[2] = arg0[2] + arg1[2];
- result[3] = arg0[3] + arg1[3];
-}
-
-
-static void do_DP3( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = (arg0[0] * arg1[0] +
- arg0[1] * arg1[1] +
- arg0[2] * arg1[2]);
-
- PUFF(result);
-}
-
-
-
-static void do_DP4( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = (arg0[0] * arg1[0] +
- arg0[1] * arg1[1] +
- arg0[2] * arg1[2] +
- arg0[3] * arg1[3]);
-
- PUFF(result);
-}
-
-static void do_DPH( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = (arg0[0] * arg1[0] +
- arg0[1] * arg1[1] +
- arg0[2] * arg1[2] +
- 1.0 * arg1[3]);
-
- PUFF(result);
-}
-
-static void do_DST( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- /* This should be ok even if result == arg0 or result == arg1.
- */
- result[0] = 1.0F;
- result[1] = arg0[1] * arg1[1];
- result[2] = arg0[2];
- result[3] = arg1[3];
-}
-
-
-/* Intended to be high precision:
- */
-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] = ApproxExp2(arg0[0]);
- PUFF(result);
-}
-
-
-/* Allowed to be lower precision:
- */
-static void do_EXP( 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];
- const GLfloat tmp = arg0[0];
- const GLfloat flr_tmp = FLOORF(tmp);
- const GLfloat frac_tmp = tmp - flr_tmp;
-
- result[0] = LDEXPF(1.0, (int)flr_tmp);
- result[1] = frac_tmp;
- result[2] = RoughApproxExp2(tmp);
- result[3] = 1.0F;
-}
-
-static void do_FLR( 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] = FLOORF(arg0[0]);
- result[1] = FLOORF(arg0[1]);
- result[2] = FLOORF(arg0[2]);
- result[3] = FLOORF(arg0[3]);
-}
-
-static void do_FRC( 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] = arg0[0] - FLOORF(arg0[0]);
- result[1] = arg0[1] - FLOORF(arg0[1]);
- result[2] = arg0[2] - FLOORF(arg0[2]);
- 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 )
-{
- GLfloat *result = m->File[0][op.alu.dst];
- const GLfloat *arg0 = m->File[op.alu.file0][op.alu.idx0];
-
- result[0] = ApproxLog2(arg0[0]);
- PUFF(result);
-}
-
-
-
-static void do_LIT( 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];
- GLfloat tmp[4]; /* use temp in case arg0 == result register */
-
- tmp[0] = 1.0;
- tmp[1] = arg0[0];
- if (arg0[0] > 0.0) {
- tmp[2] = RoughApproxPower(arg0[1], arg0[3]);
- }
- else {
- tmp[2] = 0.0;
- }
- tmp[3] = 1.0;
-
- COPY_4V(result, tmp);
-}
-
-
-/* Intended to allow a lower precision than required for LG2 above.
- */
-static void do_LOG( 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];
- const GLfloat tmp = FABSF(arg0[0]);
- int exponent;
- const GLfloat mantissa = FREXPF(tmp, &exponent);
-
- result[0] = (GLfloat) (exponent - 1);
- result[1] = 2.0 * mantissa; /* map [.5, 1) -> [1, 2) */
- result[2] = exponent + LOG2(mantissa);
- result[3] = 1.0;
-}
-
-static void do_MAX( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = (arg0[0] > arg1[0]) ? arg0[0] : arg1[0];
- result[1] = (arg0[1] > arg1[1]) ? arg0[1] : arg1[1];
- result[2] = (arg0[2] > arg1[2]) ? arg0[2] : arg1[2];
- result[3] = (arg0[3] > arg1[3]) ? arg0[3] : arg1[3];
-}
-
-
-static void do_MIN( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = (arg0[0] < arg1[0]) ? arg0[0] : arg1[0];
- result[1] = (arg0[1] < arg1[1]) ? arg0[1] : arg1[1];
- result[2] = (arg0[2] < arg1[2]) ? arg0[2] : arg1[2];
- result[3] = (arg0[3] < arg1[3]) ? arg0[3] : arg1[3];
-}
-
-static void do_MOV( 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] = arg0[0];
- result[1] = arg0[1];
- result[2] = arg0[2];
- result[3] = arg0[3];
-}
-
-static void do_MUL( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = arg0[0] * arg1[0];
- result[1] = arg0[1] * arg1[1];
- result[2] = arg0[2] * arg1[2];
- result[3] = arg0[3] * arg1[3];
-}
-
-
-/* Intended to be "high" precision
- */
-static void do_POW( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = (GLfloat)ApproxPower(arg0[0], arg1[0]);
- PUFF(result);
-}
-
-static void do_REL( struct arb_vp_machine *m, union instruction op )
-{
- GLfloat *result = m->File[0][op.alu.dst];
- const GLuint idx = (op.alu.idx0 + (GLint)m->File[0][REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1);
- const GLfloat *arg0 = m->File[op.alu.file0][idx];
-
- result[0] = arg0[0];
- result[1] = arg0[1];
- result[2] = arg0[2];
- result[3] = arg0[3];
-}
-
-static void do_RCP( 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] = 1.0F / arg0[0];
- PUFF(result);
-}
-
-static void do_RSQ( 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] = INV_SQRTF(FABSF(arg0[0]));
- PUFF(result);
-}
-
-
-static void do_SGE( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = (arg0[0] >= arg1[0]) ? 1.0F : 0.0F;
- result[1] = (arg0[1] >= arg1[1]) ? 1.0F : 0.0F;
- result[2] = (arg0[2] >= arg1[2]) ? 1.0F : 0.0F;
- result[3] = (arg0[3] >= arg1[3]) ? 1.0F : 0.0F;
-}
-
-
-static void do_SLT( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = (arg0[0] < arg1[0]) ? 1.0F : 0.0F;
- result[1] = (arg0[1] < arg1[1]) ? 1.0F : 0.0F;
- result[2] = (arg0[2] < arg1[2]) ? 1.0F : 0.0F;
- result[3] = (arg0[3] < arg1[3]) ? 1.0F : 0.0F;
-}
-
-static void do_SUB( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
-
- result[0] = arg0[0] - arg1[0];
- result[1] = arg0[1] - arg1[1];
- result[2] = arg0[2] - arg1[2];
- result[3] = arg0[3] - arg1[3];
-}
-
-
-static void do_XPD( 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];
- const GLfloat *arg1 = m->File[op.alu.file1][op.alu.idx1];
- GLfloat tmp[3];
-
- tmp[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1];
- tmp[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2];
- tmp[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0];
-
- /* Need a temporary to be correct in the case where result == arg0
- * or result == arg1.
- */
- result[0] = tmp[0];
- result[1] = tmp[1];
- result[2] = tmp[2];
-}
-
-static void do_NOP( struct arb_vp_machine *m, union instruction op )
-{
-}
-
-/* Some useful debugging functions:
- */
-static void print_mask( GLuint mask )
-{
- _mesa_printf(".");
- if (mask & WRITEMASK_X) _mesa_printf("x");
- if (mask & WRITEMASK_Y) _mesa_printf("y");
- if (mask & WRITEMASK_Z) _mesa_printf("z");
- if (mask & WRITEMASK_W) _mesa_printf("w");
-}
-
-static void print_reg( GLuint file, GLuint reg )
-{
- static const char *reg_file[] = {
- "REG",
- "LOCAL_PARAM",
- "ENV_PARAM",
- "STATE_VAR",
- };
-
- if (file == 0) {
- if (reg == REG_RES)
- _mesa_printf("RES");
- else if (reg >= REG_ARG0 && reg <= REG_ARG1)
- _mesa_printf("ARG%d", reg - REG_ARG0);
- else if (reg >= REG_TMP0 && reg <= REG_TMP11)
- _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_OUT23)
- _mesa_printf("OUT%d", reg - REG_OUT0);
- else if (reg == REG_ADDR)
- _mesa_printf("ADDR");
- else if (reg == REG_ID)
- _mesa_printf("ID");
- else
- _mesa_printf("REG%d", reg);
- }
- else
- _mesa_printf("%s:%d", reg_file[file], reg);
-}
-
-
-static void print_RSW( union instruction op )
-{
- GLuint swz = op.rsw.swz;
- GLuint neg = op.rsw.neg;
- GLuint i;
-
- _mesa_printf("RSW ");
- print_reg(0, op.rsw.dst);
- _mesa_printf(", ");
- print_reg(op.rsw.file0, op.rsw.idx0);
- _mesa_printf(".");
- for (i = 0; i < 4; i++, swz >>= 3) {
- const char *cswz = "xyzw01";
- if (neg & (1<<i))
- _mesa_printf("-");
- _mesa_printf("%c", cswz[swz&0x7]);
- }
- _mesa_printf("\n");
-}
-
-static void print_SWZ( union instruction op )
-{
- GLuint swz = op.rsw.swz;
- GLuint neg = op.rsw.neg;
- GLuint i;
-
- _mesa_printf("SWZ ");
- print_reg(0, op.rsw.dst);
- _mesa_printf(", ");
- print_reg(op.rsw.file0, op.rsw.idx0);
- _mesa_printf(".");
- for (i = 0; i < 4; i++, swz >>= 3) {
- const char *cswz = "xyzw01";
- if (neg & (1<<i))
- _mesa_printf("-");
- _mesa_printf("%c", cswz[swz&0x7]);
- }
- _mesa_printf("\n");
-}
-
-
-static void print_ALU( union instruction op )
-{
- _mesa_printf("%s ", _mesa_opcode_string((enum prog_opcode) op.alu.opcode));
- print_reg(0, op.alu.dst);
- _mesa_printf(", ");
- print_reg(op.alu.file0, op.alu.idx0);
- if (_mesa_num_inst_src_regs((enum prog_opcode) op.alu.opcode) > 1) {
- _mesa_printf(", ");
- print_reg(op.alu.file1, op.alu.idx1);
- }
- _mesa_printf("\n");
-}
-
-static void print_MSK( union instruction op )
-{
- _mesa_printf("MSK ");
- print_reg(0, op.msk.dst);
- print_mask(op.msk.mask);
- _mesa_printf(", ");
- print_reg(op.msk.file, op.msk.idx);
- _mesa_printf("\n");
-}
-
-static void print_NOP( union instruction op )
-{
-}
-
-void
-_tnl_disassem_vba_insn( union instruction op )
-{
- switch (op.alu.opcode) {
- case OPCODE_ABS:
- case OPCODE_ADD:
- case OPCODE_DP3:
- case OPCODE_DP4:
- case OPCODE_DPH:
- case OPCODE_DST:
- case OPCODE_EX2:
- case OPCODE_EXP:
- case OPCODE_FLR:
- case OPCODE_FRC:
- case OPCODE_INT:
- case OPCODE_LG2:
- case OPCODE_LIT:
- case OPCODE_LOG:
- case OPCODE_MAX:
- case OPCODE_MIN:
- case OPCODE_MOV:
- case OPCODE_MUL:
- case OPCODE_POW:
- case OPCODE_PRINT:
- case OPCODE_RCP:
- case OPCODE_RSQ:
- case OPCODE_SGE:
- case OPCODE_SLT:
- case OPCODE_SUB:
- case OPCODE_XPD:
- print_ALU(op);
- break;
- case OPCODE_ARA:
- case OPCODE_ARL:
- case OPCODE_ARL_NV:
- case OPCODE_ARR:
- case OPCODE_BRA:
- case OPCODE_CAL:
- case OPCODE_END:
- case OPCODE_MAD:
- case OPCODE_POPA:
- case OPCODE_PUSHA:
- case OPCODE_RCC:
- case OPCODE_RET:
- case OPCODE_SSG:
- print_NOP(op);
- break;
- case OPCODE_SWZ:
- print_SWZ(op);
- break;
- case RSW:
- print_RSW(op);
- break;
- case MSK:
- print_MSK(op);
- break;
- case REL:
- print_ALU(op);
- break;
- default:
- _mesa_problem(NULL, "Bad opcode in _tnl_disassem_vba_insn()");
- }
-}
-
-typedef void (*gpu_function)(struct arb_vp_machine *m, union instruction op);
-
-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*/
- do_DP3,
- do_DP4,
- do_DPH,
- do_DST,
- 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,
- do_LIT,
- do_LOG,
- do_NOP,/*LRP*/
- do_NOP,/*MAD*/
- do_MAX,
- 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*/
- do_NOP,/*PK4UB*/
- do_POW,
- do_NOP,/*POPA*/
- do_PRT,
- do_NOP,/*PUSHA*/
- do_NOP,/*RCC*/
- do_RCP,/*RCP*/
- do_NOP,/*RET*/
- do_NOP,/*RFL*/
- do_RSQ,
- do_NOP,/*SCS*/
- do_NOP,/*SEQ*/
- do_NOP,/*SFL*/
- do_SGE,
- do_NOP,/*SGT*/
- do_NOP,/*SIN*/
- do_NOP,/*SLE*/
- do_SLT,
- do_NOP,/*SNE*/
- do_NOP,/*SSG*/
- do_NOP,/*STR*/
- do_SUB,
- do_SWZ,/*SWZ*/
- do_NOP,/*TEX*/
- do_NOP,/*TXB*/
- do_NOP,/*TXD*/
- do_NOP,/*TXL*/
- do_NOP,/*TXP*/
- do_NOP,/*TXP_NV*/
- do_NOP,/*UP2H*/
- do_NOP,/*UP2US*/
- do_NOP,/*UP4B*/
- do_NOP,/*UP4UB*/
- do_NOP,/*X2D*/
- do_XPD,
- do_RSW,
- do_MSK,
- do_REL,
-};
-
-static union instruction *cvp_next_instruction( struct compilation *cp )
-{
- union instruction *op = cp->csr++;
- _mesa_bzero(op, sizeof(*op));
- return op;
-}
-
-static struct reg cvp_make_reg( GLuint file, GLuint idx )
-{
- struct reg reg;
- reg.file = file;
- reg.idx = idx;
- return reg;
-}
-
-static struct reg cvp_emit_rel( struct compilation *cp,
- struct reg reg,
- struct reg tmpreg )
-{
- union instruction *op = cvp_next_instruction(cp);
- op->alu.opcode = REL;
- op->alu.file0 = reg.file;
- op->alu.idx0 = reg.idx;
- op->alu.dst = tmpreg.idx;
- return tmpreg;
-}
-
-
-static struct reg cvp_load_reg( struct compilation *cp,
- GLuint file,
- GLuint index,
- GLuint rel,
- GLuint tmpidx )
-{
- struct reg tmpreg = cvp_make_reg(FILE_REG, tmpidx);
- struct reg reg;
-
- switch (file) {
- case PROGRAM_TEMPORARY:
- assert(REG_TMP0 + index <= REG_TMP11);
- return cvp_make_reg(FILE_REG, REG_TMP0 + index);
-
- case PROGRAM_INPUT:
- return cvp_make_reg(FILE_REG, REG_IN0 + index);
-
- case PROGRAM_OUTPUT:
- return cvp_make_reg(FILE_REG, REG_OUT0 + index);
-
- /* These two aren't populated by the parser?
- */
- case PROGRAM_LOCAL_PARAM:
- reg = cvp_make_reg(FILE_LOCAL_PARAM, index);
- if (rel)
- return cvp_emit_rel(cp, reg, tmpreg);
- else
- return reg;
-
- case PROGRAM_ENV_PARAM:
- reg = cvp_make_reg(FILE_ENV_PARAM, index);
- if (rel)
- return cvp_emit_rel(cp, reg, tmpreg);
- else
- 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);
- else
- return reg;
-
- /* Invalid values:
- */
- case PROGRAM_WRITE_ONLY:
- case PROGRAM_ADDRESS:
- default:
- _mesa_problem(NULL, "Invalid register file %d in cvp_load_reg()", file);
- assert(0);
- return tmpreg; /* can't happen */
- }
-}
-
-static struct reg cvp_emit_arg( struct compilation *cp,
- const struct prog_src_register *src,
- GLuint arg )
-{
- struct reg reg = cvp_load_reg( cp, src->File, src->Index, src->RelAddr, arg );
- union instruction rsw, noop;
-
- /* Emit any necessary swizzling.
- */
- _mesa_bzero(&rsw, sizeof(rsw));
- rsw.rsw.neg = src->NegateBase ? WRITEMASK_XYZW : 0;
-
- /* we're expecting 2-bit swizzles below... */
-#if 1 /* XXX THESE ASSERTIONS CURRENTLY FAIL DURING GLEAN TESTS! */
-/* hopefully no longer happens? */
- ASSERT(GET_SWZ(src->Swizzle, 0) < 4);
- ASSERT(GET_SWZ(src->Swizzle, 1) < 4);
- ASSERT(GET_SWZ(src->Swizzle, 2) < 4);
- ASSERT(GET_SWZ(src->Swizzle, 3) < 4);
-#endif
- rsw.rsw.swz = src->Swizzle;
-
- _mesa_bzero(&noop, sizeof(noop));
- noop.rsw.neg = 0;
- noop.rsw.swz = SWIZZLE_NOOP;
-
- if (_mesa_memcmp(&rsw, &noop, sizeof(rsw)) !=0) {
- union instruction *op = cvp_next_instruction(cp);
- struct reg rsw_reg = cvp_make_reg(FILE_REG, REG_ARG0 + arg);
- *op = rsw;
- op->rsw.opcode = RSW;
- op->rsw.file0 = reg.file;
- op->rsw.idx0 = reg.idx;
- op->rsw.dst = rsw_reg.idx;
- return rsw_reg;
- }
- else
- return reg;
-}
-
-static GLuint cvp_choose_result( struct compilation *cp,
- const struct prog_dst_register *dst,
- union instruction *fixup )
-{
- GLuint mask = dst->WriteMask;
- GLuint idx;
-
- switch (dst->File) {
- case PROGRAM_TEMPORARY:
- idx = REG_TMP0 + dst->Index;
- break;
- case PROGRAM_OUTPUT:
- 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 */
- }
-
- /* Optimization: When writing (with a writemask) to an undefined
- * value for the first time, the writemask may be ignored.
- */
- if (mask != WRITEMASK_XYZW && (cp->reg_active & (1 << idx))) {
- fixup->msk.opcode = MSK;
- fixup->msk.dst = idx;
- fixup->msk.file = FILE_REG;
- fixup->msk.idx = REG_RES;
- fixup->msk.mask = mask;
- cp->reg_active |= 1 << idx;
- return REG_RES;
- }
- else {
- _mesa_bzero(fixup, sizeof(*fixup));
- cp->reg_active |= 1 << idx;
- return idx;
- }
-}
-
-
-static void cvp_emit_inst( struct compilation *cp,
- const struct prog_instruction *inst )
-{
- union instruction *op;
- union instruction fixup;
- struct reg reg[3];
- GLuint result, nr_args, i;
-
- /* Need to handle SWZ, ARL specially.
- */
- switch (inst->Opcode) {
- /* Split into mul and add:
- */
- case OPCODE_MAD:
- result = cvp_choose_result( cp, &inst->DstReg, &fixup );
- for (i = 0; i < 3; i++)
- reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0+i );
-
- op = cvp_next_instruction(cp);
- op->alu.opcode = OPCODE_MUL;
- op->alu.file0 = reg[0].file;
- op->alu.idx0 = reg[0].idx;
- op->alu.file1 = reg[1].file;
- op->alu.idx1 = reg[1].idx;
- op->alu.dst = REG_ARG0;
-
- op = cvp_next_instruction(cp);
- op->alu.opcode = OPCODE_ADD;
- op->alu.file0 = FILE_REG;
- op->alu.idx0 = REG_ARG0;
- op->alu.file1 = reg[2].file;
- op->alu.idx1 = reg[2].idx;
- op->alu.dst = result;
-
- if (result == REG_RES) {
- op = cvp_next_instruction(cp);
- *op = fixup;
- }
- break;
-
- case OPCODE_ARL:
- reg[0] = cvp_emit_arg( cp, &inst->SrcReg[0], REG_ARG0 );
-
- op = cvp_next_instruction(cp);
- op->alu.opcode = OPCODE_FLR;
- op->alu.dst = REG_ADDR;
- op->alu.file0 = reg[0].file;
- op->alu.idx0 = reg[0].idx;
- break;
-
- case OPCODE_END:
- break;
-
- case OPCODE_SWZ:
- result = cvp_choose_result( cp, &inst->DstReg, &fixup );
- reg[0] = cvp_load_reg( cp, inst->SrcReg[0].File,
- inst->SrcReg[0].Index, inst->SrcReg[0].RelAddr, REG_ARG0 );
- op = cvp_next_instruction(cp);
- op->rsw.opcode = inst->Opcode;
- op->rsw.file0 = reg[0].file;
- op->rsw.idx0 = reg[0].idx;
- op->rsw.dst = result;
- op->rsw.swz = inst->SrcReg[0].Swizzle;
- op->rsw.neg = inst->SrcReg[0].NegateBase;
-
- if (result == REG_RES) {
- op = cvp_next_instruction(cp);
- *op = fixup;
- }
- 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);
- for (i = 0; i < nr_args; i++)
- reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0 + i );
-
- op = cvp_next_instruction(cp);
- op->alu.opcode = inst->Opcode;
- op->alu.file0 = reg[0].file;
- op->alu.idx0 = reg[0].idx;
- op->alu.file1 = reg[1].file;
- op->alu.idx1 = reg[1].idx;
- op->alu.dst = result;
-
- if (result == REG_RES) {
- op = cvp_next_instruction(cp);
- *op = fixup;
- }
- break;
- }
-}
-
-static void free_tnl_data( struct gl_vertex_program *program )
-{
- struct tnl_compiled_program *p = (struct tnl_compiled_program *) program->TnlData;
- if (p->compiled_func)
- _mesa_free((void *)p->compiled_func);
- _mesa_free(p);
- program->TnlData = NULL;
-}
-
-static void compile_vertex_program( struct gl_vertex_program *program,
- GLboolean try_codegen )
-{
- struct compilation cp;
- 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 );
-
- program->TnlData = p;
-
- /* Initialize cp. Note that ctx and VB aren't used in compilation
- * so we don't have to worry about statechanges:
- */
- _mesa_memset(&cp, 0, sizeof(cp));
- cp.csr = p->instructions;
-
- /* Compile instructions:
- */
- for (i = 0; i < program->Base.NumInstructions; i++) {
- cvp_emit_inst(&cp, &program->Base.Instructions[i]);
- }
-
- /* Finish up:
- */
- p->nr_instructions = cp.csr - p->instructions;
-
- /* Print/disassemble:
- */
- if (DISASSEM) {
- for (i = 0; i < p->nr_instructions; i++) {
- _tnl_disassem_vba_insn(p->instructions[i]);
- }
- _mesa_printf("\n\n");
- }
-
-#ifdef USE_SSE_ASM
- if (try_codegen)
- _tnl_sse_codegen_vertex_program(p);
-#endif
-
-}
-
-
-
-/* ----------------------------------------------------------------------
- * Execution
- */
-static void userclip( GLcontext *ctx,
- GLvector4f *clip,
- GLubyte *clipmask,
- GLubyte *clipormask,
- GLubyte *clipandmask )
-{
- GLuint p;
-
- for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
- if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
- GLuint nr, i;
- const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
- const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
- const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
- const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
- GLfloat *coord = (GLfloat *)clip->data;
- GLuint stride = clip->stride;
- GLuint count = clip->count;
-
- for (nr = 0, i = 0 ; i < count ; i++) {
- GLfloat dp = (coord[0] * a +
- coord[1] * b +
- coord[2] * c +
- coord[3] * d);
-
- if (dp < 0) {
- nr++;
- clipmask[i] |= CLIP_USER_BIT;
- }
-
- STRIDE_F(coord, stride);
- }
-
- if (nr > 0) {
- *clipormask |= CLIP_USER_BIT;
- if (nr == count) {
- *clipandmask |= CLIP_USER_BIT;
- return;
- }
- }
- }
- }
-}
-
-
-static GLboolean
-do_ndc_cliptest(GLcontext *ctx, struct arb_vp_machine *m)
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct vertex_buffer *VB = m->VB;
-
- /* Cliptest and perspective divide. Clip functions must clear
- * the clipmask.
- */
- m->ormask = 0;
- m->andmask = CLIP_FRUSTUM_BITS;
-
- if (tnl->NeedNdcCoords) {
- VB->NdcPtr =
- _mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
- &m->ndcCoords,
- m->clipmask,
- &m->ormask,
- &m->andmask );
- }
- else {
- VB->NdcPtr = NULL;
- _mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
- NULL,
- m->clipmask,
- &m->ormask,
- &m->andmask );
- }
-
- if (m->andmask) {
- /* All vertices are outside the frustum */
- return GL_FALSE;
- }
-
- /* 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,
- VB->ClipPtr,
- m->clipmask,
- &m->ormask,
- &m->andmask );
-
- if (m->andmask) {
- return GL_FALSE;
- }
- }
-
- VB->ClipAndMask = m->andmask;
- VB->ClipOrMask = m->ormask;
- VB->ClipMask = m->clipmask;
-
- return GL_TRUE;
-}
-
-
-static INLINE void call_func( struct tnl_compiled_program *p,
- struct arb_vp_machine *m )
-{
- p->compiled_func(m);
-}
-
-
-/**
- * Execute the given vertex program.
- *
- * TODO: Integrate the t_vertex.c code here, to build machine vertices
- * directly at this point.
- *
- * TODO: Eliminate the VB struct entirely and just use
- * struct arb_vertex_machine.
- */
-static GLboolean
-run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
-{
- 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;
-
-#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);
- }
-
- p = (struct tnl_compiled_program *)program->TnlData;
- assert(p);
-
-
- m->nr_inputs = m->nr_outputs = 0;
-
- for (i = 0; i < VERT_ATTRIB_MAX; i++) {
- if (program->Base.InputsRead & (1<<i)) {
- GLuint j = m->nr_inputs++;
- m->input[j].idx = i;
- m->input[j].data = (GLfloat *)m->VB->AttribPtr[i]->data;
- m->input[j].stride = m->VB->AttribPtr[i]->stride;
- m->input[j].size = m->VB->AttribPtr[i]->size;
- ASSIGN_4V(m->File[0][REG_IN0 + i], 0, 0, 0, 1);
- }
- }
-
- for (i = 0; i < VERT_RESULT_MAX; i++) {
- if (program->Base.OutputsWritten & (1 << i)) {
- GLuint j = m->nr_outputs++;
- m->output[j].idx = i;
- m->output[j].data = (GLfloat *)m->attribs[i].data;
- }
- }
-
-
- /* Run the actual program:
- */
- for (m->vtx_nr = 0; m->vtx_nr < VB->Count; m->vtx_nr++) {
- for (j = 0; j < m->nr_inputs; j++) {
- GLuint idx = REG_IN0 + m->input[j].idx;
- switch (m->input[j].size) {
- case 4: m->File[0][idx][3] = m->input[j].data[3];
- case 3: m->File[0][idx][2] = m->input[j].data[2];
- 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);
- }
-
-
- if (p->compiled_func) {
- call_func( p, m );
- }
- else {
- GLint pc;
- for (pc = 0; pc < p->nr_instructions; pc++) {
- union instruction inst = p->instructions[pc];
- opcode_func[inst.alu.opcode]( m, inst );
- }
- }
-
- for (j = 0; j < m->nr_outputs; j++) {
- GLuint idx = REG_OUT0 + m->output[j].idx;
- m->output[j].data[0] = m->File[0][idx][0];
- m->output[j].data[1] = m->File[0][idx][1];
- m->output[j].data[2] = m->File[0][idx][2];
- m->output[j].data[3] = m->File[0][idx][3];
- m->output[j].data += 4;
- }
-
- }
-
- /* Setup the VB pointers so that the next pipeline stages get
- * their data from the right place (the program output arrays).
- *
- * TODO: 1) Have tnl use these RESULT values for outputs rather
- * than trying to shoe-horn inputs and outputs into one set of
- * values.
- *
- * TODO: 2) Integrate t_vertex.c so that we just go straight ahead
- * and build machine vertices here.
- */
-
- /* XXX There seems to be confusion between using the VERT_ATTRIB_*
- * values vs _TNL_ATTRIB_* tokens here:
- */
- outputs = program->Base.OutputsWritten;
-
- if (program->IsPositionInvariant) {
- /* We need the exact same transform as in the fixed function path here
- to guarantee invariance, depending on compiler optimization flags results
- could be different otherwise */
- VB->ClipPtr = TransformRaw( &m->attribs[0],
- &ctx->_ModelProjectMatrix,
- m->VB->AttribPtr[0] );
-
- /* Drivers expect this to be clean to element 4...
- */
- switch (VB->ClipPtr->size) {
- case 1:
- /* impossible */
- case 2:
- _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 2 );
- /* fall-through */
- case 3:
- _mesa_vector4f_clean_elem( VB->ClipPtr, VB->Count, 3 );
- /* fall-through */
- case 4:
- break;
- }
- }
- else {
- VB->ClipPtr = &m->attribs[VERT_RESULT_HPOS];
- VB->ClipPtr->count = VB->Count;
- }
-
- if (outputs & (1<<VERT_RESULT_COL0)) {
- VB->ColorPtr[0] =
- VB->AttribPtr[VERT_ATTRIB_COLOR0] = &m->attribs[VERT_RESULT_COL0];
- }
-
- if (outputs & (1<<VERT_RESULT_BFC0)) {
- VB->ColorPtr[1] = &m->attribs[VERT_RESULT_BFC0];
- }
-
- if (outputs & (1<<VERT_RESULT_COL1)) {
- VB->SecondaryColorPtr[0] =
- VB->AttribPtr[VERT_ATTRIB_COLOR1] = &m->attribs[VERT_RESULT_COL1];
- }
-
- if (outputs & (1<<VERT_RESULT_BFC1)) {
- VB->SecondaryColorPtr[1] = &m->attribs[VERT_RESULT_BFC1];
- }
-
- if (outputs & (1<<VERT_RESULT_FOGC)) {
- VB->FogCoordPtr =
- VB->AttribPtr[VERT_ATTRIB_FOG] = &m->attribs[VERT_RESULT_FOGC];
- }
-
- if (outputs & (1<<VERT_RESULT_PSIZ)) {
- VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &m->attribs[VERT_RESULT_PSIZ];
- }
-
- for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
- if (outputs & (1<<(VERT_RESULT_TEX0+i))) {
- VB->TexCoordPtr[i] =
- VB->AttribPtr[VERT_ATTRIB_TEX0+i] = &m->attribs[VERT_RESULT_TEX0 + i];
- }
- }
-
- 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,
- VEC_ELT(VB->ClipPtr, GLfloat, i)[0],
- VEC_ELT(VB->ClipPtr, GLfloat, i)[1],
- VEC_ELT(VB->ClipPtr, GLfloat, i)[2],
- VEC_ELT(VB->ClipPtr, GLfloat, i)[3],
- VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[0],
- VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[1],
- VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[2],
- VEC_ELT(VB->AttribPtr[VERT_ATTRIB_TEX0], GLfloat, i)[3]);
- }
-#endif
-
- /* Perform NDC and cliptest operations:
- */
- return do_ndc_cliptest(ctx, m);
-}
-
-
-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 = ctx->VertexProgram._Current;
-
-#if FORCE_OLD
- if (0 &&program) {
-#else
- if (program) {
-#endif
- if (!program->TnlData)
- compile_vertex_program( program, m->try_codegen );
-
- /* Grab the state GL state and put into registers:
- */
- m->File[FILE_LOCAL_PARAM] = program->Base.LocalParams;
- m->File[FILE_ENV_PARAM] = ctx->VertexProgram.Parameters;
- /* GL_NV_vertex_programs can't reference GL state */
- if (program->Base.Parameters)
- m->File[FILE_STATE_PARAM] = program->Base.Parameters->ParameterValues;
- else
- m->File[FILE_STATE_PARAM] = NULL;
- }
-}
-
-
-/**
- * Called the first time stage->run is called. In effect, don't
- * allocate data until the first time the stage is run.
- */
-static GLboolean init_vertex_program( GLcontext *ctx,
- struct tnl_pipeline_stage *stage )
-{
- TNLcontext *tnl = TNL_CONTEXT(ctx);
- struct vertex_buffer *VB = &(tnl->vb);
- struct arb_vp_machine *m;
- 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)
- return GL_FALSE;
-
- /* arb_vertex_machine struct should subsume the VB:
- */
- m->VB = VB;
-
- m->File[0] = (GLfloat(*)[4])ALIGN_MALLOC(REG_MAX * sizeof(GLfloat) * 4, 16);
-
- /* Initialize regs where necessary:
- */
- ASSIGN_4V(m->File[0][REG_ID], 0, 0, 0, 1);
- ASSIGN_4V(m->File[0][REG_ONES], 1, 1, 1, 1);
- ASSIGN_4V(m->File[0][REG_SWZ], 1, -1, 0, 0);
- ASSIGN_4V(m->File[0][REG_NEG], -1, -1, -1, -1);
- ASSIGN_4V(m->File[0][REG_LIT], 1, 0, 0, 1);
- ASSIGN_4V(m->File[0][REG_LIT2], 1, .5, .2, 1); /* debug value */
-
- if (_mesa_getenv("MESA_EXPERIMENTAL"))
- m->try_codegen = GL_TRUE;
-
- /* Allocate arrays of vertex output values */
- for (i = 0; i < VERT_RESULT_MAX; i++) {
- _mesa_vector4f_alloc( &m->attribs[i], 0, size, 32 );
- m->attribs[i].size = 4;
- }
-
- /* a few other misc allocations */
- _mesa_vector4f_alloc( &m->ndcCoords, 0, size, 32 );
- m->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
-
- if (ctx->VertexProgram._MaintainTnlProgram)
- _mesa_allow_light_in_model( ctx, GL_FALSE );
-
- m->fpucntl_rnd_neg = RND_NEG_FPU; /* const value */
- m->fpucntl_restore = RESTORE_FPU; /* const value */
-
- return GL_TRUE;
-}
-
-
-/**
- * Destructor for this pipeline stage.
- */
-static void dtr( struct tnl_pipeline_stage *stage )
-{
- struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
-
- if (m) {
- GLuint i;
-
- /* free the vertex program result arrays */
- for (i = 0; i < VERT_RESULT_MAX; i++)
- _mesa_vector4f_free( &m->attribs[i] );
-
- /* free misc arrays */
- _mesa_vector4f_free( &m->ndcCoords );
- ALIGN_FREE( m->clipmask );
- ALIGN_FREE( m->File[0] );
-
- _mesa_free( m );
- stage->privatePtr = NULL;
- }
-}
-
-
-/**
- * Public description of this pipeline stage.
- */
-const struct tnl_pipeline_stage _tnl_arb_vertex_program_stage =
-{
- "arb-vertex-program",
- NULL, /* private_data */
- init_vertex_program, /* create */
- dtr, /* destroy */
- validate_vertex_program, /* validate */
- run_arb_vertex_program /* run */
-};
-
-
-/**
- * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
- * string has been parsed.
- */
-void
-_tnl_program_string(GLcontext *ctx, GLenum target, struct gl_program *program)
-{
- if (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) {
- free_tnl_data(vprog);
- }
- }
-}
diff --git a/src/mesa/tnl/t_vb_arbprogram.h b/src/mesa/tnl/t_vb_arbprogram.h
deleted file mode 100644
index 1bec2a411e..0000000000
--- a/src/mesa/tnl/t_vb_arbprogram.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.5
- *
- * Copyright (C) 1999-2005 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.
- */
-
-/**
- * \file t_arb_program.c
- * Compile vertex programs to an intermediate representation.
- * Execute vertex programs over a buffer of vertices.
- * \author Keith Whitwell, Brian Paul
- */
-
-
-#ifndef _T_VB_ARBPROGRAM_H_
-#define _T_VB_ARBPROGRAM_H_
-
-
-/* New, internal instructions:
- */
-#define RSW (MAX_OPCODE)
-#define MSK (MAX_OPCODE+1)
-#define REL (MAX_OPCODE+2)
-
-/**
- * Register files for vertex programs
- */
-#define FILE_REG 0 /* temporaries */
-#define FILE_LOCAL_PARAM 1 /* local parameters */
-#define FILE_ENV_PARAM 2 /* global parameters */
-#define FILE_STATE_PARAM 3 /* GL state references */
-
-#define REG_ARG0 0
-#define REG_ARG1 1
-#define REG_ARG2 2
-#define REG_RES 3
-#define REG_ADDR 4
-#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
-#define REG_ID 64 /* 0,0,0,1 */
-#define REG_ONES 65 /* 1,1,1,1 */
-#define REG_SWZ 66 /* 1,-1,0,0 */
-#define REG_NEG 67 /* -1,-1,-1,-1 */
-#define REG_LIT 68 /* 1,0,0,1 */
-#define REG_LIT2 69 /* 1,0,0,1 */
-#define REG_SCRATCH 70 /* 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
-#endif
-
-/* ARB_vp instructions are broken down into one or more of the
- * following micro-instructions, each representable in a 64 bit packed
- * structure.
- */
-struct reg {
- GLuint file:2;
- GLuint idx:8;
-};
-
-
-union instruction {
- struct {
- GLuint opcode:7;
- GLuint dst:6;
- GLuint file0:2;
- GLuint idx0:8;
- GLuint file1:2;
- GLuint idx1:7;
- GLuint pad:2;
- GLuint pad2;
- } alu;
-
- struct {
- GLuint opcode:7;
- GLuint dst:6;
- GLuint file0:2;
- GLuint idx0:8;
- GLuint neg:4;
- GLuint swz:12; /* xyzw01 */
- } rsw;
-
- struct {
- GLuint opcode:7;
- GLuint dst:6;
- GLuint file:2;
- GLuint idx:8;
- GLuint mask:4;
- GLuint pad:7;
- GLuint pad2;
- } msk;
-};
-
-
-/**
- * Reduced swizzle is a 3-bit field, for simplicity same as normal swizzle, X/Y/Z/W/0/1 allowed.
- */
-
-struct input {
- GLuint idx;
- GLfloat *data;
- GLuint stride;
- GLuint size;
-};
-
-struct output {
- GLuint idx;
- GLfloat *data;
-};
-
-
-
-/*--------------------------------------------------------------------------- */
-#if defined(USE_SSE_ASM)
-#ifdef NO_FAST_MATH
-#define RESTORE_FPU (DEFAULT_X86_FPU)
-#define RND_NEG_FPU (DEFAULT_X86_FPU | 0x400)
-#else
-#define RESTORE_FPU (FAST_X86_FPU)
-#define RND_NEG_FPU (FAST_X86_FPU | 0x400)
-#endif
-#else
-#define RESTORE_FPU 0
-#define RND_NEG_FPU 0
-#endif
-
-
-/**
- * Private storage for the vertex program pipeline stage.
- */
-struct arb_vp_machine {
- GLfloat (*File[4])[4]; /* All values referencable from the program. */
-
- struct input input[VERT_ATTRIB_MAX];
- GLuint nr_inputs;
-
- struct output output[VERT_RESULT_MAX];
- GLuint nr_outputs;
-
- GLvector4f attribs[VERT_RESULT_MAX]; /**< result vectors. */
- GLvector4f ndcCoords; /**< normalized device coords */
- GLubyte *clipmask; /**< clip flags */
- GLubyte ormask, andmask; /**< for clipping */
-
- GLuint vtx_nr; /**< loop counter */
-
- struct vertex_buffer *VB;
-
- GLshort fpucntl_rnd_neg; /* constant value */
- GLshort fpucntl_restore; /* constant value */
-
- GLboolean try_codegen;
-};
-
-struct tnl_compiled_program {
- union instruction instructions[1024];
- GLint nr_instructions;
- void (*compiled_func)( struct arb_vp_machine * ); /**< codegen'd program */
-};
-
-void _tnl_program_string_change( struct gl_vertex_program * );
-void _tnl_program_destroy( struct gl_vertex_program * );
-
-void _tnl_disassem_vba_insn( union instruction op );
-
-GLboolean _tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p);
-
-#endif
diff --git a/src/mesa/tnl/t_vb_arbprogram_sse.c b/src/mesa/tnl/t_vb_arbprogram_sse.c
deleted file mode 100644
index d0f66fd619..0000000000
--- a/src/mesa/tnl/t_vb_arbprogram_sse.c
+++ /dev/null
@@ -1,1330 +0,0 @@
-/*
- * Mesa 3-D graphics library
- * Version: 6.3
- *
- * Copyright (C) 1999-2004 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.
- */
-
-/**
- * \file t_vb_arb_program_sse.c
- *
- * Translate simplified vertex_program representation to
- * x86/x87/SSE/SSE2 machine code using mesa's rtasm runtime assembler.
- *
- * This is very much a first attempt - build something that works.
- * There are probably better approaches for applying SSE to vertex
- * programs, and the whole thing is crying out for static analysis of
- * the programs to avoid redundant operations.
- *
- * \author Keith Whitwell
- */
-
-#include "glheader.h"
-#include "context.h"
-#include "imports.h"
-#include "macros.h"
-#include "mtypes.h"
-#include "arbprogparse.h"
-#include "program.h"
-#include "prog_instruction.h"
-#include "math/m_matrix.h"
-#include "math/m_translate.h"
-#include "t_context.h"
-#include "t_vb_arbprogram.h"
-
-#if defined(USE_SSE_ASM)
-
-#include "x86/rtasm/x86sse.h"
-#include "x86/common_x86_asm.h"
-
-#define X 0
-#define Y 1
-#define Z 2
-#define W 3
-
-/* Reg usage:
- *
- * EAX - temp
- * EBX - point to 'm->File[0]'
- * ECX - point to 'm->File[3]'
- * EDX - holds 'm'
- * EBP,
- * ESI,
- * EDI
- */
-
-#define DISASSEM 0
-
-#define FAIL \
-do { \
- _mesa_printf("x86 translation failed in %s\n", __FUNCTION__); \
- return GL_FALSE; \
-} while (0)
-
-struct compilation {
- struct x86_function func;
- struct tnl_compiled_program *p;
- GLuint insn_counter;
-
- struct {
- GLuint file:2;
- GLuint idx:7;
- GLuint dirty:1;
- GLuint last_used:10;
- } xmm[8];
-
- struct {
- struct x86_reg base;
- } file[4];
-
- GLboolean have_sse2;
- GLshort fpucntl;
-};
-
-static INLINE GLboolean eq( struct x86_reg a,
- struct x86_reg b )
-{
- return (a.file == b.file &&
- a.idx == b.idx &&
- a.mod == b.mod &&
- a.disp == b.disp);
-}
-
-static GLint get_offset( const void *a, const void *b )
-{
- return (const char *)b - (const char *)a;
-}
-
-
-static struct x86_reg get_reg_ptr(GLuint file,
- GLuint idx )
-{
- struct x86_reg reg;
-
- switch (file) {
- case FILE_REG:
- reg = x86_make_reg(file_REG32, reg_BX);
- assert(idx != REG_UNDEF);
- break;
- case FILE_STATE_PARAM:
- reg = x86_make_reg(file_REG32, reg_CX);
- break;
- default:
- assert(0);
- }
-
- return x86_make_disp(reg, 16 * idx);
-}
-
-
-static void spill( struct compilation *cp, GLuint idx )
-{
- struct x86_reg oldval = get_reg_ptr(cp->xmm[idx].file,
- cp->xmm[idx].idx);
-
- assert(cp->xmm[idx].dirty);
- sse_movups(&cp->func, oldval, x86_make_reg(file_XMM, idx));
- cp->xmm[idx].dirty = 0;
-}
-
-static struct x86_reg get_xmm_reg( struct compilation *cp )
-{
- GLuint i;
- GLuint oldest = 0;
-
- for (i = 0; i < 8; i++)
- if (cp->xmm[i].last_used < cp->xmm[oldest].last_used)
- oldest = i;
-
- /* Need to write out the old value?
- */
- if (cp->xmm[oldest].dirty)
- spill(cp, oldest);
-
- assert(cp->xmm[oldest].last_used != cp->insn_counter);
-
- cp->xmm[oldest].file = FILE_REG;
- cp->xmm[oldest].idx = REG_UNDEF;
- cp->xmm[oldest].last_used = cp->insn_counter;
- return x86_make_reg(file_XMM, oldest);
-}
-
-static void invalidate_xmm( struct compilation *cp,
- GLuint file, GLuint idx )
-{
- GLuint i;
-
- /* Invalidate any old copy of this register in XMM0-7.
- */
- for (i = 0; i < 8; i++) {
- if (cp->xmm[i].file == file && cp->xmm[i].idx == idx) {
- cp->xmm[i].file = FILE_REG;
- cp->xmm[i].idx = REG_UNDEF;
- cp->xmm[i].dirty = 0;
- break;
- }
- }
-}
-
-
-/* Return an XMM reg to receive the results of an operation.
- */
-static struct x86_reg get_dst_xmm_reg( struct compilation *cp,
- GLuint file, GLuint idx )
-{
- struct x86_reg reg;
-
- /* Invalidate any old copy of this register in XMM0-7. Don't reuse
- * as this may be one of the arguments.
- */
- invalidate_xmm( cp, file, idx );
-
- reg = get_xmm_reg( cp );
- cp->xmm[reg.idx].file = file;
- cp->xmm[reg.idx].idx = idx;
- cp->xmm[reg.idx].dirty = 1;
- return reg;
-}
-
-/* As above, but return a pointer. Note - this pointer may alias
- * those returned by get_arg_ptr().
- */
-static struct x86_reg get_dst_ptr( struct compilation *cp,
- GLuint file, GLuint idx )
-{
- /* Invalidate any old copy of this register in XMM0-7. Don't reuse
- * as this may be one of the arguments.
- */
- invalidate_xmm( cp, file, idx );
-
- return get_reg_ptr(file, idx);
-}
-
-
-
-/* Return an XMM reg if the argument is resident, otherwise return a
- * base+offset pointer to the saved value.
- */
-static struct x86_reg get_arg( struct compilation *cp, GLuint file, GLuint idx )
-{
- GLuint i;
-
- for (i = 0; i < 8; i++) {
- if (cp->xmm[i].file == file &&
- cp->xmm[i].idx == idx) {
- cp->xmm[i].last_used = cp->insn_counter;
- return x86_make_reg(file_XMM, i);
- }
- }
-
- return get_reg_ptr(file, idx);
-}
-
-/* As above, but always return a pointer:
- */
-static struct x86_reg get_arg_ptr( struct compilation *cp, GLuint file, GLuint idx )
-{
- GLuint i;
-
- /* If there is a modified version of this register in one of the
- * XMM regs, write it out to memory.
- */
- for (i = 0; i < 8; i++) {
- if (cp->xmm[i].file == file &&
- cp->xmm[i].idx == idx &&
- cp->xmm[i].dirty)
- spill(cp, i);
- }
-
- return get_reg_ptr(file, idx);
-}
-
-/* Emulate pshufd insn in regular SSE, if necessary:
- */
-static void emit_pshufd( struct compilation *cp,
- struct x86_reg dst,
- struct x86_reg arg0,
- GLubyte shuf )
-{
- if (cp->have_sse2) {
- sse2_pshufd(&cp->func, dst, arg0, shuf);
- cp->func.fn = 0;
- }
- else {
- if (!eq(dst, arg0))
- sse_movups(&cp->func, dst, arg0);
-
- sse_shufps(&cp->func, dst, dst, shuf);
- }
-}
-
-static void set_fpu_round_neg_inf( struct compilation *cp )
-{
- if (cp->fpucntl != RND_NEG_FPU) {
- struct x86_reg regEDX = x86_make_reg(file_REG32, reg_DX);
- struct arb_vp_machine *m = NULL;
-
- cp->fpucntl = RND_NEG_FPU;
- x87_fnclex(&cp->func);
- x87_fldcw(&cp->func, x86_make_disp(regEDX, get_offset(m, &m->fpucntl_rnd_neg)));
- }
-}
-
-
-/* Perform a reduced swizzle.
- */
-static GLboolean emit_RSW( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.rsw.file0, op.rsw.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.rsw.dst);
- GLuint swz = GET_SWZ(op.rsw.swz, 0) | (GET_SWZ(op.rsw.swz, 1) << 2) |
- (GET_SWZ(op.rsw.swz, 2) << 4| (GET_SWZ(op.rsw.swz, 3) << 6));
- GLuint neg = op.rsw.neg;
-
- emit_pshufd(cp, dst, arg0, swz);
-
- if (neg) {
- struct x86_reg negs = get_arg(cp, FILE_REG, REG_SWZ);
- struct x86_reg tmp = get_xmm_reg(cp);
- /* Load 1,-1,0,0
- * Use neg as arg to pshufd
- * Multiply
- */
- /* is the emit_pshufd necessary? only SWZ can negate individual components */
- emit_pshufd(cp, tmp, negs,
- SHUF((neg & 1) ? 1 : 0,
- (neg & 2) ? 1 : 0,
- (neg & 4) ? 1 : 0,
- (neg & 8) ? 1 : 0));
- sse_mulps(&cp->func, dst, tmp);
- }
-
- return GL_TRUE;
-}
-
-/* Perform a full swizzle
- */
-static GLboolean emit_SWZ( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.rsw.file0, op.rsw.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.rsw.dst);
- struct x86_reg negs = get_arg(cp, FILE_REG, REG_SWZ);
- struct x86_reg tmp = get_xmm_reg(cp);
- GLubyte neg = op.rsw.neg;
- GLubyte shuf2, swz, savepos, savemask, swizzle[4];
-
- swizzle[0] = GET_SWZ(op.rsw.swz, 0);
- swizzle[1] = GET_SWZ(op.rsw.swz, 1);
- swizzle[2] = GET_SWZ(op.rsw.swz, 2);
- swizzle[3] = GET_SWZ(op.rsw.swz, 3);
-
- swz = SHUF((swizzle[0] & 3), (swizzle[1] & 3),
- (swizzle[2] & 3), (swizzle[3] & 3));
-
- emit_pshufd(cp, dst, arg0, swz);
-
- /* can handle negation and replace with zero with the same shuffle/mul */
- shuf2 = SHUF(swizzle[0] == 4 ? 2 : (neg & 1),
- swizzle[1] == 4 ? 2 : ((neg & 2) >> 1),
- swizzle[2] == 4 ? 2 : ((neg & 4) >> 2),
- swizzle[3] == 4 ? 2 : ((neg & 8) >> 3));
-
- /* now the hard part is getting those 1's in there... */
- savepos = 0;
- savemask = 0;
- if (swizzle[0] == 5) savepos = 1;
- if (swizzle[1] == 5) savepos = 2;
- else savemask |= 1 << 2;
- if (swizzle[2] == 5) savepos = 3;
- else savemask |= 2 << 4;
- if (swizzle[3] == 5) savepos = 4;
- else savemask |= 3 << 6;
- if (savepos) {
- /* need a mov first as movss from memory will overwrite high bits of xmm reg */
- sse_movups(&cp->func, tmp, negs);
- /* can only replace lowest 32bits, thus move away that part first */
- emit_pshufd(cp, dst, dst, savemask);
- sse_movss(&cp->func, dst, tmp);
- emit_pshufd(cp, dst, dst, (savepos - 1) | (savemask & 0xfc));
- }
-
- if (shuf2) {
- /* Load 1,-1,0,0
- * Use neg as arg to pshufd
- * Multiply
- */
- emit_pshufd(cp, tmp, negs, shuf2);
- sse_mulps(&cp->func, dst, tmp);
- }
-
- return GL_TRUE;
-}
-
-/* Helper for writemask:
- */
-static GLboolean emit_shuf_copy1( struct compilation *cp,
- struct x86_reg dst,
- struct x86_reg arg0,
- struct x86_reg arg1,
- GLubyte shuf )
-{
- struct x86_reg tmp = get_xmm_reg(cp);
- sse_movups(&cp->func, dst, arg1);
- emit_pshufd(cp, dst, dst, shuf);
- emit_pshufd(cp, tmp, arg0, shuf);
-
- sse_movss(&cp->func, dst, tmp);
-
- emit_pshufd(cp, dst, dst, shuf);
- return GL_TRUE;
-}
-
-
-/* Helper for writemask:
- */
-static GLboolean emit_shuf_copy2( struct compilation *cp,
- struct x86_reg dst,
- struct x86_reg arg0,
- struct x86_reg arg1,
- GLubyte shuf )
-{
- struct x86_reg tmp = get_xmm_reg(cp);
- emit_pshufd(cp, dst, arg1, shuf);
- emit_pshufd(cp, tmp, arg0, shuf);
-
- sse_shufps(&cp->func, dst, tmp, SHUF(X, Y, Z, W));
-
- emit_pshufd(cp, dst, dst, shuf);
- return GL_TRUE;
-}
-
-
-static void emit_x87_ex2( struct compilation *cp )
-{
- struct x86_reg st0 = x86_make_reg(file_x87, 0);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- struct x86_reg st3 = x86_make_reg(file_x87, 3);
-
- set_fpu_round_neg_inf( cp );
-
- x87_fld(&cp->func, st0); /* a a */
- x87_fprndint( &cp->func ); /* int(a) a */
- x87_fld(&cp->func, st0); /* int(a) int(a) a */
- x87_fstp(&cp->func, st3); /* int(a) a int(a)*/
- x87_fsubp(&cp->func, st1); /* frac(a) int(a) */
- x87_f2xm1(&cp->func); /* (2^frac(a))-1 int(a)*/
- x87_fld1(&cp->func); /* 1 (2^frac(a))-1 int(a)*/
- x87_faddp(&cp->func, st1); /* 2^frac(a) int(a) */
- x87_fscale(&cp->func); /* 2^a */
-}
-
-#if 0
-static GLboolean emit_MSK2( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.msk.file, op.msk.arg);
- struct x86_reg arg1 = get_arg(cp, FILE_REG, op.msk.dst); /* NOTE! */
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.msk.dst);
-
- /* make full width bitmask in tmp
- * dst = ~tmp
- * tmp &= arg0
- * dst &= arg1
- * dst |= tmp
- */
- emit_pshufd(cp, tmp, get_arg(cp, FILE_REG, REG_NEGS),
- SHUF((op.msk.mask & 1) ? 2 : 0,
- (op.msk.mask & 2) ? 2 : 0,
- (op.msk.mask & 4) ? 2 : 0,
- (op.msk.mask & 8) ? 2 : 0));
- sse2_pnot(&cp->func, dst, tmp);
- sse2_pand(&cp->func, arg0, tmp);
- sse2_pand(&cp->func, arg1, dst);
- sse2_por(&cp->func, tmp, dst);
- return GL_TRUE;
-}
-#endif
-
-
-/* Used to implement write masking. This and most of the other instructions
- * here would be easier to implement if there had been a translation
- * to a 2 argument format (dst/arg0, arg1) at the shader level before
- * attempting to translate to x86/sse code.
- */
-static GLboolean emit_MSK( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg = get_arg(cp, op.msk.file, op.msk.idx);
- struct x86_reg dst0 = get_arg(cp, FILE_REG, op.msk.dst); /* NOTE! */
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.msk.dst);
-
- /* Note that dst and dst0 refer to the same program variable, but
- * will definitely be different XMM registers. We're effectively
- * treating this as a 2 argument SEL now, just one of which happens
- * always to be the same register as the destination.
- */
-
- switch (op.msk.mask) {
- case 0:
- sse_movups(&cp->func, dst, dst0);
- return GL_TRUE;
-
- case WRITEMASK_X:
- if (arg.file == file_XMM) {
- sse_movups(&cp->func, dst, dst0);
- sse_movss(&cp->func, dst, arg);
- }
- else {
- struct x86_reg tmp = get_xmm_reg(cp);
- sse_movups(&cp->func, dst, dst0);
- sse_movss(&cp->func, tmp, arg);
- sse_movss(&cp->func, dst, tmp);
- }
- return GL_TRUE;
-
- case WRITEMASK_XY:
- sse_movups(&cp->func, dst, dst0);
- sse_shufps(&cp->func, dst, arg, SHUF(X, Y, Z, W));
- return GL_TRUE;
-
- case WRITEMASK_ZW:
- sse_movups(&cp->func, dst, arg);
- sse_shufps(&cp->func, dst, dst0, SHUF(X, Y, Z, W));
- return GL_TRUE;
-
- case WRITEMASK_YZW:
- if (dst0.file == file_XMM) {
- sse_movups(&cp->func, dst, arg);
- sse_movss(&cp->func, dst, dst0);
- }
- else {
- struct x86_reg tmp = get_xmm_reg(cp);
- sse_movups(&cp->func, dst, arg);
- sse_movss(&cp->func, tmp, dst0);
- sse_movss(&cp->func, dst, tmp);
- }
- return GL_TRUE;
-
- case WRITEMASK_Y:
- emit_shuf_copy1(cp, dst, arg, dst0, SHUF(Y,X,Z,W));
- return GL_TRUE;
-
- case WRITEMASK_Z:
- emit_shuf_copy1(cp, dst, arg, dst0, SHUF(Z,Y,X,W));
- return GL_TRUE;
-
- case WRITEMASK_W:
- emit_shuf_copy1(cp, dst, arg, dst0, SHUF(W,Y,Z,X));
- return GL_TRUE;
-
- case WRITEMASK_XZ:
- emit_shuf_copy2(cp, dst, arg, dst0, SHUF(X,Z,Y,W));
- return GL_TRUE;
-
- case WRITEMASK_XW:
- emit_shuf_copy2(cp, dst, arg, dst0, SHUF(X,W,Z,Y));
-
- case WRITEMASK_YZ:
- emit_shuf_copy2(cp, dst, arg, dst0, SHUF(Z,Y,X,W));
- return GL_TRUE;
-
- case WRITEMASK_YW:
- emit_shuf_copy2(cp, dst, arg, dst0, SHUF(W,Y,Z,X));
- return GL_TRUE;
-
- case WRITEMASK_XZW:
- emit_shuf_copy1(cp, dst, dst0, arg, SHUF(Y,X,Z,W));
- return GL_TRUE;
-
- case WRITEMASK_XYW:
- emit_shuf_copy1(cp, dst, dst0, arg, SHUF(Z,Y,X,W));
- return GL_TRUE;
-
- case WRITEMASK_XYZ:
- emit_shuf_copy1(cp, dst, dst0, arg, SHUF(W,Y,Z,X));
- return GL_TRUE;
-
- case WRITEMASK_XYZW:
- sse_movups(&cp->func, dst, arg);
- return GL_TRUE;
-
- default:
- assert(0);
- break;
- }
-}
-
-
-
-static GLboolean emit_PRT( struct compilation *cp, union instruction op )
-{
- FAIL;
-}
-
-
-/**
- * The traditional instructions. All operate on internal registers
- * and ignore write masks and swizzling issues.
- */
-
-static GLboolean emit_ABS( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg neg = get_reg_ptr(FILE_REG, REG_NEG);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, neg);
- sse_maxps(&cp->func, dst, arg0);
- return GL_TRUE;
-}
-
-static GLboolean emit_ADD( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_addps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-
-/* The dotproduct instructions don't really do that well in sse:
- */
-static GLboolean emit_DP3( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp = get_xmm_reg(cp);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, arg1);
-
- /* Now the hard bit: sum the first 3 values:
- */
- sse_movhlps(&cp->func, tmp, dst);
- sse_addss(&cp->func, dst, tmp); /* a*x+c*z, b*y, ?, ? */
- emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
- sse_addss(&cp->func, dst, tmp);
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-
-
-static GLboolean emit_DP4( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp = get_xmm_reg(cp);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, arg1);
-
- /* Now the hard bit: sum the values:
- */
- sse_movhlps(&cp->func, tmp, dst);
- sse_addps(&cp->func, dst, tmp); /* a*x+c*z, b*y+d*w, a*x+c*z, b*y+d*w */
- emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
- sse_addss(&cp->func, dst, tmp);
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-static GLboolean emit_DPH( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp = get_xmm_reg(cp);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, arg1);
-
- /* Now the hard bit: sum the values (from DP3):
- */
- sse_movhlps(&cp->func, tmp, dst);
- sse_addss(&cp->func, dst, tmp); /* a*x+c*z, b*y, ?, ? */
- emit_pshufd(cp, tmp, dst, SHUF(Y,X,W,Z));
- sse_addss(&cp->func, dst, tmp);
- emit_pshufd(cp, tmp, arg1, SHUF(W,W,W,W));
- sse_addss(&cp->func, dst, tmp);
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-#if 0
-static GLboolean emit_DST( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg_ptr(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
-
-/* dst[0] = 1.0 * 1.0F; */
-/* dst[1] = arg0[1] * arg1[1]; */
-/* dst[2] = arg0[2] * 1.0; */
-/* dst[3] = 1.0 * arg1[3]; */
-
- /* Would rather do some of this with integer regs, but:
- * 1) No proper support for immediate values yet
- * 2) I'd need to push/pop somewhere to get a free reg.
- */
- x87_fld1(&cp->func);
- x87_fstp(&cp->func, dst); /* would rather do an immediate store... */
- x87_fld(&cp->func, x86_make_disp(arg0, 4));
- x87_fmul(&cp->func, x86_make_disp(arg1, 4));
- x87_fstp(&cp->func, x86_make_disp(dst, 4));
-
- if (!eq(arg0, dst)) {
- x86_fld(&cp->func, x86_make_disp(arg0, 8));
- x86_stp(&cp->func, x86_make_disp(dst, 8));
- }
-
- if (!eq(arg1, dst)) {
- x86_fld(&cp->func, x86_make_disp(arg0, 12));
- x86_stp(&cp->func, x86_make_disp(dst, 12));
- }
-
- return GL_TRUE;
-}
-#else
-static GLboolean emit_DST( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp = get_xmm_reg(cp);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
-
- emit_shuf_copy2(cp, dst, arg0, ones, SHUF(X,W,Z,Y));
- emit_shuf_copy2(cp, tmp, arg1, ones, SHUF(X,Z,Y,W));
- sse_mulps(&cp->func, dst, tmp);
-
-/* dst[0] = 1.0 * 1.0F; */
-/* dst[1] = arg0[1] * arg1[1]; */
-/* dst[2] = arg0[2] * 1.0; */
-/* dst[3] = 1.0 * arg1[3]; */
-
- return GL_TRUE;
-}
-#endif
-
-static GLboolean emit_LG2( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
-
- x87_fld1(&cp->func); /* 1 */
- x87_fld(&cp->func, arg0); /* a0 1 */
- x87_fyl2x(&cp->func); /* log2(a0) */
- x87_fst(&cp->func, x86_make_disp(dst, 0));
- x87_fst(&cp->func, x86_make_disp(dst, 4));
- x87_fst(&cp->func, x86_make_disp(dst, 8));
- x87_fstp(&cp->func, x86_make_disp(dst, 12));
-
- return GL_TRUE;
-}
-
-
-static GLboolean emit_EX2( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
-
- /* CAUTION: dst may alias arg0!
- */
- x87_fld(&cp->func, arg0);
-
- emit_x87_ex2(cp);
-
- x87_fst(&cp->func, x86_make_disp(dst, 0));
- x87_fst(&cp->func, x86_make_disp(dst, 4));
- x87_fst(&cp->func, x86_make_disp(dst, 8));
- x87_fst(&cp->func, x86_make_disp(dst, 12));
- return GL_TRUE;
-}
-
-static GLboolean emit_EXP( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- struct x86_reg st0 = x86_make_reg(file_x87, 0);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- struct x86_reg st3 = x86_make_reg(file_x87, 3);
-
- /* CAUTION: dst may alias arg0!
- */
- x87_fld(&cp->func, arg0); /* arg0.x */
- x87_fld(&cp->func, st0); /* arg arg */
-
- /* by default, fpu is setup to round-to-nearest. We want to
- * change this now, and track the state through to the end of the
- * generated function so that it isn't repeated unnecessarily.
- * Alternately, could subtract .5 to get round to -inf behaviour.
- */
- set_fpu_round_neg_inf( cp );
- x87_fprndint( &cp->func ); /* flr(a) a */
- x87_fld(&cp->func, st0); /* flr(a) flr(a) a */
- x87_fld1(&cp->func); /* 1 floor(a) floor(a) a */
- x87_fst(&cp->func, x86_make_disp(dst, 12)); /* stack unchanged */
- x87_fscale(&cp->func); /* 2^floor(a) floor(a) a */
- x87_fst(&cp->func, st3); /* 2^floor(a) floor(a) a 2^floor(a)*/
- x87_fstp(&cp->func, x86_make_disp(dst, 0)); /* flr(a) a 2^flr(a) */
- x87_fsubrp(&cp->func, st1); /* frac(a) 2^flr(a) */
- x87_fst(&cp->func, x86_make_disp(dst, 4)); /* frac(a) 2^flr(a) */
- x87_f2xm1(&cp->func); /* (2^frac(a))-1 2^flr(a)*/
- x87_fld1(&cp->func); /* 1 (2^frac(a))-1 2^flr(a)*/
- x87_faddp(&cp->func, st1); /* 2^frac(a) 2^flr(a) */
- x87_fmulp(&cp->func, st1); /* 2^a */
- x87_fst(&cp->func, x86_make_disp(dst, 8));
-
-
-
-/* dst[0] = 2^floor(tmp); */
-/* dst[1] = frac(tmp); */
-/* dst[2] = 2^floor(tmp) * 2^frac(tmp); */
-/* dst[3] = 1.0F; */
- return GL_TRUE;
-}
-
-static GLboolean emit_LOG( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- struct x86_reg st0 = x86_make_reg(file_x87, 0);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- struct x86_reg st2 = x86_make_reg(file_x87, 2);
-
- /* CAUTION: dst may alias arg0!
- */
- x87_fld(&cp->func, arg0); /* arg0.x */
- x87_fabs(&cp->func); /* |arg0.x| */
- x87_fxtract(&cp->func); /* mantissa(arg0.x), exponent(arg0.x) */
- x87_fst(&cp->func, st2); /* mantissa, exponent, mantissa */
- x87_fld1(&cp->func); /* 1, mantissa, exponent, mantissa */
- x87_fyl2x(&cp->func); /* log2(mantissa), exponent, mantissa */
- x87_fadd(&cp->func, st0, st1); /* e+l2(m), e, m */
- x87_fstp(&cp->func, x86_make_disp(dst, 8)); /* e, m */
-
- x87_fld1(&cp->func); /* 1, e, m */
- x87_fsub(&cp->func, st1, st0); /* 1, e-1, m */
- x87_fstp(&cp->func, x86_make_disp(dst, 12)); /* e-1,m */
- x87_fstp(&cp->func, dst); /* m */
-
- x87_fadd(&cp->func, st0, st0); /* 2m */
- x87_fstp(&cp->func, x86_make_disp(dst, 4));
-
- return GL_TRUE;
-}
-
-static GLboolean emit_FLR( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- int i;
-
- set_fpu_round_neg_inf( cp );
-
- for (i = 0; i < 4; i++) {
- x87_fld(&cp->func, x86_make_disp(arg0, i*4));
- x87_fprndint( &cp->func );
- x87_fstp(&cp->func, x86_make_disp(dst, i*4));
- }
-
-
- return GL_TRUE;
-}
-
-static GLboolean emit_FRC( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- struct x86_reg st0 = x86_make_reg(file_x87, 0);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- int i;
-
- set_fpu_round_neg_inf( cp );
-
- /* Knowing liveness info or even just writemask would be useful
- * here:
- */
- for (i = 0; i < 4; i++) {
- x87_fld(&cp->func, x86_make_disp(arg0, i*4));
- x87_fld(&cp->func, st0); /* a a */
- x87_fprndint( &cp->func ); /* flr(a) a */
- x87_fsubrp(&cp->func, st1); /* frc(a) */
- x87_fstp(&cp->func, x86_make_disp(dst, i*4));
- }
-
- return GL_TRUE;
-}
-
-
-
-static GLboolean emit_LIT( struct compilation *cp, union instruction op )
-{
-#if 1
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
- struct x86_reg lit = get_arg(cp, FILE_REG, REG_LIT);
- struct x86_reg tmp = get_xmm_reg(cp);
- struct x86_reg st1 = x86_make_reg(file_x87, 1);
- struct x86_reg regEAX = x86_make_reg(file_REG32, reg_AX);
- GLubyte *fixup1, *fixup2;
-
-
- /* Load the interesting parts of arg0:
- */
- x87_fld(&cp->func, x86_make_disp(arg0, 12)); /* a3 */
- x87_fld(&cp->func, x86_make_disp(arg0, 4)); /* a1 a3 */
- x87_fld(&cp->func, x86_make_disp(arg0, 0)); /* a0 a1 a3 */
-
- /* Intialize dst:
- */
- sse_movaps(&cp->func, tmp, lit);
- sse_movaps(&cp->func, dst, tmp);
-
- /* Check arg0[0]:
- */
- x87_fldz(&cp->func); /* 0 a0 a1 a3 */
- x87_fucomp(&cp->func, st1); /* a0 a1 a3 */
- x87_fnstsw(&cp->func, regEAX);
- x86_sahf(&cp->func);
- fixup1 = x86_jcc_forward(&cp->func, cc_AE);
-
- x87_fstp(&cp->func, x86_make_disp(dst, 4)); /* a1 a3 */
-
- /* Check arg0[1]:
- */
- x87_fldz(&cp->func); /* 0 a1 a3 */
- x87_fucomp(&cp->func, st1); /* a1 a3 */
- x87_fnstsw(&cp->func, regEAX);
- x86_sahf(&cp->func);
- fixup2 = x86_jcc_forward(&cp->func, cc_AE);
-
- /* Compute pow(a1, a3)
- */
- x87_fyl2x(&cp->func); /* a3*log2(a1) */
-
- emit_x87_ex2( cp ); /* 2^(a3*log2(a1)) */
-
- x87_fstp(&cp->func, x86_make_disp(dst, 8));
-
- /* Land jumps:
- */
- x86_fixup_fwd_jump(&cp->func, fixup1);
- x86_fixup_fwd_jump(&cp->func, fixup2);
-#else
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_LIT);
- sse_movups(&cp->func, dst, ones);
-#endif
- return GL_TRUE;
-}
-
-
-
-static GLboolean emit_MAX( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_maxps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-
-static GLboolean emit_MIN( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_minps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-static GLboolean emit_MOV( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- return GL_TRUE;
-}
-
-static GLboolean emit_MUL( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_mulps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-
-static GLboolean emit_POW( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg_ptr(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg_ptr(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_ptr(cp, FILE_REG, op.alu.dst);
-
- x87_fld(&cp->func, arg1); /* a1 */
- x87_fld(&cp->func, arg0); /* a0 a1 */
- x87_fyl2x(&cp->func); /* a1*log2(a0) */
-
- emit_x87_ex2( cp ); /* 2^(a1*log2(a0)) */
-
- x87_fst(&cp->func, x86_make_disp(dst, 0));
- x87_fst(&cp->func, x86_make_disp(dst, 4));
- x87_fst(&cp->func, x86_make_disp(dst, 8));
- x87_fstp(&cp->func, x86_make_disp(dst, 12));
-
- return GL_TRUE;
-}
-
-static GLboolean emit_REL( struct compilation *cp, union instruction op )
-{
-/* GLuint idx = (op.alu.idx0 + (GLint)cp->File[0][REG_ADDR][0]) & (MAX_NV_VERTEX_PROGRAM_PARAMS-1); */
-/* GLuint idx = 0; */
-/* struct x86_reg arg0 = get_arg(cp, op.alu.file0, idx); */
-/* struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst); */
-
-/* dst[0] = arg0[0]; */
-/* dst[1] = arg0[1]; */
-/* dst[2] = arg0[2]; */
-/* dst[3] = arg0[3]; */
-
- FAIL;
-}
-
-static GLboolean emit_RCP( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- if (cp->have_sse2) {
- sse2_rcpss(&cp->func, dst, arg0);
- }
- else {
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
- sse_movss(&cp->func, dst, ones);
- sse_divss(&cp->func, dst, arg0);
- }
-
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-static GLboolean emit_RSQ( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-#if 0
- struct x86_reg neg = get_reg_ptr(FILE_REG, REG_NEG);
-
-/* get abs value first. This STILL doesn't work.
- Looks like we get bogus neg values ?
-*/
- sse_movss(&cp->func, dst, arg0);
- sse_mulss(&cp->func, dst, neg);
- sse_maxss(&cp->func, dst, arg0);
-
- sse_rsqrtss(&cp->func, dst, dst);
-#endif
- sse_rsqrtss(&cp->func, dst, arg0);
- sse_shufps(&cp->func, dst, dst, SHUF(X, X, X, X));
- return GL_TRUE;
-}
-
-
-static GLboolean emit_SGE( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
-
- sse_movups(&cp->func, dst, arg0);
- sse_cmpps(&cp->func, dst, arg1, cc_NotLessThan);
- sse_andps(&cp->func, dst, ones);
- return GL_TRUE;
-}
-
-
-static GLboolean emit_SLT( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg ones = get_reg_ptr(FILE_REG, REG_ONES);
-
- sse_movups(&cp->func, dst, arg0);
- sse_cmpps(&cp->func, dst, arg1, cc_LessThan);
- sse_andps(&cp->func, dst, ones);
- return GL_TRUE;
-}
-
-static GLboolean emit_SUB( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
-
- sse_movups(&cp->func, dst, arg0);
- sse_subps(&cp->func, dst, arg1);
- return GL_TRUE;
-}
-
-
-static GLboolean emit_XPD( struct compilation *cp, union instruction op )
-{
- struct x86_reg arg0 = get_arg(cp, op.alu.file0, op.alu.idx0);
- struct x86_reg arg1 = get_arg(cp, op.alu.file1, op.alu.idx1);
- struct x86_reg dst = get_dst_xmm_reg(cp, FILE_REG, op.alu.dst);
- struct x86_reg tmp0 = get_xmm_reg(cp);
- struct x86_reg tmp1 = get_xmm_reg(cp);
-
- /* Could avoid tmp0, tmp1 if we overwrote arg0, arg1. Need a way
- * to invalidate registers. This will come with better analysis
- * (liveness analysis) of the incoming program.
- */
- emit_pshufd(cp, dst, arg0, SHUF(Y, Z, X, W));
- emit_pshufd(cp, tmp1, arg1, SHUF(Z, X, Y, W));
- sse_mulps(&cp->func, dst, tmp1);
- emit_pshufd(cp, tmp0, arg0, SHUF(Z, X, Y, W));
- emit_pshufd(cp, tmp1, arg1, SHUF(Y, Z, X, W));
- sse_mulps(&cp->func, tmp0, tmp1);
- sse_subps(&cp->func, dst, tmp0);
-
-/* dst[0] = arg0[1] * arg1[2] - arg0[2] * arg1[1]; */
-/* dst[1] = arg0[2] * arg1[0] - arg0[0] * arg1[2]; */
-/* dst[2] = arg0[0] * arg1[1] - arg0[1] * arg1[0]; */
-/* dst[3] is undef */
-
- return GL_TRUE;
-}
-
-static GLboolean emit_NOP( struct compilation *cp, union instruction op )
-{
- return GL_TRUE;
-}
-
-
-static GLboolean (* const emit_func[])(struct compilation *, union instruction) =
-{
- emit_ABS,
- emit_ADD,
- emit_NOP, /* ARA */
- emit_NOP, /* ARL */
- emit_NOP, /* ARL_NV */
- emit_NOP, /* ARR */
- emit_NOP, /* BRA */
- emit_NOP, /* CAL */
- emit_NOP, /* CMP */
- emit_NOP, /* COS */
- emit_NOP, /* DDX */
- emit_NOP, /* DDY */
- emit_DP3,
- emit_DP4,
- emit_DPH,
- emit_DST,
- emit_NOP, /* END */
- emit_EX2,
- emit_EXP,
- emit_FLR,
- emit_FRC,
- emit_NOP, /* KIL */
- emit_NOP, /* KIL_NV */
- emit_LG2,
- emit_LIT,
- emit_LOG,
- emit_NOP, /* LRP */
- emit_NOP, /* MAD */
- emit_MAX,
- emit_MIN,
- emit_MOV,
- emit_MUL,
- emit_NOP, /* PK2H */
- emit_NOP, /* PK2US */
- emit_NOP, /* PK4B */
- emit_NOP, /* PK4UB */
- emit_POW,
- emit_NOP, /* POPA */
- emit_PRT,
- emit_NOP, /* PUSHA */
- emit_NOP, /* RCC */
- emit_RCP,
- emit_NOP, /* RET */
- emit_NOP, /* RFL */
- emit_RSQ,
- emit_NOP, /* SCS */
- emit_NOP, /* SEQ */
- emit_NOP, /* SFL */
- emit_SGE,
- emit_NOP, /* SGT */
- emit_NOP, /* SIN */
- emit_NOP, /* SLE */
- emit_SLT,
- emit_NOP, /* SNE */
- emit_NOP, /* SSG */
- emit_NOP, /* STR */
- emit_SUB,
- emit_SWZ, /* SWZ */
- emit_NOP, /* TEX */
- emit_NOP, /* TXB */
- emit_NOP, /* TXD */
- emit_NOP, /* TXL */
- emit_NOP, /* TXP */
- emit_NOP, /* TXP_NV */
- emit_NOP, /* UP2H */
- emit_NOP, /* UP2US */
- emit_NOP, /* UP4B */
- emit_NOP, /* UP4UB */
- emit_NOP, /* X2D */
- emit_XPD,
- emit_RSW,
- emit_MSK,
- emit_REL,
-};
-
-
-
-static GLboolean build_vertex_program( struct compilation *cp )
-{
- struct arb_vp_machine *m = NULL;
- GLuint j;
-
- struct x86_reg regEBX = x86_make_reg(file_REG32, reg_BX);
- struct x86_reg regECX = x86_make_reg(file_REG32, reg_CX);
- struct x86_reg regEDX = x86_make_reg(file_REG32, reg_DX);
-
- x86_push(&cp->func, regEBX);
-
- x86_mov(&cp->func, regEDX, x86_fn_arg(&cp->func, 1));
- x86_mov(&cp->func, regEBX, x86_make_disp(regEDX, get_offset(m, m->File + FILE_REG)));
- x86_mov(&cp->func, regECX, x86_make_disp(regEDX, get_offset(m, m->File + FILE_STATE_PARAM)));
-
- for (j = 0; j < cp->p->nr_instructions; j++) {
- union instruction inst = cp->p->instructions[j];
- cp->insn_counter = j+1; /* avoid zero */
-
- if (DISASSEM) {
- _mesa_printf("%p: ", cp->func.csr);
- _tnl_disassem_vba_insn( inst );
- }
- cp->func.fn = NULL;
-
- if (!emit_func[inst.alu.opcode]( cp, inst )) {
- return GL_FALSE;
- }
- }
-
- /* TODO: only for outputs:
- */
- for (j = 0; j < 8; j++) {
- if (cp->xmm[j].dirty)
- spill(cp, j);
- }
-
-
- /* Exit mmx state?
- */
- if (cp->func.need_emms)
- mmx_emms(&cp->func);
-
- /* Restore FPU control word?
- */
- if (cp->fpucntl != RESTORE_FPU) {
- x87_fnclex(&cp->func);
- x87_fldcw(&cp->func, x86_make_disp(regEDX, get_offset(m, &m->fpucntl_restore)));
- }
-
- x86_pop(&cp->func, regEBX);
- x86_ret(&cp->func);
-
- return GL_TRUE;
-}
-
-/**
- * Execute the given vertex program.
- *
- * TODO: Integrate the t_vertex.c code here, to build machine vertices
- * directly at this point.
- *
- * TODO: Eliminate the VB struct entirely and just use
- * struct arb_vertex_machine.
- */
-GLboolean
-_tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p)
-{
- struct compilation cp;
-
- /* sanity checks */
- assert(emit_func[OPCODE_ABS] == emit_ABS);
- assert(emit_func[OPCODE_MUL] == emit_MUL);
- assert(emit_func[OPCODE_XPD] == emit_XPD);
-
- _mesa_memset(&cp, 0, sizeof(cp));
- cp.p = p;
- cp.have_sse2 = 1;
-
- if (p->compiled_func) {
- _mesa_free((void *)p->compiled_func);
- p->compiled_func = NULL;
- }
-
- x86_init_func(&cp.func);
-
- cp.fpucntl = RESTORE_FPU;
-
-
- /* Note ctx state is not referenced in building the function, so it
- * depends only on the list of instructions:
- */
- if (!build_vertex_program(&cp)) {
- x86_release_func( &cp.func );
- return GL_FALSE;
- }
-
-
- p->compiled_func = (void (*)(struct arb_vp_machine *))x86_get_func( &cp.func );
- return GL_TRUE;
-}
-
-
-
-#else
-
-GLboolean
-_tnl_sse_codegen_vertex_program(struct tnl_compiled_program *p)
-{
- /* Dummy version for when USE_SSE_ASM not defined */
- return GL_FALSE;
-}
-
-#endif
diff --git a/src/mesa/tnl/t_vb_fog.c b/src/mesa/tnl/t_vb_fog.c
index 5440ff7894..f6518500d8 100644
--- a/src/mesa/tnl/t_vb_fog.c
+++ b/src/mesa/tnl/t_vb_fog.c
@@ -114,7 +114,7 @@ compute_fog_blend_factors(GLcontext *ctx, GLvector4f *out, const GLvector4f *in)
else
d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
- const GLfloat z = FABSF(*v);
+ const GLfloat z = *v;
GLfloat f = (end - z) * d;
data[i][0] = CLAMP(f, 0.0F, 1.0F);
}
@@ -122,14 +122,14 @@ compute_fog_blend_factors(GLcontext *ctx, GLvector4f *out, const GLvector4f *in)
case GL_EXP:
d = ctx->Fog.Density;
for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) {
- const GLfloat z = FABSF(*v);
+ const GLfloat z = *v;
NEG_EXP( data[i][0], d * z );
}
break;
case GL_EXP2:
d = ctx->Fog.Density*ctx->Fog.Density;
for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
- const GLfloat z = FABSF(*v);
+ const GLfloat z = *v;
NEG_EXP( data[i][0], d * z * z );
}
break;
@@ -153,6 +153,8 @@ run_fog_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) {
+ GLuint i;
+ GLfloat *coord;
/* Fog is computed from vertex or fragment Z values */
/* source = VB->ObjPtr or VB->EyePtr coords */
/* dest = VB->AttribPtr[_TNL_ATTRIB_FOG] = fog stage private storage */
@@ -168,6 +170,8 @@ run_fog_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
input = &store->fogcoord;
/* NOTE: negate plane here so we get positive fog coords! */
+ /* NOTE2: this doesn't always work (tests/fog - all frag depth fog
+ coords will be negative). */
plane[0] = -m[2];
plane[1] = -m[6];
plane[2] = -m[10];
@@ -180,18 +184,29 @@ run_fog_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
VB->ObjPtr, plane );
input->count = VB->ObjPtr->count;
+
+ /* make sure coords are really positive
+ NOTE should avoid going through array twice */
+ coord = input->start;
+ for (i = 0; i < input->count; i++) {
+ input->data[i][0] = FABSF(*coord);
+ STRIDE_F(coord, input->stride);
+ }
}
else {
/* fog coordinates = eye Z coordinates (use ABS later) */
- input = &store->input;
+ input = &store->fogcoord;
if (VB->EyePtr->size < 2)
_mesa_vector4f_clean_elem( VB->EyePtr, VB->Count, 2 );
- input->data = (GLfloat (*)[4]) &(VB->EyePtr->data[0][2]);
- input->start = VB->EyePtr->start+2;
- input->stride = VB->EyePtr->stride;
+ input->stride = 4 * sizeof(GLfloat);
input->count = VB->EyePtr->count;
+ coord = VB->EyePtr->start;
+ for (i = 0 ; i < VB->EyePtr->count; i++) {
+ input->data[i][0] = FABSF(coord[2]);
+ STRIDE_F(coord, VB->EyePtr->stride);
+ }
}
}
else {
diff --git a/src/mesa/tnl/t_vb_points.c b/src/mesa/tnl/t_vb_points.c
index 9327f8c273..1ac14fedf9 100644
--- a/src/mesa/tnl/t_vb_points.c
+++ b/src/mesa/tnl/t_vb_points.c
@@ -1,8 +1,8 @@
/*
* Mesa 3-D graphics library
- * Version: 6.5
+ * Version: 7.0
*
- * 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"),
@@ -50,7 +50,8 @@ run_point_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
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;
+ const GLfloat *eyeCoord = (GLfloat *) VB->EyePtr->data + 2;
+ const GLint eyeCoordStride = VB->EyePtr->stride / sizeof(GLfloat);
const GLfloat p0 = ctx->Point.Params[0];
const GLfloat p1 = ctx->Point.Params[1];
const GLfloat p2 = ctx->Point.Params[2];
@@ -59,10 +60,11 @@ run_point_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
GLuint i;
for (i = 0; i < VB->Count; i++) {
- const GLfloat dist = FABSF(eye[i][2]);
+ const GLfloat dist = FABSF(*eyeCoord);
const GLfloat q = p0 + dist * (p1 + dist * p2);
const GLfloat atten = (q != 0.0) ? SQRTF(1.0 / q) : 1.0;
size[i][0] = pointSize * atten; /* clamping done in rasterization */
+ eyeCoord += eyeCoordStride;
}
VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &store->PointSize;
diff --git a/src/mesa/tnl/t_vb_program.c b/src/mesa/tnl/t_vb_program.c
index 0a959a04af..9961af70ce 100644
--- a/src/mesa/tnl/t_vb_program.c
+++ b/src/mesa/tnl/t_vb_program.c
@@ -25,12 +25,13 @@
/**
* \file tnl/t_vb_program.c
- * \brief Pipeline stage for executing NVIDIA vertex programs.
+ * \brief Pipeline stage for executing vertex programs.
* \author Brian Paul, Keith Whitwell
*/
#include "glheader.h"
+#include "colormac.h"
#include "context.h"
#include "macros.h"
#include "imports.h"
@@ -42,6 +43,46 @@
#include "t_context.h"
#include "t_pipeline.h"
+#include "swrast/s_context.h"
+#include "swrast/s_texfilter.h"
+
+/**
+ * XXX the texture sampling code in this module is a bit of a hack.
+ * The texture sampling code is in swrast, though it doesn't have any
+ * real dependencies on the rest of swrast. It should probably be
+ * moved into main/ someday.
+ */
+
+static void
+vp_fetch_texel(GLcontext *ctx, const GLfloat texcoord[4], GLfloat lambda,
+ GLuint unit, GLfloat color[4])
+{
+ GLchan rgba[4];
+ SWcontext *swrast = SWRAST_CONTEXT(ctx);
+
+ /* XXX use a float-valued TextureSample routine here!!! */
+ swrast->TextureSample[unit](ctx, ctx->Texture.Unit[unit]._Current,
+ 1, (const GLfloat (*)[4]) texcoord,
+ &lambda, &rgba);
+ color[0] = CHAN_TO_FLOAT(rgba[0]);
+ color[1] = CHAN_TO_FLOAT(rgba[1]);
+ color[2] = CHAN_TO_FLOAT(rgba[2]);
+ color[3] = CHAN_TO_FLOAT(rgba[3]);
+}
+
+
+/**
+ * Called via ctx->Driver.ProgramStringNotify() after a new vertex program
+ * string has been parsed.
+ */
+void
+_tnl_program_string(GLcontext *ctx, GLenum target, struct gl_program *program)
+{
+ /* No-op.
+ * If we had derived anything from the program that was private to this
+ * stage we'd recompute/validate it here.
+ */
+}
/*!
@@ -70,7 +111,7 @@ init_machine(GLcontext *ctx, struct gl_program_machine *machine)
MEMCPY(machine->VertAttribs, ctx->Current.Attrib,
MAX_VERTEX_PROGRAM_ATTRIBS * 4 * sizeof(GLfloat));
- if (ctx->VertexProgram.Current->IsNVProgram) {
+ 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++) {
@@ -85,6 +126,8 @@ init_machine(GLcontext *ctx, struct gl_program_machine *machine)
}
}
+ machine->NumDeriv = 0;
+
/* init condition codes */
machine->CondCodes[0] = COND_EQ;
machine->CondCodes[1] = COND_EQ;
@@ -93,6 +136,9 @@ init_machine(GLcontext *ctx, struct gl_program_machine *machine)
/* init call stack */
machine->StackDepth = 0;
+
+ machine->FetchTexelLod = vp_fetch_texel;
+ machine->FetchTexelDeriv = NULL; /* not used by vertex programs */
}
@@ -202,19 +248,14 @@ run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
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;
-#else
- if (!program || !program->IsNVProgram)
- return GL_TRUE;
-#endif
- if (ctx->VertexProgram.Current->IsNVProgram) {
+ if (program->IsNVProgram) {
_mesa_load_tracked_matrices(ctx);
}
else {
+ /* ARB program or vertex shader */
_mesa_load_state_parameters(ctx, program->Base.Parameters);
}
@@ -262,17 +303,6 @@ run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
/* execute the program */
_mesa_execute_program(ctx, &program->Base, &machine);
- /* Fixup fog an point size results if needed */
- if (ctx->Fog.Enabled &&
- (program->Base.OutputsWritten & (1 << VERT_RESULT_FOGC)) == 0) {
- machine.Outputs[VERT_RESULT_FOGC][0] = 1.0;
- }
-
- if (ctx->VertexProgram.PointSizeEnabled &&
- (program->Base.OutputsWritten & (1 << VERT_RESULT_PSIZ)) == 0) {
- machine.Outputs[VERT_RESULT_PSIZ][0] = ctx->Point.Size;
- }
-
/* copy the output registers into the VB->attribs arrays */
for (j = 0; j < numOutputs; j++) {
const GLuint attr = outputs[j];
@@ -287,6 +317,23 @@ run_vp( GLcontext *ctx, struct tnl_pipeline_stage *stage )
#endif
}
+ /* Fixup fog and point size results if needed */
+ if (program->IsNVProgram) {
+ if (ctx->Fog.Enabled &&
+ (program->Base.OutputsWritten & (1 << VERT_RESULT_FOGC)) == 0) {
+ for (i = 0; i < VB->Count; i++) {
+ store->results[VERT_RESULT_FOGC].data[i][0] = 1.0;
+ }
+ }
+
+ if (ctx->VertexProgram.PointSizeEnabled &&
+ (program->Base.OutputsWritten & (1 << VERT_RESULT_PSIZ)) == 0) {
+ for (i = 0; i < VB->Count; i++) {
+ store->results[VERT_RESULT_PSIZ].data[i][0] = ctx->Point.Size;
+ }
+ }
+ }
+
/* Setup the VB pointers so that the next pipeline stages get
* their data from the right place (the program output arrays).
*/
@@ -360,8 +407,8 @@ 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.
*/
-static GLboolean init_vp( GLcontext *ctx,
- struct tnl_pipeline_stage *stage )
+static GLboolean
+init_vp(GLcontext *ctx, struct tnl_pipeline_stage *stage)
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &(tnl->vb);
@@ -391,7 +438,8 @@ static GLboolean init_vp( GLcontext *ctx,
/**
* Destructor for this pipeline stage.
*/
-static void dtr( struct tnl_pipeline_stage *stage )
+static void
+dtr(struct tnl_pipeline_stage *stage)
{
struct vp_stage_data *store = VP_STAGE_DATA(stage);
@@ -412,6 +460,16 @@ static void dtr( struct tnl_pipeline_stage *stage )
}
+static void
+validate_vp_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
+{
+ if (ctx->VertexProgram._Current) {
+ _swrast_update_texture_samplers(ctx);
+ }
+}
+
+
+
/**
* Public description of this pipeline stage.
*/
@@ -421,6 +479,6 @@ const struct tnl_pipeline_stage _tnl_vertex_program_stage =
NULL, /* private_data */
init_vp, /* create */
dtr, /* destroy */
- NULL, /* validate */
+ validate_vp_stage, /* validate */
run_vp /* run -- initially set to ctr */
};
diff --git a/src/mesa/tnl/t_vertex.c b/src/mesa/tnl/t_vertex.c
index c666b38742..6aae602037 100644
--- a/src/mesa/tnl/t_vertex.c
+++ b/src/mesa/tnl/t_vertex.c
@@ -229,7 +229,15 @@ void _tnl_get_attr( GLcontext *ctx, const void *vin,
/* Else return the value from ctx->Current.
*/
- _mesa_memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat));
+ if (attr == _TNL_ATTRIB_POINTSIZE) {
+ /* If the hardware vertex doesn't have point size then use size from
+ * GLcontext. XXX this will be wrong if drawing attenuated points!
+ */
+ dest[0] = ctx->Point._Size;
+ }
+ else {
+ _mesa_memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat));
+ }
}
diff --git a/src/mesa/tnl/t_vp_build.c b/src/mesa/tnl/t_vp_build.c
index dff062a417..2a1cae77f2 100644
--- a/src/mesa/tnl/t_vp_build.c
+++ b/src/mesa/tnl/t_vp_build.c
@@ -1103,7 +1103,9 @@ static void build_fog( struct tnl_program *p )
{
struct ureg fog = register_output(p, VERT_RESULT_FOGC);
struct ureg input;
-
+ GLuint useabs = p->state->fog_source_is_depth && p->state->fog_mode &&
+ (p->state->fog_mode != FOG_EXP2);
+
if (p->state->fog_source_is_depth) {
input = swizzle1(get_eye_position(p), Z);
}
@@ -1111,31 +1113,36 @@ static void build_fog( struct tnl_program *p )
input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X);
}
- if (p->state->tnl_do_vertex_fog) {
+ if (p->state->fog_mode && p->state->tnl_do_vertex_fog) {
struct ureg params = register_param2(p, STATE_INTERNAL,
STATE_FOG_PARAMS_OPTIMIZED);
struct ureg tmp = get_temp(p);
+ if (useabs) {
+ emit_op1(p, OPCODE_ABS, tmp, 0, input);
+ }
+
switch (p->state->fog_mode) {
case FOG_LINEAR: {
struct ureg id = get_identity_param(p);
- emit_op3(p, OPCODE_MAD, tmp, 0, input, swizzle1(params,X), swizzle1(params,Y));
+ emit_op3(p, OPCODE_MAD, tmp, 0, useabs ? tmp : input,
+ swizzle1(params,X), swizzle1(params,Y));
emit_op2(p, OPCODE_MAX, tmp, 0, tmp, swizzle1(id,X)); /* saturate */
emit_op2(p, OPCODE_MIN, fog, WRITEMASK_X, tmp, swizzle1(id,W));
break;
}
case FOG_EXP:
- emit_op1(p, OPCODE_ABS, tmp, 0, input);
- emit_op2(p, OPCODE_MUL, tmp, 0, tmp, swizzle1(params,Z));
+ emit_op2(p, OPCODE_MUL, tmp, 0, useabs ? tmp : input,
+ swizzle1(params,Z));
emit_op1(p, OPCODE_EX2, fog, WRITEMASK_X, negate(tmp));
break;
case FOG_EXP2:
emit_op2(p, OPCODE_MUL, tmp, 0, input, swizzle1(params,W));
- emit_op2(p, OPCODE_MUL, tmp, 0, tmp, tmp);
+ emit_op2(p, OPCODE_MUL, tmp, 0, tmp, tmp);
emit_op1(p, OPCODE_EX2, fog, WRITEMASK_X, negate(tmp));
break;
}
-
+
release_temp(p, tmp);
}
else {
@@ -1143,7 +1150,7 @@ static void build_fog( struct tnl_program *p )
*
* KW: Is it really necessary to do anything in this case?
*/
- emit_op1(p, OPCODE_MOV, fog, WRITEMASK_X, input);
+ emit_op1(p, useabs ? OPCODE_ABS : OPCODE_MOV, fog, WRITEMASK_X, input);
}
}