gamma-control: move to new impl

This commit is contained in:
Vaxry 2024-04-22 18:21:03 +01:00
parent dafc9ed4eb
commit 741c75d907
13 changed files with 383 additions and 48 deletions

View file

@ -188,8 +188,6 @@ void CCompositor::initServer() {
wlr_primary_selection_v1_device_manager_create(m_sWLDisplay);
wlr_viewporter_create(m_sWLDisplay);
m_sWLRGammaCtrlMgr = wlr_gamma_control_manager_v1_create(m_sWLDisplay);
m_sWLROutputLayout = wlr_output_layout_create(m_sWLDisplay);
m_sWLROutputPowerMgr = wlr_output_power_manager_v1_create(m_sWLDisplay);
@ -299,7 +297,6 @@ void CCompositor::initAllSignals() {
addWLSignal(&m_sWLRTextInputMgr->events.text_input, &Events::listen_newTextInput, m_sWLRTextInputMgr, "TextInputMgr");
addWLSignal(&m_sWLRActivation->events.request_activate, &Events::listen_activateXDG, m_sWLRActivation, "ActivationV1");
addWLSignal(&m_sWLRSessionLockMgr->events.new_lock, &Events::listen_newSessionLock, m_sWLRSessionLockMgr, "SessionLockMgr");
addWLSignal(&m_sWLRGammaCtrlMgr->events.set_gamma, &Events::listen_setGamma, m_sWLRGammaCtrlMgr, "GammaCtrlMgr");
addWLSignal(&m_sWLRKbShInhibitMgr->events.new_inhibitor, &Events::listen_newShortcutInhibitor, m_sWLRKbShInhibitMgr, "ShortcutInhibitMgr");
if (m_sWRLDRMLeaseMgr)
@ -349,7 +346,6 @@ void CCompositor::removeAllSignals() {
removeWLSignal(&Events::listen_newTextInput);
removeWLSignal(&Events::listen_activateXDG);
removeWLSignal(&Events::listen_newSessionLock);
removeWLSignal(&Events::listen_setGamma);
removeWLSignal(&Events::listen_newShortcutInhibitor);
if (m_sWRLDRMLeaseMgr)

View file

@ -77,7 +77,6 @@ class CCompositor {
wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf;
wlr_backend* m_sWLRHeadlessBackend;
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
// ------------------------------------------------- //
std::string m_szWLDisplaySocket = "";

View file

@ -133,9 +133,6 @@ namespace Events {
// Session Lock
LISTENER(newSessionLock);
// Gamma control
LISTENER(setGamma);
// Shortcut inhibitor
LISTENER(newShortcutInhibitor);
};

View file

@ -222,23 +222,6 @@ void Events::listener_newSessionLock(wl_listener* listener, void* data) {
g_pSessionLockManager->onNewSessionLock((wlr_session_lock_v1*)data);
}
void Events::listener_setGamma(wl_listener* listener, void* data) {
Debug::log(LOG, "New Gamma event at {:x}", (uintptr_t)data);
const auto E = (wlr_gamma_control_manager_v1_set_gamma_event*)data;
const auto PMONITOR = g_pCompositor->getMonitorFromOutput(E->output);
if (!PMONITOR) {
Debug::log(ERR, "Gamma event object references non-existent output {:x} ?", (uintptr_t)E->output);
return;
}
PMONITOR->gammaChanged = true;
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
}
void Events::listener_newShortcutInhibitor(wl_listener* listener, void* data) {
const auto INHIBITOR = (wlr_keyboard_shortcuts_inhibitor_v1*)data;

View file

@ -1,10 +1,8 @@
#include "Monitor.hpp"
#include "MiscFunctions.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/GammaControl.hpp"
int ratHandler(void* data) {
g_pHyprRenderer->renderMonitor((CMonitor*)data);
@ -26,6 +24,8 @@ CMonitor::~CMonitor() {
hyprListener_monitorNeedsFrame.removeCallback();
hyprListener_monitorCommit.removeCallback();
hyprListener_monitorBind.removeCallback();
events.destroy.emit();
}
void CMonitor::onConnect(bool noRule) {
@ -214,6 +214,10 @@ void CMonitor::onConnect(bool noRule) {
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
g_pCompositor->scheduleFrameForMonitor(this);
PROTO::gamma->applyGammaToState(this);
events.connect.emit();
}
void CMonitor::onDisconnect(bool destroy) {
@ -228,6 +232,8 @@ void CMonitor::onDisconnect(bool destroy) {
Debug::log(LOG, "onDisconnect called for {}", output->name);
events.disconnect.emit();
// Cleanup everything. Move windows back, snap cursor, shit.
CMonitor* BACKUPMON = nullptr;
for (auto& m : g_pCompositor->m_vMonitors) {

View file

@ -11,6 +11,8 @@
#include "Region.hpp"
#include <optional>
#include "signal/Signal.hpp"
struct SMonitorRule {
std::string name = "";
Vector2D resolution = Vector2D(1280, 720);
@ -83,7 +85,6 @@ class CMonitor {
bool noFrameSchedule = false;
bool scheduledRecalc = false;
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
bool gammaChanged = false;
float xwaylandScale = 1.f;
std::array<float, 9> projMatrix = {0};
std::optional<Vector2D> forceSize;
@ -120,6 +121,12 @@ class CMonitor {
bool frameScheduledWhileBusy = false;
} tearingState;
struct {
CSignal destroy;
CSignal connect;
CSignal disconnect;
} events;
std::array<std::vector<std::unique_ptr<SLayerSurface>>, 4> m_aLayerSurfaceLayers;
DYNLISTENER(monitorFrame);

View file

@ -8,6 +8,7 @@
#include "../protocols/RelativePointer.hpp"
#include "../protocols/XDGDecoration.hpp"
#include "../protocols/AlphaModifier.hpp"
#include "../protocols/GammaControl.hpp"
#include "tearing-control-v1.hpp"
#include "fractional-scale-v1.hpp"
@ -17,6 +18,7 @@
#include "relative-pointer-unstable-v1.hpp"
#include "xdg-decoration-unstable-v1.hpp"
#include "alpha-modifier-v1.hpp"
#include "wlr-gamma-control-unstable-v1.hpp"
CProtocolManager::CProtocolManager() {
@ -28,6 +30,7 @@ CProtocolManager::CProtocolManager() {
PROTO::relativePointer = std::make_unique<CRelativePointerProtocol>(&zwp_relative_pointer_manager_v1_interface, 1, "RelativePointer");
PROTO::xdgDecoration = std::make_unique<CXDGDecorationProtocol>(&zxdg_decoration_manager_v1_interface, 1, "XDGDecoration");
PROTO::alphaModifier = std::make_unique<CAlphaModifierProtocol>(&wp_alpha_modifier_v1_interface, 1, "AlphaModifier");
PROTO::gamma = std::make_unique<CGammaControlProtocol>(&zwlr_gamma_control_manager_v1_interface, 1, "GammaControl");
// Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner.

View file

@ -0,0 +1,177 @@
#include "GammaControl.hpp"
#include <fcntl.h>
#include <unistd.h>
#include "../helpers/Monitor.hpp"
#include "../Compositor.hpp"
CGammaControl::CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* output) : resource(resource_) {
if (!resource_->resource())
return;
wlr_output* wlrOutput = wlr_output_from_resource(output);
if (!wlrOutput) {
Debug::log(ERR, "[gamma] No wlr_output");
resource->sendFailed();
return;
}
pMonitor = g_pCompositor->getRealMonitorFromOutput(wlrOutput);
if (!pMonitor) {
Debug::log(ERR, "[gamma] No CMonitor");
resource->sendFailed();
return;
}
for (auto& g : PROTO::gamma->m_vGammaControllers) {
if (g->pMonitor == pMonitor) {
resource->sendFailed();
return;
}
}
gammaSize = wlr_output_get_gamma_size(wlrOutput);
if (gammaSize <= 0) {
Debug::log(ERR, "[gamma] Output {} doesn't support gamma", pMonitor->szName);
resource->sendFailed();
return;
}
gammaTable.resize(gammaSize * 3);
resource->setDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); });
resource->setOnDestroy([this](CZwlrGammaControlV1* gamma) { PROTO::gamma->destroyGammaControl(this); });
resource->setSetGamma([this](CZwlrGammaControlV1* gamma, int32_t fd) {
Debug::log(LOG, "[gamma] setGamma for {}", pMonitor->szName);
int fdFlags = fcntl(fd, F_GETFL, 0);
if (fdFlags < 0) {
Debug::log(ERR, "[gamma] Failed to get fd flags");
resource->sendFailed();
close(fd);
return;
}
if (fcntl(fd, F_SETFL, fdFlags | O_NONBLOCK) < 0) {
Debug::log(ERR, "[gamma] Failed to set fd flags");
resource->sendFailed();
close(fd);
return;
}
ssize_t readBytes = pread(fd, gammaTable.data(), gammaTable.size() * sizeof(uint16_t), 0);
if (readBytes < 0 || (size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) {
Debug::log(ERR, "[gamma] Failed to read bytes");
close(fd);
if ((size_t)readBytes != gammaTable.size() * sizeof(uint16_t)) {
wl_resource_post_error(gamma->resource(), ZWLR_GAMMA_CONTROL_V1_ERROR_INVALID_GAMMA, "Gamma ramps size mismatch");
return;
}
resource->sendFailed();
return;
}
gammaTableSet = true;
close(fd);
applyToMonitor();
});
resource->sendGammaSize(gammaSize);
listeners.monitorDestroy = pMonitor->events.destroy.registerListener([this](std::any) { this->onMonitorDestroy(); });
listeners.monitorDisconnect = pMonitor->events.destroy.registerListener([this](std::any) { this->onMonitorDestroy(); });
}
CGammaControl::~CGammaControl() {
if (!gammaTableSet || !pMonitor)
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);
}
bool CGammaControl::good() {
return resource->resource();
}
void CGammaControl::applyToMonitor() {
if (!pMonitor)
return; // ??
Debug::log(LOG, "[gamma] setting to monitor {}", pMonitor->szName);
if (!gammaTableSet) {
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
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);
if (!pMonitor->state.test()) {
Debug::log(LOG, "[gamma] setting to monitor {} failed", pMonitor->szName);
wlr_output_state_set_gamma_lut(pMonitor->state.wlr(), 0, nullptr, nullptr, nullptr);
}
g_pHyprRenderer->damageMonitor(pMonitor);
}
CMonitor* CGammaControl::getMonitor() {
return pMonitor;
}
void CGammaControl::onMonitorDestroy() {
resource->sendFailed();
pMonitor = nullptr;
}
CGammaControlProtocol::CGammaControlProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
;
}
void CGammaControlProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CZwlrGammaControlManagerV1>(client, ver, id)).get();
RESOURCE->setOnDestroy([this](CZwlrGammaControlManagerV1* p) { this->onManagerResourceDestroy(p->resource()); });
RESOURCE->setDestroy([this](CZwlrGammaControlManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
RESOURCE->setGetGammaControl([this](CZwlrGammaControlManagerV1* pMgr, uint32_t id, wl_resource* output) { this->onGetGammaControl(pMgr, id, output); });
}
void CGammaControlProtocol::onManagerResourceDestroy(wl_resource* res) {
std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
}
void CGammaControlProtocol::destroyGammaControl(CGammaControl* gamma) {
std::erase_if(m_vGammaControllers, [&](const auto& other) { return other.get() == gamma; });
}
void CGammaControlProtocol::onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, uint32_t id, wl_resource* output) {
const auto CLIENT = wl_resource_get_client(pMgr->resource());
const auto RESOURCE =
m_vGammaControllers.emplace_back(std::make_unique<CGammaControl>(std::make_shared<CZwlrGammaControlV1>(CLIENT, wl_resource_get_version(pMgr->resource()), id), output))
.get();
if (!RESOURCE->good()) {
wl_resource_post_no_memory(pMgr->resource());
m_vGammaControllers.pop_back();
return;
}
}
void CGammaControlProtocol::applyGammaToState(CMonitor* pMonitor) {
for (auto& g : m_vGammaControllers) {
if (g->getMonitor() != pMonitor)
continue;
g->applyToMonitor();
break;
}
}

View file

@ -0,0 +1,58 @@
#pragma once
#include <memory>
#include <vector>
#include <cstdint>
#include "WaylandProtocol.hpp"
#include "wlr-gamma-control-unstable-v1.hpp"
#include "../helpers/signal/Listener.hpp"
class CMonitor;
class CGammaControl {
public:
CGammaControl(SP<CZwlrGammaControlV1> resource_, wl_resource* output);
~CGammaControl();
bool good();
void applyToMonitor();
CMonitor* getMonitor();
private:
SP<CZwlrGammaControlV1> resource;
CMonitor* pMonitor = nullptr;
size_t gammaSize = 0;
bool gammaTableSet = false;
std::vector<uint16_t> gammaTable;
void onMonitorDestroy();
struct {
CHyprSignalListener monitorDisconnect;
CHyprSignalListener monitorDestroy;
} listeners;
};
class CGammaControlProtocol : public IWaylandProtocol {
public:
CGammaControlProtocol(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 applyGammaToState(CMonitor* pMonitor);
private:
void onManagerResourceDestroy(wl_resource* res);
void destroyGammaControl(CGammaControl* gamma);
void onGetGammaControl(CZwlrGammaControlManagerV1* pMgr, uint32_t id, wl_resource* output);
//
std::vector<UP<CZwlrGammaControlManagerV1>> m_vManagers;
std::vector<UP<CGammaControl>> m_vGammaControllers;
friend class CGammaControl;
};
namespace PROTO {
inline UP<CGammaControlProtocol> gamma;
};

View file

@ -1151,25 +1151,6 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
g_pLayoutManager->getCurrentLayout()->recalculateMonitor(pMonitor->ID);
}
// gamma stuff
if (pMonitor->gammaChanged) {
pMonitor->gammaChanged = false;
const auto PGAMMACTRL = wlr_gamma_control_manager_v1_get_control(g_pCompositor->m_sWLRGammaCtrlMgr, pMonitor->output);
if (!wlr_gamma_control_v1_apply(PGAMMACTRL, pMonitor->state.wlr())) {
Debug::log(ERR, "Could not apply gamma control to {}", pMonitor->szName);
return;
}
if (!wlr_output_test_state(pMonitor->output, pMonitor->state.wlr())) {
Debug::log(ERR, "Output test failed for setting gamma to {}", pMonitor->szName);
// aka rollback
wlr_gamma_control_v1_apply(nullptr, pMonitor->state.wlr());
wlr_gamma_control_v1_send_failed_and_destroy(PGAMMACTRL);
}
}
// tearing and DS first
bool shouldTear = false;
if (pMonitor->tearingState.nextRenderTorn) {