feat: add coordLess

This commit is contained in:
dualfroz committed 2026-09-06 21:09:17 +02:00
1 parent e1eef931ac
commit b0704f42d2
1 file changed
+159
+159
View File
@@ -0,0 +1,159 @@
#include "vf/ChunkCache.h"
#include <algorithm>
#include <mutex>
namespace vf {
namespace {
bool coordLess(const Vec3i& a, const Vec3i& b) {
if (a.x != b.x) return a.x < b.x;
if (a.y != b.y) return a.y < b.y;
return a.z < b.z;
}
std::uint64_t meshBytes(const ChunkMesh& mesh) {
std::uint64_t total = 0;
total += static_cast<std::uint64_t>(mesh.opaque.vertices.size()) * sizeof(Vertex);
total += static_cast<std::uint64_t>(mesh.opaque.indices.size()) * sizeof(std::uint32_t);
total += static_cast<std::uint64_t>(mesh.transparent.vertices.size()) * sizeof(Vertex);
total += static_cast<std::uint64_t>(mesh.transparent.indices.size()) * sizeof(std::uint32_t);
return total;
}
} // namespace
ChunkCache::ChunkCache(std::uint64_t byteBudget, CachePolicy policy)
: budget(byteBudget), replacement(policy) {}
std::uint64_t ChunkCache::entrySizeBytes(const Chunk& chunk, const ChunkMesh& mesh) {
return static_cast<std::uint64_t>(chunk.raw().size() * sizeof(Block)) + meshBytes(mesh);
}
void ChunkCache::setByteBudget(std::uint64_t bytes) {
std::unique_lock<std::shared_mutex> lock(mutex);
budget = bytes;
enforceBudgetLocked();
}
void ChunkCache::setPolicy(CachePolicy policy) {
std::unique_lock<std::shared_mutex> lock(mutex);
replacement = policy;
}
void ChunkCache::setDistanceWeight(std::uint64_t weight) {
std::unique_lock<std::shared_mutex> lock(mutex);
distanceWeight = weight;
}
void ChunkCache::setObserver(const Vec3i& chunkCoord) {
std::unique_lock<std::shared_mutex> lock(mutex);
observerChunk = chunkCoord;
for (auto& slot : entries) slot.second.distanceSq = distanceSqTo(slot.first);
}
std::uint64_t ChunkCache::byteBudget() const {
std::shared_lock<std::shared_mutex> lock(mutex);
return budget;
}
CachePolicy ChunkCache::policy() const {
std::shared_lock<std::shared_mutex> lock(mutex);
return replacement;
}
Vec3i ChunkCache::observer() const {
std::shared_lock<std::shared_mutex> lock(mutex);
return observerChunk;
}
long long ChunkCache::distanceSqTo(const Vec3i& coord) const {
long long dx = coord.x - observerChunk.x;
long long dy = coord.y - observerChunk.y;
long long dz = coord.z - observerChunk.z;
return dx * dx + dy * dy + dz * dz;
}
std::uint64_t ChunkCache::evictionScoreLocked(const CacheEntry& entry) const {
std::uint64_t age = clock - entry.lastUse;
if (replacement == CachePolicy::Lru) return age;
return age + distanceWeight * static_cast<std::uint64_t>(entry.distanceSq);
}
void ChunkCache::touchLocked(CacheEntry& entry) {
entry.lastUse = ++clock;
}
void ChunkCache::dropMeshLocked(CacheEntry& entry) {
used -= meshBytes(entry.mesh);
entry.mesh = ChunkMesh{};
entry.hasMesh = false;
entry.bytes = entrySizeBytes(entry.chunk, entry.mesh);
}
void ChunkCache::eraseLocked(const Vec3i& coord) {
auto slot = entries.find(coord);
if (slot == entries.end()) return;
used -= slot->second.bytes;
entries.erase(slot);
}
void ChunkCache::enforceBudgetLocked() {
while (used > budget) {
const CacheEntry* victim = nullptr;
std::uint64_t bestScore = 0;
for (const auto& slot : entries) {
if (slot.second.pinned) continue;
std::uint64_t score = evictionScoreLocked(slot.second);
if (victim == nullptr || score > bestScore ||
(score == bestScore && coordLess(slot.first, victim->coord))) {
victim = &slot.second;
bestScore = score;
}
}
if (victim == nullptr) return;
Vec3i victimCoord = victim->coord;
eraseLocked(victimCoord);
++counters.evictions;
}
}
void ChunkCache::store(const Vec3i& coord, const Chunk& chunk) {
store(coord, chunk, ChunkMesh{});
}
void ChunkCache::store(const Vec3i& coord, const Chunk& chunk, const ChunkMesh& mesh) {
std::unique_lock<std::shared_mutex> lock(mutex);
auto slot = entries.find(coord);
bool wasPinned = slot != entries.end() && slot->second.pinned;
if (slot != entries.end()) used -= slot->second.bytes;
CacheEntry entry;
entry.coord = coord;
entry.chunk = chunk;
entry.mesh = mesh;
entry.hasMesh = !mesh.empty();
entry.pinned = wasPinned;
entry.distanceSq = distanceSqTo(coord);
entry.bytes = entrySizeBytes(chunk, mesh);
entry.lastUse = ++clock;
used += entry.bytes;
entries[coord] = std::move(entry);
enforceBudgetLocked();
}
bool ChunkCache::fetchChunk(const Vec3i& coord, Chunk& out) {
std::unique_lock<std::shared_mutex> lock(mutex);
auto slot = entries.find(coord);
if (slot == entries.end()) {
++counters.misses;
return false;
}
++counters.hits;
touchLocked(slot->second);
out = slot->second.chunk;
return true;
}