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:
parent
e0cfbec66b
commit
1bf63dfdcd
10 changed files with 174 additions and 22 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
86
src/protocols/CTMControl.cpp
Normal file
86
src/protocols/CTMControl.cpp
Normal 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);
|
||||
}
|
||||
44
src/protocols/CTMControl.hpp
Normal file
44
src/protocols/CTMControl.hpp
Normal 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;
|
||||
};
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue