Disabled task cancellation to make VoxelLodTerrain work, will need better option later.

VoxelLodTerrain's block requests were being cancelled constantly.

This commit also contains precision improvement for cancelling
block requests based on distance, which originally was an attempt to
"properly" fix the problem with VoxelLodTerrain, but it didnt fully
worked for that node.
I left it anyways, maybe it will change in the future once a
proper fix is figured out.
This commit is contained in:
Marc Gilleron 2020-10-19 23:21:14 +01:00
parent 25fded048e
commit 30c6d7e436
3 changed files with 42 additions and 21 deletions

View File

@ -110,9 +110,7 @@ void VoxelServer::wait_and_clear_all_tasks(bool warn) {
});
}
int VoxelServer::get_priority(const PriorityDependency &dep, uint8_t lod,
float *out_closest_distance_sq) {
int VoxelServer::get_priority(const PriorityDependency &dep, uint8_t lod, float *out_closest_distance_sq) {
const std::vector<Vector3> &viewer_positions = dep.shared->viewers;
const Vector3 block_position = dep.world_position;
@ -186,6 +184,11 @@ void VoxelServer::set_volume_voxel_library(uint32_t volume_id, Ref<VoxelLibrary>
volume.meshing_dependency->library = volume.voxel_library;
}
void VoxelServer::set_volume_cancellable_requests(uint32_t volume_id, bool cancellable) {
Volume &volume = _world.volumes.get(volume_id);
volume.cancellable_requests = cancellable;
}
void VoxelServer::invalidate_volume_mesh_requests(uint32_t volume_id) {
Volume &volume = _world.volumes.get(volume_id);
volume.meshing_dependency->valid = false;
@ -197,21 +200,28 @@ static inline Vector3i get_block_center(Vector3i pos, int bs, int lod) {
return (pos << lod) * bs + Vector3i(bs / 2);
}
void VoxelServer::init_priority_dependency(
VoxelServer::PriorityDependency &dep, Vector3i block_position, uint8_t lod, const Volume &volume) {
const Vector3i voxel_pos = get_block_center(block_position, volume.block_size, lod);
const float block_radius = (volume.block_size << lod) / 2;
dep.shared = _world.shared_priority_dependency;
dep.world_position = volume.transform.xform(voxel_pos.to_vec3());
dep.radius = volume.transform.basis.xform(Vector3(block_radius, block_radius, block_radius)).length();
}
void VoxelServer::request_block_mesh(uint32_t volume_id, BlockMeshInput &input) {
const Volume &volume = _world.volumes.get(volume_id);
ERR_FAIL_COND(volume.stream.is_null());
CRASH_COND(volume.stream_dependency == nullptr);
ERR_FAIL_COND(volume.meshing_dependency == nullptr);
// TODO Handle spamming!
// It was previously done by remembering the request with a hashmap by position.
// But later we may want to solve it by not pre-emptively copying voxels, only do it on meshing using RWLock
BlockMeshRequest *r = memnew(BlockMeshRequest);
r->volume_id = volume_id;
r->blocks = input.blocks;
r->position = input.position;
r->lod = input.lod;
r->cancellable = volume.cancellable_requests;
r->smooth_enabled = volume.stream->get_used_channels_mask() & (1 << VoxelBuffer::CHANNEL_SDF);
r->blocky_enabled = volume.voxel_library.is_valid() &&
@ -219,9 +229,7 @@ void VoxelServer::request_block_mesh(uint32_t volume_id, BlockMeshInput &input)
r->meshing_dependency = volume.meshing_dependency;
const Vector3i voxel_pos = get_block_center(input.position, volume.block_size, input.lod);
r->priority_dependency.world_position = volume.transform.xform(voxel_pos.to_vec3());
r->priority_dependency.shared = _world.shared_priority_dependency;
init_priority_dependency(r->priority_dependency, input.position, input.lod, volume);
// We'll allocate this quite often. If it becomes a problem, it should be easy to pool.
_meshing_thread_pool.enqueue(r);
@ -238,12 +246,11 @@ void VoxelServer::request_block_load(uint32_t volume_id, Vector3i block_pos, int
r.lod = lod;
r.type = BlockDataRequest::TYPE_LOAD;
r.block_size = volume.block_size;
r.cancellable = volume.cancellable_requests;
r.stream_dependency = volume.stream_dependency;
const Vector3i voxel_pos = get_block_center(block_pos, volume.block_size, lod);
r.priority_dependency.world_position = volume.transform.xform(voxel_pos.to_vec3());
r.priority_dependency.shared = _world.shared_priority_dependency;
init_priority_dependency(r.priority_dependency, block_pos, lod, volume);
BlockDataRequest *rp = memnew(BlockDataRequest(r));
_streaming_thread_pool.enqueue(rp);
@ -459,7 +466,7 @@ void VoxelServer::process() {
// Cancel distance is increased because of two reasons:
// - Some volumes use a cubic area which has higher distances on their corners
// - Hysteresis is needed to reduce ping-pong
_world.shared_priority_dependency->cancel_distance_squared = squared(max_distance * 2);
_world.shared_priority_dependency->highest_view_distance = max_distance * 2;
}
}
@ -555,9 +562,12 @@ int VoxelServer::BlockDataRequest::get_priority() {
if (type == TYPE_SAVE) {
return 0;
}
float closest_distance_sq;
int p = VoxelServer::get_priority(priority_dependency, lod, &closest_distance_sq);
too_far = closest_distance_sq > priority_dependency.shared->cancel_distance_squared;
float closest_viewer_distance_sq;
const int p = VoxelServer::get_priority(priority_dependency, lod, &closest_viewer_distance_sq);
if (cancellable) {
const float closest_viewer_distance = Math::sqrt(closest_viewer_distance_sq);
too_far = closest_viewer_distance > priority_dependency.radius + priority_dependency.shared->highest_view_distance;
}
return p;
}
@ -650,9 +660,12 @@ void VoxelServer::BlockMeshRequest::run(VoxelTaskContext ctx) {
}
int VoxelServer::BlockMeshRequest::get_priority() {
float closest_distance_sq;
int p = VoxelServer::get_priority(priority_dependency, lod, &closest_distance_sq);
too_far = closest_distance_sq > priority_dependency.shared->cancel_distance_squared;
float closest_viewer_distance_sq;
const int p = VoxelServer::get_priority(priority_dependency, lod, &closest_viewer_distance_sq);
if (cancellable) {
const float closest_viewer_distance = Math::sqrt(closest_viewer_distance_sq);
too_far = closest_viewer_distance > priority_dependency.radius + priority_dependency.shared->highest_view_distance;
}
return p;
}

View File

@ -78,6 +78,7 @@ public:
void set_volume_block_size(uint32_t volume_id, uint32_t block_size);
void set_volume_stream(uint32_t volume_id, Ref<VoxelStream> stream);
void set_volume_voxel_library(uint32_t volume_id, Ref<VoxelLibrary> library);
void set_volume_cancellable_requests(uint32_t volume_id, bool cancellable);
void invalidate_volume_mesh_requests(uint32_t volume_id);
void request_block_mesh(uint32_t volume_id, BlockMeshInput &input);
void request_block_load(uint32_t volume_id, Vector3i block_pos, int lod);
@ -145,6 +146,8 @@ private:
uint32_t block_size = 16;
std::shared_ptr<StreamingDependency> stream_dependency;
std::shared_ptr<MeshingDependency> meshing_dependency;
// TODO Workaround for VoxelLodTerrain, which doesnt support this well atm
bool cancellable_requests = true;
};
struct PriorityDependencyShared {
@ -153,7 +156,7 @@ private:
// It's only used to adjust task priority so using a lock isn't worth it. In worst case scenario,
// a task will run much sooner or later than expected, but it will run in any case.
std::vector<Vector3> viewers;
unsigned int cancel_distance_squared = 999999;
float highest_view_distance = 999999;
};
struct World {
@ -167,8 +170,10 @@ private:
struct PriorityDependency {
std::shared_ptr<PriorityDependencyShared> shared;
Vector3 world_position; // TODO Won't update while in queue. Can it be bad?
float radius;
};
void init_priority_dependency(PriorityDependency &dep, Vector3i block_position, uint8_t lod, const Volume &volume);
static int get_priority(const PriorityDependency &dep, uint8_t lod, float *out_closest_distance_sq);
class BlockDataRequest : public IVoxelTask {
@ -190,6 +195,7 @@ private:
uint8_t type;
bool has_run = false;
bool too_far = false;
bool cancellable = true;
PriorityDependency priority_dependency;
std::shared_ptr<StreamingDependency> stream_dependency;
// TODO Find a way to separate save, it doesnt need sorting
@ -209,6 +215,7 @@ private:
bool blocky_enabled;
bool has_run = false;
bool too_far = false;
bool cancellable = true;
PriorityDependency priority_dependency;
std::shared_ptr<MeshingDependency> meshing_dependency;
VoxelMesher::Output blocky_surfaces_output;

View File

@ -57,6 +57,7 @@ VoxelLodTerrain::VoxelLodTerrain() {
PRINT_VERBOSE("Construct VoxelLodTerrain");
_volume_id = VoxelServer::get_singleton()->add_volume(&_reception_buffers);
VoxelServer::get_singleton()->set_volume_cancellable_requests(_volume_id, false);
_lods[0].map.instance();