mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
9675fe8108
commit
1e431fb69a
|
@ -465,6 +465,10 @@
|
|||
RelativePath="..\..\include\Utilities\Exceptions.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\FixedPointTypes.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\include\Utilities\General.h"
|
||||
>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 SynchronousMTGS;
|
||||
|
||||
bool EnableFrameLimiting;
|
||||
bool EnableFrameSkipping;
|
||||
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
|
||||
|
|
|
@ -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.
|
||||
// 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).
|
||||
|
||||
//#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)
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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() );
|
||||
|
||||
if( EmuConfig.Video.EnableFrameLimiting && (EmuConfig.Video.FpsLimit > 0) )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
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();
|
||||
}
|
||||
else
|
||||
|
||||
Fixed100 fpslimit = framerate *
|
||||
( pxAssert( EmuConfig.GS.LimitScalar > 0 ) ? EmuConfig.GS.LimitScalar : 1.0 );
|
||||
|
||||
//s64 debugme = GetTickFrequency() / 3000;
|
||||
s64 ticks = (GetTickFrequency()*500) / (fpslimit * 1000).ToIntRounded();
|
||||
|
||||
if( m_iTicks != ticks )
|
||||
{
|
||||
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
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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]); \
|
||||
}
|
||||
|
||||
|
|
229
pcsx2/GS.cpp
229
pcsx2/GS.cpp
|
@ -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;
|
||||
|
||||
//Console.WriteLn("LostTime on the EE!");
|
||||
GSsetFrameSkip( 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( 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);
|
||||
|
|
21
pcsx2/GS.h
21
pcsx2/GS.h
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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..." );
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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*
|
||||
|
|
|
@ -240,4 +240,6 @@ const VUmicroCpu intVU0 =
|
|||
, intStep
|
||||
, intExecuteBlock
|
||||
, intClear
|
||||
|
||||
, true
|
||||
};
|
||||
|
|
|
@ -225,4 +225,6 @@ const VUmicroCpu intVU1 =
|
|||
, intStep
|
||||
, intExecuteBlock
|
||||
, intClear
|
||||
|
||||
, true
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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,11 +563,14 @@ 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" );
|
||||
GSWindowOptions defaults;
|
||||
|
||||
GSOptions defaults;
|
||||
IniEntry( NominalScalar );
|
||||
IniEntry( TurboScalar );
|
||||
IniEntry( SlomoScalar );
|
||||
|
||||
IniEntry( CloseOnEsc );
|
||||
IniEntry( DefaultToFullscreen );
|
||||
|
@ -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 )
|
||||
|
|
|
@ -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;
|
||||
|
@ -134,7 +134,11 @@ public:
|
|||
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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ) );
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
protected:
|
||||
void OnMove( wxMoveEvent& evt );
|
||||
void OnResize( wxSizeEvent& evt );
|
||||
void OnActivate( wxActivateEvent& evt );
|
||||
};
|
||||
|
||||
struct PluginMenuAddition
|
||||
|
|
|
@ -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 );
|
||||
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();
|
||||
appconf.CloseOnEsc = m_check_CloseGS ->GetValue();
|
||||
appconf.DefaultToFullscreen = m_check_Fullscreen->GetValue();
|
||||
appconf.AlwaysHideMouse = m_check_HideMouse ->GetValue();
|
||||
appconf.DisableResizeBorders = m_check_SizeLock ->GetValue();
|
||||
|
||||
gsopt.AspectRatio = (AspectRatioType)m_combo_AspectRatio->GetSelection();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -55,8 +55,10 @@ using namespace VU0micro;
|
|||
|
||||
const VUmicroCpu recVU0 =
|
||||
{
|
||||
recReset
|
||||
, recStep
|
||||
, recExecuteBlock
|
||||
, recClear
|
||||
recReset
|
||||
, recStep
|
||||
, recExecuteBlock
|
||||
, recClear
|
||||
|
||||
, false
|
||||
};
|
||||
|
|
|
@ -297,4 +297,6 @@ const VUmicroCpu recVU1 =
|
|||
, recStep
|
||||
, recExecuteBlock
|
||||
, recClear
|
||||
|
||||
, false
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue