From 2547516e39125e5ed274a3c230be5f426bf5ddf2 Mon Sep 17 00:00:00 2001 From: LVEIceFire Date: Sun, 20 Sep 2026 23:57:33 +0200 Subject: [PATCH] fix(techset): write complete Direct3D 9 shader bytecode (#1004) * fix(techset): write Direct3D 9 shader bytecode bounds * chore: extract shader dumping tests into separate sections --------- Co-authored-by: Jan Laupetin --- .../Techset/TechsetDumper.cpp.template | 4 +-- .../Game/IW3/Techset/TechsetDumperIW3Test.cpp | 27 +++++++++++++++++++ .../Game/T5/Techset/TechsetDumperT5Test.cpp | 26 ++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src/ObjWriting/Techset/TechsetDumper.cpp.template b/src/ObjWriting/Techset/TechsetDumper.cpp.template index 397cac2a..fd59aa74 100644 --- a/src/ObjWriting/Techset/TechsetDumper.cpp.template +++ b/src/ObjWriting/Techset/TechsetDumper.cpp.template @@ -64,7 +64,7 @@ namespace shaderFile->write(pixelShader.prog.loadDef.program, pixelShader.prog.loadDef.programSize); #else shaderFile->write(reinterpret_cast(pixelShader.prog.loadDef.program), - static_cast(pixelShader.prog.loadDef.programSize) * sizeof(GfxPixelShaderLoadDef::program)); + static_cast(pixelShader.prog.loadDef.programSize) * sizeof(*pixelShader.prog.loadDef.program)); #endif } @@ -79,7 +79,7 @@ namespace shaderFile->write(vertexShader.prog.loadDef.program, vertexShader.prog.loadDef.programSize); #else shaderFile->write(reinterpret_cast(vertexShader.prog.loadDef.program), - static_cast(vertexShader.prog.loadDef.programSize) * sizeof(GfxVertexShaderLoadDef::program)); + static_cast(vertexShader.prog.loadDef.programSize) * sizeof(*vertexShader.prog.loadDef.program)); #endif } diff --git a/test/ObjWritingTests/Game/IW3/Techset/TechsetDumperIW3Test.cpp b/test/ObjWritingTests/Game/IW3/Techset/TechsetDumperIW3Test.cpp index 10df5b18..a58f2d7b 100644 --- a/test/ObjWritingTests/Game/IW3/Techset/TechsetDumperIW3Test.cpp +++ b/test/ObjWritingTests/Game/IW3/Techset/TechsetDumperIW3Test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include using namespace IW3; using namespace Catch; @@ -233,6 +234,23 @@ namespace zone.m_pools.AddAsset(std::make_unique>(ASSET_TYPE_TECHNIQUE_SET, techset->name, techset)); return techset; } + + void EnsureDumpedShaderMatchesInputData(const MockOutputPath& output, const std::string& fileName) + { + const auto* dumpedFile = output.GetMockedFile(std::format("shader_bin/{}", fileName)); + REQUIRE(dumpedFile); + + const auto inputFilePath = oat::paths::GetTestDirectory() / "ObjWritingTests/Game/IW3/Techset" / fileName; + std::ifstream inputFileStream(inputFilePath, std::ios::binary); + REQUIRE(inputFileStream.is_open()); + + const auto inputDataSize = static_cast(fs::file_size(inputFilePath)); + std::vector inputData(inputDataSize); + inputFileStream.read(reinterpret_cast(inputData.data()), static_cast(inputData.size())); + REQUIRE(inputFileStream.gcount() == static_cast(inputData.size())); + REQUIRE(dumpedFile->m_data.size() == inputData.size()); + REQUIRE(std::memcmp(dumpedFile->m_data.data(), inputData.data(), inputData.size()) == 0); + } } // namespace TEST_CASE("TechsetDumperIW3", "[iw3][techset][dumper]") @@ -335,4 +353,13 @@ TEST_CASE("TechsetDumperIW3", "[iw3][techset][dumper]") REQUIRE(file); REQUIRE(Trimmed(file->AsString()) == Trimmed(expected)); } + + SECTION("Can dump shaders") + { + dumper.Dump(context); + EnsureDumpedShaderMatchesInputData(mockOutput, "vs_simple.hlsl.cso"); + EnsureDumpedShaderMatchesInputData(mockOutput, "ps_simple.hlsl.cso"); + EnsureDumpedShaderMatchesInputData(mockOutput, "vs_advanced.hlsl.cso"); + EnsureDumpedShaderMatchesInputData(mockOutput, "ps_advanced.hlsl.cso"); + } } diff --git a/test/ObjWritingTests/Game/T5/Techset/TechsetDumperT5Test.cpp b/test/ObjWritingTests/Game/T5/Techset/TechsetDumperT5Test.cpp index a259fca4..75ec3fdd 100644 --- a/test/ObjWritingTests/Game/T5/Techset/TechsetDumperT5Test.cpp +++ b/test/ObjWritingTests/Game/T5/Techset/TechsetDumperT5Test.cpp @@ -409,6 +409,23 @@ namespace zone.m_pools.AddAsset(std::make_unique>(ASSET_TYPE_TECHNIQUE_SET, techset->name, techset)); return techset; } + + void EnsureDumpedShaderMatchesInputData(const MockOutputPath& output, const std::string& fileName) + { + const auto* dumpedFile = output.GetMockedFile(std::format("shader_bin/{}", fileName)); + REQUIRE(dumpedFile); + + const auto inputFilePath = oat::paths::GetTestDirectory() / "ObjWritingTests/Game/T5/Techset" / fileName; + std::ifstream inputFileStream(inputFilePath, std::ios::binary); + REQUIRE(inputFileStream.is_open()); + + const auto inputDataSize = static_cast(fs::file_size(inputFilePath)); + std::vector inputData(inputDataSize); + inputFileStream.read(reinterpret_cast(inputData.data()), static_cast(inputData.size())); + REQUIRE(inputFileStream.gcount() == static_cast(inputData.size())); + REQUIRE(dumpedFile->m_data.size() == inputData.size()); + REQUIRE(std::memcmp(dumpedFile->m_data.data(), inputData.data(), inputData.size()) == 0); + } } // namespace TEST_CASE("TechsetDumperT5", "[t5][techset][dumper]") @@ -546,4 +563,13 @@ TEST_CASE("TechsetDumperT5", "[t5][techset][dumper]") REQUIRE(file); REQUIRE(Trimmed(file->AsString()) == Trimmed(expected)); } + + SECTION("Can dump shaders") + { + dumper.Dump(context); + EnsureDumpedShaderMatchesInputData(mockOutput, "vs_simple.hlsl.cso"); + EnsureDumpedShaderMatchesInputData(mockOutput, "ps_simple.hlsl.cso"); + EnsureDumpedShaderMatchesInputData(mockOutput, "vs_advanced.hlsl.cso"); + EnsureDumpedShaderMatchesInputData(mockOutput, "ps_advanced.hlsl.cso"); + } }