Krita Source Code Documentation
Loading...
Searching...
No Matches
KisCanvasSurfaceColorSpaceManager Class Reference

#include <KisCanvasSurfaceColorSpaceManager.h>

+ Inheritance diagram for KisCanvasSurfaceColorSpaceManager:

Signals

void sigDisplayConfigChanged (const KisDisplayConfig &config)
 

Public Member Functions

QString colorManagementReport () const
 
KisDisplayConfig displayConfig () const
 
bool isReady () const
 
 KisCanvasSurfaceColorSpaceManager (KisSurfaceColorManagerInterface *interface, const KisConfig::CanvasSurfaceMode surfaceMode, const KisDisplayConfig::Options &options, QObject *parent=nullptr)
 
QString osPreferredColorSpaceReport () const
 
 Private (KisSurfaceColorManagerInterface *interface)
 
void setDisplayConfigOptions (const KisConfig::CanvasSurfaceMode surfaceMode, const KisDisplayConfig::Options &options)
 
void setDisplayConfigOptions (const KisDisplayConfig::Options &options)
 
 ~KisCanvasSurfaceColorSpaceManager ()
 
- Public Member Functions inherited from Private
 Private (KisCanvas2 *c)
 

Static Public Member Functions

static KisSurfaceColorimetry::RenderIntent calculateConfigIntent (const KisDisplayConfig::Options &options)
 

Public Attributes

KisDisplayConfig currentConfig
 
QScopedPointer< KisSurfaceColorManagerInterfaceinterface
 
std::optional< KisSurfaceColorimetry::RenderIntentproofingIntentOverride
 
KisConfig::CanvasSurfaceMode surfaceMode = KisConfig::CanvasSurfaceMode::Preferred
 
- Public Attributes inherited from Private
KisCanvas2canvas
 
int displayedFrame
 
int intendedFrame
 

Private Slots

void slotInterfacePreferredDescriptionChanged ()
 
void slotInterfaceReadyChanged (bool isReady)
 

Private Member Functions

void reinitializeSurfaceDescription (const KisDisplayConfig::Options &newOptions)
 

Private Attributes

QScopedPointer< Privatem_d
 

Detailed Description

Definition at line 20 of file KisCanvasSurfaceColorSpaceManager.cpp.

Constructor & Destructor Documentation

◆ KisCanvasSurfaceColorSpaceManager()

KisCanvasSurfaceColorSpaceManager::KisCanvasSurfaceColorSpaceManager ( KisSurfaceColorManagerInterface * interface,
const KisConfig::CanvasSurfaceMode surfaceMode,
const KisDisplayConfig::Options & options,
QObject * parent = nullptr )

Definition at line 32 of file KisCanvasSurfaceColorSpaceManager.cpp.

36 : QObject(parent)
37 , m_d(new Private(interface))
38{
39 m_d->currentConfig.profile = KoColorSpaceRegistry::instance()->p709SRGBProfile();
40 m_d->currentConfig.setOptions(options);
41 m_d->currentConfig.isHDR = false;
42 m_d->surfaceMode = surfaceMode;
43
46
47 if (m_d->interface->isReady()) {
49 }
50}
void sigReadyChanged(bool value)
void sigPreferredSurfaceDescriptionChanged(const KisSurfaceColorimetry::SurfaceDescription &desc)
QScopedPointer< KisSurfaceColorManagerInterface > interface
static KoColorSpaceRegistry * instance()
const KoColorProfile * p709SRGBProfile() const

References KoColorSpaceRegistry::instance(), m_d, KoColorSpaceRegistry::p709SRGBProfile(), KisSurfaceColorManagerInterface::sigPreferredSurfaceDescriptionChanged(), KisSurfaceColorManagerInterface::sigReadyChanged(), slotInterfacePreferredDescriptionChanged(), slotInterfaceReadyChanged(), and surfaceMode.

◆ ~KisCanvasSurfaceColorSpaceManager()

KisCanvasSurfaceColorSpaceManager::~KisCanvasSurfaceColorSpaceManager ( )

Definition at line 52 of file KisCanvasSurfaceColorSpaceManager.cpp.

53{
54}

Member Function Documentation

◆ calculateConfigIntent()

static KisSurfaceColorimetry::RenderIntent KisCanvasSurfaceColorSpaceManager::calculateConfigIntent ( const KisDisplayConfig::Options & options)
static

◆ colorManagementReport()

QString KisCanvasSurfaceColorSpaceManager::colorManagementReport ( ) const

Definition at line 56 of file KisCanvasSurfaceColorSpaceManager.cpp.

57{
58 QString report;
59 QDebug str(&report);
60
61 if (!m_d->interface->isReady()) {
62 str << "WARNING: surface color management interface is not ready!" << Qt::endl;
63 str << Qt::endl;
64 }
65
70
71 str << "Configured mode:" << m_d->surfaceMode << Qt::endl;
72
73 RenderIntent preferredIntent = Private::calculateConfigIntent(m_d->currentConfig.options());
74 str << "Configured intent:" << preferredIntent << "supported:" << m_d->interface->supportsRenderIntent(preferredIntent) << Qt::endl;
75
76 str << "Actual intent:";
77 if (m_d->interface->renderingIntent()) {
78 str << *m_d->interface->renderingIntent() << Qt::endl;
79 } else {
80 str << "<none>" << Qt::endl;
81 }
82 str << Qt::endl;
83
84 str << "Active surface description:";
85 if (m_d->interface->surfaceDescription()) {
86 str << Qt::endl;
87 str.noquote() << m_d->interface->surfaceDescription()->makeTextReport() << Qt::endl;
88 } else {
89 str << "<none>" << Qt::endl;
90 }
91 str << Qt::endl;
92
93 str << "Selected Profile:";
94 if (m_d->currentConfig.profile) {
95 auto profile = m_d->currentConfig.profile;
96
97 str << profile->name() << Qt::endl;
98 str << " primaries:" << KoColorProfile::getColorPrimariesName(profile->getColorPrimaries()) << Qt::endl;
99 str << " transfer: " << KoColorProfile::getTransferCharacteristicName(profile->getTransferCharacteristics()) << Qt::endl;
100 str << Qt::endl;
101
102 {
103 auto colVec = profile->getColorantsxyY();
104 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(colVec.size() == 9, report);
105 KisColorimetryUtils::xyY colR{colVec[0], colVec[1], colVec[2]};
106 KisColorimetryUtils::xyY colG{colVec[3], colVec[4], colVec[5]};
107 KisColorimetryUtils::xyY colB{colVec[6], colVec[7], colVec[8]};
108
109 str << " red: " << colR << Qt::endl;
110 str << " green:" << colG << Qt::endl;
111 str << " blue: " << colB << Qt::endl;
112 }
113
114 {
115 auto whiteVec = profile->getWhitePointxyY();
116 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(whiteVec.size() == 3, report);
117 KisColorimetryUtils::xyY white{whiteVec[0], whiteVec[1], whiteVec[2]};
118
119 str << " white: " << white << Qt::endl;
120 str << Qt::endl;
121 }
122
123 } else {
124 str << "<none>" << Qt::endl;
125 }
126
127 str << "Compositor preferred surface description:";
128 if (m_d->interface->preferredSurfaceDescription()) {
129 str << Qt::endl;
130 str.noquote() << m_d->interface->preferredSurfaceDescription()->makeTextReport() << Qt::endl;
131 } else {
132 str << "<none>" << Qt::endl;
133 }
134 str << Qt::endl;
135
136 return report;
137}
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
static QString getTransferCharacteristicName(TransferCharacteristics curve)
getTransferCharacteristicName
static QString getColorPrimariesName(ColorPrimaries primaries)
getColorPrimariesName

References KoColorProfile::getColorPrimariesName(), KoColorProfile::getTransferCharacteristicName(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and m_d.

◆ displayConfig()

KisDisplayConfig KisCanvasSurfaceColorSpaceManager::displayConfig ( ) const

Definition at line 423 of file KisCanvasSurfaceColorSpaceManager.cpp.

424{
425 return m_d->currentConfig;
426}

References m_d.

◆ isReady()

bool KisCanvasSurfaceColorSpaceManager::isReady ( ) const

Definition at line 418 of file KisCanvasSurfaceColorSpaceManager.cpp.

419{
420 return m_d->interface->isReady();
421}

References m_d.

◆ osPreferredColorSpaceReport()

QString KisCanvasSurfaceColorSpaceManager::osPreferredColorSpaceReport ( ) const

Definition at line 139 of file KisCanvasSurfaceColorSpaceManager.cpp.

140{
141 QString report;
142 QDebug str(&report);
143
144 if (!m_d->interface->isReady()) {
145 str << "WARNING: surface color management interface is not ready!" << Qt::endl;
146 str << Qt::endl;
147 }
148
149 if (m_d->interface->preferredSurfaceDescription()) {
150 str << Qt::endl;
151 str.noquote() << m_d->interface->preferredSurfaceDescription()->makeTextReport() << Qt::endl;
152 } else {
153 str << "<none>" << Qt::endl;
154 }
155
156 return report;
157}

References m_d.

◆ Private()

KisCanvasSurfaceColorSpaceManager::Private ( KisSurfaceColorManagerInterface * interface)
inline

Definition at line 22 of file KisCanvasSurfaceColorSpaceManager.cpp.

◆ reinitializeSurfaceDescription()

void KisCanvasSurfaceColorSpaceManager::reinitializeSurfaceDescription ( const KisDisplayConfig::Options & newOptions)
private

Our definition of rec709-g10 is different from the one used in Wayland. Krita defines it as "value 1.0 is reference white" and everything above is HDR values. But Wayland declares it as "0.0...1.0 is the full HDR range" and reference white value being put somewhere inbetween. It technically allows Wayland to use 10-bit integer surfaces for rec709-g10 space, which is a bad idea in general (due to potential resolution limit). But given that Wayland/Mesa doesn't seem to support 16-bit float surfaces, that is the only option they have.

Anyway, due to limitations of 10-bit integer surfaces in rec709-g10 mode, we just refuse to support that.

Definition at line 216 of file KisCanvasSurfaceColorSpaceManager.cpp.

217{
222
223 RenderIntent preferredIntent =
224 Private::calculateConfigIntent(newOptions);
225
226 if (!m_d->interface->supportsRenderIntent(preferredIntent)) {
227 qWarning() << "WARNING: failed to set user preferred rendering"
228 << "intent for the surface, intent \""
229 << preferredIntent << "\" is unsupported, falling back to \"perceptual\"";
230
231 preferredIntent = RenderIntent::render_intent_perceptual;
232
233 // perceptual intent is guaranteed to be supported by the compositor
234 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->interface->supportsRenderIntent(preferredIntent));
235 }
236
237 std::optional<SurfaceDescription> requestedDescription;
238 const KoColorProfile *profile = nullptr;
239
240 if (m_d->surfaceMode == KisConfig::CanvasSurfaceMode::Unmanaged) {
242 } else {
243 requestedDescription = SurfaceDescription();
244
245 using namespace KisSurfaceColorimetry;
246
247 const auto compositorPreferred = m_d->interface->preferredSurfaceDescription();
248 KIS_SAFE_ASSERT_RECOVER_RETURN(compositorPreferred);
249
250 // we have our own definition of the Rec2020PQ space with
251 // the reference point fixed to 80 cd/m2
252 auto makeKritaRec2020PQLuminance = [] () {
253 Luminance luminance;
254 luminance.minLuminance = 0;
255 luminance.referenceLuminance = 80;
256 luminance.maxLuminance = 10000;
257 return luminance;
258 };
259
260 if (m_d->surfaceMode == KisConfig::CanvasSurfaceMode::Preferred) {
261
262 if (compositorPreferred->colorSpace.isHDR()) {
263 // we support HDR only via Rec2020PQ, so reset the color space to that
264 // (KWin 6.5+ reports gamma-2.2 as preferred color space for whatever
265 // reason)
266 requestedDescription->colorSpace.primaries = NamedPrimaries::primaries_bt2020;
267 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_st2084_pq;
268 } else {
269 // we don't copy mastering properties, since they mean a different thing
270 // for the preferred space and outputs
271 requestedDescription->colorSpace = compositorPreferred->colorSpace;
272 }
273
274 if (std::holds_alternative<NamedTransferFunction>(requestedDescription->colorSpace.transferFunction) &&
275 std::get<NamedTransferFunction>(requestedDescription->colorSpace.transferFunction) == NamedTransferFunction::transfer_function_st2084_pq) {
276
277 requestedDescription->colorSpace.luminance = makeKritaRec2020PQLuminance();
278 }
279 } else if (m_d->surfaceMode == KisConfig::CanvasSurfaceMode::Rec2020pq) {
280 requestedDescription->colorSpace.primaries = NamedPrimaries::primaries_bt2020;
281 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_st2084_pq;
282 requestedDescription->colorSpace.luminance = makeKritaRec2020PQLuminance();
283 } else if (m_d->surfaceMode == KisConfig::CanvasSurfaceMode::Rec709g22) {
284 requestedDescription->colorSpace.primaries = NamedPrimaries::primaries_srgb;
285 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_gamma22;
286 if (compositorPreferred->colorSpace.luminance) {
287 // rec709-g22 is considered as SDR in lcms, so we should our space to SDR range
288 requestedDescription->colorSpace.luminance =
289 compositorPreferred->colorSpace.luminance->clipToSdr();
290 }
291 } else if (m_d->surfaceMode == KisConfig::CanvasSurfaceMode::Rec709g10) {
292 requestedDescription->colorSpace.primaries = NamedPrimaries::primaries_srgb;
293 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_ext_linear;
294 if (compositorPreferred->colorSpace.luminance) {
307 requestedDescription->colorSpace.luminance =
308 compositorPreferred->colorSpace.luminance->clipToSdr();
309 }
310 }
311
312 if (std::holds_alternative<NamedPrimaries>(requestedDescription->colorSpace.primaries) &&
313 std::get<NamedPrimaries>(requestedDescription->colorSpace.primaries) == NamedPrimaries::primaries_unknown) {
314
315 requestedDescription->colorSpace.primaries = NamedPrimaries::primaries_srgb;
316 }
317
318 if (std::holds_alternative<NamedTransferFunction>(requestedDescription->colorSpace.transferFunction) &&
319 std::get<NamedTransferFunction>(requestedDescription->colorSpace.transferFunction) == NamedTransferFunction::transfer_function_unknown) {
320
321 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_gamma22;
322 }
323
324 if (!m_d->interface->supportsSurfaceDescription(*requestedDescription)) {
325
326 // try pure sRGB
327 requestedDescription->colorSpace.primaries = NamedPrimaries::primaries_srgb;
328 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_srgb;
329
330 if (!m_d->interface->supportsSurfaceDescription(*requestedDescription)) {
331 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_gamma22;
332
333 if (!m_d->interface->supportsSurfaceDescription(*requestedDescription)) {
334 qWarning() << "WARNING: failed to find a suitable surface format for the compositor";
335 return; // TODO: extra signals?
336 }
337 }
338 }
339
340 {
341 auto request = colorSpaceToRequest(requestedDescription->colorSpace);
342 if (request.isValid()) {
343 profile = KoColorSpaceRegistry::instance()->profileFor(request.colorants,
344 request.colorPrimariesType,
345 request.transferFunction);
346 }
347 }
348
349 if (!profile) {
350 // keep primaries, but change the transfer function to gamma22
351 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_gamma22;
352 if (m_d->interface->supportsSurfaceDescription(*requestedDescription)) {
353 auto request = colorSpaceToRequest(requestedDescription->colorSpace);
354 if (request.isValid()) {
355 profile = KoColorSpaceRegistry::instance()->profileFor(request.colorants,
356 request.colorPrimariesType,
357 request.transferFunction);
358 }
359 }
360 }
361
362 if (!profile) {
363 // keep primaries, but change the transfer function to srgb
364 requestedDescription->colorSpace.transferFunction = NamedTransferFunction::transfer_function_srgb;
365 if (m_d->interface->supportsSurfaceDescription(*requestedDescription)) {
366 auto request = colorSpaceToRequest(requestedDescription->colorSpace);
367 if (request.isValid()) {
368 profile = KoColorSpaceRegistry::instance()->profileFor(request.colorants,
369 request.colorPrimariesType,
370 request.transferFunction);
371 }
372 }
373 }
374
375 if (!profile) {
376 qWarning() << "WARNING: failed to to create a profile for the compositor's preferred color space";
377 qWarning() << " " << ppVar(compositorPreferred);
378 qWarning() << " " << ppVar(*requestedDescription);
379 // TODO: debug all supported values for the compositor
380 return; // TODO: extra signals?
381 }
382 }
383
385 KIS_SAFE_ASSERT_RECOVER_RETURN(!requestedDescription || m_d->interface->supportsSurfaceDescription(*requestedDescription));
386
387 if (m_d->interface->surfaceDescription() != requestedDescription ||
388 m_d->interface->renderingIntent() != preferredIntent) {
389
390 if (requestedDescription) {
391 auto future = m_d->interface->setSurfaceDescription(*requestedDescription, preferredIntent);
392 future.then([](QFuture<bool> result) {
393 if (!result.isValid() || !result.result()) {
394 qWarning()
395 << "WARNING: failed to set color space for the surface, setSurfaceDescription() returned false";
396 }
397 });
398 } else {
399 m_d->interface->unsetSurfaceDescription();
400 }
401 }
402
403 const bool requestedDescriptionIsHDR = requestedDescription && requestedDescription->colorSpace.isHDR();
404
405 KisDisplayConfig newDisplayConfig;
406 newDisplayConfig.profile = profile;
407 newDisplayConfig.setOptions(newOptions); // TODO: think about failure to set the intent and infinite update loop
408 newDisplayConfig.isHDR = requestedDescriptionIsHDR;
409
410 KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->currentConfig.profile);
411
412 if (m_d->currentConfig != newDisplayConfig) {
413 m_d->currentConfig = newDisplayConfig;
414 Q_EMIT sigDisplayConfigChanged(m_d->currentConfig);
415 }
416}
KisDisplayConfig This class keeps track of the color management configuration for image to display....
void setOptions(const Options &options)
const KoColorProfile * profile
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define ppVar(var)
Definition kis_debug.h:155
PigmentProfileRequest colorSpaceToRequest(ColorSpace cs)
void sigDisplayConfigChanged(const KisDisplayConfig &config)
const KoColorProfile * profileFor(const QVector< double > &colorants, ColorPrimaries colorPrimaries, TransferCharacteristics transferFunction) const
profileFor tries to find the profile that matches these characteristics, if no such profile is found,...

References KoColorSpaceRegistry::instance(), KisDisplayConfig::isHDR, KIS_SAFE_ASSERT_RECOVER_RETURN, m_d, KisSurfaceColorimetry::Luminance::maxLuminance, KisSurfaceColorimetry::Luminance::minLuminance, KoColorSpaceRegistry::p709SRGBProfile(), ppVar, KisConfig::Preferred, KisDisplayConfig::profile, KoColorSpaceRegistry::profileFor(), KisConfig::Rec2020pq, KisConfig::Rec709g10, KisConfig::Rec709g22, KisSurfaceColorimetry::Luminance::referenceLuminance, KisDisplayConfig::setOptions(), sigDisplayConfigChanged(), and KisConfig::Unmanaged.

◆ setDisplayConfigOptions() [1/2]

void KisCanvasSurfaceColorSpaceManager::setDisplayConfigOptions ( const KisConfig::CanvasSurfaceMode surfaceMode,
const KisDisplayConfig::Options & options )

Definition at line 187 of file KisCanvasSurfaceColorSpaceManager.cpp.

188{
189 if (!m_d->interface->isReady()) return;
190 if (surfaceMode == m_d->surfaceMode && options == m_d->currentConfig.options()) return;
191
192 m_d->surfaceMode = surfaceMode;
194}
void reinitializeSurfaceDescription(const KisDisplayConfig::Options &newOptions)

References m_d, reinitializeSurfaceDescription(), and surfaceMode.

◆ setDisplayConfigOptions() [2/2]

void KisCanvasSurfaceColorSpaceManager::setDisplayConfigOptions ( const KisDisplayConfig::Options & options)

Definition at line 196 of file KisCanvasSurfaceColorSpaceManager.cpp.

197{
198 setDisplayConfigOptions(m_d->surfaceMode, options);
199}
void setDisplayConfigOptions(const KisConfig::CanvasSurfaceMode surfaceMode, const KisDisplayConfig::Options &options)

References m_d, and setDisplayConfigOptions().

◆ sigDisplayConfigChanged

void KisCanvasSurfaceColorSpaceManager::sigDisplayConfigChanged ( const KisDisplayConfig & config)
signal

◆ slotInterfacePreferredDescriptionChanged

void KisCanvasSurfaceColorSpaceManager::slotInterfacePreferredDescriptionChanged ( )
privateslot

Definition at line 208 of file KisCanvasSurfaceColorSpaceManager.cpp.

209{
210 reinitializeSurfaceDescription(m_d->currentConfig.options());
211}

References m_d, and reinitializeSurfaceDescription().

◆ slotInterfaceReadyChanged

void KisCanvasSurfaceColorSpaceManager::slotInterfaceReadyChanged ( bool isReady)
privateslot

Definition at line 201 of file KisCanvasSurfaceColorSpaceManager.cpp.

202{
203 if (isReady) {
204 reinitializeSurfaceDescription(m_d->currentConfig.options());
205 }
206}

References isReady(), m_d, and reinitializeSurfaceDescription().

Member Data Documentation

◆ currentConfig

KisDisplayConfig KisCanvasSurfaceColorSpaceManager::currentConfig

Definition at line 25 of file KisCanvasSurfaceColorSpaceManager.cpp.

◆ interface

QScopedPointer<KisSurfaceColorManagerInterface> KisCanvasSurfaceColorSpaceManager::interface

Definition at line 24 of file KisCanvasSurfaceColorSpaceManager.cpp.

◆ m_d

QScopedPointer<Private> KisCanvasSurfaceColorSpaceManager::m_d
private

Definition at line 49 of file KisCanvasSurfaceColorSpaceManager.h.

◆ proofingIntentOverride

std::optional<KisSurfaceColorimetry::RenderIntent> KisCanvasSurfaceColorSpaceManager::proofingIntentOverride

Definition at line 26 of file KisCanvasSurfaceColorSpaceManager.cpp.

◆ surfaceMode

KisConfig::CanvasSurfaceMode KisCanvasSurfaceColorSpaceManager::surfaceMode = KisConfig::CanvasSurfaceMode::Preferred

Definition at line 27 of file KisCanvasSurfaceColorSpaceManager.cpp.


The documentation for this class was generated from the following files: