Blender V5.0
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(scene->shader_manager->get_scene_linear_space());
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,
151 Progress &progress,
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(ShaderManager::SceneLinearSpace colorspace)
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, colorspace](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 /* OSL doesn't accept an arbitrary space, so support a few specific spaces. */
388 switch (colorspace) {
390 ss->attribute("colorspace", OSL::Strings::Rec709);
391 break;
393 ss->attribute("colorspace", OSL::Strings::HDTV);
394 break;
396 ss->attribute("colorspace", OSL::Strings::ACEScg);
397 break;
399 break;
400 }
401
402 const char *groupdata_alloc_str = getenv("CYCLES_OSL_GROUPDATA_ALLOC");
403 if (groupdata_alloc_str) {
404 ss->attribute("max_optix_groupdata_alloc", atoi(groupdata_alloc_str));
405 }
406 else {
407 ss->attribute("max_optix_groupdata_alloc", 2048);
408 }
409
410 LOG_INFO << "Using shader search path: " << shader_path;
411
412 /* our own ray types */
413 static const char *raytypes[] = {
414 "camera", /* PATH_RAY_CAMERA */
415 "reflection", /* PATH_RAY_REFLECT */
416 "refraction", /* PATH_RAY_TRANSMIT */
417 "diffuse", /* PATH_RAY_DIFFUSE */
418 "glossy", /* PATH_RAY_GLOSSY */
419 "singular", /* PATH_RAY_SINGULAR */
420 "transparent", /* PATH_RAY_TRANSPARENT */
421 "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
422 "importance_bake", /* PATH_RAY_IMPORTANCE_BAKE */
423
424 "shadow", /* PATH_RAY_SHADOW_OPAQUE */
425 "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
426
427 "__unused__", /* PATH_RAY_NODE_UNALIGNED */
428 "__unused__", /* PATH_RAY_MIS_SKIP */
429
430 "diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
431
432 /* Remaining irrelevant bits up to 32. */
433 "__unused__",
434 "__unused__",
435 "__unused__",
436 "__unused__",
437 "__unused__",
438 "__unused__",
439 "__unused__",
440 "__unused__",
441 "__unused__",
442 "__unused__",
443 "__unused__",
444 "__unused__",
445 "__unused__",
446 "__unused__",
447 "__unused__",
448 "__unused__",
449 "__unused__",
450 "__unused__",
451 };
452
453 const int nraytypes = sizeof(raytypes) / sizeof(raytypes[0]);
454 ss->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), (const void *)raytypes);
455
457 ss_shared[device_type] = std::move(ss);
458 }
459 ss_map[device_type] = ss_shared[device_type];
460 });
461}
462
463void OSLManager::shading_system_free()
464{
465 ss_map.clear();
466
467 /* if ss_shared is the only reference to the underlying shading system,
468 * no users remain, so free it. */
469 const thread_scoped_lock lock(ss_shared_mutex);
470 for (auto &[device_type, ss] : ss_shared) {
471 if (ss.use_count() == 1) {
472 ss.reset();
473 }
474 }
475
476 loaded_shaders.clear();
477}
478
479bool OSLManager::osl_compile(const string &inputfile, const string &outputfile)
480{
481 vector<string> options;
482 string stdosl_path;
483 const string shader_path = path_get("shader");
484
485 /* Specify output file name. */
486 options.push_back("-o");
487 options.push_back(outputfile);
488
489 /* Specify standard include path. */
490 const string include_path_arg = string("-I") + shader_path;
491 options.push_back(include_path_arg);
492
493 stdosl_path = path_join(shader_path, "stdcycles.h");
494
495 /* Compile.
496 *
497 * Mutex protected because the OSL compiler does not appear to be thread safe, see #92503. */
498 static thread_mutex osl_compiler_mutex;
499 const thread_scoped_lock lock(osl_compiler_mutex);
500
501 OSL::OSLCompiler compiler = OSL::OSLCompiler(&OSL::ErrorHandler::default_handler());
502 const bool ok = compiler.compile(string_view(inputfile), options, string_view(stdosl_path));
503
504 return ok;
505}
506
507bool OSLManager::osl_query(OSL::OSLQuery &query, const string &filepath)
508{
509 const string searchpath = path_user_get("shaders");
510 return query.open(filepath, searchpath);
511}
512
513static string shader_filepath_hash(const string &filepath, const uint64_t modified_time)
514{
515 /* compute a hash from filepath and modified time to detect changes */
516 MD5Hash md5;
517 md5.append((const uint8_t *)filepath.c_str(), filepath.size());
518 md5.append((const uint8_t *)&modified_time, sizeof(modified_time));
519
520 return md5.get_hex();
521}
522
523const char *OSLManager::shader_test_loaded(const string &hash)
524{
525 const map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
526 return (it == loaded_shaders.end()) ? nullptr : it->first.c_str();
527}
528
529OSLShaderInfo *OSLManager::shader_loaded_info(const string &hash)
530{
531 const map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
532 return (it == loaded_shaders.end()) ? nullptr : &it->second;
533}
534
535const char *OSLManager::shader_load_filepath(string filepath)
536{
537 const size_t len = filepath.size();
538 const string extension = filepath.substr(len - 4);
539 uint64_t modified_time = path_modified_time(filepath);
540
541 if (extension == ".osl") {
542 /* .OSL File */
543 const string osopath = filepath.substr(0, len - 4) + ".oso";
544 const uint64_t oso_modified_time = path_modified_time(osopath);
545
546 /* test if we have loaded the corresponding .OSO already */
547 if (oso_modified_time != 0) {
548 const char *hash = shader_test_loaded(shader_filepath_hash(osopath, oso_modified_time));
549
550 if (hash) {
551 return hash;
552 }
553 }
554
555 /* Auto-compile .OSL to .OSO if needed. */
556 if (oso_modified_time == 0 || (oso_modified_time < modified_time)) {
557 OSLManager::osl_compile(filepath, osopath);
558 modified_time = path_modified_time(osopath);
559 }
560 else {
561 modified_time = oso_modified_time;
562 }
563
564 filepath = osopath;
565 }
566 else {
567 if (extension == ".oso") {
568 /* .OSO File, nothing to do */
569 }
570 else if (path_dirname(filepath).empty()) {
571 /* .OSO File in search path */
572 filepath = path_join(path_user_get("shaders"), filepath + ".oso");
573 }
574 else {
575 /* unknown file */
576 return nullptr;
577 }
578
579 /* test if we have loaded this .OSO already */
580 const char *hash = shader_test_loaded(shader_filepath_hash(filepath, modified_time));
581
582 if (hash) {
583 return hash;
584 }
585 }
586
587 /* read oso bytecode from file */
588 const string bytecode_hash = shader_filepath_hash(filepath, modified_time);
589 string bytecode;
590
591 if (!path_read_text(filepath, bytecode)) {
592 LOG_ERROR << "Shader graph: failed to read file " << filepath;
593 const OSLShaderInfo info;
594 loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */
595 return nullptr;
596 }
597
598 return shader_load_bytecode(bytecode_hash, bytecode);
599}
600
601const char *OSLManager::shader_load_bytecode(const string &hash, const string &bytecode)
602{
603 foreach_shading_system(
604 [hash, bytecode](OSL::ShadingSystem *ss) { ss->LoadMemoryCompiledShader(hash, bytecode); });
605
606 tag_update();
607
608 OSLShaderInfo info;
609
610 if (!info.query.open_bytecode(bytecode)) {
611 LOG_ERROR << "OSL query error: " << info.query.geterror();
612 }
613
614 /* this is a bit weak, but works */
615 info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
616 info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
617 info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
618
619 loaded_shaders[hash] = info;
620
621 return loaded_shaders.find(hash)->first.c_str();
622}
623
624uint64_t OSLShaderManager::get_attribute_id(ustring name)
625{
626 return name.hash();
627}
628
629uint64_t OSLShaderManager::get_attribute_id(AttributeStandard std)
630{
631 /* if standard attribute, use geom: name convention */
632 const ustring stdname(string("geom:") + string(Attribute::standard_name(std)));
633 return stdname.hash();
634}
635
636void OSLShaderManager::device_update_specific(Device *device,
637 DeviceScene *dscene,
638 Scene *scene,
639 Progress &progress)
640{
641 if (!need_update()) {
642 return;
643 }
644
645 scoped_callback_timer timer([scene](double time) {
646 if (scene->update_stats) {
647 scene->update_stats->osl.times.add_entry({"device_update", time});
648 }
649 });
650
651 LOG_INFO << "Total " << scene->shaders.size() << " shaders.";
652
653 /* setup shader engine */
654 OSLManager::foreach_osl_device(device, [scene](Device *sub_device, OSLGlobals *og) {
655 OSL::ShadingSystem *ss = scene->osl_manager->get_shading_system(sub_device);
656 og->ss = ss;
657 og->ts = scene->osl_manager->get_texture_system();
658 og->services = static_cast<OSLRenderServices *>(ss->renderer());
659
660 og->use_shading = true;
661
662 og->surface_state.clear();
663 og->volume_state.clear();
664 og->displacement_state.clear();
665 og->bump_state.clear();
666 og->background_state.reset();
667 });
668
669 /* create shaders */
670 Shader *background_shader = scene->background->get_shader(scene);
671
672 /* compile each shader to OSL shader groups */
674 for (Shader *shader : scene->shaders) {
675 assert(shader->graph);
676
677 auto compile = [scene, shader, background_shader](Device *sub_device, OSLGlobals *) {
678 OSL::ShadingSystem *ss = scene->osl_manager->get_shading_system(sub_device);
679
680 OSLCompiler compiler(ss, scene, sub_device);
681 compiler.background = (shader == background_shader);
682 compiler.compile(shader);
683 };
684
685 task_pool.push([device, compile] { OSLManager::foreach_osl_device(device, compile); });
686 }
687 task_pool.wait_work();
688
689 if (progress.get_cancel()) {
690 return;
691 }
692
693 /* collect shader groups from all shaders */
694 for (Shader *shader : scene->shaders) {
695 OSLManager::OSLManager::foreach_osl_device(
696 device, [shader, background_shader](Device *sub_device, OSLGlobals *og) {
697 /* push state to array for lookup */
698 const Shader::OSLCache &cache = shader->osl_cache[sub_device];
699 og->surface_state.push_back(cache.surface);
700 og->volume_state.push_back(cache.volume);
701 og->displacement_state.push_back(cache.displacement);
702 og->bump_state.push_back(cache.bump);
703
704 if (shader == background_shader) {
705 og->background_state = cache.surface;
706 }
707 });
708
710 scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
711 }
712
713 scene->osl_manager->tag_update();
714 }
715
716 /* set background shader */
717 int background_id = scene->shader_manager->get_shader_id(background_shader);
718
719 OSLManager::foreach_osl_device(device, [background_id](Device *, OSLGlobals *og) {
720 og->background_state = og->surface_state[background_id & SHADER_MASK];
721 });
722
723 for (Shader *shader : scene->shaders) {
724 shader->clear_modified();
725 }
726
727 update_flags = UPDATE_NONE;
728
729 device_update_common(device, dscene, scene, progress);
730}
731
732void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
733{
734 device_free_common(device, dscene, scene);
735
736 /* clear shader engine */
737 OSLManager::foreach_osl_device(device, [](Device *, OSLGlobals *og) {
738 og->use_shading = false;
739
740 og->surface_state.clear();
741 og->volume_state.clear();
742 og->displacement_state.clear();
743 og->bump_state.clear();
744 og->background_state.reset();
745 });
746}
747
748/* This is a static function to avoid RTTI link errors with only this
749 * file being compiled without RTTI to match OSL and LLVM libraries. */
750OSLNode *OSLShaderManager::osl_node(ShaderGraph *graph,
751 Scene *scene,
752 const std::string &filepath,
753 const std::string &bytecode_hash,
754 const std::string &bytecode)
755{
756 if (!scene->shader_manager->use_osl()) {
757 return nullptr;
758 }
759
760 /* Ensure shading system exists before we try to load a shader. */
761 scene->osl_manager->shading_system_init(scene->shader_manager->get_scene_linear_space());
762
763 /* Load shader code. */
764 const char *hash;
765
766 if (!filepath.empty()) {
767 hash = scene->osl_manager->shader_load_filepath(filepath);
768 }
769 else {
770 hash = scene->osl_manager->shader_test_loaded(bytecode_hash);
771 if (!hash) {
772 hash = scene->osl_manager->shader_load_bytecode(bytecode_hash, bytecode);
773 }
774 }
775
776 if (!hash) {
777 return nullptr;
778 }
779
780 OSLShaderInfo *info = scene->osl_manager->shader_loaded_info(hash);
781
782 /* count number of inputs */
783 size_t num_inputs = 0;
784
785 for (int i = 0; i < info->query.nparams(); i++) {
786 const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
787
788 /* skip unsupported types */
789 if (param->varlenarray || param->isstruct || param->type.arraylen > 1) {
790 continue;
791 }
792
793 if (!param->isoutput) {
794 num_inputs++;
795 }
796 }
797
798 /* create node */
799 OSLNode *node = OSLNode::create(graph, num_inputs);
800
801 /* add new sockets from parameters */
802 const set<void *> used_sockets;
803
804 for (int i = 0; i < info->query.nparams(); i++) {
805 const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
806
807 /* skip unsupported types */
808 if (param->varlenarray || param->isstruct || param->type.arraylen > 1) {
809 continue;
810 }
811
812 SocketType::Type socket_type;
813
814 /* Read type and default value. */
815 if (param->isclosure) {
816 socket_type = SocketType::CLOSURE;
817 }
818 else if (param->type.vecsemantics != TypeDesc::NOSEMANTICS) {
819 if (param->type.vecsemantics == TypeDesc::COLOR) {
820 socket_type = SocketType::COLOR;
821 }
822 else if (param->type.vecsemantics == TypeDesc::POINT) {
823 socket_type = SocketType::POINT;
824 }
825 else if (param->type.vecsemantics == TypeDesc::VECTOR) {
826 socket_type = SocketType::VECTOR;
827 }
828 else if (param->type.vecsemantics == TypeDesc::NORMAL) {
829 socket_type = SocketType::NORMAL;
830 }
831 else {
832 continue;
833 }
834
835 if (!param->isoutput && param->validdefault) {
836 float3 *default_value = (float3 *)node->input_default_value();
837 default_value->x = param->fdefault[0];
838 default_value->y = param->fdefault[1];
839 default_value->z = param->fdefault[2];
840 }
841 }
842 else if (param->type.aggregate == TypeDesc::SCALAR) {
843 if (param->type.basetype == TypeDesc::INT) {
844 socket_type = SocketType::INT;
845
846 if (!param->isoutput && param->validdefault) {
847 *(int *)node->input_default_value() = param->idefault[0];
848 }
849 }
850 else if (param->type.basetype == TypeDesc::FLOAT) {
851 socket_type = SocketType::FLOAT;
852
853 if (!param->isoutput && param->validdefault) {
854 *(float *)node->input_default_value() = param->fdefault[0];
855 }
856 }
857 else if (param->type.basetype == TypeDesc::STRING) {
858 socket_type = SocketType::STRING;
859
860 if (!param->isoutput && param->validdefault) {
861 *(ustring *)node->input_default_value() = param->sdefault[0];
862 }
863 }
864 else {
865 continue;
866 }
867 }
868 else {
869 continue;
870 }
871
872 if (param->isoutput) {
873 node->add_output(param->name, socket_type);
874 }
875 else {
876 /* Detect if we should leave parameter initialization to OSL, either though
877 * not constant default or widget metadata. */
878 int socket_flags = 0;
879 if (!param->validdefault) {
880 socket_flags |= SocketType::LINK_OSL_INITIALIZER;
881 }
882 for (const OSL::OSLQuery::Parameter &metadata : param->metadata) {
883 if (metadata.type == TypeDesc::STRING) {
884 if (metadata.name == "widget" && metadata.sdefault[0] == "null") {
885 socket_flags |= SocketType::LINK_OSL_INITIALIZER;
886 }
887 else if (metadata.name == "defaultgeomprop") {
888 /* the following match up to MaterialX default geometry properties
889 * that we use to help set socket flags to the corresponding
890 * geometry link equivalents. */
891 if (metadata.sdefault[0] == "Nobject") {
892 socket_flags |= SocketType::LINK_TEXTURE_NORMAL;
893 }
894 else if (metadata.sdefault[0] == "Nworld") {
895 socket_flags |= SocketType::LINK_NORMAL;
896 }
897 else if (metadata.sdefault[0] == "Pobject") {
899 }
900 else if (metadata.sdefault[0] == "Pworld") {
901 socket_flags |= SocketType::LINK_POSITION;
902 }
903 else if (metadata.sdefault[0] == "Tworld") {
904 socket_flags |= SocketType::LINK_TANGENT;
905 }
906 else if (metadata.sdefault[0] == "UV0") {
907 socket_flags |= SocketType::LINK_TEXTURE_UV;
908 }
909 }
910 }
911 }
912
913 node->add_input(param->name, socket_type, socket_flags);
914 }
915 }
916
917 /* Set byte-code hash or file-path. */
918 if (!bytecode_hash.empty()) {
919 node->bytecode_hash = bytecode_hash;
920 }
921 else {
922 node->filepath = filepath;
923 }
924
925 /* Generate inputs and outputs */
926 node->create_inputs_outputs(node->type);
927
928 return node;
929}
930
931/* Static function, so only this file needs to be compile with RTTT. */
932void OSLShaderManager::osl_image_slots(Device *device,
933 ImageManager *image_manager,
934 set<int> &image_slots)
935{
936 set<OSLRenderServices *> services_shared;
937 device->foreach_device([&services_shared](Device *sub_device) {
938 OSLGlobals *og = sub_device->get_cpu_osl_memory();
939 services_shared.insert(og->services);
940 });
941
942 for (OSLRenderServices *services : services_shared) {
943 for (auto it = services->textures.begin(); it != services->textures.end(); ++it) {
944 if (it->second.handle.get_manager() == image_manager) {
945 const int slot = it->second.handle.svm_slot();
946 image_slots.insert(slot);
947 }
948 }
949 }
950}
951
952/* Graph Compiler */
953
954OSLCompiler::OSLCompiler(OSL::ShadingSystem *ss, Scene *scene, Device *device)
955 : scene(scene),
956 services(static_cast<OSLRenderServices *>(ss->renderer())),
957 ss(ss),
958 device(device)
959{
960 current_type = SHADER_TYPE_SURFACE;
961 current_shader = nullptr;
962 background = false;
963}
964
965string OSLCompiler::id(ShaderNode *node)
966{
967 /* assign layer unique name based on pointer address + bump mode */
968 std::stringstream stream;
969
970 /* Ensure that no grouping characters (e.g. commas with en_US locale)
971 * are added to the pointer string. */
972 stream.imbue(std::locale("C"));
973
974 stream << "node_" << node->type->name << "_" << node;
975
976 return stream.str();
977}
978
979string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
980{
981 string sname(input->name().string());
982 size_t i;
983
984 /* Strip white-space. */
985 while ((i = sname.find(" ")) != string::npos) {
986 sname.replace(i, 1, "");
987 }
988
989 /* if output exists with the same name, add "In" suffix */
990 for (ShaderOutput *output : node->outputs) {
991 if (input->name() == output->name()) {
992 sname += "In";
993 break;
994 }
995 }
996
997 return sname;
998}
999
1000string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
1001{
1002 string sname(output->name().string());
1003 size_t i;
1004
1005 /* Strip white-space. */
1006 while ((i = sname.find(" ")) != string::npos) {
1007 sname.replace(i, 1, "");
1008 }
1009
1010 /* if input exists with the same name, add "Out" suffix */
1011 for (ShaderInput *input : node->inputs) {
1012 if (input->name() == output->name()) {
1013 sname += "Out";
1014 break;
1015 }
1016 }
1017
1018 return sname;
1019}
1020
1021bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
1022{
1023 /* exception for output node, only one input is actually used
1024 * depending on the current shader type */
1025
1026 if (input->flags() & SocketType::SVM_INTERNAL) {
1027 return true;
1028 }
1029
1031 if (input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE) {
1032 return true;
1033 }
1034 if (input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME) {
1035 return true;
1036 }
1037 if (input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT) {
1038 return true;
1039 }
1040 if (input->name() == "Normal" && current_type != SHADER_TYPE_BUMP) {
1041 return true;
1042 }
1043 }
1044 else if (node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
1045 if (input->name() == "Height") {
1046 return true;
1047 }
1048 }
1049 else if (current_type == SHADER_TYPE_DISPLACEMENT && input->link &&
1050 input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
1051 {
1052 return true;
1053 }
1054
1055 return false;
1056}
1057
1058void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
1059{
1060 /* load filepath */
1061 if (isfilepath) {
1062 name = scene->osl_manager->shader_load_filepath(name);
1063
1064 if (name == nullptr) {
1065 return;
1066 }
1067 }
1068
1069 /* pass in fixed parameter values */
1070 for (ShaderInput *input : node->inputs) {
1071 if (!input->link) {
1072 /* checks to untangle graphs */
1073 if (node_skip_input(node, input)) {
1074 continue;
1075 }
1076 if ((input->flags() & SocketType::LINK_OSL_INITIALIZER) && !(input->constant_folded_in)) {
1077 continue;
1078 }
1079
1080 const string param_name = compatible_name(node, input);
1081 const SocketType &socket = input->socket_type;
1082 switch (input->type()) {
1083 case SocketType::COLOR:
1084 parameter_color(param_name.c_str(), node->get_float3(socket));
1085 break;
1086 case SocketType::POINT:
1087 parameter_point(param_name.c_str(), node->get_float3(socket));
1088 break;
1089 case SocketType::VECTOR:
1090 parameter_vector(param_name.c_str(), node->get_float3(socket));
1091 break;
1092 case SocketType::NORMAL:
1093 parameter_normal(param_name.c_str(), node->get_float3(socket));
1094 break;
1095 case SocketType::FLOAT:
1096 parameter(param_name.c_str(), node->get_float(socket));
1097 break;
1098 case SocketType::INT:
1099 parameter(param_name.c_str(), node->get_int(socket));
1100 break;
1101 case SocketType::STRING:
1102 parameter(param_name.c_str(), node->get_string(socket));
1103 break;
1106 default:
1107 break;
1108 }
1109 }
1110 }
1111
1112 /* Create shader of the appropriate type. OSL only distinguishes between "surface"
1113 * and "displacement" at the moment. */
1114 if (current_type == SHADER_TYPE_SURFACE) {
1115 ss->Shader(*current_group, "surface", name, id(node));
1116 }
1117 else if (current_type == SHADER_TYPE_VOLUME) {
1118 ss->Shader(*current_group, "surface", name, id(node));
1119 }
1120 else if (current_type == SHADER_TYPE_DISPLACEMENT) {
1121 ss->Shader(*current_group, "displacement", name, id(node));
1122 }
1123 else if (current_type == SHADER_TYPE_BUMP) {
1124 ss->Shader(*current_group, "displacement", name, id(node));
1125 }
1126 else {
1127 assert(0);
1128 }
1129
1130 /* link inputs to other nodes */
1131 for (ShaderInput *input : node->inputs) {
1132 if (input->link) {
1133 if (node_skip_input(node, input)) {
1134 continue;
1135 }
1136
1137 /* connect shaders */
1138 const string id_from = id(input->link->parent);
1139 const string id_to = id(node);
1140 const string param_from = compatible_name(input->link->parent, input->link);
1141 const string param_to = compatible_name(node, input);
1142
1143 ss->ConnectShaders(*current_group, id_from, param_from, id_to, param_to);
1144 }
1145 }
1146
1147 /* test if we shader contains specific closures */
1148 OSLShaderInfo *info = scene->osl_manager->shader_loaded_info(name);
1149
1150 if (current_type == SHADER_TYPE_SURFACE) {
1151 if (info) {
1152 if (info->has_surface_emission && node->special_type == SHADER_SPECIAL_TYPE_OSL) {
1153 /* Will be used by Shader::estimate_emission. */
1154 OSLNode *oslnode = static_cast<OSLNode *>(node);
1155 oslnode->has_emission = true;
1156 }
1157 if (info->has_surface_transparent) {
1158 current_shader->has_surface_transparent = true;
1159 }
1160 if (info->has_surface_bssrdf) {
1161 current_shader->has_surface_bssrdf = true;
1162 current_shader->has_bssrdf_bump = true; /* can't detect yet */
1163 }
1164 current_shader->has_bump = true; /* can't detect yet */
1165 current_shader->has_surface_raytrace = true; /* can't detect yet */
1166 }
1167
1168 if (node->has_spatial_varying()) {
1169 current_shader->has_surface_spatial_varying = true;
1170 }
1171 }
1172 else if (current_type == SHADER_TYPE_VOLUME) {
1173 if (node->has_spatial_varying()) {
1174 current_shader->has_volume_spatial_varying = true;
1175 }
1176 if (node->has_attribute_dependency()) {
1177 current_shader->has_volume_attribute_dependency = true;
1178 }
1179 }
1180}
1181
1182static TypeDesc array_typedesc(const TypeDesc typedesc, const int arraylength)
1183{
1184 return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype,
1185 (TypeDesc::AGGREGATE)typedesc.aggregate,
1186 (TypeDesc::VECSEMANTICS)typedesc.vecsemantics,
1187 arraylength);
1188}
1189
1190void OSLCompiler::parameter(ShaderNode *node, const char *name)
1191{
1192 const ustring uname = ustring(name);
1193 const SocketType &socket = *(node->type->find_input(uname));
1194
1195 switch (socket.type) {
1196 case SocketType::BOOLEAN: {
1197 int value = node->get_bool(socket);
1198 ss->Parameter(*current_group, name, TypeInt, &value);
1199 break;
1200 }
1201 case SocketType::FLOAT: {
1202 float value = node->get_float(socket);
1203 ss->Parameter(*current_group, uname, TypeFloat, &value);
1204 break;
1205 }
1206 case SocketType::INT: {
1207 int value = node->get_int(socket);
1208 ss->Parameter(*current_group, uname, TypeInt, &value);
1209 break;
1210 }
1211 case SocketType::COLOR: {
1212 float3 value = node->get_float3(socket);
1213 ss->Parameter(*current_group, uname, TypeColor, &value);
1214 break;
1215 }
1216 case SocketType::VECTOR: {
1217 float3 value = node->get_float3(socket);
1218 ss->Parameter(*current_group, uname, TypeVector, &value);
1219 break;
1220 }
1221 case SocketType::POINT: {
1222 float3 value = node->get_float3(socket);
1223 ss->Parameter(*current_group, uname, TypePoint, &value);
1224 break;
1225 }
1226 case SocketType::NORMAL: {
1227 float3 value = node->get_float3(socket);
1228 ss->Parameter(*current_group, uname, TypeNormal, &value);
1229 break;
1230 }
1231 case SocketType::POINT2: {
1232 float2 value = node->get_float2(socket);
1233 ss->Parameter(*current_group,
1234 uname,
1235 TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT),
1236 &value);
1237 break;
1238 }
1239 case SocketType::STRING: {
1240 ustring value = node->get_string(socket);
1241 ss->Parameter(*current_group, uname, TypeString, &value);
1242 break;
1243 }
1244 case SocketType::ENUM: {
1245 ustring value = node->get_string(socket);
1246 ss->Parameter(*current_group, uname, TypeString, &value);
1247 break;
1248 }
1249 case SocketType::TRANSFORM: {
1250 const Transform value = node->get_transform(socket);
1251 ProjectionTransform projection(value);
1252 projection = projection_transpose(projection);
1253 ss->Parameter(*current_group, uname, TypeMatrix, &projection);
1254 break;
1255 }
1257 // OSL does not support booleans, so convert to int
1258 const array<bool> &value = node->get_bool_array(socket);
1259 array<int> intvalue(value.size());
1260 for (size_t i = 0; i < value.size(); i++) {
1261 intvalue[i] = value[i];
1262 }
1263 ss->Parameter(*current_group, uname, array_typedesc(TypeInt, value.size()), intvalue.data());
1264 break;
1265 }
1267 const array<float> &value = node->get_float_array(socket);
1268 ss->Parameter(*current_group, uname, array_typedesc(TypeFloat, value.size()), value.data());
1269 break;
1270 }
1271 case SocketType::INT_ARRAY: {
1272 const array<int> &value = node->get_int_array(socket);
1273 ss->Parameter(*current_group, uname, array_typedesc(TypeInt, value.size()), value.data());
1274 break;
1275 }
1280 TypeDesc typedesc;
1281
1282 switch (socket.type) {
1284 typedesc = TypeColor;
1285 break;
1287 typedesc = TypeVector;
1288 break;
1290 typedesc = TypePoint;
1291 break;
1293 typedesc = TypeNormal;
1294 break;
1295 default:
1296 assert(0);
1297 break;
1298 }
1299
1300 // convert to tightly packed array since float3 has padding
1301 const array<float3> &value = node->get_float3_array(socket);
1302 array<float> fvalue(value.size() * 3);
1303 for (size_t i = 0, j = 0; i < value.size(); i++) {
1304 fvalue[j++] = value[i].x;
1305 fvalue[j++] = value[i].y;
1306 fvalue[j++] = value[i].z;
1307 }
1308
1309 ss->Parameter(*current_group, uname, array_typedesc(typedesc, value.size()), fvalue.data());
1310 break;
1311 }
1313 const array<float2> &value = node->get_float2_array(socket);
1314 ss->Parameter(
1315 *current_group,
1316 uname,
1317 array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()),
1318 value.data());
1319 break;
1320 }
1322 const array<ustring> &value = node->get_string_array(socket);
1323 ss->Parameter(*current_group, uname, array_typedesc(TypeString, value.size()), value.data());
1324 break;
1325 }
1327 const array<Transform> &value = node->get_transform_array(socket);
1328 array<ProjectionTransform> fvalue(value.size());
1329 for (size_t i = 0; i < value.size(); i++) {
1330 fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
1331 }
1332 ss->Parameter(
1333 *current_group, uname, array_typedesc(TypeMatrix, fvalue.size()), fvalue.data());
1334 break;
1335 }
1337 case SocketType::NODE:
1339 case SocketType::UINT:
1340 case SocketType::UINT64:
1342 case SocketType::NUM_TYPES: {
1343 assert(0);
1344 break;
1345 }
1346 }
1347}
1348
1349void OSLCompiler::parameter(const char *name, const float f)
1350{
1351 ss->Parameter(*current_group, name, TypeFloat, &f);
1352}
1353
1354void OSLCompiler::parameter_color(const char *name, const float3 f)
1355{
1356 ss->Parameter(*current_group, name, TypeColor, &f);
1357}
1358
1359void OSLCompiler::parameter_point(const char *name, const float3 f)
1360{
1361 ss->Parameter(*current_group, name, TypePoint, &f);
1362}
1363
1364void OSLCompiler::parameter_normal(const char *name, const float3 f)
1365{
1366 ss->Parameter(*current_group, name, TypeNormal, &f);
1367}
1368
1369void OSLCompiler::parameter_vector(const char *name, const float3 f)
1370{
1371 ss->Parameter(*current_group, name, TypeVector, &f);
1372}
1373
1374void OSLCompiler::parameter(const char *name, const int f)
1375{
1376 ss->Parameter(*current_group, name, TypeInt, &f);
1377}
1378
1379void OSLCompiler::parameter(const char *name, const char *s)
1380{
1381 ss->Parameter(*current_group, name, TypeString, (const void *)&s);
1382}
1383
1384void OSLCompiler::parameter(const char *name, ustring s)
1385{
1386 const char *str = s.c_str();
1387 ss->Parameter(*current_group, name, TypeString, (const void *)&str);
1388}
1389
1390void OSLCompiler::parameter(const char *name, const Transform &tfm)
1391{
1392 ProjectionTransform projection(tfm);
1393 projection = projection_transpose(projection);
1394 ss->Parameter(*current_group, name, TypeMatrix, (float *)&projection);
1395}
1396
1397void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
1398{
1399 TypeDesc type = TypeFloat;
1400 type.arraylen = arraylen;
1401 ss->Parameter(*current_group, name, type, f);
1402}
1403
1404void OSLCompiler::parameter_color_array(const char *name, const array<float3> &f)
1405{
1406 /* NOTE: cycles float3 type is actually 4 floats! need to use an explicit array. */
1407 array<float[3]> table(f.size());
1408
1409 for (int i = 0; i < f.size(); ++i) {
1410 table[i][0] = f[i].x;
1411 table[i][1] = f[i].y;
1412 table[i][2] = f[i].z;
1413 }
1414
1415 TypeDesc type = TypeColor;
1416 type.arraylen = table.size();
1417 ss->Parameter(*current_group, name, type, table.data());
1418}
1419
1420void OSLCompiler::parameter_attribute(const char *name, ustring s)
1421{
1422 if (Attribute::name_standard(s.c_str())) {
1423 parameter(name, (string("geom:") + s.c_str()).c_str());
1424 }
1425 else {
1426 parameter(name, s.c_str());
1427 }
1428}
1429
1430void OSLCompiler::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
1431{
1432 ShaderNode *node = (input->link) ? input->link->parent : nullptr;
1433
1434 if (node != nullptr && dependencies.find(node) == dependencies.end()) {
1435 for (ShaderInput *in : node->inputs) {
1436 if (!node_skip_input(node, in)) {
1437 find_dependencies(dependencies, in);
1438 }
1439 }
1440
1441 dependencies.insert(node);
1442 }
1443}
1444
1445void OSLCompiler::generate_nodes(const ShaderNodeSet &nodes)
1446{
1447 ShaderNodeSet done;
1448 bool nodes_done;
1449
1450 do {
1451 nodes_done = true;
1452
1453 for (ShaderNode *node : nodes) {
1454 if (done.find(node) == done.end()) {
1455 bool inputs_done = true;
1456
1457 for (ShaderInput *input : node->inputs) {
1458 if (!node_skip_input(node, input)) {
1459 if (input->link && done.find(input->link->parent) == done.end()) {
1460 inputs_done = false;
1461 }
1462 }
1463 }
1464
1465 if (inputs_done) {
1466 node->compile(*this);
1467 done.insert(node);
1468
1469 if (current_type == SHADER_TYPE_SURFACE) {
1470 if (node->has_surface_transparent()) {
1471 current_shader->has_surface_transparent = true;
1472 }
1474 current_shader->has_surface_raytrace = true;
1475 }
1476 if (node->has_spatial_varying()) {
1477 current_shader->has_surface_spatial_varying = true;
1478 }
1479 if (node->has_surface_bssrdf()) {
1480 current_shader->has_surface_bssrdf = true;
1481 if (node->has_bssrdf_bump()) {
1482 current_shader->has_bssrdf_bump = true;
1483 }
1484 }
1485 if (node->has_bump()) {
1486 current_shader->has_bump = true;
1487 }
1488 }
1489 else if (current_type == SHADER_TYPE_VOLUME) {
1490 if (node->has_spatial_varying()) {
1491 current_shader->has_volume_spatial_varying = true;
1492 }
1493 }
1494 }
1495 else {
1496 nodes_done = false;
1497 }
1498 }
1499 }
1500 } while (!nodes_done);
1501}
1502
1503OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
1504{
1505 current_type = type;
1506
1507 /* Use name hash to identify shader group to avoid issues with non-alphanumeric characters */
1508 std::stringstream name;
1509 name.imbue(std::locale("C"));
1510 name << "shader_" << shader->name.hash();
1511
1512 current_group = ss->ShaderGroupBegin(name.str());
1513
1514 ShaderNode *output = graph->output();
1515 ShaderNodeSet dependencies;
1516
1517 if (type == SHADER_TYPE_SURFACE) {
1518 /* generate surface shader */
1519 find_dependencies(dependencies, output->input("Surface"));
1520 generate_nodes(dependencies);
1521 output->compile(*this);
1522 }
1523 else if (type == SHADER_TYPE_BUMP) {
1524 /* generate bump shader */
1525 find_dependencies(dependencies, output->input("Normal"));
1526 generate_nodes(dependencies);
1527 output->compile(*this);
1528 }
1529 else if (type == SHADER_TYPE_VOLUME) {
1530 /* generate volume shader */
1531 find_dependencies(dependencies, output->input("Volume"));
1532 generate_nodes(dependencies);
1533 output->compile(*this);
1534 }
1535 else if (type == SHADER_TYPE_DISPLACEMENT) {
1536 /* generate displacement shader */
1537 find_dependencies(dependencies, output->input("Displacement"));
1538 generate_nodes(dependencies);
1539 output->compile(*this);
1540 }
1541 else {
1542 assert(0);
1543 }
1544
1545 ss->ShaderGroupEnd(*current_group);
1546
1547 return std::move(current_group);
1548}
1549
1550void OSLCompiler::compile(Shader *shader)
1551{
1552 if (shader->is_modified()) {
1553 ShaderGraph *graph = shader->graph.get();
1554 const bool has_bump = shader->has_bump;
1555
1556 current_shader = shader;
1557
1558 Shader::OSLCache cache;
1559
1560 if (shader->reference_count()) {
1561 if (shader->has_surface) {
1562 cache.surface = compile_type(shader, graph, SHADER_TYPE_SURFACE);
1563 if (has_bump) {
1564 cache.bump = compile_type(shader, graph, SHADER_TYPE_BUMP);
1565 }
1566 }
1567 if (shader->has_volume) {
1568 cache.volume = compile_type(shader, graph, SHADER_TYPE_VOLUME);
1569 }
1570 if (shader->has_displacement) {
1571 cache.displacement = compile_type(shader, graph, SHADER_TYPE_DISPLACEMENT);
1572 }
1573 }
1574
1575 shader->osl_cache[device] = std::move(cache);
1576
1577 /* Estimate emission for MIS. */
1578 shader->estimate_emission();
1579 }
1580}
1581
1582void OSLCompiler::parameter_texture(const char *name, ustring filename, ustring colorspace)
1583{
1584 /* Textured loaded through the OpenImageIO texture cache. For this
1585 * case we need to do runtime color space conversion. */
1586 OSLTextureHandle handle(OSLTextureHandle::OIIO);
1587 handle.processor = ColorSpaceManager::get_processor(colorspace);
1588 services->textures.insert(OSLUStringHash(filename), handle);
1589 parameter(name, filename);
1590}
1591
1592void OSLCompiler::parameter_texture(const char *name, const ImageHandle &handle)
1593{
1594 /* Texture loaded through SVM image texture system. We generate a unique
1595 * name, which ends up being used in OSLRenderServices::get_texture_handle
1596 * to get handle again. Note that this name must be unique between multiple
1597 * render sessions as the render services are shared. */
1598 const ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
1599 services->textures.insert(OSLUStringHash(filename),
1600 OSLTextureHandle(OSLTextureHandle::SVM, handle.get_svm_slots()));
1601 parameter(name, filename);
1602}
1603
1604void OSLCompiler::parameter_texture_ies(const char *name, const int svm_slot)
1605{
1606 /* IES light textures stored in SVM. */
1607 const ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
1608 services->textures.insert(OSLUStringHash(filename),
1609 OSLTextureHandle(OSLTextureHandle::IES, svm_slot));
1610 parameter(name, filename);
1611}
1612
1613#else
1614
1617
1619void OSLManager::reset(Scene * /*scene*/) {}
1620
1621void OSLManager::device_update_pre(Device * /*device*/, Scene * /*scene*/) {}
1623 Scene * /*scene*/,
1624 Progress & /*progress*/,
1625 const bool /*reload_kernels*/)
1626{
1627}
1628void OSLManager::device_free(Device * /*device*/, DeviceScene * /*dscene*/, Scene * /*scene*/) {}
1629
1632{
1633 return false;
1634}
1635
1636void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/) {}
1637
1638void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/) {}
1639
1640void OSLCompiler::parameter(const char * /*name*/, float /*f*/) {}
1641
1642void OSLCompiler::parameter_color(const char * /*name*/, float3 /*f*/) {}
1643
1644void OSLCompiler::parameter_vector(const char * /*name*/, float3 /*f*/) {}
1645
1646void OSLCompiler::parameter_point(const char * /*name*/, float3 /*f*/) {}
1647
1648void OSLCompiler::parameter_normal(const char * /*name*/, float3 /*f*/) {}
1649
1650void OSLCompiler::parameter(const char * /*name*/, int /*f*/) {}
1651
1652void OSLCompiler::parameter(const char * /*name*/, const char * /*s*/) {}
1653
1654void OSLCompiler::parameter(const char * /*name*/, ustring /*s*/) {}
1655
1656void OSLCompiler::parameter(const char * /*name*/, const Transform & /*tfm*/) {}
1657
1658void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], int /*arraylen*/) {}
1659
1660void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float3> & /*f*/) {}
1661
1662void OSLCompiler::parameter_texture(const char * /*name*/,
1663 ustring /*filename*/,
1664 ustring /*colorspace*/)
1665{
1666}
1667
1668void OSLCompiler::parameter_texture(const char * /*name*/, const ImageHandle & /*handle*/) {}
1669
1670void OSLCompiler::parameter_texture_ies(const char * /*name*/, int /*svm_slot*/) {}
1671
1672#endif /* WITH_OSL */
1673
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:268
string get_hex()
Definition md5.cpp:367
void parameter_array(const char *name, const float f[], int arraylen)
Definition osl.cpp:1658
void add(ShaderNode *node, const char *name, bool isfilepath=false)
Definition osl.cpp:1636
void parameter_texture(const char *name, ustring filename, ustring colorspace)
Definition osl.cpp:1662
void parameter(ShaderNode *node, const char *name)
Definition osl.cpp:1638
void compile(Shader *shader)
void parameter_color_array(const char *name, const array< float3 > &f)
Definition osl.cpp:1660
void parameter_texture_ies(const char *name, const int svm_slot)
Definition osl.cpp:1670
void parameter_point(const char *name, const float3 f)
Definition osl.cpp:1646
Scene * scene
Definition scene/osl.h:187
void parameter_vector(const char *name, const float3 f)
Definition osl.cpp:1644
void parameter_attribute(const char *name, ustring s)
void parameter_color(const char *name, const float3 f)
Definition osl.cpp:1642
void parameter_normal(const char *name, const float3 f)
Definition osl.cpp:1648
void reset(Scene *scene)
Definition osl.cpp:1619
~OSLManager()
Definition osl.cpp:1616
void device_free(Device *device, DeviceScene *dscene, Scene *scene)
Definition osl.cpp:1628
void device_update_pre(Device *device, Scene *scene)
Definition osl.cpp:1621
static void free_memory()
Definition osl.cpp:1618
void tag_update()
Definition osl.cpp:1630
void device_update_post(Device *device, Scene *scene, Progress &progress, const bool reload_kernels)
Definition osl.cpp:1622
OSLManager(Device *device)
Definition osl.cpp:1615
bool need_update() const
Definition osl.cpp:1631
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:340
OSLTextureHandleMap textures
Definition services.h:338
static void register_closures(OSL::ShadingSystem *ss)
Definition closures.cpp:68
bool get_cancel() const
Definition progress.h:77
void set_error(const string &error_message_)
Definition progress.h:98
OutputNode * output()
virtual bool has_surface_transparent()
virtual uint get_feature()
ShaderNodeSpecialType special_type
virtual bool has_bssrdf_bump()
virtual bool has_spatial_varying()
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
void estimate_emission()
bool has_volume
bool has_surface
EmissionSampling emission_sampling
bool has_displacement
bool has_bump
NODE_DECLARE unique_ptr< ShaderGraph > graph
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
#define assert(assertion)
#define in
#define output
VecBase< float, 2 > float2
VecBase< float, 3 > float3
@ SHADER_TYPE_BUMP
@ SHADER_TYPE_SURFACE
@ SHADER_TYPE_VOLUME
@ SHADER_TYPE_DISPLACEMENT
AttributeStandard
@ EMISSION_SAMPLING_NONE
@ SHADER_MASK
#define LOG_ERROR
Definition log.h:101
#define LOG_INFO
Definition log.h:106
#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
const char * name
@ 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:125
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:175
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:45
@ TRANSFORM_ARRAY
Definition node_type.h:54
Type type
Definition node_type.h:82
@ LINK_OSL_INITIALIZER
Definition node_type.h:76
@ LINK_TEXTURE_UV
Definition node_type.h:70
@ LINK_TEXTURE_GENERATED
Definition node_type.h:68
@ LINK_TEXTURE_NORMAL
Definition node_type.h:69
@ LINK_POSITION
Definition node_type.h:74
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
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