fdd872f62b904da53f95adeed903503abf83aae6
[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/device.h"
18
19 #include "render/graph.h"
20 #include "render/light.h"
21 #include "render/osl.h"
22 #include "render/scene.h"
23 #include "render/shader.h"
24 #include "render/nodes.h"
25
26 #ifdef WITH_OSL
27
28 #include "kernel/osl/osl_globals.h"
29 #include "kernel/osl/osl_services.h"
30 #include "kernel/osl/osl_shader.h"
31
32 #include "util/util_foreach.h"
33 #include "util/util_logging.h"
34 #include "util/util_md5.h"
35 #include "util/util_path.h"
36 #include "util/util_progress.h"
37 #include "util/util_projection.h"
38
39 #endif
40
41 CCL_NAMESPACE_BEGIN
42
43 #ifdef WITH_OSL
44
45 /* Shared Texture and Shading System */
46
47 OSL::TextureSystem *OSLShaderManager::ts_shared = NULL;
48 int OSLShaderManager::ts_shared_users = 0;
49 thread_mutex OSLShaderManager::ts_shared_mutex;
50
51 OSL::ShadingSystem *OSLShaderManager::ss_shared = NULL;
52 OSLRenderServices *OSLShaderManager::services_shared = NULL;
53 int OSLShaderManager::ss_shared_users = 0;
54 thread_mutex OSLShaderManager::ss_shared_mutex;
55 thread_mutex OSLShaderManager::ss_mutex;
56
57 /* Shader Manager */
58
59 OSLShaderManager::OSLShaderManager()
60 {
61         texture_system_init();
62         shading_system_init();
63 }
64
65 OSLShaderManager::~OSLShaderManager()
66 {
67         shading_system_free();
68         texture_system_free();
69 }
70
71 void OSLShaderManager::reset(Scene * /*scene*/)
72 {
73         shading_system_free();
74         shading_system_init();
75 }
76
77 void OSLShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress)
78 {
79         if(!need_update)
80                 return;
81
82         VLOG(1) << "Total " << scene->shaders.size() << " shaders.";
83
84         device_free(device, dscene, scene);
85
86         /* determine which shaders are in use */
87         device_update_shaders_used(scene);
88
89         /* create shaders */
90         OSLGlobals *og = (OSLGlobals*)device->osl_memory();
91
92         foreach(Shader *shader, scene->shaders) {
93                 assert(shader->graph);
94
95                 if(progress.get_cancel()) return;
96
97                 /* we can only compile one shader at the time as the OSL ShadingSytem
98                  * has a single state, but we put the lock here so different renders can
99                  * compile shaders alternating */
100                 thread_scoped_lock lock(ss_mutex);
101
102                 OSLCompiler compiler((void*)this, (void*)ss,
103                                      scene->image_manager,
104                                      scene->light_manager);
105                 compiler.background = (shader == scene->default_background);
106                 compiler.compile(scene, og, shader);
107
108                 if(shader->use_mis && shader->has_surface_emission)
109                         scene->light_manager->need_update = true;
110         }
111
112         /* setup shader engine */
113         og->ss = ss;
114         og->ts = ts;
115         og->services = services;
116
117         int background_id = scene->shader_manager->get_shader_id(scene->default_background);
118         og->background_state = og->surface_state[background_id & SHADER_MASK];
119         og->use = true;
120
121         foreach(Shader *shader, scene->shaders)
122                 shader->need_update = false;
123
124         need_update = false;
125
126         /* set texture system */
127         scene->image_manager->set_osl_texture_system((void*)ts);
128
129         device_update_common(device, dscene, scene, progress);
130
131         {
132                 /* Perform greedyjit optimization.
133                  *
134                  * This might waste time on optimizing gorups which are never actually
135                  * used, but this prevents OSL from allocating data on TLS at render
136                  * time.
137                  *
138                  * This is much better for us because this way we aren't required to
139                  * stop task scheduler threads to make sure all TLS is clean and don't
140                  * have issues with TLS data free accessing freed memory if task scheduler
141                  * is being freed after the Session is freed.
142                  */
143                 thread_scoped_lock lock(ss_shared_mutex);
144                 ss->optimize_all_groups();
145         }
146 }
147
148 void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
149 {
150         OSLGlobals *og = (OSLGlobals*)device->osl_memory();
151
152         device_free_common(device, dscene, scene);
153
154         /* clear shader engine */
155         og->use = false;
156         og->ss = NULL;
157         og->ts = NULL;
158
159         og->surface_state.clear();
160         og->volume_state.clear();
161         og->displacement_state.clear();
162         og->bump_state.clear();
163         og->background_state.reset();
164 }
165
166 void OSLShaderManager::texture_system_init()
167 {
168         /* create texture system, shared between different renders to reduce memory usage */
169         thread_scoped_lock lock(ts_shared_mutex);
170
171         if(ts_shared_users == 0) {
172                 ts_shared = TextureSystem::create(true);
173
174                 ts_shared->attribute("automip",  1);
175                 ts_shared->attribute("autotile", 64);
176                 ts_shared->attribute("gray_to_rgb", 1);
177
178                 /* effectively unlimited for now, until we support proper mipmap lookups */
179                 ts_shared->attribute("max_memory_MB", 16384);
180         }
181
182         ts = ts_shared;
183         ts_shared_users++;
184 }
185
186 void OSLShaderManager::texture_system_free()
187 {
188         /* shared texture system decrease users and destroy if no longer used */
189         thread_scoped_lock lock(ts_shared_mutex);
190         ts_shared_users--;
191
192         if(ts_shared_users == 0) {
193                 ts_shared->invalidate_all(true);
194                 OSL::TextureSystem::destroy(ts_shared);
195                 ts_shared = NULL;
196         }
197
198         ts = NULL;
199 }
200
201 void OSLShaderManager::shading_system_init()
202 {
203         /* create shading system, shared between different renders to reduce memory usage */
204         thread_scoped_lock lock(ss_shared_mutex);
205
206         if(ss_shared_users == 0) {
207                 services_shared = new OSLRenderServices();
208
209                 string shader_path = path_get("shader");
210 #ifdef _WIN32
211                 /* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can
212                  * operate with file paths with any character. This requires to use wide
213                  * char functions, but OSL uses old fashioned ANSI functions which means:
214                  *
215                  * - We have to convert our paths to ANSI before passing to OSL
216                  * - OSL can't be used when there's a multi-byte character in the path
217                  *   to the shaders folder.
218                  */
219                 shader_path = string_to_ansi(shader_path);
220 #endif
221
222                 ss_shared = new OSL::ShadingSystem(services_shared, ts_shared, &errhandler);
223                 ss_shared->attribute("lockgeom", 1);
224                 ss_shared->attribute("commonspace", "world");
225                 ss_shared->attribute("searchpath:shader", shader_path);
226                 ss_shared->attribute("greedyjit", 1);
227
228                 VLOG(1) << "Using shader search path: " << shader_path;
229
230                 /* our own ray types */
231                 static const char *raytypes[] = {
232                         "camera",                       /* PATH_RAY_CAMERA */
233                         "reflection",           /* PATH_RAY_REFLECT */
234                         "refraction",           /* PATH_RAY_TRANSMIT */
235                         "diffuse",                      /* PATH_RAY_DIFFUSE */
236                         "glossy",                       /* PATH_RAY_GLOSSY */
237                         "singular",                     /* PATH_RAY_SINGULAR */
238                         "transparent",          /* PATH_RAY_TRANSPARENT */
239
240                         "shadow",                       /* PATH_RAY_SHADOW_OPAQUE_NON_CATCHER */
241                         "shadow",                       /* PATH_RAY_SHADOW_OPAQUE_CATCHER */
242                         "shadow",                       /* PATH_RAY_SHADOW_TRANSPARENT_NON_CATCHER */
243                         "shadow",                       /* PATH_RAY_SHADOW_TRANSPARENT_CATCHER */
244
245                         "__unused__",
246                         "volume_scatter",       /* PATH_RAY_VOLUME_SCATTER */
247                         "__unused__",
248
249                         "__unused__",
250                         "diffuse_ancestor",     /* PATH_RAY_DIFFUSE_ANCESTOR */
251                         "__unused__",
252                         "__unused__",
253                         "__unused__",
254                         "__unused__",
255                         "__unused__",
256                         "__unused__",
257                         "__unused__",
258                 };
259
260                 const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]);
261                 ss_shared->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes);
262
263                 OSLShader::register_closures((OSLShadingSystem*)ss_shared);
264
265                 loaded_shaders.clear();
266         }
267
268         ss = ss_shared;
269         services = services_shared;
270         ss_shared_users++;
271 }
272
273 void OSLShaderManager::shading_system_free()
274 {
275         /* shared shading system decrease users and destroy if no longer used */
276         thread_scoped_lock lock(ss_shared_mutex);
277         ss_shared_users--;
278
279         if(ss_shared_users == 0) {
280                 delete ss_shared;
281                 ss_shared = NULL;
282
283                 delete services_shared;
284                 services_shared = NULL;
285         }
286
287         ss = NULL;
288         services = NULL;
289 }
290
291 bool OSLShaderManager::osl_compile(const string& inputfile, const string& outputfile)
292 {
293         vector<string> options;
294         string stdosl_path;
295         string shader_path = path_get("shader");
296
297         /* specify output file name */
298         options.push_back("-o");
299         options.push_back(outputfile);
300
301         /* specify standard include path */
302         string include_path_arg = string("-I") + shader_path;
303         options.push_back(include_path_arg);
304
305         stdosl_path = path_get("shader/stdosl.h");
306
307         /* compile */
308         OSL::OSLCompiler *compiler = new OSL::OSLCompiler(&OSL::ErrorHandler::default_handler());
309         bool ok = compiler->compile(string_view(inputfile), options, string_view(stdosl_path));
310         delete compiler;
311
312         return ok;
313 }
314
315 bool OSLShaderManager::osl_query(OSL::OSLQuery& query, const string& filepath)
316 {
317         string searchpath = path_user_get("shaders");
318         return query.open(filepath, searchpath);
319 }
320
321 static string shader_filepath_hash(const string& filepath, uint64_t modified_time)
322 {
323         /* compute a hash from filepath and modified time to detect changes */
324         MD5Hash md5;
325         md5.append((const uint8_t*)filepath.c_str(), filepath.size());
326         md5.append((const uint8_t*)&modified_time, sizeof(modified_time));
327
328         return md5.get_hex();
329 }
330
331 const char *OSLShaderManager::shader_test_loaded(const string& hash)
332 {
333         map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
334         return (it == loaded_shaders.end())? NULL: it->first.c_str();
335 }
336
337 OSLShaderInfo *OSLShaderManager::shader_loaded_info(const string& hash)
338 {
339         map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
340         return (it == loaded_shaders.end())? NULL: &it->second;
341 }
342
343 const char *OSLShaderManager::shader_load_filepath(string filepath)
344 {
345         size_t len = filepath.size();
346         string extension = filepath.substr(len - 4);
347         uint64_t modified_time = path_modified_time(filepath);
348
349         if(extension == ".osl") {
350                 /* .OSL File */
351                 string osopath = filepath.substr(0, len - 4) + ".oso";
352                 uint64_t oso_modified_time = path_modified_time(osopath);
353
354                 /* test if we have loaded the corresponding .OSO already */
355                 if(oso_modified_time != 0) {
356                         const char *hash = shader_test_loaded(shader_filepath_hash(osopath, oso_modified_time));
357
358                         if(hash)
359                                 return hash;
360                 }
361
362                 /* autocompile .OSL to .OSO if needed */
363                 if(oso_modified_time == 0 || (oso_modified_time < modified_time)) {
364                         OSLShaderManager::osl_compile(filepath, osopath);
365                         modified_time = path_modified_time(osopath);
366                 }
367                 else
368                         modified_time = oso_modified_time;
369
370                 filepath = osopath;
371         }
372         else {
373                 if(extension == ".oso") {
374                         /* .OSO File, nothing to do */
375                 }
376                 else if(path_dirname(filepath) == "") {
377                         /* .OSO File in search path */
378                         filepath = path_join(path_user_get("shaders"), filepath + ".oso");
379                 }
380                 else {
381                         /* unknown file */
382                         return NULL;
383                 }
384
385                 /* test if we have loaded this .OSO already */
386                 const char *hash = shader_test_loaded(shader_filepath_hash(filepath, modified_time));
387
388                 if(hash)
389                         return hash;
390         }
391
392         /* read oso bytecode from file */
393         string bytecode_hash = shader_filepath_hash(filepath, modified_time);
394         string bytecode;
395
396         if(!path_read_text(filepath, bytecode)) {
397                 fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str());
398                 OSLShaderInfo info;
399                 loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */
400                 return NULL;
401         }
402
403         return shader_load_bytecode(bytecode_hash, bytecode);
404 }
405
406 const char *OSLShaderManager::shader_load_bytecode(const string& hash, const string& bytecode)
407 {
408         ss->LoadMemoryCompiledShader(hash.c_str(), bytecode.c_str());
409
410         OSLShaderInfo info;
411
412         if(!info.query.open_bytecode(bytecode)) {
413                 fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str());
414         }
415
416         /* this is a bit weak, but works */
417         info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
418         info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
419         info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
420
421         loaded_shaders[hash] = info;
422
423         return loaded_shaders.find(hash)->first.c_str();
424 }
425
426 OSLNode *OSLShaderManager::osl_node(const std::string& filepath,
427                                     const std::string& bytecode_hash,
428                                     const std::string& bytecode)
429 {
430         /* create query */
431         const char *hash;
432
433         if(!filepath.empty()) {
434                 hash = shader_load_filepath(filepath);
435         }
436         else {
437                 hash = shader_test_loaded(bytecode_hash);
438                 if(!hash)
439                         hash = shader_load_bytecode(bytecode_hash, bytecode);
440         }
441
442         if(!hash) {
443                 return NULL;
444         }
445
446         OSLShaderInfo *info = shader_loaded_info(hash);
447
448         /* count number of inputs */
449         size_t num_inputs = 0;
450
451         for(int i = 0; i < info->query.nparams(); i++) {
452                 const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
453
454                 /* skip unsupported types */
455                 if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
456                         continue;
457
458                 if(!param->isoutput)
459                         num_inputs++;
460         }
461
462         /* create node */
463         OSLNode *node = OSLNode::create(num_inputs);
464
465         /* add new sockets from parameters */
466         set<void*> used_sockets;
467
468         for(int i = 0; i < info->query.nparams(); i++) {
469                 const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
470
471                 /* skip unsupported types */
472                 if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
473                         continue;
474
475                 SocketType::Type socket_type;
476
477                 if(param->isclosure) {
478                         socket_type = SocketType::CLOSURE;
479                 }
480                 else if(param->type.vecsemantics != TypeDesc::NOSEMANTICS) {
481                         if(param->type.vecsemantics == TypeDesc::COLOR)
482                                 socket_type = SocketType::COLOR;
483                         else if(param->type.vecsemantics == TypeDesc::POINT)
484                                 socket_type = SocketType::POINT;
485                         else if(param->type.vecsemantics == TypeDesc::VECTOR)
486                                 socket_type = SocketType::VECTOR;
487                         else if(param->type.vecsemantics == TypeDesc::NORMAL)
488                                 socket_type = SocketType::NORMAL;
489                         else
490                                 continue;
491
492                         if(!param->isoutput && param->validdefault) {
493                                 float3 *default_value = (float3*)node->input_default_value();
494                                 default_value->x = param->fdefault[0];
495                                 default_value->y = param->fdefault[1];
496                                 default_value->z = param->fdefault[2];
497                         }
498                 }
499                 else if(param->type.aggregate == TypeDesc::SCALAR) {
500                         if(param->type.basetype == TypeDesc::INT) {
501                                 socket_type = SocketType::INT;
502
503                                 if(!param->isoutput && param->validdefault) {
504                                         *(int*)node->input_default_value() = param->idefault[0];
505                                 }
506                         }
507                         else if(param->type.basetype == TypeDesc::FLOAT) {
508                                 socket_type = SocketType::FLOAT;
509
510                                 if(!param->isoutput && param->validdefault) {
511                                         *(float*)node->input_default_value() = param->fdefault[0];
512                                 }
513                         }
514                         else if(param->type.basetype == TypeDesc::STRING) {
515                                 socket_type = SocketType::STRING;
516
517                                 if(!param->isoutput && param->validdefault) {
518                                         *(ustring*)node->input_default_value() = param->sdefault[0];
519                                 }
520                         }
521                         else
522                                 continue;
523                 }
524                 else
525                         continue;
526
527                 if(param->isoutput) {
528                         node->add_output(param->name, socket_type);
529                 }
530                 else {
531                         node->add_input(param->name, socket_type);
532                 }
533         }
534
535         /* set bytcode hash or filepath */
536         if(!bytecode_hash.empty()) {
537                 node->bytecode_hash = bytecode_hash;
538         }
539         else {
540                 node->filepath = filepath;
541         }
542
543         /* Generate inputs and outputs */
544         node->create_inputs_outputs(node->type);
545
546         return node;
547 }
548
549 /* Graph Compiler */
550
551 OSLCompiler::OSLCompiler(void *manager_, void *shadingsys_,
552                          ImageManager *image_manager_,
553                          LightManager *light_manager_)
554 {
555         manager = manager_;
556         shadingsys = shadingsys_;
557         image_manager = image_manager_;
558         light_manager = light_manager_;
559         current_type = SHADER_TYPE_SURFACE;
560         current_shader = NULL;
561         background = false;
562 }
563
564 string OSLCompiler::id(ShaderNode *node)
565 {
566         /* assign layer unique name based on pointer address + bump mode */
567         stringstream stream;
568         stream << "node_" << node->type->name << "_" << node;
569
570         return stream.str();
571 }
572
573 string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
574 {
575         string sname(input->name().string());
576         size_t i;
577
578         /* strip whitespace */
579         while((i = sname.find(" ")) != string::npos)
580                 sname.replace(i, 1, "");
581
582         /* if output exists with the same name, add "In" suffix */
583         foreach(ShaderOutput *output, node->outputs) {
584                 if(input->name() == output->name()) {
585                         sname += "In";
586                         break;
587                 }
588         }
589
590         return sname;
591 }
592
593 string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
594 {
595         string sname(output->name().string());
596         size_t i;
597
598         /* strip whitespace */
599         while((i = sname.find(" ")) != string::npos)
600                 sname.replace(i, 1, "");
601
602         /* if input exists with the same name, add "Out" suffix */
603         foreach(ShaderInput *input, node->inputs) {
604                 if(input->name() == output->name()) {
605                         sname += "Out";
606                         break;
607                 }
608         }
609
610         return sname;
611 }
612
613 bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
614 {
615         /* exception for output node, only one input is actually used
616          * depending on the current shader type */
617
618         if(input->flags() & SocketType::SVM_INTERNAL)
619                 return true;
620
621         if(node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) {
622                 if(input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE)
623                         return true;
624                 if(input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME)
625                         return true;
626                 if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT)
627                         return true;
628                 if(input->name() == "Normal" && current_type != SHADER_TYPE_BUMP)
629                         return true;
630         }
631         else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
632                 if(input->name() == "Height")
633                         return true;
634         }
635         else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
636                 return true;
637
638         return false;
639 }
640
641 void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
642 {
643         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
644
645         /* load filepath */
646         if(isfilepath) {
647                 name = ((OSLShaderManager*)manager)->shader_load_filepath(name);
648
649                 if(name == NULL)
650                         return;
651         }
652
653         /* pass in fixed parameter values */
654         foreach(ShaderInput *input, node->inputs) {
655                 if(!input->link) {
656                         /* checks to untangle graphs */
657                         if(node_skip_input(node, input))
658                                 continue;
659                         /* already has default value assigned */
660                         else if(input->flags() & SocketType::DEFAULT_LINK_MASK)
661                                 continue;
662
663                         string param_name = compatible_name(node, input);
664                         const SocketType& socket = input->socket_type;
665                         switch(input->type()) {
666                                 case SocketType::COLOR:
667                                         parameter_color(param_name.c_str(), node->get_float3(socket));
668                                         break;
669                                 case SocketType::POINT:
670                                         parameter_point(param_name.c_str(), node->get_float3(socket));
671                                         break;
672                                 case SocketType::VECTOR:
673                                         parameter_vector(param_name.c_str(), node->get_float3(socket));
674                                         break;
675                                 case SocketType::NORMAL:
676                                         parameter_normal(param_name.c_str(), node->get_float3(socket));
677                                         break;
678                                 case SocketType::FLOAT:
679                                         parameter(param_name.c_str(), node->get_float(socket));
680                                         break;
681                                 case SocketType::INT:
682                                         parameter(param_name.c_str(), node->get_int(socket));
683                                         break;
684                                 case SocketType::STRING:
685                                         parameter(param_name.c_str(), node->get_string(socket));
686                                         break;
687                                 case SocketType::CLOSURE:
688                                 case SocketType::UNDEFINED:
689                                 default:
690                                         break;
691                         }
692                 }
693         }
694
695         /* create shader of the appropriate type. OSL only distinguishes between "surface"
696          * and "displacement" atm */
697         if(current_type == SHADER_TYPE_SURFACE)
698                 ss->Shader("surface", name, id(node).c_str());
699         else if(current_type == SHADER_TYPE_VOLUME)
700                 ss->Shader("surface", name, id(node).c_str());
701         else if(current_type == SHADER_TYPE_DISPLACEMENT)
702                 ss->Shader("displacement", name, id(node).c_str());
703         else if(current_type == SHADER_TYPE_BUMP)
704                 ss->Shader("displacement", name, id(node).c_str());
705         else
706                 assert(0);
707
708         /* link inputs to other nodes */
709         foreach(ShaderInput *input, node->inputs) {
710                 if(input->link) {
711                         if(node_skip_input(node, input))
712                                 continue;
713
714                         /* connect shaders */
715                         string id_from = id(input->link->parent);
716                         string id_to = id(node);
717                         string param_from = compatible_name(input->link->parent, input->link);
718                         string param_to = compatible_name(node, input);
719
720                         ss->ConnectShaders(id_from.c_str(), param_from.c_str(), id_to.c_str(), param_to.c_str());
721                 }
722         }
723
724         /* test if we shader contains specific closures */
725         OSLShaderInfo *info = ((OSLShaderManager*)manager)->shader_loaded_info(name);
726
727         if(current_type == SHADER_TYPE_SURFACE) {
728                 if(info) {
729                         if(info->has_surface_emission)
730                                 current_shader->has_surface_emission = true;
731                         if(info->has_surface_transparent)
732                                 current_shader->has_surface_transparent = true;
733                         if(info->has_surface_bssrdf) {
734                                 current_shader->has_surface_bssrdf = true;
735                                 current_shader->has_bssrdf_bump = true; /* can't detect yet */
736                         }
737                         current_shader->has_bump = true; /* can't detect yet */
738                 }
739
740                 if(node->has_spatial_varying()) {
741                         current_shader->has_surface_spatial_varying = true;
742                 }
743         }
744         else if(current_type == SHADER_TYPE_VOLUME) {
745                 if(node->has_spatial_varying())
746                         current_shader->has_volume_spatial_varying = true;
747         }
748
749         if(node->has_object_dependency()) {
750                 current_shader->has_object_dependency = true;
751         }
752
753         if(node->has_attribute_dependency()) {
754                 current_shader->has_attribute_dependency = true;
755         }
756
757         if(node->has_integrator_dependency()) {
758                 current_shader->has_integrator_dependency = true;
759         }
760 }
761
762 static TypeDesc array_typedesc(TypeDesc typedesc, int arraylength)
763 {
764         return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype,
765                         (TypeDesc::AGGREGATE)typedesc.aggregate,
766                         (TypeDesc::VECSEMANTICS)typedesc.vecsemantics,
767                         arraylength);
768 }
769
770 void OSLCompiler::parameter(ShaderNode* node, const char *name)
771 {
772         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
773         ustring uname = ustring(name);
774         const SocketType& socket = *(node->type->find_input(uname));
775
776         switch(socket.type)
777         {
778                 case SocketType::BOOLEAN:
779                 {
780                         int value = node->get_bool(socket);
781                         ss->Parameter(name, TypeDesc::TypeInt, &value);
782                         break;
783                 }
784                 case SocketType::FLOAT:
785                 {
786                         float value = node->get_float(socket);
787                         ss->Parameter(uname, TypeDesc::TypeFloat, &value);
788                         break;
789                 }
790                 case SocketType::INT:
791                 {
792                         int value = node->get_int(socket);
793                         ss->Parameter(uname, TypeDesc::TypeInt, &value);
794                         break;
795                 }
796                 case SocketType::COLOR:
797                 {
798                         float3 value = node->get_float3(socket);
799                         ss->Parameter(uname, TypeDesc::TypeColor, &value);
800                         break;
801                 }
802                 case SocketType::VECTOR:
803                 {
804                         float3 value = node->get_float3(socket);
805                         ss->Parameter(uname, TypeDesc::TypeVector, &value);
806                         break;
807                 }
808                 case SocketType::POINT:
809                 {
810                         float3 value = node->get_float3(socket);
811                         ss->Parameter(uname, TypeDesc::TypePoint, &value);
812                         break;
813                 }
814                 case SocketType::NORMAL:
815                 {
816                         float3 value = node->get_float3(socket);
817                         ss->Parameter(uname, TypeDesc::TypeNormal, &value);
818                         break;
819                 }
820                 case SocketType::POINT2:
821                 {
822                         float2 value = node->get_float2(socket);
823                         ss->Parameter(uname, TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), &value);
824                         break;
825                 }
826                 case SocketType::STRING:
827                 {
828                         ustring value = node->get_string(socket);
829                         ss->Parameter(uname, TypeDesc::TypeString, &value);
830                         break;
831                 }
832                 case SocketType::ENUM:
833                 {
834                         ustring value = node->get_string(socket);
835                         ss->Parameter(uname, TypeDesc::TypeString, &value);
836                         break;
837                 }
838                 case SocketType::TRANSFORM:
839                 {
840                         Transform value = node->get_transform(socket);
841                         ProjectionTransform projection(value);
842                         projection = projection_transpose(projection);
843                         ss->Parameter(uname, TypeDesc::TypeMatrix, &projection);
844                         break;
845                 }
846                 case SocketType::BOOLEAN_ARRAY:
847                 {
848                         // OSL does not support booleans, so convert to int
849                         const array<bool>& value = node->get_bool_array(socket);
850                         array<int> intvalue(value.size());
851                         for(size_t i = 0; i < value.size(); i++)
852                                 intvalue[i] = value[i];
853                         ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data());
854                         break;
855                 }
856                 case SocketType::FLOAT_ARRAY:
857                 {
858                         const array<float>& value = node->get_float_array(socket);
859                         ss->Parameter(uname, array_typedesc(TypeDesc::TypeFloat, value.size()), value.data());
860                         break;
861                 }
862                 case SocketType::INT_ARRAY:
863                 {
864                         const array<int>& value = node->get_int_array(socket);
865                         ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), value.data());
866                         break;
867                 }
868                 case SocketType::COLOR_ARRAY:
869                 case SocketType::VECTOR_ARRAY:
870                 case SocketType::POINT_ARRAY:
871                 case SocketType::NORMAL_ARRAY:
872                 {
873                         TypeDesc typedesc;
874
875                         switch(socket.type)
876                         {
877                                 case SocketType::COLOR_ARRAY: typedesc = TypeDesc::TypeColor; break;
878                                 case SocketType::VECTOR_ARRAY: typedesc = TypeDesc::TypeVector; break;
879                                 case SocketType::POINT_ARRAY: typedesc = TypeDesc::TypePoint; break;
880                                 case SocketType::NORMAL_ARRAY: typedesc = TypeDesc::TypeNormal; break;
881                                 default: assert(0); break;
882                         }
883
884                         // convert to tightly packed array since float3 has padding
885                         const array<float3>& value = node->get_float3_array(socket);
886                         array<float> fvalue(value.size() * 3);
887                         for(size_t i = 0, j = 0; i < value.size(); i++) {
888                                 fvalue[j++] = value[i].x;
889                                 fvalue[j++] = value[i].y;
890                                 fvalue[j++] = value[i].z;
891                         }
892
893                         ss->Parameter(uname, array_typedesc(typedesc, value.size()), fvalue.data());
894                         break;
895                 }
896                 case SocketType::POINT2_ARRAY:
897                 {
898                         const array<float2>& value = node->get_float2_array(socket);
899                         ss->Parameter(uname, array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()), value.data());
900                         break;
901                 }
902                 case SocketType::STRING_ARRAY:
903                 {
904                         const array<ustring>& value = node->get_string_array(socket);
905                         ss->Parameter(uname, array_typedesc(TypeDesc::TypeString, value.size()), value.data());
906                         break;
907                 }
908                 case SocketType::TRANSFORM_ARRAY:
909                 {
910                         const array<Transform>& value = node->get_transform_array(socket);
911                         array<ProjectionTransform> fvalue(value.size());
912                         for(size_t i = 0; i < value.size(); i++) {
913                                 fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
914                         }
915                         ss->Parameter(uname, array_typedesc(TypeDesc::TypeMatrix, fvalue.size()), fvalue.data());
916                         break;
917                 }
918                 case SocketType::CLOSURE:
919                 case SocketType::NODE:
920                 case SocketType::NODE_ARRAY:
921                 case SocketType::UNDEFINED:
922                 case SocketType::UINT:
923                 {
924                         assert(0);
925                         break;
926                 }
927         }
928 }
929
930 void OSLCompiler::parameter(const char *name, float f)
931 {
932         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
933         ss->Parameter(name, TypeDesc::TypeFloat, &f);
934 }
935
936 void OSLCompiler::parameter_color(const char *name, float3 f)
937 {
938         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
939         ss->Parameter(name, TypeDesc::TypeColor, &f);
940 }
941
942 void OSLCompiler::parameter_point(const char *name, float3 f)
943 {
944         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
945         ss->Parameter(name, TypeDesc::TypePoint, &f);
946 }
947
948 void OSLCompiler::parameter_normal(const char *name, float3 f)
949 {
950         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
951         ss->Parameter(name, TypeDesc::TypeNormal, &f);
952 }
953
954 void OSLCompiler::parameter_vector(const char *name, float3 f)
955 {
956         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
957         ss->Parameter(name, TypeDesc::TypeVector, &f);
958 }
959
960 void OSLCompiler::parameter(const char *name, int f)
961 {
962         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
963         ss->Parameter(name, TypeDesc::TypeInt, &f);
964 }
965
966 void OSLCompiler::parameter(const char *name, const char *s)
967 {
968         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
969         ss->Parameter(name, TypeDesc::TypeString, &s);
970 }
971
972 void OSLCompiler::parameter(const char *name, ustring s)
973 {
974         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
975         const char *str = s.c_str();
976         ss->Parameter(name, TypeDesc::TypeString, &str);
977 }
978
979 void OSLCompiler::parameter(const char *name, const Transform& tfm)
980 {
981         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
982         ProjectionTransform projection(tfm);
983         projection = projection_transpose(projection);
984         ss->Parameter(name, TypeDesc::TypeMatrix, (float*)&projection);
985 }
986
987 void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
988 {
989         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
990         TypeDesc type = TypeDesc::TypeFloat;
991         type.arraylen = arraylen;
992         ss->Parameter(name, type, f);
993 }
994
995 void OSLCompiler::parameter_color_array(const char *name, const array<float3>& f)
996 {
997         /* NB: cycles float3 type is actually 4 floats! need to use an explicit array */
998         array<float[3]> table(f.size());
999
1000         for(int i = 0; i < f.size(); ++i) {
1001                 table[i][0] = f[i].x;
1002                 table[i][1] = f[i].y;
1003                 table[i][2] = f[i].z;
1004         }
1005
1006         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
1007         TypeDesc type = TypeDesc::TypeColor;
1008         type.arraylen = table.size();
1009         ss->Parameter(name, type, table.data());
1010 }
1011
1012 void OSLCompiler::parameter_attribute(const char *name, ustring s)
1013 {
1014         if(Attribute::name_standard(s.c_str()))
1015                 parameter(name, (string("geom:") + s.c_str()).c_str());
1016         else
1017                 parameter(name, s.c_str());
1018 }
1019
1020 void OSLCompiler::find_dependencies(ShaderNodeSet& dependencies, ShaderInput *input)
1021 {
1022         ShaderNode *node = (input->link)? input->link->parent: NULL;
1023
1024         if(node != NULL && dependencies.find(node) == dependencies.end()) {
1025                 foreach(ShaderInput *in, node->inputs)
1026                         if(!node_skip_input(node, in))
1027                                 find_dependencies(dependencies, in);
1028
1029                 dependencies.insert(node);
1030         }
1031 }
1032
1033 void OSLCompiler::generate_nodes(const ShaderNodeSet& nodes)
1034 {
1035         ShaderNodeSet done;
1036         bool nodes_done;
1037
1038         do {
1039                 nodes_done = true;
1040
1041                 foreach(ShaderNode *node, nodes) {
1042                         if(done.find(node) == done.end()) {
1043                                 bool inputs_done = true;
1044
1045                                 foreach(ShaderInput *input, node->inputs)
1046                                         if(!node_skip_input(node, input))
1047                                                 if(input->link && done.find(input->link->parent) == done.end())
1048                                                         inputs_done = false;
1049
1050                                 if(inputs_done) {
1051                                         node->compile(*this);
1052                                         done.insert(node);
1053
1054                                         if(current_type == SHADER_TYPE_SURFACE) {
1055                                                 if(node->has_surface_emission())
1056                                                         current_shader->has_surface_emission = true;
1057                                                 if(node->has_surface_transparent())
1058                                                         current_shader->has_surface_transparent = true;
1059                                                 if(node->has_spatial_varying())
1060                                                         current_shader->has_surface_spatial_varying = true;
1061                                                 if(node->has_surface_bssrdf()) {
1062                                                         current_shader->has_surface_bssrdf = true;
1063                                                         if(node->has_bssrdf_bump())
1064                                                                 current_shader->has_bssrdf_bump = true;
1065                                                 }
1066                                                 if(node->has_bump()) {
1067                                                         current_shader->has_bump = true;
1068                                                 }
1069                                         }
1070                                         else if(current_type == SHADER_TYPE_VOLUME) {
1071                                                 if(node->has_spatial_varying())
1072                                                         current_shader->has_volume_spatial_varying = true;
1073                                         }
1074                                 }
1075                                 else
1076                                         nodes_done = false;
1077                         }
1078                 }
1079         } while(!nodes_done);
1080 }
1081
1082 OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
1083 {
1084         OSL::ShadingSystem *ss = (OSL::ShadingSystem*)shadingsys;
1085
1086         current_type = type;
1087
1088         OSL::ShaderGroupRef group = ss->ShaderGroupBegin(shader->name.c_str());
1089
1090         ShaderNode *output = graph->output();
1091         ShaderNodeSet dependencies;
1092
1093         if(type == SHADER_TYPE_SURFACE) {
1094                 /* generate surface shader */
1095                 find_dependencies(dependencies, output->input("Surface"));
1096                 generate_nodes(dependencies);
1097                 output->compile(*this);
1098         }
1099         else if(type == SHADER_TYPE_BUMP) {
1100                 /* generate bump shader */
1101                 find_dependencies(dependencies, output->input("Normal"));
1102                 generate_nodes(dependencies);
1103                 output->compile(*this);
1104         }
1105         else if(type == SHADER_TYPE_VOLUME) {
1106                 /* generate volume shader */
1107                 find_dependencies(dependencies, output->input("Volume"));
1108                 generate_nodes(dependencies);
1109                 output->compile(*this);
1110         }
1111         else if(type == SHADER_TYPE_DISPLACEMENT) {
1112                 /* generate displacement shader */
1113                 find_dependencies(dependencies, output->input("Displacement"));
1114                 generate_nodes(dependencies);
1115                 output->compile(*this);
1116         }
1117         else
1118                 assert(0);
1119
1120         ss->ShaderGroupEnd();
1121
1122         return group;
1123 }
1124
1125 void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
1126 {
1127         if(shader->need_update) {
1128                 ShaderGraph *graph = shader->graph;
1129                 ShaderNode *output = (graph)? graph->output(): NULL;
1130
1131                 bool has_bump = (shader->displacement_method != DISPLACE_TRUE) &&
1132                                 output->input("Surface")->link && output->input("Displacement")->link;
1133
1134                 /* finalize */
1135                 shader->graph->finalize(scene,
1136                                         has_bump,
1137                                         shader->has_integrator_dependency,
1138                                         shader->displacement_method == DISPLACE_BOTH);
1139
1140                 current_shader = shader;
1141
1142                 shader->has_surface = false;
1143                 shader->has_surface_emission = false;
1144                 shader->has_surface_transparent = false;
1145                 shader->has_surface_bssrdf = false;
1146                 shader->has_bump = has_bump;
1147                 shader->has_bssrdf_bump = has_bump;
1148                 shader->has_volume = false;
1149                 shader->has_displacement = false;
1150                 shader->has_surface_spatial_varying = false;
1151                 shader->has_volume_spatial_varying = false;
1152                 shader->has_object_dependency = false;
1153                 shader->has_attribute_dependency = false;
1154                 shader->has_integrator_dependency = false;
1155
1156                 /* generate surface shader */
1157                 if(shader->used && graph && output->input("Surface")->link) {
1158                         shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
1159
1160                         if(has_bump)
1161                                 shader->osl_surface_bump_ref = compile_type(shader, shader->graph, SHADER_TYPE_BUMP);
1162                         else
1163                                 shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
1164
1165                         shader->has_surface = true;
1166                 }
1167                 else {
1168                         shader->osl_surface_ref = OSL::ShaderGroupRef();
1169                         shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
1170                 }
1171
1172                 /* generate volume shader */
1173                 if(shader->used && graph && output->input("Volume")->link) {
1174                         shader->osl_volume_ref = compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
1175                         shader->has_volume = true;
1176                 }
1177                 else
1178                         shader->osl_volume_ref = OSL::ShaderGroupRef();
1179
1180                 /* generate displacement shader */
1181                 if(shader->used && graph && output->input("Displacement")->link) {
1182                         shader->osl_displacement_ref = compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
1183                         shader->has_displacement = true;
1184                 }
1185                 else
1186                         shader->osl_displacement_ref = OSL::ShaderGroupRef();
1187         }
1188
1189         /* push state to array for lookup */
1190         og->surface_state.push_back(shader->osl_surface_ref);
1191         og->volume_state.push_back(shader->osl_volume_ref);
1192         og->displacement_state.push_back(shader->osl_displacement_ref);
1193         og->bump_state.push_back(shader->osl_surface_bump_ref);
1194 }
1195
1196 #else
1197
1198 void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/)
1199 {
1200 }
1201
1202 void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/)
1203 {
1204 }
1205
1206 void OSLCompiler::parameter(const char * /*name*/, float /*f*/)
1207 {
1208 }
1209
1210 void OSLCompiler::parameter_color(const char * /*name*/, float3 /*f*/)
1211 {
1212 }
1213
1214 void OSLCompiler::parameter_vector(const char * /*name*/, float3 /*f*/)
1215 {
1216 }
1217
1218 void OSLCompiler::parameter_point(const char * /*name*/, float3 /*f*/)
1219 {
1220 }
1221
1222 void OSLCompiler::parameter_normal(const char * /*name*/, float3 /*f*/)
1223 {
1224 }
1225
1226 void OSLCompiler::parameter(const char * /*name*/, int /*f*/)
1227 {
1228 }
1229
1230 void OSLCompiler::parameter(const char * /*name*/, const char * /*s*/)
1231 {
1232 }
1233
1234 void OSLCompiler::parameter(const char * /*name*/, ustring /*s*/)
1235 {
1236 }
1237
1238 void OSLCompiler::parameter(const char * /*name*/, const Transform& /*tfm*/)
1239 {
1240 }
1241
1242 void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], int /*arraylen*/)
1243 {
1244 }
1245
1246 void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float3>& /*f*/)
1247 {
1248 }
1249
1250 #endif /* WITH_OSL */
1251
1252 CCL_NAMESPACE_END