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