This commit is contained in:
Tom Englund 2025-12-19 17:35:06 +00:00 committed by GitHub
commit eeb96c3940
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 293 additions and 122 deletions

View file

@ -8,6 +8,7 @@
#include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp"
#include "config/ConfigWatcher.hpp"
#include "managers/SurfaceManager.hpp"
#include "managers/CursorManager.hpp"
#include "managers/TokenManager.hpp"
#include "managers/PointerManager.hpp"
@ -661,6 +662,9 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Log::logger->log(Log::DEBUG, "Creating the SeatManager!");
g_pSeatManager = makeUnique<CSeatManager>();
Log::logger->log(Log::DEBUG, "Creating the CSurfaceManager!");
g_pSurfaceManager = makeUnique<CSurfaceManager>();
} break;
case STAGE_LATE: {
Log::logger->log(Log::DEBUG, "Creating CHyprCtl");

View file

@ -26,6 +26,7 @@
#include "../managers/animation/AnimationManager.hpp"
#include "../managers/animation/DesktopAnimationManager.hpp"
#include "../managers/input/InputManager.hpp"
#include "../managers/SurfaceManager.hpp"
#include "../hyprerror/HyprError.hpp"
#include "../i18n/Engine.hpp"
#include "sync/SyncTimeline.hpp"
@ -68,6 +69,9 @@ CMonitor::~CMonitor() {
m_events.destroy.emit();
if (g_pHyprOpenGL)
g_pHyprOpenGL->destroyMonitorResources(m_self);
if (g_pSurfaceManager)
g_pSurfaceManager->destroy(m_self);
}
void CMonitor::onConnect(bool noRule) {
@ -114,10 +118,8 @@ void CMonitor::onConnect(bool noRule) {
ts = nullptr;
}
if (!ts)
PROTO::presentation->onPresented(m_self.lock(), Time::steadyNow(), event.refresh, event.seq, event.flags);
else
PROTO::presentation->onPresented(m_self.lock(), Time::fromTimespec(event.when), event.refresh, event.seq, event.flags);
auto now = ts ? Time::fromTimespec(event.when) : Time::steadyNow();
PROTO::presentation->onPresented(m_self.lock(), now, event.refresh, event.seq, event.flags);
if (m_zoomAnimFrameCounter < 5) {
m_zoomAnimFrameCounter++;
@ -140,7 +142,7 @@ void CMonitor::onConnect(bool noRule) {
});
}
m_frameScheduler->onPresented();
m_frameScheduler->onPresented(now);
m_events.presented.emit();
});

View file

@ -3,6 +3,7 @@
#include "../Compositor.hpp"
#include "../render/Renderer.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../managers/SurfaceManager.hpp"
CMonitorFrameScheduler::CMonitorFrameScheduler(PHLMONITOR m) : m_monitor(m) {
;
@ -16,7 +17,7 @@ bool CMonitorFrameScheduler::newSchedulingEnabled() {
void CMonitorFrameScheduler::onSyncFired() {
if (!newSchedulingEnabled())
if (!newSchedulingEnabled() || m_skipThird)
return;
// Sync fired: reset submitted state, set as rendered. Check the last render time. If we are running
@ -25,21 +26,27 @@ void CMonitorFrameScheduler::onSyncFired() {
if (std::chrono::duration_cast<std::chrono::microseconds>(hrc::now() - m_lastRenderBegun).count() / 1000.F < 1000.F / m_monitor->m_refreshRate) {
// we are in. Frame is valid. We can just render as normal.
Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onSyncFired, didn't miss.", m_monitor->m_name);
if (!m_renderAtFrame)
g_pCompositor->scheduleFrameForMonitor(m_monitor.lock());
m_renderAtFrame = true;
return;
} else if (m_renderAtFrame) {
m_renderAtFrame = false;
g_pCompositor->scheduleFrameForMonitor(m_monitor.lock());
return;
}
Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onSyncFired, missed.", m_monitor->m_name);
Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onSyncFired, rendering third frame.", m_monitor->m_name);
// we are out. The frame is taking too long to render. Begin rendering immediately, but don't commit yet.
m_pendingThird = true;
m_renderAtFrame = false; // block frame rendering, we already scheduled
m_pendingThird = true;
m_lastRenderBegun = hrc::now();
// get a ref to ourselves. renderMonitor can destroy this scheduler if it decides to perform a monitor reload
// FIXME: this is horrible. "renderMonitor" should not be able to do that.
auto self = m_self;
g_pSurfaceManager->sendScheduledFrames(m_monitor, Time::steadyNow());
g_pHyprRenderer->renderMonitor(m_monitor.lock(), false);
@ -49,31 +56,28 @@ void CMonitorFrameScheduler::onSyncFired() {
onFinishRender();
}
void CMonitorFrameScheduler::onPresented() {
void CMonitorFrameScheduler::onPresented(const Time::steady_tp& now) {
g_pSurfaceManager->sendScheduledFrames(m_monitor, now);
if (!newSchedulingEnabled())
return;
m_skipThird = false;
if (!m_pendingThird)
return;
Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onPresented, missed, committing pending.", m_monitor->m_name);
m_pendingThird = false;
auto mon = m_monitor.lock();
Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onPresented, missed, committing pending at the earliest convenience.", m_monitor->m_name);
g_pHyprRenderer->commitPendingAndDoExplicitSync(mon, true); // commit the pending frame. If it didn't fire yet (is not rendered) it doesn't matter. Syncs will wait.
m_skipThird = true;
m_pendingThird = false;
g_pEventLoopManager->doLater([m = m_monitor.lock()] {
if (!m)
return;
g_pHyprRenderer->commitPendingAndDoExplicitSync(m); // commit the pending frame. If it didn't fire yet (is not rendered) it doesn't matter. Syncs will wait.
// schedule a frame: we might have some missed damage, which got cleared due to the above commit.
// TODO: this is not always necessary, but doesn't hurt in general. We likely won't hit this if nothing's happening anyways.
if (m->m_damage.hasChanged())
g_pCompositor->scheduleFrameForMonitor(m);
});
// schedule a frame: we might have some missed damage, which got cleared due to the above commit.
// TODO: this is not always necessary, but doesn't hurt in general. We likely won't hit this if nothing's happening anyways.
if (mon->m_damage.hasChanged())
g_pCompositor->scheduleFrameForMonitor(mon);
}
void CMonitorFrameScheduler::onFrame() {
@ -100,20 +104,12 @@ void CMonitorFrameScheduler::onFrame() {
return;
}
if (!m_renderAtFrame) {
Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> frame event, but m_renderAtFrame = false.", m_monitor->m_name);
return;
}
Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> frame event, render = true, rendering normally.", m_monitor->m_name);
m_lastRenderBegun = hrc::now();
// get a ref to ourselves. renderMonitor can destroy this scheduler if it decides to perform a monitor reload
// FIXME: this is horrible. "renderMonitor" should not be able to do that.
auto self = m_self;
g_pHyprRenderer->renderMonitor(m_monitor.lock());
g_pHyprRenderer->renderMonitor(m_monitor.lock(), true, (m_renderAtFrame && !m_pendingThird));
if (!self)
return;
@ -122,8 +118,12 @@ void CMonitorFrameScheduler::onFrame() {
}
void CMonitorFrameScheduler::onFinishRender() {
m_sync = CEGLSync::create(); // this destroys the old sync
g_pEventLoopManager->doOnReadable(m_sync->fd().duplicate(), [this, self = m_self] {
if (!m_monitor->m_inFence.isValid()) {
Log::logger->log(Log::ERR, "CMonitorFrameScheduler: {} -> onFinishRender, m_inFence is not valid.", m_monitor->m_name);
return;
}
g_pEventLoopManager->doOnReadable(m_monitor->m_inFence.duplicate(), [this, self = m_self] {
if (!self) // might've gotten destroyed
return;
onSyncFired();

View file

@ -18,7 +18,7 @@ class CMonitorFrameScheduler {
CMonitorFrameScheduler& operator=(CMonitorFrameScheduler&&) = delete;
void onSyncFired();
void onPresented();
void onPresented(const Time::steady_tp& when);
void onFrame();
private:
@ -28,12 +28,10 @@ class CMonitorFrameScheduler {
bool m_renderAtFrame = true;
bool m_pendingThird = false;
bool m_skipThird = false;
hrc::time_point m_lastRenderBegun;
PHLMONITORREF m_monitor;
UP<CEGLSync> m_sync;
WP<CMonitorFrameScheduler> m_self;
friend class CMonitor;

View file

@ -17,6 +17,7 @@
#include "../desktop/state/FocusState.hpp"
#include "SeatManager.hpp"
#include "../helpers/time/Time.hpp"
#include "../managers/SurfaceManager.hpp"
#include <cstring>
#include <gbm.h>
#include <cairo/cairo.h>
@ -160,7 +161,7 @@ void CPointerManager::setCursorSurface(SP<Desktop::View::CWLSurface> surf, const
if (surf->resource()->m_current.texture) {
m_currentCursorImage.size = surf->resource()->m_current.bufferSize;
surf->resource()->frame(Time::steadyNow());
g_pSurfaceManager->scheduleForFrame(Desktop::focusState()->monitor(), surf->resource());
}
}
@ -597,7 +598,8 @@ void CPointerManager::renderSoftwareCursorsFor(PHLMONITOR pMonitor, const Time::
if (!state->hardwareFailed && state->softwareLocks == 0 && !forceRender) {
if (m_currentCursorImage.surface)
m_currentCursorImage.surface->resource()->frame(now);
g_pSurfaceManager->scheduleForFrame(pMonitor, m_currentCursorImage.surface->resource());
return;
}
@ -632,7 +634,7 @@ void CPointerManager::renderSoftwareCursorsFor(PHLMONITOR pMonitor, const Time::
g_pHyprRenderer->m_renderPass.add(makeUnique<CTexPassElement>(std::move(data)));
if (m_currentCursorImage.surface)
m_currentCursorImage.surface->resource()->frame(now);
g_pSurfaceManager->scheduleForFrame(pMonitor, m_currentCursorImage.surface->resource());
}
Vector2D CPointerManager::getCursorPosForMonitor(PHLMONITOR pMonitor) {

View file

@ -0,0 +1,127 @@
#include "SurfaceManager.hpp"
#include "../helpers/Monitor.hpp"
#include "managers/eventLoop/EventLoopManager.hpp"
#include "render/OpenGL.hpp"
#include <sys/ioctl.h>
using namespace Hyprutils::OS;
#if defined(__linux__)
#include <linux/sync_file.h>
#else
struct sync_merge_data {
char name[32];
__s32 fd2;
__s32 fence;
__u32 flags;
__u32 pad;
};
#define SYNC_IOC_MAGIC '>'
#define SYNC_IOC_MERGE _IOWR(SYNC_IOC_MAGIC, 3, struct sync_merge_data)
#endif
static CFileDescriptor mergeSyncFds(const CFileDescriptor& fd1, const CFileDescriptor& fd2) {
// combines the fences of both sync_fds into a dma_fence_array (https://www.kernel.org/doc/html/latest/driver-api/dma-buf.html#c.dma_fence_array_create)
// with the signal_on_any param set to false, so the new sync_fd will "signal when all fences in the array signal."
struct sync_merge_data data{
.name = "merged release fence",
.fd2 = fd2.get(),
.fence = -1,
};
int err = -1;
do {
err = ioctl(fd1.get(), SYNC_IOC_MERGE, &data);
} while (err == -1 && (errno == EINTR || errno == EAGAIN));
if (err < 0)
return CFileDescriptor{};
else
return CFileDescriptor(data.fence);
}
bool CSurfaceManager::addBuffer(PHLMONITORREF monitor, const CHLBufferReference& buf) {
if (!monitor)
return false;
auto it = std::ranges::find_if(m_buffers[monitor], [&buf](auto& b) { return b == buf; });
if (it != m_buffers[monitor].end())
return false;
m_buffers[monitor].emplace_back(buf);
return true;
}
bool CSurfaceManager::addFrameCallback(WP<CWLSurfaceResource> surf, SP<CWLCallbackResource> cb) {
auto it = std::ranges::find_if(m_frameCallbacks[surf], [&cb](auto& c) { return c == cb; });
if (it != m_frameCallbacks[surf].end())
return false;
m_frameCallbacks[surf].emplace_back(cb);
return true;
}
void CSurfaceManager::addFence(PHLMONITORREF monitor) {
if (g_pHyprOpenGL->explicitSyncSupported() && monitor->m_inFence.isValid()) {
for (auto& b : m_buffers[monitor]) {
if (!b->m_syncReleasers.empty()) {
for (auto& releaser : b->m_syncReleasers) {
releaser->addSyncFileFd(monitor->m_inFence);
}
} else {
if (b->m_syncDropFd.isValid())
b->m_syncDropFd = mergeSyncFds(b->m_syncDropFd, monitor->m_inFence.duplicate());
else
b->m_syncDropFd = monitor->m_inFence.duplicate();
}
}
}
}
void CSurfaceManager::dropBuffers(PHLMONITORREF monitor) {
if (g_pHyprOpenGL->explicitSyncSupported()) {
std::erase_if(m_buffers[monitor], [](auto& b) { return !b->m_syncReleasers.empty(); });
for (auto& b : m_buffers[monitor]) {
g_pEventLoopManager->doOnReadable(b->m_syncDropFd.duplicate(), [buf = b] mutable {});
}
}
m_buffers[monitor].clear();
std::erase_if(m_buffers, [](auto& b) { return !b.first; }); // if monitor is gone.
}
void CSurfaceManager::sendFrameCallbacks(WP<CWLSurfaceResource> surf, const Time::steady_tp& now) {
if (surf) {
for (auto& cb : m_frameCallbacks[surf]) {
cb->send(now);
}
m_frameCallbacks.erase(surf);
}
std::erase_if(m_frameCallbacks, [](auto& b) { return !b.first; }); // if surface is gone.
}
void CSurfaceManager::scheduleForFrame(PHLMONITORREF monitor, WP<CWLSurfaceResource> surf) {
auto it = std::ranges::find_if(m_scheduledForFrame[monitor], [&surf](auto& b) { return b == surf; });
if (it != m_scheduledForFrame[monitor].end()) // already scheduled
return;
m_scheduledForFrame[monitor].emplace_back(surf);
}
void CSurfaceManager::sendScheduledFrames(PHLMONITORREF monitor, const Time::steady_tp& now) {
for (auto& f : m_scheduledForFrame[monitor]) {
sendFrameCallbacks(f, now);
}
std::erase_if(m_scheduledForFrame, [](auto& b) { return !b.first; }); // if monitor is gone.
}
void CSurfaceManager::destroy(PHLMONITORREF monitor) {
m_buffers.erase(monitor);
m_scheduledForFrame.erase(monitor);
}

View file

@ -0,0 +1,25 @@
#pragma once
#include "../defines.hpp"
#include "protocols/core/Compositor.hpp"
#include "protocols/types/Buffer.hpp"
class CSurfaceManager {
public:
CSurfaceManager() = default;
bool addBuffer(PHLMONITORREF monitor, const CHLBufferReference& buf);
bool addFrameCallback(WP<CWLSurfaceResource>, SP<CWLCallbackResource>);
void addFence(PHLMONITORREF monitor);
void dropBuffers(PHLMONITORREF monitor);
void sendFrameCallbacks(WP<CWLSurfaceResource> surf, const Time::steady_tp& now);
void scheduleForFrame(PHLMONITORREF monitor, WP<CWLSurfaceResource> surf);
void sendScheduledFrames(PHLMONITORREF monitor, const Time::steady_tp& now);
void destroy(PHLMONITORREF monitor);
private:
std::unordered_map<PHLMONITORREF, std::vector<CHLBufferReference>> m_buffers;
std::unordered_map<WP<CWLSurfaceResource>, std::vector<SP<CWLCallbackResource>>> m_frameCallbacks;
std::unordered_map<PHLMONITORREF, std::vector<WP<CWLSurfaceResource>>> m_scheduledForFrame;
};
inline UP<CSurfaceManager> g_pSurfaceManager;

View file

@ -14,6 +14,8 @@
#include "../../render/Renderer.hpp"
#include "config/ConfigValue.hpp"
#include "../../managers/eventLoop/EventLoopManager.hpp"
#include "../../managers/SurfaceManager.hpp"
#include "../../desktop/state/FocusState.hpp"
#include "protocols/types/SurfaceRole.hpp"
#include "render/Texture.hpp"
#include <cstring>
@ -225,10 +227,8 @@ CWLSurfaceResource::CWLSurfaceResource(SP<CWlSurface> resource_) : m_resource(re
m_pending.opaque = RG->m_region;
});
m_resource->setFrame([this](CWlSurface* r, uint32_t id) {
m_pending.updated.bits.frame = true;
m_pending.callbacks.emplace_back(makeShared<CWLCallbackResource>(makeShared<CWlCallback>(m_client, 1, id)));
});
m_resource->setFrame(
[this](CWlSurface* r, uint32_t id) { g_pSurfaceManager->addFrameCallback(m_self, makeShared<CWLCallbackResource>(makeShared<CWlCallback>(m_client, 1, id))); });
m_resource->setOffset([this](CWlSurface* r, int32_t x, int32_t y) {
m_pending.updated.bits.offset = true;
@ -328,17 +328,6 @@ void CWLSurfaceResource::sendPreferredScale(int32_t scale) {
m_resource->sendPreferredBufferScale(scale);
}
void CWLSurfaceResource::frame(const Time::steady_tp& now) {
if (m_current.callbacks.empty())
return;
for (auto const& c : m_current.callbacks) {
c->send(now);
}
m_current.callbacks.clear();
}
void CWLSurfaceResource::resetRole() {
m_role = makeShared<CDefaultSurfaceRole>();
}
@ -445,7 +434,7 @@ void CWLSurfaceResource::map() {
m_mapped = true;
frame(Time::steadyNow());
g_pSurfaceManager->scheduleForFrame(Desktop::focusState()->monitor(), m_self);
m_current.bufferDamage = CBox{{}, m_current.bufferSize};
m_pending.bufferDamage = CBox{{}, m_pending.bufferSize};
@ -653,7 +642,6 @@ void CWLSurfaceResource::updateCursorShm(CRegion damage) {
}
void CWLSurfaceResource::presentFeedback(const Time::steady_tp& when, PHLMONITOR pMonitor, bool discarded) {
frame(when);
auto FEEDBACK = makeUnique<CQueuedPresentationData>(m_self.lock());
FEEDBACK->attachMonitor(pMonitor);
if (discarded)
@ -661,6 +649,7 @@ void CWLSurfaceResource::presentFeedback(const Time::steady_tp& when, PHLMONITOR
else
FEEDBACK->presented();
PROTO::presentation->queueData(std::move(FEEDBACK));
g_pSurfaceManager->scheduleForFrame(pMonitor, m_self);
}
CWLCompositorResource::CWLCompositorResource(SP<CWlCompositor> resource_) : m_resource(resource_) {

View file

@ -82,7 +82,6 @@ class CWLSurfaceResource {
void leave(PHLMONITOR monitor);
void sendPreferredTransform(wl_output_transform t);
void sendPreferredScale(int32_t scale);
void frame(const Time::steady_tp& now);
uint32_t id();
void map();
void unmap();

View file

@ -15,6 +15,7 @@
#include "../../helpers/Monitor.hpp"
#include "../../render/Renderer.hpp"
#include "../../xwayland/Dnd.hpp"
#include "../../managers/SurfaceManager.hpp"
using namespace Hyprutils::OS;
CWLDataOfferResource::CWLDataOfferResource(SP<CWlDataOffer> resource_, SP<IDataSource> source_) : m_source(source_), m_resource(resource_) {
@ -836,7 +837,7 @@ void CWLDataDeviceProtocol::renderDND(PHLMONITOR pMonitor, const Time::steady_tp
CBox damageBox = CBox{surfacePos, m_dnd.dndSurface->m_current.size}.expand(5);
g_pHyprRenderer->damageBox(damageBox);
m_dnd.dndSurface->frame(when);
g_pSurfaceManager->scheduleForFrame(pMonitor, m_dnd.dndSurface);
}
bool CWLDataDeviceProtocol::dndActive() {

View file

@ -31,6 +31,7 @@ class IHLBuffer : public Aquamarine::IBuffer {
SP<CWLBufferResource> m_resource;
std::vector<UP<CSyncReleaser>> m_syncReleasers;
Hyprutils::OS::CFileDescriptor m_syncFd;
Hyprutils::OS::CFileDescriptor m_syncDropFd;
struct {
CHyprSignalListener backendRelease;

View file

@ -61,7 +61,6 @@ void SSurfaceState::reset() {
damage.clear();
bufferDamage.clear();
callbacks.clear();
lockMask = LOCK_REASON_NONE;
}
@ -107,9 +106,4 @@ void SSurfaceState::updateFrom(SSurfaceState& ref) {
if (ref.updated.bits.acked)
ackedSize = ref.ackedSize;
if (ref.updated.bits.frame) {
callbacks.insert(callbacks.end(), std::make_move_iterator(ref.callbacks.begin()), std::make_move_iterator(ref.callbacks.end()));
ref.callbacks.clear();
}
}

View file

@ -47,7 +47,6 @@ struct SSurfaceState {
bool viewport : 1;
bool acquire : 1;
bool acked : 1;
bool frame : 1;
} bits;
} updated;
@ -68,9 +67,6 @@ struct SSurfaceState {
// for xdg_shell resizing
Vector2D ackedSize;
// for wl_surface::frame callbacks.
std::vector<SP<CWLCallbackResource>> callbacks;
// viewporter protocol surface state
struct {
bool hasDestination = false;

View file

@ -16,6 +16,7 @@
#include "../desktop/view/LayerSurface.hpp"
#include "../desktop/view/GlobalViewMethods.hpp"
#include "../desktop/state/FocusState.hpp"
#include "../managers/SurfaceManager.hpp"
#include "../protocols/SessionLock.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/XDGShell.hpp"
@ -170,9 +171,10 @@ CHyprRenderer::CHyprRenderer() {
if (!w->wlSurface() || !w->wlSurface()->resource() || shouldRenderWindow(w.lock()))
continue;
w->wlSurface()->resource()->frame(Time::steadyNow());
g_pSurfaceManager->scheduleForFrame(Desktop::focusState()->monitor(), w->wlSurface()->resource());
auto FEEDBACK = makeUnique<CQueuedPresentationData>(w->wlSurface()->resource());
FEEDBACK->attachMonitor(Desktop::focusState()->monitor());
FEEDBACK->discarded();
PROTO::presentation->queueData(std::move(FEEDBACK));
}
@ -1260,7 +1262,7 @@ void CHyprRenderer::calculateUVForSurface(PHLWINDOW pWindow, SP<CWLSurfaceResour
}
}
void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit, bool dropBuffers) {
static std::chrono::high_resolution_clock::time_point renderStart = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point renderStartOverlay = std::chrono::high_resolution_clock::now();
static std::chrono::high_resolution_clock::time_point endRenderOverlay = std::chrono::high_resolution_clock::now();
@ -1488,7 +1490,7 @@ void CHyprRenderer::renderMonitor(PHLMONITOR pMonitor, bool commit) {
Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
if (commit)
commitPendingAndDoExplicitSync(pMonitor);
commitPendingAndDoExplicitSync(pMonitor, dropBuffers);
if (shouldTear)
pMonitor->m_tearingState.busy = true;
@ -1555,7 +1557,7 @@ static hdr_output_metadata createHDRMetadata(SImageDescription settings, S
};
}
bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor, bool dropBuffers) {
static auto PCT = CConfigValue<Hyprlang::INT>("render:send_content_type");
static auto PPASS = CConfigValue<Hyprlang::INT>("render:cm_fs_passthrough");
static auto PAUTOHDR = CConfigValue<Hyprlang::INT>("render:cm_auto_hdr");
@ -1674,6 +1676,28 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(PHLMONITOR pMonitor) {
pMonitor->m_previousFSWindow = FS_WINDOW;
if (!g_pHyprOpenGL->explicitSyncSupported()) {
static auto PNVIDIAANTIFLICKER = CConfigValue<Hyprlang::INT>("opengl:nvidia_anti_flicker");
Log::logger->log(Log::TRACE, "renderer: Explicit sync unsupported, falling back to implicit in endRender");
// nvidia doesn't have implicit sync, so we have to explicitly wait here, llvmpipe and other software renderer seems to bug out aswell.
if ((isNvidia() && *PNVIDIAANTIFLICKER) || isSoftware())
glFinish();
else
glFlush(); // mark an implicit sync point
pMonitor->m_inFence.reset();
} else {
if (pMonitor->m_inFence.isValid()) {
if (m_renderMode == RENDER_MODE_NORMAL) {
pMonitor->m_output->state->setExplicitInFence(pMonitor->m_inFence.get());
}
}
}
if (dropBuffers)
g_pSurfaceManager->dropBuffers(pMonitor);
bool ok = pMonitor->m_state.commit();
if (!ok) {
if (pMonitor->m_inFence.isValid()) {
@ -1714,7 +1738,7 @@ void CHyprRenderer::sendFrameEventsToWorkspace(PHLMONITOR pMonitor, PHLWORKSPACE
if (!view->aliveAndVisible())
continue;
view->wlSurface()->resource()->frame(now);
g_pSurfaceManager->scheduleForFrame(pMonitor, view->wlSurface()->resource());
}
}
@ -2358,42 +2382,29 @@ void CHyprRenderer::endRender(const std::function<void()>& renderingDoneCallback
else
glFlush(); // mark an implicit sync point
m_usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works
if (renderingDoneCallback)
renderingDoneCallback();
} else {
UP<CEGLSync> eglSync = CEGLSync::create();
if (eglSync && eglSync->isValid()) {
if (renderingDoneCallback) {
g_pEventLoopManager->doOnReadable(eglSync->fd().duplicate(), [renderingDoneCallback]() {
if (renderingDoneCallback)
renderingDoneCallback();
});
}
return;
}
UP<CEGLSync> eglSync = CEGLSync::create();
if (eglSync && eglSync->isValid()) {
for (auto const& buf : m_usedAsyncBuffers) {
for (const auto& releaser : buf->m_syncReleasers) {
releaser->addSyncFileFd(eglSync->fd());
if (m_renderMode == RENDER_MODE_NORMAL) {
PMONITOR->m_inFence = eglSync->takeFd();
g_pSurfaceManager->addFence(PMONITOR);
}
} else {
Log::logger->log(Log::ERR, "renderer: Explicit sync failed, calling renderingDoneCallback without sync");
if (renderingDoneCallback) {
Log::logger->log(Log::ERR, "renderer: Explicit sync failed, calling renderingDoneCallback without sync");
renderingDoneCallback();
}
}
// release buffer refs with release points now, since syncReleaser handles actual buffer release based on EGLSync
std::erase_if(m_usedAsyncBuffers, [](const auto& buf) { return !buf->m_syncReleasers.empty(); });
// release buffer refs without release points when EGLSync sync_file/fence is signalled
g_pEventLoopManager->doOnReadable(eglSync->fd().duplicate(), [renderingDoneCallback, prevbfs = std::move(m_usedAsyncBuffers)]() mutable {
prevbfs.clear();
if (renderingDoneCallback)
renderingDoneCallback();
});
m_usedAsyncBuffers.clear();
if (m_renderMode == RENDER_MODE_NORMAL) {
PMONITOR->m_inFence = eglSync->takeFd();
PMONITOR->m_output->state->setExplicitInFence(PMONITOR->m_inFence.get());
}
} else {
Log::logger->log(Log::ERR, "renderer: Explicit sync failed, releasing resources");
m_usedAsyncBuffers.clear(); // release all buffer refs and hope implicit sync works
if (renderingDoneCallback)
renderingDoneCallback();
}
}

View file

@ -51,7 +51,7 @@ class CHyprRenderer {
CHyprRenderer();
~CHyprRenderer();
void renderMonitor(PHLMONITOR pMonitor, bool commit = true);
void renderMonitor(PHLMONITOR pMonitor, bool commit = true, bool dropBuffers = true);
void arrangeLayersForMonitor(const MONITORID&);
void damageSurface(SP<CWLSurfaceResource>, double, double, double scale = 1.0);
void damageWindow(PHLWINDOW, bool forceFull = false);
@ -94,18 +94,16 @@ class CHyprRenderer {
bool m_bBlockSurfaceFeedback = false;
bool m_bRenderingSnapshot = false;
PHLMONITORREF m_mostHzMonitor;
bool m_directScanoutBlocked = false;
PHLMONITORREF m_mostHzMonitor;
bool m_directScanoutBlocked = false;
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
void initiateManualCrash();
void setSurfaceScanoutMode(SP<CWLSurfaceResource> surface, PHLMONITOR monitor); // nullptr monitor resets
void initiateManualCrash();
bool m_crashingInProgress = false;
float m_crashingDistort = 0.5f;
wl_event_source* m_crashingLoop = nullptr;
wl_event_source* m_cursorTicker = nullptr;
std::vector<CHLBufferReference> m_usedAsyncBuffers;
bool m_crashingInProgress = false;
float m_crashingDistort = 0.5f;
wl_event_source* m_crashingLoop = nullptr;
wl_event_source* m_cursorTicker = nullptr;
struct {
int hotspotX = 0;
@ -135,7 +133,7 @@ class CHyprRenderer {
void renderSessionLockMissing(PHLMONITOR pMonitor);
void renderBackground(PHLMONITOR pMonitor);
bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor);
bool commitPendingAndDoExplicitSync(PHLMONITOR pMonitor, bool dropBuffers);
bool shouldBlur(PHLLS ls);
bool shouldBlur(PHLWINDOW w);

View file

@ -5,7 +5,9 @@
#include "../../protocols/core/Compositor.hpp"
#include "../../protocols/DRMSyncobj.hpp"
#include "../../managers/input/InputManager.hpp"
#include "../../managers/SurfaceManager.hpp"
#include "../Renderer.hpp"
#include "../../Compositor.hpp"
#include <hyprutils/math/Box.hpp>
#include <hyprutils/math/Vector2D.hpp>
@ -154,8 +156,30 @@ void CSurfacePassElement::draw(const CRegion& damage) {
// add async (dmabuf) buffers to usedBuffers so we can handle release later
// sync (shm) buffers will be released in commitState, so no need to track them here
if (m_data.surface->m_current.buffer && !m_data.surface->m_current.buffer->isSynchronous())
g_pHyprRenderer->m_usedAsyncBuffers.emplace_back(m_data.surface->m_current.buffer);
if (m_data.surface->m_current.buffer && !m_data.surface->m_current.buffer->isSynchronous()) {
for (auto& m : g_pCompositor->m_monitors) {
if (!m)
continue;
if (m_data.pMonitor == m || (m_data.pWindow && m_data.pWindow->visibleOnMonitor(m))) {
g_pSurfaceManager->addBuffer(m, m_data.surface->m_current.buffer);
if (m_data.pMonitor != m) {
CBox wbox = {m_data.pWindow->m_realPosition->value(), m_data.pWindow->m_realSize->value()};
if (m_data.pWindow->m_isFloating)
wbox = m_data.pWindow->getFullWindowBoundingBox();
CBox monbox = {m->m_position, m->m_size};
CBox damageBox = wbox.intersection(monbox);
if (!damageBox.empty()) {
m->addDamage(damageBox);
g_pCompositor->scheduleFrameForMonitor(m, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME);
}
}
}
}
}
g_pHyprOpenGL->blend(true);
}