[Fix] (ShaderTranspiler): stop the point-size carrier landing on a location a live varying owns, and decline the evaluation stage a synthesized pass-through control stage cannot feed - an i64vec4 counted as one location, and a located input carrier trips both backends' pass-through guard

This commit is contained in:
2026-08-28 06:22:11 -04:00
parent 1c113e4b26
commit a4dcdf989e
2 changed files with 36 additions and 2 deletions
@@ -832,8 +832,17 @@ namespace MobileGL {
return 1u; return 1u;
} }
if (const auto* vector = type->AsVector()) { if (const auto* vector = type->AsVector()) {
const auto* elementFloat = vector->element_type()->AsFloat(); // 64-bit INTEGER elements count exactly like 64-bit floats:
const Bool is64Bit = elementFloat != nullptr && elementFloat->width() == 64; // ARB_gpu_shader_int64 extends 11.1.2.1's double-precision rule
// verbatim to i64/u64, and DirectVulkan advertises that extension
// unconditionally - so answering "one location" for an i64vec4 would
// place the carrier on the SECOND location that varying already owns,
// which is the underestimate this function's header forbids.
const auto* element = vector->element_type();
const auto* elementFloat = element->AsFloat();
const auto* elementInteger = element->AsInteger();
const Bool is64Bit = (elementFloat != nullptr && elementFloat->width() == 64) ||
(elementInteger != nullptr && elementInteger->width() == 64);
return (is64Bit && vector->element_count() > 2) ? 2u : 1u; return (is64Bit && vector->element_count() > 2) ? 2u : 1u;
} }
if (const auto* matrix = type->AsMatrix()) { if (const auto* matrix = type->AsMatrix()) {
@@ -1096,6 +1105,23 @@ namespace MobileGL {
outcome.declineDetail = Move(report.declineReason); outcome.declineDetail = Move(report.declineReason);
return true; // byte-identical decline; the existing refusals stay armed return true; // byte-identical decline; the existing refusals stay armed
} }
// AN EVALUATION STAGE WITH NO CONTROL STAGE THAT NOW READS A LOCATED
// INPUT. GL lets the evaluation stage sit straight on the vertex stage,
// and both backends stand a SYNTHESIZED pass-through control stage in
// between - one that forwards gl_Position and nothing else. Their guard
// for that is literally "does this module read a located input"
// (ModuleReadsLocatedInput / ReflectPassthroughTessControlNeed), so the
// carrier this pass just created would turn the very program the demotion
// exists to rescue into a declined one, reported against a varying name
// the application never wrote. Declining here keeps the modules
// byte-identical and leaves the honest built-in refusal in charge; only
// teaching the synthesized stage to forward the carrier could do better.
if (stage == 2 && stageIndex[1] < 0 && report.createdInputCarrier) {
outcome.declineDetail =
"an evaluation stage reads gl_in point size with no control stage to "
"carry it; the synthesized pass-through cannot forward the carrier";
return true;
}
rewrote[stage] = true; rewrote[stage] = true;
if (report.createdInputCarrier && producer >= 0) { if (report.createdInputCarrier && producer >= 0) {
forceOutput[producer] = true; forceOutput[producer] = true;
@@ -603,6 +603,14 @@ namespace MobileGL {
// the optimizer itself failed (modules untouched); a shape decline is // the optimizer itself failed (modules untouched); a shape decline is
// reported through `outcome` and also leaves the modules untouched. See // reported through `outcome` and also leaves the modules untouched. See
// DemotePointSizePass for the per-module rewrite and its honest residue. // DemotePointSizePass for the per-module rewrite and its honest residue.
//
// Two declines are PROGRAM-shaped and therefore live here rather than in the
// pass: a carrier that would land past the minimum-spec varying budget, and
// an evaluation stage reading gl_in point size with NO control stage - the
// synthesized pass-through control stage both backends stand in that gap
// forwards gl_Position alone, so the input carrier would strand the value and
// trip the backends' own "reads a located input" refusal against a name the
// application never wrote.
static Bool DemoteTessellationGeometryPointSizeForProgram( static Bool DemoteTessellationGeometryPointSizeForProgram(
Vector<Vector<Uint32>>& modules, const Vector<GLenum>& shaderTypes, Vector<Vector<Uint32>>& modules, const Vector<GLenum>& shaderTypes,
Bool demoteTessellation, Bool demoteGeometry, Bool captureRequestsPointSize, Bool demoteTessellation, Bool demoteGeometry, Bool captureRequestsPointSize,