mirror of
https://github.com/hyprwm/Hyprland
synced 2024-12-23 00:09:49 +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();
|
||||
}
|
||||
|
||||
// Allow the renderer to catch the last frame.
|
||||
g_pHyprOpenGL->makeWindowSnapshot(PWINDOW);
|
||||
|
||||
if (PWINDOW == g_pCompositor->m_pLastWindow) {
|
||||
g_pCompositor->m_pLastWindow = 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_bMappedX11 = false;
|
||||
|
|
|
@ -340,70 +340,30 @@ void CHyprOpenGLImpl::renderTextureInternal(const CTexture& tex, wlr_box* pBox,
|
|||
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) {
|
||||
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) {
|
||||
renderTextureInternal(tex, pBox, a, round);
|
||||
renderTexture(tex, pBox, a, round);
|
||||
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);
|
||||
float matrix[9];
|
||||
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();
|
||||
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
|
||||
float matrixFull[9];
|
||||
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);
|
||||
|
||||
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 PFRAMEBUFFER = &m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB;
|
||||
|
||||
auto drawWithShader = [&](CShader* pShader) {
|
||||
auto drawWithShader = [&](CShader* pShader, Vector2D halfpixel) {
|
||||
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);
|
||||
// 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);
|
||||
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->texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts);
|
||||
|
@ -445,20 +403,73 @@ void CHyprOpenGLImpl::renderTextureWithBlurInternal(const CTexture& tex, wlr_box
|
|||
glDisableVertexAttribArray(pShader->texAttrib);
|
||||
};
|
||||
|
||||
for (int i = 0; i < BLURPASSES; ++i) {
|
||||
drawWithShader(&m_shBLUR1); // horizontal pass
|
||||
drawWithShader(&m_shBLUR2); // vertical pass
|
||||
int sampleW = 0, sampleH = 0;
|
||||
|
||||
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);
|
||||
|
||||
// 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
|
||||
glStencilMask(-1);
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
// when the blur is done, let's render the window itself. We can't use mirror because it had discardOpaque
|
||||
renderTextureInternal(tex, pBox, a, round);
|
||||
scissor((wlr_box*)nullptr);
|
||||
}
|
||||
|
||||
void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) {
|
||||
|
|
|
@ -164,46 +164,16 @@ 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);
|
||||
}
|
||||
|
||||
uniform vec2 halfpixel;
|
||||
|
||||
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"#(
|
||||
|
@ -213,46 +183,19 @@ 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);
|
||||
}
|
||||
|
||||
uniform vec2 halfpixel;
|
||||
|
||||
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"#(
|
||||
|
|
Loading…
Reference in a new issue