2010-04-25 00:31:27 +00:00
/*
2009-02-09 21:15:56 +00:00
* Copyright ( C ) 2007 - 2009 Gabest
* http : //www.gabest.org
*
* This Program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
2010-04-25 00:31:27 +00:00
*
2009-02-09 21:15:56 +00:00
* This Program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
2010-04-25 00:31:27 +00:00
*
2009-02-09 21:15:56 +00:00
* You should have received a copy of the GNU General Public License
* along with GNU Make ; see the file COPYING . If not , write to
2012-09-09 18:16:11 +00:00
* the Free Software Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 , USA USA .
2009-02-09 21:15:56 +00:00
* http : //www.gnu.org/copyleft/gpl.html
*
*/
# include "stdafx.h"
2011-02-19 03:36:30 +00:00
# include "GSdx.h"
2009-02-09 21:15:56 +00:00
# include "GSUtil.h"
2018-11-16 18:41:37 +00:00
# include "Renderers/SW/GSRendererSW.h"
# include "Renderers/Null/GSRendererNull.h"
# include "Renderers/Null/GSDeviceNull.h"
# include "Renderers/OpenGL/GSDeviceOGL.h"
# include "Renderers/OpenGL/GSRendererOGL.h"
2017-05-24 19:12:30 +00:00
# include "GSLzma.h"
2011-02-19 03:36:30 +00:00
2016-01-27 15:33:10 +00:00
# ifdef _WIN32
2011-02-19 03:36:30 +00:00
2018-11-16 18:41:37 +00:00
# include "Renderers/DX11/GSRendererDX11.h"
# include "Renderers/DX11/GSDevice11.h"
# include "Window/GSWndDX.h"
# include "Window/GSWndWGL.h"
# include "Window/GSSettingsDlg.h"
2009-02-09 21:15:56 +00:00
2011-02-19 03:36:30 +00:00
static HRESULT s_hr = E_FAIL ;
2011-02-20 01:57:43 +00:00
# else
2011-02-20 16:09:46 +00:00
2018-11-16 18:41:37 +00:00
# include "Window/GSWndEGL.h"
2011-11-16 22:17:37 +00:00
2020-04-09 09:32:07 +00:00
# ifdef __APPLE__
# include <gtk/gtk.h>
# include <CoreFoundation/CoreFoundation.h>
# endif
2011-02-20 01:57:43 +00:00
extern bool RunLinuxDialog ( ) ;
2011-02-20 16:09:46 +00:00
2011-02-19 03:36:30 +00:00
# endif
2010-12-03 03:04:55 +00:00
2009-02-09 21:15:56 +00:00
# define PS2E_LT_GS 0x01
# define PS2E_GS_VERSION 0x0006
# define PS2E_X86 0x01 // 32 bit
# define PS2E_X86_64 0x02 // 64 bit
2009-05-22 01:22:52 +00:00
static GSRenderer * s_gs = NULL ;
2009-02-09 21:15:56 +00:00
static void ( * s_irq ) ( ) = NULL ;
2009-05-14 16:41:52 +00:00
static uint8 * s_basemem = NULL ;
2017-05-21 20:14:34 +00:00
static int s_vsync = 0 ;
2009-12-04 03:24:59 +00:00
static bool s_exclusive = true ;
2020-09-20 07:16:55 +00:00
static std : : string s_renderer_name ;
2015-07-08 17:19:22 +00:00
bool gsopen_done = false ; // crash guard for GSgetTitleInfo2 and GSKeyEvent (replace with lock?)
2010-01-28 02:53:10 +00:00
2009-05-14 16:41:52 +00:00
EXPORT_C_ ( uint32 ) PS2EgetLibType ( )
2009-02-09 21:15:56 +00:00
{
return PS2E_LT_GS ;
}
2011-02-19 23:41:52 +00:00
EXPORT_C_ ( const char * ) PS2EgetLibName ( )
2009-02-09 21:15:56 +00:00
{
return GSUtil : : GetLibName ( ) ;
}
2009-05-14 16:41:52 +00:00
EXPORT_C_ ( uint32 ) PS2EgetLibVersion2 ( uint32 type )
2009-02-09 21:15:56 +00:00
{
2015-06-24 18:00:13 +00:00
const uint32 revision = 1 ;
2020-02-10 19:22:27 +00:00
const uint32 build = 2 ;
2009-02-09 21:15:56 +00:00
return ( build < < 0 ) | ( revision < < 8 ) | ( PS2E_GS_VERSION < < 16 ) | ( PLUGIN_VERSION < < 24 ) ;
}
2009-05-14 16:41:52 +00:00
EXPORT_C_ ( uint32 ) PS2EgetCpuPlatform ( )
2009-02-09 21:15:56 +00:00
{
2014-07-15 23:21:03 +00:00
# ifdef _M_AMD64
2011-02-19 03:36:30 +00:00
2009-02-09 21:15:56 +00:00
return PS2E_X86_64 ;
2011-02-19 03:36:30 +00:00
2009-02-09 21:15:56 +00:00
# else
2011-02-19 03:36:30 +00:00
2009-02-09 21:15:56 +00:00
return PS2E_X86 ;
2011-02-19 03:36:30 +00:00
2009-02-09 21:15:56 +00:00
# endif
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSsetBaseMem ( uint8 * mem )
2009-02-09 21:15:56 +00:00
{
2009-09-18 18:45:37 +00:00
s_basemem = mem ;
2011-02-19 03:36:30 +00:00
if ( s_gs )
2009-09-18 18:45:37 +00:00
{
2011-02-19 03:36:30 +00:00
s_gs - > SetRegsMem ( s_basemem ) ;
2009-09-18 18:45:37 +00:00
}
2009-02-09 21:15:56 +00:00
}
2009-12-19 18:30:56 +00:00
EXPORT_C GSsetSettingsDir ( const char * dir )
{
theApp . SetConfigDir ( dir ) ;
}
2011-02-19 03:36:30 +00:00
EXPORT_C_ ( int ) GSinit ( )
2009-02-09 21:15:56 +00:00
{
2009-06-23 04:12:32 +00:00
if ( ! GSUtil : : CheckSSE ( ) )
{
return - 1 ;
}
2016-07-06 23:21:31 +00:00
// Vector instructions must be avoided when initialising GSdx since PCSX2
// can crash if the CPU does not support the instruction set.
// Initialise it here instead - it's not ideal since we have to strip the
// const type qualifier from all the affected variables.
2016-07-23 22:13:04 +00:00
theApp . Init ( ) ;
2017-05-19 08:41:49 +00:00
GSUtil : : Init ( ) ;
2016-07-06 23:21:31 +00:00
GSBlock : : InitVectors ( ) ;
GSClut : : InitVectors ( ) ;
GSRendererSW : : InitVectors ( ) ;
GSVector4i : : InitVectors ( ) ;
GSVector4 : : InitVectors ( ) ;
# if _M_SSE >= 0x500
GSVector8 : : InitVectors ( ) ;
# endif
# if _M_SSE >= 0x501
GSVector8i : : InitVectors ( ) ;
# endif
GSVertexTrace : : InitVectors ( ) ;
2016-11-24 09:16:35 +00:00
if ( g_const = = nullptr )
return - 1 ;
2016-11-28 18:40:25 +00:00
else
g_const - > Init ( ) ;
2016-11-24 09:16:35 +00:00
2016-01-27 15:33:10 +00:00
# ifdef _WIN32
2009-09-17 07:40:38 +00:00
s_hr = : : CoInitializeEx ( NULL , COINIT_MULTITHREADED ) ;
2011-02-25 01:01:00 +00:00
# endif
2011-02-24 23:46:26 +00:00
2009-02-09 21:15:56 +00:00
return 0 ;
}
EXPORT_C GSshutdown ( )
{
2014-06-13 21:32:50 +00:00
gsopen_done = false ;
2010-04-25 00:31:27 +00:00
delete s_gs ;
2016-11-24 09:16:35 +00:00
s_gs = nullptr ;
2011-02-19 03:36:30 +00:00
2017-03-24 08:53:33 +00:00
theApp . SetCurrentRendererType ( GSRendererType : : Undefined ) ;
2015-06-05 22:21:54 +00:00
2016-01-27 15:33:10 +00:00
# ifdef _WIN32
2009-02-09 21:15:56 +00:00
if ( SUCCEEDED ( s_hr ) )
{
: : CoUninitialize ( ) ;
s_hr = E_FAIL ;
}
2009-05-18 11:08:04 +00:00
# endif
2009-02-09 21:15:56 +00:00
}
2009-09-17 07:40:38 +00:00
EXPORT_C GSclose ( )
2009-02-09 21:15:56 +00:00
{
2014-06-13 21:32:50 +00:00
gsopen_done = false ;
2011-02-19 03:36:30 +00:00
if ( s_gs = = NULL ) return ;
2009-05-18 11:08:04 +00:00
2010-05-23 17:26:37 +00:00
s_gs - > ResetDevice ( ) ;
2013-06-16 07:05:57 +00:00
// Opengl requirement: It must be done before the Detach() of
// the context
2010-05-23 17:26:37 +00:00
delete s_gs - > m_dev ;
2011-02-19 03:36:30 +00:00
2010-05-23 17:26:37 +00:00
s_gs - > m_dev = NULL ;
2013-06-16 09:55:37 +00:00
if ( s_gs - > m_wnd )
2013-06-16 09:43:34 +00:00
{
s_gs - > m_wnd - > Detach ( ) ;
}
2009-09-17 07:40:38 +00:00
}
2015-11-06 22:25:55 +00:00
static int _GSopen ( void * * dsp , const char * title , GSRendererType renderer , int threads = - 1 )
2009-09-17 07:40:38 +00:00
{
GSDevice * dev = NULL ;
2017-02-23 17:27:22 +00:00
bool old_api = * dsp = = NULL ;
2009-02-09 21:15:56 +00:00
2017-03-24 08:52:01 +00:00
// Fresh start up or config file changed
2015-10-26 21:30:34 +00:00
if ( renderer = = GSRendererType : : Undefined )
2009-09-19 11:20:31 +00:00
{
2016-05-24 19:52:06 +00:00
renderer = static_cast < GSRendererType > ( theApp . GetConfigI ( " Renderer " ) ) ;
2017-03-24 08:52:01 +00:00
# ifdef _WIN32
if ( renderer = = GSRendererType : : Default )
renderer = GSUtil : : GetBestRenderer ( ) ;
# endif
2009-09-19 11:20:31 +00:00
}
2011-02-17 03:24:37 +00:00
if ( threads = = - 1 )
{
2016-05-24 19:52:06 +00:00
threads = theApp . GetConfigI ( " extrathreads " ) ;
2011-02-17 03:24:37 +00:00
}
2009-09-18 18:45:37 +00:00
try
2009-02-09 21:15:56 +00:00
{
2017-03-24 08:53:33 +00:00
if ( theApp . GetCurrentRendererType ( ) ! = renderer )
2017-02-22 21:54:51 +00:00
{
2017-02-23 17:27:22 +00:00
// Emulator has made a render change request, which requires a completely
// new s_gs -- if the emu doesn't save/restore the GS state across this
// GSopen call then they'll get corrupted graphics, but that's not my problem.
delete s_gs ;
s_gs = NULL ;
2017-03-24 08:53:33 +00:00
theApp . SetCurrentRendererType ( renderer ) ;
2017-02-23 17:27:22 +00:00
}
std : : shared_ptr < GSWnd > window ;
{
// Select the window first to detect the GL requirement
std : : vector < std : : shared_ptr < GSWnd > > wnds ;
switch ( renderer )
{
case GSRendererType : : OGL_HW :
case GSRendererType : : OGL_SW :
2020-08-09 03:39:56 +00:00
# if defined(__unix__)
2017-02-23 17:27:22 +00:00
// Note: EGL code use GLX otherwise maybe it could be also compatible with Windows
// Yes OpenGL code isn't complicated enough !
2017-04-29 08:39:53 +00:00
switch ( GSWndEGL : : SelectPlatform ( ) ) {
# if GS_EGL_X11
case EGL_PLATFORM_X11_KHR :
wnds . push_back ( std : : make_shared < GSWndEGL_X11 > ( ) ) ;
break ;
# endif
# if GS_EGL_WL
case EGL_PLATFORM_WAYLAND_KHR :
wnds . push_back ( std : : make_shared < GSWndEGL_WL > ( ) ) ;
break ;
# endif
default :
break ;
}
2020-04-09 09:32:07 +00:00
# elif defined(__APPLE__)
// No windows available for macOS at the moment
2017-02-22 21:54:51 +00:00
# else
2017-02-23 17:27:22 +00:00
wnds . push_back ( std : : make_shared < GSWndWGL > ( ) ) ;
2017-02-22 21:54:51 +00:00
# endif
2017-02-23 17:27:22 +00:00
break ;
default :
2017-02-22 21:54:51 +00:00
# ifdef _WIN32
2017-02-23 17:27:22 +00:00
wnds . push_back ( std : : make_shared < GSWndDX > ( ) ) ;
2020-04-09 09:32:07 +00:00
# elif defined(__APPLE__)
// No windows available for macOS at the moment
2018-11-16 22:50:25 +00:00
# else
2020-08-09 03:39:56 +00:00
wnds . push_back ( std : : make_shared < GSWndEGL_X11 > ( ) ) ;
2017-02-22 21:54:51 +00:00
# endif
2017-02-23 17:27:22 +00:00
break ;
}
2017-02-22 21:54:51 +00:00
2017-02-23 17:27:22 +00:00
int w = theApp . GetConfigI ( " ModeWidth " ) ;
int h = theApp . GetConfigI ( " ModeHeight " ) ;
# if defined(__unix__)
void * win_handle = ( void * ) ( ( uptr * ) ( dsp ) + 1 ) ;
# else
void * win_handle = * dsp ;
# endif
2017-02-22 21:54:51 +00:00
2017-02-23 17:27:22 +00:00
for ( auto & wnd : wnds )
{
try
{
if ( old_api )
{
// old-style API expects us to create and manage our own window:
wnd - > Create ( title , w , h ) ;
2015-06-05 22:21:54 +00:00
2017-02-23 17:27:22 +00:00
wnd - > Show ( ) ;
2015-06-05 22:21:54 +00:00
2017-02-23 17:27:22 +00:00
* dsp = wnd - > GetDisplay ( ) ;
}
else
{
wnd - > Attach ( win_handle , false ) ;
}
window = wnd ; // Previous code will throw if window isn't supported
break ;
}
catch ( GSDXRecoverableError )
{
wnd - > Detach ( ) ;
}
}
if ( ! window )
{
GSclose ( ) ;
return - 1 ;
}
2015-06-05 22:21:54 +00:00
}
2010-05-23 17:26:37 +00:00
2020-09-20 07:16:55 +00:00
std : : string renderer_name ;
2015-06-25 14:45:45 +00:00
switch ( renderer )
2009-09-17 07:40:38 +00:00
{
2014-09-15 13:49:16 +00:00
default :
2016-01-27 15:33:10 +00:00
# ifdef _WIN32
2015-10-26 21:30:34 +00:00
case GSRendererType : : DX1011_HW :
2015-06-25 14:45:45 +00:00
dev = new GSDevice11 ( ) ;
2020-09-20 07:16:55 +00:00
s_renderer_name = " D3D11 " ;
renderer_name = " Direct3D 11 " ;
2014-09-15 13:49:16 +00:00
break ;
# endif
2015-10-26 21:30:34 +00:00
case GSRendererType : : OGL_HW :
2020-09-20 07:16:55 +00:00
dev = new GSDeviceOGL ( ) ;
s_renderer_name = " OGL " ;
renderer_name = " OpenGL " ;
break ;
2015-10-26 21:30:34 +00:00
case GSRendererType : : OGL_SW :
2015-06-25 14:45:45 +00:00
dev = new GSDeviceOGL ( ) ;
2020-09-20 07:16:55 +00:00
s_renderer_name = " SW " ;
renderer_name = " Software " ;
break ;
case GSRendererType : : Null :
dev = new GSDeviceNull ( ) ;
s_renderer_name = " NULL " ;
renderer_name = " Null " ;
2014-09-15 13:49:16 +00:00
break ;
}
2012-01-13 18:10:05 +00:00
2020-09-20 07:16:55 +00:00
printf ( " Current Renderer: %s \n " , renderer_name . c_str ( ) ) ;
2015-11-11 18:34:12 +00:00
2015-06-25 14:45:45 +00:00
if ( dev = = NULL )
2014-09-15 13:49:16 +00:00
{
return - 1 ;
2012-01-13 18:10:05 +00:00
}
2014-09-15 13:49:16 +00:00
2015-06-25 14:45:45 +00:00
if ( s_gs = = NULL )
2009-09-18 18:45:37 +00:00
{
2015-06-25 14:45:45 +00:00
switch ( renderer )
2009-09-18 18:45:37 +00:00
{
2010-04-25 00:31:27 +00:00
default :
2016-01-27 15:33:10 +00:00
# ifdef _WIN32
2015-10-26 21:30:34 +00:00
case GSRendererType : : DX1011_HW :
2015-06-25 14:45:45 +00:00
s_gs = ( GSRenderer * ) new GSRendererDX11 ( ) ;
2014-09-15 13:49:16 +00:00
break ;
2013-01-14 09:15:39 +00:00
# endif
2015-10-26 21:30:34 +00:00
case GSRendererType : : OGL_HW :
2015-06-25 14:45:45 +00:00
s_gs = ( GSRenderer * ) new GSRendererOGL ( ) ;
2014-09-15 13:49:16 +00:00
break ;
2015-10-26 21:30:34 +00:00
case GSRendererType : : OGL_SW :
2014-09-15 13:49:16 +00:00
s_gs = new GSRendererSW ( threads ) ;
break ;
2016-05-01 16:33:53 +00:00
case GSRendererType : : Null :
2014-09-15 13:49:16 +00:00
s_gs = new GSRendererNull ( ) ;
break ;
2012-01-13 18:10:05 +00:00
}
2014-12-23 18:39:02 +00:00
if ( s_gs = = NULL )
return - 1 ;
2009-09-18 23:48:12 +00:00
}
2017-02-23 17:27:22 +00:00
s_gs - > m_wnd = window ;
2009-02-09 21:15:56 +00:00
}
2015-06-25 14:45:45 +00:00
catch ( std : : exception & ex )
2009-09-18 18:45:37 +00:00
{
// Allowing std exceptions to escape the scope of the plugin callstack could
// be problematic, because of differing typeids between DLL and EXE compilations.
2009-09-18 22:13:40 +00:00
// ('new' could throw std::alloc)
2009-09-18 18:45:37 +00:00
2011-02-17 03:24:37 +00:00
printf ( " GSdx error: Exception caught in GSopen: %s " , ex . what ( ) ) ;
2009-09-18 18:45:37 +00:00
return - 1 ;
}
2009-09-18 19:54:56 +00:00
s_gs - > SetRegsMem ( s_basemem ) ;
s_gs - > SetIrqCallback ( s_irq ) ;
2011-02-19 03:36:30 +00:00
s_gs - > SetVSync ( s_vsync ) ;
2009-02-09 21:15:56 +00:00
2017-02-23 17:27:22 +00:00
if ( ! old_api )
2011-02-17 03:24:37 +00:00
s_gs - > SetMultithreaded ( true ) ;
2011-02-19 03:36:30 +00:00
2017-02-23 17:27:22 +00:00
if ( ! s_gs - > CreateDevice ( dev ) )
2009-09-17 07:40:38 +00:00
{
2010-06-05 04:06:24 +00:00
// This probably means the user has DX11 configured with a video card that is only DX9
// compliant. Cound mean drivr issues of some sort also, but to be sure, that's the most
// common cause of device creation errors. :) --air
2009-09-17 07:40:38 +00:00
GSclose ( ) ;
2011-02-17 03:24:37 +00:00
2009-09-17 07:40:38 +00:00
return - 1 ;
}
2015-08-13 06:46:41 +00:00
2016-05-24 19:52:06 +00:00
if ( renderer = = GSRendererType : : OGL_HW & & theApp . GetConfigI ( " debug_glsl_shader " ) = = 2 ) {
2015-08-13 06:46:41 +00:00
printf ( " GSdx: test OpenGL shader. Please wait... \n \n " ) ;
2015-08-22 10:10:25 +00:00
static_cast < GSDeviceOGL * > ( s_gs - > m_dev ) - > SelfShaderTest ( ) ;
2015-08-13 06:46:41 +00:00
printf ( " \n GSdx: test OpenGL shader done. It will now exit \n " ) ;
return - 1 ;
}
2014-01-25 19:36:45 +00:00
2009-02-09 21:15:56 +00:00
return 0 ;
}
2016-09-18 20:44:10 +00:00
EXPORT_C_ ( void ) GSosdLog ( const char * utf8 , uint32 color )
{
2018-12-14 14:26:51 +00:00
if ( s_gs & & s_gs - > m_dev ) s_gs - > m_dev - > m_osd . Log ( utf8 ) ;
2016-09-18 20:44:10 +00:00
}
EXPORT_C_ ( void ) GSosdMonitor ( const char * key , const char * value , uint32 color )
{
2018-12-14 14:26:51 +00:00
if ( s_gs & & s_gs - > m_dev ) s_gs - > m_dev - > m_osd . Monitor ( key , value ) ;
2016-09-18 20:44:10 +00:00
}
2011-02-19 03:36:30 +00:00
EXPORT_C_ ( int ) GSopen2 ( void * * dsp , uint32 flags )
2009-09-17 07:40:38 +00:00
{
2015-06-21 14:03:17 +00:00
static bool stored_toggle_state = false ;
2020-09-20 07:16:55 +00:00
const bool toggle_state = ! ! ( flags & 4 ) ;
2015-06-21 14:03:17 +00:00
2020-09-20 07:16:55 +00:00
auto current_renderer = theApp . GetCurrentRendererType ( ) ;
2017-03-24 08:52:01 +00:00
2020-09-20 07:16:55 +00:00
if ( current_renderer ! = GSRendererType : : Undefined & & stored_toggle_state ! = toggle_state )
2009-09-17 07:40:38 +00:00
{
2020-09-20 07:16:55 +00:00
// SW -> HW and HW -> SW (F9 Switch)
switch ( current_renderer )
{
# ifdef _WIN32
case GSRendererType : : DX1011_HW :
current_renderer = GSRendererType : : OGL_SW ;
break ;
# endif
case GSRendererType : : OGL_SW :
# ifdef _WIN32
{
const auto config_renderer = static_cast < GSRendererType > (
theApp . GetConfigI ( " Renderer " )
) ;
if ( current_renderer = = config_renderer )
current_renderer = GSUtil : : GetBestRenderer ( ) ;
else
current_renderer = config_renderer ;
}
# else
current_renderer = GSRendererType : : OGL_HW ;
# endif
break ;
case GSRendererType : : OGL_HW :
current_renderer = GSRendererType : : OGL_SW ;
break ;
default :
current_renderer = GSRendererType : : OGL_SW ;
break ;
2013-07-19 19:25:50 +00:00
}
2009-09-17 07:40:38 +00:00
}
2015-06-21 14:03:17 +00:00
stored_toggle_state = toggle_state ;
2009-09-17 07:40:38 +00:00
2020-09-20 07:16:55 +00:00
int retval = _GSopen ( dsp , " " , current_renderer ) ;
2011-02-17 03:24:37 +00:00
2012-01-04 23:19:17 +00:00
if ( s_gs ! = NULL )
s_gs - > SetAspectRatio ( 0 ) ; // PCSX2 manages the aspect ratios
2009-12-04 03:24:59 +00:00
2014-01-25 19:53:12 +00:00
gsopen_done = true ;
2009-12-01 05:59:43 +00:00
return retval ;
2009-09-17 07:40:38 +00:00
}
2015-11-06 22:25:55 +00:00
EXPORT_C_ ( int ) GSopen ( void * * dsp , const char * title , int mt )
2009-02-09 21:15:56 +00:00
{
2015-10-26 21:30:34 +00:00
GSRendererType renderer = GSRendererType : : Default ;
2009-12-04 03:24:59 +00:00
2009-12-04 04:50:49 +00:00
// Legacy GUI expects to acquire vsync from the configuration files.
2011-02-17 03:24:37 +00:00
2017-05-21 20:14:34 +00:00
s_vsync = theApp . GetConfigI ( " vsync " ) ;
2009-12-04 03:24:59 +00:00
2009-05-11 08:18:00 +00:00
if ( mt = = 2 )
{
// pcsx2 sent a switch renderer request
2010-04-25 00:31:27 +00:00
mt = 1 ;
2009-03-05 20:00:41 +00:00
}
2010-04-25 00:31:27 +00:00
else
2009-05-11 08:18:00 +00:00
{
// normal init
2011-02-17 03:24:37 +00:00
2016-05-24 19:52:06 +00:00
renderer = static_cast < GSRendererType > ( theApp . GetConfigI ( " Renderer " ) ) ;
2009-03-05 20:00:41 +00:00
}
2009-05-11 08:18:00 +00:00
2011-02-19 03:36:30 +00:00
* dsp = NULL ;
2009-09-18 19:54:56 +00:00
int retval = _GSopen ( dsp , title , renderer ) ;
2011-02-17 03:24:37 +00:00
if ( retval = = 0 & & s_gs )
2009-09-18 19:54:56 +00:00
{
2011-02-17 03:24:37 +00:00
s_gs - > SetMultithreaded ( ! ! mt ) ;
2009-09-18 19:54:56 +00:00
}
2010-04-25 00:31:27 +00:00
2014-01-25 19:36:45 +00:00
gsopen_done = true ;
2009-09-18 19:54:56 +00:00
return retval ;
2009-02-09 21:15:56 +00:00
}
EXPORT_C GSreset ( )
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > Reset ( ) ;
}
catch ( GSDXRecoverableError )
{
}
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSgifSoftReset ( uint32 mask )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > SoftReset ( mask ) ;
}
catch ( GSDXRecoverableError )
{
}
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSwriteCSR ( uint32 csr )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > WriteCSR ( csr ) ;
}
catch ( GSDXRecoverableError )
{
}
2009-02-09 21:15:56 +00:00
}
2014-05-02 21:03:02 +00:00
EXPORT_C GSinitReadFIFO ( uint8 * mem )
{
2015-05-17 10:19:38 +00:00
GL_PERF ( " Init Read FIFO1 " ) ;
2014-05-02 21:03:02 +00:00
try
{
s_gs - > InitReadFIFO ( mem , 1 ) ;
}
catch ( GSDXRecoverableError )
{
}
2016-11-09 22:41:02 +00:00
catch ( const std : : bad_alloc & )
{
fprintf ( stderr , " GSdx: Memory allocation error \n " ) ;
}
2014-05-02 21:03:02 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSreadFIFO ( uint8 * mem )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > ReadFIFO ( mem , 1 ) ;
}
catch ( GSDXRecoverableError )
{
}
2016-11-09 22:41:02 +00:00
catch ( const std : : bad_alloc & )
{
fprintf ( stderr , " GSdx: Memory allocation error \n " ) ;
}
2009-02-09 21:15:56 +00:00
}
2014-05-02 21:03:02 +00:00
EXPORT_C GSinitReadFIFO2 ( uint8 * mem , uint32 size )
{
2015-05-17 10:19:38 +00:00
GL_PERF ( " Init Read FIFO2 " ) ;
2014-05-02 21:03:02 +00:00
try
{
s_gs - > InitReadFIFO ( mem , size ) ;
}
catch ( GSDXRecoverableError )
{
}
2016-11-09 22:41:02 +00:00
catch ( const std : : bad_alloc & )
{
fprintf ( stderr , " GSdx: Memory allocation error \n " ) ;
}
2014-05-02 21:03:02 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSreadFIFO2 ( uint8 * mem , uint32 size )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > ReadFIFO ( mem , size ) ;
}
catch ( GSDXRecoverableError )
{
}
2016-11-09 22:41:02 +00:00
catch ( const std : : bad_alloc & )
{
fprintf ( stderr , " GSdx: Memory allocation error \n " ) ;
}
2009-02-09 21:15:56 +00:00
}
2010-07-19 15:49:30 +00:00
EXPORT_C GSgifTransfer ( const uint8 * mem , uint32 size )
2010-07-11 04:38:33 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > Transfer < 3 > ( mem , size ) ;
}
catch ( GSDXRecoverableError )
{
}
2010-07-11 04:38:33 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSgifTransfer1 ( uint8 * mem , uint32 addr )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > Transfer < 0 > ( const_cast < uint8 * > ( mem ) + addr , ( 0x4000 - addr ) / 16 ) ;
}
catch ( GSDXRecoverableError )
{
}
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSgifTransfer2 ( uint8 * mem , uint32 size )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > Transfer < 1 > ( const_cast < uint8 * > ( mem ) , size ) ;
}
catch ( GSDXRecoverableError )
{
}
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSgifTransfer3 ( uint8 * mem , uint32 size )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
s_gs - > Transfer < 2 > ( const_cast < uint8 * > ( mem ) , size ) ;
}
catch ( GSDXRecoverableError )
{
}
2009-02-09 21:15:56 +00:00
}
EXPORT_C GSvsync ( int field )
{
2012-06-11 02:31:44 +00:00
try
{
2016-01-27 15:33:10 +00:00
# ifdef _WIN32
2009-05-18 11:08:04 +00:00
2013-01-04 11:41:51 +00:00
if ( s_gs - > m_wnd - > IsManaged ( ) )
2012-06-11 02:31:44 +00:00
{
MSG msg ;
2009-05-18 11:08:04 +00:00
2012-06-11 02:31:44 +00:00
memset ( & msg , 0 , sizeof ( msg ) ) ;
2009-05-18 11:08:04 +00:00
2012-06-11 02:31:44 +00:00
while ( msg . message ! = WM_QUIT & & PeekMessage ( & msg , NULL , 0 , 0 , PM_REMOVE ) )
{
TranslateMessage ( & msg ) ;
DispatchMessage ( & msg ) ;
}
2009-12-01 05:59:43 +00:00
}
2011-02-17 18:22:47 +00:00
2009-05-18 11:08:04 +00:00
# endif
2012-06-11 02:31:44 +00:00
s_gs - > VSync ( field ) ;
}
catch ( GSDXRecoverableError )
{
}
2016-11-09 22:41:02 +00:00
catch ( const std : : bad_alloc & )
{
fprintf ( stderr , " GSdx: Memory allocation error \n " ) ;
}
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C_ ( uint32 ) GSmakeSnapshot ( char * path )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
2017-05-26 15:26:46 +00:00
std : : string s { path } ;
2012-06-11 02:31:44 +00:00
2020-07-29 00:16:45 +00:00
if ( ! s . empty ( ) )
2012-06-11 02:31:44 +00:00
{
2020-07-29 00:16:45 +00:00
// Allows for providing a complete path
2020-09-16 00:32:35 +00:00
std : : string extension = s . substr ( s . size ( ) - 4 , 4 ) ;
std : : transform ( extension . begin ( ) , extension . end ( ) , extension . begin ( ) , tolower ) ;
if ( extension = = " .png " )
2020-07-29 00:16:45 +00:00
return s_gs - > MakeSnapshot ( s ) ;
else if ( s [ s . length ( ) - 1 ] ! = DIRECTORY_SEPARATOR )
s = s + DIRECTORY_SEPARATOR ;
2012-06-11 02:31:44 +00:00
}
2011-02-17 03:24:37 +00:00
2012-06-11 02:31:44 +00:00
return s_gs - > MakeSnapshot ( s + " gsdx " ) ;
}
catch ( GSDXRecoverableError )
2011-02-17 03:24:37 +00:00
{
2012-06-11 02:31:44 +00:00
return false ;
2011-02-17 03:24:37 +00:00
}
2009-02-09 21:15:56 +00:00
}
2009-05-18 11:08:04 +00:00
EXPORT_C GSkeyEvent ( GSKeyEventData * e )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
{
2014-09-15 13:49:16 +00:00
if ( gsopen_done )
{
2014-06-13 21:32:50 +00:00
s_gs - > KeyEvent ( e ) ;
2014-09-15 13:49:16 +00:00
}
2012-06-11 02:31:44 +00:00
}
catch ( GSDXRecoverableError )
{
}
2009-02-09 21:15:56 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C_ ( int ) GSfreeze ( int mode , GSFreezeData * data )
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
try
2009-02-09 21:15:56 +00:00
{
2012-06-11 02:31:44 +00:00
if ( mode = = FREEZE_SAVE )
{
return s_gs - > Freeze ( data , false ) ;
}
else if ( mode = = FREEZE_SIZE )
{
return s_gs - > Freeze ( data , true ) ;
}
else if ( mode = = FREEZE_LOAD )
{
return s_gs - > Defrost ( data ) ;
}
2009-02-09 21:15:56 +00:00
}
2012-06-11 02:31:44 +00:00
catch ( GSDXRecoverableError )
2009-02-09 21:15:56 +00:00
{
}
return 0 ;
}
EXPORT_C GSconfigure ( )
{
2012-06-11 02:31:44 +00:00
try
{
if ( ! GSUtil : : CheckSSE ( ) ) return ;
2009-11-18 08:13:28 +00:00
2016-07-23 22:13:04 +00:00
theApp . Init ( ) ;
2016-01-27 15:33:10 +00:00
# ifdef _WIN32
2015-08-22 17:32:55 +00:00
GSDialog : : InitCommonControls ( ) ;
2015-07-13 05:41:48 +00:00
if ( GSSettingsDlg ( ) . DoModal ( ) = = IDOK )
2009-09-18 23:48:12 +00:00
{
2015-06-21 14:03:17 +00:00
// Force a reload of the gs state
2017-03-24 08:53:33 +00:00
theApp . SetCurrentRendererType ( GSRendererType : : Undefined ) ;
2009-09-18 23:48:12 +00:00
}
2011-02-19 03:36:30 +00:00
2020-04-09 09:32:07 +00:00
# elif defined(__APPLE__)
// Rest of macOS UI doesn't use GTK so we need to init it now
gtk_init ( nullptr , nullptr ) ;
// GTK expects us to be using its event loop, rather than Cocoa's
// If we call its stuff right now, it'll attempt to drain a static autorelease pool that was already drained by Cocoa (see https://github.com/GNOME/gtk/blob/8c1072fad1cb6a2e292fce2441b4a571f173ce0f/gdk/quartz/gdkeventloop-quartz.c#L640-L646)
// We can convince it that touching that pool would be unsafe by running all GTK calls within a CFRunLoop
// (Blocks submitted to the main queue by dispatch_async are run by its CFRunLoop)
dispatch_async ( dispatch_get_main_queue ( ) , ^ {
if ( RunLinuxDialog ( ) ) {
theApp . ReloadConfig ( ) ;
// Force a reload of the gs state
theApp . SetCurrentRendererType ( GSRendererType : : Undefined ) ;
}
} ) ;
2011-02-19 03:36:30 +00:00
# else
2013-06-15 15:03:44 +00:00
if ( RunLinuxDialog ( ) ) {
theApp . ReloadConfig ( ) ;
2015-06-21 14:03:17 +00:00
// Force a reload of the gs state
2017-03-24 08:53:33 +00:00
theApp . SetCurrentRendererType ( GSRendererType : : Undefined ) ;
2011-02-20 01:57:43 +00:00
}
2013-06-15 15:03:44 +00:00
2011-02-19 03:36:30 +00:00
# endif
2015-06-06 06:50:27 +00:00
2012-06-11 02:31:44 +00:00
} catch ( GSDXRecoverableError )
{
}
2009-02-09 21:15:56 +00:00
}
2011-02-19 03:36:30 +00:00
EXPORT_C_ ( int ) GStest ( )
2009-02-09 21:15:56 +00:00
{
2009-11-16 00:40:09 +00:00
if ( ! GSUtil : : CheckSSE ( ) )
return - 1 ;
2009-02-09 21:15:56 +00:00
return 0 ;
}
EXPORT_C GSabout ( )
{
}
EXPORT_C GSirqCallback ( void ( * irq ) ( ) )
{
s_irq = irq ;
2011-02-17 03:24:37 +00:00
if ( s_gs )
2009-09-18 19:54:56 +00:00
{
s_gs - > SetIrqCallback ( s_irq ) ;
}
2009-02-09 21:15:56 +00:00
}
2011-11-08 13:22:54 +00:00
void pt ( const char * str ) {
2011-08-30 07:11:36 +00:00
struct tm * current ;
time_t now ;
time ( & now ) ;
current = localtime ( & now ) ;
printf ( " %02i:%02i:%02i%s " , current - > tm_hour , current - > tm_min , current - > tm_sec , str ) ;
}
2020-09-12 22:53:45 +00:00
EXPORT_C_ ( std : : wstring * ) GSsetupRecording ( int start )
2009-08-16 11:35:30 +00:00
{
2014-02-11 21:47:43 +00:00
if ( s_gs = = NULL ) {
printf ( " GSdx: no s_gs for recording \n " ) ;
2020-09-12 22:53:45 +00:00
return nullptr ;
2014-02-11 21:47:43 +00:00
}
2020-04-09 09:32:07 +00:00
# if defined(__unix__) || defined(__APPLE__)
2016-05-24 19:52:06 +00:00
if ( ! theApp . GetConfigB ( " capture_enabled " ) ) {
2015-05-19 09:53:56 +00:00
printf ( " GSdx: Recording is disabled \n " ) ;
2020-09-12 22:53:45 +00:00
return nullptr ;
2015-05-19 09:53:56 +00:00
}
# endif
2020-09-12 22:53:45 +00:00
std : : wstring * filename = nullptr ;
2010-06-24 20:25:33 +00:00
if ( start & 1 )
2011-02-17 03:24:37 +00:00
{
2014-02-12 12:52:03 +00:00
printf ( " GSdx: Recording start command \n " ) ;
2020-09-12 22:53:45 +00:00
filename = s_gs - > BeginCapture ( ) ;
if ( filename )
{
2011-08-30 07:11:36 +00:00
pt ( " - Capture started \n " ) ;
2020-09-12 22:53:45 +00:00
}
else
{
2015-09-21 03:17:30 +00:00
pt ( " - Capture cancelled \n " ) ;
2020-09-12 22:53:45 +00:00
return nullptr ;
2015-09-21 03:17:30 +00:00
}
2011-02-17 03:24:37 +00:00
}
2010-06-24 20:25:33 +00:00
else
2011-02-17 03:24:37 +00:00
{
2014-02-12 12:52:03 +00:00
printf ( " GSdx: Recording end command \n " ) ;
2010-06-24 20:25:33 +00:00
s_gs - > EndCapture ( ) ;
2011-08-30 07:11:36 +00:00
pt ( " - Capture ended \n " ) ;
2011-02-17 03:24:37 +00:00
}
2010-04-25 00:31:27 +00:00
2020-09-12 22:53:45 +00:00
return filename ;
2009-08-16 11:35:30 +00:00
}
2009-05-14 16:41:52 +00:00
EXPORT_C GSsetGameCRC ( uint32 crc , int options )
2009-02-09 21:15:56 +00:00
{
2012-06-20 18:51:30 +00:00
s_gs - > SetGameCRC ( crc , options ) ;
2009-02-09 21:15:56 +00:00
}
2009-07-15 19:44:06 +00:00
EXPORT_C GSgetLastTag ( uint32 * tag )
2009-02-09 21:15:56 +00:00
{
s_gs - > GetLastTag ( tag ) ;
}
2010-12-03 21:18:29 +00:00
EXPORT_C GSgetTitleInfo2 ( char * dest , size_t length )
2010-01-28 02:53:10 +00:00
{
2020-09-20 07:16:55 +00:00
std : : string s ;
s . append ( s_renderer_name ) ;
2013-08-28 08:44:16 +00:00
// TODO: this gets called from a different thread concurrently with GSOpen (on linux)
2015-07-08 17:19:22 +00:00
if ( gsopen_done & & s_gs ! = NULL & & s_gs - > m_GStitleInfoBuffer [ 0 ] )
2010-12-03 03:04:55 +00:00
{
2015-03-03 17:29:21 +00:00
std : : lock_guard < std : : mutex > lock ( s_gs - > m_pGSsetTitle_Crit ) ;
2011-02-19 03:36:30 +00:00
2015-06-17 18:14:57 +00:00
s . append ( " | " ) . append ( s_gs - > m_GStitleInfoBuffer ) ;
2011-02-19 03:36:30 +00:00
if ( s . size ( ) > length - 1 )
{
s = s . substr ( 0 , length - 1 ) ;
}
2010-12-03 03:04:55 +00:00
}
2011-02-19 03:36:30 +00:00
strcpy ( dest , s . c_str ( ) ) ;
2010-01-28 02:53:10 +00:00
}
2009-02-09 21:15:56 +00:00
EXPORT_C GSsetFrameSkip ( int frameskip )
{
s_gs - > SetFrameSkip ( frameskip ) ;
}
2017-05-21 20:14:34 +00:00
EXPORT_C GSsetVsync ( int vsync )
2009-12-03 15:49:12 +00:00
{
2017-05-21 20:14:34 +00:00
s_vsync = vsync ;
2011-02-17 03:24:37 +00:00
if ( s_gs )
{
2011-02-19 03:36:30 +00:00
s_gs - > SetVSync ( s_vsync ) ;
2011-02-17 03:24:37 +00:00
}
2009-12-03 15:49:12 +00:00
}
2009-10-31 01:06:23 +00:00
2009-12-04 03:24:59 +00:00
EXPORT_C GSsetExclusive ( int enabled )
{
s_exclusive = ! ! enabled ;
2011-02-17 03:24:37 +00:00
if ( s_gs )
{
2011-02-19 03:36:30 +00:00
s_gs - > SetVSync ( s_vsync ) ;
2011-02-17 03:24:37 +00:00
}
2009-12-04 03:24:59 +00:00
}
2016-01-27 15:33:10 +00:00
# ifdef _WIN32
2009-05-18 11:08:04 +00:00
2011-02-16 03:19:36 +00:00
# include <io.h>
# include <fcntl.h>
class Console
{
HANDLE m_console ;
2017-05-26 15:26:46 +00:00
std : : string m_title ;
2011-02-16 03:19:36 +00:00
public :
Console : : Console ( LPCSTR title , bool open )
: m_console ( NULL )
, m_title ( title )
{
if ( open ) Open ( ) ;
}
Console : : ~ Console ( )
{
Close ( ) ;
}
void Console : : Open ( )
{
if ( m_console = = NULL )
{
2011-02-19 03:36:30 +00:00
CONSOLE_SCREEN_BUFFER_INFO csbiInfo ;
2011-02-16 03:19:36 +00:00
AllocConsole ( ) ;
SetConsoleTitle ( m_title . c_str ( ) ) ;
m_console = GetStdHandle ( STD_OUTPUT_HANDLE ) ;
COORD size ;
size . X = 100 ;
size . Y = 300 ;
SetConsoleScreenBufferSize ( m_console , size ) ;
GetConsoleScreenBufferInfo ( m_console , & csbiInfo ) ;
SMALL_RECT rect ;
rect = csbiInfo . srWindow ;
rect . Right = rect . Left + 99 ;
rect . Bottom = rect . Top + 64 ;
SetConsoleWindowInfo ( m_console , TRUE , & rect ) ;
2017-03-23 01:33:35 +00:00
freopen ( " CONOUT$ " , " w " , stdout ) ;
freopen ( " CONOUT$ " , " w " , stderr ) ;
2011-02-16 03:19:36 +00:00
2017-03-23 01:33:35 +00:00
setvbuf ( stdout , nullptr , _IONBF , 0 ) ;
setvbuf ( stderr , nullptr , _IONBF , 0 ) ;
2011-02-16 03:19:36 +00:00
}
}
void Console : : Close ( )
{
if ( m_console ! = NULL )
{
2011-02-19 03:36:30 +00:00
FreeConsole ( ) ;
2011-02-16 03:19:36 +00:00
m_console = NULL ;
}
}
} ;
2009-09-19 11:20:31 +00:00
// lpszCmdLine:
// First parameter is the renderer.
// Second parameter is the gs file to load and run.
2011-02-17 03:24:37 +00:00
2009-02-09 21:15:56 +00:00
EXPORT_C GSReplay ( HWND hwnd , HINSTANCE hinst , LPSTR lpszCmdLine , int nCmdShow )
{
2015-10-26 21:30:34 +00:00
GSRendererType renderer = GSRendererType : : Undefined ;
2009-02-09 21:15:56 +00:00
{
char * start = lpszCmdLine ;
char * end = NULL ;
long n = strtol ( lpszCmdLine , & end , 10 ) ;
2015-10-26 21:30:34 +00:00
if ( end > start ) { renderer = static_cast < GSRendererType > ( n ) ; lpszCmdLine = end ; }
2009-02-09 21:15:56 +00:00
}
while ( * lpszCmdLine = = ' ' ) lpszCmdLine + + ;
: : SetPriorityClass ( : : GetCurrentProcess ( ) , HIGH_PRIORITY_CLASS ) ;
2017-05-24 19:12:30 +00:00
Console console { " GSdx " , true } ;
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
const std : : string f { lpszCmdLine } ;
const bool is_xz = f . size ( ) > = 4 & & f . compare ( f . size ( ) - 3 , 3 , " .xz " ) = = 0 ;
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
auto file = is_xz
? std : : unique_ptr < GSDumpFile > { std : : make_unique < GSDumpLzma > ( lpszCmdLine , nullptr ) }
: std : : unique_ptr < GSDumpFile > { std : : make_unique < GSDumpRaw > ( lpszCmdLine , nullptr ) } ;
2009-12-04 04:50:49 +00:00
2017-05-24 19:12:30 +00:00
GSinit ( ) ;
2011-02-19 03:36:30 +00:00
2017-05-24 19:12:30 +00:00
std : : array < uint8 , 0x2000 > regs ;
GSsetBaseMem ( regs . data ( ) ) ;
2009-02-09 21:15:56 +00:00
2017-05-21 20:14:34 +00:00
s_vsync = theApp . GetConfigI ( " vsync " ) ;
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
HWND hWnd = nullptr ;
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
_GSopen ( ( void * * ) & hWnd , " " , renderer ) ;
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
uint32 crc ;
file - > Read ( & crc , 4 ) ;
GSsetGameCRC ( crc , 0 ) ;
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
{
GSFreezeData fd ;
file - > Read ( & fd . size , 4 ) ;
std : : vector < uint8 > freeze_data ( fd . size ) ;
fd . data = freeze_data . data ( ) ;
file - > Read ( fd . data , fd . size ) ;
GSfreeze ( FREEZE_LOAD , & fd ) ;
}
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
file - > Read ( regs . data ( ) , 0x2000 ) ;
2012-01-05 02:40:24 +00:00
2017-05-24 19:12:30 +00:00
GSvsync ( 1 ) ;
2012-01-05 02:40:24 +00:00
2017-05-24 19:12:30 +00:00
struct Packet { uint8 type , param ; uint32 size , addr ; std : : vector < uint8 > buff ; } ;
2012-01-05 02:40:24 +00:00
2017-05-24 19:12:30 +00:00
auto read_packet = [ & file ] ( uint8 type ) {
Packet p ;
p . type = type ;
2012-01-05 02:40:24 +00:00
2017-05-24 19:12:30 +00:00
switch ( p . type ) {
case 0 :
file - > Read ( & p . param , 1 ) ;
file - > Read ( & p . size , 4 ) ;
switch ( p . param ) {
2012-01-05 02:40:24 +00:00
case 0 :
2017-05-24 19:12:30 +00:00
p . buff . resize ( 0x4000 ) ;
p . addr = 0x4000 - p . size ;
file - > Read ( & p . buff [ p . addr ] , p . size ) ;
2012-01-05 02:40:24 +00:00
break ;
case 1 :
case 2 :
case 3 :
2017-05-24 19:12:30 +00:00
p . buff . resize ( p . size ) ;
file - > Read ( p . buff . data ( ) , p . size ) ;
2012-01-05 02:40:24 +00:00
break ;
}
2017-05-24 19:12:30 +00:00
break ;
case 1 :
file - > Read ( & p . param , 1 ) ;
break ;
case 2 :
file - > Read ( & p . size , 4 ) ;
break ;
case 3 :
p . buff . resize ( 0x2000 ) ;
file - > Read ( p . buff . data ( ) , 0x2000 ) ;
break ;
2012-01-05 02:40:24 +00:00
}
2017-05-24 19:12:30 +00:00
return p ;
} ;
2012-01-05 02:40:24 +00:00
2017-05-24 19:12:30 +00:00
std : : list < Packet > packets ;
uint8 type ;
while ( file - > Read ( & type , 1 ) )
packets . push_back ( read_packet ( type ) ) ;
2011-02-07 01:59:05 +00:00
2017-05-24 19:12:30 +00:00
Sleep ( 100 ) ;
2012-01-05 02:40:24 +00:00
2017-05-24 19:12:30 +00:00
std : : vector < uint8 > buff ;
while ( IsWindowVisible ( hWnd ) )
{
for ( auto & p : packets )
2011-02-07 01:59:05 +00:00
{
2017-05-24 19:12:30 +00:00
switch ( p . type )
2011-02-07 01:59:05 +00:00
{
case 0 :
2017-05-24 19:12:30 +00:00
switch ( p . param )
2011-02-07 01:59:05 +00:00
{
2017-05-24 19:12:30 +00:00
case 0 : GSgifTransfer1 ( p . buff . data ( ) , p . addr ) ; break ;
case 1 : GSgifTransfer2 ( p . buff . data ( ) , p . size / 16 ) ; break ;
case 2 : GSgifTransfer3 ( p . buff . data ( ) , p . size / 16 ) ; break ;
case 3 : GSgifTransfer ( p . buff . data ( ) , p . size / 16 ) ; break ;
2011-02-07 01:59:05 +00:00
}
break ;
case 1 :
2017-05-24 19:12:30 +00:00
GSvsync ( p . param ) ;
2011-02-07 01:59:05 +00:00
break ;
case 2 :
2017-05-24 19:12:30 +00:00
if ( buff . size ( ) < p . size ) buff . resize ( p . size ) ;
GSreadFIFO2 ( p . buff . data ( ) , p . size / 16 ) ;
2011-02-07 01:59:05 +00:00
break ;
case 3 :
2017-05-24 19:12:30 +00:00
memcpy ( regs . data ( ) , p . buff . data ( ) , 0x2000 ) ;
2011-02-07 01:59:05 +00:00
break ;
}
}
2017-05-24 19:12:30 +00:00
}
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
Sleep ( 100 ) ;
2009-02-09 21:15:56 +00:00
2017-05-24 19:12:30 +00:00
GSclose ( ) ;
GSshutdown ( ) ;
2009-02-09 21:15:56 +00:00
}
EXPORT_C GSBenchmark ( HWND hwnd , HINSTANCE hinst , LPSTR lpszCmdLine , int nCmdShow )
{
: : SetPriorityClass ( : : GetCurrentProcess ( ) , HIGH_PRIORITY_CLASS ) ;
2014-09-15 13:49:16 +00:00
Console console ( " GSdx " , true ) ;
2009-02-09 21:15:56 +00:00
if ( 1 )
{
2014-09-15 13:49:16 +00:00
GSLocalMemory * mem = new GSLocalMemory ( ) ;
2009-02-09 21:15:56 +00:00
2010-04-25 00:31:27 +00:00
static struct { int psm ; const char * name ; } s_format [ ] =
2009-02-09 21:15:56 +00:00
{
{ PSM_PSMCT32 , " 32 " } ,
{ PSM_PSMCT24 , " 24 " } ,
{ PSM_PSMCT16 , " 16 " } ,
{ PSM_PSMCT16S , " 16S " } ,
{ PSM_PSMT8 , " 8 " } ,
{ PSM_PSMT4 , " 4 " } ,
{ PSM_PSMT8H , " 8H " } ,
{ PSM_PSMT4HL , " 4HL " } ,
{ PSM_PSMT4HH , " 4HH " } ,
{ PSM_PSMZ32 , " 32Z " } ,
{ PSM_PSMZ24 , " 24Z " } ,
{ PSM_PSMZ16 , " 16Z " } ,
{ PSM_PSMZ16S , " 16ZS " } ,
} ;
2011-02-07 01:59:05 +00:00
uint8 * ptr = ( uint8 * ) _aligned_malloc ( 1024 * 1024 * 4 , 32 ) ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
for ( int i = 0 ; i < 1024 * 1024 * 4 ; i + + ) ptr [ i ] = ( uint8 ) i ;
2009-02-09 21:15:56 +00:00
2010-04-25 00:31:27 +00:00
//
2009-02-09 21:15:56 +00:00
for ( int tbw = 5 ; tbw < = 10 ; tbw + + )
{
int n = 256 < < ( ( 10 - tbw ) * 2 ) ;
int w = 1 < < tbw ;
int h = 1 < < tbw ;
2014-09-15 13:49:16 +00:00
printf ( " %d x %d \n \n " , w , h ) ;
2009-02-09 21:15:56 +00:00
2013-06-29 12:02:03 +00:00
for ( size_t i = 0 ; i < countof ( s_format ) ; i + + )
2009-02-09 21:15:56 +00:00
{
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ s_format [ i ] . psm ] ;
GSLocalMemory : : writeImage wi = psm . wi ;
GSLocalMemory : : readImage ri = psm . ri ;
GSLocalMemory : : readTexture rtx = psm . rtx ;
GSLocalMemory : : readTexture rtxP = psm . rtxP ;
GIFRegBITBLTBUF BITBLTBUF ;
BITBLTBUF . SBP = 0 ;
BITBLTBUF . SBW = w / 64 ;
BITBLTBUF . SPSM = s_format [ i ] . psm ;
BITBLTBUF . DBP = 0 ;
BITBLTBUF . DBW = w / 64 ;
BITBLTBUF . DPSM = s_format [ i ] . psm ;
2010-04-25 00:31:27 +00:00
2009-02-09 21:15:56 +00:00
GIFRegTRXPOS TRXPOS ;
TRXPOS . SSAX = 0 ;
TRXPOS . SSAY = 0 ;
TRXPOS . DSAX = 0 ;
TRXPOS . DSAY = 0 ;
GIFRegTRXREG TRXREG ;
TRXREG . RRW = w ;
TRXREG . RRH = h ;
2009-05-14 16:41:52 +00:00
GSVector4i r ( 0 , 0 , w , h ) ;
2009-02-09 21:15:56 +00:00
GIFRegTEX0 TEX0 ;
TEX0 . TBP0 = 0 ;
TEX0 . TBW = w / 64 ;
GIFRegTEXA TEXA ;
TEXA . TA0 = 0 ;
TEXA . TA1 = 0x80 ;
TEXA . AEM = 0 ;
int trlen = w * h * psm . trbpp / 8 ;
int len = w * h * psm . bpp / 8 ;
clock_t start , end ;
2014-09-15 13:49:16 +00:00
printf ( " [%4s] " , s_format [ i ] . name ) ;
2009-02-09 21:15:56 +00:00
start = clock ( ) ;
for ( int j = 0 ; j < n ; j + + )
{
int x = 0 ;
int y = 0 ;
2014-09-15 13:49:16 +00:00
( mem - > * wi ) ( x , y , ptr , trlen , BITBLTBUF , TRXPOS , TRXREG ) ;
2009-02-09 21:15:56 +00:00
}
end = clock ( ) ;
2014-09-15 13:49:16 +00:00
printf ( " %6d %6d | " , ( int ) ( ( float ) trlen * n / ( end - start ) / 1000 ) , ( int ) ( ( float ) ( w * h ) * n / ( end - start ) / 1000 ) ) ;
2009-02-09 21:15:56 +00:00
start = clock ( ) ;
for ( int j = 0 ; j < n ; j + + )
{
int x = 0 ;
int y = 0 ;
2014-09-15 13:49:16 +00:00
( mem - > * ri ) ( x , y , ptr , trlen , BITBLTBUF , TRXPOS , TRXREG ) ;
2009-02-09 21:15:56 +00:00
}
end = clock ( ) ;
2014-09-15 13:49:16 +00:00
printf ( " %6d %6d | " , ( int ) ( ( float ) trlen * n / ( end - start ) / 1000 ) , ( int ) ( ( float ) ( w * h ) * n / ( end - start ) / 1000 ) ) ;
2009-02-09 21:15:56 +00:00
2015-05-15 18:40:09 +00:00
const GSOffset * off = mem - > GetOffset ( TEX0 . TBP0 , TEX0 . TBW , TEX0 . PSM ) ;
2009-07-22 03:55:28 +00:00
2009-02-09 21:15:56 +00:00
start = clock ( ) ;
for ( int j = 0 ; j < n ; j + + )
{
2015-05-15 18:40:09 +00:00
( mem - > * rtx ) ( off , r , ptr , w * 4 , TEXA ) ;
2009-02-09 21:15:56 +00:00
}
end = clock ( ) ;
2014-09-15 13:49:16 +00:00
printf ( " %6d %6d " , ( int ) ( ( float ) len * n / ( end - start ) / 1000 ) , ( int ) ( ( float ) ( w * h ) * n / ( end - start ) / 1000 ) ) ;
2009-02-09 21:15:56 +00:00
if ( psm . pal > 0 )
{
start = clock ( ) ;
for ( int j = 0 ; j < n ; j + + )
{
2015-05-15 18:40:09 +00:00
( mem - > * rtxP ) ( off , r , ptr , w , TEXA ) ;
2009-02-09 21:15:56 +00:00
}
end = clock ( ) ;
2014-09-15 13:49:16 +00:00
printf ( " | %6d %6d " , ( int ) ( ( float ) len * n / ( end - start ) / 1000 ) , ( int ) ( ( float ) ( w * h ) * n / ( end - start ) / 1000 ) ) ;
2009-02-09 21:15:56 +00:00
}
2014-09-15 13:49:16 +00:00
printf ( " \n " ) ;
2009-02-09 21:15:56 +00:00
}
2014-09-15 13:49:16 +00:00
printf ( " \n " ) ;
2009-02-09 21:15:56 +00:00
}
_aligned_free ( ptr ) ;
2014-09-15 13:49:16 +00:00
delete mem ;
2009-02-09 21:15:56 +00:00
}
//
if ( 0 )
{
2014-09-15 13:49:16 +00:00
GSLocalMemory * mem = new GSLocalMemory ( ) ;
2009-02-09 21:15:56 +00:00
2011-02-07 01:59:05 +00:00
uint8 * ptr = ( uint8 * ) _aligned_malloc ( 1024 * 1024 * 4 , 32 ) ;
2009-02-09 21:15:56 +00:00
2009-05-14 16:41:52 +00:00
for ( int i = 0 ; i < 1024 * 1024 * 4 ; i + + ) ptr [ i ] = ( uint8 ) i ;
2009-02-09 21:15:56 +00:00
const GSLocalMemory : : psm_t & psm = GSLocalMemory : : m_psm [ PSM_PSMCT32 ] ;
GSLocalMemory : : writeImage wi = psm . wi ;
GIFRegBITBLTBUF BITBLTBUF ;
BITBLTBUF . DBP = 0 ;
BITBLTBUF . DBW = 32 ;
BITBLTBUF . DPSM = PSM_PSMCT32 ;
2010-04-25 00:31:27 +00:00
2009-02-09 21:15:56 +00:00
GIFRegTRXPOS TRXPOS ;
TRXPOS . DSAX = 0 ;
TRXPOS . DSAY = 1 ;
GIFRegTRXREG TRXREG ;
TRXREG . RRW = 256 ;
TRXREG . RRH = 256 ;
int trlen = 256 * 256 * psm . trbpp / 8 ;
int x = 0 ;
int y = 0 ;
2014-09-15 13:49:16 +00:00
( mem - > * wi ) ( x , y , ptr , trlen , BITBLTBUF , TRXPOS , TRXREG ) ;
delete mem ;
2009-02-09 21:15:56 +00:00
}
//
2009-09-28 11:13:40 +00:00
PostQuitMessage ( 0 ) ;
2009-02-09 21:15:56 +00:00
}
2009-06-16 01:42:08 +00:00
# endif
2012-01-06 21:43:39 +00:00
2020-04-09 09:32:07 +00:00
# if defined(__unix__) || defined(__APPLE__)
2012-01-06 21:43:39 +00:00
2012-01-12 07:29:31 +00:00
inline unsigned long timeGetTime ( )
{
2016-05-13 22:43:36 +00:00
struct timespec t ;
clock_gettime ( CLOCK_REALTIME , & t ) ;
return ( unsigned long ) ( t . tv_sec * 1000 + t . tv_nsec / 1000000 ) ;
2012-01-12 07:29:31 +00:00
}
2012-01-06 21:43:39 +00:00
// Note
EXPORT_C GSReplay ( char * lpszCmdLine , int renderer )
{
2013-07-28 14:40:43 +00:00
GLLoader : : in_replayer = true ;
2017-04-29 11:05:28 +00:00
// Required by multithread driver
2020-04-09 09:32:07 +00:00
# ifndef __APPLE__
2017-04-29 11:05:28 +00:00
XInitThreads ( ) ;
2020-04-09 09:32:07 +00:00
# endif
2012-01-06 21:43:39 +00:00
2016-08-03 09:57:56 +00:00
GSinit ( ) ;
2015-10-26 21:30:34 +00:00
GSRendererType m_renderer ;
// Allow to easyly switch between SW/HW renderer -> this effectively removes the ability to select the renderer by function args
2016-05-24 19:52:06 +00:00
m_renderer = static_cast < GSRendererType > ( theApp . GetConfigI ( " Renderer " ) ) ;
2015-10-26 21:30:34 +00:00
if ( m_renderer ! = GSRendererType : : OGL_HW & & m_renderer ! = GSRendererType : : OGL_SW )
2012-03-30 19:02:37 +00:00
{
2015-10-26 21:30:34 +00:00
fprintf ( stderr , " wrong renderer selected %d \n " , static_cast < int > ( m_renderer ) ) ;
2012-03-30 19:02:37 +00:00
return ;
}
2012-01-06 21:43:39 +00:00
2017-05-26 15:57:49 +00:00
struct Packet { uint8 type , param ; uint32 size , addr ; std : : vector < uint8 > buff ; } ;
2015-05-17 13:53:31 +00:00
2017-05-26 16:07:00 +00:00
std : : list < Packet * > packets ;
2017-05-26 15:57:49 +00:00
std : : vector < uint8 > buff ;
2015-05-17 13:53:31 +00:00
uint8 regs [ 0x2000 ] ;
2013-06-26 20:09:07 +00:00
2015-05-17 14:58:50 +00:00
GSsetBaseMem ( regs ) ;
2012-01-06 21:43:39 +00:00
2017-05-21 20:14:34 +00:00
s_vsync = theApp . GetConfigI ( " vsync " ) ;
2016-10-21 19:16:50 +00:00
int finished = theApp . GetConfigI ( " linux_replay " ) ;
bool repack_dump = ( finished < 0 ) ;
2012-01-06 21:43:39 +00:00
2016-10-21 19:16:50 +00:00
if ( theApp . GetConfigI ( " dump " ) ) {
fprintf ( stderr , " Dump is enabled. Replay will be disabled \n " ) ;
finished = 1 ;
}
long frame_number = 0 ;
2012-01-06 21:43:39 +00:00
2016-10-21 19:16:50 +00:00
void * hWnd = NULL ;
2015-10-26 21:30:34 +00:00
int err = _GSopen ( ( void * * ) & hWnd , " " , m_renderer ) ;
2015-05-17 14:58:50 +00:00
if ( err ! = 0 ) {
fprintf ( stderr , " Error failed to GSopen \n " ) ;
return ;
}
if ( s_gs - > m_wnd = = NULL ) return ;
2012-01-06 21:43:39 +00:00
2015-07-15 06:59:16 +00:00
{ // Read .gs content
2015-05-17 14:58:50 +00:00
std : : string f ( lpszCmdLine ) ;
2016-10-21 19:16:50 +00:00
bool is_xz = ( f . size ( ) > = 4 ) & & ( f . compare ( f . size ( ) - 3 , 3 , " .xz " ) = = 0 ) ;
if ( is_xz )
f . replace ( f . end ( ) - 6 , f . end ( ) , " _repack.gs " ) ;
else
f . replace ( f . end ( ) - 3 , f . end ( ) , " _repack.gs " ) ;
GSDumpFile * file = is_xz
? ( GSDumpFile * ) new GSDumpLzma ( lpszCmdLine , repack_dump ? f . c_str ( ) : nullptr )
: ( GSDumpFile * ) new GSDumpRaw ( lpszCmdLine , repack_dump ? f . c_str ( ) : nullptr ) ;
2012-01-06 21:43:39 +00:00
uint32 crc ;
2015-05-17 14:58:50 +00:00
file - > Read ( & crc , 4 ) ;
2012-01-06 21:43:39 +00:00
GSsetGameCRC ( crc , 0 ) ;
GSFreezeData fd ;
2015-05-17 14:58:50 +00:00
file - > Read ( & fd . size , 4 ) ;
2012-01-06 21:43:39 +00:00
fd . data = new uint8 [ fd . size ] ;
2015-05-17 14:58:50 +00:00
file - > Read ( fd . data , fd . size ) ;
2012-01-06 21:43:39 +00:00
GSfreeze ( FREEZE_LOAD , & fd ) ;
delete [ ] fd . data ;
2015-05-17 14:58:50 +00:00
file - > Read ( regs , 0x2000 ) ;
2012-01-06 21:43:39 +00:00
2017-05-27 11:21:09 +00:00
uint8 type ;
while ( file - > Read ( & type , 1 ) )
2012-01-06 21:43:39 +00:00
{
Packet * p = new Packet ( ) ;
2015-05-17 14:58:50 +00:00
p - > type = type ;
2012-01-06 21:43:39 +00:00
switch ( type )
{
case 0 :
2015-05-17 14:58:50 +00:00
file - > Read ( & p - > param , 1 ) ;
file - > Read ( & p - > size , 4 ) ;
2012-01-06 21:43:39 +00:00
switch ( p - > param )
{
case 0 :
p - > buff . resize ( 0x4000 ) ;
p - > addr = 0x4000 - p - > size ;
2015-05-17 14:58:50 +00:00
file - > Read ( & p - > buff [ p - > addr ] , p - > size ) ;
2012-01-06 21:43:39 +00:00
break ;
case 1 :
case 2 :
case 3 :
p - > buff . resize ( p - > size ) ;
2015-05-17 14:58:50 +00:00
file - > Read ( & p - > buff [ 0 ] , p - > size ) ;
2012-01-06 21:43:39 +00:00
break ;
}
break ;
case 1 :
2015-05-17 14:58:50 +00:00
file - > Read ( & p - > param , 1 ) ;
2016-10-21 19:16:50 +00:00
frame_number + + ;
2012-01-06 21:43:39 +00:00
break ;
case 2 :
2015-05-17 14:58:50 +00:00
file - > Read ( & p - > size , 4 ) ;
2012-01-06 21:43:39 +00:00
break ;
case 3 :
p - > buff . resize ( 0x2000 ) ;
2015-05-17 14:58:50 +00:00
file - > Read ( & p - > buff [ 0 ] , 0x2000 ) ;
2012-01-06 21:43:39 +00:00
break ;
}
packets . push_back ( p ) ;
2016-10-21 19:16:50 +00:00
if ( repack_dump & & frame_number > - finished )
break ;
2012-01-06 21:43:39 +00:00
}
2015-06-02 07:26:58 +00:00
delete file ;
2015-05-17 13:53:31 +00:00
}
2012-01-06 21:43:39 +00:00
2016-07-08 19:47:53 +00:00
sleep ( 2 ) ;
2015-05-17 13:53:31 +00:00
2016-10-21 19:16:50 +00:00
frame_number = 0 ;
2016-07-08 19:47:53 +00:00
// Init vsync stuff
GSvsync ( 1 ) ;
2015-05-17 13:53:31 +00:00
while ( finished > 0 )
{
for ( auto i = packets . begin ( ) ; i ! = packets . end ( ) ; i + + )
2012-01-06 21:43:39 +00:00
{
2015-05-17 13:53:31 +00:00
Packet * p = * i ;
2012-01-06 21:43:39 +00:00
2015-05-17 13:53:31 +00:00
switch ( p - > type )
{
2012-01-06 21:43:39 +00:00
case 0 :
switch ( p - > param )
{
2015-05-17 13:53:31 +00:00
case 0 : GSgifTransfer1 ( & p - > buff [ 0 ] , p - > addr ) ; break ;
case 1 : GSgifTransfer2 ( & p - > buff [ 0 ] , p - > size / 16 ) ; break ;
case 2 : GSgifTransfer3 ( & p - > buff [ 0 ] , p - > size / 16 ) ; break ;
case 3 : GSgifTransfer ( & p - > buff [ 0 ] , p - > size / 16 ) ; break ;
2012-01-06 21:43:39 +00:00
}
break ;
case 1 :
GSvsync ( p - > param ) ;
2012-01-12 07:29:31 +00:00
frame_number + + ;
2012-01-06 21:43:39 +00:00
break ;
case 2 :
if ( buff . size ( ) < p - > size ) buff . resize ( p - > size ) ;
GSreadFIFO2 ( & buff [ 0 ] , p - > size / 16 ) ;
break ;
case 3 :
memcpy ( regs , & p - > buff [ 0 ] , 0x2000 ) ;
break ;
}
2015-05-17 13:53:31 +00:00
}
2015-08-07 14:03:49 +00:00
2016-06-26 13:27:57 +00:00
if ( finished > = 200 ) {
; // Nop for Nvidia Profiler
} else if ( finished > 90 ) {
2015-08-19 17:20:47 +00:00
sleep ( 1 ) ;
} else {
finished - - ;
}
2015-05-17 13:53:31 +00:00
}
2016-07-08 19:47:53 +00:00
static_cast < GSDeviceOGL * > ( s_gs - > m_dev ) - > GenerateProfilerData ( ) ;
2014-03-24 14:03:02 +00:00
# ifdef ENABLE_OGL_DEBUG_MEM_BW
2016-10-21 19:16:50 +00:00
unsigned long total_frame_nb = std : : max ( 1l , frame_number ) < < 10 ;
2015-05-17 13:53:31 +00:00
fprintf ( stderr , " memory bandwith. T: %f KB/f. V: %f KB/f. U: %f KB/f \n " ,
( float ) g_real_texture_upload_byte / ( float ) total_frame_nb ,
( float ) g_vertex_upload_byte / ( float ) total_frame_nb ,
( float ) g_uniform_upload_byte / ( float ) total_frame_nb
) ;
2014-03-24 14:03:02 +00:00
# endif
2012-01-12 07:29:31 +00:00
2015-05-17 13:53:31 +00:00
for ( auto i = packets . begin ( ) ; i ! = packets . end ( ) ; i + + )
{
delete * i ;
}
2012-01-06 21:43:39 +00:00
2015-05-17 13:53:31 +00:00
packets . clear ( ) ;
2012-01-06 21:43:39 +00:00
2016-07-08 19:47:53 +00:00
sleep ( 2 ) ;
2012-01-06 21:43:39 +00:00
2015-05-17 13:53:31 +00:00
GSclose ( ) ;
GSshutdown ( ) ;
2012-01-06 21:43:39 +00:00
}
# endif