2024-05-22 10:09:36 +02:00
# include <random>
# include <pango/pangocairo.h>
2022-09-28 14:48:05 +02:00
# include "Shaders.hpp"
2022-04-04 19:44:25 +02:00
# include "OpenGL.hpp"
# include "../Compositor.hpp"
2022-04-17 18:47:10 +02:00
# include "../helpers/MiscFunctions.hpp"
2024-03-03 19:39:20 +01:00
# include "../config/ConfigValue.hpp"
2024-04-30 03:41:27 +02:00
# include "../desktop/LayerSurface.hpp"
2024-05-09 22:47:21 +02:00
# include "../protocols/LayerShell.hpp"
2024-06-08 10:07:59 +02:00
# include "../protocols/core/Compositor.hpp"
# include <xf86drm.h>
2024-07-21 13:09:54 +02:00
# include <fcntl.h>
# include <gbm.h>
# include <filesystem>
2022-04-04 19:44:25 +02:00
2023-11-24 11:54:21 +01:00
inline void loadGLProc ( void * pProc , const char * name ) {
void * proc = ( void * ) eglGetProcAddress ( name ) ;
if ( proc = = NULL ) {
Debug : : log ( CRIT , " [Tracy GPU Profiling] eglGetProcAddress({}) failed " , name ) ;
abort ( ) ;
}
* ( void * * ) pProc = proc ;
}
2024-07-21 13:09:54 +02:00
static enum LogLevel eglLogToLevel ( EGLint type ) {
switch ( type ) {
case EGL_DEBUG_MSG_CRITICAL_KHR : return CRIT ;
case EGL_DEBUG_MSG_ERROR_KHR : return ERR ;
case EGL_DEBUG_MSG_WARN_KHR : return WARN ;
case EGL_DEBUG_MSG_INFO_KHR : return LOG ;
default : return LOG ;
}
}
2022-04-04 19:44:25 +02:00
2024-07-21 13:09:54 +02:00
static const char * eglErrorToString ( EGLint error ) {
switch ( error ) {
case EGL_SUCCESS : return " EGL_SUCCESS " ;
case EGL_NOT_INITIALIZED : return " EGL_NOT_INITIALIZED " ;
case EGL_BAD_ACCESS : return " EGL_BAD_ACCESS " ;
case EGL_BAD_ALLOC : return " EGL_BAD_ALLOC " ;
case EGL_BAD_ATTRIBUTE : return " EGL_BAD_ATTRIBUTE " ;
case EGL_BAD_CONTEXT : return " EGL_BAD_CONTEXT " ;
case EGL_BAD_CONFIG : return " EGL_BAD_CONFIG " ;
case EGL_BAD_CURRENT_SURFACE : return " EGL_BAD_CURRENT_SURFACE " ;
case EGL_BAD_DISPLAY : return " EGL_BAD_DISPLAY " ;
case EGL_BAD_DEVICE_EXT : return " EGL_BAD_DEVICE_EXT " ;
case EGL_BAD_SURFACE : return " EGL_BAD_SURFACE " ;
case EGL_BAD_MATCH : return " EGL_BAD_MATCH " ;
case EGL_BAD_PARAMETER : return " EGL_BAD_PARAMETER " ;
case EGL_BAD_NATIVE_PIXMAP : return " EGL_BAD_NATIVE_PIXMAP " ;
case EGL_BAD_NATIVE_WINDOW : return " EGL_BAD_NATIVE_WINDOW " ;
case EGL_CONTEXT_LOST : return " EGL_CONTEXT_LOST " ;
}
return " Unknown " ;
}
2022-04-04 19:44:25 +02:00
2024-07-21 13:09:54 +02:00
static void eglLog ( EGLenum error , const char * command , EGLint type , EGLLabelKHR thread , EGLLabelKHR obj , const char * msg ) {
Debug : : log ( eglLogToLevel ( type ) , " [EGL] Command {} errored out with {} (0x{}): {} " , command , eglErrorToString ( error ) , error , msg ) ;
}
2022-04-04 19:44:25 +02:00
2024-07-21 13:09:54 +02:00
static int openRenderNode ( int drmFd ) {
auto renderName = drmGetRenderDeviceNameFromFd ( drmFd ) ;
if ( ! renderName ) {
// This can happen on split render/display platforms, fallback to
// primary node
renderName = drmGetPrimaryDeviceNameFromFd ( drmFd ) ;
if ( ! renderName ) {
Debug : : log ( ERR , " drmGetPrimaryDeviceNameFromFd failed " ) ;
return - 1 ;
}
Debug : : log ( LOG , " DRM dev {} has no render node, falling back to primary " , renderName ) ;
drmVersion * render_version = drmGetVersion ( drmFd ) ;
if ( render_version & & render_version - > name ) {
Debug : : log ( LOG , " DRM dev versionName " , render_version - > name ) ;
if ( strcmp ( render_version - > name , " evdi " ) = = 0 ) {
free ( renderName ) ;
renderName = ( char * ) malloc ( sizeof ( char ) * 15 ) ;
strcpy ( renderName , " /dev/dri/card0 " ) ;
}
drmFreeVersion ( render_version ) ;
}
}
2022-04-04 19:44:25 +02:00
2024-07-21 13:09:54 +02:00
Debug : : log ( LOG , " openRenderNode got drm device {} " , renderName ) ;
2022-04-04 19:44:25 +02:00
2024-07-21 13:09:54 +02:00
int renderFD = open ( renderName , O_RDWR | O_CLOEXEC ) ;
if ( renderFD < 0 )
Debug : : log ( ERR , " openRenderNode failed to open drm device {} " , renderName ) ;
free ( renderName ) ;
return renderFD ;
}
void CHyprOpenGLImpl : : initEGL ( bool gbm ) {
std : : vector < EGLint > attrs ;
if ( m_sExts . KHR_display_reference ) {
attrs . push_back ( EGL_TRACK_REFERENCES_KHR ) ;
attrs . push_back ( EGL_TRUE ) ;
}
attrs . push_back ( EGL_NONE ) ;
2024-07-24 17:48:38 +02:00
m_pEglDisplay = m_sProc . eglGetPlatformDisplayEXT ( gbm ? EGL_PLATFORM_GBM_KHR : EGL_PLATFORM_DEVICE_EXT , gbm ? m_pGbmDevice : m_pEglDevice , attrs . data ( ) ) ;
2024-07-21 13:09:54 +02:00
if ( m_pEglDisplay = = EGL_NO_DISPLAY )
RASSERT ( false , " EGL: failed to create a platform display " ) ;
attrs . clear ( ) ;
EGLint major , minor ;
if ( eglInitialize ( m_pEglDisplay , & major , & minor ) = = EGL_FALSE )
RASSERT ( false , " EGL: failed to initialize a platform display " ) ;
const std : : string EGLEXTENSIONS = ( const char * ) eglQueryString ( m_pEglDisplay , EGL_EXTENSIONS ) ;
m_sExts . IMG_context_priority = EGLEXTENSIONS . contains ( " IMG_context_priority " ) ;
m_sExts . EXT_create_context_robustness = EGLEXTENSIONS . contains ( " EXT_create_context_robustness " ) ;
m_sExts . EXT_image_dma_buf_import = EGLEXTENSIONS . contains ( " EXT_image_dma_buf_import " ) ;
m_sExts . EXT_image_dma_buf_import_modifiers = EGLEXTENSIONS . contains ( " EXT_image_dma_buf_import_modifiers " ) ;
if ( m_sExts . IMG_context_priority ) {
Debug : : log ( LOG , " EGL: IMG_context_priority supported, requesting high " ) ;
attrs . push_back ( EGL_CONTEXT_PRIORITY_LEVEL_IMG ) ;
attrs . push_back ( EGL_CONTEXT_PRIORITY_HIGH_IMG ) ;
}
if ( m_sExts . EXT_create_context_robustness ) {
Debug : : log ( LOG , " EGL: EXT_create_context_robustness supported, requesting lose on reset " ) ;
attrs . push_back ( EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT ) ;
attrs . push_back ( EGL_LOSE_CONTEXT_ON_RESET_EXT ) ;
}
2024-07-22 23:05:22 +02:00
# ifndef GLES2
2024-07-21 13:09:54 +02:00
attrs . push_back ( EGL_CONTEXT_MAJOR_VERSION ) ;
attrs . push_back ( 3 ) ;
attrs . push_back ( EGL_CONTEXT_MINOR_VERSION ) ;
attrs . push_back ( 2 ) ;
2024-07-22 23:05:22 +02:00
# else
attrs . push_back ( EGL_CONTEXT_CLIENT_VERSION ) ;
attrs . push_back ( 2 ) ;
# endif
2024-07-21 13:09:54 +02:00
attrs . push_back ( EGL_NONE ) ;
m_pEglContext = eglCreateContext ( m_pEglDisplay , EGL_NO_CONFIG_KHR , EGL_NO_CONTEXT , attrs . data ( ) ) ;
if ( m_pEglContext = = EGL_NO_CONTEXT )
RASSERT ( false , " EGL: failed to create a context " ) ;
if ( m_sExts . IMG_context_priority ) {
EGLint priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG ;
eglQueryContext ( m_pEglDisplay , m_pEglContext , EGL_CONTEXT_PRIORITY_LEVEL_IMG , & priority ) ;
if ( priority ! = EGL_CONTEXT_PRIORITY_HIGH_IMG )
Debug : : log ( ERR , " EGL: Failed to obtain a high priority context " ) ;
else
Debug : : log ( LOG , " EGL: Got a high priority context " ) ;
}
eglMakeCurrent ( m_pEglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , m_pEglContext ) ;
}
2024-07-24 17:48:38 +02:00
static bool drmDeviceHasName ( const drmDevice * device , const std : : string & name ) {
for ( size_t i = 0 ; i < DRM_NODE_MAX ; i + + ) {
if ( ! ( device - > available_nodes & ( 1 < < i ) ) )
continue ;
if ( device - > nodes [ i ] = = name )
return true ;
}
return false ;
}
EGLDeviceEXT CHyprOpenGLImpl : : eglDeviceFromDRMFD ( int drmFD ) {
EGLint nDevices = 0 ;
if ( ! m_sProc . eglQueryDevicesEXT ( 0 , nullptr , & nDevices ) ) {
Debug : : log ( ERR , " eglDeviceFromDRMFD: eglQueryDevicesEXT failed " ) ;
return EGL_NO_DEVICE_EXT ;
}
if ( nDevices < = 0 ) {
Debug : : log ( ERR , " eglDeviceFromDRMFD: no devices " ) ;
return EGL_NO_DEVICE_EXT ;
}
std : : vector < EGLDeviceEXT > devices ;
devices . resize ( nDevices ) ;
if ( ! m_sProc . eglQueryDevicesEXT ( nDevices , devices . data ( ) , & nDevices ) ) {
Debug : : log ( ERR , " eglDeviceFromDRMFD: eglQueryDevicesEXT failed (2) " ) ;
return EGL_NO_DEVICE_EXT ;
}
drmDevice * drmDev = nullptr ;
if ( int ret = drmGetDevice ( drmFD , & drmDev ) ; ret < 0 ) {
Debug : : log ( ERR , " eglDeviceFromDRMFD: drmGetDevice failed " ) ;
return EGL_NO_DEVICE_EXT ;
}
for ( auto & d : devices ) {
auto devName = m_sProc . eglQueryDeviceStringEXT ( d , EGL_DRM_DEVICE_FILE_EXT ) ;
if ( ! devName )
continue ;
if ( drmDeviceHasName ( drmDev , devName ) ) {
Debug : : log ( LOG , " eglDeviceFromDRMFD: Using device {} " , devName ) ;
drmFreeDevice ( & drmDev ) ;
return d ;
}
}
drmFreeDevice ( & drmDev ) ;
Debug : : log ( LOG , " eglDeviceFromDRMFD: No drm devices found " ) ;
return EGL_NO_DEVICE_EXT ;
}
2024-07-21 13:09:54 +02:00
CHyprOpenGLImpl : : CHyprOpenGLImpl ( ) {
const std : : string EGLEXTENSIONS = ( const char * ) eglQueryString ( EGL_NO_DISPLAY , EGL_EXTENSIONS ) ;
Debug : : log ( LOG , " Supported EGL extensions: ({}) {} " , std : : count ( EGLEXTENSIONS . begin ( ) , EGLEXTENSIONS . end ( ) , ' ' ) , EGLEXTENSIONS ) ;
m_iDRMFD = g_pCompositor - > m_iDRMFD ;
m_sExts . KHR_display_reference = EGLEXTENSIONS . contains ( " KHR_display_reference " ) ;
2022-04-04 19:44:25 +02:00
2023-11-24 11:54:21 +01:00
loadGLProc ( & m_sProc . glEGLImageTargetRenderbufferStorageOES , " glEGLImageTargetRenderbufferStorageOES " ) ;
2024-06-08 10:07:59 +02:00
loadGLProc ( & m_sProc . eglCreateImageKHR , " eglCreateImageKHR " ) ;
2023-11-24 11:54:21 +01:00
loadGLProc ( & m_sProc . eglDestroyImageKHR , " eglDestroyImageKHR " ) ;
2024-06-08 10:07:59 +02:00
loadGLProc ( & m_sProc . eglQueryDmaBufFormatsEXT , " eglQueryDmaBufFormatsEXT " ) ;
loadGLProc ( & m_sProc . eglQueryDmaBufModifiersEXT , " eglQueryDmaBufModifiersEXT " ) ;
loadGLProc ( & m_sProc . glEGLImageTargetTexture2DOES , " glEGLImageTargetTexture2DOES " ) ;
2024-07-21 13:09:54 +02:00
loadGLProc ( & m_sProc . eglDebugMessageControlKHR , " eglDebugMessageControlKHR " ) ;
loadGLProc ( & m_sProc . eglGetPlatformDisplayEXT , " eglGetPlatformDisplayEXT " ) ;
loadGLProc ( & m_sProc . eglCreateSyncKHR , " eglCreateSyncKHR " ) ;
loadGLProc ( & m_sProc . eglDestroySyncKHR , " eglDestroySyncKHR " ) ;
loadGLProc ( & m_sProc . eglDupNativeFenceFDANDROID , " eglDupNativeFenceFDANDROID " ) ;
loadGLProc ( & m_sProc . eglWaitSyncKHR , " eglWaitSyncKHR " ) ;
2023-11-24 11:54:21 +01:00
2024-07-21 13:09:54 +02:00
RASSERT ( m_sProc . eglCreateSyncKHR , " Display driver doesn't support eglCreateSyncKHR " ) ;
RASSERT ( m_sProc . eglDupNativeFenceFDANDROID , " Display driver doesn't support eglDupNativeFenceFDANDROID " ) ;
RASSERT ( m_sProc . eglWaitSyncKHR , " Display driver doesn't support eglWaitSyncKHR " ) ;
if ( EGLEXTENSIONS . contains ( " EGL_EXT_device_base " ) | | EGLEXTENSIONS . contains ( " EGL_EXT_device_enumeration " ) )
loadGLProc ( & m_sProc . eglQueryDevicesEXT , " eglQueryDevicesEXT " ) ;
if ( EGLEXTENSIONS . contains ( " EGL_EXT_device_base " ) | | EGLEXTENSIONS . contains ( " EGL_EXT_device_query " ) ) {
loadGLProc ( & m_sProc . eglQueryDeviceStringEXT , " eglQueryDeviceStringEXT " ) ;
loadGLProc ( & m_sProc . eglQueryDisplayAttribEXT , " eglQueryDisplayAttribEXT " ) ;
}
if ( EGLEXTENSIONS . contains ( " EGL_KHR_debug " ) ) {
loadGLProc ( & m_sProc . eglDebugMessageControlKHR , " eglDebugMessageControlKHR " ) ;
static const EGLAttrib debugAttrs [ ] = {
EGL_DEBUG_MSG_CRITICAL_KHR , EGL_TRUE , EGL_DEBUG_MSG_ERROR_KHR , EGL_TRUE , EGL_DEBUG_MSG_WARN_KHR , EGL_TRUE , EGL_DEBUG_MSG_INFO_KHR , EGL_TRUE , EGL_NONE ,
} ;
m_sProc . eglDebugMessageControlKHR ( : : eglLog , debugAttrs ) ;
}
RASSERT ( eglBindAPI ( EGL_OPENGL_ES_API ) ! = EGL_FALSE , " Couldn't bind to EGL's opengl ES API. This means your gpu driver f'd up. This is not a hyprland issue. " ) ;
2024-07-24 17:48:38 +02:00
bool success = false ;
if ( EGLEXTENSIONS . contains ( " EXT_platform_device " ) | | ! m_sProc . eglQueryDevicesEXT | | ! m_sProc . eglQueryDeviceStringEXT ) {
m_pEglDevice = eglDeviceFromDRMFD ( m_iDRMFD ) ;
2024-07-21 13:09:54 +02:00
2024-07-24 17:48:38 +02:00
if ( m_pEglDevice ! = EGL_NO_DEVICE_EXT ) {
success = true ;
initEGL ( false ) ;
}
}
if ( ! success ) {
Debug : : log ( WARN , " EGL: EXT_platform_device or EGL_EXT_device_query not supported, using gbm " ) ;
if ( EGLEXTENSIONS . contains ( " KHR_platform_gbm " ) ) {
success = true ;
m_iGBMFD = openRenderNode ( m_iDRMFD ) ;
if ( m_iGBMFD < 0 )
RASSERT ( false , " Couldn't open a gbm fd " ) ;
2024-07-21 13:09:54 +02:00
2024-07-24 17:48:38 +02:00
m_pGbmDevice = gbm_create_device ( m_iGBMFD ) ;
if ( ! m_pGbmDevice )
RASSERT ( false , " Couldn't open a gbm device " ) ;
initEGL ( true ) ;
}
}
2024-07-21 13:09:54 +02:00
2024-07-24 17:48:38 +02:00
RASSERT ( success , " EGL does not support KHR_platform_gbm or EXT_platform_device, this is an issue with your gpu driver. " ) ;
2024-07-21 13:09:54 +02:00
auto * const EXTENSIONS = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
RASSERT ( EXTENSIONS , " Couldn't retrieve openGL extensions! " ) ;
m_szExtensions = EXTENSIONS ;
Debug : : log ( LOG , " Creating the Hypr OpenGL Renderer! " ) ;
Debug : : log ( LOG , " Using: {} " , ( char * ) glGetString ( GL_VERSION ) ) ;
Debug : : log ( LOG , " Vendor: {} " , ( char * ) glGetString ( GL_VENDOR ) ) ;
Debug : : log ( LOG , " Renderer: {} " , ( char * ) glGetString ( GL_RENDERER ) ) ;
Debug : : log ( LOG , " Supported extensions: ({}) {} " , std : : count ( m_szExtensions . begin ( ) , m_szExtensions . end ( ) , ' ' ) , m_szExtensions ) ;
m_sExts . EXT_read_format_bgra = m_szExtensions . contains ( " GL_EXT_read_format_bgra " ) ;
2024-06-08 10:07:59 +02:00
RASSERT ( m_szExtensions . contains ( " GL_EXT_texture_format_BGRA8888 " ) , " GL_EXT_texture_format_BGRA8888 support by the GPU driver is required " ) ;
if ( ! m_sExts . EXT_read_format_bgra )
Debug : : log ( WARN , " Your GPU does not support GL_EXT_read_format_bgra, this may cause issues with texture importing " ) ;
if ( ! m_sExts . EXT_image_dma_buf_import | | ! m_sExts . EXT_image_dma_buf_import_modifiers )
Debug : : log ( WARN , " Your GPU does not support DMABUFs, this will possibly cause issues and will take a hit on the performance. " ) ;
2023-12-02 15:51:35 +01:00
2023-07-20 17:47:49 +02:00
# ifdef USE_TRACY_GPU
loadGLProc ( & glQueryCounter , " glQueryCounterEXT " ) ;
loadGLProc ( & glGetQueryObjectiv , " glGetQueryObjectivEXT " ) ;
loadGLProc ( & glGetQueryObjectui64v , " glGetQueryObjectui64vEXT " ) ;
# endif
TRACY_GPU_CONTEXT ;
2022-12-16 18:17:31 +01:00
# ifdef GLES2
2022-04-13 17:34:13 +02:00
Debug : : log ( WARN , " !RENDERER: Using the legacy GLES2 renderer! " ) ;
2022-12-16 18:17:31 +01:00
# endif
2022-04-13 17:34:13 +02:00
2024-06-08 10:07:59 +02:00
initDRMFormats ( ) ;
2024-04-20 21:16:42 +02:00
static auto P = g_pHookSystem - > hookDynamic ( " preRender " , [ & ] ( void * self , SCallbackInfo & info , std : : any data ) { preRender ( std : : any_cast < CMonitor * > ( data ) ) ; } ) ;
2023-02-19 21:54:53 +01:00
2024-07-21 13:09:54 +02:00
RASSERT ( eglMakeCurrent ( m_pEglDisplay , EGL_NO_SURFACE , EGL_NO_SURFACE , EGL_NO_CONTEXT ) , " Couldn't unset current EGL! " ) ;
2023-03-05 15:05:30 +01:00
m_tGlobalTimer . reset ( ) ;
2022-04-04 19:44:25 +02:00
}
2024-06-14 21:59:21 +02:00
std : : optional < std : : vector < uint64_t > > CHyprOpenGLImpl : : getModsForFormat ( EGLint format ) {
2024-06-08 10:07:59 +02:00
// TODO: return std::expected when clang supports it
if ( ! m_sExts . EXT_image_dma_buf_import_modifiers )
2024-06-14 21:59:21 +02:00
return std : : nullopt ;
2024-06-08 10:07:59 +02:00
EGLint len = 0 ;
2024-07-21 13:09:54 +02:00
if ( ! m_sProc . eglQueryDmaBufModifiersEXT ( m_pEglDisplay , format , 0 , nullptr , nullptr , & len ) ) {
2024-06-08 10:07:59 +02:00
Debug : : log ( ERR , " EGL: Failed to query mods " ) ;
2024-06-14 21:59:21 +02:00
return std : : nullopt ;
2024-06-08 10:07:59 +02:00
}
if ( len < = 0 )
2024-06-14 21:59:21 +02:00
return std : : vector < uint64_t > { } ;
2024-06-08 10:07:59 +02:00
std : : vector < uint64_t > mods ;
std : : vector < EGLBoolean > external ;
mods . resize ( len ) ;
external . resize ( len ) ;
2024-07-21 13:09:54 +02:00
m_sProc . eglQueryDmaBufModifiersEXT ( m_pEglDisplay , format , len , mods . data ( ) , external . data ( ) , & len ) ;
2024-06-08 10:07:59 +02:00
std : : vector < uint64_t > result ;
2024-06-14 21:59:21 +02:00
bool linearIsExternal = false ;
2024-06-08 10:07:59 +02:00
for ( size_t i = 0 ; i < mods . size ( ) ; + + i ) {
2024-06-14 21:59:21 +02:00
if ( external . at ( i ) ) {
if ( mods . at ( i ) = = DRM_FORMAT_MOD_LINEAR )
linearIsExternal = true ;
2024-06-08 10:07:59 +02:00
continue ;
2024-06-14 21:59:21 +02:00
}
2024-06-08 10:07:59 +02:00
result . push_back ( mods . at ( i ) ) ;
}
2024-06-14 21:59:21 +02:00
// if the driver doesn't mark linear as external, add it. It's allowed unless the driver says otherwise. (e.g. nvidia)
if ( ! linearIsExternal & & std : : find ( mods . begin ( ) , mods . end ( ) , DRM_FORMAT_MOD_LINEAR ) = = mods . end ( ) & & mods . size ( ) = = 0 )
mods . push_back ( DRM_FORMAT_MOD_LINEAR ) ;
2024-06-08 10:07:59 +02:00
return result ;
}
void CHyprOpenGLImpl : : initDRMFormats ( ) {
const auto DISABLE_MODS = envEnabled ( " HYPRLAND_EGL_NO_MODIFIERS " ) ;
if ( DISABLE_MODS )
Debug : : log ( WARN , " HYPRLAND_EGL_NO_MODIFIERS set, disabling modifiers " ) ;
if ( ! m_sExts . EXT_image_dma_buf_import ) {
Debug : : log ( ERR , " EGL: No dmabuf import, DMABufs will not work. " ) ;
return ;
}
std : : vector < EGLint > formats ;
if ( ! m_sExts . EXT_image_dma_buf_import_modifiers | | ! m_sProc . eglQueryDmaBufFormatsEXT ) {
formats . push_back ( DRM_FORMAT_ARGB8888 ) ;
formats . push_back ( DRM_FORMAT_XRGB8888 ) ;
Debug : : log ( WARN , " EGL: No mod support " ) ;
} else {
EGLint len = 0 ;
2024-07-21 13:09:54 +02:00
m_sProc . eglQueryDmaBufFormatsEXT ( m_pEglDisplay , 0 , nullptr , & len ) ;
2024-06-08 10:07:59 +02:00
formats . resize ( len ) ;
2024-07-21 13:09:54 +02:00
m_sProc . eglQueryDmaBufFormatsEXT ( m_pEglDisplay , len , formats . data ( ) , & len ) ;
2024-06-08 10:07:59 +02:00
}
if ( formats . size ( ) = = 0 ) {
Debug : : log ( ERR , " EGL: Failed to get formats, DMABufs will not work. " ) ;
return ;
}
2024-07-21 13:09:54 +02:00
Debug : : log ( LOG , " Supported DMA-BUF formats: " ) ;
2024-06-08 10:07:59 +02:00
std : : vector < SDRMFormat > dmaFormats ;
for ( auto & fmt : formats ) {
std : : vector < uint64_t > mods ;
2024-06-14 21:59:21 +02:00
if ( ! DISABLE_MODS ) {
auto ret = getModsForFormat ( fmt ) ;
if ( ! ret . has_value ( ) )
continue ;
mods = * ret ;
} else
2024-06-08 10:07:59 +02:00
mods = { DRM_FORMAT_MOD_LINEAR } ;
m_bHasModifiers = m_bHasModifiers | | mods . size ( ) > 0 ;
2024-06-14 21:59:21 +02:00
// EGL can always do implicit modifiers.
mods . push_back ( DRM_FORMAT_MOD_INVALID ) ;
2024-06-08 10:07:59 +02:00
dmaFormats . push_back ( SDRMFormat {
2024-07-21 13:09:54 +02:00
. drmFormat = fmt ,
. modifiers = mods ,
2024-06-08 10:07:59 +02:00
} ) ;
std : : vector < std : : pair < uint64_t , std : : string > > modifierData ;
auto fmtName = drmGetFormatName ( fmt ) ;
Debug : : log ( LOG , " EGL: GPU Supports Format {} (0x{:x}) " , fmtName ? fmtName : " ?unknown? " , fmt ) ;
for ( auto & mod : mods ) {
auto modName = drmGetFormatModifierName ( mod ) ;
modifierData . emplace_back ( std : : make_pair < > ( mod , modName ? modName : " ?unknown? " ) ) ;
free ( modName ) ;
}
free ( fmtName ) ;
mods . clear ( ) ;
std : : sort ( modifierData . begin ( ) , modifierData . end ( ) , [ ] ( const auto & a , const auto & b ) {
if ( a . first = = 0 )
return false ;
if ( a . second . contains ( " DCC " ) )
return false ;
return true ;
} ) ;
for ( auto & [ m , name ] : modifierData ) {
Debug : : log ( LOG , " EGL: | with modifier {} (0x{:x}) " , name , m ) ;
mods . emplace_back ( m ) ;
}
}
Debug : : log ( LOG , " EGL: {} formats found in total. Some modifiers may be omitted as they are external-only. " , dmaFormats . size ( ) ) ;
2024-06-09 21:10:46 +02:00
if ( dmaFormats . size ( ) = = 0 )
Debug : : log ( WARN ,
" EGL: WARNING: No dmabuf formats were found, dmabuf will be disabled. This will degrade performance, but is most likely a driver issue or a very old GPU. " ) ;
2024-06-08 10:07:59 +02:00
drmFormats = dmaFormats ;
}
2024-07-21 13:09:54 +02:00
EGLImageKHR CHyprOpenGLImpl : : createEGLImage ( const Aquamarine : : SDMABUFAttrs & attrs ) {
2024-06-08 10:07:59 +02:00
std : : vector < uint32_t > attribs ;
attribs . push_back ( EGL_WIDTH ) ;
attribs . push_back ( attrs . size . x ) ;
attribs . push_back ( EGL_HEIGHT ) ;
attribs . push_back ( attrs . size . y ) ;
attribs . push_back ( EGL_LINUX_DRM_FOURCC_EXT ) ;
attribs . push_back ( attrs . format ) ;
struct {
EGLint fd ;
EGLint offset ;
EGLint pitch ;
EGLint modlo ;
EGLint modhi ;
} attrNames [ 4 ] = {
{ EGL_DMA_BUF_PLANE0_FD_EXT , EGL_DMA_BUF_PLANE0_OFFSET_EXT , EGL_DMA_BUF_PLANE0_PITCH_EXT , EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT , EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT } ,
{ EGL_DMA_BUF_PLANE1_FD_EXT , EGL_DMA_BUF_PLANE1_OFFSET_EXT , EGL_DMA_BUF_PLANE1_PITCH_EXT , EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT , EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT } ,
{ EGL_DMA_BUF_PLANE2_FD_EXT , EGL_DMA_BUF_PLANE2_OFFSET_EXT , EGL_DMA_BUF_PLANE2_PITCH_EXT , EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT , EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT } ,
{ EGL_DMA_BUF_PLANE3_FD_EXT , EGL_DMA_BUF_PLANE3_OFFSET_EXT , EGL_DMA_BUF_PLANE3_PITCH_EXT , EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT , EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT } } ;
for ( int i = 0 ; i < attrs . planes ; i + + ) {
attribs . push_back ( attrNames [ i ] . fd ) ;
attribs . push_back ( attrs . fds [ i ] ) ;
attribs . push_back ( attrNames [ i ] . offset ) ;
attribs . push_back ( attrs . offsets [ i ] ) ;
attribs . push_back ( attrNames [ i ] . pitch ) ;
attribs . push_back ( attrs . strides [ i ] ) ;
if ( m_bHasModifiers & & attrs . modifier ! = DRM_FORMAT_MOD_INVALID ) {
attribs . push_back ( attrNames [ i ] . modlo ) ;
attribs . push_back ( attrs . modifier & 0xFFFFFFFF ) ;
attribs . push_back ( attrNames [ i ] . modhi ) ;
attribs . push_back ( attrs . modifier > > 32 ) ;
}
}
attribs . push_back ( EGL_IMAGE_PRESERVED_KHR ) ;
attribs . push_back ( EGL_TRUE ) ;
attribs . push_back ( EGL_NONE ) ;
2024-07-21 13:09:54 +02:00
EGLImageKHR image = m_sProc . eglCreateImageKHR ( m_pEglDisplay , EGL_NO_CONTEXT , EGL_LINUX_DMA_BUF_EXT , nullptr , ( int * ) attribs . data ( ) ) ;
2024-06-08 10:07:59 +02:00
if ( image = = EGL_NO_IMAGE_KHR ) {
Debug : : log ( ERR , " EGL: EGLCreateImageKHR failed: {} " , eglGetError ( ) ) ;
return EGL_NO_IMAGE_KHR ;
}
return image ;
}
2024-03-21 15:46:23 +01:00
void CHyprOpenGLImpl : : logShaderError ( const GLuint & shader , bool program ) {
GLint maxLength = 0 ;
if ( program )
glGetProgramiv ( shader , GL_INFO_LOG_LENGTH , & maxLength ) ;
else
glGetShaderiv ( shader , GL_INFO_LOG_LENGTH , & maxLength ) ;
std : : vector < GLchar > errorLog ( maxLength ) ;
if ( program )
glGetProgramInfoLog ( shader , maxLength , & maxLength , errorLog . data ( ) ) ;
else
glGetShaderInfoLog ( shader , maxLength , & maxLength , errorLog . data ( ) ) ;
std : : string errorStr ( errorLog . begin ( ) , errorLog . end ( ) ) ;
g_pConfigManager - > addParseError ( ( program ? " Screen shader parser: Error linking program: " : " Screen shader parser: Error compiling shader: " ) + errorStr ) ;
}
2022-12-01 14:36:07 +01:00
GLuint CHyprOpenGLImpl : : createProgram ( const std : : string & vert , const std : : string & frag , bool dynamic ) {
2022-12-01 14:40:05 +01:00
auto vertCompiled = compileShader ( GL_VERTEX_SHADER , vert , dynamic ) ;
2022-12-01 14:36:07 +01:00
if ( dynamic ) {
if ( vertCompiled = = 0 )
return 0 ;
} else {
2023-09-06 12:51:36 +02:00
RASSERT ( vertCompiled , " Compiling shader failed. VERTEX NULL! Shader source: \n \n {} " , vert . c_str ( ) ) ;
2022-12-01 14:36:07 +01:00
}
2022-04-04 19:44:25 +02:00
2022-12-01 14:40:05 +01:00
auto fragCompiled = compileShader ( GL_FRAGMENT_SHADER , frag , dynamic ) ;
2022-12-01 14:36:07 +01:00
if ( dynamic ) {
if ( fragCompiled = = 0 )
return 0 ;
} else {
2023-09-06 12:51:36 +02:00
RASSERT ( fragCompiled , " Compiling shader failed. FRAGMENT NULL! Shader source: \n \n {} " , frag . c_str ( ) ) ;
2022-12-01 14:36:07 +01:00
}
2022-04-04 19:44:25 +02:00
auto prog = glCreateProgram ( ) ;
glAttachShader ( prog , vertCompiled ) ;
glAttachShader ( prog , fragCompiled ) ;
glLinkProgram ( prog ) ;
glDetachShader ( prog , vertCompiled ) ;
glDetachShader ( prog , fragCompiled ) ;
glDeleteShader ( vertCompiled ) ;
glDeleteShader ( fragCompiled ) ;
GLint ok ;
glGetProgramiv ( prog , GL_LINK_STATUS , & ok ) ;
2022-12-01 14:36:07 +01:00
if ( dynamic ) {
2024-03-21 15:46:23 +01:00
if ( ok = = GL_FALSE ) {
logShaderError ( prog , true ) ;
2022-12-01 14:36:07 +01:00
return 0 ;
2024-03-21 15:46:23 +01:00
}
2022-12-01 14:36:07 +01:00
} else {
RASSERT ( ok ! = GL_FALSE , " createProgram() failed! GL_LINK_STATUS not OK! " ) ;
}
2022-04-04 19:44:25 +02:00
return prog ;
}
2022-12-01 14:36:07 +01:00
GLuint CHyprOpenGLImpl : : compileShader ( const GLuint & type , std : : string src , bool dynamic ) {
2022-04-04 19:44:25 +02:00
auto shader = glCreateShader ( type ) ;
auto shaderSource = src . c_str ( ) ;
glShaderSource ( shader , 1 , ( const GLchar * * ) & shaderSource , nullptr ) ;
glCompileShader ( shader ) ;
GLint ok ;
glGetShaderiv ( shader , GL_COMPILE_STATUS , & ok ) ;
2024-03-21 15:46:23 +01:00
2022-12-01 14:36:07 +01:00
if ( dynamic ) {
2024-03-21 15:46:23 +01:00
if ( ok = = GL_FALSE ) {
logShaderError ( shader , false ) ;
2022-12-01 14:36:07 +01:00
return 0 ;
2024-03-21 15:46:23 +01:00
}
2022-12-01 14:36:07 +01:00
} else {
RASSERT ( ok ! = GL_FALSE , " compileShader() failed! GL_COMPILE_STATUS not OK! " ) ;
}
2022-04-04 19:44:25 +02:00
return shader ;
}
2023-11-24 13:37:10 +01:00
bool CHyprOpenGLImpl : : passRequiresIntrospection ( CMonitor * pMonitor ) {
2024-07-21 13:09:54 +02:00
// passes requiring introspection are the ones that need to render blur,
// or when we are rendering to a multigpu target
2022-04-04 19:44:25 +02:00
2024-03-03 19:39:20 +01:00
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
static auto PXRAY = CConfigValue < Hyprlang : : INT > ( " decoration:blur:xray " ) ;
static auto POPTIM = CConfigValue < Hyprlang : : INT > ( " decoration:blur:new_optimizations " ) ;
static auto PBLURSPECIAL = CConfigValue < Hyprlang : : INT > ( " decoration:blur:special " ) ;
2024-03-25 17:08:55 +01:00
static auto PBLURPOPUPS = CConfigValue < Hyprlang : : INT > ( " decoration:blur:popups " ) ;
2023-11-24 13:37:10 +01:00
2024-02-18 16:00:34 +01:00
if ( m_RenderData . mouseZoomFactor ! = 1.0 | | g_pHyprRenderer - > m_bCrashingInProgress )
2023-11-30 02:18:55 +01:00
return true ;
2024-04-24 17:29:41 +02:00
// mirrors should not be offloaded (as we then would basically copy the same data twice)
// yes, this breaks mirrors of mirrors
if ( pMonitor - > isMirror ( ) )
return false ;
// monitors that are mirrored however must be offloaded because we cannot copy from output FBs
2023-11-30 02:18:55 +01:00
if ( ! pMonitor - > mirrors . empty ( ) )
return true ;
2024-03-03 19:39:20 +01:00
if ( * PBLUR = = 0 )
2023-11-24 13:37:10 +01:00
return false ;
if ( m_RenderData . pCurrentMonData - > blurFBShouldRender )
return true ;
2024-04-27 13:43:12 +02:00
if ( ! pMonitor - > solitaryClient . expired ( ) )
2023-11-24 13:37:10 +01:00
return false ;
2023-11-25 15:52:47 +01:00
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY ] ) {
2024-03-03 19:39:20 +01:00
const auto XRAYMODE = ls - > xray = = - 1 ? * PXRAY : ls - > xray ;
2023-11-25 15:52:47 +01:00
if ( ls - > forceBlur & & ! XRAYMODE )
return true ;
2024-03-25 17:08:55 +01:00
if ( ls - > popupsCount ( ) > 0 & & ls - > forceBlurPopups )
return true ;
2023-11-25 15:52:47 +01:00
}
2023-11-24 13:37:10 +01:00
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_TOP ] ) {
2024-03-03 19:39:20 +01:00
const auto XRAYMODE = ls - > xray = = - 1 ? * PXRAY : ls - > xray ;
2023-11-25 15:52:47 +01:00
if ( ls - > forceBlur & & ! XRAYMODE )
2023-11-24 13:37:10 +01:00
return true ;
2024-03-25 17:08:55 +01:00
if ( ls - > popupsCount ( ) > 0 & & ls - > forceBlurPopups )
return true ;
2023-11-24 13:37:10 +01:00
}
2024-02-23 22:09:41 +01:00
// these two block optimization
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ] ) {
if ( ls - > forceBlur )
return true ;
2024-03-25 17:08:55 +01:00
if ( ls - > popupsCount ( ) > 0 & & ls - > forceBlurPopups )
return true ;
2024-02-23 22:09:41 +01:00
}
for ( auto & ls : pMonitor - > m_aLayerSurfaceLayers [ ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ] ) {
if ( ls - > forceBlur )
return true ;
2024-03-25 17:08:55 +01:00
if ( ls - > popupsCount ( ) > 0 & & ls - > forceBlurPopups )
return true ;
2024-02-23 22:09:41 +01:00
}
2023-11-25 20:40:15 +01:00
if ( * PBLURSPECIAL ) {
for ( auto & ws : g_pCompositor - > m_vWorkspaces ) {
if ( ! ws - > m_bIsSpecialWorkspace | | ws - > m_iMonitorID ! = pMonitor - > ID )
continue ;
2024-03-02 01:35:17 +01:00
if ( ws - > m_fAlpha . value ( ) = = 0 )
2023-11-25 20:40:15 +01:00
continue ;
return true ;
}
}
2024-03-03 19:39:20 +01:00
if ( * PXRAY )
2023-11-24 13:37:10 +01:00
return false ;
for ( auto & w : g_pCompositor - > m_vWindows ) {
2024-03-25 17:08:55 +01:00
if ( ! w - > m_bIsMapped | | w - > isHidden ( ) )
2023-11-24 13:37:10 +01:00
continue ;
2024-04-27 13:43:12 +02:00
if ( ! g_pHyprRenderer - > shouldRenderWindow ( w ) )
2023-11-24 13:37:10 +01:00
continue ;
2024-03-25 17:08:55 +01:00
if ( w - > popupsCount ( ) > 0 & & * PBLURPOPUPS )
return true ;
2024-04-02 21:32:39 +02:00
if ( ! w - > m_bIsFloating & & * POPTIM & & ! w - > onSpecialWorkspace ( ) )
2024-03-25 17:08:55 +01:00
continue ;
2024-07-13 20:29:07 +02:00
if ( w - > m_sWindowData . noBlur . valueOrDefault ( ) | | w - > m_sWindowData . xray . valueOrDefault ( ) )
2023-11-24 13:37:10 +01:00
continue ;
if ( w - > opaque ( ) )
continue ;
return true ;
}
return false ;
}
2024-07-21 13:09:54 +02:00
void CHyprOpenGLImpl : : beginSimple ( CMonitor * pMonitor , const CRegion & damage , SP < CRenderbuffer > rb , CFramebuffer * fb ) {
2024-05-05 23:18:10 +02:00
m_RenderData . pMonitor = pMonitor ;
# ifndef GLES2
const GLenum RESETSTATUS = glGetGraphicsResetStatus ( ) ;
if ( RESETSTATUS ! = GL_NO_ERROR ) {
std : : string errStr = " " ;
switch ( RESETSTATUS ) {
case GL_GUILTY_CONTEXT_RESET : errStr = " GL_GUILTY_CONTEXT_RESET " ; break ;
case GL_INNOCENT_CONTEXT_RESET : errStr = " GL_INNOCENT_CONTEXT_RESET " ; break ;
case GL_UNKNOWN_CONTEXT_RESET : errStr = " GL_UNKNOWN_CONTEXT_RESET " ; break ;
default : errStr = " UNKNOWN?? " ; break ;
}
RASSERT ( false , " Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented. " , errStr ) ;
return ;
}
# endif
TRACY_GPU_ZONE ( " RenderBeginSimple " ) ;
const auto FBO = rb ? rb - > getFB ( ) : fb ;
glViewport ( 0 , 0 , pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y ) ;
matrixProjection ( m_RenderData . projection , pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y , WL_OUTPUT_TRANSFORM_NORMAL ) ;
2024-07-21 13:09:54 +02:00
matrixIdentity ( m_RenderData . monitorProjection . data ( ) ) ;
2024-05-05 23:18:10 +02:00
if ( pMonitor - > transform ! = WL_OUTPUT_TRANSFORM_NORMAL ) {
const Vector2D tfmd = pMonitor - > transform % 2 = = 1 ? Vector2D { FBO - > m_vSize . y , FBO - > m_vSize . x } : FBO - > m_vSize ;
2024-07-21 13:09:54 +02:00
matrixTranslate ( m_RenderData . monitorProjection . data ( ) , FBO - > m_vSize . x / 2.0 , FBO - > m_vSize . y / 2.0 ) ;
matrixTransform ( m_RenderData . monitorProjection . data ( ) , wlTransformToHyprutils ( pMonitor - > transform ) ) ;
matrixTranslate ( m_RenderData . monitorProjection . data ( ) , - tfmd . x / 2.0 , - tfmd . y / 2.0 ) ;
2024-05-05 23:18:10 +02:00
}
m_RenderData . pCurrentMonData = & m_mMonitorRenderResources [ pMonitor ] ;
if ( ! m_RenderData . pCurrentMonData - > m_bShadersInitialized )
initShaders ( ) ;
m_RenderData . damage . set ( damage ) ;
m_RenderData . finalDamage . set ( damage ) ;
m_bFakeFrame = true ;
m_RenderData . currentFB = FBO ;
FBO - > bind ( ) ;
m_bOffloadedFramebuffer = false ;
m_RenderData . mainFB = m_RenderData . currentFB ;
m_RenderData . outFB = FBO ;
m_RenderData . simplePass = true ;
}
2024-02-23 02:02:32 +01:00
void CHyprOpenGLImpl : : begin ( CMonitor * pMonitor , const CRegion & damage_ , CFramebuffer * fb , std : : optional < CRegion > finalDamage ) {
2023-11-24 13:37:10 +01:00
m_RenderData . pMonitor = pMonitor ;
2023-07-20 17:47:49 +02:00
2024-03-03 19:39:20 +01:00
static auto PFORCEINTROSPECTION = CConfigValue < Hyprlang : : INT > ( " opengl:force_introspection " ) ;
2024-02-23 22:21:24 +01:00
2024-01-26 03:26:10 +01:00
# ifndef GLES2
const GLenum RESETSTATUS = glGetGraphicsResetStatus ( ) ;
if ( RESETSTATUS ! = GL_NO_ERROR ) {
std : : string errStr = " " ;
switch ( RESETSTATUS ) {
case GL_GUILTY_CONTEXT_RESET : errStr = " GL_GUILTY_CONTEXT_RESET " ; break ;
case GL_INNOCENT_CONTEXT_RESET : errStr = " GL_INNOCENT_CONTEXT_RESET " ; break ;
case GL_UNKNOWN_CONTEXT_RESET : errStr = " GL_UNKNOWN_CONTEXT_RESET " ; break ;
default : errStr = " UNKNOWN?? " ; break ;
}
RASSERT ( false , " Aborting, glGetGraphicsResetStatus returned {}. Cannot continue until proper GPU reset handling is implemented. " , errStr ) ;
return ;
}
# endif
2023-11-24 11:54:21 +01:00
TRACY_GPU_ZONE ( " RenderBegin " ) ;
2022-08-12 17:10:07 +02:00
2022-05-18 20:33:54 +02:00
glViewport ( 0 , 0 , pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y ) ;
2022-04-04 19:44:25 +02:00
2022-06-28 11:30:07 +02:00
matrixProjection ( m_RenderData . projection , pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y , WL_OUTPUT_TRANSFORM_NORMAL ) ;
2022-04-04 19:44:25 +02:00
2024-05-05 23:18:10 +02:00
m_RenderData . monitorProjection = pMonitor - > projMatrix ;
2024-02-02 16:36:13 +01:00
if ( m_mMonitorRenderResources . contains ( pMonitor ) & & m_mMonitorRenderResources . at ( pMonitor ) . offloadFB . m_vSize ! = pMonitor - > vecPixelSize )
destroyMonitorResources ( pMonitor ) ;
2022-06-29 12:54:53 +02:00
m_RenderData . pCurrentMonData = & m_mMonitorRenderResources [ pMonitor ] ;
2024-01-30 00:11:00 +01:00
if ( ! m_RenderData . pCurrentMonData - > m_bShadersInitialized )
initShaders ( ) ;
2022-04-09 15:01:28 +02:00
// ensure a framebuffer for the monitor exists
2024-02-02 16:36:13 +01:00
if ( m_RenderData . pCurrentMonData - > offloadFB . m_vSize ! = pMonitor - > vecPixelSize ) {
2024-06-08 10:07:59 +02:00
m_RenderData . pCurrentMonData - > stencilTex - > allocate ( ) ;
2022-04-11 16:39:48 +02:00
2024-06-08 10:07:59 +02:00
m_RenderData . pCurrentMonData - > offloadFB . m_pStencilTex = m_RenderData . pCurrentMonData - > stencilTex ;
m_RenderData . pCurrentMonData - > mirrorFB . m_pStencilTex = m_RenderData . pCurrentMonData - > stencilTex ;
m_RenderData . pCurrentMonData - > mirrorSwapFB . m_pStencilTex = m_RenderData . pCurrentMonData - > stencilTex ;
m_RenderData . pCurrentMonData - > offMainFB . m_pStencilTex = m_RenderData . pCurrentMonData - > stencilTex ;
2022-04-11 16:39:48 +02:00
2024-07-21 13:09:54 +02:00
m_RenderData . pCurrentMonData - > offloadFB . alloc ( pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y , pMonitor - > output - > state - > state ( ) . drmFormat ) ;
m_RenderData . pCurrentMonData - > mirrorFB . alloc ( pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y , pMonitor - > output - > state - > state ( ) . drmFormat ) ;
m_RenderData . pCurrentMonData - > mirrorSwapFB . alloc ( pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y , pMonitor - > output - > state - > state ( ) . drmFormat ) ;
m_RenderData . pCurrentMonData - > offMainFB . alloc ( pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y , pMonitor - > output - > state - > state ( ) . drmFormat ) ;
2022-04-10 14:32:18 +02:00
}
2022-04-09 15:01:28 +02:00
2023-07-19 21:04:45 +02:00
if ( m_RenderData . pCurrentMonData - > monitorMirrorFB . isAllocated ( ) & & m_RenderData . pMonitor - > mirrors . empty ( ) )
m_RenderData . pCurrentMonData - > monitorMirrorFB . release ( ) ;
2024-02-23 02:02:32 +01:00
m_RenderData . damage . set ( damage_ ) ;
m_RenderData . finalDamage . set ( finalDamage . value_or ( damage_ ) ) ;
2022-05-18 20:33:54 +02:00
2023-11-30 02:18:55 +01:00
m_bFakeFrame = fb ;
2022-12-01 14:36:07 +01:00
if ( m_bReloadScreenShader ) {
2024-03-03 19:39:20 +01:00
m_bReloadScreenShader = false ;
static auto PSHADER = CConfigValue < std : : string > ( " decoration:screen_shader " ) ;
2024-02-18 16:00:34 +01:00
applyScreenShader ( * PSHADER ) ;
2022-12-01 14:36:07 +01:00
}
2023-11-24 11:54:21 +01:00
2024-02-23 22:21:24 +01:00
const auto PRBO = g_pHyprRenderer - > getCurrentRBO ( ) ;
const bool FBPROPERSIZE = ! fb | | fb - > m_vSize = = pMonitor - > vecPixelSize ;
2024-03-03 19:39:20 +01:00
const bool USERFORCEDINTROSPECTION = * PFORCEINTROSPECTION = = 1 ? true : ( * PFORCEINTROSPECTION = = 2 ? g_pHyprRenderer - > isNvidia ( ) : false ) ; // 0 - no, 1 - yes, 2 - nvidia only
2023-11-24 11:54:21 +01:00
2024-02-23 22:21:24 +01:00
if ( USERFORCEDINTROSPECTION | | m_RenderData . forceIntrospection | | ! FBPROPERSIZE | | m_sFinalScreenShader . program > 0 | |
( PRBO & & pMonitor - > vecPixelSize ! = PRBO - > getFB ( ) - > m_vSize ) | | passRequiresIntrospection ( pMonitor ) ) {
2023-11-24 11:54:21 +01:00
// we have to offload
2023-11-30 02:18:55 +01:00
// bind the offload Hypr Framebuffer
2023-11-24 11:54:21 +01:00
m_RenderData . pCurrentMonData - > offloadFB . bind ( ) ;
m_RenderData . currentFB = & m_RenderData . pCurrentMonData - > offloadFB ;
m_bOffloadedFramebuffer = true ;
} else {
2023-11-30 02:18:55 +01:00
// we can render to the rbo / fbo (fake) directly
const auto PFBO = fb ? fb : PRBO - > getFB ( ) ;
2023-11-24 11:54:21 +01:00
m_RenderData . currentFB = PFBO ;
2024-06-08 10:07:59 +02:00
if ( PFBO - > m_pStencilTex ! = m_RenderData . pCurrentMonData - > stencilTex ) {
PFBO - > m_pStencilTex = m_RenderData . pCurrentMonData - > stencilTex ;
2023-11-24 11:54:21 +01:00
PFBO - > addStencil ( ) ;
}
2023-11-30 02:18:55 +01:00
PFBO - > bind ( ) ;
2023-11-24 11:54:21 +01:00
m_bOffloadedFramebuffer = false ;
}
m_RenderData . mainFB = m_RenderData . currentFB ;
2023-11-30 02:18:55 +01:00
m_RenderData . outFB = fb ? fb : PRBO - > getFB ( ) ;
2022-04-04 19:44:25 +02:00
}
void CHyprOpenGLImpl : : end ( ) {
2024-05-09 23:23:01 +02:00
static auto PZOOMRIGID = CConfigValue < Hyprlang : : INT > ( " cursor:zoom_rigid " ) ;
2023-04-16 15:48:38 +02:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderEnd " ) ;
2024-07-21 13:09:54 +02:00
// end the render, copy the data to the main framebuffer
2023-11-30 02:18:55 +01:00
if ( m_bOffloadedFramebuffer ) {
2024-02-23 02:02:32 +01:00
m_RenderData . damage = m_RenderData . finalDamage ;
2024-04-24 17:29:41 +02:00
m_bEndFrame = true ;
2022-09-13 15:25:42 +02:00
2023-11-04 18:03:05 +01:00
CBox monbox = { 0 , 0 , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y } ;
2022-04-09 15:01:28 +02:00
2023-04-16 15:48:38 +02:00
if ( m_RenderData . mouseZoomFactor ! = 1.f ) {
2023-06-14 13:47:57 +02:00
const auto ZOOMCENTER = m_RenderData . mouseZoomUseMouse ?
( g_pInputManager - > getMouseCoordsInternal ( ) - m_RenderData . pMonitor - > vecPosition ) * m_RenderData . pMonitor - > scale :
m_RenderData . pMonitor - > vecTransformedSize / 2.f ;
2023-11-04 18:03:05 +01:00
2024-03-03 19:39:20 +01:00
monbox . translate ( - ZOOMCENTER ) . scale ( m_RenderData . mouseZoomFactor ) . translate ( * PZOOMRIGID ? m_RenderData . pMonitor - > vecTransformedSize / 2.0 : ZOOMCENTER ) ;
2023-04-16 15:48:38 +02:00
if ( monbox . x > 0 )
monbox . x = 0 ;
if ( monbox . y > 0 )
monbox . y = 0 ;
if ( monbox . x + monbox . width < m_RenderData . pMonitor - > vecTransformedSize . x )
monbox . x = m_RenderData . pMonitor - > vecTransformedSize . x - monbox . width ;
if ( monbox . y + monbox . height < m_RenderData . pMonitor - > vecTransformedSize . y )
monbox . y = m_RenderData . pMonitor - > vecTransformedSize . y - monbox . height ;
}
2024-04-03 22:35:16 +02:00
m_bApplyFinalShader = ! m_RenderData . blockScreenShader ;
2023-05-01 03:49:41 +02:00
if ( m_RenderData . mouseZoomUseMouse )
m_RenderData . useNearestNeighbor = true ;
2022-05-29 12:27:45 +02:00
2024-04-24 17:29:41 +02:00
// copy the damaged areas into the mirror buffer
// we can't use the offloadFB for mirroring, as it contains artifacts from blurring
if ( ! m_RenderData . pMonitor - > mirrors . empty ( ) & & ! m_bFakeFrame )
saveBufferForMirror ( & monbox ) ;
m_RenderData . outFB - > bind ( ) ;
2023-07-20 13:49:28 +02:00
blend ( false ) ;
2024-02-18 16:00:34 +01:00
if ( m_sFinalScreenShader . program < 1 & & ! g_pHyprRenderer - > m_bCrashingInProgress )
2023-11-24 11:54:21 +01:00
renderTexturePrimitive ( m_RenderData . pCurrentMonData - > offloadFB . m_cTex , & monbox ) ;
2023-07-23 15:54:23 +02:00
else
2023-11-24 11:54:21 +01:00
renderTexture ( m_RenderData . pCurrentMonData - > offloadFB . m_cTex , & monbox , 1.f ) ;
2022-05-29 12:27:45 +02:00
2023-07-20 13:49:28 +02:00
blend ( true ) ;
2023-04-16 15:48:38 +02:00
m_RenderData . useNearestNeighbor = false ;
m_bApplyFinalShader = false ;
m_bEndFrame = false ;
2022-05-18 20:33:54 +02:00
}
2022-04-09 15:01:28 +02:00
// reset our data
2024-01-07 18:37:02 +01:00
m_RenderData . pMonitor = nullptr ;
m_RenderData . mouseZoomFactor = 1.f ;
m_RenderData . mouseZoomUseMouse = true ;
m_RenderData . forceIntrospection = false ;
2024-04-03 22:35:16 +02:00
m_RenderData . blockScreenShader = false ;
2024-02-02 15:56:04 +01:00
m_RenderData . currentFB = nullptr ;
m_RenderData . mainFB = nullptr ;
m_RenderData . outFB = nullptr ;
2024-01-26 03:26:10 +01:00
// check for gl errors
const GLenum ERR = glGetError ( ) ;
2024-03-03 01:31:36 +01:00
# ifdef GLES2
if ( ERR = = GL_CONTEXT_LOST_KHR ) /* We don't have infra to recover from this */
# else
2024-01-26 03:26:10 +01:00
if ( ERR = = GL_CONTEXT_LOST ) /* We don't have infra to recover from this */
2024-03-03 01:31:36 +01:00
# endif
2024-01-26 03:26:10 +01:00
RASSERT ( false , " glGetError at Opengl::end() returned GL_CONTEXT_LOST. Cannot continue until proper GPU reset handling is implemented. " ) ;
2022-04-04 19:44:25 +02:00
}
2024-02-23 02:02:32 +01:00
void CHyprOpenGLImpl : : setDamage ( const CRegion & damage_ , std : : optional < CRegion > finalDamage ) {
m_RenderData . damage . set ( damage_ ) ;
m_RenderData . finalDamage . set ( finalDamage . value_or ( damage_ ) ) ;
}
2022-08-11 20:29:21 +02:00
void CHyprOpenGLImpl : : initShaders ( ) {
2023-09-30 02:41:05 +02:00
GLuint prog = createProgram ( QUADVERTSRC , QUADFRAGSRC ) ;
m_RenderData . pCurrentMonData - > m_shQUAD . program = prog ;
m_RenderData . pCurrentMonData - > m_shQUAD . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shQUAD . color = glGetUniformLocation ( prog , " color " ) ;
m_RenderData . pCurrentMonData - > m_shQUAD . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shQUAD . topLeft = glGetUniformLocation ( prog , " topLeft " ) ;
m_RenderData . pCurrentMonData - > m_shQUAD . fullSize = glGetUniformLocation ( prog , " fullSize " ) ;
m_RenderData . pCurrentMonData - > m_shQUAD . radius = glGetUniformLocation ( prog , " radius " ) ;
prog = createProgram ( TEXVERTSRC , TEXFRAGSRCRGBA ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . program = prog ;
m_RenderData . pCurrentMonData - > m_shRGBA . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . tex = glGetUniformLocation ( prog , " tex " ) ;
2023-11-04 20:32:50 +01:00
m_RenderData . pCurrentMonData - > m_shRGBA . alphaMatte = glGetUniformLocation ( prog , " texMatte " ) ;
2023-09-30 02:41:05 +02:00
m_RenderData . pCurrentMonData - > m_shRGBA . alpha = glGetUniformLocation ( prog , " alpha " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
2023-11-04 20:32:50 +01:00
m_RenderData . pCurrentMonData - > m_shRGBA . matteTexAttrib = glGetAttribLocation ( prog , " texcoordMatte " ) ;
2023-09-30 02:41:05 +02:00
m_RenderData . pCurrentMonData - > m_shRGBA . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . discardOpaque = glGetUniformLocation ( prog , " discardOpaque " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . discardAlpha = glGetUniformLocation ( prog , " discardAlpha " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . discardAlphaValue = glGetUniformLocation ( prog , " discardAlphaValue " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . topLeft = glGetUniformLocation ( prog , " topLeft " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . fullSize = glGetUniformLocation ( prog , " fullSize " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . radius = glGetUniformLocation ( prog , " radius " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . applyTint = glGetUniformLocation ( prog , " applyTint " ) ;
m_RenderData . pCurrentMonData - > m_shRGBA . tint = glGetUniformLocation ( prog , " tint " ) ;
2023-11-04 20:32:50 +01:00
m_RenderData . pCurrentMonData - > m_shRGBA . useAlphaMatte = glGetUniformLocation ( prog , " useAlphaMatte " ) ;
2022-12-16 18:17:31 +01:00
2023-03-04 15:59:27 +01:00
prog = createProgram ( TEXVERTSRC , TEXFRAGSRCRGBAPASSTHRU ) ;
m_RenderData . pCurrentMonData - > m_shPASSTHRURGBA . program = prog ;
m_RenderData . pCurrentMonData - > m_shPASSTHRURGBA . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shPASSTHRURGBA . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shPASSTHRURGBA . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shPASSTHRURGBA . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
2023-11-04 20:32:50 +01:00
prog = createProgram ( TEXVERTSRC , TEXFRAGSRCRGBAMATTE ) ;
m_RenderData . pCurrentMonData - > m_shMATTE . program = prog ;
m_RenderData . pCurrentMonData - > m_shMATTE . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shMATTE . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shMATTE . alphaMatte = glGetUniformLocation ( prog , " texMatte " ) ;
m_RenderData . pCurrentMonData - > m_shMATTE . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shMATTE . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
2023-04-04 15:49:58 +02:00
prog = createProgram ( TEXVERTSRC , FRAGGLITCH ) ;
m_RenderData . pCurrentMonData - > m_shGLITCH . program = prog ;
m_RenderData . pCurrentMonData - > m_shGLITCH . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shGLITCH . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shGLITCH . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shGLITCH . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shGLITCH . distort = glGetUniformLocation ( prog , " distort " ) ;
m_RenderData . pCurrentMonData - > m_shGLITCH . time = glGetUniformLocation ( prog , " time " ) ;
m_RenderData . pCurrentMonData - > m_shGLITCH . fullSize = glGetUniformLocation ( prog , " screenSize " ) ;
2023-09-30 02:41:05 +02:00
prog = createProgram ( TEXVERTSRC , TEXFRAGSRCRGBX ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . program = prog ;
m_RenderData . pCurrentMonData - > m_shRGBX . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . alpha = glGetUniformLocation ( prog , " alpha " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . discardOpaque = glGetUniformLocation ( prog , " discardOpaque " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . discardAlpha = glGetUniformLocation ( prog , " discardAlpha " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . discardAlphaValue = glGetUniformLocation ( prog , " discardAlphaValue " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . topLeft = glGetUniformLocation ( prog , " topLeft " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . fullSize = glGetUniformLocation ( prog , " fullSize " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . radius = glGetUniformLocation ( prog , " radius " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . applyTint = glGetUniformLocation ( prog , " applyTint " ) ;
m_RenderData . pCurrentMonData - > m_shRGBX . tint = glGetUniformLocation ( prog , " tint " ) ;
prog = createProgram ( TEXVERTSRC , TEXFRAGSRCEXT ) ;
m_RenderData . pCurrentMonData - > m_shEXT . program = prog ;
m_RenderData . pCurrentMonData - > m_shEXT . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . alpha = glGetUniformLocation ( prog , " alpha " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . discardOpaque = glGetUniformLocation ( prog , " discardOpaque " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . discardAlpha = glGetUniformLocation ( prog , " discardAlpha " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . discardAlphaValue = glGetUniformLocation ( prog , " discardAlphaValue " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . topLeft = glGetUniformLocation ( prog , " topLeft " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . fullSize = glGetUniformLocation ( prog , " fullSize " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . radius = glGetUniformLocation ( prog , " radius " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . applyTint = glGetUniformLocation ( prog , " applyTint " ) ;
m_RenderData . pCurrentMonData - > m_shEXT . tint = glGetUniformLocation ( prog , " tint " ) ;
2022-12-16 18:17:31 +01:00
2023-11-06 19:49:03 +01:00
prog = createProgram ( TEXVERTSRC , FRAGBLUR1 ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . program = prog ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . alpha = glGetUniformLocation ( prog , " alpha " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . radius = glGetUniformLocation ( prog , " radius " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . halfpixel = glGetUniformLocation ( prog , " halfpixel " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . passes = glGetUniformLocation ( prog , " passes " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . vibrancy = glGetUniformLocation ( prog , " vibrancy " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR1 . vibrancy_darkness = glGetUniformLocation ( prog , " vibrancy_darkness " ) ;
2022-08-11 20:29:21 +02:00
2022-12-16 18:17:31 +01:00
prog = createProgram ( TEXVERTSRC , FRAGBLUR2 ) ;
m_RenderData . pCurrentMonData - > m_shBLUR2 . program = prog ;
m_RenderData . pCurrentMonData - > m_shBLUR2 . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR2 . alpha = glGetUniformLocation ( prog , " alpha " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR2 . proj = glGetUniformLocation ( prog , " proj " ) ;
2022-08-11 20:29:21 +02:00
m_RenderData . pCurrentMonData - > m_shBLUR2 . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shBLUR2 . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
2022-12-16 18:17:31 +01:00
m_RenderData . pCurrentMonData - > m_shBLUR2 . radius = glGetUniformLocation ( prog , " radius " ) ;
2022-08-11 20:29:21 +02:00
m_RenderData . pCurrentMonData - > m_shBLUR2 . halfpixel = glGetUniformLocation ( prog , " halfpixel " ) ;
2023-11-06 19:49:03 +01:00
prog = createProgram ( TEXVERTSRC , FRAGBLURPREPARE ) ;
m_RenderData . pCurrentMonData - > m_shBLURPREPARE . program = prog ;
m_RenderData . pCurrentMonData - > m_shBLURPREPARE . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shBLURPREPARE . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shBLURPREPARE . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shBLURPREPARE . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shBLURPREPARE . contrast = glGetUniformLocation ( prog , " contrast " ) ;
m_RenderData . pCurrentMonData - > m_shBLURPREPARE . brightness = glGetUniformLocation ( prog , " brightness " ) ;
2023-08-03 15:11:10 +02:00
prog = createProgram ( TEXVERTSRC , FRAGBLURFINISH ) ;
m_RenderData . pCurrentMonData - > m_shBLURFINISH . program = prog ;
m_RenderData . pCurrentMonData - > m_shBLURFINISH . tex = glGetUniformLocation ( prog , " tex " ) ;
m_RenderData . pCurrentMonData - > m_shBLURFINISH . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shBLURFINISH . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shBLURFINISH . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shBLURFINISH . brightness = glGetUniformLocation ( prog , " brightness " ) ;
2023-11-06 19:49:03 +01:00
m_RenderData . pCurrentMonData - > m_shBLURFINISH . noise = glGetUniformLocation ( prog , " noise " ) ;
2023-08-03 15:11:10 +02:00
2023-11-09 22:58:09 +01:00
prog = createProgram ( QUADVERTSRC , FRAGSHADOW ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . program = prog ;
m_RenderData . pCurrentMonData - > m_shSHADOW . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . topLeft = glGetUniformLocation ( prog , " topLeft " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . bottomRight = glGetUniformLocation ( prog , " bottomRight " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . fullSize = glGetUniformLocation ( prog , " fullSize " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . radius = glGetUniformLocation ( prog , " radius " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . range = glGetUniformLocation ( prog , " range " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . shadowPower = glGetUniformLocation ( prog , " shadowPower " ) ;
m_RenderData . pCurrentMonData - > m_shSHADOW . color = glGetUniformLocation ( prog , " color " ) ;
2022-12-16 18:17:31 +01:00
prog = createProgram ( QUADVERTSRC , FRAGBORDER1 ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . program = prog ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . proj = glGetUniformLocation ( prog , " proj " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . thick = glGetUniformLocation ( prog , " thick " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . posAttrib = glGetAttribLocation ( prog , " pos " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . texAttrib = glGetAttribLocation ( prog , " texcoord " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . topLeft = glGetUniformLocation ( prog , " topLeft " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . bottomRight = glGetUniformLocation ( prog , " bottomRight " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . fullSize = glGetUniformLocation ( prog , " fullSize " ) ;
2022-11-26 21:36:05 +01:00
m_RenderData . pCurrentMonData - > m_shBORDER1 . fullSizeUntransformed = glGetUniformLocation ( prog , " fullSizeUntransformed " ) ;
2022-12-16 18:17:31 +01:00
m_RenderData . pCurrentMonData - > m_shBORDER1 . radius = glGetUniformLocation ( prog , " radius " ) ;
2023-10-19 15:04:50 +02:00
m_RenderData . pCurrentMonData - > m_shBORDER1 . radiusOuter = glGetUniformLocation ( prog , " radiusOuter " ) ;
2022-12-16 18:17:31 +01:00
m_RenderData . pCurrentMonData - > m_shBORDER1 . gradient = glGetUniformLocation ( prog , " gradient " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . gradientLength = glGetUniformLocation ( prog , " gradientLength " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . angle = glGetUniformLocation ( prog , " angle " ) ;
m_RenderData . pCurrentMonData - > m_shBORDER1 . alpha = glGetUniformLocation ( prog , " alpha " ) ;
2022-08-11 20:29:21 +02:00
m_RenderData . pCurrentMonData - > m_bShadersInitialized = true ;
Debug : : log ( LOG , " Shaders initialized successfully. " ) ;
}
2022-12-01 14:36:07 +01:00
void CHyprOpenGLImpl : : applyScreenShader ( const std : : string & path ) {
2024-03-03 19:39:20 +01:00
static auto PDT = CConfigValue < Hyprlang : : INT > ( " debug:damage_tracking " ) ;
2024-02-18 16:00:34 +01:00
2022-12-01 14:36:07 +01:00
m_sFinalScreenShader . destroy ( ) ;
if ( path = = " " | | path = = STRVAL_EMPTY )
return ;
2024-07-16 21:23:37 +02:00
std : : ifstream infile ( absolutePath ( path , g_pConfigManager - > getMainConfigPath ( ) ) ) ;
2022-12-01 14:36:07 +01:00
if ( ! infile . good ( ) ) {
g_pConfigManager - > addParseError ( " Screen shader parser: Screen shader path not found " ) ;
return ;
}
std : : string fragmentShader ( ( std : : istreambuf_iterator < char > ( infile ) ) , ( std : : istreambuf_iterator < char > ( ) ) ) ;
2024-03-18 05:15:04 +01:00
m_sFinalScreenShader . program = createProgram ( fragmentShader . starts_with ( " #version 320 es " ) ? TEXVERTSRC320 : TEXVERTSRC , fragmentShader , true ) ;
2022-12-16 18:17:31 +01:00
2022-12-01 14:36:07 +01:00
if ( ! m_sFinalScreenShader . program ) {
2024-03-21 15:46:23 +01:00
// Error will have been sent by now by the underlying cause
2022-12-01 14:36:07 +01:00
return ;
}
2024-07-16 22:03:10 +02:00
m_sFinalScreenShader . proj = glGetUniformLocation ( m_sFinalScreenShader . program , " proj " ) ;
m_sFinalScreenShader . tex = glGetUniformLocation ( m_sFinalScreenShader . program , " tex " ) ;
m_sFinalScreenShader . time = glGetUniformLocation ( m_sFinalScreenShader . program , " time " ) ;
if ( m_sFinalScreenShader . time ! = - 1 )
m_sFinalScreenShader . initialTime = m_tGlobalTimer . getSeconds ( ) ;
2024-02-04 03:30:00 +01:00
m_sFinalScreenShader . wl_output = glGetUniformLocation ( m_sFinalScreenShader . program , " wl_output " ) ;
2024-03-18 17:35:22 +01:00
m_sFinalScreenShader . fullSize = glGetUniformLocation ( m_sFinalScreenShader . program , " screen_size " ) ;
2024-03-19 00:51:32 +01:00
if ( m_sFinalScreenShader . fullSize = = - 1 )
m_sFinalScreenShader . fullSize = glGetUniformLocation ( m_sFinalScreenShader . program , " screenSize " ) ;
2024-03-03 19:39:20 +01:00
if ( m_sFinalScreenShader . time ! = - 1 & & * PDT ! = 0 & & ! g_pHyprRenderer - > m_bCrashingInProgress ) {
2023-03-05 15:05:30 +01:00
// The screen shader uses the "time" uniform
// Since the screen shader could change every frame, damage tracking *needs* to be disabled
g_pConfigManager - > addParseError ( " Screen shader: Screen shader uses uniform 'time', which requires debug:damage_tracking to be switched off. \n "
" WARNING: Disabling damage tracking will *massively* increase GPU utilization! " ) ;
}
2022-12-01 14:36:07 +01:00
m_sFinalScreenShader . texAttrib = glGetAttribLocation ( m_sFinalScreenShader . program , " texcoord " ) ;
m_sFinalScreenShader . posAttrib = glGetAttribLocation ( m_sFinalScreenShader . program , " pos " ) ;
}
2022-04-04 19:44:25 +02:00
void CHyprOpenGLImpl : : clear ( const CColor & color ) {
RASSERT ( m_RenderData . pMonitor , " Tried to render without begin()! " ) ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderClear " ) ;
2023-01-05 19:25:45 +01:00
glClearColor ( color . r , color . g , color . b , color . a ) ;
2022-04-14 16:43:29 +02:00
2023-07-19 20:09:49 +02:00
if ( ! m_RenderData . damage . empty ( ) ) {
for ( auto & RECT : m_RenderData . damage . getRects ( ) ) {
2022-04-14 16:43:29 +02:00
scissor ( & RECT ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
}
}
2022-04-14 17:00:35 +02:00
2023-11-04 18:03:05 +01:00
scissor ( ( CBox * ) nullptr ) ;
2022-04-04 19:44:25 +02:00
}
2023-07-20 13:49:28 +02:00
void CHyprOpenGLImpl : : blend ( bool enabled ) {
2023-08-06 20:33:36 +02:00
if ( enabled ) {
2023-07-20 13:49:28 +02:00
glEnable ( GL_BLEND ) ;
2023-08-06 20:33:36 +02:00
glBlendFunc ( GL_ONE , GL_ONE_MINUS_SRC_ALPHA ) ; // everything is premultiplied
} else
2023-07-20 13:49:28 +02:00
glDisable ( GL_BLEND ) ;
m_bBlend = enabled ;
}
2023-11-04 18:03:05 +01:00
void CHyprOpenGLImpl : : scissor ( const CBox * pBox , bool transform ) {
2022-04-04 21:45:35 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to scissor without begin()! " ) ;
2022-05-18 20:35:24 +02:00
if ( ! pBox ) {
2022-04-04 19:44:25 +02:00
glDisable ( GL_SCISSOR_TEST ) ;
return ;
}
2023-11-04 18:03:05 +01:00
CBox newBox = * pBox ;
2022-05-29 12:27:45 +02:00
2022-09-04 19:27:38 +02:00
if ( transform ) {
2024-07-21 13:09:54 +02:00
const auto TR = wlTransformToHyprutils ( invertTransform ( m_RenderData . pMonitor - > transform ) ) ;
newBox . transform ( TR , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y ) ;
2022-09-04 19:27:38 +02:00
}
2022-05-29 12:27:45 +02:00
glScissor ( newBox . x , newBox . y , newBox . width , newBox . height ) ;
2022-04-04 19:44:25 +02:00
glEnable ( GL_SCISSOR_TEST ) ;
2022-04-04 21:45:35 +02:00
}
2022-09-04 19:27:38 +02:00
void CHyprOpenGLImpl : : scissor ( const pixman_box32 * pBox , bool transform ) {
2022-04-14 16:43:29 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to scissor without begin()! " ) ;
2022-05-18 20:35:24 +02:00
if ( ! pBox ) {
2022-04-14 16:43:29 +02:00
glDisable ( GL_SCISSOR_TEST ) ;
return ;
}
2023-11-04 18:03:05 +01:00
CBox newBox = { pBox - > x1 , pBox - > y1 , pBox - > x2 - pBox - > x1 , pBox - > y2 - pBox - > y1 } ;
2022-05-29 12:27:45 +02:00
2022-09-04 19:27:38 +02:00
scissor ( & newBox , transform ) ;
2022-04-14 16:43:29 +02:00
}
2022-09-04 19:27:38 +02:00
void CHyprOpenGLImpl : : scissor ( const int x , const int y , const int w , const int h , bool transform ) {
2023-11-04 18:03:05 +01:00
CBox box = { x , y , w , h } ;
2022-09-04 19:27:38 +02:00
scissor ( & box , transform ) ;
2022-05-02 16:54:40 +02:00
}
2023-11-04 18:03:05 +01:00
void CHyprOpenGLImpl : : renderRect ( CBox * box , const CColor & col , int round ) {
2023-07-19 20:09:49 +02:00
if ( ! m_RenderData . damage . empty ( ) )
renderRectWithDamage ( box , col , & m_RenderData . damage , round ) ;
2022-06-21 23:09:20 +02:00
}
2023-12-06 21:17:40 +01:00
void CHyprOpenGLImpl : : renderRectWithBlur ( CBox * box , const CColor & col , int round , float blurA , bool xray ) {
2023-08-25 17:43:23 +02:00
if ( m_RenderData . damage . empty ( ) )
return ;
CRegion damage { m_RenderData . damage } ;
2023-11-11 15:37:17 +01:00
damage . intersect ( * box ) ;
2023-08-25 17:43:23 +02:00
2023-12-06 21:17:40 +01:00
CFramebuffer * POUTFB = xray ? & m_RenderData . pCurrentMonData - > blurFB : blurMainFramebufferWithDamage ( blurA , & damage ) ;
2023-08-25 17:43:23 +02:00
2023-11-24 11:54:21 +01:00
m_RenderData . currentFB - > bind ( ) ;
2023-08-25 17:43:23 +02:00
// make a stencil for rounded corners to work with blur
2023-11-04 18:03:05 +01:00
scissor ( ( CBox * ) nullptr ) ; // allow the entire window and stencil to render
2023-08-25 17:43:23 +02:00
glClearStencil ( 0 ) ;
glClear ( GL_STENCIL_BUFFER_BIT ) ;
glEnable ( GL_STENCIL_TEST ) ;
glStencilFunc ( GL_ALWAYS , 1 , - 1 ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
renderRect ( box , CColor ( 0 , 0 , 0 , 0 ) , round ) ;
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
glStencilFunc ( GL_EQUAL , 1 , - 1 ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
scissor ( box ) ;
2023-11-04 18:03:05 +01:00
CBox MONITORBOX = { 0 , 0 , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y } ;
2023-08-25 17:43:23 +02:00
m_bEndFrame = true ; // fix transformed
const auto SAVEDRENDERMODIF = m_RenderData . renderModif ;
m_RenderData . renderModif = { } ; // fix shit
renderTextureInternalWithDamage ( POUTFB - > m_cTex , & MONITORBOX , blurA , & damage , 0 , false , false , false ) ;
m_bEndFrame = false ;
m_RenderData . renderModif = SAVEDRENDERMODIF ;
glClearStencil ( 0 ) ;
glClear ( GL_STENCIL_BUFFER_BIT ) ;
glDisable ( GL_STENCIL_TEST ) ;
glStencilMask ( - 1 ) ;
glStencilFunc ( GL_ALWAYS , 1 , 0xFF ) ;
2023-11-04 18:03:05 +01:00
scissor ( ( CBox * ) nullptr ) ;
2023-08-25 17:43:23 +02:00
renderRectWithDamage ( box , col , & m_RenderData . damage , round ) ;
}
2023-11-04 18:03:05 +01:00
void CHyprOpenGLImpl : : renderRectWithDamage ( CBox * box , const CColor & col , CRegion * damage , int round ) {
2022-04-04 21:45:35 +02:00
RASSERT ( ( box - > width > 0 & & box - > height > 0 ) , " Tried to render rect with width/height < 0! " ) ;
RASSERT ( m_RenderData . pMonitor , " Tried to render rect without begin()! " ) ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderRectWithDamage " ) ;
2023-11-04 18:03:05 +01:00
CBox newBox = * box ;
2024-01-07 18:35:44 +01:00
m_RenderData . renderModif . applyToBox ( newBox ) ;
2023-04-12 13:41:23 +02:00
box = & newBox ;
2022-04-04 21:45:35 +02:00
float matrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
projectBox ( matrix , newBox , wlTransformToHyprutils ( invertTransform ( ! m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData . pMonitor - > transform ) ) , newBox . rot ,
m_RenderData . monitorProjection . data ( ) ) ;
2022-04-04 21:45:35 +02:00
float glMatrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
matrixMultiply ( glMatrix , m_RenderData . projection , matrix ) ;
2022-04-04 21:45:35 +02:00
2022-08-11 20:29:21 +02:00
glUseProgram ( m_RenderData . pCurrentMonData - > m_shQUAD . program ) ;
2022-04-04 21:45:35 +02:00
2022-10-22 22:10:40 +02:00
# ifndef GLES2
2022-10-10 01:32:04 +02:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shQUAD . proj , 1 , GL_TRUE , glMatrix ) ;
2022-10-22 22:10:40 +02:00
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2022-10-22 22:10:40 +02:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shQUAD . proj , 1 , GL_FALSE , glMatrix ) ;
# endif
2023-08-06 20:33:36 +02:00
// premultiply the color as well as we don't work with straight alpha
glUniform4f ( m_RenderData . pCurrentMonData - > m_shQUAD . color , col . r * col . a , col . g * col . a , col . b * col . a , col . a ) ;
2022-04-04 21:45:35 +02:00
2023-11-04 18:03:05 +01:00
CBox transformedBox = * box ;
2024-07-21 13:09:54 +02:00
transformedBox . transform ( wlTransformToHyprutils ( invertTransform ( m_RenderData . pMonitor - > transform ) ) , m_RenderData . pMonitor - > vecTransformedSize . x ,
2023-11-04 18:03:05 +01:00
m_RenderData . pMonitor - > vecTransformedSize . y ) ;
2022-10-09 01:58:00 +02:00
2023-09-30 02:41:05 +02:00
const auto TOPLEFT = Vector2D ( transformedBox . x , transformedBox . y ) ;
const auto FULLSIZE = Vector2D ( transformedBox . width , transformedBox . height ) ;
2022-06-07 20:41:40 +02:00
2022-05-17 13:16:37 +02:00
// Rounded corners
2022-08-11 20:29:21 +02:00
glUniform2f ( m_RenderData . pCurrentMonData - > m_shQUAD . topLeft , ( float ) TOPLEFT . x , ( float ) TOPLEFT . y ) ;
glUniform2f ( m_RenderData . pCurrentMonData - > m_shQUAD . fullSize , ( float ) FULLSIZE . x , ( float ) FULLSIZE . y ) ;
glUniform1f ( m_RenderData . pCurrentMonData - > m_shQUAD . radius , round ) ;
2022-05-17 13:16:37 +02:00
2022-08-11 20:29:21 +02:00
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shQUAD . posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
2022-04-04 21:45:35 +02:00
2022-08-11 20:29:21 +02:00
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shQUAD . posAttrib ) ;
2022-04-04 21:45:35 +02:00
2022-10-07 11:35:17 +02:00
if ( m_RenderData . clipBox . width ! = 0 & & m_RenderData . clipBox . height ! = 0 ) {
2023-07-19 20:09:49 +02:00
CRegion damageClip { m_RenderData . clipBox . x , m_RenderData . clipBox . y , m_RenderData . clipBox . width , m_RenderData . clipBox . height } ;
damageClip . intersect ( * damage ) ;
2022-10-07 11:35:17 +02:00
2023-07-19 20:09:49 +02:00
if ( ! damageClip . empty ( ) ) {
for ( auto & RECT : damageClip . getRects ( ) ) {
2022-10-07 11:35:17 +02:00
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
}
} else {
2023-07-19 20:09:49 +02:00
for ( auto & RECT : damage - > getRects ( ) ) {
2022-12-16 18:17:31 +01:00
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
2022-05-17 13:16:37 +02:00
}
2022-04-04 21:45:35 +02:00
2022-08-11 20:29:21 +02:00
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shQUAD . posAttrib ) ;
2024-04-03 15:09:58 +02:00
scissor ( ( CBox * ) nullptr ) ;
2022-04-05 14:33:54 +02:00
}
2024-06-08 10:07:59 +02:00
void CHyprOpenGLImpl : : renderTexture ( SP < CTexture > tex , CBox * pBox , float alpha , int round , bool discardActive , bool allowCustomUV ) {
2022-04-14 16:43:29 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to render texture without begin()! " ) ;
2023-07-19 20:09:49 +02:00
renderTextureInternalWithDamage ( tex , pBox , alpha , & m_RenderData . damage , round , discardActive , false , allowCustomUV , true ) ;
2022-04-14 17:00:35 +02:00
2023-11-04 18:03:05 +01:00
scissor ( ( CBox * ) nullptr ) ;
2022-04-14 16:43:29 +02:00
}
2024-07-21 13:09:54 +02:00
void CHyprOpenGLImpl : : renderTextureWithDamage ( SP < CTexture > tex , CBox * pBox , CRegion * damage , float alpha , int round , bool discardActive , bool allowCustomUV ,
SP < CSyncTimeline > waitTimeline , uint64_t waitPoint ) {
2024-05-05 23:18:10 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to render texture without begin()! " ) ;
2024-07-21 13:09:54 +02:00
renderTextureInternalWithDamage ( tex , pBox , alpha , damage , round , discardActive , false , allowCustomUV , true , waitTimeline , waitPoint ) ;
2024-05-05 23:18:10 +02:00
scissor ( ( CBox * ) nullptr ) ;
}
2024-06-08 10:07:59 +02:00
void CHyprOpenGLImpl : : renderTextureInternalWithDamage ( SP < CTexture > tex , CBox * pBox , float alpha , CRegion * damage , int round , bool discardActive , bool noAA , bool allowCustomUV ,
2024-07-21 13:09:54 +02:00
bool allowDim , SP < CSyncTimeline > waitTimeline , uint64_t waitPoint ) {
2022-04-05 14:33:54 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to render texture without begin()! " ) ;
2024-06-08 10:07:59 +02:00
RASSERT ( ( tex - > m_iTexID > 0 ) , " Attempted to draw NULL texture! " ) ;
2023-01-23 14:55:11 +01:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderTextureInternalWithDamage " ) ;
2023-01-07 13:12:02 +01:00
alpha = std : : clamp ( alpha , 0.f , 1.f ) ;
2022-04-05 14:33:54 +02:00
2024-01-30 00:11:00 +01:00
if ( damage - > empty ( ) )
2022-12-16 18:17:31 +01:00
return ;
2022-10-08 00:40:05 +02:00
2023-11-04 18:03:05 +01:00
CBox newBox = * pBox ;
2024-01-07 18:35:44 +01:00
m_RenderData . renderModif . applyToBox ( newBox ) ;
2023-04-12 13:41:23 +02:00
2024-03-03 19:39:20 +01:00
static auto PDIMINACTIVE = CConfigValue < Hyprlang : : INT > ( " decoration:dim_inactive " ) ;
static auto PDT = CConfigValue < Hyprlang : : INT > ( " debug:damage_tracking " ) ;
2022-08-30 12:46:17 +02:00
2024-07-22 13:01:55 +02:00
// get the needed transform for this texture
const bool TRANSFORMS_MATCH = wlTransformToHyprutils ( m_RenderData . pMonitor - > transform ) = = tex - > m_eTransform ; // FIXME: combine them properly!!!
eTransform TRANSFORM = HYPRUTILS_TRANSFORM_NORMAL ;
if ( m_bEndFrame | | TRANSFORMS_MATCH )
TRANSFORM = wlTransformToHyprutils ( invertTransform ( m_RenderData . pMonitor - > transform ) ) ;
float matrix [ 9 ] ;
2024-06-19 16:20:06 +02:00
projectBox ( matrix , newBox , TRANSFORM , newBox . rot , m_RenderData . monitorProjection . data ( ) ) ;
2022-04-14 16:43:29 +02:00
2022-04-05 14:33:54 +02:00
float glMatrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
matrixMultiply ( glMatrix , m_RenderData . projection , matrix ) ;
if ( waitTimeline ! = nullptr ) {
if ( ! waitForTimelinePoint ( waitTimeline , waitPoint ) ) {
Debug : : log ( ERR , " renderTextureInternalWithDamage: failed to wait for explicit sync point {} " , waitPoint ) ;
return ;
}
}
2022-04-05 14:33:54 +02:00
2023-08-06 20:33:36 +02:00
CShader * shader = nullptr ;
2022-04-05 17:01:44 +02:00
2023-04-04 15:49:58 +02:00
bool usingFinalShader = false ;
const bool CRASHING = m_bApplyFinalShader & & g_pHyprRenderer - > m_bCrashingInProgress ;
2022-12-01 14:36:07 +01:00
2023-04-04 15:49:58 +02:00
if ( CRASHING ) {
shader = & m_RenderData . pCurrentMonData - > m_shGLITCH ;
usingFinalShader = true ;
} else if ( m_bApplyFinalShader & & m_sFinalScreenShader . program ) {
2022-12-16 18:17:31 +01:00
shader = & m_sFinalScreenShader ;
2022-12-01 14:36:07 +01:00
usingFinalShader = true ;
} else {
2023-03-04 15:59:27 +01:00
if ( m_bApplyFinalShader ) {
shader = & m_RenderData . pCurrentMonData - > m_shPASSTHRURGBA ;
usingFinalShader = true ;
} else {
2024-06-08 10:07:59 +02:00
switch ( tex - > m_iType ) {
2023-03-04 15:59:27 +01:00
case TEXTURE_RGBA : shader = & m_RenderData . pCurrentMonData - > m_shRGBA ; break ;
case TEXTURE_RGBX : shader = & m_RenderData . pCurrentMonData - > m_shRGBX ; break ;
case TEXTURE_EXTERNAL : shader = & m_RenderData . pCurrentMonData - > m_shEXT ; break ;
2024-06-08 10:07:59 +02:00
default : RASSERT ( false , " tex->m_iTarget unsupported! " ) ;
2023-03-04 15:59:27 +01:00
}
2022-12-01 14:36:07 +01:00
}
2022-04-05 14:33:54 +02:00
}
2024-07-11 16:10:42 +02:00
if ( m_pCurrentWindow . lock ( ) & & m_pCurrentWindow - > m_sWindowData . RGBX . valueOrDefault ( ) )
2023-03-26 03:00:24 +02:00
shader = & m_RenderData . pCurrentMonData - > m_shRGBX ;
2022-04-05 14:33:54 +02:00
glActiveTexture ( GL_TEXTURE0 ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( tex - > m_iTarget , tex - > m_iTexID ) ;
2022-04-05 14:33:54 +02:00
2023-04-16 15:48:38 +02:00
if ( m_RenderData . useNearestNeighbor ) {
2024-06-08 10:07:59 +02:00
glTexParameteri ( tex - > m_iTarget , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( tex - > m_iTarget , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
2023-04-16 15:48:38 +02:00
} else {
2024-06-08 10:07:59 +02:00
glTexParameteri ( tex - > m_iTarget , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( tex - > m_iTarget , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
2023-04-16 15:48:38 +02:00
}
2022-04-05 14:33:54 +02:00
glUseProgram ( shader - > program ) ;
2022-10-22 22:10:40 +02:00
# ifndef GLES2
2022-10-10 01:32:04 +02:00
glUniformMatrix3fv ( shader - > proj , 1 , GL_TRUE , glMatrix ) ;
2022-10-22 22:10:40 +02:00
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2022-10-22 22:10:40 +02:00
glUniformMatrix3fv ( shader - > proj , 1 , GL_FALSE , glMatrix ) ;
# endif
2022-04-05 14:33:54 +02:00
glUniform1i ( shader - > tex , 0 ) ;
2023-03-05 15:05:30 +01:00
2024-03-03 19:39:20 +01:00
if ( ( usingFinalShader & & * PDT = = 0 ) | | CRASHING ) {
2024-07-16 22:03:10 +02:00
glUniform1f ( shader - > time , m_tGlobalTimer . getSeconds ( ) - shader - > initialTime ) ;
2023-06-14 13:03:20 +02:00
} else if ( usingFinalShader & & shader - > time ! = - 1 ) {
2023-03-05 15:05:30 +01:00
// Don't let time be unitialised
glUniform1f ( shader - > time , 0.f ) ;
}
2024-02-04 03:30:00 +01:00
if ( usingFinalShader & & shader - > wl_output ! = - 1 )
glUniform1i ( shader - > wl_output , m_RenderData . pMonitor - > ID ) ;
2024-03-18 17:35:22 +01:00
if ( usingFinalShader & & shader - > fullSize ! = - 1 )
glUniform2f ( shader - > fullSize , m_RenderData . pMonitor - > vecPixelSize . x , m_RenderData . pMonitor - > vecPixelSize . y ) ;
2023-06-10 16:10:26 +02:00
2023-04-04 15:49:58 +02:00
if ( CRASHING ) {
glUniform1f ( shader - > distort , g_pHyprRenderer - > m_fCrashingDistort ) ;
glUniform2f ( shader - > fullSize , m_RenderData . pMonitor - > vecPixelSize . x , m_RenderData . pMonitor - > vecPixelSize . y ) ;
}
2022-12-01 14:36:07 +01:00
if ( ! usingFinalShader ) {
2023-01-05 19:25:45 +01:00
glUniform1f ( shader - > alpha , alpha ) ;
2023-03-18 00:16:13 +01:00
if ( discardActive ) {
glUniform1i ( shader - > discardOpaque , ! ! ( m_RenderData . discardMode & DISCARD_OPAQUE ) ) ;
2023-06-11 19:30:31 +02:00
glUniform1i ( shader - > discardAlpha , ! ! ( m_RenderData . discardMode & DISCARD_ALPHA ) ) ;
glUniform1f ( shader - > discardAlphaValue , m_RenderData . discardOpacity ) ;
2023-03-18 00:16:13 +01:00
} else {
glUniform1i ( shader - > discardOpaque , 0 ) ;
2023-06-11 19:30:31 +02:00
glUniform1i ( shader - > discardAlpha , 0 ) ;
2023-03-18 00:16:13 +01:00
}
2022-12-01 14:36:07 +01:00
}
2022-04-05 14:33:54 +02:00
2023-11-04 18:03:05 +01:00
CBox transformedBox = newBox ;
2024-07-21 13:09:54 +02:00
transformedBox . transform ( wlTransformToHyprutils ( invertTransform ( m_RenderData . pMonitor - > transform ) ) , m_RenderData . pMonitor - > vecTransformedSize . x ,
2023-11-04 18:03:05 +01:00
m_RenderData . pMonitor - > vecTransformedSize . y ) ;
2022-04-05 15:50:47 +02:00
2023-09-30 02:41:05 +02:00
const auto TOPLEFT = Vector2D ( transformedBox . x , transformedBox . y ) ;
const auto FULLSIZE = Vector2D ( transformedBox . width , transformedBox . height ) ;
2022-04-05 15:50:47 +02:00
2022-12-01 14:36:07 +01:00
if ( ! usingFinalShader ) {
// Rounded corners
glUniform2f ( shader - > topLeft , TOPLEFT . x , TOPLEFT . y ) ;
glUniform2f ( shader - > fullSize , FULLSIZE . x , FULLSIZE . y ) ;
glUniform1f ( shader - > radius , round ) ;
2024-04-27 13:43:12 +02:00
if ( allowDim & & m_pCurrentWindow . lock ( ) & & * PDIMINACTIVE ) {
2022-12-01 14:36:07 +01:00
glUniform1i ( shader - > applyTint , 1 ) ;
2024-05-05 18:16:00 +02:00
const auto DIM = m_pCurrentWindow - > m_fDimPercent . value ( ) ;
2022-12-01 14:36:07 +01:00
glUniform3f ( shader - > tint , 1.f - DIM , 1.f - DIM , 1.f - DIM ) ;
} else {
glUniform1i ( shader - > applyTint , 0 ) ;
}
2022-08-30 12:46:17 +02:00
}
2022-07-19 13:36:54 +02:00
const float verts [ ] = {
2022-12-16 18:17:31 +01:00
m_RenderData . primarySurfaceUVBottomRight . x , m_RenderData . primarySurfaceUVTopLeft . y , // top right
m_RenderData . primarySurfaceUVTopLeft . x , m_RenderData . primarySurfaceUVTopLeft . y , // top left
m_RenderData . primarySurfaceUVBottomRight . x , m_RenderData . primarySurfaceUVBottomRight . y , // bottom right
m_RenderData . primarySurfaceUVTopLeft . x , m_RenderData . primarySurfaceUVBottomRight . y , // bottom left
2022-07-19 13:36:54 +02:00
} ;
2022-06-22 15:45:56 +02:00
2022-10-01 09:54:43 +02:00
glVertexAttribPointer ( shader - > posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
2022-07-19 13:36:54 +02:00
if ( allowCustomUV & & m_RenderData . primarySurfaceUVTopLeft ! = Vector2D ( - 1 , - 1 ) ) {
2022-06-22 15:45:56 +02:00
glVertexAttribPointer ( shader - > texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , verts ) ;
} else {
glVertexAttribPointer ( shader - > texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
}
2022-04-05 14:33:54 +02:00
glEnableVertexAttribArray ( shader - > posAttrib ) ;
glEnableVertexAttribArray ( shader - > texAttrib ) ;
2022-10-07 11:35:17 +02:00
if ( m_RenderData . clipBox . width ! = 0 & & m_RenderData . clipBox . height ! = 0 ) {
2023-07-19 20:09:49 +02:00
CRegion damageClip { m_RenderData . clipBox . x , m_RenderData . clipBox . y , m_RenderData . clipBox . width , m_RenderData . clipBox . height } ;
damageClip . intersect ( * damage ) ;
2022-10-07 11:35:17 +02:00
2023-07-19 20:09:49 +02:00
if ( ! damageClip . empty ( ) ) {
for ( auto & RECT : damageClip . getRects ( ) ) {
2022-10-07 11:35:17 +02:00
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
}
} else {
2023-07-19 20:09:49 +02:00
for ( auto & RECT : damage - > getRects ( ) ) {
2022-12-16 18:17:31 +01:00
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
2022-05-10 09:56:58 +02:00
}
2022-04-05 14:33:54 +02:00
glDisableVertexAttribArray ( shader - > posAttrib ) ;
glDisableVertexAttribArray ( shader - > texAttrib ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( tex - > m_iTarget , 0 ) ;
2022-04-05 16:47:03 +02:00
}
2024-06-08 10:07:59 +02:00
void CHyprOpenGLImpl : : renderTexturePrimitive ( SP < CTexture > tex , CBox * pBox ) {
2023-07-21 17:11:50 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to render texture without begin()! " ) ;
2024-06-08 10:07:59 +02:00
RASSERT ( ( tex - > m_iTexID > 0 ) , " Attempted to draw NULL texture! " ) ;
2023-07-21 17:11:50 +02:00
TRACY_GPU_ZONE ( " RenderTexturePrimitive " ) ;
if ( m_RenderData . damage . empty ( ) )
return ;
2023-11-04 18:03:05 +01:00
CBox newBox = * pBox ;
2024-01-07 18:35:44 +01:00
m_RenderData . renderModif . applyToBox ( newBox ) ;
2023-07-21 17:11:50 +02:00
// get transform
2024-07-21 13:09:54 +02:00
const auto TRANSFORM = wlTransformToHyprutils ( invertTransform ( ! m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData . pMonitor - > transform ) ) ;
2023-07-21 17:11:50 +02:00
float matrix [ 9 ] ;
2024-06-19 16:20:06 +02:00
projectBox ( matrix , newBox , TRANSFORM , newBox . rot , m_RenderData . monitorProjection . data ( ) ) ;
2023-07-21 17:11:50 +02:00
float glMatrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
matrixMultiply ( glMatrix , m_RenderData . projection , matrix ) ;
2023-07-21 17:11:50 +02:00
CShader * shader = & m_RenderData . pCurrentMonData - > m_shPASSTHRURGBA ;
glActiveTexture ( GL_TEXTURE0 ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( tex - > m_iTarget , tex - > m_iTexID ) ;
2023-07-21 17:11:50 +02:00
glUseProgram ( shader - > program ) ;
# ifndef GLES2
glUniformMatrix3fv ( shader - > proj , 1 , GL_TRUE , glMatrix ) ;
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2023-07-21 17:11:50 +02:00
glUniformMatrix3fv ( shader - > proj , 1 , GL_FALSE , glMatrix ) ;
# endif
glUniform1i ( shader - > tex , 0 ) ;
glVertexAttribPointer ( shader - > posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glVertexAttribPointer ( shader - > texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glEnableVertexAttribArray ( shader - > posAttrib ) ;
glEnableVertexAttribArray ( shader - > texAttrib ) ;
for ( auto & RECT : m_RenderData . damage . getRects ( ) ) {
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
2023-11-04 18:03:05 +01:00
scissor ( ( CBox * ) nullptr ) ;
2023-07-25 13:33:08 +02:00
2023-07-21 17:11:50 +02:00
glDisableVertexAttribArray ( shader - > posAttrib ) ;
glDisableVertexAttribArray ( shader - > texAttrib ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( tex - > m_iTarget , 0 ) ;
2023-07-21 17:11:50 +02:00
}
2024-06-08 10:07:59 +02:00
void CHyprOpenGLImpl : : renderTextureMatte ( SP < CTexture > tex , CBox * pBox , CFramebuffer & matte ) {
2023-11-04 20:32:50 +01:00
RASSERT ( m_RenderData . pMonitor , " Tried to render texture without begin()! " ) ;
2024-06-08 10:07:59 +02:00
RASSERT ( ( tex - > m_iTexID > 0 ) , " Attempted to draw NULL texture! " ) ;
2023-11-04 20:32:50 +01:00
TRACY_GPU_ZONE ( " RenderTextureMatte " ) ;
if ( m_RenderData . damage . empty ( ) )
return ;
CBox newBox = * pBox ;
2024-01-07 18:35:44 +01:00
m_RenderData . renderModif . applyToBox ( newBox ) ;
2023-11-04 20:32:50 +01:00
// get transform
2024-07-21 13:09:54 +02:00
const auto TRANSFORM = wlTransformToHyprutils ( invertTransform ( ! m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData . pMonitor - > transform ) ) ;
2023-11-04 20:32:50 +01:00
float matrix [ 9 ] ;
2024-06-19 16:20:06 +02:00
projectBox ( matrix , newBox , TRANSFORM , newBox . rot , m_RenderData . monitorProjection . data ( ) ) ;
2023-11-04 20:32:50 +01:00
float glMatrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
matrixMultiply ( glMatrix , m_RenderData . projection , matrix ) ;
2023-11-04 20:32:50 +01:00
CShader * shader = & m_RenderData . pCurrentMonData - > m_shMATTE ;
glUseProgram ( shader - > program ) ;
# ifndef GLES2
glUniformMatrix3fv ( shader - > proj , 1 , GL_TRUE , glMatrix ) ;
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2023-11-04 20:32:50 +01:00
glUniformMatrix3fv ( shader - > proj , 1 , GL_FALSE , glMatrix ) ;
# endif
glUniform1i ( shader - > tex , 0 ) ;
glUniform1i ( shader - > alphaMatte , 1 ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( tex - > m_iTarget , tex - > m_iTexID ) ;
2023-11-04 20:32:50 +01:00
glActiveTexture ( GL_TEXTURE0 + 1 ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( matte . m_cTex - > m_iTarget , matte . m_cTex - > m_iTexID ) ;
2023-11-04 20:32:50 +01:00
glVertexAttribPointer ( shader - > posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glVertexAttribPointer ( shader - > texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glEnableVertexAttribArray ( shader - > posAttrib ) ;
glEnableVertexAttribArray ( shader - > texAttrib ) ;
for ( auto & RECT : m_RenderData . damage . getRects ( ) ) {
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
scissor ( ( CBox * ) nullptr ) ;
glDisableVertexAttribArray ( shader - > posAttrib ) ;
glDisableVertexAttribArray ( shader - > texAttrib ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( tex - > m_iTarget , 0 ) ;
2023-11-04 20:32:50 +01:00
}
2022-04-24 16:41:01 +02:00
// This probably isn't the fastest
// but it works... well, I guess?
//
// Dual (or more) kawase blur
2023-08-25 17:43:23 +02:00
CFramebuffer * CHyprOpenGLImpl : : blurMainFramebufferWithDamage ( float a , CRegion * originalDamage ) {
2022-04-09 16:51:08 +02:00
2023-07-20 17:51:38 +02:00
TRACY_GPU_ZONE ( " RenderBlurMainFramebufferWithDamage " ) ;
2023-07-20 13:49:28 +02:00
const auto BLENDBEFORE = m_bBlend ;
blend ( false ) ;
2022-05-02 16:54:40 +02:00
glDisable ( GL_STENCIL_TEST ) ;
2022-04-24 16:41:01 +02:00
2022-05-02 16:54:40 +02:00
// get transforms for the full monitor
2024-07-21 13:09:54 +02:00
const auto TRANSFORM = wlTransformToHyprutils ( invertTransform ( m_RenderData . pMonitor - > transform ) ) ;
2022-12-16 18:17:31 +01:00
float matrix [ 9 ] ;
2023-11-04 18:03:05 +01:00
CBox MONITORBOX = { 0 , 0 , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y } ;
2024-06-19 16:20:06 +02:00
projectBox ( matrix , MONITORBOX , TRANSFORM , 0 , m_RenderData . monitorProjection . data ( ) ) ;
2022-04-09 16:51:08 +02:00
float glMatrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
matrixMultiply ( glMatrix , m_RenderData . projection , matrix ) ;
2022-04-09 16:51:08 +02:00
2022-05-02 16:54:40 +02:00
// get the config settings
2024-03-03 19:39:20 +01:00
static auto PBLURSIZE = CConfigValue < Hyprlang : : INT > ( " decoration:blur:size " ) ;
static auto PBLURPASSES = CConfigValue < Hyprlang : : INT > ( " decoration:blur:passes " ) ;
static auto PBLURVIBRANCY = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:vibrancy " ) ;
static auto PBLURVIBRANCYDARKNESS = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:vibrancy_darkness " ) ;
2022-04-09 16:51:08 +02:00
2022-05-09 21:37:41 +02:00
// prep damage
2023-07-19 20:09:49 +02:00
CRegion damage { * originalDamage } ;
2024-07-21 13:09:54 +02:00
damage . transform ( wlTransformToHyprutils ( invertTransform ( m_RenderData . pMonitor - > transform ) ) , m_RenderData . pMonitor - > vecTransformedSize . x ,
m_RenderData . pMonitor - > vecTransformedSize . y ) ;
damage . expand ( * PBLURPASSES > 10 ? pow ( 2 , 15 ) : std : : clamp ( * PBLURSIZE , ( int64_t ) 1 , ( int64_t ) 40 ) * pow ( 2 , * PBLURPASSES ) ) ;
2022-09-25 20:07:48 +02:00
2022-05-02 16:54:40 +02:00
// helper
2022-12-16 18:17:31 +01:00
const auto PMIRRORFB = & m_RenderData . pCurrentMonData - > mirrorFB ;
const auto PMIRRORSWAPFB = & m_RenderData . pCurrentMonData - > mirrorSwapFB ;
2022-05-02 16:54:40 +02:00
2023-08-28 18:29:41 +02:00
CFramebuffer * currentRenderToFB = PMIRRORFB ;
2023-11-06 19:49:03 +01:00
// Begin with base color adjustments - global brightness and contrast
2023-08-28 18:29:41 +02:00
// TODO: make this a part of the first pass maybe to save on a drawcall?
{
2024-03-03 19:39:20 +01:00
static auto PBLURCONTRAST = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:contrast " ) ;
static auto PBLURBRIGHTNESS = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:brightness " ) ;
2023-08-28 18:29:41 +02:00
PMIRRORSWAPFB - > bind ( ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( m_RenderData . currentFB - > m_cTex - > m_iTarget , m_RenderData . currentFB - > m_cTex - > m_iTexID ) ;
2023-08-28 18:29:41 +02:00
2024-06-08 10:07:59 +02:00
glTexParameteri ( m_RenderData . currentFB - > m_cTex - > m_iTarget , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
2023-08-28 18:29:41 +02:00
2023-11-06 19:49:03 +01:00
glUseProgram ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . program ) ;
2023-08-28 18:29:41 +02:00
# ifndef GLES2
2023-11-06 19:49:03 +01:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . proj , 1 , GL_TRUE , glMatrix ) ;
2023-08-28 18:29:41 +02:00
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2023-11-16 22:03:17 +01:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . proj , 1 , GL_FALSE , glMatrix ) ;
2023-08-28 18:29:41 +02:00
# endif
2024-03-03 19:39:20 +01:00
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . contrast , * PBLURCONTRAST ) ;
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . brightness , * PBLURBRIGHTNESS ) ;
2023-11-06 19:49:03 +01:00
glUniform1i ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . tex , 0 ) ;
2023-08-28 18:29:41 +02:00
2023-11-06 19:49:03 +01:00
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
2023-08-28 18:29:41 +02:00
2023-11-06 19:49:03 +01:00
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . posAttrib ) ;
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . texAttrib ) ;
2023-08-28 18:29:41 +02:00
if ( ! damage . empty ( ) ) {
for ( auto & RECT : damage . getRects ( ) ) {
scissor ( & RECT , false /* this region is already transformed */ ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
}
2023-11-06 19:49:03 +01:00
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . posAttrib ) ;
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBLURPREPARE . texAttrib ) ;
2023-08-28 18:29:41 +02:00
currentRenderToFB = PMIRRORSWAPFB ;
}
2022-05-02 16:54:40 +02:00
// declare the draw func
2023-07-19 20:09:49 +02:00
auto drawPass = [ & ] ( CShader * pShader , CRegion * pDamage ) {
2022-05-02 16:54:40 +02:00
if ( currentRenderToFB = = PMIRRORFB )
PMIRRORSWAPFB - > bind ( ) ;
else
PMIRRORFB - > bind ( ) ;
2022-04-09 16:51:08 +02:00
glActiveTexture ( GL_TEXTURE0 ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( currentRenderToFB - > m_cTex - > m_iTarget , currentRenderToFB - > m_cTex - > m_iTexID ) ;
2022-05-02 16:54:40 +02:00
2024-06-08 10:07:59 +02:00
glTexParameteri ( currentRenderToFB - > m_cTex - > m_iTarget , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
2022-04-09 16:51:08 +02:00
glUseProgram ( pShader - > program ) ;
2022-05-02 16:54:40 +02:00
// prep two shaders
2022-10-22 22:10:40 +02:00
# ifndef GLES2
2022-10-10 01:32:04 +02:00
glUniformMatrix3fv ( pShader - > proj , 1 , GL_TRUE , glMatrix ) ;
2022-10-22 22:10:40 +02:00
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2022-10-22 22:10:40 +02:00
glUniformMatrix3fv ( pShader - > proj , 1 , GL_FALSE , glMatrix ) ;
# endif
2024-03-03 19:39:20 +01:00
glUniform1f ( pShader - > radius , * PBLURSIZE * a ) ; // this makes the blursize change with a
2023-11-06 19:49:03 +01:00
if ( pShader = = & m_RenderData . pCurrentMonData - > m_shBLUR1 ) {
2022-12-16 18:17:31 +01:00
glUniform2f ( m_RenderData . pCurrentMonData - > m_shBLUR1 . halfpixel , 0.5f / ( m_RenderData . pMonitor - > vecPixelSize . x / 2.f ) ,
0.5f / ( m_RenderData . pMonitor - > vecPixelSize . y / 2.f ) ) ;
2024-03-03 19:39:20 +01:00
glUniform1i ( m_RenderData . pCurrentMonData - > m_shBLUR1 . passes , * PBLURPASSES ) ;
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBLUR1 . vibrancy , * PBLURVIBRANCY ) ;
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBLUR1 . vibrancy_darkness , * PBLURVIBRANCYDARKNESS ) ;
2023-11-06 19:49:03 +01:00
} else
2022-12-16 18:17:31 +01:00
glUniform2f ( m_RenderData . pCurrentMonData - > m_shBLUR2 . halfpixel , 0.5f / ( m_RenderData . pMonitor - > vecPixelSize . x * 2.f ) ,
0.5f / ( m_RenderData . pMonitor - > vecPixelSize . y * 2.f ) ) ;
2022-04-09 16:51:08 +02:00
glUniform1i ( pShader - > tex , 0 ) ;
glVertexAttribPointer ( pShader - > posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glVertexAttribPointer ( pShader - > texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glEnableVertexAttribArray ( pShader - > posAttrib ) ;
glEnableVertexAttribArray ( pShader - > texAttrib ) ;
2023-07-19 20:09:49 +02:00
if ( ! pDamage - > empty ( ) ) {
for ( auto & RECT : pDamage - > getRects ( ) ) {
2022-09-04 19:27:38 +02:00
scissor ( & RECT , false /* this region is already transformed */ ) ;
2022-05-02 16:54:40 +02:00
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
}
2022-04-09 16:51:08 +02:00
glDisableVertexAttribArray ( pShader - > posAttrib ) ;
glDisableVertexAttribArray ( pShader - > texAttrib ) ;
2022-05-02 16:54:40 +02:00
if ( currentRenderToFB ! = PMIRRORFB )
currentRenderToFB = PMIRRORFB ;
else
currentRenderToFB = PMIRRORSWAPFB ;
} ;
2022-04-24 16:41:01 +02:00
2022-05-02 16:54:40 +02:00
// draw the things.
2023-08-28 18:29:41 +02:00
// first draw is swap -> mirr
2022-05-02 16:54:40 +02:00
PMIRRORFB - > bind ( ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( PMIRRORSWAPFB - > m_cTex - > m_iTarget , PMIRRORSWAPFB - > m_cTex - > m_iTexID ) ;
2022-04-24 16:41:01 +02:00
2022-05-02 16:54:40 +02:00
// damage region will be scaled, make a temp
2023-07-19 20:09:49 +02:00
CRegion tempDamage { damage } ;
2022-04-24 16:41:01 +02:00
2022-05-02 16:54:40 +02:00
// and draw
2024-03-03 19:39:20 +01:00
for ( int i = 1 ; i < = * PBLURPASSES ; + + i ) {
2024-07-21 13:09:54 +02:00
tempDamage = damage . copy ( ) . scale ( 1.f / ( 1 < < i ) ) ;
2022-12-16 18:17:31 +01:00
drawPass ( & m_RenderData . pCurrentMonData - > m_shBLUR1 , & tempDamage ) ; // down
2022-05-02 16:54:40 +02:00
}
2022-04-24 16:41:01 +02:00
2024-03-03 19:39:20 +01:00
for ( int i = * PBLURPASSES - 1 ; i > = 0 ; - - i ) {
2024-07-21 13:09:54 +02:00
tempDamage = damage . copy ( ) . scale ( 1.f / ( 1 < < i ) ) ; // when upsampling we make the region twice as big
drawPass ( & m_RenderData . pCurrentMonData - > m_shBLUR2 , & tempDamage ) ; // up
2022-04-09 17:06:09 +02:00
}
2022-04-09 16:51:08 +02:00
2023-11-06 19:49:03 +01:00
// finalize the image
2023-08-03 15:11:10 +02:00
{
2024-03-03 19:39:20 +01:00
static auto PBLURNOISE = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:noise " ) ;
static auto PBLURBRIGHTNESS = CConfigValue < Hyprlang : : FLOAT > ( " decoration:blur:brightness " ) ;
2023-08-03 15:11:10 +02:00
if ( currentRenderToFB = = PMIRRORFB )
PMIRRORSWAPFB - > bind ( ) ;
else
PMIRRORFB - > bind ( ) ;
glActiveTexture ( GL_TEXTURE0 ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( currentRenderToFB - > m_cTex - > m_iTarget , currentRenderToFB - > m_cTex - > m_iTexID ) ;
2023-08-03 15:11:10 +02:00
2024-06-08 10:07:59 +02:00
glTexParameteri ( currentRenderToFB - > m_cTex - > m_iTarget , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
2023-08-03 15:11:10 +02:00
glUseProgram ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . program ) ;
# ifndef GLES2
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . proj , 1 , GL_TRUE , glMatrix ) ;
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2023-08-03 15:11:10 +02:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . proj , 1 , GL_FALSE , glMatrix ) ;
# endif
2024-03-03 19:39:20 +01:00
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . noise , * PBLURNOISE ) ;
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . brightness , * PBLURBRIGHTNESS ) ;
2023-08-03 15:11:10 +02:00
glUniform1i ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . tex , 0 ) ;
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . posAttrib ) ;
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . texAttrib ) ;
if ( ! damage . empty ( ) ) {
for ( auto & RECT : damage . getRects ( ) ) {
scissor ( & RECT , false /* this region is already transformed */ ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
}
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . posAttrib ) ;
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBLURFINISH . texAttrib ) ;
if ( currentRenderToFB ! = PMIRRORFB )
currentRenderToFB = PMIRRORFB ;
else
currentRenderToFB = PMIRRORSWAPFB ;
}
2022-05-02 16:54:40 +02:00
// finish
2024-06-08 10:07:59 +02:00
glBindTexture ( PMIRRORFB - > m_cTex - > m_iTarget , 0 ) ;
2022-05-02 16:54:40 +02:00
2023-07-20 13:49:28 +02:00
blend ( BLENDBEFORE ) ;
2022-05-02 16:54:40 +02:00
return currentRenderToFB ;
}
2022-08-01 12:16:33 +02:00
void CHyprOpenGLImpl : : markBlurDirtyForMonitor ( CMonitor * pMonitor ) {
m_mMonitorRenderResources [ pMonitor ] . blurFBDirty = true ;
}
2022-08-01 20:18:26 +02:00
void CHyprOpenGLImpl : : preRender ( CMonitor * pMonitor ) {
2024-03-03 19:39:20 +01:00
static auto PBLURNEWOPTIMIZE = CConfigValue < Hyprlang : : INT > ( " decoration:blur:new_optimizations " ) ;
static auto PBLURXRAY = CConfigValue < Hyprlang : : INT > ( " decoration:blur:xray " ) ;
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
2022-08-01 20:18:26 +02:00
2024-03-03 19:39:20 +01:00
if ( ! * PBLURNEWOPTIMIZE | | ! m_mMonitorRenderResources [ pMonitor ] . blurFBDirty | | ! * PBLUR )
2022-08-01 20:18:26 +02:00
return ;
2023-12-05 01:42:58 +01:00
// ignore if solitary present, nothing to blur
2024-04-27 13:43:12 +02:00
if ( ! pMonitor - > solitaryClient . expired ( ) )
2023-12-05 01:42:58 +01:00
return ;
2022-12-18 13:41:13 +01:00
// check if we need to update the blur fb
// if there are no windows that would benefit from it,
// we will ignore that the blur FB is dirty.
2022-08-01 12:23:09 +02:00
2024-04-27 13:43:12 +02:00
auto windowShouldBeBlurred = [ & ] ( PHLWINDOW pWindow ) - > bool {
2022-11-28 20:03:44 +01:00
if ( ! pWindow )
return false ;
2024-07-11 16:10:42 +02:00
if ( pWindow - > m_sWindowData . noBlur . valueOrDefault ( ) )
2022-11-28 20:03:44 +01:00
return false ;
2024-06-08 10:07:59 +02:00
if ( pWindow - > m_pWLSurface - > small ( ) & & ! pWindow - > m_pWLSurface - > m_bFillIgnoreSmall )
2023-12-06 21:17:40 +01:00
return true ;
2024-06-08 10:07:59 +02:00
const auto PSURFACE = pWindow - > m_pWLSurface - > resource ( ) ;
2022-11-28 20:03:44 +01:00
2024-04-02 21:32:39 +02:00
const auto PWORKSPACE = pWindow - > m_pWorkspace ;
2024-03-02 01:35:17 +01:00
const float A = pWindow - > m_fAlpha . value ( ) * pWindow - > m_fActiveInactiveAlpha . value ( ) * PWORKSPACE - > m_fAlpha . value ( ) ;
2022-11-28 20:11:11 +01:00
2023-01-05 19:25:45 +01:00
if ( A > = 1.f ) {
2024-06-08 10:07:59 +02:00
// if (PSURFACE->opaque)
// return false;
2023-01-23 14:55:11 +01:00
2023-07-19 20:09:49 +02:00
CRegion inverseOpaque ;
2023-01-23 14:55:11 +01:00
2024-06-08 10:07:59 +02:00
pixman_box32_t surfbox = { 0 , 0 , PSURFACE - > current . size . x , PSURFACE - > current . size . y } ;
CRegion opaqueRegion { PSURFACE - > current . opaque } ;
inverseOpaque . set ( opaqueRegion ) . invert ( & surfbox ) . intersect ( 0 , 0 , PSURFACE - > current . size . x , PSURFACE - > current . size . y ) ;
2022-11-28 20:11:11 +01:00
2023-07-19 20:09:49 +02:00
if ( inverseOpaque . empty ( ) )
2022-11-28 20:11:11 +01:00
return false ;
2023-01-23 14:55:11 +01:00
}
2022-11-28 20:03:44 +01:00
return true ;
} ;
2022-08-01 12:23:09 +02:00
bool hasWindows = false ;
for ( auto & w : g_pCompositor - > m_vWindows ) {
2024-04-02 21:32:39 +02:00
if ( w - > m_pWorkspace = = pMonitor - > activeWorkspace & & ! w - > isHidden ( ) & & w - > m_bIsMapped & & ( ! w - > m_bIsFloating | | * PBLURXRAY ) ) {
2022-11-28 20:03:44 +01:00
// check if window is valid
2024-04-27 13:43:12 +02:00
if ( ! windowShouldBeBlurred ( w ) )
2022-11-28 20:03:44 +01:00
continue ;
2022-12-16 18:17:31 +01:00
2022-08-01 12:23:09 +02:00
hasWindows = true ;
2022-09-25 20:07:48 +02:00
break ;
2022-08-01 12:23:09 +02:00
}
}
2023-08-09 22:03:24 +02:00
for ( auto & m : g_pCompositor - > m_vMonitors ) {
for ( auto & lsl : m - > m_aLayerSurfaceLayers ) {
for ( auto & ls : lsl ) {
if ( ! ls - > layerSurface | | ls - > xray ! = 1 )
continue ;
2024-06-08 10:07:59 +02:00
// if (ls->layerSurface->surface->opaque && ls->alpha.value() >= 1.f)
// continue;
2023-08-09 22:03:24 +02:00
hasWindows = true ;
break ;
}
}
}
2022-08-01 12:23:09 +02:00
if ( ! hasWindows )
return ;
2022-12-18 13:41:13 +01:00
g_pHyprRenderer - > damageMonitor ( pMonitor ) ;
m_mMonitorRenderResources [ pMonitor ] . blurFBShouldRender = true ;
}
void CHyprOpenGLImpl : : preBlurForCurrentMonitor ( ) {
2023-07-20 17:51:38 +02:00
TRACY_GPU_ZONE ( " RenderPreBlurForCurrentMonitor " ) ;
2023-04-12 13:41:23 +02:00
const auto SAVEDRENDERMODIF = m_RenderData . renderModif ;
m_RenderData . renderModif = { } ; // fix shit
2022-12-18 13:41:13 +01:00
// make the fake dmg
2023-07-19 20:09:49 +02:00
CRegion fakeDamage { 0 , 0 , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y } ;
2023-11-04 18:03:05 +01:00
CBox wholeMonitor = { 0 , 0 , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y } ;
2023-08-25 17:43:23 +02:00
const auto POUTFB = blurMainFramebufferWithDamage ( 1 , & fakeDamage ) ;
2022-12-18 13:41:13 +01:00
// render onto blurFB
2024-07-21 13:09:54 +02:00
m_RenderData . pCurrentMonData - > blurFB . alloc ( m_RenderData . pMonitor - > vecPixelSize . x , m_RenderData . pMonitor - > vecPixelSize . y ,
m_RenderData . pMonitor - > output - > state - > state ( ) . drmFormat ) ;
2022-12-18 13:41:13 +01:00
m_RenderData . pCurrentMonData - > blurFB . bind ( ) ;
clear ( CColor ( 0 , 0 , 0 , 0 ) ) ;
m_bEndFrame = true ; // fix transformed
2023-01-05 19:25:45 +01:00
renderTextureInternalWithDamage ( POUTFB - > m_cTex , & wholeMonitor , 1 , & fakeDamage , 0 , false , true , false ) ;
2022-12-18 13:41:13 +01:00
m_bEndFrame = false ;
2023-11-24 11:54:21 +01:00
m_RenderData . currentFB - > bind ( ) ;
2022-12-18 13:41:13 +01:00
m_RenderData . pCurrentMonData - > blurFBDirty = false ;
2023-04-12 13:41:23 +02:00
m_RenderData . renderModif = SAVEDRENDERMODIF ;
2023-09-01 23:01:59 +02:00
m_mMonitorRenderResources [ m_RenderData . pMonitor ] . blurFBShouldRender = false ;
2022-12-18 13:41:13 +01:00
}
void CHyprOpenGLImpl : : preWindowPass ( ) {
2023-07-20 18:03:47 +02:00
if ( ! preBlurQueued ( ) )
2022-12-18 13:41:13 +01:00
return ;
2022-08-01 12:23:09 +02:00
// blur the main FB, it will be rendered onto the mirror
preBlurForCurrentMonitor ( ) ;
}
2023-07-20 18:03:47 +02:00
bool CHyprOpenGLImpl : : preBlurQueued ( ) {
2024-03-03 19:39:20 +01:00
static auto PBLURNEWOPTIMIZE = CConfigValue < Hyprlang : : INT > ( " decoration:blur:new_optimizations " ) ;
static auto PBLUR = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
2023-07-20 18:03:47 +02:00
2024-03-03 19:39:20 +01:00
return ! ( ! m_RenderData . pCurrentMonData - > blurFBDirty | | ! * PBLURNEWOPTIMIZE | | ! * PBLUR | | ! m_RenderData . pCurrentMonData - > blurFBShouldRender ) ;
2023-07-20 18:03:47 +02:00
}
2024-04-30 03:41:27 +02:00
bool CHyprOpenGLImpl : : shouldUseNewBlurOptimizations ( PHLLS pLayer , PHLWINDOW pWindow ) {
2024-03-03 19:39:20 +01:00
static auto PBLURNEWOPTIMIZE = CConfigValue < Hyprlang : : INT > ( " decoration:blur:new_optimizations " ) ;
static auto PBLURXRAY = CConfigValue < Hyprlang : : INT > ( " decoration:blur:xray " ) ;
2023-08-09 22:03:24 +02:00
2024-06-08 10:07:59 +02:00
if ( ! m_RenderData . pCurrentMonData - > blurFB . m_cTex - > m_iTexID )
2023-08-09 22:03:24 +02:00
return false ;
2024-07-12 23:05:19 +02:00
if ( pWindow & & pWindow - > m_sWindowData . xray . hasValue ( ) & & ! pWindow - > m_sWindowData . xray . valueOrDefault ( ) )
2023-08-09 22:03:24 +02:00
return false ;
if ( pLayer & & pLayer - > xray = = 0 )
return false ;
2024-04-02 21:32:39 +02:00
if ( ( * PBLURNEWOPTIMIZE & & pWindow & & ! pWindow - > m_bIsFloating & & ! pWindow - > onSpecialWorkspace ( ) ) | | * PBLURXRAY )
2023-08-09 22:03:24 +02:00
return true ;
2024-07-11 16:10:42 +02:00
if ( ( pLayer & & pLayer - > xray = = 1 ) | | ( pWindow & & pWindow - > m_sWindowData . xray . valueOrDefault ( ) ) )
2023-08-09 22:03:24 +02:00
return true ;
return false ;
}
2024-06-08 10:07:59 +02:00
void CHyprOpenGLImpl : : renderTextureWithBlur ( SP < CTexture > tex , CBox * pBox , float a , SP < CWLSurfaceResource > pSurface , int round , bool blockBlurOptimization , float blurA ) {
2022-05-02 16:54:40 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to render texture with blur without begin()! " ) ;
2024-03-03 19:39:20 +01:00
static auto PBLURENABLED = CConfigValue < Hyprlang : : INT > ( " decoration:blur:enabled " ) ;
static auto PNOBLUROVERSIZED = CConfigValue < Hyprlang : : INT > ( " decoration:no_blur_on_oversized " ) ;
2022-06-07 20:41:40 +02:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderTextureWithBlur " ) ;
2022-05-02 23:03:22 +02:00
// make a damage region for this window
2023-07-19 20:09:49 +02:00
CRegion texDamage { m_RenderData . damage } ;
texDamage . intersect ( pBox - > x , pBox - > y , pBox - > width , pBox - > height ) ;
2022-05-02 23:03:22 +02:00
2023-07-19 20:09:49 +02:00
if ( texDamage . empty ( ) )
2022-12-16 18:17:31 +01:00
return ;
2022-10-08 00:40:05 +02:00
2024-04-03 15:09:58 +02:00
m_RenderData . renderModif . applyToRegion ( texDamage ) ;
2024-03-03 19:39:20 +01:00
if ( * PBLURENABLED = = 0 | | ( * PNOBLUROVERSIZED & & m_RenderData . primarySurfaceUVTopLeft ! = Vector2D ( - 1 , - 1 ) ) | |
2024-07-11 16:10:42 +02:00
( m_pCurrentWindow . lock ( ) & & ( m_pCurrentWindow - > m_sWindowData . noBlur . valueOrDefault ( ) | | m_pCurrentWindow - > m_sWindowData . RGBX . valueOrDefault ( ) ) ) ) {
2022-10-08 00:40:05 +02:00
renderTexture ( tex , pBox , a , round , false , true ) ;
return ;
}
2022-05-09 21:37:41 +02:00
// amazing hack: the surface has an opaque region!
2023-07-19 20:09:49 +02:00
CRegion inverseOpaque ;
2024-06-08 10:07:59 +02:00
if ( a > = 1.f & & std : : round ( pSurface - > current . size . x * m_RenderData . pMonitor - > scale ) = = pBox - > w & &
std : : round ( pSurface - > current . size . y * m_RenderData . pMonitor - > scale ) = = pBox - > h ) {
pixman_box32_t surfbox = { 0 , 0 , pSurface - > current . size . x * pSurface - > current . scale , pSurface - > current . size . y * pSurface - > current . scale } ;
inverseOpaque = pSurface - > current . opaque ;
inverseOpaque . invert ( & surfbox ) . intersect ( 0 , 0 , pSurface - > current . size . x * pSurface - > current . scale , pSurface - > current . size . y * pSurface - > current . scale ) ;
2022-05-09 21:37:41 +02:00
2023-07-19 20:09:49 +02:00
if ( inverseOpaque . empty ( ) ) {
2022-11-28 20:11:11 +01:00
renderTexture ( tex , pBox , a , round , false , true ) ;
return ;
}
2022-11-29 12:21:03 +01:00
} else {
2023-07-19 20:09:49 +02:00
inverseOpaque = { 0 , 0 , pBox - > width , pBox - > height } ;
2022-06-07 20:10:14 +02:00
}
2022-05-02 16:54:40 +02:00
2024-07-21 13:09:54 +02:00
inverseOpaque . scale ( m_RenderData . pMonitor - > scale ) ;
2023-01-31 13:29:23 +01:00
2023-08-09 22:03:24 +02:00
// vvv TODO: layered blur fbs?
2024-04-27 13:43:12 +02:00
const bool USENEWOPTIMIZE = shouldUseNewBlurOptimizations ( m_pCurrentLayer , m_pCurrentWindow . lock ( ) ) & & ! blockBlurOptimization ;
2022-08-01 15:32:20 +02:00
2022-11-29 12:21:03 +01:00
CFramebuffer * POUTFB = nullptr ;
if ( ! USENEWOPTIMIZE ) {
2024-04-03 15:09:58 +02:00
inverseOpaque . translate ( { pBox - > x , pBox - > y } ) ;
m_RenderData . renderModif . applyToRegion ( inverseOpaque ) ;
inverseOpaque . intersect ( texDamage ) ;
2022-12-12 15:29:04 +01:00
2023-08-25 17:43:23 +02:00
POUTFB = blurMainFramebufferWithDamage ( a , & inverseOpaque ) ;
2022-11-29 12:21:03 +01:00
} else {
POUTFB = & m_RenderData . pCurrentMonData - > blurFB ;
}
2022-05-10 09:19:54 +02:00
2023-11-24 11:54:21 +01:00
m_RenderData . currentFB - > bind ( ) ;
2022-05-02 16:54:40 +02:00
2022-08-01 15:29:49 +02:00
// make a stencil for rounded corners to work with blur
2023-11-04 18:03:05 +01:00
scissor ( ( CBox * ) nullptr ) ; // allow the entire window and stencil to render
2022-08-01 15:29:49 +02:00
glClearStencil ( 0 ) ;
glClear ( GL_STENCIL_BUFFER_BIT ) ;
2022-04-24 16:41:01 +02:00
2022-08-01 15:29:49 +02:00
glEnable ( GL_STENCIL_TEST ) ;
2022-04-24 16:41:01 +02:00
2022-08-01 15:29:49 +02:00
glStencilFunc ( GL_ALWAYS , 1 , - 1 ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
2022-04-24 16:41:01 +02:00
2022-08-01 15:29:49 +02:00
glColorMask ( GL_FALSE , GL_FALSE , GL_FALSE , GL_FALSE ) ;
2023-06-11 19:30:31 +02:00
if ( USENEWOPTIMIZE & & ! ( m_RenderData . discardMode & DISCARD_ALPHA ) )
2022-12-16 18:17:31 +01:00
renderRect ( pBox , CColor ( 0 , 0 , 0 , 0 ) , round ) ;
2022-08-01 15:32:20 +02:00
else
2022-12-16 18:17:31 +01:00
renderTexture ( tex , pBox , a , round , true , true ) ; // discard opaque
2022-08-01 15:29:49 +02:00
glColorMask ( GL_TRUE , GL_TRUE , GL_TRUE , GL_TRUE ) ;
2022-04-24 16:41:01 +02:00
2022-08-01 15:29:49 +02:00
glStencilFunc ( GL_EQUAL , 1 , - 1 ) ;
glStencilOp ( GL_KEEP , GL_KEEP , GL_REPLACE ) ;
2022-04-24 16:41:01 +02:00
2022-05-02 16:54:40 +02:00
// stencil done. Render everything.
2023-11-04 18:03:05 +01:00
CBox MONITORBOX = { 0 , 0 , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y } ;
2022-10-08 00:40:05 +02:00
// render our great blurred FB
2024-03-03 19:39:20 +01:00
static auto PBLURIGNOREOPACITY = CConfigValue < Hyprlang : : INT > ( " decoration:blur:ignore_opacity " ) ;
2024-04-03 15:09:58 +02:00
setMonitorTransformEnabled ( true ) ;
2024-04-03 18:08:11 +02:00
if ( ! USENEWOPTIMIZE )
setRenderModifEnabled ( false ) ;
2024-03-03 19:39:20 +01:00
renderTextureInternalWithDamage ( POUTFB - > m_cTex , & MONITORBOX , * PBLURIGNOREOPACITY ? blurA : a * blurA , & texDamage , 0 , false , false , false ) ;
2024-04-03 18:08:11 +02:00
if ( ! USENEWOPTIMIZE )
setRenderModifEnabled ( true ) ;
2024-04-03 15:09:58 +02:00
setMonitorTransformEnabled ( false ) ;
2022-05-28 18:57:32 +02:00
2022-10-08 00:40:05 +02:00
// render the window, but clear stencil
glClearStencil ( 0 ) ;
glClear ( GL_STENCIL_BUFFER_BIT ) ;
2022-05-17 13:16:37 +02:00
2022-10-08 00:40:05 +02:00
// draw window
glDisable ( GL_STENCIL_TEST ) ;
2023-07-19 20:09:49 +02:00
renderTextureInternalWithDamage ( tex , pBox , a , & texDamage , round , false , false , true , true ) ;
2022-08-01 15:29:49 +02:00
glStencilMask ( - 1 ) ;
glStencilFunc ( GL_ALWAYS , 1 , 0xFF ) ;
2023-11-04 18:03:05 +01:00
scissor ( ( CBox * ) nullptr ) ;
2022-04-09 16:51:08 +02:00
}
2023-11-04 18:03:05 +01:00
void pushVert2D ( float x , float y , float * arr , int & counter , CBox * box ) {
2022-04-05 16:47:03 +02:00
// 0-1 space god damnit
arr [ counter * 2 + 0 ] = x / box - > width ;
arr [ counter * 2 + 1 ] = y / box - > height ;
counter + + ;
}
2023-11-04 18:03:05 +01:00
void CHyprOpenGLImpl : : renderBorder ( CBox * box , const CGradientValueData & grad , int round , int borderSize , float a , int outerRound ) {
2022-04-05 16:47:03 +02:00
RASSERT ( ( box - > width > 0 & & box - > height > 0 ) , " Tried to render rect with width/height < 0! " ) ;
RASSERT ( m_RenderData . pMonitor , " Tried to render rect without begin()! " ) ;
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderBorder " ) ;
2024-07-11 16:10:42 +02:00
if ( m_RenderData . damage . empty ( ) | | ( m_pCurrentWindow . lock ( ) & & m_pCurrentWindow - > m_sWindowData . noBorder . valueOrDefault ( ) ) )
2022-12-16 18:17:31 +01:00
return ;
2022-10-08 00:40:05 +02:00
2023-11-04 18:03:05 +01:00
CBox newBox = * box ;
2024-01-07 18:35:44 +01:00
m_RenderData . renderModif . applyToBox ( newBox ) ;
2023-04-12 13:41:23 +02:00
box = & newBox ;
2023-05-01 23:28:27 +02:00
if ( borderSize < 1 )
2022-08-05 22:21:14 +02:00
return ;
2024-01-07 18:35:44 +01:00
int scaledBorderSize = std : : round ( borderSize * m_RenderData . pMonitor - > scale ) ;
2024-04-03 15:09:58 +02:00
scaledBorderSize = std : : round ( scaledBorderSize * m_RenderData . renderModif . combinedScale ( ) ) ;
2022-09-26 17:38:08 +02:00
2022-06-26 19:39:56 +02:00
// adjust box
2022-09-26 17:38:08 +02:00
box - > x - = scaledBorderSize ;
box - > y - = scaledBorderSize ;
box - > width + = 2 * scaledBorderSize ;
box - > height + = 2 * scaledBorderSize ;
2022-06-26 19:39:56 +02:00
2022-11-26 18:56:43 +01:00
round + = round = = 0 ? 0 : scaledBorderSize ;
2022-06-26 19:39:56 +02:00
float matrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
projectBox ( matrix , newBox , wlTransformToHyprutils ( invertTransform ( ! m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData . pMonitor - > transform ) ) , newBox . rot ,
m_RenderData . monitorProjection . data ( ) ) ;
2022-06-26 19:39:56 +02:00
float glMatrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
matrixMultiply ( glMatrix , m_RenderData . projection , matrix ) ;
2022-06-26 19:39:56 +02:00
2023-08-06 20:33:36 +02:00
const auto BLEND = m_bBlend ;
blend ( true ) ;
2022-06-26 19:39:56 +02:00
2022-08-11 20:29:21 +02:00
glUseProgram ( m_RenderData . pCurrentMonData - > m_shBORDER1 . program ) ;
2022-04-05 16:47:03 +02:00
2022-10-22 22:10:40 +02:00
# ifndef GLES2
2022-10-10 01:32:04 +02:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shBORDER1 . proj , 1 , GL_TRUE , glMatrix ) ;
2022-10-22 22:10:40 +02:00
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2022-10-22 22:10:40 +02:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shBORDER1 . proj , 1 , GL_FALSE , glMatrix ) ;
# endif
2022-11-26 18:56:43 +01:00
2022-11-26 19:09:57 +01:00
static_assert ( sizeof ( CColor ) = = 4 * sizeof ( float ) ) ; // otherwise the line below this will fail
glUniform4fv ( m_RenderData . pCurrentMonData - > m_shBORDER1 . gradient , grad . m_vColors . size ( ) , ( float * ) grad . m_vColors . data ( ) ) ;
2022-11-26 18:56:43 +01:00
glUniform1i ( m_RenderData . pCurrentMonData - > m_shBORDER1 . gradientLength , grad . m_vColors . size ( ) ) ;
2022-11-26 20:37:20 +01:00
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBORDER1 . angle , ( int ) ( grad . m_fAngle / ( PI / 180.0 ) ) % 360 * ( PI / 180.0 ) ) ;
2022-11-26 19:09:57 +01:00
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBORDER1 . alpha , a ) ;
2022-04-05 16:47:03 +02:00
2023-11-04 18:03:05 +01:00
CBox transformedBox = * box ;
2024-07-21 13:09:54 +02:00
transformedBox . transform ( wlTransformToHyprutils ( invertTransform ( m_RenderData . pMonitor - > transform ) ) , m_RenderData . pMonitor - > vecTransformedSize . x ,
2023-11-04 18:03:05 +01:00
m_RenderData . pMonitor - > vecTransformedSize . y ) ;
2022-11-21 19:09:47 +01:00
2022-12-16 18:17:31 +01:00
const auto TOPLEFT = Vector2D ( transformedBox . x , transformedBox . y ) ;
2022-11-21 19:09:47 +01:00
const auto FULLSIZE = Vector2D ( transformedBox . width , transformedBox . height ) ;
2022-04-05 16:47:03 +02:00
2022-08-11 20:29:21 +02:00
glUniform2f ( m_RenderData . pCurrentMonData - > m_shBORDER1 . topLeft , ( float ) TOPLEFT . x , ( float ) TOPLEFT . y ) ;
glUniform2f ( m_RenderData . pCurrentMonData - > m_shBORDER1 . fullSize , ( float ) FULLSIZE . x , ( float ) FULLSIZE . y ) ;
2022-11-26 21:36:05 +01:00
glUniform2f ( m_RenderData . pCurrentMonData - > m_shBORDER1 . fullSizeUntransformed , ( float ) box - > width , ( float ) box - > height ) ;
2022-08-11 20:29:21 +02:00
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBORDER1 . radius , round ) ;
2023-10-19 15:04:50 +02:00
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBORDER1 . radiusOuter , outerRound = = - 1 ? round : outerRound ) ;
2022-09-26 17:38:08 +02:00
glUniform1f ( m_RenderData . pCurrentMonData - > m_shBORDER1 . thick , scaledBorderSize ) ;
2022-06-26 19:39:56 +02:00
2022-08-11 20:29:21 +02:00
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shBORDER1 . posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shBORDER1 . texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
2022-06-26 19:39:56 +02:00
2022-08-11 20:29:21 +02:00
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBORDER1 . posAttrib ) ;
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBORDER1 . texAttrib ) ;
2022-06-26 19:39:56 +02:00
2022-10-07 11:35:17 +02:00
if ( m_RenderData . clipBox . width ! = 0 & & m_RenderData . clipBox . height ! = 0 ) {
2023-07-19 20:09:49 +02:00
CRegion damageClip { m_RenderData . clipBox . x , m_RenderData . clipBox . y , m_RenderData . clipBox . width , m_RenderData . clipBox . height } ;
damageClip . intersect ( m_RenderData . damage ) ;
2022-10-07 11:35:17 +02:00
2023-07-19 20:09:49 +02:00
if ( ! damageClip . empty ( ) ) {
for ( auto & RECT : damageClip . getRects ( ) ) {
2022-10-07 11:35:17 +02:00
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
}
} else {
2023-07-19 20:09:49 +02:00
for ( auto & RECT : m_RenderData . damage . getRects ( ) ) {
2022-12-16 18:17:31 +01:00
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
2022-06-26 19:39:56 +02:00
}
2022-08-11 20:29:21 +02:00
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBORDER1 . posAttrib ) ;
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shBORDER1 . texAttrib ) ;
2022-06-26 19:39:56 +02:00
2023-08-06 20:33:36 +02:00
blend ( BLEND ) ;
2022-04-05 20:49:15 +02:00
}
2024-04-27 13:43:12 +02:00
void CHyprOpenGLImpl : : makeRawWindowSnapshot ( PHLWINDOW pWindow , CFramebuffer * pFramebuffer ) {
2022-11-06 18:52:09 +01:00
// we trust the window is valid.
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2023-03-19 03:19:52 +01:00
2023-06-15 22:07:58 +02:00
if ( ! PMONITOR | | ! PMONITOR - > output | | PMONITOR - > vecPixelSize . x < = 0 | | PMONITOR - > vecPixelSize . y < = 0 )
2023-03-19 03:19:52 +01:00
return ;
2022-11-06 18:52:09 +01:00
// we need to "damage" the entire monitor
// so that we render the entire window
2024-07-21 13:09:54 +02:00
// this is temporary, doesnt mess with the actual damage
2023-07-19 20:09:49 +02:00
CRegion fakeDamage { 0 , 0 , ( int ) PMONITOR - > vecTransformedSize . x , ( int ) PMONITOR - > vecTransformedSize . y } ;
2022-11-06 18:52:09 +01:00
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > makeEGLCurrent ( ) ;
2024-06-08 10:07:59 +02:00
pFramebuffer - > m_pStencilTex = m_RenderData . pCurrentMonData - > stencilTex ;
2023-11-30 02:18:55 +01:00
2024-07-21 13:09:54 +02:00
pFramebuffer - > alloc ( PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y , PMONITOR - > output - > state - > state ( ) . drmFormat ) ;
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , pFramebuffer ) ;
2022-11-06 18:52:09 +01:00
2022-12-16 18:17:31 +01:00
clear ( CColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
2022-11-06 18:52:09 +01:00
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
// this is a hack but it works :P
// we need to disable blur or else we will get a black background, as the shader
// will try to copy the bg to apply blur.
// this isn't entirely correct, but like, oh well.
// small todo: maybe make this correct? :P
2024-03-03 19:39:20 +01:00
static auto * const PBLUR = ( Hyprlang : : INT * const * ) ( g_pConfigManager - > getConfigValuePtr ( " decoration:blur:enabled " ) ) ;
2024-02-18 16:00:34 +01:00
const auto BLURVAL = * * PBLUR ;
* * PBLUR = 0 ;
2022-11-06 18:52:09 +01:00
// TODO: how can we make this the size of the window? setting it to window's size makes the entire screen render with the wrong res forever more. odd.
glViewport ( 0 , 0 , PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y ) ;
2023-11-04 23:25:09 +01:00
m_RenderData . currentFB = pFramebuffer ;
2022-12-16 18:17:31 +01:00
clear ( CColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
2022-11-06 18:52:09 +01:00
g_pHyprRenderer - > renderWindow ( pWindow , PMONITOR , & now , false , RENDER_PASS_ALL , true ) ;
2024-02-18 16:00:34 +01:00
* * PBLUR = BLURVAL ;
2022-11-06 18:52:09 +01:00
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > endRender ( ) ;
2022-11-06 18:52:09 +01:00
}
2024-04-27 13:43:12 +02:00
void CHyprOpenGLImpl : : makeWindowSnapshot ( PHLWINDOW pWindow ) {
2022-04-05 20:49:15 +02:00
// we trust the window is valid.
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2023-03-19 03:19:52 +01:00
2023-06-15 22:07:58 +02:00
if ( ! PMONITOR | | ! PMONITOR - > output | | PMONITOR - > vecPixelSize . x < = 0 | | PMONITOR - > vecPixelSize . y < = 0 )
2023-03-19 03:19:52 +01:00
return ;
2023-11-16 13:24:07 +01:00
if ( ! g_pHyprRenderer - > shouldRenderWindow ( pWindow ) )
return ; // ignore, window is not being rendered
2022-04-14 16:43:29 +02:00
// we need to "damage" the entire monitor
// so that we render the entire window
2024-07-21 13:09:54 +02:00
// this is temporary, doesnt mess with the actual damage
2024-04-27 13:43:12 +02:00
CRegion fakeDamage { 0 , 0 , ( int ) PMONITOR - > vecTransformedSize . x , ( int ) PMONITOR - > vecTransformedSize . y } ;
PHLWINDOWREF ref { pWindow } ;
2022-04-14 16:43:29 +02:00
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > makeEGLCurrent ( ) ;
2024-04-27 13:43:12 +02:00
const auto PFRAMEBUFFER = & m_mWindowFramebuffers [ ref ] ;
2023-11-30 02:18:55 +01:00
2024-07-21 13:09:54 +02:00
PFRAMEBUFFER - > alloc ( PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y , PMONITOR - > output - > state - > state ( ) . drmFormat ) ;
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , PFRAMEBUFFER ) ;
2022-04-14 16:43:29 +02:00
2022-12-28 15:39:17 +01:00
g_pHyprRenderer - > m_bRenderingSnapshot = true ;
2022-12-16 18:17:31 +01:00
clear ( CColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
2022-04-05 20:49:15 +02:00
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
2022-04-10 18:25:45 +02:00
// this is a hack but it works :P
// we need to disable blur or else we will get a black background, as the shader
// will try to copy the bg to apply blur.
// this isn't entirely correct, but like, oh well.
// small todo: maybe make this correct? :P
2024-03-03 19:39:20 +01:00
static auto * const PBLUR = ( Hyprlang : : INT * const * ) ( g_pConfigManager - > getConfigValuePtr ( " decoration:blur:enabled " ) ) ;
2024-02-18 16:00:34 +01:00
const auto BLURVAL = * * PBLUR ;
* * PBLUR = 0 ;
2022-04-10 18:25:45 +02:00
2022-12-16 18:17:31 +01:00
clear ( CColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
2022-05-19 20:16:08 +02:00
2022-08-30 19:40:19 +02:00
g_pHyprRenderer - > renderWindow ( pWindow , PMONITOR , & now , ! pWindow - > m_bX11DoesntWantBorders , RENDER_PASS_ALL ) ;
2024-02-18 16:00:34 +01:00
* * PBLUR = BLURVAL ;
2022-05-19 20:16:08 +02:00
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > endRender ( ) ;
2022-04-05 20:49:15 +02:00
2022-12-28 15:39:17 +01:00
g_pHyprRenderer - > m_bRenderingSnapshot = false ;
2022-04-05 20:49:15 +02:00
}
2024-04-30 03:41:27 +02:00
void CHyprOpenGLImpl : : makeLayerSnapshot ( PHLLS pLayer ) {
2022-05-14 17:23:46 +02:00
// we trust the window is valid.
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pLayer - > monitorID ) ;
2023-03-19 03:19:52 +01:00
2023-06-15 22:07:58 +02:00
if ( ! PMONITOR | | ! PMONITOR - > output | | PMONITOR - > vecPixelSize . x < = 0 | | PMONITOR - > vecPixelSize . y < = 0 )
2023-03-19 03:19:52 +01:00
return ;
2022-05-14 17:23:46 +02:00
// we need to "damage" the entire monitor
// so that we render the entire window
2024-07-21 13:09:54 +02:00
// this is temporary, doesnt mess with the actual damage
2023-11-30 03:19:17 +01:00
CRegion fakeDamage { 0 , 0 , ( int ) PMONITOR - > vecTransformedSize . x , ( int ) PMONITOR - > vecTransformedSize . y } ;
g_pHyprRenderer - > makeEGLCurrent ( ) ;
2022-12-28 15:39:17 +01:00
2022-05-14 17:23:46 +02:00
const auto PFRAMEBUFFER = & m_mLayerFramebuffers [ pLayer ] ;
2024-07-21 13:09:54 +02:00
PFRAMEBUFFER - > alloc ( PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y , PMONITOR - > output - > state - > state ( ) . drmFormat ) ;
2022-05-14 17:23:46 +02:00
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , PFRAMEBUFFER ) ;
2022-05-14 17:23:46 +02:00
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > m_bRenderingSnapshot = true ;
2023-11-04 23:25:09 +01:00
2022-12-16 18:17:31 +01:00
clear ( CColor ( 0 , 0 , 0 , 0 ) ) ; // JIC
2022-05-14 17:23:46 +02:00
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
2022-10-19 12:00:59 +02:00
const auto BLURLSSTATUS = pLayer - > forceBlur ;
2022-12-16 18:17:31 +01:00
pLayer - > forceBlur = false ;
2022-10-19 12:00:59 +02:00
2022-05-14 17:23:46 +02:00
// draw the layer
g_pHyprRenderer - > renderLayer ( pLayer , PMONITOR , & now ) ;
2022-10-19 12:00:59 +02:00
pLayer - > forceBlur = BLURLSSTATUS ;
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > endRender ( ) ;
2022-05-14 17:23:46 +02:00
2022-12-28 15:39:17 +01:00
g_pHyprRenderer - > m_bRenderingSnapshot = false ;
2022-05-14 17:23:46 +02:00
}
2024-04-27 13:43:12 +02:00
void CHyprOpenGLImpl : : renderSnapshot ( PHLWINDOW pWindow ) {
2022-04-10 14:32:18 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to render snapshot rect without begin()! " ) ;
2022-12-28 15:39:17 +01:00
2024-04-27 13:43:12 +02:00
static auto PDIMAROUND = CConfigValue < Hyprlang : : FLOAT > ( " decoration:dim_around " ) ;
2022-04-05 20:49:15 +02:00
2024-04-27 13:43:12 +02:00
PHLWINDOWREF ref { pWindow } ;
2022-04-05 20:49:15 +02:00
2024-04-27 13:43:12 +02:00
if ( ! m_mWindowFramebuffers . contains ( ref ) )
2022-04-05 20:49:15 +02:00
return ;
2024-04-27 13:43:12 +02:00
const auto FBDATA = & m_mWindowFramebuffers . at ( ref ) ;
2024-06-08 10:07:59 +02:00
if ( ! FBDATA - > m_cTex - > m_iTexID )
2024-04-27 13:43:12 +02:00
return ;
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2022-04-05 20:49:15 +02:00
2023-11-04 18:03:05 +01:00
CBox windowBox ;
2022-05-28 18:28:55 +02:00
// some mafs to figure out the correct box
2022-06-30 20:02:04 +02:00
// the originalClosedPos is relative to the monitor's pos
2024-04-27 13:43:12 +02:00
Vector2D scaleXY = Vector2D ( ( PMONITOR - > scale * pWindow - > m_vRealSize . value ( ) . x / ( pWindow - > m_vOriginalClosedSize . x * PMONITOR - > scale ) ) ,
( PMONITOR - > scale * pWindow - > m_vRealSize . value ( ) . y / ( pWindow - > m_vOriginalClosedSize . y * PMONITOR - > scale ) ) ) ;
2022-05-28 18:28:55 +02:00
2022-12-16 18:17:31 +01:00
windowBox . width = PMONITOR - > vecTransformedSize . x * scaleXY . x ;
2022-07-20 16:28:05 +02:00
windowBox . height = PMONITOR - > vecTransformedSize . y * scaleXY . y ;
2024-04-27 13:43:12 +02:00
windowBox . x = ( ( pWindow - > m_vRealPosition . value ( ) . x - PMONITOR - > vecPosition . x ) * PMONITOR - > scale ) - ( ( pWindow - > m_vOriginalClosedPos . x * PMONITOR - > scale ) * scaleXY . x ) ;
windowBox . y = ( ( pWindow - > m_vRealPosition . value ( ) . y - PMONITOR - > vecPosition . y ) * PMONITOR - > scale ) - ( ( pWindow - > m_vOriginalClosedPos . y * PMONITOR - > scale ) * scaleXY . y ) ;
2022-04-05 20:49:15 +02:00
2023-07-19 20:09:49 +02:00
CRegion fakeDamage { 0 , 0 , PMONITOR - > vecTransformedSize . x , PMONITOR - > vecTransformedSize . y } ;
2022-05-10 09:56:58 +02:00
2024-07-11 16:10:42 +02:00
if ( * PDIMAROUND & & pWindow - > m_sWindowData . dimAround . valueOrDefault ( ) ) {
2023-11-04 18:03:05 +01:00
CBox monbox = { 0 , 0 , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecPixelSize . x , g_pHyprOpenGL - > m_RenderData . pMonitor - > vecPixelSize . y } ;
2024-04-27 13:43:12 +02:00
g_pHyprOpenGL - > renderRect ( & monbox , CColor ( 0 , 0 , 0 , * PDIMAROUND * pWindow - > m_fAlpha . value ( ) ) ) ;
2022-12-29 12:19:11 +01:00
g_pHyprRenderer - > damageMonitor ( PMONITOR ) ;
2022-12-28 15:39:17 +01:00
}
2022-08-30 19:40:19 +02:00
m_bEndFrame = true ;
2024-04-27 13:43:12 +02:00
renderTextureInternalWithDamage ( FBDATA - > m_cTex , & windowBox , pWindow - > m_fAlpha . value ( ) , & fakeDamage , 0 ) ;
2022-05-10 09:56:58 +02:00
2022-08-30 19:40:19 +02:00
m_bEndFrame = false ;
2022-04-10 14:32:18 +02:00
}
2024-04-30 03:41:27 +02:00
void CHyprOpenGLImpl : : renderSnapshot ( PHLLS pLayer ) {
2022-05-14 17:23:46 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to render snapshot rect without begin()! " ) ;
2024-04-30 03:41:27 +02:00
if ( ! m_mLayerFramebuffers . contains ( pLayer ) )
return ;
2022-05-14 17:23:46 +02:00
2024-04-30 03:41:27 +02:00
const auto FBDATA = & m_mLayerFramebuffers . at ( pLayer ) ;
2024-06-08 10:07:59 +02:00
if ( ! FBDATA - > m_cTex - > m_iTexID )
2022-05-14 17:23:46 +02:00
return ;
2024-04-30 03:41:27 +02:00
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pLayer - > monitorID ) ;
2022-05-14 17:23:46 +02:00
2024-02-28 16:00:34 +01:00
CBox layerBox ;
// some mafs to figure out the correct box
// the originalClosedPos is relative to the monitor's pos
2024-04-30 03:41:27 +02:00
Vector2D scaleXY = Vector2D ( ( PMONITOR - > scale * pLayer - > realSize . value ( ) . x / ( pLayer - > geometry . w * PMONITOR - > scale ) ) ,
( PMONITOR - > scale * pLayer - > realSize . value ( ) . y / ( pLayer - > geometry . h * PMONITOR - > scale ) ) ) ;
2022-05-14 17:23:46 +02:00
2024-02-28 16:00:34 +01:00
layerBox . width = PMONITOR - > vecTransformedSize . x * scaleXY . x ;
layerBox . height = PMONITOR - > vecTransformedSize . y * scaleXY . y ;
2024-04-30 03:41:27 +02:00
layerBox . x = ( ( pLayer - > realPosition . value ( ) . x - PMONITOR - > vecPosition . x ) * PMONITOR - > scale ) - ( ( ( pLayer - > geometry . x - PMONITOR - > vecPosition . x ) * PMONITOR - > scale ) * scaleXY . x ) ;
layerBox . y = ( ( pLayer - > realPosition . value ( ) . y - PMONITOR - > vecPosition . y ) * PMONITOR - > scale ) - ( ( ( pLayer - > geometry . y - PMONITOR - > vecPosition . y ) * PMONITOR - > scale ) * scaleXY . y ) ;
2024-02-28 16:00:34 +01:00
CRegion fakeDamage { 0 , 0 , PMONITOR - > vecTransformedSize . x , PMONITOR - > vecTransformedSize . y } ;
2022-05-14 17:23:46 +02:00
2022-08-22 13:36:00 +02:00
m_bEndFrame = true ;
2024-04-30 03:41:27 +02:00
renderTextureInternalWithDamage ( FBDATA - > m_cTex , & layerBox , pLayer - > alpha . value ( ) , & fakeDamage , 0 ) ;
2022-08-22 13:36:00 +02:00
m_bEndFrame = false ;
2022-05-14 17:23:46 +02:00
}
2023-11-09 23:11:42 +01:00
void CHyprOpenGLImpl : : renderRoundedShadow ( CBox * box , int round , int range , const CColor & color , float a ) {
2022-06-25 20:28:40 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to render shadow without begin()! " ) ;
RASSERT ( ( box - > width > 0 & & box - > height > 0 ) , " Tried to render shadow with width/height < 0! " ) ;
2024-04-27 13:43:12 +02:00
RASSERT ( m_pCurrentWindow . lock ( ) , " Tried to render shadow without a window! " ) ;
2022-06-25 20:28:40 +02:00
2023-07-19 20:09:49 +02:00
if ( m_RenderData . damage . empty ( ) )
2022-12-16 18:17:31 +01:00
return ;
2022-10-08 00:40:05 +02:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderShadow " ) ;
2023-11-04 18:03:05 +01:00
CBox newBox = * box ;
2024-01-07 18:35:44 +01:00
m_RenderData . renderModif . applyToBox ( newBox ) ;
2023-04-12 13:41:23 +02:00
box = & newBox ;
2024-03-03 19:39:20 +01:00
static auto PSHADOWPOWER = CConfigValue < Hyprlang : : INT > ( " decoration:shadow_render_power " ) ;
2022-06-25 20:28:40 +02:00
2024-03-03 19:39:20 +01:00
const auto SHADOWPOWER = std : : clamp ( ( int ) * PSHADOWPOWER , 1 , 4 ) ;
2022-06-25 20:28:40 +02:00
2024-03-03 19:39:20 +01:00
const auto col = color ;
2022-06-25 20:28:40 +02:00
2024-03-03 19:39:20 +01:00
float matrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
projectBox ( matrix , newBox , wlTransformToHyprutils ( invertTransform ( ! m_bEndFrame ? WL_OUTPUT_TRANSFORM_NORMAL : m_RenderData . pMonitor - > transform ) ) , newBox . rot ,
m_RenderData . monitorProjection . data ( ) ) ;
2022-06-25 20:28:40 +02:00
float glMatrix [ 9 ] ;
2024-07-21 13:09:54 +02:00
matrixMultiply ( glMatrix , m_RenderData . projection , matrix ) ;
2022-06-25 20:28:40 +02:00
glEnable ( GL_BLEND ) ;
2022-08-11 20:29:21 +02:00
glUseProgram ( m_RenderData . pCurrentMonData - > m_shSHADOW . program ) ;
2022-06-25 20:28:40 +02:00
2022-10-22 22:10:40 +02:00
# ifndef GLES2
2022-10-10 01:32:04 +02:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shSHADOW . proj , 1 , GL_TRUE , glMatrix ) ;
2022-10-22 22:10:40 +02:00
# else
2024-07-21 13:09:54 +02:00
matrixTranspose ( glMatrix , glMatrix ) ;
2022-10-22 22:10:40 +02:00
glUniformMatrix3fv ( m_RenderData . pCurrentMonData - > m_shSHADOW . proj , 1 , GL_FALSE , glMatrix ) ;
# endif
2023-01-05 19:25:45 +01:00
glUniform4f ( m_RenderData . pCurrentMonData - > m_shSHADOW . color , col . r , col . g , col . b , col . a * a ) ;
2022-06-25 20:28:40 +02:00
2022-12-16 18:17:31 +01:00
const auto TOPLEFT = Vector2D ( range + round , range + round ) ;
2022-06-25 20:28:40 +02:00
const auto BOTTOMRIGHT = Vector2D ( box - > width - ( range + round ) , box - > height - ( range + round ) ) ;
2022-12-16 18:17:31 +01:00
const auto FULLSIZE = Vector2D ( box - > width , box - > height ) ;
2022-06-25 20:28:40 +02:00
// Rounded corners
2022-08-11 20:29:21 +02:00
glUniform2f ( m_RenderData . pCurrentMonData - > m_shSHADOW . topLeft , ( float ) TOPLEFT . x , ( float ) TOPLEFT . y ) ;
glUniform2f ( m_RenderData . pCurrentMonData - > m_shSHADOW . bottomRight , ( float ) BOTTOMRIGHT . x , ( float ) BOTTOMRIGHT . y ) ;
glUniform2f ( m_RenderData . pCurrentMonData - > m_shSHADOW . fullSize , ( float ) FULLSIZE . x , ( float ) FULLSIZE . y ) ;
glUniform1f ( m_RenderData . pCurrentMonData - > m_shSHADOW . radius , range + round ) ;
glUniform1f ( m_RenderData . pCurrentMonData - > m_shSHADOW . range , range ) ;
glUniform1f ( m_RenderData . pCurrentMonData - > m_shSHADOW . shadowPower , SHADOWPOWER ) ;
2022-06-25 20:28:40 +02:00
2022-08-11 20:29:21 +02:00
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shSHADOW . posAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
glVertexAttribPointer ( m_RenderData . pCurrentMonData - > m_shSHADOW . texAttrib , 2 , GL_FLOAT , GL_FALSE , 0 , fullVerts ) ;
2022-06-25 20:28:40 +02:00
2022-08-11 20:29:21 +02:00
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shSHADOW . posAttrib ) ;
glEnableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shSHADOW . texAttrib ) ;
2022-06-25 20:28:40 +02:00
2022-10-07 11:35:17 +02:00
if ( m_RenderData . clipBox . width ! = 0 & & m_RenderData . clipBox . height ! = 0 ) {
2023-07-19 20:09:49 +02:00
CRegion damageClip { m_RenderData . clipBox . x , m_RenderData . clipBox . y , m_RenderData . clipBox . width , m_RenderData . clipBox . height } ;
damageClip . intersect ( m_RenderData . damage ) ;
2022-10-07 11:35:17 +02:00
2023-07-19 20:09:49 +02:00
if ( ! damageClip . empty ( ) ) {
for ( auto & RECT : damageClip . getRects ( ) ) {
2022-10-07 11:35:17 +02:00
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
}
} else {
2023-07-19 20:09:49 +02:00
for ( auto & RECT : m_RenderData . damage . getRects ( ) ) {
2022-12-16 18:17:31 +01:00
scissor ( & RECT ) ;
glDrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ;
}
2022-06-25 20:28:40 +02:00
}
2022-08-11 20:29:21 +02:00
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shSHADOW . posAttrib ) ;
glDisableVertexAttribArray ( m_RenderData . pCurrentMonData - > m_shSHADOW . texAttrib ) ;
2022-06-25 20:28:40 +02:00
}
2024-04-24 17:29:41 +02:00
void CHyprOpenGLImpl : : saveBufferForMirror ( CBox * box ) {
2023-07-19 21:04:45 +02:00
if ( ! m_RenderData . pCurrentMonData - > monitorMirrorFB . isAllocated ( ) )
2024-07-21 13:09:54 +02:00
m_RenderData . pCurrentMonData - > monitorMirrorFB . alloc ( m_RenderData . pMonitor - > vecPixelSize . x , m_RenderData . pMonitor - > vecPixelSize . y ,
m_RenderData . pMonitor - > output - > state - > state ( ) . drmFormat ) ;
2023-07-19 21:04:45 +02:00
2022-09-13 15:25:42 +02:00
m_RenderData . pCurrentMonData - > monitorMirrorFB . bind ( ) ;
2023-07-20 13:49:28 +02:00
blend ( false ) ;
2024-04-24 17:29:41 +02:00
renderTexture ( m_RenderData . currentFB - > m_cTex , box , 1.f , 0 , false , false ) ;
2022-09-13 15:25:42 +02:00
2023-07-20 13:49:28 +02:00
blend ( true ) ;
2023-11-24 11:54:21 +01:00
m_RenderData . currentFB - > bind ( ) ;
2022-09-13 15:25:42 +02:00
}
void CHyprOpenGLImpl : : renderMirrored ( ) {
2024-04-24 17:29:41 +02:00
auto monitor = m_RenderData . pMonitor ;
auto mirrored = monitor - > pMirrorOf ;
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 } ;
// transform box as it will be drawn on a transformed projection
2024-06-19 16:20:06 +02:00
monbox . transform ( wlTransformToHyprutils ( mirrored - > transform ) , mirrored - > vecTransformedSize . x * scale , mirrored - > vecTransformedSize . y * scale ) ;
2024-04-24 17:29:41 +02:00
monbox . x = ( monitor - > vecTransformedSize . x - monbox . w ) / 2 ;
monbox . y = ( monitor - > vecTransformedSize . y - monbox . h ) / 2 ;
2022-09-13 15:25:42 +02:00
2024-04-24 17:29:41 +02:00
const auto PFB = & m_mMonitorRenderResources [ mirrored ] . monitorMirrorFB ;
2024-06-08 10:07:59 +02:00
if ( ! PFB - > isAllocated ( ) | | PFB - > m_cTex - > m_iTexID < = 0 )
2022-09-13 15:25:42 +02:00
return ;
2024-04-24 17:29:41 +02:00
// replace monitor projection to undo the mirrored monitor's projection
2024-07-21 13:09:54 +02:00
matrixIdentity ( m_RenderData . monitorProjection . data ( ) ) ;
matrixTranslate ( m_RenderData . monitorProjection . data ( ) , monitor - > vecPixelSize . x / 2.0 , monitor - > vecPixelSize . y / 2.0 ) ;
matrixTransform ( m_RenderData . monitorProjection . data ( ) , wlTransformToHyprutils ( monitor - > transform ) ) ;
matrixTransform ( m_RenderData . monitorProjection . data ( ) , wlTransformToHyprutils ( invertTransform ( mirrored - > transform ) ) ) ;
matrixTranslate ( m_RenderData . monitorProjection . data ( ) , - monitor - > vecTransformedSize . x / 2.0 , - monitor - > vecTransformedSize . y / 2.0 ) ;
2024-04-24 17:29:41 +02:00
// clear stuff outside of mirrored area (e.g. when changing to mirrored)
clear ( CColor ( 0 , 0 , 0 , 0 ) ) ;
2023-01-05 19:25:45 +01:00
renderTexture ( PFB - > m_cTex , & monbox , 1.f , 0 , false , false ) ;
2024-04-24 17:29:41 +02:00
// reset matrix for further drawing
2024-07-21 13:09:54 +02:00
m_RenderData . monitorProjection = monitor - > projMatrix ;
2022-09-13 15:25:42 +02:00
}
2024-01-30 00:11:00 +01:00
void CHyprOpenGLImpl : : renderSplash ( cairo_t * const CAIRO , cairo_surface_t * const CAIROSURFACE , double offsetY , const Vector2D & size ) {
2024-05-22 10:09:36 +02:00
static auto PSPLASHCOLOR = CConfigValue < Hyprlang : : INT > ( " misc:col.splash " ) ;
static auto PSPLASHFONT = CConfigValue < std : : string > ( " misc:splash_font_family " ) ;
static auto FALLBACKFONT = CConfigValue < std : : string > ( " misc:font_family " ) ;
2024-02-21 19:31:29 +01:00
2024-05-22 10:09:36 +02:00
const auto FONTFAMILY = * PSPLASHFONT ! = STRVAL_EMPTY ? * PSPLASHFONT : * FALLBACKFONT ;
const auto FONTSIZE = ( int ) ( size . y / 76 ) ;
const auto COLOR = CColor ( * PSPLASHCOLOR ) ;
2022-07-10 15:41:26 +02:00
2024-05-22 10:09:36 +02:00
PangoLayout * layoutText = pango_cairo_create_layout ( CAIRO ) ;
PangoFontDescription * pangoFD = pango_font_description_new ( ) ;
2022-07-10 15:41:26 +02:00
2024-05-22 10:09:36 +02:00
pango_font_description_set_family_static ( pangoFD , FONTFAMILY . c_str ( ) ) ;
pango_font_description_set_absolute_size ( pangoFD , FONTSIZE * PANGO_SCALE ) ;
pango_font_description_set_style ( pangoFD , PANGO_STYLE_NORMAL ) ;
pango_font_description_set_weight ( pangoFD , PANGO_WEIGHT_NORMAL ) ;
pango_layout_set_font_description ( layoutText , pangoFD ) ;
2024-02-21 19:31:29 +01:00
cairo_set_source_rgba ( CAIRO , COLOR . r , COLOR . g , COLOR . b , COLOR . a ) ;
2022-07-10 15:41:26 +02:00
2024-05-22 10:09:36 +02:00
int textW = 0 , textH = 0 ;
pango_layout_set_text ( layoutText , g_pCompositor - > m_szCurrentSplash . c_str ( ) , - 1 ) ;
pango_layout_get_size ( layoutText , & textW , & textH ) ;
textW / = PANGO_SCALE ;
textH / = PANGO_SCALE ;
2022-07-10 15:41:26 +02:00
2024-07-26 19:53:24 +02:00
cairo_move_to ( CAIRO , ( size . x - textW ) / 2.0 , size . y - textH - offsetY ) ;
2024-05-22 10:09:36 +02:00
pango_cairo_show_layout ( CAIRO , layoutText ) ;
2022-09-29 04:01:26 +02:00
2024-05-22 10:09:36 +02:00
pango_font_description_free ( pangoFD ) ;
g_object_unref ( layoutText ) ;
2022-07-10 15:41:26 +02:00
cairo_surface_flush ( CAIROSURFACE ) ;
}
2024-07-26 19:53:24 +02:00
void CHyprOpenGLImpl : : createBackgroundTexture ( const std : : string & texPath ) {
const auto CAIROSURFACE = cairo_image_surface_create_from_png ( texPath . c_str ( ) ) ;
const auto CAIROFORMAT = cairo_image_surface_get_format ( CAIROSURFACE ) ;
m_pBackgroundTexture = makeShared < CTexture > ( ) ;
m_pBackgroundTexture - > allocate ( ) ;
m_pBackgroundTexture - > m_vSize = { cairo_image_surface_get_width ( CAIROSURFACE ) , cairo_image_surface_get_height ( CAIROSURFACE ) } ;
const GLint glIFormat = CAIROFORMAT = = CAIRO_FORMAT_RGB96F ?
# ifdef GLES2
GL_RGB32F_EXT :
# else
GL_RGB32F :
# endif
GL_RGBA ;
const GLint glFormat = CAIROFORMAT = = CAIRO_FORMAT_RGB96F ? GL_RGB : GL_RGBA ;
const GLint glType = CAIROFORMAT = = CAIRO_FORMAT_RGB96F ? GL_FLOAT : GL_UNSIGNED_BYTE ;
const auto DATA = cairo_image_surface_get_data ( CAIROSURFACE ) ;
glBindTexture ( GL_TEXTURE_2D , m_pBackgroundTexture - > m_iTexID ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
# ifndef GLES2
if ( CAIROFORMAT ! = CAIRO_FORMAT_RGB96F ) {
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_R , GL_BLUE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_B , GL_RED ) ;
}
# endif
glTexImage2D ( GL_TEXTURE_2D , 0 , glIFormat , m_pBackgroundTexture - > m_vSize . x , m_pBackgroundTexture - > m_vSize . y , 0 , glFormat , glType , DATA ) ;
2024-07-27 13:03:43 +02:00
cairo_surface_destroy ( CAIROSURFACE ) ;
2024-07-26 19:53:24 +02:00
}
2022-07-27 12:32:00 +02:00
void CHyprOpenGLImpl : : createBGTextureForMonitor ( CMonitor * pMonitor ) {
2022-04-10 14:32:18 +02:00
RASSERT ( m_RenderData . pMonitor , " Tried to createBGTex without begin()! " ) ;
2024-07-26 19:53:24 +02:00
Debug : : log ( LOG , " Creating a texture for BGTex " ) ;
2023-07-13 14:32:30 +02:00
2024-07-26 19:53:24 +02:00
static auto PRENDERTEX = CConfigValue < Hyprlang : : INT > ( " misc:disable_hyprland_logo " ) ;
static auto PNOSPLASH = CConfigValue < Hyprlang : : INT > ( " misc:disable_splash_rendering " ) ;
static auto PFORCEWALLPAPER = CConfigValue < Hyprlang : : INT > ( " misc:force_default_wallpaper " ) ;
2022-07-10 15:41:26 +02:00
2024-07-26 19:53:24 +02:00
const auto FORCEWALLPAPER = std : : clamp ( * PFORCEWALLPAPER , static_cast < int64_t > ( - 1L ) , static_cast < int64_t > ( 2L ) ) ;
2024-01-30 00:11:00 +01:00
2024-03-03 19:39:20 +01:00
if ( * PRENDERTEX )
2023-12-10 17:53:08 +01:00
return ;
2022-04-10 14:32:18 +02:00
// release the last tex if exists
2024-01-30 00:11:00 +01:00
const auto PFB = & m_mMonitorBGFBs [ pMonitor ] ;
PFB - > release ( ) ;
2022-04-10 14:32:18 +02:00
2024-07-21 13:09:54 +02:00
PFB - > alloc ( pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y , pMonitor - > output - > state - > state ( ) . drmFormat ) ;
2022-04-12 21:49:35 +02:00
2024-07-26 19:53:24 +02:00
if ( ! m_pBackgroundTexture ) {
// TODO: use relative paths to the installation
// or configure the paths at build time
std : : string texPath = " " ;
texPath = " /usr/share/hyprland/wall " ;
2024-01-30 00:11:00 +01:00
// get the adequate tex
if ( FORCEWALLPAPER = = - 1 ) {
std : : mt19937_64 engine ( time ( nullptr ) ) ;
std : : uniform_int_distribution < > distribution ( 0 , 2 ) ;
texPath + = std : : to_string ( distribution ( engine ) ) ;
} else
2024-03-03 19:39:20 +01:00
texPath + = std : : to_string ( std : : clamp ( * PFORCEWALLPAPER , ( int64_t ) 0 , ( int64_t ) 2 ) ) ;
2024-01-30 00:11:00 +01:00
texPath + = " .png " ;
2022-04-10 14:32:18 +02:00
2024-01-30 00:11:00 +01:00
// check if wallpapers exist
if ( ! std : : filesystem : : exists ( texPath ) ) {
// try local
texPath = texPath . substr ( 0 , 5 ) + " local/ " + texPath . substr ( 5 ) ;
2023-07-13 14:32:30 +02:00
2024-01-30 00:11:00 +01:00
if ( ! std : : filesystem : : exists ( texPath ) )
return ; // the texture will be empty, oh well. We'll clear with a solid color anyways.
}
2024-07-26 19:53:24 +02:00
createBackgroundTexture ( texPath ) ;
2023-07-13 14:32:30 +02:00
}
2024-01-30 00:11:00 +01:00
// create a new one with cairo
2024-06-08 10:07:59 +02:00
SP < CTexture > tex = makeShared < CTexture > ( ) ;
2024-01-30 00:11:00 +01:00
2024-06-08 10:07:59 +02:00
tex - > allocate ( ) ;
2022-09-29 04:01:26 +02:00
2024-07-26 19:53:24 +02:00
const auto CAIROSURFACE = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32 , pMonitor - > vecPixelSize . x , pMonitor - > vecPixelSize . y ) ;
const auto CAIRO = cairo_create ( CAIROSURFACE ) ;
2022-09-29 04:01:26 +02:00
2024-02-02 16:36:13 +01:00
cairo_set_antialias ( CAIRO , CAIRO_ANTIALIAS_GOOD ) ;
2024-07-26 19:53:24 +02:00
cairo_save ( CAIRO ) ;
cairo_set_source_rgba ( CAIRO , 0 , 0 , 0 , 0 ) ;
cairo_set_operator ( CAIRO , CAIRO_OPERATOR_SOURCE ) ;
2024-01-30 00:11:00 +01:00
cairo_paint ( CAIRO ) ;
2024-07-26 19:53:24 +02:00
cairo_restore ( CAIRO ) ;
2022-09-26 06:35:00 +02:00
2024-03-03 19:39:20 +01:00
if ( ! * PNOSPLASH )
2024-07-26 19:53:24 +02:00
renderSplash ( CAIRO , CAIROSURFACE , 0.02 * pMonitor - > vecPixelSize . y , pMonitor - > vecPixelSize ) ;
2024-01-30 00:11:00 +01:00
cairo_surface_flush ( CAIROSURFACE ) ;
2024-07-26 19:53:24 +02:00
tex - > m_vSize = pMonitor - > vecPixelSize ;
2022-07-10 15:41:26 +02:00
2022-04-10 14:32:18 +02:00
// copy the data to an OpenGL texture we have
2024-07-26 19:53:24 +02:00
const GLint glFormat = GL_RGBA ;
const GLint glType = GL_UNSIGNED_BYTE ;
2024-01-30 00:11:00 +01:00
const auto DATA = cairo_image_surface_get_data ( CAIROSURFACE ) ;
2024-06-08 10:07:59 +02:00
glBindTexture ( GL_TEXTURE_2D , tex - > m_iTexID ) ;
2022-08-13 22:33:51 +02:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
2022-12-16 18:17:31 +01:00
# ifndef GLES2
2024-07-26 19:53:24 +02:00
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_R , GL_BLUE ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_SWIZZLE_B , GL_RED ) ;
2022-12-16 18:17:31 +01:00
# endif
2024-07-26 19:53:24 +02:00
glTexImage2D ( GL_TEXTURE_2D , 0 , glFormat , tex - > m_vSize . x , tex - > m_vSize . y , 0 , glFormat , glType , DATA ) ;
2022-04-10 14:32:18 +02:00
cairo_surface_destroy ( CAIROSURFACE ) ;
cairo_destroy ( CAIRO ) ;
2022-04-12 21:49:35 +02:00
2024-01-30 00:11:00 +01:00
// render the texture to our fb
PFB - > bind ( ) ;
CRegion fakeDamage { 0 , 0 , INT16_MAX , INT16_MAX } ;
2024-07-26 19:53:24 +02:00
blend ( true ) ;
clear ( CColor { 0 , 0 , 0 , 1 } ) ;
// first render the background
if ( m_pBackgroundTexture ) {
const double MONRATIO = m_RenderData . pMonitor - > vecTransformedSize . x / m_RenderData . pMonitor - > vecTransformedSize . y ;
const double WPRATIO = m_pBackgroundTexture - > m_vSize . x / m_pBackgroundTexture - > m_vSize . y ;
Vector2D origin ;
double scale = 1.0 ;
if ( MONRATIO > WPRATIO ) {
scale = m_RenderData . pMonitor - > vecTransformedSize . x / m_pBackgroundTexture - > m_vSize . x ;
origin . y = ( m_RenderData . pMonitor - > vecTransformedSize . y - m_pBackgroundTexture - > m_vSize . y * scale ) / 2.0 ;
} else {
scale = m_RenderData . pMonitor - > vecTransformedSize . y / m_pBackgroundTexture - > m_vSize . y ;
origin . x = ( m_RenderData . pMonitor - > vecTransformedSize . x - m_pBackgroundTexture - > m_vSize . x * scale ) / 2.0 ;
}
CBox texbox = CBox { origin , m_pBackgroundTexture - > m_vSize * scale } ;
renderTextureInternalWithDamage ( m_pBackgroundTexture , & texbox , 1.0 , & fakeDamage ) ;
}
CBox monbox = { { } , pMonitor - > vecPixelSize } ;
renderTextureInternalWithDamage ( tex , & monbox , 1.0 , & fakeDamage ) ;
2024-01-30 00:11:00 +01:00
// bind back
if ( m_RenderData . currentFB )
m_RenderData . currentFB - > bind ( ) ;
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Background created for monitor {} " , pMonitor - > szName ) ;
2022-04-10 14:32:18 +02:00
}
void CHyprOpenGLImpl : : clearWithTex ( ) {
RASSERT ( m_RenderData . pMonitor , " Tried to render BGtex without begin()! " ) ;
2022-05-18 20:33:54 +02:00
2023-07-20 17:47:49 +02:00
TRACY_GPU_ZONE ( " RenderClearWithTex " ) ;
2022-04-10 14:32:18 +02:00
2024-01-30 00:11:00 +01:00
auto TEXIT = m_mMonitorBGFBs . find ( m_RenderData . pMonitor ) ;
2022-10-09 18:02:32 +02:00
2024-01-30 00:11:00 +01:00
if ( TEXIT = = m_mMonitorBGFBs . end ( ) ) {
2023-07-20 13:49:28 +02:00
createBGTextureForMonitor ( m_RenderData . pMonitor ) ;
2024-01-30 00:11:00 +01:00
TEXIT = m_mMonitorBGFBs . find ( m_RenderData . pMonitor ) ;
2022-07-07 20:16:40 +02:00
}
2023-07-20 13:49:28 +02:00
2024-01-30 00:11:00 +01:00
if ( TEXIT ! = m_mMonitorBGFBs . end ( ) ) {
CBox monbox = { 0 , 0 , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y } ;
m_bEndFrame = true ;
renderTexture ( TEXIT - > second . m_cTex , & monbox , 1 ) ;
m_bEndFrame = false ;
}
2022-04-19 19:01:23 +02:00
}
2022-07-27 12:32:00 +02:00
void CHyprOpenGLImpl : : destroyMonitorResources ( CMonitor * pMonitor ) {
2023-11-30 02:18:55 +01:00
g_pHyprRenderer - > makeEGLCurrent ( ) ;
2022-10-07 23:19:23 +02:00
2024-07-21 13:09:54 +02:00
if ( ! g_pHyprOpenGL )
return ;
2023-12-11 17:28:22 +01:00
auto RESIT = g_pHyprOpenGL - > m_mMonitorRenderResources . find ( pMonitor ) ;
if ( RESIT ! = g_pHyprOpenGL - > m_mMonitorRenderResources . end ( ) ) {
RESIT - > second . mirrorFB . release ( ) ;
RESIT - > second . offloadFB . release ( ) ;
RESIT - > second . mirrorSwapFB . release ( ) ;
RESIT - > second . monitorMirrorFB . release ( ) ;
RESIT - > second . blurFB . release ( ) ;
RESIT - > second . offMainFB . release ( ) ;
2024-06-08 10:07:59 +02:00
RESIT - > second . stencilTex - > destroyTexture ( ) ;
2023-12-11 17:28:22 +01:00
g_pHyprOpenGL - > m_mMonitorRenderResources . erase ( RESIT ) ;
}
2024-01-30 00:11:00 +01:00
auto TEXIT = g_pHyprOpenGL - > m_mMonitorBGFBs . find ( pMonitor ) ;
if ( TEXIT ! = g_pHyprOpenGL - > m_mMonitorBGFBs . end ( ) ) {
TEXIT - > second . release ( ) ;
g_pHyprOpenGL - > m_mMonitorBGFBs . erase ( TEXIT ) ;
2023-12-11 17:28:22 +01:00
}
2022-04-19 19:01:23 +02:00
2023-09-06 21:45:37 +02:00
Debug : : log ( LOG , " Monitor {} -> destroyed all render data " , pMonitor - > szName ) ;
2022-04-19 19:01:23 +02:00
}
2023-04-12 13:41:23 +02:00
void CHyprOpenGLImpl : : saveMatrix ( ) {
memcpy ( m_RenderData . savedProjection , m_RenderData . projection , 9 * sizeof ( float ) ) ;
}
void CHyprOpenGLImpl : : setMatrixScaleTranslate ( const Vector2D & translate , const float & scale ) {
2024-07-21 13:09:54 +02:00
matrixScale ( m_RenderData . projection , scale , scale ) ;
matrixTranslate ( m_RenderData . projection , translate . x , translate . y ) ;
2023-04-12 13:41:23 +02:00
}
void CHyprOpenGLImpl : : restoreMatrix ( ) {
memcpy ( m_RenderData . projection , m_RenderData . savedProjection , 9 * sizeof ( float ) ) ;
}
2023-10-21 15:15:48 +02:00
void CHyprOpenGLImpl : : bindOffMain ( ) {
m_RenderData . pCurrentMonData - > offMainFB . bind ( ) ;
clear ( CColor ( 0 , 0 , 0 , 0 ) ) ;
m_RenderData . currentFB = & m_RenderData . pCurrentMonData - > offMainFB ;
}
void CHyprOpenGLImpl : : renderOffToMain ( CFramebuffer * off ) {
2023-11-04 18:03:05 +01:00
CBox monbox = { 0 , 0 , m_RenderData . pMonitor - > vecTransformedSize . x , m_RenderData . pMonitor - > vecTransformedSize . y } ;
2023-10-21 15:15:48 +02:00
renderTexturePrimitive ( off - > m_cTex , & monbox ) ;
}
void CHyprOpenGLImpl : : bindBackOnMain ( ) {
2023-11-24 11:54:21 +01:00
m_RenderData . mainFB - > bind ( ) ;
m_RenderData . currentFB = m_RenderData . mainFB ;
2023-10-21 15:15:48 +02:00
}
2023-11-04 20:35:49 +01:00
void CHyprOpenGLImpl : : setMonitorTransformEnabled ( bool enabled ) {
2024-03-03 03:18:00 +01:00
m_bEndFrame = enabled ;
2023-11-04 20:35:49 +01:00
}
2023-12-01 18:20:56 +01:00
2024-04-03 15:09:58 +02:00
void CHyprOpenGLImpl : : setRenderModifEnabled ( bool enabled ) {
m_RenderData . renderModif . enabled = enabled ;
}
2023-12-01 18:20:56 +01:00
uint32_t CHyprOpenGLImpl : : getPreferredReadFormat ( CMonitor * pMonitor ) {
2024-07-21 13:09:54 +02:00
return pMonitor - > output - > state - > state ( ) . drmFormat ;
}
2023-12-03 23:04:07 +01:00
2024-07-21 13:09:54 +02:00
std : : vector < SDRMFormat > CHyprOpenGLImpl : : getDRMFormats ( ) {
return drmFormats ;
}
SP < CEGLSync > CHyprOpenGLImpl : : createEGLSync ( int fenceFD ) {
std : : vector < EGLint > attribs ;
int dupFd = - 1 ;
if ( fenceFD > 0 ) {
int dupFd = fcntl ( fenceFD , F_DUPFD_CLOEXEC , 0 ) ;
if ( dupFd < 0 ) {
Debug : : log ( ERR , " createEGLSync: dup failed " ) ;
return nullptr ;
}
2023-12-03 23:04:07 +01:00
2024-07-21 13:09:54 +02:00
attribs . push_back ( EGL_SYNC_NATIVE_FENCE_FD_ANDROID ) ;
attribs . push_back ( dupFd ) ;
attribs . push_back ( EGL_NONE ) ;
}
2023-12-03 23:04:07 +01:00
2024-07-21 13:09:54 +02:00
EGLSyncKHR sync = m_sProc . eglCreateSyncKHR ( m_pEglDisplay , EGL_SYNC_NATIVE_FENCE_ANDROID , attribs . data ( ) ) ;
if ( sync = = EGL_NO_SYNC_KHR ) {
Debug : : log ( ERR , " eglCreateSyncKHR failed " ) ;
if ( dupFd > = 0 )
close ( dupFd ) ;
return nullptr ;
}
2023-12-03 23:04:07 +01:00
2024-07-21 13:09:54 +02:00
auto eglsync = SP < CEGLSync > ( new CEGLSync ) ;
eglsync - > sync = sync ;
return eglsync ;
2023-12-01 18:20:56 +01:00
}
2023-12-04 04:52:54 +01:00
2024-07-21 13:09:54 +02:00
bool CHyprOpenGLImpl : : waitForTimelinePoint ( SP < CSyncTimeline > timeline , uint64_t point ) {
int fd = timeline - > exportAsSyncFileFD ( point ) ;
if ( fd < 0 ) {
Debug : : log ( ERR , " waitForTimelinePoint: failed to get a fd from explicit timeline " ) ;
return false ;
}
auto sync = g_pHyprOpenGL - > createEGLSync ( fd ) ;
close ( fd ) ;
if ( ! sync ) {
Debug : : log ( ERR , " waitForTimelinePoint: failed to get an eglsync from explicit timeline " ) ;
return false ;
}
if ( ! sync - > wait ( ) ) {
Debug : : log ( ERR , " waitForTimelinePoint: failed to wait on an eglsync from explicit timeline " ) ;
return false ;
}
return true ;
2024-01-07 18:35:44 +01:00
}
void SRenderModifData : : applyToBox ( CBox & box ) {
2024-04-03 15:09:58 +02:00
if ( ! enabled )
return ;
2024-01-07 18:35:44 +01:00
for ( auto & [ type , val ] : modifs ) {
try {
switch ( type ) {
case RMOD_TYPE_SCALE : box . scale ( std : : any_cast < float > ( val ) ) ; break ;
case RMOD_TYPE_SCALECENTER : box . scaleFromCenter ( std : : any_cast < float > ( val ) ) ; break ;
case RMOD_TYPE_TRANSLATE : box . translate ( std : : any_cast < Vector2D > ( val ) ) ; break ;
case RMOD_TYPE_ROTATE : box . rot + = std : : any_cast < float > ( val ) ; break ;
case RMOD_TYPE_ROTATECENTER : {
const auto THETA = std : : any_cast < float > ( val ) ;
const double COS = std : : cos ( THETA ) ;
const double SIN = std : : sin ( THETA ) ;
box . rot + = THETA ;
const auto OLDPOS = box . pos ( ) ;
box . x = OLDPOS . x * COS - OLDPOS . y * SIN ;
box . y = OLDPOS . y * COS + OLDPOS . x * SIN ;
}
}
} catch ( std : : bad_any_cast & e ) { Debug : : log ( ERR , " BUG THIS OR PLUGIN ERROR: caught a bad_any_cast in SRenderModifData::applyToBox! " ) ; }
}
}
2024-04-03 15:09:58 +02:00
void SRenderModifData : : applyToRegion ( CRegion & rg ) {
if ( ! enabled )
return ;
for ( auto & [ type , val ] : modifs ) {
try {
switch ( type ) {
case RMOD_TYPE_SCALE : rg . scale ( std : : any_cast < float > ( val ) ) ; break ;
case RMOD_TYPE_SCALECENTER : rg . scale ( std : : any_cast < float > ( val ) ) ; break ;
case RMOD_TYPE_TRANSLATE : rg . translate ( std : : any_cast < Vector2D > ( val ) ) ; break ;
case RMOD_TYPE_ROTATE : /* TODO */
case RMOD_TYPE_ROTATECENTER : break ;
}
} catch ( std : : bad_any_cast & e ) { Debug : : log ( ERR , " BUG THIS OR PLUGIN ERROR: caught a bad_any_cast in SRenderModifData::applyToRegion! " ) ; }
}
}
float SRenderModifData : : combinedScale ( ) {
if ( ! enabled )
return 1 ;
float scale = 1.f ;
for ( auto & [ type , val ] : modifs ) {
try {
switch ( type ) {
case RMOD_TYPE_SCALE : scale * = std : : any_cast < float > ( val ) ; break ;
case RMOD_TYPE_SCALECENTER :
case RMOD_TYPE_TRANSLATE :
case RMOD_TYPE_ROTATE :
case RMOD_TYPE_ROTATECENTER : break ;
}
} catch ( std : : bad_any_cast & e ) { Debug : : log ( ERR , " BUG THIS OR PLUGIN ERROR: caught a bad_any_cast in SRenderModifData::combinedScale! " ) ; }
}
return scale ;
}
2024-07-21 13:09:54 +02:00
CEGLSync : : ~ CEGLSync ( ) {
if ( sync = = EGL_NO_SYNC_KHR )
return ;
if ( g_pHyprOpenGL - > m_sProc . eglDestroySyncKHR ( g_pHyprOpenGL - > m_pEglDisplay , sync ) ! = EGL_TRUE )
Debug : : log ( ERR , " eglDestroySyncKHR failed " ) ;
}
int CEGLSync : : dupFenceFD ( ) {
if ( sync = = EGL_NO_SYNC_KHR )
return - 1 ;
int fd = g_pHyprOpenGL - > m_sProc . eglDupNativeFenceFDANDROID ( g_pHyprOpenGL - > m_pEglDisplay , sync ) ;
if ( fd = = EGL_NO_NATIVE_FENCE_FD_ANDROID ) {
Debug : : log ( ERR , " eglDupNativeFenceFDANDROID failed " ) ;
return - 1 ;
}
return fd ;
}
bool CEGLSync : : wait ( ) {
if ( sync = = EGL_NO_SYNC_KHR )
return false ;
if ( g_pHyprOpenGL - > m_sProc . eglWaitSyncKHR ( g_pHyprOpenGL - > m_pEglDisplay , sync , 0 ) ! = EGL_TRUE ) {
Debug : : log ( ERR , " eglWaitSyncKHR failed " ) ;
return false ;
}
return true ;
}