diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2024-07-21 13:09:54 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-21 13:09:54 +0200 |
| commit | 016da234d0e852de3ef20eb2e89ac58d2a85f6e7 (patch) | |
| tree | 496085987176551b0794fffc069877d44943e2f1 /src/helpers/Monitor.cpp | |
| parent | f642fb97df5c69267a03452533de383ff8023570 (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.cpp | 293 |
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); } |
