[Fix] (MG_Util/ShaderTranspiler): keep decomposed workgroup types before globals

This commit is contained in:
2026-07-06 03:58:26 +08:00
parent d35e452368
commit 0bee379b61
2 changed files with 46 additions and 2 deletions
+10 -2
View File
@@ -822,6 +822,10 @@ layout(std430, binding = 0) writeonly buffer OutputBuffer {
vec4 out_data[];
};
vec3 evaluate_row(vec3 row_values[9], uint col) {
return row_values[col] + row_values[0];
}
void main() {
uint row = gl_LocalInvocationIndex;
uint col = u_col;
@@ -837,7 +841,7 @@ void main() {
memoryBarrierShared();
barrier();
out_data[gl_GlobalInvocationID.x] = vec4(loaded + rowCopy[col] + vec3(x), 1.0);
out_data[gl_GlobalInvocationID.x] = vec4(loaded + rowCopy[col] + evaluate_row(shared_memory[0], col) + vec3(x), 1.0);
}
)";
@@ -874,13 +878,17 @@ TEST_F(ProgramUtilTest, DecomposeWorkgroupVec3InSpirvPass) {
<< "SanitizeAndOptimizeBinary failed - the DecomposeWorkgroupVec3Pass may have "
"encountered an unsupported pattern";
spvtools::Optimizer parseOnlyOptimizer(SPV_ENV_VULKAN_1_1);
Vector<uint32_t> parsedBinary;
ASSERT_TRUE(parseOnlyOptimizer.Run(optimized.data(), optimized.size(), &parsedBinary))
<< "DecomposeWorkgroupVec3Pass emitted SPIR-V with invalid physical layout";
SpvcSession session(optimized, SessionUsageBit::Transpile);
auto sourceRes = ShaderCompiler::DecompileShader(session);
ASSERT_TRUE(sourceRes.has_value()) << "errc: " << sourceRes.error().errc
<< "\nlog: " << sourceRes.error().log;
const String& source = sourceRes.value();
// The decomposed output must not contain a `shared vec3` declaration.
EXPECT_EQ(source.find("shared vec3"), std::string::npos)
<< "DecomposeWorkgroupVec3Pass did not eliminate `shared vec3`:\n"
@@ -13,6 +13,7 @@
#include "source/opt/instruction.h"
#include "source/opt/ir_context.h"
#include "source/opt/module.h"
#include "source/opt/reflect.h"
#include "source/opt/type_manager.h"
#include "spirv.hpp"
@@ -308,6 +309,39 @@ namespace MobileGL {
assert(false && "DecomposeWorkgroupVec3Pass: unsupported composite store type");
}
void MoveLateTypesConstantsBeforeGlobalVariables(IRContext* context) {
Instruction* firstVariable = nullptr;
for (Instruction& inst : context->module()->types_values()) {
if (inst.opcode() == spv::Op::OpVariable) {
firstVariable = &inst;
break;
}
}
if (firstVariable == nullptr) {
return;
}
bool sawFirstVariable = false;
for (auto it = context->module()->types_values_begin();
it != context->module()->types_values_end();) {
Instruction* inst = &*it;
++it;
if (inst == firstVariable) {
sawFirstVariable = true;
continue;
}
if (sawFirstVariable &&
(spvtools::opt::IsTypeInst(inst->opcode()) ||
spvtools::opt::IsConstantInst(inst->opcode()) ||
inst->opcode() == spv::Op::OpUndef)) {
inst->InsertBefore(firstVariable);
}
}
}
} // namespace
spvtools::opt::Pass::Status DecomposeWorkgroupVec3Pass::Process() {
@@ -605,6 +639,8 @@ namespace MobileGL {
}
}
MoveLateTypesConstantsBeforeGlobalVariables(ctx);
return Status::SuccessWithChange;
}