Four review findings on the Task 7 renderer: - InstanceStore::epoch() is derived from gl::Buffer::generation() -- advanced by every allocation, deletion and move -- plus the slot the instances were written to, so the orphan fallback of grow_persistent() can no longer leave the vertex array's attribute pointers bound to a deleted buffer: the epoch reports the new identity and upload() re-points them before the draw. - PlotLayout reserves y_title_area/x_title_area outside axes (sized from the text metrics) and draw_titles() draws in them, so a title can no longer land on the data, whatever the envelope does. - draw() computes plot.layout() once and hands it to the helpers, instead of six times per frame, each of which rebuilt the ticks and the grid. - A refused fence is no longer dropped: mark_drawn() falls back to the orphan path and reports the failure rather than rotating through an unsynchronised slot. New smoke cases force both refusals through the GL entry points (glMapBufferRange, glFenceSync) and assert the pixels plus the live transfer mode; the title case asserts the title colour is absent from the bands inside axes and present in both strips. All three fail against the pre-fix sources.
79 lines
3.2 KiB
C++
79 lines
3.2 KiB
C++
#pragma once
|
|
#include <plot/core/status.hpp>
|
|
#include <plot/core/types.hpp>
|
|
#include <plot/gl/handle.hpp>
|
|
#include <plot/render/buffer.hpp>
|
|
|
|
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
|