mirror of
https://github.com/Relintai/godot_voxel.git
synced 2025-02-10 21:00:08 +01:00
Added stats to VoxelLodTerrain
This commit is contained in:
parent
8850019dc4
commit
d93f23337a
@ -1,10 +1,10 @@
|
|||||||
#include "voxel_lod_terrain.h"
|
#include "voxel_lod_terrain.h"
|
||||||
#include "../math/rect3i.h"
|
#include "../math/rect3i.h"
|
||||||
|
#include "../util/profiling_clock.h"
|
||||||
#include "voxel_map.h"
|
#include "voxel_map.h"
|
||||||
#include "voxel_mesh_updater.h"
|
#include "voxel_mesh_updater.h"
|
||||||
#include "voxel_provider_thread.h"
|
#include "voxel_provider_thread.h"
|
||||||
#include <core/engine.h>
|
#include <core/engine.h>
|
||||||
#include <core/os/os.h>
|
|
||||||
|
|
||||||
VoxelLodTerrain::VoxelLodTerrain() {
|
VoxelLodTerrain::VoxelLodTerrain() {
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ VoxelLodTerrain::VoxelLodTerrain() {
|
|||||||
_lods[0].map.instance();
|
_lods[0].map.instance();
|
||||||
|
|
||||||
set_lod_count(8);
|
set_lod_count(8);
|
||||||
set_lod_split_scale(3);
|
set_lod_split_scale(4);
|
||||||
|
|
||||||
reset_updater();
|
reset_updater();
|
||||||
}
|
}
|
||||||
@ -382,6 +382,8 @@ void VoxelLodTerrain::_process() {
|
|||||||
Vector3 viewer_pos = get_viewer_pos();
|
Vector3 viewer_pos = get_viewer_pos();
|
||||||
Vector3i viewer_block_pos = _lods[0].map->voxel_to_block(viewer_pos);
|
Vector3i viewer_block_pos = _lods[0].map->voxel_to_block(viewer_pos);
|
||||||
|
|
||||||
|
ProfilingClock profiling_clock;
|
||||||
|
|
||||||
// Here we go...
|
// Here we go...
|
||||||
|
|
||||||
// Find out which blocks _data_ need to be loaded
|
// Find out which blocks _data_ need to be loaded
|
||||||
@ -466,12 +468,15 @@ void VoxelLodTerrain::_process() {
|
|||||||
_provider_thread->push(input);
|
_provider_thread->push(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_stats.time_request_blocks_to_load = profiling_clock.restart();
|
||||||
|
|
||||||
// Get block loading responses
|
// Get block loading responses
|
||||||
// Note: if block loading is too fast, this can cause stutters.
|
// Note: if block loading is too fast, this can cause stutters.
|
||||||
// It should only happen on first load, though.
|
// It should only happen on first load, though.
|
||||||
{
|
{
|
||||||
VoxelProviderThread::OutputData output;
|
VoxelProviderThread::OutputData output;
|
||||||
_provider_thread->pop(output);
|
_provider_thread->pop(output);
|
||||||
|
_stats.provider = output.stats;
|
||||||
|
|
||||||
for (int i = 0; i < output.emerged_blocks.size(); ++i) {
|
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
|
// Send mesh updates
|
||||||
{
|
{
|
||||||
VoxelMeshUpdater::Input input;
|
VoxelMeshUpdater::Input input;
|
||||||
@ -587,11 +594,14 @@ void VoxelLodTerrain::_process() {
|
|||||||
_block_updater->push(input);
|
_block_updater->push(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_stats.time_request_blocks_to_update = profiling_clock.restart();
|
||||||
|
|
||||||
// Receive mesh updates
|
// Receive mesh updates
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
VoxelMeshUpdater::Output output;
|
VoxelMeshUpdater::Output output;
|
||||||
_block_updater->pop(output);
|
_block_updater->pop(output);
|
||||||
|
_stats.updater = output.stats;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < output.blocks.size(); ++i) {
|
for (unsigned int i = 0; i < output.blocks.size(); ++i) {
|
||||||
const VoxelMeshUpdater::OutputBlock &ob = output.blocks[i];
|
const VoxelMeshUpdater::OutputBlock &ob = output.blocks[i];
|
||||||
@ -666,6 +676,8 @@ void VoxelLodTerrain::_process() {
|
|||||||
shift_up(_blocks_pending_main_thread_update, queue_index);
|
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
|
// Find out which blocks need to be shown
|
||||||
{
|
{
|
||||||
struct SubdivideAction {
|
struct SubdivideAction {
|
||||||
@ -733,6 +745,25 @@ void VoxelLodTerrain::_process() {
|
|||||||
|
|
||||||
_lod_octree.update(viewer_pos, subdivide_action, unsubdivide_action);
|
_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() {
|
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("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_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("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::OBJECT, "provider", PROPERTY_HINT_RESOURCE_TYPE, "VoxelProvider"), "set_provider", "get_provider");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "view_distance"), "set_view_distance", "get_view_distance");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "view_distance"), "set_view_distance", "get_view_distance");
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
#include "lod_octree.h"
|
#include "lod_octree.h"
|
||||||
#include "voxel_map.h"
|
#include "voxel_map.h"
|
||||||
#include "voxel_mesh_updater.h"
|
#include "voxel_mesh_updater.h"
|
||||||
|
#include "voxel_provider_thread.h"
|
||||||
#include <core/set.h>
|
#include <core/set.h>
|
||||||
#include <scene/3d/spatial.h>
|
#include <scene/3d/spatial.h>
|
||||||
|
|
||||||
class VoxelMap;
|
class VoxelMap;
|
||||||
class VoxelProviderThread;
|
|
||||||
|
|
||||||
// Paged terrain made of voxel blocks of variable level of detail.
|
// Paged terrain made of voxel blocks of variable level of detail.
|
||||||
// Designed for highest view distances, preferably using smooth voxels.
|
// 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_meshed(Vector3 bpos, unsigned int lod_index) const;
|
||||||
bool is_block_shown(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:
|
protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
@ -113,6 +125,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Lod _lods[MAX_LOD];
|
Lod _lods[MAX_LOD];
|
||||||
|
|
||||||
|
Stats _stats;
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(VoxelLodTerrain::BlockState)
|
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());
|
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;
|
int get_required_padding() const;
|
||||||
|
|
||||||
|
static Dictionary to_dictionary(const Stats &stats);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void _thread_func(void *p_self);
|
static void _thread_func(void *p_self);
|
||||||
void thread_func();
|
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());
|
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 push(const InputData &input);
|
||||||
void pop(OutputData &out_data);
|
void pop(OutputData &out_data);
|
||||||
|
|
||||||
|
static Dictionary to_dictionary(const Stats &stats);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void _thread_func(void *p_self);
|
static void _thread_func(void *p_self);
|
||||||
|
|
||||||
|
@ -218,16 +218,10 @@ void VoxelTerrain::immerge_block(Vector3i bpos) {
|
|||||||
|
|
||||||
Dictionary VoxelTerrain::get_statistics() const {
|
Dictionary VoxelTerrain::get_statistics() const {
|
||||||
|
|
||||||
Dictionary provider;
|
Dictionary provider = VoxelProviderThread::to_dictionary(_stats.provider);
|
||||||
provider["min_time"] = _stats.provider.min_time;
|
|
||||||
provider["max_time"] = _stats.provider.max_time;
|
|
||||||
provider["remaining_blocks"] = _stats.provider.remaining_blocks;
|
|
||||||
provider["dropped_blocks"] = _stats.dropped_provider_blocks;
|
provider["dropped_blocks"] = _stats.dropped_provider_blocks;
|
||||||
|
|
||||||
Dictionary updater;
|
Dictionary updater = VoxelMeshUpdater::to_dictionary(_stats.updater);
|
||||||
updater["min_time"] = _stats.updater.min_time;
|
|
||||||
updater["max_time"] = _stats.updater.max_time;
|
|
||||||
updater["remaining_blocks"] = _stats.updater.remaining_blocks;
|
|
||||||
updater["updated_blocks"] = _stats.updated_blocks;
|
updater["updated_blocks"] = _stats.updated_blocks;
|
||||||
updater["mesh_alloc_time"] = _stats.mesh_alloc_time;
|
updater["mesh_alloc_time"] = _stats.mesh_alloc_time;
|
||||||
updater["dropped_blocks"] = _stats.dropped_updater_blocks;
|
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…
Reference in New Issue
Block a user