2012-11-01 15:19:01 +00:00
// NOTE: Apologies for the quality of this code, this is really from pre-opensource Dolphin - that is, 2003.
2013-03-29 17:50:08 +00:00
# include "base/timeutil.h"
# include "base/NativeApp.h"
2013-08-13 15:09:36 +00:00
# include "base/mutex.h"
2014-09-27 04:16:56 +00:00
# include "i18n/i18n.h"
2016-01-01 11:50:38 +00:00
# include "input/input_state.h"
2014-06-29 21:29:49 +00:00
# include "util/text/utf8.h"
2016-01-01 11:50:38 +00:00
2013-08-13 15:09:36 +00:00
# include "Common/Log.h"
# include "Common/StringUtils.h"
2012-11-01 15:19:01 +00:00
# include "../Globals.h"
2013-08-13 15:09:36 +00:00
# include "Windows/EmuThread.h"
2014-09-27 04:16:56 +00:00
# include "Windows/W32Util/Misc.h"
2015-09-19 11:14:05 +00:00
# include "Windows/MainWindow.h"
2013-08-13 15:09:36 +00:00
# include "Windows/resource.h"
# include "Core/Reporting.h"
# include "Core/MemMap.h"
# include "Core/Core.h"
# include "Core/Host.h"
# include "Core/System.h"
# include "Core/Config.h"
2013-04-13 19:24:07 +00:00
# include "thread/threadutil.h"
2012-11-01 15:19:01 +00:00
2012-11-17 22:44:29 +00:00
# include <tchar.h>
# include <process.h>
2013-06-08 00:32:07 +00:00
# include <intrin.h>
# pragma intrinsic(_InterlockedExchange)
2012-11-17 22:44:29 +00:00
2013-08-13 15:09:36 +00:00
static recursive_mutex emuThreadLock ;
2012-11-01 15:19:01 +00:00
static HANDLE emuThread ;
2013-08-13 15:09:36 +00:00
static volatile long emuThreadReady ;
2013-06-08 00:32:07 +00:00
2016-01-01 11:50:38 +00:00
InputState input_state ;
2014-08-31 07:05:59 +00:00
extern std : : vector < std : : wstring > GetWideCmdLine ( ) ;
2013-08-13 15:09:36 +00:00
enum EmuThreadStatus : long
2013-06-08 00:32:07 +00:00
{
THREAD_NONE = 0 ,
THREAD_INIT ,
THREAD_CORE_LOOP ,
THREAD_SHUTDOWN ,
THREAD_END ,
} ;
2012-11-01 15:19:01 +00:00
HANDLE EmuThread_GetThreadHandle ( )
{
2013-08-13 15:09:36 +00:00
lock_guard guard ( emuThreadLock ) ;
2012-11-01 15:19:01 +00:00
return emuThread ;
}
2013-06-08 00:32:07 +00:00
unsigned int WINAPI TheThread ( void * ) ;
2012-11-01 15:19:01 +00:00
2013-03-29 17:50:08 +00:00
void EmuThread_Start ( )
2012-11-01 15:19:01 +00:00
{
2013-08-13 15:09:36 +00:00
lock_guard guard ( emuThreadLock ) ;
2013-06-08 00:32:07 +00:00
emuThread = ( HANDLE ) _beginthreadex ( 0 , 0 , & TheThread , 0 , 0 , 0 ) ;
2012-11-01 15:19:01 +00:00
}
void EmuThread_Stop ( )
{
2013-08-13 15:03:13 +00:00
// Already stopped?
2013-08-13 15:09:36 +00:00
{
lock_guard guard ( emuThreadLock ) ;
2014-02-10 01:35:43 +00:00
if ( emuThread = = NULL | | emuThreadReady = = THREAD_END )
2013-08-13 15:09:36 +00:00
return ;
}
2013-08-13 15:03:13 +00:00
2014-06-22 07:38:46 +00:00
UpdateUIState ( UISTATE_EXIT ) ;
2012-11-01 15:19:01 +00:00
Core_Stop ( ) ;
2013-06-08 00:32:07 +00:00
Core_WaitInactive ( 800 ) ;
if ( WAIT_TIMEOUT = = WaitForSingleObject ( emuThread , 800 ) )
{
2013-07-01 05:50:58 +00:00
_dbg_assert_msg_ ( COMMON , false , " Wait for EmuThread timed out. " ) ;
2013-06-08 00:32:07 +00:00
}
2012-11-01 15:19:01 +00:00
{
2013-08-13 15:09:36 +00:00
lock_guard guard ( emuThreadLock ) ;
2013-06-08 00:32:07 +00:00
CloseHandle ( emuThread ) ;
emuThread = 0 ;
2012-11-01 15:19:01 +00:00
}
host - > UpdateUI ( ) ;
}
2013-06-08 00:32:07 +00:00
bool EmuThread_Ready ( )
{
return emuThreadReady = = THREAD_CORE_LOOP ;
}
unsigned int WINAPI TheThread ( void * )
{
_InterlockedExchange ( & emuThreadReady , THREAD_INIT ) ;
2014-06-29 10:53:03 +00:00
setCurrentThreadName ( " Emu " ) ; // And graphics...
2012-11-01 15:19:01 +00:00
2013-03-29 17:50:08 +00:00
// Native overwrites host. Can't allow that.
Host * oldHost = host ;
2014-08-31 05:17:25 +00:00
// Convert the command-line arguments to Unicode, then to proper UTF-8
// (the benefit being that we don't have to pollute the UI project with win32 ifdefs and lots of Convert<whatever>To<whatever>).
// This avoids issues with PPSSPP inadvertently destroying paths with Unicode glyphs
// (using the ANSI args resulted in Japanese/Chinese glyphs being turned into question marks, at least for me..).
// -TheDax
std : : vector < std : : wstring > wideArgs = GetWideCmdLine ( ) ;
std : : vector < std : : string > argsUTF8 ;
2014-08-31 08:16:22 +00:00
for ( auto & string : wideArgs ) {
2014-08-31 07:05:59 +00:00
argsUTF8 . push_back ( ConvertWStringToUTF8 ( string ) ) ;
2014-08-31 05:17:25 +00:00
}
std : : vector < const char * > args ;
2014-08-31 08:16:22 +00:00
for ( auto & string : argsUTF8 ) {
2014-08-31 05:17:25 +00:00
args . push_back ( string . c_str ( ) ) ;
}
2016-01-17 21:11:28 +00:00
NativeInit ( static_cast < int > ( args . size ( ) ) , & args [ 0 ] , " 1234 " , " 1234 " , nullptr ) ;
2014-08-31 05:17:25 +00:00
2013-03-29 17:50:08 +00:00
Host * nativeHost = host ;
host = oldHost ;
2012-11-01 15:19:01 +00:00
host - > UpdateUI ( ) ;
2014-01-26 23:36:39 +00:00
2015-12-31 15:59:40 +00:00
GraphicsContext * graphicsContext ;
2013-03-10 22:08:57 +00:00
std : : string error_string ;
2015-12-31 15:59:40 +00:00
if ( ! host - > InitGraphics ( & error_string , & graphicsContext ) ) {
2014-09-27 04:16:56 +00:00
I18NCategory * err = GetI18NCategory ( " Error " ) ;
2014-08-17 14:07:14 +00:00
Reporting : : ReportMessage ( " Graphics init error: %s " , error_string . c_str ( ) ) ;
2014-09-27 04:16:56 +00:00
2016-03-13 16:33:39 +00:00
const char * defaultErrorVulkan = " Failed initializing graphics. Try upgrading your graphics drivers. \n \n Would you like to try switching to OpenGL? \n \n Error message: " ;
2014-09-27 04:16:56 +00:00
const char * defaultErrorOpenGL = " Failed initializing graphics. Try upgrading your graphics drivers. \n \n Would you like to try switching to DirectX 9? \n \n Error message: " ;
2014-09-28 07:55:16 +00:00
const char * defaultErrorDirect3D9 = " Failed initializing graphics. Try upgrading your graphics drivers and directx 9 runtime. \n \n Would you like to try switching to OpenGL? \n \n Error message: " ;
2014-09-27 04:16:56 +00:00
const char * genericError ;
int nextBackend = GPU_BACKEND_DIRECT3D9 ;
switch ( g_Config . iGPUBackend ) {
case GPU_BACKEND_DIRECT3D9 :
nextBackend = GPU_BACKEND_OPENGL ;
genericError = err - > T ( " GenericDirect3D9Error " , defaultErrorDirect3D9 ) ;
break ;
2016-03-13 16:33:39 +00:00
case GPU_BACKEND_VULKAN :
nextBackend = GPU_BACKEND_OPENGL ;
genericError = err - > T ( " GenericVulkanError " , defaultErrorDirect3D9 ) ;
break ;
2014-09-27 04:16:56 +00:00
case GPU_BACKEND_OPENGL :
default :
nextBackend = GPU_BACKEND_DIRECT3D9 ;
genericError = err - > T ( " GenericOpenGLError " , defaultErrorOpenGL ) ;
break ;
}
std : : string full_error = StringFromFormat ( " %s \n \n %s " , genericError , error_string . c_str ( ) ) ;
std : : wstring title = ConvertUTF8ToWString ( err - > T ( " GenericGraphicsError " , " Graphics Error " ) ) ;
bool yes = IDYES = = MessageBox ( 0 , ConvertUTF8ToWString ( full_error ) . c_str ( ) , title . c_str ( ) , MB_ICONERROR | MB_YESNO ) ;
2013-03-10 22:08:57 +00:00
ERROR_LOG ( BOOT , full_error . c_str ( ) ) ;
2013-09-11 19:35:04 +00:00
2014-09-27 04:16:56 +00:00
if ( yes ) {
// Change the config to the alternative and restart.
g_Config . iGPUBackend = nextBackend ;
g_Config . Save ( ) ;
W32Util : : ExitAndRestart ( ) ;
}
// No safe way out without graphics.
2013-09-11 19:35:04 +00:00
ExitProcess ( 1 ) ;
2013-03-10 22:08:57 +00:00
}
2012-11-01 15:19:01 +00:00
2015-12-31 15:59:40 +00:00
PSP_CoreParameter ( ) . graphicsContext = graphicsContext ;
NativeInitGraphics ( graphicsContext ) ;
2014-02-11 15:45:13 +00:00
NativeResized ( ) ;
2012-11-01 15:19:01 +00:00
INFO_LOG ( BOOT , " Done. " ) ;
_dbg_update_ ( ) ;
2013-06-08 00:32:07 +00:00
if ( coreState = = CORE_POWERDOWN ) {
INFO_LOG ( BOOT , " Exit before core loop. " ) ;
goto shutdown ;
}
_InterlockedExchange ( & emuThreadReady , THREAD_CORE_LOOP ) ;
if ( g_Config . bBrowse )
PostMessage ( MainWindow : : GetHWND ( ) , WM_COMMAND , ID_FILE_LOAD , 0 ) ;
2013-03-29 17:50:08 +00:00
Core_EnableStepping ( FALSE ) ;
2013-06-08 00:32:07 +00:00
2014-06-22 07:38:46 +00:00
while ( GetUIState ( ) ! = UISTATE_EXIT )
2013-06-18 07:31:15 +00:00
{
// We're here again, so the game quit. Restart Core_Run() which controls the UI.
// This way they can load a new game.
2013-10-12 08:40:33 +00:00
if ( ! Core_IsActive ( ) )
UpdateUIState ( UISTATE_MENU ) ;
2015-12-31 15:59:40 +00:00
Core_Run ( graphicsContext ) ;
2013-06-18 07:31:15 +00:00
}
2012-11-01 15:19:01 +00:00
2012-11-05 12:42:33 +00:00
shutdown :
2013-06-08 00:32:07 +00:00
_InterlockedExchange ( & emuThreadReady , THREAD_SHUTDOWN ) ;
2013-08-15 22:57:04 +00:00
2013-03-29 17:50:08 +00:00
NativeShutdownGraphics ( ) ;
2013-09-11 19:35:04 +00:00
2013-08-19 06:25:14 +00:00
host - > ShutdownSound ( ) ;
2013-06-21 06:13:00 +00:00
host = nativeHost ;
2013-03-29 17:50:08 +00:00
NativeShutdown ( ) ;
host = oldHost ;
2014-09-20 19:55:58 +00:00
host - > ShutdownGraphics ( ) ;
2012-11-01 15:19:01 +00:00
2013-06-08 00:32:07 +00:00
_InterlockedExchange ( & emuThreadReady , THREAD_END ) ;
2012-11-01 15:19:01 +00:00
return 0 ;
}