diff options
| author | UjinT34 <41110182+UjinT34@users.noreply.github.com> | 2026-03-29 00:41:45 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-28 21:41:45 +0000 |
| commit | 38a7f03cf0e5ee116794a78581634ba3dab508fa (patch) | |
| tree | 969891411b2af4e437a183004018cfc359a3057e /src/render/Renderer.cpp | |
| parent | ef2e8dfd5f7e6ee55fa7bc48e44974e64938d14a (diff) | |
renderer: refactor part 7: api fixes (#13631)
Part 7 of ujin's refactors
---------
Co-authored-by: Vaxry <vaxry@vaxry.net>
Diffstat (limited to 'src/render/Renderer.cpp')
| -rw-r--r-- | src/render/Renderer.cpp | 608 |
1 files changed, 81 insertions, 527 deletions
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 0c184238..1b735a46 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -47,15 +47,17 @@ #include "../protocols/types/ContentType.hpp" #include "../helpers/MiscFunctions.hpp" #include "AsyncResourceGatherer.hpp" +#include "ElementRenderer.hpp" #include "Framebuffer.hpp" #include "OpenGL.hpp" #include "Texture.hpp" -#include "pass/BorderPassElement.hpp" -#include "pass/PreBlurElement.hpp" +#include "./pass/PreBlurElement.hpp" +#include "types.hpp" #include <hyprutils/math/Mat3x3.hpp> #include <hyprutils/math/Region.hpp> #include <hyprutils/math/Vector2D.hpp> #include <hyprutils/memory/SharedPtr.hpp> +#include <hyprutils/memory/UniquePtr.hpp> #include <optional> #include <pango/pangocairo.h> @@ -65,6 +67,7 @@ using namespace Hyprutils::Utils; using namespace Hyprutils::OS; using enum NContentType::eContentType; using namespace NColorManagement; +using namespace Render; extern "C" { #include <xf86drm.h> @@ -212,8 +215,8 @@ IHyprRenderer::~IHyprRenderer() { wl_event_source_remove(m_cursorTicker); } -WP<CHyprOpenGLImpl> IHyprRenderer::glBackend() { - return g_pHyprOpenGL; +WP<Render::GL::CHyprOpenGLImpl> IHyprRenderer::glBackend() { + return Render::GL::g_pHyprOpenGL; } bool IHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { @@ -499,16 +502,12 @@ void IHyprRenderer::renderWorkspaceWindows(PHLMONITOR pMonitor, PHLWORKSPACE pWo } void IHyprRenderer::bindOffMain() { - RASSERT(m_renderData.pMonitor->m_offMainFB->isAllocated(), "IHyprRenderer::beginRender should allocate monitor FBs") - - m_renderData.pMonitor->m_offMainFB->bind(); - draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {}); - m_renderData.currentFB = m_renderData.pMonitor->m_offMainFB; + bindFB(m_renderData.pMonitor->resources()->getUnusedWorkBuffer()); + draw(CClearPassElement::SClearData{{0, 0, 0, 0}}); } void IHyprRenderer::bindBackOnMain() { - m_renderData.mainFB->bind(); - m_renderData.currentFB = m_renderData.mainFB; + bindFB(m_renderData.mainFB); } void IHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const Time::steady_tp& time, bool decorate, eRenderPassMode mode, bool ignorePosition, bool standalone) { @@ -679,7 +678,7 @@ void IHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T } if (TRANSFORMERSPRESENT) { - IFramebuffer* last = m_renderData.currentFB.get(); + SP<IFramebuffer> last = m_renderData.currentFB; for (auto const& t : pWindow->m_transformers) { last = t->transform(last); } @@ -769,348 +768,59 @@ void IHyprRenderer::renderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor, const T m_renderData.currentWindow.reset(); } -void IHyprRenderer::drawRect(CRectPassElement* element, const CRegion& damage) { - auto& data = element->m_data; - - if (data.box.w <= 0 || data.box.h <= 0) +void IHyprRenderer::draw(WP<IPassElement> element, const CRegion& damage) { + ASSERT(element); + if (!element) return; - if (!data.clipBox.empty()) - m_renderData.clipBox = data.clipBox; - - data.modifiedBox = data.box; - m_renderData.renderModif.applyToBox(data.modifiedBox); - - CBox transformedBox = data.box; - transformedBox.transform(Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)), m_renderData.pMonitor->m_transformedSize.x, - m_renderData.pMonitor->m_transformedSize.y); - - data.TOPLEFT[0] = sc<float>(transformedBox.x); - data.TOPLEFT[1] = sc<float>(transformedBox.y); - data.FULLSIZE[0] = sc<float>(transformedBox.width); - data.FULLSIZE[1] = sc<float>(transformedBox.height); - - data.drawRegion = data.color.a == 1.F || !data.blur ? damage : m_renderData.damage; - - if (m_renderData.clipBox.width != 0 && m_renderData.clipBox.height != 0) { - CRegion damageClip{m_renderData.clipBox.x, m_renderData.clipBox.y, m_renderData.clipBox.width, m_renderData.clipBox.height}; - data.drawRegion = damageClip.intersect(data.drawRegion); - } - - draw(element, damage); - - m_renderData.clipBox = {}; + elementRenderer()->drawElement(element, damage); } -void IHyprRenderer::drawHints(CRendererHintsPassElement* element, const CRegion& damage) { - const auto m_data = element->m_data; - if (m_data.renderModif.has_value()) - m_renderData.renderModif = *m_data.renderModif; +void IHyprRenderer::draw(const CBorderPassElement::SBorderData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CBorderPassElement>(data), damage); } -void IHyprRenderer::drawPreBlur(CPreBlurElement* element, const CRegion& damage) { - TRACY_GPU_ZONE("RenderPreBlurForCurrentMonitor"); - - const auto SAVEDRENDERMODIF = m_renderData.renderModif; - m_renderData.renderModif = {}; // fix shit - - // make the fake dmg - CRegion fakeDamage{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y}; - - draw(element, fakeDamage); - - m_renderData.pMonitor->m_blurFBDirty = false; - m_renderData.pMonitor->m_blurFBShouldRender = false; - - m_renderData.renderModif = SAVEDRENDERMODIF; +void IHyprRenderer::draw(const CClearPassElement::SClearData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CClearPassElement>(data), damage); } -void IHyprRenderer::drawSurface(CSurfacePassElement* element, const CRegion& damage) { - const auto m_data = element->m_data; - - CScopeGuard x = {[]() { - g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); - g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); - }}; - - if (!m_data.texture) - return; - - const auto& TEXTURE = m_data.texture; - - // this is bad, probably has been logged elsewhere. Means the texture failed - // uploading to the GPU. - if (!TEXTURE->ok()) - return; - - const auto INTERACTIVERESIZEINPROGRESS = m_data.pWindow && g_layoutManager->dragController()->target() && g_layoutManager->dragController()->mode() == MBIND_RESIZE; - TRACY_GPU_ZONE("RenderSurface"); - - auto PSURFACE = Desktop::View::CWLSurface::fromResource(m_data.surface); - - const float ALPHA = m_data.alpha * m_data.fadeAlpha * (PSURFACE ? PSURFACE->m_alphaModifier : 1.F); - const float OVERALL_ALPHA = PSURFACE ? PSURFACE->m_overallOpacity : 1.F; - const bool BLUR = m_data.blur && (!TEXTURE->m_opaque || ALPHA < 1.F || OVERALL_ALPHA < 1.F); - - auto windowBox = element->getTexBox(); - - const auto PROJSIZEUNSCALED = windowBox.size(); - - windowBox.scale(m_data.pMonitor->m_scale); - windowBox.round(); - - if (windowBox.width <= 1 || windowBox.height <= 1) { - element->discard(); - return; - } - - const bool MISALIGNEDFSV1 = std::floor(m_data.pMonitor->m_scale) != m_data.pMonitor->m_scale /* Fractional */ && m_data.surface->m_current.scale == 1 /* fs protocol */ && - windowBox.size() != m_data.surface->m_current.bufferSize /* misaligned */ && DELTALESSTHAN(windowBox.width, m_data.surface->m_current.bufferSize.x, 3) && - DELTALESSTHAN(windowBox.height, m_data.surface->m_current.bufferSize.y, 3) /* off by one-or-two */ && - (!m_data.pWindow || (!m_data.pWindow->m_realSize->isBeingAnimated() && !INTERACTIVERESIZEINPROGRESS)) /* not window or not animated/resizing */ && - (!m_data.pLS || (!m_data.pLS->m_realSize->isBeingAnimated())); /* not LS or not animated */ - - calculateUVForSurface(m_data.pWindow, m_data.surface, m_data.pMonitor->m_self.lock(), m_data.mainSurface, windowBox.size(), PROJSIZEUNSCALED, MISALIGNEDFSV1); - - auto cancelRender = false; - auto clipRegion = element->visibleRegion(cancelRender); - if (cancelRender) - return; - - // check for fractional scale surfaces misaligning the buffer size - // in those cases it's better to just force nearest neighbor - // as long as the window is not animated. During those it'd look weird. - // UV will fixup it as well - if (MISALIGNEDFSV1) - m_renderData.useNearestNeighbor = true; - - float rounding = m_data.rounding; - float roundingPower = m_data.roundingPower; - - rounding -= 1; // to fix a border issue - - if (m_data.dontRound) { - rounding = 0; - roundingPower = 2.0f; - } - - const bool WINDOWOPAQUE = m_data.pWindow && m_data.pWindow->wlSurface()->resource() == m_data.surface ? m_data.pWindow->opaque() : false; - const bool CANDISABLEBLEND = ALPHA >= 1.f && OVERALL_ALPHA >= 1.f && rounding <= 0 && WINDOWOPAQUE; - - if (CANDISABLEBLEND) - blend(false); - else - blend(true); - - // FIXME: This is wrong and will bug the blur out as shit if the first surface - // is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back - // to what we do for misaligned surfaces (blur the entire thing and then render shit without blur) - if (m_data.surfaceCounter == 0 && !m_data.popup) { - if (BLUR) - draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{ - .tex = TEXTURE, - .box = windowBox, - .a = ALPHA, - .blurA = m_data.fadeAlpha, - .overallA = OVERALL_ALPHA, - .round = rounding, - .roundingPower = roundingPower, - .blur = true, - .blockBlurOptimization = m_data.blockBlurOptimization, - .allowCustomUV = true, - .surface = m_data.surface, - .discardMode = m_data.discardMode, - .discardOpacity = m_data.discardOpacity, - .clipRegion = clipRegion, - .currentLS = m_data.pLS, - }), - m_renderData.damage.copy().intersect(windowBox)); - else - draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{ - .tex = TEXTURE, - .box = windowBox, - .a = ALPHA * OVERALL_ALPHA, - .round = rounding, - .roundingPower = roundingPower, - .discardActive = false, - .allowCustomUV = true, - .surface = m_data.surface, - .discardMode = m_data.discardMode, - .discardOpacity = m_data.discardOpacity, - .clipRegion = clipRegion, - .currentLS = m_data.pLS, - }), - m_renderData.damage.copy().intersect(windowBox)); - } else { - if (BLUR && m_data.popup) - draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{ - .tex = TEXTURE, - .box = windowBox, - .a = ALPHA, - .blurA = m_data.fadeAlpha, - .overallA = OVERALL_ALPHA, - .round = rounding, - .roundingPower = roundingPower, - .blur = true, - .blockBlurOptimization = true, - .allowCustomUV = true, - .surface = m_data.surface, - .discardMode = m_data.discardMode, - .discardOpacity = m_data.discardOpacity, - .clipRegion = clipRegion, - .currentLS = m_data.pLS, - }), - m_renderData.damage.copy().intersect(windowBox)); - else - draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{ - .tex = TEXTURE, - .box = windowBox, - .a = ALPHA * OVERALL_ALPHA, - .round = rounding, - .roundingPower = roundingPower, - .discardActive = false, - .allowCustomUV = true, - .surface = m_data.surface, - .discardMode = m_data.discardMode, - .discardOpacity = m_data.discardOpacity, - .clipRegion = clipRegion, - .currentLS = m_data.pLS, - }), - m_renderData.damage.copy().intersect(windowBox)); - } - - blend(true); -}; - -void IHyprRenderer::preDrawSurface(CSurfacePassElement* element, const CRegion& damage) { - m_renderData.clipBox = element->m_data.clipBox; - m_renderData.useNearestNeighbor = element->m_data.useNearestNeighbor; - pushMonitorTransformEnabled(element->m_data.flipEndFrame); - m_renderData.currentWindow = element->m_data.pWindow; - - drawSurface(element, damage); - - if (!m_bBlockSurfaceFeedback) - element->m_data.surface->presentFeedback(element->m_data.when, element->m_data.pMonitor->m_self.lock()); - - // add async (dmabuf) buffers to usedBuffers so we can handle release later - // sync (shm) buffers will be released in commitState, so no need to track them here - if (element->m_data.surface->m_current.buffer && !element->m_data.surface->m_current.buffer->isSynchronous()) - m_usedAsyncBuffers.emplace_back(element->m_data.surface->m_current.buffer); - - m_renderData.clipBox = {}; - m_renderData.useNearestNeighbor = false; - popMonitorTransformEnabled(); - m_renderData.currentWindow.reset(); +void IHyprRenderer::draw(const CFramebufferElement::SFramebufferElementData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CFramebufferElement>(data), damage); } -void IHyprRenderer::drawTex(CTexPassElement* element, const CRegion& damage) { - if (!element->m_data.clipBox.empty()) - m_renderData.clipBox = element->m_data.clipBox; - - pushMonitorTransformEnabled(element->m_data.flipEndFrame); - if (element->m_data.useMirrorProjection) - setProjectionType(RPT_MIRROR); - - m_renderData.surface = element->m_data.surface; - - CScopeGuard x = {[useMirrorProjection = element->m_data.useMirrorProjection]() { - g_pHyprRenderer->popMonitorTransformEnabled(); - if (useMirrorProjection) - g_pHyprRenderer->setProjectionType(RPT_MONITOR); - g_pHyprRenderer->m_renderData.surface.reset(); - }}; - - if (element->m_data.blur) { - // make a damage region for this window - CRegion texDamage{m_renderData.damage}; - texDamage.intersect(element->m_data.box.x, element->m_data.box.y, element->m_data.box.width, element->m_data.box.height); - - // While renderTextureInternalWithDamage will clip the blur as well, - // clipping texDamage here allows blur generation to be optimized. - if (!element->m_data.clipRegion.empty()) - texDamage.intersect(element->m_data.clipRegion); - - if (texDamage.empty()) - return; - - m_renderData.renderModif.applyToRegion(texDamage); - - element->m_data.damage = texDamage; - - // amazing hack: the surface has an opaque region! - const auto& surface = element->m_data.surface; - const auto& box = element->m_data.box; - CRegion inverseOpaque; - if (element->m_data.a >= 1.f && surface && std::round(surface->m_current.size.x * m_renderData.pMonitor->m_scale) == box.w && - std::round(surface->m_current.size.y * m_renderData.pMonitor->m_scale) == box.h) { - pixman_box32_t surfbox = {0, 0, surface->m_current.size.x * surface->m_current.scale, surface->m_current.size.y * surface->m_current.scale}; - inverseOpaque = surface->m_current.opaque; - inverseOpaque.invert(&surfbox).intersect(0, 0, surface->m_current.size.x * surface->m_current.scale, surface->m_current.size.y * surface->m_current.scale); +void IHyprRenderer::draw(const CRectPassElement::SRectData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CRectPassElement>(data), damage); +} - if (inverseOpaque.empty()) { - element->m_data.blur = false; - draw(element, damage); - m_renderData.clipBox = {}; - return; - } - } else - inverseOpaque = {0, 0, element->m_data.box.width, element->m_data.box.height}; - - inverseOpaque.scale(m_renderData.pMonitor->m_scale); - element->m_data.blockBlurOptimization = - element->m_data.blockBlurOptimization.value_or(false) || !shouldUseNewBlurOptimizations(element->m_data.currentLS.lock(), m_renderData.currentWindow.lock()); - - // vvv TODO: layered blur fbs? - if (element->m_data.blockBlurOptimization.value_or(false)) { - inverseOpaque.translate(box.pos()); - m_renderData.renderModif.applyToRegion(inverseOpaque); - inverseOpaque.intersect(element->m_data.damage); - element->m_data.blurredBG = blurMainFramebuffer(element->m_data.a, &inverseOpaque); - m_renderData.currentFB->bind(); - } else - element->m_data.blurredBG = m_renderData.pMonitor->m_blurFB ? m_renderData.pMonitor->m_blurFB->getTexture() : nullptr; +void IHyprRenderer::draw(const CRendererHintsPassElement::SData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CRendererHintsPassElement>(data), damage); +} - draw(element, damage); - } else - draw(element, damage); +void IHyprRenderer::draw(const CShadowPassElement::SShadowData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CShadowPassElement>(data), damage); +} - m_renderData.clipBox = {}; +void IHyprRenderer::draw(const CSurfacePassElement::SRenderData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CSurfacePassElement>(data), damage); } -void IHyprRenderer::drawTexMatte(CTextureMatteElement* element, const CRegion& damage) { - if (m_renderData.damage.empty()) - return; +void IHyprRenderer::draw(const CTexPassElement::SRenderData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CTexPassElement>(data), damage); +} - const auto m_data = element->m_data; - if (m_data.disableTransformAndModify) { - pushMonitorTransformEnabled(true); - m_renderData.renderModif.enabled = false; - draw(element, damage); - m_renderData.renderModif.enabled = true; - popMonitorTransformEnabled(); - } else - draw(element, damage); +void IHyprRenderer::draw(const CTextureMatteElement::STextureMatteData& data, const CRegion& damage) { + elementRenderer()->drawElement(makeUnique<CTextureMatteElement>(data), damage); } -void IHyprRenderer::draw(WP<IPassElement> element, const CRegion& damage) { - if (!element) - return; +void IHyprRenderer::bindFB(SP<IFramebuffer> fb) { + fb->bind(); + m_renderData.currentFB = fb; +} - switch (element->type()) { - case EK_BORDER: draw(dc<CBorderPassElement*>(element.get()), damage); break; - case EK_CLEAR: draw(dc<CClearPassElement*>(element.get()), damage); break; - case EK_FRAMEBUFFER: draw(dc<CFramebufferElement*>(element.get()), damage); break; - case EK_PRE_BLUR: drawPreBlur(dc<CPreBlurElement*>(element.get()), damage); break; - case EK_RECT: drawRect(dc<CRectPassElement*>(element.get()), damage); break; - case EK_HINTS: drawHints(dc<CRendererHintsPassElement*>(element.get()), damage); break; - case EK_SHADOW: draw(dc<CShadowPassElement*>(element.get()), damage); break; - case EK_INNER_GLOW: draw(dc<CInnerGlowPassElement*>(element.get()), damage); break; - case EK_SURFACE: preDrawSurface(dc<CSurfacePassElement*>(element.get()), damage); break; - case EK_TEXTURE: drawTex(dc<CTexPassElement*>(element.get()), damage); break; - case EK_TEXTURE_MATTE: drawTexMatte(dc<CTextureMatteElement*>(element.get()), damage); break; - default: Log::logger->log(Log::WARN, "Unimplimented draw for {}", element->passName()); - } +UP<CScopeGuard> IHyprRenderer::bindTempFB(SP<IFramebuffer> fb) { + const auto oldFB = m_renderData.currentFB; + bindFB(fb); + return makeUnique<CScopeGuard>([this, oldFB] { bindFB(oldFB); }); } bool IHyprRenderer::preBlurQueued(PHLMONITORREF pMonitor) { @@ -1668,9 +1378,7 @@ SP<ITexture> IHyprRenderer::loadAsset(const std::string& filename) { } SP<ITexture> IHyprRenderer::getBlurTexture(PHLMONITORREF pMonitor) { - if (!pMonitor->m_blurFB) - return nullptr; - return pMonitor->m_blurFB->getTexture(); + return pMonitor->resources()->m_blurFB->getTexture(); } bool IHyprRenderer::shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow) { @@ -1893,126 +1601,6 @@ void IHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) { } } -static std::optional<Vector2D> getSurfaceExpectedSize(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main) { - const auto CAN_USE_WINDOW = pWindow && main; - const auto WINDOW_SIZE_MISALIGN = CAN_USE_WINDOW && pWindow->getReportedSize() != pWindow->wlSurface()->resource()->m_current.size; - - if (pSurface->m_current.viewport.hasDestination) - return (pSurface->m_current.viewport.destination * pMonitor->m_scale).round(); - - if (pSurface->m_current.viewport.hasSource) - return (pSurface->m_current.viewport.source.size() * pMonitor->m_scale).round(); - - if (WINDOW_SIZE_MISALIGN) - return (pSurface->m_current.size * pMonitor->m_scale).round(); - - if (CAN_USE_WINDOW) - return (pWindow->getReportedSize() * pMonitor->m_scale).round(); - - return std::nullopt; -} - -void IHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize, - const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) { - if (!pWindow || !pWindow->m_isX11) { - static auto PEXPANDEDGES = CConfigValue<Hyprlang::INT>("render:expand_undersized_textures"); - - Vector2D uvTL; - Vector2D uvBR = Vector2D(1, 1); - - if (pSurface->m_current.viewport.hasSource) { - // we stretch it to dest. if no dest, to 1,1 - Vector2D const& bufferSize = pSurface->m_current.bufferSize; - auto const& bufferSource = pSurface->m_current.viewport.source; - - // calculate UV for the basic src_box. Assume dest == size. Scale to dest later - uvTL = Vector2D(bufferSource.x / bufferSize.x, bufferSource.y / bufferSize.y); - uvBR = Vector2D((bufferSource.x + bufferSource.width) / bufferSize.x, (bufferSource.y + bufferSource.height) / bufferSize.y); - - if (uvBR.x < 0.01f || uvBR.y < 0.01f) { - uvTL = Vector2D(); - uvBR = Vector2D(1, 1); - } - } - - if (projSize != Vector2D{} && fixMisalignedFSV1) { - // instead of nearest_neighbor (we will repeat / skip) - // just cut off / expand surface - const Vector2D PIXELASUV = Vector2D{1, 1} / pSurface->m_current.bufferSize; - const auto& BUFFER_SIZE = pSurface->m_current.bufferSize; - - // compute MISALIGN from the adjusted UV coordinates. - const Vector2D MISALIGNMENT = (uvBR - uvTL) * BUFFER_SIZE - projSize; - - if (MISALIGNMENT != Vector2D{}) - uvBR -= MISALIGNMENT * PIXELASUV; - } else { - // if the surface is smaller than our viewport, extend its edges. - // this will break if later on xdg geometry is hit, but we really try - // to let the apps know to NOT add CSD. Also if source is there. - // there is no way to fix this if that's the case - const auto MONITOR_WL_SCALE = std::ceil(pMonitor->m_scale); - const bool SCALE_UNAWARE = pMonitor->m_scale != 1.f && (MONITOR_WL_SCALE == pSurface->m_current.scale || !pSurface->m_current.viewport.hasDestination); - const auto EXPECTED_SIZE = getSurfaceExpectedSize(pWindow, pSurface, pMonitor, main).value_or((projSize * pMonitor->m_scale).round()); - - const auto RATIO = projSize / EXPECTED_SIZE; - if (!SCALE_UNAWARE || MONITOR_WL_SCALE == 1) { - if (*PEXPANDEDGES && !SCALE_UNAWARE && (RATIO.x > 1 || RATIO.y > 1)) { - const auto FIX = RATIO.clamp(Vector2D{1, 1}, Vector2D{1000000, 1000000}); - uvBR = uvBR * FIX; - } - - // FIXME: probably do this for in anims on all views... - const auto SHOULD_SKIP = !pWindow || pWindow->m_animatingIn; - if (!SHOULD_SKIP && (RATIO.x < 1 || RATIO.y < 1)) { - const auto FIX = RATIO.clamp(Vector2D{0.0001, 0.0001}, Vector2D{1, 1}); - uvBR = uvBR * FIX; - } - } - } - - m_renderData.primarySurfaceUVTopLeft = uvTL; - m_renderData.primarySurfaceUVBottomRight = uvBR; - - if (m_renderData.primarySurfaceUVTopLeft == Vector2D() && m_renderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) { - // No special UV mods needed - m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); - m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); - } - - if (!main || !pWindow) - return; - - // FIXME: this doesn't work. We always set MAXIMIZED anyways, so this doesn't need to work, but it's problematic. - - // CBox geom = pWindow->m_xdgSurface->m_current.geometry; - - // // Adjust UV based on the xdg_surface geometry - // if (geom.x != 0 || geom.y != 0 || geom.w != 0 || geom.h != 0) { - // const auto XPERC = geom.x / pSurface->m_current.size.x; - // const auto YPERC = geom.y / pSurface->m_current.size.y; - // const auto WPERC = (geom.x + geom.w ? geom.w : pSurface->m_current.size.x) / pSurface->m_current.size.x; - // const auto HPERC = (geom.y + geom.h ? geom.h : pSurface->m_current.size.y) / pSurface->m_current.size.y; - - // const auto TOADDTL = Vector2D(XPERC * (uvBR.x - uvTL.x), YPERC * (uvBR.y - uvTL.y)); - // uvBR = uvBR - Vector2D((1.0 - WPERC) * (uvBR.x - uvTL.x), (1.0 - HPERC) * (uvBR.y - uvTL.y)); - // uvTL = uvTL + TOADDTL; - // } - - m_renderData.primarySurfaceUVTopLeft = uvTL; - m_renderData.primarySurfaceUVBottomRight = uvBR; - - if (m_renderData.primarySurfaceUVTopLeft == Vector2D() && m_renderData.primarySurfaceUVBottomRight == Vector2D(1, 1)) { - // No special UV mods needed - m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); - m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); - } - } else { - m_renderData.primarySurfaceUVTopLeft = Vector2D(-1, -1); - m_renderData.primarySurfaceUVBottomRight = Vector2D(-1, -1); - } -} - bool IHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode, SP<IHLBuffer> buffer, SP<IFramebuffer> fb, bool simple) { m_renderPass.clear(); m_renderMode = mode; @@ -2023,44 +1611,11 @@ bool IHyprRenderer::beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMod else setProjectionType(RPT_MONITOR); - if (!simple) { - const auto DRM_FORMAT = fb ? fb->m_drmFormat : pMonitor->m_output->state->state().drmFormat; - - // ensure a framebuffer for the monitor exists - if (!m_renderData.pMonitor->m_offloadFB || m_renderData.pMonitor->m_offloadFB->m_size != pMonitor->m_pixelSize || - DRM_FORMAT != m_renderData.pMonitor->m_offloadFB->m_drmFormat) { - if (!m_renderData.pMonitor->m_stencilTex || m_renderData.pMonitor->m_stencilTex->m_size != pMonitor->m_pixelSize) - m_renderData.pMonitor->m_stencilTex = createStencilTexture(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y); - - m_renderData.pMonitor->m_offloadFB = createFB("offload"); - m_renderData.pMonitor->m_mirrorFB = createFB("mirror"); - m_renderData.pMonitor->m_mirrorSwapFB = createFB("mirrorSwap"); - m_renderData.pMonitor->m_offMainFB = createFB("offMain"); - m_renderData.pMonitor->m_monitorMirrorFB = createFB("monitorMirror"); - m_renderData.pMonitor->m_blurFB = createFB("blur"); - - // add stencil before FB allocation to avoid reallocs - m_renderData.pMonitor->m_offloadFB->addStencil(m_renderData.pMonitor->m_stencilTex); - m_renderData.pMonitor->m_mirrorFB->addStencil(m_renderData.pMonitor->m_stencilTex); - m_renderData.pMonitor->m_mirrorSwapFB->addStencil(m_renderData.pMonitor->m_stencilTex); - m_renderData.pMonitor->m_offMainFB->addStencil(m_renderData.pMonitor->m_stencilTex); - - m_renderData.pMonitor->m_offloadFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); - m_renderData.pMonitor->m_mirrorFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); - m_renderData.pMonitor->m_mirrorSwapFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); - m_renderData.pMonitor->m_offMainFB->alloc(pMonitor->m_pixelSize.x, pMonitor->m_pixelSize.y, DRM_FORMAT); - } - } - - const bool HAS_MIRROR_FB = g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB && g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->isAllocated(); - const bool NEEDS_COPY_FB = needsACopyFB(g_pHyprRenderer->m_renderData.pMonitor.lock()); + const bool HAS_MIRROR_FB = g_pHyprRenderer->m_renderData.pMonitor->resources()->hasMirrorFB(); + const bool NEEDS_COPY_FB = g_pHyprRenderer->m_renderData.pMonitor->needsACopyFB(); if (HAS_MIRROR_FB && !NEEDS_COPY_FB) - g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->release(); - else if (!HAS_MIRROR_FB && NEEDS_COPY_FB && g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB) - g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->alloc(g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, - g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y, - g_pHyprRenderer->m_renderData.pMonitor->m_output->state->state().drmFormat); + g_pHyprRenderer->m_renderData.pMonitor->resources()->mirrorFB()->release(); if (m_renderMode == RENDER_MODE_FULL_FAKE) return beginFullFakeRenderInternal(pMonitor, damage, fb, simple); @@ -2150,9 +1705,10 @@ Mat3x3 IHyprRenderer::projectBoxToTarget(const CBox& box, std::optional<eTransfo SP<ITexture> IHyprRenderer::blurMainFramebuffer(float a, CRegion* originalDamage) { if (!m_renderData.currentFB->getTexture()) { Log::logger->log(Log::ERR, "BUG THIS: null fb texture while attempting to blur main fb?! (introspection off?!)"); - return m_renderData.pMonitor->m_mirrorFB->getTexture(); // return something to sample from at least + return m_renderData.pMonitor->resources()->m_blurFB->getTexture(); // return something to sample from at least } + auto guard = bindTempFB(m_renderData.currentFB); // blurFramebuffer messes with FB bindings return blurFramebuffer(m_renderData.currentFB, a, originalDamage); } @@ -2161,25 +1717,25 @@ void IHyprRenderer::preBlurForCurrentMonitor(CRegion* fakeDamage) { const auto blurredTex = blurMainFramebuffer(1, fakeDamage); // render onto blurFB - if (!m_renderData.pMonitor->m_blurFB) - return; - m_renderData.pMonitor->m_blurFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y, m_renderData.pMonitor->m_output->state->state().drmFormat); - m_renderData.pMonitor->m_blurFB->bind(); + auto guard = bindTempFB(m_renderData.pMonitor->resources()->m_blurFB); + const auto SAVE_TRANSFORM = blurredTex->m_transform; + blurredTex->m_transform = Math::wlTransformToHyprutils(Math::invertTransform(m_renderData.pMonitor->m_transform)); - draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{{0, 0, 0, 0}}), {}); + draw(CClearPassElement::SClearData{{0, 0, 0, 0}}); pushMonitorTransformEnabled(true); - draw(makeUnique<CTexPassElement>(CTexPassElement::SRenderData{ - .tex = blurredTex, - .box = CBox{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y}, - .damage = *fakeDamage, - }), - *fakeDamage); // .noAA = true + draw( + CTexPassElement::SRenderData{ + .tex = blurredTex, + .box = CBox{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y}, + .damage = *fakeDamage, + }, + *fakeDamage); // .noAA = true popMonitorTransformEnabled(); - m_renderData.currentFB->bind(); + blurredTex->m_transform = SAVE_TRANSFORM; } static bool isSDR2HDR(const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription) { @@ -2187,7 +1743,9 @@ static bool isSDR2HDR(const NColorManagement::SImageDescription& imageDescriptio return (imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB || imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22) && (targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ || - targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_HLG); + targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_HLG || + (targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_EXT_LINEAR && + g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ)); } static bool isHDR2SDR(const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription) { @@ -2228,8 +1786,7 @@ SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescripti auto matrix = imageDescription->getPrimaries()->convertMatrix(targetImageDescription->getPrimaries()); auto toXYZ = targetImageDescription->getPrimaries()->value().toXYZ(); - const bool needsMod = (imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_SRGB || imageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_GAMMA22) && - targetImageDescription->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ && + const bool needsMod = needsSDRmod && ((m_renderData.pMonitor->m_sdrSaturation > 0 && m_renderData.pMonitor->m_sdrSaturation != 1.0f) || (m_renderData.pMonitor->m_sdrBrightness > 0 && m_renderData.pMonitor->m_sdrBrightness != 1.0f)); @@ -2255,8 +1812,12 @@ SCMSettings IHyprRenderer::getCMSettings(const NColorManagement::PImageDescripti } void IHyprRenderer::renderMirrored() { - auto monitor = m_renderData.pMonitor; - auto mirrored = monitor->m_mirrorOf; + auto monitor = m_renderData.pMonitor; + auto mirrored = monitor->m_mirrorOf; + + // saveBufferForMirror should create it + if (!mirrored->resources()->hasMirrorFB()) + return; const double scale = std::min(monitor->m_transformedSize.x / mirrored->m_transformedSize.x, monitor->m_transformedSize.y / mirrored->m_transformedSize.y); CBox monbox = {0, 0, mirrored->m_transformedSize.x * scale, mirrored->m_transformedSize.y * scale}; @@ -2267,17 +1828,12 @@ void IHyprRenderer::renderMirrored() { monbox.x = (monitor->m_transformedSize.x - monbox.w) / 2; monbox.y = (monitor->m_transformedSize.y - monbox.h) / 2; - if (!monitor->m_monitorMirrorFB) - monitor->m_monitorMirrorFB = createFB("monitorMirror"); - - const auto PFB = mirrored->m_monitorMirrorFB; - if (!PFB || !PFB->isAllocated() || !PFB->getTexture()) - return; + const auto MIRROR_TEX = mirrored->resources()->getMirrorTexture(); m_renderPass.add(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)})); CTexPassElement::SRenderData data; - data.tex = PFB->getTexture(); + data.tex = MIRROR_TEX; data.box = monbox; data.useMirrorProjection = true; @@ -3354,7 +2910,7 @@ void IHyprRenderer::makeSnapshot(PHLWINDOW pWindow) { m_bRenderingSnapshot = true; - draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); + draw(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}); startRenderPass(); Log::logger->log(Log::DEBUG, "renderer: cleared a snapshot of {:x}", rc<uintptr_t>(pWindow.get())); @@ -3395,7 +2951,7 @@ void IHyprRenderer::makeSnapshot(PHLLS pLayer) { m_bRenderingSnapshot = true; - draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); + draw(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}); startRenderPass(); Log::logger->log(Log::DEBUG, "renderer: cleared a snapshot of layer {:x}", rc<uintptr_t>(pLayer.get())); @@ -3437,7 +2993,7 @@ void IHyprRenderer::makeSnapshot(WP<Desktop::View::CPopup> popup) { m_bRenderingSnapshot = true; - draw(makeUnique<CClearPassElement>(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); + draw(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}); CSurfacePassElement::SRenderData renderdata; renderdata.pos = popup->coordsGlobal(); @@ -3613,7 +3169,9 @@ NColorManagement::PImageDescription IHyprRenderer::workBufferImageDescription() // const auto sdrEOTF = NTransferFunction::fromConfig(IS_MONITOR_ICC); // const auto CHOSEN_SDR_EOTF = sdrEOTF != NTransferFunction::TF_SRGB ? NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22 : NColorManagement::CM_TRANSFER_FUNCTION_SRGB; - return m_renderData.pMonitor->m_imageDescription; //CImageDescription::from(NColorManagement::SImageDescription{.transferFunction = CHOSEN_SDR_EOTF}); + return m_renderData.pMonitor->useFP16() ? + LINEAR_IMAGE_DESCRIPTION : + m_renderData.pMonitor->m_imageDescription; //CImageDescription::from(NColorManagement::SImageDescription{.transferFunction = CHOSEN_SDR_EOTF}); } bool IHyprRenderer::shouldBlur(PHLLS ls) { @@ -3700,7 +3258,3 @@ SP<ITexture> IHyprRenderer::renderSplash(const std::function<SP<ITexture>(const cairo_destroy(CAIRO); return tex; } - -bool IHyprRenderer::needsACopyFB(PHLMONITOR mon) { - return !mon->m_mirrors.empty() || Screenshare::mgr()->isOutputBeingSSd(mon); -} |
