wtf? A working framelimiter? Turbo and slowmo hotkeys? Frameskipping?! Why it's all here! Rejoice! And then find lots of bugs, too, I'm sure. Note: Frameskipping has no gui stuff yet... I'll do that soon.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2294 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-12-03 15:51:39 +00:00
parent 9675fe8108
commit 1e431fb69a
39 changed files with 805 additions and 500 deletions

View File

@ -465,6 +465,10 @@
RelativePath="..\..\include\Utilities\Exceptions.h" RelativePath="..\..\include\Utilities\Exceptions.h"
> >
</File> </File>
<File
RelativePath="..\..\include\Utilities\FixedPointTypes.h"
>
</File>
<File <File
RelativePath="..\..\include\Utilities\General.h" RelativePath="..\..\include\Utilities\General.h"
> >

View File

@ -527,6 +527,7 @@ typedef void (CALLBACK* _GSsetBaseMem)(void*);
typedef void (CALLBACK* _GSsetGameCRC)(int, int); typedef void (CALLBACK* _GSsetGameCRC)(int, int);
typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip); typedef void (CALLBACK* _GSsetFrameSkip)(int frameskip);
typedef void (CALLBACK* _GSsetFrameLimit)(int limit); typedef void (CALLBACK* _GSsetFrameLimit)(int limit);
typedef void (CALLBACK* _GSsetVsync)(int enabled);
typedef int (CALLBACK* _GSsetupRecording)(int, void*); typedef int (CALLBACK* _GSsetupRecording)(int, void*);
typedef void (CALLBACK* _GSreset)(); typedef void (CALLBACK* _GSreset)();
typedef void (CALLBACK* _GSwriteCSR)(u32 value); typedef void (CALLBACK* _GSwriteCSR)(u32 value);
@ -534,8 +535,8 @@ typedef void (CALLBACK* _GSmakeSnapshot)(const char *path);
typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int); typedef void (CALLBACK* _GSmakeSnapshot2)(const char *path, int*, int);
// Worthless crap function that returns GS plugin specific data via some // Worthless crap function that returns GS plugin specific data via some
// undocumented void* to a struct. If ant pad plugin actually relies on // undocumented void* to a struct. If any pad plugin actually relies on
// this info, it deserves to fail new nwer pcsx2s. -- air // this info, it deserves to fail new newer pcsx2s. -- air
//typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info); //typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info);
// PAD // PAD
@ -673,17 +674,18 @@ extern _GSreadFIFO GSreadFIFO;
extern _GSreadFIFO2 GSreadFIFO2; extern _GSreadFIFO2 GSreadFIFO2;
extern _GSchangeSaveState GSchangeSaveState; extern _GSchangeSaveState GSchangeSaveState;
extern _GSmakeSnapshot GSmakeSnapshot; extern _GSmakeSnapshot GSmakeSnapshot;
extern _GSmakeSnapshot2 GSmakeSnapshot2; extern _GSmakeSnapshot2 GSmakeSnapshot2;
extern _GSirqCallback GSirqCallback; extern _GSirqCallback GSirqCallback;
extern _GSprintf GSprintf; extern _GSprintf GSprintf;
extern _GSsetBaseMem GSsetBaseMem; extern _GSsetBaseMem GSsetBaseMem;
extern _GSsetGameCRC GSsetGameCRC; extern _GSsetGameCRC GSsetGameCRC;
extern _GSsetFrameSkip GSsetFrameSkip; extern _GSsetFrameSkip GSsetFrameSkip;
extern _GSsetFrameLimit GSsetFrameLimit; extern _GSsetFrameLimit GSsetFrameLimit;
extern _GSsetupRecording GSsetupRecording; extern _GSsetVsync GSsetVsync;
extern _GSreset GSreset; extern _GSsetupRecording GSsetupRecording;
extern _GSwriteCSR GSwriteCSR; extern _GSreset GSreset;
extern _GSwriteCSR GSwriteCSR;
// PAD // PAD
extern _PADopen PADopen; extern _PADopen PADopen;

View File

@ -17,8 +17,12 @@
// Dependencies.h : Contains classes required by all Utilities headers. // Dependencies.h : Contains classes required by all Utilities headers.
////////////////////////////////////////////////////////////////////////////////////////// // This should prove useful....
// DeclareNoncopyableObject #define wxsFormat wxString::Format
// --------------------------------------------------------------------------------------
// DeclareNoncopyableObject
// --------------------------------------------------------------------------------------
// This macro provides an easy and clean method for ensuring objects are not copyable. // This macro provides an easy and clean method for ensuring objects are not copyable.
// Simply add the macro to the head or tail of your class declaration, and attempts to // Simply add the macro to the head or tail of your class declaration, and attempts to
// copy the class will give you a moderately obtuse compiler error that will have you // copy the class will give you a moderately obtuse compiler error that will have you

View File

@ -0,0 +1,210 @@
/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2009 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "Dependencies.h"
template< int Precision >
struct FixedInt
{
s32 Raw;
FixedInt()
{
Raw = 0;
}
FixedInt( int signedval )
{
Raw = signedval * Precision;
}
FixedInt( double doubval )
{
Raw = (int)(doubval * (double)Precision);
}
FixedInt( float floval )
{
Raw = (int)(floval * (float)Precision);
}
bool operator ==( const FixedInt<Precision>& right ) const
{
return Raw == right.Raw;
}
bool operator !=( const FixedInt<Precision>& right ) const
{
return Raw != right.Raw;
}
FixedInt<Precision> operator+( const FixedInt<Precision>& right ) const
{
return FixedInt<Precision>().SetRaw( Raw + right.Raw );
}
FixedInt<Precision> operator-( const FixedInt<Precision>& right ) const
{
return FixedInt<Precision>().SetRaw( Raw + right.Raw );
}
FixedInt<Precision>& operator+=( const FixedInt<Precision>& right )
{
return SetRaw( Raw + right.Raw );
}
FixedInt<Precision>& operator-=( const FixedInt<Precision>& right )
{
return SetRaw( Raw + right.Raw );
}
bool operator>( const FixedInt<Precision>& right ) const { return Raw > right.Raw; }
bool operator>=( const FixedInt<Precision>& right ) const { return Raw >= right.Raw; }
bool operator<( const FixedInt<Precision>& right ) const { return Raw < right.Raw; }
bool operator<=( const FixedInt<Precision>& right ) const { return Raw <= right.Raw; }
FixedInt<Precision>& ConfineTo( const FixedInt<Precision>& low, const FixedInt<Precision>& high )
{
return SetRaw( std::min( std::max( Raw, low.Raw ), high.Raw ) );
}
// Uses 64 bit internally to avoid overflows. For more precise/optimized 32 bit math
// you'll need to use the Raw values directly.
FixedInt<Precision> operator*( const FixedInt<Precision>& right ) const
{
s64 mulres = (s64)Raw * right.Raw;
return FixedInt<Precision>().SetRaw( (s32)(mulres / Precision) );
}
// Uses 64 bit internally to avoid overflows. For more precise/optimized 32 bit math
// you'll need to use the Raw values directly.
FixedInt<Precision> operator/( const FixedInt<Precision>& right ) const
{
s64 divres = Raw * Precision;
return FixedInt<Precision>().SetRaw( (s32)(divres / right.Raw) );
}
// Uses 64 bit internally to avoid overflows. For more precise/optimized 32 bit math
// you'll need to use the Raw values directly.
FixedInt<Precision>& operator*=( const FixedInt<Precision>& right )
{
s64 mulres = (s64)Raw * right.Raw;
return SetRaw( (s32)(mulres / Precision) );
}
// Uses 64 bit internally to avoid overflows. For more precise/optimized 32 bit math
// you'll need to use the Raw values directly.
FixedInt<Precision>& operator/=( const FixedInt<Precision>& right )
{
s64 divres = Raw * Precision;
return SetRaw( (s32)(divres / right.Raw) );
}
// returns TRUE if the value overflows the legal integer range of this container.
static bool OverflowCheck( int signedval )
{
return ( signedval >= (INT_MAX / Precision) );
}
// returns TRUE if the value overflows the legal integer range of this container.
static bool OverflowCheck( double signedval )
{
return ( signedval >= (INT_MAX / Precision) );
}
int GetWhole() const { return Raw / Precision; }
int GetFraction() const { return Raw % Precision; }
FixedInt<Precision>& SetRaw( s32 rawsrc )
{
Raw = rawsrc;
return *this;
}
FixedInt<Precision>& Round()
{
Raw = ToIntRounded();
return *this;
}
FixedInt<Precision>& SetWhole( s32 wholepart )
{
pxAssert( wholepart < (INT_MAX / Precision) );
Raw = GetFraction() + (wholepart * Precision);
return *this;
}
FixedInt<Precision>& SetFraction( u32 fracpart )
{
Raw = (GetWhole() * Precision) + fracpart;
return *this;
}
wxString ToString() const
{
return wxsFormat( L"%d.%d", GetWhole(), (GetFraction() * 100) / Precision );
}
wxString ToString( int fracDigits ) const
{
if( fracDigits == 0 ) return wxsFormat( L"%d", GetWhole() );
pxAssert( fracDigits <= 7 ); // higher numbers would just cause overflows and bad mojo.
int mulby = (int)pow( 10.0, fracDigits );
return wxsFormat( L"%d.%d", GetWhole(), (GetFraction() * mulby) / Precision );
}
double ToDouble() const
{
return ((double)Raw / (double)Precision);
}
float ToFloat() const
{
return ((float)Raw / (float)Precision);
}
int ToIntTruncated() const
{
return Raw / Precision;
}
int ToIntRounded() const
{
return (Raw + (Precision/2)) / Precision;
}
static FixedInt<Precision> FromString( const wxString parseFrom, const FixedInt<Precision>& defval )
{
long whole, frac;
wxString afterFirst( parseFrom.AfterFirst( L'.' ).Mid(0, 5) );
if( !parseFrom.BeforeFirst( L'.' ).ToLong( &whole ) || !afterFirst.ToLong( &frac ) )
return defval;
FixedInt<Precision> retval( whole );
if( afterFirst.Length() != 0 && frac != 0 )
{
int fracPower = (int)pow( 10.0, (int)afterFirst.Length() );
retval.SetFraction( (frac * Precision) / fracPower );
}
return retval;
}
};
typedef FixedInt<256> Fixed256;
typedef FixedInt<100> Fixed100;

View File

@ -17,7 +17,6 @@
#include "Dependencies.h" #include "Dependencies.h"
#include <wx/string.h>
#include <wx/tokenzr.h> #include <wx/tokenzr.h>
#include <wx/gdicmn.h> // for wxPoint/wxRect stuff #include <wx/gdicmn.h> // for wxPoint/wxRect stuff
@ -29,9 +28,6 @@ extern wxString fromAscii( const char* src );
// wxWidgets lacks one of its own... // wxWidgets lacks one of its own...
extern const wxRect wxDefaultRect; extern const wxRect wxDefaultRect;
// This should prove useful....
#define wxsFormat wxString::Format
extern void SplitString( wxArrayString& dest, const wxString& src, const wxString& delims, wxStringTokenizerMode mode = wxTOKEN_RET_EMPTY_ALL ); extern void SplitString( wxArrayString& dest, const wxString& src, const wxString& delims, wxStringTokenizerMode mode = wxTOKEN_RET_EMPTY_ALL );
extern void JoinString( wxString& dest, const wxArrayString& src, const wxString& separator ); extern void JoinString( wxString& dest, const wxArrayString& src, const wxString& separator );

View File

@ -28,7 +28,6 @@
static const u32 BIAS = 2; // Bus is half of the actual ps2 speed static const u32 BIAS = 2; // Bus is half of the actual ps2 speed
static const u32 PS2CLK = 294912000; //hz /* 294.912 mhz */ static const u32 PS2CLK = 294912000; //hz /* 294.912 mhz */
//#define PS2CLK 36864000 /* 294.912 mhz */
static const ConsoleColors ConColor_IOP = Color_Yellow; static const ConsoleColors ConColor_IOP = Color_Yellow;
static const ConsoleColors ConColor_EE = Color_Cyan; static const ConsoleColors ConColor_EE = Color_Cyan;

View File

@ -258,6 +258,16 @@ struct ConsoleLogFilters
ConsoleLogFilters(); ConsoleLogFilters();
void LoadSave( IniInterface& ini ); void LoadSave( IniInterface& ini );
bool operator ==( const ConsoleLogFilters& right ) const
{
return OpEqu( bitset );
}
bool operator !=( const ConsoleLogFilters& right ) const
{
return !this->operator ==( right );
}
}; };
// -------------------------------------------------------------------------------------- // --------------------------------------------------------------------------------------
@ -371,43 +381,49 @@ struct Pcsx2Config
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
struct VideoOptions struct GSOptions
{ {
// forces the MTGS to execute tags/tasks in fully blocking/synchronous // forces the MTGS to execute tags/tasks in fully blocking/synchronous
// style. Useful for debugging potential bugs in the MTGS pipeline. // style. Useful for debugging potential bugs in the MTGS pipeline.
bool SynchronousMTGS; bool SynchronousMTGS;
bool EnableFrameLimiting;
bool EnableFrameSkipping;
bool FrameLimitEnable;
bool FrameSkipEnable;
bool VsyncEnable;
// The region mode controls the default Maximum/Minimum FPS settings and also // The region mode controls the default Maximum/Minimum FPS settings and also
// regulates the vsync rates (which in turn control the IOP's SPU2 tick sync and ensure // regulates the vsync rates (which in turn control the IOP's SPU2 tick sync and ensure
// proper audio playback speed). // proper audio playback speed).
int DefaultRegionMode; // 0=NTSC and 1=PAL int DefaultRegionMode; // 0=NTSC and 1=PAL
int FpsTurbo; // Limiting kicks in if fps goes beyond this (turbo enabled) int ConsecutiveFrames; // number of consecutive frames (fields) to render
int FpsLimit; // Limiting kicks in if fps goes beyond this line int ConsecutiveSkip; // number of consecutive frames (fields) to skip
int FpsSkip; // Skipping kicks in if fps drops below this line
int ConsecutiveFrames; // number of consecutive frames (fields) to render
int ConsecutiveSkip; // number of consecutive frames (fields) to skip
VideoOptions(); Fixed100 LimitScalar;
Fixed100 FramerateNTSC;
Fixed100 FrameratePAL;
GSOptions();
void LoadSave( IniInterface& conf ); void LoadSave( IniInterface& conf );
bool operator ==( const VideoOptions& right ) const bool operator ==( const GSOptions& right ) const
{ {
return return
OpEqu( EnableFrameSkipping ) && OpEqu( SynchronousMTGS ) &&
OpEqu( EnableFrameLimiting ) && OpEqu( FrameSkipEnable ) &&
OpEqu( FrameLimitEnable ) &&
OpEqu( VsyncEnable ) &&
OpEqu( LimitScalar ) &&
OpEqu( FramerateNTSC ) &&
OpEqu( FrameratePAL ) &&
OpEqu( DefaultRegionMode ) && OpEqu( DefaultRegionMode ) &&
OpEqu( FpsTurbo ) &&
OpEqu( FpsLimit ) &&
OpEqu( FpsSkip ) &&
OpEqu( ConsecutiveFrames ) && OpEqu( ConsecutiveFrames ) &&
OpEqu( ConsecutiveSkip ); OpEqu( ConsecutiveSkip );
} }
bool operator !=( const VideoOptions& right ) const bool operator !=( const GSOptions& right ) const
{ {
return !this->operator ==( right ); return !this->operator ==( right );
} }
@ -475,15 +491,15 @@ struct Pcsx2Config
BITFIELD32() BITFIELD32()
bool bool
CdvdVerboseReads:1, // enables cdvd read activity verbosely dumped to the console CdvdVerboseReads :1, // enables cdvd read activity verbosely dumped to the console
CdvdDumpBlocks:1, // enables cdvd block dumping CdvdDumpBlocks :1, // enables cdvd block dumping
EnablePatches:1, // enables patch detection and application EnablePatches :1, // enables patch detection and application
// when enabled performs bios stub execution, skipping full sony bios + splash screens // when enabled performs bios stub execution, skipping full sony bios + splash screens
SkipBiosSplash:1, SkipBiosSplash :1,
// enables simulated ejection of memory cards when loading savestates // enables simulated ejection of memory cards when loading savestates
McdEnableEjection:1, McdEnableEjection :1,
MultitapPort0_Enabled:1, MultitapPort0_Enabled:1,
MultitapPort1_Enabled:1, MultitapPort1_Enabled:1,
@ -492,7 +508,7 @@ struct Pcsx2Config
BITFIELD_END BITFIELD_END
CpuOptions Cpu; CpuOptions Cpu;
VideoOptions Video; GSOptions GS;
SpeedhackOptions Speedhacks; SpeedhackOptions Speedhacks;
GamefixOptions Gamefixes; GamefixOptions Gamefixes;
ProfilerOptions Profiler; ProfilerOptions Profiler;
@ -517,10 +533,12 @@ struct Pcsx2Config
return return
OpEqu( bitset ) && OpEqu( bitset ) &&
OpEqu( Cpu ) && OpEqu( Cpu ) &&
OpEqu( Video ) && OpEqu( GS ) &&
OpEqu( Speedhacks ) && OpEqu( Speedhacks ) &&
OpEqu( Gamefixes ) && OpEqu( Gamefixes ) &&
OpEqu( Profiler ) && OpEqu( Profiler ) &&
OpEqu( Log ) &&
OpEqu( Trace ) &&
OpEqu( BiosFilename ); OpEqu( BiosFilename );
} }
@ -530,23 +548,12 @@ struct Pcsx2Config
} }
}; };
//////////////////////////////////////////////////////////////////////////
// Session Configuration Override Flags
//
// a handful of flags that can override user configurations for the current application session
// only. This allows us to do things like force-disable recompilers if the memory allocations
// for them fail.
struct SessionOverrideFlags
{
bool
ForceDisableEErec:1,
ForceDisableIOPrec:1,
ForceDisableVU0rec:1,
ForceDisableVU1rec:1;
};
extern const Pcsx2Config EmuConfig; extern const Pcsx2Config EmuConfig;
extern SessionOverrideFlags g_Session;
Pcsx2Config::GSOptions& SetGSConfig();
ConsoleLogFilters& SetConsoleConfig();
TraceLogFilters& SetTraceConfig();
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
// Helper Macros for Reading Emu Configurations. // Helper Macros for Reading Emu Configurations.
@ -557,10 +564,10 @@ extern SessionOverrideFlags g_Session;
#define CHECK_MACROVU0 // If defined uses mVU for VU Macro (COP2), else uses sVU #define CHECK_MACROVU0 // If defined uses mVU for VU Macro (COP2), else uses sVU
#define CHECK_MICROVU0 (EmuConfig.Cpu.Recompiler.UseMicroVU0) #define CHECK_MICROVU0 (EmuConfig.Cpu.Recompiler.UseMicroVU0)
#define CHECK_MICROVU1 (EmuConfig.Cpu.Recompiler.UseMicroVU1) #define CHECK_MICROVU1 (EmuConfig.Cpu.Recompiler.UseMicroVU1)
#define CHECK_EEREC (!g_Session.ForceDisableEErec && EmuConfig.Cpu.Recompiler.EnableEE) #define CHECK_EEREC (EmuConfig.Cpu.Recompiler.EnableEE && GetSysCoreAlloc().RecSuccess_EE)
#define CHECK_IOPREC (!g_Session.ForceDisableIOPrec && EmuConfig.Cpu.Recompiler.EnableIOP) #define CHECK_IOPREC (EmuConfig.Cpu.Recompiler.EnableIOP && GetSysCoreAlloc().RecSuccess_IOP)
#define CHECK_VU0REC (!g_Session.ForceDisableVU0rec && EmuConfig.Cpu.Recompiler.EnableVU0) #define CHECK_VU0REC (EmuConfig.Cpu.Recompiler.EnableVU0 && GetSysCoreAlloc().RecSuccess_VU0)
#define CHECK_VU1REC (!g_Session.ForceDisableVU1rec && EmuConfig.Cpu.Recompiler.EnableVU1) #define CHECK_VU1REC (EmuConfig.Cpu.Recompiler.EnableVU1 && GetSysCoreAlloc().RecSuccess_VU1)
//------------ SPECIAL GAME FIXES!!! --------------- //------------ SPECIAL GAME FIXES!!! ---------------
#define NUM_OF_GAME_FIXES 7 #define NUM_OF_GAME_FIXES 7

View File

@ -160,7 +160,7 @@ static u64 m_iStart=0;
struct vSyncTimingInfo struct vSyncTimingInfo
{ {
u32 Framerate; // frames per second * 100 (so 2500 for PAL and 2997 for NTSC) Fixed100 Framerate; // frames per second (8 bit fixed)
u32 Render; // time from vblank end to vblank start (cycles) u32 Render; // time from vblank end to vblank start (cycles)
u32 Blank; // time from vblank start to vblank end (cycles) u32 Blank; // time from vblank start to vblank end (cycles)
@ -174,34 +174,31 @@ struct vSyncTimingInfo
static vSyncTimingInfo vSyncInfo; static vSyncTimingInfo vSyncInfo;
static void vSyncInfoCalc( vSyncTimingInfo* info, u32 framesPerSecond, u32 scansPerFrame ) static void vSyncInfoCalc( vSyncTimingInfo* info, Fixed100 framesPerSecond, u32 scansPerFrame )
{ {
// Important: Cannot use floats or doubles here. The emulator changes rounding modes // I use fixed point math here to have strict control over rounding errors. --air
// depending on user-set speedhack options, and it can break float/double code
// (as in returning infinities and junk)
// NOTE: mgs3 likes a /4 vsync, but many games prefer /2. This seems to indicate a // NOTE: mgs3 likes a /4 vsync, but many games prefer /2. This seems to indicate a
// problem in the counters vsync gates somewhere. // problem in the counters vsync gates somewhere.
u64 Frame = ((u64)PS2CLK * 1000000ULL) / framesPerSecond; u64 Frame = ((u64)PS2CLK * 1000000ULL) / (framesPerSecond*100).ToIntRounded();
u64 HalfFrame = Frame / 2; u64 HalfFrame = Frame / 2;
u64 Blank = HalfFrame / 2; // two blanks and renders per frame u64 Blank = HalfFrame / 2; // two blanks and renders per frame
u64 Render = HalfFrame - Blank; // so use the half-frame value for these... u64 Render = HalfFrame - Blank; // so use the half-frame value for these...
// Important! The hRender/hBlank timers should be 50/50 for best results. // Important! The hRender/hBlank timers should be 50/50 for best results.
// In theory a 70%/30% ratio would be more correct but in practice it runs // (this appears to be what the real EE's timing crystal does anyway)
// like crap and totally screws audio synchronization and other things.
u64 Scanline = Frame / scansPerFrame; u64 Scanline = Frame / scansPerFrame;
u64 hBlank = Scanline / 2; u64 hBlank = Scanline / 2;
u64 hRender = Scanline - hBlank; u64 hRender = Scanline - hBlank;
info->Framerate = framesPerSecond; info->Framerate = framesPerSecond;
info->Render = (u32)(Render/10000); info->Render = (u32)(Render/10000);
info->Blank = (u32)(Blank/10000); info->Blank = (u32)(Blank/10000);
info->hRender = (u32)(hRender/10000); info->hRender = (u32)(hRender/10000);
info->hBlank = (u32)(hBlank/10000); info->hBlank = (u32)(hBlank/10000);
info->hScanlinesPerFrame = scansPerFrame; info->hScanlinesPerFrame = scansPerFrame;
// Apply rounding: // Apply rounding:
@ -226,53 +223,64 @@ static void vSyncInfoCalc( vSyncTimingInfo* info, u32 framesPerSecond, u32 scans
u32 UpdateVSyncRate() u32 UpdateVSyncRate()
{ {
static const char *limiterMsg = "Framelimiter rate updated (UpdateVSyncRate): %d.%d fps"; XMMRegisters::Freeze();
MMXRegisters::Freeze();
// fixme - According to some docs, progressive-scan modes actually refresh slower than // Notice: (and I probably repeat this elsewhere, but it's worth repeating)
// interlaced modes. But I can't fathom how, since the refresh rate is a function of // The PS2's vsync timer is an *independent* crystal that is fixed to either 59.94 (NTSC)
// the television and all the docs I found on TVs made no indication that they ever // or 50.0 (PAL) Hz. It has *nothing* to do with real TV timings or the real vsync of
// run anything except their native refresh rate. // the GS's output circuit. It is the same regardless if the GS is outputting interlace
// or progressive scan content. Indications are that it is also a simple 50/50 timer and
//#define VBLANK_NTSC ((Config.PsxType & 2) ? 59.94 : 59.82) //59.94 is more precise // that it does not actually measure Vblank/Vdraw zones accurately (which would be like
//#define VBLANK_PAL ((Config.PsxType & 2) ? 50.00 : 49.76) // 1/5 and 4/5 ratios).
Fixed100 framerate;
u32 scanlines;
bool isCustom;
if( gsRegionMode == Region_PAL ) if( gsRegionMode == Region_PAL )
{ {
if( vSyncInfo.Framerate != FRAMERATE_PAL ) isCustom = (EmuConfig.GS.FrameratePAL != 50.0);
vSyncInfoCalc( &vSyncInfo, FRAMERATE_PAL, SCANLINES_TOTAL_PAL ); framerate = EmuConfig.GS.FrameratePAL / 2;
scanlines = SCANLINES_TOTAL_PAL;
} }
else else
{ {
if( vSyncInfo.Framerate != FRAMERATE_NTSC ) isCustom = (EmuConfig.GS.FramerateNTSC != 59.94);
vSyncInfoCalc( &vSyncInfo, FRAMERATE_NTSC, SCANLINES_TOTAL_NTSC ); framerate = EmuConfig.GS.FramerateNTSC / 2;
scanlines = SCANLINES_TOTAL_NTSC;
}
if( vSyncInfo.Framerate != framerate )
{
vSyncInfoCalc( &vSyncInfo, framerate, scanlines );
Console.WriteLn( Color_Blue, "(UpdateVSyncRate) Mode Changed to %s.", ( gsRegionMode == Region_PAL ) ? "PAL" : "NTSC" );
if( isCustom )
Console.Indent().WriteLn( Color_StrongBlue, "... with user configured refresh rate: %.02f Hz", framerate.ToFloat() );
hsyncCounter.CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated
vsyncCounter.CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated
cpuRcntSet();
} }
hsyncCounter.CycleT = vSyncInfo.hRender; // Amount of cycles before the counter will be updated Fixed100 fpslimit = framerate *
vsyncCounter.CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated ( pxAssert( EmuConfig.GS.LimitScalar > 0 ) ? EmuConfig.GS.LimitScalar : 1.0 );
if( EmuConfig.Video.EnableFrameLimiting && (EmuConfig.Video.FpsLimit > 0) ) //s64 debugme = GetTickFrequency() / 3000;
s64 ticks = (GetTickFrequency()*500) / (fpslimit * 1000).ToIntRounded();
if( m_iTicks != ticks )
{ {
s64 ticks = GetTickFrequency() / EmuConfig.Video.FpsLimit; m_iTicks = ticks;
if( m_iTicks != ticks ) gsOnModeChanged( vSyncInfo.Framerate, m_iTicks );
{ Console.WriteLn( "(UpdateVSyncRate) FPS Limit Changed : %.02f fps", fpslimit.ToFloat()*2 );
m_iTicks = ticks;
gsOnModeChanged( vSyncInfo.Framerate, m_iTicks );
Console.WriteLn( limiterMsg, EmuConfig.Video.FpsLimit, 0 );
}
}
else
{
s64 ticks = (GetTickFrequency() * 50) / vSyncInfo.Framerate;
if( m_iTicks != ticks )
{
m_iTicks = ticks;
gsOnModeChanged( vSyncInfo.Framerate, m_iTicks );
Console.WriteLn( limiterMsg, vSyncInfo.Framerate/50, (vSyncInfo.Framerate*2)%100 );
}
} }
m_iStart = GetCPUTicks(); m_iStart = GetCPUTicks();
cpuRcntSet();
XMMRegisters::Thaw();
MMXRegisters::Thaw();
return (u32)m_iTicks; return (u32)m_iTicks;
} }
@ -289,16 +297,11 @@ extern int limitOn;
static __forceinline void frameLimit() static __forceinline void frameLimit()
{ {
// 999 means the user would rather just have framelimiting turned off... // 999 means the user would rather just have framelimiting turned off...
if( /*!EmuConfig.Video.EnableFrameLimiting*/ !limitOn || EmuConfig.Video.FpsLimit >= 999 ) return; if( !EmuConfig.GS.FrameLimitEnable ) return;
s64 sDeltaTime; u64 uExpectedEnd = m_iStart + m_iTicks;
u64 uExpectedEnd; u64 iEnd = GetCPUTicks();
u64 iEnd; s64 sDeltaTime = iEnd - uExpectedEnd;
uExpectedEnd = m_iStart + m_iTicks;
iEnd = GetCPUTicks();
sDeltaTime = iEnd - uExpectedEnd;
// If the framerate drops too low, reset the expected value. This avoids // If the framerate drops too low, reset the expected value. This avoids
// excessive amounts of "fast forward" syndrome which would occur if we // excessive amounts of "fast forward" syndrome which would occur if we
@ -307,12 +310,6 @@ static __forceinline void frameLimit()
if( sDeltaTime > m_iTicks*8 ) if( sDeltaTime > m_iTicks*8 )
{ {
m_iStart = iEnd - m_iTicks; m_iStart = iEnd - m_iTicks;
// Let the GS Skipper know we lost time.
// Keeps the GS skipper from trying to catch up to a framerate
// that the limiter already gave up on.
gsSyncLimiterLostTime( (s32)(m_iStart - uExpectedEnd) );
return; return;
} }
@ -386,7 +383,7 @@ static __forceinline void VSyncEnd(u32 sCycle)
iFrame++; iFrame++;
gsPostVsyncEnd( true ); gsPostVsyncEnd();
hwIntcIrq(INTC_VBLANK_E); // HW Irq hwIntcIrq(INTC_VBLANK_E); // HW Irq
psxVBlankEnd(); // psxCounters vBlank End psxVBlankEnd(); // psxCounters vBlank End

View File

@ -92,7 +92,7 @@ struct SyncCounter
//------------------------------------------------------------------ //------------------------------------------------------------------
// NTSC Timing Information!!! (some scanline info is guessed) // NTSC Timing Information!!! (some scanline info is guessed)
//------------------------------------------------------------------ //------------------------------------------------------------------
#define FRAMERATE_NTSC 2997// frames per second * 100 (29.97) #define FRAMERATE_NTSC 29.97 // frames per second
#define SCANLINES_TOTAL_NTSC 525 // total number of scanlines #define SCANLINES_TOTAL_NTSC 525 // total number of scanlines
#define SCANLINES_VSYNC_NTSC 3 // scanlines that are used for syncing every half-frame #define SCANLINES_VSYNC_NTSC 3 // scanlines that are used for syncing every half-frame
@ -103,7 +103,7 @@ struct SyncCounter
//------------------------------------------------------------------ //------------------------------------------------------------------
// PAL Timing Information!!! (some scanline info is guessed) // PAL Timing Information!!! (some scanline info is guessed)
//------------------------------------------------------------------ //------------------------------------------------------------------
#define FRAMERATE_PAL 2500// frames per second * 100 (25) #define FRAMERATE_PAL 25.0// frames per second * 100 (25)
#define SCANLINES_TOTAL_PAL 625 // total number of scanlines per frame #define SCANLINES_TOTAL_PAL 625 // total number of scanlines per frame
#define SCANLINES_VSYNC_PAL 5 // scanlines that are used for syncing every half-frame #define SCANLINES_VSYNC_PAL 5 // scanlines that are used for syncing every half-frame
@ -145,7 +145,7 @@ extern void rcntWhold(int index, u32 value);
extern u32 rcntRcount(int index); extern u32 rcntRcount(int index);
extern u32 rcntCycle(int index); extern u32 rcntCycle(int index);
u32 UpdateVSyncRate(); extern u32 UpdateVSyncRate();
void frameLimitReset(); extern void frameLimitReset();
#endif /* __COUNTERS_H__ */ #endif /* __COUNTERS_H__ */

View File

@ -31,7 +31,7 @@ typedef char* (*TdisR5900F)DisFInterface;
// These macros are used to assemble the disassembler functions // These macros are used to assemble the disassembler functions
#define MakeDisF(fn, b) \ #define MakeDisF(fn, b) \
char* fn DisFInterface { \ char* fn DisFInterface { \
if( !CHECK_VU1REC ) sprintf (ostr, "%8.8x %8.8x:", pc, code); \ if( !!CpuVU1.IsInterpreter ) sprintf (ostr, "%8.8x %8.8x:", pc, code); \
else ostr[0] = 0; \ else ostr[0] = 0; \
b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \ b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \
} }
@ -52,47 +52,47 @@ typedef char* (*TdisR5900F)DisFInterface;
} }
#define dCP2128f(i) { \ #define dCP2128f(i) { \
if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \
else sprintf(ostr, "%s w=%f (%8.8x) z=%f (%8.8x) y=%f (%8.8xl) x=%f (%8.8x) (%s),", ostr, VU1.VF[i].f.w, VU1.VF[i].UL[3], VU1.VF[i].f.z, VU1.VF[i].UL[2], VU1.VF[i].f.y, VU1.VF[i].UL[1], VU1.VF[i].f.x, VU1.VF[i].UL[0], disRNameCP2f[i]); \ else sprintf(ostr, "%s w=%f (%8.8x) z=%f (%8.8x) y=%f (%8.8xl) x=%f (%8.8x) (%s),", ostr, VU1.VF[i].f.w, VU1.VF[i].UL[3], VU1.VF[i].f.z, VU1.VF[i].UL[2], VU1.VF[i].f.y, VU1.VF[i].UL[1], VU1.VF[i].f.x, VU1.VF[i].UL[0], disRNameCP2f[i]); \
} \ } \
#define dCP232x(i) { \ #define dCP232x(i) { \
if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \
else sprintf(ostr, "%s x=%f (%s),", ostr, VU1.VF[i].f.x, disRNameCP2f[i]); \ else sprintf(ostr, "%s x=%f (%s),", ostr, VU1.VF[i].f.x, disRNameCP2f[i]); \
} \ } \
#define dCP232y(i) { \ #define dCP232y(i) { \
if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \
else sprintf(ostr, "%s y=%f (%s),", ostr, VU1.VF[i].f.y, disRNameCP2f[i]); \ else sprintf(ostr, "%s y=%f (%s),", ostr, VU1.VF[i].f.y, disRNameCP2f[i]); \
} \ } \
#define dCP232z(i) { \ #define dCP232z(i) { \
if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \
else sprintf(ostr, "%s z=%f (%s),", ostr, VU1.VF[i].f.z, disRNameCP2f[i]); \ else sprintf(ostr, "%s z=%f (%s),", ostr, VU1.VF[i].f.z, disRNameCP2f[i]); \
} }
#define dCP232w(i) { \ #define dCP232w(i) { \
if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s %s,", ostr, disRNameCP2f[i]); \
else sprintf(ostr, "%s w=%f (%s),", ostr, VU1.VF[i].f.w, disRNameCP2f[i]); \ else sprintf(ostr, "%s w=%f (%s),", ostr, VU1.VF[i].f.w, disRNameCP2f[i]); \
} }
#define dCP2ACCf() { \ #define dCP2ACCf() { \
if( CHECK_VU1REC ) sprintf(ostr, "%s ACC,", ostr); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s ACC,", ostr); \
else sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU1.ACC.f.w, VU1.ACC.f.z, VU1.ACC.f.y, VU1.ACC.f.x); \ else sprintf(ostr, "%s w=%f z=%f y=%f x=%f (ACC),", ostr, VU1.ACC.f.w, VU1.ACC.f.z, VU1.ACC.f.y, VU1.ACC.f.x); \
} \ } \
#define dCP232i(i) { \ #define dCP232i(i) { \
if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \
else sprintf(ostr, "%s %8.8x (%s),", ostr, VU1.VI[i].UL, disRNameCP2i[i]); \ else sprintf(ostr, "%s %8.8x (%s),", ostr, VU1.VI[i].UL, disRNameCP2i[i]); \
} }
#define dCP232iF(i) { \ #define dCP232iF(i) { \
if( CHECK_VU1REC ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s %s,", ostr, disRNameCP2i[i]); \
else sprintf(ostr, "%s %f (%s),", ostr, VU1.VI[i].F, disRNameCP2i[i]); \ else sprintf(ostr, "%s %f (%s),", ostr, VU1.VI[i].F, disRNameCP2i[i]); \
} }
#define dCP232f(i, j) { \ #define dCP232f(i, j) { \
if( CHECK_VU1REC ) sprintf(ostr, "%s %s%s,", ostr, disRNameCP2f[i], CP2VFnames[j]); \ if( !CpuVU1.IsInterpreter ) sprintf(ostr, "%s %s%s,", ostr, disRNameCP2f[i], CP2VFnames[j]); \
else sprintf(ostr, "%s %s=%f (%s),", ostr, CP2VFnames[j], VU1.VF[i].F[j], disRNameCP2f[i]); \ else sprintf(ostr, "%s %s=%f (%s),", ostr, CP2VFnames[j], VU1.VF[i].F[j], disRNameCP2f[i]); \
} }

View File

@ -30,42 +30,9 @@ u32 CSRw;
__aligned16 u8 g_RealGSMem[0x2000]; __aligned16 u8 g_RealGSMem[0x2000];
extern int m_nCounters[]; extern int m_nCounters[];
// FrameSkipping Stuff void gsOnModeChanged( Fixed100 framerate, u32 newTickrate )
// Yuck, iSlowStart is needed by the MTGS, so can't make it static yet.
u64 m_iSlowStart=0;
static s64 m_iSlowTicks=0;
static bool m_justSkipped = false;
static bool m_StrictSkipping = false;
void _gs_ChangeTimings( u32 framerate, u32 iTicks )
{ {
m_iSlowStart = GetCPUTicks(); GetMTGS().SendSimplePacket( GS_RINGTYPE_MODECHANGE, framerate.Raw, newTickrate, 0 );
u32 frameSkipThreshold = EmuConfig.Video.FpsSkip*50;
if( frameSkipThreshold == 0)
{
// default: load the frameSkipThreshold with a value roughly 90% of the PS2 native framerate
frameSkipThreshold = ( framerate * 242 ) / 256;
}
m_iSlowTicks = ( GetTickFrequency() * 50 ) / frameSkipThreshold;
// sanity check against users who set a "minimum" frame that's higher
// than the maximum framerate. Also, if framerates are within 1/3300th
// of a second of each other, assume strict skipping (it's too close,
// and could cause excessive skipping).
if( m_iSlowTicks <= (iTicks + ((s64)GetTickFrequency()/3300)) )
{
m_iSlowTicks = iTicks;
m_StrictSkipping = true;
}
}
void gsOnModeChanged( u32 framerate, u32 newTickrate )
{
GetMTGS().SendSimplePacket( GS_RINGTYPE_MODECHANGE, framerate, newTickrate, 0 );
} }
static bool gsIsInterlaced = false; static bool gsIsInterlaced = false;
@ -77,7 +44,6 @@ void gsSetRegionMode( GS_RegionMode region )
if( gsRegionMode == region ) return; if( gsRegionMode == region ) return;
gsRegionMode = region; gsRegionMode = region;
Console.WriteLn( "%s Display Mode Initialized.", (( gsRegionMode == Region_PAL ) ? "PAL" : "NTSC") );
UpdateVSyncRate(); UpdateVSyncRate();
} }
@ -92,10 +58,7 @@ void gsReset()
{ {
GetMTGS().ResetGS(); GetMTGS().ResetGS();
gsOnModeChanged( UpdateVSyncRate();
(gsRegionMode == Region_NTSC) ? FRAMERATE_NTSC : FRAMERATE_PAL,
UpdateVSyncRate()
);
memzero(g_RealGSMem); memzero(g_RealGSMem);
@ -353,161 +316,60 @@ void gsIrq() {
hwIntcIrq(INTC_GS); hwIntcIrq(INTC_GS);
} }
void gsSyncLimiterLostTime( s32 deltaTime ) // --------------------------------------------------------------------------------------
// gsFrameSkip
// --------------------------------------------------------------------------------------
// This function regulates the frameskipping status of the GS. Our new frameskipper for
// 0.9.7 is a very simple logic pattern compared to the old mess. The goal now is to provide
// the most compatible and efficient frameskip, instead of doing the adaptive logic of
// 0.9.6. This is almost a necessity because of how many games treat the GS: they upload
// great amounts of data while rendering 2 frames at a time (using double buffering), and
// then use a simple pageswap to display the contents of the second frame for that vsync.
// (this approach is mostly seen on interlace games; progressive games less so)
// The result is that any skip pattern besides a fully consistent 2on,2off would reuslt in
// tons of missing geometry, rendering frameskip useless.
//
// So instead we use a simple "always skipping" or "never skipping" logic.
//
// EE vs MTGS:
// This function does not regulate frame limiting, meaning it does no stalling. Stalling
// functions are performed by the EE, which itself uses thread sleep logic to avoid spin
// waiting as much as possible (maximizes CPU resource availability for the GS).
__forceinline void gsFrameSkip()
{ {
// This sync issue applies only to configs that are trying to maintain if( !EmuConfig.GS.FrameSkipEnable ) return;
// a perfect "specific" framerate (where both min and max fps are the same)
// any other config will eventually equalize out.
if( !m_StrictSkipping ) return; static int consec_skipped = 0;
static int consec_drawn = 0;
static bool isSkipping = false;
GSsetFrameSkip( isSkipping );
//Console.WriteLn("LostTime on the EE!"); if( isSkipping )
GetMTGS().SendSimplePacket(
GS_RINGTYPE_STARTTIME,
deltaTime,
0,
0
);
}
/////////////////////////////////////////////////////////////////////////////////////////
// FrameSkipper - Measures delta time between calls and issues frameskips
// it the time is too long. Also regulates the status of the EE's framelimiter.
// This function does not regulate frame limiting, meaning it does no stalling.
// Stalling functions are performed by the EE: If the MTGS were throtted and not
// the EE, the EE would fill the ringbuffer while the MTGS regulated frames --
// fine for most situations but could result in literally dozens of frames queued
// up in the ringbuffer durimg some game menu screens; which in turn would result
// in a half-second lag of keystroke actions becoming visible to the user (bad!).
// Alternative: Instead of this, I could have everything regulated here, and then
// put a framecount limit on the MTGS ringbuffer. But that seems no less complicated
// and would also mean that aforementioned menus would still be laggy by whatever
// frame count threshold. This method is more responsive.
__forceinline void gsFrameSkip( bool forceskip )
{
static u8 FramesToRender = 0;
static u8 FramesToSkip = 0;
if( !EmuConfig.Video.EnableFrameSkipping ) return;
// FrameSkip and VU-Skip Magic!
// Skips a sequence of consecutive frames after a sequence of rendered frames
// This is the least number of consecutive frames we will render w/o skipping
const int noSkipFrames = ((EmuConfig.Video.ConsecutiveFrames>0) ? EmuConfig.Video.ConsecutiveFrames : 1);
// This is the number of consecutive frames we will skip
const int yesSkipFrames = ((EmuConfig.Video.ConsecutiveSkip>0) ? EmuConfig.Video.ConsecutiveSkip : 1);
const u64 iEnd = GetCPUTicks();
const s64 uSlowExpectedEnd = m_iSlowStart + m_iSlowTicks;
const s64 sSlowDeltaTime = iEnd - uSlowExpectedEnd;
m_iSlowStart = uSlowExpectedEnd;
if( forceskip )
{ {
if( !FramesToSkip ) ++consec_skipped;
if( consec_skipped >= EmuConfig.GS.ConsecutiveSkip )
{ {
//Console.Status( "- Skipping some VUs!" ); consec_skipped = 0;
isSkipping = false;
GSsetFrameSkip( 1 );
FramesToRender = noSkipFrames;
FramesToSkip = 1; // just set to 1
// We're already skipping, so FramesToSkip==1 will just restore the gsFrameSkip
// setting and reset our delta times as needed.
} }
return;
} }
else
if( FramesToRender == 0 )
{ {
// -- Standard operation section -- ++consec_drawn;
// Means neither skipping frames nor force-rendering consecutive frames. if( consec_drawn >= EmuConfig.GS.ConsecutiveFrames )
if( sSlowDeltaTime > 0 )
{ {
// The game is running below the minimum framerate. consec_drawn = 0;
// But don't start skipping yet! That would be too sensitive. isSkipping = true;
// So the skipping code is only engaged if the SlowDeltaTime falls behind by
// a full frame, or if we're already skipping (in which case we don't care
// to avoid errant skips).
// Note: The MTGS can go out of phase from the EE, which means that the
// variance for a "nominal" framerate can range from 0 to m_iSlowTicks.
// We also check for that here.
if( (m_justSkipped && (sSlowDeltaTime > m_iSlowTicks)) ||
(sSlowDeltaTime > m_iSlowTicks*2) )
{
GSsetFrameSkip(1);
FramesToRender = noSkipFrames+1;
FramesToSkip = yesSkipFrames;
}
} }
else
{
// Running at or above full speed, so reset the StartTime since the Limiter
// will muck things up. (special case: if skip and limit fps are equal then
// we don't reset starttime since it would cause desyncing. We let the EE
// regulate it via calls to gsSyncLimiterStartTime).
if( !m_StrictSkipping )
m_iSlowStart = iEnd;
}
m_justSkipped = false;
return;
}
else if( FramesToSkip > 0 )
{
// -- Frames-a-Skippin' Section --
FramesToSkip--;
if( FramesToSkip == 0 )
{
// Skipped our last frame, so restore non-skip behavior
GSsetFrameSkip(0);
// Note: If we lag behind by 250ms then it's time to give up on the idea
// of catching up. Force the game to slow down by resetting iStart to
// something closer to iEnd.
if( sSlowDeltaTime > (m_iSlowTicks + ((s64)GetTickFrequency() / 4)) )
{
//Console.Status( "Frameskip couldn't skip enough -- had to lose some time!" );
m_iSlowStart = iEnd - m_iSlowTicks;
}
m_justSkipped = true;
}
else
return;
}
//Console.WriteLn( "Consecutive Frames -- Lateness: %d", (int)( sSlowDeltaTime / m_iSlowTicks ) );
// -- Consecutive frames section --
// Force-render consecutive frames without skipping.
FramesToRender--;
if( sSlowDeltaTime < 0 )
{
m_iSlowStart = iEnd;
} }
} }
// updategs - if FALSE the gs will skip the frame. void gsPostVsyncEnd()
void gsPostVsyncEnd( bool updategs )
{ {
*(u32*)(PS2MEM_GS+0x1000) ^= 0x2000; // swap the vsync field *(u32*)(PS2MEM_GS+0x1000) ^= 0x2000; // swap the vsync field
GetMTGS().PostVsyncEnd( updategs ); GetMTGS().PostVsyncEnd();
} }
void _gs_ResetFrameskip() void _gs_ResetFrameskip()
@ -521,15 +383,6 @@ void gsResetFrameSkip()
GetMTGS().SendSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0); GetMTGS().SendSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0);
} }
void gsDynamicSkipEnable()
{
if( !m_StrictSkipping ) return;
GetMTGS().WaitGS();
m_iSlowStart = GetCPUTicks();
frameLimitReset();
}
void SaveStateBase::gsFreeze() void SaveStateBase::gsFreeze()
{ {
FreezeMem(PS2MEM_GS, 0x2000); FreezeMem(PS2MEM_GS, 0x2000);

View File

@ -74,7 +74,6 @@ enum MTGS_RingCommand
, GS_RINGTYPE_WRITECSR , GS_RINGTYPE_WRITECSR
, GS_RINGTYPE_MODECHANGE // for issued mode changes. , GS_RINGTYPE_MODECHANGE // for issued mode changes.
, GS_RINGTYPE_CRC , GS_RINGTYPE_CRC
, GS_RINGTYPE_STARTTIME // special case for min==max fps frameskip settings
}; };
@ -151,7 +150,7 @@ public:
u8* GetDataPacketPtr() const; u8* GetDataPacketPtr() const;
void SetEvent(); void SetEvent();
void PostVsyncEnd( bool updategs ); void PostVsyncEnd();
protected: protected:
void OpenPlugin(); void OpenPlugin();
@ -171,10 +170,10 @@ protected:
void ExecuteTaskInThread(); void ExecuteTaskInThread();
}; };
// GetMtgsThread() is a required external implementation. This function is *NOT* // GetMTGS() is a required external implementation. This function is *NOT* provided
// provided by the PCSX2 core library. It provides an interface for the linking User // by the PCSX2 core library. It provides an interface for the linking User Interface
// Interface apps or DLLs to reference their own instance of SysMtgsThread (also allowing // apps or DLLs to reference their own instance of SysMtgsThread (also allowing them
// them to extend the class and override virtual methods). // to extend the class and override virtual methods).
// //
SysMtgsThread& GetMTGS(); SysMtgsThread& GetMTGS();
@ -185,17 +184,14 @@ extern void gsInit();
extern s32 gsOpen(); extern s32 gsOpen();
extern void gsClose(); extern void gsClose();
extern void gsReset(); extern void gsReset();
extern void gsOnModeChanged( u32 framerate, u32 newTickrate ); extern void gsOnModeChanged( Fixed100 framerate, u32 newTickrate );
extern void gsSetRegionMode( GS_RegionMode isPal ); extern void gsSetRegionMode( GS_RegionMode isPal );
extern void gsResetFrameSkip(); extern void gsResetFrameSkip();
extern void gsSyncLimiterLostTime( s32 deltaTime ); extern void gsPostVsyncEnd();
extern void gsDynamicSkipEnable(); extern void gsFrameSkip();
extern void gsPostVsyncEnd( bool updategs );
extern void gsFrameSkip( bool forceskip );
// Some functions shared by both the GS and MTGS // Some functions shared by both the GS and MTGS
extern void _gs_ResetFrameskip(); extern void _gs_ResetFrameskip();
extern void _gs_ChangeTimings( u32 framerate, u32 iTicks );
// used for resetting GIF fifo // used for resetting GIF fifo
@ -222,7 +218,6 @@ extern u64 gsRead64(u32 mem);
void gsIrq(); void gsIrq();
extern u32 CSRw; extern u32 CSRw;
extern u64 m_iSlowStart;
// GS Playback // GS Playback
enum gsrun enum gsrun

View File

@ -148,9 +148,9 @@ void SysMtgsThread::ResetGS()
GIFPath_Reset(); GIFPath_Reset();
} }
void SysMtgsThread::PostVsyncEnd( bool updategs ) void SysMtgsThread::PostVsyncEnd()
{ {
SendSimplePacket( GS_RINGTYPE_VSYNC, (*(u32*)(PS2MEM_GS+0x1000)&0x2000), updategs, 0 ); SendSimplePacket( GS_RINGTYPE_VSYNC, (*(u32*)(PS2MEM_GS+0x1000)&0x2000), 0, 0 );
// Alter-frame flushing! Restarts the ringbuffer (wraps) on every other frame. This is a // Alter-frame flushing! Restarts the ringbuffer (wraps) on every other frame. This is a
// mandatory feature that prevents the MTGS from queuing more than 2 frames at any time. // mandatory feature that prevents the MTGS from queuing more than 2 frames at any time.
@ -198,6 +198,8 @@ void SysMtgsThread::OpenPlugin()
else else
result = GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 ); result = GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
GSsetVsync( EmuConfig.GS.FrameLimitEnable && EmuConfig.GS.VsyncEnable );
if( result != 0 ) if( result != 0 )
{ {
DevCon.WriteLn( "GSopen Failed: return code: 0x%x", result ); DevCon.WriteLn( "GSopen Failed: return code: 0x%x", result );
@ -352,7 +354,7 @@ void SysMtgsThread::ExecuteTaskInThread()
{ {
MTGS_LOG( "(MTGS Packet Read) ringtype=Vsync, field=%u, skip=%s", tag.data[0], tag.data[1] ? "true" : "false" ); MTGS_LOG( "(MTGS Packet Read) ringtype=Vsync, field=%u, skip=%s", tag.data[0], tag.data[1] ? "true" : "false" );
GSvsync(tag.data[0]); GSvsync(tag.data[0]);
gsFrameSkip( !tag.data[1] ); gsFrameSkip();
if( PADupdate != NULL ) if( PADupdate != NULL )
PADupdate(0); PADupdate(0);
@ -416,17 +418,13 @@ void SysMtgsThread::ExecuteTaskInThread()
break; break;
case GS_RINGTYPE_MODECHANGE: case GS_RINGTYPE_MODECHANGE:
_gs_ChangeTimings( tag.data[0], tag.data[1] ); // [TODO] some frameskip sync logic might be needed here!
break; break;
case GS_RINGTYPE_CRC: case GS_RINGTYPE_CRC:
GSsetGameCRC( tag.data[0], 0 ); GSsetGameCRC( tag.data[0], 0 );
break; break;
case GS_RINGTYPE_STARTTIME:
m_iSlowStart += tag.data[0];
break;
#ifdef PCSX2_DEVBUILD #ifdef PCSX2_DEVBUILD
default: default:
Console.Error("GSThreadProc, bad packet (%x) at m_RingPos: %x, m_WritePos: %x", tag.command, m_RingPos, m_WritePos); Console.Error("GSThreadProc, bad packet (%x) at m_RingPos: %x, m_WritePos: %x", tag.command, m_RingPos, m_WritePos);
@ -568,7 +566,7 @@ void SysMtgsThread::SendDataPacket()
m_WritePos = temp; m_WritePos = temp;
if( EmuConfig.Video.SynchronousMTGS ) if( EmuConfig.GS.SynchronousMTGS )
{ {
WaitGS(); WaitGS();
} }
@ -854,7 +852,7 @@ void SysMtgsThread::RestartRingbuffer( uint packsize )
m_WritePos = 0; m_WritePos = 0;
m_QueuedFrameCount = 0; m_QueuedFrameCount = 0;
if( EmuConfig.Video.SynchronousMTGS ) if( EmuConfig.GS.SynchronousMTGS )
WaitGS(); WaitGS();
} }
@ -918,7 +916,7 @@ __forceinline void SysMtgsThread::_FinishSimplePacket( uint future_writepos )
pxAssert( future_writepos != volatize(m_RingPos) ); pxAssert( future_writepos != volatize(m_RingPos) );
m_WritePos = future_writepos; m_WritePos = future_writepos;
if( EmuConfig.Video.SynchronousMTGS ) if( EmuConfig.GS.SynchronousMTGS )
WaitGS(); WaitGS();
else else
++m_CopyDataTally; ++m_CopyDataTally;

View File

@ -204,35 +204,38 @@ void Pcsx2Config::CpuOptions::LoadSave( IniInterface& ini )
Recompiler.LoadSave( ini ); Recompiler.LoadSave( ini );
} }
Pcsx2Config::VideoOptions::VideoOptions() Pcsx2Config::GSOptions::GSOptions()
{ {
EnableFrameLimiting = false; FrameLimitEnable = true;
EnableFrameSkipping = false; FrameSkipEnable = false;
SynchronousMTGS = false; SynchronousMTGS = false;
DefaultRegionMode = Region_NTSC; DefaultRegionMode = Region_NTSC;
FpsTurbo = 60*4;
FpsLimit = 60;
FpsSkip = 55;
ConsecutiveFrames = 2; ConsecutiveFrames = 2;
ConsecutiveSkip = 1; ConsecutiveSkip = 2;
LimitScalar = 1.0;
FramerateNTSC = 59.94;
FrameratePAL = 50.0;
} }
void Pcsx2Config::VideoOptions::LoadSave( IniInterface& ini ) void Pcsx2Config::GSOptions::LoadSave( IniInterface& ini )
{ {
VideoOptions defaults; GSOptions defaults;
IniScopedGroup path( ini, L"Video" ); IniScopedGroup path( ini, L"GS" );
IniEntry( EnableFrameLimiting ); IniEntry( FrameLimitEnable );
IniEntry( EnableFrameSkipping ); IniEntry( FrameSkipEnable );
IniEntry( VsyncEnable );
IniEntry( LimitScalar );
IniEntry( FramerateNTSC );
IniEntry( FrameratePAL );
static const wxChar * const ntsc_pal_str[2] = { L"ntsc", L"pal" }; static const wxChar * const ntsc_pal_str[2] = { L"ntsc", L"pal" };
ini.EnumEntry( L"DefaultRegionMode", DefaultRegionMode, ntsc_pal_str, defaults.DefaultRegionMode ); ini.EnumEntry( L"DefaultRegionMode", DefaultRegionMode, ntsc_pal_str, defaults.DefaultRegionMode );
IniEntry( FpsTurbo );
IniEntry( FpsLimit );
IniEntry( FpsSkip );
IniEntry( ConsecutiveFrames ); IniEntry( ConsecutiveFrames );
IniEntry( ConsecutiveSkip ); IniEntry( ConsecutiveSkip );
} }
@ -251,9 +254,9 @@ void Pcsx2Config::GamefixOptions::LoadSave( IniInterface& ini )
IniBitBool( XgKickHack ); IniBitBool( XgKickHack );
} }
Pcsx2Config::Pcsx2Config() : Pcsx2Config::Pcsx2Config()
bitset( 0 )
{ {
bitset = 0;
} }
void Pcsx2Config::LoadSave( IniInterface& ini ) void Pcsx2Config::LoadSave( IniInterface& ini )
@ -274,13 +277,14 @@ void Pcsx2Config::LoadSave( IniInterface& ini )
// Process various sub-components: // Process various sub-components:
Speedhacks.LoadSave( ini ); Speedhacks .LoadSave( ini );
Cpu.LoadSave( ini ); Cpu .LoadSave( ini );
Video.LoadSave( ini ); GS .LoadSave( ini );
Gamefixes.LoadSave( ini ); Gamefixes .LoadSave( ini );
Profiler.LoadSave( ini ); Profiler .LoadSave( ini );
Trace.LoadSave( ini ); Trace .LoadSave( ini );
Log .LoadSave( ini );
ini.Flush(); ini.Flush();
} }

View File

@ -146,6 +146,7 @@ _GSprintf GSprintf;
_GSsetBaseMem GSsetBaseMem; _GSsetBaseMem GSsetBaseMem;
_GSsetGameCRC GSsetGameCRC; _GSsetGameCRC GSsetGameCRC;
_GSsetFrameSkip GSsetFrameSkip; _GSsetFrameSkip GSsetFrameSkip;
_GSsetVsync GSsetVsync;
_GSsetupRecording GSsetupRecording; _GSsetupRecording GSsetupRecording;
_GSreset GSreset; _GSreset GSreset;
_GSwriteCSR GSwriteCSR; _GSwriteCSR GSwriteCSR;
@ -154,6 +155,8 @@ static void CALLBACK GS_makeSnapshot(const char *path) {}
static void CALLBACK GS_setGameCRC(u32 crc, int gameopts) {} static void CALLBACK GS_setGameCRC(u32 crc, int gameopts) {}
static void CALLBACK GS_irqCallback(void (*callback)()) {} static void CALLBACK GS_irqCallback(void (*callback)()) {}
static void CALLBACK GS_setFrameSkip(int frameskip) {} static void CALLBACK GS_setFrameSkip(int frameskip) {}
static void CALLBACK GS_setVsync(int enabled) {}
static void CALLBACK GS_setFullscreen(int enabled) {}
static void CALLBACK GS_changeSaveState( int, const char* filename ) {} static void CALLBACK GS_changeSaveState( int, const char* filename ) {}
static void CALLBACK GS_printf(int timeout, char *fmt, ...) static void CALLBACK GS_printf(int timeout, char *fmt, ...)
{ {
@ -283,6 +286,7 @@ static const LegacyApi_ReqMethod s_MethMessReq_GS[] =
{ "GSsetGameCRC", (vMeth**)&GSsetGameCRC, (vMeth*)GS_setGameCRC }, { "GSsetGameCRC", (vMeth**)&GSsetGameCRC, (vMeth*)GS_setGameCRC },
{ "GSsetFrameSkip", (vMeth**)&GSsetFrameSkip, (vMeth*)GS_setFrameSkip }, { "GSsetFrameSkip", (vMeth**)&GSsetFrameSkip, (vMeth*)GS_setFrameSkip },
{ "GSsetVsync", (vMeth**)&GSsetVsync, (vMeth*)GS_setVsync },
{ "GSchangeSaveState",(vMeth**)&GSchangeSaveState,(vMeth*)GS_changeSaveState }, { "GSchangeSaveState",(vMeth**)&GSchangeSaveState,(vMeth*)GS_changeSaveState },
{ NULL } { NULL }
}; };

View File

@ -80,6 +80,7 @@ typedef int BOOL;
#include "i18n.h" #include "i18n.h"
#include "Utilities/Assertions.h" #include "Utilities/Assertions.h"
#include "Utilities/FixedPointTypes.h"
#include "Utilities/wxBaseTools.h" #include "Utilities/wxBaseTools.h"
#include "Utilities/ScopedPtr.h" #include "Utilities/ScopedPtr.h"
#include "Utilities/Path.h" #include "Utilities/Path.h"

View File

@ -550,7 +550,7 @@ __forceinline void cpuTestHwInts() {
void cpuExecuteBios() void cpuExecuteBios()
{ {
// Set the video mode to user's default request: // Set the video mode to user's default request:
gsSetRegionMode( (GS_RegionMode)EmuConfig.Video.DefaultRegionMode ); gsSetRegionMode( (GS_RegionMode)EmuConfig.GS.DefaultRegionMode );
Console.WriteLn( "Executing Bios Stub..." ); Console.WriteLn( "Executing Bios Stub..." );

View File

@ -32,8 +32,29 @@ SrcType_PageFault Source_PageFault;
const Pcsx2Config EmuConfig; const Pcsx2Config EmuConfig;
// disable all session overrides by default... // Provides an accessor for quick modification of GS options. All GS options are allowed to be
SessionOverrideFlags g_Session = {false}; // changed "on the fly" by the *main/gui thread only*.
Pcsx2Config::GSOptions& SetGSConfig()
{
//DbgCon.WriteLn( "Direct modification of EmuConfig.GS detected" );
AllowFromMainThreadOnly();
return const_cast<Pcsx2Config::GSOptions&>(EmuConfig.GS);
}
ConsoleLogFilters& SetConsoleConfig()
{
//DbgCon.WriteLn( "Direct modification of EmuConfig.Log detected" );
AllowFromMainThreadOnly();
return const_cast<ConsoleLogFilters&>(EmuConfig.Log);
}
TraceLogFilters& SetTraceConfig()
{
//DbgCon.WriteLn( "Direct modification of EmuConfig.TraceLog detected" );
AllowFromMainThreadOnly();
return const_cast<TraceLogFilters&>(EmuConfig.Trace);
}
// This function should be called once during program execution. // This function should be called once during program execution.
void SysDetect() void SysDetect()
@ -146,23 +167,21 @@ SysCoreAllocations::SysCoreAllocations()
Console.WriteLn( "Allocating memory for recompilers..." ); Console.WriteLn( "Allocating memory for recompilers..." );
try try {
{
recCpu.Allocate(); recCpu.Allocate();
RecSuccess_EE = true; RecSuccess_EE = true;
} }
catch( Exception::BaseException& ex ) catch( Exception::RuntimeError& ex )
{ {
Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
recCpu.Shutdown(); recCpu.Shutdown();
} }
try try {
{
psxRec.Allocate(); psxRec.Allocate();
RecSuccess_IOP = true; RecSuccess_IOP = true;
} }
catch( Exception::BaseException& ex ) catch( Exception::RuntimeError& ex )
{ {
Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
psxRec.Shutdown(); psxRec.Shutdown();
@ -170,23 +189,21 @@ SysCoreAllocations::SysCoreAllocations()
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :( // hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
try try {
{
VU0micro::recAlloc(); VU0micro::recAlloc();
RecSuccess_VU0 = true; RecSuccess_VU0 = true;
} }
catch( Exception::BaseException& ex ) catch( Exception::RuntimeError& ex )
{ {
Console.Error( L"VU0 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); Console.Error( L"VU0 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
VU0micro::recShutdown(); VU0micro::recShutdown();
} }
try try {
{
VU1micro::recAlloc(); VU1micro::recAlloc();
RecSuccess_VU1 = true; RecSuccess_VU1 = true;
} }
catch( Exception::BaseException& ex ) catch( Exception::RuntimeError& ex )
{ {
Console.Error( L"VU1 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() ); Console.Error( L"VU1 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
VU1micro::recShutdown(); VU1micro::recShutdown();
@ -239,8 +256,8 @@ bool SysCoreAllocations::HadSomeFailures( const Pcsx2Config::RecompilerOptions&
// 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 SysClearExecutionCache() void SysClearExecutionCache()
{ {
Cpu = CHECK_EEREC ? &recCpu : &intCpu; Cpu = CHECK_EEREC ? &recCpu : &intCpu;
psxCpu = CHECK_IOPREC ? &psxRec : &psxInt; psxCpu = CHECK_IOPREC ? &psxRec : &psxInt;
Cpu->Reset(); Cpu->Reset();
psxCpu->Reset(); psxCpu->Reset();

View File

@ -53,6 +53,9 @@ protected:
void CleanupMess() throw(); void CleanupMess() throw();
}; };
// GetSysCoreAlloc - this function is not implemented by PCSX2 core -- it must be
// implemented by the provisioning interface.
extern SysCoreAllocations& GetSysCoreAlloc();
extern void SysDetect(); // Detects cpu type and fills cpuInfo structs. extern void SysDetect(); // Detects cpu type and fills cpuInfo structs.
extern void SysClearExecutionCache(); // clears recompiled execution caches! extern void SysClearExecutionCache(); // clears recompiled execution caches!

View File

@ -16,6 +16,7 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "Common.h" #include "Common.h"
#include "Counters.h"
#include "GS.h" #include "GS.h"
#include "Elfheader.h" #include "Elfheader.h"
#include "PageFaultSource.h" #include "PageFaultSource.h"
@ -40,6 +41,7 @@ SysCoreThread::SysCoreThread()
m_name = L"EE Core"; m_name = L"EE Core";
m_resetRecompilers = true; m_resetRecompilers = true;
m_resetProfilers = true; m_resetProfilers = true;
m_resetVsyncTimers = true;
m_resetVirtualMachine = true; m_resetVirtualMachine = true;
m_hasValidState = false; m_hasValidState = false;
} }
@ -106,6 +108,14 @@ ScopedCoreThreadSuspend::ScopedCoreThreadSuspend()
m_ResumeWhenDone = GetCoreThread().Suspend(); m_ResumeWhenDone = GetCoreThread().Suspend();
} }
ScopedCoreThreadSuspend::~ScopedCoreThreadSuspend() throw()
{
if( m_ResumeWhenDone )
{
Console.WriteLn( Color_Gray, "Scoped CoreThread suspend was not allowed to resume." );
}
}
// Resumes CoreThread execution, but *only* if it was in a running state when this object // Resumes CoreThread execution, but *only* if it was in a running state when this object
// was instanized. Subsequent calls to Resume() will be ignored. // was instanized. Subsequent calls to Resume() will be ignored.
void ScopedCoreThreadSuspend::Resume() void ScopedCoreThreadSuspend::Resume()
@ -115,14 +125,29 @@ void ScopedCoreThreadSuspend::Resume()
m_ResumeWhenDone = false; m_ResumeWhenDone = false;
} }
ScopedCoreThreadSuspend::~ScopedCoreThreadSuspend() throw() ScopedCoreThreadPause::ScopedCoreThreadPause()
{
m_ResumeWhenDone = GetCoreThread().Pause();
}
ScopedCoreThreadPause::~ScopedCoreThreadPause() throw()
{ {
if( m_ResumeWhenDone ) if( m_ResumeWhenDone )
{ {
Console.WriteLn( Color_Gray, "Scoped CoreThread suspend was not allowed to resume." ); Console.WriteLn( Color_Gray, "Scoped CoreThread pause was not allowed to resume." );
} }
} }
// Resumes CoreThread execution, but *only* if it was in a running state when this object
// was instanized. Subsequent calls to Resume() will be ignored.
void ScopedCoreThreadPause::Resume()
{
if( m_ResumeWhenDone )
GetCoreThread().Resume();
m_ResumeWhenDone = false;
}
// Applies a full suite of new settings, which will automatically facilitate the necessary // Applies a full suite of new settings, which will automatically facilitate the necessary
// resets of the core and components (including plugins, if needed). The scope of resetting // resets of the core and components (including plugins, if needed). The scope of resetting
// is determined by comparing the current settings against the new settings, so that only // is determined by comparing the current settings against the new settings, so that only
@ -131,12 +156,14 @@ void SysCoreThread::ApplySettings( const Pcsx2Config& src )
{ {
if( src == EmuConfig ) return; if( src == EmuConfig ) return;
ScopedCoreThreadSuspend suspend_core; ScopedCoreThreadPause sys_paused;
m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks ); m_resetRecompilers = ( src.Cpu != EmuConfig.Cpu ) || ( src.Gamefixes != EmuConfig.Gamefixes ) || ( src.Speedhacks != EmuConfig.Speedhacks );
m_resetProfilers = (src.Profiler != EmuConfig.Profiler ); m_resetProfilers = ( src.Profiler != EmuConfig.Profiler );
m_resetVsyncTimers = ( src.GS != EmuConfig.GS );
const_cast<Pcsx2Config&>(EmuConfig) = src; const_cast<Pcsx2Config&>(EmuConfig) = src;
sys_paused.Resume();
} }
void SysCoreThread::ChangeCdvdSource( CDVD_SourceType type ) void SysCoreThread::ChangeCdvdSource( CDVD_SourceType type )
@ -189,11 +216,7 @@ void SysCoreThread::CpuInitializeMess()
{ {
if( m_hasValidState ) return; if( m_hasValidState ) return;
// Some recompiler mess might be left over -- nuke it here: _reset_stuff_as_needed();
SysClearExecutionCache();
memBindConditionalHandlers();
m_resetRecompilers = false;
m_resetProfilers = false;
ScopedBool_ClearOnError sbcoe( m_hasValidState ); ScopedBool_ClearOnError sbcoe( m_hasValidState );
@ -238,13 +261,8 @@ void SysCoreThread::CpuInitializeMess()
sbcoe.Success(); sbcoe.Success();
} }
void SysCoreThread::StateCheckInThread() void SysCoreThread::_reset_stuff_as_needed()
{ {
GetMTGS().RethrowException();
_parent::StateCheckInThread();
if( !m_hasValidState )
throw Exception::RuntimeError( "Invalid emulation state detected; Virtual machine threads have been cancelled." );
if( m_resetRecompilers || m_resetProfilers ) if( m_resetRecompilers || m_resetProfilers )
{ {
SysClearExecutionCache(); SysClearExecutionCache();
@ -252,6 +270,23 @@ void SysCoreThread::StateCheckInThread()
m_resetRecompilers = false; m_resetRecompilers = false;
m_resetProfilers = false; m_resetProfilers = false;
} }
if( m_resetVsyncTimers )
{
UpdateVSyncRate();
frameLimitReset();
m_resetVsyncTimers = false;
}
}
void SysCoreThread::StateCheckInThread()
{
GetMTGS().RethrowException();
_parent::StateCheckInThread();
if( !m_hasValidState )
throw Exception::RuntimeError( "Invalid emulation state detected; Virtual machine threads have been cancelled." );
_reset_stuff_as_needed();
} }
void SysCoreThread::ExecuteTaskInThread() void SysCoreThread::ExecuteTaskInThread()

View File

@ -187,6 +187,7 @@ class SysCoreThread : public SysThreadBase
protected: protected:
bool m_resetRecompilers; bool m_resetRecompilers;
bool m_resetProfilers; bool m_resetProfilers;
bool m_resetVsyncTimers;
bool m_resetVirtualMachine; bool m_resetVirtualMachine;
bool m_hasValidState; bool m_hasValidState;
@ -223,6 +224,7 @@ public:
protected: protected:
void CpuInitializeMess(); void CpuInitializeMess();
void _reset_stuff_as_needed();
virtual void Start(); virtual void Start();
virtual void OnSuspendInThread(); virtual void OnSuspendInThread();
@ -252,8 +254,17 @@ struct ScopedCoreThreadSuspend
bool m_ResumeWhenDone; bool m_ResumeWhenDone;
ScopedCoreThreadSuspend(); ScopedCoreThreadSuspend();
void Resume();
virtual ~ScopedCoreThreadSuspend() throw(); virtual ~ScopedCoreThreadSuspend() throw();
virtual void Resume();
};
struct ScopedCoreThreadPause
{
bool m_ResumeWhenDone;
ScopedCoreThreadPause();
virtual ~ScopedCoreThreadPause() throw();
virtual void Resume();
}; };
// GetCoreThread() is a required external implementation. This function is *NOT* // GetCoreThread() is a required external implementation. This function is *NOT*

View File

@ -240,4 +240,6 @@ const VUmicroCpu intVU0 =
, intStep , intStep
, intExecuteBlock , intExecuteBlock
, intClear , intClear
, true
}; };

View File

@ -225,4 +225,6 @@ const VUmicroCpu intVU1 =
, intStep , intStep
, intExecuteBlock , intExecuteBlock
, intClear , intClear
, true
}; };

View File

@ -23,6 +23,10 @@ struct VUmicroCpu
void (*Step)(); void (*Step)();
void (*ExecuteBlock)(); // VUs should support block-level execution only. void (*ExecuteBlock)(); // VUs should support block-level execution only.
void (__fastcall *Clear)(u32 Addr, u32 Size); void (__fastcall *Clear)(u32 Addr, u32 Size);
// this boolean indicates to some generic logging facilities if the VU's registers
// are valid for logging or not. (see DisVU1Micro.cpp, etc)
bool IsInterpreter;
}; };
extern VUmicroCpu CpuVU0; extern VUmicroCpu CpuVU0;

View File

@ -42,15 +42,7 @@ static const uint m_vuMemSize =
0x1000 + // VU0micro memory 0x1000 + // VU0micro memory
0x4000+0x800 + // VU0 memory and VU1 registers 0x4000+0x800 + // VU0 memory and VU1 registers
0x4000 + // VU1 memory 0x4000 + // VU1 memory
0x4000;/* + // VU1micro memory 0x4000;
0x4000; */ // HACKFIX (see below)
// HACKFIX! (air)
// The VIFdma1 has a nasty habit of transferring data into the 4k page of memory above
// the VU1. (oops!!) This happens to be recLUT most of the time, which causes rapid death
// of our emulator. So we allocate some extra space here to keep VIF1 a little happier.
// fixme - When the VIF is fixed, remove the third +0x4000 above. :)
void vuMicroMemAlloc() void vuMicroMemAlloc()
{ {

View File

@ -399,14 +399,19 @@ void AppConfig::LoadSave( IniInterface& ini )
LoadSaveMemcards( ini ); LoadSaveMemcards( ini );
// Process various sub-components: // Process various sub-components:
ProgLogBox.LoadSave( ini, L"ProgramLog" ); ProgLogBox .LoadSave( ini, L"ProgramLog" );
Ps2ConBox.LoadSave( ini, L"Ps2Console" ); Ps2ConBox .LoadSave( ini, L"Ps2Console" );
Folders.LoadSave( ini ); Folders .LoadSave( ini );
BaseFilenames.LoadSave( ini ); BaseFilenames .LoadSave( ini );
GSWindow .LoadSave( ini );
// Load Emulation options and apply some defaults overtop saved items, which are regulated
// by the PCSX2 UI.
EmuOptions.LoadSave( ini ); EmuOptions.LoadSave( ini );
GSWindow.LoadSave( ini ); if( ini.IsLoading() )
EmuOptions.GS.LimitScalar = GSWindow.NominalScalar;
ini.Flush(); ini.Flush();
} }
@ -444,18 +449,18 @@ void AppConfig::FolderOptions::ApplyDefaults()
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
AppConfig::FolderOptions::FolderOptions() : AppConfig::FolderOptions::FolderOptions()
bitset( 0xffffffff ) : Plugins ( PathDefs::GetPlugins() )
, Plugins ( PathDefs::GetPlugins() ) , Bios ( PathDefs::GetBios() )
, Bios ( PathDefs::GetBios() ) , Snapshots ( PathDefs::GetSnapshots() )
, Snapshots ( PathDefs::GetSnapshots() ) , Savestates ( PathDefs::GetSavestates() )
, Savestates ( PathDefs::GetSavestates() ) , MemoryCards ( PathDefs::GetMemoryCards() )
, MemoryCards ( PathDefs::GetMemoryCards() ) , Logs ( PathDefs::GetLogs() )
, Logs ( PathDefs::GetLogs() )
, RunIso( PathDefs::GetDocuments() ) // raw default is always the Documents folder. , RunIso( PathDefs::GetDocuments() ) // raw default is always the Documents folder.
, RunELF( PathDefs::GetDocuments() ) // raw default is always the Documents folder. , RunELF( PathDefs::GetDocuments() ) // raw default is always the Documents folder.
{ {
bitset = 0xffffffff;
} }
void AppConfig::FolderOptions::LoadSave( IniInterface& ini ) void AppConfig::FolderOptions::LoadSave( IniInterface& ini )
@ -518,8 +523,12 @@ void AppConfig::FilenameOptions::LoadSave( IniInterface& ini )
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
AppConfig::GSOptions::GSOptions() AppConfig::GSWindowOptions::GSWindowOptions()
{ {
NominalScalar = 1.0;
TurboScalar = 3.0;
SlomoScalar = 0.33;
CloseOnEsc = true; CloseOnEsc = true;
DefaultToFullscreen = false; DefaultToFullscreen = false;
AlwaysHideMouse = false; AlwaysHideMouse = false;
@ -532,10 +541,14 @@ AppConfig::GSOptions::GSOptions()
IsMaximized = false; IsMaximized = false;
} }
void AppConfig::GSOptions::SanityCheck() void AppConfig::GSWindowOptions::SanityCheck()
{ {
// Ensure Conformation of various options... // Ensure Conformation of various options...
NominalScalar .ConfineTo( 0.05, 10.0 );
TurboScalar .ConfineTo( 0.05, 10.0 );
SlomoScalar .ConfineTo( 0.05, 10.0 );
WindowSize.x = std::max( WindowSize.x, 8 ); WindowSize.x = std::max( WindowSize.x, 8 );
WindowSize.x = std::min( WindowSize.x, wxGetDisplayArea().GetWidth()-16 ); WindowSize.x = std::min( WindowSize.x, wxGetDisplayArea().GetWidth()-16 );
@ -550,12 +563,15 @@ void AppConfig::GSOptions::SanityCheck()
AspectRatio = AspectRatio_4_3; AspectRatio = AspectRatio_4_3;
} }
void AppConfig::GSOptions::LoadSave( IniInterface& ini ) void AppConfig::GSWindowOptions::LoadSave( IniInterface& ini )
{ {
IniScopedGroup path( ini, L"GSWindow" ); IniScopedGroup path( ini, L"GSWindow" );
GSWindowOptions defaults;
GSOptions defaults;
IniEntry( NominalScalar );
IniEntry( TurboScalar );
IniEntry( SlomoScalar );
IniEntry( CloseOnEsc ); IniEntry( CloseOnEsc );
IniEntry( DefaultToFullscreen ); IniEntry( DefaultToFullscreen );
IniEntry( AlwaysHideMouse ); IniEntry( AlwaysHideMouse );
@ -573,7 +589,7 @@ void AppConfig::GSOptions::LoadSave( IniInterface& ini )
ini.EnumEntry( L"AspectRatio", AspectRatio, AspectRatioNames, defaults.AspectRatio ); ini.EnumEntry( L"AspectRatio", AspectRatio, AspectRatioNames, defaults.AspectRatio );
DisableResizeBorders = false; if( ini.IsLoading() ) SanityCheck();
} }
wxFileConfig* OpenFileConfig( const wxString& filename ) wxFileConfig* OpenFileConfig( const wxString& filename )

View File

@ -120,7 +120,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// The GS window receives much love from the land of Options and Settings. // The GS window receives much love from the land of Options and Settings.
// //
struct GSOptions struct GSWindowOptions
{ {
// Closes the GS/Video port on escape (good for fullscreen activity) // Closes the GS/Video port on escape (good for fullscreen activity)
bool CloseOnEsc; bool CloseOnEsc;
@ -129,12 +129,16 @@ public:
bool DisableResizeBorders; bool DisableResizeBorders;
AspectRatioType AspectRatio; AspectRatioType AspectRatio;
wxSize WindowSize; wxSize WindowSize;
wxPoint WindowPos; wxPoint WindowPos;
bool IsMaximized; bool IsMaximized;
GSOptions(); Fixed100 NominalScalar;
Fixed100 TurboScalar;
Fixed100 SlomoScalar;
GSWindowOptions();
void LoadSave( IniInterface& conf ); void LoadSave( IniInterface& conf );
void SanityCheck(); void SanityCheck();
@ -183,7 +187,7 @@ public:
ConsoleLogOptions Ps2ConBox; ConsoleLogOptions Ps2ConBox;
FolderOptions Folders; FolderOptions Folders;
FilenameOptions BaseFilenames; FilenameOptions BaseFilenames;
GSOptions GSWindow; GSWindowOptions GSWindow;
// PCSX2-core emulation options, which are passed to the emu core prior to initiating // PCSX2-core emulation options, which are passed to the emu core prior to initiating
// an emulation session. Note these are the options saved into the GUI ini file and // an emulation session. Note these are the options saved into the GUI ini file and

View File

@ -192,9 +192,6 @@ void AppCoreThread::StateCheckInThread()
case WXK_MENU: m_kevt.m_altDown = isDown; return; case WXK_MENU: m_kevt.m_altDown = isDown; return;
} }
/*if( vkey != WXK_ALT )
Console.Warning( "It's not Alt!" );*/
m_kevt.m_keyCode = vkey; m_kevt.m_keyCode = vkey;
wxGetApp().PostPadKey( m_kevt ); wxGetApp().PostPadKey( m_kevt );
} }

View File

@ -306,25 +306,21 @@ bool Pcsx2App::OnInit()
if( !m_CoreAllocs->RecSuccess_EE ) if( !m_CoreAllocs->RecSuccess_EE )
{ {
message += L"\t* R5900 (EE)\n"; message += L"\t* R5900 (EE)\n";
g_Session.ForceDisableEErec = true;
} }
if( !m_CoreAllocs->RecSuccess_IOP ) if( !m_CoreAllocs->RecSuccess_IOP )
{ {
message += L"\t* R3000A (IOP)\n"; message += L"\t* R3000A (IOP)\n";
g_Session.ForceDisableIOPrec = true;
} }
if( !m_CoreAllocs->RecSuccess_VU0 ) if( !m_CoreAllocs->RecSuccess_VU0 )
{ {
message += L"\t* VU0\n"; message += L"\t* VU0\n";
g_Session.ForceDisableVU0rec = true;
} }
if( !m_CoreAllocs->RecSuccess_VU1 ) if( !m_CoreAllocs->RecSuccess_VU1 )
{ {
message += L"\t* VU1\n"; message += L"\t* VU1\n";
g_Session.ForceDisableVU1rec = true;
} }
message += pxE( ".Popup Error:EmuCore:MemoryForRecs", message += pxE( ".Popup Error:EmuCore:MemoryForRecs",

View File

@ -435,17 +435,18 @@ void AppApplySettings( const AppConfig* oldconf )
int toSend = 0; int toSend = 0;
sApp.Source_SettingsApplied().Dispatch( toSend ); sApp.Source_SettingsApplied().Dispatch( toSend );
suspend_core.Resume();
} }
static wxFileConfig _dud_config; static wxFileConfig _dud_config;
AppIniSaver::AppIniSaver() : AppIniSaver::AppIniSaver()
IniSaver( (GetAppConfig() != NULL) ? *GetAppConfig() : _dud_config ) : IniSaver( (GetAppConfig() != NULL) ? *GetAppConfig() : _dud_config )
{ {
} }
AppIniLoader::AppIniLoader() : AppIniLoader::AppIniLoader()
IniLoader( (GetAppConfig() != NULL) ? *GetAppConfig() : _dud_config ) : IniLoader( (GetAppConfig() != NULL) ? *GetAppConfig() : _dud_config )
{ {
} }
@ -656,3 +657,8 @@ SysMtgsThread& GetMTGS()
{ {
return mtgsThread; return mtgsThread;
} }
SysCoreAllocations& GetSysCoreAlloc()
{
return *wxGetApp().m_CoreAllocs;
}

View File

@ -48,13 +48,14 @@ GSPanel::GSPanel( wxWindow* parent )
: wxWindow() : wxWindow()
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) ) , m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
, m_HideMouseTimer( this ) , m_HideMouseTimer( this )
{ {
m_CursorShown = true; m_CursorShown = true;
if ( !wxWindow::Create(parent, wxID_ANY) ) if ( !wxWindow::Create(parent, wxID_ANY) )
throw Exception::RuntimeError( "GSPanel constructor esplode!!" ); throw Exception::RuntimeError( "GSPanel constructor esplode!!" );
SetName( L"GSPanel" );
InitDefaultAccelerators(); InitDefaultAccelerators();
if( g_Conf->GSWindow.AlwaysHideMouse ) if( g_Conf->GSWindow.AlwaysHideMouse )
@ -115,7 +116,7 @@ void GSPanel::DoResize()
if( client.x/16 <= client.y/9 ) if( client.x/16 <= client.y/9 )
viewport.y = (int)(client.x * (9.0/16.0)); viewport.y = (int)(client.x * (9.0/16.0));
else else
viewport.x = (int)(client.y * (9.0/16.0)); viewport.x = (int)(client.y * (16.0/9.0));
break; break;
} }
@ -182,6 +183,10 @@ void __evt_fastcall GSPanel::OnSettingsApplied( void* obj, int& evt )
panel->DoShowMouse(); panel->DoShowMouse();
} }
// --------------------------------------------------------------------------------------
// GSFrame
// --------------------------------------------------------------------------------------
GSFrame::GSFrame(wxWindow* parent, const wxString& title) GSFrame::GSFrame(wxWindow* parent, const wxString& title)
: wxFrame(parent, wxID_ANY, title, : wxFrame(parent, wxID_ANY, title,
g_Conf->GSWindow.WindowPos, wxSize( 640, 480 ), g_Conf->GSWindow.WindowPos, wxSize( 640, 480 ),
@ -193,11 +198,12 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title)
SetClientSize( g_Conf->GSWindow.WindowSize ); SetClientSize( g_Conf->GSWindow.WindowSize );
m_gspanel = new GSPanel( this ); m_gspanel = new GSPanel( this );
//Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSFrame::OnCloseWindow) ); //Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSFrame::OnCloseWindow) );
Connect( wxEVT_MOVE, wxMoveEventHandler (GSFrame::OnMove) ); Connect( wxEVT_MOVE, wxMoveEventHandler (GSFrame::OnMove) );
Connect( wxEVT_SIZE, wxSizeEventHandler (GSFrame::OnResize) ); Connect( wxEVT_SIZE, wxSizeEventHandler (GSFrame::OnResize) );
Connect( wxEVT_ACTIVATE, wxActivateEventHandler (GSFrame::OnActivate) );
} }
GSFrame::~GSFrame() throw() GSFrame::~GSFrame() throw()
@ -210,6 +216,12 @@ wxWindow* GSFrame::GetViewport()
return m_gspanel; return m_gspanel;
} }
void GSFrame::OnActivate( wxActivateEvent& evt )
{
evt.Skip();
if( wxWindow* gsPanel = FindWindowByName(L"GSPanel") ) gsPanel->SetFocus();
}
void GSFrame::OnMove( wxMoveEvent& evt ) void GSFrame::OnMove( wxMoveEvent& evt )
{ {
// evt.GetPosition() returns the client area position, not the window frame position. // evt.GetPosition() returns the client area position, not the window frame position.
@ -227,7 +239,15 @@ void GSFrame::OnMove( wxMoveEvent& evt )
void GSFrame::OnResize( wxSizeEvent& evt ) void GSFrame::OnResize( wxSizeEvent& evt )
{ {
g_Conf->GSWindow.WindowSize = GetClientSize(); g_Conf->GSWindow.WindowSize = GetClientSize();
m_gspanel->DoResize();
if( GSPanel* gsPanel = (GSPanel*)FindWindowByName(L"GSPanel") )
{
gsPanel->DoResize();
gsPanel->SetFocus();
}
//wxPoint hudpos = wxPoint(-10,-10) + (GetClientSize() - m_hud->GetSize());
//m_hud->SetPosition( hudpos ); //+ GetScreenPosition() + GetClientAreaOrigin() );
// if we skip, the panel is auto-sized to fit our window anyway, which we do not want! // if we skip, the panel is auto-sized to fit our window anyway, which we do not want!
//evt.Skip(); //evt.Skip();

View File

@ -53,24 +53,87 @@ wxString KeyAcceleratorCode::ToString() const
).ToString(); ).ToString();
} }
int limitOn = false; enum LimiterModeType
{
Limit_Nominal,
Limit_Turbo,
Limit_Slomo,
};
static LimiterModeType g_LimiterMode = Limit_Nominal;
namespace Implementations namespace Implementations
{ {
void Frameskip_Toggle() void Frameskip_Toggle()
{ {
limitOn ^= 1; g_Conf->EmuOptions.GS.FrameSkipEnable = !g_Conf->EmuOptions.GS.FrameSkipEnable;
Console.WriteLn("Framelimit mode changed to %d", limitOn ? 1 : 0); SetGSConfig().FrameSkipEnable = g_Conf->EmuOptions.GS.FrameSkipEnable;
// FIXME : Reimplement framelimiting using new double-switch boolean system
if( EmuConfig.GS.FrameSkipEnable )
Console.WriteLn( "(FrameSkipping) Enabled : FrameDraws=%d, FrameSkips=%d", g_Conf->EmuOptions.GS.ConsecutiveFrames, g_Conf->EmuOptions.GS.ConsecutiveSkip );
else
Console.WriteLn( "(FrameSkipping) Disabled." );
} }
void Framelimiter_TurboToggle() void Framelimiter_TurboToggle()
{ {
limitOn ^= 1; if( !g_Conf->EmuOptions.GS.FrameLimitEnable )
Console.WriteLn("Framelimit mode changed to %d", limitOn ? 1 : 0); {
Console.WriteLn( "(FrameLimiter) Turbo toggle ignored; framelimiter is currently disabled." );
return;
}
ScopedCoreThreadPause pauser;
if( g_LimiterMode == Limit_Turbo )
{
GSsetVsync( g_Conf->EmuOptions.GS.VsyncEnable );
g_LimiterMode = Limit_Nominal;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->GSWindow.NominalScalar;
Console.WriteLn("(FrameLimiter) Turbo DISABLED." );
}
else
{
GSsetVsync( false );
g_LimiterMode = Limit_Turbo;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->GSWindow.TurboScalar;
Console.WriteLn("(FrameLimiter) Turbo ENABLED." );
}
pauser.Resume();
}
void Framelimiter_SlomoToggle()
{
// Slow motion auto-enables the framelimiter even if it's disabled.
// This seems like desirable and expected behavior.
// FIXME: Inconsistent use of g_Conf->EmuOptions vs. EmuConfig. Should figure
// out a better consistency approach... -air
ScopedCoreThreadPause pauser;
GSsetVsync( g_Conf->EmuOptions.GS.VsyncEnable );
if( g_LimiterMode == Limit_Slomo )
{
g_LimiterMode = Limit_Nominal;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->GSWindow.NominalScalar;
Console.WriteLn("(FrameLimiter) SlowMotion DISABLED." );
}
else
{
g_LimiterMode = Limit_Slomo;
g_Conf->EmuOptions.GS.LimitScalar = g_Conf->GSWindow.SlomoScalar;
Console.WriteLn("(FrameLimiter) SlowMotion ENABLED." );
g_Conf->EmuOptions.GS.FrameLimitEnable = true;
}
pauser.Resume();
} }
void Framelimiter_MasterToggle() void Framelimiter_MasterToggle()
{ {
ScopedCoreThreadPause pauser;
g_Conf->EmuOptions.GS.FrameLimitEnable = !g_Conf->EmuOptions.GS.FrameLimitEnable;
GSsetVsync( g_Conf->EmuOptions.GS.FrameLimitEnable && g_Conf->EmuOptions.GS.VsyncEnable );
Console.WriteLn("(FrameLimiter) %s.", g_Conf->EmuOptions.GS.FrameLimitEnable ? "ENABLED" : "DISABLED" );
pauser.Resume();
} }
void Sys_Suspend() void Sys_Suspend()
@ -104,7 +167,7 @@ namespace Implementations
// FIXME: Some of the trace logs will require recompiler resets to be activated properly. // FIXME: Some of the trace logs will require recompiler resets to be activated properly.
// But since those haven't been implemented yet, no point in implementing that here either. // But since those haven't been implemented yet, no point in implementing that here either.
const_cast<Pcsx2Config&>(EmuConfig).Trace.Enabled = !EmuConfig.Trace.Enabled; SetTraceConfig().Enabled = !EmuConfig.Trace.Enabled;
GSprintf(10, const_cast<char*>(EmuConfig.Trace.Enabled ? "Logging Enabled." : "Logging Disabled.")); GSprintf(10, const_cast<char*>(EmuConfig.Trace.Enabled ? "Logging Enabled." : "Logging Disabled."));
} }
@ -209,6 +272,12 @@ static const GlobalCommandDescriptor CommandDeclarations[] =
NULL, NULL,
}, },
{ "Framelimiter_SlomoToggle",
Implementations::Framelimiter_TurboToggle,
NULL,
NULL,
},
{ "Framelimiter_MasterToggle", { "Framelimiter_MasterToggle",
Implementations::Framelimiter_MasterToggle, Implementations::Framelimiter_MasterToggle,
NULL, NULL,
@ -314,9 +383,10 @@ void Pcsx2App::InitDefaultGlobalAccelerators()
GlobalAccels.Map( AAC( WXK_F2 ), "States_CycleSlotForward" ); GlobalAccels.Map( AAC( WXK_F2 ), "States_CycleSlotForward" );
GlobalAccels.Map( AAC( WXK_F2 ).Shift(), "States_CycleSlotBackward" ); GlobalAccels.Map( AAC( WXK_F2 ).Shift(), "States_CycleSlotBackward" );
GlobalAccels.Map( AAC( WXK_F4 ), "Frameskip_Toggle"); GlobalAccels.Map( AAC( WXK_F4 ), "Framelimiter_MasterToggle");
GlobalAccels.Map( AAC( WXK_F4 ).Shift(), "Frameskip_Toggle");
GlobalAccels.Map( AAC( WXK_TAB ), "Framelimiter_TurboToggle" ); GlobalAccels.Map( AAC( WXK_TAB ), "Framelimiter_TurboToggle" );
GlobalAccels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_MasterToggle" ); GlobalAccels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_SlomoToggle" );
// Hack! The following bindings are temporary hacks which are needed because of issues // Hack! The following bindings are temporary hacks which are needed because of issues
// with PAD plugin interfacing (the local window-based accelerators in GSPanel are // with PAD plugin interfacing (the local window-based accelerators in GSPanel are

View File

@ -141,6 +141,16 @@ int IniLoader::EntryBitfield( const wxString& var, int value, const int defvalue
return result; return result;
} }
void IniLoader::Entry( const wxString& var, Fixed100& value, const Fixed100& defvalue )
{
// Note: the "easy" way would be to convert to double and load/save that, but floating point
// has way too much rounding error so we really need to do things out manually.. >_<
wxString readval( value.ToString() );
m_Config.Read( var, &readval );
value = Fixed100::FromString( readval, value );
}
void IniLoader::Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue ) void IniLoader::Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue )
{ {
TryParse( value, m_Config.Read( var, ToString( defvalue ) ), defvalue ); TryParse( value, m_Config.Read( var, ToString( defvalue ) ), defvalue );
@ -241,6 +251,14 @@ int IniSaver::EntryBitfield( const wxString& var, int value, const int defvalue
return value; return value;
} }
void IniSaver::Entry( const wxString& var, Fixed100& value, const Fixed100& defvalue )
{
// Note: the "easy" way would be to convert to double and load/save that, but floating point
// has way too much rounding error so we really need to do things out manually, using strings.
m_Config.Write( var, value.ToString() );
}
void IniSaver::Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue ) void IniSaver::Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue )
{ {
m_Config.Write( var, ToString( value ) ); m_Config.Write( var, ToString( value ) );

View File

@ -55,6 +55,8 @@ public:
virtual bool EntryBitBool( const wxString& var, bool value, const bool defvalue=false )=0; virtual bool EntryBitBool( const wxString& var, bool value, const bool defvalue=false )=0;
virtual int EntryBitfield( const wxString& var, int value, const int defvalue=0 )=0; virtual int EntryBitfield( const wxString& var, int value, const int defvalue=0 )=0;
virtual void Entry( const wxString& var, Fixed100& value, const Fixed100& defvalue=Fixed100() )=0;
virtual void Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue=wxDefaultPosition )=0; virtual void Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue=wxDefaultPosition )=0;
virtual void Entry( const wxString& var, wxSize& value, const wxSize& defvalue=wxDefaultSize )=0; virtual void Entry( const wxString& var, wxSize& value, const wxSize& defvalue=wxDefaultSize )=0;
virtual void Entry( const wxString& var, wxRect& value, const wxRect& defvalue=wxDefaultRect )=0; virtual void Entry( const wxString& var, wxRect& value, const wxRect& defvalue=wxDefaultRect )=0;
@ -113,6 +115,8 @@ public:
bool EntryBitBool( const wxString& var, bool value, const bool defvalue=false ); bool EntryBitBool( const wxString& var, bool value, const bool defvalue=false );
int EntryBitfield( const wxString& var, int value, const int defvalue=0 ); int EntryBitfield( const wxString& var, int value, const int defvalue=0 );
void Entry( const wxString& var, Fixed100& value, const Fixed100& defvalue=Fixed100() );
void Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue=wxDefaultPosition ); void Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue=wxDefaultPosition );
void Entry( const wxString& var, wxSize& value, const wxSize& defvalue=wxDefaultSize ); void Entry( const wxString& var, wxSize& value, const wxSize& defvalue=wxDefaultSize );
void Entry( const wxString& var, wxRect& value, const wxRect& defvalue=wxDefaultRect ); void Entry( const wxString& var, wxRect& value, const wxRect& defvalue=wxDefaultRect );
@ -148,6 +152,8 @@ public:
bool EntryBitBool( const wxString& var, bool value, const bool defvalue=false ); bool EntryBitBool( const wxString& var, bool value, const bool defvalue=false );
int EntryBitfield( const wxString& var, int value, const int defvalue=0 ); int EntryBitfield( const wxString& var, int value, const int defvalue=0 );
void Entry( const wxString& var, Fixed100& value, const Fixed100& defvalue=Fixed100() );
void Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue=wxDefaultPosition ); void Entry( const wxString& var, wxPoint& value, const wxPoint& defvalue=wxDefaultPosition );
void Entry( const wxString& var, wxSize& value, const wxSize& defvalue=wxDefaultSize ); void Entry( const wxString& var, wxSize& value, const wxSize& defvalue=wxDefaultSize );
void Entry( const wxString& var, wxRect& value, const wxRect& defvalue=wxDefaultRect ); void Entry( const wxString& var, wxRect& value, const wxRect& defvalue=wxDefaultRect );

View File

@ -68,6 +68,7 @@ public:
protected: protected:
void OnMove( wxMoveEvent& evt ); void OnMove( wxMoveEvent& evt );
void OnResize( wxSizeEvent& evt ); void OnResize( wxSizeEvent& evt );
void OnActivate( wxActivateEvent& evt );
}; };
struct PluginMenuAddition struct PluginMenuAddition

View File

@ -260,17 +260,17 @@ Panels::VideoPanel::VideoPanel( wxWindow* parent ) :
*this += s_table | pxExpand; *this += s_table | pxExpand;
m_check_SynchronousGS->SetValue( g_Conf->EmuOptions.Video.SynchronousMTGS ); m_check_SynchronousGS->SetValue( g_Conf->EmuOptions.GS.SynchronousMTGS );
} }
void Panels::VideoPanel::Apply() void Panels::VideoPanel::Apply()
{ {
g_Conf->EmuOptions.Video.SynchronousMTGS = m_check_SynchronousGS->GetValue(); g_Conf->EmuOptions.GS.SynchronousMTGS = m_check_SynchronousGS->GetValue();
} }
void Panels::GSWindowSettingsPanel::OnSettingsChanged() void Panels::GSWindowSettingsPanel::OnSettingsChanged()
{ {
const AppConfig::GSOptions& conf( g_Conf->GSWindow ); const AppConfig::GSWindowOptions& conf( g_Conf->GSWindow );
m_check_CloseGS ->SetValue( conf.CloseOnEsc ); m_check_CloseGS ->SetValue( conf.CloseOnEsc );
m_check_Fullscreen ->SetValue( conf.DefaultToFullscreen ); m_check_Fullscreen ->SetValue( conf.DefaultToFullscreen );
@ -279,6 +279,8 @@ void Panels::GSWindowSettingsPanel::OnSettingsChanged()
m_combo_AspectRatio ->SetSelection( (int)conf.AspectRatio ); m_combo_AspectRatio ->SetSelection( (int)conf.AspectRatio );
m_check_VsyncEnable ->SetValue( g_Conf->EmuOptions.GS.VsyncEnable );
m_text_WindowWidth ->SetValue( wxsFormat( L"%d", conf.WindowSize.GetWidth() ) ); m_text_WindowWidth ->SetValue( wxsFormat( L"%d", conf.WindowSize.GetWidth() ) );
m_text_WindowHeight ->SetValue( wxsFormat( L"%d", conf.WindowSize.GetHeight() ) ); m_text_WindowHeight ->SetValue( wxsFormat( L"%d", conf.WindowSize.GetHeight() ) );
@ -286,14 +288,17 @@ void Panels::GSWindowSettingsPanel::OnSettingsChanged()
void Panels::GSWindowSettingsPanel::Apply() void Panels::GSWindowSettingsPanel::Apply()
{ {
AppConfig::GSOptions& gsopt( g_Conf->GSWindow ); AppConfig::GSWindowOptions& appconf( g_Conf->GSWindow );
Pcsx2Config::GSOptions& gsconf( g_Conf->EmuOptions.GS );
gsopt.CloseOnEsc = m_check_CloseGS ->GetValue();
gsopt.DefaultToFullscreen = m_check_Fullscreen->GetValue();
gsopt.AlwaysHideMouse = m_check_HideMouse ->GetValue();
gsopt.DisableResizeBorders = m_check_SizeLock ->GetValue();
gsopt.AspectRatio = (AspectRatioType)m_combo_AspectRatio->GetSelection(); appconf.CloseOnEsc = m_check_CloseGS ->GetValue();
appconf.DefaultToFullscreen = m_check_Fullscreen->GetValue();
appconf.AlwaysHideMouse = m_check_HideMouse ->GetValue();
appconf.DisableResizeBorders = m_check_SizeLock ->GetValue();
appconf.AspectRatio = (AspectRatioType)m_combo_AspectRatio->GetSelection();
gsconf.VsyncEnable = m_check_VsyncEnable->GetValue();
long xr, yr; long xr, yr;
@ -303,21 +308,43 @@ void Panels::GSWindowSettingsPanel::Apply()
_("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<") _("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<")
); );
gsopt.WindowSize.x = xr; appconf.WindowSize.x = xr;
gsopt.WindowSize.y = yr; appconf.WindowSize.y = yr;
} }
void Panels::FramelimiterPanel::OnSettingsChanged() void Panels::FramelimiterPanel::OnSettingsChanged()
{ {
const Pcsx2Config::VideoOptions& conf( g_Conf->EmuOptions.Video ); const AppConfig::GSWindowOptions& appconf( g_Conf->GSWindow );
const Pcsx2Config::GSOptions& gsconf( g_Conf->EmuOptions.GS );
// TODO : Apply options from config *to* checkboxes (once video config struct is implemented) m_check_LimiterDisable->SetValue( !gsconf.FrameLimitEnable );
m_spin_NominalPct ->SetValue( (appconf.NominalScalar * 100).ToIntRounded() );
m_spin_TurboPct ->SetValue( (appconf.TurboScalar * 100).ToIntRounded() );
m_spin_TurboPct ->SetValue( (appconf.SlomoScalar * 100).ToIntRounded() );
m_text_BaseNtsc ->SetValue( gsconf.FramerateNTSC.ToString() );
m_text_BasePal ->SetValue( gsconf.FrameratePAL.ToString() );
} }
void Panels::FramelimiterPanel::Apply() void Panels::FramelimiterPanel::Apply()
{ {
Pcsx2Config::VideoOptions& conf( g_Conf->EmuOptions.Video ); AppConfig::GSWindowOptions& appconf( g_Conf->GSWindow );
Pcsx2Config::GSOptions& gsconf( g_Conf->EmuOptions.GS );
// TODO : Apply options from checkboxes (once video config struct is is implemented) gsconf.FrameLimitEnable = !m_check_LimiterDisable->GetValue();
appconf.NominalScalar = m_spin_NominalPct ->GetValue();
appconf.TurboScalar = m_spin_TurboPct ->GetValue();
appconf.SlomoScalar = m_spin_SlomoPct ->GetValue();
double ntsc, pal;
if( !m_text_BaseNtsc->GetValue().ToDouble( &ntsc ) ||
!m_text_BasePal ->GetValue().ToDouble( &pal )
)
throw Exception::CannotApplySettings( this, wxLt("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics.") );
gsconf.FramerateNTSC = ntsc;
gsconf.FrameratePAL = pal;
} }

View File

@ -85,7 +85,7 @@ void pxLogTextCtrl::OnResize( wxSizeEvent& evt )
int fonty; int fonty;
GetTextExtent( L"blaH yeah", NULL, &fonty ); GetTextExtent( L"blaH yeah", NULL, &fonty );
m_win32_LinesPerPage = (ctrly / fonty) + 1; m_win32_LinesPerPage = (ctrly / fonty) + 1;
m_win32_LinesPerScroll = m_win32_LinesPerPage * 0.72; m_win32_LinesPerScroll = m_win32_LinesPerPage * 0.25;
#endif #endif
evt.Skip(); evt.Skip();

View File

@ -55,8 +55,10 @@ using namespace VU0micro;
const VUmicroCpu recVU0 = const VUmicroCpu recVU0 =
{ {
recReset recReset
, recStep , recStep
, recExecuteBlock , recExecuteBlock
, recClear , recClear
, false
}; };

View File

@ -297,4 +297,6 @@ const VUmicroCpu recVU1 =
, recStep , recStep
, recExecuteBlock , recExecuteBlock
, recClear , recClear
, false
}; };