From 016da234d0e852de3ef20eb2e89ac58d2a85f6e7 Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:09:54 +0200 Subject: Core: Move to aquamarine (#6608) Moves Hyprland from wlroots to aquamarine for the backend. --------- Signed-off-by: Vaxry Co-authored-by: Mihai Fufezan Co-authored-by: Jan Beich Co-authored-by: vaxerski Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com> Co-authored-by: Tom Englund Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com> Co-authored-by: diniamo --- src/protocols/CursorShape.cpp | 45 +----- src/protocols/DRMLease.cpp | 302 +++++++++++++++++++++++++++++++++++ src/protocols/DRMLease.hpp | 137 ++++++++++++++++ src/protocols/DRMSyncobj.cpp | 183 ++++++++++++++++++++++ src/protocols/DRMSyncobj.hpp | 82 ++++++++++ src/protocols/GammaControl.cpp | 32 ++-- src/protocols/GammaControl.hpp | 2 +- src/protocols/InputMethodV2.cpp | 22 +-- src/protocols/InputMethodV2.hpp | 7 +- src/protocols/LinuxDMABUF.cpp | 311 ++++++++++++++++++++++++++++--------- src/protocols/LinuxDMABUF.hpp | 52 ++++--- src/protocols/MesaDRM.cpp | 42 +++-- src/protocols/MesaDRM.hpp | 2 +- src/protocols/OutputManagement.cpp | 56 +++---- src/protocols/OutputManagement.hpp | 15 +- src/protocols/OutputPower.cpp | 2 +- src/protocols/PresentationTime.cpp | 18 +-- src/protocols/Screencopy.cpp | 52 +++---- src/protocols/Screencopy.hpp | 9 +- src/protocols/Tablet.cpp | 61 ++++---- src/protocols/Tablet.hpp | 5 +- src/protocols/ToplevelExport.cpp | 19 +-- src/protocols/ToplevelExport.hpp | 2 +- src/protocols/Viewporter.cpp | 29 ++-- src/protocols/Viewporter.hpp | 5 +- src/protocols/VirtualKeyboard.cpp | 60 +++---- src/protocols/VirtualKeyboard.hpp | 13 +- src/protocols/VirtualPointer.cpp | 80 ++++------ src/protocols/VirtualPointer.hpp | 31 +++- src/protocols/XDGOutput.cpp | 6 +- src/protocols/XDGShell.cpp | 1 + src/protocols/core/Compositor.cpp | 149 ++++++++++++------ src/protocols/core/Compositor.hpp | 14 +- src/protocols/core/Output.cpp | 10 +- src/protocols/core/Output.hpp | 3 + src/protocols/core/Seat.cpp | 4 +- src/protocols/core/Shm.cpp | 27 ++-- src/protocols/core/Shm.hpp | 8 +- src/protocols/types/Buffer.cpp | 41 +---- src/protocols/types/Buffer.hpp | 82 +++------- src/protocols/types/DMABuffer.cpp | 12 +- src/protocols/types/DMABuffer.hpp | 12 +- src/protocols/types/WLBuffer.cpp | 15 ++ src/protocols/types/WLBuffer.hpp | 8 +- 44 files changed, 1470 insertions(+), 598 deletions(-) create mode 100644 src/protocols/DRMLease.cpp create mode 100644 src/protocols/DRMLease.hpp create mode 100644 src/protocols/DRMSyncobj.cpp create mode 100644 src/protocols/DRMSyncobj.hpp (limited to 'src/protocols') diff --git a/src/protocols/CursorShape.cpp b/src/protocols/CursorShape.cpp index 2f25b22b..812afe53 100644 --- a/src/protocols/CursorShape.cpp +++ b/src/protocols/CursorShape.cpp @@ -1,48 +1,9 @@ #include "CursorShape.hpp" #include +#include "../helpers/CursorShapes.hpp" #define LOGM PROTO::cursorShape->protoLog -// clang-format off -constexpr const char* SHAPE_NAMES[] = { - "invalid", - "default", - "context-menu", - "help", - "pointer", - "progress", - "wait", - "cell", - "crosshair", - "text", - "vertical-text", - "alias", - "copy", - "move", - "no-drop", - "not-allowed", - "grab", - "grabbing", - "e-resize", - "n-resize", - "ne-resize", - "nw-resize", - "s-resize", - "se-resize", - "sw-resize", - "w-resize", - "ew-resize", - "ns-resize", - "nesw-resize", - "nwse-resize", - "col-resize", - "row-resize", - "all-scroll", - "zoom-in", - "zoom-out", -}; -// clang-format on - CCursorShapeProtocol::CCursorShapeProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { ; } @@ -82,7 +43,7 @@ void CCursorShapeProtocol::createCursorShapeDevice(CWpCursorShapeManagerV1* pMgr } void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t serial, wpCursorShapeDeviceV1Shape shape) { - if ((uint32_t)shape == 0 || (uint32_t)shape > sizeof(SHAPE_NAMES)) { + if ((uint32_t)shape == 0 || (uint32_t)shape > CURSOR_SHAPE_NAMES.size()) { pMgr->error(WP_CURSOR_SHAPE_DEVICE_V1_ERROR_INVALID_SHAPE, "The shape is invalid"); return; } @@ -90,7 +51,7 @@ void CCursorShapeProtocol::onSetShape(CWpCursorShapeDeviceV1* pMgr, uint32_t ser SSetShapeEvent event; event.pMgr = pMgr; event.shape = shape; - event.shapeName = SHAPE_NAMES[shape]; + event.shapeName = CURSOR_SHAPE_NAMES.at(shape); events.setShape.emit(event); } \ No newline at end of file diff --git a/src/protocols/DRMLease.cpp b/src/protocols/DRMLease.cpp new file mode 100644 index 00000000..9f5b6312 --- /dev/null +++ b/src/protocols/DRMLease.cpp @@ -0,0 +1,302 @@ +#include "DRMLease.hpp" +#include "../Compositor.hpp" +#include +#include + +#define LOGM PROTO::lease->protoLog + +CDRMLeaseResource::CDRMLeaseResource(SP resource_, SP request) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); }); + resource->setDestroy([this](CWpDrmLeaseV1* r) { PROTO::lease->destroyResource(this); }); + + parent = request->parent; + requested = request->requested; + + for (auto& m : requested) { + if (!m->monitor || m->monitor->isBeingLeased) { + LOGM(ERR, "Rejecting lease: no monitor or monitor is being leased for {}", (m->monitor ? m->monitor->szName : "null")); + resource->sendFinished(); + return; + } + } + + // grant the lease if it is seemingly valid + + LOGM(LOG, "Leasing outputs: {}", [this]() { + std::string roll; + for (auto& o : requested) { + roll += std::format("{} ", o->monitor->szName); + } + return roll; + }()); + + std::vector> outputs; + for (auto& m : requested) { + outputs.emplace_back(m->monitor->output); + } + + auto aqlease = Aquamarine::CDRMLease::create(outputs); + if (!aqlease) { + LOGM(ERR, "Rejecting lease: backend failed to alloc a lease"); + resource->sendFinished(); + return; + } + + LOGM(LOG, "Granting lease, sending fd {}", aqlease->leaseFD); + + resource->sendLeaseFd(aqlease->leaseFD); + + lease = aqlease; + + for (auto& m : requested) { + m->monitor->isBeingLeased = true; + } + + listeners.destroyLease = lease->events.destroy.registerListener([this](std::any d) { + for (auto& m : requested) { + if (m && m->monitor) + m->monitor->isBeingLeased = false; + } + + resource->sendFinished(); + }); + + close(lease->leaseFD); +} + +bool CDRMLeaseResource::good() { + return resource->resource(); +} + +CDRMLeaseRequestResource::CDRMLeaseRequestResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseRequestV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setRequestConnector([this](CWpDrmLeaseRequestV1* r, wl_resource* conn) { + if (!conn) { + resource->error(-1, "Null connector"); + return; + } + + auto CONNECTOR = CDRMLeaseConnectorResource::fromResource(conn); + + if (std::find(requested.begin(), requested.end(), CONNECTOR) != requested.end()) { + resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_DUPLICATE_CONNECTOR, "Connector already requested"); + return; + } + + // TODO: when (if) we add multi, make sure this is from the correct device. + + requested.emplace_back(CONNECTOR); + }); + + resource->setSubmit([this](CWpDrmLeaseRequestV1* r, uint32_t id) { + if (requested.empty()) { + resource->error(WP_DRM_LEASE_REQUEST_V1_ERROR_EMPTY_LEASE, "No connectors added"); + return; + } + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), self.lock()); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + PROTO::lease->m_vLeases.emplace_back(RESOURCE); + + // per protcol, after submit, this is dead. + PROTO::lease->destroyResource(this); + }); +} + +bool CDRMLeaseRequestResource::good() { + return resource->resource(); +} + +SP CDRMLeaseConnectorResource::fromResource(wl_resource* res) { + auto data = (CDRMLeaseConnectorResource*)(((CWpDrmLeaseConnectorV1*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +CDRMLeaseConnectorResource::CDRMLeaseConnectorResource(SP resource_, SP monitor_) : monitor(monitor_), resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); }); + resource->setDestroy([this](CWpDrmLeaseConnectorV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setData(this); + + listeners.destroyMonitor = monitor->events.destroy.registerListener([this](std::any d) { + resource->sendWithdrawn(); + dead = true; + }); +} + +bool CDRMLeaseConnectorResource::good() { + return resource->resource(); +} + +void CDRMLeaseConnectorResource::sendData() { + resource->sendName(monitor->szName.c_str()); + resource->sendDescription(monitor->szDescription.c_str()); + + auto AQDRMOutput = (Aquamarine::CDRMOutput*)monitor->output.get(); + resource->sendConnectorId(AQDRMOutput->getConnectorID()); + + resource->sendDone(); +} + +CDRMLeaseDeviceResource::CDRMLeaseDeviceResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); }); + resource->setRelease([this](CWpDrmLeaseDeviceV1* r) { PROTO::lease->destroyResource(this); }); + + resource->setCreateLeaseRequest([this](CWpDrmLeaseDeviceV1* r, uint32_t id) { + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id)); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + RESOURCE->self = RESOURCE; + + PROTO::lease->m_vRequests.emplace_back(RESOURCE); + + LOGM(LOG, "New lease request {}", id); + + RESOURCE->parent = self; + }); + + int fd = ((Aquamarine::CDRMBackend*)PROTO::lease->primaryDevice->backend.get())->getNonMasterFD(); + if (fd < 0) { + LOGM(ERR, "Failed to dup fd in lease"); + return; + } + + LOGM(LOG, "Sending DRMFD {} to new lease device", fd); + resource->sendDrmFd(fd); + close(fd); + + for (auto& m : PROTO::lease->primaryDevice->offeredOutputs) { + sendConnector(m.lock()); + } + + resource->sendDone(); +} + +bool CDRMLeaseDeviceResource::good() { + return resource->resource(); +} + +void CDRMLeaseDeviceResource::sendConnector(SP monitor) { + if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e->monitor == monitor; }) != connectorsSent.end()) + return; + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), -1), monitor); + if (!RESOURCE) { + resource->noMemory(); + return; + } + + RESOURCE->parent = self; + RESOURCE->self = RESOURCE; + + LOGM(LOG, "Sending new connector {}", monitor->szName); + + connectorsSent.emplace_back(RESOURCE); + PROTO::lease->m_vConnectors.emplace_back(RESOURCE); + + resource->sendConnector(RESOURCE->resource.get()); + + RESOURCE->sendData(); +} + +CDRMLeaseDevice::CDRMLeaseDevice(SP drmBackend) : backend(drmBackend) { + auto drm = (Aquamarine::CDRMBackend*)drmBackend.get(); + + auto fd = drm->getNonMasterFD(); + + if (fd < 0) { + LOGM(ERR, "Failed to dup fd for drm node {}", drm->gpuName); + return; + } + + close(fd); + success = true; + name = drm->gpuName; +} + +CDRMLeaseProtocol::CDRMLeaseProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + for (auto& b : g_pCompositor->m_pAqBackend->getImplementations()) { + if (b->type() != Aquamarine::AQ_BACKEND_DRM) + continue; + + auto drm = ((Aquamarine::CDRMBackend*)b.get())->self.lock(); + + primaryDevice = makeShared(drm); + + if (primaryDevice->success) + break; + } + + if (!primaryDevice || primaryDevice->success) { + PROTO::lease.reset(); + return; + } +} + +void CDRMLeaseProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } + + RESOURCE->self = RESOURCE; +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseDeviceResource* resource) { + std::erase_if(m_vManagers, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseConnectorResource* resource) { + std::erase_if(m_vConnectors, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseRequestResource* resource) { + std::erase_if(m_vRequests, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::destroyResource(CDRMLeaseResource* resource) { + std::erase_if(m_vLeases, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMLeaseProtocol::offer(SP monitor) { + if (std::find(primaryDevice->offeredOutputs.begin(), primaryDevice->offeredOutputs.end(), monitor) != primaryDevice->offeredOutputs.end()) + return; + + if (monitor->output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM) + return; + + if (monitor->output->getBackend() != primaryDevice->backend) { + LOGM(ERR, "Monitor {} cannot be leased: primaryDevice lease is for a different device", monitor->szName); + return; + } + + primaryDevice->offeredOutputs.emplace_back(monitor); + + for (auto& m : m_vManagers) { + m->sendConnector(monitor); + m->resource->sendDone(); + } +} diff --git a/src/protocols/DRMLease.hpp b/src/protocols/DRMLease.hpp new file mode 100644 index 00000000..56eaa3db --- /dev/null +++ b/src/protocols/DRMLease.hpp @@ -0,0 +1,137 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "drm-lease-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +/* + TODO: this protocol is not made for systems with multiple DRM nodes (e.g. multigpu) +*/ + +AQUAMARINE_FORWARD(CDRMBackend); +AQUAMARINE_FORWARD(CDRMLease); +class CDRMLeaseDeviceResource; +class CMonitor; +class CDRMLeaseProtocol; +class CDRMLeaseConnectorResource; +class CDRMLeaseRequestResource; + +class CDRMLeaseResource { + public: + CDRMLeaseResource(SP resource_, SP request); + + bool good(); + + WP parent; + std::vector> requested; + WP lease; + + int leaseFD = -1; + + struct { + CHyprSignalListener destroyLease; + } listeners; + + private: + SP resource; +}; + +class CDRMLeaseRequestResource { + public: + CDRMLeaseRequestResource(SP resource_); + + bool good(); + + WP parent; + WP self; + std::vector> requested; + + private: + SP resource; +}; + +class CDRMLeaseConnectorResource { + public: + CDRMLeaseConnectorResource(SP resource_, SP monitor_); + static SP fromResource(wl_resource*); + + bool good(); + void sendData(); + + WP self; + WP parent; + WP monitor; + bool dead = false; + + private: + SP resource; + + struct { + CHyprSignalListener destroyMonitor; + } listeners; + + friend class CDRMLeaseDeviceResource; +}; + +class CDRMLeaseDeviceResource { + public: + CDRMLeaseDeviceResource(SP resource_); + + bool good(); + void sendConnector(SP monitor); + + std::vector> connectorsSent; + + WP self; + + private: + SP resource; + + friend class CDRMLeaseProtocol; +}; + +class CDRMLeaseDevice { + public: + CDRMLeaseDevice(SP drmBackend); + + std::string name = ""; + bool success = false; + SP backend; + + std::vector> offeredOutputs; +}; + +class CDRMLeaseProtocol : public IWaylandProtocol { + public: + CDRMLeaseProtocol(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); + + void offer(SP monitor); + + private: + void destroyResource(CDRMLeaseDeviceResource* resource); + void destroyResource(CDRMLeaseConnectorResource* resource); + void destroyResource(CDRMLeaseRequestResource* resource); + void destroyResource(CDRMLeaseResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vConnectors; + std::vector> m_vRequests; + std::vector> m_vLeases; + + SP primaryDevice; + + friend class CDRMLeaseDeviceResource; + friend class CDRMLeaseConnectorResource; + friend class CDRMLeaseRequestResource; + friend class CDRMLeaseResource; +}; + +namespace PROTO { + inline UP lease; +}; diff --git a/src/protocols/DRMSyncobj.cpp b/src/protocols/DRMSyncobj.cpp new file mode 100644 index 00000000..41178109 --- /dev/null +++ b/src/protocols/DRMSyncobj.cpp @@ -0,0 +1,183 @@ +#include "DRMSyncobj.hpp" +#include + +#include "core/Compositor.hpp" +#include "../helpers/sync/SyncTimeline.hpp" +#include "../Compositor.hpp" + +#include + +#define LOGM PROTO::sync->protoLog + +CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP resource_, SP surface_) : surface(surface_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjSurfaceV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjSurfaceV1* r) { PROTO::sync->destroyResource(this); }); + + resource->setSetAcquirePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { + if (!surface) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_); + acquireTimeline = timeline; + acquirePoint = ((uint64_t)hi << 32) | (uint64_t)lo; + }); + + resource->setSetReleasePoint([this](CWpLinuxDrmSyncobjSurfaceV1* r, wl_resource* timeline_, uint32_t hi, uint32_t lo) { + if (!surface) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_SURFACE, "Surface is gone"); + return; + } + + auto timeline = CDRMSyncobjTimelineResource::fromResource(timeline_); + releaseTimeline = timeline; + releasePoint = ((uint64_t)hi << 32) | (uint64_t)lo; + }); + + listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) { + if (!!acquireTimeline != !!releaseTimeline) { + resource->error(acquireTimeline ? WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_RELEASE_POINT : WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_ACQUIRE_POINT, "Missing timeline"); + surface->pending.rejected = true; + return; + } + + if ((acquireTimeline || releaseTimeline) && !surface->pending.buffer) { + resource->error(WP_LINUX_DRM_SYNCOBJ_SURFACE_V1_ERROR_NO_BUFFER, "Missing buffer"); + surface->pending.rejected = true; + return; + } + + if (!acquireTimeline) + return; + + // wait for the acquire timeline to materialize + auto materialized = acquireTimeline->timeline->check(acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + if (!materialized.has_value()) { + LOGM(ERR, "Failed to check the acquire timeline"); + resource->noMemory(); + return; + } + + if (materialized) + return; + + surface->lockPendingState(); + acquireTimeline->timeline->addWaiter([this]() { surface->unlockPendingState(); }, acquirePoint, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE); + }); +} + +bool CDRMSyncobjSurfaceResource::good() { + return resource->resource(); +} + +CDRMSyncobjTimelineResource::CDRMSyncobjTimelineResource(SP resource_, int fd_) : fd(fd_), resource(resource_) { + if (!good()) + return; + + resource->setData(this); + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjTimelineV1* r) { PROTO::sync->destroyResource(this); }); + + timeline = CSyncTimeline::create(PROTO::sync->drmFD, fd); + + if (!timeline) { + resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_INVALID_TIMELINE, "Timeline failed importing"); + return; + } +} + +SP CDRMSyncobjTimelineResource::fromResource(wl_resource* res) { + auto data = (CDRMSyncobjTimelineResource*)(((CWpLinuxDrmSyncobjTimelineV1*)wl_resource_get_user_data(res))->data()); + return data ? data->self.lock() : nullptr; +} + +bool CDRMSyncobjTimelineResource::good() { + return resource->resource(); +} + +CDRMSyncobjManagerResource::CDRMSyncobjManagerResource(SP resource_) : resource(resource_) { + if (!good()) + return; + + resource->setOnDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); }); + resource->setDestroy([this](CWpLinuxDrmSyncobjManagerV1* r) { PROTO::sync->destroyResource(this); }); + + resource->setGetSurface([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, wl_resource* surf) { + if (!surf) { + resource->error(-1, "Invalid surface"); + return; + } + + auto SURF = CWLSurfaceResource::fromResource(surf); + if (!SURF) { + resource->error(-1, "Invalid surface (2)"); + return; + } + + if (SURF->syncobj) { + resource->error(WP_LINUX_DRM_SYNCOBJ_MANAGER_V1_ERROR_SURFACE_EXISTS, "Surface already has a syncobj attached"); + return; + } + + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), SURF); + if (!RESOURCE->good()) { + resource->noMemory(); + return; + } + + PROTO::sync->m_vSurfaces.emplace_back(RESOURCE); + SURF->syncobj = RESOURCE; + + LOGM(LOG, "New linux_syncobj at {:x} for surface {:x}", (uintptr_t)RESOURCE.get(), (uintptr_t)SURF.get()); + }); + + resource->setImportTimeline([this](CWpLinuxDrmSyncobjManagerV1* r, uint32_t id, int32_t fd) { + auto RESOURCE = makeShared(makeShared(resource->client(), resource->version(), id), fd); + if (!RESOURCE->good()) { + resource->noMemory(); + return; + } + + PROTO::sync->m_vTimelines.emplace_back(RESOURCE); + RESOURCE->self = RESOURCE; + + LOGM(LOG, "New linux_drm_timeline at {:x}", (uintptr_t)RESOURCE.get()); + }); +} + +bool CDRMSyncobjManagerResource::good() { + return resource->resource(); +} + +CDRMSyncobjProtocol::CDRMSyncobjProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + drmFD = g_pCompositor->m_iDRMFD; +} + +void CDRMSyncobjProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(makeShared(makeShared(client, ver, id))); + + if (!RESOURCE->good()) { + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjManagerResource* resource) { + std::erase_if(m_vManagers, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjTimelineResource* resource) { + std::erase_if(m_vTimelines, [resource](const auto& e) { return e.get() == resource; }); +} + +void CDRMSyncobjProtocol::destroyResource(CDRMSyncobjSurfaceResource* resource) { + std::erase_if(m_vSurfaces, [resource](const auto& e) { return e.get() == resource; }); +} diff --git a/src/protocols/DRMSyncobj.hpp b/src/protocols/DRMSyncobj.hpp new file mode 100644 index 00000000..c1c884ff --- /dev/null +++ b/src/protocols/DRMSyncobj.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include "WaylandProtocol.hpp" +#include "linux-drm-syncobj-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CWLSurfaceResource; +class CDRMSyncobjTimelineResource; +class CSyncTimeline; + +class CDRMSyncobjSurfaceResource { + public: + CDRMSyncobjSurfaceResource(SP resource_, SP surface_); + + bool good(); + + WP surface; + WP acquireTimeline, releaseTimeline; + uint64_t acquirePoint = 0, releasePoint = 0; + + private: + SP resource; + + struct { + CHyprSignalListener surfacePrecommit; + } listeners; +}; + +class CDRMSyncobjTimelineResource { + public: + CDRMSyncobjTimelineResource(SP resource_, int fd_); + static SP fromResource(wl_resource*); + + bool good(); + + WP self; + int fd = -1; + SP timeline; + + private: + SP resource; +}; + +class CDRMSyncobjManagerResource { + public: + CDRMSyncobjManagerResource(SP resource_); + + bool good(); + + private: + SP resource; +}; + +class CDRMSyncobjProtocol : public IWaylandProtocol { + public: + CDRMSyncobjProtocol(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(CDRMSyncobjManagerResource* resource); + void destroyResource(CDRMSyncobjTimelineResource* resource); + void destroyResource(CDRMSyncobjSurfaceResource* resource); + + // + std::vector> m_vManagers; + std::vector> m_vTimelines; + std::vector> m_vSurfaces; + + // + int drmFD = -1; + + friend class CDRMSyncobjManagerResource; + friend class CDRMSyncobjTimelineResource; + friend class CDRMSyncobjSurfaceResource; +}; + +namespace PROTO { + inline UP sync; +}; diff --git a/src/protocols/GammaControl.cpp b/src/protocols/GammaControl.cpp index 7c3b39ce..494d9862 100644 --- a/src/protocols/GammaControl.cpp +++ b/src/protocols/GammaControl.cpp @@ -34,7 +34,7 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out } } - gammaSize = wlr_output_get_gamma_size(pMonitor->output); + gammaSize = pMonitor->output->getGammaSize(); if (gammaSize <= 0) { LOGM(ERR, "Output {} doesn't support gamma", pMonitor->szName); @@ -81,6 +81,24 @@ CGammaControl::CGammaControl(SP resource_, wl_resource* out gammaTableSet = true; close(fd); + + // translate the table to AQ format + std::vector red, green, blue; + red.resize(gammaTable.size() / 3); + green.resize(gammaTable.size() / 3); + blue.resize(gammaTable.size() / 3); + for (size_t i = 0; i < gammaTable.size() / 3; ++i) { + red.at(i) = gammaTable.at(i); + green.at(i) = gammaTable.at(gammaTable.size() / 3 + i); + blue.at(i) = gammaTable.at((gammaTable.size() / 3) * 2 + i); + } + + for (size_t i = 0; i < gammaTable.size() / 3; ++i) { + gammaTable.at(i * 3) = red.at(i); + gammaTable.at(i * 3 + 1) = green.at(i); + gammaTable.at(i * 3 + 2) = blue.at(i); + } + applyToMonitor(); }); @@ -95,7 +113,7 @@ CGammaControl::~CGammaControl() { return; // reset the LUT if the client dies for whatever reason and doesn't unset the gamma - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); } bool CGammaControl::good() { @@ -109,19 +127,15 @@ void CGammaControl::applyToMonitor() { LOGM(LOG, "setting to monitor {}", pMonitor->szName); if (!gammaTableSet) { - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); return; } - uint16_t* red = &gammaTable.at(0); - uint16_t* green = &gammaTable.at(gammaSize); - uint16_t* blue = &gammaTable.at(gammaSize * 2); - - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), gammaSize, red, green, blue); + pMonitor->output->state->setGammaLut(gammaTable); if (!pMonitor->state.test()) { LOGM(LOG, "setting to monitor {} failed", pMonitor->szName); - wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr); + pMonitor->output->state->setGammaLut({}); } g_pHyprRenderer->damageMonitor(pMonitor); diff --git a/src/protocols/GammaControl.hpp b/src/protocols/GammaControl.hpp index 93465b81..963eea5c 100644 --- a/src/protocols/GammaControl.hpp +++ b/src/protocols/GammaControl.hpp @@ -23,7 +23,7 @@ class CGammaControl { CMonitor* pMonitor = nullptr; size_t gammaSize = 0; bool gammaTableSet = false; - std::vector gammaTable; + std::vector gammaTable; // [r,g,b]+ void onMonitorDestroy(); diff --git a/src/protocols/InputMethodV2.cpp b/src/protocols/InputMethodV2.cpp index 24f7ad54..def4d837 100644 --- a/src/protocols/InputMethodV2.cpp +++ b/src/protocols/InputMethodV2.cpp @@ -4,6 +4,7 @@ #include "../devices/IKeyboard.hpp" #include #include "core/Compositor.hpp" +#include #define LOGM PROTO::ime->protoLog @@ -19,7 +20,7 @@ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SPkeyboard->wlr()); + sendKeyboardData(g_pSeatManager->keyboard.lock()); } CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() { @@ -27,37 +28,36 @@ CInputMethodKeyboardGrabV2::~CInputMethodKeyboardGrabV2() { std::erase_if(owner->grabs, [](const auto& g) { return g.expired(); }); } -void CInputMethodKeyboardGrabV2::sendKeyboardData(wlr_keyboard* keyboard) { +void CInputMethodKeyboardGrabV2::sendKeyboardData(SP keyboard) { if (keyboard == pLastKeyboard) return; pLastKeyboard = keyboard; - int keymapFD = allocateSHMFile(keyboard->keymap_size); + int keymapFD = allocateSHMFile(keyboard->xkbKeymapString.length() + 1); if (keymapFD < 0) { LOGM(ERR, "Failed to create a keymap file for keyboard grab"); return; } - void* data = mmap(nullptr, keyboard->keymap_size, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); + void* data = mmap(nullptr, keyboard->xkbKeymapString.length() + 1, PROT_READ | PROT_WRITE, MAP_SHARED, keymapFD, 0); if (data == MAP_FAILED) { LOGM(ERR, "Failed to mmap a keymap file for keyboard grab"); close(keymapFD); return; } - memcpy(data, keyboard->keymap_string, keyboard->keymap_size); - munmap(data, keyboard->keymap_size); + memcpy(data, keyboard->xkbKeymapString.c_str(), keyboard->xkbKeymapString.length()); + munmap(data, keyboard->xkbKeymapString.length() + 1); - resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->keymap_size); + resource->sendKeymap(WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1, keymapFD, keyboard->xkbKeymapString.length() + 1); close(keymapFD); - const auto MODS = keyboard->modifiers; - sendMods(MODS.depressed, MODS.latched, MODS.locked, MODS.group); + sendMods(keyboard->modifiersState.depressed, keyboard->modifiersState.latched, keyboard->modifiersState.locked, keyboard->modifiersState.group); - resource->sendRepeatInfo(keyboard->repeat_info.rate, keyboard->repeat_info.delay); + resource->sendRepeatInfo(keyboard->repeatRate, keyboard->repeatDelay); } void CInputMethodKeyboardGrabV2::sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state) { @@ -316,7 +316,7 @@ void CInputMethodV2::sendMods(uint32_t depressed, uint32_t latched, uint32_t loc } } -void CInputMethodV2::setKeyboard(wlr_keyboard* keyboard) { +void CInputMethodV2::setKeyboard(SP keyboard) { for (auto& gw : grabs) { auto g = gw.lock(); diff --git a/src/protocols/InputMethodV2.hpp b/src/protocols/InputMethodV2.hpp index bc21270c..0b2c7a49 100644 --- a/src/protocols/InputMethodV2.hpp +++ b/src/protocols/InputMethodV2.hpp @@ -11,6 +11,7 @@ class CInputMethodKeyboardGrabV2; class CInputMethodPopupV2; +class IKeyboard; class CInputMethodV2 { public: @@ -58,7 +59,7 @@ class CInputMethodV2 { bool hasGrab(); void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state); void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - void setKeyboard(wlr_keyboard* keyboard); + void setKeyboard(SP keyboard); wl_client* client(); wl_client* grabClient(); @@ -90,13 +91,13 @@ class CInputMethodKeyboardGrabV2 { void sendKey(uint32_t time, uint32_t key, wl_keyboard_key_state state); void sendMods(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); - void sendKeyboardData(wlr_keyboard* keyboard); + void sendKeyboardData(SP keyboard); private: SP resource; WP owner; - wlr_keyboard* pLastKeyboard = nullptr; // READ-ONLY + WP pLastKeyboard; }; class CInputMethodPopupV2 { diff --git a/src/protocols/LinuxDMABUF.cpp b/src/protocols/LinuxDMABUF.cpp index cf8f8730..0fbf832e 100644 --- a/src/protocols/LinuxDMABUF.cpp +++ b/src/protocols/LinuxDMABUF.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "core/Compositor.hpp" #include "types/DMABuffer.hpp" #include "types/WLBuffer.hpp" @@ -22,21 +23,66 @@ static std::optional devIDFromFD(int fd) { return stat.st_rdev; } -CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector tranches_) { +CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector, SDMABUFTranche>> tranches_) : + rendererTranche(_rendererTranche), monitorTranches(tranches_) { + + std::vector formatsVec; std::set> formats; - for (auto& t : tranches_) { - for (auto& fmt : t.formats) { - for (auto& mod : fmt.mods) { - formats.insert(std::make_pair<>(fmt.format, mod)); + + // insert formats into vec if they got inserted into set, meaning they're unique + size_t i = 0; + + rendererTranche.indicies.clear(); + for (auto& fmt : rendererTranche.formats) { + for (auto& mod : fmt.modifiers) { + auto format = std::make_pair<>(fmt.drmFormat, mod); + auto [_, inserted] = formats.insert(format); + if (inserted) { + // if it was inserted into set, then its unique and will have a new index in vec + rendererTranche.indicies.push_back(i++); + formatsVec.push_back(SDMABUFFormatTableEntry{ + .fmt = fmt.drmFormat, + .modifier = mod, + }); + } else { + // if it wasn't inserted then find its index in vec + auto it = + std::find_if(formatsVec.begin(), formatsVec.end(), [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + rendererTranche.indicies.push_back(it - formatsVec.begin()); } } } - tableLen = formats.size() * sizeof(SDMABUFFeedbackTableEntry); + for (auto& [monitor, tranche] : monitorTranches) { + tranche.indicies.clear(); + for (auto& fmt : tranche.formats) { + for (auto& mod : fmt.modifiers) { + // apparently these can implode on planes, so dont use them + if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) + continue; + auto format = std::make_pair<>(fmt.drmFormat, mod); + auto [_, inserted] = formats.insert(format); + if (inserted) { + tranche.indicies.push_back(i++); + formatsVec.push_back(SDMABUFFormatTableEntry{ + .fmt = fmt.drmFormat, + .modifier = mod, + }); + } else { + auto it = std::find_if(formatsVec.begin(), formatsVec.end(), + [fmt, mod](const SDMABUFFormatTableEntry& oth) { return oth.fmt == fmt.drmFormat && oth.modifier == mod; }); + tranche.indicies.push_back(it - formatsVec.begin()); + } + } + } + } + + tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry); + int fds[2] = {0}; - allocateSHMFilePair(tableLen, &fds[0], &fds[1]); + allocateSHMFilePair(tableSize, &fds[0], &fds[1]); - auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); + auto arr = (SDMABUFFormatTableEntry*)mmap(nullptr, tableSize, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0); if (arr == MAP_FAILED) { LOGM(ERR, "mmap failed"); @@ -47,33 +93,18 @@ CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector> formatsVec; - for (auto& f : formats) { - formatsVec.push_back(f); - } - - size_t i = 0; - for (auto& [fmt, mod] : formatsVec) { - arr[i++] = SDMABUFFeedbackTableEntry{ - .fmt = fmt, - .modifier = mod, - }; - } + std::copy(formatsVec.begin(), formatsVec.end(), arr); - munmap(arr, tableLen); + munmap(arr, tableSize); - mainDevice = device; - tableFD = fds[1]; - tranches = formatsVec; - - // TODO: maybe calculate indices? currently we send all as available which could be wrong? I ain't no kernel dev tho. + tableFD = fds[1]; } -CCompiledDMABUFFeedback::~CCompiledDMABUFFeedback() { +CDMABUFFormatTable::~CDMABUFFormatTable() { close(tableFD); } -CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs) { +CLinuxDMABuffer::CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs) { buffer = makeShared(id, client, attrs); buffer->resource->buffer = buffer; @@ -103,7 +134,7 @@ CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SPsetOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); }); - attrs = makeShared(); + attrs = makeShared(); attrs->success = true; @@ -190,7 +221,7 @@ void CLinuxDMABBUFParamsResource::create(uint32_t id) { return; } - LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, attrs->format, attrs->planes); + LOGM(LOG, "Creating a dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs->size, FormatUtils::drmFormatName(attrs->format), attrs->planes); for (int i = 0; i < attrs->planes; ++i) { LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs->modifier, attrs->fds[i], attrs->strides[i], attrs->offsets[i]); } @@ -277,40 +308,52 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SPsetOnDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); resource->setDestroy([this](CZwpLinuxDmabufFeedbackV1* r) { PROTO::linuxDma->destroyResource(this); }); - if (surface) - LOGM(ERR, "FIXME: surface feedback stub"); + auto& formatTable = PROTO::linuxDma->formatTable; + resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize); + sendDefaultFeedback(); +} - auto* feedback = PROTO::linuxDma->defaultFeedback.get(); +CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() { + ; +} - resource->sendFormatTable(feedback->tableFD, feedback->tableLen); +bool CLinuxDMABUFFeedbackResource::good() { + return resource->resource(); +} - // send default feedback +void CLinuxDMABUFFeedbackResource::sendTranche(SDMABUFTranche& tranche) { struct wl_array deviceArr = { - .size = sizeof(feedback->mainDevice), - .data = (void*)&feedback->mainDevice, + .size = sizeof(tranche.device), + .data = (void*)&tranche.device, }; - resource->sendMainDevice(&deviceArr); resource->sendTrancheTargetDevice(&deviceArr); - resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)0); - wl_array indices; - wl_array_init(&indices); - for (size_t i = 0; i < feedback->tranches.size(); ++i) { - *((uint16_t*)wl_array_add(&indices, sizeof(uint16_t))) = i; - } + resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)tranche.flags); + + wl_array indices = { + .size = tranche.indicies.size() * sizeof(tranche.indicies.at(0)), + .data = tranche.indicies.data(), + }; resource->sendTrancheFormats(&indices); - wl_array_release(&indices); resource->sendTrancheDone(); - - resource->sendDone(); } -CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() { - ; -} +// default tranche is based on renderer (egl) +void CLinuxDMABUFFeedbackResource::sendDefaultFeedback() { + auto mainDevice = PROTO::linuxDma->mainDevice; + auto& formatTable = PROTO::linuxDma->formatTable; -bool CLinuxDMABUFFeedbackResource::good() { - return resource->resource(); + struct wl_array deviceArr = { + .size = sizeof(mainDevice), + .data = (void*)&mainDevice, + }; + resource->sendMainDevice(&deviceArr); + + sendTranche(formatTable->rendererTranche); + + resource->sendDone(); + + lastFeedbackWasScanout = false; } CLinuxDMABUFResource::CLinuxDMABUFResource(SP resource_) : resource(resource_) { @@ -361,48 +404,81 @@ bool CLinuxDMABUFResource::good() { } void CLinuxDMABUFResource::sendMods() { - for (auto& [fmt, mod] : PROTO::linuxDma->defaultFeedback->tranches) { - if (resource->version() < 3) { - if (mod == DRM_FORMAT_MOD_INVALID) - resource->sendFormat(fmt); - continue; - } + for (auto& fmt : PROTO::linuxDma->formatTable->rendererTranche.formats) { + for (auto& mod : fmt.modifiers) { + if (resource->version() < 3) { + if (mod == DRM_FORMAT_MOD_INVALID || mod == DRM_FORMAT_MOD_LINEAR) + resource->sendFormat(fmt.drmFormat); + continue; + } - // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 + // TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166 - resource->sendModifier(fmt, mod >> 32, mod & 0xFFFFFFFF); + resource->sendModifier(fmt.drmFormat, mod >> 32, mod & 0xFFFFFFFF); + } } } CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { static auto P = g_pHookSystem->hookDynamic("ready", [this](void* self, SCallbackInfo& info, std::any d) { - int rendererFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + int rendererFD = g_pCompositor->m_iDRMFD; auto dev = devIDFromFD(rendererFD); if (!dev.has_value()) { - LOGM(ERR, "failed to get drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + removeGlobal(); return; } mainDevice = *dev; - auto fmts = g_pHyprOpenGL->getDRMFormats(); - - SDMABufTranche tranche = { - .device = *dev, - .formats = fmts, + SDMABUFTranche eglTranche = { + .device = mainDevice, + .flags = 0, // renderer isnt for ds so dont set flag. + .formats = g_pHyprOpenGL->getDRMFormats(), }; - std::vector tches; - tches.push_back(tranche); + std::vector, SDMABUFTranche>> tches; + + if (g_pCompositor->m_pAqBackend->hasSession()) { + // this assumes there's only 1 device used for both scanout and rendering + // also that each monitor never changes its primary plane + + for (auto& mon : g_pCompositor->m_vMonitors) { + auto tranche = SDMABUFTranche{ + .device = mainDevice, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = mon->output->getRenderFormats(), + }; + tches.push_back(std::make_pair<>(mon, tranche)); + } + + static auto monitorAdded = g_pHookSystem->hookDynamic("monitorAdded", [this](void* self, SCallbackInfo& info, std::any param) { + auto pMonitor = std::any_cast(param); + auto mon = pMonitor->self.lock(); + auto tranche = SDMABUFTranche{ + .device = mainDevice, + .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT, + .formats = mon->output->getRenderFormats(), + }; + formatTable->monitorTranches.push_back(std::make_pair<>(mon, tranche)); + resetFormatTable(); + }); + + static auto monitorRemoved = g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { + auto pMonitor = std::any_cast(param); + auto mon = pMonitor->self.lock(); + std::erase_if(formatTable->monitorTranches, [mon](std::pair, SDMABUFTranche> pair) { return pair.first == mon; }); + resetFormatTable(); + }); + } - defaultFeedback = std::make_unique(*dev, tches); + formatTable = std::make_unique(eglTranche, tches); drmDevice* device = nullptr; if (drmGetDeviceFromDevId(mainDevice, 0, &device) != 0) { - LOGM(ERR, "failed to get drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to get drm dev, disabling linux dmabuf"); + removeGlobal(); return; } @@ -411,17 +487,51 @@ CLinuxDMABufV1Protocol::CLinuxDMABufV1Protocol(const wl_interface* iface, const mainDeviceFD = open(name, O_RDWR | O_CLOEXEC); drmFreeDevice(&device); if (mainDeviceFD < 0) { - LOGM(ERR, "failed to open drm dev"); - PROTO::linuxDma.reset(); + protoLog(ERR, "failed to open drm dev, disabling linux dmabuf"); + removeGlobal(); return; } } else { - LOGM(ERR, "DRM device {} has no render node!!", device->nodes[DRM_NODE_PRIMARY]); + protoLog(ERR, "DRM device {} has no render node, disabling linux dmabuf", device->nodes[DRM_NODE_PRIMARY] ? device->nodes[DRM_NODE_PRIMARY] : "null"); drmFreeDevice(&device); + removeGlobal(); } }); } +void CLinuxDMABufV1Protocol::resetFormatTable() { + if (!formatTable) + return; + + LOGM(LOG, "Resetting format table"); + + // this might be a big copy + auto newFormatTable = std::make_unique(formatTable->rendererTranche, formatTable->monitorTranches); + + for (auto& feedback : m_vFeedbacks) { + feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize); + if (feedback->lastFeedbackWasScanout) { + SP mon; + auto HLSurface = CWLSurface::fromResource(feedback->surface); + if (auto w = HLSurface->getWindow(); w) + if (auto m = g_pCompositor->getMonitorFromID(w->m_iMonitorID); m) + mon = m->self.lock(); + + if (!mon) { + feedback->sendDefaultFeedback(); + return; + } + + updateScanoutTranche(feedback->surface, mon); + } else { + feedback->sendDefaultFeedback(); + } + } + + // delete old table after we sent new one + formatTable = std::move(newFormatTable); +} + CLinuxDMABufV1Protocol::~CLinuxDMABufV1Protocol() { if (mainDeviceFD >= 0) close(mainDeviceFD); @@ -452,3 +562,52 @@ void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABBUFParamsResource* resour void CLinuxDMABufV1Protocol::destroyResource(CLinuxDMABuffer* resource) { std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; }); } + +void CLinuxDMABufV1Protocol::updateScanoutTranche(SP surface, SP pMonitor) { + SP feedbackResource; + for (auto& f : m_vFeedbacks) { + if (f->surface != surface) + continue; + + feedbackResource = f; + break; + } + + if (!feedbackResource) { + LOGM(LOG, "updateScanoutTranche: surface has no dmabuf_feedback"); + return; + } + + if (!pMonitor) { + LOGM(LOG, "updateScanoutTranche: resetting feedback"); + feedbackResource->sendDefaultFeedback(); + return; + } + + const auto& monitorTranchePair = std::find_if(formatTable->monitorTranches.begin(), formatTable->monitorTranches.end(), + [pMonitor](std::pair, SDMABUFTranche> pair) { return pair.first == pMonitor; }); + + if (monitorTranchePair == formatTable->monitorTranches.end()) { + LOGM(LOG, "updateScanoutTranche: monitor has no tranche"); + return; + } + + auto& monitorTranche = (*monitorTranchePair).second; + + LOGM(LOG, "updateScanoutTranche: sending a scanout tranche"); + + struct wl_array deviceArr = { + .size = sizeof(mainDevice), + .data = (void*)&mainDevice, + }; + feedbackResource->resource->sendMainDevice(&deviceArr); + + // prioritize scnaout tranche but have renderer fallback tranche + // also yes formats can be duped here because different tranche flags (ds and no ds) + feedbackResource->sendTranche(monitorTranche); + feedbackResource->sendTranche(formatTable->rendererTranche); + + feedbackResource->resource->sendDone(); + + feedbackResource->lastFeedbackWasScanout = true; +} diff --git a/src/protocols/LinuxDMABUF.hpp b/src/protocols/LinuxDMABUF.hpp index 2b8ce736..0e25cdc6 100644 --- a/src/protocols/LinuxDMABUF.hpp +++ b/src/protocols/LinuxDMABUF.hpp @@ -7,15 +7,16 @@ #include "wayland.hpp" #include "linux-dmabuf-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include "../helpers/Format.hpp" +#include "../helpers/Monitor.hpp" +#include class CDMABuffer; -struct SDRMFormat; -struct SDMABUFAttrs; class CWLSurfaceResource; class CLinuxDMABuffer { public: - CLinuxDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + CLinuxDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs); ~CLinuxDMABuffer(); bool good(); @@ -31,34 +32,29 @@ class CLinuxDMABuffer { }; #pragma pack(push, 1) -struct SDMABUFFeedbackTableEntry { +struct SDMABUFFormatTableEntry { uint32_t fmt = 0; char pad[4]; uint64_t modifier = 0; }; #pragma pack(pop) -class SCompiledDMABUFTranche { - dev_t device = 0; - uint32_t flags = 0; - std::vector indices; -}; - -struct SDMABufTranche { +struct SDMABUFTranche { dev_t device = 0; uint32_t flags = 0; std::vector formats; + std::vector indicies; }; -class CCompiledDMABUFFeedback { +class CDMABUFFormatTable { public: - CCompiledDMABUFFeedback(dev_t device, std::vector tranches); - ~CCompiledDMABUFFeedback(); + CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector, SDMABUFTranche>> tranches); + ~CDMABUFFormatTable(); - dev_t mainDevice = 0; - int tableFD = -1; - size_t tableLen = 0; - std::vector> tranches; + int tableFD = -1; + size_t tableSize = 0; + SDMABUFTranche rendererTranche; + std::vector, SDMABUFTranche>> monitorTranches; }; class CLinuxDMABBUFParamsResource { @@ -66,12 +62,12 @@ class CLinuxDMABBUFParamsResource { CLinuxDMABBUFParamsResource(SP resource_); ~CLinuxDMABBUFParamsResource(); - bool good(); - void create(uint32_t id); // 0 means not immed + bool good(); + void create(uint32_t id); // 0 means not immed - SP attrs; - WP createdBuffer; - bool used = false; + SP attrs; + WP createdBuffer; + bool used = false; private: SP resource; @@ -86,11 +82,16 @@ class CLinuxDMABUFFeedbackResource { ~CLinuxDMABUFFeedbackResource(); bool good(); + void sendDefaultFeedback(); + void sendTranche(SDMABUFTranche& tranche); SP surface; // optional, for surface feedbacks private: SP resource; + bool lastFeedbackWasScanout = false; + + friend class CLinuxDMABufV1Protocol; }; class CLinuxDMABUFResource { @@ -110,6 +111,7 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { ~CLinuxDMABufV1Protocol(); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + void updateScanoutTranche(SP surface, SP pMonitor); private: void destroyResource(CLinuxDMABUFResource* resource); @@ -117,13 +119,15 @@ class CLinuxDMABufV1Protocol : public IWaylandProtocol { void destroyResource(CLinuxDMABBUFParamsResource* resource); void destroyResource(CLinuxDMABuffer* resource); + void resetFormatTable(); + // std::vector> m_vManagers; std::vector> m_vFeedbacks; std::vector> m_vParams; std::vector> m_vBuffers; - UP defaultFeedback; + UP formatTable; dev_t mainDevice; int mainDeviceFD = -1; diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp index 0bcf4a9c..ed412555 100644 --- a/src/protocols/MesaDRM.cpp +++ b/src/protocols/MesaDRM.cpp @@ -2,12 +2,11 @@ #include #include #include "../Compositor.hpp" -#include #include "types/WLBuffer.hpp" #define LOGM PROTO::mesaDRM->protoLog -CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) { +CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) { LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes); for (int i = 0; i < attrs_.planes; ++i) { LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]); @@ -60,10 +59,27 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { return; } - SDMABUFAttrs attrs; + uint64_t mod = DRM_FORMAT_MOD_INVALID; + + auto fmts = g_pHyprOpenGL->getDRMFormats(); + for (auto& f : fmts) { + if (f.drmFormat != fmt) + continue; + + for (auto& m : f.modifiers) { + if (m == DRM_FORMAT_MOD_LINEAR) + continue; + + mod = m; + break; + } + break; + } + + Aquamarine::SDMABUFAttrs attrs; attrs.success = true; attrs.size = {w, h}; - attrs.modifier = DRM_FORMAT_MOD_INVALID; + attrs.modifier = mod; attrs.planes = 1; attrs.offsets[0] = off0; attrs.strides[0] = str0; @@ -87,7 +103,7 @@ CMesaDRMResource::CMesaDRMResource(SP resource_) : resource(resource_) { auto fmts = g_pHyprOpenGL->getDRMFormats(); for (auto& fmt : fmts) { - resource->sendFormat(fmt.format); + resource->sendFormat(fmt.drmFormat); } } @@ -97,10 +113,10 @@ bool CMesaDRMResource::good() { CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { drmDevice* dev = nullptr; - int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer); + int drmFD = g_pCompositor->m_iDRMFD; if (drmGetDevice2(drmFD, 0, &dev) != 0) { - LOGM(ERR, "Failed to get device"); - PROTO::mesaDRM.reset(); + protoLog(ERR, "Failed to get device, disabling MesaDRM"); + removeGlobal(); return; } @@ -108,7 +124,15 @@ CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, co nodeName = dev->nodes[DRM_NODE_RENDER]; } else { ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY)); - LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); + + if (!dev->nodes[DRM_NODE_PRIMARY]) { + protoLog(ERR, "No DRM render node available, both render and primary are null, disabling MesaDRM"); + drmFreeDevice(&dev); + removeGlobal(); + return; + } + + protoLog(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); nodeName = dev->nodes[DRM_NODE_PRIMARY]; } drmFreeDevice(&dev); diff --git a/src/protocols/MesaDRM.hpp b/src/protocols/MesaDRM.hpp index ad31a182..46811d68 100644 --- a/src/protocols/MesaDRM.hpp +++ b/src/protocols/MesaDRM.hpp @@ -10,7 +10,7 @@ class CMesaDRMBufferResource { public: - CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs); + CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs); ~CMesaDRMBufferResource(); bool good(); diff --git a/src/protocols/OutputManagement.cpp b/src/protocols/OutputManagement.cpp index 68c50193..66f4c5f0 100644 --- a/src/protocols/OutputManagement.cpp +++ b/src/protocols/OutputManagement.cpp @@ -2,6 +2,8 @@ #include #include "../Compositor.hpp" +using namespace Aquamarine; + #define LOGM PROTO::outputManagement->protoLog COutputManager::COutputManager(SP resource_) : resource(resource_) { @@ -123,8 +125,8 @@ void COutputHead::sendAllData() { resource->sendName(pMonitor->szName.c_str()); resource->sendDescription(pMonitor->szDescription.c_str()); - if (pMonitor->output->phys_width > 0 && pMonitor->output->phys_height > 0) - resource->sendPhysicalSize(pMonitor->output->phys_width, pMonitor->output->phys_height); + if (pMonitor->output->physicalSize.x > 0 && pMonitor->output->physicalSize.y > 0) + resource->sendPhysicalSize(pMonitor->output->physicalSize.x, pMonitor->output->physicalSize.y); resource->sendEnabled(pMonitor->m_bEnabled); if (pMonitor->m_bEnabled) { @@ -133,12 +135,12 @@ void COutputHead::sendAllData() { resource->sendScale(wl_fixed_from_double(pMonitor->scale)); } - if (pMonitor->output->make && VERSION >= 2) - resource->sendMake(pMonitor->output->make); - if (pMonitor->output->model && VERSION >= 2) - resource->sendModel(pMonitor->output->model); - if (pMonitor->output->serial && VERSION >= 2) - resource->sendSerialNumber(pMonitor->output->serial); + if (!pMonitor->output->make.empty() && VERSION >= 2) + resource->sendMake(pMonitor->output->make.c_str()); + if (!pMonitor->output->model.empty() && VERSION >= 2) + resource->sendModel(pMonitor->output->model.c_str()); + if (!pMonitor->output->serial.empty() && VERSION >= 2) + resource->sendSerialNumber(pMonitor->output->serial.c_str()); if (VERSION >= 4) resource->sendAdaptiveSync(pMonitor->vrrActive ? ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_ENABLED : ZWLR_OUTPUT_HEAD_V1_ADAPTIVE_SYNC_STATE_DISABLED); @@ -146,12 +148,12 @@ void COutputHead::sendAllData() { // send all available modes if (modes.empty()) { - if (!wl_list_empty(&pMonitor->output->modes)) { - wlr_output_mode* mode; - - wl_list_for_each(mode, &pMonitor->output->modes, link) { - makeAndSendNewMode(mode); + if (!pMonitor->output->modes.empty()) { + for (auto& m : pMonitor->output->modes) { + makeAndSendNewMode(m); } + } else if (pMonitor->output->state->state().customMode) { + makeAndSendNewMode(pMonitor->output->state->state().customMode); } else makeAndSendNewMode(nullptr); } @@ -164,9 +166,9 @@ void COutputHead::sendAllData() { if (!m) continue; - if (m->mode == pMonitor->currentMode) { + if (m->mode == pMonitor->output->state->state().mode) { if (m->mode) - LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh); + LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate); else LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName); resource->sendCurrentMode(m->resource.get()); @@ -197,7 +199,7 @@ void COutputHead::updateMode() { if (m->mode == pMonitor->currentMode) { if (m->mode) - LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->width, m->mode->height, m->mode->refresh); + LOGM(LOG, " | sending current mode for {}: {}x{}@{}", pMonitor->szName, m->mode->pixelSize.x, m->mode->pixelSize.y, m->mode->refreshRate); else LOGM(LOG, " | sending current mode for {}: null (fake)", pMonitor->szName); resource->sendCurrentMode(m->resource.get()); @@ -207,7 +209,7 @@ void COutputHead::updateMode() { } } -void COutputHead::makeAndSendNewMode(wlr_output_mode* mode) { +void COutputHead::makeAndSendNewMode(SP mode) { const auto RESOURCE = PROTO::outputManagement->m_vModes.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), mode)); if (!RESOURCE->good()) { @@ -225,7 +227,7 @@ CMonitor* COutputHead::monitor() { return pMonitor; } -COutputMode::COutputMode(SP resource_, wlr_output_mode* mode_) : resource(resource_), mode(mode_) { +COutputMode::COutputMode(SP resource_, SP mode_) : resource(resource_), mode(mode_) { if (!good()) return; @@ -237,11 +239,11 @@ void COutputMode::sendAllData() { if (!mode) return; - LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->width, mode->height, mode->refresh, mode->preferred); + LOGM(LOG, " | sending mode {}x{}@{}mHz, pref: {}", mode->pixelSize.x, mode->pixelSize.y, mode->refreshRate, mode->preferred); - resource->sendSize(mode->width, mode->height); - if (mode->refresh > 0) - resource->sendRefresh(mode->refresh); + resource->sendSize(mode->pixelSize.x, mode->pixelSize.y); + if (mode->refreshRate > 0) + resource->sendRefresh(mode->refreshRate); if (mode->preferred) resource->sendPreferred(); } @@ -250,8 +252,8 @@ bool COutputMode::good() { return resource->resource(); } -wlr_output_mode* COutputMode::getMode() { - return mode; +SP COutputMode::getMode() { + return mode.lock(); } COutputConfiguration::COutputConfiguration(SP resource_, SP owner_) : resource(resource_), owner(owner_) { @@ -364,8 +366,8 @@ bool COutputConfiguration::applyTestConfiguration(bool test) { newRule.disabled = false; if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_MODE) { - newRule.resolution = {head->state.mode->getMode()->width, head->state.mode->getMode()->height}; - newRule.refreshRate = head->state.mode->getMode()->refresh / 1000.F; + newRule.resolution = head->state.mode->getMode()->pixelSize; + newRule.refreshRate = head->state.mode->getMode()->refreshRate / 1000.F; } else if (head->committedProperties & COutputConfigurationHead::eCommittedProperties::OUTPUT_HEAD_COMMITTED_CUSTOM_MODE) { newRule.resolution = head->state.customMode.size; newRule.refreshRate = head->state.customMode.refresh / 1000.F; @@ -425,7 +427,7 @@ COutputConfigurationHead::COutputConfigurationHead(SPszName, MODE->getMode()->width, MODE->getMode()->height, MODE->getMode()->refresh); + LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, MODE->getMode()->pixelSize.x, MODE->getMode()->pixelSize.y, MODE->getMode()->refreshRate); }); resource->setSetCustomMode([this](CZwlrOutputConfigurationHeadV1* r, int32_t w, int32_t h, int32_t refresh) { diff --git a/src/protocols/OutputManagement.hpp b/src/protocols/OutputManagement.hpp index 81ae9a71..36478d0b 100644 --- a/src/protocols/OutputManagement.hpp +++ b/src/protocols/OutputManagement.hpp @@ -6,6 +6,7 @@ #include "WaylandProtocol.hpp" #include "wlr-output-management-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include class CMonitor; @@ -34,15 +35,15 @@ class COutputManager { class COutputMode { public: - COutputMode(SP resource_, wlr_output_mode* mode_); + COutputMode(SP resource_, SP mode_); - bool good(); - wlr_output_mode* getMode(); - void sendAllData(); + bool good(); + SP getMode(); + void sendAllData(); private: - SP resource; - wlr_output_mode* mode = nullptr; + SP resource; + WP mode; friend class COutputHead; friend class COutputManagementProtocol; @@ -61,7 +62,7 @@ class COutputHead { SP resource; CMonitor* pMonitor = nullptr; - void makeAndSendNewMode(wlr_output_mode* mode); + void makeAndSendNewMode(SP mode); void sendCurrentMode(); std::vector> modes; diff --git a/src/protocols/OutputPower.cpp b/src/protocols/OutputPower.cpp index ef287cfa..597b9871 100644 --- a/src/protocols/OutputPower.cpp +++ b/src/protocols/OutputPower.cpp @@ -17,7 +17,7 @@ COutputPower::COutputPower(SP resource_, CMonitor* pMonitor_ pMonitor->dpmsStatus = mode == ZWLR_OUTPUT_POWER_V1_MODE_ON; - wlr_output_state_set_enabled(pMonitor->state.wlr(), pMonitor->dpmsStatus); + pMonitor->output->state->setEnabled(mode == ZWLR_OUTPUT_POWER_V1_MODE_ON); if (!pMonitor->state.commit()) LOGM(ERR, "Couldn't set dpms to {} for {}", pMonitor->dpmsStatus, pMonitor->szName); diff --git a/src/protocols/PresentationTime.cpp b/src/protocols/PresentationTime.cpp index 3907bf1e..e9472fc3 100644 --- a/src/protocols/PresentationTime.cpp +++ b/src/protocols/PresentationTime.cpp @@ -3,6 +3,8 @@ #include "../helpers/Monitor.hpp" #include "../managers/HookSystemManager.hpp" #include "core/Compositor.hpp" +#include "core/Output.hpp" +#include #define LOGM PROTO::presentation->protoLog @@ -41,13 +43,11 @@ bool CPresentationFeedback::good() { } void CPresentationFeedback::sendQueued(SP data, timespec* when, uint32_t untilRefreshNs, uint64_t seq, uint32_t reportedFlags) { - auto client = resource->client(); - wl_resource* res; - wl_resource_for_each(res, &data->pMonitor->output->resources) { - if (client == wl_resource_get_client(res)) { - resource->sendSyncOutput(res); - break; - } + auto client = resource->client(); + + if (PROTO::outputs.contains(data->pMonitor->szName)) { + if (auto outputResource = PROTO::outputs.at(data->pMonitor->szName)->outputResourceFrom(client); outputResource) + resource->sendSyncOutput(outputResource->getResource()->resource()); } uint32_t flags = 0; @@ -55,9 +55,9 @@ void CPresentationFeedback::sendQueued(SP data, timespe flags |= WP_PRESENTATION_FEEDBACK_KIND_VSYNC; if (data->zeroCopy) flags |= WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY; - if (reportedFlags & WLR_OUTPUT_PRESENT_HW_CLOCK) + if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_CLOCK) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; - if (reportedFlags & WLR_OUTPUT_PRESENT_HW_COMPLETION) + if (reportedFlags & Aquamarine::IOutput::AQ_OUTPUT_PRESENT_HW_COMPLETION) flags |= WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION; if (data->wasPresented && when) diff --git a/src/protocols/Screencopy.cpp b/src/protocols/Screencopy.cpp index 8a6285a1..5d1c9332 100644 --- a/src/protocols/Screencopy.cpp +++ b/src/protocols/Screencopy.cpp @@ -266,20 +266,17 @@ void CScreencopyProtocolManager::captureOutput(wl_client* client, wl_resource* r return; } - if (PFRAME->pMonitor->output->allocator && (PFRAME->pMonitor->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) { - PFRAME->dmabufFormat = PFRAME->pMonitor->output->render_format; - } else { - PFRAME->dmabufFormat = DRM_FORMAT_INVALID; - } + PFRAME->dmabufFormat = PFRAME->pMonitor->output->state->state().drmFormat; if (box.width == 0 && box.height == 0) PFRAME->box = {0, 0, (int)(PFRAME->pMonitor->vecSize.x), (int)(PFRAME->pMonitor->vecSize.y)}; else { PFRAME->box = box; } - int ow, oh; - wlr_output_effective_resolution(PFRAME->pMonitor->output, &ow, &oh); - PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), ow, oh).scale(PFRAME->pMonitor->scale).round(); + + PFRAME->box.transform(wlTransformToHyprutils(PFRAME->pMonitor->transform), PFRAME->pMonitor->vecTransformedSize.x, PFRAME->pMonitor->vecTransformedSize.y) + .scale(PFRAME->pMonitor->scale) + .round(); PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); @@ -383,10 +380,10 @@ void CScreencopyProtocolManager::copyFrame(wl_client* client, wl_resource* resou g_pHyprRenderer->damageMonitor(PFRAME->pMonitor); } -void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) { - m_pLastMonitorBackBuffer = e->state->buffer; +void CScreencopyProtocolManager::onOutputCommit(CMonitor* pMonitor) { + m_pLastMonitorBackBuffer = pMonitor->output->state->state().buffer; shareAllFrames(pMonitor); - m_pLastMonitorBackBuffer = nullptr; + m_pLastMonitorBackBuffer.reset(); } void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor) { @@ -473,11 +470,7 @@ void CScreencopyProtocolManager::sendFrameDamage(SScreencopyFrame* frame) { } bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) { - wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer); - if (!sourceTex) - return false; - - auto TEXTURE = makeShared(sourceTex); + auto TEXTURE = makeShared(m_pLastMonitorBackBuffer); auto shm = frame->buffer->shm(); auto [pixelData, fmt, bufLen] = frame->buffer->beginDataPtr(0); // no need for end, cuz it's shm @@ -487,10 +480,10 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* g_pHyprRenderer->makeEGLCurrent(); CFramebuffer fb; - fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->drmFormat); + fb.alloc(frame->box.w, frame->box.h, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : frame->pMonitor->output->state->state().drmFormat); if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_FULL_FAKE, nullptr, &fb, true)) { - wlr_texture_destroy(sourceTex); + Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering"); return false; } @@ -509,8 +502,8 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* const auto PFORMAT = FormatUtils::getPixelFormatFromDRM(shm.format); if (!PFORMAT) { + Debug::log(ERR, "Screencopy: can't copy: failed to find a pixel format"); g_pHyprRenderer->endRender(); - wlr_texture_destroy(sourceTex); return false; } @@ -539,27 +532,24 @@ bool CScreencopyProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* g_pHyprOpenGL->m_RenderData.pMonitor = nullptr; - wlr_texture_destroy(sourceTex); + Debug::log(TRACE, "Screencopy: copied frame via shm"); return true; } bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { - wlr_texture* sourceTex = wlr_texture_from_buffer(g_pCompositor->m_sWLRRenderer, m_pLastMonitorBackBuffer); - if (!sourceTex) - return false; - - auto TEXTURE = makeShared(sourceTex); + auto TEXTURE = makeShared(m_pLastMonitorBackBuffer); CRegion fakeDamage = {0, 0, INT16_MAX, INT16_MAX}; - if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) + if (!g_pHyprRenderer->beginRender(frame->pMonitor, fakeDamage, RENDER_MODE_TO_BUFFER, frame->buffer.lock(), nullptr, true)) { + Debug::log(ERR, "Screencopy: can't copy: failed to begin rendering to dma frame"); return false; + } - CBox monbox = - CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} - .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. - .transform(wlTransformToHyprutils(wlr_output_transform_invert(frame->pMonitor->output->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); + CBox monbox = CBox{0, 0, frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y} + .translate({-frame->box.x, -frame->box.y}) // vvvv kinda ass-backwards but that's how I designed the renderer... sigh. + .transform(wlTransformToHyprutils(invertTransform(frame->pMonitor->transform)), frame->pMonitor->vecPixelSize.x, frame->pMonitor->vecPixelSize.y); g_pHyprOpenGL->setMonitorTransformEnabled(true); g_pHyprOpenGL->setRenderModifEnabled(false); g_pHyprOpenGL->renderTexture(TEXTURE, &monbox, 1); @@ -569,7 +559,7 @@ bool CScreencopyProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) { g_pHyprOpenGL->m_RenderData.blockScreenShader = true; g_pHyprRenderer->endRender(); - wlr_texture_destroy(sourceTex); + Debug::log(TRACE, "Screencopy: copied frame via dma"); return true; } diff --git a/src/protocols/Screencopy.hpp b/src/protocols/Screencopy.hpp index be434285..4999773b 100644 --- a/src/protocols/Screencopy.hpp +++ b/src/protocols/Screencopy.hpp @@ -8,9 +8,10 @@ #include "../managers/HookSystemManager.hpp" #include "../helpers/Timer.hpp" #include "../managers/eventLoop/EventLoopTimer.hpp" +#include class CMonitor; -class IWLBuffer; +class IHLBuffer; enum eClientOwners { CLIENT_SCREENCOPY = 0, @@ -56,7 +57,7 @@ struct SScreencopyFrame { bool bufferDMA = false; - WP buffer; + WP buffer; CMonitor* pMonitor = nullptr; PHLWINDOWREF pWindow; @@ -79,7 +80,7 @@ class CScreencopyProtocolManager { void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer); - void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e); + void onOutputCommit(CMonitor* pMonitor); private: wl_global* m_pGlobal = nullptr; @@ -93,7 +94,7 @@ class CScreencopyProtocolManager { std::vector m_vFramesAwaitingWrite; - wlr_buffer* m_pLastMonitorBackBuffer = nullptr; + SP m_pLastMonitorBackBuffer; void shareAllFrames(CMonitor* pMonitor); void shareFrame(SScreencopyFrame* frame); diff --git a/src/protocols/Tablet.cpp b/src/protocols/Tablet.cpp index 7b62f245..72c7cfde 100644 --- a/src/protocols/Tablet.cpp +++ b/src/protocols/Tablet.cpp @@ -5,6 +5,7 @@ #include "core/Seat.hpp" #include "core/Compositor.hpp" #include +#include #define LOGM PROTO::tablet->protoLog @@ -44,17 +45,17 @@ bool CTabletPadGroupV2Resource::good() { return resource->resource(); } -void CTabletPadGroupV2Resource::sendData(SP pad, wlr_tablet_pad_group* group) { - resource->sendModes(group->mode_count); +void CTabletPadGroupV2Resource::sendData(SP pad, SP group) { + resource->sendModes(group->modes); wl_array buttonArr; wl_array_init(&buttonArr); - wl_array_add(&buttonArr, group->button_count * sizeof(int)); - memcpy(buttonArr.data, group->buttons, group->button_count * sizeof(int)); + wl_array_add(&buttonArr, group->buttons.size() * sizeof(int)); + memcpy(buttonArr.data, group->buttons.data(), group->buttons.size() * sizeof(int)); resource->sendButtons(&buttonArr); wl_array_release(&buttonArr); - for (size_t i = 0; i < group->strip_count; ++i) { + for (size_t i = 0; i < group->strips.size(); ++i) { const auto RESOURCE = PROTO::tablet->m_vStrips.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); @@ -67,7 +68,7 @@ void CTabletPadGroupV2Resource::sendData(SP pad, wlr_tablet_pad_grou resource->sendStrip(RESOURCE->resource.get()); } - for (size_t i = 0; i < group->ring_count; ++i) { + for (size_t i = 0; i < group->rings.size(); ++i) { const auto RESOURCE = PROTO::tablet->m_vRings.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), i)); @@ -97,23 +98,20 @@ bool CTabletPadV2Resource::good() { void CTabletPadV2Resource::sendData() { // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts - const char** path_ptr; - for (path_ptr = (const char**)(&pad->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&pad->wlr()->paths)->data + (&pad->wlr()->paths)->size); (path_ptr)++) { - resource->sendPath(*path_ptr); + for (auto& p : pad->aq()->paths) { + resource->sendPath(p.c_str()); } - resource->sendButtons(pad->wlr()->button_count); + resource->sendButtons(pad->aq()->buttons); - wlr_tablet_pad_group* group; - size_t i = 0; - wl_list_for_each(group, &pad->wlr()->groups, link) { - createGroup(group, i++); + for (size_t i = 0; i < pad->aq()->groups.size(); ++i) { + createGroup(pad->aq()->groups.at(i), i); } resource->sendDone(); } -void CTabletPadV2Resource::createGroup(wlr_tablet_pad_group* group, size_t idx) { +void CTabletPadV2Resource::createGroup(SP group, size_t idx) { const auto RESOURCE = PROTO::tablet->m_vGroups.emplace_back(makeShared(makeShared(resource->client(), resource->version(), 0), idx)); @@ -142,13 +140,10 @@ bool CTabletV2Resource::good() { void CTabletV2Resource::sendData() { resource->sendName(tablet->deviceName.c_str()); - resource->sendId(tablet->wlr()->usb_vendor_id, tablet->wlr()->usb_product_id); + resource->sendId(tablet->aq()->usbVendorID, tablet->aq()->usbProductID); - // this is dodgy as fuck. I hate wl_array. it's expanded wl_array_for_each because C++ would complain about the implicit casts - const char** path_ptr; - for (path_ptr = (const char**)(&tablet->wlr()->paths)->data; (const char*)path_ptr < ((const char*)(&tablet->wlr()->paths)->data + (&tablet->wlr()->paths)->size); - (path_ptr)++) { - resource->sendPath(*path_ptr); + for (auto& p : tablet->aq()->paths) { + resource->sendPath(p.c_str()); } resource->sendDone(); @@ -179,23 +174,23 @@ bool CTabletToolV2Resource::good() { } void CTabletToolV2Resource::sendData() { - static auto WLR_TYPE_TO_PROTO = [](uint32_t wlr) -> zwpTabletToolV2Type { - switch (wlr) { - case WLR_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN; - case WLR_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER; - case WLR_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH; - case WLR_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL; - case WLR_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH; - case WLR_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE; - case WLR_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS; + static auto AQ_TYPE_TO_PROTO = [](uint32_t aq) -> zwpTabletToolV2Type { + switch (aq) { + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_PEN: return ZWP_TABLET_TOOL_V2_TYPE_PEN; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_ERASER: return ZWP_TABLET_TOOL_V2_TYPE_ERASER; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_BRUSH: return ZWP_TABLET_TOOL_V2_TYPE_BRUSH; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_PENCIL: return ZWP_TABLET_TOOL_V2_TYPE_PENCIL; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_AIRBRUSH: return ZWP_TABLET_TOOL_V2_TYPE_AIRBRUSH; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_MOUSE: return ZWP_TABLET_TOOL_V2_TYPE_MOUSE; + case Aquamarine::ITabletTool::AQ_TABLET_TOOL_TYPE_LENS: return ZWP_TABLET_TOOL_V2_TYPE_LENS; default: ASSERT(false); } UNREACHABLE(); }; - resource->sendType(WLR_TYPE_TO_PROTO(tool->wlr()->type)); - resource->sendHardwareSerial(tool->wlr()->hardware_serial >> 32, tool->wlr()->hardware_serial & 0xFFFFFFFF); - resource->sendHardwareIdWacom(tool->wlr()->hardware_wacom >> 32, tool->wlr()->hardware_wacom & 0xFFFFFFFF); + resource->sendType(AQ_TYPE_TO_PROTO(tool->aq()->type)); + resource->sendHardwareSerial(tool->aq()->serial >> 32, tool->aq()->serial & 0xFFFFFFFF); + resource->sendHardwareIdWacom(tool->aq()->id >> 32, tool->aq()->id & 0xFFFFFFFF); if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_DISTANCE) resource->sendCapability(zwpTabletToolV2Capability::ZWP_TABLET_TOOL_V2_CAPABILITY_DISTANCE); if (tool->toolCapabilities & CTabletTool::eTabletToolCapabilities::HID_TABLET_TOOL_CAPABILITY_PRESSURE) diff --git a/src/protocols/Tablet.hpp b/src/protocols/Tablet.hpp index 58f13c1a..1ebcb1e5 100644 --- a/src/protocols/Tablet.hpp +++ b/src/protocols/Tablet.hpp @@ -6,6 +6,7 @@ #include "WaylandProtocol.hpp" #include "tablet-v2.hpp" #include "../helpers/math/Math.hpp" +#include class CTablet; class CTabletTool; @@ -51,7 +52,7 @@ class CTabletPadGroupV2Resource { CTabletPadGroupV2Resource(SP resource_, size_t idx); bool good(); - void sendData(SP pad, wlr_tablet_pad_group* group); + void sendData(SP pad, SP group); std::vector> rings; std::vector> strips; @@ -83,7 +84,7 @@ class CTabletPadV2Resource { private: SP resource; - void createGroup(wlr_tablet_pad_group* group, size_t idx); + void createGroup(SP group, size_t idx); friend class CTabletSeat; friend class CTabletV2Protocol; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index d4c66c3b..0e78e5f7 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -193,16 +193,11 @@ void CToplevelExportProtocolManager::captureToplevel(wl_client* client, wl_resou return; } - if (PMONITOR->output->allocator && (PMONITOR->output->allocator->buffer_caps & WLR_BUFFER_CAP_DMABUF)) { - PFRAME->dmabufFormat = PMONITOR->output->render_format; - } else { - PFRAME->dmabufFormat = DRM_FORMAT_INVALID; - } + PFRAME->dmabufFormat = PMONITOR->output->state->state().drmFormat; PFRAME->box = {0, 0, (int)(pWindow->m_vRealSize.value().x * PMONITOR->scale), (int)(pWindow->m_vRealSize.value().y * PMONITOR->scale)}; - int ow, oh; - wlr_output_effective_resolution(PMONITOR->output, &ow, &oh); - PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), ow, oh).round(); + + PFRAME->box.transform(wlTransformToHyprutils(PMONITOR->transform), PMONITOR->vecTransformedSize.x, PMONITOR->vecTransformedSize.y).round(); PFRAME->shmStride = FormatUtils::minStride(PSHMINFO, PFRAME->box.w); @@ -289,12 +284,10 @@ void CToplevelExportProtocolManager::copyFrame(wl_client* client, wl_resource* r m_vFramesAwaitingWrite.emplace_back(PFRAME); } -void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e) { +void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor) { if (m_vFramesAwaitingWrite.empty()) return; // nothing to share - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(e->output); - std::vector framesToRemove; // share frame if correct output @@ -306,7 +299,7 @@ void CToplevelExportProtocolManager::onOutputCommit(CMonitor* pMonitor, wlr_outp continue; } - if (PMONITOR != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) + if (pMonitor != g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID)) continue; CBox geometry = {PWINDOW->m_vRealPosition.value().x, PWINDOW->m_vRealPosition.value().y, PWINDOW->m_vRealSize.value().x, PWINDOW->m_vRealSize.value().y}; @@ -370,7 +363,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, times g_pHyprRenderer->makeEGLCurrent(); CFramebuffer outFB; - outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->drmFormat); + outFB.alloc(PMONITOR->vecPixelSize.x, PMONITOR->vecPixelSize.y, g_pHyprRenderer->isNvidia() ? DRM_FORMAT_XBGR8888 : PMONITOR->output->state->state().drmFormat); if (frame->overlayCursor) { g_pPointerManager->lockSoftwareForMonitor(PMONITOR->self.lock()); diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index f044a781..c3620d41 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -21,7 +21,7 @@ class CToplevelExportProtocolManager { void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage); void displayDestroy(); void onWindowUnmap(PHLWINDOW pWindow); - void onOutputCommit(CMonitor* pMonitor, wlr_output_event_commit* e); + void onOutputCommit(CMonitor* pMonitor); private: wl_global* m_pGlobal = nullptr; diff --git a/src/protocols/Viewporter.cpp b/src/protocols/Viewporter.cpp index 8cb69dbe..03c5775e 100644 --- a/src/protocols/Viewporter.cpp +++ b/src/protocols/Viewporter.cpp @@ -52,6 +52,21 @@ CViewportResource::CViewportResource(SP resource_, SPpending.viewport.hasSource = true; surface->pending.viewport.source = {x, y, w, h}; }); + + listeners.surfacePrecommit = surface->events.precommit.registerListener([this](std::any d) { + if (!surface || !surface->pending.buffer) + return; + + if (surface->pending.viewport.hasSource) { + auto& src = surface->pending.viewport.source; + + if (src.w + src.x > surface->pending.buffer->size.x || src.h + src.y > surface->pending.buffer->size.y) { + resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); + surface->pending.rejected = true; + return; + } + } + }); } CViewportResource::~CViewportResource() { @@ -66,20 +81,6 @@ bool CViewportResource::good() { return resource->resource(); } -void CViewportResource::verify() { - if (!surface) - return; - - if (surface->pending.viewport.hasSource) { - auto& src = surface->pending.viewport.source; - - if (src.w + src.x > surface->pending.size.x || src.h + src.y > surface->pending.size.y) { - resource->error(WP_VIEWPORT_ERROR_BAD_VALUE, "Box doesn't fit"); - return; - } - } -} - CViewporterResource::CViewporterResource(SP resource_) : resource(resource_) { if (!good()) return; diff --git a/src/protocols/Viewporter.hpp b/src/protocols/Viewporter.hpp index 01278203..3c2a4eef 100644 --- a/src/protocols/Viewporter.hpp +++ b/src/protocols/Viewporter.hpp @@ -15,11 +15,14 @@ class CViewportResource { ~CViewportResource(); bool good(); - void verify(); WP surface; private: SP resource; + + struct { + CHyprSignalListener surfacePrecommit; + } listeners; }; class CViewporterResource { diff --git a/src/protocols/VirtualKeyboard.cpp b/src/protocols/VirtualKeyboard.cpp index 009c277c..2642ec11 100644 --- a/src/protocols/VirtualKeyboard.cpp +++ b/src/protocols/VirtualKeyboard.cpp @@ -1,12 +1,9 @@ #include "VirtualKeyboard.hpp" #include +#include "../devices/IKeyboard.hpp" #define LOGM PROTO::virtualKeyboard->protoLog -static const struct wlr_keyboard_impl virtualKeyboardImpl = { - .name = "virtual-keyboard", -}; - CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP resource_) : resource(resource_) { if (!good()) return; @@ -28,13 +25,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_key_event event = { - .time_msec = timeMs, - .keycode = key, - .update_state = false, - .state = (wl_keyboard_key_state)state, - }; - wlr_keyboard_notify_key(&keyboard, &event); + events.key.emit(IKeyboard::SKeyEvent{ + .timeMs = timeMs, + .keycode = key, + .state = (wl_keyboard_key_state)state, + }); + + const bool CONTAINS = std::find(pressed.begin(), pressed.end(), key) != pressed.end(); + if (state && !CONTAINS) + pressed.emplace_back(key); + else if (!state && CONTAINS) + std::erase(pressed, key); }); resource->setModifiers([this](CZwpVirtualKeyboardV1* r, uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) { @@ -43,7 +44,12 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_notify_modifiers(&keyboard, depressed, latched, locked, group); + events.modifiers.emit(IKeyboard::SModifiersEvent{ + .depressed = depressed, + .latched = latched, + .locked = locked, + .group = group, + }); }); resource->setKeymap([this](CZwpVirtualKeyboardV1* r, uint32_t fmt, int32_t fd, uint32_t len) { @@ -75,7 +81,9 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP return; } - wlr_keyboard_set_keymap(&keyboard, xkbKeymap); + events.keymap.emit(IKeyboard::SKeymapEvent{ + .keymap = xkbKeymap, + }); hasKeymap = true; xkb_keymap_unref(xkbKeymap); @@ -83,22 +91,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP close(fd); }); - wlr_keyboard_init(&keyboard, &virtualKeyboardImpl, "CVirtualKeyboard"); + name = "hl-virtual-keyboard"; } CVirtualKeyboardV1Resource::~CVirtualKeyboardV1Resource() { events.destroy.emit(); - wlr_keyboard_finish(&keyboard); } bool CVirtualKeyboardV1Resource::good() { return resource->resource(); } -wlr_keyboard* CVirtualKeyboardV1Resource::wlr() { - return &keyboard; -} - wl_client* CVirtualKeyboardV1Resource::client() { return resource->resource() ? resource->client() : nullptr; } @@ -106,17 +109,16 @@ wl_client* CVirtualKeyboardV1Resource::client() { void CVirtualKeyboardV1Resource::releasePressed() { timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - size_t keycodesNum = keyboard.num_keycodes; - - for (size_t i = 0; i < keycodesNum; ++i) { - struct wlr_keyboard_key_event event = { - .time_msec = (now.tv_sec * 1000 + now.tv_nsec / 1000000), - .keycode = keyboard.keycodes[keycodesNum - i - 1], - .update_state = false, - .state = WL_KEYBOARD_KEY_STATE_RELEASED, - }; - wlr_keyboard_notify_key(&keyboard, &event); // updates num_keycodes + + for (auto& p : pressed) { + events.key.emit(IKeyboard::SKeyEvent{ + .timeMs = now.tv_sec * 1000 + now.tv_nsec / 1000000, + .keycode = p, + .state = WL_KEYBOARD_KEY_STATE_RELEASED, + }); } + + pressed.clear(); } CVirtualKeyboardProtocol::CVirtualKeyboardProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { diff --git a/src/protocols/VirtualKeyboard.hpp b/src/protocols/VirtualKeyboard.hpp index 447b5db9..93b63bb5 100644 --- a/src/protocols/VirtualKeyboard.hpp +++ b/src/protocols/VirtualKeyboard.hpp @@ -14,19 +14,24 @@ class CVirtualKeyboardV1Resource { struct { CSignal destroy; + CSignal key; + CSignal modifiers; + CSignal keymap; } events; - bool good(); - wlr_keyboard* wlr(); - wl_client* client(); + bool good(); + wl_client* client(); + + std::string name = ""; private: SP resource; - wlr_keyboard keyboard; void releasePressed(); bool hasKeymap = false; + + std::vector pressed; }; class CVirtualKeyboardProtocol : public IWaylandProtocol { diff --git a/src/protocols/VirtualPointer.cpp b/src/protocols/VirtualPointer.cpp index 1fb83888..bdeec32d 100644 --- a/src/protocols/VirtualPointer.cpp +++ b/src/protocols/VirtualPointer.cpp @@ -2,10 +2,6 @@ #define LOGM PROTO::virtualPointer->protoLog -static const wlr_pointer_impl pointerImpl = { - .name = "virtual-pointer-v1", -}; - CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP resource_) : resource(resource_) { if (!good()) return; @@ -19,41 +15,30 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r PROTO::virtualPointer->destroyResource(this); }); - wlr_pointer_init(&pointer, &pointerImpl, "CVirtualPointerV1Resource"); - resource->setMotion([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, wl_fixed_t dx, wl_fixed_t dy) { - wlr_pointer_motion_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .delta_x = wl_fixed_to_double(dx), - .delta_y = wl_fixed_to_double(dy), - .unaccel_dx = wl_fixed_to_double(dx), - .unaccel_dy = wl_fixed_to_double(dy), - }; - wl_signal_emit_mutable(&pointer.events.motion, &event); + events.move.emit(IPointer::SMotionEvent{ + .timeMs = timeMs, + .delta = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)}, + .unaccel = {wl_fixed_to_double(dx), wl_fixed_to_double(dy)}, + }); }); resource->setMotionAbsolute([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t x, uint32_t y, uint32_t xExtent, uint32_t yExtent) { if (!xExtent || !yExtent) return; - wlr_pointer_motion_absolute_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .x = (double)x / xExtent, - .y = (double)y / yExtent, - }; - wl_signal_emit_mutable(&pointer.events.motion_absolute, &event); + events.warp.emit(IPointer::SMotionAbsoluteEvent{ + .timeMs = timeMs, + .absolute = {(double)x / xExtent, (double)y / yExtent}, + }); }); resource->setButton([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t button, uint32_t state) { - struct wlr_pointer_button_event event = { - .pointer = &pointer, - .time_msec = timeMs, - .button = button, - .state = (wl_pointer_button_state)state, - }; - wl_signal_emit_mutable(&pointer.events.button, &event); + events.button.emit(IPointer::SButtonEvent{ + .timeMs = timeMs, + .button = button, + .state = (wl_pointer_button_state)state, + }); }); resource->setAxis([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value) { @@ -63,18 +48,18 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r } axis = axis_; - axisEvents[axis] = wlr_pointer_axis_event{.pointer = &pointer, .time_msec = timeMs, .orientation = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)}; + axisEvents[axis] = IPointer::SAxisEvent{.timeMs = timeMs, .axis = (wl_pointer_axis)axis, .delta = wl_fixed_to_double(value)}; }); resource->setFrame([this](CZwlrVirtualPointerV1* r) { for (auto& e : axisEvents) { - if (!e.pointer) + if (!e.timeMs) continue; - wl_signal_emit_mutable(&pointer.events.axis, &e); - e.pointer = nullptr; + events.axis.emit(e); + e.timeMs = 0; } - wl_signal_emit_mutable(&pointer.events.frame, &pointer); + events.frame.emit(); }); resource->setAxisSource([this](CZwlrVirtualPointerV1* r, uint32_t source) { axisEvents[axis].source = (wl_pointer_axis_source)source; }); @@ -85,12 +70,11 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r return; } - axis = axis_; - axisEvents[axis].pointer = &pointer; - axisEvents[axis].time_msec = timeMs; - axisEvents[axis].orientation = (wl_pointer_axis)axis; - axisEvents[axis].delta = 0; - axisEvents[axis].delta_discrete = 0; + axis = axis_; + axisEvents[axis].timeMs = timeMs; + axisEvents[axis].axis = (wl_pointer_axis)axis; + axisEvents[axis].delta = 0; + axisEvents[axis].deltaDiscrete = 0; }); resource->setAxisDiscrete([this](CZwlrVirtualPointerV1* r, uint32_t timeMs, uint32_t axis_, wl_fixed_t value, int32_t discrete) { @@ -99,17 +83,15 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP r return; } - axis = axis_; - axisEvents[axis].pointer = &pointer; - axisEvents[axis].time_msec = timeMs; - axisEvents[axis].orientation = (wl_pointer_axis)axis; - axisEvents[axis].delta = wl_fixed_to_double(value); - axisEvents[axis].delta_discrete = discrete * 120; + axis = axis_; + axisEvents[axis].timeMs = timeMs; + axisEvents[axis].axis = (wl_pointer_axis)axis; + axisEvents[axis].delta = wl_fixed_to_double(value); + axisEvents[axis].deltaDiscrete = discrete * 120; }); } CVirtualPointerV1Resource::~CVirtualPointerV1Resource() { - wlr_pointer_finish(&pointer); events.destroy.emit(); } @@ -117,10 +99,6 @@ bool CVirtualPointerV1Resource::good() { return resource->resource(); } -wlr_pointer* CVirtualPointerV1Resource::wlr() { - return &pointer; -} - wl_client* CVirtualPointerV1Resource::client() { return resource->client(); } diff --git a/src/protocols/VirtualPointer.hpp b/src/protocols/VirtualPointer.hpp index 59a7e739..ee5ee7e2 100644 --- a/src/protocols/VirtualPointer.hpp +++ b/src/protocols/VirtualPointer.hpp @@ -7,6 +7,7 @@ #include "WaylandProtocol.hpp" #include "wlr-virtual-pointer-unstable-v1.hpp" #include "../helpers/signal/Signal.hpp" +#include "../devices/IPointer.hpp" class CVirtualPointerV1Resource { public: @@ -15,19 +16,35 @@ class CVirtualPointerV1Resource { struct { CSignal destroy; + CSignal move; + CSignal warp; + CSignal button; + CSignal axis; + CSignal frame; + + CSignal swipeBegin; + CSignal swipeUpdate; + CSignal swipeEnd; + + CSignal pinchBegin; + CSignal pinchUpdate; + CSignal pinchEnd; + + CSignal holdBegin; + CSignal holdEnd; } events; - bool good(); - wlr_pointer* wlr(); - wl_client* client(); + bool good(); + wl_client* client(); + + std::string name; private: - SP resource; - wlr_pointer pointer; + SP resource; - uint32_t axis = 0; + uint32_t axis = 0; - std::array axisEvents; + std::array axisEvents; }; class CVirtualPointerProtocol : public IWaylandProtocol { diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index 03e58956..073aa502 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -75,8 +75,8 @@ void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32 if (XDGVER >= OUTPUT_NAME_SINCE_VERSION) pXDGOutput->resource->sendName(PMONITOR->szName.c_str()); - if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && PMONITOR->output->description) - pXDGOutput->resource->sendDescription(PMONITOR->output->description); + if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && !PMONITOR->output->description.empty()) + pXDGOutput->resource->sendDescription(PMONITOR->output->description.c_str()); pXDGOutput->sendDetails(); @@ -93,7 +93,7 @@ void CXDGOutputProtocol::updateAllOutputs() { o->sendDetails(); - wlr_output_schedule_done(o->monitor->output); + o->monitor->scheduleDone(); } } diff --git a/src/protocols/XDGShell.cpp b/src/protocols/XDGShell.cpp index 9c56df93..8276ed55 100644 --- a/src/protocols/XDGShell.cpp +++ b/src/protocols/XDGShell.cpp @@ -4,6 +4,7 @@ #include "../managers/SeatManager.hpp" #include "core/Seat.hpp" #include "core/Compositor.hpp" +#include #define LOGM PROTO::xdgShell->protoLog diff --git a/src/protocols/core/Compositor.cpp b/src/protocols/core/Compositor.cpp index 691267b0..5cd6005a 100644 --- a/src/protocols/core/Compositor.cpp +++ b/src/protocols/core/Compositor.cpp @@ -6,6 +6,9 @@ #include "Subcompositor.hpp" #include "../Viewporter.hpp" #include "../../helpers/Monitor.hpp" +#include "../PresentationTime.hpp" +#include "../DRMSyncobj.hpp" +#include "../../render/Renderer.hpp" #define LOGM PROTO::compositor->protoLog @@ -102,58 +105,14 @@ CWLSurfaceResource::CWLSurfaceResource(SP resource_) : resource(reso pending.size = tfs / pending.scale; } - if (viewportResource) - viewportResource->verify(); - pending.damage.intersect(CBox{{}, pending.size}); - auto previousBuffer = current.buffer; - CRegion previousBufferDamage = accumulateCurrentBufferDamage(); - - current = pending; - pending.damage.clear(); - pending.bufferDamage.clear(); - - if (current.buffer && !bufferReleased) { - // without previous dolphin et al are weird vvv - //CRegion surfaceDamage = - // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); - current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. - - // release the buffer if it's synchronous as update() has done everything thats needed - // so we can let the app know we're done. - if (current.buffer->isSynchronous()) { - current.buffer->sendRelease(); - bufferReleased = true; - } - } - - // TODO: we should _accumulate_ and not replace above if sync - if (role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)role.get(); - if (subsurface->sync) - return; - - events.commit.emit(); - } else { - // send commit to all synced surfaces in this tree. - breadthfirst( - [](SP surf, const Vector2D& offset, void* data) { - if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { - auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); - if (!subsurface->sync) - return; - } - surf->events.commit.emit(); - }, - nullptr); - } + events.precommit.emit(); + if (pending.rejected) + return; - // for async buffers, we can only release the buffer once we are unrefing it from current. - if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { - previousBuffer->sendRelease(); - bufferReleased = true; - } + if (stateLocks <= 0) + commitPendingState(); }); resource->setDamage([this](CWlSurface* r, int32_t x, int32_t y, int32_t w, int32_t h) { pending.damage.add(CBox{x, y, w, h}); }); @@ -426,7 +385,97 @@ CRegion CWLSurfaceResource::accumulateCurrentBufferDamage() { Vector2D trc = current.transform % 2 == 1 ? Vector2D{current.buffer->size.y, current.buffer->size.x} : current.buffer->size; - return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(wlr_output_transform_invert(current.transform)), trc.x, trc.y).add(current.bufferDamage); + return surfaceDamage.scale(current.scale).transform(wlTransformToHyprutils(invertTransform(current.transform)), trc.x, trc.y).add(current.bufferDamage); +} + +void CWLSurfaceResource::lockPendingState() { + stateLocks++; +} + +void CWLSurfaceResource::unlockPendingState() { + stateLocks--; + if (stateLocks <= 0) + commitPendingState(); +} + +void CWLSurfaceResource::commitPendingState() { + auto previousBuffer = current.buffer; + CRegion previousBufferDamage = accumulateCurrentBufferDamage(); + + current = pending; + pending.damage.clear(); + pending.bufferDamage.clear(); + + if (current.buffer && !bufferReleased) { + // without previous dolphin et al are weird vvv + //CRegion surfaceDamage = + // current.damage.copy().scale(current.scale).transform(current.transform, current.size.x, current.size.y).add(current.bufferDamage).add(previousBufferDamage); + current.buffer->update(CBox{{}, {INT32_MAX, INT32_MAX}}); // FIXME: figure this out to not use this hack. QT apps are wonky without this. + + // release the buffer if it's synchronous as update() has done everything thats needed + // so we can let the app know we're done. + if (current.buffer->isSynchronous()) { + current.buffer->sendReleaseWithSurface(self.lock()); + bufferReleased = true; + } + } + + // TODO: we should _accumulate_ and not replace above if sync + if (role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)role.get(); + if (subsurface->sync) + return; + + events.commit.emit(); + } else { + // send commit to all synced surfaces in this tree. + breadthfirst( + [](SP surf, const Vector2D& offset, void* data) { + if (surf->role->role() == SURFACE_ROLE_SUBSURFACE) { + auto subsurface = (CWLSubsurfaceResource*)surf->role.get(); + if (!subsurface->sync) + return; + } + surf->events.commit.emit(); + }, + nullptr); + } + + // for async buffers, we can only release the buffer once we are unrefing it from current. + if (previousBuffer && !previousBuffer->isSynchronous() && !bufferReleased) { + if (previousBuffer->lockedByBackend) { + previousBuffer->hlEvents.backendRelease = previousBuffer->events.backendRelease.registerListener([this, previousBuffer](std::any data) { + if (!self.expired()) // could be dead in the dtor + previousBuffer->sendReleaseWithSurface(self.lock()); + else + previousBuffer->sendRelease(); + previousBuffer->hlEvents.backendRelease.reset(); + bufferReleased = true; + }); + } else + previousBuffer->sendReleaseWithSurface(self.lock()); + + bufferReleased = true; + } +} + +void CWLSurfaceResource::presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync) { + frame(when); + auto FEEDBACK = makeShared(self.lock()); + FEEDBACK->attachMonitor(pMonitor); + FEEDBACK->discarded(); + PROTO::presentation->queueData(FEEDBACK); + + if (!pMonitor || !pMonitor->outTimeline || !syncobj || !needsExplicitSync) + return; + + // attach explicit sync + g_pHyprRenderer->explicitPresented.emplace_back(self.lock()); + + if (syncobj->acquirePoint > pMonitor->lastWaitPoint) { + Debug::log(TRACE, "presentFeedback lastWaitPoint {} -> {}", pMonitor->lastWaitPoint, syncobj->acquirePoint); + pMonitor->lastWaitPoint = syncobj->acquirePoint; + } } CWLCompositorResource::CWLCompositorResource(SP resource_) : resource(resource_) { diff --git a/src/protocols/core/Compositor.hpp b/src/protocols/core/Compositor.hpp index 2f276719..5e6413c8 100644 --- a/src/protocols/core/Compositor.hpp +++ b/src/protocols/core/Compositor.hpp @@ -24,6 +24,7 @@ class CWLSurface; class CWLSurfaceResource; class CWLSubsurfaceResource; class CViewportResource; +class CDRMSyncobjSurfaceResource; class CWLCallbackResource { public: @@ -74,6 +75,7 @@ class CWLSurfaceResource { Vector2D sourceSize(); struct { + CSignal precommit; CSignal commit; CSignal map; CSignal unmap; @@ -81,11 +83,11 @@ class CWLSurfaceResource { CSignal destroy; } events; - struct { + struct SState { CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */; wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; int scale = 1; - SP buffer; + SP buffer; SP texture; Vector2D offset; Vector2D size; @@ -95,6 +97,7 @@ class CWLSurfaceResource { Vector2D destination; CBox source; } viewport; + bool rejected = false; // void reset() { @@ -115,9 +118,13 @@ class CWLSurfaceResource { std::vector> subsurfaces; WP role; WP viewportResource; + WP syncobj; // may not be present void breadthfirst(std::function, const Vector2D&, void*)> fn, void* data); CRegion accumulateCurrentBufferDamage(); + void presentFeedback(timespec* when, CMonitor* pMonitor, bool needsExplicitSync = false); + void lockPendingState(); + void unlockPendingState(); // returns a pair: found surface (null if not found) and surface local coords. // localCoords param is relative to 0,0 of this surface @@ -130,7 +137,10 @@ class CWLSurfaceResource { // tracks whether we should release the buffer bool bufferReleased = false; + int stateLocks = 0; + void destroy(); + void commitPendingState(); void bfHelper(std::vector> nodes, std::function, const Vector2D&, void*)> fn, void* data); }; diff --git a/src/protocols/core/Output.cpp b/src/protocols/core/Output.cpp index 10daa15e..4ba23cbe 100644 --- a/src/protocols/core/Output.cpp +++ b/src/protocols/core/Output.cpp @@ -21,8 +21,8 @@ CWLOutputResource::CWLOutputResource(SP resource_, SP pMoni PROTO::outputs.at(monitor->szName)->destroyResource(this); }); - resource->sendGeometry(0, 0, monitor->output->phys_width, monitor->output->phys_height, monitor->output->subpixel, monitor->output->make ? monitor->output->make : "null", - monitor->output->model ? monitor->output->model : "null", monitor->transform); + resource->sendGeometry(0, 0, monitor->output->physicalSize.x, monitor->output->physicalSize.y, (wl_output_subpixel)monitor->output->subpixel, monitor->output->make.c_str(), + monitor->output->model.c_str(), monitor->transform); if (resource->version() >= 4) { resource->sendName(monitor->szName.c_str()); resource->sendDescription(monitor->szDescription.c_str()); @@ -115,3 +115,9 @@ void CWLOutputProtocol::remove() { bool CWLOutputProtocol::isDefunct() { return defunct; } + +void CWLOutputProtocol::sendDone() { + for (auto& r : m_vOutputs) { + r->resource->sendDone(); + } +} diff --git a/src/protocols/core/Output.hpp b/src/protocols/core/Output.hpp index 46981635..46e4057b 100644 --- a/src/protocols/core/Output.hpp +++ b/src/protocols/core/Output.hpp @@ -26,6 +26,8 @@ class CWLOutputResource { private: SP resource; wl_client* pClient = nullptr; + + friend class CWLOutputProtocol; }; class CWLOutputProtocol : public IWaylandProtocol { @@ -35,6 +37,7 @@ class CWLOutputProtocol : public IWaylandProtocol { virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); SP outputResourceFrom(wl_client* client); + void sendDone(); WP monitor; diff --git a/src/protocols/core/Seat.cpp b/src/protocols/core/Seat.cpp index 464a901c..21a47575 100644 --- a/src/protocols/core/Seat.cpp +++ b/src/protocols/core/Seat.cpp @@ -254,8 +254,8 @@ void CWLKeyboardResource::sendKeymap(SP keyboard) { int fd; uint32_t size; if (keyboard) { - fd = keyboard->wlr()->keymap_fd; - size = keyboard->wlr()->keymap_size; + fd = keyboard->xkbKeymapFD; + size = keyboard->xkbKeymapString.length() + 1; } else { fd = open("/dev/null", O_RDONLY | O_CLOEXEC); if (fd < 0) { diff --git a/src/protocols/core/Shm.cpp b/src/protocols/core/Shm.cpp index 4088949f..75c2134a 100644 --- a/src/protocols/core/Shm.cpp +++ b/src/protocols/core/Shm.cpp @@ -41,20 +41,20 @@ CWLSHMBuffer::~CWLSHMBuffer() { ; } -eBufferCapability CWLSHMBuffer::caps() { - return BUFFER_CAPABILITY_DATAPTR; +Aquamarine::eBufferCapability CWLSHMBuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } -eBufferType CWLSHMBuffer::type() { - return BUFFER_TYPE_SHM; +Aquamarine::eBufferType CWLSHMBuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_SHM; } bool CWLSHMBuffer::isSynchronous() { return true; } -SSHMAttrs CWLSHMBuffer::shm() { - SSHMAttrs attrs; +Aquamarine::SSHMAttrs CWLSHMBuffer::shm() { + Aquamarine::SSHMAttrs attrs; attrs.success = true; attrs.fd = pool->fd; attrs.format = FormatUtils::shmToDRM(fmt); @@ -188,11 +188,18 @@ CWLSHMProtocol::CWLSHMProtocol(const wl_interface* iface, const int& ver, const void CWLSHMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { if (shmFormats.empty()) { - size_t len = 0; - const uint32_t* formats = wlr_renderer_get_shm_texture_formats(g_pCompositor->m_sWLRRenderer, &len); + shmFormats.push_back(WL_SHM_FORMAT_ARGB8888); + shmFormats.push_back(WL_SHM_FORMAT_XRGB8888); - for (size_t i = 0; i < len; ++i) { - shmFormats.push_back(FormatUtils::drmToShm(formats[i])); + static const std::array supportedShmFourccFormats = { + DRM_FORMAT_XBGR8888, DRM_FORMAT_ABGR8888, DRM_FORMAT_XRGB2101010, DRM_FORMAT_ARGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_ABGR2101010, + }; + + for (auto& fmt : g_pHyprOpenGL->getDRMFormats()) { + if (std::find(supportedShmFourccFormats.begin(), supportedShmFourccFormats.end(), fmt.drmFormat) == supportedShmFourccFormats.end()) + continue; + + shmFormats.push_back(fmt.drmFormat); } } diff --git a/src/protocols/core/Shm.hpp b/src/protocols/core/Shm.hpp index 70a8b208..fab325fe 100644 --- a/src/protocols/core/Shm.hpp +++ b/src/protocols/core/Shm.hpp @@ -29,16 +29,16 @@ class CSHMPool { void resize(size_t size); }; -class CWLSHMBuffer : public IWLBuffer { +class CWLSHMBuffer : public IHLBuffer { public: CWLSHMBuffer(SP pool, uint32_t id, int32_t offset, const Vector2D& size, int32_t stride, uint32_t fmt); virtual ~CWLSHMBuffer(); - virtual eBufferCapability caps(); - virtual eBufferType type(); + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); virtual void update(const CRegion& damage); virtual bool isSynchronous(); - virtual SSHMAttrs shm(); + virtual Aquamarine::SSHMAttrs shm(); virtual std::tuple beginDataPtr(uint32_t flags); virtual void endDataPtr(); diff --git a/src/protocols/types/Buffer.cpp b/src/protocols/types/Buffer.cpp index 5ed942e1..0217f7e2 100644 --- a/src/protocols/types/Buffer.cpp +++ b/src/protocols/types/Buffer.cpp @@ -1,41 +1,10 @@ #include "Buffer.hpp" -#include "WLBuffer.hpp" -SDMABUFAttrs IWLBuffer::dmabuf() { - return SDMABUFAttrs{}; +void IHLBuffer::sendRelease() { + resource->sendRelease(); } -SSHMAttrs IWLBuffer::shm() { - return SSHMAttrs{}; -} - -std::tuple IWLBuffer::beginDataPtr(uint32_t flags) { - return {nullptr, 0, 0}; -} - -void IWLBuffer::endDataPtr() { - ; // empty -} - -void IWLBuffer::sendRelease() { - if (!resource || !resource->resource) - return; - resource->resource->sendRelease(); -} - -void IWLBuffer::lock() { - locks++; -} - -void IWLBuffer::unlock() { - locks--; - - ASSERT(locks >= 0); - - if (locks <= 0) - sendRelease(); -} - -bool IWLBuffer::locked() { - return locks; +void IHLBuffer::sendReleaseWithSurface(SP surf) { + if (resource && resource->good()) + resource->sendReleaseWithSurface(surf); } diff --git a/src/protocols/types/Buffer.hpp b/src/protocols/types/Buffer.hpp index 9999a4e9..ba8278f3 100644 --- a/src/protocols/types/Buffer.hpp +++ b/src/protocols/types/Buffer.hpp @@ -1,75 +1,29 @@ #pragma once #include "../../defines.hpp" -#include "../../helpers/signal/Signal.hpp" #include "../../render/Texture.hpp" +#include "./WLBuffer.hpp" -#include -#include +#include -enum eBufferCapability { - BUFFER_CAPABILITY_DATAPTR = (1 << 0), -}; - -enum eBufferType { - BUFFER_TYPE_DMABUF = 0, - BUFFER_TYPE_SHM, - BUFFER_TYPE_MISC, -}; - -class CWLBufferResource; - -struct SDMABUFAttrs { - bool success = false; - Vector2D size; - uint32_t format = 0; // fourcc - uint64_t modifier = 0; - - int planes = 1; - std::array offsets = {0}; - std::array strides = {0}; - std::array fds = {-1, -1, -1, -1}; -}; - -struct SSHMAttrs { - bool success = false; - int fd = 0; - uint32_t format = 0; - Vector2D size; - int stride = 0; - int64_t offset = 0; -}; - -class IWLBuffer { +class IHLBuffer : public Aquamarine::IBuffer { public: - virtual ~IWLBuffer() { + virtual ~IHLBuffer() { ; - }; - - virtual eBufferCapability caps() = 0; - virtual eBufferType type() = 0; - virtual void update(const CRegion& damage) = 0; - virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu - virtual SDMABUFAttrs dmabuf(); - virtual SSHMAttrs shm(); - virtual std::tuple beginDataPtr(uint32_t flags); - virtual void endDataPtr(); - virtual void sendRelease(); - virtual void lock(); - virtual void unlock(); - virtual bool locked(); - - Vector2D size; - bool opaque = false; - - SP resource; - - SP texture; + } + virtual Aquamarine::eBufferCapability caps() = 0; + virtual Aquamarine::eBufferType type() = 0; + virtual void update(const CRegion& damage) = 0; + virtual bool isSynchronous() = 0; // whether the updates to this buffer are synchronous, aka happen over cpu + virtual bool good() = 0; + virtual void sendRelease(); + virtual void sendReleaseWithSurface(SP); + + SP texture; + bool opaque = false; + SP resource; struct { - CSignal destroy; - } events; - - private: - int locks = 0; + CHyprSignalListener backendRelease; + } hlEvents; }; diff --git a/src/protocols/types/DMABuffer.cpp b/src/protocols/types/DMABuffer.cpp index 7c3a9886..63a26c76 100644 --- a/src/protocols/types/DMABuffer.cpp +++ b/src/protocols/types/DMABuffer.cpp @@ -3,7 +3,7 @@ #include "../../render/Renderer.hpp" #include "../../helpers/Format.hpp" -CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_) : attrs(attrs_) { +CDMABuffer::CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_) : attrs(attrs_) { g_pHyprRenderer->makeEGLCurrent(); listeners.resourceDestroy = events.destroy.registerListener([this](std::any d) { @@ -31,12 +31,12 @@ CDMABuffer::~CDMABuffer() { closeFDs(); } -eBufferCapability CDMABuffer::caps() { - return BUFFER_CAPABILITY_DATAPTR; +Aquamarine::eBufferCapability CDMABuffer::caps() { + return Aquamarine::eBufferCapability::BUFFER_CAPABILITY_DATAPTR; } -eBufferType CDMABuffer::type() { - return BUFFER_TYPE_DMABUF; +Aquamarine::eBufferType CDMABuffer::type() { + return Aquamarine::eBufferType::BUFFER_TYPE_DMABUF; } void CDMABuffer::update(const CRegion& damage) { @@ -47,7 +47,7 @@ bool CDMABuffer::isSynchronous() { return false; } -SDMABUFAttrs CDMABuffer::dmabuf() { +Aquamarine::SDMABUFAttrs CDMABuffer::dmabuf() { return attrs; } diff --git a/src/protocols/types/DMABuffer.hpp b/src/protocols/types/DMABuffer.hpp index d07840b7..6977df4c 100644 --- a/src/protocols/types/DMABuffer.hpp +++ b/src/protocols/types/DMABuffer.hpp @@ -2,16 +2,16 @@ #include "Buffer.hpp" -class CDMABuffer : public IWLBuffer { +class CDMABuffer : public IHLBuffer { public: - CDMABuffer(uint32_t id, wl_client* client, SDMABUFAttrs const& attrs_); + CDMABuffer(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs const& attrs_); virtual ~CDMABuffer(); - virtual eBufferCapability caps(); - virtual eBufferType type(); + virtual Aquamarine::eBufferCapability caps(); + virtual Aquamarine::eBufferType type(); virtual bool isSynchronous(); virtual void update(const CRegion& damage); - virtual SDMABUFAttrs dmabuf(); + virtual Aquamarine::SDMABUFAttrs dmabuf(); virtual std::tuple beginDataPtr(uint32_t flags); virtual void endDataPtr(); bool good(); @@ -21,7 +21,7 @@ class CDMABuffer : public IWLBuffer { bool success = false; private: - SDMABUFAttrs attrs; + Aquamarine::SDMABUFAttrs attrs; struct { CHyprSignalListener resourceDestroy; diff --git a/src/protocols/types/WLBuffer.cpp b/src/protocols/types/WLBuffer.cpp index e53538cb..d34a867d 100644 --- a/src/protocols/types/WLBuffer.cpp +++ b/src/protocols/types/WLBuffer.cpp @@ -1,5 +1,10 @@ #include "WLBuffer.hpp" #include "Buffer.hpp" +#include "../core/Compositor.hpp" +#include "../DRMSyncobj.hpp" +#include "../../helpers/sync/SyncTimeline.hpp" +#include "../../Compositor.hpp" +#include CWLBufferResource::CWLBufferResource(SP resource_) : resource(resource_) { if (!good()) @@ -27,6 +32,16 @@ void CWLBufferResource::sendRelease() { resource->sendRelease(); } +void CWLBufferResource::sendReleaseWithSurface(SP surf) { + sendRelease(); + + if (!surf || !surf->syncobj) + return; + + if (drmSyncobjTimelineSignal(g_pCompositor->m_iDRMFD, &surf->syncobj->releaseTimeline->timeline->handle, &surf->syncobj->releasePoint, 1)) + Debug::log(ERR, "sendReleaseWithSurface: drmSyncobjTimelineSignal failed"); +} + wl_resource* CWLBufferResource::getResource() { return resource->resource(); } diff --git a/src/protocols/types/WLBuffer.hpp b/src/protocols/types/WLBuffer.hpp index ac177965..59512128 100644 --- a/src/protocols/types/WLBuffer.hpp +++ b/src/protocols/types/WLBuffer.hpp @@ -7,7 +7,8 @@ #include "wayland.hpp" #include "../../helpers/signal/Signal.hpp" -class IWLBuffer; +class IHLBuffer; +class CWLSurfaceResource; class CWLBufferResource { public: @@ -16,9 +17,10 @@ class CWLBufferResource { bool good(); void sendRelease(); + void sendReleaseWithSurface(SP); wl_resource* getResource(); - WP buffer; + WP buffer; WP self; @@ -27,5 +29,5 @@ class CWLBufferResource { SP resource; - friend class IWLBuffer; + friend class IHLBuffer; }; -- cgit v1.2.3