From 62301b10617c945bbfece240754661435f7a1b17 Mon Sep 17 00:00:00 2001 From: BZLZHH Date: Wed, 5 Aug 2026 06:43:41 -0400 Subject: [PATCH] [Fix] (MG_State): let a double-typed varying be captured by transform feedback ResolveXfbSymbolType accepted only float, int and uint, and its caller reports anything it rejects as "Transform feedback varying 'x' is not an output of the vertex stage" - which is a misleading thing to say about a varying that is right there in the shader, just declared `double`. Program linkage failed outright. Doubles are now resolved to the GL_DOUBLE* types, in vector and matrix form, and the per-element size is computed from an 8-byte component rather than a hardcoded 4 (GL 4.6 core 11.1.2.1), so the byte-based limit checks charge a double what GL says it costs. direct_state_access.vertex_arrays_attribute_format stops throwing on both backends and fails on the captured values instead: the capture layout still owes the 8-byte alignment doubles require, and neither backend feeds a 64-bit vertex attribute yet - DirectGLES cannot at all, ESSL having no double. --- .../GLState/ProgramState/ProgramObject.cpp | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp index a3557444..7e9f66ab 100644 --- a/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp +++ b/MobileGL/MG_State/GLState/ProgramState/ProgramObject.cpp @@ -195,27 +195,42 @@ namespace MobileGL::MG_State::GLState { static constexpr GLenum kIntTypes[5] = {0, GL_INT, GL_INT_VEC2, GL_INT_VEC3, GL_INT_VEC4}; static constexpr GLenum kUintTypes[5] = {0, GL_UNSIGNED_INT, GL_UNSIGNED_INT_VEC2, GL_UNSIGNED_INT_VEC3, GL_UNSIGNED_INT_VEC4}; + static constexpr GLenum kDoubleTypes[5] = {0, GL_DOUBLE, GL_DOUBLE_VEC2, GL_DOUBLE_VEC3, + GL_DOUBLE_VEC4}; if (type.isMatrix()) { - if (basic != glslang::EbtFloat) return false; + if (basic != glslang::EbtFloat && basic != glslang::EbtDouble) return false; static constexpr GLenum kMatTypes[5][5] = { {}, {}, {0, 0, GL_FLOAT_MAT2, GL_FLOAT_MAT2x3, GL_FLOAT_MAT2x4}, {0, 0, GL_FLOAT_MAT3x2, GL_FLOAT_MAT3, GL_FLOAT_MAT3x4}, {0, 0, GL_FLOAT_MAT4x2, GL_FLOAT_MAT4x3, GL_FLOAT_MAT4}, }; + static constexpr GLenum kDoubleMatTypes[5][5] = { + {}, {}, + {0, 0, GL_DOUBLE_MAT2, GL_DOUBLE_MAT2x3, GL_DOUBLE_MAT2x4}, + {0, 0, GL_DOUBLE_MAT3x2, GL_DOUBLE_MAT3, GL_DOUBLE_MAT3x4}, + {0, 0, GL_DOUBLE_MAT4x2, GL_DOUBLE_MAT4x3, GL_DOUBLE_MAT4}, + }; if (columns < 2 || columns > 4 || components < 2 || components > 4) return false; - outType = kMatTypes[columns][components]; + outType = basic == glslang::EbtDouble ? kDoubleMatTypes[columns][components] + : kMatTypes[columns][components]; } else if (components >= 1 && components <= 4) { switch (basic) { case glslang::EbtFloat: outType = kFloatTypes[components]; break; case glslang::EbtInt: outType = kIntTypes[components]; break; case glslang::EbtUint: outType = kUintTypes[components]; break; + // A double-typed varying is capturable like any other; rejecting it here reported + // the varying as "not an output of the vertex stage", which it plainly was. + case glslang::EbtDouble: outType = kDoubleTypes[components]; break; default: return false; } } else { return false; } - outBytesPerElement = static_cast(columns * components) * 4u; + // GL 4.6 core 11.1.2.1: a double component occupies eight basic machine units, and + // counts as two components against the transform feedback limits. + const Uint32 bytesPerComponent = basic == glslang::EbtDouble ? 8u : 4u; + outBytesPerElement = static_cast(columns * components) * bytesPerComponent; return true; } } // namespace