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"
2024-08-06 14:52:19 +01:00
# include "../helpers/sync/SyncReleaser.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"
2024-03-09 16:52:59 +00:00
# include "../managers/CursorManager.hpp"
2024-05-05 22:18:10 +01:00
# include "../managers/PointerManager.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"
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-01-07 21:32:50 +03:00
# include "protocols/ColorManagement.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 ;
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 ( ) ;
wl_event_source_timer_update ( g_pHyprRenderer - > m_pCursorTicker , 500 ) ;
return 0 ;
}
2023-11-25 17:45:08 +00:00
2024-03-28 02:04:30 +00:00
CHyprRenderer : : CHyprRenderer ( ) {
2024-07-21 13:09:54 +02:00
if ( g_pCompositor - > m_pAqBackend - > hasSession ( ) ) {
2024-08-26 20:24:30 +02:00
for ( auto const & dev : g_pCompositor - > m_pAqBackend - > session - > sessionDevices ) {
2024-07-21 13:09:54 +02:00
const auto DRMV = drmGetVersion ( dev - > fd ) ;
if ( ! DRMV )
continue ;
2023-11-25 17:45:08 +00:00
std : : string name = std : : string { DRMV - > name , DRMV - > name_len } ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , tolower ) ;
if ( name . contains ( " nvidia " ) )
m_bNvidia = true ;
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 ) ;
}
} 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
2024-03-15 07:28:14 -07:00
const auto DRMV = drmGetVersion ( g_pCompositor - > m_iDRMFD ) ;
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 } ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , tolower ) ;
2023-11-25 17:45:08 +00:00
2024-03-15 07:28:14 -07:00
if ( name . contains ( " nvidia " ) )
m_bNvidia = 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 ) ;
}
if ( m_bNvidia )
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 ) {
2024-03-28 02:04:30 +00:00
if ( m_sCursorHiddenConditions . hiddenOnKeyboard )
return ;
m_sCursorHiddenConditions . hiddenOnKeyboard = true ;
ensureCursorRenderingMode ( ) ;
} ) ;
2024-04-20 20:16:42 +01:00
static auto P2 = g_pHookSystem - > hookDynamic ( " mouseMove " , [ & ] ( void * self , SCallbackInfo & info , std : : any param ) {
2024-03-28 02:04:30 +00:00
if ( ! m_sCursorHiddenConditions . hiddenOnKeyboard & & m_sCursorHiddenConditions . hiddenOnTouch = = g_pInputManager - > m_bLastInputTouch & &
! m_sCursorHiddenConditions . hiddenOnTimeout )
return ;
m_sCursorHiddenConditions . hiddenOnKeyboard = false ;
m_sCursorHiddenConditions . hiddenOnTimeout = false ;
m_sCursorHiddenConditions . hiddenOnTouch = g_pInputManager - > m_bLastInputTouch ;
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 ;
for ( auto & m : g_pCompositor - > m_vMonitors ) {
arrangeLayersForMonitor ( m - > ID ) ;
}
} ) ;
} ) ;
2024-03-28 02:04:30 +00:00
m_pCursorTicker = wl_event_loop_add_timer ( g_pCompositor - > m_sWLEventLoop , cursorTicker , nullptr ) ;
wl_event_source_timer_update ( m_pCursorTicker , 500 ) ;
2024-08-30 17:37:52 +02:00
m_tRenderUnfocusedTimer = makeShared < CEventLoopTimer > (
std : : nullopt ,
[ this ] ( SP < CEventLoopTimer > self , void * data ) {
static auto PFPS = CConfigValue < Hyprlang : : INT > ( " misc:render_unfocused_fps " ) ;
if ( m_vRenderUnfocused . empty ( ) )
return ;
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
bool dirty = false ;
for ( auto & w : m_vRenderUnfocused ) {
if ( ! w ) {
dirty = true ;
continue ;
}
if ( ! w - > m_pWLSurface | | ! w - > m_pWLSurface - > resource ( ) | | shouldRenderWindow ( w . lock ( ) ) )
continue ;
w - > m_pWLSurface - > resource ( ) - > frame ( & now ) ;
auto FEEDBACK = makeShared < CQueuedPresentationData > ( w - > m_pWLSurface - > resource ( ) ) ;
FEEDBACK - > attachMonitor ( g_pCompositor - > m_pLastMonitor . lock ( ) ) ;
FEEDBACK - > discarded ( ) ;
PROTO : : presentation - > queueData ( FEEDBACK ) ;
}
if ( dirty )
std : : erase_if ( m_vRenderUnfocused , [ ] ( const auto & e ) { return ! e | | ! e - > m_sWindowData . renderUnfocused . valueOr ( false ) ; } ) ;
if ( ! m_vRenderUnfocused . empty ( ) )
m_tRenderUnfocusedTimer - > updateTimeout ( std : : chrono : : milliseconds ( 1000 / * PFPS ) ) ;
} ,
nullptr ) ;
g_pEventLoopManager - > addTimer ( m_tRenderUnfocusedTimer ) ;
2023-09-28 21:48:33 +01:00
}
2024-06-13 12:08:02 +02:00
CHyprRenderer : : ~ CHyprRenderer ( ) {
if ( m_pCursorTicker )
wl_event_source_remove ( m_pCursorTicker ) ;
}
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 ;
2024-04-02 20:32:39 +01:00
if ( ! pWindow - > m_pWorkspace & & ! pWindow - > m_bFadingOut )
2023-04-12 13:05:57 +01:00
return false ;
2024-04-03 20:42:38 +01:00
if ( ! pWindow - > m_pWorkspace & & pWindow - > m_bFadingOut )
return pWindow - > workspaceID ( ) = = pMonitor - > activeWorkspaceID ( ) ;
2022-09-10 13:11:02 +02:00
if ( pWindow - > m_bPinned )
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-01-07 17:55:14 +00:00
if ( pWindow - > m_iMonitorMovedFrom ! = - 1 & & pWindow - > m_fMovingToWorkspaceAlpha - > isBeingAnimated ( ) & & pWindow - > m_fMovingToWorkspaceAlpha - > value ( ) > 0.F & & pWindow - > m_pWorkspace & &
2024-11-22 16:01:02 +00:00
! pWindow - > m_pWorkspace - > isVisible ( ) )
2024-08-28 21:54:49 +02:00
return true ;
2024-04-02 20:32:39 +01:00
const auto PWINDOWWORKSPACE = pWindow - > m_pWorkspace ;
2024-10-27 18:45:38 +00:00
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_pMonitor = = pMonitor ) {
2025-01-07 17:55:14 +00:00
if ( PWINDOWWORKSPACE - > m_vRenderOffset - > isBeingAnimated ( ) | | PWINDOWWORKSPACE - > m_fAlpha - > isBeingAnimated ( ) | | PWINDOWWORKSPACE - > m_bForceRendering )
2022-08-18 12:42:21 +02:00
return true ;
2024-04-01 08:16:18 -07:00
// if hidden behind fullscreen
2024-07-31 17:55:52 +00:00
if ( PWINDOWWORKSPACE - > m_bHasFullscreenWindow & & ! pWindow - > isFullscreen ( ) & & ( ! pWindow - > m_bIsFloating | | ! pWindow - > m_bCreatedOverFullscreen ) & &
2025-01-07 17:55:14 +00:00
pWindow - > m_fAlpha - > value ( ) = = 0 )
2024-04-01 08:16:18 -07:00
return false ;
2025-01-07 17:55:14 +00:00
if ( ! PWINDOWWORKSPACE - > m_vRenderOffset - > isBeingAnimated ( ) & & ! PWINDOWWORKSPACE - > m_fAlpha - > isBeingAnimated ( ) & & ! PWINDOWWORKSPACE - > isVisible ( ) )
2024-04-01 08:16:18 -07:00
return false ;
2022-07-28 16:33:45 +02:00
}
2024-10-27 18:45:38 +00:00
if ( pWindow - > m_pMonitor = = pMonitor )
2022-03-20 18:49:40 +01:00
return true ;
2024-11-27 09:17:45 -05:00
if ( ( ! pWindow - > m_pWorkspace | | ! pWindow - > m_pWorkspace - > isVisible ( ) ) & & pWindow - > m_pMonitor ! = 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.
2024-11-22 16:01:02 +00:00
if ( pWindow - > m_pWorkspace & & pWindow - > m_pWorkspace - > isVisible ( ) & & pWindow - > m_bIsFloating /* 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
2024-04-02 20:32:39 +01:00
if ( pMonitor - > activeSpecialWorkspace = = pWindow - > m_pWorkspace )
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-01-07 17:55:14 +00:00
if ( ! pWindow - > m_bIsFloating & & pWindow - > m_vRealPosition - > isBeingAnimated ( ) & & pWindow - > m_bAnimatingIn & & pWindow - > m_pMonitor ! = pMonitor )
2024-03-30 18:14:26 -07:00
return false ;
2025-01-07 17:55:14 +00:00
if ( pWindow - > m_vRealPosition - > isBeingAnimated ( ) ) {
if ( PWINDOWWORKSPACE & & ! PWINDOWWORKSPACE - > m_bIsSpecialWorkspace & & PWINDOWWORKSPACE - > m_vRenderOffset - > 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-01-07 17:55:14 +00:00
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_vRenderOffset - > isBeingAnimated ( ) )
windowBox . translate ( PWINDOWWORKSPACE - > m_vRenderOffset - > value ( ) ) ;
2024-03-30 18:14:26 -07:00
windowBox . translate ( pWindow - > m_vFloatingOffset ) ;
2024-03-16 07:49:34 -07:00
const CBox monitorBox = { pMonitor - > vecPosition , pMonitor - > vecSize } ;
2024-11-07 00:30:17 +01:00
if ( ! windowBox . intersection ( monitorBox ) . empty ( ) & & ( pWindow - > workspaceID ( ) = = pMonitor - > activeWorkspaceID ( ) | | pWindow - > m_iMonitorMovedFrom ! = - 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 ;
2024-04-02 20:32:39 +01:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2022-05-31 22:16:13 +02:00
2024-04-02 20:32:39 +01:00
if ( ! pWindow - > m_pWorkspace )
2023-04-12 13:05:57 +01:00
return false ;
2022-09-12 15:33:20 +02:00
if ( pWindow - > m_bPinned | | PWORKSPACE - > m_bForceRendering )
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 ;
2024-08-26 17:25:39 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2025-01-07 17:55:14 +00:00
if ( PWORKSPACE & & PWORKSPACE - > m_pMonitor = = m & & ( PWORKSPACE - > m_vRenderOffset - > isBeingAnimated ( ) | | PWORKSPACE - > m_fAlpha - > isBeingAnimated ( ) ) )
2022-05-31 22:16:13 +02:00
return true ;
2024-04-02 20:32:39 +01:00
if ( m - > activeSpecialWorkspace & & pWindow - > onSpecialWorkspace ( ) )
2022-05-31 22:16:13 +02:00
return true ;
}
return false ;
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderWorkspaceWindowsFullscreen ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * 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
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2022-09-19 17:26:11 +01:00
continue ;
2025-01-07 17:55:14 +00:00
if ( w - > m_fAlpha - > value ( ) = = 0.f )
2022-09-19 17:26:11 +01:00
continue ;
2024-07-31 17:55:52 +00:00
if ( w - > isFullscreen ( ) | | w - > m_bIsFloating )
2022-09-19 17:26:11 +01:00
continue ;
2024-04-02 20:32:39 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = 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
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2022-09-19 17:26:11 +01:00
continue ;
2025-01-07 17:55:14 +00:00
if ( w - > m_fAlpha - > value ( ) = = 0.f )
2022-09-19 17:26:11 +01:00
continue ;
2024-07-31 17:55:52 +00:00
if ( w - > isFullscreen ( ) | | ! w - > m_bIsFloating )
2022-09-19 17:26:11 +01:00
continue ;
2024-10-27 18:45:38 +00:00
if ( w - > m_pMonitor = = pWorkspace - > m_pMonitor & & pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-24 21:18:50 +00:00
continue ;
2024-10-27 18:45:38 +00:00
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_pMonitor ! = pWorkspace - > m_pMonitor )
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
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-02 20:32:39 +01:00
const auto PWORKSPACE = w - > m_pWorkspace ;
2022-07-28 15:56:55 +02:00
2024-07-31 17:55:52 +00:00
if ( w - > m_pWorkspace ! = pWorkspace | | ! w - > isFullscreen ( ) ) {
2025-01-07 17:55:14 +00:00
if ( ! ( PWORKSPACE & & ( PWORKSPACE - > m_vRenderOffset - > isBeingAnimated ( ) | | PWORKSPACE - > m_fAlpha - > isBeingAnimated ( ) | | PWORKSPACE - > m_bForceRendering ) ) )
2022-07-28 15:56:55 +02:00
continue ;
2022-08-17 12:12:16 +02:00
2024-10-27 18:45:38 +00:00
if ( w - > m_pMonitor ! = 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 ;
2024-10-27 18:45:38 +00:00
if ( w - > m_pMonitor = = pWorkspace - > m_pMonitor & & pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2024-03-04 15:29:45 -08:00
continue ;
2024-04-27 12:43:12 +01:00
if ( shouldRenderWindow ( w , pMonitor ) )
2024-07-31 17:55:52 +00:00
renderWindow ( w , pMonitor , time , pWorkspace - > m_efFullscreenMode ! = FSMODE_FULLSCREEN , RENDER_PASS_ALL ) ;
2022-03-30 20:16:23 +02:00
2024-04-02 20:32:39 +01:00
if ( w - > m_pWorkspace ! = 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...
pWorkspace - > m_bHasFullscreenWindow = false ;
return ; // this will produce one blank frame. Oh well.
}
2022-09-19 17:26:11 +01:00
// then render windows over fullscreen.
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-07-31 17:55:52 +00:00
if ( w - > m_pWorkspace ! = pWorkspaceWindow - > m_pWorkspace | | ( ! w - > m_bCreatedOverFullscreen & & ! w - > m_bPinned ) | | ( ! w - > m_bIsMapped & & ! w - > m_bFadingOut ) | | w - > isFullscreen ( ) )
2022-03-30 20:16:23 +02:00
continue ;
2024-10-27 18:45:38 +00:00
if ( w - > m_pMonitor = = pWorkspace - > m_pMonitor & & pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-24 21:18:50 +00:00
continue ;
2024-10-27 18:45:38 +00:00
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_pMonitor ! = pWorkspace - > m_pMonitor )
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
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderWorkspaceWindows ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * 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
2024-10-31 00:20:32 +01:00
std : : vector < PHLWINDOWREF > windows ;
windows . reserve ( g_pCompositor - > m_vWindows . size ( ) ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-03-14 18:25:28 +00:00
if ( w - > isHidden ( ) | | ( ! w - > m_bIsMapped & & ! w - > m_bFadingOut ) )
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 ) {
if ( w - > m_bIsFloating )
continue ; // floating are in the second pass
2024-04-02 20:32:39 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = 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
2024-05-05 17:16:00 +01:00
if ( w = = g_pCompositor - > m_pLastWindow ) {
2024-10-31 00:20:32 +01:00
lastWindow = w . lock ( ) ;
2023-09-04 15:07:56 +02:00
continue ;
}
// render the bad boy
2024-10-31 00:20:32 +01:00
renderWindow ( w . lock ( ) , pMonitor , time , true , RENDER_PASS_MAIN ) ;
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 ) ;
// 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 ;
if ( w - > m_bIsFloating )
continue ; // floating are in the second pass
2024-04-02 20:32:39 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = 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 ;
if ( ! w - > m_bIsFloating | | w - > m_bPinned )
continue ;
2024-04-02 20:32:39 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-18 19:53:45 +00:00
continue ;
2024-10-27 18:45:38 +00:00
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_pMonitor ! = pWorkspace - > m_pMonitor )
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-01-12 09:10:36 -08:00
void CHyprRenderer : : renderWindow ( PHLWINDOW pWindow , PHLMONITOR pMonitor , timespec * time , bool decorate , eRenderPassMode mode , bool ignorePosition , bool standalone ) {
if ( pWindow - > isHidden ( ) & & ! standalone )
2022-04-12 16:44:18 +02:00
return ;
2022-04-05 20:49:15 +02:00
if ( pWindow - > m_bFadingOut ) {
2024-10-27 18:45:38 +00:00
if ( pMonitor = = pWindow - > m_pMonitor ) // 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
2024-03-14 18:25:28 +00:00
if ( ! pWindow - > m_bIsMapped )
return ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderWindow " ) ;
2024-12-22 17:12:09 +01:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2025-01-07 17:55:14 +00:00
const auto REALPOS = pWindow - > m_vRealPosition - > value ( ) + ( pWindow - > m_bPinned ? Vector2D { } : PWORKSPACE - > m_vRenderOffset - > value ( ) ) ;
2024-12-22 17:12:09 +01:00
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
2022-06-21 22:54:41 +02:00
2024-12-22 17:12:09 +01:00
CSurfacePassElement : : SRenderData renderdata = { pMonitor , time } ;
2025-01-07 17:55:14 +00:00
CBox textureBox = { REALPOS . x , REALPOS . y , std : : max ( pWindow - > m_vRealSize - > value ( ) . x , 5.0 ) , std : : max ( pWindow - > m_vRealSize - > 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 ) {
2024-12-22 17:12:09 +01:00
renderdata . pos . x = pMonitor - > vecPosition . x ;
renderdata . pos . y = pMonitor - > vecPosition . y ;
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
2024-11-22 16:01:02 +00:00
const bool USE_WORKSPACE_FADE_ALPHA = pWindow - > m_iMonitorMovedFrom ! = - 1 & & ( ! PWORKSPACE | | ! PWORKSPACE - > isVisible ( ) ) ;
2024-11-17 16:42:30 +00:00
const bool DONT_BLUR = pWindow - > m_sWindowData . noBlur . valueOrDefault ( ) | | pWindow - > m_sWindowData . RGBX . valueOrDefault ( ) | | pWindow - > opaque ( ) ;
2024-08-28 21:54:49 +02:00
2024-06-08 10:07:59 +02:00
renderdata . surface = pWindow - > m_pWLSurface - > resource ( ) ;
2024-07-31 17:55:52 +00:00
renderdata . dontRound = pWindow - > isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) | | pWindow - > m_sWindowData . noRounding . valueOrDefault ( ) ;
2025-01-07 17:55:14 +00:00
renderdata . fadeAlpha = pWindow - > m_fAlpha - > value ( ) * ( pWindow - > m_bPinned | | USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE - > m_fAlpha - > value ( ) ) *
( USE_WORKSPACE_FADE_ALPHA ? pWindow - > m_fMovingToWorkspaceAlpha - > value ( ) : 1.F ) * pWindow - > m_fMovingFromWorkspaceAlpha - > value ( ) ;
renderdata . alpha = pWindow - > m_fActiveInactiveAlpha - > value ( ) ;
2025-01-05 12:38:49 -06:00
renderdata . decorate = decorate & & ! pWindow - > m_bX11DoesntWantBorders & & ! pWindow - > isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) ;
2025-01-12 09:10:36 -08:00
renderdata . rounding = standalone | | renderdata . dontRound ? 0 : pWindow - > rounding ( ) * pMonitor - > scale ;
renderdata . roundingPower = standalone | | renderdata . dontRound ? 2.0f : pWindow - > roundingPower ( ) ;
renderdata . blur = ! standalone & & * PBLUR & & ! DONT_BLUR ;
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
2024-07-11 14:10:42 +00:00
if ( pWindow - > m_sWindowData . 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
2023-05-26 13:07:45 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE_WINDOW ) ;
2024-07-11 14:10:42 +00:00
if ( * PDIMAROUND & & pWindow - > m_sWindowData . dimAround . valueOrDefault ( ) & & ! m_bRenderingSnapshot & & mode ! = RENDER_PASS_POPUP ) {
2024-12-22 17:12:09 +01:00
CBox monbox = { 0 , 0 , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . x , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . y } ;
CRectPassElement : : SRectData data ;
data . color = CHyprColor ( 0 , 0 , 0 , * PDIMAROUND * renderdata . alpha * renderdata . fadeAlpha ) ;
data . box = monbox ;
m_sRenderPass . add ( makeShared < CRectPassElement > ( data ) ) ;
2022-12-28 15:39:17 +01:00
}
2024-12-22 17:12:09 +01:00
renderdata . pos . x + = pWindow - > m_vFloatingOffset . x ;
renderdata . pos . y + = pWindow - > m_vFloatingOffset . 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-01-07 17:55:14 +00:00
if ( ! ignorePosition & & pWindow - > m_bIsFloating & & ! pWindow - > isFullscreen ( ) & & PWORKSPACE - > m_vRenderOffset - > isBeingAnimated ( ) & & ! pWindow - > m_bPinned ) {
2024-03-30 18:14:26 -07:00
CRegion rg =
2025-01-07 17:55:14 +00:00
pWindow - > getFullWindowBoundingBox ( ) . translate ( - pMonitor - > vecPosition + PWORKSPACE - > m_vRenderOffset - > value ( ) + pWindow - > m_vFloatingOffset ) . scale ( pMonitor - > 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
const bool TRANSFORMERSPRESENT = ! pWindow - > m_vTransformers . empty ( ) ;
2023-10-21 19:25:44 +01:00
if ( TRANSFORMERSPRESENT ) {
2023-10-21 14:15:48 +01:00
g_pHyprOpenGL - > bindOffMain ( ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & t : pWindow - > m_vTransformers ) {
2023-10-21 19:25:44 +01:00
t - > preWindowRender ( & renderdata ) ;
}
}
2024-04-13 23:16:26 +00:00
if ( renderdata . decorate ) {
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations ) {
2023-11-04 13:10:52 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_BOTTOM )
continue ;
2024-03-30 18:14:26 -07:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha ) ;
2023-11-04 13:10:52 +00:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations ) {
2023-11-04 13:10:52 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_UNDER )
continue ;
2024-03-30 18:14:26 -07:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha ) ;
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 " ) ;
2024-07-11 14:10:42 +00:00
if ( ( pWindow - > m_bIsX11 & & * PXWLUSENN ) | | pWindow - > m_sWindowData . nearestNeighbor . valueOrDefault ( ) )
2024-12-22 17:12:09 +01:00
renderdata . useNearestNeighbor = true ;
2023-06-11 21:33:50 +02:00
2024-07-11 14:10:42 +00:00
if ( ! pWindow - > m_sWindowData . noBlur . valueOrDefault ( ) & & pWindow - > m_pWLSurface - > small ( ) & & ! pWindow - > m_pWLSurface - > m_bFillIgnoreSmall & & renderdata . blur & & * PBLUR ) {
2024-12-22 17:12:09 +01:00
CBox wb = { renderdata . pos . x - pMonitor - > vecPosition . x , renderdata . pos . y - pMonitor - > vecPosition . y , renderdata . w , renderdata . h } ;
2023-11-04 17:03:05 +00:00
wb . scale ( pMonitor - > 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 ) ;
m_sRenderPass . add ( makeShared < CRectPassElement > ( data ) ) ;
2023-10-25 22:20:58 +01:00
renderdata . blur = false ;
}
2024-06-17 12:42:32 +02:00
renderdata . surfaceCounter = 0 ;
2024-12-22 17:12:09 +01:00
pWindow - > m_pWLSurface - > resource ( ) - > breadthfirst (
[ this , & renderdata , & pWindow ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
renderdata . texture = s - > current . texture ;
renderdata . surface = s ;
renderdata . mainSurface = s = = pWindow - > m_pWLSurface - > resource ( ) ;
m_sRenderPass . add ( makeShared < CSurfacePassElement > ( renderdata ) ) ;
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 ) {
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations ) {
2023-12-11 16:32:00 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_OVER )
continue ;
2023-11-04 13:10:52 +00:00
2024-03-30 18:14:26 -07:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha ) ;
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 ) {
CFramebuffer * last = g_pHyprOpenGL - > m_RenderData . currentFB ;
2024-08-26 20:24:30 +02:00
for ( auto const & t : pWindow - > m_vTransformers ) {
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
}
2023-11-16 20:20:41 +00:00
g_pHyprOpenGL - > m_RenderData . clipBox = CBox ( ) ;
2022-07-12 09:49:56 +02:00
if ( mode = = RENDER_PASS_ALL | | mode = = RENDER_PASS_POPUP ) {
if ( ! pWindow - > m_bIsX11 ) {
2024-05-10 23:28:33 +01:00
CBox geom = pWindow - > m_pXDGSurface - > 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 PBLURPOPUPS = CConfigValue < Hyprlang : : INT > ( " decoration:blur:popups " ) ;
static CConfigValue PBLURIGNOREA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:popups_ignorealpha " ) ;
2024-11-17 16:42:30 +00:00
renderdata . blur = * PBLURPOPUPS & & * PBLUR ;
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
}
2024-07-11 14:10:42 +00:00
if ( pWindow - > m_sWindowData . 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 ;
2024-05-10 23:28:33 +01:00
pWindow - > m_pPopupHead - > breadthfirst (
2024-12-22 17:12:09 +01:00
[ this , & renderdata ] ( CPopup * popup , void * data ) {
2024-11-17 16:16:49 +00:00
if ( ! popup - > m_pWLSurface | | ! popup - > m_pWLSurface - > resource ( ) | | ! popup - > m_bMapped )
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 ;
popup - > m_pWLSurface - > resource ( ) - > breadthfirst (
[ this , & renderdata ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
renderdata . texture = s - > current . texture ;
renderdata . surface = s ;
renderdata . mainSurface = false ;
m_sRenderPass . add ( makeShared < CSurfacePassElement > ( renderdata ) ) ;
renderdata . surfaceCounter + + ;
} ,
data ) ;
renderdata . pos = oldPos ;
2024-05-10 23:28:33 +01:00
} ,
& renderdata ) ;
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 ) {
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations ) {
2023-12-11 16:32:00 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_OVERLAY )
continue ;
2023-11-04 13:10:52 +00:00
2024-03-30 18:14:26 -07:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha ) ;
2023-12-11 16:32:00 +00:00
}
2023-11-04 13:10:52 +00:00
}
2022-05-17 13:16:37 +02:00
}
2024-12-22 22:07:08 +00:00
// for plugins
g_pHyprOpenGL - > m_RenderData . currentWindow = pWindow ;
2023-05-26 13:07:45 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WINDOW ) ;
2024-12-22 22:07:08 +00:00
g_pHyprOpenGL - > m_RenderData . currentWindow . reset ( ) ;
2022-03-21 19:18:33 +01:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderLayer ( PHLLS pLayer , PHLMONITOR pMonitor , timespec * time , bool popups ) {
2024-08-07 13:31:27 +02:00
if ( ! pLayer )
return ;
2024-04-11 21:41:18 +10:00
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
if ( * PDIMAROUND & & pLayer - > dimAround & & ! m_bRenderingSnapshot & & ! popups ) {
2024-12-22 17:12:09 +01:00
CRectPassElement : : SRectData data ;
data . box = { 0 , 0 , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . x , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . y } ;
2025-01-07 17:55:14 +00:00
data . color = CHyprColor ( 0 , 0 , 0 , * PDIMAROUND * pLayer - > alpha - > value ( ) ) ;
2024-12-22 17:12:09 +01:00
m_sRenderPass . add ( makeShared < CRectPassElement > ( data ) ) ;
2024-04-11 21:41:18 +10:00
}
2022-05-14 17:23:46 +02:00
if ( pLayer - > 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 ;
}
2024-11-17 16:42:30 +00:00
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderLayer " ) ;
2025-01-07 17:55:14 +00:00
const auto REALPOS = pLayer - > realPosition - > value ( ) ;
const auto REALSIZ = pLayer - > 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-01-07 17:55:14 +00:00
renderdata . fadeAlpha = pLayer - > alpha - > value ( ) ;
2024-12-22 17:12:09 +01:00
renderdata . blur = pLayer - > forceBlur & & * PBLUR ;
renderdata . surface = pLayer - > surface - > resource ( ) ;
renderdata . decorate = false ;
renderdata . w = REALSIZ . x ;
renderdata . h = REALSIZ . y ;
renderdata . pLS = pLayer ;
renderdata . blockBlurOptimization = pLayer - > layer = = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM | | pLayer - > layer = = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ;
2024-02-28 15:00:34 +00:00
2024-12-22 17:12:09 +01:00
renderdata . clipBox = CBox { 0 , 0 , pMonitor - > vecSize . x , pMonitor - > vecSize . y } . scale ( pMonitor - > scale ) ;
2024-03-25 16:08:55 +00:00
if ( renderdata . blur & & pLayer - > ignoreAlpha ) {
2024-12-22 17:12:09 +01:00
renderdata . discardMode | = DISCARD_ALPHA ;
renderdata . discardOpacity = pLayer - > 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 )
2024-12-22 17:12:09 +01:00
pLayer - > surface - > resource ( ) - > breadthfirst (
[ this , & renderdata , & pLayer ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) {
renderdata . localPos = offset ;
renderdata . texture = s - > current . texture ;
renderdata . surface = s ;
renderdata . mainSurface = s = = pLayer - > surface - > resource ( ) ;
m_sRenderPass . add ( makeShared < CSurfacePassElement > ( renderdata ) ) ;
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 ;
2024-03-25 16:08:55 +00:00
renderdata . blur = pLayer - > forceBlurPopups ;
2024-06-17 12:42:32 +02:00
renderdata . surfaceCounter = 0 ;
2024-05-09 21:47:21 +01:00
if ( popups ) {
pLayer - > popupHead - > breadthfirst (
2024-12-22 17:12:09 +01:00
[ this , & renderdata ] ( CPopup * popup , void * data ) {
2024-11-17 16:16:49 +00:00
if ( ! popup - > m_pWLSurface | | ! popup - > m_pWLSurface - > resource ( ) | | ! popup - > m_bMapped )
2024-05-09 21:47:21 +01:00
return ;
2024-12-22 17:12:09 +01:00
Vector2D pos = popup - > coordsRelativeToParent ( ) ;
renderdata . localPos = pos ;
renderdata . texture = popup - > m_pWLSurface - > resource ( ) - > current . texture ;
renderdata . surface = popup - > m_pWLSurface - > resource ( ) ;
renderdata . mainSurface = false ;
m_sRenderPass . add ( makeShared < CSurfacePassElement > ( renderdata ) ) ;
renderdata . surfaceCounter + + ;
2024-05-09 21:47:21 +01:00
} ,
& renderdata ) ;
}
2022-05-14 17:23:46 +02:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderIMEPopup ( CInputPopup * pPopup , PHLMONITOR pMonitor , timespec * 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 ;
2024-06-08 10:07:59 +02:00
renderdata . w = SURF - > current . size . x ;
renderdata . h = SURF - > 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 ;
renderdata . texture = s - > current . texture ;
renderdata . surface = s ;
renderdata . mainSurface = s = = SURF ;
m_sRenderPass . add ( makeShared < CSurfacePassElement > ( renderdata ) ) ;
renderdata . surfaceCounter + + ;
} ,
& renderdata ) ;
2022-08-05 17:07:01 +02:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderSessionLockSurface ( SSessionLockSurface * pSurface , PHLMONITOR pMonitor , timespec * time ) {
2024-12-22 17:12:09 +01:00
CSurfacePassElement : : SRenderData renderdata = { pMonitor , time , pMonitor - > vecPosition , pMonitor - > vecPosition } ;
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 ;
renderdata . w = pMonitor - > vecSize . x ;
renderdata . h = pMonitor - > vecSize . y ;
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 ;
renderdata . texture = s - > current . texture ;
renderdata . surface = s ;
renderdata . mainSurface = s = = pSurface - > surface - > surface ( ) ;
m_sRenderPass . add ( makeShared < CSurfacePassElement > ( renderdata ) ) ;
renderdata . surfaceCounter + + ;
} ,
& renderdata ) ;
2023-02-03 11:58:55 +00:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderAllClientsForWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * 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 " ) ;
2023-04-12 12:41:23 +01:00
if ( ! pMonitor )
2022-03-17 20:22:29 +01:00
return ;
2024-04-30 16:32:05 +01:00
if ( g_pSessionLockManager - > isSessionLocked ( ) & & ! g_pSessionLockManager - > isSessionLockPresent ( ) ) {
2023-02-03 11:58:55 +00:00
// locked with no exclusive, draw only red
2024-08-29 23:30:12 +02:00
renderSessionLockMissing ( pMonitor ) ;
2023-02-03 11:58:55 +00:00
return ;
}
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 ) ) ;
if ( ! RENDERMODIFDATA . modifs . empty ( ) ) {
g_pHyprRenderer - > m_sRenderPass . add ( makeShared < 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 ( ) ) {
g_pHyprRenderer - > m_sRenderPass . add ( makeShared < CRendererHintsPassElement > ( CRendererHintsPassElement : : SData { SRenderModifData { } } ) ) ;
}
} ) ;
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 */ )
m_sRenderPass . add ( makeShared < CClearPassElement > ( CClearPassElement : : SClearData { CHyprColor ( * PBACKGROUNDCOLOR ) } ) ) ;
else
g_pHyprOpenGL - > clearWithTex ( ) ; // will apply the hypr "wallpaper"
2024-04-03 14:09:58 +01:00
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ 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
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ 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
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ 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
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ 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 */ )
m_sRenderPass . add ( makeShared < CClearPassElement > ( CClearPassElement : : SClearData { CHyprColor ( * PBACKGROUNDCOLOR ) } ) ) ;
else
g_pHyprOpenGL - > clearWithTex ( ) ; // will apply the hypr "wallpaper"
2023-11-26 15:06:42 +00:00
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ 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
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ 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 ( ) ;
2023-09-04 15:07:56 +02:00
if ( pWorkspace - > m_bHasFullscreenWindow )
renderWorkspaceWindowsFullscreen ( pMonitor , pWorkspace , time ) ;
else
renderWorkspaceWindows ( pMonitor , pWorkspace , time ) ;
2022-05-31 14:01:00 +02:00
// and then special
2024-08-26 17:25:39 +02:00
for ( auto const & ws : g_pCompositor - > m_vWorkspaces ) {
2025-01-07 17:55:14 +00:00
if ( ws - > m_pMonitor = = pMonitor & & ws - > m_fAlpha - > value ( ) > 0.f & & ws - > m_bIsSpecialWorkspace ) {
const auto SPECIALANIMPROGRS = ws - > m_vRenderOffset - > isBeingAnimated ( ) ? ws - > m_vRenderOffset - > getCurveValue ( ) : ws - > m_fAlpha - > getCurveValue ( ) ;
2024-04-02 20:32:39 +01:00
const bool ANIMOUT = ! pMonitor - > activeSpecialWorkspace ;
2022-12-28 15:18:23 +01:00
2024-03-03 18:39:20 +00:00
if ( * PDIMSPECIAL ! = 0.f ) {
2024-12-22 17:12:09 +01:00
CRectPassElement : : SRectData data ;
data . box = { translate . x , translate . y , pMonitor - > vecTransformedSize . x * scale , pMonitor - > vecTransformedSize . y * scale } ;
data . color = CHyprColor ( 0 , 0 , 0 , * PDIMSPECIAL * ( ANIMOUT ? ( 1.0 - SPECIALANIMPROGRS ) : SPECIALANIMPROGRS ) ) ;
g_pHyprRenderer - > m_sRenderPass . add ( makeShared < CRectPassElement > ( data ) ) ;
2022-12-28 15:18:23 +01:00
}
2024-03-03 18:39:20 +00:00
if ( * PBLURSPECIAL & & * PBLUR ) {
2024-12-22 17:12:09 +01:00
CRectPassElement : : SRectData data ;
data . box = { translate . x , translate . y , pMonitor - > vecTransformedSize . x * scale , pMonitor - > vecTransformedSize . y * scale } ;
data . color = CHyprColor ( 0 , 0 , 0 , 0 ) ;
data . blur = true ;
data . blurA = ( ANIMOUT ? ( 1.0 - SPECIALANIMPROGRS ) : SPECIALANIMPROGRS ) ;
g_pHyprRenderer - > m_sRenderPass . add ( makeShared < CRectPassElement > ( data ) ) ;
2023-08-25 17:43:23 +02:00
}
2023-08-25 18:05:08 +02:00
break ;
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
2024-08-26 17:25:39 +02:00
for ( auto const & ws : g_pCompositor - > m_vWorkspaces ) {
2025-01-07 17:55:14 +00:00
if ( ws - > m_fAlpha - > value ( ) > 0.f & & ws - > m_bIsSpecialWorkspace ) {
2024-03-04 15:29:45 -08:00
if ( ws - > m_bHasFullscreenWindow )
2024-04-02 20:32:39 +01:00
renderWorkspaceWindowsFullscreen ( pMonitor , ws , time ) ;
2024-03-04 15:29:45 -08:00
else
2024-04-02 20:32:39 +01:00
renderWorkspaceWindows ( pMonitor , ws , time ) ;
2024-03-04 15:29:45 -08:00
}
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
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2023-11-22 20:05:50 +00:00
if ( w - > isHidden ( ) & & ! w - > m_bIsMapped & & ! w - > m_bFadingOut )
continue ;
if ( ! w - > m_bPinned | | ! w - > m_bIsFloating )
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
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ 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
2024-08-26 20:24:30 +02:00
for ( auto const & imep : g_pInputManager - > m_sIMERelay . m_vIMEPopups ) {
2024-03-24 16:08:25 +00:00
renderIMEPopup ( imep . get ( ) , pMonitor , time ) ;
2022-08-05 17:07:01 +02:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ 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
2024-08-26 20:24:30 +02:00
for ( auto const & lsl : pMonitor - > m_aLayerSurfaceLayers ) {
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
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderLockscreen ( PHLMONITOR pMonitor , timespec * now , const CBox & geometry ) {
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderLockscreen " ) ;
2023-02-03 11:58:55 +00:00
if ( g_pSessionLockManager - > isSessionLocked ( ) ) {
2024-03-15 17:17:13 +01:00
Vector2D translate = { geometry . x , geometry . y } ;
2023-02-03 11:58:55 +00:00
2024-03-15 17:17:13 +01:00
const auto PSLS = g_pSessionLockManager - > getSessionLockSurfaceForMonitor ( pMonitor - > ID ) ;
2024-11-17 15:58:18 +00:00
if ( ! PSLS ) {
if ( g_pSessionLockManager - > shallConsiderLockMissing ( ) )
renderSessionLockMissing ( pMonitor ) ;
} else {
2023-04-12 12:41:23 +01:00
renderSessionLockSurface ( PSLS , pMonitor , now ) ;
2024-07-13 18:32:08 +08:00
g_pSessionLockManager - > onLockscreenRenderedOnMonitor ( pMonitor - > ID ) ;
2023-02-03 11:58:55 +00:00
}
}
2022-03-17 20:22:29 +01:00
}
2022-03-19 14:07:18 +01:00
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderSessionLockMissing ( PHLMONITOR pMonitor ) {
2024-08-29 23:30:12 +02:00
const auto ALPHA = g_pSessionLockManager - > getRedScreenAlphaForMonitor ( pMonitor - > ID ) ;
CBox monbox = { { } , pMonitor - > vecPixelSize } ;
const bool ANY_PRESENT = g_pSessionLockManager - > anySessionLockSurfacesPresent ( ) ;
if ( ANY_PRESENT ) {
// render image2, without instructions. Lock still "alive", unless texture dead
2024-11-01 15:52:03 +00:00
g_pHyprOpenGL - > renderTexture ( g_pHyprOpenGL - > m_pLockDead2Texture , & monbox , ALPHA ) ;
2024-08-29 23:30:12 +02:00
} else {
// render image, with instructions. Lock is gone.
2024-11-01 15:52:03 +00:00
g_pHyprOpenGL - > renderTexture ( g_pHyprOpenGL - > m_pLockDeadTexture , & monbox , ALPHA ) ;
2024-08-29 23:30:12 +02:00
2024-11-01 15:52:03 +00:00
// also render text for the tty number
if ( g_pHyprOpenGL - > m_pLockTtyTextTexture ) {
CBox texbox = { { } , g_pHyprOpenGL - > m_pLockTtyTextTexture - > m_vSize } ;
g_pHyprOpenGL - > renderTexture ( g_pHyprOpenGL - > m_pLockTtyTextTexture , & texbox , 1.F ) ;
}
2024-08-29 23:30:12 +02:00
}
if ( ALPHA < 1.f ) /* animate */
damageMonitor ( pMonitor ) ;
else
g_pSessionLockManager - > onLockscreenRenderedOnMonitor ( pMonitor - > ID ) ;
}
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 ) {
2023-01-29 13:58:47 +00:00
if ( ! pWindow | | ! pWindow - > m_bIsX11 ) {
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
2024-06-08 10:07:59 +02:00
if ( pSurface - > current . viewport . hasSource ) {
2023-01-20 19:44:30 +01:00
// we stretch it to dest. if no dest, to 1,1
2024-10-31 00:20:32 +01:00
Vector2D const & bufferSize = pSurface - > current . bufferSize ;
auto const & bufferSource = pSurface - > 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
2024-07-31 20:47:26 +01:00
const Vector2D PIXELASUV = Vector2D { 1 , 1 } / pSurface - > current . bufferSize ;
const Vector2D MISALIGNMENT = pSurface - > 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 ) {
const auto MONITOR_WL_SCALE = std : : ceil ( pMonitor - > scale ) ;
const bool SCALE_UNAWARE = MONITOR_WL_SCALE ! = pSurface - > current . scale & & ! pSurface - > current . viewport . hasDestination ;
const auto EXPECTED_SIZE =
( ( pSurface - > current . viewport . hasDestination ? pSurface - > current . viewport . destination : pSurface - > current . bufferSize / pSurface - > current . scale ) * pMonitor - > scale )
. 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
const auto FIX = projSize / EXPECTED_SIZE ;
uvBR = uvBR * FIX ;
}
2024-10-05 00:52:53 +01:00
}
2022-12-16 17:17:31 +00:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = uvTL ;
2022-08-28 10:14:43 +02:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = uvBR ;
if ( g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = = Vector2D ( ) & & g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = = Vector2D ( 1 , 1 ) ) {
// No special UV mods needed
2022-12-16 17:17:31 +00:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:14:43 +02:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
}
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
2024-05-10 23:28:33 +01:00
CBox geom = pWindow - > m_pXDGSurface - > current . geometry ;
2023-01-20 19:44:30 +01:00
// ignore X and Y, adjust uv
2024-10-05 00:52:53 +01:00
if ( geom . x ! = 0 | | geom . y ! = 0 | | geom . width > projSizeUnscaled . x | | geom . height > projSizeUnscaled . y ) {
2024-06-08 10:07:59 +02:00
const auto XPERC = ( double ) geom . x / ( double ) pSurface - > current . size . x ;
const auto YPERC = ( double ) geom . y / ( double ) pSurface - > current . size . y ;
const auto WPERC = ( double ) ( geom . x + geom . width ) / ( double ) pSurface - > current . size . x ;
const auto HPERC = ( double ) ( geom . y + geom . height ) / ( double ) pSurface - > 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 ;
2022-08-28 10:14:43 +02:00
2024-10-05 00:52:53 +01:00
auto maxSize = projSizeUnscaled ;
2023-11-12 23:57:53 +00:00
2024-06-08 10:07:59 +02:00
if ( pWindow - > m_pWLSurface - > small ( ) & & ! pWindow - > m_pWLSurface - > m_bFillIgnoreSmall )
maxSize = pWindow - > m_pWLSurface - > getViewporterCorrectedSize ( ) ;
2023-11-12 23:57:53 +00:00
if ( geom . width > maxSize . x )
uvBR . x = uvBR . x * ( maxSize . x / geom . width ) ;
if ( geom . height > maxSize . y )
uvBR . y = uvBR . y * ( maxSize . y / geom . height ) ;
2023-01-20 19:44:30 +01:00
}
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = uvTL ;
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = uvBR ;
if ( g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = = Vector2D ( ) & & g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = = Vector2D ( 1 , 1 ) ) {
// No special UV mods needed
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 {
2022-12-16 17:17:31 +00:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:14:43 +02:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
}
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderMonitor ( PHLMONITOR pMonitor ) {
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 " ) ;
2024-08-06 14:52:19 +01:00
static auto PDIRECTSCANOUT = CConfigValue < Hyprlang : : INT > ( " render:direct_scanout " ) ;
2024-03-03 18:39:20 +00:00
static auto PVFR = CConfigValue < Hyprlang : : INT > ( " misc:vfr " ) ;
2024-05-09 22:23:01 +01:00
static auto PZOOMFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " cursor:zoom_factor " ) ;
2024-03-03 18:39:20 +00:00
static auto PANIMENABLED = CConfigValue < Hyprlang : : INT > ( " animations:enabled " ) ;
static auto PFIRSTLAUNCHANIM = CConfigValue < Hyprlang : : INT > ( " animations:first_launch_animation " ) ;
static auto PTEARINGENABLED = CConfigValue < Hyprlang : : INT > ( " general:allow_tearing " ) ;
2023-03-24 19:23:16 +00:00
static int damageBlinkCleanup = 0 ; // because double-buffered
2024-03-03 18:39:20 +00:00
if ( ! * PDAMAGEBLINK )
2023-03-24 19:23:16 +00:00
damageBlinkCleanup = 0 ;
2023-05-24 15:49:27 +02:00
static bool firstLaunch = true ;
2024-03-03 18:39:20 +00:00
static bool firstLaunchAnimActive = * PFIRSTLAUNCHANIM ;
2023-05-01 02:49:41 +01:00
float zoomInFactorFirstLaunch = 1.f ;
if ( firstLaunch ) {
firstLaunch = false ;
m_tRenderTimer . reset ( ) ;
}
2023-05-24 15:49:27 +02:00
if ( m_tRenderTimer . getSeconds ( ) < 1.5f & & firstLaunchAnimActive ) { // TODO: make the animation system more damage-flexible so that this can be migrated to there
2024-03-03 18:39:20 +00:00
if ( ! * PANIMENABLED ) {
2023-07-22 19:26:39 +02:00
zoomInFactorFirstLaunch = 1.f ;
firstLaunchAnimActive = false ;
} else {
zoomInFactorFirstLaunch = 2.f - g_pAnimationManager - > getBezier ( " default " ) - > getYForPoint ( m_tRenderTimer . getSeconds ( ) / 1.5 ) ;
damageMonitor ( pMonitor ) ;
}
2023-05-24 15:49:27 +02:00
} else {
firstLaunchAnimActive = false ;
2023-05-01 02:49:41 +01:00
}
2023-11-24 10:54:21 +00:00
renderStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( * PDEBUGOVERLAY = = 1 )
2023-03-24 19:23:16 +00:00
g_pDebugOverlay - > frameData ( pMonitor ) ;
2024-12-29 17:19:12 -06:00
if ( ! g_pCompositor - > m_bSessionActive )
2023-03-24 19:23:16 +00:00
return ;
if ( pMonitor - > ID = = m_pMostHzMonitor - > 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_pCompositor - > sanityCheckWorkspaces ( ) ;
g_pConfigManager - > dispatchExecOnce ( ) ; // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
if ( g_pConfigManager - > m_bWantsMonitorReload )
g_pConfigManager - > performMonitorReload ( ) ;
}
if ( pMonitor - > scheduledRecalc ) {
pMonitor - > scheduledRecalc = false ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitor - > ID ) ;
}
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > output - > needsFrame & & pMonitor - > forceFullFrames = = 0 )
return ;
2023-09-28 21:48:33 +01:00
// tearing and DS first
bool shouldTear = false ;
2023-09-30 17:07:50 +01:00
if ( pMonitor - > tearingState . nextRenderTorn ) {
pMonitor - > tearingState . nextRenderTorn = false ;
2023-09-28 21:48:33 +01:00
2024-03-03 18:39:20 +00:00
if ( ! * PTEARINGENABLED ) {
2023-09-28 21:48:33 +01:00
Debug : : log ( WARN , " Tearing commit requested but the master switch general:allow_tearing is off, ignoring " ) ;
return ;
}
if ( g_pHyprOpenGL - > m_RenderData . mouseZoomFactor ! = 1.0 ) {
Debug : : log ( WARN , " Tearing commit requested but scale factor is not 1, ignoring " ) ;
return ;
}
2023-09-30 17:07:50 +01:00
if ( ! pMonitor - > tearingState . canTear ) {
2023-09-28 21:48:33 +01:00
Debug : : log ( WARN , " Tearing commit requested but monitor doesn't support it, ignoring " ) ;
return ;
}
2024-04-27 12:43:12 +01:00
if ( ! pMonitor - > solitaryClient . expired ( ) )
2023-09-28 21:48:33 +01:00
shouldTear = true ;
}
2024-07-30 15:50:14 +02:00
pMonitor - > tearingState . activelyTearing = shouldTear ;
2024-08-06 14:52:19 +01:00
if ( * PDIRECTSCANOUT & & ! shouldTear ) {
2024-07-21 13:09:54 +02:00
if ( pMonitor - > attemptDirectScanout ( ) ) {
2023-03-24 19:23:16 +00:00
return ;
2024-07-21 13:09:54 +02:00
} else if ( ! pMonitor - > lastScanout . expired ( ) ) {
2023-03-24 19:23:16 +00:00
Debug : : log ( LOG , " Left a direct scanout. " ) ;
2024-07-21 13:09:54 +02:00
pMonitor - > lastScanout . reset ( ) ;
2024-08-17 19:27:11 +02:00
2024-12-29 17:19:12 -06:00
// reset DRM format, but only if needed since it might modeset
if ( pMonitor - > output - > state - > state ( ) . drmFormat ! = pMonitor - > prevDrmFormat )
pMonitor - > output - > state - > setFormat ( pMonitor - > prevDrmFormat ) ;
2024-08-31 08:07:52 -05:00
pMonitor - > drmFormat = pMonitor - > prevDrmFormat ;
2023-03-24 19:23:16 +00:00
}
}
EMIT_HOOK_EVENT ( " preRender " , pMonitor ) ;
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
// check the damage
2024-07-21 13:09:54 +02:00
bool hasChanged = pMonitor - > output - > needsFrame | | pMonitor - > damage . hasChanged ( ) ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( ! hasChanged & & * PDAMAGETRACKINGMODE ! = DAMAGE_TRACKING_NONE & & pMonitor - > 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 ) ;
2023-03-24 19:23:16 +00:00
pMonitor - > renderingActive = true ;
2024-02-19 18:17:32 +00:00
// we need to cleanup fading out when rendering the appropriate context
g_pCompositor - > cleanupFadingOut ( pMonitor - > ID ) ;
// 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 ;
if ( zoomLock & & * PZOOMFACTOR = = 1.f ) {
g_pPointerManager - > unlockSoftwareAll ( ) ;
zoomLock = false ;
} else if ( ! zoomLock & & * PZOOMFACTOR ! = 1.f ) {
g_pPointerManager - > lockSoftwareAll ( ) ;
zoomLock = true ;
}
2024-02-18 16:04:08 +00:00
if ( pMonitor = = g_pCompositor - > getMonitorFromCursor ( ) )
2024-03-03 18:39:20 +00:00
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = std : : clamp ( * PZOOMFACTOR , 1.f , INFINITY ) ;
2024-02-18 16:04:08 +00:00
else
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = 1.f ;
if ( zoomInFactorFirstLaunch > 1.f ) {
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = zoomInFactorFirstLaunch ;
g_pHyprOpenGL - > m_RenderData . mouseZoomUseMouse = false ;
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = false ;
2024-02-29 19:04:40 +00:00
pMonitor - > forceFullFrames = 10 ;
2024-02-18 16:04:08 +00:00
}
2024-02-23 01:02:32 +00: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
2024-12-22 17:12:09 +01:00
if ( * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_NONE | | * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_MONITOR | | pMonitor - > forceFullFrames > 0 | | damageBlinkCleanup > 0 )
damage = { 0 , 0 , ( int ) pMonitor - > vecTransformedSize . x * 10 , ( int ) pMonitor - > vecTransformedSize . y * 10 } ;
2023-03-24 19:23:16 +00:00
2024-12-22 17:12:09 +01:00
finalDamage = damage ;
2023-03-24 19:23:16 +00:00
2024-02-19 18:17:32 +00:00
// update damage in renderdata as we modified it
2024-02-23 01:02:32 +00:00
g_pHyprOpenGL - > setDamage ( damage , finalDamage ) ;
2023-03-24 19:23:16 +00:00
2024-02-19 18:17:32 +00:00
if ( pMonitor - > forceFullFrames > 0 ) {
pMonitor - > forceFullFrames - = 1 ;
if ( pMonitor - > forceFullFrames > 10 )
pMonitor - > forceFullFrames = 0 ;
}
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 ;
2024-04-23 12:29:01 +01:00
if ( ! finalDamage . empty ( ) ) {
2024-04-27 12:43:12 +01:00
if ( pMonitor - > 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 {
CBox renderBox = { 0 , 0 , ( int ) pMonitor - > vecPixelSize . x , ( int ) pMonitor - > vecPixelSize . y } ;
renderWorkspace ( pMonitor , pMonitor - > activeWorkspace , & now , renderBox ) ;
renderLockscreen ( pMonitor , & now , renderBox ) ;
2024-10-19 23:03:29 +01:00
if ( pMonitor = = g_pCompositor - > m_pLastMonitor ) {
2024-04-23 12:29:01 +01:00
g_pHyprNotificationOverlay - > draw ( pMonitor ) ;
g_pHyprError - > draw ( ) ;
}
// for drawing the debug overlay
2024-10-19 23:03:29 +01:00
if ( pMonitor = = g_pCompositor - > m_vMonitors . 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 ;
data . box = { 0 , 0 , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y } ;
data . color = CHyprColor ( 1.0 , 0.0 , 1.0 , 100.0 / 255.0 ) ;
m_sRenderPass . add ( makeShared < 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
2024-12-22 17:12:09 +01:00
renderWindow ( pMonitor - > solitaryClient . lock ( ) , pMonitor , & now , false , RENDER_PASS_MAIN /* solitary = no popups */ ) ;
2024-06-09 22:28:51 +02:00
} else if ( ! pMonitor - > isMirror ( ) ) {
2024-04-23 16:08:54 +01:00
sendFrameEventsToWorkspace ( pMonitor , pMonitor - > activeWorkspace , & now ) ;
if ( pMonitor - > activeSpecialWorkspace )
sendFrameEventsToWorkspace ( pMonitor , pMonitor - > 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 " ) ;
2024-05-10 23:38:46 +01:00
g_pPointerManager - > renderSoftwareCursorsFor ( pMonitor - > self . lock ( ) , & now , g_pHyprOpenGL - > m_RenderData . damage ) ;
2023-05-01 02:49:41 +01:00
}
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 ;
2024-12-29 17:19:12 -06:00
CRegion frameDamage { g_pHyprOpenGL - > m_RenderData . damage } ;
2023-03-24 19:23:16 +00:00
2024-12-29 17:19:12 -06:00
const auto TRANSFORM = invertTransform ( pMonitor - > transform ) ;
frameDamage . transform ( wlTransformToHyprutils ( TRANSFORM ) , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . 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 )
frameDamage . add ( 0 , 0 , ( int ) pMonitor - > vecTransformedSize . x , ( int ) pMonitor - > vecTransformedSize . 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
2024-12-29 17:19:12 -06:00
if ( ! pMonitor - > mirrors . empty ( ) )
2024-12-22 17:12:09 +01:00
damageMirrorsWith ( pMonitor , frameDamage ) ;
2024-07-30 15:46:35 +02:00
2023-03-24 19:23:16 +00:00
pMonitor - > renderingActive = false ;
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST ) ;
2024-12-29 17:19:12 -06:00
pMonitor - > output - > state - > addDamage ( frameDamage ) ;
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setPresentationMode ( shouldTear ? Aquamarine : : eOutputPresentationMode : : AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine : : eOutputPresentationMode : : AQ_OUTPUT_PRESENTATION_VSYNC ) ;
2023-09-28 21:48:33 +01:00
2024-07-21 13:09:54 +02:00
commitPendingAndDoExplicitSync ( pMonitor ) ;
2023-04-03 17:01:05 +01:00
2023-09-28 21:48:33 +01:00
if ( shouldTear )
2023-09-30 17:07:50 +01:00
pMonitor - > tearingState . busy = true ;
2023-09-28 21:48:33 +01:00
2024-03-03 18:39:20 +00:00
if ( * PDAMAGEBLINK | | * PVFR = = 0 | | pMonitor - > 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
pMonitor - > pendingFrame = false ;
2024-08-12 19:19:03 +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 ) ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( * PDEBUGOVERLAY = = 1 ) {
2024-10-19 23:03:29 +01:00
if ( pMonitor = = g_pCompositor - > m_vMonitors . 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-01-07 21:32:50 +03:00
static const auto BT709 = Aquamarine : : IOutput : : SChromaticityCoords {
. red = Aquamarine : : IOutput : : xy { . x = 0.64 , . y = 0.33 } ,
. green = Aquamarine : : IOutput : : xy { . x = 0.30 , . y = 0.60 } ,
. blue = Aquamarine : : IOutput : : xy { . x = 0.15 , . y = 0.06 } ,
. white = Aquamarine : : IOutput : : xy { . x = 0.3127 , . y = 0.3290 } ,
} ;
static hdr_output_metadata createHDRMetadata ( uint8_t eotf , Aquamarine : : IOutput : : SParsedEDID edid ) {
if ( eotf = = 0 )
return hdr_output_metadata { . hdmi_metadata_type1 = hdr_metadata_infoframe { . eotf = 0 } } ; // empty metadata for SDR
const auto toNits = [ ] ( float value ) { return uint16_t ( std : : round ( value ) ) ; } ;
const auto to16Bit = [ ] ( float value ) { return uint16_t ( std : : round ( value * 50000 ) ) ; } ;
const auto colorimetry = edid . chromaticityCoords . value_or ( BT709 ) ;
Debug : : log ( TRACE , " ColorManagement primaries {},{} {},{} {},{} {},{} " , colorimetry . red . x , colorimetry . red . y , colorimetry . green . x , colorimetry . green . y , colorimetry . blue . x ,
colorimetry . blue . y , colorimetry . white . x , colorimetry . white . y ) ;
Debug : : log ( TRACE , " ColorManagement max avg {}, min {}, max {} " , edid . hdrMetadata - > desiredMaxFrameAverageLuminance , edid . hdrMetadata - > desiredContentMinLuminance ,
edid . hdrMetadata - > desiredContentMaxLuminance ) ;
return hdr_output_metadata {
. metadata_type = 0 ,
. hdmi_metadata_type1 =
hdr_metadata_infoframe {
. eotf = eotf ,
. metadata_type = 0 ,
. display_primaries =
{
{ . 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 ) } ,
} ,
. white_point = { . x = to16Bit ( colorimetry . white . x ) , . y = to16Bit ( colorimetry . white . y ) } ,
. max_display_mastering_luminance = toNits ( edid . hdrMetadata - > desiredMaxFrameAverageLuminance ) ,
. min_display_mastering_luminance = toNits ( edid . hdrMetadata - > desiredContentMinLuminance * 10000 ) ,
. max_cll = toNits ( edid . hdrMetadata - > desiredMaxFrameAverageLuminance ) ,
. max_fall = toNits ( edid . hdrMetadata - > desiredMaxFrameAverageLuminance ) ,
} ,
} ;
}
static hdr_output_metadata createHDRMetadata ( SImageDescription settings , Aquamarine : : IOutput : : SParsedEDID edid ) {
if ( settings . transferFunction ! = XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ )
return hdr_output_metadata { . hdmi_metadata_type1 = hdr_metadata_infoframe { . eotf = 0 } } ; // empty metadata for SDR
const auto toNits = [ ] ( uint32_t value ) { return uint16_t ( std : : round ( value ) ) ; } ;
const auto to16Bit = [ ] ( uint32_t value ) { return uint16_t ( std : : round ( value * 50000 ) ) ; } ;
auto colorimetry = settings . primaries ;
auto luminances = settings . masteringLuminances . max > 0 ?
settings . masteringLuminances :
SImageDescription : : SPCMasteringLuminances { . min = edid . hdrMetadata - > desiredContentMinLuminance , . max = edid . hdrMetadata - > desiredContentMaxLuminance } ;
Debug : : log ( TRACE , " ColorManagement primaries {},{} {},{} {},{} {},{} " , colorimetry . red . x , colorimetry . red . y , colorimetry . green . x , colorimetry . green . y , colorimetry . blue . x ,
colorimetry . blue . y , colorimetry . white . x , colorimetry . white . y ) ;
Debug : : log ( TRACE , " ColorManagement min {}, max {}, cll {}, fall {} " , luminances . min , luminances . max , settings . maxCLL , settings . maxFALL ) ;
return hdr_output_metadata {
. metadata_type = 0 ,
. hdmi_metadata_type1 =
hdr_metadata_infoframe {
. eotf = 2 ,
. metadata_type = 0 ,
. display_primaries =
{
{ . 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 ) } ,
} ,
. 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 ) ,
} ,
} ;
}
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : commitPendingAndDoExplicitSync ( PHLMONITOR pMonitor ) {
2024-07-21 13:09:54 +02:00
// apply timelines for explicit sync
2024-08-06 14:52:19 +01:00
// save inFD otherwise reset will reset it
auto inFD = pMonitor - > output - > state - > state ( ) . explicitInFence ;
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > resetExplicitFences ( ) ;
2024-08-06 14:52:19 +01:00
if ( inFD > = 0 )
pMonitor - > output - > state - > setExplicitInFence ( inFD ) ;
2024-07-21 13:09:54 +02:00
2025-01-07 21:32:50 +03:00
static auto PWIDE = CConfigValue < Hyprlang : : INT > ( " experimental:wide_color_gamut " ) ;
2025-01-12 20:02:41 +03:00
if ( pMonitor - > output - > state - > state ( ) . wideColorGamut ! = * PWIDE ) {
2025-01-07 21:32:50 +03:00
Debug : : log ( TRACE , " Setting wide color gamut {} " , * PWIDE ? " on " : " off " ) ;
2025-01-12 20:02:41 +03:00
pMonitor - > output - > state - > setWideColorGamut ( * PWIDE ) ;
}
2025-01-07 21:32:50 +03:00
static auto PHDR = CConfigValue < Hyprlang : : INT > ( " experimental:hdr " ) ;
2025-01-08 10:28:55 +00:00
const bool SUPPORTSPQ = pMonitor - > output - > parsedEDID . hdrMetadata . has_value ( ) ? pMonitor - > output - > parsedEDID . hdrMetadata - > supportsPQ : false ;
Debug : : log ( TRACE , " ColorManagement supportsBT2020 {}, supportsPQ {} " , pMonitor - > output - > parsedEDID . supportsBT2020 , SUPPORTSPQ ) ;
if ( pMonitor - > output - > parsedEDID . supportsBT2020 & & SUPPORTSPQ ) {
2025-01-07 21:32:50 +03:00
if ( pMonitor - > activeWorkspace & & pMonitor - > activeWorkspace - > m_bHasFullscreenWindow & & pMonitor - > activeWorkspace - > m_efFullscreenMode = = FSMODE_FULLSCREEN ) {
const auto WINDOW = pMonitor - > activeWorkspace - > getFullscreenWindow ( ) ;
const auto SURF = WINDOW - > m_pWLSurface - > resource ( ) ;
2025-01-12 20:02:41 +03:00
if ( SURF - > colorManagement . valid ( ) & & SURF - > colorManagement - > hasImageDescription ( ) ) {
bool needsHdrMetadataUpdate = SURF - > colorManagement - > needsHdrMetadataUpdate ( ) | | m_previousFSWindow ! = WINDOW ;
if ( SURF - > colorManagement - > needsHdrMetadataUpdate ( ) )
SURF - > colorManagement - > setHDRMetadata ( createHDRMetadata ( SURF - > colorManagement . get ( ) - > imageDescription ( ) , pMonitor - > output - > parsedEDID ) ) ;
if ( needsHdrMetadataUpdate )
pMonitor - > output - > state - > setHDRMetadata ( SURF - > colorManagement - > hdrMetadata ( ) ) ;
} else
2025-01-07 21:32:50 +03:00
pMonitor - > output - > state - > setHDRMetadata ( * PHDR ? createHDRMetadata ( 2 , pMonitor - > output - > parsedEDID ) : createHDRMetadata ( 0 , pMonitor - > output - > parsedEDID ) ) ;
2025-01-12 20:02:41 +03:00
m_previousFSWindow = WINDOW ;
} else {
if ( ( pMonitor - > output - > state - > state ( ) . hdrMetadata . hdmi_metadata_type1 . eotf = = 2 ) ! = * PHDR )
pMonitor - > output - > state - > setHDRMetadata ( * PHDR ? createHDRMetadata ( 2 , pMonitor - > output - > parsedEDID ) : createHDRMetadata ( 0 , pMonitor - > output - > parsedEDID ) ) ;
m_previousFSWindow . reset ( ) ;
}
2025-01-07 21:32:50 +03:00
}
2024-10-08 16:59:15 +01:00
if ( pMonitor - > ctmUpdated ) {
pMonitor - > ctmUpdated = false ;
pMonitor - > output - > state - > setCTM ( pMonitor - > ctm ) ;
}
2024-08-06 14:52:19 +01:00
bool ok = pMonitor - > state . commit ( ) ;
if ( ! ok ) {
if ( inFD > = 0 ) {
Debug : : log ( TRACE , " Monitor state commit failed, retrying without a fence " ) ;
pMonitor - > output - > state - > resetExplicitFences ( ) ;
ok = pMonitor - > 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
pMonitor - > output - > swapchain - > rollback ( ) ;
pMonitor - > damage . damageEntire ( ) ;
}
2024-07-21 13:09:54 +02:00
}
2024-12-06 14:15:38 +00:00
auto explicitOptions = getExplicitSyncSettings ( ) ;
2024-08-06 14:52:19 +01:00
if ( ! explicitOptions . explicitEnabled )
2024-07-21 13:09:54 +02:00
return ok ;
2024-08-06 14:52:19 +01:00
if ( inFD > = 0 )
close ( inFD ) ;
2024-07-21 13:09:54 +02:00
2024-08-06 14:52:19 +01:00
Debug : : log ( TRACE , " Explicit: {} presented " , explicitPresented . size ( ) ) ;
auto sync = g_pHyprOpenGL - > createEGLSync ( - 1 ) ;
if ( ! sync )
Debug : : log ( TRACE , " Explicit: can't add sync, EGLSync failed " ) ;
else {
2024-08-26 20:24:30 +02:00
for ( auto const & e : explicitPresented ) {
2024-08-06 14:52:19 +01:00
if ( ! e - > current . buffer | | ! e - > current . buffer - > releaser )
continue ;
e - > current . buffer - > releaser - > addReleaseSync ( sync ) ;
}
2024-07-21 13:09:54 +02:00
}
2024-08-06 14:52:19 +01:00
explicitPresented . clear ( ) ;
pMonitor - > output - > state - > resetExplicitFences ( ) ;
2024-07-21 13:09:54 +02:00
return ok ;
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * now , const CBox & geometry ) {
2023-04-12 12:41:23 +01:00
Vector2D translate = { geometry . x , geometry . y } ;
float scale = ( float ) geometry . width / pMonitor - > vecPixelSize . x ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderWorkspace " ) ;
2023-04-12 12:50:20 +01:00
if ( ! DELTALESSTHAN ( ( double ) geometry . width / ( double ) geometry . height , pMonitor - > vecPixelSize . x / pMonitor - > vecPixelSize . 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
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : sendFrameEventsToWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * now ) {
2024-08-26 17:25:39 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-06-08 10:07:59 +02:00
if ( w - > isHidden ( ) | | ! w - > m_bIsMapped | | w - > m_bFadingOut | | ! w - > m_pWLSurface - > 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 ;
2024-06-08 10:07:59 +02:00
w - > m_pWLSurface - > resource ( ) - > breadthfirst ( [ now ] ( SP < CWLSurfaceResource > r , const Vector2D & offset , void * d ) { r - > frame ( now ) ; } , nullptr ) ;
2024-04-23 16:08:54 +01:00
}
2024-08-26 17:25:39 +02:00
for ( auto const & lsl : pMonitor - > m_aLayerSurfaceLayers ) {
for ( auto const & ls : lsl ) {
2024-06-08 10:07:59 +02:00
if ( ls - > fadingOut | | ! ls - > surface - > resource ( ) )
2024-04-23 21:15:37 +01:00
continue ;
2024-06-08 10:07:59 +02:00
ls - > 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 ) {
2023-11-04 17:03:05 +00:00
CBox full_area = { pMonitor - > vecPosition . x , pMonitor - > vecPosition . y , pMonitor - > vecSize . x , pMonitor - > vecSize . y } ;
2022-03-19 14:37:40 +01:00
2024-08-26 20:24:30 +02:00
for ( auto const & ls : layerSurfaces ) {
2024-07-21 13:09:54 +02:00
if ( ! ls | | ls - > fadingOut | | ls - > readyToDelete | | ! ls - > layerSurface | | ls - > noProcess )
2022-05-14 17:23:46 +02:00
continue ;
2022-03-21 17:00:17 +01:00
const auto PLAYER = ls - > layerSurface ;
const auto PSTATE = & PLAYER - > 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
2023-10-06 14:00:05 +01:00
const Vector2D OLDSIZE = { ls - > geometry . width , ls - > geometry . height } ;
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 ) {
2023-09-06 12:51:36 +02:00
Debug : : log ( ERR , " LayerSurface {:x} has a negative/zero w/h??? " , ( 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
2022-03-21 17:00:17 +01:00
ls - > 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 )
2024-05-09 21:47:21 +01:00
ls - > layerSurface - > configure ( box . size ( ) ) ;
2024-03-27 16:30:08 +00:00
2025-01-07 17:55:14 +00:00
* ls - > realPosition = box . pos ( ) ;
* ls - > 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
2022-12-16 17:17:31 +00:00
PMONITOR - > vecReservedBottomRight = Vector2D ( ) ;
PMONITOR - > vecReservedTopLeft = Vector2D ( ) ;
2022-03-19 14:37:40 +01:00
2023-11-04 17:03:05 +00:00
CBox usableArea = { PMONITOR - > vecPosition . x , PMONITOR - > vecPosition . y , PMONITOR - > vecSize . x , PMONITOR - > vecSize . y } ;
2022-03-21 17:00:17 +01:00
2024-10-08 21:20:25 +01:00
if ( g_pHyprError - > active ( ) & & g_pCompositor - > m_pLastMonitor = = PMONITOR - > self ) {
2024-10-08 21:58:40 +01:00
const auto HEIGHT = g_pHyprError - > height ( ) ;
if ( * BAR_POSITION = = 0 ) {
PMONITOR - > vecReservedTopLeft . y = HEIGHT ;
usableArea . y + = HEIGHT ;
usableArea . h - = HEIGHT ;
} else {
PMONITOR - > vecReservedBottomRight . y = HEIGHT ;
usableArea . h - = HEIGHT ;
}
2024-10-08 21:20:25 +01:00
}
2024-09-09 11:10:08 +02:00
for ( auto & la : PMONITOR - > m_aLayerSurfaceLayers ) {
std : : stable_sort ( la . begin ( ) , la . end ( ) , [ ] ( const PHLLSREF & a , const PHLLSREF & b ) { return a - > order > b - > order ; } ) ;
}
2024-08-26 17:25:39 +02:00
for ( auto const & la : PMONITOR - > m_aLayerSurfaceLayers )
2022-03-21 17:00:17 +01:00
arrangeLayerArray ( PMONITOR , la , true , & usableArea ) ;
2024-08-26 17:25:39 +02:00
for ( auto const & la : PMONITOR - > m_aLayerSurfaceLayers )
2022-03-21 17:00:17 +01:00
arrangeLayerArray ( PMONITOR , la , false , & usableArea ) ;
2022-12-16 17:17:31 +00:00
PMONITOR - > vecReservedTopLeft = Vector2D ( usableArea . x , usableArea . y ) - PMONITOR - > vecPosition ;
2022-03-21 17:00:17 +01:00
PMONITOR - > vecReservedBottomRight = PMONITOR - > vecSize - Vector2D ( usableArea . width , usableArea . height ) - PMONITOR - > vecReservedTopLeft ;
2022-10-17 23:23:01 +01:00
auto ADDITIONALRESERVED = g_pConfigManager - > m_mAdditionalReservedAreas . find ( PMONITOR - > szName ) ;
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 ( ) ) {
2022-12-16 17:17:31 +00:00
PMONITOR - > vecReservedTopLeft = PMONITOR - > vecReservedTopLeft + Vector2D ( ADDITIONALRESERVED - > second . left , ADDITIONALRESERVED - > second . top ) ;
2022-10-17 23:23:01 +01:00
PMONITOR - > vecReservedBottomRight = PMONITOR - > vecReservedBottomRight + Vector2D ( ADDITIONALRESERVED - > second . right , ADDITIONALRESERVED - > second . bottom ) ;
}
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
2022-08-10 23:14:53 +02:00
if ( g_pCompositor - > m_bUnsafeState )
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
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2023-03-16 16:32:03 +00:00
if ( ! m - > output )
continue ;
2024-02-19 11:24:54 +00:00
damageBoxForEach . set ( damageBox ) ;
damageBoxForEach . translate ( { - m - > vecPosition . x , - m - > vecPosition . y } ) . scale ( m - > scale ) ;
2022-07-28 22:15:56 +02:00
2022-08-23 16:07:47 +02: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 ) {
2022-08-10 23:14:53 +02:00
if ( g_pCompositor - > m_bUnsafeState )
return ;
2024-03-30 18:14:26 -07:00
CBox windowBox = pWindow - > getFullWindowBoundingBox ( ) ;
2024-04-02 20:32:39 +01:00
const auto PWINDOWWORKSPACE = pWindow - > m_pWorkspace ;
2025-01-07 17:55:14 +00:00
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_vRenderOffset - > isBeingAnimated ( ) & & ! pWindow - > m_bPinned )
windowBox . translate ( PWINDOWWORKSPACE - > m_vRenderOffset - > value ( ) ) ;
2024-03-30 18:14:26 -07:00
windowBox . translate ( pWindow - > m_vFloatingOffset ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2024-12-22 17:12:09 +01:00
if ( forceFull | | shouldRenderWindow ( pWindow , m ) ) { // only damage if window is rendered on monitor
2024-03-30 18:14:26 -07:00
CBox fixedDamageBox = { windowBox . x - m - > vecPosition . x , windowBox . y - m - > vecPosition . y , windowBox . width , windowBox . height } ;
fixedDamageBox . scale ( m - > scale ) ;
m - > addDamage ( & fixedDamageBox ) ;
}
2022-06-29 11:21:42 +02:00
}
2022-05-05 15:09:26 +02:00
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations )
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 )
2024-03-30 18:14:26 -07:00
Debug : : log ( LOG , " Damage: Window ({}): xy: {}, {} wh: {}, {} " , pWindow - > m_szTitle , 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 ) {
2022-09-13 15:25:42 +02:00
if ( g_pCompositor - > m_bUnsafeState | | 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 } ;
2022-08-23 16:07:47 +02: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 )
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Damage: Monitor {} " , pMonitor - > szName ) ;
2022-04-14 16:43:29 +02:00
}
2022-03-21 16:13:43 +01:00
2024-06-14 14:45:32 +03:00
void CHyprRenderer : : damageBox ( CBox * pBox , bool skipFrameSchedule ) {
2022-08-10 23:14:53 +02:00
if ( g_pCompositor - > m_bUnsafeState )
return ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
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 ) {
CBox damageBox = { pBox - > x - m - > vecPosition . x , pBox - > y - m - > vecPosition . y , pBox - > width , pBox - > height } ;
damageBox . scale ( m - > scale ) ;
2024-06-14 14:45:32 +03: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 )
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " Damage: Box: xy: {}, {} wh: {}, {} " , pBox - > x , pBox - > y , pBox - > width , pBox - > height ) ;
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 } ;
2022-05-05 14:02:30 +02:00
damageBox ( & box ) ;
}
2023-07-19 20:09:49 +02:00
void CHyprRenderer : : damageRegion ( const CRegion & rg ) {
2024-08-26 17:25:39 +02:00
for ( auto const & RECT : rg . getRects ( ) ) {
2022-07-16 12:44:45 +02:00
damageBox ( RECT . x1 , RECT . y1 , RECT . x2 - RECT . x1 , RECT . y2 - RECT . y1 ) ;
}
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : damageMirrorsWith ( PHLMONITOR pMonitor , const CRegion & pRegion ) {
2024-08-26 20:24:30 +02:00
for ( auto const & mirror : pMonitor - > 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
2024-12-07 18:51:18 +01:00
double scale = std : : min ( monitor - > vecTransformedSize . x / pMonitor - > vecTransformedSize . x , monitor - > vecTransformedSize . y / pMonitor - > vecTransformedSize . y ) ;
CBox monbox = { 0 , 0 , pMonitor - > vecTransformedSize . x * scale , pMonitor - > vecTransformedSize . y * scale } ;
2024-04-24 17:29:41 +02:00
monbox . x = ( monitor - > vecTransformedSize . x - monbox . w ) / 2 ;
monbox . y = ( monitor - > vecTransformedSize . y - monbox . h ) / 2 ;
2024-07-21 13:09:54 +02:00
transformed . scale ( scale ) ;
2024-12-07 18:51:18 +01:00
transformed . transform ( wlTransformToHyprutils ( pMonitor - > transform ) , pMonitor - > vecPixelSize . x * scale , pMonitor - > vecPixelSize . y * scale ) ;
2024-04-24 17:29:41 +02:00
transformed . translate ( Vector2D ( monbox . x , monbox . y ) ) ;
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
}
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderDragIcon ( PHLMONITOR pMonitor , timespec * 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 ) {
2023-09-29 17:51:07 +01:00
m_bCursorHasSurface = surf ;
2023-12-18 16:06:06 +00:00
m_sLastCursorData . name = " " ;
m_sLastCursorData . surf = surf ;
m_sLastCursorData . hotspotX = hotspotX ;
m_sLastCursorData . hotspotY = hotspotY ;
2023-10-29 18:09:05 +00:00
2024-02-21 13:48:48 +00:00
if ( m_bCursorHidden & & ! force )
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 ) {
2023-09-29 17:51:07 +01:00
m_bCursorHasSurface = true ;
2024-02-21 13:48:48 +00:00
if ( name = = m_sLastCursorData . name & & ! force )
2023-10-29 18:09:05 +00:00
return ;
m_sLastCursorData . name = name ;
2023-10-30 00:18:40 +00:00
m_sLastCursorData . surf . reset ( ) ;
2023-10-29 18:09:05 +00:00
2024-02-21 13:48:48 +00:00
if ( m_bCursorHidden & & ! force )
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 ( ) {
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 )
m_sCursorHiddenConditions . hiddenOnTimeout = false ;
if ( * PHIDEONTOUCH = = 0 )
m_sCursorHiddenConditions . hiddenOnTouch = false ;
if ( * PHIDEONKEY = = 0 )
m_sCursorHiddenConditions . hiddenOnKeyboard = false ;
2023-01-17 11:47:39 +01:00
2024-03-28 02:04:30 +00:00
if ( * PCURSORTIMEOUT > 0 )
m_sCursorHiddenConditions . hiddenOnTimeout = * PCURSORTIMEOUT < g_pInputManager - > m_tmrLastCursorMovement . getSeconds ( ) ;
2022-06-24 23:27:02 +02:00
2024-03-28 02:04:30 +00:00
const bool HIDE = m_sCursorHiddenConditions . hiddenOnTimeout | | m_sCursorHiddenConditions . hiddenOnTouch | | m_sCursorHiddenConditions . hiddenOnKeyboard ;
2022-06-24 23:27:02 +02:00
2024-03-28 02:04:30 +00:00
if ( HIDE = = m_bCursorHidden )
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
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
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) " ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
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 ) {
if ( hide = = m_bCursorHidden )
return ;
m_bCursorHidden = hide ;
if ( hide ) {
2024-05-05 22:18:10 +01:00
g_pPointerManager - > resetCursorImage ( ) ;
2023-12-20 21:40:44 +01:00
return ;
}
if ( m_sLastCursorData . surf . has_value ( ) )
setCursorSurface ( m_sLastCursorData . surf . value ( ) , m_sLastCursorData . hotspotX , m_sLastCursorData . hotspotY , true ) ;
else if ( ! m_sLastCursorData . name . empty ( ) )
setCursorFromName ( m_sLastCursorData . name , true ) ;
else
setCursorFromName ( " left_ptr " , true ) ;
}
2022-06-26 13:43:32 +02:00
bool CHyprRenderer : : shouldRenderCursor ( ) {
2023-12-29 00:04:01 +01:00
return ! m_bCursorHidden & & m_bCursorHasSurface ;
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 ) {
2023-03-24 19:23:16 +00:00
const auto POVERLAY = & g_pDebugOverlay - > m_mMonitorOverlays [ pMonitor ] ;
float avgRenderTime = 0 ;
float maxRenderTime = 0 ;
float minRenderTime = 9999 ;
2024-08-26 17:25:39 +02:00
for ( auto const & rt : POVERLAY - > m_dLastRenderTimes ) {
2023-03-24 19:23:16 +00:00
if ( rt > maxRenderTime )
maxRenderTime = rt ;
if ( rt < minRenderTime )
minRenderTime = rt ;
avgRenderTime + = rt ;
}
avgRenderTime / = POVERLAY - > m_dLastRenderTimes . size ( ) = = 0 ? 1 : POVERLAY - > m_dLastRenderTimes . size ( ) ;
return std : : make_tuple < > ( avgRenderTime , maxRenderTime , minRenderTime ) ;
}
2023-04-04 14:49:58 +01:00
static int handleCrashLoop ( void * data ) {
2024-12-03 18:58:24 +00:00
g_pHyprNotificationOverlay - > addNotification ( " Hyprland will crash in " + std : : to_string ( 10 - ( int ) ( g_pHyprRenderer - > m_fCrashingDistort * 2.f ) ) + " s. " , CHyprColor ( 0 ) , 5000 ,
2023-04-04 14:49:58 +01:00
ICON_INFO ) ;
g_pHyprRenderer - > m_fCrashingDistort + = 0.5f ;
if ( g_pHyprRenderer - > m_fCrashingDistort > = 5.5f )
2023-08-31 20:52:02 +00:00
raise ( SIGABRT ) ;
2023-04-04 14:49:58 +01:00
wl_event_source_timer_update ( g_pHyprRenderer - > m_pCrashingLoop , 1000 ) ;
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
m_pCrashingLoop = wl_event_loop_add_timer ( g_pCompositor - > m_sWLEventLoop , handleCrashLoop , nullptr ) ;
wl_event_source_timer_update ( m_pCrashingLoop , 1000 ) ;
m_bCrashingInProgress = true ;
m_fCrashingDistort = 0.5 ;
2023-04-04 22:04:32 +01:00
g_pHyprOpenGL - > m_tGlobalTimer . reset ( ) ;
2024-03-03 18:39:20 +00:00
static auto PDT = ( 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-10-19 23:03:29 +01:00
void CHyprRenderer : : recheckSolitaryForMonitor ( PHLMONITOR pMonitor ) {
2024-04-27 12:43:12 +01:00
pMonitor - > solitaryClient . reset ( ) ; // reset it, if we find one it will be set.
2023-09-28 21:48:33 +01:00
2024-05-06 02:24:11 +01:00
if ( g_pHyprNotificationOverlay - > hasAny ( ) | | g_pSessionLockManager - > isSessionLocked ( ) )
2024-02-14 11:09:18 +00:00
return ;
2024-04-02 20:32:39 +01:00
const auto PWORKSPACE = pMonitor - > activeWorkspace ;
2023-09-28 21:48:33 +01:00
2025-01-07 17:55:14 +00:00
if ( ! PWORKSPACE | | ! PWORKSPACE - > m_bHasFullscreenWindow | | PROTO : : data - > dndActive ( ) | | pMonitor - > activeSpecialWorkspace | | PWORKSPACE - > m_fAlpha - > value ( ) ! = 1.f | |
PWORKSPACE - > m_vRenderOffset - > value ( ) ! = Vector2D { } )
2023-09-28 21:48:33 +01:00
return ;
2024-11-22 16:01:02 +00:00
const auto PCANDIDATE = PWORKSPACE - > getFullscreenWindow ( ) ;
2023-09-28 21:48:33 +01:00
if ( ! PCANDIDATE )
return ; // ????
if ( ! PCANDIDATE - > opaque ( ) )
return ;
2025-01-07 17:55:14 +00:00
if ( PCANDIDATE - > m_vRealSize - > value ( ) ! = pMonitor - > vecSize | | PCANDIDATE - > m_vRealPosition - > value ( ) ! = pMonitor - > vecPosition | | PCANDIDATE - > m_vRealPosition - > isBeingAnimated ( ) | |
PCANDIDATE - > m_vRealSize - > isBeingAnimated ( ) )
2023-09-28 21:48:33 +01:00
return ;
if ( ! pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] . empty ( ) )
return ;
2024-08-26 17:25:39 +02:00
for ( auto const & topls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
2025-01-07 17:55:14 +00:00
if ( topls - > alpha - > value ( ) ! = 0.f )
2023-09-28 21:48:33 +01:00
return ;
}
2024-08-26 17:25:39 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-27 12:43:12 +01:00
if ( w = = PCANDIDATE | | ( ! w - > m_bIsMapped & & ! w - > m_bFadingOut ) | | w - > isHidden ( ) )
2024-03-14 18:25:28 +00:00
continue ;
2024-04-02 20:32:39 +01:00
if ( w - > m_pWorkspace = = PCANDIDATE - > m_pWorkspace & & w - > m_bIsFloating & & w - > m_bCreatedOverFullscreen & & w - > visibleOnMonitor ( pMonitor ) )
2023-10-04 09:44:03 +01:00
return ;
}
2024-04-02 20:32:39 +01:00
if ( pMonitor - > activeSpecialWorkspace )
2023-10-04 09:44:03 +01:00
return ;
2023-09-28 21:48:33 +01:00
// check if it did not open any subsurfaces or shit
int surfaceCount = 0 ;
2024-12-22 17:12:09 +01:00
if ( PCANDIDATE - > m_bIsX11 )
2023-09-28 21:48:33 +01:00
surfaceCount = 1 ;
2024-12-22 17:12:09 +01:00
else
2024-05-10 23:28:33 +01:00
surfaceCount = PCANDIDATE - > popupsCount ( ) + PCANDIDATE - > surfacesCount ( ) ;
2023-09-28 21:48:33 +01:00
2023-10-02 14:02:15 +01:00
if ( surfaceCount > 1 )
return ;
2023-09-28 21:48:33 +01:00
// found one!
pMonitor - > solitaryClient = PCANDIDATE ;
}
2023-11-24 10:54:21 +00:00
2024-07-21 13:09:54 +02:00
SP < CRenderbuffer > CHyprRenderer : : getOrCreateRenderbuffer ( SP < Aquamarine : : IBuffer > buffer , uint32_t fmt ) {
auto it = std : : find_if ( m_vRenderbuffers . begin ( ) , m_vRenderbuffers . end ( ) , [ & ] ( const auto & other ) { return other - > m_pHLBuffer = = buffer ; } ) ;
2023-11-24 10:54:21 +00:00
if ( it ! = m_vRenderbuffers . 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
2024-07-21 13:09:54 +02:00
m_vRenderbuffers . emplace_back ( buf ) ;
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 ;
2024-07-21 13:09:54 +02:00
if ( eglGetCurrentContext ( ) ! = g_pHyprOpenGL - > m_pEglContext )
eglMakeCurrent ( g_pHyprOpenGL - > m_pEglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , g_pHyprOpenGL - > m_pEglContext ) ;
2023-11-30 01:18:55 +00:00
}
void CHyprRenderer : : unsetEGL ( ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pHyprOpenGL )
return ;
eglMakeCurrent ( g_pHyprOpenGL - > m_pEglDisplay , 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
2024-12-22 17:12:09 +01:00
m_sRenderPass . clear ( ) ;
2023-11-24 10:54:21 +00:00
m_eRenderMode = mode ;
g_pHyprOpenGL - > m_RenderData . pMonitor = pMonitor ; // has to be set cuz allocs
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 ;
}
2024-11-17 15:58:18 +00:00
/* This is a constant expression, as we always use double-buffering in our swapchain
2024-07-21 13:09:54 +02:00
TODO : Rewrite the CDamageRing to take advantage of that maybe ? It ' s made to support longer swapchains atm because we used to do wlroots */
static constexpr const int HL_BUFFER_AGE = 2 ;
2024-06-19 18:25:20 +02:00
2023-11-30 01:18:55 +00:00
if ( ! buffer ) {
2024-07-21 13:09:54 +02:00
m_pCurrentBuffer = pMonitor - > output - > swapchain - > next ( nullptr ) ;
if ( ! m_pCurrentBuffer ) {
2024-02-23 00:02:48 +00:00
Debug : : log ( ERR , " Failed to acquire swapchain buffer for {} " , pMonitor - > szName ) ;
2023-11-24 10:54:21 +00:00
return false ;
2024-02-22 23:50:56 +00:00
}
} else
2024-07-21 13:09:54 +02:00
m_pCurrentBuffer = buffer ;
2023-11-24 10:54:21 +00:00
try {
2024-07-21 13:09:54 +02:00
m_pCurrentRenderbuffer = getOrCreateRenderbuffer ( m_pCurrentBuffer , pMonitor - > output - > state - > state ( ) . drmFormat ) ;
2023-11-24 10:54:21 +00:00
} catch ( std : : exception & e ) {
2024-02-23 00:02:48 +00:00
Debug : : log ( ERR , " getOrCreateRenderbuffer failed for {} " , pMonitor - > szName ) ;
2024-07-21 13:09:54 +02:00
return false ;
}
if ( ! m_pCurrentRenderbuffer ) {
Debug : : log ( ERR , " failed to start a render pass for output {}, no RBO could be obtained " , pMonitor - > szName ) ;
2023-11-24 10:54:21 +00:00
return false ;
}
2024-06-19 18:25:20 +02:00
if ( mode = = RENDER_MODE_NORMAL ) {
2024-07-21 13:09:54 +02:00
damage = pMonitor - > damage . getBufferDamage ( HL_BUFFER_AGE ) ;
2024-06-19 18:25:20 +02:00
pMonitor - > damage . rotate ( ) ;
}
2024-02-19 18:17:32 +00:00
2023-11-24 10:54:21 +00:00
m_pCurrentRenderbuffer - > bind ( ) ;
2024-05-05 22:18:10 +01:00
if ( simple )
g_pHyprOpenGL - > beginSimple ( pMonitor , damage , m_pCurrentRenderbuffer ) ;
else
g_pHyprOpenGL - > begin ( pMonitor , damage ) ;
2023-11-24 10:54:21 +00:00
return true ;
}
void CHyprRenderer : : endRender ( ) {
2024-03-03 18:39:20 +00:00
const auto PMONITOR = g_pHyprOpenGL - > m_RenderData . pMonitor ;
static auto PNVIDIAANTIFLICKER = CConfigValue < Hyprlang : : INT > ( " opengl:nvidia_anti_flicker " ) ;
2024-07-21 13:09:54 +02:00
PMONITOR - > commitSeq + + ;
2023-11-24 10:54:21 +00:00
2024-12-22 17:12:09 +01:00
g_pHyprOpenGL - > m_RenderData . damage = m_sRenderPass . render ( g_pHyprOpenGL - > m_RenderData . damage ) ;
2024-08-06 14:52:19 +01:00
auto cleanup = CScopeGuard ( [ this ] ( ) {
if ( m_pCurrentRenderbuffer )
m_pCurrentRenderbuffer - > unbind ( ) ;
m_pCurrentRenderbuffer = nullptr ;
m_pCurrentBuffer = nullptr ;
} ) ;
2023-11-30 10:14:35 +00:00
if ( m_eRenderMode ! = RENDER_MODE_TO_BUFFER_READ_ONLY )
g_pHyprOpenGL - > end ( ) ;
else {
2024-10-19 23:03:29 +01:00
g_pHyprOpenGL - > m_RenderData . pMonitor . reset ( ) ;
2023-11-30 10:14:35 +00:00
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = 1.f ;
g_pHyprOpenGL - > m_RenderData . mouseZoomUseMouse = true ;
}
2023-11-24 10:54:21 +00:00
2023-11-30 10:14:35 +00:00
if ( m_eRenderMode = = RENDER_MODE_FULL_FAKE )
2023-11-24 10:54:21 +00:00
return ;
2023-11-30 01:18:55 +00:00
if ( m_eRenderMode = = RENDER_MODE_NORMAL ) {
2024-07-21 13:09:54 +02:00
PMONITOR - > output - > state - > setBuffer ( m_pCurrentBuffer ) ;
2024-08-06 14:52:19 +01:00
auto explicitOptions = getExplicitSyncSettings ( ) ;
if ( PMONITOR - > inTimeline & & explicitOptions . explicitEnabled & & explicitOptions . explicitKMSEnabled ) {
2024-07-21 13:09:54 +02:00
auto sync = g_pHyprOpenGL - > createEGLSync ( - 1 ) ;
if ( ! sync ) {
Debug : : log ( ERR , " renderer: couldn't create an EGLSync for out in endRender " ) ;
return ;
}
2024-08-06 14:52:19 +01:00
bool ok = PMONITOR - > inTimeline - > importFromSyncFileFD ( PMONITOR - > commitSeq , sync - > fd ( ) ) ;
if ( ! ok ) {
Debug : : log ( ERR , " renderer: couldn't import from sync file fd in endRender " ) ;
2024-07-21 13:09:54 +02:00
return ;
}
2023-11-24 10:54:21 +00:00
2024-08-06 14:52:19 +01:00
auto fd = PMONITOR - > inTimeline - > exportAsSyncFileFD ( PMONITOR - > commitSeq ) ;
if ( fd < = 0 ) {
Debug : : log ( ERR , " renderer: couldn't export from sync timeline in endRender " ) ;
2024-07-21 13:09:54 +02:00
return ;
}
2024-08-06 14:52:19 +01:00
PMONITOR - > output - > state - > setExplicitInFence ( fd ) ;
2024-07-21 13:09:54 +02:00
} else {
if ( isNvidia ( ) & & * PNVIDIAANTIFLICKER )
glFinish ( ) ;
else
glFlush ( ) ;
}
}
2023-11-24 10:54:21 +00:00
}
void CHyprRenderer : : onRenderbufferDestroy ( CRenderbuffer * rb ) {
std : : erase_if ( m_vRenderbuffers , [ & ] ( const auto & rbo ) { return rbo . get ( ) = = rb ; } ) ;
}
2024-07-21 13:09:54 +02:00
SP < CRenderbuffer > CHyprRenderer : : getCurrentRBO ( ) {
2023-11-24 10:54:21 +00:00
return m_pCurrentRenderbuffer ;
2023-11-25 17:45:08 +00:00
}
bool CHyprRenderer : : isNvidia ( ) {
return m_bNvidia ;
2023-12-18 16:06:06 +00:00
}
2024-08-06 14:52:19 +01:00
SExplicitSyncSettings CHyprRenderer : : getExplicitSyncSettings ( ) {
static auto PENABLEEXPLICIT = CConfigValue < Hyprlang : : INT > ( " render:explicit_sync " ) ;
static auto PENABLEEXPLICITKMS = CConfigValue < Hyprlang : : INT > ( " render:explicit_sync_kms " ) ;
SExplicitSyncSettings settings ;
settings . explicitEnabled = * PENABLEEXPLICIT ;
settings . explicitKMSEnabled = * PENABLEEXPLICITKMS ;
if ( * PENABLEEXPLICIT = = 2 /* auto */ )
settings . explicitEnabled = true ;
if ( * PENABLEEXPLICITKMS = = 2 /* auto */ ) {
if ( ! m_bNvidia )
settings . explicitKMSEnabled = true ;
else {
// check nvidia version. Explicit KMS is supported in >=560
// in the case of an error, driverMajor will stay 0 and explicit KMS will be disabled
2024-08-07 18:54:45 +02:00
static int driverMajor = 0 ;
2024-08-06 14:52:19 +01:00
static bool once = true ;
if ( once ) {
once = false ;
Debug : : log ( LOG , " Renderer: checking for explicit KMS support for nvidia " ) ;
if ( std : : filesystem : : exists ( " /sys/module/nvidia_drm/version " ) ) {
Debug : : log ( LOG , " Renderer: Nvidia version file exists " ) ;
std : : ifstream ifs ( " /sys/module/nvidia_drm/version " ) ;
if ( ifs . good ( ) ) {
try {
std : : string driverInfo ( ( std : : istreambuf_iterator < char > ( ifs ) ) , ( std : : istreambuf_iterator < char > ( ) ) ) ;
Debug : : log ( LOG , " Renderer: Read nvidia version {} " , driverInfo ) ;
CVarList ver ( driverInfo , 0 , ' . ' , true ) ;
driverMajor = std : : stoi ( ver [ 0 ] ) ;
Debug : : log ( LOG , " Renderer: Parsed nvidia major version: {} " , driverMajor ) ;
} catch ( std : : exception & e ) { settings . explicitKMSEnabled = false ; }
ifs . close ( ) ;
}
}
}
settings . explicitKMSEnabled = driverMajor > = 560 ;
}
}
return settings ;
}
2024-08-30 17:37:52 +02:00
void CHyprRenderer : : addWindowToRenderUnfocused ( PHLWINDOW window ) {
static auto PFPS = CConfigValue < Hyprlang : : INT > ( " misc:render_unfocused_fps " ) ;
if ( std : : find ( m_vRenderUnfocused . begin ( ) , m_vRenderUnfocused . end ( ) , window ) ! = m_vRenderUnfocused . end ( ) )
return ;
m_vRenderUnfocused . emplace_back ( window ) ;
if ( ! m_tRenderUnfocusedTimer - > armed ( ) )
m_tRenderUnfocusedTimer - > updateTimeout ( std : : chrono : : milliseconds ( 1000 / * PFPS ) ) ;
}
2024-12-22 17:12:09 +01:00
void CHyprRenderer : : makeRawWindowSnapshot ( PHLWINDOW pWindow , CFramebuffer * pFramebuffer ) {
// we trust the window is valid.
const auto PMONITOR = pWindow - > m_pMonitor . lock ( ) ;
if ( ! PMONITOR | | ! PMONITOR - > output | | PMONITOR - > vecPixelSize . x < = 0 | | PMONITOR - > vecPixelSize . y < = 0 )
return ;
// we need to "damage" the entire monitor
// so that we render the entire window
// this is temporary, doesnt mess with the actual damage
CRegion fakeDamage { 0 , 0 , ( int ) PMONITOR - > vecTransformedSize . x , ( int ) PMONITOR - > vecTransformedSize . y } ;
makeEGLCurrent ( ) ;
pFramebuffer - > alloc ( PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y , PMONITOR - > output - > state - > state ( ) . drmFormat ) ;
pFramebuffer - > addStencil ( g_pHyprOpenGL - > m_RenderData . pCurrentMonData - > stencilTex ) ;
beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , pFramebuffer ) ;
g_pHyprOpenGL - > clear ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
// this is a hack but it works :P
// we need to disable blur or else we will get a black background, as the shader
// will try to copy the bg to apply blur.
// this isn't entirely correct, but like, oh well.
// small todo: maybe make this correct? :P
static auto * const PBLUR = ( Hyprlang : : INT * const * ) ( g_pConfigManager - > getConfigValuePtr ( " decoration:blur:enabled " ) ) ;
const auto BLURVAL = * * PBLUR ;
* * PBLUR = 0 ;
// TODO: how can we make this the size of the window? setting it to window's size makes the entire screen render with the wrong res forever more. odd.
glViewport ( 0 , 0 , PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y ) ;
g_pHyprOpenGL - > m_RenderData . currentFB = pFramebuffer ;
g_pHyprOpenGL - > clear ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
renderWindow ( pWindow , PMONITOR , & now , false , RENDER_PASS_ALL , true ) ;
* * PBLUR = BLURVAL ;
endRender ( ) ;
}
void CHyprRenderer : : makeWindowSnapshot ( PHLWINDOW pWindow ) {
// we trust the window is valid.
const auto PMONITOR = pWindow - > m_pMonitor . lock ( ) ;
if ( ! PMONITOR | | ! PMONITOR - > output | | PMONITOR - > vecPixelSize . x < = 0 | | PMONITOR - > vecPixelSize . y < = 0 )
return ;
if ( ! shouldRenderWindow ( pWindow ) )
return ; // ignore, window is not being rendered
// we need to "damage" the entire monitor
// so that we render the entire window
// this is temporary, doesnt mess with the actual damage
CRegion fakeDamage { 0 , 0 , ( int ) PMONITOR - > vecTransformedSize . x , ( int ) PMONITOR - > vecTransformedSize . y } ;
PHLWINDOWREF ref { pWindow } ;
makeEGLCurrent ( ) ;
const auto PFRAMEBUFFER = & g_pHyprOpenGL - > m_mWindowFramebuffers [ ref ] ;
PFRAMEBUFFER - > alloc ( PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y , PMONITOR - > output - > state - > state ( ) . drmFormat ) ;
beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , PFRAMEBUFFER ) ;
m_bRenderingSnapshot = true ;
g_pHyprOpenGL - > clear ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
// this is a hack but it works :P
// we need to disable blur or else we will get a black background, as the shader
// will try to copy the bg to apply blur.
// this isn't entirely correct, but like, oh well.
// small todo: maybe make this correct? :P
static auto * const PBLUR = ( Hyprlang : : INT * const * ) ( g_pConfigManager - > getConfigValuePtr ( " decoration:blur:enabled " ) ) ;
const auto BLURVAL = * * PBLUR ;
* * PBLUR = 0 ;
g_pHyprOpenGL - > clear ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
renderWindow ( pWindow , PMONITOR , & now , ! pWindow - > m_bX11DoesntWantBorders , RENDER_PASS_ALL ) ;
* * PBLUR = BLURVAL ;
endRender ( ) ;
m_bRenderingSnapshot = false ;
}
void CHyprRenderer : : makeLayerSnapshot ( PHLLS pLayer ) {
// we trust the window is valid.
const auto PMONITOR = pLayer - > monitor . lock ( ) ;
if ( ! PMONITOR | | ! PMONITOR - > output | | PMONITOR - > vecPixelSize . x < = 0 | | PMONITOR - > vecPixelSize . y < = 0 )
return ;
// we need to "damage" the entire monitor
// so that we render the entire window
// this is temporary, doesnt mess with the actual damage
CRegion fakeDamage { 0 , 0 , ( int ) PMONITOR - > vecTransformedSize . x , ( int ) PMONITOR - > vecTransformedSize . y } ;
makeEGLCurrent ( ) ;
const auto PFRAMEBUFFER = & g_pHyprOpenGL - > m_mLayerFramebuffers [ pLayer ] ;
PFRAMEBUFFER - > alloc ( PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y , PMONITOR - > output - > state - > state ( ) . drmFormat ) ;
beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , PFRAMEBUFFER ) ;
m_bRenderingSnapshot = true ;
g_pHyprOpenGL - > clear ( CHyprColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
const auto BLURLSSTATUS = pLayer - > forceBlur ;
pLayer - > forceBlur = false ;
// draw the layer
renderLayer ( pLayer , PMONITOR , & now ) ;
pLayer - > forceBlur = BLURLSSTATUS ;
endRender ( ) ;
m_bRenderingSnapshot = false ;
}
void CHyprRenderer : : renderSnapshot ( PHLWINDOW pWindow ) {
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
PHLWINDOWREF ref { pWindow } ;
if ( ! g_pHyprOpenGL - > m_mWindowFramebuffers . contains ( ref ) )
return ;
const auto FBDATA = & g_pHyprOpenGL - > m_mWindowFramebuffers . at ( ref ) ;
if ( ! FBDATA - > getTexture ( ) )
return ;
const auto PMONITOR = pWindow - > m_pMonitor . lock ( ) ;
CBox windowBox ;
// some mafs to figure out the correct box
// the originalClosedPos is relative to the monitor's pos
2025-01-07 17:55:14 +00:00
Vector2D scaleXY = Vector2D ( ( PMONITOR - > scale * pWindow - > m_vRealSize - > value ( ) . x / ( pWindow - > m_vOriginalClosedSize . x * PMONITOR - > scale ) ) ,
( PMONITOR - > scale * pWindow - > m_vRealSize - > value ( ) . y / ( pWindow - > m_vOriginalClosedSize . y * PMONITOR - > scale ) ) ) ;
2024-12-22 17:12:09 +01:00
windowBox . width = PMONITOR - > vecTransformedSize . x * scaleXY . x ;
windowBox . height = PMONITOR - > vecTransformedSize . y * scaleXY . y ;
2025-01-07 17:55:14 +00:00
windowBox . x = ( ( pWindow - > m_vRealPosition - > value ( ) . x - PMONITOR - > vecPosition . x ) * PMONITOR - > scale ) - ( ( pWindow - > m_vOriginalClosedPos . x * PMONITOR - > scale ) * scaleXY . x ) ;
windowBox . y = ( ( pWindow - > m_vRealPosition - > value ( ) . y - PMONITOR - > vecPosition . y ) * PMONITOR - > scale ) - ( ( pWindow - > m_vOriginalClosedPos . y * PMONITOR - > scale ) * scaleXY . y ) ;
2024-12-22 17:12:09 +01:00
CRegion fakeDamage { 0 , 0 , PMONITOR - > vecTransformedSize . x , PMONITOR - > vecTransformedSize . y } ;
if ( * PDIMAROUND & & pWindow - > m_sWindowData . dimAround . valueOrDefault ( ) ) {
CRectPassElement : : SRectData data ;
data . box = { 0 , 0 , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecPixelSize . x , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecPixelSize . y } ;
2025-01-07 17:55:14 +00:00
data . color = CHyprColor ( 0 , 0 , 0 , * PDIMAROUND * pWindow - > m_fAlpha - > value ( ) ) ;
2024-12-22 17:12:09 +01:00
m_sRenderPass . add ( makeShared < CRectPassElement > ( data ) ) ;
damageMonitor ( PMONITOR ) ;
}
CTexPassElement : : SRenderData data ;
data . flipEndFrame = true ;
data . tex = FBDATA - > getTexture ( ) ;
data . box = windowBox ;
2025-01-07 17:55:14 +00:00
data . a = pWindow - > m_fAlpha - > value ( ) ;
2024-12-22 17:12:09 +01:00
data . damage = fakeDamage ;
m_sRenderPass . add ( makeShared < CTexPassElement > ( data ) ) ;
}
void CHyprRenderer : : renderSnapshot ( PHLLS pLayer ) {
if ( ! g_pHyprOpenGL - > m_mLayerFramebuffers . contains ( pLayer ) )
return ;
const auto FBDATA = & g_pHyprOpenGL - > m_mLayerFramebuffers . at ( pLayer ) ;
if ( ! FBDATA - > getTexture ( ) )
return ;
const auto PMONITOR = pLayer - > monitor . lock ( ) ;
CBox layerBox ;
// some mafs to figure out the correct box
// the originalClosedPos is relative to the monitor's pos
2025-01-07 17:55:14 +00:00
Vector2D scaleXY = Vector2D ( ( PMONITOR - > scale * pLayer - > realSize - > value ( ) . x / ( pLayer - > geometry . w * PMONITOR - > scale ) ) ,
( PMONITOR - > scale * pLayer - > realSize - > value ( ) . y / ( pLayer - > geometry . h * PMONITOR - > scale ) ) ) ;
2024-12-22 17:12:09 +01:00
layerBox . width = PMONITOR - > vecTransformedSize . x * scaleXY . x ;
layerBox . height = PMONITOR - > vecTransformedSize . y * scaleXY . y ;
2025-01-07 17:55:14 +00:00
layerBox . x = ( ( pLayer - > realPosition - > value ( ) . x - PMONITOR - > vecPosition . x ) * PMONITOR - > scale ) - ( ( ( pLayer - > geometry . x - PMONITOR - > vecPosition . x ) * PMONITOR - > scale ) * scaleXY . x ) ;
layerBox . y = ( ( pLayer - > realPosition - > value ( ) . y - PMONITOR - > vecPosition . y ) * PMONITOR - > scale ) - ( ( ( pLayer - > geometry . y - PMONITOR - > vecPosition . y ) * PMONITOR - > scale ) * scaleXY . y ) ;
2024-12-22 17:12:09 +01:00
CRegion fakeDamage { 0 , 0 , PMONITOR - > vecTransformedSize . x , PMONITOR - > vecTransformedSize . y } ;
CTexPassElement : : SRenderData data ;
data . flipEndFrame = true ;
data . tex = FBDATA - > getTexture ( ) ;
data . box = layerBox ;
2025-01-07 17:55:14 +00:00
data . a = pLayer - > alpha - > value ( ) ;
2024-12-22 17:12:09 +01:00
data . damage = fakeDamage ;
m_sRenderPass . add ( makeShared < CTexPassElement > ( data ) ) ;
}