mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 11:25:59 +01:00
Switched old blur to dual kawase
This commit is contained in:
parent
3b3718df3d
commit
e5f8bca41c
3 changed files with 93 additions and 139 deletions
|
@ -187,14 +187,14 @@ void Events::listener_unmapWindow(void* owner, void* data) {
|
||||||
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
PWINDOW->hyprListener_setTitleWindow.removeCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow the renderer to catch the last frame.
|
||||||
|
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
|
||||||
|
|
||||||
if (PWINDOW == g_pCompositor->m_pLastWindow) {
|
if (PWINDOW == g_pCompositor->m_pLastWindow) {
|
||||||
g_pCompositor->m_pLastWindow = nullptr;
|
g_pCompositor->m_pLastWindow = nullptr;
|
||||||
g_pCompositor->m_pLastFocus = nullptr;
|
g_pCompositor->m_pLastFocus = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow the renderer to catch the last frame.
|
|
||||||
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
|
|
||||||
|
|
||||||
PWINDOW->m_fAlpha = 0.f;
|
PWINDOW->m_fAlpha = 0.f;
|
||||||
|
|
||||||
PWINDOW->m_bMappedX11 = false;
|
PWINDOW->m_bMappedX11 = false;
|
||||||
|
|
|
@ -340,70 +340,30 @@ void CHyprOpenGLImpl::renderTextureInternal(const CTexture& tex, wlr_box* pBox,
|
||||||
glBindTexture(tex.m_iTarget, 0);
|
glBindTexture(tex.m_iTarget, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This probably isn't the fastest
|
||||||
|
// but it works... well, I guess?
|
||||||
|
//
|
||||||
|
// Dual (or more) kawase blur
|
||||||
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, int round) {
|
void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, int round) {
|
||||||
RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!");
|
RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!");
|
||||||
|
|
||||||
// TODO: optimize this, this is bad
|
|
||||||
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
|
|
||||||
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
|
|
||||||
const auto RECT = RECTSARR[i];
|
|
||||||
scissor(&RECT);
|
|
||||||
|
|
||||||
renderTextureWithBlurInternal(tex, pBox, a, round);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
scissor((wlr_box*)nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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::renderTextureWithBlurInternal(const CTexture& tex, wlr_box* pBox, 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) {
|
if (g_pConfigManager->getInt("decoration:blur") == 0) {
|
||||||
renderTextureInternal(tex, pBox, a, round);
|
renderTexture(tex, pBox, a, round);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get transform
|
// TODO: only blur selected regions when damaged
|
||||||
|
// blur region + pad (blur size)
|
||||||
|
|
||||||
|
// basics
|
||||||
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
|
const auto TRANSFORM = wlr_output_transform_invert(WL_OUTPUT_TRANSFORM_NORMAL);
|
||||||
float matrix[9];
|
float matrix[9];
|
||||||
wlr_matrix_project_box(matrix, pBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
|
wlr_matrix_project_box(matrix, pBox, TRANSFORM, 0, m_RenderData.pMonitor->output->transform_matrix);
|
||||||
|
|
||||||
// bind the mirror FB and clear it.
|
// blur the primary FB into the mirrored one
|
||||||
m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.bind();
|
m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.bind();
|
||||||
clear(CColor(0, 0, 0, 0));
|
clear(CColor(0, 0, 0, 0));
|
||||||
|
|
||||||
// init stencil for blurring only behind da window
|
|
||||||
glClearStencil(0);
|
|
||||||
glClear(GL_STENCIL_BUFFER_BIT);
|
|
||||||
|
|
||||||
glEnable(GL_STENCIL_TEST);
|
|
||||||
|
|
||||||
glStencilFunc(GL_ALWAYS, 1, -1);
|
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
|
||||||
|
|
||||||
// render our window to the mirror FB while also writing to the stencil, discard opaque pixels
|
|
||||||
renderTextureInternal(tex, pBox, a, round, true);
|
|
||||||
|
|
||||||
// then we disable writing to the mask and ONLY accept writing within the stencil
|
|
||||||
glStencilFunc(GL_EQUAL, 1, -1);
|
|
||||||
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
|
||||||
|
|
||||||
// now we bind back the primary FB
|
|
||||||
// the mirror FB now has only our window.
|
|
||||||
m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.bind();
|
|
||||||
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
|
|
||||||
// now we make the blur by blurring the main framebuffer (it will only affect the stencil)
|
|
||||||
|
|
||||||
// matrix
|
// matrix
|
||||||
float matrixFull[9];
|
float matrixFull[9];
|
||||||
wlr_box fullMonBox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
|
wlr_box fullMonBox = {0, 0, m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y};
|
||||||
|
@ -415,23 +375,21 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(const CTexture& tex, wlr_box
|
||||||
|
|
||||||
wlr_matrix_transpose(glMatrix, glMatrix);
|
wlr_matrix_transpose(glMatrix, glMatrix);
|
||||||
|
|
||||||
const auto RADIUS = g_pConfigManager->getInt("decoration:blur_size") + 2;
|
const auto BLURSIZE = g_pConfigManager->getInt("decoration:blur_size");
|
||||||
const auto BLURPASSES = g_pConfigManager->getInt("decoration:blur_passes");
|
const auto BLURPASSES = g_pConfigManager->getInt("decoration:blur_passes");
|
||||||
const auto PFRAMEBUFFER = &m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB;
|
|
||||||
|
|
||||||
auto drawWithShader = [&](CShader* pShader) {
|
auto drawWithShader = [&](CShader* pShader, Vector2D halfpixel) {
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(PFRAMEBUFFER->m_cTex.m_iTarget, PFRAMEBUFFER->m_cTex.m_iTexID);
|
|
||||||
|
|
||||||
glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(tex.m_iTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
glUseProgram(pShader->program);
|
glUseProgram(pShader->program);
|
||||||
|
|
||||||
glUniform1f(glGetUniformLocation(pShader->program, "radius"), RADIUS);
|
// glUniform2f(glGetUniformLocation(pShader->program, "resolution"), m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y);
|
||||||
glUniform2f(glGetUniformLocation(pShader->program, "resolution"), m_RenderData.pMonitor->vecSize.x, m_RenderData.pMonitor->vecSize.y);
|
|
||||||
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
|
glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix);
|
||||||
glUniform1i(pShader->tex, 0);
|
glUniform1i(pShader->tex, 0);
|
||||||
glUniform1f(pShader->alpha, a / 255.f);
|
glUniform1f(glGetUniformLocation(pShader->program, "radius"), BLURSIZE * (a / 255.f) /* nice effect: less blur when less a */);
|
||||||
|
glUniform2f(glGetUniformLocation(pShader->program, "halfpixel"), halfpixel.x, halfpixel.y);
|
||||||
|
|
||||||
glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||||
glVertexAttribPointer(pShader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
glVertexAttribPointer(pShader->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||||
|
@ -445,20 +403,73 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(const CTexture& tex, wlr_box
|
||||||
glDisableVertexAttribArray(pShader->texAttrib);
|
glDisableVertexAttribArray(pShader->texAttrib);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < BLURPASSES; ++i) {
|
int sampleW = 0, sampleH = 0;
|
||||||
drawWithShader(&m_shBLUR1); // horizontal pass
|
|
||||||
drawWithShader(&m_shBLUR2); // vertical pass
|
glBindTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex.m_iTarget, m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex.m_iTexID);
|
||||||
|
|
||||||
|
sampleW = m_RenderData.pMonitor->vecSize.x / 2.f;
|
||||||
|
sampleH = m_RenderData.pMonitor->vecSize.y / 2.f;
|
||||||
|
|
||||||
|
drawWithShader(&m_shBLUR1, Vector2D(0.5f / sampleW, 0.5f / sampleH)); // down
|
||||||
|
|
||||||
|
glBindTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.m_cTex.m_iTarget, m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.m_cTex.m_iTexID);
|
||||||
|
|
||||||
|
for (int i = 1; i < BLURPASSES; ++i) {
|
||||||
|
drawWithShader(&m_shBLUR1, Vector2D(0.5f / sampleW, 0.5f / sampleH)); // down
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleW = m_RenderData.pMonitor->vecSize.x * 2.f;
|
||||||
|
sampleH = m_RenderData.pMonitor->vecSize.y * 2.f;
|
||||||
|
|
||||||
|
for (int i = BLURPASSES - 1; i >= 0; --i) {
|
||||||
|
drawWithShader(&m_shBLUR2, Vector2D(0.5f / sampleW, 0.5f / sampleH)); // up
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindTexture(tex.m_iTarget, 0);
|
glBindTexture(tex.m_iTarget, 0);
|
||||||
|
|
||||||
|
// ok, now we can make a stencil for our window to affect the draw of the copy
|
||||||
|
glClearStencil(0);
|
||||||
|
glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
glStencilFunc(GL_ALWAYS, 1, -1);
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
|
|
||||||
|
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
|
||||||
|
renderTextureInternal(tex, pBox, a, round, true); // discard opaque
|
||||||
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||||
|
|
||||||
|
glStencilFunc(GL_EQUAL, 1, -1);
|
||||||
|
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
|
||||||
|
|
||||||
|
// Now we have a stencil and we need to scissor the updated regions
|
||||||
|
|
||||||
|
// bind the primary fb again for final drawing
|
||||||
|
m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.bind();
|
||||||
|
if (pixman_region32_not_empty(m_RenderData.pDamage)) {
|
||||||
|
PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) {
|
||||||
|
const auto RECT = RECTSARR[i];
|
||||||
|
scissor(&RECT);
|
||||||
|
|
||||||
|
// render our great blurred FB
|
||||||
|
renderTextureInternal(m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB.m_cTex, &fullMonBox, 255.f); // 255.f because we adjusted blur strength to a
|
||||||
|
|
||||||
|
// render the window, but disable stencil for it
|
||||||
|
// because stencil has ignoreopaque
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
renderTextureInternal(tex, pBox, a, round);
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// disable the stencil
|
// disable the stencil
|
||||||
glStencilMask(-1);
|
glStencilMask(-1);
|
||||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||||
glDisable(GL_STENCIL_TEST);
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
// when the blur is done, let's render the window itself. We can't use mirror because it had discardOpaque
|
scissor((wlr_box*)nullptr);
|
||||||
renderTextureInternal(tex, pBox, a, round);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
|
|
@ -164,46 +164,16 @@ uniform sampler2D tex;
|
||||||
|
|
||||||
uniform float radius;
|
uniform float radius;
|
||||||
uniform vec2 resolution;
|
uniform vec2 resolution;
|
||||||
uniform float alpha;
|
uniform vec2 halfpixel;
|
||||||
|
|
||||||
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() {
|
void main() {
|
||||||
gl_FragColor = BlurH(resolution, v_texcoord) * alpha;
|
vec4 sum = texture2D(tex, v_texcoord) * 4.0;
|
||||||
|
sum += texture2D(tex, v_texcoord - halfpixel.xy * radius);
|
||||||
|
sum += texture2D(tex, v_texcoord + halfpixel.xy * radius);
|
||||||
|
sum += texture2D(tex, v_texcoord + vec2(halfpixel.x, -halfpixel.y) * radius);
|
||||||
|
sum += texture2D(tex, v_texcoord - vec2(halfpixel.x, -halfpixel.y) * radius);
|
||||||
|
gl_FragColor = sum / 8.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
)#";
|
)#";
|
||||||
|
|
||||||
inline const std::string FRAGBLUR2 = R"#(
|
inline const std::string FRAGBLUR2 = R"#(
|
||||||
|
@ -213,46 +183,19 @@ uniform sampler2D tex;
|
||||||
|
|
||||||
uniform float radius;
|
uniform float radius;
|
||||||
uniform vec2 resolution;
|
uniform vec2 resolution;
|
||||||
uniform float alpha;
|
uniform vec2 halfpixel;
|
||||||
|
|
||||||
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() {
|
void main() {
|
||||||
gl_FragColor = BlurV(resolution, v_texcoord) * alpha;
|
vec4 sum = texture2D(tex, v_texcoord + vec2(-halfpixel.x * 2.0, 0.0) * radius);
|
||||||
|
sum += texture2D(tex, v_texcoord + vec2(-halfpixel.x, halfpixel.y) * radius) * 2.0;
|
||||||
|
sum += texture2D(tex, v_texcoord + vec2(0.0, halfpixel.y * 2.0) * radius);
|
||||||
|
sum += texture2D(tex, v_texcoord + vec2(halfpixel.x, halfpixel.y) * radius) * 2.0;
|
||||||
|
sum += texture2D(tex, v_texcoord + vec2(halfpixel.x * 2.0, 0.0) * radius);
|
||||||
|
sum += texture2D(tex, v_texcoord + vec2(halfpixel.x, -halfpixel.y) * radius) * 2.0;
|
||||||
|
sum += texture2D(tex, v_texcoord + vec2(0.0, -halfpixel.y * 2.0) * radius);
|
||||||
|
sum += texture2D(tex, v_texcoord + vec2(-halfpixel.x, -halfpixel.y) * radius) * 2.0;
|
||||||
|
gl_FragColor = sum / 12.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
)#";
|
)#";
|
||||||
|
|
||||||
inline const std::string TEXFRAGSRCEXT = R"#(
|
inline const std::string TEXFRAGSRCEXT = R"#(
|
||||||
|
|
Loading…
Reference in a new issue