backends/drm: add support for an HDR brightness setting
This commit is contained in:
parent
589479c24a
commit
22d0631b1b
12 changed files with 78 additions and 9 deletions
|
@ -54,7 +54,7 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayer::doBeginFrame()
|
|||
// as the hardware cursor is more important than an incorrectly blended cursor edge
|
||||
|
||||
m_scanoutBuffer.reset();
|
||||
return m_surface.startRendering(targetRect().size(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->formats(m_type), m_pipeline->colorDescription(), m_pipeline->output()->channelFactors(), m_pipeline->iccProfile(), m_pipeline->output()->needsColormanagement());
|
||||
return m_surface.startRendering(targetRect().size(), m_pipeline->output()->transform().combine(OutputTransform::FlipY), m_pipeline->formats(m_type), m_pipeline->colorDescription(), m_pipeline->output()->channelFactors(), m_pipeline->iccProfile(), m_pipeline->output()->needsColormanagement(), m_pipeline->output()->brightness());
|
||||
}
|
||||
|
||||
bool EglGbmLayer::doEndFrame(const QRegion &renderedRegion, const QRegion &damagedRegion, OutputFrame *frame)
|
||||
|
|
|
@ -74,7 +74,7 @@ void EglGbmLayerSurface::destroyResources()
|
|||
m_oldSurface = {};
|
||||
}
|
||||
|
||||
std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &iccProfile, bool enableColormanagement)
|
||||
std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &iccProfile, bool enableColormanagement, double brightness)
|
||||
{
|
||||
if (!checkSurface(bufferSize, formats)) {
|
||||
return std::nullopt;
|
||||
|
@ -96,12 +96,14 @@ std::optional<OutputLayerBeginFrameInfo> EglGbmLayerSurface::startRendering(cons
|
|||
m_surface->currentSlot = slot;
|
||||
|
||||
if (m_surface->targetColorDescription != colorDescription || m_surface->channelFactors != channelFactors
|
||||
|| m_surface->colormanagementEnabled != enableColormanagement || m_surface->iccProfile != iccProfile) {
|
||||
|| m_surface->colormanagementEnabled != enableColormanagement || m_surface->iccProfile != iccProfile
|
||||
|| m_surface->brightness != brightness) {
|
||||
m_surface->damageJournal.clear();
|
||||
m_surface->colormanagementEnabled = enableColormanagement;
|
||||
m_surface->targetColorDescription = colorDescription;
|
||||
m_surface->channelFactors = channelFactors;
|
||||
m_surface->iccProfile = iccProfile;
|
||||
m_surface->brightness = brightness;
|
||||
if (iccProfile) {
|
||||
if (!m_surface->iccShader) {
|
||||
m_surface->iccShader = std::make_unique<IccShader>();
|
||||
|
@ -185,10 +187,14 @@ bool EglGbmLayerSurface::endRendering(const QRegion &damagedRegion, OutputFrame
|
|||
if (m_surface->iccShader) {
|
||||
m_surface->iccShader->setUniforms(m_surface->iccProfile, m_surface->intermediaryColorDescription.sdrBrightness(), m_surface->channelFactors);
|
||||
} else {
|
||||
// enforce a 25 nits minimum sdr brightness
|
||||
constexpr double minBrightness = 25;
|
||||
const double sdrBrightness = m_surface->intermediaryColorDescription.sdrBrightness();
|
||||
const double brightnessFactor = (m_surface->brightness * (1 - (minBrightness / sdrBrightness))) + (minBrightness / sdrBrightness);
|
||||
QMatrix4x4 ctm;
|
||||
ctm(0, 0) = m_surface->channelFactors.x();
|
||||
ctm(1, 1) = m_surface->channelFactors.y();
|
||||
ctm(2, 2) = m_surface->channelFactors.z();
|
||||
ctm(0, 0) = m_surface->channelFactors.x() * brightnessFactor;
|
||||
ctm(1, 1) = m_surface->channelFactors.y() * brightnessFactor;
|
||||
ctm(2, 2) = m_surface->channelFactors.z() * brightnessFactor;
|
||||
binder.shader()->setUniform(GLShader::Mat4Uniform::ColorimetryTransformation, ctm);
|
||||
binder.shader()->setUniform(GLShader::IntUniform::SourceNamedTransferFunction, int(m_surface->intermediaryColorDescription.transferFunction()));
|
||||
binder.shader()->setUniform(GLShader::IntUniform::DestinationNamedTransferFunction, int(m_surface->targetColorDescription.transferFunction()));
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
EglGbmLayerSurface(DrmGpu *gpu, EglGbmBackend *eglBackend, BufferTarget target = BufferTarget::Normal, FormatOption formatOption = FormatOption::PreferAlpha);
|
||||
~EglGbmLayerSurface();
|
||||
|
||||
std::optional<OutputLayerBeginFrameInfo> startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &iccProfile, bool enableColormanagement);
|
||||
std::optional<OutputLayerBeginFrameInfo> startRendering(const QSize &bufferSize, OutputTransform transformation, const QHash<uint32_t, QList<uint64_t>> &formats, const ColorDescription &colorDescription, const QVector3D &channelFactors, const std::shared_ptr<IccProfile> &iccProfile, bool enableColormanagement, double brightness);
|
||||
bool endRendering(const QRegion &damagedRegion, OutputFrame *frame);
|
||||
|
||||
bool doesSurfaceFit(const QSize &size, const QHash<uint32_t, QList<uint64_t>> &formats) const;
|
||||
|
@ -101,6 +101,7 @@ private:
|
|||
ColorDescription targetColorDescription = ColorDescription::sRGB;
|
||||
ColorDescription intermediaryColorDescription = ColorDescription::sRGB;
|
||||
QVector3D channelFactors = {1, 1, 1};
|
||||
double brightness = 1.0;
|
||||
std::unique_ptr<IccShader> iccShader;
|
||||
std::shared_ptr<IccProfile> iccProfile;
|
||||
|
||||
|
|
|
@ -402,6 +402,7 @@ void DrmOutput::applyQueuedChanges(const std::shared_ptr<OutputChangeSet> &props
|
|||
next.colorDescription = m_pipeline->colorDescription();
|
||||
next.vrrPolicy = props->vrrPolicy.value_or(m_state.vrrPolicy);
|
||||
next.colorProfileSource = props->colorProfileSource.value_or(m_state.colorProfileSource);
|
||||
next.brightness = props->brightness.value_or(m_state.brightness);
|
||||
setState(next);
|
||||
|
||||
if (!isEnabled() && m_pipeline->needsModeset()) {
|
||||
|
|
|
@ -610,6 +610,9 @@ void Output::setState(const State &state)
|
|||
if (oldState.colorProfileSource != state.colorProfileSource) {
|
||||
Q_EMIT colorProfileSourceChanged();
|
||||
}
|
||||
if (oldState.brightness != state.brightness) {
|
||||
Q_EMIT brightnessChanged();
|
||||
}
|
||||
if (oldState.enabled != state.enabled) {
|
||||
Q_EMIT enabledChanged();
|
||||
}
|
||||
|
@ -761,6 +764,11 @@ Output::ColorProfileSource Output::colorProfileSource() const
|
|||
{
|
||||
return m_state.colorProfileSource;
|
||||
}
|
||||
|
||||
double Output::brightness() const
|
||||
{
|
||||
return m_state.brightness;
|
||||
}
|
||||
} // namespace KWin
|
||||
|
||||
#include "moc_output.cpp"
|
||||
|
|
|
@ -358,6 +358,8 @@ public:
|
|||
double sdrGamutWideness() const;
|
||||
ColorProfileSource colorProfileSource() const;
|
||||
|
||||
double brightness() const;
|
||||
|
||||
const ColorDescription &colorDescription() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
@ -423,6 +425,7 @@ Q_SIGNALS:
|
|||
void sdrGamutWidenessChanged();
|
||||
void colorDescriptionChanged();
|
||||
void colorProfileSourceChanged();
|
||||
void brightnessChanged();
|
||||
|
||||
protected:
|
||||
struct Information
|
||||
|
@ -472,6 +475,7 @@ protected:
|
|||
std::optional<double> minBrightnessOverride;
|
||||
double sdrGamutWideness = 0;
|
||||
VrrPolicy vrrPolicy = VrrPolicy::Automatic;
|
||||
double brightness = 1.0;
|
||||
};
|
||||
|
||||
void setInformation(const Information &information);
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
std::optional<std::optional<double>> minBrightnessOverride;
|
||||
std::optional<double> sdrGamutWideness;
|
||||
std::optional<Output::ColorProfileSource> colorProfileSource;
|
||||
std::optional<double> brightness;
|
||||
};
|
||||
|
||||
class KWIN_EXPORT OutputConfiguration
|
||||
|
|
|
@ -229,6 +229,7 @@ void OutputConfigurationStore::storeConfig(const QList<Output *> &allOutputs, bo
|
|||
.maxAverageBrightnessOverride = changeSet->maxAverageBrightnessOverride.value_or(output->maxAverageBrightnessOverride()),
|
||||
.minBrightnessOverride = changeSet->minBrightnessOverride.value_or(output->minBrightnessOverride()),
|
||||
.sdrGamutWideness = changeSet->sdrGamutWideness.value_or(output->sdrGamutWideness()),
|
||||
.brightness = changeSet->brightness.value_or(output->brightness()),
|
||||
};
|
||||
*outputIt = SetupState{
|
||||
.outputIndex = *outputIndex,
|
||||
|
@ -263,6 +264,7 @@ void OutputConfigurationStore::storeConfig(const QList<Output *> &allOutputs, bo
|
|||
.maxAverageBrightnessOverride = output->maxAverageBrightnessOverride(),
|
||||
.minBrightnessOverride = output->minBrightnessOverride(),
|
||||
.sdrGamutWideness = output->sdrGamutWideness(),
|
||||
.brightness = output->brightness(),
|
||||
};
|
||||
*outputIt = SetupState{
|
||||
.outputIndex = *outputIndex,
|
||||
|
@ -311,6 +313,7 @@ std::pair<OutputConfiguration, QList<Output *>> OutputConfigurationStore::setupT
|
|||
.minBrightnessOverride = state.minBrightnessOverride,
|
||||
.sdrGamutWideness = state.sdrGamutWideness,
|
||||
.colorProfileSource = state.colorProfileSource,
|
||||
.brightness = state.brightness,
|
||||
};
|
||||
if (setupState.enabled) {
|
||||
priorities.push_back(std::make_pair(output, setupState.priority));
|
||||
|
@ -432,6 +435,7 @@ std::pair<OutputConfiguration, QList<Output *>> OutputConfigurationStore::genera
|
|||
.wideColorGamut = existingData.wideColorGamut.value_or(false),
|
||||
.autoRotationPolicy = existingData.autoRotation.value_or(Output::AutoRotationPolicy::InTabletMode),
|
||||
.colorProfileSource = existingData.colorProfileSource.value_or(Output::ColorProfileSource::sRGB),
|
||||
.brightness = existingData.brightness.value_or(1.0),
|
||||
};
|
||||
if (enable) {
|
||||
const auto modeSize = changeset->transform->map(mode->size());
|
||||
|
@ -737,6 +741,9 @@ void OutputConfigurationStore::load()
|
|||
state.colorProfileSource = Output::ColorProfileSource::sRGB;
|
||||
}
|
||||
}
|
||||
if (const auto it = data.find("brightness"); it != data.end() && it->isDouble()) {
|
||||
state.brightness = std::clamp(it->toDouble(), 0.0, 1.0);
|
||||
}
|
||||
outputDatas.push_back(state);
|
||||
}
|
||||
|
||||
|
@ -966,6 +973,9 @@ void OutputConfigurationStore::save()
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (output.brightness) {
|
||||
o["brightness"] = *output.brightness;
|
||||
}
|
||||
outputsData.append(o);
|
||||
}
|
||||
outputs["data"] = outputsData;
|
||||
|
|
|
@ -82,6 +82,7 @@ private:
|
|||
std::optional<double> maxAverageBrightnessOverride;
|
||||
std::optional<double> minBrightnessOverride;
|
||||
std::optional<double> sdrGamutWideness;
|
||||
std::optional<double> brightness;
|
||||
};
|
||||
struct SetupState
|
||||
{
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
static const quint32 s_version = 7;
|
||||
static const quint32 s_version = 8;
|
||||
|
||||
static QtWaylandServer::kde_output_device_v2::transform kwinTransformToOutputDeviceTransform(OutputTransform transform)
|
||||
{
|
||||
|
@ -106,6 +106,7 @@ public:
|
|||
void sendBrightnessOverrides(Resource *resource);
|
||||
void sendSdrGamutWideness(Resource *resource);
|
||||
void sendColorProfileSource(Resource *resource);
|
||||
void sendBrightness(Resource *resource);
|
||||
|
||||
OutputDeviceV2Interface *q;
|
||||
QPointer<Display> m_display;
|
||||
|
@ -142,6 +143,7 @@ public:
|
|||
std::optional<double> m_maxAverageBrightnessOverride;
|
||||
std::optional<double> m_minBrightnessOverride;
|
||||
color_profile_source m_colorProfile = color_profile_source::color_profile_source_sRGB;
|
||||
double m_brightness = 1.0;
|
||||
|
||||
protected:
|
||||
void kde_output_device_v2_bind_resource(Resource *resource) override;
|
||||
|
@ -228,6 +230,7 @@ OutputDeviceV2Interface::OutputDeviceV2Interface(Display *display, Output *handl
|
|||
updateBrightnessOverrides();
|
||||
updateSdrGamutWideness();
|
||||
updateColorProfileSource();
|
||||
updateBrightness();
|
||||
|
||||
connect(handle, &Output::geometryChanged,
|
||||
this, &OutputDeviceV2Interface::updateGlobalPosition);
|
||||
|
@ -258,6 +261,7 @@ OutputDeviceV2Interface::OutputDeviceV2Interface(Display *display, Output *handl
|
|||
connect(handle, &Output::brightnessMetadataChanged, this, &OutputDeviceV2Interface::updateBrightnessOverrides);
|
||||
connect(handle, &Output::sdrGamutWidenessChanged, this, &OutputDeviceV2Interface::updateSdrGamutWideness);
|
||||
connect(handle, &Output::colorProfileSourceChanged, this, &OutputDeviceV2Interface::updateColorProfileSource);
|
||||
connect(handle, &Output::brightnessChanged, this, &OutputDeviceV2Interface::updateBrightness);
|
||||
}
|
||||
|
||||
OutputDeviceV2Interface::~OutputDeviceV2Interface()
|
||||
|
@ -317,6 +321,7 @@ void OutputDeviceV2InterfacePrivate::kde_output_device_v2_bind_resource(Resource
|
|||
sendBrightnessOverrides(resource);
|
||||
sendSdrGamutWideness(resource);
|
||||
sendColorProfileSource(resource);
|
||||
sendBrightness(resource);
|
||||
sendDone(resource);
|
||||
}
|
||||
|
||||
|
@ -477,6 +482,13 @@ void OutputDeviceV2InterfacePrivate::sendColorProfileSource(Resource *resource)
|
|||
}
|
||||
}
|
||||
|
||||
void OutputDeviceV2InterfacePrivate::sendBrightness(Resource *resource)
|
||||
{
|
||||
if (resource->version() >= KDE_OUTPUT_DEVICE_V2_BRIGHTNESS_SINCE_VERSION) {
|
||||
send_brightness(resource->handle, m_brightness);
|
||||
}
|
||||
}
|
||||
|
||||
void OutputDeviceV2Interface::updateGeometry()
|
||||
{
|
||||
const auto clientResources = d->resourceMap();
|
||||
|
@ -821,6 +833,19 @@ void OutputDeviceV2Interface::updateColorProfileSource()
|
|||
}
|
||||
}
|
||||
|
||||
void OutputDeviceV2Interface::updateBrightness()
|
||||
{
|
||||
const uint32_t newBrightness = std::round(d->m_handle->brightness() * 10'000);
|
||||
if (d->m_brightness != newBrightness) {
|
||||
d->m_brightness = newBrightness;
|
||||
const auto clientResources = d->resourceMap();
|
||||
for (const auto &resource : clientResources) {
|
||||
d->sendBrightness(resource);
|
||||
d->sendDone(resource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OutputDeviceV2Interface *OutputDeviceV2Interface::get(wl_resource *native)
|
||||
{
|
||||
if (auto devicePrivate = resource_cast<OutputDeviceV2InterfacePrivate *>(native); devicePrivate && !devicePrivate->isGlobalRemoved()) {
|
||||
|
|
|
@ -78,6 +78,7 @@ private:
|
|||
void updateBrightnessOverrides();
|
||||
void updateSdrGamutWideness();
|
||||
void updateColorProfileSource();
|
||||
void updateBrightness();
|
||||
|
||||
std::unique_ptr<OutputDeviceV2InterfacePrivate> d;
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
namespace KWin
|
||||
{
|
||||
|
||||
static const quint32 s_version = 8;
|
||||
static const quint32 s_version = 9;
|
||||
|
||||
class OutputManagementV2InterfacePrivate : public QtWaylandServer::kde_output_management_v2
|
||||
{
|
||||
|
@ -67,6 +67,7 @@ protected:
|
|||
void kde_output_configuration_v2_set_brightness_overrides(Resource *resource, wl_resource *outputdevice, int32_t max_peak_brightness, int32_t max_average_brightness, int32_t min_brightness) override;
|
||||
void kde_output_configuration_v2_set_sdr_gamut_wideness(Resource *resource, wl_resource *outputdevice, uint32_t gamut_wideness) override;
|
||||
void kde_output_configuration_v2_set_color_profile_source(Resource *resource, wl_resource *outputdevice, uint32_t source) override;
|
||||
void kde_output_configuration_v2_set_brightness(Resource *resource, wl_resource *outputdevice, uint32_t brightness) override;
|
||||
};
|
||||
|
||||
OutputManagementV2InterfacePrivate::OutputManagementV2InterfacePrivate(Display *display)
|
||||
|
@ -342,6 +343,16 @@ void OutputConfigurationV2Interface::kde_output_configuration_v2_set_color_profi
|
|||
}
|
||||
}
|
||||
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_set_brightness(Resource *resource, wl_resource *outputdevice, uint32_t brightness)
|
||||
{
|
||||
if (invalid) {
|
||||
return;
|
||||
}
|
||||
if (OutputDeviceV2Interface *output = OutputDeviceV2Interface::get(outputdevice)) {
|
||||
config.changeSet(output->handle())->brightness = brightness / 10'000.0;
|
||||
}
|
||||
}
|
||||
|
||||
void OutputConfigurationV2Interface::kde_output_configuration_v2_destroy(Resource *resource)
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
|
|
Loading…
Reference in a new issue