feat(gl): dependency-free GL loader, RAII handles, caps probe, headless EGL harness

This commit is contained in:
Martino Ferrari committed 2026-09-27 21:07:36 +02:00
1 parent ed71719df7
commit 258caa38a7
11 files changed
+1458 -1

No files matched your search

+57
View File
@@ -0,0 +1,57 @@
#pragma once
#include <plot/core/status.hpp>
#include <plot/core/types.hpp>
#include <plot/gl/handle.hpp>
#include <cstdint>
namespace plottest {
using plot::u32;
/// A surfaceless EGL context plus an off-screen RGBA framebuffer, so renderer
/// output can be asserted pixel by pixel without a window or a display server.
///
/// Test-only: `plot_core` neither links nor includes EGL.
class HeadlessContext {
public:
explicit HeadlessContext(u32 w = 256, u32 h = 256) noexcept;
~HeadlessContext();
HeadlessContext(const HeadlessContext&) = delete;
HeadlessContext& operator=(const HeadlessContext&) = delete;
/// Makes an OpenGL 3.3 core context current on this thread, resolves the GL
/// entry points against it (`plot::gl::load(eglGetProcAddress)`) and
/// allocates the colour attachment. Idempotent. On failure `st` (when
/// non-null) carries the reason, every resource already created is released,
/// and the error is also printed to stderr so a failing CTest run is
/// diagnosable.
bool create(plot::Status* st = nullptr) noexcept;
/// Releases the framebuffer, the GL context and the EGL display. Safe to call
/// more than once, and to call after a failed create().
void destroy() noexcept;
/// Binds the off-screen target and reads one RGBA8 pixel, in GL's
/// origin-at-the-bottom-left convention. False when it cannot be read.
bool read_pixel(u32 x, u32 y, std::uint8_t rgba[4]) const noexcept;
u32 width = 0;
u32 height = 0;
/// The headless path create() selected ("egl surfaceless" or "egl pbuffer");
/// empty before a successful create() and after destroy(). Setting
/// PLOT_HEADLESS_FORCE_PBUFFER in the environment skips the surfaceless
/// attempt, so the pbuffer fallback can be exercised on a driver that does
/// support surfaceless contexts.
const char* egl_path = "";
private:
plot::gl::Texture color_;
plot::gl::Framebuffer framebuffer_;
void* display_ = nullptr; // EGLDisplay
void* context_ = nullptr; // EGLContext
void* surface_ = nullptr; // EGLSurface, null on the surfaceless path
};
} // namespace plottest