Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Compositor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,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"
Expand Down Expand Up @@ -668,6 +669,8 @@ void CCompositor::initManagers(eManagersInitStage stage) {
Desktop::History::windowTracker();
Desktop::History::workspaceTracker();

Log::logger->log(Log::DEBUG, "Creating the CSurfaceManager!");
g_pSurfaceManager = makeUnique<CSurfaceManager>();
} break;
case STAGE_LATE: {
Log::logger->log(Log::DEBUG, "Creating CHyprCtl");
Expand Down
12 changes: 7 additions & 5 deletions src/helpers/Monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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++;
Expand All @@ -140,7 +142,7 @@ void CMonitor::onConnect(bool noRule) {
});
}

m_frameScheduler->onPresented();
m_frameScheduler->onPresented(now);

m_events.presented.emit();
});
Expand Down
62 changes: 31 additions & 31 deletions src/helpers/MonitorFrameScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
;
Expand All @@ -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
Expand All @@ -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);

Expand All @@ -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;

Log::logger->log(Log::TRACE, "CMonitorFrameScheduler: {} -> onPresented, missed, committing pending at the earliest convenience.", m_monitor->m_name);

m_pendingThird = false;
auto mon = m_monitor.lock();

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.
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;

// 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() {
Expand All @@ -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;
Expand All @@ -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();
Expand Down
6 changes: 2 additions & 4 deletions src/helpers/MonitorFrameScheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class CMonitorFrameScheduler {
CMonitorFrameScheduler& operator=(CMonitorFrameScheduler&&) = delete;

void onSyncFired();
void onPresented();
void onPresented(const Time::steady_tp& when);
void onFrame();

private:
Expand All @@ -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;
Expand Down
8 changes: 5 additions & 3 deletions src/managers/PointerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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());
}
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down
127 changes: 127 additions & 0 deletions src/managers/SurfaceManager.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
25 changes: 25 additions & 0 deletions src/managers/SurfaceManager.hpp
Original file line number Diff line number Diff line change
@@ -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;
Loading
Loading