renderer: Explicit sync fixes (#7151)
Enables explicit sync by default for most platforms `misc:no_direct_scanout` -> `render:direct_scanout`
This commit is contained in:
parent
0e86808e59
commit
640d161851
24 changed files with 378 additions and 165 deletions
|
|
@ -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 (state.commit()) {
|
||||
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 (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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
10
src/helpers/ScopeGuard.cpp
Normal file
10
src/helpers/ScopeGuard.cpp
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "ScopeGuard.hpp"
|
||||
|
||||
CScopeGuard::CScopeGuard(const std::function<void()>& fn_) : fn(fn_) {
|
||||
;
|
||||
}
|
||||
|
||||
CScopeGuard::~CScopeGuard() {
|
||||
if (fn)
|
||||
fn();
|
||||
}
|
||||
13
src/helpers/ScopeGuard.hpp
Normal file
13
src/helpers/ScopeGuard.hpp
Normal file
|
|
@ -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;
|
||||
};
|
||||
25
src/helpers/sync/SyncReleaser.cpp
Normal file
25
src/helpers/sync/SyncReleaser.cpp
Normal file
|
|
@ -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();
|
||||
}
|
||||
31
src/helpers/sync/SyncReleaser.hpp
Normal file
31
src/helpers/sync/SyncReleaser.hpp
Normal file
|
|
@ -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;
|
||||
};
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue