backends/drm: allow offloading more complex color pipelines to legacy modesetting

This is done by combining multiple transfer functions and multipliers into one LUT.
This commit is contained in:
Xaver Hugl 2024-07-10 15:41:52 +02:00
parent e2c8f25d31
commit a86a914f70

View file

@ -164,25 +164,27 @@ DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy()
DrmPipeline::Error DrmPipeline::setLegacyGamma()
{
if (m_pending.crtcColorPipeline.ops.size() > 1) {
return DrmPipeline::Error::InvalidArguments;
}
QVector3D factors(1, 1, 1);
if (m_pending.crtcColorPipeline.ops.size() == 1) {
auto mult = std::get_if<ColorMultiplier>(&m_pending.crtcColorPipeline.ops.front().operation);
if (!mult) {
return DrmPipeline::Error::InvalidArguments;
}
factors = mult->factors;
}
QList<uint16_t> red(m_pending.crtc->gammaRampSize());
QList<uint16_t> green(m_pending.crtc->gammaRampSize());
QList<uint16_t> blue(m_pending.crtc->gammaRampSize());
for (int i = 0; i < m_pending.crtc->gammaRampSize(); i++) {
const double relative = i / double(m_pending.crtc->gammaRampSize() - 1) * std::numeric_limits<uint16_t>::max();
red[i] = std::round(relative * factors.x());
green[i] = std::round(relative * factors.y());
blue[i] = std::round(relative * factors.z());
const double input = i / double(m_pending.crtc->gammaRampSize() - 1);
QVector3D output = QVector3D(input, input, input);
for (const auto &op : m_pending.crtcColorPipeline.ops) {
if (auto tf = std::get_if<ColorTransferFunction>(&op.operation)) {
output = tf->tf.encodedToNits(output, tf->referenceLuminance);
} else if (auto tf = std::get_if<InverseColorTransferFunction>(&op.operation)) {
output = tf->tf.nitsToEncoded(output, tf->referenceLuminance);
} else if (auto mult = std::get_if<ColorMultiplier>(&op.operation)) {
output *= mult->factors;
} else {
// not supported
return Error::InvalidArguments;
}
}
red[i] = std::clamp(output.x(), 0.0f, 1.0f) * std::numeric_limits<uint16_t>::max();
green[i] = std::clamp(output.y(), 0.0f, 1.0f) * std::numeric_limits<uint16_t>::max();
blue[i] = std::clamp(output.z(), 0.0f, 1.0f) * std::numeric_limits<uint16_t>::max();
}
if (drmModeCrtcSetGamma(gpu()->fd(), m_pending.crtc->id(), m_pending.crtc->gammaRampSize(), red.data(), green.data(), blue.data()) != 0) {
qCWarning(KWIN_DRM) << "Setting gamma failed!" << strerror(errno);