diff --git a/src/helpers/DamageRing.cpp b/src/helpers/DamageRing.cpp new file mode 100644 index 00000000..093e7ca6 --- /dev/null +++ b/src/helpers/DamageRing.cpp @@ -0,0 +1,52 @@ +#include "DamageRing.hpp" + +void CDamageRing::setSize(const Vector2D& size_) { + if (size_ == size) + return; + + size = size_; + + damageEntire(); +} + +bool CDamageRing::damage(const CRegion& rg) { + CRegion clipped = rg.copy().intersect(CBox{{}, size}); + if (clipped.empty()) + return false; + + current.add(clipped); + return true; +} + +void CDamageRing::damageEntire() { + damage(CBox{{}, size}); +} + +void CDamageRing::rotate() { + previousIdx = (previousIdx + DAMAGE_RING_PREVIOUS_LEN - 1) % DAMAGE_RING_PREVIOUS_LEN; + + previous[previousIdx] = current; + current.clear(); +} + +CRegion CDamageRing::getBufferDamage(int age) { + if (age <= 0 || age > DAMAGE_RING_PREVIOUS_LEN + 1) + return CBox{{}, size}; + + CRegion damage = current; + + for (int i = 0; i < age - 1; ++i) { + int j = (previousIdx + i) % DAMAGE_RING_PREVIOUS_LEN; + damage.add(previous.at(j)); + } + + // don't return a ludicrous amount of rects + if (damage.getRects().size() > 8) + return damage.getExtents(); + + return damage; +} + +bool CDamageRing::hasChanged() { + return !current.empty(); +} diff --git a/src/helpers/DamageRing.hpp b/src/helpers/DamageRing.hpp new file mode 100644 index 00000000..ae85c453 --- /dev/null +++ b/src/helpers/DamageRing.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "./math/Math.hpp" +#include + +constexpr static int DAMAGE_RING_PREVIOUS_LEN = 2; + +class CDamageRing { + public: + void setSize(const Vector2D& size_); + bool damage(const CRegion& rg); + void damageEntire(); + void rotate(); + CRegion getBufferDamage(int age); + bool hasChanged(); + + private: + Vector2D size; + CRegion current; + std::array previous; + size_t previousIdx = 0; +}; diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index e99e16ef..7ebd2539 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -17,12 +17,10 @@ int ratHandler(void* data) { } CMonitor::CMonitor() : state(this) { - wlr_damage_ring_init(&damage); + ; } CMonitor::~CMonitor() { - wlr_damage_ring_finish(&damage); - hyprListener_monitorDestroy.removeCallback(); hyprListener_monitorFrame.removeCallback(); hyprListener_monitorStateRequest.removeCallback(); @@ -162,7 +160,7 @@ void CMonitor::onConnect(bool noRule) { if (!state.commit()) Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit"); - wlr_damage_ring_set_bounds(&damage, vecTransformedSize.x, vecTransformedSize.y); + damage.setSize(vecTransformedSize); Debug::log(LOG, "Added new monitor with name {} at {:j0} with size {:j0}, pointer {:x}", output->name, vecPosition, vecPixelSize, (uintptr_t)output); @@ -345,9 +343,9 @@ void CMonitor::onDisconnect(bool destroy) { void CMonitor::addDamage(const pixman_region32_t* rg) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { - wlr_damage_ring_add_whole(&damage); + damage.damageEntire(); g_pCompositor->scheduleFrameForMonitor(this); - } else if (wlr_damage_ring_add(&damage, rg)) + } else if (damage.damage(rg)) g_pCompositor->scheduleFrameForMonitor(this); } @@ -358,13 +356,11 @@ void CMonitor::addDamage(const CRegion* rg) { void CMonitor::addDamage(const CBox* box) { static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) { - wlr_damage_ring_add_whole(&damage); + damage.damageEntire(); g_pCompositor->scheduleFrameForMonitor(this); } - wlr_box damageBox = {(int)box->x, (int)box->y, (int)box->w, (int)box->h}; - - if (wlr_damage_ring_add_box(&damage, &damageBox)) + if (damage.damage(*box)) g_pCompositor->scheduleFrameForMonitor(this); } @@ -379,7 +375,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() { // keep requested minimum refresh rate if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) { // damage whole screen because some previous cursor box damages were skipped - wlr_damage_ring_add_whole(&damage); + damage.damageEntire(); return false; } diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index b8902197..8a2acdaf 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -11,6 +11,7 @@ #include "math/Math.hpp" #include #include "signal/Signal.hpp" +#include "DamageRing.hpp" // Enum for the different types of auto directions, e.g. auto-left, auto-up. enum eAutoDirs { @@ -60,33 +61,32 @@ class CMonitor { CMonitor(); ~CMonitor(); - Vector2D vecPosition = Vector2D(-1, -1); // means unset - Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset - Vector2D vecSize = Vector2D(0, 0); - Vector2D vecPixelSize = Vector2D(0, 0); - Vector2D vecTransformedSize = Vector2D(0, 0); + Vector2D vecPosition = Vector2D(-1, -1); // means unset + Vector2D vecXWaylandPosition = Vector2D(-1, -1); // means unset + Vector2D vecSize = Vector2D(0, 0); + Vector2D vecPixelSize = Vector2D(0, 0); + Vector2D vecTransformedSize = Vector2D(0, 0); - bool primary = false; + bool primary = false; - uint64_t ID = -1; - PHLWORKSPACE activeWorkspace = nullptr; - PHLWORKSPACE activeSpecialWorkspace = nullptr; - float setScale = 1; // scale set by cfg - float scale = 1; // real scale + uint64_t ID = -1; + PHLWORKSPACE activeWorkspace = nullptr; + PHLWORKSPACE activeSpecialWorkspace = nullptr; + float setScale = 1; // scale set by cfg + float scale = 1; // real scale - std::string szName = ""; - std::string szDescription = ""; - std::string szShortDescription = ""; + std::string szName = ""; + std::string szDescription = ""; + std::string szShortDescription = ""; - Vector2D vecReservedTopLeft = Vector2D(0, 0); - Vector2D vecReservedBottomRight = Vector2D(0, 0); + Vector2D vecReservedTopLeft = Vector2D(0, 0); + Vector2D vecReservedBottomRight = Vector2D(0, 0); - drmModeModeInfo customDrmMode = {}; + drmModeModeInfo customDrmMode = {}; - CMonitorState state; + CMonitorState state; + CDamageRing damage; - // WLR stuff - wlr_damage_ring damage; wlr_output* output = nullptr; float refreshRate = 60; int framesToSkip = 0; diff --git a/src/includes.hpp b/src/includes.hpp index 87bd21f8..afec078a 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -53,7 +53,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index d44f4cd5..b783ab81 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1246,7 +1246,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { clock_gettime(CLOCK_MONOTONIC, &now); // check the damage - bool hasChanged = pMonitor->output->needs_frame || pixman_region32_not_empty(&pMonitor->damage.current); + bool hasChanged = pMonitor->output->needs_frame || pMonitor->damage.hasChanged(); if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0) return; @@ -1414,7 +1414,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->state.wlr()->tearing_page_flip = shouldTear; if (!pMonitor->state.commit()) { - wlr_damage_ring_add_whole(&pMonitor->damage); + pMonitor->damage.damageEntire(); return; } @@ -2245,7 +2245,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR // updato wlroots g_pCompositor->arrangeMonitors(); - wlr_damage_ring_set_bounds(&pMonitor->damage, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y); + pMonitor->damage.setSize(pMonitor->vecTransformedSize); // Set scale for all surfaces on this monitor, needed for some clients // but not on unsafe state to avoid crashes @@ -2609,13 +2609,15 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return true; } + int bufferAge = 0; + if (!buffer) { if (!wlr_output_configure_primary_swapchain(pMonitor->output, pMonitor->state.wlr(), &pMonitor->output->swapchain)) { Debug::log(ERR, "Failed to configure primary swapchain for {}", pMonitor->szName); return false; } - m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, nullptr); + m_pCurrentWlrBuffer = wlr_swapchain_acquire(pMonitor->output->swapchain, &bufferAge); if (!m_pCurrentWlrBuffer) { Debug::log(ERR, "Failed to acquire swapchain buffer for {}", pMonitor->szName); return false; @@ -2634,8 +2636,10 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode return false; } - if (mode == RENDER_MODE_NORMAL) - wlr_damage_ring_rotate_buffer(&pMonitor->damage, m_pCurrentWlrBuffer, damage.pixman()); + if (mode == RENDER_MODE_NORMAL) { + damage = pMonitor->damage.getBufferDamage(bufferAge); + pMonitor->damage.rotate(); + } m_pCurrentRenderbuffer->bind(); if (simple)