From 88b63a00b68350d6d001445357a2582ab5975f9c Mon Sep 17 00:00:00 2001 From: Vaxry <43317083+vaxerski@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:48:33 +0100 Subject: renderer: Tearing implementation (#3441) --- src/render/Renderer.cpp | 137 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 92 insertions(+), 45 deletions(-) (limited to 'src/render/Renderer.cpp') 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; +} -- cgit v1.2.3