ソースを参照

Fix material invalidation on reimport.

* IF a texture was reimported (calling replace as an example), it would invalidate all materials using it, causing plenty of errors.
* Added the possibility to get a notification when a uniform set is erased.
* With this notification, materials can be queued for update properly.
reduz 4 年 前
コミット
83addd6ee5

+ 11 - 0
drivers/vulkan/rendering_device_vulkan.cpp

@@ -5505,6 +5505,13 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) {
 	return uniform_set_owner.owns(p_uniform_set);
 }
 
+void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) {
+	UniformSet *us = uniform_set_owner.getornull(p_uniform_set);
+	ERR_FAIL_COND(!us);
+	us->invalidated_callback = p_callback;
+	us->invalidated_callback_userdata = p_userdata;
+}
+
 Error RenderingDeviceVulkan::buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier) {
 	_THREAD_SAFE_METHOD_
 
@@ -7844,6 +7851,10 @@ void RenderingDeviceVulkan::_free_internal(RID p_id) {
 	} else if (uniform_set_owner.owns(p_id)) {
 		UniformSet *uniform_set = uniform_set_owner.getornull(p_id);
 		frames[frame].uniform_sets_to_dispose_of.push_back(*uniform_set);
+		if (uniform_set->invalidated_callback != nullptr) {
+			uniform_set->invalidated_callback(p_id, uniform_set->invalidated_callback_userdata);
+		}
+
 		uniform_set_owner.free(p_id);
 	} else if (render_pipeline_owner.owns(p_id)) {
 		RenderPipeline *pipeline = render_pipeline_owner.getornull(p_id);

+ 3 - 0
drivers/vulkan/rendering_device_vulkan.h

@@ -732,6 +732,8 @@ class RenderingDeviceVulkan : public RenderingDevice {
 		LocalVector<AttachableTexture> attachable_textures; //used for validation
 		Vector<Texture *> mutable_sampled_textures; //used for layout change
 		Vector<Texture *> mutable_storage_textures; //used for layout change
+		UniformSetInvalidatedCallback invalidated_callback = nullptr;
+		void *invalidated_callback_userdata = nullptr;
 	};
 
 	RID_Owner<UniformSet, true> uniform_set_owner;
@@ -1088,6 +1090,7 @@ public:
 
 	virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set);
 	virtual bool uniform_set_is_valid(RID p_uniform_set);
+	virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata);
 
 	virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL); //works for any buffer
 	virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL);

+ 1 - 3
servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp

@@ -442,9 +442,7 @@ bool SceneShaderForwardClustered::MaterialData::update_parameters(const Map<Stri
 }
 
 SceneShaderForwardClustered::MaterialData::~MaterialData() {
-	if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
-		RD::get_singleton()->free(uniform_set);
-	}
+	free_parameters_uniform_set(uniform_set);
 }
 
 RendererStorageRD::MaterialData *SceneShaderForwardClustered::_create_material_func(ShaderData *p_shader) {

+ 1 - 3
servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp

@@ -436,9 +436,7 @@ bool SceneShaderForwardMobile::MaterialData::update_parameters(const Map<StringN
 }
 
 SceneShaderForwardMobile::MaterialData::~MaterialData() {
-	if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
-		RD::get_singleton()->free(uniform_set);
-	}
+	free_parameters_uniform_set(uniform_set);
 }
 
 RendererStorageRD::MaterialData *SceneShaderForwardMobile::_create_material_func(ShaderData *p_shader) {

+ 1 - 3
servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp

@@ -2208,9 +2208,7 @@ bool RendererCanvasRenderRD::MaterialData::update_parameters(const Map<StringNam
 }
 
 RendererCanvasRenderRD::MaterialData::~MaterialData() {
-	if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
-		RD::get_singleton()->free(uniform_set);
-	}
+	free_parameters_uniform_set(uniform_set);
 }
 
 RendererStorageRD::MaterialData *RendererCanvasRenderRD::_create_material_func(ShaderData *p_shader) {

+ 1 - 3
servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp

@@ -239,9 +239,7 @@ bool RendererSceneSkyRD::SkyMaterialData::update_parameters(const Map<StringName
 }
 
 RendererSceneSkyRD::SkyMaterialData::~SkyMaterialData() {
-	if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
-		RD::get_singleton()->free(uniform_set);
-	}
+	free_parameters_uniform_set(uniform_set);
 }
 
 ////////////////////////////////////////////////////////////////////////////////

+ 20 - 3
servers/rendering/renderer_rd/renderer_storage_rd.cpp

@@ -2377,6 +2377,13 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari
 	}
 }
 
+void RendererStorageRD::MaterialData::free_parameters_uniform_set(RID p_uniform_set) {
+	if (p_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(p_uniform_set)) {
+		RD::get_singleton()->uniform_set_set_invalidation_callback(p_uniform_set, nullptr, nullptr);
+		RD::get_singleton()->free(p_uniform_set);
+	}
+}
+
 bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, RID> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier) {
 	if ((uint32_t)ubo_data.size() != p_ubo_size) {
 		p_uniform_dirty = true;
@@ -2393,6 +2400,7 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St
 
 		//clear previous uniform set
 		if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+			RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, nullptr, nullptr);
 			RD::get_singleton()->free(uniform_set);
 			uniform_set = RID();
 		}
@@ -2412,6 +2420,7 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St
 
 		//clear previous uniform set
 		if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
+			RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, nullptr, nullptr);
 			RD::get_singleton()->free(uniform_set);
 			uniform_set = RID();
 		}
@@ -2454,9 +2463,19 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St
 
 	uniform_set = RD::get_singleton()->uniform_set_create(uniforms, p_shader, p_shader_uniform_set);
 
+	RD::get_singleton()->uniform_set_set_invalidation_callback(uniform_set, _material_uniform_set_erased, &self);
+
 	return true;
 }
 
+void RendererStorageRD::_material_uniform_set_erased(const RID &p_set, void *p_material) {
+	RID rid = *(RID *)p_material;
+	Material *material = base_singleton->material_owner.getornull(rid);
+	if (material) {
+		material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL);
+	}
+}
+
 void RendererStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) {
 	Material *material = material_owner.getornull(p_material);
 	if (material->shader_type != p_shader_type) {
@@ -5367,9 +5386,7 @@ bool RendererStorageRD::ParticlesMaterialData::update_parameters(const Map<Strin
 }
 
 RendererStorageRD::ParticlesMaterialData::~ParticlesMaterialData() {
-	if (uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(uniform_set)) {
-		RD::get_singleton()->free(uniform_set);
-	}
+	free_parameters_uniform_set(uniform_set);
 }
 
 RendererStorageRD::MaterialData *RendererStorageRD::_create_particles_material_func(ParticlesShaderData *p_shader) {

+ 2 - 0
servers/rendering/renderer_rd/renderer_storage_rd.h

@@ -160,6 +160,7 @@ public:
 
 		//to be used internally by update_parameters, in the most common configuration of material parameters
 		bool update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, RID> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+		void free_parameters_uniform_set(RID p_uniform_set);
 
 	private:
 		friend class RendererStorageRD;
@@ -175,6 +176,7 @@ public:
 		Vector<RID> texture_cache;
 	};
 	typedef MaterialData *(*MaterialDataRequestFunction)(ShaderData *);
+	static void _material_uniform_set_erased(const RID &p_set, void *p_material);
 
 	enum DefaultRDTexture {
 		DEFAULT_RD_TEXTURE_WHITE,

+ 2 - 0
servers/rendering/rendering_device.h

@@ -715,6 +715,8 @@ public:
 
 	virtual RID uniform_set_create(const Vector<Uniform> &p_uniforms, RID p_shader, uint32_t p_shader_set) = 0;
 	virtual bool uniform_set_is_valid(RID p_uniform_set) = 0;
+	typedef void (*UniformSetInvalidatedCallback)(const RID &, void *);
+	virtual void uniform_set_set_invalidation_callback(RID p_uniform_set, UniformSetInvalidatedCallback p_callback, void *p_userdata) = 0;
 
 	virtual Error buffer_update(RID p_buffer, uint32_t p_offset, uint32_t p_size, const void *p_data, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;
 	virtual Error buffer_clear(RID p_buffer, uint32_t p_offset, uint32_t p_size, uint32_t p_post_barrier = BARRIER_MASK_ALL) = 0;