[Fix, Test] (MG_Impl, MG_State): advertised-extension conformance wave 1 - uniforms, validators, getters

First wave of the advertised-extension CTS campaign (targeted caselist: the
glcts groups of every extension both backends advertise, 4867 cases across the
KHR-GL41..46 namespaces). All frontend, shared by both backends:

- Non-square float matrix uniforms actually upload: glUniformMatrix{2x3,3x2,
  2x4,4x2,3x4,4x3}fv and the six glProgramUniformMatrix* twins were
  validate-only no-ops; they now write column-at-a-time at the global UBO's
  16-byte std140 column stride, honouring transpose. glUniformMatrix2fv had
  the sibling bug - mat2 written as 4 contiguous floats put column 1 at byte
  8 instead of 16. The readback path only ever un-padded mat3, so
  glGetUniformfv is fixed for mat2, mat3x2 (previously mis-gathered) and
  every non-square shape, with the bounds check widened to the padded span.
- glBindBufferRange validates offset/size at last: size <= 0, offset < 0,
  SSBO and UBO offset alignment, transform-feedback offset AND size
  multiples of 4 - all before any state write (a negative offset used to
  reach Range1D unchecked). glBindBuffersRange inherits per element, with
  the ARB_multi_bind up-front [first, first+count) checks added to the
  BindBuffersBase/Range and BindSamplers prologues.
- BufferSubData's second, wrong mapped-overlap test deleted (it rejected
  every write at or after a mapped range's start, mapped or not); the state
  layer's assert relaxed to the same half-open intersection the frontend
  checks. BufferStorage error precedence fixed: no-bound-buffer now beats
  bad-size/flags.
- glSamplerParameteri accepts the full GL_NEVER..GL_ALWAYS compare-func
  range (NEVER/LESS/EQUAL were rejected by a wrong lower bound).
  glBindSampler's unit gate uses GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS instead
  of the frontend array capacity, shared with glBindSamplers by construction.
- Getters: GL_MAX_SHADER_STORAGE_BLOCK_SIZE in glGetIntegerv; atomic-counter
  buffer limits; all 11 per-unit GL_TEXTURE_BINDING_* plus GL_SAMPLER_BINDING
  in glGetIntegeri_v; GL_VERTEX_ATTRIB_BINDING/_RELATIVE_OFFSET across the
  vertex-attrib query family; glGetFloati_v/glGetDoublei_v implemented (were
  stubs); KHR_debug limits raised to spec floors.
- glCreateShader records INVALID_ENUM for an unknown type (it previously
  handed out a usable name with no error at all); glCreateShaderProgramv
  validates count up front. glDispatchCompute/Indirect validate work-group
  counts, offset alignment and indirect-buffer presence.
- glVertexAttribIFormat & friends take a positive integer-type whitelist -
  GL_FLOAT/GL_HALF_FLOAT/GL_DOUBLE/GL_FIXED no longer slip through as
  integer attributes.

Gate (headless Mesa, default config = async on): 570/570 unit at default and
with the kill switch; ext caselist Espryt 76.29% -> 77.87% (+81 fixed, 6
crashes -> 0, the whole list now runs in one glcts process), Magma 75.94% ->
77.58% (+80 fixed, 0 newly broken); KHR-GL33 full mustpass lost nothing
(9884/9886, the 2 known Mesa-drift failures); retrace smoke clean (the
bsl-GLES miss is the documented golden drift, bit-identical on the pristine
baseline). The 4 DirectGLES direct_state_access.renderbuffers_storage* cases
that turned red are a PRE-EXISTING GL_FRAMEBUFFER_SRGB cross-test leak,
A/B-proven on an unpatched 2e6fc1ff build - wave 1 removed the two accidental
maskers (a crash partition and a failing case whose error path reset the
state). Fixing the leak itself is queued.
This commit is contained in:
BZLZHH
2026-08-09 04:39:22 -04:00
parent 2e6fc1ffc0
commit 33ff177bb2
17 changed files with 1248 additions and 233 deletions
+27 -1
View File
@@ -8,6 +8,7 @@
#include "GL_Sampler.h"
#include "Validators.h"
#include "../Getter/GL_Getter.h"
#include <MG_State/GLState/Core.h>
#include <MG_Util/Converters/GLToMG/TextureEnumConverter.h>
#include <MG_Util/Converters/MGToGL/TextureEnumConverter.h>
@@ -268,9 +269,20 @@ namespace MobileGL::MG_Impl::GLImpl {
}
}
// The number of texture units a sampler may be bound to. GL 3.3 core 3.8.2 names
// GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, which is what the backend advertises; the frontend's
// MAX_TEXTURE_IMAGE_UNITS is only the capacity of the unit array, so it is a clamp on the
// answer and never the answer itself - gating on it alone accepts every unit up to 192 no
// matter what the driver reports.
static GLint GetSamplerBindableTextureUnitCount() {
GLint maxTextureUnits = 0;
GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
return std::min<GLint>(std::max(maxTextureUnits, 0), MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS);
}
void BindSampler_State(GLuint unit, GLuint sampler) {
MGLOG_D("BindSampler_State: unit = %u, sampler = %u", unit, sampler);
if (unit >= MG_State::GLState::TextureState::MAX_TEXTURE_IMAGE_UNITS) {
if (static_cast<Uint64>(unit) >= static_cast<Uint64>(GetSamplerBindableTextureUnitCount())) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidValue,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSampler", "texture unit out of range"));
@@ -309,6 +321,20 @@ namespace MobileGL::MG_Impl::GLImpl {
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSamplers", "count must be non-negative"));
return;
}
// ARB_multi_bind: the whole [first, first + count) range is checked up front and a
// range that runs past the last texture unit is INVALID_OPERATION - not the
// INVALID_VALUE the single-bind BindSampler_State reports per element, and nothing is
// bound when it fails. Both gates read the same limit (see
// GetSamplerBindableTextureUnitCount), so an out-of-range multi-bind can no longer slip
// past this check and be caught one element at a time with the wrong error class.
const GLint maxTextureUnits = GetSamplerBindableTextureUnitCount();
if (static_cast<Uint64>(first) + static_cast<Uint64>(count) > static_cast<Uint64>(maxTextureUnits)) {
MG_State::pGLContext->RecordError(
ErrorCode::InvalidOperation,
MakeUnique<GenericErrorInfo>("MG_Impl/GLImpl", "BindSamplers",
"first + count exceeds the number of texture units."));
return;
}
for (GLsizei i = 0; i < count; ++i) {
BindSampler_State(first + i, samplers ? samplers[i] : 0);