Drop OpenGL based color correction from KWin
Summary: The feature has always been considered experimental. Unfortunately it is completely unmaintained and hasn't seen any commits in years. It requires kolor-manager to function, but that has not seen a release based on frameworks yet. This makes it difficult to maintain. In fact I have never been able from the introduction till now to setup a color corrected system. One needs kolor-manager and oyranos and especially the latter is hardly available on any linux distribution (e.g. not on the Debian/Ubuntu systems). Due to being unmaintained color correction in KWin did not keep up with recent changes. Neither did it see any updates during the xlib->xcb port, nor during the Wayland port. Especially the Wayland port with the rendering changes make it unlikely to function correctly. E.g. Wayland introduced a proper per-screen rendering, while color correction did a "fake" per screen rendering. How that is going to work in combination is something nobody ever tried. Now after the introduction of proper per-screen rendering the solution would be to port color correction to the new api, but that never happened. Color correction also modified the shaders, but a newer shader API got introduced some time ago. Whether the color correction shader support that or not, is unknown to me. Also which shader language versions are supported. I know it was based on 3d texture support, which back on introduction was partially lacking in OpenGL ES. Nowadays that changed, but color correction didn't update. Last but not least it is completely X11 based and there is no work on how to make it work with Wayland. Given all the problems, especially the fact that it is unmaintained and cannot be setup on my system, means to me that the only solution is to remove it. I'm open to having it reintroduced in future, but only if the availability on Linux distributions gets addressed before. As long as major linux distributions do not ship this feature, it should not be in KWin. Given that I must say that it was a mistake to add it in the first place and I need to point out that I was against the merge back then. Reviewers: #kwin, #plasma Subscribers: plasma-devel, kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D3402icc-effect-5.14.5
parent
2619ddf02e
commit
17e0bad922
|
@ -42,7 +42,6 @@ Compositing::Compositing(QObject *parent)
|
|||
, m_glScaleFilter(0)
|
||||
, m_xrScaleFilter(false)
|
||||
, m_glSwapStrategy(0)
|
||||
, m_glColorCorrection(false)
|
||||
, m_compositingType(0)
|
||||
, m_compositingEnabled(true)
|
||||
, m_changed(false)
|
||||
|
@ -57,7 +56,6 @@ Compositing::Compositing(QObject *parent)
|
|||
connect(this, &Compositing::glScaleFilterChanged, this, &Compositing::changed);
|
||||
connect(this, &Compositing::xrScaleFilterChanged, this, &Compositing::changed);
|
||||
connect(this, &Compositing::glSwapStrategyChanged, this, &Compositing::changed);
|
||||
connect(this, &Compositing::glColorCorrectionChanged, this, &Compositing::changed);
|
||||
connect(this, &Compositing::compositingTypeChanged, this, &Compositing::changed);
|
||||
connect(this, &Compositing::compositingEnabledChanged, this, &Compositing::changed);
|
||||
connect(this, &Compositing::openGLPlatformInterfaceChanged, this, &Compositing::changed);
|
||||
|
@ -94,7 +92,6 @@ void Compositing::reset()
|
|||
return 0;
|
||||
};
|
||||
setGlSwapStrategy(swapStrategy());
|
||||
setGlColorCorrection(kwinConfig.readEntry("GLColorCorrection", false));
|
||||
|
||||
auto type = [&kwinConfig]{
|
||||
const QString backend = kwinConfig.readEntry("Backend", "OpenGL");
|
||||
|
@ -127,7 +124,6 @@ void Compositing::defaults()
|
|||
setGlScaleFilter(2);
|
||||
setXrScaleFilter(false);
|
||||
setGlSwapStrategy(1);
|
||||
setGlColorCorrection(false);
|
||||
setCompositingType(CompositingType::OPENGL20_INDEX);
|
||||
const QModelIndex index = m_openGLPlatformInterfaceModel->indexForKey(QStringLiteral("glx"));
|
||||
setOpenGLPlatformInterface(index.isValid() ? index.row() : 0);
|
||||
|
@ -192,11 +188,6 @@ int Compositing::glSwapStrategy() const
|
|||
return m_glSwapStrategy;
|
||||
}
|
||||
|
||||
bool Compositing::glColorCorrection() const
|
||||
{
|
||||
return m_glColorCorrection;
|
||||
}
|
||||
|
||||
int Compositing::compositingType() const
|
||||
{
|
||||
return m_compositingType;
|
||||
|
@ -216,15 +207,6 @@ void Compositing::setAnimationSpeed(int speed)
|
|||
emit animationSpeedChanged(speed);
|
||||
}
|
||||
|
||||
void Compositing::setGlColorCorrection(bool correction)
|
||||
{
|
||||
if (correction == m_glColorCorrection) {
|
||||
return;
|
||||
}
|
||||
m_glColorCorrection = correction;
|
||||
emit glColorCorrectionChanged(correction);
|
||||
}
|
||||
|
||||
void Compositing::setGlScaleFilter(int index)
|
||||
{
|
||||
if (index == m_glScaleFilter) {
|
||||
|
@ -309,7 +291,6 @@ void Compositing::save()
|
|||
}
|
||||
};
|
||||
kwinConfig.writeEntry("GLPreferBufferSwap", swapStrategy());
|
||||
kwinConfig.writeEntry("GLColorCorrection", glColorCorrection());
|
||||
QString backend;
|
||||
bool glCore = false;
|
||||
switch (compositingType()) {
|
||||
|
|
|
@ -41,7 +41,6 @@ class Compositing : public QObject
|
|||
Q_PROPERTY(int glScaleFilter READ glScaleFilter WRITE setGlScaleFilter NOTIFY glScaleFilterChanged)
|
||||
Q_PROPERTY(bool xrScaleFilter READ xrScaleFilter WRITE setXrScaleFilter NOTIFY xrScaleFilterChanged)
|
||||
Q_PROPERTY(int glSwapStrategy READ glSwapStrategy WRITE setGlSwapStrategy NOTIFY glSwapStrategyChanged)
|
||||
Q_PROPERTY(bool glColorCorrection READ glColorCorrection WRITE setGlColorCorrection NOTIFY glColorCorrectionChanged)
|
||||
Q_PROPERTY(int compositingType READ compositingType WRITE setCompositingType NOTIFY compositingTypeChanged)
|
||||
Q_PROPERTY(bool compositingEnabled READ compositingEnabled WRITE setCompositingEnabled NOTIFY compositingEnabledChanged)
|
||||
Q_PROPERTY(KWin::Compositing::OpenGLPlatformInterfaceModel *openGLPlatformInterfaceModel READ openGLPlatformInterfaceModel CONSTANT)
|
||||
|
@ -59,7 +58,6 @@ public:
|
|||
int glScaleFilter() const;
|
||||
bool xrScaleFilter() const;
|
||||
int glSwapStrategy() const;
|
||||
bool glColorCorrection() const;
|
||||
int compositingType() const;
|
||||
bool compositingEnabled() const;
|
||||
int openGLPlatformInterface() const;
|
||||
|
@ -73,7 +71,6 @@ public:
|
|||
void setGlScaleFilter(int index);
|
||||
void setXrScaleFilter(bool filter);
|
||||
void setGlSwapStrategy(int strategy);
|
||||
void setGlColorCorrection(bool correction);
|
||||
void setCompositingType(int index);
|
||||
void setCompositingEnabled(bool enalbed);
|
||||
void setOpenGLPlatformInterface(int interface);
|
||||
|
@ -92,7 +89,6 @@ Q_SIGNALS:
|
|||
void glScaleFilterChanged(int);
|
||||
void xrScaleFilterChanged(int);
|
||||
void glSwapStrategyChanged(int);
|
||||
void glColorCorrectionChanged(bool);
|
||||
void compositingTypeChanged(int);
|
||||
void compositingEnabledChanged(bool);
|
||||
void openGLPlatformInterfaceChanged(int);
|
||||
|
@ -104,7 +100,6 @@ private:
|
|||
int m_glScaleFilter;
|
||||
bool m_xrScaleFilter;
|
||||
int m_glSwapStrategy;
|
||||
bool m_glColorCorrection;
|
||||
int m_compositingType;
|
||||
bool m_compositingEnabled;
|
||||
bool m_changed;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>462</width>
|
||||
<height>377</height>
|
||||
<height>349</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
|
@ -21,14 +21,14 @@
|
|||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text" stdset="0">
|
||||
<property name="text">
|
||||
<string>OpenGL compositing (the default) has crashed KWin in the past.
|
||||
This was most likely due to a driver bug.
|
||||
If you think that you have meanwhile upgraded to a stable driver,
|
||||
you can reset this protection but be aware that this might result in an immediate crash!
|
||||
Alternatively, you might want to use the XRender backend instead.</string>
|
||||
</property>
|
||||
<property name="wordWrap" stdset="0">
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -38,10 +38,10 @@ Alternatively, you might want to use the XRender backend instead.</string>
|
|||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text" stdset="0">
|
||||
<property name="text">
|
||||
<string>Scale method "Accurate" is not supported by all hardware and can cause performance regressions and rendering artifacts.</string>
|
||||
</property>
|
||||
<property name="wordWrap" stdset="0">
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -51,7 +51,7 @@ Alternatively, you might want to use the XRender backend instead.</string>
|
|||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="wordWrap" stdset="0">
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -61,10 +61,10 @@ Alternatively, you might want to use the XRender backend instead.</string>
|
|||
<property name="visible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text" stdset="0">
|
||||
<property name="text">
|
||||
<string>Keeping the window thumbnail always interferes with the minimized state of windows. This can result in windows not suspending their work when minimized.</string>
|
||||
</property>
|
||||
<property name="wordWrap" stdset="0">
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
|
@ -269,21 +269,7 @@ Alternatively, you might want to use the XRender backend instead.</string>
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Experimental:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="1">
|
||||
<widget class="QCheckBox" name="colorCorrection">
|
||||
<property name="text">
|
||||
<string>Enable color correction</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="13" column="1">
|
||||
<widget class="QCheckBox" name="windowsBlockCompositing">
|
||||
<property name="toolTip">
|
||||
<string>Applications can set a hint to block compositing when the window is open.
|
||||
|
|
|
@ -167,11 +167,6 @@ void KWinCompositingSettings::init()
|
|||
}
|
||||
);
|
||||
|
||||
// color correction
|
||||
m_form.colorCorrection->setChecked(m_compositing->glColorCorrection());
|
||||
connect(m_compositing, &Compositing::glColorCorrectionChanged, m_form.colorCorrection, &QCheckBox::setChecked);
|
||||
connect(m_form.colorCorrection, &QCheckBox::toggled, m_compositing, &Compositing::setGlColorCorrection);
|
||||
|
||||
// windows blocking compositing
|
||||
m_form.windowsBlockCompositing->setChecked(m_compositing->windowsBlockCompositing());
|
||||
connect(m_compositing, &Compositing::windowsBlockCompositingChanged, m_form.windowsBlockCompositing, &QCheckBox::setChecked);
|
||||
|
@ -195,7 +190,6 @@ void KWinCompositingSettings::init()
|
|||
m_form.glScaleFilterLabel->setVisible(currentType != CompositingType::XRENDER_INDEX);
|
||||
m_form.xrScaleFilter->setVisible(currentType == CompositingType::XRENDER_INDEX);
|
||||
m_form.xrScaleFilterLabel->setVisible(currentType == CompositingType::XRENDER_INDEX);
|
||||
m_form.colorCorrection->setEnabled(currentType == CompositingType::OPENGL31_INDEX || currentType == CompositingType::OPENGL20_INDEX);
|
||||
};
|
||||
showHideBasedOnType();
|
||||
connect(m_form.type, currentIndexChangedSignal,
|
||||
|
|
|
@ -243,9 +243,6 @@
|
|||
<entry name="GLLegacy" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="GLColorCorrection" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
<entry name="XRenderSmoothScale" type="Bool">
|
||||
<default>false</default>
|
||||
</entry>
|
||||
|
|
|
@ -82,7 +82,6 @@ set(kwin_GLUTILSLIB_SRCS
|
|||
kwingltexture.cpp
|
||||
kwinglutils_funcs.cpp
|
||||
kwinglplatform.cpp
|
||||
kwinglcolorcorrection.cpp
|
||||
logging.cpp
|
||||
)
|
||||
|
||||
|
@ -90,7 +89,7 @@ macro( KWIN4_ADD_GLUTILS_BACKEND name glinclude )
|
|||
include_directories(${glinclude})
|
||||
add_library(${name} SHARED ${kwin_GLUTILSLIB_SRCS})
|
||||
generate_export_header(${name} BASE_NAME kwinglutils EXPORT_FILE_NAME kwinglutils_export.h)
|
||||
target_link_libraries(${name} PUBLIC Qt5::DBus XCB::XCB KF5::CoreAddons KF5::WindowSystem)
|
||||
target_link_libraries(${name} PUBLIC XCB::XCB KF5::CoreAddons KF5::WindowSystem)
|
||||
set_target_properties(${name} PROPERTIES
|
||||
VERSION ${KWINEFFECTS_VERSION_STRING}
|
||||
SOVERSION ${KWINEFFECTS_SOVERSION}
|
||||
|
|
|
@ -1,674 +0,0 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2012 Casian Andrei <skeletk13@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#include "kwinglcolorcorrection.h"
|
||||
#include "kwinglcolorcorrection_p.h"
|
||||
|
||||
#include "kwinglplatform.h"
|
||||
#include "kwinglutils.h"
|
||||
#include "logging_p.h"
|
||||
|
||||
#include <QByteArrayMatcher>
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusError>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
#include <QPair>
|
||||
#include <QVector3D>
|
||||
|
||||
namespace KWin {
|
||||
|
||||
/*
|
||||
* Color lookup table
|
||||
*
|
||||
* The 3D lookup texture has 64 points in each dimension, using 16 bit integers.
|
||||
* That means each active region will use 1.5MiB of texture memory.
|
||||
*/
|
||||
static const int LUT_GRID_POINTS = 64;
|
||||
static const size_t CLUT_ELEMENT_SIZE = sizeof(quint16);
|
||||
static const uint CLUT_ELEMENT_COUNT = LUT_GRID_POINTS * LUT_GRID_POINTS * LUT_GRID_POINTS * 3;
|
||||
static const size_t CLUT_DATA_SIZE = CLUT_ELEMENT_COUNT * CLUT_ELEMENT_SIZE;
|
||||
|
||||
inline static void buildDummyClut(Clut &c)
|
||||
{
|
||||
c.resize(CLUT_ELEMENT_COUNT);
|
||||
quint16 *p = c.data();
|
||||
|
||||
for (int ib = 0; ib < LUT_GRID_POINTS; ++ ib) {
|
||||
quint16 b = (quint16) ((float) ib / (LUT_GRID_POINTS - 1) * 65535.0 + 0.5);
|
||||
for (int ig = 0; ig < LUT_GRID_POINTS; ++ ig) {
|
||||
quint16 g = (quint16) ((float) ig / (LUT_GRID_POINTS - 1) * 65535.0 + 0.5);
|
||||
for (int ir = 0; ir < LUT_GRID_POINTS; ++ ir) {
|
||||
quint16 r = (quint16) ((float) ir / (LUT_GRID_POINTS - 1) * 65535.0 + 0.5);
|
||||
|
||||
*(p ++) = r;
|
||||
*(p ++) = g;
|
||||
*(p ++) = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Color Server Interface
|
||||
*/
|
||||
|
||||
ColorServerInterface::ColorServerInterface(const QString &service,
|
||||
const QString &path,
|
||||
const QDBusConnection &connection,
|
||||
QObject *parent)
|
||||
: QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent)
|
||||
, m_versionInfoWatcher(0)
|
||||
, m_outputClutsWatcher(0)
|
||||
, m_regionClutsWatcher(0)
|
||||
, m_versionInfoUpdated(false)
|
||||
, m_outputClutsUpdated(false)
|
||||
, m_regionClutsUpdated(false)
|
||||
, m_versionInfo(0)
|
||||
, m_signaledFail(false)
|
||||
{
|
||||
qDBusRegisterMetaType< Clut >();
|
||||
qDBusRegisterMetaType< ClutList >();
|
||||
qDBusRegisterMetaType< RegionalClut >();
|
||||
qDBusRegisterMetaType< RegionalClutMap >();
|
||||
|
||||
connect(this, SIGNAL(outputClutsChanged()), this, SLOT(update()));
|
||||
connect(this, SIGNAL(regionClutsChanged()), this, SLOT(update()));
|
||||
}
|
||||
|
||||
ColorServerInterface::~ColorServerInterface()
|
||||
{
|
||||
}
|
||||
|
||||
uint ColorServerInterface::versionInfo() const
|
||||
{
|
||||
if (!m_versionInfoUpdated)
|
||||
qCWarning(LIBKWINGLUTILS) << "Version info not updated";
|
||||
return m_versionInfo;
|
||||
}
|
||||
|
||||
const ClutList& ColorServerInterface::outputCluts() const
|
||||
{
|
||||
return m_outputCluts;
|
||||
}
|
||||
|
||||
const RegionalClutMap& ColorServerInterface::regionCluts() const
|
||||
{
|
||||
return m_regionCluts;
|
||||
}
|
||||
|
||||
void ColorServerInterface::update()
|
||||
{
|
||||
m_versionInfoUpdated = false;
|
||||
m_outputClutsUpdated = false;
|
||||
m_regionClutsUpdated = false;
|
||||
delete m_versionInfoWatcher;
|
||||
delete m_outputClutsWatcher;
|
||||
delete m_regionClutsWatcher;
|
||||
m_versionInfoWatcher = new QDBusPendingCallWatcher(getVersionInfo(), this);
|
||||
m_outputClutsWatcher = new QDBusPendingCallWatcher(getOutputCluts(), this);
|
||||
m_regionClutsWatcher = new QDBusPendingCallWatcher(getRegionCluts(), this);
|
||||
connect(m_versionInfoWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
|
||||
connect(m_outputClutsWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
|
||||
connect(m_regionClutsWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)),
|
||||
this, SLOT(callFinishedSlot(QDBusPendingCallWatcher*)));
|
||||
|
||||
m_signaledFail = false;
|
||||
}
|
||||
|
||||
QDBusPendingReply< uint > ColorServerInterface::getVersionInfo()
|
||||
{
|
||||
return QDBusPendingReply< uint >(asyncCall(QStringLiteral("getVersionInfo")));
|
||||
}
|
||||
|
||||
QDBusPendingReply< ClutList > ColorServerInterface::getOutputCluts()
|
||||
{
|
||||
return QDBusPendingReply< ClutList >(asyncCall(QStringLiteral("getOutputCluts")));
|
||||
}
|
||||
|
||||
QDBusPendingReply< RegionalClutMap > ColorServerInterface::getRegionCluts()
|
||||
{
|
||||
return QDBusPendingReply< RegionalClutMap >(asyncCall(QStringLiteral("getRegionCluts")));
|
||||
}
|
||||
|
||||
void ColorServerInterface::callFinishedSlot(QDBusPendingCallWatcher *watcher)
|
||||
{
|
||||
if (watcher == m_versionInfoWatcher) {
|
||||
qCDebug(LIBKWINGLUTILS) << "Version info call finished";
|
||||
QDBusPendingReply< uint > reply = *watcher;
|
||||
if (reply.isError()) {
|
||||
qCWarning(LIBKWINGLUTILS) << reply.error();
|
||||
if (!m_signaledFail)
|
||||
emit updateFailed();
|
||||
m_signaledFail = true;
|
||||
return;
|
||||
} else {
|
||||
m_versionInfo = reply.value();
|
||||
m_versionInfoUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (watcher == m_outputClutsWatcher) {
|
||||
qCDebug(LIBKWINGLUTILS) << "Output cluts call finished";
|
||||
QDBusPendingReply< ClutList > reply = *watcher;
|
||||
if (reply.isError()) {
|
||||
qCWarning(LIBKWINGLUTILS) << reply.error();
|
||||
if (!m_signaledFail)
|
||||
emit updateFailed();
|
||||
m_signaledFail = true;
|
||||
return;
|
||||
} else {
|
||||
m_outputCluts = reply.value();
|
||||
m_outputClutsUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (watcher == m_regionClutsWatcher) {
|
||||
qCDebug(LIBKWINGLUTILS) << "Region cluts call finished";
|
||||
QDBusPendingReply< RegionalClutMap > reply = *watcher;
|
||||
if (reply.isError()) {
|
||||
qCWarning(LIBKWINGLUTILS) << reply.error();
|
||||
if (!m_signaledFail)
|
||||
emit updateFailed();
|
||||
m_signaledFail = true;
|
||||
return;
|
||||
} else {
|
||||
m_regionCluts = reply.value();
|
||||
m_regionClutsUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_versionInfoUpdated &&
|
||||
m_outputClutsUpdated &&
|
||||
m_regionClutsUpdated) {
|
||||
qCDebug(LIBKWINGLUTILS) << "Update succeeded";
|
||||
emit updateSucceeded();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* To be injected in the fragment shader sources
|
||||
*/
|
||||
static const char s_ccVars[] =
|
||||
"uniform sampler3D u_ccLookupTexture;\n";
|
||||
static const char s_ccAlteration[] =
|
||||
"gl_FragColor.rgb = texture3D(u_ccLookupTexture, gl_FragColor.rgb / gl_FragColor.a).rgb * gl_FragColor.a;\n";
|
||||
static const char s_ccAlteration_140[] =
|
||||
"fragColor.rgb = texture(u_ccLookupTexture, fragColor.rgb / fragColor.a).rgb * fragColor.a;\n";
|
||||
|
||||
|
||||
/*
|
||||
* Color Correction
|
||||
*/
|
||||
|
||||
ColorCorrection::ColorCorrection(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d_ptr(new ColorCorrectionPrivate(this))
|
||||
{
|
||||
connect(this, SIGNAL(errorOccured()), this, SIGNAL(changed()));
|
||||
}
|
||||
|
||||
ColorCorrection::~ColorCorrection()
|
||||
{
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
ColorCorrectionPrivate::ColorCorrectionPrivate(ColorCorrection *parent)
|
||||
: QObject(parent)
|
||||
, m_enabled(false)
|
||||
, m_hasError(false)
|
||||
, m_duringEnablingPhase(false)
|
||||
, m_haveTexture3D(!GLPlatform::instance()->isGLES() || hasGLVersion(3, 0) || hasGLExtension(QByteArrayLiteral("GL_OES_texture_3D")))
|
||||
, m_ccTextureUnit(-1)
|
||||
, m_dummyCCTexture(0)
|
||||
, m_lastOutput(-1)
|
||||
, q_ptr(parent)
|
||||
{
|
||||
// We need a dummy color lookup table (sRGB profile to sRGB profile)
|
||||
buildDummyClut(m_dummyClut);
|
||||
|
||||
// Establish a D-Bus communication interface with KolorServer
|
||||
m_csi = new ColorServerInterface(
|
||||
QStringLiteral("org.kde.kded5"),
|
||||
QStringLiteral("/modules/kolorserver"),
|
||||
QDBusConnection::sessionBus(),
|
||||
this);
|
||||
|
||||
m_outputCluts = &m_csi->outputCluts();
|
||||
|
||||
connect(m_csi, SIGNAL(updateSucceeded()), this, SLOT(colorServerUpdateSucceededSlot()));
|
||||
connect(m_csi, SIGNAL(updateFailed()), this, SLOT(colorServerUpdateFailedSlot()));
|
||||
}
|
||||
|
||||
ColorCorrectionPrivate::~ColorCorrectionPrivate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ColorCorrection::isEnabled() const
|
||||
{
|
||||
Q_D(const ColorCorrection);
|
||||
return d->m_enabled;
|
||||
}
|
||||
|
||||
bool ColorCorrection::setEnabled(bool enabled)
|
||||
{
|
||||
Q_D(ColorCorrection);
|
||||
|
||||
if (enabled == d->m_enabled)
|
||||
return true;
|
||||
|
||||
if (enabled && d->m_hasError) {
|
||||
qCCritical(LIBKWINGLUTILS) << "cannot enable color correction because of a previous error";
|
||||
return false;
|
||||
}
|
||||
|
||||
const GLPlatform *gl = GLPlatform::instance();
|
||||
if (enabled && gl->isGLES() && !d->m_haveTexture3D) {
|
||||
qCCritical(LIBKWINGLUTILS) << "color correction is not supported on OpenGL ES without OES_texture_3D";
|
||||
d->m_hasError = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
// Update all profiles and regions
|
||||
d->m_csi->update();
|
||||
qCDebug(LIBKWINGLUTILS) << "color correction will be enabled after contacting KolorManager";
|
||||
d->m_duringEnablingPhase = true;
|
||||
// d->m_enabled will be set to true in colorServerUpdateSucceededSlot()
|
||||
} else {
|
||||
d->deleteCCTextures();
|
||||
d->m_enabled = false;
|
||||
GLShader::sColorCorrect = false;
|
||||
qCDebug(LIBKWINGLUTILS) << "color correction has been disabled";
|
||||
|
||||
// Reload all shaders
|
||||
ShaderManager::cleanup();
|
||||
ShaderManager::instance();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ColorCorrection::setupForOutput(int screen)
|
||||
{
|
||||
Q_D(ColorCorrection);
|
||||
|
||||
if (!d->m_enabled || d->m_hasError)
|
||||
return;
|
||||
|
||||
GLShader *shader = ShaderManager::instance()->getBoundShader();
|
||||
if (!shader) {
|
||||
qCCritical(LIBKWINGLUTILS) << "no bound shader for color correction setup";
|
||||
d->m_hasError = true;
|
||||
emit errorOccured();
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->m_ccTextureUnit < 0) {
|
||||
GLint maxUnits = 0;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxUnits);
|
||||
d->m_ccTextureUnit = maxUnits - 1;
|
||||
}
|
||||
|
||||
if (!shader->setUniform(GLShader::ColorCorrectionLookupTextureUnit, d->m_ccTextureUnit)) {
|
||||
qCCritical(LIBKWINGLUTILS) << "unable to set uniform for the color correction lookup texture";
|
||||
d->m_hasError = true;
|
||||
emit errorOccured();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->setupCCTextures()) {
|
||||
qCCritical(LIBKWINGLUTILS) << "unable to setup color correction textures";
|
||||
d->m_hasError = true;
|
||||
emit errorOccured();
|
||||
return;
|
||||
}
|
||||
|
||||
GLint activeTexture;
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
|
||||
glActiveTexture(GL_TEXTURE0 + d->m_ccTextureUnit);
|
||||
|
||||
if (d->m_outputCCTextures.isEmpty() || screen < 0 || screen >= d->m_outputCCTextures.count()) {
|
||||
// Configure with a dummy texture in case something is wrong
|
||||
Q_ASSERT(d->m_dummyCCTexture != 0);
|
||||
glBindTexture(GL_TEXTURE_3D, d->m_dummyCCTexture);
|
||||
} else {
|
||||
// Everything looks ok, configure with the proper color correction texture
|
||||
glBindTexture(GL_TEXTURE_3D, d->m_outputCCTextures[screen]);
|
||||
}
|
||||
|
||||
glActiveTexture(activeTexture);
|
||||
|
||||
d->m_lastOutput = screen;
|
||||
}
|
||||
|
||||
void ColorCorrection::reset()
|
||||
{
|
||||
setupForOutput(-1);
|
||||
}
|
||||
|
||||
QByteArray ColorCorrection::prepareFragmentShader(const QByteArray &sourceCode)
|
||||
{
|
||||
bool sourceIsValid = true;
|
||||
|
||||
/*
|
||||
* Detect comments to ignore them later
|
||||
*/
|
||||
QList< QPair< int, int > > comments;
|
||||
int beginIndex, endIndex = 0;
|
||||
int i1, i2;
|
||||
|
||||
enum {ctNone, ctBegin, ctEnd} commentType;
|
||||
QByteArrayMatcher commentBegin1("/*"), commentBegin2("//");
|
||||
QByteArrayMatcher commentEnd1("*/"), commentEnd2("\n");
|
||||
|
||||
do {
|
||||
// Determine the next comment begin index
|
||||
i1 = commentBegin1.indexIn(sourceCode, endIndex);
|
||||
i2 = commentBegin2.indexIn(sourceCode, endIndex);
|
||||
if (i1 == -1 && i2 == -1) commentType = ctNone;
|
||||
else if (i1 == -1) commentType = ctEnd;
|
||||
else if (i2 == -1) commentType = ctBegin;
|
||||
else if (i1 < i2) commentType = ctBegin;
|
||||
else commentType = ctEnd;
|
||||
if (commentType == ctNone)
|
||||
break;
|
||||
|
||||
// Determine the comment's end index
|
||||
if (commentType == ctBegin) {
|
||||
beginIndex = i1;
|
||||
endIndex = commentEnd1.indexIn(sourceCode, beginIndex + 2);
|
||||
}
|
||||
if (commentType == ctEnd) {
|
||||
beginIndex = i2;
|
||||
endIndex = commentEnd2.indexIn(sourceCode, beginIndex + 2);
|
||||
}
|
||||
|
||||
if (endIndex != -1) {
|
||||
if (commentType == ctBegin)
|
||||
endIndex ++; // adjust for "*/" to be removed
|
||||
if (commentType == ctEnd)
|
||||
endIndex --; // adjust for "\n" to be kept
|
||||
comments.append(QPair< int, int >(beginIndex, endIndex));
|
||||
} else {
|
||||
if (commentType == ctBegin)
|
||||
sourceIsValid = false;
|
||||
if (commentType == ctEnd)
|
||||
comments.append(QPair< int, int >(beginIndex, sourceCode.length()));
|
||||
break;
|
||||
}
|
||||
} while (sourceIsValid);
|
||||
if (!sourceIsValid)
|
||||
return sourceCode;
|
||||
|
||||
// Create a version of the source code with the comments stripped out
|
||||
QByteArray cfSource(sourceCode); // comment-free source code
|
||||
for (int i = comments.size() - 1; i >= 0; -- i) {
|
||||
beginIndex = comments[i].first;
|
||||
endIndex = comments[i].second;
|
||||
cfSource.replace(beginIndex, endIndex - beginIndex + 1, " ");
|
||||
}
|
||||
|
||||
/*
|
||||
* Browse through the code while counting braces
|
||||
* Search for "void main() { ... }:
|
||||
*/
|
||||
QByteArrayMatcher braceOpen("{");
|
||||
QByteArrayMatcher braceClose("}");
|
||||
QByteArrayMatcher voidKeyword("void");
|
||||
int levelOfScope = 0;
|
||||
enum {brNone, brOpen, brClose} braceType;
|
||||
|
||||
int mainFuncBegin = -1; // where "void main" begins
|
||||
int mainFuncEnd = -1; // at the closing brace of "void main"
|
||||
bool insideMainFunc = false;
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
// Determine where the next brace is
|
||||
i1 = braceOpen.indexIn(cfSource, i);
|
||||
i2 = braceClose.indexIn(cfSource, i);
|
||||
if (i1 == -1 && i2 == -1) braceType = brNone;
|
||||
else if (i1 == -1) braceType = brClose;
|
||||
else if (i2 == -1) braceType = brOpen;
|
||||
else if (i1 < i2) braceType = brOpen;
|
||||
else braceType = brClose;
|
||||
if (braceType == brNone) {
|
||||
if (levelOfScope > 0)
|
||||
sourceIsValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle opening brance (see if is from void main())
|
||||
if (braceType == brOpen) {
|
||||
if (levelOfScope == 0) {
|
||||
// Need to search between i and i1 (the last '}' and the current '{'
|
||||
QByteArray section = cfSource.mid(i, i1 - i);
|
||||
int i_void = -1;
|
||||
while ((i_void = section.indexOf("void", i_void + 1)) != -1) {
|
||||
// Extract the subsection that begins with "void"
|
||||
QByteArray subSection = section.mid(i_void).simplified();
|
||||
subSection.replace('(', " ( ");
|
||||
subSection.replace(')', " ) ");
|
||||
QList<QByteArray> tokens = subSection.split(' ');
|
||||
for (int i_token = tokens.size() - 1; i_token >= 0; -- i_token)
|
||||
if (tokens[i_token].trimmed().isEmpty())
|
||||
tokens.removeAt(i_token);
|
||||
if (tokens.size() == 4 &&
|
||||
tokens[0] == "void" &&
|
||||
tokens[1] == "main" &&
|
||||
tokens[2] == "(" &&
|
||||
tokens[3] == ")") {
|
||||
if (mainFuncBegin != -1) {
|
||||
sourceIsValid = false;
|
||||
break;
|
||||
}
|
||||
mainFuncBegin = i + i_void;
|
||||
insideMainFunc = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
levelOfScope ++;
|
||||
i = i1 + 1;
|
||||
}
|
||||
|
||||
// Handle closing brace (see if it is from void main())
|
||||
if (braceType == brClose) {
|
||||
levelOfScope --;
|
||||
if (levelOfScope < 0) {
|
||||
sourceIsValid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (levelOfScope == 0 && insideMainFunc) {
|
||||
mainFuncEnd = i2;
|
||||
insideMainFunc = false;
|
||||
}
|
||||
|
||||
i = i2 + 1;
|
||||
}
|
||||
} while (sourceIsValid);
|
||||
sourceIsValid = sourceIsValid && mainFuncBegin != -1 && mainFuncEnd != -1;
|
||||
if (!sourceIsValid)
|
||||
return sourceCode;
|
||||
|
||||
QByteArray mainFunc = cfSource.mid(mainFuncBegin, mainFuncEnd - mainFuncBegin + 1);
|
||||
|
||||
/*
|
||||
* Insert color correction variables at the beginning and
|
||||
* the color correction code at the end of the main function.
|
||||
* Need to handle return "jumps" inside the main function.
|
||||
*/
|
||||
if (GLPlatform::instance()->glslVersion() >= kVersionNumber(1, 40))
|
||||
mainFunc.insert(mainFunc.size() - 1, s_ccAlteration_140);
|
||||
else
|
||||
mainFunc.insert(mainFunc.size() - 1, s_ccAlteration);
|
||||
mainFunc.insert(0, s_ccVars);
|
||||
|
||||
// Search for return statements inside the main function
|
||||
QByteArrayMatcher returnMatcher("return");
|
||||
i = -1;
|
||||
while ((i = returnMatcher.indexIn(mainFunc, i)) != -1) {
|
||||
i1 = mainFunc.indexOf(';', i);
|
||||
mainFunc.insert(i1 + 1, '}');
|
||||
mainFunc.insert(i, '{');
|
||||
mainFunc.insert(i + 1, s_ccAlteration);
|
||||
mainFuncEnd += strlen(s_ccAlteration) + 2;
|
||||
|
||||
i = i1 + strlen(s_ccAlteration) + 2;
|
||||
}
|
||||
|
||||
// Replace the main function
|
||||
cfSource.replace(mainFuncBegin, mainFuncEnd - mainFuncBegin + 1, mainFunc);
|
||||
|
||||
return cfSource;
|
||||
}
|
||||
|
||||
bool ColorCorrectionPrivate::setupCCTextures()
|
||||
{
|
||||
if (!m_enabled || m_hasError) {
|
||||
qCWarning(LIBKWINGLUTILS) << "Color correction not enabled or an error occurred, refusing to set up textures";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Dummy texture first
|
||||
if (!m_dummyCCTexture) {
|
||||
glGenTextures(1, &m_dummyCCTexture);
|
||||
if (!setupCCTexture(m_dummyCCTexture, m_dummyClut)) {
|
||||
qCCritical(LIBKWINGLUTILS) << "unable to setup dummy color correction texture";
|
||||
m_dummyCCTexture = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Setup actual color correction textures
|
||||
if (m_outputCCTextures.isEmpty() && !m_outputCluts->isEmpty()) {
|
||||
qCDebug(LIBKWINGLUTILS) << "setting up output color correction textures";
|
||||
|
||||
const int outputCount = m_outputCluts->size();
|
||||
m_outputCCTextures.resize(outputCount);
|
||||
glGenTextures(outputCount, m_outputCCTextures.data());
|
||||
|
||||
for (int i = 0; i < outputCount; ++i)
|
||||
if (!setupCCTexture(m_outputCCTextures[i], m_outputCluts->at(i))) {
|
||||
qCCritical(LIBKWINGLUTILS) << "unable to set up color correction texture for output" << i;
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void ColorCorrectionPrivate::deleteCCTextures()
|
||||
{
|
||||
// Delete dummy texture
|
||||
if (m_dummyCCTexture) {
|
||||
glDeleteTextures(1, &m_dummyCCTexture);
|
||||
m_dummyCCTexture = 0;
|
||||
}
|
||||
|
||||
// Delete actual color correction extures
|
||||
if (!m_outputCCTextures.isEmpty()) {
|
||||
glDeleteTextures(m_outputCCTextures.size(), m_outputCCTextures.data());
|
||||
m_outputCCTextures.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool ColorCorrectionPrivate::setupCCTexture(GLuint texture, const Clut& clut)
|
||||
{
|
||||
if ((uint) clut.size() != CLUT_ELEMENT_COUNT) {
|
||||
qCCritical(LIBKWINGLUTILS) << "cannot setup CC texture: invalid color lookup table";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear any previous GL errors
|
||||
checkGLError("setupCCTexture-clearErrors");
|
||||
|
||||
glBindTexture(GL_TEXTURE_3D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
if (!GLPlatform::instance()->isGLES()) {
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16,
|
||||
LUT_GRID_POINTS, LUT_GRID_POINTS, LUT_GRID_POINTS,
|
||||
0, GL_RGB, GL_UNSIGNED_SHORT, clut.data());
|
||||
} else {
|
||||
const int textureDataSize = clut.size();
|
||||
QVector<quint8> textureData(textureDataSize);
|
||||
quint8 *pTextureData = textureData.data();
|
||||
const quint16 *pClutData = clut.data();
|
||||
for (int i = 0; i < textureDataSize; ++i)
|
||||
*(pTextureData++) = *(pClutData++) >> 8;
|
||||
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB,
|
||||
LUT_GRID_POINTS, LUT_GRID_POINTS, LUT_GRID_POINTS,
|
||||
0, GL_RGB, GL_UNSIGNED_BYTE, textureData.data());
|
||||
}
|
||||
|
||||
return !checkGLError("setupCCTexture");
|
||||
}
|
||||
|
||||
void ColorCorrectionPrivate::colorServerUpdateSucceededSlot()
|
||||
{
|
||||
Q_Q(ColorCorrection);
|
||||
|
||||
qCDebug(LIBKWINGLUTILS) << "Update of color profiles succeeded";
|
||||
|
||||
// Force the color correction textures to be recreated
|
||||
deleteCCTextures();
|
||||
|
||||
// If this is reached after enabling color correction using ColorCorrection::setEnabled(true)
|
||||
if (m_duringEnablingPhase) {
|
||||
m_duringEnablingPhase = false;
|
||||
m_enabled = true;
|
||||
GLShader::sColorCorrect = true;
|
||||
qCDebug(LIBKWINGLUTILS) << "Color correction has been enabled";
|
||||
|
||||
// Reload all shaders
|
||||
ShaderManager::cleanup();
|
||||
}
|
||||
|
||||
emit q->changed();
|
||||
}
|
||||
|
||||
void ColorCorrectionPrivate::colorServerUpdateFailedSlot()
|
||||
{
|
||||
Q_Q(ColorCorrection);
|
||||
|
||||
m_duringEnablingPhase = false;
|
||||
|
||||
qCCritical(LIBKWINGLUTILS) << "Update of color profiles failed";
|
||||
m_hasError = true;
|
||||
emit q->errorOccured();
|
||||
}
|
||||
|
||||
} // KWin namespace
|
|
@ -1,106 +0,0 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2012 Casian Andrei <skeletk13@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef KWIN_COLOR_CORRECTION_H
|
||||
#define KWIN_COLOR_CORRECTION_H
|
||||
|
||||
#include <kwinglutils_export.h>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace KWin {
|
||||
|
||||
class ColorCorrectionPrivate;
|
||||
|
||||
/**
|
||||
* Implements a color correction mechanism. The settings are obtained
|
||||
* asynchronously via D-Bus from kolor-server, which is part of kolor-manager.
|
||||
*
|
||||
* If it fails to get the settings, nothing should happen (no correction), even
|
||||
* if it is set to enabled.
|
||||
*
|
||||
* Supports per-output and per-region correction (window region).
|
||||
*
|
||||
* \warning This class is not designed to be used by effects, however
|
||||
* it may happen to be useful their case somehow.
|
||||
*/
|
||||
class KWINGLUTILS_EXPORT ColorCorrection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ColorCorrection(QObject *parent = nullptr);
|
||||
virtual ~ColorCorrection();
|
||||
|
||||
/**
|
||||
* Prepares color correction for the output number \param screen.
|
||||
* Sets up the appropriate color lookup texture for the output.
|
||||
*/
|
||||
void setupForOutput(int screen);
|
||||
|
||||
/**
|
||||
* Unsets color correction by using a dummy color lookup texture. This
|
||||
* does not disable anything, the CC mechanisms remain in place. Instead, it
|
||||
* indicates to draw normally.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Modifies \param sourceCode, making it suitable for performing
|
||||
* color correction. This is done by inserting a 3d texture lookup operation
|
||||
* just before the output fragment color is returned.
|
||||
*/
|
||||
static QByteArray prepareFragmentShader(const QByteArray &sourceCode);
|
||||
|
||||
/**
|
||||
* @return whether color correction is enabled
|
||||
*/
|
||||
bool isEnabled() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Enables or disables color correction. Compositing should be restarted
|
||||
* for changes to take effect.
|
||||
*
|
||||
* @return true when successful
|
||||
*/
|
||||
bool setEnabled(bool enabled);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when some changes happened to the color correction settings, and
|
||||
* a full repaint of the scene should be done to make the new settings visible.
|
||||
*/
|
||||
void changed();
|
||||
|
||||
/**
|
||||
* Emitted when something failed because of an error (probably a GL error)
|
||||
* The description of the error should be found in the logs.
|
||||
*/
|
||||
void errorOccured();
|
||||
|
||||
private:
|
||||
ColorCorrectionPrivate * const d_ptr;
|
||||
Q_DECLARE_PRIVATE(ColorCorrection)
|
||||
};
|
||||
|
||||
} // KWin namespace
|
||||
|
||||
#endif // KWIN_COLOR_CORRECTION_H
|
|
@ -1,168 +0,0 @@
|
|||
/********************************************************************
|
||||
KWin - the KDE window manager
|
||||
This file is part of the KDE project.
|
||||
|
||||
Copyright (C) 2012 Casian Andrei <skeletk13@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
|
||||
#ifndef KWIN_COLOR_CORRECTION_P_H_
|
||||
#define KWIN_COLOR_CORRECTION_P_H_
|
||||
|
||||
#include "kwinglcolorcorrection.h"
|
||||
#include "kwinglutils_funcs.h"
|
||||
|
||||
#include <QDBusAbstractInterface>
|
||||
#include <QDBusMetaType>
|
||||
#include <QDBusPendingReply>
|
||||
#include <QRect>
|
||||
#include <QVector>
|
||||
|
||||
class QDBusPendingCallWatcher;
|
||||
|
||||
/*
|
||||
* Clut
|
||||
* All this should be the same as in the color server code, in kolor-manager
|
||||
*/
|
||||
typedef QVector<quint16> Clut;
|
||||
typedef QList<Clut> ClutList;
|
||||
typedef struct { QRect r; Clut c; } RegionalClut;
|
||||
typedef QMultiMap<uint, RegionalClut> RegionalClutMap;
|
||||
|
||||
Q_DECLARE_METATYPE(Clut)
|
||||
Q_DECLARE_METATYPE(ClutList)
|
||||
Q_DECLARE_METATYPE(RegionalClut)
|
||||
Q_DECLARE_METATYPE(RegionalClutMap)
|
||||
|
||||
// Marshall the RegionalClut data into a D-Bus argument
|
||||
inline QDBusArgument &operator<<(QDBusArgument &argument, const RegionalClut &rc)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << rc.r << rc.c;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
// Retrieve the RegionalClut data from the D-Bus argument
|
||||
inline const QDBusArgument &operator>>(const QDBusArgument &argument, RegionalClut &rc)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> rc.r >> rc.c;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
|
||||
namespace KWin {
|
||||
|
||||
class ColorServerInterface;
|
||||
|
||||
|
||||
/*
|
||||
* Color Correction Private Data
|
||||
*/
|
||||
class ColorCorrectionPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ColorCorrectionPrivate(ColorCorrection* parent);
|
||||
virtual ~ColorCorrectionPrivate();
|
||||
|
||||
bool setupCCTextures();
|
||||
void deleteCCTextures();
|
||||
static bool setupCCTexture(GLuint texture, const Clut &clut);
|
||||
|
||||
public Q_SLOTS:
|
||||
void colorServerUpdateSucceededSlot();
|
||||
void colorServerUpdateFailedSlot();
|
||||
|
||||
public:
|
||||
bool m_enabled;
|
||||
bool m_hasError;
|
||||
bool m_duringEnablingPhase;
|
||||
bool m_haveTexture3D;
|
||||
int m_ccTextureUnit;
|
||||
|
||||
ColorServerInterface *m_csi;
|
||||
const ClutList *m_outputCluts;
|
||||
QVector<GLuint> m_outputCCTextures;
|
||||
Clut m_dummyClut;
|
||||
GLuint m_dummyCCTexture;
|
||||
|
||||
int m_lastOutput;
|
||||
|
||||
private:
|
||||
ColorCorrection *q_ptr;
|
||||
Q_DECLARE_PUBLIC(ColorCorrection)
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Color Server DBus interface
|
||||
*/
|
||||
class ColorServerInterface : public QDBusAbstractInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static inline const char *staticInterfaceName()
|
||||
{ return "org.kde.KolorServer"; }
|
||||
|
||||
public:
|
||||
ColorServerInterface(const QString &service,
|
||||
const QString &path,
|
||||
const QDBusConnection &connection,
|
||||
QObject *parent = nullptr);
|
||||
virtual ~ColorServerInterface();
|
||||
|
||||
uint versionInfo() const;
|
||||
const ClutList& outputCluts() const;
|
||||
const RegionalClutMap& regionCluts() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void update();
|
||||
|
||||
Q_SIGNALS:
|
||||
void updateSucceeded();
|
||||
void updateFailed();
|
||||
void outputClutsChanged();
|
||||
void regionClutsChanged();
|
||||
|
||||
private:
|
||||
QDBusPendingReply< uint > getVersionInfo();
|
||||
QDBusPendingReply< ClutList > getOutputCluts();
|
||||
QDBusPendingReply< RegionalClutMap > getRegionCluts();
|
||||
|
||||
private Q_SLOTS:
|
||||
void callFinishedSlot(QDBusPendingCallWatcher *watcher);
|
||||
|
||||
private:
|
||||
QDBusPendingCallWatcher *m_versionInfoWatcher;
|
||||
QDBusPendingCallWatcher *m_outputClutsWatcher;
|
||||
QDBusPendingCallWatcher *m_regionClutsWatcher;
|
||||
bool m_versionInfoUpdated;
|
||||
bool m_outputClutsUpdated;
|
||||
bool m_regionClutsUpdated;
|
||||
uint m_versionInfo;
|
||||
ClutList m_outputCluts;
|
||||
RegionalClutMap m_regionCluts;
|
||||
|
||||
bool m_signaledFail;
|
||||
};
|
||||
|
||||
} // KWin namespace
|
||||
|
||||
#endif // KWIN_COLOR_CORRECTION_P_H_
|
|
@ -24,7 +24,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
// need to call GLTexturePrivate::initStatic()
|
||||
#include "kwingltexture_p.h"
|
||||
|
||||
#include "kwinglcolorcorrection.h"
|
||||
#include "kwineffects.h"
|
||||
#include "kwinglplatform.h"
|
||||
#include "logging_p.h"
|
||||
|
@ -142,8 +141,6 @@ bool checkGLError(const char* txt)
|
|||
// GLShader
|
||||
//****************************************
|
||||
|
||||
bool GLShader::sColorCorrect = false;
|
||||
|
||||
GLShader::GLShader(unsigned int flags)
|
||||
: mValid(false)
|
||||
, mLocationsResolved(false)
|
||||
|
@ -230,10 +227,6 @@ const QByteArray GLShader::prepareSource(GLenum shaderType, const QByteArray &so
|
|||
ba.replace("#version 140", "#version 300 es\n\nprecision highp float;\n");
|
||||
}
|
||||
|
||||
// Inject color correction code for fragment shaders, if possible
|
||||
if (shaderType == GL_FRAGMENT_SHADER && sColorCorrect)
|
||||
ba = ColorCorrection::prepareFragmentShader(ba);
|
||||
|
||||
return ba;
|
||||
}
|
||||
|
||||
|
@ -346,8 +339,6 @@ void GLShader::resolveLocations()
|
|||
|
||||
mFloatLocation[Saturation] = uniformLocation("saturation");
|
||||
|
||||
mIntLocation[ColorCorrectionLookupTextureUnit] = uniformLocation("u_ccLookupTexture");
|
||||
|
||||
mColorLocation[Color] = uniformLocation("geometryColor");
|
||||
|
||||
mLocationsResolved = true;
|
||||
|
|
|
@ -139,7 +139,6 @@ public:
|
|||
|
||||
enum IntUniform {
|
||||
AlphaToOne, ///< @deprecated no longer used
|
||||
ColorCorrectionLookupTextureUnit,
|
||||
IntUniformCount
|
||||
};
|
||||
|
||||
|
@ -178,10 +177,6 @@ private:
|
|||
int mIntLocation[IntUniformCount];
|
||||
int mColorLocation[ColorUniformCount];
|
||||
|
||||
static bool sColorCorrect;
|
||||
|
||||
friend class ColorCorrection;
|
||||
friend class ColorCorrectionPrivate;
|
||||
friend class ShaderManager;
|
||||
};
|
||||
|
||||
|
|
12
options.cpp
12
options.cpp
|
@ -115,7 +115,6 @@ Options::Options(QObject *parent)
|
|||
, m_compositingInitialized(Options::defaultCompositingInitialized())
|
||||
, m_hiddenPreviews(Options::defaultHiddenPreviews())
|
||||
, m_glSmoothScale(Options::defaultGlSmoothScale())
|
||||
, m_colorCorrected(Options::defaultColorCorrected())
|
||||
, m_xrenderSmoothScale(Options::defaultXrenderSmoothScale())
|
||||
, m_maxFpsInterval(Options::defaultMaxFpsInterval())
|
||||
, m_refreshRate(Options::defaultRefreshRate())
|
||||
|
@ -643,15 +642,6 @@ void Options::setGlSmoothScale(int glSmoothScale)
|
|||
emit glSmoothScaleChanged();
|
||||
}
|
||||
|
||||
void Options::setColorCorrected(bool colorCorrected)
|
||||
{
|
||||
if (m_colorCorrected == colorCorrected) {
|
||||
return;
|
||||
}
|
||||
m_colorCorrected = colorCorrected;
|
||||
emit colorCorrectedChanged();
|
||||
}
|
||||
|
||||
void Options::setXrenderSmoothScale(bool xrenderSmoothScale)
|
||||
{
|
||||
if (m_xrenderSmoothScale == xrenderSmoothScale) {
|
||||
|
@ -991,8 +981,6 @@ void Options::reloadCompositingSettings(bool force)
|
|||
c = 0;
|
||||
setGlPreferBufferSwap(c);
|
||||
|
||||
setColorCorrected(config.readEntry("GLColorCorrection", Options::defaultColorCorrected()));
|
||||
|
||||
m_xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false);
|
||||
|
||||
HiddenPreviews previews = Options::defaultHiddenPreviews();
|
||||
|
|
12
options.h
12
options.h
|
@ -175,7 +175,6 @@ class KWIN_EXPORT Options : public QObject
|
|||
* -1 = auto
|
||||
**/
|
||||
Q_PROPERTY(int glSmoothScale READ glSmoothScale WRITE setGlSmoothScale NOTIFY glSmoothScaleChanged)
|
||||
Q_PROPERTY(bool colorCorrected READ isColorCorrected WRITE setColorCorrected NOTIFY colorCorrectedChanged)
|
||||
Q_PROPERTY(bool xrenderSmoothScale READ isXrenderSmoothScale WRITE setXrenderSmoothScale NOTIFY xrenderSmoothScaleChanged)
|
||||
Q_PROPERTY(qint64 maxFpsInterval READ maxFpsInterval WRITE setMaxFpsInterval NOTIFY maxFpsIntervalChanged)
|
||||
Q_PROPERTY(uint refreshRate READ refreshRate WRITE setRefreshRate NOTIFY refreshRateChanged)
|
||||
|
@ -558,9 +557,6 @@ public:
|
|||
int glSmoothScale() const {
|
||||
return m_glSmoothScale;
|
||||
}
|
||||
bool isColorCorrected() const {
|
||||
return m_colorCorrected;
|
||||
}
|
||||
// XRender
|
||||
bool isXrenderSmoothScale() const {
|
||||
return m_xrenderSmoothScale;
|
||||
|
@ -743,9 +739,6 @@ public:
|
|||
static int defaultGlSmoothScale() {
|
||||
return 2;
|
||||
}
|
||||
static bool defaultColorCorrected() {
|
||||
return false;
|
||||
}
|
||||
static bool defaultXrenderSmoothScale() {
|
||||
return false;
|
||||
}
|
||||
|
@ -845,7 +838,6 @@ Q_SIGNALS:
|
|||
void compositingInitializedChanged();
|
||||
void hiddenPreviewsChanged();
|
||||
void glSmoothScaleChanged();
|
||||
void colorCorrectedChanged();
|
||||
void xrenderSmoothScaleChanged();
|
||||
void maxFpsIntervalChanged();
|
||||
void refreshRateChanged();
|
||||
|
@ -859,9 +851,6 @@ Q_SIGNALS:
|
|||
|
||||
void configChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setColorCorrected(bool colorCorrected = false);
|
||||
|
||||
private:
|
||||
void setElectricBorders(int borders);
|
||||
void syncFromKcfgc();
|
||||
|
@ -894,7 +883,6 @@ private:
|
|||
bool m_compositingInitialized;
|
||||
HiddenPreviews m_hiddenPreviews;
|
||||
int m_glSmoothScale;
|
||||
bool m_colorCorrected;
|
||||
bool m_xrenderSmoothScale;
|
||||
qint64 m_maxFpsInterval;
|
||||
// Settings that should be auto-detected
|
||||
|
|
|
@ -31,7 +31,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "platform.h"
|
||||
#include "wayland_server.h"
|
||||
|
||||
#include <kwinglcolorcorrection.h>
|
||||
#include <kwinglplatform.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
@ -992,7 +991,6 @@ bool SceneOpenGL2::supported(OpenGLBackend *backend)
|
|||
SceneOpenGL2::SceneOpenGL2(OpenGLBackend *backend, QObject *parent)
|
||||
: SceneOpenGL(backend, parent)
|
||||
, m_lanczosFilter(NULL)
|
||||
, m_colorCorrection()
|
||||
{
|
||||
if (!init_ok) {
|
||||
// base ctor already failed
|
||||
|
@ -1006,10 +1004,6 @@ SceneOpenGL2::SceneOpenGL2(OpenGLBackend *backend, QObject *parent)
|
|||
return;
|
||||
}
|
||||
|
||||
// Initialize color correction before the shaders
|
||||
slotColorCorrectedChanged(false);
|
||||
connect(options, SIGNAL(colorCorrectedChanged()), this, SLOT(slotColorCorrectedChanged()), Qt::QueuedConnection);
|
||||
|
||||
const QSize &s = screens()->size();
|
||||
GLRenderTarget::setVirtualScreenSize(s);
|
||||
GLRenderTarget::setVirtualScreenGeometry(screens()->geometry());
|
||||
|
@ -1120,20 +1114,7 @@ void SceneOpenGL2::finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region
|
|||
if (waylandServer() && waylandServer()->isScreenLocked() && !w->window()->isLockScreen() && !w->window()->isInputMethod()) {
|
||||
return;
|
||||
}
|
||||
if (!m_colorCorrection.isNull() && m_colorCorrection->isEnabled()) {
|
||||
// Split the painting for separate screens
|
||||
const int numScreens = screens()->count();
|
||||
for (int screen = 0; screen < numScreens; ++ screen) {
|
||||
QRegion regionForScreen(region);
|
||||
if (numScreens > 1)
|
||||
regionForScreen = region.intersected(screens()->geometry(screen));
|
||||
|
||||
data.setScreen(screen);
|
||||
performPaintWindow(w, mask, regionForScreen, data);
|
||||
}
|
||||
} else {
|
||||
performPaintWindow(w, mask, region, data);
|
||||
}
|
||||
performPaintWindow(w, mask, region, data);
|
||||
}
|
||||
|
||||
void SceneOpenGL2::performPaintWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data)
|
||||
|
@ -1156,33 +1137,6 @@ void SceneOpenGL2::resetLanczosFilter()
|
|||
m_lanczosFilter = NULL;
|
||||
}
|
||||
|
||||
ColorCorrection *SceneOpenGL2::colorCorrection()
|
||||
{
|
||||
return m_colorCorrection.data();
|
||||
}
|
||||
|
||||
void SceneOpenGL2::slotColorCorrectedChanged(bool recreateShaders)
|
||||
{
|
||||
qCDebug(KWIN_CORE) << "Color correction:" << options->isColorCorrected();
|
||||
if (options->isColorCorrected() && m_colorCorrection.isNull()) {
|
||||
m_colorCorrection.reset(new ColorCorrection(this));
|
||||
if (!m_colorCorrection->setEnabled(true)) {
|
||||
m_colorCorrection.reset();
|
||||
return;
|
||||
}
|
||||
connect(m_colorCorrection.data(), SIGNAL(changed()), Compositor::self(), SLOT(addRepaintFull()));
|
||||
connect(m_colorCorrection.data(), SIGNAL(errorOccured()), options, SLOT(setColorCorrected()), Qt::QueuedConnection);
|
||||
if (recreateShaders) {
|
||||
// Reload all shaders
|
||||
ShaderManager::cleanup();
|
||||
ShaderManager::instance();
|
||||
}
|
||||
} else {
|
||||
m_colorCorrection.reset();
|
||||
}
|
||||
Compositor::self()->addRepaintFull();
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// SceneOpenGL::Texture
|
||||
//****************************************
|
||||
|
@ -1521,8 +1475,6 @@ void SceneOpenGL2Window::performPaint(int mask, QRegion region, WindowPaintData
|
|||
if (!beginRenderWindow(mask, region, data))
|
||||
return;
|
||||
|
||||
SceneOpenGL2 *scene = static_cast<SceneOpenGL2 *>(m_scene);
|
||||
|
||||
QMatrix4x4 windowMatrix = transformation(mask, data);
|
||||
const QMatrix4x4 modelViewProjection = modelViewProjectionMatrix(mask, data);
|
||||
const QMatrix4x4 mvpMatrix = modelViewProjection * windowMatrix;
|
||||
|
@ -1541,10 +1493,6 @@ void SceneOpenGL2Window::performPaint(int mask, QRegion region, WindowPaintData
|
|||
}
|
||||
shader->setUniform(GLShader::ModelViewProjectionMatrix, mvpMatrix);
|
||||
|
||||
if (ColorCorrection *cc = scene->colorCorrection()) {
|
||||
cc->setupForOutput(data.screen());
|
||||
}
|
||||
|
||||
shader->setUniform(GLShader::Saturation, data.saturation());
|
||||
|
||||
const GLenum filter = (mask & (Effect::PAINT_WINDOW_TRANSFORMED | Effect::PAINT_SCREEN_TRANSFORMED))
|
||||
|
|
|
@ -32,7 +32,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
namespace KWin
|
||||
{
|
||||
class ColorCorrection;
|
||||
class LanczosFilter;
|
||||
class OpenGLBackend;
|
||||
class SyncManager;
|
||||
|
@ -128,7 +127,6 @@ public:
|
|||
|
||||
static bool supported(OpenGLBackend *backend);
|
||||
|
||||
ColorCorrection *colorCorrection();
|
||||
QMatrix4x4 projectionMatrix() const override { return m_projectionMatrix; }
|
||||
QMatrix4x4 screenProjectionMatrix() const override { return m_screenProjectionMatrix; }
|
||||
|
||||
|
@ -141,7 +139,6 @@ protected:
|
|||
virtual void updateProjectionMatrix() override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void slotColorCorrectedChanged(bool recreateShaders = true);
|
||||
void resetLanczosFilter();
|
||||
|
||||
private:
|
||||
|
@ -150,7 +147,6 @@ private:
|
|||
|
||||
private:
|
||||
LanczosFilter *m_lanczosFilter;
|
||||
QScopedPointer<ColorCorrection> m_colorCorrection;
|
||||
QMatrix4x4 m_projectionMatrix;
|
||||
QMatrix4x4 m_screenProjectionMatrix;
|
||||
GLuint vao;
|
||||
|
|
Loading…
Reference in New Issue