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; VoxelProviderThread::InputData input;
input.priority_block_position = viewer_block_pos; 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) { for (unsigned int lod_index = 0; lod_index < get_lod_count(); ++lod_index) {
Lod &lod = _lods[lod_index]; Lod &lod = _lods[lod_index];
@ -598,6 +600,9 @@ void VoxelLodTerrain::_process() {
// Send mesh updates // Send mesh updates
{ {
VoxelMeshUpdater::Input input; 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) { for (unsigned int lod_index = 0; lod_index < get_lod_count(); ++lod_index) {
Lod &lod = _lods[lod_index]; Lod &lod = _lods[lod_index];

View File

@ -73,7 +73,7 @@ void VoxelMeshUpdater::push(const Input &input) {
if (index) { if (index) {
// The block is already in the update queue, replace it // The block is already in the update queue, replace it
++replaced_blocks; ++replaced_blocks;
_shared_input.blocks.write[*index] = block; _shared_input.blocks[*index] = block;
} else { } else {
@ -88,6 +88,12 @@ void VoxelMeshUpdater::push(const Input &input) {
} }
_shared_input.priority_position = input.priority_position; _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(); 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 // so you won't trash performance with pointless allocations
surface[Mesh::ARRAY_VERTEX] = Variant(); surface[Mesh::ARRAY_VERTEX] = Variant();
{
PoolVector3Array::Write w = positions.write(); PoolVector3Array::Write w = positions.write();
int len = positions.size(); int len = positions.size();
for (int j = 0; j < len; ++j) { for (int j = 0; j < len; ++j) {
w[j] = w[j] * factor; w[j] = w[j] * factor;
} }
}
// Thank you // Thank you
surface[Mesh::ARRAY_VERTEX] = positions; surface[Mesh::ARRAY_VERTEX] = positions;
@ -282,9 +290,15 @@ void VoxelMeshUpdater::thread_sync(int queue_index, Stats stats) {
// Get input // Get input
MutexLock lock(_input_mutex); 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; _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(); _shared_input.blocks.clear();
for (unsigned int lod_index = 0; lod_index < MAX_LOD; ++lod_index) { 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(); _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) { if (!_input.blocks.empty() && needs_sort) {
// Re-sort priority // Re-sort priority
SortArray<VoxelMeshUpdater::InputBlock, BlockUpdateComparator> sorter; SortArray<VoxelMeshUpdater::InputBlock, BlockUpdateComparator> sorter;
sorter.compare.center = _input.priority_position; 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 { struct Input {
Vector<InputBlock> blocks; std::vector<InputBlock> blocks;
Vector3i priority_position; Vector3i priority_position; // In LOD0 block coordinates
int exclusive_region_extent = 0;
bool use_exclusive_region = false;
bool is_empty() const { bool is_empty() const {
return blocks.empty(); 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 // TODO If the same request is sent twice, keep only the latest one
_shared_input.blocks_to_emerge.append_array(input.blocks_to_emerge); append_array(_shared_input.blocks_to_emerge, input.blocks_to_emerge);
_shared_input.blocks_to_immerge.append_array(input.blocks_to_immerge); append_array(_shared_input.blocks_to_immerge, input.blocks_to_immerge);
_shared_input.priority_block_position = input.priority_block_position; _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(); should_run = !_shared_input.is_empty();
} }
@ -112,11 +117,13 @@ void VoxelProviderThread::thread_func() {
stats.min_time = time_taken; stats.min_time = time_taken;
stats.max_time = time_taken; stats.max_time = time_taken;
} else { } else {
if (time_taken < stats.min_time) if (time_taken < stats.min_time) {
stats.min_time = time_taken; stats.min_time = time_taken;
if (time_taken > stats.max_time) }
if (time_taken > stats.max_time) {
stats.max_time = time_taken; stats.max_time = time_taken;
} }
}
EmergeOutput eo; EmergeOutput eo;
eo.origin_in_voxels = block_origin_in_voxels; eo.origin_in_voxels = block_origin_in_voxels;
@ -137,8 +144,9 @@ void VoxelProviderThread::thread_func() {
} }
} }
if (_thread_exit) if (_thread_exit) {
break; break;
}
// Wait for future wake-up // Wait for future wake-up
_semaphore->wait(); _semaphore->wait();
@ -183,12 +191,18 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) {
// Get input // Get input
MutexLock lock(_input_mutex); MutexLock lock(_input_mutex);
_input.blocks_to_emerge.append_array(_shared_input.blocks_to_emerge); append_array(_input.blocks_to_emerge, _shared_input.blocks_to_emerge);
_input.blocks_to_immerge.append_array(_shared_input.blocks_to_immerge); append_array(_input.blocks_to_immerge, _shared_input.blocks_to_immerge);
_input.priority_block_position = _shared_input.priority_block_position; _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_emerge.clear();
_shared_input.blocks_to_immerge.clear(); _shared_input.blocks_to_immerge.clear();
_shared_input.use_exclusive_region = false;
} }
stats.remaining_blocks = _input.blocks_to_emerge.size(); stats.remaining_blocks = _input.blocks_to_emerge.size();
@ -204,12 +218,32 @@ void VoxelProviderThread::thread_sync(int emerge_index, Stats stats) {
_output.clear(); _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()) { if (!_input.blocks_to_emerge.empty()) {
// Re-sort priority // Re-sort priority
SortArray<EmergeInput, BlockPositionComparator> sorter; SortArray<EmergeInput, BlockPositionComparator> sorter;
sorter.compare.center = _input.priority_block_position; 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 #ifndef VOXEL_PROVIDER_THREAD_H
#define VOXEL_PROVIDER_THREAD_H #define VOXEL_PROVIDER_THREAD_H
#include "../math/vector3i.h" #include "../math/rect3i.h"
#include <core/resource.h> #include <core/resource.h>
#include <vector>
class VoxelProvider; class VoxelProvider;
class VoxelBuffer; class VoxelBuffer;
@ -23,9 +24,11 @@ public:
}; };
struct InputData { struct InputData {
Vector<ImmergeInput> blocks_to_immerge; std::vector<ImmergeInput> blocks_to_immerge;
Vector<EmergeInput> blocks_to_emerge; std::vector<EmergeInput> blocks_to_emerge;
Vector3i priority_block_position; Vector3i priority_block_position; // In LOD0 block coordinates
int exclusive_region_extent = 0;
bool use_exclusive_region = false;
inline bool is_empty() { inline bool is_empty() {
return blocks_to_emerge.empty() && blocks_to_immerge.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; 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 #endif // HEADER_VOXEL_UTILITY_H