Chunk now supports threaded builds. Also small fixes.

This commit is contained in:
Relintai 2019-11-19 20:39:45 +01:00
parent a377c994e9
commit edec04cfdc
4 changed files with 93 additions and 13 deletions

View File

@ -9,6 +9,13 @@ _FORCE_INLINE_ void VoxelChunk::set_is_generating(bool value) {
_is_generating = value;
}
_FORCE_INLINE_ bool VoxelChunk::get_is_build_threaded() const {
return _is_build_threaded;
}
_FORCE_INLINE_ void VoxelChunk::set_is_build_threaded(bool value) {
_is_build_threaded = value;
}
_FORCE_INLINE_ bool VoxelChunk::get_dirty() const {
return _dirty;
}
@ -470,8 +477,13 @@ void VoxelChunk::build() {
}
}
void VoxelChunk::build_phase(int phase) {
call("_build_phase", phase);
void VoxelChunk::_build_phase_threaded(void *_userdata) {
VoxelChunk *vc = (VoxelChunk *)_userdata;
vc->build_phase();
}
void VoxelChunk::build_phase() {
call("_build_phase", _current_build_phase);
}
void VoxelChunk::_build_phase(int phase) {
@ -574,6 +586,18 @@ void VoxelChunk::_build_phase(int phase) {
}
void VoxelChunk::next_phase() {
if (_abort_build) {
_current_build_phase = BUILD_PHASE_DONE;
_is_generating = false;
return;
}
if (_build_thread) {
Thread::wait_to_finish(_build_thread);
memdelete(_build_thread);
_build_thread = NULL;
}
++_current_build_phase;
if (_current_build_phase >= BUILD_PHASE_MAX) {
@ -586,7 +610,13 @@ void VoxelChunk::next_phase() {
return;
}
build_phase(_current_build_phase);
if (_is_build_threaded) {
ERR_FAIL_COND(_build_thread != NULL);
_build_thread = Thread::create(_build_phase_threaded, this);
} else {
build_phase();
}
}
void VoxelChunk::clear() {
@ -1062,6 +1092,8 @@ void VoxelChunk::free_chunk() {
VoxelChunk::VoxelChunk() {
_is_generating = false;
_is_build_threaded = false;
_abort_build = false;
_dirty = false;
_state = VOXEL_CHUNK_STATE_OK;
@ -1078,6 +1110,8 @@ VoxelChunk::VoxelChunk() {
_margin_start = 0;
_margin_end = 0;
_build_thread = NULL;
}
VoxelChunk::~VoxelChunk() {
@ -1110,6 +1144,20 @@ VoxelChunk::~VoxelChunk() {
}
}
void VoxelChunk::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_EXIT_TREE: {
if (_build_thread) {
_abort_build = true;
Thread::wait_to_finish(_build_thread);
memdelete(_build_thread);
_build_thread = NULL;
}
}
}
}
void VoxelChunk::_bind_methods() {
ADD_SIGNAL(MethodInfo("mesh_generation_finished", PropertyInfo(Variant::OBJECT, "chunk", PROPERTY_HINT_RESOURCE_TYPE, "VoxelChunk")));
@ -1124,6 +1172,10 @@ void VoxelChunk::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_is_generating", "value"), &VoxelChunk::set_is_generating);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_generating"), "set_is_generating", "get_is_generating");
ClassDB::bind_method(D_METHOD("get_is_build_threaded"), &VoxelChunk::get_is_build_threaded);
ClassDB::bind_method(D_METHOD("set_is_build_threaded", "value"), &VoxelChunk::set_is_build_threaded);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_build_threaded"), "set_is_build_threaded", "get_is_build_threaded");
ClassDB::bind_method(D_METHOD("get_dirty"), &VoxelChunk::get_dirty);
ClassDB::bind_method(D_METHOD("set_dirty", "value"), &VoxelChunk::set_dirty);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dirty"), "set_dirty", "get_dirty");
@ -1256,7 +1308,7 @@ void VoxelChunk::_bind_methods() {
BIND_VMETHOD(MethodInfo("_build_phase", PropertyInfo(Variant::INT, "phase")));
ClassDB::bind_method(D_METHOD("build"), &VoxelChunk::build);
ClassDB::bind_method(D_METHOD("build_phase", "phase"), &VoxelChunk::build_phase);
ClassDB::bind_method(D_METHOD("build_phase"), &VoxelChunk::build_phase);
ClassDB::bind_method(D_METHOD("_build_phase", "phase"), &VoxelChunk::_build_phase);
ClassDB::bind_method(D_METHOD("next_phase"), &VoxelChunk::next_phase);
ClassDB::bind_method(D_METHOD("clear"), &VoxelChunk::clear);

View File

@ -5,6 +5,9 @@
#include "core/engine.h"
#include "core/ustring.h"
#include "core/os/thread.h"
#include "core/os/thread_safe.h"
#include "scene/3d/mesh_instance.h"
#include "scene/resources/packed_scene.h"
#include "core/array.h"
@ -36,6 +39,8 @@ class VoxelWorld;
class VoxelChunk : public Spatial {
GDCLASS(VoxelChunk, Spatial);
_THREAD_SAFE_CLASS_
public:
enum {
VOXEL_CHUNK_STATE_OK = 0,
@ -79,6 +84,9 @@ public:
bool get_is_generating() const;
void set_is_generating(bool value);
bool get_is_build_threaded() const;
void set_is_build_threaded(bool value);
bool get_dirty() const;
void set_dirty(bool value);
@ -183,7 +191,8 @@ public:
void finalize_mesh();
void build();
void build_phase(int phase);
static void _build_phase_threaded(void *_userdata);
void build_phase();
void _build_phase(int phase);
void next_phase();
@ -255,9 +264,12 @@ public:
~VoxelChunk();
protected:
void _notification(int p_what);
static void _bind_methods();
bool _is_generating;
bool _is_build_threaded;
bool _abort_build;
bool _dirty;
int _state;
@ -326,6 +338,8 @@ protected:
bool _create_collider;
bool _bake_lights;
Thread *_build_thread;
};
VARIANT_ENUM_CAST(VoxelChunk::DefaultChannels);

View File

@ -214,12 +214,23 @@ void VoxelWorld::clear() {
}
VoxelChunk *VoxelWorld::create_chunk(int x, int y, int z) {
Node *n = call("_create_chunk", x, y, z);
Node *np = NULL;
Node *n = call("_create_chunk", x, y, z, np);
return(Object::cast_to<VoxelChunk>(n));
}
VoxelChunk *VoxelWorld::_create_chunk(int x, int y, int z) {
VoxelChunk *chunk = memnew(VoxelChunk);
VoxelChunk *VoxelWorld::_create_chunk(int x, int y, int z, Node *p_chunk) {
VoxelChunk *chunk;
if (p_chunk != NULL) {
chunk = Object::cast_to<VoxelChunk>(p_chunk);
} else {
chunk = memnew(VoxelChunk);
}
ERR_FAIL_COND_V(!ObjectDB::instance_validate(chunk), NULL);
chunk->set_name("Chunk[" + String::num(x) + "," + String::num(y) + "," + String::num(z) + "]");
add_child(chunk);
@ -227,6 +238,7 @@ VoxelChunk *VoxelWorld::_create_chunk(int x, int y, int z) {
chunk->set_owner(get_tree()->get_edited_scene_root());
chunk->set_voxel_world(this);
chunk->set_is_build_threaded(_use_threads);
chunk->set_position(x, y, z);
chunk->set_library(_library);
chunk->set_voxel_scale(_voxel_scale);
@ -235,7 +247,7 @@ VoxelChunk *VoxelWorld::_create_chunk(int x, int y, int z) {
add_chunk(chunk, x, y, z);
_generation_queue.push_back(chunk);
add_to_generation_queue(chunk);
return chunk;
}
@ -292,7 +304,7 @@ VoxelWorld ::~VoxelWorld() {
_player = NULL;
_generation_queue.clear();
_generating.clear();;
_generating.clear();
}
void VoxelWorld::_notification(int p_what) {
@ -340,6 +352,8 @@ void VoxelWorld::_notification(int p_what) {
generate_chunk(chunk);
}
}
case NOTIFICATION_EXIT_TREE: {
}
}
}
@ -420,12 +434,12 @@ void VoxelWorld::_bind_methods() {
ADD_SIGNAL(MethodInfo("generation_finished"));
BIND_VMETHOD(MethodInfo("_generation_finished"));
BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::OBJECT, "ret", PROPERTY_HINT_RESOURCE_TYPE, "VoxelChunk"), "_create_chunk", PropertyInfo(Variant::INT, "x"), PropertyInfo(Variant::INT, "y"), PropertyInfo(Variant::INT, "z")));
BIND_VMETHOD(MethodInfo(PropertyInfo(Variant::OBJECT, "ret", PROPERTY_HINT_RESOURCE_TYPE, "VoxelChunk"), "_create_chunk", PropertyInfo(Variant::INT, "x"), PropertyInfo(Variant::INT, "y"), PropertyInfo(Variant::INT, "z"), PropertyInfo(Variant::OBJECT, "chunk", PROPERTY_HINT_RESOURCE_TYPE, "VoxelChunk")));
BIND_VMETHOD(MethodInfo("_prepare_chunk_for_generation", PropertyInfo(Variant::OBJECT, "chunk", PROPERTY_HINT_RESOURCE_TYPE, "VoxelChunk")));
BIND_VMETHOD(MethodInfo("_generate_chunk", PropertyInfo(Variant::OBJECT, "chunk", PROPERTY_HINT_RESOURCE_TYPE, "VoxelChunk")));
ClassDB::bind_method(D_METHOD("create_chunk", "x", "y", "z"), &VoxelWorld::create_chunk);
ClassDB::bind_method(D_METHOD("_create_chunk", "x", "y", "z"), &VoxelWorld::_create_chunk);
ClassDB::bind_method(D_METHOD("_create_chunk", "x", "y", "z", "chunk"), &VoxelWorld::_create_chunk);
ClassDB::bind_method(D_METHOD("_generate_chunk", "chunk"), &VoxelWorld::_generate_chunk);
}

View File

@ -83,7 +83,7 @@ public:
void clear();
VoxelChunk *create_chunk(int x, int y, int z);
VoxelChunk *_create_chunk(int x, int y, int z);
VoxelChunk *_create_chunk(int x, int y, int z, Node *p_chunk);
void generate_chunk_bind(Node *p_chunk);
void generate_chunk(VoxelChunk *p_chunk);