From 51724c1ccdbc141b1aed67a2efc952e884cadd35 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 29 Jan 2017 22:38:48 +1000 Subject: [PATCH 1/2] LightingShaderGen: Always calculate lighting for both color channels Cel-damage depends on lighting being calculated for the first channel even though there is no color in the vertex format (defaults to the material color). If lighting for the channel is not enabled, the vertex will use the default color as before. The default value of the color is determined by the number of elements in the vertex format. This fixes the grey cubes in Super Mario Sunshine. If the color channel count is zero, we set the color to black before the end of the vertex shader. It's possible that this would be undefined behavior on hardware if a vertex color index that was greater than the channel count was used within TEV. --- Source/Core/VideoCommon/ConstantManager.h | 2 +- Source/Core/VideoCommon/GXPipelineTypes.h | 2 +- Source/Core/VideoCommon/LightingShaderGen.cpp | 62 ++----------------- Source/Core/VideoCommon/LightingShaderGen.h | 2 +- Source/Core/VideoCommon/PixelShaderGen.cpp | 10 +-- Source/Core/VideoCommon/PixelShaderGen.h | 3 +- Source/Core/VideoCommon/ShaderGenCommon.h | 1 + Source/Core/VideoCommon/UberShaderCommon.cpp | 35 +++-------- Source/Core/VideoCommon/UberShaderVertex.cpp | 58 +++++++++++++++-- Source/Core/VideoCommon/VertexShaderGen.cpp | 46 ++++++++++++-- .../Core/VideoCommon/VertexShaderManager.cpp | 12 +++- 11 files changed, 129 insertions(+), 104 deletions(-) diff --git a/Source/Core/VideoCommon/ConstantManager.h b/Source/Core/VideoCommon/ConstantManager.h index 490e4db4db..1ad385b0ee 100644 --- a/Source/Core/VideoCommon/ConstantManager.h +++ b/Source/Core/VideoCommon/ConstantManager.h @@ -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 posnormalmatrix; std::array projection; diff --git a/Source/Core/VideoCommon/GXPipelineTypes.h b/Source/Core/VideoCommon/GXPipelineTypes.h index f20b8edac6..1ddd853597 100644 --- a/Source/Core/VideoCommon/GXPipelineTypes.h +++ b/Source/Core/VideoCommon/GXPipelineTypes.h @@ -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 { diff --git a/Source/Core/VideoCommon/LightingShaderGen.cpp b/Source/Core/VideoCommon/LightingShaderGen.cpp index e4b8f16716..d84ff49e4d 100644 --- a/Source/Core/VideoCommon/LightingShaderGen.cpp +++ b/Source/Core/VideoCommon/LightingShaderGen.cpp @@ -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,43 +87,16 @@ 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"); - } + object.Write("int4 mat = int4(round({}{} * 255.0));\n", in_color_name, j); 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"); - } - } + object.Write("lacc = int4(round({}{} * 255.0));\n", in_color_name, j); else // from color - { object.Write("lacc = {}[{}];\n", I_MATERIALS, j); - } } else { @@ -135,42 +108,17 @@ 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"); - } + object.Write("mat.w = int(round({}{}.w * 255.0));\n", in_color_name, j); 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"); - } - } + object.Write("lacc.w = int(round({}{}.w * 255.0));\n", in_color_name, j); else // from color - { object.Write("lacc.w = {}[{}].w;\n", I_MATERIALS, j); - } } else { diff --git a/Source/Core/VideoCommon/LightingShaderGen.h b/Source/Core/VideoCommon/LightingShaderGen.h index 437a463091..e470db7685 100644 --- a/Source/Core/VideoCommon/LightingShaderGen.h +++ b/Source/Core/VideoCommon/LightingShaderGen.h @@ -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); diff --git a/Source/Core/VideoCommon/PixelShaderGen.cpp b/Source/Core/VideoCommon/PixelShaderGen.cpp index b51fee3acb..30bd725cb7 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/PixelShaderGen.cpp @@ -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 diff --git a/Source/Core/VideoCommon/PixelShaderGen.h b/Source/Core/VideoCommon/PixelShaderGen.h index e5840ca121..08704bda0a 100644 --- a/Source/Core/VideoCommon/PixelShaderGen.h +++ b/Source/Core/VideoCommon/PixelShaderGen.h @@ -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; diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 98d01a3ff4..2bb15e1725 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -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" diff --git a/Source/Core/VideoCommon/UberShaderCommon.cpp b/Source/Core/VideoCommon/UberShaderCommon.cpp index afd86a6943..36403d3f5b 100644 --- a/Source/Core/VideoCommon/UberShaderCommon.cpp +++ b/Source/Core/VideoCommon/UberShaderCommon.cpp @@ -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(" mat.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n", + 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(" mat.w = int(round(((chan == 0u) ? {}.w : {}.w) * 255.0));\n", in_color_0_var, + 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" + out.Write(" 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(" lacc.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n", + 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" + out.Write(" else\n" " lacc.xyz = " I_MATERIALS " [chan].xyz;\n" - " }}\n" "\n"); out.Write(" uint light_mask = {} | ({} << 4u);\n", BitfieldExtract("colorreg", LitChannel().lightMask0_3), diff --git a/Source/Core/VideoCommon/UberShaderVertex.cpp b/Source/Core/VideoCommon/UberShaderVertex.cpp index 39c6ede74a..fef809ec10 100644 --- a/Source/Core/VideoCommon/UberShaderVertex.cpp +++ b/Source/Core/VideoCommon/UberShaderVertex.cpp @@ -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 diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index a26fa006f3..584f55b5e3 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -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 diff --git a/Source/Core/VideoCommon/VertexShaderManager.cpp b/Source/Core/VideoCommon/VertexShaderManager.cpp index aa57161d71..04cb3b2f6f 100644 --- a/Source/Core/VideoCommon/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/VertexShaderManager.cpp @@ -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) From d6ce8eef36f5b0bfd0078c51701b052cc9a77005 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Tue, 31 Jan 2017 15:41:12 +1000 Subject: [PATCH 2/2] Software: Use same logic for colors as hardware backends --- .../VideoBackends/Software/SWVertexLoader.cpp | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp index 06758a3d42..380d6dda0d 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp @@ -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(&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(dst->color[0].data(), src, vdec.colors[0], 0, 4, true); + if (vdec.colors[1].enable) + ReadVertexAttribute(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(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(&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(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++) {