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.
This commit is contained in:
reduz 2021-07-07 19:55:20 -03:00
parent b1068f9f01
commit 83addd6ee5
9 changed files with 42 additions and 15 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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) {

View file

@ -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) {

View file

@ -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) {

View file

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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) {

View file

@ -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,

View file

@ -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;