فهرست منبع

Merge pull request #70253 from BastiaanOlij/cleanup_sky_render

Cleanup and improve sky render
Rémi Verschelde 2 سال پیش
والد
کامیت
f064898956

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

@@ -502,6 +502,10 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
 	return false;
 }
 
+Ref<RenderSceneBuffers> LightStorage::reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) {
+	return Ref<RenderSceneBuffers>();
+}
+
 bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
 	return true;
 }

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

@@ -366,6 +366,7 @@ public:
 	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 Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override;
 	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override;
 
 	/* LIGHTMAP CAPTURE */

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

@@ -135,6 +135,7 @@ public:
 	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 Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) override { return Ref<RenderSceneBuffers>(); }
 	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) override { return true; }
 
 	/* LIGHTMAP CAPTURE */

+ 118 - 255
servers/rendering/renderer_rd/environment/sky.cpp

@@ -32,16 +32,22 @@
 #include "core/config/project_settings.h"
 #include "core/math/math_defs.h"
 #include "servers/rendering/renderer_rd/effects/copy_effects.h"
+#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
 #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
 #include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
 #include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
 #include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
 #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
+#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
 #include "servers/rendering/rendering_server_default.h"
 #include "servers/rendering/rendering_server_globals.h"
 
 using namespace RendererRD;
 
+#define RB_SCOPE_SKY SNAME("sky_buffers")
+#define RB_HALF_TEXTURE SNAME("half_texture")
+#define RB_QUARTER_TEXTURE SNAME("quarter_texture")
+
 ////////////////////////////////////////////////////////////////////////////////
 // SKY SHADER
 
@@ -204,18 +210,17 @@ static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_basis, float *p_ar
 	p_array[11] = 0;
 }
 
-void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier) {
+void SkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier) {
 	SkyPushConstant sky_push_constant;
 
 	memset(&sky_push_constant, 0, sizeof(SkyPushConstant));
 
-	for (uint32_t v = 0; v < p_view_count; v++) {
-		// We only need key components of our projection matrix
-		sky_push_constant.projections[v][0] = p_projections[v].columns[2][0];
-		sky_push_constant.projections[v][1] = p_projections[v].columns[0][0];
-		sky_push_constant.projections[v][2] = p_projections[v].columns[2][1];
-		sky_push_constant.projections[v][3] = p_projections[v].columns[1][1];
-	}
+	// We only need key components of our projection matrix
+	sky_push_constant.projection[0] = p_projection.columns[2][0];
+	sky_push_constant.projection[1] = p_projection.columns[0][0];
+	sky_push_constant.projection[2] = p_projection.columns[2][1];
+	sky_push_constant.projection[3] = p_projection.columns[1][1];
+
 	sky_push_constant.position[0] = p_position.x;
 	sky_push_constant.position[1] = p_position.y;
 	sky_push_constant.position[2] = p_position.z;
@@ -540,28 +545,15 @@ void SkyRD::Sky::free() {
 		uniform_buffer = RID();
 	}
 
-	if (half_res_pass.is_valid()) {
-		RD::get_singleton()->free(half_res_pass);
-		half_res_pass = RID();
-	}
-
-	if (quarter_res_pass.is_valid()) {
-		RD::get_singleton()->free(quarter_res_pass);
-		quarter_res_pass = RID();
-	}
-
 	if (material.is_valid()) {
 		RSG::material_storage->material_free(material);
 		material = RID();
 	}
 }
 
-RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd) {
+RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd, Ref<RenderSceneBuffersRD> p_render_buffers) {
 	RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
 
-	if (texture_uniform_sets[p_version].is_valid() && RD::get_singleton()->uniform_set_is_valid(texture_uniform_sets[p_version])) {
-		return texture_uniform_sets[p_version];
-	}
 	Vector<RD::Uniform> uniforms;
 	{
 		RD::Uniform u;
@@ -578,17 +570,18 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade
 		RD::Uniform u;
 		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
 		u.binding = 1; // half res
-		if (half_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) {
-			if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+		if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+			if (reflection.layers[0].views[1].is_valid() && p_version != SKY_TEXTURE_SET_CUBEMAP_HALF_RES) {
 				u.append_id(reflection.layers[0].views[1]);
 			} else {
-				u.append_id(half_res_pass);
+				u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
 			}
 		} else {
-			if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
-				u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
+			RID half_texture = p_render_buffers->has_texture(RB_SCOPE_SKY, RB_HALF_TEXTURE) ? p_render_buffers->get_texture(RB_SCOPE_SKY, RB_HALF_TEXTURE) : RID();
+			if (half_texture.is_valid() && p_version != SKY_TEXTURE_SET_HALF_RES) {
+				u.append_id(half_texture);
 			} else {
-				u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+				u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
 			}
 		}
 		uniforms.push_back(u);
@@ -597,24 +590,24 @@ RID SkyRD::Sky::get_textures(SkyTextureSetVersion p_version, RID p_default_shade
 		RD::Uniform u;
 		u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
 		u.binding = 2; // quarter res
-		if (quarter_res_pass.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) {
-			if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+		if (p_version >= SKY_TEXTURE_SET_CUBEMAP) {
+			if (reflection.layers[0].views[2].is_valid() && p_version != SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES) {
 				u.append_id(reflection.layers[0].views[2]);
 			} else {
-				u.append_id(quarter_res_pass);
+				u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
 			}
 		} else {
-			if (p_version < SKY_TEXTURE_SET_CUBEMAP) {
-				u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
+			RID quarter_texture = p_render_buffers->has_texture(RB_SCOPE_SKY, RB_QUARTER_TEXTURE) ? p_render_buffers->get_texture(RB_SCOPE_SKY, RB_QUARTER_TEXTURE) : RID();
+			if (quarter_texture.is_valid() && p_version != SKY_TEXTURE_SET_QUARTER_RES) {
+				u.append_id(quarter_texture);
 			} else {
-				u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK));
+				u.append_id(texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_WHITE));
 			}
 		}
 		uniforms.push_back(u);
 	}
 
-	texture_uniform_sets[p_version] = RD::get_singleton()->uniform_set_create(uniforms, p_default_shader_rd, SKY_SET_TEXTURES);
-	return texture_uniform_sets[p_version];
+	return UniformSetCacheRD::get_singleton()->get_cache_vec(p_default_shader_rd, SKY_SET_TEXTURES, uniforms);
 }
 
 bool SkyRD::Sky::set_radiance_size(int p_radiance_size) {
@@ -1020,11 +1013,17 @@ SkyRD::~SkyRD() {
 	RD::get_singleton()->free(index_buffer); //array gets freed as dependency
 }
 
-void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
+void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render) {
 	RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
 	RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
 	ERR_FAIL_COND(p_env.is_null());
 
+	ERR_FAIL_COND(p_render_buffers.is_null());
+
+	// make sure we support our view count
+	ERR_FAIL_COND(p_view_count == 0);
+	ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
+
 	SkyMaterialData *material = nullptr;
 	Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
 
@@ -1055,31 +1054,12 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
 
 		material->set_as_used();
 
-		// Invalidate supbass buffers if screen size changes
-		if (sky->screen_size != p_screen_size) {
-			sky->screen_size = p_screen_size;
-			sky->screen_size.x = sky->screen_size.x < 4 ? 4 : sky->screen_size.x;
-			sky->screen_size.y = sky->screen_size.y < 4 ? 4 : sky->screen_size.y;
-			if (shader_data->uses_half_res) {
-				if (sky->half_res_pass.is_valid()) {
-					RD::get_singleton()->free(sky->half_res_pass);
-					sky->half_res_pass = RID();
-				}
-				invalidate_sky(sky);
-			}
-			if (shader_data->uses_quarter_res) {
-				if (sky->quarter_res_pass.is_valid()) {
-					RD::get_singleton()->free(sky->quarter_res_pass);
-					sky->quarter_res_pass = RID();
-				}
-				invalidate_sky(sky);
-			}
-		}
+		// Save our screen size, our buffers will already have been cleared
+		sky->screen_size.x = p_screen_size.x < 4 ? 4 : p_screen_size.x;
+		sky->screen_size.y = p_screen_size.y < 4 ? 4 : p_screen_size.y;
 
-		// Create new subpass buffers if necessary
-		if ((shader_data->uses_half_res && sky->half_res_pass.is_null()) ||
-				(shader_data->uses_quarter_res && sky->quarter_res_pass.is_null()) ||
-				sky->radiance.is_null()) {
+		// Trigger updating radiance buffers
+		if (sky->radiance.is_null()) {
 			invalidate_sky(sky);
 			update_dirty_skys();
 		}
@@ -1100,8 +1080,8 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
 			sky->reflection.dirty = true;
 		}
 
-		if (!p_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
-			sky->prev_position = p_transform.origin;
+		if (!p_cam_transform.origin.is_equal_approx(sky->prev_position) && shader_data->uses_position) {
+			sky->prev_position = p_cam_transform.origin;
 			sky->reflection.dirty = true;
 		}
 
@@ -1229,7 +1209,20 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
 		}
 	}
 
-	sky_scene_state.ubo.z_far = p_projection.get_z_far();
+	sky_scene_state.view_count = p_view_count;
+	sky_scene_state.cam_transform = p_cam_transform;
+	sky_scene_state.cam_projection = p_view_projections[0]; // We only use this when rendering a single view
+
+	// Our info in our UBO is only used if we're rendering stereo
+	for (uint32_t i = 0; i < p_view_count; i++) {
+		RendererRD::MaterialStorage::store_camera(p_view_projections[i].inverse(), sky_scene_state.ubo.view_inv_projections[i]);
+		sky_scene_state.ubo.view_eye_offsets[i][0] = p_view_eye_offsets[i].x;
+		sky_scene_state.ubo.view_eye_offsets[i][1] = p_view_eye_offsets[i].y;
+		sky_scene_state.ubo.view_eye_offsets[i][2] = p_view_eye_offsets[i].z;
+		sky_scene_state.ubo.view_eye_offsets[i][3] = 0.0;
+	}
+
+	sky_scene_state.ubo.z_far = p_view_projections[0].get_z_far(); // Should be the same for all projection
 	sky_scene_state.ubo.fog_enabled = RendererSceneRenderRD::get_singleton()->environment_get_fog_enabled(p_env);
 	sky_scene_state.ubo.fog_density = RendererSceneRenderRD::get_singleton()->environment_get_fog_density(p_env);
 	sky_scene_state.ubo.fog_aerial_perspective = RendererSceneRenderRD::get_singleton()->environment_get_fog_aerial_perspective(p_env);
@@ -1246,7 +1239,8 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
 	RD::get_singleton()->buffer_update(sky_scene_state.uniform_buffer, 0, sizeof(SkySceneState::UBO), &sky_scene_state.ubo);
 }
 
-void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
+void SkyRD::update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, const Vector3 &p_global_pos, double p_time, float p_luminance_multiplier) {
+	ERR_FAIL_COND(p_render_buffers.is_null());
 	RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
 	ERR_FAIL_COND(p_env.is_null());
 
@@ -1324,6 +1318,8 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
 		correction.set_depth_correction(true);
 		cm = correction * cm;
 
+		// Note, we ignore environment_get_sky_orientation here as this is applied when we do our lookup in our scene shader.
+
 		if (shader_data->uses_quarter_res) {
 			RD::get_singleton()->draw_command_begin_label("Render Sky to Quarter Res Cubemap");
 			PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
@@ -1334,10 +1330,10 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
 
 			for (int i = 0; i < 6; i++) {
 				Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
-				RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd);
+				RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_QUARTER_RES, sky_shader.default_shader_rd, p_render_buffers);
 
 				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[2].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
-				_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
+				_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[2].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier);
 				RD::get_singleton()->draw_list_end();
 			}
 			RD::get_singleton()->draw_command_end_label();
@@ -1353,10 +1349,10 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
 
 			for (int i = 0; i < 6; i++) {
 				Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
-				RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd);
+				RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP_HALF_RES, sky_shader.default_shader_rd, p_render_buffers);
 
 				cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[1].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
-				_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
+				_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[1].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier);
 				RD::get_singleton()->draw_list_end();
 			}
 			RD::get_singleton()->draw_command_end_label();
@@ -1368,10 +1364,10 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
 		RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap");
 		for (int i = 0; i < 6; i++) {
 			Basis local_view = Basis::looking_at(view_normals[i], view_up[i]);
-			RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd);
+			RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_CUBEMAP, sky_shader.default_shader_rd, p_render_buffers);
 
 			cubemap_draw_list = RD::get_singleton()->draw_list_begin(sky->reflection.layers[0].mipmaps[0].framebuffers[i], RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
-			_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, 1, &cm, local_view, p_transform.origin, p_luminance_multiplier);
+			_render_sky(cubemap_draw_list, p_time, sky->reflection.layers[0].mipmaps[0].framebuffers[i], pipeline, material->uniform_set, texture_uniform_set, cm, local_view, p_global_pos, p_luminance_multiplier);
 			RD::get_singleton()->draw_list_end();
 		}
 		RD::get_singleton()->draw_command_end_label();
@@ -1413,13 +1409,11 @@ void SkyRD::update(RID p_env, const Projection &p_projection, const Transform3D
 	}
 }
 
-void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
+void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, double p_time, float p_luminance_multiplier) {
+	ERR_FAIL_COND(p_render_buffers.is_null());
 	RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
 	ERR_FAIL_COND(p_env.is_null());
 
-	ERR_FAIL_COND(p_view_count == 0);
-	ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
-
 	Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
 
 	SkyMaterialData *material = nullptr;
@@ -1452,168 +1446,82 @@ void SkyRD::draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth
 	ERR_FAIL_COND(!material);
 
 	SkyShaderData *shader_data = material->shader_data;
-
 	ERR_FAIL_COND(!shader_data);
 
-	material->set_as_used();
-
-	Basis sky_transform = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_env);
-	sky_transform.invert();
-
-	float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
-
-	// Camera
-	Projection camera;
-	uint32_t view_count = p_view_count;
-	const Projection *projections = p_projections;
-
-	if (custom_fov) {
-		// With custom fov we don't support stereo...
-		float near_plane = p_projections[0].get_z_near();
-		float far_plane = p_projections[0].get_z_far();
-		float aspect = p_projections[0].get_aspect();
-
-		camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
-
-		view_count = 1;
-		projections = &camera;
+	if (!shader_data->uses_quarter_res && !shader_data->uses_half_res) {
+		return;
 	}
 
-	sky_transform = sky_transform * p_transform.basis;
-
-	if (shader_data->uses_quarter_res) {
-		PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
-
-		RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
-
-		Vector<Color> clear_colors;
-		clear_colors.push_back(Color(0.0, 0.0, 0.0));
-
-		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
-		_render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
-		RD::get_singleton()->draw_list_end();
-	}
-
-	if (shader_data->uses_half_res) {
-		PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
-
-		RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
-
-		Vector<Color> clear_colors;
-		clear_colors.push_back(Color(0.0, 0.0, 0.0));
-
-		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
-		_render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
-		RD::get_singleton()->draw_list_end();
-	}
-
-	PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
-
-	RID texture_uniform_set;
-	if (sky) {
-		texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
-	} else {
-		texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
-	}
-
-	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_fb, RD::INITIAL_ACTION_CONTINUE, p_can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, p_can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
-	_render_sky(draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
-	RD::get_singleton()->draw_list_end();
-}
-
-void SkyRD::update_res_buffers(RID p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
-	RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
-	ERR_FAIL_COND(p_env.is_null());
-
-	ERR_FAIL_COND(p_view_count == 0);
-	ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
-
-	Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
-	ERR_FAIL_COND(!sky);
-
-	SkyMaterialData *material = nullptr;
-	RID sky_material;
-
-	sky_material = sky_get_material(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
-
-	if (sky_material.is_valid()) {
-		material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
-		if (!material || !material->shader_data->valid) {
-			material = nullptr;
-		}
-	}
-
-	if (!material) {
-		sky_material = sky_shader.default_material;
-		material = static_cast<SkyMaterialData *>(material_storage->material_get_data(sky_material, RendererRD::MaterialStorage::SHADER_TYPE_SKY));
-	}
-
-	ERR_FAIL_COND(!material);
-
-	SkyShaderData *shader_data = material->shader_data;
-
-	ERR_FAIL_COND(!shader_data);
-
 	material->set_as_used();
 
+	RENDER_TIMESTAMP("Setup Sky Resolution Buffers");
+	RD::get_singleton()->draw_command_begin_label("Setup Sky Resolution Buffers");
+
 	Basis sky_transform = RendererSceneRenderRD::get_singleton()->environment_get_sky_orientation(p_env);
 	sky_transform.invert();
 
 	float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
 
 	// Camera
-	Projection camera;
-	uint32_t view_count = p_view_count;
-	const Projection *projections = p_projections;
+	Projection projection = sky_scene_state.cam_projection;
 
-	if (custom_fov) {
+	if (custom_fov && sky_scene_state.view_count == 1) {
 		// With custom fov we don't support stereo...
-		float near_plane = p_projections[0].get_z_near();
-		float far_plane = p_projections[0].get_z_far();
-		float aspect = p_projections[0].get_aspect();
-
-		camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
+		float near_plane = projection.get_z_near();
+		float far_plane = projection.get_z_far();
+		float aspect = projection.get_aspect();
 
-		view_count = 1;
-		projections = &camera;
+		projection.set_perspective(custom_fov, aspect, near_plane, far_plane);
 	}
 
-	sky_transform = sky_transform * p_transform.basis;
+	sky_transform = sky_transform * sky_scene_state.cam_transform.basis;
 
 	if (shader_data->uses_quarter_res) {
-		PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
+		PipelineCacheRD *pipeline = &shader_data->pipelines[sky_scene_state.view_count > 1 ? SKY_VERSION_QUARTER_RES_MULTIVIEW : SKY_VERSION_QUARTER_RES];
+
+		// Grab texture and framebuffer from cache, create if needed...
+		uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+		Size2i quarter_size = sky->screen_size / 4;
+		RID texture = p_render_buffers->create_texture(RB_SCOPE_SKY, RB_QUARTER_TEXTURE, texture_format, usage_bits, RD::TEXTURE_SAMPLES_1, quarter_size);
+		RID framebuffer = FramebufferCacheRD::get_singleton()->get_cache_multiview(sky_scene_state.view_count, texture);
 
-		RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd);
+		RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_QUARTER_RES, sky_shader.default_shader_rd, p_render_buffers);
 
 		Vector<Color> clear_colors;
 		clear_colors.push_back(Color(0.0, 0.0, 0.0));
 
-		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->quarter_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
-		_render_sky(draw_list, p_time, sky->quarter_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
+		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+		_render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier);
 		RD::get_singleton()->draw_list_end();
 	}
 
 	if (shader_data->uses_half_res) {
-		PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
+		PipelineCacheRD *pipeline = &shader_data->pipelines[sky_scene_state.view_count > 1 ? SKY_VERSION_HALF_RES_MULTIVIEW : SKY_VERSION_HALF_RES];
 
-		RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd);
+		// Grab texture and framebuffer from cache, create if needed...
+		uint32_t usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
+		Size2i half_size = sky->screen_size / 2;
+		RID texture = p_render_buffers->create_texture(RB_SCOPE_SKY, RB_HALF_TEXTURE, texture_format, usage_bits, RD::TEXTURE_SAMPLES_1, half_size);
+		RID framebuffer = FramebufferCacheRD::get_singleton()->get_cache_multiview(sky_scene_state.view_count, texture);
+
+		RID texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_HALF_RES, sky_shader.default_shader_rd, p_render_buffers);
 
 		Vector<Color> clear_colors;
 		clear_colors.push_back(Color(0.0, 0.0, 0.0));
 
-		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(sky->half_res_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
-		_render_sky(draw_list, p_time, sky->half_res_framebuffer, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
+		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
+		_render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier);
 		RD::get_singleton()->draw_list_end();
 	}
+
+	RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
 }
 
-void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier) {
+void SkyRD::draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, RID p_fb, double p_time, float p_luminance_multiplier) {
+	ERR_FAIL_COND(p_render_buffers.is_null());
 	RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
 	ERR_FAIL_COND(p_env.is_null());
 
-	ERR_FAIL_COND(p_view_count == 0);
-	ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS);
-
 	Sky *sky = get_sky(RendererSceneRenderRD::get_singleton()->environment_get_sky(p_env));
 
 	SkyMaterialData *material = nullptr;
@@ -1646,7 +1554,6 @@ void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_vie
 	ERR_FAIL_COND(!material);
 
 	SkyShaderData *shader_data = material->shader_data;
-
 	ERR_FAIL_COND(!shader_data);
 
 	material->set_as_used();
@@ -1657,34 +1564,29 @@ void SkyRD::draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_vie
 	float custom_fov = RendererSceneRenderRD::get_singleton()->environment_get_sky_custom_fov(p_env);
 
 	// Camera
-	Projection camera;
-	uint32_t view_count = p_view_count;
-	const Projection *projections = p_projections;
+	Projection projection = sky_scene_state.cam_projection;
 
-	if (custom_fov) {
+	if (custom_fov && sky_scene_state.view_count == 1) {
 		// With custom fov we don't support stereo...
-		float near_plane = p_projections[0].get_z_near();
-		float far_plane = p_projections[0].get_z_far();
-		float aspect = p_projections[0].get_aspect();
+		float near_plane = projection.get_z_near();
+		float far_plane = projection.get_z_far();
+		float aspect = projection.get_aspect();
 
-		camera.set_perspective(custom_fov, aspect, near_plane, far_plane);
-
-		view_count = 1;
-		projections = &camera;
+		projection.set_perspective(custom_fov, aspect, near_plane, far_plane);
 	}
 
-	sky_transform = sky_transform * p_transform.basis;
+	sky_transform = sky_transform * sky_scene_state.cam_transform.basis;
 
-	PipelineCacheRD *pipeline = &shader_data->pipelines[view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
+	PipelineCacheRD *pipeline = &shader_data->pipelines[sky_scene_state.view_count > 1 ? SKY_VERSION_BACKGROUND_MULTIVIEW : SKY_VERSION_BACKGROUND];
 
 	RID texture_uniform_set;
 	if (sky) {
-		texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd);
+		texture_uniform_set = sky->get_textures(SKY_TEXTURE_SET_BACKGROUND, sky_shader.default_shader_rd, p_render_buffers);
 	} else {
 		texture_uniform_set = sky_scene_state.fog_only_texture_uniform_set;
 	}
 
-	_render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, view_count, projections, sky_transform, p_transform.origin, p_luminance_multiplier);
+	_render_sky(p_draw_list, p_time, p_fb, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier);
 }
 
 void SkyRD::invalidate_sky(Sky *p_sky) {
@@ -1699,9 +1601,11 @@ void SkyRD::update_dirty_skys() {
 	Sky *sky = dirty_sky_list;
 
 	while (sky) {
-		bool texture_set_dirty = false;
 		//update sky configuration if texture is missing
 
+		// TODO See if we can move this into `update_radiance_buffers` and remove our dirty_sky logic.
+		// As this is basically a duplicate of the logic in reflection probes we could move this logic
+		// into RenderSceneBuffersRD and use that from both places.
 		if (sky->radiance.is_null()) {
 			int mipmaps = Image::get_image_required_mipmaps(sky->radiance_size, sky->radiance_size, Image::FORMAT_RGBAH) + 1;
 
@@ -1744,47 +1648,6 @@ void SkyRD::update_dirty_skys() {
 
 				sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format);
 			}
-			texture_set_dirty = true;
-		}
-
-		// Create subpass buffers if they haven't been created already
-		if (sky->half_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->half_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
-			RD::TextureFormat tformat;
-			tformat.format = texture_format;
-			tformat.width = sky->screen_size.x / 2;
-			tformat.height = sky->screen_size.y / 2;
-			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-			tformat.texture_type = RD::TEXTURE_TYPE_2D;
-
-			sky->half_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
-			Vector<RID> texs;
-			texs.push_back(sky->half_res_pass);
-			sky->half_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
-			texture_set_dirty = true;
-		}
-
-		if (sky->quarter_res_pass.is_null() && !RD::get_singleton()->texture_is_valid(sky->quarter_res_pass) && sky->screen_size.x >= 4 && sky->screen_size.y >= 4) {
-			RD::TextureFormat tformat;
-			tformat.format = texture_format;
-			tformat.width = sky->screen_size.x / 4;
-			tformat.height = sky->screen_size.y / 4;
-			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
-			tformat.texture_type = RD::TEXTURE_TYPE_2D;
-
-			sky->quarter_res_pass = RD::get_singleton()->texture_create(tformat, RD::TextureView());
-			Vector<RID> texs;
-			texs.push_back(sky->quarter_res_pass);
-			sky->quarter_res_framebuffer = RD::get_singleton()->framebuffer_create(texs);
-			texture_set_dirty = true;
-		}
-
-		if (texture_set_dirty) {
-			for (int i = 0; i < SKY_TEXTURE_SET_MAX; i++) {
-				if (sky->texture_uniform_sets[i].is_valid() && RD::get_singleton()->uniform_set_is_valid(sky->texture_uniform_sets[i])) {
-					RD::get_singleton()->free(sky->texture_uniform_sets[i]);
-					sky->texture_uniform_sets[i] = RID();
-				}
-			}
 		}
 
 		sky->reflection.dirty = true;

+ 35 - 32
servers/rendering/renderer_rd/environment/sky.h

@@ -99,11 +99,11 @@ private:
 
 	struct SkyPushConstant {
 		float orientation[12]; // 48 - 48
-		float projections[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 80
-		float position[3]; // 12 - 92
-		float time; // 4 - 96
-		float pad[3]; // 12 - 108
-		float luminance_multiplier; // 4 - 112
+		float projection[4]; // 16 - 64
+		float position[3]; // 12 - 76
+		float time; // 4 - 80
+		float pad[3]; // 12 - 92
+		float luminance_multiplier; // 4 - 96
 		// 128 is the max size of a push constant. We can replace "pad" but we can't add any more.
 	};
 
@@ -134,32 +134,39 @@ private:
 		virtual ~SkyShaderData();
 	};
 
-	void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, uint32_t p_view_count, const Projection *p_projections, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier);
+	void _render_sky(RD::DrawListID p_list, float p_time, RID p_fb, PipelineCacheRD *p_pipeline, RID p_uniform_set, RID p_texture_set, const Projection &p_projection, const Basis &p_orientation, const Vector3 &p_position, float p_luminance_multiplier);
 
 public:
 	struct SkySceneState {
 		struct UBO {
-			uint32_t volumetric_fog_enabled; // 4 - 4
-			float volumetric_fog_inv_length; // 4 - 8
-			float volumetric_fog_detail_spread; // 4 - 12
-			float volumetric_fog_sky_affect; // 4 - 16
-
-			uint32_t fog_enabled; // 4 - 20
-			float fog_sky_affect; // 4 - 24
-			float fog_density; // 4 - 28
-			float fog_sun_scatter; // 4 - 32
-
-			float fog_light_color[3]; // 12 - 44
-			float fog_aerial_perspective; // 4 - 48
-
-			float z_far; // 4 - 52
-			uint32_t directional_light_count; // 4 - 56
-			uint32_t pad1; // 4 - 60
-			uint32_t pad2; // 4 - 64
+			float view_inv_projections[RendererSceneRender::MAX_RENDER_VIEWS][16]; // 2 x 64 - 128
+			float view_eye_offsets[RendererSceneRender::MAX_RENDER_VIEWS][4]; // 2 x 16 - 160
+
+			uint32_t volumetric_fog_enabled; // 4 - 164
+			float volumetric_fog_inv_length; // 4 - 168
+			float volumetric_fog_detail_spread; // 4 - 172
+			float volumetric_fog_sky_affect; // 4 - 176
+
+			uint32_t fog_enabled; // 4 - 180
+			float fog_sky_affect; // 4 - 184
+			float fog_density; // 4 - 188
+			float fog_sun_scatter; // 4 - 192
+
+			float fog_light_color[3]; // 12 - 204
+			float fog_aerial_perspective; // 4 - 208
+
+			float z_far; // 4 - 212
+			uint32_t directional_light_count; // 4 - 216
+			uint32_t pad1; // 4 - 220
+			uint32_t pad2; // 4 - 224
 		};
 
 		UBO ubo;
 
+		uint32_t view_count = 1;
+		Transform3D cam_transform;
+		Projection cam_projection;
+
 		SkyDirectionalLightData *directional_lights = nullptr;
 		SkyDirectionalLightData *last_frame_directional_lights = nullptr;
 		uint32_t max_directional_lights;
@@ -238,13 +245,10 @@ public:
 
 	struct Sky {
 		RID radiance;
-		RID half_res_pass;
-		RID half_res_framebuffer;
 		RID quarter_res_pass;
 		RID quarter_res_framebuffer;
 		Size2i screen_size;
 
-		RID texture_uniform_sets[SKY_TEXTURE_SET_MAX];
 		RID uniform_set;
 
 		RID material;
@@ -267,7 +271,7 @@ public:
 
 		void free();
 
-		RID get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd);
+		RID get_textures(SkyTextureSetVersion p_version, RID p_default_shader_rd, Ref<RenderSceneBuffersRD> p_render_buffers);
 		bool set_radiance_size(int p_radiance_size);
 		bool set_mode(RS::SkyMode p_mode);
 		bool set_material(RID p_material);
@@ -291,11 +295,10 @@ public:
 	void set_texture_format(RD::DataFormat p_texture_format);
 	~SkyRD();
 
-	void setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, const Projection &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
-	void update(RID p_env, const Projection &p_projection, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
-	void draw(RID p_env, bool p_can_continue_color, bool p_can_continue_depth, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0); // only called by clustered renderer
-	void update_res_buffers(RID p_env, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
-	void draw(RD::DrawListID p_draw_list, RID p_env, RID p_fb, uint32_t p_view_count, const Projection *p_projections, const Transform3D &p_transform, double p_time, float p_luminance_multiplier = 1.0);
+	void setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const PagedArray<RID> &p_lights, RID p_camera_attributes, uint32_t p_view_count, const Projection *p_view_projections, const Vector3 *p_view_eye_offsets, const Transform3D &p_cam_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
+	void update_radiance_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, const Vector3 &p_global_pos, double p_time, float p_luminance_multiplier = 1.0);
+	void update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, double p_time, float p_luminance_multiplier = 1.0);
+	void draw_sky(RD::DrawListID p_draw_list, Ref<RenderSceneBuffersRD> p_render_buffers, RID p_env, RID p_fb, double p_time, float p_luminance_multiplier = 1.0);
 
 	void invalidate_sky(Sky *p_sky);
 	void update_dirty_skys();

+ 35 - 28
servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp

@@ -1636,7 +1636,21 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
 	bool reverse_cull = p_render_data->scene_data->cam_transform.basis.determinant() < 0;
 	bool using_ssil = p_render_data->environment.is_valid() && environment_get_ssil_enabled(p_render_data->environment);
 
-	if (rb.is_valid()) {
+	if (p_render_data->reflection_probe.is_valid()) {
+		uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+		screen_size.x = resolution;
+		screen_size.y = resolution;
+
+		color_framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+		color_only_framebuffer = color_framebuffer;
+		depth_framebuffer = light_storage->reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+
+		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
+		}
+
+		reverse_cull = true; // for some reason our views are inverted
+	} else if (rb.is_valid()) {
 		screen_size = rb->get_internal_size();
 
 		if (rb->get_use_taa() || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
@@ -1688,20 +1702,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
 
 		color_framebuffer = rb_data->get_color_pass_fb(color_pass_flags);
 		color_only_framebuffer = rb_data->get_color_only_fb();
-	} else if (p_render_data->reflection_probe.is_valid()) {
-		uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
-		screen_size.x = resolution;
-		screen_size.y = resolution;
-
-		color_framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
-		color_only_framebuffer = color_framebuffer;
-		depth_framebuffer = light_storage->reflection_probe_instance_get_depth_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
-
-		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
-		}
-
-		reverse_cull = true; // for some reason our views are inverted
 	} else {
 		ERR_FAIL(); //bug?
 	}
@@ -1790,29 +1790,40 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
 			default: {
 			}
 		}
+
 		// setup sky if used for ambient, reflections, or background
 		if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
 			RENDER_TIMESTAMP("Setup Sky");
 			RD::get_singleton()->draw_command_begin_label("Setup Sky");
-			Projection projection = p_render_data->scene_data->cam_projection;
+
+			// Setup our sky render information for this frame/viewport
 			if (p_render_data->reflection_probe.is_valid()) {
+				Vector3 eye_offset;
 				Projection correction;
 				correction.set_depth_correction(true);
-				projection = correction * p_render_data->scene_data->cam_projection;
-			}
+				Projection projection = correction * p_render_data->scene_data->cam_projection;
 
-			sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this);
+				sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, screen_size, this);
+			} else {
+				sky.setup_sky(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, screen_size, this);
+			}
 
 			sky_energy_multiplier *= bg_energy_multiplier;
 
 			RID sky_rid = environment_get_sky(p_render_data->environment);
 			if (sky_rid.is_valid()) {
-				sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
+				sky.update_radiance_buffers(rb, p_render_data->environment, p_render_data->scene_data->cam_transform.origin, time, sky_energy_multiplier);
 				radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
 			} else {
 				// do not try to draw sky if invalid
 				draw_sky = false;
 			}
+
+			if (draw_sky || draw_sky_fog_only) {
+				// update sky half/quarter res buffers (if required)
+				sky.update_res_buffers(rb, p_render_data->environment, time, sky_energy_multiplier);
+			}
+
 			RD::get_singleton()->draw_command_end_label();
 		}
 	} else {
@@ -1962,15 +1973,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
 		RENDER_TIMESTAMP("Render Sky");
 
 		RD::get_singleton()->draw_command_begin_label("Draw Sky");
+		RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_CONTINUE, can_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, can_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
 
-		if (p_render_data->reflection_probe.is_valid()) {
-			Projection correction;
-			correction.set_depth_correction(true);
-			Projection projection = correction * p_render_data->scene_data->cam_projection;
-			sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
-		} else {
-			sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
-		}
+		sky.draw_sky(draw_list, rb, p_render_data->environment, color_only_framebuffer, time, sky_energy_multiplier);
+
+		RD::get_singleton()->draw_list_end();
 		RD::get_singleton()->draw_command_end_label();
 	}
 

+ 43 - 52
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp

@@ -361,7 +361,9 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
 	Ref<RenderSceneBuffersRD> rb;
 	if (p_render_data && p_render_data->render_buffers.is_valid()) {
 		rb = p_render_data->render_buffers;
-		rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
+		if (rb->has_custom_data(RB_SCOPE_MOBILE)) {
+			rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
+		}
 	}
 
 	// default render buffer and scene state uniform set
@@ -640,7 +642,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 	Ref<RenderBufferDataForwardMobile> rb_data;
 	if (p_render_data->render_buffers.is_valid()) {
 		rb = p_render_data->render_buffers;
-		rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
+		if (rb->has_custom_data(RB_SCOPE_MOBILE)) {
+			rb_data = rb->get_custom_data(RB_SCOPE_MOBILE);
+		}
 	}
 
 	RENDER_TIMESTAMP("Prepare 3D Scene");
@@ -689,7 +693,21 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 		p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_render_data->instances->size();
 	}
 
-	if (rb_data.is_valid()) {
+	if (p_render_data->reflection_probe.is_valid()) {
+		uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
+		screen_size.x = resolution;
+		screen_size.y = resolution;
+
+		framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
+
+		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
+		}
+
+		reverse_cull = true;
+		using_subpass_transparent = true; // we ignore our screen/depth texture here
+		using_subpass_post_process = false; // not applicable at all for reflection probes.
+	} else if (rb_data.is_valid()) {
 		// setup rendering to render buffer
 		screen_size = p_render_data->render_buffers->get_internal_size();
 
@@ -717,20 +735,6 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 			// only opaque and sky as subpasses
 			framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_TWO_SUBPASSES);
 		}
-	} else if (p_render_data->reflection_probe.is_valid()) {
-		uint32_t resolution = light_storage->reflection_probe_instance_get_resolution(p_render_data->reflection_probe);
-		screen_size.x = resolution;
-		screen_size.y = resolution;
-
-		framebuffer = light_storage->reflection_probe_instance_get_framebuffer(p_render_data->reflection_probe, p_render_data->reflection_probe_pass);
-
-		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
-		}
-
-		reverse_cull = true;
-		using_subpass_transparent = true; // we ignore our screen/depth texture here
-		using_subpass_post_process = false; // not applicable at all for reflection probes.
 	} else {
 		ERR_FAIL(); //bug?
 	}
@@ -796,7 +800,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 				draw_sky = true;
 			} break;
 			case RS::ENV_BG_CANVAS: {
-				if (rb.is_valid()) {
+				if (rb_data.is_valid()) {
 					RID dest_framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
 					RID texture = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(rb->get_render_target());
 					copy_effects->copy_to_fb_rect(texture, dest_framebuffer, Rect2i(), false, false, false, false, RID(), false, false, true);
@@ -811,55 +815,45 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 			default: {
 			}
 		}
+
 		// setup sky if used for ambient, reflections, or background
 		if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
 			RENDER_TIMESTAMP("Setup Sky");
 			RD::get_singleton()->draw_command_begin_label("Setup Sky");
-			Projection projection = p_render_data->scene_data->cam_projection;
+
+			// Setup our sky render information for this frame/viewport
 			if (p_render_data->reflection_probe.is_valid()) {
+				Vector3 eye_offset;
 				Projection correction;
 				correction.set_depth_correction(true);
-				projection = correction * p_render_data->scene_data->cam_projection;
-			}
+				Projection projection = correction * p_render_data->scene_data->cam_projection;
 
-			sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this);
+				sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, 1, &projection, &eye_offset, p_render_data->scene_data->cam_transform, screen_size, this);
+			} else {
+				sky.setup_sky(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, screen_size, this);
+			}
 
 			sky_energy_multiplier *= bg_energy_multiplier;
 
 			RID sky_rid = environment_get_sky(p_render_data->environment);
 			if (sky_rid.is_valid()) {
-				sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
+				sky.update_radiance_buffers(rb, p_render_data->environment, p_render_data->scene_data->cam_transform.origin, time, sky_energy_multiplier);
 				radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
 			} else {
 				// do not try to draw sky if invalid
 				draw_sky = false;
 			}
+
+			if (draw_sky || draw_sky_fog_only) {
+				// update sky half/quarter res buffers (if required)
+				sky.update_res_buffers(rb, p_render_data->environment, time, sky_energy_multiplier);
+			}
 			RD::get_singleton()->draw_command_end_label(); // Setup Sky
 		}
 	} else {
 		clear_color = p_default_bg_color;
 	}
 
-	// update sky buffers (if required)
-	if (draw_sky || draw_sky_fog_only) {
-		// !BAS! @TODO See if we can limit doing some things double and maybe even move this into _pre_opaque_render
-		// and change Forward Clustered in the same way as we have here (but without using subpasses)
-		RENDER_TIMESTAMP("Setup Sky Resolution Buffers");
-
-		RD::get_singleton()->draw_command_begin_label("Setup Sky Resolution Buffers");
-
-		if (p_render_data->reflection_probe.is_valid()) {
-			Projection correction;
-			correction.set_depth_correction(true);
-			Projection projection = correction * p_render_data->scene_data->cam_projection;
-			sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
-		} else {
-			sky.update_res_buffers(p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
-		}
-
-		RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
-	}
-
 	_pre_opaque_render(p_render_data);
 
 	uint32_t spec_constant_base_flags = 0;
@@ -944,16 +938,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 		if (draw_sky || draw_sky_fog_only) {
 			RD::get_singleton()->draw_command_begin_label("Draw Sky Subpass");
 
+			// Note, sky.setup should have been called up above and setup stuff we need.
+
 			RD::DrawListID draw_list = RD::get_singleton()->draw_list_switch_to_next_pass();
 
-			if (p_render_data->reflection_probe.is_valid()) {
-				Projection correction;
-				correction.set_depth_correction(true);
-				Projection projection = correction * p_render_data->scene_data->cam_projection;
-				sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
-			} else {
-				sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
-			}
+			sky.draw_sky(draw_list, rb, p_render_data->environment, framebuffer, time, sky_energy_multiplier);
 
 			RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
 
@@ -1021,7 +1010,9 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
 		} else {
 			RENDER_TIMESTAMP("Render Transparent");
 
-			framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
+			if (rb_data.is_valid()) {
+				framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_ONE_PASS);
+			}
 
 			// this may be needed if we re-introduced steps that change info, not sure which do so in the previous implementation
 			// _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);

+ 13 - 3
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

@@ -909,10 +909,20 @@ bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const {
 }
 
 void RendererSceneRenderRD::_update_vrs(Ref<RenderSceneBuffersRD> p_render_buffers) {
-	if (p_render_buffers.is_valid() && vrs) {
+	if (p_render_buffers.is_null()) {
+		return;
+	}
+
+	RID render_target = p_render_buffers->get_render_target();
+	if (render_target.is_null()) {
+		// must be rendering reflection probes
+		return;
+	}
+
+	if (vrs) {
 		RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
 
-		RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(p_render_buffers->get_render_target());
+		RS::ViewportVRSMode vrs_mode = texture_storage->render_target_get_vrs_mode(render_target);
 		if (vrs_mode != RS::VIEWPORT_VRS_DISABLED) {
 			RID vrs_texture = p_render_buffers->get_texture(RB_SCOPE_VRS, RB_TEXTURE);
 
@@ -1064,7 +1074,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
 	}
 
 	Color clear_color;
-	if (p_render_buffers.is_valid()) {
+	if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) {
 		clear_color = texture_storage->render_target_get_clear_request_color(rb->get_render_target());
 	} else {
 		clear_color = RSG::texture_storage->get_default_clear_color();

+ 44 - 17
servers/rendering/renderer_rd/shaders/environment/sky.glsl

@@ -14,7 +14,7 @@ layout(location = 0) out vec2 uv_interp;
 
 layout(push_constant, std430) uniform Params {
 	mat3 orientation;
-	vec4 projections[MAX_VIEWS];
+	vec4 projection; // only applicable if not multiview
 	vec3 position;
 	float time;
 	vec3 pad;
@@ -54,7 +54,7 @@ layout(location = 0) in vec2 uv_interp;
 
 layout(push_constant, std430) uniform Params {
 	mat3 orientation;
-	vec4 projections[MAX_VIEWS];
+	vec4 projection; // only applicable if not multiview
 	vec3 position;
 	float time;
 	vec3 pad;
@@ -82,7 +82,10 @@ layout(set = 0, binding = 1, std430) restrict readonly buffer GlobalShaderUnifor
 }
 global_shader_uniforms;
 
-layout(set = 0, binding = 2, std140) uniform SceneData {
+layout(set = 0, binding = 2, std140) uniform SkySceneData {
+	mat4 view_inv_projections[2];
+	vec4 view_eye_offsets[2];
+
 	bool volumetric_fog_enabled; // 4 - 4
 	float volumetric_fog_inv_length; // 4 - 8
 	float volumetric_fog_detail_spread; // 4 - 12
@@ -101,7 +104,7 @@ layout(set = 0, binding = 2, std140) uniform SceneData {
 	uint pad1; // 4 - 60
 	uint pad2; // 4 - 64
 }
-scene_data;
+sky_scene_data;
 
 struct DirectionalLightData {
 	vec4 direction_energy;
@@ -124,6 +127,9 @@ layout(set = 2, binding = 0) uniform textureCube radiance;
 #ifdef USE_CUBEMAP_PASS
 layout(set = 2, binding = 1) uniform textureCube half_res;
 layout(set = 2, binding = 2) uniform textureCube quarter_res;
+#elif defined(USE_MULTIVIEW)
+layout(set = 2, binding = 1) uniform texture2DArray half_res;
+layout(set = 2, binding = 2) uniform texture2DArray quarter_res;
 #else
 layout(set = 2, binding = 1) uniform texture2D half_res;
 layout(set = 2, binding = 2) uniform texture2D quarter_res;
@@ -169,15 +175,15 @@ vec4 volumetric_fog_process(vec2 screen_uv) {
 }
 
 vec4 fog_process(vec3 view, vec3 sky_color) {
-	vec3 fog_color = mix(scene_data.fog_light_color, sky_color, scene_data.fog_aerial_perspective);
+	vec3 fog_color = mix(sky_scene_data.fog_light_color, sky_color, sky_scene_data.fog_aerial_perspective);
 
-	if (scene_data.fog_sun_scatter > 0.001) {
+	if (sky_scene_data.fog_sun_scatter > 0.001) {
 		vec4 sun_scatter = vec4(0.0);
 		float sun_total = 0.0;
-		for (uint i = 0; i < scene_data.directional_light_count; i++) {
+		for (uint i = 0; i < sky_scene_data.directional_light_count; i++) {
 			vec3 light_color = directional_lights.data[i].color_size.xyz * directional_lights.data[i].direction_energy.w;
 			float light_amount = pow(max(dot(view, directional_lights.data[i].direction_energy.xyz), 0.0), 8.0);
-			fog_color += light_color * light_amount * scene_data.fog_sun_scatter;
+			fog_color += light_color * light_amount * sky_scene_data.fog_sun_scatter;
 		}
 	}
 
@@ -186,9 +192,17 @@ vec4 fog_process(vec3 view, vec3 sky_color) {
 
 void main() {
 	vec3 cube_normal;
+#ifdef USE_MULTIVIEW
+	// In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject.
+	vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 1.0, 1.0);
+	vec4 unprojected = sky_scene_data.view_inv_projections[ViewIndex] * unproject;
+	cube_normal = unprojected.xyz / unprojected.w;
+	cube_normal += sky_scene_data.view_eye_offsets[ViewIndex].xyz;
+#else
 	cube_normal.z = -1.0;
-	cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projections[ViewIndex].x)) / params.projections[ViewIndex].y;
-	cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projections[ViewIndex].z)) / params.projections[ViewIndex].w;
+	cube_normal.x = (cube_normal.z * (-uv_interp.x - params.projection.x)) / params.projection.y;
+	cube_normal.y = -(cube_normal.z * (-uv_interp.y - params.projection.z)) / params.projection.w;
+#endif
 	cube_normal = mat3(params.orientation) * cube_normal;
 	cube_normal = normalize(cube_normal);
 
@@ -209,20 +223,33 @@ void main() {
 	vec4 custom_fog = vec4(0.0);
 
 #ifdef USE_CUBEMAP_PASS
+
 #ifdef USES_HALF_RES_COLOR
 	half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) / params.luminance_multiplier;
 #endif
 #ifdef USES_QUARTER_RES_COLOR
 	quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), cube_normal) / params.luminance_multiplier;
 #endif
+
 #else
+
 #ifdef USES_HALF_RES_COLOR
+#ifdef USE_MULTIVIEW
+	half_res_color = textureLod(sampler2DArray(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0) / params.luminance_multiplier;
+#else
 	half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) / params.luminance_multiplier;
-#endif
+#endif // USE_MULTIVIEW
+#endif // USES_HALF_RES_COLOR
+
 #ifdef USES_QUARTER_RES_COLOR
+#ifdef USE_MULTIVIEW
+	quarter_res_color = textureLod(sampler2DArray(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), vec3(uv, ViewIndex), 0.0) / params.luminance_multiplier;
+#else
 	quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) / params.luminance_multiplier;
-#endif
-#endif
+#endif // USE_MULTIVIEW
+#endif // USES_QUARTER_RES_COLOR
+
+#endif //USE_CUBEMAP_PASS
 
 	{
 
@@ -236,14 +263,14 @@ void main() {
 #if !defined(DISABLE_FOG) && !defined(USE_CUBEMAP_PASS)
 
 	// Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky.
-	if (scene_data.fog_enabled) {
+	if (sky_scene_data.fog_enabled) {
 		vec4 fog = fog_process(cube_normal, frag_color.rgb);
-		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * scene_data.fog_sky_affect);
+		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * sky_scene_data.fog_sky_affect);
 	}
 
-	if (scene_data.volumetric_fog_enabled) {
+	if (sky_scene_data.volumetric_fog_enabled) {
 		vec4 fog = volumetric_fog_process(uv);
-		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * scene_data.volumetric_fog_sky_affect);
+		frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a * sky_scene_data.volumetric_fog_sky_affect);
 	}
 
 	if (custom_fog.a > 0.0) {

+ 21 - 0
servers/rendering/renderer_rd/storage_rd/light_storage.cpp

@@ -1315,6 +1315,10 @@ void LightStorage::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_s
 
 		ra->reflections.clear();
 	}
+
+	if (ra->render_buffers.is_valid()) {
+		ra->render_buffers->cleanup();
+	}
 }
 
 int LightStorage::reflection_atlas_get_size(RID p_ref_atlas) const {
@@ -1360,6 +1364,9 @@ void LightStorage::reflection_probe_release_atlas_index(RID p_instance) {
 	ERR_FAIL_COND(!atlas);
 	ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size());
 	atlas->reflections.write[rpi->atlas_index].owner = RID();
+
+	// TODO investigate if this is enough? shouldn't we be freeing our textures and framebuffers?
+
 	rpi->atlas_index = -1;
 	rpi->atlas = RID();
 }
@@ -1398,6 +1405,10 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
 	ERR_FAIL_COND_V(!rpi, false);
 
+	if (atlas->render_buffers.is_null()) {
+		atlas->render_buffers.instantiate();
+	}
+
 	RD::get_singleton()->draw_command_begin_label("Reflection probe render");
 
 	if (LightStorage::get_singleton()->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
@@ -1455,6 +1466,9 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
 		Vector<RID> fb;
 		fb.push_back(atlas->depth_buffer);
 		atlas->depth_fb = RD::get_singleton()->framebuffer_create(fb);
+
+		atlas->render_buffers->cleanup();
+		atlas->render_buffers->configure_for_reflections(Size2i(atlas->size, atlas->size));
 	}
 
 	if (rpi->atlas_index == -1) {
@@ -1494,6 +1508,13 @@ bool LightStorage::reflection_probe_instance_begin_render(RID p_instance, RID p_
 	return true;
 }
 
+Ref<RenderSceneBuffers> LightStorage::reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) {
+	ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas);
+	ERR_FAIL_COND_V(!atlas, Ref<RenderSceneBuffersRD>());
+
+	return atlas->render_buffers;
+}
+
 bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) {
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance);
 	ERR_FAIL_COND_V(!rpi, false);

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

@@ -38,6 +38,7 @@
 #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/render_scene_buffers_rd.h"
 #include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
 #include "servers/rendering/storage/light_storage.h"
 #include "servers/rendering/storage/utilities.h"
@@ -256,6 +257,8 @@ private:
 
 		Vector<Reflection> reflections;
 
+		Ref<RenderSceneBuffersRD> render_buffers; // Further render buffers used.
+
 		ClusterBuilderRD *cluster_builder = nullptr; // only used if cluster builder is supported by the renderer.
 	};
 
@@ -846,6 +849,7 @@ public:
 	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 Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(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);

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

@@ -207,6 +207,21 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
 	}
 }
 
+void RenderSceneBuffersRD::configure_for_reflections(const Size2i p_reflection_size) {
+	// For now our render buffers for reflections are only used for effects/environment (Sky/Fog/Etc)
+	// Possibly at some point move our entire reflection atlas buffer management into this class
+
+	target_size = p_reflection_size;
+	internal_size = p_reflection_size;
+	render_target = RID();
+	fsr_sharpness = 0.0;
+	msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
+	screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
+	use_taa = false;
+	use_debanding = false;
+	view_count = 1;
+}
+
 void RenderSceneBuffersRD::set_fsr_sharpness(float p_fsr_sharpness) {
 	fsr_sharpness = p_fsr_sharpness;
 }
@@ -483,6 +498,10 @@ void RenderSceneBuffersRD::set_custom_data(const StringName &p_name, Ref<RenderB
 }
 
 Ref<RenderBufferCustomDataRD> RenderSceneBuffersRD::get_custom_data(const StringName &p_name) const {
+	if (!data_buffers.has(p_name)) {
+		print_line("test");
+	}
+
 	ERR_FAIL_COND_V(!data_buffers.has(p_name), Ref<RenderBufferCustomDataRD>());
 
 	Ref<RenderBufferCustomDataRD> ret = data_buffers[p_name];

+ 1 - 0
servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h

@@ -140,6 +140,7 @@ public:
 
 	void cleanup();
 	virtual void 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) override;
+	void configure_for_reflections(const Size2i p_reflection_size);
 	virtual void set_fsr_sharpness(float p_fsr_sharpness) override;
 	virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override;
 	virtual void set_use_debanding(bool p_use_debanding) override;

+ 6 - 4
servers/rendering/renderer_scene_cull.cpp

@@ -2945,7 +2945,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
 
 	scene_render->set_scene_pass(render_pass);
 
-	if (p_render_buffers.is_valid()) {
+	if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) {
 		//no rendering code here, this is only to set up what needs to be done, request regions, etc.
 		scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not)
 	}
@@ -3027,7 +3027,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
 	{ //sdfgi
 		cull.sdfgi.region_count = 0;
 
-		if (p_render_buffers.is_valid()) {
+		if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) {
 			cull.sdfgi.cascade_light_count = 0;
 
 			uint32_t prev_cascade = 0xFFFFFFFF;
@@ -3229,6 +3229,8 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
 	//render SDFGI
 
 	{
+		// Q: Should this whole block be skipped if we're rendering our reflection probe?
+
 		sdfgi_update_data.update_static = false;
 
 		if (cull.sdfgi.region_count > 0) {
@@ -3254,7 +3256,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
 			}
 		}
 
-		if (p_render_buffers.is_valid()) {
+		if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) {
 			sdfgi_update_data.directional_lights = &directional_lights;
 			sdfgi_update_data.positional_light_instances = scenario->dynamic_lights.ptr();
 			sdfgi_update_data.positional_light_count = scenario->dynamic_lights.size();
@@ -3407,7 +3409,7 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int
 		RendererSceneRender::CameraData camera_data;
 		camera_data.set_camera(xform, cm, false, false);
 
-		Ref<RenderSceneBuffers> render_buffers;
+		Ref<RenderSceneBuffers> render_buffers = RSG::light_storage->reflection_probe_atlas_get_render_buffers(scenario->reflection_atlas);
 		_render_scene(&camera_data, render_buffers, environment, RID(), RSG::light_storage->reflection_probe_get_cull_mask(p_instance->base), p_instance->scenario->self, RID(), shadow_atlas, reflection_probe->instance, p_step, mesh_lod_threshold, use_shadows);
 
 	} else {

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

@@ -31,6 +31,7 @@
 #ifndef LIGHT_STORAGE_H
 #define LIGHT_STORAGE_H
 
+#include "render_scene_buffers.h"
 #include "servers/rendering_server.h"
 
 class RendererLightStorage {
@@ -142,6 +143,7 @@ public:
 	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 Ref<RenderSceneBuffers> reflection_probe_atlas_get_render_buffers(RID p_reflection_atlas) = 0;
 	virtual bool reflection_probe_instance_postprocess_step(RID p_instance) = 0;
 
 	/* LIGHTMAP  */