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
This commit is contained in:
Jeroen Bakker 2023-10-24 14:49:09 +02:00
parent cdbde7d941
commit ea2746d468
1 changed files with 247 additions and 67 deletions

View File

@ -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)