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:
1 parent
258caa38a7
commit
6866457155
4 files changed
+59
-12
No files matched your search
+17
-11
@@ -10,6 +10,7 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include <utility>
|
||||
|
||||
namespace {
|
||||
@@ -65,7 +66,8 @@ PLOT_TEST(headless_context_provides_gl33) {
|
||||
PLOT_CHECK(caps.major > 3 || (caps.major == 3 && caps.minor >= 3));
|
||||
PLOT_CHECK(caps.renderer != nullptr && caps.renderer[0] != '\0');
|
||||
PLOT_CHECK(caps.vendor != nullptr && caps.vendor[0] != '\0');
|
||||
PLOT_CHECK(caps.core_profile); // the context was created as 3.3 core
|
||||
// EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR is requested, so this checks our profile-mask parsing.
|
||||
PLOT_CHECK(caps.core_profile);
|
||||
const char* version = reinterpret_cast<const char*>(plot::gl::glGetString(plot::gl::GL_VERSION));
|
||||
PLOT_CHECK(version != nullptr);
|
||||
const int major = caps.major;
|
||||
@@ -78,16 +80,20 @@ PLOT_TEST(headless_context_provides_gl33) {
|
||||
caps.core_profile ? 1 : 0);
|
||||
|
||||
// The dlsym(RTLD_DEFAULT) / libGL.so.1 fallback must resolve the whole table
|
||||
// too, and its pointers must still dispatch to the current EGL context.
|
||||
PLOT_CHECK(plot::gl::load(nullptr));
|
||||
PLOT_CHECK(plot::gl::glGetError() == plot::gl::GL_NO_ERROR);
|
||||
const char* fallback_version =
|
||||
reinterpret_cast<const char*>(plot::gl::glGetString(plot::gl::GL_VERSION));
|
||||
PLOT_CHECK(fallback_version != nullptr);
|
||||
PLOT_CHECK(std::strcmp(fallback_version, version) == 0); // same context, same driver
|
||||
const plot::gl::Caps& reprobed = plot::gl::caps(); // load() invalidated the cache
|
||||
PLOT_CHECK(reprobed.major == major && reprobed.minor == minor);
|
||||
PLOT_CHECK(reprobed.renderer != nullptr && reprobed.renderer[0] != '\0');
|
||||
// too, and its pointers must still dispatch to the current EGL context. Only
|
||||
// a host that ships desktop libGL can exercise it; on a GLES-only host there
|
||||
// is nothing to assert.
|
||||
if (dlopen("libGL.so.1", RTLD_LAZY) != nullptr) {
|
||||
PLOT_CHECK(plot::gl::load(nullptr));
|
||||
PLOT_CHECK(plot::gl::glGetError() == plot::gl::GL_NO_ERROR);
|
||||
const char* fallback_version =
|
||||
reinterpret_cast<const char*>(plot::gl::glGetString(plot::gl::GL_VERSION));
|
||||
PLOT_CHECK(fallback_version != nullptr);
|
||||
PLOT_CHECK(std::strcmp(fallback_version, version) == 0); // same context, same driver
|
||||
const plot::gl::Caps& reprobed = plot::gl::caps(); // load() invalidated the cache
|
||||
PLOT_CHECK(reprobed.major == major && reprobed.minor == minor);
|
||||
PLOT_CHECK(reprobed.renderer != nullptr && reprobed.renderer[0] != '\0');
|
||||
}
|
||||
|
||||
// Hand the table back to the context-aware resolver so teardown (deleting the
|
||||
// framebuffer) runs through the entry points of the context it belongs to.
|
||||
|
||||
Reference in new issue
Block a user