Added stats to VoxelLodTerrain
This commit is contained in:
parent
8850019dc4
commit
d93f23337a
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
21
util/profiling_clock.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user