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