mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-26 04:45:58 +01:00
Feat: Introduce render_ahead_of_time (#1863)
This commit is contained in:
parent
b3a70b565e
commit
a80f8f257f
7 changed files with 312 additions and 230 deletions
|
@ -86,6 +86,8 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["misc:hide_cursor_on_touch"].intValue = 1;
|
configValues["misc:hide_cursor_on_touch"].intValue = 1;
|
||||||
configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
|
configValues["misc:mouse_move_focuses_monitor"].intValue = 1;
|
||||||
configValues["misc:suppress_portal_warnings"].intValue = 0;
|
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:int"].intValue = 0;
|
||||||
configValues["debug:log_damage"].intValue = 0;
|
configValues["debug:log_damage"].intValue = 0;
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include <cairo/cairo.h>
|
#include <cairo/cairo.h>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class CHyprRenderer;
|
||||||
|
|
||||||
class CHyprMonitorDebugOverlay {
|
class CHyprMonitorDebugOverlay {
|
||||||
public:
|
public:
|
||||||
int draw(int offset);
|
int draw(int offset);
|
||||||
|
@ -23,6 +25,8 @@ class CHyprMonitorDebugOverlay {
|
||||||
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
std::chrono::high_resolution_clock::time_point m_tpLastFrame;
|
||||||
CMonitor* m_pMonitor = nullptr;
|
CMonitor* m_pMonitor = nullptr;
|
||||||
wlr_box m_wbLastDrawnBox;
|
wlr_box m_wbLastDrawnBox;
|
||||||
|
|
||||||
|
friend class CHyprRenderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CHyprDebugOverlay {
|
class CHyprDebugOverlay {
|
||||||
|
@ -41,6 +45,7 @@ class CHyprDebugOverlay {
|
||||||
CTexture m_tTexture;
|
CTexture m_tTexture;
|
||||||
|
|
||||||
friend class CHyprMonitorDebugOverlay;
|
friend class CHyprMonitorDebugOverlay;
|
||||||
|
friend class CHyprRenderer;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay;
|
inline std::unique_ptr<CHyprDebugOverlay> g_pDebugOverlay;
|
|
@ -126,224 +126,37 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||||
if (!PMONITOR->m_bEnabled)
|
if (!PMONITOR->m_bEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static std::chrono::high_resolution_clock::time_point startRender = std::chrono::high_resolution_clock::now();
|
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
|
||||||
static std::chrono::high_resolution_clock::time_point startRenderOverlay = std::chrono::high_resolution_clock::now();
|
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
|
||||||
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;
|
PMONITOR->lastPresentationTimer.reset();
|
||||||
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 (*PENABLERAT) {
|
||||||
|
if (!PMONITOR->RATScheduled) {
|
||||||
if (!*PDAMAGEBLINK)
|
// render
|
||||||
damageBlinkCleanup = 0;
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(PMONITOR->ID);
|
|
||||||
|
|
||||||
if (PMONITOR->framesToSkip > 10)
|
PMONITOR->RATScheduled = false;
|
||||||
PMONITOR->framesToSkip = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// checks //
|
const auto& [avg, max, min] = g_pHyprRenderer->getRenderTimes(PMONITOR);
|
||||||
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();
|
|
||||||
|
|
||||||
g_pConfigManager->dispatchExecOnce(); // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
|
if (max + *PRATSAFE > 1000.0 / PMONITOR->refreshRate)
|
||||||
|
|
||||||
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)) {
|
|
||||||
return;
|
return;
|
||||||
} else if (g_pHyprRenderer->m_pLastScanout) {
|
|
||||||
Debug::log(LOG, "Left a direct scanout.");
|
|
||||||
g_pHyprRenderer->m_pLastScanout = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EMIT_HOOK_EVENT("preRender", PMONITOR);
|
const auto MSLEFT = 1000.0 / PMONITOR->refreshRate - PMONITOR->lastPresentationTimer.getMillis();
|
||||||
|
|
||||||
timespec now;
|
PMONITOR->RATScheduled = true;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
|
||||||
|
|
||||||
// check the damage
|
const auto ESTRENDERTIME = std::ceil(avg + *PRATSAFE);
|
||||||
pixman_region32_t damage;
|
const auto TIMETOSLEEP = std::floor(MSLEFT - ESTRENDERTIME);
|
||||||
bool hasChanged;
|
|
||||||
pixman_region32_init(&damage);
|
|
||||||
|
|
||||||
if (*PDAMAGETRACKINGMODE == -1) {
|
if (MSLEFT < 1 || MSLEFT < ESTRENDERTIME)
|
||||||
Debug::log(CRIT, "Damage tracking mode -1 ????");
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
return;
|
else
|
||||||
}
|
wl_event_source_timer_update(PMONITOR->renderTimer, TIMETOSLEEP);
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
static auto* const PBLURENABLED = &g_pConfigManager->getConfigValuePtr("decoration:blur")->intValue;
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
|
|
||||||
// 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"
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,12 @@
|
||||||
|
|
||||||
#include "../Compositor.hpp"
|
#include "../Compositor.hpp"
|
||||||
|
|
||||||
|
int ratHandler(void* data) {
|
||||||
|
g_pHyprRenderer->renderMonitor((CMonitor*)data);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void CMonitor::onConnect(bool noRule) {
|
void CMonitor::onConnect(bool noRule) {
|
||||||
hyprListener_monitorDestroy.removeCallback();
|
hyprListener_monitorDestroy.removeCallback();
|
||||||
hyprListener_monitorFrame.removeCallback();
|
hyprListener_monitorFrame.removeCallback();
|
||||||
|
@ -156,10 +162,17 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
g_pCompositor->setActiveMonitor(this);
|
g_pCompositor->setActiveMonitor(this);
|
||||||
|
|
||||||
|
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMonitor::onDisconnect() {
|
void CMonitor::onDisconnect() {
|
||||||
|
|
||||||
|
if (renderTimer) {
|
||||||
|
wl_event_source_remove(renderTimer);
|
||||||
|
renderTimer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
|
if (!m_bEnabled || g_pCompositor->m_bIsShuttingDown)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include "Timer.hpp"
|
||||||
|
|
||||||
struct SMonitorRule;
|
struct SMonitorRule;
|
||||||
|
|
||||||
|
@ -45,6 +46,10 @@ class CMonitor {
|
||||||
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
bool pendingFrame = false; // if we schedule a frame during rendering, reschedule it after
|
||||||
bool renderingActive = false;
|
bool renderingActive = false;
|
||||||
|
|
||||||
|
wl_event_source* renderTimer = nullptr; // for RAT
|
||||||
|
bool RATScheduled = false;
|
||||||
|
CTimer lastPresentationTimer;
|
||||||
|
|
||||||
// mirroring
|
// mirroring
|
||||||
CMonitor* pMirrorOf = nullptr;
|
CMonitor* pMirrorOf = nullptr;
|
||||||
std::vector<CMonitor*> mirrors;
|
std::vector<CMonitor*> mirrors;
|
||||||
|
|
|
@ -740,6 +740,230 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
|
||||||
return true;
|
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) {
|
void CHyprRenderer::setWindowScanoutMode(CWindow* pWindow) {
|
||||||
if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked())
|
if (!g_pCompositor->m_sWLRLinuxDMABuf || g_pSessionLockManager->isSessionLocked())
|
||||||
return;
|
return;
|
||||||
|
@ -1528,3 +1752,21 @@ void CHyprRenderer::ensureCursorRenderingMode() {
|
||||||
bool CHyprRenderer::shouldRenderCursor() {
|
bool CHyprRenderer::shouldRenderCursor() {
|
||||||
return m_bHasARenderedCursor;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -31,33 +31,35 @@ struct SSessionLockSurface;
|
||||||
|
|
||||||
class CHyprRenderer {
|
class CHyprRenderer {
|
||||||
public:
|
public:
|
||||||
void renderAllClientsForMonitor(const int&, timespec*);
|
void renderMonitor(CMonitor* pMonitor);
|
||||||
void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
|
void renderAllClientsForMonitor(const int&, timespec*);
|
||||||
void arrangeLayersForMonitor(const int&);
|
void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
|
||||||
void damageSurface(wlr_surface*, double, double);
|
void arrangeLayersForMonitor(const int&);
|
||||||
void damageWindow(CWindow*);
|
void damageSurface(wlr_surface*, double, double);
|
||||||
void damageBox(wlr_box*);
|
void damageWindow(CWindow*);
|
||||||
void damageBox(const int& x, const int& y, const int& w, const int& h);
|
void damageBox(wlr_box*);
|
||||||
void damageRegion(pixman_region32_t*);
|
void damageBox(const int& x, const int& y, const int& w, const int& h);
|
||||||
void damageMonitor(CMonitor*);
|
void damageRegion(pixman_region32_t*);
|
||||||
void damageMirrorsWith(CMonitor*, pixman_region32_t*);
|
void damageMonitor(CMonitor*);
|
||||||
bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
|
void damageMirrorsWith(CMonitor*, pixman_region32_t*);
|
||||||
bool shouldRenderWindow(CWindow*, CMonitor*);
|
bool applyMonitorRule(CMonitor*, SMonitorRule*, bool force = false);
|
||||||
bool shouldRenderWindow(CWindow*);
|
bool shouldRenderWindow(CWindow*, CMonitor*);
|
||||||
void ensureCursorRenderingMode();
|
bool shouldRenderWindow(CWindow*);
|
||||||
bool shouldRenderCursor();
|
void ensureCursorRenderingMode();
|
||||||
void calculateUVForSurface(CWindow*, wlr_surface*, bool main = false);
|
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_bWindowRequestedCursorHide = false;
|
||||||
bool m_bBlockSurfaceFeedback = false;
|
bool m_bBlockSurfaceFeedback = false;
|
||||||
bool m_bRenderingSnapshot = false;
|
bool m_bRenderingSnapshot = false;
|
||||||
CWindow* m_pLastScanout = nullptr;
|
CWindow* m_pLastScanout = nullptr;
|
||||||
CMonitor* m_pMostHzMonitor = nullptr;
|
CMonitor* m_pMostHzMonitor = nullptr;
|
||||||
|
|
||||||
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
|
DAMAGETRACKINGMODES damageTrackingModeFromStr(const std::string&);
|
||||||
|
|
||||||
bool attemptDirectScanout(CMonitor*);
|
bool attemptDirectScanout(CMonitor*);
|
||||||
void setWindowScanoutMode(CWindow*);
|
void setWindowScanoutMode(CWindow*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
|
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
|
||||||
|
|
Loading…
Reference in a new issue