diff options
author | Jason Fielder <jason_apple> | 2022-04-14 12:47:52 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-04-14 12:49:18 +0300 |
commit | b0dc3aff2c73f2a1b65406dcb7fe73c95b9485ed (patch) | |
tree | 29642f7e85e2f5189549c1710854c421463a2e0d /source/blender/draw/engines/workbench | |
parent | d62f443f2d0b464131f77f770f9aa19d81164f0c (diff) |
Metal: GLSL shader compatibility 3rd pass
Undefined behaviour for divergent control-flow fixes, replacement for partial vector references, and resolution of a number of calculation precision issues occuring on macOS.
Authored by Apple: Michael Parkin-White
Ref: T96261
Reviewed By: fclem
Differential Revision: https://developer.blender.org/D14437
Diffstat (limited to 'source/blender/draw/engines/workbench')
3 files changed, 32 insertions, 8 deletions
diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl index 71cf08b7e8c..cfc94ef7c9a 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl @@ -8,8 +8,10 @@ /* From http://libnoise.sourceforge.net/noisegen/index.html */ float integer_noise(int n) { - n = (n >> 13) ^ n; - int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + /* Integer bit-shifts cause precision issues due to overflow + * in a number of workbench tests. Use uint instead. */ + uint nn = (uint(n) >> 13u) ^ uint(n); + nn = (nn * (nn * nn * 60493u + 19990303u) + 1376312589u) & 0x7fffffffu; return (float(nn) / 1073741824.0); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index 4ff281ccd29..36059b6076f 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -218,7 +218,15 @@ void main() /* Manual depth test. TODO: remove. */ float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r; if (gl_FragCoord.z >= depth) { + /* Note: In the Metal API, prior to Metal 2.3, Discard is not an explicit return and can + * produce undefined behaviour. This is especially prominent with derivatives if control-flow + * divergence is present. + * + * Adding a return call eliminates undefined behaviour and a later out-of-bounds read causing + * a crash on AMD platforms. + * This behaviour can also affect OpenGL on certain devices. */ discard; + return; } vec3 Lscat; @@ -268,6 +276,7 @@ void main() /* Start is further away than the end. * That means no volume is intersected. */ discard; + return; } fragColor = volume_integration(ls_ray_ori, diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index 531ed461057..20053b8917c 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -64,22 +64,35 @@ vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N if (world_data.use_specular) { /* Prepare Specular computation. Eval 4 lights at once. */ vec3 R = -reflect(I, N); + +#ifdef GPU_METAL + /* Split vectors into arrays of floats. Partial vector references are unsupported by MSL. */ + float spec_angle[4], spec_NL[4], wrap_NL[4]; +# define AS_VEC4(a) vec4(a[0], a[1], a[2], a[3]) +#else vec4 spec_angle, spec_NL, wrap_NL; - prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x); - prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y); - prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z); - prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w); +# define AS_VEC4(a) a +#endif + prep_specular( + world_data.lights[0].direction.xyz, I, N, R, spec_NL[0], wrap_NL[0], spec_angle[0]); + prep_specular( + world_data.lights[1].direction.xyz, I, N, R, spec_NL[1], wrap_NL[1], spec_angle[1]); + prep_specular( + world_data.lights[2].direction.xyz, I, N, R, spec_NL[2], wrap_NL[2], spec_angle[2]); + prep_specular( + world_data.lights[3].direction.xyz, I, N, R, spec_NL[3], wrap_NL[3], spec_angle[3]); vec4 gloss = vec4(1.0 - roughness); /* Reduce gloss for smooth light. (simulate bigger light) */ gloss *= 1.0 - wrap; vec4 shininess = exp2(10.0 * gloss + 1.0); - vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL); + vec4 spec_light = blinn_specular(shininess, AS_VEC4(spec_angle), AS_VEC4(spec_NL)); /* Simulate Env. light. */ vec4 w = mix(wrap, vec4(1.0), roughness); - vec4 spec_env = wrapped_lighting(wrap_NL, w); + vec4 spec_env = wrapped_lighting(AS_VEC4(wrap_NL), w); +#undef AS_VEC4 spec_light = mix(spec_light, spec_env, wrap * wrap); |