#pragma once #include #include #include #include namespace plot::render { /// Vertex array plus instance buffer of the line pipeline. /// /// The attribute layout is fixed by the line shader (see shaders.hpp): `a_p0` at /// location 0 and `a_p1` at location 1, two floats each, advancing once per /// instance. A caller never writes a location, stride or offset; it stages a /// `LineBatch` and uploads its `data()`. /// /// The instance buffer may sit behind either transfer strategy (see /// `UploadMode`). Only the mapped one moves the instances between slots, so /// `upload()` re-points the attributes when `InstanceStore::epoch()` changes and /// otherwise leaves them alone; the caller never has to know which path is live. class LineVertexArray { public: /// Creates the vertex array, the instance buffer and the attribute layout. /// `mode` selects the instance buffer's transfer strategy and defaults to the /// GL 3.3 baseline; a caller asking for `UploadMode::PersistentMapped` must /// have checked the context can do it (see `Renderer::init()`). bool create(Status* st = nullptr, UploadMode mode = UploadMode::Orphan) noexcept; /// Uploads `segments` instances from interleaved `x0,y0,x1,y1` floats and /// records how many the next draw should rasterise. void upload(const f32* interleaved, u32 segments) noexcept; void bind() const noexcept { vao_.bind(); } /// Waits, once, for the previous frame's draws to retire the ring before any /// slot of this frame is written (see `InstanceStore::begin_frame`). False when /// the store had to drop to the baseline path; the caller reports it. bool begin_frame() noexcept { return buffer_.begin_frame(); } /// Records the frame's single fence, behind every draw that read the ring (see /// `InstanceStore::mark_drawn`); called once per frame, after its last draw. /// False only when the driver refused the fence: the buffer has then fallen /// back to the baseline path, and `persistent()` says so from the next call on. bool mark_drawn() noexcept { return buffer_.mark_drawn(); } /// True while this array's instance buffer is the mapped ring (see /// `UploadMode`); a failure that falls back clears it. bool persistent() const noexcept { return buffer_.persistent(); } bool valid() const noexcept { return vao_.id() != 0; } u32 instance_count() const noexcept { return instances_; } private: LineBuffer buffer_; gl::VertexArray vao_; u32 instances_ = 0; /// Instance-buffer generation the attribute pointers currently point into. u32 epoch_ = 0; }; /// Vertex array plus instance buffer of the text pipeline: `a_pos` at location 0 /// and the glyph's atlas texel origin `a_uv` at location 1, two floats each, /// advancing once per instance. class TextVertexArray { public: bool create(Status* st = nullptr, UploadMode mode = UploadMode::Orphan) noexcept; /// Uploads `glyphs` instances from interleaved `x,y,u,v` floats. void upload(const f32* interleaved, u32 glyphs) noexcept; void bind() const noexcept { vao_.bind(); } /// The line pipeline's frame pair, for the text store (see /// `LineVertexArray::begin_frame` / `mark_drawn`). bool begin_frame() noexcept { return buffer_.begin_frame(); } bool mark_drawn() noexcept { return buffer_.mark_drawn(); } bool persistent() const noexcept { return buffer_.persistent(); } bool valid() const noexcept { return vao_.id() != 0; } u32 instance_count() const noexcept { return instances_; } private: TextBuffer buffer_; gl::VertexArray vao_; u32 instances_ = 0; u32 epoch_ = 0; }; } // namespace plot::render