📄 t_vp_build.c
字号:
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, 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, OPCODE_DP4, dest, WRITEMASK_X, src, mat[0]); emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Y, src, mat[1]); emit_op2(p, OPCODE_DP4, dest, WRITEMASK_Z, src, mat[2]); emit_op2(p, 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, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]); emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp); emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp); emit_op3(p, 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, OPCODE_DP3, dest, WRITEMASK_X, src, mat[0]); emit_op2(p, OPCODE_DP3, dest, WRITEMASK_Y, src, mat[1]); emit_op2(p, 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, OPCODE_DP3, tmp, 0, src, src); emit_op1(p, OPCODE_RSQ, tmp, 0, tmp); emit_op2(p, 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, 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_param5( p, STATE_MODELVIEW_MATRIX, 0, 0, 3, 0, modelview ); emit_matrix_transform_vec4(p, p->eye_position, modelview, pos); } else { register_matrix_param5( p, STATE_MODELVIEW_MATRIX, 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_param5( p, STATE_MODELVIEW_MATRIX, 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, OPCODE_MUL, p->eye_normal, 0, p->eye_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_param5( p, STATE_MVP_MATRIX, 0, 0, 3, 0, mvp ); emit_matrix_transform_vec4( p, hpos, mvp, pos ); } else { register_matrix_param5( p, STATE_MVP_MATRIX, 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);}/* 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; 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, 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, 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_norm = register_param3(p, STATE_INTERNAL, STATE_SPOT_DIR_NORMALIZED, i); struct ureg spot = get_temp(p); struct ureg slt = get_temp(p); emit_op2(p, OPCODE_DP3, spot, 0, negate(VPpli), spot_dir_norm); emit_op2(p, OPCODE_SLT, slt, 0, swizzle1(spot_dir_norm,W), spot); emit_op2(p, OPCODE_POW, spot, 0, spot, swizzle1(attenuation, W)); emit_op2(p, 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, OPCODE_RCP, dist, WRITEMASK_YZ, dist); /* 1,d,d*d,1/d */ emit_op2(p, OPCODE_MUL, dist, WRITEMASK_XZ, dist, swizzle1(dist,Y)); /* 1/dist-atten */ emit_op2(p, OPCODE_DP3, dist, 0, attenuation, dist); if (!p->state->unit[i].light_spotcutoff_is_180) { /* dist-atten */ emit_op1(p, OPCODE_RCP, dist, 0, dist); /* spot-atten * dist-atten */ emit_op2(p, OPCODE_MUL, att, 0, dist, att); } else { /* dist-atten */ emit_op1(p, 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_VECTOR 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, OPCODE_MOV, dots, WRITEMASK_W, swizzle1(shininess,X)); _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, OPCODE_MOV, dots, WRITEMASK_Z, negate(swizzle1(shininess,X))); _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, OPCODE_MOV, res0, 0, _col0); } if (separate) { struct ureg res1 = register_output( p, VERT_RESULT_COL1 ); emit_op1(p, OPCODE_MOV, res1, 0, _col1); } if (twoside) { struct ureg res0 = register_output( p, VERT_RESULT_BFC0 ); emit_op1(p, OPCODE_MOV, res0, 0, _bfc0); } if (twoside && separate) { struct ureg res1 = register_output( p, VERT_RESULT_BFC1 ); emit_op1(p, 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); if (p->state->light_local_viewer) { struct ureg eye_hat = get_eye_position_normalized(p); half = get_temp(p); emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); emit_normalize_vec3(p, half, half); } else { half = register_param3(p, STATE_LIGHT, i, STATE_HALF_VECTOR); } } 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); struct ureg tmpPpli = get_temp(p); VPpli = get_temp(p); /* In homogeneous object coordinates */ emit_op1(p, OPCODE_RCP, dist, 0, swizzle1(Ppli, W)); emit_op2(p, OPCODE_MUL, tmpPpli, 0, Ppli, dist); /* Calculate VPpli vector */ emit_op2(p, OPCODE_SUB, VPpli, 0, tmpPpli, V); /* we're done with tmpPpli now */ release_temp(p, tmpPpli); /* Normalize VPpli. The dist value also used in * attenuation below. */ emit_op2(p, OPCODE_DP3, dist, 0, VPpli, VPpli); emit_op1(p, OPCODE_RSQ, dist, 0, dist); emit_op2(p, 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); } /* We're done with dist now */ release_temp(p, dist); /* Calculate viewer direction, or use infinite viewer: */ half = get_temp(p); if (p->state->light_local_viewer) { struct ureg eye_hat = get_eye_position_normalized(p); emit_op2(p, OPCODE_SUB, half, 0, VPpli, eye_hat); } else { struct ureg z_dir = swizzle(get_identity_param(p),X,Y,W,Z); emit_op2(p, OPCODE_ADD, half, 0, VPpli, z_dir); } emit_normalize_vec3(p, half, half); } /* Calculate dot products: */ emit_op2(p, OPCODE_DP3, dots, WRITEMASK_X, normal, VPpli); emit_op2(p, OPCODE_DP3, dots, WRITEMASK_Y, normal, half); /* we're done with VPpli and half now, so free them as to not drive up our temp usage unnecessary */ release_temp(p, VPpli); release_temp(p, 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, OPCODE_LIT, lit, 0, dots); 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_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, OPCODE_MAD, _col0, 0, swizzle1(lit,X), ambient, _col0); emit_op3(p, OPCODE_MAD, res0, mask0, swizzle1(lit,Y), diffuse, _col0); emit_op3(p, 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -