📄 t_vp_build.c
字号:
emit_op1(p, OPCODE_LIT, lit, 0, negate(swizzle(dots,X,Y,W,Z))); if (!is_undef(att)) emit_op2(p, 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, OPCODE_MAD, _bfc0, 0, swizzle1(lit,X), ambient, _bfc0); emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _bfc0); emit_op3(p, OPCODE_MAD, res1, mask1, swizzle1(lit,Z), specular, _bfc1); release_temp(p, ambient); release_temp(p, diffuse); release_temp(p, specular); } 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->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); GLboolean useabs = (p->state->fog_mode != FOG_EXP2); 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, 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_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_op1(p, OPCODE_EX2, fog, WRITEMASK_X, 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? * BP: Yes, we always need to compute the absolute value, unless * we want to push that down into the fragment program... */ GLboolean useabs = GL_TRUE; emit_op1(p, useabs ? OPCODE_ABS : 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, OPCODE_DP3, tmp, 0, normal, eye_hat); /* 2n.u */ emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); /* (-2n.u)n + u */ emit_op3(p, OPCODE_MAD, dest, writemask, negate(tmp), normal, eye_hat); release_temp(p, tmp);}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, OPCODE_DP3, tmp, 0, normal, eye_hat); /* 2n.u */ emit_op2(p, OPCODE_ADD, tmp, 0, tmp, tmp); /* (-2n.u)n + u */ emit_op3(p, OPCODE_MAD, r, 0, negate(tmp), normal, eye_hat); /* r + 0,0,1 */ emit_op2(p, OPCODE_ADD, tmp, 0, r, swizzle(id,X,Y,W,Z)); /* rx^2 + ry^2 + (rz+1)^2 */ emit_op2(p, OPCODE_DP3, tmp, 0, tmp, tmp); /* 2/m */ emit_op1(p, OPCODE_RSQ, tmp, 0, tmp); /* 1/m */ emit_op2(p, OPCODE_MUL, inv_m, 0, tmp, half); /* r/m + 1/2 */ emit_op3(p, 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++) { if (!(p->state->fragprog_inputs_read & FRAG_BIT_TEX(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; 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, 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, 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, OPCODE_MOV, out_texgen, normal_mask, normal ); } if (copy_mask) { struct ureg in = register_input(p, VERT_ATTRIB_TEX0+i); emit_op1(p, 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_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, 0, texmat ); emit_matrix_transform_vec4( p, out, texmat, in ); } else { register_matrix_param5( p, STATE_TEXTURE_MATRIX, i, 0, 3, STATE_MATRIX_TRANSPOSE, texmat ); emit_transpose_matrix_transform_vec4( p, out, texmat, in ); } } release_temps(p); } else { emit_passthrough(p, VERT_ATTRIB_TEX0+i, VERT_RESULT_TEX0+i); } }}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); /* dist = |eyez| */ emit_op1(p, OPCODE_ABS, ut, WRITEMASK_Y, swizzle1(eye, Z)); /* p1 + dist * (p2 + dist * p3); */ emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), swizzle1(state_attenuation, Z), swizzle1(state_attenuation, Y)); emit_op3(p, OPCODE_MAD, ut, WRITEMASK_X, swizzle1(ut, Y), ut, swizzle1(state_attenuation, X)); /* 1 / sqrt(factor) */ emit_op1(p, OPCODE_RSQ, ut, WRITEMASK_X, ut );#if 1 /* out = pointSize / sqrt(factor) */ emit_op2(p, OPCODE_MUL, out, WRITEMASK_X, ut, state_size);#else /* not sure, might make sense to do clamping here, but it's not done in t_vb_points neither */ emit_op2(p, OPCODE_MUL, ut, WRITEMASK_X, ut, state_size); emit_op2(p, OPCODE_MAX, ut, WRITEMASK_X, ut, swizzle1(state_size, Y)); emit_op2(p, OPCODE_MIN, out, WRITEMASK_X, ut, swizzle1(state_size, Z));#endif 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->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->fragprog_inputs_read & FRAG_BIT_COL1) emit_passthrough(p, VERT_ATTRIB_COLOR1, VERT_RESULT_COL1); } } if ((p->state->fragprog_inputs_read & FRAG_BIT_FOGC) || p->state->fog_mode != FOG_NONE) build_fog(p); if (p->state->fragprog_inputs_read & FRAG_BITS_TEX_ANY) build_texture_transform(p); if (p->state->point_attenuated) build_pointsize(p); /* Finish up: */ emit_op1(p, OPCODE_END, undef, 0, undef); /* Disassemble: */ if (DISASSEM) { _mesa_printf ("\n"); }}static voidcreate_new_program( const struct state_key *key, struct gl_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->Base.Instructions = _mesa_alloc_instructions(MAX_INSN); p.program->Base.String = NULL; p.program->Base.NumInstructions = p.program->Base.NumTemporaries = p.program->Base.NumParameters = p.program->Base.NumAttributes = p.program->Base.NumAddressRegs = 0; p.program->Base.Parameters = _mesa_new_parameter_list(); p.program->Base.InputsRead = 0; p.program->Base.OutputsWritten = 0; build_tnl_program( &p );}static struct gl_vertex_program *search_cache(struct tnl_cache *cache, GLuint hash, const void *key, GLuint keysize){ struct tnl_cache_item *c; for (c = cache->items[hash % cache->size]; c; c = c->next) { if (c->hash == hash && _mesa_memcmp(c->key, key, keysize) == 0) return c->prog; } return NULL;}static void rehash( struct tnl_cache *cache ){ struct tnl_cache_item **items; struct tnl_cache_item *c, *next; GLuint size, i; size = cache->size * 3; items = (struct tnl_cache_item**) _mesa_malloc(size * sizeof(*items)); _mesa_memset(items, 0, size * sizeof(*items)); for (i = 0; i < cache->size; i++) for (c = cache->items[i]; c; c = next) { next = c->next; c->next = items[c->hash % size]; items[c->hash % size] = c; } FREE(cache->items); cache->items = items; cache->size = size;}static void cache_item( GLcontext *ctx, struct tnl_cache *cache, GLuint hash, void *key, struct gl_vertex_program *prog ){ struct tnl_cache_item *c = CALLOC_STRUCT(tnl_cache_item); c->hash = hash; c->key = key; c->prog = prog; if (++cache->n_items > cache->size * 1.5) rehash(cache); c->next = cache->items[hash % cache->size]; cache->items[hash % cache->size] = 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; const struct gl_vertex_program *prev = ctx->VertexProgram._Current; if (!ctx->VertexProgram._Current || ctx->VertexProgram._Current == ctx->VertexProgram._TnlProgram) { struct gl_vertex_program *newProg; /* 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: */ newProg = search_cache( tnl->vp_cache, hash, key, sizeof(*key)); /* OK, we'll have to build a new one: */ if (!newProg) { if (0) _mesa_printf("Build new TNL program\n"); newProg = (struct gl_vertex_program *) ctx->Driver.NewProgram(ctx, GL_VERTEX_PROGRAM_ARB, 0); create_new_program( key, newProg, ctx->Const.VertexProgram.MaxTemps ); if (ctx->Driver.ProgramStringNotify) ctx->Driver.ProgramStringNotify( ctx, GL_VERTEX_PROGRAM_ARB, &newProg->Base ); /* Our ownership of newProg is transferred to the cache */ cache_item(ctx, tnl->vp_cache, hash, key, newProg); } else { FREE(key); } _mesa_reference_vertprog(ctx, &ctx->VertexProgram._TnlProgram, newProg); _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, newProg); } /* Tell the driver about the change. Could define a new target for * this? */ if (ctx->VertexProgram._Current != prev && ctx->Driver.BindProgram) { ctx->Driver.BindProgram(ctx, GL_VERTEX_PROGRAM_ARB, (struct gl_program *) ctx->VertexProgram._Current); }}void _tnl_ProgramCacheInit( GLcontext *ctx ){ TNLcontext *tnl = TNL_CONTEXT(ctx); tnl->vp_cache = (struct tnl_cache *) MALLOC(sizeof(*tnl->vp_cache)); tnl->vp_cache->size = 17; tnl->vp_cache->n_items = 0; tnl->vp_cache->items = (struct tnl_cache_item**) _mesa_calloc(tnl->vp_cache->size * sizeof(*tnl->vp_cache->items));}void _tnl_ProgramCacheDestroy( GLcontext *ctx ){ TNLcontext *tnl = TNL_CONTEXT(ctx); struct tnl_cache_item *c, *next; GLuint i; for (i = 0; i < tnl->vp_cache->size; i++) for (c = tnl->vp_cache->items[i]; c; c = next) { next = c->next; FREE(c->key); _mesa_reference_vertprog(ctx, &c->prog, NULL); FREE(c); } FREE(tnl->vp_cache->items); FREE(tnl->vp_cache);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -