aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorVaxry <[email protected]>2023-03-24 19:23:16 +0000
committerGitHub <[email protected]>2023-03-24 19:23:16 +0000
commita80f8f257f05480a3a91e9da14715cb160ed2e0a (patch)
tree6b81c6bdb87b3f472a88224b67b0576d84e8ad99
parentb3a70b565e67ebf00bcf4ecbae54fc96e527828e (diff)
downloadHyprland-a80f8f257f05480a3a91e9da14715cb160ed2e0a.tar.gz
Hyprland-a80f8f257f05480a3a91e9da14715cb160ed2e0a.zip
Feat: Introduce render_ahead_of_time (#1863)
-rw-r--r--src/config/ConfigManager.cpp2
-rw-r--r--src/debug/HyprDebugOverlay.hpp5
-rw-r--r--src/events/Monitors.cpp225
-rw-r--r--src/helpers/Monitor.cpp13
-rw-r--r--src/helpers/Monitor.hpp5
-rw-r--r--src/render/Renderer.cpp242
-rw-r--r--src/render/Renderer.hpp50
7 files changed, 312 insertions, 230 deletions
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 94e49d20..37673014 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -86,6 +86,8 @@ void CConfigManager::setDefaultVars() {
configValues["misc:hide_cursor_on_touch"].intValue = 1;
configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
configValues["misc:suppress_portal_warnings"].intValue = 0;
+ configValues["misc:render_ahead_of_time"].intValue = 0;
+ configValues["misc:render_ahead_safezone"].intValue = 1;
configValues["debug:int"].intValue = 0;
configValues["debug:log_damage"].intValue = 0;
diff --git a/src/debug/HyprDebugOverlay.hpp b/src/debug/HyprDebugOverlay.hpp
index 67f188d2..03027018 100644
--- a/src/debug/HyprDebugOverlay.hpp
+++ b/src/debug/HyprDebugOverlay.hpp
@@ -7,6 +7,8 @@
#include <cairo/cairo.h>
#include <unordered_map>
+class CHyprRenderer;
+
class CHyprMonitorDebugOverlay {
public:
int draw(int offset);
@@ -23,6 +25,8 @@ class CHyprMonitorDebugOverlay {
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
CMonitor* m_pMonitor = nullptr;
wlr_box m_wbLastDrawnBox;
+
+ friend class CHyprRenderer;
};
class CHyprDebugOverlay {
@@ -41,6 +45,7 @@ class CHyprDebugOverlay {
CTexture m_tTexture;
friend class CHyprMonitorDebugOverlay;
+ friend class CHyprRenderer;
};
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay; \ No newline at end of file
diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp
index 0ea64e67..ae5095aa 100644
--- a/src/events/Monitors.cpp
+++ b/src/events/Monitors.cpp
@@ -126,224 +126,37 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (!PMONITOR->m_bEnabled)
return;
- static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now();
- static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now();
- static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
+ static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
+ static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
- static auto* const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
- static auto* const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("debug:damage_tracking")->intValue;
- static auto* const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue;
- static auto* const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue;
- static auto* const PVFR = &g_pConfigManager->getConfigValuePtr("misc:vfr")->intValue;
+ PMONITOR->lastPresentationTimer.reset();
- static int damageBlinkCleanup = 0; // because double-buffered
-
- if (!*PDAMAGEBLINK)
- damageBlinkCleanup = 0;
-
- if (*PDEBUGOVERLAY == 1) {
- startRender = std::chrono::high_resolution_clock::now();
- g_pDebugOverlay->frameData(PMONITOR);
- }
-
- if (PMONITOR->framesToSkip > 0) {
- PMONITOR->framesToSkip -= 1;
-
- if (!PMONITOR->noFrameSchedule)
- g_pCompositor->scheduleFrameForMonitor(PMONITOR);
- else {
- Debug::log(LOG, "NoFrameSchedule hit for %s.", PMONITOR->szName.c_str());
+ if (*PENABLERAT) {
+ if (!PMONITOR->RATScheduled) {
+ // render
+ g_pHyprRenderer->renderMonitor(PMONITOR);
}
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
- if (PMONITOR->framesToSkip > 10)
- PMONITOR->framesToSkip = 0;
- return;
- }
+ PMONITOR->RATScheduled = false;
- // checks //
- if (PMONITOR->ID == g_pHyprRenderer->m_pMostHzMonitor->ID ||
- *PVFR == 1) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that
- g_pCompositor->sanityCheckWorkspaces();
+ const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR);
- g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
-
- if (g_pConfigManager->m_bWantsMonitorReload)
- g_pConfigManager->performMonitorReload();
-
- g_pHyprRenderer->ensureCursorRenderingMode(); // so that the cursor gets hidden/shown if the user requested timeouts
- }
- // //
-
- if (PMONITOR->scheduledRecalc) {
- PMONITOR->scheduledRecalc = false;
- g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
- }
-
- // Direct scanout first
- if (!*PNODIRECTSCANOUT) {
- if (g_pHyprRenderer->attemptDirectScanout(PMONITOR)) {
+ if (max + *PRATSAFE > 1000.0 / PMONITOR->refreshRate)
return;
- } else if (g_pHyprRenderer->m_pLastScanout) {
- Debug::log(LOG, "Left a direct scanout.");
- g_pHyprRenderer->m_pLastScanout = nullptr;
- }
- }
-
- EMIT_HOOK_EVENT("preRender", PMONITOR);
-
- timespec now;
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- // check the damage
- pixman_region32_t damage;
- bool hasChanged;
- pixman_region32_init(&damage);
-
- if (*PDAMAGETRACKINGMODE == -1) {
- Debug::log(CRIT, "Damage tracking mode -1 ????");
- return;
- }
-
- if (!wlr_output_damage_attach_render(PMONITOR->damage, &hasChanged, &damage)) {
- Debug::log(ERR, "Couldn't attach render to display %s ???", PMONITOR->szName.c_str());
- return;
- }
-
- PMONITOR->renderingActive = true;
-
- // we need to cleanup fading out when rendering the appropriate context
- g_pCompositor->cleanupFadingOut(PMONITOR->ID);
-
- if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && PMONITOR->forceFullFrames == 0 && damageBlinkCleanup == 0) {
- pixman_region32_fini(&damage);
- wlr_output_rollback(PMONITOR->output);
-
- if (*PDAMAGEBLINK || *PVFR == 0)
- g_pCompositor->scheduleFrameForMonitor(PMONITOR);
-
- PMONITOR->renderingActive = false;
-
- return;
- }
-
- // if we have no tracking or full tracking, invalidate the entire monitor
- if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || PMONITOR->forceFullFrames > 0 || damageBlinkCleanup > 0 ||
- PMONITOR->isMirror() /* why??? */) {
- pixman_region32_union_rect(&damage, &damage, 0, 0, (int)PMONITOR->vecTransformedSize.x * 10, (int)PMONITOR->vecTransformedSize.y * 10); // wot?
- pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
- } else {
- static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
-
- // if we use blur we need to expand the damage for proper blurring
- if (*PBLURENABLED == 1) {
- // TODO: can this be optimized?
- static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
- static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
- const auto BLURRADIUS =
- *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
-
- // now, prep the damage, get the extended damage region
- wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring
-
- pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
-
- wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring 2
- } else {
- pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
- }
- }
-
- if (PMONITOR->forceFullFrames > 0) {
- PMONITOR->forceFullFrames -= 1;
- if (PMONITOR->forceFullFrames > 10)
- PMONITOR->forceFullFrames = 0;
- }
+ const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis();
- // TODO: this is getting called with extents being 0,0,0,0 should it be?
- // potentially can save on resources.
+ PMONITOR->RATScheduled = true;
- g_pHyprOpenGL->begin(PMONITOR, &damage);
+ const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE);
+ const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
- if (PMONITOR->isMirror()) {
- g_pHyprOpenGL->renderMirrored();
+ if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME)
+ g_pHyprRenderer->renderMonitor(PMONITOR);
+ else
+ wl_event_source_timer_update(PMONITOR->renderTimer, TIMETOSLEEP);
} else {
- g_pHyprOpenGL->clear(CColor(17.0 / 255.0, 17.0 / 255.0, 17.0 / 255.0, 1.0));
- g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
-
- g_pHyprRenderer->renderAllClientsForMonitor(PMONITOR->ID, &now);
-
- if (PMONITOR == g_pCompositor->m_pLastMonitor) {
- g_pHyprNotificationOverlay->draw(PMONITOR);
- g_pHyprError->draw();
- }
-
- // for drawing the debug overlay
- if (PMONITOR == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) {
- startRenderOverlay = std::chrono::high_resolution_clock::now();
- g_pDebugOverlay->draw();
- endRenderOverlay = std::chrono::high_resolution_clock::now();
- }
-
- if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
- wlr_box monrect = {0, 0, PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y};
- g_pHyprOpenGL->renderRect(&monrect, CColor(1.0, 0.0, 1.0, 100.0 / 255.0), 0);
- damageBlinkCleanup = 1;
- } else if (*PDAMAGEBLINK) {
- damageBlinkCleanup++;
- if (damageBlinkCleanup > 3)
- damageBlinkCleanup = 0;
- }
-
- if (wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y)) {
- wlr_output_render_software_cursors(PMONITOR->output, NULL);
- wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
- }
- }
-
- g_pHyprOpenGL->end();
-
- // calc frame damage
- pixman_region32_t frameDamage;
- pixman_region32_init(&frameDamage);
-
- const auto TRANSFORM = wlr_output_transform_invert(PMONITOR->output->transform);
- wlr_region_transform(&frameDamage, &g_pHyprOpenGL->m_rOriginalDamageRegion, TRANSFORM, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
-
- if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR)
- pixman_region32_union_rect(&frameDamage, &frameDamage, 0, 0, (int)PMONITOR->vecTransformedSize.x, (int)PMONITOR->vecTransformedSize.y);
-
- if (*PDAMAGEBLINK)
- pixman_region32_union(&frameDamage, &frameDamage, &damage);
-
- wlr_output_set_damage(PMONITOR->output, &frameDamage);
-
- if (!PMONITOR->mirrors.empty())
- g_pHyprRenderer->damageMirrorsWith(PMONITOR, &frameDamage);
-
- pixman_region32_fini(&frameDamage);
- pixman_region32_fini(&damage);
-
- PMONITOR->renderingActive = false;
-
- if (!wlr_output_commit(PMONITOR->output))
- return;
-
- if (*PDAMAGEBLINK || *PVFR == 0 || PMONITOR->pendingFrame)
- g_pCompositor->scheduleFrameForMonitor(PMONITOR);
-
- PMONITOR->pendingFrame = false;
-
- if (*PDEBUGOVERLAY == 1) {
- const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
- g_pDebugOverlay->renderData(PMONITOR, µs);
- if (PMONITOR == g_pCompositor->m_vMonitors.front().get()) {
- const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f;
- g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µsNoOverlay);
- } else {
- g_pDebugOverlay->renderDataNoOverlay(PMONITOR, µs);
- }
+ g_pHyprRenderer->renderMonitor(PMONITOR);
}
}
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 6ad60dfa..d8bae3a8 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -2,6 +2,12 @@
#include "../Compositor.hpp"
+int ratHandler(void* data) {
+ g_pHyprRenderer->renderMonitor((CMonitor*)data);
+
+ return 1;
+}
+
void CMonitor::onConnect(bool noRule) {
hyprListener_monitorDestroy.removeCallback();
hyprListener_monitorFrame.removeCallback();
@@ -156,10 +162,17 @@ void CMonitor::onConnect(bool noRule) {
if (!found)
g_pCompositor->setActiveMonitor(this);
+
+ renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
}
void CMonitor::onDisconnect() {
+ if (renderTimer) {
+ wl_event_source_remove(renderTimer);
+ renderTimer = nullptr;
+ }
+
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
return;
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 9ad6d917..0707d79f 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -6,6 +6,7 @@
#include <vector>
#include <array>
#include <memory>
+#include "Timer.hpp"
struct SMonitorRule;
@@ -45,6 +46,10 @@ class CMonitor {
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
bool renderingActive = false;
+ wl_event_source* renderTimer = nullptr; // for RAT
+ bool RATScheduled = false;
+ CTimer lastPresentationTimer;
+
// mirroring
CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors;
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index fcda60cc..a5a576d3 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -740,6 +740,230 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
return true;
}
+void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
+ static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now();
+ static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now();
+ static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
+
+ static auto* const PDEBUGOVERLAY = &g_pConfigManager->getConfigValuePtr("debug:overlay")->intValue;
+ static auto* const PDAMAGETRACKINGMODE = &g_pConfigManager->getConfigValuePtr("debug:damage_tracking")->intValue;
+ static auto* const PDAMAGEBLINK = &g_pConfigManager->getConfigValuePtr("debug:damage_blink")->intValue;
+ static auto* const PNODIRECTSCANOUT = &g_pConfigManager->getConfigValuePtr("misc:no_direct_scanout")->intValue;
+ static auto* const PVFR = &g_pConfigManager->getConfigValuePtr("misc:vfr")->intValue;
+
+ static int damageBlinkCleanup = 0; // because double-buffered
+
+ if (!*PDAMAGEBLINK)
+ damageBlinkCleanup = 0;
+
+ startRender = std::chrono::high_resolution_clock::now();
+
+ if (*PDEBUGOVERLAY == 1) {
+ g_pDebugOverlay->frameData(pMonitor);
+ }
+
+ if (pMonitor->framesToSkip > 0) {
+ pMonitor->framesToSkip -= 1;
+
+ if (!pMonitor->noFrameSchedule)
+ g_pCompositor->scheduleFrameForMonitor(pMonitor);
+ else {
+ Debug::log(LOG, "NoFrameSchedule hit for %s.", pMonitor->szName.c_str());
+ }
+ g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
+
+ if (pMonitor->framesToSkip > 10)
+ pMonitor->framesToSkip = 0;
+ return;
+ }
+
+ // checks //
+ if (pMonitor->ID == m_pMostHzMonitor->ID ||
+ *PVFR == 1) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that
+ g_pCompositor->sanityCheckWorkspaces();
+
+ g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
+
+ if (g_pConfigManager->m_bWantsMonitorReload)
+ g_pConfigManager->performMonitorReload();
+
+ ensureCursorRenderingMode(); // so that the cursor gets hidden/shown if the user requested timeouts
+ }
+ // //
+
+ if (pMonitor->scheduledRecalc) {
+ pMonitor->scheduledRecalc = false;
+ g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
+ }
+
+ // Direct scanout first
+ if (!*PNODIRECTSCANOUT) {
+ if (attemptDirectScanout(pMonitor)) {
+ return;
+ } else if (m_pLastScanout) {
+ Debug::log(LOG, "Left a direct scanout.");
+ m_pLastScanout = nullptr;
+ }
+ }
+
+ EMIT_HOOK_EVENT("preRender", pMonitor);
+
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ // check the damage
+ pixman_region32_t damage;
+ bool hasChanged;
+ pixman_region32_init(&damage);
+
+ if (*PDAMAGETRACKINGMODE == -1) {
+ Debug::log(CRIT, "Damage tracking mode -1 ????");
+ return;
+ }
+
+ if (!wlr_output_damage_attach_render(pMonitor->damage, &hasChanged, &damage)) {
+ Debug::log(ERR, "Couldn't attach render to display %s ???", pMonitor->szName.c_str());
+ return;
+ }
+
+ pMonitor->renderingActive = true;
+
+ // we need to cleanup fading out when rendering the appropriate context
+ g_pCompositor->cleanupFadingOut(pMonitor->ID);
+
+ if (!hasChanged && *PDAMAGETRACKINGMODE != DAMAGE_TRACKING_NONE && pMonitor->forceFullFrames == 0 && damageBlinkCleanup == 0) {
+ pixman_region32_fini(&damage);
+ wlr_output_rollback(pMonitor->output);
+
+ if (*PDAMAGEBLINK || *PVFR == 0)
+ g_pCompositor->scheduleFrameForMonitor(pMonitor);
+
+ pMonitor->renderingActive = false;
+
+ return;
+ }
+
+ // if we have no tracking or full tracking, invalidate the entire monitor
+ if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR || pMonitor->forceFullFrames > 0 || damageBlinkCleanup > 0 ||
+ pMonitor->isMirror() /* why??? */) {
+ pixman_region32_union_rect(&damage, &damage, 0, 0, (int)pMonitor->vecTransformedSize.x * 10, (int)pMonitor->vecTransformedSize.y * 10); // wot?
+
+ pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
+ } else {
+ static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
+
+ // if we use blur we need to expand the damage for proper blurring
+ if (*PBLURENABLED == 1) {
+ // TODO: can this be optimized?
+ static auto* const PBLURSIZE = &g_pConfigManager->getConfigValuePtr("decoration:blur_size")->intValue;
+ static auto* const PBLURPASSES = &g_pConfigManager->getConfigValuePtr("decoration:blur_passes")->intValue;
+ const auto BLURRADIUS =
+ *PBLURPASSES > 10 ? pow(2, 15) : std::clamp(*PBLURSIZE, (int64_t)1, (int64_t)40) * pow(2, *PBLURPASSES); // is this 2^pass? I don't know but it works... I think.
+
+ // now, prep the damage, get the extended damage region
+ wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring
+
+ pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
+
+ wlr_region_expand(&damage, &damage, BLURRADIUS); // expand for proper blurring 2
+ } else {
+ pixman_region32_copy(&g_pHyprOpenGL->m_rOriginalDamageRegion, &damage);
+ }
+ }
+
+ if (pMonitor->forceFullFrames > 0) {
+ pMonitor->forceFullFrames -= 1;
+ if (pMonitor->forceFullFrames > 10)
+ pMonitor->forceFullFrames = 0;
+ }
+
+ // TODO: this is getting called with extents being 0,0,0,0 should it be?
+ // potentially can save on resources.
+
+ g_pHyprOpenGL->begin(pMonitor, &damage);
+
+ if (pMonitor->isMirror()) {
+ g_pHyprOpenGL->renderMirrored();
+ } else {
+ g_pHyprOpenGL->clear(CColor(17.0 / 255.0, 17.0 / 255.0, 17.0 / 255.0, 1.0));
+ g_pHyprOpenGL->clearWithTex(); // will apply the hypr "wallpaper"
+
+ renderAllClientsForMonitor(pMonitor->ID, &now);
+
+ if (pMonitor == g_pCompositor->m_pLastMonitor) {
+ g_pHyprNotificationOverlay->draw(pMonitor);
+ g_pHyprError->draw();
+ }
+
+ // for drawing the debug overlay
+ if (pMonitor == g_pCompositor->m_vMonitors.front().get() && *PDEBUGOVERLAY == 1) {
+ startRenderOverlay = std::chrono::high_resolution_clock::now();
+ g_pDebugOverlay->draw();
+ endRenderOverlay = std::chrono::high_resolution_clock::now();
+ }
+
+ if (*PDAMAGEBLINK && damageBlinkCleanup == 0) {
+ wlr_box monrect = {0, 0, pMonitor->vecTransformedSize.x, pMonitor->vecTransformedSize.y};
+ g_pHyprOpenGL->renderRect(&monrect, CColor(1.0, 0.0, 1.0, 100.0 / 255.0), 0);
+ damageBlinkCleanup = 1;
+ } else if (*PDAMAGEBLINK) {
+ damageBlinkCleanup++;
+ if (damageBlinkCleanup > 3)
+ damageBlinkCleanup = 0;
+ }
+
+ if (wlr_renderer_begin(g_pCompositor->m_sWLRRenderer, pMonitor->vecPixelSize.x, pMonitor->vecPixelSize.y)) {
+ wlr_output_render_software_cursors(pMonitor->output, NULL);
+ wlr_renderer_end(g_pCompositor->m_sWLRRenderer);
+ }
+ }
+
+ g_pHyprOpenGL->end();
+
+ // calc frame damage
+ pixman_region32_t frameDamage;
+ pixman_region32_init(&frameDamage);
+
+ const auto TRANSFORM = wlr_output_transform_invert(pMonitor->output->transform);
+ wlr_region_transform(&frameDamage, &g_pHyprOpenGL->m_rOriginalDamageRegion, TRANSFORM, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
+
+ if (*PDAMAGETRACKINGMODE == DAMAGE_TRACKING_NONE || *PDAMAGETRACKINGMODE == DAMAGE_TRACKING_MONITOR)
+ pixman_region32_union_rect(&frameDamage, &frameDamage, 0, 0, (int)pMonitor->vecTransformedSize.x, (int)pMonitor->vecTransformedSize.y);
+
+ if (*PDAMAGEBLINK)
+ pixman_region32_union(&frameDamage, &frameDamage, &damage);
+
+ wlr_output_set_damage(pMonitor->output, &frameDamage);
+
+ if (!pMonitor->mirrors.empty())
+ g_pHyprRenderer->damageMirrorsWith(pMonitor, &frameDamage);
+
+ pixman_region32_fini(&frameDamage);
+ pixman_region32_fini(&damage);
+
+ pMonitor->renderingActive = false;
+
+ if (!wlr_output_commit(pMonitor->output))
+ return;
+
+ if (*PDAMAGEBLINK || *PVFR == 0 || pMonitor->pendingFrame)
+ g_pCompositor->scheduleFrameForMonitor(pMonitor);
+
+ pMonitor->pendingFrame = false;
+
+ const float µs = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - startRender).count() / 1000.f;
+ g_pDebugOverlay->renderData(pMonitor, µs);
+
+ if (*PDEBUGOVERLAY == 1) {
+ if (pMonitor == g_pCompositor->m_vMonitors.front().get()) {
+ const float µsNoOverlay = µs - std::chrono::duration_cast<std::chrono::nanoseconds>(endRenderOverlay - startRenderOverlay).count() / 1000.f;
+ g_pDebugOverlay->renderDataNoOverlay(pMonitor, µsNoOverlay);
+ } else {
+ g_pDebugOverlay->renderDataNoOverlay(pMonitor, µs);
+ }
+ }
+}
+
void CHyprRenderer::setWindowScanoutMode(CWindow* pWindow) {
if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked())
return;
@@ -1528,3 +1752,21 @@ void CHyprRenderer::ensureCursorRenderingMode() {
bool CHyprRenderer::shouldRenderCursor() {
return m_bHasARenderedCursor;
}
+
+std::tuple<float, float, float> CHyprRenderer::getRenderTimes(CMonitor* pMonitor) {
+ const auto POVERLAY = &g_pDebugOverlay->m_mMonitorOverlays[pMonitor];
+
+ float avgRenderTime = 0;
+ float maxRenderTime = 0;
+ float minRenderTime = 9999;
+ for (auto& rt : POVERLAY->m_dLastRenderTimes) {
+ if (rt > maxRenderTime)
+ maxRenderTime = rt;
+ if (rt < minRenderTime)
+ minRenderTime = rt;
+ avgRenderTime += rt;
+ }
+ avgRenderTime /= POVERLAY->m_dLastRenderTimes.size() == 0 ? 1 : POVERLAY->m_dLastRenderTimes.size();
+
+ return std::make_tuple<>(avgRenderTime, maxRenderTime, minRenderTime);
+}
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index 9f2456f8..4ce0f6dc 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -31,33 +31,35 @@ struct SSessionLockSurface;
class CHyprRenderer {
public:
- void renderAllClientsForMonitor(const int&, timespec*);
- void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
- void arrangeLayersForMonitor(const int&);
- void damageSurface(wlr_surface*, double, double);
- void damageWindow(CWindow*);
- void damageBox(wlr_box*);
- void damageBox(const int& x, const int& y, const int& w, const int& h);
- void damageRegion(pixman_region32_t*);
- void damageMonitor(CMonitor*);
- void damageMirrorsWith(CMonitor*, pixman_region32_t*);
- bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
- bool shouldRenderWindow(CWindow*, CMonitor*);
- bool shouldRenderWindow(CWindow*);
- void ensureCursorRenderingMode();
- bool shouldRenderCursor();
- void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false);
+ void renderMonitor(CMonitor* pMonitor);
+ void renderAllClientsForMonitor(const int&, timespec*);
+ void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
+ void arrangeLayersForMonitor(const int&);
+ void damageSurface(wlr_surface*, double, double);
+ void damageWindow(CWindow*);
+ void damageBox(wlr_box*);
+ void damageBox(const int& x, const int& y, const int& w, const int& h);
+ void damageRegion(pixman_region32_t*);
+ void damageMonitor(CMonitor*);
+ void damageMirrorsWith(CMonitor*, pixman_region32_t*);
+ bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
+ bool shouldRenderWindow(CWindow*, CMonitor*);
+ bool shouldRenderWindow(CWindow*);
+ void ensureCursorRenderingMode();
+ bool shouldRenderCursor();
+ void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false);
+ std::tuple<float, float, float> getRenderTimes(CMonitor* pMonitor); // avg max min
- bool m_bWindowRequestedCursorHide = false;
- bool m_bBlockSurfaceFeedback = false;
- bool m_bRenderingSnapshot = false;
- CWindow* m_pLastScanout = nullptr;
- CMonitor* m_pMostHzMonitor = nullptr;
+ bool m_bWindowRequestedCursorHide = false;
+ bool m_bBlockSurfaceFeedback = false;
+ bool m_bRenderingSnapshot = false;
+ CWindow* m_pLastScanout = nullptr;
+ CMonitor* m_pMostHzMonitor = nullptr;
- DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
+ DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
- bool attemptDirectScanout(CMonitor*);
- void setWindowScanoutMode(CWindow*);
+ bool attemptDirectScanout(CMonitor*);
+ void setWindowScanoutMode(CWindow*);
private:
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);