2014-11-05 00:46:40 +00:00
# include <base/detect.h>
# if defined(CONF_FAMILY_WINDOWS)
2020-09-26 19:41:58 +00:00
// For FlashWindowEx, FLASHWINFO, FLASHW_TRAY
# define _WIN32_WINNT 0x0501
# define WINVER 0x0501
2014-11-05 00:46:40 +00:00
# endif
2012-01-03 20:39:10 +00:00
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
2017-12-02 21:19:57 +00:00
# include <engine/storage.h>
2017-10-20 07:08:49 +00:00
2020-09-26 19:41:58 +00:00
# include "SDL.h"
2021-04-30 22:42:37 +00:00
2020-09-26 19:41:58 +00:00
# include "SDL_syswm.h"
2015-08-24 20:46:28 +00:00
# include <base/detect.h>
2016-04-29 22:34:12 +00:00
# include <base/math.h>
2018-03-13 20:44:58 +00:00
# include <cmath>
2020-09-26 19:41:58 +00:00
# include <stdlib.h>
2012-01-03 20:39:10 +00:00
2021-01-31 20:54:04 +00:00
# include "SDL_hints.h"
2021-08-21 19:41:51 +00:00
# include "SDL_pixels.h"
# include "SDL_video.h"
2021-01-31 20:54:04 +00:00
2014-10-26 00:25:36 +00:00
# if defined(SDL_VIDEO_DRIVER_X11)
2020-09-26 19:41:58 +00:00
# include <X11/Xlib.h>
# include <X11/Xutil.h>
2014-10-26 00:25:36 +00:00
# endif
2014-10-28 00:12:11 +00:00
# include <engine/shared/config.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)
2020-09-26 19:41:58 +00:00
# include "video.h"
2016-08-27 19:10:27 +00:00
# endif
2012-01-03 20:39:10 +00:00
# include "backend_sdl.h"
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
# include "graphics_threaded.h"
2017-09-02 13:24:07 +00:00
2020-11-18 06:36:19 +00:00
# include <engine/shared/image_manipulation.h>
2021-08-21 19:41:51 +00:00
# include <engine/graphics.h>
2017-10-17 14:38:40 +00:00
# ifdef __MINGW32__
2020-09-26 19:41:58 +00:00
extern " C " {
int putenv ( const char * ) ;
2017-10-17 14:38:40 +00:00
}
# endif
2020-08-09 15:56:47 +00:00
/*
sync_barrier - creates a full hardware fence
*/
# if defined(__GNUC__)
2020-09-26 19:41:58 +00:00
inline void sync_barrier ( )
{
__sync_synchronize ( ) ;
}
2020-08-09 15:56:47 +00:00
# elif defined(_MSC_VER)
2020-09-26 19:41:58 +00:00
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
inline void sync_barrier ( )
{
MemoryBarrier ( ) ;
}
2020-08-09 15:56:47 +00:00
# else
2020-09-26 19:41:58 +00:00
# error missing atomic implementation for this compiler
2020-08-09 15:56:47 +00:00
# endif
2012-01-03 20:39:10 +00:00
// ------------ CGraphicsBackend_Threaded
void CGraphicsBackend_Threaded : : ThreadFunc ( void * pUser )
{
CGraphicsBackend_Threaded * pThis = ( CGraphicsBackend_Threaded * ) pUser ;
while ( ! pThis - > m_Shutdown )
{
2020-11-29 16:53:54 +00:00
pThis - > m_Activity . Wait ( ) ;
2012-01-03 20:39:10 +00:00
if ( pThis - > m_pBuffer )
{
2021-02-12 12:40:29 +00:00
# ifdef CONF_PLATFORM_MACOS
2020-09-26 19:41:58 +00:00
CAutoreleasePool AutoreleasePool ;
# endif
2012-01-03 20:39:10 +00:00
pThis - > m_pProcessor - > RunBuffer ( pThis - > m_pBuffer ) ;
2016-08-30 23:39:59 +00:00
2012-01-03 20:39:10 +00:00
sync_barrier ( ) ;
pThis - > m_pBuffer = 0x0 ;
2020-11-29 16:53:54 +00:00
pThis - > m_BufferDone . Signal ( ) ;
2012-01-03 20:39:10 +00:00
}
2020-09-26 19:41:58 +00:00
# if defined(CONF_VIDEORECORDER)
if ( IVideo : : Current ( ) )
IVideo : : Current ( ) - > NextVideoFrameThread ( ) ;
# endif
2012-01-03 20:39:10 +00:00
}
}
CGraphicsBackend_Threaded : : CGraphicsBackend_Threaded ( )
{
m_pBuffer = 0x0 ;
m_pProcessor = 0x0 ;
m_pThread = 0x0 ;
}
void CGraphicsBackend_Threaded : : StartProcessor ( ICommandProcessor * pProcessor )
{
m_Shutdown = false ;
m_pProcessor = pProcessor ;
2019-03-19 10:44:16 +00:00
m_pThread = thread_init ( ThreadFunc , this , " CGraphicsBackend_Threaded " ) ;
2020-11-29 16:53:54 +00:00
m_BufferDone . Signal ( ) ;
2012-01-03 20:39:10 +00:00
}
void CGraphicsBackend_Threaded : : StopProcessor ( )
{
m_Shutdown = true ;
2020-11-29 16:53:54 +00:00
m_Activity . Signal ( ) ;
2019-03-19 10:44:16 +00:00
if ( m_pThread )
thread_wait ( m_pThread ) ;
2012-01-03 20:39:10 +00:00
}
void CGraphicsBackend_Threaded : : RunBuffer ( CCommandBuffer * pBuffer )
{
WaitForIdle ( ) ;
m_pBuffer = pBuffer ;
2020-11-29 16:53:54 +00:00
m_Activity . Signal ( ) ;
2012-01-03 20:39:10 +00:00
}
bool CGraphicsBackend_Threaded : : IsIdle ( ) const
{
return m_pBuffer = = 0x0 ;
}
void CGraphicsBackend_Threaded : : WaitForIdle ( )
{
while ( m_pBuffer ! = 0x0 )
2020-11-29 16:53:54 +00:00
m_BufferDone . Wait ( ) ;
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 ;
SDL_GL_MakeCurrent ( m_pWindow , m_GLContext ) ;
2012-01-03 20:39:10 +00:00
}
void CCommandProcessorFragment_SDL : : Cmd_Shutdown ( const SCommand_Shutdown * pCommand )
{
2015-08-24 20:46:28 +00:00
SDL_GL_MakeCurrent ( NULL , NULL ) ;
2012-01-03 20:39:10 +00:00
}
void CCommandProcessorFragment_SDL : : Cmd_Swap ( const CCommandBuffer : : SCommand_Swap * pCommand )
{
2015-08-24 20:46:28 +00:00
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 )
{
* pCommand - > m_pRetOk = SDL_GL_SetSwapInterval ( pCommand - > m_VSync ) = = 0 ;
}
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
SDL_GL_MakeCurrent ( m_pWindow , m_GLContext ) ;
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. " ) ;
SDL_GL_MakeCurrent ( NULL , NULL ) ;
# endif
}
2012-01-03 20:39:10 +00:00
CCommandProcessorFragment_SDL : : CCommandProcessorFragment_SDL ( )
{
}
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 ;
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 ;
default : return false ;
}
return true ;
}
// ------------ CCommandProcessor_SDL_OpenGL
void CCommandProcessor_SDL_OpenGL : : RunBuffer ( CCommandBuffer * pBuffer )
{
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
{
2020-10-11 15:08:04 +00:00
if ( m_pOpenGL - > RunCommand ( pCommand ) )
2020-09-26 19:41:58 +00:00
continue ;
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
}
}
2021-04-30 22:42:37 +00:00
CCommandProcessor_SDL_OpenGL : : CCommandProcessor_SDL_OpenGL ( EBackendType BackendType , int OpenGLMajor , int OpenGLMinor , int OpenGLPatch )
2020-08-29 10:10:38 +00:00
{
2021-04-30 22:42:37 +00:00
m_BackendType = BackendType ;
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)
2021-04-30 22:42:37 +00:00
if ( OpenGLMajor < 3 )
{
2021-05-02 00:52:13 +00:00
m_pOpenGL = new CCommandProcessorFragment_OpenGLES ( ) ;
2021-04-30 22:42:37 +00:00
}
else
{
2021-05-02 00:52:13 +00:00
m_pOpenGL = 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)
2021-04-30 22:42:37 +00:00
if ( OpenGLMajor < 2 )
{
m_pOpenGL = new CCommandProcessorFragment_OpenGL ( ) ;
}
if ( OpenGLMajor = = 2 )
{
m_pOpenGL = new CCommandProcessorFragment_OpenGL2 ( ) ;
}
if ( OpenGLMajor = = 3 & & OpenGLMinor = = 0 )
{
m_pOpenGL = new CCommandProcessorFragment_OpenGL3 ( ) ;
}
else if ( ( OpenGLMajor = = 3 & & OpenGLMinor = = 3 ) | | OpenGLMajor > = 4 )
{
m_pOpenGL = new CCommandProcessorFragment_OpenGL3_3 ( ) ;
}
2021-05-02 00:52:13 +00:00
# endif
2020-08-29 10:10:38 +00:00
}
}
2020-09-30 21:51:33 +00:00
CCommandProcessor_SDL_OpenGL : : ~ CCommandProcessor_SDL_OpenGL ( )
{
delete m_pOpenGL ;
}
2012-01-03 20:39:10 +00:00
// ------------ CGraphicsBackend_SDL_OpenGL
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
//support graphic cards that are pretty old(and linux)
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
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
}
2021-08-18 10:03:42 +00:00
// Don't allow GL 3.3, if the driver doesn't support atleast OpenGL 4.5
# ifndef CONF_PLATFORM_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 ;
}
2021-04-30 22:42:37 +00:00
EBackendType CGraphicsBackend_SDL_OpenGL : : DetectBackend ( )
{
# ifndef CONF_BACKEND_OPENGL_ES
2021-05-02 00:52:13 +00:00
# ifdef CONF_BACKEND_OPENGL_ES3
const char * pEnvDriver = getenv ( " DDNET_DRIVER " ) ;
if ( pEnvDriver & & str_comp ( pEnvDriver , " GLES " ) = = 0 )
return BACKEND_TYPE_OPENGL_ES ;
else
return BACKEND_TYPE_OPENGL ;
# else
2021-04-30 22:42:37 +00:00
return BACKEND_TYPE_OPENGL ;
2021-05-02 00:52:13 +00:00
# endif
2021-04-30 22:42:37 +00:00
# else
return BACKEND_TYPE_OPENGL_ES ;
# endif
}
void CGraphicsBackend_SDL_OpenGL : : ClampDriverVersion ( EBackendType BackendType )
{
if ( BackendType = = BACKEND_TYPE_OPENGL )
{
//clamp the versions to existing versions(only for OpenGL major <= 3)
if ( g_Config . m_GfxOpenGLMajor = = 1 )
{
g_Config . m_GfxOpenGLMinor = clamp ( g_Config . m_GfxOpenGLMinor , 1 , 5 ) ;
if ( g_Config . m_GfxOpenGLMinor = = 2 )
g_Config . m_GfxOpenGLPatch = clamp ( g_Config . m_GfxOpenGLPatch , 0 , 1 ) ;
else
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 2 )
{
g_Config . m_GfxOpenGLMinor = clamp ( g_Config . m_GfxOpenGLMinor , 0 , 1 ) ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
else if ( g_Config . m_GfxOpenGLMajor = = 3 )
{
g_Config . m_GfxOpenGLMinor = clamp ( g_Config . m_GfxOpenGLMinor , 0 , 3 ) ;
if ( g_Config . m_GfxOpenGLMinor < 3 )
g_Config . m_GfxOpenGLMinor = 0 ;
g_Config . m_GfxOpenGLPatch = 0 ;
}
}
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)
if ( g_Config . m_GfxOpenGLMajor < 3 )
{
g_Config . m_GfxOpenGLMajor = 1 ;
g_Config . m_GfxOpenGLMinor = 0 ;
g_Config . m_GfxOpenGLPatch = 0 ;
// GLES also doesnt know GL_QUAD
g_Config . m_GfxQuadAsTriangle = 1 ;
}
2021-05-01 00:39:06 +00:00
# else
g_Config . m_GfxOpenGLMajor = 3 ;
g_Config . m_GfxOpenGLMinor = 0 ;
g_Config . m_GfxOpenGLPatch = 0 ;
# endif
2021-04-30 22:42:37 +00:00
}
}
bool CGraphicsBackend_SDL_OpenGL : : IsModernAPI ( EBackendType BackendType )
{
if ( BackendType = = BACKEND_TYPE_OPENGL )
return ( g_Config . m_GfxOpenGLMajor = = 3 & & g_Config . m_GfxOpenGLMinor = = 3 ) | | g_Config . m_GfxOpenGLMajor > = 4 ;
else if ( BackendType = = BACKEND_TYPE_OPENGL_ES )
return g_Config . m_GfxOpenGLMajor > = 3 ;
return false ;
}
2021-05-02 21:20:21 +00:00
void CGraphicsBackend_SDL_OpenGL : : GetDriverVersion ( EGraphicsDriverAgeType DriverAgeType , int & Major , int & Minor , int & Patch )
{
if ( m_BackendType = = BACKEND_TYPE_OPENGL )
{
if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_LEGACY )
{
Major = 1 ;
Minor = 4 ;
Patch = 0 ;
}
else if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_DEFAULT )
{
Major = 3 ;
Minor = 0 ;
Patch = 0 ;
}
else if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_MODERN )
{
Major = 3 ;
Minor = 3 ;
Patch = 0 ;
}
}
else if ( m_BackendType = = BACKEND_TYPE_OPENGL_ES )
{
if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_LEGACY )
{
Major = 1 ;
Minor = 0 ;
Patch = 0 ;
}
else if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_DEFAULT )
{
Major = 3 ;
Minor = 0 ;
Patch = 0 ;
}
else if ( DriverAgeType = = GRAPHICS_DRIVER_AGE_TYPE_MODERN )
{
Major = 3 ;
Minor = 0 ;
Patch = 0 ;
}
}
}
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 ;
}
void CGraphicsBackend_SDL_OpenGL : : GetVideoModes ( CVideoMode * pModes , int MaxModes , int * pNumModes , int HiDPIScale , int MaxWindowWidth , int MaxWindowHeight , int Screen )
{
SDL_DisplayMode DesktopMode ;
int maxModes = SDL_GetNumDisplayModes ( Screen ) ;
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)
bool IsFullscreenDestkop = m_pWindow ! = NULL & & ( ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN_DESKTOP ) = = SDL_WINDOW_FULLSCREEN_DESKTOP ) ;
bool CollectFullscreenModes = m_pWindow = = NULL | | ( ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN ) ! = 0 & & ! IsFullscreenDestkop ) ;
if ( SDL_GetDesktopDisplayMode ( Screen , & DesktopMode ) < 0 )
{
dbg_msg ( " gfx " , " unable to get display mode: %s " , SDL_GetError ( ) ) ;
}
static constexpr int ModeCount = 256 ;
SDL_DisplayMode aModes [ ModeCount ] ;
int NumModes = 0 ;
for ( int i = 0 ; i < maxModes & & NumModes < ModeCount ; i + + )
{
SDL_DisplayMode mode ;
if ( SDL_GetDisplayMode ( Screen , i , & mode ) < 0 )
{
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 ;
}
void CGraphicsBackend_SDL_OpenGL : : GetCurrentVideoMode ( CVideoMode & CurMode , int HiDPIScale , int MaxWindowWidth , int MaxWindowHeight , int Screen )
{
SDL_DisplayMode DPMode ;
if ( SDL_GetDesktopDisplayMode ( Screen , & DPMode ) < 0 )
{
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 ;
}
DisplayToVideoMode ( & CurMode , & DPMode , HiDPIScale , DPMode . refresh_rate ) ;
}
int CGraphicsBackend_SDL_OpenGL : : Init ( const char * pName , int * pScreen , int * pWidth , int * pHeight , int * pRefreshRate , int FsaaSamples , int Flags , int * pDesktopWidth , int * pDesktopHeight , int * pCurrentWidth , int * pCurrentHeight , IStorage * pStorage )
2018-04-13 19:34:12 +00:00
{
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
}
}
2021-05-02 21:20:21 +00:00
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
2021-05-02 21:20:21 +00:00
m_UseNewOpenGL = IsModernAPI ( m_BackendType ) ;
2018-08-02 18:52:51 +00:00
2021-04-30 22:42:37 +00:00
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MAJOR_VERSION , g_Config . m_GfxOpenGLMajor ) ;
SDL_GL_SetAttribute ( SDL_GL_CONTEXT_MINOR_VERSION , g_Config . m_GfxOpenGLMinor ) ;
dbg_msg ( " gfx " , " Created OpenGL %zu.%zu context. " , ( size_t ) g_Config . m_GfxOpenGLMajor , ( size_t ) g_Config . m_GfxOpenGLMinor ) ;
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
{
2021-04-30 22:42:37 +00:00
if ( g_Config . m_GfxOpenGLMajor = = 3 & & g_Config . m_GfxOpenGLMinor = = 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
}
2021-04-30 22:42:37 +00:00
else if ( m_UseNewOpenGL )
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
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 ;
GetVideoModes ( aModes , sizeof ( aModes ) / sizeof ( aModes [ 0 ] ) , & ModesCount , 1 , * pDesktopWidth , * pDesktopHeight , * pScreen ) ;
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
2020-08-26 13:15:06 +00:00
int SdlFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_GRABBED | SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS ;
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
2021-08-21 19:41:51 +00:00
bool IsFullscreen = ( SdlFlags & SDL_WINDOW_FULLSCREEN ) ! = 0 ;
// 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
if ( ( IsFullscreen & & ! SupportedResolution ) | | * pWidth = = 0 | | * pHeight = = 0 | | ( IsDesktopChanged & & ( * pWidth > * pDesktopWidth | | * pHeight > * pDesktopHeight ) ) )
{
* 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
2015-08-24 20:46:28 +00:00
SDL_GL_SetAttribute ( SDL_GL_DOUBLEBUFFER , 1 ) ;
2012-01-03 20:39:10 +00:00
if ( FsaaSamples )
{
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLEBUFFERS , 1 ) ;
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLESAMPLES , FsaaSamples ) ;
}
else
{
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLEBUFFERS , 0 ) ;
SDL_GL_SetAttribute ( SDL_GL_MULTISAMPLESAMPLES , 0 ) ;
}
2016-05-07 13:59:13 +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 ( ) ) ;
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_SDL_WINDOW_CREATE_FAILED ;
2015-08-24 20:46:28 +00:00
}
m_GLContext = SDL_GL_CreateContext ( m_pWindow ) ;
2012-01-03 20:39:10 +00:00
2015-08-24 20:46:28 +00:00
if ( m_GLContext = = NULL )
2012-01-03 20:39:10 +00:00
{
2021-04-30 22:42:37 +00:00
SDL_DestroyWindow ( m_pWindow ) ;
2015-08-24 20:46:28 +00:00
dbg_msg ( " gfx " , " unable to create OpenGL context: %s " , SDL_GetError ( ) ) ;
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_OPENGL_CONTEXT_FAILED ;
2015-07-09 00:08:14 +00:00
}
2017-10-20 07:08:49 +00:00
2020-08-29 10:10:38 +00:00
int GlewMajor = 0 ;
int GlewMinor = 0 ;
int GlewPatch = 0 ;
2021-05-02 21:20:21 +00:00
if ( ! BackendInitGlew ( m_BackendType , GlewMajor , GlewMinor , GlewPatch ) )
2021-04-30 22:42:37 +00:00
{
SDL_GL_DeleteContext ( m_GLContext ) ;
SDL_DestroyWindow ( m_pWindow ) ;
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_UNKNOWN ;
}
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
2021-05-02 21:20:21 +00:00
InitError = IsVersionSupportedGlew ( m_BackendType , g_Config . m_GfxOpenGLMajor , g_Config . m_GfxOpenGLMinor , g_Config . m_GfxOpenGLPatch , 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
if ( SdlFlags & SDL_WINDOW_ALLOW_HIGHDPI )
SDL_GL_GetDrawableSize ( m_pWindow , pCurrentWidth , pCurrentHeight ) ;
else
SDL_GetWindowSize ( m_pWindow , pCurrentWidth , pCurrentHeight ) ;
2020-09-26 19:41:58 +00:00
SDL_GL_SetSwapInterval ( Flags & IGraphicsBackend : : INITFLAG_VSYNC ? 1 : 0 ) ;
2015-08-24 20:46:28 +00:00
SDL_GL_MakeCurrent ( NULL , NULL ) ;
2012-01-03 20:39:10 +00:00
2020-08-29 10:10:38 +00:00
if ( InitError ! = 0 )
{
SDL_GL_DeleteContext ( m_GLContext ) ;
SDL_DestroyWindow ( m_pWindow ) ;
// try setting to glew supported version
g_Config . m_GfxOpenGLMajor = GlewMajor ;
g_Config . m_GfxOpenGLMinor = GlewMinor ;
g_Config . m_GfxOpenGLPatch = GlewPatch ;
2020-09-26 19:41:58 +00:00
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_OPENGL_VERSION_FAILED ;
}
2012-01-03 20:39:10 +00:00
// start the command processor
2021-05-02 21:20:21 +00:00
m_pProcessor = new CCommandProcessor_SDL_OpenGL ( m_BackendType , g_Config . m_GfxOpenGLMajor , g_Config . m_GfxOpenGLMinor , g_Config . m_GfxOpenGLPatch ) ;
2012-01-03 20:39:10 +00:00
StartProcessor ( m_pProcessor ) ;
2020-09-26 19:41:58 +00:00
2020-11-05 19:38:37 +00:00
mem_zero ( m_aErrorString , sizeof ( m_aErrorString ) / sizeof ( m_aErrorString [ 0 ] ) ) ;
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 ) ;
2020-08-29 10:10:38 +00:00
//run sdl first to have the context in the thread
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 )
{
2021-05-02 00:52:13 +00:00
CCommandProcessorFragment_OpenGLBase : : SCommand_Init CmdOpenGL ;
2020-08-29 15:44:23 +00:00
CmdOpenGL . m_pTextureMemoryUsage = & m_TextureMemoryUsage ;
CmdOpenGL . m_pStorage = pStorage ;
CmdOpenGL . m_pCapabilities = & m_Capabilites ;
CmdOpenGL . m_pInitError = & InitError ;
2021-04-30 22:42:37 +00:00
CmdOpenGL . m_RequestedMajor = g_Config . m_GfxOpenGLMajor ;
CmdOpenGL . m_RequestedMinor = g_Config . m_GfxOpenGLMinor ;
CmdOpenGL . m_RequestedPatch = g_Config . m_GfxOpenGLPatch ;
CmdOpenGL . m_GlewMajor = GlewMajor ;
CmdOpenGL . m_GlewMinor = GlewMinor ;
CmdOpenGL . m_GlewPatch = GlewPatch ;
CmdOpenGL . m_pErrStringPtr = & pErrorStr ;
CmdOpenGL . m_pVendorString = m_aVendorString ;
CmdOpenGL . m_pVersionString = m_aVersionString ;
CmdOpenGL . m_pRendererString = m_aRendererString ;
2021-05-02 21:20:21 +00:00
CmdOpenGL . m_RequestedBackend = m_BackendType ;
2021-04-07 17:03:07 +00:00
CmdBuffer . AddCommandUnsafe ( CmdOpenGL ) ;
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
2021-05-02 00:52:13 +00:00
CCommandProcessorFragment_OpenGLBase : : 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 ( ) ;
// stop and delete the processor
StopProcessor ( ) ;
delete m_pProcessor ;
m_pProcessor = 0 ;
SDL_GL_DeleteContext ( m_GLContext ) ;
SDL_DestroyWindow ( m_pWindow ) ;
// try setting to version string's supported version
if ( InitError = = - 2 )
{
g_Config . m_GfxOpenGLMajor = m_Capabilites . m_ContextMajor ;
g_Config . m_GfxOpenGLMinor = m_Capabilites . m_ContextMinor ;
g_Config . m_GfxOpenGLPatch = m_Capabilites . m_ContextPatch ;
}
2020-11-05 19:38:37 +00:00
if ( pErrorStr ! = NULL )
{
str_copy ( m_aErrorString , pErrorStr , sizeof ( m_aErrorString ) / sizeof ( m_aErrorString [ 0 ] ) ) ;
}
2020-08-29 10:10:38 +00:00
return EGraphicsBackendErrorCodes : : GRAPHICS_BACKEND_ERROR_CODE_OPENGL_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
{
2021-08-21 19:41:51 +00:00
CCommandBuffer : : SCommand_Update_Viewport CmdSDL ;
CmdSDL . m_X = 0 ;
CmdSDL . m_Y = 0 ;
2017-10-23 16:02:18 +00:00
2021-08-21 19:41:51 +00:00
CmdSDL . m_Width = * pCurrentWidth ;
CmdSDL . m_Height = * pCurrentHeight ;
CmdBuffer . AddCommandUnsafe ( CmdSDL ) ;
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
}
int CGraphicsBackend_SDL_OpenGL : : Shutdown ( )
{
// issue a shutdown command
CCommandBuffer CmdBuffer ( 1024 , 512 ) ;
2021-05-02 00:52:13 +00:00
CCommandProcessorFragment_OpenGLBase : : 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
2012-01-03 20:39:10 +00:00
// stop and delete the processor
StopProcessor ( ) ;
delete m_pProcessor ;
m_pProcessor = 0 ;
2015-08-24 20:46:28 +00:00
SDL_GL_DeleteContext ( m_GLContext ) ;
SDL_DestroyWindow ( m_pWindow ) ;
2012-01-03 20:39:10 +00:00
SDL_QuitSubSystem ( SDL_INIT_VIDEO ) ;
return 0 ;
}
2012-10-06 21:31:02 +00:00
int CGraphicsBackend_SDL_OpenGL : : MemoryUsage ( ) const
{
return m_TextureMemoryUsage ;
}
2012-01-03 20:39:10 +00:00
void CGraphicsBackend_SDL_OpenGL : : Minimize ( )
{
2015-08-24 20:46:28 +00:00
SDL_MinimizeWindow ( m_pWindow ) ;
2012-01-03 20:39:10 +00:00
}
void CGraphicsBackend_SDL_OpenGL : : Maximize ( )
{
// TODO: SDL
}
2021-01-31 20:54:04 +00:00
void CGraphicsBackend_SDL_OpenGL : : SetWindowParams ( int FullscreenMode , bool IsBorderless )
2016-04-29 19:07:10 +00:00
{
2021-01-31 20:54:04 +00:00
if ( FullscreenMode > 0 )
{
if ( FullscreenMode = = 1 )
{
2021-04-17 15:49:41 +00:00
# if defined(CONF_PLATFORM_MACOS) || defined(CONF_PLATFORM_HAIKU) // 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
2021-01-31 20:54:04 +00:00
}
else if ( FullscreenMode = = 2 )
{
SDL_SetWindowFullscreen ( m_pWindow , SDL_WINDOW_FULLSCREEN_DESKTOP ) ;
}
}
else
{
SDL_SetWindowFullscreen ( m_pWindow , 0 ) ;
SDL_SetWindowBordered ( m_pWindow , SDL_bool ( ! IsBorderless ) ) ;
}
2016-04-29 22:34:12 +00:00
}
bool CGraphicsBackend_SDL_OpenGL : : SetWindowScreen ( int Index )
{
if ( Index > = 0 & & Index < m_NumScreens )
{
SDL_Rect ScreenPos ;
if ( SDL_GetDisplayBounds ( Index , & ScreenPos ) = = 0 )
{
SDL_SetWindowPosition ( m_pWindow ,
2016-05-07 14:35:31 +00:00
SDL_WINDOWPOS_CENTERED_DISPLAY ( Index ) ,
SDL_WINDOWPOS_CENTERED_DISPLAY ( Index ) ) ;
2016-04-29 22:34:12 +00:00
return true ;
}
}
return false ;
}
int CGraphicsBackend_SDL_OpenGL : : GetWindowScreen ( )
{
return SDL_GetWindowDisplayIndex ( m_pWindow ) ;
2016-04-29 19:07:10 +00:00
}
2012-01-03 20:39:10 +00:00
int CGraphicsBackend_SDL_OpenGL : : WindowActive ( )
{
2020-09-26 19:41:58 +00:00
return SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_INPUT_FOCUS ;
2012-01-03 20:39:10 +00:00
}
int CGraphicsBackend_SDL_OpenGL : : WindowOpen ( )
{
2020-09-26 19:41:58 +00:00
return SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_SHOWN ;
2014-10-18 14:17:36 +00:00
}
2012-01-03 20:39:10 +00:00
2015-08-24 23:01:38 +00:00
void CGraphicsBackend_SDL_OpenGL : : SetWindowGrab ( bool Grab )
{
SDL_SetWindowGrab ( m_pWindow , Grab ? SDL_TRUE : SDL_FALSE ) ;
}
2021-08-21 19:41:51 +00:00
void CGraphicsBackend_SDL_OpenGL : : 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
if ( ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN_DESKTOP ) ! = SDL_WINDOW_FULLSCREEN_DESKTOP )
2021-08-21 18:07:37 +00:00
{
2021-08-24 16:22:31 +00:00
// if the window is at fullscreen use SDL_SetWindowDisplayMode instead, suggested by SDL
if ( SDL_GetWindowFlags ( m_pWindow ) & SDL_WINDOW_FULLSCREEN )
{
# ifdef CONF_PLATFORM_WINDOWS
// in windows make the window windowed mode first, this prevents strange window glitches (other games probably do something similar)
SetWindowParams ( 0 , 1 ) ;
# endif
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 ) ) ;
# ifdef CONF_PLATFORM_WINDOWS
// now change it back to fullscreen, this will restore the above set state, bcs SDL saves fullscreen modes appart from other video modes (as of SDL 2.0.16)
// see implementation of SDL_SetWindowDisplayMode
SetWindowParams ( 1 , 0 ) ;
# endif
}
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
}
2020-12-12 11:58:59 +00:00
}
void CGraphicsBackend_SDL_OpenGL : : GetViewportSize ( int & w , int & h )
{
SDL_GL_GetDrawableSize ( m_pWindow , & w , & h ) ;
}
2014-10-18 14:17:36 +00:00
void CGraphicsBackend_SDL_OpenGL : : NotifyWindow ( )
{
2015-08-25 00:39:48 +00:00
// get window handle
SDL_SysWMinfo info ;
SDL_VERSION ( & info . version ) ;
if ( ! SDL_GetWindowWMInfo ( m_pWindow , & info ) )
{
dbg_msg ( " gfx " , " unable to obtain window handle " ) ;
return ;
}
2020-09-26 19:41:58 +00:00
# if defined(CONF_FAMILY_WINDOWS)
FLASHWINFO desc ;
desc . cbSize = sizeof ( desc ) ;
desc . hwnd = info . info . win . window ;
desc . dwFlags = FLASHW_TRAY ;
desc . uCount = 3 ; // flash 3 times
desc . dwTimeout = 0 ;
FlashWindowEx ( & desc ) ;
2021-02-12 12:40:29 +00:00
# elif defined(SDL_VIDEO_DRIVER_X11) && !defined(CONF_PLATFORM_MACOS)
2021-05-07 00:06:01 +00:00
Display * pX11Dpy = info . info . x11 . display ;
Window X11Win = info . info . x11 . window ;
static Atom s_DemandsAttention = XInternAtom ( pX11Dpy , " _NET_WM_STATE_DEMANDS_ATTENTION " , true ) ;
static Atom s_WmState = XInternAtom ( pX11Dpy , " _NET_WM_STATE " , true ) ;
XEvent SndNtfyEvent = { ClientMessage } ;
SndNtfyEvent . xclient . window = X11Win ;
SndNtfyEvent . xclient . message_type = s_WmState ;
SndNtfyEvent . xclient . format = 32 ;
SndNtfyEvent . xclient . data . l [ 0 ] = 1 ; // _NET_WM_STATE_ADD
SndNtfyEvent . xclient . data . l [ 1 ] = s_DemandsAttention ;
SndNtfyEvent . xclient . data . l [ 2 ] = 0 ;
SndNtfyEvent . xclient . data . l [ 3 ] = 1 ; // normal application
SndNtfyEvent . xclient . data . l [ 4 ] = 0 ;
XSendEvent ( pX11Dpy , XDefaultRootWindow ( pX11Dpy ) , False , SubstructureNotifyMask | SubstructureRedirectMask , & SndNtfyEvent ) ;
2020-09-26 19:41:58 +00:00
# endif
2012-01-03 20:39:10 +00:00
}
IGraphicsBackend * CreateGraphicsBackend ( ) { return new CGraphicsBackend_SDL_OpenGL ; }