diff --git a/common/build/Utilities/utilities.vcproj b/common/build/Utilities/utilities.vcproj index 1c15365662..0c70dc5300 100644 --- a/common/build/Utilities/utilities.vcproj +++ b/common/build/Utilities/utilities.vcproj @@ -465,6 +465,10 @@ RelativePath="..\..\include\Utilities\Exceptions.h" > + + diff --git a/common/include/PS2Edefs.h b/common/include/PS2Edefs.h index 8e8b0b69d1..8fa72bfb94 100644 --- a/common/include/PS2Edefs.h +++ b/common/include/PS2Edefs.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; diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index 7753b886e8..6d752108f8 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.h @@ -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 diff --git a/common/include/Utilities/FixedPointTypes.h b/common/include/Utilities/FixedPointTypes.h new file mode 100644 index 0000000000..5457df05c7 --- /dev/null +++ b/common/include/Utilities/FixedPointTypes.h @@ -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 . + */ + +#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& right ) const + { + return Raw == right.Raw; + } + + bool operator !=( const FixedInt& right ) const + { + return Raw != right.Raw; + } + + FixedInt operator+( const FixedInt& right ) const + { + return FixedInt().SetRaw( Raw + right.Raw ); + } + + FixedInt operator-( const FixedInt& right ) const + { + return FixedInt().SetRaw( Raw + right.Raw ); + } + + FixedInt& operator+=( const FixedInt& right ) + { + return SetRaw( Raw + right.Raw ); + } + + FixedInt& operator-=( const FixedInt& right ) + { + return SetRaw( Raw + right.Raw ); + } + + bool operator>( const FixedInt& right ) const { return Raw > right.Raw; } + bool operator>=( const FixedInt& right ) const { return Raw >= right.Raw; } + bool operator<( const FixedInt& right ) const { return Raw < right.Raw; } + bool operator<=( const FixedInt& right ) const { return Raw <= right.Raw; } + + FixedInt& ConfineTo( const FixedInt& low, const FixedInt& 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 operator*( const FixedInt& right ) const + { + s64 mulres = (s64)Raw * right.Raw; + return FixedInt().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 operator/( const FixedInt& right ) const + { + s64 divres = Raw * Precision; + return FixedInt().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& operator*=( const FixedInt& 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& operator/=( const FixedInt& 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& SetRaw( s32 rawsrc ) + { + Raw = rawsrc; + return *this; + } + + FixedInt& Round() + { + Raw = ToIntRounded(); + return *this; + } + + FixedInt& SetWhole( s32 wholepart ) + { + pxAssert( wholepart < (INT_MAX / Precision) ); + Raw = GetFraction() + (wholepart * Precision); + return *this; + } + + FixedInt& 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 FromString( const wxString parseFrom, const FixedInt& defval ) + { + long whole, frac; + wxString afterFirst( parseFrom.AfterFirst( L'.' ).Mid(0, 5) ); + if( !parseFrom.BeforeFirst( L'.' ).ToLong( &whole ) || !afterFirst.ToLong( &frac ) ) + return defval; + + FixedInt 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; diff --git a/common/include/Utilities/StringHelpers.h b/common/include/Utilities/StringHelpers.h index 9ecb466e1b..8a3a835aab 100644 --- a/common/include/Utilities/StringHelpers.h +++ b/common/include/Utilities/StringHelpers.h @@ -17,7 +17,6 @@ #include "Dependencies.h" -#include #include #include // 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 ); diff --git a/pcsx2/Common.h b/pcsx2/Common.h index 13532db030..46b820af42 100644 --- a/pcsx2/Common.h +++ b/pcsx2/Common.h @@ -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; diff --git a/pcsx2/Config.h b/pcsx2/Config.h index cfb8e37dad..5cd12f83f4 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -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 diff --git a/pcsx2/Counters.cpp b/pcsx2/Counters.cpp index fe44142b59..8551c31549 100644 --- a/pcsx2/Counters.cpp +++ b/pcsx2/Counters.cpp @@ -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 diff --git a/pcsx2/Counters.h b/pcsx2/Counters.h index 921125434f..5cc1496477 100644 --- a/pcsx2/Counters.h +++ b/pcsx2/Counters.h @@ -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__ */ diff --git a/pcsx2/DebugTools/DisVU1Micro.cpp b/pcsx2/DebugTools/DisVU1Micro.cpp index e4c582f14d..d4d2fb1fc4 100644 --- a/pcsx2/DebugTools/DisVU1Micro.cpp +++ b/pcsx2/DebugTools/DisVU1Micro.cpp @@ -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]); \ } diff --git a/pcsx2/GS.cpp b/pcsx2/GS.cpp index d5a1cc6629..83391f23ec 100644 --- a/pcsx2/GS.cpp +++ b/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; + + 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); diff --git a/pcsx2/GS.h b/pcsx2/GS.h index 276fe5835f..85a86bae65 100644 --- a/pcsx2/GS.h +++ b/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 diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 73dbc4323e..a3d7e68d56 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -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; diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 298c9d3e2b..825196059d 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -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(); } diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index f6ba564aed..bad0f47b59 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -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 } }; diff --git a/pcsx2/PrecompiledHeader.h b/pcsx2/PrecompiledHeader.h index 2e9f6a9ccf..bdbade65fa 100644 --- a/pcsx2/PrecompiledHeader.h +++ b/pcsx2/PrecompiledHeader.h @@ -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" diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index 78b3afdeac..1f0e89ffb8 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -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..." ); diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index e5a182a4e0..588975773b 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -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(EmuConfig.GS); +} + +ConsoleLogFilters& SetConsoleConfig() +{ + //DbgCon.WriteLn( "Direct modification of EmuConfig.Log detected" ); + AllowFromMainThreadOnly(); + return const_cast(EmuConfig.Log); +} + +TraceLogFilters& SetTraceConfig() +{ + //DbgCon.WriteLn( "Direct modification of EmuConfig.TraceLog detected" ); + AllowFromMainThreadOnly(); + return const_cast(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(); diff --git a/pcsx2/System.h b/pcsx2/System.h index c76286ba08..3da30065a1 100644 --- a/pcsx2/System.h +++ b/pcsx2/System.h @@ -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! diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp index ae5683133f..a4e5810166 100644 --- a/pcsx2/System/SysCoreThread.cpp +++ b/pcsx2/System/SysCoreThread.cpp @@ -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(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() diff --git a/pcsx2/System/SysThreads.h b/pcsx2/System/SysThreads.h index 32663571e9..79a4ae5ca8 100644 --- a/pcsx2/System/SysThreads.h +++ b/pcsx2/System/SysThreads.h @@ -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* diff --git a/pcsx2/VU0microInterp.cpp b/pcsx2/VU0microInterp.cpp index 5b4b6256db..7adca3a0e1 100644 --- a/pcsx2/VU0microInterp.cpp +++ b/pcsx2/VU0microInterp.cpp @@ -240,4 +240,6 @@ const VUmicroCpu intVU0 = , intStep , intExecuteBlock , intClear + +, true }; diff --git a/pcsx2/VU1microInterp.cpp b/pcsx2/VU1microInterp.cpp index 1822fa53e5..5a06a0893f 100644 --- a/pcsx2/VU1microInterp.cpp +++ b/pcsx2/VU1microInterp.cpp @@ -225,4 +225,6 @@ const VUmicroCpu intVU1 = , intStep , intExecuteBlock , intClear + +, true }; diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index c9df69d6a9..766050c6f8 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -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; diff --git a/pcsx2/VUmicroMem.cpp b/pcsx2/VUmicroMem.cpp index c41deb95da..777a64f427 100644 --- a/pcsx2/VUmicroMem.cpp +++ b/pcsx2/VUmicroMem.cpp @@ -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() { diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 9134c0fecb..8d18c17e04 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -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 ) diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index a498c1f80f..8eb272bbc2 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -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 diff --git a/pcsx2/gui/AppCoreThread.cpp b/pcsx2/gui/AppCoreThread.cpp index b70089c980..b386f1b41a 100644 --- a/pcsx2/gui/AppCoreThread.cpp +++ b/pcsx2/gui/AppCoreThread.cpp @@ -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 ); } diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index 0d438353f7..21e2169118 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -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", diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index 4f3526ec88..13e277377f 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -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; +} diff --git a/pcsx2/gui/FrameForGS.cpp b/pcsx2/gui/FrameForGS.cpp index 912144ff15..df2a97a22b 100644 --- a/pcsx2/gui/FrameForGS.cpp +++ b/pcsx2/gui/FrameForGS.cpp @@ -48,13 +48,14 @@ GSPanel::GSPanel( wxWindow* parent ) : wxWindow() , m_Listener_SettingsApplied( wxGetApp().Source_SettingsApplied(), EventListener ( 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(); diff --git a/pcsx2/gui/GlobalCommands.cpp b/pcsx2/gui/GlobalCommands.cpp index 0505228c8c..b5b999be50 100644 --- a/pcsx2/gui/GlobalCommands.cpp +++ b/pcsx2/gui/GlobalCommands.cpp @@ -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(EmuConfig).Trace.Enabled = !EmuConfig.Trace.Enabled; + SetTraceConfig().Enabled = !EmuConfig.Trace.Enabled; GSprintf(10, const_cast(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 diff --git a/pcsx2/gui/IniInterface.cpp b/pcsx2/gui/IniInterface.cpp index 6ba10bf4d5..70ffce709b 100644 --- a/pcsx2/gui/IniInterface.cpp +++ b/pcsx2/gui/IniInterface.cpp @@ -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 ) ); diff --git a/pcsx2/gui/IniInterface.h b/pcsx2/gui/IniInterface.h index 0e3fa534a4..84b7021eb8 100644 --- a/pcsx2/gui/IniInterface.h +++ b/pcsx2/gui/IniInterface.h @@ -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 ); diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index d4476ba8e1..d22a7ffa44 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -68,6 +68,7 @@ public: protected: void OnMove( wxMoveEvent& evt ); void OnResize( wxSizeEvent& evt ); + void OnActivate( wxActivateEvent& evt ); }; struct PluginMenuAddition diff --git a/pcsx2/gui/Panels/VideoPanel.cpp b/pcsx2/gui/Panels/VideoPanel.cpp index b5fd64c83d..b22da54261 100644 --- a/pcsx2/gui/Panels/VideoPanel.cpp +++ b/pcsx2/gui/Panels/VideoPanel.cpp @@ -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; } diff --git a/pcsx2/gui/pxLogTextCtrl.cpp b/pcsx2/gui/pxLogTextCtrl.cpp index 27d8037579..861e755742 100644 --- a/pcsx2/gui/pxLogTextCtrl.cpp +++ b/pcsx2/gui/pxLogTextCtrl.cpp @@ -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(); diff --git a/pcsx2/x86/iVU0micro.cpp b/pcsx2/x86/iVU0micro.cpp index 069a56e62c..72f14b9d14 100644 --- a/pcsx2/x86/iVU0micro.cpp +++ b/pcsx2/x86/iVU0micro.cpp @@ -55,8 +55,10 @@ using namespace VU0micro; const VUmicroCpu recVU0 = { - recReset - , recStep - , recExecuteBlock - , recClear + recReset +, recStep +, recExecuteBlock +, recClear + +, false }; diff --git a/pcsx2/x86/iVU1micro.cpp b/pcsx2/x86/iVU1micro.cpp index 2f77aae004..7f3ada40e3 100644 --- a/pcsx2/x86/iVU1micro.cpp +++ b/pcsx2/x86/iVU1micro.cpp @@ -297,4 +297,6 @@ const VUmicroCpu recVU1 = , recStep , recExecuteBlock , recClear + +, false };