Browse Source

Porting cubemap compute shaders to raster for the mobile renderer

Bastiaan Olij 4 years ago
parent
commit
c76426527b

+ 159 - 31
servers/rendering/renderer_rd/effects_rd.cpp

@@ -37,6 +37,10 @@
 #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
 #include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
 #include "thirdparty/misc/cubemap_coeffs.h"
 #include "thirdparty/misc/cubemap_coeffs.h"
 
 
+bool EffectsRD::get_prefer_raster_effects() {
+	return prefer_raster_effects;
+}
+
 static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
 static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
 	for (int i = 0; i < 4; i++) {
 	for (int i = 0; i < 4; i++) {
 		for (int j = 0; j < 4; j++) {
 		for (int j = 0; j < 4; j++) {
@@ -454,7 +458,7 @@ void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const
 }
 }
 
 
 void EffectsRD::gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
 void EffectsRD::gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) {
-	ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the fragment version of the gaussian glow with the clustered renderer.");
+	ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer.");
 
 
 	memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
 	memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant));
 
 
@@ -832,7 +836,7 @@ void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_
 }
 }
 
 
 void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
 void EffectsRD::luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
-	ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use fragment version of luminance reduction with the clustered renderer.");
+	ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster version of luminance reduction with the clustered renderer.");
 	ERR_FAIL_COND_MSG(p_reduce.size() != p_fb.size(), "Incorrect frame buffer account for luminance reduction.");
 	ERR_FAIL_COND_MSG(p_reduce.size() != p_fb.size(), "Incorrect frame buffer account for luminance reduction.");
 
 
 	luminance_reduce_raster.push_constant.max_luminance = p_max_luminance;
 	luminance_reduce_raster.push_constant.max_luminance = p_max_luminance;
@@ -1447,7 +1451,9 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size
 	RD::get_singleton()->compute_list_end();
 	RD::get_singleton()->compute_list_end();
 }
 }
 
 
-void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+	ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer.");
+
 	memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
 	memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
 
 
 	roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
 	roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
@@ -1457,10 +1463,10 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffe
 	roughness.push_constant.face_size = p_size;
 	roughness.push_constant.face_size = p_size;
 
 
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipeline);
+	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline);
 
 
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
-	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_framebuffer), 1);
+	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1);
 
 
 	RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
 	RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
 
 
@@ -1472,11 +1478,37 @@ void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffe
 	RD::get_singleton()->compute_list_end();
 	RD::get_singleton()->compute_list_end();
 }
 }
 
 
+void EffectsRD::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+	ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer.");
+	ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time.");
+
+	memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
+
+	roughness.push_constant.face_id = p_face_id;
+	roughness.push_constant.roughness = p_roughness;
+	roughness.push_constant.sample_count = p_sample_count;
+	roughness.push_constant.use_direct_write = p_roughness == 0.0;
+	roughness.push_constant.face_size = p_size;
+
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
+	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+	RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+
+	RD::get_singleton()->draw_list_draw(draw_list, true);
+	RD::get_singleton()->draw_list_end();
+}
+
 void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
 void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
+	ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer.");
+
 	cubemap_downsampler.push_constant.face_size = p_size.x;
 	cubemap_downsampler.push_constant.face_size = p_size.x;
+	cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call
 
 
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.pipeline);
+	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1);
 
 
@@ -1490,7 +1522,27 @@ void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, con
 	RD::get_singleton()->compute_list_end();
 	RD::get_singleton()->compute_list_end();
 }
 }
 
 
+void EffectsRD::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) {
+	ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer.");
+	ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time.");
+
+	cubemap_downsampler.push_constant.face_size = p_size.x;
+	cubemap_downsampler.push_constant.face_id = p_face_id;
+
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0);
+	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+	RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
+
+	RD::get_singleton()->draw_list_draw(draw_list, true);
+	RD::get_singleton()->draw_list_end();
+}
+
 void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {
 void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {
+	ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer.");
+
 	Vector<RD::Uniform> uniforms;
 	Vector<RD::Uniform> uniforms;
 	for (int i = 0; i < p_dest_cubemap.size(); i++) {
 	for (int i = 0; i < p_dest_cubemap.size(); i++) {
 		RD::Uniform u;
 		RD::Uniform u;
@@ -1502,12 +1554,12 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap,
 	if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
 	if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
 		RD::get_singleton()->free(filter.image_uniform_set);
 		RD::get_singleton()->free(filter.image_uniform_set);
 	}
 	}
-	filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, 0), 2);
+	filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, 0), 2);
 
 
 	int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY;
 	int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY;
 	pipeline = filter.use_high_quality ? pipeline : pipeline + 1;
 	pipeline = filter.use_high_quality ? pipeline : pipeline + 1;
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
 	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
-	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.pipelines[pipeline]);
+	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[pipeline]);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
 	RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
@@ -1519,6 +1571,29 @@ void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap,
 	RD::get_singleton()->compute_list_end();
 	RD::get_singleton()->compute_list_end();
 }
 }
 
 
+void EffectsRD::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) {
+	ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer.");
+	ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time.");
+
+	// TODO implement!
+	CubemapFilterRasterPushConstant push_constant;
+	push_constant.mip_level = p_mip_level;
+	push_constant.face_id = p_face_id;
+
+	CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY;
+
+	RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+	RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0);
+	RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1);
+	RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
+
+	RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant));
+
+	RD::get_singleton()->draw_list_draw(draw_list, true);
+	RD::get_singleton()->draw_list_end();
+}
+
 void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
 void EffectsRD::resolve_gi(RID p_source_depth, RID p_source_normal_roughness, RID p_source_voxel_gi, RID p_dest_depth, RID p_dest_normal_roughness, RID p_dest_voxel_gi, Vector2i p_screen_size, int p_samples, uint32_t p_barrier) {
 	ResolvePushConstant push_constant;
 	ResolvePushConstant push_constant;
 	push_constant.screen_size[0] = p_screen_size.x;
 	push_constant.screen_size[0] = p_screen_size.x;
@@ -1713,11 +1788,22 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
 		// Initialize roughness
 		// Initialize roughness
 		Vector<String> cubemap_roughness_modes;
 		Vector<String> cubemap_roughness_modes;
 		cubemap_roughness_modes.push_back("");
 		cubemap_roughness_modes.push_back("");
-		roughness.shader.initialize(cubemap_roughness_modes);
 
 
-		roughness.shader_version = roughness.shader.version_create();
+		if (prefer_raster_effects) {
+			roughness.raster_shader.initialize(cubemap_roughness_modes);
+
+			roughness.shader_version = roughness.raster_shader.version_create();
+
+			roughness.raster_pipeline.setup(roughness.raster_shader.version_get_shader(roughness.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+
+		} else {
+			roughness.compute_shader.initialize(cubemap_roughness_modes);
+
+			roughness.shader_version = roughness.compute_shader.version_create();
 
 
-		roughness.pipeline = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, 0));
+			roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0));
+			roughness.raster_pipeline.clear();
+		}
 	}
 	}
 
 
 	{
 	{
@@ -1983,11 +2069,21 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
 		//Initialize cubemap downsampler
 		//Initialize cubemap downsampler
 		Vector<String> cubemap_downsampler_modes;
 		Vector<String> cubemap_downsampler_modes;
 		cubemap_downsampler_modes.push_back("");
 		cubemap_downsampler_modes.push_back("");
-		cubemap_downsampler.shader.initialize(cubemap_downsampler_modes);
 
 
-		cubemap_downsampler.shader_version = cubemap_downsampler.shader.version_create();
+		if (prefer_raster_effects) {
+			cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes);
+
+			cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create();
+
+			cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+		} else {
+			cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes);
 
 
-		cubemap_downsampler.pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.shader.version_get_shader(cubemap_downsampler.shader_version, 0));
+			cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create();
+
+			cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0));
+			cubemap_downsampler.raster_pipeline.clear();
+		}
 	}
 	}
 
 
 	{
 	{
@@ -1999,12 +2095,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
 		cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n");
 		cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n");
 		cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n");
 		cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n");
 		cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n");
 		cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n");
-		filter.shader.initialize(cubemap_filter_modes);
-		filter.shader_version = filter.shader.version_create();
-
-		for (int i = 0; i < FILTER_MODE_MAX; i++) {
-			filter.pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.shader.version_get_shader(filter.shader_version, i));
-		}
 
 
 		if (filter.use_high_quality) {
 		if (filter.use_high_quality) {
 			filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs));
 			filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs));
@@ -2014,15 +2104,50 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
 			RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]);
 			RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]);
 		}
 		}
 
 
-		Vector<RD::Uniform> uniforms;
-		{
-			RD::Uniform u;
-			u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
-			u.binding = 0;
-			u.ids.push_back(filter.coefficient_buffer);
-			uniforms.push_back(u);
+		if (prefer_raster_effects) {
+			filter.raster_shader.initialize(cubemap_filter_modes);
+			filter.shader_version = filter.raster_shader.version_create();
+
+			// array variants are not supported in raster
+			filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false);
+			filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false);
+
+			for (int i = 0; i < FILTER_MODE_MAX; i++) {
+				if (filter.raster_shader.is_variant_enabled(i)) {
+					filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+				} else {
+					filter.raster_pipelines[i].clear();
+				}
+			}
+
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.binding = 0;
+				u.ids.push_back(filter.coefficient_buffer);
+				uniforms.push_back(u);
+			}
+			filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.raster_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
+		} else {
+			filter.compute_shader.initialize(cubemap_filter_modes);
+			filter.shader_version = filter.compute_shader.version_create();
+
+			for (int i = 0; i < FILTER_MODE_MAX; i++) {
+				filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i));
+				filter.raster_pipelines[i].clear();
+			}
+
+			Vector<RD::Uniform> uniforms;
+			{
+				RD::Uniform u;
+				u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+				u.binding = 0;
+				u.ids.push_back(filter.coefficient_buffer);
+				uniforms.push_back(u);
+			}
+			filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
 		}
 		}
-		filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
 	}
 	}
 
 
 	{
 	{
@@ -2199,17 +2324,20 @@ EffectsRD::~EffectsRD() {
 	if (prefer_raster_effects) {
 	if (prefer_raster_effects) {
 		blur_raster.shader.version_free(blur_raster.shader_version);
 		blur_raster.shader.version_free(blur_raster.shader_version);
 		luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
 		luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
+		roughness.raster_shader.version_free(roughness.shader_version);
+		cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
+		filter.raster_shader.version_free(filter.shader_version);
 	} else {
 	} else {
 		bokeh.shader.version_free(bokeh.shader_version);
 		bokeh.shader.version_free(bokeh.shader_version);
 		luminance_reduce.shader.version_free(luminance_reduce.shader_version);
 		luminance_reduce.shader.version_free(luminance_reduce.shader_version);
+		roughness.compute_shader.version_free(roughness.shader_version);
+		cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version);
+		filter.compute_shader.version_free(filter.shader_version);
 	}
 	}
 	copy.shader.version_free(copy.shader_version);
 	copy.shader.version_free(copy.shader_version);
 	copy_to_fb.shader.version_free(copy_to_fb.shader_version);
 	copy_to_fb.shader.version_free(copy_to_fb.shader_version);
 	cube_to_dp.shader.version_free(cube_to_dp.shader_version);
 	cube_to_dp.shader.version_free(cube_to_dp.shader_version);
-	cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version);
-	filter.shader.version_free(filter.shader_version);
 	resolve.shader.version_free(resolve.shader_version);
 	resolve.shader.version_free(resolve.shader_version);
-	roughness.shader.version_free(roughness.shader_version);
 	roughness_limiter.shader.version_free(roughness_limiter.shader_version);
 	roughness_limiter.shader.version_free(roughness_limiter.shader_version);
 	sort.shader.version_free(sort.shader_version);
 	sort.shader.version_free(sort.shader_version);
 	specular_merge.shader.version_free(specular_merge.shader_version);
 	specular_merge.shader.version_free(specular_merge.shader_version);

+ 33 - 11
servers/rendering/renderer_rd/effects_rd.h

@@ -39,8 +39,11 @@
 #include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/copy_to_fb.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h"
 #include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h"
@@ -62,6 +65,9 @@
 #include "servers/rendering_server.h"
 #include "servers/rendering_server.h"
 
 
 class EffectsRD {
 class EffectsRD {
+private:
+	bool prefer_raster_effects;
+
 	enum BlurRasterMode {
 	enum BlurRasterMode {
 		BLUR_MODE_GAUSSIAN_BLUR,
 		BLUR_MODE_GAUSSIAN_BLUR,
 		BLUR_MODE_GAUSSIAN_GLOW,
 		BLUR_MODE_GAUSSIAN_GLOW,
@@ -220,9 +226,11 @@ class EffectsRD {
 
 
 	struct CubemapRoughness {
 	struct CubemapRoughness {
 		CubemapRoughnessPushConstant push_constant;
 		CubemapRoughnessPushConstant push_constant;
-		CubemapRoughnessShaderRD shader;
+		CubemapRoughnessShaderRD compute_shader;
+		CubemapRoughnessRasterShaderRD raster_shader;
 		RID shader_version;
 		RID shader_version;
-		RID pipeline;
+		RID compute_pipeline;
+		PipelineCacheRD raster_pipeline;
 	} roughness;
 	} roughness;
 
 
 	enum TonemapMode {
 	enum TonemapMode {
@@ -508,15 +516,17 @@ class EffectsRD {
 
 
 	struct CubemapDownsamplerPushConstant {
 	struct CubemapDownsamplerPushConstant {
 		uint32_t face_size;
 		uint32_t face_size;
-		float pad[3];
+		uint32_t face_id;
+		float pad[2];
 	};
 	};
 
 
 	struct CubemapDownsampler {
 	struct CubemapDownsampler {
 		CubemapDownsamplerPushConstant push_constant;
 		CubemapDownsamplerPushConstant push_constant;
-		CubemapDownsamplerShaderRD shader;
+		CubemapDownsamplerShaderRD compute_shader;
+		CubemapDownsamplerRasterShaderRD raster_shader;
 		RID shader_version;
 		RID shader_version;
-		RID pipeline;
-
+		RID compute_pipeline;
+		PipelineCacheRD raster_pipeline;
 	} cubemap_downsampler;
 	} cubemap_downsampler;
 
 
 	enum CubemapFilterMode {
 	enum CubemapFilterMode {
@@ -527,10 +537,19 @@ class EffectsRD {
 		FILTER_MODE_MAX,
 		FILTER_MODE_MAX,
 	};
 	};
 
 
+	struct CubemapFilterRasterPushConstant {
+		uint32_t mip_level;
+		uint32_t face_id;
+		float pad[2];
+	};
+
 	struct CubemapFilter {
 	struct CubemapFilter {
-		CubemapFilterShaderRD shader;
+		CubemapFilterShaderRD compute_shader;
+		CubemapFilterRasterShaderRD raster_shader;
 		RID shader_version;
 		RID shader_version;
-		RID pipelines[FILTER_MODE_MAX];
+		RID compute_pipelines[FILTER_MODE_MAX];
+		PipelineCacheRD raster_pipelines[FILTER_MODE_MAX];
+
 		RID uniform_set;
 		RID uniform_set;
 		RID image_uniform_set;
 		RID image_uniform_set;
 		RID coefficient_buffer;
 		RID coefficient_buffer;
@@ -738,9 +757,9 @@ class EffectsRD {
 	RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false);
 	RID _get_compute_uniform_set_from_texture_pair(RID p_texture, RID p_texture2, bool p_use_mipmaps = false);
 	RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2);
 	RID _get_compute_uniform_set_from_image_pair(RID p_texture, RID p_texture2);
 
 
-	bool prefer_raster_effects;
-
 public:
 public:
+	bool get_prefer_raster_effects();
+
 	void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID());
 	void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID());
 	void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);
 	void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);
 	void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);
 	void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);
@@ -752,7 +771,8 @@ public:
 	void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
 	void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
 	void gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
 	void gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0);
 
 
-	void cubemap_roughness(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
+	void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
+	void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
 	void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
 	void make_mipmap(RID p_source_rd_texture, RID p_dest_texture, const Size2i &p_size);
 	void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip);
 	void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_texture, const Rect2 &p_rect, float p_z_near, float p_z_far, bool p_dp_flip);
 	void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
 	void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
@@ -828,7 +848,9 @@ public:
 
 
 	void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
 	void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
 	void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
 	void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
+	void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size);
 	void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
 	void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
+	void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level);
 
 
 	void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
 	void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
 	void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
 	void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);

+ 2 - 0
servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp

@@ -2325,6 +2325,8 @@ RenderForwardMobile::RenderForwardMobile(RendererStorageRD *p_storage) :
 		RendererSceneRenderRD(p_storage) {
 		RendererSceneRenderRD(p_storage) {
 	singleton = this;
 	singleton = this;
 
 
+	sky.set_texture_format(_render_buffers_get_color_format());
+
 	String defines;
 	String defines;
 
 
 	defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";
 	defines += "\n#define MAX_ROUGHNESS_LOD " + itos(get_roughness_layers() - 1) + ".0\n";

+ 5 - 1
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

@@ -629,6 +629,8 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
 	ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance);
 	ERR_FAIL_COND_V(!rpi, false);
 	ERR_FAIL_COND_V(!rpi, false);
 
 
+	RD::get_singleton()->draw_command_begin_label("Reflection probe render");
+
 	if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
 	if (storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->size != 256) {
 		WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings.");
 		WARN_PRINT("ReflectionProbes set to UPDATE_ALWAYS must have an atlas size of 256. Please update the atlas size in the ProjectSettings.");
 		reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count);
 		reflection_atlas_set_size(p_reflection_atlas, 256, atlas->count);
@@ -675,7 +677,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
 		}
 		}
 		atlas->reflections.resize(atlas->count);
 		atlas->reflections.resize(atlas->count);
 		for (int i = 0; i < atlas->count; i++) {
 		for (int i = 0; i < atlas->count; i++) {
-			atlas->reflections.write[i].data.update_reflection_data(atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers);
+			atlas->reflections.write[i].data.update_reflection_data(storage, atlas->size, mipmaps, false, atlas->reflection, i * 6, storage->reflection_probe_get_update_mode(rpi->probe) == RS::REFLECTION_PROBE_UPDATE_ALWAYS, sky.roughness_layers, _render_buffers_get_color_format());
 			for (int j = 0; j < 6; j++) {
 			for (int j = 0; j < 6; j++) {
 				Vector<RID> fb;
 				Vector<RID> fb;
 				fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
 				fb.push_back(atlas->reflections.write[i].data.layers[0].mipmaps[0].views[j]);
@@ -721,6 +723,8 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc
 	rpi->processing_layer = 1;
 	rpi->processing_layer = 1;
 	rpi->processing_side = 0;
 	rpi->processing_side = 0;
 
 
+	RD::get_singleton()->draw_command_end_label();
+
 	return true;
 	return true;
 }
 }
 
 

+ 138 - 33
servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp

@@ -313,12 +313,16 @@ void RendererSceneSkyRD::ReflectionData::clear_reflection_data() {
 	coefficient_buffer = RID();
 	coefficient_buffer = RID();
 }
 }
 
 
-void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers) {
+void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageRD *p_storage, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format) {
 	//recreate radiance and all data
 	//recreate radiance and all data
 
 
 	int mipmaps = p_mipmaps;
 	int mipmaps = p_mipmaps;
 	uint32_t w = p_size, h = p_size;
 	uint32_t w = p_size, h = p_size;
 
 
+	EffectsRD *effects = p_storage->get_effects();
+	ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+	bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
 	if (p_use_array) {
 	if (p_use_array) {
 		int num_layers = p_low_quality ? 8 : p_roughness_layers;
 		int num_layers = p_low_quality ? 8 : p_roughness_layers;
 
 
@@ -377,9 +381,9 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
 	}
 	}
 
 
 	radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
 	radiance_base_cubemap = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), p_base_cube, p_base_layer, 0, RD::TEXTURE_SLICE_CUBEMAP);
-
+	RD::get_singleton()->set_resource_name(radiance_base_cubemap, "radiance base cubemap");
 	RD::TextureFormat tf;
 	RD::TextureFormat tf;
-	tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+	tf.format = p_texture_format;
 	tf.width = 64; // Always 64x64
 	tf.width = 64; // Always 64x64
 	tf.height = 64;
 	tf.height = 64;
 	tf.texture_type = RD::TEXTURE_TYPE_CUBE;
 	tf.texture_type = RD::TEXTURE_TYPE_CUBE;
@@ -388,6 +392,7 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
 	tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
 	tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
 
 
 	downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
 	downsampled_radiance_cubemap = RD::get_singleton()->texture_create(tf, RD::TextureView());
+	RD::get_singleton()->set_resource_name(downsampled_radiance_cubemap, "downsampled radiance cubemap");
 	{
 	{
 		uint32_t mmw = 64;
 		uint32_t mmw = 64;
 		uint32_t mmh = 64;
 		uint32_t mmh = 64;
@@ -397,6 +402,18 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
 			mm.size.width = mmw;
 			mm.size.width = mmw;
 			mm.size.height = mmh;
 			mm.size.height = mmh;
 			mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP);
 			mm.view = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, 0, j, RD::TEXTURE_SLICE_CUBEMAP);
+			RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip " + itos(j) + " ");
+			if (prefer_raster_effects) {
+				// we need a framebuffer for each side of our cubemap
+
+				for (int k = 0; k < 6; k++) {
+					mm.views[k] = RD::get_singleton()->texture_create_shared_from_slice(RD::TextureView(), downsampled_radiance_cubemap, k, j);
+					RD::get_singleton()->set_resource_name(mm.view, "Downsampled Radiance Cubemap Mip: " + itos(j) + " Face: " + itos(k) + " ");
+					Vector<RID> fbtex;
+					fbtex.push_back(mm.views[k]);
+					mm.framebuffers[k] = RD::get_singleton()->framebuffer_create(fbtex);
+				}
+			}
 
 
 			mmw = MAX(1, mmw >> 1);
 			mmw = MAX(1, mmw >> 1);
 			mmh = MAX(1, mmh >> 1);
 			mmh = MAX(1, mmh >> 1);
@@ -405,50 +422,128 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(int p_size, int
 }
 }
 
 
 void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) {
 void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) {
-	p_storage->get_effects()->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+	EffectsRD *effects = p_storage->get_effects();
+	ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+	bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+	if (prefer_raster_effects) {
+		RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
+		for (int k = 0; k < 6; k++) {
+			effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size);
+		}
 
 
-	for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
-		p_storage->get_effects()->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
-	}
+		for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
+			for (int k = 0; k < 6; k++) {
+				effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size);
+			}
+		}
+		RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
 
 
-	Vector<RID> views;
-	if (p_use_arrays) {
-		for (int i = 1; i < layers.size(); i++) {
-			views.push_back(layers[i].views[0]);
+		if (p_use_arrays) {
+			RD::get_singleton()->draw_command_begin_label("filter radiance map into array heads");
+			for (int i = 0; i < layers.size(); i++) {
+				for (int k = 0; k < 6; k++) {
+					effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i);
+				}
+			}
+		} else {
+			RD::get_singleton()->draw_command_begin_label("filter radiance map into mipmaps directly");
+			for (int j = 0; j < layers[0].mipmaps.size(); j++) {
+				for (int k = 0; k < 6; k++) {
+					effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j);
+				}
+			}
 		}
 		}
+		RD::get_singleton()->draw_command_end_label(); // Filter radiance
 	} else {
 	} else {
-		for (int i = 1; i < layers[0].views.size(); i++) {
-			views.push_back(layers[0].views[i]);
+		effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+
+		for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
+			effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
+		}
+
+		Vector<RID> views;
+		if (p_use_arrays) {
+			for (int i = 1; i < layers.size(); i++) {
+				views.push_back(layers[i].views[0]);
+			}
+		} else {
+			for (int i = 1; i < layers[0].views.size(); i++) {
+				views.push_back(layers[0].views[i]);
+			}
 		}
 		}
-	}
 
 
-	p_storage->get_effects()->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+		effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+	}
 }
 }
 
 
 void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) {
 void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) {
-	if (p_use_arrays) {
-		//render directly to the layers
-		p_storage->get_effects()->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+	EffectsRD *effects = p_storage->get_effects();
+	ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+	bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+	if (prefer_raster_effects) {
+		// Need to ask clayjohn but p_cube_side is set to 10, looks like in the compute shader we're doing all 6 sides in one call
+		// here we need to do them one by one so ignoring p_cube_side
+		if (p_use_arrays) {
+			for (int k = 0; k < 6; k++) {
+				effects->cubemap_roughness_raster(
+						radiance_base_cubemap,
+						layers[p_base_layer].mipmaps[0].framebuffers[k],
+						k,
+						p_sky_ggx_samples_quality,
+						float(p_base_layer) / (layers.size() - 1.0),
+						layers[p_base_layer].mipmaps[0].size.x);
+			}
+		} else {
+			for (int k = 0; k < 6; k++) {
+				effects->cubemap_roughness_raster(
+						layers[0].views[p_base_layer - 1],
+						layers[0].mipmaps[p_base_layer].framebuffers[k],
+						k,
+						p_sky_ggx_samples_quality,
+						float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
+						layers[0].mipmaps[p_base_layer].size.x);
+			}
+		}
 	} else {
 	} else {
-		p_storage->get_effects()->cubemap_roughness(
-				layers[0].views[p_base_layer - 1],
-				layers[0].views[p_base_layer],
-				p_cube_side,
-				p_sky_ggx_samples_quality,
-				float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
-				layers[0].mipmaps[p_base_layer].size.x);
+		if (p_use_arrays) {
+			//render directly to the layers
+			effects->cubemap_roughness(radiance_base_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+		} else {
+			effects->cubemap_roughness(
+					layers[0].views[p_base_layer - 1],
+					layers[0].views[p_base_layer],
+					p_cube_side,
+					p_sky_ggx_samples_quality,
+					float(p_base_layer) / (layers[0].mipmaps.size() - 1.0),
+					layers[0].mipmaps[p_base_layer].size.x);
+		}
 	}
 	}
 }
 }
 
 
 void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) {
 void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) {
+	EffectsRD *effects = p_storage->get_effects();
+	ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
+	bool prefer_raster_effects = effects->get_prefer_raster_effects();
+
+	RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps");
 	for (int i = p_start; i < p_end; i++) {
 	for (int i = p_start; i < p_end; i++) {
 		for (int j = 0; j < layers[i].views.size() - 1; j++) {
 		for (int j = 0; j < layers[i].views.size() - 1; j++) {
 			RID view = layers[i].views[j];
 			RID view = layers[i].views[j];
-			RID texture = layers[i].views[j + 1];
 			Size2i size = layers[i].mipmaps[j + 1].size;
 			Size2i size = layers[i].mipmaps[j + 1].size;
-			p_storage->get_effects()->cubemap_downsample(view, texture, size);
+			if (prefer_raster_effects) {
+				for (int k = 0; k < 6; k++) {
+					RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k];
+					effects->cubemap_downsample_raster(view, framebuffer, k, size);
+				}
+			} else {
+				RID texture = layers[i].views[j + 1];
+				effects->cubemap_downsample(view, texture, size);
+			}
 		}
 		}
 	}
 	}
+	RD::get_singleton()->draw_command_end_label();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
@@ -902,6 +997,10 @@ void sky() {
 	}
 	}
 }
 }
 
 
+void RendererSceneSkyRD::set_texture_format(RD::DataFormat p_texture_format) {
+	texture_format = p_texture_format;
+}
+
 RendererSceneSkyRD::~RendererSceneSkyRD() {
 RendererSceneSkyRD::~RendererSceneSkyRD() {
 	// TODO cleanup anything created in init...
 	// TODO cleanup anything created in init...
 
 
@@ -1170,6 +1269,7 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
 		cm = correction * cm;
 		cm = correction * cm;
 
 
 		if (shader_data->uses_quarter_res) {
 		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];
 			PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_QUARTER_RES];
 
 
 			Vector<Color> clear_colors;
 			Vector<Color> clear_colors;
@@ -1185,9 +1285,11 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
 				_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.basis, multiplier, p_transform.origin);
 				_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.basis, multiplier, p_transform.origin);
 				RD::get_singleton()->draw_list_end();
 				RD::get_singleton()->draw_list_end();
 			}
 			}
+			RD::get_singleton()->draw_command_end_label();
 		}
 		}
 
 
 		if (shader_data->uses_half_res) {
 		if (shader_data->uses_half_res) {
+			RD::get_singleton()->draw_command_begin_label("Render Sky to Half Res Cubemap");
 			PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES];
 			PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP_HALF_RES];
 
 
 			Vector<Color> clear_colors;
 			Vector<Color> clear_colors;
@@ -1203,11 +1305,13 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
 				_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.basis, multiplier, p_transform.origin);
 				_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.basis, multiplier, p_transform.origin);
 				RD::get_singleton()->draw_list_end();
 				RD::get_singleton()->draw_list_end();
 			}
 			}
+			RD::get_singleton()->draw_command_end_label();
 		}
 		}
 
 
 		RD::DrawListID cubemap_draw_list;
 		RD::DrawListID cubemap_draw_list;
 		PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
 		PipelineCacheRD *pipeline = &shader_data->pipelines[SKY_VERSION_CUBEMAP];
 
 
+		RD::get_singleton()->draw_command_begin_label("Render Sky Cubemap");
 		for (int i = 0; i < 6; i++) {
 		for (int i = 0; i < 6; i++) {
 			Transform3D local_view;
 			Transform3D local_view;
 			local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
 			local_view.set_look_at(Vector3(0, 0, 0), view_normals[i], view_up[i]);
@@ -1217,6 +1321,7 @@ void RendererSceneSkyRD::update(RendererSceneEnvironmentRD *p_env, const CameraM
 			_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.basis, multiplier, p_transform.origin);
 			_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.basis, multiplier, p_transform.origin);
 			RD::get_singleton()->draw_list_end();
 			RD::get_singleton()->draw_list_end();
 		}
 		}
+		RD::get_singleton()->draw_command_end_label();
 
 
 		if (sky_mode == RS::SKY_MODE_REALTIME) {
 		if (sky_mode == RS::SKY_MODE_REALTIME) {
 			sky->reflection.create_reflection_fast_filter(storage, sky_use_cubemap_array);
 			sky->reflection.create_reflection_fast_filter(storage, sky_use_cubemap_array);
@@ -1393,7 +1498,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
 				//array (higher quality, 6 times more memory)
 				//array (higher quality, 6 times more memory)
 				RD::TextureFormat tf;
 				RD::TextureFormat tf;
 				tf.array_layers = layers * 6;
 				tf.array_layers = layers * 6;
-				tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+				tf.format = texture_format;
 				tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
 				tf.texture_type = RD::TEXTURE_TYPE_CUBE_ARRAY;
 				tf.mipmaps = mipmaps;
 				tf.mipmaps = mipmaps;
 				tf.width = w;
 				tf.width = w;
@@ -1402,13 +1507,13 @@ void RendererSceneSkyRD::update_dirty_skys() {
 
 
 				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
 				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
 
 
-				sky->reflection.update_reflection_data(sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+				sky->reflection.update_reflection_data(storage, sky->radiance_size, mipmaps, true, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format);
 
 
 			} else {
 			} else {
 				//regular cubemap, lower quality (aliasing, less memory)
 				//regular cubemap, lower quality (aliasing, less memory)
 				RD::TextureFormat tf;
 				RD::TextureFormat tf;
 				tf.array_layers = 6;
 				tf.array_layers = 6;
-				tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+				tf.format = texture_format;
 				tf.texture_type = RD::TEXTURE_TYPE_CUBE;
 				tf.texture_type = RD::TEXTURE_TYPE_CUBE;
 				tf.mipmaps = MIN(mipmaps, layers);
 				tf.mipmaps = MIN(mipmaps, layers);
 				tf.width = w;
 				tf.width = w;
@@ -1417,7 +1522,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
 
 
 				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
 				sky->radiance = RD::get_singleton()->texture_create(tf, RD::TextureView());
 
 
-				sky->reflection.update_reflection_data(sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers);
+				sky->reflection.update_reflection_data(storage, sky->radiance_size, MIN(mipmaps, layers), false, sky->radiance, 0, sky->mode == RS::SKY_MODE_REALTIME, roughness_layers, texture_format);
 			}
 			}
 			texture_set_dirty = true;
 			texture_set_dirty = true;
 		}
 		}
@@ -1425,7 +1530,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
 		// Create subpass buffers if they haven't been created already
 		// 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) {
 		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;
 			RD::TextureFormat tformat;
-			tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+			tformat.format = texture_format;
 			tformat.width = sky->screen_size.x / 2;
 			tformat.width = sky->screen_size.x / 2;
 			tformat.height = sky->screen_size.y / 2;
 			tformat.height = sky->screen_size.y / 2;
 			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
 			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
@@ -1440,7 +1545,7 @@ void RendererSceneSkyRD::update_dirty_skys() {
 
 
 		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) {
 		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;
 			RD::TextureFormat tformat;
-			tformat.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
+			tformat.format = texture_format;
 			tformat.width = sky->screen_size.x / 4;
 			tformat.width = sky->screen_size.x / 4;
 			tformat.height = sky->screen_size.y / 4;
 			tformat.height = sky->screen_size.y / 4;
 			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
 			tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;

+ 7 - 1
servers/rendering/renderer_rd/renderer_scene_sky_rd.h

@@ -64,6 +64,7 @@ public:
 
 
 private:
 private:
 	RendererStorageRD *storage;
 	RendererStorageRD *storage;
+	RD::DataFormat texture_format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
 
 
 	RID index_buffer;
 	RID index_buffer;
 	RID index_array;
 	RID index_array;
@@ -190,6 +191,10 @@ public:
 			struct Mipmap {
 			struct Mipmap {
 				RID view;
 				RID view;
 				Size2i size;
 				Size2i size;
+
+				// for mobile only
+				RID views[6];
+				RID framebuffers[6];
 			};
 			};
 			Vector<Mipmap> mipmaps;
 			Vector<Mipmap> mipmaps;
 		};
 		};
@@ -204,7 +209,7 @@ public:
 		Vector<Layer> layers;
 		Vector<Layer> layers;
 
 
 		void clear_reflection_data();
 		void clear_reflection_data();
-		void update_reflection_data(int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers);
+		void update_reflection_data(RendererStorageRD *p_storage, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality, int p_roughness_layers, RD::DataFormat p_texture_format);
 		void create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays);
 		void create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays);
 		void create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality);
 		void create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality);
 		void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end);
 		void update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end);
@@ -284,6 +289,7 @@ public:
 
 
 	RendererSceneSkyRD();
 	RendererSceneSkyRD();
 	void init(RendererStorageRD *p_storage);
 	void init(RendererStorageRD *p_storage);
+	void set_texture_format(RD::DataFormat p_texture_format);
 	~RendererSceneSkyRD();
 	~RendererSceneSkyRD();
 
 
 	void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);
 	void setup(RendererSceneEnvironmentRD *p_env, RID p_render_buffers, const CameraMatrix &p_projection, const Transform3D &p_transform, const Size2i p_screen_size, RendererSceneRenderRD *p_scene_render);

+ 1 - 47
servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl

@@ -32,53 +32,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
 
 
 layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
 layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
 
 
-layout(push_constant, binding = 1, std430) uniform Params {
-	uint face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-void get_dir_0(out vec3 dir, in float u, in float v) {
-	dir[0] = 1.0;
-	dir[1] = v;
-	dir[2] = -u;
-}
-
-void get_dir_1(out vec3 dir, in float u, in float v) {
-	dir[0] = -1.0;
-	dir[1] = v;
-	dir[2] = u;
-}
-
-void get_dir_2(out vec3 dir, in float u, in float v) {
-	dir[0] = u;
-	dir[1] = 1.0;
-	dir[2] = -v;
-}
-
-void get_dir_3(out vec3 dir, in float u, in float v) {
-	dir[0] = u;
-	dir[1] = -1.0;
-	dir[2] = v;
-}
-
-void get_dir_4(out vec3 dir, in float u, in float v) {
-	dir[0] = u;
-	dir[1] = v;
-	dir[2] = 1.0;
-}
-
-void get_dir_5(out vec3 dir, in float u, in float v) {
-	dir[0] = -u;
-	dir[1] = v;
-	dir[2] = -1.0;
-}
-
-float calcWeight(float u, float v) {
-	float val = u * u + v * v + 1.0;
-	return val * sqrt(val);
-}
+#include "cubemap_downsampler_inc.glsl"
 
 
 void main() {
 void main() {
 	uvec3 id = gl_GlobalInvocationID;
 	uvec3 id = gl_GlobalInvocationID;

+ 48 - 0
servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl

@@ -0,0 +1,48 @@
+layout(push_constant, binding = 1, std430) uniform Params {
+	uint face_size;
+	uint face_id; // only used in raster shader
+}
+params;
+
+#define M_PI 3.14159265359
+
+void get_dir_0(out vec3 dir, in float u, in float v) {
+	dir[0] = 1.0;
+	dir[1] = v;
+	dir[2] = -u;
+}
+
+void get_dir_1(out vec3 dir, in float u, in float v) {
+	dir[0] = -1.0;
+	dir[1] = v;
+	dir[2] = u;
+}
+
+void get_dir_2(out vec3 dir, in float u, in float v) {
+	dir[0] = u;
+	dir[1] = 1.0;
+	dir[2] = -v;
+}
+
+void get_dir_3(out vec3 dir, in float u, in float v) {
+	dir[0] = u;
+	dir[1] = -1.0;
+	dir[2] = v;
+}
+
+void get_dir_4(out vec3 dir, in float u, in float v) {
+	dir[0] = u;
+	dir[1] = v;
+	dir[2] = 1.0;
+}
+
+void get_dir_5(out vec3 dir, in float u, in float v) {
+	dir[0] = -u;
+	dir[1] = v;
+	dir[2] = -1.0;
+}
+
+float calcWeight(float u, float v) {
+	float val = u * u + v * v + 1.0;
+	return val * sqrt(val);
+}

+ 163 - 0
servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl

@@ -0,0 +1,163 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// 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.
+
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_downsampler_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+	vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+	uv_interp = base_arr[gl_VertexIndex] * float(params.face_size);
+	gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_downsampler_inc.glsl"
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(location = 0) in vec2 uv_interp;
+layout(location = 0) out vec4 frag_color;
+/* clang-format on */
+
+void main() {
+	// Converted from compute shader which uses absolute coordinates.
+	// Could possibly simplify this
+	float face_size = float(params.face_size);
+
+	if (uv_interp.x < face_size && uv_interp.y < face_size) {
+		float inv_face_size = 1.0 / face_size;
+
+		float u0 = (uv_interp.x * 2.0 + 1.0 - 0.75) * inv_face_size - 1.0;
+		float u1 = (uv_interp.x * 2.0 + 1.0 + 0.75) * inv_face_size - 1.0;
+
+		float v0 = (uv_interp.y * 2.0 + 1.0 - 0.75) * -inv_face_size + 1.0;
+		float v1 = (uv_interp.y * 2.0 + 1.0 + 0.75) * -inv_face_size + 1.0;
+
+		float weights[4];
+		weights[0] = calcWeight(u0, v0);
+		weights[1] = calcWeight(u1, v0);
+		weights[2] = calcWeight(u0, v1);
+		weights[3] = calcWeight(u1, v1);
+
+		const float wsum = 0.5 / (weights[0] + weights[1] + weights[2] + weights[3]);
+		for (int i = 0; i < 4; i++) {
+			weights[i] = weights[i] * wsum + .125;
+		}
+
+		vec3 dir;
+		vec4 color;
+		switch (params.face_id) {
+			case 0:
+				get_dir_0(dir, u0, v0);
+				color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+				get_dir_0(dir, u1, v0);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+				get_dir_0(dir, u0, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+				get_dir_0(dir, u1, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+				break;
+			case 1:
+				get_dir_1(dir, u0, v0);
+				color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+				get_dir_1(dir, u1, v0);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+				get_dir_1(dir, u0, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+				get_dir_1(dir, u1, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+				break;
+			case 2:
+				get_dir_2(dir, u0, v0);
+				color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+				get_dir_2(dir, u1, v0);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+				get_dir_2(dir, u0, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+				get_dir_2(dir, u1, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+				break;
+			case 3:
+				get_dir_3(dir, u0, v0);
+				color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+				get_dir_3(dir, u1, v0);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+				get_dir_3(dir, u0, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+				get_dir_3(dir, u1, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+				break;
+			case 4:
+				get_dir_4(dir, u0, v0);
+				color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+				get_dir_4(dir, u1, v0);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+				get_dir_4(dir, u0, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+				get_dir_4(dir, u1, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+				break;
+			default:
+				get_dir_5(dir, u0, v0);
+				color = textureLod(source_cubemap, normalize(dir), 0.0) * weights[0];
+
+				get_dir_5(dir, u1, v0);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[1];
+
+				get_dir_5(dir, u0, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[2];
+
+				get_dir_5(dir, u1, v1);
+				color += textureLod(source_cubemap, normalize(dir), 0.0) * weights[3];
+				break;
+		}
+		frag_color = color;
+	}
+}

+ 256 - 0
servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl

@@ -0,0 +1,256 @@
+// Copyright 2016 Activision Publishing, Inc.
+//
+// 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.
+
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+	int mip_level;
+	uint face_id;
+}
+params;
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+	vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+	uv_interp = base_arr[gl_VertexIndex];
+	gl_Position = vec4(base_arr[gl_VertexIndex] * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(push_constant, binding = 1, std430) uniform Params {
+	int mip_level;
+	uint face_id;
+}
+params;
+
+layout(set = 0, binding = 0) uniform samplerCube source_cubemap;
+
+layout(location = 0) in vec2 uv_interp;
+layout(location = 0) out vec4 frag_color;
+
+/* clang-format on */
+
+#ifdef USE_HIGH_QUALITY
+#define NUM_TAPS 32
+#else
+#define NUM_TAPS 8
+#endif
+
+#define BASE_RESOLUTION 128
+
+#ifdef USE_HIGH_QUALITY
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+	vec4[7][5][3][24] coeffs;
+}
+data;
+#else
+layout(set = 1, binding = 0, std430) buffer restrict readonly Data {
+	vec4[7][5][6] coeffs;
+}
+data;
+#endif
+
+void get_dir(out vec3 dir, in vec2 uv, in uint face) {
+	switch (face) {
+		case 0:
+			dir = vec3(1.0, uv[1], -uv[0]);
+			break;
+		case 1:
+			dir = vec3(-1.0, uv[1], uv[0]);
+			break;
+		case 2:
+			dir = vec3(uv[0], 1.0, -uv[1]);
+			break;
+		case 3:
+			dir = vec3(uv[0], -1.0, uv[1]);
+			break;
+		case 4:
+			dir = vec3(uv[0], uv[1], 1.0);
+			break;
+		default:
+			dir = vec3(-uv[0], uv[1], -1.0);
+			break;
+	}
+}
+
+void main() {
+	// determine dir / pos for the texel
+	vec3 dir, adir, frameZ;
+	{
+		vec2 uv;
+		uv.x = uv_interp.x;
+		uv.y = 1.0 - uv_interp.y;
+		uv = uv * 2.0 - 1.0;
+
+		get_dir(dir, uv, params.face_id);
+		frameZ = normalize(dir);
+
+		adir = abs(dir);
+	}
+
+	// determine which texel this is
+	// NOTE (macOS/MoltenVK): Do not rename, "level" variable name conflicts with the Metal "level(float lod)" mipmap sampling function name.
+	int mip_level = 0;
+
+	if (params.mip_level < 0) {
+		// return as is
+		frag_color.rgb = textureLod(source_cubemap, frameZ, 0.0).rgb;
+		frag_color.a = 1.0;
+		return;
+	} else if (params.mip_level > 6) {
+		// maximum level
+		mip_level = 6;
+	} else {
+		mip_level = params.mip_level;
+	}
+
+	// GGX gather colors
+	vec4 color = vec4(0.0);
+	for (int axis = 0; axis < 3; axis++) {
+		const int otherAxis0 = 1 - (axis & 1) - (axis >> 1);
+		const int otherAxis1 = 2 - (axis >> 1);
+
+		float frameweight = (max(adir[otherAxis0], adir[otherAxis1]) - .75) / .25;
+		if (frameweight > 0.0) {
+			// determine frame
+			vec3 UpVector;
+			switch (axis) {
+				case 0:
+					UpVector = vec3(1, 0, 0);
+					break;
+				case 1:
+					UpVector = vec3(0, 1, 0);
+					break;
+				default:
+					UpVector = vec3(0, 0, 1);
+					break;
+			}
+
+			vec3 frameX = normalize(cross(UpVector, frameZ));
+			vec3 frameY = cross(frameZ, frameX);
+
+			// calculate parametrization for polynomial
+			float Nx = dir[otherAxis0];
+			float Ny = dir[otherAxis1];
+			float Nz = adir[axis];
+
+			float NmaxXY = max(abs(Ny), abs(Nx));
+			Nx /= NmaxXY;
+			Ny /= NmaxXY;
+
+			float theta;
+			if (Ny < Nx) {
+				if (Ny <= -0.999)
+					theta = Nx;
+				else
+					theta = Ny;
+			} else {
+				if (Ny >= 0.999)
+					theta = -Nx;
+				else
+					theta = -Ny;
+			}
+
+			float phi;
+			if (Nz <= -0.999)
+				phi = -NmaxXY;
+			else if (Nz >= 0.999)
+				phi = NmaxXY;
+			else
+				phi = Nz;
+
+			float theta2 = theta * theta;
+			float phi2 = phi * phi;
+
+			// sample
+			for (int iSuperTap = 0; iSuperTap < NUM_TAPS / 4; iSuperTap++) {
+				const int index = (NUM_TAPS / 4) * axis + iSuperTap;
+
+#ifdef USE_HIGH_QUALITY
+				vec4 coeffsDir0[3];
+				vec4 coeffsDir1[3];
+				vec4 coeffsDir2[3];
+				vec4 coeffsLevel[3];
+				vec4 coeffsWeight[3];
+
+				for (int iCoeff = 0; iCoeff < 3; iCoeff++) {
+					coeffsDir0[iCoeff] = data.coeffs[mip_level][0][iCoeff][index];
+					coeffsDir1[iCoeff] = data.coeffs[mip_level][1][iCoeff][index];
+					coeffsDir2[iCoeff] = data.coeffs[mip_level][2][iCoeff][index];
+					coeffsLevel[iCoeff] = data.coeffs[mip_level][3][iCoeff][index];
+					coeffsWeight[iCoeff] = data.coeffs[mip_level][4][iCoeff][index];
+				}
+
+				for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+					// determine sample attributes (dir, weight, mip_level)
+					vec3 sample_dir = frameX * (coeffsDir0[0][iSubTap] + coeffsDir0[1][iSubTap] * theta2 + coeffsDir0[2][iSubTap] * phi2) + frameY * (coeffsDir1[0][iSubTap] + coeffsDir1[1][iSubTap] * theta2 + coeffsDir1[2][iSubTap] * phi2) + frameZ * (coeffsDir2[0][iSubTap] + coeffsDir2[1][iSubTap] * theta2 + coeffsDir2[2][iSubTap] * phi2);
+
+					float sample_level = coeffsLevel[0][iSubTap] + coeffsLevel[1][iSubTap] * theta2 + coeffsLevel[2][iSubTap] * phi2;
+
+					float sample_weight = coeffsWeight[0][iSubTap] + coeffsWeight[1][iSubTap] * theta2 + coeffsWeight[2][iSubTap] * phi2;
+#else
+				vec4 coeffsDir0 = data.coeffs[mip_level][0][index];
+				vec4 coeffsDir1 = data.coeffs[mip_level][1][index];
+				vec4 coeffsDir2 = data.coeffs[mip_level][2][index];
+				vec4 coeffsLevel = data.coeffs[mip_level][3][index];
+				vec4 coeffsWeight = data.coeffs[mip_level][4][index];
+
+				for (int iSubTap = 0; iSubTap < 4; iSubTap++) {
+					// determine sample attributes (dir, weight, mip_level)
+					vec3 sample_dir = frameX * coeffsDir0[iSubTap] + frameY * coeffsDir1[iSubTap] + frameZ * coeffsDir2[iSubTap];
+
+					float sample_level = coeffsLevel[iSubTap];
+
+					float sample_weight = coeffsWeight[iSubTap];
+#endif
+
+					sample_weight *= frameweight;
+
+					// adjust for jacobian
+					sample_dir /= max(abs(sample_dir[0]), max(abs(sample_dir[1]), abs(sample_dir[2])));
+					sample_level += 0.75 * log2(dot(sample_dir, sample_dir));
+					// sample cubemap
+					color.xyz += textureLod(source_cubemap, normalize(sample_dir), sample_level).xyz * sample_weight;
+					color.w += sample_weight;
+				}
+			}
+		}
+	}
+	color /= color.w;
+
+	// write color
+	color.xyz = max(vec3(0.0), color.xyz);
+	color.w = 1.0;
+
+	frag_color = color;
+}

+ 1 - 94
servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl

@@ -12,100 +12,7 @@ layout(set = 0, binding = 0) uniform samplerCube source_cube;
 
 
 layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
 layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly imageCube dest_cubemap;
 
 
-layout(push_constant, binding = 1, std430) uniform Params {
-	uint face_id;
-	uint sample_count;
-	float roughness;
-	bool use_direct_write;
-	float face_size;
-}
-params;
-
-#define M_PI 3.14159265359
-
-vec3 texelCoordToVec(vec2 uv, uint faceID) {
-	mat3 faceUvVectors[6];
-
-	// -x
-	faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
-	faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
-	faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
-	// +x
-	faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
-	faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
-	faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
-
-	// -y
-	faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
-	faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
-	faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
-
-	// +y
-	faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
-	faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
-	faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
-
-	// -z
-	faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
-	faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
-	faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
-
-	// +z
-	faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
-	faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
-	faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
-
-	// out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
-	vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
-	return normalize(result);
-}
-
-vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
-	float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
-
-	// Compute distribution direction
-	float Phi = 2.0 * M_PI * Xi.x;
-	float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
-	float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
-
-	// Convert to spherical direction
-	vec3 H;
-	H.x = SinTheta * cos(Phi);
-	H.y = SinTheta * sin(Phi);
-	H.z = CosTheta;
-
-	vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
-	vec3 TangentX = normalize(cross(UpVector, N));
-	vec3 TangentY = cross(N, TangentX);
-
-	// Tangent to world space
-	return TangentX * H.x + TangentY * H.y + N * H.z;
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float GGX(float NdotV, float a) {
-	float k = a / 2.0;
-	return NdotV / (NdotV * (1.0 - k) + k);
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float G_Smith(float a, float nDotV, float nDotL) {
-	return GGX(nDotL, a * a) * GGX(nDotV, a * a);
-}
-
-float radicalInverse_VdC(uint bits) {
-	bits = (bits << 16u) | (bits >> 16u);
-	bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
-	bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
-	bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
-	bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
-	return float(bits) * 2.3283064365386963e-10; // / 0x100000000
-}
-
-vec2 Hammersley(uint i, uint N) {
-	return vec2(float(i) / float(N), radicalInverse_VdC(i));
-}
+#include "cubemap_roughness_inc.glsl"
 
 
 void main() {
 void main() {
 	uvec3 id = gl_GlobalInvocationID;
 	uvec3 id = gl_GlobalInvocationID;

+ 94 - 0
servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl

@@ -0,0 +1,94 @@
+#define M_PI 3.14159265359
+
+layout(push_constant, binding = 1, std430) uniform Params {
+	uint face_id;
+	uint sample_count;
+	float roughness;
+	bool use_direct_write;
+	float face_size;
+}
+params;
+
+vec3 texelCoordToVec(vec2 uv, uint faceID) {
+	mat3 faceUvVectors[6];
+
+	// -x
+	faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+	faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+	faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+	// +x
+	faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+	faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+	faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+	// -y
+	faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+	faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+	faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+	// +y
+	faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+	faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+	faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+	// -z
+	faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+	faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+	faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+	// +z
+	faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+	faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+	faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
+
+	// out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
+	vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
+	return normalize(result);
+}
+
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
+	float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
+
+	// Compute distribution direction
+	float Phi = 2.0 * M_PI * Xi.x;
+	float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
+	float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
+
+	// Convert to spherical direction
+	vec3 H;
+	H.x = SinTheta * cos(Phi);
+	H.y = SinTheta * sin(Phi);
+	H.z = CosTheta;
+
+	vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
+	vec3 TangentX = normalize(cross(UpVector, N));
+	vec3 TangentY = cross(N, TangentX);
+
+	// Tangent to world space
+	return TangentX * H.x + TangentY * H.y + N * H.z;
+}
+
+// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float GGX(float NdotV, float a) {
+	float k = a / 2.0;
+	return NdotV / (NdotV * (1.0 - k) + k);
+}
+
+// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
+float G_Smith(float a, float nDotV, float nDotL) {
+	return GGX(nDotL, a * a) * GGX(nDotV, a * a);
+}
+
+float radicalInverse_VdC(uint bits) {
+	bits = (bits << 16u) | (bits >> 16u);
+	bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+	bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+	bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+	bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+	return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+}
+
+vec2 Hammersley(uint i, uint N) {
+	return vec2(float(i) / float(N), radicalInverse_VdC(i));
+}

+ 63 - 0
servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl

@@ -0,0 +1,63 @@
+/* clang-format off */
+#[vertex]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_roughness_inc.glsl"
+
+layout(location = 0) out vec2 uv_interp;
+/* clang-format on */
+
+void main() {
+	vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0));
+	uv_interp = base_arr[gl_VertexIndex];
+	gl_Position = vec4(uv_interp * 2.0 - 1.0, 0.0, 1.0);
+}
+
+/* clang-format off */
+#[fragment]
+
+#version 450
+
+#VERSION_DEFINES
+
+#include "cubemap_roughness_inc.glsl"
+
+layout(location = 0) in vec2 uv_interp;
+
+layout(set = 0, binding = 0) uniform samplerCube source_cube;
+
+layout(location = 0) out vec4 frag_color;
+/* clang-format on */
+
+void main() {
+	vec3 N = texelCoordToVec(uv_interp * 2.0 - 1.0, params.face_id);
+
+	//vec4 color = color_interp;
+
+	if (params.use_direct_write) {
+		frag_color = vec4(texture(source_cube, N).rgb, 1.0);
+	} else {
+		vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
+
+		for (uint sampleNum = 0u; sampleNum < params.sample_count; sampleNum++) {
+			vec2 xi = Hammersley(sampleNum, params.sample_count);
+
+			vec3 H = ImportanceSampleGGX(xi, params.roughness, N);
+			vec3 V = N;
+			vec3 L = (2.0 * dot(V, H) * H - V);
+
+			float ndotl = clamp(dot(N, L), 0.0, 1.0);
+
+			if (ndotl > 0.0) {
+				sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
+				sum.a += ndotl;
+			}
+		}
+		sum /= sum.a;
+
+		frag_color = vec4(sum.rgb, 1.0);
+	}
+}