GPU Codegen: Add new closure socket type.
authorClément Foucault <foucault.clem@gmail.com>
Mon, 3 Jul 2017 19:39:52 +0000 (21:39 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Mon, 3 Jul 2017 20:08:33 +0000 (22:08 +0200)
This allow specialized shaders to redefine the closure interface to fit their needs.

For instance, Volumetric closure needs to pass more than one vec4 (absorption vec3, scattering vec3, anisotropy float).

source/blender/gpu/GPU_material.h
source/blender/gpu/intern/gpu_codegen.c
source/blender/gpu/intern/gpu_material.c
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/nodes/shader/node_shader_util.c

index b12a59f607d2d79f1a21f406364573169efc1a13..ec50bd9d9f5481bc2a3a1d1ac01ebbf088f1a22d 100644 (file)
@@ -76,6 +76,8 @@ typedef enum GPUType {
        GPU_MAT3 = 9,
        GPU_MAT4 = 16,
 
+       GPU_CLOSURE = 17,
+
        GPU_TEX2D = 1002,
        GPU_SHADOW2D = 1003,
        GPU_TEXCUBE = 1004,
index 87fbccc0c87edb195a4f119ba1dc8507685c6163..cd367c821bad22c9a8cb42200b7203909553de7e 100644 (file)
@@ -86,9 +86,10 @@ typedef struct GPUFunction {
 } GPUFunction;
 
 /* Indices match the GPUType enum */
-static const char *GPU_DATATYPE_STR[17] = {
+static const char *GPU_DATATYPE_STR[18] = {
        "", "float", "vec2", "vec3", "vec4",
        NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4",
+       "Closure"
 };
 
 /* GLSL code parsing for finding function definitions.
@@ -172,7 +173,7 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
 
                        /* test for type */
                        type = GPU_NONE;
-                       for (i = 1; i <= 16; i++) {
+                       for (i = 1; i <= 17; i++) {
                                if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) {
                                        type = i;
                                        break;
@@ -350,6 +351,8 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
                        BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name);
                else if (from == GPU_FLOAT)
                        BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name);
+               else /* can happen with closure */
+                       BLI_dynstr_append(ds, name);
        }
 }
 
@@ -357,6 +360,11 @@ static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
 {
        int i;
 
+       if (type == GPU_CLOSURE) {
+               BLI_dynstr_append(ds, "CLOSURE_DEFAULT");
+               return;
+       }
+
        BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]);
 
        for (i = 0; i < type; i++) {
@@ -543,9 +551,16 @@ static int codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes)
                                                GPU_DATATYPE_STR[input->type], input->id);
                                }
                                else {
-                                       /* for others use const so the compiler can do folding */
-                                       BLI_dynstr_appendf(ds, "const %s cons%d = ",
-                                               GPU_DATATYPE_STR[input->type], input->id);
+                                       if (input->type != GPU_CLOSURE) {
+                                               /* for others use const so the compiler can do folding */
+                                               BLI_dynstr_appendf(ds, "const %s cons%d = ",
+                                                       GPU_DATATYPE_STR[input->type], input->id);
+                                       }
+                                       else {
+                                               /* const keyword does not work with struct */
+                                               BLI_dynstr_appendf(ds, "%s cons%d = ",
+                                                       GPU_DATATYPE_STR[input->type], input->id);
+                                       }
                                        codegen_print_datatype(ds, input->type, input->vec);
                                        BLI_dynstr_append(ds, ";\n");
                                }
@@ -667,8 +682,7 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
                BLI_dynstr_append(ds, ");\n");
        }
 
-       BLI_dynstr_append(ds, "\n\tfragColor = ");
-       codegen_convert_datatype(ds, finaloutput->type, GPU_VEC4, "tmp", finaloutput->id);
+       BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id);
        BLI_dynstr_append(ds, ";\n");
 }
 
@@ -696,7 +710,7 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, bool use
                BLI_dynstr_appendf(ds, "/* %s */\n", name);
 #endif
 
-       BLI_dynstr_append(ds, "void main()\n{\n");
+       BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n");
 
        if (use_new_shading) {
                if (builtins & GPU_VIEW_MATRIX)
@@ -764,6 +778,17 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, bool use
 
        BLI_dynstr_append(ds, "}\n");
 
+       /* XXX This cannot go into gpu_shader_material.glsl because main() would be parsed and generate error */
+       /* Old glsl mode compat. */
+       BLI_dynstr_append(ds, "#ifndef NODETREE_EXEC\n");
+       BLI_dynstr_append(ds, "out vec4 fragColor;\n");
+       BLI_dynstr_append(ds, "void main()\n");
+       BLI_dynstr_append(ds, "{\n");
+       BLI_dynstr_append(ds, "\tClosure cl = nodetree_exec();\n");
+       BLI_dynstr_append(ds, "\tfragColor = vec4(cl.radiance, cl.opacity);\n");
+       BLI_dynstr_append(ds, "}\n");
+       BLI_dynstr_append(ds, "#endif\n\n");
+
        /* create shader */
        code = BLI_dynstr_get_cstring(ds);
        BLI_dynstr_free(ds);
index dafd305e8ba0ac4a7fa7e52b5df99bc395d2d9f0..40d1acfabd10871938184d6a72a5c7bc2bb64e8f 100644 (file)
@@ -2366,6 +2366,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
                                        case GPU_VEC4:
                                        case GPU_MAT3:
                                        case GPU_MAT4:
+                                       case GPU_CLOSURE:
                                        case GPU_ATTRIB:
                                                break;
                                }
@@ -2394,6 +2395,7 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
                                                break;
 
                                        case GPU_NONE:
+                                       case GPU_CLOSURE:
                                        case GPU_TEX2D:
                                        case GPU_TEXCUBE:
                                        case GPU_SHADOW2D:
index 1f9ab45e556e952abf45538d2292275bc1c145d4..afe862bb70fe0aa7f31440a1ee879904674cb5de 100644 (file)
@@ -12,7 +12,37 @@ uniform mat4 ProjectionMatrixInverse;
 uniform mat3 NormalMatrix;
 uniform vec4 CameraTexCoFactors;
 
-out vec4 fragColor;
+/* Old glsl mode compat. */
+
+#ifndef NODETREE_EXEC
+
+struct Closure {
+       vec3 radiance;
+       float opacity;
+};
+
+#define CLOSURE_DEFAULT Closure(vec3(0.0), 0.0);
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+       Closure cl;
+       cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
+       cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
+       return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+       Closure cl;
+       cl.radiance = cl1.radiance + cl2.radiance;
+       cl.opacity = cl1.opacity + cl2.opacity;
+       return cl;
+}
+
+Closure nodetree_exec(void); /* Prototype */
+
+#endif /* NODETREE_EXEC */
+
 
 /* Converters */
 
@@ -2625,7 +2655,7 @@ layout(std140) uniform lightSource {
 
 /* bsdfs */
 
-void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
+void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
 {
        /* ambient light */
        vec3 L = vec3(0.2);
@@ -2639,10 +2669,10 @@ void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
                L += light_diffuse * bsdf;
        }
 
-       result = vec4(L * color.rgb, 1.0);
+       result = Closure(L * color.rgb, 1.0);
 }
 
-void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
+void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out Closure result)
 {
        /* ambient light */
        vec3 L = vec3(0.2);
@@ -2660,29 +2690,29 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
                L += light_specular * bsdf;
        }
 
-       result = vec4(L * color.rgb, 1.0);
+       result = Closure(L * color.rgb, 1.0);
 }
 
 void node_bsdf_anisotropic(
         vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
-        out vec4 result)
+        out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
-void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
+void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
-void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 result)
+void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
 void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
        float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
-       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
+       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result)
 {
        vec3 X, Y;
        float ax, ay;
@@ -2775,18 +2805,18 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad
                L += diffuse_and_specular_bsdf + clearcoat_bsdf;
        }
 
-       result = vec4(L, 1.0);
+       result = Closure(L, 1.0);
 }
 
 void node_bsdf_principled_simple(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
        float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
-       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
+       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result)
 {
 #ifdef EEVEE_ENGINE
        vec3 diffuse, f0;
        convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
 
-       result = vec4(eevee_surface_lit(N, diffuse, f0, roughness, 1.0), 1.0);
+       result = Closure(eevee_surface_lit(N, diffuse, f0, roughness, 1.0), 1.0);
 #else
        node_bsdf_principled(base_color, subsurface, subsurface_radius, subsurface_color, metallic, specular,
                specular_tint, roughness, anisotropic, anisotropic_rotation, sheen, sheen_tint, clearcoat,
@@ -2796,7 +2826,7 @@ void node_bsdf_principled_simple(vec4 base_color, float subsurface, vec3 subsurf
 
 void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
        float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
-       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
+       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result)
 {
 #ifdef EEVEE_ENGINE
        vec3 diffuse, f0;
@@ -2825,9 +2855,9 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs
                        surface_color.a += 1.0;
                }
        }
-       result = vec4(surface_color.rgb / surface_color.a, 1.0);
+       result = Closure(surface_color.rgb / surface_color.a, 1.0);
 #else
-       result = vec4(eevee_surface_clearcoat_lit(N, diffuse, f0, roughness, CN, clearcoat, clearcoat_roughness, 1.0), 1.0);
+       result = Closure(eevee_surface_clearcoat_lit(N, diffuse, f0, roughness, CN, clearcoat, clearcoat_roughness, 1.0), 1.0);
 #endif
 
 #else
@@ -2837,52 +2867,51 @@ void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subs
 #endif
 }
 
-void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
+void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
-void node_bsdf_transparent(vec4 color, out vec4 result)
+void node_bsdf_transparent(vec4 color, out Closure result)
 {
        /* this isn't right */
-       result.r = color.r;
-       result.g = color.g;
-       result.b = color.b;
-       result.a = 0.0;
+       result.radiance = color.rgb;
+       result.opacity = 0.0;
 }
 
-void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result)
+void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
 void node_subsurface_scattering(
         vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N,
-        out vec4 result)
+        out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
-void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out vec4 result)
+void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out Closure result)
 {
-       result = color;
+       result = Closure(color.rgb, color.a);
 }
 
-void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
+void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
-void node_ambient_occlusion(vec4 color, out vec4 result)
+void node_ambient_occlusion(vec4 color, out Closure result)
 {
-       result = color;
+       result = Closure(color.rgb, color.a);
 }
 
 /* emission */
 
-void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
+void node_emission(vec4 color, float strength, vec3 N, out Closure result)
 {
-       result = color * strength;
+       color *= strength;
+       result = Closure(color.rgb, color.a);
 }
 
 /* background */
@@ -2900,21 +2929,22 @@ void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
 #endif
 }
 
-void node_background(vec4 color, float strength, out vec4 result)
+void node_background(vec4 color, float strength, out Closure result)
 {
-       result = color * strength;
+       color *= strength;
+       result = Closure(color.rgb, color.a);
 }
 
 /* closures */
 
-void node_mix_shader(float fac, vec4 shader1, vec4 shader2, out vec4 shader)
+void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
 {
-       shader = mix(shader1, shader2, fac);
+       shader = closure_mix(shader1, shader2, fac);
 }
 
-void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
+void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
 {
-       shader = shader1 + shader2;
+       shader = closure_add(shader1, shader2);
 }
 
 /* fresnel */
@@ -3908,16 +3938,16 @@ void node_bump(float strength, float dist, float height, vec3 N, vec3 surf_pos,
 
 /* output */
 
-void node_output_material(vec4 surface, vec4 volume, float displacement, out vec4 result)
+void node_output_material(Closure surface, Closure volume, float displacement, out Closure result)
 {
        result = surface;
 }
 
 uniform float backgroundAlpha;
 
-void node_output_world(vec4 surface, vec4 volume, out vec4 result)
+void node_output_world(Closure surface, Closure volume, out Closure result)
 {
-       result = vec4(surface.rgb, backgroundAlpha);
+       result = Closure(surface.radiance, backgroundAlpha);
 }
 
 /* TODO : clean this ifdef mess */
@@ -3931,25 +3961,25 @@ void world_normals_get(out vec3 N)
 void node_eevee_metallic(
         vec4 basecol, float metallic, float specular, float roughness, vec4 emissive, float transp, vec3 normal,
         float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal,
-        float occlusion, out vec4 result)
+        float occlusion, out Closure result)
 {
        vec3 diffuse, f0;
        convert_metallic_to_specular(basecol.rgb, metallic, specular, diffuse, f0);
 
-       result = vec4(eevee_surface_lit(normal, diffuse, f0, roughness, occlusion) + emissive.rgb, 1.0 - transp);
+       result = Closure(eevee_surface_lit(normal, diffuse, f0, roughness, occlusion) + emissive.rgb, 1.0 - transp);
 }
 
 void node_eevee_specular(
         vec4 diffuse, vec4 specular, float roughness, vec4 emissive, float transp, vec3 normal,
         float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal,
-        float occlusion, out vec4 result)
+        float occlusion, out Closure result)
 {
-       result = vec4(eevee_surface_lit(normal, diffuse.rgb, specular.rgb, roughness, occlusion) + emissive.rgb, 1.0 - transp);
+       result = Closure(eevee_surface_lit(normal, diffuse.rgb, specular.rgb, roughness, occlusion) + emissive.rgb, 1.0 - transp);
 }
 
-void node_output_eevee_material(vec4 surface, out vec4 result)
+void node_output_eevee_material(Closure surface, out Closure result)
 {
-       result = vec4(surface.rgb, length(viewPosition));
+       result = Closure(surface.radiance, length(viewPosition));
 }
 
 #endif
index 5bc97f13b41125fd4a5088fdb21030723786e711..8559765e31510529fe9f8d14f15497709e2dfbe8 100644 (file)
@@ -163,7 +163,7 @@ void node_gpu_stack_from_data(struct GPUNodeStack *gs, int type, bNodeStack *ns)
                else if (type == SOCK_RGBA)
                        gs->type = GPU_VEC4;
                else if (type == SOCK_SHADER)
-                       gs->type = GPU_VEC4;
+                       gs->type = GPU_CLOSURE;
                else
                        gs->type = GPU_NONE;