godot_voxel/util/tasks/progressive_task_runner.cpp
2022-01-03 23:14:18 +00:00

56 lines
1.7 KiB
C++

#include "progressive_task_runner.h"
namespace zylann {
ProgressiveTaskRunner::~ProgressiveTaskRunner() {
flush();
ERR_FAIL_COND_MSG(_tasks.size() > 0, "Tasks got created in destructors?");
}
void ProgressiveTaskRunner::push(IProgressiveTask *task) {
ERR_FAIL_COND(task == nullptr);
_tasks.push(task);
}
void ProgressiveTaskRunner::process() {
const int64_t now_msec = Time::get_singleton()->get_ticks_msec();
const int64_t delta_msec = now_msec - _last_process_time_msec;
_last_process_time_msec = now_msec;
ERR_FAIL_COND(delta_msec < 0);
// The goal is to dequeue everything in S seconds.
// So if we have N tasks and `process` is called F times per second, we must dequeue N / (S * F) tasks.
// Or put it another way, if we call `process` every D seconds, we must dequeue (D * N) / S tasks.
// We make sure a minimum amount is run so it cannot be stuck at 0.
// As the number of pending tasks decreases, we want to keep running the highest amount we calculated.
// we reset when we are done.
_dequeue_count = math::max(int64_t(_dequeue_count), (int64_t(_tasks.size()) * delta_msec) / COMPLETION_TIME_MSEC);
_dequeue_count = math::min(_dequeue_count, math::max(MIN_COUNT, unsigned int(_tasks.size())));
unsigned int count = _dequeue_count;
while (_tasks.size() > 0 && count > 0) {
IProgressiveTask *task = _tasks.front();
_tasks.pop();
task->run();
// TODO Call recycling function instead?
memdelete(task);
--count;
}
}
void ProgressiveTaskRunner::flush() {
while (!_tasks.empty()) {
IProgressiveTask *task = _tasks.front();
_tasks.pop();
task->run();
memdelete(task);
}
}
unsigned int ProgressiveTaskRunner::get_pending_count() const {
return _tasks.size();
}
} // namespace zylann