[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) {
@@ -427,6 +427,19 @@ namespace MobileGL {
// module (see its header for the two operations that make it decline), which is
// what the backends report: no mobile driver can build such a module.
static Bool ModuleDeclaresFloat64(const Vector<Uint32>& spirv);
// True when the module declares an Input variable carrying a Location - i.e. a
// user-defined varying or a per-patch input, as opposed to a built-in.
//
// Asked of a TESSELLATION EVALUATION stage that has no control stage, to decide
// whether the pass-through control stage GL 4.6 core 11.2.2 describes can stand
// in for the missing one. That stage forwards gl_Position and nothing else, so a
// located input - which the vertex stage feeds today and which would stop
// arriving once a control stage sat in between - means the program has to be
// declined rather than fed an undefined varying. Same rule, same reasoning, as
// DirectVulkan's ReflectPassthroughTessControlNeed, which asks SPIRV-Reflect the
// identical question for the identical decision.
static Bool ModuleReadsLocatedInput(const Vector<Uint32>& spirv);
};
} // namespace ShaderTranspiler
} // namespace MG_Util