mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-24 16:05:58 +01:00
Added screen shaders
This commit is contained in:
parent
b8ccf3dc3a
commit
7b020ffa84
6 changed files with 158 additions and 39 deletions
16
example/screenShader.frag
Normal file
16
example/screenShader.frag
Normal 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;
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
RASSERT(vertCompiled, "Compiling shader failed. VERTEX NULL! Shader source:\n\n%s", vert.c_str());
|
if (dynamic) {
|
||||||
|
if (vertCompiled == 0)
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
RASSERT(fragCompiled, "Compiling shader failed. FRAGMENT NULL! Shader source:\n\n%s", frag.c_str());
|
if (dynamic) {
|
||||||
|
if (fragCompiled == 0)
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
RASSERT(ok != GL_FALSE, "createProgram() failed! GL_LINK_STATUS not OK!");
|
if (dynamic) {
|
||||||
|
if (ok == GL_FALSE)
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
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);
|
||||||
RASSERT(ok != GL_FALSE, "compileShader() failed! GL_COMPILE_STATUS not OK!");
|
if (dynamic) {
|
||||||
|
if (ok == GL_FALSE)
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
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,18 +476,25 @@ 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);
|
||||||
|
|
||||||
switch (tex.m_iType) {
|
bool usingFinalShader = false;
|
||||||
case TEXTURE_RGBA:
|
|
||||||
shader = &m_RenderData.pCurrentMonData->m_shRGBA;
|
if (m_bApplyFinalShader && m_sFinalScreenShader.program) {
|
||||||
break;
|
shader = &m_sFinalScreenShader;
|
||||||
case TEXTURE_RGBX:
|
usingFinalShader = true;
|
||||||
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
} else {
|
||||||
break;
|
switch (tex.m_iType) {
|
||||||
case TEXTURE_EXTERNAL:
|
case TEXTURE_RGBA:
|
||||||
shader = &m_RenderData.pCurrentMonData->m_shEXT;
|
shader = &m_RenderData.pCurrentMonData->m_shRGBA;
|
||||||
break;
|
break;
|
||||||
default:
|
case TEXTURE_RGBX:
|
||||||
RASSERT(false, "tex.m_iTarget unsupported!");
|
shader = &m_RenderData.pCurrentMonData->m_shRGBX;
|
||||||
|
break;
|
||||||
|
case TEXTURE_EXTERNAL:
|
||||||
|
shader = &m_RenderData.pCurrentMonData->m_shEXT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RASSERT(false, "tex.m_iTarget unsupported!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
@ -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);
|
||||||
glUniform1f(shader->alpha, alpha / 255.f);
|
if (!usingFinalShader) {
|
||||||
glUniform1i(shader->discardOpaque, (int)discardOpaque);
|
glUniform1f(shader->alpha, alpha / 255.f);
|
||||||
|
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,18 +524,20 @@ 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;
|
||||||
|
|
||||||
// Rounded corners
|
if (!usingFinalShader) {
|
||||||
glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
|
// Rounded corners
|
||||||
glUniform2f(shader->fullSize, FULLSIZE.x ,FULLSIZE.y);
|
glUniform2f(shader->topLeft, TOPLEFT.x, TOPLEFT.y);
|
||||||
glUniform1f(shader->radius, round);
|
glUniform2f(shader->fullSize, FULLSIZE.x, FULLSIZE.y);
|
||||||
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
|
glUniform1f(shader->radius, round);
|
||||||
|
glUniform1i(shader->primitiveMultisample, (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA));
|
||||||
|
|
||||||
if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
|
if (allowDim && m_pCurrentWindow && *PDIMINACTIVE && m_pCurrentWindow != g_pCompositor->m_pLastWindow) {
|
||||||
glUniform1i(shader->applyTint, 1);
|
glUniform1i(shader->applyTint, 1);
|
||||||
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
|
const auto DIM = m_pCurrentWindow->m_fDimPercent.fl();
|
||||||
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
|
glUniform3f(shader->tint, 1.f - DIM, 1.f - DIM, 1.f - DIM);
|
||||||
} else {
|
} else {
|
||||||
glUniform1i(shader->applyTint, 0);
|
glUniform1i(shader->applyTint, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const float verts[] = {
|
const float verts[] = {
|
||||||
|
@ -504,13 +571,13 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pixman_region32_fini(&damageClip);
|
pixman_region32_fini(&damageClip);
|
||||||
} else {
|
} else {
|
||||||
PIXMAN_DAMAGE_FOREACH(damage) {
|
PIXMAN_DAMAGE_FOREACH(damage) {
|
||||||
const auto RECT = RECTSARR[i];
|
const auto RECT = RECTSARR[i];
|
||||||
scissor(&RECT);
|
scissor(&RECT);
|
||||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisableVertexAttribArray(shader->posAttrib);
|
glDisableVertexAttribArray(shader->posAttrib);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
|
@ -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;
|
||||||
};
|
};
|
Loading…
Reference in a new issue