mirror of
https://github.com/coop-deluxe/sm64coopdx.git
synced 2026-05-10 19:01:46 +00:00
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run
Loading the scroll targets was probably the slowest parts to loading a romhack. The reason for this is that many romhacks can have thousands of calls to `add_scroll_target`. So, for 4,107 calls to `add_scroll_target`, the time went from ~4.5759 seconds to ~0.0173 seconds in total. Changes made: - Previously, simply finding the material data to scroll was rather slow due to using a linear sub string search across all vertices in all levels. To speed this up, I added a cache. The cache bypasses checking every level by storing the exact string (rather than the substring) in a hashmap, so lookups become a simple case of a string lookup as a key in the map. It falls back to the full lookup if the cache doesn't hit. - Changed the vertex buffer management in `scroll_targets.c` to behave closer to a modern dynamic array, where buffer size is doubled each time a new vertex buffer is added, to reduce the number of allocations performed.
69 lines
2.1 KiB
C++
69 lines
2.1 KiB
C++
#include <unordered_map>
|
|
#include <string_view>
|
|
#include <string>
|
|
#include "dynos.cpp.h"
|
|
extern "C" {
|
|
#include "game/scroll_targets.h"
|
|
}
|
|
|
|
//
|
|
// Scroll Targets
|
|
//
|
|
|
|
static void DynOS_Add_Scroll_Target_Match(u32 index, const char* name, u32 offset, u32 size, DataNode<Vtx>* node) {
|
|
if (offset >= node->mSize) { return; }
|
|
u32 finalSize = (size > 0 && size <= (node->mSize - offset)) ? size : (node->mSize - offset);
|
|
add_vtx_scroll_target(
|
|
index,
|
|
&node->mData[offset],
|
|
finalSize,
|
|
offset > 0
|
|
);
|
|
}
|
|
|
|
void DynOS_Add_Scroll_Target(u32 index, const char* name, u32 offset, u32 size) {
|
|
static std::unordered_multimap<std::string_view, DataNode<Vtx>*> sVertexNodesExactMap;
|
|
static std::vector<GfxData*> sLvlGfxDataCache; // cache existing level pointers to know when to rebuild
|
|
|
|
auto& lvlArray = DynOS_Lvl_GetArray();
|
|
|
|
// Check if cache needs rebuilding
|
|
bool rebuild = (lvlArray.size() != sLvlGfxDataCache.size());
|
|
if (!rebuild) {
|
|
for (size_t i = 0; i < lvlArray.size(); ++i) {
|
|
if (lvlArray[i].second != sLvlGfxDataCache[i]) {
|
|
rebuild = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rebuild) {
|
|
sVertexNodesExactMap.clear();
|
|
sLvlGfxDataCache.clear();
|
|
for (const auto& lvlPair : lvlArray) {
|
|
sLvlGfxDataCache.push_back(lvlPair.second);
|
|
for (const auto& node : lvlPair.second->mVertices) {
|
|
sVertexNodesExactMap.emplace(std::string_view(node->mName.begin(), node->mName.Length()), node);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check exact match
|
|
auto range = sVertexNodesExactMap.equal_range(name);
|
|
if (range.first != range.second) {
|
|
for (auto it = range.first; it != range.second; ++it) {
|
|
DynOS_Add_Scroll_Target_Match(index, name, offset, size, it->second);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Fallback to substring search
|
|
for (const auto& lvlPair : lvlArray) {
|
|
for (const auto& node : lvlPair.second->mVertices) {
|
|
if (node->mName.Find(name) >= 0) {
|
|
DynOS_Add_Scroll_Target_Match(index, name, offset, size, node);
|
|
}
|
|
}
|
|
}
|
|
}
|