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
+46
-4
@@ -310,18 +310,36 @@ const PlotLayout& Plot::layout() {
|
||||
y_width = y_axes_.empty() ? 0.0f : 2.0f * pad;
|
||||
x_height = text_->height() + 2.0f * pad;
|
||||
}
|
||||
// The title strips, though, are needed before the loop and never change, unlike
|
||||
// the label strips: a strip holds exactly one text line, so no tick label can
|
||||
// make it wider. Nothing at all is reserved without a text backend -- there is
|
||||
// then no title to measure, which is what keeps the two defaults above
|
||||
// meaningful for the no-text-backend case. The x strip is one text line tall;
|
||||
// the y strip is one horizontal run wide (see y_title_strip_width).
|
||||
const f32 y_title_w = text_ != nullptr ? y_title_strip_width() : 0.0f;
|
||||
const f32 x_title_h = text_ != nullptr && has_x_title() ? text_->height() + 2.0f * pad : 0.0f;
|
||||
|
||||
for (u32 pass = 0;; ++pass) {
|
||||
// Clamped to the viewport so a huge label set can never push the axes rect
|
||||
// outside it (or make its width negative).
|
||||
// outside it (or make its width negative). The title strips take what is left
|
||||
// after the label strip, so the two can never add up past the viewport.
|
||||
y_width = std::clamp(y_width, 0.0f, viewport_.w);
|
||||
x_height = std::clamp(x_height, 0.0f, viewport_.h);
|
||||
const f32 y_title_width = std::clamp(y_title_w, 0.0f, viewport_.w - y_width);
|
||||
const f32 x_title_height = std::clamp(x_title_h, 0.0f, viewport_.h - x_height);
|
||||
layout_.y_axis_width = y_width;
|
||||
layout_.x_axis_height = x_height;
|
||||
layout_.axes = Rect{viewport_.x + y_width, viewport_.y, viewport_.w - y_width,
|
||||
viewport_.h - x_height};
|
||||
layout_.y_label_area = Rect{viewport_.x, layout_.axes.y, y_width, layout_.axes.h};
|
||||
layout_.y_title_width = y_title_width;
|
||||
layout_.x_title_height = x_title_height;
|
||||
layout_.axes = Rect{viewport_.x + y_width + y_title_width, viewport_.y,
|
||||
viewport_.w - (y_width + y_title_width),
|
||||
viewport_.h - (x_height + x_title_height)};
|
||||
layout_.y_title_area = Rect{viewport_.x, layout_.axes.y, y_title_width, layout_.axes.h};
|
||||
layout_.y_label_area =
|
||||
Rect{layout_.y_title_area.right(), layout_.axes.y, y_width, layout_.axes.h};
|
||||
layout_.x_label_area = Rect{layout_.axes.x, layout_.axes.bottom(), layout_.axes.w, x_height};
|
||||
layout_.x_title_area = Rect{layout_.axes.x, layout_.x_label_area.bottom(), layout_.axes.w,
|
||||
x_title_height};
|
||||
|
||||
refresh_ticks();
|
||||
|
||||
@@ -367,6 +385,30 @@ f64 Plot::snapped_x(const Cursor& c) const {
|
||||
return c.x;
|
||||
}
|
||||
|
||||
bool Plot::has_x_title() const noexcept {
|
||||
for (const Axis& a : x_axes_) {
|
||||
if (!a.label.empty()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Plot::has_y_title() const noexcept {
|
||||
for (const Axis& a : y_axes_) {
|
||||
if (!a.label.empty()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
f32 Plot::y_title_strip_width() const {
|
||||
if (text_ == nullptr) return 0.0f;
|
||||
f32 widest = 0.0f;
|
||||
for (const Axis& a : y_axes_) {
|
||||
if (a.label.empty()) continue;
|
||||
widest = std::max(widest, text_->measure(a.label.c_str()));
|
||||
}
|
||||
return widest > 0.0f ? widest + 2.0f * style_.grid_label_pad : 0.0f;
|
||||
}
|
||||
|
||||
f32 Plot::y_label_width() const {
|
||||
if (text_ == nullptr || y_axes_.empty()) return 0.0f;
|
||||
f32 widest = 0.0f;
|
||||
|
||||
Reference in new issue
Block a user