From 466d7ab0f28af68c2d469aadc7885190d1f266b1 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Thu, 13 Nov 2025 22:44:09 +0000 Subject: [PATCH] feat: dump material techniques for T6 --- src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp | 21 +-- src/ObjCommon/Shader/D3D11ShaderAnalyser.h | 13 +- src/ObjCommon/Shader/D3D9ShaderAnalyser.h | 9 +- src/ObjCommon/Techset/CommonTechnique.h | 13 +- .../Game/T6/Techset/TechsetDumperT6.cpp | 50 ++++-- .../Techset/CommonTechniqueDumper.cpp | 143 ++++++++++++++++++ .../Techset/CommonTechniqueDumper.h | 4 +- .../Techset/CommonTechsetDumper.cpp | 4 +- 8 files changed, 221 insertions(+), 36 deletions(-) diff --git a/src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp b/src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp index 4f4225e8..f866236f 100644 --- a/src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp +++ b/src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp @@ -32,14 +32,17 @@ namespace d3d11 m_flags(0u) { } +} // namespace d3d11 - static constexpr auto TAG_RDEF = FileUtils::MakeMagic32('R', 'D', 'E', 'F'); - static constexpr auto TAG_SHDR = FileUtils::MakeMagic32('S', 'H', 'D', 'R'); +namespace +{ + constexpr auto TAG_RDEF = FileUtils::MakeMagic32('R', 'D', 'E', 'F'); + constexpr auto TAG_SHDR = FileUtils::MakeMagic32('S', 'H', 'D', 'R'); - static constexpr auto VERSION_5_0 = 0x500; - static constexpr auto VERSION_5_1 = 0x501; - static constexpr auto TARGET_VERSION_MASK = 0xFFFF; - static constexpr auto CHUNK_TABLE_OFFSET = 28u; + constexpr auto VERSION_5_0 = 0x500; + constexpr auto VERSION_5_1 = 0x501; + constexpr auto TARGET_VERSION_MASK = 0xFFFF; + constexpr auto CHUNK_TABLE_OFFSET = 28u; struct FileRdefHeader { @@ -669,16 +672,16 @@ namespace d3d11 return true; } -} // namespace d3d11 +} // namespace -std::unique_ptr ShaderAnalyser::GetShaderInfo(const uint8_t* shader, const size_t shaderSize) +std::unique_ptr ShaderAnalyser::GetShaderInfo(const void* shader, const size_t shaderSize) { if (shader == nullptr || shaderSize == 0) return nullptr; auto shaderInfo = std::make_unique(); - if (!PopulateShaderInfoFromBytes(*shaderInfo, shader, shaderSize)) + if (!PopulateShaderInfoFromBytes(*shaderInfo, static_cast(shader), shaderSize)) return nullptr; return shaderInfo; diff --git a/src/ObjCommon/Shader/D3D11ShaderAnalyser.h b/src/ObjCommon/Shader/D3D11ShaderAnalyser.h index 59f9f9aa..e544fcea 100644 --- a/src/ObjCommon/Shader/D3D11ShaderAnalyser.h +++ b/src/ObjCommon/Shader/D3D11ShaderAnalyser.h @@ -1,12 +1,13 @@ #pragma once +#include #include #include #include namespace d3d11 { - enum class ShaderType + enum class ShaderType : std::uint8_t { UNKNOWN, PIXEL_SHADER, @@ -33,7 +34,7 @@ namespace d3d11 unsigned m_flags; }; - enum class ConstantBufferType + enum class ConstantBufferType : std::uint8_t { UNKNOWN, CBUFFER, @@ -59,7 +60,7 @@ namespace d3d11 std::vector m_variables; }; - enum class BoundResourceType + enum class BoundResourceType : std::uint8_t { UNKNOWN, CBUFFER, @@ -68,7 +69,7 @@ namespace d3d11 SAMPLER }; - enum class BoundResourceReturnType + enum class BoundResourceReturnType : std::uint8_t { UNKNOWN, UNORM, @@ -81,7 +82,7 @@ namespace d3d11 CONTINUED, }; - enum class BoundResourceDimension + enum class BoundResourceDimension : std::uint8_t { UNKNOWN, BUFFER, @@ -131,6 +132,6 @@ namespace d3d11 class ShaderAnalyser { public: - static std::unique_ptr GetShaderInfo(const uint8_t* shader, size_t shaderSize); + static std::unique_ptr GetShaderInfo(const void* shader, size_t shaderSize); }; } // namespace d3d11 diff --git a/src/ObjCommon/Shader/D3D9ShaderAnalyser.h b/src/ObjCommon/Shader/D3D9ShaderAnalyser.h index 7e186c8d..32f5c058 100644 --- a/src/ObjCommon/Shader/D3D9ShaderAnalyser.h +++ b/src/ObjCommon/Shader/D3D9ShaderAnalyser.h @@ -1,12 +1,13 @@ #pragma once +#include #include #include #include namespace d3d9 { - enum class ShaderType + enum class ShaderType : std::uint8_t { UNKNOWN, PIXEL_SHADER, @@ -14,7 +15,7 @@ namespace d3d9 }; // https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxregister-set - enum class RegisterSet + enum class RegisterSet : std::uint8_t { BOOL, INT_4, @@ -26,7 +27,7 @@ namespace d3d9 }; // https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxparameter-class - enum class ParameterClass + enum class ParameterClass : std::uint8_t { SCALAR, VECTOR, @@ -40,7 +41,7 @@ namespace d3d9 }; // https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxparameter-type - enum class ParameterType + enum class ParameterType : std::uint8_t { VOID, BOOL, diff --git a/src/ObjCommon/Techset/CommonTechnique.h b/src/ObjCommon/Techset/CommonTechnique.h index 22259f79..5f5a4835 100644 --- a/src/ObjCommon/Techset/CommonTechnique.h +++ b/src/ObjCommon/Techset/CommonTechnique.h @@ -10,15 +10,21 @@ namespace techset { public: std::string m_name; - uint32_t m_version_major; - uint32_t m_version_minor; + const void* m_shader_bin; + size_t m_shader_bin_size; + }; + + enum class DxVersion : std::uint8_t + { + DX9, + DX11 }; class CommonPass { public: - uint64_t m_flags; uint32_t m_sampler_flags; + DxVersion m_dx_version; CommonTechniqueShader m_vertex_shader; CommonTechniqueShader m_pixel_shader; }; @@ -26,6 +32,7 @@ namespace techset class CommonTechnique { public: + std::string m_name; uint64_t m_flags; std::vector m_passes; }; diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index b49c6b74..e3327ec7 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -6,7 +6,6 @@ #include "Techset/CommonTechsetDumper.h" #include "Techset/TechniqueDumpingZoneState.h" -#include #include using namespace T6; @@ -102,18 +101,51 @@ namespace techset::CommonTechnique ConvertToCommonTechnique(const MaterialTechnique& technique) { - std::vector techniqueNames(std::extent_v); + std::vector passes; - for (auto techniqueIndex = 0u; techniqueIndex < std::extent_v; techniqueIndex++) + for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) { - const auto* technique = techset.techniques[techniqueIndex]; - if (technique && technique->name) - techniqueNames[techniqueIndex] = technique->name; + const auto& pass = technique.passArray[passIndex]; + + techset::CommonTechniqueShader vertexShader{}; + techset::CommonTechniqueShader pixelShader{}; + + if (pass.vertexShader) + { + if (pass.vertexShader->name) + vertexShader.m_name = pass.vertexShader->name; + + if (pass.vertexShader->prog.loadDef.program) + { + vertexShader.m_shader_bin = pass.vertexShader->prog.loadDef.program; + vertexShader.m_shader_bin_size = pass.vertexShader->prog.loadDef.programSize * sizeof(uint32_t); + } + } + + if (pass.pixelShader) + { + if (pass.pixelShader->name) + pixelShader.m_name = pass.pixelShader->name; + + if (pass.pixelShader->prog.loadDef.program) + { + pixelShader.m_shader_bin = pass.pixelShader->prog.loadDef.program; + pixelShader.m_shader_bin_size = pass.pixelShader->prog.loadDef.programSize * sizeof(uint32_t); + } + } + + passes.emplace_back(techset::CommonPass{ + .m_sampler_flags = pass.customSamplerFlags, + .m_dx_version = techset::DxVersion::DX11, + .m_vertex_shader = vertexShader, + .m_pixel_shader = pixelShader, + }); } - return techset::CommonTechset{ - .m_name = techset.name, - .m_technique_names = std::move(techniqueNames), + return techset::CommonTechnique{ + .m_name = technique.name ? technique.name : std::string(), + .m_flags = technique.flags, + .m_passes = std::move(passes), }; } diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp index e69de29b..9e497da5 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -0,0 +1,143 @@ +#include "CommonTechniqueDumper.h" + +#include "Dumping/AbstractTextDumper.h" +#include "Shader/D3D11ShaderAnalyser.h" +#include "Shader/D3D9ShaderAnalyser.h" +#include "Techset/TechsetCommon.h" + +#include +#include + +using namespace techset; + +namespace +{ + enum class TechniqueShaderType : std::uint8_t + { + VERTEX_SHADER, + PIXEL_SHADER + }; + + class TechniqueFileWriter : public AbstractTextDumper + { + public: + explicit TechniqueFileWriter(std::ostream& stream) + : AbstractTextDumper(stream) + { + } + + void DumpTechnique(const CommonTechnique& technique) + { +#ifdef TECHSET_DEBUG + if (technique.m_flags) + { + for (auto i = 0u; i < sizeof(CommonTechnique::m_flags) * 8u; i++) + { + const auto mask = 1ui64 << i; + if (technique.m_flags & mask) + { + Indent(); + m_stream << std::format("// TECHNIQUE FLAGS: 0x{:x}\n", mask); + } + } + } +#endif + + for (const auto& pass : technique.m_passes) + DumpPass(pass); + } + + private: + void DumpPass(const CommonPass& pass) + { + m_stream << "{\n"; + IncIndent(); + +#ifdef TECHSET_DEBUG + for (auto i = 0u; i < sizeof(CommonPass::m_sampler_flags) * 8u; i++) + { + const auto mask = 1ui64 << i; + if (pass.m_sampler_flags & mask) + { + Indent(); + m_stream << std::format("// CUSTOM SAMPLER FLAGS: 0x{:x}\n", mask); + } + } +#endif + + DumpStateMap(); + DumpShader(pass, pass.m_vertex_shader, TechniqueShaderType::VERTEX_SHADER); + DumpShader(pass, pass.m_pixel_shader, TechniqueShaderType::PIXEL_SHADER); + // DumpVertexDecl(pass); + + DecIndent(); + m_stream << "}\n"; + } + + void DumpStateMap() const + { + Indent(); + // TODO: Actual statemap: Maybe find all materials using this techset and try to make out rules + // for the flags based on the statebitstable + m_stream << "stateMap \"passthrough\"; // TODO\n"; + } + + void DumpShader(const CommonPass& pass, const CommonTechniqueShader& shader, const TechniqueShaderType shaderType) const + { + if (!shader.m_shader_bin) + { + if (!shader.m_name.empty()) + m_stream << std::format("// Cannot dump shader {} as its data is not loaded\n", shader.m_name); + + return; + } + + unsigned versionMajor, versionMinor; + if (pass.m_dx_version == DxVersion::DX9) + { + const auto shaderInfo = d3d9::ShaderAnalyser::GetShaderInfo(shader.m_shader_bin, shader.m_shader_bin_size); + assert(shaderInfo); + if (!shaderInfo) + return; + + versionMajor = shaderInfo->m_version_major; + versionMinor = shaderInfo->m_version_minor; + } + else + { + assert(pass.m_dx_version == DxVersion::DX11); + const auto shaderInfo = d3d11::ShaderAnalyser::GetShaderInfo(shader.m_shader_bin, shader.m_shader_bin_size); + assert(shaderInfo); + if (!shaderInfo) + return; + + versionMajor = shaderInfo->m_version_major; + versionMinor = shaderInfo->m_version_minor; + } + + const auto shaderTypeName = shaderType == TechniqueShaderType::VERTEX_SHADER ? "vertexShader" : "pixelShader"; + + m_stream << "\n"; + Indent(); + m_stream << std::format("{} {}.{} \"{}\"\n", shaderTypeName, versionMajor, versionMinor, shader.m_name); + Indent(); + m_stream << "{\n"; + + Indent(); + m_stream << "}\n"; + } + }; +} // namespace + +namespace techset +{ + void DumpCommonTechnique(const AssetDumpingContext& context, const CommonTechnique& technique) + { + const auto techniqueFile = context.OpenAssetFile(GetFileNameForTechniqueName(technique.m_name)); + if (techniqueFile) + { + TechniqueFileWriter writer(*techniqueFile); + writer.DumpTechnique(technique); + } + } +} // namespace techset diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.h b/src/ObjWriting/Techset/CommonTechniqueDumper.h index 168c27b7..d541414a 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.h +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.h @@ -1,9 +1,9 @@ #pragma once #include "Dumping/AssetDumpingContext.h" -#include "Techset/CommonTechset.h" +#include "Techset/CommonTechnique.h" namespace techset { - void DumpCommonTechnique(const AssetDumpingContext& context, const CommonTechset& techset); + void DumpCommonTechnique(const AssetDumpingContext& context, const CommonTechnique& technique); } // namespace techset diff --git a/src/ObjWriting/Techset/CommonTechsetDumper.cpp b/src/ObjWriting/Techset/CommonTechsetDumper.cpp index d2c9b9db..8448cc4b 100644 --- a/src/ObjWriting/Techset/CommonTechsetDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechsetDumper.cpp @@ -1,7 +1,6 @@ #include "CommonTechsetDumper.h" #include "Dumping/AbstractTextDumper.h" -#include "Game/IW3/Material/MaterialConstantZoneStateIW3.h" #include "Techset/TechsetCommon.h" #include @@ -36,8 +35,7 @@ namespace dumpedTechniques[techniqueIndex] = true; WriteTechniqueType(techniqueIndex); - for (auto nextTechniqueIndex = techniqueIndex + 1; nextTechniqueIndex < std::extent_v; - nextTechniqueIndex++) + for (auto nextTechniqueIndex = techniqueIndex + 1; nextTechniqueIndex < techniqueCount; nextTechniqueIndex++) { if (techset.m_technique_names[nextTechniqueIndex] != technique) continue;