Refactor: Color Management: Determine gamut and transfer function for views

Ref #144911

Pull Request: https://projects.blender.org/blender/blender/pulls/145025
This commit is contained in:
Brecht Van Lommel
2025-08-23 09:38:38 +02:00
parent 14bd7a531f
commit b5769044d4
9 changed files with 121 additions and 40 deletions

View File

@@ -2836,7 +2836,7 @@ bool IMB_colormanagement_display_is_wide_gamut(const ColorManagedDisplaySettings
return false;
}
const ocio::View *view = display->get_view_by_name(view_name);
return (view) ? view->is_wide_gamut() : false;
return (view) ? view->gamut() != ocio::Gamut::Rec709 : false;
}
/** \} */

View File

@@ -8,6 +8,25 @@
namespace blender::ocio {
enum class Gamut {
Unknown,
Rec709, /* sRGB primaries + D65 white point. */
P3D65, /* DCI-P3 primaries + D65 white point. */
Rec2020, /* Rec.2020 primaries + D65 white point */
};
enum class TransferFunction {
Unknown,
sRGB, /* Piecewise sRGB */
ExtendedsRGB, /* Piecewise sRGB, unclipped for wide gamut */
Gamma18, /* Pure Gamma 1.8 */
Gamma22, /* Pure Gamma 2.2 */
Gamma24, /* Pure Gamma 2.4 */
Gamma26, /* Pure Gamma 2.6 */
PQ, /* PQ from Rec.2100 */
HLG, /* HLG from Rec.2100 */
};
class View {
public:
virtual ~View() = default;
@@ -30,9 +49,14 @@ class View {
virtual bool is_hdr() const = 0;
/**
* Does this view transform output wide gamut colors?
* Gamut of the display colorspace.
*/
virtual bool is_wide_gamut() const = 0;
virtual Gamut gamut() const = 0;
/**
* Transfer function of the display colorspace.
*/
virtual TransferFunction transfer_function() const = 0;
};
} // namespace blender::ocio

View File

@@ -25,9 +25,14 @@ class FallbackDefaultView : public View {
return false;
}
bool is_wide_gamut() const override
Gamut gamut() const override
{
return false;
return Gamut::Rec709;
}
TransferFunction transfer_function() const override
{
return TransferFunction::sRGB;
}
};

View File

@@ -158,6 +158,15 @@ LibOCIOColorSpace::LibOCIOColorSpace(const int index,
else if (first_alias == "rec2100_hlg_display") {
interop_id_ = "hlg_rec2020_display";
}
else if (first_alias == "lin_rec709_srgb" || first_alias == "lin_rec709") {
interop_id_ = "lin_rec709_scene";
}
else if (first_alias == "lin_rec2020") {
interop_id_ = "lin_rec2020_scene";
}
else if (first_alias == "lin_p3d65" || first_alias == "lin_displayp3") {
interop_id_ = "lin_p3d65_scene";
}
else if ((first_alias.startswith("lin_") || first_alias.startswith("srgb_") ||
first_alias.startswith("g18_") || first_alias.startswith("g22_") ||
first_alias.startswith("g24_") || first_alias.startswith("g26_") ||

View File

@@ -347,6 +347,23 @@ const ColorSpace *LibOCIOConfig::get_sorted_color_space_by_index(const int index
return get_color_space_by_index(sorted_color_space_index_[index]);
}
const ColorSpace *LibOCIOConfig::get_color_space_by_interop_id(StringRefNull interop_id) const
{
for (const LibOCIOColorSpace &color_space : color_spaces_) {
if (color_space.interop_id() == interop_id) {
return &color_space;
}
}
for (const LibOCIOColorSpace &color_space : inactive_color_spaces_) {
if (color_space.interop_id() == interop_id) {
return &color_space;
}
}
return nullptr;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -59,6 +59,7 @@ class LibOCIOConfig : public Config {
int get_num_color_spaces() const override;
const ColorSpace *get_color_space_by_index(int index) const override;
const ColorSpace *get_sorted_color_space_by_index(int index) const override;
const ColorSpace *get_color_space_by_interop_id(StringRefNull interop_id) const;
/* Display API. */
const Display *get_default_display() const override;

View File

@@ -65,11 +65,10 @@ LibOCIODisplay::LibOCIODisplay(const int index, const LibOCIOConfig &config) : c
is_hdr_ |= view_is_hdr;
}
/* Detect sRGB and wide gamut through interop ID. These are not entirely reliable,
* and are currently only used as optimization. */
bool is_wide_gamut = true;
bool is_srgb = false;
bool is_extended = false;
/* Detect gamut and transfer function through interop ID. When unknown, things
* should still work correctly but may miss optimizations. */
Gamut gamut = Gamut::Unknown;
TransferFunction transfer_function = TransferFunction::Unknown;
StringRefNull display_interop_id;
if (ocio_display_colorspace) {
@@ -81,14 +80,49 @@ LibOCIODisplay::LibOCIODisplay(const int index, const LibOCIOConfig &config) : c
}
if (!display_interop_id.is_empty()) {
is_srgb = display_interop_id == "srgb_rec709_display" ||
display_interop_id == "srgb_rec709_scene";
is_wide_gamut = !(display_interop_id.endswith("_rec709_display") ||
display_interop_id.endswith("_rec709_scene"));
is_extended = display_interop_id.startswith("srgbx_");
if (display_interop_id.endswith("_rec709_display") ||
display_interop_id.endswith("_rec709_scene"))
{
gamut = Gamut::Rec709;
}
else if (display_interop_id.endswith("_p3d65_display") ||
display_interop_id.endswith("_p3d65_scene"))
{
gamut = Gamut::P3D65;
}
else if (display_interop_id.endswith("_rec2020_display") ||
display_interop_id.endswith("_rec2020_scene"))
{
gamut = Gamut::Rec2020;
}
if (display_interop_id.startswith("srgb_")) {
transfer_function = TransferFunction::sRGB;
}
else if (display_interop_id.startswith("srgbx_")) {
transfer_function = TransferFunction::ExtendedsRGB;
}
else if (display_interop_id.startswith("pq_")) {
transfer_function = TransferFunction::PQ;
}
else if (display_interop_id.startswith("hlg_")) {
transfer_function = TransferFunction::HLG;
}
else if (display_interop_id.startswith("g18_")) {
transfer_function = TransferFunction::Gamma18;
}
else if (display_interop_id.startswith("g22_")) {
transfer_function = TransferFunction::Gamma22;
}
else if (display_interop_id.startswith("g24_")) {
transfer_function = TransferFunction::Gamma24;
}
else if (display_interop_id.startswith("g26_")) {
transfer_function = TransferFunction::Gamma26;
}
}
views_.append_as(view_index, view_name, view_is_hdr, is_wide_gamut, is_srgb, is_extended);
views_.append_as(view_index, view_name, view_is_hdr, gamut, transfer_function);
}
/* Detect untonemppaed view transform. */

View File

@@ -3,6 +3,8 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "libocio_display_processor.hh"
#include "OCIO_view.hh"
#include <OpenColorIO/OpenColorTransforms.h>
#if defined(WITH_OPENCOLORIO)
@@ -55,7 +57,7 @@ static void display_as_extended_srgb(const LibOCIOConfig &config,
/* Clamp to gamut, so that we don't display values outside of it. One exception
* is extended sRGB, where we need to preserve them for correct results and assume
* the view transform already clamped them. */
if (!(view && view->is_extended())) {
if (!(view && view->transfer_function() == TransferFunction::ExtendedsRGB)) {
auto clamp = OCIO_NAMESPACE::RangeTransform::Create();
clamp->setStyle(OCIO_NAMESPACE::RANGE_CLAMP);
clamp->setMinInValue(0.0);
@@ -66,7 +68,9 @@ static void display_as_extended_srgb(const LibOCIOConfig &config,
}
/* Nothing further to do if already using sRGB. */
if (view && view->is_srgb()) {
if (view && view->transfer_function() == TransferFunction::sRGB &&
view->gamut() == Gamut::Rec709)
{
return;
}

View File

@@ -17,22 +17,16 @@ namespace blender::ocio {
class LibOCIOView : public View {
StringRefNull name_;
bool is_hdr_ = false;
bool is_wide_gamut_ = false;
bool is_srgb_ = false;
bool is_extended_ = false;
Gamut gamut_ = Gamut::Unknown;
TransferFunction transfer_function_ = TransferFunction::Unknown;
public:
LibOCIOView(const int index,
const StringRefNull name,
const bool is_hdr,
const bool is_wide_gamut,
const bool is_srgb,
const bool is_extended)
: name_(name),
is_hdr_(is_hdr),
is_wide_gamut_(is_wide_gamut),
is_srgb_(is_srgb),
is_extended_(is_extended)
const Gamut gamut,
const TransferFunction transfer_function)
: name_(name), is_hdr_(is_hdr), gamut_(gamut), transfer_function_(transfer_function)
{
this->index = index;
}
@@ -47,21 +41,14 @@ class LibOCIOView : public View {
return is_hdr_;
}
bool is_wide_gamut() const override
Gamut gamut() const override
{
return is_wide_gamut_;
return gamut_;
}
/* Display space is exactly Rec.709 + sRGB piecewise transfer function. */
bool is_srgb() const
TransferFunction transfer_function() const override
{
return is_srgb_;
}
/* Display space has values outside of 0..1 range. */
bool is_extended() const
{
return is_extended_;
return transfer_function_;
}
MEM_CXX_CLASS_ALLOC_FUNCS("LibOCIOView");