diff --git a/src/ObjCommon/Techset/CommonTechnique.cpp b/src/ObjCommon/Techset/CommonTechnique.cpp index d06c3f91..f719d37d 100644 --- a/src/ObjCommon/Techset/CommonTechnique.cpp +++ b/src/ObjCommon/Techset/CommonTechnique.cpp @@ -208,6 +208,48 @@ namespace techset return std::nullopt; } + CommonShaderArg::CommonShaderArg(const CommonShaderArgumentType type, const CommonShaderArgDestination& destination, const CommonShaderArgValue& value) + : m_type(type), + m_destination(destination), + m_value(value) + { + } + + CommonCodeSourceUpdateFrequency CommonShaderArg::GetFrequency(const CommonCodeSourceInfos& infos) const + { + switch (m_type.m_value_type) + { + case CommonShaderValueType::CODE_CONST: + { + const auto info = infos.GetInfoForCodeConstSource(m_value.code_const_source.m_index); + assert(info); + return info->updateFrequency; + } + + case CommonShaderValueType::CODE_SAMPLER: + { + const auto info = infos.GetInfoForCodeSamplerSource(m_value.code_sampler_source); + assert(info); + return info->updateFrequency; + } + + case CommonShaderValueType::MATERIAL_CONST: + case CommonShaderValueType::LITERAL_CONST: + case CommonShaderValueType::MATERIAL_SAMPLER: + return CommonCodeSourceUpdateFrequency::RARELY; + + default: + assert(false); + return CommonCodeSourceUpdateFrequency::RARELY; + } + } + + CommonStreamRouting::CommonStreamRouting(const CommonStreamSource source, const CommonStreamDestination destination) + : m_source(source), + m_destination(destination) + { + } + CommonVertexDeclaration::CommonVertexDeclaration(std::vector routing) : m_routing(std::move(routing)) { @@ -221,4 +263,52 @@ namespace techset return r1.m_source < r2.m_source; }); } + + CommonTechniqueShader::CommonTechniqueShader() + : m_type(CommonTechniqueShaderType::VERTEX) + { + } + + CommonTechniqueShader::CommonTechniqueShader(const CommonTechniqueShaderType type, std::string name) + : m_type(type), + m_name(std::move(name)) + { + } + + CommonPass::CommonPass(const uint32_t samplerFlags, + std::string stateMap, + CommonTechniqueShader vertexShader, + CommonTechniqueShader pixelShader, + CommonVertexDeclaration vertexDeclaration) + : m_sampler_flags(samplerFlags), + m_state_map(std::move(stateMap)), + m_vertex_shader(std::move(vertexShader)), + m_pixel_shader(std::move(pixelShader)), + m_vertex_declaration(std::move(vertexDeclaration)) + { + } + + CommonPass::FrequencyCounts_t CommonPass::GetFrequencyCounts(const CommonCodeSourceInfos& infos) const + { + FrequencyCounts_t result; + for (auto& count : result) + count = 0; + + for (auto& arg : m_args) + result[std::to_underlying(arg.GetFrequency(infos))]++; + + return result; + } + + CommonTechnique::CommonTechnique(std::string name) + : m_name(std::move(name)), + m_flags(0) + { + } + + CommonTechnique::CommonTechnique(std::string name, const uint64_t flags) + : m_name(std::move(name)), + m_flags(flags) + { + } } // namespace techset diff --git a/src/ObjCommon/Techset/CommonTechnique.h b/src/ObjCommon/Techset/CommonTechnique.h index 09cc2bef..ab8950d6 100644 --- a/src/ObjCommon/Techset/CommonTechnique.h +++ b/src/ObjCommon/Techset/CommonTechnique.h @@ -172,10 +172,17 @@ namespace techset std::unordered_map m_destination_abbreviation_lookup; }; + struct CommonShaderArgCodeConstValue + { + CommonCodeConstSource m_index; + unsigned m_first_row; + unsigned m_row_count; + }; + union CommonShaderArgValue { std::array literal_value; - CommonCodeConstSource code_const_source; + CommonShaderArgCodeConstValue code_const_source; CommonCodeSamplerSource code_sampler_source; unsigned name_hash; }; @@ -186,12 +193,23 @@ namespace techset unsigned m_destination_register; }; + // In case of a constant: Offset in constant buffer + // In case of a sampler: Index of sampler + index of texture + union CommonShaderArgLocationDx11 + { + unsigned constant_buffer_offset; + + struct + { + unsigned texture_index; + unsigned sampler_index; + }; + }; + class CommonShaderArgDestinationDx11 { public: - // In case of a constant: Offset in constant buffer - // In case of a sampler: Index of sampler - unsigned m_location; + CommonShaderArgLocationDx11 m_location; unsigned m_size; unsigned m_buffer; }; @@ -202,31 +220,26 @@ namespace techset CommonShaderArgDestinationDx11 dx11; }; - enum class CommonShaderArgType : std::uint8_t - { - // Value is set to a float4 value in the pass - LITERAL_CONST, - // Value is set to a float4 value in the material - MATERIAL_CONST, - // Value is set to a float4 value calculated in code - CODE_CONST, - // Value is set to a sampler from the material - MATERIAL_SAMPLER, - // Value is set to a sampler generated in code - CODE_SAMPLER - }; - class CommonShaderArg { public: - CommonShaderArgType m_type; + CommonShaderArg() = default; + CommonShaderArg(CommonShaderArgumentType type, const CommonShaderArgDestination& destination, const CommonShaderArgValue& value); + + [[nodiscard]] CommonCodeSourceUpdateFrequency GetFrequency(const CommonCodeSourceInfos& infos) const; + + CommonShaderArgumentType m_type; CommonShaderArgDestination m_destination; CommonShaderArgValue m_value; + std::optional m_bin; }; class CommonStreamRouting { public: + CommonStreamRouting() = default; + CommonStreamRouting(CommonStreamSource source, CommonStreamDestination destination); + CommonStreamSource m_source; CommonStreamDestination m_destination; }; @@ -242,36 +255,61 @@ namespace techset std::vector m_routing; }; + class CommonTechniqueShaderBin + { + public: + const void* m_shader_bin; + size_t m_shader_bin_size; + }; + class CommonTechniqueShader { public: + CommonTechniqueShader(); + CommonTechniqueShader(CommonTechniqueShaderType type, std::string name); + + CommonTechniqueShaderType m_type; std::string m_name; - const void* m_shader_bin; - size_t m_shader_bin_size; + std::optional m_bin; + }; + + class CommonPass + { + public: + using FrequencyCounts_t = std::array; + + CommonPass() = default; + CommonPass(uint32_t samplerFlags, + std::string stateMap, + CommonTechniqueShader vertexShader, + CommonTechniqueShader pixelShader, + CommonVertexDeclaration vertexDeclaration); + + [[nodiscard]] FrequencyCounts_t GetFrequencyCounts(const CommonCodeSourceInfos& infos) const; + + uint32_t m_sampler_flags; + std::string m_state_map; + CommonTechniqueShader m_vertex_shader; + CommonTechniqueShader m_pixel_shader; + CommonVertexDeclaration m_vertex_declaration; std::vector m_args; }; + class CommonTechnique + { + public: + CommonTechnique() = default; + explicit CommonTechnique(std::string name); + CommonTechnique(std::string name, uint64_t flags); + + std::string m_name; + uint64_t m_flags; + std::vector m_passes; + }; + enum class DxVersion : std::uint8_t { DX9, DX11 }; - - class CommonPass - { - public: - uint32_t m_sampler_flags; - DxVersion m_dx_version; - CommonTechniqueShader m_vertex_shader; - CommonTechniqueShader m_pixel_shader; - CommonVertexDeclaration m_vertex_declaration; - }; - - class CommonTechnique - { - public: - std::string m_name; - uint64_t m_flags; - std::vector m_passes; - }; } // namespace techset diff --git a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp index 3b05e895..30dcaf02 100644 --- a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp @@ -9,7 +9,6 @@ #include "Techset/TechniqueDumpingZoneState.h" #include -#include using namespace T5; @@ -67,10 +66,8 @@ namespace for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++) { const auto& routing = vertexDecl->routing.data[streamIndex]; - commonRouting.emplace_back(techset::CommonStreamRouting{ - .m_source = static_cast(routing.source), - .m_destination = static_cast(routing.dest), - }); + commonRouting.emplace_back(static_cast(routing.source), + static_cast(routing.dest)); } } @@ -79,92 +76,72 @@ namespace techset::CommonShaderArg ConvertToCommonArg(const MaterialShaderArgument& arg) { + const techset::CommonShaderArgDestination destination{.dx9 = {.m_destination_register = arg.dest}}; + switch (arg.type) { case MTL_ARG_CODE_VERTEX_CONST: case MTL_ARG_CODE_PIXEL_CONST: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::CODE_CONST, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .code_const_source = static_cast(arg.u.codeConst.index), - } + { + const techset::CommonShaderArgCodeConstValue codeConstValue{ + .m_index = static_cast(arg.u.codeConst.index), + .m_first_row = arg.u.codeConst.firstRow, + .m_row_count = arg.u.codeConst.rowCount, }; + const techset::CommonShaderArgValue value{.code_const_source = codeConstValue}; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } case MTL_ARG_MATERIAL_VERTEX_CONST: case MTL_ARG_MATERIAL_PIXEL_CONST: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::MATERIAL_CONST, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .name_hash = arg.u.nameHash, - } + { + const techset::CommonShaderArgValue value{ + .name_hash = arg.u.nameHash, }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } + case MTL_ARG_CODE_PIXEL_SAMPLER: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::CODE_SAMPLER, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .code_sampler_source = static_cast(arg.u.codeSampler), - } + { + const techset::CommonShaderArgValue value{ + .code_sampler_source = static_cast(arg.u.codeSampler), }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } + case MTL_ARG_MATERIAL_PIXEL_SAMPLER: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::MATERIAL_SAMPLER, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .name_hash = arg.u.nameHash, - } + { + const techset::CommonShaderArgValue value{ + .name_hash = arg.u.nameHash, }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } + default: case MTL_ARG_LITERAL_VERTEX_CONST: case MTL_ARG_LITERAL_PIXEL_CONST: + { + techset::CommonShaderArgValue value{}; if (arg.u.literalConst) { - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::LITERAL_CONST, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .literal_value = - { - (*arg.u.literalConst)[0], - (*arg.u.literalConst)[1], - (*arg.u.literalConst)[2], - (*arg.u.literalConst)[3], - }, } + value.literal_value = { + (*arg.u.literalConst)[0], + (*arg.u.literalConst)[1], + (*arg.u.literalConst)[2], + (*arg.u.literalConst)[3], }; } - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::LITERAL_CONST, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = {}, - }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } } } - techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPass& pass, const MaterialVertexShader* vertexShader) + techset::CommonTechniqueShader ConvertToCommonShader(const MaterialVertexShader* vertexShader) { techset::CommonTechniqueShader result{}; if (!vertexShader) @@ -175,34 +152,16 @@ namespace if (vertexShader->prog.loadDef.program) { - result.m_shader_bin = vertexShader->prog.loadDef.program; - result.m_shader_bin_size = vertexShader->prog.loadDef.programSize * sizeof(uint32_t); - } - - if (pass.args) - { - const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; - for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - - switch (arg.type) - { - case MTL_ARG_CODE_VERTEX_CONST: - case MTL_ARG_MATERIAL_VERTEX_CONST: - case MTL_ARG_LITERAL_VERTEX_CONST: - result.m_args.emplace_back(ConvertToCommonArg(arg)); - break; - default: - break; - } - } + result.m_bin = techset::CommonTechniqueShaderBin{ + .m_shader_bin = vertexShader->prog.loadDef.program, + .m_shader_bin_size = vertexShader->prog.loadDef.programSize * sizeof(uint32_t), + }; } return result; } - techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPass& pass, const MaterialPixelShader* pixelShader) + techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPixelShader* pixelShader) { techset::CommonTechniqueShader result{}; if (!pixelShader) @@ -213,30 +172,10 @@ namespace if (pixelShader->prog.loadDef.program) { - result.m_shader_bin = pixelShader->prog.loadDef.program; - result.m_shader_bin_size = pixelShader->prog.loadDef.programSize * sizeof(uint32_t); - } - - if (pass.args) - { - const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; - for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - - switch (arg.type) - { - case MTL_ARG_CODE_PIXEL_CONST: - case MTL_ARG_CODE_PIXEL_SAMPLER: - case MTL_ARG_MATERIAL_PIXEL_CONST: - case MTL_ARG_MATERIAL_PIXEL_SAMPLER: - case MTL_ARG_LITERAL_PIXEL_CONST: - result.m_args.emplace_back(ConvertToCommonArg(arg)); - break; - default: - break; - } - } + result.m_bin = techset::CommonTechniqueShaderBin{ + .m_shader_bin = pixelShader->prog.loadDef.program, + .m_shader_bin_size = pixelShader->prog.loadDef.programSize * sizeof(uint32_t), + }; } return result; @@ -244,26 +183,30 @@ namespace techset::CommonTechnique ConvertToCommonTechnique(const MaterialTechnique& technique) { - std::vector passes; + techset::CommonTechnique commonTechnique(technique.name ? technique.name : std::string(), technique.flags); for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) { const auto& pass = technique.passArray[passIndex]; + techset::CommonPass commonPass(pass.customSamplerFlags, + // No clue what the actual state map was + "passthrough", + ConvertToCommonShader(pass.vertexShader), + ConvertToCommonShader(pass.pixelShader), + ConvertToCommonVertexDeclaration(pass.vertexDecl)); - passes.emplace_back(techset::CommonPass{ - .m_sampler_flags = pass.customSamplerFlags, - .m_dx_version = techset::DxVersion::DX9, - .m_vertex_shader = ConvertToCommonShader(pass, pass.vertexShader), - .m_pixel_shader = ConvertToCommonShader(pass, pass.pixelShader), - .m_vertex_declaration = ConvertToCommonVertexDeclaration(pass.vertexDecl), - }); + if (pass.args) + { + const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; + commonPass.m_args.reserve(totalArgCount); + for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) + commonPass.m_args.emplace_back(ConvertToCommonArg(pass.args[argIndex])); + } + + commonTechnique.m_passes.emplace_back(std::move(commonPass)); } - return techset::CommonTechnique{ - .m_name = technique.name ? technique.name : std::string(), - .m_flags = technique.flags, - .m_passes = std::move(passes), - }; + return commonTechnique; } void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset) @@ -276,7 +219,8 @@ namespace { const auto commonTechnique = ConvertToCommonTechnique(*technique); - techset::DumpCommonTechnique(context, commonTechnique, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); + techset::DumpCommonTechnique( + context, commonTechnique, techset::DxVersion::DX9, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); } } } diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index 035ada88..e696658e 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -8,7 +8,7 @@ #include "Techset/ShaderDumpingZoneState.h" #include "Techset/TechniqueDumpingZoneState.h" -#include +#include using namespace T6; @@ -66,10 +66,8 @@ namespace for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++) { const auto& routing = vertexDecl->routing.data[streamIndex]; - commonRouting.emplace_back(techset::CommonStreamRouting{ - .m_source = static_cast(routing.source), - .m_destination = static_cast(routing.dest), - }); + commonRouting.emplace_back(static_cast(routing.source), + static_cast(routing.dest)); } } @@ -82,100 +80,119 @@ namespace { case MTL_ARG_CODE_VERTEX_CONST: case MTL_ARG_CODE_PIXEL_CONST: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::CODE_CONST, - .m_destination = {.dx11 = - { - .m_location = arg.location.offset, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .code_const_source = static_cast(arg.u.codeConst.index), - } + { + const techset::CommonShaderArgCodeConstValue codeConstValue{ + .m_index = static_cast(arg.u.codeConst.index), + .m_first_row = arg.u.codeConst.firstRow, + .m_row_count = arg.u.codeConst.rowCount, }; + const techset::CommonShaderArgValue value{.code_const_source = codeConstValue}; + const techset::CommonShaderArgLocationDx11 location{ + .constant_buffer_offset = arg.location.offset, + }; + const techset::CommonShaderArgDestination destination = { + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } + }; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } case MTL_ARG_MATERIAL_VERTEX_CONST: case MTL_ARG_MATERIAL_PIXEL_CONST: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::MATERIAL_CONST, - .m_destination = {.dx11 = - { - .m_location = arg.location.offset, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .name_hash = arg.u.nameHash, - } + { + const techset::CommonShaderArgValue value{ + .name_hash = arg.u.nameHash, }; + const techset::CommonShaderArgLocationDx11 location{ + .constant_buffer_offset = arg.location.offset, + }; + const techset::CommonShaderArgDestination destination{ + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } + }; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } case MTL_ARG_CODE_PIXEL_SAMPLER: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::CODE_SAMPLER, - .m_destination = {.dx11 = - { - .m_location = arg.location.samplerIndex, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .code_sampler_source = static_cast(arg.u.codeSampler), - } + { + const techset::CommonShaderArgValue value{ + .code_sampler_source = static_cast(arg.u.codeSampler), + }; + const techset::CommonShaderArgLocationDx11 location{ + .texture_index = arg.location.textureIndex, + .sampler_index = arg.location.samplerIndex, + }; + const techset::CommonShaderArgDestination destination = { + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } + case MTL_ARG_MATERIAL_PIXEL_SAMPLER: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::MATERIAL_SAMPLER, - .m_destination = {.dx11 = - { - .m_location = arg.location.samplerIndex, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .name_hash = arg.u.nameHash, - } + { + const techset::CommonShaderArgValue value{ + .name_hash = arg.u.nameHash, }; + const techset::CommonShaderArgLocationDx11 location{ + .texture_index = arg.location.textureIndex, + .sampler_index = arg.location.samplerIndex, + }; + const techset::CommonShaderArgDestination destination = { + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } + }; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } default: case MTL_ARG_LITERAL_VERTEX_CONST: case MTL_ARG_LITERAL_PIXEL_CONST: + { + techset::CommonShaderArgValue value{}; if (arg.u.literalConst) { - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::LITERAL_CONST, - .m_destination = {.dx11 = - { - .m_location = arg.location.offset, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .literal_value = - { - (*arg.u.literalConst)[0], - (*arg.u.literalConst)[1], - (*arg.u.literalConst)[2], - (*arg.u.literalConst)[3], - }, } + value.literal_value = { + (*arg.u.literalConst)[0], + (*arg.u.literalConst)[1], + (*arg.u.literalConst)[2], + (*arg.u.literalConst)[3], }; } - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::LITERAL_CONST, - .m_destination = {.dx11 = - { - .m_location = arg.location.offset, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = {}, + const techset::CommonShaderArgLocationDx11 location{ + .constant_buffer_offset = arg.location.offset, }; + const techset::CommonShaderArgDestination destination = { + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } + }; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } } } - techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPass& pass, const MaterialVertexShader* vertexShader) + techset::CommonTechniqueShader ConvertToCommonShader(const MaterialVertexShader* vertexShader) { techset::CommonTechniqueShader result{}; if (!vertexShader) @@ -186,34 +203,16 @@ namespace if (vertexShader->prog.loadDef.program) { - result.m_shader_bin = vertexShader->prog.loadDef.program; - result.m_shader_bin_size = vertexShader->prog.loadDef.programSize; - } - - if (pass.args) - { - const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; - for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - - switch (arg.type) - { - case MTL_ARG_CODE_VERTEX_CONST: - case MTL_ARG_MATERIAL_VERTEX_CONST: - case MTL_ARG_LITERAL_VERTEX_CONST: - result.m_args.emplace_back(ConvertToCommonArg(arg)); - break; - default: - break; - } - } + result.m_bin = techset::CommonTechniqueShaderBin{ + .m_shader_bin = vertexShader->prog.loadDef.program, + .m_shader_bin_size = vertexShader->prog.loadDef.programSize, + }; } return result; } - techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPass& pass, const MaterialPixelShader* pixelShader) + techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPixelShader* pixelShader) { techset::CommonTechniqueShader result{}; if (!pixelShader) @@ -224,30 +223,10 @@ namespace if (pixelShader->prog.loadDef.program) { - result.m_shader_bin = pixelShader->prog.loadDef.program; - result.m_shader_bin_size = pixelShader->prog.loadDef.programSize; - } - - if (pass.args) - { - const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; - for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - - switch (arg.type) - { - case MTL_ARG_CODE_PIXEL_CONST: - case MTL_ARG_CODE_PIXEL_SAMPLER: - case MTL_ARG_MATERIAL_PIXEL_CONST: - case MTL_ARG_MATERIAL_PIXEL_SAMPLER: - case MTL_ARG_LITERAL_PIXEL_CONST: - result.m_args.emplace_back(ConvertToCommonArg(arg)); - break; - default: - break; - } - } + result.m_bin = techset::CommonTechniqueShaderBin{ + .m_shader_bin = pixelShader->prog.loadDef.program, + .m_shader_bin_size = pixelShader->prog.loadDef.programSize, + }; } return result; @@ -255,26 +234,30 @@ namespace techset::CommonTechnique ConvertToCommonTechnique(const MaterialTechnique& technique) { - std::vector passes; + techset::CommonTechnique commonTechnique(technique.name ? technique.name : std::string(), technique.flags); for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) { const auto& pass = technique.passArray[passIndex]; + techset::CommonPass commonPass(pass.customSamplerFlags, + // No clue what the actual state map was + "passthrough", + ConvertToCommonShader(pass.vertexShader), + ConvertToCommonShader(pass.pixelShader), + ConvertToCommonVertexDeclaration(pass.vertexDecl)); - passes.emplace_back(techset::CommonPass{ - .m_sampler_flags = pass.customSamplerFlags, - .m_dx_version = techset::DxVersion::DX11, - .m_vertex_shader = ConvertToCommonShader(pass, pass.vertexShader), - .m_pixel_shader = ConvertToCommonShader(pass, pass.pixelShader), - .m_vertex_declaration = ConvertToCommonVertexDeclaration(pass.vertexDecl), - }); + if (pass.args) + { + const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; + commonPass.m_args.reserve(totalArgCount); + for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) + commonPass.m_args.emplace_back(ConvertToCommonArg(pass.args[argIndex])); + } + + commonTechnique.m_passes.emplace_back(std::move(commonPass)); } - return techset::CommonTechnique{ - .m_name = technique.name ? technique.name : std::string(), - .m_flags = technique.flags, - .m_passes = std::move(passes), - }; + return commonTechnique; } void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset) @@ -287,7 +270,8 @@ namespace { const auto commonTechnique = ConvertToCommonTechnique(*technique); - techset::DumpCommonTechnique(context, commonTechnique, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); + techset::DumpCommonTechnique( + context, commonTechnique, techset::DxVersion::DX11, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); } } } diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp index d50942ab..b43b626c 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -13,20 +13,16 @@ using namespace techset; namespace { - enum class TechniqueShaderType : std::uint8_t - { - VERTEX_SHADER, - PIXEL_SHADER - }; - class TechniqueFileWriter : public AbstractTextDumper { public: TechniqueFileWriter(std::ostream& stream, + const DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, const AbstractMaterialConstantZoneState& constantZoneState) : AbstractTextDumper(stream), + m_dx_version(dxVersion), m_code_source_infos(codeSourceInfos), m_routing_infos(routingInfos), m_constant_zone_state(constantZoneState) @@ -73,8 +69,8 @@ namespace #endif DumpStateMap(); - DumpShader(technique, pass.m_vertex_shader, TechniqueShaderType::VERTEX_SHADER, pass.m_dx_version); - DumpShader(technique, pass.m_pixel_shader, TechniqueShaderType::PIXEL_SHADER, pass.m_dx_version); + DumpShader(technique, pass, pass.m_vertex_shader, CommonTechniqueShaderType::VERTEX, m_dx_version); + DumpShader(technique, pass, pass.m_pixel_shader, CommonTechniqueShaderType::PIXEL, m_dx_version); DumpVertexDecl(pass.m_vertex_declaration); DecIndent(); @@ -89,9 +85,13 @@ namespace m_stream << "stateMap \"passthrough\"; // TODO\n"; } - void DumpShader(const CommonTechnique& technique, const CommonTechniqueShader& shader, const TechniqueShaderType shaderType, const DxVersion dxVersion) + void DumpShader(const CommonTechnique& technique, + const CommonPass& pass, + const CommonTechniqueShader& shader, + const CommonTechniqueShaderType shaderType, + const DxVersion dxVersion) { - if (!shader.m_shader_bin) + if (!shader.m_bin || !shader.m_bin->m_shader_bin) { if (!shader.m_name.empty()) { @@ -105,7 +105,7 @@ namespace unsigned versionMajor, versionMinor; if (dxVersion == DxVersion::DX9) { - const auto shaderInfo = d3d9::ShaderAnalyser::GetShaderInfo(shader.m_shader_bin, shader.m_shader_bin_size); + const auto shaderInfo = d3d9::ShaderAnalyser::GetShaderInfo(shader.m_bin->m_shader_bin, shader.m_bin->m_shader_bin_size); assert(shaderInfo); if (!shaderInfo) return; @@ -115,13 +115,16 @@ namespace DumpShaderHeader(shader, shaderType, versionMajor, versionMinor); - for (const auto& arg : shader.m_args) - DumpShaderArgDx9(technique, arg, *shaderInfo); + for (const auto& arg : pass.m_args) + { + if (arg.m_type.m_shader_type == shaderType) + DumpShaderArgDx9(technique, arg, *shaderInfo); + } } else { assert(dxVersion == DxVersion::DX11); - const auto shaderInfo = d3d11::ShaderAnalyser::GetShaderInfo(shader.m_shader_bin, shader.m_shader_bin_size); + const auto shaderInfo = d3d11::ShaderAnalyser::GetShaderInfo(shader.m_bin->m_shader_bin, shader.m_bin->m_shader_bin_size); assert(shaderInfo); if (!shaderInfo) return; @@ -131,8 +134,11 @@ namespace DumpShaderHeader(shader, shaderType, versionMajor, versionMinor); - for (const auto& arg : shader.m_args) - DumpShaderArgDx11(technique, arg, *shaderInfo); + for (const auto& arg : pass.m_args) + { + if (arg.m_type.m_shader_type == shaderType) + DumpShaderArgDx11(technique, arg, *shaderInfo); + } } DecIndent(); @@ -140,9 +146,9 @@ namespace m_stream << "}\n"; } - void DumpShaderHeader(const CommonTechniqueShader& shader, const TechniqueShaderType shaderType, unsigned versionMajor, unsigned versionMinor) + void DumpShaderHeader(const CommonTechniqueShader& shader, const CommonTechniqueShaderType shaderType, unsigned versionMajor, unsigned versionMinor) { - const auto shaderTypeName = shaderType == TechniqueShaderType::VERTEX_SHADER ? "vertexShader" : "pixelShader"; + const auto shaderTypeName = shaderType == CommonTechniqueShaderType::VERTEX ? "vertexShader" : "pixelShader"; m_stream << "\n"; Indent(); @@ -154,9 +160,10 @@ namespace void DumpShaderArgDx9(const CommonTechnique& technique, const CommonShaderArg& arg, const d3d9::ShaderInfo& shaderInfo) const { - const auto expectedRegisterSet = arg.m_type == CommonShaderArgType::CODE_SAMPLER || arg.m_type == CommonShaderArgType::MATERIAL_SAMPLER - ? d3d9::RegisterSet::SAMPLER - : d3d9::RegisterSet::FLOAT_4; + const auto expectedRegisterSet = + arg.m_type.m_value_type == CommonShaderValueType::CODE_SAMPLER || arg.m_type.m_value_type == CommonShaderValueType::MATERIAL_SAMPLER + ? d3d9::RegisterSet::SAMPLER + : d3d9::RegisterSet::FLOAT_4; const auto destinationRegister = arg.m_destination.dx9.m_destination_register; const auto targetShaderArg = std::ranges::find_if(shaderInfo.m_constants, [destinationRegister, expectedRegisterSet](const d3d9::ShaderConstant& constant) @@ -170,11 +177,11 @@ namespace if (targetShaderArg == shaderInfo.m_constants.end()) { Indent(); - m_stream << std::format("// Unrecognized arg dest: {} type: {}\n", destinationRegister, static_cast(arg.m_type)); + m_stream << std::format("// Unrecognized arg dest: {} type: {}\n", destinationRegister, static_cast(arg.m_type.m_value_type)); con::error("Technique {}: Could not find arg (type: {}; dest: {}) in shader", technique.m_name, destinationRegister, - static_cast(arg.m_type)); + static_cast(arg.m_type.m_value_type)); return; } @@ -186,14 +193,14 @@ namespace else codeDestAccessor = targetShaderArg->m_name; - DumpShaderArg(technique, arg, codeDestAccessor); + const auto isTransposed = targetShaderArg->m_class == d3d9::ParameterClass::MATRIX_COLUMNS; + DumpShaderArg(technique, arg, codeDestAccessor, isTransposed); } void DumpShaderArgDx11(const CommonTechnique& technique, const CommonShaderArg& arg, const d3d11::ShaderInfo& shaderInfo) const { const auto& destination = arg.m_destination.dx11; - if (arg.m_type == CommonShaderArgType::CODE_CONST || arg.m_type == CommonShaderArgType::MATERIAL_CONST - || arg.m_type == CommonShaderArgType::LITERAL_CONST) + if (IsConstValueType(arg.m_type.m_value_type)) { const auto boundResource = std::ranges::find_if(shaderInfo.m_bound_resources, [destination](const d3d11::BoundResource& resource) @@ -207,13 +214,13 @@ namespace Indent(); m_stream << std::format("// Could not find bound resource for arg buffer: {} offset: {} type: {}\n", destination.m_buffer, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.constant_buffer_offset, + static_cast(arg.m_type.m_value_type)); con::error("Technique {}: Could not find bound resource for arg (buffer: {} offset: {} type: {}) in shader", technique.m_name, destination.m_buffer, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.constant_buffer_offset, + static_cast(arg.m_type.m_value_type)); return; } const auto buffer = std::ranges::find_if(shaderInfo.m_constant_buffers, @@ -229,75 +236,112 @@ namespace return; } - const auto variable = std::ranges::find_if(buffer->m_variables, - [destination](const d3d11::ConstantBufferVariable& var) - { - return var.m_offset <= destination.m_location - && var.m_offset + var.m_size >= destination.m_location + destination.m_size; - }); + const auto variable = + std::ranges::find_if(buffer->m_variables, + [destination](const d3d11::ConstantBufferVariable& var) + { + return var.m_offset <= destination.m_location.constant_buffer_offset + && var.m_offset + var.m_size >= destination.m_location.constant_buffer_offset + destination.m_size; + }); if (variable == buffer->m_variables.end()) { Indent(); m_stream << std::format("// Could not find variable in buffer: {} offset: {} type: {}\n", buffer->m_name, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.constant_buffer_offset, + static_cast(arg.m_type.m_value_type)); con::error("Technique {}: Could not find variable in buffer for arg (buffer: {} offset: {} type: {}) in shader", technique.m_name, buffer->m_name, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.constant_buffer_offset, + static_cast(arg.m_type.m_value_type)); return; } - DumpShaderArg(technique, arg, variable->m_name); + std::string codeDestAccessor; + if (variable->m_element_count <= 1) + { + codeDestAccessor = variable->m_name; + } + else + { + const auto elementSize = variable->m_size / variable->m_element_count; + + // Assert destination is aligned with element size + assert((destination.m_location.constant_buffer_offset - variable->m_offset) % elementSize == 0); + + const auto destinationIndex = (destination.m_location.constant_buffer_offset - variable->m_offset) / elementSize; + + codeDestAccessor = std::format("{}[{}]", variable->m_name, destinationIndex); + } + + const auto isTransposed = variable->m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS; + DumpShaderArg(technique, arg, codeDestAccessor, isTransposed); } else { - assert(arg.m_type == CommonShaderArgType::CODE_SAMPLER || arg.m_type == CommonShaderArgType::MATERIAL_SAMPLER); + assert(IsSamplerValueType(arg.m_type.m_value_type)); - const auto boundResource = std::ranges::find_if(shaderInfo.m_bound_resources, - [destination](const d3d11::BoundResource& resource) - { - return (resource.m_type == d3d11::BoundResourceType::SAMPLER - || resource.m_type == d3d11::BoundResourceType::TEXTURE) - && resource.m_bind_point == destination.m_location; - }); - if (boundResource == shaderInfo.m_bound_resources.end()) + // The game seems to guarantee the texture name to be the accurate one + const auto boundTextureResource = std::ranges::find_if(shaderInfo.m_bound_resources, + [destination](const d3d11::BoundResource& resource) + { + if (resource.m_type == d3d11::BoundResourceType::TEXTURE) + return resource.m_bind_point == destination.m_location.texture_index; + + return false; + }); + if (boundTextureResource == shaderInfo.m_bound_resources.end()) { Indent(); - m_stream << std::format("// Could not find buffer for arg buffer: {} offset: {} type: {}\n", + m_stream << std::format("// Could not find buffer for arg buffer: {} sampler: {} texture: {} type: {}\n", destination.m_buffer, - destination.m_location, - static_cast(arg.m_type)); - con::error("Technique {}: Could not find buffer for arg (buffer: {} offset: {} type: {}) in shader", + destination.m_location.sampler_index, + destination.m_location.texture_index, + static_cast(arg.m_type.m_value_type)); + con::error("Technique {}: Could not find buffer for arg (buffer: {} sampler: {} texture: {} type: {}) in shader", technique.m_name, destination.m_buffer, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.sampler_index, + destination.m_location.texture_index, + static_cast(arg.m_type.m_value_type)); return; } - DumpShaderArg(technique, arg, boundResource->m_name); + DumpShaderArg(technique, arg, boundTextureResource->m_name, false); } } - void DumpShaderArg(const CommonTechnique& technique, const CommonShaderArg& arg, std::string codeDestAccessor) const + void DumpShaderArg(const CommonTechnique& technique, const CommonShaderArg& arg, std::string codeDestAccessor, const bool isTransposed) const { - if (arg.m_type == CommonShaderArgType::CODE_CONST) + if (arg.m_type.m_value_type == CommonShaderValueType::CODE_CONST) { - const auto constSourceInfo = m_code_source_infos.GetInfoForCodeConstSource(arg.m_value.code_const_source); + auto constSourceInfo = m_code_source_infos.GetInfoForCodeConstSource(arg.m_value.code_const_source.m_index); + + if (isTransposed) + { + assert(constSourceInfo); + if (constSourceInfo && constSourceInfo->transposedMatrix) + constSourceInfo = m_code_source_infos.GetInfoForCodeConstSource(*constSourceInfo->transposedMatrix); + } + if (constSourceInfo) { - if (codeDestAccessor != constSourceInfo->accessor) + std::string codeAccessor; + if (constSourceInfo->arrayCount <= 1) + codeAccessor = constSourceInfo->accessor; + else + codeAccessor = std::format("{}[{}]", constSourceInfo->accessor, arg.m_value.code_const_source.m_index - constSourceInfo->value); + + if (codeDestAccessor != codeAccessor) { Indent(); - m_stream << std::format("{} = constant.{};\n", codeDestAccessor, constSourceInfo->accessor); + m_stream << std::format("{} = constant.{};\n", codeDestAccessor, codeAccessor); } else { #ifdef TECHSET_DEBUG Indent(); - m_stream << std::format("// Omitted due to matching accessors: {} = constant.{};\n", codeDestAccessor, constSourceInfo->accessor); + m_stream << std::format("// Omitted due to matching accessors: {} = constant.{};\n", codeDestAccessor, codeAccessor); #endif } } @@ -309,7 +353,7 @@ namespace con::error("Technique {}: Could not find code source info for const {}", technique.m_name, codeDestAccessor); } } - else if (arg.m_type == CommonShaderArgType::CODE_SAMPLER) + else if (arg.m_type.m_value_type == CommonShaderValueType::CODE_SAMPLER) { const auto samplerSourceInfo = m_code_source_infos.GetInfoForCodeSamplerSource(arg.m_value.code_sampler_source); if (samplerSourceInfo) @@ -335,7 +379,7 @@ namespace con::error("Technique {}: Could not find code source info for sampler {}", technique.m_name, codeDestAccessor); } } - else if (arg.m_type == CommonShaderArgType::LITERAL_CONST) + else if (arg.m_type.m_value_type == CommonShaderValueType::LITERAL_CONST) { Indent(); m_stream << std::format("{} = float4({}, {}, {}, {});\n", @@ -345,7 +389,7 @@ namespace arg.m_value.literal_value[2], arg.m_value.literal_value[3]); } - else if (arg.m_type == CommonShaderArgType::MATERIAL_CONST || arg.m_type == CommonShaderArgType::MATERIAL_SAMPLER) + else if (arg.m_type.m_value_type == CommonShaderValueType::MATERIAL_CONST || arg.m_type.m_value_type == CommonShaderValueType::MATERIAL_SAMPLER) { Indent(); @@ -385,6 +429,7 @@ namespace } } + DxVersion m_dx_version; const CommonCodeSourceInfos& m_code_source_infos; const CommonStreamRoutingInfos& m_routing_infos; const AbstractMaterialConstantZoneState& m_constant_zone_state; @@ -395,6 +440,7 @@ namespace techset { void DumpCommonTechnique(const AssetDumpingContext& context, const CommonTechnique& technique, + const DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, const AbstractMaterialConstantZoneState& constantZoneState) @@ -402,7 +448,7 @@ namespace techset const auto techniqueFile = context.OpenAssetFile(GetFileNameForTechniqueName(technique.m_name)); if (techniqueFile) { - TechniqueFileWriter writer(*techniqueFile, codeSourceInfos, routingInfos, constantZoneState); + TechniqueFileWriter writer(*techniqueFile, dxVersion, codeSourceInfos, routingInfos, constantZoneState); writer.DumpTechnique(technique); } } diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.h b/src/ObjWriting/Techset/CommonTechniqueDumper.h index 4a3dc943..f2a6a4bd 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.h +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.h @@ -8,6 +8,7 @@ namespace techset { void DumpCommonTechnique(const AssetDumpingContext& context, const CommonTechnique& technique, + DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, const AbstractMaterialConstantZoneState& constantZoneState);