From 2beed0d5dcbfe6a69bc9d5a3a17c4977f10c9a7a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= <pedrojrulez@gmail.com>
Date: Wed, 26 Apr 2023 10:18:27 +0200
Subject: [PATCH 1/2] Fix breakages of volumetric fog on voxel GI changes

---
 .../rendering/renderer_rd/environment/fog.cpp | 45 +++++++++++--------
 .../rendering/renderer_rd/environment/fog.h   | 23 ++++++++--
 .../rendering/renderer_rd/environment/gi.cpp  | 18 ++++----
 3 files changed, 56 insertions(+), 30 deletions(-)

diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 4253ea861005..57da55db4d0b 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -463,15 +463,19 @@ Fog::VolumetricFog::~VolumetricFog() {
 	if (fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(fog_uniform_set)) {
 		RD::get_singleton()->free(fog_uniform_set);
 	}
-	if (process_uniform_set_density.is_valid() && RD::get_singleton()->uniform_set_is_valid(process_uniform_set_density)) {
-		RD::get_singleton()->free(process_uniform_set_density);
-	}
-	if (process_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(process_uniform_set)) {
-		RD::get_singleton()->free(process_uniform_set);
-	}
-	if (process_uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(process_uniform_set2)) {
-		RD::get_singleton()->free(process_uniform_set2);
+
+	// At this point, due to cascade deletions, the sets may no longer be valid, but still they must work as a group.
+	gi_dependent_sets.valid = RD::get_singleton()->uniform_set_is_valid(gi_dependent_sets.process_uniform_set_density);
+#ifdef DEV_ENABLED
+	gi_dependent_sets.assert_actual_validity();
+#endif
+	if (gi_dependent_sets.valid) {
+		RD::get_singleton()->free(gi_dependent_sets.copy_uniform_set);
+		RD::get_singleton()->free(gi_dependent_sets.process_uniform_set_density);
+		RD::get_singleton()->free(gi_dependent_sets.process_uniform_set);
+		RD::get_singleton()->free(gi_dependent_sets.process_uniform_set2);
 	}
+
 	if (sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sdfgi_uniform_set)) {
 		RD::get_singleton()->free(sdfgi_uniform_set);
 	}
@@ -713,7 +717,10 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
 		RD::get_singleton()->compute_list_end();
 	}
 
-	if (fog->process_uniform_set_density.is_null() || !RD::get_singleton()->uniform_set_is_valid(fog->process_uniform_set_density)) {
+#ifdef DEV_ENABLED
+	fog->gi_dependent_sets.assert_actual_validity();
+#endif
+	if (!fog->gi_dependent_sets.valid) {
 		//re create uniform set if needed
 		Vector<RD::Uniform> uniforms;
 		Vector<RD::Uniform> copy_uniforms;
@@ -910,9 +917,9 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
 			uniforms.push_back(u);
 		}
 
-		fog->copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0);
+		fog->gi_dependent_sets.copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0);
 
-		fog->process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0);
+		fog->gi_dependent_sets.process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0);
 
 		RID aux7 = uniforms.write[7].get_id(0);
 		RID aux8 = uniforms.write[8].get_id(0);
@@ -920,11 +927,13 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
 		uniforms.write[7].set_id(0, aux8);
 		uniforms.write[8].set_id(0, aux7);
 
-		fog->process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0);
+		fog->gi_dependent_sets.process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG), 0);
 
 		uniforms.remove_at(8);
 		uniforms.write[7].set_id(0, aux7);
-		fog->process_uniform_set_density = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0);
+		fog->gi_dependent_sets.process_uniform_set_density = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0);
+
+		fog->gi_dependent_sets.valid = true;
 	}
 
 	bool using_sdfgi = RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_gi_inject(p_settings.env) > 0.0001 && RendererSceneRenderRD::get_singleton()->environment_get_sdfgi_enabled(p_settings.env) && (p_settings.sdfgi.is_valid());
@@ -1067,7 +1076,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
 
 	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY]);
 
-	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->process_uniform_set_density, 0);
+	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set_density, 0);
 
 	if (using_sdfgi) {
 		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->sdfgi_uniform_set, 1);
@@ -1078,7 +1087,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
 	// Copy fog to history buffer
 	if (RendererSceneRenderRD::get_singleton()->environment_get_volumetric_fog_temporal_reprojection(p_settings.env)) {
 		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY]);
-		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->copy_uniform_set, 0);
+		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.copy_uniform_set, 0);
 		RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
 		RD::get_singleton()->compute_list_add_barrier(compute_list);
 	}
@@ -1090,7 +1099,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
 		RENDER_TIMESTAMP("Filter Fog");
 
 		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
-		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->process_uniform_set, 0);
+		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set, 0);
 		RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
 
 		RD::get_singleton()->compute_list_end();
@@ -1101,7 +1110,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
 
 		compute_list = RD::get_singleton()->compute_list_begin();
 		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]);
-		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->process_uniform_set2, 0);
+		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set2, 0);
 		RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, fog->depth);
 
 		RD::get_singleton()->compute_list_add_barrier(compute_list);
@@ -1112,7 +1121,7 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
 	RD::get_singleton()->draw_command_begin_label("Integrate Fog");
 
 	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG]);
-	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->process_uniform_set, 0);
+	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, fog->gi_dependent_sets.process_uniform_set, 0);
 	RD::get_singleton()->compute_list_dispatch_threads(compute_list, fog->width, fog->height, 1);
 
 	RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER);
diff --git a/servers/rendering/renderer_rd/environment/fog.h b/servers/rendering/renderer_rd/environment/fog.h
index 0b6bcc29fb96..926da4026ccd 100644
--- a/servers/rendering/renderer_rd/environment/fog.h
+++ b/servers/rendering/renderer_rd/environment/fog.h
@@ -301,10 +301,25 @@ class Fog : public RendererFog {
 		RID emissive_map;
 
 		RID fog_uniform_set;
-		RID copy_uniform_set;
-		RID process_uniform_set_density;
-		RID process_uniform_set;
-		RID process_uniform_set2;
+
+		struct {
+			bool valid = false;
+			RID copy_uniform_set;
+			RID process_uniform_set_density;
+			RID process_uniform_set;
+			RID process_uniform_set2;
+
+#ifdef DEV_ENABLED
+			void assert_actual_validity() {
+				// It's all-or-nothing, or something else has changed that requires dev attention.
+				DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(copy_uniform_set));
+				DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(process_uniform_set_density));
+				DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(process_uniform_set));
+				DEV_ASSERT(valid == RD::get_singleton()->uniform_set_is_valid(process_uniform_set2));
+			}
+#endif
+		} gi_dependent_sets;
+
 		RID sdfgi_uniform_set;
 		RID sky_uniform_set;
 
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index 08133bf8d6c1..fd7975ed3a59 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -3695,14 +3695,16 @@ void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBu
 		if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) {
 			Ref<Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG);
 
-			if (RD::get_singleton()->uniform_set_is_valid(fog->fog_uniform_set)) {
-				RD::get_singleton()->free(fog->fog_uniform_set);
-				RD::get_singleton()->free(fog->process_uniform_set);
-				RD::get_singleton()->free(fog->process_uniform_set2);
-			}
-			fog->fog_uniform_set = RID();
-			fog->process_uniform_set = RID();
-			fog->process_uniform_set2 = RID();
+#ifdef DEV_ENABLED
+			fog->gi_dependent_sets.assert_actual_validity();
+#endif
+			if (fog->gi_dependent_sets.valid) {
+				RD::get_singleton()->free(fog->gi_dependent_sets.copy_uniform_set);
+				RD::get_singleton()->free(fog->gi_dependent_sets.process_uniform_set_density);
+				RD::get_singleton()->free(fog->gi_dependent_sets.process_uniform_set);
+				RD::get_singleton()->free(fog->gi_dependent_sets.process_uniform_set2);
+				fog->gi_dependent_sets.valid = false;
+			}
 		}
 	}
 

From 09aa1bbdb3c9dc4891a192854636a4e33ccd46bc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pedro=20J=2E=20Est=C3=A9banez?= <pedrojrulez@gmail.com>
Date: Tue, 25 Apr 2023 14:14:01 +0200
Subject: [PATCH 2/2] Fix unsupported sampler filter used for voxel GI

---
 doc/classes/RenderingDevice.xml                      |  8 ++++++++
 drivers/vulkan/rendering_device_vulkan.cpp           | 12 ++++++++++++
 drivers/vulkan/rendering_device_vulkan.h             |  1 +
 servers/rendering/renderer_rd/environment/gi.cpp     |  4 +++-
 .../renderer_rd/shaders/environment/gi.glsl          |  8 ++++++++
 servers/rendering/rendering_device.cpp               |  1 +
 servers/rendering/rendering_device.h                 |  1 +
 7 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml
index f597cb7efc65..b9f6a009fb59 100644
--- a/doc/classes/RenderingDevice.xml
+++ b/doc/classes/RenderingDevice.xml
@@ -452,6 +452,14 @@
 			<description>
 			</description>
 		</method>
+		<method name="sampler_is_format_supported_for_filter" qualifiers="const">
+			<return type="bool" />
+			<param index="0" name="format" type="int" enum="RenderingDevice.DataFormat" />
+			<param index="1" name="sampler_filter" type="int" enum="RenderingDevice.SamplerFilter" />
+			<description>
+				Returns [code]true[/code] if implementation supports using a texture of [param format] with the given [param sampler_filter].
+			</description>
+		</method>
 		<method name="screen_get_framebuffer_format" qualifiers="const">
 			<return type="int" />
 			<description>
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index d03324527eed..2fd46d65ff81 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -4305,6 +4305,18 @@ RID RenderingDeviceVulkan::sampler_create(const SamplerState &p_state) {
 	return id;
 }
 
+bool RenderingDeviceVulkan::sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const {
+	ERR_FAIL_INDEX_V(p_format, DATA_FORMAT_MAX, false);
+
+	_THREAD_SAFE_METHOD_
+
+	// Validate that this image is supported for the intended filtering.
+	VkFormatProperties properties;
+	vkGetPhysicalDeviceFormatProperties(context->get_physical_device(), vulkan_formats[p_format], &properties);
+
+	return p_sampler_filter == RD::SAMPLER_FILTER_NEAREST || (p_sampler_filter == RD::SAMPLER_FILTER_LINEAR && (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT));
+}
+
 /**********************/
 /**** VERTEX ARRAY ****/
 /**********************/
diff --git a/drivers/vulkan/rendering_device_vulkan.h b/drivers/vulkan/rendering_device_vulkan.h
index 3f01895745bf..2ec1574955d9 100644
--- a/drivers/vulkan/rendering_device_vulkan.h
+++ b/drivers/vulkan/rendering_device_vulkan.h
@@ -1084,6 +1084,7 @@ class RenderingDeviceVulkan : public RenderingDevice {
 	/*****************/
 
 	virtual RID sampler_create(const SamplerState &p_state);
+	virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const;
 
 	/**********************/
 	/**** VERTEX ARRAY ****/
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index fd7975ed3a59..52f09e1ccb55 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -3493,6 +3493,9 @@ void GI::init(SkyRD *p_sky) {
 		if (RendererSceneRenderRD::get_singleton()->is_vrs_supported()) {
 			defines += "\n#define USE_VRS\n";
 		}
+		if (!RD::get_singleton()->sampler_is_format_supported_for_filter(RD::DATA_FORMAT_R8G8_UINT, RD::SAMPLER_FILTER_LINEAR)) {
+			defines += "\n#define SAMPLE_VOXEL_GI_NEAREST\n";
+		}
 
 		Vector<String> gi_modes;
 
@@ -3931,7 +3934,6 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor
 				u.append_id(material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED));
 				uniforms.push_back(u);
 			}
-
 			{
 				RD::Uniform u;
 				u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
index 459c4dcb1dff..59af9501bae1 100644
--- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
@@ -4,6 +4,10 @@
 
 #VERSION_DEFINES
 
+#ifdef SAMPLE_VOXEL_GI_NEAREST
+#extension GL_EXT_samplerless_texture_functions : enable
+#endif
+
 layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
 
 #define M_PI 3.141592
@@ -625,7 +629,11 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
 
 #ifdef USE_VOXEL_GI_INSTANCES
 		{
+#ifdef SAMPLE_VOXEL_GI_NEAREST
+			uvec2 voxel_gi_tex = texelFetch(voxel_gi_buffer, pos, 0).rg;
+#else
 			uvec2 voxel_gi_tex = texelFetch(usampler2D(voxel_gi_buffer, linear_sampler), pos, 0).rg;
+#endif
 			roughness *= roughness;
 			//find arbitrary tangent and bitangent, then build a matrix
 			vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 744fd051f5e9..4ff8bbfb85b9 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -723,6 +723,7 @@ void RenderingDevice::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("framebuffer_is_valid", "framebuffer"), &RenderingDevice::framebuffer_is_valid);
 
 	ClassDB::bind_method(D_METHOD("sampler_create", "state"), &RenderingDevice::_sampler_create);
+	ClassDB::bind_method(D_METHOD("sampler_is_format_supported_for_filter", "format", "sampler_filter"), &RenderingDevice::sampler_is_format_supported_for_filter);
 
 	ClassDB::bind_method(D_METHOD("vertex_buffer_create", "size_bytes", "data", "use_as_storage"), &RenderingDevice::vertex_buffer_create, DEFVAL(Vector<uint8_t>()), DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("vertex_format_create", "vertex_descriptions"), &RenderingDevice::_vertex_format_create);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 447627b08ef0..48246fa44a07 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -653,6 +653,7 @@ class RenderingDevice : public Object {
 	};
 
 	virtual RID sampler_create(const SamplerState &p_state) = 0;
+	virtual bool sampler_is_format_supported_for_filter(DataFormat p_format, SamplerFilter p_sampler_filter) const = 0;
 
 	/**********************/
 	/**** VERTEX ARRAY ****/