Merge pull request #9757 from Pokechu22/oob-ind-stage
Skip indirect operation for out of bounds indirect stages
This commit is contained in:
commit
ee4c0ba168
|
@ -810,16 +810,6 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
|
||||||
SampleTexture(out, "float2(tempcoord)", "abg", texmap, stereo, api_type);
|
SampleTexture(out, "float2(tempcoord)", "abg", texmap, stereo, api_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (u32 i = uid_data->genMode_numindstages; i < 4; i++)
|
|
||||||
{
|
|
||||||
// Referencing a stage above the number of ind stages is undefined behavior,
|
|
||||||
// and on console produces a noise pattern (details unknown).
|
|
||||||
// TODO: This behavior is nowhere near that, but it ensures the shader still compiles.
|
|
||||||
if ((uid_data->nIndirectStagesUsed & (1U << i)) != 0)
|
|
||||||
{
|
|
||||||
out.Write("\tint3 iindtex{} = int3(0, 0, 0); // Undefined behavior on console\n", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u32 i = 0; i < numStages; i++)
|
for (u32 i = 0; i < numStages; i++)
|
||||||
{
|
{
|
||||||
|
@ -967,9 +957,17 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
|
||||||
const TevStageIndirect tevind{.hex = stage.tevind};
|
const TevStageIndirect tevind{.hex = stage.tevind};
|
||||||
out.Write("\t// indirect op\n");
|
out.Write("\t// indirect op\n");
|
||||||
|
|
||||||
|
// Quirk: Referencing a stage above the number of ind stages is undefined behavior,
|
||||||
|
// and on console produces a noise pattern (details unknown).
|
||||||
|
// Instead, just skip applying the indirect operation, which is close enough.
|
||||||
|
// We need to do *something*, as there won't be an iindtex variable otherwise.
|
||||||
|
// Viewtiful Joe hits this case (bug 12525).
|
||||||
|
// Wrapping and add to previous still apply in this case (and when the stage is disabled).
|
||||||
|
const bool has_ind_stage = tevind.bt < uid_data->genMode_numindstages;
|
||||||
|
|
||||||
// Perform the indirect op on the incoming regular coordinates
|
// Perform the indirect op on the incoming regular coordinates
|
||||||
// using iindtex{} as the offset coords
|
// using iindtex{} as the offset coords
|
||||||
if (tevind.bs != IndTexBumpAlpha::Off)
|
if (has_ind_stage && tevind.bs != IndTexBumpAlpha::Off)
|
||||||
{
|
{
|
||||||
static constexpr std::array<const char*, 4> tev_ind_alpha_sel{
|
static constexpr std::array<const char*, 4> tev_ind_alpha_sel{
|
||||||
"",
|
"",
|
||||||
|
@ -995,7 +993,7 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
|
||||||
// TODO: Should we reset alphabump to 0 here?
|
// TODO: Should we reset alphabump to 0 here?
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tevind.matrix_index != IndMtxIndex::Off)
|
if (has_ind_stage && tevind.matrix_index != IndMtxIndex::Off)
|
||||||
{
|
{
|
||||||
// format
|
// format
|
||||||
static constexpr std::array<const char*, 4> tev_ind_fmt_mask{
|
static constexpr std::array<const char*, 4> tev_ind_fmt_mask{
|
||||||
|
@ -1123,9 +1121,12 @@ static void WriteStage(ShaderCode& out, const pixel_shader_uid_data* uid_data, i
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
out.Write("\tint2 indtevtrans{} = int2(0, 0);\n", n);
|
out.Write("\tint2 indtevtrans{} = int2(0, 0);\n", n);
|
||||||
|
if (tevind.matrix_index == IndMtxIndex::Off)
|
||||||
|
{
|
||||||
// If matrix_index is Off (0), matrix_id should be Indirect (0)
|
// If matrix_index is Off (0), matrix_id should be Indirect (0)
|
||||||
ASSERT(tevind.matrix_id == IndMtxId::Indirect);
|
ASSERT(tevind.matrix_id == IndMtxId::Indirect);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---------
|
// ---------
|
||||||
// Wrapping
|
// Wrapping
|
||||||
|
|
|
@ -289,10 +289,10 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
std::string_view in_index_name) {
|
std::string_view in_index_name) {
|
||||||
// in_index_name is the indirect stage, not the tev stage
|
// in_index_name is the indirect stage, not the tev stage
|
||||||
// bpmem_iref is packed differently from RAS1_IREF
|
// bpmem_iref is packed differently from RAS1_IREF
|
||||||
|
// This function assumes bpmem_iref is nonzero (i.e. matrix is not off, and the
|
||||||
|
// indirect texture stage is enabled).
|
||||||
out.Write("{{\n"
|
out.Write("{{\n"
|
||||||
" uint iref = bpmem_iref({});\n"
|
" uint iref = bpmem_iref({});\n"
|
||||||
" if ( iref != 0u)\n"
|
|
||||||
" {{\n"
|
|
||||||
" uint texcoord = bitfieldExtract(iref, 0, 3);\n"
|
" uint texcoord = bitfieldExtract(iref, 0, 3);\n"
|
||||||
" uint texmap = bitfieldExtract(iref, 8, 3);\n"
|
" uint texmap = bitfieldExtract(iref, 8, 3);\n"
|
||||||
" int2 fixedPoint_uv = getTexCoord(texcoord);\n"
|
" int2 fixedPoint_uv = getTexCoord(texcoord);\n"
|
||||||
|
@ -303,20 +303,10 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
" fixedPoint_uv = fixedPoint_uv >> " I_INDTEXSCALE "[{} >> 1].zw;\n"
|
" fixedPoint_uv = fixedPoint_uv >> " I_INDTEXSCALE "[{} >> 1].zw;\n"
|
||||||
"\n"
|
"\n"
|
||||||
" {} = sampleTexture(texmap, float3(float2(fixedPoint_uv) * " I_TEXDIMS
|
" {} = sampleTexture(texmap, float3(float2(fixedPoint_uv) * " I_TEXDIMS
|
||||||
"[texmap].xy, {})).abg;\n",
|
"[texmap].xy, {})).abg;\n"
|
||||||
|
"}}",
|
||||||
in_index_name, in_index_name, in_index_name, in_index_name, out_var_name,
|
in_index_name, in_index_name, in_index_name, in_index_name, out_var_name,
|
||||||
stereo ? "float(layer)" : "0.0");
|
stereo ? "float(layer)" : "0.0");
|
||||||
// There is always a bit set in bpmem_iref if the data is valid (matrix is not off, and the
|
|
||||||
// indirect texture stage is enabled). If the matrix is off, the result doesn't matter; if the
|
|
||||||
// indirect texture stage is disabled, the result is undefined (and produces a glitchy pattern
|
|
||||||
// on hardware, different from this).
|
|
||||||
out.Write(" }}\n"
|
|
||||||
" else\n"
|
|
||||||
" {{\n"
|
|
||||||
" {} = int3(0, 0, 0);\n"
|
|
||||||
" }}\n"
|
|
||||||
"}}\n",
|
|
||||||
out_var_name);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ======================
|
// ======================
|
||||||
|
@ -814,7 +804,16 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
BitfieldExtract<&TevStageIndirect::matrix_index>("tevind"));
|
BitfieldExtract<&TevStageIndirect::matrix_index>("tevind"));
|
||||||
out.Write(" uint matrix_id = {};\n",
|
out.Write(" uint matrix_id = {};\n",
|
||||||
BitfieldExtract<&TevStageIndirect::matrix_id>("tevind"));
|
BitfieldExtract<&TevStageIndirect::matrix_id>("tevind"));
|
||||||
out.Write("\n");
|
out.Write(" int2 indtevtrans = int2(0, 0);\n"
|
||||||
|
"\n");
|
||||||
|
// There is always a bit set in bpmem_iref if the data is valid (matrix is not off, and the
|
||||||
|
// indirect texture stage is enabled). If the matrix is off, the result doesn't matter; if the
|
||||||
|
// indirect texture stage is disabled, the result is undefined (and produces a glitchy pattern
|
||||||
|
// on hardware, different from this).
|
||||||
|
// For the undefined case, we just skip applying the indirect operation, which is close enough.
|
||||||
|
// Viewtiful Joe hits the undefined case (bug 12525).
|
||||||
|
// Wrapping and add to previous still apply in this case (and when the stage is disabled).
|
||||||
|
out.Write(" if (bpmem_iref(bt) != 0u) {{");
|
||||||
out.Write(" int3 indcoord;\n");
|
out.Write(" int3 indcoord;\n");
|
||||||
LookupIndirectTexture("indcoord", "bt");
|
LookupIndirectTexture("indcoord", "bt");
|
||||||
out.Write(" if (bs != 0u)\n"
|
out.Write(" if (bs != 0u)\n"
|
||||||
|
@ -852,7 +851,6 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
" }}\n"
|
" }}\n"
|
||||||
"\n"
|
"\n"
|
||||||
" // Matrix multiply\n"
|
" // Matrix multiply\n"
|
||||||
" int2 indtevtrans = int2(0, 0);\n"
|
|
||||||
" if (matrix_index != 0u)\n"
|
" if (matrix_index != 0u)\n"
|
||||||
" {{\n"
|
" {{\n"
|
||||||
" uint mtxidx = 2u * (matrix_index - 1u);\n"
|
" uint mtxidx = 2u * (matrix_index - 1u);\n"
|
||||||
|
@ -877,6 +875,7 @@ ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
|
||||||
" else\n"
|
" else\n"
|
||||||
" indtevtrans = indtevtrans << ((-shift) & 31);\n"
|
" indtevtrans = indtevtrans << ((-shift) & 31);\n"
|
||||||
" }}\n"
|
" }}\n"
|
||||||
|
" }}\n"
|
||||||
"\n"
|
"\n"
|
||||||
" // Wrapping\n"
|
" // Wrapping\n"
|
||||||
" uint sw = {};\n",
|
" uint sw = {};\n",
|
||||||
|
|
Loading…
Reference in New Issue