summaryrefslogtreecommitdiff
path: root/src/render
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
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')
-rw-r--r--src/render/ElementRenderer.cpp485
-rw-r--r--src/render/ElementRenderer.hpp48
-rw-r--r--src/render/Framebuffer.cpp41
-rw-r--r--src/render/Framebuffer.hpp55
-rw-r--r--src/render/GLRenderer.cpp152
-rw-r--r--src/render/GLRenderer.hpp98
-rw-r--r--src/render/OpenGL.cpp267
-rw-r--r--src/render/OpenGL.hpp623
-rw-r--r--src/render/Renderbuffer.cpp2
-rw-r--r--src/render/Renderbuffer.hpp34
-rw-r--r--src/render/Renderer.cpp608
-rw-r--r--src/render/Renderer.hpp604
-rw-r--r--src/render/Shader.cpp2
-rw-r--r--src/render/ShaderLoader.cpp3
-rw-r--r--src/render/ShaderLoader.hpp1
-rw-r--r--src/render/SyncFDManager.cpp16
-rw-r--r--src/render/SyncFDManager.hpp20
-rw-r--r--src/render/Texture.cpp2
-rw-r--r--src/render/Texture.hpp102
-rw-r--r--src/render/Transformer.hpp2
-rw-r--r--src/render/decorations/CHyprDropShadowDecoration.cpp60
-rw-r--r--src/render/decorations/CHyprGroupBarDecoration.hpp12
-rw-r--r--src/render/decorations/CHyprInnerGlowDecoration.cpp3
-rw-r--r--src/render/gl/GLElementRenderer.cpp138
-rw-r--r--src/render/gl/GLElementRenderer.hpp22
-rw-r--r--src/render/gl/GLFramebuffer.cpp49
-rw-r--r--src/render/gl/GLFramebuffer.hpp38
-rw-r--r--src/render/gl/GLRenderbuffer.cpp4
-rw-r--r--src/render/gl/GLRenderbuffer.hpp22
-rw-r--r--src/render/gl/GLTexture.cpp2
-rw-r--r--src/render/gl/GLTexture.hpp87
-rw-r--r--src/render/pass/Pass.cpp71
-rw-r--r--src/render/pass/Pass.hpp60
-rw-r--r--src/render/pass/PassElement.cpp4
-rw-r--r--src/render/pass/PassElement.hpp6
-rw-r--r--src/render/pass/RendererHintsPassElement.hpp5
-rw-r--r--src/render/pass/SurfacePassElement.hpp6
-rw-r--r--src/render/pass/TexPassElement.hpp8
-rw-r--r--src/render/pass/TextureMatteElement.hpp12
-rw-r--r--src/render/shaders/glsl/blurFinish.glsl22
-rw-r--r--src/render/shaders/glsl/blurfinish.frag14
-rw-r--r--src/render/shaders/glsl/border.frag38
-rw-r--r--src/render/shaders/glsl/border.glsl63
-rw-r--r--src/render/shaders/glsl/cm_helpers.glsl25
-rw-r--r--src/render/shaders/glsl/defines.h6
-rw-r--r--src/render/shaders/glsl/quad.frag6
-rw-r--r--src/render/shaders/glsl/rgbamatte.frag14
-rw-r--r--src/render/shaders/glsl/shadow.frag37
-rw-r--r--src/render/shaders/glsl/shadow.glsl59
-rw-r--r--src/render/shaders/glsl/surface.frag51
-rw-r--r--src/render/types.hpp131
51 files changed, 2332 insertions, 1908 deletions
diff --git a/src/render/ElementRenderer.cpp b/src/render/ElementRenderer.cpp
new file mode 100644
index 00000000..8d2dedf7
--- /dev/null
+++ b/src/render/ElementRenderer.cpp
@@ -0,0 +1,485 @@
+#include "ElementRenderer.hpp"
+#include "Renderer.hpp"
+#include "../layout/LayoutManager.hpp"
+#include "../desktop/view/Window.hpp"
+#include <hyprutils/memory/SharedPtr.hpp>
+#include <hyprutils/memory/UniquePtr.hpp>
+#include <hyprutils/utils/ScopeGuard.hpp>
+
+using namespace Render;
+
+void IElementRenderer::drawElement(WP<IPassElement> element, const CRegion& damage) {
+ if (!element)
+ return;
+
+ switch (element->type()) {
+ case EK_BORDER: draw(dynamicPointerCast<CBorderPassElement>(element), damage); break;
+ case EK_CLEAR: draw(dynamicPointerCast<CClearPassElement>(element), damage); break;
+ case EK_FRAMEBUFFER: draw(dynamicPointerCast<CFramebufferElement>(element), damage); break;
+ case EK_PRE_BLUR: drawPreBlur(dynamicPointerCast<CPreBlurElement>(element), damage); break;
+ case EK_RECT: drawRect(dynamicPointerCast<CRectPassElement>(element), damage); break;
+ case EK_HINTS: drawHints(dynamicPointerCast<CRendererHintsPassElement>(element), damage); break;
+ case EK_SHADOW: draw(dynamicPointerCast<CShadowPassElement>(element), damage); break;
+ case EK_INNER_GLOW: draw(dynamicPointerCast<CInnerGlowPassElement>(element), damage); break;
+ case EK_SURFACE: preDrawSurface(dynamicPointerCast<CSurfacePassElement>(element), damage); break;
+ case EK_TEXTURE: drawTex(dynamicPointerCast<CTexPassElement>(element), damage); break;
+ case EK_TEXTURE_MATTE: drawTexMatte(dynamicPointerCast<CTextureMatteElement>(element), damage); break;
+ case EK_CUSTOM: drawCustom(element, damage); break;
+ default: Log::logger->log(Log::WARN, "Unimplimented draw for {}", element->passName());
+ }
+}
+
+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 IElementRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResource> pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize,
+ const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) {
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+
+ 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);
+ }
+}
+
+void IElementRenderer::drawRect(WP<CRectPassElement> element, const CRegion& damage) {
+ auto& data = element->m_data;
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+
+ if (data.box.w <= 0 || data.box.h <= 0)
+ 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 = {};
+}
+
+void IElementRenderer::drawHints(WP<CRendererHintsPassElement> element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ if (m_data.renderModif.has_value())
+ g_pHyprRenderer->m_renderData.renderModif = *m_data.renderModif;
+}
+
+void IElementRenderer::drawPreBlur(WP<CPreBlurElement> element, const CRegion& damage) {
+ TRACY_GPU_ZONE("RenderPreBlurForCurrentMonitor");
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+
+ 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 IElementRenderer::drawSurface(WP<CSurfacePassElement> element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+
+ Hyprutils::Utils::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)
+ g_pHyprRenderer->blend(false);
+ else
+ g_pHyprRenderer->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)
+ drawElement(makeShared<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
+ drawElement(makeShared<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)
+ drawElement(makeShared<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
+ drawElement(makeShared<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));
+ }
+
+ g_pHyprRenderer->blend(true);
+};
+
+void IElementRenderer::preDrawSurface(WP<CSurfacePassElement> element, const CRegion& damage) {
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+ m_renderData.clipBox = element->m_data.clipBox;
+ m_renderData.useNearestNeighbor = element->m_data.useNearestNeighbor;
+ g_pHyprRenderer->pushMonitorTransformEnabled(element->m_data.flipEndFrame);
+ m_renderData.currentWindow = element->m_data.pWindow;
+
+ drawSurface(element, damage);
+
+ if (!g_pHyprRenderer->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())
+ g_pHyprRenderer->m_usedAsyncBuffers.emplace_back(element->m_data.surface->m_current.buffer);
+
+ m_renderData.clipBox = {};
+ m_renderData.useNearestNeighbor = false;
+ g_pHyprRenderer->popMonitorTransformEnabled();
+ m_renderData.currentWindow.reset();
+}
+
+void IElementRenderer::drawTex(WP<CTexPassElement> element, const CRegion& damage) {
+ auto& m_renderData = g_pHyprRenderer->m_renderData;
+ if (!element->m_data.clipBox.empty())
+ m_renderData.clipBox = element->m_data.clipBox;
+
+ g_pHyprRenderer->pushMonitorTransformEnabled(element->m_data.flipEndFrame);
+ if (element->m_data.useMirrorProjection)
+ g_pHyprRenderer->setProjectionType(RPT_MIRROR);
+
+ m_renderData.surface = element->m_data.surface;
+
+ Hyprutils::Utils::CScopeGuard x = {[useMirrorProjection = element->m_data.useMirrorProjection]() {
+ g_pHyprRenderer->popMonitorTransformEnabled();
+ if (useMirrorProjection)
+ g_pHyprRenderer->setProjectionType(RPT_MONITOR);
+ g_pHyprRenderer->m_renderData.surface.reset();
+ g_pHyprRenderer->m_renderData.clipBox = {};
+ }};
+
+ 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);
+
+ if (inverseOpaque.empty()) {
+ element->m_data.blur = false;
+ draw(element, damage);
+ 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) ||
+ !g_pHyprRenderer->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 = g_pHyprRenderer->blurMainFramebuffer(element->m_data.a, &inverseOpaque);
+ } else
+ element->m_data.blurredBG = m_renderData.pMonitor->resources()->m_blurFB->getTexture();
+
+ draw(element, damage);
+ } else
+ draw(element, damage);
+}
+
+void IElementRenderer::drawTexMatte(WP<CTextureMatteElement> element, const CRegion& damage) {
+ if (g_pHyprRenderer->m_renderData.damage.empty())
+ return;
+
+ const auto m_data = element->m_data;
+ if (m_data.disableTransformAndModify) {
+ g_pHyprRenderer->pushMonitorTransformEnabled(true);
+ g_pHyprRenderer->m_renderData.renderModif.enabled = false;
+ draw(element, damage);
+ g_pHyprRenderer->m_renderData.renderModif.enabled = true;
+ g_pHyprRenderer->popMonitorTransformEnabled();
+ } else
+ draw(element, damage);
+}
+
+void IElementRenderer::drawCustom(WP<IPassElement> element, const CRegion& damage) {
+ const auto& elements = element->draw();
+ for (const auto& el : elements) {
+ drawElement(el, damage);
+ }
+}
diff --git a/src/render/ElementRenderer.hpp b/src/render/ElementRenderer.hpp
new file mode 100644
index 00000000..ed92b06f
--- /dev/null
+++ b/src/render/ElementRenderer.hpp
@@ -0,0 +1,48 @@
+#pragma once
+
+#include "./pass/BorderPassElement.hpp"
+#include "./pass/ClearPassElement.hpp"
+#include "./pass/FramebufferElement.hpp"
+#include "./pass/PreBlurElement.hpp"
+#include "./pass/RectPassElement.hpp"
+#include "./pass/RendererHintsPassElement.hpp"
+#include "./pass/ShadowPassElement.hpp"
+#include "./pass/SurfacePassElement.hpp"
+#include "./pass/TexPassElement.hpp"
+#include "./pass/TextureMatteElement.hpp"
+#include "./pass/InnerGlowPassElement.hpp"
+#include <hyprutils/math/Region.hpp>
+
+namespace Render {
+ class IElementRenderer {
+ public:
+ IElementRenderer() = default;
+ virtual ~IElementRenderer() = default;
+
+ void drawElement(WP<IPassElement> element, const CRegion& damage);
+
+ protected:
+ virtual void draw(WP<CBorderPassElement> element, const CRegion& damage) = 0;
+ virtual void draw(WP<CClearPassElement> element, const CRegion& damage) = 0;
+ virtual void draw(WP<CFramebufferElement> element, const CRegion& damage) = 0;
+ virtual void draw(WP<CPreBlurElement> element, const CRegion& damage) = 0;
+ virtual void draw(WP<CRectPassElement> element, const CRegion& damage) = 0;
+ virtual void draw(WP<CShadowPassElement> element, const CRegion& damage) = 0;
+ virtual void draw(WP<CInnerGlowPassElement> element, const CRegion& damage) = 0;
+ virtual void draw(WP<CTexPassElement> element, const CRegion& damage) = 0;
+ virtual void draw(WP<CTextureMatteElement> element, const CRegion& damage) = 0;
+
+ private:
+ void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, PHLMONITOR pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {},
+ bool fixMisalignedFSV1 = false);
+
+ void drawRect(WP<CRectPassElement> element, const CRegion& damage);
+ void drawHints(WP<CRendererHintsPassElement> element, const CRegion& damage);
+ void drawPreBlur(WP<CPreBlurElement> element, const CRegion& damage);
+ void drawSurface(WP<CSurfacePassElement> element, const CRegion& damage);
+ void preDrawSurface(WP<CSurfacePassElement> element, const CRegion& damage);
+ void drawTex(WP<CTexPassElement> element, const CRegion& damage);
+ void drawTexMatte(WP<CTextureMatteElement> element, const CRegion& damage);
+ void drawCustom(WP<IPassElement> element, const CRegion& damage);
+ };
+}
diff --git a/src/render/Framebuffer.cpp b/src/render/Framebuffer.cpp
index b2ff7e68..47a466c1 100644
--- a/src/render/Framebuffer.cpp
+++ b/src/render/Framebuffer.cpp
@@ -1,16 +1,23 @@
#include "Framebuffer.hpp"
+#include "helpers/Format.hpp"
+#include "helpers/cm/ColorManagement.hpp"
+
+using namespace Render;
IFramebuffer::IFramebuffer(const std::string& name) : m_name(name) {}
-bool IFramebuffer::alloc(int w, int h, uint32_t format) {
+bool IFramebuffer::alloc(int w, int h, DRMFormat format) {
RASSERT((w > 0 && h > 0), "cannot alloc a FB with negative / zero size! (attempted {}x{})", w, h);
- const bool sizeChanged = (m_size != Vector2D(w, h));
- const bool formatChanged = (format != m_drmFormat);
+ const bool sizeChanged = m_size != Vector2D(w, h);
+ const bool formatChanged = format != m_drmFormat;
if (m_fbAllocated && !sizeChanged && !formatChanged)
return true;
+ if (sizeChanged || formatChanged)
+ m_tex.reset();
+
m_size = {w, h};
m_drmFormat = format;
m_fbAllocated = internalAlloc(w, h, format);
@@ -25,6 +32,34 @@ SP<ITexture> IFramebuffer::getTexture() {
return m_tex;
}
+SP<ITexture> IFramebuffer::getMirrorTexture() {
+ return m_mirrorTex;
+}
+
SP<ITexture> IFramebuffer::getStencilTex() {
return m_stencilTex;
}
+
+void IFramebuffer::enableMirror(SP<ITexture> tex) {
+ if (!tex || tex == m_mirrorTex)
+ return;
+ m_mirrorTex = tex;
+ m_fbAllocated = internalAlloc(m_size.x, m_size.y, m_drmFormat);
+}
+
+void IFramebuffer::disableMirror() {
+ if (m_mirrorTex) {
+ m_mirrorTex.reset();
+ m_fbAllocated = internalAlloc(m_size.x, m_size.y, m_drmFormat);
+ }
+}
+
+NColorManagement::PImageDescription IFramebuffer::imageDescription() {
+ return m_tex ? m_tex->m_imageDescription : m_imageDescription;
+}
+
+void IFramebuffer::setImageDescription(NColorManagement::PImageDescription desc) {
+ m_imageDescription = desc;
+ if (m_tex)
+ m_tex->m_imageDescription = desc;
+}
diff --git a/src/render/Framebuffer.hpp b/src/render/Framebuffer.hpp
index 7e33f227..215e5ed9 100644
--- a/src/render/Framebuffer.hpp
+++ b/src/render/Framebuffer.hpp
@@ -3,38 +3,49 @@
#include "../defines.hpp"
#include "../helpers/Format.hpp"
#include "Texture.hpp"
+#include "../helpers/cm/ColorManagement.hpp"
#include <cstdint>
#include <drm_fourcc.h>
class CHLBufferReference;
-class IFramebuffer {
- public:
- IFramebuffer() = default;
- IFramebuffer(const std::string& name);
- virtual ~IFramebuffer() = default;
+namespace Render {
+ class IFramebuffer {
+ public:
+ IFramebuffer() = default;
+ IFramebuffer(const std::string& name);
+ virtual ~IFramebuffer() = default;
- virtual bool alloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888);
- virtual void release() = 0;
- virtual bool readPixels(CHLBufferReference buffer, uint32_t offsetX = 0, uint32_t offsetY = 0, uint32_t width = 0, uint32_t height = 0) = 0;
+ virtual bool alloc(int w, int h, DRMFormat format = DRM_FORMAT_ARGB8888);
+ virtual void release() = 0;
+ virtual bool readPixels(CHLBufferReference buffer, uint32_t offsetX = 0, uint32_t offsetY = 0, uint32_t width = 0, uint32_t height = 0) = 0;
- virtual void bind() = 0;
+ virtual void bind() = 0;
- bool isAllocated();
- SP<ITexture> getTexture();
- SP<ITexture> getStencilTex();
+ bool isAllocated();
+ SP<ITexture> getTexture();
+ SP<ITexture> getMirrorTexture();
+ SP<ITexture> getStencilTex();
+ void enableMirror(SP<ITexture> tex);
+ void disableMirror();
+ NColorManagement::PImageDescription imageDescription();
+ void setImageDescription(NColorManagement::PImageDescription desc);
- virtual void addStencil(SP<ITexture> tex) = 0;
+ virtual void addStencil(SP<ITexture> tex) = 0;
- Vector2D m_size;
- DRMFormat m_drmFormat = DRM_FORMAT_INVALID;
+ Vector2D m_size;
+ DRMFormat m_drmFormat = DRM_FORMAT_INVALID;
- protected:
- virtual bool internalAlloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888) = 0;
+ protected:
+ virtual bool internalAlloc(int w, int h, DRMFormat format = DRM_FORMAT_ARGB8888) = 0;
- SP<ITexture> m_tex;
- bool m_fbAllocated = false;
+ SP<ITexture> m_tex;
+ SP<ITexture> m_mirrorTex;
+ bool m_fbAllocated = false;
- SP<ITexture> m_stencilTex;
- std::string m_name; // name for logging
-};
+ SP<ITexture> m_stencilTex;
+ std::string m_name; // name for logging
+
+ NColorManagement::PImageDescription m_imageDescription;
+ };
+}
diff --git a/src/render/GLRenderer.cpp b/src/render/GLRenderer.cpp
index afef2ba0..77fffd25 100644
--- a/src/render/GLRenderer.cpp
+++ b/src/render/GLRenderer.cpp
@@ -12,30 +12,35 @@
#include "../debug/HyprDebugOverlay.hpp"
#include "../helpers/Monitor.hpp"
#include "pass/TexPassElement.hpp"
-#include "pass/ClearPassElement.hpp"
-#include "pass/RectPassElement.hpp"
#include "pass/SurfacePassElement.hpp"
#include "../debug/log/Logger.hpp"
#include "../protocols/types/ContentType.hpp"
#include "OpenGL.hpp"
#include "Renderer.hpp"
-#include "gl/GLFramebuffer.hpp"
-#include "gl/GLTexture.hpp"
-#include "decorations/CHyprDropShadowDecoration.hpp"
+#include "./gl/GLElementRenderer.hpp"
+#include "./gl/GLFramebuffer.hpp"
+#include "./gl/GLTexture.hpp"
#include <cstdint>
#include <hyprutils/memory/SharedPtr.hpp>
+#include <hyprutils/memory/UniquePtr.hpp>
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Utils;
using namespace Hyprutils::OS;
using enum NContentType::eContentType;
using namespace NColorManagement;
+using namespace Render;
+using namespace Render::GL;
extern "C" {
#include <xf86drm.h>
}
-CHyprGLRenderer::CHyprGLRenderer() : IHyprRenderer() {}
+CHyprGLRenderer::CHyprGLRenderer() : IHyprRenderer(), m_elementRenderer(makeUnique<CGLElementRenderer>()) {}
+
+IHyprRenderer::eType CHyprGLRenderer::type() {
+ return RT_GL;
+}
void CHyprGLRenderer::initRender() {
g_pHyprOpenGL->makeEGLCurrent();
@@ -57,7 +62,7 @@ bool CHyprGLRenderer::beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion&
initRender();
RASSERT(fb, "Cannot render FULL_FAKE without a provided fb!");
- fb->bind();
+ bindFB(fb);
if (simple)
g_pHyprOpenGL->beginSimple(pMonitor, damage, nullptr, fb);
else
@@ -119,7 +124,7 @@ void CHyprGLRenderer::endRender(const std::function<void()>& renderingDoneCallba
return;
}
- UP<CEGLSync> eglSync = CEGLSync::create();
+ auto eglSync = createSyncFDManager();
if LIKELY (eglSync && eglSync->isValid()) {
for (auto const& buf : m_usedAsyncBuffers) {
for (const auto& releaser : buf->m_syncReleasers) {
@@ -151,7 +156,7 @@ void CHyprGLRenderer::endRender(const std::function<void()>& renderingDoneCallba
}
}
-void CHyprGLRenderer::renderOffToMain(IFramebuffer* off) {
+void CHyprGLRenderer::renderOffToMain(SP<IFramebuffer> off) {
g_pHyprOpenGL->renderOffToMain(off);
}
@@ -160,6 +165,10 @@ SP<IRenderbuffer> CHyprGLRenderer::getOrCreateRenderbufferInternal(SP<Aquamarine
return makeShared<CGLRenderbuffer>(buffer, fmt);
}
+UP<ISyncFDManager> CHyprGLRenderer::createSyncFDManager() {
+ return CEGLSync::create();
+}
+
SP<ITexture> CHyprGLRenderer::createStencilTexture(const int width, const int height) {
g_pHyprOpenGL->makeEGLCurrent();
auto tex = makeShared<CGLTexture>();
@@ -282,127 +291,8 @@ bool CHyprGLRenderer::reloadShaders(const std::string& path) {
return g_pHyprOpenGL->initShaders(path);
}
-void CHyprGLRenderer::draw(CBorderPassElement* element, const CRegion& damage) {
- const auto m_data = element->m_data;
- if (m_data.hasGrad2)
- g_pHyprOpenGL->renderBorder(
- m_data.box, m_data.grad1, m_data.grad2, m_data.lerp,
- {.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
- else
- g_pHyprOpenGL->renderBorder(
- m_data.box, m_data.grad1,
- {.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
-};
-
-void CHyprGLRenderer::draw(CClearPassElement* element, const CRegion& damage) {
- g_pHyprOpenGL->clear(element->m_data.color);
-};
-
-void CHyprGLRenderer::draw(CFramebufferElement* element, const CRegion& damage) {
- const auto m_data = element->m_data;
- SP<IFramebuffer> fb = nullptr;
-
- if (m_data.main) {
- switch (m_data.framebufferID) {
- case FB_MONITOR_RENDER_MAIN: fb = g_pHyprRenderer->m_renderData.mainFB; break;
- case FB_MONITOR_RENDER_CURRENT: fb = g_pHyprRenderer->m_renderData.currentFB; break;
- case FB_MONITOR_RENDER_OUT: fb = g_pHyprRenderer->m_renderData.outFB; break;
- default: fb = nullptr;
- }
-
- if (!fb) {
- Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: main but null");
- return;
- }
-
- } else {
- switch (m_data.framebufferID) {
- case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB; break;
- case FB_MONITOR_RENDER_EXTRA_MIRROR: fb = m_renderData.pMonitor->m_mirrorFB; break;
- case FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP: fb = m_renderData.pMonitor->m_mirrorSwapFB; break;
- case FB_MONITOR_RENDER_EXTRA_OFF_MAIN: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB; break;
- case FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB; break;
- case FB_MONITOR_RENDER_EXTRA_BLUR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_blurFB; break;
- default: fb = nullptr;
- }
-
- if (!fb) {
- Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: not main but null");
- return;
- }
- }
-
- fb->bind();
-};
-
-void CHyprGLRenderer::draw(CPreBlurElement* element, const CRegion& damage) {
- auto dmg = damage;
- g_pHyprRenderer->preBlurForCurrentMonitor(&dmg);
-};
-
-void CHyprGLRenderer::draw(CRectPassElement* element, const CRegion& damage) {
- const auto m_data = element->m_data;
-
- if (m_data.color.a == 1.F || !m_data.blur)
- g_pHyprOpenGL->renderRect(m_data.box, m_data.color, {.damage = &damage, .round = m_data.round, .roundingPower = m_data.roundingPower});
- else
- g_pHyprOpenGL->renderRect(m_data.box, m_data.color,
- {.round = m_data.round, .roundingPower = m_data.roundingPower, .blur = true, .blurA = m_data.blurA, .xray = m_data.xray});
-};
-
-void CHyprGLRenderer::draw(CShadowPassElement* element, const CRegion& damage) {
- const auto m_data = element->m_data;
- m_data.deco->render(g_pHyprRenderer->m_renderData.pMonitor.lock(), m_data.a);
-};
-
-void CHyprGLRenderer::draw(CInnerGlowPassElement* element, const CRegion& damage) {
- const auto m_data = element->m_data;
- m_data.deco->render(g_pHyprRenderer->m_renderData.pMonitor.lock(), m_data.a);
-};
-
-void CHyprGLRenderer::draw(CTexPassElement* element, const CRegion& damage) {
- const auto m_data = element->m_data;
-
- g_pHyprOpenGL->renderTexture( //
- m_data.tex, m_data.box,
- {
- // blur settings for m_data.blur == true
- .blur = m_data.blur,
- .blurA = m_data.blurA,
- .overallA = m_data.overallA,
- .blockBlurOptimization = m_data.blockBlurOptimization.value_or(false),
- .blurredBG = m_data.blurredBG,
-
- // common settings
- .damage = m_data.damage.empty() ? &damage : &m_data.damage,
- .surface = m_data.surface,
- .a = m_data.a,
- .round = m_data.round,
- .roundingPower = m_data.roundingPower,
- .discardActive = m_data.discardActive,
- .allowCustomUV = m_data.allowCustomUV,
- .cmBackToSRGB = m_data.cmBackToSRGB,
- .cmBackToSRGBSource = m_data.cmBackToSRGBSource,
- .discardMode = m_data.ignoreAlpha.has_value() ? sc<uint32_t>(DISCARD_ALPHA) : m_data.discardMode,
- .discardOpacity = m_data.ignoreAlpha.has_value() ? *m_data.ignoreAlpha : m_data.discardOpacity,
- .clipRegion = m_data.clipRegion,
- .currentLS = m_data.currentLS,
-
- .primarySurfaceUVTopLeft = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft,
- .primarySurfaceUVBottomRight = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight,
- });
-};
-
-void CHyprGLRenderer::draw(CTextureMatteElement* element, const CRegion& damage) {
- const auto m_data = element->m_data;
-
- g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb);
-};
-
SP<ITexture> CHyprGLRenderer::getBlurTexture(PHLMONITORREF pMonitor) {
- if (!pMonitor->m_blurFB)
- return nullptr;
- return pMonitor->m_blurFB->getTexture();
+ return pMonitor->resources()->m_blurFB->getTexture();
}
void CHyprGLRenderer::unsetEGL() {
@@ -411,3 +301,7 @@ void CHyprGLRenderer::unsetEGL() {
eglMakeCurrent(g_pHyprOpenGL->m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
+
+WP<IElementRenderer> CHyprGLRenderer::elementRenderer() {
+ return m_elementRenderer;
+}
diff --git a/src/render/GLRenderer.hpp b/src/render/GLRenderer.hpp
index 6f511fc3..ee831fec 100644
--- a/src/render/GLRenderer.hpp
+++ b/src/render/GLRenderer.hpp
@@ -1,53 +1,51 @@
#pragma once
#include "Renderer.hpp"
-
-class CHyprGLRenderer : public IHyprRenderer {
- public:
- CHyprGLRenderer();
-
- void endRender(const std::function<void()>& renderingDoneCallback = {}) override;
- SP<ITexture> createStencilTexture(const int width, const int height) override;
- SP<ITexture> createTexture(bool opaque = false) override;
- SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) override;
- SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) override;
- SP<ITexture> createTexture(const int width, const int height, unsigned char* const data) override;
- SP<ITexture> createTexture(cairo_surface_t* cairo) override;
- SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) override;
- bool explicitSyncSupported() override;
- std::vector<SDRMFormat> getDRMFormats() override;
- std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) override;
- SP<IFramebuffer> createFB(const std::string& name = "") override;
- void disableScissor() override;
- void blend(bool enabled) override;
- void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) override;
- SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) override;
- void setViewport(int x, int y, int width, int height) override;
- bool reloadShaders(const std::string& path = "") override;
-
- void unsetEGL();
-
- private:
- void renderOffToMain(IFramebuffer* off) override;
- SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
- bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) override;
- bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) override;
- void initRender() override;
- bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
-
- void draw(CBorderPassElement* element, const CRegion& damage) override;
- void draw(CClearPassElement* element, const CRegion& damage) override;
- void draw(CFramebufferElement* element, const CRegion& damage) override;
- void draw(CPreBlurElement* element, const CRegion& damage) override;
- void draw(CRectPassElement* element, const CRegion& damage) override;
- void draw(CShadowPassElement* element, const CRegion& damage) override;
- void draw(CInnerGlowPassElement* element, const CRegion& damage) override;
- void draw(CTexPassElement* element, const CRegion& damage) override;
- void draw(CTextureMatteElement* element, const CRegion& damage) override;
-
- SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor) override;
-
- SP<IRenderbuffer> m_currentRenderbuffer = nullptr;
-
- friend class CHyprOpenGLImpl;
-};
+#include "render/ElementRenderer.hpp"
+
+namespace Render::GL {
+ class CHyprGLRenderer : public Render::IHyprRenderer {
+ public:
+ CHyprGLRenderer();
+ ~CHyprGLRenderer() = default;
+
+ eType type() override;
+ void endRender(const std::function<void()>& renderingDoneCallback = {}) override;
+ UP<ISyncFDManager> createSyncFDManager() override;
+ SP<ITexture> createStencilTexture(const int width, const int height) override;
+ SP<ITexture> createTexture(bool opaque = false) override;
+ SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) override;
+ SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) override;
+ SP<ITexture> createTexture(const int width, const int height, unsigned char* const data) override;
+ SP<ITexture> createTexture(cairo_surface_t* cairo) override;
+ SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) override;
+ bool explicitSyncSupported() override;
+ std::vector<SDRMFormat> getDRMFormats() override;
+ std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) override;
+ SP<IFramebuffer> createFB(const std::string& name = "") override;
+ void disableScissor() override;
+ void blend(bool enabled) override;
+ void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) override;
+ SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) override;
+ void setViewport(int x, int y, int width, int height) override;
+ bool reloadShaders(const std::string& path = "") override;
+
+ void unsetEGL();
+ WP<IElementRenderer> elementRenderer() override;
+
+ private:
+ void renderOffToMain(SP<IFramebuffer> off) override;
+ SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
+ bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) override;
+ bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) override;
+ void initRender() override;
+ bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) override;
+
+ SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor) override;
+
+ SP<IRenderbuffer> m_currentRenderbuffer;
+ UP<IElementRenderer> m_elementRenderer;
+
+ friend class CHyprOpenGLImpl;
+ };
+} \ No newline at end of file
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index 9aaa99d5..cfc3dc4e 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -60,6 +60,7 @@
using namespace Hyprutils::OS;
using namespace NColorManagement;
using namespace Render;
+using namespace Render::GL;
static inline void loadGLProc(void* pProc, const char* name) {
void* proc = rc<void*>(eglGetProcAddress(name));
@@ -139,6 +140,12 @@ static int openRenderNode(int drmFd) {
return renderFD;
}
+static ShaderFeatureFlags globalFeatures() {
+ return g_pHyprRenderer->m_renderData.pMonitor && g_pHyprRenderer->m_renderData.pMonitor->needsUnmodifiedCopy() && g_pHyprRenderer->m_renderData.currentFB->getMirrorTexture() ?
+ SH_FEAT_MIRROR :
+ 0;
+}
+
void CHyprOpenGLImpl::initEGL(bool gbm) {
std::vector<EGLint> attrs;
if (m_exts.KHR_display_reference) {
@@ -687,8 +694,7 @@ void CHyprOpenGLImpl::beginSimple(PHLMONITOR pMonitor, const CRegion& damage, SP
m_fakeFrame = true;
- g_pHyprRenderer->m_renderData.currentFB = FBO;
- FBO->bind();
+ g_pHyprRenderer->bindFB(FBO);
m_offloadedFramebuffer = false;
g_pHyprRenderer->m_renderData.mainFB = g_pHyprRenderer->m_renderData.currentFB;
@@ -728,8 +734,8 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, SP<IFra
if (!m_shadersInitialized)
initShaders();
- 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 = g_pHyprRenderer->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();
g_pHyprRenderer->m_renderData.transformDamage = true;
if (HAS_MIRROR_FB != NEEDS_COPY_FB) {
@@ -749,13 +755,28 @@ void CHyprOpenGLImpl::begin(PHLMONITOR pMonitor, const CRegion& damage_, SP<IFra
applyScreenShader(*PSHADER);
}
- g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->bind();
- g_pHyprRenderer->m_renderData.currentFB = g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB;
- m_offloadedFramebuffer = true;
+ g_pHyprRenderer->bindFB(g_pHyprRenderer->m_renderData.pMonitor->resources()->getUnusedWorkBuffer());
+ m_offloadedFramebuffer = true;
g_pHyprRenderer->m_renderData.mainFB = g_pHyprRenderer->m_renderData.currentFB;
g_pHyprRenderer->m_renderData.outFB = fb ? fb : dc<CHyprGLRenderer*>(g_pHyprRenderer.get())->m_currentRenderbuffer->getFB();
+ if UNLIKELY (g_pHyprRenderer->m_renderData.pMonitor->needsUnmodifiedCopy() && !m_fakeFrame) {
+ if (!g_pHyprRenderer->m_renderData.pMonitor->resources()->m_mirrorTex) {
+ GLenum buffers[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1};
+ glDrawBuffers(2, buffers);
+ g_pHyprRenderer->m_renderData.pMonitor->resources()->enableMirror();
+ }
+ g_pHyprRenderer->m_renderData.mainFB->enableMirror(g_pHyprRenderer->m_renderData.pMonitor->resources()->m_mirrorTex);
+ } else {
+ if (g_pHyprRenderer->m_renderData.pMonitor->resources()->m_mirrorTex) {
+ GLenum buffers[] = {GL_COLOR_ATTACHMENT0};
+ glDrawBuffers(1, buffers);
+ g_pHyprRenderer->m_renderData.pMonitor->resources()->disableMirror();
+ }
+ g_pHyprRenderer->m_renderData.mainFB->disableMirror();
+ }
+
g_pHyprRenderer->pushMonitorTransformEnabled(false);
}
@@ -786,19 +807,20 @@ void CHyprOpenGLImpl::end() {
// copy the damaged areas into the mirror buffer
// we can't use the offloadFB for mirroring / ss, as it contains artifacts from blurring
- if UNLIKELY (g_pHyprRenderer->needsACopyFB(g_pHyprRenderer->m_renderData.pMonitor.lock()) && !m_fakeFrame)
+ if UNLIKELY (g_pHyprRenderer->m_renderData.pMonitor->needsACopyFB() && !m_fakeFrame)
saveBufferForMirror(monbox);
- g_pHyprRenderer->m_renderData.outFB->bind();
+ const auto TEX = g_pHyprRenderer->m_renderData.currentFB->getTexture();
+ g_pHyprRenderer->bindFB(g_pHyprRenderer->m_renderData.outFB);
blend(false);
const auto PRIMITIVE_BLOCKED = m_finalScreenShader->program() >= 1 || g_pHyprRenderer->m_crashingInProgress ||
g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription->value() != SImageDescription{};
if LIKELY (!PRIMITIVE_BLOCKED || g_pHyprRenderer->m_renderMode != RENDER_MODE_NORMAL)
- renderTexturePrimitive(g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->getTexture(), monbox);
+ renderTexturePrimitive(TEX, monbox);
else // we need to use renderTexture if we do any CM whatsoever.
- renderTexture(g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->getTexture(), monbox, {.finalMonitorCM = true});
+ renderTexture(TEX, monbox, {.finalMonitorCM = true});
blend(true);
@@ -807,39 +829,26 @@ void CHyprOpenGLImpl::end() {
g_pHyprRenderer->popMonitorTransformEnabled();
}
- // invalidate our render FBs to signal to the driver we don't need them anymore
- if (g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB) {
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB->bind();
- GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
- }
- if (g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB) {
- g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB->bind();
- GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
- }
- if (g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB) {
- g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB->bind();
- GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
- }
- if (g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB) {
- g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB->bind();
- GLFB(g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
- }
-
// reset our data
- m_renderData.pMonitor.reset();
g_pHyprRenderer->m_renderData.mouseZoomFactor = 1.f;
g_pHyprRenderer->m_renderData.mouseZoomUseMouse = true;
g_pHyprRenderer->m_renderData.blockScreenShader = false;
- g_pHyprRenderer->m_renderData.currentFB = nullptr;
- g_pHyprRenderer->m_renderData.mainFB = nullptr;
- g_pHyprRenderer->m_renderData.outFB = nullptr;
+ g_pHyprRenderer->m_renderData.currentFB.reset();
+ g_pHyprRenderer->m_renderData.mainFB.reset();
+ g_pHyprRenderer->m_renderData.outFB.reset();
g_pHyprRenderer->popMonitorTransformEnabled();
- // if we dropped to offMain, release it now.
- // if there is a plugin constantly using it, this might be a bit slow,
- // but I haven't seen a single plugin yet use these, so it's better to drop a bit of vram.
- if UNLIKELY (PMONITOR && PMONITOR->m_offMainFB && PMONITOR->m_offMainFB->isAllocated())
- PMONITOR->m_offMainFB->release();
+ // invalidate our render FBs to signal to the driver we don't need them anymore
+ if (!g_pHyprRenderer->m_renderData.pMonitor->useFP16()) { // FIXME wtf?
+ g_pHyprRenderer->m_renderData.pMonitor->resources()->forEachUnusedFB(
+ [](const auto& fb) {
+ fb->bind();
+ GLFB(fb)->invalidate({GL_STENCIL_ATTACHMENT, GL_COLOR_ATTACHMENT0});
+ },
+ false);
+ }
+
+ m_renderData.pMonitor.reset();
static const auto GLDEBUG = CConfigValue<Hyprlang::INT>("debug:gl_debugging");
@@ -963,21 +972,6 @@ void CHyprOpenGLImpl::applyScreenShader(const std::string& path) {
uniformRequireNoDamage(SHADER_POINTER_SHAPE_PREVIOUS, "pointer_shape_previous");
}
-void CHyprOpenGLImpl::clear(const CHyprColor& color) {
- RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render without begin()!");
-
- TRACY_GPU_ZONE("RenderClear");
-
- GLCALL(glClearColor(color.r, color.g, color.b, color.a));
-
- if (!g_pHyprRenderer->m_renderData.damage.empty()) {
- g_pHyprRenderer->m_renderData.damage.forEachRect([this](const auto& RECT) {
- scissor(&RECT, g_pHyprRenderer->m_renderData.transformDamage);
- glClear(GL_COLOR_BUFFER_BIT);
- });
- }
-}
-
void CHyprOpenGLImpl::blend(bool enabled) {
if (enabled) {
setCapStatus(GL_BLEND, true);
@@ -1052,16 +1046,13 @@ void CHyprOpenGLImpl::renderRectWithBlurInternal(const CBox& box, const CHyprCol
CRegion damage{g_pHyprRenderer->m_renderData.damage};
damage.intersect(box);
- auto POUTFB = data.xray ? (g_pHyprRenderer->m_renderData.pMonitor->m_blurFB ? g_pHyprRenderer->m_renderData.pMonitor->m_blurFB->getTexture() : nullptr) :
- g_pHyprRenderer->blurMainFramebuffer(data.blurA, &damage);
-
- g_pHyprRenderer->m_renderData.currentFB->bind();
+ auto blurredBG = data.xray ? g_pHyprRenderer->m_renderData.pMonitor->resources()->m_blurFB->getTexture() : g_pHyprRenderer->blurMainFramebuffer(data.blurA, &damage);
CBox MONITORBOX = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y};
g_pHyprRenderer->pushMonitorTransformEnabled(true);
const auto SAVEDRENDERMODIF = g_pHyprRenderer->m_renderData.renderModif;
g_pHyprRenderer->m_renderData.renderModif = {}; // fix shit
- renderTexture(POUTFB, MONITORBOX,
+ renderTexture(blurredBG, MONITORBOX,
STextureRenderData{.damage = &damage, .a = data.blurA, .round = data.round, .roundingPower = 2.F, .allowCustomUV = false, .allowDim = false, .noAA = false});
g_pHyprRenderer->popMonitorTransformEnabled();
g_pHyprRenderer->m_renderData.renderModif = SAVEDRENDERMODIF;
@@ -1081,7 +1072,7 @@ void CHyprOpenGLImpl::renderRectWithDamageInternal(const CBox& box, const CHyprC
const auto& glMatrix = g_pHyprRenderer->projectBoxToTarget(newBox);
- auto shader = useShader(getShaderVariant(SH_FRAG_QUAD, data.round > 0 ? SH_FEAT_ROUNDING : 0));
+ auto shader = useShader(getShaderVariant(SH_FRAG_QUAD, (data.round > 0 ? SH_FEAT_ROUNDING : 0) | globalFeatures()));
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
// premultiply the color as well as we don't work with straight alpha
@@ -1144,28 +1135,9 @@ void CHyprOpenGLImpl::renderTexture(SP<ITexture> tex, const CBox& box, STextureR
static std::map<std::pair<uint32_t, uint32_t>, std::array<GLfloat, 9>> primariesConversionCache;
-static bool isSDR2HDR(const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription) {
- // might be too strict
- 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);
-}
-
-static bool isHDR2SDR(const NColorManagement::SImageDescription& imageDescription, const NColorManagement::SImageDescription& targetImageDescription) {
- // might be too strict
- return (imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ||
- imageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_HLG) &&
- (targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_SRGB ||
- targetImageDescription.transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22);
-}
-
void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const NColorManagement::PImageDescription imageDescription,
- const NColorManagement::PImageDescription targetImageDescription, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
- const auto settings = g_pHyprRenderer->getCMSettings(imageDescription, targetImageDescription,
- g_pHyprRenderer->m_renderData.surface.valid() ? g_pHyprRenderer->m_renderData.surface.lock() : nullptr, modifySDR,
- sdrMinLuminance, sdrMaxLuminance);
-
+ const NColorManagement::PImageDescription targetImageDescription, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance,
+ const SCMSettings& settings) {
shader->setUniformInt(SHADER_SOURCE_TF, settings.sourceTF);
shader->setUniformInt(SHADER_TARGET_TF, settings.targetTF);
shader->setUniformFloat2(SHADER_SRC_TF_RANGE, settings.srcTFRange.min, settings.srcTFRange.max);
@@ -1209,6 +1181,14 @@ void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const NColorManagement:
}
}
+void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const NColorManagement::PImageDescription imageDescription,
+ const NColorManagement::PImageDescription targetImageDescription, bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance) {
+ const auto settings = g_pHyprRenderer->getCMSettings(imageDescription, targetImageDescription,
+ g_pHyprRenderer->m_renderData.surface.valid() ? g_pHyprRenderer->m_renderData.surface.lock() : nullptr, modifySDR,
+ sdrMinLuminance, sdrMaxLuminance);
+ passCMUniforms(shader, imageDescription, targetImageDescription, modifySDR, sdrMinLuminance, sdrMaxLuminance, settings);
+}
+
void CHyprOpenGLImpl::passCMUniforms(WP<CShader> shader, const PImageDescription imageDescription) {
passCMUniforms(shader, imageDescription, g_pHyprRenderer->workBufferImageDescription(), true, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance,
g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance);
@@ -1287,7 +1267,7 @@ WP<CShader> CHyprOpenGLImpl::renderToOutputInternal() {
return shader;
}
-WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox) {
+WP<CShader> CHyprOpenGLImpl::renderToFBInternal(SP<ITexture> tex, const STextureRenderData& data, eTextureType texType, const CBox& newBox) {
static const auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
static const auto PENABLECM = CConfigValue<Hyprlang::INT>("render:cm_enabled");
static auto PBLEND = CConfigValue<Hyprlang::INT>("render:use_shader_blur_blend");
@@ -1304,7 +1284,7 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
case TEXTURE_RGBX: shaderFeatures &= ~SH_FEAT_RGBA; break;
// TODO set correct features
- case TEXTURE_EXTERNAL: shader = getShaderVariant(SH_FRAG_EXT, SH_FEAT_ROUNDING | SH_FEAT_DISCARD | SH_FEAT_TINT); break; // might be unused
+ case TEXTURE_EXTERNAL: shader = getShaderVariant(SH_FRAG_EXT, SH_FEAT_ROUNDING | SH_FEAT_DISCARD | SH_FEAT_TINT | globalFeatures()); break; // might be unused
default: RASSERT(false, "tex->m_iTarget unsupported!");
}
@@ -1320,13 +1300,19 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
// chosenSdrEotf contains the valid eotf for this display
const auto SOURCE_IMAGE_DESCRIPTION = [&] {
+ if (tex->m_imageDescription)
+ return tex->m_imageDescription;
+
// if valid CM surface, use that as a source
if (g_pHyprRenderer->m_renderData.surface.valid() && g_pHyprRenderer->m_renderData.surface->m_colorManagement.valid())
return CImageDescription::from(g_pHyprRenderer->m_renderData.surface->m_colorManagement->imageDescription());
+ if (data.cmBackToSRGB)
+ return g_pHyprRenderer->m_renderData.pMonitor->m_imageDescription;
+
// otherwise, if we are CM'ing back into source, use chosen, because that's what our work buffer is in
// the same applies to the final monitor CM
- if (data.cmBackToSRGB || data.finalMonitorCM) // NOLINTNEXTLINE
+ if (data.finalMonitorCM) // NOLINTNEXTLINE
return WORK_BUFFER_IMAGE_DESCRIPTION;
// otherwise, default
@@ -1334,6 +1320,9 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
}();
const auto TARGET_IMAGE_DESCRIPTION = [&] {
+ if (g_pHyprRenderer->m_renderData.currentFB->imageDescription())
+ return g_pHyprRenderer->m_renderData.currentFB->imageDescription();
+
// if we are CM'ing back, use default sRGB
if (data.cmBackToSRGB)
return DEFAULT_IMAGE_DESCRIPTION;
@@ -1370,41 +1359,32 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
shaderFeatures |= SH_FEAT_ROUNDING;
if (!skipCM) {
+ const auto settings = g_pHyprRenderer->getCMSettings(SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION,
+ g_pHyprRenderer->m_renderData.surface.valid() ? g_pHyprRenderer->m_renderData.surface.lock() : nullptr, true,
+ g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance);
+
shaderFeatures |= SH_FEAT_CM;
if (TARGET_IMAGE_DESCRIPTION->value().icc.present)
shaderFeatures |= SH_FEAT_ICC;
else {
- const bool needsSDRmod = isSDR2HDR(SOURCE_IMAGE_DESCRIPTION->value(), TARGET_IMAGE_DESCRIPTION->value());
- const bool needsHDRmod = !needsSDRmod && isHDR2SDR(SOURCE_IMAGE_DESCRIPTION->value(), TARGET_IMAGE_DESCRIPTION->value());
- const float maxLuminance = needsHDRmod ?
- SOURCE_IMAGE_DESCRIPTION->value().getTFMaxLuminance(-1) :
- (SOURCE_IMAGE_DESCRIPTION->value().luminances.max > 0 ? SOURCE_IMAGE_DESCRIPTION->value().luminances.max : SOURCE_IMAGE_DESCRIPTION->value().luminances.reference);
- const auto dstMaxLuminance = TARGET_IMAGE_DESCRIPTION->value().luminances.max > 0 ? TARGET_IMAGE_DESCRIPTION->value().luminances.max : 10000;
-
- if (maxLuminance >= dstMaxLuminance * 1.01)
+ if (settings.needsTonemap)
shaderFeatures |= SH_FEAT_TONEMAP;
- if (!data.finalMonitorCM &&
- (SOURCE_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_SRGB ||
- SOURCE_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_GAMMA22) &&
- TARGET_IMAGE_DESCRIPTION->value().transferFunction == CM_TRANSFER_FUNCTION_ST2084_PQ &&
- ((g_pHyprRenderer->m_renderData.pMonitor->m_sdrSaturation > 0 && g_pHyprRenderer->m_renderData.pMonitor->m_sdrSaturation != 1.0f) ||
- (g_pHyprRenderer->m_renderData.pMonitor->m_sdrBrightness > 0 && g_pHyprRenderer->m_renderData.pMonitor->m_sdrBrightness != 1.0f)))
+ if (!data.finalMonitorCM && settings.needsSDRmod)
shaderFeatures |= SH_FEAT_SDR_MOD;
}
- }
- if (!shader)
- shader = getShaderVariant(SH_FRAG_SURFACE, shaderFeatures);
- shader = useShader(shader);
+ if (!shader)
+ shader = getShaderVariant(SH_FRAG_SURFACE, shaderFeatures | globalFeatures());
+ shader = useShader(shader);
- if (!skipCM) {
- if (data.finalMonitorCM || data.cmBackToSRGB)
- passCMUniforms(shader, SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION, true, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance,
- g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance);
- else
- passCMUniforms(shader, SOURCE_IMAGE_DESCRIPTION);
+ passCMUniforms(shader, SOURCE_IMAGE_DESCRIPTION, TARGET_IMAGE_DESCRIPTION, true, g_pHyprRenderer->m_renderData.pMonitor->m_sdrMinLuminance,
+ g_pHyprRenderer->m_renderData.pMonitor->m_sdrMaxLuminance, settings);
+ } else {
+ if (!shader)
+ shader = getShaderVariant(SH_FRAG_SURFACE, shaderFeatures | globalFeatures());
+ shader = useShader(shader);
}
shader->setUniformFloat(SHADER_ALPHA, alpha);
@@ -1458,7 +1438,8 @@ WP<CShader> CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data,
void CHyprOpenGLImpl::renderTextureInternal(SP<ITexture> tex, const CBox& box, const STextureRenderData& data) {
RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render texture without begin()!");
- RASSERT((tex->ok()), "Attempted to draw nullptr texture!");
+ RASSERT(tex, "Attempted to draw nullptr texture!");
+ RASSERT(tex->ok(), "Attempted to draw invalid texture!");
TRACY_GPU_ZONE("RenderTextureInternalWithDamage");
@@ -1493,7 +1474,7 @@ void CHyprOpenGLImpl::renderTextureInternal(SP<ITexture> tex, const CBox& box, c
tex->setTexParameter(GL_TEXTURE_MIN_FILTER, tex->minFilter);
}
- auto shader = renderToOutput ? renderToOutputInternal() : renderToFBInternal(data, tex->m_type, newBox);
+ auto shader = renderToOutput ? renderToOutputInternal() : renderToFBInternal(tex, data, tex->m_type, newBox);
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
shader->setUniformInt(SHADER_TEX, 0);
@@ -1608,7 +1589,7 @@ void CHyprOpenGLImpl::renderTextureMatte(SP<ITexture> tex, const CBox& box, SP<I
// get transform
const auto& glMatrix = g_pHyprRenderer->projectBoxToTarget(newBox);
- auto shader = useShader(getShaderVariant(SH_FRAG_MATTE));
+ auto shader = useShader(getShaderVariant(SH_FRAG_MATTE, globalFeatures()));
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
shader->setUniformInt(SHADER_TEX, 0);
shader->setUniformInt(SHADER_ALPHA_MATTE, 1);
@@ -1665,8 +1646,8 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
damage.expand(std::clamp(*PBLURSIZE, sc<int64_t>(1), sc<int64_t>(40)) * pow(2, BLUR_PASSES));
// helper
- const auto PMIRRORFB = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB;
- const auto PMIRRORSWAPFB = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB;
+ const auto PMIRRORFB = g_pHyprRenderer->m_renderData.pMonitor->resources()->getUnusedWorkBuffer();
+ const auto PMIRRORSWAPFB = g_pHyprRenderer->m_renderData.pMonitor->resources()->getUnusedWorkBuffer();
auto currentRenderToFB = PMIRRORFB;
@@ -1692,15 +1673,15 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
if (!skipCM) {
shader = useShader(getShaderVariant(SH_FRAG_BLURPREPARE, SH_FEAT_CM));
- passCMUniforms(shader, m_renderData.pMonitor->m_imageDescription, DEFAULT_IMAGE_DESCRIPTION);
+ passCMUniforms(shader, g_pHyprRenderer->workBufferImageDescription(), DEFAULT_IMAGE_DESCRIPTION);
shader->setUniformFloat(SHADER_SDR_SATURATION,
m_renderData.pMonitor->m_sdrSaturation > 0 &&
- m_renderData.pMonitor->m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
+ g_pHyprRenderer->workBufferImageDescription()->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
m_renderData.pMonitor->m_sdrSaturation :
1.0f);
shader->setUniformFloat(SHADER_SDR_BRIGHTNESS,
m_renderData.pMonitor->m_sdrBrightness > 0 &&
- m_renderData.pMonitor->m_imageDescription->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
+ g_pHyprRenderer->workBufferImageDescription()->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
m_renderData.pMonitor->m_sdrBrightness :
1.0f);
} else
@@ -1808,7 +1789,24 @@ SP<IFramebuffer> CHyprOpenGLImpl::blurFramebufferWithDamage(float a, CRegion* or
currentTex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- auto shader = useShader(getShaderVariant(SH_FRAG_BLURFINISH));
+ // From FB to sRGB
+ const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
+ if (!skipCM) {
+ shader = useShader(getShaderVariant(SH_FRAG_BLURFINISH, SH_FEAT_CM));
+ passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION, g_pHyprRenderer->workBufferImageDescription());
+ shader->setUniformFloat(SHADER_SDR_SATURATION,
+ m_renderData.pMonitor->m_sdrSaturation > 0 &&
+ g_pHyprRenderer->workBufferImageDescription()->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
+ m_renderData.pMonitor->m_sdrSaturation :
+ 1.0f);
+ shader->setUniformFloat(SHADER_SDR_BRIGHTNESS,
+ m_renderData.pMonitor->m_sdrBrightness > 0 &&
+ g_pHyprRenderer->workBufferImageDescription()->value().transferFunction == NColorManagement::CM_TRANSFER_FUNCTION_ST2084_PQ ?
+ m_renderData.pMonitor->m_sdrBrightness :
+ 1.0f);
+ } else
+ shader = useShader(getShaderVariant(SH_FRAG_BLURFINISH));
+
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
shader->setUniformFloat(SHADER_NOISE, *PBLURNOISE);
shader->setUniformFloat(SHADER_BRIGHTNESS, *PBLURBRIGHTNESS);
@@ -2078,10 +2076,10 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const Config::CGradientValue
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
if (!skipCM) {
- shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD)));
+ shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
} else
- shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING));
+ shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | globalFeatures()));
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
shader->setUniform4fv(SHADER_GRADIENT, grad.m_colorsOkLabA.size() / 4, grad.m_colorsOkLabA);
@@ -2163,10 +2161,10 @@ void CHyprOpenGLImpl::renderBorder(const CBox& box, const Config::CGradientValue
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
if (!skipCM) {
- shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD)));
+ shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
} else
- shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING));
+ shader = useShader(getShaderVariant(SH_FRAG_BORDER1, SH_FEAT_ROUNDING | globalFeatures()));
shader->setUniformMatrix3fv(SHADER_PROJ, 1, GL_TRUE, glMatrix.getMatrix());
shader->setUniform4fv(SHADER_GRADIENT, grad1.m_colorsOkLabA.size() / 4, grad1.m_colorsOkLabA);
@@ -2240,7 +2238,7 @@ void CHyprOpenGLImpl::renderRoundedShadow(const CBox& box, int round, float roun
const bool IS_ICC = g_pHyprRenderer->workBufferImageDescription()->value().icc.present;
const bool skipCM = !m_cmSupported || g_pHyprRenderer->workBufferImageDescription()->id() == DEFAULT_IMAGE_DESCRIPTION->id();
- auto shader = useShader(getShaderVariant(SH_FRAG_SHADOW, skipCM ? 0 : SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD)));
+ auto shader = useShader(getShaderVariant(SH_FRAG_SHADOW, skipCM ? 0 : SH_FEAT_CM | (IS_ICC ? SH_FEAT_ICC : SH_FEAT_TONEMAP | SH_FEAT_SDR_MOD) | globalFeatures()));
if (!skipCM)
passCMUniforms(shader, DEFAULT_IMAGE_DESCRIPTION);
@@ -2347,16 +2345,17 @@ void CHyprOpenGLImpl::renderInnerGlow(const CBox& box, int round, float rounding
}
void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
- auto& m_renderData = g_pHyprRenderer->m_renderData;
- if (!g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->isAllocated())
- g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->alloc(m_renderData.pMonitor->m_pixelSize.x, m_renderData.pMonitor->m_pixelSize.y,
- m_renderData.pMonitor->m_output->state->state().drmFormat);
-
- g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB->bind();
+ const auto TEX = g_pHyprRenderer->m_renderData.pMonitor->resources()->m_mirrorTex ? g_pHyprRenderer->m_renderData.pMonitor->resources()->m_mirrorTex :
+ g_pHyprRenderer->m_renderData.currentFB->getTexture();
+ if (!TEX) {
+ Log::logger->log(Log::ERR, "Invalid source texture for mirror");
+ return;
+ }
+ auto guard = g_pHyprRenderer->bindTempFB(g_pHyprRenderer->m_renderData.pMonitor->resources()->mirrorFB());
blend(false);
- renderTexture(g_pHyprRenderer->m_renderData.currentFB->getTexture(), box,
+ renderTexture(TEX, box,
STextureRenderData{
.damage = &g_pHyprRenderer->m_renderData.finalDamage,
.a = 1.F,
@@ -2367,8 +2366,6 @@ void CHyprOpenGLImpl::saveBufferForMirror(const CBox& box) {
});
blend(true);
-
- g_pHyprRenderer->m_renderData.currentFB->bind();
}
WP<CShader> CHyprOpenGLImpl::useShader(WP<CShader> prog) {
@@ -2397,7 +2394,7 @@ void CHyprOpenGLImpl::destroyMonitorResources(PHLMONITORREF pMonitor) {
Log::logger->log(Log::DEBUG, "Monitor {} -> destroyed all render data", pMonitor->m_name);
}
-void CHyprOpenGLImpl::renderOffToMain(IFramebuffer* off) {
+void CHyprOpenGLImpl::renderOffToMain(SP<IFramebuffer> off) {
CBox monbox = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_transformedSize.y};
renderTexturePrimitive(off->getTexture(), monbox);
}
@@ -2579,14 +2576,6 @@ CEGLSync::~CEGLSync() {
Log::logger->log(Log::ERR, "eglDestroySyncKHR failed");
}
-CFileDescriptor& CEGLSync::fd() {
- return m_fd;
-}
-
-CFileDescriptor&& CEGLSync::takeFd() {
- return std::move(m_fd);
-}
-
bool CEGLSync::isValid() {
return m_valid && m_sync != EGL_NO_SYNC_KHR && m_fd.isValid();
}
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index bbca01c0..78518ffe 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -16,6 +16,8 @@
#include <cairo/cairo.h>
+#include "render/SyncFDManager.hpp"
+#include "types.hpp"
#include "Shader.hpp"
#include "Texture.hpp"
#include "Framebuffer.hpp"
@@ -40,343 +42,318 @@
#define GLFB(ifb) dc<CGLFramebuffer*>(ifb.get())
struct gbm_device;
-class IHyprRenderer;
-
+namespace Render {
+ class IHyprRenderer;
+}
namespace Config {
class CGradientValueData;
}
-struct SVertex {
- float x, y; // position
- float u, v; // uv
-};
-
-constexpr std::array<SVertex, 4> fullVerts = {{
- {0.0f, 0.0f, 0.0f, 0.0f}, // top-left
- {0.0f, 1.0f, 0.0f, 1.0f}, // bottom-left
- {1.0f, 0.0f, 1.0f, 0.0f}, // top-right
- {1.0f, 1.0f, 1.0f, 1.0f}, // bottom-right
-}};
-
-inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
-
-struct SRenderModifData {
- enum eRenderModifType : uint8_t {
- RMOD_TYPE_SCALE, /* scale by a float */
- RMOD_TYPE_SCALECENTER, /* scale by a float from the center */
- RMOD_TYPE_TRANSLATE, /* translate by a Vector2D */
- RMOD_TYPE_ROTATE, /* rotate by a float in rad from top left */
- RMOD_TYPE_ROTATECENTER, /* rotate by a float in rad from center */
+namespace Render::GL {
+
+ struct SVertex {
+ float x, y; // position
+ float u, v; // uv
+ };
+
+ constexpr std::array<SVertex, 4> fullVerts = {{
+ {0.0f, 0.0f, 0.0f, 0.0f}, // top-left
+ {0.0f, 1.0f, 0.0f, 1.0f}, // bottom-left
+ {1.0f, 0.0f, 1.0f, 0.0f}, // top-right
+ {1.0f, 1.0f, 1.0f, 1.0f}, // bottom-right
+ }};
+
+ inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f};
+
+ enum eMonitorRenderFBs : uint8_t {
+ FB_MONITOR_RENDER_MAIN = 0,
+ FB_MONITOR_RENDER_CURRENT = 1,
+ FB_MONITOR_RENDER_OUT = 2,
};
- std::vector<std::pair<eRenderModifType, std::any>> modifs;
-
- void applyToBox(CBox& box);
- void applyToRegion(CRegion& rg);
- float combinedScale();
-
- bool enabled = true;
-};
-
-enum eMonitorRenderFBs : uint8_t {
- FB_MONITOR_RENDER_MAIN = 0,
- FB_MONITOR_RENDER_CURRENT = 1,
- FB_MONITOR_RENDER_OUT = 2,
-};
-
-enum eMonitorExtraRenderFBs : uint8_t {
- FB_MONITOR_RENDER_EXTRA_OFFLOAD = 0,
- FB_MONITOR_RENDER_EXTRA_MIRROR,
- FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP,
- FB_MONITOR_RENDER_EXTRA_OFF_MAIN,
- FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR,
- FB_MONITOR_RENDER_EXTRA_BLUR,
-};
-
-struct SFragShaderDesc {
- Render::ePreparedFragmentShader id;
- const char* file;
-};
-
-struct SPreparedShaders {
- // SPreparedShaders() {
- // for (auto& f : frag) {
- // f = makeShared<CShader>();
- // }
- // }
-
- std::string TEXVERTSRC;
- std::string TEXVERTSRC320;
- // std::array<SP<CShader>, SH_FRAG_LAST> frag;
- // std::map<uint8_t, SP<CShader>> fragVariants;
- std::array<std::map<Render::ShaderFeatureFlags, SP<CShader>>, Render::SH_FRAG_LAST> fragVariants;
-};
-
-struct SCurrentRenderData {
- PHLMONITORREF pMonitor;
- Mat3x3 projection;
- Mat3x3 savedProjection;
- Mat3x3 monitorProjection;
-
- SP<IFramebuffer> currentFB = nullptr; // current rendering to
- SP<IFramebuffer> mainFB = nullptr; // main to render to
- SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
-
- CRegion damage;
- CRegion finalDamage; // damage used for funal off -> main
-
- SRenderModifData renderModif;
- float mouseZoomFactor = 1.f;
- bool mouseZoomUseMouse = true; // true by default
- bool useNearestNeighbor = false;
- bool blockScreenShader = false;
- bool simplePass = false;
- bool transformDamage = true;
- bool noSimplify = false;
-
- Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
- Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
-
- CBox clipBox = {}; // scaled coordinates
- CRegion clipRegion;
-
- uint32_t discardMode = DISCARD_OPAQUE;
- float discardOpacity = 0.f;
-
- PHLLSREF currentLS;
- PHLWINDOWREF currentWindow;
- WP<CWLSurfaceResource> surface;
-};
-
-class CEGLSync {
- public:
- static UP<CEGLSync> create();
-
- ~CEGLSync();
-
- Hyprutils::OS::CFileDescriptor& fd();
- Hyprutils::OS::CFileDescriptor&& takeFd();
- bool isValid();
-
- private:
- CEGLSync() = default;
-
- Hyprutils::OS::CFileDescriptor m_fd;
- EGLSyncKHR m_sync = EGL_NO_SYNC_KHR;
- bool m_valid = false;
-
- friend class CHyprOpenGLImpl;
-};
-
-class CHyprOpenGLImpl {
- public:
- CHyprOpenGLImpl();
- ~CHyprOpenGLImpl();
-
- struct SRectRenderData {
- const CRegion* damage = nullptr;
- int round = 0;
- float roundingPower = 2.F;
- bool blur = false;
- float blurA = 1.F;
- bool xray = false;
+ enum eMonitorExtraRenderFBs : uint8_t {
+ FB_MONITOR_RENDER_EXTRA_OFFLOAD = 0,
+ FB_MONITOR_RENDER_EXTRA_MIRROR,
+ FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP,
+ FB_MONITOR_RENDER_EXTRA_OFF_MAIN,
+ FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR,
+ FB_MONITOR_RENDER_EXTRA_BLUR,
};
- struct STextureRenderData {
- bool blur = false;
- float blurA = 1.F, overallA = 1.F;
- bool blockBlurOptimization = false;
- SP<ITexture> blurredBG;
-
- const CRegion* damage = nullptr;
- SP<CWLSurfaceResource> surface = nullptr;
- float a = 1.F;
- int round = 0;
- float roundingPower = 2.F;
- bool discardActive = false;
- bool allowCustomUV = false;
- bool allowDim = true;
- bool noAA = false; // unused
- GLenum wrapX = GL_CLAMP_TO_EDGE, wrapY = GL_CLAMP_TO_EDGE;
- bool cmBackToSRGB = false;
- bool finalMonitorCM = false;
- SP<CMonitor> cmBackToSRGBSource;
-
- uint32_t discardMode = DISCARD_OPAQUE;
- float discardOpacity = 0.f;
-
- CRegion clipRegion;
- PHLLSREF currentLS;
-
- Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
- Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
+ struct SFragShaderDesc {
+ Render::ePreparedFragmentShader id;
+ const char* file;
};
- struct SBorderRenderData {
- int round = 0;
- float roundingPower = 2.F;
- int borderSize = 1;
- float a = 1.0;
- int outerRound = -1; /* use round */
+ struct SPreparedShaders {
+ std::string TEXVERTSRC;
+ std::string TEXVERTSRC320;
+ std::array<std::map<Render::ShaderFeatureFlags, SP<CShader>>, Render::SH_FRAG_LAST> fragVariants;
};
- void makeEGLCurrent();
- void begin(PHLMONITOR, const CRegion& damage, SP<IFramebuffer> fb = nullptr, std::optional<CRegion> finalDamage = {});
- void beginSimple(PHLMONITOR, const CRegion& damage, SP<IRenderbuffer> rb = nullptr, SP<IFramebuffer> fb = nullptr);
- void end();
-
- void renderRect(const CBox&, const CHyprColor&, SRectRenderData data);
- void renderTexture(SP<ITexture>, const CBox&, STextureRenderData data);
- void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0);
- void renderInnerGlow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, int glowPower, float a = 1.0);
- void renderBorder(const CBox&, const Config::CGradientValueData&, SBorderRenderData data);
- void renderBorder(const CBox&, const Config::CGradientValueData&, const Config::CGradientValueData&, float lerp, SBorderRenderData data);
- void renderTextureMatte(SP<ITexture> tex, const CBox& pBox, SP<IFramebuffer> matte);
- void renderTexturePrimitive(SP<ITexture> tex, const CBox& box);
-
- void setViewport(GLint x, GLint y, GLsizei width, GLsizei height);
- void setCapStatus(int cap, bool status);
-
- void blend(bool enabled);
-
- void clear(const CHyprColor&);
- void scissor(const CBox&, bool transform = true);
- void scissor(const pixman_box32*, bool transform = true);
- void scissor(const int x, const int y, const int w, const int h, bool transform = true);
-
- void destroyMonitorResources(PHLMONITORREF);
-
- void preRender(PHLMONITOR);
-
- void saveBufferForMirror(const CBox&);
-
- void applyScreenShader(const std::string& path);
-
- void renderOffToMain(IFramebuffer* off);
-
- std::vector<SDRMFormat> getDRMFormats();
- std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
- EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
-
- bool initShaders(const std::string& path = "");
-
- WP<CShader> useShader(WP<CShader> prog);
-
- bool explicitSyncSupported();
- WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
-
- bool m_shadersInitialized = false;
- SP<SPreparedShaders> m_shaders;
-
- Hyprutils::OS::CFileDescriptor m_gbmFD;
- gbm_device* m_gbmDevice = nullptr;
- EGLContext m_eglContext = nullptr;
- EGLDisplay m_eglDisplay = nullptr;
- EGLDeviceEXT m_eglDevice = nullptr;
-
- std::map<PHLMONITORREF, SP<IFramebuffer>> m_monitorBGFBs;
-
- struct {
- PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
- PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
- PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
- PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
- PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
- PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
- PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
- PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr;
- PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr;
- PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr;
- PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr;
- PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
- PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
- PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
- PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
- } m_proc;
-
- struct {
- bool EXT_read_format_bgra = false;
- bool EXT_image_dma_buf_import = false;
- bool EXT_image_dma_buf_import_modifiers = false;
- bool KHR_context_flush_control = false;
- bool KHR_display_reference = false;
- bool IMG_context_priority = false;
- bool EXT_create_context_robustness = false;
- bool EGL_ANDROID_native_fence_sync_ext = false;
- } m_exts;
-
- enum eEGLContextVersion : uint8_t {
- EGL_CONTEXT_GLES_2_0 = 0,
- EGL_CONTEXT_GLES_3_0,
- EGL_CONTEXT_GLES_3_2,
+ struct SCurrentRenderData {
+ PHLMONITORREF pMonitor;
+ Mat3x3 projection;
+ Mat3x3 savedProjection;
+ Mat3x3 monitorProjection;
+
+ SP<IFramebuffer> currentFB = nullptr; // current rendering to
+ SP<IFramebuffer> mainFB = nullptr; // main to render to
+ SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
+
+ CRegion damage;
+ CRegion finalDamage; // damage used for funal off -> main
+
+ Render::SRenderModifData renderModif;
+ float mouseZoomFactor = 1.f;
+ bool mouseZoomUseMouse = true; // true by default
+ bool useNearestNeighbor = false;
+ bool blockScreenShader = false;
+ bool simplePass = false;
+ bool transformDamage = true;
+ bool noSimplify = false;
+
+ Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
+ Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
+
+ CBox clipBox = {}; // scaled coordinates
+ CRegion clipRegion;
+
+ uint32_t discardMode = DISCARD_OPAQUE;
+ float discardOpacity = 0.f;
+
+ PHLLSREF currentLS;
+ PHLWINDOWREF currentWindow;
+ WP<CWLSurfaceResource> surface;
};
- eEGLContextVersion m_eglContextVersion = EGL_CONTEXT_GLES_3_2;
+ class CEGLSync : public ISyncFDManager {
+ public:
+ static UP<CEGLSync> create();
+ ~CEGLSync() override;
+
+ bool isValid() override;
- enum eCachedCapStatus : uint8_t {
- CAP_STATUS_BLEND = 0,
- CAP_STATUS_SCISSOR_TEST,
- CAP_STATUS_STENCIL_TEST,
- CAP_STATUS_END
+ private:
+ CEGLSync() : ISyncFDManager() {};
+
+ EGLSyncKHR m_sync = EGL_NO_SYNC_KHR;
+
+ friend class CHyprOpenGLImpl;
};
- private:
- struct {
- GLint x = 0;
- GLint y = 0;
- GLsizei width = 0;
- GLsizei height = 0;
- } m_lastViewport;
-
- std::array<bool, CAP_STATUS_END> m_capStatus = {};
-
- std::vector<SDRMFormat> m_drmFormats;
- bool m_hasModifiers = false;
-
- int m_drmFD = -1;
- std::string m_extensions;
-
- bool m_fakeFrame = false;
- bool m_applyFinalShader = false;
- bool m_blend = false;
- bool m_offloadedFramebuffer = false;
- bool m_cmSupported = true;
-
- SP<CShader> m_finalScreenShader;
- GLuint m_currentProgram = 0;
-
- void initDRMFormats();
- void initEGL(bool gbm);
- EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
-
- // for the final shader
- std::array<CTimer, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryTimers = {};
- std::array<Vector2D, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryPositions = {};
- GLint m_pressedHistoryKilled = 0;
- GLint m_pressedHistoryTouched = 0;
-
- //
- std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
-
- // returns the out FB, can be either Mirror or MirrorSwap
- SP<IFramebuffer> blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source);
-
- void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
- bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
- void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
- void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
- void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
- void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
- WP<CShader> renderToOutputInternal();
- WP<CShader> renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox);
- void renderTextureInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
- void renderTextureWithBlurInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
-
- friend class IHyprRenderer;
- friend class CHyprGLRenderer;
- friend class CTexPassElement;
- friend class CPreBlurElement;
- friend class CSurfacePassElement;
-};
-
-inline UP<CHyprOpenGLImpl> g_pHyprOpenGL;
+ class CHyprOpenGLImpl {
+ public:
+ CHyprOpenGLImpl();
+ ~CHyprOpenGLImpl();
+
+ struct SRectRenderData {
+ const CRegion* damage = nullptr;
+ int round = 0;
+ float roundingPower = 2.F;
+ bool blur = false;
+ float blurA = 1.F;
+ bool xray = false;
+ };
+
+ struct STextureRenderData {
+ bool blur = false;
+ float blurA = 1.F, overallA = 1.F;
+ bool blockBlurOptimization = false;
+ SP<ITexture> blurredBG;
+
+ const CRegion* damage = nullptr;
+ SP<CWLSurfaceResource> surface = nullptr;
+ float a = 1.F;
+ int round = 0;
+ float roundingPower = 2.F;
+ bool discardActive = false;
+ bool allowCustomUV = false;
+ bool allowDim = true;
+ bool noAA = false; // unused
+ GLenum wrapX = GL_CLAMP_TO_EDGE, wrapY = GL_CLAMP_TO_EDGE;
+ bool cmBackToSRGB = false;
+ bool finalMonitorCM = false;
+ SP<CMonitor> cmBackToSRGBSource;
+
+ uint32_t discardMode = DISCARD_OPAQUE;
+ float discardOpacity = 0.f;
+
+ CRegion clipRegion;
+ PHLLSREF currentLS;
+
+ Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
+ Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
+ };
+
+ struct SBorderRenderData {
+ int round = 0;
+ float roundingPower = 2.F;
+ int borderSize = 1;
+ float a = 1.0;
+ int outerRound = -1; /* use round */
+ };
+
+ void makeEGLCurrent();
+ void begin(PHLMONITOR, const CRegion& damage, SP<IFramebuffer> fb = nullptr, std::optional<CRegion> finalDamage = {});
+ void beginSimple(PHLMONITOR, const CRegion& damage, SP<IRenderbuffer> rb = nullptr, SP<IFramebuffer> fb = nullptr);
+ void end();
+
+ void renderRect(const CBox&, const CHyprColor&, SRectRenderData data);
+ void renderTexture(SP<ITexture>, const CBox&, STextureRenderData data);
+ void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0);
+ void renderInnerGlow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, int glowPower, float a = 1.0);
+ void renderBorder(const CBox&, const Config::CGradientValueData&, SBorderRenderData data);
+ void renderBorder(const CBox&, const Config::CGradientValueData&, const Config::CGradientValueData&, float lerp, SBorderRenderData data);
+ void renderTextureMatte(SP<ITexture> tex, const CBox& pBox, SP<IFramebuffer> matte);
+ void renderTexturePrimitive(SP<ITexture> tex, const CBox& box);
+
+ void setViewport(GLint x, GLint y, GLsizei width, GLsizei height);
+ void setCapStatus(int cap, bool status);
+
+ void blend(bool enabled);
+
+ void scissor(const CBox&, bool transform = true);
+ void scissor(const pixman_box32*, bool transform = true);
+ void scissor(const int x, const int y, const int w, const int h, bool transform = true);
+
+ void destroyMonitorResources(PHLMONITORREF);
+
+ void preRender(PHLMONITOR);
+
+ void saveBufferForMirror(const CBox&);
+
+ void applyScreenShader(const std::string& path);
+
+ void renderOffToMain(SP<IFramebuffer> off);
+
+ std::vector<SDRMFormat> getDRMFormats();
+ std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format);
+ EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs);
+
+ bool initShaders(const std::string& path = "");
+
+ WP<CShader> useShader(WP<CShader> prog);
+
+ bool explicitSyncSupported();
+ WP<CShader> getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0);
+
+ bool m_shadersInitialized = false;
+ SP<SPreparedShaders> m_shaders;
+
+ Hyprutils::OS::CFileDescriptor m_gbmFD;
+ gbm_device* m_gbmDevice = nullptr;
+ EGLContext m_eglContext = nullptr;
+ EGLDisplay m_eglDisplay = nullptr;
+ EGLDeviceEXT m_eglDevice = nullptr;
+
+ std::map<PHLMONITORREF, SP<IFramebuffer>> m_monitorBGFBs;
+
+ struct {
+ PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES = nullptr;
+ PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = nullptr;
+ PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR = nullptr;
+ PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR = nullptr;
+ PFNEGLQUERYDMABUFFORMATSEXTPROC eglQueryDmaBufFormatsEXT = nullptr;
+ PFNEGLQUERYDMABUFMODIFIERSEXTPROC eglQueryDmaBufModifiersEXT = nullptr;
+ PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT = nullptr;
+ PFNEGLDEBUGMESSAGECONTROLKHRPROC eglDebugMessageControlKHR = nullptr;
+ PFNEGLQUERYDEVICESEXTPROC eglQueryDevicesEXT = nullptr;
+ PFNEGLQUERYDEVICESTRINGEXTPROC eglQueryDeviceStringEXT = nullptr;
+ PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = nullptr;
+ PFNEGLCREATESYNCKHRPROC eglCreateSyncKHR = nullptr;
+ PFNEGLDESTROYSYNCKHRPROC eglDestroySyncKHR = nullptr;
+ PFNEGLDUPNATIVEFENCEFDANDROIDPROC eglDupNativeFenceFDANDROID = nullptr;
+ PFNEGLWAITSYNCKHRPROC eglWaitSyncKHR = nullptr;
+ } m_proc;
+
+ struct {
+ bool EXT_read_format_bgra = false;
+ bool EXT_image_dma_buf_import = false;
+ bool EXT_image_dma_buf_import_modifiers = false;
+ bool KHR_context_flush_control = false;
+ bool KHR_display_reference = false;
+ bool IMG_context_priority = false;
+ bool EXT_create_context_robustness = false;
+ bool EGL_ANDROID_native_fence_sync_ext = false;
+ } m_exts;
+
+ enum eEGLContextVersion : uint8_t {
+ EGL_CONTEXT_GLES_2_0 = 0,
+ EGL_CONTEXT_GLES_3_0,
+ EGL_CONTEXT_GLES_3_2,
+ };
+
+ eEGLContextVersion m_eglContextVersion = EGL_CONTEXT_GLES_3_2;
+
+ enum eCachedCapStatus : uint8_t {
+ CAP_STATUS_BLEND = 0,
+ CAP_STATUS_SCISSOR_TEST,
+ CAP_STATUS_STENCIL_TEST,
+ CAP_STATUS_END
+ };
+
+ private:
+ struct {
+ GLint x = 0;
+ GLint y = 0;
+ GLsizei width = 0;
+ GLsizei height = 0;
+ } m_lastViewport;
+
+ std::array<bool, CAP_STATUS_END> m_capStatus = {};
+
+ std::vector<SDRMFormat> m_drmFormats;
+ bool m_hasModifiers = false;
+
+ int m_drmFD = -1;
+ std::string m_extensions;
+
+ bool m_fakeFrame = false;
+ bool m_applyFinalShader = false;
+ bool m_blend = false;
+ bool m_offloadedFramebuffer = false;
+ bool m_cmSupported = true;
+
+ SP<CShader> m_finalScreenShader;
+ GLuint m_currentProgram;
+
+ void initDRMFormats();
+ void initEGL(bool gbm);
+ EGLDeviceEXT eglDeviceFromDRMFD(int drmFD);
+
+ // for the final shader
+ std::array<CTimer, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryTimers = {};
+ std::array<Vector2D, POINTER_PRESSED_HISTORY_LENGTH> m_pressedHistoryPositions = {};
+ GLint m_pressedHistoryKilled = 0;
+ GLint m_pressedHistoryTouched = 0;
+
+ //
+ std::optional<std::vector<uint64_t>> getModsForFormat(EGLint format);
+
+ // returns the out FB, can be either Mirror or MirrorSwap
+ SP<IFramebuffer> blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source);
+
+ void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
+ bool modifySDR, float sdrMinLuminance, int sdrMaxLuminance, const SCMSettings& settings);
+ void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
+ bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
+ void passCMUniforms(WP<CShader>, const NColorManagement::PImageDescription imageDescription);
+ void renderRectInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
+ void renderRectWithBlurInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
+ void renderRectWithDamageInternal(const CBox&, const CHyprColor&, const SRectRenderData& data);
+ WP<CShader> renderToOutputInternal();
+ WP<CShader> renderToFBInternal(SP<ITexture> tex, const STextureRenderData& data, eTextureType texType, const CBox& newBox);
+ void renderTextureInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
+ void renderTextureWithBlurInternal(SP<ITexture>, const CBox&, const STextureRenderData& data);
+
+ friend class IHyprRenderer;
+ friend class CHyprGLRenderer;
+ friend class CGLElementRenderer;
+ friend class CTexPassElement;
+ friend class CPreBlurElement;
+ friend class CSurfacePassElement;
+ };
+
+ inline UP<CHyprOpenGLImpl> g_pHyprOpenGL;
+}
diff --git a/src/render/Renderbuffer.cpp b/src/render/Renderbuffer.cpp
index 5ecbe845..34ce3e6a 100644
--- a/src/render/Renderbuffer.cpp
+++ b/src/render/Renderbuffer.cpp
@@ -7,6 +7,8 @@
#include <dlfcn.h>
+using namespace Render;
+
IRenderbuffer::IRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format) : m_hlBuffer(buffer) {
m_listeners.destroyBuffer = buffer->events.destroy.listen([this] { g_pHyprRenderer->onRenderbufferDestroy(this); });
}
diff --git a/src/render/Renderbuffer.hpp b/src/render/Renderbuffer.hpp
index c33144d3..e19af22f 100644
--- a/src/render/Renderbuffer.hpp
+++ b/src/render/Renderbuffer.hpp
@@ -5,24 +5,26 @@
#include "Framebuffer.hpp"
#include <aquamarine/buffer/Buffer.hpp>
-class IRenderbuffer {
- public:
- IRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
- virtual ~IRenderbuffer() = default;
+namespace Render {
+ class IRenderbuffer {
+ public:
+ IRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
+ virtual ~IRenderbuffer() = default;
- bool good();
- SP<IFramebuffer> getFB();
+ bool good();
+ SP<IFramebuffer> getFB();
- virtual void bind() = 0;
- virtual void unbind() = 0;
+ virtual void bind() = 0;
+ virtual void unbind() = 0;
- WP<Aquamarine::IBuffer> m_hlBuffer;
+ WP<Aquamarine::IBuffer> m_hlBuffer;
- protected:
- SP<IFramebuffer> m_framebuffer;
- bool m_good = false;
+ protected:
+ SP<IFramebuffer> m_framebuffer;
+ bool m_good = false;
- struct {
- CHyprSignalListener destroyBuffer;
- } m_listeners;
-};
+ struct {
+ CHyprSignalListener destroyBuffer;
+ } m_listeners;
+ };
+}
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);
-}
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index d8056d82..ba044567 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -1,47 +1,41 @@
#pragma once
#include "../defines.hpp"
+#include <cstdint>
#include <hyprgraphics/color/Color.hpp>
#include <hyprutils/math/Box.hpp>
+#include <hyprutils/utils/ScopeGuard.hpp>
#include <list>
#include <optional>
+#include "OpenGL.hpp"
+#include "./SyncFDManager.hpp"
+#include "./pass/Pass.hpp"
+#include "./pass/BorderPassElement.hpp"
+#include "./pass/ClearPassElement.hpp"
+#include "./pass/FramebufferElement.hpp"
+#include "./pass/RectPassElement.hpp"
+#include "./pass/RendererHintsPassElement.hpp"
+#include "./pass/ShadowPassElement.hpp"
+#include "./pass/SurfacePassElement.hpp"
+#include "./pass/TexPassElement.hpp"
+#include "./pass/TextureMatteElement.hpp"
+#include "types.hpp"
#include "../helpers/Monitor.hpp"
#include "../desktop/view/LayerSurface.hpp"
-#include "./pass/Pass.hpp"
#include "Renderbuffer.hpp"
#include "../helpers/time/Timer.hpp"
#include "../helpers/math/Math.hpp"
#include "../helpers/time/Time.hpp"
#include "../../protocols/cursor-shape-v1.hpp"
-#include "../desktop/view/Popup.hpp"
+#include "desktop/view/Popup.hpp"
#include "Framebuffer.hpp"
#include "Texture.hpp"
-#include "pass/BorderPassElement.hpp"
-#include "pass/ClearPassElement.hpp"
-#include "pass/FramebufferElement.hpp"
-#include "pass/PreBlurElement.hpp"
-#include "pass/RectPassElement.hpp"
-#include "pass/RendererHintsPassElement.hpp"
-#include "pass/ShadowPassElement.hpp"
-#include "pass/InnerGlowPassElement.hpp"
-#include "pass/SurfacePassElement.hpp"
-#include "pass/TexPassElement.hpp"
-#include "pass/TextureMatteElement.hpp"
struct SMonitorRule;
class CWorkspace;
class CInputPopup;
class IHLBuffer;
class CEventLoopTimer;
-class CRenderPass;
-
-const std::vector<const char*> ASSET_PATHS = {
-#ifdef DATAROOTDIR
- DATAROOTDIR,
-#endif
- "/usr/share",
- "/usr/local/share",
-};
class CToplevelExportProtocolManager;
class CInputManager;
struct SSessionLockSurface;
@@ -49,330 +43,248 @@ namespace Screenshare {
class CScreenshareFrame;
};
-enum eDamageTrackingModes : int8_t {
- DAMAGE_TRACKING_INVALID = -1,
- DAMAGE_TRACKING_NONE = 0,
- DAMAGE_TRACKING_MONITOR,
- DAMAGE_TRACKING_FULL,
-};
-
-enum eRenderPassMode : uint8_t {
- RENDER_PASS_ALL = 0,
- RENDER_PASS_MAIN,
- RENDER_PASS_POPUP
-};
-
-enum eRenderMode : uint8_t {
- RENDER_MODE_NORMAL = 0,
- RENDER_MODE_FULL_FAKE = 1,
- RENDER_MODE_TO_BUFFER = 2,
- RENDER_MODE_TO_BUFFER_READ_ONLY = 3,
-};
-
-struct SRenderWorkspaceUntilData {
- PHLLS ls;
- PHLWINDOW w;
-};
-
-enum eRenderProjectionType : uint8_t {
- RPT_MONITOR,
- RPT_MIRROR,
- RPT_FB,
- RPT_EXPORT,
-};
-
-struct SRenderData {
- // can be private
- Mat3x3 targetProjection;
-
- // ----------------------
-
- // used by public
- Vector2D fbSize = {-1, -1};
- PHLMONITORREF pMonitor;
-
- eRenderProjectionType projectionType = RPT_MONITOR;
-
- SP<IFramebuffer> currentFB = nullptr; // current rendering to
- SP<IFramebuffer> mainFB = nullptr; // main to render to
- SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
-
- CRegion damage;
- CRegion finalDamage; // damage used for funal off -> main
-
- SRenderModifData renderModif;
- float mouseZoomFactor = 1.f;
- bool mouseZoomUseMouse = true; // true by default
- bool useNearestNeighbor = false;
- bool blockScreenShader = false;
-
- Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
- Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
-
- // TODO remove and pass directly
- CBox clipBox = {}; // scaled coordinates
- PHLWINDOWREF currentWindow;
- WP<CWLSurfaceResource> surface;
-
- bool transformDamage = true;
- bool noSimplify = false;
-};
-
-struct STFRange {
- float min = 0;
- float max = 80;
-};
-
-struct SCMSettings {
- NColorManagement::eTransferFunction sourceTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
- NColorManagement::eTransferFunction targetTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
- STFRange srcTFRange;
- STFRange dstTFRange;
- float srcRefLuminance = 80;
- float dstRefLuminance = 80;
- std::array<std::array<double, 3>, 3> convertMatrix;
-
- bool needsTonemap = false;
- float maxLuminance = 80;
- float dstMaxLuminance = 80;
- std::array<std::array<double, 3>, 3> dstPrimaries2XYZ;
- bool needsSDRmod = false;
- float sdrSaturation = 1.0;
- float sdrBrightnessMultiplier = 1.0;
-};
-
-class IHyprRenderer {
- public:
- IHyprRenderer();
- virtual ~IHyprRenderer();
-
- WP<CHyprOpenGLImpl> glBackend();
-
- void renderMonitor(PHLMONITOR pMonitor, bool commit = true);
- void arrangeLayersForMonitor(const MONITORID&);
- void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
- void damageWindow(PHLWINDOW, bool forceFull = false);
- void damageBox(const CBox&, bool skipFrameSchedule = false);
- void damageBox(const int& x, const int& y, const int& w, const int& h);
- void damageRegion(const CRegion&);
- void damageMonitor(PHLMONITOR);
- void damageMirrorsWith(PHLMONITOR, const CRegion&);
- bool shouldRenderWindow(PHLWINDOW, PHLMONITOR);
- bool shouldRenderWindow(PHLWINDOW);
- void ensureCursorRenderingMode();
- bool shouldRenderCursor();
- void setCursorHidden(bool hide);
- void calculateUVForSurface(PHLWINDOW, SP<CWLSurfaceResource>, PHLMONITOR pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {},
- bool fixMisalignedFSV1 = false);
- std::tuple<float, float, float> getRenderTimes(PHLMONITOR pMonitor); // avg max min
- void ensureLockTexturesRendered(bool load);
- void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry);
- void setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
- void setCursorFromName(const std::string& name, bool force = false);
- void onRenderbufferDestroy(IRenderbuffer* rb);
- bool isNvidia();
- bool isIntel();
- bool isSoftware();
- bool isMgpu();
- void addWindowToRenderUnfocused(PHLWINDOW window);
- void makeSnapshot(PHLWINDOW);
- void makeSnapshot(PHLLS);
- void makeSnapshot(WP<Desktop::View::CPopup>);
- void renderSnapshot(PHLWINDOW);
- void renderSnapshot(PHLLS);
- void renderSnapshot(WP<Desktop::View::CPopup>);
- bool beginFullFakeRender(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb);
- bool beginRenderToBuffer(PHLMONITOR pMonitor, CRegion& damage, SP<IHLBuffer> buffer, bool simple = false);
- virtual void startRenderPass() {};
- virtual void endRender(const std::function<void()>& renderingDoneCallback = {}) = 0;
-
- NColorManagement::PImageDescription workBufferImageDescription();
- bool m_bBlockSurfaceFeedback = false;
- bool m_bRenderingSnapshot = false;
- PHLMONITORREF m_mostHzMonitor;
- bool m_directScanoutBlocked = false;
-
- void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
-
- void initiateManualCrash();
- const SRenderData& renderData();
-
- bool m_crashingInProgress = false;
- float m_crashingDistort = 0.5f;
- wl_event_source* m_crashingLoop = nullptr;
- wl_event_source* m_cursorTicker = nullptr;
-
- std::vector<CHLBufferReference> m_usedAsyncBuffers;
-
- struct {
- int hotspotX = 0;
- int hotspotY = 0;
- wpCursorShapeDeviceV1Shape shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
- wpCursorShapeDeviceV1Shape shapePrevious = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
- CTimer switchedTimer;
- std::optional<SP<Desktop::View::CWLSurface>> surf;
- std::string name;
- } m_lastCursorData;
-
- CRenderPass m_renderPass;
-
- SP<ITexture> renderSplash(const std::function<SP<ITexture>(const int, const int, unsigned char* const)>& handleData, const int fontSize, const int maxWidth = 1024,
- const int maxHeight = 1024);
-
- virtual SP<IRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt); // TODO? move to protected and fix CPointerManager::renderHWCursorBuffer
- bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); // TODO? move to protected and fix CMonitorFrameScheduler::onPresented
- SRenderData m_renderData; // TODO? move to protected and fix CRenderPass
- SP<ITexture> m_screencopyDeniedTexture; // TODO? make readonly
- uint m_failedAssetsNo = 0; // TODO? make readonly
- bool m_reloadScreenShader = true; // at launch it can be set
- CTimer m_globalTimer;
-
- void draw(WP<IPassElement> element, const CRegion& damage);
- virtual SP<ITexture> createStencilTexture(const int width, const int height) = 0;
- virtual SP<ITexture> createTexture(bool opaque = false) = 0;
- virtual SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) = 0;
- virtual SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) = 0;
- virtual SP<ITexture> createTexture(const int width, const int height, unsigned char* const) = 0;
- virtual SP<ITexture> createTexture(cairo_surface_t* cairo) = 0;
- virtual SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) = 0;
- virtual SP<ITexture> createTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy = false);
- virtual SP<ITexture> renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, int weight = 400);
- SP<ITexture> loadAsset(const std::string& filename);
- virtual bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
- virtual bool explicitSyncSupported() = 0;
- virtual std::vector<SDRMFormat> getDRMFormats() = 0;
- virtual std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) = 0;
- virtual SP<IFramebuffer> createFB(const std::string& name = "") = 0;
- virtual void disableScissor() = 0;
- virtual void blend(bool enabled) = 0;
- virtual void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) = 0;
- virtual void setViewport(int x, int y, int width, int height) = 0;
-
- bool preBlurQueued(PHLMONITORREF pMonitor);
- void pushMonitorTransformEnabled(bool enabled);
- void popMonitorTransformEnabled();
- bool monitorTransformEnabled();
-
- void setProjectionType(const Vector2D& fbSize);
- void setProjectionType(eRenderProjectionType projectionType);
- Mat3x3 getBoxProjection(const CBox& box, std::optional<eTransform> transform = std::nullopt);
- Mat3x3 projectBoxToTarget(const CBox& box, std::optional<eTransform> transform = std::nullopt);
-
- SP<ITexture> blurMainFramebuffer(float a, CRegion* originalDamage);
- virtual SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) = 0;
- void preBlurForCurrentMonitor(CRegion* fakeDamage);
-
- SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
- SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
- virtual bool reloadShaders(const std::string& path = "") = 0;
-
- bool needsACopyFB(PHLMONITOR mon);
-
- protected:
- virtual void renderOffToMain(IFramebuffer* off) = 0;
- virtual SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) = 0;
- void renderMirrored();
- void setDamage(const CRegion& damage_, std::optional<CRegion> finalDamage);
- // if RENDER_MODE_NORMAL, provided damage will be written to.
- // otherwise, it will be the one used.
- bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, SP<IFramebuffer> fb = nullptr, bool simple = false);
-
- virtual bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) {
- return false;
- };
- virtual bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) {
- return false;
- };
- virtual void initRender() {};
- virtual bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
- return false;
+namespace Render {
+ using CScopeGuard = Hyprutils::Utils::CScopeGuard;
+
+ class IElementRenderer;
+ class CRenderPass;
+
+ class IHyprRenderer {
+ public:
+ IHyprRenderer();
+ virtual ~IHyprRenderer();
+
+ enum eType : uint8_t {
+ RT_GL = 1,
+ RT_VK = 2,
+ };
+
+ virtual eType type() = 0;
+ WP<Render::GL::CHyprOpenGLImpl> glBackend();
+
+ void renderMonitor(PHLMONITOR pMonitor, bool commit = true);
+ void arrangeLayersForMonitor(const MONITORID&);
+ void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
+ void damageWindow(PHLWINDOW, bool forceFull = false);
+ void damageBox(const CBox&, bool skipFrameSchedule = false);
+ void damageBox(const int& x, const int& y, const int& w, const int& h);
+ void damageRegion(const CRegion&);
+ void damageMonitor(PHLMONITOR);
+ void damageMirrorsWith(PHLMONITOR, const CRegion&);
+ bool shouldRenderWindow(PHLWINDOW, PHLMONITOR);
+ bool shouldRenderWindow(PHLWINDOW);
+ void ensureCursorRenderingMode();
+ bool shouldRenderCursor();
+ void setCursorHidden(bool hide);
+
+ std::tuple<float, float, float> getRenderTimes(PHLMONITOR pMonitor); // avg max min
+ void ensureLockTexturesRendered(bool load);
+ void renderLockscreen(PHLMONITOR pMonitor, const Time::steady_tp& now, const CBox& geometry);
+ void setCursorSurface(SP<Desktop::View::CWLSurface> surf, int hotspotX, int hotspotY, bool force = false);
+ void setCursorFromName(const std::string& name, bool force = false);
+ void onRenderbufferDestroy(IRenderbuffer* rb);
+ bool isNvidia();
+ bool isIntel();
+ bool isSoftware();
+ bool isMgpu();
+ void addWindowToRenderUnfocused(PHLWINDOW window);
+ void makeSnapshot(PHLWINDOW);
+ void makeSnapshot(PHLLS);
+ void makeSnapshot(WP<Desktop::View::CPopup>);
+ void renderSnapshot(PHLWINDOW);
+ void renderSnapshot(PHLLS);
+ void renderSnapshot(WP<Desktop::View::CPopup>);
+ bool beginFullFakeRender(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb);
+ bool beginRenderToBuffer(PHLMONITOR pMonitor, CRegion& damage, SP<IHLBuffer> buffer, bool simple = false);
+ virtual void startRenderPass() {};
+ virtual void endRender(const std::function<void()>& renderingDoneCallback = {}) = 0;
+
+ NColorManagement::PImageDescription workBufferImageDescription();
+ bool m_bBlockSurfaceFeedback = false;
+ bool m_bRenderingSnapshot = false;
+ PHLMONITORREF m_mostHzMonitor;
+ bool m_directScanoutBlocked = false;
+
+ void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
+
+ void initiateManualCrash();
+ const SRenderData& renderData();
+
+ bool m_crashingInProgress = false;
+ float m_crashingDistort = 0.5f;
+ wl_event_source* m_crashingLoop = nullptr;
+ wl_event_source* m_cursorTicker = nullptr;
+
+ std::vector<CHLBufferReference> m_usedAsyncBuffers;
+
+ struct {
+ int hotspotX = 0;
+ int hotspotY = 0;
+ wpCursorShapeDeviceV1Shape shape = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
+ wpCursorShapeDeviceV1Shape shapePrevious = WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT;
+ CTimer switchedTimer;
+ std::optional<SP<Desktop::View::CWLSurface>> surf;
+ std::string name;
+ } m_lastCursorData;
+
+ CRenderPass m_renderPass;
+
+ SP<ITexture> renderSplash(const std::function<SP<ITexture>(const int, const int, unsigned char* const)>& handleData, const int fontSize, const int maxWidth = 1024,
+ const int maxHeight = 1024);
+
+ virtual SP<IRenderbuffer> getOrCreateRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt); // TODO? move to protected and fix CPointerManager::renderHWCursorBuffer
+ bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor); // TODO? move to protected and fix CMonitorFrameScheduler::onPresented
+ SRenderData m_renderData; // TODO? move to protected and fix CRenderPass
+ SP<ITexture> m_screencopyDeniedTexture; // TODO? make readonly
+ uint m_failedAssetsNo = 0; // TODO? make readonly
+ bool m_reloadScreenShader = true; // at launch it can be set
+ CTimer m_globalTimer;
+
+ void draw(WP<IPassElement> element, const CRegion& damage = {});
+ void draw(const CBorderPassElement::SBorderData& data, const CRegion& damage = {});
+ void draw(const CClearPassElement::SClearData& data, const CRegion& damage = {});
+ void draw(const CFramebufferElement::SFramebufferElementData& data, const CRegion& damage = {});
+ void draw(const CRectPassElement::SRectData& data, const CRegion& damage = {});
+ void draw(const CRendererHintsPassElement::SData& data, const CRegion& damage = {});
+ void draw(const CShadowPassElement::SShadowData& data, const CRegion& damage = {});
+ void draw(const CSurfacePassElement::SRenderData& data, const CRegion& damage = {});
+ void draw(const CTexPassElement::SRenderData& data, const CRegion& damage = {});
+ void draw(const CTextureMatteElement::STextureMatteData& data, const CRegion& damage = {});
+ virtual void bindFB(SP<IFramebuffer> fb);
+ UP<CScopeGuard> bindTempFB(SP<IFramebuffer> fb);
+ virtual UP<ISyncFDManager> createSyncFDManager() = 0;
+ virtual WP<IElementRenderer> elementRenderer() = 0;
+ virtual SP<ITexture> createStencilTexture(const int width, const int height) = 0;
+ virtual SP<ITexture> createTexture(bool opaque = false) = 0;
+ virtual SP<ITexture> createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) = 0;
+ virtual SP<ITexture> createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) = 0;
+ virtual SP<ITexture> createTexture(const int width, const int height, unsigned char* const) = 0;
+ virtual SP<ITexture> createTexture(cairo_surface_t* cairo) = 0;
+ virtual SP<ITexture> createTexture(std::span<const float> lut3D, size_t N) = 0;
+ virtual SP<ITexture> createTexture(const SP<Aquamarine::IBuffer> buffer, bool keepDataCopy = false);
+ virtual SP<ITexture> renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0,
+ int weight = 400);
+ SP<ITexture> loadAsset(const std::string& filename);
+ virtual bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow);
+ virtual bool explicitSyncSupported() = 0;
+ virtual std::vector<SDRMFormat> getDRMFormats() = 0;
+ virtual std::vector<uint64_t> getDRMFormatModifiers(DRMFormat format) = 0;
+ virtual SP<IFramebuffer> createFB(const std::string& name = "") = 0;
+ virtual void disableScissor() = 0;
+ virtual void blend(bool enabled) = 0;
+ virtual void drawShadow(const CBox& box, int round, float roundingPower, int range, CHyprColor color, float a) = 0;
+ virtual void setViewport(int x, int y, int width, int height) = 0;
+
+ bool preBlurQueued(PHLMONITORREF pMonitor);
+ void pushMonitorTransformEnabled(bool enabled);
+ void popMonitorTransformEnabled();
+ bool monitorTransformEnabled();
+
+ void setProjectionType(const Vector2D& fbSize);
+ void setProjectionType(eRenderProjectionType projectionType);
+ Mat3x3 getBoxProjection(const CBox& box, std::optional<eTransform> transform = std::nullopt);
+ Mat3x3 projectBoxToTarget(const CBox& box, std::optional<eTransform> transform = std::nullopt);
+
+ SP<ITexture> blurMainFramebuffer(float a, CRegion* originalDamage);
+ virtual SP<ITexture> blurFramebuffer(SP<IFramebuffer> source, float a, CRegion* originalDamage) = 0;
+ void preBlurForCurrentMonitor(CRegion* fakeDamage);
+
+ SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription,
+ SP<CWLSurfaceResource> surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1);
+ virtual bool reloadShaders(const std::string& path = "") = 0;
+
+ protected:
+ virtual void renderOffToMain(SP<IFramebuffer> off) = 0;
+ virtual SP<IRenderbuffer> getOrCreateRenderbufferInternal(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) = 0;
+ void renderMirrored();
+ void setDamage(const CRegion& damage_, std::optional<CRegion> finalDamage);
+ // if RENDER_MODE_NORMAL, provided damage will be written to.
+ // otherwise, it will be the one used.
+ bool beginRender(PHLMONITOR pMonitor, CRegion& damage, eRenderMode mode = RENDER_MODE_NORMAL, SP<IHLBuffer> buffer = {}, SP<IFramebuffer> fb = nullptr,
+ bool simple = false);
+
+ virtual bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) {
+ return false;
+ };
+ virtual bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP<IFramebuffer> fb, bool simple = false) {
+ return false;
+ };
+ virtual void initRender() {};
+ virtual bool initRenderBuffer(SP<Aquamarine::IBuffer> buffer, uint32_t fmt) {
+ return false;
+ };
+
+ SP<ITexture> getBackground(PHLMONITOR pMonitor);
+ virtual SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor);
+ SP<ITexture> m_lockDeadTexture;
+ SP<ITexture> m_lockDead2Texture;
+ SP<ITexture> m_lockTtyTextTexture;
+ bool m_monitorTransformEnabled = false; // do not modify directly
+ std::stack<bool> m_monitorTransformStack;
+
+ // old private:
+ void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
+ void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
+ void renderWorkspaceWindowsFullscreen(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
+ void renderWorkspaceWindows(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
+ void renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
+ void renderWindow(PHLWINDOW, PHLMONITOR, const Time::steady_tp&, bool, eRenderPassMode, bool ignorePosition = false, bool standalone = false);
+ void renderLayer(PHLLS, PHLMONITOR, const Time::steady_tp&, bool popups = false, bool lockscreen = false);
+ void renderSessionLockSurface(WP<SSessionLockSurface>, PHLMONITOR, const Time::steady_tp&);
+ void renderDragIcon(PHLMONITOR, const Time::steady_tp&);
+ void renderIMEPopup(CInputPopup*, PHLMONITOR, const Time::steady_tp&);
+ void sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace,
+ const Time::steady_tp& now); // sends frame displayed events but doesn't actually render anything
+ void renderSessionLockPrimer(PHLMONITOR pMonitor);
+ void renderSessionLockMissing(PHLMONITOR pMonitor);
+ void renderBackground(PHLMONITOR pMonitor);
+ void requestBackgroundResource();
+ std::string resolveAssetPath(const std::string& file);
+ void initMissingAssetTexture();
+ void initAssets();
+ SP<ITexture> m_missingAssetTexture;
+ ASP<Hyprgraphics::CImageResource> m_backgroundResource;
+ bool m_backgroundResourceFailed = false;
+
+ bool shouldBlur(PHLLS ls);
+ bool shouldBlur(PHLWINDOW w);
+ bool shouldBlur(WP<Desktop::View::CPopup> p);
+
+ bool m_cursorHidden = false;
+ bool m_cursorHiddenByCondition = false;
+ bool m_cursorHasSurface = false;
+ SP<Aquamarine::IBuffer> m_currentBuffer = nullptr;
+ eRenderMode m_renderMode = RENDER_MODE_NORMAL;
+ bool m_nvidia = false;
+ bool m_intel = false;
+ bool m_software = false;
+ bool m_mgpu = false;
+
+ struct {
+ bool hiddenOnTouch = false;
+ bool hiddenOnTablet = false;
+ bool hiddenOnTimeout = false;
+ bool hiddenOnKeyboard = false;
+ } m_cursorHiddenConditions;
+
+ std::vector<SP<IRenderbuffer>> m_renderbuffers;
+ std::vector<PHLWINDOWREF> m_renderUnfocused;
+ SP<CEventLoopTimer> m_renderUnfocusedTimer;
+
+ friend class CRenderPass;
+ friend class Render::GL::CHyprOpenGLImpl;
+ friend class CToplevelExportFrame;
+ friend class Screenshare::CScreenshareFrame;
+ friend class CInputManager;
+ friend class CPointerManager;
+ friend class CMonitor;
+ friend class CMonitorFrameScheduler;
+
+ private:
+ void bindOffMain();
+ void bindBackOnMain();
};
- SP<ITexture> getBackground(PHLMONITOR pMonitor);
- virtual void draw(CBorderPassElement* element, const CRegion& damage) = 0;
- virtual void draw(CClearPassElement* element, const CRegion& damage) = 0;
- virtual void draw(CFramebufferElement* element, const CRegion& damage) = 0;
- virtual void draw(CPreBlurElement* element, const CRegion& damage) = 0;
- virtual void draw(CRectPassElement* element, const CRegion& damage) = 0;
- virtual void draw(CShadowPassElement* element, const CRegion& damage) = 0;
- virtual void draw(CInnerGlowPassElement* element, const CRegion& damage) = 0;
- virtual void draw(CTexPassElement* element, const CRegion& damage) = 0;
- virtual void draw(CTextureMatteElement* element, const CRegion& damage) = 0;
- virtual SP<ITexture> getBlurTexture(PHLMONITORREF pMonitor);
- SP<ITexture> m_lockDeadTexture;
- SP<ITexture> m_lockDead2Texture;
- SP<ITexture> m_lockTtyTextTexture;
- bool m_monitorTransformEnabled = false; // do not modify directly
- std::stack<bool> m_monitorTransformStack;
-
- // old private:
- void arrangeLayerArray(PHLMONITOR, const std::vector<PHLLSREF>&, bool, CBox*);
- void renderWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const CBox& geometry);
- void renderWorkspaceWindowsFullscreen(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (fullscreen) (tiled, floating, pinned, but no special)
- void renderWorkspaceWindows(PHLMONITOR, PHLWORKSPACE, const Time::steady_tp&); // renders workspace windows (no fullscreen) (tiled, floating, pinned, but no special)
- void renderAllClientsForWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now, const Vector2D& translate = {0, 0}, const float& scale = 1.f);
- void renderWindow(PHLWINDOW, PHLMONITOR, const Time::steady_tp&, bool, eRenderPassMode, bool ignorePosition = false, bool standalone = false);
- void renderLayer(PHLLS, PHLMONITOR, const Time::steady_tp&, bool popups = false, bool lockscreen = false);
- void renderSessionLockSurface(WP<SSessionLockSurface>, PHLMONITOR, const Time::steady_tp&);
- void renderDragIcon(PHLMONITOR, const Time::steady_tp&);
- void renderIMEPopup(CInputPopup*, PHLMONITOR, const Time::steady_tp&);
- void sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE pWorkspace, const Time::steady_tp& now); // sends frame displayed events but doesn't actually render anything
- void renderSessionLockPrimer(PHLMONITOR pMonitor);
- void renderSessionLockMissing(PHLMONITOR pMonitor);
- void renderBackground(PHLMONITOR pMonitor);
- void requestBackgroundResource();
- std::string resolveAssetPath(const std::string& file);
- void initMissingAssetTexture();
- void initAssets();
- SP<ITexture> m_missingAssetTexture;
- ASP<Hyprgraphics::CImageResource> m_backgroundResource;
- bool m_backgroundResourceFailed = false;
-
- bool shouldBlur(PHLLS ls);
- bool shouldBlur(PHLWINDOW w);
- bool shouldBlur(WP<Desktop::View::CPopup> p);
-
- bool m_cursorHidden = false;
- bool m_cursorHiddenByCondition = false;
- bool m_cursorHasSurface = false;
- SP<Aquamarine::IBuffer> m_currentBuffer = nullptr;
- eRenderMode m_renderMode = RENDER_MODE_NORMAL;
- bool m_nvidia = false;
- bool m_intel = false;
- bool m_software = false;
- bool m_mgpu = false;
-
- struct {
- bool hiddenOnTouch = false;
- bool hiddenOnTablet = false;
- bool hiddenOnTimeout = false;
- bool hiddenOnKeyboard = false;
- } m_cursorHiddenConditions;
-
- std::vector<SP<IRenderbuffer>> m_renderbuffers;
- std::vector<PHLWINDOWREF> m_renderUnfocused;
- SP<CEventLoopTimer> m_renderUnfocusedTimer;
-
- friend class CRenderPass;
- friend class CHyprOpenGLImpl;
- friend class CToplevelExportFrame;
- friend class Screenshare::CScreenshareFrame;
- friend class CInputManager;
- friend class CPointerManager;
- friend class CMonitor;
- friend class CMonitorFrameScheduler;
-
- private:
- void bindOffMain();
- void bindBackOnMain();
-
- void drawRect(CRectPassElement* element, const CRegion& damage);
- void drawHints(CRendererHintsPassElement* element, const CRegion& damage);
- void drawPreBlur(CPreBlurElement* element, const CRegion& damage);
- void drawSurface(CSurfacePassElement* element, const CRegion& damage);
- void preDrawSurface(CSurfacePassElement* element, const CRegion& damage);
- void drawTex(CTexPassElement* element, const CRegion& damage);
- void drawTexMatte(CTextureMatteElement* element, const CRegion& damage);
-};
+}
-inline UP<IHyprRenderer> g_pHyprRenderer;
+inline UP<Render::IHyprRenderer> g_pHyprRenderer; \ No newline at end of file
diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp
index ed272fcd..dfc9045a 100644
--- a/src/render/Shader.cpp
+++ b/src/render/Shader.cpp
@@ -5,6 +5,8 @@
#define EPSILON(x, y) (std::abs((x) - (y)) < 1e-5f)
+using namespace Render::GL;
+
static bool compareFloat(auto a, auto b) {
if (a.size() != b.size())
return false;
diff --git a/src/render/ShaderLoader.cpp b/src/render/ShaderLoader.cpp
index 5cef2d99..388c1d43 100644
--- a/src/render/ShaderLoader.cpp
+++ b/src/render/ShaderLoader.cpp
@@ -14,8 +14,6 @@
using namespace Render;
-using namespace Render;
-
CShaderLoader::CShaderLoader(const std::vector<std::string> includes, const std::array<std::string, SH_FRAG_LAST>& frags, const std::string shaderPath) : m_shaderPath(shaderPath) {
m_callbacks = glsl_include_callbacks_t{
.include_local =
@@ -72,6 +70,7 @@ std::string CShaderLoader::getDefines(ShaderFeatureFlags features) {
{"USE_RGBA", features & SH_FEAT_RGBA ? "1" : "0"}, {"USE_DISCARD", features & SH_FEAT_DISCARD ? "1" : "0"}, {"USE_TINT", features & SH_FEAT_TINT ? "1" : "0"},
{"USE_ROUNDING", features & SH_FEAT_ROUNDING ? "1" : "0"}, {"USE_CM", features & SH_FEAT_CM ? "1" : "0"}, {"USE_TONEMAP", features & SH_FEAT_TONEMAP ? "1" : "0"},
{"USE_SDR_MOD", features & SH_FEAT_SDR_MOD ? "1" : "0"}, {"USE_BLUR", features & SH_FEAT_BLUR ? "1" : "0"}, {"USE_ICC", features & SH_FEAT_ICC ? "1" : "0"},
+ {"USE_MIRROR", features & SH_FEAT_MIRROR ? "1" : "0"},
};
for (const auto& [name, value] : defines) {
res += std::format("#define {} {}\n", name, value);
diff --git a/src/render/ShaderLoader.hpp b/src/render/ShaderLoader.hpp
index 9f3f787d..58184659 100644
--- a/src/render/ShaderLoader.hpp
+++ b/src/render/ShaderLoader.hpp
@@ -20,6 +20,7 @@ namespace Render {
SH_FEAT_SDR_MOD = (1 << 6), // uniforms: sdrSaturation, sdrBrightnessMultiplier; condition: SDR <-> HDR && (sdrSaturation != 1 || sdrBrightnessMultiplier != 1)
SH_FEAT_BLUR = (1 << 7), // condition: render:use_shader_blur_blend
SH_FEAT_ICC = (1 << 8), //
+ SH_FEAT_MIRROR = (1 << 9), // condition: mirror or screenshare
// uniforms: targetPrimariesXYZ; condition: SH_FEAT_TONEMAP || SH_FEAT_SDR_MOD
};
diff --git a/src/render/SyncFDManager.cpp b/src/render/SyncFDManager.cpp
new file mode 100644
index 00000000..3895c406
--- /dev/null
+++ b/src/render/SyncFDManager.cpp
@@ -0,0 +1,16 @@
+#include "SyncFDManager.hpp"
+#include <utility>
+
+using namespace Render;
+
+Hyprutils::OS::CFileDescriptor& ISyncFDManager::fd() {
+ return m_fd;
+}
+
+Hyprutils::OS::CFileDescriptor&& ISyncFDManager::takeFd() {
+ return std::move(m_fd);
+}
+
+bool ISyncFDManager::isValid() {
+ return m_valid && m_fd.isValid();
+}
diff --git a/src/render/SyncFDManager.hpp b/src/render/SyncFDManager.hpp
new file mode 100644
index 00000000..5996fbeb
--- /dev/null
+++ b/src/render/SyncFDManager.hpp
@@ -0,0 +1,20 @@
+#pragma once
+
+#include <hyprutils/os/FileDescriptor.hpp>
+
+namespace Render {
+ class ISyncFDManager {
+ public:
+ virtual ~ISyncFDManager() = default;
+
+ Hyprutils::OS::CFileDescriptor& fd();
+ Hyprutils::OS::CFileDescriptor&& takeFd();
+ virtual bool isValid();
+
+ protected:
+ ISyncFDManager() = default;
+
+ Hyprutils::OS::CFileDescriptor m_fd;
+ bool m_valid = false;
+ };
+}
diff --git a/src/render/Texture.cpp b/src/render/Texture.cpp
index 28ae4b41..1201f044 100644
--- a/src/render/Texture.cpp
+++ b/src/render/Texture.cpp
@@ -1,6 +1,8 @@
#include "Texture.hpp"
#include <cstring>
+using namespace Render;
+
ITexture::ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy, bool opaque) :
m_size(size), m_opaque(opaque), m_drmFormat(drmFormat), m_keepDataCopy(keepDataCopy) {
if (m_keepDataCopy && stride && pixels) {
diff --git a/src/render/Texture.hpp b/src/render/Texture.hpp
index 38c3ff01..473e5ad9 100644
--- a/src/render/Texture.hpp
+++ b/src/render/Texture.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "../defines.hpp"
+#include "../helpers/cm/ColorManagement.hpp"
#include <aquamarine/buffer/Buffer.hpp>
#include <hyprutils/math/Misc.hpp>
#include <span>
@@ -8,51 +9,56 @@
class IHLBuffer;
HYPRUTILS_FORWARD(Math, CRegion);
-enum eTextureType : int8_t {
- TEXTURE_INVALID = -1, // Invalid
- TEXTURE_RGBA = 0, // 4 channels
- TEXTURE_RGBX, // discard A
- TEXTURE_3D_LUT, // 3D LUT
- TEXTURE_EXTERNAL, // EGLImage
-};
-
-class ITexture {
- public:
- ITexture(ITexture&) = delete;
- ITexture(ITexture&&) = delete;
- ITexture(const ITexture&&) = delete;
- ITexture(const ITexture&) = delete;
-
- virtual ~ITexture() = default;
-
- virtual void setTexParameter(GLenum pname, GLint param) = 0;
- virtual void allocate(const Vector2D& size, uint32_t drmFormat = 0) = 0;
- virtual void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) = 0;
- virtual void bind() {};
- virtual void unbind() {};
- virtual bool ok();
- virtual bool isDMA();
-
- const std::vector<uint8_t>& dataCopy();
-
- eTextureType m_type = TEXTURE_RGBA;
- Vector2D m_size = {};
- eTransform m_transform = HYPRUTILS_TRANSFORM_NORMAL;
- bool m_opaque = false;
-
- uint32_t m_drmFormat = 0; // for shm
- bool m_isSynchronous = false;
-
- // TODO move to GLTexture
- GLuint m_texID = 0;
- GLenum magFilter = GL_LINEAR; // useNearestNeighbor overwrites these
- GLenum minFilter = GL_LINEAR;
-
- protected:
- ITexture() = default;
- ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false);
- ITexture(std::span<const float> lut3D, size_t N);
-
- bool m_keepDataCopy = false;
- std::vector<uint8_t> m_dataCopy;
-};
+namespace Render {
+ enum eTextureType : int8_t {
+ TEXTURE_INVALID = -1, // Invalid
+ TEXTURE_RGBA = 0, // 4 channels
+ TEXTURE_RGBX, // discard A
+ TEXTURE_3D_LUT, // 3D LUT
+ TEXTURE_EXTERNAL, // EGLImage
+ };
+
+ class ITexture {
+ public:
+ ITexture(ITexture&) = delete;
+ ITexture(ITexture&&) = delete;
+ ITexture(const ITexture&&) = delete;
+ ITexture(const ITexture&) = delete;
+
+ virtual ~ITexture() = default;
+
+ virtual void setTexParameter(GLenum pname, GLint param) = 0;
+ virtual void allocate(const Vector2D& size, uint32_t drmFormat = 0) = 0;
+ virtual void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) = 0;
+ virtual void bind() {};
+ virtual void unbind() {};
+ virtual bool ok();
+ virtual bool isDMA();
+
+ const std::vector<uint8_t>& dataCopy();
+
+ eTextureType m_type = TEXTURE_RGBA;
+ Vector2D m_size = {};
+ eTransform m_transform = HYPRUTILS_TRANSFORM_NORMAL;
+ bool m_opaque = false;
+
+ uint32_t m_drmFormat = 0; // for shm
+ bool m_isSynchronous = false;
+
+ // CM
+ NColorManagement::PImageDescription m_imageDescription;
+
+ // TODO move to GLTexture
+ GLuint m_texID = 0;
+ GLenum magFilter = GL_LINEAR; // useNearestNeighbor overwrites these
+ GLenum minFilter = GL_LINEAR;
+
+ protected:
+ ITexture() = default;
+ ITexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false);
+ ITexture(std::span<const float> lut3D, size_t N);
+
+ bool m_keepDataCopy = false;
+ std::vector<uint8_t> m_dataCopy;
+ };
+}
diff --git a/src/render/Transformer.hpp b/src/render/Transformer.hpp
index 8f401859..bebf5500 100644
--- a/src/render/Transformer.hpp
+++ b/src/render/Transformer.hpp
@@ -14,7 +14,7 @@ class IWindowTransformer {
// called by Hyprland. For more data about what is being rendered, inspect render data.
// returns the out fb.
- virtual IFramebuffer* transform(IFramebuffer* in) = 0;
+ virtual SP<Render::IFramebuffer> transform(SP<Render::IFramebuffer> in) = 0;
// called by Hyprland before a window main pass is started.
virtual void preWindowRender(CSurfacePassElement::SRenderData* pRenderData);
diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp
index 2d4eaba2..44a42d25 100644
--- a/src/render/decorations/CHyprDropShadowDecoration.cpp
+++ b/src/render/decorations/CHyprDropShadowDecoration.cpp
@@ -4,6 +4,7 @@
#include "../../config/ConfigValue.hpp"
#include "../pass/ShadowPassElement.hpp"
#include "../Renderer.hpp"
+#include "../pass/RectPassElement.hpp"
#include "../pass/TextureMatteElement.hpp"
CHyprDropShadowDecoration::CHyprDropShadowDecoration(PHLWINDOW pWindow) : IHyprWindowDecoration(pWindow), m_window(pWindow) {
@@ -233,50 +234,50 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) {
g_pHyprRenderer->disableScissor();
if (data.ignoreWindow) {
- // we'll take the liberty of using this as it should not be used rn
- const auto alphaFB = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB;
- const auto alphaSwapFB = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB;
- const auto LASTFB = g_pHyprRenderer->m_renderData.currentFB;
+ const auto alphaFB = g_pHyprRenderer->m_renderData.pMonitor->resources()->getUnusedWorkBuffer();
+ const auto alphaSwapFB = g_pHyprRenderer->m_renderData.pMonitor->resources()->getUnusedWorkBuffer();
CBox monbox = {0, 0, pMonitor->m_transformedSize.x, pMonitor->m_transformedSize.y};
- alphaFB->bind();
+ auto guard = g_pHyprRenderer->bindTempFB(alphaFB); // store current FB inside guard
+ // TODO not needed for 8bpc and 16fp?
// build the matte
// 10-bit formats have dogshit alpha channels, so we have to use the matte to its fullest.
// first, clear region of interest with black (fully transparent)
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{.box = data.fullBox, .color = CHyprColor(0, 0, 0, 1), .round = 0}), monbox);
+ g_pHyprRenderer->draw(CRectPassElement::SRectData{.box = data.fullBox, .color = CHyprColor(0, 0, 0, 1), .round = 0}, monbox);
// render white shadow with the alpha of the shadow color (otherwise we clear with alpha later and shit it to 2 bit)
drawShadowInternal(data.fullBox, data.rounding * pMonitor->m_scale, data.roundingPower, data.size * pMonitor->m_scale,
CHyprColor(1, 1, 1, PWINDOW->m_realShadowColor->value().a), a);
// render black window box ("clip")
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
- .box = data.windowBox,
- .color = CHyprColor(0, 0, 0, 1),
- .round = (data.rounding + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale,
- .roundingPower = data.roundingPower,
- }),
- monbox);
+ g_pHyprRenderer->draw(
+ CRectPassElement::SRectData{
+ .box = data.windowBox,
+ .color = CHyprColor(0, 0, 0, 1),
+ .round = (data.rounding + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale,
+ .roundingPower = data.roundingPower,
+ },
+ monbox);
- alphaSwapFB->bind();
+ g_pHyprRenderer->bindFB(alphaSwapFB);
// alpha swap just has the shadow color. It will be the "texture" to render.
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{.box = data.fullBox, .color = PWINDOW->m_realShadowColor->value().stripA(), .round = 0}),
- monbox);
+ g_pHyprRenderer->draw(CRectPassElement::SRectData{.box = data.fullBox, .color = PWINDOW->m_realShadowColor->value().stripA(), .round = 0}, monbox);
- LASTFB->bind();
+ guard.reset(); // restore FB
g_pHyprRenderer->pushMonitorTransformEnabled(true);
g_pHyprRenderer->m_renderData.renderModif.enabled = false;
- g_pHyprRenderer->draw(makeUnique<CTextureMatteElement>(CTextureMatteElement::STextureMatteData{
- .box = monbox,
- .tex = alphaSwapFB->getTexture(),
- .fb = alphaFB,
- }),
- {});
+ g_pHyprRenderer->draw(
+ CTextureMatteElement::STextureMatteData{
+ .box = monbox,
+ .tex = alphaSwapFB->getTexture(),
+ .fb = alphaFB,
+ },
+ {});
g_pHyprRenderer->m_renderData.renderModif.enabled = true;
g_pHyprRenderer->popMonitorTransformEnabled();
@@ -303,13 +304,12 @@ void CHyprDropShadowDecoration::drawShadowInternal(const CBox& box, int round, f
color.a *= a;
if (*PSHADOWSHARP)
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(CRectPassElement::SRectData{
- .box = box,
- .color = color,
- .round = round,
- .roundingPower = roundingPower,
- }),
- {});
+ g_pHyprRenderer->draw(CRectPassElement::SRectData{
+ .box = box,
+ .color = color,
+ .round = round,
+ .roundingPower = roundingPower,
+ });
else
g_pHyprRenderer->drawShadow(box, round, roundingPower, range, color, 1.F);
}
diff --git a/src/render/decorations/CHyprGroupBarDecoration.hpp b/src/render/decorations/CHyprGroupBarDecoration.hpp
index 5c3f4ae5..f6581c8d 100644
--- a/src/render/decorations/CHyprGroupBarDecoration.hpp
+++ b/src/render/decorations/CHyprGroupBarDecoration.hpp
@@ -12,13 +12,13 @@ class CTitleTex {
CTitleTex(PHLWINDOW pWindow, const Vector2D& bufferSize, const float monitorScale);
~CTitleTex() = default;
- SP<ITexture> m_texActive;
- SP<ITexture> m_texInactive;
- SP<ITexture> m_texLockedActive;
- SP<ITexture> m_texLockedInactive;
- std::string m_content;
+ SP<Render::ITexture> m_texActive;
+ SP<Render::ITexture> m_texInactive;
+ SP<Render::ITexture> m_texLockedActive;
+ SP<Render::ITexture> m_texLockedInactive;
+ std::string m_content;
- PHLWINDOWREF m_windowOwner;
+ PHLWINDOWREF m_windowOwner;
};
void refreshGroupBarGradients();
diff --git a/src/render/decorations/CHyprInnerGlowDecoration.cpp b/src/render/decorations/CHyprInnerGlowDecoration.cpp
index a60deccb..687a77b1 100644
--- a/src/render/decorations/CHyprInnerGlowDecoration.cpp
+++ b/src/render/decorations/CHyprInnerGlowDecoration.cpp
@@ -94,7 +94,8 @@ void CHyprInnerGlowDecoration::render(PHLMONITOR pMonitor, float const& a) {
g_pHyprRenderer->blend(true);
- g_pHyprOpenGL->renderInnerGlow(windowBox, ROUNDING * pMonitor->m_scale, ROUNDINGPOWER, GLOWSIZE * pMonitor->m_scale, GLOWCOLOR, GLOWPOWER, a);
+ // FIXME use g_pHyprRenderer API
+ Render::GL::g_pHyprOpenGL->renderInnerGlow(windowBox, ROUNDING * pMonitor->m_scale, ROUNDINGPOWER, GLOWSIZE * pMonitor->m_scale, GLOWCOLOR, GLOWPOWER, a);
g_pHyprRenderer->m_renderData.currentWindow.reset();
}
diff --git a/src/render/gl/GLElementRenderer.cpp b/src/render/gl/GLElementRenderer.cpp
new file mode 100644
index 00000000..670c7886
--- /dev/null
+++ b/src/render/gl/GLElementRenderer.cpp
@@ -0,0 +1,138 @@
+#include "GLElementRenderer.hpp"
+#include "../Renderer.hpp"
+#include "../decorations/CHyprDropShadowDecoration.hpp"
+#include "../OpenGL.hpp"
+#include "../decorations/CHyprInnerGlowDecoration.hpp"
+#include <cstdint>
+
+using namespace Render::GL;
+
+void CGLElementRenderer::draw(WP<CBorderPassElement> element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ if (m_data.hasGrad2)
+ g_pHyprOpenGL->renderBorder(
+ m_data.box, m_data.grad1, m_data.grad2, m_data.lerp,
+ {.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
+ else
+ g_pHyprOpenGL->renderBorder(
+ m_data.box, m_data.grad1,
+ {.round = m_data.round, .roundingPower = m_data.roundingPower, .borderSize = m_data.borderSize, .a = m_data.a, .outerRound = m_data.outerRound});
+};
+
+void CGLElementRenderer::draw(WP<CClearPassElement> element, const CRegion& damage) {
+ const auto& color = element->m_data.color;
+ RASSERT(g_pHyprRenderer->m_renderData.pMonitor, "Tried to render without begin()!");
+
+ TRACY_GPU_ZONE("RenderClear");
+
+ GLCALL(glClearColor(color.r, color.g, color.b, color.a));
+
+ if (!g_pHyprRenderer->m_renderData.damage.empty()) {
+ g_pHyprRenderer->m_renderData.damage.forEachRect([](const auto& RECT) {
+ g_pHyprOpenGL->scissor(&RECT, g_pHyprRenderer->m_renderData.transformDamage);
+ glClear(GL_COLOR_BUFFER_BIT);
+ });
+ }
+};
+
+void CGLElementRenderer::draw(WP<CFramebufferElement> element, const CRegion& damage) {
+ Log::logger->log(Log::ERR, "Deprecated CFramebufferElement. Use g_pHyprRenderer->m_renderData and CTexPassElement instead");
+ // const auto m_data = element->m_data;
+ // SP<IFramebuffer> fb = nullptr;
+
+ // if (m_data.main) {
+ // switch (m_data.framebufferID) {
+ // case FB_MONITOR_RENDER_MAIN: fb = g_pHyprRenderer->m_renderData.mainFB; break;
+ // case FB_MONITOR_RENDER_CURRENT: fb = g_pHyprRenderer->m_renderData.currentFB; break;
+ // case FB_MONITOR_RENDER_OUT: fb = g_pHyprRenderer->m_renderData.outFB; break;
+ // default: fb = nullptr;
+ // }
+
+ // if (!fb) {
+ // Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: main but null");
+ // return;
+ // }
+
+ // } else {
+ // switch (m_data.framebufferID) {
+ // case FB_MONITOR_RENDER_EXTRA_OFFLOAD: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offloadFB; break;
+ // case FB_MONITOR_RENDER_EXTRA_MIRROR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorFB; break;
+ // case FB_MONITOR_RENDER_EXTRA_MIRROR_SWAP: fb = g_pHyprRenderer->m_renderData.pMonitor->m_mirrorSwapFB; break;
+ // case FB_MONITOR_RENDER_EXTRA_OFF_MAIN: fb = g_pHyprRenderer->m_renderData.pMonitor->m_offMainFB; break;
+ // case FB_MONITOR_RENDER_EXTRA_MONITOR_MIRROR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_monitorMirrorFB; break;
+ // case FB_MONITOR_RENDER_EXTRA_BLUR: fb = g_pHyprRenderer->m_renderData.pMonitor->m_blurFB; break;
+ // default: fb = nullptr;
+ // }
+
+ // if (!fb) {
+ // Log::logger->log(Log::ERR, "BUG THIS: CFramebufferElement::draw: not main but null");
+ // return;
+ // }
+ // }
+
+ // g_pHyprRenderer->bindFB(fb);
+};
+
+void CGLElementRenderer::draw(WP<CPreBlurElement> element, const CRegion& damage) {
+ auto dmg = damage;
+ g_pHyprRenderer->preBlurForCurrentMonitor(&dmg);
+};
+
+void CGLElementRenderer::draw(WP<CRectPassElement> element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+
+ if (m_data.color.a == 1.F || !m_data.blur)
+ g_pHyprOpenGL->renderRect(m_data.box, m_data.color, {.damage = &damage, .round = m_data.round, .roundingPower = m_data.roundingPower});
+ else
+ g_pHyprOpenGL->renderRect(m_data.box, m_data.color,
+ {.round = m_data.round, .roundingPower = m_data.roundingPower, .blur = true, .blurA = m_data.blurA, .xray = m_data.xray});
+};
+
+void CGLElementRenderer::draw(WP<CShadowPassElement> element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ m_data.deco->render(g_pHyprRenderer->m_renderData.pMonitor.lock(), m_data.a);
+};
+
+void CGLElementRenderer::draw(WP<CInnerGlowPassElement> element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+ m_data.deco->render(g_pHyprRenderer->m_renderData.pMonitor.lock(), m_data.a);
+};
+
+void CGLElementRenderer::draw(WP<CTexPassElement> element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+
+ g_pHyprOpenGL->renderTexture( //
+ m_data.tex, m_data.box,
+ {
+ // blur settings for m_data.blur == true
+ .blur = m_data.blur,
+ .blurA = m_data.blurA,
+ .overallA = m_data.overallA,
+ .blockBlurOptimization = m_data.blockBlurOptimization.value_or(false),
+ .blurredBG = m_data.blurredBG,
+
+ // common settings
+ .damage = m_data.damage.empty() ? &damage : &m_data.damage,
+ .surface = m_data.surface,
+ .a = m_data.a,
+ .round = m_data.round,
+ .roundingPower = m_data.roundingPower,
+ .discardActive = m_data.discardActive,
+ .allowCustomUV = m_data.allowCustomUV,
+ .cmBackToSRGB = m_data.cmBackToSRGB,
+ .cmBackToSRGBSource = m_data.cmBackToSRGBSource,
+ .discardMode = m_data.ignoreAlpha.has_value() ? sc<uint32_t>(DISCARD_ALPHA) : m_data.discardMode,
+ .discardOpacity = m_data.ignoreAlpha.has_value() ? *m_data.ignoreAlpha : m_data.discardOpacity,
+ .clipRegion = m_data.clipRegion,
+ .currentLS = m_data.currentLS,
+
+ .primarySurfaceUVTopLeft = g_pHyprRenderer->m_renderData.primarySurfaceUVTopLeft,
+ .primarySurfaceUVBottomRight = g_pHyprRenderer->m_renderData.primarySurfaceUVBottomRight,
+ });
+};
+
+void CGLElementRenderer::draw(WP<CTextureMatteElement> element, const CRegion& damage) {
+ const auto m_data = element->m_data;
+
+ g_pHyprOpenGL->renderTextureMatte(m_data.tex, m_data.box, m_data.fb);
+}; \ No newline at end of file
diff --git a/src/render/gl/GLElementRenderer.hpp b/src/render/gl/GLElementRenderer.hpp
new file mode 100644
index 00000000..675714fe
--- /dev/null
+++ b/src/render/gl/GLElementRenderer.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "../ElementRenderer.hpp"
+
+namespace Render::GL {
+ class CGLElementRenderer : public Render::IElementRenderer {
+ public:
+ CGLElementRenderer() = default;
+ ~CGLElementRenderer() = default;
+
+ private:
+ void draw(WP<CBorderPassElement> element, const Hyprutils::Math::CRegion& damage) override;
+ void draw(WP<CClearPassElement> element, const CRegion& damage) override;
+ void draw(WP<CFramebufferElement> element, const CRegion& damage) override;
+ void draw(WP<CPreBlurElement> element, const CRegion& damage) override;
+ void draw(WP<CRectPassElement> element, const CRegion& damage) override;
+ void draw(WP<CShadowPassElement> element, const CRegion& damage) override;
+ void draw(WP<CInnerGlowPassElement> element, const CRegion& damage) override;
+ void draw(WP<CTexPassElement> element, const CRegion& damage) override;
+ void draw(WP<CTextureMatteElement> element, const CRegion& damage) override;
+ };
+}
diff --git a/src/render/gl/GLFramebuffer.cpp b/src/render/gl/GLFramebuffer.cpp
index 27ad4a1b..0ad84e62 100644
--- a/src/render/gl/GLFramebuffer.cpp
+++ b/src/render/gl/GLFramebuffer.cpp
@@ -4,14 +4,14 @@
#include "macros.hpp"
#include "../Framebuffer.hpp"
+using namespace Render::GL;
+
CGLFramebuffer::CGLFramebuffer() : IFramebuffer() {}
CGLFramebuffer::CGLFramebuffer(const std::string& name) : IFramebuffer(name) {}
bool CGLFramebuffer::internalAlloc(int w, int h, uint32_t drmFormat) {
g_pHyprOpenGL->makeEGLCurrent();
- bool firstAlloc = false;
-
if (!m_tex) {
m_tex = g_pHyprRenderer->createTexture();
m_tex->allocate({w, h});
@@ -20,39 +20,44 @@ bool CGLFramebuffer::internalAlloc(int w, int h, uint32_t drmFormat) {
m_tex->setTexParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_tex->setTexParameter(GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_tex->setTexParameter(GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- firstAlloc = true;
}
if (!m_fbAllocated) {
glGenFramebuffers(1, &m_fb);
m_fbAllocated = true;
- firstAlloc = true;
}
- if (firstAlloc) {
- const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat);
- m_tex->bind();
+ const auto format = NFormatUtils::getPixelFormatFromDRM(drmFormat);
+ m_tex->bind();
+ glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, w, h, 0, format->glFormat, format->glType, nullptr);
+ glBindFramebuffer(GL_FRAMEBUFFER, m_fb);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_tex->m_texID, 0);
+
+ if (m_mirrorTex) {
+ const auto format = NFormatUtils::getPixelFormatFromDRM(m_mirrorTex->m_drmFormat);
+ m_mirrorTex->bind();
glTexImage2D(GL_TEXTURE_2D, 0, format->glInternalFormat ? format->glInternalFormat : format->glFormat, w, h, 0, format->glFormat, format->glType, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, m_fb);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_tex->m_texID, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_mirrorTex->m_texID, 0);
+ } else
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
- if (m_stencilTex && m_stencilTex->ok()) {
- m_stencilTex->bind();
- glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_stencilTex->m_texID, 0);
+ if (m_stencilTex && m_stencilTex->ok()) {
+ m_stencilTex->bind();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_stencilTex->m_texID, 0);
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- }
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ }
- auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
- RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Framebuffer incomplete, couldn't create! (FB status: {}, GL Error: 0x{:x})", status, sc<int>(glGetError()));
+ auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ RASSERT((status == GL_FRAMEBUFFER_COMPLETE), "Framebuffer incomplete, couldn't create! (FB status: {}, GL Error: 0x{:x})", status, sc<int>(glGetError()));
- if (m_stencilTex && m_stencilTex->ok())
- m_stencilTex->unbind();
+ if (m_stencilTex && m_stencilTex->ok())
+ m_stencilTex->unbind();
- Log::logger->log(Log::DEBUG, "Framebuffer created, status {}", status);
- }
+ Log::logger->log(Log::DEBUG, "Framebuffer \"{}\" created, status {}", m_name, status);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -86,6 +91,8 @@ void CGLFramebuffer::release() {
if (m_fbAllocated) {
glBindFramebuffer(GL_FRAMEBUFFER, m_fb);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
+ if (m_mirrorTex)
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &m_fb);
diff --git a/src/render/gl/GLFramebuffer.hpp b/src/render/gl/GLFramebuffer.hpp
index c171444e..1be5d0e0 100644
--- a/src/render/gl/GLFramebuffer.hpp
+++ b/src/render/gl/GLFramebuffer.hpp
@@ -5,26 +5,28 @@
#include "../Framebuffer.hpp"
#include <drm_fourcc.h>
-class CGLFramebuffer : public IFramebuffer {
- public:
- CGLFramebuffer();
- CGLFramebuffer(const std::string& name);
- ~CGLFramebuffer();
+namespace Render::GL {
+ class CGLFramebuffer : public IFramebuffer {
+ public:
+ CGLFramebuffer();
+ CGLFramebuffer(const std::string& name);
+ ~CGLFramebuffer();
- void addStencil(SP<ITexture> tex) override;
- void release() override;
- bool readPixels(CHLBufferReference buffer, uint32_t offsetX = 0, uint32_t offsetY = 0, uint32_t width = 0, uint32_t height = 0) override;
+ void addStencil(SP<ITexture> tex) override;
+ void release() override;
+ bool readPixels(CHLBufferReference buffer, uint32_t offsetX = 0, uint32_t offsetY = 0, uint32_t width = 0, uint32_t height = 0) override;
- void bind() override;
- void unbind();
- GLuint getFBID();
- void invalidate(const std::vector<GLenum>& attachments);
+ void bind() override;
+ void unbind();
+ GLuint getFBID();
+ void invalidate(const std::vector<GLenum>& attachments);
- protected:
- bool internalAlloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888) override;
+ protected:
+ bool internalAlloc(int w, int h, DRMFormat format = DRM_FORMAT_ARGB8888) override;
- private:
- GLuint m_fb = -1;
+ private:
+ GLuint m_fb = -1;
- friend class CGLRenderbuffer;
-};
+ friend class CGLRenderbuffer;
+ };
+}
diff --git a/src/render/gl/GLRenderbuffer.cpp b/src/render/gl/GLRenderbuffer.cpp
index aa8b5be2..208957e5 100644
--- a/src/render/gl/GLRenderbuffer.cpp
+++ b/src/render/gl/GLRenderbuffer.cpp
@@ -11,6 +11,8 @@
#include <dlfcn.h>
+using namespace Render::GL;
+
CGLRenderbuffer::~CGLRenderbuffer() {
if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer)
return;
@@ -63,7 +65,7 @@ CGLRenderbuffer::CGLRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format
void CGLRenderbuffer::bind() {
g_pHyprOpenGL->makeEGLCurrent();
- m_framebuffer->bind();
+ g_pHyprRenderer->bindFB(m_framebuffer);
}
void CGLRenderbuffer::unbind() {
diff --git a/src/render/gl/GLRenderbuffer.hpp b/src/render/gl/GLRenderbuffer.hpp
index 8367f702..137a8e0d 100644
--- a/src/render/gl/GLRenderbuffer.hpp
+++ b/src/render/gl/GLRenderbuffer.hpp
@@ -6,15 +6,17 @@
class CMonitor;
-class CGLRenderbuffer : public IRenderbuffer {
- public:
- CGLRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
- ~CGLRenderbuffer();
+namespace Render::GL {
+ class CGLRenderbuffer : public IRenderbuffer {
+ public:
+ CGLRenderbuffer(SP<Aquamarine::IBuffer> buffer, uint32_t format);
+ ~CGLRenderbuffer();
- void bind() override;
- void unbind() override;
+ void bind() override;
+ void unbind() override;
- private:
- void* m_image = nullptr;
- GLuint m_rbo = 0;
-};
+ private:
+ void* m_image = nullptr;
+ GLuint m_rbo = 0;
+ };
+}
diff --git a/src/render/gl/GLTexture.cpp b/src/render/gl/GLTexture.cpp
index 93f85c84..d34bdb60 100644
--- a/src/render/gl/GLTexture.cpp
+++ b/src/render/gl/GLTexture.cpp
@@ -5,6 +5,8 @@
#include "../Texture.hpp"
#include <cstring>
+using namespace Render::GL;
+
CGLTexture::CGLTexture(bool opaque) {
m_opaque = opaque;
}
diff --git a/src/render/gl/GLTexture.hpp b/src/render/gl/GLTexture.hpp
index 34510e90..07b51d9a 100644
--- a/src/render/gl/GLTexture.hpp
+++ b/src/render/gl/GLTexture.hpp
@@ -4,46 +4,49 @@
#include <aquamarine/buffer/Buffer.hpp>
#include <hyprutils/math/Misc.hpp>
-class CGLTexture : public ITexture {
- public:
- using ITexture::ITexture;
-
- CGLTexture(CGLTexture&) = delete;
- CGLTexture(CGLTexture&&) = delete;
- CGLTexture(const CGLTexture&&) = delete;
- CGLTexture(const CGLTexture&) = delete;
-
- CGLTexture(bool opaque = false);
- CGLTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false);
- CGLTexture(const Aquamarine::SDMABUFAttrs&, void* image, bool opaque = false);
- CGLTexture(std::span<const float> lut3D, size_t N);
- ~CGLTexture();
-
- void allocate(const Vector2D& size, uint32_t drmFormat = 0) override;
- void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) override;
- void bind() override;
- void unbind() override;
- void setTexParameter(GLenum pname, GLint param) override;
- bool ok() override;
- bool isDMA() override;
-
- private:
- void* m_eglImage = nullptr;
-
- enum eTextureParam : uint8_t {
- TEXTURE_PAR_WRAP_S = 0,
- TEXTURE_PAR_WRAP_T,
- TEXTURE_PAR_MAG_FILTER,
- TEXTURE_PAR_MIN_FILTER,
- TEXTURE_PAR_SWIZZLE_R,
- TEXTURE_PAR_SWIZZLE_B,
- TEXTURE_PAR_LAST,
+namespace Render::GL {
+
+ class CGLTexture : public ITexture {
+ public:
+ using ITexture::ITexture;
+
+ CGLTexture(CGLTexture&) = delete;
+ CGLTexture(CGLTexture&&) = delete;
+ CGLTexture(const CGLTexture&&) = delete;
+ CGLTexture(const CGLTexture&) = delete;
+
+ CGLTexture(bool opaque = false);
+ CGLTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false);
+ CGLTexture(const Aquamarine::SDMABUFAttrs&, void* image, bool opaque = false);
+ CGLTexture(std::span<const float> lut3D, size_t N);
+ ~CGLTexture();
+
+ void allocate(const Vector2D& size, uint32_t drmFormat = 0) override;
+ void update(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const CRegion& damage) override;
+ void bind() override;
+ void unbind() override;
+ void setTexParameter(GLenum pname, GLint param) override;
+ bool ok() override;
+ bool isDMA() override;
+
+ private:
+ void* m_eglImage = nullptr;
+
+ enum eTextureParam : uint8_t {
+ TEXTURE_PAR_WRAP_S = 0,
+ TEXTURE_PAR_WRAP_T,
+ TEXTURE_PAR_MAG_FILTER,
+ TEXTURE_PAR_MIN_FILTER,
+ TEXTURE_PAR_SWIZZLE_R,
+ TEXTURE_PAR_SWIZZLE_B,
+ TEXTURE_PAR_LAST,
+ };
+
+ GLenum m_target = GL_TEXTURE_2D;
+
+ void swizzle(const std::array<GLint, 4>& colors);
+ constexpr std::optional<size_t> getCacheStateIndex(GLenum pname);
+
+ std::array<std::optional<GLint>, TEXTURE_PAR_LAST> m_cachedStates;
};
-
- GLenum m_target = GL_TEXTURE_2D;
-
- void swizzle(const std::array<GLint, 4>& colors);
- constexpr std::optional<size_t> getCacheStateIndex(GLenum pname);
-
- std::array<std::optional<GLint>, TEXTURE_PAR_LAST> m_cachedStates;
-};
+}
diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp
index cbf6ea48..a097fd59 100644
--- a/src/render/pass/Pass.cpp
+++ b/src/render/pass/Pass.cpp
@@ -10,6 +10,10 @@
#include "../../render/Renderer.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "../../protocols/core/Compositor.hpp"
+#include "RectPassElement.hpp"
+#include "macros.hpp"
+
+using namespace Render;
bool CRenderPass::empty() const {
return false;
@@ -213,15 +217,10 @@ void CRenderPass::renderDebugData() {
const auto pMonitor = g_pHyprRenderer->m_renderData.pMonitor;
CBox box = {{}, pMonitor->m_transformedSize};
for (const auto& rg : m_occludedRegions) {
- CRectPassElement::SRectData data;
- data.box = box;
- data.color = Colors::RED.modifyA(0.1F);
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), rg);
+ g_pHyprRenderer->draw(CRectPassElement::SRectData{.box = box, .color = Colors::RED.modifyA(0.1F)}, rg);
}
- CRectPassElement::SRectData data;
- data.box = box;
- data.color = Colors::GREEN.modifyA(0.1F);
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), m_totalLiveBlurRegion);
+
+ g_pHyprRenderer->draw(CRectPassElement::SRectData{.box = box, .color = Colors::GREEN.modifyA(0.1F)}, m_totalLiveBlurRegion);
std::unordered_map<CWLSurfaceResource*, float> offsets;
@@ -244,10 +243,7 @@ void CRenderPass::renderDebugData() {
if (box.intersection(CBox{{}, pMonitor->m_size}).empty())
return;
- CRectPassElement::SRectData data;
- data.box = box;
- data.color = color;
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), m_damage);
+ g_pHyprRenderer->draw(CRectPassElement::SRectData{.box = box, .color = color}, m_damage);
if (offsets.contains(surface.get()))
box.translate(Vector2D{0.F, offsets[surface.get()]});
@@ -255,16 +251,16 @@ void CRenderPass::renderDebugData() {
offsets[surface.get()] = 0;
box = {box.pos(), texture->m_size};
- CRectPassElement::SRectData data2;
- data.box = box;
- data.color = color;
- data.round = std::min(5.0, box.size().y);
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data2), m_damage);
- CTexPassElement::SRenderData texData;
- texData.tex = texture;
- texData.box = box;
- g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), m_damage);
+ g_pHyprRenderer->draw(
+ CRectPassElement::SRectData{
+ .box = box,
+ .color = color,
+ .round = std::min(5.0, box.size().y),
+ },
+ m_damage);
+
+ g_pHyprRenderer->draw(CTexPassElement::SRenderData{.tex = texture, .box = box}, m_damage);
offsets[surface.get()] += texture->m_size.y;
};
@@ -281,10 +277,7 @@ void CRenderPass::renderDebugData() {
if (hlSurface) {
auto BOX = hlSurface->getSurfaceBoxGlobal();
if (BOX) {
- CRectPassElement::SRectData data;
- data.box = box;
- data.color = CHyprColor{0.8F, 0.8F, 0.2F, 0.4F};
- g_pHyprRenderer->draw(makeUnique<CRectPassElement>(data), m_damage);
+ g_pHyprRenderer->draw(CRectPassElement::SRectData{.box = box, .color = CHyprColor{0.8F, 0.8F, 0.2F, 0.4F}}, m_damage);
}
}
}
@@ -295,13 +288,13 @@ void CRenderPass::renderDebugData() {
DISCARDED_ELEMENTS, pMonitor->m_pixelSize),
Colors::WHITE, 12);
- if (tex) {
- box = CBox{{0.F, pMonitor->m_size.y - tex->m_size.y}, tex->m_size}.scale(pMonitor->m_scale);
- CTexPassElement::SRenderData texData;
- texData.tex = tex;
- texData.box = box;
- g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), m_damage);
- }
+ if (tex)
+ g_pHyprRenderer->draw(
+ CTexPassElement::SRenderData{
+ .tex = tex,
+ .box = CBox{{0.F, pMonitor->m_size.y - tex->m_size.y}, tex->m_size}.scale(pMonitor->m_scale),
+ },
+ m_damage);
std::string passStructure;
auto yn = [](const bool val) -> const char* { return val ? "yes" : "no"; };
@@ -315,13 +308,13 @@ void CRenderPass::renderDebugData() {
passStructure.pop_back();
tex = g_pHyprRenderer->renderText(passStructure, Colors::WHITE, 12);
- if (tex) {
- box = CBox{{pMonitor->m_size.x - tex->m_size.x, pMonitor->m_size.y - tex->m_size.y}, tex->m_size}.scale(pMonitor->m_scale);
- CTexPassElement::SRenderData texData;
- texData.tex = tex;
- texData.box = box;
- g_pHyprRenderer->draw(makeUnique<CTexPassElement>(texData), m_damage);
- }
+ if (tex)
+ g_pHyprRenderer->draw(
+ CTexPassElement::SRenderData{
+ .tex = tex,
+ .box = CBox{{pMonitor->m_size.x - tex->m_size.x, pMonitor->m_size.y - tex->m_size.y}, tex->m_size}.scale(pMonitor->m_scale),
+ },
+ m_damage);
}
float CRenderPass::oneBlurRadius() {
diff --git a/src/render/pass/Pass.hpp b/src/render/pass/Pass.hpp
index d407bf3c..5a85d067 100644
--- a/src/render/pass/Pass.hpp
+++ b/src/render/pass/Pass.hpp
@@ -3,40 +3,44 @@
#include "../../defines.hpp"
#include "PassElement.hpp"
-class ITexture;
+class CGradientValueData;
-class CRenderPass {
- public:
- bool empty() const;
- bool single() const;
+namespace Render {
+ class ITexture;
- void add(UP<IPassElement>&& elem);
- void clear();
- void removeAllOfType(const std::string& type);
+ class CRenderPass {
+ public:
+ bool empty() const;
+ bool single() const;
- CRegion render(const CRegion& damage_);
+ void add(UP<IPassElement>&& elem);
+ void clear();
+ void removeAllOfType(const std::string& type);
- private:
- CRegion m_damage;
- std::vector<CRegion> m_occludedRegions;
- CRegion m_totalLiveBlurRegion;
+ CRegion render(const CRegion& damage_);
- struct SPassElementData {
- CRegion elementDamage;
- UP<IPassElement> element;
- bool discard = false;
- };
+ private:
+ CRegion m_damage;
+ std::vector<CRegion> m_occludedRegions;
+ CRegion m_totalLiveBlurRegion;
+
+ struct SPassElementData {
+ CRegion elementDamage;
+ UP<IPassElement> element;
+ bool discard = false;
+ };
- std::vector<UP<SPassElementData>> m_passElements;
+ std::vector<UP<SPassElementData>> m_passElements;
- void simplify();
- float oneBlurRadius();
- void renderDebugData();
+ void simplify();
+ float oneBlurRadius();
+ void renderDebugData();
- struct {
- bool present = false;
- SP<ITexture> keyboardFocusText, pointerFocusText, lastWindowText;
- } m_debugData;
+ struct {
+ bool present = false;
+ SP<ITexture> keyboardFocusText, pointerFocusText, lastWindowText;
+ } m_debugData;
- friend class CHyprOpenGLImpl;
-};
+ friend class CHyprOpenGLImpl;
+ };
+}
diff --git a/src/render/pass/PassElement.cpp b/src/render/pass/PassElement.cpp
index 3ae52ef5..ae24680a 100644
--- a/src/render/pass/PassElement.cpp
+++ b/src/render/pass/PassElement.cpp
@@ -19,3 +19,7 @@ void IPassElement::discard() {
bool IPassElement::undiscardable() {
return false;
}
+
+std::vector<UP<IPassElement>> IPassElement::draw() {
+ return {};
+}
diff --git a/src/render/pass/PassElement.hpp b/src/render/pass/PassElement.hpp
index c262b36c..9b939f11 100644
--- a/src/render/pass/PassElement.hpp
+++ b/src/render/pass/PassElement.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "../../defines.hpp"
+#include <vector>
enum ePassElementType : uint8_t {
EK_UNKNOWN = 0,
@@ -14,13 +15,16 @@ enum ePassElementType : uint8_t {
EK_SURFACE,
EK_TEXTURE,
EK_TEXTURE_MATTE,
- EK_INNER_GLOW
+ EK_INNER_GLOW,
+ EK_CUSTOM,
};
class IPassElement {
public:
virtual ~IPassElement() = default;
+ virtual std::vector<UP<IPassElement>> draw();
+ //
virtual bool needsLiveBlur() = 0;
virtual bool needsPrecomputeBlur() = 0;
virtual const char* passName() = 0;
diff --git a/src/render/pass/RendererHintsPassElement.hpp b/src/render/pass/RendererHintsPassElement.hpp
index a5a429b5..0a24ff6d 100644
--- a/src/render/pass/RendererHintsPassElement.hpp
+++ b/src/render/pass/RendererHintsPassElement.hpp
@@ -1,12 +1,11 @@
#pragma once
#include "PassElement.hpp"
-#include <optional>
-#include "../OpenGL.hpp"
+#include "../types.hpp"
class CRendererHintsPassElement : public IPassElement {
public:
struct SData {
- std::optional<SRenderModifData> renderModif;
+ std::optional<Render::SRenderModifData> renderModif;
};
CRendererHintsPassElement(const SData& data);
diff --git a/src/render/pass/SurfacePassElement.hpp b/src/render/pass/SurfacePassElement.hpp
index c76b475d..ebf5561c 100644
--- a/src/render/pass/SurfacePassElement.hpp
+++ b/src/render/pass/SurfacePassElement.hpp
@@ -5,7 +5,9 @@
#include "../../helpers/time/Time.hpp"
class CWLSurfaceResource;
-class ITexture;
+namespace Render {
+ class ITexture;
+}
class CSyncTimeline;
class CSurfacePassElement : public IPassElement {
@@ -17,7 +19,7 @@ class CSurfacePassElement : public IPassElement {
void* data = nullptr;
SP<CWLSurfaceResource> surface = nullptr;
- SP<ITexture> texture = nullptr;
+ SP<Render::ITexture> texture = nullptr;
bool mainSurface = true;
double w = 0, h = 0;
int rounding = 0;
diff --git a/src/render/pass/TexPassElement.hpp b/src/render/pass/TexPassElement.hpp
index 5b8c9757..6c0cfab1 100644
--- a/src/render/pass/TexPassElement.hpp
+++ b/src/render/pass/TexPassElement.hpp
@@ -3,7 +3,9 @@
#include <optional>
class CWLSurfaceResource;
-class ITexture;
+namespace Render {
+ class ITexture;
+}
class CSyncTimeline;
enum eDiscardMode : uint8_t {
@@ -14,7 +16,7 @@ enum eDiscardMode : uint8_t {
class CTexPassElement : public IPassElement {
public:
struct SRenderData {
- SP<ITexture> tex;
+ SP<Render::ITexture> tex;
CBox box;
float a = 1.F;
float blurA = 1.F;
@@ -41,7 +43,7 @@ class CTexPassElement : public IPassElement {
CRegion clipRegion;
PHLLSREF currentLS;
- SP<ITexture> blurredBG;
+ SP<Render::ITexture> blurredBG;
};
CTexPassElement(const SRenderData& data);
diff --git a/src/render/pass/TextureMatteElement.hpp b/src/render/pass/TextureMatteElement.hpp
index bf3bb4bf..03526a57 100644
--- a/src/render/pass/TextureMatteElement.hpp
+++ b/src/render/pass/TextureMatteElement.hpp
@@ -2,15 +2,17 @@
#include "PassElement.hpp"
#include "../Framebuffer.hpp"
-class ITexture;
+namespace Render {
+ class ITexture;
+}
class CTextureMatteElement : public IPassElement {
public:
struct STextureMatteData {
- CBox box;
- SP<ITexture> tex;
- SP<IFramebuffer> fb;
- bool disableTransformAndModify = false;
+ CBox box;
+ SP<Render::ITexture> tex;
+ SP<Render::IFramebuffer> fb;
+ bool disableTransformAndModify = false;
};
CTextureMatteElement(const STextureMatteData& data_);
diff --git a/src/render/shaders/glsl/blurFinish.glsl b/src/render/shaders/glsl/blurFinish.glsl
index f3d225c3..e7e1f1c6 100644
--- a/src/render/shaders/glsl/blurFinish.glsl
+++ b/src/render/shaders/glsl/blurFinish.glsl
@@ -1,10 +1,26 @@
+#ifndef ALLOW_INCLUDES
+#define ALLOW_INCLUDES
+#extension GL_ARB_shading_language_include : enable
+#endif
+
+#include "defines.h"
+
+#if USE_CM
+#include "cm_helpers.glsl"
+#endif
+
float hash(vec2 p) {
vec3 p3 = fract(vec3(p.xyx) * 1689.1984);
p3 += dot(p3, p3.yzx + 33.33);
return fract((p3.x + p3.y) * p3.z);
}
-vec4 blurFinish(vec4 pixColor, vec2 v_texcoord, float noise, float brightness) {
+vec4 blurFinish(vec4 pixColor, vec2 v_texcoord, float noise, float brightness
+#if USE_CM
+ ,
+ int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
+#endif
+) {
// noise
float noiseHash = hash(v_texcoord);
float noiseAmount = noiseHash - 0.5;
@@ -13,5 +29,9 @@ vec4 blurFinish(vec4 pixColor, vec2 v_texcoord, float noise, float brightness) {
// brightness
pixColor.rgb *= min(1.0, brightness);
+#if USE_CM
+ pixColor = doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange);
+#endif
+
return pixColor;
}
diff --git a/src/render/shaders/glsl/blurfinish.frag b/src/render/shaders/glsl/blurfinish.frag
index 0342646b..51eb7684 100644
--- a/src/render/shaders/glsl/blurfinish.frag
+++ b/src/render/shaders/glsl/blurfinish.frag
@@ -9,11 +9,23 @@ uniform sampler2D tex;
uniform float noise;
uniform float brightness;
+#include "defines.h"
+#if USE_CM
+uniform int sourceTF; // eTransferFunction
+uniform int targetTF; // eTransferFunction
+#include "CM.glsl"
+#endif
+
#include "blurFinish.glsl"
layout(location = 0) out vec4 fragColor;
void main() {
vec4 pixColor = texture(tex, v_texcoord);
- fragColor = blurFinish(pixColor, v_texcoord, noise, brightness);
+ fragColor = blurFinish(pixColor, v_texcoord, noise, brightness
+#if USE_CM
+ ,
+ sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
+#endif
+ );
}
diff --git a/src/render/shaders/glsl/border.frag b/src/render/shaders/glsl/border.frag
index 151593c1..9f97348b 100644
--- a/src/render/shaders/glsl/border.frag
+++ b/src/render/shaders/glsl/border.frag
@@ -32,29 +32,41 @@ uniform vec2 fullSize;
#include "border.glsl"
layout(location = 0) out vec4 fragColor;
+#if USE_MIRROR
+layout(location = 1) out vec4 mirrorColor;
+#endif
void main() {
- fragColor = getBorder(v_texcoord, alpha, fullSizeUntransformed, radiusOuter, thick, radius, roundingPower, topLeft, fullSize, gradientLength, gradient, angle, gradient2Length,
- gradient2, angle2, gradientLerp
+#if USE_MIRROR
+ vec4[2] pixColors =
+#else
+ fragColor =
+#endif
+ getBorder(v_texcoord, alpha, fullSizeUntransformed, radiusOuter, thick, radius, roundingPower, topLeft, fullSize, gradientLength, gradient, angle, gradient2Length,
+ gradient2, angle2, gradientLerp
#if USE_CM
- ,
- sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
+ ,
+ sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
#if USE_ICC
- ,
- iccLut3D, iccLutSize
+ ,
+ iccLut3D, iccLutSize
#else
#if USE_TONEMAP || USE_SDR_MOD
- ,
- targetPrimariesXYZ
+ ,
+ targetPrimariesXYZ
#endif
#if USE_TONEMAP
- ,
- maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
+ ,
+ maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
#endif
#if USE_SDR_MOD
- ,
- sdrSaturation, sdrBrightnessMultiplier
+ ,
+ sdrSaturation, sdrBrightnessMultiplier
+#endif
#endif
#endif
+ );
+#if USE_MIRROR
+ fragColor = pixColors[0];
+ mirrorColor = pixColors[1];
#endif
- );
}
diff --git a/src/render/shaders/glsl/border.glsl b/src/render/shaders/glsl/border.glsl
index fa2a6980..9028ad0d 100644
--- a/src/render/shaders/glsl/border.glsl
+++ b/src/render/shaders/glsl/border.glsl
@@ -87,30 +87,35 @@ vec4 getColorForCoord(vec2 normalizedCoord, int gradientLength, vec4 gradient[10
return okLabAToSrgb(mix(result1, result2, gradientLerp));
}
-vec4 getBorder(vec2 v_texcoord, float alpha, vec2 fullSizeUntransformed, float radiusOuter, float thick, float radius, float roundingPower, vec2 topLeft, vec2 fullSize,
- int gradientLength, vec4 gradient[10], float angle, int gradient2Length, vec4 gradient2[10], float angle2, float gradientLerp
+#if USE_MIRROR
+vec4[2]
+#else
+vec4
+#endif
+ getBorder(vec2 v_texcoord, float alpha, vec2 fullSizeUntransformed, float radiusOuter, float thick, float radius, float roundingPower, vec2 topLeft, vec2 fullSize,
+ int gradientLength, vec4 gradient[10], float angle, int gradient2Length, vec4 gradient2[10], float angle2, float gradientLerp
#if USE_CM
- ,
- int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
+ ,
+ int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
#if USE_ICC
- ,
- highp sampler3D iccLut3D, float iccLutSize
+ ,
+ highp sampler3D iccLut3D, float iccLutSize
#else
#if USE_TONEMAP || USE_SDR_MOD
- ,
- mat3 targetPrimariesXYZ
+ ,
+ mat3 targetPrimariesXYZ
#endif
#if USE_TONEMAP
- ,
- float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
+ ,
+ float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
#endif
#if USE_SDR_MOD
- ,
- float sdrSaturation, float sdrBrightnessMultiplier
+ ,
+ float sdrSaturation, float sdrBrightnessMultiplier
#endif
#endif
#endif
-) {
+ ) {
vec2 pixCoord = vec2(gl_FragCoord);
vec2 pixCoordOuter = pixCoord;
vec2 originalPixCoord = v_texcoord;
@@ -176,28 +181,38 @@ vec4 getBorder(vec2 v_texcoord, float alpha, vec2 fullSizeUntransformed, float r
pixColor.rgb *= pixColor[3];
#if USE_CM
- pixColor = doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
+#if USE_MIRROR
+ vec4[2] pixColors =
+#else
+ pixColor =
+#endif
+ doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
#if USE_ICC
- ,
- iccLut3D, iccLutSize
+ ,
+ iccLut3D, iccLutSize
#else
#if USE_TONEMAP || USE_SDR_MOD
- ,
- targetPrimariesXYZ
+ ,
+ targetPrimariesXYZ
#endif
#if USE_TONEMAP
- ,
- maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
+ ,
+ maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
#endif
#if USE_SDR_MOD
- ,
- sdrSaturation, sdrBrightnessMultiplier
+ ,
+ sdrSaturation, sdrBrightnessMultiplier
#endif
#endif
- );
+ );
#endif
+#if USE_MIRROR
+ pixColors[0] *= alpha * additionalAlpha;
+ pixColors[1] *= alpha * additionalAlpha;
+ return pixColors;
+#else
pixColor *= alpha * additionalAlpha;
-
return pixColor;
+#endif
}
diff --git a/src/render/shaders/glsl/cm_helpers.glsl b/src/render/shaders/glsl/cm_helpers.glsl
index 5e0d14f6..472c6ea5 100644
--- a/src/render/shaders/glsl/cm_helpers.glsl
+++ b/src/render/shaders/glsl/cm_helpers.glsl
@@ -204,10 +204,15 @@ vec4 fromLinearNit(vec4 color, int tf, vec2 range) {
#include "tonemap.glsl"
#endif
-vec4 doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
+#if USE_MIRROR
+vec4[2]
+#else
+vec4
+#endif
+ doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
#if USE_ICC
- ,
- highp sampler3D iccLut3D, float iccLutSize
+ ,
+ highp sampler3D iccLut3D, float iccLutSize
#else
#if USE_TONEMAP || USE_SDR_MOD
,
@@ -222,7 +227,7 @@ vec4 doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat3 convertMatrix,
float sdrSaturation, float sdrBrightnessMultiplier
#endif
#endif
-) {
+ ) {
pixColor.rgb /= max(pixColor.a, 0.001);
pixColor.rgb = toLinearRGB(pixColor.rgb, srcTF);
#if USE_ICC
@@ -235,6 +240,11 @@ vec4 doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat3 convertMatrix,
#if USE_TONEMAP
pixColor = tonemap(pixColor, dstxyz, maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance);
#endif
+#if USE_MIRROR
+ // TODO HDR -> SDR tonemap
+ vec4 mirrorColor = fromLinearNit(pixColor, CM_TRANSFER_FUNCTION_GAMMA22,
+ srcTF == CM_TRANSFER_FUNCTION_GAMMA22 || srcTF == CM_TRANSFER_FUNCTION_SRGB ? srcTFRange : vec2(SDR_MIN_LUMINANCE, SDR_MAX_LUMINANCE));
+#endif
pixColor = fromLinearNit(pixColor, dstTF, dstTFRange);
#if USE_SDR_MOD
pixColor = saturate(pixColor, dstxyz, sdrSaturation);
@@ -242,7 +252,14 @@ vec4 doColorManagement(vec4 pixColor, int srcTF, int dstTF, mat3 convertMatrix,
#endif
#endif
+#if USE_MIRROR
+ vec4[2] pixColors;
+ pixColors[0] = pixColor;
+ pixColors[1] = mirrorColor;
+ return pixColors;
+#else
return pixColor;
+#endif
}
#endif \ No newline at end of file
diff --git a/src/render/shaders/glsl/defines.h b/src/render/shaders/glsl/defines.h
index 31b120a4..a04e0250 100644
--- a/src/render/shaders/glsl/defines.h
+++ b/src/render/shaders/glsl/defines.h
@@ -1,4 +1,7 @@
// DO NOT EDIT. Will be overwritten in runtime
+// Values here are only for highlighting and static checking
+// 1 assumes that a shader either supports this feature or doesn't use any code supporting it
+// 0 assumes that shader uses some code supporting the feature but will never have this feature enabled
#define USE_RGBA 1
#define USE_DISCARD 1
#define USE_TINT 1
@@ -7,4 +10,5 @@
#define USE_TONEMAP 1
#define USE_SDR_MOD 1
#define USE_BLUR 1
-#define USE_ICC 1
+#define USE_ICC 0
+#define USE_MIRROR 0
diff --git a/src/render/shaders/glsl/quad.frag b/src/render/shaders/glsl/quad.frag
index 61895a60..dc1945af 100644
--- a/src/render/shaders/glsl/quad.frag
+++ b/src/render/shaders/glsl/quad.frag
@@ -16,6 +16,9 @@ uniform vec2 fullSize;
#endif
layout(location = 0) out vec4 fragColor;
+#if USE_MIRROR
+layout(location = 1) out vec4 mirrorColor;
+#endif
void main() {
vec4 pixColor = v_color;
@@ -24,4 +27,7 @@ void main() {
#endif
fragColor = pixColor;
+#if USE_MIRROR
+ mirrorColor = fragColor;
+#endif
}
diff --git a/src/render/shaders/glsl/rgbamatte.frag b/src/render/shaders/glsl/rgbamatte.frag
index a7213cfe..72fdc1d6 100644
--- a/src/render/shaders/glsl/rgbamatte.frag
+++ b/src/render/shaders/glsl/rgbamatte.frag
@@ -1,11 +1,21 @@
#version 300 es
+#define ALLOW_INCLUDES
+#extension GL_ARB_shading_language_include : enable
-precision highp float;
-in vec2 v_texcoord; // is in 0-1
+#include "defines.h"
+
+precision highp float;
+in vec2 v_texcoord; // is in 0-1
uniform sampler2D tex;
uniform sampler2D texMatte;
layout(location = 0) out vec4 fragColor;
+#if USE_MIRROR
+layout(location = 1) out vec4 mirrorColor;
+#endif
void main() {
fragColor = texture(tex, v_texcoord) * texture(texMatte, v_texcoord)[0]; // I know it only uses R, but matte should be black/white anyways.
+#if USE_MIRROR
+ mirrorColor = fragColor;
+#endif
}
diff --git a/src/render/shaders/glsl/shadow.frag b/src/render/shaders/glsl/shadow.frag
index c23ebd5d..5ba3d879 100644
--- a/src/render/shaders/glsl/shadow.frag
+++ b/src/render/shaders/glsl/shadow.frag
@@ -28,30 +28,41 @@ uniform float shadowPower;
#include "shadow.glsl"
layout(location = 0) out vec4 fragColor;
+#if USE_MIRROR
+layout(location = 1) out vec4 mirrorColor;
+#endif
void main() {
vec4 pixColor = v_color;
-
- fragColor = getShadow(pixColor, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight
+#if USE_MIRROR
+ vec4[2] pixColors =
+#else
+ fragColor =
+#endif
+ getShadow(pixColor, v_texcoord, radius, roundingPower, topLeft, fullSize, range, shadowPower, bottomRight
#if USE_CM
- ,
- sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
+ ,
+ sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
#if USE_ICC
- ,
- iccLut3D, iccLutSize
+ ,
+ iccLut3D, iccLutSize
#else
#if USE_TONEMAP || USE_SDR_MOD
- ,
- targetPrimariesXYZ
+ ,
+ targetPrimariesXYZ
#endif
#if USE_TONEMAP
- ,
- maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
+ ,
+ maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
#endif
#if USE_SDR_MOD
- ,
- sdrSaturation, sdrBrightnessMultiplier
+ ,
+ sdrSaturation, sdrBrightnessMultiplier
+#endif
#endif
#endif
+ );
+#if USE_MIRROR
+ fragColor = pixColors[0];
+ mirrorColor = pixColors[1];
#endif
- );
} \ No newline at end of file
diff --git a/src/render/shaders/glsl/shadow.glsl b/src/render/shaders/glsl/shadow.glsl
index 48cde562..265dba00 100644
--- a/src/render/shaders/glsl/shadow.glsl
+++ b/src/render/shaders/glsl/shadow.glsl
@@ -23,29 +23,34 @@ float modifiedLength(vec2 a, float roundingPower) {
return pow(pow(abs(a.x), roundingPower) + pow(abs(a.y), roundingPower), 1.0 / roundingPower);
}
-vec4 getShadow(vec4 pixColor, vec2 v_texcoord, float radius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float shadowPower, vec2 bottomRight
+#if USE_MIRROR
+vec4[2]
+#else
+vec4
+#endif
+ getShadow(vec4 pixColor, vec2 v_texcoord, float radius, float roundingPower, vec2 topLeft, vec2 fullSize, float range, float shadowPower, vec2 bottomRight
#if USE_CM
- ,
- int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
+ ,
+ int sourceTF, int targetTF, mat3 convertMatrix, vec2 srcTFRange, vec2 dstTFRange
#if USE_ICC
- ,
- highp sampler3D iccLut3D, float iccLutSize
+ ,
+ highp sampler3D iccLut3D, float iccLutSize
#else
#if USE_TONEMAP || USE_SDR_MOD
- ,
- mat3 targetPrimariesXYZ
+ ,
+ mat3 targetPrimariesXYZ
#endif
#if USE_TONEMAP
- ,
- float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
+ ,
+ float maxLuminance, float dstMaxLuminance, float dstRefLuminance, float srcRefLuminance
#endif
#if USE_SDR_MOD
- ,
- float sdrSaturation, float sdrBrightnessMultiplier
+ ,
+ float sdrSaturation, float sdrBrightnessMultiplier
#endif
#endif
#endif
-) {
+ ) {
float originalAlpha = pixColor[3];
bool done = false;
@@ -100,27 +105,35 @@ vec4 getShadow(vec4 pixColor, vec2 v_texcoord, float radius, float roundingPower
pixColor.rgb *= pixColor[3];
#if USE_CM
- pixColor = doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
+#if USE_MIRROR
+ vec4[2] pixColors =
+#else
+ pixColor =
+#endif
+ doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
#if USE_ICC
- ,
- iccLut3D, iccLutSize
+ ,
+ iccLut3D, iccLutSize
#else
#if USE_TONEMAP || USE_SDR_MOD
- ,
- targetPrimariesXYZ
+ ,
+ targetPrimariesXYZ
#endif
#if USE_TONEMAP
- ,
- maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
+ ,
+ maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
#endif
#if USE_SDR_MOD
- ,
- sdrSaturation, sdrBrightnessMultiplier
+ ,
+ sdrSaturation, sdrBrightnessMultiplier
#endif
#endif
- );
+ );
#endif
-
+#if USE_MIRROR
+ return pixColors;
+#else
return pixColor;
+#endif
}
#endif \ No newline at end of file
diff --git a/src/render/shaders/glsl/surface.frag b/src/render/shaders/glsl/surface.frag
index 30023bc8..076ca62c 100644
--- a/src/render/shaders/glsl/surface.frag
+++ b/src/render/shaders/glsl/surface.frag
@@ -47,6 +47,9 @@ const mat3 targetPrimariesXYZ = mat3(0.0);
#endif
layout(location = 0) out vec4 fragColor;
+#if USE_MIRROR
+layout(location = 1) out vec4 mirrorColor;
+#endif
void main() {
#if USE_RGBA
vec4 pixColor = texture(tex, v_texcoord);
@@ -63,25 +66,34 @@ void main() {
#endif
#if USE_CM
- pixColor = doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
+#if USE_MIRROR
+ vec4[2] pixColors =
+#else
+ pixColor =
+#endif
+ doColorManagement(pixColor, sourceTF, targetTF, convertMatrix, srcTFRange, dstTFRange
#if USE_ICC
- ,
- iccLut3D, iccLutSize
+ ,
+ iccLut3D, iccLutSize
#else
#if USE_TONEMAP || USE_SDR_MOD
- ,
- targetPrimariesXYZ
+ ,
+ targetPrimariesXYZ
#endif
#if USE_TONEMAP
- ,
- maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
+ ,
+ maxLuminance, dstMaxLuminance, dstRefLuminance, srcRefLuminance
#endif
#if USE_SDR_MOD
- ,
- sdrSaturation, sdrBrightnessMultiplier
+ ,
+ sdrSaturation, sdrBrightnessMultiplier
+#endif
#endif
+ );
#endif
- );
+#if USE_MIRROR
+ pixColor = pixColors[0];
+ mirrorColor = pixColors[1];
#endif
#if USE_TINT
@@ -101,4 +113,23 @@ void main() {
#endif
fragColor = pixColor * alpha;
+#if USE_MIRROR
+#if USE_TINT
+ mirrorColor.rgb = mirrorColor.rgb * tint;
+#endif
+
+#if USE_ROUNDING
+ mirrorColor = rounding(mirrorColor, radius, roundingPower, topLeft, fullSize);
+#endif
+#if USE_BLUR
+#if USE_DISCARD
+ mirrorColor = mix(mirrorColor, vec4(mix(texture(blurredBG, v_texcoord * uvSize + uvOffset).rgb, mirrorColor.rgb, mirrorColor.a), 1.0),
+ discardAlpha && (mirrorColor.a <= discardAlphaValue) ? 0.0 : 1.0);
+#else
+ mirrorColor = vec4(mix(texture(blurredBG, v_texcoord * uvSize + uvOffset).rgb, mirrorColor.rgb, mirrorColor.a), 1.0);
+#endif
+#endif
+
+ mirrorColor = mirrorColor * alpha;
+#endif
}
diff --git a/src/render/types.hpp b/src/render/types.hpp
new file mode 100644
index 00000000..a33c7b6d
--- /dev/null
+++ b/src/render/types.hpp
@@ -0,0 +1,131 @@
+#pragma once
+
+#include "Framebuffer.hpp"
+#include "../desktop/DesktopTypes.hpp"
+#include "../helpers/cm/ColorManagement.hpp"
+#include "../protocols/core/Compositor.hpp"
+#include <hyprgraphics/color/Color.hpp>
+#include <hyprutils/math/Box.hpp>
+#include <hyprutils/math/Mat3x3.hpp>
+#include <hyprutils/math/Region.hpp>
+#include <hyprutils/math/Vector2D.hpp>
+
+namespace Render {
+ const std::vector<const char*> ASSET_PATHS = {
+#ifdef DATAROOTDIR
+ DATAROOTDIR,
+#endif
+ "/usr/share",
+ "/usr/local/share",
+ };
+
+ enum eDamageTrackingModes : int8_t {
+ DAMAGE_TRACKING_INVALID = -1,
+ DAMAGE_TRACKING_NONE = 0,
+ DAMAGE_TRACKING_MONITOR,
+ DAMAGE_TRACKING_FULL,
+ };
+
+ enum eRenderPassMode : uint8_t {
+ RENDER_PASS_ALL = 0,
+ RENDER_PASS_MAIN,
+ RENDER_PASS_POPUP
+ };
+
+ enum eRenderMode : uint8_t {
+ RENDER_MODE_NORMAL = 0,
+ RENDER_MODE_FULL_FAKE = 1,
+ RENDER_MODE_TO_BUFFER = 2,
+ RENDER_MODE_TO_BUFFER_READ_ONLY = 3,
+ };
+
+ struct SRenderWorkspaceUntilData {
+ PHLLS ls;
+ PHLWINDOW w;
+ };
+
+ enum eRenderProjectionType : uint8_t {
+ RPT_MONITOR,
+ RPT_MIRROR,
+ RPT_FB,
+ RPT_EXPORT,
+ };
+
+ struct SRenderModifData {
+ enum eRenderModifType : uint8_t {
+ RMOD_TYPE_SCALE, /* scale by a float */
+ RMOD_TYPE_SCALECENTER, /* scale by a float from the center */
+ RMOD_TYPE_TRANSLATE, /* translate by a Vector2D */
+ RMOD_TYPE_ROTATE, /* rotate by a float in rad from top left */
+ RMOD_TYPE_ROTATECENTER, /* rotate by a float in rad from center */
+ };
+
+ std::vector<std::pair<eRenderModifType, std::any>> modifs;
+
+ void applyToBox(Hyprutils::Math::CBox& box);
+ void applyToRegion(Hyprutils::Math::CRegion& rg);
+ float combinedScale();
+
+ bool enabled = true;
+ };
+
+ struct SRenderData {
+ // can be private
+ Hyprutils::Math::Mat3x3 targetProjection;
+
+ // ----------------------
+
+ // used by public
+ Hyprutils::Math::Vector2D fbSize = {-1, -1};
+ PHLMONITORREF pMonitor;
+
+ eRenderProjectionType projectionType = RPT_MONITOR;
+
+ SP<IFramebuffer> currentFB = nullptr; // current rendering to
+ SP<IFramebuffer> mainFB = nullptr; // main to render to
+ SP<IFramebuffer> outFB = nullptr; // out to render to (if offloaded, etc)
+
+ CRegion damage;
+ CRegion finalDamage; // damage used for funal off -> main
+
+ SRenderModifData renderModif;
+ float mouseZoomFactor = 1.f;
+ bool mouseZoomUseMouse = true; // true by default
+ bool useNearestNeighbor = false;
+ bool blockScreenShader = false;
+
+ Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1);
+ Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1);
+
+ // TODO remove and pass directly
+ CBox clipBox = {}; // scaled coordinates
+ PHLWINDOWREF currentWindow;
+ WP<CWLSurfaceResource> surface;
+
+ bool transformDamage = true;
+ bool noSimplify = false;
+ };
+
+ struct STFRange {
+ float min = 0;
+ float max = 80;
+ };
+
+ struct SCMSettings {
+ NColorManagement::eTransferFunction sourceTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
+ NColorManagement::eTransferFunction targetTF = NColorManagement::CM_TRANSFER_FUNCTION_GAMMA22;
+ STFRange srcTFRange;
+ STFRange dstTFRange;
+ float srcRefLuminance = 80;
+ float dstRefLuminance = 80;
+ std::array<std::array<double, 3>, 3> convertMatrix;
+
+ bool needsTonemap = false;
+ float maxLuminance = 80;
+ float dstMaxLuminance = 80;
+ std::array<std::array<double, 3>, 3> dstPrimaries2XYZ;
+ bool needsSDRmod = false;
+ float sdrSaturation = 1.0;
+ float sdrBrightnessMultiplier = 1.0;
+ };
+} \ No newline at end of file