The repository had no licence at all, so every source was all-rights-reserved by default. Add the verbatim MIT text at LICENSE (Copyright (c) 2026 Martino Ferrari) and a two-line SPDX header to each of the 113 first-party sources -- 48 include/plot, 26 src, 10 adapters, 5 examples, 21 tests, 3 tools -- so the grant travels with each file rather than relying on the root document alone. Scripts keep their shebang on line 1; the SPDX lines follow it. Genuinely vendored code is untouched: third_party/stb_truetype.h carries no header of ours. src/render/embedded_mono_font.cpp is generated, so tools/fonts/gen_atlas.py emit() now writes the two lines into its header comment and the file was regenerated -- gen_atlas.py --check passes and the regeneration adds only those comment lines to the previously committed file. README's provenance section now states MIT and links LICENSE. No code, test or public API change.
61 lines
2.2 KiB
C++
61 lines
2.2 KiB
C++
// SPDX-License-Identifier: MIT
|
|
// SPDX-FileCopyrightText: 2026 Martino Ferrari
|
|
|
|
#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
|