2022-03-17 20:22:29 +01:00
# include "Renderer.hpp"
# include "../Compositor.hpp"
2024-06-19 16:20:06 +02:00
# include "../helpers/math/Math.hpp"
2024-08-06 14:52:19 +01:00
# include "../helpers/sync/SyncReleaser.hpp"
2023-11-12 14:14:05 +01:00
# include <algorithm>
2024-07-21 13:09:54 +02:00
# include <aquamarine/output/Output.hpp>
# include <cstring>
2024-08-06 14:52:19 +01:00
# include <filesystem>
2024-03-03 18:39:20 +00:00
# include "../config/ConfigValue.hpp"
2024-03-09 16:52:59 +00:00
# include "../managers/CursorManager.hpp"
2024-05-05 22:18:10 +01:00
# include "../managers/PointerManager.hpp"
2024-03-20 01:44:51 +00:00
# include "../desktop/Window.hpp"
2024-04-30 02:41:27 +01:00
# include "../desktop/LayerSurface.hpp"
2024-04-30 16:32:05 +01:00
# include "../protocols/SessionLock.hpp"
2024-05-09 21:47:21 +01:00
# include "../protocols/LayerShell.hpp"
2024-05-10 23:28:33 +01:00
# include "../protocols/XDGShell.hpp"
2024-05-10 02:27:54 +01:00
# include "../protocols/PresentationTime.hpp"
2024-05-11 17:13:20 +01:00
# include "../protocols/core/DataDevice.hpp"
2024-06-08 10:07:59 +02:00
# include "../protocols/core/Compositor.hpp"
2024-07-21 13:09:54 +02:00
# include "../protocols/DRMSyncobj.hpp"
# include "../protocols/LinuxDMABUF.hpp"
# include "../helpers/sync/SyncTimeline.hpp"
# include "debug/Log.hpp"
2022-03-17 20:22:29 +01:00
2024-09-21 00:33:48 +01:00
# include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils : : Utils ;
2023-11-25 17:45:08 +00:00
extern " C " {
# include <xf86drm.h>
}
2024-03-28 02:04:30 +00:00
static int cursorTicker ( void * data ) {
g_pHyprRenderer - > ensureCursorRenderingMode ( ) ;
wl_event_source_timer_update ( g_pHyprRenderer - > m_pCursorTicker , 500 ) ;
return 0 ;
}
2023-11-25 17:45:08 +00:00
2024-03-28 02:04:30 +00:00
CHyprRenderer : : CHyprRenderer ( ) {
2024-07-21 13:09:54 +02:00
if ( g_pCompositor - > m_pAqBackend - > hasSession ( ) ) {
2024-08-26 20:24:30 +02:00
for ( auto const & dev : g_pCompositor - > m_pAqBackend - > session - > sessionDevices ) {
2024-07-21 13:09:54 +02:00
const auto DRMV = drmGetVersion ( dev - > fd ) ;
if ( ! DRMV )
continue ;
2023-11-25 17:45:08 +00:00
std : : string name = std : : string { DRMV - > name , DRMV - > name_len } ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , tolower ) ;
if ( name . contains ( " nvidia " ) )
m_bNvidia = true ;
Debug : : log ( LOG , " DRM driver information: {} v{}.{}.{} from {} description {} " , name , DRMV - > version_major , DRMV - > version_minor , DRMV - > version_patchlevel ,
2023-11-25 17:56:38 +00:00
std : : string { DRMV - > date , DRMV - > date_len } , std : : string { DRMV - > desc , DRMV - > desc_len } ) ;
2023-11-25 17:45:08 +00:00
drmFreeVersion ( DRMV ) ;
}
} else {
2024-07-21 13:09:54 +02:00
Debug : : log ( LOG , " Aq backend has no session, omitting full DRM node checks " ) ;
2023-11-25 17:45:08 +00:00
2024-03-15 07:28:14 -07:00
const auto DRMV = drmGetVersion ( g_pCompositor - > m_iDRMFD ) ;
2023-11-25 17:45:08 +00:00
2024-03-15 07:28:14 -07:00
if ( DRMV ) {
std : : string name = std : : string { DRMV - > name , DRMV - > name_len } ;
std : : transform ( name . begin ( ) , name . end ( ) , name . begin ( ) , tolower ) ;
2023-11-25 17:45:08 +00:00
2024-03-15 07:28:14 -07:00
if ( name . contains ( " nvidia " ) )
m_bNvidia = true ;
2023-11-25 17:45:08 +00:00
2024-03-15 07:28:14 -07:00
Debug : : log ( LOG , " Primary DRM driver information: {} v{}.{}.{} from {} description {} " , name , DRMV - > version_major , DRMV - > version_minor , DRMV - > version_patchlevel ,
std : : string { DRMV - > date , DRMV - > date_len } , std : : string { DRMV - > desc , DRMV - > desc_len } ) ;
} else {
Debug : : log ( LOG , " No primary DRM driver information found " ) ;
}
2023-11-25 17:45:08 +00:00
drmFreeVersion ( DRMV ) ;
}
if ( m_bNvidia )
Debug : : log ( WARN , " NVIDIA detected, please remember to follow nvidia instructions on the wiki " ) ;
2024-03-28 02:04:30 +00:00
// cursor hiding stuff
2024-04-20 20:16:42 +01:00
static auto P = g_pHookSystem - > hookDynamic ( " keyPress " , [ & ] ( void * self , SCallbackInfo & info , std : : any param ) {
2024-03-28 02:04:30 +00:00
if ( m_sCursorHiddenConditions . hiddenOnKeyboard )
return ;
m_sCursorHiddenConditions . hiddenOnKeyboard = true ;
ensureCursorRenderingMode ( ) ;
} ) ;
2024-04-20 20:16:42 +01:00
static auto P2 = g_pHookSystem - > hookDynamic ( " mouseMove " , [ & ] ( void * self , SCallbackInfo & info , std : : any param ) {
2024-03-28 02:04:30 +00:00
if ( ! m_sCursorHiddenConditions . hiddenOnKeyboard & & m_sCursorHiddenConditions . hiddenOnTouch = = g_pInputManager - > m_bLastInputTouch & &
! m_sCursorHiddenConditions . hiddenOnTimeout )
return ;
m_sCursorHiddenConditions . hiddenOnKeyboard = false ;
m_sCursorHiddenConditions . hiddenOnTimeout = false ;
m_sCursorHiddenConditions . hiddenOnTouch = g_pInputManager - > m_bLastInputTouch ;
ensureCursorRenderingMode ( ) ;
} ) ;
2024-10-08 21:20:25 +01:00
static auto P3 = g_pHookSystem - > hookDynamic ( " focusedMon " , [ & ] ( void * self , SCallbackInfo & info , std : : any param ) {
g_pEventLoopManager - > doLater ( [ this ] ( ) {
if ( ! g_pHyprError - > active ( ) )
return ;
for ( auto & m : g_pCompositor - > m_vMonitors ) {
arrangeLayersForMonitor ( m - > ID ) ;
}
} ) ;
} ) ;
2024-03-28 02:04:30 +00:00
m_pCursorTicker = wl_event_loop_add_timer ( g_pCompositor - > m_sWLEventLoop , cursorTicker , nullptr ) ;
wl_event_source_timer_update ( m_pCursorTicker , 500 ) ;
2024-08-30 17:37:52 +02:00
m_tRenderUnfocusedTimer = makeShared < CEventLoopTimer > (
std : : nullopt ,
[ this ] ( SP < CEventLoopTimer > self , void * data ) {
static auto PFPS = CConfigValue < Hyprlang : : INT > ( " misc:render_unfocused_fps " ) ;
if ( m_vRenderUnfocused . empty ( ) )
return ;
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
bool dirty = false ;
for ( auto & w : m_vRenderUnfocused ) {
if ( ! w ) {
dirty = true ;
continue ;
}
if ( ! w - > m_pWLSurface | | ! w - > m_pWLSurface - > resource ( ) | | shouldRenderWindow ( w . lock ( ) ) )
continue ;
w - > m_pWLSurface - > resource ( ) - > frame ( & now ) ;
auto FEEDBACK = makeShared < CQueuedPresentationData > ( w - > m_pWLSurface - > resource ( ) ) ;
FEEDBACK - > attachMonitor ( g_pCompositor - > m_pLastMonitor . lock ( ) ) ;
FEEDBACK - > discarded ( ) ;
PROTO : : presentation - > queueData ( FEEDBACK ) ;
}
if ( dirty )
std : : erase_if ( m_vRenderUnfocused , [ ] ( const auto & e ) { return ! e | | ! e - > m_sWindowData . renderUnfocused . valueOr ( false ) ; } ) ;
if ( ! m_vRenderUnfocused . empty ( ) )
m_tRenderUnfocusedTimer - > updateTimeout ( std : : chrono : : milliseconds ( 1000 / * PFPS ) ) ;
} ,
nullptr ) ;
g_pEventLoopManager - > addTimer ( m_tRenderUnfocusedTimer ) ;
2023-09-28 21:48:33 +01:00
}
2024-06-13 12:08:02 +02:00
CHyprRenderer : : ~ CHyprRenderer ( ) {
if ( m_pCursorTicker )
wl_event_source_remove ( m_pCursorTicker ) ;
}
2024-06-08 10:07:59 +02:00
static void renderSurface ( SP < CWLSurfaceResource > surface , int x , int y , void * data ) {
2024-07-31 20:47:26 +01:00
if ( ! surface - > current . texture )
2024-06-08 10:07:59 +02:00
return ;
2024-10-31 00:20:32 +01:00
const auto & TEXTURE = surface - > current . texture ;
2022-03-17 20:22:29 +01:00
2024-06-08 10:07:59 +02:00
// this is bad, probably has been logged elsewhere. Means the texture failed
// uploading to the GPU.
if ( ! TEXTURE - > m_iTexID )
2022-03-17 20:22:29 +01:00
return ;
2024-07-21 13:09:54 +02:00
// explicit sync: wait for the timeline, if any
2024-08-06 14:52:19 +01:00
if ( surface - > syncobj & & surface - > syncobj - > current . acquireTimeline ) {
if ( ! g_pHyprOpenGL - > waitForTimelinePoint ( surface - > syncobj - > current . acquireTimeline - > timeline , surface - > syncobj - > current . acquirePoint ) ) {
2024-07-21 13:09:54 +02:00
Debug : : log ( ERR , " Renderer: failed to wait for explicit timeline " ) ;
return ;
}
}
2024-10-31 00:20:32 +01:00
const auto RDATA = ( SRenderData * ) data ;
const auto INTERACTIVERESIZEINPROGRESS = RDATA - > pWindow & & g_pInputManager - > currentlyDraggedWindow & & g_pInputManager - > dragMode = = MBIND_RESIZE ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderSurface " ) ;
2024-05-05 22:18:10 +01:00
double outputX = - RDATA - > pMonitor - > vecPosition . x , outputY = - RDATA - > pMonitor - > vecPosition . y ;
2022-03-17 20:22:29 +01:00
2024-06-08 10:07:59 +02:00
auto PSURFACE = CWLSurface : : fromResource ( surface ) ;
2024-04-21 21:21:22 +01:00
2024-04-21 21:29:37 +01:00
const float ALPHA = RDATA - > alpha * RDATA - > fadeAlpha * ( PSURFACE ? PSURFACE - > m_pAlphaModifier : 1.F ) ;
2024-11-20 11:02:21 +00:00
const bool BLUR = RDATA - > blur & & ( ! TEXTURE - > m_bOpaque | | ALPHA < 1.F ) ;
2024-04-21 21:21:22 +01:00
2024-04-21 21:29:37 +01:00
CBox windowBox ;
2023-10-20 20:15:41 +01: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 20:15:41 +01:00
// however, if surface buffer w / h < box, we need to adjust them
2024-04-21 21:29:37 +01:00
const auto PWINDOW = PSURFACE ? PSURFACE - > getWindow ( ) : nullptr ;
2023-10-20 20:15:41 +01:00
2024-10-05 00:52:53 +01:00
// center the surface if it's smaller than the viewport we assign it
2024-03-15 19:23:45 +00:00
if ( PSURFACE & & ! PSURFACE - > m_bFillIgnoreSmall & & PSURFACE - > small ( ) /* guarantees PWINDOW */ ) {
2023-12-31 13:11:20 +01:00
const auto CORRECT = PSURFACE - > correctSmallVec ( ) ;
const auto SIZE = PSURFACE - > getViewporterCorrectedSize ( ) ;
2023-10-20 20:32:47 +01:00
if ( ! INTERACTIVERESIZEINPROGRESS ) {
2024-03-15 19:23:45 +00:00
windowBox . translate ( CORRECT ) ;
2023-10-20 20:32:47 +01:00
2024-03-15 19:23:45 +00:00
windowBox . width = SIZE . x * ( PWINDOW - > m_vRealSize . value ( ) . x / PWINDOW - > m_vReportedSize . x ) ;
windowBox . height = SIZE . y * ( PWINDOW - > m_vRealSize . value ( ) . y / PWINDOW - > m_vReportedSize . y ) ;
2023-10-20 20:32:47 +01:00
} else {
2023-10-25 22:05:04 +01:00
windowBox . width = SIZE . x ;
windowBox . height = SIZE . y ;
2023-10-20 20:32:47 +01:00
}
2023-10-20 20:15:41 +01:00
}
} else { // here we clamp to 2, these might be some tiny specks
2024-06-08 10:07:59 +02:00
windowBox = { ( int ) outputX + RDATA - > x + x , ( int ) outputY + RDATA - > y + y , std : : max ( ( float ) surface - > current . size . x , 2.F ) , std : : max ( ( float ) surface - > current . size . y , 2.F ) } ;
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
2024-03-02 01:35:17 +01:00
windowBox . width = ( windowBox . width / RDATA - > pWindow - > m_vReportedSize . x ) * RDATA - > pWindow - > m_vRealSize . value ( ) . x ;
windowBox . height = ( windowBox . height / RDATA - > pWindow - > m_vReportedSize . y ) * RDATA - > pWindow - > m_vRealSize . value ( ) . y ;
2023-07-10 13:32:57 +02:00
}
}
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
2024-11-11 14:48:50 +01:00
const auto PROJSIZEUNSCALED = windowBox . size ( ) ;
windowBox . scale ( RDATA - > pMonitor - > scale ) ;
windowBox . round ( ) ;
2024-06-08 10:07:59 +02:00
if ( windowBox . width < = 1 | | windowBox . height < = 1 ) {
if ( ! g_pHyprRenderer - > m_bBlockSurfaceFeedback ) {
2024-07-21 13:09:54 +02:00
Debug : : log ( TRACE , " presentFeedback for invisible surface " ) ;
2024-08-30 15:50:25 +02:00
surface - > presentFeedback ( RDATA - > when , RDATA - > pMonitor - > self . lock ( ) ) ;
2024-06-08 10:07:59 +02:00
}
2024-07-21 13:09:54 +02:00
2023-10-21 14:20:06 +01:00
return ; // invisible
2024-06-08 10:07:59 +02:00
}
2023-10-21 14:20:06 +01:00
2024-01-28 23:42:39 +00:00
const bool MISALIGNEDFSV1 = std : : floor ( RDATA - > pMonitor - > scale ) ! = RDATA - > pMonitor - > scale /* Fractional */ & & surface - > current . scale = = 1 /* fs protocol */ & &
2024-07-31 20:47:26 +01:00
windowBox . size ( ) ! = surface - > current . bufferSize /* misaligned */ & & DELTALESSTHAN ( windowBox . width , surface - > current . bufferSize . x , 3 ) & &
DELTALESSTHAN ( windowBox . height , surface - > current . bufferSize . y , 3 ) /* off by one-or-two */ & &
2024-01-28 23:42:39 +00:00
( ! RDATA - > pWindow | | ( ! RDATA - > pWindow - > m_vRealSize . isBeingAnimated ( ) & & ! INTERACTIVERESIZEINPROGRESS ) ) /* not window or not animated/resizing */ ;
2024-10-05 00:52:53 +01:00
g_pHyprRenderer - > calculateUVForSurface ( RDATA - > pWindow , surface , RDATA - > pMonitor - > self . lock ( ) , RDATA - > surface = = surface , windowBox . size ( ) , PROJSIZEUNSCALED , MISALIGNEDFSV1 ) ;
2024-01-28 23:42:39 +00:00
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-28 23:42:39 +00: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-28 23:42:39 +00: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 00:06:48 +01:00
if ( RDATA - > dontRound )
rounding = 0 ;
2024-06-08 10:07:59 +02:00
const bool WINDOWOPAQUE = RDATA - > pWindow & & RDATA - > pWindow - > m_pWLSurface - > resource ( ) = = surface ? RDATA - > pWindow - > opaque ( ) : false ;
const bool CANDISABLEBLEND = ALPHA > = 1.f & & rounding = = 0 & & WINDOWOPAQUE ;
2023-07-20 13:49:28 +02:00
if ( CANDISABLEBLEND )
g_pHyprOpenGL - > blend ( false ) ;
else
g_pHyprOpenGL - > blend ( true ) ;
2024-06-17 12:42:32 +02:00
// FIXME: This is wrong and will bug the blur out as shit if the first surface
// is a subsurface that does NOT cover the entire frame. In such cases, we probably should fall back
// to what we do for misaligned surfaces (blur the entire thing and then render shit without blur)
2024-06-25 20:04:02 +02:00
if ( RDATA - > surfaceCounter = = 0 & & ! RDATA - > popup ) {
2024-11-17 16:42:30 +00:00
if ( BLUR )
2024-05-25 22:43:51 +02:00
g_pHyprOpenGL - > renderTextureWithBlur ( TEXTURE , & windowBox , ALPHA , surface , rounding , RDATA - > blockBlurOptimization , RDATA - > fadeAlpha ) ;
else
2024-06-08 16:16:43 +02:00
g_pHyprOpenGL - > renderTexture ( TEXTURE , & windowBox , ALPHA , rounding , false , true ) ;
2022-12-16 17:17:31 +00:00
} else {
2024-11-17 16:42:30 +00:00
if ( BLUR & & RDATA - > popup )
2024-04-21 21:21:22 +01:00
g_pHyprOpenGL - > renderTextureWithBlur ( TEXTURE , & windowBox , ALPHA , surface , rounding , true , RDATA - > fadeAlpha ) ;
2024-03-25 16:08:55 +00:00
else
2024-06-08 16:16:43 +02:00
g_pHyprOpenGL - > renderTexture ( TEXTURE , & windowBox , ALPHA , rounding , false , true ) ;
2022-07-04 15:58:12 +02:00
}
2022-03-17 20:22:29 +01:00
2024-07-21 23:25:20 +02:00
if ( ! g_pHyprRenderer - > m_bBlockSurfaceFeedback )
2024-08-30 15:50:25 +02:00
surface - > presentFeedback ( RDATA - > when , RDATA - > pMonitor - > self . lock ( ) ) ;
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 17:17:31 +00: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 ;
2024-06-17 12:42:32 +02:00
// up the counter so that we dont blur any surfaces above this one
RDATA - > surfaceCounter + + ;
2022-03-17 20:22:29 +01:00
}
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : shouldRenderWindow ( PHLWINDOW pWindow , PHLMONITOR pMonitor ) {
2024-05-05 22:18:10 +01:00
if ( ! pWindow - > visibleOnMonitor ( pMonitor ) )
2022-03-20 18:49:40 +01:00
return false ;
2024-04-02 20:32:39 +01:00
if ( ! pWindow - > m_pWorkspace & & ! pWindow - > m_bFadingOut )
2023-04-12 13:05:57 +01:00
return false ;
2024-04-03 20:42:38 +01:00
if ( ! pWindow - > m_pWorkspace & & pWindow - > m_bFadingOut )
return pWindow - > workspaceID ( ) = = pMonitor - > activeWorkspaceID ( ) ;
2022-09-10 13:11:02 +02:00
if ( pWindow - > m_bPinned )
return true ;
2024-08-28 21:54:49 +02:00
// if the window is being moved to a workspace that is not invisible, and the alpha is > 0.F, render it.
2024-11-22 16:01:02 +00:00
if ( pWindow - > m_iMonitorMovedFrom ! = - 1 & & pWindow - > m_fMovingToWorkspaceAlpha . isBeingAnimated ( ) & & pWindow - > m_fMovingToWorkspaceAlpha . value ( ) > 0.F & & pWindow - > m_pWorkspace & &
! pWindow - > m_pWorkspace - > isVisible ( ) )
2024-08-28 21:54:49 +02:00
return true ;
2024-04-02 20:32:39 +01:00
const auto PWINDOWWORKSPACE = pWindow - > m_pWorkspace ;
2024-10-27 18:45:38 +00:00
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_pMonitor = = pMonitor ) {
2024-04-01 08:16:18 -07:00
if ( PWINDOWWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) | | PWINDOWWORKSPACE - > m_fAlpha . isBeingAnimated ( ) | | PWINDOWWORKSPACE - > m_bForceRendering )
2022-08-18 12:42:21 +02:00
return true ;
2024-04-01 08:16:18 -07:00
// if hidden behind fullscreen
2024-07-31 17:55:52 +00:00
if ( PWINDOWWORKSPACE - > m_bHasFullscreenWindow & & ! pWindow - > isFullscreen ( ) & & ( ! pWindow - > m_bIsFloating | | ! pWindow - > m_bCreatedOverFullscreen ) & &
2024-04-01 08:16:18 -07:00
pWindow - > m_fAlpha . value ( ) = = 0 )
return false ;
2024-11-22 16:01:02 +00:00
if ( ! PWINDOWWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) & & ! PWINDOWWORKSPACE - > m_fAlpha . isBeingAnimated ( ) & & ! PWINDOWWORKSPACE - > isVisible ( ) )
2024-04-01 08:16:18 -07:00
return false ;
2022-07-28 16:33:45 +02:00
}
2024-10-27 18:45:38 +00:00
if ( pWindow - > m_pMonitor = = pMonitor )
2022-03-20 18:49:40 +01:00
return true ;
2024-11-27 09:17:45 -05:00
if ( ( ! pWindow - > m_pWorkspace | | ! pWindow - > m_pWorkspace - > isVisible ( ) ) & & pWindow - > m_pMonitor ! = pMonitor )
2024-03-30 18:14:26 -07:00
return false ;
2022-08-18 12:41:10 +02:00
// if not, check if it maybe is active on a different monitor.
2024-11-22 16:01:02 +00:00
if ( pWindow - > m_pWorkspace & & pWindow - > m_pWorkspace - > isVisible ( ) & & pWindow - > m_bIsFloating /* tiled windows can't be multi-ws */ )
2024-07-31 17:55:52 +00:00
return ! pWindow - > isFullscreen ( ) ; // Do not draw fullscreen windows on other monitors
2022-03-20 18:49:40 +01:00
2024-04-02 20:32:39 +01:00
if ( pMonitor - > activeSpecialWorkspace = = pWindow - > m_pWorkspace )
2022-05-31 14:01:00 +02:00
return true ;
2024-03-30 18:14:26 -07:00
// if window is tiled and it's flying in, don't render on other mons (for slide)
2024-10-27 18:45:38 +00:00
if ( ! pWindow - > m_bIsFloating & & pWindow - > m_vRealPosition . isBeingAnimated ( ) & & pWindow - > m_bAnimatingIn & & pWindow - > m_pMonitor ! = pMonitor )
2024-03-30 18:14:26 -07:00
return false ;
2024-03-16 07:49:34 -07:00
if ( pWindow - > m_vRealPosition . isBeingAnimated ( ) ) {
2024-03-23 15:14:50 -07:00
if ( PWINDOWWORKSPACE & & ! PWINDOWWORKSPACE - > m_bIsSpecialWorkspace & & PWINDOWWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) )
return false ;
2024-03-16 07:49:34 -07:00
// render window if window and monitor intersect
// (when moving out of or through a monitor)
2024-03-30 18:14:26 -07:00
CBox windowBox = pWindow - > getFullWindowBoundingBox ( ) ;
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) )
windowBox . translate ( PWINDOWWORKSPACE - > m_vRenderOffset . value ( ) ) ;
windowBox . translate ( pWindow - > m_vFloatingOffset ) ;
2024-03-16 07:49:34 -07:00
const CBox monitorBox = { pMonitor - > vecPosition , pMonitor - > vecSize } ;
2024-11-07 00:30:17 +01:00
if ( ! windowBox . intersection ( monitorBox ) . empty ( ) & & ( pWindow - > workspaceID ( ) = = pMonitor - > activeWorkspaceID ( ) | | pWindow - > m_iMonitorMovedFrom ! = - 1 ) )
2024-03-16 07:49:34 -07:00
return true ;
}
2022-03-20 18:49:40 +01:00
return false ;
}
2024-04-27 12:43:12 +01:00
bool CHyprRenderer : : shouldRenderWindow ( PHLWINDOW pWindow ) {
2022-05-31 22:16:13 +02:00
2024-04-27 12:43:12 +01:00
if ( ! validMapped ( pWindow ) )
2022-05-31 22:16:13 +02:00
return false ;
2024-04-02 20:32:39 +01:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2022-05-31 22:16:13 +02:00
2024-04-02 20:32:39 +01:00
if ( ! pWindow - > m_pWorkspace )
2023-04-12 13:05:57 +01:00
return false ;
2022-09-12 15:33:20 +02:00
if ( pWindow - > m_bPinned | | PWORKSPACE - > m_bForceRendering )
2022-09-10 13:11:02 +02:00
return true ;
2024-11-22 16:01:02 +00:00
if ( PWORKSPACE & & PWORKSPACE - > isVisible ( ) )
2022-05-31 22:16:13 +02:00
return true ;
2024-08-26 17:25:39 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2024-10-27 18:45:38 +00:00
if ( PWORKSPACE & & PWORKSPACE - > m_pMonitor = = m & & ( PWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) | | PWORKSPACE - > m_fAlpha . isBeingAnimated ( ) ) )
2022-05-31 22:16:13 +02:00
return true ;
2024-04-02 20:32:39 +01:00
if ( m - > activeSpecialWorkspace & & pWindow - > onSpecialWorkspace ( ) )
2022-05-31 22:16:13 +02:00
return true ;
}
return false ;
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderWorkspaceWindowsFullscreen ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * time ) {
2024-04-27 12:43:12 +01:00
PHLWINDOW pWorkspaceWindow = nullptr ;
2022-03-30 20:16:23 +02:00
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE_WINDOWS ) ;
2022-09-19 17:26:11 +01:00
// loop over the tiled windows that are fading out
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2022-09-19 17:26:11 +01:00
continue ;
2024-03-02 01:35:17 +01:00
if ( w - > m_fAlpha . value ( ) = = 0.f )
2022-09-19 17:26:11 +01:00
continue ;
2024-07-31 17:55:52 +00:00
if ( w - > isFullscreen ( ) | | w - > m_bIsFloating )
2022-09-19 17:26:11 +01:00
continue ;
2024-04-02 20:32:39 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-24 21:18:50 +00:00
continue ;
2024-04-27 12:43:12 +01:00
renderWindow ( w , pMonitor , time , true , RENDER_PASS_ALL ) ;
2022-09-19 17:26:11 +01:00
}
// and floating ones too
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2022-09-19 17:26:11 +01:00
continue ;
2024-03-02 01:35:17 +01:00
if ( w - > m_fAlpha . value ( ) = = 0.f )
2022-09-19 17:26:11 +01:00
continue ;
2024-07-31 17:55:52 +00:00
if ( w - > isFullscreen ( ) | | ! w - > m_bIsFloating )
2022-09-19 17:26:11 +01:00
continue ;
2024-10-27 18:45:38 +00:00
if ( w - > m_pMonitor = = pWorkspace - > m_pMonitor & & pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-24 21:18:50 +00:00
continue ;
2024-10-27 18:45:38 +00:00
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_pMonitor ! = pWorkspace - > m_pMonitor )
2023-11-24 21:18:50 +00:00
continue ; // special on another are rendered as a part of the base pass
2024-04-27 12:43:12 +01:00
renderWindow ( w , pMonitor , time , true , RENDER_PASS_ALL ) ;
2022-09-19 17:26:11 +01:00
}
2023-11-24 21:18:50 +00:00
// TODO: this pass sucks
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-02 20:32:39 +01:00
const auto PWORKSPACE = w - > m_pWorkspace ;
2022-07-28 15:56:55 +02:00
2024-07-31 17:55:52 +00:00
if ( w - > m_pWorkspace ! = pWorkspace | | ! w - > isFullscreen ( ) ) {
2022-09-19 10:23:13 +01:00
if ( ! ( PWORKSPACE & & ( PWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) | | PWORKSPACE - > m_fAlpha . isBeingAnimated ( ) | | PWORKSPACE - > m_bForceRendering ) ) )
2022-07-28 15:56:55 +02:00
continue ;
2022-08-17 12:12:16 +02:00
2024-10-27 18:45:38 +00:00
if ( w - > m_pMonitor ! = pMonitor )
2022-08-17 12:12:16 +02:00
continue ;
2022-07-28 15:56:55 +02:00
}
2022-03-21 19:18:33 +01:00
2024-07-31 17:55:52 +00:00
if ( ! w - > isFullscreen ( ) )
2022-07-28 16:33:45 +02:00
continue ;
2024-10-27 18:45:38 +00:00
if ( w - > m_pMonitor = = pWorkspace - > m_pMonitor & & pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2024-03-04 15:29:45 -08:00
continue ;
2024-04-27 12:43:12 +01:00
if ( shouldRenderWindow ( w , pMonitor ) )
2024-07-31 17:55:52 +00:00
renderWindow ( w , pMonitor , time , pWorkspace - > m_efFullscreenMode ! = FSMODE_FULLSCREEN , RENDER_PASS_ALL ) ;
2022-03-30 20:16:23 +02:00
2024-04-02 20:32:39 +01:00
if ( w - > m_pWorkspace ! = pWorkspace )
2024-01-09 20:42:07 +01:00
continue ;
2024-04-27 12:43:12 +01:00
pWorkspaceWindow = w ;
2022-03-30 20:16:23 +02:00
}
2022-10-11 20:29:37 +01:00
if ( ! pWorkspaceWindow ) {
// ?? happens sometimes...
pWorkspace - > m_bHasFullscreenWindow = false ;
return ; // this will produce one blank frame. Oh well.
}
2022-09-19 17:26:11 +01:00
// then render windows over fullscreen.
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-07-31 17:55:52 +00:00
if ( w - > m_pWorkspace ! = pWorkspaceWindow - > m_pWorkspace | | ( ! w - > m_bCreatedOverFullscreen & & ! w - > m_bPinned ) | | ( ! w - > m_bIsMapped & & ! w - > m_bFadingOut ) | | w - > isFullscreen ( ) )
2022-03-30 20:16:23 +02:00
continue ;
2024-10-27 18:45:38 +00:00
if ( w - > m_pMonitor = = pWorkspace - > m_pMonitor & & pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-24 21:18:50 +00:00
continue ;
2024-10-27 18:45:38 +00:00
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_pMonitor ! = pWorkspace - > m_pMonitor )
2023-11-24 21:18:50 +00:00
continue ; // special on another are rendered as a part of the base pass
2024-04-27 12:43:12 +01:00
renderWindow ( w , pMonitor , time , true , RENDER_PASS_ALL ) ;
2022-05-31 14:20:41 +02:00
}
2023-09-04 15:07:56 +02:00
}
2022-05-31 14:20:41 +02:00
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderWorkspaceWindows ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * time ) {
2024-04-27 12:43:12 +01:00
PHLWINDOW lastWindow ;
2022-05-31 14:20:41 +02:00
2023-09-04 15:07:56 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE_WINDOWS ) ;
2022-05-31 14:20:41 +02:00
2024-10-31 00:20:32 +01:00
std : : vector < PHLWINDOWREF > windows ;
windows . reserve ( g_pCompositor - > m_vWindows . size ( ) ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-03-14 18:25:28 +00:00
if ( w - > isHidden ( ) | | ( ! w - > m_bIsMapped & & ! w - > m_bFadingOut ) )
2023-09-04 15:07:56 +02:00
continue ;
2022-05-31 14:20:41 +02:00
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2023-09-04 15:07:56 +02:00
continue ;
2024-10-31 00:20:32 +01:00
windows . push_back ( w ) ;
}
// Non-floating main
for ( auto & w : windows ) {
if ( w - > m_bIsFloating )
continue ; // floating are in the second pass
2024-04-02 20:32:39 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-22 20:05:50 +00:00
continue ;
2023-09-04 15:07:56 +02:00
// render active window after all others of this pass
2024-05-05 17:16:00 +01:00
if ( w = = g_pCompositor - > m_pLastWindow ) {
2024-10-31 00:20:32 +01:00
lastWindow = w . lock ( ) ;
2023-09-04 15:07:56 +02:00
continue ;
}
// render the bad boy
2024-10-31 00:20:32 +01:00
renderWindow ( w . lock ( ) , pMonitor , time , true , RENDER_PASS_MAIN ) ;
2022-05-29 15:44:30 +02:00
}
2023-09-04 15:07:56 +02:00
if ( lastWindow )
renderWindow ( lastWindow , pMonitor , time , true , RENDER_PASS_MAIN ) ;
// Non-floating popup
2024-10-31 00:20:32 +01:00
for ( auto & w : windows ) {
if ( ! w )
2023-09-04 15:07:56 +02:00
continue ;
if ( w - > m_bIsFloating )
continue ; // floating are in the second pass
2024-04-02 20:32:39 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-22 20:05:50 +00:00
continue ;
2023-09-04 15:07:56 +02:00
// render the bad boy
2024-10-31 00:20:32 +01:00
renderWindow ( w . lock ( ) , pMonitor , time , true , RENDER_PASS_POPUP ) ;
w . reset ( ) ;
2022-04-25 21:49:45 +02:00
}
2023-09-04 15:07:56 +02:00
// floating on top
2024-10-31 00:20:32 +01:00
for ( auto & w : windows ) {
if ( ! w )
2023-09-04 15:07:56 +02:00
continue ;
if ( ! w - > m_bIsFloating | | w - > m_bPinned )
continue ;
2024-04-02 20:32:39 +01:00
if ( pWorkspace - > m_bIsSpecialWorkspace ! = w - > onSpecialWorkspace ( ) )
2023-11-18 19:53:45 +00:00
continue ;
2024-10-27 18:45:38 +00:00
if ( pWorkspace - > m_bIsSpecialWorkspace & & w - > m_pMonitor ! = pWorkspace - > m_pMonitor )
2023-11-24 21:18:50 +00:00
continue ; // special on another are rendered as a part of the base pass
2023-09-04 15:07:56 +02:00
// render the bad boy
2024-10-31 00:20:32 +01:00
renderWindow ( w . lock ( ) , pMonitor , time , true , RENDER_PASS_ALL ) ;
2023-09-02 20:32:10 +02:00
}
2022-03-21 19:18:33 +01:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderWindow ( PHLWINDOW pWindow , PHLMONITOR pMonitor , timespec * time , bool decorate , eRenderPassMode mode , bool ignorePosition , bool ignoreAllGeometry ) {
2022-10-14 20:46:32 +01: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 ) {
2024-10-27 18:45:38 +00:00
if ( pMonitor = = pWindow - > m_pMonitor ) // TODO: fix this
2024-04-27 12:43:12 +01:00
g_pHyprOpenGL - > renderSnapshot ( pWindow ) ;
2022-04-05 20:49:15 +02:00
return ;
}
2022-09-25 20:07:48 +02:00
2024-03-14 18:25:28 +00:00
if ( ! pWindow - > m_bIsMapped )
return ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderWindow " ) ;
2024-04-02 20:32:39 +01:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2024-03-03 18:39:20 +00:00
const auto REALPOS = pWindow - > m_vRealPosition . value ( ) + ( pWindow - > m_bPinned ? Vector2D { } : PWORKSPACE - > m_vRenderOffset . value ( ) ) ;
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
2022-06-21 22:54:41 +02:00
2024-03-03 18:39:20 +00:00
SRenderData renderdata = { pMonitor , time } ;
CBox textureBox = { REALPOS . x , REALPOS . y , std : : max ( pWindow - > m_vRealSize . value ( ) . x , 5.0 ) , std : : max ( pWindow - > m_vRealSize . value ( ) . y , 5.0 ) } ;
2023-11-04 17:03:05 +00:00
renderdata . x = textureBox . x ;
renderdata . y = textureBox . y ;
renderdata . w = textureBox . w ;
renderdata . h = textureBox . h ;
2022-11-06 17:52:09 +00:00
if ( ignorePosition ) {
2022-11-06 17:58:56 +00:00
renderdata . x = pMonitor - > vecPosition . x ;
renderdata . y = pMonitor - > vecPosition . y ;
2022-11-06 17:52:09 +00:00
}
2022-12-05 17:05:15 +00:00
if ( ignoreAllGeometry )
decorate = false ;
2024-08-28 21:54:49 +02:00
// whether to use m_fMovingToWorkspaceAlpha, only if fading out into an invisible ws
2024-11-22 16:01:02 +00:00
const bool USE_WORKSPACE_FADE_ALPHA = pWindow - > m_iMonitorMovedFrom ! = - 1 & & ( ! PWORKSPACE | | ! PWORKSPACE - > isVisible ( ) ) ;
2024-11-17 16:42:30 +00:00
const bool DONT_BLUR = pWindow - > m_sWindowData . noBlur . valueOrDefault ( ) | | pWindow - > m_sWindowData . RGBX . valueOrDefault ( ) | | pWindow - > opaque ( ) ;
2024-08-28 21:54:49 +02:00
2024-06-08 10:07:59 +02:00
renderdata . surface = pWindow - > m_pWLSurface - > resource ( ) ;
2024-07-31 17:55:52 +00:00
renderdata . dontRound = pWindow - > isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) | | pWindow - > m_sWindowData . noRounding . valueOrDefault ( ) ;
2024-08-28 21:54:49 +02:00
renderdata . fadeAlpha = pWindow - > m_fAlpha . value ( ) * ( pWindow - > m_bPinned | | USE_WORKSPACE_FADE_ALPHA ? 1.f : PWORKSPACE - > m_fAlpha . value ( ) ) *
( USE_WORKSPACE_FADE_ALPHA ? pWindow - > m_fMovingToWorkspaceAlpha . value ( ) : 1.F ) ;
renderdata . alpha = pWindow - > m_fActiveInactiveAlpha . value ( ) ;
renderdata . decorate = decorate & & ! pWindow - > m_bX11DoesntWantBorders & & ! pWindow - > isEffectiveInternalFSMode ( FSMODE_FULLSCREEN ) ;
renderdata . rounding = ignoreAllGeometry | | renderdata . dontRound ? 0 : pWindow - > rounding ( ) * pMonitor - > scale ;
2024-11-17 16:42:30 +00:00
renderdata . blur = ! ignoreAllGeometry & & * PBLUR & & ! DONT_BLUR ;
2024-08-28 21:54:49 +02:00
renderdata . pWindow = pWindow ;
2022-03-21 19:18:33 +01:00
2022-12-05 18:00:57 +00:00
if ( ignoreAllGeometry ) {
2022-12-16 17:17:31 +00:00
renderdata . alpha = 1.f ;
2023-01-05 19:25:45 +01:00
renderdata . fadeAlpha = 1.f ;
2022-12-05 18:00:57 +00:00
}
2022-07-28 12:07:41 +02:00
// apply opaque
2024-07-11 14:10:42 +00:00
if ( pWindow - > m_sWindowData . opaque . valueOrDefault ( ) )
2022-07-28 12:07:41 +02:00
renderdata . alpha = 1.f ;
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 ) ;
2024-07-11 14:10:42 +00:00
if ( * PDIMAROUND & & pWindow - > m_sWindowData . dimAround . valueOrDefault ( ) & & ! m_bRenderingSnapshot & & mode ! = RENDER_PASS_POPUP ) {
2023-11-04 17:03:05 +00:00
CBox monbox = { 0 , 0 , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . x , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . y } ;
2024-12-03 18:58:24 +00:00
g_pHyprOpenGL - > renderRect ( & monbox , CHyprColor ( 0 , 0 , 0 , * PDIMAROUND * renderdata . alpha * renderdata . fadeAlpha ) ) ;
2022-12-28 15:39:17 +01:00
}
2024-03-30 18:14:26 -07:00
renderdata . x + = pWindow - > m_vFloatingOffset . x ;
renderdata . y + = pWindow - > m_vFloatingOffset . y ;
2022-12-16 17:17:31 +00:00
2023-11-16 20:20:41 +00:00
// if window is floating and we have a slide animation, clip it to its full bb
2024-07-31 17:55:52 +00:00
if ( ! ignorePosition & & pWindow - > m_bIsFloating & & ! pWindow - > isFullscreen ( ) & & PWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) & & ! pWindow - > m_bPinned ) {
2024-03-30 18:14:26 -07:00
CRegion rg =
pWindow - > getFullWindowBoundingBox ( ) . translate ( - pMonitor - > vecPosition + PWORKSPACE - > m_vRenderOffset . value ( ) + pWindow - > m_vFloatingOffset ) . scale ( pMonitor - > scale ) ;
2023-11-18 17:00:24 +00:00
g_pHyprOpenGL - > m_RenderData . clipBox = rg . getExtents ( ) ;
}
2023-11-16 20:20:41 +00:00
2022-06-28 15:45:38 +02:00
// render window decorations first, if not fullscreen full
2022-07-12 09:49:56 +02:00
if ( mode = = RENDER_PASS_ALL | | mode = = RENDER_PASS_MAIN ) {
2023-10-21 14:15:48 +01:00
const bool TRANSFORMERSPRESENT = ! pWindow - > m_vTransformers . empty ( ) ;
2023-10-21 19:25:44 +01:00
if ( TRANSFORMERSPRESENT ) {
2023-10-21 14:15:48 +01:00
g_pHyprOpenGL - > bindOffMain ( ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & t : pWindow - > m_vTransformers ) {
2023-10-21 19:25:44 +01:00
t - > preWindowRender ( & renderdata ) ;
}
}
2024-04-13 23:16:26 +00:00
if ( renderdata . decorate ) {
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations ) {
2023-11-04 13:10:52 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_BOTTOM )
continue ;
2024-03-30 18:14:26 -07:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha ) ;
2023-11-04 13:10:52 +00:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations ) {
2023-11-04 13:10:52 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_UNDER )
continue ;
2024-03-30 18:14:26 -07:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha ) ;
2023-11-04 13:10:52 +00:00
}
}
2022-06-22 15:45:56 +02:00
2024-03-03 18:39:20 +00:00
static auto PXWLUSENN = CConfigValue < Hyprlang : : INT > ( " xwayland:use_nearest_neighbor " ) ;
2024-07-11 14:10:42 +00:00
if ( ( pWindow - > m_bIsX11 & & * PXWLUSENN ) | | pWindow - > m_sWindowData . nearestNeighbor . valueOrDefault ( ) )
2023-06-11 21:33:50 +02:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = true ;
2024-07-11 14:10:42 +00:00
if ( ! pWindow - > m_sWindowData . noBlur . valueOrDefault ( ) & & pWindow - > m_pWLSurface - > small ( ) & & ! pWindow - > m_pWLSurface - > m_bFillIgnoreSmall & & renderdata . blur & & * PBLUR ) {
2023-11-04 17:03:05 +00:00
CBox wb = { renderdata . x - pMonitor - > vecPosition . x , renderdata . y - pMonitor - > vecPosition . y , renderdata . w , renderdata . h } ;
wb . scale ( pMonitor - > scale ) . round ( ) ;
2024-12-03 18:58:24 +00:00
g_pHyprOpenGL - > renderRectWithBlur ( & wb , CHyprColor ( 0 , 0 , 0 , 0 ) , renderdata . dontRound ? 0 : renderdata . rounding - 1 , renderdata . fadeAlpha ,
2023-12-06 20:17:40 +00:00
g_pHyprOpenGL - > shouldUseNewBlurOptimizations ( nullptr , pWindow ) ) ;
2023-10-25 22:20:58 +01:00
renderdata . blur = false ;
}
2024-06-17 12:42:32 +02:00
renderdata . surfaceCounter = 0 ;
2024-06-08 10:07:59 +02:00
pWindow - > m_pWLSurface - > resource ( ) - > breadthfirst ( [ ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) { renderSurface ( s , offset . x , offset . y , data ) ; } ,
& renderdata ) ;
2022-07-12 09:49:56 +02:00
2023-06-11 21:33:50 +02:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = false ;
2024-04-13 23:16:26 +00:00
if ( renderdata . decorate ) {
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations ) {
2023-12-11 16:32:00 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_OVER )
continue ;
2023-11-04 13:10:52 +00:00
2024-03-30 18:14:26 -07:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha ) ;
2023-12-11 16:32:00 +00:00
}
2023-11-04 13:10:52 +00:00
}
2023-10-21 14:15:48 +01:00
if ( TRANSFORMERSPRESENT ) {
CFramebuffer * last = g_pHyprOpenGL - > m_RenderData . currentFB ;
2024-08-26 20:24:30 +02:00
for ( auto const & t : pWindow - > m_vTransformers ) {
2023-10-21 14:15:48 +01:00
last = t - > transform ( last ) ;
}
g_pHyprOpenGL - > bindBackOnMain ( ) ;
g_pHyprOpenGL - > renderOffToMain ( last ) ;
}
2022-06-22 15:45:56 +02:00
}
2023-11-16 20:20:41 +00:00
g_pHyprOpenGL - > m_RenderData . clipBox = CBox ( ) ;
2022-07-12 09:49:56 +02:00
if ( mode = = RENDER_PASS_ALL | | mode = = RENDER_PASS_POPUP ) {
if ( ! pWindow - > m_bIsX11 ) {
2024-05-10 23:28:33 +01:00
CBox geom = pWindow - > m_pXDGSurface - > current . geometry ;
2022-08-28 10:14:43 +02:00
renderdata . x - = geom . x ;
renderdata . y - = geom . y ;
2022-12-16 17:17:31 +00:00
renderdata . dontRound = true ; // don't round popups
renderdata . pMonitor = pMonitor ;
2022-07-15 19:07:06 +02:00
renderdata . squishOversized = false ; // don't squish popups
2023-12-25 18:04:00 +01:00
renderdata . popup = true ;
2023-10-24 21:28:55 +01:00
2024-03-25 16:08:55 +00:00
static CConfigValue PBLURPOPUPS = CConfigValue < Hyprlang : : INT > ( " decoration:blur:popups " ) ;
static CConfigValue PBLURIGNOREA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:popups_ignorealpha " ) ;
2024-11-17 16:42:30 +00:00
renderdata . blur = * PBLURPOPUPS & & * PBLUR ;
2024-03-25 16:08:55 +00:00
const auto DM = g_pHyprOpenGL - > m_RenderData . discardMode ;
const auto DA = g_pHyprOpenGL - > m_RenderData . discardOpacity ;
if ( renderdata . blur ) {
g_pHyprOpenGL - > m_RenderData . discardMode | = DISCARD_ALPHA ;
g_pHyprOpenGL - > m_RenderData . discardOpacity = * PBLURIGNOREA ;
}
2024-07-11 14:10:42 +00:00
if ( pWindow - > m_sWindowData . nearestNeighbor . valueOrDefault ( ) )
2023-10-24 21:28:55 +01:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = true ;
2024-06-17 12:42:32 +02:00
renderdata . surfaceCounter = 0 ;
2024-05-10 23:28:33 +01:00
pWindow - > m_pPopupHead - > breadthfirst (
[ ] ( CPopup * popup , void * data ) {
2024-11-17 16:16:49 +00:00
if ( ! popup - > m_pWLSurface | | ! popup - > m_pWLSurface - > resource ( ) | | ! popup - > m_bMapped )
2024-05-10 23:28:33 +01:00
return ;
2024-11-17 16:42:30 +00:00
const auto pos = popup - > coordsRelativeToParent ( ) ;
auto rd = ( SRenderData * ) data ;
const Vector2D oldPos = { rd - > x , rd - > y } ;
2024-05-10 23:28:33 +01:00
rd - > x + = pos . x ;
rd - > y + = pos . y ;
2024-11-17 16:42:30 +00:00
2024-06-08 10:07:59 +02:00
popup - > m_pWLSurface - > resource ( ) - > breadthfirst ( [ ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) { renderSurface ( s , offset . x , offset . y , data ) ; } ,
data ) ;
2024-11-17 16:42:30 +00:00
2024-05-10 23:28:33 +01:00
rd - > x = oldPos . x ;
rd - > y = oldPos . y ;
} ,
& renderdata ) ;
2023-10-24 21:28:55 +01:00
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = false ;
2024-03-25 16:08:55 +00:00
g_pHyprOpenGL - > m_RenderData . discardMode = DM ;
g_pHyprOpenGL - > m_RenderData . discardOpacity = DA ;
2022-07-12 09:49:56 +02:00
}
2023-11-04 13:10:52 +00:00
2023-12-11 16:32:00 +00:00
if ( decorate ) {
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations ) {
2023-12-11 16:32:00 +00:00
if ( wd - > getDecorationLayer ( ) ! = DECORATION_LAYER_OVERLAY )
continue ;
2023-11-04 13:10:52 +00:00
2024-03-30 18:14:26 -07:00
wd - > draw ( pMonitor , renderdata . alpha * renderdata . fadeAlpha ) ;
2023-12-11 16:32:00 +00:00
}
2023-11-04 13:10:52 +00:00
}
2022-05-17 13:16:37 +02:00
}
2023-05-26 13:07:45 +02:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WINDOW ) ;
2024-04-27 12:43:12 +01:00
g_pHyprOpenGL - > m_pCurrentWindow . reset ( ) ;
2023-11-16 20:20:41 +00:00
g_pHyprOpenGL - > m_RenderData . clipBox = CBox ( ) ;
2022-03-21 19:18:33 +01:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderLayer ( PHLLS pLayer , PHLMONITOR pMonitor , timespec * time , bool popups ) {
2024-08-07 13:31:27 +02:00
if ( ! pLayer )
return ;
2024-04-11 21:41:18 +10:00
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
if ( * PDIMAROUND & & pLayer - > dimAround & & ! m_bRenderingSnapshot & & ! popups ) {
CBox monbox = { 0 , 0 , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . x , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecTransformedSize . y } ;
2024-12-03 18:58:24 +00:00
g_pHyprOpenGL - > renderRect ( & monbox , CHyprColor ( 0 , 0 , 0 , * PDIMAROUND * pLayer - > alpha . value ( ) ) ) ;
2024-04-11 21:41:18 +10:00
}
2022-05-14 17:23:46 +02:00
if ( pLayer - > fadingOut ) {
2024-04-04 22:43:57 +01:00
if ( ! popups )
2024-04-30 02:41:27 +01:00
g_pHyprOpenGL - > renderSnapshot ( pLayer ) ;
2022-05-14 17:23:46 +02:00
return ;
}
2024-11-17 16:42:30 +00:00
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderLayer " ) ;
2024-03-02 01:35:17 +01:00
const auto REALPOS = pLayer - > realPosition . value ( ) ;
const auto REALSIZ = pLayer - > realSize . value ( ) ;
2024-02-28 15:00:34 +00:00
SRenderData renderdata = { pMonitor , time , REALPOS . x , REALPOS . y } ;
2024-03-02 01:35:17 +01:00
renderdata . fadeAlpha = pLayer - > alpha . value ( ) ;
2024-11-17 16:42:30 +00:00
renderdata . blur = pLayer - > forceBlur & & * PBLUR ;
2024-06-08 10:07:59 +02:00
renderdata . surface = pLayer - > surface - > resource ( ) ;
2022-12-16 17:17:31 +00:00
renderdata . decorate = false ;
2024-02-28 15:00:34 +00:00
renderdata . w = REALSIZ . x ;
renderdata . h = REALSIZ . y ;
2022-12-04 22:57:41 +02:00
renderdata . blockBlurOptimization = pLayer - > layer = = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM | | pLayer - > layer = = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ;
2023-03-17 23:16:13 +00:00
2024-02-28 15:00:34 +00: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 ;
2024-03-25 16:08:55 +00:00
const auto DM = g_pHyprOpenGL - > m_RenderData . discardMode ;
const auto DA = g_pHyprOpenGL - > m_RenderData . discardOpacity ;
if ( renderdata . blur & & pLayer - > ignoreAlpha ) {
2023-06-12 00:30:31 +07:00
g_pHyprOpenGL - > m_RenderData . discardMode | = DISCARD_ALPHA ;
g_pHyprOpenGL - > m_RenderData . discardOpacity = pLayer - > ignoreAlphaValue ;
}
2024-03-25 16:08:55 +00:00
2024-03-25 16:20:30 +00:00
if ( ! popups )
2024-06-08 10:07:59 +02:00
pLayer - > surface - > resource ( ) - > breadthfirst ( [ ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) { renderSurface ( s , offset . x , offset . y , data ) ; } , & renderdata ) ;
2022-07-27 18:02:20 +02:00
2022-12-16 17:17:31 +00:00
renderdata . squishOversized = false ; // don't squish popups
renderdata . dontRound = true ;
2023-12-25 18:04:00 +01:00
renderdata . popup = true ;
2024-03-25 16:08:55 +00:00
renderdata . blur = pLayer - > forceBlurPopups ;
2024-06-17 12:42:32 +02:00
renderdata . surfaceCounter = 0 ;
2024-05-09 21:47:21 +01:00
if ( popups ) {
pLayer - > popupHead - > breadthfirst (
[ ] ( CPopup * popup , void * data ) {
2024-11-17 16:16:49 +00:00
if ( ! popup - > m_pWLSurface | | ! popup - > m_pWLSurface - > resource ( ) | | ! popup - > m_bMapped )
2024-05-09 21:47:21 +01:00
return ;
Vector2D pos = popup - > coordsRelativeToParent ( ) ;
2024-06-08 10:07:59 +02:00
renderSurface ( popup - > m_pWLSurface - > resource ( ) , pos . x , pos . y , data ) ;
2024-05-09 21:47:21 +01:00
} ,
& renderdata ) ;
}
2023-08-09 22:03:24 +02:00
2024-03-25 16:08:55 +00:00
g_pHyprOpenGL - > m_pCurrentLayer = nullptr ;
g_pHyprOpenGL - > m_RenderData . clipBox = { } ;
g_pHyprOpenGL - > m_RenderData . discardMode = DM ;
g_pHyprOpenGL - > m_RenderData . discardOpacity = DA ;
2022-05-14 17:23:46 +02:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderIMEPopup ( CInputPopup * pPopup , PHLMONITOR pMonitor , timespec * time ) {
2024-03-24 16:08:25 +00:00
const auto POS = pPopup - > globalBox ( ) . pos ( ) ;
SRenderData renderdata = { pMonitor , time , POS . x , POS . y } ;
2024-06-08 10:07:59 +02:00
const auto SURF = pPopup - > getSurface ( ) ;
2022-08-05 17:07:01 +02:00
2024-03-24 16:08:25 +00:00
renderdata . surface = SURF ;
2022-08-05 17:07:01 +02:00
renderdata . decorate = false ;
2024-06-08 10:07:59 +02:00
renderdata . w = SURF - > current . size . x ;
renderdata . h = SURF - > current . size . y ;
2022-08-05 17:07:01 +02:00
2024-11-23 09:29:29 -05:00
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
static auto PBLURIMES = CConfigValue < Hyprlang : : INT > ( " decoration:blur:input_methods " ) ;
static auto PBLURIGNOREA = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:input_methods_ignorealpha " ) ;
2024-11-28 23:51:53 +00:00
// TODO: make push/pop methods for this.
const auto DM = g_pHyprOpenGL - > m_RenderData . discardMode ;
const auto DA = g_pHyprOpenGL - > m_RenderData . discardOpacity ;
2024-11-23 09:29:29 -05:00
renderdata . blur = * PBLURIMES & & * PBLUR ;
if ( renderdata . blur ) {
g_pHyprOpenGL - > m_RenderData . discardMode | = DISCARD_ALPHA ;
g_pHyprOpenGL - > m_RenderData . discardOpacity = * PBLURIGNOREA ;
}
2024-06-08 10:07:59 +02:00
SURF - > breadthfirst ( [ ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) { renderSurface ( s , offset . x , offset . y , data ) ; } , & renderdata ) ;
2024-11-28 23:51:53 +00:00
g_pHyprOpenGL - > m_RenderData . discardMode = DM ;
g_pHyprOpenGL - > m_RenderData . discardOpacity = DA ;
2022-08-05 17:07:01 +02:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderSessionLockSurface ( SSessionLockSurface * pSurface , PHLMONITOR pMonitor , timespec * time ) {
2023-02-03 14:00:23 +00:00
SRenderData renderdata = { pMonitor , time , pMonitor - > vecPosition . x , pMonitor - > vecPosition . y } ;
2023-02-03 11:58:55 +00:00
renderdata . blur = false ;
2024-05-05 17:16:00 +01:00
renderdata . surface = pSurface - > surface - > surface ( ) ;
2023-02-03 11:58:55 +00:00
renderdata . decorate = false ;
renderdata . w = pMonitor - > vecSize . x ;
renderdata . h = pMonitor - > vecSize . y ;
2024-06-08 10:07:59 +02:00
renderdata . surface - > breadthfirst ( [ ] ( SP < CWLSurfaceResource > s , const Vector2D & offset , void * data ) { renderSurface ( s , offset . x , offset . y , data ) ; } , & renderdata ) ;
2023-02-03 11:58:55 +00:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderAllClientsForWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * time , const Vector2D & translate , const float & scale ) {
2024-03-03 18:39:20 +00:00
static auto PDIMSPECIAL = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_special " ) ;
static auto PBLURSPECIAL = CConfigValue < Hyprlang : : INT > ( " decoration:blur:special " ) ;
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
static auto PRENDERTEX = CConfigValue < Hyprlang : : INT > ( " misc:disable_hyprland_logo " ) ;
static auto PBACKGROUNDCOLOR = CConfigValue < Hyprlang : : INT > ( " misc:background_color " ) ;
2024-01-07 18:35:44 +01:00
2024-03-03 18:39:20 +00:00
SRenderModifData RENDERMODIFDATA ;
2024-01-07 18:35:44 +01:00
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 12:41:23 +01:00
if ( ! pMonitor )
2022-03-17 20:22:29 +01:00
return ;
2024-04-30 16:32:05 +01:00
if ( g_pSessionLockManager - > isSessionLocked ( ) & & ! g_pSessionLockManager - > isSessionLockPresent ( ) ) {
2023-02-03 11:58:55 +00:00
// locked with no exclusive, draw only red
2024-08-29 23:30:12 +02:00
renderSessionLockMissing ( pMonitor ) ;
2023-02-03 11:58:55 +00:00
return ;
}
2023-04-12 12:41:23 +01:00
// todo: matrices are buggy atm for some reason, but probably would be preferable in the long run
// g_pHyprOpenGL->saveMatrix();
// g_pHyprOpenGL->setMatrixScaleTranslate(translate, scale);
g_pHyprOpenGL - > m_RenderData . renderModif = RENDERMODIFDATA ;
2024-04-03 14:09:58 +01:00
if ( ! pWorkspace ) {
// allow rendering without a workspace. In this case, just render layers.
2024-04-03 14:28:15 +01:00
g_pHyprOpenGL - > blend ( false ) ;
if ( ! canSkipBackBufferClear ( pMonitor ) ) {
if ( * PRENDERTEX /* inverted cfg flag */ )
2024-12-03 18:58:24 +00:00
g_pHyprOpenGL - > clear ( CHyprColor ( * PBACKGROUNDCOLOR ) ) ;
2024-04-03 14:28:15 +01:00
else
g_pHyprOpenGL - > clearWithTex ( ) ; // will apply the hypr "wallpaper"
}
2024-04-03 14:09:58 +01:00
g_pHyprOpenGL - > blend ( true ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2024-04-03 14:09:58 +01:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2024-04-03 14:09:58 +01:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2024-04-03 14:09:58 +01:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2024-04-03 14:09:58 +01:00
}
g_pHyprOpenGL - > m_RenderData . renderModif = { } ;
return ;
}
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 12:36:50 +01: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.
2024-11-22 16:01:02 +00:00
const auto PFULLWINDOW = pWorkspace ? pWorkspace - > getFullscreenWindow ( ) : nullptr ;
2024-07-31 17:55:52 +00:00
if ( ! pWorkspace - > m_bHasFullscreenWindow | | pWorkspace - > m_efFullscreenMode ! = FSMODE_FULLSCREEN | | ! PFULLWINDOW | | PFULLWINDOW - > m_vRealSize . isBeingAnimated ( ) | |
2024-07-02 18:40:21 +02:00
! PFULLWINDOW - > opaque ( ) | | pWorkspace - > m_vRenderOffset . value ( ) ! = Vector2D { } | | g_pHyprOpenGL - > preBlurQueued ( ) ) {
2023-07-19 16:13:55 +02:00
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 15:06:42 +00:00
g_pHyprOpenGL - > blend ( false ) ;
if ( ! canSkipBackBufferClear ( pMonitor ) ) {
2024-03-03 18:39:20 +00:00
if ( * PRENDERTEX /* inverted cfg flag */ )
2024-12-03 18:58:24 +00:00
g_pHyprOpenGL - > clear ( CHyprColor ( * PBACKGROUNDCOLOR ) ) ;
2023-11-26 15:06:42 +00:00
else
g_pHyprOpenGL - > clearWithTex ( ) ; // will apply the hypr "wallpaper"
}
g_pHyprOpenGL - > blend ( true ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2023-04-22 12:36:50 +01:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2023-04-22 12:36:50 +01:00
}
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 ;
2022-05-31 14:01:00 +02:00
// and then special
2024-08-26 17:25:39 +02:00
for ( auto const & ws : g_pCompositor - > m_vWorkspaces ) {
2024-10-27 18:45:38 +00:00
if ( ws - > m_pMonitor = = pMonitor & & ws - > m_fAlpha . value ( ) > 0.f & & ws - > m_bIsSpecialWorkspace ) {
2023-08-25 18:05:08 +02:00
const auto SPECIALANIMPROGRS = ws - > m_vRenderOffset . isBeingAnimated ( ) ? ws - > m_vRenderOffset . getCurveValue ( ) : ws - > m_fAlpha . getCurveValue ( ) ;
2024-04-02 20:32:39 +01:00
const bool ANIMOUT = ! pMonitor - > activeSpecialWorkspace ;
2022-12-28 15:18:23 +01:00
2024-03-03 18:39:20 +00:00
if ( * PDIMSPECIAL ! = 0.f ) {
2023-11-04 17:03:05 +00:00
CBox monbox = { translate . x , translate . y , pMonitor - > vecTransformedSize . x * scale , pMonitor - > vecTransformedSize . y * scale } ;
2024-12-03 18:58:24 +00:00
g_pHyprOpenGL - > renderRect ( & monbox , CHyprColor ( 0 , 0 , 0 , * PDIMSPECIAL * ( ANIMOUT ? ( 1.0 - SPECIALANIMPROGRS ) : SPECIALANIMPROGRS ) ) ) ;
2022-12-28 15:18:23 +01:00
}
2024-03-03 18:39:20 +00:00
if ( * PBLURSPECIAL & & * PBLUR ) {
2023-11-04 17:03:05 +00:00
CBox monbox = { translate . x , translate . y , pMonitor - > vecTransformedSize . x * scale , pMonitor - > vecTransformedSize . y * scale } ;
2024-12-03 18:58:24 +00:00
g_pHyprOpenGL - > renderRectWithBlur ( & monbox , CHyprColor ( 0 , 0 , 0 , 0 ) , 0 , ( ANIMOUT ? ( 1.0 - SPECIALANIMPROGRS ) : SPECIALANIMPROGRS ) ) ;
2023-08-25 17:43:23 +02:00
}
2023-08-25 18:05:08 +02:00
break ;
2022-12-28 15:18:23 +01:00
}
2023-08-25 18:05:08 +02:00
}
2023-11-18 17:00:24 +00:00
// special
2024-08-26 17:25:39 +02:00
for ( auto const & ws : g_pCompositor - > m_vWorkspaces ) {
2024-03-16 07:49:34 -07:00
if ( ws - > m_fAlpha . value ( ) > 0.f & & ws - > m_bIsSpecialWorkspace ) {
2024-03-04 15:29:45 -08:00
if ( ws - > m_bHasFullscreenWindow )
2024-04-02 20:32:39 +01:00
renderWorkspaceWindowsFullscreen ( pMonitor , ws , time ) ;
2024-03-04 15:29:45 -08:00
else
2024-04-02 20:32:39 +01:00
renderWorkspaceWindows ( pMonitor , ws , time ) ;
2024-03-04 15:29:45 -08:00
}
2022-03-18 20:03:39 +01:00
}
2022-03-19 13:35:04 +01:00
2023-11-22 20:05:50 +00:00
// pinned always above
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2023-11-22 20:05:50 +00:00
if ( w - > isHidden ( ) & & ! w - > m_bIsMapped & & ! w - > m_bFadingOut )
continue ;
if ( ! w - > m_bPinned | | ! w - > m_bIsFloating )
continue ;
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2023-11-22 20:05:50 +00:00
continue ;
// render the bad boy
2024-04-27 12:43:12 +01:00
renderWindow ( w , pMonitor , time , true , RENDER_PASS_ALL ) ;
2023-11-22 20:05:50 +00:00
}
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST_WINDOWS ) ;
2022-03-19 13:35:04 +01:00
// Render surfaces above windows for monitor
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2022-03-19 13:35:04 +01:00
}
2022-08-05 17:07:01 +02:00
// Render IME popups
2024-08-26 20:24:30 +02:00
for ( auto const & imep : g_pInputManager - > m_sIMERelay . m_vIMEPopups ) {
2024-03-24 16:08:25 +00:00
renderIMEPopup ( imep . get ( ) , pMonitor , time ) ;
2022-08-05 17:07:01 +02:00
}
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time ) ;
2022-03-19 13:35:04 +01:00
}
2022-03-31 17:25:23 +02:00
2024-08-26 20:24:30 +02:00
for ( auto const & lsl : pMonitor - > m_aLayerSurfaceLayers ) {
for ( auto const & ls : lsl ) {
2024-05-09 21:47:21 +01:00
renderLayer ( ls . lock ( ) , pMonitor , time , true ) ;
2024-03-25 16:20:30 +00:00
}
}
2023-04-12 12:41:23 +01:00
renderDragIcon ( pMonitor , time ) ;
//g_pHyprOpenGL->restoreMatrix();
g_pHyprOpenGL - > m_RenderData . renderModif = { } ;
}
2023-02-03 11:58:55 +00:00
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderLockscreen ( PHLMONITOR pMonitor , timespec * now , const CBox & geometry ) {
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderLockscreen " ) ;
2023-02-03 11:58:55 +00:00
if ( g_pSessionLockManager - > isSessionLocked ( ) ) {
2024-03-15 17:17:13 +01:00
Vector2D translate = { geometry . x , geometry . y } ;
2023-02-03 11:58:55 +00:00
2024-03-15 17:17:13 +01:00
const auto PSLS = g_pSessionLockManager - > getSessionLockSurfaceForMonitor ( pMonitor - > ID ) ;
2024-11-17 15:58:18 +00:00
if ( ! PSLS ) {
if ( g_pSessionLockManager - > shallConsiderLockMissing ( ) )
renderSessionLockMissing ( pMonitor ) ;
} else {
2023-04-12 12:41:23 +01:00
renderSessionLockSurface ( PSLS , pMonitor , now ) ;
2024-07-13 18:32:08 +08:00
g_pSessionLockManager - > onLockscreenRenderedOnMonitor ( pMonitor - > ID ) ;
2023-02-03 11:58:55 +00:00
}
}
2022-03-17 20:22:29 +01:00
}
2022-03-19 14:07:18 +01:00
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderSessionLockMissing ( PHLMONITOR pMonitor ) {
2024-08-29 23:30:12 +02:00
const auto ALPHA = g_pSessionLockManager - > getRedScreenAlphaForMonitor ( pMonitor - > ID ) ;
CBox monbox = { { } , pMonitor - > vecPixelSize } ;
const bool ANY_PRESENT = g_pSessionLockManager - > anySessionLockSurfacesPresent ( ) ;
if ( ANY_PRESENT ) {
// render image2, without instructions. Lock still "alive", unless texture dead
2024-11-01 15:52:03 +00:00
g_pHyprOpenGL - > renderTexture ( g_pHyprOpenGL - > m_pLockDead2Texture , & monbox , ALPHA ) ;
2024-08-29 23:30:12 +02:00
} else {
// render image, with instructions. Lock is gone.
2024-11-01 15:52:03 +00:00
g_pHyprOpenGL - > renderTexture ( g_pHyprOpenGL - > m_pLockDeadTexture , & monbox , ALPHA ) ;
2024-08-29 23:30:12 +02:00
2024-11-01 15:52:03 +00:00
// also render text for the tty number
if ( g_pHyprOpenGL - > m_pLockTtyTextTexture ) {
CBox texbox = { { } , g_pHyprOpenGL - > m_pLockTtyTextTexture - > m_vSize } ;
g_pHyprOpenGL - > renderTexture ( g_pHyprOpenGL - > m_pLockTtyTextTexture , & texbox , 1.F ) ;
}
2024-08-29 23:30:12 +02:00
}
if ( ALPHA < 1.f ) /* animate */
damageMonitor ( pMonitor ) ;
else
g_pSessionLockManager - > onLockscreenRenderedOnMonitor ( pMonitor - > ID ) ;
}
2024-10-26 02:06:13 +01:00
void CHyprRenderer : : calculateUVForSurface ( PHLWINDOW pWindow , SP < CWLSurfaceResource > pSurface , PHLMONITOR pMonitor , bool main , const Vector2D & projSize ,
2024-10-05 00:52:53 +01:00
const Vector2D & projSizeUnscaled , bool fixMisalignedFSV1 ) {
2023-01-29 13:58:47 +00:00
if ( ! pWindow | | ! pWindow - > m_bIsX11 ) {
2024-11-04 19:42:47 +00:00
static auto PEXPANDEDGES = CConfigValue < Hyprlang : : INT > ( " render:expand_undersized_textures " ) ;
Vector2D uvTL ;
Vector2D uvBR = Vector2D ( 1 , 1 ) ;
2022-08-28 10:14:43 +02:00
2024-06-08 10:07:59 +02:00
if ( pSurface - > current . viewport . hasSource ) {
2023-01-20 19:44:30 +01:00
// we stretch it to dest. if no dest, to 1,1
2024-10-31 00:20:32 +01:00
Vector2D const & bufferSize = pSurface - > current . bufferSize ;
auto const & bufferSource = pSurface - > current . viewport . source ;
2022-08-28 10:14:43 +02:00
2023-01-29 15:58:36 +00:00
// calculate UV for the basic src_box. Assume dest == size. Scale to dest later
2023-01-20 19:44:30 +01:00
uvTL = Vector2D ( bufferSource . x / bufferSize . x , bufferSource . y / bufferSize . y ) ;
uvBR = Vector2D ( ( bufferSource . x + bufferSource . width ) / bufferSize . x , ( bufferSource . y + bufferSource . height ) / bufferSize . y ) ;
2022-08-28 10:14:43 +02:00
2022-08-28 14:32:06 +02:00
if ( uvBR . x < 0.01f | | uvBR . y < 0.01f ) {
uvTL = Vector2D ( ) ;
2022-12-16 17:17:31 +00:00
uvBR = Vector2D ( 1 , 1 ) ;
2022-08-28 14:32:06 +02:00
}
2022-08-28 10:14:43 +02:00
}
2024-01-28 23:42:39 +00:00
if ( projSize ! = Vector2D { } & & fixMisalignedFSV1 ) {
// instead of nearest_neighbor (we will repeat / skip)
// just cut off / expand surface
2024-07-31 20:47:26 +01:00
const Vector2D PIXELASUV = Vector2D { 1 , 1 } / pSurface - > current . bufferSize ;
const Vector2D MISALIGNMENT = pSurface - > current . bufferSize - projSize ;
2024-01-28 23:42:39 +00:00
if ( MISALIGNMENT ! = Vector2D { } )
uvBR - = MISALIGNMENT * PIXELASUV ;
}
2024-10-05 00:52:53 +01:00
// if the surface is smaller than our viewport, extend its edges.
// this will break if later on xdg geometry is hit, but we really try
// to let the apps know to NOT add CSD. Also if source is there.
// there is no way to fix this if that's the case
2024-11-04 19:42:47 +00:00
if ( * PEXPANDEDGES ) {
const auto MONITOR_WL_SCALE = std : : ceil ( pMonitor - > scale ) ;
const bool SCALE_UNAWARE = MONITOR_WL_SCALE ! = pSurface - > current . scale & & ! pSurface - > current . viewport . hasDestination ;
const auto EXPECTED_SIZE =
( ( pSurface - > current . viewport . hasDestination ? pSurface - > current . viewport . destination : pSurface - > current . bufferSize / pSurface - > current . scale ) * pMonitor - > scale )
. round ( ) ;
if ( ! SCALE_UNAWARE & & ( EXPECTED_SIZE . x < projSize . x | | EXPECTED_SIZE . y < projSize . y ) ) {
// this will not work with shm AFAIK, idk why.
// NOTE: this math is wrong if we have a source... or geom updates later, but I don't think we can do much
const auto FIX = projSize / EXPECTED_SIZE ;
uvBR = uvBR * FIX ;
}
2024-10-05 00:52:53 +01:00
}
2022-12-16 17:17:31 +00:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = uvTL ;
2022-08-28 10:14:43 +02:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = uvBR ;
if ( g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = = Vector2D ( ) & & g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = = Vector2D ( 1 , 1 ) ) {
// No special UV mods needed
2022-12-16 17:17:31 +00:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:14:43 +02:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
}
2023-01-29 13:58:47 +00:00
if ( ! main | | ! pWindow )
2023-01-20 19:44:30 +01:00
return ;
2022-08-28 10:14:43 +02:00
2024-05-10 23:28:33 +01:00
CBox geom = pWindow - > m_pXDGSurface - > current . geometry ;
2023-01-20 19:44:30 +01:00
// ignore X and Y, adjust uv
2024-10-05 00:52:53 +01:00
if ( geom . x ! = 0 | | geom . y ! = 0 | | geom . width > projSizeUnscaled . x | | geom . height > projSizeUnscaled . y ) {
2024-06-08 10:07:59 +02:00
const auto XPERC = ( double ) geom . x / ( double ) pSurface - > current . size . x ;
const auto YPERC = ( double ) geom . y / ( double ) pSurface - > current . size . y ;
const auto WPERC = ( double ) ( geom . x + geom . width ) / ( double ) pSurface - > current . size . x ;
const auto HPERC = ( double ) ( geom . y + geom . height ) / ( double ) pSurface - > current . size . y ;
2022-08-28 10:14:43 +02:00
2023-01-20 19:44:30 +01:00
const auto TOADDTL = Vector2D ( XPERC * ( uvBR . x - uvTL . x ) , YPERC * ( uvBR . y - uvTL . y ) ) ;
2024-10-03 22:00:44 +00:00
uvBR = uvBR - Vector2D ( ( 1.0 - WPERC ) * ( uvBR . x - uvTL . x ) , ( 1.0 - HPERC ) * ( uvBR . y - uvTL . y ) ) ;
2023-01-20 19:44:30 +01:00
uvTL = uvTL + TOADDTL ;
2022-08-28 10:14:43 +02:00
2024-10-05 00:52:53 +01:00
auto maxSize = projSizeUnscaled ;
2023-11-12 23:57:53 +00:00
2024-06-08 10:07:59 +02:00
if ( pWindow - > m_pWLSurface - > small ( ) & & ! pWindow - > m_pWLSurface - > m_bFillIgnoreSmall )
maxSize = pWindow - > m_pWLSurface - > getViewporterCorrectedSize ( ) ;
2023-11-12 23:57:53 +00:00
if ( geom . width > maxSize . x )
uvBR . x = uvBR . x * ( maxSize . x / geom . width ) ;
if ( geom . height > maxSize . y )
uvBR . y = uvBR . y * ( maxSize . y / geom . height ) ;
2023-01-20 19:44:30 +01:00
}
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = uvTL ;
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = uvBR ;
if ( g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = = Vector2D ( ) & & g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = = Vector2D ( 1 , 1 ) ) {
// No special UV mods needed
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:14:43 +02:00
}
} else {
2022-12-16 17:17:31 +00:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVTopLeft = Vector2D ( - 1 , - 1 ) ;
2022-08-28 10:14:43 +02:00
g_pHyprOpenGL - > m_RenderData . primarySurfaceUVBottomRight = Vector2D ( - 1 , - 1 ) ;
}
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderMonitor ( PHLMONITOR pMonitor ) {
2023-11-24 10:54:21 +00:00
static std : : chrono : : high_resolution_clock : : time_point renderStart = std : : chrono : : high_resolution_clock : : now ( ) ;
static std : : chrono : : high_resolution_clock : : time_point renderStartOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-03-24 19:23:16 +00:00
static std : : chrono : : high_resolution_clock : : time_point endRenderOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
2024-03-03 18:39:20 +00:00
static auto PDEBUGOVERLAY = CConfigValue < Hyprlang : : INT > ( " debug:overlay " ) ;
static auto PDAMAGETRACKINGMODE = CConfigValue < Hyprlang : : INT > ( " debug:damage_tracking " ) ;
static auto PDAMAGEBLINK = CConfigValue < Hyprlang : : INT > ( " debug:damage_blink " ) ;
2024-08-06 14:52:19 +01:00
static auto PDIRECTSCANOUT = CConfigValue < Hyprlang : : INT > ( " render:direct_scanout " ) ;
2024-03-03 18:39:20 +00:00
static auto PVFR = CConfigValue < Hyprlang : : INT > ( " misc:vfr " ) ;
2024-05-09 22:23:01 +01:00
static auto PZOOMFACTOR = CConfigValue < Hyprlang : : FLOAT > ( " cursor:zoom_factor " ) ;
2024-03-03 18:39:20 +00:00
static auto PANIMENABLED = CConfigValue < Hyprlang : : INT > ( " animations:enabled " ) ;
static auto PFIRSTLAUNCHANIM = CConfigValue < Hyprlang : : INT > ( " animations:first_launch_animation " ) ;
static auto PTEARINGENABLED = CConfigValue < Hyprlang : : INT > ( " general:allow_tearing " ) ;
2023-03-24 19:23:16 +00:00
static int damageBlinkCleanup = 0 ; // because double-buffered
2024-03-03 18:39:20 +00:00
if ( ! * PDAMAGEBLINK )
2023-03-24 19:23:16 +00:00
damageBlinkCleanup = 0 ;
2023-05-24 15:49:27 +02:00
static bool firstLaunch = true ;
2024-03-03 18:39:20 +00:00
static bool firstLaunchAnimActive = * PFIRSTLAUNCHANIM ;
2023-05-01 02:49:41 +01:00
float zoomInFactorFirstLaunch = 1.f ;
if ( firstLaunch ) {
firstLaunch = false ;
m_tRenderTimer . reset ( ) ;
}
2023-05-24 15:49:27 +02:00
if ( m_tRenderTimer . getSeconds ( ) < 1.5f & & firstLaunchAnimActive ) { // TODO: make the animation system more damage-flexible so that this can be migrated to there
2024-03-03 18:39:20 +00:00
if ( ! * PANIMENABLED ) {
2023-07-22 19:26:39 +02:00
zoomInFactorFirstLaunch = 1.f ;
firstLaunchAnimActive = false ;
} else {
zoomInFactorFirstLaunch = 2.f - g_pAnimationManager - > getBezier ( " default " ) - > getYForPoint ( m_tRenderTimer . getSeconds ( ) / 1.5 ) ;
damageMonitor ( pMonitor ) ;
}
2023-05-24 15:49:27 +02:00
} else {
firstLaunchAnimActive = false ;
2023-05-01 02:49:41 +01:00
}
2023-11-24 10:54:21 +00:00
renderStart = std : : chrono : : high_resolution_clock : : now ( ) ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( * PDEBUGOVERLAY = = 1 )
2023-03-24 19:23:16 +00:00
g_pDebugOverlay - > frameData ( pMonitor ) ;
if ( pMonitor - > framesToSkip > 0 ) {
pMonitor - > framesToSkip - = 1 ;
if ( ! pMonitor - > noFrameSchedule )
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( pMonitor , Aquamarine : : IOutput : : AQ_SCHEDULE_RENDER_MONITOR ) ;
2024-02-18 15:00:34 +00:00
else
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " NoFrameSchedule hit for {}. " , pMonitor - > szName ) ;
2024-02-18 15:00:34 +00:00
2023-03-24 19:23:16 +00:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitor - > ID ) ;
if ( pMonitor - > framesToSkip > 10 )
pMonitor - > framesToSkip = 0 ;
return ;
}
// checks //
if ( pMonitor - > ID = = m_pMostHzMonitor - > ID | |
2024-03-03 18:39:20 +00:00
* PVFR = = 1 ) { // unfortunately with VFR we don't have the guarantee mostHz is going to be updated all the time, so we have to ignore that
2023-03-24 19:23:16 +00:00
g_pCompositor - > sanityCheckWorkspaces ( ) ;
g_pConfigManager - > dispatchExecOnce ( ) ; // We exec-once when at least one monitor starts refreshing, meaning stuff has init'd
if ( g_pConfigManager - > m_bWantsMonitorReload )
g_pConfigManager - > performMonitorReload ( ) ;
}
// //
if ( pMonitor - > scheduledRecalc ) {
pMonitor - > scheduledRecalc = false ;
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( pMonitor - > ID ) ;
}
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > output - > needsFrame & & pMonitor - > forceFullFrames = = 0 )
return ;
2023-09-28 21:48:33 +01:00
// tearing and DS first
bool shouldTear = false ;
2023-09-30 17:07:50 +01:00
if ( pMonitor - > tearingState . nextRenderTorn ) {
pMonitor - > tearingState . nextRenderTorn = false ;
2023-09-28 21:48:33 +01:00
2024-03-03 18:39:20 +00:00
if ( ! * PTEARINGENABLED ) {
2023-09-28 21:48:33 +01:00
Debug : : log ( WARN , " Tearing commit requested but the master switch general:allow_tearing is off, ignoring " ) ;
return ;
}
if ( g_pHyprOpenGL - > m_RenderData . mouseZoomFactor ! = 1.0 ) {
Debug : : log ( WARN , " Tearing commit requested but scale factor is not 1, ignoring " ) ;
return ;
}
2023-09-30 17:07:50 +01:00
if ( ! pMonitor - > tearingState . canTear ) {
2023-09-28 21:48:33 +01:00
Debug : : log ( WARN , " Tearing commit requested but monitor doesn't support it, ignoring " ) ;
return ;
}
2024-04-27 12:43:12 +01:00
if ( ! pMonitor - > solitaryClient . expired ( ) )
2023-09-28 21:48:33 +01:00
shouldTear = true ;
}
2024-07-30 15:50:14 +02:00
pMonitor - > tearingState . activelyTearing = shouldTear ;
2024-08-06 14:52:19 +01:00
if ( * PDIRECTSCANOUT & & ! shouldTear ) {
2024-07-21 13:09:54 +02:00
if ( pMonitor - > attemptDirectScanout ( ) ) {
2023-03-24 19:23:16 +00:00
return ;
2024-07-21 13:09:54 +02:00
} else if ( ! pMonitor - > lastScanout . expired ( ) ) {
2023-03-24 19:23:16 +00:00
Debug : : log ( LOG , " Left a direct scanout. " ) ;
2024-07-21 13:09:54 +02:00
pMonitor - > lastScanout . reset ( ) ;
2024-08-17 19:27:11 +02:00
// reset DRM format, make sure it's the one we want.
2024-08-31 08:07:52 -05:00
pMonitor - > output - > state - > setFormat ( pMonitor - > prevDrmFormat ) ;
pMonitor - > drmFormat = pMonitor - > prevDrmFormat ;
2023-03-24 19:23:16 +00:00
}
}
EMIT_HOOK_EVENT ( " preRender " , pMonitor ) ;
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
// check the damage
2024-07-21 13:09:54 +02:00
bool hasChanged = pMonitor - > output - > needsFrame | | pMonitor - > damage . hasChanged ( ) ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( ! hasChanged & & * PDAMAGETRACKINGMODE ! = DAMAGE_TRACKING_NONE & & pMonitor - > forceFullFrames = = 0 & & damageBlinkCleanup = = 0 )
2023-04-09 17:59:24 +01:00
return ;
2024-03-03 18:39:20 +00:00
if ( * PDAMAGETRACKINGMODE = = - 1 ) {
2023-03-24 19:23:16 +00:00
Debug : : log ( CRIT , " Damage tracking mode -1 ???? " ) ;
return ;
}
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_PRE ) ;
2023-03-24 19:23:16 +00:00
pMonitor - > renderingActive = true ;
2024-02-19 18:17:32 +00:00
// we need to cleanup fading out when rendering the appropriate context
g_pCompositor - > cleanupFadingOut ( pMonitor - > ID ) ;
// TODO: this is getting called with extents being 0,0,0,0 should it be?
// potentially can save on resources.
2024-02-18 16:04:08 +00:00
TRACY_GPU_ZONE ( " Render " ) ;
2024-06-12 12:28:52 -05:00
static bool zoomLock = false ;
if ( zoomLock & & * PZOOMFACTOR = = 1.f ) {
g_pPointerManager - > unlockSoftwareAll ( ) ;
zoomLock = false ;
} else if ( ! zoomLock & & * PZOOMFACTOR ! = 1.f ) {
g_pPointerManager - > lockSoftwareAll ( ) ;
zoomLock = true ;
}
2024-02-18 16:04:08 +00:00
if ( pMonitor = = g_pCompositor - > getMonitorFromCursor ( ) )
2024-03-03 18:39:20 +00:00
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = std : : clamp ( * PZOOMFACTOR , 1.f , INFINITY ) ;
2024-02-18 16:04:08 +00:00
else
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = 1.f ;
if ( zoomInFactorFirstLaunch > 1.f ) {
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = zoomInFactorFirstLaunch ;
g_pHyprOpenGL - > m_RenderData . mouseZoomUseMouse = false ;
g_pHyprOpenGL - > m_RenderData . useNearestNeighbor = false ;
2024-02-29 19:04:40 +00:00
pMonitor - > forceFullFrames = 10 ;
2024-02-18 16:04:08 +00:00
}
2024-02-23 01:02:32 +00:00
CRegion damage , finalDamage ;
2024-02-18 16:04:08 +00:00
if ( ! beginRender ( pMonitor , damage , RENDER_MODE_NORMAL ) ) {
Debug : : log ( ERR , " renderer: couldn't beginRender()! " ) ;
return ;
}
2023-03-24 19:23:16 +00:00
// if we have no tracking or full tracking, invalidate the entire monitor
2024-04-24 17:29:41 +02:00
if ( * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_NONE | | * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_MONITOR | | pMonitor - > forceFullFrames > 0 | | damageBlinkCleanup > 0 ) {
2024-02-23 01:02:32 +00:00
damage = { 0 , 0 , ( int ) pMonitor - > vecTransformedSize . x * 10 , ( int ) pMonitor - > vecTransformedSize . y * 10 } ;
finalDamage = damage ;
2023-03-24 19:23:16 +00:00
} else {
2024-03-03 18:39:20 +00:00
static auto PBLURENABLED = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
2023-03-24 19:23:16 +00:00
// if we use blur we need to expand the damage for proper blurring
2024-02-22 23:01:22 +00:00
// if framebuffer was not offloaded we're not doing introspection aka not blurring so this is redundant and dumb
2024-03-03 18:39:20 +00:00
if ( * PBLURENABLED = = 1 & & g_pHyprOpenGL - > m_bOffloadedFramebuffer ) {
2023-03-24 19:23:16 +00:00
// TODO: can this be optimized?
2024-03-03 18:39:20 +00:00
static auto PBLURSIZE = CConfigValue < Hyprlang : : INT > ( " decoration:blur:size " ) ;
static auto PBLURPASSES = CConfigValue < Hyprlang : : INT > ( " decoration:blur:passes " ) ;
const auto BLURRADIUS =
* 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 19:23:16 +00:00
// now, prep the damage, get the extended damage region
2024-07-21 13:09:54 +02:00
damage . expand ( BLURRADIUS ) ; // expand for proper blurring
2023-03-24 19:23:16 +00:00
2024-02-23 01:02:32 +00:00
finalDamage = damage ;
2023-03-24 19:23:16 +00:00
2024-07-21 13:09:54 +02:00
damage . expand ( BLURRADIUS ) ; // expand for proper blurring
2024-02-23 01:02:32 +00:00
} else
finalDamage = damage ;
2023-03-24 19:23:16 +00:00
}
2024-02-19 18:17:32 +00:00
// update damage in renderdata as we modified it
2024-02-23 01:02:32 +00:00
g_pHyprOpenGL - > setDamage ( damage , finalDamage ) ;
2023-03-24 19:23:16 +00:00
2024-02-19 18:17:32 +00:00
if ( pMonitor - > forceFullFrames > 0 ) {
pMonitor - > forceFullFrames - = 1 ;
if ( pMonitor - > forceFullFrames > 10 )
pMonitor - > forceFullFrames = 0 ;
}
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_BEGIN ) ;
2023-09-29 17:51:07 +01:00
bool renderCursor = true ;
2024-04-23 12:29:01 +01:00
if ( ! finalDamage . empty ( ) ) {
2024-04-27 12:43:12 +01:00
if ( pMonitor - > solitaryClient . expired ( ) ) {
2024-04-23 12:29:01 +01:00
if ( pMonitor - > isMirror ( ) ) {
g_pHyprOpenGL - > blend ( false ) ;
g_pHyprOpenGL - > renderMirrored ( ) ;
g_pHyprOpenGL - > blend ( true ) ;
EMIT_HOOK_EVENT ( " render " , RENDER_POST_MIRROR ) ;
renderCursor = false ;
} else {
CBox renderBox = { 0 , 0 , ( int ) pMonitor - > vecPixelSize . x , ( int ) pMonitor - > vecPixelSize . y } ;
renderWorkspace ( pMonitor , pMonitor - > activeWorkspace , & now , renderBox ) ;
renderLockscreen ( pMonitor , & now , renderBox ) ;
2024-10-19 23:03:29 +01:00
if ( pMonitor = = g_pCompositor - > m_pLastMonitor ) {
2024-04-23 12:29:01 +01:00
g_pHyprNotificationOverlay - > draw ( pMonitor ) ;
g_pHyprError - > draw ( ) ;
}
// for drawing the debug overlay
2024-10-19 23:03:29 +01:00
if ( pMonitor = = g_pCompositor - > m_vMonitors . front ( ) & & * PDEBUGOVERLAY = = 1 ) {
2024-04-23 12:29:01 +01:00
renderStartOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
g_pDebugOverlay - > draw ( ) ;
endRenderOverlay = std : : chrono : : high_resolution_clock : : now ( ) ;
}
if ( * PDAMAGEBLINK & & damageBlinkCleanup = = 0 ) {
CBox monrect = { 0 , 0 , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y } ;
2024-12-03 18:58:24 +00:00
g_pHyprOpenGL - > renderRect ( & monrect , CHyprColor ( 1.0 , 0.0 , 1.0 , 100.0 / 255.0 ) , 0 ) ;
2024-04-23 12:29:01 +01:00
damageBlinkCleanup = 1 ;
} else if ( * PDAMAGEBLINK ) {
damageBlinkCleanup + + ;
if ( damageBlinkCleanup > 3 )
damageBlinkCleanup = 0 ;
}
2023-09-29 17:51:07 +01:00
}
2024-04-23 16:08:54 +01:00
} else
2024-04-27 12:43:12 +01:00
g_pHyprRenderer - > renderWindow ( pMonitor - > solitaryClient . lock ( ) , pMonitor , & now , false , RENDER_PASS_MAIN /* solitary = no popups */ ) ;
2024-06-09 22:28:51 +02:00
} else if ( ! pMonitor - > isMirror ( ) ) {
2024-04-23 16:08:54 +01:00
sendFrameEventsToWorkspace ( pMonitor , pMonitor - > activeWorkspace , & now ) ;
if ( pMonitor - > activeSpecialWorkspace )
sendFrameEventsToWorkspace ( pMonitor , pMonitor - > activeSpecialWorkspace , & now ) ;
2023-09-29 17:51:07 +01:00
}
2023-03-24 19:23:16 +00:00
2023-09-29 17:51:07 +01:00
renderCursor = renderCursor & & shouldRenderCursor ( ) ;
2023-11-24 10:54:21 +00:00
if ( renderCursor ) {
2023-09-29 17:51:07 +01:00
TRACY_GPU_ZONE ( " RenderCursor " ) ;
2024-05-10 23:38:46 +01:00
g_pPointerManager - > renderSoftwareCursorsFor ( pMonitor - > self . lock ( ) , & now , g_pHyprOpenGL - > m_RenderData . damage ) ;
2023-05-01 02:49:41 +01:00
}
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_LAST_MOMENT ) ;
2023-11-24 10:54:21 +00:00
endRender ( ) ;
2023-03-24 19:23:16 +00:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_COLLECT ;
2024-02-14 22:33:50 +00:00
if ( ! pMonitor - > mirrors . empty ( ) ) {
2024-07-21 13:09:54 +02:00
CRegion frameDamage { finalDamage } ;
2023-03-24 19:23:16 +00:00
2024-07-21 13:09:54 +02:00
const auto TRANSFORM = invertTransform ( pMonitor - > transform ) ;
frameDamage . transform ( wlTransformToHyprutils ( TRANSFORM ) , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y ) ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_NONE | | * PDAMAGETRACKINGMODE = = DAMAGE_TRACKING_MONITOR )
2024-02-14 22:33:50 +00:00
frameDamage . add ( 0 , 0 , ( int ) pMonitor - > vecTransformedSize . x , ( int ) pMonitor - > vecTransformedSize . y ) ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( * PDAMAGEBLINK )
2024-02-14 22:33:50 +00:00
frameDamage . add ( damage ) ;
2023-03-24 19:23:16 +00:00
2023-07-19 20:09:49 +02:00
g_pHyprRenderer - > damageMirrorsWith ( pMonitor , frameDamage ) ;
2024-07-30 15:46:35 +02:00
pMonitor - > output - > state - > addDamage ( frameDamage ) ;
2024-02-14 22:33:50 +00:00
}
2023-03-24 19:23:16 +00:00
pMonitor - > renderingActive = false ;
2023-04-17 23:45:03 +01:00
EMIT_HOOK_EVENT ( " render " , RENDER_POST ) ;
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setPresentationMode ( shouldTear ? Aquamarine : : eOutputPresentationMode : : AQ_OUTPUT_PRESENTATION_IMMEDIATE :
Aquamarine : : eOutputPresentationMode : : AQ_OUTPUT_PRESENTATION_VSYNC ) ;
2023-09-28 21:48:33 +01:00
2024-07-21 13:09:54 +02:00
commitPendingAndDoExplicitSync ( pMonitor ) ;
2023-04-03 17:01:05 +01:00
2023-09-28 21:48:33 +01:00
if ( shouldTear )
2023-09-30 17:07:50 +01:00
pMonitor - > tearingState . busy = true ;
2023-09-28 21:48:33 +01:00
2024-03-03 18:39:20 +00:00
if ( * PDAMAGEBLINK | | * PVFR = = 0 | | pMonitor - > pendingFrame )
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( pMonitor , Aquamarine : : IOutput : : AQ_SCHEDULE_RENDER_MONITOR ) ;
2023-03-24 19:23:16 +00:00
pMonitor - > pendingFrame = false ;
2024-08-12 19:19:03 +02:00
const float durationUs = std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( std : : chrono : : high_resolution_clock : : now ( ) - renderStart ) . count ( ) / 1000.f ;
g_pDebugOverlay - > renderData ( pMonitor , durationUs ) ;
2023-03-24 19:23:16 +00:00
2024-03-03 18:39:20 +00:00
if ( * PDEBUGOVERLAY = = 1 ) {
2024-10-19 23:03:29 +01:00
if ( pMonitor = = g_pCompositor - > m_vMonitors . front ( ) ) {
2024-08-12 19:19:03 +02:00
const float noOverlayUs = durationUs - std : : chrono : : duration_cast < std : : chrono : : nanoseconds > ( endRenderOverlay - renderStartOverlay ) . count ( ) / 1000.f ;
g_pDebugOverlay - > renderDataNoOverlay ( pMonitor , noOverlayUs ) ;
2023-03-24 19:23:16 +00:00
} else {
2024-08-12 19:19:03 +02:00
g_pDebugOverlay - > renderDataNoOverlay ( pMonitor , durationUs ) ;
2023-03-24 19:23:16 +00:00
}
}
}
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : commitPendingAndDoExplicitSync ( PHLMONITOR pMonitor ) {
2024-07-21 13:09:54 +02:00
// apply timelines for explicit sync
2024-08-06 14:52:19 +01:00
// save inFD otherwise reset will reset it
auto inFD = pMonitor - > output - > state - > state ( ) . explicitInFence ;
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > resetExplicitFences ( ) ;
2024-08-06 14:52:19 +01:00
if ( inFD > = 0 )
pMonitor - > output - > state - > setExplicitInFence ( inFD ) ;
2024-11-15 03:45:13 +03:00
auto explicitOptions = getExplicitSyncSettings ( ) ;
if ( explicitOptions . explicitEnabled & & explicitOptions . explicitKMSEnabled )
pMonitor - > output - > state - > enableExplicitOutFenceForNextCommit ( ) ;
2024-07-21 13:09:54 +02:00
2024-10-08 16:59:15 +01:00
if ( pMonitor - > ctmUpdated ) {
pMonitor - > ctmUpdated = false ;
pMonitor - > output - > state - > setCTM ( pMonitor - > ctm ) ;
}
2024-08-06 14:52:19 +01:00
bool ok = pMonitor - > state . commit ( ) ;
if ( ! ok ) {
if ( inFD > = 0 ) {
Debug : : log ( TRACE , " Monitor state commit failed, retrying without a fence " ) ;
pMonitor - > output - > state - > resetExplicitFences ( ) ;
ok = pMonitor - > state . commit ( ) ;
2024-07-21 13:09:54 +02:00
}
2024-08-06 14:52:19 +01:00
if ( ! ok ) {
Debug : : log ( TRACE , " Monitor state commit failed " ) ;
// rollback the buffer to avoid writing to the front buffer that is being
// displayed
pMonitor - > output - > swapchain - > rollback ( ) ;
pMonitor - > damage . damageEntire ( ) ;
}
2024-07-21 13:09:54 +02:00
}
2024-08-06 14:52:19 +01:00
if ( ! explicitOptions . explicitEnabled )
2024-07-21 13:09:54 +02:00
return ok ;
2024-08-06 14:52:19 +01:00
if ( inFD > = 0 )
close ( inFD ) ;
2024-07-21 13:09:54 +02:00
if ( pMonitor - > output - > state - > state ( ) . explicitOutFence > = 0 ) {
2024-08-06 14:52:19 +01:00
Debug : : log ( TRACE , " Aquamarine returned an explicit out fence at {} " , pMonitor - > output - > state - > state ( ) . explicitOutFence ) ;
2024-07-21 13:09:54 +02:00
close ( pMonitor - > output - > state - > state ( ) . explicitOutFence ) ;
2024-08-06 14:52:19 +01:00
} else
Debug : : log ( TRACE , " Aquamarine did not return an explicit out fence " ) ;
Debug : : log ( TRACE , " Explicit: {} presented " , explicitPresented . size ( ) ) ;
auto sync = g_pHyprOpenGL - > createEGLSync ( - 1 ) ;
if ( ! sync )
Debug : : log ( TRACE , " Explicit: can't add sync, EGLSync failed " ) ;
else {
2024-08-26 20:24:30 +02:00
for ( auto const & e : explicitPresented ) {
2024-08-06 14:52:19 +01:00
if ( ! e - > current . buffer | | ! e - > current . buffer - > releaser )
continue ;
e - > current . buffer - > releaser - > addReleaseSync ( sync ) ;
}
2024-07-21 13:09:54 +02:00
}
2024-08-06 14:52:19 +01:00
explicitPresented . clear ( ) ;
pMonitor - > output - > state - > resetExplicitFences ( ) ;
2024-07-21 13:09:54 +02:00
return ok ;
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * now , const CBox & geometry ) {
2023-04-12 12:41:23 +01:00
Vector2D translate = { geometry . x , geometry . y } ;
float scale = ( float ) geometry . width / pMonitor - > vecPixelSize . x ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderWorkspace " ) ;
2023-04-12 12:50:20 +01:00
if ( ! DELTALESSTHAN ( ( double ) geometry . width / ( double ) geometry . height , pMonitor - > vecPixelSize . x / pMonitor - > vecPixelSize . y , 0.01 ) ) {
2023-04-12 12:41:23 +01:00
Debug : : log ( ERR , " Ignoring geometry in renderWorkspace: aspect ratio mismatch " ) ;
scale = 1.f ;
translate = Vector2D { } ;
}
2023-04-17 23:47:12 +01:00
g_pHyprOpenGL - > m_RenderData . pWorkspace = pWorkspace ;
2023-04-12 13:05:57 +01:00
renderAllClientsForWorkspace ( pMonitor , pWorkspace , now , translate , scale ) ;
2023-04-17 23:47:12 +01:00
g_pHyprOpenGL - > m_RenderData . pWorkspace = nullptr ;
2023-04-12 12:41:23 +01:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : sendFrameEventsToWorkspace ( PHLMONITOR pMonitor , PHLWORKSPACE pWorkspace , timespec * now ) {
2024-08-26 17:25:39 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-06-08 10:07:59 +02:00
if ( w - > isHidden ( ) | | ! w - > m_bIsMapped | | w - > m_bFadingOut | | ! w - > m_pWLSurface - > resource ( ) )
2024-04-23 16:08:54 +01:00
continue ;
2024-04-27 12:43:12 +01:00
if ( ! shouldRenderWindow ( w , pMonitor ) )
2024-04-23 16:08:54 +01:00
continue ;
2024-06-08 10:07:59 +02:00
w - > m_pWLSurface - > resource ( ) - > breadthfirst ( [ now ] ( SP < CWLSurfaceResource > r , const Vector2D & offset , void * d ) { r - > frame ( now ) ; } , nullptr ) ;
2024-04-23 16:08:54 +01:00
}
2024-08-26 17:25:39 +02:00
for ( auto const & lsl : pMonitor - > m_aLayerSurfaceLayers ) {
for ( auto const & ls : lsl ) {
2024-06-08 10:07:59 +02:00
if ( ls - > fadingOut | | ! ls - > surface - > resource ( ) )
2024-04-23 21:15:37 +01:00
continue ;
2024-06-08 10:07:59 +02:00
ls - > surface - > resource ( ) - > breadthfirst ( [ now ] ( SP < CWLSurfaceResource > r , const Vector2D & offset , void * d ) { r - > frame ( now ) ; } , nullptr ) ;
2024-04-23 16:08:54 +01:00
}
}
}
2024-10-26 02:06:13 +01:00
void CHyprRenderer : : setSurfaceScanoutMode ( SP < CWLSurfaceResource > surface , PHLMONITOR monitor ) {
2024-07-21 13:09:54 +02:00
if ( ! PROTO : : linuxDma )
return ;
2022-11-05 12:50:47 +00:00
2024-07-21 13:09:54 +02:00
PROTO : : linuxDma - > updateScanoutTranche ( surface , monitor ) ;
2022-11-05 12:50:47 +00:00
}
2022-03-21 17:00:17 +01:00
// taken from Sway.
// this is just too much of a spaghetti for me to understand
2024-07-22 23:36:58 +02:00
static void applyExclusive ( CBox & usableArea , uint32_t anchor , int32_t exclusive , uint32_t exclusiveEdge , int32_t marginTop , int32_t marginRight , int32_t marginBottom ,
int32_t marginLeft ) {
2022-03-21 17:00:17 +01:00
if ( exclusive < = 0 ) {
return ;
}
struct {
uint32_t singular_anchor ;
uint32_t anchor_triplet ;
2024-06-19 16:20:06 +02:00
double * positive_axis ;
double * negative_axis ;
2022-12-16 17:17:31 +00:00
int margin ;
2022-03-21 17:00:17 +01:00
} edges [ ] = {
// Top
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ,
2022-12-16 17:17:31 +00:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ,
2023-12-19 11:55:56 +00:00
. positive_axis = & usableArea . y ,
. negative_axis = & usableArea . height ,
. margin = marginTop ,
2022-03-21 17:00:17 +01:00
} ,
// Bottom
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
2022-12-16 17:17:31 +00:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
. positive_axis = NULL ,
2023-12-19 11:55:56 +00:00
. negative_axis = & usableArea . height ,
. margin = marginBottom ,
2022-03-21 17:00:17 +01:00
} ,
// Left
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ,
2022-12-16 17:17:31 +00:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
2023-12-19 11:55:56 +00:00
. positive_axis = & usableArea . x ,
. negative_axis = & usableArea . width ,
. margin = marginLeft ,
2022-03-21 17:00:17 +01:00
} ,
// Right
{
. singular_anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ,
2022-12-16 17:17:31 +00:00
. anchor_triplet = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ,
. positive_axis = NULL ,
2023-12-19 11:55:56 +00:00
. negative_axis = & usableArea . width ,
. margin = marginRight ,
2022-03-21 17:00:17 +01:00
} ,
} ;
for ( size_t i = 0 ; i < sizeof ( edges ) / sizeof ( edges [ 0 ] ) ; + + i ) {
2024-07-22 23:36:58 +02:00
if ( ( exclusiveEdge = = edges [ i ] . singular_anchor | | anchor = = edges [ i ] . singular_anchor | | anchor = = edges [ i ] . anchor_triplet ) & & exclusive + edges [ i ] . margin > 0 ) {
2022-03-21 17:00:17 +01:00
if ( edges [ i ] . positive_axis ) {
* edges [ i ] . positive_axis + = exclusive + edges [ i ] . margin ;
}
if ( edges [ i ] . negative_axis ) {
* edges [ i ] . negative_axis - = exclusive + edges [ i ] . margin ;
}
break ;
}
}
}
2022-03-19 14:37:40 +01:00
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : arrangeLayerArray ( PHLMONITOR pMonitor , const std : : vector < PHLLSREF > & layerSurfaces , bool exclusiveZone , CBox * usableArea ) {
2023-11-04 17:03:05 +00:00
CBox full_area = { pMonitor - > vecPosition . x , pMonitor - > vecPosition . y , pMonitor - > vecSize . x , pMonitor - > vecSize . y } ;
2022-03-19 14:37:40 +01:00
2024-08-26 20:24:30 +02:00
for ( auto const & ls : layerSurfaces ) {
2024-07-21 13:09:54 +02:00
if ( ! ls | | ls - > fadingOut | | ls - > readyToDelete | | ! ls - > layerSurface | | ls - > noProcess )
2022-05-14 17:23:46 +02:00
continue ;
2022-03-21 17:00:17 +01:00
const auto PLAYER = ls - > layerSurface ;
const auto PSTATE = & PLAYER - > current ;
2024-05-09 21:47:21 +01:00
if ( exclusiveZone ! = ( PSTATE - > exclusive > 0 ) )
2022-03-21 17:00:17 +01:00
continue ;
2022-03-19 14:37:40 +01:00
2023-11-04 17:03:05 +00:00
CBox bounds ;
2024-05-09 21:47:21 +01:00
if ( PSTATE - > exclusive = = - 1 )
2022-03-21 17:00:17 +01:00
bounds = full_area ;
2023-10-06 14:00:05 +01:00
else
2022-03-21 17:00:17 +01:00
bounds = * usableArea ;
2022-03-19 14:37:40 +01:00
2023-10-06 14:00:05 +01:00
const Vector2D OLDSIZE = { ls - > geometry . width , ls - > geometry . height } ;
2024-05-09 21:47:21 +01:00
CBox box = { { } , PSTATE - > desiredSize } ;
2022-03-21 17:00:17 +01:00
// Horizontal axis
const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ;
2024-10-19 23:47:28 +01:00
if ( box . width = = 0 )
2022-03-21 17:00:17 +01:00
box . x = bounds . x ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & both_horiz ) = = both_horiz )
2022-03-21 17:00:17 +01:00
box . x = bounds . x + ( ( bounds . width / 2 ) - ( box . width / 2 ) ) ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ) )
2022-03-21 17:00:17 +01:00
box . x = bounds . x ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ) )
2022-03-21 17:00:17 +01:00
box . x = bounds . x + ( bounds . width - box . width ) ;
2024-10-19 23:47:28 +01:00
else
2022-03-21 17:00:17 +01:00
box . x = bounds . x + ( ( bounds . width / 2 ) - ( box . width / 2 ) ) ;
2024-10-19 23:47:28 +01:00
2022-03-21 17:00:17 +01:00
// Vertical axis
const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ;
2024-10-19 23:47:28 +01:00
if ( box . height = = 0 )
2022-03-21 17:00:17 +01:00
box . y = bounds . y ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & both_vert ) = = both_vert )
2022-03-21 17:00:17 +01:00
box . y = bounds . y + ( ( bounds . height / 2 ) - ( box . height / 2 ) ) ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ) )
2022-03-21 17:00:17 +01:00
box . y = bounds . y ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ) )
2022-03-21 17:00:17 +01:00
box . y = bounds . y + ( bounds . height - box . height ) ;
2024-10-19 23:47:28 +01:00
else
2022-03-21 17:00:17 +01:00
box . y = bounds . y + ( ( bounds . height / 2 ) - ( box . height / 2 ) ) ;
2024-10-19 23:47:28 +01:00
2022-03-21 17:00:17 +01:00
// Margin
if ( box . width = = 0 ) {
box . x + = PSTATE - > margin . left ;
2022-12-16 17:17:31 +00:00
box . width = bounds . width - ( PSTATE - > margin . left + PSTATE - > margin . right ) ;
2024-10-19 23:47:28 +01:00
} else if ( ( PSTATE - > anchor & both_horiz ) = = both_horiz )
; // don't apply margins
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT ) )
2022-03-21 17:00:17 +01:00
box . x + = PSTATE - > margin . left ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT ) )
2022-03-21 17:00:17 +01:00
box . x - = PSTATE - > margin . right ;
2024-10-19 23:47:28 +01:00
2022-03-21 17:00:17 +01:00
if ( box . height = = 0 ) {
box . y + = PSTATE - > margin . top ;
2022-12-16 17:17:31 +00:00
box . height = bounds . height - ( PSTATE - > margin . top + PSTATE - > margin . bottom ) ;
2024-10-19 23:47:28 +01:00
} else if ( ( PSTATE - > anchor & both_vert ) = = both_vert )
; // don't apply margins
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP ) )
2022-03-21 17:00:17 +01:00
box . y + = PSTATE - > margin . top ;
2024-10-19 23:47:28 +01:00
else if ( ( PSTATE - > anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ) )
2022-03-21 17:00:17 +01:00
box . y - = PSTATE - > margin . bottom ;
2024-10-19 23:47:28 +01:00
2022-03-21 17:00:17 +01:00
if ( box . width < = 0 | | box . height < = 0 ) {
2023-09-06 12:51:36 +02:00
Debug : : log ( ERR , " LayerSurface {:x} has a negative/zero w/h??? " , ( uintptr_t ) ls . get ( ) ) ;
2022-03-21 17:00:17 +01:00
continue ;
2022-03-20 14:52:23 +01:00
}
2024-10-19 23:45:51 +01:00
box . round ( ) ; // fix rounding errors
2022-03-21 17:00:17 +01:00
ls - > geometry = box ;
2022-03-20 14:52:23 +01:00
2024-07-22 23:36:58 +02:00
applyExclusive ( * usableArea , PSTATE - > anchor , PSTATE - > exclusive , PSTATE - > exclusiveEdge , PSTATE - > margin . top , PSTATE - > margin . right , PSTATE - > margin . bottom , PSTATE - > margin . left ) ;
2022-03-19 14:37:40 +01:00
2023-10-06 14:00:05 +01:00
if ( Vector2D { box . width , box . height } ! = OLDSIZE )
2024-05-09 21:47:21 +01:00
ls - > layerSurface - > configure ( box . size ( ) ) ;
2024-03-27 16:30:08 +00:00
ls - > realPosition = box . pos ( ) ;
ls - > realSize = box . size ( ) ;
2022-03-19 14:37:40 +01:00
}
}
2024-08-08 21:01:50 +02:00
void CHyprRenderer : : arrangeLayersForMonitor ( const MONITORID & monitor ) {
2024-10-08 21:58:40 +01:00
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( monitor ) ;
static auto BAR_POSITION = CConfigValue < Hyprlang : : INT > ( " debug:error_position " ) ;
2022-03-19 14:37:40 +01:00
if ( ! PMONITOR )
return ;
// Reset the reserved
2022-12-16 17:17:31 +00:00
PMONITOR - > vecReservedBottomRight = Vector2D ( ) ;
PMONITOR - > vecReservedTopLeft = Vector2D ( ) ;
2022-03-19 14:37:40 +01:00
2023-11-04 17:03:05 +00:00
CBox usableArea = { PMONITOR - > vecPosition . x , PMONITOR - > vecPosition . y , PMONITOR - > vecSize . x , PMONITOR - > vecSize . y } ;
2022-03-21 17:00:17 +01:00
2024-10-08 21:20:25 +01:00
if ( g_pHyprError - > active ( ) & & g_pCompositor - > m_pLastMonitor = = PMONITOR - > self ) {
2024-10-08 21:58:40 +01:00
const auto HEIGHT = g_pHyprError - > height ( ) ;
if ( * BAR_POSITION = = 0 ) {
PMONITOR - > vecReservedTopLeft . y = HEIGHT ;
usableArea . y + = HEIGHT ;
usableArea . h - = HEIGHT ;
} else {
PMONITOR - > vecReservedBottomRight . y = HEIGHT ;
usableArea . h - = HEIGHT ;
}
2024-10-08 21:20:25 +01:00
}
2024-09-09 11:10:08 +02:00
for ( auto & la : PMONITOR - > m_aLayerSurfaceLayers ) {
std : : stable_sort ( la . begin ( ) , la . end ( ) , [ ] ( const PHLLSREF & a , const PHLLSREF & b ) { return a - > order > b - > order ; } ) ;
}
2024-08-26 17:25:39 +02:00
for ( auto const & la : PMONITOR - > m_aLayerSurfaceLayers )
2022-03-21 17:00:17 +01:00
arrangeLayerArray ( PMONITOR , la , true , & usableArea ) ;
2024-08-26 17:25:39 +02:00
for ( auto const & la : PMONITOR - > m_aLayerSurfaceLayers )
2022-03-21 17:00:17 +01:00
arrangeLayerArray ( PMONITOR , la , false , & usableArea ) ;
2022-12-16 17:17:31 +00:00
PMONITOR - > vecReservedTopLeft = Vector2D ( usableArea . x , usableArea . y ) - PMONITOR - > vecPosition ;
2022-03-21 17:00:17 +01:00
PMONITOR - > vecReservedBottomRight = PMONITOR - > vecSize - Vector2D ( usableArea . width , usableArea . height ) - PMONITOR - > vecReservedTopLeft ;
2022-10-17 23:23:01 +01:00
auto ADDITIONALRESERVED = g_pConfigManager - > m_mAdditionalReservedAreas . find ( PMONITOR - > szName ) ;
if ( ADDITIONALRESERVED = = g_pConfigManager - > m_mAdditionalReservedAreas . end ( ) ) {
2022-12-16 17:17:31 +00:00
ADDITIONALRESERVED = g_pConfigManager - > m_mAdditionalReservedAreas . find ( " " ) ; // glob wildcard
2022-10-17 23:23:01 +01:00
}
if ( ADDITIONALRESERVED ! = g_pConfigManager - > m_mAdditionalReservedAreas . end ( ) ) {
2022-12-16 17:17:31 +00:00
PMONITOR - > vecReservedTopLeft = PMONITOR - > vecReservedTopLeft + Vector2D ( ADDITIONALRESERVED - > second . left , ADDITIONALRESERVED - > second . top ) ;
2022-10-17 23:23:01 +01:00
PMONITOR - > vecReservedBottomRight = PMONITOR - > vecReservedBottomRight + Vector2D ( ADDITIONALRESERVED - > second . right , ADDITIONALRESERVED - > second . bottom ) ;
}
2022-04-27 17:46:07 +02:00
2022-05-04 15:23:30 +02:00
// damage the monitor if can
2023-04-07 12:18:40 +01:00
damageMonitor ( PMONITOR ) ;
2022-05-04 15:23:30 +02:00
2022-09-08 14:11:32 +02:00
g_pLayoutManager - > getCurrentLayout ( ) - > recalculateMonitor ( monitor ) ;
2022-03-19 16:13:19 +01:00
}
2024-06-08 10:07:59 +02:00
void CHyprRenderer : : damageSurface ( SP < CWLSurfaceResource > pSurface , double x , double y , double scale ) {
2022-04-14 16:43:29 +02:00
if ( ! pSurface )
return ; // wut?
2022-03-21 16:13:43 +01:00
2022-08-10 23:14:53 +02:00
if ( g_pCompositor - > m_bUnsafeState )
return ;
2024-06-08 10:07:59 +02:00
const auto WLSURF = CWLSurface : : fromResource ( pSurface ) ;
2024-07-22 12:37:54 +02:00
CRegion damageBox = WLSURF ? WLSURF - > computeDamage ( ) : CRegion { } ;
2024-02-19 11:34:55 +00:00
if ( ! WLSURF ) {
2024-02-19 11:24:54 +00:00
Debug : : log ( ERR , " BUG THIS: No CWLSurface for surface in damageSurface!!! " ) ;
2024-06-08 10:07:59 +02:00
return ;
2024-02-19 11:34:55 +00:00
}
2024-04-08 15:33:02 +01:00
2023-06-11 21:52:13 +02:00
if ( scale ! = 1.0 )
2024-02-19 11:24:54 +00:00
damageBox . scale ( scale ) ;
2022-03-21 16:13:43 +01:00
2022-07-04 17:55:33 +02:00
// schedule frame events
2024-07-21 13:09:54 +02:00
g_pCompositor - > scheduleFrameForMonitor ( g_pCompositor - > getMonitorFromVector ( Vector2D ( x , y ) ) , Aquamarine : : IOutput : : AQ_SCHEDULE_DAMAGE ) ;
2022-07-04 17:55:33 +02:00
2023-07-19 20:09:49 +02:00
if ( damageBox . empty ( ) )
2022-06-28 15:30:46 +02:00
return ;
2024-02-19 11:24:54 +00:00
damageBox . translate ( { x , y } ) ;
2023-07-19 20:09:49 +02:00
CRegion damageBoxForEach ;
2022-07-28 22:15:56 +02:00
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2023-03-16 16:32:03 +00:00
if ( ! m - > output )
continue ;
2024-02-19 11:24:54 +00:00
damageBoxForEach . set ( damageBox ) ;
damageBoxForEach . translate ( { - m - > vecPosition . x , - m - > vecPosition . y } ) . scale ( m - > scale ) ;
2022-07-28 22:15:56 +02:00
2022-08-23 16:07:47 +02:00
m - > addDamage ( & damageBoxForEach ) ;
2022-03-21 16:13:43 +01:00
}
2024-03-03 18:39:20 +00:00
static auto PLOGDAMAGE = CConfigValue < Hyprlang : : INT > ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-03-03 18:39:20 +00:00
if ( * PLOGDAMAGE )
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " Damage: Surface (extents): xy: {}, {} wh: {}, {} " , damageBox . pixman ( ) - > extents . x1 , damageBox . pixman ( ) - > extents . y1 ,
2023-07-19 20:09:49 +02:00
damageBox . pixman ( ) - > extents . x2 - damageBox . pixman ( ) - > extents . x1 , damageBox . pixman ( ) - > extents . y2 - damageBox . pixman ( ) - > extents . y1 ) ;
2022-04-14 16:43:29 +02:00
}
2022-03-21 16:13:43 +01:00
2024-04-27 12:43:12 +01:00
void CHyprRenderer : : damageWindow ( PHLWINDOW pWindow , bool forceFull ) {
2022-08-10 23:14:53 +02:00
if ( g_pCompositor - > m_bUnsafeState )
return ;
2024-03-30 18:14:26 -07:00
CBox windowBox = pWindow - > getFullWindowBoundingBox ( ) ;
2024-04-02 20:32:39 +01:00
const auto PWINDOWWORKSPACE = pWindow - > m_pWorkspace ;
2024-03-30 18:14:26 -07:00
if ( PWINDOWWORKSPACE & & PWINDOWWORKSPACE - > m_vRenderOffset . isBeingAnimated ( ) & & ! pWindow - > m_bPinned )
windowBox . translate ( PWINDOWWORKSPACE - > m_vRenderOffset . value ( ) ) ;
windowBox . translate ( pWindow - > m_vFloatingOffset ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2024-10-19 23:03:29 +01:00
if ( forceFull | | g_pHyprRenderer - > shouldRenderWindow ( pWindow , m ) ) { // only damage if window is rendered on monitor
2024-03-30 18:14:26 -07:00
CBox fixedDamageBox = { windowBox . x - m - > vecPosition . x , windowBox . y - m - > vecPosition . y , windowBox . width , windowBox . height } ;
fixedDamageBox . scale ( m - > scale ) ;
m - > addDamage ( & fixedDamageBox ) ;
}
2022-06-29 11:21:42 +02:00
}
2022-05-05 15:09:26 +02:00
2024-08-26 20:24:30 +02:00
for ( auto const & wd : pWindow - > m_dWindowDecorations )
2023-06-27 13:23:53 +02:00
wd - > damageEntire ( ) ;
2024-03-03 18:39:20 +00:00
static auto PLOGDAMAGE = CConfigValue < Hyprlang : : INT > ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-03-03 18:39:20 +00:00
if ( * PLOGDAMAGE )
2024-03-30 18:14:26 -07:00
Debug : : log ( LOG , " Damage: Window ({}): xy: {}, {} wh: {}, {} " , pWindow - > m_szTitle , windowBox . x , windowBox . y , windowBox . width , windowBox . height ) ;
2022-03-21 16:13:43 +01:00
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : damageMonitor ( PHLMONITOR pMonitor ) {
2022-09-13 15:25:42 +02:00
if ( g_pCompositor - > m_bUnsafeState | | pMonitor - > isMirror ( ) )
2022-08-10 23:14:53 +02:00
return ;
2023-11-04 17:03:05 +00:00
CBox damageBox = { 0 , 0 , INT16_MAX , INT16_MAX } ;
2022-08-23 16:07:47 +02:00
pMonitor - > addDamage ( & damageBox ) ;
2022-05-05 15:09:26 +02:00
2024-03-03 18:39:20 +00:00
static auto PLOGDAMAGE = CConfigValue < Hyprlang : : INT > ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-03-03 18:39:20 +00:00
if ( * PLOGDAMAGE )
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Damage: Monitor {} " , pMonitor - > szName ) ;
2022-04-14 16:43:29 +02:00
}
2022-03-21 16:13:43 +01:00
2024-06-14 14:45:32 +03:00
void CHyprRenderer : : damageBox ( CBox * pBox , bool skipFrameSchedule ) {
2022-08-10 23:14:53 +02:00
if ( g_pCompositor - > m_bUnsafeState )
return ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2022-09-13 15:25:42 +02:00
if ( m - > isMirror ( ) )
continue ; // don't damage mirrors traditionally
2024-10-31 00:20:32 +01:00
if ( ! skipFrameSchedule ) {
CBox damageBox = { pBox - > x - m - > vecPosition . x , pBox - > y - m - > vecPosition . y , pBox - > width , pBox - > height } ;
damageBox . scale ( m - > scale ) ;
2024-06-14 14:45:32 +03:00
m - > addDamage ( & damageBox ) ;
2024-10-31 00:20:32 +01:00
}
2022-04-17 18:47:10 +02:00
}
2022-05-05 15:09:26 +02:00
2024-03-03 18:39:20 +00:00
static auto PLOGDAMAGE = CConfigValue < Hyprlang : : INT > ( " debug:log_damage " ) ;
2022-06-07 20:41:40 +02:00
2024-03-03 18:39:20 +00:00
if ( * PLOGDAMAGE )
2023-09-06 12:51:36 +02:00
Debug : : log ( LOG , " Damage: Box: xy: {}, {} wh: {}, {} " , pBox - > x , pBox - > y , pBox - > width , pBox - > height ) ;
2022-03-31 17:25:23 +02:00
}
2022-05-05 14:02:30 +02:00
void CHyprRenderer : : damageBox ( const int & x , const int & y , const int & w , const int & h ) {
2023-11-04 17:03:05 +00:00
CBox box = { x , y , w , h } ;
2022-05-05 14:02:30 +02:00
damageBox ( & box ) ;
}
2023-07-19 20:09:49 +02:00
void CHyprRenderer : : damageRegion ( const CRegion & rg ) {
2024-08-26 17:25:39 +02:00
for ( auto const & RECT : rg . getRects ( ) ) {
2022-07-16 12:44:45 +02:00
damageBox ( RECT . x1 , RECT . y1 , RECT . x2 - RECT . x1 , RECT . y2 - RECT . y1 ) ;
}
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : damageMirrorsWith ( PHLMONITOR pMonitor , const CRegion & pRegion ) {
2024-08-26 20:24:30 +02:00
for ( auto const & mirror : pMonitor - > mirrors ) {
2022-09-13 15:25:42 +02:00
2024-04-24 17:29:41 +02:00
// transform the damage here, so it won't get clipped by the monitor damage ring
auto monitor = mirror ;
auto mirrored = pMonitor ;
CRegion transformed { pRegion } ;
// we want to transform to the same box as in CHyprOpenGLImpl::renderMirrored
double scale = std : : min ( monitor - > vecTransformedSize . x / mirrored - > vecTransformedSize . x , monitor - > vecTransformedSize . y / mirrored - > vecTransformedSize . y ) ;
CBox monbox = { 0 , 0 , mirrored - > vecTransformedSize . x * scale , mirrored - > vecTransformedSize . y * scale } ;
monbox . x = ( monitor - > vecTransformedSize . x - monbox . w ) / 2 ;
monbox . y = ( monitor - > vecTransformedSize . y - monbox . h ) / 2 ;
2024-07-21 13:09:54 +02:00
transformed . scale ( scale ) ;
2024-06-19 16:20:06 +02:00
transformed . transform ( wlTransformToHyprutils ( mirrored - > transform ) , mirrored - > vecPixelSize . x * scale , mirrored - > vecPixelSize . y * scale ) ;
2024-04-24 17:29:41 +02:00
transformed . translate ( Vector2D ( monbox . x , monbox . y ) ) ;
mirror - > addDamage ( & transformed ) ;
2023-03-04 00:48:02 +00:00
2024-10-19 23:03:29 +01:00
g_pCompositor - > scheduleFrameForMonitor ( mirror . lock ( ) , Aquamarine : : IOutput : : AQ_SCHEDULE_DAMAGE ) ;
2022-09-13 15:25:42 +02:00
}
}
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : renderDragIcon ( PHLMONITOR pMonitor , timespec * time ) {
2024-05-11 17:13:20 +01:00
PROTO : : data - > renderDND ( pMonitor , time ) ;
2022-04-14 16:43:29 +02:00
}
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
}
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : applyMonitorRule ( PHLMONITOR pMonitor , SMonitorRule * pMonitorRule , bool force ) {
2022-04-19 19:01:23 +02:00
2024-03-03 18:39:20 +00:00
static auto PDISABLESCALECHECKS = CConfigValue < Hyprlang : : INT > ( " 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 22:05:36 +00: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 22:05:36 +00:00
if ( RULE - > disabled ) {
2022-07-27 12:32:00 +02:00
if ( pMonitor - > m_bEnabled )
pMonitor - > onDisconnect ( ) ;
2024-04-29 01:28:26 +01:00
pMonitor - > events . modeChanged . emit ( ) ;
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
2024-07-21 13:09:54 +02:00
if ( pMonitor - > output - > nonDesktop )
2023-02-15 15:50:51 +01:00
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 22:05:36 +00: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 ) ;
2024-06-09 22:28:51 +02:00
pMonitor - > setMirror ( RULE - > mirrorOf ) ;
2022-06-30 23:55:28 +02:00
return true ;
2022-04-19 19:01:23 +02:00
}
2024-02-02 15:36:13 +00: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 = { } ;
2024-05-03 17:58:40 +01:00
pMonitor - > currentMode = nullptr ;
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setFormat ( DRM_FORMAT_XRGB8888 ) ;
2024-08-31 08:07:52 -05:00
pMonitor - > prevDrmFormat = pMonitor - > drmFormat ;
pMonitor - > drmFormat = DRM_FORMAT_XRGB8888 ;
2024-08-06 14:52:19 +01:00
pMonitor - > output - > state - > resetExplicitFences ( ) ;
2024-07-21 13:09:54 +02:00
bool autoScale = false ;
2023-05-09 15:01:45 +02:00
2024-02-14 22:05:36 +00:00
if ( RULE - > scale > 0.1 ) {
pMonitor - > scale = RULE - > scale ;
2022-12-14 17:57:18 +00:00
} else {
2023-12-31 13:54:24 +01:00
autoScale = true ;
2022-12-14 17:57:18 +00:00
const auto DEFAULTSCALE = pMonitor - > getDefaultScale ( ) ;
2023-12-22 23:00:36 +01:00
pMonitor - > scale = DEFAULTSCALE ;
2022-12-14 17:57:18 +00:00
}
2022-04-19 19:01:23 +02:00
2024-07-21 13:09:54 +02:00
pMonitor - > setScale = pMonitor - > scale ;
2024-02-14 22:05:36 +00:00
pMonitor - > transform = RULE - > transform ;
2022-11-18 14:15:19 +00:00
2024-07-21 13:09:54 +02:00
const auto WLRREFRESHRATE = pMonitor - > output - > getBackend ( ) - > type ( ) = = Aquamarine : : eBackendType : : AQ_BACKEND_DRM ? RULE - > refreshRate * 1000 : 0 ;
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 22:05:36 +00:00
if ( RULE - > resolution ! = Vector2D ( ) & & RULE - > resolution ! = Vector2D ( - 1 , - 1 ) & & RULE - > resolution ! = Vector2D ( - 1 , - 2 ) ) {
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > output - > modes . empty ( ) & & RULE - > drmMode . type ! = DRM_MODE_TYPE_USERDEF ) {
bool found = false ;
2022-07-30 22:54:29 +02:00
2024-08-26 20:24:30 +02:00
for ( auto const & mode : pMonitor - > output - > modes ) {
2022-07-30 22:54:29 +02:00
// if delta of refresh rate, w and h chosen and mode is < 1 we accept it
2024-07-21 13:09:54 +02:00
if ( DELTALESSTHAN ( mode - > pixelSize . x , RULE - > resolution . x , 1 ) & & DELTALESSTHAN ( mode - > pixelSize . y , RULE - > resolution . y , 1 ) & &
DELTALESSTHAN ( mode - > refreshRate / 1000.f , RULE - > refreshRate , 1 ) ) {
pMonitor - > output - > state - > setMode ( mode ) ;
2022-07-30 22:54:29 +02:00
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > state . test ( ) ) {
Debug : : log ( LOG , " Monitor {}: REJECTED available mode: {}x{}@{:2f}! " , pMonitor - > output - > name , mode - > pixelSize . x , mode - > pixelSize . y ,
mode - > refreshRate / 1000.f ) ;
2022-07-30 22:54:29 +02:00
continue ;
}
2024-02-14 22:05:36 +00:00
Debug : : log ( LOG , " Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying. " , pMonitor - > output - > name , RULE - > resolution ,
2024-07-21 13:09:54 +02:00
( float ) RULE - > refreshRate , mode - > pixelSize . x , mode - > pixelSize . y , mode - > refreshRate ) ;
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
2024-07-21 13:09:54 +02:00
pMonitor - > refreshRate = mode - > refreshRate / 1000.f ;
pMonitor - > vecSize = mode - > pixelSize ;
2024-05-03 17:58:40 +01:00
pMonitor - > currentMode = mode ;
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-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setCustomMode ( makeShared < Aquamarine : : SOutputMode > ( Aquamarine : : SOutputMode { . pixelSize = RULE - > resolution , . refreshRate = WLRREFRESHRATE } ) ) ;
2024-02-14 22:05:36 +00:00
pMonitor - > vecSize = RULE - > resolution ;
pMonitor - > refreshRate = RULE - > refreshRate ;
2022-04-19 19:01:23 +02:00
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > state . test ( ) ) {
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
2024-07-21 13:09:54 +02:00
const auto PREFERREDMODE = pMonitor - > output - > preferredMode ( ) ;
2022-06-28 11:12:01 +02:00
2022-07-30 22:54:29 +02:00
if ( ! PREFERREDMODE ) {
2024-02-14 22:05:36 +00: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-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setMode ( PREFERREDMODE ) ;
2022-04-19 19:01:23 +02:00
2024-02-14 22:05:36 +00:00
Debug : : log ( ERR , " Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
2024-07-21 13:09:54 +02:00
( float ) RULE - > refreshRate , PREFERREDMODE - > pixelSize . x , PREFERREDMODE - > pixelSize . y , PREFERREDMODE - > refreshRate / 1000.f ) ;
2022-04-19 19:01:23 +02:00
2024-07-21 13:09:54 +02:00
pMonitor - > refreshRate = PREFERREDMODE - > refreshRate / 1000.f ;
pMonitor - > vecSize = PREFERREDMODE - > pixelSize ;
2024-05-03 17:58:40 +01:00
pMonitor - > currentMode = PREFERREDMODE ;
2022-07-30 22:54:29 +02:00
} else {
2024-02-14 22:05:36 +00: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 13:10:11 +01:00
} else {
2023-05-09 15:01:45 +02:00
// custom resolution
bool fail = false ;
2024-02-14 22:05:36 +00:00
if ( RULE - > drmMode . type = = DRM_MODE_TYPE_USERDEF ) {
2024-07-21 13:09:54 +02:00
if ( pMonitor - > output - > getBackend ( ) - > type ( ) ! = Aquamarine : : eBackendType : : AQ_BACKEND_DRM ) {
2023-05-09 15:01:45 +02:00
Debug : : log ( ERR , " Tried to set custom modeline on non-DRM output " ) ;
fail = true ;
2024-08-18 20:19:13 +02:00
} else
pMonitor - > output - > state - > setCustomMode ( makeShared < Aquamarine : : SOutputMode > (
Aquamarine : : SOutputMode { . pixelSize = { RULE - > drmMode . hdisplay , RULE - > drmMode . vdisplay } , . refreshRate = RULE - > drmMode . vrefresh , . modeInfo = RULE - > drmMode } ) ) ;
2024-07-21 13:09:54 +02:00
} else
pMonitor - > output - > state - > setCustomMode ( makeShared < Aquamarine : : SOutputMode > ( Aquamarine : : SOutputMode { . pixelSize = RULE - > resolution , . refreshRate = WLRREFRESHRATE } ) ) ;
2023-05-09 15:01:45 +02:00
2024-02-14 22:05:36 +00:00
pMonitor - > vecSize = RULE - > resolution ;
pMonitor - > refreshRate = RULE - > refreshRate ;
2022-09-24 13:10:11 +01:00
2024-07-21 13:09:54 +02:00
if ( fail | | ! pMonitor - > state . test ( ) ) {
2022-09-24 13:10:11 +01:00
Debug : : log ( ERR , " Custom resolution FAILED, falling back to preferred " ) ;
2024-07-21 13:09:54 +02:00
const auto PREFERREDMODE = pMonitor - > output - > preferredMode ( ) ;
2022-09-24 13:10:11 +01:00
if ( ! PREFERREDMODE ) {
2024-02-14 22:05:36 +00: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 13:10:11 +01:00
return true ;
}
// Preferred is valid
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setMode ( PREFERREDMODE ) ;
2022-09-24 13:10:11 +01:00
2024-02-14 22:05:36 +00:00
Debug : : log ( ERR , " Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
2024-07-21 13:09:54 +02:00
( float ) RULE - > refreshRate , PREFERREDMODE - > pixelSize . x , PREFERREDMODE - > pixelSize . y , PREFERREDMODE - > refreshRate / 1000.f ) ;
2022-09-24 13:10:11 +01:00
2024-07-21 13:09:54 +02:00
pMonitor - > refreshRate = PREFERREDMODE - > refreshRate / 1000.f ;
pMonitor - > vecSize = PREFERREDMODE - > pixelSize ;
2023-05-09 15:01:45 +02:00
pMonitor - > customDrmMode = { } ;
2024-07-21 13:09:54 +02:00
} else
2024-02-14 22:05:36 +00:00
Debug : : log ( LOG , " Set a custom mode {:X0}@{:2f} (mode not found in monitor modes) " , RULE - > resolution , ( float ) RULE - > refreshRate ) ;
2022-09-22 00:45:56 +02:00
}
2024-02-14 22:05:36 +00:00
} else if ( RULE - > resolution ! = Vector2D ( ) ) {
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > output - > modes . empty ( ) ) {
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 22:05:36 +00:00
if ( RULE - > resolution = = Vector2D ( - 1 , - 1 ) ) {
2024-08-26 20:24:30 +02:00
for ( auto const & mode : pMonitor - > output - > modes ) {
2024-07-21 13:09:54 +02:00
if ( ( mode - > pixelSize . x > = currentWidth & & mode - > pixelSize . y > = currentHeight & & mode - > refreshRate > = ( currentRefresh - 1000.f ) ) | |
mode - > refreshRate > ( currentRefresh + 3000.f ) ) {
pMonitor - > output - > state - > setMode ( mode ) ;
if ( pMonitor - > state . test ( ) ) {
currentWidth = mode - > pixelSize . x ;
currentHeight = mode - > pixelSize . y ;
currentRefresh = mode - > refreshRate ;
2022-12-16 17:17:31 +00:00
success = true ;
}
}
2022-09-22 00:45:56 +02:00
}
} else {
2024-08-26 20:24:30 +02:00
for ( auto const & mode : pMonitor - > output - > modes ) {
2024-07-21 13:09:54 +02:00
if ( ( mode - > pixelSize . x > = currentWidth & & mode - > pixelSize . y > = currentHeight & & mode - > refreshRate > = ( currentRefresh - 1000.f ) ) | |
( mode - > pixelSize . x > currentWidth & & mode - > pixelSize . y > currentHeight ) ) {
pMonitor - > output - > state - > setMode ( mode ) ;
if ( pMonitor - > state . test ( ) ) {
currentWidth = mode - > pixelSize . x ;
currentHeight = mode - > pixelSize . y ;
currentRefresh = mode - > refreshRate ;
2022-12-16 17:17:31 +00:00
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-07-21 13:09:54 +02:00
if ( pMonitor - > output - > state - > state ( ) . mode )
Debug : : log ( LOG , " Monitor {}: REJECTED mode: {:X0}@{:2f}! Falling back to preferred: {}x{}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
( float ) RULE - > refreshRate , pMonitor - > output - > state - > state ( ) . mode - > pixelSize . x , pMonitor - > output - > state - > state ( ) . mode - > pixelSize . y ,
pMonitor - > output - > state - > state ( ) . mode - > refreshRate / 1000.f ) ;
2022-09-25 20:07:48 +02:00
2024-07-21 13:09:54 +02:00
const auto PREFERREDMODE = pMonitor - > output - > preferredMode ( ) ;
2022-09-21 22:29:52 +02:00
2022-09-22 00:45:56 +02:00
if ( ! PREFERREDMODE ) {
2024-02-14 22:05:36 +00: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-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setMode ( PREFERREDMODE ) ;
2022-09-21 22:29:52 +02:00
2024-02-14 22:05:36 +00:00
Debug : : log ( ERR , " Monitor {} got an invalid requested mode: {:X0}@{:2f}, using the preferred one instead: {}x{}@{:2f} " , pMonitor - > output - > name , RULE - > resolution ,
2024-07-21 13:09:54 +02:00
( float ) RULE - > refreshRate , PREFERREDMODE - > pixelSize . x , PREFERREDMODE - > pixelSize . y , PREFERREDMODE - > refreshRate / 1000.f ) ;
2022-09-21 22:29:52 +02:00
2024-07-21 13:09:54 +02:00
pMonitor - > refreshRate = PREFERREDMODE - > refreshRate / 1000.f ;
pMonitor - > vecSize = PREFERREDMODE - > pixelSize ;
2024-05-03 17:58:40 +01:00
pMonitor - > currentMode = PREFERREDMODE ;
2022-09-22 00:45:56 +02:00
} else {
2022-09-21 22:29:52 +02:00
2023-09-20 15:25:03 +00: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 17:17:31 +00:00
pMonitor - > vecSize = Vector2D ( currentWidth , currentHeight ) ;
2022-09-21 22:29:52 +02:00
}
2022-09-22 00:45:56 +02:00
}
} else {
2024-07-21 13:09:54 +02:00
const auto PREFERREDMODE = pMonitor - > output - > preferredMode ( ) ;
2022-07-30 22:54:29 +02:00
if ( ! PREFERREDMODE ) {
2023-09-20 15:25:03 +00:00
Debug : : log ( ERR , " Monitor {} has NO PREFERRED MODE " , pMonitor - > output - > name ) ;
2022-07-30 22:54:29 +02:00
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > output - > modes . empty ( ) ) {
2024-08-26 20:24:30 +02:00
for ( auto const & mode : pMonitor - > output - > modes ) {
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setMode ( mode ) ;
2022-08-02 22:20:45 +02:00
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > state . test ( ) ) {
Debug : : log ( LOG , " Monitor {}: REJECTED available mode: {}x{}@{:2f}! " , pMonitor - > output - > name , mode - > pixelSize . x , mode - > pixelSize . y ,
mode - > refreshRate / 1000.f ) ;
2022-08-02 22:20:45 +02:00
continue ;
}
2024-02-14 22:05:36 +00:00
Debug : : log ( LOG , " Monitor {}: requested {:X0}@{:2f}, found available mode: {}x{}@{}mHz, applying. " , pMonitor - > output - > name , RULE - > resolution ,
2024-07-21 13:09:54 +02:00
( float ) RULE - > refreshRate , mode - > pixelSize . x , mode - > pixelSize . y , mode - > refreshRate ) ;
2022-08-02 22:20:45 +02:00
2024-07-21 13:09:54 +02:00
pMonitor - > refreshRate = mode - > refreshRate / 1000.f ;
pMonitor - > vecSize = mode - > pixelSize ;
2024-05-03 17:58:40 +01:00
pMonitor - > currentMode = mode ;
2022-08-02 22:20:45 +02:00
break ;
}
}
} else {
// Preferred is valid
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setMode ( PREFERREDMODE ) ;
2022-08-02 22:20:45 +02:00
2024-07-21 13:09:54 +02:00
pMonitor - > vecSize = PREFERREDMODE - > pixelSize ;
pMonitor - > refreshRate = PREFERREDMODE - > refreshRate / 1000.f ;
2024-05-03 17:58:40 +01:00
pMonitor - > currentMode = PREFERREDMODE ;
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-07-21 13:09:54 +02:00
pMonitor - > vrrActive = pMonitor - > output - > state - > state ( ) . adaptiveSync // 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 ;
2024-07-21 13:09:54 +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
bool set10bit = false ;
2024-08-26 20:24:30 +02:00
for ( auto const & fmt : formats [ ( int ) ! RULE - > enable10bit ] ) {
2024-07-21 13:09:54 +02:00
pMonitor - > output - > state - > setFormat ( fmt . second ) ;
2024-08-31 08:07:52 -05:00
pMonitor - > prevDrmFormat = pMonitor - > drmFormat ;
pMonitor - > drmFormat = fmt . second ;
2024-07-21 13:09:54 +02:00
if ( ! pMonitor - > state . test ( ) ) {
Debug : : log ( ERR , " output {} failed basic test on format {} " , pMonitor - > szName , fmt . first ) ;
} else {
Debug : : log ( LOG , " output {} succeeded basic test on format {} " , pMonitor - > szName , fmt . first ) ;
if ( RULE - > enable10bit & & fmt . first . contains ( " 101010 " ) )
set10bit = true ;
break ;
}
}
pMonitor - > enabled10bit = set10bit ;
2023-12-22 19:54:05 +01:00
Vector2D logicalSize = pMonitor - > vecPixelSize / pMonitor - > scale ;
2024-03-03 18:39:20 +00: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 ;
2024-07-21 13:09:54 +02:00
if ( logicalZero = = logicalZero . round ( ) )
2023-12-23 00:09:55 +01:00
pMonitor - > scale = scaleZero ;
2024-07-21 13:09:54 +02:00
else {
2023-12-23 00:09:55 +01:00
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
}
2022-10-27 13:26:47 +01:00
}
}
2024-07-21 13:09:54 +02:00
pMonitor - > output - > scheduleFrame ( ) ;
2023-09-22 20:15:06 +01:00
2024-01-28 01:57:13 +00: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 19:11:03 +00:00
2024-07-21 13:09:54 +02:00
Vector2D xfmd = pMonitor - > transform % 2 = = 1 ? Vector2D { pMonitor - > vecPixelSize . y , pMonitor - > vecPixelSize . x } : pMonitor - > vecPixelSize ;
pMonitor - > vecSize = ( xfmd / pMonitor - > scale ) . round ( ) ;
pMonitor - > vecTransformedSize = xfmd ;
2022-05-29 12:27:45 +02:00
2022-11-05 18:04:44 +00:00
if ( pMonitor - > createdByUser ) {
2023-11-04 17:03:05 +00:00
CBox transformedBox = { 0 , 0 , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y } ;
2024-07-21 13:09:54 +02:00
transformedBox . transform ( wlTransformToHyprutils ( invertTransform ( pMonitor - > transform ) ) , pMonitor - > vecTransformedSize . x , pMonitor - > vecTransformedSize . y ) ;
2022-11-05 18:04:44 +00:00
pMonitor - > vecPixelSize = Vector2D ( transformedBox . width , transformedBox . height ) ;
}
2023-11-24 10:54:21 +00:00
pMonitor - > updateMatrix ( ) ;
2024-02-02 15:36:13 +00:00
if ( WAS10B ! = pMonitor - > enabled10bit | | OLDRES ! = pMonitor - > vecPixelSize )
g_pHyprOpenGL - > destroyMonitorResources ( pMonitor ) ;
2022-10-07 22:19:23 +01:00
2023-08-14 14:22:06 +02:00
g_pCompositor - > arrangeMonitors ( ) ;
2022-04-21 18:11:28 +02:00
2024-06-19 18:25:20 +02:00
pMonitor - > damage . setSize ( pMonitor - > vecTransformedSize ) ;
2023-04-07 12:18:40 +01:00
2024-01-14 13:56:35 +00: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 ) {
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-01-14 13:56:35 +00:00
w - > updateSurfaceScaleTransformDetails ( ) ;
}
}
2022-04-21 18:11:28 +02:00
// updato us
arrangeLayersForMonitor ( pMonitor - > ID ) ;
2022-09-13 15:25:42 +02:00
// reload to fix mirrors
g_pConfigManager - > m_bWantsMonitorReload = true ;
2023-09-20 15:25:03 +00: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
2024-04-29 01:28:26 +01:00
pMonitor - > events . modeChanged . emit ( ) ;
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
2024-06-08 10:07:59 +02:00
void CHyprRenderer : : setCursorSurface ( SP < CWLSurface > surf , int hotspotX , int hotspotY , bool force ) {
2023-09-29 17:51:07 +01:00
m_bCursorHasSurface = surf ;
2023-12-18 16:06:06 +00:00
m_sLastCursorData . name = " " ;
m_sLastCursorData . surf = surf ;
m_sLastCursorData . hotspotX = hotspotX ;
m_sLastCursorData . hotspotY = hotspotY ;
2023-10-29 18:09:05 +00:00
2024-02-21 13:48:48 +00:00
if ( m_bCursorHidden & & ! force )
return ;
2024-05-05 22:18:10 +01:00
g_pCursorManager - > setCursorSurface ( surf , { hotspotX , hotspotY } ) ;
2023-09-29 17:51:07 +01:00
}
2023-12-20 13:00:27 +01:00
2023-12-20 21:40:44 +01:00
void CHyprRenderer : : setCursorFromName ( const std : : string & name , bool force ) {
2023-09-29 17:51:07 +01:00
m_bCursorHasSurface = true ;
2024-02-21 13:48:48 +00:00
if ( name = = m_sLastCursorData . name & & ! force )
2023-10-29 18:09:05 +00:00
return ;
m_sLastCursorData . name = name ;
2023-10-30 00:18:40 +00:00
m_sLastCursorData . surf . reset ( ) ;
2023-10-29 18:09:05 +00:00
2024-02-21 13:48:48 +00:00
if ( m_bCursorHidden & & ! force )
return ;
2024-03-09 16:52:59 +00:00
g_pCursorManager - > setCursorFromName ( name ) ;
2023-09-29 17:51:07 +01:00
}
2022-06-24 23:27:02 +02:00
void CHyprRenderer : : ensureCursorRenderingMode ( ) {
2024-08-10 13:42:45 -07:00
static auto PCURSORTIMEOUT = CConfigValue < Hyprlang : : FLOAT > ( " cursor:inactive_timeout " ) ;
2024-05-09 22:23:01 +01:00
static auto PHIDEONTOUCH = CConfigValue < Hyprlang : : INT > ( " cursor:hide_on_touch " ) ;
static auto PHIDEONKEY = CConfigValue < Hyprlang : : INT > ( " cursor:hide_on_key_press " ) ;
2022-06-24 23:27:02 +02:00
2024-03-28 02:04:30 +00:00
if ( * PCURSORTIMEOUT < = 0 )
m_sCursorHiddenConditions . hiddenOnTimeout = false ;
if ( * PHIDEONTOUCH = = 0 )
m_sCursorHiddenConditions . hiddenOnTouch = false ;
if ( * PHIDEONKEY = = 0 )
m_sCursorHiddenConditions . hiddenOnKeyboard = false ;
2023-01-17 11:47:39 +01:00
2024-03-28 02:04:30 +00:00
if ( * PCURSORTIMEOUT > 0 )
m_sCursorHiddenConditions . hiddenOnTimeout = * PCURSORTIMEOUT < g_pInputManager - > m_tmrLastCursorMovement . getSeconds ( ) ;
2022-06-24 23:27:02 +02:00
2024-03-28 02:04:30 +00:00
const bool HIDE = m_sCursorHiddenConditions . hiddenOnTimeout | | m_sCursorHiddenConditions . hiddenOnTouch | | m_sCursorHiddenConditions . hiddenOnKeyboard ;
2022-06-24 23:27:02 +02:00
2024-03-28 02:04:30 +00:00
if ( HIDE = = m_bCursorHidden )
return ;
2023-12-20 21:40:44 +01:00
2024-03-28 02:04:30 +00:00
if ( HIDE ) {
Debug : : log ( LOG , " Hiding the cursor (hl-mandated) " ) ;
2022-06-24 23:27:02 +02:00
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pPointerManager - > softwareLockedFor ( m ) )
2024-03-28 02:04:30 +00:00
continue ;
2023-12-20 21:40:44 +01:00
2024-10-19 23:03:29 +01:00
g_pHyprRenderer - > damageMonitor ( m ) ; // TODO: maybe just damage the cursor area?
2022-06-24 23:27:02 +02:00
}
2024-03-28 02:04:30 +00:00
setCursorHidden ( true ) ;
2022-06-24 23:27:02 +02:00
} else {
2024-03-28 02:04:30 +00:00
Debug : : log ( LOG , " Showing the cursor (hl-mandated) " ) ;
2024-08-26 20:24:30 +02:00
for ( auto const & m : g_pCompositor - > m_vMonitors ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pPointerManager - > softwareLockedFor ( m ) )
2024-03-28 02:04:30 +00:00
continue ;
2024-10-19 23:03:29 +01:00
g_pHyprRenderer - > damageMonitor ( m ) ; // TODO: maybe just damage the cursor area?
2024-03-28 02:04:30 +00:00
}
2023-12-20 21:40:44 +01:00
setCursorHidden ( false ) ;
2022-06-24 23:27:02 +02:00
}
2022-06-26 13:43:32 +02:00
}
2023-12-20 21:40:44 +01:00
void CHyprRenderer : : setCursorHidden ( bool hide ) {
if ( hide = = m_bCursorHidden )
return ;
m_bCursorHidden = hide ;
if ( hide ) {
2024-05-05 22:18:10 +01:00
g_pPointerManager - > resetCursorImage ( ) ;
2023-12-20 21:40:44 +01:00
return ;
}
if ( m_sLastCursorData . surf . has_value ( ) )
setCursorSurface ( m_sLastCursorData . surf . value ( ) , m_sLastCursorData . hotspotX , m_sLastCursorData . hotspotY , true ) ;
else if ( ! m_sLastCursorData . name . empty ( ) )
setCursorFromName ( m_sLastCursorData . name , true ) ;
else
setCursorFromName ( " left_ptr " , true ) ;
}
2022-06-26 13:43:32 +02:00
bool CHyprRenderer : : shouldRenderCursor ( ) {
2023-12-29 00:04:01 +01:00
return ! m_bCursorHidden & & m_bCursorHasSurface ;
2022-07-11 23:38:10 +02:00
}
2023-03-24 19:23:16 +00:00
2024-10-19 23:03:29 +01:00
std : : tuple < float , float , float > CHyprRenderer : : getRenderTimes ( PHLMONITOR pMonitor ) {
2023-03-24 19:23:16 +00:00
const auto POVERLAY = & g_pDebugOverlay - > m_mMonitorOverlays [ pMonitor ] ;
float avgRenderTime = 0 ;
float maxRenderTime = 0 ;
float minRenderTime = 9999 ;
2024-08-26 17:25:39 +02:00
for ( auto const & rt : POVERLAY - > m_dLastRenderTimes ) {
2023-03-24 19:23:16 +00:00
if ( rt > maxRenderTime )
maxRenderTime = rt ;
if ( rt < minRenderTime )
minRenderTime = rt ;
avgRenderTime + = rt ;
}
avgRenderTime / = POVERLAY - > m_dLastRenderTimes . size ( ) = = 0 ? 1 : POVERLAY - > m_dLastRenderTimes . size ( ) ;
return std : : make_tuple < > ( avgRenderTime , maxRenderTime , minRenderTime ) ;
}
2023-04-04 14:49:58 +01:00
static int handleCrashLoop ( void * data ) {
2024-12-03 18:58:24 +00:00
g_pHyprNotificationOverlay - > addNotification ( " Hyprland will crash in " + std : : to_string ( 10 - ( int ) ( g_pHyprRenderer - > m_fCrashingDistort * 2.f ) ) + " s. " , CHyprColor ( 0 ) , 5000 ,
2023-04-04 14:49:58 +01:00
ICON_INFO ) ;
g_pHyprRenderer - > m_fCrashingDistort + = 0.5f ;
if ( g_pHyprRenderer - > m_fCrashingDistort > = 5.5f )
2023-08-31 20:52:02 +00:00
raise ( SIGABRT ) ;
2023-04-04 14:49:58 +01:00
wl_event_source_timer_update ( g_pHyprRenderer - > m_pCrashingLoop , 1000 ) ;
return 1 ;
}
void CHyprRenderer : : initiateManualCrash ( ) {
2024-12-03 18:58:24 +00:00
g_pHyprNotificationOverlay - > addNotification ( " Manual crash initiated. Farewell... " , CHyprColor ( 0 ) , 5000 , ICON_INFO ) ;
2023-04-04 14:49:58 +01:00
m_pCrashingLoop = wl_event_loop_add_timer ( g_pCompositor - > m_sWLEventLoop , handleCrashLoop , nullptr ) ;
wl_event_source_timer_update ( m_pCrashingLoop , 1000 ) ;
m_bCrashingInProgress = true ;
m_fCrashingDistort = 0.5 ;
2023-04-04 22:04:32 +01:00
g_pHyprOpenGL - > m_tGlobalTimer . reset ( ) ;
2024-03-03 18:39:20 +00:00
static auto PDT = ( Hyprlang : : INT * const * ) ( g_pConfigManager - > getConfigValuePtr ( " debug:damage_tracking " ) ) ;
2024-02-18 15:00:34 +00:00
* * PDT = 0 ;
2023-04-14 15:16:43 +01:00
}
2023-07-19 16:13:55 +02:00
2024-04-02 20:32:39 +01:00
void CHyprRenderer : : setOccludedForMainWorkspace ( CRegion & region , PHLWORKSPACE pWorkspace ) {
2023-12-23 22:41:42 +01:00
CRegion rg ;
2024-10-27 18:45:38 +00:00
const auto PMONITOR = pWorkspace - > m_pMonitor . lock ( ) ;
2023-12-23 22:41:42 +01:00
2024-04-02 20:32:39 +01:00
if ( ! PMONITOR - > activeSpecialWorkspace )
2023-12-23 22:41:42 +01:00
return ;
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-02 20:32:39 +01:00
if ( ! w - > m_bIsMapped | | w - > isHidden ( ) | | w - > m_pWorkspace ! = PMONITOR - > activeSpecialWorkspace )
2023-12-23 22:41:42 +01:00
continue ;
if ( ! w - > opaque ( ) )
continue ;
const auto ROUNDING = w - > rounding ( ) * PMONITOR - > scale ;
2024-03-02 01:35:17 +01:00
const Vector2D POS = w - > m_vRealPosition . value ( ) + Vector2D { ROUNDING , ROUNDING } - PMONITOR - > vecPosition + ( w - > m_bPinned ? Vector2D { } : pWorkspace - > m_vRenderOffset . value ( ) ) ;
const Vector2D SIZE = w - > m_vRealSize . value ( ) - Vector2D { ROUNDING * 2 , ROUNDING * 2 } ;
2023-12-23 22:41:42 +01:00
CBox box = { POS . x , POS . y , SIZE . x , SIZE . y } ;
box . scale ( PMONITOR - > scale ) ;
rg . add ( box ) ;
}
region . subtract ( rg ) ;
}
2024-04-02 20:32:39 +01:00
void CHyprRenderer : : setOccludedForBackLayers ( CRegion & region , PHLWORKSPACE pWorkspace ) {
2024-06-21 19:25:34 +02:00
CRegion rg ;
2023-07-19 16:13:55 +02:00
2024-10-27 18:45:38 +00:00
const auto PMONITOR = pWorkspace - > m_pMonitor . lock ( ) ;
2024-06-21 19:25:34 +02:00
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
static auto PBLURSIZE = CConfigValue < Hyprlang : : INT > ( " decoration:blur:size " ) ;
static auto PBLURPASSES = CConfigValue < Hyprlang : : INT > ( " decoration:blur:passes " ) ;
const auto BLURRADIUS = * PBLUR ? ( * PBLURPASSES > 10 ? pow ( 2 , 15 ) : std : : clamp ( * PBLURSIZE , ( int64_t ) 1 , ( int64_t ) 40 ) * pow ( 2 , * PBLURPASSES ) ) : 0 ;
2023-07-19 16:13:55 +02:00
2024-08-26 20:24:30 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-02 20:32:39 +01:00
if ( ! w - > m_bIsMapped | | w - > isHidden ( ) | | w - > m_pWorkspace ! = pWorkspace )
2023-07-19 16:13:55 +02:00
continue ;
if ( ! w - > opaque ( ) )
continue ;
const auto ROUNDING = w - > rounding ( ) * PMONITOR - > scale ;
2024-03-02 01:35:17 +01:00
const Vector2D POS = w - > m_vRealPosition . value ( ) + Vector2D { ROUNDING , ROUNDING } - PMONITOR - > vecPosition + ( w - > m_bPinned ? Vector2D { } : pWorkspace - > m_vRenderOffset . value ( ) ) ;
const Vector2D SIZE = w - > m_vRealSize . value ( ) - Vector2D { ROUNDING * 2 , ROUNDING * 2 } ;
2023-07-19 16:13:55 +02:00
2023-11-04 17:03:05 +00:00
CBox box = { POS . x , POS . y , SIZE . x , SIZE . y } ;
2023-07-20 18:12:29 +02:00
2024-06-21 19:25:34 +02:00
box . scale ( PMONITOR - > scale ) . expand ( - BLURRADIUS ) ;
2024-04-03 14:09:58 +01:00
g_pHyprOpenGL - > m_RenderData . renderModif . applyToBox ( box ) ;
2023-07-20 18:12:29 +02:00
2023-11-11 14:37:17 +00: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
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : canSkipBackBufferClear ( PHLMONITOR pMonitor ) {
2024-08-26 20:24:30 +02:00
for ( auto const & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ] ) {
2023-07-20 14:11:05 +02:00
if ( ! ls - > layerSurface )
continue ;
2024-03-02 01:35:17 +01:00
if ( ls - > alpha . value ( ) < 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 15:24:24 +00:00
// TODO: cache maybe?
2024-06-08 10:07:59 +02:00
CRegion opaque = ls - > layerSurface - > surface - > current . opaque ;
CBox lsbox = { { } , ls - > layerSurface - > surface - > current . size } ;
2023-11-26 15:24:24 +00:00
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 21:48:33 +01:00
2024-10-19 23:03:29 +01:00
void CHyprRenderer : : recheckSolitaryForMonitor ( PHLMONITOR pMonitor ) {
2024-04-27 12:43:12 +01:00
pMonitor - > solitaryClient . reset ( ) ; // reset it, if we find one it will be set.
2023-09-28 21:48:33 +01:00
2024-05-06 02:24:11 +01:00
if ( g_pHyprNotificationOverlay - > hasAny ( ) | | g_pSessionLockManager - > isSessionLocked ( ) )
2024-02-14 11:09:18 +00:00
return ;
2024-04-02 20:32:39 +01:00
const auto PWORKSPACE = pMonitor - > activeWorkspace ;
2023-09-28 21:48:33 +01:00
2024-05-11 17:13:20 +01:00
if ( ! PWORKSPACE | | ! PWORKSPACE - > m_bHasFullscreenWindow | | PROTO : : data - > dndActive ( ) | | pMonitor - > activeSpecialWorkspace | | PWORKSPACE - > m_fAlpha . value ( ) ! = 1.f | |
2024-05-10 18:27:57 +01:00
PWORKSPACE - > m_vRenderOffset . value ( ) ! = Vector2D { } )
2023-09-28 21:48:33 +01:00
return ;
2024-11-22 16:01:02 +00:00
const auto PCANDIDATE = PWORKSPACE - > getFullscreenWindow ( ) ;
2023-09-28 21:48:33 +01:00
if ( ! PCANDIDATE )
return ; // ????
if ( ! PCANDIDATE - > opaque ( ) )
return ;
2024-03-02 01:35:17 +01:00
if ( PCANDIDATE - > m_vRealSize . value ( ) ! = pMonitor - > vecSize | | PCANDIDATE - > m_vRealPosition . value ( ) ! = pMonitor - > vecPosition | | PCANDIDATE - > m_vRealPosition . isBeingAnimated ( ) | |
2023-09-28 21:48:33 +01:00
PCANDIDATE - > m_vRealSize . isBeingAnimated ( ) )
return ;
if ( ! pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] . empty ( ) )
return ;
2024-08-26 17:25:39 +02:00
for ( auto const & topls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
2024-03-02 01:35:17 +01:00
if ( topls - > alpha . value ( ) ! = 0.f )
2023-09-28 21:48:33 +01:00
return ;
}
2024-08-26 17:25:39 +02:00
for ( auto const & w : g_pCompositor - > m_vWindows ) {
2024-04-27 12:43:12 +01:00
if ( w = = PCANDIDATE | | ( ! w - > m_bIsMapped & & ! w - > m_bFadingOut ) | | w - > isHidden ( ) )
2024-03-14 18:25:28 +00:00
continue ;
2024-04-02 20:32:39 +01:00
if ( w - > m_pWorkspace = = PCANDIDATE - > m_pWorkspace & & w - > m_bIsFloating & & w - > m_bCreatedOverFullscreen & & w - > visibleOnMonitor ( pMonitor ) )
2023-10-04 09:44:03 +01:00
return ;
}
2024-04-02 20:32:39 +01:00
if ( pMonitor - > activeSpecialWorkspace )
2023-10-04 09:44:03 +01:00
return ;
2023-09-28 21:48:33 +01:00
// check if it did not open any subsurfaces or shit
int surfaceCount = 0 ;
if ( PCANDIDATE - > m_bIsX11 ) {
surfaceCount = 1 ;
} else {
2024-05-10 23:28:33 +01:00
surfaceCount = PCANDIDATE - > popupsCount ( ) + PCANDIDATE - > surfacesCount ( ) ;
2023-09-28 21:48:33 +01:00
}
2023-10-02 14:02:15 +01:00
if ( surfaceCount > 1 )
return ;
2023-09-28 21:48:33 +01:00
// found one!
pMonitor - > solitaryClient = PCANDIDATE ;
}
2023-11-24 10:54:21 +00:00
2024-07-21 13:09:54 +02:00
SP < CRenderbuffer > CHyprRenderer : : getOrCreateRenderbuffer ( SP < Aquamarine : : IBuffer > buffer , uint32_t fmt ) {
auto it = std : : find_if ( m_vRenderbuffers . begin ( ) , m_vRenderbuffers . end ( ) , [ & ] ( const auto & other ) { return other - > m_pHLBuffer = = buffer ; } ) ;
2023-11-24 10:54:21 +00:00
if ( it ! = m_vRenderbuffers . end ( ) )
2024-07-21 13:09:54 +02:00
return * it ;
2023-11-24 10:54:21 +00:00
2024-07-21 13:09:54 +02:00
auto buf = makeShared < CRenderbuffer > ( buffer , fmt ) ;
2023-11-24 10:54:21 +00:00
2024-07-21 13:09:54 +02:00
if ( ! buf - > good ( ) )
return nullptr ;
2024-06-08 10:07:59 +02:00
2024-07-21 13:09:54 +02:00
m_vRenderbuffers . emplace_back ( buf ) ;
return buf ;
2024-06-08 10:07:59 +02:00
}
2023-11-30 01:18:55 +00:00
void CHyprRenderer : : makeEGLCurrent ( ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pCompositor | | ! g_pHyprOpenGL )
2023-12-06 14:46:18 +00:00
return ;
2024-07-21 13:09:54 +02:00
if ( eglGetCurrentContext ( ) ! = g_pHyprOpenGL - > m_pEglContext )
eglMakeCurrent ( g_pHyprOpenGL - > m_pEglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , g_pHyprOpenGL - > m_pEglContext ) ;
2023-11-30 01:18:55 +00:00
}
void CHyprRenderer : : unsetEGL ( ) {
2024-07-21 13:09:54 +02:00
if ( ! g_pHyprOpenGL )
return ;
eglMakeCurrent ( g_pHyprOpenGL - > m_pEglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) ;
2023-11-30 01:18:55 +00:00
}
2024-10-19 23:03:29 +01:00
bool CHyprRenderer : : beginRender ( PHLMONITOR pMonitor , CRegion & damage , eRenderMode mode , SP < IHLBuffer > buffer , CFramebuffer * fb , bool simple ) {
2023-11-30 01:18:55 +00:00
makeEGLCurrent ( ) ;
2023-11-24 10:54:21 +00:00
m_eRenderMode = mode ;
g_pHyprOpenGL - > m_RenderData . pMonitor = pMonitor ; // has to be set cuz allocs
if ( mode = = RENDER_MODE_FULL_FAKE ) {
2023-11-30 01:18:55 +00:00
RASSERT ( fb , " Cannot render FULL_FAKE without a provided fb! " ) ;
fb - > bind ( ) ;
2024-05-05 22:18:10 +01:00
if ( simple )
g_pHyprOpenGL - > beginSimple ( pMonitor , damage , nullptr , fb ) ;
else
g_pHyprOpenGL - > begin ( pMonitor , damage , fb ) ;
2023-11-24 10:54:21 +00:00
return true ;
}
2024-11-17 15:58:18 +00:00
/* This is a constant expression, as we always use double-buffering in our swapchain
2024-07-21 13:09:54 +02:00
TODO : Rewrite the CDamageRing to take advantage of that maybe ? It ' s made to support longer swapchains atm because we used to do wlroots */
static constexpr const int HL_BUFFER_AGE = 2 ;
2024-06-19 18:25:20 +02:00
2023-11-30 01:18:55 +00:00
if ( ! buffer ) {
2024-07-21 13:09:54 +02:00
m_pCurrentBuffer = pMonitor - > output - > swapchain - > next ( nullptr ) ;
if ( ! m_pCurrentBuffer ) {
2024-02-23 00:02:48 +00:00
Debug : : log ( ERR , " Failed to acquire swapchain buffer for {} " , pMonitor - > szName ) ;
2023-11-24 10:54:21 +00:00
return false ;
2024-02-22 23:50:56 +00:00
}
} else
2024-07-21 13:09:54 +02:00
m_pCurrentBuffer = buffer ;
2023-11-24 10:54:21 +00:00
try {
2024-07-21 13:09:54 +02:00
m_pCurrentRenderbuffer = getOrCreateRenderbuffer ( m_pCurrentBuffer , pMonitor - > output - > state - > state ( ) . drmFormat ) ;
2023-11-24 10:54:21 +00:00
} catch ( std : : exception & e ) {
2024-02-23 00:02:48 +00:00
Debug : : log ( ERR , " getOrCreateRenderbuffer failed for {} " , pMonitor - > szName ) ;
2024-07-21 13:09:54 +02:00
return false ;
}
if ( ! m_pCurrentRenderbuffer ) {
Debug : : log ( ERR , " failed to start a render pass for output {}, no RBO could be obtained " , pMonitor - > szName ) ;
2023-11-24 10:54:21 +00:00
return false ;
}
2024-06-19 18:25:20 +02:00
if ( mode = = RENDER_MODE_NORMAL ) {
2024-07-21 13:09:54 +02:00
damage = pMonitor - > damage . getBufferDamage ( HL_BUFFER_AGE ) ;
2024-06-19 18:25:20 +02:00
pMonitor - > damage . rotate ( ) ;
}
2024-02-19 18:17:32 +00:00
2023-11-24 10:54:21 +00:00
m_pCurrentRenderbuffer - > bind ( ) ;
2024-05-05 22:18:10 +01:00
if ( simple )
g_pHyprOpenGL - > beginSimple ( pMonitor , damage , m_pCurrentRenderbuffer ) ;
else
g_pHyprOpenGL - > begin ( pMonitor , damage ) ;
2023-11-24 10:54:21 +00:00
return true ;
}
void CHyprRenderer : : endRender ( ) {
2024-03-03 18:39:20 +00:00
const auto PMONITOR = g_pHyprOpenGL - > m_RenderData . pMonitor ;
static auto PNVIDIAANTIFLICKER = CConfigValue < Hyprlang : : INT > ( " opengl:nvidia_anti_flicker " ) ;
2024-07-21 13:09:54 +02:00
PMONITOR - > commitSeq + + ;
2023-11-24 10:54:21 +00:00
2024-08-06 14:52:19 +01:00
auto cleanup = CScopeGuard ( [ this ] ( ) {
if ( m_pCurrentRenderbuffer )
m_pCurrentRenderbuffer - > unbind ( ) ;
m_pCurrentRenderbuffer = nullptr ;
m_pCurrentBuffer = nullptr ;
} ) ;
2023-11-30 10:14:35 +00:00
if ( m_eRenderMode ! = RENDER_MODE_TO_BUFFER_READ_ONLY )
g_pHyprOpenGL - > end ( ) ;
else {
2024-10-19 23:03:29 +01:00
g_pHyprOpenGL - > m_RenderData . pMonitor . reset ( ) ;
2023-11-30 10:14:35 +00:00
g_pHyprOpenGL - > m_RenderData . mouseZoomFactor = 1.f ;
g_pHyprOpenGL - > m_RenderData . mouseZoomUseMouse = true ;
}
2023-11-24 10:54:21 +00:00
2023-11-30 10:14:35 +00:00
if ( m_eRenderMode = = RENDER_MODE_FULL_FAKE )
2023-11-24 10:54:21 +00:00
return ;
2023-11-30 01:18:55 +00:00
if ( m_eRenderMode = = RENDER_MODE_NORMAL ) {
2024-07-21 13:09:54 +02:00
PMONITOR - > output - > state - > setBuffer ( m_pCurrentBuffer ) ;
2024-08-06 14:52:19 +01:00
auto explicitOptions = getExplicitSyncSettings ( ) ;
if ( PMONITOR - > inTimeline & & explicitOptions . explicitEnabled & & explicitOptions . explicitKMSEnabled ) {
2024-07-21 13:09:54 +02:00
auto sync = g_pHyprOpenGL - > createEGLSync ( - 1 ) ;
if ( ! sync ) {
Debug : : log ( ERR , " renderer: couldn't create an EGLSync for out in endRender " ) ;
return ;
}
2024-08-06 14:52:19 +01:00
bool ok = PMONITOR - > inTimeline - > importFromSyncFileFD ( PMONITOR - > commitSeq , sync - > fd ( ) ) ;
if ( ! ok ) {
Debug : : log ( ERR , " renderer: couldn't import from sync file fd in endRender " ) ;
2024-07-21 13:09:54 +02:00
return ;
}
2023-11-24 10:54:21 +00:00
2024-08-06 14:52:19 +01:00
auto fd = PMONITOR - > inTimeline - > exportAsSyncFileFD ( PMONITOR - > commitSeq ) ;
if ( fd < = 0 ) {
Debug : : log ( ERR , " renderer: couldn't export from sync timeline in endRender " ) ;
2024-07-21 13:09:54 +02:00
return ;
}
2024-08-06 14:52:19 +01:00
PMONITOR - > output - > state - > setExplicitInFence ( fd ) ;
2024-07-21 13:09:54 +02:00
} else {
if ( isNvidia ( ) & & * PNVIDIAANTIFLICKER )
glFinish ( ) ;
else
glFlush ( ) ;
}
}
2023-11-24 10:54:21 +00:00
}
void CHyprRenderer : : onRenderbufferDestroy ( CRenderbuffer * rb ) {
std : : erase_if ( m_vRenderbuffers , [ & ] ( const auto & rbo ) { return rbo . get ( ) = = rb ; } ) ;
}
2024-07-21 13:09:54 +02:00
SP < CRenderbuffer > CHyprRenderer : : getCurrentRBO ( ) {
2023-11-24 10:54:21 +00:00
return m_pCurrentRenderbuffer ;
2023-11-25 17:45:08 +00:00
}
bool CHyprRenderer : : isNvidia ( ) {
return m_bNvidia ;
2023-12-18 16:06:06 +00:00
}
2024-08-06 14:52:19 +01:00
SExplicitSyncSettings CHyprRenderer : : getExplicitSyncSettings ( ) {
static auto PENABLEEXPLICIT = CConfigValue < Hyprlang : : INT > ( " render:explicit_sync " ) ;
static auto PENABLEEXPLICITKMS = CConfigValue < Hyprlang : : INT > ( " render:explicit_sync_kms " ) ;
SExplicitSyncSettings settings ;
settings . explicitEnabled = * PENABLEEXPLICIT ;
settings . explicitKMSEnabled = * PENABLEEXPLICITKMS ;
if ( * PENABLEEXPLICIT = = 2 /* auto */ )
settings . explicitEnabled = true ;
if ( * PENABLEEXPLICITKMS = = 2 /* auto */ ) {
if ( ! m_bNvidia )
settings . explicitKMSEnabled = true ;
else {
// check nvidia version. Explicit KMS is supported in >=560
// in the case of an error, driverMajor will stay 0 and explicit KMS will be disabled
2024-08-07 18:54:45 +02:00
static int driverMajor = 0 ;
2024-08-06 14:52:19 +01:00
static bool once = true ;
if ( once ) {
once = false ;
Debug : : log ( LOG , " Renderer: checking for explicit KMS support for nvidia " ) ;
if ( std : : filesystem : : exists ( " /sys/module/nvidia_drm/version " ) ) {
Debug : : log ( LOG , " Renderer: Nvidia version file exists " ) ;
std : : ifstream ifs ( " /sys/module/nvidia_drm/version " ) ;
if ( ifs . good ( ) ) {
try {
std : : string driverInfo ( ( std : : istreambuf_iterator < char > ( ifs ) ) , ( std : : istreambuf_iterator < char > ( ) ) ) ;
Debug : : log ( LOG , " Renderer: Read nvidia version {} " , driverInfo ) ;
CVarList ver ( driverInfo , 0 , ' . ' , true ) ;
driverMajor = std : : stoi ( ver [ 0 ] ) ;
Debug : : log ( LOG , " Renderer: Parsed nvidia major version: {} " , driverMajor ) ;
} catch ( std : : exception & e ) { settings . explicitKMSEnabled = false ; }
ifs . close ( ) ;
}
}
}
settings . explicitKMSEnabled = driverMajor > = 560 ;
}
}
return settings ;
}
2024-08-30 17:37:52 +02:00
void CHyprRenderer : : addWindowToRenderUnfocused ( PHLWINDOW window ) {
static auto PFPS = CConfigValue < Hyprlang : : INT > ( " misc:render_unfocused_fps " ) ;
if ( std : : find ( m_vRenderUnfocused . begin ( ) , m_vRenderUnfocused . end ( ) , window ) ! = m_vRenderUnfocused . end ( ) )
return ;
m_vRenderUnfocused . emplace_back ( window ) ;
if ( ! m_tRenderUnfocusedTimer - > armed ( ) )
m_tRenderUnfocusedTimer - > updateTimeout ( std : : chrono : : milliseconds ( 1000 / * PFPS ) ) ;
}