Split refcounts

This commit is contained in:
Marc Gilleron 2021-04-15 20:16:27 +01:00
parent f7d0039811
commit 63d9361a87
5 changed files with 33 additions and 70 deletions

View File

@ -11,8 +11,7 @@ public:
Ref<VoxelBuffer> voxels;
const Vector3i position;
const unsigned int lod_index = 0;
// TODO Only data view type can be used here. Split it?
VoxelViewerRefCount viewers;
VoxelRefCount viewers;
static VoxelDataBlock *create(Vector3i bpos, Ref<VoxelBuffer> buffer, unsigned int size, unsigned int p_lod_index) {
const int bs = size;

View File

@ -29,7 +29,8 @@ public:
Vector3i position;
unsigned int lod_index = 0;
bool pending_transition_update = false;
VoxelViewerRefCount viewers;
VoxelRefCount mesh_viewers;
VoxelRefCount collision_viewers;
bool got_first_mesh_update = false;
uint32_t last_collider_update_time = 0;

View File

@ -310,8 +310,7 @@ void VoxelTerrain::try_schedule_mesh_update(VoxelMeshBlock *mesh_block) {
// Already in the list
return;
}
if (mesh_block->viewers.get(VoxelViewerRefCount::TYPE_MESH) == 0 &&
mesh_block->viewers.get(VoxelViewerRefCount::TYPE_COLLISION) == 0) {
if (mesh_block->mesh_viewers.get() == 0 && mesh_block->collision_viewers.get() == 0) {
// No viewers want mesh on this block (why even call this function then?)
return;
}
@ -346,7 +345,7 @@ void VoxelTerrain::view_data_block(Vector3i bpos) {
if (loading_block == nullptr) {
// First viewer to request it
LoadingBlock new_loading_block;
new_loading_block.viewers.add(VoxelViewerRefCount::TYPE_DATA);
new_loading_block.viewers.add();
// Schedule a loading request
_loading_blocks.set(bpos, new_loading_block);
@ -354,12 +353,12 @@ void VoxelTerrain::view_data_block(Vector3i bpos) {
} else {
// More viewers
loading_block->viewers.add(VoxelViewerRefCount::TYPE_DATA);
loading_block->viewers.add();
}
} else {
// The block is loaded
block->viewers.add(VoxelViewerRefCount::TYPE_DATA);
block->viewers.add();
// TODO viewers with varying flags during the game is not supported at the moment.
// They have to be re-created, which may cause world re-load...
@ -389,7 +388,12 @@ void VoxelTerrain::view_mesh_block(Vector3i bpos, bool mesh_flag, bool collision
view_data_block(data_bpos);
});*/
block->viewers.add(false, mesh_flag, collision_flag);
if (mesh_flag) {
block->mesh_viewers.add();
}
if (collision_flag) {
block->collision_viewers.add();
}
// This is needed in case a viewer wants to view meshes in places data blocks are already present.
// Before that, meshes were updated only when a data block was loaded or modified,
@ -428,9 +432,9 @@ void VoxelTerrain::unview_data_block(Vector3i bpos) {
return;
}
loading_block->viewers.remove(VoxelViewerRefCount::TYPE_DATA);
loading_block->viewers.remove();
if (loading_block->viewers.get(VoxelViewerRefCount::TYPE_DATA) == 0) {
if (loading_block->viewers.get() == 0) {
// No longer want to load it
_loading_blocks.erase(bpos);
@ -446,11 +450,8 @@ void VoxelTerrain::unview_data_block(Vector3i bpos) {
} else {
// The block is loaded
VoxelViewerRefCount &viewers = block->viewers;
viewers.remove(VoxelViewerRefCount::TYPE_DATA);
if (viewers.get(VoxelViewerRefCount::TYPE_DATA) == 0) {
block->viewers.remove();
if (block->viewers.get() == 0) {
// The block itself is no longer wanted
unload_data_block(bpos);
}
@ -470,25 +471,23 @@ void VoxelTerrain::unview_mesh_block(Vector3i bpos, bool mesh_flag, bool collisi
unview_data_block(data_bpos);
});*/
VoxelViewerRefCount &viewers = block->viewers;
if (mesh_flag) {
viewers.remove(VoxelViewerRefCount::TYPE_MESH);
if (viewers.get(VoxelViewerRefCount::TYPE_MESH) == 0) {
block->mesh_viewers.remove();
if (block->mesh_viewers.get() == 0) {
// Mesh no longer required
block->drop_mesh();
}
}
if (collision_flag) {
viewers.remove(VoxelViewerRefCount::TYPE_COLLISION);
if (viewers.get(VoxelViewerRefCount::TYPE_COLLISION) == 0) {
block->collision_viewers.remove();
if (block->collision_viewers.get() == 0) {
// Collision no longer required
block->drop_collision();
}
}
if (viewers.get(VoxelViewerRefCount::TYPE_MESH) == 0 && viewers.get(VoxelViewerRefCount::TYPE_COLLISION) == 0) {
if (block->collision_viewers.get() == 0 && block->collision_viewers.get() == 0) {
unload_mesh_block(bpos);
}
}
@ -1555,8 +1554,7 @@ void VoxelTerrain::_process() {
collidable_surfaces.clear();
}
const bool gen_collisions =
_generate_collisions && block->viewers.get(VoxelViewerRefCount::TYPE_COLLISION) > 0;
const bool gen_collisions = _generate_collisions && block->collision_viewers.get() > 0;
block->set_mesh(mesh);
if (gen_collisions) {

View File

@ -176,7 +176,7 @@ private:
// Therefore, could a simple grid be better to use than a hashmap?
struct LoadingBlock {
VoxelViewerRefCount viewers;
VoxelRefCount viewers;
};
HashMap<Vector3i, LoadingBlock, Vector3iHasher> _loading_blocks;

View File

@ -3,58 +3,23 @@
#include "../util/fixed_array.h"
class VoxelViewerRefCount {
class VoxelRefCount {
public:
enum ViewerType {
TYPE_DATA = 0, // This one is always counted, others are optional
TYPE_MESH,
TYPE_COLLISION,
TYPE_COUNT
};
VoxelViewerRefCount() {
_counts.fill(0);
inline void add() {
++_count;
}
inline void add(bool data, bool mesh, bool collision) {
if (data) {
add(TYPE_DATA);
}
if (mesh) {
add(TYPE_MESH);
}
if (collision) {
add(TYPE_COLLISION);
}
inline void remove() {
ERR_FAIL_COND_MSG(_count == 0, "Trying to decrease refcount when it's already zero");
--_count;
}
inline void remove(bool data, bool mesh, bool collision) {
if (data) {
remove(TYPE_DATA);
}
if (mesh) {
remove(TYPE_MESH);
}
if (collision) {
remove(TYPE_COLLISION);
}
}
inline void add(ViewerType t) {
++_counts[t];
}
inline void remove(ViewerType t) {
CRASH_COND_MSG(_counts[t] == 0, "Trying to remove a viewer to a block that had none");
--_counts[t];
}
inline uint32_t get(ViewerType t) const {
return _counts[t];
inline unsigned int get() const {
return _count;
}
private:
FixedArray<uint32_t, TYPE_COUNT> _counts;
unsigned int _count = 0;
};
#endif // VOXEL_VIEWER_REF_COUNT_H