Skip to content
Merged
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 @@ -450,6 +450,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
7 changes: 7 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 Expand Up @@ -1793,6 +1795,7 @@ bool CMonitor::attemptDirectScanout() {

auto PBUFFER = PSURFACE->m_current.buffer.m_buffer;

// #TODO this entire bit needs figuring out, vrr goes down the drain without it
if (PBUFFER == m_output->state->state().buffer) {
PSURFACE->presentFeedback(Time::steadyNow(), m_self.lock());

Expand All @@ -1811,6 +1814,10 @@ bool CMonitor::attemptDirectScanout() {
m_scanoutNeedsCursorUpdate = false;
}

//#TODO this entire bit is bootleg deluxe, above bit is to not make vrr go down the drain, returning early here means fifo gets forever locked.
if (PSURFACE->m_fifo)
PSURFACE->m_stateQueue.unlockFirst(LOCK_REASON_FIFO);

return true;
}

Expand Down
1 change: 1 addition & 0 deletions src/helpers/Monitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,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
140 changes: 140 additions & 0 deletions src/protocols/CommitTiming.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#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->setData(this);
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) {
return;

if (!m_surface) {
r->error(WP_COMMIT_TIMER_V1_ERROR_SURFACE_DESTROYED, "Surface was gone");
return;
}

if (m_pendingTimeout.has_value()) {
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.
m_pendingTimeout = Time::steady_dur::min();
} else
m_pendingTimeout = TIME - TIME_NOW;
});

m_listeners.surfaceStateCommit = m_surface->m_events.stateCommit2.listen([this](auto state) {
if (!m_pendingTimeout.has_value())
return;

m_surface->m_stateQueue.lock(state, LOCK_REASON_TIMER);

if (!m_timerPresent) {
m_timerPresent = true;
timer = makeShared<CEventLoopTimer>(
m_pendingTimeout,
[this](SP<CEventLoopTimer> self, void* data) {
if (!m_surface)
return;

m_surface->m_stateQueue.unlockFirst(LOCK_REASON_TIMER);
},
nullptr);
} else
timer->updateTimeout(m_pendingTimeout);

m_pendingTimeout.reset();
});
}

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->setData(this);
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;
}

if (surf->m_commitTimer) {
r->error(WP_COMMIT_TIMING_MANAGER_V1_ERROR_COMMIT_TIMER_EXISTS, "Surface already has a commit timing");
return;
}

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

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

surf->m_commitTimer = RESOURCE;
});
}

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; });
}
67 changes: 67 additions & 0 deletions src/protocols/CommitTiming.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#pragma once

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

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

class CWLSurfaceResource;
class CEventLoopTimer;

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

bool good();

private:
UP<CWpCommitTimerV1> m_resource;
WP<CWLSurfaceResource> m_surface;
bool m_timerPresent = false;
std::optional<Time::steady_dur> m_pendingTimeout;
SP<CEventLoopTimer> timer;

struct {
CHyprSignalListener surfaceStateCommit;
} 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;
};
21 changes: 11 additions & 10 deletions src/protocols/DRMSyncobj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,38 +74,39 @@ CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(UP<CWpLinuxDrmSyncobjSurf
m_pendingRelease = {timeline->m_timeline, (sc<uint64_t>(hi) << 32) | sc<uint64_t>(lo)};
});

m_listeners.surfacePrecommit = m_surface->m_events.precommit.listen([this] {
if (!m_surface->m_pending.updated.bits.buffer || !m_surface->m_pending.buffer) {
m_listeners.surfaceStateCommit = m_surface->m_events.stateCommit.listen([this](auto state) {
if (!state->updated.bits.buffer || !state->buffer) {
if (m_pendingAcquire.timeline() || m_pendingRelease.timeline()) {
m_resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer");
m_surface->m_pending.rejected = true;
state->rejected = true;
}
return;
}

if (!m_pendingAcquire.timeline()) {
m_resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing acquire timeline");
m_surface->m_pending.rejected = true;
state->rejected = true;
return;
}

if (!m_pendingRelease.timeline()) {
m_resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT, "Missing release timeline");
m_surface->m_pending.rejected = true;
state->rejected = true;
return;
}

if (m_pendingAcquire.timeline() == m_pendingRelease.timeline() && m_pendingAcquire.point() >= m_pendingRelease.point()) {
m_resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_CONFLICTING_POINTS, "Acquire and release points are on the same timeline, and acquire >= release");
m_surface->m_pending.rejected = true;
state->rejected = true;
return;
}

m_surface->m_pending.updated.bits.acquire = true;
m_surface->m_pending.acquire = m_pendingAcquire;
m_pendingAcquire = {};
state->updated.bits.acquire = true;
state->acquire = m_pendingAcquire;
m_surface->m_stateQueue.lock(state, LOCK_REASON_FENCE);
m_pendingAcquire = {};

m_surface->m_pending.buffer->addReleasePoint(m_pendingRelease);
state->buffer->addReleasePoint(m_pendingRelease);
m_pendingRelease = {};
});
}
Expand Down
2 changes: 1 addition & 1 deletion src/protocols/DRMSyncobj.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class CDRMSyncobjSurfaceResource {
CDRMSyncPointState m_pendingRelease;

struct {
CHyprSignalListener surfacePrecommit;
CHyprSignalListener surfaceStateCommit;
} m_listeners;
};

Expand Down
Loading
Loading