Several fp and vp tweaks:
- Renumber VERT_RESULT_* values so that they match the numbers of the corresponding FRAG_ATTRIB_ values. - Add ctx->VertexProgram._Current and FragmentProgram._Current values which point to either the current client-supplied program if enabled, or otherwise to the current mesa-internal program. Thus this program is always the correct one for the current state, providing that the mesa flags to turn on automatic generation are enabled. - Add callbacks to ctx->Driver.BindProgram() in texenvprogram.c and t_vp_build.c so that the driver knows when the generated program changes. This is cleaner than trying to code all the possible _NEW_* flags into the driver, and more precise as well. - Add a UsesKill flag to identify fragment programs with that instruction, as these can require special treatment. - Move the FRAG_OUTPUT values to mtypes.h, near to similar defn's.
This commit is contained in:
@@ -195,18 +195,18 @@ enum
|
||||
#define VERT_RESULT_HPOS 0
|
||||
#define VERT_RESULT_COL0 1
|
||||
#define VERT_RESULT_COL1 2
|
||||
#define VERT_RESULT_BFC0 3
|
||||
#define VERT_RESULT_BFC1 4
|
||||
#define VERT_RESULT_FOGC 5
|
||||
#define VERT_RESULT_PSIZ 6
|
||||
#define VERT_RESULT_TEX0 7
|
||||
#define VERT_RESULT_TEX1 8
|
||||
#define VERT_RESULT_TEX2 9
|
||||
#define VERT_RESULT_TEX3 10
|
||||
#define VERT_RESULT_TEX4 11
|
||||
#define VERT_RESULT_TEX5 12
|
||||
#define VERT_RESULT_TEX6 13
|
||||
#define VERT_RESULT_TEX7 14
|
||||
#define VERT_RESULT_FOGC 3
|
||||
#define VERT_RESULT_TEX0 4
|
||||
#define VERT_RESULT_TEX1 5
|
||||
#define VERT_RESULT_TEX2 6
|
||||
#define VERT_RESULT_TEX3 7
|
||||
#define VERT_RESULT_TEX4 8
|
||||
#define VERT_RESULT_TEX5 9
|
||||
#define VERT_RESULT_TEX6 10
|
||||
#define VERT_RESULT_TEX7 11
|
||||
#define VERT_RESULT_PSIZ 12
|
||||
#define VERT_RESULT_BFC0 13
|
||||
#define VERT_RESULT_BFC1 14
|
||||
#define VERT_RESULT_MAX 15
|
||||
|
||||
|
||||
@@ -226,7 +226,9 @@ enum
|
||||
FRAG_ATTRIB_TEX4 = 8,
|
||||
FRAG_ATTRIB_TEX5 = 9,
|
||||
FRAG_ATTRIB_TEX6 = 10,
|
||||
FRAG_ATTRIB_TEX7 = 11
|
||||
FRAG_ATTRIB_TEX7 = 11,
|
||||
|
||||
FRAG_ATTRIB_MAX = 12
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -257,6 +259,14 @@ enum
|
||||
/*@}*/
|
||||
|
||||
|
||||
/* Fragment program results
|
||||
*/
|
||||
#define FRAG_OUTPUT_COLR 0
|
||||
#define FRAG_OUTPUT_COLH 1
|
||||
#define FRAG_OUTPUT_DEPR 2
|
||||
#define FRAG_OUTPUT_MAX 3
|
||||
|
||||
|
||||
/**
|
||||
* Indexes for all renderbuffers
|
||||
*/
|
||||
@@ -1791,6 +1801,7 @@ struct fragment_program
|
||||
GLuint NumNativeTexIndirections;
|
||||
GLenum FogOption;
|
||||
struct program_parameter_list *Parameters; /**< array [NumParameters] */
|
||||
GLboolean UsesKill;
|
||||
|
||||
#ifdef USE_TCC
|
||||
char c_str[4096]; /* experimental... */
|
||||
@@ -1835,6 +1846,9 @@ struct gl_vertex_program_state
|
||||
GLboolean PointSizeEnabled; /**< GL_VERTEX_PROGRAM_POINT_SIZE_NV */
|
||||
GLboolean TwoSideEnabled; /**< GL_VERTEX_PROGRAM_TWO_SIDE_NV */
|
||||
struct vertex_program *Current; /**< ptr to currently bound program */
|
||||
struct vertex_program *_Current; /**< ptr to currently bound
|
||||
program, including internal
|
||||
(t_vp_build.c) programs */
|
||||
|
||||
GLenum TrackMatrix[MAX_NV_VERTEX_PROGRAM_PARAMS / 4];
|
||||
GLenum TrackMatrixTransform[MAX_NV_VERTEX_PROGRAM_PARAMS / 4];
|
||||
@@ -1865,7 +1879,8 @@ struct gl_fragment_program_state
|
||||
GLboolean _Enabled; /* Really enabled? */
|
||||
GLboolean _Active; /* Really really enabled? */
|
||||
struct fragment_program *Current; /* ptr to currently bound program */
|
||||
struct fragment_program *_Current; /* ptr to currently active program */
|
||||
struct fragment_program *_Current; /* ptr to currently active program
|
||||
(including internal programs) */
|
||||
struct fp_machine Machine; /* machine state */
|
||||
GLfloat Parameters[MAX_NV_FRAGMENT_PROGRAM_PARAMS][4]; /* Env params */
|
||||
|
||||
|
@@ -1130,32 +1130,41 @@ void _mesa_UpdateTexEnvProgram( GLcontext *ctx )
|
||||
{
|
||||
struct state_key *key;
|
||||
GLuint hash;
|
||||
struct fragment_program *prev = ctx->FragmentProgram._Current;
|
||||
|
||||
if (ctx->FragmentProgram._Enabled)
|
||||
return;
|
||||
if (!ctx->FragmentProgram._Enabled) {
|
||||
key = make_state_key(ctx);
|
||||
hash = hash_key(key);
|
||||
|
||||
ctx->FragmentProgram._Current = ctx->_TexEnvProgram =
|
||||
(struct fragment_program *)
|
||||
search_cache(ctx->Texture.env_fp_cache, hash, key, sizeof(*key));
|
||||
|
||||
key = make_state_key(ctx);
|
||||
hash = hash_key(key);
|
||||
|
||||
ctx->FragmentProgram._Current = ctx->_TexEnvProgram =
|
||||
(struct fragment_program *)
|
||||
search_cache(ctx->Texture.env_fp_cache, hash, key, sizeof(*key));
|
||||
|
||||
if (!ctx->_TexEnvProgram) {
|
||||
if (0) _mesa_printf("Building new texenv proggy for key %x\n", hash);
|
||||
if (!ctx->_TexEnvProgram) {
|
||||
if (1) _mesa_printf("Building new texenv proggy for key %x\n", hash);
|
||||
|
||||
ctx->FragmentProgram._Current = ctx->_TexEnvProgram =
|
||||
(struct fragment_program *)
|
||||
ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
|
||||
ctx->FragmentProgram._Current = ctx->_TexEnvProgram =
|
||||
(struct fragment_program *)
|
||||
ctx->Driver.NewProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, 0);
|
||||
|
||||
create_new_program(key, ctx, ctx->_TexEnvProgram);
|
||||
create_new_program(key, ctx, ctx->_TexEnvProgram);
|
||||
|
||||
cache_item(&ctx->Texture.env_fp_cache, hash, key, ctx->_TexEnvProgram);
|
||||
} else {
|
||||
FREE(key);
|
||||
if (0) _mesa_printf("Found existing texenv program for key %x\n", hash);
|
||||
cache_item(&ctx->Texture.env_fp_cache, hash, key, ctx->_TexEnvProgram);
|
||||
} else {
|
||||
FREE(key);
|
||||
if (1) _mesa_printf("Found existing texenv program for key %x\n", hash);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ctx->FragmentProgram._Current = ctx->FragmentProgram.Current;
|
||||
}
|
||||
|
||||
|
||||
/* Tell the driver about the change. Could define a new target for
|
||||
* this?
|
||||
*/
|
||||
if (ctx->FragmentProgram._Current != prev)
|
||||
ctx->Driver.BindProgram(ctx, GL_FRAGMENT_PROGRAM_ARB, (struct program *)
|
||||
ctx->FragmentProgram._Current);
|
||||
}
|
||||
|
||||
void _mesa_TexEnvProgramCacheDestroy( GLcontext *ctx )
|
||||
|
@@ -3013,6 +3013,7 @@ parse_fp_instruction (GLcontext * ctx, GLubyte ** inst,
|
||||
break;
|
||||
|
||||
case OP_TEX_KIL:
|
||||
Program->UsesKill = 1;
|
||||
if (parse_fp_vector_src_reg(ctx, inst, vc_head, Program, &fp->SrcReg[0]))
|
||||
return 1;
|
||||
fp->Opcode = FP_OPCODE_KIL;
|
||||
@@ -4014,6 +4015,8 @@ _mesa_parse_arb_program (GLcontext * ctx, const GLubyte * str, GLsizei len,
|
||||
program->NumTexInstructions =
|
||||
program->NumTexIndirections = 0;
|
||||
|
||||
program->UsesKill = 0;
|
||||
|
||||
program->FPInstructions = NULL;
|
||||
program->VPInstructions = NULL;
|
||||
|
||||
|
@@ -65,6 +65,8 @@ struct arb_program
|
||||
GLuint NumAluInstructions;
|
||||
GLuint NumTexInstructions;
|
||||
GLuint NumTexIndirections;
|
||||
|
||||
GLboolean UsesKill;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -37,15 +37,6 @@
|
||||
#include "mtypes.h"
|
||||
|
||||
|
||||
/**
|
||||
* Fragment program output registers.
|
||||
* Note: when we fully suppport GL_ARB_draw_buffers we'll have more than
|
||||
* one output color.
|
||||
*/
|
||||
#define FRAG_OUTPUT_COLR 0 /* fragment color */
|
||||
#define FRAG_OUTPUT_COLH 1 /* fragment color, half precision (NV) */
|
||||
#define FRAG_OUTPUT_DEPR 2 /* depth/Z */
|
||||
|
||||
|
||||
/* condition codes */
|
||||
#define COND_GT 1 /* greater than zero */
|
||||
|
@@ -288,8 +288,9 @@ static const char *InputRegisters[MAX_NV_VERTEX_PROGRAM_INPUTS + 1] = {
|
||||
};
|
||||
|
||||
static const char *OutputRegisters[MAX_NV_VERTEX_PROGRAM_OUTPUTS + 1] = {
|
||||
"HPOS", "COL0", "COL1", "BFC0", "BFC1", "FOGC", "PSIZ",
|
||||
"TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7", NULL
|
||||
"HPOS", "COL0", "COL1", "FOGC",
|
||||
"TEX0", "TEX1", "TEX2", "TEX3", "TEX4", "TEX5", "TEX6", "TEX7",
|
||||
"PSIZ", "BFC0", "BFC1", NULL
|
||||
};
|
||||
|
||||
/* NOTE: the order here must match opcodes in nvvertprog.h */
|
||||
|
@@ -53,10 +53,10 @@ struct state_key {
|
||||
unsigned fog_source_is_depth:1;
|
||||
unsigned tnl_do_vertex_fog:1;
|
||||
unsigned separate_specular:1;
|
||||
unsigned fog_enabled:1;
|
||||
unsigned fog_mode:2;
|
||||
unsigned point_attenuated:1;
|
||||
unsigned texture_enabled_global:1;
|
||||
unsigned fragprog_inputs_read:12;
|
||||
|
||||
struct {
|
||||
unsigned light_enabled:1;
|
||||
@@ -75,10 +75,10 @@ struct state_key {
|
||||
|
||||
|
||||
|
||||
#define FOG_LINEAR 0
|
||||
#define FOG_EXP 1
|
||||
#define FOG_EXP2 2
|
||||
#define FOG_UNKNOWN 3
|
||||
#define FOG_NONE 0
|
||||
#define FOG_LINEAR 1
|
||||
#define FOG_EXP 2
|
||||
#define FOG_EXP2 3
|
||||
|
||||
static GLuint translate_fog_mode( GLenum mode )
|
||||
{
|
||||
@@ -86,7 +86,7 @@ static GLuint translate_fog_mode( GLenum mode )
|
||||
case GL_LINEAR: return FOG_LINEAR;
|
||||
case GL_EXP: return FOG_EXP;
|
||||
case GL_EXP2: return FOG_EXP2;
|
||||
default: return FOG_UNKNOWN;
|
||||
default: return FOG_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,9 +116,16 @@ static struct state_key *make_state_key( GLcontext *ctx )
|
||||
{
|
||||
TNLcontext *tnl = TNL_CONTEXT(ctx);
|
||||
struct vertex_buffer *VB = &tnl->vb;
|
||||
struct fragment_program *fp = ctx->FragmentProgram._Current;
|
||||
struct state_key *key = CALLOC_STRUCT(state_key);
|
||||
GLuint i;
|
||||
|
||||
/* This now relies on texenvprogram.c being active:
|
||||
*/
|
||||
assert(fp);
|
||||
|
||||
key->fragprog_inputs_read = fp->InputsRead;
|
||||
|
||||
key->separate_specular = (ctx->Light.Model.ColorControl ==
|
||||
GL_SEPARATE_SPECULAR_COLOR);
|
||||
|
||||
@@ -166,18 +173,13 @@ static struct state_key *make_state_key( GLcontext *ctx )
|
||||
if (ctx->Transform.RescaleNormals)
|
||||
key->rescale_normals = 1;
|
||||
|
||||
if (ctx->Fog.Enabled)
|
||||
key->fog_enabled = 1;
|
||||
|
||||
if (key->fog_enabled) {
|
||||
if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT)
|
||||
key->fog_source_is_depth = 1;
|
||||
|
||||
if (tnl->_DoVertexFog)
|
||||
key->tnl_do_vertex_fog = 1;
|
||||
|
||||
key->fog_mode = translate_fog_mode(ctx->Fog.Mode);
|
||||
}
|
||||
key->fog_mode = translate_fog_mode(fp->FogOption);
|
||||
|
||||
if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT)
|
||||
key->fog_source_is_depth = 1;
|
||||
|
||||
if (tnl->_DoVertexFog)
|
||||
key->tnl_do_vertex_fog = 1;
|
||||
|
||||
if (ctx->Point._Attenuated)
|
||||
key->point_attenuated = 1;
|
||||
@@ -332,6 +334,9 @@ static struct ureg get_temp( struct tnl_program *p )
|
||||
_mesa_exit(1);
|
||||
}
|
||||
|
||||
if (bit > p->program->Base.NumTemporaries)
|
||||
p->program->Base.NumTemporaries = bit;
|
||||
|
||||
p->temp_in_use |= 1<<(bit-1);
|
||||
return make_ureg(PROGRAM_TEMPORARY, bit-1);
|
||||
}
|
||||
@@ -710,6 +715,8 @@ static GLuint material_attrib( GLuint side, GLuint property )
|
||||
side);
|
||||
}
|
||||
|
||||
/* Get a bitmask of which material values vary on a per-vertex basis.
|
||||
*/
|
||||
static void set_material_flags( struct tnl_program *p )
|
||||
{
|
||||
p->color_materials = 0;
|
||||
@@ -1194,9 +1201,14 @@ static void build_texture_transform( struct tnl_program *p )
|
||||
GLuint i, j;
|
||||
|
||||
for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
|
||||
GLuint texmat_enabled = p->state->unit[i].texmat_enabled;
|
||||
|
||||
if (p->state->unit[i].texgen_enabled || texmat_enabled) {
|
||||
if (!(p->state->fragprog_inputs_read & (FRAG_BIT_TEX0<<i)))
|
||||
continue;
|
||||
|
||||
if (p->state->unit[i].texgen_enabled ||
|
||||
p->state->unit[i].texmat_enabled) {
|
||||
|
||||
GLuint texmat_enabled = p->state->unit[i].texmat_enabled;
|
||||
struct ureg out = register_output(p, VERT_RESULT_TEX0 + i);
|
||||
struct ureg out_texgen = undef;
|
||||
|
||||
@@ -1293,10 +1305,7 @@ static void build_texture_transform( struct tnl_program *p )
|
||||
|
||||
release_temps(p);
|
||||
}
|
||||
else if (p->state->unit[i].texunit_really_enabled) {
|
||||
/* KW: _ReallyEnabled isn't sufficient? Need to know whether
|
||||
* this texture unit is referenced by the fragment shader.
|
||||
*/
|
||||
else {
|
||||
emit_passthrough(p, VERT_ATTRIB_TEX0+i, VERT_RESULT_TEX0+i);
|
||||
}
|
||||
}
|
||||
@@ -1338,15 +1347,23 @@ static void build_tnl_program( struct tnl_program *p )
|
||||
|
||||
/* Lighting calculations:
|
||||
*/
|
||||
if (p->state->light_global_enabled)
|
||||
build_lighting(p);
|
||||
else
|
||||
emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL0);
|
||||
if (p->state->fragprog_inputs_read & (FRAG_BIT_COL0|FRAG_BIT_COL1)) {
|
||||
if (p->state->light_global_enabled)
|
||||
build_lighting(p);
|
||||
else {
|
||||
if (p->state->fragprog_inputs_read & FRAG_BIT_COL0)
|
||||
emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL0);
|
||||
|
||||
if (p->state->fog_enabled)
|
||||
if (p->state->fragprog_inputs_read & FRAG_BIT_COL1)
|
||||
emit_passthrough(p, VERT_ATTRIB_COLOR0, VERT_RESULT_COL1);
|
||||
}
|
||||
}
|
||||
|
||||
if ((p->state->fragprog_inputs_read & FRAG_BIT_FOGC) ||
|
||||
p->state->fog_mode != FOG_NONE)
|
||||
build_fog(p);
|
||||
|
||||
if (p->state->texture_enabled_global)
|
||||
if (p->state->fragprog_inputs_read & FRAG_BITS_TEX_ANY)
|
||||
build_texture_transform(p);
|
||||
|
||||
if (p->state->point_attenuated)
|
||||
@@ -1470,42 +1487,60 @@ void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx )
|
||||
TNLcontext *tnl = TNL_CONTEXT(ctx);
|
||||
struct state_key *key;
|
||||
GLuint hash;
|
||||
struct vertex_program *prev = ctx->VertexProgram._Current;
|
||||
|
||||
if (ctx->VertexProgram._Enabled)
|
||||
return;
|
||||
if (ctx->VertexProgram._Enabled) {
|
||||
/* Grab all the relevent state and put it in a single structure:
|
||||
*/
|
||||
key = make_state_key(ctx);
|
||||
hash = hash_key(key);
|
||||
|
||||
/* Grab all the relevent state and put it in a single structure:
|
||||
*/
|
||||
key = make_state_key(ctx);
|
||||
hash = hash_key(key);
|
||||
|
||||
/* Look for an already-prepared program for this state:
|
||||
*/
|
||||
ctx->_TnlProgram = (struct vertex_program *)
|
||||
search_cache( tnl->vp_cache, hash, key, sizeof(*key) );
|
||||
|
||||
/* OK, we'll have to build a new one:
|
||||
*/
|
||||
if (!ctx->_TnlProgram) {
|
||||
if (0)
|
||||
_mesa_printf("Build new TNL program\n");
|
||||
if (tnl->vp_cache == NULL) {
|
||||
tnl->vp_cache = MALLOC(sizeof(*tnl->vp_cache));
|
||||
tnl->vp_cache->size = 5;
|
||||
tnl->vp_cache->n_items = 0;
|
||||
tnl->vp_cache->items = MALLOC(tnl->vp_cache->size *
|
||||
sizeof(*tnl->vp_cache->items));
|
||||
_mesa_memset(tnl->vp_cache->items, 0, tnl->vp_cache->size *
|
||||
sizeof(*tnl->vp_cache->items));
|
||||
}
|
||||
|
||||
/* Look for an already-prepared program for this state:
|
||||
*/
|
||||
ctx->_TnlProgram = (struct vertex_program *)
|
||||
ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
|
||||
search_cache( tnl->vp_cache, hash, key, sizeof(*key) );
|
||||
|
||||
/* OK, we'll have to build a new one:
|
||||
*/
|
||||
if (!ctx->_TnlProgram) {
|
||||
if (0)
|
||||
_mesa_printf("Build new TNL program\n");
|
||||
|
||||
ctx->_TnlProgram = (struct vertex_program *)
|
||||
ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
|
||||
|
||||
create_new_program( key, ctx->_TnlProgram,
|
||||
ctx->Const.VertexProgram.MaxTemps );
|
||||
create_new_program( key, ctx->_TnlProgram,
|
||||
ctx->Const.VertexProgram.MaxTemps );
|
||||
|
||||
cache_item(tnl->vp_cache, hash, key, ctx->_TnlProgram );
|
||||
|
||||
cache_item(tnl->vp_cache, hash, key, ctx->_TnlProgram );
|
||||
}
|
||||
else {
|
||||
FREE(key);
|
||||
if (0)
|
||||
_mesa_printf("Found existing TNL program for key %x\n", hash);
|
||||
}
|
||||
}
|
||||
else {
|
||||
FREE(key);
|
||||
if (0)
|
||||
_mesa_printf("Found existing TNL program for key %x\n", hash);
|
||||
ctx->VertexProgram._Current = ctx->VertexProgram.Current;
|
||||
}
|
||||
|
||||
/* Need a BindProgram callback for the driver?
|
||||
/* Tell the driver about the change. Could define a new target for
|
||||
* this?
|
||||
*/
|
||||
if (ctx->VertexProgram._Current != prev)
|
||||
ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB, (struct program *)
|
||||
ctx->VertexProgram._Current);
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user