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