perf: resolve the portrait's widget once rather than every frame

findByName compares the name of every widget in the tree, and the tree holds
some eight and a half thousand after FrameXML loads. Ids are stable, so the
lookup is kept and reused; the name is still checked each frame because
reloading the interface rebuilds the tree and an id could then belong to
something else.
This commit is contained in:
Kelsi
2026-08-01 20:07:16 -07:00
parent 37de38eff4
commit c08fcffe4d
2 changed files with 12 additions and 2 deletions

View File

@@ -154,6 +154,11 @@ private:
ui::WidgetRenderer widgetRenderer_;
/// The live head-and-shoulders view the interface's portrait draws.
ui::UnitPortrait unitPortrait_;
/// Where the portrait's widget was found last time. Ids are stable, so
/// this saves a scan of every widget by name on every frame; the name is
/// still checked, because reloading the interface rebuilds the tree and
/// the id could then belong to something else.
uint32_t portraitWidgetId_ = 0;
bool addonsLoaded_ = false;
std::unique_ptr<game::ExpansionRegistry> expansionRegistry_;
// Empty means assets follow the active protocol profile. "legacy" selects

View File

@@ -2873,9 +2873,14 @@ void Application::render() {
// descriptor set that has been destroyed — the render target is
// torn down whenever the model is rebuilt — and drawing from
// that is a use-after-free rather than a stale picture.
if (auto* w = engine->widgets().findByName("PlayerPortrait")) {
w->externalTexture = unitPortrait_.textureId();
auto& widgets = engine->widgets();
ui::Widget* portrait = portraitWidgetId_
? widgets.get(portraitWidgetId_) : nullptr;
if (!portrait || portrait->name != "PlayerPortrait") {
portrait = widgets.findByName("PlayerPortrait");
portraitWidgetId_ = portrait ? portrait->id : 0;
}
if (portrait) portrait->externalTexture = unitPortrait_.textureId();
}
// Lay out first: hit testing reads the rects this produces, so