mirror of https://github.com/PCSX2/pcsx2.git
Major GUI API Cleanups. Most likely buggy as all hell.
* Moved most of the shared code between the two GUIs into platform independent source modules (System.cpp, Saveslots.cpp, and RecoverySystem.cpp) * Created two new namespaces which house functions that need to be implemented by OS/platforms: HostGui and HostSys. HostGui is useful -- HostSys I'm not sure I'll keep around in the long run. * Moved keyEvent struct from PS2Edefs.h to PS2Etypes.h * Many improvements to the logic flow of the GUI (should be a little less fallible). git-svn-id: http://pcsx2.googlecode.com/svn/trunk@675 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
900d4bd485
commit
cc930f86c5
|
@ -95,15 +95,6 @@ char* CALLBACK PS2EgetLibName(void);
|
||||||
linux: the XK_XXX will be used (XFree86)
|
linux: the XK_XXX will be used (XFree86)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// event values:
|
|
||||||
#define KEYPRESS 1
|
|
||||||
#define KEYRELEASE 2
|
|
||||||
|
|
||||||
typedef struct _keyEvent {
|
|
||||||
u32 key;
|
|
||||||
u32 evt;
|
|
||||||
} keyEvent;
|
|
||||||
|
|
||||||
// for 64bit compilers
|
// for 64bit compilers
|
||||||
typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1];
|
typedef char __keyEvent_Size__[(sizeof(keyEvent) == 8)?1:-1];
|
||||||
|
|
||||||
|
|
|
@ -219,6 +219,15 @@ typedef struct {
|
||||||
s8 *data;
|
s8 *data;
|
||||||
} freezeData;
|
} freezeData;
|
||||||
|
|
||||||
|
// event values:
|
||||||
|
#define KEYPRESS 1
|
||||||
|
#define KEYRELEASE 2
|
||||||
|
|
||||||
|
typedef struct _keyEvent {
|
||||||
|
u32 key;
|
||||||
|
u32 evt;
|
||||||
|
} keyEvent;
|
||||||
|
|
||||||
/* common defines */
|
/* common defines */
|
||||||
#ifndef C_ASSERT
|
#ifndef C_ASSERT
|
||||||
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
|
#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
|
||||||
|
|
|
@ -21,28 +21,6 @@
|
||||||
|
|
||||||
#include "PS2Etypes.h"
|
#include "PS2Etypes.h"
|
||||||
|
|
||||||
struct TESTRUNARGS
|
|
||||||
{
|
|
||||||
u8 enabled;
|
|
||||||
u8 jpgcapture;
|
|
||||||
|
|
||||||
int frame; // if < 0, frame is unlimited (run until crash).
|
|
||||||
int numimages;
|
|
||||||
int curimage;
|
|
||||||
u32 autopad; // mask for auto buttons
|
|
||||||
bool efile;
|
|
||||||
int snapdone;
|
|
||||||
|
|
||||||
const char* ptitle;
|
|
||||||
const char* pimagename;
|
|
||||||
const char* plogname;
|
|
||||||
const char* pgsdll, *pcdvddll, *pspudll;
|
|
||||||
const char* ppad1dll, *ppad2dll, *pdev9dll;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
extern TESTRUNARGS g_TestRun;
|
|
||||||
|
|
||||||
#define BIAS 2 // Bus is half of the actual ps2 speed
|
#define BIAS 2 // Bus is half of the actual ps2 speed
|
||||||
//#define PS2CLK 36864000 /* 294.912 mhz */
|
//#define PS2CLK 36864000 /* 294.912 mhz */
|
||||||
//#define PSXCLK 9216000 /* 36.864 Mhz */
|
//#define PSXCLK 9216000 /* 36.864 Mhz */
|
||||||
|
|
|
@ -137,7 +137,7 @@ void rcntInit() {
|
||||||
|
|
||||||
// debug code, used for stats
|
// debug code, used for stats
|
||||||
int g_nCounters[4];
|
int g_nCounters[4];
|
||||||
static int iFrame = 0;
|
static uint iFrame = 0;
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -270,81 +270,6 @@ u32 UpdateVSyncRate()
|
||||||
|
|
||||||
extern u32 vu0time;
|
extern u32 vu0time;
|
||||||
|
|
||||||
|
|
||||||
void vSyncDebugStuff() {
|
|
||||||
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
|
||||||
if( g_TestRun.enabled && g_TestRun.frame > 0 ) {
|
|
||||||
if( iFrame > g_TestRun.frame ) {
|
|
||||||
// take a snapshot
|
|
||||||
if( g_TestRun.pimagename != NULL && GSmakeSnapshot2 != NULL ) {
|
|
||||||
if( g_TestRun.snapdone ) {
|
|
||||||
g_TestRun.curimage++;
|
|
||||||
g_TestRun.snapdone = 0;
|
|
||||||
g_TestRun.frame += 20;
|
|
||||||
if( g_TestRun.curimage >= g_TestRun.numimages ) {
|
|
||||||
// exit
|
|
||||||
SysClose();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// query for the image
|
|
||||||
GSmakeSnapshot2(g_TestRun.pimagename, &g_TestRun.snapdone, g_TestRun.jpgcapture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// exit
|
|
||||||
SysClose();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GSVSYNC();
|
|
||||||
|
|
||||||
if( g_SaveGSStream == 1 ) {
|
|
||||||
freezeData fP;
|
|
||||||
|
|
||||||
g_SaveGSStream = 2;
|
|
||||||
g_fGSSave->gsFreeze();
|
|
||||||
|
|
||||||
if (GSfreeze(FREEZE_SIZE, &fP) == -1) {
|
|
||||||
safe_delete( g_fGSSave );
|
|
||||||
g_SaveGSStream = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fP.data = (s8*)malloc(fP.size);
|
|
||||||
if (fP.data == NULL) {
|
|
||||||
safe_delete( g_fGSSave );
|
|
||||||
g_SaveGSStream = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (GSfreeze(FREEZE_SAVE, &fP) == -1) {
|
|
||||||
safe_delete( g_fGSSave );
|
|
||||||
g_SaveGSStream = 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g_fGSSave->Freeze( fP.size );
|
|
||||||
if (fP.size) {
|
|
||||||
g_fGSSave->FreezeMem( fP.data, fP.size );
|
|
||||||
free(fP.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( g_SaveGSStream == 2 ) {
|
|
||||||
|
|
||||||
if( --g_nLeftGSFrames <= 0 ) {
|
|
||||||
safe_delete( g_fGSSave );
|
|
||||||
g_SaveGSStream = 0;
|
|
||||||
Console::WriteLn("Done saving GS stream");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void frameLimitReset()
|
void frameLimitReset()
|
||||||
{
|
{
|
||||||
m_iStart = GetCPUTicks();
|
m_iStart = GetCPUTicks();
|
||||||
|
@ -401,7 +326,7 @@ static __forceinline void frameLimit()
|
||||||
static __forceinline void VSyncStart(u32 sCycle)
|
static __forceinline void VSyncStart(u32 sCycle)
|
||||||
{
|
{
|
||||||
EECNT_LOG( "///////// EE COUNTER VSYNC START \\\\\\\\\\\\\\\\\\\\ (frame: %d)\n", iFrame );
|
EECNT_LOG( "///////// EE COUNTER VSYNC START \\\\\\\\\\\\\\\\\\\\ (frame: %d)\n", iFrame );
|
||||||
vSyncDebugStuff(); // EE Profiling and Debug code
|
vSyncDebugStuff( iFrame ); // EE Profiling and Debug code
|
||||||
|
|
||||||
if ((CSRw & 0x8)) GSCSRr|= 0x8;
|
if ((CSRw & 0x8)) GSCSRr|= 0x8;
|
||||||
if (!(GSIMR&0x800)) gsIrq();
|
if (!(GSIMR&0x800)) gsIrq();
|
||||||
|
@ -512,7 +437,6 @@ __forceinline bool rcntUpdate_vSync()
|
||||||
counters[5].modeval = MODE_VRENDER;
|
counters[5].modeval = MODE_VRENDER;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
// SysUpdate(); // check for and handle keyevents
|
|
||||||
}
|
}
|
||||||
else // VSYNC end / VRENDER begin
|
else // VSYNC end / VRENDER begin
|
||||||
{
|
{
|
||||||
|
|
|
@ -540,7 +540,7 @@ int loadElfFile(const char *filename)
|
||||||
// Reset all recompilers prior to initiating a BIOS or new ELF. The cleaner the
|
// Reset all recompilers prior to initiating a BIOS or new ELF. The cleaner the
|
||||||
// slate, the happier the recompiler!
|
// slate, the happier the recompiler!
|
||||||
|
|
||||||
SysResetExecutionState();
|
SysClearExecutionCache();
|
||||||
|
|
||||||
if( filename == NULL || filename[0] == 0 )
|
if( filename == NULL || filename[0] == 0 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/* Pcsx2 - Pc Ps2 Emulator
|
||||||
|
* Copyright (C) 2002-2009 Pcsx2 Team
|
||||||
|
*
|
||||||
|
* 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 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// TestRun Parameters.
|
||||||
|
|
||||||
|
struct TESTRUNARGS
|
||||||
|
{
|
||||||
|
u8 enabled;
|
||||||
|
u8 jpgcapture;
|
||||||
|
|
||||||
|
uint frame; // if == 0, frame is unlimited (run until crash).
|
||||||
|
int numimages;
|
||||||
|
int curimage;
|
||||||
|
u32 autopad; // mask for auto buttons
|
||||||
|
bool efile;
|
||||||
|
int snapdone;
|
||||||
|
|
||||||
|
const char* ptitle;
|
||||||
|
const char* pimagename;
|
||||||
|
const char* plogname;
|
||||||
|
const char* pgsdll, *pcdvddll, *pspudll;
|
||||||
|
const char* ppad1dll, *ppad2dll, *pdev9dll;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TESTRUNARGS g_TestRun;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Core Gui APIs (shared by all platforms)
|
||||||
|
//
|
||||||
|
// Most of these are implemented in SystemGui.cpp
|
||||||
|
|
||||||
|
extern void States_Load( const string& file );
|
||||||
|
extern void States_Save( const string& file );
|
||||||
|
extern void States_Load( int num );
|
||||||
|
extern void States_Save( int num );
|
||||||
|
extern bool States_isSlotUsed(int num);
|
||||||
|
|
||||||
|
extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (set to false on reset)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// External Gui APIs (platform specific)
|
||||||
|
//
|
||||||
|
// The following section contains API declarations for GUI callback functions that the
|
||||||
|
// Pcsx2 core expects and needs to be implemented by Pcsx2 platform dependent code
|
||||||
|
// (Win32/Linux). If anything in this header comes up as a missing external during link,
|
||||||
|
// it means that the necessary platform dependent files are not being compiled, or the
|
||||||
|
// platform code is incomplete.
|
||||||
|
//
|
||||||
|
// These APIs have been namespaced to help simplify and organize the process of implementing
|
||||||
|
// them and resolving linker errors.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Namespace housing gui-level implementations relating to events and signals such
|
||||||
|
// as keyboard events, menu/status updates, and cpu execution invocation.
|
||||||
|
namespace HostGui
|
||||||
|
{
|
||||||
|
// Signal for informing the GUI that the saveslot status has been altered.
|
||||||
|
// The guis hould re-enumerate the slot information displayed in the menu, or wherever.
|
||||||
|
extern void ResetMenuSlots();
|
||||||
|
|
||||||
|
// Signals to the GUI that execution of the emulator should begin. This can be either
|
||||||
|
// a blocking or non-blocking (threaded) action.
|
||||||
|
extern void BeginExecution();
|
||||||
|
|
||||||
|
// Signals the gui with a keystroke. Handle or discard or dispatch, or enjoy its
|
||||||
|
// pleasant flavor.
|
||||||
|
extern void __fastcall KeyEvent( keyEvent* ev );
|
||||||
|
|
||||||
|
// For issuing notices to both the status bar and the console at the same time.
|
||||||
|
// Single-line text only please! Multi-line msgs should be directed to the
|
||||||
|
// console directly, thanks.
|
||||||
|
extern void Notice( const std::string& text );
|
||||||
|
|
||||||
|
// sets the contents of the pcsx2 window status bar.
|
||||||
|
extern void SetStatusMsg( const std::string& text );
|
||||||
|
};
|
|
@ -27,12 +27,6 @@ const char* g_pRunGSState = NULL;
|
||||||
|
|
||||||
int efile = 0;
|
int efile = 0;
|
||||||
char elfname[g_MaxPath];
|
char elfname[g_MaxPath];
|
||||||
bool Slots[5] = { false, false, false, false, false };
|
|
||||||
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
|
||||||
TESTRUNARGS g_TestRun;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char MAIN_DIR[g_MaxPath];
|
char MAIN_DIR[g_MaxPath];
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
|
@ -275,7 +269,7 @@ void StartGui()
|
||||||
gtk_widget_destroy(lookup_widget(MainWindow, "GtkMenuItem_Debug"));
|
gtk_widget_destroy(lookup_widget(MainWindow, "GtkMenuItem_Debug"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CheckSlots();
|
ResetMenuSlots();
|
||||||
|
|
||||||
gtk_widget_show_all(MainWindow);
|
gtk_widget_show_all(MainWindow);
|
||||||
gtk_window_activate_focus(GTK_WINDOW(MainWindow));
|
gtk_window_activate_focus(GTK_WINDOW(MainWindow));
|
||||||
|
@ -312,7 +306,7 @@ void OnLanguage(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
void OnFile_RunCD(GtkMenuItem *menuitem, gpointer user_data)
|
void OnFile_RunCD(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
{
|
{
|
||||||
SysReset();
|
SysReset();
|
||||||
RunExecute(NULL);
|
SysPrepareExecution(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnRunElf_Ok(GtkButton* button, gpointer user_data)
|
void OnRunElf_Ok(GtkButton* button, gpointer user_data)
|
||||||
|
@ -323,7 +317,7 @@ void OnRunElf_Ok(GtkButton* button, gpointer user_data)
|
||||||
strcpy(elfname, File);
|
strcpy(elfname, File);
|
||||||
gtk_widget_destroy(FileSel);
|
gtk_widget_destroy(FileSel);
|
||||||
|
|
||||||
RunExecute(elfname);
|
SysPrepareExecution(elfname);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnRunElf_Cancel(GtkButton* button, gpointer user_data)
|
void OnRunElf_Cancel(GtkButton* button, gpointer user_data)
|
||||||
|
@ -400,11 +394,7 @@ void OnFile_Exit(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
|
|
||||||
void OnEmu_Run(GtkMenuItem *menuitem, gpointer user_data)
|
void OnEmu_Run(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
{
|
{
|
||||||
if (g_EmulationInProgress)
|
SysPrepareExecution(NULL, true); // boots bios if no savestate is to be recovered
|
||||||
ExecuteCpu();
|
|
||||||
else
|
|
||||||
RunExecute(NULL, true); // boots bios if no savestate is to be recovered
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnEmu_Reset(GtkMenuItem *menuitem, gpointer user_data)
|
void OnEmu_Reset(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
|
@ -412,46 +402,6 @@ void OnEmu_Reset(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
SysReset();
|
SysReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetMenuSlots()
|
|
||||||
{
|
|
||||||
GtkWidget *Item;
|
|
||||||
char str[g_MaxPath], str2[g_MaxPath];
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
|
|
||||||
sprintf(str, "load_slot_%d", i);
|
|
||||||
sprintf(str2, "save_slot_%d", i);
|
|
||||||
Item = lookup_widget(MainWindow, str);
|
|
||||||
|
|
||||||
if GTK_IS_WIDGET(Item)
|
|
||||||
gtk_widget_set_sensitive(Item, Slots[i]);
|
|
||||||
else
|
|
||||||
Console::Error("No such widget: %s", params str);
|
|
||||||
|
|
||||||
Item = lookup_widget(MainWindow, str2);
|
|
||||||
gtk_widget_set_sensitive(Item, (ElfCRC != 0));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CheckSlots()
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (ElfCRC == 0) Console::Notice("Disabling game slots until a game is loaded.");
|
|
||||||
|
|
||||||
for (i=0; i<5; i++)
|
|
||||||
{
|
|
||||||
if (isSlotUsed(i))
|
|
||||||
Slots[i] = true;
|
|
||||||
else
|
|
||||||
Slots[i] = false;
|
|
||||||
}
|
|
||||||
ResetMenuSlots();
|
|
||||||
}
|
|
||||||
|
|
||||||
//2002-09-28 (Florin)
|
//2002-09-28 (Florin)
|
||||||
void OnArguments_Ok(GtkButton *button, gpointer user_data)
|
void OnArguments_Ok(GtkButton *button, gpointer user_data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,22 +20,13 @@
|
||||||
#define __LNXMAIN_H__
|
#define __LNXMAIN_H__
|
||||||
|
|
||||||
#include "Linux.h"
|
#include "Linux.h"
|
||||||
|
#include "HostGui.h"
|
||||||
|
|
||||||
extern bool applychanges;
|
extern bool applychanges;
|
||||||
|
|
||||||
extern SafeArray<u8>* g_RecoveryState;
|
|
||||||
extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (set to false on reset)
|
|
||||||
|
|
||||||
extern void RunExecute(const char* elf_file, bool use_bios = false);
|
|
||||||
extern void ExecuteCpu();
|
|
||||||
extern void CheckSlots();
|
|
||||||
extern bool isSlotUsed(int num);
|
|
||||||
extern bool ParseCommandLine(int argc, char *argv[], char *file);
|
extern bool ParseCommandLine(int argc, char *argv[], char *file);
|
||||||
extern void MemoryCard_Init();
|
extern void MemoryCard_Init();
|
||||||
|
|
||||||
extern void StatusBar_Notice( const std::string& text );
|
|
||||||
extern void StatusBar_SetMsg( const std::string& text );
|
|
||||||
|
|
||||||
void OnLanguage(GtkMenuItem *menuitem, gpointer user_data);
|
void OnLanguage(GtkMenuItem *menuitem, gpointer user_data);
|
||||||
void InitLanguages();
|
void InitLanguages();
|
||||||
char *GetLanguageNext();
|
char *GetLanguageNext();
|
||||||
|
|
|
@ -18,16 +18,9 @@
|
||||||
|
|
||||||
#include "Linux.h"
|
#include "Linux.h"
|
||||||
#include "LnxSysExec.h"
|
#include "LnxSysExec.h"
|
||||||
#include "R5900Exceptions.h"
|
|
||||||
|
|
||||||
bool UseGui = true;
|
bool UseGui = true;
|
||||||
|
|
||||||
SafeArray<u8>* g_RecoveryState = NULL;
|
|
||||||
SafeArray<u8>* g_gsRecoveryState = NULL;
|
|
||||||
|
|
||||||
bool g_ReturnToGui = false; // set to exit the execution of the emulator and return control to the GUI
|
|
||||||
bool g_EmulationInProgress = false; // Set TRUE if a game is actively running (set to false on reset)
|
|
||||||
|
|
||||||
static bool sinit = false;
|
static bool sinit = false;
|
||||||
GtkWidget *FileSel;
|
GtkWidget *FileSel;
|
||||||
|
|
||||||
|
@ -69,25 +62,6 @@ void SysPageFaultExceptionFilter( int signal, siginfo_t *info, void * )
|
||||||
mmap_ClearCpuBlock( offset & ~m_pagemask );
|
mmap_ClearCpuBlock( offset & ~m_pagemask );
|
||||||
}
|
}
|
||||||
|
|
||||||
// For issuing notices to both the status bar and the console at the same time.
|
|
||||||
// Single-line text only please! Mutli-line msgs should be directed to the
|
|
||||||
// console directly, thanks.
|
|
||||||
void StatusBar_Notice( const std::string& text )
|
|
||||||
{
|
|
||||||
// mirror output to the console!
|
|
||||||
Console::Status( text.c_str() );
|
|
||||||
|
|
||||||
// don't try this in Visual C++ folks!
|
|
||||||
gtk_statusbar_push(GTK_STATUSBAR(pStatusBar), 0, text.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the status bar message without mirroring the output to the console.
|
|
||||||
void StatusBar_SetMsg( const std::string& text )
|
|
||||||
{
|
|
||||||
// don't try this in Visual C++ folks!
|
|
||||||
gtk_statusbar_push(GTK_STATUSBAR(pStatusBar), 0, text.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ParseCommandLine(int argc, char *argv[], char *file)
|
bool ParseCommandLine(int argc, char *argv[], char *file)
|
||||||
{
|
{
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
@ -206,410 +180,11 @@ void SysPrintf(const char *fmt, ...)
|
||||||
Console::Write(msg);
|
Console::Write(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void KeyEvent(keyEvent* ev);
|
|
||||||
|
|
||||||
void SysUpdate()
|
|
||||||
{
|
|
||||||
KeyEvent(PAD1keyEvent());
|
|
||||||
KeyEvent(PAD2keyEvent());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TryRecoverFromGsState()
|
|
||||||
{
|
|
||||||
if( g_gsRecoveryState != NULL )
|
|
||||||
{
|
|
||||||
s32 dummylen;
|
|
||||||
|
|
||||||
memLoadingState eddie( *g_gsRecoveryState );
|
|
||||||
eddie.FreezePlugin( "GS", gsSafeFreeze );
|
|
||||||
eddie.Freeze( dummylen ); // reads the length value recorded earlier.
|
|
||||||
eddie.gsFreeze();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExecuteCpu()
|
|
||||||
{
|
|
||||||
// Make sure any left-over recovery states are cleaned up.
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
|
|
||||||
// Just in case they weren't initialized earlier (no harm in calling this multiple times)
|
|
||||||
if (OpenPlugins(NULL) == -1) return;
|
|
||||||
|
|
||||||
// this needs to be called for every new game!
|
|
||||||
// (note: sometimes launching games through bios will give a crc of 0)
|
|
||||||
|
|
||||||
if( GSsetGameCRC != NULL ) GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
|
||||||
|
|
||||||
TryRecoverFromGsState();
|
|
||||||
|
|
||||||
safe_delete( g_gsRecoveryState );
|
|
||||||
|
|
||||||
// Destroy the window. Ugly thing.
|
|
||||||
gtk_widget_destroy(MainWindow);
|
|
||||||
gtk_main_quit();
|
|
||||||
|
|
||||||
while (gtk_events_pending()) gtk_main_iteration();
|
|
||||||
|
|
||||||
g_EmulationInProgress = true;
|
|
||||||
g_ReturnToGui = false;
|
|
||||||
|
|
||||||
signal(SIGINT, SignalExit);
|
|
||||||
signal(SIGPIPE, SignalExit);
|
|
||||||
|
|
||||||
// Optimization: We hardcode two versions of the EE here -- one for recs and one for ints.
|
|
||||||
// This is because recs are performance critical, and being able to inline them into the
|
|
||||||
// function here helps a small bit (not much but every small bit counts!).
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (CHECK_EEREC)
|
|
||||||
{
|
|
||||||
while (!g_ReturnToGui)
|
|
||||||
{
|
|
||||||
recExecute();
|
|
||||||
SysUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while (!g_ReturnToGui)
|
|
||||||
{
|
|
||||||
Cpu->Execute();
|
|
||||||
SysUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch( R5900Exception::BaseExcept& ex )
|
|
||||||
{
|
|
||||||
Console::Error( ex.cMessage() );
|
|
||||||
Console::Error( fmt_string( "(EE) PC: 0x%8.8x \tCycle:0x8.8x", ex.cpuState.pc, ex.cpuState.cycle ).c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunGui()
|
void RunGui()
|
||||||
{
|
{
|
||||||
StartGui();
|
StartGui();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Runs an ELF image directly (ISO or ELF program or BIN)
|
|
||||||
// Used by Run::FromCD and such
|
|
||||||
void RunExecute(const char* elf_file, bool use_bios)
|
|
||||||
{
|
|
||||||
|
|
||||||
// (air notes:)
|
|
||||||
// If you want to use the new to-memory savestate feature, take a look at the new
|
|
||||||
// RunExecute in WinMain.c, and secondly the CpuDlg.c or AdvancedDlg.cpp. The
|
|
||||||
// objects used are SafeArray, memLoadingState, and memSavingState.
|
|
||||||
|
|
||||||
// It's important to make sure to reset the CPU and the plugins correctly, which is
|
|
||||||
// where the new RunExecute comes into play. It can be kind of tricky knowing
|
|
||||||
// when to call cpuExecuteBios and loadElfFile, and with what parameters.
|
|
||||||
|
|
||||||
// (or, as an alternative maybe we should switch to wxWidgets and have a unified
|
|
||||||
// cross platform gui?) - Air
|
|
||||||
|
|
||||||
// Sounds like a good idea, at this point.
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cpuReset();
|
|
||||||
}
|
|
||||||
|
|
||||||
catch( Exception::BaseException& ex )
|
|
||||||
{
|
|
||||||
Msgbox::Alert( ex.cMessage() );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OpenPlugins(NULL) == -1)
|
|
||||||
{
|
|
||||||
RunGui();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elf_file == NULL)
|
|
||||||
{
|
|
||||||
if (g_RecoveryState != NULL)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
memLoadingState(*g_RecoveryState).FreezeAll();
|
|
||||||
}
|
|
||||||
catch (std::runtime_error& ex)
|
|
||||||
{
|
|
||||||
Msgbox::Alert(
|
|
||||||
"Gamestate recovery failed. Your game progress will be lost (sorry!)\n"
|
|
||||||
"\nError: %s\n", params ex.what());
|
|
||||||
|
|
||||||
// Take the user back to the GUI...
|
|
||||||
safe_delete(g_RecoveryState);
|
|
||||||
ClosePlugins( true );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( g_gsRecoveryState == NULL )
|
|
||||||
{
|
|
||||||
// Not recovering a state, so need to execute the bios and load the ELF information.
|
|
||||||
|
|
||||||
// if the elf_file is null we use the CDVD elf file.
|
|
||||||
// But if the elf_file is an empty string then we boot the bios instead.
|
|
||||||
|
|
||||||
char ename[g_MaxPath];
|
|
||||||
ename[0] = 0;
|
|
||||||
|
|
||||||
if (!use_bios) GetPS2ElfName(ename);
|
|
||||||
loadElfFile(ename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Custom ELF specified (not using CDVD).
|
|
||||||
// Run the BIOS and load the ELF.
|
|
||||||
|
|
||||||
loadElfFile(elf_file);
|
|
||||||
}
|
|
||||||
ExecuteCpu();
|
|
||||||
}
|
|
||||||
|
|
||||||
class RecoveryMemSavingState : public memSavingState, Sealed
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~RecoveryMemSavingState() { }
|
|
||||||
RecoveryMemSavingState() : memSavingState( *g_RecoveryState )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void gsFreeze()
|
|
||||||
{
|
|
||||||
if (g_gsRecoveryState != NULL)
|
|
||||||
{
|
|
||||||
// just copy the data from src to dst.
|
|
||||||
// the normal savestate doesn't expect a length prefix for internal structures,
|
|
||||||
// so don't copy that part.
|
|
||||||
const u32 pluginlen = *((u32*)g_gsRecoveryState->GetPtr());
|
|
||||||
const u32 gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
|
||||||
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(pluginlen+8), gslen );
|
|
||||||
m_idx += gslen;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memSavingState::gsFreeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )
|
|
||||||
{
|
|
||||||
if ((freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL))
|
|
||||||
{
|
|
||||||
// Gs data is already in memory, so just copy from src to dest:
|
|
||||||
// length of the GS data is stored as the first u32, so use that to run the copy:
|
|
||||||
const u32 len = *((u32*)g_gsRecoveryState->GetPtr());
|
|
||||||
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(), len+4 );
|
|
||||||
m_idx += len+4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memSavingState::FreezePlugin( name, freezer );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class RecoveryZipSavingState : public gzSavingState, Sealed
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~RecoveryZipSavingState() { }
|
|
||||||
RecoveryZipSavingState( const string& filename ) : gzSavingState( filename )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void gsFreeze()
|
|
||||||
{
|
|
||||||
if (g_gsRecoveryState != NULL)
|
|
||||||
{
|
|
||||||
// read data from the gsRecoveryState allocation instead of the GS, since the gs
|
|
||||||
// info was invalidated when the plugin was shut down.
|
|
||||||
|
|
||||||
// the normal savestate doesn't expect a length prefix for internal structures,
|
|
||||||
// so don't copy that part.
|
|
||||||
|
|
||||||
u32& pluginlen = *((u32*)g_gsRecoveryState->GetPtr(0));
|
|
||||||
u32& gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
|
||||||
gzwrite( m_file, g_gsRecoveryState->GetPtr(pluginlen+4), gslen );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gzSavingState::gsFreeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )
|
|
||||||
{
|
|
||||||
if ((freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL))
|
|
||||||
{
|
|
||||||
// Gs data is already in memory, so just copy from there into the gzip file.
|
|
||||||
// length of the GS data is stored as the first u32, so use that to run the copy:
|
|
||||||
u32& len = *((u32*)g_gsRecoveryState->GetPtr());
|
|
||||||
gzwrite( m_file, g_gsRecoveryState->GetPtr(), len+4 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gzSavingState::FreezePlugin( name, freezer );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
bool isSlotUsed(int num)
|
|
||||||
{
|
|
||||||
if (ElfCRC == 0)
|
|
||||||
return false;
|
|
||||||
else
|
|
||||||
return Path::isFile(SaveState::GetFilename( num ));
|
|
||||||
}
|
|
||||||
|
|
||||||
void States_Load(const string& file, int num = -1)
|
|
||||||
{
|
|
||||||
if( !Path::isFile( file ) )
|
|
||||||
{
|
|
||||||
Console::Notice( "Saveslot %d is empty.", params num );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
char Text[g_MaxPath];
|
|
||||||
gzLoadingState joe( file ); // this'll throw an StateLoadError_Recoverable.
|
|
||||||
|
|
||||||
// Make sure the cpu and plugins are ready to be state-ified!
|
|
||||||
cpuReset();
|
|
||||||
OpenPlugins( NULL );
|
|
||||||
|
|
||||||
joe.FreezeAll();
|
|
||||||
|
|
||||||
if( num != -1 )
|
|
||||||
sprintf (Text, _("*PCSX2*: Loaded State %d"), num);
|
|
||||||
else
|
|
||||||
sprintf (Text, _("*PCSX2*: Loaded State %s"), file.c_str());
|
|
||||||
|
|
||||||
StatusBar_Notice( Text );
|
|
||||||
|
|
||||||
if( GSsetGameCRC != NULL ) GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
|
||||||
}
|
|
||||||
catch( Exception::StateLoadError_Recoverable& ex)
|
|
||||||
{
|
|
||||||
if( num != -1 )
|
|
||||||
Console::Notice( "Could not load savestate from slot %d.\n\n%s", params num, ex.cMessage() );
|
|
||||||
else
|
|
||||||
Console::Notice( "Could not load savestate file: %s.\n\n%s", params file.c_str(), ex.cMessage() );
|
|
||||||
|
|
||||||
// At this point the cpu hasn't been reset, so we can return
|
|
||||||
// control to the user safely... (that's why we use a console notice instead of a popup)
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch( Exception::BaseException& ex )
|
|
||||||
{
|
|
||||||
// The emulation state is ruined. Might as well give them a popup and start the gui.
|
|
||||||
|
|
||||||
string message;
|
|
||||||
|
|
||||||
if( num != -1 )
|
|
||||||
ssprintf( message,
|
|
||||||
"Encountered an error while loading savestate from slot %d.\n", num );
|
|
||||||
else
|
|
||||||
ssprintf( message,
|
|
||||||
"Encountered an error while loading savestate from file: %s.\n", file.c_str() );
|
|
||||||
|
|
||||||
if( g_EmulationInProgress )
|
|
||||||
message += "Since the savestate load was incomplete, the emulator has been reset.\n";
|
|
||||||
|
|
||||||
message += "\nError: " + ex.Message();
|
|
||||||
|
|
||||||
Msgbox::Alert( message.c_str() );
|
|
||||||
SysClose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start emulating!
|
|
||||||
ExecuteCpu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void States_Load(int num)
|
|
||||||
{
|
|
||||||
States_Load( SaveState::GetFilename( num ), num );
|
|
||||||
}
|
|
||||||
|
|
||||||
void States_Save( const string& file, int num = -1 )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string text;
|
|
||||||
RecoveryZipSavingState( file ).FreezeAll();
|
|
||||||
if( num != -1 )
|
|
||||||
ssprintf( text, _( "State saved to slot %d" ), num );
|
|
||||||
else
|
|
||||||
ssprintf( text, _( "State saved to file: %s" ), file.c_str() );
|
|
||||||
|
|
||||||
StatusBar_Notice( text );
|
|
||||||
}
|
|
||||||
catch( Exception::BaseException& ex )
|
|
||||||
{
|
|
||||||
string message;
|
|
||||||
|
|
||||||
if( num != -1 )
|
|
||||||
ssprintf( message, "An error occurred while trying to save to slot %d\n", num );
|
|
||||||
else
|
|
||||||
ssprintf( message, "An error occurred while trying to save to file: %s\n", file.c_str() );
|
|
||||||
|
|
||||||
message += "Your emulation state has not been saved!\n\nError: " + ex.Message();
|
|
||||||
|
|
||||||
Console::Error( message.c_str() );
|
|
||||||
}
|
|
||||||
CheckSlots();
|
|
||||||
}
|
|
||||||
|
|
||||||
void States_Save(int num)
|
|
||||||
{
|
|
||||||
if( g_RecoveryState != NULL )
|
|
||||||
{
|
|
||||||
// State is already saved into memory, and the emulator (and in-progress flag)
|
|
||||||
// have likely been cleared out. So save from the Recovery buffer instead of
|
|
||||||
// doing a "standard" save:
|
|
||||||
|
|
||||||
string text( SaveState::GetFilename( num ) );
|
|
||||||
gzFile fileptr = gzopen( text.c_str(), "wb" );
|
|
||||||
if( fileptr == NULL )
|
|
||||||
{
|
|
||||||
Msgbox::Alert( _("File permissions error while trying to save to slot %d"), params num );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gzwrite( fileptr, &g_SaveVersion, sizeof( u32 ) );
|
|
||||||
gzwrite( fileptr, g_RecoveryState->GetPtr(), g_RecoveryState->GetSizeInBytes() );
|
|
||||||
gzclose( fileptr );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !g_EmulationInProgress )
|
|
||||||
{
|
|
||||||
Msgbox::Alert( "You need to start a game first before you can save it's state." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
States_Save( SaveState::GetFilename( num ), num );
|
|
||||||
}
|
|
||||||
|
|
||||||
class JustGsSavingState : public memSavingState, Sealed
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~JustGsSavingState() { }
|
|
||||||
JustGsSavingState() : memSavingState( *g_gsRecoveryState )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// This special override saves the gs info to m_idx+4, and then goes back and
|
|
||||||
// writes in the length of data saved.
|
|
||||||
void gsFreeze()
|
|
||||||
{
|
|
||||||
int oldmidx = m_idx;
|
|
||||||
m_idx += 4;
|
|
||||||
memSavingState::gsFreeze();
|
|
||||||
if( IsSaving() )
|
|
||||||
{
|
|
||||||
s32& len = *((s32*)m_memory.GetPtr( oldmidx ));
|
|
||||||
len = (m_idx - oldmidx)-4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void OnStates_Load(GtkMenuItem *menuitem, gpointer user_data)
|
void OnStates_Load(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
{
|
{
|
||||||
char *name;
|
char *name;
|
||||||
|
@ -626,7 +201,8 @@ void OnStates_Load(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
sscanf(name, "Slot %d", &i);
|
sscanf(name, "Slot %d", &i);
|
||||||
States_Load(i);
|
if( States_Load(i) )
|
||||||
|
ExecuteCpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnLoadOther_Ok(GtkButton* button, gpointer user_data)
|
void OnLoadOther_Ok(GtkButton* button, gpointer user_data)
|
||||||
|
@ -638,7 +214,8 @@ void OnLoadOther_Ok(GtkButton* button, gpointer user_data)
|
||||||
strcpy(str, File);
|
strcpy(str, File);
|
||||||
gtk_widget_destroy(FileSel);
|
gtk_widget_destroy(FileSel);
|
||||||
|
|
||||||
States_Load(str);
|
if( States_Load(str) )
|
||||||
|
ExecuteCpu();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnLoadOther_Cancel(GtkButton* button, gpointer user_data)
|
void OnLoadOther_Cancel(GtkButton* button, gpointer user_data)
|
||||||
|
@ -726,156 +303,6 @@ void OnStates_SaveOther(GtkMenuItem *menuitem, gpointer user_data)
|
||||||
#define ALT_EVT(evt) ((evt == XK_Alt_L) || (evt == XK_Alt_R))
|
#define ALT_EVT(evt) ((evt == XK_Alt_L) || (evt == XK_Alt_R))
|
||||||
#define CAPS_LOCK_EVT(evt) (evt == XK_Caps_Lock)
|
#define CAPS_LOCK_EVT(evt) (evt == XK_Caps_Lock)
|
||||||
|
|
||||||
void KeyEvent(keyEvent* ev)
|
|
||||||
{
|
|
||||||
static int shift = 0;
|
|
||||||
|
|
||||||
if (ev == NULL) return;
|
|
||||||
|
|
||||||
if (GSkeyEvent != NULL) GSkeyEvent(ev);
|
|
||||||
|
|
||||||
if (ev->evt == KEYPRESS)
|
|
||||||
{
|
|
||||||
if (SHIFT_EVT(ev->key))
|
|
||||||
shift = 1;
|
|
||||||
if (CAPS_LOCK_EVT(ev->key))
|
|
||||||
{
|
|
||||||
//Set up anything we want to happen while caps lock is down.
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ev->key)
|
|
||||||
{
|
|
||||||
case XK_F1:
|
|
||||||
case XK_F2:
|
|
||||||
case XK_F3:
|
|
||||||
case XK_F4:
|
|
||||||
case XK_F5:
|
|
||||||
case XK_F6:
|
|
||||||
case XK_F7:
|
|
||||||
case XK_F8:
|
|
||||||
case XK_F9:
|
|
||||||
case XK_F10:
|
|
||||||
case XK_F11:
|
|
||||||
case XK_F12:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ProcessFKeys(ev->key - XK_F1 + 1, shift);
|
|
||||||
}
|
|
||||||
catch (Exception::CpuStateShutdown&)
|
|
||||||
{
|
|
||||||
// Woops! Something was unrecoverable. Bummer.
|
|
||||||
// Let's give the user a RunGui!
|
|
||||||
|
|
||||||
g_EmulationInProgress = false;
|
|
||||||
g_ReturnToGui = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XK_Tab:
|
|
||||||
CycleFrameLimit(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case XK_Escape:
|
|
||||||
signal(SIGINT, SIG_DFL);
|
|
||||||
signal(SIGPIPE, SIG_DFL);
|
|
||||||
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
|
||||||
if (g_SaveGSStream >= 3)
|
|
||||||
{
|
|
||||||
g_SaveGSStream = 4;// gs state
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if( Config.closeGSonEsc )
|
|
||||||
{
|
|
||||||
safe_delete( g_gsRecoveryState );
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
g_gsRecoveryState = new SafeArray<u8>();
|
|
||||||
JustGsSavingState eddie;
|
|
||||||
eddie.FreezePlugin( "GS", gsSafeFreeze ) ;
|
|
||||||
eddie.gsFreeze();
|
|
||||||
PluginsResetGS();
|
|
||||||
}
|
|
||||||
|
|
||||||
ClosePlugins( Config.closeGSonEsc );
|
|
||||||
|
|
||||||
if (!UseGui) exit(0);
|
|
||||||
|
|
||||||
// fixme: The GUI is now capable of receiving control back from the
|
|
||||||
// emulator. Which means that when I set g_ReturnToGui here, the emulation
|
|
||||||
// loop in ExecuteCpu() will exit. You should be able to set it up so
|
|
||||||
// that it returns control to the existing GTK event loop, instead of
|
|
||||||
// always starting a new one via RunGui(). (but could take some trial and
|
|
||||||
// error) -- (air)
|
|
||||||
|
|
||||||
// Easier said then done; running gtk in two threads at the same time can't be
|
|
||||||
// done, and working around that is pretty fiddly.
|
|
||||||
g_ReturnToGui = true;
|
|
||||||
RunGui();
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
GSkeyEvent(ev);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ev->evt == KEYRELEASE)
|
|
||||||
{
|
|
||||||
if (SHIFT_EVT(ev->key))
|
|
||||||
shift = 0;
|
|
||||||
if (CAPS_LOCK_EVT(ev->key))
|
|
||||||
{
|
|
||||||
//Release caps lock
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SysRestorableReset()
|
|
||||||
{
|
|
||||||
// already reset? and saved?
|
|
||||||
if( !g_EmulationInProgress ) return;
|
|
||||||
if( g_RecoveryState != NULL ) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
g_RecoveryState = new SafeArray<u8>( "Memory Savestate Recovery" );
|
|
||||||
RecoveryMemSavingState().FreezeAll();
|
|
||||||
safe_delete( g_gsRecoveryState );
|
|
||||||
g_EmulationInProgress = false;
|
|
||||||
}
|
|
||||||
catch( Exception::RuntimeError& ex )
|
|
||||||
{
|
|
||||||
Msgbox::Alert(
|
|
||||||
"Pcsx2 gamestate recovery failed. Some options may have been reverted to protect your game's state.\n"
|
|
||||||
"Error: %s", params ex.cMessage() );
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysReset()
|
|
||||||
{
|
|
||||||
if (!sinit) return;
|
|
||||||
|
|
||||||
StatusBar_Notice(_("Resetting..."));
|
|
||||||
//Console::SetTitle(_("Resetting..."));
|
|
||||||
|
|
||||||
g_EmulationInProgress = false;
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
safe_delete( g_gsRecoveryState );
|
|
||||||
ResetPlugins();
|
|
||||||
|
|
||||||
ElfCRC = 0;
|
|
||||||
|
|
||||||
// Note : No need to call cpuReset() here. It gets called automatically before the
|
|
||||||
// emulator resumes execution.
|
|
||||||
|
|
||||||
StatusBar_Notice(_("Ready"));
|
|
||||||
//Console::SetTitle(_("*PCSX2* Emulation state is reset."));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SysInit()
|
bool SysInit()
|
||||||
{
|
{
|
||||||
if (sinit) return true;
|
if (sinit) return true;
|
||||||
|
@ -928,61 +355,212 @@ void SysClose()
|
||||||
emuLog = NULL;
|
emuLog = NULL;
|
||||||
}
|
}
|
||||||
sinit = false;
|
sinit = false;
|
||||||
|
|
||||||
|
// Precautionary extra shutdown stuff.
|
||||||
|
SysEndExecution();
|
||||||
|
g_EmulationInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *SysLoadLibrary(const char *lib)
|
namespace HostSys
|
||||||
{
|
{
|
||||||
return dlopen(lib, RTLD_NOW);
|
void *LoadLibrary(const char *lib)
|
||||||
}
|
|
||||||
|
|
||||||
void *SysLoadSym(void *lib, const char *sym)
|
|
||||||
{
|
|
||||||
return dlsym(lib, sym);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *SysLibError()
|
|
||||||
{
|
|
||||||
return dlerror();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysCloseLibrary(void *lib)
|
|
||||||
{
|
|
||||||
dlclose(lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysRunGui()
|
|
||||||
{
|
|
||||||
RunGui();
|
|
||||||
}
|
|
||||||
|
|
||||||
void *SysMmap(uptr base, u32 size)
|
|
||||||
{
|
|
||||||
u8 *Mem;
|
|
||||||
Mem = (u8*)mmap((uptr*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
|
||||||
if (Mem == MAP_FAILED) Console::Notice("Mmap Failed!");
|
|
||||||
|
|
||||||
return Mem;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysMunmap(uptr base, u32 size)
|
|
||||||
{
|
|
||||||
munmap((uptr*)base, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysMemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution )
|
|
||||||
{
|
|
||||||
int lnxmode = 0;
|
|
||||||
|
|
||||||
// make sure size is aligned to the system page size:
|
|
||||||
size = (size + m_pagemask) & ~m_pagemask;
|
|
||||||
|
|
||||||
switch( mode )
|
|
||||||
{
|
{
|
||||||
case Protect_NoAccess: break;
|
return dlopen(lib, RTLD_NOW);
|
||||||
case Protect_ReadOnly: lnxmode = PROT_READ; break;
|
|
||||||
case Protect_ReadWrite: lnxmode = PROT_READ | PROT_WRITE; break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( allowExecution ) lnxmode |= PROT_EXEC;
|
void *LoadSym(void *lib, const char *sym)
|
||||||
mprotect( baseaddr, size, lnxmode );
|
{
|
||||||
|
return dlsym(lib, sym);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *LibError()
|
||||||
|
{
|
||||||
|
return dlerror();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseLibrary(void *lib)
|
||||||
|
{
|
||||||
|
dlclose(lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mmap(uptr base, u32 size)
|
||||||
|
{
|
||||||
|
u8 *Mem;
|
||||||
|
Mem = (u8*)mmap((uptr*)base, size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
|
||||||
|
if (Mem == MAP_FAILED) Console::Notice("Mmap Failed!");
|
||||||
|
|
||||||
|
return Mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Munmap(uptr base, u32 size)
|
||||||
|
{
|
||||||
|
munmap((uptr*)base, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution )
|
||||||
|
{
|
||||||
|
int lnxmode = 0;
|
||||||
|
|
||||||
|
// make sure size is aligned to the system page size:
|
||||||
|
size = (size + m_pagemask) & ~m_pagemask;
|
||||||
|
|
||||||
|
switch( mode )
|
||||||
|
{
|
||||||
|
case Protect_NoAccess: break;
|
||||||
|
case Protect_ReadOnly: lnxmode = PROT_READ; break;
|
||||||
|
case Protect_ReadWrite: lnxmode = PROT_READ | PROT_WRITE; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( allowExecution ) lnxmode |= PROT_EXEC;
|
||||||
|
mprotect( baseaddr, size, lnxmode );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace HostGui
|
||||||
|
{
|
||||||
|
// Sets the status bar message without mirroring the output to the console.
|
||||||
|
void SetStatusMsg( const string& text )
|
||||||
|
{
|
||||||
|
// don't try this in Visual C++ folks!
|
||||||
|
gtk_statusbar_push(GTK_STATUSBAR(pStatusBar), 0, text.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Notice( const string& text )
|
||||||
|
{
|
||||||
|
// mirror output to the console!
|
||||||
|
Console::Status( text.c_str() );
|
||||||
|
SetStatusMsg( test );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetMenuSlots()
|
||||||
|
{
|
||||||
|
GtkWidget *Item;
|
||||||
|
char str[g_MaxPath], str2[g_MaxPath];
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
sprintf(str, "load_slot_%d", i);
|
||||||
|
sprintf(str2, "save_slot_%d", i);
|
||||||
|
Item = lookup_widget(MainWindow, str);
|
||||||
|
|
||||||
|
if GTK_IS_WIDGET(Item)
|
||||||
|
gtk_widget_set_sensitive(Item, Slots[i]);
|
||||||
|
else
|
||||||
|
Console::Error("No such widget: %s", params str);
|
||||||
|
|
||||||
|
Item = lookup_widget(MainWindow, str2);
|
||||||
|
gtk_widget_set_sensitive(Item, (ElfCRC != 0));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginExecution()
|
||||||
|
{
|
||||||
|
// Destroy the window. Ugly thing.
|
||||||
|
gtk_widget_destroy(MainWindow);
|
||||||
|
gtk_main_quit();
|
||||||
|
|
||||||
|
while (gtk_events_pending()) gtk_main_iteration();
|
||||||
|
|
||||||
|
signal(SIGINT, SignalExit);
|
||||||
|
signal(SIGPIPE, SignalExit);
|
||||||
|
|
||||||
|
// no try/catch needed since no cleanup needed.. ?
|
||||||
|
SysExecute();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall KeyEvent(keyEvent* ev)
|
||||||
|
{
|
||||||
|
static int shift = 0;
|
||||||
|
|
||||||
|
if (ev == NULL) return;
|
||||||
|
|
||||||
|
if (GSkeyEvent != NULL) GSkeyEvent(ev);
|
||||||
|
|
||||||
|
if (ev->evt == KEYPRESS)
|
||||||
|
{
|
||||||
|
if (SHIFT_EVT(ev->key))
|
||||||
|
shift = 1;
|
||||||
|
if (CAPS_LOCK_EVT(ev->key))
|
||||||
|
{
|
||||||
|
//Set up anything we want to happen while caps lock is down.
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ev->key)
|
||||||
|
{
|
||||||
|
case XK_F1:
|
||||||
|
case XK_F2:
|
||||||
|
case XK_F3:
|
||||||
|
case XK_F4:
|
||||||
|
case XK_F5:
|
||||||
|
case XK_F6:
|
||||||
|
case XK_F7:
|
||||||
|
case XK_F8:
|
||||||
|
case XK_F9:
|
||||||
|
case XK_F10:
|
||||||
|
case XK_F11:
|
||||||
|
case XK_F12:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessFKeys(ev->key - XK_F1 + 1, shift);
|
||||||
|
}
|
||||||
|
catch (Exception::CpuStateShutdown&)
|
||||||
|
{
|
||||||
|
// Woops! Something was unrecoverable. Bummer.
|
||||||
|
// Let's give the user a RunGui!
|
||||||
|
|
||||||
|
g_EmulationInProgress = false;
|
||||||
|
SysEndExecution();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XK_Tab:
|
||||||
|
CycleFrameLimit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case XK_Escape:
|
||||||
|
signal(SIGINT, SIG_DFL);
|
||||||
|
signal(SIGPIPE, SIG_DFL);
|
||||||
|
|
||||||
|
#ifdef PCSX2_DEVBUILD
|
||||||
|
if (g_SaveGSStream >= 3)
|
||||||
|
{
|
||||||
|
g_SaveGSStream = 4;// gs state
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
SysEndExecution();
|
||||||
|
|
||||||
|
if (!UseGui) exit(0);
|
||||||
|
|
||||||
|
// fixme: The GUI is now capable of receiving control back from the
|
||||||
|
// emulator. Which means that when we call SysEscapeExecute() here, the
|
||||||
|
// emulation loop in ExecuteCpu() will exit. You should be able to set it
|
||||||
|
// up so that it returns control to the existing GTK event loop, instead of
|
||||||
|
// always starting a new one via RunGui(). (but could take some trial and
|
||||||
|
// error) -- (air)
|
||||||
|
|
||||||
|
// Easier said then done; running gtk in two threads at the same time can't be
|
||||||
|
// done, and working around that is pretty fiddly.
|
||||||
|
RunGui();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
GSkeyEvent(ev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ev->evt == KEYRELEASE)
|
||||||
|
{
|
||||||
|
if (SHIFT_EVT(ev->key))
|
||||||
|
shift = 0;
|
||||||
|
if (CAPS_LOCK_EVT(ev->key))
|
||||||
|
{
|
||||||
|
//Release caps lock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -10,7 +10,8 @@ Memory.cpp MemoryCard.cpp Misc.cpp Patch.cpp PathUtils.cpp Plugins.cpp Precompil
|
||||||
R3000AInterpreter.cpp R3000AOpcodeTables.cpp R5900.cpp R5900OpcodeImpl.cpp R5900OpcodeTables.cpp \
|
R3000AInterpreter.cpp R3000AOpcodeTables.cpp R5900.cpp R5900OpcodeImpl.cpp R5900OpcodeTables.cpp \
|
||||||
SPR.cpp SaveState.cpp Sif.cpp Sio.cpp SourceLog.cpp Stats.cpp System.cpp ThreadTools.cpp \
|
SPR.cpp SaveState.cpp Sif.cpp Sio.cpp SourceLog.cpp Stats.cpp System.cpp ThreadTools.cpp \
|
||||||
VU0.cpp VU0micro.cpp VU0microInterp.cpp VU1micro.cpp VU1microInterp.cpp VUflags.cpp VUmicroMem.cpp VUops.cpp \
|
VU0.cpp VU0micro.cpp VU0microInterp.cpp VU1micro.cpp VU1microInterp.cpp VUflags.cpp VUmicroMem.cpp VUops.cpp \
|
||||||
Vif.cpp VifDma.cpp vssprintf.cpp vtlb.cpp xmlpatchloader.cpp AlignedMalloc.cpp
|
Vif.cpp VifDma.cpp vssprintf.cpp vtlb.cpp xmlpatchloader.cpp AlignedMalloc.cpp \
|
||||||
|
RecoverySystem.cpp Saveslots.cpp
|
||||||
|
|
||||||
|
|
||||||
libpcsx2_a_SOURCES += \
|
libpcsx2_a_SOURCES += \
|
||||||
|
@ -18,6 +19,6 @@ CDVD.h CDVDiso.h CDVDisodrv.h CDVDlib.h COP0.h Cache.h CdRom.h Common.h Counters
|
||||||
Elfheader.h Exceptions.h GS.h Hw.h IopBios.h IopBios2.h IopCounters.h IopDma.h IopHw.h IopMem.h IopSio2.h Memcpyfast.h \
|
Elfheader.h Exceptions.h GS.h Hw.h IopBios.h IopBios2.h IopCounters.h IopDma.h IopHw.h IopMem.h IopSio2.h Memcpyfast.h \
|
||||||
Memory.h MemoryCard.h Misc.h Patch.h Paths.h Plugins.h PrecompiledHeader.h PsxCommon.h R3000A.h R5900.h R5900OpcodeTables.h \
|
Memory.h MemoryCard.h Misc.h Patch.h Paths.h Plugins.h PrecompiledHeader.h PsxCommon.h R3000A.h R5900.h R5900OpcodeTables.h \
|
||||||
SPR.h SamplProf.h SaveState.h Sif.h Sifcmd.h Sio.h SafeArray.h Stats.h StringUtils.h System.h Threading.h \
|
SPR.h SamplProf.h SaveState.h Sif.h Sifcmd.h Sio.h SafeArray.h Stats.h StringUtils.h System.h Threading.h \
|
||||||
VU.h VUflags.h VUmicro.h VUops.h Vif.h VifDma.h cheatscpp.h vtlb.h NakedAsm.h R5900Exceptions.h
|
VU.h VUflags.h VUmicro.h VUops.h Vif.h VifDma.h cheatscpp.h vtlb.h NakedAsm.h R5900Exceptions.h HostGui.h
|
||||||
|
|
||||||
SUBDIRS = x86 . DebugTools IPU RDebug tinyxml Linux
|
SUBDIRS = x86 . DebugTools IPU RDebug tinyxml Linux
|
|
@ -651,7 +651,7 @@ void memReset()
|
||||||
{
|
{
|
||||||
// VTLB Protection Preparations.
|
// VTLB Protection Preparations.
|
||||||
|
|
||||||
SysMemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite );
|
HostSys::MemProtect( m_psAllMem, m_allMemSize, Protect_ReadWrite );
|
||||||
|
|
||||||
// Note!! Ideally the vtlb should only be initialized once, and then subsequent
|
// Note!! Ideally the vtlb should only be initialized once, and then subsequent
|
||||||
// resets of the system hardware would only clear vtlb mappings, but since the
|
// resets of the system hardware would only clear vtlb mappings, but since the
|
||||||
|
@ -821,7 +821,7 @@ int mmap_GetRamPageInfo(void* ptr)
|
||||||
|
|
||||||
void mmap_MarkCountedRamPage(void* ptr,u32 vaddr)
|
void mmap_MarkCountedRamPage(void* ptr,u32 vaddr)
|
||||||
{
|
{
|
||||||
SysMemProtect( ptr, 1, Protect_ReadOnly );
|
HostSys::MemProtect( ptr, 1, Protect_ReadOnly );
|
||||||
|
|
||||||
u32 offset=((u8*)ptr-psM);
|
u32 offset=((u8*)ptr-psM);
|
||||||
offset>>=12;
|
offset>>=12;
|
||||||
|
@ -842,12 +842,12 @@ void mmap_ResetBlockTracking()
|
||||||
{
|
{
|
||||||
psMPWVA[i].clear();
|
psMPWVA[i].clear();
|
||||||
}
|
}
|
||||||
SysMemProtect( psM, Ps2MemSize::Base, Protect_ReadWrite );
|
HostSys::MemProtect( psM, Ps2MemSize::Base, Protect_ReadWrite );
|
||||||
}
|
}
|
||||||
|
|
||||||
void mmap_ClearCpuBlock( uint offset )
|
void mmap_ClearCpuBlock( uint offset )
|
||||||
{
|
{
|
||||||
SysMemProtect( &psM[offset], 1, Protect_ReadWrite );
|
HostSys::MemProtect( &psM[offset], 1, Protect_ReadWrite );
|
||||||
|
|
||||||
offset>>=12;
|
offset>>=12;
|
||||||
psMPWC[(offset/32)]|=(1<<(offset&31));
|
psMPWC[(offset/32)]|=(1<<(offset&31));
|
||||||
|
|
|
@ -63,7 +63,7 @@ const char *LabelAuthors = { N_(
|
||||||
"\n"
|
"\n"
|
||||||
"Betatesting: Bositman, ChaosCode,\n"
|
"Betatesting: Bositman, ChaosCode,\n"
|
||||||
"CKemu, crushtest, GeneralPlot,\n"
|
"CKemu, crushtest, GeneralPlot,\n"
|
||||||
"Krakatos, Paorotaku, Rudy_X\n"
|
"Krakatos, Parotaku, Rudy_X\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Webmasters: CKemu, Falcon4ever"
|
"Webmasters: CKemu, Falcon4ever"
|
||||||
)
|
)
|
||||||
|
@ -611,7 +611,7 @@ void ProcessFKeys(int fkey, int shift)
|
||||||
{
|
{
|
||||||
gzLoadingState joe( SaveState::GetFilename( StatesC ) ); // throws exception on version mismatch
|
gzLoadingState joe( SaveState::GetFilename( StatesC ) ); // throws exception on version mismatch
|
||||||
cpuReset();
|
cpuReset();
|
||||||
SysResetExecutionState();
|
SysClearExecutionCache();
|
||||||
joe.FreezeAll();
|
joe.FreezeAll();
|
||||||
}
|
}
|
||||||
catch( Exception::StateLoadError_Recoverable& )
|
catch( Exception::StateLoadError_Recoverable& )
|
||||||
|
@ -647,7 +647,7 @@ void ProcessFKeys(int fkey, int shift)
|
||||||
|
|
||||||
// note: VK_F5-VK_F7 are reserved for GS
|
// note: VK_F5-VK_F7 are reserved for GS
|
||||||
case 8:
|
case 8:
|
||||||
GSmakeSnapshot("snaps/");
|
GSmakeSnapshot( SNAPSHOTS_DIR "/" );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
|
|
|
@ -18,6 +18,7 @@ extern char MAIN_DIR[g_MaxPath];
|
||||||
#define SSTATES_DIR "sstates"
|
#define SSTATES_DIR "sstates"
|
||||||
#define LANGS_DIR "Langs"
|
#define LANGS_DIR "Langs"
|
||||||
#define LOGS_DIR "logs"
|
#define LOGS_DIR "logs"
|
||||||
|
#define SNAPSHOTS_DIR "snaps"
|
||||||
|
|
||||||
#define DEFAULT_MEMCARD1 "Mcd001.ps2"
|
#define DEFAULT_MEMCARD1 "Mcd001.ps2"
|
||||||
#define DEFAULT_MEMCARD2 "Mcd002.ps2"
|
#define DEFAULT_MEMCARD2 "Mcd002.ps2"
|
||||||
|
|
|
@ -648,7 +648,8 @@ int InitPlugins()
|
||||||
void ShutdownPlugins()
|
void ShutdownPlugins()
|
||||||
{
|
{
|
||||||
if( !initp ) return;
|
if( !initp ) return;
|
||||||
|
|
||||||
|
mtgsWaitGS();
|
||||||
ClosePlugins( true );
|
ClosePlugins( true );
|
||||||
|
|
||||||
if( GSshutdown != NULL )
|
if( GSshutdown != NULL )
|
||||||
|
@ -848,15 +849,6 @@ void ClosePlugins( bool closegs )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetPlugins()
|
|
||||||
{
|
|
||||||
|
|
||||||
mtgsWaitGS();
|
|
||||||
|
|
||||||
ShutdownPlugins();
|
|
||||||
InitPlugins();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReleasePlugins()
|
void ReleasePlugins()
|
||||||
{
|
{
|
||||||
if (!loadp) return;
|
if (!loadp) return;
|
||||||
|
|
|
@ -34,11 +34,7 @@ int OpenPlugins(const char* pTitleFilename);
|
||||||
void ClosePlugins( bool closegs );
|
void ClosePlugins( bool closegs );
|
||||||
|
|
||||||
int InitPlugins();
|
int InitPlugins();
|
||||||
|
void ShutdownPlugins();
|
||||||
// Completely shuts down all plugins and re-initializes them. (clean slate)
|
|
||||||
// Plugins are not unloaded, so changes to Config.Plugins values will not
|
|
||||||
// take effect. Use a manual set oc alls to ReleasePlugins and LoadPlugins for that.
|
|
||||||
void ResetPlugins();
|
|
||||||
|
|
||||||
void PluginsResetGS();
|
void PluginsResetGS();
|
||||||
|
|
||||||
|
|
|
@ -58,31 +58,11 @@ bool eeEventTestIsActive = false;
|
||||||
|
|
||||||
R5900Exception::BaseExcept::~BaseExcept() throw (){}
|
R5900Exception::BaseExcept::~BaseExcept() throw (){}
|
||||||
|
|
||||||
// A run-once procedure for initializing the emulation state.
|
|
||||||
// Can be done anytime after allocating memory, and before calling Cpu->Execute().
|
|
||||||
// Multiple calls to this function are automatically ignored.
|
|
||||||
/*void cpuInit()
|
|
||||||
{
|
|
||||||
DevCon::WriteLn( "cpuInit > %s", params cpuIsInitialized ? "Initializing..." : "Skipping (already initialized)" );
|
|
||||||
|
|
||||||
if( cpuIsInitialized ) return;
|
|
||||||
|
|
||||||
cpuIsInitialized = true;
|
|
||||||
|
|
||||||
// non memInit() currently since we don't support soft resets. memory is initialized in full
|
|
||||||
// instead during cpuReset() [using memReset()]
|
|
||||||
//memInit();
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void cpuReset()
|
void cpuReset()
|
||||||
{
|
{
|
||||||
mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case.
|
mtgsWaitGS(); // GS better be done processing before we reset the EE, just in case.
|
||||||
//cpuInit(); // more just-in-caseness!
|
cpuIsInitialized = true;
|
||||||
|
|
||||||
//if( !cpuIsInitialized )
|
|
||||||
{
|
|
||||||
cpuIsInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
memReset();
|
memReset();
|
||||||
psxMemReset();
|
psxMemReset();
|
||||||
|
@ -118,9 +98,6 @@ void cpuReset()
|
||||||
|
|
||||||
void cpuShutdown()
|
void cpuShutdown()
|
||||||
{
|
{
|
||||||
//if( !cpuIsInitialized ) return;
|
|
||||||
//cpuIsInitialized = false;
|
|
||||||
|
|
||||||
mtgsWaitGS();
|
mtgsWaitGS();
|
||||||
|
|
||||||
hwShutdown();
|
hwShutdown();
|
||||||
|
|
|
@ -0,0 +1,290 @@
|
||||||
|
/* Pcsx2 - Pc Ps2 Emulator
|
||||||
|
* Copyright (C) 2002-2009 Pcsx2 Team
|
||||||
|
*
|
||||||
|
* 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 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "HostGui.h"
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RecoverySystem.cpp -- houses code for recovering from on-the-fly changes to the emu
|
||||||
|
// configuration, and for saving/restoring the GS state (for more seamless exiting of
|
||||||
|
// fullscreen GS operation).
|
||||||
|
//
|
||||||
|
// The following handful of local classes are implemented att he bottom of this file.
|
||||||
|
|
||||||
|
static SafeArray<u8>* g_RecoveryState = NULL;
|
||||||
|
static SafeArray<u8>* g_gsRecoveryState = NULL;
|
||||||
|
|
||||||
|
// This class type creates a memory savestate using the existing Recovery information
|
||||||
|
// (if present) to generate the savestate material. If no recovery data is present,
|
||||||
|
// the current emulation state is used instead.
|
||||||
|
class RecoveryMemSavingState : public memSavingState, Sealed
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~RecoveryMemSavingState() { }
|
||||||
|
RecoveryMemSavingState();
|
||||||
|
|
||||||
|
void gsFreeze();
|
||||||
|
void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) );
|
||||||
|
};
|
||||||
|
|
||||||
|
// This class type creates an on-disk (zipped) savestate using the existing Recovery
|
||||||
|
// information (if present) to generate the savestate material. If no recovery data is
|
||||||
|
// present, the current emulation state is used instead.
|
||||||
|
class RecoveryZipSavingState : public gzSavingState, Sealed
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~RecoveryZipSavingState() { }
|
||||||
|
RecoveryZipSavingState( const string& filename );
|
||||||
|
|
||||||
|
void gsFreeze();
|
||||||
|
void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) );
|
||||||
|
};
|
||||||
|
|
||||||
|
// Special helper class used to save *just* the GS-relevant state information.
|
||||||
|
class JustGsSavingState : public memSavingState, Sealed
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~JustGsSavingState() { }
|
||||||
|
JustGsSavingState();
|
||||||
|
|
||||||
|
// This special override saves the gs info to m_idx+4, and then goes back and
|
||||||
|
// writes in the length of data saved.
|
||||||
|
void gsFreeze();
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace StateRecovery {
|
||||||
|
|
||||||
|
bool HasState()
|
||||||
|
{
|
||||||
|
return g_RecoveryState != NULL || g_gsRecoveryState != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exceptions:
|
||||||
|
void Recover()
|
||||||
|
{
|
||||||
|
// Just in case they weren't initialized earlier (no harm in calling this multiple times)
|
||||||
|
if( OpenPlugins(NULL) == -1 ) return;
|
||||||
|
|
||||||
|
if( g_RecoveryState != NULL )
|
||||||
|
{
|
||||||
|
Console::Status( "Resuming execution from full memory state..." );
|
||||||
|
memLoadingState( *g_RecoveryState ).FreezeAll();
|
||||||
|
}
|
||||||
|
else if( g_gsRecoveryState != NULL )
|
||||||
|
{
|
||||||
|
s32 dummylen;
|
||||||
|
|
||||||
|
Console::Status( "Resuming execution from gsState..." );
|
||||||
|
memLoadingState eddie( *g_gsRecoveryState );
|
||||||
|
eddie.FreezePlugin( "GS", gsSafeFreeze );
|
||||||
|
eddie.Freeze( dummylen ); // reads the length value recorded earlier.
|
||||||
|
eddie.gsFreeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
StateRecovery::Clear();
|
||||||
|
|
||||||
|
// this needs to be called for every new game!
|
||||||
|
// (note: sometimes launching games through bios will give a crc of 0)
|
||||||
|
|
||||||
|
if( GSsetGameCRC != NULL )
|
||||||
|
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saves recovery state info to the given filename, or saves the active emulation state
|
||||||
|
// (if one exists) and no recovery data was found. This is needed because when a recovery
|
||||||
|
// state is made, the emulation state is usually reset so the only persisting state is
|
||||||
|
// the one in the memory save. :)
|
||||||
|
void SaveToFile( const string& file )
|
||||||
|
{
|
||||||
|
if( g_RecoveryState != NULL )
|
||||||
|
{
|
||||||
|
// State is already saved into memory, and the emulator (and in-progress flag)
|
||||||
|
// have likely been cleared out. So save from the Recovery buffer instead of
|
||||||
|
// doing a "standard" save:
|
||||||
|
|
||||||
|
gzFile fileptr = gzopen( file.c_str(), "wb" );
|
||||||
|
if( fileptr == NULL )
|
||||||
|
{
|
||||||
|
Msgbox::Alert( _("File permissions error while trying to save to file:\n\t%ts"), params &file );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gzwrite( fileptr, &g_SaveVersion, sizeof( u32 ) );
|
||||||
|
gzwrite( fileptr, g_RecoveryState->GetPtr(), g_RecoveryState->GetSizeInBytes() );
|
||||||
|
gzclose( fileptr );
|
||||||
|
}
|
||||||
|
else if( g_gsRecoveryState != NULL )
|
||||||
|
{
|
||||||
|
RecoveryZipSavingState( file ).FreezeAll();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !g_EmulationInProgress )
|
||||||
|
{
|
||||||
|
Msgbox::Alert( "You need to start a game first before you can save it's state." );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
States_Save( file );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Saves recovery state info to the given saveslot, or saves the active emulation state
|
||||||
|
// (if one exists) and no recovery data was found. This is needed because when a recovery
|
||||||
|
// state is made, the emulation state is usually reset so the only persisting state is
|
||||||
|
// the one in the memory save. :)
|
||||||
|
void SaveToSlot( uint num )
|
||||||
|
{
|
||||||
|
SaveToFile( SaveState::GetFilename( num ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
// This method will override any existing recovery states, so call it with caution, if you
|
||||||
|
// think that there could be existing important state info in the recovery buffers (but
|
||||||
|
// really there shouldn't be, unless you're calling this function when it's not intended
|
||||||
|
// to be called).
|
||||||
|
void MakeGsOnly()
|
||||||
|
{
|
||||||
|
StateRecovery::Clear();
|
||||||
|
|
||||||
|
if( !g_EmulationInProgress ) return;
|
||||||
|
|
||||||
|
g_gsRecoveryState = new SafeArray<u8>();
|
||||||
|
JustGsSavingState eddie;
|
||||||
|
eddie.FreezePlugin( "GS", gsSafeFreeze ) ;
|
||||||
|
eddie.gsFreeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a full recovery of the entire emulation state (CPU and all plugins).
|
||||||
|
// If a current recovery state is already present, then nothing is done (the
|
||||||
|
// existing recovery state takes precedence).
|
||||||
|
void MakeFull()
|
||||||
|
{
|
||||||
|
if( g_RecoveryState != NULL ) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
g_RecoveryState = new SafeArray<u8>( "Memory Savestate Recovery" );
|
||||||
|
RecoveryMemSavingState().FreezeAll();
|
||||||
|
safe_delete( g_gsRecoveryState );
|
||||||
|
g_EmulationInProgress = false;
|
||||||
|
}
|
||||||
|
catch( Exception::RuntimeError& ex )
|
||||||
|
{
|
||||||
|
Msgbox::Alert(
|
||||||
|
"Pcsx2 gamestate recovery failed. Some options may have been reverted to protect your game's state.\n"
|
||||||
|
"Error: %s", params ex.cMessage() );
|
||||||
|
safe_delete( g_RecoveryState );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clears and deallocates any recovery states.
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
safe_delete( g_RecoveryState );
|
||||||
|
safe_delete( g_gsRecoveryState );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RecoveryMemSavingState::RecoveryMemSavingState() : memSavingState( *g_RecoveryState )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecoveryMemSavingState::gsFreeze()
|
||||||
|
{
|
||||||
|
if( g_gsRecoveryState != NULL )
|
||||||
|
{
|
||||||
|
// just copy the data from src to dst.
|
||||||
|
// the normal savestate doesn't expect a length prefix for internal structures,
|
||||||
|
// so don't copy that part.
|
||||||
|
const u32 pluginlen = *((u32*)g_gsRecoveryState->GetPtr());
|
||||||
|
const u32 gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
||||||
|
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(pluginlen+8), gslen );
|
||||||
|
m_idx += gslen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memSavingState::gsFreeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecoveryMemSavingState::FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )
|
||||||
|
{
|
||||||
|
if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) )
|
||||||
|
{
|
||||||
|
// Gs data is already in memory, so just copy from src to dest:
|
||||||
|
// length of the GS data is stored as the first u32, so use that to run the copy:
|
||||||
|
const u32 len = *((u32*)g_gsRecoveryState->GetPtr());
|
||||||
|
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(), len+4 );
|
||||||
|
m_idx += len+4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memSavingState::FreezePlugin( name, freezer );
|
||||||
|
}
|
||||||
|
|
||||||
|
RecoveryZipSavingState::RecoveryZipSavingState( const string& filename ) : gzSavingState( filename )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecoveryZipSavingState::gsFreeze()
|
||||||
|
{
|
||||||
|
if( g_gsRecoveryState != NULL )
|
||||||
|
{
|
||||||
|
// read data from the gsRecoveryState allocation instead of the GS, since the gs
|
||||||
|
// info was invalidated when the plugin was shut down.
|
||||||
|
|
||||||
|
// the normal savestate doesn't expect a length prefix for internal structures,
|
||||||
|
// so don't copy that part.
|
||||||
|
|
||||||
|
u32& pluginlen = *((u32*)g_gsRecoveryState->GetPtr(0));
|
||||||
|
u32& gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
||||||
|
gzwrite( m_file, g_gsRecoveryState->GetPtr(pluginlen+4), gslen );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gzSavingState::gsFreeze();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RecoveryZipSavingState::FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )
|
||||||
|
{
|
||||||
|
if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) )
|
||||||
|
{
|
||||||
|
// Gs data is already in memory, so just copy from there into the gzip file.
|
||||||
|
// length of the GS data is stored as the first u32, so use that to run the copy:
|
||||||
|
u32& len = *((u32*)g_gsRecoveryState->GetPtr());
|
||||||
|
gzwrite( m_file, g_gsRecoveryState->GetPtr(), len+4 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gzSavingState::FreezePlugin( name, freezer );
|
||||||
|
}
|
||||||
|
|
||||||
|
JustGsSavingState::JustGsSavingState() : memSavingState( *g_gsRecoveryState )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// This special override saves the gs info to m_idx+4, and then goes back and
|
||||||
|
// writes in the length of data saved.
|
||||||
|
void JustGsSavingState::gsFreeze()
|
||||||
|
{
|
||||||
|
int oldmidx = m_idx;
|
||||||
|
m_idx += 4;
|
||||||
|
memSavingState::gsFreeze();
|
||||||
|
if( IsSaving() )
|
||||||
|
{
|
||||||
|
s32& len = *((s32*)m_memory.GetPtr( oldmidx ));
|
||||||
|
len = (m_idx - oldmidx)-4;
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,7 +62,7 @@ extern void pcsx2_aligned_free(void* pmem);
|
||||||
|
|
||||||
#define SafeSysMunmap( ptr, size ) \
|
#define SafeSysMunmap( ptr, size ) \
|
||||||
if( ptr != NULL ) { \
|
if( ptr != NULL ) { \
|
||||||
SysMunmap( (uptr)ptr, size ); \
|
HostSys::Munmap( (uptr)ptr, size ); \
|
||||||
ptr = NULL; \
|
ptr = NULL; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,6 @@
|
||||||
#include "COP0.h"
|
#include "COP0.h"
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace R5900;
|
using namespace R5900;
|
||||||
|
|
||||||
extern int g_psxWriteOk;
|
extern int g_psxWriteOk;
|
||||||
|
@ -41,7 +40,7 @@ extern void recResetIOP();
|
||||||
|
|
||||||
static void PreLoadPrep()
|
static void PreLoadPrep()
|
||||||
{
|
{
|
||||||
SysResetExecutionState();
|
SysClearExecutionCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PostLoadPrep()
|
static void PostLoadPrep()
|
||||||
|
|
|
@ -200,4 +200,15 @@ public:
|
||||||
bool IsSaving() const { return false; }
|
bool IsSaving() const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace StateRecovery
|
||||||
|
{
|
||||||
|
extern bool HasState();
|
||||||
|
extern void Recover();
|
||||||
|
extern void SaveToFile( const string& file );
|
||||||
|
extern void SaveToSlot( uint num );
|
||||||
|
extern void MakeGsOnly();
|
||||||
|
extern void MakeFull();
|
||||||
|
extern void Clear();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,251 @@
|
||||||
|
/* Pcsx2 - Pc Ps2 Emulator
|
||||||
|
* Copyright (C) 2002-2009 Pcsx2 Team
|
||||||
|
*
|
||||||
|
* 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 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PrecompiledHeader.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "HostGui.h"
|
||||||
|
|
||||||
|
#include "GS.h"
|
||||||
|
|
||||||
|
TESTRUNARGS g_TestRun;
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Save Slot Detection System
|
||||||
|
|
||||||
|
static int Slots[5] = { -1, -1, -1, -1, -1 };
|
||||||
|
|
||||||
|
bool States_isSlotUsed(int num)
|
||||||
|
{
|
||||||
|
if (ElfCRC == 0)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return Path::isFile(SaveState::GetFilename( num ));
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Save state load-from-file (or slot) helpers.
|
||||||
|
|
||||||
|
// Internal use state loading function which does not trap exceptions.
|
||||||
|
// The calling function should trap ahnd handle exceptions as needed.
|
||||||
|
static void _loadStateOrExcept( const string& file )
|
||||||
|
{
|
||||||
|
gzLoadingState joe( file ); // this'll throw an StateLoadError_Recoverable.
|
||||||
|
|
||||||
|
// Make sure the cpu and plugins are ready to be state-ified!
|
||||||
|
cpuReset();
|
||||||
|
OpenPlugins( NULL );
|
||||||
|
|
||||||
|
joe.FreezeAll();
|
||||||
|
|
||||||
|
if( GSsetGameCRC != NULL )
|
||||||
|
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the new state was loaded, or false if nothing happened.
|
||||||
|
void States_Load( const string& file )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_loadStateOrExcept( file );
|
||||||
|
HostGui::Notice( fmt_string(_("*PCSX2*: Loaded State %s"), file) );
|
||||||
|
}
|
||||||
|
catch( Exception::StateLoadError_Recoverable& ex)
|
||||||
|
{
|
||||||
|
Console::Notice( "Could not load savestate file: %s.\n\n%s", params file, ex.cMessage() );
|
||||||
|
|
||||||
|
// At this point the cpu hasn't been reset, so we can return
|
||||||
|
// control to the user safely... (that's why we use a console notice instead of a popup)
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch( Exception::BaseException& ex )
|
||||||
|
{
|
||||||
|
// The emulation state is ruined. Might as well give them a popup and start the gui.
|
||||||
|
|
||||||
|
string message( fmt_string(
|
||||||
|
"Encountered an error while loading savestate from file: %s.\n", file ) );
|
||||||
|
|
||||||
|
if( g_EmulationInProgress )
|
||||||
|
message += "Since the savestate load was incomplete, the emulator must reset.\n";
|
||||||
|
|
||||||
|
message += "\nError: " + ex.Message();
|
||||||
|
|
||||||
|
Msgbox::Alert( message.c_str() );
|
||||||
|
SysReset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HostGui::BeginExecution();
|
||||||
|
}
|
||||||
|
|
||||||
|
void States_Load(int num)
|
||||||
|
{
|
||||||
|
string file( SaveState::GetFilename( num ) );
|
||||||
|
|
||||||
|
if( !Path::isFile( file ) )
|
||||||
|
{
|
||||||
|
Console::Notice( "Saveslot %d is empty.", params num );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_loadStateOrExcept( file );
|
||||||
|
HostGui::Notice( fmt_string( _("*PCSX2*: Loaded State %d"), num ) );
|
||||||
|
}
|
||||||
|
catch( Exception::StateLoadError_Recoverable& ex)
|
||||||
|
{
|
||||||
|
Console::Notice( "Could not load savestate slot %d.\n\n%s", params num, ex.cMessage() );
|
||||||
|
|
||||||
|
// At this point the cpu hasn't been reset, so we can return
|
||||||
|
// control to the user safely... (that's why we use a console notice instead of a popup)
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch( Exception::BaseException& ex )
|
||||||
|
{
|
||||||
|
// The emulation state is ruined. Might as well give them a popup and start the gui.
|
||||||
|
|
||||||
|
string message( fmt_string(
|
||||||
|
"Encountered an error while loading savestate from slot %d.\n", num ) );
|
||||||
|
|
||||||
|
if( g_EmulationInProgress )
|
||||||
|
message += "Since the savestate load was incomplete, the emulator has been reset.\n";
|
||||||
|
|
||||||
|
message += "\nError: " + ex.Message();
|
||||||
|
|
||||||
|
Msgbox::Alert( message.c_str() );
|
||||||
|
SysEndExecution();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HostGui::BeginExecution();
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Save state save-to-file (or slot) helpers.
|
||||||
|
|
||||||
|
void States_Save( const string& file )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
StateRecovery::SaveToFile( file );
|
||||||
|
HostGui::Notice( fmt_string( _( "State saved to file: %s" ), file ) );
|
||||||
|
}
|
||||||
|
catch( Exception::BaseException& ex )
|
||||||
|
{
|
||||||
|
Console::Error( (fmt_string(
|
||||||
|
"An error occurred while trying to save to file %s\n", file ) +
|
||||||
|
"Your emulation state has not been saved!\n\nError: " + ex.Message()).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filename could be a valid slot, so still need to update
|
||||||
|
HostGui::ResetMenuSlots();
|
||||||
|
}
|
||||||
|
|
||||||
|
void States_Save(int num)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
StateRecovery::SaveToSlot( num );
|
||||||
|
HostGui::Notice( fmt_string( _( "State saved to slot %d" ) , num ) );
|
||||||
|
}
|
||||||
|
catch( Exception::BaseException& ex )
|
||||||
|
{
|
||||||
|
Console::Error( (fmt_string(
|
||||||
|
"An error occurred while trying to save to slot %d\n", num ) +
|
||||||
|
"Your emulation state has not been saved!\n\nError: " + ex.Message()).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
HostGui::ResetMenuSlots();
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
void vSyncDebugStuff( uint frame )
|
||||||
|
{
|
||||||
|
#ifdef PCSX2_DEVBUILD
|
||||||
|
if( g_TestRun.enabled && g_TestRun.frame > 0 ) {
|
||||||
|
if( frame > g_TestRun.frame ) {
|
||||||
|
// take a snapshot
|
||||||
|
if( g_TestRun.pimagename != NULL && GSmakeSnapshot2 != NULL ) {
|
||||||
|
if( g_TestRun.snapdone ) {
|
||||||
|
g_TestRun.curimage++;
|
||||||
|
g_TestRun.snapdone = 0;
|
||||||
|
g_TestRun.frame += 20;
|
||||||
|
if( g_TestRun.curimage >= g_TestRun.numimages ) {
|
||||||
|
// exit
|
||||||
|
SysEndExecution();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// query for the image
|
||||||
|
GSmakeSnapshot2(g_TestRun.pimagename, &g_TestRun.snapdone, g_TestRun.jpgcapture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// exit
|
||||||
|
SysEndExecution();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GSVSYNC();
|
||||||
|
|
||||||
|
if( g_SaveGSStream == 1 ) {
|
||||||
|
freezeData fP;
|
||||||
|
|
||||||
|
g_SaveGSStream = 2;
|
||||||
|
g_fGSSave->gsFreeze();
|
||||||
|
|
||||||
|
if (GSfreeze(FREEZE_SIZE, &fP) == -1) {
|
||||||
|
safe_delete( g_fGSSave );
|
||||||
|
g_SaveGSStream = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fP.data = (s8*)malloc(fP.size);
|
||||||
|
if (fP.data == NULL) {
|
||||||
|
safe_delete( g_fGSSave );
|
||||||
|
g_SaveGSStream = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (GSfreeze(FREEZE_SAVE, &fP) == -1) {
|
||||||
|
safe_delete( g_fGSSave );
|
||||||
|
g_SaveGSStream = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_fGSSave->Freeze( fP.size );
|
||||||
|
if (fP.size) {
|
||||||
|
g_fGSSave->FreezeMem( fP.data, fP.size );
|
||||||
|
free(fP.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if( g_SaveGSStream == 2 ) {
|
||||||
|
|
||||||
|
if( --g_nLeftGSFrames <= 0 ) {
|
||||||
|
safe_delete( g_fGSSave );
|
||||||
|
g_SaveGSStream = 0;
|
||||||
|
Console::WriteLn("Done saving GS stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
157
pcsx2/System.cpp
157
pcsx2/System.cpp
|
@ -19,14 +19,16 @@
|
||||||
#include "PrecompiledHeader.h"
|
#include "PrecompiledHeader.h"
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
#include "VUmicro.h"
|
|
||||||
#include "Threading.h"
|
#include "Threading.h"
|
||||||
|
#include "HostGui.h"
|
||||||
|
|
||||||
|
#include "VUmicro.h"
|
||||||
#include "iR5900.h"
|
#include "iR5900.h"
|
||||||
#include "R3000A.h"
|
#include "R3000A.h"
|
||||||
#include "IopMem.h"
|
#include "IopMem.h"
|
||||||
#include "iVUzerorec.h" // for SuperVUReset
|
#include "iVUzerorec.h" // for SuperVUReset
|
||||||
|
|
||||||
|
#include "R5900Exceptions.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace Console;
|
using namespace Console;
|
||||||
|
@ -279,12 +281,16 @@ void SysShutdownDynarecs()
|
||||||
recCpu.Shutdown();
|
recCpu.Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resets all PS2 cpu execution states, which does not affect that actual PS2 state/condition.
|
|
||||||
|
bool g_ReturnToGui = false; // set to exit the execution of the emulator and return control to the GUI
|
||||||
|
bool g_EmulationInProgress = false; // Set TRUE if a game is actively running (set to false on reset)
|
||||||
|
|
||||||
|
// Resets all PS2 cpu execution caches, which does not affect that actual PS2 state/condition.
|
||||||
// This can be called at any time outside the context of a Cpu->Execute() block without
|
// This can be called at any time outside the context of a Cpu->Execute() block without
|
||||||
// bad things happening (recompilers will slow down for a brief moment since rec code blocks
|
// bad things happening (recompilers will slow down for a brief moment since rec code blocks
|
||||||
// are dumped).
|
// are dumped).
|
||||||
// Use this method to reset the recs when important global pointers like the MTGS are re-assigned.
|
// Use this method to reset the recs when important global pointers like the MTGS are re-assigned.
|
||||||
void SysResetExecutionState()
|
void SysClearExecutionCache()
|
||||||
{
|
{
|
||||||
if( CHECK_EEREC )
|
if( CHECK_EEREC )
|
||||||
{
|
{
|
||||||
|
@ -306,9 +312,146 @@ void SysResetExecutionState()
|
||||||
vu1MicroDisableSkip();
|
vu1MicroDisableSkip();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__forceinline void SysUpdate()
|
||||||
|
{
|
||||||
|
keyEvent* ev1 = PAD1keyEvent();
|
||||||
|
keyEvent* ev2 = PAD2keyEvent();
|
||||||
|
|
||||||
|
HostGui::KeyEvent( (ev1 != NULL) ? ev1 : ev2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysExecute()
|
||||||
|
{
|
||||||
|
g_EmulationInProgress = true;
|
||||||
|
g_ReturnToGui = false;
|
||||||
|
|
||||||
|
// Optimization: We hardcode two versions of the EE here -- one for recs and one for ints.
|
||||||
|
// This is because recs are performance critical, and being able to inline them into the
|
||||||
|
// function here helps a small bit (not much but every small bit counts!).
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if( CHECK_EEREC )
|
||||||
|
{
|
||||||
|
while( !g_ReturnToGui )
|
||||||
|
{
|
||||||
|
recExecute();
|
||||||
|
SysUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while( !g_ReturnToGui )
|
||||||
|
{
|
||||||
|
Cpu->Execute();
|
||||||
|
SysUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch( R5900Exception::BaseExcept& ex )
|
||||||
|
{
|
||||||
|
Console::Error( ex.cMessage() );
|
||||||
|
Console::Error( fmt_string( "(EE) PC: 0x%8.8x \tCycle:0x8.8x", ex.cpuState.pc, ex.cpuState.cycle ).c_str() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function provided to escape the emulation state, by shutting down plugins and saving
|
||||||
|
// the GS state. The execution state is effectively preserved, and can be resumed with a
|
||||||
|
// call to SysExecute.
|
||||||
|
void SysEndExecution()
|
||||||
|
{
|
||||||
|
if( Config.closeGSonEsc )
|
||||||
|
StateRecovery::MakeGsOnly();
|
||||||
|
|
||||||
|
ClosePlugins( Config.closeGSonEsc );
|
||||||
|
g_ReturnToGui = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs an ELF image directly (ISO or ELF program or BIN)
|
||||||
|
// Used by Run::FromCD, and Run->Execute when no active emulation state is present.
|
||||||
|
// elf_file - if NULL, the CDVD plugin is queried for the ELF file.
|
||||||
|
// use_bios - forces the game to boot through the PS2 bios, instead of bypassing it.
|
||||||
|
void SysPrepareExecution( const char* elf_file, bool use_bios )
|
||||||
|
{
|
||||||
|
if( !g_EmulationInProgress )
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
cpuReset();
|
||||||
|
}
|
||||||
|
catch( Exception::BaseException& ex )
|
||||||
|
{
|
||||||
|
Msgbox::Alert( ex.cMessage() );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OpenPlugins(g_TestRun.ptitle) == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if( elf_file == NULL )
|
||||||
|
{
|
||||||
|
if( !StateRecovery::HasState() )
|
||||||
|
{
|
||||||
|
// Not recovering a state, so need to execute the bios and load the ELF information.
|
||||||
|
// (note: gsRecoveries are done from ExecuteCpu)
|
||||||
|
|
||||||
|
// if the elf_file is null we use the CDVD elf file.
|
||||||
|
// But if the elf_file is an empty string then we boot the bios instead.
|
||||||
|
|
||||||
|
char ename[g_MaxPath];
|
||||||
|
ename[0] = 0;
|
||||||
|
if( !use_bios )
|
||||||
|
GetPS2ElfName( ename );
|
||||||
|
|
||||||
|
loadElfFile( ename );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Custom ELF specified (not using CDVD).
|
||||||
|
// Run the BIOS and load the ELF.
|
||||||
|
|
||||||
|
loadElfFile( elf_file );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StateRecovery::Recover();
|
||||||
|
HostGui::BeginExecution();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysRestorableReset()
|
||||||
|
{
|
||||||
|
if( !g_EmulationInProgress ) return;
|
||||||
|
StateRecovery::MakeFull();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SysReset()
|
||||||
|
{
|
||||||
|
// fixme - this code sets the statusbar but never returns control to the window message pump
|
||||||
|
// so the status bar won't receive the WM_PAINT messages needed to update itself anyway.
|
||||||
|
// Oops! (air)
|
||||||
|
|
||||||
|
HostGui::Notice(_("Resetting..."));
|
||||||
|
Console::SetTitle(_("Resetting..."));
|
||||||
|
|
||||||
|
g_EmulationInProgress = false;
|
||||||
|
StateRecovery::Clear();
|
||||||
|
|
||||||
|
cpuShutdown();
|
||||||
|
ShutdownPlugins();
|
||||||
|
|
||||||
|
ElfCRC = 0;
|
||||||
|
|
||||||
|
// Note : No need to call cpuReset() here. It gets called automatically before the
|
||||||
|
// emulator resumes execution.
|
||||||
|
|
||||||
|
HostGui::Notice(_("Ready"));
|
||||||
|
Console::SetTitle(_("*PCSX2* Emulation state is reset."));
|
||||||
|
}
|
||||||
|
|
||||||
u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
|
u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
|
||||||
{
|
{
|
||||||
u8 *Mem = (u8*)SysMmap( base, size );
|
u8 *Mem = (u8*)HostSys::Mmap( base, size );
|
||||||
|
|
||||||
if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) )
|
if( (Mem == NULL) || (bounds != 0 && (((uptr)Mem + size) > bounds)) )
|
||||||
{
|
{
|
||||||
|
@ -319,7 +462,7 @@ u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
|
||||||
|
|
||||||
SafeSysMunmap( Mem, size );
|
SafeSysMunmap( Mem, size );
|
||||||
|
|
||||||
Mem = (u8*)SysMmap( NULL, size );
|
Mem = (u8*)HostSys::Mmap( NULL, size );
|
||||||
if( bounds != 0 && (((uptr)Mem + size) > bounds) )
|
if( bounds != 0 && (((uptr)Mem + size) > bounds) )
|
||||||
{
|
{
|
||||||
DevCon::Error( "Fatal Error:\n\tSecond try failed allocating %s, block ptr 0x%x does not meet required criteria.", params caller, Mem );
|
DevCon::Error( "Fatal Error:\n\tSecond try failed allocating %s, block ptr 0x%x does not meet required criteria.", params caller, Mem );
|
||||||
|
@ -331,3 +474,7 @@ u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller)
|
||||||
return Mem;
|
return Mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *SysLoadLibrary(const char *lib) { return HostSys::LoadLibrary( lib ); }
|
||||||
|
void *SysLoadSym(void *lib, const char *sym) { return HostSys::LoadSym( lib, sym ); }
|
||||||
|
const char *SysLibError() { return HostSys::LibError(); }
|
||||||
|
void SysCloseLibrary(void *lib) { HostSys::CloseLibrary( lib ); }
|
||||||
|
|
102
pcsx2/System.h
102
pcsx2/System.h
|
@ -25,41 +25,6 @@
|
||||||
#include "MemcpyFast.h"
|
#include "MemcpyFast.h"
|
||||||
#include "SafeArray.h"
|
#include "SafeArray.h"
|
||||||
|
|
||||||
void SysDetect(); // Detects cpu type and fills cpuInfo structs.
|
|
||||||
bool SysInit(); // Init logfiles, directories, critical memory resources, and other OS-specific one-time
|
|
||||||
void SysReset(); // Resets the various PS2 cpus, sub-systems, and recompilers.
|
|
||||||
void SysUpdate(); // Called on VBlank (to update i.e. pads)
|
|
||||||
void SysClose(); // Close mem and plugins
|
|
||||||
|
|
||||||
bool SysAllocateMem(); // allocates memory for all PS2 systems; returns FALSe on critical error.
|
|
||||||
void SysAllocateDynarecs(); // allocates memory for all dynarecs, and force-disables any failures.
|
|
||||||
void SysShutdownDynarecs();
|
|
||||||
void SysShutdownMem();
|
|
||||||
void SysResetExecutionState();
|
|
||||||
|
|
||||||
void *SysLoadLibrary(const char *lib); // Loads Library
|
|
||||||
void *SysLoadSym(void *lib, const char *sym); // Loads Symbol from Library
|
|
||||||
const char *SysLibError(); // Gets previous error loading symbols
|
|
||||||
void SysCloseLibrary(void *lib); // Closes Library
|
|
||||||
|
|
||||||
// Maps a block of memory for use as a recompiled code buffer.
|
|
||||||
// The allocated block has code execution privileges.
|
|
||||||
// Returns NULL on allocation failure.
|
|
||||||
void *SysMmap(uptr base, u32 size);
|
|
||||||
|
|
||||||
// Maps a block of memory for use as a recompiled code buffer, and ensures that the
|
|
||||||
// allocation is below a certain memory address (specified in "bounds" parameter).
|
|
||||||
// The allocated block has code execution privileges.
|
|
||||||
// Returns NULL on allocation failure.
|
|
||||||
u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
|
|
||||||
|
|
||||||
// Unmaps a block allocated by SysMmap
|
|
||||||
void SysMunmap(uptr base, u32 size);
|
|
||||||
|
|
||||||
static __forceinline void SysMunmap( void* base, u32 size )
|
|
||||||
{
|
|
||||||
SysMunmap( (uptr)base, size );
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PageProtectionMode
|
enum PageProtectionMode
|
||||||
{
|
{
|
||||||
|
@ -68,7 +33,72 @@ enum PageProtectionMode
|
||||||
Protect_ReadWrite
|
Protect_ReadWrite
|
||||||
};
|
};
|
||||||
|
|
||||||
void SysMemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution=false );
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// HostSys - Namespace housing general system-level implementations relating to loading
|
||||||
|
// plugins and allocating memory. For now, these functions are all accessed via Sys*
|
||||||
|
// versions defined in System.h/cpp.
|
||||||
|
namespace HostSys
|
||||||
|
{
|
||||||
|
// Damn windows.h namespace pollution!!
|
||||||
|
#undef LoadLibrary
|
||||||
|
|
||||||
|
extern void *LoadLibrary(const char *lib); // Loads Library
|
||||||
|
extern void *LoadSym(void *lib, const char *sym); // Loads Symbol from Library
|
||||||
|
extern const char *LibError(); // Gets previous error loading symbols
|
||||||
|
extern void CloseLibrary(void *lib); // Closes Library
|
||||||
|
|
||||||
|
// Maps a block of memory for use as a recompiled code buffer.
|
||||||
|
// The allocated block has code execution privileges.
|
||||||
|
// Returns NULL on allocation failure.
|
||||||
|
extern void *Mmap(uptr base, u32 size);
|
||||||
|
|
||||||
|
// Unmaps a block allocated by SysMmap
|
||||||
|
extern void Munmap(uptr base, u32 size);
|
||||||
|
|
||||||
|
extern void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution=false );
|
||||||
|
|
||||||
|
static __forceinline void Munmap( void* base, u32 size )
|
||||||
|
{
|
||||||
|
Munmap( (uptr)base, size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern void SysDetect(); // Detects cpu type and fills cpuInfo structs.
|
||||||
|
extern void SysReset(); // Resets the various PS2 cpus, sub-systems, and recompilers.
|
||||||
|
extern void SysUpdate(); // Called on VBlank (to update i.e. pads)
|
||||||
|
|
||||||
|
extern bool SysAllocateMem(); // allocates memory for all PS2 systems; returns FALSe on critical error.
|
||||||
|
extern void SysAllocateDynarecs(); // allocates memory for all dynarecs, and force-disables any failures.
|
||||||
|
extern void SysShutdownDynarecs();
|
||||||
|
extern void SysShutdownMem();
|
||||||
|
|
||||||
|
extern void SysRestorableReset(); // Saves the current emulation state prior to spu reset.
|
||||||
|
extern void SysClearExecutionCache(); // clears recompiled execution caches!
|
||||||
|
extern void SysEndExecution(); // terminates plugins, saves GS state (if enabled), and signals emulation loop to end.
|
||||||
|
extern void SysPrepareExecution( const char* elf_file, bool use_bios=false );
|
||||||
|
|
||||||
|
// initiates high-speed execution of the emulation state. This function is currently
|
||||||
|
// designed to be run from an event loop, but will eventually be re-tooled with threading
|
||||||
|
// in mindunder the new GUI (assuming Linux approves!), which will make life easier *and*
|
||||||
|
// improve overall performance too!
|
||||||
|
extern void SysExecute();
|
||||||
|
|
||||||
|
|
||||||
|
// Library Helpers for HostSys functions, left in for now for convenience.
|
||||||
|
|
||||||
|
extern void *SysLoadLibrary(const char *lib); // Loads Library
|
||||||
|
extern void *SysLoadSym(void *lib, const char *sym); // Loads Symbol from Library
|
||||||
|
extern const char *SysLibError(); // Gets previous error loading symbols
|
||||||
|
extern void SysCloseLibrary(void *lib); // Closes Library
|
||||||
|
|
||||||
|
// Maps a block of memory for use as a recompiled code buffer, and ensures that the
|
||||||
|
// allocation is below a certain memory address (specified in "bounds" parameter).
|
||||||
|
// The allocated block has code execution privileges.
|
||||||
|
// Returns NULL on allocation failure.
|
||||||
|
extern u8 *SysMmapEx(uptr base, u32 size, uptr bounds, const char *caller="Unnamed");
|
||||||
|
|
||||||
|
extern void vSyncDebugStuff( uint frame );
|
||||||
|
|
||||||
// Writes text to the console.
|
// Writes text to the console.
|
||||||
// *DEPRECIATED* Use Console namespace methods instead.
|
// *DEPRECIATED* Use Console namespace methods instead.
|
||||||
|
|
|
@ -581,7 +581,7 @@ void vtlb_free( void* pmem, uint size )
|
||||||
SafeSysMunmap( pmem, size );
|
SafeSysMunmap( pmem, size );
|
||||||
#else
|
#else
|
||||||
// Make sure and unprotect memory first, since CrtDebug will try to write to it.
|
// Make sure and unprotect memory first, since CrtDebug will try to write to it.
|
||||||
SysMemProtect( pmem, size, Protect_ReadWrite );
|
HostSys::MemProtect( pmem, size, Protect_ReadWrite );
|
||||||
safe_aligned_free( pmem );
|
safe_aligned_free( pmem );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,28 +21,29 @@
|
||||||
#include "AboutDlg.h"
|
#include "AboutDlg.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
|
||||||
|
#include "Hyperlinks.h"
|
||||||
|
|
||||||
#define IDC_STATIC (-1)
|
#define IDC_STATIC (-1)
|
||||||
|
|
||||||
HWND hW;
|
static HWND hW;
|
||||||
HBITMAP hBMP, hSilverBMP;
|
static HBITMAP hSilverBMP;
|
||||||
|
|
||||||
LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch(uMsg)
|
switch(uMsg)
|
||||||
{
|
{
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
//hBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(SPLASH_LOGO));
|
|
||||||
hSilverBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PS2SILVER));
|
hSilverBMP = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_PS2SILVER));
|
||||||
|
|
||||||
/*hW = CreateWindow("STATIC", "", WS_VISIBLE | WS_CHILD | SS_BITMAP,
|
|
||||||
230, 10, 211, 110, hDlg, (HMENU)IDC_STATIC, GetModuleHandle(NULL), NULL);
|
|
||||||
SendMessage(hW, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBMP);*/
|
|
||||||
|
|
||||||
SetWindowText(hDlg, _("About PCSX2"));
|
SetWindowText(hDlg, _("About PCSX2"));
|
||||||
|
|
||||||
Button_SetText(GetDlgItem(hDlg, IDOK), _("OK"));
|
Button_SetText(GetDlgItem(hDlg, IDOK), _("OK"));
|
||||||
Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_AUTHORS), _(LabelAuthors));
|
Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_AUTHORS), _(LabelAuthors));
|
||||||
Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_GREETS), _(LabelGreets));
|
Static_SetText(GetDlgItem(hDlg, IDC_PCSX_ABOUT_GREETS), _(LabelGreets));
|
||||||
|
|
||||||
|
ConvertStaticToHyperlink( hDlg, IDC_LINK_GOOGLECODE );
|
||||||
|
ConvertStaticToHyperlink( hDlg, IDC_LINK_WEBSITE );
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
|
@ -51,6 +52,16 @@ LRESULT WINAPI AboutDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
case IDOK:
|
case IDOK:
|
||||||
EndDialog( hDlg, TRUE );
|
EndDialog( hDlg, TRUE );
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
case IDC_LINK_WEBSITE:
|
||||||
|
ShellExecute(hDlg, "open", "http://www.pcsx2.net/",
|
||||||
|
NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case IDC_LINK_GOOGLECODE:
|
||||||
|
ShellExecute(hDlg, "open", "http://code.google.com/p/pcsx2",
|
||||||
|
NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ struct ComboInitializer
|
||||||
bool LoadNextLibrary()
|
bool LoadNextLibrary()
|
||||||
{
|
{
|
||||||
string tmpStr( Path::Combine( Config.PluginsDir, FindData.cFileName ) );
|
string tmpStr( Path::Combine( Config.PluginsDir, FindData.cFileName ) );
|
||||||
Lib = LoadLibrary( tmpStr.c_str() );
|
Lib = HostSys::LoadLibrary( tmpStr.c_str() );
|
||||||
if (Lib == NULL)
|
if (Lib == NULL)
|
||||||
{
|
{
|
||||||
Console::Error( "Plugin load failure: %hs\n\tSysLibError Message: %s", params &tmpStr, SysLibError() );
|
Console::Error( "Plugin load failure: %hs\n\tSysLibError Message: %s", params &tmpStr, SysLibError() );
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
// Hyperlinks.cpp
|
||||||
|
//
|
||||||
|
// Copyright 2002 Neal Stublen
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// http://www.awesoftware.com
|
||||||
|
//
|
||||||
|
|
||||||
|
// This taken as found on Codeguru: http://www.codeguru.com/cpp/controls/staticctrl/article.php/c5803
|
||||||
|
|
||||||
|
#include "Win32.h"
|
||||||
|
#include "Hyperlinks.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define PROP_ORIGINAL_FONT TEXT("_Hyperlink_Original_Font_")
|
||||||
|
#define PROP_ORIGINAL_PROC TEXT("_Hyperlink_Original_Proc_")
|
||||||
|
#define PROP_STATIC_HYPERLINK TEXT("_Hyperlink_From_Static_")
|
||||||
|
#define PROP_UNDERLINE_FONT TEXT("_Hyperlink_Underline_Font_")
|
||||||
|
|
||||||
|
|
||||||
|
LRESULT CALLBACK _HyperlinkParentProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
WNDPROC pfnOrigProc = (WNDPROC) GetProp(hwnd, PROP_ORIGINAL_PROC);
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_CTLCOLORSTATIC:
|
||||||
|
{
|
||||||
|
HDC hdc = (HDC) wParam;
|
||||||
|
HWND hwndCtl = (HWND) lParam;
|
||||||
|
|
||||||
|
BOOL fHyperlink = (NULL != GetProp(hwndCtl, PROP_STATIC_HYPERLINK));
|
||||||
|
if (fHyperlink)
|
||||||
|
{
|
||||||
|
LRESULT lr = CallWindowProc(pfnOrigProc, hwnd, message, wParam, lParam);
|
||||||
|
SetTextColor(hdc, RGB(0, 0, 192));
|
||||||
|
return lr;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WM_DESTROY:
|
||||||
|
{
|
||||||
|
SetWindowLong(hwnd, GWL_WNDPROC, (LONG) pfnOrigProc);
|
||||||
|
RemoveProp(hwnd, PROP_ORIGINAL_PROC);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CallWindowProc(pfnOrigProc, hwnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT CALLBACK _HyperlinkProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
WNDPROC pfnOrigProc = (WNDPROC) GetProp(hwnd, PROP_ORIGINAL_PROC);
|
||||||
|
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case WM_DESTROY:
|
||||||
|
{
|
||||||
|
SetWindowLong(hwnd, GWL_WNDPROC, (LONG) pfnOrigProc);
|
||||||
|
RemoveProp(hwnd, PROP_ORIGINAL_PROC);
|
||||||
|
|
||||||
|
HFONT hOrigFont = (HFONT) GetProp(hwnd, PROP_ORIGINAL_FONT);
|
||||||
|
SendMessage(hwnd, WM_SETFONT, (WPARAM) hOrigFont, 0);
|
||||||
|
RemoveProp(hwnd, PROP_ORIGINAL_FONT);
|
||||||
|
|
||||||
|
HFONT hFont = (HFONT) GetProp(hwnd, PROP_UNDERLINE_FONT);
|
||||||
|
DeleteObject(hFont);
|
||||||
|
RemoveProp(hwnd, PROP_UNDERLINE_FONT);
|
||||||
|
|
||||||
|
RemoveProp(hwnd, PROP_STATIC_HYPERLINK);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WM_MOUSEMOVE:
|
||||||
|
{
|
||||||
|
if (GetCapture() != hwnd)
|
||||||
|
{
|
||||||
|
HFONT hFont = (HFONT) GetProp(hwnd, PROP_UNDERLINE_FONT);
|
||||||
|
SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, FALSE);
|
||||||
|
InvalidateRect(hwnd, NULL, FALSE);
|
||||||
|
SetCapture(hwnd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RECT rect;
|
||||||
|
GetWindowRect(hwnd, &rect);
|
||||||
|
|
||||||
|
POINT pt = { LOWORD(lParam), HIWORD(lParam) };
|
||||||
|
ClientToScreen(hwnd, &pt);
|
||||||
|
|
||||||
|
if (!PtInRect(&rect, pt))
|
||||||
|
{
|
||||||
|
HFONT hFont = (HFONT) GetProp(hwnd, PROP_ORIGINAL_FONT);
|
||||||
|
SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, FALSE);
|
||||||
|
InvalidateRect(hwnd, NULL, FALSE);
|
||||||
|
ReleaseCapture();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WM_SETCURSOR:
|
||||||
|
{
|
||||||
|
// Since IDC_HAND is not available on all operating systems,
|
||||||
|
// we will load the arrow cursor if IDC_HAND is not present.
|
||||||
|
HCURSOR hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND));
|
||||||
|
if (NULL == hCursor)
|
||||||
|
{
|
||||||
|
hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
|
||||||
|
}
|
||||||
|
SetCursor(hCursor);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallWindowProc(pfnOrigProc, hwnd, message, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ConvertStaticToHyperlink(HWND hwndCtl)
|
||||||
|
{
|
||||||
|
// Subclass the parent so we can color the controls as we desire.
|
||||||
|
|
||||||
|
HWND hwndParent = GetParent(hwndCtl);
|
||||||
|
if (NULL != hwndParent)
|
||||||
|
{
|
||||||
|
WNDPROC pfnOrigProc = (WNDPROC) GetWindowLong(hwndParent, GWL_WNDPROC);
|
||||||
|
if (pfnOrigProc != _HyperlinkParentProc)
|
||||||
|
{
|
||||||
|
SetProp(hwndParent, PROP_ORIGINAL_PROC, (HANDLE) pfnOrigProc);
|
||||||
|
SetWindowLong(hwndParent, GWL_WNDPROC, (LONG) (WNDPROC) _HyperlinkParentProc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the control will send notifications.
|
||||||
|
|
||||||
|
DWORD dwStyle = GetWindowLong(hwndCtl, GWL_STYLE);
|
||||||
|
SetWindowLong(hwndCtl, GWL_STYLE, dwStyle | SS_NOTIFY);
|
||||||
|
|
||||||
|
// Subclass the existing control.
|
||||||
|
|
||||||
|
WNDPROC pfnOrigProc = (WNDPROC) GetWindowLong(hwndCtl, GWL_WNDPROC);
|
||||||
|
SetProp(hwndCtl, PROP_ORIGINAL_PROC, (HANDLE) pfnOrigProc);
|
||||||
|
SetWindowLong(hwndCtl, GWL_WNDPROC, (LONG) (WNDPROC) _HyperlinkProc);
|
||||||
|
|
||||||
|
// Create an updated font by adding an underline.
|
||||||
|
|
||||||
|
HFONT hOrigFont = (HFONT) SendMessage(hwndCtl, WM_GETFONT, 0, 0);
|
||||||
|
SetProp(hwndCtl, PROP_ORIGINAL_FONT, (HANDLE) hOrigFont);
|
||||||
|
|
||||||
|
LOGFONT lf;
|
||||||
|
GetObject(hOrigFont, sizeof(lf), &lf);
|
||||||
|
lf.lfUnderline = TRUE;
|
||||||
|
|
||||||
|
HFONT hFont = CreateFontIndirect(&lf);
|
||||||
|
SetProp(hwndCtl, PROP_UNDERLINE_FONT, (HANDLE) hFont);
|
||||||
|
|
||||||
|
// Set a flag on the control so we know what color it should be.
|
||||||
|
|
||||||
|
SetProp(hwndCtl, PROP_STATIC_HYPERLINK, (HANDLE) 1);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ConvertStaticToHyperlink(HWND hwndParent, UINT uiCtlId)
|
||||||
|
{
|
||||||
|
return ConvertStaticToHyperlink(GetDlgItem(hwndParent, uiCtlId));
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
// Hyperlinks.h
|
||||||
|
//
|
||||||
|
// Copyright 2002 Neal Stublen
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// http://www.awesoftware.com
|
||||||
|
//
|
||||||
|
|
||||||
|
BOOL ConvertStaticToHyperlink(HWND hwndCtl);
|
||||||
|
BOOL ConvertStaticToHyperlink(HWND hwndParent, UINT uiCtlId);
|
|
@ -305,10 +305,6 @@
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\AboutDlg.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\AdvancedDlg.cpp"
|
RelativePath="..\AdvancedDlg.cpp"
|
||||||
>
|
>
|
||||||
|
@ -433,6 +429,37 @@
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\Hyperlinks.cpp"
|
||||||
|
>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Debug|Win32"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
PrecompiledHeaderThrough="Win32.h"
|
||||||
|
PrecompiledHeaderFile="$(IntDir)\win32.pch"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Devel|Win32"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
PrecompiledHeaderThrough="Win32.h"
|
||||||
|
PrecompiledHeaderFile="$(IntDir)\win32.pch"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
<FileConfiguration
|
||||||
|
Name="Release|Win32"
|
||||||
|
>
|
||||||
|
<Tool
|
||||||
|
Name="VCCLCompilerTool"
|
||||||
|
PrecompiledHeaderThrough="Win32.h"
|
||||||
|
PrecompiledHeaderFile="$(IntDir)\win32.pch"
|
||||||
|
/>
|
||||||
|
</FileConfiguration>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\ini.cpp"
|
RelativePath="..\ini.cpp"
|
||||||
>
|
>
|
||||||
|
@ -520,10 +547,6 @@
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath="..\McdsDlg.h"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
<File
|
||||||
RelativePath="..\PatchBrowser.cpp"
|
RelativePath="..\PatchBrowser.cpp"
|
||||||
>
|
>
|
||||||
|
@ -578,11 +601,7 @@
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\RDebugger.h"
|
RelativePath="..\..\Saveslots.cpp"
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\Win32.h"
|
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
|
@ -839,10 +858,42 @@
|
||||||
RelativePath="..\ps2_silver.bmp"
|
RelativePath="..\ps2_silver.bmp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
</Filter>
|
||||||
|
<Filter
|
||||||
|
Name="Include"
|
||||||
|
>
|
||||||
|
<File
|
||||||
|
RelativePath="..\AboutDlg.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\HostGui.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\Hyperlinks.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\McdsDlg.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\RDebugger.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\resource.h"
|
RelativePath="..\resource.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\Win32.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\WinDebugResource.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
|
@ -2287,14 +2338,6 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
|
||||||
Name="Dynarec"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\x86\iIPU.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="memory"
|
Name="memory"
|
||||||
|
@ -2343,38 +2386,6 @@
|
||||||
RelativePath="..\..\MTGS.cpp"
|
RelativePath="..\..\MTGS.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<Filter
|
|
||||||
Name="Dynarec"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\x86\iGS.cpp"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Devel|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="VUmicro"
|
Name="VUmicro"
|
||||||
|
@ -2595,42 +2606,6 @@
|
||||||
RelativePath="..\..\SPR.h"
|
RelativePath="..\..\SPR.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<Filter
|
|
||||||
Name="Dynarec"
|
|
||||||
>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\x86\iHw.cpp"
|
|
||||||
>
|
|
||||||
</File>
|
|
||||||
<File
|
|
||||||
RelativePath="..\..\x86\iPsxHw.cpp"
|
|
||||||
>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Debug|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Devel|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
<FileConfiguration
|
|
||||||
Name="Release|Win32"
|
|
||||||
ExcludedFromBuild="true"
|
|
||||||
>
|
|
||||||
<Tool
|
|
||||||
Name="VCCLCompilerTool"
|
|
||||||
/>
|
|
||||||
</FileConfiguration>
|
|
||||||
</File>
|
|
||||||
</Filter>
|
|
||||||
</Filter>
|
</Filter>
|
||||||
<Filter
|
<Filter
|
||||||
Name="Sif"
|
Name="Sif"
|
||||||
|
@ -2732,6 +2707,10 @@
|
||||||
RelativePath="..\..\Plugins.cpp"
|
RelativePath="..\..\Plugins.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\RecoverySystem.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\SamplProf.cpp"
|
RelativePath="..\SamplProf.cpp"
|
||||||
>
|
>
|
||||||
|
@ -3096,7 +3075,7 @@
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\WinDebugResource.h"
|
RelativePath="..\WinDebugResource"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
</Files>
|
</Files>
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <tchar.h>
|
#include <tchar.h>
|
||||||
|
|
||||||
#include "Misc.h"
|
#include "Misc.h"
|
||||||
|
#include "HostGui.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#include "WinDebugResource.h"
|
#include "WinDebugResource.h"
|
||||||
|
|
||||||
|
@ -121,43 +122,35 @@ public:
|
||||||
void EnumEntry( const string& var, int& value, const char* const* enumArray, const int defvalue=0 );
|
void EnumEntry( const string& var, int& value, const char* const* enumArray, const int defvalue=0 );
|
||||||
};
|
};
|
||||||
|
|
||||||
LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM);
|
extern LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
void CreateMainWindow();
|
extern void CreateMainWindow();
|
||||||
void RunGui();
|
extern void RunGui();
|
||||||
|
extern bool HostGuiInit();
|
||||||
|
|
||||||
BOOL Pcsx2Configure(HWND hWnd);
|
extern BOOL Pcsx2Configure(HWND hWnd);
|
||||||
void InitLanguages();
|
extern void InitLanguages();
|
||||||
char *GetLanguageNext();
|
extern char *GetLanguageNext();
|
||||||
void CloseLanguages();
|
extern void CloseLanguages();
|
||||||
void ChangeLanguage(char *lang);
|
extern void ChangeLanguage(char *lang);
|
||||||
|
|
||||||
void SysRestorableReset();
|
extern void WinClose();
|
||||||
|
extern void ExecuteCpu();
|
||||||
|
extern void OnStates_LoadOther();
|
||||||
|
extern void OnStates_SaveOther();
|
||||||
|
extern int ParseCommandLine( int tokenCount, TCHAR *const *const tokens );
|
||||||
|
extern void strcatz(char *dst, char *src);
|
||||||
|
|
||||||
void WinClose();
|
extern BOOL CALLBACK PatchBDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
void States_Load( const string& file, int num=-1 );
|
extern BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
void States_Save( const string& file, int num=-1 );
|
extern BOOL CALLBACK AdvancedOptionsProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||||
void States_Load(int num);
|
extern BOOL CALLBACK HacksProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
||||||
void States_Save(int num);
|
|
||||||
void OnStates_LoadOther();
|
|
||||||
void OnStates_SaveOther();
|
|
||||||
int ParseCommandLine( int tokenCount, TCHAR *const *const tokens );
|
|
||||||
void RunExecute( const char* elf_file, bool use_bios=false );
|
|
||||||
void ExecuteCpu();
|
|
||||||
void strcatz(char *dst, char *src);
|
|
||||||
|
|
||||||
BOOL CALLBACK PatchBDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
||||||
BOOL CALLBACK CpuDlgProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
||||||
BOOL CALLBACK AdvancedOptionsProc(HWND hW, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
|
||||||
BOOL CALLBACK HacksProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
|
|
||||||
|
|
||||||
extern AppData gApp;
|
extern AppData gApp;
|
||||||
extern HWND hStatusWnd;
|
extern HWND hStatusWnd;
|
||||||
extern PcsxConfig winConfig; // local storage of the configuration options.
|
extern PcsxConfig winConfig; // local storage of the configuration options.
|
||||||
extern bool g_ReturnToGui; // set to exit the execution of the emulator and return control to the GUI
|
|
||||||
extern bool g_EmulationInProgress; // Set TRUE if a game is actively running (set to false on reset)
|
|
||||||
|
|
||||||
extern int UseGui;
|
extern bool UseGui;
|
||||||
extern int nDisableSC; // screensaver
|
extern bool nDisableSC; // screensaver
|
||||||
extern unsigned int langsMax;
|
extern unsigned int langsMax;
|
||||||
|
|
||||||
extern SafeArray<u8>* g_RecoveryState;
|
extern SafeArray<u8>* g_RecoveryState;
|
||||||
|
@ -165,11 +158,6 @@ extern SafeArray<u8>* g_gsRecoveryState;
|
||||||
extern const char* g_pRunGSState;
|
extern const char* g_pRunGSState;
|
||||||
extern int g_SaveGSStream;
|
extern int g_SaveGSStream;
|
||||||
|
|
||||||
|
|
||||||
// sets the contents of the Pcsx2 status bar...
|
|
||||||
extern void StatusBar_Notice( const std::string& text );
|
|
||||||
extern void StatusBar_SetMsg( const std::string& text );
|
|
||||||
|
|
||||||
// Throws an exception based on the value returned from GetLastError.
|
// Throws an exception based on the value returned from GetLastError.
|
||||||
// Performs an option return value success/fail check on hresult.
|
// Performs an option return value success/fail check on hresult.
|
||||||
extern void StreamException_ThrowLastError( const string& streamname, HANDLE result=INVALID_HANDLE_VALUE );
|
extern void StreamException_ThrowLastError( const string& streamname, HANDLE result=INVALID_HANDLE_VALUE );
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define IDD_BPCNT 105
|
#define IDD_BPCNT 105
|
||||||
#define IDD_DEBUG 108
|
#define IDD_DEBUG 108
|
||||||
#define IDD_VU0REGS 111
|
#define IDD_VU0REGS 111
|
||||||
|
#define IDD_JUMP 112
|
||||||
#define IDD_VU0INTEGER 113
|
#define IDD_VU0INTEGER 113
|
||||||
#define IDD_GPREGS 114
|
#define IDD_GPREGS 114
|
||||||
#define IDD_CP0REGS 115
|
#define IDD_CP0REGS 115
|
||||||
|
@ -172,6 +173,7 @@
|
||||||
#define IDC_VU1_VF26 1097
|
#define IDC_VU1_VF26 1097
|
||||||
#define IDC_DEBUG_DUMP 1097
|
#define IDC_DEBUG_DUMP 1097
|
||||||
#define IDC_CP04 1097
|
#define IDC_CP04 1097
|
||||||
|
#define IDC_JUMP_PC 1097
|
||||||
#define IDC_VU1_VF27 1098
|
#define IDC_VU1_VF27 1098
|
||||||
#define IDC_DUMP_END 1098
|
#define IDC_DUMP_END 1098
|
||||||
#define IDC_DEBUG_MEMORY 1098
|
#define IDC_DEBUG_MEMORY 1098
|
||||||
|
|
|
@ -59,8 +59,6 @@ void strcatz(char *dst, char *src)
|
||||||
BOOL APIENTRY CmdlineProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);//forward def
|
BOOL APIENTRY CmdlineProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);//forward def
|
||||||
//-------------------
|
//-------------------
|
||||||
|
|
||||||
TESTRUNARGS g_TestRun;
|
|
||||||
|
|
||||||
static const char* phelpmsg =
|
static const char* phelpmsg =
|
||||||
"pcsx2 [options] [file]\n\n"
|
"pcsx2 [options] [file]\n\n"
|
||||||
"-cfg [file] {configuration file}\n"
|
"-cfg [file] {configuration file}\n"
|
||||||
|
@ -175,7 +173,7 @@ static PTCHAR* _CommandLineToArgv( const TCHAR *CmdLine, int* _argc )
|
||||||
|
|
||||||
void WinClose()
|
void WinClose()
|
||||||
{
|
{
|
||||||
SysClose();
|
cpuShutdown();
|
||||||
|
|
||||||
// Don't check Config.Profiler here -- the Profiler will know if it's running or not.
|
// Don't check Config.Profiler here -- the Profiler will know if it's running or not.
|
||||||
ProfilerTerm();
|
ProfilerTerm();
|
||||||
|
@ -197,9 +195,9 @@ static bool TestRunMode()
|
||||||
if( IsDevBuild && (g_TestRun.enabled || g_TestRun.ptitle != NULL) )
|
if( IsDevBuild && (g_TestRun.enabled || g_TestRun.ptitle != NULL) )
|
||||||
{
|
{
|
||||||
// run without ui
|
// run without ui
|
||||||
UseGui = 0;
|
UseGui = false;
|
||||||
PCSX2_MEM_PROTECT_BEGIN();
|
PCSX2_MEM_PROTECT_BEGIN();
|
||||||
RunExecute( g_TestRun.efile ? g_TestRun.ptitle : NULL );
|
SysPrepareExecution( g_TestRun.efile ? g_TestRun.ptitle : NULL );
|
||||||
PCSX2_MEM_PROTECT_END();
|
PCSX2_MEM_PROTECT_END();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -347,7 +345,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||||
// Important! Always allocate dynarecs before loading plugins, to give the dynarecs
|
// Important! Always allocate dynarecs before loading plugins, to give the dynarecs
|
||||||
// the best possible chance of claiming ideal memory space!
|
// the best possible chance of claiming ideal memory space!
|
||||||
|
|
||||||
SysInit();
|
HostGuiInit();
|
||||||
|
|
||||||
if( needsToConfig )
|
if( needsToConfig )
|
||||||
{
|
{
|
||||||
|
@ -630,22 +628,24 @@ LRESULT WINAPI MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
case ID_FILEOPEN:
|
case ID_FILEOPEN:
|
||||||
{
|
{
|
||||||
std::string outstr;
|
string outstr;
|
||||||
if( Open_File_Proc( outstr ) )
|
if( Open_File_Proc( outstr ) )
|
||||||
RunExecute( outstr.c_str() );
|
{
|
||||||
|
SysReset();
|
||||||
|
SysPrepareExecution( outstr.c_str() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ID_RUN_EXECUTE:
|
case ID_RUN_EXECUTE:
|
||||||
if( g_EmulationInProgress )
|
// Execute without reset -- resumes existing states or runs the BIOS if
|
||||||
ExecuteCpu();
|
// the state is cleared/reset.
|
||||||
else
|
SysPrepareExecution( NULL, true );
|
||||||
RunExecute( NULL, true ); // boots bios if no savestate is to be recovered
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ID_FILE_RUNCD:
|
case ID_FILE_RUNCD:
|
||||||
SysReset();
|
SysReset();
|
||||||
RunExecute( NULL );
|
SysPrepareExecution( NULL );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ID_RUN_RESET:
|
case ID_RUN_RESET:
|
||||||
|
@ -745,7 +745,7 @@ LRESULT WINAPI MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
if (remoteDebugBios)
|
if (remoteDebugBios)
|
||||||
{
|
{
|
||||||
cpuReset();
|
cpuReset();
|
||||||
SysResetExecutionState();
|
SysClearExecutionCache();
|
||||||
cpuExecuteBios();
|
cpuExecuteBios();
|
||||||
|
|
||||||
DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_RDEBUG), NULL, (DLGPROC)RemoteDebuggerProc);
|
DialogBox(gApp.hInstance, MAKEINTRESOURCE(IDD_RDEBUG), NULL, (DLGPROC)RemoteDebuggerProc);
|
||||||
|
@ -870,19 +870,6 @@ LRESULT WINAPI MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
return DefWindowProc(hWnd, msg, wParam, lParam);
|
return DefWindowProc(hWnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Slots[5] = { -1, -1, -1, -1, -1 };
|
|
||||||
|
|
||||||
void ResetMenuSlots() {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i=0; i<5; i++) {
|
|
||||||
if (Slots[i] == -1)
|
|
||||||
EnableMenuItem(GetSubMenu(gApp.hMenu, 0), ID_FILE_STATES_LOAD_SLOT1+i, MF_GRAYED);
|
|
||||||
else
|
|
||||||
EnableMenuItem(GetSubMenu(gApp.hMenu, 0), ID_FILE_STATES_LOAD_SLOT1+i, MF_ENABLED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fixme - this looks like the beginnings of a dynamic "list of valid saveslots"
|
// fixme - this looks like the beginnings of a dynamic "list of valid saveslots"
|
||||||
// feature. Too bad it's never called and CheckState was old/dead code.
|
// feature. Too bad it's never called and CheckState was old/dead code.
|
||||||
/*void UpdateMenuSlots() {
|
/*void UpdateMenuSlots() {
|
||||||
|
@ -1040,7 +1027,7 @@ void CreateMainWindow()
|
||||||
RECT rect;
|
RECT rect;
|
||||||
int w, h;
|
int w, h;
|
||||||
|
|
||||||
g_ReturnToGui = true;
|
//g_ReturnToGui = true;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
sprintf(COMPILER, "(VC%d)", (_MSC_VER+100)/200);//hacky:) works for VC6 & VC.NET
|
sprintf(COMPILER, "(VC%d)", (_MSC_VER+100)/200);//hacky:) works for VC6 & VC.NET
|
||||||
|
@ -1080,7 +1067,7 @@ void CreateMainWindow()
|
||||||
);
|
);
|
||||||
|
|
||||||
gApp.hWnd = hWnd;
|
gApp.hWnd = hWnd;
|
||||||
ResetMenuSlots();
|
HostGui::ResetMenuSlots();
|
||||||
CreateMainMenu();
|
CreateMainMenu();
|
||||||
|
|
||||||
SetMenu(gApp.hWnd, gApp.hMenu);
|
SetMenu(gApp.hWnd, gApp.hMenu);
|
||||||
|
@ -1100,7 +1087,7 @@ void CreateMainWindow()
|
||||||
MoveWindow(hWnd, 60, 60, w, h, TRUE);
|
MoveWindow(hWnd, 60, 60, w, h, TRUE);
|
||||||
SendMessage( hStatusWnd, WM_SIZE, 0, 0 );
|
SendMessage( hStatusWnd, WM_SIZE, 0, 0 );
|
||||||
|
|
||||||
StatusBar_SetMsg("F1 - save, F2 - next state, Shift+F2 - prev state, F3 - load, F8 - snapshot");
|
HostGui::SetStatusMsg("F1 - save, F2 - next state, Shift+F2 - prev state, F3 - load, F8 - snapshot");
|
||||||
|
|
||||||
ShowWindow(hWnd, true);
|
ShowWindow(hWnd, true);
|
||||||
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
|
SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
|
||||||
|
|
|
@ -20,20 +20,14 @@
|
||||||
#include <winnt.h>
|
#include <winnt.h>
|
||||||
|
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
//#include "PsxCommon.h"
|
|
||||||
#include "VUmicro.h"
|
#include "VUmicro.h"
|
||||||
|
|
||||||
#include "iR5900.h"
|
#include "iR5900.h"
|
||||||
|
|
||||||
int UseGui = 1;
|
static bool sinit = false;
|
||||||
int nDisableSC = 0; // screensaver
|
bool UseGui = true;
|
||||||
|
bool nDisableSC = false; // screensaver
|
||||||
|
|
||||||
SafeArray<u8>* g_RecoveryState = NULL;
|
|
||||||
SafeArray<u8>* g_gsRecoveryState = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
bool g_ReturnToGui = false; // set to exit the execution of the emulator and return control to the GUI
|
|
||||||
bool g_EmulationInProgress = false; // Set TRUE if a game is actively running (set to false on reset)
|
|
||||||
|
|
||||||
// This instance is not modified by command line overrides so
|
// This instance is not modified by command line overrides so
|
||||||
// that command line plugins and stuff won't be saved into the
|
// that command line plugins and stuff won't be saved into the
|
||||||
|
@ -50,7 +44,6 @@ const char* g_pRunGSState = NULL;
|
||||||
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||||
{
|
{
|
||||||
const _EXCEPTION_RECORD& ExceptionRecord = *eps->ExceptionRecord;
|
const _EXCEPTION_RECORD& ExceptionRecord = *eps->ExceptionRecord;
|
||||||
//const _CONTEXT& ContextRecord = *eps->ContextRecord;
|
|
||||||
|
|
||||||
if (ExceptionRecord.ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
if (ExceptionRecord.ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||||
{
|
{
|
||||||
|
@ -69,25 +62,6 @@ int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// For issuing notices to both the status bar and the console at the same time.
|
|
||||||
// Single-line text only please! Mutli-line msgs should be directed to the
|
|
||||||
// console directly, thanks.
|
|
||||||
void StatusBar_Notice( const std::string& text )
|
|
||||||
{
|
|
||||||
// mirror output to the console!
|
|
||||||
Console::Status( text.c_str() );
|
|
||||||
|
|
||||||
// don't try this in GCC folks!
|
|
||||||
SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the status bar message without mirroring the output to the console.
|
|
||||||
void StatusBar_SetMsg( const std::string& text )
|
|
||||||
{
|
|
||||||
// don't try this in GCC folks!
|
|
||||||
SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text.c_str() );
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns 1 if the user requested help (show help and exit)
|
// returns 1 if the user requested help (show help and exit)
|
||||||
// returns zero on success.
|
// returns zero on success.
|
||||||
// returns -1 on failure (bad command line argument)
|
// returns -1 on failure (bad command line argument)
|
||||||
|
@ -116,7 +90,7 @@ int ParseCommandLine( int tokenCount, TCHAR *const *const tokens )
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if( CmdSwitchIs( "nogui" ) ) {
|
else if( CmdSwitchIs( "nogui" ) ) {
|
||||||
UseGui = 0;
|
UseGui = false;
|
||||||
}
|
}
|
||||||
#ifdef PCSX2_DEVBUILD
|
#ifdef PCSX2_DEVBUILD
|
||||||
else if( CmdSwitchIs( "jpg" ) ) {
|
else if( CmdSwitchIs( "jpg" ) ) {
|
||||||
|
@ -205,376 +179,6 @@ void SysPrintf(const char *fmt, ...)
|
||||||
Console::Write( msg );
|
Console::Write( msg );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __fastcall KeyEvent(keyEvent* ev);
|
|
||||||
|
|
||||||
__forceinline void SysUpdate() {
|
|
||||||
|
|
||||||
keyEvent* ev1 = PAD1keyEvent();
|
|
||||||
keyEvent* ev2 = PAD2keyEvent();
|
|
||||||
|
|
||||||
KeyEvent( (ev1 != NULL) ? ev1 : ev2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TryRecoverFromGsState()
|
|
||||||
{
|
|
||||||
if( g_gsRecoveryState != NULL )
|
|
||||||
{
|
|
||||||
s32 dummylen;
|
|
||||||
|
|
||||||
memLoadingState eddie( *g_gsRecoveryState );
|
|
||||||
eddie.FreezePlugin( "GS", gsSafeFreeze );
|
|
||||||
eddie.Freeze( dummylen ); // reads the length value recorded earlier.
|
|
||||||
eddie.gsFreeze();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#include "R5900Exceptions.h"
|
|
||||||
|
|
||||||
void ExecuteCpu()
|
|
||||||
{
|
|
||||||
// Make sure any left-over recovery states are cleaned up.
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
|
|
||||||
// Just in case they weren't initialized earlier (no harm in calling this multiple times)
|
|
||||||
if (OpenPlugins(NULL) == -1) return;
|
|
||||||
|
|
||||||
// this needs to be called for every new game!
|
|
||||||
// (note: sometimes launching games through bios will give a crc of 0)
|
|
||||||
|
|
||||||
if( GSsetGameCRC != NULL )
|
|
||||||
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
|
||||||
|
|
||||||
TryRecoverFromGsState();
|
|
||||||
|
|
||||||
safe_delete( g_gsRecoveryState );
|
|
||||||
|
|
||||||
// ... and hide the window. Ugly thing.
|
|
||||||
|
|
||||||
ShowWindow( gApp.hWnd, SW_HIDE );
|
|
||||||
|
|
||||||
g_EmulationInProgress = true;
|
|
||||||
g_ReturnToGui = false;
|
|
||||||
|
|
||||||
// Optimization: We hardcode two versions of the EE here -- one for recs and one for ints.
|
|
||||||
// This is because recs are performance critical, and being able to inline them into the
|
|
||||||
// function here helps a small bit (not much but every small bit counts!).
|
|
||||||
|
|
||||||
timeBeginPeriod( 1 );
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if( CHECK_EEREC )
|
|
||||||
{
|
|
||||||
while( !g_ReturnToGui )
|
|
||||||
{
|
|
||||||
recExecute();
|
|
||||||
SysUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while( !g_ReturnToGui )
|
|
||||||
{
|
|
||||||
Cpu->Execute();
|
|
||||||
SysUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch( R5900Exception::BaseExcept& ex )
|
|
||||||
{
|
|
||||||
Console::Error( ex.cMessage() );
|
|
||||||
Console::Error( fmt_string( "(EE) PC: 0x%8.8x \tCycle:0x8.8x", ex.cpuState.pc, ex.cpuState.cycle ).c_str() );
|
|
||||||
|
|
||||||
if( !Config.PsxOut )
|
|
||||||
{
|
|
||||||
// TODO : no console opened, so use a popup to msg the user.
|
|
||||||
// Need to take care to shut down the GS first, or else it'll cause ugliness on fullscreen execution.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
timeEndPeriod( 1 );
|
|
||||||
|
|
||||||
ShowWindow( gApp.hWnd, SW_SHOW );
|
|
||||||
SetForegroundWindow( gApp.hWnd );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Runs and ELF image directly (ISO or ELF program or BIN)
|
|
||||||
// Used by Run::FromCD and such
|
|
||||||
void RunExecute( const char* elf_file, bool use_bios )
|
|
||||||
{
|
|
||||||
nDisableSC = 1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
cpuReset();
|
|
||||||
}
|
|
||||||
catch( Exception::BaseException& ex )
|
|
||||||
{
|
|
||||||
Msgbox::Alert( ex.cMessage() );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OpenPlugins(g_TestRun.ptitle) == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if( elf_file == NULL )
|
|
||||||
{
|
|
||||||
if(g_RecoveryState != NULL)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
memLoadingState( *g_RecoveryState ).FreezeAll();
|
|
||||||
}
|
|
||||||
catch( std::runtime_error& ex )
|
|
||||||
{
|
|
||||||
Msgbox::Alert(
|
|
||||||
"Gamestate recovery failed. Your game progress will be lost (sorry!)\n"
|
|
||||||
"\nError: %s\n", params ex.what() );
|
|
||||||
|
|
||||||
// Take the user back to the GUI...
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
ClosePlugins( true );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( g_gsRecoveryState == NULL )
|
|
||||||
{
|
|
||||||
// Not recovering a state, so need to execute the bios and load the ELF information.
|
|
||||||
// (note: gsRecoveries are done from ExecuteCpu)
|
|
||||||
|
|
||||||
// if the elf_file is null we use the CDVD elf file.
|
|
||||||
// But if the elf_file is an empty string then we boot the bios instead.
|
|
||||||
|
|
||||||
char ename[g_MaxPath];
|
|
||||||
ename[0] = 0;
|
|
||||||
if( !use_bios )
|
|
||||||
GetPS2ElfName( ename );
|
|
||||||
|
|
||||||
loadElfFile( ename );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Custom ELF specified (not using CDVD).
|
|
||||||
// Run the BIOS and load the ELF.
|
|
||||||
|
|
||||||
loadElfFile( elf_file );
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecuteCpu();
|
|
||||||
}
|
|
||||||
|
|
||||||
class RecoveryMemSavingState : public memSavingState, Sealed
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~RecoveryMemSavingState() { }
|
|
||||||
RecoveryMemSavingState() : memSavingState( *g_RecoveryState )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void gsFreeze()
|
|
||||||
{
|
|
||||||
if( g_gsRecoveryState != NULL )
|
|
||||||
{
|
|
||||||
// just copy the data from src to dst.
|
|
||||||
// the normal savestate doesn't expect a length prefix for internal structures,
|
|
||||||
// so don't copy that part.
|
|
||||||
const u32 pluginlen = *((u32*)g_gsRecoveryState->GetPtr());
|
|
||||||
const u32 gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
|
||||||
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(pluginlen+8), gslen );
|
|
||||||
m_idx += gslen;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memSavingState::gsFreeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )
|
|
||||||
{
|
|
||||||
if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) )
|
|
||||||
{
|
|
||||||
// Gs data is already in memory, so just copy from src to dest:
|
|
||||||
// length of the GS data is stored as the first u32, so use that to run the copy:
|
|
||||||
const u32 len = *((u32*)g_gsRecoveryState->GetPtr());
|
|
||||||
memcpy( m_memory.GetPtr(m_idx), g_gsRecoveryState->GetPtr(), len+4 );
|
|
||||||
m_idx += len+4;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memSavingState::FreezePlugin( name, freezer );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class RecoveryZipSavingState : public gzSavingState, Sealed
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~RecoveryZipSavingState() { }
|
|
||||||
RecoveryZipSavingState( const string& filename ) : gzSavingState( filename )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void gsFreeze()
|
|
||||||
{
|
|
||||||
if( g_gsRecoveryState != NULL )
|
|
||||||
{
|
|
||||||
// read data from the gsRecoveryState allocation instead of the GS, since the gs
|
|
||||||
// info was invalidated when the plugin was shut down.
|
|
||||||
|
|
||||||
// the normal savestate doesn't expect a length prefix for internal structures,
|
|
||||||
// so don't copy that part.
|
|
||||||
|
|
||||||
u32& pluginlen = *((u32*)g_gsRecoveryState->GetPtr(0));
|
|
||||||
u32& gslen = *((u32*)g_gsRecoveryState->GetPtr(pluginlen+4));
|
|
||||||
gzwrite( m_file, g_gsRecoveryState->GetPtr(pluginlen+4), gslen );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gzSavingState::gsFreeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FreezePlugin( const char* name, s32 (CALLBACK* freezer)(int mode, freezeData *data) )
|
|
||||||
{
|
|
||||||
if( (freezer == gsSafeFreeze) && (g_gsRecoveryState != NULL) )
|
|
||||||
{
|
|
||||||
// Gs data is already in memory, so just copy from there into the gzip file.
|
|
||||||
// length of the GS data is stored as the first u32, so use that to run the copy:
|
|
||||||
u32& len = *((u32*)g_gsRecoveryState->GetPtr());
|
|
||||||
gzwrite( m_file, g_gsRecoveryState->GetPtr(), len+4 );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gzSavingState::FreezePlugin( name, freezer );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void States_Load( const string& file, int num )
|
|
||||||
{
|
|
||||||
if( !Path::isFile( file ) )
|
|
||||||
{
|
|
||||||
Console::Notice( "Saveslot %d is empty.", params num );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
char Text[g_MaxPath];
|
|
||||||
gzLoadingState joe( file ); // this'll throw an StateLoadError_Recoverable.
|
|
||||||
|
|
||||||
// Make sure the cpu and plugins are ready to be state-ified!
|
|
||||||
cpuReset();
|
|
||||||
OpenPlugins( NULL );
|
|
||||||
|
|
||||||
joe.FreezeAll();
|
|
||||||
|
|
||||||
if( num != -1 )
|
|
||||||
sprintf (Text, _("*PCSX2*: Loaded State %d"), num);
|
|
||||||
else
|
|
||||||
sprintf (Text, _("*PCSX2*: Loaded State %s"), file);
|
|
||||||
|
|
||||||
StatusBar_Notice( Text );
|
|
||||||
|
|
||||||
if( GSsetGameCRC != NULL )
|
|
||||||
GSsetGameCRC(ElfCRC, g_ZeroGSOptions);
|
|
||||||
}
|
|
||||||
catch( Exception::StateLoadError_Recoverable& ex)
|
|
||||||
{
|
|
||||||
if( num != -1 )
|
|
||||||
Console::Notice( "Could not load savestate from slot %d.\n\n%s", params num, ex.cMessage() );
|
|
||||||
else
|
|
||||||
Console::Notice( "Could not load savestate file: %s.\n\n%s", params file, ex.cMessage() );
|
|
||||||
|
|
||||||
// At this point the cpu hasn't been reset, so we can return
|
|
||||||
// control to the user safely... (that's why we use a console notice instead of a popup)
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
catch( Exception::BaseException& ex )
|
|
||||||
{
|
|
||||||
// The emulation state is ruined. Might as well give them a popup and start the gui.
|
|
||||||
|
|
||||||
string message;
|
|
||||||
|
|
||||||
if( num != -1 )
|
|
||||||
ssprintf( message,
|
|
||||||
"Encountered an error while loading savestate from slot %d.\n", num );
|
|
||||||
else
|
|
||||||
ssprintf( message,
|
|
||||||
"Encountered an error while loading savestate from file: %s.\n", file );
|
|
||||||
|
|
||||||
if( g_EmulationInProgress )
|
|
||||||
message += "Since the savestate load was incomplete, the emulator has been reset.\n";
|
|
||||||
|
|
||||||
message += "\nError: " + ex.Message();
|
|
||||||
|
|
||||||
Msgbox::Alert( message.c_str() );
|
|
||||||
SysClose();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start emulating!
|
|
||||||
ExecuteCpu();
|
|
||||||
}
|
|
||||||
|
|
||||||
void States_Save( const string& file, int num )
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string text;
|
|
||||||
RecoveryZipSavingState( file ).FreezeAll();
|
|
||||||
if( num != -1 )
|
|
||||||
ssprintf( text, _( "State saved to slot %d" ), num );
|
|
||||||
else
|
|
||||||
ssprintf( text, _( "State saved to file: %s" ), file );
|
|
||||||
|
|
||||||
StatusBar_Notice( text );
|
|
||||||
}
|
|
||||||
catch( Exception::BaseException& ex )
|
|
||||||
{
|
|
||||||
string message;
|
|
||||||
|
|
||||||
if( num != -1 )
|
|
||||||
ssprintf( message, "An error occurred while trying to save to slot %d\n", num );
|
|
||||||
else
|
|
||||||
ssprintf( message, "An error occurred while trying to save to file: %s\n", file );
|
|
||||||
|
|
||||||
message += "Your emulation state has not been saved!\n\nError: " + ex.Message();
|
|
||||||
|
|
||||||
Console::Error( message.c_str() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void States_Load(int num)
|
|
||||||
{
|
|
||||||
States_Load( SaveState::GetFilename( num ), num );
|
|
||||||
}
|
|
||||||
|
|
||||||
void States_Save(int num)
|
|
||||||
{
|
|
||||||
if( g_RecoveryState != NULL )
|
|
||||||
{
|
|
||||||
// State is already saved into memory, and the emulator (and in-progress flag)
|
|
||||||
// have likely been cleared out. So save from the Recovery buffer instead of
|
|
||||||
// doing a "standard" save:
|
|
||||||
|
|
||||||
string text( SaveState::GetFilename( num ) );
|
|
||||||
gzFile fileptr = gzopen( text.c_str(), "wb" );
|
|
||||||
if( fileptr == NULL )
|
|
||||||
{
|
|
||||||
Msgbox::Alert( _("File permissions error while trying to save to slot %d"), params num );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
gzwrite( fileptr, &g_SaveVersion, sizeof( u32 ) );
|
|
||||||
gzwrite( fileptr, g_RecoveryState->GetPtr(), g_RecoveryState->GetSizeInBytes() );
|
|
||||||
gzclose( fileptr );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !g_EmulationInProgress )
|
|
||||||
{
|
|
||||||
Msgbox::Alert( "You need to start a game first before you can save it's state." );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
States_Save( SaveState::GetFilename( num ), num );
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnStates_LoadOther()
|
void OnStates_LoadOther()
|
||||||
{
|
{
|
||||||
OPENFILENAME ofn;
|
OPENFILENAME ofn;
|
||||||
|
@ -639,171 +243,14 @@ void OnStates_SaveOther()
|
||||||
States_Save( szFileName );
|
States_Save( szFileName );
|
||||||
}
|
}
|
||||||
|
|
||||||
class JustGsSavingState : public memSavingState, Sealed
|
bool HostGuiInit()
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~JustGsSavingState() { }
|
|
||||||
JustGsSavingState() : memSavingState( *g_gsRecoveryState )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// This special override saves the gs info to m_idx+4, and then goes back and
|
|
||||||
// writes in the length of data saved.
|
|
||||||
void gsFreeze()
|
|
||||||
{
|
|
||||||
int oldmidx = m_idx;
|
|
||||||
m_idx += 4;
|
|
||||||
memSavingState::gsFreeze();
|
|
||||||
if( IsSaving() )
|
|
||||||
{
|
|
||||||
s32& len = *((s32*)m_memory.GetPtr( oldmidx ));
|
|
||||||
len = (m_idx - oldmidx)-4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int shiftkey = 0;
|
|
||||||
static void __fastcall KeyEvent(keyEvent* ev)
|
|
||||||
{
|
|
||||||
if (ev == NULL) return;
|
|
||||||
if (ev->evt == KEYRELEASE) {
|
|
||||||
switch (ev->key) {
|
|
||||||
case VK_SHIFT: shiftkey = 0; break;
|
|
||||||
}
|
|
||||||
GSkeyEvent(ev); return;
|
|
||||||
}
|
|
||||||
if (ev->evt != KEYPRESS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
//some pad plugins don't give a key released event for shift, so this is needed
|
|
||||||
//shiftkey = GetKeyState(VK_SHIFT)&0x8000;
|
|
||||||
//Well SSXPad breaks with your code, thats why my code worked and your makes reg dumping impossible
|
|
||||||
//So i suggest you fix the plugins that dont.
|
|
||||||
|
|
||||||
switch (ev->key) {
|
|
||||||
case VK_SHIFT: shiftkey = 1; break;
|
|
||||||
|
|
||||||
case VK_F1: case VK_F2: case VK_F3: case VK_F4:
|
|
||||||
case VK_F5: case VK_F6: case VK_F7: case VK_F8:
|
|
||||||
case VK_F9: case VK_F10: case VK_F11: case VK_F12:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ProcessFKeys(ev->key-VK_F1 + 1, shiftkey);
|
|
||||||
}
|
|
||||||
catch( Exception::CpuStateShutdown& )
|
|
||||||
{
|
|
||||||
// Woops! Something was unrecoverable. Bummer.
|
|
||||||
// Let's give the user a RunGui!
|
|
||||||
|
|
||||||
g_EmulationInProgress = false;
|
|
||||||
g_ReturnToGui = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_TAB:
|
|
||||||
CycleFrameLimit(0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VK_ESCAPE:
|
|
||||||
#ifdef PCSX2_DEVBUILD
|
|
||||||
if( g_SaveGSStream >= 3 ) {
|
|
||||||
// gs state
|
|
||||||
g_SaveGSStream = 4;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
g_ReturnToGui = true;
|
|
||||||
if( CHECK_ESCAPE_HACK )
|
|
||||||
{
|
|
||||||
//PostMessage(GetForegroundWindow(), WM_CLOSE, 0, 0);
|
|
||||||
DestroyWindow( gApp.hWnd );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( !UseGui ) {
|
|
||||||
// not using GUI and user just quit, so exit
|
|
||||||
WinClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
if( Config.closeGSonEsc )
|
|
||||||
{
|
|
||||||
safe_delete( g_gsRecoveryState );
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
g_gsRecoveryState = new SafeArray<u8>();
|
|
||||||
JustGsSavingState eddie;
|
|
||||||
eddie.FreezePlugin( "GS", gsSafeFreeze ) ;
|
|
||||||
eddie.gsFreeze();
|
|
||||||
}
|
|
||||||
|
|
||||||
ClosePlugins( Config.closeGSonEsc );
|
|
||||||
nDisableSC = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
GSkeyEvent(ev);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool sinit=false;
|
|
||||||
|
|
||||||
|
|
||||||
void SysRestorableReset()
|
|
||||||
{
|
|
||||||
// already reset? and saved?
|
|
||||||
if( !g_EmulationInProgress ) return;
|
|
||||||
if( g_RecoveryState != NULL ) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
g_RecoveryState = new SafeArray<u8>( "Memory Savestate Recovery" );
|
|
||||||
RecoveryMemSavingState().FreezeAll();
|
|
||||||
safe_delete( g_gsRecoveryState );
|
|
||||||
g_EmulationInProgress = false;
|
|
||||||
}
|
|
||||||
catch( Exception::RuntimeError& ex )
|
|
||||||
{
|
|
||||||
Msgbox::Alert(
|
|
||||||
"Pcsx2 gamestate recovery failed. Some options may have been reverted to protect your game's state.\n"
|
|
||||||
"Error: %s", params ex.cMessage() );
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysReset()
|
|
||||||
{
|
|
||||||
if (!sinit) return;
|
|
||||||
|
|
||||||
// fixme - this code sets the statusbar but never returns control to the window message pump
|
|
||||||
// so the status bar won't receive the WM_PAINT messages needed to update itself anyway.
|
|
||||||
// Oops! (air)
|
|
||||||
|
|
||||||
StatusBar_Notice(_("Resetting..."));
|
|
||||||
Console::SetTitle(_("Resetting..."));
|
|
||||||
|
|
||||||
g_EmulationInProgress = false;
|
|
||||||
safe_delete( g_RecoveryState );
|
|
||||||
safe_delete( g_gsRecoveryState );
|
|
||||||
ResetPlugins();
|
|
||||||
|
|
||||||
ElfCRC = 0;
|
|
||||||
|
|
||||||
// Note : No need to call cpuReset() here. It gets called automatically before the
|
|
||||||
// emulator resumes execution.
|
|
||||||
|
|
||||||
StatusBar_Notice(_("Ready"));
|
|
||||||
Console::SetTitle(_("*PCSX2* Emulation state is reset."));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SysInit()
|
|
||||||
{
|
{
|
||||||
if( sinit ) return true;
|
if( sinit ) return true;
|
||||||
sinit = true;
|
sinit = true;
|
||||||
|
|
||||||
CreateDirectory(MEMCARDS_DIR, NULL);
|
CreateDirectory(MEMCARDS_DIR, NULL);
|
||||||
CreateDirectory(SSTATES_DIR, NULL);
|
CreateDirectory(SSTATES_DIR, NULL);
|
||||||
|
CreateDirectory(SNAPSHOTS_DIR, NULL);
|
||||||
|
|
||||||
// Set the compression attribute on the Memcards folder.
|
// Set the compression attribute on the Memcards folder.
|
||||||
// Memcards generally compress very well via NTFS compression.
|
// Memcards generally compress very well via NTFS compression.
|
||||||
|
@ -827,80 +274,208 @@ bool SysInit()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// completely shuts down the emulator's cpu state, and unloads all plugins from memory.
|
|
||||||
void SysClose()
|
|
||||||
{
|
|
||||||
if (!sinit) return;
|
|
||||||
cpuShutdown();
|
|
||||||
ClosePlugins( true );
|
|
||||||
ReleasePlugins();
|
|
||||||
sinit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static const char *err = N_("Error Loading Symbol");
|
static const char *err = N_("Error Loading Symbol");
|
||||||
static int errval;
|
static int errval;
|
||||||
|
|
||||||
void *SysLoadLibrary(const char *lib) {
|
namespace HostSys
|
||||||
return LoadLibrary(lib);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *SysLoadSym(void *lib, const char *sym) {
|
|
||||||
void *tmp = GetProcAddress((HINSTANCE)lib, sym);
|
|
||||||
if (tmp == NULL) errval = GetLastError();
|
|
||||||
else errval = 0;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *SysLibError() {
|
|
||||||
if( errval )
|
|
||||||
{
|
|
||||||
static char perr[4096];
|
|
||||||
|
|
||||||
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),NULL,perr,4095,NULL);
|
|
||||||
|
|
||||||
errval = 0;
|
|
||||||
return _(perr);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysCloseLibrary(void *lib)
|
|
||||||
{
|
{
|
||||||
FreeLibrary((HINSTANCE)lib);
|
void *LoadLibrary(const char *lib)
|
||||||
}
|
|
||||||
|
|
||||||
void *SysMmap(uptr base, u32 size)
|
|
||||||
{
|
|
||||||
return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysMunmap(uptr base, u32 size)
|
|
||||||
{
|
|
||||||
if( base == NULL ) return;
|
|
||||||
VirtualFree((void*)base, size, MEM_DECOMMIT);
|
|
||||||
VirtualFree((void*)base, 0, MEM_RELEASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SysMemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution )
|
|
||||||
{
|
|
||||||
DWORD winmode = 0;
|
|
||||||
|
|
||||||
switch( mode )
|
|
||||||
{
|
{
|
||||||
case Protect_NoAccess:
|
return LoadLibraryA( lib );
|
||||||
winmode = ( allowExecution ) ? PAGE_EXECUTE : PAGE_NOACCESS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Protect_ReadOnly:
|
|
||||||
winmode = ( allowExecution ) ? PAGE_EXECUTE_READ : PAGE_READONLY;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Protect_ReadWrite:
|
|
||||||
winmode = ( allowExecution ) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD OldProtect; // enjoy my uselessness, yo!
|
void *LoadSym(void *lib, const char *sym)
|
||||||
VirtualProtect( baseaddr, size, winmode, &OldProtect );
|
{
|
||||||
|
void *tmp = GetProcAddress((HINSTANCE)lib, sym);
|
||||||
|
if (tmp == NULL) errval = GetLastError();
|
||||||
|
else errval = 0;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *LibError()
|
||||||
|
{
|
||||||
|
if( errval )
|
||||||
|
{
|
||||||
|
static char perr[4096];
|
||||||
|
|
||||||
|
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),NULL,perr,4095,NULL);
|
||||||
|
|
||||||
|
errval = 0;
|
||||||
|
return _(perr);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CloseLibrary(void *lib)
|
||||||
|
{
|
||||||
|
FreeLibrary((HINSTANCE)lib);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *Mmap(uptr base, u32 size)
|
||||||
|
{
|
||||||
|
return VirtualAlloc((void*)base, size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Munmap(uptr base, u32 size)
|
||||||
|
{
|
||||||
|
if( base == NULL ) return;
|
||||||
|
VirtualFree((void*)base, size, MEM_DECOMMIT);
|
||||||
|
VirtualFree((void*)base, 0, MEM_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemProtect( void* baseaddr, size_t size, PageProtectionMode mode, bool allowExecution )
|
||||||
|
{
|
||||||
|
DWORD winmode = 0;
|
||||||
|
|
||||||
|
switch( mode )
|
||||||
|
{
|
||||||
|
case Protect_NoAccess:
|
||||||
|
winmode = ( allowExecution ) ? PAGE_EXECUTE : PAGE_NOACCESS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Protect_ReadOnly:
|
||||||
|
winmode = ( allowExecution ) ? PAGE_EXECUTE_READ : PAGE_READONLY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Protect_ReadWrite:
|
||||||
|
winmode = ( allowExecution ) ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD OldProtect; // enjoy my uselessness, yo!
|
||||||
|
VirtualProtect( baseaddr, size, winmode, &OldProtect );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace HostGui
|
||||||
|
{
|
||||||
|
// Sets the status bar message without mirroring the output to the console.
|
||||||
|
void SetStatusMsg( const string& text )
|
||||||
|
{
|
||||||
|
// don't try this in GCC folks!
|
||||||
|
SendMessage(hStatusWnd, SB_SETTEXT, 0, (LPARAM)text.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Notice( const string& text )
|
||||||
|
{
|
||||||
|
// mirror output to the console!
|
||||||
|
Console::Status( text.c_str() );
|
||||||
|
SetStatusMsg( text );
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetMenuSlots()
|
||||||
|
{
|
||||||
|
for( int i=0; i<5; i++ )
|
||||||
|
{
|
||||||
|
EnableMenuItem( GetSubMenu(gApp.hMenu, 0),
|
||||||
|
ID_FILE_STATES_LOAD_SLOT1+i,
|
||||||
|
States_isSlotUsed(i) ? MF_ENABLED : MF_GRAYED
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Because C++ lacks the finally clause >_<
|
||||||
|
static void _executeCpuFinally()
|
||||||
|
{
|
||||||
|
timeEndPeriod( 1 );
|
||||||
|
ShowWindow( gApp.hWnd, SW_SHOW );
|
||||||
|
SetForegroundWindow( gApp.hWnd );
|
||||||
|
nDisableSC = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginExecution()
|
||||||
|
{
|
||||||
|
nDisableSC = true;
|
||||||
|
|
||||||
|
// ... and hide the window. Ugly thing.
|
||||||
|
ShowWindow( gApp.hWnd, SW_HIDE );
|
||||||
|
timeBeginPeriod( 1 ); // improves multithreaded responsiveness
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SysExecute();
|
||||||
|
}
|
||||||
|
catch( Exception::BaseException& )
|
||||||
|
{
|
||||||
|
_executeCpuFinally();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
_executeCpuFinally();
|
||||||
|
}
|
||||||
|
|
||||||
|
void __fastcall KeyEvent( keyEvent* ev )
|
||||||
|
{
|
||||||
|
static int shiftkey = 0;
|
||||||
|
|
||||||
|
if (ev == NULL) return;
|
||||||
|
if (ev->evt == KEYRELEASE)
|
||||||
|
{
|
||||||
|
switch (ev->key)
|
||||||
|
{
|
||||||
|
case VK_SHIFT: shiftkey = 0; break;
|
||||||
|
}
|
||||||
|
GSkeyEvent(ev); return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->evt != KEYPRESS) return;
|
||||||
|
|
||||||
|
switch (ev->key)
|
||||||
|
{
|
||||||
|
case VK_SHIFT: shiftkey = 1; break;
|
||||||
|
|
||||||
|
case VK_F1: case VK_F2: case VK_F3: case VK_F4:
|
||||||
|
case VK_F5: case VK_F6: case VK_F7: case VK_F8:
|
||||||
|
case VK_F9: case VK_F10: case VK_F11: case VK_F12:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ProcessFKeys(ev->key-VK_F1 + 1, shiftkey);
|
||||||
|
}
|
||||||
|
catch( Exception::CpuStateShutdown& )
|
||||||
|
{
|
||||||
|
// Woops! Something was unrecoverable (like state load). Bummer.
|
||||||
|
// Let's give the user a RunGui!
|
||||||
|
|
||||||
|
g_EmulationInProgress = false;
|
||||||
|
SysEndExecution();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_TAB:
|
||||||
|
CycleFrameLimit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VK_ESCAPE:
|
||||||
|
#ifdef PCSX2_DEVBUILD
|
||||||
|
if( g_SaveGSStream >= 3 ) {
|
||||||
|
// gs state
|
||||||
|
g_SaveGSStream = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if( CHECK_ESCAPE_HACK )
|
||||||
|
{
|
||||||
|
g_EmulationInProgress = false;
|
||||||
|
DestroyWindow( gApp.hWnd );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !UseGui ) {
|
||||||
|
// not using GUI and user just quit, so exit
|
||||||
|
WinClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
nDisableSC = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SysEndExecution();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
GSkeyEvent(ev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,8 +7,7 @@
|
||||||
//
|
//
|
||||||
// Generated from the TEXTINCLUDE 2 resource.
|
// Generated from the TEXTINCLUDE 2 resource.
|
||||||
//
|
//
|
||||||
#include "afxresmw.h"
|
#include "afxresmw.h"
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
#undef APSTUDIO_READONLY_SYMBOLS
|
#undef APSTUDIO_READONLY_SYMBOLS
|
||||||
|
|
||||||
|
@ -731,6 +730,17 @@ BEGIN
|
||||||
EDITTEXT IDC_CP031,191,218,51,12,ES_READONLY
|
EDITTEXT IDC_CP031,191,218,51,12,ES_READONLY
|
||||||
END
|
END
|
||||||
|
|
||||||
|
IDD_JUMP DIALOGEX 0, 0, 175, 64
|
||||||
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||||
|
CAPTION "Jump to specific address"
|
||||||
|
FONT 8, "MS Shell Dlg", 0, 0, 0x0
|
||||||
|
BEGIN
|
||||||
|
EDITTEXT IDC_JUMP_PC,73,14,82,13
|
||||||
|
DEFPUSHBUTTON "OK",IDOK,25,43,50,14
|
||||||
|
PUSHBUTTON "Cancel",IDCANCEL,101,42,50,14
|
||||||
|
LTEXT "Enter new PC Address:",IDC_STATIC,3,16,65,8
|
||||||
|
END
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@ -889,8 +899,7 @@ END
|
||||||
//
|
//
|
||||||
// Generated from the TEXTINCLUDE 3 resource.
|
// Generated from the TEXTINCLUDE 3 resource.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
#endif // not APSTUDIO_INVOKED
|
#endif // not APSTUDIO_INVOKED
|
||||||
|
|
||||||
|
|
|
@ -129,17 +129,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||||
// Dialog
|
// Dialog
|
||||||
//
|
//
|
||||||
|
|
||||||
IDD_JUMP DIALOGEX 0, 0, 175, 64
|
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
|
||||||
CAPTION "Jump to specific address"
|
|
||||||
FONT 8, "MS Shell Dlg", 0, 0, 0x0
|
|
||||||
BEGIN
|
|
||||||
EDITTEXT IDC_JUMP_PC,73,14,82,13
|
|
||||||
DEFPUSHBUTTON "OK",IDOK,25,43,50,14
|
|
||||||
PUSHBUTTON "Cancel",IDCANCEL,101,42,50,14
|
|
||||||
LTEXT "Enter new PC Address:",IDC_STATIC,3,16,65,8
|
|
||||||
END
|
|
||||||
|
|
||||||
IDD_MEMORY DIALOG 0, 0, 317, 270
|
IDD_MEMORY DIALOG 0, 0, 317, 270
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||||
CAPTION "Memory"
|
CAPTION "Memory"
|
||||||
|
@ -235,10 +224,7 @@ BEGIN
|
||||||
GROUPBOX "Clamp Mode",IDC_STATIC,281,80,236,127,BS_LEFT
|
GROUPBOX "Clamp Mode",IDC_STATIC,281,80,236,127,BS_LEFT
|
||||||
GROUPBOX "Other Options",IDC_STATIC,281,210,237,34,BS_LEFT
|
GROUPBOX "Other Options",IDC_STATIC,281,210,237,34,BS_LEFT
|
||||||
LTEXT "These options specify how PCSX2's recompilers will clamp Infinities and NaN (Not a Number) values in the opcode instructions.",IDC_STATIC,286,94,224,19
|
LTEXT "These options specify how PCSX2's recompilers will clamp Infinities and NaN (Not a Number) values in the opcode instructions.",IDC_STATIC,286,94,224,19
|
||||||
LTEXT "*None* - No clamping. (Fastest Mode)\n*Normal* - Clamps the result.\n*Extra* - Clamps the operands, the result, and anywhere in between.\n*Extra + Preserve Sign* - Same as ""Extra"", except preserves NaN's sign when clamping the operands.",IDC_STATIC,286,114,224,48
|
LTEXT "*None* - No clamping. (Fastest Mode)\n*Normal* - Clamps the result.\n*Extra* - Clamps the operands, the result, and anywhere in between.\n*Extra + Preserve Sign* - Same as ""Extra"", except preserves NaN's sign when clamping the operands.",IDC_STATIC,286,114,224,48 LTEXT "*Full* - Attempts to emulate large numbers correctly for the EE's FPU. VU's clamp mode should be set to ""Extra + Preserve Sign"" for this to work best. (but still works for most games even with ""Normal"" VU clamping)",IDC_STATIC,287,163,214,36 LTEXT "Flush to Zero - Makes floating point underflows become zero.\nDenormals are Zero - Makes floating point denormals become zero.",IDC_STATIC,287,222,224,18END
|
||||||
LTEXT "*Full* - Attempts to emulate large numbers correctly for the EE's FPU. VU's clamp mode should be set to ""Extra + Preserve Sign"" for this to work best. (but still works for most games even with ""Normal"" VU clamping)",IDC_STATIC,287,163,214,36
|
|
||||||
LTEXT "Flush to Zero - Makes floating point underflows become zero.\nDenormals are Zero - Makes floating point denormals become zero.",IDC_STATIC,287,222,224,18
|
|
||||||
END
|
|
||||||
|
|
||||||
IDD_CONF_MEMCARD DIALOGEX 0, 0, 451, 215
|
IDD_CONF_MEMCARD DIALOGEX 0, 0, 451, 215
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||||
|
@ -343,11 +329,13 @@ FONT 8, "MS Shell Dlg", 400, 0, 0x0
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "OK",IDOK,205,274,50,14
|
DEFPUSHBUTTON "OK",IDOK,205,274,50,14
|
||||||
CTEXT "PCSX2, a PS2 Emulator...",IDC_PCSX_ABOUT_AUTHORS,9,10,135,127,0,WS_EX_TRANSPARENT
|
CTEXT "PCSX2, a PS2 Emulator...",IDC_PCSX_ABOUT_AUTHORS,9,10,135,127,0,WS_EX_TRANSPARENT
|
||||||
CTEXT "Greets to...",IDC_PCSX_ABOUT_GREETS,94,178,319,77
|
CTEXT "Greets to...",IDC_PCSX_ABOUT_GREETS,94,186,319,77
|
||||||
GROUPBOX "",IDC_STATIC,5,3,145,141
|
GROUPBOX "",IDC_STATIC,5,3,145,141
|
||||||
GROUPBOX "",IDC_STATIC,87,169,333,91
|
GROUPBOX "",IDC_STATIC,87,177,333,91
|
||||||
CONTROL 132,IDC_PS2SILVER_RECT,"Static",SS_BITMAP | SS_SUNKEN,10,179,71,75
|
CONTROL 132,IDC_PS2SILVER_RECT,"Static",SS_BITMAP | SS_SUNKEN,10,187,71,75
|
||||||
CONTROL 113,IDC_STATIC,"Static",SS_BITMAP,162,7,259,137,WS_EX_CLIENTEDGE
|
CONTROL 113,IDC_STATIC,"Static",SS_BITMAP,162,7,259,137,WS_EX_CLIENTEDGE
|
||||||
|
CTEXT "Pcsx2 Official Svn Repository @ Googlecode",IDC_LINK_GOOGLECODE,79,164,273,10,SS_NOPREFIX | SS_NOTIFY
|
||||||
|
CTEXT "Pcsx2 Official Website and Forums",IDC_LINK_WEBSITE,79,151,273,10,SS_NOPREFIX | SS_NOTIFY
|
||||||
END
|
END
|
||||||
|
|
||||||
IDD_HACKS DIALOGEX 0, 0, 335, 263
|
IDD_HACKS DIALOGEX 0, 0, 335, 263
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#define ABOUT_DIALOG 104
|
#define ABOUT_DIALOG 104
|
||||||
#define IDI_ICON 108
|
#define IDI_ICON 108
|
||||||
#define IDD_MEMORY 110
|
#define IDD_MEMORY 110
|
||||||
#define IDD_JUMP 112
|
|
||||||
#define SPLASH_LOGO 113
|
#define SPLASH_LOGO 113
|
||||||
#define IDD_LOGGING 119
|
#define IDD_LOGGING 119
|
||||||
#define IDD_CMDLINE 120
|
#define IDD_CMDLINE 120
|
||||||
|
@ -69,8 +68,10 @@
|
||||||
#define IDC_LISTCDVD 1054
|
#define IDC_LISTCDVD 1054
|
||||||
#define IDC_DEBUG_L17 1055
|
#define IDC_DEBUG_L17 1055
|
||||||
#define IDC_LISTBIOS 1055
|
#define IDC_LISTBIOS 1055
|
||||||
|
#define IDC_LINK_WEBSITE 1055
|
||||||
#define IDC_DEBUG_L18 1056
|
#define IDC_DEBUG_L18 1056
|
||||||
#define IDC_CONFIGGS 1056
|
#define IDC_CONFIGGS 1056
|
||||||
|
#define IDC_LINK_GOOGLECODE 1056
|
||||||
#define IDC_DEBUG_L19 1057
|
#define IDC_DEBUG_L19 1057
|
||||||
#define IDC_TESTGS 1057
|
#define IDC_TESTGS 1057
|
||||||
#define IDC_DEBUG_L20 1058
|
#define IDC_DEBUG_L20 1058
|
||||||
|
@ -139,7 +140,6 @@
|
||||||
#define IDC_DEBUG_R27 1094
|
#define IDC_DEBUG_R27 1094
|
||||||
#define IDC_DEBUG_R28 1095
|
#define IDC_DEBUG_R28 1095
|
||||||
#define IDC_DEBUG_R29 1096
|
#define IDC_DEBUG_R29 1096
|
||||||
#define IDC_JUMP_PC 1097
|
|
||||||
#define IDC_DEBUG_LOGGING 1098
|
#define IDC_DEBUG_LOGGING 1098
|
||||||
#define IDC_CMDLINE 1155
|
#define IDC_CMDLINE 1155
|
||||||
#define IDC_PCSX_ABOUT_GREETS 1163
|
#define IDC_PCSX_ABOUT_GREETS 1163
|
||||||
|
|
|
@ -389,14 +389,14 @@ void cpudetectInit()
|
||||||
// intrinsic equivalents available. So we use our own ix86 emitter to generate
|
// intrinsic equivalents available. So we use our own ix86 emitter to generate
|
||||||
// some code and run it that way. :)
|
// some code and run it that way. :)
|
||||||
|
|
||||||
u8* recSSE = (u8*)SysMmap( NULL, 0x1000 );
|
u8* recSSE = (u8*)HostSys::Mmap( NULL, 0x1000 );
|
||||||
if( recSSE != NULL )
|
if( recSSE != NULL )
|
||||||
{
|
{
|
||||||
x86SetPtr(recSSE);
|
x86SetPtr(recSSE);
|
||||||
SSE3_MOVSLDUP_XMM_to_XMM(XMM0, XMM0);
|
SSE3_MOVSLDUP_XMM_to_XMM(XMM0, XMM0);
|
||||||
RET();
|
RET();
|
||||||
cpudetectSSE3(recSSE);
|
cpudetectSSE3(recSSE);
|
||||||
SysMunmap( recSSE, 0x1000 );
|
HostSys::Munmap( recSSE, 0x1000 );
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////
|
//////////////////////////////////////
|
||||||
|
|
|
@ -77,7 +77,7 @@ microVUt(void) mVUclose() {
|
||||||
|
|
||||||
microVU* mVU = mVUx;
|
microVU* mVU = mVUx;
|
||||||
|
|
||||||
if ( mVU->cache ) { SysMunmap( mVU->cache, mVU->cacheSize ); mVU->cache = NULL; }
|
if ( mVU->cache ) { HostSys::Munmap( mVU->cache, mVU->cacheSize ); mVU->cache = NULL; }
|
||||||
|
|
||||||
// Delete Block Managers
|
// Delete Block Managers
|
||||||
for (int i; i <= mVU->prog.max; i++) {
|
for (int i; i <= mVU->prog.max; i++) {
|
||||||
|
|
Loading…
Reference in New Issue