[effects] Combine all shaders in resources

One resource is used for shader version 1.10 and one for version 1.40.

The ideas behind this change is to remove the locating of the shader
sources and also to fix that user provided shaders could be loaded
instead of the original ones (possible attack vector on Wayland).

To simplify the ShaderManager provides a new method call to load the
shader from the resource. This means the effects don't need to
duplicate the check for the shader version any more and also don't
need to duplicate the file reading functionality.

REVIEW: 126905
This commit is contained in:
Martin Gräßlin 2016-01-26 15:38:42 +01:00
parent fbf14306d7
commit 613d76f2df
18 changed files with 101 additions and 159 deletions

View file

@ -96,6 +96,8 @@ set( kwin4_effect_builtins_sources
zoom/zoom.cpp
)
qt5_add_resources( kwin4_effect_builtins_sources shaders.qrc )
kconfig_add_kcfg_files(kwin4_effect_builtins_sources
blur/blurconfig.kcfgc
cube/cubeslideconfig.kcfgc

View file

@ -1,12 +1,5 @@
#######################################
# Effect
install( FILES
shaders/1.10/coverswitch-reflection.glsl
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.10 )
install( FILES
shaders/1.40/coverswitch-reflection.glsl
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.40 )
#######################################
# Config

View file

@ -61,15 +61,7 @@ CoverSwitchEffect::CoverSwitchEffect()
captionFont.setPointSize(captionFont.pointSize() * 2);
if (effects->compositingType() == OpenGL2Compositing) {
QString shadersDir = QStringLiteral("kwin/shaders/1.10/");
const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40);
if (GLPlatform::instance()->glslVersion() >= coreVersionNumber)
shadersDir = QStringLiteral("kwin/shaders/1.40/");
const QString fragmentshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, shadersDir + QStringLiteral("coverswitch-reflection.glsl"));
QFile ff(fragmentshader);
if (ff.open(QIODevice::ReadOnly)) {
m_reflectionShader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture, QByteArray(), ff.readAll());
}
m_reflectionShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("coverswitch-reflection.glsl"));
} else {
m_reflectionShader = NULL;
}

View file

@ -6,22 +6,6 @@ install( FILES
data/cubecap.png
DESTINATION ${DATA_INSTALL_DIR}/kwin )
install( FILES
data/1.10/cube-cap.glsl
data/1.10/cube-reflection.glsl
data/1.10/cylinder.vert
data/1.10/sphere.vert
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.10
)
install( FILES
data/1.40/cube-cap.glsl
data/1.40/cube-reflection.glsl
data/1.40/cylinder.vert
data/1.40/sphere.vert
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.40
)
#######################################
# Config

View file

@ -89,28 +89,15 @@ CubeEffect::CubeEffect()
, zOrderingFactor(0.0f)
, mAddedHeightCoeff1(0.0f)
, mAddedHeightCoeff2(0.0f)
, m_shadersDir(QStringLiteral("kwin/shaders/1.10/"))
, m_cubeCapBuffer(NULL)
, m_proxy(this)
{
desktopNameFont.setBold(true);
desktopNameFont.setPointSize(14);
const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40);
if (GLPlatform::instance()->glslVersion() >= coreVersionNumber)
m_shadersDir = QStringLiteral("kwin/shaders/1.40/");
if (effects->compositingType() == OpenGL2Compositing) {
const QString fragmentshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, m_shadersDir + QStringLiteral("cube-reflection.glsl"));
QFile ffr(fragmentshader);
if (ffr.open(QIODevice::ReadOnly)) {
m_reflectionShader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture, QByteArray(), ffr.readAll());
}
const QString capshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, m_shadersDir + QStringLiteral("cube-cap.glsl"));
QFile ff(capshader);
if (ff.open(QIODevice::ReadOnly)) {
m_capShader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture, QByteArray(), ff.readAll());
}
m_reflectionShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("cube-reflection.glsl"));
m_capShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("cube-cap.glsl"));
} else {
m_reflectionShader = NULL;
m_capShader = NULL;
@ -301,20 +288,8 @@ bool CubeEffect::loadShader()
if (!(GLPlatform::instance()->supports(GLSL) &&
(effects->compositingType() == OpenGL2Compositing)))
return false;
QString cylinderVertexshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, m_shadersDir + QStringLiteral("cylinder.vert"));
QString sphereVertexshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, m_shadersDir + QStringLiteral("sphere.vert"));
if (cylinderVertexshader.isEmpty() || sphereVertexshader.isEmpty()) {
qCCritical(KWINEFFECTS) << "Couldn't locate shader files";
return false;
}
QFile cvf(cylinderVertexshader);
if (!cvf.open(QIODevice::ReadOnly)) {
qCCritical(KWINEFFECTS) << "The cylinder shader couldn't be opened!";
return false;
}
cylinderShader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture | ShaderTrait::AdjustSaturation | ShaderTrait::Modulate, cvf.readAll(), QByteArray());
cylinderShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture | ShaderTrait::AdjustSaturation | ShaderTrait::Modulate, QStringLiteral("cylinder.vert"), QString());
if (!cylinderShader->isValid()) {
qCCritical(KWINEFFECTS) << "The cylinder shader failed to load!";
return false;
@ -325,12 +300,7 @@ bool CubeEffect::loadShader()
cylinderShader->setUniform("width", (float)rect.width() * 0.5f);
}
QFile svf(sphereVertexshader);
if (!svf.open(QIODevice::ReadOnly)) {
qCCritical(KWINEFFECTS) << "The sphere shader couldn't be opened!";
return false;
}
sphereShader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture | ShaderTrait::AdjustSaturation | ShaderTrait::Modulate, svf.readAll(), QByteArray());
sphereShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture | ShaderTrait::AdjustSaturation | ShaderTrait::Modulate, QStringLiteral("sphere.vert"), QString());
if (!sphereShader->isValid()) {
qCCritical(KWINEFFECTS) << "The sphere shader failed to load!";
return false;

View file

@ -231,8 +231,6 @@ private:
float mAddedHeightCoeff1;
float mAddedHeightCoeff2;
QString m_shadersDir;
QMatrix4x4 m_rotationMatrix;
QMatrix4x4 m_reflectionMatrix;
QMatrix4x4 m_textureMirrorMatrix;

View file

@ -1,14 +1,6 @@
#######################################
# Effect
# Data files
install( FILES
data/1.10/invert.frag
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.10 )
install( FILES
data/1.40/invert.frag
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.40 )
#######################################
# Config
set(kwin_invert_config_SRCS invert_config.cpp)

View file

@ -73,19 +73,7 @@ bool InvertEffect::loadData()
{
m_inited = true;
QString shadersDir = QStringLiteral("kwin/shaders/1.10/");
const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40);
if (GLPlatform::instance()->glslVersion() >= coreVersionNumber)
shadersDir = QStringLiteral("kwin/shaders/1.40/");
const QString fragmentshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, shadersDir + QStringLiteral("invert.frag"));
QFile ff(fragmentshader);
if (!ff.open(QIODevice::ReadOnly)) {
qCCritical(KWINEFFECTS) << "Couldn't open" << fragmentshader << "for reading!";
return false;
}
m_shader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture, QByteArray(), ff.readAll());
m_shader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("invert.frag"));
if (!m_shader->isValid()) {
qCCritical(KWINEFFECTS) << "The shader failed to load!";
return false;

View file

@ -7,16 +7,3 @@ set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
)
kconfig_add_kcfg_files(kwin4_effect_builtins_sources logout/logoutconfig.kcfgc)
# Data files
install( FILES
logout/data/1.10/vignetting.frag
logout/data/1.10/logout-blur.frag
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.10
)
install( FILES
logout/data/1.40/vignetting.frag
logout/data/1.40/logout-blur.frag
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.40
)

View file

@ -67,7 +67,6 @@ LogoutEffect::LogoutEffect()
, ignoredWindows()
, m_vignettingShader(NULL)
, m_blurShader(NULL)
, m_shadersDir(QStringLiteral("kwin/shaders/1.10/"))
{
if (logoutAtom.isValid()) {
// Persistent effect
@ -81,12 +80,6 @@ LogoutEffect::LogoutEffect()
connect(effects, SIGNAL(windowClosed(KWin::EffectWindow*)), this, SLOT(slotWindowClosed(KWin::EffectWindow*)));
connect(effects, SIGNAL(windowDeleted(KWin::EffectWindow*)), this, SLOT(slotWindowDeleted(KWin::EffectWindow*)));
connect(effects, SIGNAL(propertyNotify(KWin::EffectWindow*,long)), this, SLOT(slotPropertyNotify(KWin::EffectWindow*,long)));
if (effects->isOpenGLCompositing()) {
const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40);
if (GLPlatform::instance()->glslVersion() >= coreVersionNumber)
m_shadersDir = QStringLiteral("kwin/shaders/1.40/");
}
}
LogoutEffect::~LogoutEffect()
@ -304,12 +297,7 @@ bool LogoutEffect::isLogoutDialog(EffectWindow* w)
void LogoutEffect::renderVignetting(const QMatrix4x4 &projection)
{
if (!m_vignettingShader) {
QFile ff(QStandardPaths::locate(QStandardPaths::GenericDataLocation, m_shadersDir + QStringLiteral("vignetting.frag")));
if (!ff.open(QIODevice::ReadOnly)) {
qCDebug(KWINEFFECTS) << "Could not open Vignetting Shader";
return;
}
m_vignettingShader = ShaderManager::instance()->generateCustomShader(ShaderTrait(), QByteArray(), ff.readAll());
m_vignettingShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait(), QString(), QStringLiteral("vignetting.frag"));
if (!m_vignettingShader->isValid()) {
qCDebug(KWINEFFECTS) << "Vignetting Shader failed to load";
return;
@ -351,16 +339,12 @@ void LogoutEffect::renderVignetting(const QMatrix4x4 &projection)
void LogoutEffect::renderBlurTexture(const QMatrix4x4 &projection)
{
if (!m_blurShader) {
QFile ff(QStandardPaths::locate(QStandardPaths::GenericDataLocation, m_shadersDir + QStringLiteral("logout-blur.frag")));
if (!ff.open(QIODevice::ReadOnly)) {
qCDebug(KWINEFFECTS) << "Could not open Logout Blur Shader";
return;
}
m_blurShader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture, QByteArray(), ff.readAll());
m_blurShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("logout-blur.frag"));
if (!m_blurShader->isValid()) {
qCDebug(KWINEFFECTS) << "Logout blur shader failed to load";
}
} else if (!m_blurShader->isValid()) {
}
if (!m_blurShader->isValid()) {
// shader is broken - no need to continue here
return;
}

View file

@ -96,7 +96,6 @@ private:
QList<WinDataPair> m_windows;
GLShader *m_vignettingShader;
GLShader *m_blurShader;
QString m_shadersDir;
};
} // namespace

View file

@ -1,14 +1,6 @@
#######################################
# Effect
# Data files
install( FILES
data/1.10/lookingglass.frag
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.10 )
install( FILES
data/1.40/lookingglass.frag
DESTINATION ${DATA_INSTALL_DIR}/kwin/shaders/1.40 )
#######################################
# Config
set(kwin_lookingglass_config_SRCS lookingglass_config.cpp)

View file

@ -112,17 +112,7 @@ bool LookingGlassEffect::loadData()
return false;
}
QString shadersDir = QStringLiteral("kwin/shaders/1.10/");
const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40);
if (GLPlatform::instance()->glslVersion() >= coreVersionNumber)
shadersDir = QStringLiteral("kwin/shaders/1.40/");
const QString fragmentshader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, shadersDir + QStringLiteral("lookingglass.frag"));
QFile ff(fragmentshader);
if (!ff.open(QIODevice::ReadOnly)) {
qCCritical(KWINEFFECTS) << "Failed to read shader!";
return false;
}
m_shader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture, QByteArray(), ff.readAll());
m_shader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("lookingglass.frag"));
if (m_shader->isValid()) {
ShaderBinder binder(m_shader);
m_shader->setUniform("u_textureSize", QVector2D(screenSize.width(), screenSize.height()));

26
effects/shaders.qrc Normal file
View file

@ -0,0 +1,26 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/effect-shaders-1.10">
<file alias="coverswitch-reflection.glsl">coverswitch/shaders/1.10/coverswitch-reflection.glsl</file>
<file alias="cube-cap.glsl">cube/data/1.10/cube-cap.glsl</file>
<file alias="cube-reflection.glsl">cube/data/1.10/cube-reflection.glsl</file>
<file alias="cylinder.vert">cube/data/1.10/cylinder.vert</file>
<file alias="sphere.vert">cube/data/1.10/sphere.vert</file>
<file alias="invert.frag">invert/data/1.10/invert.frag</file>
<file alias="logout-blur.frag">logout/data/1.10/logout-blur.frag</file>
<file alias="vignetting.frag">logout/data/1.10/vignetting.frag</file>
<file alias="lookingglass.frag">lookingglass/data/1.10/lookingglass.frag</file>
<file alias="blinking-startup-fragment.glsl">startupfeedback/data/blinking-startup-fragment.glsl</file>
</qresource>
<qresource prefix="/effect-shaders-1.40">
<file alias="coverswitch-reflection.glsl">coverswitch/shaders/1.40/coverswitch-reflection.glsl</file>
<file alias="cube-cap.glsl">cube/data/1.40/cube-cap.glsl</file>
<file alias="cube-reflection.glsl">cube/data/1.40/cube-reflection.glsl</file>
<file alias="cylinder.vert">cube/data/1.40/cylinder.vert</file>
<file alias="sphere.vert">cube/data/1.40/sphere.vert</file>
<file alias="invert.frag">invert/data/1.40/invert.frag</file>
<file alias="logout-blur.frag">logout/data/1.40/logout-blur.frag</file>
<file alias="vignetting.frag">logout/data/1.40/vignetting.frag</file>
<file alias="lookingglass.frag">lookingglass/data/1.40/lookingglass.frag</file>
</qresource>
</RCC>

View file

@ -6,10 +6,5 @@ set( kwin4_effect_builtins_sources ${kwin4_effect_builtins_sources}
startupfeedback/startupfeedback.cpp
)
# Data files
install( FILES
startupfeedback/data/blinking-startup-fragment.glsl
DESTINATION ${DATA_INSTALL_DIR}/kwin )
#######################################
# Config

View file

@ -130,19 +130,11 @@ void StartupFeedbackEffect::reconfigure(Effect::ReconfigureFlags flags)
m_type = BlinkingFeedback;
if (effects->compositingType() == OpenGL2Compositing) {
delete m_blinkingShader;
m_blinkingShader = 0;
const QString shader = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kwin/blinking-startup-fragment.glsl"));
QFile ff(shader);
if (ff.open(QIODevice::ReadOnly)) {
m_blinkingShader = ShaderManager::instance()->generateCustomShader(ShaderTrait::MapTexture, QByteArray(), ff.readAll());
if (m_blinkingShader->isValid()) {
qCDebug(KWINEFFECTS) << "Blinking Shader is valid";
} else {
qCDebug(KWINEFFECTS) << "Blinking Shader is not valid";
}
m_blinkingShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("blinking-startup-fragment.glsl"));
if (m_blinkingShader->isValid()) {
qCDebug(KWINEFFECTS) << "Blinking Shader is valid";
} else {
qCCritical(KWINEFFECTS) << "Couldn't open" << shader << "for reading!";
qCDebug(KWINEFFECTS) << "Blinking Shader is not valid";
}
}
} else

View file

@ -644,6 +644,13 @@ void ShaderManager::cleanup()
ShaderManager::ShaderManager()
{
m_debug = qstrcmp(qgetenv("KWIN_GL_DEBUG"), "1") == 0;
const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40);
if (GLPlatform::instance()->glslVersion() >= coreVersionNumber) {
m_resourcePath = QStringLiteral(":/effect-shaders-1.40/");
} else {
m_resourcePath = QStringLiteral(":/effect-shaders-1.10/");
}
}
ShaderManager::~ShaderManager()
@ -1003,6 +1010,33 @@ GLShader *ShaderManager::generateCustomShader(ShaderTraits traits, const QByteAr
return shader;
}
GLShader *ShaderManager::generateShaderFromResources(ShaderTraits traits, const QString &vertexFile, const QString &fragmentFile)
{
auto loadShaderFile = [this] (const QString &fileName) {
QFile file(m_resourcePath + fileName);
if (file.open(QIODevice::ReadOnly)) {
return file.readAll();
}
qCCritical(LIBKWINGLUTILS) << "Failed to read shader " << fileName;
return QByteArray();
};
QByteArray vertexSource;
QByteArray fragmentSource;
if (!vertexFile.isEmpty()) {
vertexSource = loadShaderFile(vertexFile);
if (vertexSource.isEmpty()) {
return new GLShader();
}
}
if (!fragmentFile.isEmpty()) {
fragmentSource = loadShaderFile(fragmentFile);
if (fragmentSource.isEmpty()) {
return new GLShader();
}
}
return generateCustomShader(traits, vertexSource, fragmentSource);
}
GLShader *ShaderManager::shader(ShaderTraits traits)
{
GLShader *shader = m_shaderHash.value(traits);

View file

@ -301,6 +301,29 @@ public:
**/
GLShader *generateCustomShader(ShaderTraits traits, const QByteArray &vertexSource = QByteArray(), const QByteArray &fragmentSource = QByteArray());
/**
* Creates a custom shader with the given @p traits and custom @p vertexFile and or @p fragmentFile.
* The file names specified in @p vertexFile and @p fragmentFile are relative paths to the shaders
* resource file shipped together with KWin. This means this method can only be used for built-in
* effects, for 3rd party effects @link {generateCustomShader} should be used.
*
* If the @p vertexFile is empty a vertex shader with the given @p traits is generated.
* If it is not empty the @p vertexFile is used as the source for the vertex shader.
*
* The same applies for argument @p fragmentFile just for the fragment shader.
*
* So if both @p vertexFile and @p fragmentFile are provided the @p traits are ignored.
* If neither are provided a new shader following the @p traits is generated.
*
* @param traits The shader traits for generating the shader
* @param vertexFile optional vertex shader source code to be used instead of shader traits
* @param fragmentFile optional fragment shader source code to be used instead of shader traits
* @return new generated shader
* @see generateCustomShader
* @since 5.6
**/
GLShader *generateShaderFromResources(ShaderTraits traits, const QString &vertexFile = QString(), const QString &fragmentFile = QString());
/**
* Compiles and tests the dynamically generated shaders.
* Returns true if successful and false otherwise.
@ -331,6 +354,7 @@ private:
QStack<GLShader*> m_boundShaders;
QHash<ShaderTraits, GLShader *> m_shaderHash;
bool m_debug;
QString m_resourcePath;
static ShaderManager *s_shaderManager;
};