Switched old blur to dual kawase

This commit is contained in:
vaxerski 2022-04-24 16:41:01 +02:00
parent 3b3718df3d
commit e5f8bca41c
3 changed files with 93 additions and 139 deletions

View file

@ -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;

View file

@ -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) {

View file

@ -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"#(