rsx/fp: Fragment program overhaul

- Separate TXB from TXL: They are completely different!
- Properly perform TMU emulation in the fragment shader. Implemens SRGB conversion and alphakill at the moment
- Properly perform ROP emulation in the fragment shader. Implements FRAMEBUFFER_SRGB. While support on the chip looks to be incomplete (and wierd), it does work
- Document some more bits in SHADER_CONTROL register
This commit is contained in:
kd-11 2018-03-23 14:47:03 +03:00
parent c6a2525c9b
commit 9fc1740608
12 changed files with 213 additions and 220 deletions

View File

@ -711,6 +711,23 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode)
}
return false;
case RSX_FP_OPCODE_TXB:
switch (m_prog.get_texture_dimension(dst.tex_num))
{
case rsx::texture_dimension_extended::texture_dimension_1d:
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_BIAS));
return true;
case rsx::texture_dimension_extended::texture_dimension_2d:
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_BIAS));
m_2d_sampled_textures |= (1 << dst.tex_num);
return true;
case rsx::texture_dimension_extended::texture_dimension_cubemap:
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_BIAS));
return true;
case rsx::texture_dimension_extended::texture_dimension_3d:
SetDst(getFunction(FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_BIAS));
return true;
}
return false;
case RSX_FP_OPCODE_TXL:
switch (m_prog.get_texture_dimension(dst.tex_num))
{

View File

@ -313,7 +313,45 @@ namespace glsl
OS << "}\n\n";
}
static void insert_glsl_legacy_function(std::ostream& OS, glsl::program_domain domain, bool require_lit_emulation, bool require_depth_conversion = false, bool require_wpos = false)
static void insert_rop(std::ostream& OS, bool _32_bit_exports)
{
const std::string reg0 = _32_bit_exports ? "r0" : "h0";
const std::string reg1 = _32_bit_exports ? "r2" : "h4";
const std::string reg2 = _32_bit_exports ? "r3" : "h6";
const std::string reg3 = _32_bit_exports ? "r4" : "h8";
//TODO: Implement all ROP options like CSAA and ALPHA_TO_ONE here
OS << " if ((rop_control & 0xFF) != 0)\n";
OS << " {\n";
OS << " bool alpha_test = (rop_control & 0x11) > 0;\n";
OS << " uint alpha_func = ((rop_control >> 16) & 0x7);\n";
OS << " bool srgb_convert = (rop_control & 0x2) > 0;\n\n";
OS << " if (alpha_test && !comparison_passes(" << reg0 << ".a, alpha_ref, alpha_func))\n";
OS << " {\n";
OS << " discard;\n";
OS << " }\n";
if (!_32_bit_exports)
{
//Tested using NPUB90375; some shaders (32-bit output only?) do not obey srgb flags
OS << " else if (srgb_convert)\n";
OS << " {\n";
OS << " " << reg0 << ".rgb = linear_to_srgb(" << reg0 << ").rgb;\n";
OS << " " << reg1 << ".rgb = linear_to_srgb(" << reg1 << ").rgb;\n";
OS << " " << reg2 << ".rgb = linear_to_srgb(" << reg2 << ").rgb;\n";
OS << " " << reg3 << ".rgb = linear_to_srgb(" << reg3 << ").rgb;\n";
OS << " }\n";
}
OS << " }\n\n";
OS << " ocol0 = " << reg0 << ";\n";
OS << " ocol1 = " << reg1 << ";\n";
OS << " ocol2 = " << reg2 << ";\n";
OS << " ocol3 = " << reg3 << ";\n\n";
}
static void insert_glsl_legacy_function(std::ostream& OS, glsl::program_domain domain, bool require_lit_emulation, bool require_depth_conversion = false, bool require_wpos = false, bool require_texture_ops = true)
{
if (require_lit_emulation)
{
@ -394,6 +432,67 @@ namespace glsl
OS << "}\n\n";
}
if (require_texture_ops)
{
OS << "vec4 linear_to_srgb(vec4 cl)\n";
OS << "{\n";
OS << " vec4 low = cl * 12.92;\n";
OS << " vec4 high = 1.055 * pow(cl, vec4(1. / 2.4)) - 0.055;\n";
OS << " bvec4 select = lessThan(cl, vec4(0.0031308));\n";
OS << " return clamp(mix(high, low, select), 0., 1.);\n";
OS << "}\n\n";
OS << "float srgb_to_linear(float cs)\n";
OS << "{\n";
OS << " if (cs <= 0.04045) return cs / 12.92;\n";
OS << " return pow((cs + 0.055) / 1.055, 2.4);\n";
OS << "}\n\n";
//TODO: Move all the texture read control operations here
OS << "vec4 process_texel(vec4 rgba, uint control_bits)\n";
OS << "{\n";
OS << " if (control_bits == 0) return rgba;\n\n";
OS << " if ((control_bits & 0x10) > 0)\n";
OS << " {\n";
OS << " //Alphakill\n";
OS << " if (!comparison_passes(rgba.a, 0., (control_bits >> 5) & 0x7))\n";
OS << " {\n";
OS << " discard;\n";
OS << " return rgba;\n";
OS << " }\n";
OS << " }\n\n";
OS << " //TODO: Verify gamma control bit ordering, looks to be 0x7 for rgb, 0xF for rgba\n";
OS << " uint srgb_in = (control_bits & 0xF);\n";
OS << " if ((srgb_in & 0x1) > 0) rgba.r = srgb_to_linear(rgba.r);\n";
OS << " if ((srgb_in & 0x2) > 0) rgba.g = srgb_to_linear(rgba.g);\n";
OS << " if ((srgb_in & 0x4) > 0) rgba.b = srgb_to_linear(rgba.b);\n";
OS << " if ((srgb_in & 0x8) > 0) rgba.a = srgb_to_linear(rgba.a);\n";
OS << " return rgba;\n";
OS << "}\n\n";
OS << "#define TEX1D(index, tex, coord1) process_texel(texture(tex, coord1 * texture_parameters[index].x), uint(texture_parameters[index].w))\n";
OS << "#define TEX1D_BIAS(index, tex, coord1, bias) process_texel(texture(tex, coord1 * texture_parameters[index].x, bias), uint(texture_parameters[index].w))\n";
OS << "#define TEX1D_LOD(index, tex, coord1, lod) process_texel(textureLod(tex, coord1 * texture_parameters[index].x, lod), uint(texture_parameters[index].w))\n";
OS << "#define TEX1D_GRAD(index, tex, coord1, dpdx, dpdy) process_texel(textureGrad(tex, coord1 * texture_parameters[index].x, dpdx, dpdy), uint(texture_parameters[index].w))\n";
OS << "#define TEX1D_PROJ(index, tex, coord2) process_texel(textureGrad(tex, coord2 * vec2(texture_parameters[index].x, 1.)), uint(texture_parameters[index].w))\n";
OS << "#define TEX2D(index, tex, coord2) process_texel(texture(tex, coord2 * texture_parameters[index].xy), uint(texture_parameters[index].w))\n";
OS << "#define TEX2D_BIAS(index, tex, coord2, bias) process_texel(texture(tex, coord2 * texture_parameters[index].xy, bias), uint(texture_parameters[index].w))\n";
OS << "#define TEX2D_LOD(index, tex, coord2, lod) process_texel(textureLod(tex, coord2 * texture_parameters[index].xy, lod), uint(texture_parameters[index].w))\n";
OS << "#define TEX2D_GRAD(index, tex, coord2, dpdx, dpdy) process_texel(textureGrad(tex, coord2 * texture_parameters[index].xy, dpdx, dpdy), uint(texture_parameters[index].w))\n";
OS << "#define TEX2D_PROJ(index, tex, coord4) process_texel(textureProj(tex, coord4 * vec4(texture_parameters[index].xy, 1., 1.)), uint(texture_parameters[index].w))\n";
OS << "#define TEX2D_DEPTH_RGBA8(index, tex, coord2) process_texel(texture2DReconstruct(tex, coord2 * texture_parameters[index].xy, texture_parameters[index].z), uint(texture_parameters[index].w))\n";
OS << "#define TEX2D_SHADOW(index, tex, coord3) texture(tex, coord3 * vec3(texture_parameters[index].xy, 1.))\n";
OS << "#define TEX2D_SHADOWPROJ(index, tex, coord4) textureProj(tex, coord4 * vec4(texture_parameters[index].xy, 1., 1.))\n";
OS << "#define TEX3D(index, tex, coord3) process_texel(texture(tex, coord3), uint(texture_parameters[index].w))\n";
OS << "#define TEX3D_BIAS(index, tex, coord3, bias) process_texel(texture(tex, coord3, bias), uint(texture_parameters[index].w))\n";
OS << "#define TEX3D_LOD(index, tex, coord3, lod) process_texel(textureLod(tex, coord3, lod), uint(texture_parameters[index].w))\n";
OS << "#define TEX3D_GRAD(index, tex, coord3, dpdx, dpdy) process_texel(textureGrad(tex, coord3, dpdx, dpdy), uint(texture_parameters[index].w))\n";
OS << "#define TEX3D_PROJ(index, tex, coord4) process_texel(textureProj(tex, coord4), uint(texture_parameters[index].w))\n\n";
}
if (require_wpos)
{
OS << "vec4 get_wpos()\n";
@ -434,41 +533,49 @@ namespace glsl
case FUNCTION::FUNCTION_REFL:
return "vec4($0 - 2.0 * (dot($0, $1)) * $1)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D:
return "texture($t, $0.x)";
return "TEX1D($_i, $t, $0.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_BIAS:
return "TEX1D_BIAS($_i, $t, $0.xy)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ:
return "textureProj($t, $0.x, $1.x)"; // Note: $1.x is bias
return "TEX1D_PROJ($_i, $t, $0.xy)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
return "textureLod($t, $0.x, $1.x)";
return "TEX1D_LOD($_i, $t, $0.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD:
return "textureGrad($t, $0.x, $1.x, $2.x)";
return "TEX1D_GRAD($_i, $t, $0.x, $1.x, $2.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D:
return "texture($t, $0.xy * texture_parameters[$_i].xy)";
return "TEX2D($_i, $t, $0.xy)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_BIAS:
return "TEX2D_BIAS($_i, $t, $0.xy, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
return "textureProj($t, $0 * vec4(texture_parameters[$_i].xy, 1., 1.), $1.x)"; // Note: $1.x is bias
return "TEX2D_PROJ($_i, $t, $0)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
return "textureLod($t, $0.xy * texture_parameters[$_i].xy, $1.x)";
return "TEX2D_LOD($_i, $t, $0.xy, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD:
return "textureGrad($t, $0.xy * texture_parameters[$_i].xy , $1.xy, $2.xy)";
return "TEX2D_GRAD($_i, $t, $0.xy, $1.xy, $2.xy)";
case FUNCTION::FUNCTION_TEXTURE_SHADOW2D:
return "texture($t, $0.xyz * vec3(texture_parameters[$_i].xy, 1.))";
return "TEX2D_SHADOW($_i, $t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SHADOW2D_PROJ:
return "textureProj($t, $0 * vec4(texture_parameters[$_i].xy, 1., 1.), $1.x)"; // Note: $1.x is bias
return "TEX2D_SHADOWPROJ($_i, $t, $0)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE:
return "texture($t, $0.xyz)";
return "TEX3D($_i, $t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_BIAS:
return "TEX3D_BIAS($_i, $t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
return "texture($t, ($0.xyz / $0.w))";
return "TEX3D($_i, $t, ($0.xyz / $0.w))";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
return "textureLod($t, $0.xyz, $1.x)";
return "TEX3D_LOD($_i, $t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD:
return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
return "TEX3D_GRAD($_i, $t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D:
return "texture($t, $0.xyz)";
return "TEX3D($_i, $t, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_BIAS:
return "TEX3D_BIAS($_i, $t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ:
return "textureProj($t, $0.xyzw, $1.x)"; // Note: $1.x is bias
return "TEX3D_PROJ($_i, $t, $0)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD:
return "textureLod($t, $0.xyz, $1.x)";
return "TEX3D_LOD($_i, $t, $0.xyz, $1.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_GRAD:
return "textureGrad($t, $0.xyz, $1.xyz, $2.xyz)";
return "TEX3D_GRAD($_i, $t, $0.xyz, $1.xyz, $2.xyz)";
case FUNCTION::FUNCTION_DFDX:
return "dFdx($0)";
case FUNCTION::FUNCTION_DFDY:
@ -476,7 +583,7 @@ namespace glsl
case FUNCTION::FUNCTION_VERTEX_TEXTURE_FETCH2D:
return "textureLod($t, $0.xy, 0)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_DEPTH_RGBA:
return "texture2DReconstruct($t, $0.xy * texture_parameters[$_i].xy, texture_parameters[$_i].z)";
return "TEX2D_DEPTH_RGBA8($_i, $t, $0.xy)";
}
}
}

View File

@ -18,20 +18,24 @@ enum class FUNCTION {
FUNCTION_DFDY,
FUNCTION_REFL,
FUNCTION_TEXTURE_SAMPLE1D,
FUNCTION_TEXTURE_SAMPLE1D_BIAS,
FUNCTION_TEXTURE_SAMPLE1D_PROJ,
FUNCTION_TEXTURE_SAMPLE1D_LOD,
FUNCTION_TEXTURE_SAMPLE1D_GRAD,
FUNCTION_TEXTURE_SAMPLE2D,
FUNCTION_TEXTURE_SAMPLE2D_BIAS,
FUNCTION_TEXTURE_SAMPLE2D_PROJ,
FUNCTION_TEXTURE_SAMPLE2D_LOD,
FUNCTION_TEXTURE_SAMPLE2D_GRAD,
FUNCTION_TEXTURE_SHADOW2D,
FUNCTION_TEXTURE_SHADOW2D_PROJ,
FUNCTION_TEXTURE_SAMPLECUBE,
FUNCTION_TEXTURE_SAMPLECUBE_BIAS,
FUNCTION_TEXTURE_SAMPLECUBE_PROJ,
FUNCTION_TEXTURE_SAMPLECUBE_LOD,
FUNCTION_TEXTURE_SAMPLECUBE_GRAD,
FUNCTION_TEXTURE_SAMPLE3D,
FUNCTION_TEXTURE_SAMPLE3D_BIAS,
FUNCTION_TEXTURE_SAMPLE3D_PROJ,
FUNCTION_TEXTURE_SAMPLE3D_LOD,
FUNCTION_TEXTURE_SAMPLE3D_GRAD,

View File

@ -1693,10 +1693,10 @@ namespace rsx
//Invalidate with writing=false, discard=false, rebuild=false, native_flush=true
invalidate_range_impl_base(texaddr, tex_size, false, false, false, true, std::forward<Args>(extras)...);
const auto colorspace = tex.gamma() ? rsx::texture_colorspace::srgb_nonlinear : rsx::texture_colorspace::rgb_linear;
//NOTE: SRGB correction is to be handled in the fragment shader; upload as linear RGB
m_texture_memory_in_use += (tex_pitch * tex_height);
return{ upload_image_from_cpu(cmd, texaddr, tex_width, tex_height, depth, tex.get_exact_mipmap_count(), tex_pitch, format,
texture_upload_context::shader_read, subresources_layout, extended_dimension, colorspace, is_swizzled, remap_vector)->get_raw_view(),
texture_upload_context::shader_read, subresources_layout, extended_dimension, rsx::texture_colorspace::rgb_linear, is_swizzled, remap_vector)->get_raw_view(),
texture_upload_context::shader_read, is_depth_format, scale_x, scale_y, extended_dimension };
}

View File

@ -48,6 +48,7 @@ std::string getFunctionImp(FUNCTION f)
return "$t.Sample($tsampler, $0.x)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_PROJ:
return "$t.Sample($tsampler, ($0.x / $0.w))";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_BIAS:
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_LOD:
return "$t.SampleLevel($tsampler, $0.x, $1)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE1D_GRAD:
@ -58,6 +59,7 @@ std::string getFunctionImp(FUNCTION f)
return "$t.Sample($tsampler, $0.xy * $t_scale)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_PROJ:
return "$t.Sample($tsampler, ($0.xy / $0.w) * $t_scale)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_BIAS:
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_LOD:
return "$t.SampleLevel($tsampler, $0.xy * $t_scale, $1)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE2D_GRAD:
@ -66,6 +68,7 @@ std::string getFunctionImp(FUNCTION f)
return "$t.Sample($tsampler, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_PROJ:
return "$t.Sample($tsampler, ($0.xyz / $0.w))";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_BIAS:
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_LOD:
return "$t.SampleLevel($tsampler, $0.xyz, $1)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLECUBE_GRAD:
@ -74,6 +77,7 @@ std::string getFunctionImp(FUNCTION f)
return "$t.Sample($tsampler, $0.xyz)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_PROJ:
return "$t.Sample($tsampler, ($0.xyz / $0.w))";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_BIAS:
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_LOD:
return "$t.SampleLevel($tsampler, $0.xyz, $1)";
case FUNCTION::FUNCTION_TEXTURE_SAMPLE3D_GRAD:

View File

@ -350,7 +350,7 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
}
}
OS << " if (alpha_test != 0 && !comparison_passes(Out." << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n";
OS << " if ((alpha_test & 0x11) != 0 && !comparison_passes(Out." << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n";
}
OS << " return Out;\n";

View File

@ -150,9 +150,9 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
// Fragment state parameters
OS << " float fog_param0;\n";
OS << " float fog_param1;\n";
OS << " uint alpha_test;\n";
OS << " uint rop_control;\n";
OS << " float alpha_ref;\n";
OS << " uint alpha_func;\n";
OS << " uint reserved;\n";
OS << " uint fog_mode;\n";
OS << " float wpos_scale;\n";
OS << " float wpos_bias;\n";
@ -160,38 +160,6 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
OS << "};\n";
}
namespace
{
void insert_texture_scale(std::stringstream & OS, const RSXFragmentProgram& prog, int index)
{
std::string vec_type = "vec2";
switch (prog.get_texture_dimension(index))
{
case rsx::texture_dimension_extended::texture_dimension_1d: vec_type = "float"; break;
case rsx::texture_dimension_extended::texture_dimension_2d: vec_type = "vec2"; break;
case rsx::texture_dimension_extended::texture_dimension_3d:
case rsx::texture_dimension_extended::texture_dimension_cubemap: vec_type = "vec3";
}
}
std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index)
{
std::string tex_name = "tex" + std::to_string(index);
std::string coord_name = "(tc" + std::to_string(index) + " * texture_parameters[" + std::to_string(index) + "])";
switch (prog.get_texture_dimension(index))
{
case rsx::texture_dimension_extended::texture_dimension_1d: return "texture(" + tex_name + ", " + coord_name + ".x)";
case rsx::texture_dimension_extended::texture_dimension_2d: return "texture(" + tex_name + ", " + coord_name + ".xy)";
case rsx::texture_dimension_extended::texture_dimension_3d:
case rsx::texture_dimension_extended::texture_dimension_cubemap: return "texture(" + tex_name + ", " + coord_name + ".xyz)";
}
fmt::throw_exception("Invalid texture dimension %d" HERE, (u32)prog.get_texture_dimension(index));
}
}
void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
{
glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program, properties.has_lit_op, m_prog.redirected_textures != 0, properties.has_wpos_input);
@ -254,20 +222,6 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
if (properties.has_wpos_input)
OS << " vec4 wpos = get_wpos();\n";
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
{
if (PT.type != "sampler2D")
continue;
for (const ParamItem& PI : PT.items)
{
std::string samplerType = PT.type;
int index = atoi(&PI.name.data()[3]);
insert_texture_scale(OS, m_prog, index);
}
}
bool two_sided_enabled = m_prog.front_back_color_enabled && (m_prog.back_color_diffuse_output || m_prog.back_color_specular_output);
for (const ParamType& PT : m_parr.params[PF_PARAM_IN])
@ -322,32 +276,12 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
{
const std::pair<std::string, std::string> table[] =
{
{ "ocol0", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r0" : "h0" },
{ "ocol1", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r2" : "h4" },
{ "ocol2", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r3" : "h6" },
{ "ocol3", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r4" : "h8" },
};
const std::set<std::string> output_values =
{
"r0", "r1", "r2", "r3", "r4",
"h0", "h2", "h4", "h6", "h8"
};
std::string first_output_name = "";
std::string color_output_block = "";
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
{
if (m_parr.HasParam(PF_PARAM_NONE, "vec4", table[i].second))
{
color_output_block += " " + table[i].first + " = " + table[i].second + ";\n";
if (first_output_name.empty()) first_output_name = table[i].second;
}
}
OS << "}\n\n";
OS << "void main()\n";
@ -368,44 +302,7 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
OS << "\n" << " fs_main(" + parameters + ");\n\n";
if (!first_output_name.empty())
{
auto make_comparison_test = [](rsx::comparison_function compare_func, const std::string &test, const std::string &a, const std::string &b) -> std::string
{
std::string compare;
switch (compare_func)
{
case rsx::comparison_function::equal: compare = " == "; break;
case rsx::comparison_function::not_equal: compare = " != "; break;
case rsx::comparison_function::less_or_equal: compare = " <= "; break;
case rsx::comparison_function::less: compare = " < "; break;
case rsx::comparison_function::greater: compare = " > "; break;
case rsx::comparison_function::greater_or_equal: compare = " >= "; break;
default:
return "";
}
return " if (" + test + "!(" + a + compare + b + ")) discard;\n";
};
for (u8 index = 0; index < 16; ++index)
{
if (m_prog.textures_alpha_kill[index])
{
const std::string texture_name = "tex" + std::to_string(index);
if (m_parr.HasParamTypeless(PF_PARAM_UNIFORM, texture_name))
{
std::string fetch_texture = insert_texture_fetch(m_prog, index) + ".a";
OS << make_comparison_test((rsx::comparison_function)m_prog.textures_zfunc[index], "", "0", fetch_texture);
}
}
}
OS << " if (alpha_test != 0 && !comparison_passes(" << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n\n";
}
//Append the color output assignments
OS << color_output_block;
glsl::insert_rop(OS, m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS);
if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
{

View File

@ -956,9 +956,9 @@ namespace rsx
//TODO: Properly support alpha-to-coverage and alpha-to-one behavior in shaders
auto fragment_alpha_func = rsx::method_registers.alpha_func();
auto alpha_ref = rsx::method_registers.alpha_ref() / 255.f;
auto is_alpha_tested = (u32)rsx::method_registers.alpha_test_enabled();
auto rop_control = (u32)rsx::method_registers.alpha_test_enabled();
if (rsx::method_registers.msaa_alpha_to_coverage_enabled() && !is_alpha_tested)
if (rsx::method_registers.msaa_alpha_to_coverage_enabled() && !rop_control)
{
if (rsx::method_registers.msaa_enabled() &&
rsx::method_registers.surface_antialias() != rsx::surface_antialiasing::center_1_sample)
@ -968,7 +968,7 @@ namespace rsx
//simulated using combined alpha blend and alpha test
fragment_alpha_func = rsx::comparison_function::greater;
alpha_ref = rsx::method_registers.msaa_sample_mask()? 0.25f : 0.f;
is_alpha_tested |= (1 << 4);
rop_control |= (1 << 4);
}
}
@ -977,6 +977,9 @@ namespace rsx
const u32 alpha_func = static_cast<u32>(fragment_alpha_func);
const u32 fog_mode = static_cast<u32>(rsx::method_registers.fog_equation());
rop_control |= (alpha_func << 16);
rop_control |= rsx::method_registers.framebuffer_srgb_enabled() ? 0x2 : 0;
// Generate wpos coeffecients
// wpos equation is now as follows:
// wpos.y = (frag_coord / resolution_scale) * ((window_origin!=top)?-1.: 1.) + ((window_origin!=top)? window_height : 0)
@ -990,8 +993,7 @@ namespace rsx
const f32 wpos_bias = (window_origin == rsx::window_origin::top) ? 0.f : window_height;
u32 *dst = static_cast<u32*>(buffer);
stream_vector(dst, (u32&)fog0, (u32&)fog1, is_alpha_tested, (u32&)alpha_ref);
stream_vector(dst, (u32&)fog0, (u32&)fog1, rop_control, (u32&)alpha_ref);
stream_vector(dst + 4, alpha_func, fog_mode, (u32&)wpos_scale, (u32&)wpos_bias);
size_t offset = 8;
@ -1518,9 +1520,6 @@ namespace rsx
result.texture_scale[i][0] = sampler_descriptors[i]->scale_x;
result.texture_scale[i][1] = sampler_descriptors[i]->scale_y;
result.texture_scale[i][2] = (f32)tex.remap(); //Debug value
result.texture_scale[i][3] = (f32)tex.format(); //Debug value
result.textures_alpha_kill[i] = 0;
result.textures_zfunc[i] = 0;
if (!tex.enabled())
{
@ -1528,16 +1527,17 @@ namespace rsx
}
else
{
u32 texture_control = 0;
texture_dimensions[i] = sampler_descriptors[i]->image_type;
if (tex.alpha_kill_enabled())
{
//alphakill can be ignored unless a valid comparison function is set
const rsx::comparison_function func = (rsx::comparison_function)tex.zfunc();
if (func < rsx::comparison_function::always && func > rsx::comparison_function::never)
if (func < rsx::comparison_function::always && func >= rsx::comparison_function::never)
{
result.textures_alpha_kill[i] = 1;
result.textures_zfunc[i] = (u8)func;
texture_control |= (1 << 4); //alphakill enable
texture_control |= ((u32)func << 5); //alphakill function
}
}
@ -1577,6 +1577,9 @@ namespace rsx
LOG_ERROR(RSX, "Depth texture bound to pipeline with unexpected format 0x%X", format);
}
}
texture_control |= tex.gamma();
result.texture_scale[i][3] = (f32)texture_control;
}
}

View File

@ -161,9 +161,9 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
OS << " float fog_param0;\n";
OS << " float fog_param1;\n";
OS << " uint alpha_test;\n";
OS << " uint rop_control;\n";
OS << " float alpha_ref;\n";
OS << " uint alpha_func;\n";
OS << " uint reserved;\n";
OS << " uint fog_mode;\n";
OS << " float wpos_scale;\n";
OS << " float wpos_bias;\n";
@ -179,25 +179,6 @@ void VKFragmentDecompilerThread::insertConstants(std::stringstream & OS)
inputs.push_back(in);
}
namespace vk
{
std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index)
{
std::string tex_name = "tex" + std::to_string(index);
std::string coord_name = "(tc" + std::to_string(index) + " * texture_parameters[" + std::to_string(index) + "])";
switch (prog.get_texture_dimension(index))
{
case rsx::texture_dimension_extended::texture_dimension_1d: return "texture(" + tex_name + ", " + coord_name + ".x)";
case rsx::texture_dimension_extended::texture_dimension_2d: return "texture(" + tex_name + ", " + coord_name + ".xy)";
case rsx::texture_dimension_extended::texture_dimension_3d:
case rsx::texture_dimension_extended::texture_dimension_cubemap: return "texture(" + tex_name + ", " + coord_name + ".xyz)";
}
fmt::throw_exception("Invalid texture dimension %d" HERE, (u32)prog.get_texture_dimension(index));
}
}
void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
{
glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program, properties.has_lit_op, m_prog.redirected_textures != 0, properties.has_wpos_input);
@ -317,32 +298,12 @@ void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
{
const std::pair<std::string, std::string> table[] =
{
{ "ocol0", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r0" : "h0" },
{ "ocol1", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r2" : "h4" },
{ "ocol2", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r3" : "h6" },
{ "ocol3", m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? "r4" : "h8" },
};
const std::set<std::string> output_values =
{
"r0", "r1", "r2", "r3", "r4",
"h0", "h2", "h4", "h6", "h8"
};
std::string first_output_name = "";
std::string color_output_block = "";
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
{
if (m_parr.HasParam(PF_PARAM_NONE, "vec4", table[i].second))
{
color_output_block += " " + table[i].first + " = " + table[i].second + ";\n";
if (first_output_name.empty()) first_output_name = table[i].second;
}
}
OS << "}\n\n";
OS << "void main()\n";
@ -363,44 +324,7 @@ void VKFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
OS << "\n" << " fs_main(" + parameters + ");\n\n";
if (!first_output_name.empty())
{
auto make_comparison_test = [](rsx::comparison_function compare_func, const std::string &test, const std::string &a, const std::string &b) -> std::string
{
std::string compare;
switch (compare_func)
{
case rsx::comparison_function::equal: compare = " == "; break;
case rsx::comparison_function::not_equal: compare = " != "; break;
case rsx::comparison_function::less_or_equal: compare = " <= "; break;
case rsx::comparison_function::less: compare = " < "; break;
case rsx::comparison_function::greater: compare = " > "; break;
case rsx::comparison_function::greater_or_equal: compare = " >= "; break;
default:
return "";
}
return " if (" + test + "!(" + a + compare + b + ")) discard;\n";
};
for (u8 index = 0; index < 16; ++index)
{
if (m_prog.textures_alpha_kill[index])
{
const std::string texture_name = "tex" + std::to_string(index);
if (m_parr.HasParamTypeless(PF_PARAM_UNIFORM, texture_name))
{
std::string fetch_texture = vk::insert_texture_fetch(m_prog, index) + ".a";
OS << make_comparison_test((rsx::comparison_function)m_prog.textures_zfunc[index], "", "0", fetch_texture);
}
}
}
OS << " if (alpha_test != 0 && !comparison_passes(" << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n\n";
}
//Append the color output assignments
OS << color_output_block;
glsl::insert_rop(OS, m_ctrl & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS);
if (m_ctrl & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT)
{

View File

@ -686,7 +686,14 @@ enum
enum
{
CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT = 0xe, ///< shader program exports the depth of the shaded fragment
CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS = 0x40 ///< shader program exports 32 bits registers values (instead of 16 bits ones)
CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS = 0x40, ///< shader program exports 32 bits registers values (instead of 16 bits ones)
//Other known flags
RSX_SHADER_CONTROL_USED_REGS_MASK = 0xf,
RSX_SHADER_CONTROL_USED_TEMP_REGS_MASK = 0xff << 24,
RSX_SHADER_CONTROL_USES_KIL = 0x80, //program uses KIL op
RSX_SHADER_CONTROL_UNKNOWN0 = 0x400, //seemingly always set
RSX_SHADER_CONTROL_UNKNOWN1 = 0x8000 //seemingly set when srgb packer is used??
};
// GCM Reports

View File

@ -1904,6 +1904,31 @@ struct registers_decoder<NV4097_SET_SHADER_CONTROL>
}
};
template<>
struct registers_decoder<NV4097_SET_SHADER_PACKER>
{
struct decoded_type
{
private:
union
{
u32 raw_value;
} m_data;
public:
decoded_type(u32 raw_value) { m_data.raw_value = raw_value; }
bool srgb_output_enabled() const
{
return bool(m_data.raw_value);
}
};
static std::string dump(decoded_type &&decoded_values)
{
return "Shader packer control: srgb_enabled = " + std::to_string(decoded_values.srgb_output_enabled());
}
};
template<>
struct registers_decoder<NV4097_SET_VERTEX_DATA_BASE_OFFSET>
{

View File

@ -1224,6 +1224,11 @@ namespace rsx
{
return decode<NV4097_SET_ZMIN_MAX_CONTROL>().depth_clip_ignore_w();
}
bool framebuffer_srgb_enabled()
{
return decode<NV4097_SET_SHADER_PACKER>().srgb_output_enabled();
}
};
extern rsx_state method_registers;