mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-24 18:25:59 +01:00
renderer: Tearing implementation (#3441)
This commit is contained in:
parent
1e513e25d5
commit
88b63a00b6
19 changed files with 231 additions and 61 deletions
|
@ -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/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("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/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("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)
|
protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false)
|
||||||
|
|
|
@ -25,6 +25,7 @@ protocols = [
|
||||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
[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/fractional-scale/fractional-scale-v1.xml'],
|
||||||
[wl_protocol_dir, 'staging/cursor-shape/cursor-shape-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-foreign-toplevel-management-unstable-v1.xml'],
|
||||||
['wlr-layer-shell-unstable-v1.xml'],
|
['wlr-layer-shell-unstable-v1.xml'],
|
||||||
['wlr-output-power-management-unstable-v1.xml'],
|
['wlr-output-power-management-unstable-v1.xml'],
|
||||||
|
|
|
@ -257,6 +257,8 @@ void CCompositor::initServer() {
|
||||||
|
|
||||||
m_sWLRCursorShapeMgr = wlr_cursor_shape_manager_v1_create(m_sWLDisplay, 1);
|
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) {
|
if (!m_sWLRHeadlessBackend) {
|
||||||
Debug::log(CRIT, "Couldn't create the headless backend");
|
Debug::log(CRIT, "Couldn't create the headless backend");
|
||||||
throwError("wlr_headless_backend_create() failed!");
|
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_sWLRSessionLockMgr->events.new_lock, &Events::listen_newSessionLock, m_sWLRSessionLockMgr, "SessionLockMgr");
|
||||||
addWLSignal(&m_sWLRGammaCtrlMgr->events.set_gamma, &Events::listen_setGamma, m_sWLRGammaCtrlMgr, "GammaCtrlMgr");
|
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_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)
|
if (m_sWRLDRMLeaseMgr)
|
||||||
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
|
addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM");
|
||||||
|
@ -2475,7 +2478,13 @@ int CCompositor::getNewSpecialID() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCompositor::performUserChecks() {
|
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) {
|
void CCompositor::moveWindowToWorkspaceSafe(CWindow* pWindow, CWorkspace* pWorkspace) {
|
||||||
|
|
|
@ -85,6 +85,7 @@ class CCompositor {
|
||||||
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
|
wlr_session_lock_manager_v1* m_sWLRSessionLockMgr;
|
||||||
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
|
wlr_gamma_control_manager_v1* m_sWLRGammaCtrlMgr;
|
||||||
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
|
wlr_cursor_shape_manager_v1* m_sWLRCursorShapeMgr;
|
||||||
|
wlr_tearing_control_manager_v1* m_sWLRTearingControlMgr;
|
||||||
// ------------------------------------------------- //
|
// ------------------------------------------------- //
|
||||||
|
|
||||||
std::string m_szWLDisplaySocket = "";
|
std::string m_szWLDisplaySocket = "";
|
||||||
|
|
|
@ -414,6 +414,11 @@ void CWindow::onUnmap() {
|
||||||
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
|
if (PMONITOR && PMONITOR->specialWorkspaceID == m_iWorkspaceID)
|
||||||
PMONITOR->setSpecialWorkspace(nullptr);
|
PMONITOR->setSpecialWorkspace(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto PMONITOR = g_pCompositor->getMonitorFromID(m_iMonitorID);
|
||||||
|
|
||||||
|
if (PMONITOR && PMONITOR->solitaryClient == this)
|
||||||
|
PMONITOR->solitaryClient = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWindow::onMap() {
|
void CWindow::onMap() {
|
||||||
|
@ -492,6 +497,8 @@ void CWindow::applyDynamicRule(const SWindowRule& r) {
|
||||||
} else if (r.szRule == "opaque") {
|
} else if (r.szRule == "opaque") {
|
||||||
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
|
if (!m_sAdditionalConfigData.forceOpaqueOverridden)
|
||||||
m_sAdditionalConfigData.forceOpaque = true;
|
m_sAdditionalConfigData.forceOpaque = true;
|
||||||
|
} else if (r.szRule == "immediate") {
|
||||||
|
m_sAdditionalConfigData.forceTearing = true;
|
||||||
} else if (r.szRule.find("rounding") == 0) {
|
} else if (r.szRule.find("rounding") == 0) {
|
||||||
try {
|
try {
|
||||||
m_sAdditionalConfigData.rounding = std::stoi(r.szRule.substr(r.szRule.find_first_of(' ') + 1));
|
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.borderSize = -1;
|
||||||
m_sAdditionalConfigData.keepAspectRatio = false;
|
m_sAdditionalConfigData.keepAspectRatio = false;
|
||||||
m_sAdditionalConfigData.xray = -1;
|
m_sAdditionalConfigData.xray = -1;
|
||||||
|
m_sAdditionalConfigData.forceTearing = false;
|
||||||
|
|
||||||
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
|
const auto WINDOWRULES = g_pConfigManager->getMatchingRules(this);
|
||||||
for (auto& r : WINDOWRULES) {
|
for (auto& r : WINDOWRULES) {
|
||||||
|
@ -925,3 +933,7 @@ int CWindow::getRealBorderSize() {
|
||||||
|
|
||||||
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
return g_pConfigManager->getConfigValuePtr("general:border_size")->intValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CWindow::canBeTorn() {
|
||||||
|
return (m_sAdditionalConfigData.forceTearing.toUnderlying() || m_bTearingHint) && g_pHyprRenderer->m_bTearingEnvSatisfied;
|
||||||
|
}
|
||||||
|
|
|
@ -11,14 +11,16 @@
|
||||||
#include "macros.hpp"
|
#include "macros.hpp"
|
||||||
#include "managers/XWaylandManager.hpp"
|
#include "managers/XWaylandManager.hpp"
|
||||||
|
|
||||||
enum eIdleInhibitMode {
|
enum eIdleInhibitMode
|
||||||
|
{
|
||||||
IDLEINHIBIT_NONE = 0,
|
IDLEINHIBIT_NONE = 0,
|
||||||
IDLEINHIBIT_ALWAYS,
|
IDLEINHIBIT_ALWAYS,
|
||||||
IDLEINHIBIT_FULLSCREEN,
|
IDLEINHIBIT_FULLSCREEN,
|
||||||
IDLEINHIBIT_FOCUS
|
IDLEINHIBIT_FOCUS
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eGroupRules {
|
enum eGroupRules
|
||||||
|
{
|
||||||
// effective only during first map, except for _ALWAYS variant
|
// effective only during first map, except for _ALWAYS variant
|
||||||
GROUP_NONE = 0,
|
GROUP_NONE = 0,
|
||||||
GROUP_SET = 1 << 0, // Open as new group or add to focused group
|
GROUP_SET = 1 << 0, // Open as new group or add to focused group
|
||||||
|
@ -138,6 +140,7 @@ struct SWindowAdditionalConfigData {
|
||||||
CWindowOverridableVar<bool> keepAspectRatio = false;
|
CWindowOverridableVar<bool> keepAspectRatio = false;
|
||||||
CWindowOverridableVar<int> xray = -1; // -1 means unset, takes precedence over the renderdata one
|
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<int> borderSize = -1; // -1 means unset, takes precedence over the renderdata one
|
||||||
|
CWindowOverridableVar<bool> forceTearing = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SWindowRule {
|
struct SWindowRule {
|
||||||
|
@ -317,6 +320,8 @@ class CWindow {
|
||||||
} m_sGroupData;
|
} m_sGroupData;
|
||||||
uint16_t m_eGroupRules = GROUP_NONE;
|
uint16_t m_eGroupRules = GROUP_NONE;
|
||||||
|
|
||||||
|
bool m_bTearingHint = false;
|
||||||
|
|
||||||
// For the list lookup
|
// For the list lookup
|
||||||
bool operator==(const CWindow& rhs) {
|
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 &&
|
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();
|
Vector2D middle();
|
||||||
bool opaque();
|
bool opaque();
|
||||||
float rounding();
|
float rounding();
|
||||||
|
bool canBeTorn();
|
||||||
|
|
||||||
int getRealBorderSize();
|
int getRealBorderSize();
|
||||||
void updateSpecialRenderData();
|
void updateSpecialRenderData();
|
||||||
|
|
|
@ -87,6 +87,7 @@ void CConfigManager::setDefaultVars() {
|
||||||
configValues["general:extend_border_grab_area"].intValue = 15;
|
configValues["general:extend_border_grab_area"].intValue = 15;
|
||||||
configValues["general:hover_icon_on_border"].intValue = 1;
|
configValues["general:hover_icon_on_border"].intValue = 1;
|
||||||
configValues["general:layout"].strValue = "dwindle";
|
configValues["general:layout"].strValue = "dwindle";
|
||||||
|
configValues["general:allow_tearing"].intValue = 0;
|
||||||
|
|
||||||
configValues["misc:disable_hyprland_logo"].intValue = 0;
|
configValues["misc:disable_hyprland_logo"].intValue = 0;
|
||||||
configValues["misc:disable_splash_rendering"].intValue = 0;
|
configValues["misc:disable_splash_rendering"].intValue = 0;
|
||||||
|
@ -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 != "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 != "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("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) {
|
bool layerRuleValid(const std::string& RULE) {
|
||||||
|
|
|
@ -1009,6 +1009,8 @@ std::string dispatchSetProp(std::string request) {
|
||||||
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
PWINDOW->m_sSpecialRenderData.borderSize.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||||
} else if (PROP == "keepaspectratio") {
|
} else if (PROP == "keepaspectratio") {
|
||||||
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
PWINDOW->m_sAdditionalConfigData.keepAspectRatio.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||||
|
} else if (PROP == "immediate") {
|
||||||
|
PWINDOW->m_sAdditionalConfigData.forceTearing.forceSetIgnoreLocked(configStringToInt(VAL), lock);
|
||||||
} else {
|
} else {
|
||||||
return "prop not found";
|
return "prop not found";
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,4 +174,7 @@ namespace Events {
|
||||||
|
|
||||||
// Cursor shape
|
// Cursor shape
|
||||||
LISTENER(setCursorShape);
|
LISTENER(setCursorShape);
|
||||||
|
|
||||||
|
// Tearing hints
|
||||||
|
LISTENER(newTearingHint);
|
||||||
};
|
};
|
||||||
|
|
|
@ -237,3 +237,43 @@ void Events::listener_setCursorShape(wl_listener* listener, void* data) {
|
||||||
|
|
||||||
g_pInputManager->processMouseRequest(E);
|
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");
|
||||||
|
}
|
||||||
|
|
|
@ -149,6 +149,14 @@ void Events::listener_monitorFrame(void* owner, void* data) {
|
||||||
if (!PMONITOR->m_bEnabled)
|
if (!PMONITOR->m_bEnabled)
|
||||||
return;
|
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 PENABLERAT = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_of_time")->intValue;
|
||||||
static auto* const PRATSAFE = &g_pConfigManager->getConfigValuePtr("misc:render_ahead_safezone")->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 {
|
} else {
|
||||||
g_pHyprRenderer->renderMonitor(PMONITOR);
|
g_pHyprRenderer->renderMonitor(PMONITOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PMONITOR->renderingFromVblankEvent = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Events::listener_monitorDestroy(void* owner, void* data) {
|
void Events::listener_monitorDestroy(void* owner, void* data) {
|
||||||
|
|
|
@ -40,6 +40,8 @@ void CMonitor::onConnect(bool noRule) {
|
||||||
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
|
hyprListener_monitorCommit.initCallback(&output->events.commit, &Events::listener_monitorCommit, this);
|
||||||
hyprListener_monitorBind.initCallback(&output->events.bind, &Events::listener_monitorBind, 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) {
|
if (m_bEnabled) {
|
||||||
wlr_output_enable(output, 1);
|
wlr_output_enable(output, 1);
|
||||||
wlr_output_commit(output);
|
wlr_output_commit(output);
|
||||||
|
|
|
@ -81,6 +81,13 @@ class CMonitor {
|
||||||
|
|
||||||
CRegion lastFrameDamage; // stores last frame damage
|
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.
|
// for the special workspace. 0 means not open.
|
||||||
int specialWorkspaceID = 0;
|
int specialWorkspaceID = 0;
|
||||||
|
|
||||||
|
|
|
@ -245,6 +245,15 @@ void Events::listener_commitSubsurface(void* owner, void* data) {
|
||||||
|
|
||||||
if (pNode->pSurface && pNode->pSurface->exists())
|
if (pNode->pSurface && pNode->pSurface->exists())
|
||||||
g_pHyprRenderer->damageSurface(pNode->pSurface->wlr(), lx, ly, SCALE);
|
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) {
|
void Events::listener_destroySubsurface(void* owner, void* data) {
|
||||||
|
|
|
@ -393,3 +393,14 @@ struct SSwitchDevice {
|
||||||
return pWlrDevice == other.pWlrDevice;
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
|
@ -105,6 +105,7 @@ extern "C" {
|
||||||
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
|
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
|
||||||
#include <wlr/types/wlr_idle_notify_v1.h>
|
#include <wlr/types/wlr_idle_notify_v1.h>
|
||||||
#include <wlr/types/wlr_cursor_shape_v1.h>
|
#include <wlr/types/wlr_cursor_shape_v1.h>
|
||||||
|
#include <wlr/types/wlr_tearing_control_v1.h>
|
||||||
|
|
||||||
#include <libdrm/drm_fourcc.h>
|
#include <libdrm/drm_fourcc.h>
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
|
||||||
if (*PZOOMFACTOR != 1.f)
|
if (*PZOOMFACTOR != 1.f)
|
||||||
g_pHyprRenderer->damageMonitor(PMONITOR);
|
g_pHyprRenderer->damageMonitor(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);
|
g_pCompositor->scheduleFrameForMonitor(PMONITOR);
|
||||||
|
|
||||||
CWindow* forcedFocus = m_pForcedFocus;
|
CWindow* forcedFocus = m_pForcedFocus;
|
||||||
|
|
|
@ -3,6 +3,13 @@
|
||||||
#include "linux-dmabuf-unstable-v1-protocol.h"
|
#include "linux-dmabuf-unstable-v1-protocol.h"
|
||||||
#include "../helpers/Region.hpp"
|
#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) {
|
void renderSurface(struct wlr_surface* surface, int x, int y, void* data) {
|
||||||
const auto TEXTURE = wlr_surface_get_texture(surface);
|
const auto TEXTURE = wlr_surface_get_texture(surface);
|
||||||
const auto RDATA = (SRenderData*)data;
|
const auto RDATA = (SRenderData*)data;
|
||||||
|
@ -702,51 +709,12 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
|
||||||
if (!wlr_output_is_direct_scanout_allowed(pMonitor->output))
|
if (!wlr_output_is_direct_scanout_allowed(pMonitor->output))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto PWORKSPACE = g_pCompositor->getWorkspaceByID(pMonitor->activeWorkspace);
|
const auto PCANDIDATE = pMonitor->solitaryClient;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!PCANDIDATE)
|
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;
|
return false;
|
||||||
|
|
||||||
if (PCANDIDATE->m_vRealSize.vec() != pMonitor->vecSize || PCANDIDATE->m_vRealPosition.vec() != pMonitor->vecPosition || PCANDIDATE->m_vRealPosition.isBeingAnimated() ||
|
const auto PSURFACE = g_pXWaylandManager->getWindowSurface(PCANDIDATE);
|
||||||
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();
|
|
||||||
|
|
||||||
if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
|
if (!PSURFACE || PSURFACE->current.scale != pMonitor->output->scale || PSURFACE->current.transform != pMonitor->output->transform)
|
||||||
return false;
|
return false;
|
||||||
|
@ -754,9 +722,8 @@ bool CHyprRenderer::attemptDirectScanout(CMonitor* pMonitor) {
|
||||||
// finally, we should be GTG.
|
// finally, we should be GTG.
|
||||||
wlr_output_attach_buffer(pMonitor->output, &PSURFACE->buffer->base);
|
wlr_output_attach_buffer(pMonitor->output, &PSURFACE->buffer->base);
|
||||||
|
|
||||||
if (!wlr_output_test(pMonitor->output)) {
|
if (!wlr_output_test(pMonitor->output))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
timespec now;
|
timespec now;
|
||||||
clock_gettime(CLOCK_MONOTONIC, &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 PRENDERTEX = &g_pConfigManager->getConfigValuePtr("misc:disable_hyprland_logo")->intValue;
|
||||||
static auto* const PBACKGROUNDCOLOR = &g_pConfigManager->getConfigValuePtr("misc:background_color")->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 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
|
static int damageBlinkCleanup = 0; // because double-buffered
|
||||||
|
|
||||||
|
@ -876,8 +844,38 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direct scanout first
|
// tearing and DS first
|
||||||
if (!*PNODIRECTSCANOUT) {
|
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)) {
|
if (attemptDirectScanout(pMonitor)) {
|
||||||
return;
|
return;
|
||||||
} else if (m_pLastScanout) {
|
} else if (m_pLastScanout) {
|
||||||
|
@ -1061,6 +1059,8 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
||||||
|
|
||||||
EMIT_HOOK_EVENT("render", RENDER_POST);
|
EMIT_HOOK_EVENT("render", RENDER_POST);
|
||||||
|
|
||||||
|
pMonitor->output->pending.tearing_page_flip = shouldTear;
|
||||||
|
|
||||||
if (!wlr_output_commit(pMonitor->output)) {
|
if (!wlr_output_commit(pMonitor->output)) {
|
||||||
if (UNLOCK_SC)
|
if (UNLOCK_SC)
|
||||||
wlr_output_lock_software_cursors(pMonitor->output, false);
|
wlr_output_lock_software_cursors(pMonitor->output, false);
|
||||||
|
@ -1068,6 +1068,9 @@ void CHyprRenderer::renderMonitor(CMonitor* pMonitor) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldTear)
|
||||||
|
pMonitor->ignoreNextFlipEvent = true;
|
||||||
|
|
||||||
wlr_damage_ring_rotate(&pMonitor->damage);
|
wlr_damage_ring_rotate(&pMonitor->damage);
|
||||||
|
|
||||||
if (UNLOCK_SC)
|
if (UNLOCK_SC)
|
||||||
|
@ -1986,3 +1989,47 @@ bool CHyprRenderer::canSkipBackBufferClear(CMonitor* pMonitor) {
|
||||||
|
|
||||||
return false;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -33,6 +33,8 @@ struct SSessionLockSurface;
|
||||||
|
|
||||||
class CHyprRenderer {
|
class CHyprRenderer {
|
||||||
public:
|
public:
|
||||||
|
CHyprRenderer();
|
||||||
|
|
||||||
void renderMonitor(CMonitor* pMonitor);
|
void renderMonitor(CMonitor* pMonitor);
|
||||||
void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
|
void outputMgrApplyTest(wlr_output_configuration_v1*, bool);
|
||||||
void arrangeLayersForMonitor(const int&);
|
void arrangeLayersForMonitor(const int&);
|
||||||
|
@ -53,6 +55,7 @@ class CHyprRenderer {
|
||||||
void renderLockscreen(CMonitor* pMonitor, timespec* now);
|
void renderLockscreen(CMonitor* pMonitor, timespec* now);
|
||||||
void setOccludedForBackLayers(CRegion& region, CWorkspace* pWorkspace);
|
void setOccludedForBackLayers(CRegion& region, CWorkspace* pWorkspace);
|
||||||
bool canSkipBackBufferClear(CMonitor* pMonitor);
|
bool canSkipBackBufferClear(CMonitor* pMonitor);
|
||||||
|
void recheckSolitaryForMonitor(CMonitor* pMonitor);
|
||||||
|
|
||||||
bool m_bWindowRequestedCursorHide = false;
|
bool m_bWindowRequestedCursorHide = false;
|
||||||
bool m_bBlockSurfaceFeedback = false;
|
bool m_bBlockSurfaceFeedback = false;
|
||||||
|
@ -61,6 +64,7 @@ class CHyprRenderer {
|
||||||
CMonitor* m_pMostHzMonitor = nullptr;
|
CMonitor* m_pMostHzMonitor = nullptr;
|
||||||
bool m_bDirectScanoutBlocked = false;
|
bool m_bDirectScanoutBlocked = false;
|
||||||
bool m_bSoftwareCursorsLocked = false;
|
bool m_bSoftwareCursorsLocked = false;
|
||||||
|
bool m_bTearingEnvSatisfied = false;
|
||||||
|
|
||||||
DAMAGETRACKINGMODES
|
DAMAGETRACKINGMODES
|
||||||
damageTrackingModeFromStr(const std::string&);
|
damageTrackingModeFromStr(const std::string&);
|
||||||
|
@ -73,6 +77,8 @@ class CHyprRenderer {
|
||||||
float m_fCrashingDistort = 0.5f;
|
float m_fCrashingDistort = 0.5f;
|
||||||
wl_event_source* m_pCrashingLoop = nullptr;
|
wl_event_source* m_pCrashingLoop = nullptr;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<STearingController>> m_vTearingControllers;
|
||||||
|
|
||||||
CTimer m_tRenderTimer;
|
CTimer m_tRenderTimer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue