fix(render): bind identity into the epoch, titles into reserved strips, one layout per frame
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.
This commit is contained in:
1 parent
3555ab63d7
commit
8f45108559
11 files changed
+492
-70
No files matched your search
@@ -71,9 +71,13 @@ class InstanceStore {
|
||||
|
||||
/// Records that the draw the caller just issued read the current slot, so the
|
||||
/// fence guarding that slot's reuse ends up in the command stream behind the
|
||||
/// draw. A no-op in `Orphan` mode, where nothing reads the store after the
|
||||
/// orphan.
|
||||
void mark_drawn() noexcept;
|
||||
/// draw. True when the slot is guarded, and always in `Orphan` mode, where
|
||||
/// nothing reads the store after the orphan.
|
||||
///
|
||||
/// False when the driver refused the fence: the slot would stay unsynchronised,
|
||||
/// so the store drops the mapped ring for the orphan path instead of rotating
|
||||
/// through it (the caller reports the failure -- see `Renderer`).
|
||||
bool mark_drawn() noexcept;
|
||||
|
||||
/// Byte offset the current slot's instances start at: 0 in `Orphan` mode,
|
||||
/// `slot * slot_bytes` in `PersistentMapped` mode. The vertex array re-points
|
||||
@@ -84,7 +88,14 @@ class InstanceStore {
|
||||
|
||||
/// Changes whenever the staged instances moved (a new slot) or the GL buffer
|
||||
/// was recreated, i.e. whenever attribute pointers into this store went stale.
|
||||
u32 epoch() const noexcept { return epoch_; }
|
||||
///
|
||||
/// Derived from the two things that can make them stale rather than bumped by
|
||||
/// hand at every site that replaces the buffer object: `gl::Buffer::generation()`
|
||||
/// advances on every allocation and deletion (so a fallback that re-creates the
|
||||
/// buffer cannot leave the vertex array bound to a deleted one), and `slot_epoch_`
|
||||
/// advances on every upload that lands in a new slot. Both counters only ever
|
||||
/// increase, so their sum changes whenever either does, and never repeats.
|
||||
u32 epoch() const noexcept { return buffer_.generation() + slot_epoch_; }
|
||||
|
||||
void bind() const noexcept { buffer_.bind(); }
|
||||
bool persistent() const noexcept { return mode_ == UploadMode::PersistentMapped; }
|
||||
@@ -103,7 +114,9 @@ class InstanceStore {
|
||||
u32 capacity_ = 0; ///< instances the orphan store can hold
|
||||
usize slot_bytes_ = 0; ///< bytes per slot of the persistent ring
|
||||
u32 slot_ = kSlots - 1u; ///< last slot written; an upload advances it first
|
||||
u32 epoch_ = 0;
|
||||
/// Times an upload landed in a new slot. Kept apart from the buffer's own
|
||||
/// identity (see `epoch()`) so neither has to know about the other.
|
||||
u32 slot_epoch_ = 0;
|
||||
u8* mapped_ = nullptr; ///< base of the mapped ring, null in `Orphan` mode
|
||||
gl::Fence fences_[kSlots];
|
||||
};
|
||||
@@ -119,7 +132,7 @@ class LineBuffer {
|
||||
void upload(const f32* interleaved, u32 count) noexcept {
|
||||
store_.upload(interleaved, count, sizeof(LineInstance));
|
||||
}
|
||||
void mark_drawn() noexcept { store_.mark_drawn(); }
|
||||
bool mark_drawn() noexcept { return store_.mark_drawn(); }
|
||||
usize slot_offset() const noexcept { return store_.slot_offset(); }
|
||||
u32 epoch() const noexcept { return store_.epoch(); }
|
||||
bool persistent() const noexcept { return store_.persistent(); }
|
||||
@@ -138,7 +151,7 @@ class TextBuffer {
|
||||
void upload(const f32* interleaved, u32 count) noexcept {
|
||||
store_.upload(interleaved, count, sizeof(TextInstance));
|
||||
}
|
||||
void mark_drawn() noexcept { store_.mark_drawn(); }
|
||||
bool mark_drawn() noexcept { return store_.mark_drawn(); }
|
||||
usize slot_offset() const noexcept { return store_.slot_offset(); }
|
||||
u32 epoch() const noexcept { return store_.epoch(); }
|
||||
bool persistent() const noexcept { return store_.persistent(); }
|
||||
|
||||
Reference in new issue
Block a user