summaryrefslogtreecommitdiff
path: root/src/helpers/Monitor.cpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2024-07-21 13:09:54 +0200
committerGitHub <noreply@github.com>2024-07-21 13:09:54 +0200
commit016da234d0e852de3ef20eb2e89ac58d2a85f6e7 (patch)
tree496085987176551b0794fffc069877d44943e2f1 /src/helpers/Monitor.cpp
parentf642fb97df5c69267a03452533de383ff8023570 (diff)
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>
Diffstat (limited to 'src/helpers/Monitor.cpp')
-rw-r--r--src/helpers/Monitor.cpp293
1 files changed, 185 insertions, 108 deletions
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index 20c2e81e..a23b9861 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -1,12 +1,18 @@
#include "Monitor.hpp"
#include "MiscFunctions.hpp"
+#include "math/Math.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/GammaControl.hpp"
#include "../devices/ITouch.hpp"
#include "../protocols/LayerShell.hpp"
#include "../protocols/PresentationTime.hpp"
+#include "../protocols/DRMLease.hpp"
+#include "../protocols/core/Output.hpp"
#include "../managers/PointerManager.hpp"
+#include "../protocols/core/Compositor.hpp"
+#include "sync/SyncTimeline.hpp"
+#include <aquamarine/output/Output.hpp>
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
@@ -21,62 +27,73 @@ CMonitor::CMonitor() : state(this) {
}
CMonitor::~CMonitor() {
- hyprListener_monitorDestroy.removeCallback();
- hyprListener_monitorFrame.removeCallback();
- hyprListener_monitorStateRequest.removeCallback();
- hyprListener_monitorDamage.removeCallback();
- hyprListener_monitorNeedsFrame.removeCallback();
- hyprListener_monitorCommit.removeCallback();
- hyprListener_monitorBind.removeCallback();
-
events.destroy.emit();
}
-static void onPresented(void* owner, void* data) {
- const auto PMONITOR = (CMonitor*)owner;
- auto E = (wlr_output_event_present*)data;
+void CMonitor::onConnect(bool noRule) {
- PROTO::presentation->onPresented(PMONITOR, E->when, E->refresh, E->seq, E->flags);
-}
+ if (output->supportsExplicit) {
+ inTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
+ outTimeline = CSyncTimeline::create(output->getBackend()->drmFD());
+ }
+
+ listeners.frame = output->events.frame.registerListener([this](std::any d) { Events::listener_monitorFrame(this, nullptr); });
+ listeners.destroy = output->events.destroy.registerListener([this](std::any d) { Events::listener_monitorDestroy(this, nullptr); });
+ listeners.commit = output->events.commit.registerListener([this](std::any d) { Events::listener_monitorCommit(this, nullptr); });
+ listeners.needsFrame =
+ output->events.needsFrame.registerListener([this](std::any d) { g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEEDS_FRAME); });
+ listeners.presented = output->events.present.registerListener([this](std::any d) {
+ auto E = std::any_cast<Aquamarine::IOutput::SPresentEvent>(d);
+ PROTO::presentation->onPresented(this, E.when, E.refresh, E.seq, E.flags);
+ });
+
+ listeners.state = output->events.state.registerListener([this](std::any d) {
+ auto E = std::any_cast<Aquamarine::IOutput::SStateEvent>(d);
+
+ if (E.size == Vector2D{}) {
+ // an indication to re-set state
+ // we can't do much for createdByUser displays I think
+ if (createdByUser)
+ return;
+
+ Debug::log(LOG, "Reapplying monitor rule for {} from a state request", szName);
+ g_pHyprRenderer->applyMonitorRule(this, &activeMonitorRule, true);
+ return;
+ }
-void CMonitor::onConnect(bool noRule) {
- hyprListener_monitorDestroy.removeCallback();
- hyprListener_monitorFrame.removeCallback();
- hyprListener_monitorStateRequest.removeCallback();
- hyprListener_monitorDamage.removeCallback();
- hyprListener_monitorNeedsFrame.removeCallback();
- hyprListener_monitorCommit.removeCallback();
- hyprListener_monitorBind.removeCallback();
- hyprListener_monitorPresented.removeCallback();
- hyprListener_monitorFrame.initCallback(&output->events.frame, &Events::listener_monitorFrame, this, "CMonitor");
- hyprListener_monitorDestroy.initCallback(&output->events.destroy, &Events::listener_monitorDestroy, this, "CMonitor");
- hyprListener_monitorStateRequest.initCallback(&output->events.request_state, &Events::listener_monitorStateRequest, this, "CMonitor");
- hyprListener_monitorDamage.initCallback(&output->events.damage, &Events::listener_monitorDamage, this, "CMonitor");
- hyprListener_monitorNeedsFrame.initCallback(&output->events.needs_frame, &Events::listener_monitorNeedsFrame, this, "CMonitor");
- hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this, "CMonitor");
- hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this, "CMonitor");
- hyprListener_monitorPresented.initCallback(&output->events.present, ::onPresented, this, "CMonitor");
-
- tearingState.canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
+ if (!createdByUser)
+ return;
+
+ const auto SIZE = E.size;
+
+ forceSize = SIZE;
+
+ SMonitorRule rule = activeMonitorRule;
+ rule.resolution = SIZE;
+
+ g_pHyprRenderer->applyMonitorRule(this, &rule);
+ });
+
+ tearingState.canTear = output->getBackend()->type() == Aquamarine::AQ_BACKEND_DRM;
if (m_bEnabled) {
- wlr_output_state_set_enabled(state.wlr(), true);
+ output->state->setEnabled(true);
state.commit();
return;
}
szName = output->name;
- szDescription = output->description ? output->description : "";
+ szDescription = output->description;
// remove comma character from description. This allow monitor specific rules to work on monitor with comma on their description
std::erase(szDescription, ',');
// field is backwards-compatible with intended usage of `szDescription` but excludes the parenthesized DRM node name suffix
- szShortDescription = trim(std::format("{} {} {}", output->make ? output->make : "", output->model ? output->model : "", output->serial ? output->serial : ""));
+ szShortDescription = trim(std::format("{} {} {}", output->make, output->model, output->serial));
std::erase(szShortDescription, ',');
- if (!wlr_backend_is_drm(output->backend))
- createdByUser = true; // should be true. WL, X11 and Headless backends should be addable / removable
+ if (output->getBackend()->type() != Aquamarine::AQ_BACKEND_DRM)
+ createdByUser = true; // should be true. WL and Headless backends should be addable / removable
// get monitor rule that matches
SMonitorRule monitorRule = g_pConfigManager->getMonitorRuleFor(*this);
@@ -84,54 +101,23 @@ void CMonitor::onConnect(bool noRule) {
// if it's disabled, disable and ignore
if (monitorRule.disabled) {
- wlr_output_state_set_scale(state.wlr(), 1);
- wlr_output_state_set_transform(state.wlr(), WL_OUTPUT_TRANSFORM_NORMAL);
-
- auto PREFSTATE = wlr_output_preferred_mode(output);
-
- if (!PREFSTATE) {
- wlr_output_mode* mode;
-
- wl_list_for_each(mode, &output->modes, link) {
- wlr_output_state_set_mode(state.wlr(), mode);
-
- if (!wlr_output_test_state(output, state.wlr()))
- continue;
-
- PREFSTATE = mode;
- break;
- }
- }
-
- if (PREFSTATE)
- wlr_output_state_set_mode(state.wlr(), PREFSTATE);
- else
- Debug::log(WARN, "No mode found for disabled output {}", output->name);
-
- wlr_output_state_set_enabled(state.wlr(), 0);
+ output->state->setEnabled(false);
if (!state.commit())
Debug::log(ERR, "Couldn't commit disabled state on output {}", output->name);
m_bEnabled = false;
- hyprListener_monitorFrame.removeCallback();
+ listeners.frame.reset();
return;
}
- if (output->non_desktop) {
+ if (output->nonDesktop) {
Debug::log(LOG, "Not configuring non-desktop output");
- if (g_pCompositor->m_sWRLDRMLeaseMgr) {
- wlr_drm_lease_v1_manager_offer_output(g_pCompositor->m_sWRLDRMLeaseMgr, output);
- }
- return;
- }
+ if (PROTO::lease)
+ PROTO::lease->offer(self.lock());
- if (!m_bRenderingInitPassed) {
- output->allocator = nullptr;
- output->renderer = nullptr;
- wlr_output_init_render(output, g_pCompositor->m_sWLRAllocator, g_pCompositor->m_sWLRRenderer);
- m_bRenderingInitPassed = true;
+ return;
}
SP<CMonitor>* thisWrapper = nullptr;
@@ -151,14 +137,14 @@ void CMonitor::onConnect(bool noRule) {
m_bEnabled = true;
- wlr_output_state_set_enabled(state.wlr(), 1);
+ output->state->setEnabled(true);
// set mode, also applies
if (!noRule)
g_pHyprRenderer->applyMonitorRule(this, &monitorRule, true);
if (!state.commit())
- Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onCommit");
+ Debug::log(WARN, "state.commit() failed in CMonitor::onCommit");
damage.setSize(vecTransformedSize);
@@ -214,7 +200,7 @@ void CMonitor::onConnect(bool noRule) {
renderTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, ratHandler, this);
- g_pCompositor->scheduleFrameForMonitor(this);
+ g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_NEW_MONITOR);
PROTO::gamma->applyGammaToState(this);
@@ -261,12 +247,10 @@ void CMonitor::onDisconnect(bool destroy) {
g_pConfigManager->m_bWantsMonitorReload = true;
}
- hyprListener_monitorFrame.removeCallback();
- hyprListener_monitorPresented.removeCallback();
- hyprListener_monitorDamage.removeCallback();
- hyprListener_monitorNeedsFrame.removeCallback();
- hyprListener_monitorCommit.removeCallback();
- hyprListener_monitorBind.removeCallback();
+ listeners.frame.reset();
+ listeners.presented.reset();
+ listeners.needsFrame.reset();
+ listeners.commit.reset();
for (size_t i = 0; i < 4; ++i) {
for (auto& ls : m_aLayerSurfaceLayers[i]) {
@@ -316,10 +300,10 @@ void CMonitor::onDisconnect(bool destroy) {
activeWorkspace->m_bVisible = false;
activeWorkspace.reset();
- wlr_output_state_set_enabled(state.wlr(), false);
+ output->state->setEnabled(false);
if (!state.commit())
- Debug::log(WARN, "wlr_output_commit_state failed in CMonitor::onDisconnect");
+ Debug::log(WARN, "state.commit() failed in CMonitor::onDisconnect");
if (g_pCompositor->m_pLastMonitor.get() == this)
g_pCompositor->setActiveMonitor(BACKUPMON ? BACKUPMON : g_pCompositor->m_pUnsafeOutput);
@@ -344,9 +328,9 @@ void CMonitor::addDamage(const pixman_region32_t* rg) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
damage.damageEntire();
- g_pCompositor->scheduleFrameForMonitor(this);
+ g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
} else if (damage.damage(rg))
- g_pCompositor->scheduleFrameForMonitor(this);
+ g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
}
void CMonitor::addDamage(const CRegion* rg) {
@@ -357,11 +341,11 @@ void CMonitor::addDamage(const CBox* box) {
static auto PZOOMFACTOR = CConfigValue<Hyprlang::FLOAT>("cursor:zoom_factor");
if (*PZOOMFACTOR != 1.f && g_pCompositor->getMonitorFromCursor() == this) {
damage.damageEntire();
- g_pCompositor->scheduleFrameForMonitor(this);
+ g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
}
if (damage.damage(*box))
- g_pCompositor->scheduleFrameForMonitor(this);
+ g_pCompositor->scheduleFrameForMonitor(this, Aquamarine::IOutput::AQ_SCHEDULE_DAMAGE);
}
bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
@@ -369,8 +353,8 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
static auto PMINRR = CConfigValue<Hyprlang::INT>("cursor:min_refresh_rate");
// skip scheduling extra frames for fullsreen apps with vrr
- bool shouldSkip = *PNOBREAK && output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow &&
- activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
+ bool shouldSkip =
+ *PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FULLSCREEN_FULL;
// keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
@@ -563,7 +547,7 @@ float CMonitor::getDefaultScale() {
static constexpr double MMPERINCH = 25.4;
const auto DIAGONALPX = sqrt(pow(vecPixelSize.x, 2) + pow(vecPixelSize.y, 2));
- const auto DIAGONALIN = sqrt(pow(output->phys_width / MMPERINCH, 2) + pow(output->phys_height / MMPERINCH, 2));
+ const auto DIAGONALIN = sqrt(pow(output->physicalSize.x / MMPERINCH, 2) + pow(output->physicalSize.y / MMPERINCH, 2));
const auto PPI = DIAGONALPX / DIAGONALIN;
@@ -767,11 +751,11 @@ Vector2D CMonitor::middle() {
}
void CMonitor::updateMatrix() {
- wlr_matrix_identity(projMatrix.data());
+ matrixIdentity(projMatrix.data());
if (transform != WL_OUTPUT_TRANSFORM_NORMAL) {
- wlr_matrix_translate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
- wlr_matrix_transform(projMatrix.data(), transform);
- wlr_matrix_translate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
+ matrixTranslate(projMatrix.data(), vecPixelSize.x / 2.0, vecPixelSize.y / 2.0);
+ matrixTransform(projMatrix.data(), wlTransformToHyprutils(transform));
+ matrixTranslate(projMatrix.data(), -vecTransformedSize.x / 2.0, -vecTransformedSize.y / 2.0);
}
}
@@ -787,31 +771,124 @@ CBox CMonitor::logicalBox() {
return {vecPosition, vecSize};
}
+static void onDoneSource(void* data) {
+ auto pMonitor = (CMonitor*)data;
+
+ if (!PROTO::outputs.contains(pMonitor->szName))
+ return;
+
+ PROTO::outputs.at(pMonitor->szName)->sendDone();
+}
+
+void CMonitor::scheduleDone() {
+ if (doneSource)
+ return;
+
+ doneSource = wl_event_loop_add_idle(g_pCompositor->m_sWLEventLoop, ::onDoneSource, this);
+}
+
+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.
+
+ if (g_pPointerManager->softwareLockedFor(self.lock()))
+ return false;
+
+ const auto PCANDIDATE = solitaryClient.lock();
+
+ if (!PCANDIDATE)
+ return false;
+
+ const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
+
+ if (!PSURFACE || !PSURFACE->current.buffer || PSURFACE->current.buffer->size != vecPixelSize || PSURFACE->current.transform != transform)
+ return false;
+
+ // we can't scanout shm buffers.
+ if (!PSURFACE->current.buffer->dmabuf().success)
+ return false;
+
+ // FIXME: make sure the buffer actually follows the available scanout dmabuf formats
+ // and comes from the appropriate device. This may implode on multi-gpu!!
+
+ output->state->setBuffer(PSURFACE->current.buffer);
+ output->state->setPresentationMode(Aquamarine::eOutputPresentationMode::AQ_OUTPUT_PRESENTATION_VSYNC);
+
+ if (!state.test())
+ return false;
+
+ timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ Debug::log(TRACE, "presentFeedback for DS");
+ PSURFACE->presentFeedback(&now, this, true);
+
+ if (state.commit()) {
+ if (lastScanout.expired()) {
+ lastScanout = PCANDIDATE;
+ Debug::log(LOG, "Entered a direct scanout to {:x}: \"{}\"", (uintptr_t)PCANDIDATE.get(), PCANDIDATE->m_szTitle);
+ }
+ } else {
+ lastScanout.reset();
+ return false;
+ }
+
+ return true;
+}
+
CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
- wlr_output_state_init(&m_state);
}
CMonitorState::~CMonitorState() {
- wlr_output_state_finish(&m_state);
+ ;
}
-wlr_output_state* CMonitorState::wlr() {
- return &m_state;
-}
+void CMonitorState::ensureBufferPresent() {
+ if (!m_pOwner->output->state->state().enabled) {
+ Debug::log(TRACE, "CMonitorState::ensureBufferPresent: Ignoring, monitor is not enabled");
+ return;
+ }
+
+ if (m_pOwner->output->state->state().buffer)
+ return;
-void CMonitorState::clear() {
- wlr_output_state_finish(&m_state);
- m_state = {0};
- wlr_output_state_init(&m_state);
+ // this is required for modesetting being possible and might be missing in case of first tests in the renderer
+ // where we test modes and buffers
+ Debug::log(LOG, "CMonitorState::ensureBufferPresent: no buffer, attaching one from the swapchain for modeset being possible");
+ m_pOwner->output->state->setBuffer(m_pOwner->output->swapchain->next(nullptr));
+ m_pOwner->output->swapchain->rollback(); // restore the counter, don't advance the swapchain
}
bool CMonitorState::commit() {
- bool ret = wlr_output_commit_state(m_pOwner->output, &m_state);
- clear();
+ if (!updateSwapchain())
+ return false;
+
+ ensureBufferPresent();
+
+ bool ret = m_pOwner->output->commit();
return ret;
}
bool CMonitorState::test() {
- return wlr_output_test_state(m_pOwner->output, &m_state);
+ if (!updateSwapchain())
+ return false;
+
+ ensureBufferPresent();
+
+ return m_pOwner->output->test();
+}
+
+bool CMonitorState::updateSwapchain() {
+ auto options = m_pOwner->output->swapchain->currentOptions();
+ const auto& STATE = m_pOwner->output->state->state();
+ const auto& MODE = STATE.mode ? STATE.mode : STATE.customMode;
+ if (!MODE) {
+ Debug::log(WARN, "updateSwapchain: No mode?");
+ return true;
+ }
+ options.format = STATE.drmFormat;
+ options.scanout = true;
+ options.length = 2;
+ options.size = MODE->pixelSize;
+ return m_pOwner->output->swapchain->reconfigure(options);
}