summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPedro J. Estébanez <pedrojrulez@gmail.com>2023-05-09 18:59:59 +0200
committerPedro J. Estébanez <pedrojrulez@gmail.com>2023-05-10 18:53:41 +0200
commitb6647a58080da116d74edf2eb9378b5bbe2e97cc (patch)
treec356a40e596f01f02d64e4c2daa4fbef52cb99b5
parent5a4613f5512b84a758d7cb4850f6e35db2bcceba (diff)
downloadredot-engine-b6647a58080da116d74edf2eb9378b5bbe2e97cc.tar.gz
Avoid sync issues in materials with scheduled shader updates
-rw-r--r--core/io/resource_loader.h2
-rw-r--r--scene/resources/canvas_item_material.cpp6
-rw-r--r--scene/resources/canvas_item_material.h1
-rw-r--r--scene/resources/material.cpp22
-rw-r--r--scene/resources/material.h10
-rw-r--r--scene/resources/particle_process_material.cpp5
-rw-r--r--scene/resources/particle_process_material.h1
7 files changed, 35 insertions, 12 deletions
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 0615ae63aa..2bb46387e9 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -199,6 +199,8 @@ public:
static ThreadLoadStatus load_threaded_get_status(const String &p_path, float *r_progress = nullptr);
static Ref<Resource> load_threaded_get(const String &p_path, Error *r_error = nullptr);
+ static bool is_within_load() { return load_nesting > 0; };
+
static Ref<Resource> load(const String &p_path, const String &p_type_hint = "", ResourceFormatLoader::CacheMode p_cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE, Error *r_error = nullptr);
static bool exists(const String &p_path, const String &p_type_hint = "");
diff --git a/scene/resources/canvas_item_material.cpp b/scene/resources/canvas_item_material.cpp
index 0d5d735ed0..31c8e68ea5 100644
--- a/scene/resources/canvas_item_material.cpp
+++ b/scene/resources/canvas_item_material.cpp
@@ -161,7 +161,7 @@ void CanvasItemMaterial::flush_changes() {
void CanvasItemMaterial::_queue_shader_change() {
MutexLock lock(material_mutex);
- if (is_initialized && !element.in_list()) {
+ if (_is_initialized() && !element.in_list()) {
dirty_materials->add(&element);
}
}
@@ -287,8 +287,8 @@ CanvasItemMaterial::CanvasItemMaterial() :
set_particles_anim_loop(false);
current_key.invalid_key = 1;
- is_initialized = true;
- _queue_shader_change();
+
+ _mark_initialized(callable_mp(this, &CanvasItemMaterial::_queue_shader_change));
}
CanvasItemMaterial::~CanvasItemMaterial() {
diff --git a/scene/resources/canvas_item_material.h b/scene/resources/canvas_item_material.h
index cf5df76147..7dddd74a31 100644
--- a/scene/resources/canvas_item_material.h
+++ b/scene/resources/canvas_item_material.h
@@ -105,7 +105,6 @@ private:
_FORCE_INLINE_ void _queue_shader_change();
_FORCE_INLINE_ bool _is_shader_dirty() const;
- bool is_initialized = false;
BlendMode blend_mode = BLEND_MODE_MIX;
LightMode light_mode = LIGHT_MODE_NORMAL;
bool particles_animation = false;
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index d0aa224773..d35c49b266 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -82,6 +82,23 @@ void Material::_validate_property(PropertyInfo &p_property) const {
}
}
+void Material::_mark_initialized(const Callable &p_queue_shader_change_callable) {
+ // If this is happening as part of resource loading, it is not safe to queue the update
+ // as an addition to the dirty list, unless the load is happening on the main thread.
+ if (ResourceLoader::is_within_load() && Thread::get_caller_id() != Thread::get_main_id()) {
+ DEV_ASSERT(init_state != INIT_STATE_READY);
+ if (init_state == INIT_STATE_UNINITIALIZED) { // Prevent queueing twice.
+ // Queue an individual update of this material (the ResourceLoader knows how to handle deferred calls safely).
+ p_queue_shader_change_callable.call_deferred();
+ init_state = INIT_STATE_INITIALIZING;
+ }
+ } else {
+ // Straightforward conditions.
+ init_state = INIT_STATE_READY;
+ p_queue_shader_change_callable.callv(Array());
+ }
+}
+
void Material::inspect_native_shader_code() {
SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop());
RID shader = get_shader_rid();
@@ -1485,7 +1502,7 @@ void BaseMaterial3D::flush_changes() {
void BaseMaterial3D::_queue_shader_change() {
MutexLock lock(material_mutex);
- if (is_initialized && !element.in_list()) {
+ if (_is_initialized() && !element.in_list()) {
dirty_materials->add(&element);
}
}
@@ -3028,8 +3045,7 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
flags[FLAG_ALBEDO_TEXTURE_MSDF] = false;
flags[FLAG_USE_TEXTURE_REPEAT] = true;
- is_initialized = true;
- _queue_shader_change();
+ _mark_initialized(callable_mp(this, &BaseMaterial3D::_queue_shader_change));
}
BaseMaterial3D::~BaseMaterial3D() {
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 1fa9a24bc5..b70522dda1 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -46,6 +46,12 @@ class Material : public Resource {
Ref<Material> next_pass;
int render_priority;
+ enum {
+ INIT_STATE_UNINITIALIZED,
+ INIT_STATE_INITIALIZING,
+ INIT_STATE_READY,
+ } init_state = INIT_STATE_UNINITIALIZED;
+
void inspect_native_shader_code();
protected:
@@ -56,6 +62,9 @@ protected:
void _validate_property(PropertyInfo &p_property) const;
+ void _mark_initialized(const Callable &p_queue_shader_change_callable);
+ bool _is_initialized() { return init_state == INIT_STATE_READY; }
+
GDVIRTUAL0RC(RID, _get_shader_rid)
GDVIRTUAL0RC(Shader::Mode, _get_shader_mode)
GDVIRTUAL0RC(bool, _can_do_next_pass)
@@ -452,7 +461,6 @@ private:
_FORCE_INLINE_ void _queue_shader_change();
_FORCE_INLINE_ bool _is_shader_dirty() const;
- bool is_initialized = false;
bool orm;
Color albedo;
diff --git a/scene/resources/particle_process_material.cpp b/scene/resources/particle_process_material.cpp
index 41edbcb726..cb94d5af36 100644
--- a/scene/resources/particle_process_material.cpp
+++ b/scene/resources/particle_process_material.cpp
@@ -915,7 +915,7 @@ void ParticleProcessMaterial::flush_changes() {
void ParticleProcessMaterial::_queue_shader_change() {
MutexLock lock(material_mutex);
- if (is_initialized && !element.in_list()) {
+ if (_is_initialized() && !element.in_list()) {
dirty_materials->add(&element);
}
}
@@ -1889,8 +1889,7 @@ ParticleProcessMaterial::ParticleProcessMaterial() :
current_key.invalid_key = 1;
- is_initialized = true;
- _queue_shader_change();
+ _mark_initialized(callable_mp(this, &ParticleProcessMaterial::_queue_shader_change));
}
ParticleProcessMaterial::~ParticleProcessMaterial() {
diff --git a/scene/resources/particle_process_material.h b/scene/resources/particle_process_material.h
index c32a143cdc..533bd9636f 100644
--- a/scene/resources/particle_process_material.h
+++ b/scene/resources/particle_process_material.h
@@ -261,7 +261,6 @@ private:
_FORCE_INLINE_ void _queue_shader_change();
_FORCE_INLINE_ bool _is_shader_dirty() const;
- bool is_initialized = false;
Vector3 direction;
float spread = 0.0f;
float flatness = 0.0f;