From ea2746d46844bf8132028c017f23a70c4bb689bd Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 24 Oct 2023 14:49:09 +0200 Subject: [PATCH] Fix #113235: Voronoi GLSL Shaders On Legacy Intel When using Voronoi shader nodes on legacy Intel platforms (HD4400) Blender would crash due to a driver bug. The bug is related to generating the `fractal_voronoi_x_fx` functions. It doesn't effect all drivers, but mainly from vendors that don't allow installing the official intel drivers. We have tried several approaches including using unique function names and unroll only the function of the body. But none worked on the failing platform. In the future we could solve this by including our own GLSL compiler, but that is still very experimental and requires a lot of testing.#113938 Pull Request: https://projects.blender.org/blender/blender/pulls/113834 --- .../gpu_shader_material_fractal_voronoi.glsl | 314 ++++++++++++++---- 1 file changed, 247 insertions(+), 67 deletions(-) diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_voronoi.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_voronoi.glsl index c8f70256823..8da27d6715a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_fractal_voronoi.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_fractal_voronoi.glsl @@ -6,69 +6,9 @@ #pragma BLENDER_REQUIRE(gpu_shader_common_math_utils.glsl) #pragma BLENDER_REQUIRE(gpu_shader_material_voronoi.glsl) -/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced - * by lerps. */ -#define FRACTAL_VORONOI_X_FX(T) \ - VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, T coord) \ - { \ - float amplitude = 1.0; \ - float max_amplitude = 0.0; \ - float scale = 1.0; \ -\ - VoronoiOutput Output; \ - Output.Distance = 0.0; \ - Output.Color = vec3(0.0, 0.0, 0.0); \ - Output.Position = vec4(0.0, 0.0, 0.0, 0.0); \ - bool zero_input = params.detail == 0.0 || params.roughness == 0.0; \ -\ - for (int i = 0; i <= ceil(params.detail); ++i) { \ - VoronoiOutput octave; \ - if (params.feature == SHD_VORONOI_F2) { \ - octave = voronoi_f2(params, coord * scale); \ - } \ - else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) { \ - octave = voronoi_smooth_f1(params, coord * scale); \ - } \ - else { \ - octave = voronoi_f1(params, coord * scale); \ - } \ -\ - if (zero_input) { \ - max_amplitude = 1.0; \ - Output = octave; \ - break; \ - } \ - else if (i <= params.detail) { \ - max_amplitude += amplitude; \ - Output.Distance += octave.Distance * amplitude; \ - Output.Color += octave.Color * amplitude; \ - Output.Position = mix(Output.Position, octave.Position / scale, amplitude); \ - scale *= params.lacunarity; \ - amplitude *= params.roughness; \ - } \ - else { \ - float remainder = params.detail - floor(params.detail); \ - if (remainder != 0.0) { \ - max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); \ - Output.Distance = mix( \ - Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); \ - Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); \ - Output.Position = mix(Output.Position, \ - mix(Output.Position, octave.Position / scale, amplitude), \ - remainder); \ - } \ - } \ - } \ -\ - if (params.normalize) { \ - Output.Distance /= max_amplitude * params.max_distance; \ - Output.Color /= max_amplitude; \ - } \ -\ - Output.Position = safe_divide(Output.Position, params.scale); \ -\ - return Output; \ - } +/* TODO(jbakker): Deduplicate code when OpenGL backend has been removed. + * `fractal_voronoi_x_fx` functions are identical, except for the input parameter. + * It used to be a macro, but didn't work on legacy drivers. */ /* The fractalization logic is the same as for fBM Noise, except that some additions are replaced * by lerps. */ @@ -115,24 +55,264 @@ /* **** 1D Fractal Voronoi **** */ -FRACTAL_VORONOI_X_FX(float) +/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced + * by lerps. */ +VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, float coord) +{ + float amplitude = 1.0; + float max_amplitude = 0.0; + float scale = 1.0; + + VoronoiOutput Output; + Output.Distance = 0.0; + Output.Color = vec3(0.0, 0.0, 0.0); + Output.Position = vec4(0.0, 0.0, 0.0, 0.0); + bool zero_input = params.detail == 0.0 || params.roughness == 0.0; + + for (int i = 0; i <= ceil(params.detail); ++i) { + VoronoiOutput octave; + if (params.feature == SHD_VORONOI_F2) { + octave = voronoi_f2(params, coord * scale); + } + else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) { + octave = voronoi_smooth_f1(params, coord * scale); + } + else { + octave = voronoi_f1(params, coord * scale); + } + + if (zero_input) { + max_amplitude = 1.0; + Output = octave; + break; + } + else if (i <= params.detail) { + max_amplitude += amplitude; + Output.Distance += octave.Distance * amplitude; + Output.Color += octave.Color * amplitude; + Output.Position = mix(Output.Position, octave.Position / scale, amplitude); + scale *= params.lacunarity; + amplitude *= params.roughness; + } + else { + float remainder = params.detail - floor(params.detail); + if (remainder != 0.0) { + max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); + Output.Distance = mix( + Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); + Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); + Output.Position = mix( + Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder); + } + } + } + + if (params.normalize) { + Output.Distance /= max_amplitude * params.max_distance; + Output.Color /= max_amplitude; + } + + Output.Position = safe_divide(Output.Position, params.scale); + + return Output; +} FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(float) /* **** 2D Fractal Voronoi **** */ -FRACTAL_VORONOI_X_FX(vec2) +/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced + * by lerps. */ +VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, vec2 coord) +{ + float amplitude = 1.0; + float max_amplitude = 0.0; + float scale = 1.0; + + VoronoiOutput Output; + Output.Distance = 0.0; + Output.Color = vec3(0.0, 0.0, 0.0); + Output.Position = vec4(0.0, 0.0, 0.0, 0.0); + bool zero_input = params.detail == 0.0 || params.roughness == 0.0; + + for (int i = 0; i <= ceil(params.detail); ++i) { + VoronoiOutput octave; + if (params.feature == SHD_VORONOI_F2) { + octave = voronoi_f2(params, coord * scale); + } + else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) { + octave = voronoi_smooth_f1(params, coord * scale); + } + else { + octave = voronoi_f1(params, coord * scale); + } + + if (zero_input) { + max_amplitude = 1.0; + Output = octave; + break; + } + else if (i <= params.detail) { + max_amplitude += amplitude; + Output.Distance += octave.Distance * amplitude; + Output.Color += octave.Color * amplitude; + Output.Position = mix(Output.Position, octave.Position / scale, amplitude); + scale *= params.lacunarity; + amplitude *= params.roughness; + } + else { + float remainder = params.detail - floor(params.detail); + if (remainder != 0.0) { + max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); + Output.Distance = mix( + Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); + Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); + Output.Position = mix( + Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder); + } + } + } + + if (params.normalize) { + Output.Distance /= max_amplitude * params.max_distance; + Output.Color /= max_amplitude; + } + + Output.Position = safe_divide(Output.Position, params.scale); + + return Output; +} FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec2) /* **** 3D Fractal Voronoi **** */ -FRACTAL_VORONOI_X_FX(vec3) +/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced + * by lerps. */ +VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, vec3 coord) +{ + float amplitude = 1.0; + float max_amplitude = 0.0; + float scale = 1.0; + + VoronoiOutput Output; + Output.Distance = 0.0; + Output.Color = vec3(0.0, 0.0, 0.0); + Output.Position = vec4(0.0, 0.0, 0.0, 0.0); + bool zero_input = params.detail == 0.0 || params.roughness == 0.0; + + for (int i = 0; i <= ceil(params.detail); ++i) { + VoronoiOutput octave; + if (params.feature == SHD_VORONOI_F2) { + octave = voronoi_f2(params, coord * scale); + } + else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) { + octave = voronoi_smooth_f1(params, coord * scale); + } + else { + octave = voronoi_f1(params, coord * scale); + } + + if (zero_input) { + max_amplitude = 1.0; + Output = octave; + break; + } + else if (i <= params.detail) { + max_amplitude += amplitude; + Output.Distance += octave.Distance * amplitude; + Output.Color += octave.Color * amplitude; + Output.Position = mix(Output.Position, octave.Position / scale, amplitude); + scale *= params.lacunarity; + amplitude *= params.roughness; + } + else { + float remainder = params.detail - floor(params.detail); + if (remainder != 0.0) { + max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); + Output.Distance = mix( + Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); + Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); + Output.Position = mix( + Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder); + } + } + } + + if (params.normalize) { + Output.Distance /= max_amplitude * params.max_distance; + Output.Color /= max_amplitude; + } + + Output.Position = safe_divide(Output.Position, params.scale); + + return Output; +} FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec3) /* **** 4D Fractal Voronoi **** */ -FRACTAL_VORONOI_X_FX(vec4) +/* The fractalization logic is the same as for fBM Noise, except that some additions are replaced + * by lerps. */ +VoronoiOutput fractal_voronoi_x_fx(VoronoiParams params, vec4 coord) +{ + float amplitude = 1.0; + float max_amplitude = 0.0; + float scale = 1.0; + + VoronoiOutput Output; + Output.Distance = 0.0; + Output.Color = vec3(0.0, 0.0, 0.0); + Output.Position = vec4(0.0, 0.0, 0.0, 0.0); + bool zero_input = params.detail == 0.0 || params.roughness == 0.0; + + for (int i = 0; i <= ceil(params.detail); ++i) { + VoronoiOutput octave; + if (params.feature == SHD_VORONOI_F2) { + octave = voronoi_f2(params, coord * scale); + } + else if (params.feature == SHD_VORONOI_SMOOTH_F1 && params.smoothness != 0.0) { + octave = voronoi_smooth_f1(params, coord * scale); + } + else { + octave = voronoi_f1(params, coord * scale); + } + + if (zero_input) { + max_amplitude = 1.0; + Output = octave; + break; + } + else if (i <= params.detail) { + max_amplitude += amplitude; + Output.Distance += octave.Distance * amplitude; + Output.Color += octave.Color * amplitude; + Output.Position = mix(Output.Position, octave.Position / scale, amplitude); + scale *= params.lacunarity; + amplitude *= params.roughness; + } + else { + float remainder = params.detail - floor(params.detail); + if (remainder != 0.0) { + max_amplitude = mix(max_amplitude, max_amplitude + amplitude, remainder); + Output.Distance = mix( + Output.Distance, Output.Distance + octave.Distance * amplitude, remainder); + Output.Color = mix(Output.Color, Output.Color + octave.Color * amplitude, remainder); + Output.Position = mix( + Output.Position, mix(Output.Position, octave.Position / scale, amplitude), remainder); + } + } + } + + if (params.normalize) { + Output.Distance /= max_amplitude * params.max_distance; + Output.Color /= max_amplitude; + } + + Output.Position = safe_divide(Output.Position, params.scale); + + return Output; +} FRACTAL_VORONOI_DISTANCE_TO_EDGE_FUNCTION(vec4)