2022-03-17 20:22:29 +01:00
# include "Renderer.hpp"
# include "../Compositor.hpp"
2024-06-19 16:20:06 +02:00
# include "../helpers/math/Math.hpp"
2023-11-12 14:14:05 +01:00
# include <algorithm>
2024-07-21 13:09:54 +02:00
# include <aquamarine/output/Output.hpp>
2024-08-06 14:52:19 +01:00
# include <filesystem>
2024-03-03 18:39:20 +00:00
# include "../config/ConfigValue.hpp"
2025-04-15 23:00:40 +00:00
# include "../config/ConfigManager.hpp"
2024-03-09 16:52:59 +00:00
# include "../managers/CursorManager.hpp"
2024-05-05 22:18:10 +01:00
# include "../managers/PointerManager.hpp"
2025-01-17 15:21:35 +00:00
# include "../managers/input/InputManager.hpp"
# include "../managers/HookSystemManager.hpp"
2025-08-28 11:20:29 +02:00
# include "../managers/animation/AnimationManager.hpp"
2025-01-17 15:21:35 +00:00
# include "../managers/LayoutManager.hpp"
2024-03-20 01:44:51 +00:00
# include "../desktop/Window.hpp"
2024-04-30 02:41:27 +01:00
# include "../desktop/LayerSurface.hpp"
2024-04-30 16:32:05 +01:00
# include "../protocols/SessionLock.hpp"
2024-05-09 21:47:21 +01:00
# include "../protocols/LayerShell.hpp"
2024-05-10 23:28:33 +01:00
# include "../protocols/XDGShell.hpp"
2024-05-10 02:27:54 +01:00
# include "../protocols/PresentationTime.hpp"
2024-05-11 17:13:20 +01:00
# include "../protocols/core/DataDevice.hpp"
2024-06-08 10:07:59 +02:00
# include "../protocols/core/Compositor.hpp"
2024-07-21 13:09:54 +02:00
# include "../protocols/DRMSyncobj.hpp"
# include "../protocols/LinuxDMABUF.hpp"
# include "../helpers/sync/SyncTimeline.hpp"
2025-01-17 15:21:35 +00:00
# include "../hyprerror/HyprError.hpp"
# include "../debug/HyprDebugOverlay.hpp"
# include "../debug/HyprNotificationOverlay.hpp"
2025-06-23 15:33:09 +03:00
# include "helpers/Monitor.hpp"
2024-12-22 17:12:09 +01:00
# include "pass/TexPassElement.hpp"
# include "pass/ClearPassElement.hpp"
# include "pass/RectPassElement.hpp"
2025-01-01 14:11:21 +01:00
# include "pass/RendererHintsPassElement.hpp"
2024-12-22 17:12:09 +01:00
# include "pass/SurfacePassElement.hpp"
2024-07-21 13:09:54 +02:00
# include "debug/Log.hpp"
2025-03-14 02:15:18 +03:00
# include "../protocols/ColorManagement.hpp"
# include "../protocols/types/ContentType.hpp"
2025-04-18 20:44:54 +01:00
# include "../helpers/MiscFunctions.hpp"
2025-07-14 13:13:54 +02:00
# include "render/OpenGL.hpp"
2022-03-17 20:22:29 +01:00
2024-09-21 00:33:48 +01:00
# include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils : : Utils ;
2025-01-30 12:30:12 +01:00
using namespace Hyprutils : : OS ;
2025-02-02 22:25:29 +03:00
using enum NContentType : : eContentType ;
2025-02-26 17:56:37 +03:00
using namespace NColorManagement ;
2024-09-21 00:33:48 +01:00
2023-11-25 17:45:08 +00:00
extern " C " {
# include <xf86drm.h>
}
2024-03-28 02:04:30 +00:00
static int cursorTicker ( void * data ) {
g_pHyprRenderer - > ensureCursorRenderingMode ( ) ;
2025-05-05 23:44:49 +02:00
wl_event_source_timer_update ( g_pHyprRenderer - > m_cursorTicker , 500 ) ;
2024-03-28 02:04:30 +00:00
return 0 ;
}
2023-11-25 17:45:08 +00:00
2024-03-28 02:04:30 +00:00
CHyprRenderer : : CHyprRenderer ( ) {
2025-04-22 15:23:29 +02:00
if ( g_pCompositor - > m_aqBackend - > hasSession ( ) ) {
2025-07-16 11:02:20 +02:00
size_t drmDevices = 0 ;
2025-04-22 15:23:29 +02:00
for ( auto const & dev : g_pCompositor - > m_aqBackend - > session - > sessionDevices ) {
2024-07-21 13:09:54 +02:00
const auto DRMV = drmGetVersion ( dev - > fd ) ;
if ( ! DRMV )
continue ;
2025-07-16 11:02:20 +02:00
drmDevices + + ;
2023-11-25 17:45:08 +00:00
std : : string name = std : : string { DRMV - > name , DRMV - > name_len } ;
2025-05-30 18:25:59 +05:00
std : : ranges : : transform ( name , name . begin ( ) , tolower ) ;
2023-11-25 17:45:08 +00:00
if ( name . contains ( " nvidia " ) )
2025-05-05 23:44:49 +02:00
m_nvidia = true ;
2025-08-24 09:57:37 +02:00
else if ( name . contains ( " i915 " ) )
m_intel = true ;
2025-08-24 22:32:13 +02:00
else if ( name . contains ( " softpipe " ) | | name . contains ( " Software Rasterizer " ) | | name . contains ( " llvmpipe " ) )
m_software = true ;
2023-11-25 17:45:08 +00:00
Debug : : log ( LOG , " DRM driver information: {} v{}.{}.{} from {} description {} " , name , DRMV - > version_major , DRMV - > version_minor , DRMV - > version_patchlevel ,
2023-11-25 17:56:38 +00:00
std : : string { DRMV - > date , DRMV - > date_len } , std : : string { DRMV - > desc , DRMV - > desc_len } ) ;
2023-11-25 17:45:08 +00:00
drmFreeVersion ( DRMV ) ;
}
2025-07-16 11:02:20 +02:00
m_mgpu = drmDevices > 1 ;
2023-11-25 17:45:08 +00:00
} else {
2024-07-21 13:09:54 +02:00
Debug : : log ( LOG , " Aq backend has no session, omitting full DRM node checks " ) ;
2023-11-25 17:45:08 +00:00
2025-08-24 22:32:13 +02:00
const auto DRMV = drmGetVersion ( g_pCompositor - > m_drm . fd ) ;
2023-11-25 17:45:08 +00:00
2024-03-15 07:28:14 -07:00
if ( DRMV ) {
std : : string name = std : : string { DRMV - > name , DRMV - > name_len } ;
2025-05-30 18:25:59 +05:00
std : : ranges : : transform ( name , name . begin ( ) , tolower ) ;
2023-11-25 17:45:08 +00:00
2024-03-15 07:28:14 -07:00
if ( name . contains ( " nvidia " ) )
2025-05-05 23:44:49 +02:00
m_nvidia = true ;
2025-08-24 09:57:37 +02:00
else if ( name . contains ( " i915 " ) )
m_intel = true ;
2025-08-24 22:32:13 +02:00
else if ( name . contains ( " softpipe " ) | | name . contains ( " Software Rasterizer " ) | | name . contains ( " llvmpipe " ) )
m_software = true ;
2023-11-25 17:45:08 +00:00
2024-03-15 07:28:14 -07:00
Debug : : log ( LOG , " Primary DRM driver information: {} v{}.{}.{} from {} description {} " , name , DRMV - > version_major , DRMV - > version_minor , DRMV - > version_patchlevel ,
std : : string { DRMV - > date , DRMV - > date_len } , std : : string { DRMV - > desc , DRMV - > desc_len } ) ;
} else {
Debug : : log ( LOG , " No primary DRM driver information found " ) ;
}
2023-11-25 17:45:08 +00:00
drmFreeVersion ( DRMV ) ;
}
2025-05-05 23:44:49 +02:00
if ( m_nvidia )
2023-11-25 17:45:08 +00:00
Debug : : log ( WARN , " NVIDIA detected, please remember to follow nvidia instructions on the wiki " ) ;
2024-03-28 02:04:30 +00:00
// cursor hiding stuff
2024-04-20 20:16:42 +01:00
static auto P = g_pHookSystem - > hookDynamic ( " keyPress " , [ & ] ( void * self , SCallbackInfo & info , std : : any param ) {
2025-05-05 23:44:49 +02:00
if ( m_cursorHiddenConditions . hiddenOnKeyboard )
2024-03-28 02:04:30 +00:00
return ;
2025-05-05 23:44:49 +02:00
m_cursorHiddenConditions . hiddenOnKeyboard = true ;
2024-03-28 02:04:30 +00:00
ensureCursorRenderingMode ( ) ;
} ) ;
2024-04-20 20:16:42 +01:00
static auto P2 = g_pHookSystem - > hookDynamic ( " mouseMove " , [ & ] ( void * self , SCallbackInfo & info , std : : any param ) {
2025-05-05 23:44:49 +02:00
if ( ! m_cursorHiddenConditions . hiddenOnKeyboard & & m_cursorHiddenConditions . hiddenOnTouch = = g_pInputManager - > m_lastInputTouch & & ! m_cursorHiddenConditions . hiddenOnTimeout )
2024-03-28 02:04:30 +00:00
return ;
2025-05-05 23:44:49 +02:00
m_cursorHiddenConditions . hiddenOnKeyboard = false ;
m_cursorHiddenConditions . hiddenOnTimeout = false ;
m_cursorHiddenConditions . hiddenOnTouch = g_pInputManager - > m_lastInputTouch ;
2024-03-28 02:04:30 +00:00
ensureCursorRenderingMode ( ) ;
} ) ;
2024-10-08 21:20:25 +01:00
static auto P3 = g_pHookSystem - > hookDynamic ( " focusedMon " , [ & ] ( void * self , SCallbackInfo & info , std : : any param ) {
g_pEventLoopManager - > doLater ( [ this ] ( ) {
if ( ! g_pHyprError - > active ( ) )
return ;
2025-04-22 15:23:29 +02:00
for ( auto & m : g_pCompositor - > m_monitors ) {
2025-04-30 23:45:20 +02:00
arrangeLayersForMonitor ( m - > m_id ) ;
2024-10-08 21:20:25 +01:00
}
} ) ;
} ) ;
2025-05-05 23:44:49 +02:00
m_cursorTicker = wl_event_loop_add_timer ( g_pCompositor - > m_wlEventLoop , cursorTicker , nullptr ) ;
wl_event_source_timer_update ( m_cursorTicker , 500 ) ;
2024-08-30 17:37:52 +02:00
2025-05-05 23:44:49 +02:00
m_renderUnfocusedTimer = makeShared < CEventLoopTimer > (
2024-08-30 17:37:52 +02:00
std : : nullopt ,
[ this ] ( SP < CEventLoopTimer > self , void * data ) {
static auto PFPS = CConfigValue < Hyprlang : : INT > ( " misc:render_unfocused_fps " ) ;
2025-05-05 23:44:49 +02:00
if ( m_renderUnfocused . empty ( ) )
2024-08-30 17:37:52 +02:00
return ;
bool dirty = false ;
2025-05-05 23:44:49 +02:00
for ( auto & w : m_renderUnfocused ) {
2024-08-30 17:37:52 +02:00
if ( ! w ) {
dirty = true ;
continue ;
}
2025-04-28 22:25:22 +02:00
if ( ! w - > m_wlSurface | | ! w - > m_wlSurface - > resource ( ) | | shouldRenderWindow ( w . lock ( ) ) )
2024-08-30 17:37:52 +02:00
continue ;
2025-04-28 22:25:22 +02:00
w - > m_wlSurface - > resource ( ) - > frame ( Time : : steadyNow ( ) ) ;
2025-07-10 13:09:19 +02:00
auto FEEDBACK = makeUnique < CQueuedPresentationData > ( w - > m_wlSurface - > resource ( ) ) ;
2025-04-22 15:23:29 +02:00
FEEDBACK - > attachMonitor ( g_pCompositor - > m_lastMonitor . lock ( ) ) ;
2024-08-30 17:37:52 +02:00
FEEDBACK - > discarded ( ) ;
2025-07-10 13:09:19 +02:00
PROTO : : presentation - > queueData ( std : : move ( FEEDBACK ) ) ;
2024-08-30 17:37:52 +02:00
}
if ( dirty )
2025-05-05 23:44:49 +02:00
std : : erase_if ( m_renderUnfocused , [ ] ( const auto & e ) { return ! e | | ! e - > m_windowData . renderUnfocused . valueOr ( false ) ; } ) ;
2024-08-30 17:37:52 +02:00
2025-05-05 23:44:49 +02:00
if ( ! m_renderUnfocused . empty ( ) )
m_renderUnfocusedTimer - > updateTimeout ( std : : chrono : : milliseconds ( 1000 / * PFPS ) ) ;
2024-08-30 17:37:52 +02:00
} ,
nullptr ) ;
2025-05-05 23:44:49 +02:00
g_pEventLoopManager - > addTimer ( m_renderUnfocusedTimer ) ;
2023-09-28 21:48:33 +01:00
}
2024-06-13 12:08:02 +02:00
CHyprRenderer : : ~ CHyprRenderer ( ) {
2025-05-05 23:44:49 +02:00
if ( m_cursorTicker )
wl_event_source_remove ( m_cursorTicker ) ;
2024-06-13 12:08:02 +02:00
}
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : shouldRenderWindow ( PHLWINDOW pWindow , PHLMONITOR pMonitor ) {
2024-05-05 22:18:10 +01:00
if ( ! pWindow - > visibleOnMonitor ( pMonitor ) )
2022-03-20 18:49:40 +01:00
return false ;
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_workspace & & ! pWindow - > m_fadingOut )
2023-04-12 13:05:57 +01:00
return false ;
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_workspace & & pWindow - > m_fadingOut )
2025-05-10 23:53:05 +01:00
return pWindow - > workspaceID ( ) = = pMonitor - > activeWorkspaceID ( ) | | pWindow - > workspaceID ( ) = = pMonitor - > activeSpecialWorkspaceID ( ) ;
2024-04-03 20:42:38 +01:00
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_pinned )
2022-09-10 13:11:02 +02:00
return true ;
2024-08-28 21:54:49 +02:00
// if the window is being moved to a workspace that is not invisible, and the alpha is > 0.F, render it.
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_monitorMovedFrom ! = - 1 & & pWindow - > m_movingToWorkspaceAlpha - > isBeingAnimated ( ) & & pWindow - > m_movingToWorkspaceAlpha - > value ( ) > 0.F & & pWindow - > m_workspace & &
! pWindow - > m_workspace - > isVisible ( ) )
2024-08-28 21:54:49 +02:00
return true ;
2025-04-28 22:25:22 +02:00
const auto PWINDOWWORKSPACE = pWindow - > m_workspace ;
2025-04-25 02:37:12 +02:00
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_monitor = = pMonitor ) {
if ( PWINDOWWORKSPACE - > m_renderOffset - > isBeingAnimated ( ) | | PWINDOWWORKSPACE - > m_alpha - > isBeingAnimated ( ) | | PWINDOWWORKSPACE - > m_forceRendering )
2022-08-18 12:42:21 +02:00
return true ;
2024-04-01 08:16:18 -07:00
// if hidden behind fullscreen
2025-04-28 22:25:22 +02:00
if ( PWINDOWWORKSPACE - > m_hasFullscreenWindow & & ! pWindow - > isFullscreen ( ) & & ( ! pWindow - > m_isFloating | | ! pWindow - > m_createdOverFullscreen ) & & pWindow - > m_alpha - > value ( ) = = 0 )
2024-04-01 08:16:18 -07:00
return false ;
2025-04-25 02:37:12 +02:00
if ( ! PWINDOWWORKSPACE - > m_renderOffset - > isBeingAnimated ( ) & & ! PWINDOWWORKSPACE - > m_alpha - > isBeingAnimated ( ) & & ! PWINDOWWORKSPACE - > isVisible ( ) )
2024-04-01 08:16:18 -07:00
return false ;
2022-07-28 16:33:45 +02:00
}
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_monitor = = pMonitor )
2022-03-20 18:49:40 +01:00
return true ;
2025-04-28 22:25:22 +02:00
if ( ( ! pWindow - > m_workspace | | ! pWindow - > m_workspace - > isVisible ( ) ) & & pWindow - > m_monitor ! = pMonitor )
2024-03-30 18:14:26 -07:00
return false ;
2022-08-18 12:41:10 +02:00
// if not, check if it maybe is active on a different monitor.
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_workspace & & pWindow - > m_workspace - > isVisible ( ) & & pWindow - > m_isFloating /* tiled windows can't be multi-ws */ )
2024-07-31 17:55:52 +00:00
return ! pWindow - > isFullscreen ( ) ; // Do not draw fullscreen windows on other monitors
2022-03-20 18:49:40 +01:00
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_activeSpecialWorkspace = = pWindow - > m_workspace )
2022-05-31 14:01:00 +02:00
return true ;
2024-03-30 18:14:26 -07:00
// if window is tiled and it's flying in, don't render on other mons (for slide)
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_isFloating & & pWindow - > m_realPosition - > isBeingAnimated ( ) & & pWindow - > m_animatingIn & & pWindow - > m_monitor ! = pMonitor )
2024-03-30 18:14:26 -07:00
return false ;
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_realPosition - > isBeingAnimated ( ) ) {
2025-04-25 02:37:12 +02:00
if ( PWINDOWWORKSPACE & & ! PWINDOWWORKSPACE - > m_isSpecialWorkspace & & PWINDOWWORKSPACE - > m_renderOffset - > isBeingAnimated ( ) )
2024-03-23 15:14:50 -07:00
return false ;
2024-03-16 07:49:34 -07:00
// render window if window and monitor intersect
// (when moving out of or through a monitor)
2024-03-30 18:14:26 -07:00
CBox windowBox = pWindow - > getFullWindowBoundingBox ( ) ;
2025-04-25 02:37:12 +02:00
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_renderOffset - > isBeingAnimated ( ) )
windowBox . translate ( PWINDOWWORKSPACE - > m_renderOffset - > value ( ) ) ;
2025-04-28 22:25:22 +02:00
windowBox . translate ( pWindow - > m_floatingOffset ) ;
2024-03-30 18:14:26 -07:00
2025-04-30 23:45:20 +02:00
const CBox monitorBox = { pMonitor - > m_position , pMonitor - > m_size } ;
2025-04-28 22:25:22 +02:00
if ( ! windowBox . intersection ( monitorBox ) . empty ( ) & & ( pWindow - > workspaceID ( ) = = pMonitor - > activeWorkspaceID ( ) | | pWindow - > m_monitorMovedFrom ! = - 1 ) )
2024-03-16 07:49:34 -07:00
return true ;
}
2022-03-20 18:49:40 +01:00
return false ;
}
2024-04-27 12:43:12 +01:00
bool CHyprRenderer : : shouldRenderWindow ( PHLWINDOW pWindow ) {
2022-05-31 22:16:13 +02:00
2024-04-27 12:43:12 +01:00
if ( ! validMapped ( pWindow ) )
2022-05-31 22:16:13 +02:00
return false ;
2025-04-28 22:25:22 +02:00
const auto PWORKSPACE = pWindow - > m_workspace ;
2022-05-31 22:16:13 +02:00
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_workspace )
2023-04-12 13:05:57 +01:00
return false ;
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_pinned | | PWORKSPACE - > m_forceRendering )
2022-09-10 13:11:02 +02:00
return true ;
2024-11-22 16:01:02 +00:00
if ( PWORKSPACE & & PWORKSPACE - > isVisible ( ) )
2022-05-31 22:16:13 +02:00
return true ;
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_monitors ) {
2025-04-25 02:37:12 +02:00
if ( PWORKSPACE & & PWORKSPACE - > m_monitor = = m & & ( PWORKSPACE - > m_renderOffset - > isBeingAnimated ( ) | | PWORKSPACE - > m_alpha - > isBeingAnimated ( ) ) )
2022-05-31 22:16:13 +02:00
return true ;
2025-04-30 23:45:20 +02:00
if ( m - > m_activeSpecialWorkspace & & pWindow - > onSpecialWorkspace ( ) )
2022-05-31 22:16:13 +02:00
return true ;
}
return false ;
}
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderWorkspaceWindowsFullscreen ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , const Time : : steady_tp & time ) {
2024-04-27 12:43:12 +01:00
PHLWINDOW pWorkspaceWindow = nullptr ;
2022-03-30 20:16:23 +02:00
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE_WINDOWS ) ;
2022-09-19 17:26:11 +01:00
// loop over the tiled windows that are fading out
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2022-09-19 17:26:11 +01:00
continue ;
2025-04-28 22:25:22 +02:00
if ( w - > m_alpha - > value ( ) = = 0.f )
2022-09-19 17:26:11 +01:00
continue ;
2025-04-28 22:25:22 +02:00
if ( w - > isFullscreen ( ) | | w - > m_isFloating )
2022-09-19 17:26:11 +01:00
continue ;
2025-04-25 02:37:12 +02:00
if ( pWorkspace - > m_isSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-24 21:18:50 +00:00
continue ;
2024-04-27 12:43:12 +01:00
renderWindow ( w , pMonitor , time , true , RENDER_PASS_ALL ) ;
2022-09-19 17:26:11 +01:00
}
// and floating ones too
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2022-09-19 17:26:11 +01:00
continue ;
2025-04-28 22:25:22 +02:00
if ( w - > m_alpha - > value ( ) = = 0.f )
2022-09-19 17:26:11 +01:00
continue ;
2025-04-28 22:25:22 +02:00
if ( w - > isFullscreen ( ) | | ! w - > m_isFloating )
2022-09-19 17:26:11 +01:00
continue ;
2025-04-28 22:25:22 +02:00
if ( w - > m_monitor = = pWorkspace - > m_monitor & & pWorkspace - > m_isSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-24 21:18:50 +00:00
continue ;
2025-04-28 22:25:22 +02:00
if ( pWorkspace - > m_isSpecialWorkspace & & w - > m_monitor ! = pWorkspace - > m_monitor )
2023-11-24 21:18:50 +00:00
continue ; // special on another are rendered as a part of the base pass
2024-04-27 12:43:12 +01:00
renderWindow ( w , pMonitor , time , true , RENDER_PASS_ALL ) ;
2022-09-19 17:26:11 +01:00
}
2023-11-24 21:18:50 +00:00
// TODO: this pass sucks
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
const auto PWORKSPACE = w - > m_workspace ;
2022-07-28 15:56:55 +02:00
2025-04-28 22:25:22 +02:00
if ( w - > m_workspace ! = pWorkspace | | ! w - > isFullscreen ( ) ) {
2025-04-25 02:37:12 +02:00
if ( ! ( PWORKSPACE & & ( PWORKSPACE - > m_renderOffset - > isBeingAnimated ( ) | | PWORKSPACE - > m_alpha - > isBeingAnimated ( ) | | PWORKSPACE - > m_forceRendering ) ) )
2022-07-28 15:56:55 +02:00
continue ;
2022-08-17 12:12:16 +02:00
2025-04-28 22:25:22 +02:00
if ( w - > m_monitor ! = pMonitor )
2022-08-17 12:12:16 +02:00
continue ;
2022-07-28 15:56:55 +02:00
}
2022-03-21 19:18:33 +01:00
2024-07-31 17:55:52 +00:00
if ( ! w - > isFullscreen ( ) )
2022-07-28 16:33:45 +02:00
continue ;
2025-04-28 22:25:22 +02:00
if ( w - > m_monitor = = pWorkspace - > m_monitor & & pWorkspace - > m_isSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2024-03-04 15:29:45 -08:00
continue ;
2024-04-27 12:43:12 +01:00
if ( shouldRenderWindow ( w , pMonitor ) )
2025-04-25 02:37:12 +02:00
renderWindow ( w , pMonitor , time , pWorkspace - > m_fullscreenMode ! = FSMODE_FULLSCREEN , RENDER_PASS_ALL ) ;
2022-03-30 20:16:23 +02:00
2025-04-28 22:25:22 +02:00
if ( w - > m_workspace ! = pWorkspace )
2024-01-09 20:42:07 +01:00
continue ;
2024-04-27 12:43:12 +01:00
pWorkspaceWindow = w ;
2022-03-30 20:16:23 +02:00
}
2022-10-11 20:29:37 +01:00
if ( ! pWorkspaceWindow ) {
// ?? happens sometimes...
2025-04-25 02:37:12 +02:00
pWorkspace - > m_hasFullscreenWindow = false ;
2022-10-11 20:29:37 +01:00
return ; // this will produce one blank frame. Oh well.
}
2022-09-19 17:26:11 +01:00
// then render windows over fullscreen.
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-05-02 00:16:17 +01:00
if ( w - > workspaceID ( ) ! = pWorkspaceWindow - > workspaceID ( ) | | ! w - > m_isFloating | | ( ! w - > m_createdOverFullscreen & & ! w - > m_pinned ) | | ( ! w - > m_isMapped & & ! w - > m_fadingOut ) | |
2025-01-27 13:41:38 +00:00
w - > isFullscreen ( ) )
2022-03-30 20:16:23 +02:00
continue ;
2025-04-28 22:25:22 +02:00
if ( w - > m_monitor = = pWorkspace - > m_monitor & & pWorkspace - > m_isSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-24 21:18:50 +00:00
continue ;
2025-04-28 22:25:22 +02:00
if ( pWorkspace - > m_isSpecialWorkspace & & w - > m_monitor ! = pWorkspace - > m_monitor )
2023-11-24 21:18:50 +00:00
continue ; // special on another are rendered as a part of the base pass
2024-04-27 12:43:12 +01:00
renderWindow ( w , pMonitor , time , true , RENDER_PASS_ALL ) ;
2022-05-31 14:20:41 +02:00
}
2023-09-04 15:07:56 +02:00
}
2022-05-31 14:20:41 +02:00
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderWorkspaceWindows ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , const Time : : steady_tp & time ) {
2024-04-27 12:43:12 +01:00
PHLWINDOW lastWindow ;
2022-05-31 14:20:41 +02:00
2023-09-04 15:07:56 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE_WINDOWS ) ;
2022-05-31 14:20:41 +02:00
2025-04-01 00:25:09 +01:00
std : : vector < PHLWINDOWREF > windows , tiledFadingOut ;
2025-04-22 15:23:29 +02:00
windows . reserve ( g_pCompositor - > m_windows . size ( ) ) ;
2024-10-31 00:20:32 +01:00
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
if ( w - > isHidden ( ) | | ( ! w - > m_isMapped & & ! w - > m_fadingOut ) )
2023-09-04 15:07:56 +02:00
continue ;
2022-05-31 14:20:41 +02:00
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2023-09-04 15:07:56 +02:00
continue ;
2024-12-22 17:12:09 +01:00
windows . emplace_back ( w ) ;
2024-10-31 00:20:32 +01:00
}
// Non-floating main
for ( auto & w : windows ) {
2025-04-28 22:25:22 +02:00
if ( w - > m_isFloating )
2024-10-31 00:20:32 +01:00
continue ; // floating are in the second pass
2025-02-06 17:45:25 +00:00
// some things may force us to ignore the special/not special disparity
2025-04-28 22:25:22 +02:00
const bool IGNORE_SPECIAL_CHECK = w - > m_monitorMovedFrom ! = - 1 & & ( w - > m_workspace & & ! w - > m_workspace - > isVisible ( ) ) ;
2025-02-06 17:45:25 +00:00
2025-04-25 02:37:12 +02:00
if ( ! IGNORE_SPECIAL_CHECK & & pWorkspace - > m_isSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-22 20:05:50 +00:00
continue ;
2023-09-04 15:07:56 +02:00
// render active window after all others of this pass
2025-04-22 15:23:29 +02:00
if ( w = = g_pCompositor - > m_lastWindow ) {
2024-10-31 00:20:32 +01:00
lastWindow = w . lock ( ) ;
2023-09-04 15:07:56 +02:00
continue ;
}
2025-04-01 00:25:09 +01:00
// render tiled fading out after others
2025-04-28 22:25:22 +02:00
if ( w - > m_fadingOut ) {
2025-04-01 00:25:09 +01:00
tiledFadingOut . emplace_back ( w ) ;
w . reset ( ) ;
continue ;
}
2023-09-04 15:07:56 +02:00
// render the bad boy
2024-10-31 00:20:32 +01:00
renderWindow ( w . lock ( ) , pMonitor , time , true , RENDER_PASS_MAIN ) ;
2025-02-06 17:45:25 +00:00
w . reset ( ) ;
2022-05-29 15:44:30 +02:00
}
2023-09-04 15:07:56 +02:00
if ( lastWindow )
renderWindow ( lastWindow , pMonitor , time , true , RENDER_PASS_MAIN ) ;
2025-02-06 17:45:25 +00:00
lastWindow . reset ( ) ;
2025-04-01 00:25:09 +01:00
// render tiled windows that are fading out after other tiled to not hide them behind
for ( auto & w : tiledFadingOut ) {
renderWindow ( w . lock ( ) , pMonitor , time , true , RENDER_PASS_MAIN ) ;
}
2023-09-04 15:07:56 +02:00
// Non-floating popup
2024-10-31 00:20:32 +01:00
for ( auto & w : windows ) {
if ( ! w )
2023-09-04 15:07:56 +02:00
continue ;
2025-04-28 22:25:22 +02:00
if ( w - > m_isFloating )
2023-09-04 15:07:56 +02:00
continue ; // floating are in the second pass
2025-02-06 17:45:25 +00:00
// some things may force us to ignore the special/not special disparity
2025-04-28 22:25:22 +02:00
const bool IGNORE_SPECIAL_CHECK = w - > m_monitorMovedFrom ! = - 1 & & ( w - > m_workspace & & ! w - > m_workspace - > isVisible ( ) ) ;
2025-02-06 17:45:25 +00:00
2025-04-25 02:37:12 +02:00
if ( ! IGNORE_SPECIAL_CHECK & & pWorkspace - > m_isSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-22 20:05:50 +00:00
continue ;
2023-09-04 15:07:56 +02:00
// render the bad boy
2024-10-31 00:20:32 +01:00
renderWindow ( w . lock ( ) , pMonitor , time , true , RENDER_PASS_POPUP ) ;
w . reset ( ) ;
2022-04-25 21:49:45 +02:00
}
2023-09-04 15:07:56 +02:00
// floating on top
2024-10-31 00:20:32 +01:00
for ( auto & w : windows ) {
if ( ! w )
2023-09-04 15:07:56 +02:00
continue ;
2025-04-28 22:25:22 +02:00
if ( ! w - > m_isFloating | | w - > m_pinned )
2023-09-04 15:07:56 +02:00
continue ;
2025-02-06 17:45:25 +00:00
// some things may force us to ignore the special/not special disparity
2025-04-28 22:25:22 +02:00
const bool IGNORE_SPECIAL_CHECK = w - > m_monitorMovedFrom ! = - 1 & & ( w - > m_workspace & & ! w - > m_workspace - > isVisible ( ) ) ;
2025-02-06 17:45:25 +00:00
2025-04-25 02:37:12 +02:00
if ( ! IGNORE_SPECIAL_CHECK & & pWorkspace - > m_isSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-18 19:53:45 +00:00
continue ;
2025-04-28 22:25:22 +02:00
if ( pWorkspace - > m_isSpecialWorkspace & & w - > m_monitor ! = pWorkspace - > m_monitor )
2023-11-24 21:18:50 +00:00
continue ; // special on another are rendered as a part of the base pass
2023-09-04 15:07:56 +02:00
// render the bad boy
2024-10-31 00:20:32 +01:00
renderWindow ( w . lock ( ) , pMonitor , time , true , RENDER_PASS_ALL ) ;
2023-09-02 20:32:10 +02:00
}
2022-03-21 19:18:33 +01:00
}
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderWindow ( PHLWINDOW pWindow , PHLMONITOR pMonitor , const Time : : steady_tp & time , bool decorate , eRenderPassMode mode , bool ignorePosition , bool standalone ) {
2025-01-12 09:10:36 -08:00
if ( pWindow - > isHidden ( ) & & ! standalone )
2022-04-12 16:44:18 +02:00
return ;
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_fadingOut ) {
if ( pMonitor = = pWindow - > m_monitor ) // TODO: fix this
2024-12-22 17:12:09 +01:00
renderSnapshot ( pWindow ) ;
2022-04-05 20:49:15 +02:00
return ;
}
2022-09-25 20:07:48 +02:00
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_isMapped )
2024-03-14 18:25:28 +00:00
return ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderWindow " ) ;
2025-04-28 22:25:22 +02:00
const auto PWORKSPACE = pWindow - > m_workspace ;
const auto REALPOS = pWindow - > m_realPosition - > value ( ) + ( pWindow - > m_pinned ? Vector2D { } : PWORKSPACE - > m_renderOffset - > value ( ) ) ;
2024-12-22 17:12:09 +01:00
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
2022-06-21 22:54:41 +02:00
2024-12-22 17:12:09 +01:00
CSurfacePassElement : : SRenderData renderdata = { pMonitor , time } ;
2025-04-28 22:25:22 +02:00
CBox textureBox = { REALPOS . x , REALPOS . y , std : : max ( pWindow - > m_realSize - > value ( ) . x , 5.0 ) , std : : max ( pWindow - > m_realSize - > value ( ) . y , 5.0 ) } ;
2023-11-04 17:03:05 +00:00
2024-12-22 17:12:09 +01:00
renderdata . pos . x = textureBox . x ;
renderdata . pos . y = textureBox . y ;
renderdata . w = textureBox . w ;
renderdata . h = textureBox . h ;
2023-11-04 17:03:05 +00:00
2022-11-06 17:52:09 +00:00
if ( ignorePosition ) {
2025-04-30 23:45:20 +02:00
renderdata . pos . x = pMonitor - > m_position . x ;
renderdata . pos . y = pMonitor - > m_position . y ;
2025-02-18 15:10:40 +00:00
} else {
const bool ANR = pWindow - > isNotResponding ( ) ;
if ( ANR & & pWindow - > m_notRespondingTint - > goal ( ) ! = 0.2F )
* pWindow - > m_notRespondingTint = 0.2F ;
else if ( ! ANR & & pWindow - > m_notRespondingTint - > goal ( ) ! = 0.F )
* pWindow - > m_notRespondingTint = 0.F ;
2022-11-06 17:52:09 +00:00
}
2025-01-12 09:10:36 -08:00
if ( standalone )
2022-12-05 17:05:15 +00:00
decorate = false ;
2024-08-28 21:54:49 +02:00
// whether to use m_fMovingToWorkspaceAlpha, only if fading out into an invisible ws
2025-04-28 22:25:22 +02:00
const bool USE_WORKSPACE_FADE_ALPHA = pWindow - > m_monitorMovedFrom ! = - 1 & & ( ! PWORKSPACE | | ! PWORKSPACE - > isVisible ( ) ) ;
renderdata . surface = pWindow - > m_wlSurface - > resource ( ) ;
renderdata . dontRound = pWindow - > isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) | | pWindow - > m_windowData . noRounding . valueOrDefault ( ) ;
renderdata . fadeAlpha = pWindow - > m_alpha - > value ( ) * ( pWindow - > m_pinned | | USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE - > m_alpha - > value ( ) ) *
( USE_WORKSPACE_FADE_ALPHA ? pWindow - > m_movingToWorkspaceAlpha - > value ( ) : 1.F ) * pWindow - > m_movingFromWorkspaceAlpha - > value ( ) ;
renderdata . alpha = pWindow - > m_activeInactiveAlpha - > value ( ) ;
renderdata . decorate = decorate & & ! pWindow - > m_X11DoesntWantBorders & & ! pWindow - > isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) ;
2025-04-30 23:45:20 +02:00
renderdata . rounding = standalone | | renderdata . dontRound ? 0 : pWindow - > rounding ( ) * pMonitor - > m_scale ;
2025-01-12 09:10:36 -08:00
renderdata . roundingPower = standalone | | renderdata . dontRound ? 2.0f : pWindow - > roundingPower ( ) ;
2025-05-10 18:31:26 +01:00
renderdata . blur = ! standalone & & shouldBlur ( pWindow ) ;
2025-01-05 12:38:49 -06:00
renderdata . pWindow = pWindow ;
2022-03-21 19:18:33 +01:00
2025-01-12 09:10:36 -08:00
if ( standalone ) {
2022-12-16 17:17:31 +00:00
renderdata . alpha = 1.f ;
2023-01-05 19:25:45 +01:00
renderdata . fadeAlpha = 1.f ;
2022-12-05 18:00:57 +00:00
}
2022-07-28 12:07:41 +02:00
// apply opaque
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_windowData . opaque . valueOrDefault ( ) )
2022-07-28 12:07:41 +02:00
renderdata . alpha = 1.f ;
2024-12-22 17:12:09 +01:00
renderdata . pWindow = pWindow ;
2022-03-21 19:18:33 +01:00
2025-07-07 11:06:42 -05:00
// for plugins
g_pHyprOpenGL - > m_renderData . currentWindow = pWindow ;
2023-05-26 13:07:45 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE_WINDOW ) ;
2025-05-07 19:02:07 +02:00
const auto fullAlpha = renderdata . alpha * renderdata . fadeAlpha ;
2025-04-28 22:25:22 +02:00
if ( * PDIMAROUND & & pWindow - > m_windowData . dimAround . valueOrDefault ( ) & & ! m_bRenderingSnapshot & & mode ! = RENDER_PASS_POPUP ) {
2025-05-05 23:44:49 +02:00
CBox monbox = { 0 , 0 , g_pHyprOpenGL - > m_renderData . pMonitor - > m_transformedSize . x , g_pHyprOpenGL - > m_renderData . pMonitor - > m_transformedSize . y } ;
2024-12-22 17:12:09 +01:00
CRectPassElement : : SRectData data ;
2025-05-07 19:02:07 +02:00
data . color = CHyprColor ( 0 , 0 , 0 , * PDIMAROUND * fullAlpha ) ;
2024-12-22 17:12:09 +01:00
data . box = monbox ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CRectPassElement > ( data ) ) ;
2022-12-28 15:39:17 +01:00
}
2025-04-28 22:25:22 +02:00
renderdata . pos . x + = pWindow - > m_floatingOffset . x ;
renderdata . pos . y + = pWindow - > m_floatingOffset . y ;
2022-12-16 17:17:31 +00:00
2023-11-16 20:20:41 +00:00
// if window is floating and we have a slide animation, clip it to its full bb
2025-04-28 22:25:22 +02:00
if ( ! ignorePosition & & pWindow - > m_isFloating & & ! pWindow - > isFullscreen ( ) & & PWORKSPACE - > m_renderOffset - > isBeingAnimated ( ) & & ! pWindow - > m_pinned ) {
2025-04-30 23:45:20 +02:00
CRegion rg =
pWindow - > getFullWindowBoundingBox ( ) . translate ( - pMonitor - > m_position + PWORKSPACE - > m_renderOffset - > value ( ) + pWindow - > m_floatingOffset ) . scale ( pMonitor - > m_scale ) ;
2024-12-22 17:12:09 +01:00
renderdata . clipBox = rg . getExtents ( ) ;
2023-11-18 17:00:24 +00:00
}
2023-11-16 20:20:41 +00:00
2022-06-28 15:45:38 +02:00
// render window decorations first, if not fullscreen full
2022-07-12 09:49:56 +02:00
if ( mode = = RENDER_PASS_ALL | | mode = = RENDER_PASS_MAIN ) {
2023-10-21 14:15:48 +01:00
2025-04-28 22:25:22 +02:00
const bool TRANSFORMERSPRESENT = ! pWindow - > m_transformers . empty ( ) ;
2023-10-21 14:15:48 +01:00
2023-10-21 19:25:44 +01:00
if ( TRANSFORMERSPRESENT ) {
2023-10-21 14:15:48 +01:00
g_pHyprOpenGL - > bindOffMain ( ) ;
2025-04-28 22:25:22 +02:00
for ( auto const & t : pWindow - > m_transformers ) {
2023-10-21 19:25:44 +01:00
t - > preWindowRender ( & renderdata ) ;
}
}
2024-04-13 23:16:26 +00:00
if ( renderdata . decorate ) {
2025-04-28 22:25:22 +02:00
for ( auto const & wd : pWindow - > m_windowDecorations ) {
2023-11-04 13:10:52 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_BOTTOM )
continue ;
2025-05-07 19:02:07 +02:00
wd - > draw ( pMonitor , fullAlpha ) ;
2023-11-04 13:10:52 +00:00
}
2025-04-28 22:25:22 +02:00
for ( auto const & wd : pWindow - > m_windowDecorations ) {
2023-11-04 13:10:52 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_UNDER )
continue ;
2025-05-07 19:02:07 +02:00
wd - > draw ( pMonitor , fullAlpha ) ;
2023-11-04 13:10:52 +00:00
}
}
2022-06-22 15:45:56 +02:00
2024-03-03 18:39:20 +00:00
static auto PXWLUSENN = CConfigValue < Hyprlang : : INT > ( " xwayland:use_nearest_neighbor " ) ;
2025-04-28 22:25:22 +02:00
if ( ( pWindow - > m_isX11 & & * PXWLUSENN ) | | pWindow - > m_windowData . nearestNeighbor . valueOrDefault ( ) )
2024-12-22 17:12:09 +01:00
renderdata . useNearestNeighbor = true ;
2023-06-11 21:33:50 +02:00
2025-05-10 18:31:26 +01:00
if ( pWindow - > m_wlSurface - > small ( ) & & ! pWindow - > m_wlSurface - > m_fillIgnoreSmall & & renderdata . blur ) {
2025-04-30 23:45:20 +02:00
CBox wb = { renderdata . pos . x - pMonitor - > m_position . x , renderdata . pos . y - pMonitor - > m_position . y , renderdata . w , renderdata . h } ;
wb . scale ( pMonitor - > m_scale ) . round ( ) ;
2024-12-22 17:12:09 +01:00
CRectPassElement : : SRectData data ;
data . color = CHyprColor ( 0 , 0 , 0 , 0 ) ;
data . box = wb ;
data . round = renderdata . dontRound ? 0 : renderdata . rounding - 1 ;
2024-12-30 20:00:34 +01:00
data . blur = true ;
2024-12-22 17:12:09 +01:00
data . blurA = renderdata . fadeAlpha ;
data . xray = g_pHyprOpenGL - > shouldUseNewBlurOptimizations ( nullptr , pWindow ) ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CRectPassElement > ( data ) ) ;
2023-10-25 22:20:58 +01:00
renderdata . blur = false ;
}
2024-06-17 12:42:32 +02:00
renderdata . surfaceCounter = 0 ;
2025-04-28 22:25:22 +02:00
pWindow - > m_wlSurface - > resource ( ) - > breadthfirst (
2024-12-22 17:12:09 +01:00
[ this , & renderdata , & pWindow ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
2025-05-03 16:02:49 +02:00
renderdata . texture = s - > m_current . texture ;
2024-12-22 17:12:09 +01:00
renderdata . surface = s ;
2025-04-28 22:25:22 +02:00
renderdata . mainSurface = s = = pWindow - > m_wlSurface - > resource ( ) ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CSurfacePassElement > ( renderdata ) ) ;
2024-12-22 17:12:09 +01:00
renderdata . surfaceCounter + + ;
} ,
nullptr ) ;
2022-07-12 09:49:56 +02:00
2024-12-22 22:07:08 +00:00
renderdata . useNearestNeighbor = false ;
2023-06-11 21:33:50 +02:00
2024-04-13 23:16:26 +00:00
if ( renderdata . decorate ) {
2025-04-28 22:25:22 +02:00
for ( auto const & wd : pWindow - > m_windowDecorations ) {
2023-12-11 16:32:00 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_OVER )
continue ;
2023-11-04 13:10:52 +00:00
2025-05-07 19:02:07 +02:00
wd - > draw ( pMonitor , fullAlpha ) ;
2023-12-11 16:32:00 +00:00
}
2023-11-04 13:10:52 +00:00
}
2023-10-21 14:15:48 +01:00
if ( TRANSFORMERSPRESENT ) {
2025-05-05 23:44:49 +02:00
CFramebuffer * last = g_pHyprOpenGL - > m_renderData . currentFB ;
2025-04-28 22:25:22 +02:00
for ( auto const & t : pWindow - > m_transformers ) {
2023-10-21 14:15:48 +01:00
last = t - > transform ( last ) ;
}
g_pHyprOpenGL - > bindBackOnMain ( ) ;
g_pHyprOpenGL - > renderOffToMain ( last ) ;
}
2022-06-22 15:45:56 +02:00
}
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . clipBox = CBox ( ) ;
2023-11-16 20:20:41 +00:00
2022-07-12 09:49:56 +02:00
if ( mode = = RENDER_PASS_ALL | | mode = = RENDER_PASS_POPUP ) {
2025-04-28 22:25:22 +02:00
if ( ! pWindow - > m_isX11 ) {
2025-05-04 23:39:00 +02:00
CBox geom = pWindow - > m_xdgSurface - > m_current . geometry ;
2022-08-28 10:14:43 +02:00
2024-12-22 17:12:09 +01:00
renderdata . pos - = geom . pos ( ) ;
2022-12-16 17:17:31 +00:00
renderdata . dontRound = true ; // don't round popups
renderdata . pMonitor = pMonitor ;
2022-07-15 19:07:06 +02:00
renderdata . squishOversized = false ; // don't squish popups
2023-12-25 18:04:00 +01:00
renderdata . popup = true ;
2023-10-24 21:28:55 +01:00
2024-03-25 16:08:55 +00:00
static CConfigValue PBLURIGNOREA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:popups_ignorealpha " ) ;
2025-08-03 13:44:50 +02:00
renderdata . blur = shouldBlur ( pWindow - > m_popupHead ) ;
2024-03-25 16:08:55 +00:00
if ( renderdata . blur ) {
2024-12-22 17:12:09 +01:00
renderdata . discardMode | = DISCARD_ALPHA ;
renderdata . discardOpacity = * PBLURIGNOREA ;
2024-03-25 16:08:55 +00:00
}
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_windowData . nearestNeighbor . valueOrDefault ( ) )
2024-12-22 17:12:09 +01:00
renderdata . useNearestNeighbor = true ;
2023-10-24 21:28:55 +01:00
2024-06-17 12:42:32 +02:00
renderdata . surfaceCounter = 0 ;
2025-04-28 22:25:22 +02:00
pWindow - > m_popupHead - > breadthfirst (
2025-01-26 12:54:32 +00:00
[ this , & renderdata ] ( WP < CPopup > popup , void * data ) {
2025-08-03 13:44:50 +02:00
if ( popup - > m_fadingOut ) {
renderSnapshot ( popup ) ;
return ;
}
2025-04-24 20:49:49 +02:00
if ( ! popup - > m_wlSurface | | ! popup - > m_wlSurface - > resource ( ) | | ! popup - > m_mapped )
2024-05-10 23:28:33 +01:00
return ;
2024-11-17 16:42:30 +00:00
const auto pos = popup - > coordsRelativeToParent ( ) ;
2024-12-22 17:12:09 +01:00
const Vector2D oldPos = renderdata . pos ;
renderdata . pos + = pos ;
2025-08-03 16:39:54 +02:00
renderdata . fadeAlpha = popup - > m_alpha - > value ( ) ;
2024-12-22 17:12:09 +01:00
2025-04-24 20:49:49 +02:00
popup - > m_wlSurface - > resource ( ) - > breadthfirst (
2024-12-22 17:12:09 +01:00
[ this , & renderdata ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
2025-05-03 16:02:49 +02:00
renderdata . texture = s - > m_current . texture ;
2024-12-22 17:12:09 +01:00
renderdata . surface = s ;
renderdata . mainSurface = false ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CSurfacePassElement > ( renderdata ) ) ;
2024-12-22 17:12:09 +01:00
renderdata . surfaceCounter + + ;
} ,
data ) ;
renderdata . pos = oldPos ;
2024-05-10 23:28:33 +01:00
} ,
& renderdata ) ;
2025-08-03 13:44:50 +02:00
renderdata . alpha = 1.F ;
2022-07-12 09:49:56 +02:00
}
2023-11-04 13:10:52 +00:00
2023-12-11 16:32:00 +00:00
if ( decorate ) {
2025-04-28 22:25:22 +02:00
for ( auto const & wd : pWindow - > m_windowDecorations ) {
2023-12-11 16:32:00 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_OVERLAY )
continue ;
2023-11-04 13:10:52 +00:00
2025-05-07 19:02:07 +02:00
wd - > draw ( pMonitor , fullAlpha ) ;
2023-12-11 16:32:00 +00:00
}
2023-11-04 13:10:52 +00:00
}
2022-05-17 13:16:37 +02:00
}
2023-05-26 13:07:45 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WINDOW ) ;
2024-12-22 22:07:08 +00:00
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . currentWindow . reset ( ) ;
2022-03-21 19:18:33 +01:00
}
2025-04-25 16:38:31 +02:00
void CHyprRenderer : : renderLayer ( PHLLS pLayer , PHLMONITOR pMonitor , const Time : : steady_tp & time , bool popups , bool lockscreen ) {
2024-08-07 13:31:27 +02:00
if ( ! pLayer )
return ;
2025-04-25 16:38:31 +02:00
// skip rendering based on abovelock rule and make sure to not render abovelock layers twice
if ( ( pLayer - > m_aboveLockscreen & & ! lockscreen & & g_pSessionLockManager - > isSessionLocked ( ) ) | | ( lockscreen & & ! pLayer - > m_aboveLockscreen ) )
return ;
2024-04-11 21:41:18 +10:00
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
2025-04-24 20:49:49 +02:00
if ( * PDIMAROUND & & pLayer - > m_dimAround & & ! m_bRenderingSnapshot & & ! popups ) {
2024-12-22 17:12:09 +01:00
CRectPassElement : : SRectData data ;
2025-05-05 23:44:49 +02:00
data . box = { 0 , 0 , g_pHyprOpenGL - > m_renderData . pMonitor - > m_transformedSize . x , g_pHyprOpenGL - > m_renderData . pMonitor - > m_transformedSize . y } ;
2025-04-24 20:49:49 +02:00
data . color = CHyprColor ( 0 , 0 , 0 , * PDIMAROUND * pLayer - > m_alpha - > value ( ) ) ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CRectPassElement > ( data ) ) ;
2024-04-11 21:41:18 +10:00
}
2025-04-24 20:49:49 +02:00
if ( pLayer - > m_fadingOut ) {
2024-04-04 22:43:57 +01:00
if ( ! popups )
2024-12-22 17:12:09 +01:00
renderSnapshot ( pLayer ) ;
2022-05-14 17:23:46 +02:00
return ;
}
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderLayer " ) ;
2025-04-24 20:49:49 +02:00
const auto REALPOS = pLayer - > m_realPosition - > value ( ) ;
const auto REALSIZ = pLayer - > m_realSize - > value ( ) ;
2023-03-17 23:16:13 +00:00
2024-12-22 17:12:09 +01:00
CSurfacePassElement : : SRenderData renderdata = { pMonitor , time , REALPOS } ;
2025-04-24 20:49:49 +02:00
renderdata . fadeAlpha = pLayer - > m_alpha - > value ( ) ;
2025-05-10 18:31:26 +01:00
renderdata . blur = shouldBlur ( pLayer ) ;
2025-04-24 20:49:49 +02:00
renderdata . surface = pLayer - > m_surface - > resource ( ) ;
2024-12-22 17:12:09 +01:00
renderdata . decorate = false ;
renderdata . w = REALSIZ . x ;
renderdata . h = REALSIZ . y ;
renderdata . pLS = pLayer ;
2025-04-24 20:49:49 +02:00
renderdata . blockBlurOptimization = pLayer - > m_layer = = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM | | pLayer - > m_layer = = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ;
2024-02-28 15:00:34 +00:00
2025-04-30 23:45:20 +02:00
renderdata . clipBox = CBox { 0 , 0 , pMonitor - > m_size . x , pMonitor - > m_size . y } . scale ( pMonitor - > m_scale ) ;
2024-03-25 16:08:55 +00:00
2025-04-24 20:49:49 +02:00
if ( renderdata . blur & & pLayer - > m_ignoreAlpha ) {
2024-12-22 17:12:09 +01:00
renderdata . discardMode | = DISCARD_ALPHA ;
2025-04-24 20:49:49 +02:00
renderdata . discardOpacity = pLayer - > m_ignoreAlphaValue ;
2023-06-12 00:30:31 +07:00
}
2024-03-25 16:08:55 +00:00
2024-03-25 16:20:30 +00:00
if ( ! popups )
2025-04-24 20:49:49 +02:00
pLayer - > m_surface - > resource ( ) - > breadthfirst (
2024-12-22 17:12:09 +01:00
[ this , & renderdata , & pLayer ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
2025-05-03 16:02:49 +02:00
renderdata . texture = s - > m_current . texture ;
2024-12-22 17:12:09 +01:00
renderdata . surface = s ;
2025-04-24 20:49:49 +02:00
renderdata . mainSurface = s = = pLayer - > m_surface - > resource ( ) ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CSurfacePassElement > ( renderdata ) ) ;
2024-12-22 17:12:09 +01:00
renderdata . surfaceCounter + + ;
} ,
& renderdata ) ;
2022-07-27 18:02:20 +02:00
2022-12-16 17:17:31 +00:00
renderdata . squishOversized = false ; // don't squish popups
renderdata . dontRound = true ;
2023-12-25 18:04:00 +01:00
renderdata . popup = true ;
2025-04-24 20:49:49 +02:00
renderdata . blur = pLayer - > m_forceBlurPopups ;
2024-06-17 12:42:32 +02:00
renderdata . surfaceCounter = 0 ;
2024-05-09 21:47:21 +01:00
if ( popups ) {
2025-04-24 20:49:49 +02:00
pLayer - > m_popupHead - > breadthfirst (
2025-01-26 12:54:32 +00:00
[ this , & renderdata ] ( WP < CPopup > popup , void * data ) {
2025-04-24 20:49:49 +02:00
if ( ! popup - > m_wlSurface | | ! popup - > m_wlSurface - > resource ( ) | | ! popup - > m_mapped )
2024-05-09 21:47:21 +01:00
return ;
2024-12-22 17:12:09 +01:00
Vector2D pos = popup - > coordsRelativeToParent ( ) ;
renderdata . localPos = pos ;
2025-05-03 16:02:49 +02:00
renderdata . texture = popup - > m_wlSurface - > resource ( ) - > m_current . texture ;
2025-04-24 20:49:49 +02:00
renderdata . surface = popup - > m_wlSurface - > resource ( ) ;
2024-12-22 17:12:09 +01:00
renderdata . mainSurface = false ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CSurfacePassElement > ( renderdata ) ) ;
2024-12-22 17:12:09 +01:00
renderdata . surfaceCounter + + ;
2024-05-09 21:47:21 +01:00
} ,
& renderdata ) ;
}
2022-05-14 17:23:46 +02:00
}
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderIMEPopup ( CInputPopup * pPopup , PHLMONITOR pMonitor , const Time : : steady_tp & time ) {
2024-12-22 17:12:09 +01:00
const auto POS = pPopup - > globalBox ( ) . pos ( ) ;
2024-03-24 16:08:25 +00:00
2024-12-22 17:12:09 +01:00
CSurfacePassElement : : SRenderData renderdata = { pMonitor , time , POS } ;
2024-03-24 16:08:25 +00:00
2024-12-22 17:12:09 +01:00
const auto SURF = pPopup - > getSurface ( ) ;
2022-08-05 17:07:01 +02:00
2024-03-24 16:08:25 +00:00
renderdata . surface = SURF ;
2022-08-05 17:07:01 +02:00
renderdata . decorate = false ;
2025-05-03 16:02:49 +02:00
renderdata . w = SURF - > m_current . size . x ;
renderdata . h = SURF - > m_current . size . y ;
2022-08-05 17:07:01 +02:00
2024-11-23 09:29:29 -05:00
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
static auto PBLURIMES = CConfigValue < Hyprlang : : INT > ( " decoration:blur:input_methods " ) ;
static auto PBLURIGNOREA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:input_methods_ignorealpha " ) ;
renderdata . blur = * PBLURIMES & & * PBLUR ;
if ( renderdata . blur ) {
2024-12-22 17:12:09 +01:00
renderdata . discardMode | = DISCARD_ALPHA ;
renderdata . discardOpacity = * PBLURIGNOREA ;
}
SURF - > breadthfirst (
[ this , & renderdata , & SURF ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
2025-05-03 16:02:49 +02:00
renderdata . texture = s - > m_current . texture ;
2024-12-22 17:12:09 +01:00
renderdata . surface = s ;
renderdata . mainSurface = s = = SURF ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CSurfacePassElement > ( renderdata ) ) ;
2024-12-22 17:12:09 +01:00
renderdata . surfaceCounter + + ;
} ,
& renderdata ) ;
2022-08-05 17:07:01 +02:00
}
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderSessionLockSurface ( WP < SSessionLockSurface > pSurface , PHLMONITOR pMonitor , const Time : : steady_tp & time ) {
2025-04-30 23:45:20 +02:00
CSurfacePassElement : : SRenderData renderdata = { pMonitor , time , pMonitor - > m_position , pMonitor - > m_position } ;
2023-02-03 11:58:55 +00:00
renderdata . blur = false ;
2024-05-05 17:16:00 +01:00
renderdata . surface = pSurface - > surface - > surface ( ) ;
2023-02-03 11:58:55 +00:00
renderdata . decorate = false ;
2025-04-30 23:45:20 +02:00
renderdata . w = pMonitor - > m_size . x ;
renderdata . h = pMonitor - > m_size . y ;
2023-02-03 11:58:55 +00:00
2024-12-22 17:12:09 +01:00
renderdata . surface - > breadthfirst (
[ this , & renderdata , & pSurface ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
2025-05-03 16:02:49 +02:00
renderdata . texture = s - > m_current . texture ;
2024-12-22 17:12:09 +01:00
renderdata . surface = s ;
renderdata . mainSurface = s = = pSurface - > surface - > surface ( ) ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CSurfacePassElement > ( renderdata ) ) ;
2024-12-22 17:12:09 +01:00
renderdata . surfaceCounter + + ;
} ,
& renderdata ) ;
2023-02-03 11:58:55 +00:00
}
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderAllClientsForWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , const Time : : steady_tp & time , const Vector2D & translate , const float & scale ) {
2025-01-01 14:11:21 +01:00
static auto PDIMSPECIAL = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_special " ) ;
static auto PBLURSPECIAL = CConfigValue < Hyprlang : : INT > ( " decoration:blur:special " ) ;
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
static auto PRENDERTEX = CConfigValue < Hyprlang : : INT > ( " misc:disable_hyprland_logo " ) ;
static auto PBACKGROUNDCOLOR = CConfigValue < Hyprlang : : INT > ( " misc:background_color " ) ;
static auto PXPMODE = CConfigValue < Hyprlang : : INT > ( " render:xp_mode " ) ;
2025-07-14 13:13:54 +02:00
static auto PSESSIONLOCKXRAY = CConfigValue < Hyprlang : : INT > ( " misc:session_lock_xray " ) ;
2023-04-12 12:41:23 +01:00
if ( ! pMonitor )
2022-03-17 20:22:29 +01:00
return ;
2025-07-14 13:13:54 +02:00
if ( g_pSessionLockManager - > isSessionLocked ( ) & & ! * PSESSIONLOCKXRAY ) {
// We stop to render workspaces as soon as the lockscreen was sent the "locked" or "finished" (aka denied) event.
// In addition we make sure to stop rendering workspaces after misc:lockdead_screen_delay has passed.
if ( g_pSessionLockManager - > shallConsiderLockMissing ( ) | | g_pSessionLockManager - > clientLocked ( ) | | g_pSessionLockManager - > clientDenied ( ) )
return ;
2023-02-03 11:58:55 +00:00
}
2023-04-12 12:41:23 +01:00
// todo: matrices are buggy atm for some reason, but probably would be preferable in the long run
// g_pHyprOpenGL->saveMatrix();
// g_pHyprOpenGL->setMatrixScaleTranslate(translate, scale);
2025-01-01 14:11:21 +01:00
SRenderModifData RENDERMODIFDATA ;
if ( translate ! = Vector2D { 0 , 0 } )
RENDERMODIFDATA . modifs . emplace_back ( std : : make_pair < > ( SRenderModifData : : eRenderModifType : : RMOD_TYPE_TRANSLATE , translate ) ) ;
if ( scale ! = 1.f )
RENDERMODIFDATA . modifs . emplace_back ( std : : make_pair < > ( SRenderModifData : : eRenderModifType : : RMOD_TYPE_SCALE , scale ) ) ;
2025-06-11 17:52:16 +02:00
if ( ! RENDERMODIFDATA . modifs . empty ( ) )
2025-07-10 10:44:59 +02:00
g_pHyprRenderer - > m_renderPass . add ( makeUnique < CRendererHintsPassElement > ( CRendererHintsPassElement : : SData { RENDERMODIFDATA } ) ) ;
2023-04-12 12:41:23 +01:00
2025-01-02 06:51:59 -05:00
CScopeGuard x ( [ & RENDERMODIFDATA ] {
if ( ! RENDERMODIFDATA . modifs . empty ( ) ) {
2025-07-10 10:44:59 +02:00
g_pHyprRenderer - > m_renderPass . add ( makeUnique < CRendererHintsPassElement > ( CRendererHintsPassElement : : SData { SRenderModifData { } } ) ) ;
2025-01-02 06:51:59 -05:00
}
} ) ;
2024-04-03 14:09:58 +01:00
if ( ! pWorkspace ) {
// allow rendering without a workspace. In this case, just render layers.
2024-12-22 17:12:09 +01:00
if ( * PRENDERTEX /* inverted cfg flag */ )
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CClearPassElement > ( CClearPassElement : : SClearData { CHyprColor ( * PBACKGROUNDCOLOR ) } ) ) ;
2024-12-22 17:12:09 +01:00
else
g_pHyprOpenGL - > clearWithTex ( ) ; // will apply the hypr "wallpaper"
2024-04-03 14:09:58 +01:00
2025-04-30 23:45:20 +02:00
for ( auto const & ls : pMonitor - > m_layerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2024-04-03 14:09:58 +01:00
}
2025-05-10 18:31:26 +01:00
2025-08-22 12:19:00 -05:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WALLPAPER ) ;
2025-04-30 23:45:20 +02:00
for ( auto const & ls : pMonitor - > m_layerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2024-04-03 14:09:58 +01:00
}
2025-05-10 18:31:26 +01:00
2025-04-30 23:45:20 +02:00
for ( auto const & ls : pMonitor - > m_layerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2024-04-03 14:09:58 +01:00
}
2025-05-10 18:31:26 +01:00
2025-04-30 23:45:20 +02:00
for ( auto const & ls : pMonitor - > m_layerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2024-04-03 14:09:58 +01:00
}
return ;
}
2024-12-22 17:12:09 +01:00
if ( ! * PXPMODE ) {
if ( * PRENDERTEX /* inverted cfg flag */ )
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CClearPassElement > ( CClearPassElement : : SClearData { CHyprColor ( * PBACKGROUNDCOLOR ) } ) ) ;
2024-12-22 17:12:09 +01:00
else
g_pHyprOpenGL - > clearWithTex ( ) ; // will apply the hypr "wallpaper"
2023-11-26 15:06:42 +00:00
2025-04-30 23:45:20 +02:00
for ( auto const & ls : pMonitor - > m_layerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2023-04-22 12:36:50 +01:00
}
2025-05-10 18:31:26 +01:00
2025-08-22 12:19:00 -05:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WALLPAPER ) ;
2025-04-30 23:45:20 +02:00
for ( auto const & ls : pMonitor - > m_layerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2023-04-22 12:36:50 +01:00
}
2022-03-19 13:35:04 +01:00
}
2022-08-01 12:23:09 +02:00
// pre window pass
g_pHyprOpenGL - > preWindowPass ( ) ;
2025-04-25 02:37:12 +02:00
if ( pWorkspace - > m_hasFullscreenWindow )
2023-09-04 15:07:56 +02:00
renderWorkspaceWindowsFullscreen ( pMonitor , pWorkspace , time ) ;
else
renderWorkspaceWindows ( pMonitor , pWorkspace , time ) ;
2022-05-31 14:01:00 +02:00
// and then special
2025-06-11 17:52:16 +02:00
if ( pMonitor - > m_specialFade - > value ( ) ! = 0.F ) {
const auto SPECIALANIMPROGRS = pMonitor - > m_specialFade - > getCurveValue ( ) ;
const bool ANIMOUT = ! pMonitor - > m_activeSpecialWorkspace ;
2024-12-22 17:12:09 +01:00
2025-06-11 17:52:16 +02:00
if ( * PDIMSPECIAL ! = 0.f ) {
CRectPassElement : : SRectData data ;
data . box = { translate . x , translate . y , pMonitor - > m_transformedSize . x * scale , pMonitor - > m_transformedSize . y * scale } ;
data . color = CHyprColor ( 0 , 0 , 0 , * PDIMSPECIAL * ( ANIMOUT ? ( 1.0 - SPECIALANIMPROGRS ) : SPECIALANIMPROGRS ) ) ;
2022-12-28 15:18:23 +01:00
2025-07-10 10:44:59 +02:00
g_pHyprRenderer - > m_renderPass . add ( makeUnique < CRectPassElement > ( data ) ) ;
2025-06-11 17:52:16 +02:00
}
2024-12-22 17:12:09 +01:00
2025-06-11 17:52:16 +02:00
if ( * PBLURSPECIAL & & * PBLUR ) {
CRectPassElement : : SRectData data ;
data . box = { translate . x , translate . y , pMonitor - > m_transformedSize . x * scale , pMonitor - > m_transformedSize . y * scale } ;
data . color = CHyprColor ( 0 , 0 , 0 , 0 ) ;
data . blur = true ;
data . blurA = ( ANIMOUT ? ( 1.0 - SPECIALANIMPROGRS ) : SPECIALANIMPROGRS ) ;
2023-08-25 17:43:23 +02:00
2025-07-10 10:44:59 +02:00
g_pHyprRenderer - > m_renderPass . add ( makeUnique < CRectPassElement > ( data ) ) ;
2022-12-28 15:18:23 +01:00
}
2023-08-25 18:05:08 +02:00
}
2023-11-18 17:00:24 +00:00
// special
2025-07-24 00:36:29 +02:00
for ( auto const & ws : g_pCompositor - > getWorkspaces ( ) ) {
2025-06-11 17:52:16 +02:00
if ( ws - > m_alpha - > value ( ) < = 0.F | | ! ws - > m_isSpecialWorkspace )
continue ;
if ( ws - > m_hasFullscreenWindow )
2025-07-24 00:36:29 +02:00
renderWorkspaceWindowsFullscreen ( pMonitor , ws . lock ( ) , time ) ;
2025-06-11 17:52:16 +02:00
else
2025-07-24 00:36:29 +02:00
renderWorkspaceWindows ( pMonitor , ws . lock ( ) , time ) ;
2022-03-18 20:03:39 +01:00
}
2022-03-19 13:35:04 +01:00
2023-11-22 20:05:50 +00:00
// pinned always above
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
if ( w - > isHidden ( ) & & ! w - > m_isMapped & & ! w - > m_fadingOut )
2023-11-22 20:05:50 +00:00
continue ;
2025-04-28 22:25:22 +02:00
if ( ! w - > m_pinned | | ! w - > m_isFloating )
2023-11-22 20:05:50 +00:00
continue ;
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2023-11-22 20:05:50 +00:00
continue ;
// render the bad boy
2024-04-27 12:43:12 +01:00
renderWindow ( w , pMonitor , time , true , RENDER_PASS_ALL ) ;
2023-11-22 20:05:50 +00:00
}
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WINDOWS ) ;
2022-03-19 13:35:04 +01:00
// Render surfaces above windows for monitor
2025-04-30 23:45:20 +02:00
for ( auto const & ls : pMonitor - > m_layerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2022-03-19 13:35:04 +01:00
}
2022-08-05 17:07:01 +02:00
// Render IME popups
2025-05-01 23:57:11 +02:00
for ( auto const & imep : g_pInputManager - > m_relay . m_inputMethodPopups ) {
2024-03-24 16:08:25 +00:00
renderIMEPopup ( imep . get ( ) , pMonitor , time ) ;
2022-08-05 17:07:01 +02:00
}
2025-04-30 23:45:20 +02:00
for ( auto const & ls : pMonitor - > m_layerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2022-03-19 13:35:04 +01:00
}
2022-03-31 17:25:23 +02:00
2025-04-30 23:45:20 +02:00
for ( auto const & lsl : pMonitor - > m_layerSurfaceLayers ) {
2024-08-26 20:24:30 +02:00
for ( auto const & ls : lsl ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time , true ) ;
2024-03-25 16:20:30 +00:00
}
}
2023-04-12 12:41:23 +01:00
renderDragIcon ( pMonitor , time ) ;
//g_pHyprOpenGL->restoreMatrix();
}
2023-02-03 11:58:55 +00:00
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderLockscreen ( PHLMONITOR pMonitor , const Time : : steady_tp & now , const CBox & geometry ) {
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderLockscreen " ) ;
2025-06-19 13:46:42 +02:00
const bool LOCKED = g_pSessionLockManager - > isSessionLocked ( ) ;
2025-07-14 13:13:54 +02:00
if ( ! LOCKED ) {
g_pHyprOpenGL - > ensureLockTexturesRendered ( false ) ;
return ;
}
2025-06-19 13:46:42 +02:00
2025-07-14 13:13:54 +02:00
const bool RENDERPRIMER = g_pSessionLockManager - > shallConsiderLockMissing ( ) | | g_pSessionLockManager - > clientLocked ( ) | | g_pSessionLockManager - > clientDenied ( ) ;
if ( RENDERPRIMER )
renderSessionLockPrimer ( pMonitor ) ;
2025-06-19 13:46:42 +02:00
2025-07-14 13:13:54 +02:00
const auto PSLS = g_pSessionLockManager - > getSessionLockSurfaceForMonitor ( pMonitor - > m_id ) ;
const bool RENDERLOCKMISSING = ( PSLS . expired ( ) | | g_pSessionLockManager - > clientDenied ( ) ) & & g_pSessionLockManager - > shallConsiderLockMissing ( ) ;
2023-02-03 11:58:55 +00:00
2025-07-14 13:13:54 +02:00
g_pHyprOpenGL - > ensureLockTexturesRendered ( RENDERLOCKMISSING ) ;
2025-04-25 16:38:31 +02:00
2025-07-14 13:13:54 +02:00
if ( RENDERLOCKMISSING )
renderSessionLockMissing ( pMonitor ) ;
else if ( PSLS ) {
renderSessionLockSurface ( PSLS , pMonitor , now ) ;
g_pSessionLockManager - > onLockscreenRenderedOnMonitor ( pMonitor - > m_id ) ;
// render layers and then their popups for abovelock rule
for ( auto const & lsl : pMonitor - > m_layerSurfaceLayers ) {
for ( auto const & ls : lsl ) {
renderLayer ( ls . lock ( ) , pMonitor , now , false , true ) ;
2025-04-25 16:38:31 +02:00
}
2025-07-14 13:13:54 +02:00
}
for ( auto const & lsl : pMonitor - > m_layerSurfaceLayers ) {
for ( auto const & ls : lsl ) {
renderLayer ( ls . lock ( ) , pMonitor , now , true , true ) ;
2025-04-25 16:38:31 +02:00
}
2023-02-03 11:58:55 +00:00
}
}
2022-03-17 20:22:29 +01:00
}
2022-03-19 14:07:18 +01:00
2025-07-14 13:13:54 +02:00
void CHyprRenderer : : renderSessionLockPrimer ( PHLMONITOR pMonitor ) {
static auto PSESSIONLOCKXRAY = CConfigValue < Hyprlang : : INT > ( " misc:session_lock_xray " ) ;
if ( * PSESSIONLOCKXRAY )
return ;
CRectPassElement : : SRectData data ;
data . color = CHyprColor ( 0 , 0 , 0 , 1.f ) ;
data . box = CBox { { } , pMonitor - > m_pixelSize } ;
2024-08-29 23:30:12 +02:00
2025-07-14 15:48:50 +02:00
m_renderPass . add ( makeUnique < CRectPassElement > ( std : : move ( data ) ) ) ;
2025-07-14 13:13:54 +02:00
}
2024-08-29 23:30:12 +02:00
2025-07-14 13:13:54 +02:00
void CHyprRenderer : : renderSessionLockMissing ( PHLMONITOR pMonitor ) {
2024-08-29 23:30:12 +02:00
const bool ANY_PRESENT = g_pSessionLockManager - > anySessionLockSurfacesPresent ( ) ;
2025-07-14 13:13:54 +02:00
// ANY_PRESENT: render image2, without instructions. Lock still "alive", unless texture dead
// else: render image, with instructions. Lock is gone.
CBox monbox = { { } , pMonitor - > m_pixelSize } ;
CTexPassElement : : SRenderData data ;
data . tex = ( ANY_PRESENT ) ? g_pHyprOpenGL - > m_lockDead2Texture : g_pHyprOpenGL - > m_lockDeadTexture ;
data . box = monbox ;
data . a = 1 ;
2025-07-14 15:48:50 +02:00
m_renderPass . add ( makeUnique < CTexPassElement > ( data ) ) ;
2024-08-29 23:30:12 +02:00
2025-07-14 13:13:54 +02:00
if ( ! ANY_PRESENT & & g_pHyprOpenGL - > m_lockTtyTextTexture ) {
2024-11-01 15:52:03 +00:00
// also render text for the tty number
2025-07-14 13:13:54 +02:00
CBox texbox = { { } , g_pHyprOpenGL - > m_lockTtyTextTexture - > m_size } ;
data . tex = g_pHyprOpenGL - > m_lockTtyTextTexture ;
data . box = texbox ;
2024-08-29 23:30:12 +02:00
2025-07-14 15:48:50 +02:00
m_renderPass . add ( makeUnique < CTexPassElement > ( std : : move ( data ) ) ) ;
2025-07-14 13:13:54 +02:00
}
2024-08-29 23:30:12 +02:00
}
2024-10-26 02:06:13 +01:00
void CHyprRenderer : : calculateUVForSurface ( PHLWINDOW pWindow , SP < CWLSurfaceResource > pSurface , PHLMONITOR pMonitor , bool main , const Vector2D & projSize ,
2024-10-05 00:52:53 +01:00
const Vector2D & projSizeUnscaled , bool fixMisalignedFSV1 ) {
2025-04-28 22:25:22 +02:00
if ( ! pWindow | | ! pWindow - > m_isX11 ) {
2024-11-04 19:42:47 +00:00
static auto PEXPANDEDGES = CConfigValue < Hyprlang : : INT > ( " render:expand_undersized_textures " ) ;
Vector2D uvTL ;
Vector2D uvBR = Vector2D ( 1 , 1 ) ;
2022-08-28 10:14:43 +02:00
2025-05-03 16:02:49 +02:00
if ( pSurface - > m_current . viewport . hasSource ) {
2023-01-20 19:44:30 +01:00
// we stretch it to dest. if no dest, to 1,1
2025-05-03 16:02:49 +02:00
Vector2D const & bufferSize = pSurface - > m_current . bufferSize ;
auto const & bufferSource = pSurface - > m_current . viewport . source ;
2022-08-28 10:14:43 +02:00
2023-01-29 15:58:36 +00:00
// calculate UV for the basic src_box. Assume dest == size. Scale to dest later
2023-01-20 19:44:30 +01:00
uvTL = Vector2D ( bufferSource . x / bufferSize . x , bufferSource . y / bufferSize . y ) ;
uvBR = Vector2D ( ( bufferSource . x + bufferSource . width ) / bufferSize . x , ( bufferSource . y + bufferSource . height ) / bufferSize . y ) ;
2022-08-28 10:14:43 +02:00
2022-08-28 14:32:06 +02:00
if ( uvBR . x < 0.01f | | uvBR . y < 0.01f ) {
uvTL = Vector2D ( ) ;
2022-12-16 17:17:31 +00:00
uvBR = Vector2D ( 1 , 1 ) ;
2022-08-28 14:32:06 +02:00
}
2022-08-28 10:14:43 +02:00
}
2024-01-28 23:42:39 +00:00
if ( projSize ! = Vector2D { } & & fixMisalignedFSV1 ) {
// instead of nearest_neighbor (we will repeat / skip)
// just cut off / expand surface
2025-05-03 16:02:49 +02:00
const Vector2D PIXELASUV = Vector2D { 1 , 1 } / pSurface - > m_current . bufferSize ;
const Vector2D MISALIGNMENT = pSurface - > m_current . bufferSize - projSize ;
2024-01-28 23:42:39 +00:00
if ( MISALIGNMENT ! = Vector2D { } )
uvBR - = MISALIGNMENT * PIXELASUV ;
}
2024-10-05 00:52:53 +01:00
// if the surface is smaller than our viewport, extend its edges.
// this will break if later on xdg geometry is hit, but we really try
// to let the apps know to NOT add CSD. Also if source is there.
// there is no way to fix this if that's the case
2024-11-04 19:42:47 +00:00
if ( * PEXPANDEDGES ) {
2025-04-30 23:45:20 +02:00
const auto MONITOR_WL_SCALE = std : : ceil ( pMonitor - > m_scale ) ;
2025-05-03 16:02:49 +02:00
const bool SCALE_UNAWARE = MONITOR_WL_SCALE ! = pSurface - > m_current . scale & & ! pSurface - > m_current . viewport . hasDestination ;
2024-11-04 19:42:47 +00:00
const auto EXPECTED_SIZE =
2025-05-03 16:02:49 +02:00
( ( pSurface - > m_current . viewport . hasDestination ? pSurface - > m_current . viewport . destination : pSurface - > m_current . bufferSize / pSurface - > m_current . scale ) *
pMonitor - > m_scale )
2024-11-04 19:42:47 +00:00
. round ( ) ;
if ( ! SCALE_UNAWARE & & ( EXPECTED_SIZE . x < projSize . x | | EXPECTED_SIZE . y < projSize . y ) ) {
// this will not work with shm AFAIK, idk why.
// NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much
2025-08-08 16:14:02 +02:00
const auto FIX = ( projSize / EXPECTED_SIZE ) . clamp ( Vector2D { 1 , 1 } , Vector2D { 1000000 , 1000000 } ) ;
2024-11-04 19:42:47 +00:00
uvBR = uvBR * FIX ;
}
2024-10-05 00:52:53 +01:00
}
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . primarySurfaceUVTopLeft = uvTL ;
g_pHyprOpenGL - > m_renderData . primarySurfaceUVBottomRight = uvBR ;
2022-08-28 10:14:43 +02:00
2025-05-05 23:44:49 +02:00
if ( g_pHyprOpenGL - > m_renderData . primarySurfaceUVTopLeft = = Vector2D ( ) & & g_pHyprOpenGL - > m_renderData . primarySurfaceUVBottomRight = = Vector2D ( 1 , 1 ) ) {
2022-08-28 10:14:43 +02:00
// No special UV mods needed
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
g_pHyprOpenGL - > m_renderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:14:43 +02:00
}
2023-01-29 13:58:47 +00:00
if ( ! main | | ! pWindow )
2023-01-20 19:44:30 +01:00
return ;
2022-08-28 10:14:43 +02:00
2025-05-04 23:39:00 +02:00
CBox geom = pWindow - > m_xdgSurface - > m_current . geometry ;
2023-01-20 19:44:30 +01:00
2025-08-08 16:14:02 +02:00
// Adjust UV based on the xdg_surface geometry
if ( geom . x ! = 0 | | geom . y ! = 0 | | geom . w ! = 0 | | geom . h ! = 0 ) {
2025-08-14 19:44:56 +05:00
const auto XPERC = geom . x / pSurface - > m_current . size . x ;
const auto YPERC = geom . y / pSurface - > m_current . size . y ;
const auto WPERC = ( geom . x + geom . w ? geom . w : pSurface - > m_current . size . x ) / pSurface - > m_current . size . x ;
const auto HPERC = ( geom . y + geom . h ? geom . h : pSurface - > m_current . size . y ) / pSurface - > m_current . size . y ;
2022-08-28 10:14:43 +02:00
2023-01-20 19:44:30 +01:00
const auto TOADDTL = Vector2D ( XPERC * ( uvBR . x - uvTL . x ) , YPERC * ( uvBR . y - uvTL . y ) ) ;
2024-10-03 22:00:44 +00:00
uvBR = uvBR - Vector2D ( ( 1.0 - WPERC ) * ( uvBR . x - uvTL . x ) , ( 1.0 - HPERC ) * ( uvBR . y - uvTL . y ) ) ;
2023-01-20 19:44:30 +01:00
uvTL = uvTL + TOADDTL ;
2025-08-08 16:14:02 +02:00
}
2022-08-28 10:14:43 +02:00
2025-08-08 16:14:02 +02:00
// Adjust UV based on our animation progress
if ( pSurface - > m_current . size . x > projSizeUnscaled . x | | pSurface - > m_current . size . y > projSizeUnscaled . y ) {
2024-10-05 00:52:53 +01:00
auto maxSize = projSizeUnscaled ;
2023-11-12 23:57:53 +00:00
2025-04-28 22:25:22 +02:00
if ( pWindow - > m_wlSurface - > small ( ) & & ! pWindow - > m_wlSurface - > m_fillIgnoreSmall )
maxSize = pWindow - > m_wlSurface - > getViewporterCorrectedSize ( ) ;
2023-11-12 23:57:53 +00:00
2025-08-08 16:14:02 +02:00
if ( pSurface - > m_current . size . x > maxSize . x )
uvBR . x = uvBR . x * ( maxSize . x / pSurface - > m_current . size . x ) ;
if ( pSurface - > m_current . size . y > maxSize . y )
uvBR . y = uvBR . y * ( maxSize . y / pSurface - > m_current . size . y ) ;
2023-01-20 19:44:30 +01:00
}
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . primarySurfaceUVTopLeft = uvTL ;
g_pHyprOpenGL - > m_renderData . primarySurfaceUVBottomRight = uvBR ;
2023-01-20 19:44:30 +01:00
2025-05-05 23:44:49 +02:00
if ( g_pHyprOpenGL - > m_renderData . primarySurfaceUVTopLeft = = Vector2D ( ) & & g_pHyprOpenGL - > m_renderData . primarySurfaceUVBottomRight = = Vector2D ( 1 , 1 ) ) {
2023-01-20 19:44:30 +01:00
// No special UV mods needed
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
g_pHyprOpenGL - > m_renderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:14:43 +02:00
}
} else {
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
g_pHyprOpenGL - > m_renderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:14:43 +02:00
}
}
2025-07-08 12:41:10 +02:00
void CHyprRenderer : : renderMonitor ( PHLMONITOR pMonitor , bool commit ) {
2023-11-24 10:54:21 +00:00
static std : : chrono : : high_resolution_clock : : time_point renderStart = std : : chrono : : high_resolution_clock : : now ( ) ;
static std : : chrono : : high_resolution_clock : : time_point renderStartOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-03-24 19:23:16 +00:00
static std : : chrono : : high_resolution_clock : : time_point endRenderOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
2024-03-03 18:39:20 +00:00
static auto PDEBUGOVERLAY = CConfigValue < Hyprlang : : INT > ( " debug:overlay " ) ;
static auto PDAMAGETRACKINGMODE = CConfigValue < Hyprlang : : INT > ( " debug:damage_tracking " ) ;
static auto PDAMAGEBLINK = CConfigValue < Hyprlang : : INT > ( " debug:damage_blink " ) ;
static auto PVFR = CConfigValue < Hyprlang : : INT > ( " misc:vfr " ) ;
2023-03-24 19:23:16 +00:00
static int damageBlinkCleanup = 0 ; // because double-buffered
2025-07-01 11:33:48 +02:00
const float ZOOMFACTOR = pMonitor - > m_cursorZoom - > value ( ) ;
2025-06-11 16:57:07 +02:00
if ( pMonitor - > m_pixelSize . x < 1 | | pMonitor - > m_pixelSize . y < 1 ) {
Debug : : log ( ERR , " Refusing to render a monitor because of an invalid pixel size: {} " , pMonitor - > m_pixelSize ) ;
return ;
}
2024-03-03 18:39:20 +00:00
if ( ! * PDAMAGEBLINK )
2023-03-24 19:23:16 +00:00
damageBlinkCleanup = 0 ;
2025-07-04 09:39:53 +02:00
if ( * PDEBUGOVERLAY = = 1 ) {
renderStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-03-24 19:23:16 +00:00
g_pDebugOverlay - > frameData ( pMonitor ) ;
2025-07-04 09:39:53 +02:00
}
2023-03-24 19:23:16 +00:00
2025-04-22 15:23:29 +02:00
if ( ! g_pCompositor - > m_sessionActive )
2023-03-24 19:23:16 +00:00
return ;
2025-05-05 23:44:49 +02:00
if ( pMonitor - > m_id = = m_mostHzMonitor - > m_id | |
2024-03-03 18:39:20 +00:00
* PVFR = = 1 ) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that
2023-03-24 19:23:16 +00:00
g_pConfigManager - > dispatchExecOnce ( ) ; // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
2025-04-20 20:39:33 +02:00
if ( g_pConfigManager - > m_wantsMonitorReload )
2023-03-24 19:23:16 +00:00
g_pConfigManager - > performMonitorReload ( ) ;
}
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_scheduledRecalc ) {
pMonitor - > m_scheduledRecalc = false ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitor - > m_id ) ;
2023-03-24 19:23:16 +00:00
}
2025-04-30 23:45:20 +02:00
if ( ! pMonitor - > m_output - > needsFrame & & pMonitor - > m_forceFullFrames = = 0 )
2024-07-21 13:09:54 +02:00
return ;
2023-09-28 21:48:33 +01:00
// tearing and DS first
2025-08-22 20:24:25 +03:00
bool shouldTear = pMonitor - > updateTearing ( ) ;
2023-09-28 21:48:33 +01:00
2025-08-22 20:24:25 +03:00
if ( pMonitor - > attemptDirectScanout ( ) ) {
return ;
} else if ( ! pMonitor - > m_lastScanout . expired ( ) ) {
Debug : : log ( LOG , " Left a direct scanout. " ) ;
pMonitor - > m_lastScanout . reset ( ) ;
2024-08-17 19:27:11 +02:00
2025-08-22 20:24:25 +03:00
// reset DRM format, but only if needed since it might modeset
if ( pMonitor - > m_output - > state - > state ( ) . drmFormat ! = pMonitor - > m_prevDrmFormat )
pMonitor - > m_output - > state - > setFormat ( pMonitor - > m_prevDrmFormat ) ;
2024-12-29 17:19:12 -06:00
2025-08-22 20:24:25 +03:00
pMonitor - > m_drmFormat = pMonitor - > m_prevDrmFormat ;
2023-03-24 19:23:16 +00:00
}
EMIT_HOOK_EVENT ( " preRender " , pMonitor ) ;
2025-04-16 01:37:48 +01:00
const auto NOW = Time : : steadyNow ( ) ;
2023-03-24 19:23:16 +00:00
// check the damage
2025-04-30 23:45:20 +02:00
bool hasChanged = pMonitor - > m_output - > needsFrame | | pMonitor - > m_damage . hasChanged ( ) ;
2023-03-24 19:23:16 +00:00
2025-04-30 23:45:20 +02:00
if ( ! hasChanged & & * PDAMAGETRACKINGMODE ! = DAMAGE_TRACKING_NONE & & pMonitor - > m_forceFullFrames = = 0 & & damageBlinkCleanup = = 0 )
2023-04-09 17:59:24 +01:00
return ;
2024-03-03 18:39:20 +00:00
if ( * PDAMAGETRACKINGMODE = = - 1 ) {
2023-03-24 19:23:16 +00:00
Debug : : log ( CRIT , " Damage tracking mode -1 ???? " ) ;
return ;
}
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE ) ;
2025-04-30 23:45:20 +02:00
pMonitor - > m_renderingActive = true ;
2023-03-24 19:23:16 +00:00
2024-02-19 18:17:32 +00:00
// we need to cleanup fading out when rendering the appropriate context
2025-04-30 23:45:20 +02:00
g_pCompositor - > cleanupFadingOut ( pMonitor - > m_id ) ;
2024-02-19 18:17:32 +00:00
// TODO: this is getting called with extents being 0,0,0,0 should it be?
// potentially can save on resources.
2024-02-18 16:04:08 +00:00
TRACY_GPU_ZONE ( " Render " ) ;
2024-06-12 12:28:52 -05:00
static bool zoomLock = false ;
2025-07-01 11:33:48 +02:00
if ( zoomLock & & ZOOMFACTOR = = 1.f ) {
2024-06-12 12:28:52 -05:00
g_pPointerManager - > unlockSoftwareAll ( ) ;
zoomLock = false ;
2025-07-01 11:33:48 +02:00
} else if ( ! zoomLock & & ZOOMFACTOR ! = 1.f ) {
2024-06-12 12:28:52 -05:00
g_pPointerManager - > lockSoftwareAll ( ) ;
zoomLock = true ;
}
2024-02-18 16:04:08 +00:00
if ( pMonitor = = g_pCompositor - > getMonitorFromCursor ( ) )
2025-07-01 11:33:48 +02:00
g_pHyprOpenGL - > m_renderData . mouseZoomFactor = std : : clamp ( ZOOMFACTOR , 1.f , INFINITY ) ;
2024-02-18 16:04:08 +00:00
else
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . mouseZoomFactor = 1.f ;
2024-02-18 16:04:08 +00:00
2025-08-17 17:14:29 +01:00
if ( pMonitor - > m_zoomAnimProgress - > value ( ) ! = 1 ) {
2025-08-16 20:02:15 +01:00
g_pHyprOpenGL - > m_renderData . mouseZoomFactor = 2.0 - pMonitor - > m_zoomAnimProgress - > value ( ) ; // 2x zoom -> 1x zoom
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . mouseZoomUseMouse = false ;
g_pHyprOpenGL - > m_renderData . useNearestNeighbor = false ;
2024-02-18 16:04:08 +00:00
}
2025-04-11 00:34:50 +02:00
CRegion damage , finalDamage ;
2024-02-18 16:04:08 +00:00
if ( ! beginRender ( pMonitor , damage , RENDER_MODE_NORMAL ) ) {
Debug : : log ( ERR , " renderer: couldn't beginRender()! " ) ;
return ;
}
2023-03-24 19:23:16 +00:00
// if we have no tracking or full tracking, invalidate the entire monitor
2025-04-30 23:45:20 +02:00
if ( * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_NONE | | * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_MONITOR | | pMonitor - > m_forceFullFrames > 0 | | damageBlinkCleanup > 0 )
2025-08-14 19:44:56 +05:00
damage = { 0 , 0 , sc < int > ( pMonitor - > m_transformedSize . x ) * 10 , sc < int > ( pMonitor - > m_transformedSize . y ) * 10 } ;
2023-03-24 19:23:16 +00:00
2025-04-11 00:34:50 +02:00
finalDamage = damage ;
2024-02-19 18:17:32 +00:00
// update damage in renderdata as we modified it
2025-04-11 00:34:50 +02:00
g_pHyprOpenGL - > setDamage ( damage , finalDamage ) ;
2023-03-24 19:23:16 +00:00
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_forceFullFrames > 0 ) {
pMonitor - > m_forceFullFrames - = 1 ;
if ( pMonitor - > m_forceFullFrames > 10 )
pMonitor - > m_forceFullFrames = 0 ;
2024-02-19 18:17:32 +00:00
}
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_BEGIN ) ;
2023-09-29 17:51:07 +01:00
bool renderCursor = true ;
2025-04-11 00:34:50 +02:00
if ( ! finalDamage . empty ( ) ) {
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_solitaryClient . expired ( ) ) {
2024-04-23 12:29:01 +01:00
if ( pMonitor - > isMirror ( ) ) {
g_pHyprOpenGL - > blend ( false ) ;
g_pHyprOpenGL - > renderMirrored ( ) ;
g_pHyprOpenGL - > blend ( true ) ;
EMIT_HOOK_EVENT ( " render " , RENDER_POST_MIRROR ) ;
renderCursor = false ;
} else {
2025-08-14 19:44:56 +05:00
CBox renderBox = { 0 , 0 , sc < int > ( pMonitor - > m_pixelSize . x ) , sc < int > ( pMonitor - > m_pixelSize . y ) } ;
2025-04-30 23:45:20 +02:00
renderWorkspace ( pMonitor , pMonitor - > m_activeWorkspace , NOW , renderBox ) ;
2024-04-23 12:29:01 +01:00
2025-04-16 01:37:48 +01:00
renderLockscreen ( pMonitor , NOW , renderBox ) ;
2024-04-23 12:29:01 +01:00
2025-04-22 15:23:29 +02:00
if ( pMonitor = = g_pCompositor - > m_lastMonitor ) {
2024-04-23 12:29:01 +01:00
g_pHyprNotificationOverlay - > draw ( pMonitor ) ;
g_pHyprError - > draw ( ) ;
}
// for drawing the debug overlay
2025-04-22 15:23:29 +02:00
if ( pMonitor = = g_pCompositor - > m_monitors . front ( ) & & * PDEBUGOVERLAY = = 1 ) {
2024-04-23 12:29:01 +01:00
renderStartOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
g_pDebugOverlay - > draw ( ) ;
endRenderOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
}
if ( * PDAMAGEBLINK & & damageBlinkCleanup = = 0 ) {
2024-12-22 17:12:09 +01:00
CRectPassElement : : SRectData data ;
2025-04-30 23:45:20 +02:00
data . box = { 0 , 0 , pMonitor - > m_transformedSize . x , pMonitor - > m_transformedSize . y } ;
2024-12-22 17:12:09 +01:00
data . color = CHyprColor ( 1.0 , 0.0 , 1.0 , 100.0 / 255.0 ) ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CRectPassElement > ( data ) ) ;
2024-04-23 12:29:01 +01:00
damageBlinkCleanup = 1 ;
} else if ( * PDAMAGEBLINK ) {
damageBlinkCleanup + + ;
if ( damageBlinkCleanup > 3 )
damageBlinkCleanup = 0 ;
}
2023-09-29 17:51:07 +01:00
}
2024-04-23 16:08:54 +01:00
} else
2025-04-30 23:45:20 +02:00
renderWindow ( pMonitor - > m_solitaryClient . lock ( ) , pMonitor , NOW , false , RENDER_PASS_MAIN /* solitary = no popups */ ) ;
2024-06-09 22:28:51 +02:00
} else if ( ! pMonitor - > isMirror ( ) ) {
2025-04-30 23:45:20 +02:00
sendFrameEventsToWorkspace ( pMonitor , pMonitor - > m_activeWorkspace , NOW ) ;
if ( pMonitor - > m_activeSpecialWorkspace )
sendFrameEventsToWorkspace ( pMonitor , pMonitor - > m_activeSpecialWorkspace , NOW ) ;
2023-09-29 17:51:07 +01:00
}
2023-03-24 19:23:16 +00:00
2023-09-29 17:51:07 +01:00
renderCursor = renderCursor & & shouldRenderCursor ( ) ;
2023-11-24 10:54:21 +00:00
if ( renderCursor ) {
2023-09-29 17:51:07 +01:00
TRACY_GPU_ZONE ( " RenderCursor " ) ;
2025-05-05 23:44:49 +02:00
g_pPointerManager - > renderSoftwareCursorsFor ( pMonitor - > m_self . lock ( ) , NOW , g_pHyprOpenGL - > m_renderData . damage ) ;
2023-05-01 02:49:41 +01:00
}
2025-08-17 08:37:13 +01:00
if ( pMonitor - > m_dpmsBlackOpacity - > value ( ) ! = 0.F ) {
// render the DPMS black if we are animating
CRectPassElement : : SRectData data ;
data . box = { 0 , 0 , pMonitor - > m_transformedSize . x , pMonitor - > m_transformedSize . y } ;
data . color = Colors : : BLACK . modifyA ( pMonitor - > m_dpmsBlackOpacity - > value ( ) ) ;
m_renderPass . add ( makeUnique < CRectPassElement > ( data ) ) ;
}
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_LAST_MOMENT ) ;
2023-11-24 10:54:21 +00:00
endRender ( ) ;
2023-03-24 19:23:16 +00:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_COLLECT ;
2025-05-05 23:44:49 +02:00
CRegion frameDamage { g_pHyprOpenGL - > m_renderData . damage } ;
2023-03-24 19:23:16 +00:00
2025-04-30 23:45:20 +02:00
const auto TRANSFORM = invertTransform ( pMonitor - > m_transform ) ;
frameDamage . transform ( wlTransformToHyprutils ( TRANSFORM ) , pMonitor - > m_transformedSize . x , pMonitor - > m_transformedSize . y ) ;
2023-03-24 19:23:16 +00:00
2024-12-29 17:19:12 -06:00
if ( * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_NONE | | * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_MONITOR )
2025-08-14 19:44:56 +05:00
frameDamage . add ( 0 , 0 , sc < int > ( pMonitor - > m_transformedSize . x ) , sc < int > ( pMonitor - > m_transformedSize . y ) ) ;
2023-03-24 19:23:16 +00:00
2024-12-29 17:19:12 -06:00
if ( * PDAMAGEBLINK )
frameDamage . add ( damage ) ;
2023-03-24 19:23:16 +00:00
2025-04-30 23:45:20 +02:00
if ( ! pMonitor - > m_mirrors . empty ( ) )
2024-12-22 17:12:09 +01:00
damageMirrorsWith ( pMonitor , frameDamage ) ;
2024-07-30 15:46:35 +02:00
2025-04-30 23:45:20 +02:00
pMonitor - > m_renderingActive = false ;
2023-03-24 19:23:16 +00:00
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST ) ;
2025-04-30 23:45:20 +02:00
pMonitor - > m_output - > state - > addDamage ( frameDamage ) ;
pMonitor - > m_output - > state - > setPresentationMode ( shouldTear ? Aquamarine : : eOutputPresentationMode : : AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine : : eOutputPresentationMode : : AQ_OUTPUT_PRESENTATION_VSYNC ) ;
2023-09-28 21:48:33 +01:00
2025-07-08 12:41:10 +02:00
if ( commit )
commitPendingAndDoExplicitSync ( pMonitor ) ;
2023-04-03 17:01:05 +01:00
2023-09-28 21:48:33 +01:00
if ( shouldTear )
2025-04-30 23:45:20 +02:00
pMonitor - > m_tearingState . busy = true ;
2023-09-28 21:48:33 +01:00
2025-04-30 23:45:20 +02:00
if ( * PDAMAGEBLINK | | * PVFR = = 0 | | pMonitor - > m_pendingFrame )
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( pMonitor , Aquamarine : : IOutput : : AQ_SCHEDULE_RENDER_MONITOR ) ;
2023-03-24 19:23:16 +00:00
2025-04-30 23:45:20 +02:00
pMonitor - > m_pendingFrame = false ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( * PDEBUGOVERLAY = = 1 ) {
2025-07-04 09:39:53 +02:00
const float durationUs = std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( std : : chrono : : high_resolution_clock : : now ( ) - renderStart ) . count ( ) / 1000.f ;
g_pDebugOverlay - > renderData ( pMonitor , durationUs ) ;
2025-04-22 15:23:29 +02:00
if ( pMonitor = = g_pCompositor - > m_monitors . front ( ) ) {
2024-08-12 19:19:03 +02:00
const float noOverlayUs = durationUs - std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( endRenderOverlay - renderStartOverlay ) . count ( ) / 1000.f ;
g_pDebugOverlay - > renderDataNoOverlay ( pMonitor , noOverlayUs ) ;
2024-12-22 17:12:09 +01:00
} else
2024-08-12 19:19:03 +02:00
g_pDebugOverlay - > renderDataNoOverlay ( pMonitor , durationUs ) ;
2023-03-24 19:23:16 +00:00
}
}
2025-03-14 02:15:18 +03:00
static const hdr_output_metadata NO_HDR_METADATA = { . hdmi_metadata_type1 = hdr_metadata_infoframe { . eotf = 0 } } ;
2025-01-07 21:32:50 +03:00
2025-08-19 21:28:52 +03:00
static hdr_output_metadata createHDRMetadata ( SImageDescription settings , SP < CMonitor > monitor ) {
2025-03-24 15:56:07 +03:00
uint8_t eotf = 0 ;
switch ( settings . transferFunction ) {
case CM_TRANSFER_FUNCTION_SRGB : eotf = 0 ; break ; // used to send primaries and luminances to AQ. ignored for now
case CM_TRANSFER_FUNCTION_ST2084_PQ : eotf = 2 ; break ;
2025-08-22 13:13:55 +03:00
case CM_TRANSFER_FUNCTION_EXT_LINEAR :
eotf = 2 ;
break ; // should be Windows scRGB
2025-03-24 15:56:07 +03:00
// case CM_TRANSFER_FUNCTION_HLG: eotf = 3; break; TODO check display capabilities first
default : return NO_HDR_METADATA ; // empty metadata for SDR
}
2025-01-07 21:32:50 +03:00
2025-08-14 19:44:56 +05:00
const auto toNits = [ ] ( uint32_t value ) { return sc < uint16_t > ( std : : round ( value ) ) ; } ;
const auto to16Bit = [ ] ( float value ) { return sc < uint16_t > ( std : : round ( value * 50000 ) ) ; } ;
2025-01-07 21:32:50 +03:00
2025-03-14 02:15:18 +03:00
auto colorimetry = settings . primariesNameSet | | settings . primaries = = SPCPRimaries { } ? getPrimaries ( settings . primariesNamed ) : settings . primaries ;
2025-08-19 21:28:52 +03:00
auto luminances = settings . masteringLuminances . max > 0 ? settings . masteringLuminances :
SImageDescription : : SPCMasteringLuminances { . min = monitor - > minLuminance ( ) , . max = monitor - > maxLuminance ( 10000 ) } ;
2025-01-07 21:32:50 +03:00
Debug : : log ( TRACE , " ColorManagement primaries {},{} {},{} {},{} {},{} " , colorimetry . red . x , colorimetry . red . y , colorimetry . green . x , colorimetry . green . y , colorimetry . blue . x ,
2025-03-14 02:15:18 +03:00
colorimetry . blue . y , colorimetry . white . x , colorimetry . white . y ) ;
2025-01-07 21:32:50 +03:00
Debug : : log ( TRACE , " ColorManagement min {}, max {}, cll {}, fall {} " , luminances . min , luminances . max , settings . maxCLL , settings . maxFALL ) ;
return hdr_output_metadata {
2025-03-14 02:15:18 +03:00
. metadata_type = 0 ,
. hdmi_metadata_type1 =
2025-01-07 21:32:50 +03:00
hdr_metadata_infoframe {
2025-03-24 15:56:07 +03:00
. eotf = eotf ,
2025-03-14 02:15:18 +03:00
. metadata_type = 0 ,
. display_primaries =
{
2025-01-07 21:32:50 +03:00
{ . x = to16Bit ( colorimetry . red . x ) , . y = to16Bit ( colorimetry . red . y ) } ,
{ . x = to16Bit ( colorimetry . green . x ) , . y = to16Bit ( colorimetry . green . y ) } ,
{ . x = to16Bit ( colorimetry . blue . x ) , . y = to16Bit ( colorimetry . blue . y ) } ,
} ,
2025-03-14 02:15:18 +03:00
. white_point = { . x = to16Bit ( colorimetry . white . x ) , . y = to16Bit ( colorimetry . white . y ) } ,
. max_display_mastering_luminance = toNits ( luminances . max ) ,
. min_display_mastering_luminance = toNits ( luminances . min * 10000 ) ,
. max_cll = toNits ( settings . maxCLL ) ,
. max_fall = toNits ( settings . maxFALL ) ,
2025-01-07 21:32:50 +03:00
} ,
} ;
}
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : commitPendingAndDoExplicitSync ( PHLMONITOR pMonitor ) {
2025-06-23 15:33:09 +03:00
static auto PCT = CConfigValue < Hyprlang : : INT > ( " render:send_content_type " ) ;
static auto PPASS = CConfigValue < Hyprlang : : INT > ( " render:cm_fs_passthrough " ) ;
static auto PAUTOHDR = CConfigValue < Hyprlang : : INT > ( " render:cm_auto_hdr " ) ;
const bool configuredHDR = ( pMonitor - > m_cmType = = CM_HDR_EDID | | pMonitor - > m_cmType = = CM_HDR ) ;
bool wantHDR = configuredHDR ;
2025-01-07 21:32:50 +03:00
2025-06-15 13:15:18 +03:00
if ( pMonitor - > supportsHDR ( ) ) {
2025-03-24 15:56:07 +03:00
// HDR metadata determined by
// PPASS = 0 monitor settings
// PPASS = 1
// windowed: monitor settings
// fullscreen surface: surface settings FIXME: fullscreen SDR surface passthrough - pass degamma, ctm, gamma if needed
// PPASS = 2
// windowed: monitor settings
// fullscreen SDR surface: monitor settings
// fullscreen HDR surface: surface settings
bool hdrIsHandled = false ;
2025-06-23 15:33:09 +03:00
if ( pMonitor - > m_activeWorkspace & & pMonitor - > m_activeWorkspace - > m_hasFullscreenWindow & & pMonitor - > m_activeWorkspace - > m_fullscreenMode = = FSMODE_FULLSCREEN ) {
2025-04-30 23:45:20 +02:00
const auto WINDOW = pMonitor - > m_activeWorkspace - > getFullscreenWindow ( ) ;
2025-04-28 22:25:22 +02:00
const auto ROOT_SURF = WINDOW - > m_wlSurface - > resource ( ) ;
2025-02-26 17:56:37 +03:00
const auto SURF =
2025-05-03 16:02:49 +02:00
ROOT_SURF - > findFirstPreorder ( [ ROOT_SURF ] ( SP < CWLSurfaceResource > surf ) { return surf - > m_colorManagement . valid ( ) & & surf - > extends ( ) = = ROOT_SURF - > extends ( ) ; } ) ;
2025-02-26 17:56:37 +03:00
2025-06-23 15:33:09 +03:00
// we have a surface with image description
if ( SURF & & SURF - > m_colorManagement . valid ( ) & & SURF - > m_colorManagement - > hasImageDescription ( ) ) {
2025-08-22 13:13:55 +03:00
const bool surfaceIsHDR = SURF - > m_colorManagement - > isHDR ( ) ;
2025-06-23 15:33:09 +03:00
if ( * PPASS = = 1 | | ( * PPASS = = 2 & & surfaceIsHDR ) ) {
// passthrough
bool needsHdrMetadataUpdate = SURF - > m_colorManagement - > needsHdrMetadataUpdate ( ) | | pMonitor - > m_previousFSWindow ! = WINDOW ;
if ( SURF - > m_colorManagement - > needsHdrMetadataUpdate ( ) )
2025-08-19 21:28:52 +03:00
SURF - > m_colorManagement - > setHDRMetadata ( createHDRMetadata ( SURF - > m_colorManagement - > imageDescription ( ) , pMonitor ) ) ;
2025-06-23 15:33:09 +03:00
if ( needsHdrMetadataUpdate )
pMonitor - > m_output - > state - > setHDRMetadata ( SURF - > m_colorManagement - > hdrMetadata ( ) ) ;
hdrIsHandled = true ;
} else if ( * PAUTOHDR & & surfaceIsHDR )
wantHDR = true ; // auto-hdr: hdr on
2025-03-24 15:56:07 +03:00
}
2025-01-17 23:23:57 +03:00
pMonitor - > m_previousFSWindow = WINDOW ;
2025-03-24 15:56:07 +03:00
}
2025-06-23 15:33:09 +03:00
2025-03-24 15:56:07 +03:00
if ( ! hdrIsHandled ) {
2025-08-22 13:13:55 +03:00
if ( pMonitor - > inHDR ( ) ! = wantHDR ) {
if ( * PAUTOHDR & & ! ( pMonitor - > inHDR ( ) & & configuredHDR ) ) {
2025-06-23 15:33:09 +03:00
// modify or restore monitor image description for auto-hdr
// FIXME ok for now, will need some other logic if monitor image description can be modified some other way
pMonitor - > applyCMType ( wantHDR ? ( * PAUTOHDR = = 2 ? CM_HDR_EDID : CM_HDR ) : pMonitor - > m_cmType ) ;
}
2025-08-19 21:28:52 +03:00
pMonitor - > m_output - > state - > setHDRMetadata ( wantHDR ? createHDRMetadata ( pMonitor - > m_imageDescription , pMonitor ) : NO_HDR_METADATA ) ;
2025-06-23 15:33:09 +03:00
}
2025-01-17 23:23:57 +03:00
pMonitor - > m_previousFSWindow . reset ( ) ;
}
}
2025-08-22 13:13:55 +03:00
const bool needsWCG = pMonitor - > wantsWideColor ( ) ;
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_output - > state - > state ( ) . wideColorGamut ! = needsWCG ) {
2025-01-17 23:23:57 +03:00
Debug : : log ( TRACE , " Setting wide color gamut {} " , needsWCG ? " on " : " off " ) ;
2025-04-30 23:45:20 +02:00
pMonitor - > m_output - > state - > setWideColorGamut ( needsWCG ) ;
2025-01-17 23:23:57 +03:00
// FIXME do not trust enabled10bit, auto switch to 10bit and back if needed
2025-04-30 23:45:20 +02:00
if ( needsWCG & & ! pMonitor - > m_enabled10bit ) {
2025-01-17 23:23:57 +03:00
Debug : : log ( WARN , " Wide color gamut is enabled but the display is not in 10bit mode " ) ;
static bool shown = false ;
if ( ! shown ) {
g_pHyprNotificationOverlay - > addNotification ( " Wide color gamut is enabled but the display is not in 10bit mode " , CHyprColor { } , 15000 , ICON_WARNING ) ;
shown = true ;
}
2025-01-12 20:02:41 +03:00
}
2025-01-07 21:32:50 +03:00
}
2025-04-29 23:09:14 +03:00
if ( * PCT ) {
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_activeWorkspace & & pMonitor - > m_activeWorkspace - > m_hasFullscreenWindow & & pMonitor - > m_activeWorkspace - > m_fullscreenMode = = FSMODE_FULLSCREEN ) {
const auto WINDOW = pMonitor - > m_activeWorkspace - > getFullscreenWindow ( ) ;
pMonitor - > m_output - > state - > setContentType ( NContentType : : toDRM ( WINDOW - > getContentType ( ) ) ) ;
2025-04-29 23:09:14 +03:00
} else
2025-04-30 23:45:20 +02:00
pMonitor - > m_output - > state - > setContentType ( NContentType : : toDRM ( CONTENT_TYPE_NONE ) ) ;
2025-04-29 23:09:14 +03:00
}
2025-02-02 22:25:29 +03:00
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_ctmUpdated ) {
pMonitor - > m_ctmUpdated = false ;
pMonitor - > m_output - > state - > setCTM ( pMonitor - > m_ctm ) ;
2024-10-08 16:59:15 +01:00
}
2025-04-30 23:45:20 +02:00
bool ok = pMonitor - > m_state . commit ( ) ;
2024-08-06 14:52:19 +01:00
if ( ! ok ) {
2025-04-30 23:45:20 +02:00
if ( pMonitor - > m_inFence . isValid ( ) ) {
2024-08-06 14:52:19 +01:00
Debug : : log ( TRACE , " Monitor state commit failed, retrying without a fence " ) ;
2025-04-30 23:45:20 +02:00
pMonitor - > m_output - > state - > resetExplicitFences ( ) ;
ok = pMonitor - > m_state . commit ( ) ;
2024-07-21 13:09:54 +02:00
}
2024-08-06 14:52:19 +01:00
if ( ! ok ) {
Debug : : log ( TRACE , " Monitor state commit failed " ) ;
// rollback the buffer to avoid writing to the front buffer that is being
// displayed
2025-04-30 23:45:20 +02:00
pMonitor - > m_output - > swapchain - > rollback ( ) ;
pMonitor - > m_damage . damageEntire ( ) ;
2024-08-06 14:52:19 +01:00
}
2024-07-21 13:09:54 +02:00
}
return ok ;
}
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , const Time : : steady_tp & now , const CBox & geometry ) {
2023-04-12 12:41:23 +01:00
Vector2D translate = { geometry . x , geometry . y } ;
2025-08-14 19:44:56 +05:00
float scale = sc < float > ( geometry . width ) / pMonitor - > m_pixelSize . x ;
2023-04-12 12:41:23 +01:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderWorkspace " ) ;
2025-08-14 19:44:56 +05:00
if ( ! DELTALESSTHAN ( sc < double > ( geometry . width ) / sc < double > ( geometry . height ) , pMonitor - > m_pixelSize . x / pMonitor - > m_pixelSize . y , 0.01 ) ) {
2023-04-12 12:41:23 +01:00
Debug : : log ( ERR , " Ignoring geometry in renderWorkspace: aspect ratio mismatch " ) ;
scale = 1.f ;
translate = Vector2D { } ;
}
2023-04-12 13:05:57 +01:00
renderAllClientsForWorkspace ( pMonitor , pWorkspace , now , translate , scale ) ;
2023-04-12 12:41:23 +01:00
}
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : sendFrameEventsToWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , const Time : : steady_tp & now ) {
2025-04-22 15:23:29 +02:00
for ( auto const & w : g_pCompositor - > m_windows ) {
2025-04-28 22:25:22 +02:00
if ( w - > isHidden ( ) | | ! w - > m_isMapped | | w - > m_fadingOut | | ! w - > m_wlSurface - > resource ( ) )
2024-04-23 16:08:54 +01:00
continue ;
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2024-04-23 16:08:54 +01:00
continue ;
2025-04-28 22:25:22 +02:00
w - > m_wlSurface - > resource ( ) - > breadthfirst ( [ now ] ( SP < CWLSurfaceResource > r , const Vector2D & offset , void * d ) { r - > frame ( now ) ; } , nullptr ) ;
2024-04-23 16:08:54 +01:00
}
2025-04-30 23:45:20 +02:00
for ( auto const & lsl : pMonitor - > m_layerSurfaceLayers ) {
2024-08-26 17:25:39 +02:00
for ( auto const & ls : lsl ) {
2025-04-24 20:49:49 +02:00
if ( ls - > m_fadingOut | | ! ls - > m_surface - > resource ( ) )
2024-04-23 21:15:37 +01:00
continue ;
2025-04-24 20:49:49 +02:00
ls - > m_surface - > resource ( ) - > breadthfirst ( [ now ] ( SP < CWLSurfaceResource > r , const Vector2D & offset , void * d ) { r - > frame ( now ) ; } , nullptr ) ;
2024-04-23 16:08:54 +01:00
}
}
}
2024-10-26 02:06:13 +01:00
void CHyprRenderer : : setSurfaceScanoutMode ( SP < CWLSurfaceResource > surface , PHLMONITOR monitor ) {
2024-07-21 13:09:54 +02:00
if ( ! PROTO : : linuxDma )
return ;
2022-11-05 12:50:47 +00:00
2024-07-21 13:09:54 +02:00
PROTO : : linuxDma - > updateScanoutTranche ( surface , monitor ) ;
2022-11-05 12:50:47 +00:00
}
2022-03-21 17:00:17 +01:00
// taken from Sway.
// this is just too much of a spaghetti for me to understand
2024-07-22 23:36:58 +02:00
static void applyExclusive ( CBox & usableArea , uint32_t anchor , int32_t exclusive , uint32_t exclusiveEdge , int32_t marginTop , int32_t marginRight , int32_t marginBottom ,
int32_t marginLeft ) {
2022-03-21 17:00:17 +01:00
if ( exclusive < = 0 ) {
return ;
}
struct {
uint32_t singular_anchor ;
uint32_t anchor_triplet ;
2024-06-19 16:20:06 +02:00
double * positive_axis ;
double * negative_axis ;
2022-12-16 17:17:31 +00:00
int margin ;
2022-03-21 17:00:17 +01:00
} edges [ ] = {
// Top
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ,
2022-12-16 17:17:31 +00:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ,
2023-12-19 11:55:56 +00:00
. positive_axis = & usableArea . y ,
. negative_axis = & usableArea . height ,
. margin = marginTop ,
2022-03-21 17:00:17 +01:00
} ,
// Bottom
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
2022-12-16 17:17:31 +00:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
2024-12-07 18:51:18 +01:00
. positive_axis = nullptr ,
2023-12-19 11:55:56 +00:00
. negative_axis = & usableArea . height ,
. margin = marginBottom ,
2022-03-21 17:00:17 +01:00
} ,
// Left
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ,
2022-12-16 17:17:31 +00:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
2023-12-19 11:55:56 +00:00
. positive_axis = & usableArea . x ,
. negative_axis = & usableArea . width ,
. margin = marginLeft ,
2022-03-21 17:00:17 +01:00
} ,
// Right
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ,
2022-12-16 17:17:31 +00:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
2024-12-07 18:51:18 +01:00
. positive_axis = nullptr ,
2023-12-19 11:55:56 +00:00
. negative_axis = & usableArea . width ,
. margin = marginRight ,
2022-03-21 17:00:17 +01:00
} ,
} ;
for ( size_t i = 0 ; i < sizeof ( edges ) / sizeof ( edges [ 0 ] ) ; + + i ) {
2024-07-22 23:36:58 +02:00
if ( ( exclusiveEdge = = edges [ i ] . singular_anchor | | anchor = = edges [ i ] . singular_anchor | | anchor = = edges [ i ] . anchor_triplet ) & & exclusive + edges [ i ] . margin > 0 ) {
2022-03-21 17:00:17 +01:00
if ( edges [ i ] . positive_axis ) {
* edges [ i ] . positive_axis + = exclusive + edges [ i ] . margin ;
}
if ( edges [ i ] . negative_axis ) {
* edges [ i ] . negative_axis - = exclusive + edges [ i ] . margin ;
}
break ;
}
}
}
2022-03-19 14:37:40 +01:00
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : arrangeLayerArray ( PHLMONITOR pMonitor , const std : : vector < PHLLSREF > & layerSurfaces , bool exclusiveZone , CBox * usableArea ) {
2025-04-30 23:45:20 +02:00
CBox full_area = { pMonitor - > m_position . x , pMonitor - > m_position . y , pMonitor - > m_size . x , pMonitor - > m_size . y } ;
2022-03-19 14:37:40 +01:00
2024-08-26 20:24:30 +02:00
for ( auto const & ls : layerSurfaces ) {
2025-04-24 20:49:49 +02:00
if ( ! ls | | ls - > m_fadingOut | | ls - > m_readyToDelete | | ! ls - > m_layerSurface | | ls - > m_noProcess )
2022-05-14 17:23:46 +02:00
continue ;
2025-04-24 20:49:49 +02:00
const auto PLAYER = ls - > m_layerSurface ;
2025-05-04 00:13:29 +02:00
const auto PSTATE = & PLAYER - > m_current ;
2024-05-09 21:47:21 +01:00
if ( exclusiveZone ! = ( PSTATE - > exclusive > 0 ) )
2022-03-21 17:00:17 +01:00
continue ;
2022-03-19 14:37:40 +01:00
2023-11-04 17:03:05 +00:00
CBox bounds ;
2024-05-09 21:47:21 +01:00
if ( PSTATE - > exclusive = = - 1 )
2022-03-21 17:00:17 +01:00
bounds = full_area ;
2023-10-06 14:00:05 +01:00
else
2022-03-21 17:00:17 +01:00
bounds = * usableArea ;
2022-03-19 14:37:40 +01:00
2025-04-24 20:49:49 +02:00
const Vector2D OLDSIZE = { ls - > m_geometry . width , ls - > m_geometry . height } ;
2023-10-06 14:00:05 +01:00
2024-05-09 21:47:21 +01:00
CBox box = { { } , PSTATE - > desiredSize } ;
2022-03-21 17:00:17 +01:00
// Horizontal axis
const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ;
2024-10-19 23:47:28 +01:00
if ( box . width = = 0 )
2022-03-21 17:00:17 +01:00
box . x = bounds . x ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & both_horiz ) = = both_horiz )
2022-03-21 17:00:17 +01:00
box . x = bounds . x + ( ( bounds . width / 2 ) - ( box . width / 2 ) ) ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ) )
2022-03-21 17:00:17 +01:00
box . x = bounds . x ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ) )
2022-03-21 17:00:17 +01:00
box . x = bounds . x + ( bounds . width - box . width ) ;
2024-10-19 23:47:28 +01:00
else
2022-03-21 17:00:17 +01:00
box . x = bounds . x + ( ( bounds . width / 2 ) - ( box . width / 2 ) ) ;
2024-10-19 23:47:28 +01:00
2022-03-21 17:00:17 +01:00
// Vertical axis
const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ;
2024-10-19 23:47:28 +01:00
if ( box . height = = 0 )
2022-03-21 17:00:17 +01:00
box . y = bounds . y ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & both_vert ) = = both_vert )
2022-03-21 17:00:17 +01:00
box . y = bounds . y + ( ( bounds . height / 2 ) - ( box . height / 2 ) ) ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ) )
2022-03-21 17:00:17 +01:00
box . y = bounds . y ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ) )
2022-03-21 17:00:17 +01:00
box . y = bounds . y + ( bounds . height - box . height ) ;
2024-10-19 23:47:28 +01:00
else
2022-03-21 17:00:17 +01:00
box . y = bounds . y + ( ( bounds . height / 2 ) - ( box . height / 2 ) ) ;
2024-10-19 23:47:28 +01:00
2022-03-21 17:00:17 +01:00
// Margin
if ( box . width = = 0 ) {
box . x + = PSTATE - > margin . left ;
2022-12-16 17:17:31 +00:00
box . width = bounds . width - ( PSTATE - > margin . left + PSTATE - > margin . right ) ;
2024-10-19 23:47:28 +01:00
} else if ( ( PSTATE - > anchor & both_horiz ) = = both_horiz )
; // don't apply margins
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ) )
2022-03-21 17:00:17 +01:00
box . x + = PSTATE - > margin . left ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ) )
2022-03-21 17:00:17 +01:00
box . x - = PSTATE - > margin . right ;
2024-10-19 23:47:28 +01:00
2022-03-21 17:00:17 +01:00
if ( box . height = = 0 ) {
box . y + = PSTATE - > margin . top ;
2022-12-16 17:17:31 +00:00
box . height = bounds . height - ( PSTATE - > margin . top + PSTATE - > margin . bottom ) ;
2024-10-19 23:47:28 +01:00
} else if ( ( PSTATE - > anchor & both_vert ) = = both_vert )
; // don't apply margins
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ) )
2022-03-21 17:00:17 +01:00
box . y + = PSTATE - > margin . top ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ) )
2022-03-21 17:00:17 +01:00
box . y - = PSTATE - > margin . bottom ;
2024-10-19 23:47:28 +01:00
2022-03-21 17:00:17 +01:00
if ( box . width < = 0 | | box . height < = 0 ) {
2025-08-14 19:44:56 +05:00
Debug : : log ( ERR , " LayerSurface {:x} has a negative/zero w/h??? " , rc < uintptr_t > ( ls . get ( ) ) ) ;
2022-03-21 17:00:17 +01:00
continue ;
2022-03-20 14:52:23 +01:00
}
2024-10-19 23:45:51 +01:00
box . round ( ) ; // fix rounding errors
2025-04-24 20:49:49 +02:00
ls - > m_geometry = box ;
2022-03-20 14:52:23 +01:00
2024-07-22 23:36:58 +02:00
applyExclusive ( * usableArea , PSTATE - > anchor , PSTATE - > exclusive , PSTATE - > exclusiveEdge , PSTATE - > margin . top , PSTATE - > margin . right , PSTATE - > margin . bottom , PSTATE - > margin . left ) ;
2022-03-19 14:37:40 +01:00
2023-10-06 14:00:05 +01:00
if ( Vector2D { box . width , box . height } ! = OLDSIZE )
2025-04-24 20:49:49 +02:00
ls - > m_layerSurface - > configure ( box . size ( ) ) ;
2024-03-27 16:30:08 +00:00
2025-04-24 20:49:49 +02:00
* ls - > m_realPosition = box . pos ( ) ;
* ls - > m_realSize = box . size ( ) ;
2022-03-19 14:37:40 +01:00
}
}
2024-08-08 21:01:50 +02:00
void CHyprRenderer : : arrangeLayersForMonitor ( const MONITORID & monitor ) {
2024-10-08 21:58:40 +01:00
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( monitor ) ;
static auto BAR_POSITION = CConfigValue < Hyprlang : : INT > ( " debug:error_position " ) ;
2022-03-19 14:37:40 +01:00
if ( ! PMONITOR )
return ;
// Reset the reserved
2025-04-30 23:45:20 +02:00
PMONITOR - > m_reservedBottomRight = Vector2D ( ) ;
PMONITOR - > m_reservedTopLeft = Vector2D ( ) ;
2022-03-19 14:37:40 +01:00
2025-04-30 23:45:20 +02:00
CBox usableArea = { PMONITOR - > m_position . x , PMONITOR - > m_position . y , PMONITOR - > m_size . x , PMONITOR - > m_size . y } ;
2022-03-21 17:00:17 +01:00
2025-04-30 23:45:20 +02:00
if ( g_pHyprError - > active ( ) & & g_pCompositor - > m_lastMonitor = = PMONITOR - > m_self ) {
2024-10-08 21:58:40 +01:00
const auto HEIGHT = g_pHyprError - > height ( ) ;
if ( * BAR_POSITION = = 0 ) {
2025-04-30 23:45:20 +02:00
PMONITOR - > m_reservedTopLeft . y = HEIGHT ;
2024-10-08 21:58:40 +01:00
usableArea . y + = HEIGHT ;
usableArea . h - = HEIGHT ;
} else {
2025-04-30 23:45:20 +02:00
PMONITOR - > m_reservedBottomRight . y = HEIGHT ;
2024-10-08 21:58:40 +01:00
usableArea . h - = HEIGHT ;
}
2024-10-08 21:20:25 +01:00
}
2025-04-30 23:45:20 +02:00
for ( auto & la : PMONITOR - > m_layerSurfaceLayers ) {
2025-05-30 18:25:59 +05:00
std : : ranges : : stable_sort ( la , [ ] ( const PHLLSREF & a , const PHLLSREF & b ) { return a - > m_order > b - > m_order ; } ) ;
2024-09-09 11:10:08 +02:00
}
2025-04-30 23:45:20 +02:00
for ( auto const & la : PMONITOR - > m_layerSurfaceLayers )
2022-03-21 17:00:17 +01:00
arrangeLayerArray ( PMONITOR , la , true , & usableArea ) ;
2025-04-30 23:45:20 +02:00
for ( auto const & la : PMONITOR - > m_layerSurfaceLayers )
2022-03-21 17:00:17 +01:00
arrangeLayerArray ( PMONITOR , la , false , & usableArea ) ;
2025-04-30 23:45:20 +02:00
PMONITOR - > m_reservedTopLeft = Vector2D ( usableArea . x , usableArea . y ) - PMONITOR - > m_position ;
PMONITOR - > m_reservedBottomRight = PMONITOR - > m_size - Vector2D ( usableArea . width , usableArea . height ) - PMONITOR - > m_reservedTopLeft ;
2022-03-21 17:00:17 +01:00
2025-04-30 23:45:20 +02:00
auto ADDITIONALRESERVED = g_pConfigManager - > m_mAdditionalReservedAreas . find ( PMONITOR - > m_name ) ;
2022-10-17 23:23:01 +01:00
if ( ADDITIONALRESERVED = = g_pConfigManager - > m_mAdditionalReservedAreas . end ( ) ) {
2022-12-16 17:17:31 +00:00
ADDITIONALRESERVED = g_pConfigManager - > m_mAdditionalReservedAreas . find ( " " ) ; // glob wildcard
2022-10-17 23:23:01 +01:00
}
if ( ADDITIONALRESERVED ! = g_pConfigManager - > m_mAdditionalReservedAreas . end ( ) ) {
2025-04-30 23:45:20 +02:00
PMONITOR - > m_reservedTopLeft = PMONITOR - > m_reservedTopLeft + Vector2D ( ADDITIONALRESERVED - > second . left , ADDITIONALRESERVED - > second . top ) ;
PMONITOR - > m_reservedBottomRight = PMONITOR - > m_reservedBottomRight + Vector2D ( ADDITIONALRESERVED - > second . right , ADDITIONALRESERVED - > second . bottom ) ;
2022-10-17 23:23:01 +01:00
}
2022-04-27 17:46:07 +02:00
2022-05-04 15:23:30 +02:00
// damage the monitor if can
2023-04-07 12:18:40 +01:00
damageMonitor ( PMONITOR ) ;
2022-05-04 15:23:30 +02:00
2022-09-08 14:11:32 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitor ) ;
2022-03-19 16:13:19 +01:00
}
2024-06-08 10:07:59 +02:00
void CHyprRenderer : : damageSurface ( SP < CWLSurfaceResource > pSurface , double x , double y , double scale ) {
2022-04-14 16:43:29 +02:00
if ( ! pSurface )
return ; // wut?
2022-03-21 16:13:43 +01:00
2025-04-22 15:23:29 +02:00
if ( g_pCompositor - > m_unsafeState )
2022-08-10 23:14:53 +02:00
return ;
2024-06-08 10:07:59 +02:00
const auto WLSURF = CWLSurface : : fromResource ( pSurface ) ;
2024-07-22 12:37:54 +02:00
CRegion damageBox = WLSURF ? WLSURF - > computeDamage ( ) : CRegion { } ;
2024-02-19 11:34:55 +00:00
if ( ! WLSURF ) {
2024-02-19 11:24:54 +00:00
Debug : : log ( ERR , " BUG THIS: No CWLSurface for surface in damageSurface!!! " ) ;
2024-06-08 10:07:59 +02:00
return ;
2024-02-19 11:34:55 +00:00
}
2024-04-08 15:33:02 +01:00
2023-06-11 21:52:13 +02:00
if ( scale ! = 1.0 )
2024-02-19 11:24:54 +00:00
damageBox . scale ( scale ) ;
2022-03-21 16:13:43 +01:00
2022-07-04 17:55:33 +02:00
// schedule frame events
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( g_pCompositor - > getMonitorFromVector ( Vector2D ( x , y ) ) , Aquamarine : : IOutput : : AQ_SCHEDULE_DAMAGE ) ;
2022-07-04 17:55:33 +02:00
2023-07-19 20:09:49 +02:00
if ( damageBox . empty ( ) )
2022-06-28 15:30:46 +02:00
return ;
2024-02-19 11:24:54 +00:00
damageBox . translate ( { x , y } ) ;
2023-07-19 20:09:49 +02:00
CRegion damageBoxForEach ;
2022-07-28 22:15:56 +02:00
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_monitors ) {
2025-04-30 23:45:20 +02:00
if ( ! m - > m_output )
2023-03-16 16:32:03 +00:00
continue ;
2024-02-19 11:24:54 +00:00
damageBoxForEach . set ( damageBox ) ;
2025-04-30 23:45:20 +02:00
damageBoxForEach . translate ( { - m - > m_position . x , - m - > m_position . y } ) . scale ( m - > m_scale ) ;
2022-07-28 22:15:56 +02:00
2025-01-26 15:05:34 +00:00
m - > addDamage ( damageBoxForEach ) ;
2022-03-21 16:13:43 +01:00
}
2024-03-03 18:39:20 +00:00
static auto PLOGDAMAGE = CConfigValue < Hyprlang : : INT > ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-03-03 18:39:20 +00:00
if ( * PLOGDAMAGE )
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " Damage: Surface (extents): xy: {}, {} wh: {}, {} " , damageBox . pixman ( ) - > extents . x1 , damageBox . pixman ( ) - > extents . y1 ,
2023-07-19 20:09:49 +02:00
damageBox . pixman ( ) - > extents . x2 - damageBox . pixman ( ) - > extents . x1 , damageBox . pixman ( ) - > extents . y2 - damageBox . pixman ( ) - > extents . y1 ) ;
2022-04-14 16:43:29 +02:00
}
2022-03-21 16:13:43 +01:00
2024-04-27 12:43:12 +01:00
void CHyprRenderer : : damageWindow ( PHLWINDOW pWindow , bool forceFull ) {
2025-04-22 15:23:29 +02:00
if ( g_pCompositor - > m_unsafeState )
2022-08-10 23:14:53 +02:00
return ;
2024-03-30 18:14:26 -07:00
CBox windowBox = pWindow - > getFullWindowBoundingBox ( ) ;
2025-04-28 22:25:22 +02:00
const auto PWINDOWWORKSPACE = pWindow - > m_workspace ;
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_renderOffset - > isBeingAnimated ( ) & & ! pWindow - > m_pinned )
2025-04-25 02:37:12 +02:00
windowBox . translate ( PWINDOWWORKSPACE - > m_renderOffset - > value ( ) ) ;
2025-04-28 22:25:22 +02:00
windowBox . translate ( pWindow - > m_floatingOffset ) ;
2024-03-30 18:14:26 -07:00
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_monitors ) {
2024-12-22 17:12:09 +01:00
if ( forceFull | | shouldRenderWindow ( pWindow , m ) ) { // only damage if window is rendered on monitor
2025-04-30 23:45:20 +02:00
CBox fixedDamageBox = { windowBox . x - m - > m_position . x , windowBox . y - m - > m_position . y , windowBox . width , windowBox . height } ;
fixedDamageBox . scale ( m - > m_scale ) ;
2025-01-26 15:05:34 +00:00
m - > addDamage ( fixedDamageBox ) ;
2024-03-30 18:14:26 -07:00
}
2022-06-29 11:21:42 +02:00
}
2022-05-05 15:09:26 +02:00
2025-04-28 22:25:22 +02:00
for ( auto const & wd : pWindow - > m_windowDecorations )
2023-06-27 13:23:53 +02:00
wd - > damageEntire ( ) ;
2024-03-03 18:39:20 +00:00
static auto PLOGDAMAGE = CConfigValue < Hyprlang : : INT > ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-03-03 18:39:20 +00:00
if ( * PLOGDAMAGE )
2025-04-28 22:25:22 +02:00
Debug : : log ( LOG , " Damage: Window ({}): xy: {}, {} wh: {}, {} " , pWindow - > m_title , windowBox . x , windowBox . y , windowBox . width , windowBox . height ) ;
2022-03-21 16:13:43 +01:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : damageMonitor ( PHLMONITOR pMonitor ) {
2025-04-22 15:23:29 +02:00
if ( g_pCompositor - > m_unsafeState | | pMonitor - > isMirror ( ) )
2022-08-10 23:14:53 +02:00
return ;
2023-11-04 17:03:05 +00:00
CBox damageBox = { 0 , 0 , INT16_MAX , INT16_MAX } ;
2025-01-26 15:05:34 +00:00
pMonitor - > addDamage ( damageBox ) ;
2022-05-05 15:09:26 +02:00
2024-03-03 18:39:20 +00:00
static auto PLOGDAMAGE = CConfigValue < Hyprlang : : INT > ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-03-03 18:39:20 +00:00
if ( * PLOGDAMAGE )
2025-04-30 23:45:20 +02:00
Debug : : log ( LOG , " Damage: Monitor {} " , pMonitor - > m_name ) ;
2022-04-14 16:43:29 +02:00
}
2022-03-21 16:13:43 +01:00
2025-01-26 15:05:34 +00:00
void CHyprRenderer : : damageBox ( const CBox & box , bool skipFrameSchedule ) {
2025-04-22 15:23:29 +02:00
if ( g_pCompositor - > m_unsafeState )
2022-08-10 23:14:53 +02:00
return ;
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_monitors ) {
2022-09-13 15:25:42 +02:00
if ( m - > isMirror ( ) )
continue ; // don't damage mirrors traditionally
2024-10-31 00:20:32 +01:00
if ( ! skipFrameSchedule ) {
2025-04-30 23:45:20 +02:00
CBox damageBox = box . copy ( ) . translate ( - m - > m_position ) . scale ( m - > m_scale ) ;
2025-01-26 15:05:34 +00:00
m - > addDamage ( damageBox ) ;
2024-10-31 00:20:32 +01:00
}
2022-04-17 18:47:10 +02:00
}
2022-05-05 15:09:26 +02:00
2024-03-03 18:39:20 +00:00
static auto PLOGDAMAGE = CConfigValue < Hyprlang : : INT > ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-03-03 18:39:20 +00:00
if ( * PLOGDAMAGE )
2025-01-26 15:05:34 +00:00
Debug : : log ( LOG , " Damage: Box: xy: {}, {} wh: {}, {} " , box . x , box . y , box . w , box . h ) ;
2022-03-31 17:25:23 +02:00
}
2022-05-05 14:02:30 +02:00
void CHyprRenderer : : damageBox ( const int & x , const int & y , const int & w , const int & h ) {
2023-11-04 17:03:05 +00:00
CBox box = { x , y , w , h } ;
2025-01-26 15:05:34 +00:00
damageBox ( box ) ;
2022-05-05 14:02:30 +02:00
}
2023-07-19 20:09:49 +02:00
void CHyprRenderer : : damageRegion ( const CRegion & rg ) {
2025-07-30 11:54:09 +02:00
rg . forEachRect ( [ this ] ( const auto & RECT ) { damageBox ( RECT . x1 , RECT . y1 , RECT . x2 - RECT . x1 , RECT . y2 - RECT . y1 ) ; } ) ;
2022-07-16 12:44:45 +02:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : damageMirrorsWith ( PHLMONITOR pMonitor , const CRegion & pRegion ) {
2025-04-30 23:45:20 +02:00
for ( auto const & mirror : pMonitor - > m_mirrors ) {
2022-09-13 15:25:42 +02:00
2024-04-24 17:29:41 +02:00
// transform the damage here, so it won't get clipped by the monitor damage ring
2024-12-07 18:51:18 +01:00
auto monitor = mirror ;
2024-04-24 17:29:41 +02:00
CRegion transformed { pRegion } ;
// we want to transform to the same box as in CHyprOpenGLImpl::renderMirrored
2025-04-30 23:45:20 +02:00
double scale = std : : min ( monitor - > m_transformedSize . x / pMonitor - > m_transformedSize . x , monitor - > m_transformedSize . y / pMonitor - > m_transformedSize . y ) ;
CBox monbox = { 0 , 0 , pMonitor - > m_transformedSize . x * scale , pMonitor - > m_transformedSize . y * scale } ;
monbox . x = ( monitor - > m_transformedSize . x - monbox . w ) / 2 ;
monbox . y = ( monitor - > m_transformedSize . y - monbox . h ) / 2 ;
2024-04-24 17:29:41 +02:00
2024-07-21 13:09:54 +02:00
transformed . scale ( scale ) ;
2025-04-30 23:45:20 +02:00
transformed . transform ( wlTransformToHyprutils ( pMonitor - > m_transform ) , pMonitor - > m_pixelSize . x * scale , pMonitor - > m_pixelSize . y * scale ) ;
2024-04-24 17:29:41 +02:00
transformed . translate ( Vector2D ( monbox . x , monbox . y ) ) ;
2025-01-26 15:05:34 +00:00
mirror - > addDamage ( transformed ) ;
2023-03-04 00:48:02 +00:00
2024-10-19 23:03:29 +01:00
g_pCompositor - > scheduleFrameForMonitor ( mirror . lock ( ) , Aquamarine : : IOutput : : AQ_SCHEDULE_DAMAGE ) ;
2022-09-13 15:25:42 +02:00
}
}
2025-04-16 01:37:48 +01:00
void CHyprRenderer : : renderDragIcon ( PHLMONITOR pMonitor , const Time : : steady_tp & time ) {
2024-05-11 17:13:20 +01:00
PROTO : : data - > renderDND ( pMonitor , time ) ;
2022-04-14 16:43:29 +02:00
}
2024-06-08 10:07:59 +02:00
void CHyprRenderer : : setCursorSurface ( SP < CWLSurface > surf , int hotspotX , int hotspotY , bool force ) {
2025-05-05 23:44:49 +02:00
m_cursorHasSurface = surf ;
2023-09-29 17:51:07 +01:00
2025-05-05 23:44:49 +02:00
m_lastCursorData . name = " " ;
m_lastCursorData . surf = surf ;
m_lastCursorData . hotspotX = hotspotX ;
m_lastCursorData . hotspotY = hotspotY ;
2023-10-29 18:09:05 +00:00
2025-05-05 23:44:49 +02:00
if ( m_cursorHidden & & ! force )
2024-02-21 13:48:48 +00:00
return ;
2024-05-05 22:18:10 +01:00
g_pCursorManager - > setCursorSurface ( surf , { hotspotX , hotspotY } ) ;
2023-09-29 17:51:07 +01:00
}
2023-12-20 13:00:27 +01:00
2023-12-20 21:40:44 +01:00
void CHyprRenderer : : setCursorFromName ( const std : : string & name , bool force ) {
2025-05-05 23:44:49 +02:00
m_cursorHasSurface = true ;
2023-09-29 17:51:07 +01:00
2025-05-05 23:44:49 +02:00
if ( name = = m_lastCursorData . name & & ! force )
2023-10-29 18:09:05 +00:00
return ;
2025-05-05 23:44:49 +02:00
m_lastCursorData . name = name ;
m_lastCursorData . surf . reset ( ) ;
2023-10-29 18:09:05 +00:00
2025-05-05 23:44:49 +02:00
if ( m_cursorHidden & & ! force )
2024-02-21 13:48:48 +00:00
return ;
2024-03-09 16:52:59 +00:00
g_pCursorManager - > setCursorFromName ( name ) ;
2023-09-29 17:51:07 +01:00
}
2022-06-24 23:27:02 +02:00
void CHyprRenderer : : ensureCursorRenderingMode ( ) {
2025-07-20 10:40:21 +00:00
static auto PINVISIBLE = CConfigValue < Hyprlang : : INT > ( " cursor:invisible " ) ;
2024-08-10 13:42:45 -07:00
static auto PCURSORTIMEOUT = CConfigValue < Hyprlang : : FLOAT > ( " cursor:inactive_timeout " ) ;
2024-05-09 22:23:01 +01:00
static auto PHIDEONTOUCH = CConfigValue < Hyprlang : : INT > ( " cursor:hide_on_touch " ) ;
static auto PHIDEONKEY = CConfigValue < Hyprlang : : INT > ( " cursor:hide_on_key_press " ) ;
2022-06-24 23:27:02 +02:00
2024-03-28 02:04:30 +00:00
if ( * PCURSORTIMEOUT < = 0 )
2025-05-05 23:44:49 +02:00
m_cursorHiddenConditions . hiddenOnTimeout = false ;
2024-03-28 02:04:30 +00:00
if ( * PHIDEONTOUCH = = 0 )
2025-05-05 23:44:49 +02:00
m_cursorHiddenConditions . hiddenOnTouch = false ;
2024-03-28 02:04:30 +00:00
if ( * PHIDEONKEY = = 0 )
2025-05-05 23:44:49 +02:00
m_cursorHiddenConditions . hiddenOnKeyboard = false ;
2023-01-17 11:47:39 +01:00
2024-03-28 02:04:30 +00:00
if ( * PCURSORTIMEOUT > 0 )
2025-05-05 23:44:49 +02:00
m_cursorHiddenConditions . hiddenOnTimeout = * PCURSORTIMEOUT < g_pInputManager - > m_lastCursorMovement . getSeconds ( ) ;
2022-06-24 23:27:02 +02:00
2025-07-20 10:40:21 +00:00
const bool HIDE = m_cursorHiddenConditions . hiddenOnTimeout | | m_cursorHiddenConditions . hiddenOnTouch | | m_cursorHiddenConditions . hiddenOnKeyboard | | ( * PINVISIBLE ! = 0 ) ;
2022-06-24 23:27:02 +02:00
2025-05-05 23:44:49 +02:00
if ( HIDE = = m_cursorHidden )
2024-03-28 02:04:30 +00:00
return ;
2023-12-20 21:40:44 +01:00
2024-03-28 02:04:30 +00:00
if ( HIDE ) {
Debug : : log ( LOG , " Hiding the cursor (hl-mandated) " ) ;
2022-06-24 23:27:02 +02:00
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_monitors ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pPointerManager - > softwareLockedFor ( m ) )
2024-03-28 02:04:30 +00:00
continue ;
2023-12-20 21:40:44 +01:00
2024-12-22 17:12:09 +01:00
damageMonitor ( m ) ; // TODO: maybe just damage the cursor area?
2022-06-24 23:27:02 +02:00
}
2024-03-28 02:04:30 +00:00
setCursorHidden ( true ) ;
2022-06-24 23:27:02 +02:00
} else {
2024-03-28 02:04:30 +00:00
Debug : : log ( LOG , " Showing the cursor (hl-mandated) " ) ;
2025-04-22 15:23:29 +02:00
for ( auto const & m : g_pCompositor - > m_monitors ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pPointerManager - > softwareLockedFor ( m ) )
2024-03-28 02:04:30 +00:00
continue ;
2024-12-22 17:12:09 +01:00
damageMonitor ( m ) ; // TODO: maybe just damage the cursor area?
2024-03-28 02:04:30 +00:00
}
2023-12-20 21:40:44 +01:00
setCursorHidden ( false ) ;
2022-06-24 23:27:02 +02:00
}
2022-06-26 13:43:32 +02:00
}
2023-12-20 21:40:44 +01:00
void CHyprRenderer : : setCursorHidden ( bool hide ) {
2025-05-05 23:44:49 +02:00
if ( hide = = m_cursorHidden )
2023-12-20 21:40:44 +01:00
return ;
2025-05-05 23:44:49 +02:00
m_cursorHidden = hide ;
2023-12-20 21:40:44 +01:00
if ( hide ) {
2024-05-05 22:18:10 +01:00
g_pPointerManager - > resetCursorImage ( ) ;
2023-12-20 21:40:44 +01:00
return ;
}
2025-05-05 23:44:49 +02:00
if ( m_lastCursorData . surf . has_value ( ) )
setCursorSurface ( m_lastCursorData . surf . value ( ) , m_lastCursorData . hotspotX , m_lastCursorData . hotspotY , true ) ;
else if ( ! m_lastCursorData . name . empty ( ) )
setCursorFromName ( m_lastCursorData . name , true ) ;
2023-12-20 21:40:44 +01:00
else
setCursorFromName ( " left_ptr " , true ) ;
}
2022-06-26 13:43:32 +02:00
bool CHyprRenderer : : shouldRenderCursor ( ) {
2025-05-05 23:44:49 +02:00
return ! m_cursorHidden & & m_cursorHasSurface ;
2022-07-11 23:38:10 +02:00
}
2023-03-24 19:23:16 +00:00
2024-10-19 23:03:29 +01:00
std : : tuple < float , float , float > CHyprRenderer : : getRenderTimes ( PHLMONITOR pMonitor ) {
2025-04-21 20:42:02 +02:00
const auto POVERLAY = & g_pDebugOverlay - > m_monitorOverlays [ pMonitor ] ;
2023-03-24 19:23:16 +00:00
float avgRenderTime = 0 ;
float maxRenderTime = 0 ;
float minRenderTime = 9999 ;
2025-04-21 20:42:02 +02:00
for ( auto const & rt : POVERLAY - > m_lastRenderTimes ) {
2023-03-24 19:23:16 +00:00
if ( rt > maxRenderTime )
maxRenderTime = rt ;
if ( rt < minRenderTime )
minRenderTime = rt ;
avgRenderTime + = rt ;
}
2025-05-31 23:49:50 +05:00
avgRenderTime / = POVERLAY - > m_lastRenderTimes . empty ( ) ? 1 : POVERLAY - > m_lastRenderTimes . size ( ) ;
2023-03-24 19:23:16 +00:00
return std : : make_tuple < > ( avgRenderTime , maxRenderTime , minRenderTime ) ;
}
2023-04-04 14:49:58 +01:00
static int handleCrashLoop ( void * data ) {
2025-08-14 19:44:56 +05:00
g_pHyprNotificationOverlay - > addNotification ( " Hyprland will crash in " + std : : to_string ( 10 - sc < int > ( g_pHyprRenderer - > m_crashingDistort * 2.f ) ) + " s. " , CHyprColor ( 0 ) , 5000 ,
2023-04-04 14:49:58 +01:00
ICON_INFO ) ;
2025-05-05 23:44:49 +02:00
g_pHyprRenderer - > m_crashingDistort + = 0.5f ;
2023-04-04 14:49:58 +01:00
2025-05-05 23:44:49 +02:00
if ( g_pHyprRenderer - > m_crashingDistort > = 5.5f )
2023-08-31 20:52:02 +00:00
raise ( SIGABRT ) ;
2023-04-04 14:49:58 +01:00
2025-05-05 23:44:49 +02:00
wl_event_source_timer_update ( g_pHyprRenderer - > m_crashingLoop , 1000 ) ;
2023-04-04 14:49:58 +01:00
return 1 ;
}
void CHyprRenderer : : initiateManualCrash ( ) {
2024-12-03 18:58:24 +00:00
g_pHyprNotificationOverlay - > addNotification ( " Manual crash initiated. Farewell... " , CHyprColor ( 0 ) , 5000 , ICON_INFO ) ;
2023-04-04 14:49:58 +01:00
2025-05-05 23:44:49 +02:00
m_crashingLoop = wl_event_loop_add_timer ( g_pCompositor - > m_wlEventLoop , handleCrashLoop , nullptr ) ;
wl_event_source_timer_update ( m_crashingLoop , 1000 ) ;
2023-04-04 14:49:58 +01:00
2025-05-05 23:44:49 +02:00
m_crashingInProgress = true ;
m_crashingDistort = 0.5 ;
2023-04-04 14:49:58 +01:00
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_globalTimer . reset ( ) ;
2023-04-04 22:04:32 +01:00
2025-08-14 19:44:56 +05:00
static auto PDT = rc < Hyprlang : : INT * const * > ( g_pConfigManager - > getConfigValuePtr ( " debug:damage_tracking " ) ) ;
2024-02-18 15:00:34 +00:00
* * PDT = 0 ;
2023-04-14 15:16:43 +01:00
}
2023-07-19 16:13:55 +02:00
2024-07-21 13:09:54 +02:00
SP < CRenderbuffer > CHyprRenderer : : getOrCreateRenderbuffer ( SP < Aquamarine : : IBuffer > buffer , uint32_t fmt ) {
2025-05-30 18:25:59 +05:00
auto it = std : : ranges : : find_if ( m_renderbuffers , [ & ] ( const auto & other ) { return other - > m_hlBuffer = = buffer ; } ) ;
2023-11-24 10:54:21 +00:00
2025-05-05 23:44:49 +02:00
if ( it ! = m_renderbuffers . end ( ) )
2024-07-21 13:09:54 +02:00
return * it ;
2023-11-24 10:54:21 +00:00
2024-07-21 13:09:54 +02:00
auto buf = makeShared < CRenderbuffer > ( buffer , fmt ) ;
2023-11-24 10:54:21 +00:00
2024-07-21 13:09:54 +02:00
if ( ! buf - > good ( ) )
return nullptr ;
2024-06-08 10:07:59 +02:00
2025-05-05 23:44:49 +02:00
m_renderbuffers . emplace_back ( buf ) ;
2024-07-21 13:09:54 +02:00
return buf ;
2024-06-08 10:07:59 +02:00
}
2023-11-30 01:18:55 +00:00
void CHyprRenderer : : makeEGLCurrent ( ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pCompositor | | ! g_pHyprOpenGL )
2023-12-06 14:46:18 +00:00
return ;
2025-05-05 23:44:49 +02:00
if ( eglGetCurrentContext ( ) ! = g_pHyprOpenGL - > m_eglContext )
eglMakeCurrent ( g_pHyprOpenGL - > m_eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , g_pHyprOpenGL - > m_eglContext ) ;
2023-11-30 01:18:55 +00:00
}
void CHyprRenderer : : unsetEGL ( ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pHyprOpenGL )
return ;
2025-05-05 23:44:49 +02:00
eglMakeCurrent ( g_pHyprOpenGL - > m_eglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
2023-11-30 01:18:55 +00:00
}
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : beginRender ( PHLMONITOR pMonitor , CRegion & damage , eRenderMode mode , SP < IHLBuffer > buffer , CFramebuffer * fb , bool simple ) {
2023-11-30 01:18:55 +00:00
makeEGLCurrent ( ) ;
2023-11-24 10:54:21 +00:00
2025-05-05 23:44:49 +02:00
m_renderPass . clear ( ) ;
2024-12-22 17:12:09 +01:00
2025-05-05 23:44:49 +02:00
m_renderMode = mode ;
2023-11-24 10:54:21 +00:00
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . pMonitor = pMonitor ; // has to be set cuz allocs
2023-11-24 10:54:21 +00:00
if ( mode = = RENDER_MODE_FULL_FAKE ) {
2023-11-30 01:18:55 +00:00
RASSERT ( fb , " Cannot render FULL_FAKE without a provided fb! " ) ;
fb - > bind ( ) ;
2024-05-05 22:18:10 +01:00
if ( simple )
g_pHyprOpenGL - > beginSimple ( pMonitor , damage , nullptr , fb ) ;
else
g_pHyprOpenGL - > begin ( pMonitor , damage , fb ) ;
2023-11-24 10:54:21 +00:00
return true ;
}
2025-07-08 12:41:10 +02:00
int bufferAge = 0 ;
2024-06-19 18:25:20 +02:00
2023-11-30 01:18:55 +00:00
if ( ! buffer ) {
2025-07-08 12:41:10 +02:00
m_currentBuffer = pMonitor - > m_output - > swapchain - > next ( & bufferAge ) ;
2025-05-05 23:44:49 +02:00
if ( ! m_currentBuffer ) {
2025-04-30 23:45:20 +02:00
Debug : : log ( ERR , " Failed to acquire swapchain buffer for {} " , pMonitor - > m_name ) ;
2023-11-24 10:54:21 +00:00
return false ;
2024-02-22 23:50:56 +00:00
}
} else
2025-05-05 23:44:49 +02:00
m_currentBuffer = buffer ;
2023-11-24 10:54:21 +00:00
try {
2025-05-05 23:44:49 +02:00
m_currentRenderbuffer = getOrCreateRenderbuffer ( m_currentBuffer , pMonitor - > m_output - > state - > state ( ) . drmFormat ) ;
2023-11-24 10:54:21 +00:00
} catch ( std : : exception & e ) {
2025-04-30 23:45:20 +02:00
Debug : : log ( ERR , " getOrCreateRenderbuffer failed for {} " , pMonitor - > m_name ) ;
2024-07-21 13:09:54 +02:00
return false ;
}
2025-05-05 23:44:49 +02:00
if ( ! m_currentRenderbuffer ) {
2025-04-30 23:45:20 +02:00
Debug : : log ( ERR , " failed to start a render pass for output {}, no RBO could be obtained " , pMonitor - > m_name ) ;
2023-11-24 10:54:21 +00:00
return false ;
}
2024-06-19 18:25:20 +02:00
if ( mode = = RENDER_MODE_NORMAL ) {
2025-07-08 12:41:10 +02:00
damage = pMonitor - > m_damage . getBufferDamage ( bufferAge ) ;
2025-04-30 23:45:20 +02:00
pMonitor - > m_damage . rotate ( ) ;
2024-06-19 18:25:20 +02:00
}
2024-02-19 18:17:32 +00:00
2025-05-05 23:44:49 +02:00
m_currentRenderbuffer - > bind ( ) ;
2024-05-05 22:18:10 +01:00
if ( simple )
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > beginSimple ( pMonitor , damage , m_currentRenderbuffer ) ;
2024-05-05 22:18:10 +01:00
else
g_pHyprOpenGL - > begin ( pMonitor , damage ) ;
2023-11-24 10:54:21 +00:00
return true ;
}
2025-04-30 11:35:25 -05:00
void CHyprRenderer : : endRender ( const std : : function < void ( ) > & renderingDoneCallback ) {
2025-05-05 23:44:49 +02:00
const auto PMONITOR = g_pHyprOpenGL - > m_renderData . pMonitor ;
2024-03-03 18:39:20 +00:00
static auto PNVIDIAANTIFLICKER = CConfigValue < Hyprlang : : INT > ( " opengl:nvidia_anti_flicker " ) ;
2024-07-21 13:09:54 +02:00
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . damage = m_renderPass . render ( g_pHyprOpenGL - > m_renderData . damage ) ;
2024-12-22 17:12:09 +01:00
2024-08-06 14:52:19 +01:00
auto cleanup = CScopeGuard ( [ this ] ( ) {
2025-05-05 23:44:49 +02:00
if ( m_currentRenderbuffer )
m_currentRenderbuffer - > unbind ( ) ;
m_currentRenderbuffer = nullptr ;
m_currentBuffer = nullptr ;
2024-08-06 14:52:19 +01:00
} ) ;
2025-05-05 23:44:49 +02:00
if ( m_renderMode ! = RENDER_MODE_TO_BUFFER_READ_ONLY )
2023-11-30 10:14:35 +00:00
g_pHyprOpenGL - > end ( ) ;
else {
2025-05-05 23:44:49 +02:00
g_pHyprOpenGL - > m_renderData . pMonitor . reset ( ) ;
g_pHyprOpenGL - > m_renderData . mouseZoomFactor = 1.f ;
g_pHyprOpenGL - > m_renderData . mouseZoomUseMouse = true ;
2023-11-30 10:14:35 +00:00
}
2023-11-24 10:54:21 +00:00
2025-05-05 23:44:49 +02:00
if ( m_renderMode = = RENDER_MODE_FULL_FAKE )
2023-11-24 10:54:21 +00:00
return ;
2025-05-05 23:44:49 +02:00
if ( m_renderMode = = RENDER_MODE_NORMAL )
PMONITOR - > m_output - > state - > setBuffer ( m_currentBuffer ) ;
2024-07-21 13:09:54 +02:00
2025-07-19 12:38:41 +02:00
if ( ! g_pHyprOpenGL - > explicitSyncSupported ( ) ) {
Debug : : log ( TRACE , " renderer: Explicit sync unsupported, falling back to implicit in endRender " ) ;
2025-08-24 22:32:13 +02:00
// nvidia doesn't have implicit sync, so we have to explicitly wait here, llvmpipe and other software renderer seems to bug out aswell.
if ( ( isNvidia ( ) & & * PNVIDIAANTIFLICKER ) | | isSoftware ( ) )
2025-07-19 12:38:41 +02:00
glFinish ( ) ;
else
glFlush ( ) ; // mark an implicit sync point
m_usedAsyncBuffers . clear ( ) ; // release all buffer refs and hope implicit sync works
if ( renderingDoneCallback )
renderingDoneCallback ( ) ;
return ;
}
2025-04-30 11:35:25 -05:00
UP < CEGLSync > eglSync = CEGLSync : : create ( ) ;
if ( eglSync & & eglSync - > isValid ( ) ) {
2025-05-05 23:44:49 +02:00
for ( auto const & buf : m_usedAsyncBuffers ) {
2025-05-03 18:54:50 +02:00
for ( const auto & releaser : buf - > m_syncReleasers ) {
2025-04-30 11:35:25 -05:00
releaser - > addSyncFileFd ( eglSync - > fd ( ) ) ;
}
2025-03-22 11:01:14 -05:00
}
2024-07-21 13:09:54 +02:00
2025-04-30 11:35:25 -05:00
// release buffer refs with release points now, since syncReleaser handles actual buffer release based on EGLSync
2025-05-05 23:44:49 +02:00
std : : erase_if ( m_usedAsyncBuffers , [ ] ( const auto & buf ) { return ! buf - > m_syncReleasers . empty ( ) ; } ) ;
2023-11-24 10:54:21 +00:00
2025-04-30 11:35:25 -05:00
// release buffer refs without release points when EGLSync sync_file/fence is signalled
2025-05-05 23:44:49 +02:00
g_pEventLoopManager - > doOnReadable ( eglSync - > fd ( ) . duplicate ( ) , [ renderingDoneCallback , prevbfs = std : : move ( m_usedAsyncBuffers ) ] ( ) mutable {
2025-04-30 11:35:25 -05:00
prevbfs . clear ( ) ;
if ( renderingDoneCallback )
renderingDoneCallback ( ) ;
} ) ;
2025-05-05 23:44:49 +02:00
m_usedAsyncBuffers . clear ( ) ;
2024-08-06 14:52:19 +01:00
2025-05-05 23:44:49 +02:00
if ( m_renderMode = = RENDER_MODE_NORMAL ) {
2025-04-30 23:45:20 +02:00
PMONITOR - > m_inFence = eglSync - > takeFd ( ) ;
PMONITOR - > m_output - > state - > setExplicitInFence ( PMONITOR - > m_inFence . get ( ) ) ;
2024-07-21 13:09:54 +02:00
}
2025-03-22 11:01:14 -05:00
} else {
2025-07-19 12:38:41 +02:00
Debug : : log ( ERR , " renderer: Explicit sync failed, releasing resources " ) ;
2025-04-30 11:35:25 -05:00
2025-05-05 23:44:49 +02:00
m_usedAsyncBuffers . clear ( ) ; // release all buffer refs and hope implicit sync works
2025-04-30 11:35:25 -05:00
if ( renderingDoneCallback )
renderingDoneCallback ( ) ;
2024-07-21 13:09:54 +02:00
}
2023-11-24 10:54:21 +00:00
}
void CHyprRenderer : : onRenderbufferDestroy ( CRenderbuffer * rb ) {
2025-05-05 23:44:49 +02:00
std : : erase_if ( m_renderbuffers , [ & ] ( const auto & rbo ) { return rbo . get ( ) = = rb ; } ) ;
2023-11-24 10:54:21 +00:00
}
2024-07-21 13:09:54 +02:00
SP < CRenderbuffer > CHyprRenderer : : getCurrentRBO ( ) {
2025-05-05 23:44:49 +02:00
return m_currentRenderbuffer ;
2023-11-25 17:45:08 +00:00
}
bool CHyprRenderer : : isNvidia ( ) {
2025-05-05 23:44:49 +02:00
return m_nvidia ;
2023-12-18 16:06:06 +00:00
}
2024-08-06 14:52:19 +01:00
2025-08-24 09:57:37 +02:00
bool CHyprRenderer : : isIntel ( ) {
return m_intel ;
}
2025-08-24 22:32:13 +02:00
bool CHyprRenderer : : isSoftware ( ) {
return m_software ;
}
2025-07-16 11:02:20 +02:00
bool CHyprRenderer : : isMgpu ( ) {
return m_mgpu ;
}
2024-08-30 17:37:52 +02:00
void CHyprRenderer : : addWindowToRenderUnfocused ( PHLWINDOW window ) {
static auto PFPS = CConfigValue < Hyprlang : : INT > ( " misc:render_unfocused_fps " ) ;
2025-05-30 18:25:59 +05:00
if ( std : : ranges : : find ( m_renderUnfocused , window ) ! = m_renderUnfocused . end ( ) )
2024-08-30 17:37:52 +02:00
return ;
2025-05-05 23:44:49 +02:00
m_renderUnfocused . emplace_back ( window ) ;
2024-08-30 17:37:52 +02:00
2025-05-05 23:44:49 +02:00
if ( ! m_renderUnfocusedTimer - > armed ( ) )
m_renderUnfocusedTimer - > updateTimeout ( std : : chrono : : milliseconds ( 1000 / * PFPS ) ) ;
2024-08-30 17:37:52 +02:00
}
2024-12-22 17:12:09 +01:00
2025-06-15 11:51:27 +02:00
void CHyprRenderer : : makeSnapshot ( PHLWINDOW pWindow ) {
2024-12-22 17:12:09 +01:00
// we trust the window is valid.
2025-04-28 22:25:22 +02:00
const auto PMONITOR = pWindow - > m_monitor . lock ( ) ;
2024-12-22 17:12:09 +01:00
2025-04-30 23:45:20 +02:00
if ( ! PMONITOR | | ! PMONITOR - > m_output | | PMONITOR - > m_pixelSize . x < = 0 | | PMONITOR - > m_pixelSize . y < = 0 )
2024-12-22 17:12:09 +01:00
return ;
if ( ! shouldRenderWindow ( pWindow ) )
return ; // ignore, window is not being rendered
2025-08-14 19:44:56 +05:00
Debug : : log ( LOG , " renderer: making a snapshot of {:x} " , rc < uintptr_t > ( pWindow . get ( ) ) ) ;
2025-08-03 16:39:54 +02:00
2024-12-22 17:12:09 +01:00
// we need to "damage" the entire monitor
// so that we render the entire window
2025-07-25 15:19:23 +00:00
// this is temporary, doesn't mess with the actual damage
2025-08-14 19:44:56 +05:00
CRegion fakeDamage { 0 , 0 , sc < int > ( PMONITOR - > m_transformedSize . x ) , sc < int > ( PMONITOR - > m_transformedSize . y ) } ;
2024-12-22 17:12:09 +01:00
PHLWINDOWREF ref { pWindow } ;
makeEGLCurrent ( ) ;
2025-05-05 23:44:49 +02:00
const auto PFRAMEBUFFER = & g_pHyprOpenGL - > m_windowFramebuffers [ ref ] ;
2024-12-22 17:12:09 +01:00
2025-05-09 22:16:21 +01:00
PFRAMEBUFFER - > alloc ( PMONITOR - > m_pixelSize . x , PMONITOR - > m_pixelSize . y , DRM_FORMAT_ABGR8888 ) ;
2024-12-22 17:12:09 +01:00
beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , PFRAMEBUFFER ) ;
m_bRenderingSnapshot = true ;
g_pHyprOpenGL - > clear ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
2025-04-28 22:25:22 +02:00
renderWindow ( pWindow , PMONITOR , Time : : steadyNow ( ) , ! pWindow - > m_X11DoesntWantBorders , RENDER_PASS_ALL ) ;
2024-12-22 17:12:09 +01:00
endRender ( ) ;
m_bRenderingSnapshot = false ;
}
2025-06-15 11:51:27 +02:00
void CHyprRenderer : : makeSnapshot ( PHLLS pLayer ) {
2024-12-22 17:12:09 +01:00
// we trust the window is valid.
2025-04-24 20:49:49 +02:00
const auto PMONITOR = pLayer - > m_monitor . lock ( ) ;
2024-12-22 17:12:09 +01:00
2025-04-30 23:45:20 +02:00
if ( ! PMONITOR | | ! PMONITOR - > m_output | | PMONITOR - > m_pixelSize . x < = 0 | | PMONITOR - > m_pixelSize . y < = 0 )
2024-12-22 17:12:09 +01:00
return ;
2025-08-14 19:44:56 +05:00
Debug : : log ( LOG , " renderer: making a snapshot of {:x} " , rc < uintptr_t > ( pLayer . get ( ) ) ) ;
2025-08-03 16:39:54 +02:00
2024-12-22 17:12:09 +01:00
// we need to "damage" the entire monitor
// so that we render the entire window
2025-07-25 15:19:23 +00:00
// this is temporary, doesn't mess with the actual damage
2025-08-14 19:44:56 +05:00
CRegion fakeDamage { 0 , 0 , sc < int > ( PMONITOR - > m_transformedSize . x ) , sc < int > ( PMONITOR - > m_transformedSize . y ) } ;
2024-12-22 17:12:09 +01:00
makeEGLCurrent ( ) ;
2025-05-05 23:44:49 +02:00
const auto PFRAMEBUFFER = & g_pHyprOpenGL - > m_layerFramebuffers [ pLayer ] ;
2024-12-22 17:12:09 +01:00
2025-05-09 22:16:21 +01:00
PFRAMEBUFFER - > alloc ( PMONITOR - > m_pixelSize . x , PMONITOR - > m_pixelSize . y , DRM_FORMAT_ABGR8888 ) ;
2024-12-22 17:12:09 +01:00
beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , PFRAMEBUFFER ) ;
m_bRenderingSnapshot = true ;
g_pHyprOpenGL - > clear ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
// draw the layer
2025-04-16 01:37:48 +01:00
renderLayer ( pLayer , PMONITOR , Time : : steadyNow ( ) ) ;
2024-12-22 17:12:09 +01:00
endRender ( ) ;
m_bRenderingSnapshot = false ;
}
2025-08-03 13:44:50 +02:00
void CHyprRenderer : : makeSnapshot ( WP < CPopup > popup ) {
// we trust the window is valid.
const auto PMONITOR = popup - > getMonitor ( ) ;
if ( ! PMONITOR | | ! PMONITOR - > m_output | | PMONITOR - > m_pixelSize . x < = 0 | | PMONITOR - > m_pixelSize . y < = 0 )
return ;
if ( ! popup - > m_wlSurface | | ! popup - > m_wlSurface - > resource ( ) | | ! popup - > m_mapped )
return ;
2025-08-14 19:44:56 +05:00
Debug : : log ( LOG , " renderer: making a snapshot of {:x} " , rc < uintptr_t > ( popup . get ( ) ) ) ;
2025-08-03 16:39:54 +02:00
2025-08-03 13:44:50 +02:00
CRegion fakeDamage { 0 , 0 , PMONITOR - > m_transformedSize . x , PMONITOR - > m_transformedSize . y } ;
makeEGLCurrent ( ) ;
const auto PFRAMEBUFFER = & g_pHyprOpenGL - > m_popupFramebuffers [ popup ] ;
PFRAMEBUFFER - > alloc ( PMONITOR - > m_pixelSize . x , PMONITOR - > m_pixelSize . y , DRM_FORMAT_ABGR8888 ) ;
beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , PFRAMEBUFFER ) ;
m_bRenderingSnapshot = true ;
g_pHyprOpenGL - > clear ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
CSurfacePassElement : : SRenderData renderdata ;
2025-08-03 16:19:36 +02:00
renderdata . pos = popup - > coordsGlobal ( ) ;
2025-08-03 13:44:50 +02:00
renderdata . alpha = 1.F ;
renderdata . dontRound = true ; // don't round popups
renderdata . pMonitor = PMONITOR ;
renderdata . squishOversized = false ; // don't squish popups
renderdata . popup = true ;
2025-08-03 16:19:36 +02:00
renderdata . blur = false ;
2025-08-03 13:44:50 +02:00
popup - > m_wlSurface - > resource ( ) - > breadthfirst (
[ this , & renderdata ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
renderdata . texture = s - > m_current . texture ;
renderdata . surface = s ;
renderdata . mainSurface = false ;
m_renderPass . add ( makeUnique < CSurfacePassElement > ( renderdata ) ) ;
renderdata . surfaceCounter + + ;
} ,
nullptr ) ;
endRender ( ) ;
m_bRenderingSnapshot = false ;
}
2024-12-22 17:12:09 +01:00
void CHyprRenderer : : renderSnapshot ( PHLWINDOW pWindow ) {
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
PHLWINDOWREF ref { pWindow } ;
2025-05-05 23:44:49 +02:00
if ( ! g_pHyprOpenGL - > m_windowFramebuffers . contains ( ref ) )
2024-12-22 17:12:09 +01:00
return ;
2025-05-05 23:44:49 +02:00
const auto FBDATA = & g_pHyprOpenGL - > m_windowFramebuffers . at ( ref ) ;
2024-12-22 17:12:09 +01:00
if ( ! FBDATA - > getTexture ( ) )
return ;
2025-04-28 22:25:22 +02:00
const auto PMONITOR = pWindow - > m_monitor . lock ( ) ;
2024-12-22 17:12:09 +01:00
CBox windowBox ;
// some mafs to figure out the correct box
// the originalClosedPos is relative to the monitor's pos
2025-04-30 23:45:20 +02:00
Vector2D scaleXY = Vector2D ( ( PMONITOR - > m_scale * pWindow - > m_realSize - > value ( ) . x / ( pWindow - > m_originalClosedSize . x * PMONITOR - > m_scale ) ) ,
( PMONITOR - > m_scale * pWindow - > m_realSize - > value ( ) . y / ( pWindow - > m_originalClosedSize . y * PMONITOR - > m_scale ) ) ) ;
2024-12-22 17:12:09 +01:00
2025-04-30 23:45:20 +02:00
windowBox . width = PMONITOR - > m_transformedSize . x * scaleXY . x ;
windowBox . height = PMONITOR - > m_transformedSize . y * scaleXY . y ;
windowBox . x = ( ( pWindow - > m_realPosition - > value ( ) . x - PMONITOR - > m_position . x ) * PMONITOR - > m_scale ) - ( ( pWindow - > m_originalClosedPos . x * PMONITOR - > m_scale ) * scaleXY . x ) ;
windowBox . y = ( ( pWindow - > m_realPosition - > value ( ) . y - PMONITOR - > m_position . y ) * PMONITOR - > m_scale ) - ( ( pWindow - > m_originalClosedPos . y * PMONITOR - > m_scale ) * scaleXY . y ) ;
2024-12-22 17:12:09 +01:00
2025-04-30 23:45:20 +02:00
CRegion fakeDamage { 0 , 0 , PMONITOR - > m_transformedSize . x , PMONITOR - > m_transformedSize . y } ;
2024-12-22 17:12:09 +01:00
2025-04-28 22:25:22 +02:00
if ( * PDIMAROUND & & pWindow - > m_windowData . dimAround . valueOrDefault ( ) ) {
2024-12-22 17:12:09 +01:00
CRectPassElement : : SRectData data ;
2025-05-05 23:44:49 +02:00
data . box = { 0 , 0 , g_pHyprOpenGL - > m_renderData . pMonitor - > m_pixelSize . x , g_pHyprOpenGL - > m_renderData . pMonitor - > m_pixelSize . y } ;
2025-04-28 22:25:22 +02:00
data . color = CHyprColor ( 0 , 0 , 0 , * PDIMAROUND * pWindow - > m_alpha - > value ( ) ) ;
2024-12-22 17:12:09 +01:00
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CRectPassElement > ( data ) ) ;
2024-12-22 17:12:09 +01:00
}
2025-05-10 18:31:26 +01:00
if ( shouldBlur ( pWindow ) ) {
CRectPassElement : : SRectData data ;
data . box = CBox { pWindow - > m_realPosition - > value ( ) , pWindow - > m_realSize - > value ( ) } . translate ( - PMONITOR - > m_position ) . scale ( PMONITOR - > m_scale ) . round ( ) ;
data . color = CHyprColor { 0 , 0 , 0 , 0 } ;
data . blur = true ;
data . blurA = sqrt ( pWindow - > m_alpha - > value ( ) ) ; // sqrt makes the blur fadeout more realistic.
data . round = pWindow - > rounding ( ) ;
data . roundingPower = pWindow - > roundingPower ( ) ;
data . xray = pWindow - > m_windowData . xray . valueOr ( false ) ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CRectPassElement > ( std : : move ( data ) ) ) ;
2025-05-10 18:31:26 +01:00
}
2024-12-22 17:12:09 +01:00
CTexPassElement : : SRenderData data ;
data . flipEndFrame = true ;
data . tex = FBDATA - > getTexture ( ) ;
data . box = windowBox ;
2025-04-28 22:25:22 +02:00
data . a = pWindow - > m_alpha - > value ( ) ;
2024-12-22 17:12:09 +01:00
data . damage = fakeDamage ;
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CTexPassElement > ( std : : move ( data ) ) ) ;
2024-12-22 17:12:09 +01:00
}
void CHyprRenderer : : renderSnapshot ( PHLLS pLayer ) {
2025-05-05 23:44:49 +02:00
if ( ! g_pHyprOpenGL - > m_layerFramebuffers . contains ( pLayer ) )
2024-12-22 17:12:09 +01:00
return ;
2025-05-05 23:44:49 +02:00
const auto FBDATA = & g_pHyprOpenGL - > m_layerFramebuffers . at ( pLayer ) ;
2024-12-22 17:12:09 +01:00
if ( ! FBDATA - > getTexture ( ) )
return ;
2025-04-24 20:49:49 +02:00
const auto PMONITOR = pLayer - > m_monitor . lock ( ) ;
2024-12-22 17:12:09 +01:00
CBox layerBox ;
// some mafs to figure out the correct box
// the originalClosedPos is relative to the monitor's pos
2025-04-30 23:45:20 +02:00
Vector2D scaleXY = Vector2D ( ( PMONITOR - > m_scale * pLayer - > m_realSize - > value ( ) . x / ( pLayer - > m_geometry . w * PMONITOR - > m_scale ) ) ,
( PMONITOR - > m_scale * pLayer - > m_realSize - > value ( ) . y / ( pLayer - > m_geometry . h * PMONITOR - > m_scale ) ) ) ;
2024-12-22 17:12:09 +01:00
2025-04-30 23:45:20 +02:00
layerBox . width = PMONITOR - > m_transformedSize . x * scaleXY . x ;
layerBox . height = PMONITOR - > m_transformedSize . y * scaleXY . y ;
2025-04-24 20:49:49 +02:00
layerBox . x =
2025-04-30 23:45:20 +02:00
( ( pLayer - > m_realPosition - > value ( ) . x - PMONITOR - > m_position . x ) * PMONITOR - > m_scale ) - ( ( ( pLayer - > m_geometry . x - PMONITOR - > m_position . x ) * PMONITOR - > m_scale ) * scaleXY . x ) ;
2025-04-24 20:49:49 +02:00
layerBox . y =
2025-04-30 23:45:20 +02:00
( ( pLayer - > m_realPosition - > value ( ) . y - PMONITOR - > m_position . y ) * PMONITOR - > m_scale ) - ( ( ( pLayer - > m_geometry . y - PMONITOR - > m_position . y ) * PMONITOR - > m_scale ) * scaleXY . y ) ;
2024-12-22 17:12:09 +01:00
2025-04-30 23:45:20 +02:00
CRegion fakeDamage { 0 , 0 , PMONITOR - > m_transformedSize . x , PMONITOR - > m_transformedSize . y } ;
2024-12-22 17:12:09 +01:00
2025-05-10 18:31:26 +01:00
const bool SHOULD_BLUR = shouldBlur ( pLayer ) ;
2024-12-22 17:12:09 +01:00
CTexPassElement : : SRenderData data ;
data . flipEndFrame = true ;
data . tex = FBDATA - > getTexture ( ) ;
data . box = layerBox ;
2025-04-24 20:49:49 +02:00
data . a = pLayer - > m_alpha - > value ( ) ;
2024-12-22 17:12:09 +01:00
data . damage = fakeDamage ;
2025-05-10 18:31:26 +01:00
data . blur = SHOULD_BLUR ;
data . blurA = sqrt ( pLayer - > m_alpha - > value ( ) ) ; // sqrt makes the blur fadeout more realistic.
if ( SHOULD_BLUR )
data . ignoreAlpha = pLayer - > m_ignoreAlpha ? pLayer - > m_ignoreAlphaValue : 0.01F /* ignore the alpha 0 regions */ ;
2024-12-22 17:12:09 +01:00
2025-07-10 10:44:59 +02:00
m_renderPass . add ( makeUnique < CTexPassElement > ( std : : move ( data ) ) ) ;
2024-12-22 17:12:09 +01:00
}
2025-05-10 18:31:26 +01:00
2025-08-03 13:44:50 +02:00
void CHyprRenderer : : renderSnapshot ( WP < CPopup > popup ) {
if ( ! g_pHyprOpenGL - > m_popupFramebuffers . contains ( popup ) )
return ;
static CConfigValue PBLURIGNOREA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:popups_ignorealpha " ) ;
const auto FBDATA = & g_pHyprOpenGL - > m_popupFramebuffers . at ( popup ) ;
if ( ! FBDATA - > getTexture ( ) )
return ;
const auto PMONITOR = popup - > getMonitor ( ) ;
if ( ! PMONITOR )
return ;
CRegion fakeDamage { 0 , 0 , PMONITOR - > m_transformedSize . x , PMONITOR - > m_transformedSize . y } ;
const bool SHOULD_BLUR = shouldBlur ( popup ) ;
CTexPassElement : : SRenderData data ;
data . flipEndFrame = true ;
data . tex = FBDATA - > getTexture ( ) ;
data . box = { { } , PMONITOR - > m_transformedSize } ;
data . a = popup - > m_alpha - > value ( ) ;
data . damage = fakeDamage ;
data . blur = SHOULD_BLUR ;
data . blurA = sqrt ( popup - > m_alpha - > value ( ) ) ; // sqrt makes the blur fadeout more realistic.
if ( SHOULD_BLUR )
data . ignoreAlpha = std : : max ( * PBLURIGNOREA , 0.01F ) ; /* ignore the alpha 0 regions */
;
m_renderPass . add ( makeUnique < CTexPassElement > ( std : : move ( data ) ) ) ;
}
2025-05-10 18:31:26 +01:00
bool CHyprRenderer : : shouldBlur ( PHLLS ls ) {
if ( m_bRenderingSnapshot )
return false ;
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
return * PBLUR & & ls - > m_forceBlur ;
}
bool CHyprRenderer : : shouldBlur ( PHLWINDOW w ) {
if ( m_bRenderingSnapshot )
return false ;
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
const bool DONT_BLUR = w - > m_windowData . noBlur . valueOrDefault ( ) | | w - > m_windowData . RGBX . valueOrDefault ( ) | | w - > opaque ( ) ;
return * PBLUR & & ! DONT_BLUR ;
}
2025-08-03 13:44:50 +02:00
bool CHyprRenderer : : shouldBlur ( WP < CPopup > p ) {
static CConfigValue PBLURPOPUPS = CConfigValue < Hyprlang : : INT > ( " decoration:blur:popups " ) ;
static CConfigValue PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
return * PBLURPOPUPS & & * PBLUR ;
}