diff --git a/src/Common/Win32/EmuShared.cpp b/src/Common/Win32/EmuShared.cpp index 5409f3746..d46e2693f 100644 --- a/src/Common/Win32/EmuShared.cpp +++ b/src/Common/Win32/EmuShared.cpp @@ -160,4 +160,4 @@ void EmuShared::Save() m_XBController.Save("Software\\Cxbx-Reloaded\\XBController"); m_XBVideo.Save("Software\\Cxbx-Reloaded\\XBVideo"); m_XBAudio.Save("Software\\Cxbx-Reloaded\\XBAudio"); -} \ No newline at end of file +} diff --git a/src/Cxbx/ResCxbx.h b/src/Cxbx/ResCxbx.h index 7d7b1d33d..bc0d7dff8 100644 --- a/src/Cxbx/ResCxbx.h +++ b/src/Cxbx/ResCxbx.h @@ -39,84 +39,83 @@ #define IDC_SET_LEFT_NEGX 1017 #define IDC_SET_LEFT_NEGY 1018 #define IDC_SET_LEFT_POSX 1019 -#define IDC_INPUT_CONFIG_CANCEL 1022 -#define IDC_INPUT_CONFIG_ACCEPT 1023 -#define IDC_CONFIG_STATUS 1025 -#define IDC_SET_RIGHT_POSY 1026 -#define IDC_SET_RIGHT_NEGY 1027 -#define IDC_SET_RIGHT_NEGX 1028 -#define IDC_SET_RIGHT_POSX 1029 -#define IDC_BUTTON1 1030 -#define IDC_CONFIGURE_ALL 1030 -#define IDC_BTN_EJECT 1030 -#define IDC_BUTTON2 1031 -#define IDC_BTN_COCKPIT_HATCH 1031 -#define IDC_BTN_IGNITION 1032 -#define IDC_BTN_START 1033 -#define IDC_CV_FULLSCREEN 1034 -#define IDC_BTN_ZOOM_IN 1034 -#define IDC_BTN_ZOOM_OUT 1035 -#define IDC_BTN_MODE_SELECT 1036 -#define IDC_VC_DISPLAY_ADAPTER 1037 +#define IDC_INPUT_CONFIG_CANCEL 1020 +#define IDC_INPUT_CONFIG_ACCEPT 1021 +#define IDC_CONFIG_STATUS 1022 +#define IDC_SET_RIGHT_POSY 1023 +#define IDC_SET_RIGHT_NEGY 1024 +#define IDC_SET_RIGHT_NEGX 1025 +#define IDC_SET_RIGHT_POSX 1026 +#define IDC_CONFIGURE_ALL 1027 +#define IDC_BTN_EJECT 1028 +#define IDC_BTN_COCKPIT_HATCH 1029 +#define IDC_BTN_IGNITION 1030 +#define IDC_BTN_START 1031 +#define IDC_CV_FULLSCREEN 1032 +#define IDC_BTN_ZOOM_IN 1033 +#define IDC_BTN_ZOOM_OUT 1034 +#define IDC_BTN_MODE_SELECT 1035 +#define IDC_VC_DISPLAY_ADAPTER 1036 #define IDC_BTN_SUB_MONITOR_MODE_SELECT 1037 #define IDC_VC_D3D_DEVICE 1038 -#define IDC_BTN_OPEN_CLOSE 1038 -#define IDC_BTN_MAP_ZOON_IN_OUT 1039 -#define IDC_VC_ACCEPT 1040 -#define IDC_BTN_MAIN_WEAPON_CONTROL 1040 -#define IDC_VC_CANCEL 1041 -#define IDC_BTN_SUB_WEAPON_CONTROL 1041 -#define IDC_CV_VSYNC 1042 -#define IDC_BTN_EXTINGUISHER 1042 -#define IDC_BTN_MAGAZINE_CHANGE 1043 -#define IDC_BTN_CHAFF 1044 -#define IDC_BTN_WASHING 1045 -#define IDC_BTN_COM1 1046 -#define IDC_VC_VIDEO_RESOLUTION 1047 -#define IDC_BTN_COM2 1047 -#define IDC_BTN_COM3 1048 -#define IDC_BTN_COM4 1049 -#define IDC_CV_HARDWAREYUV 1050 -#define IDC_BTN_COM5 1050 -#define IDC_BTN_FUNC1 1051 -#define IDC_BTN_FUNC2 1052 -#define IDC_BTN_FUNC3 1053 -#define IDC_BTN_TANK_DETACH 1054 -#define IDC_LIST2 1055 -#define IDC_BTN_FSS 1055 -#define IDC_ABOUT 1056 -#define IDC_BTN_OVERRIDE 1056 -#define IDC_TAB1 1057 -#define IDC_BTN_NIGHT_SCOPE 1057 -#define IDC_AC_ACCEPT 1058 -#define IDC_BTN_MANIPULATOR 1058 -#define IDC_AC_CANCEL 1059 -#define IDC_BTN_LINE_COLOR_CHANGE 1059 -#define IDC_AC_AUDIO_ADAPTER 1060 -#define IDC_AC_PCM 1062 -#define IDC_AC_XADPCM 1063 -#define IDC_AC_UNKNOWN_CODEC 1064 -#define IDC_EE_CONFOUNDER 1065 -#define IDC_EE_HDDKEY 1066 -#define IDC_EE_XBOX_REGION 1067 -#define IDC_EE_SERIAL_NUMBER 1068 -#define IDC_EE_MAC_ADDRESS 1069 -#define IDC_EE_ONLINE_KEY 1070 -#define IDC_EE_AVREGION 1071 -#define IDC_EE_LANGUAGE 1072 -#define IDC_EE_AVSETTINGS 1073 -#define IDC_EE_AUDIOSETTINGS 1074 -#define IDC_EE_GAME_PRTL_CRTL 1075 -#define IDC_EE_PRTL_PASS 1076 -#define IDC_EE_MOVIE_PRTL_CRTL 1077 -#define IDC_EE_DVDREGION 1078 -#define IDC_EE_ACCEPT 1079 -#define IDC_EE_CANCEL 1080 -#define IDC_EE_RESET 1081 -#define IDC_EE_PAL60HZ 1082 -#define IDC_EE_480P 1083 -#define IDC_EE_720P 1084 -#define IDC_EE_1080I 1085 +#define IDC_BTN_OPEN_CLOSE 1039 +#define IDC_BTN_MAP_ZOON_IN_OUT 1040 +#define IDC_VC_ACCEPT 1041 +#define IDC_BTN_MAIN_WEAPON_CONTROL 1042 +#define IDC_VC_CANCEL 1043 +#define IDC_BTN_SUB_WEAPON_CONTROL 1044 +#define IDC_CV_VSYNC 1045 +#define IDC_BTN_EXTINGUISHER 1046 +#define IDC_BTN_MAGAZINE_CHANGE 1047 +#define IDC_BTN_CHAFF 1048 +#define IDC_BTN_WASHING 1049 +#define IDC_BTN_COM1 1050 +#define IDC_VC_VIDEO_RESOLUTION 1051 +#define IDC_BTN_COM2 1052 +#define IDC_BTN_COM3 1053 +#define IDC_BTN_COM4 1054 +#define IDC_CV_HARDWAREYUV 1055 +#define IDC_BTN_COM5 1056 +#define IDC_BTN_FUNC1 1057 +#define IDC_BTN_FUNC2 1058 +#define IDC_BTN_FUNC3 1059 +#define IDC_BTN_TANK_DETACH 1060 +#define IDC_LIST2 1061 +#define IDC_BTN_FSS 1062 +#define IDC_ABOUT 1063 +#define IDC_BTN_OVERRIDE 1064 +#define IDC_TAB1 1065 +#define IDC_BTN_NIGHT_SCOPE 1066 +#define IDC_AC_ACCEPT 1067 +#define IDC_BTN_MANIPULATOR 1068 +#define IDC_AC_CANCEL 1069 +#define IDC_BTN_LINE_COLOR_CHANGE 1070 +#define IDC_AC_AUDIO_ADAPTER 1071 +#define IDC_AC_PCM 1072 +#define IDC_AC_XADPCM 1073 +#define IDC_AC_UNKNOWN_CODEC 1074 +#define IDC_EE_CONFOUNDER 1075 +#define IDC_EE_HDDKEY 1076 +#define IDC_EE_XBOX_REGION 1077 +#define IDC_EE_SERIAL_NUMBER 1078 +#define IDC_EE_MAC_ADDRESS 1079 +#define IDC_EE_ONLINE_KEY 1080 +#define IDC_EE_AVREGION 1081 +#define IDC_EE_LANGUAGE 1082 +#define IDC_EE_AVSETTINGS 1083 +#define IDC_EE_AUDIOSETTINGS 1084 +#define IDC_EE_GAME_PRTL_CRTL 1085 +#define IDC_EE_PRTL_PASS 1086 +#define IDC_EE_MOVIE_PRTL_CRTL 1087 +#define IDC_EE_DVDREGION 1088 +#define IDC_EE_ACCEPT 1089 +#define IDC_EE_CANCEL 1090 +#define IDC_EE_RESET 1091 +#define IDC_EE_PAL60HZ 1092 +#define IDC_EE_480P 1093 +#define IDC_EE_720P 1094 +#define IDC_EE_1080I 1095 +#define ID_KRNL_IS_READY 1096 #define IDC_XBOX_PORT_0 1158 #define IDC_HOST_NOTCONNECT_0_0 1159 #define IDC_HOST_XINPUT_0_0 1160 diff --git a/src/Cxbx/WndMain.cpp b/src/Cxbx/WndMain.cpp index 5756dbb6d..1cb8d090a 100644 --- a/src/Cxbx/WndMain.cpp +++ b/src/Cxbx/WndMain.cpp @@ -231,7 +231,7 @@ WndMain::WndMain(HINSTANCE x_hInstance) : dwType = REG_DWORD; dwSize = sizeof(DWORD); result = RegQueryValueEx(hKey, "HackDirectBackBufferAccess", NULL, &dwType, (PBYTE)&m_DirectHostBackBufferAccess, &dwSize); if (result != ERROR_SUCCESS) { - m_DirectHostBackBufferAccess = 0; + m_DirectHostBackBufferAccess = 1; } @@ -523,13 +523,13 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP } break; + // NOTE: WM_PARENTNOTIFY was triggered by kernel process' graphic window creation. case WM_PARENTNOTIFY: { switch(LOWORD(wParam)) { case WM_CREATE: { - CreateThread(NULL, NULL, CrashMonitorWrapper, (void*)this, NULL, NULL); // create the crash monitoring thread if (m_hwndChild == NULL) { float fps = 0.0f; float mspf = 0.0f; @@ -539,14 +539,14 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP g_EmuShared->SetLedSequence(LedSequence); SetTimer(hwnd, TIMERID_FPS, 1000, (TIMERPROC)NULL); SetTimer(hwnd, TIMERID_LED, XBOX_LED_FLASH_PERIOD, (TIMERPROC)NULL); - m_hwndChild = GetWindow(hwnd, GW_CHILD); // (HWND)HIWORD(wParam) seems to be NULL + m_hwndChild = GetWindow(hwnd, GW_CHILD); UpdateCaption(); RefreshMenus(); } - else - { + else { m_hwndChild = GetWindow(hwnd, GW_CHILD); } + CreateThread(NULL, NULL, CrashMonitorWrapper, (void*)this, NULL, NULL); // create the crash monitoring thread } break; @@ -562,8 +562,20 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP } } break; - } - }; + + case WM_USER: { + switch(lParam) { + // NOTE: If anything need to set before kernel process start do anything, do it here. + case ID_KRNL_IS_READY: { + g_EmuShared->SetFlagsLLE(&m_FlagsLLE); + g_EmuShared->SetIsReady(true); + break; + } + } + break; + } + } + }; break; // added per PVS suggestion. case WM_TIMER: @@ -1393,7 +1405,6 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP case ID_EMULATION_LLE_JIT: { m_FlagsLLE = m_FlagsLLE ^ LLE_JIT; - ClearHLECache(); RefreshMenus(); } break; @@ -1401,7 +1412,6 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP case ID_EMULATION_LLE_APU: { m_FlagsLLE = m_FlagsLLE ^ LLE_APU; - ClearHLECache(); RefreshMenus(); } break; @@ -1409,7 +1419,6 @@ LRESULT CALLBACK WndMain::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lP case ID_EMULATION_LLE_GPU: { m_FlagsLLE = m_FlagsLLE ^ LLE_GPU; - ClearHLECache(); RefreshMenus(); } break; @@ -2282,6 +2291,17 @@ void WndMain::SaveXbeAs() void WndMain::StartEmulation(HWND hwndParent, DebuggerState LocalDebuggerState /*= debuggerOff*/) { char szBuffer[MAX_PATH]; + bool isEmulating = false; + + g_EmuShared->GetIsEmulating(&isEmulating); + + if (isEmulating) { + MessageBox(m_hwnd, "A title is currently emulating, please stop emulation before attempt start again.", + "Cxbx-Reloaded", MB_ICONERROR | MB_OK); + return; + } + + g_EmuShared->SetIsEmulating(true); // register xbe path with emulator process g_EmuShared->SetXbePath(m_Xbe->m_szPath); @@ -2384,15 +2404,16 @@ void WndMain::StopEmulation() RefreshMenus(); // Set the window size back to it's GUI dimensions ResizeWindow(m_hwnd, /*bForGUI=*/true); + g_EmuShared->SetIsEmulating(false); } - // wrapper function to call CrashMonitor DWORD WINAPI WndMain::CrashMonitorWrapper(LPVOID lpVoid) { CxbxSetThreadName("Cxbx Crash Monitor"); static_cast(lpVoid)->CrashMonitor(); + return 0; } @@ -2400,41 +2421,50 @@ DWORD WINAPI WndMain::CrashMonitorWrapper(LPVOID lpVoid) void WndMain::CrashMonitor() { bool bQuickReboot; - HANDLE hCrashMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, "CrashMutex"); + DWORD dwProcessID_ExitCode = 0; + GetWindowThreadProcessId(m_hwndChild, &dwProcessID_ExitCode); - DWORD state = WaitForSingleObject(hCrashMutex, INFINITE); + // If we do receive valid process ID, let's do the next step. + if (dwProcessID_ExitCode != 0) { - g_EmuShared->GetMultiXbeFlag(&bQuickReboot); + HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, dwProcessID_ExitCode); - if (state == WAIT_OBJECT_0) // StopEmulation - { - CloseHandle(hCrashMutex); - return; + // If we do receive valid handle, let's do the next step. + if (hProcess != NULL) { + + WaitForSingleObject(hProcess, INFINITE); + dwProcessID_ExitCode = 0; + GetExitCodeProcess(hProcess, &dwProcessID_ExitCode); + CloseHandle(hProcess); + + g_EmuShared->GetMultiXbeFlag(&bQuickReboot); + + if (!bQuickReboot) { + if (dwProcessID_ExitCode == EXIT_SUCCESS) {// StopEmulation + return; + } + // Or else, it's a crash + } + else { + + // multi-xbe + // destroy this thread and start a new one + bQuickReboot = false; + g_EmuShared->SetMultiXbeFlag(&bQuickReboot); + return; + } + } } - if (state == WAIT_ABANDONED && !bQuickReboot) // that's a crash - { - CloseHandle(hCrashMutex); - if (m_bIsStarted) // that's a hard crash, Dr Watson is invoked - { - KillTimer(m_hwnd, TIMERID_FPS); - KillTimer(m_hwnd, TIMERID_LED); - DrawLedBitmap(m_hwnd, true); - m_hwndChild = NULL; - m_bIsStarted = false; - UpdateCaption(); - RefreshMenus(); - } - return; - } + // Crash clean up. - // multi-xbe - // destroy this thread and start a new one - CloseHandle(hCrashMutex); - bQuickReboot = false; - g_EmuShared->SetMultiXbeFlag(&bQuickReboot); - - return; + KillTimer(m_hwnd, TIMERID_FPS); + KillTimer(m_hwnd, TIMERID_LED); + DrawLedBitmap(m_hwnd, true); + m_hwndChild = NULL; + m_bIsStarted = false; + UpdateCaption(); + RefreshMenus(); } // draw Xbox LED bitmap @@ -2459,6 +2489,7 @@ void WndMain::DrawLedBitmap(HWND hwnd, bool bdefault) else { // draw colored bitmap int LedSequence[4] = { XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF, XBOX_LED_COLOUR_OFF }; static int LedSequenceOffset = 0; + int FlagsLLE = 0; g_EmuShared->GetLedSequence(LedSequence); @@ -2466,17 +2497,18 @@ void WndMain::DrawLedBitmap(HWND hwnd, bool bdefault) ActiveLEDColor = LedSequence[LedSequenceOffset & 3]; ++LedSequenceOffset; + g_EmuShared->GetFlagsLLE(&FlagsLLE); // Set LLE flags string based on selected LLE flags - if (m_FlagsLLE & LLE_APU) { + if (FlagsLLE & LLE_APU) { strcat(flagString, "A"); } - if (m_FlagsLLE & LLE_GPU) { + if (FlagsLLE & LLE_GPU) { strcat(flagString, "G"); } - if (m_FlagsLLE & LLE_JIT) { + if (FlagsLLE & LLE_JIT) { strcat(flagString, "J"); } - if (m_FlagsLLE == 0) { + if (FlagsLLE == 0) { sprintf(flagString, "HLE"); } } diff --git a/src/CxbxKrnl/CxbxKrnl.cpp b/src/CxbxKrnl/CxbxKrnl.cpp index cae9f853e..4693c6b75 100644 --- a/src/CxbxKrnl/CxbxKrnl.cpp +++ b/src/CxbxKrnl/CxbxKrnl.cpp @@ -42,6 +42,7 @@ namespace xboxkrnl #include }; +#include "Cxbx\ResCxbx.h" #include "CxbxKrnl.h" #include "Cxbx\CxbxXbdm.h" // For Cxbx_LibXbdmThunkTable #include "CxbxVersion.h" @@ -602,12 +603,12 @@ void PrintCurrentConfigurationLog() // Print Enabled Hacks { printf("--------------------------- HACKS CONFIG ---------------------------\n"); - printf("Disable Pixel Shaders: %s\n", g_DisablePixelShaders == 1 ? "On" : "Off"); - printf("Uncap Framerate: %s\n", g_UncapFramerate == 1 ? "On" : "Off"); - printf("Run Xbox threads on all cores: %s\n", g_UseAllCores == 1 ? "On" : "Off"); - printf("Skip RDTSC Patching: %s\n", g_SkipRdtscPatching == 1 ? "On" : "Off"); - printf("Scale Xbox to host viewport (and back): %s\n", g_ScaleViewport == 1 ? "On" : "Off"); - printf("Render directly to Host BackBuffer: %s\n", g_DirectHostBackBufferAccess == 1 ? "On" : "Off"); + printf("Disable Pixel Shaders: %s\n", g_DisablePixelShaders == 1 ? "On" : "Off (Default)"); + printf("Uncap Framerate: %s\n", g_UncapFramerate == 1 ? "On" : "Off (Default)"); + printf("Run Xbox threads on all cores: %s\n", g_UseAllCores == 1 ? "On" : "Off (Default)"); + printf("Skip RDTSC Patching: %s\n", g_SkipRdtscPatching == 1 ? "On" : "Off (Default)"); + printf("Scale Xbox to host viewport (and back): %s\n", g_ScaleViewport == 1 ? "On" : "Off (Default)"); + printf("Render directly to Host BackBuffer: %s\n", g_DirectHostBackBufferAccess == 1 ? "On (Default)" : "Off"); } printf("------------------------- END OF CONFIG LOG ------------------------\n"); @@ -905,6 +906,47 @@ void CxbxKrnlMain(int argc, char* argv[]) g_CurrentProcessHandle = GetCurrentProcess(); // OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); + if (CxbxKrnl_hEmuParent == NULL) { + CxbxKrnlCleanup("GUI process does not exist!"); + } else { + SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_USER, ID_KRNL_IS_READY); + } + + // Force wait until first allocated process is ready + do { + int waitCounter = 10; + bool isReady = false; + + while (waitCounter > 0) { + g_EmuShared->GetIsReady(&isReady); + if (isReady) { + break; + } + waitCounter--; + Sleep(100); + } + if (!isReady) { + EmuWarning("GUI process is not ready!"); + int mbRet = MessageBox(NULL, "GUI process is not ready, do you wish to retry?", TEXT("Cxbx-Reloaded"), + MB_ICONWARNING | MB_RETRYCANCEL | MB_TOPMOST | MB_SETFOREGROUND); + if (mbRet == IDRETRY) { + continue; + } + CxbxKrnlShutDown(); + } + break; + } while (true); + + g_EmuShared->SetIsReady(false); + + bool bQuickReboot; + g_EmuShared->GetMultiXbeFlag(&bQuickReboot); + + // precaution for multi-xbe titles in the case CrashMonitor has still not destoyed the previous mutex + while (bQuickReboot) { + g_EmuShared->GetMultiXbeFlag(&bQuickReboot); + } + // Write a header to the log { printf("[0x%.4X] INIT: Cxbx-Reloaded Version %s\n", GetCurrentThreadId(), _CXBX_VERSION); diff --git a/src/CxbxKrnl/EmuD3D8.cpp b/src/CxbxKrnl/EmuD3D8.cpp index 6a4922d57..7dd0323d7 100644 --- a/src/CxbxKrnl/EmuD3D8.cpp +++ b/src/CxbxKrnl/EmuD3D8.cpp @@ -1420,17 +1420,6 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) RegisterClassEx(&wc); } - bool bQuickReboot; - g_EmuShared->GetMultiXbeFlag(&bQuickReboot); - - // precaution for multi-xbe titles in the case CrashMonitor has still not destoyed the previous mutex - while (bQuickReboot) - { - g_EmuShared->GetMultiXbeFlag(&bQuickReboot); - } - - HANDLE hCrashMutex = CreateMutex(NULL, TRUE, "CrashMutex"); - // create the window { HWND hwndParent = GetDesktopWindow(); @@ -1510,8 +1499,6 @@ static DWORD WINAPI EmuRenderWindow(LPVOID lpVoid) delete dbgConsole; - if (hCrashMutex != NULL) { ReleaseMutex(hCrashMutex); } - CxbxKrnlCleanup(NULL); } diff --git a/src/CxbxKrnl/EmuShared.h b/src/CxbxKrnl/EmuShared.h index f81e51bb4..d53b9274d 100644 --- a/src/CxbxKrnl/EmuShared.h +++ b/src/CxbxKrnl/EmuShared.h @@ -67,14 +67,26 @@ class EmuShared : public Mutex // ****************************************************************** static void Init(); - void EmuShared::Load(); - void EmuShared::Save(); + void Load(); + void Save(); // ****************************************************************** // * Each process needs to call this to cleanup shared memory // ****************************************************************** static void Cleanup(); + // ****************************************************************** + // * Check if parent process is emulating title + // ****************************************************************** + void GetIsEmulating(bool *isEmulating) { Lock(); *isEmulating = m_bEmulating; Unlock(); } + void SetIsEmulating(bool isEmulating) { Lock(); m_bEmulating = isEmulating; Unlock(); } + + // ****************************************************************** + // * Each child process need to wait until parent process is ready + // ****************************************************************** + void GetIsReady(bool *isReady) { Lock(); *isReady = m_bReady; Unlock(); } + void SetIsReady(bool isReady) { Lock(); m_bReady = isReady; Unlock(); } + // ****************************************************************** // * Xbox Video Accessors // ****************************************************************** @@ -199,20 +211,22 @@ class EmuShared : public Mutex XBVideo m_XBVideo; XBAudio m_XBAudio; char m_XbePath[MAX_PATH]; - int m_BootFlags; + int m_BootFlags; int m_FlagsLLE; - int m_XInputEnabled; - int m_DisablePixelShaders; - int m_UncapFramerate; - int m_UseAllCores; - int m_SkipRdtscPatching; - float m_MSpF; + int m_XInputEnabled; + int m_DisablePixelShaders; + int m_UncapFramerate; + int m_UseAllCores; + int m_SkipRdtscPatching; + float m_MSpF; float m_FPS; - bool m_bMultiXbeFlag; - bool m_bDebugging; + bool m_bMultiXbeFlag; + bool m_bDebugging; + bool m_bReady; + bool m_bEmulating; int m_LedSequence[4]; int m_ScaleViewport; - int m_DirectHostBackBufferAccess; + int m_DirectHostBackBufferAccess; char m_StorageLocation[MAX_PATH]; }; diff --git a/src/CxbxKrnl/HLEIntercept.cpp b/src/CxbxKrnl/HLEIntercept.cpp index 5ea271da5..368b9c466 100644 --- a/src/CxbxKrnl/HLEIntercept.cpp +++ b/src/CxbxKrnl/HLEIntercept.cpp @@ -324,11 +324,71 @@ void EmuD3D_Init_DeferredStates() } } +// Update shared structure with GUI process +void EmuUpdateLLEStatus(uint32_t XbLibScan) +{ + int FlagsLLE; + g_EmuShared->GetFlagsLLE(&FlagsLLE); + + if ((FlagsLLE & LLE_GPU) == false + && !((XbLibScan & XbSymbolLib_D3D8) > 0 + || (XbLibScan & XbSymbolLib_D3D8LTCG) > 0)) { + bLLE_GPU = true; + FlagsLLE ^= LLE_GPU; + EmuOutputMessage(XB_OUTPUT_MESSAGE_INFO, "Fallback to LLE GPU."); + } + + if ((FlagsLLE & LLE_APU) == false + && (XbLibScan & XbSymbolLib_DSOUND) == 0) { + bLLE_APU = true; + FlagsLLE ^= LLE_APU; + EmuOutputMessage(XB_OUTPUT_MESSAGE_INFO, "Fallback to LLE APU."); + } + g_EmuShared->SetFlagsLLE(&FlagsLLE); +} + // NOTE: EmuHLEIntercept do not get to be in XbSymbolDatabase, do the intecept in Cxbx project only. void EmuHLEIntercept(Xbe::Header *pXbeHeader) { + // NOTE: Increase this revision number any time we changed something inside Cxbx-Reloaded. + int revisionCache = 4; + Xbe::LibraryVersion *pLibraryVersion = (Xbe::LibraryVersion*)pXbeHeader->dwLibraryVersionsAddr; + uint16 xdkVersion = 0; + uint32_t XbLibScan = 0; + + // NOTE: We need to check if title has library header to optimize verification process. + if (pLibraryVersion != nullptr) { + uint32 dwLibraryVersions = pXbeHeader->dwLibraryVersions; + const char* SectionName = nullptr; + Xbe::SectionHeader* pSectionHeaders = (Xbe::SectionHeader*)pXbeHeader->dwSectionHeadersAddr; + + // Get the highest revision build and prefix library to scan. + for (uint32 v = 0; v < dwLibraryVersions; v++) { + uint16 BuildVersion = pLibraryVersion[v].wBuildVersion; + uint16 QFEVersion = pLibraryVersion[v].wFlags.QFEVersion; + + if (xdkVersion < BuildVersion) { + xdkVersion = BuildVersion; + } + XbLibScan |= XbSymbolLibrayToFlag(std::string(pLibraryVersion[v].szName, pLibraryVersion[v].szName + 8).c_str()); + } + + // Since XDK 4039 title does not have library version for DSOUND, let's check section header if it exists or not. + for (unsigned int v = 0; v < pXbeHeader->dwSections; v++) { + SectionName = (const char*)pSectionHeaders[v].dwSectionNameAddr; + if (strncmp(SectionName, Lib_DSOUND, 8) == 0) { + XbLibScan |= XbSymbolLib_DSOUND; + break; + } + } + } + + EmuUpdateLLEStatus(XbLibScan); + int gFlagsLLE; + g_EmuShared->GetFlagsLLE(&gFlagsLLE); + printf("\n"); printf("*******************************************************************************\n"); printf("* Cxbx-Reloaded High Level Emulation database\n"); @@ -367,84 +427,86 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader) if (HLECacheHash == XbSymbolLibraryVersion()) { char buffer[SHRT_MAX] = { 0 }; char* bufferPtr = buffer; - - printf("Using HLE Cache\n"); - - GetPrivateProfileSection("Symbols", buffer, sizeof(buffer), filename.c_str()); - - // Parse the .INI file into the map of symbol addresses - while (strlen(bufferPtr) > 0) { - std::string ini_entry(bufferPtr); - - auto separator = ini_entry.find('='); - std::string key = ini_entry.substr(0, separator); - std::string value = ini_entry.substr(separator + 1, std::string::npos); - uint32_t addr = strtol(value.c_str(), 0, 16); - - g_SymbolAddresses[key] = addr; - bufferPtr += strlen(bufferPtr) + 1; - } - - // Iterate through the map of symbol addresses, calling GetEmuPatchAddr on all functions. - for (auto it = g_SymbolAddresses.begin(); it != g_SymbolAddresses.end(); ++it) { - std::string functionName = (*it).first; - xbaddr location = (*it).second; - - std::stringstream output; - output << "HLECache: 0x" << std::setfill('0') << std::setw(8) << std::hex << location - << " -> " << functionName; - void* pFunc = GetEmuPatchAddr(functionName); - if (pFunc != nullptr) - { - // skip entries that weren't located at all - if (location == NULL) - { - output << "\t(not patched)"; - } - // Prevent patching illegal addresses - else if (location < XBE_IMAGE_BASE) - { - output << "\t*ADDRESS TOO LOW!*"; - } - else if (location > g_SystemMaxMemory) - { - output << "\t*ADDRESS TOO HIGH!*"; - } - else - { - EmuInstallPatch(functionName, location, pFunc); - output << "\t*PATCHED*"; - } - } - else - { - if (location != NULL) - output << "\t(no patch)"; - } - - output << "\n"; - printf(output.str().c_str()); - } - - // Fix up Render state and Texture States - if (g_SymbolAddresses.find("D3DDeferredRenderState") == g_SymbolAddresses.end() - || g_SymbolAddresses["D3DDeferredRenderState"] == 0) { - EmuWarning("EmuD3DDeferredRenderState was not found!"); - } - - if (g_SymbolAddresses.find("D3DDeferredTextureState") == g_SymbolAddresses.end() - || g_SymbolAddresses["D3DDeferredTextureState"] == 0) { - EmuWarning("EmuD3DDeferredTextureState was not found!"); - } - - if (g_SymbolAddresses.find("D3DDEVICE") == g_SymbolAddresses.end() - || g_SymbolAddresses["D3DDEVICE"] == 0) { - EmuWarning("D3DDEVICE was not found!"); - } - - EmuD3D_Init_DeferredStates(); - g_HLECacheUsed = true; + + const uint32 cacheRevision = GetPrivateProfileInt("Info", "revision", 0, filename.c_str()); + const uint32 cacheFlagsLLE = GetPrivateProfileInt("Info", "FlagsLLE", 0, filename.c_str()); + + if (cacheFlagsLLE != gFlagsLLE) { + g_HLECacheUsed = false; + } + else if (cacheRevision != revisionCache) { + g_HLECacheUsed = false; + } + + if (g_HLECacheUsed) { + printf("Using HLE Cache\n"); + + GetPrivateProfileSection("Symbols", buffer, sizeof(buffer), filename.c_str()); + + // Parse the .INI file into the map of symbol addresses + while (strlen(bufferPtr) > 0) { + std::string ini_entry(bufferPtr); + + auto separator = ini_entry.find('='); + std::string key = ini_entry.substr(0, separator); + std::string value = ini_entry.substr(separator + 1, std::string::npos); + uint32_t addr = strtol(value.c_str(), 0, 16); + + g_SymbolAddresses[key] = addr; + bufferPtr += strlen(bufferPtr) + 1; + } + + // Iterate through the map of symbol addresses, calling GetEmuPatchAddr on all functions. + for (auto it = g_SymbolAddresses.begin(); it != g_SymbolAddresses.end(); ++it) { + std::string functionName = (*it).first; + xbaddr location = (*it).second; + + std::stringstream output; + output << "HLECache: 0x" << std::setfill('0') << std::setw(8) << std::hex << location + << " -> " << functionName; + void* pFunc = GetEmuPatchAddr(functionName); + if (pFunc != nullptr) { + // skip entries that weren't located at all + if (location == NULL) { + output << "\t(not patched)"; + } + // Prevent patching illegal addresses + else if (location < XBE_IMAGE_BASE) { + output << "\t*ADDRESS TOO LOW!*"; + } else if (location > g_SystemMaxMemory) { + output << "\t*ADDRESS TOO HIGH!*"; + } else { + EmuInstallPatch(functionName, location, pFunc); + output << "\t*PATCHED*"; + } + } else { + if (location != NULL) + output << "\t(no patch)"; + } + + output << "\n"; + printf(output.str().c_str()); + } + + // Fix up Render state and Texture States + if (g_SymbolAddresses.find("D3DDeferredRenderState") == g_SymbolAddresses.end() + || g_SymbolAddresses["D3DDeferredRenderState"] == 0) { + EmuWarning("EmuD3DDeferredRenderState was not found!"); + } + + if (g_SymbolAddresses.find("D3DDeferredTextureState") == g_SymbolAddresses.end() + || g_SymbolAddresses["D3DDeferredTextureState"] == 0) { + EmuWarning("EmuD3DDeferredTextureState was not found!"); + } + + if (g_SymbolAddresses.find("D3DDEVICE") == g_SymbolAddresses.end() + || g_SymbolAddresses["D3DDEVICE"] == 0) { + EmuWarning("D3DDEVICE was not found!"); + } + + EmuD3D_Init_DeferredStates(); + } } // If g_SymbolAddresses didn't get filled, the HLE cache is invalid @@ -462,26 +524,10 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader) // // initialize Microsoft XDK emulation // - if(pLibraryVersion != 0) - { + if(pLibraryVersion != nullptr) { + printf("HLE: Detected Microsoft XDK application...\n"); - uint32 dwLibraryVersions = pXbeHeader->dwLibraryVersions; - - uint16 xdkVersion = 0; - uint32_t XbLibScan = 0; - - // Get the highest revision build and prefix library to scan. - for (uint32 v = 0; v < dwLibraryVersions; v++) { - uint16 BuildVersion = pLibraryVersion[v].wBuildVersion; - uint16 QFEVersion = pLibraryVersion[v].wFlags.QFEVersion; - - if (xdkVersion < BuildVersion) { - xdkVersion = BuildVersion; - } - XbLibScan |= XbSymbolLibrayToFlag(std::string(pLibraryVersion[v].szName, pLibraryVersion[v].szName + 8).c_str()); - } - // TODO: Is this enough for alias? We need to verify it. if ((XbLibScan & XbSymbolLib_D3D8) > 0 || (XbLibScan & XbSymbolLib_D3D8LTCG) > 0) { g_BuildVersion = xdkVersion; @@ -533,6 +579,15 @@ void EmuHLEIntercept(Xbe::Header *pXbeHeader) WritePrivateProfileString("Info", "HLECacheHash", HLECacheHashString.c_str(), filename.c_str()); } + + std::stringstream revision; + revision << std::dec << revisionCache; + WritePrivateProfileString("Info", "revision", revision.str().c_str(), filename.c_str()); + + std::stringstream flagsLLE; + flagsLLE << std::dec << gFlagsLLE; + WritePrivateProfileString("Info", "FlagsLLE", flagsLLE.str().c_str(), filename.c_str()); + // Write the Certificate Details to the cache file WritePrivateProfileString("Certificate", "Name", tAsciiTitle, filename.c_str());