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"
>
</File>
<File
RelativePath="..\..\include\Utilities\FixedPointTypes.h"
>
</File>
<File
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* _GSsetFrameSkip)(int frameskip);
typedef void (CALLBACK* _GSsetFrameLimit)(int limit);
typedef void (CALLBACK* _GSsetVsync)(int enabled);
typedef int (CALLBACK* _GSsetupRecording)(int, void*);
typedef void (CALLBACK* _GSreset)();
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);
// Worthless crap function that returns GS plugin specific data via some
// undocumented void* to a struct. If ant pad plugin actually relies on
// this info, it deserves to fail new nwer pcsx2s. -- air
// undocumented void* to a struct. If any pad plugin actually relies on
// this info, it deserves to fail new newer pcsx2s. -- air
//typedef void (CALLBACK* _GSgetDriverInfo)(GSdriverInfo *info);
// PAD
@ -673,17 +674,18 @@ extern _GSreadFIFO GSreadFIFO;
extern _GSreadFIFO2 GSreadFIFO2;
extern _GSchangeSaveState GSchangeSaveState;
extern _GSmakeSnapshot GSmakeSnapshot;
extern _GSmakeSnapshot GSmakeSnapshot;
extern _GSmakeSnapshot2 GSmakeSnapshot2;
extern _GSirqCallback GSirqCallback;
extern _GSprintf GSprintf;
extern _GSsetBaseMem GSsetBaseMem;
extern _GSsetGameCRC GSsetGameCRC;
extern _GSsetFrameSkip GSsetFrameSkip;
extern _GSsetFrameLimit GSsetFrameLimit;
extern _GSsetupRecording GSsetupRecording;
extern _GSreset GSreset;
extern _GSwriteCSR GSwriteCSR;
extern _GSirqCallback GSirqCallback;
extern _GSprintf GSprintf;
extern _GSsetBaseMem GSsetBaseMem;
extern _GSsetGameCRC GSsetGameCRC;
extern _GSsetFrameSkip GSsetFrameSkip;
extern _GSsetFrameLimit GSsetFrameLimit;
extern _GSsetVsync GSsetVsync;
extern _GSsetupRecording GSsetupRecording;
extern _GSreset GSreset;
extern _GSwriteCSR GSwriteCSR;
// PAD
extern _PADopen PADopen;

View File

@ -17,8 +17,12 @@
// Dependencies.h : Contains classes required by all Utilities headers.
//////////////////////////////////////////////////////////////////////////////////////////
// DeclareNoncopyableObject
// This should prove useful....
#define wxsFormat wxString::Format
// --------------------------------------------------------------------------------------
// DeclareNoncopyableObject
// --------------------------------------------------------------------------------------
// 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
// 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 <wx/string.h>
#include <wx/tokenzr.h>
#include <wx/gdicmn.h> // for wxPoint/wxRect stuff
@ -29,9 +28,6 @@ extern wxString fromAscii( const char* src );
// wxWidgets lacks one of its own...
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 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 PS2CLK = 294912000; //hz /* 294.912 mhz */
//#define PS2CLK 36864000 /* 294.912 mhz */
static const ConsoleColors ConColor_IOP = Color_Yellow;
static const ConsoleColors ConColor_EE = Color_Cyan;

View File

@ -258,6 +258,16 @@ struct ConsoleLogFilters
ConsoleLogFilters();
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
// style. Useful for debugging potential bugs in the MTGS pipeline.
bool SynchronousMTGS;
bool EnableFrameLimiting;
bool EnableFrameSkipping;
bool SynchronousMTGS;
bool FrameLimitEnable;
bool FrameSkipEnable;
bool VsyncEnable;
// 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
// 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 FpsLimit; // Limiting kicks in if fps goes beyond this line
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
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 );
bool operator ==( const VideoOptions& right ) const
bool operator ==( const GSOptions& right ) const
{
return
OpEqu( EnableFrameSkipping ) &&
OpEqu( EnableFrameLimiting ) &&
OpEqu( SynchronousMTGS ) &&
OpEqu( FrameSkipEnable ) &&
OpEqu( FrameLimitEnable ) &&
OpEqu( VsyncEnable ) &&
OpEqu( LimitScalar ) &&
OpEqu( FramerateNTSC ) &&
OpEqu( FrameratePAL ) &&
OpEqu( DefaultRegionMode ) &&
OpEqu( FpsTurbo ) &&
OpEqu( FpsLimit ) &&
OpEqu( FpsSkip ) &&
OpEqu( ConsecutiveFrames ) &&
OpEqu( ConsecutiveSkip );
}
bool operator !=( const VideoOptions& right ) const
bool operator !=( const GSOptions& right ) const
{
return !this->operator ==( right );
}
@ -475,15 +491,15 @@ struct Pcsx2Config
BITFIELD32()
bool
CdvdVerboseReads:1, // enables cdvd read activity verbosely dumped to the console
CdvdDumpBlocks:1, // enables cdvd block dumping
EnablePatches:1, // enables patch detection and application
CdvdVerboseReads :1, // enables cdvd read activity verbosely dumped to the console
CdvdDumpBlocks :1, // enables cdvd block dumping
EnablePatches :1, // enables patch detection and application
// 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
McdEnableEjection:1,
McdEnableEjection :1,
MultitapPort0_Enabled:1,
MultitapPort1_Enabled:1,
@ -492,7 +508,7 @@ struct Pcsx2Config
BITFIELD_END
CpuOptions Cpu;
VideoOptions Video;
GSOptions GS;
SpeedhackOptions Speedhacks;
GamefixOptions Gamefixes;
ProfilerOptions Profiler;
@ -517,10 +533,12 @@ struct Pcsx2Config
return
OpEqu( bitset ) &&
OpEqu( Cpu ) &&
OpEqu( Video ) &&
OpEqu( GS ) &&
OpEqu( Speedhacks ) &&
OpEqu( Gamefixes ) &&
OpEqu( Profiler ) &&
OpEqu( Log ) &&
OpEqu( Trace ) &&
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 SessionOverrideFlags g_Session;
Pcsx2Config::GSOptions& SetGSConfig();
ConsoleLogFilters& SetConsoleConfig();
TraceLogFilters& SetTraceConfig();
/////////////////////////////////////////////////////////////////////////////////////////
// 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_MICROVU0 (EmuConfig.Cpu.Recompiler.UseMicroVU0)
#define CHECK_MICROVU1 (EmuConfig.Cpu.Recompiler.UseMicroVU1)
#define CHECK_EEREC (!g_Session.ForceDisableEErec && EmuConfig.Cpu.Recompiler.EnableEE)
#define CHECK_IOPREC (!g_Session.ForceDisableIOPrec && EmuConfig.Cpu.Recompiler.EnableIOP)
#define CHECK_VU0REC (!g_Session.ForceDisableVU0rec && EmuConfig.Cpu.Recompiler.EnableVU0)
#define CHECK_VU1REC (!g_Session.ForceDisableVU1rec && EmuConfig.Cpu.Recompiler.EnableVU1)
#define CHECK_EEREC (EmuConfig.Cpu.Recompiler.EnableEE && GetSysCoreAlloc().RecSuccess_EE)
#define CHECK_IOPREC (EmuConfig.Cpu.Recompiler.EnableIOP && GetSysCoreAlloc().RecSuccess_IOP)
#define CHECK_VU0REC (EmuConfig.Cpu.Recompiler.EnableVU0 && GetSysCoreAlloc().RecSuccess_VU0)
#define CHECK_VU1REC (EmuConfig.Cpu.Recompiler.EnableVU1 && GetSysCoreAlloc().RecSuccess_VU1)
//------------ SPECIAL GAME FIXES!!! ---------------
#define NUM_OF_GAME_FIXES 7

View File

@ -160,7 +160,7 @@ static u64 m_iStart=0;
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 Blank; // time from vblank start to vblank end (cycles)
@ -174,34 +174,31 @@ struct vSyncTimingInfo
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
// depending on user-set speedhack options, and it can break float/double code
// (as in returning infinities and junk)
// I use fixed point math here to have strict control over rounding errors. --air
// NOTE: mgs3 likes a /4 vsync, but many games prefer /2. This seems to indicate a
// problem in the counters vsync gates somewhere.
u64 Frame = ((u64)PS2CLK * 1000000ULL) / framesPerSecond;
u64 HalfFrame = Frame / 2;
u64 Blank = HalfFrame / 2; // two blanks and renders per frame
u64 Render = HalfFrame - Blank; // so use the half-frame value for these...
u64 Frame = ((u64)PS2CLK * 1000000ULL) / (framesPerSecond*100).ToIntRounded();
u64 HalfFrame = Frame / 2;
u64 Blank = HalfFrame / 2; // two blanks and renders per frame
u64 Render = HalfFrame - Blank; // so use the half-frame value for these...
// 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
// like crap and totally screws audio synchronization and other things.
// (this appears to be what the real EE's timing crystal does anyway)
u64 Scanline = Frame / scansPerFrame;
u64 hBlank = Scanline / 2;
u64 hRender = Scanline - hBlank;
u64 Scanline = Frame / scansPerFrame;
u64 hBlank = Scanline / 2;
u64 hRender = Scanline - hBlank;
info->Framerate = framesPerSecond;
info->Render = (u32)(Render/10000);
info->Blank = (u32)(Blank/10000);
info->Framerate = framesPerSecond;
info->Render = (u32)(Render/10000);
info->Blank = (u32)(Blank/10000);
info->hRender = (u32)(hRender/10000);
info->hBlank = (u32)(hBlank/10000);
info->hRender = (u32)(hRender/10000);
info->hBlank = (u32)(hBlank/10000);
info->hScanlinesPerFrame = scansPerFrame;
// Apply rounding:
@ -226,53 +223,64 @@ static void vSyncInfoCalc( vSyncTimingInfo* info, u32 framesPerSecond, u32 scans
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
// interlaced modes. But I can't fathom how, since the refresh rate is a function of
// the television and all the docs I found on TVs made no indication that they ever
// run anything except their native refresh rate.
//#define VBLANK_NTSC ((Config.PsxType & 2) ? 59.94 : 59.82) //59.94 is more precise
//#define VBLANK_PAL ((Config.PsxType & 2) ? 50.00 : 49.76)
// Notice: (and I probably repeat this elsewhere, but it's worth repeating)
// The PS2's vsync timer is an *independent* crystal that is fixed to either 59.94 (NTSC)
// or 50.0 (PAL) Hz. It has *nothing* to do with real TV timings or the real vsync of
// 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
// that it does not actually measure Vblank/Vdraw zones accurately (which would be like
// 1/5 and 4/5 ratios).
Fixed100 framerate;
u32 scanlines;
bool isCustom;
if( gsRegionMode == Region_PAL )
{
if( vSyncInfo.Framerate != FRAMERATE_PAL )
vSyncInfoCalc( &vSyncInfo, FRAMERATE_PAL, SCANLINES_TOTAL_PAL );
isCustom = (EmuConfig.GS.FrameratePAL != 50.0);
framerate = EmuConfig.GS.FrameratePAL / 2;
scanlines = SCANLINES_TOTAL_PAL;
}
else
{
if( vSyncInfo.Framerate != FRAMERATE_NTSC )
vSyncInfoCalc( &vSyncInfo, FRAMERATE_NTSC, SCANLINES_TOTAL_NTSC );
isCustom = (EmuConfig.GS.FramerateNTSC != 59.94);
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
vsyncCounter.CycleT = vSyncInfo.Render; // Amount of cycles before the counter will be updated
Fixed100 fpslimit = framerate *
( 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;
if( m_iTicks != ticks )
{
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_iTicks = ticks;
gsOnModeChanged( vSyncInfo.Framerate, m_iTicks );
Console.WriteLn( "(UpdateVSyncRate) FPS Limit Changed : %.02f fps", fpslimit.ToFloat()*2 );
}
m_iStart = GetCPUTicks();
cpuRcntSet();
XMMRegisters::Thaw();
MMXRegisters::Thaw();
return (u32)m_iTicks;
}
@ -289,16 +297,11 @@ extern int limitOn;
static __forceinline void frameLimit()
{
// 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;
u64 iEnd;
uExpectedEnd = m_iStart + m_iTicks;
iEnd = GetCPUTicks();
sDeltaTime = iEnd - uExpectedEnd;
u64 uExpectedEnd = m_iStart + m_iTicks;
u64 iEnd = GetCPUTicks();
s64 sDeltaTime = iEnd - uExpectedEnd;
// If the framerate drops too low, reset the expected value. This avoids
// excessive amounts of "fast forward" syndrome which would occur if we
@ -307,12 +310,6 @@ static __forceinline void frameLimit()
if( sDeltaTime > m_iTicks*8 )
{
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;
}
@ -386,7 +383,7 @@ static __forceinline void VSyncEnd(u32 sCycle)
iFrame++;
gsPostVsyncEnd( true );
gsPostVsyncEnd();
hwIntcIrq(INTC_VBLANK_E); // HW Irq
psxVBlankEnd(); // psxCounters vBlank End

View File

@ -92,7 +92,7 @@ struct SyncCounter
//------------------------------------------------------------------
// 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_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)
//------------------------------------------------------------------
#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_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 rcntCycle(int index);
u32 UpdateVSyncRate();
void frameLimitReset();
extern u32 UpdateVSyncRate();
extern void frameLimitReset();
#endif /* __COUNTERS_H__ */

View File

@ -31,7 +31,7 @@ typedef char* (*TdisR5900F)DisFInterface;
// These macros are used to assemble the disassembler functions
#define MakeDisF(fn, b) \
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; \
b; /*ostr[(strlen(ostr) - 1)] = 0;*/ return ostr; \
}
@ -52,47 +52,47 @@ typedef char* (*TdisR5900F)DisFInterface;
}
#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]); \
} \
#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]); \
} \
#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]); \
} \
#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]); \
}
#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]); \
}
#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); \
} \
#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]); \
}
#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]); \
}
#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]); \
}

View File

@ -30,42 +30,9 @@ u32 CSRw;
__aligned16 u8 g_RealGSMem[0x2000];
extern int m_nCounters[];
// FrameSkipping Stuff
// 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 )
void gsOnModeChanged( Fixed100 framerate, u32 newTickrate )
{
m_iSlowStart = GetCPUTicks();
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 );
GetMTGS().SendSimplePacket( GS_RINGTYPE_MODECHANGE, framerate.Raw, newTickrate, 0 );
}
static bool gsIsInterlaced = false;
@ -77,7 +44,6 @@ void gsSetRegionMode( GS_RegionMode region )
if( gsRegionMode == region ) return;
gsRegionMode = region;
Console.WriteLn( "%s Display Mode Initialized.", (( gsRegionMode == Region_PAL ) ? "PAL" : "NTSC") );
UpdateVSyncRate();
}
@ -92,10 +58,7 @@ void gsReset()
{
GetMTGS().ResetGS();
gsOnModeChanged(
(gsRegionMode == Region_NTSC) ? FRAMERATE_NTSC : FRAMERATE_PAL,
UpdateVSyncRate()
);
UpdateVSyncRate();
memzero(g_RealGSMem);
@ -353,161 +316,60 @@ void gsIrq() {
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
// a perfect "specific" framerate (where both min and max fps are the same)
// any other config will eventually equalize out.
if( !EmuConfig.GS.FrameSkipEnable ) return;
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!");
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( isSkipping )
{
if( !FramesToSkip )
++consec_skipped;
if( consec_skipped >= EmuConfig.GS.ConsecutiveSkip )
{
//Console.Status( "- Skipping some VUs!" );
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.
consec_skipped = 0;
isSkipping = false;
}
return;
}
if( FramesToRender == 0 )
else
{
// -- Standard operation section --
// Means neither skipping frames nor force-rendering consecutive frames.
if( sSlowDeltaTime > 0 )
++consec_drawn;
if( consec_drawn >= EmuConfig.GS.ConsecutiveFrames )
{
// The game is running below the minimum framerate.
// But don't start skipping yet! That would be too sensitive.
// 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;
}
consec_drawn = 0;
isSkipping = true;
}
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( bool updategs )
void gsPostVsyncEnd()
{
*(u32*)(PS2MEM_GS+0x1000) ^= 0x2000; // swap the vsync field
GetMTGS().PostVsyncEnd( updategs );
GetMTGS().PostVsyncEnd();
}
void _gs_ResetFrameskip()
@ -521,15 +383,6 @@ void gsResetFrameSkip()
GetMTGS().SendSimplePacket(GS_RINGTYPE_FRAMESKIP, 0, 0, 0);
}
void gsDynamicSkipEnable()
{
if( !m_StrictSkipping ) return;
GetMTGS().WaitGS();
m_iSlowStart = GetCPUTicks();
frameLimitReset();
}
void SaveStateBase::gsFreeze()
{
FreezeMem(PS2MEM_GS, 0x2000);

View File

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

View File

@ -148,9 +148,9 @@ void SysMtgsThread::ResetGS()
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
// mandatory feature that prevents the MTGS from queuing more than 2 frames at any time.
@ -198,6 +198,8 @@ void SysMtgsThread::OpenPlugin()
else
result = GSopen( (void*)&pDsp, "PCSX2", renderswitch ? 2 : 1 );
GSsetVsync( EmuConfig.GS.FrameLimitEnable && EmuConfig.GS.VsyncEnable );
if( result != 0 )
{
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" );
GSvsync(tag.data[0]);
gsFrameSkip( !tag.data[1] );
gsFrameSkip();
if( PADupdate != NULL )
PADupdate(0);
@ -416,17 +418,13 @@ void SysMtgsThread::ExecuteTaskInThread()
break;
case GS_RINGTYPE_MODECHANGE:
_gs_ChangeTimings( tag.data[0], tag.data[1] );
// [TODO] some frameskip sync logic might be needed here!
break;
case GS_RINGTYPE_CRC:
GSsetGameCRC( tag.data[0], 0 );
break;
case GS_RINGTYPE_STARTTIME:
m_iSlowStart += tag.data[0];
break;
#ifdef PCSX2_DEVBUILD
default:
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;
if( EmuConfig.Video.SynchronousMTGS )
if( EmuConfig.GS.SynchronousMTGS )
{
WaitGS();
}
@ -854,7 +852,7 @@ void SysMtgsThread::RestartRingbuffer( uint packsize )
m_WritePos = 0;
m_QueuedFrameCount = 0;
if( EmuConfig.Video.SynchronousMTGS )
if( EmuConfig.GS.SynchronousMTGS )
WaitGS();
}
@ -918,7 +916,7 @@ __forceinline void SysMtgsThread::_FinishSimplePacket( uint future_writepos )
pxAssert( future_writepos != volatize(m_RingPos) );
m_WritePos = future_writepos;
if( EmuConfig.Video.SynchronousMTGS )
if( EmuConfig.GS.SynchronousMTGS )
WaitGS();
else
++m_CopyDataTally;

View File

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

View File

@ -146,6 +146,7 @@ _GSprintf GSprintf;
_GSsetBaseMem GSsetBaseMem;
_GSsetGameCRC GSsetGameCRC;
_GSsetFrameSkip GSsetFrameSkip;
_GSsetVsync GSsetVsync;
_GSsetupRecording GSsetupRecording;
_GSreset GSreset;
_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_irqCallback(void (*callback)()) {}
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_printf(int timeout, char *fmt, ...)
{
@ -283,6 +286,7 @@ static const LegacyApi_ReqMethod s_MethMessReq_GS[] =
{ "GSsetGameCRC", (vMeth**)&GSsetGameCRC, (vMeth*)GS_setGameCRC },
{ "GSsetFrameSkip", (vMeth**)&GSsetFrameSkip, (vMeth*)GS_setFrameSkip },
{ "GSsetVsync", (vMeth**)&GSsetVsync, (vMeth*)GS_setVsync },
{ "GSchangeSaveState",(vMeth**)&GSchangeSaveState,(vMeth*)GS_changeSaveState },
{ NULL }
};

View File

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

View File

@ -550,7 +550,7 @@ __forceinline void cpuTestHwInts() {
void cpuExecuteBios()
{
// 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..." );

View File

@ -32,8 +32,29 @@ SrcType_PageFault Source_PageFault;
const Pcsx2Config EmuConfig;
// disable all session overrides by default...
SessionOverrideFlags g_Session = {false};
// Provides an accessor for quick modification of GS options. All GS options are allowed to be
// 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.
void SysDetect()
@ -146,23 +167,21 @@ SysCoreAllocations::SysCoreAllocations()
Console.WriteLn( "Allocating memory for recompilers..." );
try
{
try {
recCpu.Allocate();
RecSuccess_EE = true;
}
catch( Exception::BaseException& ex )
catch( Exception::RuntimeError& ex )
{
Console.Error( L"EE Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
recCpu.Shutdown();
}
try
{
try {
psxRec.Allocate();
RecSuccess_IOP = true;
}
catch( Exception::BaseException& ex )
catch( Exception::RuntimeError& ex )
{
Console.Error( L"IOP Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
psxRec.Shutdown();
@ -170,23 +189,21 @@ SysCoreAllocations::SysCoreAllocations()
// hmm! : VU0 and VU1 pre-allocations should do sVU and mVU separately? Sounds complicated. :(
try
{
try {
VU0micro::recAlloc();
RecSuccess_VU0 = true;
}
catch( Exception::BaseException& ex )
catch( Exception::RuntimeError& ex )
{
Console.Error( L"VU0 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
VU0micro::recShutdown();
}
try
{
try {
VU1micro::recAlloc();
RecSuccess_VU1 = true;
}
catch( Exception::BaseException& ex )
catch( Exception::RuntimeError& ex )
{
Console.Error( L"VU1 Recompiler Allocation Failed:\n" + ex.FormatDiagnosticMessage() );
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.
void SysClearExecutionCache()
{
Cpu = CHECK_EEREC ? &recCpu : &intCpu;
psxCpu = CHECK_IOPREC ? &psxRec : &psxInt;
Cpu = CHECK_EEREC ? &recCpu : &intCpu;
psxCpu = CHECK_IOPREC ? &psxRec : &psxInt;
Cpu->Reset();
psxCpu->Reset();

View File

@ -53,6 +53,9 @@ protected:
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 SysClearExecutionCache(); // clears recompiled execution caches!

View File

@ -16,6 +16,7 @@
#include "PrecompiledHeader.h"
#include "Common.h"
#include "Counters.h"
#include "GS.h"
#include "Elfheader.h"
#include "PageFaultSource.h"
@ -40,6 +41,7 @@ SysCoreThread::SysCoreThread()
m_name = L"EE Core";
m_resetRecompilers = true;
m_resetProfilers = true;
m_resetVsyncTimers = true;
m_resetVirtualMachine = true;
m_hasValidState = false;
}
@ -106,6 +108,14 @@ ScopedCoreThreadSuspend::ScopedCoreThreadSuspend()
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
// was instanized. Subsequent calls to Resume() will be ignored.
void ScopedCoreThreadSuspend::Resume()
@ -115,14 +125,29 @@ void ScopedCoreThreadSuspend::Resume()
m_ResumeWhenDone = false;
}
ScopedCoreThreadSuspend::~ScopedCoreThreadSuspend() throw()
ScopedCoreThreadPause::ScopedCoreThreadPause()
{
m_ResumeWhenDone = GetCoreThread().Pause();
}
ScopedCoreThreadPause::~ScopedCoreThreadPause() throw()
{
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
// 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
@ -131,12 +156,14 @@ void SysCoreThread::ApplySettings( const Pcsx2Config& src )
{
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_resetProfilers = (src.Profiler != EmuConfig.Profiler );
m_resetProfilers = ( src.Profiler != EmuConfig.Profiler );
m_resetVsyncTimers = ( src.GS != EmuConfig.GS );
const_cast<Pcsx2Config&>(EmuConfig) = src;
sys_paused.Resume();
}
void SysCoreThread::ChangeCdvdSource( CDVD_SourceType type )
@ -189,11 +216,7 @@ void SysCoreThread::CpuInitializeMess()
{
if( m_hasValidState ) return;
// Some recompiler mess might be left over -- nuke it here:
SysClearExecutionCache();
memBindConditionalHandlers();
m_resetRecompilers = false;
m_resetProfilers = false;
_reset_stuff_as_needed();
ScopedBool_ClearOnError sbcoe( m_hasValidState );
@ -238,13 +261,8 @@ void SysCoreThread::CpuInitializeMess()
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 )
{
SysClearExecutionCache();
@ -252,6 +270,23 @@ void SysCoreThread::StateCheckInThread()
m_resetRecompilers = 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()

View File

@ -187,6 +187,7 @@ class SysCoreThread : public SysThreadBase
protected:
bool m_resetRecompilers;
bool m_resetProfilers;
bool m_resetVsyncTimers;
bool m_resetVirtualMachine;
bool m_hasValidState;
@ -223,6 +224,7 @@ public:
protected:
void CpuInitializeMess();
void _reset_stuff_as_needed();
virtual void Start();
virtual void OnSuspendInThread();
@ -252,8 +254,17 @@ struct ScopedCoreThreadSuspend
bool m_ResumeWhenDone;
ScopedCoreThreadSuspend();
void Resume();
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*

View File

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

View File

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

View File

@ -23,6 +23,10 @@ struct VUmicroCpu
void (*Step)();
void (*ExecuteBlock)(); // VUs should support block-level execution only.
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;

View File

@ -42,15 +42,7 @@ static const uint m_vuMemSize =
0x1000 + // VU0micro memory
0x4000+0x800 + // VU0 memory and VU1 registers
0x4000 + // VU1 memory
0x4000;/* + // VU1micro memory
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. :)
0x4000;
void vuMicroMemAlloc()
{

View File

@ -399,14 +399,19 @@ void AppConfig::LoadSave( IniInterface& ini )
LoadSaveMemcards( ini );
// Process various sub-components:
ProgLogBox.LoadSave( ini, L"ProgramLog" );
Ps2ConBox.LoadSave( ini, L"Ps2Console" );
ProgLogBox .LoadSave( ini, L"ProgramLog" );
Ps2ConBox .LoadSave( ini, L"Ps2Console" );
Folders.LoadSave( ini );
BaseFilenames.LoadSave( ini );
Folders .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 );
GSWindow.LoadSave( ini );
if( ini.IsLoading() )
EmuOptions.GS.LimitScalar = GSWindow.NominalScalar;
ini.Flush();
}
@ -444,18 +449,18 @@ void AppConfig::FolderOptions::ApplyDefaults()
}
// ------------------------------------------------------------------------
AppConfig::FolderOptions::FolderOptions() :
bitset( 0xffffffff )
, Plugins ( PathDefs::GetPlugins() )
, Bios ( PathDefs::GetBios() )
, Snapshots ( PathDefs::GetSnapshots() )
, Savestates ( PathDefs::GetSavestates() )
, MemoryCards ( PathDefs::GetMemoryCards() )
, Logs ( PathDefs::GetLogs() )
AppConfig::FolderOptions::FolderOptions()
: Plugins ( PathDefs::GetPlugins() )
, Bios ( PathDefs::GetBios() )
, Snapshots ( PathDefs::GetSnapshots() )
, Savestates ( PathDefs::GetSavestates() )
, MemoryCards ( PathDefs::GetMemoryCards() )
, Logs ( PathDefs::GetLogs() )
, RunIso( PathDefs::GetDocuments() ) // raw default is always the Documents folder.
, RunELF( 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.
{
bitset = 0xffffffff;
}
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;
DefaultToFullscreen = false;
AlwaysHideMouse = false;
@ -532,10 +541,14 @@ AppConfig::GSOptions::GSOptions()
IsMaximized = false;
}
void AppConfig::GSOptions::SanityCheck()
void AppConfig::GSWindowOptions::SanityCheck()
{
// 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::min( WindowSize.x, wxGetDisplayArea().GetWidth()-16 );
@ -550,12 +563,15 @@ void AppConfig::GSOptions::SanityCheck()
AspectRatio = AspectRatio_4_3;
}
void AppConfig::GSOptions::LoadSave( IniInterface& ini )
void AppConfig::GSWindowOptions::LoadSave( IniInterface& ini )
{
IniScopedGroup path( ini, L"GSWindow" );
GSOptions defaults;
GSWindowOptions defaults;
IniEntry( NominalScalar );
IniEntry( TurboScalar );
IniEntry( SlomoScalar );
IniEntry( CloseOnEsc );
IniEntry( DefaultToFullscreen );
IniEntry( AlwaysHideMouse );
@ -573,7 +589,7 @@ void AppConfig::GSOptions::LoadSave( IniInterface& ini )
ini.EnumEntry( L"AspectRatio", AspectRatio, AspectRatioNames, defaults.AspectRatio );
DisableResizeBorders = false;
if( ini.IsLoading() ) SanityCheck();
}
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.
//
struct GSOptions
struct GSWindowOptions
{
// Closes the GS/Video port on escape (good for fullscreen activity)
bool CloseOnEsc;
@ -129,12 +129,16 @@ public:
bool DisableResizeBorders;
AspectRatioType AspectRatio;
wxSize WindowSize;
wxPoint WindowPos;
bool IsMaximized;
GSOptions();
Fixed100 NominalScalar;
Fixed100 TurboScalar;
Fixed100 SlomoScalar;
GSWindowOptions();
void LoadSave( IniInterface& conf );
void SanityCheck();
@ -183,7 +187,7 @@ public:
ConsoleLogOptions Ps2ConBox;
FolderOptions Folders;
FilenameOptions BaseFilenames;
GSOptions GSWindow;
GSWindowOptions GSWindow;
// 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

View File

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

View File

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

View File

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

View File

@ -48,13 +48,14 @@ GSPanel::GSPanel( wxWindow* parent )
: wxWindow()
, m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener<int> ( this, OnSettingsApplied ) )
, m_HideMouseTimer( this )
{
m_CursorShown = true;
if ( !wxWindow::Create(parent, wxID_ANY) )
throw Exception::RuntimeError( "GSPanel constructor esplode!!" );
SetName( L"GSPanel" );
InitDefaultAccelerators();
if( g_Conf->GSWindow.AlwaysHideMouse )
@ -115,7 +116,7 @@ void GSPanel::DoResize()
if( client.x/16 <= client.y/9 )
viewport.y = (int)(client.x * (9.0/16.0));
else
viewport.x = (int)(client.y * (9.0/16.0));
viewport.x = (int)(client.y * (16.0/9.0));
break;
}
@ -182,6 +183,10 @@ void __evt_fastcall GSPanel::OnSettingsApplied( void* obj, int& evt )
panel->DoShowMouse();
}
// --------------------------------------------------------------------------------------
// GSFrame
// --------------------------------------------------------------------------------------
GSFrame::GSFrame(wxWindow* parent, const wxString& title)
: wxFrame(parent, wxID_ANY, title,
g_Conf->GSWindow.WindowPos, wxSize( 640, 480 ),
@ -193,11 +198,12 @@ GSFrame::GSFrame(wxWindow* parent, const wxString& title)
SetClientSize( g_Conf->GSWindow.WindowSize );
m_gspanel = new GSPanel( this );
m_gspanel = new GSPanel( this );
//Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSFrame::OnCloseWindow) );
Connect( wxEVT_MOVE, wxMoveEventHandler (GSFrame::OnMove) );
Connect( wxEVT_SIZE, wxSizeEventHandler (GSFrame::OnResize) );
//Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler (GSFrame::OnCloseWindow) );
Connect( wxEVT_MOVE, wxMoveEventHandler (GSFrame::OnMove) );
Connect( wxEVT_SIZE, wxSizeEventHandler (GSFrame::OnResize) );
Connect( wxEVT_ACTIVATE, wxActivateEventHandler (GSFrame::OnActivate) );
}
GSFrame::~GSFrame() throw()
@ -210,6 +216,12 @@ wxWindow* GSFrame::GetViewport()
return m_gspanel;
}
void GSFrame::OnActivate( wxActivateEvent& evt )
{
evt.Skip();
if( wxWindow* gsPanel = FindWindowByName(L"GSPanel") ) gsPanel->SetFocus();
}
void GSFrame::OnMove( wxMoveEvent& evt )
{
// 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 )
{
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!
//evt.Skip();

View File

@ -53,24 +53,87 @@ wxString KeyAcceleratorCode::ToString() const
).ToString();
}
int limitOn = false;
enum LimiterModeType
{
Limit_Nominal,
Limit_Turbo,
Limit_Slomo,
};
static LimiterModeType g_LimiterMode = Limit_Nominal;
namespace Implementations
{
void Frameskip_Toggle()
{
limitOn ^= 1;
Console.WriteLn("Framelimit mode changed to %d", limitOn ? 1 : 0);
// FIXME : Reimplement framelimiting using new double-switch boolean system
g_Conf->EmuOptions.GS.FrameSkipEnable = !g_Conf->EmuOptions.GS.FrameSkipEnable;
SetGSConfig().FrameSkipEnable = g_Conf->EmuOptions.GS.FrameSkipEnable;
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()
{
limitOn ^= 1;
Console.WriteLn("Framelimit mode changed to %d", limitOn ? 1 : 0);
if( !g_Conf->EmuOptions.GS.FrameLimitEnable )
{
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()
{
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()
@ -104,7 +167,7 @@ namespace Implementations
// 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.
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."));
}
@ -209,6 +272,12 @@ static const GlobalCommandDescriptor CommandDeclarations[] =
NULL,
},
{ "Framelimiter_SlomoToggle",
Implementations::Framelimiter_TurboToggle,
NULL,
NULL,
},
{ "Framelimiter_MasterToggle",
Implementations::Framelimiter_MasterToggle,
NULL,
@ -314,9 +383,10 @@ void Pcsx2App::InitDefaultGlobalAccelerators()
GlobalAccels.Map( AAC( WXK_F2 ), "States_CycleSlotForward" );
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 ).Shift(), "Framelimiter_MasterToggle" );
GlobalAccels.Map( AAC( WXK_TAB ).Shift(), "Framelimiter_SlomoToggle" );
// 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

View File

@ -141,6 +141,16 @@ int IniLoader::EntryBitfield( const wxString& var, int value, const int defvalue
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 )
{
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;
}
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 )
{
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 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, wxSize& value, const wxSize& defvalue=wxDefaultSize )=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 );
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, wxSize& value, const wxSize& defvalue=wxDefaultSize );
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 );
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, wxSize& value, const wxSize& defvalue=wxDefaultSize );
void Entry( const wxString& var, wxRect& value, const wxRect& defvalue=wxDefaultRect );

View File

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

View File

@ -260,17 +260,17 @@ Panels::VideoPanel::VideoPanel( wxWindow* parent ) :
*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()
{
g_Conf->EmuOptions.Video.SynchronousMTGS = m_check_SynchronousGS->GetValue();
g_Conf->EmuOptions.GS.SynchronousMTGS = m_check_SynchronousGS->GetValue();
}
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_Fullscreen ->SetValue( conf.DefaultToFullscreen );
@ -279,6 +279,8 @@ void Panels::GSWindowSettingsPanel::OnSettingsChanged()
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_WindowHeight ->SetValue( wxsFormat( L"%d", conf.WindowSize.GetHeight() ) );
@ -286,14 +288,17 @@ void Panels::GSWindowSettingsPanel::OnSettingsChanged()
void Panels::GSWindowSettingsPanel::Apply()
{
AppConfig::GSOptions& gsopt( g_Conf->GSWindow );
gsopt.CloseOnEsc = m_check_CloseGS ->GetValue();
gsopt.DefaultToFullscreen = m_check_Fullscreen->GetValue();
gsopt.AlwaysHideMouse = m_check_HideMouse ->GetValue();
gsopt.DisableResizeBorders = m_check_SizeLock ->GetValue();
AppConfig::GSWindowOptions& appconf( g_Conf->GSWindow );
Pcsx2Config::GSOptions& gsconf( g_Conf->EmuOptions.GS );
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;
@ -303,21 +308,43 @@ void Panels::GSWindowSettingsPanel::Apply()
_("Invalid window dimensions specified: Size cannot contain non-numeric digits! >_<")
);
gsopt.WindowSize.x = xr;
gsopt.WindowSize.y = yr;
appconf.WindowSize.x = xr;
appconf.WindowSize.y = yr;
}
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()
{
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;
GetTextExtent( L"blaH yeah", NULL, &fonty );
m_win32_LinesPerPage = (ctrly / fonty) + 1;
m_win32_LinesPerScroll = m_win32_LinesPerPage * 0.72;
m_win32_LinesPerScroll = m_win32_LinesPerPage * 0.25;
#endif
evt.Skip();

View File

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

View File

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