Code refactor: reduce special node types, use generic constant folding.
[blender.git] / intern / cycles / render / osl.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "device.h"
18
19 #include "graph.h"
20 #include "light.h"
21 #include "osl.h"
22 #include "scene.h"
23 #include "shader.h"
24 #include "nodes.h"
25
26 #ifdef WITH_OSL
27
28 #include "osl_globals.h"
29 #include "osl_services.h"
30 #include "osl_shader.h"
31
32 #include "util_foreach.h"
33 #include "util_logging.h"
34 #include "util_md5.h"
35 #include "util_path.h"
36 #include "util_progress.h"
37
38 #endif
39
40 CCL_NAMESPACE_BEGIN
41
42 #ifdef WITH_OSL
43
44 /* Shared Texture and Shading System */
45
46 OSL::TextureSystem *OSLShaderManager::ts_shared = NULL;
47 int OSLShaderManager::ts_shared_users = 0;
48 thread_mutex OSLShaderManager::ts_shared_mutex;
49
50 OSL::ShadingSystem *OSLShaderManager::ss_shared = NULL;
51 OSLRenderServices *OSLShaderManager::services_shared = NULL;
52 int OSLShaderManager::ss_shared_users = 0;
53 thread_mutex OSLShaderManager::ss_shared_mutex;
54 thread_mutex OSLShaderManager::ss_mutex;
55
56 /* Shader Manager */
57
58 OSLShaderManager::OSLShaderManager()
59 {
60         texture_system_init();
61         shading_system_init();
62 }
63
64 OSLShaderManager::~OSLShaderManager()
65 {
66         shading_system_free();
67         texture_system_free();
68 }
69
70 void OSLShaderManager::reset(Scene * /*scene*/)
71 {
72         shading_system_free();
73         shading_system_init();
74 }
75
76 void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
77 {
78         if(!need_update)
79                 return;
80
81         VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
82
83         device_free(device, dscene, scene);
84
85         /* determine which shaders are in use */
86         device_update_shaders_used(scene);
87
88         /* create shaders */
89         OSLGlobals *og = (OSLGlobals*)device->osl_memory();
90
91         foreach(Shader *shader, scene->shaders) {
92                 assert(shader->graph);
93
94                 if(progress.get_cancel()) return;
95
96                 /* we can only compile one shader at the time as the OSL ShadingSytem
97                  * has a single state, but we put the lock here so different renders can
98                  * compile shaders alternating */
99                 thread_scoped_lock lock(ss_mutex);
100
101                 OSLCompiler compiler((void*)this, (void*)ss, scene->image_manager);
102                 compiler.background = (shader == scene->shaders[scene->default_background]);
103                 compiler.compile(scene, og, shader);
104
105                 if(shader->use_mis && shader->has_surface_emission)
106                         scene->light_manager->need_update = true;
107         }
108
109         /* setup shader engine */
110         og->ss = ss;
111         og->ts = ts;
112         og->services = services;
113
114         int background_id = scene->shader_manager->get_shader_id(scene->default_background);
115         og->background_state = og->surface_state[background_id & SHADER_MASK];
116         og->use = true;
117
118         foreach(Shader *shader, scene->shaders)
119                 shader->need_update = false;
120
121         need_update = false;
122         
123         /* set texture system */
124         scene->image_manager->set_osl_texture_system((void*)ts);
125
126         device_update_common(device, dscene, scene, progress);
127
128         {
129                 /* Perform greedyjit optimization.
130                  *
131                  * This might waste time on optimizing gorups which are never actually
132                  * used, but this prevents OSL from allocating data on TLS at render
133                  * time.
134                  *
135                  * This is much better for us because this way we aren't required to
136                  * stop task scheduler threads to make sure all TLS is clean and don't
137                  * have issues with TLS data free accessing freed memory if task scheduler
138                  * is being freed after the Session is freed.
139                  */
140                 thread_scoped_lock lock(ss_shared_mutex);
141                 ss->optimize_all_groups();
142         }
143 }
144
145 void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
146 {
147         OSLGlobals *og = (OSLGlobals*)device->osl_memory();
148
149         device_free_common(device, dscene, scene);
150
151         /* clear shader engine */
152         og->use = false;
153         og->ss = NULL;
154         og->ts = NULL;
155
156         og->surface_state.clear();
157         og->volume_state.clear();
158         og->displacement_state.clear();
159         og->background_state.reset();
160 }
161
162 void OSLShaderManager::texture_system_init()
163 {
164         /* create texture system, shared between different renders to reduce memory usage */
165         thread_scoped_lock lock(ts_shared_mutex);
166
167         if(ts_shared_users == 0) {
168                 ts_shared = TextureSystem::create(true);
169
170                 ts_shared->attribute("automip",  1);
171                 ts_shared->attribute("autotile", 64);
172                 ts_shared->attribute("gray_to_rgb", 1);
173
174                 /* effectively unlimited for now, until we support proper mipmap lookups */
175                 ts_shared->attribute("max_memory_MB", 16384);
176         }
177
178         ts = ts_shared;
179         ts_shared_users++;
180 }
181
182 void OSLShaderManager::texture_system_free()
183 {
184         /* shared texture system decrease users and destroy if no longer used */
185         thread_scoped_lock lock(ts_shared_mutex);
186         ts_shared_users--;
187
188         if(ts_shared_users == 0) {
189                 ts_shared->invalidate_all(true);
190                 OSL::TextureSystem::destroy(ts_shared);
191                 ts_shared = NULL;
192         }
193
194         ts = NULL;
195 }
196
197 void OSLShaderManager::shading_system_init()
198 {
199         /* create shading system, shared between different renders to reduce memory usage */
200         thread_scoped_lock lock(ss_shared_mutex);
201
202         if(ss_shared_users == 0) {
203                 services_shared = new OSLRenderServices();
204
205                 string shader_path = path_get("shader");
206 #ifdef _WIN32
207                 /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can
208                  * operate with file paths with any character. This requires to use wide
209                  * char functions, but OSL uses old fashioned ANSI functions which means:
210                  *
211                  * - We have to convert our paths to ANSI before passing to OSL
212                  * - OSL can't be used when there's a multi-byte character in the path
213                  *   to the shaders folder.
214                  */
215                 shader_path = string_to_ansi(shader_path);
216 #endif
217
218                 ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler);
219                 ss_shared->attribute("lockgeom", 1);
220                 ss_shared->attribute("commonspace", "world");
221                 ss_shared->attribute("searchpath:shader", shader_path);
222                 ss_shared->attribute("greedyjit", 1);
223
224                 VLOG(1) << "Using shader search path: " << shader_path;
225
226                 /* our own ray types */
227                 static const char *raytypes[] = {
228                         "camera",                       /* PATH_RAY_CAMERA */
229                         "reflection",           /* PATH_RAY_REFLECT */
230                         "refraction",           /* PATH_RAY_TRANSMIT */
231                         "diffuse",                      /* PATH_RAY_DIFFUSE */
232                         "glossy",                       /* PATH_RAY_GLOSSY */
233                         "singular",                     /* PATH_RAY_SINGULAR */
234                         "transparent",          /* PATH_RAY_TRANSPARENT */
235                         "shadow",                       /* PATH_RAY_SHADOW_OPAQUE */
236                         "shadow",                       /* PATH_RAY_SHADOW_TRANSPARENT */
237
238                         "__unused__",
239                         "__unused__",
240                         "diffuse_ancestor",     /* PATH_RAY_DIFFUSE_ANCESTOR */
241                         "__unused__",
242                         "__unused__",
243                         "__unused__",           /* PATH_RAY_SINGLE_PASS_DONE */
244                         "volume_scatter",       /* PATH_RAY_VOLUME_SCATTER */
245                 };
246
247                 const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]);
248                 ss_shared->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes);
249
250                 OSLShader::register_closures((OSLShadingSystem*)ss_shared);
251
252                 loaded_shaders.clear();
253         }
254
255         ss = ss_shared;
256         services = services_shared;
257         ss_shared_users++;
258 }
259
260 void OSLShaderManager::shading_system_free()
261 {
262         /* shared shading system decrease users and destroy if no longer used */
263         thread_scoped_lock lock(ss_shared_mutex);
264         ss_shared_users--;
265
266         if(ss_shared_users == 0) {
267                 delete ss_shared;
268                 ss_shared = NULL;
269
270                 delete services_shared;
271                 services_shared = NULL;
272         }
273
274         ss = NULL;
275         services = NULL;
276 }
277
278 bool OSLShaderManager::osl_compile(const string& inputfile, const string& outputfile)
279 {
280         vector<string> options;
281         string stdosl_path;
282         string shader_path = path_get("shader");
283
284         /* specify output file name */
285         options.push_back("-o");
286         options.push_back(outputfile);
287
288         /* specify standard include path */
289         string include_path_arg = string("-I") + shader_path;
290         options.push_back(include_path_arg);
291
292         stdosl_path = path_get("shader/stdosl.h");
293
294         /* compile */
295         OSL::OSLCompiler *compiler = new OSL::OSLCompiler(&OSL::ErrorHandler::default_handler());
296         bool ok = compiler->compile(string_view(inputfile), options, string_view(stdosl_path));
297         delete compiler;
298
299         return ok;
300 }
301
302 bool OSLShaderManager::osl_query(OSL::OSLQuery& query, const string& filepath)
303 {
304         string searchpath = path_user_get("shaders");
305         return query.open(filepath, searchpath);
306 }
307
308 static string shader_filepath_hash(const string& filepath, uint64_t modified_time)
309 {
310         /* compute a hash from filepath and modified time to detect changes */
311         MD5Hash md5;
312         md5.append((const uint8_t*)filepath.c_str(), filepath.size());
313         md5.append((const uint8_t*)&modified_time, sizeof(modified_time));
314
315         return md5.get_hex();
316 }
317
318 const char *OSLShaderManager::shader_test_loaded(const string& hash)
319 {
320         map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
321         return (it == loaded_shaders.end())? NULL: it->first.c_str();
322 }
323
324 OSLShaderInfo *OSLShaderManager::shader_loaded_info(const string& hash)
325 {
326         map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
327         return (it == loaded_shaders.end())? NULL: &it->second;
328 }
329
330 const char *OSLShaderManager::shader_load_filepath(string filepath)
331 {
332         size_t len = filepath.size();
333         string extension = filepath.substr(len - 4);
334         uint64_t modified_time = path_modified_time(filepath);
335
336         if(extension == ".osl") {
337                 /* .OSL File */
338                 string osopath = filepath.substr(0, len - 4) + ".oso";
339                 uint64_t oso_modified_time = path_modified_time(osopath);
340
341                 /* test if we have loaded the corresponding .OSO already */
342                 if(oso_modified_time != 0) {
343                         const char *hash = shader_test_loaded(shader_filepath_hash(osopath, oso_modified_time));
344
345                         if(hash)
346                                 return hash;
347                 }
348
349                 /* autocompile .OSL to .OSO if needed */
350                 if(oso_modified_time == 0 || (oso_modified_time < modified_time)) {
351                         OSLShaderManager::osl_compile(filepath, osopath);
352                         modified_time = path_modified_time(osopath);
353                 }
354                 else
355                         modified_time = oso_modified_time;
356
357                 filepath = osopath;
358         }
359         else {
360                 if(extension == ".oso") {
361                         /* .OSO File, nothing to do */
362                 }
363                 else if(path_dirname(filepath) == "") {
364                         /* .OSO File in search path */
365                         filepath = path_join(path_user_get("shaders"), filepath + ".oso");
366                 }
367                 else {
368                         /* unknown file */
369                         return NULL;
370                 }
371
372                 /* test if we have loaded this .OSO already */
373                 const char *hash = shader_test_loaded(shader_filepath_hash(filepath, modified_time));
374
375                 if(hash)
376                         return hash;
377         }
378
379         /* read oso bytecode from file */
380         string bytecode_hash = shader_filepath_hash(filepath, modified_time);
381         string bytecode;
382
383         if(!path_read_text(filepath, bytecode)) {
384                 fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str());
385                 OSLShaderInfo info;
386                 loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */
387                 return NULL;
388         }
389
390         return shader_load_bytecode(bytecode_hash, bytecode);
391 }
392
393 const char *OSLShaderManager::shader_load_bytecode(const string& hash, const string& bytecode)
394 {
395         ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
396
397         /* this is a bit weak, but works */
398         OSLShaderInfo info;
399         info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
400         info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
401         info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
402         loaded_shaders[hash] = info;
403
404         return loaded_shaders.find(hash)->first.c_str();
405 }
406
407 /* Graph Compiler */
408
409 OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_, ImageManager *image_manager_)
410 {
411         manager = manager_;
412         shadingsys = shadingsys_;
413         image_manager = image_manager_;
414         current_type = SHADER_TYPE_SURFACE;
415         current_shader = NULL;
416         background = false;
417 }
418
419 string OSLCompiler::id(ShaderNode *node)
420 {
421         /* assign layer unique name based on pointer address + bump mode */
422         stringstream stream;
423         stream << "node_" << node->name << "_" << node;
424
425         return stream.str();
426 }
427
428 string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
429 {
430         string sname(input->name);
431         size_t i;
432
433         /* strip whitespace */
434         while((i = sname.find(" ")) != string::npos)
435                 sname.replace(i, 1, "");
436         
437         /* if output exists with the same name, add "In" suffix */
438         foreach(ShaderOutput *output, node->outputs) {
439                 if(strcmp(input->name, output->name)==0) {
440                         sname += "In";
441                         break;
442                 }
443         }
444         
445         return sname;
446 }
447
448 string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
449 {
450         string sname(output->name);
451         size_t i;
452
453         /* strip whitespace */
454         while((i = sname.find(" ")) != string::npos)
455                 sname.replace(i, 1, "");
456         
457         /* if input exists with the same name, add "Out" suffix */
458         foreach(ShaderInput *input, node->inputs) {
459                 if(strcmp(input->name, output->name)==0) {
460                         sname += "Out";
461                         break;
462                 }
463         }
464         
465         return sname;
466 }
467
468 bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
469 {
470         /* exception for output node, only one input is actually used
471          * depending on the current shader type */
472         
473         if(!(input->usage & ShaderInput::USE_OSL))
474                 return true;
475
476         if(node->name == ustring("output")) {
477                 if(strcmp(input->name, "Surface") == 0 && current_type != SHADER_TYPE_SURFACE)
478                         return true;
479                 if(strcmp(input->name, "Volume") == 0 && current_type != SHADER_TYPE_VOLUME)
480                         return true;
481                 if(strcmp(input->name, "Displacement") == 0 && current_type != SHADER_TYPE_DISPLACEMENT)
482                         return true;
483                 if(strcmp(input->name, "Normal") == 0)
484                         return true;
485         }
486         else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
487                 if(strcmp(input->name, "Height") == 0)
488                         return true;
489         }
490         else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
491                 return true;
492
493         return false;
494 }
495
496 void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
497 {
498         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
499
500         /* load filepath */
501         if(isfilepath) {
502                 name = ((OSLShaderManager*)manager)->shader_load_filepath(name);
503
504                 if(name == NULL)
505                         return;
506         }
507
508         /* pass in fixed parameter values */
509         foreach(ShaderInput *input, node->inputs) {
510                 if(!input->link) {
511                         /* checks to untangle graphs */
512                         if(node_skip_input(node, input))
513                                 continue;
514                         /* already has default value assigned */
515                         else if(input->default_value != ShaderInput::NONE)
516                                 continue;
517
518                         string param_name = compatible_name(node, input);
519                         switch(input->type) {
520                                 case SHADER_SOCKET_COLOR:
521                                         parameter_color(param_name.c_str(), input->value);
522                                         break;
523                                 case SHADER_SOCKET_POINT:
524                                         parameter_point(param_name.c_str(), input->value);
525                                         break;
526                                 case SHADER_SOCKET_VECTOR:
527                                         parameter_vector(param_name.c_str(), input->value);
528                                         break;
529                                 case SHADER_SOCKET_NORMAL:
530                                         parameter_normal(param_name.c_str(), input->value);
531                                         break;
532                                 case SHADER_SOCKET_FLOAT:
533                                         parameter(param_name.c_str(), input->value.x);
534                                         break;
535                                 case SHADER_SOCKET_INT:
536                                         parameter(param_name.c_str(), (int)input->value.x);
537                                         break;
538                                 case SHADER_SOCKET_STRING:
539                                         parameter(param_name.c_str(), input->value_string);
540                                         break;
541                                 case SHADER_SOCKET_CLOSURE:
542                                 case SHADER_SOCKET_UNDEFINED:
543                                         break;
544                         }
545                 }
546         }
547
548         /* create shader of the appropriate type. OSL only distinguishes between "surface"
549          * and "displacement" atm */
550         if(current_type == SHADER_TYPE_SURFACE)
551                 ss->Shader("surface", name, id(node).c_str());
552         else if(current_type == SHADER_TYPE_VOLUME)
553                 ss->Shader("surface", name, id(node).c_str());
554         else if(current_type == SHADER_TYPE_DISPLACEMENT)
555                 ss->Shader("displacement", name, id(node).c_str());
556         else
557                 assert(0);
558         
559         /* link inputs to other nodes */
560         foreach(ShaderInput *input, node->inputs) {
561                 if(input->link) {
562                         if(node_skip_input(node, input))
563                                 continue;
564
565                         /* connect shaders */
566                         string id_from = id(input->link->parent);
567                         string id_to = id(node);
568                         string param_from = compatible_name(input->link->parent, input->link);
569                         string param_to = compatible_name(node, input);
570
571                         ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str());
572                 }
573         }
574
575         /* test if we shader contains specific closures */
576         OSLShaderInfo *info = ((OSLShaderManager*)manager)->shader_loaded_info(name);
577
578         if(current_type == SHADER_TYPE_SURFACE) {
579                 if(info) {
580                         if(info->has_surface_emission)
581                                 current_shader->has_surface_emission = true;
582                         if(info->has_surface_transparent)
583                                 current_shader->has_surface_transparent = true;
584                         if(info->has_surface_bssrdf) {
585                                 current_shader->has_surface_bssrdf = true;
586                                 current_shader->has_bssrdf_bump = true; /* can't detect yet */
587                         }
588                 }
589
590                 if(node->has_spatial_varying()) {
591                         current_shader->has_surface_spatial_varying = true;
592                 }
593         }
594         else if(current_type == SHADER_TYPE_VOLUME) {
595                 if(node->has_spatial_varying())
596                         current_shader->has_volume_spatial_varying = true;
597         }
598
599         if(node->has_object_dependency()) {
600                 current_shader->has_object_dependency = true;
601         }
602
603         if(node->has_integrator_dependency()) {
604                 current_shader->has_integrator_dependency = true;
605         }
606 }
607
608 void OSLCompiler::parameter(const char *name, float f)
609 {
610         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
611         ss->Parameter(name, TypeDesc::TypeFloat, &f);
612 }
613
614 void OSLCompiler::parameter_color(const char *name, float3 f)
615 {
616         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
617         ss->Parameter(name, TypeDesc::TypeColor, &f);
618 }
619
620 void OSLCompiler::parameter_point(const char *name, float3 f)
621 {
622         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
623         ss->Parameter(name, TypeDesc::TypePoint, &f);
624 }
625
626 void OSLCompiler::parameter_normal(const char *name, float3 f)
627 {
628         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
629         ss->Parameter(name, TypeDesc::TypeNormal, &f);
630 }
631
632 void OSLCompiler::parameter_vector(const char *name, float3 f)
633 {
634         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
635         ss->Parameter(name, TypeDesc::TypeVector, &f);
636 }
637
638 void OSLCompiler::parameter(const char *name, int f)
639 {
640         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
641         ss->Parameter(name, TypeDesc::TypeInt, &f);
642 }
643
644 void OSLCompiler::parameter(const char *name, const char *s)
645 {
646         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
647         ss->Parameter(name, TypeDesc::TypeString, &s);
648 }
649
650 void OSLCompiler::parameter(const char *name, ustring s)
651 {
652         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
653         const char *str = s.c_str();
654         ss->Parameter(name, TypeDesc::TypeString, &str);
655 }
656
657 void OSLCompiler::parameter(const char *name, const Transform& tfm)
658 {
659         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
660         ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&tfm);
661 }
662
663 void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
664 {
665         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
666         TypeDesc type = TypeDesc::TypeFloat;
667         type.arraylen = arraylen;
668         ss->Parameter(name, type, f);
669 }
670
671 void OSLCompiler::parameter_color_array(const char *name, const float f[][3], int arraylen)
672 {
673         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
674         TypeDesc type = TypeDesc::TypeColor;
675         type.arraylen = arraylen;
676         ss->Parameter(name, type, f);
677 }
678
679 void OSLCompiler::parameter_vector_array(const char *name, const float f[][3], int arraylen)
680 {
681         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
682         TypeDesc type = TypeDesc::TypeVector;
683         type.arraylen = arraylen;
684         ss->Parameter(name, type, f);
685 }
686
687 void OSLCompiler::parameter_normal_array(const char *name, const float f[][3], int arraylen)
688 {
689         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
690         TypeDesc type = TypeDesc::TypeNormal;
691         type.arraylen = arraylen;
692         ss->Parameter(name, type, f);
693 }
694
695 void OSLCompiler::parameter_point_array(const char *name, const float f[][3], int arraylen)
696 {
697         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
698         TypeDesc type = TypeDesc::TypePoint;
699         type.arraylen = arraylen;
700         ss->Parameter(name, type, f);
701 }
702
703 void OSLCompiler::parameter_array(const char *name, const int f[], int arraylen)
704 {
705         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
706         TypeDesc type = TypeDesc::TypeInt;
707         type.arraylen = arraylen;
708         ss->Parameter(name, type, f);
709 }
710
711 void OSLCompiler::parameter_array(const char *name, const char * const s[], int arraylen)
712 {
713         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
714         TypeDesc type = TypeDesc::TypeString;
715         type.arraylen = arraylen;
716         ss->Parameter(name, type, s);
717 }
718
719 void OSLCompiler::parameter_array(const char *name, const Transform tfm[], int arraylen)
720 {
721         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
722         TypeDesc type = TypeDesc::TypeMatrix;
723         type.arraylen = arraylen;
724         ss->Parameter(name, type, (const float *)tfm);
725 }
726
727 void OSLCompiler::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input)
728 {
729         ShaderNode *node = (input->link)? input->link->parent: NULL;
730
731         if(node != NULL && dependencies.find(node) == dependencies.end()) {
732                 foreach(ShaderInput *in, node->inputs)
733                         if(!node_skip_input(node, in))
734                                 find_dependencies(dependencies, in);
735
736                 dependencies.insert(node);
737         }
738 }
739
740 void OSLCompiler::generate_nodes(const ShaderNodeSet& nodes)
741 {
742         ShaderNodeSet done;
743         bool nodes_done;
744
745         do {
746                 nodes_done = true;
747
748                 foreach(ShaderNode *node, nodes) {
749                         if(done.find(node) == done.end()) {
750                                 bool inputs_done = true;
751
752                                 foreach(ShaderInput *input, node->inputs)
753                                         if(!node_skip_input(node, input))
754                                                 if(input->link && done.find(input->link->parent) == done.end())
755                                                         inputs_done = false;
756
757                                 if(inputs_done) {
758                                         node->compile(*this);
759                                         done.insert(node);
760
761                                         if(current_type == SHADER_TYPE_SURFACE) {
762                                                 if(node->has_surface_emission())
763                                                         current_shader->has_surface_emission = true;
764                                                 if(node->has_surface_transparent())
765                                                         current_shader->has_surface_transparent = true;
766                                                 if(node->has_spatial_varying())
767                                                         current_shader->has_surface_spatial_varying = true;
768                                                 if(node->has_surface_bssrdf()) {
769                                                         current_shader->has_surface_bssrdf = true;
770                                                         if(node->has_bssrdf_bump())
771                                                                 current_shader->has_bssrdf_bump = true;
772                                                 }
773                                         }
774                                         else if(current_type == SHADER_TYPE_VOLUME) {
775                                                 if(node->has_spatial_varying())
776                                                         current_shader->has_volume_spatial_varying = true;
777                                         }
778                                 }
779                                 else
780                                         nodes_done = false;
781                         }
782                 }
783         } while(!nodes_done);
784 }
785
786 OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
787 {
788         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
789
790         current_type = type;
791
792         OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str());
793
794         ShaderNode *output = graph->output();
795         ShaderNodeSet dependencies;
796
797         if(type == SHADER_TYPE_SURFACE) {
798                 /* generate surface shader */
799                 find_dependencies(dependencies, output->input("Surface"));
800                 generate_nodes(dependencies);
801                 output->compile(*this);
802         }
803         else if(type == SHADER_TYPE_VOLUME) {
804                 /* generate volume shader */
805                 find_dependencies(dependencies, output->input("Volume"));
806                 generate_nodes(dependencies);
807                 output->compile(*this);
808         }
809         else if(type == SHADER_TYPE_DISPLACEMENT) {
810                 /* generate displacement shader */
811                 find_dependencies(dependencies, output->input("Displacement"));
812                 generate_nodes(dependencies);
813                 output->compile(*this);
814         }
815         else
816                 assert(0);
817
818         ss->ShaderGroupEnd();
819
820         return group;
821 }
822
823 void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
824 {
825         if(shader->need_update) {
826                 ShaderGraph *graph = shader->graph;
827                 ShaderNode *output = (graph)? graph->output(): NULL;
828
829                 /* copy graph for shader with bump mapping */
830                 if(output->input("Surface")->link && output->input("Displacement")->link)
831                         if(!shader->graph_bump)
832                                 shader->graph_bump = shader->graph->copy();
833
834                 /* finalize */
835                 shader->graph->finalize(scene,
836                                         false,
837                                         true,
838                                         shader->has_integrator_dependency);
839                 if(shader->graph_bump) {
840                         shader->graph_bump->finalize(scene,
841                                                      true,
842                                                      true,
843                                                      shader->has_integrator_dependency);
844                 }
845
846                 current_shader = shader;
847
848                 shader->has_surface = false;
849                 shader->has_surface_emission = false;
850                 shader->has_surface_transparent = false;
851                 shader->has_surface_bssrdf = false;
852                 shader->has_bssrdf_bump = false;
853                 shader->has_volume = false;
854                 shader->has_displacement = false;
855                 shader->has_surface_spatial_varying = false;
856                 shader->has_volume_spatial_varying = false;
857                 shader->has_object_dependency = false;
858                 shader->has_integrator_dependency = false;
859
860                 /* generate surface shader */
861                 if(shader->used && graph && output->input("Surface")->link) {
862                         shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
863
864                         if(shader->graph_bump)
865                                 shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
866                         else
867                                 shader->osl_surface_bump_ref = shader->osl_surface_ref;
868
869                         shader->has_surface = true;
870                 }
871                 else {
872                         shader->osl_surface_ref = OSL::ShaderGroupRef();
873                         shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
874                 }
875
876                 /* generate volume shader */
877                 if(shader->used && graph && output->input("Volume")->link) {
878                         shader->osl_volume_ref = compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
879                         shader->has_volume = true;
880                 }
881                 else
882                         shader->osl_volume_ref = OSL::ShaderGroupRef();
883
884                 /* generate displacement shader */
885                 if(shader->used && graph && output->input("Displacement")->link) {
886                         shader->osl_displacement_ref = compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
887                         shader->has_displacement = true;
888                 }
889                 else
890                         shader->osl_displacement_ref = OSL::ShaderGroupRef();
891         }
892
893         /* push state to array for lookup */
894         og->surface_state.push_back(shader->osl_surface_ref);
895         og->surface_state.push_back(shader->osl_surface_bump_ref);
896
897         og->volume_state.push_back(shader->osl_volume_ref);
898         og->volume_state.push_back(shader->osl_volume_ref);
899
900         og->displacement_state.push_back(shader->osl_displacement_ref);
901         og->displacement_state.push_back(shader->osl_displacement_ref);
902 }
903
904 #else
905
906 void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/)
907 {
908 }
909
910 void OSLCompiler::parameter(const char * /*name*/, float /*f*/)
911 {
912 }
913
914 void OSLCompiler::parameter_color(const char * /*name*/, float3 /*f*/)
915 {
916 }
917
918 void OSLCompiler::parameter_vector(const char * /*name*/, float3 /*f*/)
919 {
920 }
921
922 void OSLCompiler::parameter_point(const char * /*name*/, float3 /*f*/)
923 {
924 }
925
926 void OSLCompiler::parameter_normal(const char * /*name*/, float3 /*f*/)
927 {
928 }
929
930 void OSLCompiler::parameter(const char * /*name*/, int /*f*/)
931 {
932 }
933
934 void OSLCompiler::parameter(const char * /*name*/, const char * /*s*/)
935 {
936 }
937
938 void OSLCompiler::parameter(const char * /*name*/, ustring /*s*/)
939 {
940 }
941
942 void OSLCompiler::parameter(const char * /*name*/, const Transform& /*tfm*/)
943 {
944 }
945
946 void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], int /*arraylen*/)
947 {
948 }
949
950 void OSLCompiler::parameter_color_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
951 {
952 }
953
954 void OSLCompiler::parameter_vector_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
955 {
956 }
957
958 void OSLCompiler::parameter_normal_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
959 {
960 }
961
962 void OSLCompiler::parameter_point_array(const char * /*name*/, const float /*f*/[][3], int /*arraylen*/)
963 {
964 }
965
966 void OSLCompiler::parameter_array(const char * /*name*/, const int /*f*/[], int /*arraylen*/)
967 {
968 }
969
970 void OSLCompiler::parameter_array(const char * /*name*/, const char * const /*s*/[], int /*arraylen*/)
971 {
972 }
973
974 void OSLCompiler::parameter_array(const char * /*name*/, const Transform /*tfm*/[], int /*arraylen*/)
975 {
976 }
977
978 #endif /* WITH_OSL */
979
980 CCL_NAMESPACE_END
981