Fix more issues when allocating and deleting chunks really fast. (Flying around in the editor at max speed.)

This commit is contained in:
Relintai 2022-02-19 22:09:22 +01:00
parent bc6aec520c
commit 0845d92e65
4 changed files with 137 additions and 16 deletions

View File

@ -732,7 +732,10 @@ void TerrainChunkDefault::_visibility_changed(bool visible) {
void TerrainChunkDefault::_exit_tree() { void TerrainChunkDefault::_exit_tree() {
TerrainChunk::_exit_tree(); TerrainChunk::_exit_tree();
rids_free(); if (!_is_generating) {
rids_free();
rids_clear();
}
} }
void TerrainChunkDefault::_world_transform_changed() { void TerrainChunkDefault::_world_transform_changed() {
@ -874,6 +877,9 @@ TerrainChunkDefault::~TerrainChunkDefault() {
_lights.clear(); _lights.clear();
debug_mesh_free(); debug_mesh_free();
rids_free();
rids_clear();
} }
void TerrainChunkDefault::_channel_setup() { void TerrainChunkDefault::_channel_setup() {

View File

@ -28,6 +28,7 @@ SOFTWARE.
#include "../defines.h" #include "../defines.h"
#include "core/message_queue.h"
#include "jobs/terrain_job.h" #include "jobs/terrain_job.h"
#include "terrain_structure.h" #include "terrain_structure.h"
@ -65,6 +66,10 @@ _FORCE_INLINE_ void TerrainChunk::set_is_generating(const bool value) {
_is_generating = value; _is_generating = value;
} }
bool TerrainChunk::is_build_aborted() const {
return _abort_build;
}
bool TerrainChunk::is_in_tree() const { bool TerrainChunk::is_in_tree() const {
return _is_in_tree; return _is_in_tree;
} }
@ -268,6 +273,12 @@ int TerrainChunk::job_get_current_index() {
return _current_job; return _current_job;
} }
void TerrainChunk::job_next() { void TerrainChunk::job_next() {
if (_abort_build) {
_is_generating = false;
_current_job = -1;
return;
}
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
++_current_job; ++_current_job;
@ -676,6 +687,22 @@ void TerrainChunk::finalize_build() {
} }
} }
void TerrainChunk::cancel_build() {
_queued_generation = false;
_abort_build = true;
#if THREAD_POOL_PRESENT
if (_is_generating) {
Ref<TerrainJob> job = job_get_current();
if (job.is_valid()) {
ThreadPool::get_singleton()->cancel_job(job);
}
}
#endif
}
void TerrainChunk::bake_lights() { void TerrainChunk::bake_lights() {
if (has_method("_bake_lights")) if (has_method("_bake_lights"))
call("_bake_lights"); call("_bake_lights");
@ -966,12 +993,6 @@ void TerrainChunk::enter_tree() {
void TerrainChunk::exit_tree() { void TerrainChunk::exit_tree() {
_is_in_tree = false; _is_in_tree = false;
if (_library.is_valid() && _library->supports_caching()) {
if (material_cache_key_has()) {
_library->material_cache_unref(material_cache_key_get());
}
}
if (has_method("_exit_tree")) if (has_method("_exit_tree"))
call("_exit_tree"); call("_exit_tree");
} }
@ -1026,6 +1047,24 @@ Vector3 TerrainChunk::to_global(Vector3 p_local) const {
return get_global_transform().xform(p_local); return get_global_transform().xform(p_local);
} }
bool TerrainChunk::is_safe_to_delete() {
#if THREAD_POOL_PRESENT
if (!_is_generating) {
return true;
}
Ref<TerrainJob> job = job_get_current();
if (!job.is_valid()) {
return true;
}
return !ThreadPool::get_singleton()->has_job(job);
#else
return true;
#endif
}
TerrainChunk::TerrainChunk() { TerrainChunk::TerrainChunk() {
_is_processing = false; _is_processing = false;
_is_phisics_processing = false; _is_phisics_processing = false;
@ -1110,7 +1149,9 @@ void TerrainChunk::_enter_tree() {
} }
void TerrainChunk::_exit_tree() { void TerrainChunk::_exit_tree() {
_abort_build = true; if (_is_generating) {
cancel_build();
}
for (int i = 0; i < _jobs.size(); ++i) { for (int i = 0; i < _jobs.size(); ++i) {
Ref<TerrainJob> j = _jobs[i]; Ref<TerrainJob> j = _jobs[i];
@ -1119,9 +1160,19 @@ void TerrainChunk::_exit_tree() {
j->chunk_exit_tree(); j->chunk_exit_tree();
} }
} }
if (_library.is_valid() && _library->supports_caching()) {
if (material_cache_key_has()) {
_library->material_cache_unref(material_cache_key_get());
}
}
} }
void TerrainChunk::_generation_process(const float delta) { void TerrainChunk::_generation_process(const float delta) {
if (_abort_build) {
return;
}
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (_current_job < 0 || _current_job >= _jobs.size()) if (_current_job < 0 || _current_job >= _jobs.size())
@ -1147,6 +1198,10 @@ void TerrainChunk::_generation_process(const float delta) {
} }
} }
void TerrainChunk::_generation_physics_process(const float delta) { void TerrainChunk::_generation_physics_process(const float delta) {
if (_abort_build) {
return;
}
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
if (_current_job < 0 || _current_job >= _jobs.size()) if (_current_job < 0 || _current_job >= _jobs.size())
@ -1270,6 +1325,8 @@ void TerrainChunk::_bind_methods() {
ClassDB::bind_method(D_METHOD("finalize_build"), &TerrainChunk::finalize_build); ClassDB::bind_method(D_METHOD("finalize_build"), &TerrainChunk::finalize_build);
ClassDB::bind_method(D_METHOD("cancel_build"), &TerrainChunk::cancel_build);
ClassDB::bind_method(D_METHOD("get_process"), &TerrainChunk::get_process); ClassDB::bind_method(D_METHOD("get_process"), &TerrainChunk::get_process);
ClassDB::bind_method(D_METHOD("set_process", "value"), &TerrainChunk::set_process); ClassDB::bind_method(D_METHOD("set_process", "value"), &TerrainChunk::set_process);
@ -1290,6 +1347,8 @@ void TerrainChunk::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_is_generating", "value"), &TerrainChunk::set_is_generating); ClassDB::bind_method(D_METHOD("set_is_generating", "value"), &TerrainChunk::set_is_generating);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_generating", PROPERTY_HINT_NONE, "", 0), "set_is_generating", "get_is_generating"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_generating", PROPERTY_HINT_NONE, "", 0), "set_is_generating", "get_is_generating");
ClassDB::bind_method(D_METHOD("is_build_aborted"), &TerrainChunk::is_build_aborted);
ClassDB::bind_method(D_METHOD("get_dirty"), &TerrainChunk::get_dirty); ClassDB::bind_method(D_METHOD("get_dirty"), &TerrainChunk::get_dirty);
ClassDB::bind_method(D_METHOD("set_dirty", "value"), &TerrainChunk::set_dirty); ClassDB::bind_method(D_METHOD("set_dirty", "value"), &TerrainChunk::set_dirty);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dirty", PROPERTY_HINT_NONE, "", 0), "set_dirty", "get_dirty"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dirty", PROPERTY_HINT_NONE, "", 0), "set_dirty", "get_dirty");
@ -1498,4 +1557,6 @@ void TerrainChunk::_bind_methods() {
ClassDB::bind_method(D_METHOD("_generation_process"), &TerrainChunk::_generation_process); ClassDB::bind_method(D_METHOD("_generation_process"), &TerrainChunk::_generation_process);
ClassDB::bind_method(D_METHOD("_generation_physics_process"), &TerrainChunk::_generation_physics_process); ClassDB::bind_method(D_METHOD("_generation_physics_process"), &TerrainChunk::_generation_physics_process);
ClassDB::bind_method(D_METHOD("is_safe_to_delete"), &TerrainChunk::is_safe_to_delete);
} }

View File

@ -95,6 +95,8 @@ public:
bool get_is_generating() const; bool get_is_generating() const;
void set_is_generating(const bool value); void set_is_generating(const bool value);
bool is_build_aborted() const;
bool is_in_tree() const; bool is_in_tree() const;
bool get_dirty() const; bool get_dirty() const;
@ -222,6 +224,7 @@ public:
void build(); void build();
void clear(); void clear();
void finalize_build(); void finalize_build();
void cancel_build();
void _build(); void _build();
@ -304,6 +307,8 @@ public:
Vector3 to_local(Vector3 p_global) const; Vector3 to_local(Vector3 p_global) const;
Vector3 to_global(Vector3 p_local) const; Vector3 to_global(Vector3 p_local) const;
bool is_safe_to_delete();
TerrainChunk(); TerrainChunk();
~TerrainChunk(); ~TerrainChunk();

View File

@ -24,6 +24,7 @@ SOFTWARE.
#include "core/version.h" #include "core/version.h"
#include "core/message_queue.h"
#include "terrain_chunk.h" #include "terrain_chunk.h"
#include "terrain_structure.h" #include "terrain_structure.h"
@ -291,11 +292,14 @@ Ref<TerrainChunk> TerrainWorld::chunk_get(const int x, const int z) {
Ref<TerrainChunk> TerrainWorld::chunk_remove(const int x, const int z) { Ref<TerrainChunk> TerrainWorld::chunk_remove(const int x, const int z) {
IntPos pos(x, z); IntPos pos(x, z);
if (!_chunks.has(pos)) if (!_chunks.has(pos)) {
return NULL; return NULL;
}
Ref<TerrainChunk> chunk = _chunks.get(pos); Ref<TerrainChunk> chunk = _chunks.get(pos);
chunk->exit_tree();
for (int i = 0; i < _chunks_vector.size(); ++i) { for (int i = 0; i < _chunks_vector.size(); ++i) {
if (_chunks_vector.get(i) == chunk) { if (_chunks_vector.get(i) == chunk) {
_chunks_vector.VREMOVE(i); _chunks_vector.VREMOVE(i);
@ -303,7 +307,14 @@ Ref<TerrainChunk> TerrainWorld::chunk_remove(const int x, const int z) {
} }
} }
chunk->exit_tree(); _generation_queue.erase(chunk);
if (chunk->get_is_generating()) {
chunk->cancel_build();
}
//never remove from this here
//_generating.erase(chunk);
_chunks.erase(pos); _chunks.erase(pos);
@ -315,9 +326,18 @@ Ref<TerrainChunk> TerrainWorld::chunk_remove_index(const int index) {
ERR_FAIL_INDEX_V(index, _chunks_vector.size(), NULL); ERR_FAIL_INDEX_V(index, _chunks_vector.size(), NULL);
Ref<TerrainChunk> chunk = _chunks_vector.get(index); Ref<TerrainChunk> chunk = _chunks_vector.get(index);
chunk->exit_tree();
_chunks_vector.VREMOVE(index); _chunks_vector.VREMOVE(index);
_chunks.erase(IntPos(chunk->get_position_x(), chunk->get_position_z())); _chunks.erase(IntPos(chunk->get_position_x(), chunk->get_position_z()));
chunk->exit_tree(); _generation_queue.erase(chunk);
if (chunk->get_is_generating()) {
chunk->cancel_build();
}
//never remove from this here
//_generating.erase(chunk);
emit_signal("chunk_removed", chunk); emit_signal("chunk_removed", chunk);
@ -343,11 +363,19 @@ void TerrainWorld::chunks_clear() {
} }
_chunks_vector.clear(); _chunks_vector.clear();
_chunks.clear(); _chunks.clear();
_generation_queue.clear(); _generation_queue.clear();
_generating.clear();
for (int i = 0; i < _generating.size(); ++i) {
Ref<TerrainChunk> chunk = _generating[i];
if (chunk->get_is_generating()) {
chunk->cancel_build();
}
}
//never remove from this here
//_generating.clear();
} }
Ref<TerrainChunk> TerrainWorld::chunk_get_or_create(int x, int z) { Ref<TerrainChunk> TerrainWorld::chunk_get_or_create(int x, int z) {
@ -433,7 +461,16 @@ void TerrainWorld::chunks_set(const Vector<Variant> &chunks) {
if (chunks.find(chunk) == -1) { if (chunks.find(chunk) == -1) {
chunk_remove_index(i); chunk_remove_index(i);
_generation_queue.erase(chunk); _generation_queue.erase(chunk);
_generating.erase(chunk);
chunk->exit_tree();
if (chunk->get_is_generating()) {
chunk->cancel_build();
}
//never remove from this here
//_generating.erase(chunk);
--i; --i;
} }
} }
@ -963,7 +1000,19 @@ void TerrainWorld::_notification(int p_what) {
for (int i = 0; i < _generating.size(); ++i) { for (int i = 0; i < _generating.size(); ++i) {
Ref<TerrainChunk> chunk = _generating.get(i); Ref<TerrainChunk> chunk = _generating.get(i);
if (!chunk.is_valid() || !chunk->get_is_generating()) { if (!chunk.is_valid()) {
_generating.VREMOVE(i);
--i;
continue;
}
if (!chunk->get_is_generating()) {
_generating.VREMOVE(i);
--i;
continue;
}
if (chunk->is_build_aborted() && chunk->is_safe_to_delete()) {
_generating.VREMOVE(i); _generating.VREMOVE(i);
--i; --i;
continue; continue;