Reduce locking of VoxelGeneratorGraph.
Generation hold its own shared pointer. If the user recompiles the graph, the runtime is replaced with a new one, while the generator can finish its current block with the old runtime without locking.master
parent
67b1a2b86f
commit
f54b152e2d
|
@ -22,10 +22,7 @@ void VoxelGeneratorGraph::clear() {
|
||||||
_graph.clear();
|
_graph.clear();
|
||||||
{
|
{
|
||||||
RWLockWrite wlock(_runtime_lock);
|
RWLockWrite wlock(_runtime_lock);
|
||||||
if (_runtime != nullptr) {
|
_runtime.reset();
|
||||||
memdelete(_runtime);
|
|
||||||
_runtime = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,9 +199,11 @@ void VoxelGeneratorGraph::generate_block(VoxelBlockRequest &input) {
|
||||||
// If the user tries to edit (and recompile) the graph while it's still generating stuff in the editor,
|
// If the user tries to edit (and recompile) the graph while it's still generating stuff in the editor,
|
||||||
// the editor will freeze until generation has completed.
|
// the editor will freeze until generation has completed.
|
||||||
// Use std::shared_ptr?
|
// Use std::shared_ptr?
|
||||||
RWLockRead rlock(_runtime_lock);
|
std::shared_ptr<VoxelGraphRuntime> runtime;
|
||||||
|
{
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
RWLockRead rlock(_runtime_lock);
|
||||||
|
runtime = _runtime;
|
||||||
|
}
|
||||||
|
|
||||||
if (runtime == nullptr || !runtime->has_output()) {
|
if (runtime == nullptr || !runtime->has_output()) {
|
||||||
return;
|
return;
|
||||||
|
@ -314,19 +313,12 @@ void VoxelGeneratorGraph::generate_block(VoxelBlockRequest &input) {
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelGraphRuntime::CompilationResult VoxelGeneratorGraph::compile() {
|
VoxelGraphRuntime::CompilationResult VoxelGeneratorGraph::compile() {
|
||||||
VoxelGraphRuntime::CompilationResult result;
|
std::shared_ptr<VoxelGraphRuntime> r = std::make_shared<VoxelGraphRuntime>();
|
||||||
VoxelGraphRuntime *r = memnew(VoxelGraphRuntime);
|
const VoxelGraphRuntime::CompilationResult result = r->compile(_graph, Engine::get_singleton()->is_editor_hint());
|
||||||
result = r->compile(_graph, Engine::get_singleton()->is_editor_hint());
|
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
RWLockWrite wlock(_runtime_lock);
|
RWLockWrite wlock(_runtime_lock);
|
||||||
if (_runtime != nullptr) {
|
|
||||||
memdelete(_runtime);
|
|
||||||
}
|
|
||||||
_runtime = r;
|
_runtime = r;
|
||||||
|
|
||||||
} else {
|
|
||||||
memdelete(r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -335,19 +327,17 @@ VoxelGraphRuntime::CompilationResult VoxelGeneratorGraph::compile() {
|
||||||
// This is an external API which involves locking so better not use this internally
|
// This is an external API which involves locking so better not use this internally
|
||||||
bool VoxelGeneratorGraph::is_good() const {
|
bool VoxelGeneratorGraph::is_good() const {
|
||||||
RWLockRead rlock(_runtime_lock);
|
RWLockRead rlock(_runtime_lock);
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
return _runtime != nullptr && _runtime->has_output();
|
||||||
return runtime != nullptr && runtime->has_output();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelGeneratorGraph::generate_set(ArraySlice<float> in_x, ArraySlice<float> in_y, ArraySlice<float> in_z,
|
void VoxelGeneratorGraph::generate_set(ArraySlice<float> in_x, ArraySlice<float> in_y, ArraySlice<float> in_z,
|
||||||
ArraySlice<float> out_sdf) {
|
ArraySlice<float> out_sdf) {
|
||||||
|
|
||||||
RWLockRead rlock(_runtime_lock);
|
RWLockRead rlock(_runtime_lock);
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
ERR_FAIL_COND(_runtime == nullptr || !_runtime->has_output());
|
||||||
ERR_FAIL_COND(runtime == nullptr || !runtime->has_output());
|
|
||||||
Cache &cache = _cache;
|
Cache &cache = _cache;
|
||||||
runtime->prepare_state(cache.state, in_x.size());
|
_runtime->prepare_state(cache.state, in_x.size());
|
||||||
runtime->generate_set(cache.state, in_x, in_y, in_z, out_sdf, false);
|
_runtime->generate_set(cache.state, in_x, in_y, in_z, out_sdf, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const VoxelGraphRuntime::State &VoxelGeneratorGraph::get_last_state_from_current_thread() {
|
const VoxelGraphRuntime::State &VoxelGeneratorGraph::get_last_state_from_current_thread() {
|
||||||
|
@ -356,9 +346,8 @@ const VoxelGraphRuntime::State &VoxelGeneratorGraph::get_last_state_from_current
|
||||||
|
|
||||||
uint32_t VoxelGeneratorGraph::get_output_port_address(ProgramGraph::PortLocation port) const {
|
uint32_t VoxelGeneratorGraph::get_output_port_address(ProgramGraph::PortLocation port) const {
|
||||||
RWLockRead rlock(_runtime_lock);
|
RWLockRead rlock(_runtime_lock);
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
ERR_FAIL_COND_V(_runtime == nullptr || !_runtime->has_output(), 0);
|
||||||
ERR_FAIL_COND_V(runtime == nullptr || !runtime->has_output(), 0);
|
return _runtime->get_output_port_address(port);
|
||||||
return runtime->get_output_port_address(port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Vector3 get_3d_pos_from_panorama_uv(Vector2 uv) {
|
inline Vector3 get_3d_pos_from_panorama_uv(Vector2 uv) {
|
||||||
|
@ -374,8 +363,12 @@ inline Vector3 get_3d_pos_from_panorama_uv(Vector2 uv) {
|
||||||
void VoxelGeneratorGraph::bake_sphere_bumpmap(Ref<Image> im, float ref_radius, float sdf_min, float sdf_max) {
|
void VoxelGeneratorGraph::bake_sphere_bumpmap(Ref<Image> im, float ref_radius, float sdf_min, float sdf_max) {
|
||||||
ERR_FAIL_COND(im.is_null());
|
ERR_FAIL_COND(im.is_null());
|
||||||
|
|
||||||
RWLockRead rlock(_runtime_lock);
|
std::shared_ptr<const VoxelGraphRuntime> runtime;
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
{
|
||||||
|
RWLockRead rlock(_runtime_lock);
|
||||||
|
runtime = _runtime;
|
||||||
|
}
|
||||||
|
|
||||||
ERR_FAIL_COND(runtime == nullptr || !runtime->has_output());
|
ERR_FAIL_COND(runtime == nullptr || !runtime->has_output());
|
||||||
|
|
||||||
Cache &cache = _cache;
|
Cache &cache = _cache;
|
||||||
|
@ -409,8 +402,12 @@ void VoxelGeneratorGraph::bake_sphere_bumpmap(Ref<Image> im, float ref_radius, f
|
||||||
void VoxelGeneratorGraph::bake_sphere_normalmap(Ref<Image> im, float ref_radius, float strength) {
|
void VoxelGeneratorGraph::bake_sphere_normalmap(Ref<Image> im, float ref_radius, float strength) {
|
||||||
ERR_FAIL_COND(im.is_null());
|
ERR_FAIL_COND(im.is_null());
|
||||||
|
|
||||||
RWLockRead rlock(_runtime_lock);
|
std::shared_ptr<const VoxelGraphRuntime> runtime;
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
{
|
||||||
|
RWLockRead rlock(_runtime_lock);
|
||||||
|
runtime = _runtime;
|
||||||
|
}
|
||||||
|
|
||||||
ERR_FAIL_COND(runtime == nullptr || !runtime->has_output());
|
ERR_FAIL_COND(runtime == nullptr || !runtime->has_output());
|
||||||
|
|
||||||
Cache &cache = _cache;
|
Cache &cache = _cache;
|
||||||
|
@ -469,8 +466,11 @@ void VoxelGeneratorGraph::bake_sphere_normalmap(Ref<Image> im, float ref_radius,
|
||||||
|
|
||||||
// TODO This function isn't used yet, but whatever uses it should probably put locking and cache outside
|
// TODO This function isn't used yet, but whatever uses it should probably put locking and cache outside
|
||||||
float VoxelGeneratorGraph::generate_single(const Vector3i &position) {
|
float VoxelGeneratorGraph::generate_single(const Vector3i &position) {
|
||||||
RWLockRead rlock(_runtime_lock);
|
std::shared_ptr<const VoxelGraphRuntime> runtime;
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
{
|
||||||
|
RWLockRead rlock(_runtime_lock);
|
||||||
|
runtime = _runtime;
|
||||||
|
}
|
||||||
ERR_FAIL_COND_V(runtime == nullptr || !runtime->has_output(), 0.f);
|
ERR_FAIL_COND_V(runtime == nullptr || !runtime->has_output(), 0.f);
|
||||||
Cache &cache = _cache;
|
Cache &cache = _cache;
|
||||||
runtime->prepare_state(cache.state, 1);
|
runtime->prepare_state(cache.state, 1);
|
||||||
|
@ -479,7 +479,11 @@ float VoxelGeneratorGraph::generate_single(const Vector3i &position) {
|
||||||
|
|
||||||
Interval VoxelGeneratorGraph::analyze_range(Vector3i min_pos, Vector3i max_pos) {
|
Interval VoxelGeneratorGraph::analyze_range(Vector3i min_pos, Vector3i max_pos) {
|
||||||
RWLockRead rlock(_runtime_lock);
|
RWLockRead rlock(_runtime_lock);
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
std::shared_ptr<const VoxelGraphRuntime> runtime;
|
||||||
|
{
|
||||||
|
RWLockRead rlock(_runtime_lock);
|
||||||
|
runtime = _runtime;
|
||||||
|
}
|
||||||
ERR_FAIL_COND_V(runtime == nullptr || !runtime->has_output(), Interval::from_single_value(0.f));
|
ERR_FAIL_COND_V(runtime == nullptr || !runtime->has_output(), Interval::from_single_value(0.f));
|
||||||
Cache &cache = _cache;
|
Cache &cache = _cache;
|
||||||
// Note, buffer size is irrelevant here
|
// Note, buffer size is irrelevant here
|
||||||
|
@ -644,7 +648,11 @@ void VoxelGeneratorGraph::load_graph_from_variant_data(Dictionary data) {
|
||||||
|
|
||||||
float VoxelGeneratorGraph::debug_measure_microseconds_per_voxel(bool singular) {
|
float VoxelGeneratorGraph::debug_measure_microseconds_per_voxel(bool singular) {
|
||||||
RWLockRead rlock(_runtime_lock);
|
RWLockRead rlock(_runtime_lock);
|
||||||
const VoxelGraphRuntime *runtime = _runtime;
|
std::shared_ptr<const VoxelGraphRuntime> runtime;
|
||||||
|
{
|
||||||
|
RWLockRead rlock(_runtime_lock);
|
||||||
|
runtime = _runtime;
|
||||||
|
}
|
||||||
ERR_FAIL_COND_V(runtime == nullptr || !runtime->has_output(), 0.f);
|
ERR_FAIL_COND_V(runtime == nullptr || !runtime->has_output(), 0.f);
|
||||||
|
|
||||||
const uint32_t cube_size = 16;
|
const uint32_t cube_size = 16;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "../voxel_generator.h"
|
#include "../voxel_generator.h"
|
||||||
#include "program_graph.h"
|
#include "program_graph.h"
|
||||||
#include "voxel_graph_runtime.h"
|
#include "voxel_graph_runtime.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class VoxelGeneratorGraph : public VoxelGenerator {
|
class VoxelGeneratorGraph : public VoxelGenerator {
|
||||||
GDCLASS(VoxelGeneratorGraph, VoxelGenerator)
|
GDCLASS(VoxelGeneratorGraph, VoxelGenerator)
|
||||||
|
@ -150,7 +151,7 @@ private:
|
||||||
|
|
||||||
// Only compiling and generation methods are thread-safe.
|
// Only compiling and generation methods are thread-safe.
|
||||||
|
|
||||||
VoxelGraphRuntime *_runtime = nullptr;
|
std::shared_ptr<VoxelGraphRuntime> _runtime = nullptr;
|
||||||
RWLock *_runtime_lock = nullptr;
|
RWLock *_runtime_lock = nullptr;
|
||||||
|
|
||||||
struct Cache {
|
struct Cache {
|
||||||
|
|
Loading…
Reference in New Issue