diff options
| author | xDarksome <dev@darkso.me> | 2022-07-02 19:43:52 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-07-02 19:43:52 +0300 |
| commit | 185c4d6ea13ad5f4483aa2e389e43bd09106002f (patch) | |
| tree | a7bc4a9510c39e367317b5ce64d2ee0e0a72d4f0 /src/render | |
| parent | fc4b10d13c14c4eb08febb0637f27177cb6a1940 (diff) | |
| parent | b7b3344188e3ebd2baed14bc288ee42a1ae8d6f2 (diff) | |
Merge branch 'hyprwm:main' into main
Diffstat (limited to 'src/render')
| -rw-r--r-- | src/render/OpenGL.cpp | 239 | ||||
| -rw-r--r-- | src/render/OpenGL.hpp | 29 | ||||
| -rw-r--r-- | src/render/Renderer.cpp | 204 | ||||
| -rw-r--r-- | src/render/Renderer.hpp | 2 | ||||
| -rw-r--r-- | src/render/Shader.cpp | 13 | ||||
| -rw-r--r-- | src/render/Shader.hpp | 15 | ||||
| -rw-r--r-- | src/render/Shaders.hpp | 3 | ||||
| -rw-r--r-- | src/render/decorations/CHyprDropShadowDecoration.cpp | 71 | ||||
| -rw-r--r-- | src/render/decorations/CHyprGroupBarDecoration.cpp | 8 | ||||
| -rw-r--r-- | src/render/decorations/IHyprWindowDecoration.hpp | 2 | ||||
| -rw-r--r-- | src/render/shaders/Border.hpp | 91 | ||||
| -rw-r--r-- | src/render/shaders/Shadow.hpp | 3 |
12 files changed, 425 insertions, 255 deletions
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index e44e108b..793901aa 100644 --- a/src/render/OpenGL.cpp +++ b/src/render/OpenGL.cpp @@ -81,6 +81,12 @@ CHyprOpenGLImpl::CHyprOpenGLImpl() { m_shSHADOW.posAttrib = glGetAttribLocation(prog, "pos"); m_shSHADOW.texAttrib = glGetAttribLocation(prog, "texcoord"); + prog = createProgram(QUADVERTSRC, FRAGBORDER1); + m_shBORDER1.program = prog; + m_shBORDER1.proj = glGetUniformLocation(prog, "proj"); + m_shBORDER1.posAttrib = glGetAttribLocation(prog, "pos"); + m_shBORDER1.texAttrib = glGetAttribLocation(prog, "texcoord"); + Debug::log(LOG, "Shaders initialized successfully."); // End shaders @@ -138,7 +144,9 @@ void CHyprOpenGLImpl::begin(SMonitor* pMonitor, pixman_region32_t* pDamage, bool glViewport(0, 0, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - wlr_matrix_projection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); // TODO: this is deprecated + matrixProjection(m_RenderData.projection, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y, WL_OUTPUT_TRANSFORM_NORMAL); + + m_RenderData.pCurrentMonData = &m_mMonitorRenderResources[pMonitor]; glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); @@ -146,22 +154,22 @@ void CHyprOpenGLImpl::begin(SMonitor* pMonitor, pixman_region32_t* pDamage, bool m_iWLROutputFb = m_iCurrentOutputFb; // ensure a framebuffer for the monitor exists - if (m_mMonitorRenderResources.find(pMonitor) == m_mMonitorRenderResources.end() || m_mMonitorRenderResources[pMonitor].primaryFB.m_Size != pMonitor->vecPixelSize) { - m_mMonitorRenderResources[pMonitor].stencilTex.allocate(); + if (m_mMonitorRenderResources.find(pMonitor) == m_mMonitorRenderResources.end() || m_RenderData.pCurrentMonData->primaryFB.m_Size != pMonitor->vecPixelSize) { + m_RenderData.pCurrentMonData->stencilTex.allocate(); - m_mMonitorRenderResources[pMonitor].primaryFB.m_pStencilTex = &m_mMonitorRenderResources[pMonitor].stencilTex; - m_mMonitorRenderResources[pMonitor].mirrorFB.m_pStencilTex = &m_mMonitorRenderResources[pMonitor].stencilTex; - m_mMonitorRenderResources[pMonitor].mirrorSwapFB.m_pStencilTex = &m_mMonitorRenderResources[pMonitor].stencilTex; + m_RenderData.pCurrentMonData->primaryFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; + m_RenderData.pCurrentMonData->mirrorSwapFB.m_pStencilTex = &m_RenderData.pCurrentMonData->stencilTex; - m_mMonitorRenderResources[pMonitor].primaryFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - m_mMonitorRenderResources[pMonitor].mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); - m_mMonitorRenderResources[pMonitor].mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + m_RenderData.pCurrentMonData->primaryFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + m_RenderData.pCurrentMonData->mirrorFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); + m_RenderData.pCurrentMonData->mirrorSwapFB.alloc(pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y); createBGTextureForMonitor(pMonitor); } // bind the primary Hypr Framebuffer - m_mMonitorRenderResources[pMonitor].primaryFB.bind(); + m_RenderData.pCurrentMonData->primaryFB.bind(); m_RenderData.pDamage = pDamage; @@ -180,7 +188,7 @@ void CHyprOpenGLImpl::end() { m_bEndFrame = true; - renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex, &monbox, 255.f, 0); + renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &monbox, 255.f, 0); m_bEndFrame = false; } @@ -277,11 +285,11 @@ void CHyprOpenGLImpl::renderRectWithDamage(wlr_box* box, const CColor& col, pixm static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; // Rounded corners - glUniform2f(glGetUniformLocation(m_shQUAD.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(glGetUniformLocation(m_shQUAD.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); - glUniform2f(glGetUniformLocation(m_shQUAD.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(glGetUniformLocation(m_shQUAD.program, "radius"), round); - glUniform1i(glGetUniformLocation(m_shQUAD.program, "primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0)); + glUniform2f(m_shQUAD.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shQUAD.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(m_shQUAD.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(m_shQUAD.getUniformLocation("radius"), round); + glUniform1i(m_shQUAD.getUniformLocation("primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0)); glVertexAttribPointer(m_shQUAD.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(m_shQUAD.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -309,15 +317,15 @@ void CHyprOpenGLImpl::renderTexture(wlr_texture* tex, wlr_box* pBox, float alpha renderTexture(CTexture(tex), pBox, alpha, round); } -void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool border, bool allowPrimary) { +void CHyprOpenGLImpl::renderTexture(const CTexture& tex, wlr_box* pBox, float alpha, int round, bool discardopaque, bool allowPrimary) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); - renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, border, false, allowPrimary); + renderTextureInternalWithDamage(tex, pBox, alpha, m_RenderData.pDamage, round, discardopaque, false, allowPrimary); scissor((wlr_box*)nullptr); } -void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool border, bool noAA, bool allowPrimary) { +void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_box* pBox, float alpha, pixman_region32_t* damage, int round, bool discardOpaque, bool noAA, bool allowPrimary) { RASSERT(m_RenderData.pMonitor, "Tried to render texture without begin()!"); RASSERT((tex.m_iTexID > 0), "Attempted to draw NULL texture!"); @@ -351,23 +359,6 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b RASSERT(false, "tex.m_iTarget unsupported!"); } - // stencil for when we want a border - if (border) { - glClearStencil(0); - glClear(GL_STENCIL_BUFFER_BIT); - - glEnable(GL_STENCIL_TEST); - - glStencilFunc(GL_ALWAYS, 1, -1); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - - // hacky fix to fix broken borders. - // TODO: this is kinda slow... question mark? - renderRect(pBox, CColor(0, 0, 0, 0), round); - - glDisable(GL_STENCIL_TEST); - } - glActiveTexture(GL_TEXTURE0); glBindTexture(tex.m_iTarget, tex.m_iTexID); @@ -389,11 +380,11 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b static auto *const PMULTISAMPLEEDGES = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; // Rounded corners - glUniform2f(glGetUniformLocation(shader->program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(glGetUniformLocation(shader->program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); - glUniform2f(glGetUniformLocation(shader->program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(glGetUniformLocation(shader->program, "radius"), round); - glUniform1i(glGetUniformLocation(shader->program, "primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !border && !noAA)); + glUniform2f(shader->getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(shader->getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(shader->getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(shader->getUniformLocation("radius"), round); + glUniform1i(shader->getUniformLocation("primitiveMultisample"), (int)(*PMULTISAMPLEEDGES == 1 && round != 0 && !noAA)); glVertexAttribPointer(shader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -421,30 +412,10 @@ void CHyprOpenGLImpl::renderTextureInternalWithDamage(const CTexture& tex, wlr_b } } - if (border) { - glEnable(GL_STENCIL_TEST); - - glStencilFunc(GL_EQUAL, 1, -1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } - glDisableVertexAttribArray(shader->posAttrib); glDisableVertexAttribArray(shader->texAttrib); glBindTexture(tex.m_iTarget, 0); - - // if border draw - // we dont disable stencil here if we havent touched it. - // some other func might be using it. - if (border) { - auto BORDERCOL = m_pCurrentWindow->m_cRealBorderColor.col(); - static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; - BORDERCOL.a *= alpha / 255.f; - renderBorder(pBox, BORDERCOL, *PBORDERSIZE, round); - glStencilMask(-1); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - glDisable(GL_STENCIL_TEST); - } } // This probably isn't the fastest @@ -478,10 +449,10 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p wlr_region_expand(&damage, &damage, pow(2, *PBLURPASSES) * *PBLURSIZE); // helper - const auto PMIRRORFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorFB; - const auto PMIRRORSWAPFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].mirrorSwapFB; + const auto PMIRRORFB = &m_RenderData.pCurrentMonData->mirrorFB; + const auto PMIRRORSWAPFB = &m_RenderData.pCurrentMonData->mirrorSwapFB; - CFramebuffer* currentRenderToFB = &m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB; + CFramebuffer* currentRenderToFB = &m_RenderData.pCurrentMonData->primaryFB; // declare the draw func auto drawPass = [&](CShader* pShader, pixman_region32_t* pDamage) { @@ -500,11 +471,11 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p // prep two shaders glUniformMatrix3fv(pShader->proj, 1, GL_FALSE, glMatrix); - glUniform1f(glGetUniformLocation(pShader->program, "radius"), *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a + glUniform1f(pShader->getUniformLocation("radius"), *PBLURSIZE * (a / 255.f)); // this makes the blursize change with a if (pShader == &m_shBLUR1) - glUniform2f(glGetUniformLocation(m_shBLUR1.program, "halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); + glUniform2f(m_shBLUR1.getUniformLocation("halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x / 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y / 2.f)); else - glUniform2f(glGetUniformLocation(m_shBLUR2.program, "halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f)); + glUniform2f(m_shBLUR2.getUniformLocation("halfpixel"), 0.5f / (m_RenderData.pMonitor->vecPixelSize.x * 2.f), 0.5f / (m_RenderData.pMonitor->vecPixelSize.y * 2.f)); glUniform1i(pShader->tex, 0); glVertexAttribPointer(pShader->posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); @@ -534,7 +505,7 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p // draw the things. // first draw is prim -> mirr PMIRRORFB->bind(); - glBindTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex.m_iTarget, m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex.m_iTexID); + glBindTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTarget, m_RenderData.pCurrentMonData->primaryFB.m_cTex.m_iTexID); // damage region will be scaled, make a temp pixman_region32_t tempDamage; @@ -566,14 +537,14 @@ CFramebuffer* CHyprOpenGLImpl::blurMainFramebufferWithDamage(float a, wlr_box* p return currentRenderToFB; } -void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round, bool border) { +void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, float a, wlr_surface* pSurface, int round) { RASSERT(m_RenderData.pMonitor, "Tried to render texture with blur without begin()!"); static auto *const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue; static auto* const PNOBLUROVERSIZED = &g_pConfigManager->getConfigValuePtr("decoration:no_blur_on_oversized")->intValue; if (*PBLURENABLED == 0 || (*PNOBLUROVERSIZED && m_RenderData.primarySurfaceUVTopLeft != Vector2D(-1, -1)) || (m_pCurrentWindow && m_pCurrentWindow->m_sAdditionalConfigData.forceNoBlur)) { - renderTexture(tex, pBox, a, round, false, border, true); + renderTexture(tex, pBox, a, round, false, true); return; } @@ -596,7 +567,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, } if (!pixman_region32_not_empty(&inverseOpaque)) { - renderTexture(tex, pBox, a, round, false, border); // reject blurring a fully opaque window + renderTexture(tex, pBox, a, round, false); // reject blurring a fully opaque window return; } @@ -606,7 +577,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, pixman_region32_fini(&inverseOpaque); // bind primary - m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.bind(); + m_RenderData.pCurrentMonData->primaryFB.bind(); // make a stencil for rounded corners to work with blur scissor((wlr_box*)nullptr); // allow the entire window and stencil to render @@ -630,7 +601,7 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, if (pixman_region32_not_empty(&damage)) { // render our great blurred FB static auto *const PBLURIGNOREOPACITY = &g_pConfigManager->getConfigValuePtr("decoration:blur_ignore_opacity")->intValue; - renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, false, true); + renderTextureInternalWithDamage(POUTFB->m_cTex, &MONITORBOX, *PBLURIGNOREOPACITY ? 255.f : a, &damage, 0, false, false, true); // render the window, but clear stencil glClearStencil(0); @@ -638,36 +609,11 @@ void CHyprOpenGLImpl::renderTextureWithBlur(const CTexture& tex, wlr_box* pBox, // draw window glDisable(GL_STENCIL_TEST); - renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true, true); - glEnable(GL_STENCIL_TEST); - - // prep stencil for border - glStencilFunc(GL_ALWAYS, 1, -1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - - if (border) { - // hacky fix to fix broken borders. - // TODO: this is kinda slow... question mark? - renderRectWithDamage(pBox, CColor(0,0,0,0), &damage, round); - } - - // then stop - glStencilFunc(GL_EQUAL, 1, -1); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + renderTextureInternalWithDamage(tex, pBox, a, &damage, round, false, false, true); } - // disable the stencil (if no border), finalize everything - if (!border) { - glStencilMask(-1); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - } else { - auto BORDERCOL = m_pCurrentWindow->m_cRealBorderColor.col(); - BORDERCOL.a *= a / 255.f; - static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; - renderBorder(pBox, BORDERCOL, *PBORDERSIZE, round); - } - - glDisable(GL_STENCIL_TEST); + glStencilMask(-1); + glStencilFunc(GL_ALWAYS, 1, 0xFF); pixman_region32_fini(&damage); scissor((wlr_box*)nullptr); } @@ -679,23 +625,67 @@ void pushVert2D(float x, float y, float* arr, int& counter, wlr_box* box) { counter++; } -void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int thick, int round) { +void CHyprOpenGLImpl::renderBorder(wlr_box* box, const CColor& col, int round) { RASSERT((box->width > 0 && box->height > 0), "Tried to render rect with width/height < 0!"); RASSERT(m_RenderData.pMonitor, "Tried to render rect without begin()!"); - // this method assumes a set stencil and scaled box - box->x -= thick; - box->y -= thick; - box->width += 2 * thick; - box->height += 2 * thick; + static auto *const PBORDERSIZE = &g_pConfigManager->getConfigValuePtr("general:border_size")->intValue; + static auto *const PMULTISAMPLE = &g_pConfigManager->getConfigValuePtr("decoration:multisample_edges")->intValue; - round += thick; // cuz yeah + // adjust box + box->x -= *PBORDERSIZE; + box->y -= *PBORDERSIZE; + box->width += 2 * *PBORDERSIZE; + box->height += 2 * *PBORDERSIZE; - // only draw on non-stencild. - glStencilFunc(GL_NOTEQUAL, 1, -1); + round += *PBORDERSIZE; - // draw a rounded rect - renderRect(box, col, round); + float matrix[9]; + wlr_matrix_project_box(matrix, box, wlr_output_transform_invert(!m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData.pMonitor->transform), 0, m_RenderData.pMonitor->output->transform_matrix); // TODO: write own, don't use WLR here + + float glMatrix[9]; + wlr_matrix_multiply(glMatrix, m_RenderData.projection, matrix); + wlr_matrix_multiply(glMatrix, matrixFlip180, glMatrix); + + wlr_matrix_transpose(glMatrix, glMatrix); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glUseProgram(m_shBORDER1.program); + + glUniformMatrix3fv(m_shBORDER1.proj, 1, GL_FALSE, glMatrix); + glUniform4f(m_shBORDER1.getUniformLocation("color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f); + + const auto TOPLEFT = Vector2D(round, round); + const auto BOTTOMRIGHT = Vector2D(box->width - round, box->height - round); + const auto FULLSIZE = Vector2D(box->width, box->height); + + glUniform2f(m_shBORDER1.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shBORDER1.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(m_shBORDER1.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(m_shBORDER1.getUniformLocation("radius"), round); + glUniform1f(m_shBORDER1.getUniformLocation("thick"), *PBORDERSIZE); + glUniform1i(m_shBORDER1.getUniformLocation("primitiveMultisample"), *PMULTISAMPLE); + + glVertexAttribPointer(m_shBORDER1.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + glVertexAttribPointer(m_shBORDER1.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); + + glEnableVertexAttribArray(m_shBORDER1.posAttrib); + glEnableVertexAttribArray(m_shBORDER1.texAttrib); + + if (pixman_region32_not_empty(m_RenderData.pDamage)) { + PIXMAN_DAMAGE_FOREACH(m_RenderData.pDamage) { + const auto RECT = RECTSARR[i]; + scissor(&RECT); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + } + } + + glDisableVertexAttribArray(m_shBORDER1.posAttrib); + glDisableVertexAttribArray(m_shBORDER1.texAttrib); + + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { @@ -744,7 +734,7 @@ void CHyprOpenGLImpl::makeWindowSnapshot(CWindow* pWindow) { clear(CColor(0, 0, 0, 0)); // JIC wlr_box fullMonBox = {0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y}; - renderTexture(m_mMonitorRenderResources[m_RenderData.pMonitor].primaryFB.m_cTex, &fullMonBox, 255.f, 0); + renderTexture(m_RenderData.pCurrentMonData->primaryFB.m_cTex, &fullMonBox, 255.f, 0); // restore original fb #ifndef GLES2 @@ -823,12 +813,13 @@ void CHyprOpenGLImpl::renderSnapshot(CWindow** pWindow) { wlr_box windowBox; // some mafs to figure out the correct box - Vector2D scaleXY = Vector2D((PWINDOW->m_vRealSize.vec().x / PWINDOW->m_vOriginalClosedSize.x), (PWINDOW->m_vRealSize.vec().y / PWINDOW->m_vOriginalClosedSize.y)); + // the originalClosedPos is relative to the monitor's pos + Vector2D scaleXY = Vector2D((PMONITOR->scale * PWINDOW->m_vRealSize.vec().x / (PWINDOW->m_vOriginalClosedSize.x * PMONITOR->scale)), (PMONITOR->scale * PWINDOW->m_vRealSize.vec().y / (PWINDOW->m_vOriginalClosedSize.y * PMONITOR->scale))); windowBox.width = PMONITOR->vecPixelSize.x * scaleXY.x; windowBox.height = PMONITOR->vecPixelSize.y * scaleXY.y; - windowBox.x = (PWINDOW->m_vRealPosition.vec().x - PMONITOR->vecPosition.x) - ((PWINDOW->m_vOriginalClosedPos.x - PMONITOR->vecPosition.x) * scaleXY.x); - windowBox.y = (PWINDOW->m_vRealPosition.vec().y - PMONITOR->vecPosition.y) - ((PWINDOW->m_vOriginalClosedPos.y - PMONITOR->vecPosition.y) * scaleXY.y); + windowBox.x = ((PWINDOW->m_vRealPosition.vec().x - PMONITOR->vecPosition.x) * PMONITOR->scale) - ((PWINDOW->m_vOriginalClosedPos.x * PMONITOR->scale) * scaleXY.x); + windowBox.y = ((PWINDOW->m_vRealPosition.vec().y - PMONITOR->vecPosition.y) * PMONITOR->scale) - ((PWINDOW->m_vOriginalClosedPos.y * PMONITOR->scale) * scaleXY.y); pixman_region32_t fakeDamage; pixman_region32_init_rect(&fakeDamage, 0, 0, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y); @@ -870,7 +861,6 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl static auto *const PSHADOWCOL = &g_pConfigManager->getConfigValuePtr("decoration:col.shadow")->intValue; static auto *const PSHADOWPOWER = &g_pConfigManager->getConfigValuePtr("decoration:shadow_render_power")->intValue; - static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; const auto SHADOWPOWER = std::clamp((int)*PSHADOWPOWER, 1, 4); @@ -891,20 +881,19 @@ void CHyprOpenGLImpl::renderRoundedShadow(wlr_box* box, int round, int range, fl glUseProgram(m_shSHADOW.program); glUniformMatrix3fv(m_shSHADOW.proj, 1, GL_FALSE, glMatrix); - glUniform4f(glGetUniformLocation(m_shSHADOW.program, "color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a); + glUniform4f(m_shSHADOW.getUniformLocation("color"), col.r / 255.f, col.g / 255.f, col.b / 255.f, col.a / 255.f * a); const auto TOPLEFT = Vector2D(range + round, range + round); const auto BOTTOMRIGHT = Vector2D(box->width - (range + round), box->height - (range + round)); const auto FULLSIZE = Vector2D(box->width, box->height); // Rounded corners - glUniform2f(glGetUniformLocation(m_shSHADOW.program, "topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); - glUniform2f(glGetUniformLocation(m_shSHADOW.program, "bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); - glUniform2f(glGetUniformLocation(m_shSHADOW.program, "fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); - glUniform1f(glGetUniformLocation(m_shSHADOW.program, "radius"), range + round); - glUniform1f(glGetUniformLocation(m_shSHADOW.program, "range"), range); - glUniform1f(glGetUniformLocation(m_shSHADOW.program, "shadowPower"), SHADOWPOWER); - glUniform1i(glGetUniformLocation(m_shSHADOW.program, "ignoreWindow"), *PSHADOWIGNOREWINDOW); + glUniform2f(m_shSHADOW.getUniformLocation("topLeft"), (float)TOPLEFT.x, (float)TOPLEFT.y); + glUniform2f(m_shSHADOW.getUniformLocation("bottomRight"), (float)BOTTOMRIGHT.x, (float)BOTTOMRIGHT.y); + glUniform2f(m_shSHADOW.getUniformLocation("fullSize"), (float)FULLSIZE.x, (float)FULLSIZE.y); + glUniform1f(m_shSHADOW.getUniformLocation("radius"), range + round); + glUniform1f(m_shSHADOW.getUniformLocation("range"), range); + glUniform1f(m_shSHADOW.getUniformLocation("shadowPower"), SHADOWPOWER); glVertexAttribPointer(m_shSHADOW.posAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); glVertexAttribPointer(m_shSHADOW.texAttrib, 2, GL_FLOAT, GL_FALSE, 0, fullVerts); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 9d6e098d..292eba36 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -29,10 +29,20 @@ inline const float fanVertsFull[] = { -1.0f, 1.0f }; +struct SMonitorRenderData { + CFramebuffer primaryFB; + CFramebuffer mirrorFB; + CFramebuffer mirrorSwapFB; + + CTexture stencilTex; +}; + struct SCurrentRenderData { SMonitor* pMonitor = nullptr; float projection[9]; + SMonitorRenderData* pCurrentMonData = nullptr; + pixman_region32_t* pDamage = nullptr; bool renderingPrimarySurface = false; @@ -40,14 +50,6 @@ struct SCurrentRenderData { Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); }; -struct SMonitorRenderData { - CFramebuffer primaryFB; - CFramebuffer mirrorFB; - CFramebuffer mirrorSwapFB; - - CTexture stencilTex; -}; - class CHyprOpenGLImpl { public: @@ -59,9 +61,10 @@ public: void renderRect(wlr_box*, const CColor&, int round = 0); void renderRectWithDamage(wlr_box*, const CColor&, pixman_region32_t* damage, int round = 0); void renderTexture(wlr_texture*, wlr_box*, float a, int round = 0); - void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool border = false, bool allowPrimary = false); - void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0, bool border = false); + void renderTexture(const CTexture&, wlr_box*, float a, int round = 0, bool discardOpaque = false, bool allowPrimary = false); + void renderTextureWithBlur(const CTexture&, wlr_box*, float a, wlr_surface* pSurface, int round = 0); void renderRoundedShadow(wlr_box*, int round, int range, float a = 1.0); + void renderBorder(wlr_box*, const CColor&, int round); void makeWindowSnapshot(CWindow*); void makeLayerSnapshot(SLayerSurface*); @@ -101,13 +104,14 @@ private: bool m_bEndFrame = false; // Shaders - SQuad m_shQUAD; + CShader m_shQUAD; CShader m_shRGBA; CShader m_shRGBX; CShader m_shEXT; CShader m_shBLUR1; CShader m_shBLUR2; CShader m_shSHADOW; + CShader m_shBORDER1; // GLuint createProgram(const std::string&, const std::string&); @@ -117,8 +121,7 @@ private: // returns the out FB, can be either Mirror or MirrorSwap CFramebuffer* blurMainFramebufferWithDamage(float a, wlr_box* pBox, pixman_region32_t* damage); - void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool border = false, bool noAA = false, bool allowPrimary = false); - void renderBorder(wlr_box*, const CColor&, int thick = 1, int round = 0); + void renderTextureInternalWithDamage(const CTexture&, wlr_box* pBox, float a, pixman_region32_t* damage, int round = 0, bool discardOpaque = false, bool noAA = false, bool allowPrimary = false); }; inline std::unique_ptr<CHyprOpenGLImpl> g_pHyprOpenGL;
\ No newline at end of file diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index f7328997..eaa3cd90 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -27,7 +27,13 @@ void renderSurface(struct wlr_surface* surface, int x, int y, void* data) { if (RDATA->surface && surface == RDATA->surface) { g_pHyprOpenGL->m_RenderData.renderingPrimarySurface = true; - g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding, RDATA->decorate); + g_pHyprOpenGL->renderTextureWithBlur(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, surface, rounding); + + if (RDATA->decorate) { + auto col = g_pHyprOpenGL->m_pCurrentWindow->m_cRealBorderColor.col(); + col.a *= RDATA->fadeAlpha * RDATA->alpha / 255.f; + g_pHyprOpenGL->renderBorder(&windowBox, col, rounding); + } } else g_pHyprOpenGL->renderTexture(TEXTURE, &windowBox, RDATA->fadeAlpha * RDATA->alpha, rounding, false, false); @@ -68,11 +74,11 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) { if (g_pCompositor->isWorkspaceVisible(pWindow->m_iWorkspaceID)) return true; - for (auto& m : g_pCompositor->m_lMonitors) { - if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m.ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) + for (auto& m : g_pCompositor->m_vMonitors) { + if (PWORKSPACE && PWORKSPACE->m_iMonitorID == m->ID && (PWORKSPACE->m_vRenderOffset.isBeingAnimated() || PWORKSPACE->m_fAlpha.isBeingAnimated())) return true; - if (m.specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) + if (m->specialWorkspaceOpen && pWindow->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) return true; } @@ -82,37 +88,37 @@ bool CHyprRenderer::shouldRenderWindow(CWindow* pWindow) { void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWorkspace* pWorkspace, timespec* time) { CWindow* pWorkspaceWindow = nullptr; - for (auto& w : g_pCompositor->m_lWindows) { - if (w.m_iWorkspaceID != pWorkspace->m_iID || !w.m_bIsFullscreen) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_iWorkspaceID != pWorkspace->m_iID || !w->m_bIsFullscreen) continue; // found it! - renderWindow(&w, pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL); + renderWindow(w.get(), pMonitor, time, pWorkspace->m_efFullscreenMode != FULLSCREEN_FULL); - pWorkspaceWindow = &w; + pWorkspaceWindow = w.get(); } // then render windows over fullscreen - for (auto& w : g_pCompositor->m_lWindows) { - if (w.m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || !w.m_bCreatedOverFullscreen || !w.m_bIsMapped) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_iWorkspaceID != pWorkspaceWindow->m_iWorkspaceID || !w->m_bCreatedOverFullscreen || !w->m_bIsMapped) continue; - renderWindow(&w, pMonitor, time, true); + renderWindow(w.get(), pMonitor, time, true); } // and then special windows - for (auto& w : g_pCompositor->m_lWindows) { - if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut) + for (auto& w : g_pCompositor->m_vWindows) { + if (!g_pCompositor->windowValidMapped(w.get()) && !w->m_bFadingOut) continue; - if (w.m_iWorkspaceID != SPECIAL_WORKSPACE_ID) + if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) continue; - if (!shouldRenderWindow(&w, pMonitor)) + if (!shouldRenderWindow(w.get(), pMonitor)) continue; // render the bad boy - renderWindow(&w, pMonitor, time, true); + renderWindow(w.get(), pMonitor, time, true); } // and the overlay layers @@ -130,7 +136,7 @@ void CHyprRenderer::renderWorkspaceWithFullscreenWindow(SMonitor* pMonitor, CWor renderDragIcon(pMonitor, time); // if correct monitor draw hyprerror - if (pMonitor == &g_pCompositor->m_lMonitors.front()) + if (pMonitor == g_pCompositor->m_vMonitors.front().get()) g_pHyprError->draw(); } @@ -155,7 +161,7 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* renderdata.dontRound = pWindow->m_bIsFullscreen && PWORKSPACE->m_efFullscreenMode == FULLSCREEN_FULL; renderdata.fadeAlpha = pWindow->m_fAlpha.fl() * (PWORKSPACE->m_fAlpha.fl() / 255.f); renderdata.alpha = pWindow->m_bIsFullscreen ? g_pConfigManager->getFloat("decoration:fullscreen_opacity") : pWindow == g_pCompositor->m_pLastWindow ? g_pConfigManager->getFloat("decoration:active_opacity") : g_pConfigManager->getFloat("decoration:inactive_opacity"); - renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true); + renderdata.decorate = decorate && !pWindow->m_bX11DoesntWantBorders && (pWindow->m_bIsFloating ? *PNOFLOATINGBORDERS == 0 : true) && (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL); renderdata.rounding = pWindow->m_sAdditionalConfigData.rounding; // apply window special data @@ -166,8 +172,8 @@ void CHyprRenderer::renderWindow(CWindow* pWindow, SMonitor* pMonitor, timespec* g_pHyprOpenGL->m_pCurrentWindow = pWindow; - // render window decorations first - for (auto& wd : pWindow->m_dWindowDecorations) + // render window decorations first, if not fullscreen full + if (!pWindow->m_bIsFullscreen || PWORKSPACE->m_efFullscreenMode != FULLSCREEN_FULL) for (auto& wd : pWindow->m_dWindowDecorations) wd->draw(pMonitor, renderdata.alpha * renderdata.fadeAlpha / 255.f); if (!pWindow->m_bIsX11) { @@ -238,54 +244,54 @@ void CHyprRenderer::renderAllClientsForMonitor(const int& ID, timespec* time) { } // Non-floating - for (auto& w : g_pCompositor->m_lWindows) { - if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) continue; - if (w.m_bIsFloating) + if (w->m_bIsFloating) continue; // floating are in the second pass - if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID) + if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) continue; // special are in the third pass - if (!shouldRenderWindow(&w, PMONITOR)) + if (!shouldRenderWindow(w.get(), PMONITOR)) continue; // render the bad boy - renderWindow(&w, PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true); } // floating on top - for (auto& w : g_pCompositor->m_lWindows) { - if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) continue; - if (!w.m_bIsFloating) + if (!w->m_bIsFloating) continue; - if (w.m_iWorkspaceID == SPECIAL_WORKSPACE_ID) + if (w->m_iWorkspaceID == SPECIAL_WORKSPACE_ID) continue; - if (!shouldRenderWindow(&w, PMONITOR)) + if (!shouldRenderWindow(w.get(), PMONITOR)) continue; // render the bad boy - renderWindow(&w, PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true); } // and then special - for (auto& w : g_pCompositor->m_lWindows) { - if (!g_pCompositor->windowValidMapped(&w) && !w.m_bFadingOut) + for (auto& w : g_pCompositor->m_vWindows) { + if (w->m_bHidden && !w->m_bIsMapped && !w->m_bFadingOut) continue; - if (w.m_iWorkspaceID != SPECIAL_WORKSPACE_ID) + if (w->m_iWorkspaceID != SPECIAL_WORKSPACE_ID) continue; - if (!shouldRenderWindow(&w, PMONITOR)) + if (!shouldRenderWindow(w.get(), PMONITOR)) continue; // render the bad boy - renderWindow(&w, PMONITOR, time, true); + renderWindow(w.get(), PMONITOR, time, true); } // Render surfaces above windows for monitor @@ -545,14 +551,19 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) { pixman_region32_init(&damageBox); wlr_surface_get_effective_damage(pSurface, &damageBox); + if (!pixman_region32_not_empty(&damageBox)) { + pixman_region32_fini(&damageBox); + return; + } + pixman_region32_translate(&damageBox, x, y); - for (auto& m : g_pCompositor->m_lMonitors) { + for (auto& m : g_pCompositor->m_vMonitors) { double lx = 0, ly = 0; - wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m.output, &lx, &ly); + wlr_output_layout_output_coords(g_pCompositor->m_sWLROutputLayout, m->output, &lx, &ly); pixman_region32_translate(&damageBox, lx, ly); - wlr_region_scale(&damageBox, &damageBox, m.scale); - wlr_output_damage_add(m.damage, &damageBox); + wlr_region_scale(&damageBox, &damageBox, m->scale); + wlr_output_damage_add(m->damage, &damageBox); pixman_region32_translate(&damageBox, -lx, -ly); } @@ -565,39 +576,17 @@ void CHyprRenderer::damageSurface(wlr_surface* pSurface, double x, double y) { } void CHyprRenderer::damageWindow(CWindow* pWindow) { - if (!pWindow->m_bIsFloating) { - // damage by size & pos - // TODO TEMP: revise when added shadows/etc - - wlr_box damageBox = pWindow->getFullWindowBoundingBox(); - for (auto& m : g_pCompositor->m_lMonitors) { - wlr_box fixedDamageBox = damageBox; - fixedDamageBox.x -= m.vecPosition.x; - fixedDamageBox.y -= m.vecPosition.y; - scaleBox(&fixedDamageBox, m.scale); - wlr_output_damage_add_box(m.damage, &fixedDamageBox); - } - - static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; - - if (*PLOGDAMAGE) - Debug::log(LOG, "Damage: Window floated (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); - } else { - // damage by real size & pos + border size * 2 (JIC) - wlr_box damageBox = pWindow->getFullWindowBoundingBox(); - for (auto& m : g_pCompositor->m_lMonitors) { - wlr_box fixedDamageBox = damageBox; - fixedDamageBox.x -= m.vecPosition.x; - fixedDamageBox.y -= m.vecPosition.y; - scaleBox(&fixedDamageBox, m.scale); - wlr_output_damage_add_box(m.damage, &fixedDamageBox); - } + wlr_box damageBox = pWindow->getFullWindowBoundingBox(); + for (auto& m : g_pCompositor->m_vMonitors) { + wlr_box fixedDamageBox = {damageBox.x - m->vecPosition.x, damageBox.y - m->vecPosition.y, damageBox.width, damageBox.height}; + scaleBox(&fixedDamageBox, m->scale); + wlr_output_damage_add_box(m->damage, &fixedDamageBox); + } - static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; + static auto* const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; - if (*PLOGDAMAGE) - Debug::log(LOG, "Damage: Window tiled (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); - } + if (*PLOGDAMAGE) + Debug::log(LOG, "Damage: Window (%s): xy: %d, %d wh: %d, %d", pWindow->m_szTitle.c_str(), damageBox.x, damageBox.y, damageBox.width, damageBox.height); } void CHyprRenderer::damageMonitor(SMonitor* pMonitor) { @@ -611,10 +600,10 @@ void CHyprRenderer::damageMonitor(SMonitor* pMonitor) { } void CHyprRenderer::damageBox(wlr_box* pBox) { - for (auto& m : g_pCompositor->m_lMonitors) { - wlr_box damageBox = {pBox->x - m.vecPosition.x, pBox->y - m.vecPosition.y, pBox->width, pBox->height}; - scaleBox(&damageBox, m.scale); - wlr_output_damage_add_box(m.damage, &damageBox); + for (auto& m : g_pCompositor->m_vMonitors) { + wlr_box damageBox = {pBox->x - m->vecPosition.x, pBox->y - m->vecPosition.y, pBox->width, pBox->height}; + scaleBox(&damageBox, m->scale); + wlr_output_damage_add_box(m->damage, &damageBox); } static auto *const PLOGDAMAGE = &g_pConfigManager->getConfigValuePtr("debug:log_damage")->intValue; @@ -638,6 +627,9 @@ void CHyprRenderer::renderDragIcon(SMonitor* pMonitor, timespec* time) { renderdata.h = g_pInputManager->m_sDrag.dragIcon->surface->current.height; wlr_surface_for_each_surface(g_pInputManager->m_sDrag.dragIcon->surface, renderSurface, &renderdata); + + wlr_box box = {g_pInputManager->m_sDrag.pos.x - 2, g_pInputManager->m_sDrag.pos.y - 2, g_pInputManager->m_sDrag.dragIcon->surface->current.width + 4, g_pInputManager->m_sDrag.dragIcon->surface->current.height + 4}; + g_pHyprRenderer->damageBox(&box); } DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& mode) { @@ -651,14 +643,23 @@ DAMAGETRACKINGMODES CHyprRenderer::damageTrackingModeFromStr(const std::string& return DAMAGE_TRACKING_INVALID; } -void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) { +bool CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorRule, bool force) { Debug::log(LOG, "Applying monitor rule for %s", pMonitor->szName.c_str()); + // if it's disabled, disable and ignore + if (pMonitorRule->disabled) { + wlr_output_enable(pMonitor->output, 0); + wlr_output_commit(pMonitor->output); + + Events::listener_monitorDestroy(nullptr, pMonitor->output); + return false; + } + // Check if the rule isn't already applied if (!force && DELTALESSTHAN(pMonitor->vecPixelSize.x, pMonitorRule->resolution.x, 1) && DELTALESSTHAN(pMonitor->vecPixelSize.y, pMonitorRule->resolution.y, 1) && DELTALESSTHAN(pMonitor->refreshRate, pMonitorRule->refreshRate, 1) && pMonitor->scale == pMonitorRule->scale && DELTALESSTHAN(pMonitor->vecPosition.x, pMonitorRule->offset.x, 1) && DELTALESSTHAN(pMonitor->vecPosition.y, pMonitorRule->offset.y, 1) && pMonitor->transform == pMonitorRule->transform) { Debug::log(LOG, "Not applying a new rule to %s because it's already applied!", pMonitor->szName.c_str()); - return; + return true; } wlr_output_set_scale(pMonitor->output, pMonitorRule->scale); @@ -697,23 +698,32 @@ void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR } if (!found) { - const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); + wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000); + pMonitor->vecSize = pMonitorRule->resolution; - if (!PREFERREDMODE) { - Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f", - (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate); - return; - } + if (!wlr_output_test(pMonitor->output)) { + Debug::log(ERR, "Custom resolution FAILED, falling back to preferred"); + + const auto PREFERREDMODE = wlr_output_preferred_mode(pMonitor->output); - // Preferred is valid - wlr_output_set_mode(pMonitor->output, PREFERREDMODE); + if (!PREFERREDMODE) { + Debug::log(ERR, "Monitor %s has NO PREFERRED MODE, and an INVALID one was requested: %ix%i@%2f", + (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate); + return true; + } + + // Preferred is valid + wlr_output_set_mode(pMonitor->output, PREFERREDMODE); - Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f", - pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, - PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); + Debug::log(ERR, "Monitor %s got an invalid requested mode: %ix%i@%2f, using the preferred one instead: %ix%i@%2f", + pMonitor->output->name, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate, + PREFERREDMODE->width, PREFERREDMODE->height, PREFERREDMODE->refresh / 1000.f); - pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; - pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + pMonitor->refreshRate = PREFERREDMODE->refresh / 1000.f; + pMonitor->vecSize = Vector2D(PREFERREDMODE->width, PREFERREDMODE->height); + } else { + Debug::log(LOG, "Set a custom mode %ix%i@%2f (mode not found in monitor modes)", (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (float)pMonitorRule->refreshRate); + } } } else { wlr_output_set_custom_mode(pMonitor->output, (int)pMonitorRule->resolution.x, (int)pMonitorRule->resolution.y, (int)pMonitorRule->refreshRate * 1000); @@ -730,7 +740,7 @@ void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR if (!wlr_output_commit(pMonitor->output)) { Debug::log(ERR, "Couldn't commit output named %s", pMonitor->output->name); - return; + return true; } int x, y; @@ -752,6 +762,8 @@ void CHyprRenderer::applyMonitorRule(SMonitor* pMonitor, SMonitorRule* pMonitorR // frame skip pMonitor->framesToSkip = 1; + + return true; } void CHyprRenderer::ensureCursorRenderingMode() { @@ -767,8 +779,8 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Hiding the cursor (timeout)"); - for (auto& m : g_pCompositor->m_lMonitors) - g_pHyprRenderer->damageMonitor(&m); // TODO: maybe just damage the cursor area? + for (auto& m : g_pCompositor->m_vMonitors) + g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? } else if (*PCURSORTIMEOUT > PASSEDCURSORSECONDS && !m_bHasARenderedCursor) { m_bHasARenderedCursor = true; @@ -777,8 +789,8 @@ void CHyprRenderer::ensureCursorRenderingMode() { Debug::log(LOG, "Showing the cursor (timeout)"); - for (auto& m : g_pCompositor->m_lMonitors) - g_pHyprRenderer->damageMonitor(&m); // TODO: maybe just damage the cursor area? + for (auto& m : g_pCompositor->m_vMonitors) + g_pHyprRenderer->damageMonitor(m.get()); // TODO: maybe just damage the cursor area? } } else { m_bHasARenderedCursor = true; diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 43a241ed..ff9fd4ea 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -28,7 +28,7 @@ public: void damageBox(wlr_box*); void damageBox(const int& x, const int& y, const int& w, const int& h); void damageMonitor(SMonitor*); - void applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false); + bool applyMonitorRule(SMonitor*, SMonitorRule*, bool force = false); bool shouldRenderWindow(CWindow*, SMonitor*); bool shouldRenderWindow(CWindow*); void ensureCursorRenderingMode(); diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp index e69de29b..96b3caf7 100644 --- a/src/render/Shader.cpp +++ b/src/render/Shader.cpp @@ -0,0 +1,13 @@ +#include "Shader.hpp" + +GLint CShader::getUniformLocation(const std::string& unif) { + const auto itpos = m_muUniforms.find(unif); + + if (itpos == m_muUniforms.end()) { + const auto unifLoc = glGetUniformLocation(program, unif.c_str()); + m_muUniforms[unif] = unifLoc; + return unifLoc; + } + + return itpos->second; +}
\ No newline at end of file diff --git a/src/render/Shader.hpp b/src/render/Shader.hpp index 4d94358e..f996894b 100644 --- a/src/render/Shader.hpp +++ b/src/render/Shader.hpp @@ -1,22 +1,21 @@ #pragma once #include "../defines.hpp" - -struct SQuad { - GLuint program; - GLint proj; - GLint color; - GLint posAttrib; - GLint texAttrib; -}; +#include <unordered_map> class CShader { public: GLuint program; GLint proj; + GLint color; GLint tex; GLint alpha; GLint posAttrib; GLint texAttrib; GLint discardOpaque; + + GLint getUniformLocation(const std::string&); + +private: + std::unordered_map<std::string, GLint> m_muUniforms; };
\ No newline at end of file diff --git a/src/render/Shaders.hpp b/src/render/Shaders.hpp index ac7f9424..1849c621 100644 --- a/src/render/Shaders.hpp +++ b/src/render/Shaders.hpp @@ -1,4 +1,5 @@ #pragma once #include "shaders/Textures.hpp" -#include "shaders/Shadow.hpp"
\ No newline at end of file +#include "shaders/Shadow.hpp" +#include "shaders/Border.hpp"
\ No newline at end of file diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 6933e687..40051942 100644 --- a/src/render/decorations/CHyprDropShadowDecoration.cpp +++ b/src/render/decorations/CHyprDropShadowDecoration.cpp @@ -35,6 +35,17 @@ void CHyprDropShadowDecoration::damageEntire() { void CHyprDropShadowDecoration::updateWindow(CWindow* pWindow) { damageEntire(); + + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); + + const auto WORKSPACEOFFSET = PWORKSPACE ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); + + if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { + m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; + m_vLastWindowSize = pWindow->m_vRealSize.vec(); + + damageEntire(); + } } void CHyprDropShadowDecoration::draw(SMonitor* pMonitor, float a) { @@ -45,22 +56,70 @@ void CHyprDropShadowDecoration::draw(SMonitor* pMonitor, float a) { static auto *const PSHADOWS = &g_pConfigManager->getConfigValuePtr("decoration:drop_shadow")->intValue; static auto *const PSHADOWSIZE = &g_pConfigManager->getConfigValuePtr("decoration:shadow_range")->intValue; static auto *const PROUNDING = &g_pConfigManager->getConfigValuePtr("decoration:rounding")->intValue; + static auto *const PSHADOWIGNOREWINDOW = &g_pConfigManager->getConfigValuePtr("decoration:shadow_ignore_window")->intValue; + static auto *const PSHADOWOFFSET = &g_pConfigManager->getConfigValuePtr("decoration:shadow_offset")->strValue; if (*PSHADOWS != 1) return; // disabled - // update the extents if needed - if (*PSHADOWSIZE != m_seExtents.topLeft.x) - m_seExtents = {{*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}, {*PSHADOWSIZE + 2, *PSHADOWSIZE + 2}}; + // get the real offset + Vector2D offset; + try { + if (const auto SPACEPOS = PSHADOWOFFSET->find(' '); SPACEPOS != std::string::npos) { + const auto X = PSHADOWOFFSET->substr(0, SPACEPOS); + const auto Y = PSHADOWOFFSET->substr(SPACEPOS + 1); - m_vLastWindowPos = m_pWindow->m_vRealPosition.vec(); - m_vLastWindowSize = m_pWindow->m_vRealSize.vec(); + if (isNumber(X, true) && isNumber(Y, true)) { + offset = Vector2D(std::stof(X), std::stof(Y)); + } + } + } catch (std::exception& e) { + return; // cannot parse + } + + // update the extents + m_seExtents = {{*PSHADOWSIZE + 2 - offset.x, *PSHADOWSIZE + 2 - offset.y}, {*PSHADOWSIZE + 2 + offset.x, *PSHADOWSIZE + 2 + offset.y}}; // draw the shadow wlr_box fullBox = {m_vLastWindowPos.x - m_seExtents.topLeft.x + 2, m_vLastWindowPos.y - m_seExtents.topLeft.y + 2, m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x - 4, m_vLastWindowSize.y + m_seExtents.topLeft.y + m_seExtents.bottomRight.y - 4}; fullBox.x -= pMonitor->vecPosition.x; fullBox.y -= pMonitor->vecPosition.y; - + + if (fullBox.width < 1 || fullBox.height < 1) + return; // don't draw invisible shadows + + if (*PSHADOWIGNOREWINDOW) { + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + + glEnable(GL_STENCIL_TEST); + + glStencilFunc(GL_ALWAYS, 1, -1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + + wlr_box windowBox = {m_vLastWindowPos.x - pMonitor->vecPosition.x, m_vLastWindowPos.y - pMonitor->vecPosition.y, m_vLastWindowSize.x, m_vLastWindowSize.y}; + + scaleBox(&windowBox, pMonitor->scale); + + if (windowBox.width < 1 || windowBox.height < 1) { + glDisable(GL_STENCIL_TEST); + return; // prevent assert failed + } + + g_pHyprOpenGL->renderRect(&windowBox, CColor(0,0,0,0), *PROUNDING); + + glStencilFunc(GL_NOTEQUAL, 1, -1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + + scaleBox(&fullBox, pMonitor->scale); g_pHyprOpenGL->renderRoundedShadow(&fullBox, *PROUNDING, *PSHADOWSIZE, a); + + if (*PSHADOWIGNOREWINDOW) { + // cleanup + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + glDisable(GL_STENCIL_TEST); + } } diff --git a/src/render/decorations/CHyprGroupBarDecoration.cpp b/src/render/decorations/CHyprGroupBarDecoration.cpp index 2bb486ee..abb5d90c 100644 --- a/src/render/decorations/CHyprGroupBarDecoration.cpp +++ b/src/render/decorations/CHyprGroupBarDecoration.cpp @@ -21,14 +21,18 @@ eDecorationType CHyprGroupBarDecoration::getDecorationType() { void CHyprGroupBarDecoration::updateWindow(CWindow* pWindow) { damageEntire(); - if (pWindow->m_vRealPosition.vec() != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { + const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pWindow->m_iWorkspaceID); + + const auto WORKSPACEOFFSET = PWORKSPACE ? PWORKSPACE->m_vRenderOffset.vec() : Vector2D(); + + if (pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET != m_vLastWindowPos || pWindow->m_vRealSize.vec() != m_vLastWindowSize) { // we draw 3px above the window's border with 3px const auto BORDERSIZE = g_pConfigManager->getInt("general:border_size"); m_seExtents.topLeft = Vector2D(0, BORDERSIZE + 3 + 3); m_seExtents.bottomRight = Vector2D(); - m_vLastWindowPos = pWindow->m_vRealPosition.vec(); + m_vLastWindowPos = pWindow->m_vRealPosition.vec() + WORKSPACEOFFSET; m_vLastWindowSize = pWindow->m_vRealSize.vec(); } diff --git a/src/render/decorations/IHyprWindowDecoration.hpp b/src/render/decorations/IHyprWindowDecoration.hpp index 21219b36..4066b6f3 100644 --- a/src/render/decorations/IHyprWindowDecoration.hpp +++ b/src/render/decorations/IHyprWindowDecoration.hpp @@ -16,7 +16,7 @@ struct SWindowDecorationExtents { class CWindow; struct SMonitor; -class IHyprWindowDecoration { +interface IHyprWindowDecoration { public: virtual ~IHyprWindowDecoration() = 0; diff --git a/src/render/shaders/Border.hpp b/src/render/shaders/Border.hpp new file mode 100644 index 00000000..69f1ad5b --- /dev/null +++ b/src/render/shaders/Border.hpp @@ -0,0 +1,91 @@ +#pragma once + +#include <string> + +// makes a stencil without corners +inline const std::string FRAGBORDER1 = R"#( +precision mediump float; +varying vec4 v_color; +varying vec2 v_texcoord; + +uniform vec2 topLeft; +uniform vec2 bottomRight; +uniform vec2 fullSize; +uniform float radius; +uniform float thick; +uniform int primitiveMultisample; + +float getOpacityForPixAndCorner(vec2 pix, vec2 corner) { + + if (primitiveMultisample == 0) { + float dis = distance(pix + vec2(0.5, 0.5), corner); + return dis < radius && dis > radius - thick ? 1.0 : 0.0; + } + + float distance1 = distance(pix + vec2(0.25, 0.25), corner); + float distance2 = distance(pix + vec2(0.75, 0.25), corner); + float distance3 = distance(pix + vec2(0.25, 0.75), corner); + float distance4 = distance(pix + vec2(0.75, 0.75), corner); + + float v1 = distance1 < radius && distance1 > radius - thick ? 1.0 : 0.0; + float v2 = distance2 < radius && distance2 > radius - thick ? 1.0 : 0.0; + float v3 = distance3 < radius && distance3 > radius - thick ? 1.0 : 0.0; + float v4 = distance4 < radius && distance4 > radius - thick ? 1.0 : 0.0; + + return (v1 + v2 + v3 + v4) / 4.0; +} + +void main() { + + vec2 pixCoord = fullSize * v_texcoord; + + vec4 pixColor = v_color; + + bool done = false; + + // check for edges + if (pixCoord[0] < topLeft[0]) { + if (pixCoord[1] < topLeft[1]) { + // top left + pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, topLeft + vec2(1,1)); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom left + pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(topLeft[0] + 1.0, bottomRight[1])); + done = true; + } + } else if (pixCoord[0] > bottomRight[0]) { + if (pixCoord[1] < topLeft[1]) { + // top right + pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, vec2(bottomRight[0], topLeft[1] + 1.0)); + done = true; + } else if (pixCoord[1] > bottomRight[1]) { + // bottom right + pixColor[3] = pixColor[3] * getOpacityForPixAndCorner(pixCoord, bottomRight); + done = true; + } + } + + // now check for other shit + if (!done) { + // distance to all straight bb borders + float distanceT = pixCoord[1]; + float distanceB = fullSize[1] - pixCoord[1]; + float distanceL = pixCoord[0]; + float distanceR = fullSize[0] - pixCoord[0]; + + // get the smallest + float smallest = min(min(distanceT, distanceB), min(distanceL, distanceR)); + + if (smallest > thick) { + discard; return; + } + } + + if (pixColor[3] == 0.0) { + discard; return; + } + + gl_FragColor = pixColor; +} +)#";
\ No newline at end of file diff --git a/src/render/shaders/Shadow.hpp b/src/render/shaders/Shadow.hpp index f54124fa..dca194c0 100644 --- a/src/render/shaders/Shadow.hpp +++ b/src/render/shaders/Shadow.hpp @@ -13,7 +13,6 @@ uniform vec2 fullSize; uniform float radius; uniform float range; uniform float shadowPower; -uniform int ignoreWindow; float pixAlphaRoundedDistance(float distanceToCorner) { if (distanceToCorner > radius) { @@ -75,7 +74,7 @@ void main() { } } - if (pixColor[3] == 0.0 || (ignoreWindow == 1 && pixColor[3] == originalAlpha)) { + if (pixColor[3] == 0.0) { discard; return; } |
