diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp index 1a12fbcb5b4..14f006c65d8 100644 --- a/intern/cycles/scene/camera.cpp +++ b/intern/cycles/scene/camera.cpp @@ -899,6 +899,9 @@ void Camera::set_osl_camera(Scene *scene, const std::string &bytecode) { #ifdef WITH_OSL + /* Ensure shading system exists before we try to load a shader. */ + scene->osl_manager->shading_system_init(scene->shader_manager->get_scene_linear_space()); + /* Load the shader. */ const char *hash; diff --git a/intern/cycles/scene/osl.cpp b/intern/cycles/scene/osl.cpp index a85f91eb55d..fde9b0285da 100644 --- a/intern/cycles/scene/osl.cpp +++ b/intern/cycles/scene/osl.cpp @@ -124,7 +124,7 @@ bool OSLManager::need_update() const void OSLManager::device_update_pre(Device *device, Scene *scene) { if (scene->shader_manager->use_osl() || !scene->camera->script_name.empty()) { - shading_system_init(); + shading_system_init(scene->shader_manager->get_scene_linear_space()); } if (!need_update()) { @@ -343,7 +343,7 @@ void OSLManager::texture_system_free() } } -void OSLManager::shading_system_init() +void OSLManager::shading_system_init(ShaderManager::SceneLinearSpace colorspace) { /* No need to do anything if we already have shading systems. */ if (!ss_map.empty()) { @@ -353,7 +353,7 @@ void OSLManager::shading_system_init() /* create shading system, shared between different renders to reduce memory usage */ const thread_scoped_lock lock(ss_shared_mutex); - foreach_osl_device(device_, [this](Device *sub_device, OSLGlobals *) { + foreach_osl_device(device_, [this, colorspace](Device *sub_device, OSLGlobals *) { const DeviceType device_type = sub_device->info.type; if (!ss_shared[device_type]) { @@ -381,6 +381,21 @@ void OSLManager::shading_system_init() ss->attribute("searchpath:shader", shader_path); ss->attribute("greedyjit", 1); + /* OSL doesn't accept an arbitrary space, so support a few specific spaces. */ + switch (colorspace) { + case ShaderManager::SceneLinearSpace::Rec709: + ss->attribute("colorspace", OSL::Strings::Rec709); + break; + case ShaderManager::SceneLinearSpace::Rec2020: + ss->attribute("colorspace", OSL::Strings::HDTV); + break; + case ShaderManager::SceneLinearSpace::ACEScg: + ss->attribute("colorspace", OSL::Strings::ACEScg); + break; + case ShaderManager::SceneLinearSpace::Unknown: + break; + } + const char *groupdata_alloc_str = getenv("CYCLES_OSL_GROUPDATA_ALLOC"); if (groupdata_alloc_str) { ss->attribute("max_optix_groupdata_alloc", atoi(groupdata_alloc_str)); @@ -582,8 +597,6 @@ const char *OSLManager::shader_load_filepath(string filepath) const char *OSLManager::shader_load_bytecode(const string &hash, const string &bytecode) { - shading_system_init(); - foreach_shading_system( [hash, bytecode](OSL::ShadingSystem *ss) { ss->LoadMemoryCompiledShader(hash, bytecode); }); @@ -740,7 +753,10 @@ OSLNode *OSLShaderManager::osl_node(ShaderGraph *graph, return nullptr; } - /* create query */ + /* Ensure shading system exists before we try to load a shader. */ + scene->osl_manager->shading_system_init(scene->shader_manager->get_scene_linear_space()); + + /* Load shader code. */ const char *hash; if (!filepath.empty()) { diff --git a/intern/cycles/scene/osl.h b/intern/cycles/scene/osl.h index f3865aba6ee..5eb431e7dd3 100644 --- a/intern/cycles/scene/osl.h +++ b/intern/cycles/scene/osl.h @@ -79,6 +79,8 @@ class OSLManager { const char *shader_load_filepath(string filepath); OSLShaderInfo *shader_loaded_info(const string &hash); + void shading_system_init(ShaderManager::SceneLinearSpace colorspace); + OSL::ShadingSystem *get_shading_system(Device *sub_device); OSL::TextureSystem *get_texture_system(); static void foreach_osl_device(Device *device, @@ -93,7 +95,6 @@ class OSLManager { void texture_system_init(); void texture_system_free(); - void shading_system_init(); void shading_system_free(); void foreach_shading_system(const std::function &callback); diff --git a/intern/cycles/scene/shader.cpp b/intern/cycles/scene/shader.cpp index d3fa0fb7bef..69c6b1f3dd3 100644 --- a/intern/cycles/scene/shader.cpp +++ b/intern/cycles/scene/shader.cpp @@ -696,7 +696,7 @@ void ShaderManager::device_update_common(Device * /*device*/, kfilm->rec709_to_r = make_float4(rec709_to_r); kfilm->rec709_to_g = make_float4(rec709_to_g); kfilm->rec709_to_b = make_float4(rec709_to_b); - kfilm->is_rec709 = is_rec709; + kfilm->is_rec709 = scene_linear_space == SceneLinearSpace::Rec709; } void ShaderManager::device_free_common(Device * /*device*/, DeviceScene *dscene, Scene *scene) @@ -1011,7 +1011,7 @@ void ShaderManager::init_xyz_transforms() rec709_to_r = make_float3(1.0f, 0.0f, 0.0f); rec709_to_g = make_float3(0.0f, 1.0f, 0.0f); rec709_to_b = make_float3(0.0f, 0.0f, 1.0f); - is_rec709 = true; + scene_linear_space = SceneLinearSpace::Rec709; compute_thin_film_table(xyz_to_rec709); @@ -1079,9 +1079,46 @@ void ShaderManager::init_xyz_transforms() rec709_to_r = make_float3(rec709_to_rgb.x); rec709_to_g = make_float3(rec709_to_rgb.y); rec709_to_b = make_float3(rec709_to_rgb.z); - is_rec709 = transform_equal_threshold(xyz_to_rgb, xyz_to_rec709, 0.0001f); compute_thin_film_table(xyz_to_rgb); + + const Transform xyz_to_rec2020 = make_transform(1.7166512f, + -0.3556708f, + -0.2533663f, + 0.0f, + -0.6666844, + 1.6164812f, + 0.0157685f, + 0.0f, + 0.0176399f, + -0.0427706f, + 0.9421031f, + 0.0f); + const Transform acescg_to_xyz = make_transform(0.652238f, + 0.128237f, + 0.169983f, + 0.0f, + 0.267672f, + 0.674340f, + 0.057988f, + 0.0f, + -0.005382f, + 0.001369f, + 1.093071f, + 0.0f); + + if (transform_equal_threshold(xyz_to_rgb, xyz_to_rec709, 0.001f)) { + scene_linear_space = SceneLinearSpace::Rec709; + } + else if (transform_equal_threshold(xyz_to_rgb, xyz_to_rec2020, 0.001f)) { + scene_linear_space = SceneLinearSpace::Rec2020; + } + else if (transform_equal_threshold(rgb_to_xyz, acescg_to_xyz, 0.001f)) { + scene_linear_space = SceneLinearSpace::ACEScg; + } + else { + scene_linear_space = SceneLinearSpace::Unknown; + } #endif } diff --git a/intern/cycles/scene/shader.h b/intern/cycles/scene/shader.h index ecaef5cc827..7b323c30119 100644 --- a/intern/cycles/scene/shader.h +++ b/intern/cycles/scene/shader.h @@ -212,6 +212,13 @@ class ShaderManager { void init_xyz_transforms(); + enum class SceneLinearSpace { Rec709, Rec2020, ACEScg, Unknown }; + + SceneLinearSpace get_scene_linear_space() + { + return scene_linear_space; + } + protected: ShaderManager(); @@ -235,7 +242,7 @@ class ShaderManager { float3 rec709_to_r; float3 rec709_to_g; float3 rec709_to_b; - bool is_rec709; + SceneLinearSpace scene_linear_space; vector thin_film_table; template