📄 t_vp_build.c
字号:
GLuint nr = p->program->Base.NumInstructions++;
struct vp_instruction *inst = &p->program->Instructions[nr];
if (p->program->Base.NumInstructions > MAX_INSN) {
_mesa_problem(0, "Out of instructions in emit_op3fn\n");
return;
}
inst->Opcode = op;
inst->StringPos = 0;
inst->Data = 0;
emit_arg( &inst->SrcReg[0], src0 );
emit_arg( &inst->SrcReg[1], src1 );
emit_arg( &inst->SrcReg[2], src2 );
emit_dst( &inst->DstReg, dest, mask );
debug_insn(inst, fn, line);
}
#define emit_op3(p, op, dst, mask, src0, src1, src2) \
emit_op3fn(p, op, dst, mask, src0, src1, src2, __FUNCTION__, __LINE__)
#define emit_op2(p, op, dst, mask, src0, src1) \
emit_op3fn(p, op, dst, mask, src0, src1, undef, __FUNCTION__, __LINE__)
#define emit_op1(p, op, dst, mask, src0) \
emit_op3fn(p, op, dst, mask, src0, undef, undef, __FUNCTION__, __LINE__)
static struct ureg make_temp( struct tnl_program *p, struct ureg reg )
{
if (reg.file == PROGRAM_TEMPORARY &&
!(p->temp_reserved & (1<<reg.idx)))
return reg;
else {
struct ureg temp = get_temp(p);
emit_op1(p, VP_OPCODE_MOV, temp, 0, reg);
return temp;
}
}
/* Currently no tracking performed of input/output/register size or
* active elements. Could be used to reduce these operations, as
* could the matrix type.
*/
static void emit_matrix_transform_vec4( struct tnl_program *p,
struct ureg dest,
const struct ureg *mat,
struct ureg src)
{
emit_op2(p, VP_OPCODE_DP4, dest, WRITEMASK_X, src, mat[0]);
emit_op2(p, VP_OPCODE_DP4, dest, WRITEMASK_Y, src, mat[1]);
emit_op2(p, VP_OPCODE_DP4, dest, WRITEMASK_Z, src, mat[2]);
emit_op2(p, VP_OPCODE_DP4, dest, WRITEMASK_W, src, mat[3]);
}
/* This version is much easier to implement if writemasks are not
* supported natively on the target or (like SSE), the target doesn't
* have a clean/obvious dotproduct implementation.
*/
static void emit_transpose_matrix_transform_vec4( struct tnl_program *p,
struct ureg dest,
const struct ureg *mat,
struct ureg src)
{
struct ureg tmp;
if (dest.file != PROGRAM_TEMPORARY)
tmp = get_temp(p);
else
tmp = dest;
emit_op2(p, VP_OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]);
emit_op3(p, VP_OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp);
emit_op3(p, VP_OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp);
emit_op3(p, VP_OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp);
if (dest.file != PROGRAM_TEMPORARY)
release_temp(p, tmp);
}
static void emit_matrix_transform_vec3( struct tnl_program *p,
struct ureg dest,
const struct ureg *mat,
struct ureg src)
{
emit_op2(p, VP_OPCODE_DP3, dest, WRITEMASK_X, src, mat[0]);
emit_op2(p, VP_OPCODE_DP3, dest, WRITEMASK_Y, src, mat[1]);
emit_op2(p, VP_OPCODE_DP3, dest, WRITEMASK_Z, src, mat[2]);
}
static void emit_normalize_vec3( struct tnl_program *p,
struct ureg dest,
struct ureg src )
{
struct ureg tmp = get_temp(p);
emit_op2(p, VP_OPCODE_DP3, tmp, 0, src, src);
emit_op1(p, VP_OPCODE_RSQ, tmp, 0, tmp);
emit_op2(p, VP_OPCODE_MUL, dest, 0, src, tmp);
release_temp(p, tmp);
}
static void emit_passthrough( struct tnl_program *p,
GLuint input,
GLuint output )
{
struct ureg out = register_output(p, output);
emit_op1(p, VP_OPCODE_MOV, out, 0, register_input(p, input));
}
static struct ureg get_eye_position( struct tnl_program *p )
{
if (is_undef(p->eye_position)) {
struct ureg pos = register_input( p, VERT_ATTRIB_POS );
struct ureg modelview[4];
p->eye_position = reserve_temp(p);
if (PREFER_DP4) {
register_matrix_param6( p, STATE_MATRIX, STATE_MODELVIEW, 0, 0, 3,
STATE_MATRIX, modelview );
emit_matrix_transform_vec4(p, p->eye_position, modelview, pos);
}
else {
register_matrix_param6( p, STATE_MATRIX, STATE_MODELVIEW, 0, 0, 3,
STATE_MATRIX_TRANSPOSE, modelview );
emit_transpose_matrix_transform_vec4(p, p->eye_position, modelview, pos);
}
}
return p->eye_position;
}
static struct ureg get_eye_position_normalized( struct tnl_program *p )
{
if (is_undef(p->eye_position_normalized)) {
struct ureg eye = get_eye_position(p);
p->eye_position_normalized = reserve_temp(p);
emit_normalize_vec3(p, p->eye_position_normalized, eye);
}
return p->eye_position_normalized;
}
static struct ureg get_eye_normal( struct tnl_program *p )
{
if (is_undef(p->eye_normal)) {
struct ureg normal = register_input(p, VERT_ATTRIB_NORMAL );
struct ureg mvinv[3];
register_matrix_param6( p, STATE_MATRIX, STATE_MODELVIEW, 0, 0, 2,
STATE_MATRIX_INVTRANS, mvinv );
p->eye_normal = reserve_temp(p);
/* Transform to eye space:
*/
emit_matrix_transform_vec3( p, p->eye_normal, mvinv, normal );
/* Normalize/Rescale:
*/
if (p->state->normalize) {
emit_normalize_vec3( p, p->eye_normal, p->eye_normal );
}
else if (p->state->rescale_normals) {
struct ureg rescale = register_param2(p, STATE_INTERNAL,
STATE_NORMAL_SCALE);
emit_op2( p, VP_OPCODE_MUL, p->eye_normal, 0, normal,
swizzle1(rescale, X));
}
}
return p->eye_normal;
}
static void build_hpos( struct tnl_program *p )
{
struct ureg pos = register_input( p, VERT_ATTRIB_POS );
struct ureg hpos = register_output( p, VERT_RESULT_HPOS );
struct ureg mvp[4];
if (PREFER_DP4) {
register_matrix_param6( p, STATE_MATRIX, STATE_MVP, 0, 0, 3,
STATE_MATRIX, mvp );
emit_matrix_transform_vec4( p, hpos, mvp, pos );
}
else {
register_matrix_param6( p, STATE_MATRIX, STATE_MVP, 0, 0, 3,
STATE_MATRIX_TRANSPOSE, mvp );
emit_transpose_matrix_transform_vec4( p, hpos, mvp, pos );
}
}
static GLuint material_attrib( GLuint side, GLuint property )
{
return ((property - STATE_AMBIENT) * 2 +
side);
}
static void set_material_flags( struct tnl_program *p )
{
p->color_materials = 0;
p->materials = 0;
if (p->state->light_color_material) {
p->materials =
p->color_materials = p->state->light_color_material_mask;
}
p->materials |= p->state->light_material_mask;
}
static struct ureg get_material( struct tnl_program *p, GLuint side,
GLuint property )
{
GLuint attrib = material_attrib(side, property);
if (p->color_materials & (1<<attrib))
return register_input(p, VERT_ATTRIB_COLOR0);
else if (p->materials & (1<<attrib))
return register_input( p, attrib + _TNL_ATTRIB_MAT_FRONT_AMBIENT );
else
return register_param3( p, STATE_MATERIAL, side, property );
}
#define SCENE_COLOR_BITS(side) (( MAT_BIT_FRONT_EMISSION | \
MAT_BIT_FRONT_AMBIENT | \
MAT_BIT_FRONT_DIFFUSE) << (side))
/* Either return a precalculated constant value or emit code to
* calculate these values dynamically in the case where material calls
* are present between begin/end pairs.
*
* Probably want to shift this to the program compilation phase - if
* we always emitted the calculation here, a smart compiler could
* detect that it was constant (given a certain set of inputs), and
* lift it out of the main loop. That way the programs created here
* would be independent of the vertex_buffer details.
*/
static struct ureg get_scenecolor( struct tnl_program *p, GLuint side )
{
if (p->materials & SCENE_COLOR_BITS(side)) {
struct ureg lm_ambient = register_param1(p, STATE_LIGHTMODEL_AMBIENT);
struct ureg material_emission = get_material(p, side, STATE_EMISSION);
struct ureg material_ambient = get_material(p, side, STATE_AMBIENT);
struct ureg material_diffuse = get_material(p, side, STATE_DIFFUSE);
struct ureg tmp = make_temp(p, material_diffuse);
emit_op3(p, VP_OPCODE_MAD, tmp, WRITEMASK_XYZ, lm_ambient,
material_ambient, material_emission);
return tmp;
}
else
return register_param2( p, STATE_LIGHTMODEL_SCENECOLOR, side );
}
static struct ureg get_lightprod( struct tnl_program *p, GLuint light,
GLuint side, GLuint property )
{
GLuint attrib = material_attrib(side, property);
if (p->materials & (1<<attrib)) {
struct ureg light_value =
register_param3(p, STATE_LIGHT, light, property);
struct ureg material_value = get_material(p, side, property);
struct ureg tmp = get_temp(p);
emit_op2(p, VP_OPCODE_MUL, tmp, 0, light_value, material_value);
return tmp;
}
else
return register_param4(p, STATE_LIGHTPROD, light, side, property);
}
static struct ureg calculate_light_attenuation( struct tnl_program *p,
GLuint i,
struct ureg VPpli,
struct ureg dist )
{
struct ureg attenuation = register_param3(p, STATE_LIGHT, i,
STATE_ATTENUATION);
struct ureg att = get_temp(p);
/* Calculate spot attenuation:
*/
if (!p->state->unit[i].light_spotcutoff_is_180) {
struct ureg spot_dir = register_param3(p, STATE_LIGHT, i,
STATE_SPOT_DIRECTION);
struct ureg spot = get_temp(p);
struct ureg slt = get_temp(p);
emit_normalize_vec3( p, spot, spot_dir ); /* XXX: precompute! */
emit_op2(p, VP_OPCODE_DP3, spot, 0, negate(VPpli), spot);
emit_op2(p, VP_OPCODE_SLT, slt, 0, swizzle1(spot_dir,W), spot);
emit_op2(p, VP_OPCODE_POW, spot, 0, spot, swizzle1(attenuation, W));
emit_op2(p, VP_OPCODE_MUL, att, 0, slt, spot);
release_temp(p, spot);
release_temp(p, slt);
}
/* Calculate distance attenuation:
*/
if (p->state->unit[i].light_attenuated) {
/* 1/d,d,d,1/d */
emit_op1(p, VP_OPCODE_RCP, dist, WRITEMASK_YZ, dist);
/* 1,d,d*d,1/d */
emit_op2(p, VP_OPCODE_MUL, dist, WRITEMASK_XZ, dist, swizzle1(dist,Y));
/* 1/dist-atten */
emit_op2(p, VP_OPCODE_DP3, dist, 0, attenuation, dist);
if (!p->state->unit[i].light_spotcutoff_is_180) {
/* dist-atten */
emit_op1(p, VP_OPCODE_RCP, dist, 0, dist);
/* spot-atten * dist-atten */
emit_op2(p, VP_OPCODE_MUL, att, 0, dist, att);
} else {
/* dist-atten */
emit_op1(p, VP_OPCODE_RCP, att, 0, dist);
}
}
return att;
}
/* Need to add some addtional parameters to allow lighting in object
* space - STATE_SPOT_DIRECTION and STATE_HALF implicitly assume eye
* space lighting.
*/
static void build_lighting( struct tnl_program *p )
{
const GLboolean twoside = p->state->light_twoside;
const GLboolean separate = p->state->separate_specular;
GLuint nr_lights = 0, count = 0;
struct ureg normal = get_eye_normal(p);
struct ureg lit = get_temp(p);
struct ureg dots = get_temp(p);
struct ureg _col0 = undef, _col1 = undef;
struct ureg _bfc0 = undef, _bfc1 = undef;
GLuint i;
for (i = 0; i < MAX_LIGHTS; i++)
if (p->state->unit[i].light_enabled)
nr_lights++;
set_material_flags(p);
{
struct ureg shininess = get_material(p, 0, STATE_SHININESS);
emit_op1(p, VP_OPCODE_MOV, dots, WRITEMASK_W, swizzle1(shininess,X));
release_temp(p, shininess);
_col0 = make_temp(p, get_scenecolor(p, 0));
if (separate)
_col1 = make_temp(p, get_identity_param(p));
else
_col1 = _col0;
}
if (twoside) {
struct ureg shininess = get_material(p, 1, STATE_SHININESS);
emit_op1(p, VP_OPCODE_MOV, dots, WRITEMASK_Z,
negate(swizzle1(shininess,X)));
release_temp(p, shininess);
_bfc0 = make_temp(p, get_scenecolor(p, 1));
if (separate)
_bfc1 = make_temp(p, get_identity_param(p));
else
_bfc1 = _bfc0;
}
/* If no lights, still need to emit the scenecolor.
*/
{
struct ureg res0 = register_output( p, VERT_RESULT_COL0 );
emit_op1(p, VP_OPCODE_MOV, res0, 0, _col0);
}
if (separate) {
struct ureg res1 = register_output( p, VERT_RESULT_COL1 );
emit_op1(p, VP_OPCODE_MOV, res1, 0, _col1);
}
if (twoside) {
struct ureg res0 = register_output( p, VERT_RESULT_BFC0 );
emit_op1(p, VP_OPCODE_MOV, res0, 0, _bfc0);
}
if (twoside && separate) {
struct ureg res1 = register_output( p, VERT_RESULT_BFC1 );
emit_op1(p, VP_OPCODE_MOV, res1, 0, _bfc1);
}
if (nr_lights == 0) {
release_temps(p);
return;
}
for (i = 0; i < MAX_LIGHTS; i++) {
if (p->state->unit[i].light_enabled) {
struct ureg half = undef;
struct ureg att = undef, VPpli = undef;
count++;
if (p->state->unit[i].light_eyepos3_is_zero) {
/* Can used precomputed constants in this case.
* Attenuation never applies to infinite lights.
*/
VPpli = register_param3(p, STATE_LIGHT, i,
STATE_POSITION_NORMALIZED);
half = register_param3(p, STATE_LIGHT, i, STATE_HALF);
}
else {
struct ureg Ppli = register_param3(p, STATE_LIGHT, i,
STATE_POSITION);
struct ureg V = get_eye_position(p);
struct ureg dist = get_temp(p);
VPpli = get_temp(p);
half = get_temp(p);
/* Calulate VPpli vector
*/
emit_op2(p, VP_OPCODE_SUB, VPpli, 0, Ppli, V);
/* Normalize VPpli. The dist value also used in
* attenuation below.
*/
emit_op2(p, VP_OPCODE_DP3, dist, 0, VPpli, VPpli);
emit_op1(p, VP_OPCODE_RSQ, dist, 0, dist);
emit_op2(p, VP_OPCODE_MUL, VPpli, 0, VPpli, dist);
/* Calculate attenuation:
*/
if (!p->state->unit[i].light_spotcutoff_is_180 ||
p->state->unit[i].light_attenuated) {
att = calculate_light_attenuation(p, i, VPpli, dist);
}
/* Calculate viewer direction, or use infinite viewer:
*/
if (p->state->light_local_viewer) {
struct ureg eye_hat = get_eye_position_normalized(p);
emit_op2(p, VP_OPCODE_SUB, half, 0, VPpli, eye_hat);
}
else {
struct ureg z_dir = swizzle(get_identity_param(p),X,Y,W,Z);
emit_op2(p, VP_OPCODE_ADD, half, 0, VPpli, z_dir);
}
emit_normalize_vec3(p, half, half);
release_temp(p, dist);
}
/* Calculate dot products:
*/
emit_op2(p, VP_OPCODE_DP3, dots, WRITEMASK_X, normal, VPpli);
emit_op2(p, VP_OPCODE_DP3, dots, WRITEMASK_Y, normal, half);
/* Front face lighting:
*/
{
struct ureg ambient = get_lightprod(p, i, 0, STATE_AMBIENT);
struct ureg diffuse = get_lightprod(p, i, 0, STATE_DIFFUSE);
struct ureg specular = get_lightprod(p, i, 0, STATE_SPECULAR);
struct ureg res0, res1;
GLuint mask0, mask1;
emit_op1(p, VP_OPCODE_LIT, lit, 0, dots);
if (!is_undef(att))
emit_op2(p, VP_OPCODE_MUL, lit, 0, lit, att);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -