[Feat] (Program): report the geometry and tessellation link properties glGetProgramiv had no source for

This commit is contained in:
2026-08-27 03:49:38 -04:00
parent 7168f2ef77
commit 6cc9faf772
4 changed files with 300 additions and 2 deletions
@@ -670,9 +670,14 @@ namespace MobileGL::MG_State::GLState {
return;
}
// GL_GEOMETRY_INPUT_TYPE. A draw's primitive type has to be compatible with it
// (GL 4.6 core 11.3.1), so it is resolved for every link, not only a capturing one.
// The geometry stage's link properties. GL_GEOMETRY_INPUT_TYPE is load-bearing beyond the
// query surface - a draw's primitive type has to be compatible with it (GL 4.6 core
// 11.3.1) - so this block runs for every link, not only a capturing one. The other three
// are pure glGetProgramiv answers that previously had no source at all.
artifacts.gsInputPrimitive = GL_NONE;
artifacts.gsOutputPrimitive = GL_NONE;
artifacts.gsMaxVertices = 0;
artifacts.gsInvocations = 0;
if (const glslang::TIntermediate* gs = artifacts.program->getIntermediate(EShLangGeometry)) {
switch (gs->getInputPrimitive()) {
case glslang::ElgPoints: artifacts.gsInputPrimitive = GL_POINTS; break;
@@ -682,6 +687,45 @@ namespace MobileGL::MG_State::GLState {
case glslang::ElgTrianglesAdjacency: artifacts.gsInputPrimitive = GL_TRIANGLES_ADJACENCY; break;
default: break;
}
switch (gs->getOutputPrimitive()) {
case glslang::ElgPoints: artifacts.gsOutputPrimitive = GL_POINTS; break;
case glslang::ElgLineStrip: artifacts.gsOutputPrimitive = GL_LINE_STRIP; break;
case glslang::ElgTriangleStrip: artifacts.gsOutputPrimitive = GL_TRIANGLE_STRIP; break;
default: break;
}
// glslang leaves both at TQualifier::layoutNotSet (-1) when the shader declared no
// such layout, and `invocations` defaults to one per GLSL 4.60 4.4.2.2 - so clamp
// rather than forward, or GL_GEOMETRY_SHADER_INVOCATIONS reports the sentinel.
artifacts.gsMaxVertices = std::max(gs->getVertices(), 0);
artifacts.gsInvocations = std::max(gs->getInvocations(), 1);
}
// The tessellation evaluation stage's link properties, GL 4.6 core table 23.35: the
// primitive generator's mode, spacing, winding and point mode. (The control stage's
// output patch size is captured below, together with the limit check that goes with it.)
artifacts.tessGenMode = GL_NONE;
artifacts.tessGenSpacing = GL_NONE;
artifacts.tessGenVertexOrder = GL_NONE;
artifacts.tessGenPointMode = false;
if (const glslang::TIntermediate* tes = artifacts.program->getIntermediate(EShLangTessEvaluation)) {
switch (tes->getInputPrimitive()) {
case glslang::ElgTriangles: artifacts.tessGenMode = GL_TRIANGLES; break;
case glslang::ElgQuads: artifacts.tessGenMode = GL_QUADS; break;
case glslang::ElgIsolines: artifacts.tessGenMode = GL_ISOLINES; break;
default: break;
}
// GLSL 4.60 4.4.2.3: equal_spacing and ccw are the defaults, which is what an unset
// qualifier means here.
switch (tes->getVertexSpacing()) {
case glslang::EvsFractionalEven: artifacts.tessGenSpacing = GL_FRACTIONAL_EVEN; break;
case glslang::EvsFractionalOdd: artifacts.tessGenSpacing = GL_FRACTIONAL_ODD; break;
default: artifacts.tessGenSpacing = GL_EQUAL; break;
}
switch (tes->getVertexOrder()) {
case glslang::EvoCw: artifacts.tessGenVertexOrder = GL_CW; break;
default: artifacts.tessGenVertexOrder = GL_CCW; break;
}
artifacts.tessGenPointMode = tes->getPointMode();
}
// GL_TESS_CONTROL_OUTPUT_VERTICES, i.e. the `layout(vertices = N) out` the control stage
@@ -1356,6 +1356,23 @@ namespace MobileGL::MG_State::GLState {
// tessellation control stage, or 0 when the program has none. Checked against
// GL_MAX_PATCH_VERTICES at link (GL 4.6 core 11.2.1.1).
Int tcsOutputVertices = 0;
// The rest of the geometry stage's link properties, and the tessellation evaluation
// stage's. Every one of these is a glGetProgramiv answer that had no source at all:
// the query surface listed the geometry pnames only to fall through to
// GL_INVALID_ENUM, and the GL_TESS_GEN_* pnames were not mentioned anywhere. They
// come from the linked intermediates for the same reason gsInputPrimitive and
// tcsOutputVertices do - glslang has already merged the compilation units' layout
// qualifiers and diagnosed contradictions, so the linked program is the thing that
// knows.
GLenum gsOutputPrimitive = GL_NONE;
Int gsMaxVertices = 0;
Int gsInvocations = 0;
// The tessellation evaluation stage's layout: GL_QUADS / GL_TRIANGLES / GL_ISOLINES,
// GL_EQUAL / GL_FRACTIONAL_EVEN / GL_FRACTIONAL_ODD, GL_CW / GL_CCW, and point mode.
GLenum tessGenMode = GL_NONE;
GLenum tessGenSpacing = GL_NONE;
GLenum tessGenVertexOrder = GL_NONE;
Bool tessGenPointMode = false;
GLenum xfbBufferMode = GL_INTERLEAVED_ATTRIBS;
Int xfbVaryingNameMaxLength = 0;
Bool xfbNeedsScatteredCapture = false;
@@ -1545,10 +1562,22 @@ namespace MobileGL::MG_State::GLState {
// GL_LINES_ADJACENCY, GL_TRIANGLES or GL_TRIANGLES_ADJACENCY), or GL_NONE when the
// program has no geometry stage. Draws must present a compatible primitive type.
GLenum GetGeometryInputType() const { return Artifacts().gsInputPrimitive; }
// GL_GEOMETRY_OUTPUT_TYPE (GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP),
// GL_GEOMETRY_VERTICES_OUT and GL_GEOMETRY_SHADER_INVOCATIONS of the linked geometry
// stage. Meaningless without one - glGetProgramiv raises INVALID_OPERATION there.
GLenum GetGeometryOutputType() const { return Artifacts().gsOutputPrimitive; }
Int GetGeometryVerticesOut() const { return Artifacts().gsMaxVertices; }
Int GetGeometryShaderInvocations() const { return Artifacts().gsInvocations; }
// GL_TESS_CONTROL_OUTPUT_VERTICES of the linked tessellation control stage, or 0 when
// the program has no such stage. Never greater than GL_MAX_PATCH_VERTICES: a program
// that declared more does not link at all (GL 4.6 core 11.2.1.1).
Int GetTessControlOutputVertices() const { return Artifacts().tcsOutputVertices; }
// GL_TESS_GEN_MODE / _SPACING / _VERTEX_ORDER / _POINT_MODE of the linked tessellation
// evaluation stage.
GLenum GetTessGenMode() const { return Artifacts().tessGenMode; }
GLenum GetTessGenSpacing() const { return Artifacts().tessGenSpacing; }
GLenum GetTessGenVertexOrder() const { return Artifacts().tessGenVertexOrder; }
Bool GetTessGenPointMode() const { return Artifacts().tessGenPointMode; }
Uint GetExternalIndex() const { return m_externalIndex; }
// Globally-unique, never-reused id for this program object's lifetime. Unlike the GL