Added exclusive area parameter to block processors so they can remove blocks from their queue

This commit is contained in:
Marc Gilleron 2019-05-12 16:33:25 +01:00
parent 561f95a506
commit efe58f1af6
6 changed files with 111 additions and 21 deletions

View File

@ -527,6 +527,8 @@ void VoxelLodTerrain::_process() {
VoxelProviderThread::InputData input;
input.priority_block_position = viewer_block_pos;
input.use_exclusive_region = true;
input.exclusive_region_extent = get_block_region_extent();
for (unsigned int lod_index = 0; lod_index < get_lod_count(); ++lod_index) {
Lod &lod = _lods[lod_index];
@ -598,6 +600,9 @@ void VoxelLodTerrain::_process() {
// Send mesh updates
{
VoxelMeshUpdater::Input input;
input.priority_position = viewer_block_pos;
input.use_exclusive_region = true;
input.exclusive_region_extent = get_block_region_extent();
for (unsigned int lod_index = 0; lod_index < get_lod_count(); ++lod_index) {
Lod &lod = _lods[lod_index];

View File

@ -73,7 +73,7 @@ void VoxelMeshUpdater::push(const Input &input) {
if (index) {
// The block is already in the update queue, replace it
++replaced_blocks;
_shared_input.blocks.write[*index] = block;
_shared_input.blocks[*index] = block;
} else {
@ -88,6 +88,12 @@ void VoxelMeshUpdater::push(const Input &input) {
}
_shared_input.priority_position = input.priority_position;
if (input.use_exclusive_region) {
_shared_input.use_exclusive_region = true;
_shared_input.exclusive_region_extent = input.exclusive_region_extent;
}
should_run = !_shared_input.is_empty();
}
@ -209,11 +215,13 @@ static void scale_mesh_data(VoxelMesher::Output &data, float factor) {
// so you won't trash performance with pointless allocations
surface[Mesh::ARRAY_VERTEX] = Variant();
{
PoolVector3Array::Write w = positions.write();
int len = positions.size();
for (int j = 0; j < len; ++j) {
w[j] = w[j] * factor;
}
}
// Thank you
surface[Mesh::ARRAY_VERTEX] = positions;
@ -282,9 +290,15 @@ void VoxelMeshUpdater::thread_sync(int queue_index, Stats stats) {
// Get input
MutexLock lock(_input_mutex);
_input.blocks.append_array(_shared_input.blocks);
append_array(_input.blocks, _shared_input.blocks);
_input.priority_position = _shared_input.priority_position;
if (_shared_input.use_exclusive_region) {
_input.use_exclusive_region = true;
_input.exclusive_region_extent = _shared_input.exclusive_region_extent;
}
_shared_input.blocks.clear();
for (unsigned int lod_index = 0; lod_index < MAX_LOD; ++lod_index) {
@ -307,12 +321,39 @@ void VoxelMeshUpdater::thread_sync(int queue_index, Stats stats) {
_output.blocks.clear();
}
// Cancel blocks outside exclusive region
//int dropped_count = 0;
if (_input.use_exclusive_region) {
for (int i = 0; i < _input.blocks.size(); ++i) {
const InputBlock &ib = _input.blocks[i];
Rect3i box = Rect3i::from_center_extents(_input.priority_position >> ib.lod, Vector3i(_input.exclusive_region_extent));
if (!box.contains(ib.position)) {
Vector3i shifted_block_pos = _input.blocks.back().position;
_input.blocks[i] = _input.blocks.back();
_input.blocks.pop_back();
_block_indexes[ib.lod].erase(ib.position);
_block_indexes[ib.lod][shifted_block_pos] = i;
//++dropped_count;
}
}
}
// if (dropped_count > 0) {
// print_line(String("Dropped {0} blocks to mesh from thread").format(varray(dropped_count)));
// }
if (!_input.blocks.empty() && needs_sort) {
// Re-sort priority
SortArray<VoxelMeshUpdater::InputBlock, BlockUpdateComparator> sorter;
sorter.compare.center = _input.priority_position;
sorter.sort(_input.blocks.ptrw(), _input.blocks.size());
sorter.sort(_input.blocks.data(), _input.blocks.size());
}
}

View File

@ -20,8 +20,10 @@ public:
};
struct Input {
Vector<InputBlock> blocks;
Vector3i priority_position;
std::vector<InputBlock> blocks;
Vector3i priority_position; // In LOD0 block coordinates
int exclusive_region_extent = 0;
bool use_exclusive_region = false;
bool is_empty() const {
return blocks.empty();

View File

@ -42,10 +42,15 @@ void VoxelProviderThread::push(const InputData &input) {
// TODO If the same request is sent twice, keep only the latest one
_shared_input.blocks_to_emerge.append_array(input.blocks_to_emerge);
_shared_input.blocks_to_immerge.append_array(input.blocks_to_immerge);
append_array(_shared_input.blocks_to_emerge, input.blocks_to_emerge);
append_array(_shared_input.blocks_to_immerge, input.blocks_to_immerge);
_shared_input.priority_block_position = input.priority_block_position;
if (input.use_exclusive_region) {
_shared_input.use_exclusive_region = true;
_shared_input.exclusive_region_extent = input.exclusive_region_extent;
}
should_run = !_shared_input.is_empty();
}
@ -112,11 +117,13 @@ void VoxelProviderThread::thread_func() {
stats.min_time = time_taken;
stats.max_time = time_taken;
} else {
if (time_taken < stats.min_time)
if (time_taken < stats.min_time) {
stats.min_time = time_taken;
if (time_taken > stats.max_time)
}
if (time_taken > stats.max_time) {
stats.max_time = time_taken;
}
}
EmergeOutput eo;
eo.origin_in_voxels = block_origin_in_voxels;
@ -137,8 +144,9 @@ void VoxelProviderThread::thread_func() {
}
}
if (_thread_exit)
if (_thread_exit) {
break;
}
// Wait for future wake-up
_semaphore->wait();
@ -183,12 +191,18 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) {
// Get input
MutexLock lock(_input_mutex);
_input.blocks_to_emerge.append_array(_shared_input.blocks_to_emerge);
_input.blocks_to_immerge.append_array(_shared_input.blocks_to_immerge);
append_array(_input.blocks_to_emerge, _shared_input.blocks_to_emerge);
append_array(_input.blocks_to_immerge, _shared_input.blocks_to_immerge);
_input.priority_block_position = _shared_input.priority_block_position;
if (_shared_input.use_exclusive_region) {
_input.use_exclusive_region = true;
_input.exclusive_region_extent = _shared_input.exclusive_region_extent;
}
_shared_input.blocks_to_emerge.clear();
_shared_input.blocks_to_immerge.clear();
_shared_input.use_exclusive_region = false;
}
stats.remaining_blocks = _input.blocks_to_emerge.size();
@ -204,12 +218,32 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) {
_output.clear();
}
// Cancel blocks outside exclusive region
//int dropped_count = 0;
if (_input.use_exclusive_region) {
for (int i = 0; i < _input.blocks_to_emerge.size(); ++i) {
const EmergeInput &ei = _input.blocks_to_emerge[i];
Rect3i box = Rect3i::from_center_extents(_input.priority_block_position >> ei.lod, Vector3i(_input.exclusive_region_extent));
if (!box.contains(ei.block_position)) {
_input.blocks_to_emerge[i] = _input.blocks_to_emerge.back();
_input.blocks_to_emerge.pop_back();
//++dropped_count;
}
}
}
// if (dropped_count > 0) {
// print_line(String("Dropped {0} blocks to load from thread").format(varray(dropped_count)));
// }
if (!_input.blocks_to_emerge.empty()) {
// Re-sort priority
SortArray<EmergeInput, BlockPositionComparator> sorter;
sorter.compare.center = _input.priority_block_position;
sorter.sort(_input.blocks_to_emerge.ptrw(), _input.blocks_to_emerge.size());
sorter.sort(_input.blocks_to_emerge.data(), _input.blocks_to_emerge.size());
}
}

View File

@ -1,8 +1,9 @@
#ifndef VOXEL_PROVIDER_THREAD_H
#define VOXEL_PROVIDER_THREAD_H
#include "../math/vector3i.h"
#include "../math/rect3i.h"
#include <core/resource.h>
#include <vector>
class VoxelProvider;
class VoxelBuffer;
@ -23,9 +24,11 @@ public:
};
struct InputData {
Vector<ImmergeInput> blocks_to_immerge;
Vector<EmergeInput> blocks_to_emerge;
Vector3i priority_block_position;
std::vector<ImmergeInput> blocks_to_immerge;
std::vector<EmergeInput> blocks_to_emerge;
Vector3i priority_block_position; // In LOD0 block coordinates
int exclusive_region_extent = 0;
bool use_exclusive_region = false;
inline bool is_empty() {
return blocks_to_emerge.empty() && blocks_to_immerge.empty();

View File

@ -103,4 +103,9 @@ inline bool is_mesh_empty(Ref<Mesh> mesh_ref) {
return false;
}
template <typename T>
inline void append_array(std::vector<T> &dst, const std::vector<T> &src) {
dst.insert(dst.end(), src.begin(), src.end());
}
#endif // HEADER_VOXEL_UTILITY_H