Prechádzať zdrojové kódy

Merge pull request #65822 from BastiaanOlij/more_reorg_20220915

Move cluster builder, sdfgi and gi structures to clustered renderer, and more
Rémi Verschelde 2 rokov pred
rodič
commit
bff9fcfc1c
52 zmenil súbory, kde vykonal 4976 pridanie a 3939 odobranie
  1. 1 1
      drivers/gles3/environment/fog.cpp
  2. 1 1
      drivers/gles3/environment/fog.h
  3. 12 124
      drivers/gles3/rasterizer_scene_gles3.cpp
  4. 3 74
      drivers/gles3/rasterizer_scene_gles3.h
  5. 131 0
      drivers/gles3/storage/light_storage.cpp
  6. 90 0
      drivers/gles3/storage/light_storage.h
  7. 12 0
      drivers/gles3/storage/texture_storage.cpp
  8. 6 0
      drivers/gles3/storage/texture_storage.h
  9. 1 1
      servers/rendering/dummy/environment/fog.h
  10. 0 35
      servers/rendering/dummy/rasterizer_scene_dummy.h
  11. 47 0
      servers/rendering/dummy/storage/light_storage.h
  12. 6 0
      servers/rendering/dummy/storage/texture_storage.h
  13. 1 1
      servers/rendering/environment/renderer_fog.h
  14. 2 1
      servers/rendering/renderer_rd/effects/fsr.cpp
  15. 3 4
      servers/rendering/renderer_rd/effects/fsr.h
  16. 119 76
      servers/rendering/renderer_rd/effects/ss_effects.cpp
  17. 33 18
      servers/rendering/renderer_rd/effects/ss_effects.h
  18. 8 1
      servers/rendering/renderer_rd/environment/fog.cpp
  19. 31 8
      servers/rendering/renderer_rd/environment/fog.h
  20. 75 60
      servers/rendering/renderer_rd/environment/gi.cpp
  21. 6 6
      servers/rendering/renderer_rd/environment/gi.h
  22. 3 4
      servers/rendering/renderer_rd/environment/sky.cpp
  23. 792 24
      servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
  24. 79 10
      servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
  25. 363 97
      servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
  26. 73 38
      servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
  27. 549 2373
      servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
  28. 50 717
      servers/rendering/renderer_rd/renderer_scene_render_rd.h
  29. 43 0
      servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp
  30. 68 0
      servers/rendering/renderer_rd/storage_rd/forward_id_storage.h
  31. 1135 68
      servers/rendering/renderer_rd/storage_rd/light_storage.cpp
  32. 708 0
      servers/rendering/renderer_rd/storage_rd/light_storage.h
  33. 12 0
      servers/rendering/renderer_rd/storage_rd/material_storage.cpp
  34. 2 0
      servers/rendering/renderer_rd/storage_rd/material_storage.h
  35. 18 0
      servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
  36. 2 0
      servers/rendering/renderer_rd/storage_rd/mesh_storage.h
  37. 15 0
      servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
  38. 2 0
      servers/rendering/renderer_rd/storage_rd/particles_storage.h
  39. 0 33
      servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
  40. 4 30
      servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
  41. 246 1
      servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
  42. 92 1
      servers/rendering/renderer_rd/storage_rd/texture_storage.h
  43. 17 38
      servers/rendering/renderer_rd/storage_rd/utilities.cpp
  44. 40 39
      servers/rendering/renderer_scene_cull.cpp
  45. 1 6
      servers/rendering/renderer_scene_cull.h
  46. 0 38
      servers/rendering/renderer_scene_render.h
  47. 4 4
      servers/rendering/renderer_viewport.cpp
  48. 0 6
      servers/rendering/rendering_method.h
  49. 7 1
      servers/rendering/rendering_server_default.h
  50. 51 0
      servers/rendering/storage/light_storage.h
  51. 6 0
      servers/rendering/storage/texture_storage.h
  52. 6 0
      servers/rendering_server.h

+ 1 - 1
drivers/gles3/environment/fog.cpp

@@ -43,7 +43,7 @@ RID Fog::fog_volume_allocate() {
 void Fog::fog_volume_initialize(RID p_rid) {
 }
 
-void Fog::fog_free(RID p_rid) {
+void Fog::fog_volume_free(RID p_rid) {
 }
 
 void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {

+ 1 - 1
drivers/gles3/environment/fog.h

@@ -46,7 +46,7 @@ public:
 
 	virtual RID fog_volume_allocate() override;
 	virtual void fog_volume_initialize(RID p_rid) override;
-	virtual void fog_free(RID p_rid) override;
+	virtual void fog_volume_free(RID p_rid) override;
 
 	virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override;
 	virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override;

+ 12 - 124
drivers/gles3/rasterizer_scene_gles3.cpp

@@ -34,7 +34,6 @@
 #include "servers/rendering/rendering_server_default.h"
 #include "servers/rendering/rendering_server_globals.h"
 #include "storage/config.h"
-#include "storage/light_storage.h"
 #include "storage/mesh_storage.h"
 #include "storage/texture_storage.h"
 
@@ -70,7 +69,7 @@ void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instances(const RID
 	spot_lights.clear();
 
 	for (uint32_t i = 0; i < p_light_instance_count; i++) {
-		RS::LightType type = RasterizerSceneGLES3::get_singleton()->light_instance_get_type(p_light_instances[i]);
+		RS::LightType type = GLES3::LightStorage::get_singleton()->light_instance_get_type(p_light_instances[i]);
 		switch (type) {
 			case RS::LIGHT_OMNI: {
 				if (omni_light_count < (uint32_t)config->max_lights_per_object) {
@@ -399,32 +398,6 @@ void RasterizerSceneGLES3::_geometry_instance_update(RenderGeometryInstance *p_g
 	ginstance->dirty_list_element.remove_from_list();
 }
 
-/* SHADOW ATLAS API */
-
-RID RasterizerSceneGLES3::shadow_atlas_create() {
-	return RID();
-}
-
-void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
-}
-
-void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
-}
-
-bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
-	return false;
-}
-
-void RasterizerSceneGLES3::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
-}
-
-int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) {
-	return 0;
-}
-
-void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) {
-}
-
 /* SKY API */
 
 void RasterizerSceneGLES3::_free_sky_data(Sky *p_sky) {
@@ -625,7 +598,7 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
 		if (shader_data->uses_light) {
 			sky_globals.directional_light_count = 0;
 			for (int i = 0; i < (int)p_lights.size(); i++) {
-				LightInstance *li = light_instance_owner.get_or_null(p_lights[i]);
+				GLES3::LightInstance *li = GLES3::LightStorage::get_singleton()->get_light_instance(p_lights[i]);
 				if (!li) {
 					continue;
 				}
@@ -1084,38 +1057,6 @@ void RasterizerSceneGLES3::positional_soft_shadow_filter_set_quality(RS::ShadowQ
 void RasterizerSceneGLES3::directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) {
 }
 
-RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
-	RID li = light_instance_owner.make_rid(LightInstance());
-
-	LightInstance *light_instance = light_instance_owner.get_or_null(li);
-
-	light_instance->self = li;
-	light_instance->light = p_light;
-	light_instance->light_type = RSG::light_storage->light_get_type(p_light);
-
-	return li;
-}
-
-void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
-	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
-	ERR_FAIL_COND(!light_instance);
-
-	light_instance->transform = p_transform;
-}
-
-void RasterizerSceneGLES3::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
-	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
-	ERR_FAIL_COND(!light_instance);
-
-	light_instance->aabb = p_aabb;
-}
-
-void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
-}
-
-void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) {
-}
-
 RID RasterizerSceneGLES3::fog_volume_instance_create(RID p_fog_volume) {
 	return RID();
 }
@@ -1134,57 +1075,6 @@ Vector3 RasterizerSceneGLES3::fog_volume_instance_get_position(RID p_fog_volume_
 	return Vector3();
 }
 
-RID RasterizerSceneGLES3::reflection_atlas_create() {
-	return RID();
-}
-
-int RasterizerSceneGLES3::reflection_atlas_get_size(RID p_ref_atlas) const {
-	return 0;
-}
-
-void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
-}
-
-RID RasterizerSceneGLES3::reflection_probe_instance_create(RID p_probe) {
-	return RID();
-}
-
-void RasterizerSceneGLES3::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
-}
-
-void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance) {
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_needs_redraw(RID p_instance) {
-	return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_has_reflection(RID p_instance) {
-	return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
-	return false;
-}
-
-bool RasterizerSceneGLES3::reflection_probe_instance_postprocess_step(RID p_instance) {
-	return true;
-}
-
-RID RasterizerSceneGLES3::decal_instance_create(RID p_decal) {
-	return RID();
-}
-
-void RasterizerSceneGLES3::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
-}
-
-RID RasterizerSceneGLES3::lightmap_instance_create(RID p_lightmap) {
-	return RID();
-}
-
-void RasterizerSceneGLES3::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
-}
-
 RID RasterizerSceneGLES3::voxel_gi_instance_create(RID p_voxel_gi) {
 	return RID();
 }
@@ -1257,13 +1147,13 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const
 			if (inst->omni_light_count) {
 				inst->omni_light_gl_cache.resize(inst->omni_light_count);
 				for (uint32_t j = 0; j < inst->omni_light_count; j++) {
-					inst->omni_light_gl_cache[j] = light_instance_get_gl_id(inst->omni_lights[j]);
+					inst->omni_light_gl_cache[j] = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(inst->omni_lights[j]);
 				}
 			}
 			if (inst->spot_light_count) {
 				inst->spot_light_gl_cache.resize(inst->spot_light_count);
 				for (uint32_t j = 0; j < inst->spot_light_count; j++) {
-					inst->spot_light_gl_cache[j] = light_instance_get_gl_id(inst->spot_lights[j]);
+					inst->spot_light_gl_cache[j] = GLES3::LightStorage::get_singleton()->light_instance_get_gl_id(inst->spot_lights[j]);
 				}
 			}
 		}
@@ -1501,7 +1391,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
 	int num_lights = lights.size();
 
 	for (int i = 0; i < num_lights; i++) {
-		LightInstance *li = light_instance_owner.get_or_null(lights[i]);
+		GLES3::LightInstance *li = GLES3::LightStorage::get_singleton()->get_light_instance(lights[i]);
 		if (!li) {
 			continue;
 		}
@@ -1606,12 +1496,12 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
 	}
 
 	if (r_omni_light_count) {
-		SortArray<InstanceSort<LightInstance>> sorter;
+		SortArray<InstanceSort<GLES3::LightInstance>> sorter;
 		sorter.sort(scene_state.omni_light_sort, r_omni_light_count);
 	}
 
 	if (r_spot_light_count) {
-		SortArray<InstanceSort<LightInstance>> sorter;
+		SortArray<InstanceSort<GLES3::LightInstance>> sorter;
 		sorter.sort(scene_state.spot_light_sort, r_spot_light_count);
 	}
 
@@ -1619,7 +1509,7 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
 		uint32_t index = (i < r_omni_light_count) ? i : i - (r_omni_light_count);
 		LightData &light_data = (i < r_omni_light_count) ? scene_state.omni_lights[index] : scene_state.spot_lights[index];
 		RS::LightType type = (i < r_omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
-		LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
+		GLES3::LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
 		RID base = li->light;
 
 		Transform3D light_transform = li->transform;
@@ -2390,10 +2280,8 @@ bool RasterizerSceneGLES3::free(RID p_rid) {
 		ERR_FAIL_COND_V(!sky, false);
 		_free_sky_data(sky);
 		sky_owner.free(p_rid);
-	} else if (light_instance_owner.owns(p_rid)) {
-		LightInstance *light_instance = light_instance_owner.get_or_null(p_rid);
-		ERR_FAIL_COND_V(!light_instance, false);
-		light_instance_owner.free(p_rid);
+	} else if (GLES3::LightStorage::get_singleton()->owns_light_instance(p_rid)) {
+		GLES3::LightStorage::get_singleton()->light_instance_free(p_rid);
 	} else if (RSG::camera_attributes->owns_camera_attributes(p_rid)) {
 		//not much to delete, just free it
 		RSG::camera_attributes->camera_attributes_free(p_rid);
@@ -2433,13 +2321,13 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
 
 		uint32_t light_buffer_size = config->max_renderable_lights * sizeof(LightData);
 		scene_state.omni_lights = memnew_arr(LightData, config->max_renderable_lights);
-		scene_state.omni_light_sort = memnew_arr(InstanceSort<LightInstance>, config->max_renderable_lights);
+		scene_state.omni_light_sort = memnew_arr(InstanceSort<GLES3::LightInstance>, config->max_renderable_lights);
 		glGenBuffers(1, &scene_state.omni_light_buffer);
 		glBindBuffer(GL_UNIFORM_BUFFER, scene_state.omni_light_buffer);
 		glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);
 
 		scene_state.spot_lights = memnew_arr(LightData, config->max_renderable_lights);
-		scene_state.spot_light_sort = memnew_arr(InstanceSort<LightInstance>, config->max_renderable_lights);
+		scene_state.spot_light_sort = memnew_arr(InstanceSort<GLES3::LightInstance>, config->max_renderable_lights);
 		glGenBuffers(1, &scene_state.spot_light_buffer);
 		glBindBuffer(GL_UNIFORM_BUFFER, scene_state.spot_light_buffer);
 		glBufferData(GL_UNIFORM_BUFFER, light_buffer_size, nullptr, GL_STREAM_DRAW);

+ 3 - 74
drivers/gles3/rasterizer_scene_gles3.h

@@ -44,6 +44,7 @@
 #include "shader_gles3.h"
 #include "shaders/cubemap_filter.glsl.gen.h"
 #include "shaders/sky.glsl.gen.h"
+#include "storage/light_storage.h"
 #include "storage/material_storage.h"
 #include "storage/render_scene_buffers_gles3.h"
 #include "storage/utilities.h"
@@ -183,34 +184,6 @@ private:
 	};
 	static_assert(sizeof(DirectionalLightData) % 16 == 0, "DirectionalLightData size must be a multiple of 16 bytes");
 
-	struct LightInstance {
-		RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
-
-		AABB aabb;
-		RID self;
-		RID light;
-		Transform3D transform;
-
-		Vector3 light_vector;
-		Vector3 spot_vector;
-		float linear_att = 0.0;
-
-		uint64_t shadow_pass = 0;
-		uint64_t last_scene_pass = 0;
-		uint64_t last_scene_shadow_pass = 0;
-		uint64_t last_pass = 0;
-		uint32_t cull_mask = 0;
-		uint32_t light_directional_index = 0;
-
-		Rect2 directional_rect;
-
-		uint32_t gl_id = -1;
-
-		LightInstance() {}
-	};
-
-	mutable RID_Owner<LightInstance> light_instance_owner;
-
 	class GeometryInstanceGLES3;
 
 	// Cached data for drawing surfaces
@@ -398,8 +371,8 @@ private:
 		LightData *omni_lights = nullptr;
 		LightData *spot_lights = nullptr;
 
-		InstanceSort<LightInstance> *omni_light_sort;
-		InstanceSort<LightInstance> *spot_light_sort;
+		InstanceSort<GLES3::LightInstance> *omni_light_sort;
+		InstanceSort<GLES3::LightInstance> *spot_light_sort;
 		GLuint omni_light_buffer = 0;
 		GLuint spot_light_buffer = 0;
 		uint32_t omni_light_count = 0;
@@ -605,17 +578,6 @@ public:
 
 	uint32_t geometry_instance_get_pair_mask() override;
 
-	/* SHADOW ATLAS API */
-
-	RID shadow_atlas_create() override;
-	void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
-	void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
-	bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
-
-	void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
-	int get_directional_light_shadow_size(RID p_light_intance) override;
-	void set_directional_shadow_count(int p_count) override;
-
 	/* SDFGI UPDATE */
 
 	void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
@@ -666,45 +628,12 @@ public:
 	void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
 	void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
 
-	RID light_instance_create(RID p_light) override;
-	void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
-	void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
-	void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
-	void light_instance_mark_visible(RID p_light_instance) override;
-
-	_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->light_type;
-	}
-	_FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->gl_id;
-	}
-
 	RID fog_volume_instance_create(RID p_fog_volume) override;
 	void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
 	void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override;
 	RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override;
 	Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override;
 
-	RID reflection_atlas_create() override;
-	int reflection_atlas_get_size(RID p_ref_atlas) const override;
-	void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
-
-	RID reflection_probe_instance_create(RID p_probe) override;
-	void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
-	void reflection_probe_release_atlas_index(RID p_instance) override;
-	bool reflection_probe_instance_needs_redraw(RID p_instance) override;
-	bool reflection_probe_instance_has_reflection(RID p_instance) override;
-	bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
-	bool reflection_probe_instance_postprocess_step(RID p_instance) override;
-
-	RID decal_instance_create(RID p_decal) override;
-	void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
-
-	RID lightmap_instance_create(RID p_lightmap) override;
-	void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
-
 	RID voxel_gi_instance_create(RID p_voxel_gi) override;
 	void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override;
 	bool voxel_gi_needs_update(RID p_probe) const override;

+ 131 - 0
drivers/gles3/storage/light_storage.cpp

@@ -333,6 +333,46 @@ AABB LightStorage::light_get_aabb(RID p_light) const {
 	ERR_FAIL_V(AABB());
 }
 
+/* LIGHT INSTANCE API */
+
+RID LightStorage::light_instance_create(RID p_light) {
+	RID li = light_instance_owner.make_rid(LightInstance());
+
+	LightInstance *light_instance = light_instance_owner.get_or_null(li);
+
+	light_instance->self = li;
+	light_instance->light = p_light;
+	light_instance->light_type = light_get_type(p_light);
+
+	return li;
+}
+
+void LightStorage::light_instance_free(RID p_light_instance) {
+	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+	ERR_FAIL_COND(!light_instance);
+	light_instance_owner.free(p_light_instance);
+}
+
+void LightStorage::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
+	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+	ERR_FAIL_COND(!light_instance);
+
+	light_instance->transform = p_transform;
+}
+
+void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
+	LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+	ERR_FAIL_COND(!light_instance);
+
+	light_instance->aabb = p_aabb;
+}
+
+void LightStorage::light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) {
+}
+
+void LightStorage::light_instance_mark_visible(RID p_light_instance) {
+}
+
 /* PROBE API */
 
 RID LightStorage::reflection_probe_allocate() {
@@ -419,6 +459,53 @@ float LightStorage::reflection_probe_get_mesh_lod_threshold(RID p_probe) const {
 	return 0.0;
 }
 
+/* REFLECTION ATLAS */
+
+RID LightStorage::reflection_atlas_create() {
+	return RID();
+}
+
+void LightStorage::reflection_atlas_free(RID p_ref_atlas) {
+}
+
+int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const {
+	return 0;
+}
+
+void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) {
+}
+
+/* REFLECTION PROBE INSTANCE */
+
+RID LightStorage::reflection_probe_instance_create(RID p_probe) {
+	return RID();
+}
+
+void LightStorage::reflection_probe_instance_free(RID p_instance) {
+}
+
+void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) {
+}
+
+void LightStorage::reflection_probe_release_atlas_index(RID p_instance) {
+}
+
+bool LightStorage::reflection_probe_instance_needs_redraw(RID p_instance) {
+	return false;
+}
+
+bool LightStorage::reflection_probe_instance_has_reflection(RID p_instance) {
+	return false;
+}
+
+bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) {
+	return false;
+}
+
+bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
+	return true;
+}
+
 /* LIGHTMAP CAPTURE */
 
 RID LightStorage::lightmap_allocate() {
@@ -484,6 +571,18 @@ float LightStorage::lightmap_get_probe_capture_update_speed() const {
 	return 0;
 }
 
+/* LIGHTMAP INSTANCE */
+
+RID LightStorage::lightmap_instance_create(RID p_lightmap) {
+	return RID();
+}
+
+void LightStorage::lightmap_instance_free(RID p_lightmap) {
+}
+
+void LightStorage::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) {
+}
+
 /* LIGHT SHADOW MAPPING */
 /*
 
@@ -584,4 +683,36 @@ void LightStorage::canvas_light_occluder_set_polylines(RID p_occluder, const Poo
 }
 */
 
+/* SHADOW ATLAS API */
+
+RID LightStorage::shadow_atlas_create() {
+	return RID();
+}
+
+void LightStorage::shadow_atlas_free(RID p_atlas) {
+}
+
+void LightStorage::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) {
+}
+
+void LightStorage::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
+}
+
+bool LightStorage::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
+	return false;
+}
+
+void LightStorage::shadow_atlas_update(RID p_atlas) {
+}
+
+void LightStorage::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) {
+}
+
+int LightStorage::get_directional_light_shadow_size(RID p_light_intance) {
+	return 0;
+}
+
+void LightStorage::set_directional_shadow_count(int p_count) {
+}
+
 #endif // !GLES3_ENABLED

+ 90 - 0
drivers/gles3/storage/light_storage.h

@@ -76,6 +76,33 @@ struct Light {
 	Dependency dependency;
 };
 
+/* Light instance */
+struct LightInstance {
+	RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
+
+	AABB aabb;
+	RID self;
+	RID light;
+	Transform3D transform;
+
+	Vector3 light_vector;
+	Vector3 spot_vector;
+	float linear_att = 0.0;
+
+	uint64_t shadow_pass = 0;
+	uint64_t last_scene_pass = 0;
+	uint64_t last_scene_shadow_pass = 0;
+	uint64_t last_pass = 0;
+	uint32_t cull_mask = 0;
+	uint32_t light_directional_index = 0;
+
+	Rect2 directional_rect;
+
+	uint32_t gl_id = -1;
+
+	LightInstance() {}
+};
+
 /* REFLECTION PROBE */
 
 struct ReflectionProbe {
@@ -128,6 +155,9 @@ private:
 	/* LIGHT */
 	mutable RID_Owner<Light, true> light_owner;
 
+	/* Light instance */
+	mutable RID_Owner<LightInstance> light_instance_owner;
+
 	/* REFLECTION PROBE */
 	mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
 
@@ -268,6 +298,28 @@ public:
 	virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
 	virtual uint64_t light_get_version(RID p_light) const override;
 
+	/* LIGHT INSTANCE API */
+
+	LightInstance *get_light_instance(RID p_rid) { return light_instance_owner.get_or_null(p_rid); };
+	bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); };
+
+	virtual RID light_instance_create(RID p_light) override;
+	virtual void light_instance_free(RID p_light_instance) override;
+
+	virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
+	virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
+	virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
+	virtual void light_instance_mark_visible(RID p_light_instance) override;
+
+	_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->light_type;
+	}
+	_FORCE_INLINE_ uint32_t light_instance_get_gl_id(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->gl_id;
+	}
+
 	/* PROBE API */
 
 	virtual RID reflection_probe_allocate() override;
@@ -298,6 +350,24 @@ public:
 	virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override;
 	virtual bool reflection_probe_renders_shadows(RID p_probe) const override;
 
+	/* REFLECTION ATLAS */
+
+	virtual RID reflection_atlas_create() override;
+	virtual void reflection_atlas_free(RID p_ref_atlas) override;
+	virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
+	virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
+
+	/* REFLECTION PROBE INSTANCE */
+
+	virtual RID reflection_probe_instance_create(RID p_probe) override;
+	virtual void reflection_probe_instance_free(RID p_instance) override;
+	virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
+	virtual void reflection_probe_release_atlas_index(RID p_instance) override;
+	virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
+	virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
+	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
+
 	/* LIGHTMAP CAPTURE */
 
 	Lightmap *get_lightmap(RID p_rid) { return lightmap_owner.get_or_null(p_rid); };
@@ -338,6 +408,26 @@ public:
 	RID canvas_light_occluder_create();
 	void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector<Vector2> &p_lines);
 	*/
+
+	/* LIGHTMAP INSTANCE */
+
+	virtual RID lightmap_instance_create(RID p_lightmap) override;
+	virtual void lightmap_instance_free(RID p_lightmap) override;
+	virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
+
+	/* SHADOW ATLAS API */
+
+	virtual RID shadow_atlas_create() override;
+	virtual void shadow_atlas_free(RID p_atlas) override;
+	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
+	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
+	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override;
+
+	virtual void shadow_atlas_update(RID p_atlas) override;
+
+	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
+	virtual int get_directional_light_shadow_size(RID p_light_intance) override;
+	virtual void set_directional_shadow_count(int p_count) override;
 };
 
 } // namespace GLES3

+ 12 - 0
drivers/gles3/storage/texture_storage.cpp

@@ -1183,6 +1183,18 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const {
 	return AABB();
 }
 
+/* DECAL INSTANCE API */
+
+RID TextureStorage::decal_instance_create(RID p_decal) {
+	return RID();
+}
+
+void TextureStorage::decal_instance_free(RID p_decal_instance) {
+}
+
+void TextureStorage::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
+}
+
 /* RENDER TARGET API */
 
 GLuint TextureStorage::system_fbo = 0;

+ 6 - 0
drivers/gles3/storage/texture_storage.h

@@ -509,6 +509,12 @@ public:
 	virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
 	virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
 
+	/* DECAL INSTANCE */
+
+	virtual RID decal_instance_create(RID p_decal) override;
+	virtual void decal_instance_free(RID p_decal_instance) override;
+	virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
+
 	/* RENDER TARGET API */
 
 	static GLuint system_fbo;

+ 1 - 1
servers/rendering/dummy/environment/fog.h

@@ -41,7 +41,7 @@ public:
 
 	virtual RID fog_volume_allocate() override { return RID(); }
 	virtual void fog_volume_initialize(RID p_rid) override {}
-	virtual void fog_free(RID p_rid) override {}
+	virtual void fog_volume_free(RID p_rid) override {}
 
 	virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override {}
 	virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override {}

+ 0 - 35
servers/rendering/dummy/rasterizer_scene_dummy.h

@@ -93,17 +93,6 @@ public:
 
 	uint32_t geometry_instance_get_pair_mask() override { return 0; }
 
-	/* SHADOW ATLAS API */
-
-	RID shadow_atlas_create() override { return RID(); }
-	void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override {}
-	void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override {}
-	bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override { return false; }
-
-	void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override {}
-	int get_directional_light_shadow_size(RID p_light_intance) override { return 0; }
-	void set_directional_shadow_count(int p_count) override {}
-
 	/* SDFGI UPDATE */
 
 	void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override {}
@@ -143,36 +132,12 @@ public:
 	void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
 	void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override {}
 
-	RID light_instance_create(RID p_light) override { return RID(); }
-	void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override {}
-	void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {}
-	void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {}
-	void light_instance_mark_visible(RID p_light_instance) override {}
-
 	RID fog_volume_instance_create(RID p_fog_volume) override { return RID(); }
 	void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override {}
 	void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override {}
 	RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override { return RID(); }
 	Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override { return Vector3(); }
 
-	RID reflection_atlas_create() override { return RID(); }
-	int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; }
-	void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
-
-	RID reflection_probe_instance_create(RID p_probe) override { return RID(); }
-	void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {}
-	void reflection_probe_release_atlas_index(RID p_instance) override {}
-	bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; }
-	bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; }
-	bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; }
-	bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
-
-	RID decal_instance_create(RID p_decal) override { return RID(); }
-	void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
-
-	RID lightmap_instance_create(RID p_lightmap) override { return RID(); }
-	void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {}
-
 	RID voxel_gi_instance_create(RID p_voxel_gi) override { return RID(); }
 	void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override {}
 	bool voxel_gi_needs_update(RID p_probe) const override { return false; }

+ 47 - 0
servers/rendering/dummy/storage/light_storage.h

@@ -81,6 +81,15 @@ public:
 	virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) override { return 0; }
 	virtual uint64_t light_get_version(RID p_light) const override { return 0; }
 
+	/* LIGHT INSTANCE API */
+
+	RID light_instance_create(RID p_light) override { return RID(); }
+	void light_instance_free(RID p_light) override {}
+	void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override {}
+	void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {}
+	void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {}
+	void light_instance_mark_visible(RID p_light_instance) override {}
+
 	/* PROBE API */
 	virtual RID reflection_probe_allocate() override { return RID(); }
 	virtual void reflection_probe_initialize(RID p_rid) override {}
@@ -110,7 +119,26 @@ public:
 	virtual float reflection_probe_get_origin_max_distance(RID p_probe) const override { return 0.0; }
 	virtual bool reflection_probe_renders_shadows(RID p_probe) const override { return false; }
 
+	/* REFLECTION ATLAS */
+
+	virtual RID reflection_atlas_create() override { return RID(); }
+	virtual void reflection_atlas_free(RID p_ref_atlas) override {}
+	virtual int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; }
+	virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {}
+
+	/* REFLECTION PROBE INSTANCE */
+
+	virtual RID reflection_probe_instance_create(RID p_probe) override { return RID(); }
+	virtual void reflection_probe_instance_free(RID p_instance) override {}
+	virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {}
+	virtual void reflection_probe_release_atlas_index(RID p_instance) override {}
+	virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; }
+	virtual bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; }
+	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override { return false; }
+	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
+
 	/* LIGHTMAP CAPTURE */
+
 	virtual RID lightmap_allocate() override { return RID(); }
 	virtual void lightmap_initialize(RID p_rid) override {}
 	virtual void lightmap_free(RID p_rid) override {}
@@ -129,6 +157,25 @@ public:
 	virtual bool lightmap_is_interior(RID p_lightmap) const override { return false; }
 	virtual void lightmap_set_probe_capture_update_speed(float p_speed) override {}
 	virtual float lightmap_get_probe_capture_update_speed() const override { return 0; }
+
+	/* LIGHTMAP INSTANCE */
+
+	RID lightmap_instance_create(RID p_lightmap) override { return RID(); }
+	void lightmap_instance_free(RID p_lightmap) override {}
+	void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override {}
+
+	/* SHADOW ATLAS API */
+	virtual RID shadow_atlas_create() override { return RID(); }
+	virtual void shadow_atlas_free(RID p_atlas) override {}
+	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override {}
+	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override {}
+	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override { return false; }
+
+	virtual void shadow_atlas_update(RID p_atlas) override {}
+
+	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override {}
+	virtual int get_directional_light_shadow_size(RID p_light_intance) override { return 0; }
+	virtual void set_directional_shadow_count(int p_count) override {}
 };
 
 } // namespace RendererDummy

+ 6 - 0
servers/rendering/dummy/storage/texture_storage.h

@@ -146,6 +146,12 @@ public:
 	virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
 	virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {}
 
+	/* DECAL INSTANCE */
+
+	virtual RID decal_instance_create(RID p_decal) override { return RID(); }
+	virtual void decal_instance_free(RID p_decal_instance) override {}
+	virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
+
 	/* RENDER TARGET */
 
 	virtual RID render_target_create() override { return RID(); }

+ 1 - 1
servers/rendering/environment/renderer_fog.h

@@ -41,7 +41,7 @@ public:
 
 	virtual RID fog_volume_allocate() = 0;
 	virtual void fog_volume_initialize(RID p_rid) = 0;
-	virtual void fog_free(RID p_rid) = 0;
+	virtual void fog_volume_free(RID p_rid) = 0;
 
 	virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) = 0;
 	virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) = 0;

+ 2 - 1
servers/rendering/renderer_rd/effects/fsr.cpp

@@ -29,7 +29,8 @@
 /*************************************************************************/
 
 #include "fsr.h"
-#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+#include "../storage_rd/material_storage.h"
+#include "../uniform_set_cache_rd.h"
 
 using namespace RendererRD;
 

+ 3 - 4
servers/rendering/renderer_rd/effects/fsr.h

@@ -31,11 +31,10 @@
 #ifndef FSR_RD_H
 #define FSR_RD_H
 
-#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
-#include "servers/rendering/renderer_rd/shaders/effects/fsr_upscale.glsl.gen.h"
-#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
+#include "../pipeline_cache_rd.h"
+#include "../shaders/effects/fsr_upscale.glsl.gen.h"
+#include "../storage_rd/render_scene_buffers_rd.h"
 #include "servers/rendering/renderer_scene_render.h"
-
 #include "servers/rendering_server.h"
 
 namespace RendererRD {

+ 119 - 76
servers/rendering/renderer_rd/effects/ss_effects.cpp

@@ -30,6 +30,7 @@
 
 #include "ss_effects.h"
 
+#include "core/config/project_settings.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/storage_rd/render_scene_buffers_rd.h"
@@ -50,8 +51,8 @@ static _FORCE_INLINE_ void store_camera(const Projection &p_mtx, float *p_array)
 SSEffects::SSEffects() {
 	singleton = this;
 
+	// Initialize depth buffer for screen space effects
 	{
-		// 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");
@@ -100,6 +101,7 @@ SSEffects::SSEffects() {
 	}
 
 	// Initialize Screen Space Indirect Lighting (SSIL)
+	ssil_set_quality(RS::EnvironmentSSILQuality(int(GLOBAL_GET("rendering/environment/ssil/quality"))), GLOBAL_GET("rendering/environment/ssil/half_size"), GLOBAL_GET("rendering/environment/ssil/adaptive_target"), GLOBAL_GET("rendering/environment/ssil/blur_passes"), GLOBAL_GET("rendering/environment/ssil/fadeout_from"), GLOBAL_GET("rendering/environment/ssil/fadeout_to"));
 
 	{
 		Vector<String> ssil_modes;
@@ -175,9 +177,10 @@ SSEffects::SSEffects() {
 		}
 	}
 
-	{
-		// Initialize Screen Space Ambient Occlusion (SSAO)
+	// Initialize Screen Space Ambient Occlusion (SSAO)
+	ssao_set_quality(RS::EnvironmentSSAOQuality(int(GLOBAL_GET("rendering/environment/ssao/quality"))), GLOBAL_GET("rendering/environment/ssao/half_size"), GLOBAL_GET("rendering/environment/ssao/adaptive_target"), GLOBAL_GET("rendering/environment/ssao/blur_passes"), GLOBAL_GET("rendering/environment/ssao/fadeout_from"), GLOBAL_GET("rendering/environment/ssao/fadeout_to"));
 
+	{
 		RD::SamplerState sampler;
 		sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST;
 		sampler.min_filter = RD::SAMPLER_FILTER_NEAREST;
@@ -276,9 +279,10 @@ SSEffects::SSEffects() {
 		ss_effects.mirror_sampler = RD::get_singleton()->sampler_create(sampler);
 	}
 
-	{
-		// Screen Space Reflections
+	// Screen Space Reflections
+	ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/environment/screen_space_reflection/roughness_quality")));
 
+	{
 		Vector<RD::PipelineSpecializationConstant> specialization_constants;
 
 		{
@@ -336,6 +340,10 @@ SSEffects::SSEffects() {
 	}
 
 	// Subsurface scattering
+	sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_quality")));
+	sss_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_scale");
+	sss_depth_scale = GLOBAL_GET("rendering/environment/subsurface_scattering/subsurface_scattering_depth_scale");
+
 	{
 		Vector<String> sss_modes;
 		sss_modes.push_back("\n#define USE_11_SAMPLES\n");
@@ -403,7 +411,7 @@ SSEffects::~SSEffects() {
 
 /* 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 Projection &p_projection) {
+void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, bool p_invalidate_uniform_set, Size2i p_full_screen_size, const Projection &p_projection) {
 	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
 	ERR_FAIL_NULL(uniform_set_cache);
 	MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -413,9 +421,9 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_
 	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;
+	bool use_mips = ssao_quality > RS::ENV_SSAO_QUALITY_MEDIUM || 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) {
+	if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW && ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
 		downsample_mode = SS_EFFECTS_DOWNSAMPLE_HALF;
 	} else if (use_mips) {
 		downsample_mode = SS_EFFECTS_DOWNSAMPLE_MIPMAP;
@@ -424,10 +432,10 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_
 	bool use_half_size = false;
 	bool use_full_mips = false;
 
-	if (p_ssao_half_size && p_ssil_half_size) {
+	if (ssao_half_size && ssil_half_size) {
 		downsample_mode++;
 		use_half_size = true;
-	} else if (p_ssao_half_size != p_ssil_half_size) {
+	} else if (ssao_half_size != ssil_half_size) {
 		if (use_mips) {
 			downsample_mode = SS_EFFECTS_DOWNSAMPLE_FULL_MIPS;
 			use_full_mips = true;
@@ -526,12 +534,21 @@ void SSEffects::downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_
 
 /* SSIL */
 
+void SSEffects::ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
+	ssil_quality = p_quality;
+	ssil_half_size = p_half_size;
+	ssil_adaptive_target = p_adaptive_target;
+	ssil_blur_passes = p_blur_passes;
+	ssil_fadeout_from = p_fadeout_from;
+	ssil_fadeout_to = p_fadeout_to;
+}
+
 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) {
+	if ((ssil_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);
@@ -539,7 +556,7 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID>
 	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))) {
+		if ((ssil_quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
 			continue;
 		}
 
@@ -554,7 +571,7 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID>
 		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));
+		Size2i size = Size2i(p_settings.full_screen_size.x >> (ssil_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssil_half_size ? 2 : 1));
 
 		RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1);
 	}
@@ -562,11 +579,11 @@ void SSEffects::gather_ssil(RD::ComputeListID p_compute_list, const Vector<RID>
 }
 
 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) {
+	if (p_ssil_buffers.half_size != ssil_half_size) {
 		ssil_free(p_ssil_buffers);
 	}
 
-	if (p_settings.half_size) {
+	if (ssil_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;
@@ -580,7 +597,7 @@ void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const S
 
 	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);
+			p_ssil_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, ssil_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
 		}
 		{
 			RD::TextureFormat tf;
@@ -665,7 +682,7 @@ void SSEffects::ssil_allocate_buffers(SSILRenderBuffers &p_ssil_buffers, const S
 			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;
+		p_ssil_buffers.half_size = ssil_half_size;
 	}
 }
 
@@ -711,26 +728,26 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
 
 		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) {
+		if (ssil_quality <= RS::ENV_SSIL_QUALITY_LOW) {
 			radius_near_limit *= 1.50f;
 
-			if (p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) {
+			if (ssil_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.fade_out_mul = -1.0 / (ssil_fadeout_to - ssil_fadeout_from);
+		ssil.gather_push_constant.fade_out_add = ssil_fadeout_from / (ssil_fadeout_to - ssil_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.adaptive_sample_limit = ssil_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;
+		ssil.gather_push_constant.quality = MAX(0, ssil_quality - 1);
+		ssil.gather_push_constant.size_multiplier = ssil_half_size ? 2 : 1;
 
 		if (p_ssil_buffers.projection_uniform_set.is_null()) {
 			Vector<RD::Uniform> uniforms;
@@ -806,7 +823,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
 			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) {
+		if (ssil_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;
@@ -865,13 +882,13 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
 		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;
+		int blur_passes = ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW ? ssil_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) {
+			if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) {
 				blur_pipeline = SSIL_BLUR_PASS_SMART;
 				if (pass < blur_passes - 2) {
 					blur_pipeline = SSIL_BLUR_PASS_WIDE;
@@ -879,13 +896,13 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
 			}
 
 			for (int i = 0; i < 4; i++) {
-				if ((p_settings.quality == RS::ENV_SSIL_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+				if ((ssil_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) {
+					if (ssil_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 {
@@ -896,7 +913,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
 					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) {
+					if (ssil_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 {
@@ -913,11 +930,11 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
 
 				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));
+				int x_groups = (p_settings.full_screen_size.x >> (ssil_half_size ? 2 : 1));
+				int y_groups = (p_settings.full_screen_size.y >> (ssil_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) {
+				if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW) {
 					RD::get_singleton()->compute_list_add_barrier(compute_list);
 				}
 			}
@@ -931,12 +948,12 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_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);
+		ssil.interleave_push_constant.size_modifier = uint32_t(ssil_half_size ? 4 : 2);
 
 		int interleave_pipeline = SSIL_INTERLEAVE_HALF;
-		if (p_settings.quality == RS::ENV_SSIL_QUALITY_LOW) {
+		if (ssil_quality == RS::ENV_SSIL_QUALITY_LOW) {
 			interleave_pipeline = SSIL_INTERLEAVE;
-		} else if (p_settings.quality >= RS::ENV_SSIL_QUALITY_MEDIUM) {
+		} else if (ssil_quality >= RS::ENV_SSIL_QUALITY_MEDIUM) {
 			interleave_pipeline = SSIL_INTERLEAVE_SMART;
 		}
 
@@ -947,7 +964,7 @@ void SSEffects::screen_space_indirect_lighting(SSILRenderBuffers &p_ssil_buffers
 		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) {
+		if (ssil_quality > RS::ENV_SSIL_QUALITY_VERY_LOW && ssil_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 {
@@ -1003,19 +1020,28 @@ void SSEffects::ssil_free(SSILRenderBuffers &p_ssil_buffers) {
 
 /* SSAO */
 
+void SSEffects::ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) {
+	ssao_quality = p_quality;
+	ssao_half_size = p_half_size;
+	ssao_adaptive_target = p_adaptive_target;
+	ssao_blur_passes = p_blur_passes;
+	ssao_fadeout_from = p_fadeout_from;
+	ssao_fadeout_to = p_fadeout_to;
+}
+
 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) {
+	if ((ssao_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))) {
+		if ((ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
 			continue;
 		}
 
@@ -1029,7 +1055,7 @@ void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID>
 		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));
+		Size2i size = Size2i(p_settings.full_screen_size.x >> (ssao_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssao_half_size ? 2 : 1));
 
 		RD::get_singleton()->compute_list_dispatch_threads(p_compute_list, size.x, size.y, 1);
 	}
@@ -1037,11 +1063,11 @@ void SSEffects::gather_ssao(RD::ComputeListID p_compute_list, const Vector<RID>
 }
 
 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) {
+	if (p_ssao_buffers.half_size != ssao_half_size) {
 		ssao_free(p_ssao_buffers);
 	}
 
-	if (p_settings.half_size) {
+	if (ssao_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;
@@ -1055,7 +1081,7 @@ void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const S
 
 	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);
+			p_ssao_buffers.depth_texture_view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_linear_depth, 0, ssao_half_size ? 1 : 0, 4, RD::TEXTURE_SLICE_2D_ARRAY);
 		}
 		{
 			RD::TextureFormat tf;
@@ -1111,7 +1137,7 @@ void SSEffects::ssao_allocate_buffers(SSAORenderBuffers &p_ssao_buffers, const S
 			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;
+		p_ssao_buffers.half_size = ssao_half_size;
 	}
 }
 
@@ -1151,10 +1177,10 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 
 		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) {
+		if (ssao_quality <= RS::ENV_SSAO_QUALITY_LOW) {
 			radius_near_limit *= 1.50f;
 
-			if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
+			if (ssao_quality == RS::ENV_SSAO_QUALITY_VERY_LOW) {
 				ssao.gather_push_constant.radius *= 0.8f;
 			}
 		}
@@ -1162,18 +1188,18 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 		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.fade_out_mul = -1.0 / (ssao_fadeout_to - ssao_fadeout_from);
+		ssao.gather_push_constant.fade_out_add = ssao_fadeout_from / (ssao_fadeout_to - ssao_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.adaptive_sample_limit = ssao_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;
+		ssao.gather_push_constant.quality = MAX(0, ssao_quality - 1);
+		ssao.gather_push_constant.size_multiplier = ssao_half_size ? 2 : 1;
 
 		if (p_ssao_buffers.gather_uniform_set.is_null()) {
 			Vector<RD::Uniform> uniforms;
@@ -1231,7 +1257,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 			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) {
+		if (ssao_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;
@@ -1299,13 +1325,13 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 		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;
+		int blur_passes = ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW ? ssao_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) {
+			if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
 				blur_pipeline = SSAO_BLUR_PASS_SMART;
 				if (pass < blur_passes - 2) {
 					blur_pipeline = SSAO_BLUR_PASS_WIDE;
@@ -1315,13 +1341,13 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 			}
 
 			for (int i = 0; i < 4; i++) {
-				if ((p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) && ((i == 1) || (i == 2))) {
+				if ((ssao_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) {
+					if (ssao_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 {
@@ -1332,7 +1358,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 					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) {
+					if (ssao_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 {
@@ -1345,11 +1371,11 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 				}
 				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));
+				Size2i size(p_settings.full_screen_size.x >> (ssao_half_size ? 2 : 1), p_settings.full_screen_size.y >> (ssao_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) {
+			if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW) {
 				RD::get_singleton()->compute_list_add_barrier(compute_list);
 			}
 		}
@@ -1364,14 +1390,14 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 		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);
+		ssao.interleave_push_constant.size_modifier = uint32_t(ssao_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) {
+		if (ssao_quality == RS::ENV_SSAO_QUALITY_LOW) {
 			interleave_pipeline = SSAO_INTERLEAVE;
-		} else if (p_settings.quality >= RS::ENV_SSAO_QUALITY_MEDIUM) {
+		} else if (ssao_quality >= RS::ENV_SSAO_QUALITY_MEDIUM) {
 			interleave_pipeline = SSAO_INTERLEAVE_SMART;
 		}
 
@@ -1380,7 +1406,7 @@ void SSEffects::generate_ssao(SSAORenderBuffers &p_ssao_buffers, RID p_normal_bu
 		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) {
+		if (ssao_quality > RS::ENV_SSAO_QUALITY_VERY_LOW && ssao_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 {
@@ -1425,7 +1451,11 @@ void SSEffects::ssao_free(SSAORenderBuffers &p_ssao_buffers) {
 
 /* 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) {
+void SSEffects::ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) {
+	ssr_roughness_quality = p_quality;
+}
+
+void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, 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()) {
@@ -1446,7 +1476,7 @@ void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const Rend
 		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()) {
+	if (ssr_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;
@@ -1490,7 +1520,7 @@ void SSEffects::ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const Rend
 	}
 }
 
-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 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 Projection *p_projections, const Vector3 *p_eye_offsets) {
+void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const RID *p_diffuse_slices, const RID *p_normal_roughness_slices, const RID *p_metallic_slices, 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 Projection *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();
@@ -1586,7 +1616,7 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
 			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];
 
-			ScreenSpaceReflectionMode mode = (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) ? SCREEN_SPACE_REFLECTION_ROUGH : SCREEN_SPACE_REFLECTION_NORMAL;
+			ScreenSpaceReflectionMode mode = (ssr_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]);
@@ -1598,7 +1628,7 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
 			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) {
+			if (ssr_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);
@@ -1619,7 +1649,7 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
 			RD::get_singleton()->draw_command_end_label();
 		}
 
-		if (p_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
+		if (ssr_roughness_quality != RS::ENV_SSR_ROUGHNESS_QUALITY_DISABLED) {
 			RD::get_singleton()->draw_command_begin_label("SSR filter");
 			//blur
 
@@ -1634,10 +1664,10 @@ void SSEffects::screen_space_reflection(SSRRenderBuffers &p_ssr_buffers, const R
 			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) {
+			if (ssr_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) {
+			} else if (ssr_roughness_quality == RS::ENV_SSR_ROUGHNESS_QUALITY_MEDIUM) {
 				push_constant.steps = p_max_steps / 2;
 				push_constant.increment = 2;
 			} else {
@@ -1740,7 +1770,20 @@ void SSEffects::ssr_free(SSRRenderBuffers &p_ssr_buffers) {
 
 /* Subsurface scattering */
 
-void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) {
+void SSEffects::sss_set_quality(RS::SubSurfaceScatteringQuality p_quality) {
+	sss_quality = p_quality;
+}
+
+RS::SubSurfaceScatteringQuality SSEffects::sss_get_quality() const {
+	return sss_quality;
+}
+
+void SSEffects::sss_set_scale(float p_scale, float p_depth_scale) {
+	sss_scale = p_scale;
+	sss_depth_scale = p_depth_scale;
+}
+
+void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size) {
 	UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
 	ERR_FAIL_NULL(uniform_set_cache);
 	MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -1769,11 +1812,11 @@ void SSEffects::sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffer
 		sss.push_constant.screen_size[0] = p_screen_size.x;
 		sss.push_constant.screen_size[1] = p_screen_size.y;
 		sss.push_constant.vertical = false;
-		sss.push_constant.scale = p_scale;
-		sss.push_constant.depth_scale = p_depth_scale;
+		sss.push_constant.scale = sss_scale;
+		sss.push_constant.depth_scale = sss_depth_scale;
 
-		RID shader = sss.shader.version_get_shader(sss.shader_version, p_quality - 1);
-		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[p_quality - 1]);
+		RID shader = sss.shader.version_get_shader(sss.shader_version, sss_quality - 1);
+		RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[sss_quality - 1]);
 
 		RD::Uniform u_diffuse_with_sampler(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_diffuse }));
 		RD::Uniform u_diffuse(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_diffuse }));

+ 33 - 18
servers/rendering/renderer_rd/effects/ss_effects.h

@@ -64,9 +64,10 @@ public:
 
 	/* 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 Projection &p_projection);
+	void downsample_depth(RID p_depth_buffer, const Vector<RID> &p_depth_mipmaps, bool p_invalidate_uniform_set, Size2i p_full_screen_size, const Projection &p_projection);
 
 	/* SSIL */
+	void ssil_set_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to);
 
 	struct SSILRenderBuffers {
 		bool half_size = false;
@@ -99,13 +100,6 @@ public:
 		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();
 	};
 
@@ -114,6 +108,7 @@ public:
 	void ssil_free(SSILRenderBuffers &p_ssil_buffers);
 
 	/* SSAO */
+	void ssao_set_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to);
 
 	struct SSAORenderBuffers {
 		bool half_size = false;
@@ -142,13 +137,6 @@ public:
 		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();
 	};
 
@@ -157,6 +145,7 @@ public:
 	void ssao_free(SSAORenderBuffers &p_ssao_buffers);
 
 	/* Screen Space Reflection */
+	void ssr_set_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality);
 
 	struct SSRRenderBuffers {
 		RID normal_scaled;
@@ -167,14 +156,40 @@ public:
 		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 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 Projection *p_projections, const Vector3 *p_eye_offsets);
+	void ssr_allocate_buffers(SSRRenderBuffers &p_ssr_buffers, const RenderingDevice::DataFormat p_color_format, 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, const RID *p_metallic_slices, 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 Projection *p_projections, const Vector3 *p_eye_offsets);
 	void ssr_free(SSRRenderBuffers &p_ssr_buffers);
 
 	/* subsurface scattering */
-	void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality);
+	void sss_set_quality(RS::SubSurfaceScatteringQuality p_quality);
+	RS::SubSurfaceScatteringQuality sss_get_quality() const;
+	void sss_set_scale(float p_scale, float p_depth_scale);
+
+	void sub_surface_scattering(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_diffuse, RID p_depth, const Projection &p_camera, const Size2i &p_screen_size);
 
 private:
+	/* Settings */
+
+	RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
+	bool ssao_half_size = false;
+	float ssao_adaptive_target = 0.5;
+	int ssao_blur_passes = 2;
+	float ssao_fadeout_from = 50.0;
+	float ssao_fadeout_to = 300.0;
+
+	RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM;
+	bool ssil_half_size = false;
+	float ssil_adaptive_target = 0.5;
+	int ssil_blur_passes = 4;
+	float ssil_fadeout_from = 50.0;
+	float ssil_fadeout_to = 300.0;
+
+	RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
+
+	RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
+	float sss_scale = 0.05;
+	float sss_depth_scale = 0.01;
+
 	/* SS Downsampler */
 
 	struct SSEffectsDownsamplePushConstant {

+ 8 - 1
servers/rendering/renderer_rd/environment/fog.cpp

@@ -57,12 +57,19 @@ void Fog::fog_volume_initialize(RID p_rid) {
 	fog_volume_owner.initialize_rid(p_rid, FogVolume());
 }
 
-void Fog::fog_free(RID p_rid) {
+void Fog::fog_volume_free(RID p_rid) {
 	FogVolume *fog_volume = fog_volume_owner.get_or_null(p_rid);
 	fog_volume->dependency.deleted_notify(p_rid);
 	fog_volume_owner.free(p_rid);
 }
 
+Dependency *Fog::fog_volume_get_dependency(RID p_fog_volume) const {
+	FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
+	ERR_FAIL_NULL_V(fog_volume, nullptr);
+
+	return &fog_volume->dependency;
+}
+
 void Fog::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) {
 	FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume);
 	ERR_FAIL_COND(!fog_volume);

+ 31 - 8
servers/rendering/renderer_rd/environment/fog.h

@@ -46,7 +46,9 @@
 namespace RendererRD {
 
 class Fog : public RendererFog {
-public:
+private:
+	static Fog *singleton;
+
 	/* FOG VOLUMES */
 
 	struct FogVolume {
@@ -58,16 +60,14 @@ public:
 		Dependency dependency;
 	};
 
+	mutable RID_Owner<FogVolume, true> fog_volume_owner;
+
 	struct FogVolumeInstance {
 		RID volume;
 		Transform3D transform;
 		bool active = false;
 	};
 
-private:
-	static Fog *singleton;
-
-	mutable RID_Owner<FogVolume, true> fog_volume_owner;
 	mutable RID_Owner<FogVolumeInstance> fog_volume_instance_owner;
 
 	/* Volumetric Fog */
@@ -240,12 +240,12 @@ public:
 
 	/* FOG VOLUMES */
 
-	FogVolume *get_fog_volume(RID p_rid) { return fog_volume_owner.get_or_null(p_rid); };
 	bool owns_fog_volume(RID p_rid) { return fog_volume_owner.owns(p_rid); };
 
 	virtual RID fog_volume_allocate() override;
 	virtual void fog_volume_initialize(RID p_rid) override;
-	virtual void fog_free(RID p_rid) override;
+	virtual void fog_volume_free(RID p_rid) override;
+	Dependency *fog_volume_get_dependency(RID p_fog_volume) const;
 
 	virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override;
 	virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override;
@@ -257,12 +257,35 @@ public:
 
 	/* FOG VOLUMES INSTANCE */
 
-	FogVolumeInstance *get_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.get_or_null(p_rid); };
 	bool owns_fog_volume_instance(RID p_rid) { return fog_volume_instance_owner.owns(p_rid); };
 
 	RID fog_volume_instance_create(RID p_fog_volume);
 	void fog_instance_free(RID p_rid);
 
+	void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) {
+		Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+		ERR_FAIL_COND(!fvi);
+		fvi->transform = p_transform;
+	}
+
+	void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) {
+		Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+		ERR_FAIL_COND(!fvi);
+		fvi->active = p_active;
+	}
+
+	RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const {
+		Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+		ERR_FAIL_COND_V(!fvi, RID());
+		return fvi->volume;
+	}
+
+	Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const {
+		Fog::FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance);
+		ERR_FAIL_COND_V(!fvi, Vector3());
+		return fvi->transform.get_origin();
+	}
+
 	/* Volumetric FOG */
 	class VolumetricFog : public RenderBufferCustomDataRD {
 		GDCLASS(VolumetricFog, RenderBufferCustomDataRD)

+ 75 - 60
servers/rendering/renderer_rd/environment/gi.cpp

@@ -1798,7 +1798,8 @@ void GI::SDFGI::debug_probes(RID p_framebuffer, const uint32_t p_view_count, con
 	RD::get_singleton()->draw_list_end();
 }
 
-void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render) {
+void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data) {
+	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
 	/* Update general SDFGI Buffer */
 
 	SDFGIData sdfgi_data;
@@ -1881,40 +1882,43 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
 
 		SDFGIShader::Light lights[SDFGI::MAX_DYNAMIC_LIGHTS];
 		uint32_t idx = 0;
-		for (uint32_t j = 0; j < (uint32_t)p_scene_render->render_state.sdfgi_update_data->directional_lights->size(); j++) {
+		for (uint32_t j = 0; j < (uint32_t)p_render_data->sdfgi_update_data->directional_lights->size(); j++) {
 			if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
 				break;
 			}
 
-			RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j));
-			ERR_CONTINUE(!li);
+			RID light_instance = p_render_data->sdfgi_update_data->directional_lights->get(j);
+			ERR_CONTINUE(!light_storage->owns_light_instance(light_instance));
 
-			if (RSG::light_storage->light_directional_get_sky_mode(li->light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
+			RID light = light_storage->light_instance_get_base_light(light_instance);
+			Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance);
+
+			if (RSG::light_storage->light_directional_get_sky_mode(light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
 				continue;
 			}
 
-			Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z);
+			Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z);
 			dir.y *= y_mult;
 			dir.normalize();
 			lights[idx].direction[0] = dir.x;
 			lights[idx].direction[1] = dir.y;
 			lights[idx].direction[2] = dir.z;
-			Color color = RSG::light_storage->light_get_color(li->light);
+			Color color = RSG::light_storage->light_get_color(light);
 			color = color.srgb_to_linear();
 			lights[idx].color[0] = color.r;
 			lights[idx].color[1] = color.g;
 			lights[idx].color[2] = color.b;
 			lights[idx].type = RS::LIGHT_DIRECTIONAL;
-			lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
-			if (p_scene_render->is_using_physical_light_units()) {
-				lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+			lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+			if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
+				lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
 			}
 
 			if (p_render_data->camera_attributes.is_valid()) {
 				lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
 			}
 
-			lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
+			lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light);
 
 			idx++;
 		}
@@ -1923,45 +1927,49 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
 		cascade_aabb.position = Vector3((Vector3i(1, 1, 1) * -int32_t(cascade_size >> 1) + cascade.position)) * cascade.cell_size;
 		cascade_aabb.size = Vector3(1, 1, 1) * cascade_size * cascade.cell_size;
 
-		for (uint32_t j = 0; j < p_scene_render->render_state.sdfgi_update_data->positional_light_count; j++) {
+		for (uint32_t j = 0; j < p_render_data->sdfgi_update_data->positional_light_count; j++) {
 			if (idx == SDFGI::MAX_DYNAMIC_LIGHTS) {
 				break;
 			}
 
-			RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]);
-			ERR_CONTINUE(!li);
+			RID light_instance = p_render_data->sdfgi_update_data->positional_light_instances[j];
+			ERR_CONTINUE(!light_storage->owns_light_instance(light_instance));
+
+			RID light = light_storage->light_instance_get_base_light(light_instance);
+			AABB light_aabb = light_storage->light_instance_get_base_aabb(light_instance);
+			Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance);
 
-			uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(li->light);
+			uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(light);
 			if (i > max_sdfgi_cascade) {
 				continue;
 			}
 
-			if (!cascade_aabb.intersects(li->aabb)) {
+			if (!cascade_aabb.intersects(light_aabb)) {
 				continue;
 			}
 
-			Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z);
+			Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z);
 			//faster to not do this here
 			//dir.y *= y_mult;
 			//dir.normalize();
 			lights[idx].direction[0] = dir.x;
 			lights[idx].direction[1] = dir.y;
 			lights[idx].direction[2] = dir.z;
-			Vector3 pos = li->transform.origin;
+			Vector3 pos = light_transform.origin;
 			pos.y *= y_mult;
 			lights[idx].position[0] = pos.x;
 			lights[idx].position[1] = pos.y;
 			lights[idx].position[2] = pos.z;
-			Color color = RSG::light_storage->light_get_color(li->light);
+			Color color = RSG::light_storage->light_get_color(light);
 			color = color.srgb_to_linear();
 			lights[idx].color[0] = color.r;
 			lights[idx].color[1] = color.g;
 			lights[idx].color[2] = color.b;
-			lights[idx].type = RSG::light_storage->light_get_type(li->light);
+			lights[idx].type = RSG::light_storage->light_get_type(light);
 
-			lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
-			if (p_scene_render->is_using_physical_light_units()) {
-				lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+			lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+			if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
+				lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
 
 				// Convert from Luminous Power to Luminous Intensity
 				if (lights[idx].type == RS::LIGHT_OMNI) {
@@ -1977,11 +1985,11 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
 				lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
 			}
 
-			lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
-			lights[idx].attenuation = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
-			lights[idx].radius = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
-			lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
-			lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+			lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light);
+			lights[idx].attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
+			lights[idx].radius = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_RANGE);
+			lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+			lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
 
 			idx++;
 		}
@@ -1994,7 +2002,7 @@ void GI::SDFGI::pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_r
 	}
 }
 
-void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render, float p_exposure_normalization) {
+void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization) {
 	//print_line("rendering region " + itos(p_region));
 	ERR_FAIL_COND(p_render_buffers.is_null()); // we wouldn't be here if this failed but...
 	AABB bounds;
@@ -2015,7 +2023,7 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
 	}
 
 	//print_line("rendering cascade " + itos(p_region) + " objects: " + itos(p_cull_count) + " bounds: " + bounds + " from: " + from + " size: " + size + " cell size: " + rtos(cascades[cascade].cell_size));
-	p_scene_render->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing, p_exposure_normalization);
+	RendererSceneRenderRD::get_singleton()->_render_sdfgi(p_render_buffers, from, size, bounds, p_instances, render_albedo, render_emission, render_emission_aniso, render_geom_facing, p_exposure_normalization);
 
 	if (cascade_next != cascade) {
 		RD::get_singleton()->draw_command_begin_label("SDFGI Pre-Process Cascade");
@@ -2353,9 +2361,11 @@ void GI::SDFGI::render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_
 	}
 }
 
-void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) {
+void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result) {
 	ERR_FAIL_COND(p_render_buffers.is_null()); // we wouldn't be here if this failed but...
 
+	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
 	RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lights");
 
 	update_cascades();
@@ -2381,21 +2391,25 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
 					break;
 				}
 
-				RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_positional_light_cull_result[i][j]);
-				ERR_CONTINUE(!li);
+				RID light_instance = p_positional_light_cull_result[i][j];
+				ERR_CONTINUE(!light_storage->owns_light_instance(light_instance));
+
+				RID light = light_storage->light_instance_get_base_light(light_instance);
+				AABB light_aabb = light_storage->light_instance_get_base_aabb(light_instance);
+				Transform3D light_transform = light_storage->light_instance_get_base_transform(light_instance);
 
-				uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(li->light);
+				uint32_t max_sdfgi_cascade = RSG::light_storage->light_get_max_sdfgi_cascade(light);
 				if (p_cascade_indices[i] > max_sdfgi_cascade) {
 					continue;
 				}
 
-				if (!cascade_aabb.intersects(li->aabb)) {
+				if (!cascade_aabb.intersects(light_aabb)) {
 					continue;
 				}
 
-				lights[idx].type = RSG::light_storage->light_get_type(li->light);
+				lights[idx].type = RSG::light_storage->light_get_type(light);
 
-				Vector3 dir = -li->transform.basis.get_column(Vector3::AXIS_Z);
+				Vector3 dir = -light_transform.basis.get_column(Vector3::AXIS_Z);
 				if (lights[idx].type == RS::LIGHT_DIRECTIONAL) {
 					dir.y *= y_mult; //only makes sense for directional
 					dir.normalize();
@@ -2403,20 +2417,20 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
 				lights[idx].direction[0] = dir.x;
 				lights[idx].direction[1] = dir.y;
 				lights[idx].direction[2] = dir.z;
-				Vector3 pos = li->transform.origin;
+				Vector3 pos = light_transform.origin;
 				pos.y *= y_mult;
 				lights[idx].position[0] = pos.x;
 				lights[idx].position[1] = pos.y;
 				lights[idx].position[2] = pos.z;
-				Color color = RSG::light_storage->light_get_color(li->light);
+				Color color = RSG::light_storage->light_get_color(light);
 				color = color.srgb_to_linear();
 				lights[idx].color[0] = color.r;
 				lights[idx].color[1] = color.g;
 				lights[idx].color[2] = color.b;
 
-				lights[idx].energy = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
-				if (p_scene_render->is_using_physical_light_units()) {
-					lights[idx].energy *= RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_INTENSITY);
+				lights[idx].energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
+				if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
+					lights[idx].energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
 
 					// Convert from Luminous Power to Luminous Intensity
 					if (lights[idx].type == RS::LIGHT_OMNI) {
@@ -2432,11 +2446,11 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
 					lights[idx].energy *= RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
 				}
 
-				lights[idx].has_shadow = RSG::light_storage->light_has_shadow(li->light);
-				lights[idx].attenuation = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
-				lights[idx].radius = RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
-				lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
-				lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+				lights[idx].has_shadow = RSG::light_storage->light_has_shadow(light);
+				lights[idx].attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
+				lights[idx].radius = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_RANGE);
+				lights[idx].cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+				lights[idx].inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
 
 				idx++;
 			}
@@ -2492,7 +2506,8 @@ void GI::SDFGI::render_static_lights(RenderDataRD *p_render_data, Ref<RenderScen
 ////////////////////////////////////////////////////////////////////////////////
 // VoxelGIInstance
 
-void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) {
+	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
 	RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
 
 	uint32_t data_version = gi->voxel_gi_get_data_version(probe);
@@ -2834,7 +2849,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
 		last_probe_data_version = data_version;
 		p_update_light_instances = true; //just in case
 
-		p_scene_render->_base_uniforms_changed();
+		RendererSceneRenderRD::get_singleton()->base_uniforms_changed();
 	}
 
 	// UDPDATE TIME
@@ -2857,7 +2872,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
 			for (uint32_t i = 0; i < light_count; i++) {
 				VoxelGILight &l = gi->voxel_gi_lights[i];
 				RID light_instance = p_light_instances[i];
-				RID light = p_scene_render->light_instance_get_base_light(light_instance);
+				RID light = light_storage->light_instance_get_base_light(light_instance);
 
 				l.type = RSG::light_storage->light_get_type(light);
 				if (l.type == RS::LIGHT_DIRECTIONAL && RSG::light_storage->light_directional_get_sky_mode(light) == RS::LIGHT_DIRECTIONAL_SKY_MODE_SKY_ONLY) {
@@ -2868,7 +2883,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
 				l.attenuation = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ATTENUATION);
 				l.energy = RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_ENERGY) * RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INDIRECT_ENERGY);
 
-				if (p_scene_render->is_using_physical_light_units()) {
+				if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
 					l.energy *= RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_INTENSITY);
 
 					l.energy *= gi->voxel_gi_get_baked_exposure_normalization(probe);
@@ -2892,7 +2907,7 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
 				l.cos_spot_angle = Math::cos(Math::deg_to_rad(RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
 				l.inv_spot_attenuation = 1.0f / RSG::light_storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
 
-				Transform3D xform = p_scene_render->light_instance_get_base_transform(light_instance);
+				Transform3D xform = light_storage->light_instance_get_base_transform(light_instance);
 
 				Vector3 pos = to_probe_xform.xform(xform.origin);
 				Vector3 dir = to_probe_xform.basis.xform(-xform.basis.get_column(2)).normalized();
@@ -3087,17 +3102,17 @@ void GI::VoxelGIInstance::update(bool p_update_light_instances, const Vector<RID
 				Projection cm;
 				cm.set_orthogonal(-rect.size.width / 2, rect.size.width / 2, -rect.size.height / 2, rect.size.height / 2, 0.0001, aabb.size[z_axis]);
 
-				if (p_scene_render->cull_argument.size() == 0) {
-					p_scene_render->cull_argument.push_back(nullptr);
+				if (RendererSceneRenderRD::get_singleton()->cull_argument.size() == 0) {
+					RendererSceneRenderRD::get_singleton()->cull_argument.push_back(nullptr);
 				}
-				p_scene_render->cull_argument[0] = instance;
+				RendererSceneRenderRD::get_singleton()->cull_argument[0] = instance;
 
 				float exposure_normalization = 1.0;
-				if (p_scene_render->is_using_physical_light_units()) {
+				if (RendererSceneRenderRD::get_singleton()->is_using_physical_light_units()) {
 					exposure_normalization = gi->voxel_gi_get_baked_exposure_normalization(probe);
 				}
 
-				p_scene_render->_render_material(to_world_xform * xform, cm, true, p_scene_render->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size), exposure_normalization);
+				RendererSceneRenderRD::get_singleton()->_render_material(to_world_xform * xform, cm, true, RendererSceneRenderRD::get_singleton()->cull_argument, dynamic_maps[0].fb, Rect2i(Vector2i(), rect.size), exposure_normalization);
 
 				VoxelGIDynamicPushConstant push_constant;
 				memset(&push_constant, 0, sizeof(VoxelGIDynamicPushConstant));
@@ -3591,7 +3606,7 @@ Ref<GI::SDFGI> GI::create_sdfgi(RID p_env, const Vector3 &p_world_position, uint
 	return sdfgi;
 }
 
-void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render) {
+void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used) {
 	ERR_FAIL_COND(p_render_buffers.is_null());
 
 	RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
@@ -4051,11 +4066,11 @@ bool GI::voxel_gi_needs_update(RID p_probe) const {
 	return voxel_gi->last_probe_version != voxel_gi_get_version(voxel_gi->probe);
 }
 
-void GI::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render) {
+void GI::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects) {
 	VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_probe);
 	ERR_FAIL_COND(!voxel_gi);
 
-	voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects, p_scene_render);
+	voxel_gi->update(p_update_light_instances, p_light_instances, p_dynamic_objects);
 }
 
 void GI::debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) {

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

@@ -145,7 +145,7 @@ public:
 
 		Transform3D transform;
 
-		void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+		void update(bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects);
 		void debug(RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
 		void free_resources();
 	};
@@ -687,9 +687,9 @@ public:
 		void debug_draw(uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, int p_width, int p_height, RID p_render_target, RID p_texture, const Vector<RID> &p_texture_views);
 		void debug_probes(RID p_framebuffer, const uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
 
-		void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data, RendererSceneRenderRD *p_scene_render);
-		void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render, float p_exposure_normalization);
-		void render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render);
+		void pre_process_gi(const Transform3D &p_transform, RenderDataRD *p_render_data);
+		void render_region(Ref<RenderSceneBuffersRD> p_render_buffers, int p_region, const PagedArray<RenderGeometryInstance *> &p_instances, float p_exposure_normalization);
+		void render_static_lights(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result);
 	};
 
 	RS::EnvironmentSDFGIRayCount sdfgi_ray_count = RS::ENV_SDFGI_RAY_COUNT_16;
@@ -812,13 +812,13 @@ public:
 
 	Ref<SDFGI> create_sdfgi(RID p_env, const Vector3 &p_world_position, uint32_t p_requested_history_size);
 
-	void setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used, RendererSceneRenderRD *p_scene_render);
+	void setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBuffersRD> p_render_buffers, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, uint32_t &r_voxel_gi_instances_used);
 	void process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer, RID p_environment, uint32_t p_view_count, const Projection *p_projections, const Vector3 *p_eye_offsets, const Transform3D &p_cam_transform, const PagedArray<RID> &p_voxel_gi_instances);
 
 	RID voxel_gi_instance_create(RID p_base);
 	void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform);
 	bool voxel_gi_needs_update(RID p_probe) const;
-	void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects, RendererSceneRenderRD *p_scene_render);
+	void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector<RID> &p_light_instances, const PagedArray<RenderGeometryInstance *> &p_dynamic_objects);
 	void debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const Projection &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha);
 };
 

+ 3 - 4
servers/rendering/renderer_rd/environment/sky.cpp

@@ -1200,18 +1200,17 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
 			// This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called
 			// after the depth prepass, but this runs before the depth prepass
 			for (int i = 0; i < (int)p_lights.size(); i++) {
-				RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_lights[i]);
-				if (!li) {
+				if (!light_storage->owns_light_instance(p_lights[i])) {
 					continue;
 				}
-				RID base = li->light;
+				RID base = light_storage->light_instance_get_base_light(p_lights[i]);
 
 				ERR_CONTINUE(base.is_null());
 
 				RS::LightType type = light_storage->light_get_type(base);
 				if (type == RS::LIGHT_DIRECTIONAL && light_storage->light_directional_get_sky_mode(base) != RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_ONLY) {
 					SkyDirectionalLightData &sky_light_data = sky_scene_state.directional_lights[sky_scene_state.ubo.directional_light_count];
-					Transform3D light_transform = li->transform;
+					Transform3D light_transform = light_storage->light_instance_get_base_transform(p_lights[i]);
 					Vector3 world_direction = light_transform.basis.xform(Vector3(0, 0, 1)).normalized();
 
 					sky_light_data.direction[0] = world_direction.x;

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 792 - 24
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp


+ 79 - 10
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h

@@ -32,7 +32,9 @@
 #define RENDER_FORWARD_CLUSTERED_H
 
 #include "core/templates/paged_allocator.h"
+#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
 #include "servers/rendering/renderer_rd/effects/resolve.h"
+#include "servers/rendering/renderer_rd/effects/ss_effects.h"
 #include "servers/rendering/renderer_rd/effects/taa.h"
 #include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
 #include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
@@ -99,7 +101,21 @@ class RenderForwardClustered : public RendererSceneRenderRD {
 		RD::TextureSamples texture_samples = RD::TEXTURE_SAMPLES_1;
 
 	public:
-		//for rendering, may be MSAAd
+		ClusterBuilderRD *cluster_builder = nullptr;
+
+		struct SSEffectsData {
+			RID linear_depth;
+			Vector<RID> linear_depth_slices;
+
+			RID downsample_uniform_set;
+
+			Projection last_frame_projection;
+			Transform3D last_frame_transform;
+
+			RendererRD::SSEffects::SSAORenderBuffers ssao;
+			RendererRD::SSEffects::SSILRenderBuffers ssil;
+			RendererRD::SSEffects::SSRRenderBuffers ssr;
+		} ss_effects_data;
 
 		enum DepthFrameBufferType {
 			DEPTH_FB,
@@ -139,6 +155,9 @@ class RenderForwardClustered : public RendererSceneRenderRD {
 		RID get_depth_fb(DepthFrameBufferType p_type = DEPTH_FB);
 		RID get_specular_only_fb();
 
+		RID get_ao_texture() const { return ss_effects_data.ssao.ao_final; }
+		RID get_ssil_texture() const { return ss_effects_data.ssil.ssil_final; }
+
 		virtual void configure(RenderSceneBuffersRD *p_render_buffers) override;
 		virtual void free_data() override;
 	};
@@ -149,10 +168,6 @@ class RenderForwardClustered : public RendererSceneRenderRD {
 
 	uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
 
-	virtual void _base_uniforms_changed() override;
-	virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
-	virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
-
 	bool base_uniform_set_updated = false;
 	void _update_render_base_uniform_set();
 	RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture);
@@ -558,16 +573,61 @@ class RenderForwardClustered : public RendererSceneRenderRD {
 
 	virtual void _update_shader_quality_settings() override;
 
+	/* Effects */
+
 	RendererRD::Resolve *resolve_effects = nullptr;
 	RendererRD::TAA *taa = nullptr;
+	RendererRD::SSEffects *ss_effects = nullptr;
+
+	/* Cluster builder */
+
+	ClusterBuilderSharedDataRD cluster_builder_shared;
+	ClusterBuilderRD *current_cluster_builder = nullptr;
+
+	/* SDFGI */
+	void _update_sdfgi(RenderDataRD *p_render_data);
+
+	/* Volumetric fog */
+	RID shadow_sampler;
+
+	void _update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes);
+
+	/* Render shadows */
+
+	void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
+	void _render_shadow_begin();
+	void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
+	void _render_shadow_process();
+	void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
+
+	/* Render Scene */
+	void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection);
+	void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform);
+	void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers);
+	void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
+	void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
+	void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
+
+	/* Debug */
+	void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers);
 
 protected:
-	virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+	/* setup */
+
+	virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+	virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+
+	virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
+	virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
+	virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override;
 
-	virtual void _render_shadow_begin() override;
-	virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) override;
-	virtual void _render_shadow_process() override;
-	virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
+	virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override;
+	virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override;
+
+	/* Rendering */
+
+	virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+	virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) override;
 
 	virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
 	virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
@@ -577,6 +637,15 @@ protected:
 public:
 	static RenderForwardClustered *get_singleton() { return singleton; }
 
+	ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; }
+	RendererRD::SSEffects *get_ss_effects() { return ss_effects; }
+
+	/* callback from updating our lighting UBOs, used to populate cluster builder */
+	virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents) override;
+	virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture) override;
+	virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents) override;
+
+	virtual void base_uniforms_changed() override;
 	_FORCE_INLINE_ virtual void update_uniform_sets() override {
 		base_uniform_set_updated = true;
 		_update_render_base_uniform_set();

+ 363 - 97
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp

@@ -39,7 +39,7 @@
 
 using namespace RendererSceneRenderImplementation;
 
-RenderForwardMobile::ForwardID RenderForwardMobile::_allocate_forward_id(ForwardIDType p_type) {
+RendererRD::ForwardID RenderForwardMobile::ForwardIDStorageMobile::allocate_forward_id(RendererRD::ForwardIDType p_type) {
 	int32_t index = -1;
 	for (uint32_t i = 0; i < forward_id_allocators[p_type].allocations.size(); i++) {
 		if (forward_id_allocators[p_type].allocations[i] == false) {
@@ -58,15 +58,66 @@ RenderForwardMobile::ForwardID RenderForwardMobile::_allocate_forward_id(Forward
 
 	return index;
 }
-void RenderForwardMobile::_free_forward_id(ForwardIDType p_type, ForwardID p_id) {
-	ERR_FAIL_INDEX(p_id, (ForwardID)forward_id_allocators[p_type].allocations.size());
+void RenderForwardMobile::ForwardIDStorageMobile::free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) {
+	ERR_FAIL_INDEX(p_id, (RendererRD::ForwardID)forward_id_allocators[p_type].allocations.size());
 	forward_id_allocators[p_type].allocations[p_id] = false;
 }
 
-void RenderForwardMobile::_map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {
+void RenderForwardMobile::ForwardIDStorageMobile::map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) {
 	forward_id_allocators[p_type].map[p_id] = p_index;
 }
 
+void RenderForwardMobile::ForwardIDStorageMobile::fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
+	// first zero out our indices
+
+	p_push_constant->omni_lights[0] = 0xFFFF;
+	p_push_constant->omni_lights[1] = 0xFFFF;
+
+	p_push_constant->spot_lights[0] = 0xFFFF;
+	p_push_constant->spot_lights[1] = 0xFFFF;
+
+	p_push_constant->decals[0] = 0xFFFF;
+	p_push_constant->decals[1] = 0xFFFF;
+
+	p_push_constant->reflection_probes[0] = 0xFFFF;
+	p_push_constant->reflection_probes[1] = 0xFFFF;
+
+	if (p_instance->omni_light_count == 0) {
+		spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
+	}
+	if (p_instance->spot_light_count == 0) {
+		spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
+	}
+	if (p_instance->reflection_probe_count == 0) {
+		spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
+	}
+	if (p_instance->decals_count == 0) {
+		spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
+	}
+
+	for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
+		uint32_t ofs = i < 4 ? 0 : 1;
+		uint32_t shift = (i & 0x3) << 3;
+		uint32_t mask = ~(0xFF << shift);
+		if (i < p_instance->omni_light_count) {
+			p_push_constant->omni_lights[ofs] &= mask;
+			p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
+		}
+		if (i < p_instance->spot_light_count) {
+			p_push_constant->spot_lights[ofs] &= mask;
+			p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
+		}
+		if (i < p_instance->decals_count) {
+			p_push_constant->decals[ofs] &= mask;
+			p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
+		}
+		if (i < p_instance->reflection_probe_count) {
+			p_push_constant->reflection_probes[ofs] &= mask;
+			p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[RendererRD::FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
+		}
+	}
+}
+
 /* Render buffer */
 
 void RenderForwardMobile::RenderBufferDataForwardMobile::free_data() {
@@ -300,6 +351,7 @@ bool RenderForwardMobile::_render_buffers_can_be_storage() {
 }
 
 RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas, int p_index) {
+	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
 	RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
 
 	//there should always be enough uniform buffers for render passes, otherwise bugs
@@ -340,7 +392,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
 	}
 
 	{
-		RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
+		RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? light_storage->reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
 		RD::Uniform u;
 		u.binding = 3;
 		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
@@ -358,7 +410,7 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
 		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
 		RID texture;
 		if (p_render_data && p_render_data->shadow_atlas.is_valid()) {
-			texture = shadow_atlas_get_texture(p_render_data->shadow_atlas);
+			texture = light_storage->shadow_atlas_get_texture(p_render_data->shadow_atlas);
 		}
 		if (!texture.is_valid()) {
 			texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
@@ -370,8 +422,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
 		RD::Uniform u;
 		u.binding = 5;
 		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
-		if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) {
-			u.append_id(directional_shadow_get_texture());
+		if (p_use_directional_shadow_atlas && light_storage->directional_shadow_get_texture().is_valid()) {
+			u.append_id(light_storage->directional_shadow_get_texture());
 		} else {
 			u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH));
 		}
@@ -387,8 +439,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
 		RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
 		for (uint32_t i = 0; i < scene_state.max_lightmaps; i++) {
 			if (p_render_data && i < p_render_data->lightmaps->size()) {
-				RID base = lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
-				RID texture = RendererRD::LightStorage::get_singleton()->lightmap_get_texture(base);
+				RID base = light_storage->lightmap_instance_get_lightmap((*p_render_data->lightmaps)[i]);
+				RID texture = light_storage->lightmap_get_texture(base);
 				RID rd_texture = texture_storage->texture_get_rd_texture(texture);
 				u.append_id(rd_texture);
 			} else {
@@ -467,6 +519,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
 }
 
 void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform) {
+	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
 	// This probably needs to change...
 	scene_state.lightmaps_used = 0;
 	for (int i = 0; i < (int)p_lightmaps.size(); i++) {
@@ -474,20 +528,20 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co
 			break;
 		}
 
-		RID lightmap = lightmap_instance_get_lightmap(p_lightmaps[i]);
+		RID lightmap = light_storage->lightmap_instance_get_lightmap(p_lightmaps[i]);
 
-		Basis to_lm = lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
+		Basis to_lm = light_storage->lightmap_instance_get_transform(p_lightmaps[i]).basis.inverse() * p_cam_transform.basis;
 		to_lm = to_lm.inverse().transposed(); //will transform normals
 		RendererRD::MaterialStorage::store_transform_3x3(to_lm, scene_state.lightmaps[i].normal_xform);
 		scene_state.lightmaps[i].exposure_normalization = 1.0;
 		if (p_render_data->camera_attributes.is_valid()) {
-			float baked_exposure = RendererRD::LightStorage::get_singleton()->lightmap_get_baked_exposure_normalization(lightmap);
+			float baked_exposure = light_storage->lightmap_get_baked_exposure_normalization(lightmap);
 			float enf = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
 			scene_state.lightmaps[i].exposure_normalization = enf / baked_exposure;
 		}
 
 		scene_state.lightmap_ids[i] = p_lightmaps[i];
-		scene_state.lightmap_has_sh[i] = RendererRD::LightStorage::get_singleton()->lightmap_uses_spherical_harmonics(lightmap);
+		scene_state.lightmap_has_sh[i] = light_storage->lightmap_uses_spherical_harmonics(lightmap);
 
 		scene_state.lightmaps_used++;
 	}
@@ -496,12 +550,103 @@ void RenderForwardMobile::_setup_lightmaps(const RenderDataRD *p_render_data, co
 	}
 }
 
+void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) {
+	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+	RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
+
+	p_render_data->cube_shadows.clear();
+	p_render_data->shadows.clear();
+	p_render_data->directional_shadows.clear();
+
+	Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
+	float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier();
+	{
+		for (int i = 0; i < p_render_data->render_shadow_count; i++) {
+			RID li = p_render_data->render_shadows[i].light;
+			RID base = light_storage->light_instance_get_base_light(li);
+
+			if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+				p_render_data->directional_shadows.push_back(i);
+			} else if (light_storage->light_get_type(base) == RS::LIGHT_OMNI && light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+				p_render_data->cube_shadows.push_back(i);
+			} else {
+				p_render_data->shadows.push_back(i);
+			}
+		}
+
+		//cube shadows are rendered in their own way
+		for (uint32_t i = 0; i < p_render_data->cube_shadows.size(); i++) {
+			_render_shadow_pass(p_render_data->render_shadows[p_render_data->cube_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->cube_shadows[i]].pass, p_render_data->render_shadows[p_render_data->cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
+		}
+
+		if (p_render_data->directional_shadows.size()) {
+			//open the pass for directional shadows
+			light_storage->update_directional_shadow_atlas();
+			RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_CONTINUE);
+			RD::get_singleton()->draw_list_end();
+		}
+	}
+
+	bool render_shadows = p_render_data->directional_shadows.size() || p_render_data->shadows.size();
+
+	if (render_shadows) {
+		RENDER_TIMESTAMP("Render Shadows");
+	}
+
+	//prepare shadow rendering
+	if (render_shadows) {
+		_render_shadow_begin();
+
+		//render directional shadows
+		for (uint32_t i = 0; i < p_render_data->directional_shadows.size(); i++) {
+			_render_shadow_pass(p_render_data->render_shadows[p_render_data->directional_shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->directional_shadows[i]].pass, p_render_data->render_shadows[p_render_data->directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == p_render_data->directional_shadows.size() - 1, false, p_render_data->render_info);
+		}
+		//render positional shadows
+		for (uint32_t i = 0; i < p_render_data->shadows.size(); i++) {
+			_render_shadow_pass(p_render_data->render_shadows[p_render_data->shadows[i]].light, p_render_data->shadow_atlas, p_render_data->render_shadows[p_render_data->shadows[i]].pass, p_render_data->render_shadows[p_render_data->shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == p_render_data->shadows.size() - 1, true, p_render_data->render_info);
+		}
+
+		_render_shadow_process();
+
+		_render_shadow_end(RD::BARRIER_MASK_NO_BARRIER);
+	}
+
+	//full barrier here, we need raster, transfer and compute and it depends from the previous work
+	RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL);
+
+	bool using_shadows = true;
+
+	if (p_render_data->reflection_probe.is_valid()) {
+		if (!RSG::light_storage->reflection_probe_renders_shadows(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+			using_shadows = false;
+		}
+	} else {
+		//do not render reflections when rendering a reflection probe
+		light_storage->update_reflection_probe_buffer(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment);
+	}
+
+	uint32_t directional_light_count = 0;
+	uint32_t positional_light_count = 0;
+	light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
+	texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse());
+
+	p_render_data->directional_light_count = directional_light_count;
+}
+
 void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) {
+	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
+	Ref<RenderSceneBuffersRD> rb;
 	Ref<RenderBufferDataForwardMobile> rb_data;
 	if (p_render_data->render_buffers.is_valid()) {
-		rb_data = p_render_data->render_buffers->get_custom_data(RB_SCOPE_MOBILE);
+		rb = p_render_data->render_buffers;
+		rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
 	}
 
+	RENDER_TIMESTAMP("Prepare 3D Scene");
+
+	_update_vrs(rb);
+
 	RENDER_TIMESTAMP("Setup 3D Scene");
 
 	/* TODO
@@ -532,9 +677,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 	bool using_subpass_transparent = true;
 	bool using_subpass_post_process = true;
 
-	bool using_ssr = false; // I don't think we support this in our mobile renderer so probably should phase it out
-	bool using_sss = false; // I don't think we support this in our mobile renderer so probably should phase it out
-
 	// fill our render lists early so we can find out if we use various features
 	_fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR);
 	render_list[RENDER_LIST_OPAQUE].sort_by_key();
@@ -559,7 +701,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 			using_subpass_post_process = false;
 		}
 
-		if (using_ssr || using_sss || scene_state.used_screen_texture || scene_state.used_depth_texture) {
+		if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
 			// can't use our last two subpasses
 			using_subpass_transparent = false;
 			using_subpass_post_process = false;
@@ -576,13 +718,13 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 			framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_TWO_SUBPASSES);
 		}
 	} else if (p_render_data->reflection_probe.is_valid()) {
-		uint32_t resolution = reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+		uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
 		screen_size.x = resolution;
 		screen_size.y = resolution;
 
-		framebuffer = reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+		framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
 
-		if (RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
+		if (light_storage->reflection_probe_is_interior(light_storage->reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
 			p_render_data->environment = RID(); //no environment on interiors
 		}
 
@@ -713,8 +855,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 		RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
 	}
 
-	RID nullrids[RendererSceneRender::MAX_RENDER_VIEWS];
-	_pre_opaque_render(p_render_data, false, false, false, nullrids, RID());
+	_pre_opaque_render(p_render_data);
 
 	uint32_t spec_constant_base_flags = 0;
 
@@ -758,8 +899,8 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 
 		RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, true);
 
-		bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture && !using_ssr && !using_sss;
-		bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture && !using_ssr && !using_sss;
+		bool can_continue_color = !using_subpass_transparent && !scene_state.used_screen_texture;
+		bool can_continue_depth = !using_subpass_transparent && !scene_state.used_depth_texture;
 
 		{
 			// regular forward for now
@@ -917,10 +1058,190 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 	if (rb_data.is_valid()) {
 		_disable_clear_request(p_render_data);
 	}
+
+	if (rb.is_valid()) {
+		_render_buffers_debug_draw(rb, p_render_data->shadow_atlas, p_render_data->occluder_debug_tex);
+	}
 }
 
 /* these are being called from RendererSceneRenderRD::_pre_opaque_render */
 
+void RenderForwardMobile::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_mesh_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RenderingMethod::RenderInfo *p_render_info) {
+	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+
+	ERR_FAIL_COND(!light_storage->owns_light_instance(p_light));
+
+	RID base = light_storage->light_instance_get_base_light(p_light);
+
+	Rect2i atlas_rect;
+	uint32_t atlas_size = 1;
+	RID atlas_fb;
+
+	bool using_dual_paraboloid = false;
+	bool using_dual_paraboloid_flip = false;
+	Vector2i dual_paraboloid_offset;
+	RID render_fb;
+	RID render_texture;
+	float zfar;
+
+	bool use_pancake = false;
+	bool render_cubemap = false;
+	bool finalize_cubemap = false;
+
+	bool flip_y = false;
+
+	Projection light_projection;
+	Transform3D light_transform;
+
+	if (light_storage->light_get_type(base) == RS::LIGHT_DIRECTIONAL) {
+		//set pssm stuff
+		uint64_t last_scene_shadow_pass = light_storage->light_instance_get_shadow_pass(p_light);
+		if (last_scene_shadow_pass != get_scene_pass()) {
+			light_storage->light_instance_set_directional_rect(p_light, light_storage->get_directional_shadow_rect());
+			light_storage->directional_shadow_increase_current_light();
+			light_storage->light_instance_set_shadow_pass(p_light, get_scene_pass());
+		}
+
+		use_pancake = light_storage->light_get_param(base, RS::LIGHT_PARAM_SHADOW_PANCAKE_SIZE) > 0;
+		light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass);
+		light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass);
+
+		atlas_rect = light_storage->light_instance_get_directional_rect(p_light);
+
+		if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+			atlas_rect.size.width /= 2;
+			atlas_rect.size.height /= 2;
+
+			if (p_pass == 1) {
+				atlas_rect.position.x += atlas_rect.size.width;
+			} else if (p_pass == 2) {
+				atlas_rect.position.y += atlas_rect.size.height;
+			} else if (p_pass == 3) {
+				atlas_rect.position += atlas_rect.size;
+			}
+		} else if (light_storage->light_directional_get_shadow_mode(base) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+			atlas_rect.size.height /= 2;
+
+			if (p_pass == 0) {
+			} else {
+				atlas_rect.position.y += atlas_rect.size.height;
+			}
+		}
+
+		int directional_shadow_size = light_storage->directional_shadow_get_size();
+		atlas_rect.position /= directional_shadow_size;
+		atlas_rect.size /= directional_shadow_size;
+
+		light_storage->light_instance_set_directional_shadow_atlas_rect(p_light, p_pass, atlas_rect);
+
+		zfar = RSG::light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
+
+		render_fb = light_storage->direction_shadow_get_fb();
+		render_texture = RID();
+		flip_y = true;
+
+	} else {
+		//set from shadow atlas
+
+		ERR_FAIL_COND(!light_storage->owns_shadow_atlas(p_shadow_atlas));
+		ERR_FAIL_COND(!light_storage->shadow_atlas_owns_light_instance(p_shadow_atlas, p_light));
+
+		RSG::light_storage->shadow_atlas_update(p_shadow_atlas);
+
+		uint32_t key = light_storage->shadow_atlas_get_light_instance_key(p_shadow_atlas, p_light);
+
+		uint32_t quadrant = (key >> RendererRD::LightStorage::QUADRANT_SHIFT) & 0x3;
+		uint32_t shadow = key & RendererRD::LightStorage::SHADOW_INDEX_MASK;
+		uint32_t subdivision = light_storage->shadow_atlas_get_quadrant_subdivision(p_shadow_atlas, quadrant);
+
+		ERR_FAIL_INDEX((int)shadow, light_storage->shadow_atlas_get_quadrant_shadow_size(p_shadow_atlas, quadrant));
+
+		uint32_t shadow_atlas_size = light_storage->shadow_atlas_get_size(p_shadow_atlas);
+		uint32_t quadrant_size = shadow_atlas_size >> 1;
+
+		atlas_rect.position.x = (quadrant & 1) * quadrant_size;
+		atlas_rect.position.y = (quadrant >> 1) * quadrant_size;
+
+		uint32_t shadow_size = (quadrant_size / subdivision);
+		atlas_rect.position.x += (shadow % subdivision) * shadow_size;
+		atlas_rect.position.y += (shadow / subdivision) * shadow_size;
+
+		atlas_rect.size.width = shadow_size;
+		atlas_rect.size.height = shadow_size;
+
+		zfar = light_storage->light_get_param(base, RS::LIGHT_PARAM_RANGE);
+
+		if (light_storage->light_get_type(base) == RS::LIGHT_OMNI) {
+			bool wrap = (shadow + 1) % subdivision == 0;
+			dual_paraboloid_offset = wrap ? Vector2i(1 - subdivision, 1) : Vector2i(1, 0);
+
+			if (light_storage->light_omni_get_shadow_mode(base) == RS::LIGHT_OMNI_SHADOW_CUBE) {
+				render_texture = light_storage->get_cubemap(shadow_size / 2);
+				render_fb = light_storage->get_cubemap_fb(shadow_size / 2, p_pass);
+
+				light_projection = light_storage->light_instance_get_shadow_camera(p_light, p_pass);
+				light_transform = light_storage->light_instance_get_shadow_transform(p_light, p_pass);
+				render_cubemap = true;
+				finalize_cubemap = p_pass == 5;
+				atlas_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+
+				atlas_size = shadow_atlas_size;
+
+				if (p_pass == 0) {
+					_render_shadow_begin();
+				}
+
+			} else {
+				atlas_rect.position.x += 1;
+				atlas_rect.position.y += 1;
+				atlas_rect.size.x -= 2;
+				atlas_rect.size.y -= 2;
+
+				atlas_rect.position += p_pass * atlas_rect.size * dual_paraboloid_offset;
+
+				light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
+				light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
+
+				using_dual_paraboloid = true;
+				using_dual_paraboloid_flip = p_pass == 1;
+				render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+				flip_y = true;
+			}
+
+		} else if (light_storage->light_get_type(base) == RS::LIGHT_SPOT) {
+			light_projection = light_storage->light_instance_get_shadow_camera(p_light, 0);
+			light_transform = light_storage->light_instance_get_shadow_transform(p_light, 0);
+
+			render_fb = light_storage->shadow_atlas_get_fb(p_shadow_atlas);
+
+			flip_y = true;
+		}
+	}
+
+	if (render_cubemap) {
+		//rendering to cubemap
+		_render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, false, false, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, Rect2(), false, true, true, true, p_render_info);
+		if (finalize_cubemap) {
+			_render_shadow_process();
+			_render_shadow_end();
+			//reblit
+			Rect2 atlas_rect_norm = atlas_rect;
+			atlas_rect_norm.position /= float(atlas_size);
+			atlas_rect_norm.size /= float(atlas_size);
+			copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
+			atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
+			copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
+
+			//restore transform so it can be properly used
+			light_storage->light_instance_set_shadow_transform(p_light, Projection(), light_storage->light_instance_get_base_transform(p_light), zfar, 0, 0, 0);
+		}
+
+	} else {
+		//render shadow
+		_render_shadow_append(render_fb, p_instances, light_projection, light_transform, zfar, 0, 0, using_dual_paraboloid, using_dual_paraboloid_flip, use_pancake, p_camera_plane, p_lod_distance_multiplier, p_screen_mesh_lod_threshold, atlas_rect, flip_y, p_clear_region, p_open_pass, p_close_pass, p_render_info);
+	}
+}
+
 void RenderForwardMobile::_render_shadow_begin() {
 	scene_state.shadow_passes.clear();
 	RD::get_singleton()->draw_command_begin_label("Shadow Setup");
@@ -1146,7 +1467,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
 }
 
 void RenderForwardMobile::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) {
-	// we don't do GI in low end..
+	// we don't do SDFGI in low end..
 }
 
 void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) {
@@ -1189,7 +1510,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
 	RD::get_singleton()->draw_command_end_label();
 }
 
-void RenderForwardMobile::_base_uniforms_changed() {
+void RenderForwardMobile::base_uniforms_changed() {
 	if (!render_base_uniform_set.is_null() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
 		RD::get_singleton()->free(render_base_uniform_set);
 	}
@@ -1305,14 +1626,14 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
 			RD::Uniform u;
 			u.binding = 5;
 			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
-			u.append_id(get_omni_light_buffer());
+			u.append_id(RendererRD::LightStorage::get_singleton()->get_omni_light_buffer());
 			uniforms.push_back(u);
 		}
 		{
 			RD::Uniform u;
 			u.binding = 6;
 			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
-			u.append_id(get_spot_light_buffer());
+			u.append_id(RendererRD::LightStorage::get_singleton()->get_spot_light_buffer());
 			uniforms.push_back(u);
 		}
 
@@ -1320,14 +1641,14 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
 			RD::Uniform u;
 			u.binding = 7;
 			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
-			u.append_id(get_reflection_probe_buffer());
+			u.append_id(RendererRD::LightStorage::get_singleton()->get_reflection_probe_buffer());
 			uniforms.push_back(u);
 		}
 		{
 			RD::Uniform u;
 			u.binding = 8;
 			u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
-			u.append_id(get_directional_light_buffer());
+			u.append_id(RendererRD::LightStorage::get_singleton()->get_directional_light_buffer());
 			uniforms.push_back(u);
 		}
 		{
@@ -1364,7 +1685,7 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
 			RD::Uniform u;
 			u.binding = 13;
 			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
-			u.append_id(get_decal_buffer());
+			u.append_id(RendererRD::TextureStorage::get_singleton()->get_decal_buffer());
 			uniforms.push_back(u);
 		}
 
@@ -1584,7 +1905,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
 void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
 	Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
 	RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
-	RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
+	RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? RendererRD::LightStorage::get_singleton()->reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
 
 	// May do this earlier in RenderSceneRenderRD::render_scene
 	if (p_index >= (int)scene_state.uniform_buffers.size()) {
@@ -1665,57 +1986,6 @@ void RenderForwardMobile::_render_list_with_threads(RenderListParameters *p_para
 	}
 }
 
-void RenderForwardMobile::_fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance) {
-	// first zero out our indices
-
-	p_push_constant->omni_lights[0] = 0xFFFF;
-	p_push_constant->omni_lights[1] = 0xFFFF;
-
-	p_push_constant->spot_lights[0] = 0xFFFF;
-	p_push_constant->spot_lights[1] = 0xFFFF;
-
-	p_push_constant->decals[0] = 0xFFFF;
-	p_push_constant->decals[1] = 0xFFFF;
-
-	p_push_constant->reflection_probes[0] = 0xFFFF;
-	p_push_constant->reflection_probes[1] = 0xFFFF;
-
-	if (p_instance->omni_light_count == 0) {
-		spec_constants |= 1 << SPEC_CONSTANT_DISABLE_OMNI_LIGHTS;
-	}
-	if (p_instance->spot_light_count == 0) {
-		spec_constants |= 1 << SPEC_CONSTANT_DISABLE_SPOT_LIGHTS;
-	}
-	if (p_instance->reflection_probe_count == 0) {
-		spec_constants |= 1 << SPEC_CONSTANT_DISABLE_REFLECTION_PROBES;
-	}
-	if (p_instance->decals_count == 0) {
-		spec_constants |= 1 << SPEC_CONSTANT_DISABLE_DECALS;
-	}
-
-	for (uint32_t i = 0; i < MAX_RDL_CULL; i++) {
-		uint32_t ofs = i < 4 ? 0 : 1;
-		uint32_t shift = (i & 0x3) << 3;
-		uint32_t mask = ~(0xFF << shift);
-		if (i < p_instance->omni_light_count) {
-			p_push_constant->omni_lights[ofs] &= mask;
-			p_push_constant->omni_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_OMNI_LIGHT].map[p_instance->omni_lights[i]]) << shift;
-		}
-		if (i < p_instance->spot_light_count) {
-			p_push_constant->spot_lights[ofs] &= mask;
-			p_push_constant->spot_lights[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_SPOT_LIGHT].map[p_instance->spot_lights[i]]) << shift;
-		}
-		if (i < p_instance->decals_count) {
-			p_push_constant->decals[ofs] &= mask;
-			p_push_constant->decals[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_DECAL].map[p_instance->decals[i]]) << shift;
-		}
-		if (i < p_instance->reflection_probe_count) {
-			p_push_constant->reflection_probes[ofs] &= mask;
-			p_push_constant->reflection_probes[ofs] |= uint32_t(forward_id_allocators[FORWARD_ID_TYPE_REFLECTION_PROBE].map[p_instance->reflection_probes[i]]) << shift;
-		}
-	}
-}
-
 template <RenderForwardMobile::PassMode p_pass_mode>
 void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) {
 	RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
@@ -1797,7 +2067,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
 			if (inst->use_soft_shadow) {
 				base_spec_constants |= 1 << SPEC_CONSTANT_USING_SOFT_SHADOWS;
 			}
-			_fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
+			forward_id_storage_mobile->fill_push_constant_instance_indices(&push_constant, base_spec_constants, inst);
 
 #ifdef DEBUG_ENABLED
 			if (unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING)) {
@@ -1989,17 +2259,17 @@ void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instances(co
 	spot_light_count = 0;
 
 	for (uint32_t i = 0; i < p_light_instance_count; i++) {
-		RS::LightType type = RenderForwardMobile::get_singleton()->light_instance_get_type(p_light_instances[i]);
+		RS::LightType type = RendererRD::LightStorage::get_singleton()->light_instance_get_type(p_light_instances[i]);
 		switch (type) {
 			case RS::LIGHT_OMNI: {
 				if (omni_light_count < (uint32_t)MAX_RDL_CULL) {
-					omni_lights[omni_light_count] = RenderForwardMobile::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
+					omni_lights[omni_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
 					omni_light_count++;
 				}
 			} break;
 			case RS::LIGHT_SPOT: {
 				if (spot_light_count < (uint32_t)MAX_RDL_CULL) {
-					spot_lights[spot_light_count] = RenderForwardMobile::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
+					spot_lights[spot_light_count] = RendererRD::LightStorage::get_singleton()->light_instance_get_forward_id(p_light_instances[i]);
 					spot_light_count++;
 				}
 			} break;
@@ -2012,14 +2282,14 @@ void RenderForwardMobile::GeometryInstanceForwardMobile::pair_light_instances(co
 void RenderForwardMobile::GeometryInstanceForwardMobile::pair_reflection_probe_instances(const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) {
 	reflection_probe_count = p_reflection_probe_instance_count < (uint32_t)MAX_RDL_CULL ? p_reflection_probe_instance_count : (uint32_t)MAX_RDL_CULL;
 	for (uint32_t i = 0; i < reflection_probe_count; i++) {
-		reflection_probes[i] = RenderForwardMobile::get_singleton()->reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]);
+		reflection_probes[i] = RendererRD::LightStorage::get_singleton()->reflection_probe_instance_get_forward_id(p_reflection_probe_instances[i]);
 	}
 }
 
 void RenderForwardMobile::GeometryInstanceForwardMobile::pair_decal_instances(const RID *p_decal_instances, uint32_t p_decal_instance_count) {
 	decals_count = p_decal_instance_count < (uint32_t)MAX_RDL_CULL ? p_decal_instance_count : (uint32_t)MAX_RDL_CULL;
 	for (uint32_t i = 0; i < decals_count; i++) {
-		decals[i] = RenderForwardMobile::get_singleton()->decal_instance_get_forward_id(p_decal_instances[i]);
+		decals[i] = RendererRD::TextureStorage::get_singleton()->decal_instance_get_forward_id(p_decal_instances[i]);
 	}
 }
 
@@ -2387,10 +2657,6 @@ bool RenderForwardMobile::is_dynamic_gi_supported() const {
 	return false;
 }
 
-bool RenderForwardMobile::is_clustered_enabled() const {
-	return false;
-}
-
 bool RenderForwardMobile::is_volumetric_supported() const {
 	return false;
 }
@@ -2446,7 +2712,7 @@ void RenderForwardMobile::_update_shader_quality_settings() {
 
 	scene_shader.set_default_specialization_constants(spec_constants);
 
-	_base_uniforms_changed(); //also need this
+	base_uniforms_changed(); //also need this
 }
 
 RenderForwardMobile::RenderForwardMobile() {
@@ -2495,7 +2761,7 @@ RenderForwardMobile::RenderForwardMobile() {
 }
 
 RenderForwardMobile::~RenderForwardMobile() {
-	directional_shadow_atlas_set_size(0);
+	RSG::light_storage->directional_shadow_atlas_set_size(0);
 
 	//clear base uniform set if still valid
 	for (uint32_t i = 0; i < render_pass_uniform_sets.size(); i++) {

+ 73 - 38
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h

@@ -44,19 +44,12 @@ namespace RendererSceneRenderImplementation {
 class RenderForwardMobile : public RendererSceneRenderRD {
 	friend SceneShaderForwardMobile;
 
-	struct ForwardIDAllocator {
-		LocalVector<bool> allocations;
-		LocalVector<uint8_t> map;
-	};
-
-	ForwardIDAllocator forward_id_allocators[FORWARD_ID_MAX];
+protected:
+	struct GeometryInstanceSurfaceDataCache;
 
-	virtual ForwardID _allocate_forward_id(ForwardIDType p_type) override;
-	virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) override;
-	virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) override;
-	virtual bool _uses_forward_ids() const override { return true; }
+private:
+	static RenderForwardMobile *singleton;
 
-protected:
 	/* Scene Shader */
 
 	enum {
@@ -157,8 +150,6 @@ protected:
 		// PASS_MODE_SDF,
 	};
 
-	class GeometryInstanceForwardMobile;
-	struct GeometryInstanceSurfaceDataCache;
 	struct RenderElementInfo;
 
 	struct RenderListParameters {
@@ -201,36 +192,27 @@ protected:
 		}
 	};
 
-	virtual float _render_buffers_get_luminance_multiplier() override;
-	virtual RD::DataFormat _render_buffers_get_color_format() override;
-	virtual bool _render_buffers_can_be_storage() override;
+	/* Render shadows */
 
-	RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
-	virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+	void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
+	void _render_shadow_begin();
+	void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
+	void _render_shadow_process();
+	void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL);
 
-	virtual void _render_shadow_begin() override;
-	virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) override;
-	virtual void _render_shadow_process() override;
-	virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) override;
+	/* Render Scene */
 
-	virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
-	virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
-	virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) override;
-	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override;
+	RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
+	void _pre_opaque_render(RenderDataRD *p_render_data);
 
 	uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
 
-	virtual void _base_uniforms_changed() override;
 	void _update_render_base_uniform_set();
-	virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
-	virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
 
 	void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_append = false);
 	void _fill_element_info(RenderListType p_render_list, uint32_t p_offset = 0, int32_t p_max_elements = -1);
 	// void _update_instance_data_buffer(RenderListType p_render_list);
 
-	static RenderForwardMobile *singleton;
-
 	void _setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers = false, bool p_pancake_shadows = false, int p_index = 0);
 	void _setup_lightmaps(const RenderDataRD *p_render_data, const PagedArray<RID> &p_lightmaps, const Transform3D &p_cam_transform);
 
@@ -369,8 +351,28 @@ protected:
 
 	RenderList render_list[RENDER_LIST_MAX];
 
+protected:
+	/* setup */
+	virtual void _update_shader_quality_settings() override;
+
+	virtual float _render_buffers_get_luminance_multiplier() override;
+	virtual RD::DataFormat _render_buffers_get_color_format() override;
+	virtual bool _render_buffers_can_be_storage() override;
+
+	virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+	virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) override;
+
+	virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{};
+	virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override{};
+	virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override{};
+
+	virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override{};
+	virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override{};
+
 	/* Geometry instance */
 
+	class GeometryInstanceForwardMobile;
+
 	// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
 	enum {
 		INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
@@ -484,13 +486,13 @@ protected:
 
 		// culled light info
 		uint32_t reflection_probe_count = 0;
-		ForwardID reflection_probes[MAX_RDL_CULL];
+		RendererRD::ForwardID reflection_probes[MAX_RDL_CULL];
 		uint32_t omni_light_count = 0;
-		ForwardID omni_lights[MAX_RDL_CULL];
+		RendererRD::ForwardID omni_lights[MAX_RDL_CULL];
 		uint32_t spot_light_count = 0;
-		ForwardID spot_lights[MAX_RDL_CULL];
+		RendererRD::ForwardID spot_lights[MAX_RDL_CULL];
 		uint32_t decals_count = 0;
-		ForwardID decals[MAX_RDL_CULL];
+		RendererRD::ForwardID decals[MAX_RDL_CULL];
 
 		GeometryInstanceSurfaceDataCache *surface_caches = nullptr;
 
@@ -513,9 +515,41 @@ protected:
 		virtual void set_softshadow_projector_pairing(bool p_softshadow, bool p_projector) override;
 	};
 
-	_FORCE_INLINE_ void _fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance);
+	/* Rendering */
 
-	void _update_shader_quality_settings() override;
+	virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_bg_color) override;
+
+	virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) override;
+	virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
+	virtual void _render_sdfgi(Ref<RenderSceneBuffersRD> p_render_buffers, const Vector3i &p_from, const Vector3i &p_size, const AABB &p_bounds, const PagedArray<RenderGeometryInstance *> &p_instances, const RID &p_albedo_texture, const RID &p_emission_texture, const RID &p_emission_aniso_texture, const RID &p_geom_facing_texture, float p_exposure_normalization) override;
+	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) override;
+
+	/* Forward ID */
+
+	class ForwardIDStorageMobile : public RendererRD::ForwardIDStorage {
+	public:
+		struct ForwardIDAllocator {
+			LocalVector<bool> allocations;
+			LocalVector<uint8_t> map;
+		};
+
+		ForwardIDAllocator forward_id_allocators[RendererRD::FORWARD_ID_MAX];
+
+	public:
+		virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) override;
+		virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) override;
+		virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) override;
+		virtual bool uses_forward_ids() const override { return true; }
+
+		void fill_push_constant_instance_indices(GeometryInstanceForwardMobile::PushConstant *p_push_constant, uint32_t &spec_constants, const GeometryInstanceForwardMobile *p_instance);
+	};
+
+	ForwardIDStorageMobile *forward_id_storage_mobile = nullptr;
+
+	virtual RendererRD::ForwardIDStorage *create_forward_id_storage() override {
+		forward_id_storage_mobile = memnew(ForwardIDStorageMobile);
+		return forward_id_storage_mobile;
+	}
 
 public:
 	static RenderForwardMobile *get_singleton() { return singleton; }
@@ -544,8 +578,9 @@ public:
 
 	virtual bool free(RID p_rid) override;
 
+	virtual void base_uniforms_changed() override;
+
 	virtual bool is_dynamic_gi_supported() const override;
-	virtual bool is_clustered_enabled() const override;
 	virtual bool is_volumetric_supported() const override;
 	virtual uint32_t get_max_elements() const override;
 

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 549 - 2373
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp


+ 50 - 717
servers/rendering/renderer_rd/renderer_scene_render_rd.h

@@ -38,19 +38,21 @@
 #include "servers/rendering/renderer_rd/effects/bokeh_dof.h"
 #include "servers/rendering/renderer_rd/effects/copy_effects.h"
 #include "servers/rendering/renderer_rd/effects/fsr.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/fog.h"
 #include "servers/rendering/renderer_rd/environment/gi.h"
 #include "servers/rendering/renderer_rd/environment/sky.h"
 #include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
 #include "servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h"
 #include "servers/rendering/renderer_scene_render.h"
 #include "servers/rendering/rendering_device.h"
 #include "servers/rendering/rendering_method.h"
 
+// For RenderDataRD, possibly inherited from RefCounted and add proper getters for our implementation classes
+
 struct RenderDataRD {
 	Ref<RenderSceneBuffersRD> render_buffers;
 	RenderSceneDataRD *scene_data;
@@ -65,6 +67,7 @@ struct RenderDataRD {
 	RID environment;
 	RID camera_attributes;
 	RID shadow_atlas;
+	RID occluder_debug_tex;
 	RID reflection_atlas;
 	RID reflection_probe;
 	int reflection_probe_pass = 0;
@@ -77,6 +80,21 @@ struct RenderDataRD {
 	bool directional_light_soft_shadows = false;
 
 	RenderingMethod::RenderInfo *render_info = nullptr;
+
+	/* Shadow data */
+	const RendererSceneRender::RenderShadowData *render_shadows = nullptr;
+	int render_shadow_count = 0;
+
+	LocalVector<int> cube_shadows;
+	LocalVector<int> shadows;
+	LocalVector<int> directional_shadows;
+
+	/* GI info */
+	const RendererSceneRender::RenderSDFGIData *render_sdfgi_regions = nullptr;
+	int render_sdfgi_region_count = 0;
+	const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr;
+
+	uint32_t voxel_gi_count = 0;
 };
 
 class RendererSceneRenderRD : public RendererSceneRender {
@@ -84,6 +102,7 @@ class RendererSceneRenderRD : public RendererSceneRender {
 	friend RendererRD::GI;
 
 protected:
+	RendererRD::ForwardIDStorage *forward_id_storage = nullptr;
 	RendererRD::BokehDOF *bokeh_dof = nullptr;
 	RendererRD::CopyEffects *copy_effects = nullptr;
 	RendererRD::ToneMapper *tone_mapper = nullptr;
@@ -92,18 +111,23 @@ protected:
 	double time = 0.0;
 	double time_step = 0.0;
 
-	virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
+	/* ENVIRONMENT */
 
-	void _setup_lights(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows);
-	void _setup_decals(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
-	void _setup_reflections(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
+	bool glow_bicubic_upscale = false;
+	bool glow_high_quality = false;
 
-	virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
+	bool use_physical_light_units = false;
+
+	////////////////////////////////
+
+	virtual RendererRD::ForwardIDStorage *create_forward_id_storage() { return memnew(RendererRD::ForwardIDStorage); };
 
-	virtual void _render_shadow_begin() = 0;
-	virtual void _render_shadow_append(RID p_framebuffer, const PagedArray<RenderGeometryInstance *> &p_instances, const Projection &p_projection, const Transform3D &p_transform, float p_zfar, float p_bias, float p_normal_bias, bool p_use_dp, bool p_use_dp_flip, bool p_use_pancake, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0, const Rect2i &p_rect = Rect2i(), bool p_flip_y = false, bool p_clear_region = true, bool p_begin = true, bool p_end = true, RenderingMethod::RenderInfo *p_render_info = nullptr) = 0;
-	virtual void _render_shadow_process() = 0;
-	virtual void _render_shadow_end(uint32_t p_barrier = RD::BARRIER_MASK_ALL) = 0;
+	void _update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers);
+
+	virtual void setup_render_buffer_data(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
+
+	virtual void _render_scene(RenderDataRD *p_render_data, const Color &p_default_color) = 0;
+	virtual void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
 
 	virtual void _render_material(const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal, const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region, float p_exposure_normalization) = 0;
 	virtual void _render_uv2(const PagedArray<RenderGeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0;
@@ -111,25 +135,14 @@ protected:
 	virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const Projection &p_cam_projection, const PagedArray<RenderGeometryInstance *> &p_instances) = 0;
 
 	void _debug_sdfgi_probes(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_framebuffer, uint32_t p_view_count, const Projection *p_camera_with_transforms, bool p_will_continue_color, bool p_will_continue_depth);
-	void _debug_draw_cluster(Ref<RenderSceneBuffersRD> p_render_buffers);
 
-	virtual void _base_uniforms_changed() = 0;
 	virtual RID _render_buffers_get_normal_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
 	virtual RID _render_buffers_get_velocity_texture(Ref<RenderSceneBuffersRD> p_render_buffers) = 0;
 
-	void _process_ssao(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection);
-	void _process_ssr(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_dest_framebuffer, const RID *p_normal_buffer_slices, RID p_specular_buffer, const RID *p_metallic_slices, RID p_environment, const Projection *p_projections, const Vector3 *p_eye_offsets, bool p_use_additive);
-	void _process_sss(Ref<RenderSceneBuffersRD> p_render_buffers, const Projection &p_camera);
-	void _process_ssil(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, RID p_normal_buffer, const Projection &p_projection, const Transform3D &p_transform);
-
-	void _copy_framebuffer_to_ssil(Ref<RenderSceneBuffersRD> p_render_buffers);
-
 	bool _needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
 	void _post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi);
 	void _pre_resolve_render(RenderDataRD *p_render_data, bool p_use_gi);
 
-	void _pre_opaque_render(RenderDataRD *p_render_data, bool p_use_ssao, bool p_use_ssil, bool p_use_gi, const RID *p_normal_roughness_slices, RID p_voxel_gi_buffer);
-
 	void _render_buffers_copy_screen_texture(const RenderDataRD *p_render_data);
 	void _render_buffers_copy_depth_texture(const RenderDataRD *p_render_data);
 	void _render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data);
@@ -140,26 +153,8 @@ protected:
 	PagedArrayPool<RenderGeometryInstance *> cull_argument_pool;
 	PagedArray<RenderGeometryInstance *> cull_argument; //need this to exist
 
-	RendererRD::SSEffects *ss_effects = nullptr;
-	RendererRD::GI gi;
 	RendererRD::SkyRD sky;
-
-	//used for mobile renderer mostly
-
-	typedef int32_t ForwardID;
-
-	enum ForwardIDType {
-		FORWARD_ID_TYPE_OMNI_LIGHT,
-		FORWARD_ID_TYPE_SPOT_LIGHT,
-		FORWARD_ID_TYPE_REFLECTION_PROBE,
-		FORWARD_ID_TYPE_DECAL,
-		FORWARD_ID_MAX,
-	};
-
-	virtual ForwardID _allocate_forward_id(ForwardIDType p_type) { return -1; }
-	virtual void _free_forward_id(ForwardIDType p_type, ForwardID p_id) {}
-	virtual void _map_forward_id(ForwardIDType p_type, ForwardID p_id, uint32_t p_index) {}
-	virtual bool _uses_forward_ids() const { return false; }
+	RendererRD::GI gi;
 
 	virtual void _update_shader_quality_settings() {}
 
@@ -167,125 +162,7 @@ private:
 	RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
 	static RendererSceneRenderRD *singleton;
 
-	/* REFLECTION ATLAS */
-
-	struct ReflectionAtlas {
-		int count = 0;
-		int size = 0;
-
-		RID reflection;
-		RID depth_buffer;
-		RID depth_fb;
-
-		struct Reflection {
-			RID owner;
-			RendererRD::SkyRD::ReflectionData data;
-			RID fbs[6];
-		};
-
-		Vector<Reflection> reflections;
-
-		ClusterBuilderRD *cluster_builder = nullptr;
-	};
-
-	mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner;
-
-	/* REFLECTION PROBE INSTANCE */
-
-	struct ReflectionProbeInstance {
-		RID probe;
-		int atlas_index = -1;
-		RID atlas;
-
-		bool dirty = true;
-		bool rendering = false;
-		int processing_layer = 1;
-		int processing_side = 0;
-
-		uint32_t render_step = 0;
-		uint64_t last_pass = 0;
-		uint32_t cull_mask = 0;
-
-		ForwardID forward_id = -1;
-
-		Transform3D transform;
-	};
-
-	mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
-
-	/* DECAL INSTANCE */
-
-	struct DecalInstance {
-		RID decal;
-		Transform3D transform;
-		uint32_t cull_mask = 0;
-		ForwardID forward_id = -1;
-	};
-
-	mutable RID_Owner<DecalInstance> decal_instance_owner;
-
-	/* LIGHTMAP INSTANCE */
-
-	struct LightmapInstance {
-		RID lightmap;
-		Transform3D transform;
-	};
-
-	mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
-
-	/* SHADOW ATLAS */
-
-	struct ShadowShrinkStage {
-		RID texture;
-		RID filter_texture;
-		uint32_t size = 0;
-	};
-
-	struct ShadowAtlas {
-		enum {
-			QUADRANT_SHIFT = 27,
-			OMNI_LIGHT_FLAG = 1 << 26,
-			SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
-			SHADOW_INVALID = 0xFFFFFFFF
-		};
-
-		struct Quadrant {
-			uint32_t subdivision = 0;
-
-			struct Shadow {
-				RID owner;
-				uint64_t version = 0;
-				uint64_t fog_version = 0; // used for fog
-				uint64_t alloc_tick = 0;
-
-				Shadow() {}
-			};
-
-			Vector<Shadow> shadows;
-
-			Quadrant() {}
-		} quadrants[4];
-
-		int size_order[4] = { 0, 1, 2, 3 };
-		uint32_t smallest_subdiv = 0;
-
-		int size = 0;
-		bool use_16_bits = true;
-
-		RID depth;
-		RID fb; //for copying
-
-		HashMap<RID, uint32_t> shadow_owners;
-	};
-
-	RID_Owner<ShadowAtlas> shadow_atlas_owner;
-
-	void _update_shadow_atlas(ShadowAtlas *shadow_atlas);
-
-	void _shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx);
-	bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
-	bool _shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
-
+	/* Shadow atlas */
 	RS::ShadowQuality shadows_quality = RS::SHADOW_QUALITY_MAX; //So it always updates when first set
 	RS::ShadowQuality directional_shadow_quality = RS::SHADOW_QUALITY_MAX;
 	float shadows_quality_radius = 1.0;
@@ -302,299 +179,36 @@ private:
 	RS::DecalFilter decals_filter = RS::DECAL_FILTER_LINEAR_MIPMAPS;
 	RS::LightProjectorFilter light_projectors_filter = RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS;
 
-	/* DIRECTIONAL SHADOW */
-
-	struct DirectionalShadow {
-		RID depth;
-		RID fb; //when renderign direct
-
-		int light_count = 0;
-		int size = 0;
-		bool use_16_bits = true;
-		int current_light = 0;
-	} directional_shadow;
-
-	void _update_directional_shadow_atlas();
-
-	/* SHADOW CUBEMAPS */
-
-	struct ShadowCubemap {
-		RID cubemap;
-		RID side_fb[6];
-	};
-
-	HashMap<int, ShadowCubemap> shadow_cubemaps;
-	ShadowCubemap *_get_shadow_cubemap(int p_size);
-
-	void _create_shadow_cubemaps();
-
-	/* LIGHT INSTANCE */
-
-	struct LightInstance {
-		struct ShadowTransform {
-			Projection camera;
-			Transform3D transform;
-			float farplane;
-			float split;
-			float bias_scale;
-			float shadow_texel_size;
-			float range_begin;
-			Rect2 atlas_rect;
-			Vector2 uv_scale;
-		};
-
-		RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
-
-		ShadowTransform shadow_transform[6];
-
-		AABB aabb;
-		RID self;
-		RID light;
-		Transform3D transform;
-
-		Vector3 light_vector;
-		Vector3 spot_vector;
-		float linear_att = 0.0;
-
-		uint64_t shadow_pass = 0;
-		uint64_t last_scene_pass = 0;
-		uint64_t last_scene_shadow_pass = 0;
-		uint64_t last_pass = 0;
-		uint32_t cull_mask = 0;
-		uint32_t light_directional_index = 0;
-
-		Rect2 directional_rect;
-
-		HashSet<RID> shadow_atlases; //shadow atlases where this light is registered
-
-		ForwardID forward_id = -1;
-
-		LightInstance() {}
-	};
-
-	mutable RID_Owner<LightInstance> light_instance_owner;
-
-	/* ENVIRONMENT */
-
-	RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM;
-	bool ssao_half_size = false;
-	float ssao_adaptive_target = 0.5;
-	int ssao_blur_passes = 2;
-	float ssao_fadeout_from = 50.0;
-	float ssao_fadeout_to = 300.0;
-
-	RS::EnvironmentSSILQuality ssil_quality = RS::ENV_SSIL_QUALITY_MEDIUM;
-	bool ssil_half_size = false;
-	bool ssil_using_half_size = false;
-	float ssil_adaptive_target = 0.5;
-	int ssil_blur_passes = 4;
-	float ssil_fadeout_from = 50.0;
-	float ssil_fadeout_to = 300.0;
-
-	bool glow_bicubic_upscale = false;
-	bool glow_high_quality = false;
-	RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::ENV_SSR_ROUGHNESS_QUALITY_LOW;
-
-	RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM;
-	float sss_scale = 0.05;
-	float sss_depth_scale = 0.01;
-
-	bool use_physical_light_units = false;
-
-	/* Cluster builder */
-
-	ClusterBuilderSharedDataRD cluster_builder_shared;
-	ClusterBuilderRD *current_cluster_builder = nullptr;
-
 	/* RENDER BUFFERS */
 
+	// TODO move into effects/luminance.h/cpp
 	void _allocate_luminance_textures(Ref<RenderSceneBuffersRD> rb);
 
-	void _render_buffers_debug_draw(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer);
-
 	/* GI */
 	bool screen_space_roughness_limiter = false;
 	float screen_space_roughness_limiter_amount = 0.25;
 	float screen_space_roughness_limiter_limit = 0.18;
 
-	/* Cluster */
-
-	struct Cluster {
-		/* Scene State UBO */
-
-		// !BAS! Most data here is not just used by our clustering logic but also by other lighting implementations. Maybe rename this struct to something more appropriate
-
-		enum {
-			REFLECTION_AMBIENT_DISABLED = 0,
-			REFLECTION_AMBIENT_ENVIRONMENT = 1,
-			REFLECTION_AMBIENT_COLOR = 2,
-		};
-
-		struct ReflectionData {
-			float box_extents[3];
-			float index;
-			float box_offset[3];
-			uint32_t mask;
-			float ambient[3]; // ambient color,
-			float intensity;
-			uint32_t exterior;
-			uint32_t box_project;
-			uint32_t ambient_mode;
-			float exposure_normalization;
-			float local_matrix[16]; // up to here for spot and omni, rest is for directional
-		};
-
-		struct LightData {
-			float position[3];
-			float inv_radius;
-			float direction[3]; // in omni, x and y are used for dual paraboloid offset
-			float size;
-
-			float color[3];
-			float attenuation;
-
-			float inv_spot_attenuation;
-			float cos_spot_angle;
-			float specular_amount;
-			float shadow_opacity;
-
-			float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
-			float shadow_matrix[16];
-			float shadow_bias;
-			float shadow_normal_bias;
-			float transmittance_bias;
-			float soft_shadow_size;
-			float soft_shadow_scale;
-			uint32_t mask;
-			float volumetric_fog_energy;
-			uint32_t bake_mode;
-			float projector_rect[4];
-		};
-
-		struct DirectionalLightData {
-			float direction[3];
-			float energy;
-			float color[3];
-			float size;
-			float specular;
-			uint32_t mask;
-			float softshadow_angle;
-			float soft_shadow_scale;
-			uint32_t blend_splits;
-			float shadow_opacity;
-			float fade_from;
-			float fade_to;
-			uint32_t pad[2];
-			uint32_t bake_mode;
-			float volumetric_fog_energy;
-			float shadow_bias[4];
-			float shadow_normal_bias[4];
-			float shadow_transmittance_bias[4];
-			float shadow_z_range[4];
-			float shadow_range_begin[4];
-			float shadow_split_offsets[4];
-			float shadow_matrices[4][16];
-			float uv_scale1[2];
-			float uv_scale2[2];
-			float uv_scale3[2];
-			float uv_scale4[2];
-		};
-
-		struct DecalData {
-			float xform[16];
-			float inv_extents[3];
-			float albedo_mix;
-			float albedo_rect[4];
-			float normal_rect[4];
-			float orm_rect[4];
-			float emission_rect[4];
-			float modulate[4];
-			float emission_energy;
-			uint32_t mask;
-			float upper_fade;
-			float lower_fade;
-			float normal_xform[12];
-			float normal[3];
-			float normal_fade;
-		};
-
-		template <class T>
-		struct InstanceSort {
-			float depth;
-			T *instance = nullptr;
-			bool operator<(const InstanceSort &p_sort) const {
-				return depth < p_sort.depth;
-			}
-		};
-
-		ReflectionData *reflections = nullptr;
-		InstanceSort<ReflectionProbeInstance> *reflection_sort;
-		uint32_t max_reflections;
-		RID reflection_buffer;
-		uint32_t max_reflection_probes_per_instance;
-		uint32_t reflection_count = 0;
-
-		DecalData *decals = nullptr;
-		InstanceSort<DecalInstance> *decal_sort;
-		uint32_t max_decals;
-		RID decal_buffer;
-		uint32_t decal_count;
-
-		LightData *omni_lights = nullptr;
-		LightData *spot_lights = nullptr;
-
-		InstanceSort<LightInstance> *omni_light_sort;
-		InstanceSort<LightInstance> *spot_light_sort;
-		uint32_t max_lights;
-		RID omni_light_buffer;
-		RID spot_light_buffer;
-		uint32_t omni_light_count = 0;
-		uint32_t spot_light_count = 0;
-
-		DirectionalLightData *directional_lights = nullptr;
-		uint32_t max_directional_lights;
-		RID directional_light_buffer;
-
-	} cluster;
-
-	struct RenderState {
-		const RendererSceneRender::RenderShadowData *render_shadows = nullptr;
-		int render_shadow_count = 0;
-		const RendererSceneRender::RenderSDFGIData *render_sdfgi_regions = nullptr;
-		int render_sdfgi_region_count = 0;
-		const RendererSceneRender::RenderSDFGIUpdateData *sdfgi_update_data = nullptr;
-
-		uint32_t voxel_gi_count = 0;
-
-		LocalVector<int> cube_shadows;
-		LocalVector<int> shadows;
-		LocalVector<int> directional_shadows;
-
-		bool depth_prepass_used; // this does not seem used anywhere...
-	} render_state;
-
-	RID shadow_sampler;
+	/* Light data */
 
 	uint64_t scene_pass = 0;
-	uint64_t shadow_atlas_realloc_tolerance_msec = 500;
 
 	uint32_t max_cluster_elements = 512;
 
-	void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RenderingMethod::RenderInfo *p_render_info = nullptr);
-
 	/* Volumetric Fog */
 
 	uint32_t volumetric_fog_size = 128;
 	uint32_t volumetric_fog_depth = 128;
 	bool volumetric_fog_filter_active = true;
 
-	void _update_volumetric_fog(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_environment, const Projection &p_cam_projection, const Transform3D &p_cam_transform, const Transform3D &p_prev_cam_inv_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes);
-
 public:
 	static RendererSceneRenderRD *get_singleton() { return singleton; }
 
-	/* Cluster builder */
-	ClusterBuilderSharedDataRD *get_cluster_builder_shared() { return &cluster_builder_shared; }
+	/* LIGHTING */
+
+	virtual void setup_added_reflection_probe(const Transform3D &p_transform, const Vector3 &p_half_extents){};
+	virtual void setup_added_light(const RS::LightType p_type, const Transform3D &p_transform, float p_radius, float p_spot_aperture){};
+	virtual void setup_added_decal(const Transform3D &p_transform, const Vector3 &p_half_extents){};
 
 	/* GI */
 
@@ -604,42 +218,6 @@ public:
 
 	RendererRD::SkyRD *get_sky() { return &sky; }
 
-	/* SHADOW ATLAS API */
-
-	virtual RID shadow_atlas_create() override;
-	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
-	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
-	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
-	_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
-		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
-		ERR_FAIL_COND_V(!atlas, false);
-		return atlas->shadow_owners.has(p_light_intance);
-	}
-
-	_FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
-		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
-		ERR_FAIL_COND_V(!atlas, RID());
-		return atlas->depth;
-	}
-
-	_FORCE_INLINE_ Size2i shadow_atlas_get_size(RID p_atlas) {
-		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
-		ERR_FAIL_COND_V(!atlas, Size2i());
-		return Size2(atlas->size, atlas->size);
-	}
-
-	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
-	virtual int get_directional_light_shadow_size(RID p_light_intance) override;
-	virtual void set_directional_shadow_count(int p_count) override;
-
-	_FORCE_INLINE_ RID directional_shadow_get_texture() {
-		return directional_shadow.depth;
-	}
-
-	_FORCE_INLINE_ Size2i directional_shadow_get_size() {
-		return Size2i(directional_shadow.size, directional_shadow.size);
-	}
-
 	/* SDFGI UPDATE */
 
 	virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) override;
@@ -666,266 +244,32 @@ public:
 	virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override;
 	virtual void environment_set_volumetric_fog_filter_active(bool p_enable) override;
 
-	virtual void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
-
-	virtual void environment_set_ssil_quality(RS::EnvironmentSSILQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override;
-
 	virtual void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override;
 	virtual void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override;
 	virtual void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override;
 
-	virtual void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override;
-	RS::EnvironmentSSRRoughnessQuality environment_get_ssr_roughness_quality() const;
-
 	virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override;
 
 	_FORCE_INLINE_ bool is_using_physical_light_units() {
 		return use_physical_light_units;
 	}
 
-	/* LIGHT INSTANCE API */
-
-	virtual RID light_instance_create(RID p_light) override;
-	virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
-	virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
-	virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
-	virtual void light_instance_mark_visible(RID p_light_instance) override;
-
-	_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->light;
-	}
-
-	_FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->transform;
-	}
-
-	_FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) {
-		ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		uint32_t key = shadow_atlas->shadow_owners[li->self];
-
-		uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
-		uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
-
-		ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2());
-
-		uint32_t atlas_size = shadow_atlas->size;
-		uint32_t quadrant_size = atlas_size >> 1;
-
-		uint32_t x = (quadrant & 1) * quadrant_size;
-		uint32_t y = (quadrant >> 1) * quadrant_size;
-
-		uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
-		x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
-		y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
-
-		if (key & ShadowAtlas::OMNI_LIGHT_FLAG) {
-			if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) {
-				r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision);
-				r_omni_offset.y = 1;
-			} else {
-				r_omni_offset.x = 1;
-				r_omni_offset.y = 0;
-			}
-		}
-
-		uint32_t width = shadow_size;
-		uint32_t height = shadow_size;
-
-		return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size));
-	}
-
-	_FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].camera;
-	}
-
-	_FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
-#ifdef DEBUG_ENABLED
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
-#endif
-		ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
-		ERR_FAIL_COND_V(!shadow_atlas, 0);
-#ifdef DEBUG_ENABLED
-		ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
-#endif
-		uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
-
-		uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
-
-		uint32_t quadrant_size = shadow_atlas->size >> 1;
-
-		uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
-
-		return float(1.0) / shadow_size;
-	}
-
-	_FORCE_INLINE_ Transform3D
-	light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].transform;
-	}
-	_FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].bias_scale;
-	}
-	_FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].farplane;
-	}
-	_FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].range_begin;
-	}
-
-	_FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].uv_scale;
-	}
-
-	_FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].atlas_rect;
-	}
-
-	_FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].split;
-	}
-
-	_FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->shadow_transform[p_index].shadow_texel_size;
-	}
-
-	_FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		li->last_pass = p_pass;
-	}
-
-	_FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->last_pass;
-	}
-
-	_FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->forward_id;
-	}
+	/* REFLECTION PROBE */
 
-	_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
-		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
-		return li->light_type;
-	}
+	virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth);
 
 	/* FOG VOLUMES */
 
+	uint32_t get_volumetric_fog_size() const { return volumetric_fog_size; }
+	uint32_t get_volumetric_fog_depth() const { return volumetric_fog_depth; }
+	bool get_volumetric_fog_filter_active() const { return volumetric_fog_filter_active; }
+
 	virtual RID fog_volume_instance_create(RID p_fog_volume) override;
 	virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override;
 	virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override;
 	virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override;
 	virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override;
 
-	virtual RID reflection_atlas_create() override;
-	virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
-	virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
-
-	_FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
-		ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas);
-		ERR_FAIL_COND_V(!atlas, RID());
-		return atlas->reflection;
-	}
-
-	virtual RID reflection_probe_instance_create(RID p_probe) override;
-	virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
-	virtual void reflection_probe_release_atlas_index(RID p_instance) override;
-	virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
-	virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
-	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
-	virtual RID reflection_probe_create_framebuffer(RID p_color, RID p_depth);
-	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
-
-	uint32_t reflection_probe_instance_get_resolution(RID p_instance);
-	RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
-	RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
-
-	_FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
-		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
-		ERR_FAIL_COND_V(!rpi, RID());
-
-		return rpi->probe;
-	}
-
-	_FORCE_INLINE_ ForwardID reflection_probe_instance_get_forward_id(RID p_instance) {
-		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
-		ERR_FAIL_COND_V(!rpi, 0);
-
-		return rpi->forward_id;
-	}
-
-	_FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
-		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
-		ERR_FAIL_COND(!rpi);
-		rpi->last_pass = p_render_pass;
-	}
-
-	_FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
-		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
-		ERR_FAIL_COND_V(!rpi, 0);
-
-		return rpi->last_pass;
-	}
-
-	_FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) {
-		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
-		ERR_FAIL_COND_V(!rpi, Transform3D());
-
-		return rpi->transform;
-	}
-
-	_FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
-		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
-		ERR_FAIL_COND_V(!rpi, -1);
-
-		return rpi->atlas_index;
-	}
-
-	virtual RID decal_instance_create(RID p_decal) override;
-	virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
-
-	_FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const {
-		DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
-		return decal->decal;
-	}
-
-	_FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal) const {
-		DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
-		return decal->forward_id;
-	}
-
-	_FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal) const {
-		DecalInstance *decal = decal_instance_owner.get_or_null(p_decal);
-		return decal->transform;
-	}
-
-	virtual RID lightmap_instance_create(RID p_lightmap) override;
-	virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
-	_FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) {
-		return lightmap_instance_owner.get_or_null(p_lightmap_instance) != nullptr;
-	}
-
-	_FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) {
-		LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
-		return li->lightmap;
-	}
-	_FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) {
-		LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
-		return li->transform;
-	}
-
 	/* gi light probes */
 
 	virtual RID voxel_gi_instance_create(RID p_base) override;
@@ -944,6 +288,7 @@ public:
 
 	RID render_buffers_get_default_voxel_gi_buffer();
 
+	virtual void base_uniforms_changed() = 0;
 	virtual void update_uniform_sets(){};
 
 	virtual void render_scene(const Ref<RenderSceneBuffers> &p_render_buffers, const CameraData *p_camera_data, const CameraData *p_prev_camera_data, const PagedArray<RenderGeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_attributes, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_mesh_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RenderingMethod::RenderInfo *r_render_info = nullptr) override;
@@ -964,10 +309,6 @@ public:
 	virtual float screen_space_roughness_limiter_get_amount() const;
 	virtual float screen_space_roughness_limiter_get_limit() const;
 
-	virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override;
-	RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const;
-	virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override;
-
 	virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
 	virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) override;
 
@@ -1036,18 +377,10 @@ public:
 
 	virtual void set_time(double p_time, double p_step) override;
 
-	RID get_reflection_probe_buffer();
-	RID get_omni_light_buffer();
-	RID get_spot_light_buffer();
-	RID get_directional_light_buffer();
-	RID get_decal_buffer();
-	int get_max_directional_lights() const;
-
 	virtual void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override;
 
 	virtual bool is_vrs_supported() const;
 	virtual bool is_dynamic_gi_supported() const;
-	virtual bool is_clustered_enabled() const;
 	virtual bool is_volumetric_supported() const;
 	virtual uint32_t get_max_elements() const;
 

+ 43 - 0
servers/rendering/renderer_rd/storage_rd/forward_id_storage.cpp

@@ -0,0 +1,43 @@
+/*************************************************************************/
+/*  forward_id_storage.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 "forward_id_storage.h"
+
+using namespace RendererRD;
+
+ForwardIDStorage *ForwardIDStorage::singleton = nullptr;
+
+ForwardIDStorage::ForwardIDStorage() {
+	singleton = this;
+}
+
+ForwardIDStorage::~ForwardIDStorage() {
+	singleton = nullptr;
+}

+ 68 - 0
servers/rendering/renderer_rd/storage_rd/forward_id_storage.h

@@ -0,0 +1,68 @@
+/*************************************************************************/
+/*  forward_id_storage.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 FORWARD_ID_STORAGE_H
+#define FORWARD_ID_STORAGE_H
+
+#include "servers/rendering/storage/utilities.h"
+
+class RendererSceneRenderRD;
+
+namespace RendererRD {
+
+typedef int32_t ForwardID;
+
+enum ForwardIDType {
+	FORWARD_ID_TYPE_OMNI_LIGHT,
+	FORWARD_ID_TYPE_SPOT_LIGHT,
+	FORWARD_ID_TYPE_REFLECTION_PROBE,
+	FORWARD_ID_TYPE_DECAL,
+	FORWARD_ID_MAX,
+};
+
+class ForwardIDStorage {
+private:
+	static ForwardIDStorage *singleton;
+
+public:
+	static ForwardIDStorage *get_singleton() { return singleton; }
+
+	ForwardIDStorage();
+	virtual ~ForwardIDStorage();
+
+	virtual RendererRD::ForwardID allocate_forward_id(RendererRD::ForwardIDType p_type) { return -1; }
+	virtual void free_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id) {}
+	virtual void map_forward_id(RendererRD::ForwardIDType p_type, RendererRD::ForwardID p_id, uint32_t p_index) {}
+	virtual bool uses_forward_ids() const { return false; }
+};
+
+} // namespace RendererRD
+
+#endif // FORWARD_ID_STORAGE_H

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1135 - 68
servers/rendering/renderer_rd/storage_rd/light_storage.cpp


+ 708 - 0
servers/rendering/renderer_rd/storage_rd/light_storage.h

@@ -32,17 +32,32 @@
 #define LIGHT_STORAGE_RD_H
 
 #include "core/templates/local_vector.h"
+#include "core/templates/paged_array.h"
 #include "core/templates/rid_owner.h"
 #include "core/templates/self_list.h"
+#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
+#include "servers/rendering/renderer_rd/environment/sky.h"
+#include "servers/rendering/renderer_rd/storage_rd/forward_id_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
 #include "servers/rendering/storage/light_storage.h"
 #include "servers/rendering/storage/utilities.h"
 
+struct RenderDataRD;
+
 namespace RendererRD {
 
 class LightStorage : public RendererLightStorage {
+public:
+	enum ShadowAtlastQuadrant {
+		QUADRANT_SHIFT = 27,
+		OMNI_LIGHT_FLAG = 1 << 26,
+		SHADOW_INDEX_MASK = OMNI_LIGHT_FLAG - 1,
+		SHADOW_INVALID = 0xFFFFFFFF
+	};
+
 private:
 	static LightStorage *singleton;
+	uint32_t max_cluster_elements = 512;
 
 	/* LIGHT */
 	struct Light {
@@ -71,6 +86,135 @@ private:
 
 	mutable RID_Owner<Light, true> light_owner;
 
+	/* LIGHT INSTANCE */
+
+	struct LightInstance {
+		struct ShadowTransform {
+			Projection camera;
+			Transform3D transform;
+			float farplane;
+			float split;
+			float bias_scale;
+			float shadow_texel_size;
+			float range_begin;
+			Rect2 atlas_rect;
+			Vector2 uv_scale;
+		};
+
+		RS::LightType light_type = RS::LIGHT_DIRECTIONAL;
+
+		ShadowTransform shadow_transform[6];
+
+		AABB aabb;
+		RID self;
+		RID light;
+		Transform3D transform;
+
+		Vector3 light_vector;
+		Vector3 spot_vector;
+		float linear_att = 0.0;
+
+		uint64_t shadow_pass = 0;
+		uint64_t last_scene_pass = 0;
+		uint64_t last_scene_shadow_pass = 0;
+		uint64_t last_pass = 0;
+		uint32_t cull_mask = 0;
+		uint32_t light_directional_index = 0;
+
+		Rect2 directional_rect;
+
+		HashSet<RID> shadow_atlases; //shadow atlases where this light is registered
+
+		ForwardID forward_id = -1;
+
+		LightInstance() {}
+	};
+
+	mutable RID_Owner<LightInstance> light_instance_owner;
+
+	/* OMNI/SPOT LIGHT DATA */
+
+	struct LightData {
+		float position[3];
+		float inv_radius;
+		float direction[3]; // in omni, x and y are used for dual paraboloid offset
+		float size;
+
+		float color[3];
+		float attenuation;
+
+		float inv_spot_attenuation;
+		float cos_spot_angle;
+		float specular_amount;
+		float shadow_opacity;
+
+		float atlas_rect[4]; // in omni, used for atlas uv, in spot, used for projector uv
+		float shadow_matrix[16];
+		float shadow_bias;
+		float shadow_normal_bias;
+		float transmittance_bias;
+		float soft_shadow_size;
+		float soft_shadow_scale;
+		uint32_t mask;
+		float volumetric_fog_energy;
+		uint32_t bake_mode;
+		float projector_rect[4];
+	};
+
+	struct LightInstanceDepthSort {
+		float depth;
+		LightInstance *light_instance;
+		Light *light;
+		bool operator<(const LightInstanceDepthSort &p_sort) const {
+			return depth < p_sort.depth;
+		}
+	};
+
+	uint32_t max_lights;
+	uint32_t omni_light_count = 0;
+	uint32_t spot_light_count = 0;
+	LightData *omni_lights = nullptr;
+	LightData *spot_lights = nullptr;
+	LightInstanceDepthSort *omni_light_sort = nullptr;
+	LightInstanceDepthSort *spot_light_sort = nullptr;
+	RID omni_light_buffer;
+	RID spot_light_buffer;
+
+	/* DIRECTIONAL LIGHT DATA */
+
+	struct DirectionalLightData {
+		float direction[3];
+		float energy;
+		float color[3];
+		float size;
+		float specular;
+		uint32_t mask;
+		float softshadow_angle;
+		float soft_shadow_scale;
+		uint32_t blend_splits;
+		float shadow_opacity;
+		float fade_from;
+		float fade_to;
+		uint32_t pad[2];
+		uint32_t bake_mode;
+		float volumetric_fog_energy;
+		float shadow_bias[4];
+		float shadow_normal_bias[4];
+		float shadow_transmittance_bias[4];
+		float shadow_z_range[4];
+		float shadow_range_begin[4];
+		float shadow_split_offsets[4];
+		float shadow_matrices[4][16];
+		float uv_scale1[2];
+		float uv_scale2[2];
+		float uv_scale3[2];
+		float uv_scale4[2];
+	};
+
+	uint32_t max_directional_lights;
+	DirectionalLightData *directional_lights = nullptr;
+	RID directional_light_buffer;
+
 	/* REFLECTION PROBE */
 
 	struct ReflectionProbe {
@@ -94,6 +238,89 @@ private:
 	};
 	mutable RID_Owner<ReflectionProbe, true> reflection_probe_owner;
 
+	/* REFLECTION ATLAS */
+
+	struct ReflectionAtlas {
+		int count = 0;
+		int size = 0;
+
+		RID reflection;
+		RID depth_buffer;
+		RID depth_fb;
+
+		struct Reflection {
+			RID owner;
+			RendererRD::SkyRD::ReflectionData data;
+			RID fbs[6];
+		};
+
+		Vector<Reflection> reflections;
+
+		ClusterBuilderRD *cluster_builder = nullptr; // only used if cluster builder is supported by the renderer.
+	};
+
+	mutable RID_Owner<ReflectionAtlas> reflection_atlas_owner;
+
+	/* REFLECTION PROBE INSTANCE */
+
+	struct ReflectionProbeInstance {
+		RID probe;
+		int atlas_index = -1;
+		RID atlas;
+
+		bool dirty = true;
+		bool rendering = false;
+		int processing_layer = 1;
+		int processing_side = 0;
+
+		uint32_t render_step = 0;
+		uint64_t last_pass = 0;
+		uint32_t cull_mask = 0;
+
+		RendererRD::ForwardID forward_id = -1;
+
+		Transform3D transform;
+	};
+
+	mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner;
+
+	/* REFLECTION DATA */
+
+	enum {
+		REFLECTION_AMBIENT_DISABLED = 0,
+		REFLECTION_AMBIENT_ENVIRONMENT = 1,
+		REFLECTION_AMBIENT_COLOR = 2,
+	};
+
+	struct ReflectionData {
+		float box_extents[3];
+		float index;
+		float box_offset[3];
+		uint32_t mask;
+		float ambient[3]; // ambient color,
+		float intensity;
+		uint32_t exterior;
+		uint32_t box_project;
+		uint32_t ambient_mode;
+		float exposure_normalization;
+		float local_matrix[16]; // up to here for spot and omni, rest is for directional
+	};
+
+	struct ReflectionProbeInstanceSort {
+		float depth;
+		ReflectionProbeInstance *probe_instance;
+		bool operator<(const ReflectionProbeInstanceSort &p_sort) const {
+			return depth < p_sort.depth;
+		}
+	};
+
+	uint32_t max_reflections;
+	uint32_t reflection_count = 0;
+	// uint32_t max_reflection_probes_per_instance = 0; // seems unused
+	ReflectionData *reflections = nullptr;
+	ReflectionProbeInstanceSort *reflection_sort = nullptr;
+	RID reflection_buffer;
+
 	/* LIGHTMAP */
 
 	struct Lightmap {
@@ -124,12 +351,101 @@ private:
 
 	mutable RID_Owner<Lightmap, true> lightmap_owner;
 
+	/* LIGHTMAP INSTANCE */
+
+	struct LightmapInstance {
+		RID lightmap;
+		Transform3D transform;
+	};
+
+	mutable RID_Owner<LightmapInstance> lightmap_instance_owner;
+
+	/* SHADOW ATLAS */
+
+	uint64_t shadow_atlas_realloc_tolerance_msec = 500;
+
+	struct ShadowShrinkStage {
+		RID texture;
+		RID filter_texture;
+		uint32_t size = 0;
+	};
+
+	struct ShadowAtlas {
+		struct Quadrant {
+			uint32_t subdivision = 0;
+
+			struct Shadow {
+				RID owner;
+				uint64_t version = 0;
+				uint64_t fog_version = 0; // used for fog
+				uint64_t alloc_tick = 0;
+
+				Shadow() {}
+			};
+
+			Vector<Shadow> shadows;
+
+			Quadrant() {}
+		} quadrants[4];
+
+		int size_order[4] = { 0, 1, 2, 3 };
+		uint32_t smallest_subdiv = 0;
+
+		int size = 0;
+		bool use_16_bits = true;
+
+		RID depth;
+		RID fb; //for copying
+
+		HashMap<RID, uint32_t> shadow_owners;
+	};
+
+	RID_Owner<ShadowAtlas> shadow_atlas_owner;
+
+	void _update_shadow_atlas(ShadowAtlas *shadow_atlas);
+
+	void _shadow_atlas_invalidate_shadow(ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx);
+	bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
+	bool _shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
+
+	/* DIRECTIONAL SHADOW */
+
+	struct DirectionalShadow {
+		RID depth;
+		RID fb; //when renderign direct
+
+		int light_count = 0;
+		int size = 0;
+		bool use_16_bits = true;
+		int current_light = 0;
+	} directional_shadow;
+
+	/* SHADOW CUBEMAPS */
+
+	struct ShadowCubemap {
+		RID cubemap;
+		RID side_fb[6];
+	};
+
+	HashMap<int, ShadowCubemap> shadow_cubemaps;
+	ShadowCubemap *_get_shadow_cubemap(int p_size);
+
 public:
 	static LightStorage *get_singleton();
 
 	LightStorage();
 	virtual ~LightStorage();
 
+	bool free(RID p_rid);
+
+	/* Settings */
+	void set_max_cluster_elements(const uint32_t p_max_cluster_elements) {
+		max_cluster_elements = p_max_cluster_elements;
+		set_max_reflection_probes(p_max_cluster_elements);
+		set_max_lights(p_max_cluster_elements);
+	}
+	uint32_t get_max_cluster_elements() const { return max_cluster_elements; }
+
 	/* LIGHT */
 
 	bool owns_light(RID p_rid) { return light_owner.owns(p_rid); };
@@ -259,6 +575,205 @@ public:
 
 	Dependency *light_get_dependency(RID p_light) const;
 
+	/* LIGHT INSTANCE API */
+
+	bool owns_light_instance(RID p_rid) { return light_instance_owner.owns(p_rid); };
+
+	virtual RID light_instance_create(RID p_light) override;
+	virtual void light_instance_free(RID p_light) override;
+	virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override;
+	virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override;
+	virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
+	virtual void light_instance_mark_visible(RID p_light_instance) override;
+
+	_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->light;
+	}
+
+	_FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->transform;
+	}
+
+	_FORCE_INLINE_ AABB light_instance_get_base_aabb(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->aabb;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_cull_mask(RID p_light_instance, uint32_t p_cull_mask) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->cull_mask = p_cull_mask;
+	}
+
+	_FORCE_INLINE_ uint32_t light_instance_get_cull_mask(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->cull_mask;
+	}
+
+	_FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) {
+		ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		uint32_t key = shadow_atlas->shadow_owners[li->self];
+
+		uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
+		uint32_t shadow = key & SHADOW_INDEX_MASK;
+
+		ERR_FAIL_COND_V(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size(), Rect2());
+
+		uint32_t atlas_size = shadow_atlas->size;
+		uint32_t quadrant_size = atlas_size >> 1;
+
+		uint32_t x = (quadrant & 1) * quadrant_size;
+		uint32_t y = (quadrant >> 1) * quadrant_size;
+
+		uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+		x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+		y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+		if (key & OMNI_LIGHT_FLAG) {
+			if (((shadow + 1) % shadow_atlas->quadrants[quadrant].subdivision) == 0) {
+				r_omni_offset.x = 1 - int(shadow_atlas->quadrants[quadrant].subdivision);
+				r_omni_offset.y = 1;
+			} else {
+				r_omni_offset.x = 1;
+				r_omni_offset.y = 0;
+			}
+		}
+
+		uint32_t width = shadow_size;
+		uint32_t height = shadow_size;
+
+		return Rect2(x / float(shadow_atlas->size), y / float(shadow_atlas->size), width / float(shadow_atlas->size), height / float(shadow_atlas->size));
+	}
+
+	_FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) {
+#ifdef DEBUG_ENABLED
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0);
+#endif
+		ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas);
+		ERR_FAIL_COND_V(!shadow_atlas, 0);
+#ifdef DEBUG_ENABLED
+		ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0);
+#endif
+		uint32_t key = shadow_atlas->shadow_owners[p_light_instance];
+
+		uint32_t quadrant = (key >> QUADRANT_SHIFT) & 0x3;
+
+		uint32_t quadrant_size = shadow_atlas->size >> 1;
+
+		uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+
+		return float(1.0) / shadow_size;
+	}
+
+	_FORCE_INLINE_ Projection light_instance_get_shadow_camera(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].camera;
+	}
+
+	_FORCE_INLINE_ Transform3D
+	light_instance_get_shadow_transform(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].transform;
+	}
+	_FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].bias_scale;
+	}
+	_FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].farplane;
+	}
+	_FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].range_begin;
+	}
+
+	_FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].uv_scale;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_directional_shadow_atlas_rect(RID p_light_instance, int p_index, const Rect2 p_atlas_rect) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->shadow_transform[p_index].atlas_rect = p_atlas_rect;
+	}
+
+	_FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].atlas_rect;
+	}
+
+	_FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].split;
+	}
+
+	_FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->shadow_transform[p_index].shadow_texel_size;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->last_pass = p_pass;
+	}
+
+	_FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->last_pass;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_shadow_pass(RID p_light_instance, uint64_t p_pass) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->last_scene_shadow_pass = p_pass;
+	}
+
+	_FORCE_INLINE_ uint64_t light_instance_get_shadow_pass(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->last_scene_shadow_pass;
+	}
+
+	_FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->forward_id;
+	}
+
+	_FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->light_type;
+	}
+
+	_FORCE_INLINE_ void light_instance_set_directional_rect(RID p_light_instance, const Rect2 &p_directional_rect) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		li->directional_rect = p_directional_rect;
+	}
+
+	_FORCE_INLINE_ Rect2 light_instance_get_directional_rect(RID p_light_instance) {
+		LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
+		return li->directional_rect;
+	}
+
+	/* LIGHT DATA */
+
+	void free_light_data();
+	void set_max_lights(const uint32_t p_max_lights);
+	RID get_omni_light_buffer() { return omni_light_buffer; }
+	RID get_spot_light_buffer() { return spot_light_buffer; }
+	RID get_directional_light_buffer() { return directional_light_buffer; }
+	uint32_t get_max_directional_lights() { return max_directional_lights; }
+	bool has_directional_shadows(const uint32_t p_directional_light_count) {
+		for (uint32_t i = 0; i < p_directional_light_count; i++) {
+			if (directional_lights[i].shadow_opacity > 0.001) {
+				return true;
+			}
+		}
+		return false;
+	}
+	void update_light_buffers(RenderDataRD *p_render_data, const PagedArray<RID> &p_lights, const Transform3D &p_camera_transform, RID p_shadow_atlas, bool p_using_shadows, uint32_t &r_directional_light_count, uint32_t &r_positional_light_count, bool &r_directional_light_soft_shadows);
+
 	/* REFLECTION PROBE */
 
 	bool owns_reflection_probe(RID p_rid) { return reflection_probe_owner.owns(p_rid); };
@@ -305,6 +820,94 @@ public:
 
 	Dependency *reflection_probe_get_dependency(RID p_probe) const;
 
+	/* REFLECTION ATLAS */
+
+	bool owns_reflection_atlas(RID p_rid) { return reflection_atlas_owner.owns(p_rid); }
+
+	virtual RID reflection_atlas_create() override;
+	virtual void reflection_atlas_free(RID p_ref_atlas) override;
+	virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override;
+	virtual int reflection_atlas_get_size(RID p_ref_atlas) const override;
+
+	_FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) {
+		ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas);
+		ERR_FAIL_COND_V(!atlas, RID());
+		return atlas->reflection;
+	}
+
+	/* REFLECTION PROBE INSTANCE */
+
+	bool owns_reflection_probe_instance(RID p_rid) { return reflection_probe_instance_owner.owns(p_rid); }
+
+	virtual RID reflection_probe_instance_create(RID p_probe) override;
+	virtual void reflection_probe_instance_free(RID p_instance) override;
+	virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override;
+	virtual void reflection_probe_release_atlas_index(RID p_instance) override;
+	virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override;
+	virtual bool reflection_probe_instance_has_reflection(RID p_instance) override;
+	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override;
+	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
+
+	uint32_t reflection_probe_instance_get_resolution(RID p_instance);
+	RID reflection_probe_instance_get_framebuffer(RID p_instance, int p_index);
+	RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index);
+
+	_FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+		ERR_FAIL_COND_V(!rpi, RID());
+
+		return rpi->probe;
+	}
+
+	_FORCE_INLINE_ RendererRD::ForwardID reflection_probe_instance_get_forward_id(RID p_instance) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+		ERR_FAIL_COND_V(!rpi, 0);
+
+		return rpi->forward_id;
+	}
+
+	_FORCE_INLINE_ void reflection_probe_instance_set_cull_mask(RID p_instance, uint32_t p_render_pass) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+		ERR_FAIL_COND(!rpi);
+		rpi->cull_mask = p_render_pass;
+	}
+
+	_FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+		ERR_FAIL_COND(!rpi);
+		rpi->last_pass = p_render_pass;
+	}
+
+	_FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+		ERR_FAIL_COND_V(!rpi, 0);
+
+		return rpi->last_pass;
+	}
+
+	_FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+		ERR_FAIL_COND_V(!rpi, Transform3D());
+
+		return rpi->transform;
+	}
+
+	_FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) {
+		ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
+		ERR_FAIL_COND_V(!rpi, -1);
+
+		return rpi->atlas_index;
+	}
+
+	ClusterBuilderRD *reflection_probe_instance_get_cluster_builder(RID p_instance, ClusterBuilderSharedDataRD *p_cluster_builder_shared);
+
+	/* REFLECTION DATA */
+
+	void free_reflection_data();
+	void set_max_reflection_probes(const uint32_t p_max_reflection_probes);
+	RID get_reflection_probe_buffer() { return reflection_buffer; }
+	void update_reflection_probe_buffer(RenderDataRD *p_render_data, const PagedArray<RID> &p_reflections, const Transform3D &p_camera_inverse_transform, RID p_environment);
+
 	/* LIGHTMAP */
 
 	bool owns_lightmap(RID p_rid) { return lightmap_owner.owns(p_rid); };
@@ -366,6 +969,111 @@ public:
 		ERR_FAIL_COND_V(!using_lightmap_array, lightmap_textures); //only for arrays
 		return lightmap_textures;
 	}
+
+	/* LIGHTMAP INSTANCE */
+
+	bool owns_lightmap_instance(RID p_rid) { return lightmap_instance_owner.owns(p_rid); };
+
+	virtual RID lightmap_instance_create(RID p_lightmap) override;
+	virtual void lightmap_instance_free(RID p_lightmap) override;
+	virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override;
+	_FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) {
+		return lightmap_instance_owner.get_or_null(p_lightmap_instance) != nullptr;
+	}
+
+	_FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) {
+		LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
+		return li->lightmap;
+	}
+	_FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) {
+		LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance);
+		return li->transform;
+	}
+
+	/* SHADOW ATLAS API */
+
+	bool owns_shadow_atlas(RID p_rid) { return shadow_atlas_owner.owns(p_rid); };
+
+	virtual RID shadow_atlas_create() override;
+	virtual void shadow_atlas_free(RID p_atlas) override;
+
+	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) override;
+	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override;
+	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_instance, float p_coverage, uint64_t p_light_version) override;
+	_FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_COND_V(!atlas, false);
+		return atlas->shadow_owners.has(p_light_intance);
+	}
+	_FORCE_INLINE_ uint32_t shadow_atlas_get_light_instance_key(RID p_atlas, RID p_light_intance) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_COND_V(!atlas, -1);
+		return atlas->shadow_owners[p_light_intance];
+	}
+
+	_FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_COND_V(!atlas, RID());
+		return atlas->depth;
+	}
+
+	_FORCE_INLINE_ int shadow_atlas_get_size(RID p_atlas) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_COND_V(!atlas, 0);
+		return atlas->size;
+	}
+
+	_FORCE_INLINE_ int shadow_atlas_get_quadrant_shadow_size(RID p_atlas, uint32_t p_quadrant) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_COND_V(!atlas, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+		return atlas->quadrants[p_quadrant].shadows.size();
+	}
+
+	_FORCE_INLINE_ uint32_t shadow_atlas_get_quadrant_subdivision(RID p_atlas, uint32_t p_quadrant) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_COND_V(!atlas, 0);
+		ERR_FAIL_UNSIGNED_INDEX_V(p_quadrant, 4, 0);
+		return atlas->quadrants[p_quadrant].subdivision;
+	}
+
+	_FORCE_INLINE_ RID shadow_atlas_get_fb(RID p_atlas) {
+		ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas);
+		ERR_FAIL_COND_V(!atlas, RID());
+		return atlas->fb;
+	}
+
+	virtual void shadow_atlas_update(RID p_atlas) override;
+
+	/* DIRECTIONAL SHADOW */
+
+	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) override;
+	virtual int get_directional_light_shadow_size(RID p_light_intance) override;
+	virtual void set_directional_shadow_count(int p_count) override;
+
+	Rect2i get_directional_shadow_rect();
+	void update_directional_shadow_atlas();
+
+	_FORCE_INLINE_ RID directional_shadow_get_texture() {
+		return directional_shadow.depth;
+	}
+
+	_FORCE_INLINE_ int directional_shadow_get_size() {
+		return directional_shadow.size;
+	}
+
+	_FORCE_INLINE_ RID direction_shadow_get_fb() {
+		return directional_shadow.fb;
+	}
+
+	_FORCE_INLINE_ void directional_shadow_increase_current_light() {
+		directional_shadow.current_light++;
+	}
+
+	/* SHADOW CUBEMAPS */
+
+	RID get_cubemap(int p_size);
+	RID get_cubemap_fb(int p_size, int p_pass);
 };
 
 } // namespace RendererRD

+ 12 - 0
servers/rendering/renderer_rd/storage_rd/material_storage.cpp

@@ -1528,6 +1528,18 @@ MaterialStorage::~MaterialStorage() {
 	singleton = nullptr;
 }
 
+bool MaterialStorage::free(RID p_rid) {
+	if (owns_shader(p_rid)) {
+		shader_free(p_rid);
+		return true;
+	} else if (owns_material(p_rid)) {
+		material_free(p_rid);
+		return true;
+	}
+
+	return false;
+}
+
 /* Samplers */
 
 void MaterialStorage::sampler_rd_configure_custom(float p_mipmap_bias) {

+ 2 - 0
servers/rendering/renderer_rd/storage_rd/material_storage.h

@@ -231,6 +231,8 @@ public:
 	MaterialStorage();
 	virtual ~MaterialStorage();
 
+	bool free(RID p_rid);
+
 	/* Helpers */
 
 	static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) {

+ 18 - 0
servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp

@@ -197,6 +197,24 @@ MeshStorage::~MeshStorage() {
 	singleton = nullptr;
 }
 
+bool MeshStorage::free(RID p_rid) {
+	if (owns_mesh(p_rid)) {
+		mesh_free(p_rid);
+		return true;
+	} else if (owns_mesh_instance(p_rid)) {
+		mesh_instance_free(p_rid);
+		return true;
+	} else if (owns_multimesh(p_rid)) {
+		multimesh_free(p_rid);
+		return true;
+	} else if (owns_skeleton(p_rid)) {
+		skeleton_free(p_rid);
+		return true;
+	}
+
+	return false;
+}
+
 /* MESH API */
 
 RID MeshStorage::mesh_allocate() {

+ 2 - 0
servers/rendering/renderer_rd/storage_rd/mesh_storage.h

@@ -308,6 +308,8 @@ public:
 	MeshStorage();
 	virtual ~MeshStorage();
 
+	bool free(RID p_rid);
+
 	RID get_default_rd_storage_buffer() const { return default_rd_storage_buffer; }
 
 	/* MESH API */

+ 15 - 0
servers/rendering/renderer_rd/storage_rd/particles_storage.cpp

@@ -208,6 +208,21 @@ ParticlesStorage::~ParticlesStorage() {
 	singleton = nullptr;
 }
 
+bool ParticlesStorage::free(RID p_rid) {
+	if (owns_particles(p_rid)) {
+		particles_free(p_rid);
+		return true;
+	} else if (owns_particles_collision(p_rid)) {
+		particles_collision_free(p_rid);
+		return true;
+	} else if (owns_particles_collision_instance(p_rid)) {
+		particles_collision_instance_free(p_rid);
+		return true;
+	}
+
+	return false;
+}
+
 /* PARTICLES */
 
 RID ParticlesStorage::particles_allocate() {

+ 2 - 0
servers/rendering/renderer_rd/storage_rd/particles_storage.h

@@ -405,6 +405,8 @@ public:
 	ParticlesStorage();
 	virtual ~ParticlesStorage();
 
+	bool free(RID p_rid);
+
 	/* PARTICLES */
 
 	bool owns_particles(RID p_rid) { return particles_owner.owns(p_rid); }

+ 0 - 33
servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp

@@ -40,11 +40,6 @@ RenderSceneBuffersRD::~RenderSceneBuffersRD() {
 	cleanup();
 
 	data_buffers.clear();
-
-	// need to investigate if we can remove these things.
-	if (cluster_builder) {
-		memdelete(cluster_builder);
-	}
 }
 
 void RenderSceneBuffersRD::_bind_methods() {
@@ -121,21 +116,6 @@ void RenderSceneBuffersRD::cleanup() {
 		RD::get_singleton()->free(luminance.current);
 		luminance.current = RID();
 	}
-
-	if (ss_effects.linear_depth.is_valid()) {
-		RD::get_singleton()->free(ss_effects.linear_depth);
-		ss_effects.linear_depth = RID();
-		ss_effects.linear_depth_slices.clear();
-	}
-
-	if (ss_effects.downsample_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(ss_effects.downsample_uniform_set)) {
-		RD::get_singleton()->free(ss_effects.downsample_uniform_set);
-		ss_effects.downsample_uniform_set = RID();
-	}
-
-	sse->ssao_free(ss_effects.ssao);
-	sse->ssil_free(ss_effects.ssil);
-	sse->ssr_free(ssr);
 }
 
 void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
@@ -179,14 +159,6 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
 	use_debanding = p_use_debanding;
 	view_count = p_view_count;
 
-	/* may move this into our clustered renderer data object */
-	if (can_be_storage) {
-		if (cluster_builder == nullptr) {
-			cluster_builder = memnew(ClusterBuilderRD);
-		}
-		cluster_builder->set_shared(RendererSceneRenderRD::get_singleton()->get_cluster_builder_shared());
-	}
-
 	// cleanout any old buffers we had.
 	cleanup();
 
@@ -233,11 +205,6 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
 	for (KeyValue<StringName, Ref<RenderBufferCustomDataRD>> &E : data_buffers) {
 		E.value->configure(this);
 	}
-
-	if (cluster_builder) {
-		RID sampler = RendererRD::MaterialStorage::get_singleton()->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
-		cluster_builder->setup(internal_size, max_cluster_elements, get_depth_texture(), sampler, get_internal_texture());
-	}
 }
 
 void RenderSceneBuffersRD::set_fsr_sharpness(float p_fsr_sharpness) {

+ 4 - 30
servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h

@@ -31,19 +31,14 @@
 #ifndef RENDER_SCENE_BUFFERS_RD_H
 #define RENDER_SCENE_BUFFERS_RD_H
 
+#include "../effects/vrs.h"
+#include "../framebuffer_cache_rd.h"
 #include "core/templates/hash_map.h"
-#include "servers/rendering/renderer_rd/effects/vrs.h"
-#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
-#include "servers/rendering/renderer_rd/storage_rd/render_buffer_custom_data_rd.h"
+#include "render_buffer_custom_data_rd.h"
 #include "servers/rendering/rendering_device.h"
 #include "servers/rendering/rendering_method.h"
 #include "servers/rendering/storage/render_scene_buffers.h"
 
-// These can be retired in due time
-#include "servers/rendering/renderer_rd/cluster_builder_rd.h"
-#include "servers/rendering/renderer_rd/effects/ss_effects.h"
-#include "servers/rendering/renderer_rd/environment/fog.h"
-
 #define RB_SCOPE_BUFFERS SNAME("render_buffers")
 #define RB_SCOPE_VRS SNAME("VRS")
 
@@ -68,7 +63,6 @@ private:
 	bool can_be_storage = true;
 	uint32_t max_cluster_elements = 512;
 	RD::DataFormat base_data_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
-	RendererRD::SSEffects *sse = nullptr;
 	RendererRD::VRS *vrs = nullptr;
 	uint64_t auto_exposure_version = 1;
 
@@ -139,9 +133,9 @@ public:
 	// info from our renderer
 	void set_can_be_storage(const bool p_can_be_storage) { can_be_storage = p_can_be_storage; }
 	void set_max_cluster_elements(const uint32_t p_max_elements) { max_cluster_elements = p_max_elements; }
+	uint32_t get_max_cluster_elements() { return max_cluster_elements; }
 	void set_base_data_format(const RD::DataFormat p_base_data_format) { base_data_format = p_base_data_format; }
 	RD::DataFormat get_base_data_format() const { return base_data_format; }
-	void set_sseffects(RendererRD::SSEffects *p_ss_effects) { sse = p_ss_effects; }
 	void set_vrs(RendererRD::VRS *p_vrs) { vrs = p_vrs; }
 
 	void cleanup();
@@ -215,8 +209,6 @@ public:
 	////////////////////////////////////////////////////////////////////////////////////////////////////////////
 	// Everything after this needs to be re-evaluated, this is all old implementation
 
-	ClusterBuilderRD *cluster_builder = nullptr;
-
 	struct WeightBuffers {
 		RID weight;
 		RID fb; // FB with both texture and weight writing into one level lower
@@ -233,24 +225,6 @@ public:
 		Vector<RID> fb;
 		RID current_fb;
 	} luminance;
-
-	struct SSEffects {
-		RID linear_depth;
-		Vector<RID> linear_depth_slices;
-
-		RID downsample_uniform_set;
-
-		Projection last_frame_projection;
-		Transform3D last_frame_transform;
-
-		RendererRD::SSEffects::SSAORenderBuffers ssao;
-		RendererRD::SSEffects::SSILRenderBuffers ssil;
-	} ss_effects;
-
-	RendererRD::SSEffects::SSRRenderBuffers ssr;
-
-	RID get_ao_texture() const { return ss_effects.ssao.ao_final; }
-	RID get_ssil_texture() const { return ss_effects.ssil.ssil_final; }
 };
 
 #endif // RENDER_SCENE_BUFFERS_RD_H

+ 246 - 1
servers/rendering/renderer_rd/storage_rd/texture_storage.cpp

@@ -31,6 +31,7 @@
 #include "texture_storage.h"
 #include "../effects/copy_effects.h"
 #include "material_storage.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
 
 using namespace RendererRD;
 
@@ -457,6 +458,8 @@ TextureStorage::TextureStorage() {
 TextureStorage::~TextureStorage() {
 	rt_sdf.shader.version_free(rt_sdf.shader_version);
 
+	free_decal_data();
+
 	if (decal_atlas.textures.size()) {
 		ERR_PRINT("Decal Atlas: " + itos(decal_atlas.textures.size()) + " textures were not removed from the atlas.");
 	}
@@ -475,6 +478,27 @@ TextureStorage::~TextureStorage() {
 	singleton = nullptr;
 }
 
+bool TextureStorage::free(RID p_rid) {
+	if (owns_texture(p_rid)) {
+		texture_free(p_rid);
+		return true;
+	} else if (owns_canvas_texture(p_rid)) {
+		canvas_texture_free(p_rid);
+		return true;
+	} else if (owns_decal(p_rid)) {
+		decal_free(p_rid);
+		return true;
+	} else if (owns_decal_instance(p_rid)) {
+		decal_instance_free(p_rid);
+		return true;
+	} else if (owns_render_target(p_rid)) {
+		render_target_free(p_rid);
+		return true;
+	}
+
+	return false;
+}
+
 bool TextureStorage::can_create_resources_async() const {
 	return true;
 }
@@ -1888,7 +1912,7 @@ Dependency *TextureStorage::decal_get_dependency(RID p_decal) {
 }
 
 void TextureStorage::update_decal_atlas() {
-	RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
+	CopyEffects *copy_effects = CopyEffects::get_singleton();
 	ERR_FAIL_NULL(copy_effects);
 
 	if (!decal_atlas.dirty) {
@@ -2112,6 +2136,227 @@ void TextureStorage::texture_remove_from_decal_atlas(RID p_texture, bool p_panor
 	}
 }
 
+/* DECAL INSTANCE API */
+
+RID TextureStorage::decal_instance_create(RID p_decal) {
+	DecalInstance di;
+	di.decal = p_decal;
+	di.forward_id = ForwardIDStorage::get_singleton()->allocate_forward_id(FORWARD_ID_TYPE_DECAL);
+	return decal_instance_owner.make_rid(di);
+}
+
+void TextureStorage::decal_instance_free(RID p_decal_instance) {
+	DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+	ForwardIDStorage::get_singleton()->free_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id);
+	decal_instance_owner.free(p_decal_instance);
+}
+
+void TextureStorage::decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) {
+	DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+	ERR_FAIL_COND(!di);
+	di->transform = p_transform;
+}
+
+/* DECAL DATA API */
+
+void TextureStorage::free_decal_data() {
+	if (decal_buffer.is_valid()) {
+		RD::get_singleton()->free(decal_buffer);
+		decal_buffer = RID();
+	}
+
+	if (decals != nullptr) {
+		memdelete_arr(decals);
+		decals = nullptr;
+	}
+
+	if (decal_sort != nullptr) {
+		memdelete_arr(decal_sort);
+		decal_sort = nullptr;
+	}
+}
+
+void TextureStorage::set_max_decals(const uint32_t p_max_decals) {
+	max_decals = p_max_decals;
+	uint32_t decal_buffer_size = max_decals * sizeof(DecalData);
+	decals = memnew_arr(DecalData, max_decals);
+	decal_sort = memnew_arr(DecalInstanceSort, max_decals);
+	decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size);
+}
+
+void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) {
+	ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton();
+
+	Transform3D uv_xform;
+	uv_xform.basis.scale(Vector3(2.0, 1.0, 2.0));
+	uv_xform.origin = Vector3(-1.0, 0.0, -1.0);
+
+	uint32_t decals_size = p_decals.size();
+
+	decal_count = 0;
+
+	for (uint32_t i = 0; i < decals_size; i++) {
+		if (decal_count == max_decals) {
+			break;
+		}
+
+		DecalInstance *decal_instance = decal_instance_owner.get_or_null(p_decals[i]);
+		if (!decal_instance) {
+			continue;
+		}
+		Decal *decal = decal_owner.get_or_null(decal_instance->decal);
+
+		Transform3D xform = decal_instance->transform;
+
+		real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+
+		if (decal->distance_fade) {
+			float fade_begin = decal->distance_fade_begin;
+			float fade_length = decal->distance_fade_length;
+
+			if (distance > fade_begin) {
+				if (distance > fade_begin + fade_length) {
+					continue; // do not use this decal, its invisible
+				}
+			}
+		}
+
+		decal_sort[decal_count].decal_instance = decal_instance;
+		decal_sort[decal_count].decal = decal;
+		decal_sort[decal_count].depth = distance;
+		decal_count++;
+	}
+
+	if (decal_count > 0) {
+		SortArray<DecalInstanceSort> sort_array;
+		sort_array.sort(decal_sort, decal_count);
+	}
+
+	bool using_forward_ids = forward_id_storage->uses_forward_ids();
+	for (uint32_t i = 0; i < decal_count; i++) {
+		DecalInstance *decal_instance = decal_sort[i].decal_instance;
+		Decal *decal = decal_sort[i].decal;
+
+		if (using_forward_ids) {
+			forward_id_storage->map_forward_id(FORWARD_ID_TYPE_DECAL, decal_instance->forward_id, i);
+		}
+
+		decal_instance->cull_mask = decal->cull_mask;
+
+		Transform3D xform = decal_instance->transform;
+		float fade = 1.0;
+
+		if (decal->distance_fade) {
+			const real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+			const float fade_begin = decal->distance_fade_begin;
+			const float fade_length = decal->distance_fade_length;
+
+			if (distance > fade_begin) {
+				// Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
+				fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - fade_begin) / fade_length);
+			}
+		}
+
+		DecalData &dd = decals[i];
+
+		Vector3 decal_extents = decal->extents;
+
+		Transform3D scale_xform;
+		scale_xform.basis.scale(decal_extents);
+		Transform3D to_decal_xform = (p_camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse();
+		MaterialStorage::store_transform(to_decal_xform, dd.xform);
+
+		Vector3 normal = xform.basis.get_column(Vector3::AXIS_Y).normalized();
+		normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
+
+		dd.normal[0] = normal.x;
+		dd.normal[1] = normal.y;
+		dd.normal[2] = normal.z;
+		dd.normal_fade = decal->normal_fade;
+
+		RID albedo_tex = decal->textures[RS::DECAL_TEXTURE_ALBEDO];
+		RID emission_tex = decal->textures[RS::DECAL_TEXTURE_EMISSION];
+		if (albedo_tex.is_valid()) {
+			Rect2 rect = decal_atlas_get_texture_rect(albedo_tex);
+			dd.albedo_rect[0] = rect.position.x;
+			dd.albedo_rect[1] = rect.position.y;
+			dd.albedo_rect[2] = rect.size.x;
+			dd.albedo_rect[3] = rect.size.y;
+		} else {
+			if (!emission_tex.is_valid()) {
+				continue; //no albedo, no emission, no decal.
+			}
+			dd.albedo_rect[0] = 0;
+			dd.albedo_rect[1] = 0;
+			dd.albedo_rect[2] = 0;
+			dd.albedo_rect[3] = 0;
+		}
+
+		RID normal_tex = decal->textures[RS::DECAL_TEXTURE_NORMAL];
+
+		if (normal_tex.is_valid()) {
+			Rect2 rect = decal_atlas_get_texture_rect(normal_tex);
+			dd.normal_rect[0] = rect.position.x;
+			dd.normal_rect[1] = rect.position.y;
+			dd.normal_rect[2] = rect.size.x;
+			dd.normal_rect[3] = rect.size.y;
+
+			Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized();
+			MaterialStorage::store_basis_3x4(normal_xform, dd.normal_xform);
+		} else {
+			dd.normal_rect[0] = 0;
+			dd.normal_rect[1] = 0;
+			dd.normal_rect[2] = 0;
+			dd.normal_rect[3] = 0;
+		}
+
+		RID orm_tex = decal->textures[RS::DECAL_TEXTURE_ORM];
+		if (orm_tex.is_valid()) {
+			Rect2 rect = decal_atlas_get_texture_rect(orm_tex);
+			dd.orm_rect[0] = rect.position.x;
+			dd.orm_rect[1] = rect.position.y;
+			dd.orm_rect[2] = rect.size.x;
+			dd.orm_rect[3] = rect.size.y;
+		} else {
+			dd.orm_rect[0] = 0;
+			dd.orm_rect[1] = 0;
+			dd.orm_rect[2] = 0;
+			dd.orm_rect[3] = 0;
+		}
+
+		if (emission_tex.is_valid()) {
+			Rect2 rect = decal_atlas_get_texture_rect(emission_tex);
+			dd.emission_rect[0] = rect.position.x;
+			dd.emission_rect[1] = rect.position.y;
+			dd.emission_rect[2] = rect.size.x;
+			dd.emission_rect[3] = rect.size.y;
+		} else {
+			dd.emission_rect[0] = 0;
+			dd.emission_rect[1] = 0;
+			dd.emission_rect[2] = 0;
+			dd.emission_rect[3] = 0;
+		}
+
+		Color modulate = decal->modulate;
+		dd.modulate[0] = modulate.r;
+		dd.modulate[1] = modulate.g;
+		dd.modulate[2] = modulate.b;
+		dd.modulate[3] = modulate.a * fade;
+		dd.emission_energy = decal->emission_energy * fade;
+		dd.albedo_mix = decal->albedo_mix;
+		dd.mask = decal->cull_mask;
+		dd.upper_fade = decal->upper_fade;
+		dd.lower_fade = decal->lower_fade;
+
+		// hook for subclass to do further processing.
+		RendererSceneRenderRD::get_singleton()->setup_added_decal(xform, decal_extents);
+	}
+
+	if (decal_count > 0) {
+		RD::get_singleton()->buffer_update(decal_buffer, 0, sizeof(DecalData) * decal_count, decals, RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_COMPUTE);
+	}
+}
+
 /* RENDER TARGET API */
 
 void TextureStorage::_clear_render_target(RenderTarget *rt) {

+ 92 - 1
servers/rendering/renderer_rd/storage_rd/texture_storage.h

@@ -31,8 +31,12 @@
 #ifndef TEXTURE_STORAGE_RD_H
 #define TEXTURE_STORAGE_RD_H
 
+#include "core/templates/local_vector.h"
+#include "core/templates/paged_array.h"
 #include "core/templates/rid_owner.h"
 #include "servers/rendering/renderer_rd/shaders/canvas_sdf.glsl.gen.h"
+#include "servers/rendering/renderer_rd/storage_rd/forward_id_storage.h"
+#include "servers/rendering/rendering_server_default.h"
 #include "servers/rendering/storage/texture_storage.h"
 #include "servers/rendering/storage/utilities.h"
 
@@ -245,7 +249,52 @@ private:
 	};
 
 	mutable RID_Owner<Decal, true> decal_owner;
-	Decal *get_decal(RID p_rid) const { return decal_owner.get_or_null(p_rid); };
+
+	/* DECAL INSTANCE */
+
+	struct DecalInstance {
+		RID decal;
+		Transform3D transform;
+		uint32_t cull_mask = 0;
+		RendererRD::ForwardID forward_id = -1;
+	};
+
+	mutable RID_Owner<DecalInstance> decal_instance_owner;
+
+	/* DECAL DATA (UBO) */
+
+	struct DecalData {
+		float xform[16];
+		float inv_extents[3];
+		float albedo_mix;
+		float albedo_rect[4];
+		float normal_rect[4];
+		float orm_rect[4];
+		float emission_rect[4];
+		float modulate[4];
+		float emission_energy;
+		uint32_t mask;
+		float upper_fade;
+		float lower_fade;
+		float normal_xform[12];
+		float normal[3];
+		float normal_fade;
+	};
+
+	struct DecalInstanceSort {
+		float depth;
+		DecalInstance *decal_instance;
+		Decal *decal;
+		bool operator<(const DecalInstanceSort &p_sort) const {
+			return depth < p_sort.depth;
+		}
+	};
+
+	uint32_t max_decals = 0;
+	uint32_t decal_count = 0;
+	DecalData *decals = nullptr;
+	DecalInstanceSort *decal_sort = nullptr;
+	RID decal_buffer;
 
 	/* RENDER TARGET API */
 
@@ -343,6 +392,8 @@ public:
 	TextureStorage();
 	virtual ~TextureStorage();
 
+	bool free(RID p_rid);
+
 	/* Canvas Texture API */
 
 	bool owns_canvas_texture(RID p_rid) { return canvas_texture_owner.owns(p_rid); };
@@ -545,6 +596,46 @@ public:
 	virtual AABB decal_get_aabb(RID p_decal) const override;
 	Dependency *decal_get_dependency(RID p_decal);
 
+	/* DECAL INSTANCE API */
+
+	bool owns_decal_instance(RID p_rid) const { return decal_instance_owner.owns(p_rid); }
+
+	virtual RID decal_instance_create(RID p_decal) override;
+	virtual void decal_instance_free(RID p_decal_instance) override;
+	virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) override;
+
+	_FORCE_INLINE_ RID decal_instance_get_base(RID p_decal_instance) const {
+		DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+		return di->decal;
+	}
+
+	_FORCE_INLINE_ RendererRD::ForwardID decal_instance_get_forward_id(RID p_decal_instance) const {
+		DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+		return di->forward_id;
+	}
+
+	_FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal_instance) const {
+		DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+		return di->transform;
+	}
+
+	_FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal_instance) {
+		DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+		return di->forward_id;
+	}
+
+	_FORCE_INLINE_ void decal_instance_set_cullmask(RID p_decal_instance, uint32_t p_cull_mask) const {
+		DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+		di->cull_mask = p_cull_mask;
+	}
+
+	/* DECAL DATA API */
+
+	void free_decal_data();
+	void set_max_decals(const uint32_t p_max_decals);
+	RID get_decal_buffer() { return decal_buffer; }
+	void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
+
 	/* RENDER TARGET API */
 
 	bool owns_render_target(RID p_rid) const { return render_target_owner.owns(p_rid); };

+ 17 - 38
servers/rendering/renderer_rd/storage_rd/utilities.cpp

@@ -89,49 +89,28 @@ RS::InstanceType Utilities::get_base_type(RID p_rid) const {
 }
 
 bool Utilities::free(RID p_rid) {
-	if (RendererRD::TextureStorage::get_singleton()->owns_texture(p_rid)) {
-		RendererRD::TextureStorage::get_singleton()->texture_free(p_rid);
-	} else if (RendererRD::TextureStorage::get_singleton()->owns_canvas_texture(p_rid)) {
-		RendererRD::TextureStorage::get_singleton()->canvas_texture_free(p_rid);
-	} else if (RendererRD::MaterialStorage::get_singleton()->owns_shader(p_rid)) {
-		RendererRD::MaterialStorage::get_singleton()->shader_free(p_rid);
-	} else if (RendererRD::MaterialStorage::get_singleton()->owns_material(p_rid)) {
-		RendererRD::MaterialStorage::get_singleton()->material_free(p_rid);
-	} else if (RendererRD::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
-		RendererRD::MeshStorage::get_singleton()->mesh_free(p_rid);
-	} else if (RendererRD::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) {
-		RendererRD::MeshStorage::get_singleton()->mesh_instance_free(p_rid);
-	} else if (RendererRD::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
-		RendererRD::MeshStorage::get_singleton()->multimesh_free(p_rid);
-	} else if (RendererRD::MeshStorage::get_singleton()->owns_skeleton(p_rid)) {
-		RendererRD::MeshStorage::get_singleton()->skeleton_free(p_rid);
-	} else if (RendererRD::LightStorage::get_singleton()->owns_reflection_probe(p_rid)) {
-		RendererRD::LightStorage::get_singleton()->reflection_probe_free(p_rid);
-	} else if (RendererRD::TextureStorage::get_singleton()->owns_decal(p_rid)) {
-		RendererRD::TextureStorage::get_singleton()->decal_free(p_rid);
+	if (RendererRD::LightStorage::get_singleton()->free(p_rid)) {
+		return true;
+	} else if (RendererRD::MaterialStorage::get_singleton()->free(p_rid)) {
+		return true;
+	} else if (RendererRD::MeshStorage::get_singleton()->free(p_rid)) {
+		return true;
+	} else if (RendererRD::ParticlesStorage::get_singleton()->free(p_rid)) {
+		return true;
+	} else if (RendererRD::TextureStorage::get_singleton()->free(p_rid)) {
+		return true;
 	} else if (RendererRD::GI::get_singleton()->owns_voxel_gi(p_rid)) {
 		RendererRD::GI::get_singleton()->voxel_gi_free(p_rid);
-	} else if (RendererRD::LightStorage::get_singleton()->owns_lightmap(p_rid)) {
-		RendererRD::LightStorage::get_singleton()->lightmap_free(p_rid);
-	} else if (RendererRD::LightStorage::get_singleton()->owns_light(p_rid)) {
-		RendererRD::LightStorage::get_singleton()->light_free(p_rid);
-	} else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles(p_rid)) {
-		RendererRD::ParticlesStorage::get_singleton()->particles_free(p_rid);
-	} else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles_collision(p_rid)) {
-		RendererRD::ParticlesStorage::get_singleton()->particles_collision_free(p_rid);
+		return true;
+	} else if (RendererRD::Fog::get_singleton()->owns_fog_volume(p_rid)) {
+		RendererRD::Fog::get_singleton()->fog_volume_free(p_rid);
+		return true;
 	} else if (owns_visibility_notifier(p_rid)) {
 		visibility_notifier_free(p_rid);
-	} else if (RendererRD::ParticlesStorage::get_singleton()->owns_particles_collision_instance(p_rid)) {
-		RendererRD::ParticlesStorage::get_singleton()->particles_collision_instance_free(p_rid);
-	} else if (RendererRD::Fog::get_singleton()->owns_fog_volume(p_rid)) {
-		RendererRD::Fog::get_singleton()->fog_free(p_rid);
-	} else if (RendererRD::TextureStorage::get_singleton()->owns_render_target(p_rid)) {
-		RendererRD::TextureStorage::get_singleton()->render_target_free(p_rid);
+		return true;
 	} else {
 		return false;
 	}
-
-	return true;
 }
 
 /* DEPENDENCIES */
@@ -170,8 +149,8 @@ void Utilities::base_update_dependency(RID p_base, DependencyTracker *p_instance
 		Dependency *dependency = ParticlesStorage::get_singleton()->particles_collision_get_dependency(p_base);
 		p_instance->update_dependency(dependency);
 	} else if (Fog::get_singleton()->owns_fog_volume(p_base)) {
-		Fog::FogVolume *fv = Fog::get_singleton()->get_fog_volume(p_base);
-		p_instance->update_dependency(&fv->dependency);
+		Dependency *dependency = Fog::get_singleton()->fog_volume_get_dependency(p_base);
+		p_instance->update_dependency(dependency);
 	} else if (owns_visibility_notifier(p_base)) {
 		VisibilityNotifier *vn = get_visibility_notifier(p_base);
 		p_instance->update_dependency(&vn->dependency);

+ 40 - 39
servers/rendering/renderer_scene_cull.cpp

@@ -357,13 +357,14 @@ void RendererSceneCull::scenario_initialize(RID p_rid) {
 	Scenario *scenario = scenario_owner.get_or_null(p_rid);
 	scenario->self = p_rid;
 
-	scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create();
-	scene_render->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest
-	scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4);
-	scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4);
-	scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4);
-	scene_render->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8);
-	scenario->reflection_atlas = scene_render->reflection_atlas_create();
+	scenario->reflection_probe_shadow_atlas = RSG::light_storage->shadow_atlas_create();
+	RSG::light_storage->shadow_atlas_set_size(scenario->reflection_probe_shadow_atlas, 1024); //make enough shadows for close distance, don't bother with rest
+	RSG::light_storage->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 0, 4);
+	RSG::light_storage->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 1, 4);
+	RSG::light_storage->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 2, 4);
+	RSG::light_storage->shadow_atlas_set_quadrant_subdivision(scenario->reflection_probe_shadow_atlas, 3, 8);
+
+	scenario->reflection_atlas = RSG::light_storage->reflection_atlas_create();
 
 	scenario->instance_aabbs.set_page_pool(&instance_aabb_page_pool);
 	scenario->instance_data.set_page_pool(&instance_data_page_pool);
@@ -393,7 +394,7 @@ void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_
 void RendererSceneCull::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) {
 	Scenario *scenario = scenario_owner.get_or_null(p_scenario);
 	ERR_FAIL_COND(!scenario);
-	scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
+	RSG::light_storage->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count);
 }
 
 bool RendererSceneCull::is_scenario(RID p_scenario) const {
@@ -534,7 +535,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
 					scenario->directional_lights.erase(light->D);
 					light->D = nullptr;
 				}
-				scene_render->free(light->instance);
+				RSG::light_storage->light_instance_free(light->instance);
 			} break;
 			case RS::INSTANCE_PARTICLES_COLLISION: {
 				InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data);
@@ -549,14 +550,14 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
 			} break;
 			case RS::INSTANCE_REFLECTION_PROBE: {
 				InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
-				scene_render->free(reflection_probe->instance);
+				RSG::light_storage->reflection_probe_instance_free(reflection_probe->instance);
 				if (reflection_probe->update_list.in_list()) {
 					reflection_probe_render_list.remove(&reflection_probe->update_list);
 				}
 			} break;
 			case RS::INSTANCE_DECAL: {
 				InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data);
-				scene_render->free(decal->instance);
+				RSG::texture_storage->decal_instance_free(decal->instance);
 
 			} break;
 			case RS::INSTANCE_LIGHTMAP: {
@@ -565,7 +566,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
 				while (lightmap_data->users.begin()) {
 					instance_geometry_set_lightmap((*lightmap_data->users.begin())->self, RID(), Rect2(), 0);
 				}
-				scene_render->free(lightmap_data->instance);
+				RSG::light_storage->lightmap_instance_free(lightmap_data->instance);
 			} break;
 			case RS::INSTANCE_VOXEL_GI: {
 				InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(instance->base_data);
@@ -626,7 +627,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
 					light->D = scenario->directional_lights.push_back(instance);
 				}
 
-				light->instance = scene_render->light_instance_create(p_base);
+				light->instance = RSG::light_storage->light_instance_create(p_base);
 
 				instance->base_data = light;
 			} break;
@@ -684,19 +685,19 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
 				reflection_probe->owner = instance;
 				instance->base_data = reflection_probe;
 
-				reflection_probe->instance = scene_render->reflection_probe_instance_create(p_base);
+				reflection_probe->instance = RSG::light_storage->reflection_probe_instance_create(p_base);
 			} break;
 			case RS::INSTANCE_DECAL: {
 				InstanceDecalData *decal = memnew(InstanceDecalData);
 				decal->owner = instance;
 				instance->base_data = decal;
 
-				decal->instance = scene_render->decal_instance_create(p_base);
+				decal->instance = RSG::texture_storage->decal_instance_create(p_base);
 			} break;
 			case RS::INSTANCE_LIGHTMAP: {
 				InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData);
 				instance->base_data = lightmap_data;
-				lightmap_data->instance = scene_render->lightmap_instance_create(p_base);
+				lightmap_data->instance = RSG::light_storage->lightmap_instance_create(p_base);
 			} break;
 			case RS::INSTANCE_VOXEL_GI: {
 				InstanceVoxelGIData *voxel_gi = memnew(InstanceVoxelGIData);
@@ -758,7 +759,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
 			} break;
 			case RS::INSTANCE_REFLECTION_PROBE: {
 				InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(instance->base_data);
-				scene_render->reflection_probe_release_atlas_index(reflection_probe->instance);
+				RSG::light_storage->reflection_probe_release_atlas_index(reflection_probe->instance);
 
 			} break;
 			case RS::INSTANCE_PARTICLES_COLLISION: {
@@ -1502,8 +1503,8 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
 	if (p_instance->base_type == RS::INSTANCE_LIGHT) {
 		InstanceLightData *light = static_cast<InstanceLightData *>(p_instance->base_data);
 
-		scene_render->light_instance_set_transform(light->instance, p_instance->transform);
-		scene_render->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb));
+		RSG::light_storage->light_instance_set_transform(light->instance, p_instance->transform);
+		RSG::light_storage->light_instance_set_aabb(light->instance, p_instance->transform.xform(p_instance->aabb));
 		light->shadow_dirty = true;
 
 		RS::LightBakeMode bake_mode = RSG::light_storage->light_get_bake_mode(p_instance->base);
@@ -1526,7 +1527,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
 	} else if (p_instance->base_type == RS::INSTANCE_REFLECTION_PROBE) {
 		InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(p_instance->base_data);
 
-		scene_render->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform);
+		RSG::light_storage->reflection_probe_instance_set_transform(reflection_probe->instance, p_instance->transform);
 
 		if (p_instance->scenario && p_instance->array_index >= 0) {
 			InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index];
@@ -1535,11 +1536,11 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
 	} else if (p_instance->base_type == RS::INSTANCE_DECAL) {
 		InstanceDecalData *decal = static_cast<InstanceDecalData *>(p_instance->base_data);
 
-		scene_render->decal_instance_set_transform(decal->instance, p_instance->transform);
+		RSG::texture_storage->decal_instance_set_transform(decal->instance, p_instance->transform);
 	} else if (p_instance->base_type == RS::INSTANCE_LIGHTMAP) {
 		InstanceLightmapData *lightmap = static_cast<InstanceLightmapData *>(p_instance->base_data);
 
-		scene_render->lightmap_instance_set_transform(lightmap->instance, p_instance->transform);
+		RSG::light_storage->lightmap_instance_set_transform(lightmap->instance, p_instance->transform);
 	} else if (p_instance->base_type == RS::INSTANCE_VOXEL_GI) {
 		InstanceVoxelGIData *voxel_gi = static_cast<InstanceVoxelGIData *>(p_instance->base_data);
 
@@ -2050,7 +2051,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in
 
 	distances[splits] = max_distance;
 
-	real_t texture_size = scene_render->get_directional_light_shadow_size(light->instance);
+	real_t texture_size = RSG::light_storage->get_directional_light_shadow_size(light->instance);
 
 	bool overlap = RSG::light_storage->light_directional_get_blend_splits(p_instance->base);
 
@@ -2241,7 +2242,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 		case RS::LIGHT_OMNI: {
 			RS::LightOmniShadowMode shadow_mode = RSG::light_storage->light_omni_get_shadow_mode(p_instance->base);
 
-			if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !scene_render->light_instances_can_render_shadow_cube()) {
+			if (shadow_mode == RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID || !RSG::light_storage->light_instances_can_render_shadow_cube()) {
 				if (max_shadows_used + 2 > MAX_UPDATE_SHADOWS) {
 					return true;
 				}
@@ -2300,7 +2301,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 
 					RSG::mesh_storage->update_mesh_instances();
 
-					scene_render->light_instance_set_shadow_transform(light->instance, Projection(), light_transform, radius, 0, i, 0);
+					RSG::light_storage->light_instance_set_shadow_transform(light->instance, Projection(), light_transform, radius, 0, i, 0);
 					shadow_data.light = light->instance;
 					shadow_data.pass = i;
 				}
@@ -2376,14 +2377,14 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 					}
 
 					RSG::mesh_storage->update_mesh_instances();
-					scene_render->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
+					RSG::light_storage->light_instance_set_shadow_transform(light->instance, cm, xform, radius, 0, i, 0);
 
 					shadow_data.light = light->instance;
 					shadow_data.pass = i;
 				}
 
 				//restore the regular DP matrix
-				//scene_render->light_instance_set_shadow_transform(light->instance, Projection(), light_transform, radius, 0, 0, 0);
+				//RSG::light_storage->light_instance_set_shadow_transform(light->instance, Projection(), light_transform, radius, 0, 0, 0);
 			}
 
 		} break;
@@ -2440,7 +2441,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons
 
 			RSG::mesh_storage->update_mesh_instances();
 
-			scene_render->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
+			RSG::light_storage->light_instance_set_shadow_transform(light->instance, cm, light_transform, radius, 0, 0, 0);
 			shadow_data.light = light->instance;
 			shadow_data.pass = 0;
 
@@ -2680,14 +2681,14 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
 					cull_result.lights.push_back(idata.instance);
 					cull_result.light_instances.push_back(RID::from_uint64(idata.instance_data_rid));
 					if (cull_data.shadow_atlas.is_valid() && RSG::light_storage->light_has_shadow(idata.base_rid)) {
-						scene_render->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
+						RSG::light_storage->light_instance_mark_visible(RID::from_uint64(idata.instance_data_rid)); //mark it visible for shadow allocation later
 					}
 
 				} else if (base_type == RS::INSTANCE_REFLECTION_PROBE) {
 					if (cull_data.render_reflection_probe != idata.instance) {
 						//avoid entering The Matrix
 
-						if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || scene_render->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
+						if ((idata.flags & InstanceData::FLAG_REFLECTION_PROBE_DIRTY) || RSG::light_storage->reflection_probe_instance_needs_redraw(RID::from_uint64(idata.instance_data_rid))) {
 							InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(idata.instance->base_data);
 							cull_data.cull->lock.lock();
 							if (!reflection_probe->update_list.in_list()) {
@@ -2699,7 +2700,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
 							idata.flags &= ~uint32_t(InstanceData::FLAG_REFLECTION_PROBE_DIRTY);
 						}
 
-						if (scene_render->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
+						if (RSG::light_storage->reflection_probe_instance_has_reflection(RID::from_uint64(idata.instance_data_rid))) {
 							cull_result.reflections.push_back(RID::from_uint64(idata.instance_data_rid));
 						}
 					}
@@ -2991,7 +2992,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
 			}
 		}
 
-		scene_render->set_directional_shadow_count(lights_with_shadow.size());
+		RSG::light_storage->set_directional_shadow_count(lights_with_shadow.size());
 
 		for (int i = 0; i < lights_with_shadow.size(); i++) {
 			_light_instance_setup_directional_shadow(i, lights_with_shadow[i], p_camera_data->main_transform, p_camera_data->main_projection, p_camera_data->is_orthogonal, p_camera_data->vaspect);
@@ -3091,7 +3092,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
 			for (uint32_t j = 0; j < cull.shadows[i].cascade_count; j++) {
 				const Cull::Shadow::Cascade &c = cull.shadows[i].cascades[j];
 				//			print_line("shadow " + itos(i) + " cascade " + itos(j) + " elements: " + itos(c.cull_result.size()));
-				scene_render->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale);
+				RSG::light_storage->light_instance_set_shadow_transform(cull.shadows[i].light_instance, c.projection, c.transform, c.zfar, c.split, j, c.shadow_texel_size, c.bias_scale, c.range_begin, c.uv_scale);
 				if (max_shadows_used == MAX_UPDATE_SHADOWS) {
 					continue;
 				}
@@ -3187,7 +3188,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
 				light->shadow_dirty = false;
 			}
 
-			bool redraw = scene_render->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version);
+			bool redraw = RSG::light_storage->shadow_atlas_update_light(p_shadow_atlas, light->instance, coverage, light->last_version);
 
 			if (redraw && max_shadows_used < MAX_UPDATE_SHADOWS) {
 				//must redraw!
@@ -3320,7 +3321,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
 	RenderingServerDefault::redraw_request(); //update, so it updates in editor
 
 	if (p_step == 0) {
-		if (!scene_render->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {
+		if (!RSG::light_storage->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) {
 			return true; //all full
 		}
 	}
@@ -3346,7 +3347,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
 		Vector3 extents = RSG::light_storage->reflection_probe_get_extents(p_instance->base);
 		Vector3 origin_offset = RSG::light_storage->reflection_probe_get_origin_offset(p_instance->base);
 		float max_distance = RSG::light_storage->reflection_probe_get_origin_max_distance(p_instance->base);
-		float size = scene_render->reflection_atlas_get_size(scenario->reflection_atlas);
+		float size = RSG::light_storage->reflection_atlas_get_size(scenario->reflection_atlas);
 		float mesh_lod_threshold = RSG::light_storage->reflection_probe_get_mesh_lod_threshold(p_instance->base) / size;
 
 		Vector3 edge = view_normals[p_step] * extents;
@@ -3387,7 +3388,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
 	} else {
 		//do roughness postprocess step until it believes it's done
 		RENDER_TIMESTAMP("Post-Process ReflectionProbe, Step " + itos(p_step));
-		return scene_render->reflection_probe_instance_postprocess_step(reflection_probe->instance);
+		return RSG::light_storage->reflection_probe_instance_postprocess_step(reflection_probe->instance);
 	}
 
 	return false;
@@ -3967,8 +3968,8 @@ bool RendererSceneCull::free(RID p_rid) {
 		scenario->instance_data.reset();
 		scenario->instance_visibility.reset();
 
-		scene_render->free(scenario->reflection_probe_shadow_atlas);
-		scene_render->free(scenario->reflection_atlas);
+		RSG::light_storage->shadow_atlas_free(scenario->reflection_probe_shadow_atlas);
+		RSG::light_storage->reflection_atlas_free(scenario->reflection_atlas);
 		scenario_owner.free(p_rid);
 		RendererSceneOcclusionCull::get_singleton()->remove_scenario(p_rid);
 

+ 1 - 6
servers/rendering/renderer_scene_cull.h

@@ -1076,7 +1076,6 @@ public:
 
 #define PASSBASE scene_render
 
-	PASS2(directional_shadow_atlas_set_size, int, bool)
 	PASS1(voxel_gi_set_quality, RS::VoxelGIQuality)
 
 	/* SKY API */
@@ -1258,11 +1257,7 @@ public:
 	PASS0R(Ref<RenderSceneBuffers>, render_buffers_create)
 	PASS1(gi_set_use_half_resolution, bool)
 
-	/* Shadow Atlas */
-	PASS0R(RID, shadow_atlas_create)
-	PASS3(shadow_atlas_set_size, RID, int, bool)
-	PASS3(shadow_atlas_set_quadrant_subdivision, RID, int, int)
-
+	/* Misc */
 	PASS1(set_debug_draw_mode, RS::ViewportDebugDraw)
 
 	PASS1(decals_set_filter, RS::DecalFilter)

+ 0 - 38
servers/rendering/renderer_scene_render.h

@@ -56,17 +56,6 @@ public:
 	virtual void geometry_instance_free(RenderGeometryInstance *p_geometry_instance) = 0;
 	virtual uint32_t geometry_instance_get_pair_mask() = 0;
 
-	/* SHADOW ATLAS API */
-
-	virtual RID shadow_atlas_create() = 0;
-	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = true) = 0;
-	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
-	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0;
-
-	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
-	virtual int get_directional_light_shadow_size(RID p_light_intance) = 0;
-	virtual void set_directional_shadow_count(int p_count) = 0;
-
 	/* SDFGI UPDATE */
 
 	virtual void sdfgi_update(const Ref<RenderSceneBuffers> &p_render_buffers, RID p_environment, const Vector3 &p_world_position) = 0;
@@ -240,39 +229,12 @@ public:
 	virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
 	virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
 
-	virtual RID light_instance_create(RID p_light) = 0;
-	virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) = 0;
-	virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0;
-	virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0;
-	virtual void light_instance_mark_visible(RID p_light_instance) = 0;
-	virtual bool light_instances_can_render_shadow_cube() const {
-		return true;
-	}
-
 	virtual RID fog_volume_instance_create(RID p_fog_volume) = 0;
 	virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) = 0;
 	virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) = 0;
 	virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const = 0;
 	virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const = 0;
 
-	virtual RID reflection_atlas_create() = 0;
-	virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
-	virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0;
-
-	virtual RID reflection_probe_instance_create(RID p_probe) = 0;
-	virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
-	virtual void reflection_probe_release_atlas_index(RID p_instance) = 0;
-	virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
-	virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
-	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
-	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
-
-	virtual RID decal_instance_create(RID p_decal) = 0;
-	virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) = 0;
-
-	virtual RID lightmap_instance_create(RID p_lightmap) = 0;
-	virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) = 0;
-
 	virtual RID voxel_gi_instance_create(RID p_voxel_gi) = 0;
 	virtual void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) = 0;
 	virtual bool voxel_gi_needs_update(RID p_probe) const = 0;

+ 4 - 4
servers/rendering/renderer_viewport.cpp

@@ -760,7 +760,7 @@ void RendererViewport::viewport_initialize(RID p_rid) {
 	Viewport *viewport = viewport_owner.get_or_null(p_rid);
 	viewport->self = p_rid;
 	viewport->render_target = RSG::texture_storage->render_target_create();
-	viewport->shadow_atlas = RSG::scene->shadow_atlas_create();
+	viewport->shadow_atlas = RSG::light_storage->shadow_atlas_create();
 	viewport->viewport_render_direct_to_screen = false;
 
 	viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d;
@@ -1076,14 +1076,14 @@ void RendererViewport::viewport_set_positional_shadow_atlas_size(RID p_viewport,
 	viewport->shadow_atlas_size = p_size;
 	viewport->shadow_atlas_16_bits = p_16_bits;
 
-	RSG::scene->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits);
+	RSG::light_storage->shadow_atlas_set_size(viewport->shadow_atlas, viewport->shadow_atlas_size, viewport->shadow_atlas_16_bits);
 }
 
 void RendererViewport::viewport_set_positional_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) {
 	Viewport *viewport = viewport_owner.get_or_null(p_viewport);
 	ERR_FAIL_COND(!viewport);
 
-	RSG::scene->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
+	RSG::light_storage->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv);
 }
 
 void RendererViewport::viewport_set_msaa_2d(RID p_viewport, RS::ViewportMSAA p_msaa) {
@@ -1294,7 +1294,7 @@ bool RendererViewport::free(RID p_rid) {
 		Viewport *viewport = viewport_owner.get_or_null(p_rid);
 
 		RSG::texture_storage->render_target_free(viewport->render_target);
-		RSG::scene->free(viewport->shadow_atlas);
+		RSG::light_storage->shadow_atlas_free(viewport->shadow_atlas);
 		if (viewport->render_buffers.is_valid()) {
 			viewport->render_buffers.unref();
 		}

+ 0 - 6
servers/rendering/rendering_method.h

@@ -106,8 +106,6 @@ public:
 	virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0;
 	virtual Variant instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const = 0;
 
-	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
-
 	/* SKY API */
 
 	virtual RID sky_allocate() = 0;
@@ -284,10 +282,6 @@ public:
 	virtual void positional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
 	virtual void directional_soft_shadow_filter_set_quality(RS::ShadowQuality p_quality) = 0;
 
-	virtual RID shadow_atlas_create() = 0;
-	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = true) = 0;
-	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
-
 	/* Render Buffers */
 
 	virtual Ref<RenderSceneBuffers> render_buffers_create() = 0;

+ 7 - 1
servers/rendering/rendering_server_default.h

@@ -410,6 +410,13 @@ public:
 	FUNC1RC(PackedInt32Array, lightmap_get_probe_capture_bsp_tree, RID)
 	FUNC1(lightmap_set_probe_capture_update_speed, float)
 
+	/* Shadow Atlas */
+	FUNC0R(RID, shadow_atlas_create)
+	FUNC3(shadow_atlas_set_size, RID, int, bool)
+	FUNC3(shadow_atlas_set_quadrant_subdivision, RID, int, int)
+
+	FUNC2(directional_shadow_atlas_set_size, int, bool)
+
 	/* DECAL API */
 
 #undef ServerName
@@ -652,7 +659,6 @@ public:
 #define ServerName RenderingMethod
 #define server_name RSG::scene
 
-	FUNC2(directional_shadow_atlas_set_size, int, bool)
 	FUNC1(voxel_gi_set_quality, VoxelGIQuality)
 
 	/* SKY API */

+ 51 - 0
servers/rendering/storage/light_storage.h

@@ -84,6 +84,18 @@ public:
 	virtual uint32_t light_get_max_sdfgi_cascade(RID p_light) = 0;
 	virtual uint64_t light_get_version(RID p_light) const = 0;
 
+	/* LIGHT INSTANCE API */
+
+	virtual RID light_instance_create(RID p_light) = 0;
+	virtual void light_instance_free(RID p_light_instance) = 0;
+	virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) = 0;
+	virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) = 0;
+	virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) = 0;
+	virtual void light_instance_mark_visible(RID p_light_instance) = 0;
+	virtual bool light_instances_can_render_shadow_cube() const {
+		return true;
+	}
+
 	/* PROBE API */
 
 	virtual RID reflection_probe_allocate() = 0;
@@ -114,6 +126,24 @@ public:
 	virtual bool reflection_probe_renders_shadows(RID p_probe) const = 0;
 	virtual float reflection_probe_get_mesh_lod_threshold(RID p_probe) const = 0;
 
+	/* REFLECTION ATLAS */
+
+	virtual RID reflection_atlas_create() = 0;
+	virtual void reflection_atlas_free(RID p_ref_atlas) = 0;
+	virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0;
+	virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0;
+
+	/* REFLECTION PROBE INSTANCE */
+
+	virtual RID reflection_probe_instance_create(RID p_probe) = 0;
+	virtual void reflection_probe_instance_free(RID p_instance) = 0;
+	virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0;
+	virtual void reflection_probe_release_atlas_index(RID p_instance) = 0;
+	virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0;
+	virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0;
+	virtual bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) = 0;
+	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
+
 	/* LIGHTMAP  */
 
 	virtual RID lightmap_allocate() = 0;
@@ -134,6 +164,27 @@ public:
 	virtual bool lightmap_is_interior(RID p_lightmap) const = 0;
 	virtual void lightmap_set_probe_capture_update_speed(float p_speed) = 0;
 	virtual float lightmap_get_probe_capture_update_speed() const = 0;
+
+	/* LIGHTMAP INSTANCE */
+
+	virtual RID lightmap_instance_create(RID p_lightmap) = 0;
+	virtual void lightmap_instance_free(RID p_lightmap) = 0;
+	virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) = 0;
+
+	/* SHADOW ATLAS */
+
+	virtual RID shadow_atlas_create() = 0;
+	virtual void shadow_atlas_free(RID p_atlas) = 0;
+
+	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = true) = 0;
+	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
+	virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) = 0;
+
+	virtual void shadow_atlas_update(RID p_atlas) = 0;
+
+	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
+	virtual int get_directional_light_shadow_size(RID p_light_intance) = 0;
+	virtual void set_directional_shadow_count(int p_count) = 0;
 };
 
 #endif // LIGHT_STORAGE_H

+ 6 - 0
servers/rendering/storage/texture_storage.h

@@ -120,6 +120,12 @@ public:
 	virtual void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0;
 	virtual void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) = 0;
 
+	/* DECAL INSTANCE */
+
+	virtual RID decal_instance_create(RID p_decal) = 0;
+	virtual void decal_instance_free(RID p_decal_instance) = 0;
+	virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) = 0;
+
 	/* RENDER TARGET */
 
 	virtual RID render_target_create() = 0;

+ 6 - 0
servers/rendering_server.h

@@ -485,6 +485,12 @@ public:
 	virtual void light_directional_set_blend_splits(RID p_light, bool p_enable) = 0;
 	virtual void light_directional_set_sky_mode(RID p_light, LightDirectionalSkyMode p_mode) = 0;
 
+	// Shadow atlas
+
+	virtual RID shadow_atlas_create() = 0;
+	virtual void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_use_16_bits = true) = 0;
+	virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) = 0;
+
 	virtual void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = true) = 0;
 
 	enum ShadowQuality {

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov