Merge pull request #9122 from Pokechu22/pr-4601-test

Fix Super Mario Sunshine debug cubes (originally PR #4601 by stenzek)
This commit is contained in:
Léo Lam 2020-11-21 02:55:50 +01:00 committed by GitHub
commit 608dd6a37b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 164 additions and 111 deletions

View File

@ -18,6 +18,7 @@
#include "VideoBackends/Software/Tev.h"
#include "VideoBackends/Software/TransformUnit.h"
#include "VideoCommon/CPMemory.h"
#include "VideoCommon/DataReader.h"
#include "VideoCommon/IndexGenerator.h"
#include "VideoCommon/OpcodeDecoding.h"
@ -69,9 +70,6 @@ void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_
const u16 index = m_cpu_index_buffer[i];
memset(static_cast<void*>(&m_vertex), 0, sizeof(m_vertex));
// Super Mario Sunshine requires those to be zero for those debug boxes.
m_vertex.color = {};
// parse the videocommon format to our own struct format (m_vertex)
SetFormat(g_main_cp_state.last_id, primitiveType);
ParseVertex(VertexLoaderManager::GetCurrentVertexFormat()->GetVertexDeclaration(), index);
@ -184,6 +182,39 @@ static void ReadVertexAttribute(T* dst, DataReader src, const AttributeFormat& f
}
}
static void ParseColorAttributes(InputVertexData* dst, DataReader& src,
const PortableVertexDeclaration& vdec)
{
const auto set_default_color = [](u8* color, int i) {
// The default alpha channel seems to depend on the number of components in the vertex format.
const auto& g0 = g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0;
const u32 color_elements = i == 0 ? g0.Color0Elements : g0.Color1Elements;
color[0] = color_elements == 0 ? 255 : 0;
color[1] = 255;
color[2] = 255;
color[3] = 255;
};
if (vdec.colors[0].enable)
{
// Use color0 for channel 0, and color1 for channel 1 if both colors 0 and 1 are present.
ReadVertexAttribute<u8>(dst->color[0].data(), src, vdec.colors[0], 0, 4, true);
if (vdec.colors[1].enable)
ReadVertexAttribute<u8>(dst->color[1].data(), src, vdec.colors[1], 0, 4, true);
else
set_default_color(dst->color[1].data(), 1);
}
else
{
// If only one of the color attributes is enabled, it is directed to color 0.
if (vdec.colors[1].enable)
ReadVertexAttribute<u8>(dst->color[0].data(), src, vdec.colors[1], 0, 4, true);
else
set_default_color(dst->color[0].data(), 0);
set_default_color(dst->color[1].data(), 1);
}
}
void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec, int index)
{
DataReader src(m_cpu_vertex_buffer.data(),
@ -197,10 +228,7 @@ void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec, int inde
ReadVertexAttribute<float>(&m_vertex.normal[i][0], src, vdec.normals[i], 0, 3, false);
}
for (std::size_t i = 0; i < m_vertex.color.size(); i++)
{
ReadVertexAttribute<u8>(m_vertex.color[i].data(), src, vdec.colors[i], 0, 4, true);
}
ParseColorAttributes(&m_vertex, src, vdec);
for (std::size_t i = 0; i < m_vertex.texCoords.size(); i++)
{

View File

@ -58,7 +58,7 @@ struct VertexShaderConstants
u32 components; // .x
u32 xfmem_dualTexInfo; // .y
u32 xfmem_numColorChans; // .z
u32 pad1; // .w
u32 color_chan_alpha; // .w
std::array<float4, 6> posnormalmatrix;
std::array<float4, 4> projection;

View File

@ -20,7 +20,7 @@ namespace VideoCommon
// As pipelines encompass both shader UIDs and render states, changes to either of these should
// also increment the pipeline UID version. Incrementing the UID version will cause all UID
// caches to be invalidated.
constexpr u32 GX_PIPELINE_UID_VERSION = 1; // Last changed in PR 6431
constexpr u32 GX_PIPELINE_UID_VERSION = 2; // Last changed in PR 9122
struct GXPipelineUid
{

View File

@ -78,7 +78,7 @@ static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_d
// materials name is I_MATERIALS in vs and I_PMATERIALS in ps
// inColorName is color in vs and colors_ in ps
// dest is o.colors_ in vs and colors_ in ps
void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_data, int components,
void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_data,
std::string_view in_color_name, std::string_view dest)
{
for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++)
@ -87,44 +87,17 @@ void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_d
const bool colormatsource = !!(uid_data.matsource & (1 << j));
if (colormatsource) // from vertex
{
if ((components & (VB_HAS_COL0 << j)) != 0)
object.Write("int4 mat = int4(round({}{} * 255.0));\n", in_color_name, j);
else if ((components & VB_HAS_COL0) != 0)
object.Write("int4 mat = int4(round({}0 * 255.0));\n", in_color_name);
else
object.Write("int4 mat = int4(255, 255, 255, 255);\n");
}
else // from color
{
object.Write("int4 mat = {}[{}];\n", I_MATERIALS, j + 2);
}
if ((uid_data.enablelighting & (1 << j)) != 0)
{
if ((uid_data.ambsource & (1 << j)) != 0) // from vertex
{
if ((components & (VB_HAS_COL0 << j)) != 0)
{
object.Write("lacc = int4(round({}{} * 255.0));\n", in_color_name, j);
}
else if ((components & VB_HAS_COL0) != 0)
{
object.Write("lacc = int4(round({}0 * 255.0));\n", in_color_name);
}
else
{
// TODO: this isn't verified. Here we want to read the ambient from the vertex,
// but the vertex itself has no color. So we don't know which value to read.
// Returning 1.0 is the same as disabled lightning, so this could be fine
object.Write("lacc = int4(255, 255, 255, 255);\n");
}
}
else // from color
{
object.Write("lacc = {}[{}];\n", I_MATERIALS, j);
}
}
else
{
object.Write("lacc = int4(255, 255, 255, 255);\n");
@ -135,43 +108,18 @@ void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_d
if (alphamatsource != colormatsource)
{
if (alphamatsource) // from vertex
{
if ((components & (VB_HAS_COL0 << j)) != 0)
object.Write("mat.w = int(round({}{}.w * 255.0));\n", in_color_name, j);
else if ((components & VB_HAS_COL0) != 0)
object.Write("mat.w = int(round({}0.w * 255.0));\n", in_color_name);
else
object.Write("mat.w = 255;\n");
}
else // from color
{
object.Write("mat.w = {}[{}].w;\n", I_MATERIALS, j + 2);
}
}
if ((uid_data.enablelighting & (1 << (j + 2))) != 0)
{
if ((uid_data.ambsource & (1 << (j + 2))) != 0) // from vertex
{
if ((components & (VB_HAS_COL0 << j)) != 0)
{
object.Write("lacc.w = int(round({}{}.w * 255.0));\n", in_color_name, j);
}
else if ((components & VB_HAS_COL0) != 0)
{
object.Write("lacc.w = int(round({}0.w * 255.0));\n", in_color_name);
}
else
{
// TODO: The same for alpha: We want to read from vertex, but the vertex has no color
object.Write("lacc.w = 255;\n");
}
}
else // from color
{
object.Write("lacc.w = {}[{}].w;\n", I_MATERIALS, j);
}
}
else
{
object.Write("lacc.w = 255;\n");

View File

@ -45,6 +45,6 @@ constexpr inline char s_lighting_struct[] = "struct Light {\n"
"\tfloat4 dir;\n"
"};\n";
void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_data, int components,
void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_data,
std::string_view in_color_name, std::string_view dest);
void GetLightingShaderUid(LightingUidData& uid_data);

View File

@ -203,9 +203,6 @@ PixelShaderUid GetPixelShaderUid()
if (g_ActiveConfig.bEnablePixelLighting)
{
// The lighting shader only needs the two color bits of the 23bit component bit array.
uid_data->components =
(VertexLoaderManager::g_current_components & (VB_HAS_COL0 | VB_HAS_COL1)) >> VB_COL_SHIFT;
uid_data->numColorChans = xfmem.numChan.numColorChans;
GetLightingShaderUid(uid_data->lighting);
}
@ -768,8 +765,11 @@ ShaderCode GeneratePixelShaderCode(APIType api_type, const ShaderHostConfig& hos
// out.SetConstantsUsed(C_PLIGHT_COLORS, C_PLIGHT_COLORS+7); // TODO: Can be optimized further
// out.SetConstantsUsed(C_PLIGHTS, C_PLIGHTS+31); // TODO: Can be optimized further
// out.SetConstantsUsed(C_PMATERIALS, C_PMATERIALS+3);
GenerateLightingShaderCode(out, uid_data->lighting, uid_data->components << VB_COL_SHIFT,
"colors_", "col");
GenerateLightingShaderCode(out, uid_data->lighting, "colors_", "col");
if (uid_data->numColorChans == 0)
out.Write("col0 = float4(0.0, 0.0, 0.0, 0.0);\n");
if (uid_data->numColorChans <= 1)
out.Write("col1 = float4(0.0, 0.0, 0.0, 0.0);\n");
}
// HACK to handle cases where the tex gen is not enabled

View File

@ -17,8 +17,7 @@ struct pixel_shader_uid_data
u32 num_values; // TODO: Shouldn't be a u32
u32 NumValues() const { return num_values; }
u32 components : 2;
u32 pad0 : 2;
u32 pad0 : 4;
u32 useDstAlpha : 1;
u32 Pretest : 2;
u32 nIndirectStagesUsed : 4;

View File

@ -229,6 +229,7 @@ const char* GetInterpolationQualifier(bool msaa, bool ssaa, bool in_glsl_interfa
static const char s_shader_uniforms[] = "\tuint components;\n"
"\tuint xfmem_dualTexInfo;\n"
"\tuint xfmem_numColorChans;\n"
"\tuint color_chan_alpha;\n"
"\tfloat4 " I_POSNORMALMATRIX "[6];\n"
"\tfloat4 " I_PROJECTION "[4];\n"
"\tint4 " I_MATERIALS "[4];\n"

View File

@ -103,42 +103,23 @@ void WriteVertexLighting(ShaderCode& out, APIType api_type, std::string_view wor
" int4 lacc = int4(255, 255, 255, 255);\n"
"\n");
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().matsource));
out.Write(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.Write(" if ({} != 0u)\n", BitfieldExtract("colorreg", LitChannel().matsource));
out.Write(" mat.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n",
in_color_0_var, in_color_1_var);
out.Write(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.Write(" mat.xyz = int3(round({}.xyz * 255.0));\n", in_color_0_var);
out.Write(" else\n"
" mat.xyz = int3(255, 255, 255);\n"
" }}\n"
"\n");
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("alphareg", LitChannel().matsource));
out.Write(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.Write(" if ({} != 0u)\n", BitfieldExtract("alphareg", LitChannel().matsource));
out.Write(" mat.w = int(round(((chan == 0u) ? {}.w : {}.w) * 255.0));\n", in_color_0_var,
in_color_1_var);
out.Write(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.Write(" mat.w = int(round({}.w * 255.0));\n", in_color_0_var);
out.Write(" else\n"
" mat.w = 255;\n"
" }} else {{\n"
" mat.w = " I_MATERIALS " [chan + 2u].w;\n"
" }}\n"
"\n");
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().enablelighting));
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().ambsource));
out.Write(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.Write(" if ({} != 0u)\n", BitfieldExtract("colorreg", LitChannel().ambsource));
out.Write(" lacc.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n",
in_color_0_var, in_color_1_var);
out.Write(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.Write(" lacc.xyz = int3(round({}.xyz * 255.0));\n", in_color_0_var);
out.Write(" else\n"
" lacc.xyz = int3(255, 255, 255);\n"
" }} else {{\n"
" lacc.xyz = " I_MATERIALS " [chan].xyz;\n"
" }}\n"
"\n");
out.Write(" uint light_mask = {} | ({} << 4u);\n",
BitfieldExtract("colorreg", LitChannel().lightMask0_3),

View File

@ -176,8 +176,43 @@ ShaderCode GenVertexShader(APIType api_type, const ShaderHostConfig& host_config
"\n");
// Hardware Lighting
WriteVertexLighting(out, api_type, "pos.xyz", "_norm0", "rawcolor0", "rawcolor1", "o.colors_0",
"o.colors_1");
out.Write("// xfmem.numColorChans controls the number of color channels available to TEV,\n"
"// but we still need to generate all channels here, as it can be used in texgen.\n"
"// Cel-damage is an example of this.\n"
"float4 vertex_color_0, vertex_color_1;\n"
"\n");
out.Write("// To use color 1, the vertex descriptor must have color 0 and 1.\n"
"// If color 1 is present but not color 0, it is used for lighting channel 0.\n"
"bool use_color_1 = ((components & {0}) == {0}); // VB_HAS_COL0 | VB_HAS_COL1\n",
VB_HAS_COL0 | VB_HAS_COL1);
out.Write("for (uint color = 0; color < {}; color++) {{\n", NUM_XF_COLOR_CHANNELS);
out.Write(" if ((color == 0 || use_color_1) && (components & ({} << color)) != 0) {{\n",
VB_HAS_COL0);
out.Write(" float4 color_value;\n"
" // Use color0 for channel 0, and color1 for channel 1 if both colors 0 and 1 are "
"present.\n"
" if (color == 0u)\n"
" vertex_color_0 = rawcolor0;\n"
" else\n"
" vertex_color_1 = rawcolor1;\n"
" }} else if (color == 0 && (components & {}) != 0) {{\n",
VB_HAS_COL1);
out.Write(" // Use color1 for channel 0 if color0 is not present.\n"
" vertex_color_0 = rawcolor1;\n"
" }} else {{\n"
" // The default alpha channel depends on the number of components in the vertex.\n"
" float alpha = float((color_chan_alpha >> color) & 1u);\n"
" if (color == 0u)\n"
" vertex_color_0 = float4(1.0, 1.0, 1.0, alpha);\n"
" else\n"
" vertex_color_1 = float4(1.0, 1.0, 1.0, alpha);\n"
" }}\n"
"}}\n"
"\n");
WriteVertexLighting(out, api_type, "pos.xyz", "_norm0", "vertex_color_0", "vertex_color_1",
"o.colors_0", "o.colors_1");
// Texture Coordinates
if (num_texgen > 0)
@ -207,14 +242,27 @@ ShaderCode GenVertexShader(APIType api_type, const ShaderHostConfig& host_config
if (per_pixel_lighting)
{
out.Write("o.Normal = _norm0;\n"
"o.WorldPos = pos.xyz;\n");
"o.WorldPos = pos.xyz;\n"
"// Pass through the vertex colors unmodified so we can evaluate the lighting\n"
"// in the same manner.\n");
out.Write("if ((components & {}u) != 0u) // VB_HAS_COL0\n"
" o.colors_0 = rawcolor0;\n",
" o.colors_0 = vertex_color_0;\n",
VB_HAS_COL0);
out.Write("if ((components & {}u) != 0u) // VB_HAS_COL1\n"
" o.colors_1 = rawcolor1;\n",
" o.colors_1 = vertex_color_1;\n",
VB_HAS_COL1);
}
else
{
out.Write("// The number of colors available to TEV is determined by numColorChans.\n"
"// We have to provide the fields to match the interface, so set to zero\n"
"// if it's not enabled.\n"
"if (xfmem_numColorChans == 0u)\n"
" o.colors_0 = float4(0.0, 0.0, 0.0, 0.0);\n"
"if (xfmem_numColorChans <= 1u)\n"
" o.colors_1 = float4(0.0, 0.0, 0.0, 0.0);\n"
"\n");
}
// If we can disable the incorrect depth clipping planes using depth clamping, then we can do
// our own depth clipping and calculate the depth range before the perspective divide if

View File

@ -191,6 +191,35 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
out.Write("VS_OUTPUT o;\n");
// xfmem.numColorChans controls the number of color channels available to TEV, but we still need
// to generate all channels here, as it can be used in texgen. Cel-damage is an example of this.
out.Write("float4 vertex_color_0, vertex_color_1;\n");
// To use color 1, the vertex descriptor must have color 0 and 1.
// If color 1 is present but not color 0, it is used for lighting channel 0.
const bool use_color_1 =
(uid_data->components & (VB_HAS_COL0 | VB_HAS_COL1)) == (VB_HAS_COL0 | VB_HAS_COL1);
for (u32 color = 0; color < NUM_XF_COLOR_CHANNELS; color++)
{
if ((color == 0 || use_color_1) && (uid_data->components & (VB_HAS_COL0 << color)) != 0)
{
// Use color0 for channel 0, and color1 for channel 1 if both colors 0 and 1 are present.
out.Write("vertex_color_{0} = rawcolor{0};\n", color);
}
else if (color == 0 && (uid_data->components & VB_HAS_COL1) != 0)
{
// Use color1 for channel 0 if color0 is not present.
out.Write("vertex_color_{} = rawcolor1;\n", color);
}
else
{
// The default alpha channel depends on the number of components in the vertex format.
out.Write(
"vertex_color_{0} = float4(1.0, 1.0, 1.0, float((color_chan_alpha >> {0}) & 1u));\n",
color);
}
}
// transforms
if ((uid_data->components & VB_HAS_POSMTXIDX) != 0)
{
@ -256,8 +285,7 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
"float3 ldir, h, cosAttn, distAttn;\n"
"float dist, dist2, attn;\n");
GenerateLightingShaderCode(out, uid_data->lighting, uid_data->components, "rawcolor",
"o.colors_");
GenerateLightingShaderCode(out, uid_data->lighting, "vertex_color_", "o.colors_");
// transform texcoords
out.Write("float4 coord = float4(0.0, 0.0, 1.0, 1.0);\n");
@ -434,11 +462,21 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho
out.Write("o.Normal = _norm0;\n"
"o.WorldPos = pos.xyz;\n");
// Pass through the vertex colors unmodified so we can evaluate the lighting in the same manner.
if ((uid_data->components & VB_HAS_COL0) != 0)
out.Write("o.colors_0 = rawcolor0;\n");
out.Write("o.colors_0 = vertex_color_0;\n");
if ((uid_data->components & VB_HAS_COL1) != 0)
out.Write("o.colors_1 = rawcolor1;\n");
out.Write("o.colors_1 = vertex_color_1;\n");
}
else
{
// The number of colors available to TEV is determined by numColorChans.
// We have to provide the fields to match the interface, so set to zero if it's not enabled.
if (uid_data->numColorChans == 0)
out.Write("o.colors_0 = float4(0.0, 0.0, 0.0, 0.0);\n");
if (uid_data->numColorChans <= 1)
out.Write("o.colors_1 = float4(0.0, 0.0, 0.0, 0.0);\n");
}
// If we can disable the incorrect depth clipping planes using depth clamping, then we can do

View File

@ -452,7 +452,6 @@ void VertexShaderManager::SetConstants()
constants.xfmem_pack1[i][3] = xfmem.alpha[i].hex;
}
constants.xfmem_numColorChans = xfmem.numChan.numColorChans;
dirty = true;
}
}
@ -617,6 +616,17 @@ void VertexShaderManager::SetVertexFormat(u32 components)
constants.components = components;
dirty = true;
}
// The default alpha channel seems to depend on the number of components in the vertex format.
// If the vertex attribute has an alpha channel, zero is used, otherwise one.
const u32 color_chan_alpha =
(g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0.Color0Elements ^ 1) |
((g_main_cp_state.vtx_attr[g_main_cp_state.last_id].g0.Color1Elements ^ 1) << 1);
if (color_chan_alpha != constants.color_chan_alpha)
{
constants.color_chan_alpha = color_chan_alpha;
dirty = true;
}
}
void VertexShaderManager::SetTexMatrixInfoChanged(int index)