effects: Fix resource file reading for builtin effects

Currently, the invert effect doesn't work because it can't load its
fragment shader because builtin effects are static libs. We need
Q_INIT_RESOURCE() before reading shader code.

This modularizes builtin effects more, which makes easier to add and
remove builtin effects, as well as allows to have per effect resources.

Technically, changing the inner workings of the ShaderManager is an
API incompatible change, but ShaderManager::generateShaderFromResources()
can be used only by builtin effects so it's okay.

ShaderManager::generateShaderFromResources() had to be changed because
two resource files can't share the same prefix. Appending "_core" was
inspired by QtQuick.
This commit is contained in:
Vlad Zahorodnii 2022-01-13 11:31:37 +02:00
parent 11763bb32c
commit 754e0d8f6e
19 changed files with 76 additions and 30 deletions

View file

@ -169,8 +169,6 @@ set(kwin4_effect_builtins_sources
../service_utils.cpp
)
qt5_add_resources(kwin4_effect_builtins_sources shaders.qrc)
add_library(kwin4_effect_builtins STATIC ${kwin4_effect_builtins_sources})
kcoreaddons_target_static_plugins(kwin4_effect_builtins "kwin/effects/plugins" LINK_OPTION "PRIVATE")
target_link_libraries(kwin4_effect_builtins PRIVATE

View file

@ -3,6 +3,7 @@
set(invert_SOURCES
invert.cpp
invert.qrc
main.cpp
)

View file

@ -22,6 +22,12 @@
Q_LOGGING_CATEGORY(KWIN_INVERT, "kwin_effect_invert", QtWarningMsg)
static void ensureResources()
{
// Must initialize resources manually because the effect is a static lib.
Q_INIT_RESOURCE(invert);
}
namespace KWin
{
@ -62,9 +68,10 @@ bool InvertEffect::supported()
bool InvertEffect::loadData()
{
ensureResources();
m_inited = true;
m_shader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("invert.frag"));
m_shader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral(":/effects/invert/shaders/invert.frag"));
if (!m_shader->isValid()) {
qCCritical(KWIN_INVERT) << "The shader failed to load!";
return false;

View file

@ -0,0 +1,6 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/effects/invert/">
<file>shaders/invert.frag</file>
<file>shaders/invert_core.frag</file>
</qresource>
</RCC>

View file

@ -3,6 +3,7 @@
set(lookingglass_SOURCES
lookingglass.cpp
lookingglass.qrc
main.cpp
)

View file

@ -29,6 +29,12 @@
Q_LOGGING_CATEGORY(KWIN_LOOKINGGLASS, "kwin_effect_lookingglass", QtWarningMsg)
static void ensureResources()
{
// Must initialize resources manually because the effect is a static lib.
Q_INIT_RESOURCE(lookingglass);
}
namespace KWin
{
@ -91,6 +97,8 @@ void LookingGlassEffect::reconfigure(ReconfigureFlags)
bool LookingGlassEffect::loadData()
{
ensureResources();
const QSize screenSize = effects->virtualScreenSize();
int texw = screenSize.width();
int texh = screenSize.height();
@ -106,7 +114,7 @@ bool LookingGlassEffect::loadData()
return false;
}
m_shader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("lookingglass.frag"));
m_shader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral(":/effects/lookingglass/shaders/lookingglass.frag"));
if (m_shader->isValid()) {
ShaderBinder binder(m_shader);
m_shader->setUniform("u_textureSize", QVector2D(screenSize.width(), screenSize.height()));

View file

@ -0,0 +1,7 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/effects/lookingglass/">
<file>shaders/lookingglass.frag</file>
<file>shaders/lookingglass_core.frag</file>
</qresource>
</RCC>

View file

@ -1,13 +0,0 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/effect-shaders-1.10">
<file alias="invert.frag">invert/data/1.10/invert.frag</file>
<file alias="lookingglass.frag">lookingglass/data/1.10/lookingglass.frag</file>
<file alias="blinking-startup-fragment.glsl">startupfeedback/data/1.10/blinking-startup-fragment.glsl</file>
</qresource>
<qresource prefix="/effect-shaders-1.40">
<file alias="invert.frag">invert/data/1.40/invert.frag</file>
<file alias="lookingglass.frag">lookingglass/data/1.40/lookingglass.frag</file>
<file alias="blinking-startup-fragment.glsl">startupfeedback/data/1.40/blinking-startup-fragment.glsl</file>
</qresource>
</RCC>

View file

@ -5,6 +5,7 @@
set(startupfeedback_SOURCES
main.cpp
startupfeedback.cpp
startupfeedback.qrc
)
kwin4_add_effect_module(kwin4_effect_startupfeedback ${startupfeedback_SOURCES})

View file

@ -30,6 +30,12 @@
Q_LOGGING_CATEGORY(KWIN_STARTUPFEEDBACK, "kwin_effect_startupfeedback", QtWarningMsg)
static void ensureResources()
{
// Must initialize resources manually because the effect is a static lib.
Q_INIT_RESOURCE(startupfeedback);
}
namespace KWin
{
@ -145,7 +151,8 @@ void StartupFeedbackEffect::reconfigure(Effect::ReconfigureFlags flags)
else if (busyBlinking) {
m_type = BlinkingFeedback;
if (effects->compositingType() == OpenGLCompositing) {
m_blinkingShader.reset(ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("blinking-startup-fragment.glsl")));
ensureResources();
m_blinkingShader.reset(ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral(":/effects/startupfeedback/shaders/blinking-startup.frag")));
if (m_blinkingShader->isValid()) {
qCDebug(KWIN_STARTUPFEEDBACK) << "Blinking Shader is valid";
} else {

View file

@ -0,0 +1,7 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/effects/startupfeedback/">
<file>shaders/blinking-startup.frag</file>
<file>shaders/blinking-startup_core.frag</file>
</qresource>
</RCC>

View file

@ -618,12 +618,6 @@ void ShaderManager::cleanup()
ShaderManager::ShaderManager()
{
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()
@ -783,26 +777,49 @@ GLShader *ShaderManager::generateCustomShader(ShaderTraits traits, const QByteAr
return shader;
}
static QString resolveShaderFilePath(const QString &filePath)
{
QString suffix;
QString extension;
const qint64 coreVersionNumber = GLPlatform::instance()->isGLES() ? kVersionNumber(3, 0) : kVersionNumber(1, 40);
if (GLPlatform::instance()->glslVersion() >= coreVersionNumber) {
suffix = QStringLiteral("_core");
}
if (filePath.endsWith(QStringLiteral(".frag"))) {
extension = QStringLiteral(".frag");
} else if (filePath.endsWith(QStringLiteral(".vert"))) {
extension = QStringLiteral(".vert");
} else {
qCWarning(LIBKWINGLUTILS) << filePath << "must end either with .vert or .frag";
return QString();
}
const QString prefix = filePath.chopped(extension.size());
return prefix + suffix + extension;
}
GLShader *ShaderManager::generateShaderFromResources(ShaderTraits traits, const QString &vertexFile, const QString &fragmentFile)
{
auto loadShaderFile = [this] (const QString &fileName) {
QFile file(m_resourcePath + fileName);
auto loadShaderFile = [](const QString &filePath) {
QFile file(filePath);
if (file.open(QIODevice::ReadOnly)) {
return file.readAll();
}
qCCritical(LIBKWINGLUTILS) << "Failed to read shader " << fileName;
qCCritical(LIBKWINGLUTILS) << "Failed to read shader " << filePath;
return QByteArray();
};
QByteArray vertexSource;
QByteArray fragmentSource;
if (!vertexFile.isEmpty()) {
vertexSource = loadShaderFile(vertexFile);
vertexSource = loadShaderFile(resolveShaderFilePath(vertexFile));
if (vertexSource.isEmpty()) {
return new GLShader();
}
}
if (!fragmentFile.isEmpty()) {
fragmentSource = loadShaderFile(fragmentFile);
fragmentSource = loadShaderFile(resolveShaderFilePath(fragmentFile));
if (fragmentSource.isEmpty()) {
return new GLShader();
}

View file

@ -306,7 +306,6 @@ private:
QStack<GLShader*> m_boundShaders;
QHash<ShaderTraits, GLShader *> m_shaderHash;
QString m_resourcePath;
static ShaderManager *s_shaderManager;
};