7#if defined(WITH_OPENCOLORIO)
12# include <fmt/format.h>
34std::unique_ptr<Config> LibOCIOConfig::create_from_environment()
37 OCIO_NAMESPACE::ConstConfigRcPtr ocio_config = OCIO_NAMESPACE::Config::CreateFromEnv();
42 return std::unique_ptr<LibOCIOConfig>(
new LibOCIOConfig(ocio_config));
44 catch (OCIO_NAMESPACE::Exception &exception) {
45 report_exception(exception);
51std::unique_ptr<Config> LibOCIOConfig::create_from_file(
const StringRefNull filename)
54 OCIO_NAMESPACE::ConstConfigRcPtr ocio_config = OCIO_NAMESPACE::Config::CreateFromFile(
60 return std::unique_ptr<LibOCIOConfig>(
new LibOCIOConfig(ocio_config));
62 catch (OCIO_NAMESPACE::Exception &exception) {
63 report_exception(exception);
69LibOCIOConfig::LibOCIOConfig(
const OCIO_NAMESPACE::ConstConfigRcPtr &ocio_config)
78 OCIO_NAMESPACE::SetCurrentConfig(ocio_config);
79 ocio_config_ = OCIO_NAMESPACE::GetCurrentConfig();
81 initialize_active_color_spaces();
82 initialize_inactive_color_spaces();
83 initialize_hdr_color_spaces();
85 initialize_displays();
88LibOCIOConfig::~LibOCIOConfig() {}
90void LibOCIOConfig::initialize_active_color_spaces()
92 OCIO_NAMESPACE::ColorSpaceSetRcPtr ocio_color_spaces;
95 ocio_color_spaces = ocio_config_->getColorSpaces(
nullptr);
97 catch (OCIO_NAMESPACE::Exception &exception) {
98 report_exception(exception);
102 if (!ocio_color_spaces) {
103 report_error(
"Invalid OpenColorIO configuration: color spaces set is nullptr");
107 const int num_color_spaces = ocio_color_spaces->getNumColorSpaces();
108 if (num_color_spaces < 0) {
109 report_error(fmt::format(
110 "Invalid OpenColorIO configuration: invalid number of color spaces {}", num_color_spaces));
114 color_spaces_.reserve(num_color_spaces);
116 for (
const int i : IndexRange(num_color_spaces)) {
117 const OCIO_NAMESPACE::ConstColorSpaceRcPtr ocio_color_space =
118 ocio_color_spaces->getColorSpaceByIndex(
i);
119 color_spaces_.append_as(
i, ocio_config_, ocio_color_space);
123 sorted_color_space_index_.resize(num_color_spaces);
124 std::iota(sorted_color_space_index_.begin(), sorted_color_space_index_.end(), 0);
125 std::sort(sorted_color_space_index_.begin(), sorted_color_space_index_.end(), [&](
int a,
int b) {
126 return color_spaces_[a].name() < color_spaces_[b].name();
130void LibOCIOConfig::initialize_inactive_color_spaces()
132 const int num_inactive_color_spaces = ocio_config_->getNumColorSpaces(
133 OCIO_NAMESPACE::SEARCH_REFERENCE_SPACE_ALL, OCIO_NAMESPACE::COLORSPACE_INACTIVE);
134 if (num_inactive_color_spaces < 0) {
135 report_error(fmt::format(
136 "Invalid OpenColorIO configuration: invalid number of inactive color spaces {}",
137 num_inactive_color_spaces));
141 for (
const int i : IndexRange(num_inactive_color_spaces)) {
142 const char *colorspace_name = ocio_config_->getColorSpaceNameByIndex(
143 OCIO_NAMESPACE::SEARCH_REFERENCE_SPACE_ALL, OCIO_NAMESPACE::COLORSPACE_INACTIVE,
i);
145 OCIO_NAMESPACE::ConstColorSpaceRcPtr ocio_color_space;
147 ocio_color_space = ocio_config_->getColorSpace(colorspace_name);
149 catch (OCIO_NAMESPACE::Exception &exception) {
150 report_exception(exception);
154 inactive_color_spaces_.append_as(
i, ocio_config_, ocio_color_space);
158void LibOCIOConfig::initialize_looks()
160 const int num_looks = ocio_config_->getNumLooks();
162 looks_.reserve(num_looks + 1);
165 looks_.append_as(0,
nullptr);
167 for (
const int i : IndexRange(num_looks)) {
168 const StringRefNull view_name = ocio_config_->getLookNameByIndex(
i);
171 if (view_name ==
"None") {
175 const OCIO_NAMESPACE::ConstLookRcPtr ocio_look = ocio_config_->getLook(view_name.
c_str());
176 looks_.append_as(
i + 1, ocio_look);
180void LibOCIOConfig::initialize_displays()
182 const int num_displays = ocio_config_->getNumDisplays();
183 if (num_displays < 0) {
184 report_error(fmt::format(
"Invalid OpenColorIO configuration: invalid number of displays {}",
189 displays_.reserve(num_displays);
191 for (
const int i : IndexRange(num_displays)) {
192 displays_.append_as(
i, *
this);
202float3 LibOCIOConfig::get_default_luma_coefs()
const
205 double rgb_double[3];
206 ocio_config_->getDefaultLumaCoefs(rgb_double);
208 return float3(rgb_double[0], rgb_double[1], rgb_double[2]);
210 catch (OCIO_NAMESPACE::Exception &exception) {
211 report_exception(exception);
216 return float3(0.2126f, 0.7152f, 0.0722f);
219static bool to_scene_linear_matrix(
const OCIO_NAMESPACE::ConstConfigRcPtr &ocio_config,
220 const StringRefNull colorspace,
223 const OCIO_NAMESPACE::ConstProcessorRcPtr processor = create_ocio_processor(
224 ocio_config, colorspace.
c_str(), OCIO_NAMESPACE::ROLE_SCENE_LINEAR);
229 const OCIO_NAMESPACE::ConstCPUProcessorRcPtr cpu_processor = processor->getDefaultCPUProcessor();
231 cpu_processor->applyRGB(to_scene_linear[0]);
232 cpu_processor->applyRGB(to_scene_linear[1]);
233 cpu_processor->applyRGB(to_scene_linear[2]);
238float3x3 LibOCIOConfig::get_xyz_to_scene_linear_matrix()
const
245 if (!ocio_config_->hasRole(OCIO_NAMESPACE::ROLE_SCENE_LINEAR)) {
249 if (ocio_config_->hasRole(
"aces_interchange")) {
252 if (to_scene_linear_matrix(ocio_config_,
"aces_interchange", aces_to_scene_linear)) {
257 else if (ocio_config_->hasRole(
"XYZ")) {
259 to_scene_linear_matrix(ocio_config_,
"XYZ", xyz_to_scene_linear);
265const char *LibOCIOConfig::get_color_space_from_filepath(
const char *filepath)
const
273 if (ocio_config_->filepathOnlyMatchesDefaultRule(filepath)) {
277 return ocio_config_->getColorSpaceFromFilepath(filepath);
286const ColorSpace *LibOCIOConfig::get_color_space(
const StringRefNull
name)
const
288 OCIO_NAMESPACE::ConstColorSpaceRcPtr ocio_color_space;
292 ocio_color_space = ocio_config_->getColorSpace(
name.c_str());
294 catch (OCIO_NAMESPACE::Exception &exception) {
295 report_exception(exception);
299 if (!ocio_color_space) {
306 for (
const LibOCIOColorSpace &color_space : color_spaces_) {
307 if (color_space.name() == ocio_color_space->getName()) {
314 for (
const LibOCIOColorSpace &color_space : inactive_color_spaces_) {
315 if (color_space.name() == ocio_color_space->getName()) {
320 if (!ocio_config_->isInactiveColorSpace(ocio_color_space->getName())) {
322 fmt::format(
"Invalid OpenColorIO configuration: color space {} not found on Blender side",
323 ocio_color_space->getName()));
329int LibOCIOConfig::get_num_color_spaces()
const
331 return color_spaces_.size();
334const ColorSpace *LibOCIOConfig::get_color_space_by_index(
int const index)
const
336 if (index < 0 || index >= color_spaces_.size()) {
339 return &color_spaces_[index];
342const ColorSpace *LibOCIOConfig::get_sorted_color_space_by_index(
const int index)
const
344 BLI_assert(color_spaces_.size() == sorted_color_space_index_.size());
345 if (index < 0 || index >= color_spaces_.size()) {
348 return get_color_space_by_index(sorted_color_space_index_[index]);
351const ColorSpace *LibOCIOConfig::get_color_space_by_interop_id(StringRefNull interop_id)
const
353 for (
const LibOCIOColorSpace &color_space : color_spaces_) {
354 if (color_space.interop_id() == interop_id) {
359 for (
const LibOCIOColorSpace &color_space : inactive_color_spaces_) {
360 if (color_space.interop_id() == interop_id) {
374const ColorSpace *LibOCIOConfig::get_color_space_for_hdr_image(StringRefNull
name)
const
379 if (colorspece->
interop_id() ==
"pq_rec2020_display") {
380 return get_color_space(
"blender:pq_rec2020_display_203nits");
382 if (colorspece->
interop_id() ==
"hlg_rec2020_display") {
383 return get_color_space(
"blender:hlg_rec2020_display_203nits");
388void LibOCIOConfig::initialize_hdr_color_spaces()
390 for (StringRefNull interop_id : {
"pq_rec2020_display",
"hlg_rec2020_display"}) {
391 const auto *colorspace =
static_cast<const LibOCIOColorSpace *
>(
392 get_color_space_by_interop_id(interop_id));
393 if (!colorspace || !colorspace->is_display_referred()) {
398 const auto hdr_100_colorspace = ocio_config_->getColorSpace(colorspace->name().
c_str());
399 const auto hdr_colorspace = OCIO_NAMESPACE::ColorSpace::Create(
400 OCIO_NAMESPACE::REFERENCE_SPACE_DISPLAY);
401 const auto group = OCIO_NAMESPACE::GroupTransform::Create();
403 hdr_colorspace->setName((
"blender:" + interop_id +
"_203nits").c_str());
405 const auto to_203_nits = OCIO_NAMESPACE::MatrixTransform::Create();
407 group->appendTransform(to_203_nits);
409 const auto to_display = hdr_100_colorspace
410 ->getTransform(OCIO_NAMESPACE::COLORSPACE_DIR_FROM_REFERENCE)
411 ->createEditableCopy();
412 group->appendTransform(to_display);
414 hdr_colorspace->setTransform(group, OCIO_NAMESPACE::COLORSPACE_DIR_FROM_REFERENCE);
416 OCIO_NAMESPACE::Config *mutable_ocio_config =
const_cast<OCIO_NAMESPACE::Config *
>(
418 mutable_ocio_config->addColorSpace(hdr_colorspace);
420 inactive_color_spaces_.append_as(inactive_color_spaces_.size(), ocio_config_, hdr_colorspace);
430void LibOCIOConfig::set_scene_linear_role(StringRefNull
name)
432 if (ocio_config_->getRoleColorSpace(OCIO_NAMESPACE::ROLE_SCENE_LINEAR) ==
name) {
438 OCIO_NAMESPACE::Config *mutable_ocio_config =
const_cast<OCIO_NAMESPACE::Config *
>(
440 mutable_ocio_config->setRole(OCIO_NAMESPACE::ROLE_SCENE_LINEAR,
name.c_str());
442 for (LibOCIOColorSpace &color_space : color_spaces_) {
443 color_space.clear_caches();
445 for (LibOCIOColorSpace &color_space : inactive_color_spaces_) {
446 color_space.clear_caches();
448 for (LibOCIODisplay &display : displays_) {
449 display.clear_caches();
451 gpu_shader_binder_.clear_caches();
460const Display *LibOCIOConfig::get_default_display()
const
462 if (displays_.is_empty()) {
467 return &displays_[0];
470const Display *LibOCIOConfig::get_display_by_name(
const StringRefNull
name)
const
473 for (
const LibOCIODisplay &display : displays_) {
474 if (display.name() ==
name) {
481int LibOCIOConfig::get_num_displays()
const
483 return displays_.size();
486const Display *LibOCIOConfig::get_display_by_index(
int index)
const
488 if (index < 0 || index >= displays_.size()) {
491 return &displays_[index];
500const ColorSpace *LibOCIOConfig::get_display_view_color_space(
const StringRefNull display,
501 const StringRefNull
view)
const
503 StringRefNull display_color_space;
506 display_color_space = ocio_config_->getDisplayViewColorSpaceName(display.
c_str(),
509 if (strcasecmp(display_color_space.
c_str(),
"<USE_DISPLAY_NAME>") == 0) {
510 display_color_space = display;
513 catch (OCIO_NAMESPACE::Exception &exception) {
514 report_exception(exception);
515 display_color_space = display;
518 return get_color_space(display_color_space);
527const Look *LibOCIOConfig::get_look_by_name(
const StringRefNull
name)
const
530 for (
const LibOCIOLook &look : looks_) {
531 if (look.name() ==
name) {
538int LibOCIOConfig::get_num_looks()
const
540 return looks_.size();
543const Look *LibOCIOConfig::get_look_by_index(
const int index)
const
545 if (index < 0 || index >= looks_.size()) {
548 return &looks_[index];
557std::shared_ptr<const CPUProcessor> LibOCIOConfig::get_display_cpu_processor(
560 OCIO_NAMESPACE::ConstProcessorRcPtr processor = create_ocio_display_processor(
561 *
this, display_parameters);
565 return std::make_shared<LibOCIOCPUProcessor>(processor->getDefaultCPUProcessor());
568std::shared_ptr<const CPUProcessor> LibOCIOConfig::get_cpu_processor(
569 const StringRefNull from_colorspace,
const StringRefNull to_colorspace)
const
571 const OCIO_NAMESPACE::ConstProcessorRcPtr processor = create_ocio_processor(
572 ocio_config_, from_colorspace.
c_str(), to_colorspace.
c_str());
576 return std::make_shared<LibOCIOCPUProcessor>(processor->getDefaultCPUProcessor());
587 return gpu_shader_binder_;
constexpr const char * c_str() const
virtual StringRefNull interop_id() const =0
BLI_INLINE ColorSceneLinear4f< eAlpha::Straight > to_scene_linear(const ColorTheme4f &theme4f)
float3x3 aces_to_scene_linear
float3x3 xyz_to_scene_linear
CartesianBasis invert(const CartesianBasis &basis)
static const float3x3 ACES_TO_XYZ
static const float3x3 XYZ_TO_REC709
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
MatBase< double, 4, 4 > double4x4
static MatBase diagonal(double value)
static MatBase identity()