diff --git a/doc/classes/RenderingDevice.xml b/doc/classes/RenderingDevice.xml index f597cb7efc6..b9f6a009fb5 100644 --- a/doc/classes/RenderingDevice.xml +++ b/doc/classes/RenderingDevice.xml @@ -452,6 +452,14 @@ + + + + + + Returns [code]true[/code] if implementation supports using a texture of [param format] with the given [param sampler_filter]. + + diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index d03324527ee..2fd46d65ff8 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 3f01895745b..2ec1574955d 100644 --- a/drivers/vulkan/rendering_device_vulkan.h +++ b/drivers/vulkan/rendering_device_vulkan.h @@ -1084,6 +1084,7 @@ public: /*****************/ 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/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 4253ea86100..57da55db4d0 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 uniforms; Vector 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 0b6bcc29fb9..926da4026cc 100644 --- a/servers/rendering/renderer_rd/environment/fog.h +++ b/servers/rendering/renderer_rd/environment/fog.h @@ -301,10 +301,25 @@ public: 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 08133bf8d6c..52f09e1ccb5 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 gi_modes; @@ -3695,14 +3698,16 @@ void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Refhas_custom_data(RB_SCOPE_FOG)) { Ref 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); +#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; } - fog->fog_uniform_set = RID(); - fog->process_uniform_set = RID(); - fog->process_uniform_set2 = RID(); } } @@ -3929,7 +3934,6 @@ void GI::process_gi(Ref 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 459c4dcb1df..59af9501bae 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 744fd051f5e..4ff8bbfb85b 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()), 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 447627b08ef..48246fa44a0 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -653,6 +653,7 @@ public: }; 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 ****/