Update aurora & utilize RmlUi culling

Huge improvement to Mod Manager performance in particular
This commit is contained in:
Luke Street
2026-09-29 22:44:36 -06:00
parent ceda410434
commit eb5ad19dbc
5 changed files with 40 additions and 50 deletions
+1 -1
+1
View File
@@ -59,6 +59,7 @@ mod-entry {
transition: decorator 0.1s linear-in-out;
cursor: pointer;
focus: auto;
contain: paint;
}
mod-entry.current {
+1
View File
@@ -147,6 +147,7 @@ ui-list-content {
ui-list-content > button.ui-list-row {
flex: 0 0 auto;
contain: paint;
}
ui-list-empty {
+32 -45
View File
@@ -32,7 +32,7 @@ List::List(Rml::Element* parent, Props props)
mEmpty = append_element(mRoot, "ui-list-empty");
append_text(mEmpty, "No items");
Component::listen(mViewport, Rml::EventId::Scroll, [this](Rml::Event&) { mCullDirty = true; });
Component::listen(mViewport, Rml::EventId::Scroll, [this](Rml::Event&) { mRangeDirty = true; });
listen(Rml::EventId::Keydown, [this](Rml::Event& event) { handle_keydown(event); });
apply_items(std::move(mProps.items));
@@ -52,19 +52,13 @@ void List::update() {
apply_items(std::move(items), snapshotFocus);
}
for (const auto& row : mRows) {
if (!row->culled) {
row->button->update();
}
}
const float scrollTop = mViewport->GetScrollTop();
const float viewportWidth = mViewport->GetClientWidth();
const float viewportHeight = mViewport->GetClientHeight();
if (scrollTop != mLastScrollTop || viewportWidth != mLastViewportWidth ||
viewportHeight != mLastViewportHeight)
{
mCullDirty = true;
mRangeDirty = true;
if (viewportWidth != mLastViewportWidth || viewportHeight != mLastViewportHeight) {
mLayoutScanFrames = std::max(mLayoutScanFrames, 2);
}
@@ -73,14 +67,25 @@ void List::update() {
mLastViewportHeight = viewportHeight;
}
if (mCullDirty || mLayoutScanFrames > 0) {
update_culling();
mCullDirty = false;
if (mRangeDirty || mLayoutScanFrames > 0) {
update_active_range();
mRangeDirty = false;
if (mLayoutScanFrames > 0) {
--mLayoutScanFrames;
}
}
if (mUpdateAllRows) {
mUpdateAllRows = false;
for (const auto& row : mRows) {
row->button->update();
}
} else {
for (size_t i = mActiveFirst; i < std::min(mActiveLast, mRows.size()); ++i) {
mRows[i]->button->update();
}
}
update_pending_focus();
}
@@ -156,7 +161,6 @@ std::unique_ptr<List::Row> List::create_row(const Item& item) {
[this, key = item.key] { return mProps.isDisabled && mProps.isDisabled(key); },
});
row->button->root()->SetClass("ui-list-row", true);
row->button->root()->SetProperty("visibility", "hidden");
row->button->Component::listen(row->button->root(), Rml::EventId::Focus,
[this, key = item.key](Rml::Event&) { mActiveKey = key; });
row->button->on_pressed([this, key = item.key] {
@@ -230,43 +234,29 @@ void List::apply_items(std::vector<Item> items, const std::optional<SnapshotFocu
mPendingFocusMayEnterList = false;
}
mCullDirty = true;
mRangeDirty = true;
mUpdateAllRows = true;
mLayoutScanFrames = 2;
}
void List::update_culling() {
const float viewTop = mViewport->GetAbsoluteOffset(Rml::BoxArea::Border).y;
void List::update_active_range() {
mActiveFirst = 0;
mActiveLast = 0;
const float viewHeight = mViewport->GetClientHeight();
if (viewHeight <= 0.0f) {
return;
}
auto* context = mRoot->GetContext();
const Row* focusedRow = context != nullptr ? row_from_element(context->GetFocusElement()) : nullptr;
for (const auto& row : mRows) {
auto* element = row->button->root();
const float top = element->GetAbsoluteOffset(Rml::BoxArea::Border).y - viewTop;
const bool inWindow =
top + element->GetOffsetHeight() >= -viewHeight && top <= viewHeight * 2.0f;
const bool focusGuard =
row.get() == focusedRow || (mPendingFocusKey && row->key == *mPendingFocusKey);
const bool shouldShow = inWindow || focusGuard;
if (shouldShow && row->culled) {
show_row(*row);
} else if (!shouldShow && !row->culled) {
row->culled = true;
element->SetProperty("visibility", "hidden");
}
}
}
void List::show_row(Row& row) {
if (!row.culled) {
return;
}
row.button->update();
row.button->root()->RemoveProperty("visibility");
row.culled = false;
const float viewTop = mViewport->GetAbsoluteOffset(Rml::BoxArea::Border).y;
const auto rowTop = [](const std::unique_ptr<Row>& row) {
return row->button->root()->GetAbsoluteOffset(Rml::BoxArea::Border).y;
};
const auto first = std::ranges::partition_point(mRows, [&](const auto& row) {
return rowTop(row) + row->button->root()->GetOffsetHeight() < viewTop - viewHeight;
});
const auto last = std::ranges::partition_point(first, mRows.end(),
[&](const auto& row) { return rowTop(row) <= viewTop + viewHeight * 2.0f; });
mActiveFirst = static_cast<size_t>(first - mRows.begin());
mActiveLast = static_cast<size_t>(last - mRows.begin());
}
bool List::focus_row(int index, bool mayEnterList) {
@@ -274,7 +264,6 @@ bool List::focus_row(int index, bool mayEnterList) {
return false;
}
auto& row = *mRows[index];
show_row(row);
row.button->update();
if (row.button->root()->IsPseudoClassSet("disabled")) {
return false;
@@ -295,7 +284,6 @@ void List::request_focus(uint64_t key, bool mayEnterList) {
if (it == mRowsByKey.end()) {
return;
}
show_row(*it->second);
mPendingFocusKey = key;
mPendingFocusFrames = 2;
mPendingFocusMayEnterList = mayEnterList;
@@ -329,7 +317,6 @@ void List::update_pending_focus() {
}
auto& row = *it->second;
show_row(row);
row.button->update();
if (!row.button->root()->IsPseudoClassSet("disabled") && row.button->focus()) {
mActiveKey = row.key;
+5 -4
View File
@@ -42,7 +42,6 @@ private:
struct Row {
uint64_t key = 0;
std::unique_ptr<ControlledButton> button;
bool culled = true;
};
Row* row_from_element(Rml::Element* element) const;
@@ -50,8 +49,7 @@ private:
SnapshotFocus capture_snapshot_focus();
std::unique_ptr<Row> create_row(const Item& item);
void apply_items(std::vector<Item> items, const std::optional<SnapshotFocus>& snapshotFocus = {});
void update_culling();
void show_row(Row& row);
void update_active_range();
bool focus_row(int index, bool mayEnterList);
void request_focus(uint64_t key, bool mayEnterList);
void update_pending_focus();
@@ -70,7 +68,10 @@ private:
std::optional<uint64_t> mPendingFocusKey;
int mPendingFocusFrames = 0;
bool mPendingFocusMayEnterList = false;
bool mCullDirty = true;
size_t mActiveFirst = 0;
size_t mActiveLast = 0;
bool mRangeDirty = true;
bool mUpdateAllRows = true;
int mLayoutScanFrames = 2;
float mLastScrollTop = -1.0f;
float mLastViewportWidth = -1.0f;