feat: add coordLess and chunkStageName

This commit is contained in:
dualfroz committed 2026-09-06 21:13:51 +02:00
1 parent cac397d13b
commit c3953fca90
1 file changed
+163
+163
View File
@@ -0,0 +1,163 @@
#include "vf/ChunkPipeline.h"
#include <algorithm>
#include <chrono>
#include <numeric>
#include <string>
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 nanosSince(const std::chrono::steady_clock::time_point& start) {
auto elapsed = std::chrono::steady_clock::now() - start;
return static_cast<std::uint64_t>(
std::chrono::duration_cast<std::chrono::nanoseconds>(elapsed).count());
}
std::string coordLabel(const Vec3i& coord) {
return "chunk(" + std::to_string(coord.x) + "," + std::to_string(coord.y) + "," +
std::to_string(coord.z) + ")";
}
} // namespace
const char* chunkStageName(ChunkStage stage) {
switch (stage) {
case ChunkStage::Generate: return "generate";
case ChunkStage::Light: return "light";
case ChunkStage::Mesh: return "mesh";
case ChunkStage::Ready: return "ready";
}
return "unknown";
}
double PipelineStats::averageStageMs(ChunkStage stage) const {
std::size_t index = static_cast<std::size_t>(stage);
if (stageCompleted[index] == 0) return 0.0;
double total = static_cast<double>(stageNanos[index]);
return total / static_cast<double>(stageCompleted[index]) / 1000000.0;
}
ChunkPipeline::ChunkPipeline(const PipelineConfig& config)
: config(config),
generator(config.gen),
chunkStore(config.cacheBudgetBytes, config.cachePolicy),
jobs(config.threadCount) {}
void ChunkPipeline::setObserver(const Vec3i& chunkCoord) {
{
std::lock_guard<std::mutex> lock(controlMutex);
observerChunk = chunkCoord;
}
chunkStore.setObserver(chunkCoord);
}
Vec3i ChunkPipeline::observer() const {
std::lock_guard<std::mutex> lock(controlMutex);
return observerChunk;
}
long long ChunkPipeline::distanceSqLocked(const Vec3i& chunkCoord) const {
long long dx = chunkCoord.x - observerChunk.x;
long long dy = chunkCoord.y - observerChunk.y;
long long dz = chunkCoord.z - observerChunk.z;
return dx * dx + dy * dy + dz * dz;
}
bool ChunkPipeline::inViewVolumeLocked(const Vec3i& chunkCoord) const {
if (chunkCoord.y < 0 || chunkCoord.y >= config.verticalChunks) return false;
long long dx = chunkCoord.x - observerChunk.x;
long long dz = chunkCoord.z - observerChunk.z;
long long radius = config.viewRadius;
return dx * dx + dz * dz <= radius * radius;
}
bool ChunkPipeline::inViewVolume(const Vec3i& chunkCoord) const {
std::lock_guard<std::mutex> lock(controlMutex);
return inViewVolumeLocked(chunkCoord);
}
JobPriority ChunkPipeline::priorityFor(long long distanceSq) const {
long long radius = config.viewRadius;
long long radiusSq = radius * radius;
if (distanceSq * 9 <= radiusSq) return JobPriority::High;
if (distanceSq * 9 <= radiusSq * 4) return JobPriority::Normal;
return JobPriority::Low;
}
void ChunkPipeline::enqueue(const Vec3i& chunkCoord) {
std::lock_guard<std::mutex> lock(controlMutex);
if (!pendingSet.insert(chunkCoord).second) return;
pending.push_back(chunkCoord);
}
std::size_t ChunkPipeline::enqueueViewVolume() {
std::vector<Vec3i> volume;
{
std::lock_guard<std::mutex> lock(controlMutex);
int radius = config.viewRadius;
for (int dx = -radius; dx <= radius; ++dx) {
for (int dz = -radius; dz <= radius; ++dz) {
for (int y = 0; y < config.verticalChunks; ++y) {
Vec3i coord{observerChunk.x + dx, y, observerChunk.z + dz};
if (inViewVolumeLocked(coord)) volume.push_back(coord);
}
}
}
}
std::sort(volume.begin(), volume.end(), coordLess);
std::size_t added = 0;
for (const Vec3i& coord : volume) {
std::lock_guard<std::mutex> lock(controlMutex);
if (!pendingSet.insert(coord).second) continue;
pending.push_back(coord);
++added;
}
return added;
}
std::size_t ChunkPipeline::pendingCount() const {
std::lock_guard<std::mutex> lock(controlMutex);
return pending.size();
}
void ChunkPipeline::cancel(const Vec3i& chunkCoord) {
std::lock_guard<std::mutex> lock(controlMutex);
cancelledCoords.insert(chunkCoord);
auto active = activeIndex.find(chunkCoord);
if (active != activeIndex.end())
cancelFlags[active->second]->store(true, std::memory_order_release);
}
bool ChunkPipeline::isCancelled(const Vec3i& chunkCoord) const {
std::lock_guard<std::mutex> lock(controlMutex);
return cancelledCoords.count(chunkCoord) != 0;
}
std::vector<ChunkTask> ChunkPipeline::pendingTasks() const {
std::lock_guard<std::mutex> lock(controlMutex);
std::vector<ChunkTask> tasks;
tasks.reserve(pending.size());
for (const Vec3i& coord : pending) {
ChunkTask task;
task.coord = coord;
task.stage = ChunkStage::Generate;
task.distanceSq = distanceSqLocked(coord);
task.priority = priorityFor(task.distanceSq);
task.inRange = inViewVolumeLocked(coord);
tasks.push_back(task);
}
std::sort(tasks.begin(), tasks.end(), [](const ChunkTask& a, const ChunkTask& b) {
if (a.distanceSq != b.distanceSq) return a.distanceSq < b.distanceSq;
return coordLess(a.coord, b.coord);
});
return tasks;
}