diff options
author | Vaxry <[email protected]> | 2024-12-22 17:12:09 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2024-12-22 17:12:09 +0100 |
commit | e536b02248f370971716b744968776f6880528be (patch) | |
tree | 5e5755b7894eb44f9259cfe0e1d97899148a8a60 /src/render/pass/Pass.cpp | |
parent | 1cc1a46c2e154a27750b81307040d3bf7ff0f64f (diff) | |
download | Hyprland-e536b02248f370971716b744968776f6880528be.tar.gz Hyprland-e536b02248f370971716b744968776f6880528be.zip |
Renderer: rewrite render scheduling (#8683)
This rewrites renderer scheduling. Occlusion is now unified in a new Pass type.
Diffstat (limited to 'src/render/pass/Pass.cpp')
-rw-r--r-- | src/render/pass/Pass.cpp | 157 |
1 files changed, 157 insertions, 0 deletions
diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp new file mode 100644 index 00000000..31385acb --- /dev/null +++ b/src/render/pass/Pass.cpp @@ -0,0 +1,157 @@ +#include "Pass.hpp" +#include "../OpenGL.hpp" +#include <algorithm> +#include <ranges> +#include "../../config/ConfigValue.hpp" + +bool CRenderPass::empty() const { + return false; +} + +bool CRenderPass::single() const { + return m_vPassElements.size() == 1; +} + +bool CRenderPass::needsIntrospection() const { + return true; +} + +void CRenderPass::add(SP<IPassElement> el) { + m_vPassElements.emplace_back(makeShared<SPassElementData>(CRegion{}, el)); +} + +void CRenderPass::simplify() { + // TODO: use precompute blur for instances where there is nothing in between + + // if there is live blur, we need to NOT occlude any area where it will be influenced + const auto WILLBLUR = std::ranges::any_of(m_vPassElements, [](const auto& el) { return el->element->needsLiveBlur(); }); + + CRegion newDamage = damage.copy().intersect(CBox{{}, g_pHyprOpenGL->m_RenderData.pMonitor->vecTransformedSize}); + for (auto& el : m_vPassElements | std::views::reverse) { + + if (newDamage.empty()) { + el->discard = true; + continue; + } + + el->elementDamage = newDamage; + auto bb1 = el->element->boundingBox(); + if (!bb1) + continue; + + auto bb = bb1->scale(g_pHyprOpenGL->m_RenderData.pMonitor->scale); + + // drop if empty + if (CRegion copy = newDamage.copy(); copy.intersect(bb).empty()) { + el->discard = true; + continue; + } + + auto opaque = el->element->opaqueRegion(); + + if (!opaque.empty()) { + opaque.scale(g_pHyprOpenGL->m_RenderData.pMonitor->scale); + + // if this intersects the liveBlur region, allow live blur to operate correctly. + // do not occlude a border near it. + if (WILLBLUR) { + CRegion liveBlurRegion; + for (auto& el2 : m_vPassElements) { + // if we reach self, no problem, we can break. + // if the blur is above us, we don't care, it will work fine. + if (el2 == el) + break; + + if (!el2->element->needsLiveBlur()) + continue; + + const auto BB = el2->element->boundingBox(); + RASSERT(BB, "No bounding box for an element with live blur is illegal"); + + liveBlurRegion.add(*BB); + } + + if (auto infringement = opaque.copy().intersect(liveBlurRegion); !infringement.empty()) { + // eh, this is not the correct solution, but it will do... + // TODO: is this *easily* fixable? + opaque.subtract(infringement.expand(oneBlurRadius())); + } + } + newDamage.subtract(opaque); + } + } +} + +void CRenderPass::clear() { + m_vPassElements.clear(); +} + +CRegion CRenderPass::render(const CRegion& damage_) { + const auto WILLBLUR = std::ranges::any_of(m_vPassElements, [](const auto& el) { return el->element->needsLiveBlur(); }); + + damage = damage_.copy(); + + if (damage.empty()) { + g_pHyprOpenGL->m_RenderData.damage = damage; + g_pHyprOpenGL->m_RenderData.finalDamage = damage; + return damage; + } + + if (WILLBLUR) { + // combine blur regions into one that will be expanded + CRegion blurRegion; + for (auto& el : m_vPassElements) { + if (!el->element->needsLiveBlur()) + continue; + + const auto BB = el->element->boundingBox(); + RASSERT(BB, "No bounding box for an element with live blur is illegal"); + + blurRegion.add(*BB); + } + + blurRegion.intersect(damage).expand(oneBlurRadius()); + + g_pHyprOpenGL->m_RenderData.finalDamage = blurRegion.copy().add(damage); + + // FIXME: why does this break on * 1.F ? + // used to work when we expand all the damage... I think? Well, before pass. + // moving a window over blur shows the edges being wonk. + blurRegion.expand(oneBlurRadius() * 1.5F); + + damage = blurRegion.copy().add(damage); + } else + g_pHyprOpenGL->m_RenderData.finalDamage = damage; + + if (std::ranges::any_of(m_vPassElements, [](const auto& el) { return el->element->disableSimplification(); })) { + for (auto& el : m_vPassElements) { + el->elementDamage = damage; + } + } else + simplify(); + + g_pHyprOpenGL->m_RenderData.pCurrentMonData->blurFBShouldRender = std::ranges::any_of(m_vPassElements, [](const auto& el) { return el->element->needsPrecomputeBlur(); }); + + if (m_vPassElements.empty()) + return {}; + + for (auto& el : m_vPassElements) { + if (el->discard) { + el->element->discard(); + continue; + } + + g_pHyprOpenGL->m_RenderData.damage = el->elementDamage; + el->element->draw(el->elementDamage); + } + + g_pHyprOpenGL->m_RenderData.damage = damage; + return damage; +} + +float CRenderPass::oneBlurRadius() { + // TODO: is this exact range correct? + static auto PBLURSIZE = CConfigValue<Hyprlang::INT>("decoration:blur:size"); + static auto PBLURPASSES = CConfigValue<Hyprlang::INT>("decoration:blur:passes"); + return *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think. +} |