godot icon indicating copy to clipboard operation
godot copied to clipboard

Vulkan canvas_item shader different to GLS3

Open Lippanon opened this issue 2 years ago • 17 comments

Godot version

v4.0.beta.custom_build [380fba627]

System information

Windows 10, Vulkan

Issue description

Porting projects with complex shaders from 3.x GLS3 to 4.x Vulkan, trying to fix what appears broken. I've tried to strip it down to simpler parts that still showcase the issue. A ShaderMaterial applied to a ColorRect. None of the 'texture_filter' options seem to have any impact, nor 'texture_repeat' options in the node (which makes sense to me when directly modifying 'COLOR' in a canvas_item). Godot 3.5: image

Godot 4 [380fba627]: image

I've tried different render modes to no avail, maybe there's a project setting I'm missing. I know 'MODULATE' is gone and 'COLOR' has new behaviour but it doesn't seem related.

Steps to reproduce

Same shader code on both projects:

shader_type canvas_item;

float hash12(vec2 p) {
	return fract(sin(dot(p, vec2(12.9898,12.1414))) * 83758.5453);
}

float noise(vec2 n) {
	vec2 v2_floor = floor(n);
	vec2 v2_fract = fract(n);
	float m1 = mix(hash12(v2_floor), hash12(v2_floor + vec2(1.0, 0.0)), v2_fract.x);
	float m2 = mix(hash12(v2_floor + vec2(0.0, 1.0)), hash12(v2_floor + vec2(1.0)), v2_fract.x);
	float m3 = mix(m1, m2, v2_fract.y);
	return m3;
}

void fragment() {
	vec2 v_uv = UV*5.0;
	float n = noise(v_uv);
	COLOR = vec4(n);
}

Minimal reproduction project

Shader Issue 4.x.zip Shader Issue 3.x.zip

Lippanon avatar Oct 09 '22 18:10 Lippanon

Likely related to the fact that COLOR behavior is different in 4.0

Zireael07 avatar Oct 09 '22 18:10 Zireael07

Present in v4.0.beta.custom_build [204715ae9]

I don't think it's related to COLOR, but I could be wrong. It's as if the UV is being degraded over time quickly, which is a problem with shaders that use TIME. I've updated the MRP to use a better hash by default and show the problem in a different way (also removed the .godot folders, sorry about that).

Does Vulkan use different float precision on shaders by default? I've tried enforcing highp but the result is the same... don't know what else to try.

4.x: image

3.x: image

New MRPs (also edited in OP): Shader Issue 4.x.zip Shader Issue 3.x.zip

Lippanon avatar Dec 08 '22 19:12 Lippanon

I can't reproduce the issue on an intel integrated GPU with PopOS 22.04 and running current master f692b476869c14023b342c12efc21cb5cd6002b7

The result looks fine: Screenshot from 2022-12-08 12-13-37

clayjohn avatar Dec 08 '22 20:12 clayjohn

I can't reproduce the issue on an intel integrated GPU with PopOS 22.04 and running current master [f692b47]

Can you post a pic from the new MRP, please? I see the issues on a GTX 970.

Lippanon avatar Dec 08 '22 20:12 Lippanon

@Lippanon

Screenshot from 2022-12-08 12-25-03

clayjohn avatar Dec 08 '22 20:12 clayjohn

Thank you, I'll try updating my drivers and followup later.

Lippanon avatar Dec 08 '22 20:12 Lippanon

It could be an issue from using sin in the hash function see e.g. https://www.shadertoy.com/view/4djSRW

clayjohn avatar Dec 08 '22 20:12 clayjohn

It could be an issue from using sin in the hash function see e.g. https://www.shadertoy.com/view/4djSRW

If you notice the new MRP, it's using a different hash for that reason, without sin. I left the older hash for archive reasons, but it's not in use.

Had a friend test on his GTX 1070, Windows 10: image

Also broken for them.

Lippanon avatar Dec 08 '22 20:12 Lippanon

@Lippanon Can you test the same shader in shadertoy to see if you get the issue there as well?

here is the code converted to shadertoy:

float hash12(vec2 p) {
	return fract(sin(dot(p, vec2(12.9898,12.1414))) * 83758.5453);
}

float noise(vec2 n) {
	vec2 v2_floor = floor(n);
	vec2 v2_fract = fract(n);
	float m1 = mix(hash12(v2_floor), hash12(v2_floor + vec2(1.0, 0.0)), v2_fract.x);
	float m2 = mix(hash12(v2_floor + vec2(0.0, 1.0)), hash12(v2_floor + vec2(1.0)), v2_fract.x);
	float m3 = mix(m1, m2, v2_fract.y);
	return m3;
}

vec4 fragment(vec2 UV) {
	vec2 v_uv = UV*15.0;
	float n = noise(v_uv);
	return vec4(n);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    // Output to screen
    fragColor = fragment(uv);
}

clayjohn avatar Dec 08 '22 21:12 clayjohn

@clayjohn Here's my output on shadertoy with that code: image

It does appear correct in shadertoy. I also tested other variants that appear broken for me in 4.x, and they also seem correct in shadertoy.

Lippanon avatar Dec 08 '22 23:12 Lippanon

This happens to me. Tested in Godot 3.5.1 (GLES3), Godot 4.0 (Vulkan, GLES3), even with a GLSL shader compiled via RenderingDevice. Same result.

Adding a non-constant term to the hash function makes it work

float hash12(vec2 p) {
	p += min(TIME,0.0);
	return fract(sin(dot(p, vec2(12.9898,12.1414))) * 83758.5453);
}

celyk avatar Mar 03 '23 12:03 celyk

This happens to me. Tested in Godot 3.5.1 (GLES3), Godot 4.0 (Vulkan, GLES3), even with a GLSL shader compiled via RenderingDevice. Same result.

Adding a non-constant term to the hash function makes it work

float hash12(vec2 p) {
	p += min(TIME,0.0);
	return fract(sin(dot(p, vec2(12.9898,12.1414))) * 83758.5453);
}

Thank you for the temp fix! I confirm that does work for me also, it fixes the artifacts. Pinging @clayjohn to let you know.

Lippanon avatar Mar 04 '23 09:03 Lippanon

Has anyone tested this on newer Nvidia GPUs? (16 series, 20 series, 30 series and 40 series)

mrjustaguy avatar Mar 10 '23 09:03 mrjustaguy

It seems to be be happening on newer Nvidia GPUs. We are working on a sky_shader for Godot 4 Stable with another developper, he's on a 10 series and have no glitches. The same fresh project with his shader glitches the same way and i have a RTX 3080.

RemyCampanals avatar Mar 10 '23 14:03 RemyCampanals

What driver version is he using?

also @Lippanon what driver is the 1070 on?

mrjustaguy avatar Mar 10 '23 15:03 mrjustaguy

image Not the latest (It's actually 531.18), but one of the latest. I'll try update my drivers to see if it change anything.

RemyCampanals avatar Mar 10 '23 15:03 RemyCampanals

Just to update everyone on this issue. This is an NVidia Vulkan driver bug. I'm glad to here users have found a workaround, because there isn't really anything we can do. We just pass the shader code off to the GPU driver to compile.

Other people experience this same bug and NVidia hasnt done anything about it https://github.com/danilw/GPU-my-list-of-bugs and https://www.shadertoy.com/view/stK3WG

Just a note about the workaround, if used in a sky shader another value other than TIME should be used as using TIME will force sky shaders to update reflections each frame which is a costly operation.

clayjohn avatar Mar 10 '23 17:03 clayjohn

The issue here originates from the line: fract(sin(dot(p, vec2(12.9898,12.1414))) * 83758.5453);. From what I have read, each manufacturer, and even each version of driver has different ways to handle sin(), and is generally inaccurate, causing these issues. If you are experiencing this issue on compute shaders, you can try p += min(float(gl_LocalInvocationID), 0.0);, in my case with a 1070, it solved the problem.

I recently upgraded to a Radeon card, and had similar issues, which were not resolved by the aforementioned workaround. Instead, I had to use a different hash function that omits the use of sin() entirely.

Here is the function I used:

float hash_fract(vec2 p) {
    p  = fract( p*0.3183099+.1 );
    p *= 17.0;
    return -1.+2.*fract( p.x*p.y*(p.x+p.y) );
}

addmix avatar Sep 29 '23 04:09 addmix

As already stated in https://github.com/godotengine/godot/issues/67150#issuecomment-1343330054, it also happens when using sinless hashes. The MRP is using a sinless hash. Celyk's non-constant term work-around works perfectly with any hash I've tested aswell.

Lippanon avatar Sep 29 '23 07:09 Lippanon

I only mention it because despite using the p += min(float(gl_LocalInvocationID), 0.0);, I still had the same issue while using a 7900XTX, where the issue was resolved by that workaround on my 1070.

addmix avatar Sep 29 '23 08:09 addmix