Update VoxelLodTerrain stats
This commit is contained in:
parent
f25a019c62
commit
669e5230ed
@ -1086,6 +1086,9 @@ inline bool check_block_sizes(int data_block_size, int mesh_block_size) {
|
||||
void VoxelLodTerrain::_process(float delta) {
|
||||
VOXEL_PROFILE_SCOPE();
|
||||
|
||||
_stats.dropped_block_loads = 0;
|
||||
_stats.dropped_block_meshs = 0;
|
||||
|
||||
if (get_lod_count() == 0) {
|
||||
// If there isn't a LOD 0, there is nothing to load
|
||||
return;
|
||||
@ -1232,6 +1235,12 @@ void VoxelLodTerrain::apply_main_thread_update_tasks() {
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
_stats.blocked_lods = state.stats.blocked_lods;
|
||||
_stats.time_detect_required_blocks = state.stats.time_detect_required_blocks;
|
||||
_stats.time_io_requests = state.stats.time_io_requests;
|
||||
_stats.time_mesh_requests = state.stats.time_mesh_requests;
|
||||
_stats.time_update_task = state.stats.time_total;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -1650,16 +1659,18 @@ Dictionary VoxelLodTerrain::_b_get_statistics() const {
|
||||
deferred_collision_updates += _deferred_collision_updates_per_lod[lod_index].size();
|
||||
}
|
||||
|
||||
// Breakdown of time spent in _process
|
||||
d["time_detect_required_blocks"] = _stats.time_detect_required_blocks;
|
||||
d["time_request_blocks_to_load"] = _stats.time_request_blocks_to_load;
|
||||
d["time_process_load_responses"] = _stats.time_process_load_responses;
|
||||
d["time_request_blocks_to_update"] = _stats.time_request_blocks_to_update;
|
||||
// Breakdown of information and time spent in _process and the update task.
|
||||
|
||||
// Update task
|
||||
d["time_detect_required_blocks"] = _stats.time_detect_required_blocks;
|
||||
d["time_io_requests"] = _stats.time_io_requests;
|
||||
d["time_mesh_requests"] = _stats.time_mesh_requests;
|
||||
d["time_update_task"] = _stats.time_update_task;
|
||||
d["blocked_lods"] = _stats.blocked_lods;
|
||||
|
||||
// Process
|
||||
d["dropped_block_loads"] = _stats.dropped_block_loads;
|
||||
d["dropped_block_meshs"] = _stats.dropped_block_meshs;
|
||||
d["updated_blocks"] = _stats.updated_blocks;
|
||||
d["blocked_lods"] = _stats.blocked_lods;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
@ -178,14 +178,21 @@ public:
|
||||
Ref<VoxelTool> get_voxel_tool();
|
||||
|
||||
struct Stats {
|
||||
int blocked_lods = 0;
|
||||
int updated_blocks = 0;
|
||||
int dropped_block_loads = 0;
|
||||
int dropped_block_meshs = 0;
|
||||
// Amount of octree nodes waiting for data. It should reach zero when everything is loaded.
|
||||
uint32_t blocked_lods = 0;
|
||||
// How many data blocks were rejected this frame (due to loading too late for example).
|
||||
uint32_t dropped_block_loads = 0;
|
||||
// How many mesh blocks were rejected this frame (due to loading too late for example).
|
||||
uint32_t dropped_block_meshs = 0;
|
||||
// Time spent in the last update unloading unused blocks and detecting required ones, in microseconds
|
||||
uint32_t time_detect_required_blocks = 0;
|
||||
uint32_t time_request_blocks_to_load = 0;
|
||||
uint32_t time_process_load_responses = 0;
|
||||
uint32_t time_request_blocks_to_update = 0;
|
||||
// Time spent in the last update requesting data blocks, in microseconds
|
||||
uint32_t time_io_requests = 0;
|
||||
// Time spent in the last update requesting meshes, in microseconds
|
||||
uint32_t time_mesh_requests = 0;
|
||||
// Total time spent in the last update task, in microseconds.
|
||||
// This only includes the threadable part, not the whole `process` function.
|
||||
uint32_t time_update_task = 0;
|
||||
};
|
||||
|
||||
const Stats &get_stats() const;
|
||||
|
@ -126,6 +126,14 @@ struct VoxelLodTerrainUpdateData {
|
||||
Box3i box;
|
||||
};
|
||||
|
||||
struct Stats {
|
||||
uint32_t blocked_lods;
|
||||
uint32_t time_detect_required_blocks;
|
||||
uint32_t time_io_requests;
|
||||
uint32_t time_mesh_requests;
|
||||
uint32_t time_total;
|
||||
};
|
||||
|
||||
// Data modified by the update task
|
||||
struct State {
|
||||
// This terrain type is a sparse grid of octrees.
|
||||
@ -146,6 +154,8 @@ struct VoxelLodTerrainUpdateData {
|
||||
std::vector<AsyncEdit> pending_async_edits;
|
||||
BinaryMutex pending_async_edits_mutex;
|
||||
std::vector<RunningAsyncEdit> running_async_edits;
|
||||
|
||||
Stats stats;
|
||||
};
|
||||
|
||||
// Set to true when the update task is finished
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "../server/voxel_server.h"
|
||||
#include "../util/godot/funcs.h"
|
||||
#include "../util/profiling.h"
|
||||
#include "../util/profiling_clock.h"
|
||||
|
||||
namespace zylann::voxel {
|
||||
|
||||
@ -968,7 +969,7 @@ static void process_octrees_fitting(VoxelLodTerrainUpdateData::State &state,
|
||||
|
||||
// Ideally, this stat should stabilize to zero.
|
||||
// If not, something in block management prevents LODs from properly show up and should be fixed.
|
||||
//_stats.blocked_lods += octree_actions.blocked_count;
|
||||
state.stats.blocked_lods += octree_actions.blocked_count;
|
||||
}
|
||||
|
||||
{
|
||||
@ -1327,6 +1328,14 @@ static void process_async_edits(VoxelLodTerrainUpdateData::State &state,
|
||||
void VoxelLodTerrainUpdateTask::run(ThreadedTaskContext ctx) {
|
||||
VOXEL_PROFILE_SCOPE();
|
||||
|
||||
struct SetCompleteOnScopeExit {
|
||||
std::atomic_bool &_complete;
|
||||
SetCompleteOnScopeExit(std::atomic_bool &b) : _complete(b) {}
|
||||
~SetCompleteOnScopeExit() {
|
||||
_complete = true;
|
||||
}
|
||||
};
|
||||
|
||||
CRASH_COND(_update_data == nullptr);
|
||||
CRASH_COND(_data == nullptr);
|
||||
CRASH_COND(_streaming_dependency == nullptr);
|
||||
@ -1338,6 +1347,11 @@ void VoxelLodTerrainUpdateTask::run(ThreadedTaskContext ctx) {
|
||||
VoxelDataLodMap &data = *_data;
|
||||
Ref<VoxelGenerator> generator = _streaming_dependency->generator;
|
||||
Ref<VoxelStream> stream = _streaming_dependency->stream;
|
||||
ProfilingClock profiling_clock;
|
||||
ProfilingClock profiling_clock_total;
|
||||
|
||||
const bool stream_enabled = (stream.is_valid() || generator.is_valid()) &&
|
||||
(Engine::get_singleton()->is_editor_hint() == false || settings.run_stream_in_editor);
|
||||
|
||||
CRASH_COND(data.lod_count != update_data.settings.lod_count);
|
||||
|
||||
@ -1349,6 +1363,8 @@ void VoxelLodTerrainUpdateTask::run(ThreadedTaskContext ctx) {
|
||||
CRASH_COND(lod.mesh_blocks_to_deactivate.size() != 0);
|
||||
}
|
||||
|
||||
SetCompleteOnScopeExit scoped_complete(update_data.task_is_complete);
|
||||
|
||||
CRASH_COND_MSG(update_data.task_is_complete, "Expected only one update task to run on a given volume");
|
||||
MutexLock mutex_lock(update_data.completion_mutex);
|
||||
|
||||
@ -1358,47 +1374,56 @@ void VoxelLodTerrainUpdateTask::run(ThreadedTaskContext ctx) {
|
||||
flush_pending_lod_edits(state, data, generator, settings.full_load_mode, 1 << settings.mesh_block_size_po2);
|
||||
|
||||
static thread_local std::vector<VoxelLodTerrainUpdateData::BlockToSave> data_blocks_to_save;
|
||||
|
||||
// Unload data blocks falling out of block region extent
|
||||
if (update_data.settings.full_load_mode == false) {
|
||||
process_unload_data_blocks_sliding_box(
|
||||
state, data, _viewer_pos, data_blocks_to_save, stream.is_valid(), settings);
|
||||
}
|
||||
|
||||
// Unload mesh blocks falling out of block region extent
|
||||
process_unload_mesh_blocks_sliding_box(state, _viewer_pos, settings);
|
||||
|
||||
// Create and remove octrees in a grid around the viewer.
|
||||
// Mesh blocks drive the loading of voxel data and visuals.
|
||||
process_octrees_sliding_box(state, _viewer_pos, settings);
|
||||
|
||||
const bool stream_enabled = (stream.is_valid() || generator.is_valid()) &&
|
||||
(Engine::get_singleton()->is_editor_hint() == false || settings.run_stream_in_editor);
|
||||
|
||||
static thread_local std::vector<VoxelLodTerrainUpdateData::BlockLocation> data_blocks_to_load;
|
||||
data_blocks_to_load.clear();
|
||||
|
||||
// Find which blocks we need to load and see, within each octree
|
||||
if (stream_enabled) {
|
||||
process_octrees_fitting(state, settings, data, _viewer_pos, data_blocks_to_load);
|
||||
profiling_clock.restart();
|
||||
{
|
||||
// Unload data blocks falling out of block region extent
|
||||
if (update_data.settings.full_load_mode == false) {
|
||||
process_unload_data_blocks_sliding_box(
|
||||
state, data, _viewer_pos, data_blocks_to_save, stream.is_valid(), settings);
|
||||
}
|
||||
|
||||
// Unload mesh blocks falling out of block region extent
|
||||
process_unload_mesh_blocks_sliding_box(state, _viewer_pos, settings);
|
||||
|
||||
// Create and remove octrees in a grid around the viewer.
|
||||
// Mesh blocks drive the loading of voxel data and visuals.
|
||||
process_octrees_sliding_box(state, _viewer_pos, settings);
|
||||
|
||||
state.stats.blocked_lods = 0;
|
||||
|
||||
// Find which blocks we need to load and see, within each octree
|
||||
if (stream_enabled) {
|
||||
process_octrees_fitting(state, settings, data, _viewer_pos, data_blocks_to_load);
|
||||
}
|
||||
}
|
||||
state.stats.time_detect_required_blocks = profiling_clock.restart();
|
||||
|
||||
process_async_edits(
|
||||
state, settings, data, _volume_id, _streaming_dependency, _shared_viewers_data, _volume_transform);
|
||||
|
||||
// It's possible the user didn't set a stream yet, or it is turned off
|
||||
if (stream_enabled) {
|
||||
const unsigned int data_block_size = data.lods[0].map.get_block_size();
|
||||
send_block_data_requests(_volume_id, to_span_const(data_blocks_to_load), _streaming_dependency,
|
||||
_shared_viewers_data, data_block_size, _request_instances, _volume_transform, settings.lod_distance);
|
||||
send_block_save_requests(_volume_id, to_span(data_blocks_to_save), _streaming_dependency, data_block_size);
|
||||
profiling_clock.restart();
|
||||
{
|
||||
// It's possible the user didn't set a stream yet, or it is turned off
|
||||
if (stream_enabled) {
|
||||
const unsigned int data_block_size = data.lods[0].map.get_block_size();
|
||||
send_block_data_requests(_volume_id, to_span_const(data_blocks_to_load), _streaming_dependency,
|
||||
_shared_viewers_data, data_block_size, _request_instances, _volume_transform,
|
||||
settings.lod_distance);
|
||||
send_block_save_requests(_volume_id, to_span(data_blocks_to_save), _streaming_dependency, data_block_size);
|
||||
}
|
||||
data_blocks_to_load.clear();
|
||||
data_blocks_to_save.clear();
|
||||
}
|
||||
data_blocks_to_load.clear();
|
||||
data_blocks_to_save.clear();
|
||||
state.stats.time_io_requests = profiling_clock.restart();
|
||||
|
||||
// TODO Don't request meshes if there is no mesher
|
||||
send_mesh_requests(_volume_id, state, settings, data, _meshing_dependency, _shared_viewers_data, _volume_transform);
|
||||
state.stats.time_mesh_requests = profiling_clock.restart();
|
||||
|
||||
update_data.task_is_complete = true;
|
||||
state.stats.time_total = profiling_clock.restart();
|
||||
}
|
||||
|
||||
} // namespace zylann::voxel
|
||||
|
Loading…
x
Reference in New Issue
Block a user