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