[Fix, Test] (DirectGLES, ShaderTranspiler): synthesize the pass-through tessellation control stage ES requires

This commit is contained in:
2026-08-21 05:23:57 -04:00
parent d9def5c1bb
commit 50da7de737
8 changed files with 443 additions and 1 deletions
@@ -598,6 +598,43 @@ namespace MobileGL {
return false;
}
Bool ShaderCompiler::ModuleReadsLocatedInput(const Vector<Uint32>& spirv) {
if (spirv.empty()) {
return false;
}
std::unique_ptr<spvtools::opt::IRContext> context = spvtools::BuildModule(
SPV_ENV_VULKAN_1_1, MakeSpirvMessageConsumer("ModuleReadsLocatedInput"), spirv.data(),
spirv.size());
if (!context) {
return false;
}
// A LOCATION is exactly the property that separates a user-defined varying (or a
// per-patch input) from a built-in: gl_in, gl_TessCoord, gl_PatchVerticesIn,
// gl_PrimitiveID and the tessellation levels carry none, and every one of them is
// either forwarded by the pass-through or generated by the tessellator itself.
//
// Decided on the OpVariable's own Location decoration rather than on any
// built-in classification, for the reason DirectVulkan's
// ReflectPassthroughTessControlNeed records at length: gl_in is an ARRAY OF
// INTERFACE BLOCKS, and a member walk of one reads back as BuiltIn::Position for
// every member, so classifying by built-in would accept anything.
for (auto& variable : context->module()->types_values()) {
if (variable.opcode() != spv::Op::OpVariable || variable.NumInOperands() < 1) {
continue;
}
if (static_cast<spv::StorageClass>(variable.GetSingleWordInOperand(0)) !=
spv::StorageClass::Input) {
continue;
}
Bool located = false;
context->get_decoration_mgr()->ForEachDecoration(
variable.result_id(), static_cast<uint32_t>(spv::Decoration::Location),
[&located](const spvtools::opt::Instruction&) { located = true; });
if (located) return true;
}
return false;
}
bool ShaderCompiler::DemoteFloat64ToFloat32(const Vector<Uint32>& inputBinary,
Vector<uint32_t>& outputBinary,
const bool enableSpirvValidation) {