Skip to content
Closed
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
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,8 @@ protocolnew("staging/xdg-system-bell" "xdg-system-bell-v1" false)
protocolnew("staging/ext-workspace" "ext-workspace-v1" false)
protocolnew("staging/ext-data-control" "ext-data-control-v1" false)
protocolnew("staging/pointer-warp" "pointer-warp-v1" false)
protocolnew("staging/fifo" "fifo-v1" false)
protocolnew("staging/commit-timing" "commit-timing-v1" false)

protocolwayland()

Expand Down
2 changes: 2 additions & 0 deletions protocols/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ protocols = [
wayland_protocol_dir / 'staging/ext-workspace/ext-workspace-v1.xml',
wayland_protocol_dir / 'staging/ext-data-control/ext-data-control-v1.xml',
wayland_protocol_dir / 'staging/pointer-warp/pointer-warp-v1.xml',
wayland_protocol_dir / 'staging/fifo/fifo-v1.xml',
wayland_protocol_dir / 'staging/commit-timing/commit-timing-v1.xml',
]

wl_protocols = []
Expand Down
2 changes: 2 additions & 0 deletions src/helpers/Monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ void CMonitor::onConnect(bool noRule) {
}

m_frameScheduler->onPresented();

m_events.presented.emit();
});

m_listeners.destroy = m_output->events.destroy.listen([this] {
Expand Down
1 change: 1 addition & 0 deletions src/helpers/Monitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ class CMonitor {
CSignalT<> disconnect;
CSignalT<> dpmsChanged;
CSignalT<> modeChanged;
CSignalT<> presented;
} m_events;

std::array<std::vector<PHLLSREF>, 4> m_layerSurfaceLayers;
Expand Down
8 changes: 8 additions & 0 deletions src/managers/ProtocolManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
#include "../protocols/ExtWorkspace.hpp"
#include "../protocols/ExtDataDevice.hpp"
#include "../protocols/PointerWarp.hpp"
#include "../protocols/Fifo.hpp"
#include "../protocols/CommitTiming.hpp"

#include "../helpers/Monitor.hpp"
#include "../render/Renderer.hpp"
Expand Down Expand Up @@ -194,6 +196,8 @@ CProtocolManager::CProtocolManager() {
PROTO::extWorkspace = makeUnique<CExtWorkspaceProtocol>(&ext_workspace_manager_v1_interface, 1, "ExtWorkspace");
PROTO::extDataDevice = makeUnique<CExtDataDeviceProtocol>(&ext_data_control_manager_v1_interface, 1, "ExtDataDevice");
PROTO::pointerWarp = makeUnique<CPointerWarpProtocol>(&wp_pointer_warp_v1_interface, 1, "PointerWarp");
PROTO::fifo = makeUnique<CFifoProtocol>(&wp_fifo_manager_v1_interface, 1, "Fifo");
PROTO::commitTiming = makeUnique<CCommitTimingProtocol>(&wp_commit_timing_manager_v1_interface, 1, "CommitTiming");

if (*PENABLECM)
PROTO::colorManagement = makeUnique<CColorManagementProtocol>(&wp_color_manager_v1_interface, 1, "ColorManagement", *PDEBUGCM);
Expand Down Expand Up @@ -298,6 +302,8 @@ CProtocolManager::~CProtocolManager() {
PROTO::extWorkspace.reset();
PROTO::extDataDevice.reset();
PROTO::pointerWarp.reset();
PROTO::fifo.reset();
PROTO::commitTiming.reset();

for (auto& [_, lease] : PROTO::lease) {
lease.reset();
Expand Down Expand Up @@ -353,6 +359,8 @@ bool CProtocolManager::isGlobalPrivileged(const wl_global* global) {
PROTO::hyprlandSurface->getGlobal(),
PROTO::xdgTag->getGlobal(),
PROTO::xdgBell->getGlobal(),
PROTO::fifo->getGlobal(),
PROTO::commitTiming->getGlobal(),
PROTO::sync ? PROTO::sync->getGlobal() : nullptr,
PROTO::mesaDRM ? PROTO::mesaDRM->getGlobal() : nullptr,
PROTO::linuxDma ? PROTO::linuxDma->getGlobal() : nullptr,
Expand Down
132 changes: 132 additions & 0 deletions src/protocols/CommitTiming.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#include "CommitTiming.hpp"
#include "core/Compositor.hpp"
#include "../managers/eventLoop/EventLoopManager.hpp"
#include "../managers/eventLoop/EventLoopTimer.hpp"

CCommitTimerResource::CCommitTimerResource(UP<CWpCommitTimerV1>&& resource_, SP<CWLSurfaceResource> surface) : m_resource(std::move(resource_)), m_surface(surface) {
if UNLIKELY (!m_resource->resource())
return;

m_resource->setDestroy([this](CWpCommitTimerV1* r) { PROTO::commitTiming->destroyResource(this); });
m_resource->setOnDestroy([this](CWpCommitTimerV1* r) { PROTO::commitTiming->destroyResource(this); });

m_resource->setSetTimestamp([this](CWpCommitTimerV1* r, uint32_t tvHi, uint32_t tvLo, uint32_t tvNsec) {
if (!m_surface) {
r->error(WP_COMMIT_TIMER_V1_ERROR_SURFACE_DESTROYED, "Surface was gone");
return;
}

if (m_timerPresent) {
r->error(WP_COMMIT_TIMER_V1_ERROR_TIMESTAMP_EXISTS, "Timestamp is already set");
return;
}

timespec ts;
ts.tv_sec = (((uint64_t)tvHi) << 32) | (uint64_t)tvLo;
ts.tv_nsec = tvNsec;

const auto TIME = Time::fromTimespec(&ts);
const auto TIME_NOW = Time::steadyNow();

if (TIME_NOW > TIME) {
// TODO: should we err here?
// for now just do nothing I guess, thats some lag.
return;
}

m_timerPresent = true;

// FIXME: this doesn't *exactly* guarantee we wont fire a few dozen ns before
// the desired time...
m_timers.emplace_back(makeShared<STimerLock>(STimerLock{
.timer = makeShared<CEventLoopTimer>(
TIME - TIME_NOW,
[this](SP<CEventLoopTimer> self, void* data) {
// unlock the state if applicable
std::erase_if(m_timers, [self](const auto& e) { return e->timer == self; });
},
nullptr),
.lock = CSurfaceScopeLock::create(m_surface->m_pending.lock),
}));
});

m_listeners.surfacePrecommit = m_surface->m_events.precommit.listen([this] { m_timerPresent = false; });
}

CCommitTimerResource::~CCommitTimerResource() {
;
}

bool CCommitTimerResource::good() {
return m_resource->resource();
}

CCommitTimingManagerResource::CCommitTimingManagerResource(UP<CWpCommitTimingManagerV1>&& resource_) : m_resource(std::move(resource_)) {
if UNLIKELY (!m_resource->resource())
return;

m_resource->setDestroy([this](CWpCommitTimingManagerV1* r) { PROTO::commitTiming->destroyResource(this); });
m_resource->setOnDestroy([this](CWpCommitTimingManagerV1* r) { PROTO::commitTiming->destroyResource(this); });

m_resource->setGetTimer([](CWpCommitTimingManagerV1* r, uint32_t id, wl_resource* surfResource) {
if (!surfResource) {
r->error(-1, "No resource for commit timing");
return;
}

auto surf = CWLSurfaceResource::fromResource(surfResource);

if (!surf) {
r->error(-1, "No surface for commit timing");
return;
}

for (const auto& timer : PROTO::commitTiming->m_timers) {
if (timer->m_surface == surf) {
r->error(WP_COMMIT_TIMING_MANAGER_V1_ERROR_COMMIT_TIMER_EXISTS, "Surface already has a commit timing");
return;
}
}

const auto CLIENT = r->client();
const auto RESOURCE = PROTO::commitTiming->m_timers.emplace_back(makeUnique<CCommitTimerResource>(makeUnique<CWpCommitTimerV1>(CLIENT, r->version(), id), surf)).get();

if (!RESOURCE->good()) {
r->noMemory();
PROTO::commitTiming->m_timers.pop_back();
return;
}

RESOURCE->m_self = PROTO::commitTiming->m_timers.back();
});
}

CCommitTimingManagerResource::~CCommitTimingManagerResource() {
;
}

bool CCommitTimingManagerResource::good() {
return m_resource->resource();
}

CCommitTimingProtocol::CCommitTimingProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}

void CCommitTimingProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_managers.emplace_back(makeUnique<CCommitTimingManagerResource>(makeUnique<CWpCommitTimingManagerV1>(client, ver, id))).get();

if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_managers.pop_back();
return;
}
}

void CCommitTimingProtocol::destroyResource(CCommitTimingManagerResource* res) {
std::erase_if(m_managers, [&](const auto& other) { return other.get() == res; });
}

void CCommitTimingProtocol::destroyResource(CCommitTimerResource* res) {
std::erase_if(m_timers, [&](const auto& other) { return other.get() == res; });
}
76 changes: 76 additions & 0 deletions src/protocols/CommitTiming.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#pragma once

#include <vector>
#include <unordered_map>
#include "WaylandProtocol.hpp"
#include "commit-timing-v1.hpp"

#include "../helpers/signal/Signal.hpp"

class CWLSurfaceResource;
class CEventLoopTimer;
class CSurfaceScopeLock;

class CCommitTimerResource {
public:
CCommitTimerResource(UP<CWpCommitTimerV1>&& resource_, SP<CWLSurfaceResource> surface);
~CCommitTimerResource();

bool good();

WP<CCommitTimerResource> m_self;

private:
UP<CWpCommitTimerV1> m_resource;

WP<CWLSurfaceResource> m_surface;

bool m_timerPresent = false;

struct STimerLock {
SP<CEventLoopTimer> timer;
SP<CSurfaceScopeLock> lock;
};

std::vector<SP<STimerLock>> m_timers;

struct {
CHyprSignalListener surfacePrecommit;
} m_listeners;

friend class CCommitTimingProtocol;
friend class CCommitTimingManagerResource;
};

class CCommitTimingManagerResource {
public:
CCommitTimingManagerResource(UP<CWpCommitTimingManagerV1>&& resource_);
~CCommitTimingManagerResource();

bool good();

private:
UP<CWpCommitTimingManagerV1> m_resource;
};

class CCommitTimingProtocol : public IWaylandProtocol {
public:
CCommitTimingProtocol(const wl_interface* iface, const int& ver, const std::string& name);

virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);

private:
void destroyResource(CCommitTimingManagerResource* resource);
void destroyResource(CCommitTimerResource* resource);

//
std::vector<UP<CCommitTimingManagerResource>> m_managers;
std::vector<UP<CCommitTimerResource>> m_timers;

friend class CCommitTimingManagerResource;
friend class CCommitTimerResource;
};

namespace PROTO {
inline UP<CCommitTimingProtocol> commitTiming;
};
Loading
Loading