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