Feat: Introduce render_ahead_of_time (#1863)

This commit is contained in:
Vaxry
2023-03-24 19:23:16 +00:00
committed by GitHub
parent b3a70b565e
commit a80f8f257f
7 changed files with 312 additions and 230 deletions

View File

@@ -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);
}