2014-11-05 00:46:40 +00:00
# include <base/detect.h>
2021-04-30 22:42:37 +00:00
# ifndef CONF_BACKEND_OPENGL_ES
2018-02-12 22:14:14 +00:00
# include <GL/glew.h>
2021-04-30 22:42:37 +00:00
# endif
2022-05-29 13:51:38 +00:00
# include <SDL.h>
2022-12-09 15:16:16 +00:00
# include <SDL_messagebox.h>
2021-04-30 22:42:37 +00:00
2016-04-29 22:34:12 +00:00
# include <base/math.h>
2022-02-14 23:22:52 +00:00
# include <cstdlib>
2012-01-03 20:39:10 +00:00
2014-10-28 00:12:11 +00:00
# include <engine/shared/config.h>
2022-12-09 15:16:16 +00:00
# include <engine/shared/localization.h>
2016-08-30 23:39:59 +00:00
2012-02-05 12:22:39 +00:00
# include <base/tl/threading.h>
2016-08-27 19:10:27 +00:00
# if defined(CONF_VIDEORECORDER)
2022-06-16 17:50:46 +00:00
# include <engine/shared/video.h>
2016-08-27 19:10:27 +00:00
# endif
2012-01-03 20:39:10 +00:00
# include "backend_sdl.h"
2022-06-16 17:50:46 +00:00
# if defined(CONF_HEADLESS_CLIENT)
2022-04-16 10:29:10 +00:00
# include "backend/null/backend_null.h"
2022-06-16 17:50:46 +00:00
# endif
2022-04-16 10:29:10 +00:00
2021-05-02 00:52:13 +00:00
# if !defined(CONF_BACKEND_OPENGL_ES)
# include "backend/opengl/backend_opengl3.h"
# endif
# if defined(CONF_BACKEND_OPENGL_ES3) || defined(CONF_BACKEND_OPENGL_ES)
# include "backend/opengles/backend_opengles3.h"
# endif
2022-03-20 17:03:25 +00:00
# if defined(CONF_BACKEND_VULKAN)
# include "backend/vulkan/backend_vulkan.h"
# endif
2021-05-02 00:52:13 +00:00
# include "graphics_threaded.h"
2017-09-02 13:24:07 +00:00
2021-08-21 19:41:51 +00:00
# include <engine/graphics.h>
2022-06-16 17:50:46 +00:00
class IStorage ;
2012-01-03 20:39:10 +00:00
// ------------ CGraphicsBackend_Threaded
2022-01-21 22:50:17 +00:00
void CGraphicsBackend_Threaded : : ThreadFunc ( void * pUser )
2012-01-03 20:39:10 +00:00
{
2022-01-21 22:50:17 +00:00
auto * pSelf = ( CGraphicsBackend_Threaded * ) pUser ;
std : : unique_lock < std : : mutex > Lock ( pSelf - > m_BufferSwapMutex ) ;
2021-10-27 22:52:06 +00:00
// notify, that the thread started
2022-02-15 15:27:53 +00:00
pSelf - > m_Started = true ;
2022-03-20 17:04:00 +00:00
pSelf - > m_BufferSwapCond . notify_all ( ) ;
2022-01-21 22:50:17 +00:00
while ( ! pSelf - > m_Shutdown )
2012-01-03 20:39:10 +00:00
{
2022-03-20 17:04:00 +00:00
pSelf - > m_BufferSwapCond . wait ( Lock , [ & pSelf ] { return pSelf - > m_pBuffer ! = nullptr | | pSelf - > m_Shutdown ; } ) ;
2022-01-21 22:50:17 +00:00
if ( pSelf - > m_pBuffer )
2012-01-03 20:39:10 +00:00
{
2021-02-12 12:40:29 +00:00
# ifdef CONF_PLATFORM_MACOS
2020-09-26 19:41:58 +00:00
CAutoreleasePool AutoreleasePool ;
# endif
2022-01-21 22:50:17 +00:00
pSelf - > m_pProcessor - > RunBuffer ( pSelf - > m_pBuffer ) ;
2016-08-30 23:39:59 +00:00
2022-01-21 22:50:17 +00:00
pSelf - > m_pBuffer = nullptr ;
pSelf - > m_BufferInProcess . store ( false , std : : memory_order_relaxed ) ;
2022-03-20 17:04:00 +00:00
pSelf - > m_BufferSwapCond . notify_all ( ) ;
2022-02-15 15:27:53 +00:00
2020-09-26 19:41:58 +00:00
# if defined(CONF_VIDEORECORDER)
2022-02-15 15:27:53 +00:00
if ( IVideo : : Current ( ) )
IVideo : : Current ( ) - > NextVideoFrameThread ( ) ;
2020-09-26 19:41:58 +00:00
# endif
2022-02-15 15:27:53 +00:00
}
2012-01-03 20:39:10 +00:00
}
}
2022-12-09 15:16:16 +00:00
CGraphicsBackend_Threaded : : CGraphicsBackend_Threaded ( TTranslateFunc & & TranslateFunc ) :
m_TranslateFunc ( std : : move ( TranslateFunc ) )
2012-01-03 20:39:10 +00:00
{
2021-10-27 22:52:06 +00:00
m_pBuffer = nullptr ;
m_pProcessor = nullptr ;
2022-03-21 15:38:12 +00:00
m_Shutdown = true ;
2021-10-27 22:52:06 +00:00
m_BufferInProcess . store ( false , std : : memory_order_relaxed ) ;
2012-01-03 20:39:10 +00:00
}
void CGraphicsBackend_Threaded : : StartProcessor ( ICommandProcessor * pProcessor )
{
2022-03-20 17:04:00 +00:00
dbg_assert ( m_Shutdown , " Processor was already not shut down. " ) ;
2012-01-03 20:39:10 +00:00
m_Shutdown = false ;
m_pProcessor = pProcessor ;
2021-10-27 22:52:06 +00:00
std : : unique_lock < std : : mutex > Lock ( m_BufferSwapMutex ) ;
2022-03-24 18:30:26 +00:00
m_pThread = thread_init ( ThreadFunc , this , " Graphics thread " ) ;
2021-10-27 22:52:06 +00:00
// wait for the thread to start
2022-03-20 17:04:00 +00:00
m_BufferSwapCond . wait ( Lock , [ this ] ( ) - > bool { return m_Started ; } ) ;
2012-01-03 20:39:10 +00:00
}
void CGraphicsBackend_Threaded : : StopProcessor ( )
{
2022-03-20 17:04:00 +00:00
dbg_assert ( ! m_Shutdown , " Processor was already shut down. " ) ;
2012-01-03 20:39:10 +00:00
m_Shutdown = true ;
2021-10-27 22:52:06 +00:00
{
std : : unique_lock < std : : mutex > Lock ( m_BufferSwapMutex ) ;
2022-12-09 15:16:16 +00:00
m_Warning = m_pProcessor - > GetWarning ( ) ;
2021-10-27 22:52:06 +00:00
m_BufferSwapCond . notify_all ( ) ;
}
2022-03-24 18:30:26 +00:00
thread_wait ( m_pThread ) ;
2012-01-03 20:39:10 +00:00
}
void CGraphicsBackend_Threaded : : RunBuffer ( CCommandBuffer * pBuffer )
{
2022-03-25 08:26:37 +00:00
# ifdef CONF_WEBASM
// run everything single threaded for now, context binding in a thread seems to not work as of now
2022-12-09 15:16:16 +00:00
if ( ! m_pProcessor - > HasError ( ) )
{
RunBufferSingleThreadedUnsafe ( pBuffer ) ;
}
else
{
ProcessError ( ) ;
}
2022-03-25 08:26:37 +00:00
# else
2012-01-03 20:39:10 +00:00
WaitForIdle ( ) ;
2021-10-27 22:52:06 +00:00
std : : unique_lock < std : : mutex > Lock ( m_BufferSwapMutex ) ;
2022-12-09 15:16:16 +00:00
if ( ! m_pProcessor - > HasError ( ) )
{
m_pBuffer = pBuffer ;
m_BufferInProcess . store ( true , std : : memory_order_relaxed ) ;
m_BufferSwapCond . notify_all ( ) ;
}
else
{
ProcessError ( ) ;
}
2022-03-25 08:26:37 +00:00
# endif
2012-01-03 20:39:10 +00:00
}
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_Threaded : : RunBufferSingleThreadedUnsafe ( CCommandBuffer * pBuffer )
{
m_pProcessor - > RunBuffer ( pBuffer ) ;
}
2012-01-03 20:39:10 +00:00
bool CGraphicsBackend_Threaded : : IsIdle ( ) const
{
2021-10-27 22:52:06 +00:00
return ! m_BufferInProcess . load ( std : : memory_order_relaxed ) ;
2012-01-03 20:39:10 +00:00
}
void CGraphicsBackend_Threaded : : WaitForIdle ( )
{
2021-10-27 22:52:06 +00:00
std : : unique_lock < std : : mutex > Lock ( m_BufferSwapMutex ) ;
2022-03-20 17:04:00 +00:00
m_BufferSwapCond . wait ( Lock , [ this ] ( ) { return m_pBuffer = = nullptr ; } ) ;
2012-01-03 20:39:10 +00:00
}
2022-12-09 15:16:16 +00:00
void CGraphicsBackend_Threaded : : ProcessError ( )
{
const auto & Error = m_pProcessor - > GetError ( ) ;
std : : string VerboseStr ;
for ( const auto & ErrStr : Error . m_vErrors )
2023-01-04 17:19:53 +00:00
{
if ( ErrStr . m_RequiresTranslation )
VerboseStr . append ( std : : string ( m_TranslateFunc ( ErrStr . m_Err . c_str ( ) , " " ) ) + " \n " ) ;
else
VerboseStr . append ( ErrStr . m_Err + " \n " ) ;
}
2022-12-09 15:16:16 +00:00
const auto CreatedMsgBox = TryCreateMsgBox ( true , " Graphics Assertion " , VerboseStr . c_str ( ) ) ;
// check if error msg can be shown, then assert
dbg_assert ( ! CreatedMsgBox , VerboseStr . c_str ( ) ) ;
}
bool CGraphicsBackend_Threaded : : GetWarning ( std : : vector < std : : string > & WarningStrings )
{
if ( HasWarning ( ) )
{
m_Warning . m_WarningType = GFX_WARNING_TYPE_NONE ;
WarningStrings = m_Warning . m_vWarnings ;
return true ;
}
return false ;
}
2012-01-03 20:39:10 +00:00
// ------------ CCommandProcessorFragment_General
void CCommandProcessorFragment_General : : Cmd_Signal ( const CCommandBuffer : : SCommand_Signal * pCommand )
{
2020-11-29 16:53:54 +00:00
pCommand - > m_pSemaphore - > Signal ( ) ;
2012-01-03 20:39:10 +00:00
}
2020-09-26 19:41:58 +00:00
bool CCommandProcessorFragment_General : : RunCommand ( const CCommandBuffer : : SCommand * pBaseCommand )
2012-01-03 20:39:10 +00:00
{
switch ( pBaseCommand - > m_Cmd )
{
case CCommandBuffer : : CMD_NOP : break ;
case CCommandBuffer : : CMD_SIGNAL : Cmd_Signal ( static_cast < const CCommandBuffer : : SCommand_Signal * > ( pBaseCommand ) ) ; break ;
default : return false ;
}
return true ;
2021-04-30 22:42:37 +00:00
}
2020-08-29 10:10:38 +00:00
2021-04-30 22:42:37 +00:00
// ------------ CCommandProcessorFragment_SDL
void CCommandProcessorFragment_SDL : : Cmd_Init ( const SCommand_Init * pCommand )
{
m_GLContext = pCommand - > m_GLContext ;
m_pWindow = pCommand - > m_pWindow ;
2022-03-20 17:03:25 +00:00
if ( m_GLContext )
SDL_GL_MakeCurrent ( m_pWindow , m_GLContext ) ;
2012-01-03 20:39:10 +00:00
}
void CCommandProcessorFragment_SDL : : Cmd_Shutdown ( const SCommand_Shutdown * pCommand )
{
2022-03-20 17:03:25 +00:00
if ( m_GLContext )
SDL_GL_MakeCurrent ( NULL , NULL ) ;
2012-01-03 20:39:10 +00:00
}
void CCommandProcessorFragment_SDL : : Cmd_Swap ( const CCommandBuffer : : SCommand_Swap * pCommand )
{
2022-03-20 17:03:25 +00:00
if ( m_GLContext )
SDL_GL_SwapWindow ( m_pWindow ) ;
2012-01-03 20:39:10 +00:00
}
2016-04-29 22:34:12 +00:00
void CCommandProcessorFragment_SDL : : Cmd_VSync ( const CCommandBuffer : : SCommand_VSync * pCommand )
{
2022-03-20 17:03:25 +00:00
if ( m_GLContext )
* pCommand - > m_pRetOk = SDL_GL_SetSwapInterval ( pCommand - > m_VSync ) = = 0 ;
2016-04-29 22:34:12 +00:00
}
2021-08-24 10:18:20 +00:00
void CCommandProcessorFragment_SDL : : Cmd_WindowCreateNtf ( const CCommandBuffer : : SCommand_WindowCreateNtf * pCommand )
{
m_pWindow = SDL_GetWindowFromID ( pCommand - > m_WindowID ) ;
// Android destroys windows when they are not visible, so we get the new one and work with that
// The graphic context does not need to be recreated, just unbound see @see SCommand_WindowDestroyNtf
# ifdef CONF_PLATFORM_ANDROID
2022-03-20 17:03:25 +00:00
if ( m_GLContext )
SDL_GL_MakeCurrent ( m_pWindow , m_GLContext ) ;
2021-08-24 10:18:20 +00:00
dbg_msg ( " gfx " , " render surface created. " ) ;
# endif
}
void CCommandProcessorFragment_SDL : : Cmd_WindowDestroyNtf ( const CCommandBuffer : : SCommand_WindowDestroyNtf * pCommand )
{
// Unbind the graphic context from the window, so it does not get destroyed
# ifdef CONF_PLATFORM_ANDROID
dbg_msg ( " gfx " , " render surface destroyed. " ) ;
2022-03-20 17:03:25 +00:00
if ( m_GLContext )
SDL_GL_MakeCurrent ( NULL , NULL ) ;
2021-08-24 10:18:20 +00:00
# endif
}
2022-02-14 23:32:04 +00:00
CCommandProcessorFragment_SDL : : CCommandProcessorFragment_SDL ( ) = default ;
2012-01-03 20:39:10 +00:00
bool CCommandProcessorFragment_SDL : : RunCommand ( const CCommandBuffer : : SCommand * pBaseCommand )
{
switch ( pBaseCommand - > m_Cmd )
{
2021-08-24 10:18:20 +00:00
case CCommandBuffer : : CMD_WINDOW_CREATE_NTF : Cmd_WindowCreateNtf ( static_cast < const CCommandBuffer : : SCommand_WindowCreateNtf * > ( pBaseCommand ) ) ; break ;
case CCommandBuffer : : CMD_WINDOW_DESTROY_NTF : Cmd_WindowDestroyNtf ( static_cast < const CCommandBuffer : : SCommand_WindowDestroyNtf * > ( pBaseCommand ) ) ; break ;
2012-01-03 20:39:10 +00:00
case CCommandBuffer : : CMD_SWAP : Cmd_Swap ( static_cast < const CCommandBuffer : : SCommand_Swap * > ( pBaseCommand ) ) ; break ;
2016-04-29 22:34:12 +00:00
case CCommandBuffer : : CMD_VSYNC : Cmd_VSync ( static_cast < const CCommandBuffer : : SCommand_VSync * > ( pBaseCommand ) ) ; break ;
2022-04-26 18:09:47 +00:00
case CCommandBuffer : : CMD_MULTISAMPLING : break ;
2012-01-03 20:39:10 +00:00
case CMD_INIT : Cmd_Init ( static_cast < const SCommand_Init * > ( pBaseCommand ) ) ; break ;
case CMD_SHUTDOWN : Cmd_Shutdown ( static_cast < const SCommand_Shutdown * > ( pBaseCommand ) ) ; break ;
2022-03-20 17:03:25 +00:00
case CCommandProcessorFragment_GLBase : : CMD_PRE_INIT : break ;
case CCommandProcessorFragment_GLBase : : CMD_POST_SHUTDOWN : break ;
2012-01-03 20:39:10 +00:00
default : return false ;
}
return true ;
}
2022-03-20 17:03:25 +00:00
// ------------ CCommandProcessor_SDL_GL
2012-01-03 20:39:10 +00:00
2022-12-09 15:16:16 +00:00
void CCommandProcessor_SDL_GL : : HandleError ( )
{
auto & Error = GetError ( ) ;
switch ( Error . m_ErrorType )
{
case GFX_ERROR_TYPE_INIT :
2023-01-03 16:03:41 +00:00
Error . m_vErrors . emplace_back ( SGFXErrorContainer : : SError { true , Localizable ( " Failed during initialization. Try to change gfx_backend to OpenGL or Vulkan in settings_ddnet.cfg in the config directory and try again. " , " Graphics error " ) } ) ;
2022-12-09 15:16:16 +00:00
break ;
case GFX_ERROR_TYPE_OUT_OF_MEMORY_IMAGE :
[[fallthrough]] ;
case GFX_ERROR_TYPE_OUT_OF_MEMORY_BUFFER :
[[fallthrough]] ;
case GFX_ERROR_TYPE_OUT_OF_MEMORY_STAGING :
2023-01-03 16:03:41 +00:00
Error . m_vErrors . emplace_back ( SGFXErrorContainer : : SError { true , Localizable ( " Out of VRAM. Try removing custom assets (skins, entities, etc.), especially those with high resolution. " , " Graphics error " ) } ) ;
2022-12-09 15:16:16 +00:00
break ;
case GFX_ERROR_TYPE_RENDER_RECORDING :
2023-01-03 16:03:41 +00:00
Error . m_vErrors . emplace_back ( SGFXErrorContainer : : SError { true , Localizable ( " An error during command recording occurred. Try to update your GPU drivers. " , " Graphics error " ) } ) ;
2022-12-09 15:16:16 +00:00
break ;
case GFX_ERROR_TYPE_RENDER_CMD_FAILED :
2023-01-03 16:03:41 +00:00
Error . m_vErrors . emplace_back ( SGFXErrorContainer : : SError { true , Localizable ( " A render command failed. Try to update your GPU drivers. " , " Graphics error " ) } ) ;
2022-12-09 15:16:16 +00:00
break ;
case GFX_ERROR_TYPE_RENDER_SUBMIT_FAILED :
2023-01-03 16:03:41 +00:00
Error . m_vErrors . emplace_back ( SGFXErrorContainer : : SError { true , Localizable ( " Submitting the render commands failed. Try to update your GPU drivers. " , " Graphics error " ) } ) ;
2022-12-09 15:16:16 +00:00
break ;
case GFX_ERROR_TYPE_SWAP_FAILED :
2023-01-03 16:03:41 +00:00
Error . m_vErrors . emplace_back ( SGFXErrorContainer : : SError { true , Localizable ( " Failed to swap framebuffers. Try to update your GPU drivers. " , " Graphics error " ) } ) ;
2022-12-09 15:16:16 +00:00
break ;
case GFX_ERROR_TYPE_UNKNOWN :
[[fallthrough]] ;
default :
2023-01-03 16:03:41 +00:00
Error . m_vErrors . emplace_back ( SGFXErrorContainer : : SError { true , Localizable ( " Unknown error. Try to change gfx_backend to OpenGL or Vulkan in settings_ddnet.cfg in the config directory and try again. " , " Graphics error " ) } ) ;
2022-12-09 15:16:16 +00:00
break ;
}
}
void CCommandProcessor_SDL_GL : : HandleWarning ( )
{
auto & Warn = GetWarning ( ) ;
switch ( Warn . m_WarningType )
{
case GFX_WARNING_TYPE_INIT_FAILED :
2023-01-03 16:03:41 +00:00
Warn . m_vWarnings . emplace_back ( Localizable ( " Could not initialize the given graphics backend, reverting to the default backend now. " , " Graphics error " ) ) ;
2022-12-09 15:16:16 +00:00
break ;
2023-01-06 19:23:43 +00:00
case GFX_WARNING_TYPE_INIT_FAILED_MISSING_INTEGRATED_GPU_DRIVER :
2023-02-25 09:36:23 +00:00
Warn . m_vWarnings . emplace_back ( Localizable ( " Could not initialize the given graphics backend, this is probably because you didn't install the driver of the integrated graphics card. " , " Graphics error " ) ) ;
2023-01-06 19:23:43 +00:00
break ;
2022-12-09 15:16:16 +00:00
case GFX_WARNING_MISSING_EXTENSION :
// ignore this warning for now
return ;
case GFX_WARNING_LOW_ON_MEMORY :
// ignore this warning for now
return ;
default :
dbg_msg ( " gfx " , " unhandled warning %d " , ( int ) Warn . m_WarningType ) ;
break ;
}
}
2022-03-20 17:03:25 +00:00
void CCommandProcessor_SDL_GL : : RunBuffer ( CCommandBuffer * pBuffer )
2012-01-03 20:39:10 +00:00
{
2022-03-20 17:04:00 +00:00
m_pGLBackend - > StartCommands ( pBuffer - > m_CommandCount , pBuffer - > m_RenderCallCount ) ;
2022-03-20 17:03:25 +00:00
2020-10-11 15:08:04 +00:00
for ( CCommandBuffer : : SCommand * pCommand = pBuffer - > Head ( ) ; pCommand ; pCommand = pCommand - > m_pNext )
2012-01-03 20:39:10 +00:00
{
2022-12-09 15:16:16 +00:00
auto Res = m_pGLBackend - > RunCommand ( pCommand ) ;
if ( Res = = ERunCommandReturnTypes : : RUN_COMMAND_COMMAND_HANDLED )
{
2020-09-26 19:41:58 +00:00
continue ;
2022-12-09 15:16:16 +00:00
}
else if ( Res = = ERunCommandReturnTypes : : RUN_COMMAND_COMMAND_ERROR )
{
m_Error = m_pGLBackend - > GetError ( ) ;
HandleError ( ) ;
return ;
}
else if ( Res = = ERunCommandReturnTypes : : RUN_COMMAND_COMMAND_WARNING )
{
m_Warning = m_pGLBackend - > GetWarning ( ) ;
HandleWarning ( ) ;
return ;
}
2020-08-29 10:10:38 +00:00
2020-10-11 15:08:04 +00:00
if ( m_SDL . RunCommand ( pCommand ) )
2012-01-03 20:39:10 +00:00
continue ;
2020-10-11 15:08:04 +00:00
if ( m_General . RunCommand ( pCommand ) )
2012-01-03 20:39:10 +00:00
continue ;
2015-07-09 00:08:14 +00:00
2020-10-26 08:57:41 +00:00
dbg_msg ( " gfx " , " unknown command %d " , pCommand - > m_Cmd ) ;
2012-01-03 20:39:10 +00:00
}
2022-03-20 17:03:25 +00:00
m_pGLBackend - > EndCommands ( ) ;
2012-01-03 20:39:10 +00:00
}
2022-03-20 17:03:25 +00:00
CCommandProcessor_SDL_GL : : CCommandProcessor_SDL_GL ( EBackendType BackendType , int GLMajor , int GLMinor , int GLPatch )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
m_BackendType = BackendType ;
2022-04-16 10:29:10 +00:00
# if defined(CONF_HEADLESS_CLIENT)
m_pGLBackend = new CCommandProcessorFragment_Null ( ) ;
# else
2021-04-30 22:42:37 +00:00
if ( BackendType = = BACKEND_TYPE_OPENGL_ES )
2020-09-26 19:41:58 +00:00
{
2021-05-02 00:52:13 +00:00
# if defined(CONF_BACKEND_OPENGL_ES) || defined(CONF_BACKEND_OPENGL_ES3)
2022-03-20 17:03:25 +00:00
if ( GLMajor < 3 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
m_pGLBackend = new CCommandProcessorFragment_OpenGLES ( ) ;
2021-04-30 22:42:37 +00:00
}
else
{
2022-03-20 17:03:25 +00:00
m_pGLBackend = new CCommandProcessorFragment_OpenGLES3 ( ) ;
2021-04-30 22:42:37 +00:00
}
2021-05-02 00:52:13 +00:00
# endif
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
else if ( BackendType = = BACKEND_TYPE_OPENGL )
2020-09-26 19:41:58 +00:00
{
2021-05-02 00:52:13 +00:00
# if !defined(CONF_BACKEND_OPENGL_ES)
2022-03-20 17:03:25 +00:00
if ( GLMajor < 2 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
m_pGLBackend = new CCommandProcessorFragment_OpenGL ( ) ;
2021-04-30 22:42:37 +00:00
}
2022-03-20 17:03:25 +00:00
if ( GLMajor = = 2 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
m_pGLBackend = new CCommandProcessorFragment_OpenGL2 ( ) ;
2021-04-30 22:42:37 +00:00
}
2022-03-20 17:03:25 +00:00
if ( GLMajor = = 3 & & GLMinor = = 0 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
m_pGLBackend = new CCommandProcessorFragment_OpenGL3 ( ) ;
2021-04-30 22:42:37 +00:00
}
2022-03-20 17:03:25 +00:00
else if ( ( GLMajor = = 3 & & GLMinor = = 3 ) | | GLMajor > = 4 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
m_pGLBackend = new CCommandProcessorFragment_OpenGL3_3 ( ) ;
2021-04-30 22:42:37 +00:00
}
2022-03-20 17:03:25 +00:00
# endif
}
else if ( BackendType = = BACKEND_TYPE_VULKAN )
{
# if defined(CONF_BACKEND_VULKAN)
m_pGLBackend = CreateVulkanCommandProcessorFragment ( ) ;
2021-05-02 00:52:13 +00:00
# endif
2020-08-29 10:10:38 +00:00
}
2022-04-16 10:29:10 +00:00
# endif
2020-08-29 10:10:38 +00:00
}
2022-03-20 17:03:25 +00:00
CCommandProcessor_SDL_GL : : ~ CCommandProcessor_SDL_GL ( )
2020-09-30 21:51:33 +00:00
{
2022-03-20 17:03:25 +00:00
delete m_pGLBackend ;
2020-09-30 21:51:33 +00:00
}
2022-12-09 15:16:16 +00:00
SGFXErrorContainer & CCommandProcessor_SDL_GL : : GetError ( )
{
return m_Error ;
}
void CCommandProcessor_SDL_GL : : ErroneousCleanup ( )
{
return m_pGLBackend - > ErroneousCleanup ( ) ;
}
SGFXWarningContainer & CCommandProcessor_SDL_GL : : GetWarning ( )
{
return m_Warning ;
}
2022-03-20 17:03:25 +00:00
// ------------ CGraphicsBackend_SDL_GL
2012-01-03 20:39:10 +00:00
2021-04-30 22:42:37 +00:00
static bool BackendInitGlew ( EBackendType BackendType , int & GlewMajor , int & GlewMinor , int & GlewPatch )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
if ( BackendType = = BACKEND_TYPE_OPENGL )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
# ifndef CONF_BACKEND_OPENGL_ES
2022-03-20 17:03:25 +00:00
// support graphic cards that are pretty old(and linux)
2021-04-30 22:42:37 +00:00
glewExperimental = GL_TRUE ;
2021-08-23 10:31:41 +00:00
# ifdef CONF_GLEW_HAS_CONTEXT_INIT
if ( GLEW_OK ! = glewContextInit ( ) )
# else
2021-04-30 22:42:37 +00:00
if ( GLEW_OK ! = glewInit ( ) )
2021-08-23 10:31:41 +00:00
# endif
2021-04-30 22:42:37 +00:00
return false ;
2020-08-29 10:10:38 +00:00
2021-04-30 22:42:37 +00:00
# ifdef GLEW_VERSION_4_6
if ( GLEW_VERSION_4_6 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
GlewMajor = 4 ;
GlewMinor = 6 ;
GlewPatch = 0 ;
return true ;
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
# endif
2022-02-08 17:20:17 +00:00
# ifdef GLEW_VERSION_4_5
2021-04-30 22:42:37 +00:00
if ( GLEW_VERSION_4_5 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
GlewMajor = 4 ;
GlewMinor = 5 ;
GlewPatch = 0 ;
return true ;
2020-08-29 10:10:38 +00:00
}
2022-02-08 17:20:17 +00:00
# endif
2022-10-25 16:51:56 +00:00
// Don't allow GL 3.3, if the driver doesn't support at least OpenGL 4.5
2022-01-15 15:20:01 +00:00
# ifndef CONF_FAMILY_WINDOWS
2021-04-30 22:42:37 +00:00
if ( GLEW_VERSION_4_4 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
GlewMajor = 4 ;
GlewMinor = 4 ;
GlewPatch = 0 ;
return true ;
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
if ( GLEW_VERSION_4_3 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
GlewMajor = 4 ;
GlewMinor = 3 ;
GlewPatch = 0 ;
return true ;
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
if ( GLEW_VERSION_4_2 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
GlewMajor = 4 ;
GlewMinor = 2 ;
GlewPatch = 0 ;
return true ;
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
if ( GLEW_VERSION_4_1 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
GlewMajor = 4 ;
GlewMinor = 1 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_4_0 )
{
GlewMajor = 4 ;
GlewMinor = 0 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_3_3 )
{
GlewMajor = 3 ;
GlewMinor = 3 ;
GlewPatch = 0 ;
return true ;
}
2021-08-18 10:03:42 +00:00
# endif
2021-04-30 22:42:37 +00:00
if ( GLEW_VERSION_3_0 )
{
GlewMajor = 3 ;
GlewMinor = 0 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_2_1 )
{
GlewMajor = 2 ;
GlewMinor = 1 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_2_0 )
{
GlewMajor = 2 ;
GlewMinor = 0 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_1_5 )
{
GlewMajor = 1 ;
GlewMinor = 5 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_1_4 )
{
GlewMajor = 1 ;
GlewMinor = 4 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_1_3 )
{
GlewMajor = 1 ;
GlewMinor = 3 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_1_2_1 )
{
GlewMajor = 1 ;
GlewMinor = 2 ;
GlewPatch = 1 ;
return true ;
}
if ( GLEW_VERSION_1_2 )
{
GlewMajor = 1 ;
GlewMinor = 2 ;
GlewPatch = 0 ;
return true ;
}
if ( GLEW_VERSION_1_1 )
{
GlewMajor = 1 ;
GlewMinor = 1 ;
GlewPatch = 0 ;
return true ;
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
# endif
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
else if ( BackendType = = BACKEND_TYPE_OPENGL_ES )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
// just assume the version we need
GlewMajor = 3 ;
GlewMinor = 0 ;
GlewPatch = 0 ;
return true ;
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
return true ;
}
static int IsVersionSupportedGlew ( EBackendType BackendType , int VersionMajor , int VersionMinor , int VersionPatch , int GlewMajor , int GlewMinor , int GlewPatch )
{
int InitError = 0 ;
if ( BackendType = = BACKEND_TYPE_OPENGL )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
if ( VersionMajor > = 4 & & GlewMajor < 4 )
2020-08-29 10:10:38 +00:00
{
InitError = - 1 ;
}
2021-04-30 22:42:37 +00:00
else if ( VersionMajor > = 3 & & GlewMajor < 3 )
2020-08-29 10:10:38 +00:00
{
InitError = - 1 ;
}
2021-04-30 22:42:37 +00:00
else if ( VersionMajor = = 3 & & GlewMajor = = 3 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
if ( VersionMinor > = 3 & & GlewMinor < 3 )
{
InitError = - 1 ;
}
if ( VersionMinor > = 2 & & GlewMinor < 2 )
{
InitError = - 1 ;
}
if ( VersionMinor > = 1 & & GlewMinor < 1 )
{
InitError = - 1 ;
}
if ( VersionMinor > = 0 & & GlewMinor < 0 )
{
InitError = - 1 ;
}
2020-08-29 10:10:38 +00:00
}
2021-04-30 22:42:37 +00:00
else if ( VersionMajor > = 2 & & GlewMajor < 2 )
2020-08-29 10:10:38 +00:00
{
InitError = - 1 ;
}
2021-04-30 22:42:37 +00:00
else if ( VersionMajor = = 2 & & GlewMajor = = 2 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
if ( VersionMinor > = 1 & & GlewMinor < 1 )
2020-08-29 10:10:38 +00:00
{
InitError = - 1 ;
}
2021-04-30 22:42:37 +00:00
if ( VersionMinor > = 0 & & GlewMinor < 0 )
2020-08-29 10:10:38 +00:00
{
InitError = - 1 ;
}
}
2021-04-30 22:42:37 +00:00
else if ( VersionMajor > = 1 & & GlewMajor < 1 )
2020-08-29 10:10:38 +00:00
{
InitError = - 1 ;
}
2021-04-30 22:42:37 +00:00
else if ( VersionMajor = = 1 & & GlewMajor = = 1 )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
if ( VersionMinor > = 5 & & GlewMinor < 5 )
{
InitError = - 1 ;
}
if ( VersionMinor > = 4 & & GlewMinor < 4 )
{
InitError = - 1 ;
}
if ( VersionMinor > = 3 & & GlewMinor < 3 )
{
InitError = - 1 ;
}
if ( VersionMinor > = 2 & & GlewMinor < 2 )
{
InitError = - 1 ;
}
else if ( VersionMinor = = 2 & & GlewMinor = = 2 )
{
if ( VersionPatch > = 1 & & GlewPatch < 1 )
{
InitError = - 1 ;
}
if ( VersionPatch > = 0 & & GlewPatch < 0 )
{
InitError = - 1 ;
}
}
if ( VersionMinor > = 1 & & GlewMinor < 1 )
{
InitError = - 1 ;
}
if ( VersionMinor > = 0 & & GlewMinor < 0 )
{
InitError = - 1 ;
}
2020-08-29 10:10:38 +00:00
}
}
return InitError ;
}
2022-03-20 17:03:25 +00:00
EBackendType CGraphicsBackend_SDL_GL : : DetectBackend ( )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
EBackendType RetBackendType = BACKEND_TYPE_OPENGL ;
2022-05-17 18:29:15 +00:00
# if defined(CONF_BACKEND_VULKAN)
2022-03-20 17:04:00 +00:00
const char * pEnvDriver = SDL_getenv ( " DDNET_DRIVER " ) ;
2022-03-20 17:03:25 +00:00
if ( pEnvDriver & & str_comp_nocase ( pEnvDriver , " GLES " ) = = 0 )
RetBackendType = BACKEND_TYPE_OPENGL_ES ;
else if ( pEnvDriver & & str_comp_nocase ( pEnvDriver , " Vulkan " ) = = 0 )
RetBackendType = BACKEND_TYPE_VULKAN ;
else if ( pEnvDriver & & str_comp_nocase ( pEnvDriver , " OpenGL " ) = = 0 )
RetBackendType = BACKEND_TYPE_OPENGL ;
else if ( pEnvDriver = = nullptr )
{
// load the config backend
const char * pConfBackend = g_Config . m_GfxBackend ;
if ( str_comp_nocase ( pConfBackend , " GLES " ) = = 0 )
RetBackendType = BACKEND_TYPE_OPENGL_ES ;
else if ( str_comp_nocase ( pConfBackend , " Vulkan " ) = = 0 )
RetBackendType = BACKEND_TYPE_VULKAN ;
else if ( str_comp_nocase ( pConfBackend , " OpenGL " ) = = 0 )
RetBackendType = BACKEND_TYPE_OPENGL ;
}
2022-05-17 18:29:15 +00:00
# else
2022-03-20 17:04:00 +00:00
RetBackendType = BACKEND_TYPE_OPENGL ;
# endif
2022-03-20 17:03:25 +00:00
# if !defined(CONF_BACKEND_OPENGL_ES) && !defined(CONF_BACKEND_OPENGL_ES3)
if ( RetBackendType = = BACKEND_TYPE_OPENGL_ES )
RetBackendType = BACKEND_TYPE_OPENGL ;
2022-03-20 17:04:00 +00:00
# elif defined(CONF_BACKEND_OPENGL_ES)
if ( RetBackendType = = BACKEND_TYPE_OPENGL )
RetBackendType = BACKEND_TYPE_OPENGL_ES ;
2021-04-30 22:42:37 +00:00
# endif
2022-03-20 17:03:25 +00:00
return RetBackendType ;
2021-04-30 22:42:37 +00:00
}
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_SDL_GL : : ClampDriverVersion ( EBackendType BackendType )
2021-04-30 22:42:37 +00:00
{
if ( BackendType = = BACKEND_TYPE_OPENGL )
{
2022-03-20 17:03:25 +00:00
// clamp the versions to existing versions(only for OpenGL major <= 3)
if ( g_Config . m_GfxGLMajor = = 1 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLMinor = clamp ( g_Config . m_GfxGLMinor , 1 , 5 ) ;
if ( g_Config . m_GfxGLMinor = = 2 )
g_Config . m_GfxGLPatch = clamp ( g_Config . m_GfxGLPatch , 0 , 1 ) ;
2021-04-30 22:42:37 +00:00
else
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLPatch = 0 ;
2021-04-30 22:42:37 +00:00
}
2022-03-20 17:03:25 +00:00
else if ( g_Config . m_GfxGLMajor = = 2 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLMinor = clamp ( g_Config . m_GfxGLMinor , 0 , 1 ) ;
g_Config . m_GfxGLPatch = 0 ;
2021-04-30 22:42:37 +00:00
}
2022-03-20 17:03:25 +00:00
else if ( g_Config . m_GfxGLMajor = = 3 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLMinor = clamp ( g_Config . m_GfxGLMinor , 0 , 3 ) ;
if ( g_Config . m_GfxGLMinor < 3 )
g_Config . m_GfxGLMinor = 0 ;
g_Config . m_GfxGLPatch = 0 ;
2021-04-30 22:42:37 +00:00
}
}
else if ( BackendType = = BACKEND_TYPE_OPENGL_ES )
{
2021-05-02 00:52:13 +00:00
# if !defined(CONF_BACKEND_OPENGL_ES3)
2021-04-30 22:42:37 +00:00
// Make sure GLES is set to 1.0 (which is equivalent to OpenGL 1.3), if its not set to >= 3.0(which is equivalent to OpenGL 3.3)
2022-03-20 17:03:25 +00:00
if ( g_Config . m_GfxGLMajor < 3 )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLMajor = 1 ;
g_Config . m_GfxGLMinor = 0 ;
g_Config . m_GfxGLPatch = 0 ;
2021-04-30 22:42:37 +00:00
2022-10-25 16:51:56 +00:00
// GLES also doesn't know GL_QUAD
2021-04-30 22:42:37 +00:00
g_Config . m_GfxQuadAsTriangle = 1 ;
}
2021-05-01 00:39:06 +00:00
# else
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLMajor = 3 ;
g_Config . m_GfxGLMinor = 0 ;
g_Config . m_GfxGLPatch = 0 ;
2021-05-01 00:39:06 +00:00
# endif
2021-04-30 22:42:37 +00:00
}
2022-03-20 17:03:25 +00:00
else if ( BackendType = = BACKEND_TYPE_VULKAN )
{
2022-03-20 17:04:00 +00:00
# if defined(CONF_BACKEND_VULKAN)
g_Config . m_GfxGLMajor = gs_BackendVulkanMajor ;
g_Config . m_GfxGLMinor = gs_BackendVulkanMinor ;
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLPatch = 0 ;
2022-03-20 17:04:00 +00:00
# endif
2022-03-20 17:03:25 +00:00
}
2021-04-30 22:42:37 +00:00
}
2022-12-09 15:16:16 +00:00
bool CGraphicsBackend_SDL_GL : : TryCreateMsgBox ( bool AsError , const char * pTitle , const char * pMsg )
{
m_pProcessor - > ErroneousCleanup ( ) ;
SDL_DestroyWindow ( m_pWindow ) ;
SDL_ShowSimpleMessageBox ( AsError ? SDL_MESSAGEBOX_ERROR : SDL_MESSAGEBOX_WARNING , pTitle , pMsg , nullptr ) ;
return true ;
}
2022-03-20 17:03:25 +00:00
bool CGraphicsBackend_SDL_GL : : IsModernAPI ( EBackendType BackendType )
2021-04-30 22:42:37 +00:00
{
if ( BackendType = = BACKEND_TYPE_OPENGL )
2022-03-20 17:03:25 +00:00
return ( g_Config . m_GfxGLMajor = = 3 & & g_Config . m_GfxGLMinor = = 3 ) | | g_Config . m_GfxGLMajor > = 4 ;
2021-04-30 22:42:37 +00:00
else if ( BackendType = = BACKEND_TYPE_OPENGL_ES )
2022-03-20 17:03:25 +00:00
return g_Config . m_GfxGLMajor > = 3 ;
else if ( BackendType = = BACKEND_TYPE_VULKAN )
return true ;
2021-04-30 22:42:37 +00:00
return false ;
}
2022-03-20 17:04:00 +00:00
bool CGraphicsBackend_SDL_GL : : GetDriverVersion ( EGraphicsDriverAgeType DriverAgeType , int & Major , int & Minor , int & Patch , const char * & pName , EBackendType BackendType )
2021-05-02 21:20:21 +00:00
{
2022-03-20 17:04:00 +00:00
if ( BackendType = = BACKEND_TYPE_AUTO )
BackendType = m_BackendType ;
if ( BackendType = = BACKEND_TYPE_OPENGL )
2021-05-02 21:20:21 +00:00
{
2022-03-20 17:04:00 +00:00
pName = " OpenGL " ;
2022-03-25 08:26:37 +00:00
# ifndef CONF_BACKEND_OPENGL_ES
2021-05-02 21:20:21 +00:00
if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_LEGACY )
{
Major = 1 ;
Minor = 4 ;
Patch = 0 ;
2022-03-20 17:04:00 +00:00
return true ;
2021-05-02 21:20:21 +00:00
}
else if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_DEFAULT )
{
Major = 3 ;
Minor = 0 ;
Patch = 0 ;
2022-03-20 17:04:00 +00:00
return true ;
2021-05-02 21:20:21 +00:00
}
else if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_MODERN )
{
Major = 3 ;
Minor = 3 ;
Patch = 0 ;
2022-03-20 17:04:00 +00:00
return true ;
2021-05-02 21:20:21 +00:00
}
2022-03-25 08:26:37 +00:00
# endif
2021-05-02 21:20:21 +00:00
}
2022-03-20 17:04:00 +00:00
else if ( BackendType = = BACKEND_TYPE_OPENGL_ES )
2021-05-02 21:20:21 +00:00
{
2022-03-20 17:04:00 +00:00
pName = " GLES " ;
# ifdef CONF_BACKEND_OPENGL_ES
2021-05-02 21:20:21 +00:00
if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_LEGACY )
{
Major = 1 ;
Minor = 0 ;
Patch = 0 ;
2022-03-20 17:04:00 +00:00
return true ;
2021-05-02 21:20:21 +00:00
}
else if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_DEFAULT )
{
Major = 3 ;
Minor = 0 ;
Patch = 0 ;
2022-03-20 17:04:00 +00:00
// there isn't really a default one
return false ;
2021-05-02 21:20:21 +00:00
}
2022-03-20 17:04:00 +00:00
# endif
# ifdef CONF_BACKEND_OPENGL_ES3
if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_MODERN )
2021-05-02 21:20:21 +00:00
{
Major = 3 ;
Minor = 0 ;
Patch = 0 ;
2022-03-20 17:04:00 +00:00
return true ;
2021-05-02 21:20:21 +00:00
}
2022-03-20 17:04:00 +00:00
# endif
2021-05-02 21:20:21 +00:00
}
2022-03-20 17:04:00 +00:00
else if ( BackendType = = BACKEND_TYPE_VULKAN )
{
pName = " Vulkan " ;
# ifdef CONF_BACKEND_VULKAN
if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_DEFAULT )
{
Major = gs_BackendVulkanMajor ;
Minor = gs_BackendVulkanMinor ;
Patch = 0 ;
return true ;
}
# else
return false ;
# endif
}
return false ;
2021-05-02 21:20:21 +00:00
}
2021-08-21 19:41:51 +00:00
static void DisplayToVideoMode ( CVideoMode * pVMode , SDL_DisplayMode * pMode , int HiDPIScale , int RefreshRate )
{
pVMode - > m_CanvasWidth = pMode - > w * HiDPIScale ;
pVMode - > m_CanvasHeight = pMode - > h * HiDPIScale ;
pVMode - > m_WindowWidth = pMode - > w ;
pVMode - > m_WindowHeight = pMode - > h ;
pVMode - > m_RefreshRate = RefreshRate ;
pVMode - > m_Red = SDL_BITSPERPIXEL ( pMode - > format ) ;
pVMode - > m_Green = SDL_BITSPERPIXEL ( pMode - > format ) ;
pVMode - > m_Blue = SDL_BITSPERPIXEL ( pMode - > format ) ;
pVMode - > m_Format = pMode - > format ;
}
2022-03-24 00:16:05 +00:00
void CGraphicsBackend_SDL_GL : : GetVideoModes ( CVideoMode * pModes , int MaxModes , int * pNumModes , int HiDPIScale , int MaxWindowWidth , int MaxWindowHeight , int ScreenID )
2021-08-21 19:41:51 +00:00
{
SDL_DisplayMode DesktopMode ;
2022-03-24 00:16:05 +00:00
int maxModes = SDL_GetNumDisplayModes ( ScreenID ) ;
2021-08-21 19:41:51 +00:00
int numModes = 0 ;
// Only collect fullscreen modes when requested, that makes sure in windowed mode no refresh rates are shown that aren't supported without
// fullscreen anyway(except fullscreen desktop)
2022-02-04 10:13:38 +00:00
bool IsFullscreenDestkop = m_pWindow ! = NULL & & ( ( ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN_DESKTOP ) = = SDL_WINDOW_FULLSCREEN_DESKTOP ) | | g_Config . m_GfxFullscreen = = 3 ) ;
2021-08-21 19:41:51 +00:00
bool CollectFullscreenModes = m_pWindow = = NULL | | ( ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN ) ! = 0 & & ! IsFullscreenDestkop ) ;
2022-03-24 00:16:05 +00:00
if ( SDL_GetDesktopDisplayMode ( ScreenID , & DesktopMode ) < 0 )
2021-08-21 19:41:51 +00:00
{
dbg_msg ( " gfx " , " unable to get display mode: %s " , SDL_GetError ( ) ) ;
}
2022-06-30 22:36:32 +00:00
constexpr int ModeCount = 256 ;
2021-08-21 19:41:51 +00:00
SDL_DisplayMode aModes [ ModeCount ] ;
int NumModes = 0 ;
for ( int i = 0 ; i < maxModes & & NumModes < ModeCount ; i + + )
{
SDL_DisplayMode mode ;
2022-03-24 00:16:05 +00:00
if ( SDL_GetDisplayMode ( ScreenID , i , & mode ) < 0 )
2021-08-21 19:41:51 +00:00
{
dbg_msg ( " gfx " , " unable to get display mode: %s " , SDL_GetError ( ) ) ;
continue ;
}
aModes [ NumModes ] = mode ;
+ + NumModes ;
}
auto & & ModeInsert = [ & ] ( SDL_DisplayMode & mode ) {
if ( numModes < MaxModes )
{
// if last mode was equal, ignore this one --- in fullscreen this can really only happen if the screen
// supports different color modes
// in non fullscren these are the modes that show different refresh rate, but are basically the same
if ( numModes > 0 & & pModes [ numModes - 1 ] . m_WindowWidth = = mode . w & & pModes [ numModes - 1 ] . m_WindowHeight = = mode . h & & ( pModes [ numModes - 1 ] . m_RefreshRate = = mode . refresh_rate | | ( mode . refresh_rate ! = DesktopMode . refresh_rate & & ! CollectFullscreenModes ) ) )
return ;
DisplayToVideoMode ( & pModes [ numModes ] , & mode , HiDPIScale , ! CollectFullscreenModes ? DesktopMode . refresh_rate : mode . refresh_rate ) ;
numModes + + ;
}
} ;
for ( int i = 0 ; i < NumModes ; i + + )
{
SDL_DisplayMode & mode = aModes [ i ] ;
if ( mode . w > MaxWindowWidth | | mode . h > MaxWindowHeight )
continue ;
ModeInsert ( mode ) ;
if ( IsFullscreenDestkop )
break ;
if ( numModes > = MaxModes )
break ;
}
* pNumModes = numModes ;
}
2022-03-24 00:16:05 +00:00
void CGraphicsBackend_SDL_GL : : GetCurrentVideoMode ( CVideoMode & CurMode , int HiDPIScale , int MaxWindowWidth , int MaxWindowHeight , int ScreenID )
2021-08-21 19:41:51 +00:00
{
SDL_DisplayMode DPMode ;
2022-01-15 15:20:01 +00:00
// if "real" fullscreen, obtain the video mode for that
if ( ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN_DESKTOP ) = = SDL_WINDOW_FULLSCREEN )
2021-08-21 19:41:51 +00:00
{
2022-03-24 00:16:05 +00:00
if ( SDL_GetCurrentDisplayMode ( ScreenID , & DPMode ) )
2022-01-15 15:20:01 +00:00
{
dbg_msg ( " gfx " , " unable to get display mode: %s " , SDL_GetError ( ) ) ;
}
2021-08-21 19:41:51 +00:00
}
else
{
2022-03-24 00:16:05 +00:00
if ( SDL_GetDesktopDisplayMode ( ScreenID , & DPMode ) < 0 )
2022-01-15 15:20:01 +00:00
{
dbg_msg ( " gfx " , " unable to get display mode: %s " , SDL_GetError ( ) ) ;
}
else
{
int Width = 0 ;
int Height = 0 ;
SDL_GL_GetDrawableSize ( m_pWindow , & Width , & Height ) ;
DPMode . w = Width ;
DPMode . h = Height ;
}
2021-08-21 19:41:51 +00:00
}
DisplayToVideoMode ( & CurMode , & DPMode , HiDPIScale , DPMode . refresh_rate ) ;
}
2022-12-09 15:16:16 +00:00
CGraphicsBackend_SDL_GL : : CGraphicsBackend_SDL_GL ( TTranslateFunc & & TranslateFunc ) :
CGraphicsBackend_Threaded ( std : : move ( TranslateFunc ) )
2022-02-15 17:00:15 +00:00
{
2022-03-30 13:16:19 +00:00
mem_zero ( m_aErrorString , std : : size ( m_aErrorString ) ) ;
2022-02-15 17:00:15 +00:00
}
2022-05-22 12:27:55 +00:00
int CGraphicsBackend_SDL_GL : : Init ( const char * pName , int * pScreen , int * pWidth , int * pHeight , int * pRefreshRate , int * pFsaaSamples , int Flags , int * pDesktopWidth , int * pDesktopHeight , int * pCurrentWidth , int * pCurrentHeight , IStorage * pStorage )
2018-04-13 19:34:12 +00:00
{
2022-04-16 10:29:10 +00:00
# if defined(CONF_HEADLESS_CLIENT)
int InitError = 0 ;
const char * pErrorStr = NULL ;
int GlewMajor = 0 ;
int GlewMinor = 0 ;
int GlewPatch = 0 ;
IsVersionSupportedGlew ( m_BackendType , g_Config . m_GfxGLMajor , g_Config . m_GfxGLMinor , g_Config . m_GfxGLPatch , GlewMajor , GlewMinor , GlewPatch ) ;
BackendInitGlew ( m_BackendType , GlewMajor , GlewMinor , GlewPatch ) ;
# else
2020-03-20 12:48:45 +00:00
// print sdl version
{
SDL_version Compiled ;
SDL_version Linked ;
SDL_VERSION ( & Compiled ) ;
SDL_GetVersion ( & Linked ) ;
2020-03-23 11:50:19 +00:00
dbg_msg ( " sdl " , " SDL version %d.%d.%d (compiled = %d.%d.%d) " , Linked . major , Linked . minor , Linked . patch ,
Compiled . major , Compiled . minor , Compiled . patch ) ;
2020-03-20 12:48:45 +00:00
}
2020-03-23 11:50:19 +00:00
2012-01-03 20:39:10 +00:00
if ( ! SDL_WasInit ( SDL_INIT_VIDEO ) )
{
if ( SDL_InitSubSystem ( SDL_INIT_VIDEO ) < 0 )
{
dbg_msg ( " gfx " , " unable to init SDL video: %s " , SDL_GetError ( ) ) ;
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_SDL_INIT_FAILED ;
2012-01-03 20:39:10 +00:00
}
}
2022-03-20 17:04:00 +00:00
EBackendType OldBackendType = m_BackendType ;
2021-05-02 21:20:21 +00:00
m_BackendType = DetectBackend ( ) ;
2022-03-20 17:04:00 +00:00
// little fallback for Vulkan
if ( OldBackendType ! = BACKEND_TYPE_AUTO )
{
if ( m_BackendType = = BACKEND_TYPE_VULKAN )
{
2022-03-30 12:53:53 +00:00
// try default opengl settings
2022-07-09 16:14:56 +00:00
str_copy ( g_Config . m_GfxBackend , " OpenGL " ) ;
2022-03-30 12:53:53 +00:00
g_Config . m_GfxGLMajor = 3 ;
g_Config . m_GfxGLMinor = 0 ;
g_Config . m_GfxGLPatch = 0 ;
// do another analysis round too, just in case
2022-03-30 15:38:15 +00:00
g_Config . m_Gfx3DTextureAnalysisRan = 0 ;
2022-03-30 12:53:53 +00:00
g_Config . m_GfxDriverIsBlocked = 0 ;
2022-03-20 17:04:00 +00:00
SDL_setenv ( " DDNET_DRIVER " , " OpenGL " , 1 ) ;
m_BackendType = DetectBackend ( ) ;
}
}
2018-08-02 18:52:51 +00:00
2021-05-02 21:20:21 +00:00
ClampDriverVersion ( m_BackendType ) ;
2020-08-29 10:10:38 +00:00
2022-03-20 17:03:25 +00:00
bool UseModernGL = IsModernAPI ( m_BackendType ) ;
2018-08-02 18:52:51 +00:00
2022-03-20 17:03:25 +00:00
bool IsOpenGLFamilyBackend = m_BackendType = = BACKEND_TYPE_OPENGL | | m_BackendType = = BACKEND_TYPE_OPENGL_ES ;
if ( IsOpenGLFamilyBackend )
{
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MAJOR_VERSION , g_Config . m_GfxGLMajor ) ;
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MINOR_VERSION , g_Config . m_GfxGLMinor ) ;
}
dbg_msg ( " gfx " , " Created %s %d.%d context. " , ( ( m_BackendType = = BACKEND_TYPE_VULKAN ) ? " Vulkan " : " OpenGL " ) , g_Config . m_GfxGLMajor , g_Config . m_GfxGLMinor ) ;
2018-08-02 18:52:51 +00:00
2021-05-02 21:20:21 +00:00
if ( m_BackendType = = BACKEND_TYPE_OPENGL )
2017-09-13 18:33:58 +00:00
{
2022-03-20 17:03:25 +00:00
if ( g_Config . m_GfxGLMajor = = 3 & & g_Config . m_GfxGLMinor = = 0 )
2018-04-13 19:34:12 +00:00
{
2021-04-30 22:42:37 +00:00
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_COMPATIBILITY ) ;
2017-09-02 13:24:07 +00:00
}
2022-03-20 17:03:25 +00:00
else if ( UseModernGL )
2018-04-13 19:34:12 +00:00
{
2021-04-30 22:42:37 +00:00
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_CORE ) ;
2018-04-13 19:34:12 +00:00
}
2017-09-27 10:16:34 +00:00
}
2021-05-02 21:20:21 +00:00
else if ( m_BackendType = = BACKEND_TYPE_OPENGL_ES )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_PROFILE_MASK , SDL_GL_CONTEXT_PROFILE_ES ) ;
2020-08-29 10:10:38 +00:00
}
2017-09-02 13:24:07 +00:00
2022-05-22 12:27:55 +00:00
if ( IsOpenGLFamilyBackend )
{
* pFsaaSamples = std : : clamp ( * pFsaaSamples , 0 , 8 ) ;
}
2016-04-29 22:34:12 +00:00
// set screen
SDL_Rect ScreenPos ;
m_NumScreens = SDL_GetNumVideoDisplays ( ) ;
if ( m_NumScreens > 0 )
{
2021-08-21 19:41:51 +00:00
* pScreen = clamp ( * pScreen , 0 , m_NumScreens - 1 ) ;
if ( SDL_GetDisplayBounds ( * pScreen , & ScreenPos ) ! = 0 )
2016-04-29 22:34:12 +00:00
{
dbg_msg ( " gfx " , " unable to retrieve screen information: %s " , SDL_GetError ( ) ) ;
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_INFO_REQUEST_FAILED ;
2016-04-29 22:34:12 +00:00
}
}
else
2015-08-24 20:46:28 +00:00
{
2016-04-29 22:34:12 +00:00
dbg_msg ( " gfx " , " unable to retrieve number of screens: %s " , SDL_GetError ( ) ) ;
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_REQUEST_FAILED ;
2015-08-24 20:46:28 +00:00
}
2012-01-03 20:39:10 +00:00
2016-04-29 22:34:12 +00:00
// store desktop resolution for settings reset button
SDL_DisplayMode DisplayMode ;
2021-08-21 19:41:51 +00:00
if ( SDL_GetDesktopDisplayMode ( * pScreen , & DisplayMode ) )
2016-04-29 22:34:12 +00:00
{
dbg_msg ( " gfx " , " unable to get desktop resolution: %s " , SDL_GetError ( ) ) ;
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_SDL_SCREEN_RESOLUTION_REQUEST_FAILED ;
2016-04-29 22:34:12 +00:00
}
2021-05-07 04:00:32 +00:00
bool IsDesktopChanged = * pDesktopWidth = = 0 | | * pDesktopHeight = = 0 | | * pDesktopWidth ! = DisplayMode . w | | * pDesktopHeight ! = DisplayMode . h ;
2016-04-29 22:34:12 +00:00
* pDesktopWidth = DisplayMode . w ;
* pDesktopHeight = DisplayMode . h ;
2021-08-21 19:41:51 +00:00
// fetch supported video modes
bool SupportedResolution = false ;
CVideoMode aModes [ 256 ] ;
int ModesCount = 0 ;
int IndexOfResolution = - 1 ;
2022-03-30 13:16:19 +00:00
GetVideoModes ( aModes , std : : size ( aModes ) , & ModesCount , 1 , * pDesktopWidth , * pDesktopHeight , * pScreen ) ;
2021-08-21 19:41:51 +00:00
for ( int i = 0 ; i < ModesCount ; i + + )
2017-07-11 12:08:03 +00:00
{
2021-08-21 19:41:51 +00:00
if ( * pWidth = = aModes [ i ] . m_WindowWidth & & * pHeight = = aModes [ i ] . m_WindowHeight & & ( * pRefreshRate = = aModes [ i ] . m_RefreshRate | | * pRefreshRate = = 0 ) )
{
SupportedResolution = true ;
IndexOfResolution = i ;
break ;
}
2017-07-11 12:08:03 +00:00
}
2012-03-04 11:46:55 +00:00
2015-08-24 20:46:28 +00:00
// set flags
2022-03-20 17:03:25 +00:00
int SdlFlags = SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS ;
2022-03-20 17:04:00 +00:00
SdlFlags | = ( IsOpenGLFamilyBackend ) ? SDL_WINDOW_OPENGL : SDL_WINDOW_VULKAN ;
2020-09-26 19:41:58 +00:00
if ( Flags & IGraphicsBackend : : INITFLAG_HIGHDPI )
2020-04-07 20:37:46 +00:00
SdlFlags | = SDL_WINDOW_ALLOW_HIGHDPI ;
2020-09-26 19:41:58 +00:00
if ( Flags & IGraphicsBackend : : INITFLAG_RESIZABLE )
2015-08-24 20:46:28 +00:00
SdlFlags | = SDL_WINDOW_RESIZABLE ;
2020-09-26 19:41:58 +00:00
if ( Flags & IGraphicsBackend : : INITFLAG_BORDERLESS )
2015-08-24 20:46:28 +00:00
SdlFlags | = SDL_WINDOW_BORDERLESS ;
2020-09-26 19:41:58 +00:00
if ( Flags & IGraphicsBackend : : INITFLAG_FULLSCREEN )
2021-08-21 19:41:51 +00:00
SdlFlags | = SDL_WINDOW_FULLSCREEN ;
else if ( Flags & ( IGraphicsBackend : : INITFLAG_DESKTOP_FULLSCREEN ) )
SdlFlags | = SDL_WINDOW_FULLSCREEN_DESKTOP ;
2017-10-23 16:02:18 +00:00
2022-02-04 10:13:38 +00:00
bool IsFullscreen = ( SdlFlags & SDL_WINDOW_FULLSCREEN ) ! = 0 | | g_Config . m_GfxFullscreen = = 3 ;
2021-08-21 19:41:51 +00:00
// use desktop resolution as default resolution, clamp resolution if users's display is smaller than we remembered
// if the user starts in fullscreen, and the resolution was not found use the desktop one
2022-03-30 17:03:39 +00:00
if ( ( IsFullscreen & & ! SupportedResolution ) | | * pWidth = = 0 | | * pHeight = = 0 | | ( IsDesktopChanged & & ( ! SupportedResolution | | ! IsFullscreen ) & & ( * pWidth > * pDesktopWidth | | * pHeight > * pDesktopHeight ) ) )
2021-08-21 19:41:51 +00:00
{
* pWidth = * pDesktopWidth ;
* pHeight = * pDesktopHeight ;
* pRefreshRate = DisplayMode . refresh_rate ;
}
2017-10-23 16:02:18 +00:00
2021-08-21 19:41:51 +00:00
// if in fullscreen and refresh rate wasn't set yet, just use the one from the found list
if ( * pRefreshRate = = 0 & & SupportedResolution )
{
* pRefreshRate = aModes [ IndexOfResolution ] . m_RefreshRate ;
2016-04-30 21:10:09 +00:00
}
2021-08-21 19:41:51 +00:00
else if ( * pRefreshRate = = 0 )
2021-01-31 20:54:04 +00:00
{
2021-08-21 19:41:51 +00:00
* pRefreshRate = DisplayMode . refresh_rate ;
2021-01-31 20:54:04 +00:00
}
2012-01-03 20:39:10 +00:00
// set gl attributes
2022-03-20 17:03:25 +00:00
if ( IsOpenGLFamilyBackend )
2012-01-03 20:39:10 +00:00
{
2022-03-20 17:03:25 +00:00
SDL_GL_SetAttribute ( SDL_GL_DOUBLEBUFFER , 1 ) ;
2022-05-22 12:27:55 +00:00
if ( * pFsaaSamples )
2022-03-20 17:03:25 +00:00
{
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLEBUFFERS , 1 ) ;
2022-05-22 12:27:55 +00:00
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLESAMPLES , * pFsaaSamples ) ;
2022-03-20 17:03:25 +00:00
}
else
{
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLEBUFFERS , 0 ) ;
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLESAMPLES , 0 ) ;
}
2012-01-03 20:39:10 +00:00
}
2021-10-23 11:48:21 +00:00
if ( g_Config . m_InpMouseOld )
SDL_SetHint ( SDL_HINT_MOUSE_RELATIVE_MODE_WARP , " 1 " ) ;
2015-08-24 20:46:28 +00:00
m_pWindow = SDL_CreateWindow (
pName ,
2021-08-21 19:41:51 +00:00
SDL_WINDOWPOS_CENTERED_DISPLAY ( * pScreen ) ,
SDL_WINDOWPOS_CENTERED_DISPLAY ( * pScreen ) ,
2015-08-24 20:46:28 +00:00
* pWidth ,
* pHeight ,
SdlFlags ) ;
2012-01-03 20:39:10 +00:00
// set caption
2015-08-24 20:46:28 +00:00
if ( m_pWindow = = NULL )
{
dbg_msg ( " gfx " , " unable to create window: %s " , SDL_GetError ( ) ) ;
2022-03-20 17:04:00 +00:00
if ( m_BackendType = = BACKEND_TYPE_VULKAN )
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED ;
else
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED ;
2015-08-24 20:46:28 +00:00
}
2020-08-29 10:10:38 +00:00
int GlewMajor = 0 ;
int GlewMinor = 0 ;
int GlewPatch = 0 ;
2022-03-20 17:03:25 +00:00
if ( IsOpenGLFamilyBackend )
2021-04-30 22:42:37 +00:00
{
2022-03-20 17:03:25 +00:00
m_GLContext = SDL_GL_CreateContext ( m_pWindow ) ;
if ( m_GLContext = = NULL )
{
SDL_DestroyWindow ( m_pWindow ) ;
dbg_msg ( " gfx " , " unable to create graphic context: %s " , SDL_GetError ( ) ) ;
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_GL_CONTEXT_FAILED ;
}
if ( ! BackendInitGlew ( m_BackendType , GlewMajor , GlewMinor , GlewPatch ) )
{
SDL_GL_DeleteContext ( m_GLContext ) ;
SDL_DestroyWindow ( m_pWindow ) ;
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN ;
}
2021-04-30 22:42:37 +00:00
}
2020-08-29 10:10:38 +00:00
int InitError = 0 ;
2020-11-05 19:38:37 +00:00
const char * pErrorStr = NULL ;
2020-08-29 10:10:38 +00:00
2022-03-20 17:03:25 +00:00
InitError = IsVersionSupportedGlew ( m_BackendType , g_Config . m_GfxGLMajor , g_Config . m_GfxGLMinor , g_Config . m_GfxGLPatch , GlewMajor , GlewMinor , GlewPatch ) ;
2012-01-03 20:39:10 +00:00
2021-05-06 10:59:30 +00:00
// SDL_GL_GetDrawableSize reports HiDPI resolution even with SDL_WINDOW_ALLOW_HIGHDPI not set, which is wrong
2022-03-20 17:04:00 +00:00
if ( SdlFlags & SDL_WINDOW_ALLOW_HIGHDPI & & IsOpenGLFamilyBackend )
2021-05-06 10:59:30 +00:00
SDL_GL_GetDrawableSize ( m_pWindow , pCurrentWidth , pCurrentHeight ) ;
else
SDL_GetWindowSize ( m_pWindow , pCurrentWidth , pCurrentHeight ) ;
2022-03-20 17:03:25 +00:00
if ( IsOpenGLFamilyBackend )
{
SDL_GL_SetSwapInterval ( Flags & IGraphicsBackend : : INITFLAG_VSYNC ? 1 : 0 ) ;
SDL_GL_MakeCurrent ( NULL , NULL ) ;
}
2012-01-03 20:39:10 +00:00
2020-08-29 10:10:38 +00:00
if ( InitError ! = 0 )
{
2022-03-20 17:03:25 +00:00
if ( m_GLContext )
SDL_GL_DeleteContext ( m_GLContext ) ;
2020-08-29 10:10:38 +00:00
SDL_DestroyWindow ( m_pWindow ) ;
// try setting to glew supported version
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLMajor = GlewMajor ;
g_Config . m_GfxGLMinor = GlewMinor ;
g_Config . m_GfxGLPatch = GlewPatch ;
2020-09-26 19:41:58 +00:00
2022-03-20 17:03:25 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED ;
2020-08-29 10:10:38 +00:00
}
2022-04-16 10:29:10 +00:00
# endif // CONF_HEADLESS_CLIENT
2020-08-29 10:10:38 +00:00
2012-01-03 20:39:10 +00:00
// start the command processor
2022-03-20 17:04:00 +00:00
dbg_assert ( m_pProcessor = = nullptr , " Processor was not cleaned up properly. " ) ;
2022-03-20 17:03:25 +00:00
m_pProcessor = new CCommandProcessor_SDL_GL ( m_BackendType , g_Config . m_GfxGLMajor , g_Config . m_GfxGLMinor , g_Config . m_GfxGLPatch ) ;
2012-01-03 20:39:10 +00:00
StartProcessor ( m_pProcessor ) ;
2020-09-26 19:41:58 +00:00
2012-10-06 21:31:02 +00:00
// issue init commands for OpenGL and SDL
2012-01-03 20:39:10 +00:00
CCommandBuffer CmdBuffer ( 1024 , 512 ) ;
2022-03-20 17:03:25 +00:00
CCommandProcessorFragment_GLBase : : SCommand_PreInit CmdPre ;
CmdPre . m_pWindow = m_pWindow ;
CmdPre . m_Width = * pCurrentWidth ;
CmdPre . m_Height = * pCurrentHeight ;
CmdPre . m_pVendorString = m_aVendorString ;
CmdPre . m_pVersionString = m_aVersionString ;
CmdPre . m_pRendererString = m_aRendererString ;
CmdPre . m_pGPUList = & m_GPUList ;
CmdBuffer . AddCommandUnsafe ( CmdPre ) ;
RunBufferSingleThreadedUnsafe ( & CmdBuffer ) ;
CmdBuffer . Reset ( ) ;
// run sdl first to have the context in the thread
2020-08-29 10:10:38 +00:00
CCommandProcessorFragment_SDL : : SCommand_Init CmdSDL ;
CmdSDL . m_pWindow = m_pWindow ;
CmdSDL . m_GLContext = m_GLContext ;
2021-04-07 17:03:07 +00:00
CmdBuffer . AddCommandUnsafe ( CmdSDL ) ;
2020-08-29 10:10:38 +00:00
RunBuffer ( & CmdBuffer ) ;
WaitForIdle ( ) ;
CmdBuffer . Reset ( ) ;
2020-08-29 15:44:23 +00:00
if ( InitError = = 0 )
{
2022-03-20 17:03:25 +00:00
CCommandProcessorFragment_GLBase : : SCommand_Init CmdGL ;
CmdGL . m_pWindow = m_pWindow ;
CmdGL . m_Width = * pCurrentWidth ;
CmdGL . m_Height = * pCurrentHeight ;
CmdGL . m_pTextureMemoryUsage = & m_TextureMemoryUsage ;
CmdGL . m_pBufferMemoryUsage = & m_BufferMemoryUsage ;
CmdGL . m_pStreamMemoryUsage = & m_StreamMemoryUsage ;
CmdGL . m_pStagingMemoryUsage = & m_StagingMemoryUsage ;
CmdGL . m_pGPUList = & m_GPUList ;
CmdGL . m_pReadPresentedImageDataFunc = & m_ReadPresentedImageDataFunc ;
CmdGL . m_pStorage = pStorage ;
CmdGL . m_pCapabilities = & m_Capabilites ;
CmdGL . m_pInitError = & InitError ;
CmdGL . m_RequestedMajor = g_Config . m_GfxGLMajor ;
CmdGL . m_RequestedMinor = g_Config . m_GfxGLMinor ;
CmdGL . m_RequestedPatch = g_Config . m_GfxGLPatch ;
CmdGL . m_GlewMajor = GlewMajor ;
CmdGL . m_GlewMinor = GlewMinor ;
CmdGL . m_GlewPatch = GlewPatch ;
CmdGL . m_pErrStringPtr = & pErrorStr ;
CmdGL . m_pVendorString = m_aVendorString ;
CmdGL . m_pVersionString = m_aVersionString ;
CmdGL . m_pRendererString = m_aRendererString ;
CmdGL . m_RequestedBackend = m_BackendType ;
CmdBuffer . AddCommandUnsafe ( CmdGL ) ;
2021-04-30 22:42:37 +00:00
2020-08-29 15:44:23 +00:00
RunBuffer ( & CmdBuffer ) ;
WaitForIdle ( ) ;
CmdBuffer . Reset ( ) ;
2021-05-06 10:55:39 +00:00
}
2020-08-29 15:44:23 +00:00
2021-05-06 10:55:39 +00:00
if ( InitError ! = 0 )
{
if ( InitError ! = - 2 )
2020-08-29 15:44:23 +00:00
{
2021-05-06 10:55:39 +00:00
// shutdown the context, as it might have been initialized
2022-03-20 17:03:25 +00:00
CCommandProcessorFragment_GLBase : : SCommand_Shutdown CmdGL ;
2021-04-07 17:03:07 +00:00
CmdBuffer . AddCommandUnsafe ( CmdGL ) ;
2020-09-03 09:43:32 +00:00
RunBuffer ( & CmdBuffer ) ;
WaitForIdle ( ) ;
CmdBuffer . Reset ( ) ;
2020-08-29 15:44:23 +00:00
}
2020-08-29 10:10:38 +00:00
CCommandProcessorFragment_SDL : : SCommand_Shutdown Cmd ;
2021-04-07 17:03:07 +00:00
CmdBuffer . AddCommandUnsafe ( Cmd ) ;
2017-09-02 13:24:07 +00:00
RunBuffer ( & CmdBuffer ) ;
WaitForIdle ( ) ;
2020-08-29 10:10:38 +00:00
CmdBuffer . Reset ( ) ;
2022-03-20 17:03:25 +00:00
CCommandProcessorFragment_GLBase : : SCommand_PostShutdown CmdPost ;
CmdBuffer . AddCommandUnsafe ( CmdPost ) ;
RunBufferSingleThreadedUnsafe ( & CmdBuffer ) ;
CmdBuffer . Reset ( ) ;
2020-08-29 10:10:38 +00:00
// stop and delete the processor
StopProcessor ( ) ;
delete m_pProcessor ;
2022-03-20 17:04:00 +00:00
m_pProcessor = nullptr ;
2020-08-29 10:10:38 +00:00
2022-03-20 17:03:25 +00:00
if ( m_GLContext )
SDL_GL_DeleteContext ( m_GLContext ) ;
2020-08-29 10:10:38 +00:00
SDL_DestroyWindow ( m_pWindow ) ;
// try setting to version string's supported version
if ( InitError = = - 2 )
{
2022-03-20 17:03:25 +00:00
g_Config . m_GfxGLMajor = m_Capabilites . m_ContextMajor ;
g_Config . m_GfxGLMinor = m_Capabilites . m_ContextMinor ;
g_Config . m_GfxGLPatch = m_Capabilites . m_ContextPatch ;
2020-08-29 10:10:38 +00:00
}
2020-11-05 19:38:37 +00:00
if ( pErrorStr ! = NULL )
{
2022-07-09 16:14:56 +00:00
str_copy ( m_aErrorString , pErrorStr ) ;
2020-11-05 19:38:37 +00:00
}
2022-03-20 17:03:25 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_GL_VERSION_FAILED ;
2017-09-02 13:24:07 +00:00
}
2012-01-03 20:39:10 +00:00
2017-10-23 16:02:18 +00:00
{
2022-03-20 11:57:50 +00:00
CCommandBuffer : : SCommand_Update_Viewport CmdSDL2 ;
CmdSDL2 . m_X = 0 ;
CmdSDL2 . m_Y = 0 ;
2017-10-23 16:02:18 +00:00
2022-03-20 11:57:50 +00:00
CmdSDL2 . m_Width = * pCurrentWidth ;
CmdSDL2 . m_Height = * pCurrentHeight ;
2022-03-20 17:03:25 +00:00
CmdSDL2 . m_ByResize = true ;
2022-03-20 11:57:50 +00:00
CmdBuffer . AddCommandUnsafe ( CmdSDL2 ) ;
2021-08-21 19:41:51 +00:00
RunBuffer ( & CmdBuffer ) ;
WaitForIdle ( ) ;
CmdBuffer . Reset ( ) ;
2017-10-23 16:02:18 +00:00
}
2016-05-07 19:16:31 +00:00
2012-01-03 20:39:10 +00:00
// return
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_NONE ;
2012-01-03 20:39:10 +00:00
}
2022-03-20 17:03:25 +00:00
int CGraphicsBackend_SDL_GL : : Shutdown ( )
2012-01-03 20:39:10 +00:00
{
// issue a shutdown command
CCommandBuffer CmdBuffer ( 1024 , 512 ) ;
2022-03-20 17:03:25 +00:00
CCommandProcessorFragment_GLBase : : SCommand_Shutdown CmdGL ;
2021-04-07 17:03:07 +00:00
CmdBuffer . AddCommandUnsafe ( CmdGL ) ;
2020-09-03 09:43:32 +00:00
RunBuffer ( & CmdBuffer ) ;
WaitForIdle ( ) ;
CmdBuffer . Reset ( ) ;
2012-01-03 20:39:10 +00:00
CCommandProcessorFragment_SDL : : SCommand_Shutdown Cmd ;
2021-04-07 17:03:07 +00:00
CmdBuffer . AddCommandUnsafe ( Cmd ) ;
2012-01-03 20:39:10 +00:00
RunBuffer ( & CmdBuffer ) ;
WaitForIdle ( ) ;
2020-08-29 10:10:38 +00:00
CmdBuffer . Reset ( ) ;
2015-07-09 00:08:14 +00:00
2022-03-20 17:03:25 +00:00
CCommandProcessorFragment_GLBase : : SCommand_PostShutdown CmdPost ;
CmdBuffer . AddCommandUnsafe ( CmdPost ) ;
RunBufferSingleThreadedUnsafe ( & CmdBuffer ) ;
CmdBuffer . Reset ( ) ;
2012-01-03 20:39:10 +00:00
// stop and delete the processor
StopProcessor ( ) ;
delete m_pProcessor ;
2022-03-20 17:04:00 +00:00
m_pProcessor = nullptr ;
2012-01-03 20:39:10 +00:00
2022-12-04 21:54:18 +00:00
if ( m_GLContext ! = nullptr )
SDL_GL_DeleteContext ( m_GLContext ) ;
2015-08-24 20:46:28 +00:00
SDL_DestroyWindow ( m_pWindow ) ;
2012-01-03 20:39:10 +00:00
SDL_QuitSubSystem ( SDL_INIT_VIDEO ) ;
return 0 ;
}
2022-03-20 17:03:25 +00:00
uint64_t CGraphicsBackend_SDL_GL : : TextureMemoryUsage ( ) const
2012-10-06 21:31:02 +00:00
{
return m_TextureMemoryUsage ;
}
2022-03-20 17:03:25 +00:00
uint64_t CGraphicsBackend_SDL_GL : : BufferMemoryUsage ( ) const
{
return m_BufferMemoryUsage ;
}
uint64_t CGraphicsBackend_SDL_GL : : StreamedMemoryUsage ( ) const
{
return m_StreamMemoryUsage ;
}
uint64_t CGraphicsBackend_SDL_GL : : StagingMemoryUsage ( ) const
{
return m_StagingMemoryUsage ;
}
const TTWGraphicsGPUList & CGraphicsBackend_SDL_GL : : GetGPUs ( ) const
{
return m_GPUList ;
}
void CGraphicsBackend_SDL_GL : : Minimize ( )
2012-01-03 20:39:10 +00:00
{
2015-08-24 20:46:28 +00:00
SDL_MinimizeWindow ( m_pWindow ) ;
2012-01-03 20:39:10 +00:00
}
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_SDL_GL : : Maximize ( )
2012-01-03 20:39:10 +00:00
{
// TODO: SDL
}
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_SDL_GL : : SetWindowParams ( int FullscreenMode , bool IsBorderless , bool AllowResizing )
2016-04-29 19:07:10 +00:00
{
2021-01-31 20:54:04 +00:00
if ( FullscreenMode > 0 )
{
2022-02-04 10:13:38 +00:00
bool IsDesktopFullscreen = FullscreenMode = = 2 ;
# ifndef CONF_FAMILY_WINDOWS
// special mode for windows only
IsDesktopFullscreen | = FullscreenMode = = 3 ;
# endif
2021-01-31 20:54:04 +00:00
if ( FullscreenMode = = 1 )
{
2021-04-18 12:16:05 +00:00
# if defined(CONF_PLATFORM_MACOS) || defined(CONF_PLATFORM_HAIKU)
2021-09-13 19:13:39 +00:00
// Todo SDL: remove this when fixed (game freezes when losing focus in fullscreen)
2021-01-31 20:54:04 +00:00
SDL_SetWindowFullscreen ( m_pWindow , SDL_WINDOW_FULLSCREEN_DESKTOP ) ;
2016-04-29 22:34:12 +00:00
# else
2021-01-31 20:54:04 +00:00
SDL_SetWindowFullscreen ( m_pWindow , SDL_WINDOW_FULLSCREEN ) ;
2016-04-29 22:34:12 +00:00
# endif
2022-02-04 10:13:38 +00:00
SDL_SetWindowResizable ( m_pWindow , SDL_TRUE ) ;
2021-01-31 20:54:04 +00:00
}
2022-02-04 10:13:38 +00:00
else if ( IsDesktopFullscreen )
2021-01-31 20:54:04 +00:00
{
SDL_SetWindowFullscreen ( m_pWindow , SDL_WINDOW_FULLSCREEN_DESKTOP ) ;
2022-02-04 10:13:38 +00:00
SDL_SetWindowResizable ( m_pWindow , SDL_TRUE ) ;
}
else
{
SDL_SetWindowFullscreen ( m_pWindow , 0 ) ;
SDL_SetWindowBordered ( m_pWindow , SDL_TRUE ) ;
SDL_SetWindowResizable ( m_pWindow , SDL_FALSE ) ;
SDL_DisplayMode DPMode ;
if ( SDL_GetDesktopDisplayMode ( g_Config . m_GfxScreen , & DPMode ) < 0 )
{
dbg_msg ( " gfx " , " unable to get display mode: %s " , SDL_GetError ( ) ) ;
}
else
{
ResizeWindow ( DPMode . w , DPMode . h , DPMode . refresh_rate ) ;
SDL_SetWindowPosition ( m_pWindow , SDL_WINDOWPOS_CENTERED_DISPLAY ( g_Config . m_GfxScreen ) , SDL_WINDOWPOS_CENTERED_DISPLAY ( g_Config . m_GfxScreen ) ) ;
}
2021-01-31 20:54:04 +00:00
}
}
else
{
SDL_SetWindowFullscreen ( m_pWindow , 0 ) ;
SDL_SetWindowBordered ( m_pWindow , SDL_bool ( ! IsBorderless ) ) ;
2022-02-04 10:13:38 +00:00
SDL_SetWindowResizable ( m_pWindow , SDL_TRUE ) ;
2021-01-31 20:54:04 +00:00
}
2016-04-29 22:34:12 +00:00
}
2022-03-20 17:03:25 +00:00
bool CGraphicsBackend_SDL_GL : : SetWindowScreen ( int Index )
2016-04-29 22:34:12 +00:00
{
2021-12-13 17:42:21 +00:00
if ( Index < 0 | | Index > = m_NumScreens )
2016-04-29 22:34:12 +00:00
{
2021-12-13 17:42:21 +00:00
return false ;
2016-04-29 22:34:12 +00:00
}
2021-12-13 17:42:21 +00:00
SDL_Rect ScreenPos ;
if ( SDL_GetDisplayBounds ( Index , & ScreenPos ) ! = 0 )
{
return false ;
}
SDL_SetWindowPosition ( m_pWindow ,
SDL_WINDOWPOS_CENTERED_DISPLAY ( Index ) ,
SDL_WINDOWPOS_CENTERED_DISPLAY ( Index ) ) ;
return UpdateDisplayMode ( Index ) ;
}
2022-03-20 17:03:25 +00:00
bool CGraphicsBackend_SDL_GL : : UpdateDisplayMode ( int Index )
2021-12-13 17:42:21 +00:00
{
SDL_DisplayMode DisplayMode ;
if ( SDL_GetDesktopDisplayMode ( Index , & DisplayMode ) < 0 )
{
dbg_msg ( " gfx " , " unable to get display mode: %s " , SDL_GetError ( ) ) ;
return false ;
}
g_Config . m_GfxDesktopWidth = DisplayMode . w ;
g_Config . m_GfxDesktopHeight = DisplayMode . h ;
return true ;
2016-04-29 22:34:12 +00:00
}
2022-03-20 17:03:25 +00:00
int CGraphicsBackend_SDL_GL : : GetWindowScreen ( )
2016-04-29 22:34:12 +00:00
{
return SDL_GetWindowDisplayIndex ( m_pWindow ) ;
2016-04-29 19:07:10 +00:00
}
2022-03-20 17:03:25 +00:00
int CGraphicsBackend_SDL_GL : : WindowActive ( )
2012-01-03 20:39:10 +00:00
{
2021-12-25 17:44:44 +00:00
return m_pWindow & & SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_INPUT_FOCUS ;
2012-01-03 20:39:10 +00:00
}
2022-03-20 17:03:25 +00:00
int CGraphicsBackend_SDL_GL : : WindowOpen ( )
2012-01-03 20:39:10 +00:00
{
2021-12-25 17:44:44 +00:00
return m_pWindow & & SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_SHOWN ;
2014-10-18 14:17:36 +00:00
}
2012-01-03 20:39:10 +00:00
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_SDL_GL : : SetWindowGrab ( bool Grab )
2015-08-24 23:01:38 +00:00
{
SDL_SetWindowGrab ( m_pWindow , Grab ? SDL_TRUE : SDL_FALSE ) ;
}
2022-03-20 17:03:25 +00:00
bool CGraphicsBackend_SDL_GL : : ResizeWindow ( int w , int h , int RefreshRate )
2020-12-12 11:58:59 +00:00
{
2021-08-24 16:22:31 +00:00
// don't call resize events when the window is at fullscreen desktop
2021-12-25 17:44:44 +00:00
if ( ! m_pWindow | | ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN_DESKTOP ) = = SDL_WINDOW_FULLSCREEN_DESKTOP )
2022-01-15 15:20:01 +00:00
return false ;
2021-12-25 17:44:44 +00:00
// if the window is at fullscreen use SDL_SetWindowDisplayMode instead, suggested by SDL
if ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN )
2021-08-21 18:07:37 +00:00
{
2022-01-15 15:20:01 +00:00
# ifdef CONF_FAMILY_WINDOWS
2021-12-25 17:44:44 +00:00
// in windows make the window windowed mode first, this prevents strange window glitches (other games probably do something similar)
2022-07-10 19:00:40 +00:00
SetWindowParams ( 0 , true , true ) ;
2021-08-24 16:22:31 +00:00
# endif
2021-12-25 17:44:44 +00:00
SDL_DisplayMode SetMode = { } ;
SDL_DisplayMode ClosestMode = { } ;
SetMode . format = 0 ;
SetMode . w = w ;
SetMode . h = h ;
SetMode . refresh_rate = RefreshRate ;
SDL_SetWindowDisplayMode ( m_pWindow , SDL_GetClosestDisplayMode ( g_Config . m_GfxScreen , & SetMode , & ClosestMode ) ) ;
2022-01-15 15:20:01 +00:00
# ifdef CONF_FAMILY_WINDOWS
2022-10-25 16:51:56 +00:00
// now change it back to fullscreen, this will restore the above set state, bcs SDL saves fullscreen modes apart from other video modes (as of SDL 2.0.16)
2021-12-25 17:44:44 +00:00
// see implementation of SDL_SetWindowDisplayMode
2022-07-10 19:00:40 +00:00
SetWindowParams ( 1 , false , true ) ;
2021-08-24 16:22:31 +00:00
# endif
2022-01-15 15:20:01 +00:00
return true ;
2021-12-25 17:44:44 +00:00
}
else
{
SDL_SetWindowSize ( m_pWindow , w , h ) ;
if ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_MAXIMIZED )
// remove maximize flag
SDL_RestoreWindow ( m_pWindow ) ;
2021-08-21 18:07:37 +00:00
}
2022-01-15 15:20:01 +00:00
return false ;
2020-12-12 11:58:59 +00:00
}
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_SDL_GL : : GetViewportSize ( int & w , int & h )
2020-12-12 11:58:59 +00:00
{
SDL_GL_GetDrawableSize ( m_pWindow , & w , & h ) ;
}
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_SDL_GL : : NotifyWindow ( )
2014-10-18 14:17:36 +00:00
{
2021-06-04 23:34:26 +00:00
# if SDL_MAJOR_VERSION > 2 || (SDL_MAJOR_VERSION == 2 && SDL_PATCHLEVEL >= 16)
2021-10-16 17:37:51 +00:00
if ( SDL_FlashWindow ( m_pWindow , SDL_FlashOperation : : SDL_FLASH_UNTIL_FOCUSED ) ! = 0 )
2015-08-25 00:39:48 +00:00
{
2021-06-04 23:34:26 +00:00
// fails if SDL hasn't implemented it
2015-08-25 00:39:48 +00:00
return ;
}
2020-09-26 19:41:58 +00:00
# endif
2012-01-03 20:39:10 +00:00
}
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_SDL_GL : : WindowDestroyNtf ( uint32_t WindowID )
2022-01-20 09:49:31 +00:00
{
}
2022-03-20 17:03:25 +00:00
void CGraphicsBackend_SDL_GL : : WindowCreateNtf ( uint32_t WindowID )
2022-01-20 09:49:31 +00:00
{
m_pWindow = SDL_GetWindowFromID ( WindowID ) ;
}
2022-03-20 17:03:25 +00:00
TGLBackendReadPresentedImageData & CGraphicsBackend_SDL_GL : : GetReadPresentedImageDataFuncUnsafe ( )
{
return m_ReadPresentedImageDataFunc ;
}
2022-12-09 15:16:16 +00:00
IGraphicsBackend * CreateGraphicsBackend ( TTranslateFunc & & TranslateFunc ) { return new CGraphicsBackend_SDL_GL ( std : : move ( TranslateFunc ) ) ; }