aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorVaxry <[email protected]>2024-08-06 14:52:19 +0100
committerGitHub <[email protected]>2024-08-06 15:52:19 +0200
commit640d1618519d42dd592f7af5e9984ad52eb8b820 (patch)
treef44a5b58822eb60e7fd2dfc3e18af9bba0ab2cb0
parent0e86808e5912823f1c6bea1b6d5fcae297fc9f57 (diff)
downloadHyprland-640d1618519d42dd592f7af5e9984ad52eb8b820.tar.gz
Hyprland-640d1618519d42dd592f7af5e9984ad52eb8b820.zip
renderer: Explicit sync fixes (#7151)
Enables explicit sync by default for most platforms `misc:no_direct_scanout` -> `render:direct_scanout`
-rw-r--r--src/Compositor.cpp4
-rw-r--r--src/config/ConfigManager.cpp17
-rw-r--r--src/helpers/Monitor.cpp64
-rw-r--r--src/helpers/Monitor.hpp3
-rw-r--r--src/helpers/ScopeGuard.cpp10
-rw-r--r--src/helpers/ScopeGuard.hpp13
-rw-r--r--src/helpers/sync/SyncReleaser.cpp25
-rw-r--r--src/helpers/sync/SyncReleaser.hpp31
-rw-r--r--src/helpers/sync/SyncTimeline.cpp5
-rw-r--r--src/helpers/sync/SyncTimeline.hpp1
-rw-r--r--src/managers/KeybindManager.cpp1
-rw-r--r--src/managers/ProtocolManager.cpp2
-rw-r--r--src/protocols/DRMSyncobj.cpp47
-rw-r--r--src/protocols/DRMSyncobj.hpp11
-rw-r--r--src/protocols/core/Compositor.cpp17
-rw-r--r--src/protocols/core/Compositor.hpp5
-rw-r--r--src/protocols/types/Buffer.cpp25
-rw-r--r--src/protocols/types/Buffer.hpp12
-rw-r--r--src/protocols/types/WLBuffer.cpp10
-rw-r--r--src/protocols/types/WLBuffer.hpp1
-rw-r--r--src/render/OpenGL.cpp32
-rw-r--r--src/render/OpenGL.hpp4
-rw-r--r--src/render/Renderer.cpp187
-rw-r--r--src/render/Renderer.hpp6
24 files changed, 373 insertions, 160 deletions
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index a139742c..299a16c6 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -2282,7 +2282,7 @@ void CCompositor::setWindowFullscreenClient(const PHLWINDOW PWINDOW, const eFull
}
void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenState state) {
- static auto PNODIRECTSCANOUT = CConfigValue<Hyprlang::INT>("misc:no_direct_scanout");
+ static auto PDIRECTSCANOUT = CConfigValue<Hyprlang::INT>("render:direct_scanout");
if (!validMapped(PWINDOW) || g_pCompositor->m_bUnsafeState)
return;
@@ -2342,7 +2342,7 @@ void CCompositor::setWindowFullscreenState(const PHLWINDOW PWINDOW, sFullscreenS
// send a scanout tranche if we are entering fullscreen, and send a regular one if we aren't.
// ignore if DS is disabled.
- if (!*PNODIRECTSCANOUT)
+ if (*PDIRECTSCANOUT)
g_pHyprRenderer->setSurfaceScanoutMode(PWINDOW->m_pWLSurface->resource(), EFFECTIVE_MODE != FSMODE_NONE ? PMONITOR->self.lock() : nullptr);
g_pConfigManager->ensureVRR(PMONITOR);
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index fe3af8c0..be6433fa 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -3,6 +3,7 @@
#include "../render/decorations/CHyprGroupBarDecoration.hpp"
#include "config/ConfigDataValues.hpp"
+#include "config/ConfigValue.hpp"
#include "helpers/varlist/VarList.hpp"
#include "../protocols/LayerShell.hpp"
@@ -346,7 +347,6 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("misc:swallow_regex", {STRVAL_EMPTY});
m_pConfig->addConfigValue("misc:swallow_exception_regex", {STRVAL_EMPTY});
m_pConfig->addConfigValue("misc:focus_on_activate", Hyprlang::INT{0});
- m_pConfig->addConfigValue("misc:no_direct_scanout", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:mouse_move_focuses_monitor", Hyprlang::INT{1});
m_pConfig->addConfigValue("misc:render_ahead_of_time", Hyprlang::INT{0});
m_pConfig->addConfigValue("misc:render_ahead_safezone", Hyprlang::INT{1});
@@ -560,7 +560,9 @@ CConfigManager::CConfigManager() {
m_pConfig->addConfigValue("group:groupbar:col.locked_active", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66ff5500"});
m_pConfig->addConfigValue("group:groupbar:col.locked_inactive", Hyprlang::CConfigCustomValueType{&configHandleGradientSet, configHandleGradientDestroy, "0x66775500"});
- m_pConfig->addConfigValue("experimental:explicit_sync", Hyprlang::INT{0});
+ m_pConfig->addConfigValue("render:explicit_sync", Hyprlang::INT{2});
+ m_pConfig->addConfigValue("render:explicit_sync_kms", Hyprlang::INT{2});
+ m_pConfig->addConfigValue("render:direct_scanout", Hyprlang::INT{0});
// devices
m_pConfig->addSpecialCategory("device", {"name"});
@@ -798,6 +800,9 @@ std::optional<std::string> CConfigManager::resetHLConfig() {
}
void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
+ static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
+ static int prevEnabledExplicit = *PENABLEEXPLICIT;
+
for (auto& w : g_pCompositor->m_vWindows) {
w->uncacheWindowDecos();
}
@@ -816,6 +821,9 @@ void CConfigManager::postConfigReload(const Hyprlang::CParseResult& result) {
if (!isFirstLaunch)
g_pHyprOpenGL->m_bReloadScreenShader = true;
+ if (!isFirstLaunch && *PENABLEEXPLICIT != prevEnabledExplicit)
+ g_pHyprError->queueCreate("Warning: You changed the render:explicit_sync option, this requires you to restart Hyprland.", CColor(0.9, 0.76, 0.221, 1.0));
+
// parseError will be displayed next frame
if (result.error)
@@ -1417,7 +1425,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
if (USEVRR == 0) {
if (m->vrrActive) {
-
+ m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(false);
if (!m->state.commit())
@@ -1427,6 +1435,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
return;
} else if (USEVRR == 1) {
if (!m->vrrActive) {
+ m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(true);
if (!m->state.test()) {
@@ -1451,6 +1460,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
const auto WORKSPACEFULL = PWORKSPACE->m_bHasFullscreenWindow && (PWORKSPACE->m_efFullscreenMode & FSMODE_FULLSCREEN);
if (WORKSPACEFULL) {
+ m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(true);
if (!m->state.test()) {
@@ -1462,6 +1472,7 @@ void CConfigManager::ensureVRR(CMonitor* pMonitor) {
Debug::log(ERR, "Couldn't commit output {} in ensureVRR -> true", m->output->name);
} else if (!WORKSPACEFULL) {
+ m->output->state->resetExplicitFences();
m->output->state->setAdaptiveSync(false);
if (!m->state.commit())
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 1cf1b069..8f23c462 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -1,6 +1,8 @@
#include "Monitor.hpp"
#include "MiscFunctions.hpp"
#include "math/Math.hpp"
+#include "sync/SyncReleaser.hpp"
+#include "ScopeGuard.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/GammaControl.hpp"
@@ -8,6 +10,7 @@
#include "../protocols/LayerShell.hpp"
#include "../protocols/PresentationTime.hpp"
#include "../protocols/DRMLease.hpp"
+#include "../protocols/DRMSyncobj.hpp"
#include "../protocols/core/Output.hpp"
#include "../managers/PointerManager.hpp"
#include "../protocols/core/Compositor.hpp"
@@ -77,6 +80,7 @@ void CMonitor::onConnect(bool noRule) {
tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
if (m_bEnabled) {
+ output->state->resetExplicitFences();
output->state->setEnabled(true);
state.commit();
return;
@@ -101,6 +105,7 @@ void CMonitor::onConnect(bool noRule) {
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
+ output->state->resetExplicitFences();
output->state->setEnabled(false);
if (!state.commit())
@@ -137,6 +142,7 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true;
+ output->state->resetExplicitFences();
output->state->setEnabled(true);
// set mode, also applies
@@ -300,6 +306,7 @@ void CMonitor::onDisconnect(bool destroy) {
activeWorkspace->m_bVisible = false;
activeWorkspace.reset();
+ output->state->resetExplicitFences();
output->state->setEnabled(false);
if (!state.commit())
@@ -808,28 +815,77 @@ bool CMonitor::attemptDirectScanout() {
if (!PSURFACE->current.buffer || !PSURFACE->current.texture || !PSURFACE->current.texture->m_pEglImage /* dmabuf */)
return false;
+ Debug::log(TRACE, "attemptDirectScanout: surface {:x} passed, will attempt", (uintptr_t)PSURFACE.get());
+
// FIXME: make sure the buffer actually follows the available scanout dmabuf formats
// and comes from the appropriate device. This may implode on multi-gpu!!
output->state->setBuffer(PSURFACE->current.buffer->buffer.lock());
output->state->setPresentationMode(tearingState.activelyTearing ? Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
- if (!state.test())
+ if (!state.test()) {
+ Debug::log(TRACE, "attemptDirectScanout: failed basic test");
return false;
+ }
+
+ auto explicitOptions = g_pHyprRenderer->getExplicitSyncSettings();
+
+ // wait for the explicit fence if present, and if kms explicit is allowed
+ bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.acquireTimeline && PSURFACE->syncobj->current.acquireTimeline->timeline && explicitOptions.explicitKMSEnabled;
+ int explicitWaitFD = -1;
+ if (DOEXPLICIT) {
+ explicitWaitFD = PSURFACE->syncobj->current.acquireTimeline->timeline->exportAsSyncFileFD(PSURFACE->syncobj->current.acquirePoint);
+ if (explicitWaitFD < 0)
+ Debug::log(TRACE, "attemptDirectScanout: failed to acquire an explicit wait fd");
+ }
+ DOEXPLICIT = DOEXPLICIT && explicitWaitFD >= 0;
+
+ auto cleanup = CScopeGuard([explicitWaitFD, this]() {
+ output->state->resetExplicitFences();
+ if (explicitWaitFD >= 0)
+ close(explicitWaitFD);
+ });
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
- Debug::log(TRACE, "presentFeedback for DS");
- PSURFACE->presentFeedback(&now, this, true);
+ PSURFACE->presentFeedback(&now, this);
output->state->addDamage(CBox{{}, vecPixelSize});
+ output->state->resetExplicitFences();
+
+ if (DOEXPLICIT) {
+ Debug::log(TRACE, "attemptDirectScanout: setting IN_FENCE for aq to {}", explicitWaitFD);
+ output->state->setExplicitInFence(explicitWaitFD);
+ }
+
+ bool ok = output->commit();
+
+ if (!ok && DOEXPLICIT) {
+ Debug::log(TRACE, "attemptDirectScanout: EXPLICIT SYNC FAILED: commit() returned false. Resetting fences and retrying, might result in glitches.");
+ output->state->resetExplicitFences();
+
+ ok = output->commit();
+ }
- if (state.commit()) {
+ if (ok) {
if (lastScanout.expired()) {
lastScanout = PCANDIDATE;
Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
}
+
+ // delay explicit sync feedback until kms release of the buffer
+ if (DOEXPLICIT) {
+ Debug::log(TRACE, "attemptDirectScanout: Delaying explicit sync release feedback until kms release");
+ PSURFACE->current.buffer->releaser->drop();
+
+ PSURFACE->current.buffer->buffer->hlEvents.backendRelease2 = PSURFACE->current.buffer->buffer->events.backendRelease.registerListener([PSURFACE](std::any d) {
+ const bool DOEXPLICIT = PSURFACE->syncobj && PSURFACE->syncobj->current.releaseTimeline && PSURFACE->syncobj->current.releaseTimeline->timeline;
+ if (DOEXPLICIT)
+ PSURFACE->syncobj->current.releaseTimeline->timeline->signal(PSURFACE->syncobj->current.releasePoint);
+ });
+ }
} else {
+ Debug::log(TRACE, "attemptDirectScanout: failed to scanout surface");
lastScanout.reset();
return false;
}
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 32fc768a..fbe26f67 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -121,8 +121,7 @@ class CMonitor {
// explicit sync
SP<CSyncTimeline> inTimeline;
SP<CSyncTimeline> outTimeline;
- uint64_t lastWaitPoint = 0;
- uint64_t commitSeq = 0;
+ uint64_t commitSeq = 0;
WP<CMonitor> self;
diff --git a/src/helpers/ScopeGuard.cpp b/src/helpers/ScopeGuard.cpp
new file mode 100644
index 00000000..319255cd
--- /dev/null
+++ b/src/helpers/ScopeGuard.cpp
@@ -0,0 +1,10 @@
+#include "ScopeGuard.hpp"
+
+CScopeGuard::CScopeGuard(const std::function<void()>& fn_) : fn(fn_) {
+ ;
+}
+
+CScopeGuard::~CScopeGuard() {
+ if (fn)
+ fn();
+}
diff --git a/src/helpers/ScopeGuard.hpp b/src/helpers/ScopeGuard.hpp
new file mode 100644
index 00000000..8a1468eb
--- /dev/null
+++ b/src/helpers/ScopeGuard.hpp
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <functional>
+
+// calls a function when it goes out of scope
+class CScopeGuard {
+ public:
+ CScopeGuard(const std::function<void()>& fn_);
+ ~CScopeGuard();
+
+ private:
+ std::function<void()> fn;
+};
diff --git a/src/helpers/sync/SyncReleaser.cpp b/src/helpers/sync/SyncReleaser.cpp
new file mode 100644
index 00000000..198495ab
--- /dev/null
+++ b/src/helpers/sync/SyncReleaser.cpp
@@ -0,0 +1,25 @@
+#include "SyncReleaser.hpp"
+#include "SyncTimeline.hpp"
+#include "../../render/OpenGL.hpp"
+
+CSyncReleaser::CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_) : timeline(timeline_), point(point_) {
+ ;
+}
+
+CSyncReleaser::~CSyncReleaser() {
+ if (timeline.expired())
+ return;
+
+ if (sync)
+ timeline->importFromSyncFileFD(point, sync->fd());
+ else
+ timeline->signal(point);
+}
+
+void CSyncReleaser::addReleaseSync(SP<CEGLSync> sync_) {
+ sync = sync_;
+}
+
+void CSyncReleaser::drop() {
+ timeline.reset();
+} \ No newline at end of file
diff --git a/src/helpers/sync/SyncReleaser.hpp b/src/helpers/sync/SyncReleaser.hpp
new file mode 100644
index 00000000..e21d2e34
--- /dev/null
+++ b/src/helpers/sync/SyncReleaser.hpp
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <cstdint>
+#include <optional>
+#include <vector>
+#include <functional>
+#include "../memory/Memory.hpp"
+
+/*
+ A helper (inspired by KDE's KWin) that will release the timeline point in the dtor
+*/
+
+class CSyncTimeline;
+class CEGLSync;
+
+class CSyncReleaser {
+ public:
+ CSyncReleaser(WP<CSyncTimeline> timeline_, uint64_t point_);
+ ~CSyncReleaser();
+
+ // drops the releaser, will never signal anymore
+ void drop();
+
+ // wait for this gpu job to finish before releasing
+ void addReleaseSync(SP<CEGLSync> sync);
+
+ private:
+ WP<CSyncTimeline> timeline;
+ uint64_t point = 0;
+ SP<CEGLSync> sync;
+};
diff --git a/src/helpers/sync/SyncTimeline.cpp b/src/helpers/sync/SyncTimeline.cpp
index 352120ea..16b5bd92 100644
--- a/src/helpers/sync/SyncTimeline.cpp
+++ b/src/helpers/sync/SyncTimeline.cpp
@@ -188,3 +188,8 @@ bool CSyncTimeline::transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_
return true;
}
+
+void CSyncTimeline::signal(uint64_t point) {
+ if (drmSyncobjTimelineSignal(drmFD, &handle, &point, 1))
+ Debug::log(ERR, "CSyncTimeline::signal: drmSyncobjTimelineSignal failed");
+}
diff --git a/src/helpers/sync/SyncTimeline.hpp b/src/helpers/sync/SyncTimeline.hpp
index 3d868a95..88ad4921 100644
--- a/src/helpers/sync/SyncTimeline.hpp
+++ b/src/helpers/sync/SyncTimeline.hpp
@@ -35,6 +35,7 @@ class CSyncTimeline {
int exportAsSyncFileFD(uint64_t src);
bool importFromSyncFileFD(uint64_t dst, int fd);
bool transfer(SP<CSyncTimeline> from, uint64_t fromPoint, uint64_t toPoint);
+ void signal(uint64_t point);
int drmFD = -1;
uint32_t handle = 0;
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index 09ba7d50..08c6998d 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -2293,6 +2293,7 @@ void CKeybindManager::dpms(std::string arg) {
if (!port.empty() && m->szName != port)
continue;
+ m->output->state->resetExplicitFences();
m->output->state->setEnabled(enable);
m->dpmsStatus = enable;
diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp
index 635e6223..6e5cd16f 100644
--- a/src/managers/ProtocolManager.cpp
+++ b/src/managers/ProtocolManager.cpp
@@ -76,7 +76,7 @@ void CProtocolManager::onMonitorModeChange(CMonitor* pMonitor) {
CProtocolManager::CProtocolManager() {
- static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("experimental:explicit_sync");
+ static const auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
// Outputs are a bit dumb, we have to agree.
static auto P = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) {
diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp
index 33339554..8b0330de 100644
--- a/src/protocols/DRMSyncobj.cpp
+++ b/src/protocols/DRMSyncobj.cpp
@@ -24,9 +24,9 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return;
}
- auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
- acquireTimeline = timeline;
- acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
+ auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
+ pending.acquireTimeline = timeline;
+ pending.acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
});
resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) {
@@ -35,29 +35,33 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return;
}
- auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
- releaseTimeline = timeline;
- releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
+ auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_);
+ pending.releaseTimeline = timeline;
+ pending.releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo;
});
listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) {
- if (!!acquireTimeline != !!releaseTimeline) {
- resource->error(acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline");
+ if ((pending.acquireTimeline || pending.releaseTimeline) && !surface->pending.texture) {
+ resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
surface->pending.rejected = true;
return;
}
- if ((acquireTimeline || releaseTimeline) && !surface->pending.texture) {
- resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
+ if (!surface->pending.newBuffer)
+ return; // this commit does not change the state here
+
+ if (!!pending.acquireTimeline != !!pending.releaseTimeline) {
+ resource->error(pending.acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT,
+ "Missing timeline");
surface->pending.rejected = true;
return;
}
- if (!acquireTimeline)
+ if (!pending.acquireTimeline)
return;
// wait for the acquire timeline to materialize
- auto materialized = acquireTimeline->timeline->check(acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
+ auto materialized = pending.acquireTimeline->timeline->check(pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
if (!materialized.has_value()) {
LOGM(ERR, "Failed to check the acquire timeline");
resource->noMemory();
@@ -68,7 +72,24 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurf
return;
surface->lockPendingState();
- acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
+ pending.acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, pending.acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE);
+ });
+
+ listeners.surfaceCommit = surface->events.commit.registerListener([this](std::any d) {
+ // apply timelines if new ones have been attached, otherwise don't touch
+ // the current ones
+ if (pending.releaseTimeline) {
+ current.releaseTimeline = pending.releaseTimeline;
+ current.releasePoint = pending.releasePoint;
+ }
+
+ if (pending.acquireTimeline) {
+ current.acquireTimeline = pending.acquireTimeline;
+ current.acquirePoint = pending.acquirePoint;
+ }
+
+ pending.releaseTimeline.reset();
+ pending.acquireTimeline.reset();
});
}
diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp
index c1c884ff..25dc10c1 100644
--- a/src/protocols/DRMSyncobj.hpp
+++ b/src/protocols/DRMSyncobj.hpp
@@ -14,17 +14,20 @@ class CDRMSyncobjSurfaceResource {
public:
CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> surface_);
- bool good();
+ bool good();
- WP<CWLSurfaceResource> surface;
- WP<CDRMSyncobjTimelineResource> acquireTimeline, releaseTimeline;
- uint64_t acquirePoint = 0, releasePoint = 0;
+ WP<CWLSurfaceResource> surface;
+ struct {
+ WP<CDRMSyncobjTimelineResource> acquireTimeline, releaseTimeline;
+ uint64_t acquirePoint = 0, releasePoint = 0;
+ } current, pending;
private:
SP<CWpLinuxDrmSyncobjSurfaceV1> resource;
struct {
CHyprSignalListener surfacePrecommit;
+ CHyprSignalListener surfaceCommit;
} listeners;
};
diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp
index 4a6fa40f..b0111032 100644
--- a/src/protocols/core/Compositor.cpp
+++ b/src/protocols/core/Compositor.cpp
@@ -7,6 +7,7 @@
#include "Subcompositor.hpp"
#include "../Viewporter.hpp"
#include "../../helpers/Monitor.hpp"
+#include "../../helpers/sync/SyncReleaser.hpp"
#include "../PresentationTime.hpp"
#include "../DRMSyncobj.hpp"
#include "../../render/Renderer.hpp"
@@ -69,7 +70,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : resource(reso
resource->setOnDestroy([this](CWlSurface* r) { destroy(); });
resource->setAttach([this](CWlSurface* r, wl_resource* buffer, int32_t x, int32_t y) {
- pending.offset = {x, y};
+ pending.offset = {x, y};
+ pending.newBuffer = true;
if (!buffer) {
pending.buffer.reset();
@@ -428,6 +430,10 @@ void CWLSurfaceResource::commitPendingState() {
current = pending;
pending.damage.clear();
pending.bufferDamage.clear();
+ pending.newBuffer = false;
+
+ if (syncobj && syncobj->current.releaseTimeline && syncobj->current.releaseTimeline->timeline && current.buffer && current.buffer->buffer)
+ current.buffer->releaser = makeShared<CSyncReleaser>(syncobj->current.releaseTimeline->timeline, syncobj->current.releasePoint);
if (current.texture)
current.texture->m_eTransform = wlTransformToHyprutils(current.transform);
@@ -501,23 +507,18 @@ void CWLSurfaceResource::updateCursorShm() {
memcpy(shmData.data(), pixelData, bufLen);
}
-void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) {
+void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor) {
frame(when);
auto FEEDBACK = makeShared<CQueuedPresentationData>(self.lock());
FEEDBACK->attachMonitor(pMonitor);
FEEDBACK->presented();
PROTO::presentation->queueData(FEEDBACK);
- if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync)
+ if (!pMonitor || !pMonitor->outTimeline || !syncobj)
return;
// attach explicit sync
g_pHyprRenderer->explicitPresented.emplace_back(self.lock());
-
- if (syncobj->acquirePoint > pMonitor->lastWaitPoint) {
- Debug::log(TRACE, "presentFeedback lastWaitPoint {} -> {}", pMonitor->lastWaitPoint, syncobj->acquirePoint);
- pMonitor->lastWaitPoint = syncobj->acquirePoint;
- }
}
CWLCompositorResource::CWLCompositorResource(SP<CWlCompositor> resource_) : resource(resource_) {
diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp
index 460ec755..af0dfa58 100644
--- a/src/protocols/core/Compositor.hpp
+++ b/src/protocols/core/Compositor.hpp
@@ -97,7 +97,8 @@ class CWLSurfaceResource {
Vector2D destination;
CBox source;
} viewport;
- bool rejected = false;
+ bool rejected = false;
+ bool newBuffer = false;
//
void reset() {
@@ -122,7 +123,7 @@ class CWLSurfaceResource {
void breadthfirst(std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
CRegion accumulateCurrentBufferDamage();
- void presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync = false);
+ void presentFeedback(timespec* when, CMonitor* pMonitor);
void lockPendingState();
void unlockPendingState();
diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp
index 40f2eaf8..ea12f017 100644
--- a/src/protocols/types/Buffer.cpp
+++ b/src/protocols/types/Buffer.cpp
@@ -9,11 +9,6 @@ void IHLBuffer::sendRelease() {
resource->sendRelease();
}
-void IHLBuffer::sendReleaseWithSurface(SP<CWLSurfaceResource> surf) {
- if (resource && resource->good())
- resource->sendReleaseWithSurface(surf);
-}
-
void IHLBuffer::lock() {
nLocks++;
}
@@ -27,26 +22,13 @@ void IHLBuffer::unlock() {
sendRelease();
}
-void IHLBuffer::unlockWithSurface(SP<CWLSurfaceResource> surf) {
- nLocks--;
-
- ASSERT(nLocks >= 0);
-
- if (nLocks == 0)
- sendReleaseWithSurface(surf);
-}
-
bool IHLBuffer::locked() {
return nLocks > 0;
}
void IHLBuffer::unlockOnBufferRelease(WP<CWLSurfaceResource> surf) {
- unlockSurface = surf;
hlEvents.backendRelease = events.backendRelease.registerListener([this](std::any data) {
- if (unlockSurface.expired())
- unlock();
- else
- unlockWithSurface(unlockSurface.lock());
+ unlock();
hlEvents.backendRelease.reset();
});
}
@@ -59,8 +41,5 @@ CHLBufferReference::~CHLBufferReference() {
if (buffer.expired())
return;
- if (surface)
- buffer->unlockWithSurface(surface.lock());
- else
- buffer->unlock();
+ buffer->unlock();
}
diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp
index d2157181..7d84dce7 100644
--- a/src/protocols/types/Buffer.hpp
+++ b/src/protocols/types/Buffer.hpp
@@ -6,6 +6,8 @@
#include <aquamarine/buffer/Buffer.hpp>
+class CSyncReleaser;
+
class IHLBuffer : public Aquamarine::IBuffer {
public:
virtual ~IHLBuffer();
@@ -15,10 +17,8 @@ class IHLBuffer : public Aquamarine::IBuffer {
virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu
virtual bool good() = 0;
virtual void sendRelease();
- virtual void sendReleaseWithSurface(SP<CWLSurfaceResource>);
virtual void lock();
virtual void unlock();
- virtual void unlockWithSurface(SP<CWLSurfaceResource> surf);
virtual bool locked();
void unlockOnBufferRelease(WP<CWLSurfaceResource> surf /* optional */);
@@ -29,12 +29,11 @@ class IHLBuffer : public Aquamarine::IBuffer {
struct {
CHyprSignalListener backendRelease;
+ CHyprSignalListener backendRelease2; // for explicit ds
} hlEvents;
private:
- int nLocks = 0;
-
- WP<CWLSurfaceResource> unlockSurface;
+ int nLocks = 0;
};
// for ref-counting. Releases in ~dtor
@@ -44,7 +43,8 @@ class CHLBufferReference {
CHLBufferReference(SP<IHLBuffer> buffer, SP<CWLSurfaceResource> surface);
~CHLBufferReference();
- WP<IHLBuffer> buffer;
+ WP<IHLBuffer> buffer;
+ SP<CSyncReleaser> releaser;
private:
WP<CWLSurfaceResource> surface;
diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp
index d34a867d..eb7d1fde 100644
--- a/src/protocols/types/WLBuffer.cpp
+++ b/src/protocols/types/WLBuffer.cpp
@@ -32,16 +32,6 @@ void CWLBufferResource::sendRelease() {
resource->sendRelease();
}
-void CWLBufferResource::sendReleaseWithSurface(SP<CWLSurfaceResource> surf) {
- sendRelease();
-
- if (!surf || !surf->syncobj)
- return;
-
- if (drmSyncobjTimelineSignal(g_pCompositor->m_iDRMFD, &surf->syncobj->releaseTimeline->timeline->handle, &surf->syncobj->releasePoint, 1))
- Debug::log(ERR, "sendReleaseWithSurface: drmSyncobjTimelineSignal failed");
-}
-
wl_resource* CWLBufferResource::getResource() {
return resource->resource();
}
diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp
index 59512128..787abe1f 100644
--- a/src/protocols/types/WLBuffer.hpp
+++ b/src/protocols/types/WLBuffer.hpp
@@ -17,7 +17,6 @@ class CWLBufferResource {
bool good();
void sendRelease();
- void sendReleaseWithSurface(SP<CWLSurfaceResource>);
wl_resource* getResource();
WP<IHLBuffer> buffer;
diff --git a/src/render/OpenGL.cpp b/src/render/OpenGL.cpp
index ea388df0..8875d8f4 100644
--- a/src/render/OpenGL.cpp
+++ b/src/render/OpenGL.cpp
@@ -2870,7 +2870,7 @@ SP<CEGLSync> CHyprOpenGLImpl::createEGLSync(int fenceFD) {
std::vector<EGLint> attribs;
int dupFd = -1;
if (fenceFD > 0) {
- int dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0);
+ dupFd = fcntl(fenceFD, F_DUPFD_CLOEXEC, 0);
if (dupFd < 0) {
Debug::log(ERR, "createEGLSync: dup failed");
return nullptr;
@@ -2889,8 +2889,18 @@ SP<CEGLSync> CHyprOpenGLImpl::createEGLSync(int fenceFD) {
return nullptr;
}
- auto eglsync = SP<CEGLSync>(new CEGLSync);
- eglsync->sync = sync;
+ // we need to flush otherwise we might not get a valid fd
+ glFlush();
+
+ int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync);
+ if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ Debug::log(ERR, "eglDupNativeFenceFDANDROID failed");
+ return nullptr;
+ }
+
+ auto eglsync = SP<CEGLSync>(new CEGLSync);
+ eglsync->sync = sync;
+ eglsync->m_iFd = fd;
return eglsync;
}
@@ -2983,19 +2993,13 @@ CEGLSync::~CEGLSync() {
if (g_pHyprOpenGL->m_sProc.eglDestroySyncKHR(g_pHyprOpenGL->m_pEglDisplay, sync) != EGL_TRUE)
Debug::log(ERR, "eglDestroySyncKHR failed");
-}
-int CEGLSync::dupFenceFD() {
- if (sync == EGL_NO_SYNC_KHR)
- return -1;
-
- int fd = g_pHyprOpenGL->m_sProc.eglDupNativeFenceFDANDROID(g_pHyprOpenGL->m_pEglDisplay, sync);
- if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
- Debug::log(ERR, "eglDupNativeFenceFDANDROID failed");
- return -1;
- }
+ if (m_iFd >= 0)
+ close(m_iFd);
+}
- return fd;
+int CEGLSync::fd() {
+ return m_iFd;
}
bool CEGLSync::wait() {
diff --git a/src/render/OpenGL.hpp b/src/render/OpenGL.hpp
index 1e8325c1..f405cb7c 100644
--- a/src/render/OpenGL.hpp
+++ b/src/render/OpenGL.hpp
@@ -131,12 +131,14 @@ class CEGLSync {
EGLSyncKHR sync = nullptr;
- int dupFenceFD();
+ int fd();
bool wait();
private:
CEGLSync() = default;
+ int m_iFd = -1;
+
friend class CHyprOpenGLImpl;
};
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 <algorithm>
#include <aquamarine/output/Output.hpp>
#include <cstring>
+#include <filesystem>
#include "../config/ConfigValue.hpp"
#include "../managers/CursorManager.hpp"
#include "../managers/PointerManager.hpp"
@@ -115,8 +118,8 @@ static void renderSurface(SP<CWLSurfaceResource> 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<Hyprlang::INT>("debug:overlay");
static auto PDAMAGETRACKINGMODE = CConfigValue<Hyprlang::INT>("debug:damage_tracking");
static auto PDAMAGEBLINK = CConfigValue<Hyprlang::INT>("debug:damage_blink");
- static auto PNODIRECTSCANOUT = CConfigValue<Hyprlang::INT>("misc:no_direct_scanout");
+ static auto PDIRECTSCANOUT = CConfigValue<Hyprlang::INT>("render:direct_scanout");
static auto PVFR = CConfigValue<Hyprlang::INT>("misc:vfr");
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
static auto PANIMENABLED = CConfigValue<Hyprlang::INT>("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<Hyprlang::INT>("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<Hyprlang::INT>("opengl:nvidia_anti_flicker");
- static auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("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<CRenderbuffer> CHyprRenderer::getCurrentRBO() {
bool CHyprRenderer::isNvidia() {
return m_bNvidia;
}
+
+SExplicitSyncSettings CHyprRenderer::getExplicitSyncSettings() {
+ static auto PENABLEEXPLICIT = CConfigValue<Hyprlang::INT>("render:explicit_sync");
+ static auto PENABLEEXPLICITKMS = CConfigValue<Hyprlang::INT>("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<char>(ifs)), (std::istreambuf_iterator<char>()));
+
+ 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;
+}
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index a9397cac..84501821 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -39,6 +39,10 @@ class CToplevelExportProtocolManager;
class CInputManager;
struct SSessionLockSurface;
+struct SExplicitSyncSettings {
+ bool explicitEnabled = false, explicitKMSEnabled = false;
+};
+
class CHyprRenderer {
public:
CHyprRenderer();
@@ -73,6 +77,7 @@ class CHyprRenderer {
bool isNvidia();
void makeEGLCurrent();
void unsetEGL();
+ SExplicitSyncSettings getExplicitSyncSettings();
// if RENDER_MODE_NORMAL, provided damage will be written to.
// otherwise, it will be the one used.
@@ -142,6 +147,7 @@ class CHyprRenderer {
friend class CToplevelExportFrame;
friend class CInputManager;
friend class CPointerManager;
+ friend class CMonitor;
};
inline std::unique_ptr<CHyprRenderer> g_pHyprRenderer;