Browse Source

Move screen space effects into a separate class

Bastiaan Olij 3 years ago
parent
commit
eefcb5ed67
27 changed files with 2633 additions and 1919 deletions
  1. 0 1
      drivers/gles3/rasterizer_scene_gles3.h
  2. 106 0
      servers/rendering/renderer_rd/effects/copy_effects.cpp
  3. 30 0
      servers/rendering/renderer_rd/effects/copy_effects.h
  4. 1715 0
      servers/rendering/renderer_rd/effects/ss_effects.cpp
  5. 508 0
      servers/rendering/renderer_rd/effects/ss_effects.h
  6. 1 1073
      servers/rendering/renderer_rd/effects_rd.cpp
  7. 0 384
      servers/rendering/renderer_rd/effects_rd.h
  8. 1 1
      servers/rendering/renderer_rd/environment/gi.h
  9. 22 4
      servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
  10. 2 0
      servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
  11. 39 322
      servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
  12. 6 38
      servers/rendering/renderer_rd/renderer_scene_render_rd.h
  13. 24 14
      servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
  14. 7 13
      servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl
  15. 28 0
      servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl
  16. 32 16
      servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl
  17. 112 0
      servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl
  18. 0 0
      servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl
  19. 0 0
      servers/rendering/renderer_rd/shaders/effects/ssao.glsl
  20. 0 0
      servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl
  21. 0 0
      servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl
  22. 0 0
      servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl
  23. 0 0
      servers/rendering/renderer_rd/shaders/effects/ssil.glsl
  24. 0 0
      servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl
  25. 0 0
      servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl
  26. 0 0
      servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl
  27. 0 53
      servers/rendering/renderer_rd/shaders/specular_merge.glsl

+ 0 - 1
drivers/gles3/rasterizer_scene_gles3.h

@@ -651,7 +651,6 @@ protected:
 
 	RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
 	bool ssao_half_size = false;
-	bool ssao_using_half_size = false;
 	float ssao_adaptive_target = 0.5;
 	int ssao_blur_passes = 2;
 	float ssao_fadeout_from = 50.0;

+ 106 - 0
servers/rendering/renderer_rd/effects/copy_effects.cpp

@@ -249,6 +249,56 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
 			roughness.raster_pipeline.clear();
 		}
 	}
+
+	{
+		Vector<String> specular_modes;
+		specular_modes.push_back("\n#define MODE_MERGE\n"); // SPECULAR_MERGE_ADD
+		specular_modes.push_back("\n#define MODE_MERGE\n#define MODE_SSR\n"); // SPECULAR_MERGE_SSR
+		specular_modes.push_back("\n"); // SPECULAR_MERGE_ADDITIVE_ADD
+		specular_modes.push_back("\n#define MODE_SSR\n"); // SPECULAR_MERGE_ADDITIVE_SSR
+
+		specular_modes.push_back("\n#define USE_MULTIVIEW\n#define MODE_MERGE\n"); // SPECULAR_MERGE_ADD_MULTIVIEW
+		specular_modes.push_back("\n#define USE_MULTIVIEW\n#define MODE_MERGE\n#define MODE_SSR\n"); // SPECULAR_MERGE_SSR_MULTIVIEW
+		specular_modes.push_back("\n#define USE_MULTIVIEW\n"); // SPECULAR_MERGE_ADDITIVE_ADD_MULTIVIEW
+		specular_modes.push_back("\n#define USE_MULTIVIEW\n#define MODE_SSR\n"); // SPECULAR_MERGE_ADDITIVE_SSR_MULTIVIEW
+
+		specular_merge.shader.initialize(specular_modes);
+
+		if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+			specular_merge.shader.set_variant_enabled(SPECULAR_MERGE_ADD_MULTIVIEW, false);
+			specular_merge.shader.set_variant_enabled(SPECULAR_MERGE_SSR_MULTIVIEW, false);
+			specular_merge.shader.set_variant_enabled(SPECULAR_MERGE_ADDITIVE_ADD_MULTIVIEW, false);
+			specular_merge.shader.set_variant_enabled(SPECULAR_MERGE_ADDITIVE_SSR_MULTIVIEW, false);
+		}
+
+		specular_merge.shader_version = specular_merge.shader.version_create();
+
+		//use additive
+
+		RD::PipelineColorBlendState::Attachment ba;
+		ba.enable_blend = true;
+		ba.src_color_blend_factor = RD::BLEND_FACTOR_ONE;
+		ba.dst_color_blend_factor = RD::BLEND_FACTOR_ONE;
+		ba.src_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+		ba.dst_alpha_blend_factor = RD::BLEND_FACTOR_ONE;
+		ba.color_blend_op = RD::BLEND_OP_ADD;
+		ba.alpha_blend_op = RD::BLEND_OP_ADD;
+
+		RD::PipelineColorBlendState blend_additive;
+		blend_additive.attachments.push_back(ba);
+
+		for (int i = 0; i < SPECULAR_MERGE_MAX; i++) {
+			if (specular_merge.shader.is_variant_enabled(i)) {
+				RD::PipelineColorBlendState blend_state;
+				if (i == SPECULAR_MERGE_ADDITIVE_ADD || i == SPECULAR_MERGE_ADDITIVE_SSR || i == SPECULAR_MERGE_ADDITIVE_ADD_MULTIVIEW || i == SPECULAR_MERGE_ADDITIVE_SSR_MULTIVIEW) {
+					blend_state = blend_additive;
+				} else {
+					blend_state = RD::PipelineColorBlendState::create_disabled();
+				}
+				specular_merge.pipelines[i].setup(specular_merge.shader.version_get_shader(specular_merge.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0);
+			}
+		}
+	}
 }
 
 CopyEffects::~CopyEffects() {
@@ -264,6 +314,8 @@ CopyEffects::~CopyEffects() {
 		roughness.compute_shader.version_free(roughness.shader_version);
 	}
 
+	specular_merge.shader.version_free(specular_merge.shader_version);
+
 	RD::get_singleton()->free(filter.coefficient_buffer);
 
 	if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
@@ -1083,3 +1135,57 @@ void CopyEffects::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_f
 	RD::get_singleton()->draw_list_draw(draw_list, true);
 	RD::get_singleton()->draw_list_end();
 }
+
+void CopyEffects::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection, uint32_t p_view_count) {
+	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+	ERR_FAIL_NULL(uniform_set_cache);
+	MaterialStorage *material_storage = MaterialStorage::get_singleton();
+	ERR_FAIL_NULL(material_storage);
+
+	RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+	RD::get_singleton()->draw_command_begin_label("Merge specular");
+
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, Vector<Color>());
+
+	int mode;
+	if (p_reflection.is_valid()) {
+		if (p_base.is_valid()) {
+			mode = SPECULAR_MERGE_SSR;
+		} else {
+			mode = SPECULAR_MERGE_ADDITIVE_SSR;
+		}
+	} else {
+		if (p_base.is_valid()) {
+			mode = SPECULAR_MERGE_ADD;
+		} else {
+			mode = SPECULAR_MERGE_ADDITIVE_ADD;
+		}
+	}
+
+	if (p_view_count > 1) {
+		mode += SPECULAR_MERGE_ADD_MULTIVIEW;
+	}
+
+	RID shader = specular_merge.shader.version_get_shader(specular_merge.shader_version, mode);
+	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, specular_merge.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+
+	if (p_base.is_valid()) {
+		RD::Uniform u_base(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_base }));
+		RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 2, u_base), 2);
+	}
+
+	RD::Uniform u_specular(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_specular }));
+	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_specular), 0);
+
+	if (p_reflection.is_valid()) {
+		RD::Uniform u_reflection(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_reflection }));
+		RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 1, u_reflection), 1);
+	}
+
+	RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
+	RD::get_singleton()->draw_list_draw(draw_list, true);
+	RD::get_singleton()->draw_list_end();
+
+	RD::get_singleton()->draw_command_end_label();
+}

+ 30 - 0
servers/rendering/renderer_rd/effects/copy_effects.h

@@ -42,6 +42,7 @@
 #include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl.gen.h"
 #include "servers/rendering/renderer_scene_render.h"
 
 #include "servers/rendering_server.h"
@@ -274,6 +275,33 @@ private:
 		PipelineCacheRD raster_pipeline;
 	} roughness;
 
+	// Merge specular
+
+	enum SpecularMergeMode {
+		SPECULAR_MERGE_ADD,
+		SPECULAR_MERGE_SSR,
+		SPECULAR_MERGE_ADDITIVE_ADD,
+		SPECULAR_MERGE_ADDITIVE_SSR,
+
+		SPECULAR_MERGE_ADD_MULTIVIEW,
+		SPECULAR_MERGE_SSR_MULTIVIEW,
+		SPECULAR_MERGE_ADDITIVE_ADD_MULTIVIEW,
+		SPECULAR_MERGE_ADDITIVE_SSR_MULTIVIEW,
+
+		SPECULAR_MERGE_MAX
+	};
+
+	/* Specular merge must be done using raster, rather than compute
+	 * because it must continue the existing color buffer
+	 */
+
+	struct SpecularMerge {
+		SpecularMergeShaderRD shader;
+		RID shader_version;
+		PipelineCacheRD pipelines[SPECULAR_MERGE_MAX];
+
+	} specular_merge;
+
 	static CopyEffects *singleton;
 
 public:
@@ -309,6 +337,8 @@ public:
 
 	void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
 	void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
+
+	void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection, uint32_t p_view_count);
 };
 
 } // namespace RendererRD

+ 1715 - 0
servers/rendering/renderer_rd/effects/ss_effects.cpp

@@ -0,0 +1,1715 @@
+/*************************************************************************/
+/*  ss_effects.cpp                                                       */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#include "ss_effects.h"
+
+#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
+#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+
+using namespace RendererRD;
+
+SSEffects *SSEffects::singleton = nullptr;
+
+static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
+	for (int i = 0; i < 4; i++) {
+		for (int j = 0; j < 4; j++) {
+			p_array[i * 4 + j] = p_mtx.matrix[i][j];
+		}
+	}
+}
+
+SSEffects::SSEffects() {
+	singleton = this;
+
+	{
+		// Initialize depth buffer for screen space effects
+		Vector<String> downsampler_modes;
+		downsampler_modes.push_back("\n");
+		downsampler_modes.push_back("\n#define USE_HALF_SIZE\n");
+		downsampler_modes.push_back("\n#define GENERATE_MIPS\n");
+		downsampler_modes.push_back("\n#define GENERATE_MIPS\n#define USE_HALF_SIZE\n");
+		downsampler_modes.push_back("\n#define USE_HALF_BUFFERS\n");
+		downsampler_modes.push_back("\n#define USE_HALF_BUFFERS\n#define USE_HALF_SIZE\n");
+		downsampler_modes.push_back("\n#define GENERATE_MIPS\n#define GENERATE_FULL_MIPS");
+
+		ss_effects.downsample_shader.initialize(downsampler_modes);
+
+		ss_effects.downsample_shader_version = ss_effects.downsample_shader.version_create();
+
+		for (int i = 0; i < SS_EFFECTS_MAX; i++) {
+			ss_effects.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, i));
+		}
+
+		ss_effects.gather_constants_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSEffectsGatherConstants));
+		SSEffectsGatherConstants gather_constants;
+
+		const int sub_pass_count = 5;
+		for (int pass = 0; pass < 4; pass++) {
+			for (int subPass = 0; subPass < sub_pass_count; subPass++) {
+				int a = pass;
+				int b = subPass;
+
+				int spmap[5]{ 0, 1, 4, 3, 2 };
+				b = spmap[subPass];
+
+				float ca, sa;
+				float angle0 = (float(a) + float(b) / float(sub_pass_count)) * Math_PI * 0.5f;
+
+				ca = Math::cos(angle0);
+				sa = Math::sin(angle0);
+
+				float scale = 1.0f + (a - 1.5f + (b - (sub_pass_count - 1.0f) * 0.5f) / float(sub_pass_count)) * 0.07f;
+
+				gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 0] = scale * ca;
+				gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 1] = scale * -sa;
+				gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 2] = -scale * sa;
+				gather_constants.rotation_matrices[pass * 20 + subPass * 4 + 3] = -scale * ca;
+			}
+		}
+
+		RD::get_singleton()->buffer_update(ss_effects.gather_constants_buffer, 0, sizeof(SSEffectsGatherConstants), &gather_constants);
+	}
+
+	// Initialize Screen Space Indirect Lighting (SSIL)
+
+	{
+		Vector<String> ssil_modes;
+		ssil_modes.push_back("\n");
+		ssil_modes.push_back("\n#define SSIL_BASE\n");
+		ssil_modes.push_back("\n#define ADAPTIVE\n");
+
+		ssil.gather_shader.initialize(ssil_modes);
+
+		ssil.gather_shader_version = ssil.gather_shader.version_create();
+
+		for (int i = SSIL_GATHER; i <= SSIL_GATHER_ADAPTIVE; i++) {
+			ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.gather_shader.version_get_shader(ssil.gather_shader_version, i));
+		}
+		ssil.projection_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(SSILProjectionUniforms));
+	}
+
+	{
+		Vector<String> ssil_modes;
+		ssil_modes.push_back("\n#define GENERATE_MAP\n");
+		ssil_modes.push_back("\n#define PROCESS_MAPA\n");
+		ssil_modes.push_back("\n#define PROCESS_MAPB\n");
+
+		ssil.importance_map_shader.initialize(ssil_modes);
+
+		ssil.importance_map_shader_version = ssil.importance_map_shader.version_create();
+
+		for (int i = SSIL_GENERATE_IMPORTANCE_MAP; i <= SSIL_PROCESS_IMPORTANCE_MAPB; i++) {
+			ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, i - SSIL_GENERATE_IMPORTANCE_MAP));
+		}
+		ssil.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t));
+		int zero[1] = { 0 };
+		RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero);
+		RD::get_singleton()->set_resource_name(ssil.importance_map_load_counter, "Importance Map Load Counter");
+
+		Vector<RD::Uniform> uniforms;
+		{
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+			u.binding = 0;
+			u.append_id(ssil.importance_map_load_counter);
+			uniforms.push_back(u);
+		}
+		ssil.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.importance_map_shader.version_get_shader(ssil.importance_map_shader_version, 2), 2);
+		RD::get_singleton()->set_resource_name(ssil.counter_uniform_set, "Load Counter Uniform Set");
+	}
+
+	{
+		Vector<String> ssil_modes;
+		ssil_modes.push_back("\n#define MODE_NON_SMART\n");
+		ssil_modes.push_back("\n#define MODE_SMART\n");
+		ssil_modes.push_back("\n#define MODE_WIDE\n");
+
+		ssil.blur_shader.initialize(ssil_modes);
+
+		ssil.blur_shader_version = ssil.blur_shader.version_create();
+		for (int i = SSIL_BLUR_PASS; i <= SSIL_BLUR_PASS_WIDE; i++) {
+			ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.blur_shader.version_get_shader(ssil.blur_shader_version, i - SSIL_BLUR_PASS));
+		}
+	}
+
+	{
+		Vector<String> ssil_modes;
+		ssil_modes.push_back("\n#define MODE_NON_SMART\n");
+		ssil_modes.push_back("\n#define MODE_SMART\n");
+		ssil_modes.push_back("\n#define MODE_HALF\n");
+
+		ssil.interleave_shader.initialize(ssil_modes);
+
+		ssil.interleave_shader_version = ssil.interleave_shader.version_create();
+		for (int i = SSIL_INTERLEAVE; i <= SSIL_INTERLEAVE_HALF; i++) {
+			ssil.pipelines[i] = RD::get_singleton()->compute_pipeline_create(ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, i - SSIL_INTERLEAVE));
+		}
+	}
+
+	{
+		// Initialize Screen Space Ambient Occlusion (SSAO)
+
+		RD::SamplerState sampler;
+		sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+		sampler.min_filter = RD::SAMPLER_FILTER_NEAREST;
+		sampler.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+		sampler.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+		sampler.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+		sampler.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+		sampler.max_lod = 4;
+
+		uint32_t pipeline = 0;
+		{
+			Vector<String> ssao_modes;
+
+			ssao_modes.push_back("\n");
+			ssao_modes.push_back("\n#define SSAO_BASE\n");
+			ssao_modes.push_back("\n#define ADAPTIVE\n");
+
+			ssao.gather_shader.initialize(ssao_modes);
+
+			ssao.gather_shader_version = ssao.gather_shader.version_create();
+
+			for (int i = 0; i <= SSAO_GATHER_ADAPTIVE; i++) {
+				ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.gather_shader.version_get_shader(ssao.gather_shader_version, i));
+				pipeline++;
+			}
+		}
+
+		{
+			Vector<String> ssao_modes;
+			ssao_modes.push_back("\n#define GENERATE_MAP\n");
+			ssao_modes.push_back("\n#define PROCESS_MAPA\n");
+			ssao_modes.push_back("\n#define PROCESS_MAPB\n");
+
+			ssao.importance_map_shader.initialize(ssao_modes);
+
+			ssao.importance_map_shader_version = ssao.importance_map_shader.version_create();
+
+			for (int i = SSAO_GENERATE_IMPORTANCE_MAP; i <= SSAO_PROCESS_IMPORTANCE_MAPB; i++) {
+				ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, i - SSAO_GENERATE_IMPORTANCE_MAP));
+
+				pipeline++;
+			}
+
+			ssao.importance_map_load_counter = RD::get_singleton()->storage_buffer_create(sizeof(uint32_t));
+			int zero[1] = { 0 };
+			RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero);
+			RD::get_singleton()->set_resource_name(ssao.importance_map_load_counter, "Importance Map Load Counter");
+
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.binding = 0;
+				u.append_id(ssao.importance_map_load_counter);
+				uniforms.push_back(u);
+			}
+			ssao.counter_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.importance_map_shader.version_get_shader(ssao.importance_map_shader_version, 2), 2);
+			RD::get_singleton()->set_resource_name(ssao.counter_uniform_set, "Load Counter Uniform Set");
+		}
+
+		{
+			Vector<String> ssao_modes;
+			ssao_modes.push_back("\n#define MODE_NON_SMART\n");
+			ssao_modes.push_back("\n#define MODE_SMART\n");
+			ssao_modes.push_back("\n#define MODE_WIDE\n");
+
+			ssao.blur_shader.initialize(ssao_modes);
+
+			ssao.blur_shader_version = ssao.blur_shader.version_create();
+
+			for (int i = SSAO_BLUR_PASS; i <= SSAO_BLUR_PASS_WIDE; i++) {
+				ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.blur_shader.version_get_shader(ssao.blur_shader_version, i - SSAO_BLUR_PASS));
+
+				pipeline++;
+			}
+		}
+
+		{
+			Vector<String> ssao_modes;
+			ssao_modes.push_back("\n#define MODE_NON_SMART\n");
+			ssao_modes.push_back("\n#define MODE_SMART\n");
+			ssao_modes.push_back("\n#define MODE_HALF\n");
+
+			ssao.interleave_shader.initialize(ssao_modes);
+
+			ssao.interleave_shader_version = ssao.interleave_shader.version_create();
+			for (int i = SSAO_INTERLEAVE; i <= SSAO_INTERLEAVE_HALF; i++) {
+				ssao.pipelines[pipeline] = RD::get_singleton()->compute_pipeline_create(ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, i - SSAO_INTERLEAVE));
+				RD::get_singleton()->set_resource_name(ssao.pipelines[pipeline], "Interleave Pipeline " + itos(i));
+				pipeline++;
+			}
+		}
+
+		ERR_FAIL_COND(pipeline != SSAO_MAX);
+
+		ss_effects.mirror_sampler = RD::get_singleton()->sampler_create(sampler);
+	}
+
+	{
+		// Screen Space Reflections
+
+		Vector<RD::PipelineSpecializationConstant> specialization_constants;
+
+		{
+			RD::PipelineSpecializationConstant sc;
+			sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
+			sc.constant_id = 0; // SSR_USE_FULL_PROJECTION_MATRIX
+			sc.bool_value = false;
+			specialization_constants.push_back(sc);
+		}
+
+		{
+			Vector<String> ssr_scale_modes;
+			ssr_scale_modes.push_back("\n");
+
+			ssr_scale.shader.initialize(ssr_scale_modes);
+			ssr_scale.shader_version = ssr_scale.shader.version_create();
+
+			for (int v = 0; v < SSR_VARIATIONS; v++) {
+				specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false;
+				ssr_scale.pipelines[v] = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0), specialization_constants);
+			}
+		}
+
+		{
+			Vector<String> ssr_modes;
+			ssr_modes.push_back("\n"); // SCREEN_SPACE_REFLECTION_NORMAL
+			ssr_modes.push_back("\n#define MODE_ROUGH\n"); // SCREEN_SPACE_REFLECTION_ROUGH
+
+			ssr.shader.initialize(ssr_modes);
+			ssr.shader_version = ssr.shader.version_create();
+
+			for (int v = 0; v < SSR_VARIATIONS; v++) {
+				specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false;
+				for (int i = 0; i < SCREEN_SPACE_REFLECTION_MAX; i++) {
+					ssr.pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(ssr.shader.version_get_shader(ssr.shader_version, i), specialization_constants);
+				}
+			}
+		}
+
+		{
+			Vector<String> ssr_filter_modes;
+			ssr_filter_modes.push_back("\n"); // SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL
+			ssr_filter_modes.push_back("\n#define VERTICAL_PASS\n"); // SCREEN_SPACE_REFLECTION_FILTER_VERTICAL
+
+			ssr_filter.shader.initialize(ssr_filter_modes);
+			ssr_filter.shader_version = ssr_filter.shader.version_create();
+
+			for (int v = 0; v < SSR_VARIATIONS; v++) {
+				specialization_constants.ptrw()[0].bool_value = (v & SSR_MULTIVIEW) ? true : false;
+				for (int i = 0; i < SCREEN_SPACE_REFLECTION_FILTER_MAX; i++) {
+					ssr_filter.pipelines[v][i] = RD::get_singleton()->compute_pipeline_create(ssr_filter.shader.version_get_shader(ssr_filter.shader_version, i), specialization_constants);
+				}
+			}
+		}
+	}
+}
+
+SSEffects::~SSEffects() {
+	{
+		// Cleanup SS Reflections
+		ssr.shader.version_free(ssr.shader_version);
+		ssr_filter.shader.version_free(ssr_filter.shader_version);
+		ssr_scale.shader.version_free(ssr_scale.shader_version);
+
+		if (ssr.ubo.is_valid()) {
+			RD::get_singleton()->free(ssr.ubo);
+		}
+	}
+
+	{
+		// Cleanup SS downsampler
+		ss_effects.downsample_shader.version_free(ss_effects.downsample_shader_version);
+
+		RD::get_singleton()->free(ss_effects.mirror_sampler);
+		RD::get_singleton()->free(ss_effects.gather_constants_buffer);
+	}
+
+	{
+		// Cleanup SSIL
+		ssil.blur_shader.version_free(ssil.blur_shader_version);
+		ssil.gather_shader.version_free(ssil.gather_shader_version);
+		ssil.interleave_shader.version_free(ssil.interleave_shader_version);
+		ssil.importance_map_shader.version_free(ssil.importance_map_shader_version);
+
+		RD::get_singleton()->free(ssil.importance_map_load_counter);
+		RD::get_singleton()->free(ssil.projection_uniform_buffer);
+	}
+
+	{
+		// Cleanup SSAO
+		ssao.blur_shader.version_free(ssao.blur_shader_version);
+		ssao.gather_shader.version_free(ssao.gather_shader_version);
+		ssao.interleave_shader.version_free(ssao.interleave_shader_version);
+		ssao.importance_map_shader.version_free(ssao.importance_map_shader_version);
+
+		RD::get_singleton()->free(ssao.importance_map_load_counter);
+	}
+
+	singleton = nullptr;
+}
+
+/* SS Downsampler */
+
+void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const CameraMatrix &p_projection) {
+	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+	ERR_FAIL_NULL(uniform_set_cache);
+	MaterialStorage *material_storage = MaterialStorage::get_singleton();
+	ERR_FAIL_NULL(material_storage);
+
+	// Downsample and deinterleave the depth buffer for SSAO and SSIL
+	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+	int downsample_mode = SS_EFFECTS_DOWNSAMPLE;
+	bool use_mips = p_ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || p_ssil_quality > RS::ENV_SSIL_QUALITY_MEDIUM;
+
+	if (p_ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && p_ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+		downsample_mode = SS_EFFECTS_DOWNSAMPLE_HALF;
+	} else if (use_mips) {
+		downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP;
+	}
+
+	bool use_half_size = false;
+	bool use_full_mips = false;
+
+	if (p_ssao_half_size && p_ssil_half_size) {
+		downsample_mode++;
+		use_half_size = true;
+	} else if (p_ssao_half_size != p_ssil_half_size) {
+		if (use_mips) {
+			downsample_mode = SS_EFFECTS_DOWNSAMPLE_FULL_MIPS;
+			use_full_mips = true;
+		} else {
+			// Only need the first two mipmaps, but the cost to generate the next two is trivial
+			// TODO investigate the benefit of a shader version to generate only 2 mips
+			downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP;
+			use_mips = true;
+		}
+	}
+
+	int depth_index = use_half_size ? 1 : 0;
+
+	RD::get_singleton()->draw_command_begin_label("Downsample Depth");
+	if (p_invalidate_uniform_set || use_full_mips != ss_effects.used_full_mips_last_frame || use_half_size != ss_effects.used_half_size_last_frame || use_mips != ss_effects.used_mips_last_frame) {
+		Vector<RD::Uniform> uniforms;
+		{
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+			u.binding = 0;
+			u.append_id(p_depth_mipmaps[depth_index + 1]);
+			uniforms.push_back(u);
+		}
+		{
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+			u.binding = 1;
+			u.append_id(p_depth_mipmaps[depth_index + 2]);
+			uniforms.push_back(u);
+		}
+		{
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+			u.binding = 2;
+			u.append_id(p_depth_mipmaps[depth_index + 3]);
+			uniforms.push_back(u);
+		}
+		if (use_full_mips) {
+			RD::Uniform u;
+			u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+			u.binding = 3;
+			u.append_id(p_depth_mipmaps[4]);
+			uniforms.push_back(u);
+		}
+		ss_effects.downsample_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, use_full_mips ? 6 : 2), 2);
+	}
+
+	float depth_linearize_mul = -p_projection.matrix[3][2];
+	float depth_linearize_add = p_projection.matrix[2][2];
+	if (depth_linearize_mul * depth_linearize_add < 0) {
+		depth_linearize_add = -depth_linearize_add;
+	}
+
+	ss_effects.downsample_push_constant.orthogonal = p_projection.is_orthogonal();
+	ss_effects.downsample_push_constant.z_near = depth_linearize_mul;
+	ss_effects.downsample_push_constant.z_far = depth_linearize_add;
+	if (ss_effects.downsample_push_constant.orthogonal) {
+		ss_effects.downsample_push_constant.z_near = p_projection.get_z_near();
+		ss_effects.downsample_push_constant.z_far = p_projection.get_z_far();
+	}
+	ss_effects.downsample_push_constant.pixel_size[0] = 1.0 / p_full_screen_size.x;
+	ss_effects.downsample_push_constant.pixel_size[1] = 1.0 / p_full_screen_size.y;
+	ss_effects.downsample_push_constant.radius_sq = 1.0;
+
+	RID shader = ss_effects.downsample_shader.version_get_shader(ss_effects.downsample_shader_version, downsample_mode);
+	RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+	RD::Uniform u_depth_buffer(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_depth_buffer }));
+	RD::Uniform u_depth_mipmaps(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_depth_mipmaps[depth_index + 0] }));
+
+	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ss_effects.pipelines[downsample_mode]);
+	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_depth_buffer), 0);
+	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth_mipmaps), 1);
+	if (use_mips) {
+		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ss_effects.downsample_uniform_set, 2);
+	}
+	RD::get_singleton()->compute_list_set_push_constant(compute_list, &ss_effects.downsample_push_constant, sizeof(SSEffectsDownsamplePushConstant));
+
+	Size2i size(MAX(1, p_full_screen_size.x >> (use_half_size ? 2 : 1)), MAX(1, p_full_screen_size.y >> (use_half_size ? 2 : 1)));
+
+	RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1);
+	RD::get_singleton()->compute_list_add_barrier(compute_list);
+	RD::get_singleton()->draw_command_end_label();
+
+	RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_COMPUTE);
+
+	ss_effects.used_full_mips_last_frame = use_full_mips;
+	ss_effects.used_half_size_last_frame = use_half_size;
+}
+
+/* SSIL */
+
+void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set) {
+	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+	ERR_FAIL_NULL(uniform_set_cache);
+
+	RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0);
+	if ((p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) && !p_adaptive_base_pass) {
+		RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 1);
+	}
+	RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_projection_uniform_set, 3);
+
+	RID shader = ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0);
+
+	for (int i = 0; i < 4; i++) {
+		if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+			continue;
+		}
+
+		RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_slices[i] }));
+		RD::Uniform u_edges_slice(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_edges_slices[i] }));
+
+		ssil.gather_push_constant.pass_coord_offset[0] = i % 2;
+		ssil.gather_push_constant.pass_coord_offset[1] = i / 2;
+		ssil.gather_push_constant.pass_uv_offset[0] = ((i % 2) - 0.0) / p_settings.full_screen_size.x;
+		ssil.gather_push_constant.pass_uv_offset[1] = ((i / 2) - 0.0) / p_settings.full_screen_size.y;
+		ssil.gather_push_constant.pass = i;
+		RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, uniform_set_cache->get_cache(shader, 2, u_ssil_slice, u_edges_slice), 2);
+		RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssil.gather_push_constant, sizeof(SSILGatherPushConstant));
+
+		Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1));
+
+		RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1);
+	}
+	RD::get_singleton()->compute_list_add_barrier(p_compute_list);
+}
+
+void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const SSILSettings &p_settings, RID p_linear_depth) {
+	if (p_ssil_buffers.half_size != p_settings.half_size) {
+		ssil_free(p_ssil_buffers);
+	}
+
+	if (p_settings.half_size) {
+		p_ssil_buffers.buffer_width = (p_settings.full_screen_size.x + 3) / 4;
+		p_ssil_buffers.buffer_height = (p_settings.full_screen_size.y + 3) / 4;
+		p_ssil_buffers.half_buffer_width = (p_settings.full_screen_size.x + 7) / 8;
+		p_ssil_buffers.half_buffer_height = (p_settings.full_screen_size.y + 7) / 8;
+	} else {
+		p_ssil_buffers.buffer_width = (p_settings.full_screen_size.x + 1) / 2;
+		p_ssil_buffers.buffer_height = (p_settings.full_screen_size.y + 1) / 2;
+		p_ssil_buffers.half_buffer_width = (p_settings.full_screen_size.x + 3) / 4;
+		p_ssil_buffers.half_buffer_height = (p_settings.full_screen_size.y + 3) / 4;
+	}
+
+	if (p_ssil_buffers.ssil_final.is_null()) {
+		{
+			p_ssil_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, p_settings.half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
+		}
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+			tf.width = p_settings.full_screen_size.x;
+			tf.height = p_settings.full_screen_size.y;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
+			p_ssil_buffers.ssil_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssil_buffers.ssil_final, "SSIL texture");
+			RD::get_singleton()->texture_clear(p_ssil_buffers.ssil_final, Color(0, 0, 0, 0), 0, 1, 0, 1);
+			if (p_ssil_buffers.last_frame.is_null()) {
+				tf.mipmaps = 6;
+				p_ssil_buffers.last_frame = RD::get_singleton()->texture_create(tf, RD::TextureView());
+				RD::get_singleton()->set_resource_name(p_ssil_buffers.last_frame, "Last Frame Radiance");
+				RD::get_singleton()->texture_clear(p_ssil_buffers.last_frame, Color(0, 0, 0, 0), 0, tf.mipmaps, 0, 1);
+				for (uint32_t i = 0; i < 6; i++) {
+					RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_ssil_buffers.last_frame, 0, i);
+					p_ssil_buffers.last_frame_slices.push_back(slice);
+					RD::get_singleton()->set_resource_name(slice, "Last Frame Radiance Mip " + itos(i) + " ");
+				}
+			}
+		}
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+			tf.width = p_ssil_buffers.buffer_width;
+			tf.height = p_ssil_buffers.buffer_height;
+			tf.array_layers = 4;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+			p_ssil_buffers.deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssil_buffers.deinterleaved, "SSIL deinterleaved buffer");
+			for (uint32_t i = 0; i < 4; i++) {
+				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_ssil_buffers.deinterleaved, i, 0);
+				p_ssil_buffers.deinterleaved_slices.push_back(slice);
+				RD::get_singleton()->set_resource_name(slice, "SSIL deinterleaved buffer array " + itos(i) + " ");
+			}
+		}
+
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+			tf.width = p_ssil_buffers.buffer_width;
+			tf.height = p_ssil_buffers.buffer_height;
+			tf.array_layers = 4;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+			p_ssil_buffers.pong = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssil_buffers.pong, "SSIL deinterleaved pong buffer");
+			for (uint32_t i = 0; i < 4; i++) {
+				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_ssil_buffers.pong, i, 0);
+				p_ssil_buffers.pong_slices.push_back(slice);
+				RD::get_singleton()->set_resource_name(slice, "SSIL deinterleaved buffer pong array " + itos(i) + " ");
+			}
+		}
+
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R8_UNORM;
+			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+			tf.width = p_ssil_buffers.buffer_width;
+			tf.height = p_ssil_buffers.buffer_height;
+			tf.array_layers = 4;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+			p_ssil_buffers.edges = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssil_buffers.edges, "SSIL edges buffer");
+			for (uint32_t i = 0; i < 4; i++) {
+				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_ssil_buffers.edges, i, 0);
+				p_ssil_buffers.edges_slices.push_back(slice);
+				RD::get_singleton()->set_resource_name(slice, "SSIL edges buffer slice " + itos(i) + " ");
+			}
+		}
+
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R8_UNORM;
+			tf.width = p_ssil_buffers.half_buffer_width;
+			tf.height = p_ssil_buffers.half_buffer_height;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+			p_ssil_buffers.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssil_buffers.importance_map[0], "SSIL Importance Map");
+			p_ssil_buffers.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssil_buffers.importance_map[1], "SSIL Importance Map Pong");
+		}
+		p_ssil_buffers.half_size = p_settings.half_size;
+	}
+}
+
+void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers, RID p_normal_buffer, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings) {
+	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+	ERR_FAIL_NULL(uniform_set_cache);
+	MaterialStorage *material_storage = MaterialStorage::get_singleton();
+	ERR_FAIL_NULL(material_storage);
+
+	RD::get_singleton()->draw_command_begin_label("Process Screen Space Indirect Lighting");
+	//Store projection info before starting the compute list
+	SSILProjectionUniforms projection_uniforms;
+	store_camera(p_last_projection, projection_uniforms.inv_last_frame_projection_matrix);
+
+	RD::get_singleton()->buffer_update(ssil.projection_uniform_buffer, 0, sizeof(SSILProjectionUniforms), &projection_uniforms);
+
+	memset(&ssil.gather_push_constant, 0, sizeof(SSILGatherPushConstant));
+
+	RID shader = ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0);
+	RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+	RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+	{
+		RD::get_singleton()->draw_command_begin_label("Gather Samples");
+		ssil.gather_push_constant.screen_size[0] = p_settings.full_screen_size.x;
+		ssil.gather_push_constant.screen_size[1] = p_settings.full_screen_size.y;
+
+		ssil.gather_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width;
+		ssil.gather_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height;
+		float tan_half_fov_x = 1.0 / p_projection.matrix[0][0];
+		float tan_half_fov_y = 1.0 / p_projection.matrix[1][1];
+		ssil.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0;
+		ssil.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0;
+		ssil.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0;
+		ssil.gather_push_constant.NDC_to_view_add[1] = tan_half_fov_y;
+		ssil.gather_push_constant.z_near = p_projection.get_z_near();
+		ssil.gather_push_constant.z_far = p_projection.get_z_far();
+		ssil.gather_push_constant.is_orthogonal = p_projection.is_orthogonal();
+
+		ssil.gather_push_constant.half_screen_pixel_size_x025[0] = ssil.gather_push_constant.half_screen_pixel_size[0] * 0.25;
+		ssil.gather_push_constant.half_screen_pixel_size_x025[1] = ssil.gather_push_constant.half_screen_pixel_size[1] * 0.25;
+
+		ssil.gather_push_constant.radius = p_settings.radius;
+		float radius_near_limit = (p_settings.radius * 1.2f);
+		if (p_settings.quality <= RS::ENV_SSIL_QUALITY_LOW) {
+			radius_near_limit *= 1.50f;
+
+			if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+				ssil.gather_push_constant.radius *= 0.8f;
+			}
+		}
+		radius_near_limit /= tan_half_fov_y;
+		ssil.gather_push_constant.intensity = p_settings.intensity * Math_PI;
+		ssil.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from);
+		ssil.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0;
+		ssil.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit;
+		ssil.gather_push_constant.neg_inv_radius = -1.0 / ssil.gather_push_constant.radius;
+		ssil.gather_push_constant.normal_rejection_amount = p_settings.normal_rejection;
+
+		ssil.gather_push_constant.load_counter_avg_div = 9.0 / float((p_ssil_buffers.half_buffer_width) * (p_ssil_buffers.half_buffer_height) * 255);
+		ssil.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target;
+
+		ssil.gather_push_constant.quality = MAX(0, p_settings.quality - 1);
+		ssil.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1;
+
+		if (p_ssil_buffers.projection_uniform_set.is_null()) {
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+				u.binding = 0;
+				u.append_id(default_mipmap_sampler);
+				u.append_id(p_ssil_buffers.last_frame);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+				u.binding = 1;
+				u.append_id(ssil.projection_uniform_buffer);
+				uniforms.push_back(u);
+			}
+			p_ssil_buffers.projection_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0), 3);
+		}
+
+		if (p_ssil_buffers.gather_uniform_set.is_null()) {
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+				u.binding = 0;
+				u.append_id(default_sampler);
+				u.append_id(p_ssil_buffers.depth_texture_view);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+				u.binding = 1;
+				u.append_id(p_normal_buffer);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+				u.binding = 2;
+				u.append_id(ss_effects.gather_constants_buffer);
+				uniforms.push_back(u);
+			}
+			p_ssil_buffers.gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 0), 0);
+		}
+
+		if (p_ssil_buffers.importance_map_uniform_set.is_null()) {
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+				u.binding = 0;
+				u.append_id(p_ssil_buffers.pong);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+				u.binding = 1;
+				u.append_id(default_sampler);
+				u.append_id(p_ssil_buffers.importance_map[0]);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.binding = 2;
+				u.append_id(ssil.importance_map_load_counter);
+				uniforms.push_back(u);
+			}
+			p_ssil_buffers.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssil.gather_shader.version_get_shader(ssil.gather_shader_version, 2), 1);
+		}
+
+		if (p_settings.quality == RS::ENV_SSIL_QUALITY_ULTRA) {
+			RD::get_singleton()->draw_command_begin_label("Generate Importance Map");
+			ssil.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width;
+			ssil.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height;
+			ssil.importance_map_push_constant.intensity = p_settings.intensity * Math_PI;
+			//base pass
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_BASE]);
+			gather_ssil(compute_list, p_ssil_buffers.pong_slices, p_ssil_buffers.edges_slices, p_settings, true, p_ssil_buffers.gather_uniform_set, p_ssil_buffers.importance_map_uniform_set, p_ssil_buffers.projection_uniform_set);
+
+			//generate importance map
+			RD::Uniform u_ssil_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.pong }));
+			RD::Uniform u_importance_map(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.importance_map[0] }));
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GENERATE_IMPORTANCE_MAP]);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_pong_with_sampler), 0);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_importance_map), 1);
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssil_buffers.half_buffer_width, p_ssil_buffers.half_buffer_height, 1);
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			// process Importance Map A
+			RD::Uniform u_importance_map_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.importance_map[0] }));
+			RD::Uniform u_importance_map_pong(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.importance_map[1] }));
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPA]);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_importance_map_with_sampler), 0);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_importance_map_pong), 1);
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssil_buffers.half_buffer_width, p_ssil_buffers.half_buffer_height, 1);
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			// process Importance Map B
+			RD::Uniform u_importance_map_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.importance_map[1] }));
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_PROCESS_IMPORTANCE_MAPB]);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_importance_map_pong_with_sampler), 0);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_importance_map), 1);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssil.counter_uniform_set, 2);
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.importance_map_push_constant, sizeof(SSILImportanceMapPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssil_buffers.half_buffer_width, p_ssil_buffers.half_buffer_height, 1);
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			RD::get_singleton()->draw_command_end_label(); // Importance Map
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER_ADAPTIVE]);
+		} else {
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[SSIL_GATHER]);
+		}
+
+		gather_ssil(compute_list, p_ssil_buffers.deinterleaved_slices, p_ssil_buffers.edges_slices, p_settings, false, p_ssil_buffers.gather_uniform_set, p_ssil_buffers.importance_map_uniform_set, p_ssil_buffers.projection_uniform_set);
+		RD::get_singleton()->draw_command_end_label(); //Gather
+	}
+
+	{
+		RD::get_singleton()->draw_command_begin_label("Edge Aware Blur");
+		ssil.blur_push_constant.edge_sharpness = 1.0 - p_settings.sharpness;
+		ssil.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssil_buffers.buffer_width;
+		ssil.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssil_buffers.buffer_height;
+
+		int blur_passes = p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? p_settings.blur_passes : 1;
+
+		shader = ssil.blur_shader.version_get_shader(ssil.blur_shader_version, 0);
+
+		for (int pass = 0; pass < blur_passes; pass++) {
+			int blur_pipeline = SSIL_BLUR_PASS;
+			if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) {
+				blur_pipeline = SSIL_BLUR_PASS_SMART;
+				if (pass < blur_passes - 2) {
+					blur_pipeline = SSIL_BLUR_PASS_WIDE;
+				}
+			}
+
+			for (int i = 0; i < 4; i++) {
+				if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+					continue;
+				}
+
+				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[blur_pipeline]);
+				if (pass % 2 == 0) {
+					if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+						RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.deinterleaved_slices[i] }));
+						RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_slice), 0);
+					} else {
+						RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ ss_effects.mirror_sampler, p_ssil_buffers.deinterleaved_slices[i] }));
+						RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_slice), 0);
+					}
+
+					RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.pong_slices[i] }));
+					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil_pong_slice), 1);
+				} else {
+					if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+						RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.pong_slices[i] }));
+						RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_pong_slice), 0);
+					} else {
+						RD::Uniform u_ssil_pong_slice(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ ss_effects.mirror_sampler, p_ssil_buffers.pong_slices[i] }));
+						RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ssil_pong_slice), 0);
+					}
+
+					RD::Uniform u_ssil_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.deinterleaved_slices[i] }));
+					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil_slice), 1);
+				}
+
+				RD::Uniform u_edges_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.edges_slices[i] }));
+				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_edges_slice), 2);
+
+				RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.blur_push_constant, sizeof(SSILBlurPushConstant));
+
+				int x_groups = (p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1));
+				int y_groups = (p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1));
+
+				RD::get_singleton()->compute_list_dispatch_threads(compute_list, x_groups, y_groups, 1);
+				if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW) {
+					RD::get_singleton()->compute_list_add_barrier(compute_list);
+				}
+			}
+		}
+
+		RD::get_singleton()->draw_command_end_label(); // Blur
+	}
+
+	{
+		RD::get_singleton()->draw_command_begin_label("Interleave Buffers");
+		ssil.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness;
+		ssil.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x;
+		ssil.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y;
+		ssil.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2);
+
+		int interleave_pipeline = SSIL_INTERLEAVE_HALF;
+		if (p_settings.quality == RS::ENV_SSIL_QUALITY_LOW) {
+			interleave_pipeline = SSIL_INTERLEAVE;
+		} else if (p_settings.quality >= RS::ENV_SSIL_QUALITY_MEDIUM) {
+			interleave_pipeline = SSIL_INTERLEAVE_SMART;
+		}
+
+		shader = ssil.interleave_shader.version_get_shader(ssil.interleave_shader_version, 0);
+
+		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssil.pipelines[interleave_pipeline]);
+
+		RD::Uniform u_destination(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.ssil_final }));
+		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_destination), 0);
+
+		if (p_settings.quality > RS::ENV_SSIL_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) {
+			RD::Uniform u_ssil(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.deinterleaved }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil), 1);
+		} else {
+			RD::Uniform u_ssil_pong(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssil_buffers.pong }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ssil_pong), 1);
+		}
+
+		RD::Uniform u_edges(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssil_buffers.edges }));
+		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_edges), 2);
+
+		RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssil.interleave_push_constant, sizeof(SSILInterleavePushConstant));
+
+		RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.full_screen_size.x, p_settings.full_screen_size.y, 1);
+		RD::get_singleton()->compute_list_add_barrier(compute_list);
+		RD::get_singleton()->draw_command_end_label(); // Interleave
+	}
+
+	RD::get_singleton()->draw_command_end_label(); // SSIL
+
+	RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER);
+
+	int zero[1] = { 0 };
+	RD::get_singleton()->buffer_update(ssil.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier
+}
+
+void SSEffects::ssil_free(SSILRenderBuffers &p_ssil_buffers) {
+	if (p_ssil_buffers.ssil_final.is_valid()) {
+		RD::get_singleton()->free(p_ssil_buffers.ssil_final);
+		RD::get_singleton()->free(p_ssil_buffers.deinterleaved);
+		RD::get_singleton()->free(p_ssil_buffers.pong);
+		RD::get_singleton()->free(p_ssil_buffers.edges);
+		RD::get_singleton()->free(p_ssil_buffers.importance_map[0]);
+		RD::get_singleton()->free(p_ssil_buffers.importance_map[1]);
+		RD::get_singleton()->free(p_ssil_buffers.last_frame);
+
+		p_ssil_buffers.ssil_final = RID();
+		p_ssil_buffers.deinterleaved = RID();
+		p_ssil_buffers.pong = RID();
+		p_ssil_buffers.edges = RID();
+		p_ssil_buffers.deinterleaved_slices.clear();
+		p_ssil_buffers.pong_slices.clear();
+		p_ssil_buffers.edges_slices.clear();
+		p_ssil_buffers.importance_map[0] = RID();
+		p_ssil_buffers.importance_map[1] = RID();
+		p_ssil_buffers.last_frame = RID();
+		p_ssil_buffers.last_frame_slices.clear();
+
+		p_ssil_buffers.gather_uniform_set = RID();
+		p_ssil_buffers.importance_map_uniform_set = RID();
+		p_ssil_buffers.projection_uniform_set = RID();
+	}
+}
+
+/* SSAO */
+
+void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set) {
+	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+	ERR_FAIL_NULL(uniform_set_cache);
+
+	RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_gather_uniform_set, 0);
+	if ((p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) && !p_adaptive_base_pass) {
+		RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, p_importance_map_uniform_set, 0);
+	}
+
+	RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 1); //
+
+	for (int i = 0; i < 4; i++) {
+		if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+			continue;
+		}
+
+		RD::Uniform u_ao_slice(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ao_slices[i] }));
+
+		ssao.gather_push_constant.pass_coord_offset[0] = i % 2;
+		ssao.gather_push_constant.pass_coord_offset[1] = i / 2;
+		ssao.gather_push_constant.pass_uv_offset[0] = ((i % 2) - 0.0) / p_settings.full_screen_size.x;
+		ssao.gather_push_constant.pass_uv_offset[1] = ((i / 2) - 0.0) / p_settings.full_screen_size.y;
+		ssao.gather_push_constant.pass = i;
+		RD::get_singleton()->compute_list_bind_uniform_set(p_compute_list, uniform_set_cache->get_cache(shader, 2, u_ao_slice), 2);
+		RD::get_singleton()->compute_list_set_push_constant(p_compute_list, &ssao.gather_push_constant, sizeof(SSAOGatherPushConstant));
+
+		Size2i size = Size2i(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1));
+
+		RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1);
+	}
+	RD::get_singleton()->compute_list_add_barrier(p_compute_list);
+}
+
+void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const SSAOSettings &p_settings, RID p_linear_depth) {
+	if (p_ssao_buffers.half_size != p_settings.half_size) {
+		ssao_free(p_ssao_buffers);
+	}
+
+	if (p_settings.half_size) {
+		p_ssao_buffers.buffer_width = (p_settings.full_screen_size.x + 3) / 4;
+		p_ssao_buffers.buffer_height = (p_settings.full_screen_size.y + 3) / 4;
+		p_ssao_buffers.half_buffer_width = (p_settings.full_screen_size.x + 7) / 8;
+		p_ssao_buffers.half_buffer_height = (p_settings.full_screen_size.y + 7) / 8;
+	} else {
+		p_ssao_buffers.buffer_width = (p_settings.full_screen_size.x + 1) / 2;
+		p_ssao_buffers.buffer_height = (p_settings.full_screen_size.y + 1) / 2;
+		p_ssao_buffers.half_buffer_width = (p_settings.full_screen_size.x + 3) / 4;
+		p_ssao_buffers.half_buffer_height = (p_settings.full_screen_size.y + 3) / 4;
+	}
+
+	if (p_ssao_buffers.ao_deinterleaved.is_null()) {
+		{
+			p_ssao_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, p_settings.half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
+		}
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R8G8_UNORM;
+			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+			tf.width = p_ssao_buffers.buffer_width;
+			tf.height = p_ssao_buffers.buffer_height;
+			tf.array_layers = 4;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+			p_ssao_buffers.ao_deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssao_buffers.ao_deinterleaved, "SSAO De-interleaved Array");
+			for (uint32_t i = 0; i < 4; i++) {
+				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_ssao_buffers.ao_deinterleaved, i, 0);
+				p_ssao_buffers.ao_deinterleaved_slices.push_back(slice);
+				RD::get_singleton()->set_resource_name(slice, "SSAO De-interleaved Array Layer " + itos(i) + " ");
+			}
+		}
+
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R8G8_UNORM;
+			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+			tf.width = p_ssao_buffers.buffer_width;
+			tf.height = p_ssao_buffers.buffer_height;
+			tf.array_layers = 4;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+			p_ssao_buffers.ao_pong = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssao_buffers.ao_pong, "SSAO De-interleaved Array Pong");
+			for (uint32_t i = 0; i < 4; i++) {
+				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_ssao_buffers.ao_pong, i, 0);
+				p_ssao_buffers.ao_pong_slices.push_back(slice);
+				RD::get_singleton()->set_resource_name(slice, "SSAO De-interleaved Array Layer " + itos(i) + " Pong");
+			}
+		}
+
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R8_UNORM;
+			tf.width = p_ssao_buffers.buffer_width;
+			tf.height = p_ssao_buffers.buffer_height;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+			p_ssao_buffers.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssao_buffers.importance_map[0], "SSAO Importance Map");
+			p_ssao_buffers.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssao_buffers.importance_map[1], "SSAO Importance Map Pong");
+		}
+		{
+			RD::TextureFormat tf;
+			tf.format = RD::DATA_FORMAT_R8_UNORM;
+			tf.width = p_settings.full_screen_size.x;
+			tf.height = p_settings.full_screen_size.y;
+			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+			p_ssao_buffers.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
+			RD::get_singleton()->set_resource_name(p_ssao_buffers.ao_final, "SSAO Final");
+		}
+		p_ssao_buffers.half_size = p_settings.half_size;
+	}
+}
+
+void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_buffer, const CameraMatrix &p_projection, const SSAOSettings &p_settings) {
+	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+	ERR_FAIL_NULL(uniform_set_cache);
+	MaterialStorage *material_storage = MaterialStorage::get_singleton();
+	ERR_FAIL_NULL(material_storage);
+
+	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+	memset(&ssao.gather_push_constant, 0, sizeof(SSAOGatherPushConstant));
+	/* FIRST PASS */
+
+	RID shader = ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 0);
+	RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+	RD::get_singleton()->draw_command_begin_label("Process Screen Space Ambient Occlusion");
+	/* SECOND PASS */
+	// Sample SSAO
+	{
+		RD::get_singleton()->draw_command_begin_label("Gather Samples");
+		ssao.gather_push_constant.screen_size[0] = p_settings.full_screen_size.x;
+		ssao.gather_push_constant.screen_size[1] = p_settings.full_screen_size.y;
+
+		ssao.gather_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width;
+		ssao.gather_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height;
+		float tan_half_fov_x = 1.0 / p_projection.matrix[0][0];
+		float tan_half_fov_y = 1.0 / p_projection.matrix[1][1];
+		ssao.gather_push_constant.NDC_to_view_mul[0] = tan_half_fov_x * 2.0;
+		ssao.gather_push_constant.NDC_to_view_mul[1] = tan_half_fov_y * -2.0;
+		ssao.gather_push_constant.NDC_to_view_add[0] = tan_half_fov_x * -1.0;
+		ssao.gather_push_constant.NDC_to_view_add[1] = tan_half_fov_y;
+		ssao.gather_push_constant.is_orthogonal = p_projection.is_orthogonal();
+
+		ssao.gather_push_constant.half_screen_pixel_size_x025[0] = ssao.gather_push_constant.half_screen_pixel_size[0] * 0.25;
+		ssao.gather_push_constant.half_screen_pixel_size_x025[1] = ssao.gather_push_constant.half_screen_pixel_size[1] * 0.25;
+
+		ssao.gather_push_constant.radius = p_settings.radius;
+		float radius_near_limit = (p_settings.radius * 1.2f);
+		if (p_settings.quality <= RS::ENV_SSAO_QUALITY_LOW) {
+			radius_near_limit *= 1.50f;
+
+			if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
+				ssao.gather_push_constant.radius *= 0.8f;
+			}
+		}
+		radius_near_limit /= tan_half_fov_y;
+		ssao.gather_push_constant.intensity = p_settings.intensity;
+		ssao.gather_push_constant.shadow_power = p_settings.power;
+		ssao.gather_push_constant.shadow_clamp = 0.98;
+		ssao.gather_push_constant.fade_out_mul = -1.0 / (p_settings.fadeout_to - p_settings.fadeout_from);
+		ssao.gather_push_constant.fade_out_add = p_settings.fadeout_from / (p_settings.fadeout_to - p_settings.fadeout_from) + 1.0;
+		ssao.gather_push_constant.horizon_angle_threshold = p_settings.horizon;
+		ssao.gather_push_constant.inv_radius_near_limit = 1.0f / radius_near_limit;
+		ssao.gather_push_constant.neg_inv_radius = -1.0 / ssao.gather_push_constant.radius;
+
+		ssao.gather_push_constant.load_counter_avg_div = 9.0 / float((p_ssao_buffers.half_buffer_width) * (p_ssao_buffers.half_buffer_height) * 255);
+		ssao.gather_push_constant.adaptive_sample_limit = p_settings.adaptive_target;
+
+		ssao.gather_push_constant.detail_intensity = p_settings.detail;
+		ssao.gather_push_constant.quality = MAX(0, p_settings.quality - 1);
+		ssao.gather_push_constant.size_multiplier = p_settings.half_size ? 2 : 1;
+
+		if (p_ssao_buffers.gather_uniform_set.is_null()) {
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+				u.binding = 0;
+				u.append_id(default_sampler);
+				u.append_id(p_ssao_buffers.depth_texture_view);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+				u.binding = 1;
+				u.append_id(p_normal_buffer);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+				u.binding = 2;
+				u.append_id(ss_effects.gather_constants_buffer);
+				uniforms.push_back(u);
+			}
+			p_ssao_buffers.gather_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader, 0);
+			RD::get_singleton()->set_resource_name(p_ssao_buffers.gather_uniform_set, "SSAO Gather Uniform Set");
+		}
+
+		if (p_ssao_buffers.importance_map_uniform_set.is_null()) {
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+				u.binding = 0;
+				u.append_id(p_ssao_buffers.ao_pong);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE;
+				u.binding = 1;
+				u.append_id(default_sampler);
+				u.append_id(p_ssao_buffers.importance_map[0]);
+				uniforms.push_back(u);
+			}
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.binding = 2;
+				u.append_id(ssao.importance_map_load_counter);
+				uniforms.push_back(u);
+			}
+			p_ssao_buffers.importance_map_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, ssao.gather_shader.version_get_shader(ssao.gather_shader_version, 2), 1);
+			RD::get_singleton()->set_resource_name(p_ssao_buffers.importance_map_uniform_set, "SSAO Importance Map Uniform Set");
+		}
+
+		if (p_settings.quality == RS::ENV_SSAO_QUALITY_ULTRA) {
+			RD::get_singleton()->draw_command_begin_label("Generate Importance Map");
+			ssao.importance_map_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width;
+			ssao.importance_map_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height;
+			ssao.importance_map_push_constant.intensity = p_settings.intensity;
+			ssao.importance_map_push_constant.power = p_settings.power;
+
+			//base pass
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_BASE]);
+			gather_ssao(compute_list, p_ssao_buffers.ao_pong_slices, p_settings, true, p_ssao_buffers.gather_uniform_set, RID());
+
+			//generate importance map
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GENERATE_IMPORTANCE_MAP]);
+
+			RD::Uniform u_ao_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_pong }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_pong_with_sampler), 0);
+
+			RD::Uniform u_importance_map(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.importance_map[0] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_importance_map), 1);
+
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.half_buffer_width, p_ssao_buffers.half_buffer_height, 1);
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			//process importance map A
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPA]);
+
+			RD::Uniform u_importance_map_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.importance_map[0] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_importance_map_with_sampler), 0);
+
+			RD::Uniform u_importance_map_pong(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.importance_map[1] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_importance_map_pong), 1);
+
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.half_buffer_width, p_ssao_buffers.half_buffer_height, 1);
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			//process Importance Map B
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_PROCESS_IMPORTANCE_MAPB]);
+
+			RD::Uniform u_importance_map_pong_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.importance_map[1] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_importance_map_pong_with_sampler), 0);
+
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_importance_map), 1);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, ssao.counter_uniform_set, 2);
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.importance_map_push_constant, sizeof(SSAOImportanceMapPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_ssao_buffers.half_buffer_width, p_ssao_buffers.half_buffer_height, 1);
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER_ADAPTIVE]);
+			RD::get_singleton()->draw_command_end_label(); // Importance Map
+		} else {
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[SSAO_GATHER]);
+		}
+
+		gather_ssao(compute_list, p_ssao_buffers.ao_deinterleaved_slices, p_settings, false, p_ssao_buffers.gather_uniform_set, p_ssao_buffers.importance_map_uniform_set);
+		RD::get_singleton()->draw_command_end_label(); // Gather SSAO
+	}
+
+	//	/* THIRD PASS */
+	//	// Blur
+	//
+	{
+		RD::get_singleton()->draw_command_begin_label("Edge Aware Blur");
+		ssao.blur_push_constant.edge_sharpness = 1.0 - p_settings.sharpness;
+		ssao.blur_push_constant.half_screen_pixel_size[0] = 1.0 / p_ssao_buffers.buffer_width;
+		ssao.blur_push_constant.half_screen_pixel_size[1] = 1.0 / p_ssao_buffers.buffer_height;
+
+		int blur_passes = p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? p_settings.blur_passes : 1;
+
+		shader = ssao.blur_shader.version_get_shader(ssao.blur_shader_version, 0);
+
+		for (int pass = 0; pass < blur_passes; pass++) {
+			int blur_pipeline = SSAO_BLUR_PASS;
+			if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
+				blur_pipeline = SSAO_BLUR_PASS_SMART;
+				if (pass < blur_passes - 2) {
+					blur_pipeline = SSAO_BLUR_PASS_WIDE;
+				} else {
+					blur_pipeline = SSAO_BLUR_PASS_SMART;
+				}
+			}
+
+			for (int i = 0; i < 4; i++) {
+				if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+					continue;
+				}
+
+				RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[blur_pipeline]);
+				if (pass % 2 == 0) {
+					if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
+						RD::Uniform u_ao_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_deinterleaved_slices[i] }));
+						RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_slices_with_sampler), 0);
+					} else {
+						RD::Uniform u_ao_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ ss_effects.mirror_sampler, p_ssao_buffers.ao_deinterleaved_slices[i] }));
+						RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_slices_with_sampler), 0);
+					}
+
+					RD::Uniform u_ao_pong_slices(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.ao_pong_slices[i] }));
+					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ao_pong_slices), 1);
+				} else {
+					if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
+						RD::Uniform u_ao_pong_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_pong_slices[i] }));
+						RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_pong_slices_with_sampler), 0);
+					} else {
+						RD::Uniform u_ao_pong_slices_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ ss_effects.mirror_sampler, p_ssao_buffers.ao_pong_slices[i] }));
+						RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_ao_pong_slices_with_sampler), 0);
+					}
+
+					RD::Uniform u_ao_slices(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.ao_deinterleaved_slices[i] }));
+					RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ao_slices), 1);
+				}
+				RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.blur_push_constant, sizeof(SSAOBlurPushConstant));
+
+				Size2i size(p_settings.full_screen_size.x >> (p_settings.half_size ? 2 : 1), p_settings.full_screen_size.y >> (p_settings.half_size ? 2 : 1));
+				RD::get_singleton()->compute_list_dispatch_threads(compute_list, size.x, size.y, 1);
+			}
+
+			if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
+				RD::get_singleton()->compute_list_add_barrier(compute_list);
+			}
+		}
+		RD::get_singleton()->draw_command_end_label(); // Blur
+	}
+
+	/* FOURTH PASS */
+	// Interleave buffers
+	// back to full size
+	{
+		RD::get_singleton()->draw_command_begin_label("Interleave Buffers");
+		ssao.interleave_push_constant.inv_sharpness = 1.0 - p_settings.sharpness;
+		ssao.interleave_push_constant.pixel_size[0] = 1.0 / p_settings.full_screen_size.x;
+		ssao.interleave_push_constant.pixel_size[1] = 1.0 / p_settings.full_screen_size.y;
+		ssao.interleave_push_constant.size_modifier = uint32_t(p_settings.half_size ? 4 : 2);
+
+		shader = ssao.interleave_shader.version_get_shader(ssao.interleave_shader_version, 0);
+
+		int interleave_pipeline = SSAO_INTERLEAVE_HALF;
+		if (p_settings.quality == RS::ENV_SSAO_QUALITY_LOW) {
+			interleave_pipeline = SSAO_INTERLEAVE;
+		} else if (p_settings.quality >= RS::ENV_SSAO_QUALITY_MEDIUM) {
+			interleave_pipeline = SSAO_INTERLEAVE_SMART;
+		}
+
+		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssao.pipelines[interleave_pipeline]);
+
+		RD::Uniform u_upscale_buffer(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssao_buffers.ao_final }));
+		RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_upscale_buffer), 0);
+
+		if (p_settings.quality > RS::ENV_SSAO_QUALITY_VERY_LOW && p_settings.blur_passes % 2 == 0) {
+			RD::Uniform u_ao(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_deinterleaved }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ao), 1);
+		} else {
+			RD::Uniform u_ao(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_ssao_buffers.ao_pong }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_ao), 1);
+		}
+
+		RD::get_singleton()->compute_list_set_push_constant(compute_list, &ssao.interleave_push_constant, sizeof(SSAOInterleavePushConstant));
+
+		RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_settings.full_screen_size.x, p_settings.full_screen_size.y, 1);
+		RD::get_singleton()->compute_list_add_barrier(compute_list);
+		RD::get_singleton()->draw_command_end_label(); // Interleave
+	}
+	RD::get_singleton()->draw_command_end_label(); //SSAO
+	RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //wait for upcoming transfer
+
+	int zero[1] = { 0 };
+	RD::get_singleton()->buffer_update(ssao.importance_map_load_counter, 0, sizeof(uint32_t), &zero, 0); //no barrier
+}
+
+void SSEffects::ssao_free(SSAORenderBuffers &p_ssao_buffers) {
+	if (p_ssao_buffers.ao_final.is_valid()) {
+		RD::get_singleton()->free(p_ssao_buffers.ao_deinterleaved);
+		RD::get_singleton()->free(p_ssao_buffers.ao_pong);
+		RD::get_singleton()->free(p_ssao_buffers.ao_final);
+
+		RD::get_singleton()->free(p_ssao_buffers.importance_map[0]);
+		RD::get_singleton()->free(p_ssao_buffers.importance_map[1]);
+
+		p_ssao_buffers.ao_deinterleaved = RID();
+		p_ssao_buffers.ao_pong = RID();
+		p_ssao_buffers.ao_final = RID();
+		p_ssao_buffers.importance_map[0] = RID();
+		p_ssao_buffers.importance_map[1] = RID();
+		p_ssao_buffers.ao_deinterleaved_slices.clear();
+		p_ssao_buffers.ao_pong_slices.clear();
+
+		p_ssao_buffers.gather_uniform_set = RID();
+		p_ssao_buffers.importance_map_uniform_set = RID();
+	}
+}
+
+/* Screen Space Reflection */
+
+void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const Size2i &p_screen_size, const uint32_t p_view_count) {
+	// As we are processing one view at a time, we can reuse buffers, only our output needs to have layers for each view.
+
+	if (p_ssr_buffers.depth_scaled.is_null()) {
+		RD::TextureFormat tf;
+		tf.format = RD::DATA_FORMAT_R32_SFLOAT;
+		tf.width = p_screen_size.x;
+		tf.height = p_screen_size.y;
+		tf.texture_type = RD::TEXTURE_TYPE_2D;
+		tf.array_layers = 1;
+		tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
+
+		p_ssr_buffers.depth_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView());
+		RD::get_singleton()->set_resource_name(p_ssr_buffers.depth_scaled, "SSR Depth Scaled");
+
+		tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+
+		p_ssr_buffers.normal_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView());
+		RD::get_singleton()->set_resource_name(p_ssr_buffers.normal_scaled, "SSR Normal Scaled");
+	}
+
+	if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !p_ssr_buffers.blur_radius[0].is_valid()) {
+		RD::TextureFormat tf;
+		tf.format = RD::DATA_FORMAT_R8_UNORM;
+		tf.width = p_screen_size.x;
+		tf.height = p_screen_size.y;
+		tf.texture_type = RD::TEXTURE_TYPE_2D;
+		tf.array_layers = 1;
+		tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
+
+		p_ssr_buffers.blur_radius[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+		RD::get_singleton()->set_resource_name(p_ssr_buffers.blur_radius[0], "SSR Blur Radius 0");
+		p_ssr_buffers.blur_radius[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
+		RD::get_singleton()->set_resource_name(p_ssr_buffers.blur_radius[1], "SSR Blur Radius 1");
+	}
+
+	if (p_ssr_buffers.intermediate.is_null()) {
+		RD::TextureFormat tf;
+		tf.format = p_color_format;
+		tf.width = p_screen_size.x;
+		tf.height = p_screen_size.y;
+		tf.texture_type = RD::TEXTURE_TYPE_2D;
+		tf.array_layers = 1;
+		tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+
+		p_ssr_buffers.intermediate = RD::get_singleton()->texture_create(tf, RD::TextureView());
+		RD::get_singleton()->set_resource_name(p_ssr_buffers.intermediate, "SSR Intermediate");
+
+		if (p_view_count > 1) {
+			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+			tf.array_layers = p_view_count;
+		} else {
+			tf.texture_type = RD::TEXTURE_TYPE_2D;
+			tf.array_layers = 1;
+		}
+
+		p_ssr_buffers.output = RD::get_singleton()->texture_create(tf, RD::TextureView());
+		RD::get_singleton()->set_resource_name(p_ssr_buffers.output, "SSR Output");
+
+		for (uint32_t v = 0; v < p_view_count; v++) {
+			p_ssr_buffers.output_slices[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_ssr_buffers.output, v, 0);
+		}
+	}
+}
+
+void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const Color &p_metallic_mask, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets) {
+	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+	ERR_FAIL_NULL(uniform_set_cache);
+	MaterialStorage *material_storage = MaterialStorage::get_singleton();
+	ERR_FAIL_NULL(material_storage);
+
+	RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+	{
+		// Store some scene data in a UBO, in the near future we will use a UBO shared with other shaders
+		ScreenSpaceReflectionSceneData scene_data;
+
+		if (ssr.ubo.is_null()) {
+			ssr.ubo = RD::get_singleton()->uniform_buffer_create(sizeof(ScreenSpaceReflectionSceneData));
+		}
+
+		for (uint32_t v = 0; v < p_view_count; v++) {
+			store_camera(p_projections[v], scene_data.projection[v]);
+			store_camera(p_projections[v].inverse(), scene_data.inv_projection[v]);
+			scene_data.eye_offset[v][0] = p_eye_offsets[v].x;
+			scene_data.eye_offset[v][1] = p_eye_offsets[v].y;
+			scene_data.eye_offset[v][2] = p_eye_offsets[v].z;
+			scene_data.eye_offset[v][3] = 0.0;
+		}
+
+		RD::get_singleton()->buffer_update(ssr.ubo, 0, sizeof(ScreenSpaceReflectionSceneData), &scene_data, RD::BARRIER_MASK_COMPUTE);
+	}
+
+	uint32_t pipeline_specialization = 0;
+	if (p_view_count > 1) {
+		pipeline_specialization |= SSR_MULTIVIEW;
+	}
+
+	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+
+	for (uint32_t v = 0; v < p_view_count; v++) {
+		RD::get_singleton()->draw_command_begin_label(String("SSR View ") + itos(v));
+
+		{ //scale color and depth to half
+			RD::get_singleton()->draw_command_begin_label("SSR Scale");
+
+			ScreenSpaceReflectionScalePushConstant push_constant;
+			push_constant.view_index = v;
+			push_constant.camera_z_far = p_projections[v].get_z_far();
+			push_constant.camera_z_near = p_projections[v].get_z_near();
+			push_constant.orthogonal = p_projections[v].is_orthogonal();
+			push_constant.filter = false; //enabling causes arctifacts
+			push_constant.screen_size[0] = p_screen_size.x;
+			push_constant.screen_size[1] = p_screen_size.y;
+
+			RID shader = ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0);
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_scale.pipelines[pipeline_specialization]);
+
+			RD::Uniform u_diffuse(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_diffuse_slices[v] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_diffuse), 0);
+
+			RD::Uniform u_depth(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_depth_slices[v] }));
+			RD::Uniform u_normal_roughness(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 1, Vector<RID>({ default_sampler, p_normal_roughness_slices[v] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_depth, u_normal_roughness), 1);
+
+			RD::Uniform u_output_blur(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_output_blur), 2);
+
+			RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.depth_scaled }));
+			RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.normal_scaled }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_scale_depth, u_scale_normal), 3);
+
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ScreenSpaceReflectionScalePushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
+
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			RD::get_singleton()->draw_command_end_label();
+		}
+
+		{
+			RD::get_singleton()->draw_command_begin_label("SSR main");
+
+			ScreenSpaceReflectionPushConstant push_constant;
+			push_constant.view_index = v;
+			push_constant.camera_z_far = p_projections[v].get_z_far();
+			push_constant.camera_z_near = p_projections[v].get_z_near();
+			push_constant.orthogonal = p_projections[v].is_orthogonal();
+			push_constant.screen_size[0] = p_screen_size.x;
+			push_constant.screen_size[1] = p_screen_size.y;
+			push_constant.curve_fade_in = p_fade_in;
+			push_constant.distance_fade = p_fade_out;
+			push_constant.num_steps = p_max_steps;
+			push_constant.depth_tolerance = p_tolerance;
+			push_constant.use_half_res = true;
+			push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_projections[v].matrix[0][0]);
+			push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_projections[v].matrix[1][1]);
+			push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0];
+			push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1];
+			push_constant.metallic_mask[0] = CLAMP(p_metallic_mask.r * 255.0, 0, 255);
+			push_constant.metallic_mask[1] = CLAMP(p_metallic_mask.g * 255.0, 0, 255);
+			push_constant.metallic_mask[2] = CLAMP(p_metallic_mask.b * 255.0, 0, 255);
+			push_constant.metallic_mask[3] = CLAMP(p_metallic_mask.a * 255.0, 0, 255);
+
+			ScreenSpaceReflectionMode mode = (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL;
+			RID shader = ssr.shader.version_get_shader(ssr.shader_version, mode);
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr.pipelines[pipeline_specialization][mode]);
+
+			RD::Uniform u_scene_data(RD::UNIFORM_TYPE_UNIFORM_BUFFER, 0, ssr.ubo);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4);
+
+			RD::Uniform u_output_blur(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
+			RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.depth_scaled }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_output_blur, u_scale_depth), 0);
+
+			if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
+				RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
+				RD::Uniform u_blur_radius(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.blur_radius[0] }));
+				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate, u_blur_radius), 1);
+			} else {
+				RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
+				RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_intermediate), 1);
+			}
+
+			RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.normal_scaled }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_scale_normal), 2);
+
+			RD::Uniform u_metallic(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_metallic_slices[v] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_metallic), 3);
+
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ScreenSpaceReflectionPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
+
+			RD::get_singleton()->draw_command_end_label();
+		}
+
+		if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
+			RD::get_singleton()->draw_command_begin_label("SSR filter");
+			//blur
+
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			ScreenSpaceReflectionFilterPushConstant push_constant;
+			push_constant.view_index = v;
+			push_constant.orthogonal = p_projections[v].is_orthogonal();
+			push_constant.edge_tolerance = Math::sin(Math::deg2rad(15.0));
+			push_constant.proj_info[0] = -2.0f / (p_screen_size.width * p_projections[v].matrix[0][0]);
+			push_constant.proj_info[1] = -2.0f / (p_screen_size.height * p_projections[v].matrix[1][1]);
+			push_constant.proj_info[2] = (1.0f - p_projections[v].matrix[0][2]) / p_projections[v].matrix[0][0];
+			push_constant.proj_info[3] = (1.0f + p_projections[v].matrix[1][2]) / p_projections[v].matrix[1][1];
+			push_constant.vertical = 0;
+			if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_LOW) {
+				push_constant.steps = p_max_steps / 3;
+				push_constant.increment = 3;
+			} else if (p_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) {
+				push_constant.steps = p_max_steps / 2;
+				push_constant.increment = 2;
+			} else {
+				push_constant.steps = p_max_steps;
+				push_constant.increment = 1;
+			}
+
+			push_constant.screen_size[0] = p_screen_size.width;
+			push_constant.screen_size[1] = p_screen_size.height;
+
+			// Horizontal pass
+
+			SSRReflectionMode mode = SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL;
+
+			RID shader = ssr_filter.shader.version_get_shader(ssr_filter.shader_version, mode);
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[pipeline_specialization][mode]);
+
+			RD::Uniform u_scene_data(RD::UNIFORM_TYPE_UNIFORM_BUFFER, 0, ssr.ubo);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4);
+
+			RD::Uniform u_intermediate(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.intermediate }));
+			RD::Uniform u_blur_radius(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.blur_radius[0] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_intermediate, u_blur_radius), 0);
+
+			RD::Uniform u_scale_normal(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.normal_scaled }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_scale_normal), 1);
+
+			RD::Uniform u_output_blur(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.output_slices[v] }));
+			RD::Uniform u_blur_radius2(RD::UNIFORM_TYPE_IMAGE, 1, Vector<RID>({ p_ssr_buffers.blur_radius[1] }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_output_blur, u_blur_radius2), 2);
+
+			RD::Uniform u_scale_depth(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_ssr_buffers.depth_scaled }));
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_scale_depth), 3);
+
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
+			RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+			// Vertical pass
+
+			mode = SCREEN_SPACE_REFLECTION_FILTER_VERTICAL;
+			shader = ssr_filter.shader.version_get_shader(ssr_filter.shader_version, mode);
+
+			RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, ssr_filter.pipelines[pipeline_specialization][mode]);
+
+			push_constant.vertical = 1;
+
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_output_blur, u_blur_radius2), 0);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_scale_normal), 1);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 2, u_intermediate), 2);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 3, u_scale_depth), 3);
+			RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 4, u_scene_data), 4);
+
+			RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(ScreenSpaceReflectionFilterPushConstant));
+			RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_screen_size.width, p_screen_size.height, 1);
+
+			if (v != p_view_count - 1) {
+				RD::get_singleton()->compute_list_add_barrier(compute_list);
+			}
+
+			RD::get_singleton()->draw_command_end_label();
+		}
+
+		RD::get_singleton()->draw_command_end_label();
+	}
+
+	RD::get_singleton()->compute_list_end();
+}
+
+void SSEffects::ssr_free(SSRRenderBuffers &p_ssr_buffers) {
+	for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
+		p_ssr_buffers.output_slices[v] = RID();
+	}
+
+	if (p_ssr_buffers.output.is_valid()) {
+		RD::get_singleton()->free(p_ssr_buffers.output);
+		p_ssr_buffers.output = RID();
+	}
+
+	if (p_ssr_buffers.intermediate.is_valid()) {
+		RD::get_singleton()->free(p_ssr_buffers.intermediate);
+		p_ssr_buffers.intermediate = RID();
+	}
+
+	if (p_ssr_buffers.blur_radius[0].is_valid()) {
+		RD::get_singleton()->free(p_ssr_buffers.blur_radius[0]);
+		RD::get_singleton()->free(p_ssr_buffers.blur_radius[1]);
+		p_ssr_buffers.blur_radius[0] = RID();
+		p_ssr_buffers.blur_radius[1] = RID();
+	}
+
+	if (p_ssr_buffers.depth_scaled.is_valid()) {
+		RD::get_singleton()->free(p_ssr_buffers.depth_scaled);
+		p_ssr_buffers.depth_scaled = RID();
+		RD::get_singleton()->free(p_ssr_buffers.normal_scaled);
+		p_ssr_buffers.normal_scaled = RID();
+	}
+}

+ 508 - 0
servers/rendering/renderer_rd/effects/ss_effects.h

@@ -0,0 +1,508 @@
+/*************************************************************************/
+/*  ss_effects.h                                                         */
+/*************************************************************************/
+/*                       This file is part of:                           */
+/*                           GODOT ENGINE                                */
+/*                      https://godotengine.org                          */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
+/*                                                                       */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the       */
+/* "Software"), to deal in the Software without restriction, including   */
+/* without limitation the rights to use, copy, modify, merge, publish,   */
+/* distribute, sublicense, and/or sell copies of the Software, and to    */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions:                                             */
+/*                                                                       */
+/* The above copyright notice and this permission notice shall be        */
+/* included in all copies or substantial portions of the Software.       */
+/*                                                                       */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
+/*************************************************************************/
+
+#ifndef SS_EFFECTS_RD_H
+#define SS_EFFECTS_RD_H
+
+#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
+#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ssao.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ssil.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl.gen.h"
+#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering_server.h"
+
+namespace RendererRD {
+
+class SSEffects {
+private:
+	static SSEffects *singleton;
+
+public:
+	static SSEffects *get_singleton() { return singleton; }
+
+	SSEffects();
+	~SSEffects();
+
+	/* SS Downsampler */
+
+	void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const CameraMatrix &p_projection);
+
+	/* SSIL */
+
+	struct SSILRenderBuffers {
+		bool half_size = false;
+		int buffer_width;
+		int buffer_height;
+		int half_buffer_width;
+		int half_buffer_height;
+
+		RID ssil_final;
+		RID deinterleaved;
+		Vector<RID> deinterleaved_slices;
+		RID pong;
+		Vector<RID> pong_slices;
+		RID edges;
+		Vector<RID> edges_slices;
+		RID importance_map[2];
+		RID depth_texture_view;
+
+		RID last_frame;
+		Vector<RID> last_frame_slices;
+
+		RID gather_uniform_set;
+		RID importance_map_uniform_set;
+		RID projection_uniform_set;
+	};
+
+	struct SSILSettings {
+		float radius = 1.0;
+		float intensity = 2.0;
+		float sharpness = 0.98;
+		float normal_rejection = 1.0;
+
+		RS::EnvironmentSSILQuality quality = RS::ENV_SSIL_QUALITY_MEDIUM;
+		bool half_size = true;
+		float adaptive_target = 0.5;
+		int blur_passes = 4;
+		float fadeout_from = 50.0;
+		float fadeout_to = 300.0;
+
+		Size2i full_screen_size = Size2i();
+	};
+
+	void ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const SSILSettings &p_settings, RID p_linear_depth);
+	void screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers, RID p_normal_buffer, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings);
+	void ssil_free(SSILRenderBuffers &p_ssil_buffers);
+
+	/* SSAO */
+
+	struct SSAORenderBuffers {
+		bool half_size = false;
+		int buffer_width;
+		int buffer_height;
+		int half_buffer_width;
+		int half_buffer_height;
+
+		RID ao_deinterleaved;
+		Vector<RID> ao_deinterleaved_slices;
+		RID ao_pong;
+		Vector<RID> ao_pong_slices;
+		RID ao_final;
+		RID importance_map[2];
+		RID depth_texture_view;
+
+		RID gather_uniform_set;
+		RID importance_map_uniform_set;
+	};
+
+	struct SSAOSettings {
+		float radius = 1.0;
+		float intensity = 2.0;
+		float power = 1.5;
+		float detail = 0.5;
+		float horizon = 0.06;
+		float sharpness = 0.98;
+
+		RS::EnvironmentSSAOQuality quality = RS::ENV_SSAO_QUALITY_MEDIUM;
+		bool half_size = false;
+		float adaptive_target = 0.5;
+		int blur_passes = 2;
+		float fadeout_from = 50.0;
+		float fadeout_to = 300.0;
+
+		Size2i full_screen_size = Size2i();
+	};
+
+	void ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const SSAOSettings &p_settings, RID p_linear_depth);
+	void generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_buffer, const CameraMatrix &p_projection, const SSAOSettings &p_settings);
+	void ssao_free(SSAORenderBuffers &p_ssao_buffers);
+
+	/* Screen Space Reflection */
+
+	struct SSRRenderBuffers {
+		RID normal_scaled;
+		RID depth_scaled;
+		RID blur_radius[2];
+		RID intermediate;
+		RID output;
+		RID output_slices[RendererSceneRender::MAX_RENDER_VIEWS];
+	};
+
+	void ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, RenderingServer::EnvironmentSSRRoughnessQuality p_roughness_quality, const Size2i &p_screen_size, const uint32_t p_view_count);
+	void screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, const RID *p_metallic_slices, const Color &p_metallic_mask, const RID *p_depth_slices, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const uint32_t p_view_count, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets);
+	void ssr_free(SSRRenderBuffers &p_ssr_buffers);
+
+private:
+	/* SS Downsampler */
+
+	struct SSEffectsDownsamplePushConstant {
+		float pixel_size[2];
+		float z_far;
+		float z_near;
+		uint32_t orthogonal;
+		float radius_sq;
+		uint32_t pad[2];
+	};
+
+	enum SSEffectsMode {
+		SS_EFFECTS_DOWNSAMPLE,
+		SS_EFFECTS_DOWNSAMPLE_HALF_RES,
+		SS_EFFECTS_DOWNSAMPLE_MIPMAP,
+		SS_EFFECTS_DOWNSAMPLE_MIPMAP_HALF_RES,
+		SS_EFFECTS_DOWNSAMPLE_HALF,
+		SS_EFFECTS_DOWNSAMPLE_HALF_RES_HALF,
+		SS_EFFECTS_DOWNSAMPLE_FULL_MIPS,
+		SS_EFFECTS_MAX
+	};
+
+	struct SSEffectsGatherConstants {
+		float rotation_matrices[80]; //5 vec4s * 4
+	};
+
+	struct SSEffectsShader {
+		SSEffectsDownsamplePushConstant downsample_push_constant;
+		SsEffectsDownsampleShaderRD downsample_shader;
+		RID downsample_shader_version;
+		RID downsample_uniform_set;
+		bool used_half_size_last_frame = false;
+		bool used_mips_last_frame = false;
+		bool used_full_mips_last_frame = false;
+
+		RID gather_constants_buffer;
+
+		RID mirror_sampler;
+
+		RID pipelines[SS_EFFECTS_MAX];
+	} ss_effects;
+
+	/* SSIL */
+
+	enum SSILMode {
+		SSIL_GATHER,
+		SSIL_GATHER_BASE,
+		SSIL_GATHER_ADAPTIVE,
+		SSIL_GENERATE_IMPORTANCE_MAP,
+		SSIL_PROCESS_IMPORTANCE_MAPA,
+		SSIL_PROCESS_IMPORTANCE_MAPB,
+		SSIL_BLUR_PASS,
+		SSIL_BLUR_PASS_SMART,
+		SSIL_BLUR_PASS_WIDE,
+		SSIL_INTERLEAVE,
+		SSIL_INTERLEAVE_SMART,
+		SSIL_INTERLEAVE_HALF,
+		SSIL_MAX
+	};
+
+	struct SSILGatherPushConstant {
+		int32_t screen_size[2];
+		int pass;
+		int quality;
+
+		float half_screen_pixel_size[2];
+		float half_screen_pixel_size_x025[2];
+
+		float NDC_to_view_mul[2];
+		float NDC_to_view_add[2];
+
+		float pad2[2];
+		float z_near;
+		float z_far;
+
+		float radius;
+		float intensity;
+		int size_multiplier;
+		int pad;
+
+		float fade_out_mul;
+		float fade_out_add;
+		float normal_rejection_amount;
+		float inv_radius_near_limit;
+
+		uint32_t is_orthogonal;
+		float neg_inv_radius;
+		float load_counter_avg_div;
+		float adaptive_sample_limit;
+
+		int32_t pass_coord_offset[2];
+		float pass_uv_offset[2];
+	};
+
+	struct SSILImportanceMapPushConstant {
+		float half_screen_pixel_size[2];
+		float intensity;
+		float pad;
+	};
+
+	struct SSILBlurPushConstant {
+		float edge_sharpness;
+		float pad;
+		float half_screen_pixel_size[2];
+	};
+
+	struct SSILInterleavePushConstant {
+		float inv_sharpness;
+		uint32_t size_modifier;
+		float pixel_size[2];
+	};
+
+	struct SSILProjectionUniforms {
+		float inv_last_frame_projection_matrix[16];
+	};
+
+	struct SSIL {
+		SSILGatherPushConstant gather_push_constant;
+		SsilShaderRD gather_shader;
+		RID gather_shader_version;
+		RID projection_uniform_buffer;
+
+		SSILImportanceMapPushConstant importance_map_push_constant;
+		SsilImportanceMapShaderRD importance_map_shader;
+		RID importance_map_shader_version;
+		RID importance_map_load_counter;
+		RID counter_uniform_set;
+
+		SSILBlurPushConstant blur_push_constant;
+		SsilBlurShaderRD blur_shader;
+		RID blur_shader_version;
+
+		SSILInterleavePushConstant interleave_push_constant;
+		SsilInterleaveShaderRD interleave_shader;
+		RID interleave_shader_version;
+
+		RID pipelines[SSIL_MAX];
+	} ssil;
+
+	void gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set);
+
+	/* SSAO */
+
+	enum SSAOMode {
+		SSAO_GATHER,
+		SSAO_GATHER_BASE,
+		SSAO_GATHER_ADAPTIVE,
+		SSAO_GENERATE_IMPORTANCE_MAP,
+		SSAO_PROCESS_IMPORTANCE_MAPA,
+		SSAO_PROCESS_IMPORTANCE_MAPB,
+		SSAO_BLUR_PASS,
+		SSAO_BLUR_PASS_SMART,
+		SSAO_BLUR_PASS_WIDE,
+		SSAO_INTERLEAVE,
+		SSAO_INTERLEAVE_SMART,
+		SSAO_INTERLEAVE_HALF,
+		SSAO_MAX
+	};
+
+	struct SSAOGatherPushConstant {
+		int32_t screen_size[2];
+		int pass;
+		int quality;
+
+		float half_screen_pixel_size[2];
+		int size_multiplier;
+		float detail_intensity;
+
+		float NDC_to_view_mul[2];
+		float NDC_to_view_add[2];
+
+		float pad[2];
+		float half_screen_pixel_size_x025[2];
+
+		float radius;
+		float intensity;
+		float shadow_power;
+		float shadow_clamp;
+
+		float fade_out_mul;
+		float fade_out_add;
+		float horizon_angle_threshold;
+		float inv_radius_near_limit;
+
+		uint32_t is_orthogonal;
+		float neg_inv_radius;
+		float load_counter_avg_div;
+		float adaptive_sample_limit;
+
+		int32_t pass_coord_offset[2];
+		float pass_uv_offset[2];
+	};
+
+	struct SSAOImportanceMapPushConstant {
+		float half_screen_pixel_size[2];
+		float intensity;
+		float power;
+	};
+
+	struct SSAOBlurPushConstant {
+		float edge_sharpness;
+		float pad;
+		float half_screen_pixel_size[2];
+	};
+
+	struct SSAOInterleavePushConstant {
+		float inv_sharpness;
+		uint32_t size_modifier;
+		float pixel_size[2];
+	};
+
+	struct SSAO {
+		SSAOGatherPushConstant gather_push_constant;
+		SsaoShaderRD gather_shader;
+		RID gather_shader_version;
+
+		SSAOImportanceMapPushConstant importance_map_push_constant;
+		SsaoImportanceMapShaderRD importance_map_shader;
+		RID importance_map_shader_version;
+		RID importance_map_load_counter;
+		RID counter_uniform_set;
+
+		SSAOBlurPushConstant blur_push_constant;
+		SsaoBlurShaderRD blur_shader;
+		RID blur_shader_version;
+
+		SSAOInterleavePushConstant interleave_push_constant;
+		SsaoInterleaveShaderRD interleave_shader;
+		RID interleave_shader_version;
+
+		RID pipelines[SSAO_MAX];
+	} ssao;
+
+	void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
+
+	/* Screen Space Reflection */
+
+	enum SSRShaderSpecializations {
+		SSR_MULTIVIEW = 1 << 0,
+		SSR_VARIATIONS = 2,
+	};
+
+	struct ScreenSpaceReflectionSceneData {
+		float projection[2][16];
+		float inv_projection[2][16];
+		float eye_offset[2][4];
+	};
+
+	// SSR Scale
+
+	struct ScreenSpaceReflectionScalePushConstant {
+		int32_t screen_size[2];
+		float camera_z_near;
+		float camera_z_far;
+
+		uint32_t orthogonal;
+		uint32_t filter;
+		uint32_t view_index;
+		uint32_t pad1;
+	};
+
+	struct ScreenSpaceReflectionScale {
+		ScreenSpaceReflectionScaleShaderRD shader;
+		RID shader_version;
+		RID pipelines[SSR_VARIATIONS];
+	} ssr_scale;
+
+	// SSR main
+
+	enum ScreenSpaceReflectionMode {
+		SCREEN_SPACE_REFLECTION_NORMAL,
+		SCREEN_SPACE_REFLECTION_ROUGH,
+		SCREEN_SPACE_REFLECTION_MAX,
+	};
+
+	struct ScreenSpaceReflectionPushConstant {
+		float proj_info[4]; // 16 - 16
+
+		int32_t screen_size[2]; //  8 - 24
+		float camera_z_near; //  4 - 28
+		float camera_z_far; //  4 - 32
+
+		int32_t num_steps; //  4 - 36
+		float depth_tolerance; //  4 - 40
+		float distance_fade; //  4 - 44
+		float curve_fade_in; //  4 - 48
+
+		uint32_t orthogonal; //  4 - 52
+		float filter_mipmap_levels; //  4 - 56
+		uint32_t use_half_res; //  4 - 60
+		uint8_t metallic_mask[4]; //  4 - 64
+
+		uint32_t view_index; //  4 - 68
+		uint32_t pad[3]; // 12 - 80
+
+		// float projection[16];			// this is in our ScreenSpaceReflectionSceneData now
+	};
+
+	struct ScreenSpaceReflection {
+		ScreenSpaceReflectionShaderRD shader;
+		RID shader_version;
+		RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_MAX];
+
+		RID ubo;
+	} ssr;
+
+	// SSR Filter
+
+	struct ScreenSpaceReflectionFilterPushConstant {
+		float proj_info[4]; // 16 - 16
+
+		uint32_t orthogonal; //  4 - 20
+		float edge_tolerance; //  4 - 24
+		int32_t increment; //  4 - 28
+		uint32_t view_index; //  4 - 32
+
+		int32_t screen_size[2]; //  8 - 40
+		uint32_t vertical; //  4 - 44
+		uint32_t steps; //  4 - 48
+	};
+
+	enum SSRReflectionMode {
+		SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL,
+		SCREEN_SPACE_REFLECTION_FILTER_VERTICAL,
+		SCREEN_SPACE_REFLECTION_FILTER_MAX,
+	};
+
+	struct ScreenSpaceReflectionFilter {
+		ScreenSpaceReflectionFilterShaderRD shader;
+		RID shader_version;
+		RID pipelines[SSR_VARIATIONS][SCREEN_SPACE_REFLECTION_FILTER_MAX];
+	} ssr_filter;
+};
+
+} // namespace RendererRD
+
+#endif // !SS_EFFECTS_RD_H

File diff suppressed because it is too large
+ 1 - 1073
servers/rendering/renderer_rd/effects_rd.cpp


+ 0 - 384
servers/rendering/renderer_rd/effects_rd.h

@@ -37,20 +37,7 @@
 #include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/roughness_limiter.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/sort.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/specular_merge.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ssao.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ssao_blur.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ssao_interleave.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ssil.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ssil_blur.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/ssil_interleave.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/subsurface_scattering.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/taa_resolve.glsl.gen.h"
 #include "servers/rendering/renderer_scene_render.h"
@@ -142,231 +129,6 @@ private:
 		PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX];
 	} luminance_reduce_raster;
 
-	struct SSEffectsDownsamplePushConstant {
-		float pixel_size[2];
-		float z_far;
-		float z_near;
-		uint32_t orthogonal;
-		float radius_sq;
-		uint32_t pad[2];
-	};
-
-	enum SSEffectsMode {
-		SS_EFFECTS_DOWNSAMPLE,
-		SS_EFFECTS_DOWNSAMPLE_HALF_RES,
-		SS_EFFECTS_DOWNSAMPLE_MIPMAP,
-		SS_EFFECTS_DOWNSAMPLE_MIPMAP_HALF_RES,
-		SS_EFFECTS_DOWNSAMPLE_HALF,
-		SS_EFFECTS_DOWNSAMPLE_HALF_RES_HALF,
-		SS_EFFECTS_DOWNSAMPLE_FULL_MIPS,
-		SS_EFFECTS_MAX
-	};
-
-	struct SSEffectsGatherConstants {
-		float rotation_matrices[80]; //5 vec4s * 4
-	};
-
-	struct SSEffects {
-		SSEffectsDownsamplePushConstant downsample_push_constant;
-		SsEffectsDownsampleShaderRD downsample_shader;
-		RID downsample_shader_version;
-		RID downsample_uniform_set;
-		bool used_half_size_last_frame = false;
-		bool used_mips_last_frame = false;
-		bool used_full_mips_last_frame = false;
-
-		RID gather_constants_buffer;
-
-		RID mirror_sampler;
-
-		RID pipelines[SS_EFFECTS_MAX];
-	} ss_effects;
-
-	enum SSAOMode {
-		SSAO_GATHER,
-		SSAO_GATHER_BASE,
-		SSAO_GATHER_ADAPTIVE,
-		SSAO_GENERATE_IMPORTANCE_MAP,
-		SSAO_PROCESS_IMPORTANCE_MAPA,
-		SSAO_PROCESS_IMPORTANCE_MAPB,
-		SSAO_BLUR_PASS,
-		SSAO_BLUR_PASS_SMART,
-		SSAO_BLUR_PASS_WIDE,
-		SSAO_INTERLEAVE,
-		SSAO_INTERLEAVE_SMART,
-		SSAO_INTERLEAVE_HALF,
-		SSAO_MAX
-	};
-
-	struct SSAOGatherPushConstant {
-		int32_t screen_size[2];
-		int pass;
-		int quality;
-
-		float half_screen_pixel_size[2];
-		int size_multiplier;
-		float detail_intensity;
-
-		float NDC_to_view_mul[2];
-		float NDC_to_view_add[2];
-
-		float pad[2];
-		float half_screen_pixel_size_x025[2];
-
-		float radius;
-		float intensity;
-		float shadow_power;
-		float shadow_clamp;
-
-		float fade_out_mul;
-		float fade_out_add;
-		float horizon_angle_threshold;
-		float inv_radius_near_limit;
-
-		uint32_t is_orthogonal;
-		float neg_inv_radius;
-		float load_counter_avg_div;
-		float adaptive_sample_limit;
-
-		int32_t pass_coord_offset[2];
-		float pass_uv_offset[2];
-	};
-
-	struct SSAOImportanceMapPushConstant {
-		float half_screen_pixel_size[2];
-		float intensity;
-		float power;
-	};
-
-	struct SSAOBlurPushConstant {
-		float edge_sharpness;
-		float pad;
-		float half_screen_pixel_size[2];
-	};
-
-	struct SSAOInterleavePushConstant {
-		float inv_sharpness;
-		uint32_t size_modifier;
-		float pixel_size[2];
-	};
-
-	struct SSAO {
-		SSAOGatherPushConstant gather_push_constant;
-		SsaoShaderRD gather_shader;
-		RID gather_shader_version;
-
-		SSAOImportanceMapPushConstant importance_map_push_constant;
-		SsaoImportanceMapShaderRD importance_map_shader;
-		RID importance_map_shader_version;
-		RID importance_map_load_counter;
-		RID counter_uniform_set;
-
-		SSAOBlurPushConstant blur_push_constant;
-		SsaoBlurShaderRD blur_shader;
-		RID blur_shader_version;
-
-		SSAOInterleavePushConstant interleave_push_constant;
-		SsaoInterleaveShaderRD interleave_shader;
-		RID interleave_shader_version;
-
-		RID pipelines[SSAO_MAX];
-	} ssao;
-
-	enum SSILMode {
-		SSIL_GATHER,
-		SSIL_GATHER_BASE,
-		SSIL_GATHER_ADAPTIVE,
-		SSIL_GENERATE_IMPORTANCE_MAP,
-		SSIL_PROCESS_IMPORTANCE_MAPA,
-		SSIL_PROCESS_IMPORTANCE_MAPB,
-		SSIL_BLUR_PASS,
-		SSIL_BLUR_PASS_SMART,
-		SSIL_BLUR_PASS_WIDE,
-		SSIL_INTERLEAVE,
-		SSIL_INTERLEAVE_SMART,
-		SSIL_INTERLEAVE_HALF,
-		SSIL_MAX
-	};
-
-	struct SSILGatherPushConstant {
-		int32_t screen_size[2];
-		int pass;
-		int quality;
-
-		float half_screen_pixel_size[2];
-		float half_screen_pixel_size_x025[2];
-
-		float NDC_to_view_mul[2];
-		float NDC_to_view_add[2];
-
-		float pad2[2];
-		float z_near;
-		float z_far;
-
-		float radius;
-		float intensity;
-		int size_multiplier;
-		int pad;
-
-		float fade_out_mul;
-		float fade_out_add;
-		float normal_rejection_amount;
-		float inv_radius_near_limit;
-
-		uint32_t is_orthogonal;
-		float neg_inv_radius;
-		float load_counter_avg_div;
-		float adaptive_sample_limit;
-
-		int32_t pass_coord_offset[2];
-		float pass_uv_offset[2];
-	};
-
-	struct SSILImportanceMapPushConstant {
-		float half_screen_pixel_size[2];
-		float intensity;
-		float pad;
-	};
-
-	struct SSILBlurPushConstant {
-		float edge_sharpness;
-		float pad;
-		float half_screen_pixel_size[2];
-	};
-
-	struct SSILInterleavePushConstant {
-		float inv_sharpness;
-		uint32_t size_modifier;
-		float pixel_size[2];
-	};
-
-	struct SSILProjectionUniforms {
-		float inv_last_frame_projection_matrix[16];
-	};
-
-	struct SSIL {
-		SSILGatherPushConstant gather_push_constant;
-		SsilShaderRD gather_shader;
-		RID gather_shader_version;
-		RID projection_uniform_buffer;
-
-		SSILImportanceMapPushConstant importance_map_push_constant;
-		SsilImportanceMapShaderRD importance_map_shader;
-		RID importance_map_shader_version;
-		RID importance_map_load_counter;
-		RID counter_uniform_set;
-
-		SSILBlurPushConstant blur_push_constant;
-		SsilBlurShaderRD blur_shader;
-		RID blur_shader_version;
-
-		SSILInterleavePushConstant interleave_push_constant;
-		SsilInterleaveShaderRD interleave_shader;
-		RID interleave_shader_version;
-
-		RID pipelines[SSIL_MAX];
-	} ssil;
-
 	struct RoughnessLimiterPushConstant {
 		int32_t screen_size[2];
 		float curve;
@@ -381,101 +143,6 @@ private:
 
 	} roughness_limiter;
 
-	enum SpecularMergeMode {
-		SPECULAR_MERGE_ADD,
-		SPECULAR_MERGE_SSR,
-		SPECULAR_MERGE_ADDITIVE_ADD,
-		SPECULAR_MERGE_ADDITIVE_SSR,
-		SPECULAR_MERGE_MAX
-	};
-
-	/* Specular merge must be done using raster, rather than compute
-	 * because it must continue the existing color buffer
-	 */
-
-	struct SpecularMerge {
-		SpecularMergeShaderRD shader;
-		RID shader_version;
-		PipelineCacheRD pipelines[SPECULAR_MERGE_MAX];
-
-	} specular_merge;
-
-	enum ScreenSpaceReflectionMode {
-		SCREEN_SPACE_REFLECTION_NORMAL,
-		SCREEN_SPACE_REFLECTION_ROUGH,
-		SCREEN_SPACE_REFLECTION_MAX,
-	};
-
-	struct ScreenSpaceReflectionPushConstant {
-		float proj_info[4];
-
-		int32_t screen_size[2];
-		float camera_z_near;
-		float camera_z_far;
-
-		int32_t num_steps;
-		float depth_tolerance;
-		float distance_fade;
-		float curve_fade_in;
-
-		uint32_t orthogonal;
-		float filter_mipmap_levels;
-		uint32_t use_half_res;
-		uint8_t metallic_mask[4];
-
-		float projection[16];
-	};
-
-	struct ScreenSpaceReflection {
-		ScreenSpaceReflectionPushConstant push_constant;
-		ScreenSpaceReflectionShaderRD shader;
-		RID shader_version;
-		RID pipelines[SCREEN_SPACE_REFLECTION_MAX];
-
-	} ssr;
-
-	struct ScreenSpaceReflectionFilterPushConstant {
-		float proj_info[4];
-
-		uint32_t orthogonal;
-		float edge_tolerance;
-		int32_t increment;
-		uint32_t pad;
-
-		int32_t screen_size[2];
-		uint32_t vertical;
-		uint32_t steps;
-	};
-	enum {
-		SCREEN_SPACE_REFLECTION_FILTER_HORIZONTAL,
-		SCREEN_SPACE_REFLECTION_FILTER_VERTICAL,
-		SCREEN_SPACE_REFLECTION_FILTER_MAX,
-	};
-
-	struct ScreenSpaceReflectionFilter {
-		ScreenSpaceReflectionFilterPushConstant push_constant;
-		ScreenSpaceReflectionFilterShaderRD shader;
-		RID shader_version;
-		RID pipelines[SCREEN_SPACE_REFLECTION_FILTER_MAX];
-	} ssr_filter;
-
-	struct ScreenSpaceReflectionScalePushConstant {
-		int32_t screen_size[2];
-		float camera_z_near;
-		float camera_z_far;
-
-		uint32_t orthogonal;
-		uint32_t filter;
-		uint32_t pad[2];
-	};
-
-	struct ScreenSpaceReflectionScale {
-		ScreenSpaceReflectionScalePushConstant push_constant;
-		ScreenSpaceReflectionScaleShaderRD shader;
-		RID shader_version;
-		RID pipeline;
-	} ssr_scale;
-
 	struct SubSurfaceScatteringPushConstant {
 		int32_t screen_size[2];
 		float camera_z_far;
@@ -559,9 +226,6 @@ private:
 	RID _get_uniform_set_from_image(RID p_texture);
 	RID _get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
 	RID _get_compute_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps = false);
-	RID _get_compute_uniform_set_from_texture_and_sampler(RID p_texture, RID p_sampler);
-	RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false);
-	RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2);
 
 public:
 	bool get_prefer_raster_effects();
@@ -572,56 +236,8 @@ public:
 	void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
 	void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
 
-	struct SSAOSettings {
-		float radius = 1.0;
-		float intensity = 2.0;
-		float power = 1.5;
-		float detail = 0.5;
-		float horizon = 0.06;
-		float sharpness = 0.98;
-
-		RS::EnvironmentSSAOQuality quality = RS::ENV_SSAO_QUALITY_MEDIUM;
-		bool half_size = false;
-		float adaptive_target = 0.5;
-		int blur_passes = 2;
-		float fadeout_from = 50.0;
-		float fadeout_to = 300.0;
-
-		Size2i full_screen_size = Size2i();
-		Size2i half_screen_size = Size2i();
-		Size2i quarter_screen_size = Size2i();
-	};
-
-	struct SSILSettings {
-		float radius = 1.0;
-		float intensity = 2.0;
-		float sharpness = 0.98;
-		float normal_rejection = 1.0;
-
-		RS::EnvironmentSSILQuality quality = RS::ENV_SSIL_QUALITY_MEDIUM;
-		bool half_size = true;
-		float adaptive_target = 0.5;
-		int blur_passes = 4;
-		float fadeout_from = 50.0;
-		float fadeout_to = 300.0;
-
-		Size2i full_screen_size = Size2i();
-		Size2i half_screen_size = Size2i();
-		Size2i quarter_screen_size = Size2i();
-	};
-
-	void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, RS::EnvironmentSSAOQuality p_ssao_quality, RS::EnvironmentSSILQuality p_ssil_quality, bool p_invalidate_uniform_set, bool p_ssao_half_size, bool p_ssil_half_size, Size2i p_full_screen_size, const CameraMatrix &p_projection);
-
-	void gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID> p_ao_slices, const SSAOSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set);
-	void generate_ssao(RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_upscale_buffer, RID p_importance_map, RID p_importance_map_pong, const CameraMatrix &p_projection, const SSAOSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set);
-
-	void gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID> p_ssil_slices, const Vector<RID> p_edges_slices, const SSILSettings &p_settings, bool p_adaptive_base_pass, RID p_gather_uniform_set, RID p_importance_map_uniform_set, RID p_projection_uniform_set);
-	void screen_space_indirect_lighting(RID p_diffuse, RID p_destination, RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_importance_map, RID p_importance_map_pong, RID p_edges, const Vector<RID> p_edges_slices, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set, RID &r_projection_uniform_set);
-
 	void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
 
-	void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
-	void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
 	void sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality);
 
 	void sort_buffer(RID p_uniform_set, int p_size);

+ 1 - 1
servers/rendering/renderer_rd/environment/gi.h

@@ -755,7 +755,7 @@ public:
 		SHADER_SPECIALIZATION_HALF_RES = 1 << 0,
 		SHADER_SPECIALIZATION_USE_FULL_PROJECTION_MATRIX = 1 << 1,
 		SHADER_SPECIALIZATION_USE_VRS = 1 << 2,
-		SHADER_SPECIALIZATION_VARIATIONS = 0x07,
+		SHADER_SPECIALIZATION_VARIATIONS = 8,
 	};
 
 	RID default_voxel_gi_buffer;

+ 22 - 4
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp

@@ -66,6 +66,13 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular()
 		}
 
 		specular = RD::get_singleton()->texture_create(tf, RD::TextureView());
+		if (view_count == 1) {
+			specular_views[0] = specular;
+		} else {
+			for (uint32_t v = 0; v < view_count; v++) {
+				specular_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), specular, v, 0);
+			}
+		}
 
 		if (msaa == RS::VIEWPORT_MSAA_DISABLED) {
 			{
@@ -80,6 +87,14 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::ensure_specular()
 			tf.usage_bits = RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT;
 			specular_msaa = RD::get_singleton()->texture_create(tf, RD::TextureView());
 
+			if (view_count == 1) {
+				specular_msaa_views[0] = specular_msaa;
+			} else {
+				for (uint32_t v = 0; v < view_count; v++) {
+					specular_msaa_views[v] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), specular_msaa, v, 0);
+				}
+			}
+
 			{
 				Vector<RID> fb;
 				fb.push_back(specular_msaa);
@@ -175,6 +190,8 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::clear() {
 	for (uint32_t v = 0; v < RendererSceneRender::MAX_RENDER_VIEWS; v++) {
 		color_views[v] = RID();
 		depth_views[v] = RID();
+		specular_views[v] = RID();
+		specular_msaa_views[v] = RID();
 		color_msaa_views[v] = RID();
 		depth_msaa_views[v] = RID();
 		normal_roughness_views[v] = RID();
@@ -1749,9 +1766,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
 		for (uint32_t v = 0; v < render_buffer->view_count; v++) {
 			RD::get_singleton()->texture_resolve_multisample(render_buffer->color_msaa_views[v], render_buffer->color_views[v]);
 		}
-		// TODO mame this do multiview
 		if (using_separate_specular) {
-			RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa, render_buffer->specular);
+			for (uint32_t v = 0; v < render_buffer->view_count; v++) {
+				RD::get_singleton()->texture_resolve_multisample(render_buffer->specular_msaa_views[v], render_buffer->specular_views[v]);
+			}
 		}
 	}
 
@@ -1772,12 +1790,12 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
 		if (using_ssr) {
 			RENDER_TIMESTAMP("Screen-Space Reflections");
 			RD::get_singleton()->draw_command_begin_label("Process Screen-Space Reflections");
-			_process_ssr(p_render_data->render_buffers, color_only_framebuffer, render_buffer->normal_roughness_buffer, render_buffer->specular, render_buffer->specular, Color(0, 0, 0, 1), p_render_data->environment, p_render_data->cam_projection, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED);
+			_process_ssr(p_render_data->render_buffers, color_only_framebuffer, render_buffer->normal_roughness_views, render_buffer->specular, render_buffer->specular_views, Color(0, 0, 0, 1), p_render_data->environment, p_render_data->view_projection, p_render_data->view_eye_offset, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED);
 			RD::get_singleton()->draw_command_end_label();
 		} else {
 			//just mix specular back
 			RENDER_TIMESTAMP("Merge Specular");
-			RendererCompositorRD::singleton->get_effects()->merge_specular(color_only_framebuffer, render_buffer->specular, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED ? RID() : render_buffer->color, RID());
+			copy_effects->merge_specular(color_only_framebuffer, render_buffer->specular, render_buffer->msaa == RS::VIEWPORT_MSAA_DISABLED ? RID() : render_buffer->color, RID(), p_render_data->view_count);
 		}
 	}
 

+ 2 - 0
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h

@@ -117,6 +117,8 @@ class RenderForwardClustered : public RendererSceneRenderRD {
 		uint32_t view_count = 1;
 		RID color_views[RendererSceneRender::MAX_RENDER_VIEWS]; // we should rewrite this so we get access to the existing views in our renderer, something we can address when we reorg this
 		RID depth_views[RendererSceneRender::MAX_RENDER_VIEWS]; // we should rewrite this so we get access to the existing views in our renderer, something we can address when we reorg this
+		RID specular_views[RendererSceneRender::MAX_RENDER_VIEWS];
+		RID specular_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
 		RID color_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
 		RID depth_msaa_views[RendererSceneRender::MAX_RENDER_VIEWS];
 		RID normal_roughness_views[RendererSceneRender::MAX_RENDER_VIEWS];

+ 39 - 322
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

@@ -1891,60 +1891,9 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
 		rb->ss_effects.linear_depth_slices.clear();
 	}
 
-	if (rb->ss_effects.ssao.ao_final.is_valid()) {
-		RD::get_singleton()->free(rb->ss_effects.ssao.ao_deinterleaved);
-		RD::get_singleton()->free(rb->ss_effects.ssao.ao_pong);
-		RD::get_singleton()->free(rb->ss_effects.ssao.ao_final);
-
-		RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[0]);
-		RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[1]);
-
-		rb->ss_effects.ssao.ao_deinterleaved = RID();
-		rb->ss_effects.ssao.ao_pong = RID();
-		rb->ss_effects.ssao.ao_final = RID();
-		rb->ss_effects.ssao.importance_map[0] = RID();
-		rb->ss_effects.ssao.importance_map[1] = RID();
-
-		rb->ss_effects.ssao.ao_deinterleaved_slices.clear();
-		rb->ss_effects.ssao.ao_pong_slices.clear();
-	}
-
-	if (rb->ss_effects.ssil.ssil_final.is_valid()) {
-		RD::get_singleton()->free(rb->ss_effects.ssil.ssil_final);
-		RD::get_singleton()->free(rb->ss_effects.ssil.deinterleaved);
-		RD::get_singleton()->free(rb->ss_effects.ssil.pong);
-		RD::get_singleton()->free(rb->ss_effects.ssil.edges);
-		RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[0]);
-		RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[1]);
-
-		rb->ss_effects.ssil.ssil_final = RID();
-		rb->ss_effects.ssil.deinterleaved = RID();
-		rb->ss_effects.ssil.pong = RID();
-		rb->ss_effects.ssil.edges = RID();
-		rb->ss_effects.ssil.deinterleaved_slices.clear();
-		rb->ss_effects.ssil.pong_slices.clear();
-		rb->ss_effects.ssil.edges_slices.clear();
-		rb->ss_effects.ssil.importance_map[0] = RID();
-		rb->ss_effects.ssil.importance_map[1] = RID();
-
-		RD::get_singleton()->free(rb->ss_effects.last_frame);
-		rb->ss_effects.last_frame = RID();
-		rb->ss_effects.last_frame_slices.clear();
-	}
-
-	if (rb->ssr.blur_radius[0].is_valid()) {
-		RD::get_singleton()->free(rb->ssr.blur_radius[0]);
-		RD::get_singleton()->free(rb->ssr.blur_radius[1]);
-		rb->ssr.blur_radius[0] = RID();
-		rb->ssr.blur_radius[1] = RID();
-	}
-
-	if (rb->ssr.depth_scaled.is_valid()) {
-		RD::get_singleton()->free(rb->ssr.depth_scaled);
-		rb->ssr.depth_scaled = RID();
-		RD::get_singleton()->free(rb->ssr.normal_scaled);
-		rb->ssr.normal_scaled = RID();
-	}
+	ss_effects->ssao_free(rb->ss_effects.ssao);
+	ss_effects->ssil_free(rb->ss_effects.ssil);
+	ss_effects->ssr_free(rb->ssr);
 
 	if (rb->taa.history.is_valid()) {
 		RD::get_singleton()->free(rb->taa.history);
@@ -1982,7 +1931,9 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri
 	RendererCompositorRD::singleton->get_effects()->sub_surface_scattering(rb->internal_texture, rb->sss_texture, rb->depth_texture, p_camera, Size2i(rb->internal_width, rb->internal_height), sss_scale, sss_depth_scale, sss_quality);
 }
 
-void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) {
+void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_slices, RID p_specular_buffer, const RID *p_metallic_slices, const Color &p_metallic_mask, RID p_environment, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive) {
+	ERR_FAIL_NULL(ss_effects);
+
 	RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
 	ERR_FAIL_COND(!rb);
 
@@ -1990,7 +1941,7 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
 
 	if (!can_use_effects) {
 		//just copy
-		RendererCompositorRD::singleton->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, RID());
+		copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, RID(), rb->view_count);
 		return;
 	}
 
@@ -1999,42 +1950,23 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
 
 	ERR_FAIL_COND(!env->ssr_enabled);
 
-	if (rb->ssr.depth_scaled.is_null()) {
-		RD::TextureFormat tf;
-		tf.format = RD::DATA_FORMAT_R32_SFLOAT;
-		tf.width = rb->internal_width / 2;
-		tf.height = rb->internal_height / 2;
-		tf.texture_type = RD::TEXTURE_TYPE_2D;
-		tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
-
-		rb->ssr.depth_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView());
-
-		tf.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
-
-		rb->ssr.normal_scaled = RD::get_singleton()->texture_create(tf, RD::TextureView());
+	Size2i half_size = Size2i(rb->internal_width / 2, rb->internal_height / 2);
+	if (rb->ssr.output.is_null()) {
+		ss_effects->ssr_allocate_buffers(rb->ssr, _render_buffers_get_color_format(), ssr_roughness_quality, half_size, rb->view_count);
 	}
-
-	if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) {
-		RD::TextureFormat tf;
-		tf.format = RD::DATA_FORMAT_R8_UNORM;
-		tf.width = rb->internal_width / 2;
-		tf.height = rb->internal_height / 2;
-		tf.texture_type = RD::TEXTURE_TYPE_2D;
-		tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
-
-		rb->ssr.blur_radius[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
-		rb->ssr.blur_radius[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
-	}
-
-	if (rb->blur[0].texture.is_null()) {
-		_allocate_blur_textures(rb);
+	RID texture_slices[RendererSceneRender::MAX_RENDER_VIEWS];
+	RID depth_slices[RendererSceneRender::MAX_RENDER_VIEWS];
+	for (uint32_t v = 0; v < rb->view_count; v++) {
+		texture_slices[v] = rb->views[v].view_texture;
+		depth_slices[v] = rb->views[v].view_depth;
 	}
-
-	RendererCompositorRD::singleton->get_effects()->screen_space_reflection(rb->internal_texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].layers[0].mipmaps[1].texture, rb->blur[1].layers[0].mipmaps[0].texture, Size2i(rb->internal_width / 2, rb->internal_height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection);
-	RendererCompositorRD::singleton->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, rb->blur[0].layers[0].mipmaps[1].texture);
+	ss_effects->screen_space_reflection(rb->ssr, texture_slices, p_normal_slices, ssr_roughness_quality, p_metallic_slices, p_metallic_mask, depth_slices, half_size, env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, rb->view_count, p_projections, p_eye_offsets);
+	copy_effects->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, rb->ssr.output, rb->view_count);
 }
 
 void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) {
+	ERR_FAIL_NULL(ss_effects);
+
 	RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
 	ERR_FAIL_COND(!rb);
 
@@ -2043,102 +1975,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
 
 	RENDER_TIMESTAMP("Process SSAO");
 
-	if (rb->ss_effects.ssao.ao_final.is_valid() && ssao_using_half_size != ssao_half_size) {
-		RD::get_singleton()->free(rb->ss_effects.ssao.ao_deinterleaved);
-		RD::get_singleton()->free(rb->ss_effects.ssao.ao_pong);
-		RD::get_singleton()->free(rb->ss_effects.ssao.ao_final);
-
-		RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[0]);
-		RD::get_singleton()->free(rb->ss_effects.ssao.importance_map[1]);
-
-		rb->ss_effects.ssao.ao_deinterleaved = RID();
-		rb->ss_effects.ssao.ao_pong = RID();
-		rb->ss_effects.ssao.ao_final = RID();
-		rb->ss_effects.ssao.importance_map[0] = RID();
-		rb->ss_effects.ssao.importance_map[1] = RID();
-		rb->ss_effects.ssao.ao_deinterleaved_slices.clear();
-		rb->ss_effects.ssao.ao_pong_slices.clear();
-	}
-
-	int buffer_width;
-	int buffer_height;
-	int half_width;
-	int half_height;
-	if (ssao_half_size) {
-		buffer_width = (rb->internal_width + 3) / 4;
-		buffer_height = (rb->internal_height + 3) / 4;
-		half_width = (rb->internal_width + 7) / 8;
-		half_height = (rb->internal_height + 7) / 8;
-	} else {
-		buffer_width = (rb->internal_width + 1) / 2;
-		buffer_height = (rb->internal_height + 1) / 2;
-		half_width = (rb->internal_width + 3) / 4;
-		half_height = (rb->internal_height + 3) / 4;
-	}
-	bool uniform_sets_are_invalid = false;
-	if (rb->ss_effects.ssao.ao_deinterleaved.is_null()) {
-		{
-			rb->ss_effects.ssao.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, ssao_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
-		}
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R8G8_UNORM;
-			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
-			tf.width = buffer_width;
-			tf.height = buffer_height;
-			tf.array_layers = 4;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-			rb->ss_effects.ssao.ao_deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_deinterleaved, "SSAO De-interleaved Array");
-			for (uint32_t i = 0; i < 4; i++) {
-				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssao.ao_deinterleaved, i, 0);
-				rb->ss_effects.ssao.ao_deinterleaved_slices.push_back(slice);
-				RD::get_singleton()->set_resource_name(slice, "SSAO De-interleaved Array Layer " + itos(i) + " ");
-			}
-		}
-
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R8G8_UNORM;
-			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
-			tf.width = buffer_width;
-			tf.height = buffer_height;
-			tf.array_layers = 4;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-			rb->ss_effects.ssao.ao_pong = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_pong, "SSAO De-interleaved Array Pong");
-			for (uint32_t i = 0; i < 4; i++) {
-				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssao.ao_pong, i, 0);
-				rb->ss_effects.ssao.ao_pong_slices.push_back(slice);
-				RD::get_singleton()->set_resource_name(slice, "SSAO De-interleaved Array Layer " + itos(i) + " Pong");
-			}
-		}
-
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R8_UNORM;
-			tf.width = half_width;
-			tf.height = half_height;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-			rb->ss_effects.ssao.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.importance_map[0], "SSAO Importance Map");
-			rb->ss_effects.ssao.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.importance_map[1], "SSAO Importance Map Pong");
-		}
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R8_UNORM;
-			tf.width = rb->internal_width;
-			tf.height = rb->internal_height;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-			rb->ss_effects.ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssao.ao_final, "SSAO Final");
-		}
-		ssao_using_half_size = ssao_half_size;
-		uniform_sets_are_invalid = true;
-	}
-
-	EffectsRD::SSAOSettings settings;
+	RendererRD::SSEffects::SSAOSettings settings;
 	settings.radius = env->ssao_radius;
 	settings.intensity = env->ssao_intensity;
 	settings.power = env->ssao_power;
@@ -2153,13 +1990,14 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
 	settings.fadeout_from = ssao_fadeout_from;
 	settings.fadeout_to = ssao_fadeout_to;
 	settings.full_screen_size = Size2i(rb->internal_width, rb->internal_height);
-	settings.half_screen_size = Size2i(buffer_width, buffer_height);
-	settings.quarter_screen_size = Size2i(half_width, half_height);
 
-	RendererCompositorRD::singleton->get_effects()->generate_ssao(p_normal_buffer, rb->ss_effects.ssao.depth_texture_view, rb->ss_effects.ssao.ao_deinterleaved, rb->ss_effects.ssao.ao_deinterleaved_slices, rb->ss_effects.ssao.ao_pong, rb->ss_effects.ssao.ao_pong_slices, rb->ss_effects.ssao.ao_final, rb->ss_effects.ssao.importance_map[0], rb->ss_effects.ssao.importance_map[1], p_projection, settings, uniform_sets_are_invalid, rb->ss_effects.ssao.gather_uniform_set, rb->ss_effects.ssao.importance_map_uniform_set);
+	ss_effects->ssao_allocate_buffers(rb->ss_effects.ssao, settings, rb->ss_effects.linear_depth);
+	ss_effects->generate_ssao(rb->ss_effects.ssao, p_normal_buffer, p_projection, settings);
 }
 
 void RendererSceneRenderRD::_process_ssil(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection, const Transform3D &p_transform) {
+	ERR_FAIL_NULL(ss_effects);
+
 	RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
 	ERR_FAIL_COND(!rb);
 
@@ -2168,133 +2006,7 @@ void RendererSceneRenderRD::_process_ssil(RID p_render_buffers, RID p_environmen
 
 	RENDER_TIMESTAMP("Process SSIL");
 
-	if (rb->ss_effects.ssil.ssil_final.is_valid() && ssil_using_half_size != ssil_half_size) {
-		RD::get_singleton()->free(rb->ss_effects.ssil.ssil_final);
-		RD::get_singleton()->free(rb->ss_effects.ssil.deinterleaved);
-		RD::get_singleton()->free(rb->ss_effects.ssil.pong);
-		RD::get_singleton()->free(rb->ss_effects.ssil.edges);
-		RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[0]);
-		RD::get_singleton()->free(rb->ss_effects.ssil.importance_map[1]);
-
-		rb->ss_effects.ssil.ssil_final = RID();
-		rb->ss_effects.ssil.deinterleaved = RID();
-		rb->ss_effects.ssil.pong = RID();
-		rb->ss_effects.ssil.edges = RID();
-		rb->ss_effects.ssil.deinterleaved_slices.clear();
-		rb->ss_effects.ssil.pong_slices.clear();
-		rb->ss_effects.ssil.edges_slices.clear();
-		rb->ss_effects.ssil.importance_map[0] = RID();
-		rb->ss_effects.ssil.importance_map[1] = RID();
-	}
-
-	int buffer_width;
-	int buffer_height;
-	int half_width;
-	int half_height;
-	if (ssil_half_size) {
-		buffer_width = (rb->width + 3) / 4;
-		buffer_height = (rb->height + 3) / 4;
-		half_width = (rb->width + 7) / 8;
-		half_height = (rb->height + 7) / 8;
-	} else {
-		buffer_width = (rb->width + 1) / 2;
-		buffer_height = (rb->height + 1) / 2;
-		half_width = (rb->width + 3) / 4;
-		half_height = (rb->height + 3) / 4;
-	}
-	bool uniform_sets_are_invalid = false;
-	if (rb->ss_effects.ssil.ssil_final.is_null()) {
-		{
-			rb->ss_effects.ssil.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.linear_depth, 0, ssil_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
-		}
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
-			tf.width = rb->width;
-			tf.height = rb->height;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
-			rb->ss_effects.ssil.ssil_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.ssil_final, "SSIL texture");
-			RD::get_singleton()->texture_clear(rb->ss_effects.ssil.ssil_final, Color(0, 0, 0, 0), 0, 1, 0, 1);
-			if (rb->ss_effects.last_frame.is_null()) {
-				tf.mipmaps = 6;
-				rb->ss_effects.last_frame = RD::get_singleton()->texture_create(tf, RD::TextureView());
-				RD::get_singleton()->set_resource_name(rb->ss_effects.last_frame, "Last Frame Radiance");
-				RD::get_singleton()->texture_clear(rb->ss_effects.last_frame, Color(0, 0, 0, 0), 0, tf.mipmaps, 0, 1);
-				for (uint32_t i = 0; i < 6; i++) {
-					RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.last_frame, 0, i);
-					rb->ss_effects.last_frame_slices.push_back(slice);
-					RD::get_singleton()->set_resource_name(slice, "Last Frame Radiance Mip " + itos(i) + " ");
-				}
-			}
-		}
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
-			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
-			tf.width = buffer_width;
-			tf.height = buffer_height;
-			tf.array_layers = 4;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-			rb->ss_effects.ssil.deinterleaved = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.deinterleaved, "SSIL deinterleaved buffer");
-			for (uint32_t i = 0; i < 4; i++) {
-				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.deinterleaved, i, 0);
-				rb->ss_effects.ssil.deinterleaved_slices.push_back(slice);
-				RD::get_singleton()->set_resource_name(slice, "SSIL deinterleaved buffer array " + itos(i) + " ");
-			}
-		}
-
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
-			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
-			tf.width = buffer_width;
-			tf.height = buffer_height;
-			tf.array_layers = 4;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-			rb->ss_effects.ssil.pong = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.pong, "SSIL deinterleaved pong buffer");
-			for (uint32_t i = 0; i < 4; i++) {
-				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.pong, i, 0);
-				rb->ss_effects.ssil.pong_slices.push_back(slice);
-				RD::get_singleton()->set_resource_name(slice, "SSIL deinterleaved buffer pong array " + itos(i) + " ");
-			}
-		}
-
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R8_UNORM;
-			tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
-			tf.width = buffer_width;
-			tf.height = buffer_height;
-			tf.array_layers = 4;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-			rb->ss_effects.ssil.edges = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.edges, "SSIL edges buffer");
-			for (uint32_t i = 0; i < 4; i++) {
-				RID slice = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), rb->ss_effects.ssil.edges, i, 0);
-				rb->ss_effects.ssil.edges_slices.push_back(slice);
-				RD::get_singleton()->set_resource_name(slice, "SSIL edges buffer slice " + itos(i) + " ");
-			}
-		}
-
-		{
-			RD::TextureFormat tf;
-			tf.format = RD::DATA_FORMAT_R8_UNORM;
-			tf.width = half_width;
-			tf.height = half_height;
-			tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
-			rb->ss_effects.ssil.importance_map[0] = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.importance_map[0], "SSIL Importance Map");
-			rb->ss_effects.ssil.importance_map[1] = RD::get_singleton()->texture_create(tf, RD::TextureView());
-			RD::get_singleton()->set_resource_name(rb->ss_effects.ssil.importance_map[1], "SSIL Importance Map Pong");
-		}
-		uniform_sets_are_invalid = true;
-		ssil_using_half_size = ssil_half_size;
-	}
-
-	EffectsRD::SSILSettings settings;
+	RendererRD::SSEffects::SSILSettings settings;
 	settings.radius = env->ssil_radius;
 	settings.intensity = env->ssil_intensity;
 	settings.sharpness = env->ssil_sharpness;
@@ -2307,8 +2019,6 @@ void RendererSceneRenderRD::_process_ssil(RID p_render_buffers, RID p_environmen
 	settings.fadeout_from = ssil_fadeout_from;
 	settings.fadeout_to = ssil_fadeout_to;
 	settings.full_screen_size = Size2i(rb->width, rb->height);
-	settings.half_screen_size = Size2i(buffer_width, buffer_height);
-	settings.quarter_screen_size = Size2i(half_width, half_height);
 
 	CameraMatrix correction;
 	correction.set_depth_correction(true);
@@ -2317,7 +2027,8 @@ void RendererSceneRenderRD::_process_ssil(RID p_render_buffers, RID p_environmen
 	transform.set_origin(Vector3(0.0, 0.0, 0.0));
 	CameraMatrix last_frame_projection = rb->ss_effects.last_frame_projection * CameraMatrix(rb->ss_effects.last_frame_transform.affine_inverse()) * CameraMatrix(transform) * projection.inverse();
 
-	RendererCompositorRD::singleton->get_effects()->screen_space_indirect_lighting(rb->ss_effects.last_frame, rb->ss_effects.ssil.ssil_final, p_normal_buffer, rb->ss_effects.ssil.depth_texture_view, rb->ss_effects.ssil.deinterleaved, rb->ss_effects.ssil.deinterleaved_slices, rb->ss_effects.ssil.pong, rb->ss_effects.ssil.pong_slices, rb->ss_effects.ssil.importance_map[0], rb->ss_effects.ssil.importance_map[1], rb->ss_effects.ssil.edges, rb->ss_effects.ssil.edges_slices, p_projection, last_frame_projection, settings, uniform_sets_are_invalid, rb->ss_effects.ssil.gather_uniform_set, rb->ss_effects.ssil.importance_map_uniform_set, rb->ss_effects.ssil.projection_uniform_set);
+	ss_effects->ssil_allocate_buffers(rb->ss_effects.ssil, settings, rb->ss_effects.linear_depth);
+	ss_effects->screen_space_indirect_lighting(rb->ss_effects.ssil, p_normal_buffer, p_projection, last_frame_projection, settings);
 	rb->ss_effects.last_frame_projection = projection;
 	rb->ss_effects.last_frame_transform = transform;
 }
@@ -2326,15 +2037,15 @@ void RendererSceneRenderRD::_copy_framebuffer_to_ssil(RID p_render_buffers) {
 	RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
 	ERR_FAIL_COND(!rb);
 
-	if (rb->ss_effects.last_frame.is_valid()) {
-		copy_effects->copy_to_rect(rb->texture, rb->ss_effects.last_frame, Rect2i(0, 0, rb->width, rb->height));
+	if (rb->ss_effects.ssil.last_frame.is_valid()) {
+		copy_effects->copy_to_rect(rb->texture, rb->ss_effects.ssil.last_frame, Rect2i(0, 0, rb->width, rb->height));
 
 		int width = rb->width;
 		int height = rb->height;
-		for (int i = 0; i < rb->ss_effects.last_frame_slices.size() - 1; i++) {
+		for (int i = 0; i < rb->ss_effects.ssil.last_frame_slices.size() - 1; i++) {
 			width = MAX(1, width >> 1);
 			height = MAX(1, height >> 1);
-			copy_effects->make_mipmap(rb->ss_effects.last_frame_slices[i], rb->ss_effects.last_frame_slices[i + 1], Size2i(width, height));
+			copy_effects->make_mipmap(rb->ss_effects.ssil.last_frame_slices[i], rb->ss_effects.ssil.last_frame_slices[i + 1], Size2i(width, height));
 		}
 	}
 }
@@ -5031,7 +4742,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
 		RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //use a later barrier
 	}
 
-	if (p_render_data->render_buffers.is_valid()) {
+	if (p_render_data->render_buffers.is_valid() && ss_effects) {
 		if (p_use_ssao || p_use_ssil) {
 			RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers);
 			ERR_FAIL_COND(!rb);
@@ -5056,7 +4767,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
 				invalidate_uniform_set = true;
 			}
 
-			RendererCompositorRD::singleton->get_effects()->downsample_depth(rb->depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, Size2i(rb->width, rb->height), p_render_data->cam_projection);
+			ss_effects->downsample_depth(rb->depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, Size2i(rb->width, rb->height), p_render_data->cam_projection);
 		}
 
 		if (p_use_ssao) {
@@ -6000,6 +5711,9 @@ void fog() {
 	copy_effects = memnew(RendererRD::CopyEffects(!can_use_storage));
 	tone_mapper = memnew(RendererRD::ToneMapper);
 	vrs = memnew(RendererRD::VRS);
+	if (can_use_storage) {
+		ss_effects = memnew(RendererRD::SSEffects);
+	}
 }
 
 RendererSceneRenderRD::~RendererSceneRenderRD() {
@@ -6017,6 +5731,9 @@ RendererSceneRenderRD::~RendererSceneRenderRD() {
 	if (vrs) {
 		memdelete(vrs);
 	}
+	if (ss_effects) {
+		memdelete(ss_effects);
+	}
 
 	for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) {
 		RD::get_singleton()->free(E.value.cubemap);

+ 6 - 38
servers/rendering/renderer_rd/renderer_scene_render_rd.h

@@ -37,6 +37,7 @@
 #include "servers/rendering/renderer_rd/cluster_builder_rd.h"
 #include "servers/rendering/renderer_rd/effects/bokeh_dof.h"
 #include "servers/rendering/renderer_rd/effects/copy_effects.h"
+#include "servers/rendering/renderer_rd/effects/ss_effects.h"
 #include "servers/rendering/renderer_rd/effects/tone_mapper.h"
 #include "servers/rendering/renderer_rd/effects/vrs.h"
 #include "servers/rendering/renderer_rd/environment/gi.h"
@@ -141,7 +142,7 @@ protected:
 	virtual RID _render_buffers_get_velocity_texture(RID p_render_buffers) = 0;
 
 	void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection);
-	void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive);
+	void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, const Color &p_metallic_mask, RID p_environment, const CameraMatrix *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
 	void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera);
 	void _process_ssil(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection, const Transform3D &p_transform);
 	void _copy_framebuffer_to_ssil(RID p_render_buffers);
@@ -163,6 +164,7 @@ protected:
 	PagedArrayPool<GeometryInstance *> cull_argument_pool;
 	PagedArray<GeometryInstance *> cull_argument; //need this to exist
 
+	RendererRD::SSEffects *ss_effects = nullptr;
 	RendererRD::GI gi;
 	RendererSceneSkyRD sky;
 
@@ -418,7 +420,6 @@ private:
 
 	RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
 	bool ssao_half_size = false;
-	bool ssao_using_half_size = false;
 	float ssao_adaptive_target = 0.5;
 	int ssao_blur_passes = 2;
 	float ssao_fadeout_from = 50.0;
@@ -561,47 +562,14 @@ private:
 
 			RID downsample_uniform_set;
 
-			RID last_frame;
-			Vector<RID> last_frame_slices;
-
 			CameraMatrix last_frame_projection;
 			Transform3D last_frame_transform;
 
-			struct SSAO {
-				RID ao_deinterleaved;
-				Vector<RID> ao_deinterleaved_slices;
-				RID ao_pong;
-				Vector<RID> ao_pong_slices;
-				RID ao_final;
-				RID importance_map[2];
-				RID depth_texture_view;
-
-				RID gather_uniform_set;
-				RID importance_map_uniform_set;
-			} ssao;
-
-			struct SSIL {
-				RID ssil_final;
-				RID deinterleaved;
-				Vector<RID> deinterleaved_slices;
-				RID pong;
-				Vector<RID> pong_slices;
-				RID edges;
-				Vector<RID> edges_slices;
-				RID importance_map[2];
-				RID depth_texture_view;
-
-				RID gather_uniform_set;
-				RID importance_map_uniform_set;
-				RID projection_uniform_set;
-			} ssil;
+			RendererRD::SSEffects::SSAORenderBuffers ssao;
+			RendererRD::SSEffects::SSILRenderBuffers ssil;
 		} ss_effects;
 
-		struct SSR {
-			RID normal_scaled;
-			RID depth_scaled;
-			RID blur_radius[2];
-		} ssr;
+		RendererRD::SSEffects::SSRRenderBuffers ssr;
 
 		struct TAA {
 			RID history;

+ 24 - 14
servers/rendering/renderer_rd/shaders/screen_space_reflection.glsl → servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl

@@ -32,12 +32,17 @@ layout(push_constant, std430) uniform Params {
 	bool use_half_res;
 	uint metallic_mask;
 
-	mat4 projection;
+	uint view_index;
+	uint pad1;
+	uint pad2;
+	uint pad3;
 }
 params;
 
+#include "screen_space_reflection_inc.glsl"
+
 vec2 view_to_screen(vec3 view_pos, out float w) {
-	vec4 projected = params.projection * vec4(view_pos, 1.0);
+	vec4 projected = scene_data.projection[params.view_index] * vec4(view_pos, 1.0);
 	projected.xyz /= projected.w;
 	projected.xy = projected.xy * 0.5 + 0.5;
 	w = projected.w;
@@ -46,24 +51,16 @@ vec2 view_to_screen(vec3 view_pos, out float w) {
 
 #define M_PI 3.14159265359
 
-vec3 reconstructCSPosition(vec2 S, float z) {
-	if (params.orthogonal) {
-		return vec3((S.xy * params.proj_info.xy + params.proj_info.zw), z);
-	} else {
-		return vec3((S.xy * params.proj_info.xy + params.proj_info.zw) * z, z);
-	}
-}
-
 void main() {
 	// Pixel being shaded
 	ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
 
-	if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing
+	if (any(greaterThanEqual(ssC.xy, params.screen_size))) { //too large, do nothing
 		return;
 	}
 
 	vec2 pixel_size = 1.0 / vec2(params.screen_size);
-	vec2 uv = vec2(ssC) * pixel_size;
+	vec2 uv = vec2(ssC.xy) * pixel_size;
 
 	uv += pixel_size * 0.5;
 
@@ -77,7 +74,12 @@ void main() {
 	normal = normalize(normal);
 	normal.y = -normal.y; //because this code reads flipped
 
-	vec3 view_dir = normalize(vertex);
+	vec3 view_dir;
+	if (sc_multiview) {
+		view_dir = normalize(vertex + scene_data.eye_offset[params.view_index].xyz);
+	} else {
+		view_dir = normalize(vertex);
+	}
 	vec3 ray_dir = normalize(reflect(view_dir, normal));
 
 	if (dot(ray_dir, normal) < 0.001) {
@@ -154,6 +156,11 @@ void main() {
 		// convert to linear depth
 
 		depth = imageLoad(source_depth, ivec2(pos - 0.5)).r;
+		if (sc_multiview) {
+			depth = depth * 2.0 - 1.0;
+			depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
+			depth = -depth;
+		}
 
 		z_from = z_to;
 		z_to = z / w;
@@ -222,13 +229,16 @@ void main() {
 				blur_radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h);
 			}
 		}
+
+		// Isn't this going to be overwritten after our endif?
 		final_color = imageLoad(source_diffuse, ivec2((final_pos - 0.5) * pixel_size));
 
 		imageStore(blur_radius_image, ssC, vec4(blur_radius / 255.0)); //stored in r8
 
-#endif
+#endif // MODE_ROUGH
 
 		final_color = vec4(imageLoad(source_diffuse, ivec2(final_pos - 0.5)).rgb, fade * margin_blend);
+
 		//change blend by metallic
 		vec4 metallic_mask = unpackUnorm4x8(params.metallic_mask);
 		final_color.a *= dot(metallic_mask, texelFetch(source_metallic, ssC << 1, 0));

+ 7 - 13
servers/rendering/renderer_rd/shaders/screen_space_reflection_filter.glsl → servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_filter.glsl

@@ -22,7 +22,7 @@ layout(push_constant, std430) uniform Params {
 	bool orthogonal;
 	float edge_tolerance;
 	int increment;
-	uint pad;
+	uint view_index;
 
 	ivec2 screen_size;
 	bool vertical;
@@ -30,6 +30,8 @@ layout(push_constant, std430) uniform Params {
 }
 params;
 
+#include "screen_space_reflection_inc.glsl"
+
 #define GAUSS_TABLE_SIZE 15
 
 const float gauss_table[GAUSS_TABLE_SIZE + 1] = float[](
@@ -64,14 +66,6 @@ float gauss_weight(float p_val) {
 
 #define M_PI 3.14159265359
 
-vec3 reconstructCSPosition(vec2 S, float z) {
-	if (params.orthogonal) {
-		return vec3((S.xy * params.proj_info.xy + params.proj_info.zw), z);
-	} else {
-		return vec3((S.xy * params.proj_info.xy + params.proj_info.zw) * z, z);
-	}
-}
-
 void do_filter(inout vec4 accum, inout float accum_radius, inout float divisor, ivec2 texcoord, ivec2 increment, vec3 p_pos, vec3 normal, float p_limit_radius) {
 	for (int i = 1; i < params.steps; i++) {
 		float d = float(i * params.increment);
@@ -110,7 +104,7 @@ void main() {
 	// Pixel being shaded
 	ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
 
-	if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing
+	if (any(greaterThanEqual(ssC.xy, params.screen_size))) { //too large, do nothing
 		return;
 	}
 
@@ -130,13 +124,13 @@ void main() {
 	ivec2 direction = ivec2(params.increment, 0);
 #endif
 	float depth = imageLoad(source_depth, ssC).r;
-	vec3 pos = reconstructCSPosition(vec2(ssC) + 0.5, depth);
+	vec3 pos = reconstructCSPosition(vec2(ssC.xy) + 0.5, depth);
 	vec3 normal = imageLoad(source_normal, ssC).xyz * 2.0 - 1.0;
 	normal = normalize(normal);
 	normal.y = -normal.y;
 
-	do_filter(accum, accum_radius, divisor, ssC, direction, pos, normal, radius);
-	do_filter(accum, accum_radius, divisor, ssC, -direction, pos, normal, radius);
+	do_filter(accum, accum_radius, divisor, ssC.xy, direction, pos, normal, radius);
+	do_filter(accum, accum_radius, divisor, ssC.xy, -direction, pos, normal, radius);
 
 	if (divisor > 0.0) {
 		accum /= divisor;

+ 28 - 0
servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_inc.glsl

@@ -0,0 +1,28 @@
+layout(constant_id = 0) const bool sc_multiview = false;
+
+layout(set = 4, binding = 0, std140) uniform SceneData {
+	mat4x4 projection[2];
+	mat4x4 inv_projection[2];
+	vec4 eye_offset[2];
+}
+scene_data;
+
+vec3 reconstructCSPosition(vec2 screen_pos, float z) {
+	if (sc_multiview) {
+		vec4 pos;
+		pos.xy = (2.0 * vec2(screen_pos) / vec2(params.screen_size)) - 1.0;
+		pos.z = z * 2.0 - 1.0;
+		pos.w = 1.0;
+
+		pos = scene_data.inv_projection[params.view_index] * pos;
+		pos.xyz /= pos.w;
+
+		return pos.xyz;
+	} else {
+		if (params.orthogonal) {
+			return vec3((screen_pos.xy * params.proj_info.xy + params.proj_info.zw), z);
+		} else {
+			return vec3((screen_pos.xy * params.proj_info.xy + params.proj_info.zw) * z, z);
+		}
+	}
+}

+ 32 - 16
servers/rendering/renderer_rd/shaders/screen_space_reflection_scale.glsl → servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl

@@ -6,6 +6,11 @@
 
 layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
 
+/* Specialization Constants (Toggles) */
+
+layout(constant_id = 0) const bool sc_multiview = false;
+
+/* inputs */
 layout(set = 0, binding = 0) uniform sampler2D source_ssr;
 layout(set = 1, binding = 0) uniform sampler2D source_depth;
 layout(set = 1, binding = 1) uniform sampler2D source_normal;
@@ -28,7 +33,7 @@ void main() {
 	// Pixel being shaded
 	ivec2 ssC = ivec2(gl_GlobalInvocationID.xy);
 
-	if (any(greaterThanEqual(ssC, params.screen_size))) { //too large, do nothing
+	if (any(greaterThanEqual(ssC.xy, params.screen_size))) { //too large, do nothing
 		return;
 	}
 	//do not filter, SSR will generate arctifacts if this is done
@@ -57,13 +62,19 @@ void main() {
 			normal.xyz += nr.xyz * 2.0 - 1.0;
 			normal.w += nr.w;
 
-			d = d * 2.0 - 1.0;
-			if (params.orthogonal) {
-				d = ((d + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
+			if (sc_multiview) {
+				// we're doing a full unproject so we need the value as is.
+				depth += d;
 			} else {
-				d = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - d * (params.camera_z_far - params.camera_z_near));
+				// unproject our Z value so we can use it directly.
+				d = d * 2.0 - 1.0;
+				if (params.orthogonal) {
+					d = ((d + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
+				} else {
+					d = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - d * (params.camera_z_far - params.camera_z_near));
+				}
+				depth += -d;
 			}
-			depth += -d;
 		}
 
 		color /= 4.0;
@@ -71,17 +82,22 @@ void main() {
 		normal.xyz = normalize(normal.xyz / 4.0) * 0.5 + 0.5;
 		normal.w /= 4.0;
 	} else {
-		color = texelFetch(source_ssr, ssC << 1, 0);
-		depth = texelFetch(source_depth, ssC << 1, 0).r;
-		normal = texelFetch(source_normal, ssC << 1, 0);
-
-		depth = depth * 2.0 - 1.0;
-		if (params.orthogonal) {
-			depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
-		} else {
-			depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
+		ivec2 ofs = ssC << 1;
+
+		color = texelFetch(source_ssr, ofs, 0);
+		depth = texelFetch(source_depth, ofs, 0).r;
+		normal = texelFetch(source_normal, ofs, 0);
+
+		if (!sc_multiview) {
+			// unproject our Z value so we can use it directly.
+			depth = depth * 2.0 - 1.0;
+			if (params.orthogonal) {
+				depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
+			} else {
+				depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
+			}
+			depth = -depth;
 		}
-		depth = -depth;
 	}
 
 	imageStore(dest_ssr, ssC, color);

+ 112 - 0
servers/rendering/renderer_rd/shaders/effects/specular_merge.glsl

@@ -0,0 +1,112 @@
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
+#extension GL_EXT_multiview : enable
+#endif
+
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#define ViewIndex gl_ViewIndex
+#else // has_VK_KHR_multiview
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
+#endif // has_VK_KHR_multiview
+#else // USE_MULTIVIEW
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
+
+#ifdef USE_MULTIVIEW
+layout(location = 0) out vec3 uv_interp;
+#else // USE_MULTIVIEW
+layout(location = 0) out vec2 uv_interp;
+#endif //USE_MULTIVIEW
+
+void main() {
+	vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+
+#ifdef USE_MULTIVIEW
+	uv_interp = vec3(base_arr[gl_VertexIndex], ViewIndex);
+
+	gl_Position = vec4(uv_interp.xy * 2.0 - 1.0, 0.0, 1.0);
+#else
+	uv_interp = base_arr[gl_VertexIndex];
+
+	gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+#endif
+}
+
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#if defined(USE_MULTIVIEW) && defined(has_VK_KHR_multiview)
+#extension GL_EXT_multiview : enable
+#endif
+
+#ifdef USE_MULTIVIEW
+#ifdef has_VK_KHR_multiview
+#define ViewIndex gl_ViewIndex
+#else // has_VK_KHR_multiview
+// !BAS! This needs to become an input once we implement our fallback!
+#define ViewIndex 0
+#endif // has_VK_KHR_multiview
+#else // USE_MULTIVIEW
+// Set to zero, not supported in non stereo
+#define ViewIndex 0
+#endif //USE_MULTIVIEW
+
+#ifdef USE_MULTIVIEW
+layout(location = 0) in vec3 uv_interp;
+#else // USE_MULTIVIEW
+layout(location = 0) in vec2 uv_interp;
+#endif //USE_MULTIVIEW
+
+#ifdef USE_MULTIVIEW
+layout(set = 0, binding = 0) uniform sampler2DArray specular;
+#else // USE_MULTIVIEW
+layout(set = 0, binding = 0) uniform sampler2D specular;
+#endif //USE_MULTIVIEW
+
+#ifdef MODE_SSR
+
+#ifdef USE_MULTIVIEW
+layout(set = 1, binding = 0) uniform sampler2DArray ssr;
+#else // USE_MULTIVIEW
+layout(set = 1, binding = 0) uniform sampler2D ssr;
+#endif //USE_MULTIVIEW
+
+#endif
+
+#ifdef MODE_MERGE
+
+#ifdef USE_MULTIVIEW
+layout(set = 2, binding = 0) uniform sampler2DArray diffuse;
+#else // USE_MULTIVIEW
+layout(set = 2, binding = 0) uniform sampler2D diffuse;
+#endif //USE_MULTIVIEW
+
+#endif
+
+layout(location = 0) out vec4 frag_color;
+
+void main() {
+	frag_color.rgb = texture(specular, uv_interp).rgb;
+	frag_color.a = 0.0;
+#ifdef MODE_SSR
+
+	vec4 ssr_color = texture(ssr, uv_interp);
+	frag_color.rgb = mix(frag_color.rgb, ssr_color.rgb, ssr_color.a);
+#endif
+
+#ifdef MODE_MERGE
+	frag_color += texture(diffuse, uv_interp);
+#endif
+	//added using additive blend
+}

+ 0 - 0
servers/rendering/renderer_rd/shaders/ss_effects_downsample.glsl → servers/rendering/renderer_rd/shaders/effects/ss_effects_downsample.glsl


+ 0 - 0
servers/rendering/renderer_rd/shaders/ssao.glsl → servers/rendering/renderer_rd/shaders/effects/ssao.glsl


+ 0 - 0
servers/rendering/renderer_rd/shaders/ssao_blur.glsl → servers/rendering/renderer_rd/shaders/effects/ssao_blur.glsl


+ 0 - 0
servers/rendering/renderer_rd/shaders/ssao_importance_map.glsl → servers/rendering/renderer_rd/shaders/effects/ssao_importance_map.glsl


+ 0 - 0
servers/rendering/renderer_rd/shaders/ssao_interleave.glsl → servers/rendering/renderer_rd/shaders/effects/ssao_interleave.glsl


+ 0 - 0
servers/rendering/renderer_rd/shaders/ssil.glsl → servers/rendering/renderer_rd/shaders/effects/ssil.glsl


+ 0 - 0
servers/rendering/renderer_rd/shaders/ssil_blur.glsl → servers/rendering/renderer_rd/shaders/effects/ssil_blur.glsl


+ 0 - 0
servers/rendering/renderer_rd/shaders/ssil_importance_map.glsl → servers/rendering/renderer_rd/shaders/effects/ssil_importance_map.glsl


+ 0 - 0
servers/rendering/renderer_rd/shaders/ssil_interleave.glsl → servers/rendering/renderer_rd/shaders/effects/ssil_interleave.glsl


+ 0 - 53
servers/rendering/renderer_rd/shaders/specular_merge.glsl

@@ -1,53 +0,0 @@
-#[vertex]
-
-#version 450
-
-#VERSION_DEFINES
-
-layout(location = 0) out vec2 uv_interp;
-
-void main() {
-	vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
-	uv_interp = base_arr[gl_VertexIndex];
-
-	gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
-}
-
-#[fragment]
-
-#version 450
-
-#VERSION_DEFINES
-
-layout(location = 0) in vec2 uv_interp;
-
-layout(set = 0, binding = 0) uniform sampler2D specular;
-
-#ifdef MODE_SSR
-
-layout(set = 1, binding = 0) uniform sampler2D ssr;
-
-#endif
-
-#ifdef MODE_MERGE
-
-layout(set = 2, binding = 0) uniform sampler2D diffuse;
-
-#endif
-
-layout(location = 0) out vec4 frag_color;
-
-void main() {
-	frag_color.rgb = texture(specular, uv_interp).rgb;
-	frag_color.a = 0.0;
-#ifdef MODE_SSR
-
-	vec4 ssr_color = texture(ssr, uv_interp);
-	frag_color.rgb = mix(frag_color.rgb, ssr_color.rgb, ssr_color.a);
-#endif
-
-#ifdef MODE_MERGE
-	frag_color += texture(diffuse, uv_interp);
-#endif
-	//added using additive blend
-}

Some files were not shown because too many files changed in this diff