Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/gpu/intern/gpu_codegen.c')
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c3362
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);
}