From 9e9bac1549cb293850feac145622267153f9c7aa Mon Sep 17 00:00:00 2001 From: Tom Coxon Date: Mon, 6 Sep 2021 13:32:59 +0100 Subject: [PATCH] Prevent shaders from generating code before the constructor finishes. Fixes #43733: "creating SpatialMaterial in a separate thread creates invalid shaders (temporarily)." The bug occurred because various setters called in materials' constructors add materials to queues that are processed on the main thread. This means that when the materials are created in another thread, they can be processed on the main thread before the constructor has finished. The fix adds a flag to affected materials that prevents them from being added to the queue until their constructors have finished initialising all the members. --- scene/2d/canvas_item.cpp | 3 ++- scene/2d/canvas_item.h | 1 + scene/resources/material.cpp | 3 ++- scene/resources/material.h | 1 + scene/resources/particles_material.cpp | 3 ++- scene/resources/particles_material.h | 1 + 6 files changed, 9 insertions(+), 3 deletions(-) diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 7e97872469af..f65bd8ddc90c 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -176,7 +176,7 @@ void CanvasItemMaterial::flush_changes() { void CanvasItemMaterial::_queue_shader_change() { material_mutex.lock(); - if (!element.in_list()) { + if (is_initialized && !element.in_list()) { dirty_materials->add(&element); } @@ -313,6 +313,7 @@ CanvasItemMaterial::CanvasItemMaterial() : current_key.key = 0; current_key.invalid_key = 1; + is_initialized = true; _queue_shader_change(); } diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index ae0e638fdfd8..9ea94154459c 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -113,6 +113,7 @@ class CanvasItemMaterial : public Material { _FORCE_INLINE_ void _queue_shader_change(); _FORCE_INLINE_ bool _is_shader_dirty() const; + bool is_initialized = false; BlendMode blend_mode; LightMode light_mode; bool particles_animation; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 36c56847e220..4cf8a83e9572 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1073,7 +1073,7 @@ void SpatialMaterial::flush_changes() { void SpatialMaterial::_queue_shader_change() { material_mutex.lock(); - if (!element.in_list()) { + if (is_initialized && !element.in_list()) { dirty_materials->add(&element); } @@ -2317,6 +2317,7 @@ SpatialMaterial::SpatialMaterial() : current_key.key = 0; current_key.invalid_key = 1; + is_initialized = true; _queue_shader_change(); } diff --git a/scene/resources/material.h b/scene/resources/material.h index e8e772386c6a..94ab38304e5f 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -366,6 +366,7 @@ class SpatialMaterial : public Material { _FORCE_INLINE_ void _queue_shader_change(); _FORCE_INLINE_ bool _is_shader_dirty() const; + bool is_initialized = false; Color albedo; float specular; float metallic; diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index 74034c560042..ae7008f5b8e5 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -690,7 +690,7 @@ void ParticlesMaterial::flush_changes() { void ParticlesMaterial::_queue_shader_change() { material_mutex.lock(); - if (!element.in_list()) { + if (is_initialized && !element.in_list()) { dirty_materials->add(&element); } @@ -1367,6 +1367,7 @@ ParticlesMaterial::ParticlesMaterial() : current_key.key = 0; current_key.invalid_key = 1; + is_initialized = true; _queue_shader_change(); } diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index f82274bde2f0..3d564c7880aa 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -203,6 +203,7 @@ class ParticlesMaterial : public Material { _FORCE_INLINE_ void _queue_shader_change(); _FORCE_INLINE_ bool _is_shader_dirty() const; + bool is_initialized = false; Vector3 direction; float spread; float flatness;