📄 t_vp_build.c
字号:
if (count == nr_lights) {
if (separate) {
mask0 = WRITEMASK_XYZ;
mask1 = WRITEMASK_XYZ;
res0 = register_output( p, VERT_RESULT_COL0 );
res1 = register_output( p, VERT_RESULT_COL1 );
}
else {
mask0 = 0;
mask1 = WRITEMASK_XYZ;
res0 = _col0;
res1 = register_output( p, VERT_RESULT_COL0 );
}
} else {
mask0 = 0;
mask1 = 0;
res0 = _col0;
res1 = _col1;
}
emit_op3(p, VP_OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0);
emit_op3(p, VP_OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0);
emit_op3(p, VP_OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _col1);
release_temp(p, ambient);
release_temp(p, diffuse);
release_temp(p, specular);
}
/* Back face lighting:
*/
if (twoside) {
struct ureg ambient = get_lightprod(p, i, 1, STATE_AMBIENT);
struct ureg diffuse = get_lightprod(p, i, 1, STATE_DIFFUSE);
struct ureg specular = get_lightprod(p, i, 1, STATE_SPECULAR);
struct ureg res0, res1;
GLuint mask0, mask1;
emit_op1(p, VP_OPCODE_LIT, lit, 0, negate(swizzle(dots,X,Y,W,Z)));
if (!is_undef(att))
emit_op2(p, VP_OPCODE_MUL, lit, 0, lit, att);
if (count == nr_lights) {
if (separate) {
mask0 = WRITEMASK_XYZ;
mask1 = WRITEMASK_XYZ;
res0 = register_output( p, VERT_RESULT_BFC0 );
res1 = register_output( p, VERT_RESULT_BFC1 );
}
else {
mask0 = 0;
mask1 = WRITEMASK_XYZ;
res0 = _bfc0;
res1 = register_output( p, VERT_RESULT_BFC0 );
}
} else {
res0 = _bfc0;
res1 = _bfc1;
mask0 = 0;
mask1 = 0;
}
emit_op3(p, VP_OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0);
emit_op3(p, VP_OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0);
emit_op3(p, VP_OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1);
release_temp(p, ambient);
release_temp(p, diffuse);
release_temp(p, specular);
}
release_temp(p, half);
release_temp(p, VPpli);
release_temp(p, att);
}
}
release_temps( p );
}
static void build_fog( struct tnl_program *p )
{
struct ureg fog = register_output(p, VERT_RESULT_FOGC);
struct ureg input;
if (p->state->fog_source_is_depth) {
input = swizzle1(get_eye_position(p), Z);
}
else {
input = swizzle1(register_input(p, VERT_ATTRIB_FOG), X);
}
if (p->state->tnl_do_vertex_fog) {
struct ureg params = register_param1(p, STATE_FOG_PARAMS);
struct ureg tmp = get_temp(p);
switch (p->state->fog_mode) {
case FOG_LINEAR: {
struct ureg id = get_identity_param(p);
emit_op2(p, VP_OPCODE_SUB, tmp, 0, swizzle1(params,Z), input);
emit_op2(p, VP_OPCODE_MUL, tmp, 0, tmp, swizzle1(params,W));
emit_op2(p, VP_OPCODE_MAX, tmp, 0, tmp, swizzle1(id,X)); /* saturate */
emit_op2(p, VP_OPCODE_MIN, fog, WRITEMASK_X, tmp, swizzle1(id,W));
break;
}
case FOG_EXP:
emit_op1(p, VP_OPCODE_ABS, tmp, 0, input);
emit_op2(p, VP_OPCODE_MUL, tmp, 0, tmp, swizzle1(params,X));
emit_op2(p, VP_OPCODE_POW, fog, WRITEMASK_X,
register_const1f(p, M_E), negate(tmp));
break;
case FOG_EXP2:
emit_op2(p, VP_OPCODE_MUL, tmp, 0, input, swizzle1(params,X));
emit_op2(p, VP_OPCODE_MUL, tmp, 0, tmp, tmp);
emit_op2(p, VP_OPCODE_POW, fog, WRITEMASK_X,
register_const1f(p, M_E), negate(tmp));
break;
}
release_temp(p, tmp);
}
else {
/* results = incoming fog coords (compute fog per-fragment later)
*
* KW: Is it really necessary to do anything in this case?
*/
emit_op1(p, VP_OPCODE_MOV, fog, WRITEMASK_X, input);
}
}
static void build_reflect_texgen( struct tnl_program *p,
struct ureg dest,
GLuint writemask )
{
struct ureg normal = get_eye_normal(p);
struct ureg eye_hat = get_eye_position_normalized(p);
struct ureg tmp = get_temp(p);
/* n.u */
emit_op2(p, VP_OPCODE_DP3, tmp, 0, normal, eye_hat);
/* 2n.u */
emit_op2(p, VP_OPCODE_ADD, tmp, 0, tmp, tmp);
/* (-2n.u)n + u */
emit_op3(p, VP_OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat);
}
static void build_sphere_texgen( struct tnl_program *p,
struct ureg dest,
GLuint writemask )
{
struct ureg normal = get_eye_normal(p);
struct ureg eye_hat = get_eye_position_normalized(p);
struct ureg tmp = get_temp(p);
struct ureg half = register_scalar_const(p, .5);
struct ureg r = get_temp(p);
struct ureg inv_m = get_temp(p);
struct ureg id = get_identity_param(p);
/* Could share the above calculations, but it would be
* a fairly odd state for someone to set (both sphere and
* reflection active for different texture coordinate
* components. Of course - if two texture units enable
* reflect and/or sphere, things start to tilt in favour
* of seperating this out:
*/
/* n.u */
emit_op2(p, VP_OPCODE_DP3, tmp, 0, normal, eye_hat);
/* 2n.u */
emit_op2(p, VP_OPCODE_ADD, tmp, 0, tmp, tmp);
/* (-2n.u)n + u */
emit_op3(p, VP_OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat);
/* r + 0,0,1 */
emit_op2(p, VP_OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z));
/* rx^2 + ry^2 + (rz+1)^2 */
emit_op2(p, VP_OPCODE_DP3, tmp, 0, tmp, tmp);
/* 2/m */
emit_op1(p, VP_OPCODE_RSQ, tmp, 0, tmp);
/* 1/m */
emit_op2(p, VP_OPCODE_MUL, inv_m, 0, tmp, half);
/* r/m + 1/2 */
emit_op3(p, VP_OPCODE_MAD, dest, writemask, r, inv_m, half);
release_temp(p, tmp);
release_temp(p, r);
release_temp(p, inv_m);
}
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) {
struct ureg out = register_output(p, VERT_RESULT_TEX0 + i);
struct ureg out_texgen = undef;
if (p->state->unit[i].texgen_enabled) {
GLuint copy_mask = 0;
GLuint sphere_mask = 0;
GLuint reflect_mask = 0;
GLuint normal_mask = 0;
GLuint modes[4];
if (texmat_enabled)
out_texgen = get_temp(p);
else
out_texgen = out;
modes[0] = p->state->unit[i].texgen_mode0;
modes[1] = p->state->unit[i].texgen_mode1;
modes[2] = p->state->unit[i].texgen_mode2;
modes[3] = p->state->unit[i].texgen_mode3;
for (j = 0; j < 4; j++) {
switch (modes[j]) {
case TXG_OBJ_LINEAR: {
struct ureg obj = register_input(p, VERT_ATTRIB_POS);
struct ureg plane =
register_param3(p, STATE_TEXGEN, i,
STATE_TEXGEN_OBJECT_S + j);
emit_op2(p, VP_OPCODE_DP4, out_texgen, WRITEMASK_X << j,
obj, plane );
break;
}
case TXG_EYE_LINEAR: {
struct ureg eye = get_eye_position(p);
struct ureg plane =
register_param3(p, STATE_TEXGEN, i,
STATE_TEXGEN_EYE_S + j);
emit_op2(p, VP_OPCODE_DP4, out_texgen, WRITEMASK_X << j,
eye, plane );
break;
}
case TXG_SPHERE_MAP:
sphere_mask |= WRITEMASK_X << j;
break;
case TXG_REFLECTION_MAP:
reflect_mask |= WRITEMASK_X << j;
break;
case TXG_NORMAL_MAP:
normal_mask |= WRITEMASK_X << j;
break;
case TXG_NONE:
copy_mask |= WRITEMASK_X << j;
}
}
if (sphere_mask) {
build_sphere_texgen(p, out_texgen, sphere_mask);
}
if (reflect_mask) {
build_reflect_texgen(p, out_texgen, reflect_mask);
}
if (normal_mask) {
struct ureg normal = get_eye_normal(p);
emit_op1(p, VP_OPCODE_MOV, out_texgen, normal_mask, normal );
}
if (copy_mask) {
struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i);
emit_op1(p, VP_OPCODE_MOV, out_texgen, copy_mask, in );
}
}
if (texmat_enabled) {
struct ureg texmat[4];
struct ureg in = (!is_undef(out_texgen) ?
out_texgen :
register_input(p, VERT_ATTRIB_TEX0+i));
if (PREFER_DP4) {
register_matrix_param6( p, STATE_MATRIX, STATE_TEXTURE, i,
0, 3, STATE_MATRIX, texmat );
emit_matrix_transform_vec4( p, out, texmat, in );
}
else {
register_matrix_param6( p, STATE_MATRIX, STATE_TEXTURE, i,
0, 3, STATE_MATRIX_TRANSPOSE, texmat );
emit_transpose_matrix_transform_vec4( p, out, texmat, in );
}
}
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.
*/
emit_passthrough(p, VERT_ATTRIB_TEX0+i, VERT_RESULT_TEX0+i);
}
}
}
/* Seems like it could be tighter:
*/
static void build_pointsize( struct tnl_program *p )
{
struct ureg eye = get_eye_position(p);
struct ureg state_size = register_param1(p, STATE_POINT_SIZE);
struct ureg state_attenuation = register_param1(p, STATE_POINT_ATTENUATION);
struct ureg out = register_output(p, VERT_RESULT_PSIZ);
struct ureg ut = get_temp(p);
/* 1, -Z, Z * Z, 1 */
emit_op1(p, VP_OPCODE_MOV, ut, 0, swizzle1(get_identity_param(p), W));
emit_op2(p, VP_OPCODE_MUL, ut, WRITEMASK_YZ, ut, negate(swizzle1(eye, Z)));
emit_op2(p, VP_OPCODE_MUL, ut, WRITEMASK_Z, ut, negate(swizzle1(eye, Z)));
/* p1 + p2 * dist + p3 * dist * dist, 0 */
emit_op2(p, VP_OPCODE_DP3, ut, 0, ut, state_attenuation);
/* 1 / factor */
emit_op1(p, VP_OPCODE_RCP, ut, 0, ut );
/* out = pointSize / factor */
emit_op2(p, VP_OPCODE_MUL, out, WRITEMASK_X, ut, state_size);
release_temp(p, ut);
}
static void build_tnl_program( struct tnl_program *p )
{ /* Emit the program, starting with modelviewproject:
*/
build_hpos(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->fog_enabled)
build_fog(p);
if (p->state->texture_enabled_global)
build_texture_transform(p);
if (p->state->point_attenuated)
build_pointsize(p);
/* Finish up:
*/
emit_op1(p, VP_OPCODE_END, undef, 0, undef);
/* Disassemble:
*/
if (DISASSEM) {
_mesa_printf ("\n");
}
}
static void
create_new_program( const struct state_key *key,
struct vertex_program *program,
GLuint max_temps)
{
struct tnl_program p;
_mesa_memset(&p, 0, sizeof(p));
p.state = key;
p.program = program;
p.eye_position = undef;
p.eye_position_normalized = undef;
p.eye_normal = undef;
p.identity = undef;
p.temp_in_use = 0;
if (max_temps >= sizeof(int) * 8)
p.temp_reserved = 0;
else
p.temp_reserved = ~((1<<max_temps)-1);
p.program->Instructions = MALLOC(sizeof(struct vp_instruction) * MAX_INSN);
p.program->Base.String = 0;
p.program->Base.NumInstructions =
p.program->Base.NumTemporaries =
p.program->Base.NumParameters =
p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0;
p.program->Parameters = _mesa_new_parameter_list();
p.program->InputsRead = 0;
p.program->OutputsWritten = 0;
build_tnl_program( &p );
}
static void *search_cache( struct tnl_cache *cache,
GLuint hash,
const void *key,
GLuint keysize)
{
struct tnl_cache *c;
for (c = cache; c; c = c->next) {
if (c->hash == hash && memcmp(c->key, key, keysize) == 0)
return c->data;
}
return NULL;
}
static void cache_item( struct tnl_cache **cache,
GLuint hash,
void *key,
void *data )
{
struct tnl_cache *c = MALLOC(sizeof(*c));
c->hash = hash;
c->key = key;
c->data = data;
c->next = *cache;
*cache = c;
}
static GLuint hash_key( struct state_key *key )
{
GLuint *ikey = (GLuint *)key;
GLuint hash = 0, i;
/* I'm sure this can be improved on, but speed is important:
*/
for (i = 0; i < sizeof(*key)/sizeof(GLuint); i++)
hash ^= ikey[i];
return hash;
}
void _tnl_UpdateFixedFunctionProgram( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct state_key *key;
GLuint hash;
if (ctx->VertexProgram._Enabled)
return;
/* 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");
ctx->_TnlProgram = (struct vertex_program *)
ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0);
create_new_program( key, ctx->_TnlProgram,
ctx->Const.MaxVertexProgramTemps );
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);
}
/* Need a BindProgram callback for the driver?
*/
}
void _tnl_ProgramCacheDestroy( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct tnl_cache *a, *tmp;
for (a = tnl->vp_cache ; a; a = tmp) {
tmp = a->next;
FREE(a->key);
FREE(a->data);
FREE(a);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -