protocols: Add support for hyprland-ctm-control-v1 (#8023)

* initial ctm support

* flake.lock: update

* Meson: bump required versions and add ctm proto

---------

Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
Vaxry 2024-10-08 16:59:15 +01:00 committed by GitHub
parent e0cfbec66b
commit 1bf63dfdcd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 174 additions and 22 deletions

View file

@ -100,7 +100,7 @@ find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.1)
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine)
pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.4.2)
add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}")
@ -274,7 +274,7 @@ endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.2.0)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.4.0)
if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
@ -301,6 +301,8 @@ protocolnew("protocols" "wlr-data-control-unstable-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true)
protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
protocolnew("protocols" "wayland-drm" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false)
protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)

View file

@ -16,11 +16,11 @@
]
},
"locked": {
"lastModified": 1727261104,
"narHash": "sha256-rxDI7WrxIRV9it9mDCHcLa7xQykf1JloXnoXr5xQ8zI=",
"lastModified": 1728326504,
"narHash": "sha256-dQXAj+4d6neY7ldCiH6gNym3upP49PVxRzEPxXlD9Aw=",
"owner": "hyprwm",
"repo": "aquamarine",
"rev": "b82fdaff917582a9d568969e15e61b398c71e990",
"rev": "65dd97b5d21e917295159bbef1d52e06963f4eb0",
"type": "github"
},
"original": {
@ -79,11 +79,11 @@
]
},
"locked": {
"lastModified": 1727532803,
"narHash": "sha256-ZaZ7h7PY8mQc4vtGmVqWLAq9CAO02gHMyNR5yY8zDmM=",
"lastModified": 1727821604,
"narHash": "sha256-hNw5J6xatedqytYowx0mJKgctjA4lQARZFdgnzM2RpM=",
"owner": "hyprwm",
"repo": "hyprcursor",
"rev": "b98726e431d4d3ed58bd58bee1047cdb81cec69f",
"rev": "d60e1e01e6e6633ef1c87148b9137cc1dd39263d",
"type": "github"
},
"original": {
@ -102,11 +102,11 @@
]
},
"locked": {
"lastModified": 1727451107,
"narHash": "sha256-qV9savtHwmZUa0eJE294WYJjKPGB2+bJhwByFShsVyo=",
"lastModified": 1728345020,
"narHash": "sha256-xGbkc7U/Roe0/Cv3iKlzijIaFBNguasI31ynL2IlEoM=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
"rev": "6b3261ee13a6d2b99de79a31d352f6996e35bde3",
"rev": "a7c183800e74f337753de186522b9017a07a8cee",
"type": "github"
},
"original": {
@ -128,11 +128,11 @@
]
},
"locked": {
"lastModified": 1725997860,
"narHash": "sha256-d/rZ/fHR5l1n7PeyLw0StWMNLXVU9c4HFyfskw568so=",
"lastModified": 1728168612,
"narHash": "sha256-AnB1KfiXINmuiW7BALYrKqcjCnsLZPifhb/7BsfPbns=",
"owner": "hyprwm",
"repo": "hyprlang",
"rev": "dfeb5811dd6485490cce18d6cc1e38a055eea876",
"rev": "f054f2e44d6a0b74607a6bc0f52dba337a3db38e",
"type": "github"
},
"original": {
@ -189,11 +189,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1727348695,
"narHash": "sha256-J+PeFKSDV+pHL7ukkfpVzCOO7mBSrrpJ3svwBFABbhI=",
"lastModified": 1728018373,
"narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "1925c603f17fc89f4c8f6bf6f631a802ad85d784",
"rev": "bc947f541ae55e999ffdb4013441347d83b00feb",
"type": "github"
},
"original": {
@ -293,11 +293,11 @@
]
},
"locked": {
"lastModified": 1727524473,
"narHash": "sha256-1DGktDtSWIJpnDbVoj/qpvJSH5zg6JbOfuh6xqZMap0=",
"lastModified": 1728166987,
"narHash": "sha256-w6dVTguAn9zJ+7aPOhBQgDz8bn6YZ7b56cY8Kg5HJRI=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
"rev": "7e500e679ede40e79cf2d89b5f5fa3e34923bd26",
"rev": "fb9c8d665af0588bb087f97d0f673ddf0d501787",
"type": "github"
},
"original": {

View file

@ -30,7 +30,7 @@ if cpp_compiler.check_header('execinfo.h')
add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
endif
aquamarine = dependency('aquamarine')
aquamarine = dependency('aquamarine', version: '>=0.4.2')
add_project_arguments(['-DAQUAMARINE_VERSION="@0@"'.format(aquamarine.version())], language: 'cpp')
xcb_dep = dependency('xcb', required: get_option('xwayland'))

View file

@ -7,7 +7,7 @@ wayland_protos = dependency(
hyprland_protos = dependency(
'hyprland-protocols',
version: '>=0.2',
version: '>=0.4',
fallback: 'hyprland-protocols',
)
@ -36,6 +36,7 @@ protocols = [
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml',
wayland_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
wayland_protocol_dir / 'staging/fractional-scale/fractional-scale-v1.xml',
wayland_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',

View file

@ -813,6 +813,12 @@ void CMonitor::scheduleDone() {
});
}
void CMonitor::setCTM(const Mat3x3& ctm_) {
ctm = ctm_;
ctmUpdated = true;
g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::scheduleFrameReason::AQ_SCHEDULE_NEEDS_FRAME);
}
bool CMonitor::attemptDirectScanout() {
if (!mirrors.empty() || isMirror() || g_pHyprRenderer->m_bDirectScanoutBlocked)
return false; // do not DS if this monitor is being mirrored. Will break the functionality.

View file

@ -131,6 +131,10 @@ class CMonitor {
CMonitor* pMirrorOf = nullptr;
std::vector<CMonitor*> mirrors;
// ctm
Mat3x3 ctm = Mat3x3::identity();
bool ctmUpdated = false;
// for tearing
PHLWINDOWREF solitaryClient;
@ -179,6 +183,7 @@ class CMonitor {
CBox logicalBox();
void scheduleDone();
bool attemptDirectScanout();
void setCTM(const Mat3x3& ctm);
bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;

View file

@ -46,6 +46,7 @@
#include "../protocols/XDGDialog.hpp"
#include "../protocols/SinglePixel.hpp"
#include "../protocols/SecurityContext.hpp"
#include "../protocols/CTMControl.hpp"
#include "../protocols/core/Seat.hpp"
#include "../protocols/core/DataDevice.hpp"
@ -157,6 +158,7 @@ CProtocolManager::CProtocolManager() {
PROTO::xdgDialog = std::make_unique<CXDGDialogProtocol>(&xdg_dialog_v1_interface, 1, "XDGDialog");
PROTO::singlePixel = std::make_unique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel");
PROTO::securityContext = std::make_unique<CSecurityContextProtocol>(&wp_security_context_manager_v1_interface, 1, "SecurityContext");
PROTO::ctm = std::make_unique<CHyprlandCTMControlProtocol>(&hyprland_ctm_control_manager_v1_interface, 1, "CTMControl");
for (auto const& b : g_pCompositor->m_pAqBackend->getImplementations()) {
if (b->type() != Aquamarine::AQ_BACKEND_DRM)
@ -229,6 +231,7 @@ CProtocolManager::~CProtocolManager() {
PROTO::xdgDialog.reset();
PROTO::singlePixel.reset();
PROTO::securityContext.reset();
PROTO::ctm.reset();
PROTO::lease.reset();
PROTO::sync.reset();

View file

@ -0,0 +1,86 @@
#include "CTMControl.hpp"
#include "../Compositor.hpp"
#include "core/Output.hpp"
CHyprlandCTMControlResource::CHyprlandCTMControlResource(SP<CHyprlandCtmControlManagerV1> resource_) : resource(resource_) {
if (!good())
return;
resource->setDestroy([this](CHyprlandCtmControlManagerV1* pMgr) { PROTO::ctm->destroyResource(this); });
resource->setOnDestroy([this](CHyprlandCtmControlManagerV1* pMgr) { PROTO::ctm->destroyResource(this); });
resource->setSetCtmForOutput([this](CHyprlandCtmControlManagerV1* r, wl_resource* output, wl_fixed_t mat0, wl_fixed_t mat1, wl_fixed_t mat2, wl_fixed_t mat3, wl_fixed_t mat4,
wl_fixed_t mat5, wl_fixed_t mat6, wl_fixed_t mat7, wl_fixed_t mat8) {
const auto OUTPUTRESOURCE = CWLOutputResource::fromResource(output);
if (!OUTPUTRESOURCE)
return; // ?!
const auto PMONITOR = OUTPUTRESOURCE->monitor.lock();
if (!PMONITOR)
return; // ?!?!
const std::array<float, 9> MAT = {wl_fixed_to_double(mat0), wl_fixed_to_double(mat1), wl_fixed_to_double(mat2), wl_fixed_to_double(mat3), wl_fixed_to_double(mat4),
wl_fixed_to_double(mat5), wl_fixed_to_double(mat6), wl_fixed_to_double(mat7), wl_fixed_to_double(mat8)};
for (auto& el : MAT) {
if (el < 0.F) {
resource->error(HYPRLAND_CTM_CONTROL_MANAGER_V1_ERROR_INVALID_MATRIX, "a matrix component was < 0");
return;
}
}
ctms[PMONITOR->szName] = MAT;
LOGM(LOG, "CTM set for output {}: {}", PMONITOR->szName, ctms.at(PMONITOR->szName).toString());
});
resource->setCommit([this](CHyprlandCtmControlManagerV1* r) {
LOGM(LOG, "Committing ctms to outputs");
for (auto& m : g_pCompositor->m_vMonitors) {
if (!ctms.contains(m->szName)) {
PROTO::ctm->setCTM(m, Mat3x3::identity());
continue;
}
PROTO::ctm->setCTM(m, ctms.at(m->szName));
}
});
}
CHyprlandCTMControlResource::~CHyprlandCTMControlResource() {
for (auto& m : g_pCompositor->m_vMonitors) {
PROTO::ctm->setCTM(m, Mat3x3::identity());
}
}
bool CHyprlandCTMControlResource::good() {
return resource->resource();
}
CHyprlandCTMControlProtocol::CHyprlandCTMControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CHyprlandCTMControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeShared<CHyprlandCTMControlResource>(makeShared<CHyprlandCtmControlManagerV1>(client, ver, id)));
if (!RESOURCE->good()) {
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
LOGM(LOG, "New CTM Manager at 0x{:x}", (uintptr_t)RESOURCE.get());
}
void CHyprlandCTMControlProtocol::destroyResource(CHyprlandCTMControlResource* res) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == res; });
}
void CHyprlandCTMControlProtocol::setCTM(SP<CMonitor> monitor, const Mat3x3& ctm) {
monitor->setCTM(ctm);
}

View file

@ -0,0 +1,44 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
#include "hyprland-ctm-control-v1.hpp"
#include <unordered_map>
class CMonitor;
class CHyprlandCTMControlResource {
public:
CHyprlandCTMControlResource(SP<CHyprlandCtmControlManagerV1> resource_);
~CHyprlandCTMControlResource();
bool good();
private:
SP<CHyprlandCtmControlManagerV1> resource;
std::unordered_map<std::string, Mat3x3> ctms;
};
class CHyprlandCTMControlProtocol : public IWaylandProtocol {
public:
CHyprlandCTMControlProtocol(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(CHyprlandCTMControlResource* resource);
void setCTM(SP<CMonitor> monitor, const Mat3x3& ctm);
//
std::vector<SP<CHyprlandCTMControlResource>> m_vManagers;
friend class CHyprlandCTMControlResource;
};
namespace PROTO {
inline UP<CHyprlandCTMControlProtocol> ctm;
};

View file

@ -1498,6 +1498,11 @@ bool CHyprRenderer::commitPendingAndDoExplicitSync(CMonitor* pMonitor) {
if (inFD >= 0)
pMonitor->output->state->setExplicitInFence(inFD);
if (pMonitor->ctmUpdated) {
pMonitor->ctmUpdated = false;
pMonitor->output->state->setCTM(pMonitor->ctm);
}
bool ok = pMonitor->state.commit();
if (!ok) {
if (inFD >= 0) {