2022-03-17 20:22:29 +01:00
# include "Renderer.hpp"
# include "../Compositor.hpp"
2023-04-27 14:55:13 +02:00
# include "linux-dmabuf-unstable-v1-protocol.h"
2023-07-19 20:09:49 +02:00
# include "../helpers/Region.hpp"
2023-11-12 14:14:05 +01:00
# include <algorithm>
2022-03-17 20:22:29 +01:00
2023-11-25 18:45:08 +01:00
extern " C " {
# include <xf86drm.h>
}
2023-09-28 22:48:33 +02:00
CHyprRenderer : : CHyprRenderer ( ) {
2023-11-25 18:45:08 +01:00
if ( g_pCompositor - > m_sWLRSession ) {
wlr_device * dev ;
2023-11-25 18:56:38 +01:00
wl_list_for_each ( dev , & g_pCompositor - > m_sWLRSession - > devices , link ) {
2023-11-25 18:45:08 +01:00
const auto DRMV = drmGetVersion ( dev - > fd ) ;
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 18:56:38 +01:00
std : : string { DRMV - > date , DRMV - > date_len } , std : : string { DRMV - > desc , DRMV - > desc_len } ) ;
2023-11-25 18:45:08 +01:00
drmFreeVersion ( DRMV ) ;
}
} else {
Debug : : log ( LOG , " m_sWLRSession is null, omitting full DRM node checks " ) ;
const auto DRMV = drmGetVersion ( g_pCompositor - > m_iDRMFD ) ;
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 , " Primary DRM driver information: {} v{}.{}.{} from {} description {} " , name , DRMV - > version_major , DRMV - > version_minor , DRMV - > version_patchlevel ,
2023-11-25 18:56:38 +01:00
std : : string { DRMV - > date , DRMV - > date_len } , std : : string { DRMV - > desc , DRMV - > desc_len } ) ;
2023-11-25 18:45:08 +01:00
drmFreeVersion ( DRMV ) ;
}
if ( m_bNvidia )
Debug : : log ( WARN , " NVIDIA detected, please remember to follow nvidia instructions on the wiki " ) ;
2023-09-28 22:48:33 +02:00
}
2023-12-19 12:55:56 +01:00
static void renderSurface ( struct wlr_surface * surface , int x , int y , void * data ) {
2024-02-18 16:00:34 +01:00
static auto * const PBLURPOPUPS = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:blur:popups " ) ;
static auto * const PBLURPOPUPSIGNOREALPHA = ( Hyprlang : : FLOAT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:blur:popups_ignorealpha " ) ;
2023-12-25 18:04:00 +01:00
2023-12-31 13:11:20 +01:00
const auto TEXTURE = wlr_surface_get_texture ( surface ) ;
const auto RDATA = ( SRenderData * ) data ;
const auto INTERACTIVERESIZEINPROGRESS = RDATA - > pWindow & & g_pInputManager - > currentlyDraggedWindow = = RDATA - > pWindow & & g_pInputManager - > dragMode = = MBIND_RESIZE ;
2022-03-17 20:22:29 +01:00
if ( ! TEXTURE )
return ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderSurface " ) ;
2022-03-17 20:22:29 +01:00
double outputX = 0 , outputY = 0 ;
2023-01-20 19:44:30 +01:00
wlr_output_layout_output_coords ( g_pCompositor - > m_sWLROutputLayout , RDATA - > pMonitor - > output , & outputX , & outputY ) ;
2022-03-17 20:22:29 +01:00
2023-11-04 18:03:05 +01:00
CBox windowBox ;
2023-10-20 21:15:41 +02:00
if ( RDATA - > surface & & surface = = RDATA - > surface ) {
2022-06-29 12:54:53 +02:00
windowBox = { ( int ) outputX + RDATA - > x + x , ( int ) outputY + RDATA - > y + y , RDATA - > w , RDATA - > h } ;
2023-10-20 21:15:41 +02:00
// however, if surface buffer w / h < box, we need to adjust them
auto * const PSURFACE = CWLSurface : : surfaceFromWlr ( surface ) ;
if ( PSURFACE & & ! PSURFACE - > m_bFillIgnoreSmall & & PSURFACE - > small ( ) /* guarantees m_pOwner */ ) {
2023-12-31 13:11:20 +01:00
const auto CORRECT = PSURFACE - > correctSmallVec ( ) ;
const auto SIZE = PSURFACE - > getViewporterCorrectedSize ( ) ;
2023-10-20 21:32:47 +02:00
if ( ! INTERACTIVERESIZEINPROGRESS ) {
windowBox . x + = CORRECT . x ;
windowBox . y + = CORRECT . y ;
2023-10-25 23:05:04 +02:00
windowBox . width = SIZE . x * ( PSURFACE - > m_pOwner - > m_vRealSize . vec ( ) . x / PSURFACE - > m_pOwner - > m_vReportedSize . x ) ;
windowBox . height = SIZE . y * ( PSURFACE - > m_pOwner - > m_vRealSize . vec ( ) . y / PSURFACE - > m_pOwner - > m_vReportedSize . y ) ;
2023-10-20 21:32:47 +02:00
} else {
2023-10-25 23:05:04 +02:00
windowBox . width = SIZE . x ;
windowBox . height = SIZE . y ;
2023-10-20 21:32:47 +02:00
}
2023-10-20 21:15:41 +02:00
}
} else { // here we clamp to 2, these might be some tiny specks
2022-09-26 21:10:24 +02:00
windowBox = { ( int ) outputX + RDATA - > x + x , ( int ) outputY + RDATA - > y + y , std : : max ( surface - > current . width , 2 ) , std : : max ( surface - > current . height , 2 ) } ;
2023-07-10 13:32:57 +02:00
if ( RDATA - > pWindow & & RDATA - > pWindow - > m_vRealSize . isBeingAnimated ( ) & & RDATA - > surface & & RDATA - > surface ! = surface & & RDATA - > squishOversized /* subsurface */ ) {
// adjust subsurfaces to the window
windowBox . width = ( windowBox . width / RDATA - > pWindow - > m_vReportedSize . x ) * RDATA - > pWindow - > m_vRealSize . vec ( ) . x ;
windowBox . height = ( windowBox . height / RDATA - > pWindow - > m_vReportedSize . y ) * RDATA - > pWindow - > m_vRealSize . vec ( ) . y ;
}
}
2022-09-25 20:07:48 +02:00
2022-07-11 23:38:10 +02:00
if ( RDATA - > squishOversized ) {
if ( x + windowBox . width > RDATA - > w )
windowBox . width = RDATA - > w - x ;
2022-07-15 19:07:06 +02:00
if ( y + windowBox . height > RDATA - > h )
2022-07-11 23:38:10 +02:00
windowBox . height = RDATA - > h - y ;
}
2022-08-28 10:14:43 +02:00
2023-10-21 15:20:06 +02:00
if ( windowBox . width < = 1 | | windowBox . height < = 1 )
return ; // invisible
2023-11-04 18:03:05 +01:00
windowBox . scale ( RDATA - > pMonitor - > scale ) ;
windowBox . round ( ) ;
2022-03-17 20:22:29 +01:00
2024-01-29 00:42:39 +01:00
const bool MISALIGNEDFSV1 = std : : floor ( RDATA - > pMonitor - > scale ) ! = RDATA - > pMonitor - > scale /* Fractional */ & & surface - > current . scale = = 1 /* fs protocol */ & &
windowBox . size ( ) ! = Vector2D { surface - > current . buffer_width , surface - > current . buffer_height } /* misaligned */ & &
DELTALESSTHAN ( windowBox . width , surface - > current . buffer_width , 3 ) & & DELTALESSTHAN ( windowBox . height , surface - > current . buffer_height , 3 ) /* off by one-or-two */ & &
( ! RDATA - > pWindow | | ( ! RDATA - > pWindow - > m_vRealSize . isBeingAnimated ( ) & & ! INTERACTIVERESIZEINPROGRESS ) ) /* not window or not animated/resizing */ ;
g_pHyprRenderer - > calculateUVForSurface ( RDATA - > pWindow , surface , RDATA - > surface = = surface , windowBox . size ( ) , MISALIGNEDFSV1 ) ;
2023-12-31 13:11:20 +01:00
// check for fractional scale surfaces misaligning the buffer size
// in those cases it's better to just force nearest neighbor
2024-01-29 00:42:39 +01:00
// as long as the window is not animated. During those it'd look weird.
// UV will fixup it as well
2023-12-31 13:11:20 +01:00
const auto NEARESTNEIGHBORSET = g_pHyprOpenGL - > m_RenderData . useNearestNeighbor ;
2024-01-29 00:42:39 +01:00
if ( MISALIGNEDFSV1 )
2023-12-31 13:11:20 +01:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = true ;
2023-07-19 20:06:19 +02:00
float rounding = RDATA - > rounding ;
2022-05-28 17:48:01 +02:00
2022-08-20 22:45:30 +02:00
rounding - = 1 ; // to fix a border issue
2023-09-23 01:06:48 +02:00
if ( RDATA - > dontRound )
rounding = 0 ;
2023-10-29 21:54:14 +01:00
const bool WINDOWOPAQUE = RDATA - > pWindow & & RDATA - > pWindow - > m_pWLSurface . wlr ( ) = = surface ? RDATA - > pWindow - > opaque ( ) : false ;
const bool CANDISABLEBLEND = RDATA - > alpha * RDATA - > fadeAlpha > = 1.f & & rounding = = 0 & & ( WINDOWOPAQUE | | surface - > opaque ) ;
2023-07-20 13:49:28 +02:00
if ( CANDISABLEBLEND )
g_pHyprOpenGL - > blend ( false ) ;
else
g_pHyprOpenGL - > blend ( true ) ;
2022-06-22 15:45:56 +02:00
if ( RDATA - > surface & & surface = = RDATA - > surface ) {
2023-02-03 13:43:43 +01:00
if ( wlr_xwayland_surface_try_from_wlr_surface ( surface ) & & ! wlr_xwayland_surface_try_from_wlr_surface ( surface ) - > has_alpha & & RDATA - > fadeAlpha * RDATA - > alpha = = 1.f ) {
2022-07-06 22:12:03 +02:00
g_pHyprOpenGL - > renderTexture ( TEXTURE , & windowBox , RDATA - > fadeAlpha * RDATA - > alpha , rounding , true ) ;
2022-07-27 13:30:55 +02:00
} else {
if ( RDATA - > blur )
2023-08-23 12:03:23 +02:00
g_pHyprOpenGL - > renderTextureWithBlur ( TEXTURE , & windowBox , RDATA - > fadeAlpha * RDATA - > alpha , surface , rounding , RDATA - > blockBlurOptimization , RDATA - > fadeAlpha ) ;
2022-07-27 13:30:55 +02:00
else
g_pHyprOpenGL - > renderTexture ( TEXTURE , & windowBox , RDATA - > fadeAlpha * RDATA - > alpha , rounding , true ) ;
}
2022-12-16 18:17:31 +01:00
} else {
2024-02-18 16:00:34 +01:00
if ( RDATA - > blur & & RDATA - > popup & & * * PBLURPOPUPS ) {
2023-12-28 22:28:58 +01:00
2024-02-18 16:00:34 +01:00
if ( * * PBLURPOPUPSIGNOREALPHA ! = 1.f ) {
2023-12-28 22:28:58 +01:00
g_pHyprOpenGL - > m_RenderData . discardMode | = DISCARD_ALPHA ;
2024-02-18 16:00:34 +01:00
g_pHyprOpenGL - > m_RenderData . discardOpacity = * * PBLURPOPUPSIGNOREALPHA ;
2023-12-28 22:28:58 +01:00
}
2023-12-25 18:04:00 +01:00
g_pHyprOpenGL - > renderTextureWithBlur ( TEXTURE , & windowBox , RDATA - > fadeAlpha * RDATA - > alpha , surface , rounding , true ) ;
2023-12-28 22:28:58 +01:00
g_pHyprOpenGL - > m_RenderData . discardMode & = ~ DISCARD_ALPHA ;
} else
2023-12-25 18:04:00 +01:00
g_pHyprOpenGL - > renderTexture ( TEXTURE , & windowBox , RDATA - > fadeAlpha * RDATA - > alpha , rounding , true ) ;
2022-07-04 15:58:12 +02:00
}
2022-03-17 20:22:29 +01:00
2022-12-05 20:11:02 +01:00
if ( ! g_pHyprRenderer - > m_bBlockSurfaceFeedback ) {
wlr_surface_send_frame_done ( surface , RDATA - > when ) ;
2024-01-01 16:47:54 +01:00
wlr_presentation_surface_textured_on_output ( surface , RDATA - > pMonitor - > output ) ;
2022-12-05 20:11:02 +01:00
}
2022-08-28 10:41:47 +02:00
2023-07-20 13:49:28 +02:00
g_pHyprOpenGL - > blend ( true ) ;
2023-12-31 13:11:20 +01:00
// reset props
2022-12-16 18:17:31 +01:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:41:47 +02:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
2023-12-31 13:11:20 +01:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = NEARESTNEIGHBORSET ;
2022-03-17 20:22:29 +01:00
}
2023-04-12 14:05:57 +02:00
bool CHyprRenderer : : shouldRenderWindow ( CWindow * pWindow , CMonitor * pMonitor , CWorkspace * pWorkspace ) {
2023-11-04 18:03:05 +01:00
CBox geometry = pWindow - > getFullWindowBoundingBox ( ) ;
2022-03-20 18:49:40 +01:00
2023-11-04 18:03:05 +01:00
if ( ! wlr_output_layout_intersects ( g_pCompositor - > m_sWLROutputLayout , pMonitor - > output , geometry . pWlr ( ) ) )
2022-03-20 18:49:40 +01:00
return false ;
2023-04-12 14:05:57 +02:00
if ( pWindow - > m_iWorkspaceID = = - 1 )
return false ;
2022-09-10 13:11:02 +02:00
if ( pWindow - > m_bPinned )
return true ;
2023-04-14 16:16:43 +02:00
const auto PWINDOWWORKSPACE = g_pCompositor - > getWorkspaceByID ( pWindow - > m_iWorkspaceID ) ;
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_iMonitorID = = pMonitor - > ID ) {
if ( PWINDOWWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) | | PWINDOWWORKSPACE - > m_fAlpha . isBeingAnimated ( ) | | PWINDOWWORKSPACE - > m_bForceRendering ) {
2022-08-18 12:42:21 +02:00
return true ;
} else {
2023-12-09 19:38:32 +01:00
if ( PWINDOWWORKSPACE - > m_bHasFullscreenWindow & & ! pWindow - > m_bIsFullscreen & & ! pWindow - > m_bIsFloating & & ! pWindow - > m_bCreatedOverFullscreen & &
pWindow - > m_fAlpha . fl ( ) = = 0 )
2022-08-18 12:42:21 +02:00
return false ;
}
2022-07-28 16:33:45 +02:00
}
2023-04-12 14:05:57 +02:00
if ( pWindow - > m_iWorkspaceID = = pWorkspace - > m_iID )
2022-03-20 18:49:40 +01:00
return true ;
2022-08-18 12:41:10 +02:00
// if not, check if it maybe is active on a different monitor.
2022-10-12 19:37:11 +02:00
if ( g_pCompositor - > isWorkspaceVisible ( pWindow - > m_iWorkspaceID ) & & pWindow - > m_bIsFloating /* tiled windows can't be multi-ws */ )
2022-08-18 12:41:10 +02:00
return ! pWindow - > m_bIsFullscreen ; // Do not draw fullscreen windows on other monitors
2022-03-20 18:49:40 +01:00
2022-12-11 17:53:59 +01:00
if ( pMonitor - > specialWorkspaceID = = pWindow - > m_iWorkspaceID )
2022-05-31 14:01:00 +02:00
return true ;
2022-03-20 18:49:40 +01:00
return false ;
}
2022-05-31 22:16:13 +02:00
bool CHyprRenderer : : shouldRenderWindow ( CWindow * pWindow ) {
if ( ! g_pCompositor - > windowValidMapped ( pWindow ) )
return false ;
const auto PWORKSPACE = g_pCompositor - > getWorkspaceByID ( pWindow - > m_iWorkspaceID ) ;
2023-04-12 14:05:57 +02:00
if ( pWindow - > m_iWorkspaceID = = - 1 )
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 ;
2022-05-31 22:16:13 +02:00
if ( g_pCompositor - > isWorkspaceVisible ( pWindow - > m_iWorkspaceID ) )
return true ;
2022-06-30 15:44:26 +02:00
for ( auto & m : g_pCompositor - > m_vMonitors ) {
if ( PWORKSPACE & & PWORKSPACE - > m_iMonitorID = = m - > ID & & ( PWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) | | PWORKSPACE - > m_fAlpha . isBeingAnimated ( ) ) )
2022-05-31 22:16:13 +02:00
return true ;
2022-11-27 23:42:22 +01:00
if ( m - > specialWorkspaceID & & g_pCompositor - > isWorkspaceSpecial ( pWindow - > m_iWorkspaceID ) )
2022-05-31 22:16:13 +02:00
return true ;
}
return false ;
}
2023-09-04 15:07:56 +02:00
void CHyprRenderer : : renderWorkspaceWindowsFullscreen ( CMonitor * pMonitor , CWorkspace * pWorkspace , timespec * time ) {
2022-03-30 20:16:23 +02:00
CWindow * pWorkspaceWindow = nullptr ;
2023-04-18 00:45:03 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE_WINDOWS ) ;
2022-09-19 18:26:11 +02:00
// loop over the tiled windows that are fading out
for ( auto & w : g_pCompositor - > m_vWindows ) {
2023-12-09 19:38:32 +01:00
if ( ! shouldRenderWindow ( w . get ( ) , pMonitor , pWorkspace ) )
2022-09-19 18:26:11 +02:00
continue ;
if ( w - > m_fAlpha . fl ( ) = = 0.f )
continue ;
if ( w - > m_bIsFullscreen | | w - > m_bIsFloating )
continue ;
2023-11-24 22:18:50 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = g_pCompositor - > isWorkspaceSpecial ( w - > m_iWorkspaceID ) )
continue ;
2022-09-19 18:26:11 +02:00
renderWindow ( w . get ( ) , pMonitor , time , true , RENDER_PASS_ALL ) ;
}
// and floating ones too
for ( auto & w : g_pCompositor - > m_vWindows ) {
2023-12-09 19:38:32 +01:00
if ( ! shouldRenderWindow ( w . get ( ) , pMonitor , pWorkspace ) )
2022-09-19 18:26:11 +02:00
continue ;
if ( w - > m_fAlpha . fl ( ) = = 0.f )
continue ;
if ( w - > m_bIsFullscreen | | ! w - > m_bIsFloating )
continue ;
2023-11-24 22:18:50 +01:00
if ( w - > m_iMonitorID = = pWorkspace - > m_iMonitorID & & pWorkspace - > m_bIsSpecialWorkspace ! = g_pCompositor - > isWorkspaceSpecial ( w - > m_iWorkspaceID ) )
continue ;
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_iMonitorID ! = pWorkspace - > m_iMonitorID )
continue ; // special on another are rendered as a part of the base pass
2022-09-19 18:26:11 +02:00
renderWindow ( w . get ( ) , pMonitor , time , true , RENDER_PASS_ALL ) ;
}
2023-11-24 22:18:50 +01:00
// TODO: this pass sucks
2022-06-30 15:44:26 +02:00
for ( auto & w : g_pCompositor - > m_vWindows ) {
2022-07-28 15:56:55 +02:00
const auto PWORKSPACE = g_pCompositor - > getWorkspaceByID ( w - > m_iWorkspaceID ) ;
2022-12-16 18:17:31 +01:00
if ( w - > m_iWorkspaceID ! = pWorkspace - > m_iID | | ! w - > m_bIsFullscreen ) {
2022-09-19 11:23:13 +02: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
if ( w - > m_iMonitorID ! = pMonitor - > ID )
continue ;
2022-07-28 15:56:55 +02:00
}
2022-03-21 19:18:33 +01:00
2024-01-09 20:42:07 +01:00
if ( ! w - > m_bIsFullscreen )
2022-07-28 16:33:45 +02:00
continue ;
2022-07-12 09:49:56 +02:00
renderWindow ( w . get ( ) , pMonitor , time , pWorkspace - > m_efFullscreenMode ! = FULLSCREEN_FULL , RENDER_PASS_ALL ) ;
2022-03-30 20:16:23 +02:00
2024-01-09 20:42:07 +01:00
if ( w - > m_iWorkspaceID ! = pWorkspace - > m_iID )
continue ;
2022-06-30 15:44:26 +02:00
pWorkspaceWindow = w . get ( ) ;
2022-03-30 20:16:23 +02:00
}
2022-10-11 21:29:37 +02:00
if ( ! pWorkspaceWindow ) {
// ?? happens sometimes...
pWorkspace - > m_bHasFullscreenWindow = false ;
return ; // this will produce one blank frame. Oh well.
}
2022-09-19 18:26:11 +02:00
// then render windows over fullscreen.
2022-06-30 15:44:26 +02:00
for ( auto & w : g_pCompositor - > m_vWindows ) {
2023-05-10 19:36:13 +02:00
if ( w - > m_iWorkspaceID ! = pWorkspaceWindow - > m_iWorkspaceID | | ( ! w - > m_bCreatedOverFullscreen & & ! w - > m_bPinned ) | | ( ! w - > m_bIsMapped & & ! w - > m_bFadingOut ) | | w - > m_bIsFullscreen )
2022-03-30 20:16:23 +02:00
continue ;
2023-11-24 22:18:50 +01:00
if ( w - > m_iMonitorID = = pWorkspace - > m_iMonitorID & & pWorkspace - > m_bIsSpecialWorkspace ! = g_pCompositor - > isWorkspaceSpecial ( w - > m_iWorkspaceID ) )
continue ;
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_iMonitorID ! = pWorkspace - > m_iMonitorID )
continue ; // special on another are rendered as a part of the base pass
2022-07-12 09:49:56 +02:00
renderWindow ( w . get ( ) , 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
2023-09-04 15:07:56 +02:00
void CHyprRenderer : : renderWorkspaceWindows ( CMonitor * pMonitor , CWorkspace * pWorkspace , timespec * time ) {
CWindow * lastWindow = nullptr ;
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
2023-09-04 15:07:56 +02:00
// Non-floating main
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( w - > isHidden ( ) & & ! w - > m_bIsMapped & & ! w - > m_bFadingOut )
continue ;
2022-05-31 14:20:41 +02:00
2023-09-04 15:07:56 +02:00
if ( w - > m_bIsFloating )
continue ; // floating are in the second pass
2022-03-31 17:25:23 +02:00
2023-09-04 15:07:56 +02:00
if ( ! shouldRenderWindow ( w . get ( ) , pMonitor , pWorkspace ) )
continue ;
2023-11-24 22:18:50 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = g_pCompositor - > isWorkspaceSpecial ( w - > m_iWorkspaceID ) )
2023-11-22 21:05:50 +01:00
continue ;
2023-09-04 15:07:56 +02:00
// render active window after all others of this pass
2023-11-23 00:43:46 +01:00
if ( w . get ( ) = = g_pCompositor - > m_pLastWindow & & w - > m_iWorkspaceID = = pWorkspace - > m_iID ) {
2023-09-04 15:07:56 +02:00
lastWindow = w . get ( ) ;
continue ;
}
// render the bad boy
renderWindow ( w . get ( ) , 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
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( w - > isHidden ( ) & & ! w - > m_bIsMapped & & ! w - > m_bFadingOut )
continue ;
if ( w - > m_bIsFloating )
continue ; // floating are in the second pass
2023-11-24 22:18:50 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = g_pCompositor - > isWorkspaceSpecial ( w - > m_iWorkspaceID ) )
2023-11-22 21:05:50 +01:00
continue ;
2023-09-04 15:07:56 +02:00
if ( ! shouldRenderWindow ( w . get ( ) , pMonitor , pWorkspace ) )
continue ;
// render the bad boy
renderWindow ( w . get ( ) , pMonitor , time , true , RENDER_PASS_POPUP ) ;
2022-04-25 21:49:45 +02:00
}
2023-09-04 15:07:56 +02:00
// floating on top
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( w - > isHidden ( ) & & ! w - > m_bIsMapped & & ! w - > m_bFadingOut )
continue ;
if ( ! w - > m_bIsFloating | | w - > m_bPinned )
continue ;
if ( ! shouldRenderWindow ( w . get ( ) , pMonitor , pWorkspace ) )
continue ;
2023-11-24 22:18:50 +01:00
if ( w - > m_iMonitorID = = pWorkspace - > m_iMonitorID & & pWorkspace - > m_bIsSpecialWorkspace ! = g_pCompositor - > isWorkspaceSpecial ( w - > m_iWorkspaceID ) )
2023-11-18 20:53:45 +01:00
continue ;
2023-11-24 22:18:50 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_iMonitorID ! = pWorkspace - > m_iMonitorID )
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
renderWindow ( w . get ( ) , pMonitor , time , true , RENDER_PASS_ALL ) ;
2023-09-02 20:32:10 +02:00
}
2022-03-21 19:18:33 +01:00
}
2022-12-05 18:05:15 +01:00
void CHyprRenderer : : renderWindow ( CWindow * pWindow , CMonitor * pMonitor , timespec * time , bool decorate , eRenderPassMode mode , bool ignorePosition , bool ignoreAllGeometry ) {
2022-10-14 21:46:32 +02:00
if ( pWindow - > isHidden ( ) )
2022-04-12 16:44:18 +02:00
return ;
2022-04-05 20:49:15 +02:00
if ( pWindow - > m_bFadingOut ) {
2022-05-28 18:52:22 +02:00
if ( pMonitor - > ID = = pWindow - > m_iMonitorID ) // TODO: fix this
g_pHyprOpenGL - > renderSnapshot ( & pWindow ) ;
2022-04-05 20:49:15 +02:00
return ;
}
2022-09-25 20:07:48 +02:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderWindow " ) ;
2023-12-10 17:28:12 +01:00
const auto PWORKSPACE = g_pCompositor - > getWorkspaceByID ( pWindow - > m_iWorkspaceID ) ;
const auto REALPOS = pWindow - > m_vRealPosition . vec ( ) + ( pWindow - > m_bPinned ? Vector2D { } : PWORKSPACE - > m_vRenderOffset . vec ( ) ) ;
2024-02-18 16:00:34 +01:00
static auto * const PDIMAROUND = ( Hyprlang : : FLOAT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:dim_around " ) ;
static auto * const PBLUR = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:blur:enabled " ) ;
2022-06-21 22:54:41 +02:00
2023-11-04 18:03:05 +01:00
SRenderData renderdata = { pMonitor , time } ;
CBox textureBox = { REALPOS . x , REALPOS . y , std : : max ( pWindow - > m_vRealSize . vec ( ) . x , 5.0 ) , std : : max ( pWindow - > m_vRealSize . vec ( ) . y , 5.0 ) } ;
renderdata . x = textureBox . x ;
renderdata . y = textureBox . y ;
renderdata . w = textureBox . w ;
renderdata . h = textureBox . h ;
2022-11-06 18:52:09 +01:00
if ( ignorePosition ) {
2022-11-06 18:58:56 +01:00
renderdata . x = pMonitor - > vecPosition . x ;
renderdata . y = pMonitor - > vecPosition . y ;
2022-11-06 18:52:09 +01:00
}
2022-12-05 18:05:15 +01:00
if ( ignoreAllGeometry )
decorate = false ;
2023-03-20 16:00:58 +01:00
renderdata . surface = pWindow - > m_pWLSurface . wlr ( ) ;
2022-08-01 12:57:37 +02:00
renderdata . dontRound = ( pWindow - > m_bIsFullscreen & & PWORKSPACE - > m_efFullscreenMode = = FULLSCREEN_FULL ) | | ( ! pWindow - > m_sSpecialRenderData . rounding ) ;
2023-01-05 19:25:45 +01:00
renderdata . fadeAlpha = pWindow - > m_fAlpha . fl ( ) * ( pWindow - > m_bPinned ? 1.f : PWORKSPACE - > m_fAlpha . fl ( ) ) ;
2022-12-16 18:17:31 +01:00
renderdata . alpha = pWindow - > m_fActiveInactiveAlpha . fl ( ) ;
2023-08-17 10:13:19 +02:00
renderdata . decorate = decorate & & ! pWindow - > m_bX11DoesntWantBorders & & ( ! pWindow - > m_bIsFullscreen | | PWORKSPACE - > m_efFullscreenMode ! = FULLSCREEN_FULL ) ;
renderdata . rounding = ignoreAllGeometry | | renderdata . dontRound ? 0 : pWindow - > rounding ( ) * pMonitor - > scale ;
renderdata . blur = ! ignoreAllGeometry ; // if it shouldn't, it will be ignored later
renderdata . pWindow = pWindow ;
2022-03-21 19:18:33 +01:00
2022-12-05 19:00:57 +01:00
if ( ignoreAllGeometry ) {
2022-12-16 18:17:31 +01:00
renderdata . alpha = 1.f ;
2023-01-05 19:25:45 +01:00
renderdata . fadeAlpha = 1.f ;
2022-12-05 19:00:57 +01:00
}
2022-07-28 12:07:41 +02:00
// apply opaque
if ( pWindow - > m_sAdditionalConfigData . forceOpaque )
renderdata . alpha = 1.f ;
2022-05-17 13:16:37 +02:00
g_pHyprOpenGL - > m_pCurrentWindow = pWindow ;
2022-03-21 19:18:33 +01:00
2023-05-26 13:07:45 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE_WINDOW ) ;
2022-12-28 19:56:18 +01:00
if ( * PDIMAROUND & & pWindow - > m_sAdditionalConfigData . dimAround & & ! m_bRenderingSnapshot & & mode ! = RENDER_PASS_POPUP ) {
2023-11-04 18:03:05 +01:00
CBox monbox = { 0 , 0 , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . x , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . y } ;
2024-02-18 16:00:34 +01:00
g_pHyprOpenGL - > renderRect ( & monbox , CColor ( 0 , 0 , 0 , * * PDIMAROUND * renderdata . alpha * renderdata . fadeAlpha ) ) ;
2022-12-28 15:39:17 +01:00
}
2022-10-07 11:35:17 +02:00
// clip box for animated offsets
2023-10-21 20:51:14 +02:00
const Vector2D PREOFFSETPOS = { renderdata . x , renderdata . y } ;
2024-01-08 19:58:15 +01:00
if ( ! ignorePosition & & pWindow - > m_bIsFloating & & ! pWindow - > m_bPinned & & ! pWindow - > m_bIsFullscreen ) {
2023-10-21 20:51:14 +02:00
Vector2D offset ;
2022-11-06 19:10:53 +01:00
if ( PWORKSPACE - > m_vRenderOffset . vec ( ) . x ! = 0 ) {
2022-12-16 18:17:31 +01:00
const auto PWSMON = g_pCompositor - > getMonitorFromID ( PWORKSPACE - > m_iMonitorID ) ;
2022-11-06 19:10:53 +01:00
const auto PROGRESS = PWORKSPACE - > m_vRenderOffset . vec ( ) . x / PWSMON - > vecSize . x ;
2022-12-16 18:17:31 +01:00
const auto WINBB = pWindow - > getFullWindowBoundingBox ( ) ;
2022-11-06 19:10:53 +01:00
if ( WINBB . x < PWSMON - > vecPosition . x ) {
offset . x = ( PWSMON - > vecPosition . x - WINBB . x ) * PROGRESS ;
2022-11-16 16:17:01 +01:00
} else if ( WINBB . x + WINBB . width > PWSMON - > vecPosition . x + PWSMON - > vecSize . x ) {
offset . x = ( WINBB . x + WINBB . width - PWSMON - > vecPosition . x - PWSMON - > vecSize . x ) * PROGRESS ;
2022-11-06 19:10:53 +01:00
}
} else if ( PWORKSPACE - > m_vRenderOffset . vec ( ) . y ) {
2022-12-16 18:17:31 +01:00
const auto PWSMON = g_pCompositor - > getMonitorFromID ( PWORKSPACE - > m_iMonitorID ) ;
2022-11-06 19:10:53 +01:00
const auto PROGRESS = PWORKSPACE - > m_vRenderOffset . vec ( ) . y / PWSMON - > vecSize . y ;
2022-12-16 18:17:31 +01:00
const auto WINBB = pWindow - > getFullWindowBoundingBox ( ) ;
2022-11-06 19:10:53 +01:00
if ( WINBB . y < PWSMON - > vecPosition . y ) {
offset . y = ( PWSMON - > vecPosition . y - WINBB . y ) * PROGRESS ;
2022-11-16 16:17:01 +01:00
} else if ( WINBB . y + WINBB . height > PWSMON - > vecPosition . y + PWSMON - > vecSize . y ) {
offset . y = ( WINBB . y + WINBB . width - PWSMON - > vecPosition . y - PWSMON - > vecSize . y ) * PROGRESS ;
2022-11-06 19:10:53 +01:00
}
2022-10-07 13:34:54 +02:00
}
2022-11-06 19:10:53 +01:00
renderdata . x + = offset . x ;
renderdata . y + = offset . y ;
}
2022-12-16 18:17:31 +01:00
2023-11-16 21:20:41 +01:00
// if window is floating and we have a slide animation, clip it to its full bb
2023-12-09 19:41:32 +01:00
if ( ! ignorePosition & & pWindow - > m_bIsFloating & & ! pWindow - > m_bIsFullscreen & & PWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) & & ! pWindow - > m_bPinned ) {
2023-11-21 01:34:34 +01:00
CRegion rg = pWindow - > getFullWindowBoundingBox ( ) . translate ( - pMonitor - > vecPosition + PWORKSPACE - > m_vRenderOffset . vec ( ) ) . scale ( pMonitor - > scale ) ;
2023-11-18 18:00:24 +01:00
g_pHyprOpenGL - > m_RenderData . clipBox = rg . getExtents ( ) ;
}
2023-11-16 21:20:41 +01: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 15:15:48 +02:00
const bool TRANSFORMERSPRESENT = ! pWindow - > m_vTransformers . empty ( ) ;
2023-10-21 20:25:44 +02:00
if ( TRANSFORMERSPRESENT ) {
2023-10-21 15:15:48 +02:00
g_pHyprOpenGL - > bindOffMain ( ) ;
2023-10-21 20:25:44 +02:00
for ( auto & t : pWindow - > m_vTransformers ) {
t - > preWindowRender ( & renderdata ) ;
}
}
2023-12-11 17:32:00 +01:00
if ( decorate ) {
2023-11-04 14:10:52 +01:00
for ( auto & wd : pWindow - > m_dWindowDecorations ) {
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_BOTTOM )
continue ;
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha , Vector2D { renderdata . x , renderdata . y } - PREOFFSETPOS ) ;
}
for ( auto & wd : pWindow - > m_dWindowDecorations ) {
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_UNDER )
continue ;
2023-10-21 20:51:14 +02:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha , Vector2D { renderdata . x , renderdata . y } - PREOFFSETPOS ) ;
2023-11-04 14:10:52 +01:00
}
}
2022-06-22 15:45:56 +02:00
2024-02-18 16:00:34 +01:00
static auto * const PXWLUSENN = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " xwayland:use_nearest_neighbor " ) ;
if ( ( pWindow - > m_bIsX11 & & * * PXWLUSENN ) | | pWindow - > m_sAdditionalConfigData . nearestNeighbor . toUnderlying ( ) )
2023-06-11 21:33:50 +02:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = true ;
2024-02-18 16:00:34 +01:00
if ( pWindow - > m_pWLSurface . small ( ) & & ! pWindow - > m_pWLSurface . m_bFillIgnoreSmall & & renderdata . blur & & * * PBLUR ) {
2023-11-04 18:03:05 +01:00
CBox wb = { renderdata . x - pMonitor - > vecPosition . x , renderdata . y - pMonitor - > vecPosition . y , renderdata . w , renderdata . h } ;
wb . scale ( pMonitor - > scale ) . round ( ) ;
2023-12-06 21:17:40 +01:00
g_pHyprOpenGL - > renderRectWithBlur ( & wb , CColor ( 0 , 0 , 0 , 0 ) , renderdata . dontRound ? 0 : renderdata . rounding - 1 , renderdata . fadeAlpha ,
g_pHyprOpenGL - > shouldUseNewBlurOptimizations ( nullptr , pWindow ) ) ;
2023-10-25 23:20:58 +02:00
renderdata . blur = false ;
}
2023-03-20 16:00:58 +01:00
wlr_surface_for_each_surface ( pWindow - > m_pWLSurface . wlr ( ) , renderSurface , & renderdata ) ;
2022-07-12 09:49:56 +02:00
2023-06-11 21:33:50 +02:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = false ;
2023-12-11 17:32:00 +01:00
if ( decorate ) {
for ( auto & wd : pWindow - > m_dWindowDecorations ) {
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_OVER )
continue ;
2023-11-04 14:10:52 +01:00
2023-12-11 17:32:00 +01:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha , Vector2D { renderdata . x , renderdata . y } - PREOFFSETPOS ) ;
}
2023-11-04 14:10:52 +01:00
}
2023-10-21 15:15:48 +02:00
if ( TRANSFORMERSPRESENT ) {
CFramebuffer * last = g_pHyprOpenGL - > m_RenderData . currentFB ;
for ( auto & t : pWindow - > m_vTransformers ) {
last = t - > transform ( last ) ;
}
g_pHyprOpenGL - > bindBackOnMain ( ) ;
g_pHyprOpenGL - > renderOffToMain ( last ) ;
}
2022-06-22 15:45:56 +02:00
}
2023-11-16 21:20:41 +01: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 ) {
2023-11-04 18:03:05 +01:00
CBox geom ;
wlr_xdg_surface_get_geometry ( pWindow - > m_uSurface . xdg , geom . pWlr ( ) ) ;
geom . applyFromWlr ( ) ;
2022-08-28 10:14:43 +02:00
renderdata . x - = geom . x ;
renderdata . y - = geom . y ;
2022-12-16 18:17:31 +01: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 22:28:55 +02:00
if ( pWindow - > m_sAdditionalConfigData . nearestNeighbor . toUnderlying ( ) )
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = true ;
2022-07-12 09:49:56 +02:00
wlr_xdg_surface_for_each_popup_surface ( pWindow - > m_uSurface . xdg , renderSurface , & renderdata ) ;
2023-10-24 22:28:55 +02:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = false ;
2022-07-12 09:49:56 +02:00
}
2023-11-04 14:10:52 +01:00
2023-12-11 17:32:00 +01:00
if ( decorate ) {
for ( auto & wd : pWindow - > m_dWindowDecorations ) {
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_OVERLAY )
continue ;
2023-11-04 14:10:52 +01:00
2023-12-11 17:32:00 +01:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha , Vector2D { renderdata . x , renderdata . y } - PREOFFSETPOS ) ;
}
2023-11-04 14:10:52 +01:00
}
2022-05-17 13:16:37 +02:00
}
2023-05-26 13:07:45 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WINDOW ) ;
2022-12-16 18:17:31 +01:00
g_pHyprOpenGL - > m_pCurrentWindow = nullptr ;
2023-11-16 21:20:41 +01:00
g_pHyprOpenGL - > m_RenderData . clipBox = CBox ( ) ;
2022-03-21 19:18:33 +01:00
}
2022-07-27 12:32:00 +02:00
void CHyprRenderer : : renderLayer ( SLayerSurface * pLayer , CMonitor * pMonitor , timespec * time ) {
2022-05-14 17:23:46 +02:00
if ( pLayer - > fadingOut ) {
g_pHyprOpenGL - > renderSnapshot ( & pLayer ) ;
return ;
}
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderLayer " ) ;
2024-02-28 16:00:34 +01:00
const auto REALPOS = pLayer - > realPosition . vec ( ) ;
const auto REALSIZ = pLayer - > realSize . vec ( ) ;
SRenderData renderdata = { pMonitor , time , REALPOS . x , REALPOS . y } ;
2022-12-16 18:17:31 +01:00
renderdata . fadeAlpha = pLayer - > alpha . fl ( ) ;
renderdata . blur = pLayer - > forceBlur ;
renderdata . surface = pLayer - > layerSurface - > surface ;
renderdata . decorate = false ;
2024-02-28 16:00:34 +01:00
renderdata . w = REALSIZ . x ;
renderdata . h = REALSIZ . y ;
2022-12-04 21:57:41 +01:00
renderdata . blockBlurOptimization = pLayer - > layer = = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM | | pLayer - > layer = = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ;
2023-03-18 00:16:13 +01:00
2024-02-28 16:00:34 +01:00
g_pHyprOpenGL - > m_RenderData . clipBox = CBox { 0 , 0 , pMonitor - > vecSize . x , pMonitor - > vecSize . y } . scale ( pMonitor - > scale ) ;
2023-08-09 22:03:24 +02:00
g_pHyprOpenGL - > m_pCurrentLayer = pLayer ;
2023-06-11 19:30:31 +02:00
if ( pLayer - > ignoreAlpha ) {
g_pHyprOpenGL - > m_RenderData . discardMode | = DISCARD_ALPHA ;
g_pHyprOpenGL - > m_RenderData . discardOpacity = pLayer - > ignoreAlphaValue ;
}
2022-05-14 17:23:46 +02:00
wlr_surface_for_each_surface ( pLayer - > layerSurface - > surface , renderSurface , & renderdata ) ;
2023-06-11 19:30:31 +02:00
g_pHyprOpenGL - > m_RenderData . discardMode & = ~ DISCARD_ALPHA ;
2022-07-27 18:02:20 +02:00
2022-12-16 18:17:31 +01:00
renderdata . squishOversized = false ; // don't squish popups
renderdata . dontRound = true ;
2023-12-25 18:04:00 +01:00
renderdata . popup = true ;
2022-07-27 18:02:20 +02:00
wlr_layer_surface_v1_for_each_popup_surface ( pLayer - > layerSurface , renderSurface , & renderdata ) ;
2023-08-09 22:03:24 +02:00
2024-02-28 16:00:34 +01:00
g_pHyprOpenGL - > m_pCurrentLayer = nullptr ;
g_pHyprOpenGL - > m_RenderData . clipBox = { } ;
2022-05-14 17:23:46 +02:00
}
2022-08-05 17:07:01 +02:00
void CHyprRenderer : : renderIMEPopup ( SIMEPopup * pPopup , CMonitor * pMonitor , timespec * time ) {
2023-01-20 19:44:30 +01:00
SRenderData renderdata = { pMonitor , time , pPopup - > realX , pPopup - > realY } ;
2022-08-05 17:07:01 +02:00
2022-12-16 18:17:31 +01:00
renderdata . blur = false ;
renderdata . surface = pPopup - > pSurface - > surface ;
2022-08-05 17:07:01 +02:00
renderdata . decorate = false ;
2022-12-16 18:17:31 +01:00
renderdata . w = pPopup - > pSurface - > surface - > current . width ;
renderdata . h = pPopup - > pSurface - > surface - > current . height ;
2022-08-05 17:07:01 +02:00
wlr_surface_for_each_surface ( pPopup - > pSurface - > surface , renderSurface , & renderdata ) ;
}
2023-02-03 12:58:55 +01:00
void CHyprRenderer : : renderSessionLockSurface ( SSessionLockSurface * pSurface , CMonitor * pMonitor , timespec * time ) {
2023-02-03 15:00:23 +01:00
SRenderData renderdata = { pMonitor , time , pMonitor - > vecPosition . x , pMonitor - > vecPosition . y } ;
2023-02-03 12:58:55 +01:00
renderdata . blur = false ;
renderdata . surface = pSurface - > pWlrLockSurface - > surface ;
renderdata . decorate = false ;
renderdata . w = pMonitor - > vecSize . x ;
renderdata . h = pMonitor - > vecSize . y ;
wlr_surface_for_each_surface ( pSurface - > pWlrLockSurface - > surface , renderSurface , & renderdata ) ;
}
2023-04-12 14:05:57 +02:00
void CHyprRenderer : : renderAllClientsForWorkspace ( CMonitor * pMonitor , CWorkspace * pWorkspace , timespec * time , const Vector2D & translate , const float & scale ) {
2024-02-18 16:00:34 +01:00
static auto * const PDIMSPECIAL = ( Hyprlang : : FLOAT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:dim_special " ) ;
static auto * const PBLURSPECIAL = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:blur:special " ) ;
static auto * const PBLUR = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:blur:enabled " ) ;
static auto * const PRENDERTEX = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " misc:disable_hyprland_logo " ) ;
static auto * const PBACKGROUNDCOLOR = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " misc:background_color " ) ;
2024-01-07 18:35:44 +01:00
SRenderModifData RENDERMODIFDATA ;
if ( translate ! = Vector2D { 0 , 0 } )
RENDERMODIFDATA . modifs . push_back ( { SRenderModifData : : eRenderModifType : : RMOD_TYPE_TRANSLATE , translate } ) ;
if ( scale ! = 1.f )
RENDERMODIFDATA . modifs . push_back ( { SRenderModifData : : eRenderModifType : : RMOD_TYPE_SCALE , scale } ) ;
2023-04-12 13:41:23 +02:00
if ( ! pMonitor )
2022-03-17 20:22:29 +01:00
return ;
2023-02-03 12:58:55 +01:00
if ( ! g_pCompositor - > m_sSeat . exclusiveClient & & g_pSessionLockManager - > isSessionLocked ( ) ) {
// locked with no exclusive, draw only red
2023-11-04 18:03:05 +01:00
CBox boxe = { 0 , 0 , INT16_MAX , INT16_MAX } ;
2023-02-03 12:58:55 +01:00
g_pHyprOpenGL - > renderRect ( & boxe , CColor ( 1.0 , 0.2 , 0.2 , 1.0 ) ) ;
return ;
}
2023-04-12 13:41:23 +02: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);
g_pHyprOpenGL - > m_RenderData . renderModif = RENDERMODIFDATA ;
2023-07-19 16:13:55 +02:00
// for storing damage when we optimize for occlusion
2023-07-19 20:09:49 +02:00
CRegion preOccludedDamage { g_pHyprOpenGL - > m_RenderData . damage } ;
2023-07-19 16:13:55 +02:00
2022-03-19 13:35:04 +01:00
// Render layer surfaces below windows for monitor
2023-04-22 13:36:50 +02:00
// if we have a fullscreen, opaque window that convers the screen, we can skip this.
// TODO: check better with solitary after MR for tearing.
const auto PFULLWINDOW = g_pCompositor - > getFullscreenWindowOnWorkspace ( pWorkspace - > m_iID ) ;
2023-04-22 13:54:57 +02:00
if ( ! pWorkspace - > m_bHasFullscreenWindow | | pWorkspace - > m_efFullscreenMode ! = FULLSCREEN_FULL | | ! PFULLWINDOW | | PFULLWINDOW - > m_vRealSize . isBeingAnimated ( ) | |
2023-07-19 16:13:55 +02:00
! PFULLWINDOW - > opaque ( ) | | pWorkspace - > m_vRenderOffset . vec ( ) ! = Vector2D { } ) {
2023-09-01 23:01:59 +02:00
if ( ! g_pHyprOpenGL - > m_RenderData . pCurrentMonData - > blurFBShouldRender )
2023-07-20 18:03:47 +02:00
setOccludedForBackLayers ( g_pHyprOpenGL - > m_RenderData . damage , pWorkspace ) ;
2023-07-19 16:13:55 +02:00
2023-11-26 16:06:42 +01:00
g_pHyprOpenGL - > blend ( false ) ;
if ( ! canSkipBackBufferClear ( pMonitor ) ) {
2024-02-18 16:00:34 +01:00
if ( * * PRENDERTEX /* inverted cfg flag */ )
g_pHyprOpenGL - > clear ( CColor ( * * PBACKGROUNDCOLOR ) ) ;
2023-11-26 16:06:42 +01:00
else
g_pHyprOpenGL - > clearWithTex ( ) ; // will apply the hypr "wallpaper"
}
g_pHyprOpenGL - > blend ( true ) ;
2023-04-22 13:36:50 +02:00
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ] ) {
renderLayer ( ls . get ( ) , pMonitor , time ) ;
}
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ] ) {
renderLayer ( ls . get ( ) , pMonitor , time ) ;
}
2023-07-19 16:13:55 +02:00
2023-07-19 20:09:49 +02:00
g_pHyprOpenGL - > m_RenderData . damage = preOccludedDamage ;
2022-03-19 13:35:04 +01:00
}
2022-08-01 12:23:09 +02:00
// pre window pass
g_pHyprOpenGL - > preWindowPass ( ) ;
2023-12-23 22:41:42 +01:00
setOccludedForMainWorkspace ( g_pHyprOpenGL - > m_RenderData . damage , pWorkspace ) ;
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
2023-12-23 22:41:42 +01:00
g_pHyprOpenGL - > m_RenderData . damage = preOccludedDamage ;
2023-09-04 15:07:56 +02:00
g_pHyprOpenGL - > m_RenderData . renderModif = { } ;
2022-05-31 14:01:00 +02:00
// and then special
2023-08-25 18:05:08 +02:00
for ( auto & ws : g_pCompositor - > m_vWorkspaces ) {
if ( ws - > m_iMonitorID = = pMonitor - > ID & & ws - > m_fAlpha . fl ( ) > 0.f & & ws - > m_bIsSpecialWorkspace ) {
const auto SPECIALANIMPROGRS = ws - > m_vRenderOffset . isBeingAnimated ( ) ? ws - > m_vRenderOffset . getCurveValue ( ) : ws - > m_fAlpha . getCurveValue ( ) ;
const bool ANIMOUT = ! pMonitor - > specialWorkspaceID ;
2022-12-28 15:18:23 +01:00
2024-02-18 16:00:34 +01:00
if ( * * PDIMSPECIAL ! = 0.f ) {
2023-11-04 18:03:05 +01:00
CBox monbox = { translate . x , translate . y , pMonitor - > vecTransformedSize . x * scale , pMonitor - > vecTransformedSize . y * scale } ;
2024-02-18 16:00:34 +01:00
g_pHyprOpenGL - > renderRect ( & monbox , CColor ( 0 , 0 , 0 , * * PDIMSPECIAL * ( ANIMOUT ? ( 1.0 - SPECIALANIMPROGRS ) : SPECIALANIMPROGRS ) ) ) ;
2022-12-28 15:18:23 +01:00
}
2024-02-18 16:00:34 +01:00
if ( * * PBLURSPECIAL & & * * PBLUR ) {
2023-11-04 18:03:05 +01:00
CBox monbox = { translate . x , translate . y , pMonitor - > vecTransformedSize . x * scale , pMonitor - > vecTransformedSize . y * scale } ;
2023-08-25 17:43:23 +02:00
g_pHyprOpenGL - > renderRectWithBlur ( & monbox , CColor ( 0 , 0 , 0 , 0 ) , 0 , ( ANIMOUT ? ( 1.0 - SPECIALANIMPROGRS ) : SPECIALANIMPROGRS ) ) ;
}
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 18:00:24 +01:00
// special
for ( auto & ws : g_pCompositor - > m_vWorkspaces ) {
if ( ws - > m_iMonitorID = = pMonitor - > ID & & ws - > m_fAlpha . fl ( ) > 0.f & & ws - > m_bIsSpecialWorkspace )
renderWorkspaceWindows ( pMonitor , ws . get ( ) , time ) ;
2022-03-18 20:03:39 +01:00
}
2022-03-19 13:35:04 +01:00
2023-11-22 21:05:50 +01:00
// pinned always above
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( w - > isHidden ( ) & & ! w - > m_bIsMapped & & ! w - > m_bFadingOut )
continue ;
if ( ! w - > m_bPinned | | ! w - > m_bIsFloating )
continue ;
if ( ! shouldRenderWindow ( w . get ( ) , pMonitor , pWorkspace ) )
continue ;
// render the bad boy
renderWindow ( w . get ( ) , pMonitor , time , true , RENDER_PASS_ALL ) ;
}
2023-04-18 00:45:03 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WINDOWS ) ;
2022-03-19 13:35:04 +01:00
// Render surfaces above windows for monitor
2023-04-12 13:41:23 +02:00
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
renderLayer ( ls . get ( ) , pMonitor , time ) ;
2022-03-19 13:35:04 +01:00
}
2022-08-05 17:07:01 +02:00
// Render IME popups
for ( auto & imep : g_pInputManager - > m_sIMERelay . m_lIMEPopups ) {
2023-04-12 13:41:23 +02:00
renderIMEPopup ( & imep , pMonitor , time ) ;
2022-08-05 17:07:01 +02:00
}
2023-04-12 13:41:23 +02:00
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] ) {
renderLayer ( ls . get ( ) , pMonitor , time ) ;
2022-03-19 13:35:04 +01:00
}
2022-03-31 17:25:23 +02:00
2023-04-12 13:41:23 +02:00
renderDragIcon ( pMonitor , time ) ;
//g_pHyprOpenGL->restoreMatrix();
g_pHyprOpenGL - > m_RenderData . renderModif = { } ;
}
2023-02-03 12:58:55 +01:00
2023-04-12 13:41:23 +02:00
void CHyprRenderer : : renderLockscreen ( CMonitor * pMonitor , timespec * now ) {
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderLockscreen " ) ;
2023-02-03 12:58:55 +01:00
if ( g_pSessionLockManager - > isSessionLocked ( ) ) {
2023-04-12 13:41:23 +02:00
const auto PSLS = g_pSessionLockManager - > getSessionLockSurfaceForMonitor ( pMonitor - > ID ) ;
2023-02-03 12:58:55 +01:00
if ( ! PSLS ) {
// locked with no surface, fill with red
2023-11-04 18:03:05 +01:00
CBox boxe = { 0 , 0 , INT16_MAX , INT16_MAX } ;
2023-02-03 12:58:55 +01:00
g_pHyprOpenGL - > renderRect ( & boxe , CColor ( 1.0 , 0.2 , 0.2 , 1.0 ) ) ;
} else {
2023-04-12 13:41:23 +02:00
renderSessionLockSurface ( PSLS , pMonitor , now ) ;
2023-02-03 12:58:55 +01:00
}
}
2022-03-17 20:22:29 +01:00
}
2022-03-19 14:07:18 +01:00
2024-01-29 00:42:39 +01:00
void CHyprRenderer : : calculateUVForSurface ( CWindow * pWindow , wlr_surface * pSurface , bool main , const Vector2D & projSize , bool fixMisalignedFSV1 ) {
2023-01-29 14:58:47 +01:00
if ( ! pWindow | | ! pWindow - > m_bIsX11 ) {
2022-08-28 10:14:43 +02:00
Vector2D uvTL ;
Vector2D uvBR = Vector2D ( 1 , 1 ) ;
if ( pSurface - > current . viewport . has_src ) {
2023-01-20 19:44:30 +01:00
// we stretch it to dest. if no dest, to 1,1
2022-08-28 10:14:43 +02:00
wlr_fbox bufferSource ;
wlr_surface_get_buffer_source_box ( pSurface , & bufferSource ) ;
2023-01-20 19:44:30 +01:00
Vector2D bufferSize = Vector2D ( pSurface - > buffer - > texture - > width , pSurface - > buffer - > texture - > height ) ;
2022-08-28 10:14:43 +02:00
2023-01-29 16:58:36 +01: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 18:17:31 +01:00
uvBR = Vector2D ( 1 , 1 ) ;
2022-08-28 14:32:06 +02:00
}
2022-08-28 10:14:43 +02:00
}
2024-01-29 00:42:39 +01:00
if ( projSize ! = Vector2D { } & & fixMisalignedFSV1 ) {
// instead of nearest_neighbor (we will repeat / skip)
// just cut off / expand surface
const Vector2D PIXELASUV = Vector2D { 1 , 1 } / Vector2D { pSurface - > buffer - > texture - > width , pSurface - > buffer - > texture - > height } ;
const Vector2D MISALIGNMENT = Vector2D { pSurface - > buffer - > texture - > width , pSurface - > buffer - > texture - > height } - projSize ;
if ( MISALIGNMENT ! = Vector2D { } )
uvBR - = MISALIGNMENT * PIXELASUV ;
}
2022-12-16 18:17:31 +01: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 18:17:31 +01: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 14:58:47 +01:00
if ( ! main | | ! pWindow )
2023-01-20 19:44:30 +01:00
return ;
2022-08-28 10:14:43 +02:00
2023-11-04 18:03:05 +01:00
CBox geom ;
wlr_xdg_surface_get_geometry ( pWindow - > m_uSurface . xdg , geom . pWlr ( ) ) ;
geom . applyFromWlr ( ) ;
2023-01-20 19:44:30 +01:00
// ignore X and Y, adjust uv
2023-10-20 21:32:47 +02:00
if ( geom . x ! = 0 | | geom . y ! = 0 | | geom . width > pWindow - > m_vRealSize . vec ( ) . x | | geom . height > pWindow - > m_vRealSize . vec ( ) . y ) {
2023-01-20 19:44:30 +01:00
const auto XPERC = ( double ) geom . x / ( double ) pSurface - > current . width ;
const auto YPERC = ( double ) geom . y / ( double ) pSurface - > current . height ;
const auto WPERC = ( double ) ( geom . x + geom . width ) / ( double ) pSurface - > current . width ;
const auto HPERC = ( double ) ( geom . y + geom . height ) / ( double ) pSurface - > current . height ;
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 ) ) ;
uvBR = uvBR - Vector2D ( 1.0 - WPERC * ( uvBR . x - uvTL . x ) , 1.0 - HPERC * ( uvBR . y - uvTL . y ) ) ;
uvTL = uvTL + TOADDTL ;
2022-08-28 10:14:43 +02:00
2023-11-13 00:57:53 +01:00
// TODO: make this passed to the func. Might break in the future.
auto maxSize = pWindow - > m_vRealSize . vec ( ) ;
if ( pWindow - > m_pWLSurface . small ( ) & & ! pWindow - > m_pWLSurface . m_bFillIgnoreSmall )
maxSize = pWindow - > m_pWLSurface . getViewporterCorrectedSize ( ) ;
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 18:17:31 +01: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 ) ;
}
}
2022-11-05 13:50:47 +01:00
void countSubsurfacesIter ( wlr_surface * pSurface , int x , int y , void * data ) {
* ( int * ) data + = 1 ;
}
bool CHyprRenderer : : attemptDirectScanout ( CMonitor * pMonitor ) {
2023-04-03 18:01:05 +02:00
if ( ! pMonitor - > mirrors . empty ( ) | | pMonitor - > isMirror ( ) | | m_bDirectScanoutBlocked )
2022-11-09 11:56:36 +01:00
return false ; // do not DS if this monitor is being mirrored. Will break the functionality.
2023-04-06 22:03:53 +02:00
if ( ! wlr_output_is_direct_scanout_allowed ( pMonitor - > output ) )
return false ;
2023-09-28 22:48:33 +02:00
const auto PCANDIDATE = pMonitor - > solitaryClient ;
2022-11-05 13:50:47 +01:00
if ( ! PCANDIDATE )
return false ;
2023-09-28 22:48:33 +02:00
const auto PSURFACE = g_pXWaylandManager - > getWindowSurface ( PCANDIDATE ) ;
2022-11-05 13:50:47 +01:00
if ( ! PSURFACE | | PSURFACE - > current . scale ! = pMonitor - > output - > scale | | PSURFACE - > current . transform ! = pMonitor - > output - > transform )
return false ;
// finally, we should be GTG.
2024-01-28 02:57:13 +01:00
wlr_output_state_set_buffer ( pMonitor - > state . wlr ( ) , & PSURFACE - > buffer - > base ) ;
2022-11-05 13:50:47 +01:00
2024-01-28 02:57:13 +01:00
if ( ! wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) )
2022-11-05 13:50:47 +01:00
return false ;
2022-11-06 15:20:03 +01:00
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
wlr_surface_send_frame_done ( PSURFACE , & now ) ;
2024-01-01 16:47:54 +01:00
wlr_presentation_surface_scanned_out_on_output ( PSURFACE , pMonitor - > output ) ;
2022-11-05 13:50:47 +01:00
2024-01-28 02:57:13 +01:00
if ( pMonitor - > state . commit ( ) ) {
2022-11-05 13:50:47 +01:00
if ( ! m_pLastScanout ) {
m_pLastScanout = PCANDIDATE ;
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Entered a direct scanout to {:x}: \" {} \" " , ( uintptr_t ) PCANDIDATE , PCANDIDATE - > m_szTitle ) ;
2022-11-05 13:50:47 +01:00
}
} else {
m_pLastScanout = nullptr ;
return false ;
}
return true ;
}
2023-03-24 20:23:16 +01:00
void CHyprRenderer : : renderMonitor ( CMonitor * pMonitor ) {
2023-11-24 11:54:21 +01: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 20:23:16 +01:00
static std : : chrono : : high_resolution_clock : : time_point endRenderOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
2024-02-18 16:00:34 +01:00
static auto * const PDEBUGOVERLAY = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:overlay " ) ;
static auto * const PDAMAGETRACKINGMODE = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:damage_tracking " ) ;
static auto * const PDAMAGEBLINK = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:damage_blink " ) ;
static auto * const PNODIRECTSCANOUT = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " misc:no_direct_scanout " ) ;
static auto * const PVFR = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " misc:vfr " ) ;
static auto * const PZOOMFACTOR = ( Hyprlang : : FLOAT * const * ) g_pConfigManager - > getConfigValuePtr ( " misc:cursor_zoom_factor " ) ;
static auto * const PANIMENABLED = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " animations:enabled " ) ;
static auto * const PFIRSTLAUNCHANIM = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " animations:first_launch_animation " ) ;
static auto * const PTEARINGENABLED = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " general:allow_tearing " ) ;
2023-03-24 20:23:16 +01:00
static int damageBlinkCleanup = 0 ; // because double-buffered
2024-02-18 16:00:34 +01:00
if ( ! * * PDAMAGEBLINK )
2023-03-24 20:23:16 +01:00
damageBlinkCleanup = 0 ;
2023-05-24 15:49:27 +02:00
static bool firstLaunch = true ;
2024-02-18 16:00:34 +01:00
static bool firstLaunchAnimActive = * * PFIRSTLAUNCHANIM ;
2023-05-01 03:49:41 +02: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-02-18 16:00:34 +01: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 03:49:41 +02:00
}
2023-11-24 11:54:21 +01:00
renderStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-03-24 20:23:16 +01:00
2024-02-18 16:00:34 +01:00
if ( * * PDEBUGOVERLAY = = 1 )
2023-03-24 20:23:16 +01:00
g_pDebugOverlay - > frameData ( pMonitor ) ;
if ( pMonitor - > framesToSkip > 0 ) {
pMonitor - > framesToSkip - = 1 ;
if ( ! pMonitor - > noFrameSchedule )
g_pCompositor - > scheduleFrameForMonitor ( pMonitor ) ;
2024-02-18 16:00:34 +01:00
else
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " NoFrameSchedule hit for {}. " , pMonitor - > szName ) ;
2024-02-18 16:00:34 +01:00
2023-03-24 20:23:16 +01:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitor - > ID ) ;
if ( pMonitor - > framesToSkip > 10 )
pMonitor - > framesToSkip = 0 ;
return ;
}
// checks //
if ( pMonitor - > ID = = m_pMostHzMonitor - > ID | |
2024-02-18 16:00:34 +01: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 20:23:16 +01: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 ( ) ;
ensureCursorRenderingMode ( ) ; // so that the cursor gets hidden/shown if the user requested timeouts
}
// //
if ( pMonitor - > scheduledRecalc ) {
pMonitor - > scheduledRecalc = false ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitor - > ID ) ;
}
2023-06-14 13:26:47 +02:00
// gamma stuff
if ( pMonitor - > gammaChanged ) {
pMonitor - > gammaChanged = false ;
const auto PGAMMACTRL = wlr_gamma_control_manager_v1_get_control ( g_pCompositor - > m_sWLRGammaCtrlMgr , pMonitor - > output ) ;
2024-01-28 02:57:13 +01:00
if ( ! wlr_gamma_control_v1_apply ( PGAMMACTRL , pMonitor - > state . wlr ( ) ) ) {
2023-09-06 21:45:37 +02:00
Debug : : log ( ERR , " Could not apply gamma control to {} " , pMonitor - > szName ) ;
2023-06-14 13:26:47 +02:00
return ;
}
2024-01-28 02:57:13 +01:00
if ( ! wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) ) {
2023-09-06 21:45:37 +02:00
Debug : : log ( ERR , " Output test failed for setting gamma to {} " , pMonitor - > szName ) ;
2024-01-27 14:58:13 +01:00
// aka rollback
2024-01-28 02:57:13 +01:00
wlr_gamma_control_v1_apply ( nullptr , pMonitor - > state . wlr ( ) ) ;
2023-06-14 13:26:47 +02:00
wlr_gamma_control_v1_send_failed_and_destroy ( PGAMMACTRL ) ;
}
}
2023-09-28 22:48:33 +02:00
// tearing and DS first
bool shouldTear = false ;
2023-09-30 18:07:50 +02:00
if ( pMonitor - > tearingState . nextRenderTorn ) {
pMonitor - > tearingState . nextRenderTorn = false ;
2023-09-28 22:48:33 +02:00
2024-02-18 16:00:34 +01:00
if ( ! * * PTEARINGENABLED ) {
2023-09-28 22:48:33 +02: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 18:07:50 +02:00
if ( ! pMonitor - > tearingState . canTear ) {
2023-09-28 22:48:33 +02:00
Debug : : log ( WARN , " Tearing commit requested but monitor doesn't support it, ignoring " ) ;
return ;
}
if ( pMonitor - > solitaryClient )
shouldTear = true ;
}
2024-02-18 16:00:34 +01:00
if ( ! * * PNODIRECTSCANOUT & & ! shouldTear ) {
2023-03-24 20:23:16 +01:00
if ( attemptDirectScanout ( pMonitor ) ) {
return ;
} else if ( m_pLastScanout ) {
Debug : : log ( LOG , " Left a direct scanout. " ) ;
m_pLastScanout = nullptr ;
}
}
2023-09-30 18:07:50 +02:00
if ( pMonitor - > tearingState . activelyTearing ! = shouldTear ) {
2023-09-30 17:55:41 +02:00
// change of state
2023-09-30 18:07:50 +02:00
pMonitor - > tearingState . activelyTearing = shouldTear ;
2023-09-30 17:55:41 +02:00
}
2023-09-30 14:06:25 +02:00
2023-03-24 20:23:16 +01:00
EMIT_HOOK_EVENT ( " preRender " , pMonitor ) ;
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
// check the damage
2024-02-17 03:09:12 +01:00
bool hasChanged = pMonitor - > output - > needs_frame | | pixman_region32_not_empty ( & pMonitor - > damage . current ) ;
2023-03-24 20:23:16 +01:00
2024-02-18 16:00:34 +01:00
if ( ! hasChanged & & * * PDAMAGETRACKINGMODE ! = DAMAGE_TRACKING_NONE & & pMonitor - > forceFullFrames = = 0 & & damageBlinkCleanup = = 0 )
2023-04-09 18:59:24 +02:00
return ;
2024-02-18 16:00:34 +01:00
if ( * * PDAMAGETRACKINGMODE = = - 1 ) {
2023-03-24 20:23:16 +01:00
Debug : : log ( CRIT , " Damage tracking mode -1 ???? " ) ;
return ;
}
2023-04-18 00:45:03 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE ) ;
2023-04-03 18:01:05 +02:00
const bool UNLOCK_SC = g_pHyprRenderer - > m_bSoftwareCursorsLocked ;
if ( UNLOCK_SC )
wlr_output_lock_software_cursors ( pMonitor - > output , true ) ;
2023-03-24 20:23:16 +01:00
pMonitor - > renderingActive = true ;
2024-02-19 19:17:32 +01: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 17:04:08 +01:00
TRACY_GPU_ZONE ( " Render " ) ;
if ( pMonitor = = g_pCompositor - > getMonitorFromCursor ( ) )
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = std : : clamp ( * * PZOOMFACTOR , 1.f , INFINITY ) ;
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-23 02:02:32 +01:00
CRegion damage , finalDamage ;
2024-02-18 17:04:08 +01:00
if ( ! beginRender ( pMonitor , damage , RENDER_MODE_NORMAL ) ) {
Debug : : log ( ERR , " renderer: couldn't beginRender()! " ) ;
if ( UNLOCK_SC )
wlr_output_lock_software_cursors ( pMonitor - > output , false ) ;
pMonitor - > state . clear ( ) ;
return ;
}
2023-03-24 20:23:16 +01:00
// if we have no tracking or full tracking, invalidate the entire monitor
2024-02-18 16:00:34 +01:00
if ( * * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_NONE | | * * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_MONITOR | | pMonitor - > forceFullFrames > 0 | | damageBlinkCleanup > 0 | |
2023-03-24 20:23:16 +01:00
pMonitor - > isMirror ( ) /* why??? */ ) {
2024-02-23 02:02:32 +01:00
damage = { 0 , 0 , ( int ) pMonitor - > vecTransformedSize . x * 10 , ( int ) pMonitor - > vecTransformedSize . y * 10 } ;
finalDamage = damage ;
2023-03-24 20:23:16 +01:00
} else {
2024-02-18 16:00:34 +01:00
static auto * const PBLURENABLED = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:blur:enabled " ) ;
2023-03-24 20:23:16 +01:00
// if we use blur we need to expand the damage for proper blurring
2024-02-23 00:01:22 +01:00
// if framebuffer was not offloaded we're not doing introspection aka not blurring so this is redundant and dumb
if ( * * PBLURENABLED = = 1 & & g_pHyprOpenGL - > m_bOffloadedFramebuffer ) {
2023-03-24 20:23:16 +01:00
// TODO: can this be optimized?
2024-02-18 16:00:34 +01:00
static auto * const PBLURSIZE = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:blur:size " ) ;
static auto * const PBLURPASSES = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " decoration:blur:passes " ) ;
2023-03-24 20:23:16 +01:00
const auto BLURRADIUS =
2024-02-18 16:00:34 +01:00
* * PBLURPASSES > 10 ? pow ( 2 , 15 ) : std : : clamp ( * * PBLURSIZE , ( int64_t ) 1 , ( int64_t ) 40 ) * pow ( 2 , * * PBLURPASSES ) ; // is this 2^pass? I don't know but it works... I think.
2023-03-24 20:23:16 +01:00
// now, prep the damage, get the extended damage region
2023-07-19 20:09:49 +02:00
wlr_region_expand ( damage . pixman ( ) , damage . pixman ( ) , BLURRADIUS ) ; // expand for proper blurring
2023-03-24 20:23:16 +01:00
2024-02-23 02:02:32 +01:00
finalDamage = damage ;
2023-03-24 20:23:16 +01:00
2023-07-19 20:09:49 +02:00
wlr_region_expand ( damage . pixman ( ) , damage . pixman ( ) , BLURRADIUS ) ; // expand for proper blurring 2
2024-02-23 02:02:32 +01:00
} else
finalDamage = damage ;
2023-03-24 20:23:16 +01:00
}
2024-02-19 19:17:32 +01:00
// update damage in renderdata as we modified it
2024-02-23 02:02:32 +01:00
g_pHyprOpenGL - > setDamage ( damage , finalDamage ) ;
2023-03-24 20:23:16 +01:00
2024-02-19 19:17:32 +01:00
if ( pMonitor - > forceFullFrames > 0 ) {
pMonitor - > forceFullFrames - = 1 ;
if ( pMonitor - > forceFullFrames > 10 )
pMonitor - > forceFullFrames = 0 ;
}
2023-04-18 00:45:03 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_BEGIN ) ;
2023-09-29 18:51:07 +02:00
bool renderCursor = true ;
if ( ! pMonitor - > solitaryClient ) {
if ( pMonitor - > isMirror ( ) ) {
g_pHyprOpenGL - > blend ( false ) ;
g_pHyprOpenGL - > renderMirrored ( ) ;
g_pHyprOpenGL - > blend ( true ) ;
EMIT_HOOK_EVENT ( " render " , RENDER_POST_MIRROR ) ;
renderCursor = false ;
} else {
2023-11-04 18:03:05 +01:00
CBox renderBox = { 0 , 0 , ( int ) pMonitor - > vecPixelSize . x , ( int ) pMonitor - > vecPixelSize . y } ;
2023-09-29 18:51:07 +02:00
renderWorkspace ( pMonitor , g_pCompositor - > getWorkspaceByID ( pMonitor - > activeWorkspace ) , & now , renderBox ) ;
2023-04-12 13:41:23 +02:00
2023-09-29 18:51:07 +02:00
renderLockscreen ( pMonitor , & now ) ;
2023-03-24 20:23:16 +01:00
2023-09-29 18:51:07 +02:00
if ( pMonitor = = g_pCompositor - > m_pLastMonitor ) {
g_pHyprNotificationOverlay - > draw ( pMonitor ) ;
g_pHyprError - > draw ( ) ;
}
2023-03-24 20:23:16 +01:00
2023-09-29 18:51:07 +02:00
// for drawing the debug overlay
2024-02-18 16:00:34 +01:00
if ( pMonitor = = g_pCompositor - > m_vMonitors . front ( ) . get ( ) & & * * PDEBUGOVERLAY = = 1 ) {
2023-11-24 11:54:21 +01:00
renderStartOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-09-29 18:51:07 +02:00
g_pDebugOverlay - > draw ( ) ;
endRenderOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
}
2023-03-24 20:23:16 +01:00
2024-02-18 16:00:34 +01:00
if ( * * PDAMAGEBLINK & & damageBlinkCleanup = = 0 ) {
2023-11-04 18:03:05 +01:00
CBox monrect = { 0 , 0 , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y } ;
2023-09-29 18:51:07 +02:00
g_pHyprOpenGL - > renderRect ( & monrect , CColor ( 1.0 , 0.0 , 1.0 , 100.0 / 255.0 ) , 0 ) ;
damageBlinkCleanup = 1 ;
2024-02-18 16:00:34 +01:00
} else if ( * * PDAMAGEBLINK ) {
2023-09-29 18:51:07 +02:00
damageBlinkCleanup + + ;
if ( damageBlinkCleanup > 3 )
damageBlinkCleanup = 0 ;
}
2023-03-24 20:23:16 +01:00
}
2023-09-29 18:51:07 +02:00
} else {
g_pHyprRenderer - > renderWindow ( pMonitor - > solitaryClient , pMonitor , & now , false , RENDER_PASS_MAIN /* solitary = no popups */ ) ;
}
2023-03-24 20:23:16 +01:00
2023-09-29 18:51:07 +02:00
renderCursor = renderCursor & & shouldRenderCursor ( ) ;
2023-11-24 11:54:21 +01:00
if ( renderCursor ) {
2023-09-29 18:51:07 +02:00
TRACY_GPU_ZONE ( " RenderCursor " ) ;
2024-02-18 16:00:34 +01:00
bool lockSoftware = pMonitor = = g_pCompositor - > getMonitorFromCursor ( ) & & * * PZOOMFACTOR ! = 1.f ;
2023-09-29 18:51:07 +02:00
if ( lockSoftware ) {
wlr_output_lock_software_cursors ( pMonitor - > output , true ) ;
2023-11-24 11:54:21 +01:00
g_pHyprRenderer - > renderSoftwareCursors ( pMonitor , g_pHyprOpenGL - > m_RenderData . damage ) ;
2023-09-29 18:51:07 +02:00
wlr_output_lock_software_cursors ( pMonitor - > output , false ) ;
} else
2023-11-24 11:54:21 +01:00
g_pHyprRenderer - > renderSoftwareCursors ( pMonitor , g_pHyprOpenGL - > m_RenderData . damage ) ;
2023-05-01 03:49:41 +02:00
}
2023-04-18 00:45:03 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_LAST_MOMENT ) ;
2023-11-24 11:54:21 +01:00
endRender ( ) ;
2023-03-24 20:23:16 +01:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_COLLECT ;
2024-02-14 23:33:50 +01:00
if ( ! pMonitor - > mirrors . empty ( ) ) {
CRegion frameDamage { } ;
2023-03-24 20:23:16 +01:00
2024-02-14 23:33:50 +01:00
const auto TRANSFORM = wlr_output_transform_invert ( pMonitor - > output - > transform ) ;
2024-02-23 02:02:32 +01:00
wlr_region_transform ( frameDamage . pixman ( ) , finalDamage . pixman ( ) , TRANSFORM , ( int ) pMonitor - > vecTransformedSize . x , ( int ) pMonitor - > vecTransformedSize . y ) ;
2023-03-24 20:23:16 +01:00
2024-02-18 16:00:34 +01:00
if ( * * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_NONE | | * * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_MONITOR )
2024-02-14 23:33:50 +01:00
frameDamage . add ( 0 , 0 , ( int ) pMonitor - > vecTransformedSize . x , ( int ) pMonitor - > vecTransformedSize . y ) ;
2023-03-24 20:23:16 +01:00
2024-02-18 16:00:34 +01:00
if ( * * PDAMAGEBLINK )
2024-02-14 23:33:50 +01:00
frameDamage . add ( damage ) ;
2023-03-24 20:23:16 +01:00
2023-07-19 20:09:49 +02:00
g_pHyprRenderer - > damageMirrorsWith ( pMonitor , frameDamage ) ;
2024-02-14 23:33:50 +01:00
}
2023-03-24 20:23:16 +01:00
pMonitor - > renderingActive = false ;
2023-04-18 00:45:03 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST ) ;
2024-01-28 02:57:13 +01:00
pMonitor - > state . wlr ( ) - > tearing_page_flip = shouldTear ;
2023-09-28 22:48:33 +02:00
2024-01-28 02:57:13 +01:00
if ( ! pMonitor - > state . commit ( ) ) {
2023-09-29 18:51:07 +02:00
2023-04-03 18:01:05 +02:00
if ( UNLOCK_SC )
wlr_output_lock_software_cursors ( pMonitor - > output , false ) ;
2024-02-28 19:00:02 +01:00
wlr_damage_ring_add_whole ( & pMonitor - > damage ) ;
2024-02-19 19:17:32 +01:00
2023-03-24 20:23:16 +01:00
return ;
2023-04-03 18:01:05 +02:00
}
2023-09-28 22:48:33 +02:00
if ( shouldTear )
2023-09-30 18:07:50 +02:00
pMonitor - > tearingState . busy = true ;
2023-09-28 22:48:33 +02:00
2023-04-03 18:01:05 +02:00
if ( UNLOCK_SC )
wlr_output_lock_software_cursors ( pMonitor - > output , false ) ;
2023-03-24 20:23:16 +01:00
2024-02-18 16:00:34 +01:00
if ( * * PDAMAGEBLINK | | * * PVFR = = 0 | | pMonitor - > pendingFrame )
2023-03-24 20:23:16 +01:00
g_pCompositor - > scheduleFrameForMonitor ( pMonitor ) ;
pMonitor - > pendingFrame = false ;
2023-11-24 11:54:21 +01:00
const float µ s = std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( std : : chrono : : high_resolution_clock : : now ( ) - renderStart ) . count ( ) / 1000.f ;
2023-03-24 20:23:16 +01:00
g_pDebugOverlay - > renderData ( pMonitor , µ s ) ;
2024-02-18 16:00:34 +01:00
if ( * * PDEBUGOVERLAY = = 1 ) {
2023-03-24 20:23:16 +01:00
if ( pMonitor = = g_pCompositor - > m_vMonitors . front ( ) . get ( ) ) {
2023-11-24 11:54:21 +01:00
const float µ sNoOverlay = µ s - std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( endRenderOverlay - renderStartOverlay ) . count ( ) / 1000.f ;
2023-03-24 20:23:16 +01:00
g_pDebugOverlay - > renderDataNoOverlay ( pMonitor , µ sNoOverlay ) ;
} else {
g_pDebugOverlay - > renderDataNoOverlay ( pMonitor , µ s ) ;
}
}
}
2023-11-04 18:03:05 +01:00
void CHyprRenderer : : renderWorkspace ( CMonitor * pMonitor , CWorkspace * pWorkspace , timespec * now , const CBox & geometry ) {
2023-04-12 13:41:23 +02: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 13:50:20 +02:00
if ( ! DELTALESSTHAN ( ( double ) geometry . width / ( double ) geometry . height , pMonitor - > vecPixelSize . x / pMonitor - > vecPixelSize . y , 0.01 ) ) {
2023-04-12 13:41:23 +02:00
Debug : : log ( ERR , " Ignoring geometry in renderWorkspace: aspect ratio mismatch " ) ;
scale = 1.f ;
translate = Vector2D { } ;
}
2023-04-18 00:47:12 +02:00
g_pHyprOpenGL - > m_RenderData . pWorkspace = pWorkspace ;
2023-04-12 14:05:57 +02:00
renderAllClientsForWorkspace ( pMonitor , pWorkspace , now , translate , scale ) ;
2023-04-18 00:47:12 +02:00
g_pHyprOpenGL - > m_RenderData . pWorkspace = nullptr ;
2023-04-12 13:41:23 +02:00
}
2022-11-05 13:50:47 +01:00
void CHyprRenderer : : setWindowScanoutMode ( CWindow * pWindow ) {
2023-02-03 12:58:55 +01:00
if ( ! g_pCompositor - > m_sWLRLinuxDMABuf | | g_pSessionLockManager - > isSessionLocked ( ) )
2022-11-05 13:50:47 +01:00
return ;
if ( ! pWindow - > m_bIsFullscreen ) {
2023-03-20 16:00:58 +01:00
wlr_linux_dmabuf_v1_set_surface_feedback ( g_pCompositor - > m_sWLRLinuxDMABuf , pWindow - > m_pWLSurface . wlr ( ) , nullptr ) ;
2023-09-20 17:25:03 +02:00
Debug : : log ( LOG , " Scanout mode OFF set for {} " , pWindow ) ;
2022-11-05 13:50:47 +01:00
return ;
}
2023-03-03 22:28:22 +01:00
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2022-11-05 13:50:47 +01:00
2023-03-03 22:28:22 +01:00
const wlr_linux_dmabuf_feedback_v1_init_options INIT_OPTIONS = {
. main_renderer = g_pCompositor - > m_sWLRRenderer ,
. scanout_primary_output = PMONITOR - > output ,
2022-11-05 13:50:47 +01:00
} ;
2023-03-03 22:28:22 +01:00
wlr_linux_dmabuf_feedback_v1 feedback = { 0 } ;
2022-11-05 13:50:47 +01:00
2023-03-03 22:28:22 +01:00
if ( ! wlr_linux_dmabuf_feedback_v1_init_with_options ( & feedback , & INIT_OPTIONS ) )
2022-11-05 13:50:47 +01:00
return ;
2023-03-20 16:00:58 +01:00
wlr_linux_dmabuf_v1_set_surface_feedback ( g_pCompositor - > m_sWLRLinuxDMABuf , pWindow - > m_pWLSurface . wlr ( ) , & feedback ) ;
2023-03-03 22:28:22 +01:00
wlr_linux_dmabuf_feedback_v1_finish ( & feedback ) ;
2022-11-05 13:50:47 +01:00
2023-09-20 17:25:03 +02:00
Debug : : log ( LOG , " Scanout mode ON set for {} " , pWindow ) ;
2022-11-05 13:50:47 +01:00
}
2022-03-19 14:07:18 +01:00
void CHyprRenderer : : outputMgrApplyTest ( wlr_output_configuration_v1 * config , bool test ) {
wlr_output_configuration_head_v1 * head ;
2023-09-10 14:14:27 +02:00
bool ok = true ;
2022-03-19 14:07:18 +01:00
wl_list_for_each ( head , & config - > heads , link ) {
2022-05-06 17:18:24 +02:00
std : : string commandForCfg = " " ;
2022-12-16 18:17:31 +01:00
const auto OUTPUT = head - > state . output ;
2022-03-19 14:07:18 +01:00
2022-05-06 17:18:24 +02:00
commandForCfg + = std : : string ( OUTPUT - > name ) + " , " ;
if ( ! head - > state . enabled ) {
commandForCfg + = " disabled " ;
if ( ! test )
2024-02-18 16:00:34 +01:00
g_pConfigManager - > parseKeyword ( " monitor " , commandForCfg ) ;
2022-05-06 17:18:24 +02:00
continue ;
2022-03-19 14:07:18 +01:00
}
2024-02-18 03:24:01 +01:00
const auto PMONITOR = g_pCompositor - > getRealMonitorFromOutput ( OUTPUT ) ;
RASSERT ( PMONITOR , " nullptr monitor in outputMgrApplyTest " ) ;
2024-01-28 02:57:13 +01:00
wlr_output_state_set_enabled ( PMONITOR - > state . wlr ( ) , head - > state . enabled ) ;
2022-05-06 17:18:24 +02:00
if ( head - > state . mode )
2022-12-16 18:17:31 +01:00
commandForCfg + =
std : : to_string ( head - > state . mode - > width ) + " x " + std : : to_string ( head - > state . mode - > height ) + " @ " + std : : to_string ( head - > state . mode - > refresh / 1000.f ) + " , " ;
2022-05-06 17:18:24 +02:00
else
2022-12-16 18:17:31 +01:00
commandForCfg + = std : : to_string ( head - > state . custom_mode . width ) + " x " + std : : to_string ( head - > state . custom_mode . height ) + " @ " +
std : : to_string ( head - > state . custom_mode . refresh / 1000.f ) + " , " ;
2022-05-06 17:18:24 +02:00
2023-09-10 14:14:27 +02:00
commandForCfg + = std : : to_string ( head - > state . x ) + " x " + std : : to_string ( head - > state . y ) + " , " + std : : to_string ( head - > state . scale ) + " ,transform, " +
std : : to_string ( ( int ) head - > state . transform ) ;
2022-05-06 17:18:24 +02:00
2022-11-03 10:06:44 +01:00
if ( ! test ) {
2024-02-18 16:00:34 +01:00
g_pConfigManager - > parseKeyword ( " monitor " , commandForCfg ) ;
2024-01-28 02:57:13 +01:00
wlr_output_state_set_adaptive_sync_enabled ( PMONITOR - > state . wlr ( ) , head - > state . adaptive_sync_enabled ) ;
2022-11-03 10:06:44 +01:00
}
2022-05-06 17:18:24 +02:00
2024-01-28 02:57:13 +01:00
ok = wlr_output_test_state ( OUTPUT , PMONITOR - > state . wlr ( ) ) ;
2022-03-19 14:07:18 +01:00
2023-09-10 14:14:27 +02:00
if ( ! ok )
2022-03-19 14:07:18 +01:00
break ;
}
2023-11-12 14:14:05 +01:00
if ( ! test ) {
2022-12-16 18:17:31 +01:00
g_pConfigManager - > m_bWantsMonitorReload = true ; // for monitor keywords
2023-11-12 14:14:05 +01:00
// if everything is disabled, performMonitorReload won't be called from renderMonitor
bool allDisabled = std : : all_of ( g_pCompositor - > m_vMonitors . begin ( ) , g_pCompositor - > m_vMonitors . end ( ) ,
[ ] ( const auto m ) { return ! m - > m_bEnabled | | g_pCompositor - > m_pUnsafeOutput = = m . get ( ) ; } ) ;
if ( allDisabled ) {
Debug : : log ( LOG , " OutputMgr apply: All monitors disabled; performing monitor reload. " ) ;
g_pConfigManager - > performMonitorReload ( ) ;
}
}
2022-03-19 14:07:18 +01:00
2023-09-10 14:14:27 +02:00
if ( ok )
2022-03-19 14:07:18 +01:00
wlr_output_configuration_v1_send_succeeded ( config ) ;
else
wlr_output_configuration_v1_send_failed ( config ) ;
2023-11-12 14:14:05 +01:00
2022-03-19 14:07:18 +01:00
wlr_output_configuration_v1_destroy ( config ) ;
Debug : : log ( LOG , " OutputMgr Applied/Tested. " ) ;
2022-03-19 14:37:40 +01:00
}
2022-03-21 17:00:17 +01:00
// taken from Sway.
// this is just too much of a spaghetti for me to understand
2023-12-19 12:55:56 +01:00
static void applyExclusive ( wlr_box & usableArea , uint32_t anchor , int32_t exclusive , 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 ;
2022-12-16 18:17:31 +01:00
int * positive_axis ;
int * negative_axis ;
int margin ;
2022-03-21 17:00:17 +01:00
} edges [ ] = {
// Top
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ,
2022-12-16 18:17:31 +01:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ,
2023-12-19 12:55:56 +01: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 18:17:31 +01:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
. positive_axis = NULL ,
2023-12-19 12:55:56 +01: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 18:17:31 +01:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
2023-12-19 12:55:56 +01: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 18:17:31 +01:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
. positive_axis = NULL ,
2023-12-19 12:55:56 +01: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 ) {
if ( ( anchor = = edges [ i ] . singular_anchor | | anchor = = edges [ i ] . anchor_triplet ) & & exclusive + edges [ i ] . margin > 0 ) {
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
2023-11-04 18:03:05 +01:00
void CHyprRenderer : : arrangeLayerArray ( CMonitor * pMonitor , const std : : vector < std : : unique_ptr < SLayerSurface > > & layerSurfaces , bool exclusiveZone , CBox * usableArea ) {
CBox full_area = { pMonitor - > vecPosition . x , pMonitor - > vecPosition . y , pMonitor - > vecSize . x , pMonitor - > vecSize . y } ;
2022-03-19 14:37:40 +01:00
2022-03-21 17:00:17 +01:00
for ( auto & ls : layerSurfaces ) {
2022-07-18 21:16:01 +02:00
if ( 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 ;
2023-10-06 15:00:05 +02:00
if ( exclusiveZone ! = ( PSTATE - > exclusive_zone > 0 ) )
2022-03-21 17:00:17 +01:00
continue ;
2022-03-19 14:37:40 +01:00
2023-11-04 18:03:05 +01:00
CBox bounds ;
2023-10-06 15:00:05 +02:00
if ( PSTATE - > exclusive_zone = = - 1 )
2022-03-21 17:00:17 +01:00
bounds = full_area ;
2023-10-06 15:00:05 +02:00
else
2022-03-21 17:00:17 +01:00
bounds = * usableArea ;
2022-03-19 14:37:40 +01:00
2023-10-06 15:00:05 +02:00
const Vector2D OLDSIZE = { ls - > geometry . width , ls - > geometry . height } ;
2023-11-04 18:03:05 +01:00
CBox box = { 0 , 0 , PSTATE - > desired_width , PSTATE - > desired_height } ;
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 ;
if ( box . width = = 0 ) {
box . x = bounds . x ;
} else if ( ( PSTATE - > anchor & both_horiz ) = = both_horiz ) {
box . x = bounds . x + ( ( bounds . width / 2 ) - ( box . width / 2 ) ) ;
} else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ) ) {
box . x = bounds . x ;
} else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ) ) {
box . x = bounds . x + ( bounds . width - box . width ) ;
} else {
box . x = bounds . x + ( ( bounds . width / 2 ) - ( box . width / 2 ) ) ;
2022-03-19 14:37:40 +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 ;
if ( box . height = = 0 ) {
box . y = bounds . y ;
} else if ( ( PSTATE - > anchor & both_vert ) = = both_vert ) {
box . y = bounds . y + ( ( bounds . height / 2 ) - ( box . height / 2 ) ) ;
} else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ) ) {
box . y = bounds . y ;
} else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ) ) {
box . y = bounds . y + ( bounds . height - box . height ) ;
} else {
box . y = bounds . y + ( ( bounds . height / 2 ) - ( box . height / 2 ) ) ;
2022-03-19 14:37:40 +01:00
}
2022-03-21 17:00:17 +01:00
// Margin
if ( box . width = = 0 ) {
box . x + = PSTATE - > margin . left ;
2022-12-16 18:17:31 +01:00
box . width = bounds . width - ( PSTATE - > margin . left + PSTATE - > margin . right ) ;
2022-03-21 17:00:17 +01:00
} else if ( ( PSTATE - > anchor & both_horiz ) = = both_horiz ) {
// don't apply margins
} else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ) ) {
box . x + = PSTATE - > margin . left ;
} else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ) ) {
box . x - = PSTATE - > margin . right ;
}
if ( box . height = = 0 ) {
box . y + = PSTATE - > margin . top ;
2022-12-16 18:17:31 +01:00
box . height = bounds . height - ( PSTATE - > margin . top + PSTATE - > margin . bottom ) ;
2022-03-21 17:00:17 +01:00
} else if ( ( PSTATE - > anchor & both_vert ) = = both_vert ) {
// don't apply margins
} else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ) ) {
box . y + = PSTATE - > margin . top ;
} else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ) ) {
box . y - = PSTATE - > margin . bottom ;
}
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
}
2022-03-21 17:00:17 +01:00
// Apply
ls - > geometry = box ;
2022-03-20 14:52:23 +01:00
2023-12-19 12:55:56 +01:00
applyExclusive ( * usableArea - > pWlr ( ) , PSTATE - > anchor , PSTATE - > exclusive_zone , PSTATE - > margin . top , PSTATE - > margin . right , PSTATE - > margin . bottom , PSTATE - > margin . left ) ;
2023-11-04 18:03:05 +01:00
usableArea - > applyFromWlr ( ) ;
2022-03-19 14:37:40 +01:00
2023-10-06 15:00:05 +02:00
if ( Vector2D { box . width , box . height } ! = OLDSIZE )
wlr_layer_surface_v1_configure ( ls - > layerSurface , box . width , box . height ) ;
2022-03-19 14:37:40 +01:00
}
}
void CHyprRenderer : : arrangeLayersForMonitor ( const int & monitor ) {
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( monitor ) ;
if ( ! PMONITOR )
return ;
// Reset the reserved
2022-12-16 18:17:31 +01:00
PMONITOR - > vecReservedBottomRight = Vector2D ( ) ;
PMONITOR - > vecReservedTopLeft = Vector2D ( ) ;
2022-03-19 14:37:40 +01:00
2023-11-04 18:03:05 +01:00
CBox usableArea = { PMONITOR - > vecPosition . x , PMONITOR - > vecPosition . y , PMONITOR - > vecSize . x , PMONITOR - > vecSize . y } ;
2022-03-21 17:00:17 +01:00
2023-01-22 17:03:25 +01:00
for ( auto & la : PMONITOR - > m_aLayerSurfaceLayers )
2022-03-21 17:00:17 +01:00
arrangeLayerArray ( PMONITOR , la , true , & usableArea ) ;
2023-01-22 17:03:25 +01:00
for ( auto & la : PMONITOR - > m_aLayerSurfaceLayers )
2022-03-21 17:00:17 +01:00
arrangeLayerArray ( PMONITOR , la , false , & usableArea ) ;
2022-12-16 18:17:31 +01: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-18 00:23:01 +02:00
auto ADDITIONALRESERVED = g_pConfigManager - > m_mAdditionalReservedAreas . find ( PMONITOR - > szName ) ;
if ( ADDITIONALRESERVED = = g_pConfigManager - > m_mAdditionalReservedAreas . end ( ) ) {
2022-12-16 18:17:31 +01:00
ADDITIONALRESERVED = g_pConfigManager - > m_mAdditionalReservedAreas . find ( " " ) ; // glob wildcard
2022-10-18 00:23:01 +02:00
}
if ( ADDITIONALRESERVED ! = g_pConfigManager - > m_mAdditionalReservedAreas . end ( ) ) {
2022-12-16 18:17:31 +01:00
PMONITOR - > vecReservedTopLeft = PMONITOR - > vecReservedTopLeft + Vector2D ( ADDITIONALRESERVED - > second . left , ADDITIONALRESERVED - > second . top ) ;
2022-10-18 00:23:01 +02: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 13:18:40 +02: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
}
2023-06-11 21:52:13 +02:00
void CHyprRenderer : : damageSurface ( wlr_surface * 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 ;
2023-10-20 21:15:41 +02:00
auto * const PSURFACE = CWLSurface : : surfaceFromWlr ( pSurface ) ;
if ( PSURFACE & & PSURFACE - > m_pOwner & & PSURFACE - > small ( ) ) {
const auto CORRECTION = PSURFACE - > correctSmallVec ( ) ;
x + = CORRECTION . x ;
y + = CORRECTION . y ;
}
2024-02-19 12:34:55 +01:00
const auto WLSURF = CWLSurface : : surfaceFromWlr ( pSurface ) ;
CRegion damageBox = WLSURF ? WLSURF - > logicalDamage ( ) : CRegion { } ;
if ( ! WLSURF ) {
2024-02-19 12:24:54 +01:00
Debug : : log ( ERR , " BUG THIS: No CWLSurface for surface in damageSurface!!! " ) ;
2024-02-19 12:34:55 +01:00
wlr_surface_get_effective_damage ( pSurface , damageBox . pixman ( ) ) ;
}
2023-06-11 21:52:13 +02:00
if ( scale ! = 1.0 )
2024-02-19 12:24:54 +01:00
damageBox . scale ( scale ) ;
2022-03-21 16:13:43 +01:00
2022-07-04 17:55:33 +02:00
// schedule frame events
2024-02-19 12:24:54 +01:00
if ( ! wl_list_empty ( & pSurface - > current . frame_callback_list ) )
2022-07-13 18:18:23 +02:00
g_pCompositor - > scheduleFrameForMonitor ( g_pCompositor - > getMonitorFromVector ( Vector2D ( x , y ) ) ) ;
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 12:24:54 +01:00
damageBox . translate ( { x , y } ) ;
2023-07-19 20:09:49 +02:00
CRegion damageBoxForEach ;
2022-07-28 22:15:56 +02:00
2022-06-30 15:44:26 +02:00
for ( auto & m : g_pCompositor - > m_vMonitors ) {
2023-03-16 17:32:03 +01:00
if ( ! m - > output )
continue ;
2024-02-19 12:24:54 +01: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-02-18 16:00:34 +01:00
static auto * const PLOGDAMAGE = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-02-18 16:00:34 +01: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
2022-04-14 16:43:29 +02:00
void CHyprRenderer : : damageWindow ( CWindow * pWindow ) {
2022-08-10 23:14:53 +02:00
if ( g_pCompositor - > m_bUnsafeState )
return ;
2023-11-04 18:03:05 +01:00
CBox damageBox = pWindow - > getFullWindowBoundingBox ( ) ;
2022-06-30 15:44:26 +02:00
for ( auto & m : g_pCompositor - > m_vMonitors ) {
2023-11-04 18:03:05 +01:00
CBox fixedDamageBox = { damageBox . x - m - > vecPosition . x , damageBox . y - m - > vecPosition . y , damageBox . width , damageBox . height } ;
fixedDamageBox . scale ( m - > scale ) ;
2022-08-23 16:07:47 +02:00
m - > addDamage ( & fixedDamageBox ) ;
2022-06-29 11:21:42 +02:00
}
2022-05-05 15:09:26 +02:00
2023-06-27 13:23:53 +02:00
for ( auto & wd : pWindow - > m_dWindowDecorations )
wd - > damageEntire ( ) ;
2024-02-18 16:00:34 +01:00
static auto * const PLOGDAMAGE = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-02-18 16:00:34 +01:00
if ( * * PLOGDAMAGE )
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Damage: Window ({}): xy: {}, {} wh: {}, {} " , pWindow - > m_szTitle , damageBox . x , damageBox . y , damageBox . width , damageBox . height ) ;
2022-03-21 16:13:43 +01:00
}
2022-07-27 12:32:00 +02:00
void CHyprRenderer : : damageMonitor ( CMonitor * 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 18:03:05 +01: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-02-18 16:00:34 +01:00
static auto * const PLOGDAMAGE = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-02-18 16:00:34 +01: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
2023-11-04 18:03:05 +01:00
void CHyprRenderer : : damageBox ( CBox * pBox ) {
2022-08-10 23:14:53 +02:00
if ( g_pCompositor - > m_bUnsafeState )
return ;
2022-06-30 15:44:26 +02:00
for ( auto & m : g_pCompositor - > m_vMonitors ) {
2022-09-13 15:25:42 +02:00
if ( m - > isMirror ( ) )
continue ; // don't damage mirrors traditionally
2023-11-04 18:03:05 +01:00
CBox damageBox = { pBox - > x - m - > vecPosition . x , pBox - > y - m - > vecPosition . y , pBox - > width , pBox - > height } ;
damageBox . scale ( m - > scale ) ;
2022-08-23 16:07:47 +02:00
m - > addDamage ( & damageBox ) ;
2022-04-17 18:47:10 +02:00
}
2022-05-05 15:09:26 +02:00
2024-02-18 16:00:34 +01:00
static auto * const PLOGDAMAGE = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-02-18 16:00:34 +01: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 18:03:05 +01: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 ) {
for ( auto & RECT : rg . getRects ( ) ) {
2022-07-16 12:44:45 +02:00
damageBox ( RECT . x1 , RECT . y1 , RECT . x2 - RECT . x1 , RECT . y2 - RECT . y1 ) ;
}
}
2023-07-19 20:09:49 +02:00
void CHyprRenderer : : damageMirrorsWith ( CMonitor * pMonitor , const CRegion & pRegion ) {
2022-09-13 15:25:42 +02:00
for ( auto & mirror : pMonitor - > mirrors ) {
2023-07-19 20:09:49 +02:00
Vector2D scale = { mirror - > vecSize . x / pMonitor - > vecSize . x , mirror - > vecSize . y / pMonitor - > vecSize . y } ;
2022-09-13 15:25:42 +02:00
2023-07-19 20:09:49 +02:00
CRegion rg { pRegion } ;
wlr_region_scale_xy ( rg . pixman ( ) , rg . pixman ( ) , scale . x , scale . y ) ;
2022-09-13 15:25:42 +02:00
pMonitor - > addDamage ( & rg ) ;
2023-03-04 01:48:02 +01:00
g_pCompositor - > scheduleFrameForMonitor ( mirror ) ;
2022-09-13 15:25:42 +02:00
}
}
2022-07-27 12:32:00 +02:00
void CHyprRenderer : : renderDragIcon ( CMonitor * pMonitor , timespec * time ) {
2022-03-31 17:25:23 +02:00
if ( ! ( g_pInputManager - > m_sDrag . dragIcon & & g_pInputManager - > m_sDrag . iconMapped & & g_pInputManager - > m_sDrag . dragIcon - > surface ) )
return ;
2023-01-20 19:44:30 +01:00
SRenderData renderdata = { pMonitor , time , g_pInputManager - > m_sDrag . pos . x , g_pInputManager - > m_sDrag . pos . y } ;
2022-12-16 18:17:31 +01:00
renderdata . surface = g_pInputManager - > m_sDrag . dragIcon - > surface ;
renderdata . w = g_pInputManager - > m_sDrag . dragIcon - > surface - > current . width ;
renderdata . h = g_pInputManager - > m_sDrag . dragIcon - > surface - > current . height ;
2022-03-31 17:25:23 +02:00
wlr_surface_for_each_surface ( g_pInputManager - > m_sDrag . dragIcon - > surface , renderSurface , & renderdata ) ;
2022-06-29 14:15:08 +02:00
2023-11-04 18:03:05 +01:00
CBox box = { g_pInputManager - > m_sDrag . pos . x - 2 , g_pInputManager - > m_sDrag . pos . y - 2 , g_pInputManager - > m_sDrag . dragIcon - > surface - > current . width + 4 ,
g_pInputManager - > m_sDrag . dragIcon - > surface - > current . height + 4 } ;
2022-06-29 14:15:08 +02:00
g_pHyprRenderer - > damageBox ( & box ) ;
2022-04-14 16:43:29 +02:00
}
DAMAGETRACKINGMODES CHyprRenderer : : damageTrackingModeFromStr ( const std : : string & mode ) {
if ( mode = = " full " )
return DAMAGE_TRACKING_FULL ;
if ( mode = = " monitor " )
return DAMAGE_TRACKING_MONITOR ;
if ( mode = = " none " )
return DAMAGE_TRACKING_NONE ;
return DAMAGE_TRACKING_INVALID ;
2022-04-19 19:01:23 +02:00
}
2022-07-27 12:32:00 +02:00
bool CHyprRenderer : : applyMonitorRule ( CMonitor * pMonitor , SMonitorRule * pMonitorRule , bool force ) {
2022-04-19 19:01:23 +02:00
2024-02-18 16:00:34 +01:00
static auto * const PDISABLESCALECHECKS = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:disable_scale_checks " ) ;
2023-12-23 00:21:02 +01:00
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Applying monitor rule for {} " , pMonitor - > szName ) ;
2022-04-21 18:11:28 +02:00
2023-08-11 17:37:52 +02:00
pMonitor - > activeMonitorRule = * pMonitorRule ;
2024-02-14 23:05:36 +01:00
if ( pMonitor - > forceSize . has_value ( ) )
pMonitor - > activeMonitorRule . resolution = pMonitor - > forceSize . value ( ) ;
const auto RULE = & pMonitor - > activeMonitorRule ;
2022-06-30 23:50:57 +02:00
// if it's disabled, disable and ignore
2024-02-14 23:05:36 +01:00
if ( RULE - > disabled ) {
2022-07-27 12:32:00 +02:00
if ( pMonitor - > m_bEnabled )
pMonitor - > onDisconnect ( ) ;
2022-08-03 17:32:12 +02:00
return true ;
2022-06-30 23:50:57 +02:00
}
2023-02-15 15:50:51 +01:00
// don't touch VR headsets
if ( pMonitor - > output - > non_desktop )
return true ;
2022-07-27 12:32:00 +02:00
if ( ! pMonitor - > m_bEnabled ) {
pMonitor - > onConnect ( true ) ; // enable it.
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Monitor {} is disabled but is requested to be enabled " , pMonitor - > szName ) ;
2022-07-27 12:32:00 +02:00
force = true ;
}
2022-04-19 19:01:23 +02:00
// Check if the rule isn't already applied
2023-08-11 17:37:52 +02:00
// TODO: clean this up lol
2024-02-14 23:05:36 +01:00
if ( ! force & & DELTALESSTHAN ( pMonitor - > vecPixelSize . x , RULE - > resolution . x , 1 ) & & DELTALESSTHAN ( pMonitor - > vecPixelSize . y , RULE - > resolution . y , 1 ) & &
DELTALESSTHAN ( pMonitor - > refreshRate , RULE - > refreshRate , 1 ) & & pMonitor - > setScale = = RULE - > scale & &
( ( DELTALESSTHAN ( pMonitor - > vecPosition . x , RULE - > offset . x , 1 ) & & DELTALESSTHAN ( pMonitor - > vecPosition . y , RULE - > offset . y , 1 ) ) | |
RULE - > offset = = Vector2D ( - INT32_MAX , - INT32_MAX ) ) & &
pMonitor - > transform = = RULE - > transform & & RULE - > enable10bit = = pMonitor - > enabled10bit & &
! memcmp ( & pMonitor - > customDrmMode , & RULE - > drmMode , sizeof ( pMonitor - > customDrmMode ) ) ) {
2022-08-04 11:10:26 +02:00
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Not applying a new rule to {} because it's already applied! " , pMonitor - > szName ) ;
2022-06-30 23:55:28 +02:00
return true ;
2022-04-19 19:01:23 +02:00
}
2024-02-02 16:36:13 +01:00
const auto WAS10B = pMonitor - > enabled10bit ;
const auto OLDRES = pMonitor - > vecPixelSize ;
2023-05-09 15:01:45 +02:00
// Needed in case we are switching from a custom modeline to a standard mode
pMonitor - > customDrmMode = { } ;
2023-12-31 13:54:24 +01:00
bool autoScale = false ;
2023-05-09 15:01:45 +02:00
2024-02-14 23:05:36 +01:00
if ( RULE - > scale > 0.1 ) {
pMonitor - > scale = RULE - > scale ;
2022-12-14 18:57:18 +01:00
} else {
2023-12-31 13:54:24 +01:00
autoScale = true ;
2022-12-14 18:57:18 +01:00
const auto DEFAULTSCALE = pMonitor - > getDefaultScale ( ) ;
2023-12-22 23:00:36 +01:00
pMonitor - > scale = DEFAULTSCALE ;
2022-12-14 18:57:18 +01:00
}
2022-04-19 19:01:23 +02:00
2024-01-28 02:57:13 +01:00
wlr_output_state_set_scale ( pMonitor - > state . wlr ( ) , pMonitor - > scale ) ;
2023-12-22 19:54:05 +01:00
pMonitor - > setScale = pMonitor - > scale ;
2024-02-14 23:05:36 +01:00
wlr_output_state_set_transform ( pMonitor - > state . wlr ( ) , RULE - > transform ) ;
pMonitor - > transform = RULE - > transform ;
2022-11-18 15:15:19 +01:00
2024-02-14 23:05:36 +01:00
const auto WLRREFRESHRATE = ( wlr_backend_is_wl ( pMonitor - > output - > backend ) | | wlr_backend_is_x11 ( pMonitor - > output - > backend ) ) ? 0 : RULE - > refreshRate * 1000 ;
2023-07-19 00:26:04 +02:00
2022-04-19 19:01:23 +02:00
// loop over modes and choose an appropriate one.
2024-02-14 23:05:36 +01:00
if ( RULE - > resolution ! = Vector2D ( ) & & RULE - > resolution ! = Vector2D ( - 1 , - 1 ) & & RULE - > resolution ! = Vector2D ( - 1 , - 2 ) ) {
if ( ! wl_list_empty ( & pMonitor - > output - > modes ) & & RULE - > drmMode . type ! = DRM_MODE_TYPE_USERDEF ) {
2022-07-30 22:54:29 +02:00
wlr_output_mode * mode ;
2022-12-16 18:17:31 +01:00
bool found = false ;
2022-07-30 22:54:29 +02:00
wl_list_for_each ( mode , & pMonitor - > output - > modes , link ) {
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it
2024-02-14 23:05:36 +01:00
if ( DELTALESSTHAN ( mode - > width , RULE - > resolution . x , 1 ) & & DELTALESSTHAN ( mode - > height , RULE - > resolution . y , 1 ) & &
DELTALESSTHAN ( mode - > refresh / 1000.f , RULE - > refreshRate , 1 ) ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , mode ) ;
2022-07-30 22:54:29 +02:00
2024-01-28 02:57:13 +01:00
if ( ! wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) ) {
2023-09-20 17:25:03 +02:00
Debug : : log ( LOG , " Monitor {}: REJECTED available mode: {}x{}@{:2f}! " , pMonitor - > output - > name , mode - > width , mode - > height , mode - > refresh / 1000.f ) ;
2022-07-30 22:54:29 +02:00
continue ;
}
2024-02-14 23:05:36 +01:00
Debug : : log ( LOG , " Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying. " , pMonitor - > output - > name , RULE - > resolution ,
( float ) RULE - > refreshRate , mode - > width , mode - > height , mode - > refresh ) ;
2022-04-19 19:01:23 +02:00
2022-07-30 22:54:29 +02:00
found = true ;
2022-04-19 19:01:23 +02:00
2022-07-30 22:54:29 +02:00
pMonitor - > refreshRate = mode - > refresh / 1000.f ;
2022-12-16 18:17:31 +01:00
pMonitor - > vecSize = Vector2D ( mode - > width , mode - > height ) ;
2022-04-19 19:01:23 +02:00
2022-07-30 22:54:29 +02:00
break ;
}
2022-04-19 19:01:23 +02:00
}
2022-07-30 22:54:29 +02:00
if ( ! found ) {
2024-02-14 23:05:36 +01:00
wlr_output_state_set_custom_mode ( pMonitor - > state . wlr ( ) , ( int ) RULE - > resolution . x , ( int ) RULE - > resolution . y , WLRREFRESHRATE ) ;
pMonitor - > vecSize = RULE - > resolution ;
pMonitor - > refreshRate = RULE - > refreshRate ;
2022-04-19 19:01:23 +02:00
2024-01-28 02:57:13 +01:00
if ( ! wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) ) {
2022-07-30 22:54:29 +02:00
Debug : : log ( ERR , " Custom resolution FAILED, falling back to preferred " ) ;
2022-06-28 11:12:01 +02:00
2022-07-30 22:54:29 +02:00
const auto PREFERREDMODE = wlr_output_preferred_mode ( pMonitor - > output ) ;
2022-06-28 11:12:01 +02:00
2022-07-30 22:54:29 +02:00
if ( ! PREFERREDMODE ) {
2024-02-14 23:05:36 +01:00
Debug : : log ( ERR , " Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f} " , pMonitor - > ID , RULE - > resolution ,
( float ) RULE - > refreshRate ) ;
2022-07-30 22:54:29 +02:00
return true ;
}
2022-04-19 19:01:23 +02:00
2022-07-30 22:54:29 +02:00
// Preferred is valid
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , PREFERREDMODE ) ;
2022-04-19 19:01:23 +02:00
2024-02-14 23:05:36 +01:00
Debug : : log ( ERR , " Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
( float ) RULE - > refreshRate , PREFERREDMODE - > width , PREFERREDMODE - > height , PREFERREDMODE - > refresh / 1000.f ) ;
2022-04-19 19:01:23 +02:00
2022-07-30 22:54:29 +02:00
pMonitor - > refreshRate = PREFERREDMODE - > refresh / 1000.f ;
2022-12-16 18:17:31 +01:00
pMonitor - > vecSize = Vector2D ( PREFERREDMODE - > width , PREFERREDMODE - > height ) ;
2022-07-30 22:54:29 +02:00
} else {
2024-02-14 23:05:36 +01:00
Debug : : log ( LOG , " Set a custom mode {:X0}@{:2f} (mode not found in monitor modes) " , RULE - > resolution , ( float ) RULE - > refreshRate ) ;
2022-07-30 22:54:29 +02:00
}
2022-06-28 11:12:01 +02:00
}
2022-09-24 14:10:11 +02:00
} else {
2023-05-09 15:01:45 +02:00
// custom resolution
bool fail = false ;
2024-02-14 23:05:36 +01:00
if ( RULE - > drmMode . type = = DRM_MODE_TYPE_USERDEF ) {
2023-05-09 15:01:45 +02:00
if ( ! wlr_output_is_drm ( pMonitor - > output ) ) {
Debug : : log ( ERR , " Tried to set custom modeline on non-DRM output " ) ;
fail = true ;
} else {
2024-02-14 23:05:36 +01:00
auto * mode = wlr_drm_connector_add_mode ( pMonitor - > output , & RULE - > drmMode ) ;
2023-05-09 15:01:45 +02:00
if ( mode ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , mode ) ;
2024-02-14 23:05:36 +01:00
pMonitor - > customDrmMode = RULE - > drmMode ;
2023-05-09 15:01:45 +02:00
} else {
Debug : : log ( ERR , " wlr_drm_connector_add_mode failed " ) ;
fail = true ;
}
}
} else {
2024-02-14 23:05:36 +01:00
wlr_output_state_set_custom_mode ( pMonitor - > state . wlr ( ) , ( int ) RULE - > resolution . x , ( int ) RULE - > resolution . y , WLRREFRESHRATE ) ;
2023-05-09 15:01:45 +02:00
}
2024-02-14 23:05:36 +01:00
pMonitor - > vecSize = RULE - > resolution ;
pMonitor - > refreshRate = RULE - > refreshRate ;
2022-09-24 14:10:11 +02:00
2024-01-28 02:57:13 +01:00
if ( fail | | ! wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) ) {
2022-09-24 14:10:11 +02:00
Debug : : log ( ERR , " Custom resolution FAILED, falling back to preferred " ) ;
const auto PREFERREDMODE = wlr_output_preferred_mode ( pMonitor - > output ) ;
if ( ! PREFERREDMODE ) {
2024-02-14 23:05:36 +01:00
Debug : : log ( ERR , " Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
( float ) RULE - > refreshRate ) ;
2022-09-24 14:10:11 +02:00
return true ;
}
// Preferred is valid
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , PREFERREDMODE ) ;
2022-09-24 14:10:11 +02:00
2024-02-14 23:05:36 +01:00
Debug : : log ( ERR , " Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
( float ) RULE - > refreshRate , PREFERREDMODE - > width , PREFERREDMODE - > height , PREFERREDMODE - > refresh / 1000.f ) ;
2022-09-24 14:10:11 +02:00
2023-05-09 15:01:45 +02:00
pMonitor - > refreshRate = PREFERREDMODE - > refresh / 1000.f ;
pMonitor - > vecSize = Vector2D ( PREFERREDMODE - > width , PREFERREDMODE - > height ) ;
pMonitor - > customDrmMode = { } ;
2022-09-24 14:10:11 +02:00
} else {
2024-02-14 23:05:36 +01:00
Debug : : log ( LOG , " Set a custom mode {:X0}@{:2f} (mode not found in monitor modes) " , RULE - > resolution , ( float ) RULE - > refreshRate ) ;
2022-09-24 14:10:11 +02:00
}
2022-09-22 00:45:56 +02:00
}
2024-02-14 23:05:36 +01:00
} else if ( RULE - > resolution ! = Vector2D ( ) ) {
2022-09-22 00:45:56 +02:00
if ( ! wl_list_empty ( & pMonitor - > output - > modes ) ) {
wlr_output_mode * mode ;
2022-12-16 18:17:31 +01:00
float currentWidth = 0 ;
float currentHeight = 0 ;
float currentRefresh = 0 ;
bool success = false ;
2022-09-22 00:45:56 +02:00
2022-09-25 20:07:48 +02:00
//(-1,-1) indicates a preference to refreshrate over resolution, (-1,-2) preference to resolution
2024-02-14 23:05:36 +01:00
if ( RULE - > resolution = = Vector2D ( - 1 , - 1 ) ) {
2022-09-22 00:45:56 +02:00
wl_list_for_each ( mode , & pMonitor - > output - > modes , link ) {
2022-12-16 18:17:31 +01:00
if ( ( mode - > width > = currentWidth & & mode - > height > = currentHeight & & mode - > refresh > = ( currentRefresh - 1000.f ) ) | | mode - > refresh > ( currentRefresh + 3000.f ) ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , mode ) ;
if ( wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) ) {
2022-12-16 18:17:31 +01:00
currentWidth = mode - > width ;
currentHeight = mode - > height ;
currentRefresh = mode - > refresh ;
success = true ;
}
}
2022-09-22 00:45:56 +02:00
}
} else {
wl_list_for_each ( mode , & pMonitor - > output - > modes , link ) {
2022-12-16 18:17:31 +01:00
if ( ( mode - > width > = currentWidth & & mode - > height > = currentHeight & & mode - > refresh > = ( currentRefresh - 1000.f ) ) | |
( mode - > width > currentWidth & & mode - > height > currentHeight ) ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , mode ) ;
if ( wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) ) {
2022-12-16 18:17:31 +01:00
currentWidth = mode - > width ;
currentHeight = mode - > height ;
currentRefresh = mode - > refresh ;
success = true ;
}
}
2022-09-21 22:29:52 +02:00
}
2022-09-22 00:45:56 +02:00
}
2022-08-07 19:28:31 +02:00
2022-09-22 00:45:56 +02:00
if ( ! success ) {
2024-02-14 23:05:36 +01:00
Debug : : log ( LOG , " Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
( float ) RULE - > refreshRate , mode - > width , mode - > height , mode - > refresh / 1000.f ) ;
2022-09-25 20:07:48 +02:00
2022-09-22 00:45:56 +02:00
const auto PREFERREDMODE = wlr_output_preferred_mode ( pMonitor - > output ) ;
2022-09-21 22:29:52 +02:00
2022-09-22 00:45:56 +02:00
if ( ! PREFERREDMODE ) {
2024-02-14 23:05:36 +01:00
Debug : : log ( ERR , " Monitor {} has NO PREFERRED MODE, and an INVALID one was requested: {:X0}@{:2f} " , pMonitor - > ID , RULE - > resolution , ( float ) RULE - > refreshRate ) ;
2022-09-22 00:45:56 +02:00
return true ;
}
2022-09-21 22:29:52 +02:00
2022-09-22 00:45:56 +02:00
// Preferred is valid
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , PREFERREDMODE ) ;
2022-09-21 22:29:52 +02:00
2024-02-14 23:05:36 +01:00
Debug : : log ( ERR , " Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
( float ) RULE - > refreshRate , PREFERREDMODE - > width , PREFERREDMODE - > height , PREFERREDMODE - > refresh / 1000.f ) ;
2022-09-21 22:29:52 +02:00
2022-09-22 00:45:56 +02:00
pMonitor - > refreshRate = PREFERREDMODE - > refresh / 1000.f ;
2022-12-16 18:17:31 +01:00
pMonitor - > vecSize = Vector2D ( PREFERREDMODE - > width , PREFERREDMODE - > height ) ;
2022-09-22 00:45:56 +02:00
} else {
2022-09-21 22:29:52 +02:00
2023-09-20 17:25:03 +02:00
Debug : : log ( LOG , " Monitor {}: Applying highest mode {}x{}@{:2f}. " , pMonitor - > output - > name , ( int ) currentWidth , ( int ) currentHeight , ( int ) currentRefresh / 1000.f ) ;
2022-09-21 22:29:52 +02:00
2022-09-22 00:45:56 +02:00
pMonitor - > refreshRate = currentRefresh / 1000.f ;
2022-12-16 18:17:31 +01:00
pMonitor - > vecSize = Vector2D ( currentWidth , currentHeight ) ;
2022-09-21 22:29:52 +02:00
}
2022-09-22 00:45:56 +02:00
}
} else {
2022-07-30 22:54:29 +02:00
const auto PREFERREDMODE = wlr_output_preferred_mode ( pMonitor - > output ) ;
if ( ! PREFERREDMODE ) {
2023-09-20 17:25:03 +02:00
Debug : : log ( ERR , " Monitor {} has NO PREFERRED MODE " , pMonitor - > output - > name ) ;
2022-07-30 22:54:29 +02:00
2022-08-02 22:20:45 +02:00
if ( ! wl_list_empty ( & pMonitor - > output - > modes ) ) {
wlr_output_mode * mode ;
wl_list_for_each ( mode , & pMonitor - > output - > modes , link ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , mode ) ;
2022-08-02 22:20:45 +02:00
2024-01-28 02:57:13 +01:00
if ( ! wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) ) {
2023-09-20 17:25:03 +02:00
Debug : : log ( LOG , " Monitor {}: REJECTED available mode: {}x{}@{:2f}! " , pMonitor - > output - > name , mode - > width , mode - > height , mode - > refresh / 1000.f ) ;
2022-08-02 22:20:45 +02:00
continue ;
}
2024-02-14 23:05:36 +01:00
Debug : : log ( LOG , " Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying. " , pMonitor - > output - > name , RULE - > resolution ,
( float ) RULE - > refreshRate , mode - > width , mode - > height , mode - > refresh ) ;
2022-08-02 22:20:45 +02:00
pMonitor - > refreshRate = mode - > refresh / 1000.f ;
2022-12-16 18:17:31 +01:00
pMonitor - > vecSize = Vector2D ( mode - > width , mode - > height ) ;
2022-08-02 22:20:45 +02:00
break ;
}
}
} else {
// Preferred is valid
2024-01-28 02:57:13 +01:00
wlr_output_state_set_mode ( pMonitor - > state . wlr ( ) , PREFERREDMODE ) ;
2022-08-02 22:20:45 +02:00
2022-12-16 18:17:31 +01:00
pMonitor - > vecSize = Vector2D ( PREFERREDMODE - > width , PREFERREDMODE - > height ) ;
2022-08-02 22:20:45 +02:00
pMonitor - > refreshRate = PREFERREDMODE - > refresh / 1000.f ;
2022-08-07 19:28:31 +02:00
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " Setting preferred mode for {} " , pMonitor - > output - > name ) ;
2022-08-02 22:20:45 +02:00
}
2022-04-19 19:01:23 +02:00
}
2022-09-25 20:07:48 +02:00
2024-01-28 02:57:13 +01:00
pMonitor - > vrrActive = pMonitor - > state . wlr ( ) - > adaptive_sync_enabled // disabled here, will be tested in CConfigManager::ensureVRR()
| | pMonitor - > createdByUser ; // wayland backend doesn't allow for disabling adaptive_sync
2022-04-19 19:01:23 +02:00
2022-05-18 20:33:54 +02:00
pMonitor - > vecPixelSize = pMonitor - > vecSize ;
2023-12-22 19:54:05 +01:00
Vector2D logicalSize = pMonitor - > vecPixelSize / pMonitor - > scale ;
2024-02-18 16:00:34 +01:00
if ( ! * * PDISABLESCALECHECKS & & ( logicalSize . x ! = std : : round ( logicalSize . x ) | | logicalSize . y ! = std : : round ( logicalSize . y ) ) ) {
2023-12-22 19:54:05 +01:00
// invalid scale, will produce fractional pixels.
// find the nearest valid.
2023-12-27 23:46:56 +01:00
float searchScale = std : : round ( pMonitor - > scale * 120.0 ) ;
2023-12-23 00:09:55 +01:00
bool found = false ;
2023-12-22 19:54:05 +01:00
2023-12-27 23:46:56 +01:00
double scaleZero = searchScale / 120.0 ;
2023-12-22 19:54:05 +01:00
2023-12-23 00:09:55 +01:00
Vector2D logicalZero = pMonitor - > vecPixelSize / scaleZero ;
if ( logicalZero = = logicalZero . round ( ) ) {
pMonitor - > scale = scaleZero ;
2024-01-28 02:57:13 +01:00
wlr_output_state_set_scale ( pMonitor - > state . wlr ( ) , pMonitor - > scale ) ;
2023-12-23 00:09:55 +01:00
} else {
for ( size_t i = 1 ; i < 90 ; + + i ) {
2023-12-27 23:46:56 +01:00
double scaleUp = ( searchScale + i ) / 120.0 ;
double scaleDown = ( searchScale - i ) / 120.0 ;
2023-12-23 00:09:55 +01:00
Vector2D logicalUp = pMonitor - > vecPixelSize / scaleUp ;
Vector2D logicalDown = pMonitor - > vecPixelSize / scaleDown ;
2023-12-22 19:54:05 +01:00
2023-12-23 00:09:55 +01:00
if ( logicalUp = = logicalUp . round ( ) ) {
found = true ;
searchScale = scaleUp ;
break ;
}
if ( logicalDown = = logicalDown . round ( ) ) {
found = true ;
searchScale = scaleDown ;
break ;
}
2023-12-22 19:54:05 +01:00
}
2023-12-23 00:09:55 +01:00
if ( ! found ) {
2023-12-31 13:54:24 +01:00
if ( autoScale )
pMonitor - > scale = std : : round ( scaleZero ) ;
else {
Debug : : log ( ERR , " Invalid scale passed to monitor, {} failed to find a clean divisor " , pMonitor - > scale ) ;
g_pConfigManager - > addParseError ( " Invalid scale passed to monitor " + pMonitor - > szName + " , failed to find a clean divisor " ) ;
pMonitor - > scale = pMonitor - > getDefaultScale ( ) ;
}
2023-12-23 00:09:55 +01:00
} else {
2023-12-31 13:54:24 +01:00
if ( ! autoScale ) {
Debug : : log ( ERR , " Invalid scale passed to monitor, {} found suggestion {} " , pMonitor - > scale , searchScale ) ;
g_pConfigManager - > addParseError (
std : : format ( " Invalid scale passed to monitor {}, failed to find a clean divisor. Suggested nearest scale: {:5f} " , pMonitor - > szName , searchScale ) ) ;
pMonitor - > scale = pMonitor - > getDefaultScale ( ) ;
} else
pMonitor - > scale = searchScale ;
2023-12-22 19:54:05 +01:00
}
2024-01-11 13:15:20 +01:00
// for wlroots, that likes flooring, we have to do this.
double logicalX = std : : round ( pMonitor - > vecPixelSize . x / pMonitor - > scale ) ;
logicalX + = 0.1 ;
2024-01-28 02:57:13 +01:00
wlr_output_state_set_scale ( pMonitor - > state . wlr ( ) , pMonitor - > vecPixelSize . x / logicalX ) ;
2023-12-22 19:54:05 +01:00
}
}
2023-09-22 21:15:06 +02:00
// clang-format off
static const std : : array < std : : vector < std : : pair < std : : string , uint32_t > > , 2 > formats {
std : : vector < std : : pair < std : : string , uint32_t > > { /* 10-bit */
{ " DRM_FORMAT_XRGB2101010 " , DRM_FORMAT_XRGB2101010 } , { " DRM_FORMAT_XBGR2101010 " , DRM_FORMAT_XBGR2101010 } , { " DRM_FORMAT_XRGB8888 " , DRM_FORMAT_XRGB8888 } , { " DRM_FORMAT_XBGR8888 " , DRM_FORMAT_XBGR8888 } , { " DRM_FORMAT_INVALID " , DRM_FORMAT_INVALID }
} ,
std : : vector < std : : pair < std : : string , uint32_t > > { /* 8-bit */
{ " DRM_FORMAT_XRGB8888 " , DRM_FORMAT_XRGB8888 } , { " DRM_FORMAT_XBGR8888 " , DRM_FORMAT_XBGR8888 } , { " DRM_FORMAT_INVALID " , DRM_FORMAT_INVALID }
}
} ;
// clang-format on
2022-10-27 14:26:47 +02:00
2023-10-30 16:56:02 +01:00
bool set10bit = false ;
pMonitor - > drmFormat = DRM_FORMAT_INVALID ;
2022-10-27 14:26:47 +02:00
2024-02-14 23:05:36 +01:00
for ( auto & fmt : formats [ ( int ) ! RULE - > enable10bit ] ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_render_format ( pMonitor - > state . wlr ( ) , fmt . second ) ;
2022-10-27 14:26:47 +02:00
2024-01-28 02:57:13 +01:00
if ( ! wlr_output_test_state ( pMonitor - > output , pMonitor - > state . wlr ( ) ) ) {
2023-09-22 21:15:06 +02:00
Debug : : log ( ERR , " output {} failed basic test on format {} " , pMonitor - > szName , fmt . first ) ;
2022-10-27 14:26:47 +02:00
} else {
2023-09-22 21:15:06 +02:00
Debug : : log ( LOG , " output {} succeeded basic test on format {} " , pMonitor - > szName , fmt . first ) ;
2024-02-14 23:05:36 +01:00
if ( RULE - > enable10bit & & fmt . first . contains ( " 101010 " ) )
2023-09-22 21:15:06 +02:00
set10bit = true ;
2023-10-30 16:56:02 +01:00
pMonitor - > drmFormat = fmt . second ;
2023-09-22 21:15:06 +02:00
break ;
2022-10-27 14:26:47 +02:00
}
}
2023-09-22 21:15:06 +02:00
pMonitor - > enabled10bit = set10bit ;
2024-01-28 02:57:13 +01:00
if ( ! pMonitor - > state . commit ( ) )
2023-09-06 12:51:36 +02:00
Debug : : log ( ERR , " Couldn't commit output named {} " , pMonitor - > output - > name ) ;
2024-01-27 20:11:03 +01:00
2022-05-29 12:27:45 +02:00
int x , y ;
wlr_output_transformed_resolution ( pMonitor - > output , & x , & y ) ;
2022-12-16 18:17:31 +01:00
pMonitor - > vecSize = ( Vector2D ( x , y ) / pMonitor - > scale ) . floor ( ) ;
pMonitor - > vecTransformedSize = Vector2D ( x , y ) ;
2022-05-29 12:27:45 +02:00
2022-11-05 19:04:44 +01:00
if ( pMonitor - > createdByUser ) {
2023-11-04 18:03:05 +01:00
CBox transformedBox = { 0 , 0 , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y } ;
transformedBox . transform ( wlr_output_transform_invert ( pMonitor - > output - > transform ) , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y ) ;
2022-11-05 19:04:44 +01:00
pMonitor - > vecPixelSize = Vector2D ( transformedBox . width , transformedBox . height ) ;
}
2023-11-24 11:54:21 +01:00
pMonitor - > updateMatrix ( ) ;
2024-02-02 16:36:13 +01:00
if ( WAS10B ! = pMonitor - > enabled10bit | | OLDRES ! = pMonitor - > vecPixelSize )
g_pHyprOpenGL - > destroyMonitorResources ( pMonitor ) ;
2022-10-07 23:19:23 +02:00
2022-04-21 18:11:28 +02:00
// updato wlroots
2023-08-14 14:22:06 +02:00
g_pCompositor - > arrangeMonitors ( ) ;
2022-04-21 18:11:28 +02:00
2023-04-07 13:18:40 +02:00
wlr_damage_ring_set_bounds ( & pMonitor - > damage , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y ) ;
2024-01-14 14:56:35 +01:00
// Set scale for all surfaces on this monitor, needed for some clients
// but not on unsafe state to avoid crashes
if ( ! g_pCompositor - > m_bUnsafeState ) {
for ( auto & w : g_pCompositor - > m_vWindows ) {
w - > updateSurfaceScaleTransformDetails ( ) ;
}
}
2022-04-21 18:11:28 +02:00
// updato us
arrangeLayersForMonitor ( pMonitor - > ID ) ;
// frame skip
2022-06-06 13:48:17 +02:00
pMonitor - > framesToSkip = 1 ;
2022-06-30 23:55:28 +02:00
2022-09-13 15:25:42 +02:00
// reload to fix mirrors
g_pConfigManager - > m_bWantsMonitorReload = true ;
2023-09-20 17:25:03 +02:00
Debug : : log ( LOG , " Monitor {} data dump: res {:X}@{:.2f}Hz, scale {:.2f}, transform {}, pos {:X}, 10b {} " , pMonitor - > szName , pMonitor - > vecPixelSize , pMonitor - > refreshRate ,
pMonitor - > scale , ( int ) pMonitor - > transform , pMonitor - > vecPosition , ( int ) pMonitor - > enabled10bit ) ;
2023-01-17 11:57:36 +01:00
2023-07-18 15:30:28 +02:00
EMIT_HOOK_EVENT ( " monitorLayoutChanged " , nullptr ) ;
2023-06-23 21:14:04 +02:00
2023-09-10 14:14:27 +02:00
Events : : listener_change ( nullptr , nullptr ) ;
2022-06-30 23:55:28 +02:00
return true ;
2022-04-21 18:11:28 +02:00
}
2022-06-24 23:27:02 +02:00
2023-12-20 21:40:44 +01:00
void CHyprRenderer : : setCursorSurface ( wlr_surface * surf , int hotspotX , int hotspotY , bool force ) {
2023-09-29 18:51:07 +02:00
m_bCursorHasSurface = surf ;
2024-02-21 14:48:48 +01:00
if ( surf = = m_sLastCursorData . surf & & hotspotX = = m_sLastCursorData . hotspotX & & hotspotY = = m_sLastCursorData . hotspotY & & ! force )
2023-10-29 19:09:05 +01:00
return ;
2023-12-18 17:06:06 +01:00
m_sLastCursorData . name = " " ;
m_sLastCursorData . surf = surf ;
m_sLastCursorData . hotspotX = hotspotX ;
m_sLastCursorData . hotspotY = hotspotY ;
2023-10-29 19:09:05 +01:00
2024-02-21 14:48:48 +01:00
if ( m_bCursorHidden & & ! force )
return ;
2023-12-20 13:00:27 +01:00
wlr_cursor_set_surface ( g_pCompositor - > m_sWLRCursor , surf , hotspotX , hotspotY ) ;
2023-09-29 18:51:07 +02: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 18:51:07 +02:00
m_bCursorHasSurface = true ;
2024-02-21 14:48:48 +01:00
if ( name = = m_sLastCursorData . name & & ! force )
2023-10-29 19:09:05 +01:00
return ;
m_sLastCursorData . name = name ;
2023-10-30 01:18:40 +01:00
m_sLastCursorData . surf . reset ( ) ;
2023-10-29 19:09:05 +01:00
2024-02-21 14:48:48 +01:00
if ( m_bCursorHidden & & ! force )
return ;
2023-12-20 13:00:27 +01:00
wlr_cursor_set_xcursor ( g_pCompositor - > m_sWLRCursor , g_pCompositor - > m_sWLRXCursorMgr , name . c_str ( ) ) ;
2023-09-29 18:51:07 +02:00
}
2022-06-24 23:27:02 +02:00
void CHyprRenderer : : ensureCursorRenderingMode ( ) {
2024-02-18 16:00:34 +01:00
static auto * const PCURSORTIMEOUT = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " general:cursor_inactive_timeout " ) ;
static auto * const PHIDEONTOUCH = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " misc:hide_cursor_on_touch " ) ;
2022-06-24 23:27:02 +02:00
2022-12-16 18:17:31 +01:00
const auto PASSEDCURSORSECONDS = g_pInputManager - > m_tmrLastCursorMovement . getSeconds ( ) ;
2022-06-24 23:27:02 +02:00
2024-02-18 16:00:34 +01:00
if ( * * PCURSORTIMEOUT > 0 | | * * PHIDEONTOUCH ) {
const bool HIDE = ( * * PCURSORTIMEOUT > 0 & & * * PCURSORTIMEOUT < PASSEDCURSORSECONDS ) | | ( g_pInputManager - > m_bLastInputTouch & & * * PHIDEONTOUCH ) ;
2023-01-17 11:47:39 +01:00
2023-12-20 21:40:44 +01:00
if ( HIDE & & ! m_bCursorHidden ) {
2022-06-24 23:27:02 +02:00
Debug : : log ( LOG , " Hiding the cursor (timeout) " ) ;
2022-06-30 15:44:26 +02:00
for ( auto & m : g_pCompositor - > m_vMonitors )
2022-12-16 18:17:31 +01:00
g_pHyprRenderer - > damageMonitor ( m . get ( ) ) ; // TODO: maybe just damage the cursor area?
2022-06-24 23:27:02 +02:00
2023-12-20 21:40:44 +01:00
setCursorHidden ( true ) ;
} else if ( ! HIDE & & m_bCursorHidden ) {
2022-06-24 23:27:02 +02:00
Debug : : log ( LOG , " Showing the cursor (timeout) " ) ;
2022-06-30 15:44:26 +02:00
for ( auto & m : g_pCompositor - > m_vMonitors )
2022-12-16 18:17:31 +01:00
g_pHyprRenderer - > damageMonitor ( m . get ( ) ) ; // TODO: maybe just damage the cursor area?
2023-12-20 21:40:44 +01:00
setCursorHidden ( false ) ;
2022-06-24 23:27:02 +02:00
}
} else {
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 ) {
wlr_cursor_unset_image ( g_pCompositor - > m_sWLRCursor ) ;
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 20:23:16 +01:00
std : : tuple < float , float , float > CHyprRenderer : : getRenderTimes ( CMonitor * pMonitor ) {
const auto POVERLAY = & g_pDebugOverlay - > m_mMonitorOverlays [ pMonitor ] ;
float avgRenderTime = 0 ;
float maxRenderTime = 0 ;
float minRenderTime = 9999 ;
for ( auto & rt : POVERLAY - > m_dLastRenderTimes ) {
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 15:49:58 +02:00
static int handleCrashLoop ( void * data ) {
g_pHyprNotificationOverlay - > addNotification ( " Hyprland will crash in " + std : : to_string ( 10 - ( int ) ( g_pHyprRenderer - > m_fCrashingDistort * 2.f ) ) + " s. " , CColor ( 0 ) , 5000 ,
ICON_INFO ) ;
g_pHyprRenderer - > m_fCrashingDistort + = 0.5f ;
if ( g_pHyprRenderer - > m_fCrashingDistort > = 5.5f )
2023-08-31 22:52:02 +02:00
raise ( SIGABRT ) ;
2023-04-04 15:49:58 +02:00
wl_event_source_timer_update ( g_pHyprRenderer - > m_pCrashingLoop , 1000 ) ;
return 1 ;
}
void CHyprRenderer : : initiateManualCrash ( ) {
g_pHyprNotificationOverlay - > addNotification ( " Manual crash initiated. Farewell... " , CColor ( 0 ) , 5000 , ICON_INFO ) ;
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 23:04:32 +02:00
g_pHyprOpenGL - > m_tGlobalTimer . reset ( ) ;
2024-02-18 16:00:34 +01:00
static auto * const PDT = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " debug:damage_tracking " ) ;
* * PDT = 0 ;
2023-04-14 16:16:43 +02:00
}
2023-07-19 16:13:55 +02:00
2023-12-23 22:41:42 +01:00
void CHyprRenderer : : setOccludedForMainWorkspace ( CRegion & region , CWorkspace * pWorkspace ) {
CRegion rg ;
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWorkspace - > m_iMonitorID ) ;
if ( ! PMONITOR - > specialWorkspaceID )
return ;
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( ! w - > m_bIsMapped | | w - > isHidden ( ) | | w - > m_iWorkspaceID ! = PMONITOR - > specialWorkspaceID )
continue ;
if ( ! w - > opaque ( ) )
continue ;
const auto ROUNDING = w - > rounding ( ) * PMONITOR - > scale ;
const Vector2D POS = w - > m_vRealPosition . vec ( ) + Vector2D { ROUNDING , ROUNDING } - PMONITOR - > vecPosition + ( w - > m_bPinned ? Vector2D { } : pWorkspace - > m_vRenderOffset . vec ( ) ) ;
const Vector2D SIZE = w - > m_vRealSize . vec ( ) - Vector2D { ROUNDING * 2 , ROUNDING * 2 } ;
CBox box = { POS . x , POS . y , SIZE . x , SIZE . y } ;
box . scale ( PMONITOR - > scale ) ;
rg . add ( box ) ;
}
region . subtract ( rg ) ;
}
2023-07-19 20:09:49 +02:00
void CHyprRenderer : : setOccludedForBackLayers ( CRegion & region , CWorkspace * pWorkspace ) {
CRegion rg ;
2023-07-19 16:13:55 +02:00
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWorkspace - > m_iMonitorID ) ;
for ( auto & w : g_pCompositor - > m_vWindows ) {
if ( ! w - > m_bIsMapped | | w - > isHidden ( ) | | w - > m_iWorkspaceID ! = pWorkspace - > m_iID )
continue ;
if ( ! w - > opaque ( ) )
continue ;
const auto ROUNDING = w - > rounding ( ) * PMONITOR - > scale ;
2023-08-09 22:15:37 +02:00
const Vector2D POS = w - > m_vRealPosition . vec ( ) + Vector2D { ROUNDING , ROUNDING } - PMONITOR - > vecPosition + ( w - > m_bPinned ? Vector2D { } : pWorkspace - > m_vRenderOffset . vec ( ) ) ;
2023-07-19 16:13:55 +02:00
const Vector2D SIZE = w - > m_vRealSize . vec ( ) - Vector2D { ROUNDING * 2 , ROUNDING * 2 } ;
2023-11-04 18:03:05 +01:00
CBox box = { POS . x , POS . y , SIZE . x , SIZE . y } ;
2023-07-20 18:12:29 +02:00
2023-11-04 18:03:05 +01:00
box . scale ( PMONITOR - > scale ) ;
2023-07-20 18:12:29 +02:00
2023-11-11 15:37:17 +01:00
rg . add ( box ) ;
2023-07-19 16:13:55 +02:00
}
2023-07-19 20:09:49 +02:00
region . subtract ( rg ) ;
2023-07-19 16:13:55 +02:00
}
2023-07-20 14:11:05 +02:00
bool CHyprRenderer : : canSkipBackBufferClear ( CMonitor * pMonitor ) {
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ] ) {
if ( ! ls - > layerSurface )
continue ;
2023-07-20 18:27:14 +02:00
if ( ls - > alpha . fl ( ) < 1.f )
2023-07-20 14:11:05 +02:00
continue ;
2023-07-20 18:27:14 +02:00
if ( ls - > geometry . x ! = pMonitor - > vecPosition . x | | ls - > geometry . y ! = pMonitor - > vecPosition . y | | ls - > geometry . width ! = pMonitor - > vecSize . x | |
ls - > geometry . height ! = pMonitor - > vecSize . y )
continue ;
2023-11-26 16:24:24 +01:00
// TODO: cache maybe?
CRegion opaque = & ls - > layerSurface - > surface - > opaque_region ;
CBox lsbox = { 0 , 0 , ls - > layerSurface - > surface - > current . buffer_width , ls - > layerSurface - > surface - > current . buffer_height } ;
opaque . invert ( lsbox ) ;
if ( ! opaque . empty ( ) )
2023-07-20 18:27:14 +02:00
continue ;
return true ;
2023-07-20 14:11:05 +02:00
}
return false ;
}
2023-09-28 22:48:33 +02:00
void CHyprRenderer : : recheckSolitaryForMonitor ( CMonitor * pMonitor ) {
pMonitor - > solitaryClient = nullptr ; // reset it, if we find one it will be set.
2024-02-14 12:09:18 +01:00
if ( g_pHyprNotificationOverlay - > hasAny ( ) )
return ;
2023-09-28 22:48:33 +02:00
const auto PWORKSPACE = g_pCompositor - > getWorkspaceByID ( pMonitor - > activeWorkspace ) ;
2023-09-29 18:51:07 +02:00
if ( ! PWORKSPACE | | ! PWORKSPACE - > m_bHasFullscreenWindow | | g_pInputManager - > m_sDrag . drag | | g_pCompositor - > m_sSeat . exclusiveClient | | pMonitor - > specialWorkspaceID | |
PWORKSPACE - > m_fAlpha . fl ( ) ! = 1.f | | PWORKSPACE - > m_vRenderOffset . vec ( ) ! = Vector2D { } )
2023-09-28 22:48:33 +02:00
return ;
const auto PCANDIDATE = g_pCompositor - > getFullscreenWindowOnWorkspace ( PWORKSPACE - > m_iID ) ;
if ( ! PCANDIDATE )
return ; // ????
if ( ! PCANDIDATE - > opaque ( ) )
return ;
if ( PCANDIDATE - > m_vRealSize . vec ( ) ! = pMonitor - > vecSize | | PCANDIDATE - > m_vRealPosition . vec ( ) ! = pMonitor - > vecPosition | | PCANDIDATE - > m_vRealPosition . isBeingAnimated ( ) | |
PCANDIDATE - > m_vRealSize . isBeingAnimated ( ) )
return ;
if ( ! pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] . empty ( ) )
return ;
for ( auto & topls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
if ( topls - > alpha . fl ( ) ! = 0.f )
return ;
}
2023-10-04 10:44:03 +02:00
for ( auto & w : g_pCompositor - > m_vWindows ) {
2024-02-26 01:19:16 +01:00
if ( w - > m_iWorkspaceID = = PCANDIDATE - > m_iWorkspaceID & & w - > m_bIsFloating & & w - > m_bCreatedOverFullscreen & & ! w - > isHidden ( ) & & ( w - > m_bIsMapped | | w - > m_bFadingOut ) & &
w . get ( ) ! = PCANDIDATE )
2023-10-04 10:44:03 +02:00
return ;
}
if ( pMonitor - > specialWorkspaceID ! = 0 )
return ;
2023-09-28 22:48:33 +02:00
// check if it did not open any subsurfaces or shit
int surfaceCount = 0 ;
if ( PCANDIDATE - > m_bIsX11 ) {
surfaceCount = 1 ;
} else {
wlr_xdg_surface_for_each_surface ( PCANDIDATE - > m_uSurface . xdg , countSubsurfacesIter , & surfaceCount ) ;
wlr_xdg_surface_for_each_popup_surface ( PCANDIDATE - > m_uSurface . xdg , countSubsurfacesIter , & surfaceCount ) ;
}
2023-10-02 15:02:15 +02:00
if ( surfaceCount > 1 )
return ;
2023-09-28 22:48:33 +02:00
// found one!
pMonitor - > solitaryClient = PCANDIDATE ;
}
2023-11-24 11:54:21 +01:00
void CHyprRenderer : : renderSoftwareCursors ( CMonitor * pMonitor , const CRegion & damage , std : : optional < Vector2D > overridePos ) {
2023-11-24 22:30:28 +01:00
const auto CURSORPOS = overridePos . value_or ( g_pInputManager - > getMouseCoordsInternal ( ) - pMonitor - > vecPosition ) * pMonitor - > scale ;
2023-11-24 11:54:21 +01:00
wlr_output_cursor * cursor ;
wl_list_for_each ( cursor , & pMonitor - > output - > cursors , link ) {
if ( ! cursor - > enabled | | ! cursor - > visible | | pMonitor - > output - > hardware_cursor = = cursor )
continue ;
if ( ! cursor - > texture )
continue ;
2023-11-24 22:30:28 +01:00
CBox cursorBox = CBox { CURSORPOS . x , CURSORPOS . y , cursor - > width , cursor - > height } . translate ( { - cursor - > hotspot_x , - cursor - > hotspot_y } ) ;
2023-11-24 11:54:21 +01:00
2023-11-24 14:47:36 +01:00
// TODO: NVIDIA doesn't like if we use renderTexturePrimitive here. Why?
g_pHyprOpenGL - > renderTexture ( cursor - > texture , & cursorBox , 1.0 ) ;
2023-11-24 11:54:21 +01:00
}
}
CRenderbuffer * CHyprRenderer : : getOrCreateRenderbuffer ( wlr_buffer * buffer , uint32_t fmt ) {
auto it = std : : find_if ( m_vRenderbuffers . begin ( ) , m_vRenderbuffers . end ( ) , [ & ] ( const auto & other ) { return other - > m_pWlrBuffer = = buffer ; } ) ;
if ( it ! = m_vRenderbuffers . end ( ) )
return it - > get ( ) ;
return m_vRenderbuffers . emplace_back ( std : : make_unique < CRenderbuffer > ( buffer , fmt ) ) . get ( ) ;
}
2023-11-30 02:18:55 +01:00
void CHyprRenderer : : makeEGLCurrent ( ) {
2023-12-06 15:46:18 +01:00
if ( ! g_pCompositor )
return ;
2023-11-24 11:54:21 +01:00
if ( eglGetCurrentContext ( ) ! = wlr_egl_get_context ( g_pCompositor - > m_sWLREGL ) )
eglMakeCurrent ( wlr_egl_get_display ( g_pCompositor - > m_sWLREGL ) , EGL_NO_SURFACE , EGL_NO_SURFACE , wlr_egl_get_context ( g_pCompositor - > m_sWLREGL ) ) ;
2023-11-30 02:18:55 +01:00
}
void CHyprRenderer : : unsetEGL ( ) {
eglMakeCurrent ( wlr_egl_get_display ( g_pCompositor - > m_sWLREGL ) , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
}
bool CHyprRenderer : : beginRender ( CMonitor * pMonitor , CRegion & damage , eRenderMode mode , wlr_buffer * buffer , CFramebuffer * fb ) {
makeEGLCurrent ( ) ;
2023-11-24 11:54:21 +01: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 02:18:55 +01:00
RASSERT ( fb , " Cannot render FULL_FAKE without a provided fb! " ) ;
fb - > bind ( ) ;
2024-02-23 02:02:32 +01:00
g_pHyprOpenGL - > begin ( pMonitor , damage , fb ) ;
2023-11-24 11:54:21 +01:00
return true ;
}
2023-11-30 02:18:55 +01:00
if ( ! buffer ) {
2024-02-23 00:50:56 +01:00
if ( ! wlr_output_configure_primary_swapchain ( pMonitor - > output , pMonitor - > state . wlr ( ) , & pMonitor - > output - > swapchain ) ) {
2024-02-23 01:02:48 +01:00
Debug : : log ( ERR , " Failed to configure primary swapchain for {} " , pMonitor - > szName ) ;
2023-11-24 11:54:21 +01:00
return false ;
2024-02-23 00:50:56 +01:00
}
2023-11-24 11:54:21 +01:00
2024-02-18 17:04:08 +01:00
m_pCurrentWlrBuffer = wlr_swapchain_acquire ( pMonitor - > output - > swapchain , nullptr ) ;
2024-02-23 00:50:56 +01:00
if ( ! m_pCurrentWlrBuffer ) {
2024-02-23 01:02:48 +01:00
Debug : : log ( ERR , " Failed to acquire swapchain buffer for {} " , pMonitor - > szName ) ;
2023-11-24 11:54:21 +01:00
return false ;
2024-02-23 00:50:56 +01:00
}
} else
2023-11-30 11:14:35 +01:00
m_pCurrentWlrBuffer = wlr_buffer_lock ( buffer ) ;
2023-11-24 11:54:21 +01:00
try {
m_pCurrentRenderbuffer = getOrCreateRenderbuffer ( m_pCurrentWlrBuffer , pMonitor - > drmFormat ) ;
} catch ( std : : exception & e ) {
2024-02-23 01:02:48 +01:00
Debug : : log ( ERR , " getOrCreateRenderbuffer failed for {} " , pMonitor - > szName ) ;
2023-11-24 11:54:21 +01:00
wlr_buffer_unlock ( m_pCurrentWlrBuffer ) ;
return false ;
}
2024-02-19 19:17:32 +01:00
if ( mode = = RENDER_MODE_NORMAL )
wlr_damage_ring_rotate_buffer ( & pMonitor - > damage , m_pCurrentWlrBuffer , damage . pixman ( ) ) ;
2023-11-24 11:54:21 +01:00
m_pCurrentRenderbuffer - > bind ( ) ;
2024-02-23 02:02:32 +01:00
g_pHyprOpenGL - > begin ( pMonitor , damage ) ;
2023-11-24 11:54:21 +01:00
return true ;
}
void CHyprRenderer : : endRender ( ) {
2023-12-27 19:16:57 +01:00
const auto PMONITOR = g_pHyprOpenGL - > m_RenderData . pMonitor ;
2024-02-18 16:00:34 +01:00
static auto * const PNVIDIAANTIFLICKER = ( Hyprlang : : INT * const * ) g_pConfigManager - > getConfigValuePtr ( " opengl:nvidia_anti_flicker " ) ;
2023-11-24 11:54:21 +01:00
2023-11-30 11:14:35 +01:00
if ( m_eRenderMode ! = RENDER_MODE_TO_BUFFER_READ_ONLY )
g_pHyprOpenGL - > end ( ) ;
else {
g_pHyprOpenGL - > m_RenderData . pMonitor = nullptr ;
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = 1.f ;
g_pHyprOpenGL - > m_RenderData . mouseZoomUseMouse = true ;
}
2023-11-24 11:54:21 +01:00
2023-11-30 11:14:35 +01:00
if ( m_eRenderMode = = RENDER_MODE_FULL_FAKE )
2023-11-24 11:54:21 +01:00
return ;
2024-02-18 16:00:34 +01:00
if ( isNvidia ( ) & & * * PNVIDIAANTIFLICKER )
2023-11-25 18:45:08 +01:00
glFinish ( ) ;
else
glFlush ( ) ;
2023-11-24 11:54:21 +01:00
2023-11-30 02:18:55 +01:00
if ( m_eRenderMode = = RENDER_MODE_NORMAL ) {
2024-01-28 02:57:13 +01:00
wlr_output_state_set_buffer ( PMONITOR - > state . wlr ( ) , m_pCurrentWlrBuffer ) ;
2023-11-30 02:18:55 +01:00
unsetEGL ( ) ; // flush the context
}
2023-11-24 11:54:21 +01:00
wlr_buffer_unlock ( m_pCurrentWlrBuffer ) ;
m_pCurrentRenderbuffer - > unbind ( ) ;
m_pCurrentRenderbuffer = nullptr ;
m_pCurrentWlrBuffer = nullptr ;
}
void CHyprRenderer : : onRenderbufferDestroy ( CRenderbuffer * rb ) {
std : : erase_if ( m_vRenderbuffers , [ & ] ( const auto & rbo ) { return rbo . get ( ) = = rb ; } ) ;
}
CRenderbuffer * CHyprRenderer : : getCurrentRBO ( ) {
return m_pCurrentRenderbuffer ;
2023-11-25 18:45:08 +01:00
}
bool CHyprRenderer : : isNvidia ( ) {
return m_bNvidia ;
2023-12-18 17:06:06 +01:00
}