From 640d1618519d42dd592f7af5e9984ad52eb8b820 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:52:19 +0100 Subject: renderer: Explicit sync fixes (#7151) Enables explicit sync by default for most platforms `misc:no_direct_scanout` -> `render:direct_scanout` --- src/render/Renderer.cpp | 187 +++++++++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 66 deletions(-) (limited to 'src/render/Renderer.cpp') diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 127ae187..7794d476 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -1,9 +1,12 @@ #include "Renderer.hpp" #include "../Compositor.hpp" #include "../helpers/math/Math.hpp" +#include "../helpers/ScopeGuard.hpp" +#include "../helpers/sync/SyncReleaser.hpp" #include #include #include +#include #include "../config/ConfigValue.hpp" #include "../managers/CursorManager.hpp" #include "../managers/PointerManager.hpp" @@ -115,8 +118,8 @@ static void renderSurface(SP surface, int x, int y, void* da return; // explicit sync: wait for the timeline, if any - if (surface->syncobj && surface->syncobj->acquireTimeline) { - if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->acquireTimeline->timeline, surface->syncobj->acquirePoint)) { + if (surface->syncobj && surface->syncobj->current.acquireTimeline) { + if (!g_pHyprOpenGL->waitForTimelinePoint(surface->syncobj->current.acquireTimeline->timeline, surface->syncobj->current.acquirePoint)) { Debug::log(ERR, "Renderer: failed to wait for explicit timeline"); return; } @@ -1095,7 +1098,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { static auto PDEBUGOVERLAY = CConfigValue("debug:overlay"); static auto PDAMAGETRACKINGMODE = CConfigValue("debug:damage_tracking"); static auto PDAMAGEBLINK = CConfigValue("debug:damage_blink"); - static auto PNODIRECTSCANOUT = CConfigValue("misc:no_direct_scanout"); + static auto PDIRECTSCANOUT = CConfigValue("render:direct_scanout"); static auto PVFR = CConfigValue("misc:vfr"); static auto PZOOMFACTOR = CConfigValue("cursor:zoom_factor"); static auto PANIMENABLED = CConfigValue("animations:enabled"); @@ -1195,7 +1198,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { pMonitor->tearingState.activelyTearing = shouldTear; - if (!*PNODIRECTSCANOUT && !shouldTear) { + if (*PDIRECTSCANOUT && !shouldTear) { if (pMonitor->attemptDirectScanout()) { return; } else if (!pMonitor->lastScanout.expired()) { @@ -1403,59 +1406,62 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) { } bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) { - static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); - // apply timelines for explicit sync + // save inFD otherwise reset will reset it + auto inFD = pMonitor->output->state->state().explicitInFence; pMonitor->output->state->resetExplicitFences(); + if (inFD >= 0) + pMonitor->output->state->setExplicitInFence(inFD); - bool anyExplicit = !explicitPresented.empty(); - if (anyExplicit) { - Debug::log(TRACE, "Explicit sync presented begin"); - auto inFence = pMonitor->inTimeline->exportAsSyncFileFD(pMonitor->lastWaitPoint); - if (inFence < 0) - Debug::log(ERR, "Export lastWaitPoint {} as sync explicitInFence failed", pMonitor->lastWaitPoint); - - pMonitor->output->state->setExplicitInFence(inFence); - - for (auto& e : explicitPresented) { - Debug::log(TRACE, "Explicit sync presented releasePoint {}", e->syncobj && e->syncobj->releaseTimeline ? e->syncobj->releasePoint : -1); - if (!e->syncobj || !e->syncobj->releaseTimeline) - continue; - e->syncobj->releaseTimeline->timeline->transfer(pMonitor->outTimeline, pMonitor->commitSeq, e->syncobj->releasePoint); + bool ok = pMonitor->state.commit(); + if (!ok) { + if (inFD >= 0) { + Debug::log(TRACE, "Monitor state commit failed, retrying without a fence"); + pMonitor->output->state->resetExplicitFences(); + ok = pMonitor->state.commit(); } - explicitPresented.clear(); - auto outFence = pMonitor->outTimeline->exportAsSyncFileFD(pMonitor->commitSeq); - if (outFence < 0) - Debug::log(ERR, "Export commitSeq {} as sync explicitOutFence failed", pMonitor->commitSeq); - - pMonitor->output->state->setExplicitOutFence(outFence); - Debug::log(TRACE, "Explicit sync presented end"); + if (!ok) { + Debug::log(TRACE, "Monitor state commit failed"); + // rollback the buffer to avoid writing to the front buffer that is being + // displayed + pMonitor->output->swapchain->rollback(); + pMonitor->damage.damageEntire(); + } } - pMonitor->lastWaitPoint = 0; + auto explicitOptions = getExplicitSyncSettings(); - bool ok = pMonitor->state.commit(); - if (!ok) { - Debug::log(TRACE, "Monitor state commit failed"); - // rollback the buffer to avoid writing to the front buffer that is being - // displayed - pMonitor->output->swapchain->rollback(); - pMonitor->damage.damageEntire(); - } - - if (!*PENABLEEXPLICIT) + if (!explicitOptions.explicitEnabled) return ok; - if (pMonitor->output->state->state().explicitInFence >= 0) - close(pMonitor->output->state->state().explicitInFence); + if (inFD >= 0) + close(inFD); if (pMonitor->output->state->state().explicitOutFence >= 0) { - if (ok) - pMonitor->outTimeline->importFromSyncFileFD(pMonitor->commitSeq, pMonitor->output->state->state().explicitOutFence); + Debug::log(TRACE, "Aquamarine returned an explicit out fence at {}", pMonitor->output->state->state().explicitOutFence); close(pMonitor->output->state->state().explicitOutFence); + } else + Debug::log(TRACE, "Aquamarine did not return an explicit out fence"); + + Debug::log(TRACE, "Explicit: {} presented", explicitPresented.size()); + auto sync = g_pHyprOpenGL->createEGLSync(-1); + + if (!sync) + Debug::log(TRACE, "Explicit: can't add sync, EGLSync failed"); + else { + for (auto& e : explicitPresented) { + if (!e->current.buffer || !e->current.buffer->releaser) + continue; + + e->current.buffer->releaser->addReleaseSync(sync); + } } + explicitPresented.clear(); + + pMonitor->output->state->resetExplicitFences(); + return ok; } @@ -1898,6 +1904,7 @@ bool CHyprRenderer::applyMonitorRule(CMonitor* pMonitor, SMonitorRule* pMonitorR pMonitor->currentMode = nullptr; pMonitor->output->state->setFormat(DRM_FORMAT_XRGB8888); + pMonitor->output->state->resetExplicitFences(); bool autoScale = false; @@ -2643,10 +2650,16 @@ bool CHyprRenderer::beginRender(CMonitor* pMonitor, CRegion& damage, eRenderMode void CHyprRenderer::endRender() { const auto PMONITOR = g_pHyprOpenGL->m_RenderData.pMonitor; static auto PNVIDIAANTIFLICKER = CConfigValue("opengl:nvidia_anti_flicker"); - static auto PENABLEEXPLICIT = CConfigValue("experimental:explicit_sync"); PMONITOR->commitSeq++; + auto cleanup = CScopeGuard([this]() { + if (m_pCurrentRenderbuffer) + m_pCurrentRenderbuffer->unbind(); + m_pCurrentRenderbuffer = nullptr; + m_pCurrentBuffer = nullptr; + }); + if (m_eRenderMode != RENDER_MODE_TO_BUFFER_READ_ONLY) g_pHyprOpenGL->end(); else { @@ -2661,35 +2674,28 @@ void CHyprRenderer::endRender() { if (m_eRenderMode == RENDER_MODE_NORMAL) { PMONITOR->output->state->setBuffer(m_pCurrentBuffer); - if (PMONITOR->inTimeline && *PENABLEEXPLICIT) { + auto explicitOptions = getExplicitSyncSettings(); + + if (PMONITOR->inTimeline && explicitOptions.explicitEnabled && explicitOptions.explicitKMSEnabled) { auto sync = g_pHyprOpenGL->createEGLSync(-1); if (!sync) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; Debug::log(ERR, "renderer: couldn't create an EGLSync for out in endRender"); return; } - auto dupedfd = sync->dupFenceFD(); - sync.reset(); - if (dupedfd < 0) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; - Debug::log(ERR, "renderer: couldn't dup an EGLSync fence for out in endRender"); + bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, sync->fd()); + if (!ok) { + Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); return; } - bool ok = PMONITOR->inTimeline->importFromSyncFileFD(PMONITOR->commitSeq, dupedfd); - close(dupedfd); - if (!ok) { - m_pCurrentRenderbuffer->unbind(); - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; - Debug::log(ERR, "renderer: couldn't import from sync file fd in endRender"); + auto fd = PMONITOR->inTimeline->exportAsSyncFileFD(PMONITOR->commitSeq); + if (fd <= 0) { + Debug::log(ERR, "renderer: couldn't export from sync timeline in endRender"); return; } + + PMONITOR->output->state->setExplicitInFence(fd); } else { if (isNvidia() && *PNVIDIAANTIFLICKER) glFinish(); @@ -2697,11 +2703,6 @@ void CHyprRenderer::endRender() { glFlush(); } } - - m_pCurrentRenderbuffer->unbind(); - - m_pCurrentRenderbuffer = nullptr; - m_pCurrentBuffer = nullptr; } void CHyprRenderer::onRenderbufferDestroy(CRenderbuffer* rb) { @@ -2715,3 +2716,57 @@ SP CHyprRenderer::getCurrentRBO() { bool CHyprRenderer::isNvidia() { return m_bNvidia; } + +SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() { + static auto PENABLEEXPLICIT = CConfigValue("render:explicit_sync"); + static auto PENABLEEXPLICITKMS = CConfigValue("render:explicit_sync_kms"); + + SExplicitSyncSettings settings; + settings.explicitEnabled = *PENABLEEXPLICIT; + settings.explicitKMSEnabled = *PENABLEEXPLICITKMS; + + if (*PENABLEEXPLICIT == 2 /* auto */) + settings.explicitEnabled = true; + if (*PENABLEEXPLICITKMS == 2 /* auto */) { + if (!m_bNvidia) + settings.explicitKMSEnabled = true; + else { + + // check nvidia version. Explicit KMS is supported in >=560 + // in the case of an error, driverMajor will stay 0 and explicit KMS will be disabled + int driverMajor = 0; + + static bool once = true; + if (once) { + once = false; + + Debug::log(LOG, "Renderer: checking for explicit KMS support for nvidia"); + + if (std::filesystem::exists("/sys/module/nvidia_drm/version")) { + Debug::log(LOG, "Renderer: Nvidia version file exists"); + + std::ifstream ifs("/sys/module/nvidia_drm/version"); + if (ifs.good()) { + try { + std::string driverInfo((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator())); + + Debug::log(LOG, "Renderer: Read nvidia version {}", driverInfo); + + CVarList ver(driverInfo, 0, '.', true); + driverMajor = std::stoi(ver[0]); + + Debug::log(LOG, "Renderer: Parsed nvidia major version: {}", driverMajor); + + } catch (std::exception& e) { settings.explicitKMSEnabled = false; } + + ifs.close(); + } + } + } + + settings.explicitKMSEnabled = driverMajor >= 560; + } + } + + return settings; +} -- cgit v1.2.3