Added stats to VoxelLodTerrain

This commit is contained in:
Marc Gilleron 2019-05-05 01:09:12 +01:00
parent 8850019dc4
commit d93f23337a
8 changed files with 92 additions and 11 deletions

View File

@ -1,10 +1,10 @@
#include "voxel_lod_terrain.h"
#include "../math/rect3i.h"
#include "../util/profiling_clock.h"
#include "voxel_map.h"
#include "voxel_mesh_updater.h"
#include "voxel_provider_thread.h"
#include <core/engine.h>
#include <core/os/os.h>
VoxelLodTerrain::VoxelLodTerrain() {
@ -13,7 +13,7 @@ VoxelLodTerrain::VoxelLodTerrain() {
_lods[0].map.instance();
set_lod_count(8);
set_lod_split_scale(3);
set_lod_split_scale(4);
reset_updater();
}
@ -382,6 +382,8 @@ void VoxelLodTerrain::_process() {
Vector3 viewer_pos = get_viewer_pos();
Vector3i viewer_block_pos = _lods[0].map->voxel_to_block(viewer_pos);
ProfilingClock profiling_clock;
// Here we go...
// Find out which blocks _data_ need to be loaded
@ -466,12 +468,15 @@ void VoxelLodTerrain::_process() {
_provider_thread->push(input);
}
_stats.time_request_blocks_to_load = profiling_clock.restart();
// Get block loading responses
// Note: if block loading is too fast, this can cause stutters.
// It should only happen on first load, though.
{
VoxelProviderThread::OutputData output;
_provider_thread->pop(output);
_stats.provider = output.stats;
for (int i = 0; i < output.emerged_blocks.size(); ++i) {
@ -541,6 +546,8 @@ void VoxelLodTerrain::_process() {
}
}
_stats.time_process_load_responses = profiling_clock.restart();
// Send mesh updates
{
VoxelMeshUpdater::Input input;
@ -587,11 +594,14 @@ void VoxelLodTerrain::_process() {
_block_updater->push(input);
}
_stats.time_request_blocks_to_update = profiling_clock.restart();
// Receive mesh updates
{
{
VoxelMeshUpdater::Output output;
_block_updater->pop(output);
_stats.updater = output.stats;
for (unsigned int i = 0; i < output.blocks.size(); ++i) {
const VoxelMeshUpdater::OutputBlock &ob = output.blocks[i];
@ -666,6 +676,8 @@ void VoxelLodTerrain::_process() {
shift_up(_blocks_pending_main_thread_update, queue_index);
}
_stats.time_process_update_responses = profiling_clock.restart();
// Find out which blocks need to be shown
{
struct SubdivideAction {
@ -733,6 +745,25 @@ void VoxelLodTerrain::_process() {
_lod_octree.update(viewer_pos, subdivide_action, unsubdivide_action);
}
_stats.time_process_lod = profiling_clock.restart();
}
Dictionary VoxelLodTerrain::get_stats() const {
Dictionary process;
process["time_request_blocks_to_load"] = _stats.time_request_blocks_to_load;
process["time_process_load_responses"] = _stats.time_process_load_responses;
process["time_request_blocks_to_update"] = _stats.time_request_blocks_to_update;
process["time_process_update_responses"] = _stats.time_process_update_responses;
process["time_process_lod"] = _stats.time_process_lod;
Dictionary d;
d["provider"] = VoxelProviderThread::to_dictionary(_stats.provider);
d["updater"] = VoxelMeshUpdater::to_dictionary(_stats.updater);
d["process"] = process;
return d;
}
void VoxelLodTerrain::_bind_methods() {
@ -752,6 +783,7 @@ void VoxelLodTerrain::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_block_state", "block_pos", "lod"), &VoxelLodTerrain::get_block_state);
ClassDB::bind_method(D_METHOD("is_block_meshed", "block_pos", "lod"), &VoxelLodTerrain::is_block_meshed);
ClassDB::bind_method(D_METHOD("is_block_shown", "block_pos", "lod"), &VoxelLodTerrain::is_block_shown);
ClassDB::bind_method(D_METHOD("get_stats"), &VoxelLodTerrain::get_stats);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "provider", PROPERTY_HINT_RESOURCE_TYPE, "VoxelProvider"), "set_provider", "get_provider");
ADD_PROPERTY(PropertyInfo(Variant::INT, "view_distance"), "set_view_distance", "get_view_distance");

View File

@ -5,11 +5,11 @@
#include "lod_octree.h"
#include "voxel_map.h"
#include "voxel_mesh_updater.h"
#include "voxel_provider_thread.h"
#include <core/set.h>
#include <scene/3d/spatial.h>
class VoxelMap;
class VoxelProviderThread;
// Paged terrain made of voxel blocks of variable level of detail.
// Designed for highest view distances, preferably using smooth voxels.
@ -53,6 +53,18 @@ public:
bool is_block_meshed(Vector3 bpos, unsigned int lod_index) const;
bool is_block_shown(Vector3 bpos, unsigned int lod_index) const;
struct Stats {
VoxelMeshUpdater::Stats updater;
VoxelProviderThread::Stats provider;
uint64_t time_request_blocks_to_load = 0;
uint64_t time_process_load_responses = 0;
uint64_t time_request_blocks_to_update = 0;
uint64_t time_process_update_responses = 0;
uint64_t time_process_lod = 0;
};
Dictionary get_stats() const;
protected:
static void _bind_methods();
@ -113,6 +125,8 @@ private:
};
Lod _lods[MAX_LOD];
Stats _stats;
};
VARIANT_ENUM_CAST(VoxelLodTerrain::BlockState)

View File

@ -307,3 +307,11 @@ void VoxelMeshUpdater::thread_sync(int queue_index, Stats stats) {
sorter.sort(_input.blocks.ptrw(), _input.blocks.size());
}
}
Dictionary VoxelMeshUpdater::to_dictionary(const Stats &stats) {
Dictionary d;
d["min_time"] = stats.min_time;
d["max_time"] = stats.max_time;
d["remaining_blocks"] = stats.remaining_blocks;
return d;
}

View File

@ -61,6 +61,8 @@ public:
int get_required_padding() const;
static Dictionary to_dictionary(const Stats &stats);
private:
static void _thread_func(void *p_self);
void thread_func();

View File

@ -207,3 +207,11 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) {
sorter.sort(_input.blocks_to_emerge.ptrw(), _input.blocks_to_emerge.size());
}
}
Dictionary VoxelProviderThread::to_dictionary(const Stats &stats) {
Dictionary d;
d["min_time"] = stats.min_time;
d["max_time"] = stats.max_time;
d["remaining_blocks"] = stats.remaining_blocks;
return d;
}

View File

@ -57,6 +57,8 @@ public:
void push(const InputData &input);
void pop(OutputData &out_data);
static Dictionary to_dictionary(const Stats &stats);
private:
static void _thread_func(void *p_self);

View File

@ -218,16 +218,10 @@ void VoxelTerrain::immerge_block(Vector3i bpos) {
Dictionary VoxelTerrain::get_statistics() const {
Dictionary provider;
provider["min_time"] = _stats.provider.min_time;
provider["max_time"] = _stats.provider.max_time;
provider["remaining_blocks"] = _stats.provider.remaining_blocks;
Dictionary provider = VoxelProviderThread::to_dictionary(_stats.provider);
provider["dropped_blocks"] = _stats.dropped_provider_blocks;
Dictionary updater;
updater["min_time"] = _stats.updater.min_time;
updater["max_time"] = _stats.updater.max_time;
updater["remaining_blocks"] = _stats.updater.remaining_blocks;
Dictionary updater = VoxelMeshUpdater::to_dictionary(_stats.updater);
updater["updated_blocks"] = _stats.updated_blocks;
updater["mesh_alloc_time"] = _stats.mesh_alloc_time;
updater["dropped_blocks"] = _stats.dropped_updater_blocks;

21
util/profiling_clock.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef PROFILING_CLOCK_H
#define PROFILING_CLOCK_H
#include <core/os/os.h>
struct ProfilingClock {
uint64_t time_before = 0;
ProfilingClock() {
restart();
}
uint64_t restart() {
uint64_t now = OS::get_singleton()->get_ticks_usec();
uint64_t time_spent = now - time_before;
time_before = OS::get_singleton()->get_ticks_usec();
return time_spent;
}
};
#endif // PROFILING_CLOCK_H