From d071feb9b6db6c39531973be04706cc3b755a6fd Mon Sep 17 00:00:00 2001 From: UjinT34 Date: Sat, 7 Mar 2026 13:28:45 +0300 Subject: [PATCH] namespaces & element renderer --- src/Compositor.cpp | 1 + src/debug/HyprCtl.cpp | 2 + src/debug/HyprDebugOverlay.hpp | 8 +- src/helpers/Monitor.cpp | 1 + src/helpers/Monitor.hpp | 4 +- src/helpers/MonitorFrameScheduler.cpp | 2 + src/helpers/MonitorFrameScheduler.hpp | 6 +- src/helpers/MonitorZoomController.cpp | 4 +- src/helpers/MonitorZoomController.hpp | 8 +- src/managers/PointerManager.cpp | 3 +- src/managers/input/InputMethodRelay.hpp | 6 +- .../screenshare/CursorshareSession.cpp | 9 +- src/managers/screenshare/ScreenshareFrame.cpp | 25 +- src/render/ElementRenderer.cpp | 478 ++++++++++++++ src/render/ElementRenderer.hpp | 45 ++ src/render/GLRenderer.cpp | 135 +--- src/render/GLRenderer.hpp | 81 ++- src/render/OpenGL.cpp | 18 +- src/render/OpenGL.hpp | 601 +++++++++--------- src/render/Renderer.cpp | 480 +------------- src/render/Renderer.hpp | 513 ++++++--------- src/render/Shader.cpp | 2 + src/render/ShaderLoader.cpp | 2 - .../decorations/CHyprDropShadowDecoration.cpp | 11 +- src/render/gl/GLElementRenderer.cpp | 131 ++++ src/render/gl/GLElementRenderer.hpp | 21 + src/render/gl/GLFramebuffer.cpp | 2 + src/render/gl/GLFramebuffer.hpp | 38 +- src/render/gl/GLRenderbuffer.cpp | 2 + src/render/gl/GLRenderbuffer.hpp | 22 +- src/render/gl/GLTexture.cpp | 2 + src/render/gl/GLTexture.hpp | 77 +-- src/render/pass/Pass.cpp | 21 +- src/render/pass/RendererHintsPassElement.hpp | 5 +- src/render/types.hpp | 131 ++++ 35 files changed, 1520 insertions(+), 1377 deletions(-) create mode 100644 src/render/ElementRenderer.cpp create mode 100644 src/render/ElementRenderer.hpp create mode 100644 src/render/gl/GLElementRenderer.cpp create mode 100644 src/render/gl/GLElementRenderer.hpp create mode 100644 src/render/types.hpp diff --git a/src/Compositor.cpp b/src/Compositor.cpp index b6aaad002..46a68e6a9 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -98,6 +98,7 @@ using namespace Hyprutils::String; using namespace Aquamarine; using enum NContentType::eContentType; using namespace NColorManagement; +using namespace Render::GL; static int handleCritSignal(int signo, void* data) { Log::logger->log(Log::DEBUG, "Hyprland received signal {}", signo); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index f113325f7..d69e066d8 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -71,6 +71,8 @@ using namespace Hyprutils::OS; #include "../layout/algorithm/TiledAlgorithm.hpp" #include "../layout/supplementary/WorkspaceAlgoMatcher.hpp" +using namespace Render::GL; + #if defined(__DragonFly__) || defined(__FreeBSD__) #include #define CRED_T xucred diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp index 775ce62c4..b263138c3 100644 --- a/src/debug/HyprDebugOverlay.hpp +++ b/src/debug/HyprDebugOverlay.hpp @@ -6,7 +6,9 @@ #include #include -class IHyprRenderer; +namespace Render { + class IHyprRenderer; +} class CHyprMonitorDebugOverlay { public: @@ -25,7 +27,7 @@ class CHyprMonitorDebugOverlay { PHLMONITORREF m_monitor; CBox m_lastDrawnBox; - friend class IHyprRenderer; + friend class Render::IHyprRenderer; }; class CHyprDebugOverlay { @@ -45,7 +47,7 @@ class CHyprDebugOverlay { SP m_texture; friend class CHyprMonitorDebugOverlay; - friend class IHyprRenderer; + friend class Render::IHyprRenderer; }; inline UP g_pDebugOverlay; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index dafec82ad..031d416f6 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -58,6 +58,7 @@ using namespace Hyprutils::Utils; using namespace Hyprutils::OS; using enum NContentType::eContentType; using namespace NColorManagement; +using namespace Render::GL; CMonitor::CMonitor(SP output_) : m_state(this), m_output(output_), m_imageDescription(DEFAULT_IMAGE_DESCRIPTION) { g_pAnimationManager->createAnimation(0.f, m_specialFade, Config::animationTree()->getAnimationPropertyConfig("specialWorkspaceIn"), AVARDAMAGE_NONE); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 69ee888bc..7a8b2e7b9 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -31,7 +31,9 @@ class CMonitorFrameScheduler; class CMonitor; class CSyncTimeline; -class CEGLSync; +namespace Render::GL { + class CEGLSync; +} class CEventLoopTimer; class CMonitorState { diff --git a/src/helpers/MonitorFrameScheduler.cpp b/src/helpers/MonitorFrameScheduler.cpp index e816d6104..da7fcfba1 100644 --- a/src/helpers/MonitorFrameScheduler.cpp +++ b/src/helpers/MonitorFrameScheduler.cpp @@ -4,6 +4,8 @@ #include "../render/Renderer.hpp" #include "../managers/eventLoop/EventLoopManager.hpp" +using namespace Render::GL; + CMonitorFrameScheduler::CMonitorFrameScheduler(PHLMONITOR m) : m_monitor(m) { ; } diff --git a/src/helpers/MonitorFrameScheduler.hpp b/src/helpers/MonitorFrameScheduler.hpp index c9b45a64a..37cf9cba6 100644 --- a/src/helpers/MonitorFrameScheduler.hpp +++ b/src/helpers/MonitorFrameScheduler.hpp @@ -4,7 +4,9 @@ #include -class CEGLSync; +namespace Render::GL { + class CEGLSync; +} class CMonitorFrameScheduler { public: @@ -32,7 +34,7 @@ class CMonitorFrameScheduler { PHLMONITORREF m_monitor; - UP m_sync; + UP m_sync; WP m_self; diff --git a/src/helpers/MonitorZoomController.cpp b/src/helpers/MonitorZoomController.cpp index 80c617e50..3e1bab99a 100644 --- a/src/helpers/MonitorZoomController.cpp +++ b/src/helpers/MonitorZoomController.cpp @@ -7,7 +7,7 @@ #include "desktop/DesktopTypes.hpp" #include "render/Renderer.hpp" -void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const SRenderData& m_renderData) { +void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData) { const auto m = m_renderData.pMonitor; auto monbox = CBox(0, 0, m->m_size.x, m->m_size.y); const auto ZOOM = g_pHyprRenderer->m_renderData.mouseZoomFactor; @@ -68,7 +68,7 @@ void CMonitorZoomController::zoomWithDetachedCamera(CBox& result, const SRenderD result = monbox; } -void CMonitorZoomController::applyZoomTransform(CBox& monbox, const SRenderData& m_renderData) { +void CMonitorZoomController::applyZoomTransform(CBox& monbox, const Render::SRenderData& m_renderData) { static auto PZOOMRIGID = CConfigValue("cursor:zoom_rigid"); static auto PZOOMDETACHEDCAMERA = CConfigValue("cursor:zoom_detached_camera"); const auto ZOOM = g_pHyprRenderer->m_renderData.mouseZoomFactor; diff --git a/src/helpers/MonitorZoomController.hpp b/src/helpers/MonitorZoomController.hpp index 54c7376ec..94373bafc 100644 --- a/src/helpers/MonitorZoomController.hpp +++ b/src/helpers/MonitorZoomController.hpp @@ -2,16 +2,18 @@ #include "./math/Math.hpp" -struct SRenderData; +namespace Render { + struct SRenderData; +} class CMonitorZoomController { public: bool m_resetCameraState = true; - void applyZoomTransform(CBox& monbox, const SRenderData& m_renderData); + void applyZoomTransform(CBox& monbox, const Render::SRenderData& m_renderData); private: - void zoomWithDetachedCamera(CBox& result, const SRenderData& m_renderData); + void zoomWithDetachedCamera(CBox& result, const Render::SRenderData& m_renderData); CBox m_camera; float m_lastZoomLevel = 1.0f; diff --git a/src/managers/PointerManager.cpp b/src/managers/PointerManager.cpp index a09804ff1..a0e336b47 100644 --- a/src/managers/PointerManager.cpp +++ b/src/managers/PointerManager.cpp @@ -10,6 +10,7 @@ #include "../protocols/core/Seat.hpp" #include "debug/log/Logger.hpp" #include "eventLoop/EventLoopManager.hpp" +#include "../render/pass/ClearPassElement.hpp" #include "../render/pass/TexPassElement.hpp" #include "../managers/input/InputManager.hpp" #include "../render/Renderer.hpp" @@ -594,7 +595,7 @@ SP CPointerManager::renderHWCursorBuffer(SPbeginFullFakeRender(state->monitor.lock(), damageRegion, RBO->getFB()); g_pHyprRenderer->startRenderPass(); - g_pHyprRenderer->draw(makeUnique(CClearPassElement::SClearData{{0.F, 0.F, 0.F, 0.F}}), {}); + g_pHyprRenderer->draw(makeShared(CClearPassElement::SClearData{{0.F, 0.F, 0.F, 0.F}}), {}); CBox xbox = {{}, Vector2D{m_currentCursorImage.size / m_currentCursorImage.scale * state->monitor->m_scale}.round()}; Log::logger->log(Log::TRACE, "[pointer] monitor: {}, size: {}, hw buf: {}, scale: {:.2f}, monscale: {:.2f}, xbox: {}", state->monitor->m_name, m_currentCursorImage.size, diff --git a/src/managers/input/InputMethodRelay.hpp b/src/managers/input/InputMethodRelay.hpp index 301d1b757..0f66fae83 100644 --- a/src/managers/input/InputMethodRelay.hpp +++ b/src/managers/input/InputMethodRelay.hpp @@ -9,7 +9,9 @@ #include class CInputManager; -class IHyprRenderer; +namespace Render { + class IHyprRenderer; +} class CTextInputV1; class CInputMethodV2; @@ -54,7 +56,7 @@ class CInputMethodRelay { CHyprSignalListener newPopup; } m_listeners; - friend class IHyprRenderer; + friend class Render::IHyprRenderer; friend class CInputManager; friend class CTextInputV1ProtocolManager; friend class CTextInput; diff --git a/src/managers/screenshare/CursorshareSession.cpp b/src/managers/screenshare/CursorshareSession.cpp index 5ccc3d22b..3f5aa027d 100644 --- a/src/managers/screenshare/CursorshareSession.cpp +++ b/src/managers/screenshare/CursorshareSession.cpp @@ -3,7 +3,8 @@ #include "../../protocols/core/Seat.hpp" #include "../permissions/DynamicPermissionManager.hpp" #include "../../render/Renderer.hpp" -#include "render/pass/TexPassElement.hpp" +#include "../../render/pass/ClearPassElement.hpp" +#include "../../render/pass/TexPassElement.hpp" using namespace Screenshare; @@ -122,14 +123,14 @@ void CCursorshareSession::render() { g_pHyprRenderer->startRenderPass(); if (PERM != PERMISSION_RULE_ALLOW_MODE_ALLOW || !overlaps) { // render black when not allowed - g_pHyprRenderer->draw(makeUnique(CClearPassElement::SClearData{Colors::BLACK}), {}); + g_pHyprRenderer->draw(makeShared(CClearPassElement::SClearData{Colors::BLACK}), {}); } else if (!cursorImage.pBuffer || !cursorImage.surface || !cursorImage.bufferTex) { // render clear when cursor is probably hidden - g_pHyprRenderer->draw(makeUnique(CClearPassElement::SClearData{{0, 0, 0, 0}}), {}); + g_pHyprRenderer->draw(makeShared(CClearPassElement::SClearData{{0, 0, 0, 0}}), {}); } else { // render cursor CBox texbox = {{}, cursorImage.bufferTex->m_size}; - g_pHyprRenderer->draw(makeUnique(CTexPassElement::SRenderData{ + g_pHyprRenderer->draw(makeShared(CTexPassElement::SRenderData{ .tex = cursorImage.bufferTex, .box = texbox, }), diff --git a/src/managers/screenshare/ScreenshareFrame.cpp b/src/managers/screenshare/ScreenshareFrame.cpp index 9c5b5aa68..290a4eb65 100644 --- a/src/managers/screenshare/ScreenshareFrame.cpp +++ b/src/managers/screenshare/ScreenshareFrame.cpp @@ -10,7 +10,8 @@ #include "../../helpers/Monitor.hpp" #include "../../desktop/view/Window.hpp" #include "../../desktop/state/FocusState.hpp" -#include "render/pass/RectPassElement.hpp" +#include "../../render/pass/ClearPassElement.hpp" +#include "../../render/pass/RectPassElement.hpp" #include using namespace Screenshare; @@ -175,7 +176,7 @@ void CScreenshareFrame::renderMonitor() { const auto OLD = g_pHyprRenderer->m_renderData.renderModif.enabled; g_pHyprRenderer->m_renderData.renderModif.enabled = false; g_pHyprRenderer->startRenderPass(); - g_pHyprRenderer->draw(makeUnique(CTexPassElement::SRenderData{ + g_pHyprRenderer->draw(makeShared(CTexPassElement::SRenderData{ .tex = TEXTURE, .box = monbox, .flipEndFrame = true, @@ -199,7 +200,7 @@ void CScreenshareFrame::renderMonitor() { CBox{popupBaseOffset + popRel + localOff, size}.translate(PMONITOR->m_position).scale(PMONITOR->m_scale).translate(-m_session->m_captureBox.pos()); if LIKELY (surfBox.w > 0 && surfBox.h > 0) - g_pHyprRenderer->draw(makeUnique(CRectPassElement::SRectData{ + g_pHyprRenderer->draw(makeShared(CRectPassElement::SRectData{ .box = surfBox, .color = Colors::BLACK, }), @@ -224,7 +225,7 @@ void CScreenshareFrame::renderMonitor() { .scale(PMONITOR->m_scale) .translate(-m_session->m_captureBox.pos()); - g_pHyprRenderer->draw(makeUnique(CRectPassElement::SRectData{ + g_pHyprRenderer->draw(makeShared(CRectPassElement::SRectData{ .box = noScreenShareBox, .color = Colors::BLACK, }), @@ -263,7 +264,7 @@ void CScreenshareFrame::renderMonitor() { const auto rounding = dontRound ? 0 : w->rounding() * PMONITOR->m_scale; const auto roundingPower = dontRound ? 2.0f : w->roundingPower(); - g_pHyprRenderer->draw(makeUnique(CRectPassElement::SRectData{ + g_pHyprRenderer->draw(makeShared(CRectPassElement::SRectData{ .box = noScreenShareBox, .color = Colors::BLACK, .round = rounding, @@ -298,12 +299,12 @@ void CScreenshareFrame::renderWindow() { // TODO: implement a monitor independent render mode to buffer that does this in CHyprRenderer::begin() or something like that g_pHyprRenderer->m_renderData.fbSize = m_bufferSize; - g_pHyprRenderer->setProjectionType(RPT_EXPORT); + g_pHyprRenderer->setProjectionType(Render::RPT_EXPORT); g_pHyprRenderer->m_renderData.transformDamage = false; g_pHyprRenderer->setViewport(0, 0, m_bufferSize.x, m_bufferSize.y); g_pHyprRenderer->m_bBlockSurfaceFeedback = g_pHyprRenderer->shouldRenderWindow(PWINDOW); // block the feedback to avoid spamming the surface if it's visible - g_pHyprRenderer->renderWindow(PWINDOW, PMONITOR, NOW, false, RENDER_PASS_ALL, true, true); + g_pHyprRenderer->renderWindow(PWINDOW, PMONITOR, NOW, false, Render::RENDER_PASS_ALL, true, true); g_pHyprRenderer->m_bBlockSurfaceFeedback = false; if (!m_overlayCursor) @@ -334,16 +335,16 @@ void CScreenshareFrame::render() { CRegion frameRegion = {0, 0, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.x, g_pHyprRenderer->m_renderData.pMonitor->m_pixelSize.y}; if (PERM == PERMISSION_RULE_ALLOW_MODE_PENDING) { - g_pHyprRenderer->draw(makeUnique(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion); + g_pHyprRenderer->draw(makeShared(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion); return; } bool windowShareDenied = m_session->m_type == SHARE_WINDOW && m_session->m_window->m_ruleApplicator && m_session->m_window->m_ruleApplicator->noScreenShare().valueOrDefault(); g_pHyprRenderer->startRenderPass(); if (PERM == PERMISSION_RULE_ALLOW_MODE_DENY || windowShareDenied) { - g_pHyprRenderer->draw(makeUnique(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion); + g_pHyprRenderer->draw(makeShared(CClearPassElement::SClearData{{0, 0, 0, 0}}), frameRegion); CBox texbox = CBox{m_bufferSize / 2.F, g_pHyprRenderer->m_screencopyDeniedTexture->m_size}.translate(-g_pHyprRenderer->m_screencopyDeniedTexture->m_size / 2.F); - g_pHyprRenderer->draw(makeUnique(CTexPassElement::SRenderData{ + g_pHyprRenderer->draw(makeShared(CTexPassElement::SRenderData{ .tex = g_pHyprRenderer->m_screencopyDeniedTexture, .box = texbox, }), @@ -353,7 +354,7 @@ void CScreenshareFrame::render() { if (m_session->m_tempFB && m_session->m_tempFB->isAllocated()) { CBox texbox = {{}, m_bufferSize}; - g_pHyprRenderer->draw(makeUnique(CTexPassElement::SRenderData{ + g_pHyprRenderer->draw(makeShared(CTexPassElement::SRenderData{ .tex = m_session->m_tempFB->getTexture(), .box = texbox, }), @@ -375,7 +376,7 @@ bool CScreenshareFrame::copyDmabuf() { if (done()) return false; - if (!g_pHyprRenderer->beginRender(m_session->monitor(), m_damage, RENDER_MODE_TO_BUFFER, m_buffer, nullptr, true)) { + if (!g_pHyprRenderer->beginRender(m_session->monitor(), m_damage, Render::RENDER_MODE_TO_BUFFER, m_buffer, nullptr, true)) { LOGM(Log::ERR, "Can't copy: failed to begin rendering to dma frame"); return false; } diff --git a/src/render/ElementRenderer.cpp b/src/render/ElementRenderer.cpp new file mode 100644 index 000000000..7daf651fa --- /dev/null +++ b/src/render/ElementRenderer.cpp @@ -0,0 +1,478 @@ +#include "ElementRenderer.hpp" +#include "Renderer.hpp" +#include "../layout/LayoutManager.hpp" +#include "../desktop/view/Window.hpp" +#include +#include + +using namespace Render; + +void IElementRenderer::drawElement(WP element, const CRegion& damage) { + if (!element) + return; + + switch (element->type()) { + case EK_BORDER: draw(dynamicPointerCast(element), damage); break; + case EK_CLEAR: draw(dynamicPointerCast(element), damage); break; + case EK_FRAMEBUFFER: draw(dynamicPointerCast(element), damage); break; + case EK_PRE_BLUR: drawPreBlur(dynamicPointerCast(element), damage); break; + case EK_RECT: drawRect(dynamicPointerCast(element), damage); break; + case EK_HINTS: drawHints(dynamicPointerCast(element), damage); break; + case EK_SHADOW: draw(dynamicPointerCast(element), damage); break; + case EK_SURFACE: preDrawSurface(dynamicPointerCast(element), damage); break; + case EK_TEXTURE: drawTex(dynamicPointerCast(element), damage); break; + case EK_TEXTURE_MATTE: drawTexMatte(dynamicPointerCast(element), damage); break; + default: Log::logger->log(Log::WARN, "Unimplimented draw for {}", element->passName()); + } +} + +static std::optional getSurfaceExpectedSize(PHLWINDOW pWindow, SP 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 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("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 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(transformedBox.x); + data.TOPLEFT[1] = sc(transformedBox.y); + data.FULLSIZE[0] = sc(transformedBox.width); + data.FULLSIZE[1] = sc(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 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 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 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::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::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::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::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 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 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(); + }}; + + 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); + 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) || + !g_pHyprRenderer->shouldUseNewBlurOptimizations(element->m_data.currentLS.lock(), m_renderData.currentWindow.lock()); + + // vvv TODO: layered blur fbs? + if (element->m_data.blockBlurOptimization) { + 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); + m_renderData.currentFB->bind(); + } else + element->m_data.blurredBG = m_renderData.pMonitor->m_blurFB ? m_renderData.pMonitor->m_blurFB->getTexture() : nullptr; + + draw(element, damage); + } else + draw(element, damage); + + m_renderData.clipBox = {}; +} + +void IElementRenderer::drawTexMatte(WP 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); +} \ No newline at end of file diff --git a/src/render/ElementRenderer.hpp b/src/render/ElementRenderer.hpp new file mode 100644 index 000000000..67e716ade --- /dev/null +++ b/src/render/ElementRenderer.hpp @@ -0,0 +1,45 @@ +#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 + +namespace Render { + class IElementRenderer { + public: + IElementRenderer() = default; + virtual ~IElementRenderer() = default; + + void drawElement(WP element, const CRegion& damage); + + protected: + virtual void draw(WP element, const CRegion& damage) = 0; + virtual void draw(WP element, const CRegion& damage) = 0; + virtual void draw(WP element, const CRegion& damage) = 0; + virtual void draw(WP element, const CRegion& damage) = 0; + virtual void draw(WP element, const CRegion& damage) = 0; + virtual void draw(WP element, const CRegion& damage) = 0; + virtual void draw(WP element, const CRegion& damage) = 0; + virtual void draw(WP element, const CRegion& damage) = 0; + + private: + void calculateUVForSurface(PHLWINDOW, SP, PHLMONITOR pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {}, + bool fixMisalignedFSV1 = false); + + void drawRect(WP element, const CRegion& damage); + void drawHints(WP element, const CRegion& damage); + void drawPreBlur(WP element, const CRegion& damage); + void drawSurface(WP element, const CRegion& damage); + void preDrawSurface(WP element, const CRegion& damage); + void drawTex(WP element, const CRegion& damage); + void drawTexMatte(WP element, const CRegion& damage); + }; +} diff --git a/src/render/GLRenderer.cpp b/src/render/GLRenderer.cpp index 48825a4b5..1cc4d62ad 100644 --- a/src/render/GLRenderer.cpp +++ b/src/render/GLRenderer.cpp @@ -11,30 +11,37 @@ #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 #include +#include #include 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 } -CHyprGLRenderer::CHyprGLRenderer() : IHyprRenderer() {} +CHyprGLRenderer::CHyprGLRenderer() : IHyprRenderer() { + m_elementRenderer = makeUnique(); +} + +CHyprGLRenderer::~CHyprGLRenderer() { + m_elementRenderer.reset(); +} void CHyprGLRenderer::initRender() { g_pHyprOpenGL->makeEGLCurrent(); @@ -281,118 +288,6 @@ 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 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(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(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 CHyprGLRenderer::getBlurTexture(PHLMONITORREF pMonitor) { if (!pMonitor->m_blurFB) return nullptr; @@ -405,3 +300,7 @@ void CHyprGLRenderer::unsetEGL() { eglMakeCurrent(g_pHyprOpenGL->m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); } + +WP CHyprGLRenderer::elementRenderer() { + return m_elementRenderer; +} diff --git a/src/render/GLRenderer.hpp b/src/render/GLRenderer.hpp index 1446e9b29..853fdc2da 100644 --- a/src/render/GLRenderer.hpp +++ b/src/render/GLRenderer.hpp @@ -1,52 +1,49 @@ #pragma once #include "Renderer.hpp" +#include "render/ElementRenderer.hpp" -class CHyprGLRenderer : public IHyprRenderer { - public: - CHyprGLRenderer(); +namespace Render::GL { + class CHyprGLRenderer : public Render::IHyprRenderer { + public: + CHyprGLRenderer(); + ~CHyprGLRenderer(); - void endRender(const std::function& renderingDoneCallback = {}) override; - SP createStencilTexture(const int width, const int height) override; - SP createTexture(bool opaque = false) override; - SP createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) override; - SP createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) override; - SP createTexture(const int width, const int height, unsigned char* const data) override; - SP createTexture(cairo_surface_t* cairo) override; - SP createTexture(std::span lut3D, size_t N) override; - bool explicitSyncSupported() override; - std::vector getDRMFormats() override; - std::vector getDRMFormatModifiers(DRMFormat format) override; - SP 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 blurFramebuffer(SP 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 endRender(const std::function& renderingDoneCallback = {}) override; + SP createStencilTexture(const int width, const int height) override; + SP createTexture(bool opaque = false) override; + SP createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) override; + SP createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) override; + SP createTexture(const int width, const int height, unsigned char* const data) override; + SP createTexture(cairo_surface_t* cairo) override; + SP createTexture(std::span lut3D, size_t N) override; + bool explicitSyncSupported() override; + std::vector getDRMFormats() override; + std::vector getDRMFormatModifiers(DRMFormat format) override; + SP 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 blurFramebuffer(SP 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(); + void unsetEGL(); + WP elementRenderer() override; - private: - void renderOffToMain(IFramebuffer* off) override; - SP getOrCreateRenderbufferInternal(SP buffer, uint32_t fmt) override; - bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) override; - bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP fb, bool simple = false) override; - void initRender() override; - bool initRenderBuffer(SP buffer, uint32_t fmt) override; + private: + void renderOffToMain(IFramebuffer* off) override; + SP getOrCreateRenderbufferInternal(SP buffer, uint32_t fmt) override; + bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) override; + bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP fb, bool simple = false) override; + void initRender() override; + bool initRenderBuffer(SP 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(CTexPassElement* element, const CRegion& damage) override; - void draw(CTextureMatteElement* element, const CRegion& damage) override; + SP getBlurTexture(PHLMONITORREF pMonitor) override; - SP getBlurTexture(PHLMONITORREF pMonitor) override; + SP m_currentRenderbuffer; + UP m_elementRenderer; - SP m_currentRenderbuffer = nullptr; - - friend class CHyprOpenGLImpl; -}; + friend class CHyprOpenGLImpl; + }; +} \ No newline at end of file diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp index d466dc82b..1c1e3a842 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(eglGetProcAddress(name)); @@ -951,21 +952,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); @@ -1446,7 +1432,7 @@ WP CHyprOpenGLImpl::renderToFBInternal(const STextureRenderData& data, void CHyprOpenGLImpl::renderTextureInternal(SP 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 && tex->ok()), "Attempted to draw nullptr texture!"); TRACY_GPU_ZONE("RenderTextureInternalWithDamage"); diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp index 66339fdbd..415231ce1 100644 --- a/src/render/OpenGL.hpp +++ b/src/render/OpenGL.hpp @@ -16,6 +16,7 @@ #include +#include "types.hpp" #include "Shader.hpp" #include "Texture.hpp" #include "Framebuffer.hpp" @@ -40,342 +41,326 @@ #define GLFB(ifb) dc(ifb.get()) struct gbm_device; -class IHyprRenderer; - -namespace Config { - class CGradientValueData; +namespace Render { + class IHyprRenderer; } +class CGradientValueData; -struct SVertex { - float x, y; // position - float u, v; // uv -}; +namespace Render::GL { -constexpr std::array 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 */ + struct SVertex { + float x, y; // position + float u, v; // uv }; - std::vector> modifs; + constexpr std::array 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 + }}; - void applyToBox(CBox& box); - void applyToRegion(CRegion& rg); - float combinedScale(); + inline const float fanVertsFull[] = {-1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f}; - 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(); - // } - // } - - std::string TEXVERTSRC; - std::string TEXVERTSRC320; - // std::array, SH_FRAG_LAST> frag; - // std::map> fragVariants; - std::array>, Render::SH_FRAG_LAST> fragVariants; -}; - -struct SCurrentRenderData { - PHLMONITORREF pMonitor; - Mat3x3 projection; - Mat3x3 savedProjection; - Mat3x3 monitorProjection; - - SP currentFB = nullptr; // current rendering to - SP mainFB = nullptr; // main to render to - SP 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 surface; -}; - -class CEGLSync { - public: - static UP 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 eMonitorRenderFBs : uint8_t { + FB_MONITOR_RENDER_MAIN = 0, + FB_MONITOR_RENDER_CURRENT = 1, + FB_MONITOR_RENDER_OUT = 2, }; - struct STextureRenderData { - bool blur = false; - float blurA = 1.F, overallA = 1.F; - bool blockBlurOptimization = false; - SP blurredBG; - - const CRegion* damage = nullptr; - SP 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 cmBackToSRGBSource; - - uint32_t discardMode = DISCARD_OPAQUE; - float discardOpacity = 0.f; - - CRegion clipRegion; - PHLLSREF currentLS; - - Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); - Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); + 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 SBorderRenderData { - int round = 0; - float roundingPower = 2.F; - int borderSize = 1; - float a = 1.0; - int outerRound = -1; /* use round */ + struct SFragShaderDesc { + Render::ePreparedFragmentShader id; + const char* file; }; - void makeEGLCurrent(); - void begin(PHLMONITOR, const CRegion& damage, SP fb = nullptr, std::optional finalDamage = {}); - void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, SP fb = nullptr); - void end(); + struct SPreparedShaders { + // SPreparedShaders() { + // for (auto& f : frag) { + // f = makeShared(); + // } + // } - void renderRect(const CBox&, const CHyprColor&, SRectRenderData data); - void renderTexture(SP, const CBox&, STextureRenderData data); - void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, 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 tex, const CBox& pBox, SP matte); - void renderTexturePrimitive(SP 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 getDRMFormats(); - std::vector getDRMFormatModifiers(DRMFormat format); - EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); - - bool initShaders(const std::string& path = ""); - - WP useShader(WP prog); - - bool explicitSyncSupported(); - WP getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0); - - bool m_shadersInitialized = false; - SP 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> 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, + std::string TEXVERTSRC; + std::string TEXVERTSRC320; + // std::array, SH_FRAG_LAST> frag; + // std::map> fragVariants; + std::array>, Render::SH_FRAG_LAST> fragVariants; }; - eEGLContextVersion m_eglContextVersion = EGL_CONTEXT_GLES_3_2; + struct SCurrentRenderData { + PHLMONITORREF pMonitor; + Mat3x3 projection; + Mat3x3 savedProjection; + Mat3x3 monitorProjection; - enum eCachedCapStatus : uint8_t { - CAP_STATUS_BLEND = 0, - CAP_STATUS_SCISSOR_TEST, - CAP_STATUS_STENCIL_TEST, - CAP_STATUS_END + SP currentFB = nullptr; // current rendering to + SP mainFB = nullptr; // main to render to + SP 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 surface; }; - private: - struct { - GLint x = 0; - GLint y = 0; - GLsizei width = 0; - GLsizei height = 0; - } m_lastViewport; + class CEGLSync { + public: + static UP create(); - std::array m_capStatus = {}; + ~CEGLSync(); - std::vector m_drmFormats; - bool m_hasModifiers = false; + Hyprutils::OS::CFileDescriptor& fd(); + Hyprutils::OS::CFileDescriptor&& takeFd(); + bool isValid(); - int m_drmFD = -1; - std::string m_extensions; + private: + CEGLSync() = default; - bool m_fakeFrame = false; - bool m_applyFinalShader = false; - bool m_blend = false; - bool m_offloadedFramebuffer = false; - bool m_cmSupported = true; + Hyprutils::OS::CFileDescriptor m_fd; + EGLSyncKHR m_sync = EGL_NO_SYNC_KHR; + bool m_valid = false; - SP m_finalScreenShader; - GLuint m_currentProgram; + friend class CHyprOpenGLImpl; + }; - void initDRMFormats(); - void initEGL(bool gbm); - EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); + class CHyprOpenGLImpl { + public: + CHyprOpenGLImpl(); + ~CHyprOpenGLImpl(); - // for the final shader - std::array m_pressedHistoryTimers = {}; - std::array m_pressedHistoryPositions = {}; - GLint m_pressedHistoryKilled = 0; - GLint m_pressedHistoryTouched = 0; + struct SRectRenderData { + const CRegion* damage = nullptr; + int round = 0; + float roundingPower = 2.F; + bool blur = false; + float blurA = 1.F; + bool xray = false; + }; - // - std::optional> getModsForFormat(EGLint format); + struct STextureRenderData { + bool blur = false; + float blurA = 1.F, overallA = 1.F; + bool blockBlurOptimization = false; + SP blurredBG; - // returns the out FB, can be either Mirror or MirrorSwap - SP blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source); + const CRegion* damage = nullptr; + SP 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 cmBackToSRGBSource; - void passCMUniforms(WP, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, - bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); - void passCMUniforms(WP, 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 renderToOutputInternal(); - WP renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox); - void renderTextureInternal(SP, const CBox&, const STextureRenderData& data); - void renderTextureWithBlurInternal(SP, const CBox&, const STextureRenderData& data); + uint32_t discardMode = DISCARD_OPAQUE; + float discardOpacity = 0.f; - friend class IHyprRenderer; - friend class CHyprGLRenderer; - friend class CTexPassElement; - friend class CPreBlurElement; - friend class CSurfacePassElement; -}; + CRegion clipRegion; + PHLLSREF currentLS; -inline UP g_pHyprOpenGL; + 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 fb = nullptr, std::optional finalDamage = {}); + void beginSimple(PHLMONITOR, const CRegion& damage, SP rb = nullptr, SP fb = nullptr); + void end(); + + void renderRect(const CBox&, const CHyprColor&, SRectRenderData data); + void renderTexture(SP, const CBox&, STextureRenderData data); + void renderRoundedShadow(const CBox&, int round, float roundingPower, int range, const CHyprColor& color, float a = 1.0); + void renderBorder(const CBox&, const CGradientValueData&, SBorderRenderData data); + void renderBorder(const CBox&, const CGradientValueData&, const CGradientValueData&, float lerp, SBorderRenderData data); + void renderTextureMatte(SP tex, const CBox& pBox, SP matte); + void renderTexturePrimitive(SP 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(IFramebuffer* off); + + std::vector getDRMFormats(); + std::vector getDRMFormatModifiers(DRMFormat format); + EGLImageKHR createEGLImage(const Aquamarine::SDMABUFAttrs& attrs); + + bool initShaders(const std::string& path = ""); + + WP useShader(WP prog); + + bool explicitSyncSupported(); + WP getShaderVariant(Render::ePreparedFragmentShader frag, Render::ShaderFeatureFlags features = 0); + + bool m_shadersInitialized = false; + SP 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> 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 m_capStatus = {}; + + std::vector 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 m_finalScreenShader; + GLuint m_currentProgram; + + void initDRMFormats(); + void initEGL(bool gbm); + EGLDeviceEXT eglDeviceFromDRMFD(int drmFD); + + // for the final shader + std::array m_pressedHistoryTimers = {}; + std::array m_pressedHistoryPositions = {}; + GLint m_pressedHistoryKilled = 0; + GLint m_pressedHistoryTouched = 0; + + // + std::optional> getModsForFormat(EGLint format); + + // returns the out FB, can be either Mirror or MirrorSwap + SP blurFramebufferWithDamage(float a, CRegion* damage, CGLFramebuffer& source); + + void passCMUniforms(WP, const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, + bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); + void passCMUniforms(WP, 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 renderToOutputInternal(); + WP renderToFBInternal(const STextureRenderData& data, eTextureType texType, const CBox& newBox); + void renderTextureInternal(SP, const CBox&, const STextureRenderData& data); + void renderTextureWithBlurInternal(SP, 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 g_pHyprOpenGL; +} diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index e242ecc00..105daf65e 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -47,11 +47,11 @@ #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 #include #include @@ -65,6 +65,7 @@ using namespace Hyprutils::Utils; using namespace Hyprutils::OS; using enum NContentType::eContentType; using namespace NColorManagement; +using namespace Render; extern "C" { #include @@ -212,8 +213,8 @@ IHyprRenderer::~IHyprRenderer() { wl_event_source_remove(m_cursorTicker); } -WP IHyprRenderer::glBackend() { - return g_pHyprOpenGL; +WP IHyprRenderer::glBackend() { + return Render::GL::g_pHyprOpenGL; } bool IHyprRenderer::shouldRenderWindow(PHLWINDOW pWindow, PHLMONITOR pMonitor) { @@ -502,7 +503,7 @@ 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::SClearData{{0, 0, 0, 0}}), {}); + draw(makeShared(CClearPassElement::SClearData{{0, 0, 0, 0}}), {}); m_renderData.currentFB = m_renderData.pMonitor->m_offMainFB; } @@ -769,347 +770,12 @@ 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) - 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(transformedBox.x); - data.TOPLEFT[1] = sc(transformedBox.y); - data.FULLSIZE[0] = sc(transformedBox.width); - data.FULLSIZE[1] = sc(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 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::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::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::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::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::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::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::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); - - 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; - - draw(element, damage); - } else - draw(element, damage); - - m_renderData.clipBox = {}; -} - -void IHyprRenderer::drawTexMatte(CTextureMatteElement* element, const CRegion& damage) { - if (m_renderData.damage.empty()) - return; - - 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(WP element, const CRegion& damage) { + ASSERT(element); if (!element) return; - switch (element->type()) { - case EK_BORDER: draw(dc(element.get()), damage); break; - case EK_CLEAR: draw(dc(element.get()), damage); break; - case EK_FRAMEBUFFER: draw(dc(element.get()), damage); break; - case EK_PRE_BLUR: drawPreBlur(dc(element.get()), damage); break; - case EK_RECT: drawRect(dc(element.get()), damage); break; - case EK_HINTS: drawHints(dc(element.get()), damage); break; - case EK_SHADOW: draw(dc(element.get()), damage); break; - case EK_SURFACE: preDrawSurface(dc(element.get()), damage); break; - case EK_TEXTURE: drawTex(dc(element.get()), damage); break; - case EK_TEXTURE_MATTE: drawTexMatte(dc(element.get()), damage); break; - default: Log::logger->log(Log::WARN, "Unimplimented draw for {}", element->passName()); - } + elementRenderer()->drawElement(element, damage); } bool IHyprRenderer::preBlurQueued(PHLMONITORREF pMonitor) { @@ -1892,126 +1558,6 @@ void IHyprRenderer::renderSessionLockMissing(PHLMONITOR pMonitor) { } } -static std::optional getSurfaceExpectedSize(PHLWINDOW pWindow, SP 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 pSurface, PHLMONITOR pMonitor, bool main, const Vector2D& projSize, - const Vector2D& projSizeUnscaled, bool fixMisalignedFSV1) { - if (!pWindow || !pWindow->m_isX11) { - static auto PEXPANDEDGES = CConfigValue("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 buffer, SP fb, bool simple) { m_renderPass.clear(); m_renderMode = mode; @@ -2165,11 +1711,11 @@ void IHyprRenderer::preBlurForCurrentMonitor(CRegion* fakeDamage) { 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(); - draw(makeUnique(CClearPassElement::SClearData{{0, 0, 0, 0}}), {}); + draw(makeShared(CClearPassElement::SClearData{{0, 0, 0, 0}}), {}); pushMonitorTransformEnabled(true); - draw(makeUnique(CTexPassElement::SRenderData{ + draw(makeShared(CTexPassElement::SRenderData{ .tex = blurredTex, .box = CBox{0, 0, m_renderData.pMonitor->m_transformedSize.x, m_renderData.pMonitor->m_transformedSize.y}, .damage = *fakeDamage, @@ -3351,7 +2897,7 @@ void IHyprRenderer::makeSnapshot(PHLWINDOW pWindow) { m_bRenderingSnapshot = true; - draw(makeUnique(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); + draw(makeShared(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); startRenderPass(); Log::logger->log(Log::DEBUG, "renderer: cleared a snapshot of {:x}", rc(pWindow.get())); @@ -3392,7 +2938,7 @@ void IHyprRenderer::makeSnapshot(PHLLS pLayer) { m_bRenderingSnapshot = true; - draw(makeUnique(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); + draw(makeShared(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); startRenderPass(); Log::logger->log(Log::DEBUG, "renderer: cleared a snapshot of layer {:x}", rc(pLayer.get())); @@ -3434,7 +2980,7 @@ void IHyprRenderer::makeSnapshot(WP popup) { m_bRenderingSnapshot = true; - draw(makeUnique(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); + draw(makeShared(CClearPassElement::SClearData{CHyprColor(0, 0, 0, 0)}), {}); CSurfacePassElement::SRenderData renderdata; renderdata.pos = popup->coordsGlobal(); diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp index 4b65141a1..44aff1b9b 100644 --- a/src/render/Renderer.hpp +++ b/src/render/Renderer.hpp @@ -5,6 +5,8 @@ #include #include #include +#include "OpenGL.hpp" +#include "types.hpp" #include "../helpers/Monitor.hpp" #include "../desktop/view/LayerSurface.hpp" #include "./pass/Pass.hpp" @@ -13,19 +15,12 @@ #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/SurfacePassElement.hpp" -#include "pass/TexPassElement.hpp" -#include "pass/TextureMatteElement.hpp" +#include "./pass/SurfacePassElement.hpp" +#include "./pass/TexPassElement.hpp" +#include "./pass/TextureMatteElement.hpp" struct SMonitorRule; class CWorkspace; @@ -33,14 +28,6 @@ class CInputPopup; class IHLBuffer; class CEventLoopTimer; class CRenderPass; - -const std::vector ASSET_PATHS = { -#ifdef DATAROOTDIR - DATAROOTDIR, -#endif - "/usr/share", - "/usr/local/share", -}; class CToplevelExportProtocolManager; class CInputManager; struct SSessionLockSurface; @@ -48,329 +35,229 @@ namespace Screenshare { class CScreenshareFrame; }; -enum eDamageTrackingModes : int8_t { - DAMAGE_TRACKING_INVALID = -1, - DAMAGE_TRACKING_NONE = 0, - DAMAGE_TRACKING_MONITOR, - DAMAGE_TRACKING_FULL, -}; +namespace Render { + class IElementRenderer; -enum eRenderPassMode : uint8_t { - RENDER_PASS_ALL = 0, - RENDER_PASS_MAIN, - RENDER_PASS_POPUP -}; + class IHyprRenderer { + public: + IHyprRenderer(); + virtual ~IHyprRenderer(); -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, -}; + WP glBackend(); -struct SRenderWorkspaceUntilData { - PHLLS ls; - PHLWINDOW w; -}; + void renderMonitor(PHLMONITOR pMonitor, bool commit = true); + void arrangeLayersForMonitor(const MONITORID&); + void damageSurface(SP, 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); -enum eRenderProjectionType : uint8_t { - RPT_MONITOR, - RPT_MIRROR, - RPT_FB, - RPT_EXPORT, -}; + std::tuple 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 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); + void renderSnapshot(PHLWINDOW); + void renderSnapshot(PHLLS); + void renderSnapshot(WP); + bool beginFullFakeRender(PHLMONITOR pMonitor, CRegion& damage, SP fb); + bool beginRenderToBuffer(PHLMONITOR pMonitor, CRegion& damage, SP buffer, bool simple = false); + virtual void startRenderPass() {}; + virtual void endRender(const std::function& renderingDoneCallback = {}) = 0; -struct SRenderData { - // can be private - Mat3x3 targetProjection; + NColorManagement::PImageDescription workBufferImageDescription(); + bool m_bBlockSurfaceFeedback = false; + bool m_bRenderingSnapshot = false; + PHLMONITORREF m_mostHzMonitor; + bool m_directScanoutBlocked = false; - // ---------------------- + void setSurfaceScanoutMode(SP surface, PHLMONITOR monitor); // nullptr monitor resets - // used by public - Vector2D fbSize = {-1, -1}; - PHLMONITORREF pMonitor; + void initiateManualCrash(); + const SRenderData& renderData(); - eRenderProjectionType projectionType = RPT_MONITOR; + bool m_crashingInProgress = false; + float m_crashingDistort = 0.5f; + wl_event_source* m_crashingLoop = nullptr; + wl_event_source* m_cursorTicker = nullptr; - SP currentFB = nullptr; // current rendering to - SP mainFB = nullptr; // main to render to - SP outFB = nullptr; // out to render to (if offloaded, etc) + std::vector m_usedAsyncBuffers; - CRegion damage; - CRegion finalDamage; // damage used for funal off -> main + 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> surf; + std::string name; + } m_lastCursorData; - SRenderModifData renderModif; - float mouseZoomFactor = 1.f; - bool mouseZoomUseMouse = true; // true by default - bool useNearestNeighbor = false; - bool blockScreenShader = false; + CRenderPass m_renderPass; - Vector2D primarySurfaceUVTopLeft = Vector2D(-1, -1); - Vector2D primarySurfaceUVBottomRight = Vector2D(-1, -1); + SP renderSplash(const std::function(const int, const int, unsigned char* const)>& handleData, const int fontSize, const int maxWidth = 1024, + const int maxHeight = 1024); - // TODO remove and pass directly - CBox clipBox = {}; // scaled coordinates - PHLWINDOWREF currentWindow; - WP surface; + virtual SP getOrCreateRenderbuffer(SP 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 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; - bool transformDamage = true; - bool noSimplify = false; -}; + void draw(WP element, const CRegion& damage); + virtual WP elementRenderer() = 0; + virtual SP createStencilTexture(const int width, const int height) = 0; + virtual SP createTexture(bool opaque = false) = 0; + virtual SP createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) = 0; + virtual SP createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) = 0; + virtual SP createTexture(const int width, const int height, unsigned char* const) = 0; + virtual SP createTexture(cairo_surface_t* cairo) = 0; + virtual SP createTexture(std::span lut3D, size_t N) = 0; + virtual SP createTexture(const SP buffer, bool keepDataCopy = false); + virtual SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, + int weight = 400); + SP loadAsset(const std::string& filename); + virtual bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); + virtual bool explicitSyncSupported() = 0; + virtual std::vector getDRMFormats() = 0; + virtual std::vector getDRMFormatModifiers(DRMFormat format) = 0; + virtual SP 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; -struct STFRange { - float min = 0; - float max = 80; -}; + bool preBlurQueued(PHLMONITORREF pMonitor); + void pushMonitorTransformEnabled(bool enabled); + void popMonitorTransformEnabled(); + bool monitorTransformEnabled(); -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, 3> convertMatrix; + void setProjectionType(const Vector2D& fbSize); + void setProjectionType(eRenderProjectionType projectionType); + Mat3x3 getBoxProjection(const CBox& box, std::optional transform = std::nullopt); + Mat3x3 projectBoxToTarget(const CBox& box, std::optional transform = std::nullopt); - bool needsTonemap = false; - float maxLuminance = 80; - float dstMaxLuminance = 80; - std::array, 3> dstPrimaries2XYZ; - bool needsSDRmod = false; - float sdrSaturation = 1.0; - float sdrBrightnessMultiplier = 1.0; -}; + SP blurMainFramebuffer(float a, CRegion* originalDamage); + virtual SP blurFramebuffer(SP source, float a, CRegion* originalDamage) = 0; + void preBlurForCurrentMonitor(CRegion* fakeDamage); -class IHyprRenderer { - public: - IHyprRenderer(); - virtual ~IHyprRenderer(); + SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, + SP surface = nullptr, bool modifySDR = false, float sdrMinLuminance = -1.0f, int sdrMaxLuminance = -1); + virtual bool reloadShaders(const std::string& path = "") = 0; - WP glBackend(); + bool needsACopyFB(PHLMONITOR mon); - void renderMonitor(PHLMONITOR pMonitor, bool commit = true); - void arrangeLayersForMonitor(const MONITORID&); - void damageSurface(SP, 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, PHLMONITOR pMonitor, bool main = false, const Vector2D& projSize = {}, const Vector2D& projSizeUnscaled = {}, - bool fixMisalignedFSV1 = false); - std::tuple 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 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); - void renderSnapshot(PHLWINDOW); - void renderSnapshot(PHLLS); - void renderSnapshot(WP); - bool beginFullFakeRender(PHLMONITOR pMonitor, CRegion& damage, SP fb); - bool beginRenderToBuffer(PHLMONITOR pMonitor, CRegion& damage, SP buffer, bool simple = false); - virtual void startRenderPass() {}; - virtual void endRender(const std::function& renderingDoneCallback = {}) = 0; + protected: + virtual void renderOffToMain(IFramebuffer* off) = 0; + virtual SP getOrCreateRenderbufferInternal(SP buffer, uint32_t fmt) = 0; + void renderMirrored(); + void setDamage(const CRegion& damage_, std::optional 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 buffer = {}, SP fb = nullptr, + bool simple = false); - NColorManagement::PImageDescription workBufferImageDescription(); - bool m_bBlockSurfaceFeedback = false; - bool m_bRenderingSnapshot = false; - PHLMONITORREF m_mostHzMonitor; - bool m_directScanoutBlocked = false; + virtual bool beginRenderInternal(PHLMONITOR pMonitor, CRegion& damage, bool simple = false) { + return false; + }; + virtual bool beginFullFakeRenderInternal(PHLMONITOR pMonitor, CRegion& damage, SP fb, bool simple = false) { + return false; + }; + virtual void initRender() {}; + virtual bool initRenderBuffer(SP buffer, uint32_t fmt) { + return false; + }; - void setSurfaceScanoutMode(SP surface, PHLMONITOR monitor); // nullptr monitor resets + SP getBackground(PHLMONITOR pMonitor); + virtual SP getBlurTexture(PHLMONITORREF pMonitor); + SP m_lockDeadTexture; + SP m_lockDead2Texture; + SP m_lockTtyTextTexture; + bool m_monitorTransformEnabled = false; // do not modify directly + std::stack m_monitorTransformStack; - void initiateManualCrash(); - const SRenderData& renderData(); + // old private: + void arrangeLayerArray(PHLMONITOR, const std::vector&, 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, 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 m_missingAssetTexture; + ASP m_backgroundResource; + bool m_backgroundResourceFailed = false; - bool m_crashingInProgress = false; - float m_crashingDistort = 0.5f; - wl_event_source* m_crashingLoop = nullptr; - wl_event_source* m_cursorTicker = nullptr; + bool shouldBlur(PHLLS ls); + bool shouldBlur(PHLWINDOW w); + bool shouldBlur(WP p); - std::vector m_usedAsyncBuffers; + bool m_cursorHidden = false; + bool m_cursorHiddenByCondition = false; + bool m_cursorHasSurface = false; + SP 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 { - 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> surf; - std::string name; - } m_lastCursorData; + struct { + bool hiddenOnTouch = false; + bool hiddenOnTablet = false; + bool hiddenOnTimeout = false; + bool hiddenOnKeyboard = false; + } m_cursorHiddenConditions; - CRenderPass m_renderPass; + std::vector> m_renderbuffers; + std::vector m_renderUnfocused; + SP m_renderUnfocusedTimer; - SP renderSplash(const std::function(const int, const int, unsigned char* const)>& handleData, const int fontSize, const int maxWidth = 1024, - const int maxHeight = 1024); + 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; - virtual SP getOrCreateRenderbuffer(SP 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 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 element, const CRegion& damage); - virtual SP createStencilTexture(const int width, const int height) = 0; - virtual SP createTexture(bool opaque = false) = 0; - virtual SP createTexture(uint32_t drmFormat, uint8_t* pixels, uint32_t stride, const Vector2D& size, bool keepDataCopy = false, bool opaque = false) = 0; - virtual SP createTexture(const Aquamarine::SDMABUFAttrs&, bool opaque = false) = 0; - virtual SP createTexture(const int width, const int height, unsigned char* const) = 0; - virtual SP createTexture(cairo_surface_t* cairo) = 0; - virtual SP createTexture(std::span lut3D, size_t N) = 0; - virtual SP createTexture(const SP buffer, bool keepDataCopy = false); - virtual SP renderText(const std::string& text, CHyprColor col, int pt, bool italic = false, const std::string& fontFamily = "", int maxWidth = 0, int weight = 400); - SP loadAsset(const std::string& filename); - virtual bool shouldUseNewBlurOptimizations(PHLLS pLayer, PHLWINDOW pWindow); - virtual bool explicitSyncSupported() = 0; - virtual std::vector getDRMFormats() = 0; - virtual std::vector getDRMFormatModifiers(DRMFormat format) = 0; - virtual SP 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 transform = std::nullopt); - Mat3x3 projectBoxToTarget(const CBox& box, std::optional transform = std::nullopt); - - SP blurMainFramebuffer(float a, CRegion* originalDamage); - virtual SP blurFramebuffer(SP source, float a, CRegion* originalDamage) = 0; - void preBlurForCurrentMonitor(CRegion* fakeDamage); - - SCMSettings getCMSettings(const NColorManagement::PImageDescription imageDescription, const NColorManagement::PImageDescription targetImageDescription, - SP 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 getOrCreateRenderbufferInternal(SP buffer, uint32_t fmt) = 0; - void renderMirrored(); - void setDamage(const CRegion& damage_, std::optional 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 buffer = {}, SP 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 fb, bool simple = false) { - return false; - }; - virtual void initRender() {}; - virtual bool initRenderBuffer(SP buffer, uint32_t fmt) { - return false; + private: + void bindOffMain(); + void bindBackOnMain(); }; - SP 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(CTexPassElement* element, const CRegion& damage) = 0; - virtual void draw(CTextureMatteElement* element, const CRegion& damage) = 0; - virtual SP getBlurTexture(PHLMONITORREF pMonitor); - SP m_lockDeadTexture; - SP m_lockDead2Texture; - SP m_lockTtyTextTexture; - bool m_monitorTransformEnabled = false; // do not modify directly - std::stack m_monitorTransformStack; +} - // old private: - void arrangeLayerArray(PHLMONITOR, const std::vector&, 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, 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 m_missingAssetTexture; - ASP m_backgroundResource; - bool m_backgroundResourceFailed = false; - - bool shouldBlur(PHLLS ls); - bool shouldBlur(PHLWINDOW w); - bool shouldBlur(WP p); - - bool m_cursorHidden = false; - bool m_cursorHiddenByCondition = false; - bool m_cursorHasSurface = false; - SP 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> m_renderbuffers; - std::vector m_renderUnfocused; - SP 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 g_pHyprRenderer; +inline UP g_pHyprRenderer; \ No newline at end of file diff --git a/src/render/Shader.cpp b/src/render/Shader.cpp index ed272fcd9..dfc9045ae 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 5cef2d99e..fd3f59aab 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 includes, const std::array& frags, const std::string shaderPath) : m_shaderPath(shaderPath) { m_callbacks = glsl_include_callbacks_t{ .include_local = diff --git a/src/render/decorations/CHyprDropShadowDecoration.cpp b/src/render/decorations/CHyprDropShadowDecoration.cpp index 2d4eaba28..d454327b3 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) { @@ -245,14 +246,14 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { // 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::SRectData{.box = data.fullBox, .color = CHyprColor(0, 0, 0, 1), .round = 0}), monbox); + g_pHyprRenderer->draw(makeShared(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::SRectData{ + g_pHyprRenderer->draw(makeShared(CRectPassElement::SRectData{ .box = data.windowBox, .color = CHyprColor(0, 0, 0, 1), .round = (data.rounding + 1 /* This fixes small pixel gaps. */) * pMonitor->m_scale, @@ -263,7 +264,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { alphaSwapFB->bind(); // alpha swap just has the shadow color. It will be the "texture" to render. - g_pHyprRenderer->draw(makeUnique(CRectPassElement::SRectData{.box = data.fullBox, .color = PWINDOW->m_realShadowColor->value().stripA(), .round = 0}), + g_pHyprRenderer->draw(makeShared(CRectPassElement::SRectData{.box = data.fullBox, .color = PWINDOW->m_realShadowColor->value().stripA(), .round = 0}), monbox); LASTFB->bind(); @@ -271,7 +272,7 @@ void CHyprDropShadowDecoration::render(PHLMONITOR pMonitor, float const& a) { g_pHyprRenderer->pushMonitorTransformEnabled(true); g_pHyprRenderer->m_renderData.renderModif.enabled = false; - g_pHyprRenderer->draw(makeUnique(CTextureMatteElement::STextureMatteData{ + g_pHyprRenderer->draw(makeShared(CTextureMatteElement::STextureMatteData{ .box = monbox, .tex = alphaSwapFB->getTexture(), .fb = alphaFB, @@ -303,7 +304,7 @@ void CHyprDropShadowDecoration::drawShadowInternal(const CBox& box, int round, f color.a *= a; if (*PSHADOWSHARP) - g_pHyprRenderer->draw(makeUnique(CRectPassElement::SRectData{ + g_pHyprRenderer->draw(makeShared(CRectPassElement::SRectData{ .box = box, .color = color, .round = round, diff --git a/src/render/gl/GLElementRenderer.cpp b/src/render/gl/GLElementRenderer.cpp new file mode 100644 index 000000000..b520b0f2b --- /dev/null +++ b/src/render/gl/GLElementRenderer.cpp @@ -0,0 +1,131 @@ +#include "GLElementRenderer.hpp" +#include "../Renderer.hpp" +#include "../decorations/CHyprDropShadowDecoration.hpp" +#include "../OpenGL.hpp" +#include + +using namespace Render::GL; + +void CGLElementRenderer::draw(WP 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 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 element, const CRegion& damage) { + const auto m_data = element->m_data; + SP 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; + } + } + + fb->bind(); +}; + +void CGLElementRenderer::draw(WP element, const CRegion& damage) { + auto dmg = damage; + g_pHyprRenderer->preBlurForCurrentMonitor(&dmg); +}; + +void CGLElementRenderer::draw(WP 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 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 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(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 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 000000000..36fa9012d --- /dev/null +++ b/src/render/gl/GLElementRenderer.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "../ElementRenderer.hpp" + +namespace Render::GL { + class CGLElementRenderer : public Render::IElementRenderer { + public: + CGLElementRenderer() = default; + ~CGLElementRenderer() = default; + + private: + void draw(WP element, const Hyprutils::Math::CRegion& damage); + void draw(WP element, const CRegion& damage); + void draw(WP element, const CRegion& damage); + void draw(WP element, const CRegion& damage); + void draw(WP element, const CRegion& damage); + void draw(WP element, const CRegion& damage); + void draw(WP element, const CRegion& damage); + void draw(WP element, const CRegion& damage); + }; +} diff --git a/src/render/gl/GLFramebuffer.cpp b/src/render/gl/GLFramebuffer.cpp index 27ad4a1b6..b50b257ad 100644 --- a/src/render/gl/GLFramebuffer.cpp +++ b/src/render/gl/GLFramebuffer.cpp @@ -4,6 +4,8 @@ #include "macros.hpp" #include "../Framebuffer.hpp" +using namespace Render::GL; + CGLFramebuffer::CGLFramebuffer() : IFramebuffer() {} CGLFramebuffer::CGLFramebuffer(const std::string& name) : IFramebuffer(name) {} diff --git a/src/render/gl/GLFramebuffer.hpp b/src/render/gl/GLFramebuffer.hpp index c171444e9..8bb032ac5 100644 --- a/src/render/gl/GLFramebuffer.hpp +++ b/src/render/gl/GLFramebuffer.hpp @@ -5,26 +5,28 @@ #include "../Framebuffer.hpp" #include -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 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 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& attachments); + void bind() override; + void unbind(); + GLuint getFBID(); + void invalidate(const std::vector& attachments); - protected: - bool internalAlloc(int w, int h, uint32_t format = DRM_FORMAT_ARGB8888) override; + protected: + bool internalAlloc(int w, int h, uint32_t 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 aa8b5be2a..17edd8eaf 100644 --- a/src/render/gl/GLRenderbuffer.cpp +++ b/src/render/gl/GLRenderbuffer.cpp @@ -11,6 +11,8 @@ #include +using namespace Render::GL; + CGLRenderbuffer::~CGLRenderbuffer() { if (!g_pCompositor || g_pCompositor->m_isShuttingDown || !g_pHyprRenderer) return; diff --git a/src/render/gl/GLRenderbuffer.hpp b/src/render/gl/GLRenderbuffer.hpp index 8367f7023..137a8e0d5 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 buffer, uint32_t format); - ~CGLRenderbuffer(); +namespace Render::GL { + class CGLRenderbuffer : public IRenderbuffer { + public: + CGLRenderbuffer(SP 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 93f85c843..d34bdb605 100644 --- a/src/render/gl/GLTexture.cpp +++ b/src/render/gl/GLTexture.cpp @@ -5,6 +5,8 @@ #include "../Texture.hpp" #include +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 34510e903..07b51d9a4 100644 --- a/src/render/gl/GLTexture.hpp +++ b/src/render/gl/GLTexture.hpp @@ -4,46 +4,49 @@ #include #include -class CGLTexture : public ITexture { - public: - using ITexture::ITexture; +namespace Render::GL { - CGLTexture(CGLTexture&) = delete; - CGLTexture(CGLTexture&&) = delete; - CGLTexture(const CGLTexture&&) = delete; - CGLTexture(const CGLTexture&) = delete; + class CGLTexture : public ITexture { + public: + using ITexture::ITexture; - 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 lut3D, size_t N); - ~CGLTexture(); + CGLTexture(CGLTexture&) = delete; + CGLTexture(CGLTexture&&) = delete; + CGLTexture(const CGLTexture&&) = delete; + CGLTexture(const CGLTexture&) = delete; - 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; + 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 lut3D, size_t N); + ~CGLTexture(); - private: - void* m_eglImage = nullptr; + 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; - 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, + 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& colors); + constexpr std::optional getCacheStateIndex(GLenum pname); + + std::array, TEXTURE_PAR_LAST> m_cachedStates; }; - - GLenum m_target = GL_TEXTURE_2D; - - void swizzle(const std::array& colors); - constexpr std::optional getCacheStateIndex(GLenum pname); - - std::array, TEXTURE_PAR_LAST> m_cachedStates; -}; +} diff --git a/src/render/pass/Pass.cpp b/src/render/pass/Pass.cpp index b7923a665..ece4d7da8 100644 --- a/src/render/pass/Pass.cpp +++ b/src/render/pass/Pass.cpp @@ -10,6 +10,11 @@ #include "../../render/Renderer.hpp" #include "../../desktop/state/FocusState.hpp" #include "../../protocols/core/Compositor.hpp" +#include "RectPassElement.hpp" +#include "macros.hpp" +#include "render/pass/ClearPassElement.hpp" + +using namespace Render; bool CRenderPass::empty() const { return false; @@ -216,12 +221,12 @@ void CRenderPass::renderDebugData() { CRectPassElement::SRectData data; data.box = box; data.color = Colors::RED.modifyA(0.1F); - g_pHyprRenderer->draw(makeUnique(data), rg); + g_pHyprRenderer->draw(makeShared(data), rg); } CRectPassElement::SRectData data; data.box = box; data.color = Colors::GREEN.modifyA(0.1F); - g_pHyprRenderer->draw(makeUnique(data), m_totalLiveBlurRegion); + g_pHyprRenderer->draw(makeShared(data), m_totalLiveBlurRegion); std::unordered_map offsets; @@ -249,7 +254,7 @@ void CRenderPass::renderDebugData() { CRectPassElement::SRectData data; data.box = box; data.color = color; - g_pHyprRenderer->draw(makeUnique(data), FULL_REGION); + g_pHyprRenderer->draw(makeShared(data), FULL_REGION); if (offsets.contains(surface.get())) box.translate(Vector2D{0.F, offsets[surface.get()]}); @@ -261,12 +266,12 @@ void CRenderPass::renderDebugData() { data.box = box; data.color = color; data.round = std::min(5.0, box.size().y); - g_pHyprRenderer->draw(makeUnique(data2), FULL_REGION); + g_pHyprRenderer->draw(makeShared(data2), FULL_REGION); CTexPassElement::SRenderData texData; texData.tex = texture; texData.box = box; - g_pHyprRenderer->draw(makeUnique(texData), {}); + g_pHyprRenderer->draw(makeShared(texData), {}); offsets[surface.get()] += texture->m_size.y; }; @@ -287,7 +292,7 @@ void CRenderPass::renderDebugData() { CRectPassElement::SRectData data; data.box = box; data.color = CHyprColor{0.8F, 0.8F, 0.2F, 0.4F}; - g_pHyprRenderer->draw(makeUnique(data), region); + g_pHyprRenderer->draw(makeShared(data), region); } } } @@ -303,7 +308,7 @@ void CRenderPass::renderDebugData() { CTexPassElement::SRenderData texData; texData.tex = tex; texData.box = box; - g_pHyprRenderer->draw(makeUnique(texData), {}); + g_pHyprRenderer->draw(makeShared(texData), {}); } std::string passStructure; @@ -323,7 +328,7 @@ void CRenderPass::renderDebugData() { CTexPassElement::SRenderData texData; texData.tex = tex; texData.box = box; - g_pHyprRenderer->draw(makeUnique(texData), {}); + g_pHyprRenderer->draw(makeShared(texData), {}); } } diff --git a/src/render/pass/RendererHintsPassElement.hpp b/src/render/pass/RendererHintsPassElement.hpp index a5a429b55..0a24ff6de 100644 --- a/src/render/pass/RendererHintsPassElement.hpp +++ b/src/render/pass/RendererHintsPassElement.hpp @@ -1,12 +1,11 @@ #pragma once #include "PassElement.hpp" -#include -#include "../OpenGL.hpp" +#include "../types.hpp" class CRendererHintsPassElement : public IPassElement { public: struct SData { - std::optional renderModif; + std::optional renderModif; }; CRendererHintsPassElement(const SData& data); diff --git a/src/render/types.hpp b/src/render/types.hpp new file mode 100644 index 000000000..a33c7b6df --- /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 +#include +#include +#include +#include + +namespace Render { + const std::vector 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> 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 currentFB = nullptr; // current rendering to + SP mainFB = nullptr; // main to render to + SP 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 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, 3> convertMatrix; + + bool needsTonemap = false; + float maxLuminance = 80; + float dstMaxLuminance = 80; + std::array, 3> dstPrimaries2XYZ; + bool needsSDRmod = false; + float sdrSaturation = 1.0; + float sdrBrightnessMultiplier = 1.0; + }; +} \ No newline at end of file