From 916fdf40af0ca6674899bc975850b692f699a198 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 8 Aug 2025 13:46:08 +0800 Subject: [PATCH] [Feat] (MG_Util/ShaderCompiler): extract global UBO offset from GL plain uniforms --- MobileGL/MG_Test/Program/ProgramTest.cpp | 19 ++++++- .../ShaderTranspiler/ShaderCompiler.cpp | 2 +- .../MG_Util/ShaderTranspiler/SpvcSession.cpp | 56 +++++++++++++------ .../MG_Util/ShaderTranspiler/SpvcSession.h | 24 +++++++- MobileGL/MG_Util/ShaderTranspiler/Types.h | 2 + 5 files changed, 81 insertions(+), 22 deletions(-) diff --git a/MobileGL/MG_Test/Program/ProgramTest.cpp b/MobileGL/MG_Test/Program/ProgramTest.cpp index aae50984..7a3b9fdd 100644 --- a/MobileGL/MG_Test/Program/ProgramTest.cpp +++ b/MobileGL/MG_Test/Program/ProgramTest.cpp @@ -287,6 +287,21 @@ TEST_F(ProgramTest, DecompProgram) { } } - auto ubo0 = sessions[0].GetShaderInterface(SPVC_RESOURCE_TYPE_UNIFORM_BUFFER); - auto ubo1 = sessions[1].GetShaderInterface(SPVC_RESOURCE_TYPE_UNIFORM_BUFFER); + auto& meta0 = sessions[0].GetMetadata(); + auto& meta1 = sessions[1].GetMetadata(); + + for (auto& [name, offset] : meta0.plainUniformOffsetsInUBO) { + printf("%s: \t%u\n", name.c_str(), offset); + } + + printf("\n"); + + for (auto& [name, offset] : meta1.plainUniformOffsetsInUBO) { + printf("%s: \t%u\n", name.c_str(), offset); + } + + EXPECT_EQ(meta0.plainUniformOffsetsInUBO.size(), meta1.plainUniformOffsetsInUBO.size()); + for (auto& [name, offset] : meta0.plainUniformOffsetsInUBO) { + EXPECT_EQ(offset, meta1.plainUniformOffsetsInUBO.at(name)); + } } diff --git a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp index 9d76a54c..a623cc28 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/ShaderCompiler.cpp @@ -137,7 +137,7 @@ namespace MobileGL { tshader->setAutoMapLocations(true); tshader->setAutoMapBindings(true); tshader->setEnvInputVulkanRulesRelaxed(); // using EXT_vulkan_glsl_relaxed for gl_VertexID and gl_InstanceID? - tshader->setGlobalUniformBlockName("MGL_GLOBAL_UBO"); + tshader->setGlobalUniformBlockName(GLOBAL_UBO_NAME); if (!tshader->parse(&GetTBuiltInResourceInstance(), 150, ECoreProfile, /*forceDefaultVersionAndProfile: */false, /*forwardCompatible: */true, EShMsgDefault)) { diff --git a/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp b/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp index cb6aff33..b229bcb3 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp +++ b/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.cpp @@ -54,32 +54,52 @@ namespace ShaderTranspiler { var.name = list[i].name; var.location = spvc_compiler_get_decoration(compiler, list[i].id, SpvDecorationLocation); variables.push_back(var); - - if (resource_type == SPVC_RESOURCE_TYPE_UNIFORM_BUFFER) { - spvc_type type = spvc_compiler_get_type_handle(compiler, list[i].base_type_id); - size_t num_members = spvc_type_get_num_member_types(type); - printf("uniform %s {\n", var.name.c_str()); - for (size_t j = 0; j < num_members; ++j) { - const char *memberName = spvc_compiler_get_member_name(compiler, list[i].base_type_id, j); - // auto memberTypeId = spvc_type_get_member_type(type, j); - // auto memberType = spvc_compiler_get_type_handle(compiler, memberTypeId); - - unsigned memberOffset = 0; - spvc_compiler_type_struct_member_offset(compiler, type, j, &memberOffset); - printf("\b%s; // %u\n", memberName, memberOffset); - } - printf("}\n"); - } } std::sort(variables.begin(), variables.end()); return variables; } - spvc_result SpvcSession::Compile(const char** result) const { - return spvc_compiler_compile(compiler, result); + spvc_result SpvcSession::Compile(const char** result) { + SPVC_CHK_INIT + SPVC_CHK_RESULT(spvc_compiler_compile(compiler, result)); + SPVC_CHK_RESULT(ParseMetaData()); + SPVC_CHK_RETURN } + spvc_result SpvcSession::ParseMetaData() { + SPVC_CHK_INIT + metadata = SpvcMetadata(); + + const spvc_reflected_resource *list = nullptr; + size_t count = 0; + + SPVC_CHK_RESULT( + spvc_resources_get_resource_list_for_type(resources, SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, &list, &count); + ) + for (size_t i = 0; i < count; ++i) { + if (spvc_compiler_has_decoration(compiler, list[i].id, SpvDecorationBuiltIn)) { + continue; + } + + if (strcmp(list[i].name, GLOBAL_UBO_NAME) == 0) { + spvc_type type = spvc_compiler_get_type_handle(compiler, list[i].base_type_id); + size_t num_members = spvc_type_get_num_member_types(type); + for (size_t j = 0; j < num_members; ++j) { + const char *memberName = spvc_compiler_get_member_name(compiler, list[i].base_type_id, j); + + unsigned memberOffset = 0; + SPVC_CHK_RESULT(spvc_compiler_type_struct_member_offset(compiler, type, j, &memberOffset);) + metadata.plainUniformOffsetsInUBO[memberName] = memberOffset; + } + } + } + SPVC_CHK_RETURN + } + + const SpvcMetadata& SpvcSession::GetMetadata() const { + return metadata; + } const char* SpvcSession::GetLastErrorString() const { return spvc_context_get_last_error_string(context); diff --git a/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.h b/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.h index 9ecf7189..2d3a3f1f 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.h +++ b/MobileGL/MG_Util/ShaderTranspiler/SpvcSession.h @@ -7,9 +7,25 @@ #pragma once +#define SPVC_CHK_INIT \ + auto __r = SPVC_SUCCESS; + +#define SPVC_CHK_RESULT(res) \ + __r = res; \ + if (__r != SPVC_SUCCESS) { \ + return __r; \ + } + +#define SPVC_CHK_RETURN \ + return __r; + namespace MobileGL { namespace MG_Util { namespace ShaderTranspiler { + struct SpvcMetadata { + UnorderedMap plainUniformOffsetsInUBO; + }; + class SpvcSession { public: SpvcSession() {} @@ -29,15 +45,21 @@ namespace ShaderTranspiler { spvc_result CreateOptions(spvc_compiler_options *options); spvc_result SetOptions(spvc_compiler_options options); Vector GetShaderInterface(spvc_resource_type resource_type) const; - spvc_result Compile(const char** result) const; + spvc_result Compile(const char** result); + const SpvcMetadata& GetMetadata() const; const char* GetLastErrorString() const; private: + // Should be called once, and only once, for every SPIR-V binary + spvc_result ParseMetaData(); + spvc_context context = nullptr; spvc_parsed_ir ir = nullptr; spvc_compiler compiler = nullptr; spvc_compiler_options compiler_options = nullptr; spvc_resources resources = nullptr; + + SpvcMetadata metadata; }; } } diff --git a/MobileGL/MG_Util/ShaderTranspiler/Types.h b/MobileGL/MG_Util/ShaderTranspiler/Types.h index 788873c9..e9276194 100644 --- a/MobileGL/MG_Util/ShaderTranspiler/Types.h +++ b/MobileGL/MG_Util/ShaderTranspiler/Types.h @@ -4,6 +4,8 @@ namespace MobileGL { namespace MG_Util { namespace ShaderTranspiler { + inline const char* GLOBAL_UBO_NAME = "MGL_GLOBAL_UBO"; + struct EmptyType {}; struct ShaderAttrib {