2023-06-14 16:52:36 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
2011-04-27 11:58:34 +00:00
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 20:39:14 +02:00
|
|
|
#include "device/device.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
#include "scene/background.h"
|
|
|
|
|
#include "scene/colorspace.h"
|
|
|
|
|
#include "scene/light.h"
|
|
|
|
|
#include "scene/osl.h"
|
|
|
|
|
#include "scene/scene.h"
|
|
|
|
|
#include "scene/shader.h"
|
|
|
|
|
#include "scene/shader_graph.h"
|
|
|
|
|
#include "scene/shader_nodes.h"
|
|
|
|
|
#include "scene/stats.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
#ifdef WITH_OSL
|
|
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
# include "kernel/osl/globals.h"
|
|
|
|
|
# include "kernel/osl/services.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2021-10-24 14:19:19 +02:00
|
|
|
# include "util/aligned_malloc.h"
|
|
|
|
|
# include "util/log.h"
|
|
|
|
|
# include "util/md5.h"
|
|
|
|
|
# include "util/path.h"
|
|
|
|
|
# include "util/progress.h"
|
|
|
|
|
# include "util/projection.h"
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
# include "util/task.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_OSL
|
|
|
|
|
|
2013-04-22 14:27:12 +00:00
|
|
|
/* Shared Texture and Shading System */
|
2013-04-04 23:48:07 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
std::shared_ptr<OSL::TextureSystem> ts_shared;
|
|
|
|
|
thread_mutex ts_shared_mutex;
|
2013-04-04 23:48:07 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
map<DeviceType, std::shared_ptr<OSL::ShadingSystem>> ss_shared;
|
|
|
|
|
thread_mutex ss_shared_mutex;
|
|
|
|
|
OSL::ErrorHandler errhandler;
|
2022-11-09 14:25:32 +01:00
|
|
|
|
2025-02-20 16:32:44 +01:00
|
|
|
std::atomic<int> OSLCompiler::texture_shared_unique_id = 0;
|
2013-04-22 14:27:12 +00:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Shader Manager */
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
OSLManager::OSLManager(Device *device) : device_(device), need_update_(true) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
OSLManager::~OSLManager()
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2013-04-22 14:27:12 +00:00
|
|
|
shading_system_free();
|
|
|
|
|
texture_system_free();
|
2019-03-13 18:26:11 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::free_memory()
|
2019-03-13 18:26:11 +01:00
|
|
|
{
|
2018-08-27 19:37:55 -06:00
|
|
|
# ifdef OSL_HAS_BLENDER_CLEANUP_FIX
|
2020-10-09 12:12:29 +11:00
|
|
|
/* There is a problem with LLVM+OSL: The order global destructors across
|
2018-08-27 19:37:55 -06:00
|
|
|
* different compilation units run cannot be guaranteed, on windows this means
|
2020-10-09 12:12:29 +11:00
|
|
|
* that the LLVM destructors run before the osl destructors, causing a crash
|
2018-08-27 19:37:55 -06:00
|
|
|
* when the process exits. the OSL in svn has a special cleanup hack to
|
|
|
|
|
* sidestep this behavior */
|
|
|
|
|
OSL::pvt::LLVM_Util::Cleanup();
|
|
|
|
|
# endif
|
2013-02-14 16:11:47 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::reset(Scene * /*scene*/)
|
2013-02-14 16:11:47 +00:00
|
|
|
{
|
2013-04-22 14:27:12 +00:00
|
|
|
shading_system_free();
|
2025-03-04 17:27:10 +01:00
|
|
|
tag_update();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
OSL::TextureSystem *OSLManager::get_texture_system()
|
2022-09-09 11:55:35 +02:00
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
if (!ts) {
|
|
|
|
|
texture_system_init();
|
|
|
|
|
}
|
|
|
|
|
return ts.get();
|
2022-09-09 11:55:35 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
OSL::ShadingSystem *OSLManager::get_shading_system(Device *sub_device)
|
2022-09-09 11:55:35 +02:00
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
return ss_map[sub_device->info.type].get();
|
2022-09-09 11:55:35 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::foreach_shading_system(const std::function<void(OSL::ShadingSystem *)> &callback)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
for (const auto &[device_type, ss] : ss_map) {
|
|
|
|
|
callback(ss.get());
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2025-03-04 17:27:10 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::foreach_render_services(const std::function<void(OSLRenderServices *)> &callback)
|
|
|
|
|
{
|
|
|
|
|
for (const auto &[device_type, ss] : ss_map) {
|
|
|
|
|
callback(static_cast<OSLRenderServices *>(ss->renderer()));
|
2022-11-09 14:25:32 +01:00
|
|
|
}
|
2025-03-04 17:27:10 +01:00
|
|
|
}
|
2012-10-30 11:51:17 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::foreach_osl_device(Device *device,
|
|
|
|
|
const std::function<void(Device *, OSLGlobals *)> &callback)
|
|
|
|
|
{
|
|
|
|
|
device->foreach_device([callback](Device *sub_device) {
|
|
|
|
|
OSLGlobals *og = sub_device->get_cpu_osl_memory();
|
|
|
|
|
if (og != nullptr) {
|
|
|
|
|
callback(sub_device, og);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::tag_update()
|
|
|
|
|
{
|
|
|
|
|
need_update_ = true;
|
|
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
bool OSLManager::need_update() const
|
|
|
|
|
{
|
|
|
|
|
return need_update_;
|
|
|
|
|
}
|
2013-04-22 14:27:12 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::device_update_pre(Device *device, Scene *scene)
|
|
|
|
|
{
|
|
|
|
|
if (!need_update()) {
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
/* set texture system (only on CPU devices, since GPU devices cannot use OIIO) */
|
|
|
|
|
if (scene->shader_manager->use_osl()) {
|
|
|
|
|
shading_system_init();
|
|
|
|
|
|
|
|
|
|
/* add special builtin texture types */
|
|
|
|
|
foreach_render_services([](OSLRenderServices *services) {
|
|
|
|
|
services->textures.insert(OSLUStringHash("@ao"), OSLTextureHandle(OSLTextureHandle::AO));
|
|
|
|
|
services->textures.insert(OSLUStringHash("@bevel"),
|
|
|
|
|
OSLTextureHandle(OSLTextureHandle::BEVEL));
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
});
|
2012-12-12 06:51:06 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
if (device->info.type == DEVICE_CPU) {
|
|
|
|
|
scene->image_manager->set_osl_texture_system((void *)get_texture_system());
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2025-03-04 17:27:10 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::device_update_post(Device *device, Scene *scene, Progress &progress)
|
|
|
|
|
{
|
|
|
|
|
if (!need_update())
|
|
|
|
|
return;
|
2021-10-21 14:52:34 +02:00
|
|
|
|
2013-06-28 13:05:21 +00:00
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
scoped_callback_timer timer([scene](double time) {
|
|
|
|
|
if (scene->update_stats) {
|
|
|
|
|
scene->update_stats->osl.times.add_entry({"jit", time});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2016-01-03 18:28:33 +05:00
|
|
|
/* Perform greedyjit optimization.
|
|
|
|
|
*
|
2019-08-01 13:53:25 +10:00
|
|
|
* This might waste time on optimizing groups which are never actually
|
2016-01-03 18:28:33 +05:00
|
|
|
* used, but this prevents OSL from allocating data on TLS at render
|
|
|
|
|
* time.
|
|
|
|
|
*
|
|
|
|
|
* This is much better for us because this way we aren't required to
|
|
|
|
|
* stop task scheduler threads to make sure all TLS is clean and don't
|
|
|
|
|
* have issues with TLS data free accessing freed memory if task scheduler
|
|
|
|
|
* is being freed after the Session is freed.
|
|
|
|
|
*/
|
2024-12-29 17:32:00 +01:00
|
|
|
const thread_scoped_lock lock(ss_shared_mutex);
|
2023-01-18 17:28:03 +01:00
|
|
|
|
|
|
|
|
/* Set current image manager during the lock, so that there is no conflict with other shader
|
|
|
|
|
* manager instances.
|
|
|
|
|
*
|
|
|
|
|
* It is used in "OSLRenderServices::get_texture_handle" called during optimization below to
|
|
|
|
|
* load images for the GPU. */
|
2024-12-29 23:13:45 +01:00
|
|
|
OSLRenderServices::image_manager = scene->image_manager.get();
|
2023-01-18 17:28:03 +01:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
foreach_shading_system([](OSL::ShadingSystem *ss) { ss->optimize_all_groups(); });
|
2023-01-18 17:28:03 +01:00
|
|
|
|
|
|
|
|
OSLRenderServices::image_manager = nullptr;
|
2022-11-09 14:25:32 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
/* setup shader engine */
|
|
|
|
|
foreach_osl_device(device, [this, &progress](Device *sub_device, OSLGlobals *og) {
|
|
|
|
|
if (og->use) {
|
|
|
|
|
OSL::ShadingSystem *ss = get_shading_system(sub_device);
|
|
|
|
|
|
|
|
|
|
og->ss = ss;
|
|
|
|
|
og->ts = get_texture_system();
|
|
|
|
|
og->services = static_cast<OSLRenderServices *>(ss->renderer());
|
|
|
|
|
|
|
|
|
|
/* load kernels */
|
|
|
|
|
if (!sub_device->load_osl_kernels()) {
|
|
|
|
|
progress.set_error(sub_device->error_message());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
need_update_ = false;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::device_free(Device *device, DeviceScene * /*dscene*/, Scene *scene)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
/* clear shader engine */
|
2025-03-04 17:27:10 +01:00
|
|
|
foreach_osl_device(device, [](Device *, OSLGlobals *og) {
|
2022-11-09 14:25:32 +01:00
|
|
|
og->use = false;
|
2024-12-26 17:53:55 +01:00
|
|
|
og->ss = nullptr;
|
|
|
|
|
og->ts = nullptr;
|
2022-11-09 14:25:32 +01:00
|
|
|
});
|
2023-01-18 17:28:03 +01:00
|
|
|
|
|
|
|
|
/* Remove any textures specific to an image manager from shared render services textures, since
|
|
|
|
|
* the image manager may get destroyed next. */
|
2025-03-04 17:27:10 +01:00
|
|
|
foreach_render_services([scene](OSLRenderServices *services) {
|
2023-01-18 17:28:03 +01:00
|
|
|
for (auto it = services->textures.begin(); it != services->textures.end(); ++it) {
|
2024-12-29 23:13:45 +01:00
|
|
|
if (it->second.handle.get_manager() == scene->image_manager.get()) {
|
2023-01-18 17:28:03 +01:00
|
|
|
/* Don't lock again, since the iterator already did so. */
|
|
|
|
|
services->textures.erase(it->first, false);
|
|
|
|
|
it.clear();
|
|
|
|
|
/* Iterator was invalidated, start from the beginning again. */
|
|
|
|
|
it = services->textures.begin();
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-04 17:27:10 +01:00
|
|
|
});
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::texture_system_init()
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2013-04-04 23:48:07 +00:00
|
|
|
/* create texture system, shared between different renders to reduce memory usage */
|
2024-12-29 17:32:00 +01:00
|
|
|
const thread_scoped_lock lock(ts_shared_mutex);
|
2013-04-04 23:48:07 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
if (!ts_shared) {
|
|
|
|
|
# if OIIO_VERSION_MAJOR >= 3
|
|
|
|
|
ts_shared = OSL::TextureSystem::create(false);
|
|
|
|
|
# else
|
|
|
|
|
ts_shared = shared_ptr(OSL::TextureSystem::create(false), OSL::TextureSystem::destroy);
|
|
|
|
|
# endif
|
2013-04-04 23:48:07 +00:00
|
|
|
|
|
|
|
|
ts_shared->attribute("automip", 1);
|
|
|
|
|
ts_shared->attribute("autotile", 64);
|
|
|
|
|
ts_shared->attribute("gray_to_rgb", 1);
|
|
|
|
|
|
|
|
|
|
/* effectively unlimited for now, until we support proper mipmap lookups */
|
|
|
|
|
ts_shared->attribute("max_memory_MB", 16384);
|
|
|
|
|
}
|
2025-03-04 17:27:10 +01:00
|
|
|
|
|
|
|
|
/* make local copy to increase use count */
|
|
|
|
|
ts = ts_shared;
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::texture_system_free()
|
2013-04-22 14:27:12 +00:00
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
ts.reset();
|
2013-04-22 14:27:12 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
/* if ts_shared is the only reference to the underlying texture system,
|
|
|
|
|
* no users remain, so free it. */
|
|
|
|
|
const thread_scoped_lock lock(ts_shared_mutex);
|
|
|
|
|
if (ts_shared.use_count() == 1) {
|
2025-01-05 00:44:41 +01:00
|
|
|
ts_shared.reset();
|
2013-04-22 14:27:12 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::shading_system_init()
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
/* No need to do anything if we already have shading systems. */
|
|
|
|
|
if (!ss_map.empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-22 14:27:12 +00:00
|
|
|
/* create shading system, shared between different renders to reduce memory usage */
|
2024-12-29 17:32:00 +01:00
|
|
|
const thread_scoped_lock lock(ss_shared_mutex);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
foreach_osl_device(device_, [this](Device *sub_device, OSLGlobals *) {
|
2022-11-09 14:25:32 +01:00
|
|
|
const DeviceType device_type = sub_device->info.type;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
if (!ss_shared[device_type]) {
|
|
|
|
|
OSLRenderServices *services = util_aligned_new<OSLRenderServices>(get_texture_system(),
|
2025-01-05 00:44:41 +01:00
|
|
|
device_type);
|
2016-03-23 13:58:31 +01:00
|
|
|
# ifdef _WIN32
|
2022-11-09 14:25:32 +01:00
|
|
|
/* Annoying thing, Cycles stores paths in UTF-8 codepage, so it can
|
|
|
|
|
* operate with file paths with any character. This requires to use wide
|
|
|
|
|
* char functions, but OSL uses old fashioned ANSI functions which means:
|
|
|
|
|
*
|
|
|
|
|
* - We have to convert our paths to ANSI before passing to OSL
|
|
|
|
|
* - OSL can't be used when there's a multi-byte character in the path
|
|
|
|
|
* to the shaders folder.
|
|
|
|
|
*/
|
2024-12-29 17:32:00 +01:00
|
|
|
const string shader_path = string_to_ansi(path_get("shader"));
|
|
|
|
|
# else
|
|
|
|
|
const string shader_path = path_get("shader");
|
2016-03-23 13:58:31 +01:00
|
|
|
# endif
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
auto ss = std::shared_ptr<OSL::ShadingSystem>(
|
|
|
|
|
new OSL::ShadingSystem(services, get_texture_system(), &errhandler),
|
|
|
|
|
[](auto *ss) { util_aligned_delete(static_cast<OSLRenderServices *>(ss->renderer())); });
|
2022-11-09 14:25:32 +01:00
|
|
|
ss->attribute("lockgeom", 1);
|
|
|
|
|
ss->attribute("commonspace", "world");
|
|
|
|
|
ss->attribute("searchpath:shader", shader_path);
|
|
|
|
|
ss->attribute("greedyjit", 1);
|
|
|
|
|
|
Cycles: Use fused OptiX OSL programs
Based on #123377 by @brecht, but Gitea doesn't like the rebase these
so here's a new PR.
The purpose here is to switch to fused OptiX programs for OSL execution
on CUDA. On the one hand, this makes the code easier since, but there's
also another advantage - how memory allocation is managed.
OSL shaders need memory to store intermediate values, but how much is
needed depends on the complexity of the shader. With the split program
approach, Cycles had to provide that memory, so we had to allocate a
certain amount (2 KiB, to be precise) statically and show an error if
the shader would need more. If the shader used less (which is the case
for the vast majority), the memory was just wasted.
By switching to fused kernels, OSL knows the required amount during JIT
codegen, so it can allocate only what's required, which avoids this
waste. One still needs to set a maximum, and in theory, OSL would also
support spilling over into a Cycles-provided alternative memory region.
However, we currently don't implement that - instead, we default to the
same 2048 limit as before and let advanced users override it via the
CYCLES_OSL_GROUPDATA_ALLOC environment variable if really needed.
Co-authored-by: Brecht Van Lommel <brecht@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/130149
2024-11-26 23:58:32 +01:00
|
|
|
const char *groupdata_alloc_str = getenv("CYCLES_OSL_GROUPDATA_ALLOC");
|
|
|
|
|
if (groupdata_alloc_str) {
|
|
|
|
|
ss->attribute("max_optix_groupdata_alloc", atoi(groupdata_alloc_str));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ss->attribute("max_optix_groupdata_alloc", 2048);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-09 14:25:32 +01:00
|
|
|
VLOG_INFO << "Using shader search path: " << shader_path;
|
|
|
|
|
|
|
|
|
|
/* our own ray types */
|
|
|
|
|
static const char *raytypes[] = {
|
2023-01-19 18:22:47 -06:00
|
|
|
"camera", /* PATH_RAY_CAMERA */
|
|
|
|
|
"reflection", /* PATH_RAY_REFLECT */
|
|
|
|
|
"refraction", /* PATH_RAY_TRANSMIT */
|
|
|
|
|
"diffuse", /* PATH_RAY_DIFFUSE */
|
|
|
|
|
"glossy", /* PATH_RAY_GLOSSY */
|
|
|
|
|
"singular", /* PATH_RAY_SINGULAR */
|
|
|
|
|
"transparent", /* PATH_RAY_TRANSPARENT */
|
|
|
|
|
"volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
|
|
|
|
|
"importance_bake", /* PATH_RAY_IMPORTANCE_BAKE */
|
2022-11-09 14:25:32 +01:00
|
|
|
|
|
|
|
|
"shadow", /* PATH_RAY_SHADOW_OPAQUE */
|
|
|
|
|
"shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
|
|
|
|
|
|
|
|
|
|
"__unused__", /* PATH_RAY_NODE_UNALIGNED */
|
|
|
|
|
"__unused__", /* PATH_RAY_MIS_SKIP */
|
|
|
|
|
|
|
|
|
|
"diffuse_ancestor", /* PATH_RAY_DIFFUSE_ANCESTOR */
|
|
|
|
|
|
|
|
|
|
/* Remaining irrelevant bits up to 32. */
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
"__unused__",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const int nraytypes = sizeof(raytypes) / sizeof(raytypes[0]);
|
2024-12-26 17:53:59 +01:00
|
|
|
ss->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), (const void *)raytypes);
|
2022-11-09 14:25:32 +01:00
|
|
|
|
2024-12-29 23:13:45 +01:00
|
|
|
OSLRenderServices::register_closures(ss.get());
|
|
|
|
|
ss_shared[device_type] = std::move(ss);
|
2022-11-09 14:25:32 +01:00
|
|
|
}
|
2025-03-04 17:27:10 +01:00
|
|
|
ss_map[device_type] = ss_shared[device_type];
|
2022-11-09 14:25:32 +01:00
|
|
|
});
|
2013-04-22 14:27:12 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
void OSLManager::shading_system_free()
|
2013-04-22 14:27:12 +00:00
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
ss_map.clear();
|
2013-04-22 14:27:12 +00:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
/* if ss_shared is the only reference to the underlying shading system,
|
|
|
|
|
* no users remain, so free it. */
|
|
|
|
|
const thread_scoped_lock lock(ss_shared_mutex);
|
|
|
|
|
for (auto &[device_type, ss] : ss_shared) {
|
|
|
|
|
if (ss.use_count() == 1) {
|
|
|
|
|
ss.reset();
|
2022-11-09 14:25:32 +01:00
|
|
|
}
|
2025-03-04 17:27:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
loaded_shaders.clear();
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
bool OSLManager::osl_compile(const string &inputfile, const string &outputfile)
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2015-01-17 00:13:30 +05:00
|
|
|
vector<string> options;
|
2012-11-03 14:32:35 +00:00
|
|
|
string stdosl_path;
|
2024-12-29 17:32:00 +01:00
|
|
|
const string shader_path = path_get("shader");
|
2012-11-03 14:32:35 +00:00
|
|
|
|
2021-10-28 15:46:20 +02:00
|
|
|
/* Specify output file name. */
|
2012-11-03 14:32:35 +00:00
|
|
|
options.push_back("-o");
|
|
|
|
|
options.push_back(outputfile);
|
|
|
|
|
|
2021-10-28 15:46:20 +02:00
|
|
|
/* Specify standard include path. */
|
2024-12-29 17:32:00 +01:00
|
|
|
const string include_path_arg = string("-I") + shader_path;
|
2015-02-05 12:06:24 +05:00
|
|
|
options.push_back(include_path_arg);
|
2014-08-05 11:11:52 +02:00
|
|
|
|
2021-01-12 14:30:35 +01:00
|
|
|
stdosl_path = path_join(shader_path, "stdcycles.h");
|
2012-11-03 14:32:35 +00:00
|
|
|
|
2021-10-28 15:46:20 +02:00
|
|
|
/* Compile.
|
|
|
|
|
*
|
2023-02-12 14:37:16 +11:00
|
|
|
* Mutex protected because the OSL compiler does not appear to be thread safe, see #92503. */
|
2021-10-28 15:46:20 +02:00
|
|
|
static thread_mutex osl_compiler_mutex;
|
2024-12-29 17:32:00 +01:00
|
|
|
const thread_scoped_lock lock(osl_compiler_mutex);
|
2021-10-28 15:46:20 +02:00
|
|
|
|
2024-12-29 23:13:45 +01:00
|
|
|
OSL::OSLCompiler compiler = OSL::OSLCompiler(&OSL::ErrorHandler::default_handler());
|
|
|
|
|
const bool ok = compiler.compile(string_view(inputfile), options, string_view(stdosl_path));
|
2012-11-03 14:32:35 +00:00
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
bool OSLManager::osl_query(OSL::OSLQuery &query, const string &filepath)
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const string searchpath = path_user_get("shaders");
|
2012-11-03 14:32:35 +00:00
|
|
|
return query.open(filepath, searchpath);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static string shader_filepath_hash(const string &filepath, const uint64_t modified_time)
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
|
|
|
|
/* compute a hash from filepath and modified time to detect changes */
|
|
|
|
|
MD5Hash md5;
|
|
|
|
|
md5.append((const uint8_t *)filepath.c_str(), filepath.size());
|
|
|
|
|
md5.append((const uint8_t *)&modified_time, sizeof(modified_time));
|
|
|
|
|
|
|
|
|
|
return md5.get_hex();
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
const char *OSLManager::shader_test_loaded(const string &hash)
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
|
2024-12-26 17:53:55 +01:00
|
|
|
return (it == loaded_shaders.end()) ? nullptr : it->first.c_str();
|
2012-12-12 06:51:06 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
OSLShaderInfo *OSLManager::shader_loaded_info(const string &hash)
|
2012-12-12 06:51:06 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const map<string, OSLShaderInfo>::iterator it = loaded_shaders.find(hash);
|
2024-12-26 17:53:55 +01:00
|
|
|
return (it == loaded_shaders.end()) ? nullptr : &it->second;
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
const char *OSLManager::shader_load_filepath(string filepath)
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const size_t len = filepath.size();
|
|
|
|
|
const string extension = filepath.substr(len - 4);
|
2012-11-03 14:32:35 +00:00
|
|
|
uint64_t modified_time = path_modified_time(filepath);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
if (extension == ".osl") {
|
|
|
|
|
/* .OSL File */
|
2024-12-29 17:32:00 +01:00
|
|
|
const string osopath = filepath.substr(0, len - 4) + ".oso";
|
|
|
|
|
const uint64_t oso_modified_time = path_modified_time(osopath);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
/* test if we have loaded the corresponding .OSO already */
|
|
|
|
|
if (oso_modified_time != 0) {
|
|
|
|
|
const char *hash = shader_test_loaded(shader_filepath_hash(osopath, oso_modified_time));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
if (hash) {
|
2012-11-03 14:32:35 +00:00
|
|
|
return hash;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Auto-compile .OSL to .OSO if needed. */
|
2012-11-03 14:32:35 +00:00
|
|
|
if (oso_modified_time == 0 || (oso_modified_time < modified_time)) {
|
2025-03-04 17:27:10 +01:00
|
|
|
OSLManager::osl_compile(filepath, osopath);
|
2012-11-03 14:32:35 +00:00
|
|
|
modified_time = path_modified_time(osopath);
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
2012-11-03 14:32:35 +00:00
|
|
|
modified_time = oso_modified_time;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
filepath = osopath;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (extension == ".oso") {
|
|
|
|
|
/* .OSO File, nothing to do */
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else if (path_dirname(filepath).empty()) {
|
2012-11-03 14:32:35 +00:00
|
|
|
/* .OSO File in search path */
|
|
|
|
|
filepath = path_join(path_user_get("shaders"), filepath + ".oso");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* unknown file */
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
/* test if we have loaded this .OSO already */
|
|
|
|
|
const char *hash = shader_test_loaded(shader_filepath_hash(filepath, modified_time));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
if (hash) {
|
2012-11-03 14:32:35 +00:00
|
|
|
return hash;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
/* read oso bytecode from file */
|
2024-12-29 17:32:00 +01:00
|
|
|
const string bytecode_hash = shader_filepath_hash(filepath, modified_time);
|
2012-11-03 14:32:35 +00:00
|
|
|
string bytecode;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
if (!path_read_text(filepath, bytecode)) {
|
|
|
|
|
fprintf(stderr, "Cycles shader graph: failed to read file %s\n", filepath.c_str());
|
2024-12-29 17:32:00 +01:00
|
|
|
const OSLShaderInfo info;
|
2012-12-12 06:51:06 +00:00
|
|
|
loaded_shaders[bytecode_hash] = info; /* to avoid repeat tries */
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
return shader_load_bytecode(bytecode_hash, bytecode);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
const char *OSLManager::shader_load_bytecode(const string &hash, const string &bytecode)
|
2012-11-03 14:32:35 +00:00
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
shading_system_init();
|
|
|
|
|
|
|
|
|
|
foreach_shading_system(
|
|
|
|
|
[hash, bytecode](OSL::ShadingSystem *ss) { ss->LoadMemoryCompiledShader(hash, bytecode); });
|
|
|
|
|
|
|
|
|
|
tag_update();
|
2012-11-03 14:32:35 +00:00
|
|
|
|
2012-12-12 06:51:06 +00:00
|
|
|
OSLShaderInfo info;
|
2016-05-29 15:10:34 +02:00
|
|
|
|
|
|
|
|
if (!info.query.open_bytecode(bytecode)) {
|
|
|
|
|
fprintf(stderr, "OSL query error: %s\n", info.query.geterror().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* this is a bit weak, but works */
|
2012-12-12 06:51:06 +00:00
|
|
|
info.has_surface_emission = (bytecode.find("\"emission\"") != string::npos);
|
|
|
|
|
info.has_surface_transparent = (bytecode.find("\"transparent\"") != string::npos);
|
2013-04-01 20:26:52 +00:00
|
|
|
info.has_surface_bssrdf = (bytecode.find("\"bssrdf\"") != string::npos);
|
2016-05-29 15:10:34 +02:00
|
|
|
|
2012-12-12 06:51:06 +00:00
|
|
|
loaded_shaders[hash] = info;
|
|
|
|
|
|
|
|
|
|
return loaded_shaders.find(hash)->first.c_str();
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
uint64_t OSLShaderManager::get_attribute_id(ustring name)
|
|
|
|
|
{
|
|
|
|
|
return name.hash();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t OSLShaderManager::get_attribute_id(AttributeStandard std)
|
|
|
|
|
{
|
|
|
|
|
/* if standard attribute, use geom: name convention */
|
|
|
|
|
const ustring stdname(string("geom:") + string(Attribute::standard_name(std)));
|
|
|
|
|
return stdname.hash();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OSLShaderManager::device_update_specific(Device *device,
|
|
|
|
|
DeviceScene *dscene,
|
|
|
|
|
Scene *scene,
|
|
|
|
|
Progress &progress)
|
|
|
|
|
{
|
|
|
|
|
if (!need_update())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
scoped_callback_timer timer([scene](double time) {
|
|
|
|
|
if (scene->update_stats) {
|
|
|
|
|
scene->update_stats->osl.times.add_entry({"device_update", time});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
VLOG_INFO << "Total " << scene->shaders.size() << " shaders.";
|
|
|
|
|
|
|
|
|
|
/* setup shader engine */
|
|
|
|
|
OSLManager::foreach_osl_device(device, [](Device *, OSLGlobals *og) {
|
|
|
|
|
og->use = true;
|
|
|
|
|
|
|
|
|
|
og->surface_state.clear();
|
|
|
|
|
og->volume_state.clear();
|
|
|
|
|
og->displacement_state.clear();
|
|
|
|
|
og->bump_state.clear();
|
|
|
|
|
og->background_state.reset();
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/* create shaders */
|
|
|
|
|
Shader *background_shader = scene->background->get_shader(scene);
|
|
|
|
|
|
|
|
|
|
/* compile each shader to OSL shader groups */
|
|
|
|
|
TaskPool task_pool;
|
|
|
|
|
for (Shader *shader : scene->shaders) {
|
|
|
|
|
assert(shader->graph);
|
|
|
|
|
|
|
|
|
|
auto compile = [this, scene, shader, background_shader](Device *sub_device, OSLGlobals *) {
|
|
|
|
|
OSL::ShadingSystem *ss = scene->osl_manager->get_shading_system(sub_device);
|
|
|
|
|
|
|
|
|
|
OSLCompiler compiler(this, ss, scene);
|
|
|
|
|
compiler.background = (shader == background_shader);
|
|
|
|
|
compiler.compile(shader);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
task_pool.push([device, compile] { OSLManager::foreach_osl_device(device, compile); });
|
|
|
|
|
}
|
|
|
|
|
task_pool.wait_work();
|
|
|
|
|
|
|
|
|
|
if (progress.get_cancel()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* collect shader groups from all shaders */
|
|
|
|
|
for (Shader *shader : scene->shaders) {
|
|
|
|
|
OSLManager::OSLManager::foreach_osl_device(
|
|
|
|
|
device, [shader, background_shader](Device *, OSLGlobals *og) {
|
|
|
|
|
/* push state to array for lookup */
|
|
|
|
|
og->surface_state.push_back(shader->osl_surface_ref);
|
|
|
|
|
og->volume_state.push_back(shader->osl_volume_ref);
|
|
|
|
|
og->displacement_state.push_back(shader->osl_displacement_ref);
|
|
|
|
|
og->bump_state.push_back(shader->osl_surface_bump_ref);
|
|
|
|
|
|
|
|
|
|
if (shader == background_shader) {
|
|
|
|
|
og->background_state = shader->osl_surface_ref;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (shader->emission_sampling != EMISSION_SAMPLING_NONE) {
|
|
|
|
|
scene->light_manager->tag_update(scene, LightManager::SHADER_COMPILED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
scene->osl_manager->tag_update();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* set background shader */
|
|
|
|
|
int background_id = scene->shader_manager->get_shader_id(background_shader);
|
|
|
|
|
|
|
|
|
|
OSLManager::foreach_osl_device(device, [background_id](Device *, OSLGlobals *og) {
|
|
|
|
|
og->background_state = og->surface_state[background_id & SHADER_MASK];
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (Shader *shader : scene->shaders) {
|
|
|
|
|
shader->clear_modified();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_flags = UPDATE_NONE;
|
|
|
|
|
|
|
|
|
|
device_update_common(device, dscene, scene, progress);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OSLShaderManager::device_free(Device *device, DeviceScene *dscene, Scene *scene)
|
|
|
|
|
{
|
|
|
|
|
device_free_common(device, dscene, scene);
|
|
|
|
|
|
|
|
|
|
/* clear shader engine */
|
|
|
|
|
OSLManager::foreach_osl_device(device, [](Device *, OSLGlobals *og) {
|
|
|
|
|
og->use = false;
|
|
|
|
|
|
|
|
|
|
og->surface_state.clear();
|
|
|
|
|
og->volume_state.clear();
|
|
|
|
|
og->displacement_state.clear();
|
|
|
|
|
og->bump_state.clear();
|
|
|
|
|
og->background_state.reset();
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-11 16:51:42 +01:00
|
|
|
/* This is a static function to avoid RTTI link errors with only this
|
|
|
|
|
* file being compiled without RTTI to match OSL and LLVM libraries. */
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
OSLNode *OSLShaderManager::osl_node(ShaderGraph *graph,
|
2025-03-04 17:27:10 +01:00
|
|
|
Scene *scene,
|
2020-03-11 16:51:42 +01:00
|
|
|
const std::string &filepath,
|
2016-05-29 15:10:34 +02:00
|
|
|
const std::string &bytecode_hash,
|
|
|
|
|
const std::string &bytecode)
|
|
|
|
|
{
|
2025-03-04 17:27:10 +01:00
|
|
|
if (!scene->shader_manager->use_osl()) {
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2020-03-11 16:51:42 +01:00
|
|
|
}
|
|
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
/* create query */
|
|
|
|
|
const char *hash;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (!filepath.empty()) {
|
2025-03-04 17:27:10 +01:00
|
|
|
hash = scene->osl_manager->shader_load_filepath(filepath);
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2025-03-04 17:27:10 +01:00
|
|
|
hash = scene->osl_manager->shader_test_loaded(bytecode_hash);
|
2024-12-26 17:53:59 +01:00
|
|
|
if (!hash) {
|
2025-03-04 17:27:10 +01:00
|
|
|
hash = scene->osl_manager->shader_load_bytecode(bytecode_hash, bytecode);
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (!hash) {
|
2024-12-26 17:53:55 +01:00
|
|
|
return nullptr;
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
OSLShaderInfo *info = scene->osl_manager->shader_loaded_info(hash);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
/* count number of inputs */
|
|
|
|
|
size_t num_inputs = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
for (int i = 0; i < info->query.nparams(); i++) {
|
|
|
|
|
const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
/* skip unsupported types */
|
2024-12-26 17:53:59 +01:00
|
|
|
if (param->varlenarray || param->isstruct || param->type.arraylen > 1) {
|
2016-05-29 15:10:34 +02:00
|
|
|
continue;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
if (!param->isoutput) {
|
2016-05-29 15:10:34 +02:00
|
|
|
num_inputs++;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
/* create node */
|
Cycles: introduce an ownership system to protect nodes from unwanted deletions.
Problem: the Blender synchronization process creates and tags nodes for usage. It does
this by directly adding and removing nodes from the scene data. If some node is not tagged
as used at the end of a synchronization, it then deletes the node from the scene. This poses
a problem when it comes to supporting procedural nodes who can create other nodes not known
by the Blender synchonization system, which will remove them.
Nodes now have a NodeOwner, which is set after creation. Those owners for now are the Scene
for scene level nodes and ShaderGraph for shader nodes. Instead of creating and deleting
nodes using `new` and `delete` explicitely, we now use `create_node` and `delete_node` methods
found on the owners. `delete_node` will assert that the owner is the right one.
Whenever a scene level node is created or deleted, the appropriate node manager is tagged for
an update, freeing this responsability from BlenderSync or other software exporters.
Concerning BlenderSync, the `id_maps` do not explicitely manipulate scene data anymore, they
only keep track of which nodes are used, employing the scene to create and delete them. To
achieve this, the ParticleSystem is now a Node, although it does not have any sockets.
This is part of T79131.
Reviewed By: #cycles, brecht
Maniphest Tasks: T79131
Differential Revision: https://developer.blender.org/D8540
2020-08-30 23:20:51 +02:00
|
|
|
OSLNode *node = OSLNode::create(graph, num_inputs);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
/* add new sockets from parameters */
|
2024-12-29 17:32:00 +01:00
|
|
|
const set<void *> used_sockets;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
for (int i = 0; i < info->query.nparams(); i++) {
|
|
|
|
|
const OSL::OSLQuery::Parameter *param = info->query.getparam(i);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
/* skip unsupported types */
|
2024-12-26 17:53:59 +01:00
|
|
|
if (param->varlenarray || param->isstruct || param->type.arraylen > 1) {
|
2016-05-29 15:10:34 +02:00
|
|
|
continue;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
SocketType::Type socket_type;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-23 18:02:45 +01:00
|
|
|
/* Read type and default value. */
|
2016-05-29 15:10:34 +02:00
|
|
|
if (param->isclosure) {
|
|
|
|
|
socket_type = SocketType::CLOSURE;
|
|
|
|
|
}
|
|
|
|
|
else if (param->type.vecsemantics != TypeDesc::NOSEMANTICS) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (param->type.vecsemantics == TypeDesc::COLOR) {
|
2016-05-29 15:10:34 +02:00
|
|
|
socket_type = SocketType::COLOR;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
else if (param->type.vecsemantics == TypeDesc::POINT) {
|
2016-05-29 15:10:34 +02:00
|
|
|
socket_type = SocketType::POINT;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
else if (param->type.vecsemantics == TypeDesc::VECTOR) {
|
2016-05-29 15:10:34 +02:00
|
|
|
socket_type = SocketType::VECTOR;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
else if (param->type.vecsemantics == TypeDesc::NORMAL) {
|
2016-05-29 15:10:34 +02:00
|
|
|
socket_type = SocketType::NORMAL;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2016-05-29 15:10:34 +02:00
|
|
|
continue;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (!param->isoutput && param->validdefault) {
|
2016-05-07 19:48:28 +02:00
|
|
|
float3 *default_value = (float3 *)node->input_default_value();
|
|
|
|
|
default_value->x = param->fdefault[0];
|
|
|
|
|
default_value->y = param->fdefault[1];
|
|
|
|
|
default_value->z = param->fdefault[2];
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (param->type.aggregate == TypeDesc::SCALAR) {
|
|
|
|
|
if (param->type.basetype == TypeDesc::INT) {
|
|
|
|
|
socket_type = SocketType::INT;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (!param->isoutput && param->validdefault) {
|
2016-05-07 19:48:28 +02:00
|
|
|
*(int *)node->input_default_value() = param->idefault[0];
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (param->type.basetype == TypeDesc::FLOAT) {
|
|
|
|
|
socket_type = SocketType::FLOAT;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (!param->isoutput && param->validdefault) {
|
2016-05-07 19:48:28 +02:00
|
|
|
*(float *)node->input_default_value() = param->fdefault[0];
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (param->type.basetype == TypeDesc::STRING) {
|
|
|
|
|
socket_type = SocketType::STRING;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (!param->isoutput && param->validdefault) {
|
2016-05-07 19:48:28 +02:00
|
|
|
*(ustring *)node->input_default_value() = param->sdefault[0];
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
2016-05-29 15:10:34 +02:00
|
|
|
continue;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
2016-05-29 15:10:34 +02:00
|
|
|
continue;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
if (param->isoutput) {
|
2016-05-07 19:48:28 +02:00
|
|
|
node->add_output(param->name, socket_type);
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2022-11-23 18:02:45 +01:00
|
|
|
/* Detect if we should leave parameter initialization to OSL, either though
|
|
|
|
|
* not constant default or widget metadata. */
|
|
|
|
|
int socket_flags = 0;
|
|
|
|
|
if (!param->validdefault) {
|
|
|
|
|
socket_flags |= SocketType::LINK_OSL_INITIALIZER;
|
|
|
|
|
}
|
|
|
|
|
for (const OSL::OSLQuery::Parameter &metadata : param->metadata) {
|
|
|
|
|
if (metadata.type == TypeDesc::STRING) {
|
|
|
|
|
if (metadata.name == "widget" && metadata.sdefault[0] == "null") {
|
|
|
|
|
socket_flags |= SocketType::LINK_OSL_INITIALIZER;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
node->add_input(param->name, socket_type, socket_flags);
|
2016-05-29 15:10:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-02-05 16:23:34 +11:00
|
|
|
/* Set byte-code hash or file-path. */
|
2016-05-29 15:10:34 +02:00
|
|
|
if (!bytecode_hash.empty()) {
|
|
|
|
|
node->bytecode_hash = bytecode_hash;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
node->filepath = filepath;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
/* Generate inputs and outputs */
|
|
|
|
|
node->create_inputs_outputs(node->type);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-29 15:10:34 +02:00
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 22:02:39 +01:00
|
|
|
/* Static function, so only this file needs to be compile with RTTT. */
|
|
|
|
|
void OSLShaderManager::osl_image_slots(Device *device,
|
|
|
|
|
ImageManager *image_manager,
|
|
|
|
|
set<int> &image_slots)
|
|
|
|
|
{
|
|
|
|
|
set<OSLRenderServices *> services_shared;
|
|
|
|
|
device->foreach_device([&services_shared](Device *sub_device) {
|
2024-12-29 23:13:45 +01:00
|
|
|
OSLGlobals *og = sub_device->get_cpu_osl_memory();
|
2023-02-08 22:02:39 +01:00
|
|
|
services_shared.insert(og->services);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
for (OSLRenderServices *services : services_shared) {
|
|
|
|
|
for (auto it = services->textures.begin(); it != services->textures.end(); ++it) {
|
2024-12-29 23:13:45 +01:00
|
|
|
if (it->second.handle.get_manager() == image_manager) {
|
|
|
|
|
const int slot = it->second.handle.svm_slot();
|
2023-02-08 22:02:39 +01:00
|
|
|
image_slots.insert(slot);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* Graph Compiler */
|
|
|
|
|
|
2022-11-09 14:25:32 +01:00
|
|
|
OSLCompiler::OSLCompiler(OSLShaderManager *manager, OSL::ShadingSystem *ss, Scene *scene)
|
|
|
|
|
: scene(scene),
|
|
|
|
|
manager(manager),
|
|
|
|
|
services(static_cast<OSLRenderServices *>(ss->renderer())),
|
|
|
|
|
ss(ss)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2011-10-12 23:03:12 +00:00
|
|
|
current_type = SHADER_TYPE_SURFACE;
|
2024-12-26 17:53:55 +01:00
|
|
|
current_shader = nullptr;
|
2011-04-27 11:58:34 +00:00
|
|
|
background = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string OSLCompiler::id(ShaderNode *node)
|
|
|
|
|
{
|
|
|
|
|
/* assign layer unique name based on pointer address + bump mode */
|
2023-08-12 10:52:56 +03:00
|
|
|
std::stringstream stream;
|
2023-04-14 13:51:38 +10:00
|
|
|
|
|
|
|
|
/* Ensure that no grouping characters (e.g. commas with en_US locale)
|
|
|
|
|
* are added to the pointer string. */
|
|
|
|
|
stream.imbue(std::locale("C"));
|
|
|
|
|
|
2016-08-04 14:48:34 +03:00
|
|
|
stream << "node_" << node->type->name << "_" << node;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
return stream.str();
|
|
|
|
|
}
|
|
|
|
|
|
2012-09-15 16:31:07 +00:00
|
|
|
string OSLCompiler::compatible_name(ShaderNode *node, ShaderInput *input)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2016-05-08 01:32:09 +02:00
|
|
|
string sname(input->name().string());
|
2011-04-27 11:58:34 +00:00
|
|
|
size_t i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-24 19:31:08 +11:00
|
|
|
/* Strip white-space. */
|
2024-12-26 17:53:59 +01:00
|
|
|
while ((i = sname.find(" ")) != string::npos) {
|
2011-04-27 11:58:34 +00:00
|
|
|
sname.replace(i, 1, "");
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-09-15 16:31:07 +00:00
|
|
|
/* if output exists with the same name, add "In" suffix */
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderOutput *output : node->outputs) {
|
2016-05-08 01:32:09 +02:00
|
|
|
if (input->name() == output->name()) {
|
2012-09-15 16:31:07 +00:00
|
|
|
sname += "In";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-09-15 16:31:07 +00:00
|
|
|
return sname;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string OSLCompiler::compatible_name(ShaderNode *node, ShaderOutput *output)
|
|
|
|
|
{
|
2016-05-08 01:32:09 +02:00
|
|
|
string sname(output->name().string());
|
2012-09-15 16:31:07 +00:00
|
|
|
size_t i;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-10-24 19:31:08 +11:00
|
|
|
/* Strip white-space. */
|
2024-12-26 17:53:59 +01:00
|
|
|
while ((i = sname.find(" ")) != string::npos) {
|
2012-09-15 16:31:07 +00:00
|
|
|
sname.replace(i, 1, "");
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-20 17:40:21 +00:00
|
|
|
/* if input exists with the same name, add "Out" suffix */
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderInput *input : node->inputs) {
|
2016-05-08 01:32:09 +02:00
|
|
|
if (input->name() == output->name()) {
|
2012-09-15 16:31:07 +00:00
|
|
|
sname += "Out";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
return sname;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
|
|
|
|
|
{
|
|
|
|
|
/* exception for output node, only one input is actually used
|
2012-06-09 17:22:52 +00:00
|
|
|
* depending on the current shader type */
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
if (input->flags() & SocketType::SVM_INTERNAL) {
|
2012-11-27 16:02:12 +00:00
|
|
|
return true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 00:41:01 +02:00
|
|
|
if (node->special_type == SHADER_SPECIAL_TYPE_OUTPUT) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (input->name() == "Surface" && current_type != SHADER_TYPE_SURFACE) {
|
2011-10-12 23:03:12 +00:00
|
|
|
return true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
if (input->name() == "Volume" && current_type != SHADER_TYPE_VOLUME) {
|
2011-04-27 11:58:34 +00:00
|
|
|
return true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
if (input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT) {
|
2011-04-27 11:58:34 +00:00
|
|
|
return true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
if (input->name() == "Normal" && current_type != SHADER_TYPE_BUMP) {
|
2012-10-20 12:18:00 +00:00
|
|
|
return true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2016-05-02 00:05:16 +02:00
|
|
|
else if (node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (input->name() == "Height") {
|
2012-10-20 15:09:36 +00:00
|
|
|
return true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2012-10-20 15:09:36 +00:00
|
|
|
}
|
2016-05-02 00:05:16 +02:00
|
|
|
else if (current_type == SHADER_TYPE_DISPLACEMENT && input->link &&
|
|
|
|
|
input->link->parent->special_type == SHADER_SPECIAL_TYPE_BUMP)
|
2024-12-26 17:53:59 +01:00
|
|
|
{
|
2011-04-27 11:58:34 +00:00
|
|
|
return true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2012-11-03 14:32:35 +00:00
|
|
|
/* load filepath */
|
|
|
|
|
if (isfilepath) {
|
2025-03-04 17:27:10 +01:00
|
|
|
name = scene->osl_manager->shader_load_filepath(name);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
if (name == nullptr) {
|
2012-11-03 14:32:35 +00:00
|
|
|
return;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* pass in fixed parameter values */
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderInput *input : node->inputs) {
|
2011-04-27 11:58:34 +00:00
|
|
|
if (!input->link) {
|
|
|
|
|
/* checks to untangle graphs */
|
2022-11-23 18:02:45 +01:00
|
|
|
if (node_skip_input(node, input)) {
|
2011-04-27 11:58:34 +00:00
|
|
|
continue;
|
2022-11-23 18:02:45 +01:00
|
|
|
}
|
2022-11-24 16:59:37 +01:00
|
|
|
if ((input->flags() & SocketType::LINK_OSL_INITIALIZER) && !(input->constant_folded_in)) {
|
2022-11-23 18:02:45 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const string param_name = compatible_name(node, input);
|
2016-05-07 19:48:28 +02:00
|
|
|
const SocketType &socket = input->socket_type;
|
2016-05-08 01:32:09 +02:00
|
|
|
switch (input->type()) {
|
|
|
|
|
case SocketType::COLOR:
|
2016-05-07 19:48:28 +02:00
|
|
|
parameter_color(param_name.c_str(), node->get_float3(socket));
|
2011-04-27 11:58:34 +00:00
|
|
|
break;
|
2016-05-08 01:32:09 +02:00
|
|
|
case SocketType::POINT:
|
2016-05-07 19:48:28 +02:00
|
|
|
parameter_point(param_name.c_str(), node->get_float3(socket));
|
2011-04-27 11:58:34 +00:00
|
|
|
break;
|
2016-05-08 01:32:09 +02:00
|
|
|
case SocketType::VECTOR:
|
2016-05-07 19:48:28 +02:00
|
|
|
parameter_vector(param_name.c_str(), node->get_float3(socket));
|
2011-04-27 11:58:34 +00:00
|
|
|
break;
|
2016-05-08 01:32:09 +02:00
|
|
|
case SocketType::NORMAL:
|
2016-05-07 19:48:28 +02:00
|
|
|
parameter_normal(param_name.c_str(), node->get_float3(socket));
|
2011-04-27 11:58:34 +00:00
|
|
|
break;
|
2016-05-08 01:32:09 +02:00
|
|
|
case SocketType::FLOAT:
|
2016-05-07 19:48:28 +02:00
|
|
|
parameter(param_name.c_str(), node->get_float(socket));
|
2011-04-27 11:58:34 +00:00
|
|
|
break;
|
2016-05-08 01:32:09 +02:00
|
|
|
case SocketType::INT:
|
2016-05-07 19:48:28 +02:00
|
|
|
parameter(param_name.c_str(), node->get_int(socket));
|
2012-10-20 13:11:45 +00:00
|
|
|
break;
|
2016-05-08 01:32:09 +02:00
|
|
|
case SocketType::STRING:
|
2016-05-07 19:48:28 +02:00
|
|
|
parameter(param_name.c_str(), node->get_string(socket));
|
2012-11-06 21:36:44 +00:00
|
|
|
break;
|
2016-05-08 01:32:09 +02:00
|
|
|
case SocketType::CLOSURE:
|
|
|
|
|
case SocketType::UNDEFINED:
|
|
|
|
|
default:
|
2011-04-27 11:58:34 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2021-09-24 11:31:23 +10:00
|
|
|
/* Create shader of the appropriate type. OSL only distinguishes between "surface"
|
|
|
|
|
* and "displacement" at the moment. */
|
2024-12-26 17:53:59 +01:00
|
|
|
if (current_type == SHADER_TYPE_SURFACE) {
|
|
|
|
|
ss->Shader(*current_group, "surface", name, id(node));
|
|
|
|
|
}
|
|
|
|
|
else if (current_type == SHADER_TYPE_VOLUME) {
|
|
|
|
|
ss->Shader(*current_group, "surface", name, id(node));
|
|
|
|
|
}
|
|
|
|
|
else if (current_type == SHADER_TYPE_DISPLACEMENT) {
|
|
|
|
|
ss->Shader(*current_group, "displacement", name, id(node));
|
|
|
|
|
}
|
|
|
|
|
else if (current_type == SHADER_TYPE_BUMP) {
|
|
|
|
|
ss->Shader(*current_group, "displacement", name, id(node));
|
|
|
|
|
}
|
|
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
assert(0);
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* link inputs to other nodes */
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderInput *input : node->inputs) {
|
2011-04-27 11:58:34 +00:00
|
|
|
if (input->link) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node_skip_input(node, input)) {
|
2011-04-27 11:58:34 +00:00
|
|
|
continue;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
/* connect shaders */
|
2024-12-29 17:32:00 +01:00
|
|
|
const string id_from = id(input->link->parent);
|
|
|
|
|
const string id_to = id(node);
|
|
|
|
|
const string param_from = compatible_name(input->link->parent, input->link);
|
|
|
|
|
const string param_to = compatible_name(node, input);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
ss->ConnectShaders(*current_group, id_from, param_from, id_to, param_to);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-12-12 06:51:06 +00:00
|
|
|
/* test if we shader contains specific closures */
|
2025-03-04 17:27:10 +01:00
|
|
|
OSLShaderInfo *info = scene->osl_manager->shader_loaded_info(name);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-05 22:13:51 +01:00
|
|
|
if (current_type == SHADER_TYPE_SURFACE) {
|
|
|
|
|
if (info) {
|
2022-11-30 20:50:11 +01:00
|
|
|
if (info->has_surface_emission && node->special_type == SHADER_SPECIAL_TYPE_OSL) {
|
|
|
|
|
/* Will be used by Shader::estimate_emission. */
|
|
|
|
|
OSLNode *oslnode = static_cast<OSLNode *>(node);
|
|
|
|
|
oslnode->has_emission = true;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
if (info->has_surface_transparent) {
|
2016-02-05 22:13:51 +01:00
|
|
|
current_shader->has_surface_transparent = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2016-02-05 22:13:51 +01:00
|
|
|
if (info->has_surface_bssrdf) {
|
|
|
|
|
current_shader->has_surface_bssrdf = true;
|
|
|
|
|
current_shader->has_bssrdf_bump = true; /* can't detect yet */
|
|
|
|
|
}
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
current_shader->has_bump = true; /* can't detect yet */
|
|
|
|
|
current_shader->has_surface_raytrace = true; /* can't detect yet */
|
2016-02-05 22:13:51 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-02-05 22:13:51 +01:00
|
|
|
if (node->has_spatial_varying()) {
|
|
|
|
|
current_shader->has_surface_spatial_varying = true;
|
2013-08-18 14:15:57 +00:00
|
|
|
}
|
2012-12-12 06:51:06 +00:00
|
|
|
}
|
2014-04-04 13:20:46 +02:00
|
|
|
else if (current_type == SHADER_TYPE_VOLUME) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node->has_spatial_varying()) {
|
2016-02-05 21:33:37 +01:00
|
|
|
current_shader->has_volume_spatial_varying = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
if (node->has_attribute_dependency()) {
|
2020-03-07 14:38:52 +01:00
|
|
|
current_shader->has_volume_attribute_dependency = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2014-04-04 13:20:46 +02:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
static TypeDesc array_typedesc(const TypeDesc typedesc, const int arraylength)
|
2016-05-07 19:48:28 +02:00
|
|
|
{
|
|
|
|
|
return TypeDesc((TypeDesc::BASETYPE)typedesc.basetype,
|
|
|
|
|
(TypeDesc::AGGREGATE)typedesc.aggregate,
|
|
|
|
|
(TypeDesc::VECSEMANTICS)typedesc.vecsemantics,
|
|
|
|
|
arraylength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OSLCompiler::parameter(ShaderNode *node, const char *name)
|
|
|
|
|
{
|
2024-12-29 17:32:00 +01:00
|
|
|
const ustring uname = ustring(name);
|
2016-05-07 19:48:28 +02:00
|
|
|
const SocketType &socket = *(node->type->find_input(uname));
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
switch (socket.type) {
|
|
|
|
|
case SocketType::BOOLEAN: {
|
|
|
|
|
int value = node->get_bool(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeInt, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::FLOAT: {
|
|
|
|
|
float value = node->get_float(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypeFloat, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::INT: {
|
|
|
|
|
int value = node->get_int(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypeInt, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::COLOR: {
|
|
|
|
|
float3 value = node->get_float3(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypeColor, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::VECTOR: {
|
|
|
|
|
float3 value = node->get_float3(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypeVector, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::POINT: {
|
|
|
|
|
float3 value = node->get_float3(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypePoint, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::NORMAL: {
|
|
|
|
|
float3 value = node->get_float3(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypeNormal, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::POINT2: {
|
|
|
|
|
float2 value = node->get_float2(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group,
|
|
|
|
|
uname,
|
|
|
|
|
TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT),
|
|
|
|
|
&value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::STRING: {
|
|
|
|
|
ustring value = node->get_string(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypeString, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::ENUM: {
|
|
|
|
|
ustring value = node->get_string(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypeString, &value);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::TRANSFORM: {
|
2024-12-29 17:32:00 +01:00
|
|
|
const Transform value = node->get_transform(socket);
|
2018-03-08 06:48:14 +01:00
|
|
|
ProjectionTransform projection(value);
|
|
|
|
|
projection = projection_transpose(projection);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, TypeMatrix, &projection);
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::BOOLEAN_ARRAY: {
|
|
|
|
|
// OSL does not support booleans, so convert to int
|
|
|
|
|
const array<bool> &value = node->get_bool_array(socket);
|
|
|
|
|
array<int> intvalue(value.size());
|
2024-12-26 17:53:59 +01:00
|
|
|
for (size_t i = 0; i < value.size(); i++) {
|
2016-05-07 19:48:28 +02:00
|
|
|
intvalue[i] = value[i];
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, array_typedesc(TypeInt, value.size()), intvalue.data());
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::FLOAT_ARRAY: {
|
|
|
|
|
const array<float> &value = node->get_float_array(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, array_typedesc(TypeFloat, value.size()), value.data());
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::INT_ARRAY: {
|
|
|
|
|
const array<int> &value = node->get_int_array(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, array_typedesc(TypeInt, value.size()), value.data());
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2016-05-07 19:48:28 +02:00
|
|
|
case SocketType::COLOR_ARRAY:
|
|
|
|
|
case SocketType::VECTOR_ARRAY:
|
|
|
|
|
case SocketType::POINT_ARRAY:
|
|
|
|
|
case SocketType::NORMAL_ARRAY: {
|
|
|
|
|
TypeDesc typedesc;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
switch (socket.type) {
|
|
|
|
|
case SocketType::COLOR_ARRAY:
|
2024-10-17 19:48:38 +02:00
|
|
|
typedesc = TypeColor;
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
case SocketType::VECTOR_ARRAY:
|
2024-10-17 19:48:38 +02:00
|
|
|
typedesc = TypeVector;
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
case SocketType::POINT_ARRAY:
|
2024-10-17 19:48:38 +02:00
|
|
|
typedesc = TypePoint;
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
case SocketType::NORMAL_ARRAY:
|
2024-10-17 19:48:38 +02:00
|
|
|
typedesc = TypeNormal;
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-07 19:48:28 +02:00
|
|
|
// convert to tightly packed array since float3 has padding
|
|
|
|
|
const array<float3> &value = node->get_float3_array(socket);
|
|
|
|
|
array<float> fvalue(value.size() * 3);
|
2016-10-24 12:26:12 +02:00
|
|
|
for (size_t i = 0, j = 0; i < value.size(); i++) {
|
2016-05-07 19:48:28 +02:00
|
|
|
fvalue[j++] = value[i].x;
|
|
|
|
|
fvalue[j++] = value[i].y;
|
|
|
|
|
fvalue[j++] = value[i].z;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, array_typedesc(typedesc, value.size()), fvalue.data());
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::POINT2_ARRAY: {
|
|
|
|
|
const array<float2> &value = node->get_float2_array(socket);
|
|
|
|
|
ss->Parameter(
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
*current_group,
|
2016-05-07 19:48:28 +02:00
|
|
|
uname,
|
|
|
|
|
array_typedesc(TypeDesc(TypeDesc::FLOAT, TypeDesc::VEC2, TypeDesc::POINT), value.size()),
|
|
|
|
|
value.data());
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::STRING_ARRAY: {
|
|
|
|
|
const array<ustring> &value = node->get_string_array(socket);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, uname, array_typedesc(TypeString, value.size()), value.data());
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::TRANSFORM_ARRAY: {
|
|
|
|
|
const array<Transform> &value = node->get_transform_array(socket);
|
2018-03-08 06:48:14 +01:00
|
|
|
array<ProjectionTransform> fvalue(value.size());
|
|
|
|
|
for (size_t i = 0; i < value.size(); i++) {
|
|
|
|
|
fvalue[i] = projection_transpose(ProjectionTransform(value[i]));
|
|
|
|
|
}
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(
|
|
|
|
|
*current_group, uname, array_typedesc(TypeMatrix, fvalue.size()), fvalue.data());
|
2016-05-07 19:48:28 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case SocketType::CLOSURE:
|
|
|
|
|
case SocketType::NODE:
|
|
|
|
|
case SocketType::NODE_ARRAY:
|
2023-05-24 13:36:13 +02:00
|
|
|
case SocketType::UINT:
|
|
|
|
|
case SocketType::UINT64:
|
2016-05-07 19:48:28 +02:00
|
|
|
case SocketType::UNDEFINED:
|
2023-05-24 13:36:13 +02:00
|
|
|
case SocketType::NUM_TYPES: {
|
2016-05-07 19:48:28 +02:00
|
|
|
assert(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void OSLCompiler::parameter(const char *name, const float f)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeFloat, &f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void OSLCompiler::parameter_color(const char *name, const float3 f)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeColor, &f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void OSLCompiler::parameter_point(const char *name, const float3 f)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, TypePoint, &f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void OSLCompiler::parameter_normal(const char *name, const float3 f)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeNormal, &f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void OSLCompiler::parameter_vector(const char *name, const float3 f)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeVector, &f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void OSLCompiler::parameter(const char *name, const int f)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeInt, &f);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OSLCompiler::parameter(const char *name, const char *s)
|
|
|
|
|
{
|
2024-12-26 17:53:59 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeString, (const void *)&s);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OSLCompiler::parameter(const char *name, ustring s)
|
|
|
|
|
{
|
|
|
|
|
const char *str = s.c_str();
|
2024-12-26 17:53:59 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeString, (const void *)&str);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OSLCompiler::parameter(const char *name, const Transform &tfm)
|
|
|
|
|
{
|
2018-03-08 06:48:14 +01:00
|
|
|
ProjectionTransform projection(tfm);
|
|
|
|
|
projection = projection_transpose(projection);
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, TypeMatrix, (float *)&projection);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
2012-09-15 15:41:37 +00:00
|
|
|
void OSLCompiler::parameter_array(const char *name, const float f[], int arraylen)
|
|
|
|
|
{
|
2024-10-17 19:48:38 +02:00
|
|
|
TypeDesc type = TypeFloat;
|
2012-09-15 15:41:37 +00:00
|
|
|
type.arraylen = arraylen;
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, type, f);
|
2012-09-15 15:41:37 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-08 01:54:35 +02:00
|
|
|
void OSLCompiler::parameter_color_array(const char *name, const array<float3> &f)
|
2012-09-15 15:41:37 +00:00
|
|
|
{
|
2021-07-21 13:05:39 +10:00
|
|
|
/* NOTE: cycles float3 type is actually 4 floats! need to use an explicit array. */
|
2016-05-08 01:54:35 +02:00
|
|
|
array<float[3]> table(f.size());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2016-05-08 01:54:35 +02:00
|
|
|
for (int i = 0; i < f.size(); ++i) {
|
|
|
|
|
table[i][0] = f[i].x;
|
|
|
|
|
table[i][1] = f[i].y;
|
|
|
|
|
table[i][2] = f[i].z;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-10-17 19:48:38 +02:00
|
|
|
TypeDesc type = TypeColor;
|
2016-05-08 01:54:35 +02:00
|
|
|
type.arraylen = table.size();
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->Parameter(*current_group, name, type, table.data());
|
2012-09-15 15:41:37 +00:00
|
|
|
}
|
|
|
|
|
|
2018-02-18 03:20:39 +01:00
|
|
|
void OSLCompiler::parameter_attribute(const char *name, ustring s)
|
|
|
|
|
{
|
2024-12-26 17:53:59 +01:00
|
|
|
if (Attribute::name_standard(s.c_str())) {
|
2018-02-18 03:20:39 +01:00
|
|
|
parameter(name, (string("geom:") + s.c_str()).c_str());
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2018-02-18 03:20:39 +01:00
|
|
|
parameter(name, s.c_str());
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2018-02-18 03:20:39 +01:00
|
|
|
}
|
|
|
|
|
|
2015-11-25 13:07:29 +05:00
|
|
|
void OSLCompiler::find_dependencies(ShaderNodeSet &dependencies, ShaderInput *input)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2024-12-26 17:53:55 +01:00
|
|
|
ShaderNode *node = (input->link) ? input->link->parent : nullptr;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2024-12-26 17:53:55 +01:00
|
|
|
if (node != nullptr && dependencies.find(node) == dependencies.end()) {
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderInput *in : node->inputs) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (!node_skip_input(node, in)) {
|
2011-04-27 11:58:34 +00:00
|
|
|
find_dependencies(dependencies, in);
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2024-12-26 19:41:25 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
|
dependencies.insert(node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-25 13:07:29 +05:00
|
|
|
void OSLCompiler::generate_nodes(const ShaderNodeSet &nodes)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2015-11-25 13:07:29 +05:00
|
|
|
ShaderNodeSet done;
|
2011-04-27 11:58:34 +00:00
|
|
|
bool nodes_done;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
do {
|
|
|
|
|
nodes_done = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderNode *node : nodes) {
|
2011-04-27 11:58:34 +00:00
|
|
|
if (done.find(node) == done.end()) {
|
|
|
|
|
bool inputs_done = true;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 19:41:25 +01:00
|
|
|
for (ShaderInput *input : node->inputs) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (!node_skip_input(node, input)) {
|
|
|
|
|
if (input->link && done.find(input->link->parent) == done.end()) {
|
2011-04-27 11:58:34 +00:00
|
|
|
inputs_done = false;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
}
|
2024-12-26 19:41:25 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if (inputs_done) {
|
|
|
|
|
node->compile(*this);
|
|
|
|
|
done.insert(node);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2014-03-29 13:03:48 +01:00
|
|
|
if (current_type == SHADER_TYPE_SURFACE) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node->has_surface_transparent()) {
|
2014-03-29 13:03:48 +01:00
|
|
|
current_shader->has_surface_transparent = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
if (node->get_feature() & KERNEL_FEATURE_NODE_RAYTRACE) {
|
Cycles: merge of cycles-x branch, a major update to the renderer
This includes much improved GPU rendering performance, viewport interactivity,
new shadow catcher, revamped sampling settings, subsurface scattering anisotropy,
new GPU volume sampling, improved PMJ sampling pattern, and more.
Some features have also been removed or changed, breaking backwards compatibility.
Including the removal of the OpenCL backend, for which alternatives are under
development.
Release notes and code docs:
https://wiki.blender.org/wiki/Reference/Release_Notes/3.0/Cycles
https://wiki.blender.org/wiki/Source/Render/Cycles
Credits:
* Sergey Sharybin
* Brecht Van Lommel
* Patrick Mours (OptiX backend)
* Christophe Hery (subsurface scattering anisotropy)
* William Leeson (PMJ sampling pattern)
* Alaska (various fixes and tweaks)
* Thomas Dinges (various fixes)
For the full commit history, see the cycles-x branch. This squashes together
all the changes since intermediate changes would often fail building or tests.
Ref T87839, T87837, T87836
Fixes T90734, T89353, T80267, T80267, T77185, T69800
2021-09-20 17:59:20 +02:00
|
|
|
current_shader->has_surface_raytrace = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
if (node->has_spatial_varying()) {
|
2016-02-05 22:13:51 +01:00
|
|
|
current_shader->has_surface_spatial_varying = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2014-03-29 13:03:48 +01:00
|
|
|
if (node->has_surface_bssrdf()) {
|
|
|
|
|
current_shader->has_surface_bssrdf = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node->has_bssrdf_bump()) {
|
2014-03-29 13:03:48 +01:00
|
|
|
current_shader->has_bssrdf_bump = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2014-03-29 13:03:48 +01:00
|
|
|
}
|
2017-08-20 03:25:13 +02:00
|
|
|
if (node->has_bump()) {
|
|
|
|
|
current_shader->has_bump = true;
|
|
|
|
|
}
|
2013-08-18 14:15:57 +00:00
|
|
|
}
|
2014-04-04 13:20:46 +02:00
|
|
|
else if (current_type == SHADER_TYPE_VOLUME) {
|
2024-12-26 17:53:59 +01:00
|
|
|
if (node->has_spatial_varying()) {
|
2016-02-05 21:33:37 +01:00
|
|
|
current_shader->has_volume_spatial_varying = true;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2014-04-04 13:20:46 +02:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
nodes_done = false;
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (!nodes_done);
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-07 13:15:30 +05:00
|
|
|
OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType type)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
|
current_type = type;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-11-10 19:27:07 +01:00
|
|
|
/* Use name hash to identify shader group to avoid issues with non-alphanumeric characters */
|
2023-08-12 10:52:56 +03:00
|
|
|
std::stringstream name;
|
2022-11-10 19:27:07 +01:00
|
|
|
name.imbue(std::locale("C"));
|
|
|
|
|
name << "shader_" << shader->name.hash();
|
2022-11-09 14:25:32 +01:00
|
|
|
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
current_group = ss->ShaderGroupBegin(name.str());
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
ShaderNode *output = graph->output();
|
2015-11-25 13:07:29 +05:00
|
|
|
ShaderNodeSet dependencies;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2011-10-12 23:03:12 +00:00
|
|
|
if (type == SHADER_TYPE_SURFACE) {
|
2011-04-27 11:58:34 +00:00
|
|
|
/* generate surface shader */
|
2011-10-12 23:03:12 +00:00
|
|
|
find_dependencies(dependencies, output->input("Surface"));
|
|
|
|
|
generate_nodes(dependencies);
|
|
|
|
|
output->compile(*this);
|
|
|
|
|
}
|
2016-08-14 11:44:25 -04:00
|
|
|
else if (type == SHADER_TYPE_BUMP) {
|
|
|
|
|
/* generate bump shader */
|
|
|
|
|
find_dependencies(dependencies, output->input("Normal"));
|
|
|
|
|
generate_nodes(dependencies);
|
|
|
|
|
output->compile(*this);
|
|
|
|
|
}
|
2011-10-12 23:03:12 +00:00
|
|
|
else if (type == SHADER_TYPE_VOLUME) {
|
|
|
|
|
/* generate volume shader */
|
|
|
|
|
find_dependencies(dependencies, output->input("Volume"));
|
2011-04-27 11:58:34 +00:00
|
|
|
generate_nodes(dependencies);
|
|
|
|
|
output->compile(*this);
|
|
|
|
|
}
|
|
|
|
|
else if (type == SHADER_TYPE_DISPLACEMENT) {
|
|
|
|
|
/* generate displacement shader */
|
|
|
|
|
find_dependencies(dependencies, output->input("Displacement"));
|
|
|
|
|
generate_nodes(dependencies);
|
|
|
|
|
output->compile(*this);
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
2011-04-27 11:58:34 +00:00
|
|
|
assert(0);
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
ss->ShaderGroupEnd(*current_group);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
return std::move(current_group);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
Cycles: Make OSL shader compilation threadsafe and multi-threaded
The original OSL Shading System API was stateful: You'd create a shader
group, configure it, and then end it. However, this means that only one
group can be created at a time. Further, since Cycles reuses the
Shading System for multiple instances (e.g. viewport render and
material preview), a process-wide mutex is needed.
However, for years now OSL has had a better interface, where you
explicitly provide the group you refer to. With this, we can not only
get rid of the mutex, but actually multi-thread the shader setup even
within one instance.
Realistically, most time is still spent in the JIT stage, but it's
still better than nothing.
Pull Request: https://projects.blender.org/blender/blender/pulls/130133
2024-12-09 14:36:35 +01:00
|
|
|
void OSLCompiler::compile(Shader *shader)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2020-11-04 11:17:38 +01:00
|
|
|
if (shader->is_modified()) {
|
2024-12-29 23:13:45 +01:00
|
|
|
ShaderGraph *graph = shader->graph.get();
|
2024-12-26 17:53:55 +01:00
|
|
|
ShaderNode *output = (graph) ? graph->output() : nullptr;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-29 17:32:00 +01:00
|
|
|
const bool has_bump = (shader->get_displacement_method() != DISPLACE_TRUE) &&
|
|
|
|
|
output->input("Surface")->link && output->input("Displacement")->link;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
/* finalize */
|
2023-07-12 12:36:31 +02:00
|
|
|
shader->graph->finalize(scene, has_bump, shader->get_displacement_method() == DISPLACE_BOTH);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
current_shader = shader;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
shader->has_surface = false;
|
|
|
|
|
shader->has_surface_transparent = false;
|
2023-01-27 15:58:03 +01:00
|
|
|
shader->has_surface_raytrace = false;
|
2013-04-01 20:26:52 +00:00
|
|
|
shader->has_surface_bssrdf = false;
|
2017-08-20 14:02:16 +02:00
|
|
|
shader->has_bump = has_bump;
|
|
|
|
|
shader->has_bssrdf_bump = has_bump;
|
2012-11-03 14:32:35 +00:00
|
|
|
shader->has_volume = false;
|
|
|
|
|
shader->has_displacement = false;
|
2016-02-05 22:13:51 +01:00
|
|
|
shader->has_surface_spatial_varying = false;
|
2016-02-05 21:33:37 +01:00
|
|
|
shader->has_volume_spatial_varying = false;
|
2020-03-07 14:38:52 +01:00
|
|
|
shader->has_volume_attribute_dependency = false;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
/* generate surface shader */
|
2021-05-02 02:34:56 +02:00
|
|
|
if (shader->reference_count() && graph && output->input("Surface")->link) {
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->osl_surface_ref = compile_type(shader, shader->graph.get(), SHADER_TYPE_SURFACE);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-12-26 17:53:59 +01:00
|
|
|
if (has_bump) {
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->osl_surface_bump_ref = compile_type(shader, shader->graph.get(), SHADER_TYPE_BUMP);
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
|
|
|
|
else {
|
2016-08-14 11:44:25 -04:00
|
|
|
shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
shader->has_surface = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2016-01-07 13:15:30 +05:00
|
|
|
shader->osl_surface_ref = OSL::ShaderGroupRef();
|
|
|
|
|
shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
/* generate volume shader */
|
2021-05-02 02:34:56 +02:00
|
|
|
if (shader->reference_count() && graph && output->input("Volume")->link) {
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->osl_volume_ref = compile_type(shader, shader->graph.get(), SHADER_TYPE_VOLUME);
|
2012-11-03 14:32:35 +00:00
|
|
|
shader->has_volume = true;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
2016-01-07 13:15:30 +05:00
|
|
|
shader->osl_volume_ref = OSL::ShaderGroupRef();
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
/* generate displacement shader */
|
2021-05-02 02:34:56 +02:00
|
|
|
if (shader->reference_count() && graph && output->input("Displacement")->link) {
|
2024-12-29 23:13:45 +01:00
|
|
|
shader->osl_displacement_ref = compile_type(
|
|
|
|
|
shader, shader->graph.get(), SHADER_TYPE_DISPLACEMENT);
|
2012-11-03 14:32:35 +00:00
|
|
|
shader->has_displacement = true;
|
|
|
|
|
}
|
2024-12-26 17:53:59 +01:00
|
|
|
else {
|
2016-01-07 13:15:30 +05:00
|
|
|
shader->osl_displacement_ref = OSL::ShaderGroupRef();
|
2024-12-26 17:53:59 +01:00
|
|
|
}
|
2022-11-30 20:50:11 +01:00
|
|
|
|
|
|
|
|
/* Estimate emission for MIS. */
|
|
|
|
|
shader->estimate_emission();
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-02 15:45:31 +02:00
|
|
|
void OSLCompiler::parameter_texture(const char *name, ustring filename, ustring colorspace)
|
2019-05-02 12:40:24 +02:00
|
|
|
{
|
2019-05-02 15:45:31 +02:00
|
|
|
/* Textured loaded through the OpenImageIO texture cache. For this
|
|
|
|
|
* case we need to do runtime color space conversion. */
|
2024-12-29 23:13:45 +01:00
|
|
|
OSLTextureHandle handle(OSLTextureHandle::OIIO);
|
|
|
|
|
handle.processor = ColorSpaceManager::get_processor(colorspace);
|
2023-08-10 20:01:09 +02:00
|
|
|
services->textures.insert(OSLUStringHash(filename), handle);
|
2019-05-02 15:45:31 +02:00
|
|
|
parameter(name, filename);
|
|
|
|
|
}
|
2019-05-02 12:40:24 +02:00
|
|
|
|
2022-05-11 20:11:44 -07:00
|
|
|
void OSLCompiler::parameter_texture(const char *name, const ImageHandle &handle)
|
2019-05-02 15:45:31 +02:00
|
|
|
{
|
|
|
|
|
/* Texture loaded through SVM image texture system. We generate a unique
|
|
|
|
|
* name, which ends up being used in OSLRenderServices::get_texture_handle
|
2019-05-14 12:13:43 +02:00
|
|
|
* to get handle again. Note that this name must be unique between multiple
|
|
|
|
|
* render sessions as the render services are shared. */
|
2024-12-29 17:32:00 +01:00
|
|
|
const ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
|
2023-08-10 20:01:09 +02:00
|
|
|
services->textures.insert(OSLUStringHash(filename),
|
2024-12-29 23:13:45 +01:00
|
|
|
OSLTextureHandle(OSLTextureHandle::SVM, handle.get_svm_slots()));
|
2019-05-02 12:40:24 +02:00
|
|
|
parameter(name, filename);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-01 18:15:54 +01:00
|
|
|
void OSLCompiler::parameter_texture_ies(const char *name, const int svm_slot)
|
2019-05-02 12:40:24 +02:00
|
|
|
{
|
2019-05-02 15:45:31 +02:00
|
|
|
/* IES light textures stored in SVM. */
|
2024-12-29 17:32:00 +01:00
|
|
|
const ustring filename(string_printf("@svm%d", texture_shared_unique_id++).c_str());
|
2023-08-10 20:01:09 +02:00
|
|
|
services->textures.insert(OSLUStringHash(filename),
|
2024-12-29 23:13:45 +01:00
|
|
|
OSLTextureHandle(OSLTextureHandle::IES, svm_slot));
|
2019-05-02 12:40:24 +02:00
|
|
|
parameter(name, filename);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
#else
|
|
|
|
|
|
2025-03-04 17:27:10 +01:00
|
|
|
OSLManager::OSLManager(Device *device) {}
|
|
|
|
|
OSLManager::~OSLManager() {}
|
|
|
|
|
|
|
|
|
|
void OSLManager::free_memory() {}
|
|
|
|
|
void OSLManager::reset(Scene *scene) {}
|
|
|
|
|
|
|
|
|
|
void OSLManager::device_update_pre(Device *device, Scene *scene) {}
|
|
|
|
|
void OSLManager::device_update_post(Device *device, Scene *scene, Progress &progress) {}
|
|
|
|
|
void OSLManager::device_free(Device *device, DeviceScene *dscene, Scene *scene) {}
|
|
|
|
|
|
|
|
|
|
void OSLManager::tag_update() {}
|
|
|
|
|
bool OSLManager::need_update() const
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::add(ShaderNode * /*node*/, const char * /*name*/, bool /*isfilepath*/) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter(ShaderNode * /*node*/, const char * /*name*/) {}
|
2016-05-07 19:48:28 +02:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter(const char * /*name*/, float /*f*/) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter_color(const char * /*name*/, float3 /*f*/) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter_vector(const char * /*name*/, float3 /*f*/) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter_point(const char * /*name*/, float3 /*f*/) {}
|
2012-09-15 18:08:51 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter_normal(const char * /*name*/, float3 /*f*/) {}
|
2012-09-15 18:08:51 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter(const char * /*name*/, int /*f*/) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter(const char * /*name*/, const char * /*s*/) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter(const char * /*name*/, ustring /*s*/) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter(const char * /*name*/, const Transform & /*tfm*/) {}
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter_array(const char * /*name*/, const float /*f*/[], int /*arraylen*/) {}
|
2012-09-15 16:31:11 +00:00
|
|
|
|
2023-03-29 16:50:54 +02:00
|
|
|
void OSLCompiler::parameter_color_array(const char * /*name*/, const array<float3> & /*f*/) {}
|
2012-09-15 16:31:11 +00:00
|
|
|
|
2024-03-09 23:40:57 +11:00
|
|
|
void OSLCompiler::parameter_texture(const char * /*name*/,
|
|
|
|
|
ustring /*filename*/,
|
|
|
|
|
ustring /*colorspace*/)
|
2019-05-02 15:45:31 +02:00
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-09 23:40:57 +11:00
|
|
|
void OSLCompiler::parameter_texture(const char * /*name*/, const ImageHandle & /*handle*/) {}
|
2019-05-02 12:40:24 +02:00
|
|
|
|
2024-03-09 23:40:57 +11:00
|
|
|
void OSLCompiler::parameter_texture_ies(const char * /*name*/, int /*svm_slot*/) {}
|
2019-05-02 12:40:24 +02:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
#endif /* WITH_OSL */
|
|
|
|
|
|
|
|
|
|
CCL_NAMESPACE_END
|