Commit 9bd47330 authored by Casian Andrei's avatar Casian Andrei
Browse files

Implement color correction (per output)

Add an option to kcmcompositing in the 'Advanced' tab, to enable or
disable color correction. It is specified that it's experimental and it
needs Kolor Manager.

Before painting for a particular screen, ColorCorrection::setupForOutput
should be called.

A screen property is added for WindowPaintData.

In kwinglutils, The fragment shaders are intercepted before being
compiled and they get a couple of lines of code inserted in order to do
the color correction. This happens only when color correction is enabled, of
course.

For D-Bus communication with KolorServer, everything is async.

The implementation basically manages a set of color lookup tables for
different outputs and for different window regions. These are taken via
D-Bus. Each lookup table has around 700 KB.

This commit reintroduces the changes from the former merge with the
"color2" branch. In this form, it can be easily reverted.

REVIEW: 106141
parent bee21046
......@@ -130,6 +130,7 @@ KWinCompositingConfig::KWinCompositingConfig(QWidget *parent, const QVariantList
connect(ui.glVSync, SIGNAL(toggled(bool)), this, SLOT(changed()));
connect(ui.glShaders, SIGNAL(toggled(bool)), this, SLOT(changed()));
connect(ui.glColorCorrection, SIGNAL(toggled(bool)), this, SLOT(changed()));
connect(m_showDetailedErrors, SIGNAL(triggered(bool)), SLOT(showDetailedEffectLoadingInformation()));
connect(ui.ghns, SIGNAL(clicked(bool)), SLOT(slotGHNS()));
......@@ -384,6 +385,7 @@ void KWinCompositingConfig::loadAdvancedTab()
ui.glVSync->setChecked(config.readEntry("GLVSync", true));
ui.glShaders->setChecked(!config.readEntry<bool>("GLLegacy", false));
ui.glColorCorrection->setChecked(config.readEntry("GLColorCorrection", false));
toogleSmoothScaleUi(ui.compositingType->currentIndex());
}
......@@ -517,7 +519,7 @@ bool KWinCompositingConfig::saveAdvancedTab()
config.writeEntry("GLVSync", ui.glVSync->isChecked());
config.writeEntry("GLLegacy", !ui.glShaders->isChecked());
config.writeEntry("GLColorCorrection", ui.glColorCorrection->isChecked());
return advancedChanged;
}
......@@ -755,6 +757,7 @@ void KWinCompositingConfig::defaults()
ui.glScaleFilter->setCurrentIndex(2);
ui.glVSync->setChecked(true);
ui.glShaders->setChecked(true);
ui.glColorCorrection->setChecked(false);
}
QString KWinCompositingConfig::quickHelp() const
......
......@@ -806,6 +806,17 @@ p, li { white-space: pre-wrap; }
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QCheckBox" name="glShaders">
<property name="toolTip">
<string>If enabled all rendering will be performed with Shaders written in the OpenGL Shading Language.
On legacy hardware disabling Shaders can improve the performance.</string>
</property>
<property name="text">
<string>Use OpenGL 2 Shaders</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="glVSync">
<property name="text">
......@@ -816,14 +827,16 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="glShaders">
<item row="2" column="0">
<widget class="QCheckBox" name="glColorCorrection">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>If enabled all rendering will be performed with Shaders written in the OpenGL Shading Language.
On legacy hardware disabling Shaders can improve the performance.</string>
<string>&lt;p&gt;Activates color correction if possible, using the Kolor-Manager. Requires OpenGL 2 Shaders to be enabled and Kolor-Manager to be installed. May fail silently.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Experimental&lt;/strong&gt;.&lt;/p&gt;</string>
</property>
<property name="text">
<string>Use OpenGL 2 Shaders</string>
<string>Enable color correction (experimental)</string>
</property>
</widget>
</item>
......@@ -921,12 +934,28 @@ On legacy hardware disabling Shaders can improve the performance.</string>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>161</x>
<y>64</y>
<x>312</x>
<y>119</y>
</hint>
<hint type="destinationlabel">
<x>194</x>
<y>119</y>
<x>345</x>
<y>146</y>
</hint>
</hints>
</connection>
<connection>
<sender>glShaders</sender>
<signal>toggled(bool)</signal>
<receiver>glColorCorrection</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>204</x>
<y>315</y>
</hint>
<hint type="destinationlabel">
<x>204</x>
<y>358</y>
</hint>
</hints>
</connection>
......
......@@ -29,6 +29,7 @@ set(kwin_GLUTILSLIB_SRCS
kwingltexture.cpp
kwinglutils_funcs.cpp
kwinglplatform.cpp
kwinglcolorcorrection.cpp
)
macro( KWIN4_ADD_GLUTILS_BACKEND name glinclude )
......
......@@ -211,6 +211,7 @@ public:
qreal decorationOpacity;
qreal saturation;
qreal brightness;
int screen;
};
WindowPaintData::WindowPaintData(EffectWindow* w)
......@@ -223,6 +224,7 @@ WindowPaintData::WindowPaintData(EffectWindow* w)
setDecorationOpacity(1.0);
setSaturation(1.0);
setBrightness(1.0);
setScreen(0);
}
WindowPaintData::WindowPaintData(const WindowPaintData &other)
......@@ -242,6 +244,7 @@ WindowPaintData::WindowPaintData(const WindowPaintData &other)
setDecorationOpacity(other.decorationOpacity());
setSaturation(other.saturation());
setBrightness(other.brightness());
setScreen(other.screen());
}
WindowPaintData::~WindowPaintData()
......@@ -269,6 +272,11 @@ qreal WindowPaintData::brightness() const
return d->brightness;
}
int WindowPaintData::screen() const
{
return d->screen;
}
void WindowPaintData::setDecorationOpacity(qreal opacity)
{
d->decorationOpacity = opacity;
......@@ -289,6 +297,11 @@ void WindowPaintData::setBrightness(qreal brightness)
d->brightness = brightness;
}
void WindowPaintData::setScreen(int screen) const
{
d->screen = screen;
}
qreal WindowPaintData::multiplyDecorationOpacity(qreal factor)
{
d->decorationOpacity *= factor;
......
......@@ -1949,6 +1949,18 @@ public:
* @since 4.10
**/
qreal multiplyBrightness(qreal factor);
/**
* The screen number for which the painting should be done.
* This affects color correction (different screens may need different
* color correction lookup tables because they have different ICC profiles).
* @return screen for which painting should be done
*/
int screen() const;
/**
* @param screen New screen number
* A value less than 0 will indicate that a default profile should be done.
*/
void setScreen(int screen) const;
WindowQuadList quads;
/**
* Shader to be used for rendering, if any.
......
This diff is collapsed.
/********************************************************************
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_funcs.h"
#include <QObject>
#include <QMap>
#include <QRect>
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 KWIN_EXPORT ColorCorrection : public QObject
{
Q_OBJECT
public:
explicit ColorCorrection(QObject *parent = 0);
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);
public slots:
/**
* Enables or disables color correction. Compositing should be restarted
* for changes to take effect.
*/
void setEnabled(bool enabled);
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();
private:
ColorCorrectionPrivate * const d_ptr;
Q_DECLARE_PRIVATE(ColorCorrection)
};
} // KWin namespace
#endif // KWIN_COLOR_CORRECTION_H
/********************************************************************
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 <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();
void setupCCTextures();
void deleteCCTextures();
static void setupCCTexture(GLuint texture, const Clut &clut);
public slots:
void colorServerUpdateSucceededSlot();
void colorServerUpdateFailedSlot();
public:
bool m_enabled;
bool m_hasError;
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 = 0);
virtual ~ColorServerInterface();
uint versionInfo() const;
const ClutList& outputCluts() const;
const RegionalClutMap& regionCluts() const;
public slots:
void update();
signals:
void updateSucceeded();
void updateFailed();
void outputClutsChanged();
void regionClutsChanged();
private:
QDBusPendingReply< uint > getVersionInfo();
QDBusPendingReply< ClutList > getOutputCluts();
QDBusPendingReply< RegionalClutMap > getRegionCluts();
private 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_
......@@ -1031,5 +1031,14 @@ CompositingType GLPlatform::recommendedCompositor() const
return m_recommendedCompositor;
}
bool GLPlatform::isGLES() const
{
#ifdef KWIN_HAVE_OPENGLES
return true;
#else
return false;
#endif
}
} // namespace KWin
......@@ -295,6 +295,10 @@ public:
* @since 4.9
**/
bool isLooseBinding() const;
/**
* @returns Whether OpenGL ES is used
*/
bool isGLES() const;
/**
* @returns The CompositingType recommended by the driver.
......
......@@ -24,6 +24,7 @@ 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 "kwinglobals.h"
#include "kwineffects.h"
#include "kwinglplatform.h"
......@@ -258,6 +259,8 @@ void popMatrix()
// GLShader
//****************************************
bool GLShader::sColorCorrect = false;
GLShader::GLShader()
: mProgram(0)
, mValid(false)
......@@ -299,10 +302,8 @@ bool GLShader::loadFromFiles(const QString &vertexFile, const QString &fragmentF
return load(vertexSource, fragmentSource);
}
bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &source) const
const QByteArray GLShader::prepareSource(GLenum shaderType, const QByteArray &source) const
{
GLuint shader = glCreateShader(shaderType);
// Prepare the source code
QByteArray ba;
#ifdef KWIN_HAVE_OPENGLES
......@@ -313,7 +314,19 @@ bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &sour
}
ba.append(source);
const char* src = ba.constData();
// Inject color correction code for fragment shaders, if possible
if (shaderType == GL_FRAGMENT_SHADER && sColorCorrect)
ba = ColorCorrection::prepareFragmentShader(ba);
return ba;
}
bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &source) const
{
GLuint shader = glCreateShader(shaderType);
QByteArray preparedSource = prepareSource(shaderType, source);
const char* src = preparedSource.constData();
glShaderSource(shader, 1, &src, NULL);
// Compile the shader
......
......@@ -204,6 +204,7 @@ protected:
GLShader();
bool loadFromFiles(const QString& vertexfile, const QString& fragmentfile);
bool load(const QByteArray &vertexSource, const QByteArray &fragmentSource);
const QByteArray prepareSource(GLenum shaderType, const QByteArray &sourceCode) const;
bool compile(GLuint program, GLenum shaderType, const QByteArray &sourceCode) const;
void bind();
void unbind();
......@@ -219,6 +220,9 @@ private:
int mFloatLocation[FloatUniformCount];
int mIntLocation[IntUniformCount];
static bool sColorCorrect;
friend class ColorCorrection;
friend class ShaderManager;
};
......
......@@ -148,6 +148,7 @@ Options::Options(QObject *parent)
, m_unredirectFullscreen(Options::defaultUnredirectFullscreen())
, m_glSmoothScale(Options::defaultGlSmoothScale())
, m_glVSync(Options::defaultGlVSync())
, m_colorCorrected(Options::defaultColorCorrected())
, m_xrenderSmoothScale(Options::defaultXrenderSmoothScale())
, m_maxFpsInterval(Options::defaultMaxFpsInterval())
, m_refreshRate(Options::defaultRefreshRate())
......@@ -719,6 +720,15 @@ void Options::setGlVSync(bool glVSync)
emit glVSyncChanged();
}
void Options::setColorCorrected(bool colorCorrected)
{
if (m_colorCorrected == colorCorrected) {
return;
}
m_colorCorrected = colorCorrected;
emit colorCorrectedChanged();
}
void Options::setXrenderSmoothScale(bool xrenderSmoothScale)
{
if (m_xrenderSmoothScale == xrenderSmoothScale) {
......@@ -1020,6 +1030,8 @@ void Options::reloadCompositingSettings(bool force)
}
setGlLegacy(config.readEntry("GLLegacy", Options::defaultGlLegacy()));
setColorCorrected(config.readEntry("GLColorCorrection", Options::defaultColorCorrected()));
m_xrenderSmoothScale = config.readEntry("XRenderSmoothScale", false);
HiddenPreviews previews = Options::defaultHiddenPreviews();
......
......@@ -187,6 +187,7 @@ class Options : public QObject, public KDecorationOptions
**/
Q_PROPERTY(int glSmoothScale READ glSmoothScale WRITE setGlSmoothScale NOTIFY glSmoothScaleChanged)
Q_PROPERTY(bool glVSync READ isGlVSync WRITE setGlVSync NOTIFY glVSyncChanged)
Q_PROPERTY(bool colorCorrected READ isColorCorrected WRITE setColorCorrected NOTIFY colorCorrectedChanged)
Q_PROPERTY(bool xrenderSmoothScale READ isXrenderSmoothScale WRITE setXrenderSmoothScale NOTIFY xrenderSmoothScaleChanged)
Q_PROPERTY(uint maxFpsInterval READ maxFpsInterval WRITE setMaxFpsInterval NOTIFY maxFpsIntervalChanged)
Q_PROPERTY(uint refreshRate READ refreshRate WRITE setRefreshRate NOTIFY refreshRateChanged)
......@@ -561,6 +562,9 @@ public:
bool isGlVSync() const {
return m_glVSync;
}
bool isColorCorrected() const {
return m_colorCorrected;
}
// XRender
bool isXrenderSmoothScale() const {
return m_xrenderSmoothScale;
......@@ -645,6 +649,7 @@ public:
void setUnredirectFullscreen(bool unredirectFullscreen);
void setGlSmoothScale(int glSmoothScale);
void setGlVSync(bool glVSync);
void setColorCorrected(bool colorCorrected);
void setXrenderSmoothScale(bool xrenderSmoothScale);
void setMaxFpsInterval(uint maxFpsInterval);
void setRefreshRate(uint refreshRate);
......@@ -854,6 +859,9 @@ public:
static bool defaultGlVSync() {
return true;
}
static bool defaultColorCorrected() {
return false;
}
static bool defaultXrenderSmoothScale() {
return false;
}
......@@ -956,6 +964,7 @@ Q_SIGNALS:
void unredirectFullscreenChanged();
void glSmoothScaleChanged();
void glVSyncChanged();
void colorCorrectedChanged();
void xrenderSmoothScaleChanged();
void maxFpsIntervalChanged();
void refreshRateChanged();
......@@ -999,6 +1008,7 @@ private:
bool m_unredirectFullscreen;
int m_glSmoothScale;