KWin
Loading...
Searching...
No Matches
output.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2018 Roman Gilg <subdiff@gmail.com>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "output.h"
11#include "iccprofile.h"
12#include "outputconfiguration.h"
13
14#include <KConfigGroup>
15#include <KLocalizedString>
16#include <KSharedConfig>
17
18namespace KWin
19{
20
21QDebug operator<<(QDebug debug, const Output *output)
22{
23 QDebugStateSaver saver(debug);
24 debug.nospace();
25 if (output) {
26 debug << output->metaObject()->className() << '(' << static_cast<const void *>(output);
27 debug << ", name=" << output->name();
28 debug << ", geometry=" << output->geometry();
29 debug << ", scale=" << output->scale();
30 if (debug.verbosity() > 2) {
31 debug << ", manufacturer=" << output->manufacturer();
32 debug << ", model=" << output->model();
33 debug << ", serialNumber=" << output->serialNumber();
34 }
35 debug << ')';
36 } else {
37 debug << "Output(0x0)";
38 }
39 return debug;
40}
41
42OutputMode::OutputMode(const QSize &size, uint32_t refreshRate, Flags flags)
43 : m_size(size)
44 , m_refreshRate(refreshRate)
45 , m_flags(flags)
46{
47}
48
49QSize OutputMode::size() const
50{
51 return m_size;
52}
53
55{
56 return m_refreshRate;
57}
58
59OutputMode::Flags OutputMode::flags() const
60{
61 return m_flags;
62}
63
65{
66 return m_kind;
67}
68
70{
71 switch (m_kind) {
72 case Kind::Normal:
73 return Kind::Normal;
74 case Kind::Rotate90:
75 return Kind::Rotate270;
76 case Kind::Rotate180:
77 return Kind::Rotate180;
78 case Kind::Rotate270:
79 return Kind::Rotate90;
80 case Kind::FlipX:
81 case Kind::FlipX90:
82 case Kind::FlipX180:
83 case Kind::FlipX270:
84 return m_kind; // inverse transform of a flip transform is itself
85 }
86
87 Q_UNREACHABLE();
88}
89
90QRectF OutputTransform::map(const QRectF &rect, const QSizeF &bounds) const
91{
92 switch (m_kind) {
93 case Kind::Normal:
94 return rect;
95 case Kind::Rotate90:
96 return QRectF(rect.y(),
97 bounds.width() - (rect.x() + rect.width()),
98 rect.height(),
99 rect.width());
100 case Kind::Rotate180:
101 return QRectF(bounds.width() - (rect.x() + rect.width()),
102 bounds.height() - (rect.y() + rect.height()),
103 rect.width(),
104 rect.height());
105 case Kind::Rotate270:
106 return QRectF(bounds.height() - (rect.y() + rect.height()),
107 rect.x(),
108 rect.height(),
109 rect.width());
110 case Kind::FlipX:
111 return QRectF(bounds.width() - (rect.x() + rect.width()),
112 rect.y(),
113 rect.width(),
114 rect.height());
115 case Kind::FlipX90:
116 return QRectF(rect.y(),
117 rect.x(),
118 rect.height(),
119 rect.width());
120 case Kind::FlipX180:
121 return QRectF(rect.x(),
122 bounds.height() - (rect.y() + rect.height()),
123 rect.width(),
124 rect.height());
125 case Kind::FlipX270:
126 return QRectF(bounds.height() - (rect.y() + rect.height()),
127 bounds.width() - (rect.x() + rect.width()),
128 rect.height(),
129 rect.width());
130 default:
131 Q_UNREACHABLE();
132 }
133}
134
135QRect OutputTransform::map(const QRect &rect, const QSize &bounds) const
136{
137 switch (m_kind) {
138 case Kind::Normal:
139 return rect;
140 case Kind::Rotate90:
141 return QRect(rect.y(),
142 bounds.width() - (rect.x() + rect.width()),
143 rect.height(),
144 rect.width());
145 case Kind::Rotate180:
146 return QRect(bounds.width() - (rect.x() + rect.width()),
147 bounds.height() - (rect.y() + rect.height()),
148 rect.width(),
149 rect.height());
150 case Kind::Rotate270:
151 return QRect(bounds.height() - (rect.y() + rect.height()),
152 rect.x(),
153 rect.height(),
154 rect.width());
155 case Kind::FlipX:
156 return QRect(bounds.width() - (rect.x() + rect.width()),
157 rect.y(),
158 rect.width(),
159 rect.height());
160 case Kind::FlipX90:
161 return QRect(rect.y(),
162 rect.x(),
163 rect.height(),
164 rect.width());
165 case Kind::FlipX180:
166 return QRect(rect.x(),
167 bounds.height() - (rect.y() + rect.height()),
168 rect.width(),
169 rect.height());
170 case Kind::FlipX270:
171 return QRect(bounds.height() - (rect.y() + rect.height()),
172 bounds.width() - (rect.x() + rect.width()),
173 rect.height(),
174 rect.width());
175 default:
176 Q_UNREACHABLE();
177 }
178}
179
180QPointF OutputTransform::map(const QPointF &point, const QSizeF &bounds) const
181{
182 switch (m_kind) {
183 case Kind::Normal:
184 return point;
185 case Kind::Rotate90:
186 return QPointF(point.y(),
187 bounds.width() - point.x());
188 case Kind::Rotate180:
189 return QPointF(bounds.width() - point.x(),
190 bounds.height() - point.y());
191 case Kind::Rotate270:
192 return QPointF(bounds.height() - point.y(),
193 point.x());
194 case Kind::FlipX:
195 return QPointF(bounds.width() - point.x(),
196 point.y());
197 case Kind::FlipX90:
198 return QPointF(point.y(),
199 point.x());
200 case Kind::FlipX180:
201 return QPointF(point.x(),
202 bounds.height() - point.y());
203 case Kind::FlipX270:
204 return QPointF(bounds.height() - point.y(),
205 bounds.width() - point.x());
206 default:
207 Q_UNREACHABLE();
208 }
209}
210
211QPoint OutputTransform::map(const QPoint &point, const QSize &bounds) const
212{
213 switch (m_kind) {
214 case Kind::Normal:
215 return point;
216 case Kind::Rotate90:
217 return QPoint(point.y(),
218 bounds.width() - point.x());
219 case Kind::Rotate180:
220 return QPoint(bounds.width() - point.x(),
221 bounds.height() - point.y());
222 case Kind::Rotate270:
223 return QPoint(bounds.height() - point.y(),
224 point.x());
225 case Kind::FlipX:
226 return QPoint(bounds.width() - point.x(),
227 point.y());
228 case Kind::FlipX90:
229 return QPoint(point.y(),
230 point.x());
231 case Kind::FlipX180:
232 return QPoint(point.x(),
233 bounds.height() - point.y());
234 case Kind::FlipX270:
235 return QPoint(bounds.height() - point.y(),
236 bounds.width() - point.x());
237 default:
238 Q_UNREACHABLE();
239 }
240}
241
242QSizeF OutputTransform::map(const QSizeF &size) const
243{
244 switch (m_kind) {
245 case Kind::Normal:
246 case Kind::Rotate180:
247 case Kind::FlipX:
248 case Kind::FlipX180:
249 return size;
250 default:
251 return size.transposed();
252 }
253}
254
255QSize OutputTransform::map(const QSize &size) const
256{
257 switch (m_kind) {
258 case Kind::Normal:
259 case Kind::Rotate180:
260 case Kind::FlipX:
261 case Kind::FlipX180:
262 return size;
263 default:
264 return size.transposed();
265 }
266}
267
269{
270 // Combining a rotate-N or flip-N (mirror-x | rotate-N) transform with a rotate-M
271 // transform involves only adding rotation angles:
272 // rotate-N | rotate-M => rotate-(N + M)
273 // flip-N | rotate-M => mirror-x | rotate-N | rotate-M
274 // => mirror-x | rotate-(N + M)
275 // => flip-(N + M)
276 //
277 // rotate-N | mirror-x is the same as mirror-x | rotate-(360 - N). This can be used
278 // to derive the resulting transform if the other transform flips the x axis
279 // rotate-N | flip-M => rotate-N | mirror-x | rotate-M
280 // => mirror-x | rotate-(360 - N + M)
281 // => flip-(M - N)
282 // flip-N | flip-M => mirror-x | rotate-N | mirror-x | rotate-M
283 // => mirror-x | mirror-x | rotate-(360 - N + M)
284 // => rotate-(360 - N + M)
285 // => rotate-(M - N)
286 //
287 // The remaining code here relies on the bit pattern of transform enums, i.e. the
288 // lower two bits specify the rotation, the third bit indicates mirroring along the x axis.
289
290 const int flip = (m_kind ^ other.m_kind) & 0x4;
291 int rotate;
292 if (other.m_kind & 0x4) {
293 rotate = (other.m_kind - m_kind) & 0x3;
294 } else {
295 rotate = (m_kind + other.m_kind) & 0x3;
296 }
297 return OutputTransform(Kind(flip | rotate));
298}
299
301{
302 QMatrix4x4 matrix;
303 switch (m_kind) {
304 case Kind::Normal:
305 break;
306 case Kind::Rotate90:
307 matrix.rotate(-90, 0, 0, 1);
308 break;
309 case Kind::Rotate180:
310 matrix.rotate(-180, 0, 0, 1);
311 break;
312 case Kind::Rotate270:
313 matrix.rotate(-270, 0, 0, 1);
314 break;
315 case Kind::FlipX:
316 matrix.scale(-1, 1);
317 break;
318 case Kind::FlipX90:
319 matrix.rotate(-90, 0, 0, 1);
320 matrix.scale(-1, 1);
321 break;
322 case Kind::FlipX180:
323 matrix.rotate(-180, 0, 0, 1);
324 matrix.scale(-1, 1);
325 break;
326 case Kind::FlipX270:
327 matrix.rotate(-270, 0, 0, 1);
328 matrix.scale(-1, 1);
329 break;
330 default:
331 Q_UNREACHABLE();
332 }
333 return matrix;
334}
335
336Output::Output(QObject *parent)
337 : QObject(parent)
338{
339}
340
342{
343}
344
346{
347 m_refCount++;
348}
349
351{
352 Q_ASSERT(m_refCount > 0);
353 m_refCount--;
354 if (m_refCount == 0) {
355 delete this;
356 }
357}
358
359QString Output::name() const
360{
361 return m_information.name;
362}
363
364QUuid Output::uuid() const
365{
366 return m_uuid;
367}
368
373
378
379QString Output::eisaId() const
380{
381 return m_information.eisaId;
382}
383
384QString Output::manufacturer() const
385{
387}
388
389QString Output::model() const
390{
391 return m_information.model;
392}
393
394QString Output::serialNumber() const
395{
397}
398
400{
401 return m_information.internal;
402}
403
408
413
415{
417}
418
419std::chrono::milliseconds Output::dimAnimationTime()
420{
421 // See kscreen.kcfg
422 return std::chrono::milliseconds(KSharedConfig::openConfig()->group(QStringLiteral("Effect-Kscreen")).readEntry("Duration", 250));
423}
424
425QRect Output::mapFromGlobal(const QRect &rect) const
426{
427 return rect.translated(-geometry().topLeft());
428}
429
430QRectF Output::mapFromGlobal(const QRectF &rect) const
431{
432 return rect.translated(-geometry().topLeft());
433}
434
435QRectF Output::mapToGlobal(const QRectF &rect) const
436{
437 return rect.translated(geometry().topLeft());
438}
439
440QPointF Output::mapToGlobal(const QPointF &pos) const
441{
442 return pos + geometry().topLeft();
443}
444
445QPointF Output::mapFromGlobal(const QPointF &pos) const
446{
447 return pos - geometry().topLeft();
448}
449
450Output::Capabilities Output::capabilities() const
451{
453}
454
455qreal Output::scale() const
456{
457 return m_state.scale;
458}
459
460QRect Output::geometry() const
461{
462 return QRect(m_state.position, pixelSize() / scale());
463}
464
465QRectF Output::geometryF() const
466{
467 return QRectF(m_state.position, QSizeF(pixelSize()) / scale());
468}
469
471{
473}
474
475uint32_t Output::refreshRate() const
476{
477 return m_state.currentMode ? m_state.currentMode->refreshRate() : 0;
478}
479
480QSize Output::modeSize() const
481{
482 return m_state.currentMode ? m_state.currentMode->size() : QSize();
483}
484
485QSize Output::pixelSize() const
486{
487 return orientateSize(modeSize());
488}
489
490const Edid &Output::edid() const
491{
492 return m_information.edid;
493}
494
495QList<std::shared_ptr<OutputMode>> Output::modes() const
496{
497 return m_state.modes;
498}
499
500std::shared_ptr<OutputMode> Output::currentMode() const
501{
502 return m_state.currentMode;
503}
504
509
511{
512 auto props = config.constChangeSet(this);
513 if (!props) {
514 return;
515 }
516 Q_EMIT aboutToChange(props.get());
517
518 State next = m_state;
519 next.enabled = props->enabled.value_or(m_state.enabled);
520 next.transform = props->transform.value_or(m_state.transform);
521 next.position = props->pos.value_or(m_state.position);
522 next.scale = props->scale.value_or(m_state.scale);
523 next.rgbRange = props->rgbRange.value_or(m_state.rgbRange);
524 next.autoRotatePolicy = props->autoRotationPolicy.value_or(m_state.autoRotatePolicy);
525 next.iccProfilePath = props->iccProfilePath.value_or(m_state.iccProfilePath);
526 if (props->iccProfilePath) {
527 next.iccProfile = IccProfile::load(*props->iccProfilePath);
528 }
529 next.vrrPolicy = props->vrrPolicy.value_or(m_state.vrrPolicy);
530
531 setState(next);
532
533 Q_EMIT changed();
534}
535
537{
538 return m_state.enabled;
539}
540
541QString Output::description() const
542{
543 return manufacturer() + ' ' + model();
544}
545
546static QUuid generateOutputId(const QString &eisaId, const QString &model,
547 const QString &serialNumber, const QString &name)
548{
549 static const QUuid urlNs = QUuid("6ba7b811-9dad-11d1-80b4-00c04fd430c8"); // NameSpace_URL
550 static const QUuid kwinNs = QUuid::createUuidV5(urlNs, QStringLiteral("https://kwin.kde.org/o/"));
551
552 const QString payload = QStringList{name, eisaId, model, serialNumber}.join(':');
553 return QUuid::createUuidV5(kwinNs, payload);
554}
555
556void Output::setInformation(const Information &information)
557{
558 m_information = information;
559 m_uuid = generateOutputId(eisaId(), model(), serialNumber(), name());
560}
561
562void Output::setState(const State &state)
563{
564 const QRect oldGeometry = geometry();
565 const State oldState = m_state;
566
567 m_state = state;
568
569 if (oldGeometry != geometry()) {
570 Q_EMIT geometryChanged();
571 }
572 if (oldState.scale != state.scale) {
573 Q_EMIT scaleChanged();
574 }
575 if (oldState.modes != state.modes) {
576 Q_EMIT modesChanged();
577 }
578 if (oldState.currentMode != state.currentMode) {
579 Q_EMIT currentModeChanged();
580 }
581 if (oldState.transform != state.transform) {
582 Q_EMIT transformChanged();
583 }
584 if (oldState.overscan != state.overscan) {
585 Q_EMIT overscanChanged();
586 }
587 if (oldState.dpmsMode != state.dpmsMode) {
588 Q_EMIT dpmsModeChanged();
589 }
590 if (oldState.rgbRange != state.rgbRange) {
591 Q_EMIT rgbRangeChanged();
592 }
593 if (oldState.highDynamicRange != state.highDynamicRange) {
595 }
596 if (oldState.sdrBrightness != state.sdrBrightness) {
597 Q_EMIT sdrBrightnessChanged();
598 }
599 if (oldState.wideColorGamut != state.wideColorGamut) {
600 Q_EMIT wideColorGamutChanged();
601 }
602 if (oldState.autoRotatePolicy != state.autoRotatePolicy) {
604 }
605 if (oldState.iccProfile != state.iccProfile) {
606 Q_EMIT iccProfileChanged();
607 }
608 if (oldState.iccProfilePath != state.iccProfilePath) {
609 Q_EMIT iccProfilePathChanged();
610 }
613 || oldState.minBrightnessOverride != state.minBrightnessOverride) {
615 }
616 if (oldState.sdrGamutWideness != state.sdrGamutWideness) {
618 }
619 if (oldState.vrrPolicy != state.vrrPolicy) {
620 Q_EMIT vrrPolicyChanged();
621 }
622 if (oldState.colorDescription != state.colorDescription) {
624 }
625 if (oldState.enabled != state.enabled) {
626 Q_EMIT enabledChanged();
627 }
628}
629
630QSize Output::orientateSize(const QSize &size) const
631{
632 switch (m_state.transform.kind()) {
637 return size.transposed();
638 default:
639 return size;
640 }
641}
642
644{
645}
646
648{
649 return m_state.dpmsMode;
650}
651
652uint32_t Output::overscan() const
653{
654 return m_state.overscan;
655}
656
658{
659 return m_state.vrrPolicy;
660}
661
663{
665}
666
668{
670}
671
673{
674 return m_state.rgbRange;
675}
676
677bool Output::setChannelFactors(const QVector3D &rgb)
678{
679 return false;
680}
681
682bool Output::setGammaRamp(const std::shared_ptr<ColorTransformation> &transformation)
683{
684 return false;
685}
686
691
693{
694 return m_state.wideColorGamut;
695}
696
698{
700}
701
702uint32_t Output::sdrBrightness() const
703{
704 return m_state.sdrBrightness;
705}
706
711
712std::shared_ptr<IccProfile> Output::iccProfile() const
713{
714 return m_state.iccProfile;
715}
716
718{
719 return m_state.iccProfilePath;
720}
721
722QByteArray Output::mstPath() const
723{
724 return m_information.mstPath;
725}
726
728{
729 return false;
730}
731
736
741
746
751
752std::optional<double> Output::maxPeakBrightnessOverride() const
753{
755}
756
757std::optional<double> Output::maxAverageBrightnessOverride() const
758{
760}
761
762std::optional<double> Output::minBrightnessOverride() const
763{
765}
766
768{
770}
771} // namespace KWin
772
773#include "moc_output.cpp"
static std::unique_ptr< IccProfile > load(const QString &path)
std::shared_ptr< OutputChangeSet > constChangeSet(Output *output) const
void inhibitDirectScanout()
Definition output.cpp:404
VrrPolicy vrrPolicy() const
Definition output.cpp:657
void unref()
Definition output.cpp:350
std::shared_ptr< OutputMode > currentMode() const
Definition output.cpp:500
virtual void setDpmsMode(DpmsMode mode)
Definition output.cpp:643
QString eisaId() const
Definition output.cpp:379
bool isPlaceholder() const
Definition output.cpp:662
void enabledChanged()
QSize orientateSize(const QSize &size) const
Definition output.cpp:630
QRect rect() const
Definition output.h:484
void rgbRangeChanged()
QString manufacturer
Definition output.h:137
double sdrGamutWideness() const
Definition output.cpp:767
QString description() const
Definition output.cpp:541
qreal scale() const
Definition output.cpp:455
~Output() override
Definition output.cpp:341
void colorDescriptionChanged()
QRectF geometryF() const
Definition output.cpp:465
QList< std::shared_ptr< OutputMode > > modes() const
Definition output.cpp:495
uint32_t overscan() const
Definition output.cpp:652
OutputTransform panelOrientation() const
Definition output.cpp:687
uint32_t refreshRate() const
Definition output.cpp:475
int m_directScanoutCount
Definition output.h:480
void setInformation(const Information &information)
Definition output.cpp:556
virtual bool setGammaRamp(const std::shared_ptr< ColorTransformation > &transformation)
Definition output.cpp:682
double minBrightness() const
Definition output.cpp:747
QString model
Definition output.h:138
void overscanChanged()
void setState(const State &state)
Definition output.cpp:562
void currentModeChanged()
bool highDynamicRange() const
Definition output.cpp:697
QUuid uuid() const
Definition output.cpp:364
int m_refCount
Definition output.h:481
std::optional< double > maxAverageBrightnessOverride() const
Definition output.cpp:757
void highDynamicRangeChanged()
QSize modeSize() const
Definition output.cpp:480
void geometryChanged()
const ColorDescription & colorDescription() const
Definition output.cpp:732
RgbRange rgbRange() const
Definition output.cpp:672
OutputTransform transform() const
Definition output.cpp:369
void autoRotationPolicyChanged()
void sdrBrightnessChanged()
bool directScanoutInhibited() const
Definition output.cpp:414
void scaleChanged()
QRect mapFromGlobal(const QRect &rect) const
Definition output.cpp:425
QRectF mapToGlobal(const QRectF &rect) const
Definition output.cpp:435
AutoRotationPolicy autoRotationPolicy() const
Definition output.cpp:707
void modesChanged()
void iccProfilePathChanged()
static std::chrono::milliseconds dimAnimationTime()
Definition output.cpp:419
SubPixel subPixel() const
Definition output.cpp:505
void vrrPolicyChanged()
std::optional< double > maxAverageBrightness() const
Definition output.cpp:742
QString iccProfilePath() const
Definition output.cpp:717
QByteArray mstPath() const
Definition output.cpp:722
void ref()
Definition output.cpp:345
void aboutToChange(OutputChangeSet *changeSet)
uint32_t sdrBrightness() const
Definition output.cpp:702
const Edid & edid() const
Definition output.cpp:490
std::optional< double > maxPeakBrightness() const
Definition output.cpp:737
bool isInternal() const
Definition output.cpp:399
void applyChanges(const OutputConfiguration &config)
Definition output.cpp:510
OutputTransform manualTransform() const
Definition output.cpp:374
void iccProfileChanged()
bool wideColorGamut() const
Definition output.cpp:692
void sdrGamutWidenessChanged()
void brightnessMetadataChanged()
std::optional< double > minBrightnessOverride() const
Definition output.cpp:762
State m_state
Definition output.h:477
void transformChanged()
void changed()
std::shared_ptr< IccProfile > iccProfile() const
Definition output.cpp:712
QString serialNumber
Definition output.h:139
virtual bool setChannelFactors(const QVector3D &rgb)
Definition output.cpp:677
void wideColorGamutChanged()
QRect geometry
Definition output.h:134
QString name
Definition output.h:136
Information m_information
Definition output.h:478
Output(QObject *parent=nullptr)
Definition output.cpp:336
virtual bool updateCursorLayer()
Definition output.cpp:727
Capabilities capabilities() const
Definition output.cpp:450
bool isEnabled() const
Definition output.cpp:536
void dpmsModeChanged()
void uninhibitDirectScanout()
Definition output.cpp:409
QUuid m_uuid
Definition output.h:479
QSize pixelSize() const
Definition output.cpp:485
bool isNonDesktop() const
Definition output.cpp:667
std::optional< double > maxPeakBrightnessOverride() const
Definition output.cpp:752
DpmsMode dpmsMode() const
Definition output.cpp:647
QSize physicalSize() const
Definition output.cpp:470
Flags flags() const
Definition output.cpp:59
uint32_t refreshRate() const
Definition output.cpp:54
QSize size() const
Definition output.cpp:49
OutputMode(const QSize &size, uint32_t refreshRate, Flags flags={})
Definition output.cpp:42
QSizeF map(const QSizeF &size) const
Definition output.cpp:242
Kind kind() const
Definition output.cpp:64
OutputTransform combine(OutputTransform other) const
Definition output.cpp:268
OutputTransform inverted() const
Definition output.cpp:69
QMatrix4x4 toMatrix() const
Definition output.cpp:300
VrrPolicy
Definition globals.h:292
QDebug & operator<<(QDebug &s, const KWin::DrmConnector *obj)
Capabilities capabilities
Definition output.h:436
std::optional< double > maxAverageBrightness
Definition output.h:443
OutputTransform panelOrientation
Definition output.h:437
std::optional< double > maxPeakBrightness
Definition output.h:442
uint32_t sdrBrightness
Definition output.h:462
std::shared_ptr< OutputMode > currentMode
Definition output.h:454
QList< std::shared_ptr< OutputMode > > modes
Definition output.h:453
double sdrGamutWideness
Definition output.h:470
uint32_t overscan
Definition output.h:458
QString iccProfilePath
Definition output.h:464
ColorDescription colorDescription
Definition output.h:466
VrrPolicy vrrPolicy
Definition output.h:471
OutputTransform manualTransform
Definition output.h:452
std::shared_ptr< IccProfile > iccProfile
Definition output.h:465
std::optional< double > maxAverageBrightnessOverride
Definition output.h:468
DpmsMode dpmsMode
Definition output.h:455
OutputTransform transform
Definition output.h:451
std::optional< double > minBrightnessOverride
Definition output.h:469
RgbRange rgbRange
Definition output.h:459
AutoRotationPolicy autoRotatePolicy
Definition output.h:463
std::optional< double > maxPeakBrightnessOverride
Definition output.h:467