Core: Move to aquamarine (#6608)

Moves Hyprland from wlroots to aquamarine for the backend.

---------

Signed-off-by: Vaxry <vaxry@vaxry.net>
Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
Co-authored-by: Jan Beich <jbeich@FreeBSD.org>
Co-authored-by: vaxerski <vaxerski@users.noreply.github.com>
Co-authored-by: UjinT34 <41110182+UjinT34@users.noreply.github.com>
Co-authored-by: Tom Englund <tomenglund26@gmail.com>
Co-authored-by: Ikalco <73481042+ikalco@users.noreply.github.com>
Co-authored-by: diniamo <diniamo53@gmail.com>
This commit is contained in:
Vaxry 2024-07-21 13:09:54 +02:00 committed by GitHub
parent f642fb97df
commit 016da234d0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
131 changed files with 4755 additions and 3460 deletions

View file

@ -1,48 +1,9 @@
#include "CursorShape.hpp"
#include <algorithm>
#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);
}

302
src/protocols/DRMLease.cpp Normal file
View file

@ -0,0 +1,302 @@
#include "DRMLease.hpp"
#include "../Compositor.hpp"
#include <aquamarine/backend/DRM.hpp>
#include <fcntl.h>
#define LOGM PROTO::lease->protoLog
CDRMLeaseResource::CDRMLeaseResource(SP<CWpDrmLeaseV1> resource_, SP<CDRMLeaseRequestResource> 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<SP<Aquamarine::IOutput>> 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<CWpDrmLeaseRequestV1> 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<CDRMLeaseResource>(makeShared<CWpDrmLeaseV1>(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> 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<CWpDrmLeaseConnectorV1> resource_, SP<CMonitor> 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<CWpDrmLeaseDeviceV1> 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<CDRMLeaseRequestResource>(makeShared<CWpDrmLeaseRequestV1>(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<CMonitor> monitor) {
if (std::find_if(connectorsSent.begin(), connectorsSent.end(), [monitor](const auto& e) { return e->monitor == monitor; }) != connectorsSent.end())
return;
auto RESOURCE = makeShared<CDRMLeaseConnectorResource>(makeShared<CWpDrmLeaseConnectorV1>(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<Aquamarine::CDRMBackend> 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<CDRMLeaseDevice>(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<CDRMLeaseDeviceResource>(makeShared<CWpDrmLeaseDeviceV1>(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<CMonitor> 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();
}
}

137
src/protocols/DRMLease.hpp Normal file
View file

@ -0,0 +1,137 @@
#pragma once
#include <memory>
#include <vector>
#include <unordered_map>
#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<CWpDrmLeaseV1> resource_, SP<CDRMLeaseRequestResource> request);
bool good();
WP<CDRMLeaseDeviceResource> parent;
std::vector<WP<CDRMLeaseConnectorResource>> requested;
WP<Aquamarine::CDRMLease> lease;
int leaseFD = -1;
struct {
CHyprSignalListener destroyLease;
} listeners;
private:
SP<CWpDrmLeaseV1> resource;
};
class CDRMLeaseRequestResource {
public:
CDRMLeaseRequestResource(SP<CWpDrmLeaseRequestV1> resource_);
bool good();
WP<CDRMLeaseDeviceResource> parent;
WP<CDRMLeaseRequestResource> self;
std::vector<WP<CDRMLeaseConnectorResource>> requested;
private:
SP<CWpDrmLeaseRequestV1> resource;
};
class CDRMLeaseConnectorResource {
public:
CDRMLeaseConnectorResource(SP<CWpDrmLeaseConnectorV1> resource_, SP<CMonitor> monitor_);
static SP<CDRMLeaseConnectorResource> fromResource(wl_resource*);
bool good();
void sendData();
WP<CDRMLeaseConnectorResource> self;
WP<CDRMLeaseDeviceResource> parent;
WP<CMonitor> monitor;
bool dead = false;
private:
SP<CWpDrmLeaseConnectorV1> resource;
struct {
CHyprSignalListener destroyMonitor;
} listeners;
friend class CDRMLeaseDeviceResource;
};
class CDRMLeaseDeviceResource {
public:
CDRMLeaseDeviceResource(SP<CWpDrmLeaseDeviceV1> resource_);
bool good();
void sendConnector(SP<CMonitor> monitor);
std::vector<WP<CDRMLeaseConnectorResource>> connectorsSent;
WP<CDRMLeaseDeviceResource> self;
private:
SP<CWpDrmLeaseDeviceV1> resource;
friend class CDRMLeaseProtocol;
};
class CDRMLeaseDevice {
public:
CDRMLeaseDevice(SP<Aquamarine::CDRMBackend> drmBackend);
std::string name = "";
bool success = false;
SP<Aquamarine::CDRMBackend> backend;
std::vector<WP<CMonitor>> 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<CMonitor> monitor);
private:
void destroyResource(CDRMLeaseDeviceResource* resource);
void destroyResource(CDRMLeaseConnectorResource* resource);
void destroyResource(CDRMLeaseRequestResource* resource);
void destroyResource(CDRMLeaseResource* resource);
//
std::vector<SP<CDRMLeaseDeviceResource>> m_vManagers;
std::vector<SP<CDRMLeaseConnectorResource>> m_vConnectors;
std::vector<SP<CDRMLeaseRequestResource>> m_vRequests;
std::vector<SP<CDRMLeaseResource>> m_vLeases;
SP<CDRMLeaseDevice> primaryDevice;
friend class CDRMLeaseDeviceResource;
friend class CDRMLeaseConnectorResource;
friend class CDRMLeaseRequestResource;
friend class CDRMLeaseResource;
};
namespace PROTO {
inline UP<CDRMLeaseProtocol> lease;
};

View file

@ -0,0 +1,183 @@
#include "DRMSyncobj.hpp"
#include <algorithm>
#include "core/Compositor.hpp"
#include "../helpers/sync/SyncTimeline.hpp"
#include "../Compositor.hpp"
#include <fcntl.h>
#define LOGM PROTO::sync->protoLog
CDRMSyncobjSurfaceResource::CDRMSyncobjSurfaceResource(SP<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> 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<CWpLinuxDrmSyncobjTimelineV1> 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> 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<CWpLinuxDrmSyncobjManagerV1> 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<CDRMSyncobjSurfaceResource>(makeShared<CWpLinuxDrmSyncobjSurfaceV1>(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<CDRMSyncobjTimelineResource>(makeShared<CWpLinuxDrmSyncobjTimelineV1>(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<CDRMSyncobjManagerResource>(makeShared<CWpLinuxDrmSyncobjManagerV1>(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; });
}

View file

@ -0,0 +1,82 @@
#pragma once
#include <memory>
#include <vector>
#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<CWpLinuxDrmSyncobjSurfaceV1> resource_, SP<CWLSurfaceResource> surface_);
bool good();
WP<CWLSurfaceResource> surface;
WP<CDRMSyncobjTimelineResource> acquireTimeline, releaseTimeline;
uint64_t acquirePoint = 0, releasePoint = 0;
private:
SP<CWpLinuxDrmSyncobjSurfaceV1> resource;
struct {
CHyprSignalListener surfacePrecommit;
} listeners;
};
class CDRMSyncobjTimelineResource {
public:
CDRMSyncobjTimelineResource(SP<CWpLinuxDrmSyncobjTimelineV1> resource_, int fd_);
static SP<CDRMSyncobjTimelineResource> fromResource(wl_resource*);
bool good();
WP<CDRMSyncobjTimelineResource> self;
int fd = -1;
SP<CSyncTimeline> timeline;
private:
SP<CWpLinuxDrmSyncobjTimelineV1> resource;
};
class CDRMSyncobjManagerResource {
public:
CDRMSyncobjManagerResource(SP<CWpLinuxDrmSyncobjManagerV1> resource_);
bool good();
private:
SP<CWpLinuxDrmSyncobjManagerV1> 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<SP<CDRMSyncobjManagerResource>> m_vManagers;
std::vector<SP<CDRMSyncobjTimelineResource>> m_vTimelines;
std::vector<SP<CDRMSyncobjSurfaceResource>> m_vSurfaces;
//
int drmFD = -1;
friend class CDRMSyncobjManagerResource;
friend class CDRMSyncobjTimelineResource;
friend class CDRMSyncobjSurfaceResource;
};
namespace PROTO {
inline UP<CDRMSyncobjProtocol> sync;
};

View file

@ -34,7 +34,7 @@ CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> 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<CZwlrGammaControlV1> resource_, wl_resource* out
gammaTableSet = true;
close(fd);
// translate the table to AQ format
std::vector<uint16_t> 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);

View file

@ -23,7 +23,7 @@ class CGammaControl {
CMonitor* pMonitor = nullptr;
size_t gammaSize = 0;
bool gammaTableSet = false;
std::vector<uint16_t> gammaTable;
std::vector<uint16_t> gammaTable; // [r,g,b]+
void onMonitorDestroy();

View file

@ -4,6 +4,7 @@
#include "../devices/IKeyboard.hpp"
#include <sys/mman.h>
#include "core/Compositor.hpp"
#include <cstring>
#define LOGM PROTO::ime->protoLog
@ -19,7 +20,7 @@ CInputMethodKeyboardGrabV2::CInputMethodKeyboardGrabV2(SP<CZwpInputMethodKeyboar
return;
}
sendKeyboardData(g_pSeatManager->keyboard->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<IKeyboard> 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<IKeyboard> keyboard) {
for (auto& gw : grabs) {
auto g = gw.lock();

View file

@ -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<IKeyboard> 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<IKeyboard> keyboard);
private:
SP<CZwpInputMethodKeyboardGrabV2> resource;
WP<CInputMethodV2> owner;
wlr_keyboard* pLastKeyboard = nullptr; // READ-ONLY
WP<IKeyboard> pLastKeyboard;
};
class CInputMethodPopupV2 {

View file

@ -6,6 +6,7 @@
#include <sys/mman.h>
#include <xf86drm.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "core/Compositor.hpp"
#include "types/DMABuffer.hpp"
#include "types/WLBuffer.hpp"
@ -22,21 +23,66 @@ static std::optional<dev_t> devIDFromFD(int fd) {
return stat.st_rdev;
}
CCompiledDMABUFFeedback::CCompiledDMABUFFeedback(dev_t device, std::vector<SDMABufTranche> tranches_) {
CDMABUFFormatTable::CDMABUFFormatTable(SDMABUFTranche _rendererTranche, std::vector<std::pair<SP<CMonitor>, SDMABUFTranche>> tranches_) :
rendererTranche(_rendererTranche), monitorTranches(tranches_) {
std::vector<SDMABUFFormatTableEntry> formatsVec;
std::set<std::pair<uint32_t, uint64_t>> 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);
int fds[2] = {0};
allocateSHMFilePair(tableLen, &fds[0], &fds[1]);
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());
}
}
}
}
auto arr = (SDMABUFFeedbackTableEntry*)mmap(nullptr, tableLen, PROT_READ | PROT_WRITE, MAP_SHARED, fds[0], 0);
tableSize = formatsVec.size() * sizeof(SDMABUFFormatTableEntry);
int fds[2] = {0};
allocateSHMFilePair(tableSize, &fds[0], &fds[1]);
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<SDMAB
close(fds[0]);
std::vector<std::pair<uint32_t, uint64_t>> formatsVec;
for (auto& f : formats) {
formatsVec.push_back(f);
}
std::copy(formatsVec.begin(), formatsVec.end(), arr);
size_t i = 0;
for (auto& [fmt, mod] : formatsVec) {
arr[i++] = SDMABUFFeedbackTableEntry{
.fmt = fmt,
.modifier = mod,
};
}
munmap(arr, tableSize);
munmap(arr, tableLen);
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<CDMABuffer>(id, client, attrs);
buffer->resource->buffer = buffer;
@ -103,7 +134,7 @@ CLinuxDMABBUFParamsResource::CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParam
resource->setOnDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); });
resource->setDestroy([this](CZwpLinuxBufferParamsV1* r) { PROTO::linuxDma->destroyResource(this); });
attrs = makeShared<SDMABUFAttrs>();
attrs = makeShared<Aquamarine::SDMABUFAttrs>();
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,32 +308,9 @@ CLinuxDMABUFFeedbackResource::CLinuxDMABUFFeedbackResource(SP<CZwpLinuxDmabufFee
resource->setOnDestroy([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* feedback = PROTO::linuxDma->defaultFeedback.get();
resource->sendFormatTable(feedback->tableFD, feedback->tableLen);
// send default feedback
struct wl_array deviceArr = {
.size = sizeof(feedback->mainDevice),
.data = (void*)&feedback->mainDevice,
};
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->sendTrancheFormats(&indices);
wl_array_release(&indices);
resource->sendTrancheDone();
resource->sendDone();
auto& formatTable = PROTO::linuxDma->formatTable;
resource->sendFormatTable(formatTable->tableFD, formatTable->tableSize);
sendDefaultFeedback();
}
CLinuxDMABUFFeedbackResource::~CLinuxDMABUFFeedbackResource() {
@ -313,6 +321,41 @@ bool CLinuxDMABUFFeedbackResource::good() {
return resource->resource();
}
void CLinuxDMABUFFeedbackResource::sendTranche(SDMABUFTranche& tranche) {
struct wl_array deviceArr = {
.size = sizeof(tranche.device),
.data = (void*)&tranche.device,
};
resource->sendTrancheTargetDevice(&deviceArr);
resource->sendTrancheFlags((zwpLinuxDmabufFeedbackV1TrancheFlags)tranche.flags);
wl_array indices = {
.size = tranche.indicies.size() * sizeof(tranche.indicies.at(0)),
.data = tranche.indicies.data(),
};
resource->sendTrancheFormats(&indices);
resource->sendTrancheDone();
}
// default tranche is based on renderer (egl)
void CLinuxDMABUFFeedbackResource::sendDefaultFeedback() {
auto mainDevice = PROTO::linuxDma->mainDevice;
auto& formatTable = PROTO::linuxDma->formatTable;
struct wl_array deviceArr = {
.size = sizeof(mainDevice),
.data = (void*)&mainDevice,
};
resource->sendMainDevice(&deviceArr);
sendTranche(formatTable->rendererTranche);
resource->sendDone();
lastFeedbackWasScanout = false;
}
CLinuxDMABUFResource::CLinuxDMABUFResource(SP<CZwpLinuxDmabufV1> resource_) : resource(resource_) {
if (!good())
return;
@ -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
resource->sendModifier(fmt.drmFormat, mod >> 32, mod & 0xFFFFFFFF);
}
// TODO: https://gitlab.freedesktop.org/xorg/xserver/-/issues/1166
resource->sendModifier(fmt, 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<SDMABufTranche> tches;
tches.push_back(tranche);
std::vector<std::pair<SP<CMonitor>, SDMABUFTranche>> tches;
defaultFeedback = std::make_unique<CCompiledDMABUFFeedback>(*dev, 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<CMonitor*>(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<CMonitor*>(param);
auto mon = pMonitor->self.lock();
std::erase_if(formatTable->monitorTranches, [mon](std::pair<SP<CMonitor>, SDMABUFTranche> pair) { return pair.first == mon; });
resetFormatTable();
});
}
formatTable = std::make_unique<CDMABUFFormatTable>(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<CDMABUFFormatTable>(formatTable->rendererTranche, formatTable->monitorTranches);
for (auto& feedback : m_vFeedbacks) {
feedback->resource->sendFormatTable(newFormatTable->tableFD, newFormatTable->tableSize);
if (feedback->lastFeedbackWasScanout) {
SP<CMonitor> 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<CWLSurfaceResource> surface, SP<CMonitor> pMonitor) {
SP<CLinuxDMABUFFeedbackResource> 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<SP<CMonitor>, 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;
}

View file

@ -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 <aquamarine/buffer/Buffer.hpp>
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<uint16_t> indices;
};
struct SDMABufTranche {
struct SDMABUFTranche {
dev_t device = 0;
uint32_t flags = 0;
std::vector<SDRMFormat> formats;
std::vector<uint16_t> indicies;
};
class CCompiledDMABUFFeedback {
class CDMABUFFormatTable {
public:
CCompiledDMABUFFeedback(dev_t device, std::vector<SDMABufTranche> tranches);
~CCompiledDMABUFFeedback();
CDMABUFFormatTable(SDMABUFTranche rendererTranche, std::vector<std::pair<SP<CMonitor>, SDMABUFTranche>> tranches);
~CDMABUFFormatTable();
dev_t mainDevice = 0;
int tableFD = -1;
size_t tableLen = 0;
std::vector<std::pair<uint32_t, uint64_t>> tranches;
int tableFD = -1;
size_t tableSize = 0;
SDMABUFTranche rendererTranche;
std::vector<std::pair<SP<CMonitor>, SDMABUFTranche>> monitorTranches;
};
class CLinuxDMABBUFParamsResource {
@ -66,12 +62,12 @@ class CLinuxDMABBUFParamsResource {
CLinuxDMABBUFParamsResource(SP<CZwpLinuxBufferParamsV1> 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<SDMABUFAttrs> attrs;
WP<CLinuxDMABuffer> createdBuffer;
bool used = false;
SP<Aquamarine::SDMABUFAttrs> attrs;
WP<CLinuxDMABuffer> createdBuffer;
bool used = false;
private:
SP<CZwpLinuxBufferParamsV1> resource;
@ -86,11 +82,16 @@ class CLinuxDMABUFFeedbackResource {
~CLinuxDMABUFFeedbackResource();
bool good();
void sendDefaultFeedback();
void sendTranche(SDMABUFTranche& tranche);
SP<CWLSurfaceResource> surface; // optional, for surface feedbacks
private:
SP<CZwpLinuxDmabufFeedbackV1> 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<CWLSurfaceResource> surface, SP<CMonitor> 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<SP<CLinuxDMABUFResource>> m_vManagers;
std::vector<SP<CLinuxDMABUFFeedbackResource>> m_vFeedbacks;
std::vector<SP<CLinuxDMABBUFParamsResource>> m_vParams;
std::vector<SP<CLinuxDMABuffer>> m_vBuffers;
UP<CCompiledDMABUFFeedback> defaultFeedback;
UP<CDMABUFFormatTable> formatTable;
dev_t mainDevice;
int mainDeviceFD = -1;

View file

@ -2,12 +2,11 @@
#include <algorithm>
#include <xf86drm.h>
#include "../Compositor.hpp"
#include <wlr/render/drm_format_set.h>
#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<CWlDrm> 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<CWlDrm> 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);

View file

@ -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();

View file

@ -2,6 +2,8 @@
#include <algorithm>
#include "../Compositor.hpp"
using namespace Aquamarine;
#define LOGM PROTO::outputManagement->protoLog
COutputManager::COutputManager(SP<CZwlrOutputManagerV1> 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<Aquamarine::SOutputMode> mode) {
const auto RESOURCE = PROTO::outputManagement->m_vModes.emplace_back(makeShared<COutputMode>(makeShared<CZwlrOutputModeV1>(resource->client(), resource->version(), 0), mode));
if (!RESOURCE->good()) {
@ -225,7 +227,7 @@ CMonitor* COutputHead::monitor() {
return pMonitor;
}
COutputMode::COutputMode(SP<CZwlrOutputModeV1> resource_, wlr_output_mode* mode_) : resource(resource_), mode(mode_) {
COutputMode::COutputMode(SP<CZwlrOutputModeV1> resource_, SP<Aquamarine::SOutputMode> 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<Aquamarine::SOutputMode> COutputMode::getMode() {
return mode.lock();
}
COutputConfiguration::COutputConfiguration(SP<CZwlrOutputConfigurationV1> resource_, SP<COutputManager> 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(SP<CZwlrOutputConfigurationHe
committedProperties |= OUTPUT_HEAD_COMMITTED_MODE;
state.mode = MODE;
LOGM(LOG, " | configHead for {}: set mode to {}x{}@{}", pMonitor->szName, 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) {

View file

@ -6,6 +6,7 @@
#include "WaylandProtocol.hpp"
#include "wlr-output-management-unstable-v1.hpp"
#include "../helpers/signal/Signal.hpp"
#include <aquamarine/output/Output.hpp>
class CMonitor;
@ -34,15 +35,15 @@ class COutputManager {
class COutputMode {
public:
COutputMode(SP<CZwlrOutputModeV1> resource_, wlr_output_mode* mode_);
COutputMode(SP<CZwlrOutputModeV1> resource_, SP<Aquamarine::SOutputMode> mode_);
bool good();
wlr_output_mode* getMode();
void sendAllData();
bool good();
SP<Aquamarine::SOutputMode> getMode();
void sendAllData();
private:
SP<CZwlrOutputModeV1> resource;
wlr_output_mode* mode = nullptr;
SP<CZwlrOutputModeV1> resource;
WP<Aquamarine::SOutputMode> mode;
friend class COutputHead;
friend class COutputManagementProtocol;
@ -61,7 +62,7 @@ class COutputHead {
SP<CZwlrOutputHeadV1> resource;
CMonitor* pMonitor = nullptr;
void makeAndSendNewMode(wlr_output_mode* mode);
void makeAndSendNewMode(SP<Aquamarine::SOutputMode> mode);
void sendCurrentMode();
std::vector<WP<COutputMode>> modes;

View file

@ -17,7 +17,7 @@ COutputPower::COutputPower(SP<CZwlrOutputPowerV1> 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);

View file

@ -3,6 +3,8 @@
#include "../helpers/Monitor.hpp"
#include "../managers/HookSystemManager.hpp"
#include "core/Compositor.hpp"
#include "core/Output.hpp"
#include <aquamarine/output/Output.hpp>
#define LOGM PROTO::presentation->protoLog
@ -41,13 +43,11 @@ bool CPresentationFeedback::good() {
}
void CPresentationFeedback::sendQueued(SP<CQueuedPresentationData> 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<CQueuedPresentationData> 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)

View file

@ -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<CTexture>(sourceTex);
auto TEXTURE = makeShared<CTexture>(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<CTexture>(sourceTex);
auto TEXTURE = makeShared<CTexture>(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;
}

View file

@ -8,9 +8,10 @@
#include "../managers/HookSystemManager.hpp"
#include "../helpers/Timer.hpp"
#include "../managers/eventLoop/EventLoopTimer.hpp"
#include <aquamarine/buffer/Buffer.hpp>
class CMonitor;
class IWLBuffer;
class IHLBuffer;
enum eClientOwners {
CLIENT_SCREENCOPY = 0,
@ -56,7 +57,7 @@ struct SScreencopyFrame {
bool bufferDMA = false;
WP<IWLBuffer> buffer;
WP<IHLBuffer> 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<SScreencopyFrame*> m_vFramesAwaitingWrite;
wlr_buffer* m_pLastMonitorBackBuffer = nullptr;
SP<Aquamarine::IBuffer> m_pLastMonitorBackBuffer;
void shareAllFrames(CMonitor* pMonitor);
void shareFrame(SScreencopyFrame* frame);

View file

@ -5,6 +5,7 @@
#include "core/Seat.hpp"
#include "core/Compositor.hpp"
#include <algorithm>
#include <cstring>
#define LOGM PROTO::tablet->protoLog
@ -44,17 +45,17 @@ bool CTabletPadGroupV2Resource::good() {
return resource->resource();
}
void CTabletPadGroupV2Resource::sendData(SP<CTabletPad> pad, wlr_tablet_pad_group* group) {
resource->sendModes(group->mode_count);
void CTabletPadGroupV2Resource::sendData(SP<CTabletPad> pad, SP<Aquamarine::ITabletPad::STabletPadGroup> 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<CTabletPadStripV2Resource>(makeShared<CZwpTabletPadStripV2>(resource->client(), resource->version(), 0), i));
@ -67,7 +68,7 @@ void CTabletPadGroupV2Resource::sendData(SP<CTabletPad> 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<CTabletPadRingV2Resource>(makeShared<CZwpTabletPadRingV2>(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<Aquamarine::ITabletPad::STabletPadGroup> group, size_t idx) {
const auto RESOURCE =
PROTO::tablet->m_vGroups.emplace_back(makeShared<CTabletPadGroupV2Resource>(makeShared<CZwpTabletPadGroupV2>(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)

View file

@ -6,6 +6,7 @@
#include "WaylandProtocol.hpp"
#include "tablet-v2.hpp"
#include "../helpers/math/Math.hpp"
#include <aquamarine/input/Input.hpp>
class CTablet;
class CTabletTool;
@ -51,7 +52,7 @@ class CTabletPadGroupV2Resource {
CTabletPadGroupV2Resource(SP<CZwpTabletPadGroupV2> resource_, size_t idx);
bool good();
void sendData(SP<CTabletPad> pad, wlr_tablet_pad_group* group);
void sendData(SP<CTabletPad> pad, SP<Aquamarine::ITabletPad::STabletPadGroup> group);
std::vector<WP<CTabletPadRingV2Resource>> rings;
std::vector<WP<CTabletPadStripV2Resource>> strips;
@ -83,7 +84,7 @@ class CTabletPadV2Resource {
private:
SP<CZwpTabletPadV2> resource;
void createGroup(wlr_tablet_pad_group* group, size_t idx);
void createGroup(SP<Aquamarine::ITabletPad::STabletPadGroup> group, size_t idx);
friend class CTabletSeat;
friend class CTabletV2Protocol;

View file

@ -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<SScreencopyFrame*> 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());

View file

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

View file

@ -52,6 +52,21 @@ CViewportResource::CViewportResource(SP<CWpViewport> resource_, SP<CWLSurfaceRes
surface->pending.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<CWpViewporter> resource_) : resource(resource_) {
if (!good())
return;

View file

@ -15,11 +15,14 @@ class CViewportResource {
~CViewportResource();
bool good();
void verify();
WP<CWLSurfaceResource> surface;
private:
SP<CWpViewport> resource;
struct {
CHyprSignalListener surfacePrecommit;
} listeners;
};
class CViewporterResource {

View file

@ -1,12 +1,9 @@
#include "VirtualKeyboard.hpp"
#include <sys/mman.h>
#include "../devices/IKeyboard.hpp"
#define LOGM PROTO::virtualKeyboard->protoLog
static const struct wlr_keyboard_impl virtualKeyboardImpl = {
.name = "virtual-keyboard",
};
CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1> resource_) : resource(resource_) {
if (!good())
return;
@ -28,13 +25,17 @@ CVirtualKeyboardV1Resource::CVirtualKeyboardV1Resource(SP<CZwpVirtualKeyboardV1>
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<CZwpVirtualKeyboardV1>
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<CZwpVirtualKeyboardV1>
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<CZwpVirtualKeyboardV1>
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) {

View file

@ -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<CZwpVirtualKeyboardV1> resource;
wlr_keyboard keyboard;
void releasePressed();
bool hasKeymap = false;
std::vector<uint32_t> pressed;
};
class CVirtualKeyboardProtocol : public IWaylandProtocol {

View file

@ -2,10 +2,6 @@
#define LOGM PROTO::virtualPointer->protoLog
static const wlr_pointer_impl pointerImpl = {
.name = "virtual-pointer-v1",
};
CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> resource_) : resource(resource_) {
if (!good())
return;
@ -19,41 +15,30 @@ CVirtualPointerV1Resource::CVirtualPointerV1Resource(SP<CZwlrVirtualPointerV1> 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<CZwlrVirtualPointerV1> 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<CZwlrVirtualPointerV1> 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<CZwlrVirtualPointerV1> 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();
}

View file

@ -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<CZwlrVirtualPointerV1> resource;
wlr_pointer pointer;
SP<CZwlrVirtualPointerV1> resource;
uint32_t axis = 0;
uint32_t axis = 0;
std::array<wlr_pointer_axis_event, 2> axisEvents;
std::array<IPointer::SAxisEvent, 2> axisEvents;
};
class CVirtualPointerProtocol : public IWaylandProtocol {

View file

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

View file

@ -4,6 +4,7 @@
#include "../managers/SeatManager.hpp"
#include "core/Seat.hpp"
#include "core/Compositor.hpp"
#include <cstring>
#define LOGM PROTO::xdgShell->protoLog

View file

@ -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<CWlSurface> 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();
events.precommit.emit();
if (pending.rejected)
return;
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<CWLSurfaceResource> 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) {
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<CWLSurfaceResource> 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<CQueuedPresentationData>(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<CWlCompositor> resource_) : resource(resource_) {

View file

@ -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<IWLBuffer> buffer;
SP<IHLBuffer> buffer;
SP<CTexture> 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<WP<CWLSubsurfaceResource>> subsurfaces;
WP<ISurfaceRole> role;
WP<CViewportResource> viewportResource;
WP<CDRMSyncobjSurfaceResource> syncobj; // may not be present
void breadthfirst(std::function<void(SP<CWLSurfaceResource>, 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<SP<CWLSurfaceResource>> nodes, std::function<void(SP<CWLSurfaceResource>, const Vector2D&, void*)> fn, void* data);
};

View file

@ -21,8 +21,8 @@ CWLOutputResource::CWLOutputResource(SP<CWlOutput> resource_, SP<CMonitor> 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();
}
}

View file

@ -26,6 +26,8 @@ class CWLOutputResource {
private:
SP<CWlOutput> 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<CWLOutputResource> outputResourceFrom(wl_client* client);
void sendDone();
WP<CMonitor> monitor;

View file

@ -254,8 +254,8 @@ void CWLKeyboardResource::sendKeymap(SP<IKeyboard> 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) {

View file

@ -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<DRMFormat, 6> 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);
}
}

View file

@ -29,16 +29,16 @@ class CSHMPool {
void resize(size_t size);
};
class CWLSHMBuffer : public IWLBuffer {
class CWLSHMBuffer : public IHLBuffer {
public:
CWLSHMBuffer(SP<CWLSHMPoolResource> 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<uint8_t*, uint32_t, size_t> beginDataPtr(uint32_t flags);
virtual void endDataPtr();

View file

@ -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<uint8_t*, uint32_t, size_t> 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<CWLSurfaceResource> surf) {
if (resource && resource->good())
resource->sendReleaseWithSurface(surf);
}

View file

@ -1,75 +1,29 @@
#pragma once
#include "../../defines.hpp"
#include "../../helpers/signal/Signal.hpp"
#include "../../render/Texture.hpp"
#include "./WLBuffer.hpp"
#include <array>
#include <tuple>
#include <aquamarine/buffer/Buffer.hpp>
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<uint32_t, 4> offsets = {0};
std::array<uint32_t, 4> strides = {0};
std::array<int, 4> 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 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<CWLSurfaceResource>);
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<uint8_t*, uint32_t, size_t> 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<CWLBufferResource> resource;
SP<CTexture> texture;
SP<CTexture> texture;
bool opaque = false;
SP<CWLBufferResource> resource;
struct {
CSignal destroy;
} events;
private:
int locks = 0;
CHyprSignalListener backendRelease;
} hlEvents;
};

View file

@ -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;
}

View file

@ -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<uint8_t*, uint32_t, size_t> 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;

View file

@ -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 <xf86drm.h>
CWLBufferResource::CWLBufferResource(SP<CWlBuffer> resource_) : resource(resource_) {
if (!good())
@ -27,6 +32,16 @@ void CWLBufferResource::sendRelease() {
resource->sendRelease();
}
void CWLBufferResource::sendReleaseWithSurface(SP<CWLSurfaceResource> 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();
}

View file

@ -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<CWLSurfaceResource>);
wl_resource* getResource();
WP<IWLBuffer> buffer;
WP<IHLBuffer> buffer;
WP<CWLBufferResource> self;
@ -27,5 +29,5 @@ class CWLBufferResource {
SP<CWlBuffer> resource;
friend class IWLBuffer;
friend class IHLBuffer;
};