Browse Source

Rewrite textureProjLod usage to avoid a Vulkan validation error.

Dario 3 months ago
parent
commit
499fff51fb

+ 3 - 4
servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp

@@ -723,6 +723,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
 
 		//print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale));
 		state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
+		state_buffer.shadow_pixel_size = 1.0f / (float)(state.shadow_texture_size);
 
 		state_buffer.flags = use_linear_colors ? CANVAS_FLAGS_CONVERT_ATTRIBUTES_TO_LINEAR : 0;
 
@@ -1923,11 +1924,9 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
 		state.lights_uniform_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(LightUniform) * state.max_lights_per_render);
 
 		RD::SamplerState shadow_sampler_state;
-		shadow_sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
-		shadow_sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+		shadow_sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+		shadow_sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
 		shadow_sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; //shadow wrap around
-		shadow_sampler_state.compare_op = RD::COMPARE_OP_GREATER;
-		shadow_sampler_state.enable_compare = true;
 		state.shadow_sampler = RD::get_singleton()->sampler_create(shadow_sampler_state);
 	}
 

+ 1 - 1
servers/rendering/renderer_rd/renderer_canvas_render_rd.h

@@ -550,8 +550,8 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
 
 			uint32_t directional_light_count;
 			float tex_to_sdf;
+			float shadow_pixel_size;
 			uint32_t flags;
-			uint32_t pad2;
 		};
 
 		DataBuffer canvas_instance_data_buffers[BATCH_DATA_BUFFER_COUNT];

+ 30 - 19
servers/rendering/renderer_rd/shaders/canvas.glsl

@@ -286,6 +286,17 @@ vec2 sdf_to_screen_uv(vec2 p_sdf) {
 	return p_sdf * canvas_data.sdf_to_screen;
 }
 
+// Emulate textureProjLod by doing it manually because the source texture is not an actual depth texture that can be used for this operation.
+// Since the sampler is configured to nearest use one textureGather tap to emulate bilinear.
+float texture_shadow(vec4 p) {
+	// Manually round p to the nearest texel because textureGather uses strange rounding rules.
+	vec2 unit_p = floor(p.xy / canvas_data.shadow_pixel_size) * canvas_data.shadow_pixel_size;
+	float depth = p.z;
+	float fx = fract(p.x / canvas_data.shadow_pixel_size);
+	vec2 tap = textureGather(sampler2D(shadow_atlas_texture, shadow_sampler), unit_p.xy).zw;
+	return mix(step(tap.y, depth), step(tap.x, depth), fx);
+}
+
 #GLOBALS
 
 #ifdef LIGHT_CODE_USED
@@ -396,32 +407,32 @@ vec4 light_shadow_compute(uint light_base, vec4 light_color, vec4 shadow_uv
 	uint shadow_mode = light_array.data[light_base].flags & LIGHT_FLAGS_FILTER_MASK;
 
 	if (shadow_mode == LIGHT_FLAGS_SHADOW_NEAREST) {
-		shadow = textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
+		shadow = texture_shadow(shadow_uv);
 	} else if (shadow_mode == LIGHT_FLAGS_SHADOW_PCF5) {
 		vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
 		shadow = 0.0;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
+		shadow += texture_shadow(shadow_uv - shadow_pixel_size * 2.0);
+		shadow += texture_shadow(shadow_uv - shadow_pixel_size);
+		shadow += texture_shadow(shadow_uv);
+		shadow += texture_shadow(shadow_uv + shadow_pixel_size);
+		shadow += texture_shadow(shadow_uv + shadow_pixel_size * 2.0);
 		shadow /= 5.0;
 	} else { //PCF13
 		vec4 shadow_pixel_size = vec4(light_array.data[light_base].shadow_pixel_size, 0.0, 0.0, 0.0);
 		shadow = 0.0;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 6.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 5.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 4.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 3.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size * 2.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv - shadow_pixel_size, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 2.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 3.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 4.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 5.0, 0.0).x;
-		shadow += textureProjLod(sampler2DShadow(shadow_atlas_texture, shadow_sampler), shadow_uv + shadow_pixel_size * 6.0, 0.0).x;
+		shadow += texture_shadow(shadow_uv - shadow_pixel_size * 6.0);
+		shadow += texture_shadow(shadow_uv - shadow_pixel_size * 5.0);
+		shadow += texture_shadow(shadow_uv - shadow_pixel_size * 4.0);
+		shadow += texture_shadow(shadow_uv - shadow_pixel_size * 3.0);
+		shadow += texture_shadow(shadow_uv - shadow_pixel_size * 2.0);
+		shadow += texture_shadow(shadow_uv - shadow_pixel_size);
+		shadow += texture_shadow(shadow_uv);
+		shadow += texture_shadow(shadow_uv + shadow_pixel_size);
+		shadow += texture_shadow(shadow_uv + shadow_pixel_size * 2.0);
+		shadow += texture_shadow(shadow_uv + shadow_pixel_size * 3.0);
+		shadow += texture_shadow(shadow_uv + shadow_pixel_size * 4.0);
+		shadow += texture_shadow(shadow_uv + shadow_pixel_size * 5.0);
+		shadow += texture_shadow(shadow_uv + shadow_pixel_size * 6.0);
 		shadow /= 13.0;
 	}
 

+ 1 - 1
servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl

@@ -109,8 +109,8 @@ layout(set = 0, binding = 1, std140) uniform CanvasData {
 
 	uint directional_light_count;
 	float tex_to_sdf;
+	float shadow_pixel_size;
 	uint flags;
-	uint pad2;
 }
 canvas_data;