Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2005 Blender Foundation. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Brecht Van Lommel. 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00033 #include "GL/glew.h" 00034 00035 #include "MEM_guardedalloc.h" 00036 00037 #include "DNA_customdata_types.h" 00038 #include "DNA_image_types.h" 00039 #include "DNA_material_types.h" 00040 00041 #include "BLI_blenlib.h" 00042 #include "BLI_utildefines.h" 00043 #include "BLI_dynstr.h" 00044 #include "BLI_ghash.h" 00045 #include "BLI_heap.h" 00046 00047 #include "GPU_material.h" 00048 #include "GPU_extensions.h" 00049 00050 #include "BLO_sys_types.h" // for intptr_t support 00051 00052 #include "gpu_codegen.h" 00053 00054 #include "node_util.h" /* For muting node stuff... */ 00055 00056 #include <string.h> 00057 #include <stdarg.h> 00058 00059 extern char datatoc_gpu_shader_material_glsl[]; 00060 extern char datatoc_gpu_shader_vertex_glsl[]; 00061 00062 00063 static char *glsl_material_library = NULL; 00064 00065 00066 /* structs and defines */ 00067 00068 static const char* GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4", 00069 NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4"}; 00070 00071 /* GLSL code parsing for finding function definitions. 00072 * These are stored in a hash for lookup when creating a material. */ 00073 00074 static GHash *FUNCTION_HASH= NULL; 00075 /*static char *FUNCTION_PROTOTYPES= NULL; 00076 static GPUShader *FUNCTION_LIB= NULL;*/ 00077 00078 static int gpu_str_prefix(const char *str, const char *prefix) 00079 { 00080 while(*str && *prefix) { 00081 if(*str != *prefix) 00082 return 0; 00083 00084 str++; 00085 prefix++; 00086 } 00087 00088 return (*prefix == '\0'); 00089 } 00090 00091 static char *gpu_str_skip_token(char *str, char *token, int max) 00092 { 00093 int len = 0; 00094 00095 /* skip a variable/function name */ 00096 while(*str) { 00097 if(ELEM7(*str, ' ', '(', ')', ',', '\t', '\n', '\r')) 00098 break; 00099 else { 00100 if(token && len < max-1) { 00101 *token= *str; 00102 token++; 00103 len++; 00104 } 00105 str++; 00106 } 00107 } 00108 00109 if(token) 00110 *token= '\0'; 00111 00112 /* skip the next special characters: 00113 * note the missing ')' */ 00114 while(*str) { 00115 if(ELEM6(*str, ' ', '(', ',', '\t', '\n', '\r')) 00116 str++; 00117 else 00118 break; 00119 } 00120 00121 return str; 00122 } 00123 00124 static void gpu_parse_functions_string(GHash *hash, char *code) 00125 { 00126 GPUFunction *function; 00127 int i, type, qual; 00128 00129 while((code = strstr(code, "void "))) { 00130 function = MEM_callocN(sizeof(GPUFunction), "GPUFunction"); 00131 00132 code = gpu_str_skip_token(code, NULL, 0); 00133 code = gpu_str_skip_token(code, function->name, MAX_FUNCTION_NAME); 00134 00135 /* get parameters */ 00136 while(*code && *code != ')') { 00137 /* test if it's an input or output */ 00138 qual = FUNCTION_QUAL_IN; 00139 if(gpu_str_prefix(code, "out ")) 00140 qual = FUNCTION_QUAL_OUT; 00141 if(gpu_str_prefix(code, "inout ")) 00142 qual = FUNCTION_QUAL_INOUT; 00143 if((qual != FUNCTION_QUAL_IN) || gpu_str_prefix(code, "in ")) 00144 code = gpu_str_skip_token(code, NULL, 0); 00145 00146 /* test for type */ 00147 type= 0; 00148 for(i=1; i<=16; i++) { 00149 if(GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) { 00150 type= i; 00151 break; 00152 } 00153 } 00154 00155 if(!type && gpu_str_prefix(code, "sampler2DShadow")) 00156 type= GPU_SHADOW2D; 00157 if(!type && gpu_str_prefix(code, "sampler2D")) 00158 type= GPU_TEX2D; 00159 00160 if(type) { 00161 /* add paramater */ 00162 code = gpu_str_skip_token(code, NULL, 0); 00163 code = gpu_str_skip_token(code, NULL, 0); 00164 function->paramqual[function->totparam]= qual; 00165 function->paramtype[function->totparam]= type; 00166 function->totparam++; 00167 } 00168 else { 00169 fprintf(stderr, "GPU invalid function parameter in %s.\n", function->name); 00170 break; 00171 } 00172 } 00173 00174 if(function->name[0] == '\0' || function->totparam == 0) { 00175 fprintf(stderr, "GPU functions parse error.\n"); 00176 MEM_freeN(function); 00177 break; 00178 } 00179 00180 BLI_ghash_insert(hash, function->name, function); 00181 } 00182 } 00183 00184 #if 0 00185 static char *gpu_generate_function_prototyps(GHash *hash) 00186 { 00187 DynStr *ds = BLI_dynstr_new(); 00188 GHashIterator *ghi; 00189 GPUFunction *function; 00190 char *name, *prototypes; 00191 int a; 00192 00193 /* automatically generate function prototypes to add to the top of the 00194 * generated code, to avoid have to add the actual code & recompile all */ 00195 ghi = BLI_ghashIterator_new(hash); 00196 00197 for(; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) { 00198 name = BLI_ghashIterator_getValue(ghi); 00199 function = BLI_ghashIterator_getValue(ghi); 00200 00201 BLI_dynstr_appendf(ds, "void %s(", name); 00202 for(a=0; a<function->totparam; a++) { 00203 if(function->paramqual[a] == FUNCTION_QUAL_OUT) 00204 BLI_dynstr_append(ds, "out "); 00205 else if(function->paramqual[a] == FUNCTION_QUAL_INOUT) 00206 BLI_dynstr_append(ds, "inout "); 00207 00208 if(function->paramtype[a] == GPU_TEX2D) 00209 BLI_dynstr_append(ds, "sampler2D"); 00210 else if(function->paramtype[a] == GPU_SHADOW2D) 00211 BLI_dynstr_append(ds, "sampler2DShadow"); 00212 else 00213 BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]); 00214 00215 //BLI_dynstr_appendf(ds, " param%d", a); 00216 00217 if(a != function->totparam-1) 00218 BLI_dynstr_append(ds, ", "); 00219 } 00220 BLI_dynstr_append(ds, ");\n"); 00221 } 00222 00223 BLI_dynstr_append(ds, "\n"); 00224 00225 prototypes = BLI_dynstr_get_cstring(ds); 00226 BLI_dynstr_free(ds); 00227 00228 return prototypes; 00229 } 00230 #endif 00231 00232 GPUFunction *GPU_lookup_function(const char *name) 00233 { 00234 if(!FUNCTION_HASH) { 00235 FUNCTION_HASH = BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp, "GPU_lookup_function gh"); 00236 gpu_parse_functions_string(FUNCTION_HASH, glsl_material_library); 00237 /*FUNCTION_PROTOTYPES = gpu_generate_function_prototyps(FUNCTION_HASH); 00238 FUNCTION_LIB = GPU_shader_create_lib(datatoc_gpu_shader_material_glsl);*/ 00239 } 00240 00241 return (GPUFunction*)BLI_ghash_lookup(FUNCTION_HASH, (void *)name); 00242 } 00243 00244 void GPU_codegen_init(void) 00245 { 00246 GPU_code_generate_glsl_lib(); 00247 } 00248 00249 void GPU_codegen_exit(void) 00250 { 00251 extern Material defmaterial; // render module abuse... 00252 00253 if(defmaterial.gpumaterial.first) 00254 GPU_material_free(&defmaterial); 00255 00256 if(FUNCTION_HASH) { 00257 BLI_ghash_free(FUNCTION_HASH, NULL, (GHashValFreeFP)MEM_freeN); 00258 FUNCTION_HASH = NULL; 00259 } 00260 00261 if(glsl_material_library) { 00262 MEM_freeN(glsl_material_library); 00263 glsl_material_library = NULL; 00264 } 00265 00266 /*if(FUNCTION_PROTOTYPES) { 00267 MEM_freeN(FUNCTION_PROTOTYPES); 00268 FUNCTION_PROTOTYPES = NULL; 00269 }*/ 00270 /*if(FUNCTION_LIB) { 00271 GPU_shader_free(FUNCTION_LIB); 00272 FUNCTION_LIB = NULL; 00273 }*/ 00274 } 00275 00276 /* GLSL code generation */ 00277 00278 static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *tmp, int id) 00279 { 00280 char name[1024]; 00281 00282 BLI_snprintf(name, sizeof(name), "%s%d", tmp, id); 00283 00284 if (from == to) { 00285 BLI_dynstr_append(ds, name); 00286 } 00287 else if (to == GPU_FLOAT) { 00288 if (from == GPU_VEC4) 00289 BLI_dynstr_appendf(ds, "dot(%s.rgb, vec3(0.35, 0.45, 0.2))", name); 00290 else if (from == GPU_VEC3) 00291 BLI_dynstr_appendf(ds, "dot(%s, vec3(0.33))", name); 00292 else if (from == GPU_VEC2) 00293 BLI_dynstr_appendf(ds, "%s.r", name); 00294 } 00295 else if (to == GPU_VEC2) { 00296 if (from == GPU_VEC4) 00297 BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.35, 0.45, 0.2)), %s.a)", name, name); 00298 else if (from == GPU_VEC3) 00299 BLI_dynstr_appendf(ds, "vec2(dot(%s.rgb, vec3(0.33)), 1.0)", name); 00300 else if (from == GPU_FLOAT) 00301 BLI_dynstr_appendf(ds, "vec2(%s, 1.0)", name); 00302 } 00303 else if (to == GPU_VEC3) { 00304 if (from == GPU_VEC4) 00305 BLI_dynstr_appendf(ds, "%s.rgb", name); 00306 else if (from == GPU_VEC2) 00307 BLI_dynstr_appendf(ds, "vec3(%s.r, %s.r, %s.r)", name, name, name); 00308 else if (from == GPU_FLOAT) 00309 BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name); 00310 } 00311 else { 00312 if (from == GPU_VEC3) 00313 BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name); 00314 else if (from == GPU_VEC2) 00315 BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name); 00316 else if (from == GPU_FLOAT) 00317 BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name); 00318 } 00319 } 00320 00321 static void codegen_print_datatype(DynStr *ds, int type, float *data) 00322 { 00323 int i; 00324 00325 BLI_dynstr_appendf(ds, "%s(", GPU_DATATYPE_STR[type]); 00326 00327 for(i=0; i<type; i++) { 00328 BLI_dynstr_appendf(ds, "%f", data[i]); 00329 if(i == type-1) 00330 BLI_dynstr_append(ds, ")"); 00331 else 00332 BLI_dynstr_append(ds, ", "); 00333 } 00334 } 00335 00336 static int codegen_input_has_texture(GPUInput *input) 00337 { 00338 if (input->link) 00339 return 0; 00340 else if(input->ima) 00341 return 1; 00342 else 00343 return input->tex != NULL; 00344 } 00345 00346 const char *GPU_builtin_name(GPUBuiltin builtin) 00347 { 00348 if(builtin == GPU_VIEW_MATRIX) 00349 return "unfviewmat"; 00350 else if(builtin == GPU_OBJECT_MATRIX) 00351 return "unfobmat"; 00352 else if(builtin == GPU_INVERSE_VIEW_MATRIX) 00353 return "unfinvviewmat"; 00354 else if(builtin == GPU_INVERSE_OBJECT_MATRIX) 00355 return "unfinvobmat"; 00356 else if(builtin == GPU_VIEW_POSITION) 00357 return "varposition"; 00358 else if(builtin == GPU_VIEW_NORMAL) 00359 return "varnormal"; 00360 else if(builtin == GPU_OBCOLOR) 00361 return "unfobcolor"; 00362 else if(builtin == GPU_AUTO_BUMPSCALE) 00363 return "unfobautobumpscale"; 00364 else 00365 return ""; 00366 } 00367 00368 static void codegen_set_unique_ids(ListBase *nodes) 00369 { 00370 GHash *bindhash, *definehash; 00371 GPUNode *node; 00372 GPUInput *input; 00373 GPUOutput *output; 00374 int id = 1, texid = 0; 00375 00376 bindhash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "codegen_set_unique_ids1 gh"); 00377 definehash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "codegen_set_unique_ids2 gh"); 00378 00379 for (node=nodes->first; node; node=node->next) { 00380 for (input=node->inputs.first; input; input=input->next) { 00381 /* set id for unique names of uniform variables */ 00382 input->id = id++; 00383 input->bindtex = 0; 00384 input->definetex = 0; 00385 00386 /* set texid used for settings texture slot with multitexture */ 00387 if (codegen_input_has_texture(input) && 00388 ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL))) { 00389 if (input->link) { 00390 /* input is texture from buffer, assign only one texid per 00391 buffer to avoid sampling the same texture twice */ 00392 if (!BLI_ghash_haskey(bindhash, input->link)) { 00393 input->texid = texid++; 00394 input->bindtex = 1; 00395 BLI_ghash_insert(bindhash, input->link, SET_INT_IN_POINTER(input->texid)); 00396 } 00397 else 00398 input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->link)); 00399 } 00400 else if(input->ima) { 00401 /* input is texture from image, assign only one texid per 00402 buffer to avoid sampling the same texture twice */ 00403 if (!BLI_ghash_haskey(bindhash, input->ima)) { 00404 input->texid = texid++; 00405 input->bindtex = 1; 00406 BLI_ghash_insert(bindhash, input->ima, SET_INT_IN_POINTER(input->texid)); 00407 } 00408 else 00409 input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->ima)); 00410 } 00411 else { 00412 if (!BLI_ghash_haskey(bindhash, input->tex)) { 00413 /* input is user created texture, check tex pointer */ 00414 input->texid = texid++; 00415 input->bindtex = 1; 00416 BLI_ghash_insert(bindhash, input->tex, SET_INT_IN_POINTER(input->texid)); 00417 } 00418 else 00419 input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->tex)); 00420 } 00421 00422 /* make sure this pixel is defined exactly once */ 00423 if (input->source == GPU_SOURCE_TEX_PIXEL) { 00424 if(input->ima) { 00425 if (!BLI_ghash_haskey(definehash, input->ima)) { 00426 input->definetex = 1; 00427 BLI_ghash_insert(definehash, input->ima, SET_INT_IN_POINTER(input->texid)); 00428 } 00429 } 00430 else { 00431 if (!BLI_ghash_haskey(definehash, input->link)) { 00432 input->definetex = 1; 00433 BLI_ghash_insert(definehash, input->link, SET_INT_IN_POINTER(input->texid)); 00434 } 00435 } 00436 } 00437 } 00438 } 00439 00440 for (output=node->outputs.first; output; output=output->next) 00441 /* set id for unique names of tmp variables storing output */ 00442 output->id = id++; 00443 } 00444 00445 BLI_ghash_free(bindhash, NULL, NULL); 00446 BLI_ghash_free(definehash, NULL, NULL); 00447 } 00448 00449 static void codegen_print_uniforms_functions(DynStr *ds, ListBase *nodes) 00450 { 00451 GPUNode *node; 00452 GPUInput *input; 00453 const char *name; 00454 int builtins = 0; 00455 00456 /* print uniforms */ 00457 for (node=nodes->first; node; node=node->next) { 00458 for (input=node->inputs.first; input; input=input->next) { 00459 if ((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)) { 00460 /* create exactly one sampler for each texture */ 00461 if (codegen_input_has_texture(input) && input->bindtex) 00462 BLI_dynstr_appendf(ds, "uniform %s samp%d;\n", 00463 (input->textype == GPU_TEX2D)? "sampler2D": "sampler2DShadow", 00464 input->texid); 00465 } 00466 else if(input->source == GPU_SOURCE_BUILTIN) { 00467 /* only define each builting uniform/varying once */ 00468 if(!(builtins & input->builtin)) { 00469 builtins |= input->builtin; 00470 name = GPU_builtin_name(input->builtin); 00471 00472 if(gpu_str_prefix(name, "unf")) { 00473 BLI_dynstr_appendf(ds, "uniform %s %s;\n", 00474 GPU_DATATYPE_STR[input->type], name); 00475 } 00476 else { 00477 BLI_dynstr_appendf(ds, "varying %s %s;\n", 00478 GPU_DATATYPE_STR[input->type], name); 00479 } 00480 } 00481 } 00482 else if (input->source == GPU_SOURCE_VEC_UNIFORM) { 00483 if(input->dynamicvec) { 00484 /* only create uniforms for dynamic vectors */ 00485 BLI_dynstr_appendf(ds, "uniform %s unf%d;\n", 00486 GPU_DATATYPE_STR[input->type], input->id); 00487 } 00488 else { 00489 /* for others use const so the compiler can do folding */ 00490 BLI_dynstr_appendf(ds, "const %s cons%d = ", 00491 GPU_DATATYPE_STR[input->type], input->id); 00492 codegen_print_datatype(ds, input->type, input->vec); 00493 BLI_dynstr_append(ds, ";\n"); 00494 } 00495 } 00496 else if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { 00497 BLI_dynstr_appendf(ds, "varying %s var%d;\n", 00498 GPU_DATATYPE_STR[input->type], input->attribid); 00499 } 00500 } 00501 } 00502 00503 BLI_dynstr_append(ds, "\n"); 00504 } 00505 00506 static void codegen_declare_tmps(DynStr *ds, ListBase *nodes) 00507 { 00508 GPUNode *node; 00509 GPUInput *input; 00510 GPUOutput *output; 00511 00512 for (node=nodes->first; node; node=node->next) { 00513 /* load pixels from textures */ 00514 for (input=node->inputs.first; input; input=input->next) { 00515 if (input->source == GPU_SOURCE_TEX_PIXEL) { 00516 if (codegen_input_has_texture(input) && input->definetex) { 00517 BLI_dynstr_appendf(ds, "\tvec4 tex%d = texture2D(", input->texid); 00518 BLI_dynstr_appendf(ds, "samp%d, gl_TexCoord[%d].st);\n", 00519 input->texid, input->texid); 00520 } 00521 } 00522 } 00523 00524 /* declare temporary variables for node output storage */ 00525 for (output=node->outputs.first; output; output=output->next) 00526 BLI_dynstr_appendf(ds, "\t%s tmp%d;\n", 00527 GPU_DATATYPE_STR[output->type], output->id); 00528 } 00529 00530 BLI_dynstr_append(ds, "\n"); 00531 } 00532 00533 static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *finaloutput) 00534 { 00535 GPUNode *node; 00536 GPUInput *input; 00537 GPUOutput *output; 00538 00539 for (node=nodes->first; node; node=node->next) { 00540 BLI_dynstr_appendf(ds, "\t%s(", node->name); 00541 00542 for (input=node->inputs.first; input; input=input->next) { 00543 if (input->source == GPU_SOURCE_TEX) { 00544 BLI_dynstr_appendf(ds, "samp%d", input->texid); 00545 if (input->link) 00546 BLI_dynstr_appendf(ds, ", gl_TexCoord[%d].st", input->texid); 00547 } 00548 else if (input->source == GPU_SOURCE_TEX_PIXEL) { 00549 codegen_convert_datatype(ds, input->link->output->type, input->type, 00550 "tmp", input->link->output->id); 00551 } 00552 else if(input->source == GPU_SOURCE_BUILTIN) 00553 BLI_dynstr_appendf(ds, "%s", GPU_builtin_name(input->builtin)); 00554 else if(input->source == GPU_SOURCE_VEC_UNIFORM) { 00555 if(input->dynamicvec) 00556 BLI_dynstr_appendf(ds, "unf%d", input->id); 00557 else 00558 BLI_dynstr_appendf(ds, "cons%d", input->id); 00559 } 00560 else if (input->source == GPU_SOURCE_ATTRIB) 00561 BLI_dynstr_appendf(ds, "var%d", input->attribid); 00562 00563 BLI_dynstr_append(ds, ", "); 00564 } 00565 00566 for (output=node->outputs.first; output; output=output->next) { 00567 BLI_dynstr_appendf(ds, "tmp%d", output->id); 00568 if (output->next) 00569 BLI_dynstr_append(ds, ", "); 00570 } 00571 00572 BLI_dynstr_append(ds, ");\n"); 00573 } 00574 00575 BLI_dynstr_append(ds, "\n\tgl_FragColor = "); 00576 codegen_convert_datatype(ds, finaloutput->type, GPU_VEC4, "tmp", finaloutput->id); 00577 BLI_dynstr_append(ds, ";\n"); 00578 } 00579 00580 static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, const char *UNUSED(name)) 00581 { 00582 DynStr *ds = BLI_dynstr_new(); 00583 char *code; 00584 00585 /*BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);*/ 00586 00587 codegen_set_unique_ids(nodes); 00588 codegen_print_uniforms_functions(ds, nodes); 00589 00590 //if(G.f & G_DEBUG) 00591 // BLI_dynstr_appendf(ds, "/* %s */\n", name); 00592 00593 BLI_dynstr_append(ds, "void main(void)\n"); 00594 BLI_dynstr_append(ds, "{\n"); 00595 00596 codegen_declare_tmps(ds, nodes); 00597 codegen_call_functions(ds, nodes, output); 00598 00599 BLI_dynstr_append(ds, "}\n"); 00600 00601 /* create shader */ 00602 code = BLI_dynstr_get_cstring(ds); 00603 BLI_dynstr_free(ds); 00604 00605 //if(G.f & G_DEBUG) printf("%s\n", code); 00606 00607 return code; 00608 } 00609 00610 static char *code_generate_vertex(ListBase *nodes) 00611 { 00612 DynStr *ds = BLI_dynstr_new(); 00613 GPUNode *node; 00614 GPUInput *input; 00615 char *code; 00616 00617 for (node=nodes->first; node; node=node->next) { 00618 for (input=node->inputs.first; input; input=input->next) { 00619 if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { 00620 BLI_dynstr_appendf(ds, "attribute %s att%d;\n", 00621 GPU_DATATYPE_STR[input->type], input->attribid); 00622 BLI_dynstr_appendf(ds, "varying %s var%d;\n", 00623 GPU_DATATYPE_STR[input->type], input->attribid); 00624 } 00625 } 00626 } 00627 00628 BLI_dynstr_append(ds, "\n"); 00629 BLI_dynstr_append(ds, datatoc_gpu_shader_vertex_glsl); 00630 00631 for (node=nodes->first; node; node=node->next) 00632 for (input=node->inputs.first; input; input=input->next) 00633 if (input->source == GPU_SOURCE_ATTRIB && input->attribfirst) { 00634 if(input->attribtype == CD_TANGENT) /* silly exception */ 00635 { 00636 BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize((gl_ModelViewMatrix * vec4(att%d.xyz, 0)).xyz);\n", input->attribid, input->attribid); 00637 BLI_dynstr_appendf(ds, "\tvar%d.w = att%d.w;\n", input->attribid, input->attribid); 00638 } 00639 else 00640 BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid); 00641 } 00642 00643 BLI_dynstr_append(ds, "}\n\n"); 00644 00645 code = BLI_dynstr_get_cstring(ds); 00646 00647 BLI_dynstr_free(ds); 00648 00649 //if(G.f & G_DEBUG) printf("%s\n", code); 00650 00651 return code; 00652 } 00653 00654 int GPU_bicubic_bump_support(void) 00655 { 00656 return GLEW_ARB_texture_gather && GLEW_ARB_texture_query_lod && GLEW_VERSION_3_0; 00657 } 00658 00659 void GPU_code_generate_glsl_lib(void) 00660 { 00661 DynStr *ds; 00662 00663 /* only initialize the library once */ 00664 if(glsl_material_library) 00665 return; 00666 00667 ds = BLI_dynstr_new(); 00668 00669 if(GPU_bicubic_bump_support()){ 00670 BLI_dynstr_append(ds, "/* These are needed for high quality bump mapping */\n" 00671 "#version 130\n" 00672 "#extension GL_ARB_texture_gather: enable\n" 00673 "#extension GL_ARB_texture_query_lod: enable\n" 00674 "#define BUMP_BICUBIC\n"); 00675 } 00676 BLI_dynstr_append(ds, datatoc_gpu_shader_material_glsl); 00677 00678 00679 glsl_material_library = BLI_dynstr_get_cstring(ds); 00680 00681 BLI_dynstr_free(ds); 00682 } 00683 00684 00685 /* GPU pass binding/unbinding */ 00686 00687 GPUShader *GPU_pass_shader(GPUPass *pass) 00688 { 00689 return pass->shader; 00690 } 00691 00692 static void GPU_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes) 00693 { 00694 GPUShader *shader = pass->shader; 00695 GPUNode *node; 00696 GPUInput *next, *input; 00697 ListBase *inputs = &pass->inputs; 00698 int extract, z; 00699 00700 memset(inputs, 0, sizeof(*inputs)); 00701 00702 if(!shader) 00703 return; 00704 00705 GPU_shader_bind(shader); 00706 00707 for (node=nodes->first; node; node=node->next) { 00708 z = 0; 00709 for (input=node->inputs.first; input; input=next, z++) { 00710 next = input->next; 00711 00712 /* attributes don't need to be bound, they already have 00713 * an id that the drawing functions will use */ 00714 if(input->source == GPU_SOURCE_ATTRIB || 00715 input->source == GPU_SOURCE_BUILTIN) 00716 continue; 00717 00718 if (input->ima || input->tex) 00719 BLI_snprintf(input->shadername, sizeof(input->shadername), "samp%d", input->texid); 00720 else 00721 BLI_snprintf(input->shadername, sizeof(input->shadername), "unf%d", input->id); 00722 00723 /* pass non-dynamic uniforms to opengl */ 00724 extract = 0; 00725 00726 if(input->ima || input->tex) { 00727 if (input->bindtex) 00728 extract = 1; 00729 } 00730 else if(input->dynamicvec) 00731 extract = 1; 00732 00733 if(extract) 00734 input->shaderloc = GPU_shader_get_uniform(shader, input->shadername); 00735 00736 /* extract nodes */ 00737 if(extract) { 00738 BLI_remlink(&node->inputs, input); 00739 BLI_addtail(inputs, input); 00740 } 00741 } 00742 } 00743 00744 GPU_shader_unbind(shader); 00745 } 00746 00747 void GPU_pass_bind(GPUPass *pass, double time, int mipmap) 00748 { 00749 GPUInput *input; 00750 GPUShader *shader = pass->shader; 00751 ListBase *inputs = &pass->inputs; 00752 00753 if (!shader) 00754 return; 00755 00756 GPU_shader_bind(shader); 00757 00758 /* now bind the textures */ 00759 for (input=inputs->first; input; input=input->next) { 00760 if (input->ima) 00761 input->tex = GPU_texture_from_blender(input->ima, input->iuser, time, mipmap); 00762 00763 if(input->tex && input->bindtex) { 00764 GPU_texture_bind(input->tex, input->texid); 00765 GPU_shader_uniform_texture(shader, input->shaderloc, input->tex); 00766 } 00767 } 00768 } 00769 00770 void GPU_pass_update_uniforms(GPUPass *pass) 00771 { 00772 GPUInput *input; 00773 GPUShader *shader = pass->shader; 00774 ListBase *inputs = &pass->inputs; 00775 00776 if (!shader) 00777 return; 00778 00779 /* pass dynamic inputs to opengl, others were removed */ 00780 for (input=inputs->first; input; input=input->next) 00781 if(!(input->ima || input->tex)) 00782 GPU_shader_uniform_vector(shader, input->shaderloc, input->type, 1, 00783 input->dynamicvec); 00784 } 00785 00786 void GPU_pass_unbind(GPUPass *pass) 00787 { 00788 GPUInput *input; 00789 GPUShader *shader = pass->shader; 00790 ListBase *inputs = &pass->inputs; 00791 00792 if (!shader) 00793 return; 00794 00795 for (input=inputs->first; input; input=input->next) { 00796 if(input->tex && input->bindtex) 00797 GPU_texture_unbind(input->tex); 00798 00799 if (input->ima) 00800 input->tex = NULL; 00801 } 00802 00803 GPU_shader_unbind(shader); 00804 } 00805 00806 /* Node Link Functions */ 00807 00808 static GPUNodeLink *GPU_node_link_create(int type) 00809 { 00810 GPUNodeLink *link = MEM_callocN(sizeof(GPUNodeLink), "GPUNodeLink"); 00811 link->type = type; 00812 link->users++; 00813 00814 return link; 00815 } 00816 00817 static void GPU_node_link_free(GPUNodeLink *link) 00818 { 00819 link->users--; 00820 00821 if (link->users < 0) 00822 fprintf(stderr, "GPU_node_link_free: negative refcount\n"); 00823 00824 if (link->users == 0) { 00825 if (link->output) 00826 link->output->link = NULL; 00827 MEM_freeN(link); 00828 } 00829 } 00830 00831 /* Node Functions */ 00832 00833 static GPUNode *GPU_node_begin(const char *name) 00834 { 00835 GPUNode *node = MEM_callocN(sizeof(GPUNode), "GPUNode"); 00836 00837 node->name= name; 00838 00839 return node; 00840 } 00841 00842 static void GPU_node_end(GPUNode *UNUSED(node)) 00843 { 00844 /* empty */ 00845 } 00846 00847 static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type) 00848 { 00849 GPUInput *input; 00850 GPUNode *outnode; 00851 const char *name; 00852 00853 if(link->output) { 00854 outnode = link->output->node; 00855 name = outnode->name; 00856 00857 if(strcmp(name, "set_value")==0 || strcmp(name, "set_rgb")==0) { 00858 input = MEM_dupallocN(outnode->inputs.first); 00859 input->type = type; 00860 if(input->link) 00861 input->link->users++; 00862 BLI_addtail(&node->inputs, input); 00863 return; 00864 } 00865 } 00866 00867 input = MEM_callocN(sizeof(GPUInput), "GPUInput"); 00868 input->node = node; 00869 00870 if(link->builtin) { 00871 /* builtin uniform */ 00872 input->type = type; 00873 input->source = GPU_SOURCE_BUILTIN; 00874 input->builtin = link->builtin; 00875 00876 MEM_freeN(link); 00877 } 00878 else if(link->output) { 00879 /* link to a node output */ 00880 input->type = type; 00881 input->source = GPU_SOURCE_TEX_PIXEL; 00882 input->link = link; 00883 link->users++; 00884 } 00885 else if(link->dynamictex) { 00886 /* dynamic texture, GPUTexture is updated/deleted externally */ 00887 input->type = type; 00888 input->source = GPU_SOURCE_TEX; 00889 00890 input->tex = link->dynamictex; 00891 input->textarget = GL_TEXTURE_2D; 00892 input->textype = type; 00893 input->dynamictex = 1; 00894 input->dynamicdata = link->ptr2; 00895 MEM_freeN(link); 00896 } 00897 else if(link->texture) { 00898 /* small texture created on the fly, like for colorbands */ 00899 input->type = GPU_VEC4; 00900 input->source = GPU_SOURCE_TEX; 00901 input->textype = type; 00902 00903 //input->tex = GPU_texture_create_2D(link->texturesize, link->texturesize, link->ptr2, NULL); 00904 input->tex = GPU_texture_create_2D(link->texturesize, 1, link->ptr1, NULL); 00905 input->textarget = GL_TEXTURE_2D; 00906 00907 MEM_freeN(link->ptr1); 00908 MEM_freeN(link); 00909 } 00910 else if(link->image) { 00911 /* blender image */ 00912 input->type = GPU_VEC4; 00913 input->source = GPU_SOURCE_TEX; 00914 00915 input->ima = link->ptr1; 00916 input->iuser = link->ptr2; 00917 input->textarget = GL_TEXTURE_2D; 00918 input->textype = GPU_TEX2D; 00919 MEM_freeN(link); 00920 } 00921 else if(link->attribtype) { 00922 /* vertex attribute */ 00923 input->type = type; 00924 input->source = GPU_SOURCE_ATTRIB; 00925 00926 input->attribtype = link->attribtype; 00927 BLI_strncpy(input->attribname, link->attribname, sizeof(input->attribname)); 00928 MEM_freeN(link); 00929 } 00930 else { 00931 /* uniform vector */ 00932 input->type = type; 00933 input->source = GPU_SOURCE_VEC_UNIFORM; 00934 00935 memcpy(input->vec, link->ptr1, type*sizeof(float)); 00936 if(link->dynamic) { 00937 input->dynamicvec= link->ptr1; 00938 input->dynamictype= link->dynamictype; 00939 input->dynamicdata= link->ptr2; 00940 } 00941 MEM_freeN(link); 00942 } 00943 00944 BLI_addtail(&node->inputs, input); 00945 } 00946 00947 static void gpu_node_input_socket(GPUNode *node, GPUNodeStack *sock) 00948 { 00949 GPUNodeLink *link; 00950 00951 if(sock->link) { 00952 gpu_node_input_link(node, sock->link, sock->type); 00953 } 00954 else { 00955 link = GPU_node_link_create(0); 00956 link->ptr1 = sock->vec; 00957 gpu_node_input_link(node, link, sock->type); 00958 } 00959 } 00960 00961 static void GPU_node_output(GPUNode *node, int type, const char *UNUSED(name), GPUNodeLink **link) 00962 { 00963 GPUOutput *output = MEM_callocN(sizeof(GPUOutput), "GPUOutput"); 00964 00965 output->type = type; 00966 output->node = node; 00967 00968 if (link) { 00969 *link = output->link = GPU_node_link_create(type); 00970 output->link->output = output; 00971 00972 /* note: the caller owns the reference to the linkfer, GPUOutput 00973 merely points to it, and if the node is destroyed it will 00974 set that pointer to NULL */ 00975 } 00976 00977 BLI_addtail(&node->outputs, output); 00978 } 00979 00980 static void GPU_inputs_free(ListBase *inputs) 00981 { 00982 GPUInput *input; 00983 00984 for(input=inputs->first; input; input=input->next) { 00985 if(input->link) 00986 GPU_node_link_free(input->link); 00987 else if(input->tex && !input->dynamictex) 00988 GPU_texture_free(input->tex); 00989 } 00990 00991 BLI_freelistN(inputs); 00992 } 00993 00994 static void GPU_node_free(GPUNode *node) 00995 { 00996 GPUOutput *output; 00997 00998 GPU_inputs_free(&node->inputs); 00999 01000 for (output=node->outputs.first; output; output=output->next) 01001 if (output->link) { 01002 output->link->output = NULL; 01003 GPU_node_link_free(output->link); 01004 } 01005 01006 BLI_freelistN(&node->outputs); 01007 MEM_freeN(node); 01008 } 01009 01010 static void GPU_nodes_free(ListBase *nodes) 01011 { 01012 GPUNode *node; 01013 01014 while (nodes->first) { 01015 node = nodes->first; 01016 BLI_remlink(nodes, node); 01017 GPU_node_free(node); 01018 } 01019 } 01020 01021 /* vertex attributes */ 01022 01023 static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *attribs) 01024 { 01025 GPUNode *node; 01026 GPUInput *input; 01027 int a; 01028 01029 /* convert attributes requested by node inputs to an array of layers, 01030 * checking for duplicates and assigning id's starting from zero. */ 01031 01032 memset(attribs, 0, sizeof(*attribs)); 01033 01034 for(node=nodes->first; node; node=node->next) { 01035 for(input=node->inputs.first; input; input=input->next) { 01036 if(input->source == GPU_SOURCE_ATTRIB) { 01037 for(a=0; a<attribs->totlayer; a++) { 01038 if(attribs->layer[a].type == input->attribtype && 01039 strcmp(attribs->layer[a].name, input->attribname) == 0) 01040 break; 01041 } 01042 01043 if(a == attribs->totlayer && a < GPU_MAX_ATTRIB) { 01044 input->attribid = attribs->totlayer++; 01045 input->attribfirst = 1; 01046 01047 attribs->layer[a].type = input->attribtype; 01048 attribs->layer[a].attribid = input->attribid; 01049 BLI_strncpy(attribs->layer[a].name, input->attribname, 01050 sizeof(attribs->layer[a].name)); 01051 } 01052 else 01053 input->attribid = attribs->layer[a].attribid; 01054 } 01055 } 01056 } 01057 } 01058 01059 static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin) 01060 { 01061 GPUNode *node; 01062 GPUInput *input; 01063 01064 *builtin= 0; 01065 01066 for(node=nodes->first; node; node=node->next) 01067 for(input=node->inputs.first; input; input=input->next) 01068 if(input->source == GPU_SOURCE_BUILTIN) 01069 *builtin |= input->builtin; 01070 } 01071 01072 /* varargs linking */ 01073 01074 GPUNodeLink *GPU_attribute(int type, const char *name) 01075 { 01076 GPUNodeLink *link = GPU_node_link_create(0); 01077 01078 link->attribtype= type; 01079 link->attribname= name; 01080 01081 return link; 01082 } 01083 01084 GPUNodeLink *GPU_uniform(float *num) 01085 { 01086 GPUNodeLink *link = GPU_node_link_create(0); 01087 01088 link->ptr1= num; 01089 link->ptr2= NULL; 01090 01091 return link; 01092 } 01093 01094 GPUNodeLink *GPU_dynamic_uniform(float *num, int dynamictype, void *data) 01095 { 01096 GPUNodeLink *link = GPU_node_link_create(0); 01097 01098 link->ptr1= num; 01099 link->ptr2= data; 01100 link->dynamic= 1; 01101 link->dynamictype = dynamictype; 01102 01103 01104 return link; 01105 } 01106 01107 GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser) 01108 { 01109 GPUNodeLink *link = GPU_node_link_create(0); 01110 01111 link->image= 1; 01112 link->ptr1= ima; 01113 link->ptr2= iuser; 01114 01115 return link; 01116 } 01117 01118 GPUNodeLink *GPU_texture(int size, float *pixels) 01119 { 01120 GPUNodeLink *link = GPU_node_link_create(0); 01121 01122 link->texture = 1; 01123 link->texturesize = size; 01124 link->ptr1= pixels; 01125 01126 return link; 01127 } 01128 01129 GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, int dynamictype, void *data) 01130 { 01131 GPUNodeLink *link = GPU_node_link_create(0); 01132 01133 link->dynamic = 1; 01134 link->dynamictex = tex; 01135 link->dynamictype = dynamictype; 01136 link->ptr2 = data; 01137 01138 return link; 01139 } 01140 01141 GPUNodeLink *GPU_socket(GPUNodeStack *sock) 01142 { 01143 GPUNodeLink *link = GPU_node_link_create(0); 01144 01145 link->socket= sock; 01146 01147 return link; 01148 } 01149 01150 GPUNodeLink *GPU_builtin(GPUBuiltin builtin) 01151 { 01152 GPUNodeLink *link = GPU_node_link_create(0); 01153 01154 link->builtin= builtin; 01155 01156 return link; 01157 } 01158 01159 int GPU_link(GPUMaterial *mat, const char *name, ...) 01160 { 01161 GPUNode *node; 01162 GPUFunction *function; 01163 GPUNodeLink *link, **linkptr; 01164 va_list params; 01165 int i; 01166 01167 function = GPU_lookup_function(name); 01168 if(!function) { 01169 fprintf(stderr, "GPU failed to find function %s\n", name); 01170 return 0; 01171 } 01172 01173 node = GPU_node_begin(name); 01174 01175 va_start(params, name); 01176 for(i=0; i<function->totparam; i++) { 01177 if(function->paramqual[i] != FUNCTION_QUAL_IN) { 01178 linkptr= va_arg(params, GPUNodeLink**); 01179 GPU_node_output(node, function->paramtype[i], "", linkptr); 01180 } 01181 else { 01182 link= va_arg(params, GPUNodeLink*); 01183 gpu_node_input_link(node, link, function->paramtype[i]); 01184 } 01185 } 01186 va_end(params); 01187 01188 GPU_node_end(node); 01189 01190 gpu_material_add_node(mat, node); 01191 01192 return 1; 01193 } 01194 01195 int GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNodeStack *out, ...) 01196 { 01197 GPUNode *node; 01198 GPUFunction *function; 01199 GPUNodeLink *link, **linkptr; 01200 va_list params; 01201 int i, totin, totout; 01202 01203 function = GPU_lookup_function(name); 01204 if(!function) { 01205 fprintf(stderr, "GPU failed to find function %s\n", name); 01206 return 0; 01207 } 01208 01209 node = GPU_node_begin(name); 01210 totin = 0; 01211 totout = 0; 01212 01213 if(in) { 01214 for(i = 0; in[i].type != GPU_NONE; i++) { 01215 gpu_node_input_socket(node, &in[i]); 01216 totin++; 01217 } 01218 } 01219 01220 if(out) { 01221 for(i = 0; out[i].type != GPU_NONE; i++) { 01222 GPU_node_output(node, out[i].type, out[i].name, &out[i].link); 01223 totout++; 01224 } 01225 } 01226 01227 va_start(params, out); 01228 for(i=0; i<function->totparam; i++) { 01229 if(function->paramqual[i] != FUNCTION_QUAL_IN) { 01230 if(totout == 0) { 01231 linkptr= va_arg(params, GPUNodeLink**); 01232 GPU_node_output(node, function->paramtype[i], "", linkptr); 01233 } 01234 else 01235 totout--; 01236 } 01237 else { 01238 if(totin == 0) { 01239 link= va_arg(params, GPUNodeLink*); 01240 if(link->socket) 01241 gpu_node_input_socket(node, link->socket); 01242 else 01243 gpu_node_input_link(node, link, function->paramtype[i]); 01244 } 01245 else 01246 totin--; 01247 } 01248 } 01249 va_end(params); 01250 01251 GPU_node_end(node); 01252 01253 gpu_material_add_node(mat, node); 01254 01255 return 1; 01256 } 01257 01258 int GPU_stack_link_mute(GPUMaterial *mat, const char *name, LinkInOutsMuteNode *mlnk) 01259 { 01260 GPUNode *node; 01261 GPUFunction *function; 01262 int i; 01263 01264 function = GPU_lookup_function(name); 01265 if(!function) { 01266 fprintf(stderr, "GPU failed to find function %s\n", name); 01267 return 0; 01268 } 01269 01270 for(i = 0; i < mlnk->num_outs; i++) { 01271 node = GPU_node_begin(name); 01272 gpu_node_input_socket(node, (GPUNodeStack*)mlnk->in); 01273 GPU_node_output(node, ((GPUNodeStack*)mlnk->outs+i)->type, ((GPUNodeStack*)mlnk->outs+i)->name, 01274 &((GPUNodeStack*)mlnk->outs+i)->link); 01275 GPU_node_end(node); 01276 01277 gpu_material_add_node(mat, node); 01278 } 01279 01280 return 1; 01281 } 01282 01283 int GPU_link_changed(GPUNodeLink *link) 01284 { 01285 GPUNode *node; 01286 GPUInput *input; 01287 const char *name; 01288 01289 if(link->output) { 01290 node = link->output->node; 01291 name = node->name; 01292 01293 if(strcmp(name, "set_value")==0 || strcmp(name, "set_rgb")==0) { 01294 input = node->inputs.first; 01295 return (input->link != NULL); 01296 } 01297 01298 return 1; 01299 } 01300 else 01301 return 0; 01302 } 01303 01304 /* Pass create/free */ 01305 01306 static void gpu_nodes_tag(GPUNodeLink *link) 01307 { 01308 GPUNode *node; 01309 GPUInput *input; 01310 01311 if(!link->output) 01312 return; 01313 01314 node = link->output->node; 01315 if(node->tag) 01316 return; 01317 01318 node->tag= 1; 01319 for(input=node->inputs.first; input; input=input->next) 01320 if(input->link) 01321 gpu_nodes_tag(input->link); 01322 } 01323 01324 static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink) 01325 { 01326 GPUNode *node, *next; 01327 01328 for(node=nodes->first; node; node=node->next) 01329 node->tag= 0; 01330 01331 gpu_nodes_tag(outlink); 01332 01333 for(node=nodes->first; node; node=next) { 01334 next = node->next; 01335 01336 if(!node->tag) { 01337 BLI_remlink(nodes, node); 01338 GPU_node_free(node); 01339 } 01340 } 01341 } 01342 01343 GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, const char *name) 01344 { 01345 GPUShader *shader; 01346 GPUPass *pass; 01347 char *vertexcode, *fragmentcode; 01348 01349 /*if(!FUNCTION_LIB) { 01350 GPU_nodes_free(nodes); 01351 return NULL; 01352 }*/ 01353 01354 /* prune unused nodes */ 01355 gpu_nodes_prune(nodes, outlink); 01356 01357 gpu_nodes_get_vertex_attributes(nodes, attribs); 01358 gpu_nodes_get_builtin_flag(nodes, builtins); 01359 01360 /* generate code and compile with opengl */ 01361 fragmentcode = code_generate_fragment(nodes, outlink->output, name); 01362 vertexcode = code_generate_vertex(nodes); 01363 shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library); /*FUNCTION_LIB);*/ 01364 01365 /* failed? */ 01366 if (!shader) { 01367 memset(attribs, 0, sizeof(*attribs)); 01368 memset(builtins, 0, sizeof(*builtins)); 01369 GPU_nodes_free(nodes); 01370 return NULL; 01371 } 01372 01373 /* create pass */ 01374 pass = MEM_callocN(sizeof(GPUPass), "GPUPass"); 01375 01376 pass->output = outlink->output; 01377 pass->shader = shader; 01378 pass->fragmentcode = fragmentcode; 01379 pass->vertexcode = vertexcode; 01380 pass->libcode = glsl_material_library; 01381 01382 /* extract dynamic inputs and throw away nodes */ 01383 GPU_nodes_extract_dynamic_inputs(pass, nodes); 01384 GPU_nodes_free(nodes); 01385 01386 return pass; 01387 } 01388 01389 void GPU_pass_free(GPUPass *pass) 01390 { 01391 GPU_shader_free(pass->shader); 01392 GPU_inputs_free(&pass->inputs); 01393 if (pass->fragmentcode) 01394 MEM_freeN(pass->fragmentcode); 01395 if (pass->vertexcode) 01396 MEM_freeN(pass->vertexcode); 01397 MEM_freeN(pass); 01398 } 01399