diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_codegen.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_codegen.c | 3362 |
1 files changed, 1694 insertions, 1668 deletions
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 84164045984..458c0d5da85 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -72,81 +72,100 @@ static SpinLock pass_cache_spin; static uint32_t gpu_pass_hash(const char *frag_gen, const char *defs, GPUVertAttrLayers *attrs) { - BLI_HashMurmur2A hm2a; - BLI_hash_mm2a_init(&hm2a, 0); - BLI_hash_mm2a_add(&hm2a, (uchar *)frag_gen, strlen(frag_gen)); - if (attrs) { - for (int att_idx = 0; att_idx < attrs->totlayer; att_idx++) { - char *name = attrs->layer[att_idx].name; - BLI_hash_mm2a_add(&hm2a, (uchar *)name, strlen(name)); - } - } - if (defs) - BLI_hash_mm2a_add(&hm2a, (uchar *)defs, strlen(defs)); - - return BLI_hash_mm2a_end(&hm2a); + BLI_HashMurmur2A hm2a; + BLI_hash_mm2a_init(&hm2a, 0); + BLI_hash_mm2a_add(&hm2a, (uchar *)frag_gen, strlen(frag_gen)); + if (attrs) { + for (int att_idx = 0; att_idx < attrs->totlayer; att_idx++) { + char *name = attrs->layer[att_idx].name; + BLI_hash_mm2a_add(&hm2a, (uchar *)name, strlen(name)); + } + } + if (defs) + BLI_hash_mm2a_add(&hm2a, (uchar *)defs, strlen(defs)); + + return BLI_hash_mm2a_end(&hm2a); } /* Search by hash only. Return first pass with the same hash. * There is hash collision if (pass->next && pass->next->hash == hash) */ static GPUPass *gpu_pass_cache_lookup(uint32_t hash) { - BLI_spin_lock(&pass_cache_spin); - /* Could be optimized with a Lookup table. */ - for (GPUPass *pass = pass_cache; pass; pass = pass->next) { - if (pass->hash == hash) { - BLI_spin_unlock(&pass_cache_spin); - return pass; - } - } - BLI_spin_unlock(&pass_cache_spin); - return NULL; + BLI_spin_lock(&pass_cache_spin); + /* Could be optimized with a Lookup table. */ + for (GPUPass *pass = pass_cache; pass; pass = pass->next) { + if (pass->hash == hash) { + BLI_spin_unlock(&pass_cache_spin); + return pass; + } + } + BLI_spin_unlock(&pass_cache_spin); + return NULL; } /* Check all possible passes with the same hash. */ -static GPUPass *gpu_pass_cache_resolve_collision( - GPUPass *pass, const char *vert, const char *geom, const char *frag, const char *defs, uint32_t hash) +static GPUPass *gpu_pass_cache_resolve_collision(GPUPass *pass, + const char *vert, + const char *geom, + const char *frag, + const char *defs, + uint32_t hash) { - BLI_spin_lock(&pass_cache_spin); - /* Collision, need to strcmp the whole shader. */ - for (; pass && (pass->hash == hash); pass = pass->next) { - if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ } - else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ } - else if ((strcmp(pass->fragmentcode, frag) == 0) && - (strcmp(pass->vertexcode, vert) == 0)) - { - BLI_spin_unlock(&pass_cache_spin); - return pass; - } - } - BLI_spin_unlock(&pass_cache_spin); - return NULL; + BLI_spin_lock(&pass_cache_spin); + /* Collision, need to strcmp the whole shader. */ + for (; pass && (pass->hash == hash); pass = pass->next) { + if ((defs != NULL) && (strcmp(pass->defines, defs) != 0)) { /* Pass */ + } + else if ((geom != NULL) && (strcmp(pass->geometrycode, geom) != 0)) { /* Pass */ + } + else if ((strcmp(pass->fragmentcode, frag) == 0) && (strcmp(pass->vertexcode, vert) == 0)) { + BLI_spin_unlock(&pass_cache_spin); + return pass; + } + } + BLI_spin_unlock(&pass_cache_spin); + return NULL; } /* -------------------- GPU Codegen ------------------ */ /* type definitions and constants */ -#define MAX_FUNCTION_NAME 64 -#define MAX_PARAMETER 32 +#define MAX_FUNCTION_NAME 64 +#define MAX_PARAMETER 32 typedef enum { - FUNCTION_QUAL_IN, - FUNCTION_QUAL_OUT, - FUNCTION_QUAL_INOUT, + FUNCTION_QUAL_IN, + FUNCTION_QUAL_OUT, + FUNCTION_QUAL_INOUT, } GPUFunctionQual; typedef struct GPUFunction { - char name[MAX_FUNCTION_NAME]; - eGPUType paramtype[MAX_PARAMETER]; - GPUFunctionQual paramqual[MAX_PARAMETER]; - int totparam; + char name[MAX_FUNCTION_NAME]; + eGPUType paramtype[MAX_PARAMETER]; + GPUFunctionQual paramqual[MAX_PARAMETER]; + int totparam; } GPUFunction; /* Indices match the eGPUType enum */ static const char *GPU_DATATYPE_STR[17] = { - "", "float", "vec2", "vec3", "vec4", - NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4", + "", + "float", + "vec2", + "vec3", + "vec4", + NULL, + NULL, + NULL, + NULL, + "mat3", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "mat4", }; /* GLSL code parsing for finding function definitions. @@ -160,219 +179,219 @@ static GPUShader *FUNCTION_LIB = NULL; static int gpu_str_prefix(const char *str, const char *prefix) { - while (*str && *prefix) { - if (*str != *prefix) - return 0; + while (*str && *prefix) { + if (*str != *prefix) + return 0; - str++; - prefix++; - } + str++; + prefix++; + } - return (*prefix == '\0'); + return (*prefix == '\0'); } static char *gpu_str_skip_token(char *str, char *token, int max) { - int len = 0; - - /* skip a variable/function name */ - while (*str) { - if (ELEM(*str, ' ', '(', ')', ',', ';', '\t', '\n', '\r')) - break; - else { - if (token && len < max - 1) { - *token = *str; - token++; - len++; - } - str++; - } - } - - if (token) - *token = '\0'; - - /* skip the next special characters: - * note the missing ')' */ - while (*str) { - if (ELEM(*str, ' ', '(', ',', ';', '\t', '\n', '\r')) - str++; - else - break; - } - - return str; + int len = 0; + + /* skip a variable/function name */ + while (*str) { + if (ELEM(*str, ' ', '(', ')', ',', ';', '\t', '\n', '\r')) + break; + else { + if (token && len < max - 1) { + *token = *str; + token++; + len++; + } + str++; + } + } + + if (token) + *token = '\0'; + + /* skip the next special characters: + * note the missing ')' */ + while (*str) { + if (ELEM(*str, ' ', '(', ',', ';', '\t', '\n', '\r')) + str++; + else + break; + } + + return str; } static void gpu_parse_functions_string(GHash *hash, char *code) { - GPUFunction *function; - eGPUType type; - GPUFunctionQual qual; - int i; - - while ((code = strstr(code, "void "))) { - function = MEM_callocN(sizeof(GPUFunction), "GPUFunction"); - - code = gpu_str_skip_token(code, NULL, 0); - code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME); - - /* get parameters */ - while (*code && *code != ')') { - /* test if it's an input or output */ - qual = FUNCTION_QUAL_IN; - if (gpu_str_prefix(code, "out ")) - qual = FUNCTION_QUAL_OUT; - if (gpu_str_prefix(code, "inout ")) - qual = FUNCTION_QUAL_INOUT; - if ((qual != FUNCTION_QUAL_IN) || gpu_str_prefix(code, "in ")) - code = gpu_str_skip_token(code, NULL, 0); - - /* test for type */ - type = GPU_NONE; - for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) { - if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) { - type = i; - break; - } - } - - if (!type && gpu_str_prefix(code, "samplerCube")) { - type = GPU_TEXCUBE; - } - if (!type && gpu_str_prefix(code, "sampler2DShadow")) { - type = GPU_SHADOW2D; - } - if (!type && gpu_str_prefix(code, "sampler1DArray")) { - type = GPU_TEX1D_ARRAY; - } - if (!type && gpu_str_prefix(code, "sampler2D")) { - type = GPU_TEX2D; - } - if (!type && gpu_str_prefix(code, "sampler3D")) { - type = GPU_TEX3D; - } - - if (!type && gpu_str_prefix(code, "Closure")) { - type = GPU_CLOSURE; - } - - if (type) { - /* add parameter */ - code = gpu_str_skip_token(code, NULL, 0); - code = gpu_str_skip_token(code, NULL, 0); - function->paramqual[function->totparam] = qual; - function->paramtype[function->totparam] = type; - function->totparam++; - } - else { - fprintf(stderr, "GPU invalid function parameter in %s.\n", function->name); - break; - } - } - - if (function->name[0] == '\0' || function->totparam == 0) { - fprintf(stderr, "GPU functions parse error.\n"); - MEM_freeN(function); - break; - } - - BLI_ghash_insert(hash, function->name, function); - } + GPUFunction *function; + eGPUType type; + GPUFunctionQual qual; + int i; + + while ((code = strstr(code, "void "))) { + function = MEM_callocN(sizeof(GPUFunction), "GPUFunction"); + + code = gpu_str_skip_token(code, NULL, 0); + code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME); + + /* get parameters */ + while (*code && *code != ')') { + /* test if it's an input or output */ + qual = FUNCTION_QUAL_IN; + if (gpu_str_prefix(code, "out ")) + qual = FUNCTION_QUAL_OUT; + if (gpu_str_prefix(code, "inout ")) + qual = FUNCTION_QUAL_INOUT; + if ((qual != FUNCTION_QUAL_IN) || gpu_str_prefix(code, "in ")) + code = gpu_str_skip_token(code, NULL, 0); + + /* test for type */ + type = GPU_NONE; + for (i = 1; i < ARRAY_SIZE(GPU_DATATYPE_STR); i++) { + if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) { + type = i; + break; + } + } + + if (!type && gpu_str_prefix(code, "samplerCube")) { + type = GPU_TEXCUBE; + } + if (!type && gpu_str_prefix(code, "sampler2DShadow")) { + type = GPU_SHADOW2D; + } + if (!type && gpu_str_prefix(code, "sampler1DArray")) { + type = GPU_TEX1D_ARRAY; + } + if (!type && gpu_str_prefix(code, "sampler2D")) { + type = GPU_TEX2D; + } + if (!type && gpu_str_prefix(code, "sampler3D")) { + type = GPU_TEX3D; + } + + if (!type && gpu_str_prefix(code, "Closure")) { + type = GPU_CLOSURE; + } + + if (type) { + /* add parameter */ + code = gpu_str_skip_token(code, NULL, 0); + code = gpu_str_skip_token(code, NULL, 0); + function->paramqual[function->totparam] = qual; + function->paramtype[function->totparam] = type; + function->totparam++; + } + else { + fprintf(stderr, "GPU invalid function parameter in %s.\n", function->name); + break; + } + } + + if (function->name[0] == '\0' || function->totparam == 0) { + fprintf(stderr, "GPU functions parse error.\n"); + MEM_freeN(function); + break; + } + + BLI_ghash_insert(hash, function->name, function); + } } #if 0 static char *gpu_generate_function_prototyps(GHash *hash) { - DynStr *ds = BLI_dynstr_new(); - GHashIterator *ghi; - GPUFunction *function; - char *name, *prototypes; - int a; - - /* automatically generate function prototypes to add to the top of the - * generated code, to avoid have to add the actual code & recompile all */ - ghi = BLI_ghashIterator_new(hash); - - for (; !BLI_ghashIterator_done(ghi); BLI_ghashIterator_step(ghi)) { - name = BLI_ghashIterator_getValue(ghi); - function = BLI_ghashIterator_getValue(ghi); - - BLI_dynstr_appendf(ds, "void %s(", name); - for (a = 0; a < function->totparam; a++) { - if (function->paramqual[a] == FUNCTION_QUAL_OUT) - BLI_dynstr_append(ds, "out "); - else if (function->paramqual[a] == FUNCTION_QUAL_INOUT) - BLI_dynstr_append(ds, "inout "); - - if (function->paramtype[a] == GPU_TEX2D) - BLI_dynstr_append(ds, "sampler2D"); - else if (function->paramtype[a] == GPU_SHADOW2D) - BLI_dynstr_append(ds, "sampler2DShadow"); - else - BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]); + DynStr *ds = BLI_dynstr_new(); + GHashIterator *ghi; + GPUFunction *function; + char *name, *prototypes; + int a; + + /* automatically generate function prototypes to add to the top of the + * generated code, to avoid have to add the actual code & recompile all */ + ghi = BLI_ghashIterator_new(hash); + + for (; !BLI_ghashIterator_done(ghi); BLI_ghashIterator_step(ghi)) { + name = BLI_ghashIterator_getValue(ghi); + function = BLI_ghashIterator_getValue(ghi); + + BLI_dynstr_appendf(ds, "void %s(", name); + for (a = 0; a < function->totparam; a++) { + if (function->paramqual[a] == FUNCTION_QUAL_OUT) + BLI_dynstr_append(ds, "out "); + else if (function->paramqual[a] == FUNCTION_QUAL_INOUT) + BLI_dynstr_append(ds, "inout "); + + if (function->paramtype[a] == GPU_TEX2D) + BLI_dynstr_append(ds, "sampler2D"); + else if (function->paramtype[a] == GPU_SHADOW2D) + BLI_dynstr_append(ds, "sampler2DShadow"); + else + BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]); # if 0 - BLI_dynstr_appendf(ds, " param%d", a); + BLI_dynstr_appendf(ds, " param%d", a); # endif - if (a != function->totparam - 1) - BLI_dynstr_append(ds, ", "); - } - BLI_dynstr_append(ds, ");\n"); - } + if (a != function->totparam - 1) + BLI_dynstr_append(ds, ", "); + } + BLI_dynstr_append(ds, ");\n"); + } - BLI_dynstr_append(ds, "\n"); + BLI_dynstr_append(ds, "\n"); - prototypes = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); + prototypes = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); - return prototypes; + return prototypes; } #endif static GPUFunction *gpu_lookup_function(const char *name) { - if (!FUNCTION_HASH) { - FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh"); - gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library); - } + if (!FUNCTION_HASH) { + FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh"); + gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library); + } - return BLI_ghash_lookup(FUNCTION_HASH, (const void *)name); + return BLI_ghash_lookup(FUNCTION_HASH, (const void *)name); } void gpu_codegen_init(void) { - GPU_code_generate_glsl_lib(); + GPU_code_generate_glsl_lib(); } void gpu_codegen_exit(void) { - extern Material defmaterial; /* render module abuse... */ + extern Material defmaterial; /* render module abuse... */ - if (defmaterial.gpumaterial.first) - GPU_material_free(&defmaterial.gpumaterial); + if (defmaterial.gpumaterial.first) + GPU_material_free(&defmaterial.gpumaterial); - if (FUNCTION_HASH) { - BLI_ghash_free(FUNCTION_HASH, NULL, MEM_freeN); - FUNCTION_HASH = NULL; - } + if (FUNCTION_HASH) { + BLI_ghash_free(FUNCTION_HASH, NULL, MEM_freeN); + FUNCTION_HASH = NULL; + } - GPU_shader_free_builtin_shaders(); + GPU_shader_free_builtin_shaders(); - if (glsl_material_library) { - MEM_freeN(glsl_material_library); - glsl_material_library = NULL; - } + if (glsl_material_library) { + MEM_freeN(glsl_material_library); + glsl_material_library = NULL; + } #if 0 - if (FUNCTION_PROTOTYPES) { - MEM_freeN(FUNCTION_PROTOTYPES); - FUNCTION_PROTOTYPES = NULL; - } - if (FUNCTION_LIB) { - GPU_shader_free(FUNCTION_LIB); - FUNCTION_LIB = NULL; - } + if (FUNCTION_PROTOTYPES) { + MEM_freeN(FUNCTION_PROTOTYPES); + FUNCTION_PROTOTYPES = NULL; + } + if (FUNCTION_LIB) { + GPU_shader_free(FUNCTION_LIB); + FUNCTION_LIB = NULL; + } #endif } @@ -380,189 +399,189 @@ void gpu_codegen_exit(void) static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *tmp, int id) { - char name[1024]; - - BLI_snprintf(name, sizeof(name), "%s%d", tmp, id); - - if (from == to) { - BLI_dynstr_append(ds, name); - } - else if (to == GPU_FLOAT) { - if (from == GPU_VEC4) - BLI_dynstr_appendf(ds, "convert_rgba_to_float(%s)", name); - else if (from == GPU_VEC3) - BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name); - else if (from == GPU_VEC2) - BLI_dynstr_appendf(ds, "%s.r", name); - } - else if (to == GPU_VEC2) { - if (from == GPU_VEC4) - BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name); - else if (from == GPU_VEC3) - BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name); - else if (from == GPU_FLOAT) - BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name); - } - else if (to == GPU_VEC3) { - if (from == GPU_VEC4) - BLI_dynstr_appendf(ds, "%s.rgb", name); - else if (from == GPU_VEC2) - BLI_dynstr_appendf(ds, "vec3(%s.r, %s.r, %s.r)", name, name, name); - else if (from == GPU_FLOAT) - BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name); - } - else if (to == GPU_VEC4) { - if (from == GPU_VEC3) - BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name); - else if (from == GPU_VEC2) - 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 if (to == GPU_CLOSURE) { - if (from == GPU_VEC4) - BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name); - else if (from == GPU_VEC3) - BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name); - else if (from == GPU_VEC2) - BLI_dynstr_appendf(ds, "closure_emission(%s.rrr)", name); - else if (from == GPU_FLOAT) - BLI_dynstr_appendf(ds, "closure_emission(vec3(%s, %s, %s))", name, name, name); - } - else { - BLI_dynstr_append(ds, name); - } + char name[1024]; + + BLI_snprintf(name, sizeof(name), "%s%d", tmp, id); + + if (from == to) { + BLI_dynstr_append(ds, name); + } + else if (to == GPU_FLOAT) { + if (from == GPU_VEC4) + BLI_dynstr_appendf(ds, "convert_rgba_to_float(%s)", name); + else if (from == GPU_VEC3) + BLI_dynstr_appendf(ds, "(%s.r + %s.g + %s.b) / 3.0", name, name, name); + else if (from == GPU_VEC2) + BLI_dynstr_appendf(ds, "%s.r", name); + } + else if (to == GPU_VEC2) { + if (from == GPU_VEC4) + BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, %s.a)", name, name, name, name); + else if (from == GPU_VEC3) + BLI_dynstr_appendf(ds, "vec2((%s.r + %s.g + %s.b) / 3.0, 1.0)", name, name, name); + else if (from == GPU_FLOAT) + BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name); + } + else if (to == GPU_VEC3) { + if (from == GPU_VEC4) + BLI_dynstr_appendf(ds, "%s.rgb", name); + else if (from == GPU_VEC2) + BLI_dynstr_appendf(ds, "vec3(%s.r, %s.r, %s.r)", name, name, name); + else if (from == GPU_FLOAT) + BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name); + } + else if (to == GPU_VEC4) { + if (from == GPU_VEC3) + BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name); + else if (from == GPU_VEC2) + 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 if (to == GPU_CLOSURE) { + if (from == GPU_VEC4) + BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name); + else if (from == GPU_VEC3) + BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name); + else if (from == GPU_VEC2) + BLI_dynstr_appendf(ds, "closure_emission(%s.rrr)", name); + else if (from == GPU_FLOAT) + BLI_dynstr_appendf(ds, "closure_emission(vec3(%s, %s, %s))", name, name, name); + } + else { + BLI_dynstr_append(ds, name); + } } static void codegen_print_datatype(DynStr *ds, const eGPUType type, float *data) { - int i; + int i; - BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]); + BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]); - for (i = 0; i < type; i++) { - BLI_dynstr_appendf(ds, "%.12f", data[i]); - if (i == type - 1) - BLI_dynstr_append(ds, ")"); - else - BLI_dynstr_append(ds, ", "); - } + for (i = 0; i < type; i++) { + BLI_dynstr_appendf(ds, "%.12f", data[i]); + if (i == type - 1) + BLI_dynstr_append(ds, ")"); + else + BLI_dynstr_append(ds, ", "); + } } static int codegen_input_has_texture(GPUInput *input) { - if (input->link) - return 0; - else - return (input->source == GPU_SOURCE_TEX); + if (input->link) + return 0; + else + return (input->source == GPU_SOURCE_TEX); } const char *GPU_builtin_name(eGPUBuiltin builtin) { - if (builtin == GPU_VIEW_MATRIX) - return "unfviewmat"; - else if (builtin == GPU_OBJECT_MATRIX) - return "unfobmat"; - else if (builtin == GPU_INVERSE_VIEW_MATRIX) - return "unfinvviewmat"; - else if (builtin == GPU_INVERSE_OBJECT_MATRIX) - return "unfinvobmat"; - else if (builtin == GPU_INVERSE_NORMAL_MATRIX) - return "unfinvnormat"; - else if (builtin == GPU_LOC_TO_VIEW_MATRIX) - return "unflocaltoviewmat"; - else if (builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) - return "unfinvlocaltoviewmat"; - else if (builtin == GPU_VIEW_POSITION) - return "varposition"; - else if (builtin == GPU_VIEW_NORMAL) - return "varnormal"; - else if (builtin == GPU_OBCOLOR) - return "unfobcolor"; - else if (builtin == GPU_AUTO_BUMPSCALE) - return "unfobautobumpscale"; - else if (builtin == GPU_CAMERA_TEXCO_FACTORS) - return "unfcameratexfactors"; - else if (builtin == GPU_PARTICLE_SCALAR_PROPS) - return "unfparticlescalarprops"; - else if (builtin == GPU_PARTICLE_LOCATION) - return "unfparticleco"; - else if (builtin == GPU_PARTICLE_VELOCITY) - return "unfparticlevel"; - else if (builtin == GPU_PARTICLE_ANG_VELOCITY) - return "unfparticleangvel"; - else if (builtin == GPU_OBJECT_INFO) - return "unfobjectinfo"; - else if (builtin == GPU_VOLUME_DENSITY) - return "sampdensity"; - else if (builtin == GPU_VOLUME_FLAME) - return "sampflame"; - else if (builtin == GPU_VOLUME_TEMPERATURE) - return "unftemperature"; - else if (builtin == GPU_BARYCENTRIC_TEXCO) - return "unfbarycentrictex"; - else if (builtin == GPU_BARYCENTRIC_DIST) - return "unfbarycentricdist"; - else - return ""; + if (builtin == GPU_VIEW_MATRIX) + return "unfviewmat"; + else if (builtin == GPU_OBJECT_MATRIX) + return "unfobmat"; + else if (builtin == GPU_INVERSE_VIEW_MATRIX) + return "unfinvviewmat"; + else if (builtin == GPU_INVERSE_OBJECT_MATRIX) + return "unfinvobmat"; + else if (builtin == GPU_INVERSE_NORMAL_MATRIX) + return "unfinvnormat"; + else if (builtin == GPU_LOC_TO_VIEW_MATRIX) + return "unflocaltoviewmat"; + else if (builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) + return "unfinvlocaltoviewmat"; + else if (builtin == GPU_VIEW_POSITION) + return "varposition"; + else if (builtin == GPU_VIEW_NORMAL) + return "varnormal"; + else if (builtin == GPU_OBCOLOR) + return "unfobcolor"; + else if (builtin == GPU_AUTO_BUMPSCALE) + return "unfobautobumpscale"; + else if (builtin == GPU_CAMERA_TEXCO_FACTORS) + return "unfcameratexfactors"; + else if (builtin == GPU_PARTICLE_SCALAR_PROPS) + return "unfparticlescalarprops"; + else if (builtin == GPU_PARTICLE_LOCATION) + return "unfparticleco"; + else if (builtin == GPU_PARTICLE_VELOCITY) + return "unfparticlevel"; + else if (builtin == GPU_PARTICLE_ANG_VELOCITY) + return "unfparticleangvel"; + else if (builtin == GPU_OBJECT_INFO) + return "unfobjectinfo"; + else if (builtin == GPU_VOLUME_DENSITY) + return "sampdensity"; + else if (builtin == GPU_VOLUME_FLAME) + return "sampflame"; + else if (builtin == GPU_VOLUME_TEMPERATURE) + return "unftemperature"; + else if (builtin == GPU_BARYCENTRIC_TEXCO) + return "unfbarycentrictex"; + else if (builtin == GPU_BARYCENTRIC_DIST) + return "unfbarycentricdist"; + else + return ""; } /* assign only one texid per buffer to avoid sampling the same texture twice */ static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void *key) { - if (BLI_ghash_haskey(bindhash, key)) { - /* Reuse existing texid */ - input->texid = POINTER_AS_INT(BLI_ghash_lookup(bindhash, key)); - } - else { - /* Allocate new texid */ - input->texid = *texid; - (*texid)++; - input->bindtex = true; - BLI_ghash_insert(bindhash, key, POINTER_FROM_INT(input->texid)); - } + if (BLI_ghash_haskey(bindhash, key)) { + /* Reuse existing texid */ + input->texid = POINTER_AS_INT(BLI_ghash_lookup(bindhash, key)); + } + else { + /* Allocate new texid */ + input->texid = *texid; + (*texid)++; + input->bindtex = true; + BLI_ghash_insert(bindhash, key, POINTER_FROM_INT(input->texid)); + } } static void codegen_set_unique_ids(ListBase *nodes) { - GHash *bindhash; - GPUNode *node; - GPUInput *input; - GPUOutput *output; - int id = 1, texid = 0; - - bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh"); - - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - /* set id for unique names of uniform variables */ - input->id = id++; - - /* set texid used for settings texture slot */ - if (codegen_input_has_texture(input)) { - input->bindtex = false; - if (input->ima) { - /* input is texture from image */ - codegen_set_texid(bindhash, input, &texid, input->ima); - } - else if (input->coba) { - /* input is color band texture, check coba pointer */ - codegen_set_texid(bindhash, input, &texid, input->coba); - } - else { - /* Either input->ima or input->coba should be non-NULL. */ - BLI_assert(0); - } - } - } - - for (output = node->outputs.first; output; output = output->next) { - /* set id for unique names of tmp variables storing output */ - output->id = id++; - } - } - - BLI_ghash_free(bindhash, NULL, NULL); + GHash *bindhash; + GPUNode *node; + GPUInput *input; + GPUOutput *output; + int id = 1, texid = 0; + + bindhash = BLI_ghash_ptr_new("codegen_set_unique_ids1 gh"); + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + /* set id for unique names of uniform variables */ + input->id = id++; + + /* set texid used for settings texture slot */ + if (codegen_input_has_texture(input)) { + input->bindtex = false; + if (input->ima) { + /* input is texture from image */ + codegen_set_texid(bindhash, input, &texid, input->ima); + } + else if (input->coba) { + /* input is color band texture, check coba pointer */ + codegen_set_texid(bindhash, input, &texid, input->coba); + } + else { + /* Either input->ima or input->coba should be non-NULL. */ + BLI_assert(0); + } + } + } + + for (output = node->outputs.first; output; output = output->next) { + /* set id for unique names of tmp variables storing output */ + output->id = id++; + } + } + + BLI_ghash_free(bindhash, NULL, NULL); } /** @@ -570,1511 +589,1518 @@ static void codegen_set_unique_ids(ListBase *nodes) */ static int codegen_process_uniforms_functions(GPUMaterial *material, DynStr *ds, ListBase *nodes) { - GPUNode *node; - GPUInput *input; - const char *name; - int builtins = 0; - ListBase ubo_inputs = {NULL, NULL}; - - /* print uniforms */ - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_TEX) { - /* create exactly one sampler for each texture */ - if (codegen_input_has_texture(input) && input->bindtex) { - BLI_dynstr_appendf( - ds, "uniform %s samp%d;\n", - (input->coba) ? "sampler1DArray" : "sampler2D", - input->texid); - } - } - else if (input->source == GPU_SOURCE_BUILTIN) { - /* only define each builtin uniform/varying once */ - if (!(builtins & input->builtin)) { - builtins |= input->builtin; - name = GPU_builtin_name(input->builtin); - - if (gpu_str_prefix(name, "samp")) { - if ((input->builtin == GPU_VOLUME_DENSITY) || - (input->builtin == GPU_VOLUME_FLAME)) - { - BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name); - } - } - else if (gpu_str_prefix(name, "unf")) { - BLI_dynstr_appendf( - ds, "uniform %s %s;\n", - GPU_DATATYPE_STR[input->type], name); - } - else { - BLI_dynstr_appendf( - ds, "in %s %s;\n", - GPU_DATATYPE_STR[input->type], name); - } - } - } - else if (input->source == GPU_SOURCE_STRUCT) { - /* Add other struct here if needed. */ - BLI_dynstr_appendf(ds, "Closure strct%d = CLOSURE_DEFAULT;\n", input->id); - } - else if (input->source == GPU_SOURCE_UNIFORM) { - if (!input->link) { - /* We handle the UBOuniforms separately. */ - BLI_addtail(&ubo_inputs, BLI_genericNodeN(input)); - } - } - else if (input->source == GPU_SOURCE_CONSTANT) { - BLI_dynstr_appendf( - ds, "const %s cons%d = ", - GPU_DATATYPE_STR[input->type], input->id); - codegen_print_datatype(ds, input->type, input->vec); - BLI_dynstr_append(ds, ";\n"); - } - else if (input->source == GPU_SOURCE_ATTR && input->attr_first) { - BLI_dynstr_appendf( - ds, "in %s var%d;\n", - GPU_DATATYPE_STR[input->type], input->attr_id); - } - } - } - - /* Handle the UBO block separately. */ - if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) { - GPU_material_uniform_buffer_create(material, &ubo_inputs); - - /* Inputs are sorted */ - BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME); - - for (LinkData *link = ubo_inputs.first; link; link = link->next) { - input = link->data; - BLI_dynstr_appendf( - ds, "\t%s unf%d;\n", - GPU_DATATYPE_STR[input->type], input->id); - } - BLI_dynstr_append(ds, "};\n"); - BLI_freelistN(&ubo_inputs); - } - - BLI_dynstr_append(ds, "\n"); - - return builtins; + GPUNode *node; + GPUInput *input; + const char *name; + int builtins = 0; + ListBase ubo_inputs = {NULL, NULL}; + + /* print uniforms */ + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_TEX) { + /* create exactly one sampler for each texture */ + if (codegen_input_has_texture(input) && input->bindtex) { + BLI_dynstr_appendf(ds, + "uniform %s samp%d;\n", + (input->coba) ? "sampler1DArray" : "sampler2D", + input->texid); + } + } + else if (input->source == GPU_SOURCE_BUILTIN) { + /* only define each builtin uniform/varying once */ + if (!(builtins & input->builtin)) { + builtins |= input->builtin; + name = GPU_builtin_name(input->builtin); + + if (gpu_str_prefix(name, "samp")) { + if ((input->builtin == GPU_VOLUME_DENSITY) || (input->builtin == GPU_VOLUME_FLAME)) { + BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name); + } + } + else if (gpu_str_prefix(name, "unf")) { + BLI_dynstr_appendf(ds, "uniform %s %s;\n", GPU_DATATYPE_STR[input->type], name); + } + else { + BLI_dynstr_appendf(ds, "in %s %s;\n", GPU_DATATYPE_STR[input->type], name); + } + } + } + else if (input->source == GPU_SOURCE_STRUCT) { + /* Add other struct here if needed. */ + BLI_dynstr_appendf(ds, "Closure strct%d = CLOSURE_DEFAULT;\n", input->id); + } + else if (input->source == GPU_SOURCE_UNIFORM) { + if (!input->link) { + /* We handle the UBOuniforms separately. */ + BLI_addtail(&ubo_inputs, BLI_genericNodeN(input)); + } + } + else if (input->source == GPU_SOURCE_CONSTANT) { + BLI_dynstr_appendf(ds, "const %s cons%d = ", GPU_DATATYPE_STR[input->type], input->id); + codegen_print_datatype(ds, input->type, input->vec); + BLI_dynstr_append(ds, ";\n"); + } + else if (input->source == GPU_SOURCE_ATTR && input->attr_first) { + BLI_dynstr_appendf(ds, "in %s var%d;\n", GPU_DATATYPE_STR[input->type], input->attr_id); + } + } + } + + /* Handle the UBO block separately. */ + if ((material != NULL) && !BLI_listbase_is_empty(&ubo_inputs)) { + GPU_material_uniform_buffer_create(material, &ubo_inputs); + + /* Inputs are sorted */ + BLI_dynstr_appendf(ds, "\nlayout (std140) uniform %s {\n", GPU_UBO_BLOCK_NAME); + + for (LinkData *link = ubo_inputs.first; link; link = link->next) { + input = link->data; + BLI_dynstr_appendf(ds, "\t%s unf%d;\n", GPU_DATATYPE_STR[input->type], input->id); + } + BLI_dynstr_append(ds, "};\n"); + BLI_freelistN(&ubo_inputs); + } + + BLI_dynstr_append(ds, "\n"); + + return builtins; } static void codegen_declare_tmps(DynStr *ds, ListBase *nodes) { - GPUNode *node; - GPUOutput *output; - - for (node = nodes->first; node; node = node->next) { - /* declare temporary variables for node output storage */ - for (output = node->outputs.first; output; output = output->next) { - if (output->type == GPU_CLOSURE) { - BLI_dynstr_appendf( - ds, "\tClosure tmp%d;\n", output->id); - } - else { - BLI_dynstr_appendf( - ds, "\t%s tmp%d;\n", - GPU_DATATYPE_STR[output->type], output->id); - } - } - } - - BLI_dynstr_append(ds, "\n"); + GPUNode *node; + GPUOutput *output; + + for (node = nodes->first; node; node = node->next) { + /* declare temporary variables for node output storage */ + for (output = node->outputs.first; output; output = output->next) { + if (output->type == GPU_CLOSURE) { + BLI_dynstr_appendf(ds, "\tClosure tmp%d;\n", output->id); + } + else { + BLI_dynstr_appendf(ds, "\t%s tmp%d;\n", GPU_DATATYPE_STR[output->type], output->id); + } + } + } + + BLI_dynstr_append(ds, "\n"); } static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *finaloutput) { - GPUNode *node; - GPUInput *input; - GPUOutput *output; - - for (node = nodes->first; node; node = node->next) { - BLI_dynstr_appendf(ds, "\t%s(", node->name); - - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_TEX) { - BLI_dynstr_appendf(ds, "samp%d", input->texid); - } - else if (input->source == GPU_SOURCE_OUTPUT) { - codegen_convert_datatype( - ds, input->link->output->type, input->type, - "tmp", input->link->output->id); - } - else if (input->source == GPU_SOURCE_BUILTIN) { - /* TODO(fclem) get rid of that. */ - if (input->builtin == GPU_INVERSE_VIEW_MATRIX) - BLI_dynstr_append(ds, "viewinv"); - else if (input->builtin == GPU_VIEW_MATRIX) - BLI_dynstr_append(ds, "viewmat"); - else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS) - BLI_dynstr_append(ds, "camtexfac"); - else if (input->builtin == GPU_LOC_TO_VIEW_MATRIX) - BLI_dynstr_append(ds, "localtoviewmat"); - else if (input->builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) - BLI_dynstr_append(ds, "invlocaltoviewmat"); - else if (input->builtin == GPU_BARYCENTRIC_DIST) - BLI_dynstr_append(ds, "barycentricDist"); - else if (input->builtin == GPU_BARYCENTRIC_TEXCO) - BLI_dynstr_append(ds, "barytexco"); - else if (input->builtin == GPU_OBJECT_MATRIX) - BLI_dynstr_append(ds, "objmat"); - else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) - BLI_dynstr_append(ds, "objinv"); - else if (input->builtin == GPU_INVERSE_NORMAL_MATRIX) - BLI_dynstr_append(ds, "norinv"); - else if (input->builtin == GPU_VIEW_POSITION) - BLI_dynstr_append(ds, "viewposition"); - else if (input->builtin == GPU_VIEW_NORMAL) - BLI_dynstr_append(ds, "facingnormal"); - else - BLI_dynstr_append(ds, GPU_builtin_name(input->builtin)); - } - else if (input->source == GPU_SOURCE_STRUCT) { - BLI_dynstr_appendf(ds, "strct%d", input->id); - } - else if (input->source == GPU_SOURCE_UNIFORM) { - BLI_dynstr_appendf(ds, "unf%d", input->id); - } - else if (input->source == GPU_SOURCE_CONSTANT) { - BLI_dynstr_appendf(ds, "cons%d", input->id); - } - else if (input->source == GPU_SOURCE_ATTR) { - BLI_dynstr_appendf(ds, "var%d", input->attr_id); - } - - BLI_dynstr_append(ds, ", "); - } - - for (output = node->outputs.first; output; output = output->next) { - BLI_dynstr_appendf(ds, "tmp%d", output->id); - if (output->next) - BLI_dynstr_append(ds, ", "); - } - - BLI_dynstr_append(ds, ");\n"); - } - - BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id); - BLI_dynstr_append(ds, ";\n"); + GPUNode *node; + GPUInput *input; + GPUOutput *output; + + for (node = nodes->first; node; node = node->next) { + BLI_dynstr_appendf(ds, "\t%s(", node->name); + + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_TEX) { + BLI_dynstr_appendf(ds, "samp%d", input->texid); + } + else if (input->source == GPU_SOURCE_OUTPUT) { + codegen_convert_datatype( + ds, input->link->output->type, input->type, "tmp", input->link->output->id); + } + else if (input->source == GPU_SOURCE_BUILTIN) { + /* TODO(fclem) get rid of that. */ + if (input->builtin == GPU_INVERSE_VIEW_MATRIX) + BLI_dynstr_append(ds, "viewinv"); + else if (input->builtin == GPU_VIEW_MATRIX) + BLI_dynstr_append(ds, "viewmat"); + else if (input->builtin == GPU_CAMERA_TEXCO_FACTORS) + BLI_dynstr_append(ds, "camtexfac"); + else if (input->builtin == GPU_LOC_TO_VIEW_MATRIX) + BLI_dynstr_append(ds, "localtoviewmat"); + else if (input->builtin == GPU_INVERSE_LOC_TO_VIEW_MATRIX) + BLI_dynstr_append(ds, "invlocaltoviewmat"); + else if (input->builtin == GPU_BARYCENTRIC_DIST) + BLI_dynstr_append(ds, "barycentricDist"); + else if (input->builtin == GPU_BARYCENTRIC_TEXCO) + BLI_dynstr_append(ds, "barytexco"); + else if (input->builtin == GPU_OBJECT_MATRIX) + BLI_dynstr_append(ds, "objmat"); + else if (input->builtin == GPU_INVERSE_OBJECT_MATRIX) + BLI_dynstr_append(ds, "objinv"); + else if (input->builtin == GPU_INVERSE_NORMAL_MATRIX) + BLI_dynstr_append(ds, "norinv"); + else if (input->builtin == GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "viewposition"); + else if (input->builtin == GPU_VIEW_NORMAL) + BLI_dynstr_append(ds, "facingnormal"); + else + BLI_dynstr_append(ds, GPU_builtin_name(input->builtin)); + } + else if (input->source == GPU_SOURCE_STRUCT) { + BLI_dynstr_appendf(ds, "strct%d", input->id); + } + else if (input->source == GPU_SOURCE_UNIFORM) { + BLI_dynstr_appendf(ds, "unf%d", input->id); + } + else if (input->source == GPU_SOURCE_CONSTANT) { + BLI_dynstr_appendf(ds, "cons%d", input->id); + } + else if (input->source == GPU_SOURCE_ATTR) { + BLI_dynstr_appendf(ds, "var%d", input->attr_id); + } + + BLI_dynstr_append(ds, ", "); + } + + for (output = node->outputs.first; output; output = output->next) { + BLI_dynstr_appendf(ds, "tmp%d", output->id); + if (output->next) + BLI_dynstr_append(ds, ", "); + } + + BLI_dynstr_append(ds, ");\n"); + } + + BLI_dynstr_appendf(ds, "\n\treturn tmp%d", finaloutput->id); + BLI_dynstr_append(ds, ";\n"); } -static char *code_generate_fragment(GPUMaterial *material, ListBase *nodes, GPUOutput *output, int *rbuiltins) +static char *code_generate_fragment(GPUMaterial *material, + ListBase *nodes, + GPUOutput *output, + int *rbuiltins) { - DynStr *ds = BLI_dynstr_new(); - char *code; - int builtins; + DynStr *ds = BLI_dynstr_new(); + char *code; + int builtins; #if 0 - BLI_dynstr_append(ds, FUNCTION_PROTOTYPES); + BLI_dynstr_append(ds, FUNCTION_PROTOTYPES); #endif - codegen_set_unique_ids(nodes); - *rbuiltins = builtins = codegen_process_uniforms_functions(material, ds, nodes); - - if (builtins & GPU_BARYCENTRIC_TEXCO) - BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n"); - - if (builtins & GPU_BARYCENTRIC_DIST) - BLI_dynstr_append(ds, "flat in vec3 barycentricDist;\n"); - - BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n"); - - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); - BLI_dynstr_append(ds, "\tvec2 barytexco = vec2((fract(barycentricTexCo.y) != 0.0)\n" - "\t ? barycentricTexCo.x\n" - "\t : 1.0 - barycentricTexCo.x,\n" - "\t 0.0);\n"); - BLI_dynstr_append(ds, "#else\n"); - BLI_dynstr_append(ds, "\tvec2 barytexco = barycentricTexCo;\n"); - BLI_dynstr_append(ds, "#endif\n"); - } - /* TODO(fclem) get rid of that. */ - if (builtins & GPU_VIEW_MATRIX) - BLI_dynstr_append(ds, "\t#define viewmat ViewMatrix\n"); - if (builtins & GPU_CAMERA_TEXCO_FACTORS) - BLI_dynstr_append(ds, "\t#define camtexfac CameraTexCoFactors\n"); - if (builtins & GPU_OBJECT_MATRIX) - BLI_dynstr_append(ds, "\t#define objmat ModelMatrix\n"); - if (builtins & GPU_INVERSE_OBJECT_MATRIX) - BLI_dynstr_append(ds, "\t#define objinv ModelMatrixInverse\n"); - if (builtins & GPU_INVERSE_NORMAL_MATRIX) - BLI_dynstr_append(ds, "\t#define norinv NormalMatrixInverse\n"); - if (builtins & GPU_INVERSE_VIEW_MATRIX) - BLI_dynstr_append(ds, "\t#define viewinv ViewMatrixInverse\n"); - if (builtins & GPU_LOC_TO_VIEW_MATRIX) - BLI_dynstr_append(ds, "\t#define localtoviewmat ModelViewMatrix\n"); - if (builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) - BLI_dynstr_append(ds, "\t#define invlocaltoviewmat ModelViewMatrixInverse\n"); - if (builtins & GPU_VIEW_NORMAL) - BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? viewNormal: -viewNormal;\n"); - if (builtins & GPU_VIEW_POSITION) - BLI_dynstr_append(ds, "\t#define viewposition viewPosition\n"); - - codegen_declare_tmps(ds, nodes); - codegen_call_functions(ds, nodes, output); - - 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); + codegen_set_unique_ids(nodes); + *rbuiltins = builtins = codegen_process_uniforms_functions(material, ds, nodes); + + if (builtins & GPU_BARYCENTRIC_TEXCO) + BLI_dynstr_append(ds, "in vec2 barycentricTexCo;\n"); + + if (builtins & GPU_BARYCENTRIC_DIST) + BLI_dynstr_append(ds, "flat in vec3 barycentricDist;\n"); + + BLI_dynstr_append(ds, "Closure nodetree_exec(void)\n{\n"); + + if (builtins & GPU_BARYCENTRIC_TEXCO) { + BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); + BLI_dynstr_append(ds, + "\tvec2 barytexco = vec2((fract(barycentricTexCo.y) != 0.0)\n" + "\t ? barycentricTexCo.x\n" + "\t : 1.0 - barycentricTexCo.x,\n" + "\t 0.0);\n"); + BLI_dynstr_append(ds, "#else\n"); + BLI_dynstr_append(ds, "\tvec2 barytexco = barycentricTexCo;\n"); + BLI_dynstr_append(ds, "#endif\n"); + } + /* TODO(fclem) get rid of that. */ + if (builtins & GPU_VIEW_MATRIX) + BLI_dynstr_append(ds, "\t#define viewmat ViewMatrix\n"); + if (builtins & GPU_CAMERA_TEXCO_FACTORS) + BLI_dynstr_append(ds, "\t#define camtexfac CameraTexCoFactors\n"); + if (builtins & GPU_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\t#define objmat ModelMatrix\n"); + if (builtins & GPU_INVERSE_OBJECT_MATRIX) + BLI_dynstr_append(ds, "\t#define objinv ModelMatrixInverse\n"); + if (builtins & GPU_INVERSE_NORMAL_MATRIX) + BLI_dynstr_append(ds, "\t#define norinv NormalMatrixInverse\n"); + if (builtins & GPU_INVERSE_VIEW_MATRIX) + BLI_dynstr_append(ds, "\t#define viewinv ViewMatrixInverse\n"); + if (builtins & GPU_LOC_TO_VIEW_MATRIX) + BLI_dynstr_append(ds, "\t#define localtoviewmat ModelViewMatrix\n"); + if (builtins & GPU_INVERSE_LOC_TO_VIEW_MATRIX) + BLI_dynstr_append(ds, "\t#define invlocaltoviewmat ModelViewMatrixInverse\n"); + if (builtins & GPU_VIEW_NORMAL) + BLI_dynstr_append(ds, "\tvec3 facingnormal = gl_FrontFacing? viewNormal: -viewNormal;\n"); + if (builtins & GPU_VIEW_POSITION) + BLI_dynstr_append(ds, "\t#define viewposition viewPosition\n"); + + codegen_declare_tmps(ds, nodes); + codegen_call_functions(ds, nodes, output); + + 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); #if 0 - if (G.debug & G_DEBUG) printf("%s\n", code); + if (G.debug & G_DEBUG) printf("%s\n", code); #endif - return code; + return code; } static const char *attr_prefix_get(CustomDataType type) { - switch (type) { - case CD_ORCO: return "orco"; - case CD_MTFACE: return "u"; - case CD_TANGENT: return "t"; - case CD_MCOL: return "c"; - case CD_AUTO_FROM_NAME: return "a"; - default: BLI_assert(false && "GPUVertAttr Prefix type not found : This should not happen!"); return ""; - } + switch (type) { + case CD_ORCO: + return "orco"; + case CD_MTFACE: + return "u"; + case CD_TANGENT: + return "t"; + case CD_MCOL: + return "c"; + case CD_AUTO_FROM_NAME: + return "a"; + default: + BLI_assert(false && "GPUVertAttr Prefix type not found : This should not happen!"); + return ""; + } } static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool use_geom) { - DynStr *ds = BLI_dynstr_new(); - GPUNode *node; - GPUInput *input; - char *code; - int builtins = 0; - - /* Hairs uv and col attributes are passed by bufferTextures. */ - BLI_dynstr_append( - ds, - "#ifdef HAIR_SHADER\n" - "#define DEFINE_ATTR(type, attr) uniform samplerBuffer attr\n" - "#else\n" - "#define DEFINE_ATTR(type, attr) in type attr\n" - "#endif\n" - ); - - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_BUILTIN) { - builtins |= input->builtin; - } - if (input->source == GPU_SOURCE_ATTR && input->attr_first) { - /* XXX FIXME : see notes in mesh_render_data_create() */ - /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ - if (input->attr_type == CD_ORCO) { - /* OPTI : orco is computed from local positions, but only if no modifier is present. */ - BLI_dynstr_append(ds, "uniform vec3 OrcoTexCoFactors[2];\n"); - BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n"); - } - else if (input->attr_name[0] == '\0') { - BLI_dynstr_appendf(ds, "DEFINE_ATTR(%s, %s);\n", GPU_DATATYPE_STR[input->type], attr_prefix_get(input->attr_type)); - BLI_dynstr_appendf(ds, "#define att%d %s\n", input->attr_id, attr_prefix_get(input->attr_type)); - } - else { - uint hash = BLI_ghashutil_strhash_p(input->attr_name); - BLI_dynstr_appendf( - ds, "DEFINE_ATTR(%s, %s%u);\n", - GPU_DATATYPE_STR[input->type], attr_prefix_get(input->attr_type), hash); - BLI_dynstr_appendf( - ds, "#define att%d %s%u\n", - input->attr_id, attr_prefix_get(input->attr_type), hash); - /* Auto attribute can be vertex color byte buffer. - * We need to know and convert them to linear space in VS. */ - if (input->attr_type == CD_AUTO_FROM_NAME) { - BLI_dynstr_appendf(ds, "uniform bool ba%u;\n", hash); - BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%u\n", input->attr_id, hash); - } - } - BLI_dynstr_appendf( - ds, "out %s var%d%s;\n", - GPU_DATATYPE_STR[input->type], input->attr_id, use_geom ? "g" : ""); - } - } - } - - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); - BLI_dynstr_appendf( - ds, "out vec2 barycentricTexCo%s;\n", - use_geom ? "g" : ""); - BLI_dynstr_append(ds, "#endif\n"); - } - - if (builtins & GPU_BARYCENTRIC_DIST) { - BLI_dynstr_append(ds, "out vec3 barycentricPosg;\n"); - } - - - BLI_dynstr_append(ds, "\n"); - - BLI_dynstr_append( - ds, - "#define USE_ATTR\n" - "uniform mat3 NormalMatrix;\n" - "uniform mat4 ModelMatrixInverse;\n" - "uniform mat4 ModelMatrix;\n" - "vec3 srgb_to_linear_attr(vec3 c) {\n" - "\tc = max(c, vec3(0.0));\n" - "\tvec3 c1 = c * (1.0 / 12.92);\n" - "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n" - "\treturn mix(c1, c2, step(vec3(0.04045), c));\n" - "}\n\n" - ); - - /* Prototype because defined later. */ - BLI_dynstr_append( - ds, - "vec2 hair_get_customdata_vec2(const samplerBuffer);\n" - "vec3 hair_get_customdata_vec3(const samplerBuffer);\n" - "vec4 hair_get_customdata_vec4(const samplerBuffer);\n" - "vec3 hair_get_strand_pos(void);\n" - "int hair_get_base_id(void);\n" - "\n" - ); - - BLI_dynstr_append(ds, "void pass_attr(in vec3 position) {\n"); - - BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); - - if (builtins & GPU_BARYCENTRIC_TEXCO) { - /* To match cycles without breaking into individual segment we encode if we need to invert - * the first component into the second component. We invert if the barycentricTexCo.y - * is NOT 0.0 or 1.0. */ - BLI_dynstr_append( - ds, "\tint _base_id = hair_get_base_id();\n"); - BLI_dynstr_appendf( - ds, "\tbarycentricTexCo%s.x = float((_base_id %% 2) == 1);\n", - use_geom ? "g" : ""); - BLI_dynstr_appendf( - ds, "\tbarycentricTexCo%s.y = float(((_base_id %% 4) %% 3) > 0);\n", - use_geom ? "g" : ""); - } - - if (builtins & GPU_BARYCENTRIC_DIST) { - BLI_dynstr_append(ds, "\tbarycentricPosg = position;\n"); - } - - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_ATTR && input->attr_first) { - if (input->attr_type == CD_TANGENT) { - /* Not supported by hairs */ - BLI_dynstr_appendf( - ds, "\tvar%d%s = vec4(0.0);\n", - input->attr_id, use_geom ? "g" : ""); - } - else if (input->attr_type == CD_ORCO) { - BLI_dynstr_appendf( - ds, "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n", - input->attr_id, use_geom ? "g" : ""); - /* TODO: fix ORCO with modifiers. */ - } - else { - BLI_dynstr_appendf( - ds, "\tvar%d%s = hair_get_customdata_%s(att%d);\n", - input->attr_id, use_geom ? "g" : "", GPU_DATATYPE_STR[input->type], input->attr_id); - } - } - } - } - - BLI_dynstr_append(ds, "#else /* MESH_SHADER */\n"); - - /* GPU_BARYCENTRIC_TEXCO cannot be computed based on gl_VertexID - * for MESH_SHADER because of indexed drawing. In this case a - * geometry shader is needed. */ - - if (builtins & GPU_BARYCENTRIC_DIST) { - BLI_dynstr_append(ds, "\tbarycentricPosg = (ModelMatrix * vec4(position, 1.0)).xyz;\n"); - } - - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_ATTR && input->attr_first) { - if (input->attr_type == CD_TANGENT) { /* silly exception */ - BLI_dynstr_appendf( - ds, "\tvar%d%s.xyz = NormalMatrix * att%d.xyz;\n", - input->attr_id, use_geom ? "g" : "", input->attr_id); - BLI_dynstr_appendf( - ds, "\tvar%d%s.w = att%d.w;\n", - input->attr_id, use_geom ? "g" : "", input->attr_id); - /* Normalize only if vector is not null. */ - BLI_dynstr_appendf( - ds, "\tfloat lvar%d = dot(var%d%s.xyz, var%d%s.xyz);\n", - input->attr_id, input->attr_id, use_geom ? "g" : "", input->attr_id, use_geom ? "g" : ""); - BLI_dynstr_appendf( - ds, "\tvar%d%s.xyz *= (lvar%d > 0.0) ? inversesqrt(lvar%d) : 1.0;\n", - input->attr_id, use_geom ? "g" : "", input->attr_id, input->attr_id); - } - else if (input->attr_type == CD_ORCO) { - BLI_dynstr_appendf( - ds, "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n", - input->attr_id, use_geom ? "g" : ""); - /* See mesh_create_loop_orco() for explanation. */ - BLI_dynstr_appendf( - ds, "\tif (orco.w == 0.0) { var%d%s = orco.xyz * 0.5 + 0.5; }\n", - input->attr_id, use_geom ? "g" : ""); - } - else if (input->attr_type == CD_MCOL) { - BLI_dynstr_appendf( - ds, "\tvar%d%s = srgb_to_linear_attr(att%d);\n", - input->attr_id, use_geom ? "g" : "", input->attr_id); - } - else if (input->attr_type == CD_AUTO_FROM_NAME) { - BLI_dynstr_appendf( - ds, "\tvar%d%s = (att%d_is_srgb) ? srgb_to_linear_attr(att%d) : att%d;\n", - input->attr_id, use_geom ? "g" : "", - input->attr_id, input->attr_id, input->attr_id); - } - else { - BLI_dynstr_appendf( - ds, "\tvar%d%s = att%d;\n", - input->attr_id, use_geom ? "g" : "", input->attr_id); - } - } - } - } - BLI_dynstr_append(ds, "#endif /* HAIR_SHADER */\n"); - - BLI_dynstr_append(ds, "}\n"); - - if (use_geom) { - /* XXX HACK: Eevee specific. */ - char *vert_new, *vert_new2; - vert_new = BLI_str_replaceN(vert_code, "worldPosition", "worldPositiong"); - vert_new2 = vert_new; - vert_new = BLI_str_replaceN(vert_new2, "viewPosition", "viewPositiong"); - MEM_freeN(vert_new2); - vert_new2 = vert_new; - vert_new = BLI_str_replaceN(vert_new2, "worldNormal", "worldNormalg"); - MEM_freeN(vert_new2); - vert_new2 = vert_new; - vert_new = BLI_str_replaceN(vert_new2, "viewNormal", "viewNormalg"); - MEM_freeN(vert_new2); - - BLI_dynstr_append(ds, vert_new); - - MEM_freeN(vert_new); - } - else { - BLI_dynstr_append(ds, vert_code); - } - - code = BLI_dynstr_get_cstring(ds); - - BLI_dynstr_free(ds); + DynStr *ds = BLI_dynstr_new(); + GPUNode *node; + GPUInput *input; + char *code; + int builtins = 0; + + /* Hairs uv and col attributes are passed by bufferTextures. */ + BLI_dynstr_append(ds, + "#ifdef HAIR_SHADER\n" + "#define DEFINE_ATTR(type, attr) uniform samplerBuffer attr\n" + "#else\n" + "#define DEFINE_ATTR(type, attr) in type attr\n" + "#endif\n"); + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_BUILTIN) { + builtins |= input->builtin; + } + if (input->source == GPU_SOURCE_ATTR && input->attr_first) { + /* XXX FIXME : see notes in mesh_render_data_create() */ + /* NOTE : Replicate changes to mesh_render_data_create() in draw_cache_impl_mesh.c */ + if (input->attr_type == CD_ORCO) { + /* OPTI : orco is computed from local positions, but only if no modifier is present. */ + BLI_dynstr_append(ds, "uniform vec3 OrcoTexCoFactors[2];\n"); + BLI_dynstr_append(ds, "DEFINE_ATTR(vec4, orco);\n"); + } + else if (input->attr_name[0] == '\0') { + BLI_dynstr_appendf(ds, + "DEFINE_ATTR(%s, %s);\n", + GPU_DATATYPE_STR[input->type], + attr_prefix_get(input->attr_type)); + BLI_dynstr_appendf( + ds, "#define att%d %s\n", input->attr_id, attr_prefix_get(input->attr_type)); + } + else { + uint hash = BLI_ghashutil_strhash_p(input->attr_name); + BLI_dynstr_appendf(ds, + "DEFINE_ATTR(%s, %s%u);\n", + GPU_DATATYPE_STR[input->type], + attr_prefix_get(input->attr_type), + hash); + BLI_dynstr_appendf( + ds, "#define att%d %s%u\n", input->attr_id, attr_prefix_get(input->attr_type), hash); + /* Auto attribute can be vertex color byte buffer. + * We need to know and convert them to linear space in VS. */ + if (input->attr_type == CD_AUTO_FROM_NAME) { + BLI_dynstr_appendf(ds, "uniform bool ba%u;\n", hash); + BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%u\n", input->attr_id, hash); + } + } + BLI_dynstr_appendf(ds, + "out %s var%d%s;\n", + GPU_DATATYPE_STR[input->type], + input->attr_id, + use_geom ? "g" : ""); + } + } + } + + if (builtins & GPU_BARYCENTRIC_TEXCO) { + BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); + BLI_dynstr_appendf(ds, "out vec2 barycentricTexCo%s;\n", use_geom ? "g" : ""); + BLI_dynstr_append(ds, "#endif\n"); + } + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_append(ds, "out vec3 barycentricPosg;\n"); + } + + BLI_dynstr_append(ds, "\n"); + + BLI_dynstr_append(ds, + "#define USE_ATTR\n" + "uniform mat3 NormalMatrix;\n" + "uniform mat4 ModelMatrixInverse;\n" + "uniform mat4 ModelMatrix;\n" + "vec3 srgb_to_linear_attr(vec3 c) {\n" + "\tc = max(c, vec3(0.0));\n" + "\tvec3 c1 = c * (1.0 / 12.92);\n" + "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n" + "\treturn mix(c1, c2, step(vec3(0.04045), c));\n" + "}\n\n"); + + /* Prototype because defined later. */ + BLI_dynstr_append(ds, + "vec2 hair_get_customdata_vec2(const samplerBuffer);\n" + "vec3 hair_get_customdata_vec3(const samplerBuffer);\n" + "vec4 hair_get_customdata_vec4(const samplerBuffer);\n" + "vec3 hair_get_strand_pos(void);\n" + "int hair_get_base_id(void);\n" + "\n"); + + BLI_dynstr_append(ds, "void pass_attr(in vec3 position) {\n"); + + BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); + + if (builtins & GPU_BARYCENTRIC_TEXCO) { + /* To match cycles without breaking into individual segment we encode if we need to invert + * the first component into the second component. We invert if the barycentricTexCo.y + * is NOT 0.0 or 1.0. */ + BLI_dynstr_append(ds, "\tint _base_id = hair_get_base_id();\n"); + BLI_dynstr_appendf( + ds, "\tbarycentricTexCo%s.x = float((_base_id %% 2) == 1);\n", use_geom ? "g" : ""); + BLI_dynstr_appendf( + ds, "\tbarycentricTexCo%s.y = float(((_base_id %% 4) %% 3) > 0);\n", use_geom ? "g" : ""); + } + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_append(ds, "\tbarycentricPosg = position;\n"); + } + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTR && input->attr_first) { + if (input->attr_type == CD_TANGENT) { + /* Not supported by hairs */ + BLI_dynstr_appendf(ds, "\tvar%d%s = vec4(0.0);\n", input->attr_id, use_geom ? "g" : ""); + } + else if (input->attr_type == CD_ORCO) { + BLI_dynstr_appendf(ds, + "\tvar%d%s = OrcoTexCoFactors[0] + (ModelMatrixInverse * " + "vec4(hair_get_strand_pos(), 1.0)).xyz * OrcoTexCoFactors[1];\n", + input->attr_id, + use_geom ? "g" : ""); + /* TODO: fix ORCO with modifiers. */ + } + else { + BLI_dynstr_appendf(ds, + "\tvar%d%s = hair_get_customdata_%s(att%d);\n", + input->attr_id, + use_geom ? "g" : "", + GPU_DATATYPE_STR[input->type], + input->attr_id); + } + } + } + } + + BLI_dynstr_append(ds, "#else /* MESH_SHADER */\n"); + + /* GPU_BARYCENTRIC_TEXCO cannot be computed based on gl_VertexID + * for MESH_SHADER because of indexed drawing. In this case a + * geometry shader is needed. */ + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_append(ds, "\tbarycentricPosg = (ModelMatrix * vec4(position, 1.0)).xyz;\n"); + } + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTR && input->attr_first) { + if (input->attr_type == CD_TANGENT) { /* silly exception */ + BLI_dynstr_appendf(ds, + "\tvar%d%s.xyz = NormalMatrix * att%d.xyz;\n", + input->attr_id, + use_geom ? "g" : "", + input->attr_id); + BLI_dynstr_appendf( + ds, "\tvar%d%s.w = att%d.w;\n", input->attr_id, use_geom ? "g" : "", input->attr_id); + /* Normalize only if vector is not null. */ + BLI_dynstr_appendf(ds, + "\tfloat lvar%d = dot(var%d%s.xyz, var%d%s.xyz);\n", + input->attr_id, + input->attr_id, + use_geom ? "g" : "", + input->attr_id, + use_geom ? "g" : ""); + BLI_dynstr_appendf(ds, + "\tvar%d%s.xyz *= (lvar%d > 0.0) ? inversesqrt(lvar%d) : 1.0;\n", + input->attr_id, + use_geom ? "g" : "", + input->attr_id, + input->attr_id); + } + else if (input->attr_type == CD_ORCO) { + BLI_dynstr_appendf(ds, + "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n", + input->attr_id, + use_geom ? "g" : ""); + /* See mesh_create_loop_orco() for explanation. */ + BLI_dynstr_appendf(ds, + "\tif (orco.w == 0.0) { var%d%s = orco.xyz * 0.5 + 0.5; }\n", + input->attr_id, + use_geom ? "g" : ""); + } + else if (input->attr_type == CD_MCOL) { + BLI_dynstr_appendf(ds, + "\tvar%d%s = srgb_to_linear_attr(att%d);\n", + input->attr_id, + use_geom ? "g" : "", + input->attr_id); + } + else if (input->attr_type == CD_AUTO_FROM_NAME) { + BLI_dynstr_appendf(ds, + "\tvar%d%s = (att%d_is_srgb) ? srgb_to_linear_attr(att%d) : att%d;\n", + input->attr_id, + use_geom ? "g" : "", + input->attr_id, + input->attr_id, + input->attr_id); + } + else { + BLI_dynstr_appendf( + ds, "\tvar%d%s = att%d;\n", input->attr_id, use_geom ? "g" : "", input->attr_id); + } + } + } + } + BLI_dynstr_append(ds, "#endif /* HAIR_SHADER */\n"); + + BLI_dynstr_append(ds, "}\n"); + + if (use_geom) { + /* XXX HACK: Eevee specific. */ + char *vert_new, *vert_new2; + vert_new = BLI_str_replaceN(vert_code, "worldPosition", "worldPositiong"); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "viewPosition", "viewPositiong"); + MEM_freeN(vert_new2); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "worldNormal", "worldNormalg"); + MEM_freeN(vert_new2); + vert_new2 = vert_new; + vert_new = BLI_str_replaceN(vert_new2, "viewNormal", "viewNormalg"); + MEM_freeN(vert_new2); + + BLI_dynstr_append(ds, vert_new); + + MEM_freeN(vert_new); + } + else { + BLI_dynstr_append(ds, vert_code); + } + + code = BLI_dynstr_get_cstring(ds); + + BLI_dynstr_free(ds); #if 0 - if (G.debug & G_DEBUG) printf("%s\n", code); + if (G.debug & G_DEBUG) printf("%s\n", code); #endif - return code; + return code; } static char *code_generate_geometry(ListBase *nodes, const char *geom_code, const char *defines) { - DynStr *ds = BLI_dynstr_new(); - GPUNode *node; - GPUInput *input; - char *code; - int builtins = 0; - - /* XXX we should not make specific eevee cases here. */ - bool is_hair_shader = (strstr(defines, "HAIR_SHADER") != NULL); - - /* Create prototype because attributes cannot be declared before layout. */ - BLI_dynstr_append(ds, "void pass_attr(in int vert);\n"); - BLI_dynstr_append(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2);\n"); - BLI_dynstr_append(ds, "#define USE_ATTR\n"); - - /* Generate varying declarations. */ - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_BUILTIN) { - builtins |= input->builtin; - } - if (input->source == GPU_SOURCE_ATTR && input->attr_first) { - BLI_dynstr_appendf( - ds, "in %s var%dg[];\n", - GPU_DATATYPE_STR[input->type], - input->attr_id); - BLI_dynstr_appendf( - ds, "out %s var%d;\n", - GPU_DATATYPE_STR[input->type], - input->attr_id); - } - } - } - - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); - BLI_dynstr_append(ds, "in vec2 barycentricTexCog[];\n"); - BLI_dynstr_append(ds, "#endif\n"); - - BLI_dynstr_append(ds, "out vec2 barycentricTexCo;\n"); - } - - if (builtins & GPU_BARYCENTRIC_DIST) { - BLI_dynstr_append(ds, "in vec3 barycentricPosg[];\n"); - BLI_dynstr_append(ds, "flat out vec3 barycentricDist;\n"); - } - - if (geom_code == NULL) { - /* Force geometry usage if GPU_BARYCENTRIC_DIST or GPU_BARYCENTRIC_TEXCO are used. - * Note: GPU_BARYCENTRIC_TEXCO only requires it if the shader is not drawing hairs. */ - if ((builtins & (GPU_BARYCENTRIC_DIST | GPU_BARYCENTRIC_TEXCO)) == 0 || is_hair_shader) { - /* Early out */ - BLI_dynstr_free(ds); - return NULL; - } - else { - /* Force geom shader usage */ - /* TODO put in external file. */ - BLI_dynstr_append(ds, "layout(triangles) in;\n"); - BLI_dynstr_append(ds, "layout(triangle_strip, max_vertices=3) out;\n"); - - BLI_dynstr_append(ds, "in vec3 worldPositiong[];\n"); - BLI_dynstr_append(ds, "in vec3 viewPositiong[];\n"); - BLI_dynstr_append(ds, "in vec3 worldNormalg[];\n"); - BLI_dynstr_append(ds, "in vec3 viewNormalg[];\n"); - - BLI_dynstr_append(ds, "out vec3 worldPosition;\n"); - BLI_dynstr_append(ds, "out vec3 viewPosition;\n"); - BLI_dynstr_append(ds, "out vec3 worldNormal;\n"); - BLI_dynstr_append(ds, "out vec3 viewNormal;\n"); - - BLI_dynstr_append(ds, "void main(){\n"); - - if (builtins & GPU_BARYCENTRIC_DIST) { - BLI_dynstr_append(ds, "\tcalc_barycentric_distances(barycentricPosg[0], barycentricPosg[1], barycentricPosg[2]);\n"); - } - - BLI_dynstr_append(ds, "\tgl_Position = gl_in[0].gl_Position;\n"); - BLI_dynstr_append(ds, "\tpass_attr(0);\n"); - BLI_dynstr_append(ds, "\tEmitVertex();\n"); - - BLI_dynstr_append(ds, "\tgl_Position = gl_in[1].gl_Position;\n"); - BLI_dynstr_append(ds, "\tpass_attr(1);\n"); - BLI_dynstr_append(ds, "\tEmitVertex();\n"); - - BLI_dynstr_append(ds, "\tgl_Position = gl_in[2].gl_Position;\n"); - BLI_dynstr_append(ds, "\tpass_attr(2);\n"); - BLI_dynstr_append(ds, "\tEmitVertex();\n"); - BLI_dynstr_append(ds, "};\n"); - } - } - else { - BLI_dynstr_append(ds, geom_code); - } - - if (builtins & GPU_BARYCENTRIC_DIST) { - BLI_dynstr_append(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2) {\n"); - BLI_dynstr_append(ds, "\tvec3 edge21 = pos2 - pos1;\n"); - BLI_dynstr_append(ds, "\tvec3 edge10 = pos1 - pos0;\n"); - BLI_dynstr_append(ds, "\tvec3 edge02 = pos0 - pos2;\n"); - BLI_dynstr_append(ds, "\tvec3 d21 = normalize(edge21);\n"); - BLI_dynstr_append(ds, "\tvec3 d10 = normalize(edge10);\n"); - BLI_dynstr_append(ds, "\tvec3 d02 = normalize(edge02);\n"); - - BLI_dynstr_append(ds, "\tfloat d = dot(d21, edge02);\n"); - BLI_dynstr_append(ds, "\tbarycentricDist.x = sqrt(dot(edge02, edge02) - d * d);\n"); - BLI_dynstr_append(ds, "\td = dot(d02, edge10);\n"); - BLI_dynstr_append(ds, "\tbarycentricDist.y = sqrt(dot(edge10, edge10) - d * d);\n"); - BLI_dynstr_append(ds, "\td = dot(d10, edge21);\n"); - BLI_dynstr_append(ds, "\tbarycentricDist.z = sqrt(dot(edge21, edge21) - d * d);\n"); - BLI_dynstr_append(ds, "}\n"); - } - - /* Generate varying assignments. */ - BLI_dynstr_append(ds, "void pass_attr(in int vert) {\n"); - - /* XXX HACK: Eevee specific. */ - if (geom_code == NULL) { - BLI_dynstr_append(ds, "\tworldPosition = worldPositiong[vert];\n"); - BLI_dynstr_append(ds, "\tviewPosition = viewPositiong[vert];\n"); - BLI_dynstr_append(ds, "\tworldNormal = worldNormalg[vert];\n"); - BLI_dynstr_append(ds, "\tviewNormal = viewNormalg[vert];\n"); - } - - if (builtins & GPU_BARYCENTRIC_TEXCO) { - BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); - BLI_dynstr_append(ds, "\tbarycentricTexCo = barycentricTexCog[vert];\n"); - BLI_dynstr_append(ds, "#else\n"); - BLI_dynstr_append(ds, "\tbarycentricTexCo.x = float((vert % 3) == 0);\n"); - BLI_dynstr_append(ds, "\tbarycentricTexCo.y = float((vert % 3) == 1);\n"); - BLI_dynstr_append(ds, "#endif\n"); - } - - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_ATTR && input->attr_first) { - /* TODO let shader choose what to do depending on what the attribute is. */ - BLI_dynstr_appendf(ds, "\tvar%d = var%dg[vert];\n", input->attr_id, input->attr_id); - } - } - } - BLI_dynstr_append(ds, "}\n"); - - code = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - return code; + DynStr *ds = BLI_dynstr_new(); + GPUNode *node; + GPUInput *input; + char *code; + int builtins = 0; + + /* XXX we should not make specific eevee cases here. */ + bool is_hair_shader = (strstr(defines, "HAIR_SHADER") != NULL); + + /* Create prototype because attributes cannot be declared before layout. */ + BLI_dynstr_append(ds, "void pass_attr(in int vert);\n"); + BLI_dynstr_append(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2);\n"); + BLI_dynstr_append(ds, "#define USE_ATTR\n"); + + /* Generate varying declarations. */ + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_BUILTIN) { + builtins |= input->builtin; + } + if (input->source == GPU_SOURCE_ATTR && input->attr_first) { + BLI_dynstr_appendf(ds, "in %s var%dg[];\n", GPU_DATATYPE_STR[input->type], input->attr_id); + BLI_dynstr_appendf(ds, "out %s var%d;\n", GPU_DATATYPE_STR[input->type], input->attr_id); + } + } + } + + if (builtins & GPU_BARYCENTRIC_TEXCO) { + BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); + BLI_dynstr_append(ds, "in vec2 barycentricTexCog[];\n"); + BLI_dynstr_append(ds, "#endif\n"); + + BLI_dynstr_append(ds, "out vec2 barycentricTexCo;\n"); + } + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_append(ds, "in vec3 barycentricPosg[];\n"); + BLI_dynstr_append(ds, "flat out vec3 barycentricDist;\n"); + } + + if (geom_code == NULL) { + /* Force geometry usage if GPU_BARYCENTRIC_DIST or GPU_BARYCENTRIC_TEXCO are used. + * Note: GPU_BARYCENTRIC_TEXCO only requires it if the shader is not drawing hairs. */ + if ((builtins & (GPU_BARYCENTRIC_DIST | GPU_BARYCENTRIC_TEXCO)) == 0 || is_hair_shader) { + /* Early out */ + BLI_dynstr_free(ds); + return NULL; + } + else { + /* Force geom shader usage */ + /* TODO put in external file. */ + BLI_dynstr_append(ds, "layout(triangles) in;\n"); + BLI_dynstr_append(ds, "layout(triangle_strip, max_vertices=3) out;\n"); + + BLI_dynstr_append(ds, "in vec3 worldPositiong[];\n"); + BLI_dynstr_append(ds, "in vec3 viewPositiong[];\n"); + BLI_dynstr_append(ds, "in vec3 worldNormalg[];\n"); + BLI_dynstr_append(ds, "in vec3 viewNormalg[];\n"); + + BLI_dynstr_append(ds, "out vec3 worldPosition;\n"); + BLI_dynstr_append(ds, "out vec3 viewPosition;\n"); + BLI_dynstr_append(ds, "out vec3 worldNormal;\n"); + BLI_dynstr_append(ds, "out vec3 viewNormal;\n"); + + BLI_dynstr_append(ds, "void main(){\n"); + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_append(ds, + "\tcalc_barycentric_distances(barycentricPosg[0], barycentricPosg[1], " + "barycentricPosg[2]);\n"); + } + + BLI_dynstr_append(ds, "\tgl_Position = gl_in[0].gl_Position;\n"); + BLI_dynstr_append(ds, "\tpass_attr(0);\n"); + BLI_dynstr_append(ds, "\tEmitVertex();\n"); + + BLI_dynstr_append(ds, "\tgl_Position = gl_in[1].gl_Position;\n"); + BLI_dynstr_append(ds, "\tpass_attr(1);\n"); + BLI_dynstr_append(ds, "\tEmitVertex();\n"); + + BLI_dynstr_append(ds, "\tgl_Position = gl_in[2].gl_Position;\n"); + BLI_dynstr_append(ds, "\tpass_attr(2);\n"); + BLI_dynstr_append(ds, "\tEmitVertex();\n"); + BLI_dynstr_append(ds, "};\n"); + } + } + else { + BLI_dynstr_append(ds, geom_code); + } + + if (builtins & GPU_BARYCENTRIC_DIST) { + BLI_dynstr_append(ds, "void calc_barycentric_distances(vec3 pos0, vec3 pos1, vec3 pos2) {\n"); + BLI_dynstr_append(ds, "\tvec3 edge21 = pos2 - pos1;\n"); + BLI_dynstr_append(ds, "\tvec3 edge10 = pos1 - pos0;\n"); + BLI_dynstr_append(ds, "\tvec3 edge02 = pos0 - pos2;\n"); + BLI_dynstr_append(ds, "\tvec3 d21 = normalize(edge21);\n"); + BLI_dynstr_append(ds, "\tvec3 d10 = normalize(edge10);\n"); + BLI_dynstr_append(ds, "\tvec3 d02 = normalize(edge02);\n"); + + BLI_dynstr_append(ds, "\tfloat d = dot(d21, edge02);\n"); + BLI_dynstr_append(ds, "\tbarycentricDist.x = sqrt(dot(edge02, edge02) - d * d);\n"); + BLI_dynstr_append(ds, "\td = dot(d02, edge10);\n"); + BLI_dynstr_append(ds, "\tbarycentricDist.y = sqrt(dot(edge10, edge10) - d * d);\n"); + BLI_dynstr_append(ds, "\td = dot(d10, edge21);\n"); + BLI_dynstr_append(ds, "\tbarycentricDist.z = sqrt(dot(edge21, edge21) - d * d);\n"); + BLI_dynstr_append(ds, "}\n"); + } + + /* Generate varying assignments. */ + BLI_dynstr_append(ds, "void pass_attr(in int vert) {\n"); + + /* XXX HACK: Eevee specific. */ + if (geom_code == NULL) { + BLI_dynstr_append(ds, "\tworldPosition = worldPositiong[vert];\n"); + BLI_dynstr_append(ds, "\tviewPosition = viewPositiong[vert];\n"); + BLI_dynstr_append(ds, "\tworldNormal = worldNormalg[vert];\n"); + BLI_dynstr_append(ds, "\tviewNormal = viewNormalg[vert];\n"); + } + + if (builtins & GPU_BARYCENTRIC_TEXCO) { + BLI_dynstr_append(ds, "#ifdef HAIR_SHADER\n"); + BLI_dynstr_append(ds, "\tbarycentricTexCo = barycentricTexCog[vert];\n"); + BLI_dynstr_append(ds, "#else\n"); + BLI_dynstr_append(ds, "\tbarycentricTexCo.x = float((vert % 3) == 0);\n"); + BLI_dynstr_append(ds, "\tbarycentricTexCo.y = float((vert % 3) == 1);\n"); + BLI_dynstr_append(ds, "#endif\n"); + } + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTR && input->attr_first) { + /* TODO let shader choose what to do depending on what the attribute is. */ + BLI_dynstr_appendf(ds, "\tvar%d = var%dg[vert];\n", input->attr_id, input->attr_id); + } + } + } + BLI_dynstr_append(ds, "}\n"); + + code = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return code; } void GPU_code_generate_glsl_lib(void) { - DynStr *ds; + DynStr *ds; - /* only initialize the library once */ - if (glsl_material_library) - return; + /* only initialize the library once */ + if (glsl_material_library) + return; - ds = BLI_dynstr_new(); + ds = BLI_dynstr_new(); - BLI_dynstr_append(ds, datatoc_gpu_shader_material_glsl); + BLI_dynstr_append(ds, datatoc_gpu_shader_material_glsl); + glsl_material_library = BLI_dynstr_get_cstring(ds); - glsl_material_library = BLI_dynstr_get_cstring(ds); - - BLI_dynstr_free(ds); + BLI_dynstr_free(ds); } - /* GPU pass binding/unbinding */ GPUShader *GPU_pass_shader_get(GPUPass *pass) { - return pass->shader; + return pass->shader; } void GPU_nodes_extract_dynamic_inputs(GPUShader *shader, ListBase *inputs, ListBase *nodes) { - GPUNode *node; - GPUInput *next, *input; - - BLI_listbase_clear(inputs); - - if (!shader) - return; - - for (node = nodes->first; node; node = node->next) { - int z = 0; - for (input = node->inputs.first; input; input = next, z++) { - next = input->next; - - /* attributes don't need to be bound, they already have - * an id that the drawing functions will use. Builtins have - * constant names. */ - if (ELEM(input->source, GPU_SOURCE_ATTR, GPU_SOURCE_BUILTIN)) { - continue; - } - - if (input->source == GPU_SOURCE_TEX) - BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); - else { - BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); - } - - if (input->source == GPU_SOURCE_TEX) { - if (input->bindtex) { - input->shaderloc = GPU_shader_get_uniform_ensure(shader, input->shadername); - /* extract nodes */ - BLI_remlink(&node->inputs, input); - BLI_addtail(inputs, input); - } - } - } - } + GPUNode *node; + GPUInput *next, *input; + + BLI_listbase_clear(inputs); + + if (!shader) + return; + + for (node = nodes->first; node; node = node->next) { + int z = 0; + for (input = node->inputs.first; input; input = next, z++) { + next = input->next; + + /* attributes don't need to be bound, they already have + * an id that the drawing functions will use. Builtins have + * constant names. */ + if (ELEM(input->source, GPU_SOURCE_ATTR, GPU_SOURCE_BUILTIN)) { + continue; + } + + if (input->source == GPU_SOURCE_TEX) + BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); + else { + BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); + } + + if (input->source == GPU_SOURCE_TEX) { + if (input->bindtex) { + input->shaderloc = GPU_shader_get_uniform_ensure(shader, input->shadername); + /* extract nodes */ + BLI_remlink(&node->inputs, input); + BLI_addtail(inputs, input); + } + } + } + } } /* Node Link Functions */ static GPUNodeLink *GPU_node_link_create(void) { - GPUNodeLink *link = MEM_callocN(sizeof(GPUNodeLink), "GPUNodeLink"); - link->users++; + GPUNodeLink *link = MEM_callocN(sizeof(GPUNodeLink), "GPUNodeLink"); + link->users++; - return link; + return link; } static void gpu_node_link_free(GPUNodeLink *link) { - link->users--; + link->users--; - if (link->users < 0) - fprintf(stderr, "GPU_node_link_free: negative refcount\n"); + if (link->users < 0) + fprintf(stderr, "GPU_node_link_free: negative refcount\n"); - if (link->users == 0) { - if (link->output) - link->output->link = NULL; - MEM_freeN(link); - } + if (link->users == 0) { + if (link->output) + link->output->link = NULL; + MEM_freeN(link); + } } /* Node Functions */ static GPUNode *GPU_node_begin(const char *name) { - GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode"); + GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode"); - node->name = name; + node->name = name; - return node; + return node; } static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType type) { - GPUInput *input; - GPUNode *outnode; - const char *name; - - if (link->link_type == GPU_NODE_LINK_OUTPUT) { - outnode = link->output->node; - name = outnode->name; - input = outnode->inputs.first; - - if ((STR_ELEM(name, "set_value", "set_rgb", "set_rgba")) && - (input->type == type)) - { - input = MEM_dupallocN(outnode->inputs.first); - if (input->link) - input->link->users++; - BLI_addtail(&node->inputs, input); - return; - } - } - - input = MEM_callocN(sizeof(GPUInput), "GPUInput"); - input->node = node; - input->type = type; - - switch (link->link_type) { - case GPU_NODE_LINK_BUILTIN: - input->source = GPU_SOURCE_BUILTIN; - input->builtin = link->builtin; - break; - case GPU_NODE_LINK_OUTPUT: - input->source = GPU_SOURCE_OUTPUT; - input->link = link; - link->users++; - break; - case GPU_NODE_LINK_COLORBAND: - input->source = GPU_SOURCE_TEX; - input->coba = link->coba; - break; - case GPU_NODE_LINK_IMAGE_BLENDER: - input->source = GPU_SOURCE_TEX; - input->ima = link->ima; - input->iuser = link->iuser; - input->image_isdata = link->image_isdata; - break; - case GPU_NODE_LINK_ATTR: - input->source = GPU_SOURCE_ATTR; - input->attr_type = link->attr_type; - BLI_strncpy(input->attr_name, link->attr_name, sizeof(input->attr_name)); - break; - case GPU_NODE_LINK_CONSTANT: - input->source = (type == GPU_CLOSURE) ? GPU_SOURCE_STRUCT : GPU_SOURCE_CONSTANT; - break; - case GPU_NODE_LINK_UNIFORM: - input->source = GPU_SOURCE_UNIFORM; - break; - default: - break; - } - - if (ELEM(input->source, GPU_SOURCE_CONSTANT, GPU_SOURCE_UNIFORM)) { - memcpy(input->vec, link->data, type * sizeof(float)); - } - - if (link->link_type != GPU_NODE_LINK_OUTPUT) { - MEM_freeN(link); - } - BLI_addtail(&node->inputs, input); + GPUInput *input; + GPUNode *outnode; + const char *name; + + if (link->link_type == GPU_NODE_LINK_OUTPUT) { + outnode = link->output->node; + name = outnode->name; + input = outnode->inputs.first; + + if ((STR_ELEM(name, "set_value", "set_rgb", "set_rgba")) && (input->type == type)) { + input = MEM_dupallocN(outnode->inputs.first); + if (input->link) + input->link->users++; + BLI_addtail(&node->inputs, input); + return; + } + } + + input = MEM_callocN(sizeof(GPUInput), "GPUInput"); + input->node = node; + input->type = type; + + switch (link->link_type) { + case GPU_NODE_LINK_BUILTIN: + input->source = GPU_SOURCE_BUILTIN; + input->builtin = link->builtin; + break; + case GPU_NODE_LINK_OUTPUT: + input->source = GPU_SOURCE_OUTPUT; + input->link = link; + link->users++; + break; + case GPU_NODE_LINK_COLORBAND: + input->source = GPU_SOURCE_TEX; + input->coba = link->coba; + break; + case GPU_NODE_LINK_IMAGE_BLENDER: + input->source = GPU_SOURCE_TEX; + input->ima = link->ima; + input->iuser = link->iuser; + input->image_isdata = link->image_isdata; + break; + case GPU_NODE_LINK_ATTR: + input->source = GPU_SOURCE_ATTR; + input->attr_type = link->attr_type; + BLI_strncpy(input->attr_name, link->attr_name, sizeof(input->attr_name)); + break; + case GPU_NODE_LINK_CONSTANT: + input->source = (type == GPU_CLOSURE) ? GPU_SOURCE_STRUCT : GPU_SOURCE_CONSTANT; + break; + case GPU_NODE_LINK_UNIFORM: + input->source = GPU_SOURCE_UNIFORM; + break; + default: + break; + } + + if (ELEM(input->source, GPU_SOURCE_CONSTANT, GPU_SOURCE_UNIFORM)) { + memcpy(input->vec, link->data, type * sizeof(float)); + } + + if (link->link_type != GPU_NODE_LINK_OUTPUT) { + MEM_freeN(link); + } + BLI_addtail(&node->inputs, input); } - static const char *gpu_uniform_set_function_from_type(eNodeSocketDatatype type) { - switch (type) { - /* For now INT is supported as float. */ - case SOCK_INT: - case SOCK_FLOAT: - return "set_value"; - case SOCK_VECTOR: - return "set_rgb"; - case SOCK_RGBA: - return "set_rgba"; - default: - BLI_assert(!"No gpu function for non-supported eNodeSocketDatatype"); - return NULL; - } + switch (type) { + /* For now INT is supported as float. */ + case SOCK_INT: + case SOCK_FLOAT: + return "set_value"; + case SOCK_VECTOR: + return "set_rgb"; + case SOCK_RGBA: + return "set_rgba"; + default: + BLI_assert(!"No gpu function for non-supported eNodeSocketDatatype"); + return NULL; + } } /** * Link stack uniform buffer. * This is called for the input/output sockets that are note connected. */ -static GPUNodeLink *gpu_uniformbuffer_link( - GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index, const eNodeSocketInOut in_out) +static GPUNodeLink *gpu_uniformbuffer_link(GPUMaterial *mat, + bNode *node, + GPUNodeStack *stack, + const int index, + const eNodeSocketInOut in_out) { - bNodeSocket *socket; - - if (in_out == SOCK_IN) { - socket = BLI_findlink(&node->inputs, index); - } - else { - socket = BLI_findlink(&node->outputs, index); - } - - BLI_assert(socket != NULL); - BLI_assert(socket->in_out == in_out); - - if ((socket->flag & SOCK_HIDE_VALUE) == 0) { - GPUNodeLink *link; - switch (socket->type) { - case SOCK_FLOAT: - { - bNodeSocketValueFloat *socket_data = socket->default_value; - link = GPU_uniform(&socket_data->value); - break; - } - case SOCK_VECTOR: - { - bNodeSocketValueVector *socket_data = socket->default_value; - link = GPU_uniform(socket_data->value); - break; - } - case SOCK_RGBA: - { - bNodeSocketValueRGBA *socket_data = socket->default_value; - link = GPU_uniform(socket_data->value); - break; - } - default: - return NULL; - break; - } - - if (in_out == SOCK_IN) { - GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link); - } - return link; - } - return NULL; + bNodeSocket *socket; + + if (in_out == SOCK_IN) { + socket = BLI_findlink(&node->inputs, index); + } + else { + socket = BLI_findlink(&node->outputs, index); + } + + BLI_assert(socket != NULL); + BLI_assert(socket->in_out == in_out); + + if ((socket->flag & SOCK_HIDE_VALUE) == 0) { + GPUNodeLink *link; + switch (socket->type) { + case SOCK_FLOAT: { + bNodeSocketValueFloat *socket_data = socket->default_value; + link = GPU_uniform(&socket_data->value); + break; + } + case SOCK_VECTOR: { + bNodeSocketValueVector *socket_data = socket->default_value; + link = GPU_uniform(socket_data->value); + break; + } + case SOCK_RGBA: { + bNodeSocketValueRGBA *socket_data = socket->default_value; + link = GPU_uniform(socket_data->value); + break; + } + default: + return NULL; + break; + } + + if (in_out == SOCK_IN) { + GPU_link(mat, gpu_uniform_set_function_from_type(socket->type), link, &stack->link); + } + return link; + } + return NULL; } -static void gpu_node_input_socket(GPUMaterial *material, bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index) +static void gpu_node_input_socket( + GPUMaterial *material, bNode *bnode, GPUNode *node, GPUNodeStack *sock, const int index) { - if (sock->link) { - gpu_node_input_link(node, sock->link, sock->type); - } - else if ((material != NULL) && (gpu_uniformbuffer_link(material, bnode, sock, index, SOCK_IN) != NULL)) { - gpu_node_input_link(node, sock->link, sock->type); - } - else { - gpu_node_input_link(node, GPU_constant(sock->vec), sock->type); - } + if (sock->link) { + gpu_node_input_link(node, sock->link, sock->type); + } + else if ((material != NULL) && + (gpu_uniformbuffer_link(material, bnode, sock, index, SOCK_IN) != NULL)) { + gpu_node_input_link(node, sock->link, sock->type); + } + else { + gpu_node_input_link(node, GPU_constant(sock->vec), sock->type); + } } static void gpu_node_output(GPUNode *node, const eGPUType type, GPUNodeLink **link) { - GPUOutput *output = MEM_callocN(sizeof(GPUOutput), "GPUOutput"); + GPUOutput *output = MEM_callocN(sizeof(GPUOutput), "GPUOutput"); - output->type = type; - output->node = node; + output->type = type; + output->node = node; - if (link) { - *link = output->link = GPU_node_link_create(); - output->link->link_type = GPU_NODE_LINK_OUTPUT; - output->link->output = output; + if (link) { + *link = output->link = GPU_node_link_create(); + output->link->link_type = GPU_NODE_LINK_OUTPUT; + output->link->output = output; - /* note: the caller owns the reference to the link, GPUOutput - * merely points to it, and if the node is destroyed it will - * set that pointer to NULL */ - } + /* note: the caller owns the reference to the link, GPUOutput + * merely points to it, and if the node is destroyed it will + * set that pointer to NULL */ + } - BLI_addtail(&node->outputs, output); + BLI_addtail(&node->outputs, output); } void GPU_inputs_free(ListBase *inputs) { - GPUInput *input; + GPUInput *input; - for (input = inputs->first; input; input = input->next) { - if (input->link) - gpu_node_link_free(input->link); - } + for (input = inputs->first; input; input = input->next) { + if (input->link) + gpu_node_link_free(input->link); + } - BLI_freelistN(inputs); + BLI_freelistN(inputs); } static void gpu_node_free(GPUNode *node) { - GPUOutput *output; + GPUOutput *output; - GPU_inputs_free(&node->inputs); + GPU_inputs_free(&node->inputs); - for (output = node->outputs.first; output; output = output->next) - if (output->link) { - output->link->output = NULL; - gpu_node_link_free(output->link); - } + for (output = node->outputs.first; output; output = output->next) + if (output->link) { + output->link->output = NULL; + gpu_node_link_free(output->link); + } - BLI_freelistN(&node->outputs); - MEM_freeN(node); + BLI_freelistN(&node->outputs); + MEM_freeN(node); } static void gpu_nodes_free(ListBase *nodes) { - GPUNode *node; + GPUNode *node; - while ((node = BLI_pophead(nodes))) { - gpu_node_free(node); - } + while ((node = BLI_pophead(nodes))) { + gpu_node_free(node); + } } /* vertex attributes */ void GPU_nodes_get_vertex_attrs(ListBase *nodes, GPUVertAttrLayers *attrs) { - GPUNode *node; - GPUInput *input; - int a; - - /* convert attributes requested by node inputs to an array of layers, - * checking for duplicates and assigning id's starting from zero. */ - - memset(attrs, 0, sizeof(*attrs)); - - for (node = nodes->first; node; node = node->next) { - for (input = node->inputs.first; input; input = input->next) { - if (input->source == GPU_SOURCE_ATTR) { - for (a = 0; a < attrs->totlayer; a++) { - if (attrs->layer[a].type == input->attr_type && - STREQ(attrs->layer[a].name, input->attr_name)) - { - break; - } - } - - if (a < GPU_MAX_ATTR) { - if (a == attrs->totlayer) { - input->attr_id = attrs->totlayer++; - input->attr_first = true; - - attrs->layer[a].type = input->attr_type; - attrs->layer[a].attr_id = input->attr_id; - BLI_strncpy( - attrs->layer[a].name, input->attr_name, - sizeof(attrs->layer[a].name)); - } - else { - input->attr_id = attrs->layer[a].attr_id; - } - } - } - } - } + GPUNode *node; + GPUInput *input; + int a; + + /* convert attributes requested by node inputs to an array of layers, + * checking for duplicates and assigning id's starting from zero. */ + + memset(attrs, 0, sizeof(*attrs)); + + for (node = nodes->first; node; node = node->next) { + for (input = node->inputs.first; input; input = input->next) { + if (input->source == GPU_SOURCE_ATTR) { + for (a = 0; a < attrs->totlayer; a++) { + if (attrs->layer[a].type == input->attr_type && + STREQ(attrs->layer[a].name, input->attr_name)) { + break; + } + } + + if (a < GPU_MAX_ATTR) { + if (a == attrs->totlayer) { + input->attr_id = attrs->totlayer++; + input->attr_first = true; + + attrs->layer[a].type = input->attr_type; + attrs->layer[a].attr_id = input->attr_id; + BLI_strncpy(attrs->layer[a].name, input->attr_name, sizeof(attrs->layer[a].name)); + } + else { + input->attr_id = attrs->layer[a].attr_id; + } + } + } + } + } } /* varargs linking */ GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name) { - GPUNodeLink *link = GPU_node_link_create(); - link->link_type = GPU_NODE_LINK_ATTR; - link->attr_name = name; - /* Fall back to the UV layer, which matches old behavior. */ - if (type == CD_AUTO_FROM_NAME && name[0] == '\0') { - link->attr_type = CD_MTFACE; - } - else { - link->attr_type = type; - } - return link; + GPUNodeLink *link = GPU_node_link_create(); + link->link_type = GPU_NODE_LINK_ATTR; + link->attr_name = name; + /* Fall back to the UV layer, which matches old behavior. */ + if (type == CD_AUTO_FROM_NAME && name[0] == '\0') { + link->attr_type = CD_MTFACE; + } + else { + link->attr_type = type; + } + return link; } GPUNodeLink *GPU_constant(float *num) { - GPUNodeLink *link = GPU_node_link_create(); - link->link_type = GPU_NODE_LINK_CONSTANT; - link->data = num; - return link; + GPUNodeLink *link = GPU_node_link_create(); + link->link_type = GPU_NODE_LINK_CONSTANT; + link->data = num; + return link; } GPUNodeLink *GPU_uniform(float *num) { - GPUNodeLink *link = GPU_node_link_create(); - link->link_type = GPU_NODE_LINK_UNIFORM; - link->data = num; - return link; + GPUNodeLink *link = GPU_node_link_create(); + link->link_type = GPU_NODE_LINK_UNIFORM; + link->data = num; + return link; } GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data) { - GPUNodeLink *link = GPU_node_link_create(); - link->link_type = GPU_NODE_LINK_IMAGE_BLENDER; - link->ima = ima; - link->iuser = iuser; - link->image_isdata = is_data; - return link; + GPUNodeLink *link = GPU_node_link_create(); + link->link_type = GPU_NODE_LINK_IMAGE_BLENDER; + link->ima = ima; + link->iuser = iuser; + link->image_isdata = is_data; + return link; } GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *row) { - GPUNodeLink *link = GPU_node_link_create(); - link->link_type = GPU_NODE_LINK_COLORBAND; - link->coba = gpu_material_ramp_texture_row_set(mat, size, pixels, row); - MEM_freeN(pixels); - return link; + GPUNodeLink *link = GPU_node_link_create(); + link->link_type = GPU_NODE_LINK_COLORBAND; + link->coba = gpu_material_ramp_texture_row_set(mat, size, pixels, row); + MEM_freeN(pixels); + return link; } GPUNodeLink *GPU_builtin(eGPUBuiltin builtin) { - GPUNodeLink *link = GPU_node_link_create(); - link->link_type = GPU_NODE_LINK_BUILTIN; - link->builtin = builtin; - return link; + GPUNodeLink *link = GPU_node_link_create(); + link->link_type = GPU_NODE_LINK_BUILTIN; + link->builtin = builtin; + return link; } bool GPU_link(GPUMaterial *mat, const char *name, ...) { - GPUNode *node; - GPUFunction *function; - GPUNodeLink *link, **linkptr; - va_list params; - int i; - - function = gpu_lookup_function(name); - if (!function) { - fprintf(stderr, "GPU failed to find function %s\n", name); - return false; - } - - node = GPU_node_begin(name); - - va_start(params, name); - for (i = 0; i < function->totparam; i++) { - if (function->paramqual[i] != FUNCTION_QUAL_IN) { - linkptr = va_arg(params, GPUNodeLink **); - gpu_node_output(node, function->paramtype[i], linkptr); - } - else { - link = va_arg(params, GPUNodeLink *); - gpu_node_input_link(node, link, function->paramtype[i]); - } - } - va_end(params); - - gpu_material_add_node(mat, node); - - return true; + GPUNode *node; + GPUFunction *function; + GPUNodeLink *link, **linkptr; + va_list params; + int i; + + function = gpu_lookup_function(name); + if (!function) { + fprintf(stderr, "GPU failed to find function %s\n", name); + return false; + } + + node = GPU_node_begin(name); + + va_start(params, name); + for (i = 0; i < function->totparam; i++) { + if (function->paramqual[i] != FUNCTION_QUAL_IN) { + linkptr = va_arg(params, GPUNodeLink **); + gpu_node_output(node, function->paramtype[i], linkptr); + } + else { + link = va_arg(params, GPUNodeLink *); + gpu_node_input_link(node, link, function->paramtype[i]); + } + } + va_end(params); + + gpu_material_add_node(mat, node); + + return true; } -bool GPU_stack_link(GPUMaterial *material, bNode *bnode, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...) +bool GPU_stack_link(GPUMaterial *material, + bNode *bnode, + const char *name, + GPUNodeStack *in, + GPUNodeStack *out, + ...) { - GPUNode *node; - GPUFunction *function; - GPUNodeLink *link, **linkptr; - va_list params; - int i, totin, totout; - - function = gpu_lookup_function(name); - if (!function) { - fprintf(stderr, "GPU failed to find function %s\n", name); - return false; - } - - node = GPU_node_begin(name); - totin = 0; - totout = 0; - - if (in) { - for (i = 0; !in[i].end; i++) { - if (in[i].type != GPU_NONE) { - gpu_node_input_socket(material, bnode, node, &in[i], i); - totin++; - } - } - } - - if (out) { - for (i = 0; !out[i].end; i++) { - if (out[i].type != GPU_NONE) { - gpu_node_output(node, out[i].type, &out[i].link); - totout++; - } - } - } - - va_start(params, out); - for (i = 0; i < function->totparam; i++) { - if (function->paramqual[i] != FUNCTION_QUAL_IN) { - if (totout == 0) { - linkptr = va_arg(params, GPUNodeLink **); - gpu_node_output(node, function->paramtype[i], linkptr); - } - else - totout--; - } - else { - if (totin == 0) { - link = va_arg(params, GPUNodeLink *); - if (link->socket) - gpu_node_input_socket(NULL, NULL, node, link->socket, -1); - else - gpu_node_input_link(node, link, function->paramtype[i]); - } - else - totin--; - } - } - va_end(params); - - gpu_material_add_node(material, node); - - return true; + GPUNode *node; + GPUFunction *function; + GPUNodeLink *link, **linkptr; + va_list params; + int i, totin, totout; + + function = gpu_lookup_function(name); + if (!function) { + fprintf(stderr, "GPU failed to find function %s\n", name); + return false; + } + + node = GPU_node_begin(name); + totin = 0; + totout = 0; + + if (in) { + for (i = 0; !in[i].end; i++) { + if (in[i].type != GPU_NONE) { + gpu_node_input_socket(material, bnode, node, &in[i], i); + totin++; + } + } + } + + if (out) { + for (i = 0; !out[i].end; i++) { + if (out[i].type != GPU_NONE) { + gpu_node_output(node, out[i].type, &out[i].link); + totout++; + } + } + } + + va_start(params, out); + for (i = 0; i < function->totparam; i++) { + if (function->paramqual[i] != FUNCTION_QUAL_IN) { + if (totout == 0) { + linkptr = va_arg(params, GPUNodeLink **); + gpu_node_output(node, function->paramtype[i], linkptr); + } + else + totout--; + } + else { + if (totin == 0) { + link = va_arg(params, GPUNodeLink *); + if (link->socket) + gpu_node_input_socket(NULL, NULL, node, link->socket, -1); + else + gpu_node_input_link(node, link, function->paramtype[i]); + } + else + totin--; + } + } + va_end(params); + + gpu_material_add_node(material, node); + + return true; } -GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat, bNode *node, GPUNodeStack *stack, const int index) +GPUNodeLink *GPU_uniformbuffer_link_out(GPUMaterial *mat, + bNode *node, + GPUNodeStack *stack, + const int index) { - return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT); + return gpu_uniformbuffer_link(mat, node, stack, index, SOCK_OUT); } /* Pass create/free */ static void gpu_nodes_tag(GPUNodeLink *link) { - GPUNode *node; - GPUInput *input; + GPUNode *node; + GPUInput *input; - if (!link->output) - return; + if (!link->output) + return; - node = link->output->node; - if (node->tag) - return; + node = link->output->node; + if (node->tag) + return; - node->tag = true; - for (input = node->inputs.first; input; input = input->next) - if (input->link) - gpu_nodes_tag(input->link); + node->tag = true; + for (input = node->inputs.first; input; input = input->next) + if (input->link) + gpu_nodes_tag(input->link); } void GPU_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) { - GPUNode *node, *next; + GPUNode *node, *next; - for (node = nodes->first; node; node = node->next) - node->tag = false; + for (node = nodes->first; node; node = node->next) + node->tag = false; - gpu_nodes_tag(outlink); + gpu_nodes_tag(outlink); - for (node = nodes->first; node; node = next) { - next = node->next; + for (node = nodes->first; node; node = next) { + next = node->next; - if (!node->tag) { - BLI_remlink(nodes, node); - gpu_node_free(node); - } - } + if (!node->tag) { + BLI_remlink(nodes, node); + gpu_node_free(node); + } + } } static bool gpu_pass_is_valid(GPUPass *pass) { - /* Shader is not null if compilation is successful. */ - return (pass->compiled == false || pass->shader != NULL); + /* Shader is not null if compilation is successful. */ + return (pass->compiled == false || pass->shader != NULL); } -GPUPass *GPU_generate_pass( - GPUMaterial *material, - GPUNodeLink *frag_outlink, - struct GPUVertAttrLayers *attrs, - ListBase *nodes, - int *builtins, - const char *vert_code, - const char *geom_code, - const char *frag_lib, - const char *defines) +GPUPass *GPU_generate_pass(GPUMaterial *material, + GPUNodeLink *frag_outlink, + struct GPUVertAttrLayers *attrs, + ListBase *nodes, + int *builtins, + const char *vert_code, + const char *geom_code, + const char *frag_lib, + const char *defines) { - char *vertexcode, *geometrycode, *fragmentcode; - GPUPass *pass = NULL, *pass_hash = NULL; - - /* prune unused nodes */ - GPU_nodes_prune(nodes, frag_outlink); - - GPU_nodes_get_vertex_attrs(nodes, attrs); - - /* generate code */ - char *fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, builtins); - - /* Cache lookup: Reuse shaders already compiled */ - uint32_t hash = gpu_pass_hash(fragmentgen, defines, attrs); - pass_hash = gpu_pass_cache_lookup(hash); - - if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) { - /* No collision, just return the pass. */ - MEM_freeN(fragmentgen); - if (!gpu_pass_is_valid(pass_hash)) { - /* Shader has already been created but failed to compile. */ - return NULL; - } - pass_hash->refcount += 1; - return pass_hash; - } - - /* Either the shader is not compiled or there is a hash collision... - * continue generating the shader strings. */ - char *tmp = BLI_strdupcat(frag_lib, glsl_material_library); - - geometrycode = code_generate_geometry(nodes, geom_code, defines); - vertexcode = code_generate_vertex(nodes, vert_code, (geometrycode != NULL)); - fragmentcode = BLI_strdupcat(tmp, fragmentgen); - - MEM_freeN(fragmentgen); - MEM_freeN(tmp); - - if (pass_hash) { - /* Cache lookup: Reuse shaders already compiled */ - pass = gpu_pass_cache_resolve_collision(pass_hash, vertexcode, geometrycode, fragmentcode, defines, hash); - } - - if (pass) { - /* Cache hit. Reuse the same GPUPass and GPUShader. */ - if (!gpu_pass_is_valid(pass)) { - /* Shader has already been created but failed to compile. */ - return NULL; - } - - MEM_SAFE_FREE(vertexcode); - MEM_SAFE_FREE(fragmentcode); - MEM_SAFE_FREE(geometrycode); - - pass->refcount += 1; - } - else { - /* We still create a pass even if shader compilation - * fails to avoid trying to compile again and again. */ - pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); - pass->shader = NULL; - pass->refcount = 1; - pass->hash = hash; - pass->vertexcode = vertexcode; - pass->fragmentcode = fragmentcode; - pass->geometrycode = geometrycode; - pass->defines = (defines) ? BLI_strdup(defines) : NULL; - pass->compiled = false; - - BLI_spin_lock(&pass_cache_spin); - if (pass_hash != NULL) { - /* Add after the first pass having the same hash. */ - pass->next = pass_hash->next; - pass_hash->next = pass; - } - else { - /* No other pass have same hash, just prepend to the list. */ - BLI_LINKS_PREPEND(pass_cache, pass); - } - BLI_spin_unlock(&pass_cache_spin); - } - - return pass; + char *vertexcode, *geometrycode, *fragmentcode; + GPUPass *pass = NULL, *pass_hash = NULL; + + /* prune unused nodes */ + GPU_nodes_prune(nodes, frag_outlink); + + GPU_nodes_get_vertex_attrs(nodes, attrs); + + /* generate code */ + char *fragmentgen = code_generate_fragment(material, nodes, frag_outlink->output, builtins); + + /* Cache lookup: Reuse shaders already compiled */ + uint32_t hash = gpu_pass_hash(fragmentgen, defines, attrs); + pass_hash = gpu_pass_cache_lookup(hash); + + if (pass_hash && (pass_hash->next == NULL || pass_hash->next->hash != hash)) { + /* No collision, just return the pass. */ + MEM_freeN(fragmentgen); + if (!gpu_pass_is_valid(pass_hash)) { + /* Shader has already been created but failed to compile. */ + return NULL; + } + pass_hash->refcount += 1; + return pass_hash; + } + + /* Either the shader is not compiled or there is a hash collision... + * continue generating the shader strings. */ + char *tmp = BLI_strdupcat(frag_lib, glsl_material_library); + + geometrycode = code_generate_geometry(nodes, geom_code, defines); + vertexcode = code_generate_vertex(nodes, vert_code, (geometrycode != NULL)); + fragmentcode = BLI_strdupcat(tmp, fragmentgen); + + MEM_freeN(fragmentgen); + MEM_freeN(tmp); + + if (pass_hash) { + /* Cache lookup: Reuse shaders already compiled */ + pass = gpu_pass_cache_resolve_collision( + pass_hash, vertexcode, geometrycode, fragmentcode, defines, hash); + } + + if (pass) { + /* Cache hit. Reuse the same GPUPass and GPUShader. */ + if (!gpu_pass_is_valid(pass)) { + /* Shader has already been created but failed to compile. */ + return NULL; + } + + MEM_SAFE_FREE(vertexcode); + MEM_SAFE_FREE(fragmentcode); + MEM_SAFE_FREE(geometrycode); + + pass->refcount += 1; + } + else { + /* We still create a pass even if shader compilation + * fails to avoid trying to compile again and again. */ + pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); + pass->shader = NULL; + pass->refcount = 1; + pass->hash = hash; + pass->vertexcode = vertexcode; + pass->fragmentcode = fragmentcode; + pass->geometrycode = geometrycode; + pass->defines = (defines) ? BLI_strdup(defines) : NULL; + pass->compiled = false; + + BLI_spin_lock(&pass_cache_spin); + if (pass_hash != NULL) { + /* Add after the first pass having the same hash. */ + pass->next = pass_hash->next; + pass_hash->next = pass; + } + else { + /* No other pass have same hash, just prepend to the list. */ + BLI_LINKS_PREPEND(pass_cache, pass); + } + BLI_spin_unlock(&pass_cache_spin); + } + + return pass; } static int count_active_texture_sampler(GPUShader *shader, char *source) { - char *code = source; - int samplers_id[64]; /* Remember this is per stage. */ - int sampler_len = 0; - - while ((code = strstr(code, "uniform "))) { - /* Move past "uniform". */ - code += 7; - /* Skip following spaces. */ - while (*code == ' ') { code++; } - /* Skip "i" from potential isamplers. */ - if (*code == 'i') { code++; } - /* Skip following spaces. */ - if (gpu_str_prefix(code, "sampler")) { - /* Move past "uniform". */ - code += 7; - /* Skip sampler type suffix. */ - while (*code != ' ' && *code != '\0') { code++; } - /* Skip following spaces. */ - while (*code == ' ') { code++; } - - if (*code != '\0') { - char sampler_name[64]; - code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name)); - int id = GPU_shader_get_uniform_ensure(shader, sampler_name); - - if (id == -1) { - continue; - } - /* Catch duplicates. */ - bool is_duplicate = false; - for (int i = 0; i < sampler_len; ++i) { - if (samplers_id[i] == id) { - is_duplicate = true; - } - } - - if (!is_duplicate) { - samplers_id[sampler_len] = id; - sampler_len++; - } - } - } - } - - return sampler_len; + char *code = source; + int samplers_id[64]; /* Remember this is per stage. */ + int sampler_len = 0; + + while ((code = strstr(code, "uniform "))) { + /* Move past "uniform". */ + code += 7; + /* Skip following spaces. */ + while (*code == ' ') { + code++; + } + /* Skip "i" from potential isamplers. */ + if (*code == 'i') { + code++; + } + /* Skip following spaces. */ + if (gpu_str_prefix(code, "sampler")) { + /* Move past "uniform". */ + code += 7; + /* Skip sampler type suffix. */ + while (*code != ' ' && *code != '\0') { + code++; + } + /* Skip following spaces. */ + while (*code == ' ') { + code++; + } + + if (*code != '\0') { + char sampler_name[64]; + code = gpu_str_skip_token(code, sampler_name, sizeof(sampler_name)); + int id = GPU_shader_get_uniform_ensure(shader, sampler_name); + + if (id == -1) { + continue; + } + /* Catch duplicates. */ + bool is_duplicate = false; + for (int i = 0; i < sampler_len; ++i) { + if (samplers_id[i] == id) { + is_duplicate = true; + } + } + + if (!is_duplicate) { + samplers_id[sampler_len] = id; + sampler_len++; + } + } + } + } + + return sampler_len; } static bool gpu_pass_shader_validate(GPUPass *pass) { - if (pass->shader == NULL) { - return false; - } - - /* NOTE: The only drawback of this method is that it will count a sampler - * used in the fragment shader and only declared (but not used) in the vertex - * shader as used by both. But this corner case is not happening for now. */ - int vert_samplers_len = count_active_texture_sampler(pass->shader, pass->vertexcode); - int frag_samplers_len = count_active_texture_sampler(pass->shader, pass->fragmentcode); - - int total_samplers_len = vert_samplers_len + frag_samplers_len; - - /* Validate against opengl limit. */ - if ((frag_samplers_len > GPU_max_textures_frag()) || - (vert_samplers_len > GPU_max_textures_vert())) - { - return false; - } - - if (pass->geometrycode) { - int geom_samplers_len = count_active_texture_sampler(pass->shader, pass->geometrycode); - total_samplers_len += geom_samplers_len; - if (geom_samplers_len > GPU_max_textures_geom()) { - return false; - } - } - - return (total_samplers_len <= GPU_max_textures()); + if (pass->shader == NULL) { + return false; + } + + /* NOTE: The only drawback of this method is that it will count a sampler + * used in the fragment shader and only declared (but not used) in the vertex + * shader as used by both. But this corner case is not happening for now. */ + int vert_samplers_len = count_active_texture_sampler(pass->shader, pass->vertexcode); + int frag_samplers_len = count_active_texture_sampler(pass->shader, pass->fragmentcode); + + int total_samplers_len = vert_samplers_len + frag_samplers_len; + + /* Validate against opengl limit. */ + if ((frag_samplers_len > GPU_max_textures_frag()) || + (vert_samplers_len > GPU_max_textures_vert())) { + return false; + } + + if (pass->geometrycode) { + int geom_samplers_len = count_active_texture_sampler(pass->shader, pass->geometrycode); + total_samplers_len += geom_samplers_len; + if (geom_samplers_len > GPU_max_textures_geom()) { + return false; + } + } + + return (total_samplers_len <= GPU_max_textures()); } void GPU_pass_compile(GPUPass *pass, const char *shname) { - if (!pass->compiled) { - pass->shader = GPU_shader_create( - pass->vertexcode, - pass->fragmentcode, - pass->geometrycode, - NULL, - pass->defines, - shname); - - /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit. - * We need to make sure to count active samplers to avoid undefined behavior. */ - if (!gpu_pass_shader_validate(pass)) { - if (pass->shader != NULL) { - fprintf(stderr, "GPUShader: error: too many samplers in shader.\n"); - GPU_shader_free(pass->shader); - } - pass->shader = NULL; - } - else if (!BLI_thread_is_main()) { - /* For some Intel drivers, you must use the program at least once - * in the rendering context that it is linked. */ - glUseProgram(GPU_shader_get_program(pass->shader)); - glUseProgram(0); - } - - pass->compiled = true; - } + if (!pass->compiled) { + pass->shader = GPU_shader_create( + pass->vertexcode, pass->fragmentcode, pass->geometrycode, NULL, pass->defines, shname); + + /* NOTE: Some drivers / gpu allows more active samplers than the opengl limit. + * We need to make sure to count active samplers to avoid undefined behavior. */ + if (!gpu_pass_shader_validate(pass)) { + if (pass->shader != NULL) { + fprintf(stderr, "GPUShader: error: too many samplers in shader.\n"); + GPU_shader_free(pass->shader); + } + pass->shader = NULL; + } + else if (!BLI_thread_is_main()) { + /* For some Intel drivers, you must use the program at least once + * in the rendering context that it is linked. */ + glUseProgram(GPU_shader_get_program(pass->shader)); + glUseProgram(0); + } + + pass->compiled = true; + } } void GPU_pass_release(GPUPass *pass) { - BLI_assert(pass->refcount > 0); - pass->refcount--; + BLI_assert(pass->refcount > 0); + pass->refcount--; } static void gpu_pass_free(GPUPass *pass) { - BLI_assert(pass->refcount == 0); - if (pass->shader) { - GPU_shader_free(pass->shader); - } - MEM_SAFE_FREE(pass->fragmentcode); - MEM_SAFE_FREE(pass->geometrycode); - MEM_SAFE_FREE(pass->vertexcode); - MEM_SAFE_FREE(pass->defines); - MEM_freeN(pass); + BLI_assert(pass->refcount == 0); + if (pass->shader) { + GPU_shader_free(pass->shader); + } + MEM_SAFE_FREE(pass->fragmentcode); + MEM_SAFE_FREE(pass->geometrycode); + MEM_SAFE_FREE(pass->vertexcode); + MEM_SAFE_FREE(pass->defines); + MEM_freeN(pass); } void GPU_pass_free_nodes(ListBase *nodes) { - gpu_nodes_free(nodes); + gpu_nodes_free(nodes); } void GPU_pass_cache_garbage_collect(void) { - static int lasttime = 0; - const int shadercollectrate = 60; /* hardcoded for now. */ - int ctime = (int)PIL_check_seconds_timer(); - - if (ctime < shadercollectrate + lasttime) - return; - - lasttime = ctime; - - BLI_spin_lock(&pass_cache_spin); - GPUPass *next, **prev_pass = &pass_cache; - for (GPUPass *pass = pass_cache; pass; pass = next) { - next = pass->next; - if (pass->refcount == 0) { - /* Remove from list */ - *prev_pass = next; - gpu_pass_free(pass); - } - else { - prev_pass = &pass->next; - } - } - BLI_spin_unlock(&pass_cache_spin); + static int lasttime = 0; + const int shadercollectrate = 60; /* hardcoded for now. */ + int ctime = (int)PIL_check_seconds_timer(); + + if (ctime < shadercollectrate + lasttime) + return; + + lasttime = ctime; + + BLI_spin_lock(&pass_cache_spin); + GPUPass *next, **prev_pass = &pass_cache; + for (GPUPass *pass = pass_cache; pass; pass = next) { + next = pass->next; + if (pass->refcount == 0) { + /* Remove from list */ + *prev_pass = next; + gpu_pass_free(pass); + } + else { + prev_pass = &pass->next; + } + } + BLI_spin_unlock(&pass_cache_spin); } void GPU_pass_cache_init(void) { - BLI_spin_init(&pass_cache_spin); + BLI_spin_init(&pass_cache_spin); } void GPU_pass_cache_free(void) { - BLI_spin_lock(&pass_cache_spin); - while (pass_cache) { - GPUPass *next = pass_cache->next; - gpu_pass_free(pass_cache); - pass_cache = next; - } - BLI_spin_unlock(&pass_cache_spin); - - BLI_spin_end(&pass_cache_spin); + BLI_spin_lock(&pass_cache_spin); + while (pass_cache) { + GPUPass *next = pass_cache->next; + gpu_pass_free(pass_cache); + pass_cache = next; + } + BLI_spin_unlock(&pass_cache_spin); + + BLI_spin_end(&pass_cache_spin); } |