Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PoC Fix VRR for constrained cursors #6877

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions src/Compositor.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Compositor.hpp"
#include "debug/Log.hpp"
#include "helpers/Splashes.hpp"
#include "config/ConfigValue.hpp"
#include "managers/CursorManager.hpp"
Expand Down Expand Up @@ -1363,6 +1364,9 @@ void CCompositor::changeWindowZOrder(PHLWINDOW pWindow, bool top) {
if (!validMapped(pWindow))
return;

if (pWindow == (top ? m_vWindows.back() : m_vWindows.front()))
return;

auto moveToZ = [&](PHLWINDOW pw, bool top) -> void {
if (top) {
for (auto it = m_vWindows.begin(); it != m_vWindows.end(); ++it) {
Expand Down
19 changes: 16 additions & 3 deletions src/events/Windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "../protocols/core/Compositor.hpp"
#include "../protocols/ToplevelExport.hpp"
#include "../xwayland/XSurface.hpp"
#include "managers/PointerManager.hpp"

#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;
Expand Down Expand Up @@ -742,16 +743,28 @@ void Events::listener_commitWindow(void* owner, void* data) {
if (!PWINDOW->m_pWorkspace->m_bVisible)
return;

g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);

PMONITOR->debugLastPresentation(g_pSeatManager->isPointerFrameCommit ? "listener_commitWindow skip" : "listener_commitWindow");
if (g_pSeatManager->isPointerFrameCommit) {
g_pSeatManager->isPointerFrameSkipped = false;
g_pSeatManager->isPointerFrameCommit = false;
} else
g_pHyprRenderer->damageSurface(PWINDOW->m_pWLSurface->resource(), PWINDOW->m_vRealPosition.goal().x, PWINDOW->m_vRealPosition.goal().y,
PWINDOW->m_bIsX11 ? 1.0 / PWINDOW->m_fX11SurfaceScaledBy : 1.0);

if (g_pSeatManager->isPointerFrameSkipped) {
g_pPointerManager->sendStoredMovement();
g_pSeatManager->sendPointerFrame();
g_pSeatManager->isPointerFrameCommit = true;
}

if (!PWINDOW->m_bIsX11) {
PWINDOW->m_pSubsurfaceHead->recheckDamageForSubsurfaces();
PWINDOW->m_pPopupHead->recheckTree();
}

// tearing: if solitary, redraw it. This still might be a single surface window
const auto PMONITOR = g_pCompositor->getMonitorFromID(PWINDOW->m_iMonitorID);
if (PMONITOR && PMONITOR->solitaryClient.lock() == PWINDOW && PWINDOW->canBeTorn() && PMONITOR->tearingState.canTear && PWINDOW->m_pWLSurface->resource()->current.texture) {
CRegion damageBox{PWINDOW->m_pWLSurface->resource()->accumulateCurrentBufferDamage()};

Expand Down
8 changes: 7 additions & 1 deletion src/helpers/Monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "../protocols/core/Compositor.hpp"
#include "sync/SyncTimeline.hpp"
#include <aquamarine/output/Output.hpp>
#include "debug/Log.hpp"
#include <hyprutils/string/String.hpp>
using namespace Hyprutils::String;

Expand Down Expand Up @@ -364,7 +365,7 @@ bool CMonitor::shouldSkipScheduleFrameOnMouseEvent() {
*PNOBREAK && output->state->state().adaptiveSync && activeWorkspace && activeWorkspace->m_bHasFullscreenWindow && activeWorkspace->m_efFullscreenMode == FSMODE_FULLSCREEN;

// keep requested minimum refresh rate
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000 / *PMINRR) {
if (shouldSkip && *PMINRR && lastPresentationTimer.getMillis() > 1000.0f / *PMINRR) {
// damage whole screen because some previous cursor box damages were skipped
damage.damageEntire();
return false;
Expand Down Expand Up @@ -893,6 +894,11 @@ bool CMonitor::attemptDirectScanout() {
return true;
}

void CMonitor::debugLastPresentation(const std::string& message) {
Debug::log(TRACE, "{} (last presentation {} - {} fps)", message, lastPresentationTimer.getMillis(),
lastPresentationTimer.getMillis() > 0 ? 1000.0f / lastPresentationTimer.getMillis() : 0.0f);
}

CMonitorState::CMonitorState(CMonitor* owner) {
m_pOwner = owner;
}
Expand Down
2 changes: 2 additions & 0 deletions src/helpers/Monitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ class CMonitor {
void scheduleDone();
bool attemptDirectScanout();

void debugLastPresentation(const std::string& message);

bool m_bEnabled = false;
bool m_bRenderingInitPassed = false;

Expand Down
5 changes: 3 additions & 2 deletions src/helpers/Timer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "Timer.hpp"
#include <chrono>

void CTimer::reset() {
m_tpLastReset = std::chrono::steady_clock::now();
Expand All @@ -8,8 +9,8 @@ std::chrono::steady_clock::duration CTimer::getDuration() {
return std::chrono::steady_clock::now() - m_tpLastReset;
}

long CTimer::getMillis() {
return std::chrono::duration_cast<std::chrono::milliseconds>(getDuration()).count();
float CTimer::getMillis() {
return std::chrono::duration_cast<std::chrono::microseconds>(getDuration()).count() / 1000.f;
}

float CTimer::getSeconds() {
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/Timer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class CTimer {
public:
void reset();
float getSeconds();
long getMillis();
float getMillis();
const std::chrono::steady_clock::time_point& chrono() const;

private:
Expand Down
2 changes: 1 addition & 1 deletion src/managers/AnimationManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ void CAnimationManager::tick() {

// manually schedule a frame
if (PMONITOR)
g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
g_pCompositor->scheduleFrameForMonitor(PMONITOR, Aquamarine::IOutput::AQ_SCHEDULE_ANIMATION);
}

// do it here, because if this alters the animation vars deque we would be in trouble above.
Expand Down
43 changes: 37 additions & 6 deletions src/managers/PointerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
#include "../protocols/PointerGestures.hpp"
#include "../protocols/RelativePointer.hpp"
#include "../protocols/FractionalScale.hpp"
#include "../protocols/core/Compositor.hpp"
#include "../protocols/core/Seat.hpp"
Expand Down Expand Up @@ -343,7 +344,7 @@ void CPointerManager::onCursorMoved() {
continue;

const auto CURSORPOS = getCursorPosForMonitor(m);
m->output->moveCursor(CURSORPOS);
m->output->moveCursor(CURSORPOS, m->shouldSkipScheduleFrameOnMouseEvent());
}
}

Expand All @@ -354,7 +355,7 @@ bool CPointerManager::attemptHardwareCursor(SP<CPointerManager::SMonitorPointerS
return false;

const auto CURSORPOS = getCursorPosForMonitor(state->monitor.lock());
state->monitor->output->moveCursor(CURSORPOS);
state->monitor->output->moveCursor(CURSORPOS, state->monitor->shouldSkipScheduleFrameOnMouseEvent());

auto texture = getCurrentCursorTexture();

Expand Down Expand Up @@ -397,7 +398,8 @@ bool CPointerManager::setHWCursorBuffer(SP<SMonitorPointerState> state, SP<Aquam

state->cursorFrontBuffer = buf;

g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);
if (!state->monitor->shouldSkipScheduleFrameOnMouseEvent())
g_pCompositor->scheduleFrameForMonitor(state->monitor.get(), Aquamarine::IOutput::AQ_SCHEDULE_CURSOR_SHAPE);

return true;
}
Expand Down Expand Up @@ -688,8 +690,11 @@ void CPointerManager::warpTo(const Vector2D& logical) {
damageIfSoftware();

pointerPos = closestValid(logical);
recheckEnteredOutputs();
onCursorMoved();

if (!g_pInputManager->isLocked()) {
recheckEnteredOutputs();
onCursorMoved();
}

damageIfSoftware();
}
Expand Down Expand Up @@ -854,7 +859,14 @@ void CPointerManager::attachPointer(SP<IPointer> pointer) {
});

listener->frame = pointer->pointerEvents.frame.registerListener([this] (std::any e) {
g_pSeatManager->sendPointerFrame();
bool shouldSkip = false;
if (!g_pSeatManager->mouse.expired() && g_pInputManager->isLocked()) {
auto PMONITOR = g_pCompositor->m_pLastMonitor.get();
shouldSkip = PMONITOR && PMONITOR->shouldSkipScheduleFrameOnMouseEvent();
}
g_pSeatManager->isPointerFrameSkipped = shouldSkip;
if (!g_pSeatManager->isPointerFrameSkipped)
g_pSeatManager->sendPointerFrame();
});

listener->swipeBegin = pointer->pointerEvents.swipeBegin.registerListener([this] (std::any e) {
Expand Down Expand Up @@ -1024,3 +1036,22 @@ void CPointerManager::damageCursor(SP<CMonitor> pMonitor) {
Vector2D CPointerManager::cursorSizeLogical() {
return currentCursorImage.size / currentCursorImage.scale;
}

void CPointerManager::storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) {
storedTime = time;
storedDelta += delta;
storedUnaccel += deltaUnaccel;
}

void CPointerManager::setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel) {
storedTime = time;
storedDelta = delta;
storedUnaccel = deltaUnaccel;
}

void CPointerManager::sendStoredMovement() {
PROTO::relativePointer->sendRelativeMotion((uint64_t)storedTime * 1000, storedDelta, storedUnaccel);
storedTime = 0;
storedDelta = Vector2D{};
storedUnaccel = Vector2D{};
}
7 changes: 7 additions & 0 deletions src/managers/PointerManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ class CPointerManager {
//
Vector2D position();
Vector2D cursorSizeLogical();
void storeMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel);
void setStoredMovement(uint64_t time, const Vector2D& delta, const Vector2D& deltaUnaccel);
void sendStoredMovement();

void recheckEnteredOutputs();

Expand Down Expand Up @@ -155,6 +158,10 @@ class CPointerManager {

Vector2D pointerPos = {0, 0};

uint64_t storedTime = 0;
Vector2D storedDelta = {0, 0};
Vector2D storedUnaccel = {0, 0};

struct SMonitorPointerState {
SMonitorPointerState(SP<CMonitor> m) : monitor(m) {}
~SMonitorPointerState() {}
Expand Down
3 changes: 3 additions & 0 deletions src/managers/SeatManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ class CSeatManager {
void setGrab(SP<CSeatGrab> grab); // nullptr removes
SP<CSeatGrab> seatGrab;

bool isPointerFrameSkipped = false;
bool isPointerFrameCommit = false;

private:
struct SSeatResourceContainer {
SSeatResourceContainer(SP<CWLSeatResource>);
Expand Down
21 changes: 18 additions & 3 deletions src/managers/input/InputManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ void CInputManager::onMouseMoved(IPointer::SMotionEvent e) {

const auto DELTA = *PNOACCEL == 1 ? e.unaccel : e.delta;

if (g_pSeatManager->isPointerFrameSkipped)
g_pPointerManager->storeMovement((uint64_t)e.timeMs, DELTA, e.unaccel);
else
g_pPointerManager->setStoredMovement((uint64_t)e.timeMs, DELTA, e.unaccel);

PROTO::relativePointer->sendRelativeMotion((uint64_t)e.timeMs * 1000, DELTA, e.unaccel);

g_pPointerManager->move(DELTA);
Expand Down Expand Up @@ -176,7 +181,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {

m_vLastCursorPosFloored = MOUSECOORDSFLOORED;

const auto PMONITOR = g_pCompositor->getMonitorFromCursor();
const auto PMONITOR = isLocked() && g_pCompositor->m_pLastMonitor ? g_pCompositor->m_pLastMonitor.get() : g_pCompositor->getMonitorFromCursor();

// this can happen if there are no displays hooked up to Hyprland
if (PMONITOR == nullptr)
Expand Down Expand Up @@ -204,9 +209,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
// constraints
if (!g_pSeatManager->mouse.expired() && isConstrained()) {
const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock());
const auto CONSTRAINT = SURF->constraint();
const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr;

if (SURF && CONSTRAINT) {
if (CONSTRAINT) {
if (CONSTRAINT->isLocked()) {
const auto HINT = CONSTRAINT->logicPositionHint();
g_pCompositor->warpCursorTo(HINT, true);
Expand Down Expand Up @@ -1431,6 +1436,16 @@ bool CInputManager::isConstrained() {
return false;
}

bool CInputManager::isLocked() {
if (!isConstrained())
return false;

const auto SURF = CWLSurface::fromResource(g_pCompositor->m_pLastFocus.lock());
const auto CONSTRAINT = SURF ? SURF->constraint() : nullptr;

return CONSTRAINT && CONSTRAINT->isLocked();
}

void CInputManager::updateCapabilities() {
uint32_t caps = 0;

Expand Down
1 change: 1 addition & 0 deletions src/managers/input/InputManager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class CInputManager {

void unconstrainMouse();
bool isConstrained();
bool isLocked();

Vector2D getMouseCoordsInternal();
void refocus();
Expand Down
Loading