Added screen shaders

This commit is contained in:
Vaxry 2022-12-01 13:36:07 +00:00
parent b8ccf3dc3a
commit 7b020ffa84
6 changed files with 158 additions and 39 deletions

16
example/screenShader.frag Normal file
View file

@ -0,0 +1,16 @@
//
// Example blue light filter shader.
//
precision mediump float;
varying vec2 v_texcoord;
uniform sampler2D tex;
void main() {
vec4 pixColor = texture2D(tex, v_texcoord);
pixColor[2] *= 0.8;
gl_FragColor = pixColor;
}

View file

@ -92,6 +92,7 @@ void CConfigManager::setDefaultVars() {
configValues["decoration:col.shadow_inactive"].intValue = INT_MAX; configValues["decoration:col.shadow_inactive"].intValue = INT_MAX;
configValues["decoration:dim_inactive"].intValue = 0; configValues["decoration:dim_inactive"].intValue = 0;
configValues["decoration:dim_strength"].floatValue = 0.5f; configValues["decoration:dim_strength"].floatValue = 0.5f;
configValues["decoration:screen_shader"].strValue = STRVAL_EMPTY;
configValues["dwindle:pseudotile"].intValue = 0; configValues["dwindle:pseudotile"].intValue = 0;
configValues["dwindle:col.group_border"].intValue = 0x66777700; configValues["dwindle:col.group_border"].intValue = 0x66777700;
@ -403,6 +404,21 @@ void CConfigManager::configSetValueSafe(const std::string& COMMAND, const std::s
} }
} }
} }
if (COMMAND == "decoration:screen_shader") {
const auto PATH = absolutePath(VALUE, configCurrentPath);
configPaths.push_back(PATH);
struct stat fileStat;
int err = stat(PATH.c_str(), &fileStat);
if (err != 0) {
Debug::log(WARN, "Error at ticking config at %s, error %i: %s", PATH.c_str(), err, strerror(err));
return;
}
configModifyTimes[PATH] = fileStat.st_mtime;
}
} }
void CConfigManager::handleRawExec(const std::string& command, const std::string& args) { void CConfigManager::handleRawExec(const std::string& command, const std::string& args) {
@ -1230,6 +1246,9 @@ void CConfigManager::loadConfigLoadVars() {
// Calculate the internal vars // Calculate the internal vars
configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue); configValues["general:main_mod_internal"].intValue = g_pKeybindManager->stringToModMask(configValues["general:main_mod"].strValue);
if (!isFirstLaunch)
g_pHyprOpenGL->m_bReloadScreenShader = true;
// parseError will be displayed next frame // parseError will be displayed next frame
if (parseError != "") if (parseError != "")
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255)); g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
@ -1652,6 +1671,8 @@ SAnimationPropertyConfig* CConfigManager::getAnimationPropertyConfig(const std::
void CConfigManager::addParseError(const std::string& err) { void CConfigManager::addParseError(const std::string& err) {
if (parseError == "") if (parseError == "")
parseError = err; parseError = err;
g_pHyprError->queueCreate(parseError + "\nHyprland may not work correctly.", CColor(255, 50, 50, 255));
} }
CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) { CMonitor* CConfigManager::getBoundMonitorForWS(std::string wsname) {

View file

@ -30,12 +30,22 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!"); RASSERT(eglMakeCurrent(wlr_egl_get_display(g_pCompositor->m_sWLREGL), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT), "Couldn't unset current EGL!");
} }
GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag) { GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string& frag, bool dynamic) {
auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert); auto vertCompiled = compileShader(GL_VERTEX_SHADER, vert);
if (dynamic) {
if (vertCompiled == 0)
return 0;
} else {
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str()); RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str());
}
auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag); auto fragCompiled = compileShader(GL_FRAGMENT_SHADER, frag);
if (dynamic) {
if (fragCompiled == 0)
return 0;
} else {
RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str()); RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str());
}
auto prog = glCreateProgram(); auto prog = glCreateProgram();
glAttachShader(prog, vertCompiled); glAttachShader(prog, vertCompiled);
@ -49,12 +59,17 @@ GLuint CHyprOpenGLImpl::createProgram(const std::string& vert, const std::string
GLint ok; GLint ok;
glGetProgramiv(prog, GL_LINK_STATUS, &ok); glGetProgramiv(prog, GL_LINK_STATUS, &ok);
if (dynamic) {
if (ok == GL_FALSE)
return 0;
} else {
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!"); RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!");
}
return prog; return prog;
} }
GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) { GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src, bool dynamic) {
auto shader = glCreateShader(type); auto shader = glCreateShader(type);
auto shaderSource = src.c_str(); auto shaderSource = src.c_str();
@ -64,7 +79,12 @@ GLuint CHyprOpenGLImpl::compileShader(const GLuint& type, std::string src) {
GLint ok; GLint ok;
glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); glGetShaderiv(shader, GL_COMPILE_STATUS, &ok);
if (dynamic) {
if (ok == GL_FALSE)
return 0;
} else {
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!"); RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!");
}
return shader; return shader;
} }
@ -112,6 +132,11 @@ void CHyprOpenGLImpl::begin(CMonitor* pMonitor, pixman_region32_t* pDamage, bool
m_RenderData.pDamage = pDamage; m_RenderData.pDamage = pDamage;
m_bFakeFrame = fake; m_bFakeFrame = fake;
if (m_bReloadScreenShader) {
m_bReloadScreenShader = false;
applyScreenShader(g_pConfigManager->getString("decoration:screen_shader"));
}
} }
void CHyprOpenGLImpl::end() { void CHyprOpenGLImpl::end() {
@ -128,9 +153,11 @@ void CHyprOpenGLImpl::end() {
clear(CColor(11, 11, 11, 255)); clear(CColor(11, 11, 11, 255));
m_bEndFrame = true; m_bEndFrame = true;
m_bApplyFinalShader = true;
renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0); renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0);
m_bApplyFinalShader = false;
m_bEndFrame = false; m_bEndFrame = false;
} }
@ -250,6 +277,35 @@ void CHyprOpenGLImpl::initShaders() {
Debug::log(LOG, "Shaders initialized successfully."); Debug::log(LOG, "Shaders initialized successfully.");
} }
void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
m_sFinalScreenShader.destroy();
if (path == "" || path == STRVAL_EMPTY)
return;
std::ifstream infile(absolutePath(path, std::string(getenv("HOME")) + "/.config/hypr"));
if (!infile.good()) {
g_pConfigManager->addParseError("Screen shader parser: Screen shader path not found");
return;
}
std::string fragmentShader((std::istreambuf_iterator<char>(infile)), (std::istreambuf_iterator<char>()));
m_sFinalScreenShader.program = createProgram(TEXVERTSRC, fragmentShader, true);
if (!m_sFinalScreenShader.program) {
g_pConfigManager->addParseError("Screen shader parser: Screen shader parse failed");
return;
}
m_sFinalScreenShader.proj = glGetUniformLocation(m_sFinalScreenShader.program, "proj");
m_sFinalScreenShader.tex = glGetUniformLocation(m_sFinalScreenShader.program, "tex");
m_sFinalScreenShader.texAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "texcoord");
m_sFinalScreenShader.posAttrib = glGetAttribLocation(m_sFinalScreenShader.program, "pos");
}
void CHyprOpenGLImpl::clear(const CColor& color) { void CHyprOpenGLImpl::clear(const CColor& color) {
RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!"); RASSERT(m_RenderData.pMonitor, "Tried to render without begin()!");
@ -420,6 +476,12 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
bool usingFinalShader = false;
if (m_bApplyFinalShader && m_sFinalScreenShader.program) {
shader = &m_sFinalScreenShader;
usingFinalShader = true;
} else {
switch (tex.m_iType) { switch (tex.m_iType) {
case TEXTURE_RGBA: case TEXTURE_RGBA:
shader = &m_RenderData.pCurrentMonData->m_shRGBA; shader = &m_RenderData.pCurrentMonData->m_shRGBA;
@ -433,6 +495,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
default: default:
RASSERT(false, "tex.m_iTarget unsupported!"); RASSERT(false, "tex.m_iTarget unsupported!");
} }
}
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(tex.m_iTarget, tex.m_iTexID); glBindTexture(tex.m_iTarget, tex.m_iTexID);
@ -448,8 +511,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix); glUniformMatrix3fv(shader->proj, 1, GL_FALSE, glMatrix);
#endif #endif
glUniform1i(shader->tex, 0); glUniform1i(shader->tex, 0);
if (!usingFinalShader) {
glUniform1f(shader->alpha, alpha / 255.f); glUniform1f(shader->alpha, alpha / 255.f);
glUniform1i(shader->discardOpaque, (int)discardOpaque); glUniform1i(shader->discardOpaque, (int)discardOpaque);
}
wlr_box transformedBox; wlr_box transformedBox;
wlr_box_transform(&transformedBox, pBox, wlr_output_transform_invert(m_RenderData.pMonitor->transform), wlr_box_transform(&transformedBox, pBox, wlr_output_transform_invert(m_RenderData.pMonitor->transform),
@ -459,9 +524,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height); const auto FULLSIZE = Vector2D(transformedBox.width, transformedBox.height);
static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue;
if (!usingFinalShader) {
// Rounded corners // Rounded corners
glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y); glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
glUniform2f(shader->fullSize, FULLSIZE.x ,FULLSIZE.y); glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y);
glUniform1f(shader->radius, round); glUniform1f(shader->radius, round);
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA)); glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
@ -472,6 +538,7 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
} else { } else {
glUniform1i(shader->applyTint, 0); glUniform1i(shader->applyTint, 0);
} }
}
const float verts[] = { const float verts[] = {
m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVTopLeft.y, // top right m_RenderData.primarySurfaceUVBottomRight.x, m_RenderData.primarySurfaceUVTopLeft.y, // top right

View file

@ -111,11 +111,15 @@ public:
void onWindowResizeStart(CWindow*); void onWindowResizeStart(CWindow*);
void onWindowResizeEnd(CWindow*); void onWindowResizeEnd(CWindow*);
void applyScreenShader(const std::string& path);
SCurrentRenderData m_RenderData; SCurrentRenderData m_RenderData;
GLint m_iCurrentOutputFb = 0; GLint m_iCurrentOutputFb = 0;
GLint m_iWLROutputFb = 0; GLint m_iWLROutputFb = 0;
bool m_bReloadScreenShader = true; // at launch it can be set
CWindow* m_pCurrentWindow = nullptr; // hack to get the current rendered window CWindow* m_pCurrentWindow = nullptr; // hack to get the current rendered window
pixman_region32_t m_rOriginalDamageRegion; // used for storing the pre-expanded region pixman_region32_t m_rOriginalDamageRegion; // used for storing the pre-expanded region
@ -134,9 +138,12 @@ private:
bool m_bFakeFrame = false; bool m_bFakeFrame = false;
bool m_bEndFrame = false; bool m_bEndFrame = false;
bool m_bApplyFinalShader = false;
GLuint createProgram(const std::string&, const std::string&); CShader m_sFinalScreenShader;
GLuint compileShader(const GLuint&, std::string);
GLuint createProgram(const std::string&, const std::string&, bool dynamic = false);
GLuint compileShader(const GLuint&, std::string, bool dynamic = false);
void createBGTextureForMonitor(CMonitor*); void createBGTextureForMonitor(CMonitor*);
void initShaders(); void initShaders();

View file

@ -14,5 +14,11 @@ GLint CShader::getUniformLocation(const std::string& unif) {
CShader::~CShader() { CShader::~CShader() {
// destroy shader // destroy shader
destroy();
program = 0;
}
void CShader::destroy() {
glDeleteProgram(program); glDeleteProgram(program);
} }

View file

@ -39,6 +39,8 @@ public:
GLint getUniformLocation(const std::string&); GLint getUniformLocation(const std::string&);
void destroy();
private: private:
std::unordered_map<std::string, GLint> m_muUniforms; std::unordered_map<std::string, GLint> m_muUniforms;
}; };