#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(); } /// Records that the draw just issued read the instance buffer's current slot, /// which is what lets the mapped path reuse it safely. True in the baseline /// mode, so a caller always calls it the same way. 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(); } 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