From 937bb2aa2e12b635ba328af8de7c9a5d5963d084 Mon Sep 17 00:00:00 2001 From: Pokechu22 Date: Tue, 24 Sep 2024 23:46:45 -0700 Subject: [PATCH] Cache normals in addition to binormals and tangents Fixes LIT (https://bugs.dolphin-emu.org/issues/13635). The text does not include normals, but has lighting enabled. With the previous default of (0, 0, 0), lighting was always black (as dot(X, (0, 0, 0)) is always 0). It seems like the normal from the map in the background (0, 0, 1) is re-used. LIT also has the vertex color enabled while vertex color is not specified, the same as SMS's debug cubes; the default MissingColorValue GameINI value of solid white seems to work correctly in this case. --- Source/Core/Core/State.cpp | 2 +- .../VideoBackends/Software/SWVertexLoader.cpp | 12 ++- Source/Core/VideoCommon/ConstantManager.h | 1 + Source/Core/VideoCommon/ShaderGenCommon.h | 2 + Source/Core/VideoCommon/UberShaderVertex.cpp | 78 ++++++++++--------- Source/Core/VideoCommon/VertexLoaderARM64.cpp | 7 ++ Source/Core/VideoCommon/VertexLoaderBase.cpp | 10 +++ .../Core/VideoCommon/VertexLoaderManager.cpp | 1 + Source/Core/VideoCommon/VertexLoaderManager.h | 4 + Source/Core/VideoCommon/VertexLoaderX64.cpp | 8 ++ .../Core/VideoCommon/VertexLoader_Normal.cpp | 4 +- Source/Core/VideoCommon/VertexManagerBase.cpp | 15 +++- Source/Core/VideoCommon/VertexManagerBase.h | 2 +- Source/Core/VideoCommon/VertexShaderGen.cpp | 65 +++++++--------- .../VideoCommon/VertexLoaderTest.cpp | 12 +++ 15 files changed, 140 insertions(+), 83 deletions(-) diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index fe20d74ea4b..f9964c0fa81 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -98,7 +98,7 @@ static size_t s_state_writes_in_queue; static std::condition_variable s_state_write_queue_is_empty; // Don't forget to increase this after doing changes on the savestate system -constexpr u32 STATE_VERSION = 168; // Last changed in PR 12639 +constexpr u32 STATE_VERSION = 169; // Last changed in PR 13074 // Increase this if the StateExtendedHeader definition changes constexpr u32 EXTENDED_HEADER_VERSION = 1; // Last changed in PR 12217 diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp index cfb05d096b7..2e6e748a387 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp @@ -81,9 +81,7 @@ void SWVertexLoader::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 base_ // transform this vertex so that it can be used for rasterization (outVertex) OutputVertexData* outVertex = m_setup_unit.GetVertex(); TransformUnit::TransformPosition(&m_vertex, outVertex); - outVertex->normal = {}; - if (VertexLoaderManager::g_current_components & VB_HAS_NORMAL) - TransformUnit::TransformNormal(&m_vertex, outVertex); + TransformUnit::TransformNormal(&m_vertex, outVertex); TransformUnit::TransformColor(&m_vertex, outVertex); TransformUnit::TransformTexCoord(&m_vertex, outVertex); @@ -209,6 +207,14 @@ void SWVertexLoader::ParseVertex(const PortableVertexDeclaration& vdec, int inde { ReadVertexAttribute(&m_vertex.normal[i][0], src, vdec.normals[i], 0, 3, false); } + if (!vdec.normals[0].enable) + { + auto& system = Core::System::GetInstance(); + auto& vertex_shader_manager = system.GetVertexShaderManager(); + m_vertex.normal[0][0] = vertex_shader_manager.constants.cached_normal[0]; + m_vertex.normal[0][1] = vertex_shader_manager.constants.cached_normal[1]; + m_vertex.normal[0][2] = vertex_shader_manager.constants.cached_normal[2]; + } if (!vdec.normals[1].enable) { auto& system = Core::System::GetInstance(); diff --git a/Source/Core/VideoCommon/ConstantManager.h b/Source/Core/VideoCommon/ConstantManager.h index b8c65aaefb6..14c8732580b 100644 --- a/Source/Core/VideoCommon/ConstantManager.h +++ b/Source/Core/VideoCommon/ConstantManager.h @@ -93,6 +93,7 @@ struct alignas(16) VertexShaderConstants // .x - texMtxInfo, .y - postMtxInfo, [0..1].z = color, [0..1].w = alpha std::array xfmem_pack1; + float4 cached_normal; float4 cached_tangent; float4 cached_binormal; // For UberShader vertex loader diff --git a/Source/Core/VideoCommon/ShaderGenCommon.h b/Source/Core/VideoCommon/ShaderGenCommon.h index 6ec00331e6f..4723cbfc79d 100644 --- a/Source/Core/VideoCommon/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/ShaderGenCommon.h @@ -283,6 +283,7 @@ void WriteSwitch(ShaderCode& out, APIType ApiType, std::string_view variable, #define I_POSTTRANSFORMMATRICES "cpostmtx" #define I_PIXELCENTERCORRECTION "cpixelcenter" #define I_VIEWPORT_SIZE "cviewport" +#define I_CACHED_NORMAL "cnormal" #define I_CACHED_TANGENT "ctangent" #define I_CACHED_BINORMAL "cbinormal" @@ -306,6 +307,7 @@ static const char s_shader_uniforms[] = "\tuint components;\n" "\tfloat4 " I_PIXELCENTERCORRECTION ";\n" "\tfloat2 " I_VIEWPORT_SIZE ";\n" "\tuint4 xfmem_pack1[8];\n" + "\tfloat4 " I_CACHED_NORMAL ";\n" "\tfloat4 " I_CACHED_TANGENT ";\n" "\tfloat4 " I_CACHED_BINORMAL ";\n" "\tuint vertex_stride;\n" diff --git a/Source/Core/VideoCommon/UberShaderVertex.cpp b/Source/Core/VideoCommon/UberShaderVertex.cpp index eceda62e487..a6c0502dfec 100644 --- a/Source/Core/VideoCommon/UberShaderVertex.cpp +++ b/Source/Core/VideoCommon/UberShaderVertex.cpp @@ -251,47 +251,53 @@ float3 load_input_float3_rawtex(uint vtx_offset, uint attr_offset) {{ "o.pos = float4(dot(" I_PROJECTION "[0], pos), dot(" I_PROJECTION "[1], pos), dot(" I_PROJECTION "[2], pos), dot(" I_PROJECTION "[3], pos));\n" "\n" + "float3 _rawnormal;\n" + "float3 _rawtangent;\n" + "float3 _rawbinormal;\n" + "if ((components & {}u) != 0u) // VB_HAS_NORMAL\n" + "{{\n", + Common::ToUnderlying(VB_HAS_NORMAL)); + LoadVertexAttribute(out, host_config, 2, "rawnormal", "float3", "float3"); + out.Write(" _rawnormal = rawnormal;\n" + "}}\n" + "else\n" + "{{\n" + " _rawnormal = " I_CACHED_NORMAL ".xyz;\n" + "}}\n" + "\n" + "if ((components & {}u) != 0u) // VB_HAS_TANGENT\n" + "{{\n", + Common::ToUnderlying(VB_HAS_TANGENT)); + LoadVertexAttribute(out, host_config, 2, "rawtangent", "float3", "float3"); + out.Write(" _rawtangent = rawtangent;\n" + "}}\n" + "else\n" + "{{\n" + " _rawtangent = " I_CACHED_TANGENT ".xyz;\n" + "}}\n" + "\n" + "if ((components & {}u) != 0u) // VB_HAS_BINORMAL\n" + "{{\n", + Common::ToUnderlying(VB_HAS_BINORMAL)); + LoadVertexAttribute(out, host_config, 2, "rawbinormal", "float3", "float3"); + out.Write(" _rawbinormal = rawbinormal;\n" + "}}\n" + "else\n" + "{{\n" + " _rawbinormal = " I_CACHED_BINORMAL ".xyz;\n" + "}}\n" + "\n" "// The scale of the transform matrix is used to control the size of the emboss map\n" "// effect by changing the scale of the transformed binormals (which only get used by\n" "// emboss map texgens). By normalising the first transformed normal (which is used\n" "// by lighting calculations and needs to be unit length), the same transform matrix\n" "// can do double duty, scaling for emboss mapping, and not scaling for lighting.\n" - "float3 _normal = float3(0.0, 0.0, 0.0);\n" - "if ((components & {}u) != 0u) // VB_HAS_NORMAL\n" - "{{\n", - Common::ToUnderlying(VB_HAS_NORMAL)); - LoadVertexAttribute(out, host_config, 2, "rawnormal", "float3", "float3"); - out.Write(" _normal = normalize(float3(dot(N0, rawnormal), dot(N1, rawnormal), dot(N2, " - "rawnormal)));\n" - "}}\n" - "\n" - "float3 _tangent = float3(0.0, 0.0, 0.0);\n" - "if ((components & {}u) != 0u) // VB_HAS_TANGENT\n" - "{{\n", - Common::ToUnderlying(VB_HAS_TANGENT)); - LoadVertexAttribute(out, host_config, 2, "rawtangent", "float3", "float3"); - out.Write(" _tangent = float3(dot(N0, rawtangent), dot(N1, rawtangent), dot(N2, rawtangent));\n" - "}}\n" - "else\n" - "{{\n" - " _tangent = float3(dot(N0, " I_CACHED_TANGENT ".xyz), dot(N1, " I_CACHED_TANGENT - ".xyz), dot(N2, " I_CACHED_TANGENT ".xyz));\n" - "}}\n" - "\n" - "float3 _binormal = float3(0.0, 0.0, 0.0);\n" - "if ((components & {}u) != 0u) // VB_HAS_BINORMAL\n" - "{{\n", - Common::ToUnderlying(VB_HAS_BINORMAL)); - LoadVertexAttribute(out, host_config, 2, "rawbinormal", "float3", "float3"); - out.Write(" _binormal = float3(dot(N0, rawbinormal), dot(N1, rawbinormal), dot(N2, " - "rawbinormal));\n" - "}}\n" - "else\n" - "{{\n" - " _binormal = float3(dot(N0, " I_CACHED_BINORMAL ".xyz), dot(N1, " I_CACHED_BINORMAL - ".xyz), dot(N2, " I_CACHED_BINORMAL ".xyz));\n" - "}}\n" - "\n"); + "float3 _normal = normalize(float3(dot(N0, _rawnormal), dot(N1, _rawnormal), dot(N2, " + "_rawnormal)));\n" + "float3 _tangent = float3(dot(N0, _rawtangent), dot(N1, _rawtangent), dot(N2, " + "_rawtangent));\n" + "float3 _binormal = float3(dot(N0, _rawbinormal), dot(N1, _rawbinormal), dot(N2, " + "_rawbinormal));\n"); // Hardware Lighting out.Write("// xfmem.numColorChans controls the number of color channels available to TEV,\n" diff --git a/Source/Core/VideoCommon/VertexLoaderARM64.cpp b/Source/Core/VideoCommon/VertexLoaderARM64.cpp index 9fd8c0c29c8..9e0075f9a2f 100644 --- a/Source/Core/VideoCommon/VertexLoaderARM64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderARM64.cpp @@ -164,6 +164,13 @@ void VertexLoaderARM64::ReadVertex(VertexComponentFormat attribute, ComponentFor m_float_emit.STR(128, coords, EncodeRegTo64(scratch2_reg), ArithOption(remaining_reg, true)); SetJumpTarget(dont_store); } + else if (native_format == &m_native_vtx_decl.normals[0]) + { + FixupBranch dont_store = CBNZ(remaining_reg); + MOVP2R(EncodeRegTo64(scratch2_reg), VertexLoaderManager::normal_cache.data()); + m_float_emit.STR(128, IndexType::Unsigned, coords, EncodeRegTo64(scratch2_reg), 0); + SetJumpTarget(dont_store); + } else if (native_format == &m_native_vtx_decl.normals[1]) { FixupBranch dont_store = CBNZ(remaining_reg); diff --git a/Source/Core/VideoCommon/VertexLoaderBase.cpp b/Source/Core/VideoCommon/VertexLoaderBase.cpp index 3284a2ccdbf..a3597b53e54 100644 --- a/Source/Core/VideoCommon/VertexLoaderBase.cpp +++ b/Source/Core/VideoCommon/VertexLoaderBase.cpp @@ -68,6 +68,7 @@ public: VertexLoaderManager::position_matrix_index_cache; const std::array, 3> old_position_cache = VertexLoaderManager::position_cache; + const std::array old_normal_cache = VertexLoaderManager::normal_cache; const std::array old_tangent_cache = VertexLoaderManager::tangent_cache; const std::array old_binormal_cache = VertexLoaderManager::binormal_cache; @@ -77,12 +78,14 @@ public: VertexLoaderManager::position_matrix_index_cache; const std::array, 3> a_position_cache = VertexLoaderManager::position_cache; + const std::array a_normal_cache = VertexLoaderManager::normal_cache; const std::array a_tangent_cache = VertexLoaderManager::tangent_cache; const std::array a_binormal_cache = VertexLoaderManager::binormal_cache; // Reset state before running b VertexLoaderManager::position_matrix_index_cache = old_position_matrix_index_cache; VertexLoaderManager::position_cache = old_position_cache; + VertexLoaderManager::normal_cache = old_normal_cache; VertexLoaderManager::tangent_cache = old_tangent_cache; VertexLoaderManager::binormal_cache = old_binormal_cache; @@ -92,6 +95,7 @@ public: VertexLoaderManager::position_matrix_index_cache; const std::array, 3> b_position_cache = VertexLoaderManager::position_cache; + const std::array b_normal_cache = VertexLoaderManager::normal_cache; const std::array b_tangent_cache = VertexLoaderManager::tangent_cache; const std::array b_binormal_cache = VertexLoaderManager::binormal_cache; @@ -140,6 +144,12 @@ public: fmt::join(b_position_cache[1], ", "), fmt::join(b_position_cache[2], ", ")); // The last element is allowed to be garbage for SIMD overwrites + ASSERT_MSG(VIDEO, + std::equal(a_normal_cache.begin(), a_normal_cache.begin() + 3, + b_normal_cache.begin(), b_normal_cache.begin() + 3, bit_equal), + "Expected matching normal caches after loading (a: {}; b: {})", + fmt::join(a_normal_cache, ", "), fmt::join(b_normal_cache, ", ")); + ASSERT_MSG(VIDEO, std::equal(a_tangent_cache.begin(), a_tangent_cache.begin() + 3, b_tangent_cache.begin(), b_tangent_cache.begin() + 3, bit_equal), diff --git a/Source/Core/VideoCommon/VertexLoaderManager.cpp b/Source/Core/VideoCommon/VertexLoaderManager.cpp index 0c48bf32a8b..4ef11a12831 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/VertexLoaderManager.cpp @@ -40,6 +40,7 @@ namespace VertexLoaderManager std::array position_matrix_index_cache; // 3 vertices, 4 floats each to allow SIMD overwrite alignas(sizeof(std::array)) std::array, 3> position_cache; +alignas(sizeof(std::array)) std::array normal_cache; alignas(sizeof(std::array)) std::array tangent_cache; alignas(sizeof(std::array)) std::array binormal_cache; diff --git a/Source/Core/VideoCommon/VertexLoaderManager.h b/Source/Core/VideoCommon/VertexLoaderManager.h index ce8b6a22d15..0e1caa6fa15 100644 --- a/Source/Core/VideoCommon/VertexLoaderManager.h +++ b/Source/Core/VideoCommon/VertexLoaderManager.h @@ -62,6 +62,10 @@ void UpdateVertexArrayPointers(); // These arrays are in reverse order. extern std::array, 3> position_cache; extern std::array position_matrix_index_cache; +// Needed for the game "LIT", which has text that has lighting enabled, but doesn't have normal +// vectors. The normals from the last drawn object are used instead. +// See https://bugs.dolphin-emu.org/issues/13635 +extern std::array normal_cache; // Store the tangent and binormal vectors for games that use emboss texgens when the vertex format // doesn't include them (e.g. RS2 and RS3). These too are 4 floats each for SIMD overwrites. extern std::array tangent_cache; diff --git a/Source/Core/VideoCommon/VertexLoaderX64.cpp b/Source/Core/VideoCommon/VertexLoaderX64.cpp index 9934570b55a..aa8ad2bd679 100644 --- a/Source/Core/VideoCommon/VertexLoaderX64.cpp +++ b/Source/Core/VideoCommon/VertexLoaderX64.cpp @@ -137,6 +137,14 @@ void VertexLoaderX64::ReadVertex(OpArg data, VertexComponentFormat attribute, MOVUPS(MPIC(VertexLoaderManager::position_cache.data(), scratch3, SCALE_4), coords); SetJumpTarget(dont_store); } + else if (native_format == &m_native_vtx_decl.normals[0]) + { + TEST(32, R(remaining_reg), R(remaining_reg)); + FixupBranch dont_store = J_CC(CC_NZ); + // For similar reasons, the cached normal is 4 floats each + MOVUPS(MPIC(VertexLoaderManager::normal_cache.data()), coords); + SetJumpTarget(dont_store); + } else if (native_format == &m_native_vtx_decl.normals[1]) { TEST(32, R(remaining_reg), R(remaining_reg)); diff --git a/Source/Core/VideoCommon/VertexLoader_Normal.cpp b/Source/Core/VideoCommon/VertexLoader_Normal.cpp index b91c7fe1274..50e0dbbd63d 100644 --- a/Source/Core/VideoCommon/VertexLoader_Normal.cpp +++ b/Source/Core/VideoCommon/VertexLoader_Normal.cpp @@ -49,7 +49,9 @@ void ReadIndirect(VertexLoader* loader, const T* data) const float value = FracAdjust(Common::FromBigEndian(data[i])); if (loader->m_remaining == 0) { - if (i >= 3 && i < 6) + if (i < 3) + VertexLoaderManager::normal_cache[i] = value; + else if (i >= 3 && i < 6) VertexLoaderManager::tangent_cache[i - 3] = value; else if (i >= 6 && i < 9) VertexLoaderManager::binormal_cache[i - 6] = value; diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 02edb56d354..0e69c4fdd09 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -558,7 +558,7 @@ void VertexManagerBase::Flush() pixel_shader_manager.constants.time_ms = seconds_elapsed * 1000; } - CalculateBinormals(VertexLoaderManager::GetCurrentVertexFormat()); + CalculateNormals(VertexLoaderManager::GetCurrentVertexFormat()); // Calculate ZSlope for zfreeze const auto used_textures = UsedTextures(); std::vector texture_names; @@ -699,6 +699,7 @@ void VertexManagerBase::DoState(PointerWrap& p) } p.Do(m_zslope); + p.Do(VertexLoaderManager::normal_cache); p.Do(VertexLoaderManager::tangent_cache); p.Do(VertexLoaderManager::binormal_cache); } @@ -769,7 +770,7 @@ void VertexManagerBase::CalculateZSlope(NativeVertexFormat* format) m_zslope.dirty = true; } -void VertexManagerBase::CalculateBinormals(NativeVertexFormat* format) +void VertexManagerBase::CalculateNormals(NativeVertexFormat* format) { const PortableVertexDeclaration vert_decl = format->GetVertexDeclaration(); @@ -794,6 +795,16 @@ void VertexManagerBase::CalculateBinormals(NativeVertexFormat* format) vertex_shader_manager.constants.cached_binormal = VertexLoaderManager::binormal_cache; vertex_shader_manager.dirty = true; } + + if (vert_decl.normals[0].enable) + return; + + VertexLoaderManager::normal_cache[3] = 0; + if (vertex_shader_manager.constants.cached_normal != VertexLoaderManager::normal_cache) + { + vertex_shader_manager.constants.cached_normal = VertexLoaderManager::normal_cache; + vertex_shader_manager.dirty = true; + } } void VertexManagerBase::UpdatePipelineConfig() diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h index 648e26be599..715dbee6925 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.h +++ b/Source/Core/VideoCommon/VertexManagerBase.h @@ -192,7 +192,7 @@ protected: u32 GetRemainingIndices(OpcodeDecoder::Primitive primitive) const; void CalculateZSlope(NativeVertexFormat* format); - void CalculateBinormals(NativeVertexFormat* format); + void CalculateNormals(NativeVertexFormat* format); BitSet32 UsedTextures() const; diff --git a/Source/Core/VideoCommon/VertexShaderGen.cpp b/Source/Core/VideoCommon/VertexShaderGen.cpp index 9f854f2d9e4..4a46834c146 100644 --- a/Source/Core/VideoCommon/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/VertexShaderGen.cpp @@ -312,56 +312,43 @@ ShaderCode GenerateVertexShaderCode(APIType api_type, const ShaderHostConfig& ho out.Write("int posidx = int(posmtx.r);\n" "float4 P0 = " I_TRANSFORMMATRICES "[posidx];\n" "float4 P1 = " I_TRANSFORMMATRICES "[posidx + 1];\n" - "float4 P2 = " I_TRANSFORMMATRICES "[posidx + 2];\n"); - if ((uid_data->components & VB_HAS_NORMAL) != 0) - { - out.Write("int normidx = posidx & 31;\n" - "float3 N0 = " I_NORMALMATRICES "[normidx].xyz;\n" - "float3 N1 = " I_NORMALMATRICES "[normidx + 1].xyz;\n" - "float3 N2 = " I_NORMALMATRICES "[normidx + 2].xyz;\n"); - } + "float4 P2 = " I_TRANSFORMMATRICES "[posidx + 2];\n" + "int normidx = posidx & 31;\n" + "float3 N0 = " I_NORMALMATRICES "[normidx].xyz;\n" + "float3 N1 = " I_NORMALMATRICES "[normidx + 1].xyz;\n" + "float3 N2 = " I_NORMALMATRICES "[normidx + 2].xyz;\n"); } else { // One shared matrix out.Write("float4 P0 = " I_POSNORMALMATRIX "[0];\n" "float4 P1 = " I_POSNORMALMATRIX "[1];\n" - "float4 P2 = " I_POSNORMALMATRIX "[2];\n"); - if ((uid_data->components & VB_HAS_NORMAL) != 0) - { - out.Write("float3 N0 = " I_POSNORMALMATRIX "[3].xyz;\n" - "float3 N1 = " I_POSNORMALMATRIX "[4].xyz;\n" - "float3 N2 = " I_POSNORMALMATRIX "[5].xyz;\n"); - } + "float4 P2 = " I_POSNORMALMATRIX "[2];\n" + "float3 N0 = " I_POSNORMALMATRIX "[3].xyz;\n" + "float3 N1 = " I_POSNORMALMATRIX "[4].xyz;\n" + "float3 N2 = " I_POSNORMALMATRIX "[5].xyz;\n"); } out.Write("// Multiply the position vector by the position matrix\n" "float4 pos = float4(dot(P0, rawpos), dot(P1, rawpos), dot(P2, rawpos), 1.0);\n"); - if ((uid_data->components & VB_HAS_NORMAL) != 0) - { - if ((uid_data->components & VB_HAS_TANGENT) == 0) - out.Write("float3 rawtangent = " I_CACHED_TANGENT ".xyz;\n"); - if ((uid_data->components & VB_HAS_BINORMAL) == 0) - out.Write("float3 rawbinormal = " I_CACHED_BINORMAL ".xyz;\n"); + if ((uid_data->components & VB_HAS_NORMAL) == 0) + out.Write("float3 rawnormal = " I_CACHED_NORMAL ".xyz;\n"); + if ((uid_data->components & VB_HAS_TANGENT) == 0) + out.Write("float3 rawtangent = " I_CACHED_TANGENT ".xyz;\n"); + if ((uid_data->components & VB_HAS_BINORMAL) == 0) + out.Write("float3 rawbinormal = " I_CACHED_BINORMAL ".xyz;\n"); - // The scale of the transform matrix is used to control the size of the emboss map effect, by - // changing the scale of the transformed binormals (which only get used by emboss map texgens). - // By normalising the first transformed normal (which is used by lighting calculations and needs - // to be unit length), the same transform matrix can do double duty, scaling for emboss mapping, - // and not scaling for lighting. - out.Write("float3 _normal = normalize(float3(dot(N0, rawnormal), dot(N1, rawnormal), dot(N2, " - "rawnormal)));\n" - "float3 _tangent = float3(dot(N0, rawtangent), dot(N1, rawtangent), dot(N2, " - "rawtangent));\n" - "float3 _binormal = float3(dot(N0, rawbinormal), dot(N1, rawbinormal), dot(N2, " - "rawbinormal));\n"); - } - else - { - out.Write("float3 _normal = float3(0.0, 0.0, 0.0);\n"); - out.Write("float3 _binormal = float3(0.0, 0.0, 0.0);\n"); - out.Write("float3 _tangent = float3(0.0, 0.0, 0.0);\n"); - } + // The scale of the transform matrix is used to control the size of the emboss map effect, by + // changing the scale of the transformed binormals (which only get used by emboss map texgens). + // By normalising the first transformed normal (which is used by lighting calculations and needs + // to be unit length), the same transform matrix can do double duty, scaling for emboss mapping, + // and not scaling for lighting. + out.Write("float3 _normal = normalize(float3(dot(N0, rawnormal), dot(N1, rawnormal), dot(N2, " + "rawnormal)));\n" + "float3 _tangent = float3(dot(N0, rawtangent), dot(N1, rawtangent), dot(N2, " + "rawtangent));\n" + "float3 _binormal = float3(dot(N0, rawbinormal), dot(N1, rawbinormal), dot(N2, " + "rawbinormal));\n"); out.Write("o.pos = float4(dot(" I_PROJECTION "[0], pos), dot(" I_PROJECTION "[1], pos), dot(" I_PROJECTION "[2], pos), dot(" I_PROJECTION "[3], pos));\n"); diff --git a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp index 83b1f813dae..675be35355a 100644 --- a/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp +++ b/Source/UnitTests/VideoCommon/VertexLoaderTest.cpp @@ -702,6 +702,7 @@ TEST_P(VertexLoaderNormalTest, NormalAll) input_with_expected_type(i / 32.f); // Pre-fill these values to detect if they're modified + VertexLoaderManager::normal_cache = {-42.f, -43.f, -44.f, -45.f}; VertexLoaderManager::binormal_cache = {42.f, 43.f, 44.f, 45.f}; VertexLoaderManager::tangent_cache = {46.f, 47.f, 48.f, 49.f}; @@ -738,6 +739,9 @@ TEST_P(VertexLoaderNormalTest, NormalAll) ExpectOut(10 / 32.f); ExpectOut(11 / 32.f); ExpectOut(12 / 32.f); + EXPECT_EQ(VertexLoaderManager::normal_cache[0], 10 / 32.f); + EXPECT_EQ(VertexLoaderManager::normal_cache[1], 11 / 32.f); + EXPECT_EQ(VertexLoaderManager::normal_cache[2], 12 / 32.f); if (elements == NormalComponentCount::NTB) { // Tangent @@ -759,6 +763,14 @@ TEST_P(VertexLoaderNormalTest, NormalAll) } } + if (addr == VertexComponentFormat::NotPresent) + { + // Expect these to not be written + EXPECT_EQ(VertexLoaderManager::normal_cache[0], -42.f); + EXPECT_EQ(VertexLoaderManager::normal_cache[1], -43.f); + EXPECT_EQ(VertexLoaderManager::normal_cache[2], -44.f); + EXPECT_EQ(VertexLoaderManager::normal_cache[3], -45.f); + } if (addr == VertexComponentFormat::NotPresent || elements == NormalComponentCount::N) { // Expect these to not be written