diff --git a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c index e496f83e88..efb2dd8ff0 100644 --- a/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c +++ b/hw/xbox/nv2a/pgraph/glsl/vsh-prog.c @@ -209,6 +209,7 @@ static bool ilu_force_scalar[] = { false, }; +#define OUTPUT_REG_POS 0 #define OUTPUT_REG_FOG 5 static const char* out_reg_name[] = { @@ -304,7 +305,6 @@ static MString *decode_opcode_input(const uint32_t *shader_token, MString *ret_str = mstring_new(); - if (vsh_get_field(shader_token, neg_field) > 0) { mstring_append_fmt(ret_str, "-"); } @@ -354,6 +354,7 @@ static MString *decode_opcode(const uint32_t *shader_token, MString *ret = mstring_new(); int reg_num = vsh_get_field(shader_token, FLD_OUT_R); bool use_temp_var = false; + bool use_temp_opos = false; /* Test for paired opcodes (in other words : Are both <> NOP?) */ if (out_mux == OMUX_MAC @@ -369,6 +370,8 @@ static MString *decode_opcode(const uint32_t *shader_token, reg_num = 1; } + const char *write_mask_str = NULL; + /* See if we must add a muxed opcode too: */ if (vsh_get_field(shader_token, FLD_OUT_MUX) == out_mux /* Only if it's not masked away: */ @@ -386,12 +389,18 @@ static MString *decode_opcode(const uint32_t *shader_token, shader_token, FLD_OUT_ADDRESS))); } else { int out_reg = vsh_get_field(shader_token, FLD_OUT_ADDRESS) & 0xF; - mstring_append(ret,out_reg_name[out_reg]); + if (out_reg == OUTPUT_REG_POS && (use_temp_var || mask)) { + use_temp_opos = true; + mstring_append(ret, "_temp_r12"); + } else { + mstring_append(ret, out_reg_name[out_reg]); + } write_fog_register = out_reg == OUTPUT_REG_FOG; } int write_mask = vsh_get_field(shader_token, FLD_OUT_O_MASK); - const char *write_mask_str = write_fog_register ? fog_mask_str[write_mask] : mask_str[write_mask]; + write_mask_str = write_fog_register ? fog_mask_str[write_mask] + : mask_str[write_mask]; mstring_append(ret, write_mask_str); mstring_append(ret, inputs); mstring_append(ret, ");\n"); @@ -428,6 +437,16 @@ static MString *decode_opcode(const uint32_t *shader_token, } } + if (use_temp_opos) { + if (!*suffix) { + *suffix = mstring_new(); + } + assert(write_mask_str && "Temp oPos flagged without a mask"); + const char *write_mask_components = write_mask_str + 1; + mstring_append_fmt(*suffix, " oPos.%s = _temp_r12.%s;\n", + write_mask_components, write_mask_components); + } + return ret; } @@ -451,7 +470,7 @@ static MString *decode_token(const uint32_t *shader_token) (vsh_get_field(shader_token, FLD_C_R_HIGH) << 2) | vsh_get_field(shader_token, FLD_C_R_LOW)); - MString *mac_suffix = NULL; + MString *suffix = NULL; if (mac != MAC_NOP) { MString *inputs_mac = mstring_new(); if (mac_opcode_params[mac].A) { @@ -485,7 +504,7 @@ static MString *decode_token(const uint32_t *shader_token) vsh_get_field(shader_token, FLD_OUT_MAC_MASK), mac_opcode[mac], mstring_get_str(inputs_mac), - &mac_suffix); + &suffix); mstring_unref(inputs_mac); } else { ret = mstring_new(); @@ -502,7 +521,7 @@ static MString *decode_token(const uint32_t *shader_token) vsh_get_field(shader_token, FLD_OUT_ILU_MASK), ilu_opcode[ilu], mstring_get_str(inputs_c), - NULL); + &suffix); mstring_append(ret, mstring_get_str(ilu_op)); @@ -512,9 +531,9 @@ static MString *decode_token(const uint32_t *shader_token) mstring_unref(input_c); - if (mac_suffix) { - mstring_append(ret, mstring_get_str(mac_suffix)); - mstring_unref(mac_suffix); + if (suffix) { + mstring_append(ret, mstring_get_str(suffix)); + mstring_unref(suffix); } return ret; @@ -543,6 +562,11 @@ static const char* vsh_header = "vec4 _temp_vec;\n" "int _temp_addr;\n" + /* Used to emulate concurrency of multi-output / paired instructions that + * write to oPos and read from R12 + */ + "vec4 _temp_r12;\n" + /* See: * http://msdn.microsoft.com/en-us/library/windows/desktop/bb174703%28v=vs.85%29.aspx * https://www.opengl.org/registry/specs/NV/vertex_program1_1.txt