summaryrefslogtreecommitdiff
path: root/src/render/Renderer.cpp
diff options
context:
space:
mode:
authorUjinT34 <41110182+UjinT34@users.noreply.github.com>2026-03-29 00:41:45 +0300
committerGitHub <noreply@github.com>2026-03-28 21:41:45 +0000
commit38a7f03cf0e5ee116794a78581634ba3dab508fa (patch)
tree969891411b2af4e437a183004018cfc359a3057e /src/render/Renderer.cpp
parentef2e8dfd5f7e6ee55fa7bc48e44974e64938d14a (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.cpp608
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);
-}