mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-07 15:05:58 +01:00
Added blurring 🎉
This commit is contained in:
parent
b7094200f6
commit
969bebbd06
7 changed files with 221 additions and 3 deletions
|
@ -26,6 +26,7 @@ Nevertheless, REPORT any you find! Make an issue!
|
||||||
- Config reloaded instantly upon saving
|
- Config reloaded instantly upon saving
|
||||||
- Easily expandable and readable codebase
|
- Easily expandable and readable codebase
|
||||||
- Rounded corners
|
- Rounded corners
|
||||||
|
- Window blur
|
||||||
- Fade in/out
|
- Fade in/out
|
||||||
- Support for docks/whatever
|
- Support for docks/whatever
|
||||||
- Window rules
|
- Window rules
|
||||||
|
@ -38,7 +39,6 @@ Nevertheless, REPORT any you find! Make an issue!
|
||||||
- Damage tracking
|
- Damage tracking
|
||||||
- Animations (better)
|
- Animations (better)
|
||||||
- Fix GDK popups on multimon
|
- Fix GDK popups on multimon
|
||||||
- Blur
|
|
||||||
- Fix electron rendering issues
|
- Fix electron rendering issues
|
||||||
- Optimization
|
- Optimization
|
||||||
- Fix weird scroll on XWayland
|
- Fix weird scroll on XWayland
|
||||||
|
|
|
@ -28,6 +28,8 @@ general {
|
||||||
|
|
||||||
decoration {
|
decoration {
|
||||||
rounding=10
|
rounding=10
|
||||||
|
blur=1
|
||||||
|
blur_size=8 # minimum 2
|
||||||
}
|
}
|
||||||
|
|
||||||
animations {
|
animations {
|
||||||
|
|
|
@ -23,6 +23,8 @@ CConfigManager::CConfigManager() {
|
||||||
configValues["general:col.inactive_border"].intValue = 0xff444444;
|
configValues["general:col.inactive_border"].intValue = 0xff444444;
|
||||||
|
|
||||||
configValues["decoration:rounding"].intValue = 1;
|
configValues["decoration:rounding"].intValue = 1;
|
||||||
|
configValues["decoration:blur"].intValue = 1;
|
||||||
|
configValues["decoration:blur_size"].intValue = 8;
|
||||||
|
|
||||||
configValues["dwindle:pseudotile"].intValue = 0;
|
configValues["dwindle:pseudotile"].intValue = 0;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,22 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() {
|
||||||
m_shEXT.posAttrib = glGetAttribLocation(prog, "pos");
|
m_shEXT.posAttrib = glGetAttribLocation(prog, "pos");
|
||||||
m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord");
|
m_shEXT.texAttrib = glGetAttribLocation(prog, "texcoord");
|
||||||
|
|
||||||
|
prog = createProgram(TEXVERTSRC, FRAGBLUR1);
|
||||||
|
m_shBLUR1.program = prog;
|
||||||
|
m_shBLUR1.tex = glGetUniformLocation(prog, "tex");
|
||||||
|
m_shBLUR1.alpha = glGetUniformLocation(prog, "alpha");
|
||||||
|
m_shBLUR1.proj = glGetUniformLocation(prog, "proj");
|
||||||
|
m_shBLUR1.posAttrib = glGetAttribLocation(prog, "pos");
|
||||||
|
m_shBLUR1.texAttrib = glGetAttribLocation(prog, "texcoord");
|
||||||
|
|
||||||
|
prog = createProgram(TEXVERTSRC, FRAGBLUR2);
|
||||||
|
m_shBLUR2.program = prog;
|
||||||
|
m_shBLUR2.tex = glGetUniformLocation(prog, "tex");
|
||||||
|
m_shBLUR2.alpha = glGetUniformLocation(prog, "alpha");
|
||||||
|
m_shBLUR2.proj = glGetUniformLocation(prog, "proj");
|
||||||
|
m_shBLUR2.posAttrib = glGetAttribLocation(prog, "pos");
|
||||||
|
m_shBLUR2.texAttrib = glGetAttribLocation(prog, "texcoord");
|
||||||
|
|
||||||
Debug::log(LOG, "Shaders initialized successfully.");
|
Debug::log(LOG, "Shaders initialized successfully.");
|
||||||
|
|
||||||
// End shaders
|
// End shaders
|
||||||
|
@ -259,6 +275,97 @@ void CHyprOpenGLImpl::renderTexture(const CTexture& tex, float matrix[9], float
|
||||||
glBindTexture(tex.m_iTarget, 0);
|
glBindTexture(tex.m_iTarget, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is probably not the quickest method possible,
|
||||||
|
// feel free to contribute if you have a better method.
|
||||||
|
// cheers.
|
||||||
|
|
||||||
|
// 2-pass pseudo-gaussian blur
|
||||||
|
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, float matrix[9], float a, int round) {
|
||||||
|
RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!");
|
||||||
|
RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!");
|
||||||
|
|
||||||
|
// if blur disabled, just render the texture
|
||||||
|
if (g_pConfigManager->getInt("decoration:blur") == 0) {
|
||||||
|
renderTexture(tex, matrix, a, round);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a stencil for our thang
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
|
|
||||||
|
// we clear the stencil and then draw our texture with GL_ALWAYS to make a stencil mask.
|
||||||
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
glStencilMask(0xFF);
|
||||||
|
|
||||||
|
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||||
|
|
||||||
|
renderTexture(tex, matrix, 0, round); // 0 alpha because we dont want to draw to the FB
|
||||||
|
|
||||||
|
// then we disable writing to the mask and ONLY accept writing within the stencil
|
||||||
|
glStencilMask(0x00);
|
||||||
|
glStencilFunc(GL_EQUAL, 1, 0xFF);
|
||||||
|
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
|
||||||
|
// now we make the blur by blurring the main framebuffer (it will only affect the stencil)
|
||||||
|
|
||||||
|
// matrix
|
||||||
|
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
|
||||||
|
float matrixFull[9];
|
||||||
|
wlr_box fullMonBox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
|
||||||
|
wlr_matrix_project_box(matrixFull, &fullMonBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
|
||||||
|
|
||||||
|
float glMatrix[9];
|
||||||
|
wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrixFull);
|
||||||
|
wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix);
|
||||||
|
|
||||||
|
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||||
|
|
||||||
|
const auto RADIUS = g_pConfigManager->getInt("decoration:blur_size") + 2;
|
||||||
|
const auto PFRAMEBUFFER = &m_mMonitorFramebuffers[m_RenderData.pMonitor];
|
||||||
|
|
||||||
|
auto drawWithShader = [=](CShader* pShader) {
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(PFRAMEBUFFER->m_cTex.m_iTarget, PFRAMEBUFFER->m_cTex.m_iTexID);
|
||||||
|
|
||||||
|
glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glUseProgram(pShader->program);
|
||||||
|
|
||||||
|
glUniform1f(glGetUniformLocation(pShader->program, "radius"), RADIUS);
|
||||||
|
glUniform2f(glGetUniformLocation(pShader->program, "resolution"), m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y);
|
||||||
|
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
|
||||||
|
glUniform1i(pShader->tex, 0);
|
||||||
|
glUniform1f(pShader->alpha, a / 255.f);
|
||||||
|
|
||||||
|
glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||||
|
glVertexAttribPointer(pShader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(pShader->posAttrib);
|
||||||
|
glEnableVertexAttribArray(pShader->texAttrib);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(pShader->posAttrib);
|
||||||
|
glDisableVertexAttribArray(pShader->texAttrib);
|
||||||
|
};
|
||||||
|
|
||||||
|
drawWithShader(&m_shBLUR1); // horizontal pass
|
||||||
|
drawWithShader(&m_shBLUR2); // vertical pass
|
||||||
|
|
||||||
|
glBindTexture(tex.m_iTarget, 0);
|
||||||
|
|
||||||
|
// when the blur is done, let's render the window itself
|
||||||
|
renderTexture(tex, matrix, a, round);
|
||||||
|
|
||||||
|
// and disable the stencil
|
||||||
|
glStencilMask(0xFF);
|
||||||
|
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
}
|
||||||
|
|
||||||
void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) {
|
void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) {
|
||||||
// 0-1 space god damnit
|
// 0-1 space god damnit
|
||||||
arr[counter * 2 + 0] = x / box->width;
|
arr[counter * 2 + 0] = x / box->width;
|
||||||
|
|
|
@ -40,6 +40,7 @@ public:
|
||||||
void renderRect(wlr_box*, const CColor&);
|
void renderRect(wlr_box*, const CColor&);
|
||||||
void renderTexture(wlr_texture*, float matrix[9], float a, int round = 0);
|
void renderTexture(wlr_texture*, float matrix[9], float a, int round = 0);
|
||||||
void renderTexture(const CTexture&, float matrix[9], float a, int round = 0);
|
void renderTexture(const CTexture&, float matrix[9], float a, int round = 0);
|
||||||
|
void renderTextureWithBlur(const CTexture&, float matrix[9], float a, int round = 0);
|
||||||
void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0);
|
void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0);
|
||||||
|
|
||||||
void makeWindowSnapshot(CWindow*);
|
void makeWindowSnapshot(CWindow*);
|
||||||
|
@ -68,6 +69,8 @@ private:
|
||||||
CShader m_shRGBA;
|
CShader m_shRGBA;
|
||||||
CShader m_shRGBX;
|
CShader m_shRGBX;
|
||||||
CShader m_shEXT;
|
CShader m_shEXT;
|
||||||
|
CShader m_shBLUR1;
|
||||||
|
CShader m_shBLUR2;
|
||||||
//
|
//
|
||||||
|
|
||||||
GLuint createProgram(const std::string&, const std::string&);
|
GLuint createProgram(const std::string&, const std::string&);
|
||||||
|
|
|
@ -31,7 +31,10 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||||
float matrix[9];
|
float matrix[9];
|
||||||
wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, RDATA->output->transform_matrix);
|
wlr_matrix_project_box(matrix, &windowBox, TRANSFORM, 0, RDATA->output->transform_matrix);
|
||||||
|
|
||||||
g_pHyprOpenGL->renderTexture(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding")); // TODO: fadeinout
|
if (RDATA->surface && surface == RDATA->surface)
|
||||||
|
g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));
|
||||||
|
else
|
||||||
|
g_pHyprOpenGL->renderTexture(TEXTURE, matrix, RDATA->fadeAlpha, RDATA->dontRound ? 0 : g_pConfigManager->getInt("decoration:rounding"));
|
||||||
|
|
||||||
wlr_surface_send_frame_done(surface, RDATA->when);
|
wlr_surface_send_frame_done(surface, RDATA->when);
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,107 @@ void main() {
|
||||||
gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;
|
gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;
|
||||||
})#";
|
})#";
|
||||||
|
|
||||||
|
// thanks to Loadus
|
||||||
|
// https://www.shadertoy.com/view/Mtl3Rj
|
||||||
|
// for this pseudo-gaussian blur!
|
||||||
|
inline const std::string FRAGBLUR1 = R"#(
|
||||||
|
precision mediump float;
|
||||||
|
varying vec2 v_texcoord; // is in 0-1
|
||||||
|
uniform sampler2D tex;
|
||||||
|
|
||||||
|
uniform float radius;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
uniform float alpha;
|
||||||
|
|
||||||
|
float SCurve (float x) {
|
||||||
|
x = x * 2.0 - 1.0;
|
||||||
|
return -x * abs(x) * 0.5 + x + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 BlurH (vec2 size, vec2 uv) {
|
||||||
|
if (radius >= 1.0) {
|
||||||
|
vec4 A = vec4(0.0);
|
||||||
|
vec4 C = vec4(0.0);
|
||||||
|
|
||||||
|
float width = 1.0 / size.x;
|
||||||
|
|
||||||
|
float divisor = 0.0;
|
||||||
|
float weight = 0.0;
|
||||||
|
|
||||||
|
float radiusMultiplier = 1.0 / radius;
|
||||||
|
|
||||||
|
for (float x = -radius; x <= radius; x++) {
|
||||||
|
A = texture2D(tex, uv + vec2(x * width, 0.0));
|
||||||
|
|
||||||
|
weight = SCurve(1.0 - (abs(x) * radiusMultiplier));
|
||||||
|
|
||||||
|
C += A * weight;
|
||||||
|
|
||||||
|
divisor += weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec4(C.r / divisor, C.g / divisor, C.b / divisor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture2D(tex, uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = BlurH(resolution, v_texcoord) * alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
)#";
|
||||||
|
|
||||||
|
inline const std::string FRAGBLUR2 = R"#(
|
||||||
|
precision mediump float;
|
||||||
|
varying vec2 v_texcoord; // is in 0-1
|
||||||
|
uniform sampler2D tex;
|
||||||
|
|
||||||
|
uniform float radius;
|
||||||
|
uniform vec2 resolution;
|
||||||
|
uniform float alpha;
|
||||||
|
|
||||||
|
float SCurve (float x) {
|
||||||
|
x = x * 2.0 - 1.0;
|
||||||
|
return -x * abs(x) * 0.5 + x + 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 BlurV (vec2 size, vec2 uv) {
|
||||||
|
if (radius >= 1.0) {
|
||||||
|
vec4 A = vec4(0.0);
|
||||||
|
vec4 C = vec4(0.0);
|
||||||
|
|
||||||
|
float height = 1.0 / size.y;
|
||||||
|
|
||||||
|
float divisor = 0.0;
|
||||||
|
float weight = 0.0;
|
||||||
|
|
||||||
|
float radiusMultiplier = 1.0 / radius;
|
||||||
|
|
||||||
|
for (float y = -radius; y <= radius; y++) {
|
||||||
|
A = texture2D(tex, uv + vec2(0.0, y * height));
|
||||||
|
|
||||||
|
weight = SCurve(1.0 - (abs(y) * radiusMultiplier));
|
||||||
|
|
||||||
|
C += A * weight;
|
||||||
|
|
||||||
|
divisor += weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vec4(C.r / divisor, C.g / divisor, C.b / divisor, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return texture2D(tex, uv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_FragColor = BlurV(resolution, v_texcoord) * alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
)#";
|
||||||
|
|
||||||
inline const std::string TEXFRAGSRCEXT = R"#(
|
inline const std::string TEXFRAGSRCEXT = R"#(
|
||||||
#extension GL_OES_EGL_image_external : require
|
#extension GL_OES_EGL_image_external : require
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue