Răsfoiți Sursa

Merge pull request #36691 from clayjohn/VULKAN-cubemap-roughness

Improve cubemap importance sampling
Rémi Verschelde 5 ani în urmă
părinte
comite
c292aab247

+ 15 - 11
servers/visual/rasterizer_rd/rasterizer_effects_rd.cpp

@@ -248,26 +248,30 @@ void RasterizerEffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_framebuff
 	RD::get_singleton()->draw_list_end();
 }
 
-void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness) {
+void RasterizerEffectsRD::cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
 
 	zeromem(&roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
 
-	roughness.push_constant.face_id = p_face_id;
+	roughness.push_constant.face_id = p_face_id > 9 ? 0 : 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;
 
-	//RUN
-	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.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+	RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+	RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.pipelines[p_source_is_panorama ? CUBEMAP_ROUGHNESS_SOURCE_PANORAMA : CUBEMAP_ROUGHNESS_SOURCE_CUBEMAP]);
 
-	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()->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()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+	RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
 
-	RD::get_singleton()->draw_list_draw(draw_list, true);
-	RD::get_singleton()->draw_list_end();
+	int x_groups = (p_size - 1) / 8 + 1;
+	int y_groups = (p_size - 1) / 8 + 1;
+
+	RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1);
+
+	RD::get_singleton()->compute_list_end();
 }
 
 void RasterizerEffectsRD::render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler) {
@@ -841,7 +845,7 @@ RasterizerEffectsRD::RasterizerEffectsRD() {
 		roughness.shader_version = roughness.shader.version_create();
 
 		for (int i = 0; i < CUBEMAP_ROUGHNESS_SOURCE_MAX; i++) {
-			roughness.pipelines[i].setup(roughness.shader.version_get_shader(roughness.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+			roughness.pipelines[i] = RD::get_singleton()->compute_pipeline_create(roughness.shader.version_get_shader(roughness.shader_version, i));
 		}
 	}
 

+ 4 - 2
servers/visual/rasterizer_rd/rasterizer_effects_rd.h

@@ -127,6 +127,8 @@ class RasterizerEffectsRD {
 		uint32_t sample_count;
 		float roughness;
 		uint32_t use_direct_write;
+		float face_size;
+		float pad[3];
 	};
 
 	struct CubemapRoughness {
@@ -134,7 +136,7 @@ class RasterizerEffectsRD {
 		CubemapRoughnessPushConstant push_constant;
 		CubemapRoughnessShaderRD shader;
 		RID shader_version;
-		RenderPipelineVertexFormatCacheRD pipelines[CUBEMAP_ROUGHNESS_SOURCE_MAX];
+		RID pipelines[CUBEMAP_ROUGHNESS_SOURCE_MAX];
 	} roughness;
 
 	struct SkyPushConstant {
@@ -419,7 +421,7 @@ public:
 	void gaussian_blur(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, const Rect2 &p_region);
 	void gaussian_glow(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_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, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness);
+	void cubemap_roughness(RID p_source_rd_texture, bool p_source_is_panorama, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
 	void render_panorama(RD::DrawListID p_list, RenderingDevice::FramebufferFormatID p_fb_format, RID p_panorama, const CameraMatrix &p_camera, const Basis &p_orientation, float p_alpha, float p_multipler);
 	void make_mipmap(RID p_source_rd_texture, RID p_framebuffer_half, const Vector2 &p_pixel_size);
 	void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_rect, float p_z_near, float p_z_far, float p_bias, bool p_dp_flip);

+ 40 - 20
servers/visual/rasterizer_rd/rasterizer_scene_rd.cpp

@@ -146,9 +146,7 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID
 		if (p_quality) {
 			//render directly to the layers
 			for (int i = 0; i < rd.layers.size(); i++) {
-				for (int j = 0; j < 6; j++) {
-					storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[i].mipmaps[0].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0));
-				}
+				storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[i].views[0], 10, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0), rd.layers[i].mipmaps[0].size.x);
 			}
 		} else {
 			// Use fast filtering. Render directly to base mip levels
@@ -169,9 +167,7 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID
 		if (p_quality) {
 			//render directly to the layers
 			for (int i = 0; i < rd.layers[0].mipmaps.size(); i++) {
-				for (int j = 0; j < 6; j++) {
-					storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].mipmaps[i].framebuffers[j], j, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0));
-				}
+				storage->get_effects()->cubemap_roughness(p_panorama, true, rd.layers[0].views[i], 10, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[i].size.x);
 			}
 		} else {
 			// Use fast filtering. Render directly to each mip level
@@ -185,15 +181,13 @@ void RasterizerSceneRD::_create_reflection_from_panorama(ReflectionData &rd, RID
 	}
 }
 
-void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side) {
+void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side, int p_base_layer) {
 
 	if (p_use_arrays) {
 
 		if (p_quality) {
 			//render directly to the layers
-			for (int i = 1; i < rd.layers.size(); i++) {
-				storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[i].mipmaps[0].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_quality, float(i) / (rd.layers.size() - 1.0));
-			}
+			storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[p_base_layer].views[0], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers.size() - 1.0), rd.layers[p_base_layer].mipmaps[0].size.x);
 		} else {
 
 			storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, false, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size);
@@ -211,10 +205,8 @@ void RasterizerSceneRD::_create_reflection_from_base_mipmap(ReflectionData &rd,
 	} else {
 
 		if (p_quality) {
-			//render directly to the layers
-			for (int i = 1; i < rd.layers[0].mipmaps.size(); i++) {
-				storage->get_effects()->cubemap_roughness(rd.radiance_base_cubemap, false, rd.layers[0].mipmaps[i].framebuffers[p_cube_side], p_cube_side, sky_ggx_samples_quality, float(i) / (rd.layers[0].mipmaps.size() - 1.0));
-			}
+
+			storage->get_effects()->cubemap_roughness(rd.layers[0].views[p_base_layer - 1], false, rd.layers[0].views[p_base_layer], p_cube_side, sky_ggx_samples_quality, float(p_base_layer) / (rd.layers[0].mipmaps.size() - 1.0), rd.layers[0].mipmaps[p_base_layer].size.x);
 		} else {
 
 			storage->get_effects()->cubemap_downsample(rd.radiance_base_cubemap, false, rd.downsampled_layer.mipmaps[0].view, rd.downsampled_layer.mipmaps[0].size);
@@ -742,6 +734,21 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R
 		reflection_atlas_set_size(p_reflection_atlas, 128, atlas->count);
 	}
 
+	if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS && atlas->reflection.is_valid() && atlas->reflections[0].data.layers[0].mipmaps.size() != 7) {
+		// Invalidate reflection atlas, need to regenerate
+		RD::get_singleton()->free(atlas->reflection);
+		atlas->reflection = RID();
+
+		for (int i = 0; i < atlas->reflections.size(); i++) {
+			if (atlas->reflections[i].owner.is_null()) {
+				continue;
+			}
+			reflection_probe_release_atlas_index(atlas->reflections[i].owner);
+		}
+
+		atlas->reflections.clear();
+	}
+
 	if (atlas->reflection.is_null()) {
 		int mipmaps = MIN(roughness_layers, Image::get_image_required_mipmaps(atlas->size, atlas->size, Image::FORMAT_RGBAH) + 1);
 		mipmaps = storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS ? 7 : mipmaps; // always use 7 mipmaps with real time filtering
@@ -808,6 +815,7 @@ bool RasterizerSceneRD::reflection_probe_instance_begin_render(RID p_instance, R
 	rpi->atlas = p_reflection_atlas;
 	rpi->rendering = true;
 	rpi->dirty = false;
+	rpi->processing_layer = 1;
 	rpi->processing_side = 0;
 
 	return true;
@@ -827,24 +835,36 @@ bool RasterizerSceneRD::reflection_probe_instance_postprocess_step(RID p_instanc
 		return false;
 	}
 
-	_create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side);
+	if (rpi->processing_layer > 1) {
+		_create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, 10, rpi->processing_layer);
+		rpi->processing_layer++;
+		if (rpi->processing_layer == atlas->reflections[rpi->atlas_index].data.layers[0].mipmaps.size()) {
+			rpi->rendering = false;
+			rpi->processing_side = 0;
+			rpi->processing_layer = 1;
+			return true;
+		}
+		return false;
+
+	} else {
+		_create_reflection_from_base_mipmap(atlas->reflections.write[rpi->atlas_index].data, false, storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ONCE, rpi->processing_side, rpi->processing_layer);
+	}
 
 	if (storage->reflection_probe_get_update_mode(rpi->probe) == VS::REFLECTION_PROBE_UPDATE_ALWAYS) {
 		// Using real time reflections, all roughness is done in one step
 		rpi->rendering = false;
 		rpi->processing_side = 0;
+		rpi->processing_layer = 1;
 		return true;
 	}
 
 	rpi->processing_side++;
-
 	if (rpi->processing_side == 6) {
-		rpi->rendering = false;
 		rpi->processing_side = 0;
-		return true;
-	} else {
-		return false;
+		rpi->processing_layer++;
 	}
+
+	return false;
 }
 
 uint32_t RasterizerSceneRD::reflection_probe_instance_get_resolution(RID p_instance) {

+ 2 - 1
servers/visual/rasterizer_rd/rasterizer_scene_rd.h

@@ -108,7 +108,7 @@ private:
 	void _clear_reflection_data(ReflectionData &rd);
 	void _update_reflection_data(ReflectionData &rd, int p_size, int p_mipmaps, bool p_use_array, RID p_base_cube, int p_base_layer, bool p_low_quality);
 	void _create_reflection_from_panorama(ReflectionData &rd, RID p_panorama, bool p_quality);
-	void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side);
+	void _create_reflection_from_base_mipmap(ReflectionData &rd, bool p_use_arrays, bool p_quality, int p_cube_side, int p_base_layer);
 	void _update_reflection_mipmaps(ReflectionData &rd, bool p_quality);
 
 	/* SKY */
@@ -165,6 +165,7 @@ private:
 
 		bool dirty = true;
 		bool rendering = false;
+		int processing_layer = 1;
 		int processing_side = 0;
 
 		uint32_t render_step = 0;

+ 15 - 58
servers/visual/rasterizer_rd/shaders/cubemap_roughness.glsl

@@ -1,83 +1,38 @@
 /* clang-format off */
-[vertex]
+[compute]
 
 #version 450
 
 VERSION_DEFINES
 
-layout(location = 0) out highp 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
+#define GROUP_SIZE 8
 
-VERSION_DEFINES
+layout(local_size_x = GROUP_SIZE, local_size_y = GROUP_SIZE, local_size_z = 1) in;
+/* clang-format on */
 
 #ifdef MODE_SOURCE_PANORAMA
 layout(set = 0, binding = 0) uniform sampler2D source_panorama;
-/* clang-format on */
 #endif
 
 #ifdef MODE_SOURCE_CUBEMAP
 layout(set = 0, binding = 0) uniform samplerCube source_cube;
 #endif
 
+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;
 
-layout(location = 0) in vec2 uv_interp;
-
-layout(location = 0) out vec4 frag_color;
-
 #define M_PI 3.14159265359
 
 vec3 texelCoordToVec(vec2 uv, uint faceID) {
 	mat3 faceUvVectors[6];
-	/*
-	// -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
-
-	// +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
-
-	// -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
-
-	// +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
-
-	// -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
-
-	// +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
-	*/
 
 	// -x
 	faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
@@ -179,21 +134,23 @@ vec4 texturePanorama(vec3 normal, sampler2D pano) {
 #endif
 
 void main() {
+	uvec3 id = gl_GlobalInvocationID;
+	id.z += params.face_id;
 
-	vec2 uv = (uv_interp * 2.0) - 1.0;
-	vec3 N = texelCoordToVec(uv, params.face_id);
+	vec2 uv = ((vec2(id.xy) * 2.0 + 1.0) / (params.face_size) - 1.0);
+	vec3 N = texelCoordToVec(uv, id.z);
 
 	//vec4 color = color_interp;
 
 	if (params.use_direct_write) {
 
 #ifdef MODE_SOURCE_PANORAMA
-
-		frag_color = vec4(texturePanorama(N, source_panorama).rgb, 1.0);
+		imageStore(dest_cubemap, ivec3(id), vec4(texturePanorama(N, source_panorama).rgb, 1.0));
 #endif
 
 #ifdef MODE_SOURCE_CUBEMAP
-		frag_color = vec4(texture(source_cube, N).rgb, 1.0);
+		imageStore(dest_cubemap, ivec3(id), vec4(texture(source_cube, N).rgb, 1.0));
+
 #endif
 
 	} else {
@@ -222,6 +179,6 @@ void main() {
 		}
 		sum /= sum.a;
 
-		frag_color = vec4(sum.rgb, 1.0);
+		imageStore(dest_cubemap, ivec3(id), vec4(sum.rgb, 1.0));
 	}
 }