feat: add coordLess and chunkStageName
This commit is contained in:
1 parent
cac397d13b
commit
c3953fca90
1 file changed
+163
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in new issue
Block a user