aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--protocols/meson.build1
-rw-r--r--src/Compositor.cpp11
-rw-r--r--src/Compositor.hpp1
-rw-r--r--src/Window.cpp12
-rw-r--r--src/Window.hpp10
-rw-r--r--src/config/ConfigManager.cpp9
-rw-r--r--src/debug/HyprCtl.cpp2
-rw-r--r--src/events/Events.hpp3
-rw-r--r--src/events/Misc.cpp40
-rw-r--r--src/events/Monitors.cpp10
-rw-r--r--src/helpers/Monitor.cpp2
-rw-r--r--src/helpers/Monitor.hpp7
-rw-r--r--src/helpers/SubsurfaceTree.cpp9
-rw-r--r--src/helpers/WLClasses.hpp13
-rw-r--r--src/includes.hpp1
-rw-r--r--src/managers/input/InputManager.cpp3
-rw-r--r--src/render/Renderer.cpp137
-rw-r--r--src/render/Renderer.hpp20
19 files changed, 231 insertions, 61 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a52c798a..b3bc5526 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -218,5 +218,6 @@ protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false)
protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false)
protocol("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false)
protocol("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false)
+protocol("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false)
protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
diff --git a/protocols/meson.build b/protocols/meson.build
index 60ae20cb..cc111e98 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -25,6 +25,7 @@ protocols = [
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
[wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
+ [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
['wlr-foreign-toplevel-management-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['wlr-output-power-management-unstable-v1.xml'],
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index 0672a543..1cb378db 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -257,6 +257,8 @@ void CCompositor::initServer() {
m_sWLRCursorShapeMgr = wlr_cursor_shape_manager_v1_create(m_sWLDisplay, 1);
+ m_sWLRTearingControlMgr = wlr_tearing_control_manager_v1_create(m_sWLDisplay, 1);
+
if (!m_sWLRHeadlessBackend) {
Debug::log(CRIT, "Couldn't create the headless backend");
throwError("wlr_headless_backend_create() failed!");
@@ -315,6 +317,7 @@ void CCompositor::initAllSignals() {
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_sWLRCursorShapeMgr->events.request_set_shape, &Events::listen_setCursorShape, m_sWLRCursorShapeMgr, "CursorShapeMgr");
+ addWLSignal(&m_sWLRTearingControlMgr->events.new_object, &Events::listen_newTearingHint, m_sWLRTearingControlMgr, "TearingControlMgr");
if (m_sWRLDRMLeaseMgr)
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
@@ -2475,7 +2478,13 @@ int CCompositor::getNewSpecialID() {
}
void CCompositor::performUserChecks() {
- // empty
+ const auto atomicEnv = getenv("WLR_DRM_NO_ATOMIC");
+ const auto atomicEnvStr = std::string(atomicEnv ? atomicEnv : "");
+ if (g_pConfigManager->getInt("general:allow_tearing") == 1 && atomicEnvStr != "1") {
+ g_pHyprNotificationOverlay->addNotification("You have enabled tearing, but immediate presentations are not available on your configuration. Try adding "
+ "env = WLR_DRM_NO_ATOMIC,1 to your config.",
+ CColor(0), 15000, ICON_WARNING);
+ }
}
void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) {
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index 06d15c3c..99839b06 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -85,6 +85,7 @@ class CCompositor {
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
+ wlr_tearing_control_manager_v1* m_sWLRTearingControlMgr;
// ------------------------------------------------- //
std::string m_szWLDisplaySocket = "";
diff --git a/src/Window.cpp b/src/Window.cpp
index 4ee40dff..9055101e 100644
--- a/src/Window.cpp
+++ b/src/Window.cpp
@@ -414,6 +414,11 @@ void CWindow::onUnmap() {
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
PMONITOR->setSpecialWorkspace(nullptr);
}
+
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
+
+ if (PMONITOR && PMONITOR->solitaryClient == this)
+ PMONITOR->solitaryClient = nullptr;
}
void CWindow::onMap() {
@@ -492,6 +497,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
} else if (r.szRule == "opaque") {
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
m_sAdditionalConfigData.forceOpaque = true;
+ } else if (r.szRule == "immediate") {
+ m_sAdditionalConfigData.forceTearing = true;
} else if (r.szRule.find("rounding") == 0) {
try {
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
@@ -580,6 +587,7 @@ void CWindow::updateDynamicRules() {
m_sAdditionalConfigData.borderSize = -1;
m_sAdditionalConfigData.keepAspectRatio = false;
m_sAdditionalConfigData.xray = -1;
+ m_sAdditionalConfigData.forceTearing = false;
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
for (auto& r : WINDOWRULES) {
@@ -925,3 +933,7 @@ int CWindow::getRealBorderSize() {
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
}
+
+bool CWindow::canBeTorn() {
+ return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
+}
diff --git a/src/Window.hpp b/src/Window.hpp
index 81b6156f..dd16fdcb 100644
--- a/src/Window.hpp
+++ b/src/Window.hpp
@@ -11,14 +11,16 @@
#include "macros.hpp"
#include "managers/XWaylandManager.hpp"
-enum eIdleInhibitMode {
+enum eIdleInhibitMode
+{
IDLEINHIBIT_NONE = 0,
IDLEINHIBIT_ALWAYS,
IDLEINHIBIT_FULLSCREEN,
IDLEINHIBIT_FOCUS
};
-enum eGroupRules {
+enum eGroupRules
+{
// effective only during first map, except for _ALWAYS variant
GROUP_NONE = 0,
GROUP_SET = 1 << 0, // Open as new group or add to focused group
@@ -138,6 +140,7 @@ struct SWindowAdditionalConfigData {
CWindowOverridableVar<bool> keepAspectRatio = false;
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one
CWindowOverridableVar<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
+ CWindowOverridableVar<bool> forceTearing = false;
};
struct SWindowRule {
@@ -317,6 +320,8 @@ class CWindow {
} m_sGroupData;
uint16_t m_eGroupRules = GROUP_NONE;
+ bool m_bTearingHint = false;
+
// For the list lookup
bool operator==(const CWindow& rhs) {
return m_uSurface.xdg == rhs.m_uSurface.xdg && m_uSurface.xwayland == rhs.m_uSurface.xwayland && m_vPosition == rhs.m_vPosition && m_vSize == rhs.m_vSize &&
@@ -348,6 +353,7 @@ class CWindow {
Vector2D middle();
bool opaque();
float rounding();
+ bool canBeTorn();
int getRealBorderSize();
void updateSpecialRenderData();
diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 7556776e..fc7a9e3e 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -87,6 +87,7 @@ void CConfigManager::setDefaultVars() {
configValues["general:extend_border_grab_area"].intValue = 15;
configValues["general:hover_icon_on_border"].intValue = 1;
configValues["general:layout"].strValue = "dwindle";
+ configValues["general:allow_tearing"].intValue = 0;
configValues["misc:disable_hyprland_logo"].intValue = 0;
configValues["misc:disable_splash_rendering"].intValue = 0;
@@ -279,7 +280,7 @@ void CConfigManager::setDeviceDefaultVars(const std::string& dev) {
cfgValues["scroll_button_lock"].intValue = 0;
cfgValues["transform"].intValue = 0;
cfgValues["output"].strValue = STRVAL_EMPTY;
- cfgValues["enabled"].intValue = 1; // only for mice / touchpads
+ cfgValues["enabled"].intValue = 1; // only for mice / touchpads
cfgValues["region_position"].vecValue = Vector2D(); // only for tablets
cfgValues["region_size"].vecValue = Vector2D(); // only for tablets
}
@@ -912,7 +913,7 @@ bool windowRuleValid(const std::string& RULE) {
RULE != "nomaximizerequest" && RULE != "fakefullscreen" && RULE != "nomaxsize" && RULE != "pin" && RULE != "noanim" && RULE != "dimaround" && RULE != "windowdance" &&
RULE != "maximize" && RULE != "keepaspectratio" && RULE.find("animation") != 0 && RULE.find("rounding") != 0 && RULE.find("workspace") != 0 &&
RULE.find("bordercolor") != 0 && RULE != "forcergbx" && RULE != "noinitialfocus" && RULE != "stayfocused" && RULE.find("bordersize") != 0 && RULE.find("xray") != 0 &&
- RULE.find("center") != 0 && RULE.find("group") != 0);
+ RULE.find("center") != 0 && RULE.find("group") != 0 && RULE != "immediate");
}
bool layerRuleValid(const std::string& RULE) {
@@ -1244,7 +1245,7 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
int linenum = 1;
if (ifs.is_open()) {
auto configCurrentPathBackup = configCurrentPath;
-
+
while (std::getline(ifs, line)) {
// Read line by line.
try {
@@ -1265,7 +1266,7 @@ void CConfigManager::handleSource(const std::string& command, const std::string&
}
ifs.close();
-
+
configCurrentPath = configCurrentPathBackup;
}
}
diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index 0aafe664..8eced97d 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -1009,6 +1009,8 @@ std::string dispatchSetProp(std::string request) {
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else if (PROP == "keepaspectratio") {
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock);
+ } else if (PROP == "immediate") {
+ PWINDOW->m_sAdditionalConfigData.forceTearing.forceSetIgnoreLocked(configStringToInt(VAL), lock);
} else {
return "prop not found";
}
diff --git a/src/events/Events.hpp b/src/events/Events.hpp
index f89032ea..fc68880e 100644
--- a/src/events/Events.hpp
+++ b/src/events/Events.hpp
@@ -174,4 +174,7 @@ namespace Events {
// Cursor shape
LISTENER(setCursorShape);
+
+ // Tearing hints
+ LISTENER(newTearingHint);
};
diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp
index d4e7bad9..1df4be3a 100644
--- a/src/events/Misc.cpp
+++ b/src/events/Misc.cpp
@@ -237,3 +237,43 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
g_pInputManager->processMouseRequest(E);
}
+
+void Events::listener_newTearingHint(wl_listener* listener, void* data) {
+ const auto TCTL = (wlr_tearing_control_v1*)data;
+
+ const auto PWINDOW = g_pCompositor->getWindowFromSurface(TCTL->surface);
+
+ if (!PWINDOW) {
+ Debug::log(ERR, "Tearing hint {} was attached to an unknown surface", (uintptr_t)data);
+ return;
+ }
+
+ Debug::log(LOG, "New tearing hint for window {} at {}", PWINDOW, (uintptr_t)data);
+
+ const auto NEWCTRL = g_pHyprRenderer->m_vTearingControllers.emplace_back(std::make_unique<STearingController>()).get();
+ NEWCTRL->pWlrHint = (wlr_tearing_control_v1*)data;
+
+ NEWCTRL->hyprListener_destroy.initCallback(
+ &NEWCTRL->pWlrHint->events.destroy,
+ [&](void* owner, void* data) {
+ Debug::log(LOG, "Destroyed {} tearing hint", (uintptr_t)((STearingController*)owner)->pWlrHint);
+
+ std::erase_if(g_pHyprRenderer->m_vTearingControllers, [&](const auto& other) { return other.get() == owner; });
+ },
+ NEWCTRL, "TearingController");
+
+ NEWCTRL->hyprListener_set.initCallback(
+ &NEWCTRL->pWlrHint->events.set_hint,
+ [&](void* owner, void* data) {
+ const auto TEARINGHINT = (STearingController*)owner;
+
+ const auto PWINDOW = g_pCompositor->getWindowFromSurface(TEARINGHINT->pWlrHint->surface);
+
+ if (PWINDOW) {
+ PWINDOW->m_bTearingHint = TEARINGHINT->pWlrHint->hint;
+
+ Debug::log(LOG, "Hint {} (window {}) set tearing hint to {}", (uintptr_t)TEARINGHINT->pWlrHint, PWINDOW, (uint32_t)TEARINGHINT->pWlrHint->hint);
+ }
+ },
+ NEWCTRL, "TearingController");
+}
diff --git a/src/events/Monitors.cpp b/src/events/Monitors.cpp
index 947f9e7f..d006c2f2 100644
--- a/src/events/Monitors.cpp
+++ b/src/events/Monitors.cpp
@@ -149,6 +149,14 @@ void Events::listener_monitorFrame(void* owner, void* data) {
if (!PMONITOR->m_bEnabled)
return;
+ if (PMONITOR->ignoreNextFlipEvent) {
+ Debug::log(LOG, "Ignore next flip event for {}", PMONITOR->szName);
+ PMONITOR->ignoreNextFlipEvent = false;
+ return;
+ }
+
+ PMONITOR->renderingFromVblankEvent = true;
+
static auto* const PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->intValue;
@@ -181,6 +189,8 @@ void Events::listener_monitorFrame(void* owner, void* data) {
} else {
g_pHyprRenderer->renderMonitor(PMONITOR);
}
+
+ PMONITOR->renderingFromVblankEvent = false;
}
void Events::listener_monitorDestroy(void* owner, void* data) {
diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp
index dd9580d1..0d0b2a64 100644
--- a/src/helpers/Monitor.cpp
+++ b/src/helpers/Monitor.cpp
@@ -40,6 +40,8 @@ void CMonitor::onConnect(bool noRule) {
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, this);
+ canTear = wlr_backend_is_drm(output->backend); // tearing only works on drm
+
if (m_bEnabled) {
wlr_output_enable(output, 1);
wlr_output_commit(output);
diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp
index 93f345ba..f8b8554c 100644
--- a/src/helpers/Monitor.hpp
+++ b/src/helpers/Monitor.hpp
@@ -81,6 +81,13 @@ class CMonitor {
CRegion lastFrameDamage; // stores last frame damage
+ // for tearing
+ CWindow* solitaryClient = nullptr;
+ bool canTear = false;
+ bool nextRenderTorn = false;
+ bool ignoreNextFlipEvent = false;
+ bool renderingFromVblankEvent = false;
+
// for the special workspace. 0 means not open.
int specialWorkspaceID = 0;
diff --git a/src/helpers/SubsurfaceTree.cpp b/src/helpers/SubsurfaceTree.cpp
index 5e3e9e67..5b86f928 100644
--- a/src/helpers/SubsurfaceTree.cpp
+++ b/src/helpers/SubsurfaceTree.cpp
@@ -245,6 +245,15 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
if (pNode->pSurface && pNode->pSurface->exists())
g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
+
+ if (pNode->pWindowOwner) {
+ // tearing: if solitary, redraw it. This still might be a single surface window
+ const auto PMONITOR = g_pCompositor->getMonitorFromID(pNode->pWindowOwner->m_iMonitorID);
+ if (PMONITOR->solitaryClient == pNode->pWindowOwner && pNode->pWindowOwner->canBeTorn() && PMONITOR->canTear) {
+ PMONITOR->nextRenderTorn = true;
+ g_pHyprRenderer->renderMonitor(PMONITOR);
+ }
+ }
}
void Events::listener_destroySubsurface(void* owner, void* data) {
diff --git a/src/helpers/WLClasses.hpp b/src/helpers/WLClasses.hpp
index d33af797..e8647426 100644
--- a/src/helpers/WLClasses.hpp
+++ b/src/helpers/WLClasses.hpp
@@ -180,7 +180,7 @@ struct SConstraint {
Vector2D getLogicConstraintSize();
bool operator==(const SConstraint& b) const {
- return constraint == b.constraint;
+ return constraint == b.constraint;
}
};
@@ -393,3 +393,14 @@ struct SSwitchDevice {
return pWlrDevice == other.pWlrDevice;
}
};
+
+struct STearingController {
+ wlr_tearing_control_v1* pWlrHint = nullptr;
+
+ DYNLISTENER(set);
+ DYNLISTENER(destroy);
+
+ bool operator==(const STearingController& other) {
+ return pWlrHint == other.pWlrHint;
+ }
+};
diff --git a/src/includes.hpp b/src/includes.hpp
index c81ee9fe..1205f55c 100644
--- a/src/includes.hpp
+++ b/src/includes.hpp
@@ -105,6 +105,7 @@ extern "C" {
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_cursor_shape_v1.h>
+#include <wlr/types/wlr_tearing_control_v1.h>
#include <libdrm/drm_fourcc.h>
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index beb55c5d..e790bf7f 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -118,7 +118,8 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
if (*PZOOMFACTOR != 1.f)
g_pHyprRenderer->damageMonitor(PMONITOR);
- g_pCompositor->scheduleFrameForMonitor(PMONITOR);
+ if (!PMONITOR->solitaryClient) // if there is a solitary client we can't schedule a frame here, this will completely fuck up drm
+ g_pCompositor->scheduleFrameForMonitor(PMONITOR);
CWindow* forcedFocus = m_pForcedFocus;
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 6dcf0b44..982edd4b 100644
--- a/src/render/Renderer.cpp
+++ b/src/render/Renderer.cpp
@@ -3,6 +3,13 @@
#include "linux-dmabuf-unstable-v1-protocol.h"
#include "../helpers/Region.hpp"
+CHyprRenderer::CHyprRenderer() {
+ const auto ENV = getenv("WLR_DRM_NO_ATOMIC");
+
+ if (ENV && std::string(ENV) == "1")
+ m_bTearingEnvSatisfied = true;
+}
+
void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
const auto TEXTURE = wlr_surface_get_texture(surface);
const auto RDATA = (SRenderData*)data;
@@ -702,51 +709,12 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
if (!wlr_output_is_direct_scanout_allowed(pMonitor->output))
return false;
- const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
-
- if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient || pMonitor->specialWorkspaceID)
- return false;
-
- const auto PCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
+ const auto PCANDIDATE = pMonitor->solitaryClient;
if (!PCANDIDATE)
- return false; // ????
-
- if (PCANDIDATE->m_fAlpha.fl() != 1.f || PCANDIDATE->m_fActiveInactiveAlpha.fl() != 1.f || PWORKSPACE->m_fAlpha.fl() != 1.f)
return false;
- if (PCANDIDATE->m_vRealSize.vec() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition.vec() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition.isBeingAnimated() ||
- PCANDIDATE->m_vRealSize.isBeingAnimated())
- return false;
-
- if (!pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty())
- return false;
-
- for (auto& topls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
- if (topls->alpha.fl() != 0.f)
- return false;
- }
-
- // check if it did not open any subsurfaces or shit
- int surfaceCount = 0;
- if (PCANDIDATE->m_bIsX11) {
- surfaceCount = 1;
-
- // check opaque
- if (PCANDIDATE->m_uSurface.xwayland->has_alpha)
- return false;
- } else {
- wlr_xdg_surface_for_each_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
- wlr_xdg_surface_for_each_popup_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
-
- if (!PCANDIDATE->m_uSurface.xdg->surface->opaque)
- return false;
- }
-
- if (surfaceCount != 1)
- return false;
-
- const auto PSURFACE = PCANDIDATE->m_pWLSurface.wlr();
+ const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
return false;
@@ -754,9 +722,8 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
// finally, we should be GTG.
wlr_output_attach_buffer(pMonitor->output, &PSURFACE->buffer->base);
- if (!wlr_output_test(pMonitor->output)) {
+ if (!wlr_output_test(pMonitor->output))
return false;
- }
timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@@ -790,6 +757,7 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
static auto* const PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
static auto* const PBACKGROUNDCOLOR = &g_pConfigManager->getConfigValuePtr("misc:background_color")->intValue;
static auto* const PANIMENABLED = &g_pConfigManager->getConfigValuePtr("animations:enabled")->intValue;
+ static auto* const PTEARINGENABLED = &g_pConfigManager->getConfigValuePtr("general:allow_tearing")->intValue;
static int damageBlinkCleanup = 0; // because double-buffered
@@ -876,8 +844,38 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
}
}
- // Direct scanout first
- if (!*PNODIRECTSCANOUT) {
+ // tearing and DS first
+ bool shouldTear = false;
+ bool canTear = *PTEARINGENABLED && g_pHyprOpenGL->m_RenderData.mouseZoomFactor == 1.0;
+ recheckSolitaryForMonitor(pMonitor);
+ if (pMonitor->nextRenderTorn) {
+ pMonitor->nextRenderTorn = false;
+
+ if (!*PTEARINGENABLED) {
+ Debug::log(WARN, "Tearing commit requested but the master switch general:allow_tearing is off, ignoring");
+ return;
+ }
+
+ if (g_pHyprOpenGL->m_RenderData.mouseZoomFactor != 1.0) {
+ Debug::log(WARN, "Tearing commit requested but scale factor is not 1, ignoring");
+ return;
+ }
+
+ if (!pMonitor->canTear) {
+ Debug::log(WARN, "Tearing commit requested but monitor doesn't support it, ignoring");
+ return;
+ }
+
+ if (pMonitor->solitaryClient)
+ shouldTear = true;
+ } else {
+ // if this is a non-tearing commit, and we are in a state where we should tear
+ // then this is a vblank commit that we should ignore
+ if (canTear && pMonitor->solitaryClient && pMonitor->canTear && pMonitor->solitaryClient->canBeTorn() && pMonitor->renderingFromVblankEvent)
+ return;
+ }
+
+ if (!*PNODIRECTSCANOUT && !shouldTear) {
if (attemptDirectScanout(pMonitor)) {
return;
} else if (m_pLastScanout) {
@@ -1061,6 +1059,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
EMIT_HOOK_EVENT("render", RENDER_POST);
+ pMonitor->output->pending.tearing_page_flip = shouldTear;
+
if (!wlr_output_commit(pMonitor->output)) {
if (UNLOCK_SC)
wlr_output_lock_software_cursors(pMonitor->output, false);
@@ -1068,6 +1068,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
return;
}
+ if (shouldTear)
+ pMonitor->ignoreNextFlipEvent = true;
+
wlr_damage_ring_rotate(&pMonitor->damage);
if (UNLOCK_SC)
@@ -1986,3 +1989,47 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) {
return false;
}
+
+void CHyprRenderer::recheckSolitaryForMonitor(CMonitor* pMonitor) {
+ pMonitor->solitaryClient = nullptr; // reset it, if we find one it will be set.
+
+ const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
+
+ if (!PWORKSPACE || !PWORKSPACE->m_bHasFullscreenWindow || g_pInputManager->m_sDrag.drag || g_pCompositor->m_sSeat.exclusiveClient || pMonitor->specialWorkspaceID)
+ return;
+
+ const auto PCANDIDATE = g_pCompositor->getFullscreenWindowOnWorkspace(PWORKSPACE->m_iID);
+
+ if (!PCANDIDATE)
+ return; // ????
+
+ if (!PCANDIDATE->opaque())
+ return;
+
+ if (PCANDIDATE->m_vRealSize.vec() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition.vec() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition.isBeingAnimated() ||
+ PCANDIDATE->m_vRealSize.isBeingAnimated())
+ return;
+
+ if (!pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY].empty())
+ return;
+
+ for (auto& topls : pMonitor->m_aLayerSurfaceLayers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]) {
+ if (topls->alpha.fl() != 0.f)
+ return;
+ }
+
+ // check if it did not open any subsurfaces or shit
+ int surfaceCount = 0;
+ if (PCANDIDATE->m_bIsX11) {
+ surfaceCount = 1;
+ } else {
+ wlr_xdg_surface_for_each_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
+ wlr_xdg_surface_for_each_popup_surface(PCANDIDATE->m_uSurface.xdg, countSubsurfacesIter, &surfaceCount);
+ }
+
+ if (surfaceCount != 1)
+ Debug::log(LOG, "fuf: >1 surf");
+
+ // found one!
+ pMonitor->solitaryClient = PCANDIDATE;
+}
diff --git a/src/render/Renderer.hpp b/src/render/Renderer.hpp
index f0e19c38..2b437b00 100644
--- a/src/render/Renderer.hpp
+++ b/src/render/Renderer.hpp
@@ -33,6 +33,8 @@ struct SSessionLockSurface;
class CHyprRenderer {
public:
+ CHyprRenderer();
+
void renderMonitor(CMonitor* pMonitor);
void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
void arrangeLayersForMonitor(const int&);
@@ -53,6 +55,7 @@ class CHyprRenderer {
void renderLockscreen(CMonitor* pMonitor, timespec* now);
void setOccludedForBackLayers(CRegion& region, CWorkspace* pWorkspace);
bool canSkipBackBufferClear(CMonitor* pMonitor);
+ void recheckSolitaryForMonitor(CMonitor* pMonitor);
bool m_bWindowRequestedCursorHide = false;
bool m_bBlockSurfaceFeedback = false;
@@ -61,19 +64,22 @@ class CHyprRenderer {
CMonitor* m_pMostHzMonitor = nullptr;
bool m_bDirectScanoutBlocked = false;
bool m_bSoftwareCursorsLocked = false;
+ bool m_bTearingEnvSatisfied = false;
DAMAGETRACKINGMODES
damageTrackingModeFromStr(const std::string&);
- bool attemptDirectScanout(CMonitor*);
- void setWindowScanoutMode(CWindow*);
- void initiateManualCrash();
+ bool attemptDirectScanout(CMonitor*);
+ void setWindowScanoutMode(CWindow*);
+ void initiateManualCrash();
+
+ bool m_bCrashingInProgress = false;
+ float m_fCrashingDistort = 0.5f;
+ wl_event_source* m_pCrashingLoop = nullptr;
- bool m_bCrashingInProgress = false;
- float m_fCrashingDistort = 0.5f;
- wl_event_source* m_pCrashingLoop = nullptr;
+ std::vector<std::unique_ptr<STearingController>> m_vTearingControllers;
- CTimer m_tRenderTimer;
+ CTimer m_tRenderTimer;
private:
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);