Implement color correction support
The implementation consists of a class in libkwineffects. There are some slight modifications in the compositor. Regions for different outputs are drawn at different times. Currently only per output color correction is implemented. However, the grounds are prepared for implementing per window color correction easily. The ColorCorrection class needs to communicate via D-Bus with a KDED module, KolorServer, which is a part of KolorManager. The only visible part for the user consists of a check box in the advanced tab for the compositing KCM. The actual correction is done by injecting a piece of code in the fragment shader, code that does a 3D lookup into a special color lookup texture. The data for these textures is obtained from KolorServer. All D-Bus calls are async.
This commit is contained in:
parent
6aac45a356
commit
a417888b0e
18 changed files with 1221 additions and 63 deletions
|
@ -55,6 +55,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "compositingprefs.h"
|
||||
#include "notifications.h"
|
||||
|
||||
#include <kwinglcolorcorrection.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QtCore/QtConcurrentRun>
|
||||
|
@ -140,6 +142,10 @@ void Workspace::slotCompositingOptionsInitialized()
|
|||
}
|
||||
#endif
|
||||
|
||||
kDebug(1212) << "Color correction:" << options->isGlColorCorrection();
|
||||
ColorCorrection::instance()->setEnabled(options->isGlColorCorrection());
|
||||
connect(ColorCorrection::instance(), SIGNAL(changed()), this, SLOT(addRepaintFull()));
|
||||
|
||||
scene = new SceneOpenGL(this);
|
||||
|
||||
// TODO: Add 30 second delay to protect against screen freezes as well
|
||||
|
@ -204,6 +210,7 @@ void Workspace::finishCompositing()
|
|||
if (scene == NULL)
|
||||
return;
|
||||
m_finishingCompositing = true;
|
||||
ColorCorrection::cleanup();
|
||||
delete cm_selection;
|
||||
foreach (Client * c, clients)
|
||||
scene->windowClosed(c, NULL);
|
||||
|
|
|
@ -128,6 +128,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()));
|
||||
|
||||
// Open the temporary config file
|
||||
|
@ -381,6 +382,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());
|
||||
}
|
||||
|
@ -514,7 +516,7 @@ bool KWinCompositingConfig::saveAdvancedTab()
|
|||
|
||||
config.writeEntry("GLVSync", ui.glVSync->isChecked());
|
||||
config.writeEntry("GLLegacy", !ui.glShaders->isChecked());
|
||||
|
||||
config.writeEntry("GLColorCorrection", ui.glColorCorrection->isChecked());
|
||||
|
||||
return advancedChanged;
|
||||
}
|
||||
|
@ -752,6 +754,7 @@ void KWinCompositingConfig::defaults()
|
|||
ui.glScaleFilter->setCurrentIndex(2);
|
||||
ui.glVSync->setChecked(true);
|
||||
ui.glShaders->setChecked(true);
|
||||
ui.glColorCorrection->setChecked(false);
|
||||
}
|
||||
|
||||
QString KWinCompositingConfig::quickHelp() const
|
||||
|
|
|
@ -778,6 +778,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">
|
||||
|
@ -788,14 +799,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><html><head/><body><p>Activates color correction if possible, using the Kolor-Manager. Requires OpenGL 2 Shaders to be enabled and <span style=" text-decoration: underline;">Kolor-Manager to be installed</span>. May fail silently.</p><p><span style=" font-weight:600;">Experimental.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use OpenGL 2 Shaders</string>
|
||||
<string>Enable color correction (experimental)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -893,12 +906,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;
|
||||
qint32 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;
|
||||
}
|
||||
|
||||
qint32 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(qint32 screen) const
|
||||
{
|
||||
d->screen = screen;
|
||||
}
|
||||
|
||||
qreal WindowPaintData::multiplyDecorationOpacity(qreal factor)
|
||||
{
|
||||
d->decorationOpacity *= factor;
|
||||
|
|
|
@ -1937,6 +1937,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
|
||||
*/
|
||||
qint32 screen() const;
|
||||
/**
|
||||
* @param screen New screen number
|
||||
* A value less than 0 will indicate that a default profile should be done.
|
||||
*/
|
||||
void setScreen(qint32 screen) const;
|
||||
WindowQuadList quads;
|
||||
/**
|
||||
* Shader to be used for rendering, if any.
|
||||
|
|
711
libkwineffects/kwinglcolorcorrection.cpp
Normal file
711
libkwineffects/kwinglcolorcorrection.cpp
Normal file
|
@ -0,0 +1,711 @@
|
|||
/********************************************************************
|
||||
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 "kwinglutils.h"
|
||||
|
||||
#include <KDebug>
|
||||
|
||||
#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)
|
||||
kWarning(1212) << "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("getVersionInfo"));
|
||||
}
|
||||
|
||||
QDBusPendingReply< ClutList > ColorServerInterface::getOutputCluts()
|
||||
{
|
||||
return QDBusPendingReply< ClutList >(asyncCall("getOutputCluts"));
|
||||
}
|
||||
|
||||
QDBusPendingReply< RegionalClutMap > ColorServerInterface::getRegionCluts()
|
||||
{
|
||||
return QDBusPendingReply< RegionalClutMap >(asyncCall("getRegionCluts"));
|
||||
}
|
||||
|
||||
void ColorServerInterface::callFinishedSlot(QDBusPendingCallWatcher *watcher)
|
||||
{
|
||||
if (watcher == m_versionInfoWatcher) {
|
||||
kDebug(1212) << "Version info call finished";
|
||||
QDBusPendingReply< uint > reply = *watcher;
|
||||
if (reply.isError()) {
|
||||
kWarning(1212) << reply.error();
|
||||
if (!m_signaledFail)
|
||||
emit updateFailed();
|
||||
m_signaledFail = true;
|
||||
return;
|
||||
} else {
|
||||
m_versionInfo = reply.value();
|
||||
m_versionInfoUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (watcher == m_outputClutsWatcher) {
|
||||
kDebug(1212) << "Output cluts call finished";
|
||||
QDBusPendingReply< ClutList > reply = *watcher;
|
||||
if (reply.isError()) {
|
||||
kWarning(1212) << reply.error();
|
||||
if (!m_signaledFail)
|
||||
emit updateFailed();
|
||||
m_signaledFail = true;
|
||||
return;
|
||||
} else {
|
||||
m_outputCluts = reply.value();
|
||||
m_outputClutsUpdated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (watcher == m_regionClutsWatcher) {
|
||||
kDebug(1212) << "Region cluts call finished";
|
||||
QDBusPendingReply< RegionalClutMap > reply = *watcher;
|
||||
if (reply.isError()) {
|
||||
kWarning(1212) << 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) {
|
||||
kDebug(1212) << "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 * 63.0 / 64.0).rgb;\n";
|
||||
|
||||
|
||||
/*
|
||||
* Color Correction
|
||||
*/
|
||||
|
||||
ColorCorrection *ColorCorrection::s_colorCorrection = NULL;
|
||||
|
||||
ColorCorrection *ColorCorrection::instance()
|
||||
{
|
||||
if (!s_colorCorrection)
|
||||
s_colorCorrection = new ColorCorrection;
|
||||
return s_colorCorrection;
|
||||
}
|
||||
|
||||
void ColorCorrection::cleanup()
|
||||
{
|
||||
delete s_colorCorrection;
|
||||
s_colorCorrection = NULL;
|
||||
}
|
||||
|
||||
ColorCorrection::ColorCorrection()
|
||||
: QObject()
|
||||
, d_ptr(new ColorCorrectionPrivate(this))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ColorCorrection::~ColorCorrection()
|
||||
{
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
ColorCorrectionPrivate::ColorCorrectionPrivate(ColorCorrection *parent)
|
||||
: QObject(parent)
|
||||
, m_enabled(false)
|
||||
, m_hasError(false)
|
||||
, 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(
|
||||
"org.kde.kded",
|
||||
"/modules/kolorserver",
|
||||
QDBusConnection::sessionBus(),
|
||||
this);
|
||||
|
||||
m_outputCluts = &m_csi->outputCluts();
|
||||
m_regionCluts = &m_csi->regionCluts();
|
||||
|
||||
connect(m_csi, SIGNAL(updateSucceeded()), this, SLOT(colorServerUpdateSucceededSlot()));
|
||||
connect(m_csi, SIGNAL(updateFailed()), this, SLOT(colorServerUpdateFailedSlot()));
|
||||
}
|
||||
|
||||
ColorCorrectionPrivate::~ColorCorrectionPrivate()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ColorCorrection::setEnabled(bool enabled)
|
||||
{
|
||||
Q_D(ColorCorrection);
|
||||
|
||||
if (enabled == d->m_enabled)
|
||||
return;
|
||||
|
||||
if (enabled && d->m_hasError) {
|
||||
kError(1212) << "cannot enable color correction";
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef KWIN_HAVE_OPENGLES
|
||||
if (enabled) {
|
||||
kWarning(1212) << "color correction is not supported with OpenGL ES at the moment.";
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (enabled) {
|
||||
// Update all profiles and regions
|
||||
d->m_csi->update();
|
||||
} else {
|
||||
d->deleteCCTextures();
|
||||
}
|
||||
#endif
|
||||
|
||||
d->m_enabled = enabled;
|
||||
kDebug(1212) << enabled;
|
||||
}
|
||||
|
||||
QMap<Window, QRect>::const_iterator ColorCorrection::regionsBegin(Window w)
|
||||
{
|
||||
Q_D(ColorCorrection);
|
||||
return d->m_windowRegions.constFind(w);
|
||||
}
|
||||
|
||||
QMap<Window, QRect>::const_iterator ColorCorrection::regionsEnd(Window w)
|
||||
{
|
||||
Q_D(ColorCorrection);
|
||||
QMap<Window, QRect>::const_iterator it = d->m_windowRegions.constFind(w);
|
||||
while (it != d->m_windowRegions.constEnd() && it.key() == w) ++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
void ColorCorrection::setupForOutput(int screen)
|
||||
{
|
||||
Q_D(ColorCorrection);
|
||||
|
||||
if (!d->m_enabled)
|
||||
return;
|
||||
|
||||
GLShader *shader = ShaderManager::instance()->getBoundShader();
|
||||
if (!shader) {
|
||||
kError(1212) << "no bound shader for color correction setup";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shader->setUniform("u_ccLookupTexture", d->m_ccTextureUnit)) {
|
||||
kError(1212) << "unable to set uniform for the color correction lookup texture";
|
||||
}
|
||||
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
d->setupCCTextures();
|
||||
|
||||
GLint activeTexture;
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
|
||||
glActiveTexture(GL_TEXTURE0 + d->m_ccTextureUnit);
|
||||
glEnable(GL_TEXTURE_3D);
|
||||
|
||||
if (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 correctiont texture
|
||||
glBindTexture(GL_TEXTURE_3D, d->m_outputCCTextures[screen]);
|
||||
}
|
||||
|
||||
glActiveTexture(activeTexture);
|
||||
#else
|
||||
Q_UNUSED(screen);
|
||||
#endif // KWIN_HAVE_OPENGLES
|
||||
|
||||
d->m_lastOutput = screen;
|
||||
}
|
||||
|
||||
void ColorCorrection::setupForRegion(const QMap<Window, QRect>::const_iterator ®ionIt)
|
||||
{
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
Q_D(ColorCorrection);
|
||||
const QRect *key = &(*regionIt);
|
||||
GLuint tex = d->m_regionCCTextures.value(key, d->m_dummyCCTexture);
|
||||
|
||||
// Bind the correct color lookup texture
|
||||
GLint activeTexture;
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
|
||||
glActiveTexture(GL_TEXTURE0 + d->m_ccTextureUnit);
|
||||
glEnable(GL_TEXTURE_3D);
|
||||
glBindTexture(GL_TEXTURE_3D, tex);
|
||||
glActiveTexture(activeTexture);
|
||||
#else
|
||||
Q_UNUSED(regionIt);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ColorCorrection::resetForRegion()
|
||||
{
|
||||
Q_D(ColorCorrection);
|
||||
setupForOutput(d->m_lastOutput);
|
||||
}
|
||||
|
||||
void ColorCorrection::reset()
|
||||
{
|
||||
setupForOutput(-1);
|
||||
}
|
||||
|
||||
QByteArray ColorCorrection::prepareFragmentShader(const QByteArray &sourceCode)
|
||||
{
|
||||
Q_D(ColorCorrection);
|
||||
|
||||
if (!d->m_enabled)
|
||||
return 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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
void ColorCorrectionPrivate::setupCCTextures()
|
||||
{
|
||||
Q_Q(ColorCorrection);
|
||||
|
||||
if (m_ccTextureUnit < 0) {
|
||||
GLint maxUnits = 0;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxUnits);
|
||||
|
||||
if (maxUnits < 2) {
|
||||
kWarning(1212) << "insufficient maximum number of texture units allowed:" << maxUnits;
|
||||
kWarning(1212) << "color correction will be disabled";
|
||||
m_hasError = true;
|
||||
m_ccTextureUnit = 0;
|
||||
q->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
m_ccTextureUnit = maxUnits - 1;
|
||||
}
|
||||
|
||||
// Dummy texture first
|
||||
if (!m_dummyCCTexture) {
|
||||
glGenTextures(1, &m_dummyCCTexture);
|
||||
setupCCTexture(m_dummyCCTexture, m_dummyClut);
|
||||
}
|
||||
|
||||
// Setup actual color correction textures
|
||||
if (m_outputCCTextures.isEmpty() && !m_outputCluts->isEmpty()) {
|
||||
kDebug(1212) << "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)
|
||||
setupCCTexture(m_outputCCTextures[i], m_outputCluts->at(i));
|
||||
}
|
||||
|
||||
if (m_regionCCTextures.isEmpty() && !m_regionCluts->isEmpty()) {
|
||||
Q_ASSERT(m_windowRegions.isEmpty());
|
||||
kDebug(1212) << "setting up region color correction textures";
|
||||
|
||||
// Generate region textures (and place them inside a map)
|
||||
RegionalClutMap::const_iterator rcit;
|
||||
QMap<Window, QRect>::const_iterator rit;
|
||||
for (rcit = m_regionCluts->begin(); rcit != m_regionCluts->end(); ++rcit) {
|
||||
GLuint tex;
|
||||
glGenTextures(1, &tex);
|
||||
setupCCTexture(tex, rcit->c);
|
||||
|
||||
// Insert the new texture into the region maps
|
||||
rit = m_windowRegions.insert(rcit.key(), rcit->r); // this one maps Window -> QRect
|
||||
m_regionCCTextures.insert(&(*rit), tex); // this one maps QRect* -> texture
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Handle errors (what if a texture isn't generated?)
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
if (!m_regionCCTextures.isEmpty()) {
|
||||
QMap<const QRect*, GLuint>::const_iterator it;
|
||||
for (it = m_regionCCTextures.begin(); it != m_regionCCTextures.end(); ++it)
|
||||
glDeleteTextures(1, &(*it));
|
||||
m_regionCCTextures.clear();
|
||||
m_windowRegions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void ColorCorrectionPrivate::setupCCTexture(GLuint texture, const Clut& clut)
|
||||
{
|
||||
if ((uint) clut.size() != CLUT_ELEMENT_COUNT) {
|
||||
kError(1212) << "cannot setup CC texture: invalid color lookup table";
|
||||
return;
|
||||
}
|
||||
|
||||
kDebug(1212) << texture;
|
||||
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
glEnable(GL_TEXTURE_3D);
|
||||
glBindTexture(GL_TEXTURE_3D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
|
||||
glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB16,
|
||||
LUT_GRID_POINTS, LUT_GRID_POINTS, LUT_GRID_POINTS,
|
||||
0, GL_RGB, GL_UNSIGNED_SHORT, clut.data());
|
||||
|
||||
glDisable(GL_TEXTURE_3D);
|
||||
|
||||
checkGLError("setupCCTexture");
|
||||
#else
|
||||
Q_UNUSED(texture);
|
||||
#endif // KWIN_HAVE_OPENGLES
|
||||
}
|
||||
|
||||
void ColorCorrectionPrivate::colorServerUpdateSucceededSlot()
|
||||
{
|
||||
Q_Q(ColorCorrection);
|
||||
|
||||
kDebug(1212) << "Update of color profiles succeeded";
|
||||
|
||||
// Force the color correction textures to be recreated
|
||||
deleteCCTextures();
|
||||
|
||||
emit q->changed();
|
||||
}
|
||||
|
||||
void ColorCorrectionPrivate::colorServerUpdateFailedSlot()
|
||||
{
|
||||
Q_Q(ColorCorrection);
|
||||
|
||||
kError(1212) << "Update of color profiles failed";
|
||||
|
||||
q->setEnabled(false);
|
||||
}
|
||||
|
||||
} // KWin namespace
|
143
libkwineffects/kwinglcolorcorrection.h
Normal file
143
libkwineffects/kwinglcolorcorrection.h
Normal file
|
@ -0,0 +1,143 @@
|
|||
/********************************************************************
|
||||
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:
|
||||
static ColorCorrection *instance();
|
||||
static void cleanup();
|
||||
|
||||
/**
|
||||
* The beginning of a region list for a window \param w
|
||||
* \return Constant iterator to the beginning
|
||||
* \see setupForRegion
|
||||
*
|
||||
* It can be used to indicate a particular region for which
|
||||
* to set up color correction.
|
||||
*
|
||||
* These regions come from the applications, which communicate with the
|
||||
* color server (kolor-server in kolor-manager), and this has no direct
|
||||
* relation to KWin. Consequently, modifying these regions does not
|
||||
* make sense inside KWin.
|
||||
*/
|
||||
QMap<Window, QRect>::const_iterator regionsBegin(Window w);
|
||||
|
||||
/**
|
||||
* The ending of a region list for a window \param w
|
||||
* \return Constant iterator to the ending
|
||||
* \see setupForRegion
|
||||
*/
|
||||
QMap<Window, QRect>::const_iterator regionsEnd(Window w);
|
||||
|
||||
/**
|
||||
* Prepares color correction for the output number \param screen.
|
||||
* Sets up the appropriate color lookup texture for the output.
|
||||
*/
|
||||
void setupForOutput(int screen);
|
||||
|
||||
/**
|
||||
* Prepares color correction for one region of a window (in fact a rect),
|
||||
* which is indicated by \param regionIt. This can be obtained by iterating
|
||||
* between \ref regionsBegin and \ref regionsEnd, for that particular window.
|
||||
*
|
||||
* \note This should be called when drawing a window
|
||||
*/
|
||||
void setupForRegion(const QMap<Window, QRect>::const_iterator ®ionIt);
|
||||
|
||||
/**
|
||||
* Disables color correction for a particular window region. Instead,
|
||||
* color correction is set up again for the last output that was set
|
||||
* with \ref setupForOutput.
|
||||
*
|
||||
* \note This should be called after finishing the drawing of a window.
|
||||
*/
|
||||
void resetForRegion();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* When color correction is disabled, it does nothing and returns
|
||||
* \param sourceCode.
|
||||
*
|
||||
* Else, it 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.
|
||||
*/
|
||||
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:
|
||||
ColorCorrection();
|
||||
virtual ~ColorCorrection();
|
||||
|
||||
private:
|
||||
ColorCorrectionPrivate *d_ptr;
|
||||
Q_DECLARE_PRIVATE(ColorCorrection)
|
||||
static ColorCorrection *s_colorCorrection;
|
||||
};
|
||||
|
||||
} // KWin namespace
|
||||
|
||||
#endif // KWIN_COLOR_CORRECTION_H
|
168
libkwineffects/kwinglcolorcorrection_p.h
Normal file
168
libkwineffects/kwinglcolorcorrection_p.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
/********************************************************************
|
||||
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;
|
||||
const RegionalClutMap *m_regionCluts;
|
||||
QMultiMap<Window, QRect> m_windowRegions;
|
||||
QMap<const QRect*, GLuint> m_regionCCTextures; // keys from m_regions's values
|
||||
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_
|
|
@ -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"
|
||||
|
@ -304,10 +305,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
|
||||
|
@ -318,7 +317,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)
|
||||
ba = ColorCorrection::instance()->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();
|
||||
|
|
11
options.cpp
11
options.cpp
|
@ -148,6 +148,7 @@ Options::Options(QObject *parent)
|
|||
, m_unredirectFullscreen(Options::defaultUnredirectFullscreen())
|
||||
, m_glSmoothScale(Options::defaultGlSmoothScale())
|
||||
, m_glVSync(Options::defaultGlVSync())
|
||||
, m_glColorCorrection(Options::defaultGlColorCorrection())
|
||||
, m_xrenderSmoothScale(Options::defaultXrenderSmoothScale())
|
||||
, m_maxFpsInterval(Options::defaultMaxFpsInterval())
|
||||
, m_refreshRate(Options::defaultRefreshRate())
|
||||
|
@ -697,6 +698,15 @@ void Options::setGlVSync(bool glVSync)
|
|||
emit glVSyncChanged();
|
||||
}
|
||||
|
||||
void Options::setGlColorCorrection(bool glColorCorrection)
|
||||
{
|
||||
if (m_glColorCorrection == glColorCorrection) {
|
||||
return;
|
||||
}
|
||||
m_glColorCorrection = glColorCorrection;
|
||||
emit glColorCorrectionChanged();
|
||||
}
|
||||
|
||||
void Options::setXrenderSmoothScale(bool xrenderSmoothScale)
|
||||
{
|
||||
if (m_xrenderSmoothScale == xrenderSmoothScale) {
|
||||
|
@ -979,6 +989,7 @@ void Options::reloadCompositingSettings(bool force)
|
|||
|
||||
setGlDirect(prefs.enableDirectRendering());
|
||||
setGlVSync(config.readEntry("GLVSync", Options::defaultGlVSync()));
|
||||
setGlColorCorrection(config.readEntry("GLColorCorrection", Options::defaultGlColorCorrection()));
|
||||
setGlSmoothScale(qBound(-1, config.readEntry("GLTextureFilter", Options::defaultGlSmoothScale()), 2));
|
||||
setGlStrictBindingFollowsDriver(!config.hasKey("GLStrictBinding"));
|
||||
if (!isGlStrictBindingFollowsDriver()) {
|
||||
|
|
10
options.h
10
options.h
|
@ -179,6 +179,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 glColorCorrection READ isGlColorCorrection WRITE setGlColorCorrection NOTIFY glColorCorrectionChanged)
|
||||
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)
|
||||
|
@ -538,6 +539,9 @@ public:
|
|||
bool isGlVSync() const {
|
||||
return m_glVSync;
|
||||
}
|
||||
bool isGlColorCorrection() const {
|
||||
return m_glColorCorrection;
|
||||
}
|
||||
// XRender
|
||||
bool isXrenderSmoothScale() const {
|
||||
return m_xrenderSmoothScale;
|
||||
|
@ -617,6 +621,7 @@ public:
|
|||
void setUnredirectFullscreen(bool unredirectFullscreen);
|
||||
void setGlSmoothScale(int glSmoothScale);
|
||||
void setGlVSync(bool glVSync);
|
||||
void setGlColorCorrection(bool glColorCorrection);
|
||||
void setXrenderSmoothScale(bool xrenderSmoothScale);
|
||||
void setMaxFpsInterval(uint maxFpsInterval);
|
||||
void setRefreshRate(uint refreshRate);
|
||||
|
@ -819,6 +824,9 @@ public:
|
|||
static bool defaultGlVSync() {
|
||||
return true;
|
||||
}
|
||||
static bool defaultGlColorCorrection() {
|
||||
return false;
|
||||
}
|
||||
static bool defaultXrenderSmoothScale() {
|
||||
return false;
|
||||
}
|
||||
|
@ -916,6 +924,7 @@ Q_SIGNALS:
|
|||
void unredirectFullscreenChanged();
|
||||
void glSmoothScaleChanged();
|
||||
void glVSyncChanged();
|
||||
void glColorCorrectionChanged();
|
||||
void xrenderSmoothScaleChanged();
|
||||
void maxFpsIntervalChanged();
|
||||
void refreshRateChanged();
|
||||
|
@ -958,6 +967,7 @@ private:
|
|||
bool m_unredirectFullscreen;
|
||||
int m_glSmoothScale;
|
||||
bool m_glVSync;
|
||||
bool m_glColorCorrection;
|
||||
bool m_xrenderSmoothScale;
|
||||
uint m_maxFpsInterval;
|
||||
// Settings that should be auto-detected
|
||||
|
|
11
scene.cpp
11
scene.cpp
|
@ -75,12 +75,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsView>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
#include "client.h"
|
||||
#include "deleted.h"
|
||||
#include "effects.h"
|
||||
#include "lanczosfilter.h"
|
||||
#include "overlaywindow.h"
|
||||
#include "shadow.h"
|
||||
|
||||
|
@ -437,15 +435,6 @@ void Scene::finalPaintWindow(EffectWindowImpl* w, int mask, QRegion region, Wind
|
|||
// will be eventually called from drawWindow()
|
||||
void Scene::finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data)
|
||||
{
|
||||
if (mask & PAINT_WINDOW_LANCZOS) {
|
||||
if (lanczos_filter.isNull()) {
|
||||
lanczos_filter = new LanczosFilter(this);
|
||||
// recreate the lanczos filter when the screen gets resized
|
||||
connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), lanczos_filter.data(), SLOT(deleteLater()));
|
||||
connect(QApplication::desktop(), SIGNAL(resized(int)), lanczos_filter.data(), SLOT(deleteLater()));
|
||||
}
|
||||
lanczos_filter.data()->performPaint(w, mask, region, data);
|
||||
} else
|
||||
w->sceneWindow()->performPaint(mask, region, data);
|
||||
}
|
||||
|
||||
|
|
2
scene.h
2
scene.h
|
@ -124,7 +124,7 @@ protected:
|
|||
// shared implementation, starts painting the window
|
||||
virtual void paintWindow(Window* w, int mask, QRegion region, WindowQuadList quads);
|
||||
// called after all effects had their drawWindow() called
|
||||
void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
|
||||
virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
|
||||
// compute time since the last repaint
|
||||
void updateTimeDiff();
|
||||
// saved data for 2nd pass of optimized screen painting
|
||||
|
|
|
@ -70,12 +70,14 @@ Sources and other compositing managers:
|
|||
|
||||
#include <kxerrorhandler.h>
|
||||
|
||||
#include <kwinglcolorcorrection.h>
|
||||
#include <kwinglplatform.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "client.h"
|
||||
#include "deleted.h"
|
||||
#include "effects.h"
|
||||
#include "lanczosfilter.h"
|
||||
#include "overlaywindow.h"
|
||||
|
||||
#include <math.h>
|
||||
|
@ -87,6 +89,7 @@ Sources and other compositing managers:
|
|||
#include <X11/extensions/Xcomposite.h>
|
||||
|
||||
#include <qpainter.h>
|
||||
#include <QDesktopWidget>
|
||||
#include <QVector2D>
|
||||
#include <QVector4D>
|
||||
#include <QMatrix4x4>
|
||||
|
@ -205,6 +208,38 @@ void SceneOpenGL::paintBackground(QRegion region)
|
|||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data)
|
||||
{
|
||||
if (options->isGlColorCorrection()) {
|
||||
// Split the painting for separate screens
|
||||
int numScreens = Workspace::self()->numScreens();
|
||||
for (int screen = 0; screen < numScreens; ++ screen) {
|
||||
QRegion regionForScreen(region);
|
||||
if (numScreens > 1)
|
||||
regionForScreen = region.intersected(Workspace::self()->screenGeometry(screen));
|
||||
|
||||
data.setScreen(screen);
|
||||
performPaint(w, mask, regionForScreen, data);
|
||||
}
|
||||
} else {
|
||||
performPaint(w, mask, region, data);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::performPaint(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data)
|
||||
{
|
||||
if (mask & PAINT_WINDOW_LANCZOS) {
|
||||
if (lanczos_filter.isNull()) {
|
||||
lanczos_filter = new LanczosFilter(this);
|
||||
// recreate the lanczos filter when the screen gets resized
|
||||
connect(QApplication::desktop(), SIGNAL(screenCountChanged(int)), lanczos_filter.data(), SLOT(deleteLater()));
|
||||
connect(QApplication::desktop(), SIGNAL(resized(int)), lanczos_filter.data(), SLOT(deleteLater()));
|
||||
}
|
||||
lanczos_filter.data()->performPaint(w, mask, region, data);
|
||||
} else
|
||||
w->sceneWindow()->performPaint(mask, region, data);
|
||||
}
|
||||
|
||||
void SceneOpenGL::windowAdded(Toplevel* c)
|
||||
{
|
||||
assert(!windows.contains(c));
|
||||
|
@ -489,6 +524,8 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
|
|||
data.shader = ShaderManager::instance()->pushShader(ShaderManager::SimpleShader);
|
||||
data.shader->setUniform(GLShader::Offset, QVector2D(x(), y()));
|
||||
}
|
||||
if (options->isGlColorCorrection())
|
||||
ColorCorrection::instance()->setupForOutput(data.screen());
|
||||
sceneShader = true;
|
||||
}
|
||||
|
||||
|
@ -573,9 +610,9 @@ void SceneOpenGL::Window::performPaint(int mask, QRegion region, WindowPaintData
|
|||
WindowQuadList contentQuads = data.quads.select(WindowQuadContents);
|
||||
if (!contentQuads.empty()) {
|
||||
texture.bind();
|
||||
prepareStates(Content, data.opacity(), data.brightness(), data.saturation(), data.shader);
|
||||
prepareStates(Content, data.opacity(), data.brightness(), data.saturation(), data.screen(), data.shader);
|
||||
renderQuads(mask, region, contentQuads, &texture, false, hardwareClipping);
|
||||
restoreStates(Content, data.opacity(), data.brightness(), data.saturation(), data.shader);
|
||||
restoreStates(Content, data.opacity(), data.brightness(), data.saturation(), data.screen(), data.shader);
|
||||
texture.unbind();
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
if (static_cast<SceneOpenGL*>(scene)->debug) {
|
||||
|
@ -646,10 +683,10 @@ void SceneOpenGL::Window::paintDecoration(const QPixmap* decoration, TextureType
|
|||
decorationTexture->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||
decorationTexture->bind();
|
||||
|
||||
prepareStates(decorationType, data.opacity() * data.decorationOpacity(), data.brightness(), data.saturation(), data.shader);
|
||||
prepareStates(decorationType, data.opacity() * data.decorationOpacity(), data.brightness(), data.saturation(), data.screen(), data.shader);
|
||||
makeDecorationArrays(quads, rect, decorationTexture);
|
||||
GLVertexBuffer::streamingBuffer()->render(region, GL_TRIANGLES, hardwareClipping);
|
||||
restoreStates(decorationType, data.opacity() * data.decorationOpacity(), data.brightness(), data.saturation(), data.shader);
|
||||
restoreStates(decorationType, data.opacity() * data.decorationOpacity(), data.brightness(), data.saturation(), data.screen(), data.shader);
|
||||
decorationTexture->unbind();
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
if (static_cast<SceneOpenGL*>(scene)->debug) {
|
||||
|
@ -683,9 +720,9 @@ void SceneOpenGL::Window::paintShadow(const QRegion ®ion, const WindowPaintDa
|
|||
texture->setFilter(GL_NEAREST);
|
||||
texture->setWrapMode(GL_CLAMP_TO_EDGE);
|
||||
texture->bind();
|
||||
prepareStates(Shadow, data.opacity(), data.brightness(), data.saturation(), data.shader, texture);
|
||||
prepareStates(Shadow, data.opacity(), data.brightness(), data.saturation(), data.screen(), data.shader, texture);
|
||||
renderQuads(0, region, quads, texture, true, hardwareClipping);
|
||||
restoreStates(Shadow, data.opacity(), data.brightness(), data.saturation(), data.shader, texture);
|
||||
restoreStates(Shadow, data.opacity(), data.brightness(), data.saturation(), data.screen(), data.shader, texture);
|
||||
texture->unbind();
|
||||
#ifndef KWIN_HAVE_OPENGLES
|
||||
if (static_cast<SceneOpenGL*>(scene)->debug) {
|
||||
|
@ -781,10 +818,10 @@ void SceneOpenGL::Window::renderQuads(int, const QRegion& region, const WindowQu
|
|||
delete[] texcoords;
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader)
|
||||
void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader)
|
||||
{
|
||||
if (shader)
|
||||
prepareShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
prepareShaderRenderStates(type, opacity, brightness, saturation, screen, shader);
|
||||
else {
|
||||
Texture *tex = NULL;
|
||||
switch(type) {
|
||||
|
@ -806,20 +843,20 @@ void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double
|
|||
default:
|
||||
return;
|
||||
}
|
||||
prepareStates(type, opacity, brightness, saturation, shader, tex);
|
||||
prepareStates(type, opacity, brightness, saturation, screen, shader, tex);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture)
|
||||
void SceneOpenGL::Window::prepareStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader, GLTexture *texture)
|
||||
{
|
||||
if (shader) {
|
||||
prepareShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
prepareShaderRenderStates(type, opacity, brightness, saturation, screen, shader);
|
||||
} else {
|
||||
prepareRenderStates(type, opacity, brightness, saturation, texture);
|
||||
prepareRenderStates(type, opacity, brightness, saturation, screen, texture);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader)
|
||||
void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader)
|
||||
{
|
||||
// setup blending of transparent windows
|
||||
bool opaque = isOpaque() && opacity == 1.0;
|
||||
|
@ -828,12 +865,15 @@ void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opa
|
|||
opaque = false;
|
||||
if (!opaque) {
|
||||
glEnable(GL_BLEND);
|
||||
if (!options->isGlColorCorrection()) {
|
||||
if (alpha) {
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
} else {
|
||||
glBlendColor((float)opacity, (float)opacity, (float)opacity, (float)opacity);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_CONSTANT_ALPHA);
|
||||
}
|
||||
} else
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
const float rgb = brightness * opacity;
|
||||
|
@ -842,10 +882,14 @@ void SceneOpenGL::Window::prepareShaderRenderStates(TextureType type, double opa
|
|||
shader->setUniform(GLShader::ModulationConstant, QVector4D(rgb, rgb, rgb, a));
|
||||
shader->setUniform(GLShader::Saturation, saturation);
|
||||
shader->setUniform(GLShader::AlphaToOne, opaque ? 1 : 0);
|
||||
|
||||
if (options->isGlColorCorrection())
|
||||
ColorCorrection::instance()->setupForOutput(screen);
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex)
|
||||
void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLTexture *tex)
|
||||
{
|
||||
Q_UNUSED(screen)
|
||||
#ifdef KWIN_HAVE_OPENGLES
|
||||
Q_UNUSED(type)
|
||||
Q_UNUSED(opacity)
|
||||
|
@ -980,10 +1024,10 @@ void SceneOpenGL::Window::prepareRenderStates(TextureType type, double opacity,
|
|||
#endif
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader)
|
||||
void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader)
|
||||
{
|
||||
if (shader)
|
||||
restoreShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
restoreShaderRenderStates(type, opacity, brightness, saturation, screen, shader);
|
||||
else {
|
||||
Texture *tex = NULL;
|
||||
switch(type) {
|
||||
|
@ -1005,23 +1049,24 @@ void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double
|
|||
default:
|
||||
return;
|
||||
}
|
||||
restoreStates(type, opacity, brightness, saturation, shader, tex);
|
||||
restoreStates(type, opacity, brightness, saturation, screen, shader, tex);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture)
|
||||
void SceneOpenGL::Window::restoreStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader, GLTexture *texture)
|
||||
{
|
||||
if (shader) {
|
||||
restoreShaderRenderStates(type, opacity, brightness, saturation, shader);
|
||||
restoreShaderRenderStates(type, opacity, brightness, saturation, screen, shader);
|
||||
} else {
|
||||
restoreRenderStates(type, opacity, brightness, saturation, texture);
|
||||
restoreRenderStates(type, opacity, brightness, saturation, screen, texture);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader)
|
||||
void SceneOpenGL::Window::restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader)
|
||||
{
|
||||
Q_UNUSED(brightness);
|
||||
Q_UNUSED(saturation);
|
||||
Q_UNUSED(screen)
|
||||
Q_UNUSED(shader);
|
||||
bool opaque = isOpaque() && opacity == 1.0;
|
||||
if (type != Content)
|
||||
|
@ -1032,9 +1077,10 @@ void SceneOpenGL::Window::restoreShaderRenderStates(TextureType type, double opa
|
|||
ShaderManager::instance()->getBoundShader()->setUniform(GLShader::AlphaToOne, 0);
|
||||
}
|
||||
|
||||
void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex)
|
||||
void SceneOpenGL::Window::restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLTexture *tex)
|
||||
{
|
||||
Q_UNUSED(type)
|
||||
Q_UNUSED(screen)
|
||||
#ifdef KWIN_HAVE_OPENGLES
|
||||
Q_UNUSED(opacity)
|
||||
Q_UNUSED(brightness)
|
||||
|
|
|
@ -56,6 +56,8 @@ public:
|
|||
protected:
|
||||
virtual void paintGenericScreen(int mask, ScreenPaintData data);
|
||||
virtual void paintBackground(QRegion region);
|
||||
virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
|
||||
virtual void performPaint(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data);
|
||||
QMatrix4x4 transformation(int mask, const ScreenPaintData &data) const;
|
||||
public Q_SLOTS:
|
||||
virtual void windowOpacityChanged(KWin::Toplevel* c);
|
||||
|
@ -184,14 +186,14 @@ protected:
|
|||
void paintShadow(const QRegion ®ion, const WindowPaintData &data, bool hardwareClipping);
|
||||
void makeDecorationArrays(const WindowQuadList& quads, const QRect &rect, Texture *tex) const;
|
||||
void renderQuads(int, const QRegion& region, const WindowQuadList& quads, GLTexture* tex, bool normalized, bool hardwareClipping);
|
||||
void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
|
||||
void prepareStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture);
|
||||
void prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex);
|
||||
void prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
|
||||
void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
|
||||
void restoreStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader, GLTexture *texture);
|
||||
void restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, GLTexture *tex);
|
||||
void restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, GLShader* shader);
|
||||
void prepareStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader);
|
||||
void prepareStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader, GLTexture *texture);
|
||||
void prepareRenderStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLTexture *tex);
|
||||
void prepareShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader);
|
||||
void restoreStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader);
|
||||
void restoreStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader, GLTexture *texture);
|
||||
void restoreRenderStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLTexture *tex);
|
||||
void restoreShaderRenderStates(TextureType type, double opacity, double brightness, double saturation, int screen, GLShader* shader);
|
||||
|
||||
private:
|
||||
Texture texture;
|
||||
|
|
|
@ -191,6 +191,7 @@ Workspace::Workspace(bool restore)
|
|||
connect(&rulesUpdatedTimer, SIGNAL(timeout()), this, SLOT(writeWindowRules()));
|
||||
connect(&unredirectTimer, SIGNAL(timeout()), this, SLOT(delayedCheckUnredirect()));
|
||||
connect(&compositeResetTimer, SIGNAL(timeout()), this, SLOT(resetCompositing()));
|
||||
connect(options, SIGNAL(glColorCorrectionChanged()), this, SLOT(resetCompositing()));
|
||||
unredirectTimer.setSingleShot(true);
|
||||
compositeResetTimer.setSingleShot(true);
|
||||
|
||||
|
|
Loading…
Reference in a new issue