mirror of
https://github.com/hyprwm/Hyprland.git
synced 2024-11-29 12:31:58 +03:00
renderer: Tearing implementation (#3441)
This commit is contained in:
parent
1e513e25d5
commit
88b63a00b6
@ -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)
|
||||
|
@ -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'],
|
||||
|
@ -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) {
|
||||
|
@ -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 = "";
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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";
|
||||
}
|
||||
|
@ -174,4 +174,7 @@ namespace Events {
|
||||
|
||||
// Cursor shape
|
||||
LISTENER(setCursorShape);
|
||||
|
||||
// Tearing hints
|
||||
LISTENER(newTearingHint);
|
||||
};
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
CTimer m_tRenderTimer;
|
||||
std::vector<std::unique_ptr<STearingController>> m_vTearingControllers;
|
||||
|
||||
CTimer m_tRenderTimer;
|
||||
|
||||
private:
|
||||
void arrangeLayerArray(CMonitor*, const std::vector<std::unique_ptr<SLayerSurface>>&, bool, wlr_box*);
|
||||
|
Loading…
Reference in New Issue
Block a user