fix(gl): gate fallible constructors on a complete loader table

- loader: add available(), true only after load() has resolved every
  required entry point (false at the start of load()). Program::from_source
  and the other fallible constructors return ErrorCode::Unsupported while it
  is false, so a failed load() with a partially populated table can no longer
  fault on an unresolved entry point.
- caps: GL_CONTEXT_PROFILE_MASK only exists from 3.2, so query it only on
  3.2+ contexts. A 3.0/3.1 query latches GL_INVALID_ENUM in the context, which
  the next unrelated glGetError() (e.g. read_pixel) then reports as failure.
- tests: gate the dlsym/libGL.so.1 fallback assertions on libGL being
  resolvable, so the GL suite also passes on a GLES-only host.
This commit is contained in:
Martino Ferrari committed 2026-09-27 21:15:57 +02:00
1 parent 258caa38a7
commit 6866457155
4 files changed
+59 -12

No files matched your search

+11 -1
View File
@@ -30,6 +30,10 @@ PLOT_GL_FUNCS(PLOT_GL_DEF)
namespace {
/// False until a `load()` has resolved every required entry point of the table
/// above, which may stay partially populated until then. Read via available().
bool g_table_ready = false;
/// The system GL library, opened on the first name that neither the caller's
/// resolver nor the global namespace can supply. Never closed: the entry
/// points handed out must stay valid for the whole process.
@@ -138,7 +142,7 @@ bool query_caps(Caps& out) noexcept {
out.persistent_map = storage;
GLint profile = 0;
if (major >= 3) {
if (major > 3 || (major == 3 && minor >= 2)) {
// GL_CONTEXT_PROFILE_MASK only exists from 3.2 on; older contexts would
// raise GL_INVALID_ENUM and leave the value at 0.
glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &profile);
@@ -150,6 +154,9 @@ bool query_caps(Caps& out) noexcept {
} // namespace
bool load(ProcLoader loader) noexcept {
// A partially resolved table must not be used: the fallible constructors
// consult available() and report Unsupported until the whole table is good.
g_table_ready = false;
const char* missing = nullptr;
#define PLOT_GL_RESOLVE(ret, name, args) \
@@ -173,9 +180,12 @@ bool load(ProcLoader loader) noexcept {
PLOT_ASSERT(false, missing);
return false;
}
g_table_ready = true;
return true;
}
bool available() noexcept { return g_table_ready; }
const Caps& caps() noexcept {
if (!g_caps_valid) {
if (query_caps(g_caps)) {