mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
Wave 2 of the advertised-extension conformance campaign.
PROGRAM INTERFACE QUERIES (the load-bearing piece). glGetProgramInterfaceiv
and the five glGetProgramResource* entry points were answered by the
BACKENDS - Espryt asked the real driver about SPIRV-Cross-generated ESSL
whose namespace is not the GL one (default-block uniforms live in
MGL_GLOBAL_UBO there), and Magma kept a second, partial reflection that
hardcoded types and diverged from the frontend. Both are now deleted; a new
frontend resource-model layer (ProgramInterface.{h,cpp}) answers every
interface - uniforms, uniform blocks, atomic-counter buffers (recovered
from glslang's synthesized gl_AtomicCounterBlock_<binding> lowering),
buffer variables, shader-storage blocks (classified by TType storage
qualifier since glslang reflects them as uniform blocks), program inputs/
outputs (built-ins' layoutLocationEnd sentinel mapped to -1), and
transform-feedback varyings including the gl_NextBuffer/gl_SkipComponentsN
pseudo-varyings - from the glslang reflection the frontend already trusts
for glGetActiveUniform. Name/index round-tripping, the "[0]" array
spelling, and the GL 4.6 table 7.2 prop/error matrix live in the new layer
only; GetActiveUniform*/GetActiveAttrib* are untouched.
glShaderStorageBlockBinding now takes the interface-layer index (the one
GetProgramResourceIndex returns, with a range check it never had), records
the binding on the program keyed by block NAME - the one coordinate all
three index spaces agree on - and delegates by name across the backend
boundary. Both backends reseed the recorded bindings on their own program
rebuilds, so an unrelated resync can no longer silently revert a rebound
block, and GL_BUFFER_BINDING reports the live binding, not the declared
one. The Espryt delegate applies only to an already-synced twin and can no
longer trigger SyncToBackend from a getter; the sync path's GL query
out-params are initialized and clamped (a load-dependent stack-garbage
Vector size crash caught by the gate, reproduced 3/50 pre-fix, 100/100
post-fix under saturating load).
ESPRYT RENDER-STATE SHADOW RESET (rides along because it shares
DirectGLES.cpp): the render-state shadow is file-static and survives
MobileGL context switches, so GL_FRAMEBUFFER_SRGB (and the whole synced-cap
class) leaked between contexts - the cross-test leakage class the CTS maps
have carried for a week. MakeCurrent now invalidates the shadow like it
already invalidates the program/FBO/buffer caches, and the resync resolves
a never-set scissor box to the current surface instead of pushing the
(0,0,0,0) sentinel verbatim (which scissored everything away - caught by
the retrace gate, bisected to the exact field via a bitmask probe, and
fixed by resolving like the viewport path rather than reverting).
Frontend riders exposed by the layer: glGetUniformLocation resolves
arrays-of-arrays element addressing ("a[2][1]"); transform-feedback capture
accepts element-addressed varying names ("b[1]") and snapshots the request
verbatim for the interface (Magma's decorate pass logs loudly that element
capture is unimplemented there - follow-up).
KNOWN GAPS, documented in code and tests: the 6 subroutines-* cases
(glslang refuses subroutine for SPIR-V; wave 3), the 5 separate-programs-*
cases (glslang's pipe-I/O reflection cannot see a separable non-vertex
stage's own inputs; needs stage-aware output validation first), and
uniform-block-types' per-instance stage masks (not derivable from the
reflection).
Gate: 593/593 unit at default and kill-switch, x10 each, plus the SSB race
case 100/100 under 20-way CPU load; ext caselist Espryt 77.87% -> 80.42%,
Magma 77.58% -> 79.39% (+212 fixed, 0 newly broken); program_interface_query
2/43 -> 31/43 unique on Espryt, 9/43 -> 31/43 on Magma, backends now
byte-identical; KHR-GL45.direct_state_access 370/371 + 371/371 with the 4
sRGB leak victims recovered in cross-test ordering; KHR-GL33 held at
9884/9886; full 39x2 CI retrace with zero wave-attributable failures (the
3 failing newly-added fixtures are bit-identical on the pristine baseline).
67 lines
3.9 KiB
C++
67 lines
3.9 KiB
C++
// MobileGL - MobileGL/MG_Impl/GLImpl/Program/ProgramInterface.h
|
|
// Copyright (c) 2025-2026 MobileGL-Dev
|
|
// Licensed under the GNU Lesser General Public License v3.0:
|
|
// https://www.gnu.org/licenses/gpl-3.0.txt
|
|
// https://www.gnu.org/licenses/lgpl-3.0.txt
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
// End of Source File Header
|
|
|
|
#pragma once
|
|
#include <Includes.h>
|
|
|
|
namespace MobileGL::MG_State::GLState {
|
|
class ProgramObject;
|
|
}
|
|
|
|
// The GL program interface (ARB_program_interface_query / GL 4.3 §7.3.1) as a frontend
|
|
// resource model.
|
|
//
|
|
// WHY IT IS HERE AND NOT IN A BACKEND. glGetProgramResource* describes the program the
|
|
// APPLICATION wrote, in the application's namespace. Neither backend program is in that
|
|
// namespace: DirectGLES compiles SPIRV-Cross-generated ESSL where default-block uniforms
|
|
// live inside the synthesized MGL_GLOBAL_UBO (so a GL_UNIFORM location query against it is
|
|
// structurally -1) and stage in/out names are rewritten; DirectVulkan has no GL-level
|
|
// reflection at all and can only re-derive a partial, diverging copy. The one authoritative
|
|
// source is the frontend glslang reflection a link already produced, which is the same
|
|
// place glGetActiveUniform answers from. This layer generalizes that rule to every
|
|
// interface, so the six entry points never consult gBackendFunctionsTable.
|
|
//
|
|
// NAMING RULES LIVE HERE, NOT IN ProgramObject. The interface query spells resources
|
|
// differently from glGetActiveUniform / glGetActiveAttrib (an array is "name[0]", a lookup
|
|
// accepts both "name" and "name[0]", a subscript must be a strict decimal). Those two
|
|
// getters are what GL30-33 exercises and they must not move, so every normalization is
|
|
// applied on the way in and out of THIS file.
|
|
namespace MobileGL::MG_Impl::GLImpl::ProgramInterface {
|
|
using ProgramObject = MG_State::GLState::ProgramObject;
|
|
|
|
// <programInterface> is one of the GL 4.6 Table 7.1 interfaces.
|
|
Bool IsInterfaceEnum(GLenum programInterface);
|
|
// Interfaces whose resources have names (everything except GL_ATOMIC_COUNTER_BUFFER).
|
|
Bool IsNamedInterface(GLenum programInterface);
|
|
// <prop> is a property token GetProgramResourceiv knows at all (else GL_INVALID_ENUM).
|
|
Bool IsResourceProp(GLenum prop);
|
|
// <prop> applies to <programInterface> (else GL_INVALID_OPERATION).
|
|
Bool InterfaceSupportsProp(GLenum programInterface, GLenum prop);
|
|
// Interfaces GetProgramResourceLocation accepts (else GL_INVALID_ENUM).
|
|
Bool InterfaceHasLocations(GLenum programInterface);
|
|
|
|
// GL_ACTIVE_RESOURCES / GL_MAX_NAME_LENGTH / GL_MAX_NUM_ACTIVE_VARIABLES. All three
|
|
// report zero for an interface this implementation cannot enumerate and for a program
|
|
// that has not linked successfully - which is what the spec requires of a program with
|
|
// no active resources.
|
|
Int GetActiveResourceCount(ProgramObject& program, GLenum programInterface);
|
|
Int GetMaxNameLength(ProgramObject& program, GLenum programInterface);
|
|
Int GetMaxNumActiveVariables(ProgramObject& program, GLenum programInterface);
|
|
|
|
// GL_INVALID_INDEX when <name> names no active resource of the interface.
|
|
GLuint GetResourceIndex(ProgramObject& program, GLenum programInterface, const char* name);
|
|
// False when <index> is out of range for the interface (the caller raises INVALID_VALUE).
|
|
Bool GetResourceName(ProgramObject& program, GLenum programInterface, GLuint index, String& outName);
|
|
// Appends the value(s) of <prop> for the resource; GL_ACTIVE_VARIABLES appends several.
|
|
// False when <index> is out of range.
|
|
Bool GetResourceProp(ProgramObject& program, GLenum programInterface, GLuint index, GLenum prop,
|
|
Vector<GLint>& outValues);
|
|
GLint GetResourceLocation(ProgramObject& program, GLenum programInterface, const char* name);
|
|
GLint GetResourceLocationIndex(ProgramObject& program, GLenum programInterface, const char* name);
|
|
} // namespace MobileGL::MG_Impl::GLImpl::ProgramInterface
|