diff --git a/3rdparty/SoundTouch/CMakeLists.txt b/3rdparty/SoundTouch/CMakeLists.txt index 0a4aa03c0d..7520eb46a8 100644 --- a/3rdparty/SoundTouch/CMakeLists.txt +++ b/3rdparty/SoundTouch/CMakeLists.txt @@ -39,7 +39,7 @@ set(SoundTouchSources RateTransposer.cpp SoundTouch.cpp TDStretch.cpp - WavFile.cpp + # WavFile.cpp # directly include in spu2x cpu_detect_x86_gcc.cpp mmx_optimized.cpp sse_optimized.cpp) @@ -55,7 +55,7 @@ set(SoundTouchHeaders STTypes.h SoundTouch.h TDStretch.h - WavFile.h + # WavFile.h # directly include in spu2x cpu_detect.h) # add library diff --git a/cmake/SearchForStuff.cmake b/cmake/SearchForStuff.cmake index e87f6f7467..099e21b9b8 100644 --- a/cmake/SearchForStuff.cmake +++ b/cmake/SearchForStuff.cmake @@ -23,9 +23,6 @@ if(Linux) endif(GTK2_FOUND) find_package(X11) - # Manually find Xxf86vm because it is not done in the module... - FIND_LIBRARY(X11_Xxf86vm_LIB Xxf86vm ${X11_LIB_SEARCH_PATH}) - MARK_AS_ADVANCED(X11_Xxf86vm_LIB) endif(Linux) ## Use cmake package to find module diff --git a/common/build/Utilities/utilities.vcproj b/common/build/Utilities/utilities.vcproj index a2f77eafcb..feff13fbc0 100644 --- a/common/build/Utilities/utilities.vcproj +++ b/common/build/Utilities/utilities.vcproj @@ -445,6 +445,10 @@ RelativePath="..\..\include\Utilities\pxEvents.h" > + + diff --git a/common/include/PS2Edefs.h b/common/include/PS2Edefs.h index 777bf74825..6d6119d4c7 100644 --- a/common/include/PS2Edefs.h +++ b/common/include/PS2Edefs.h @@ -278,7 +278,9 @@ void CALLBACK GSsetFrameSkip(int frameskip); int CALLBACK GSsetupRecording(int start, void* pData); void CALLBACK GSreset(); -void CALLBACK GSgetTitleInfo( char dest[128] ); +//deprecated: GSgetTitleInfo was used in PCSX2 but no plugin supported it prior to r4070: +//void CALLBACK GSgetTitleInfo( char dest[128] ); +void CALLBACK GSgetTitleInfo2( char* dest, size_t length ); void CALLBACK GSwriteCSR(u32 value); s32 CALLBACK GSfreeze(int mode, freezeData *data); void CALLBACK GSconfigure(); @@ -575,7 +577,7 @@ typedef void (CALLBACK* _GSreadFIFO)(u64 *pMem); typedef void (CALLBACK* _GSreadFIFO2)(u64 *pMem, int qwc); typedef void (CALLBACK* _GSchangeSaveState)(int, const char* filename); -typedef void (CALLBACK* _GSgetTitleInfo)(char dest[128]); +typedef void (CALLBACK* _GSgetTitleInfo2)(char* dest, size_t length); typedef void (CALLBACK* _GSirqCallback)(void (*callback)()); typedef void (CALLBACK* _GSprintf)(int timeout, char *fmt, ...); typedef void (CALLBACK* _GSsetBaseMem)(void*); @@ -729,7 +731,7 @@ extern _GSreadFIFO GSreadFIFO; extern _GSreadFIFO2 GSreadFIFO2; extern _GSchangeSaveState GSchangeSaveState; -extern _GSgetTitleInfo GSgetTitleInfo; +extern _GSgetTitleInfo2 GSgetTitleInfo2; extern _GSmakeSnapshot GSmakeSnapshot; extern _GSmakeSnapshot2 GSmakeSnapshot2; extern _GSirqCallback GSirqCallback; diff --git a/common/include/Utilities/Dependencies.h b/common/include/Utilities/Dependencies.h index ec977b25ef..5011a6d50c 100644 --- a/common/include/Utilities/Dependencies.h +++ b/common/include/Utilities/Dependencies.h @@ -18,37 +18,7 @@ // Dependencies.h : Contains classes required by all Utilities headers. // This file is included by most .h files provided by the Utilities class. -// -------------------------------------------------------------------------------------- -// Forward Declarations Section -// -------------------------------------------------------------------------------------- - -class wxOutputStream; -class wxFileOutputStream; -class wxFFileOutputStream; - -class wxStreamBase; -class wxInputStream; -class wxFileInputStream; -class wxFFileInputStream; - -class wxPoint; -class wxRect; -class wxSize; - -extern const wxSize wxDefaultSize; -extern const wxPoint wxDefaultPosition; - -namespace Threading -{ - class Mutex; - class Semaphore; - class pxThread; -} - -namespace Exception -{ - class BaseException; -} +#include "pxForwardDefs.h" // This should prove useful.... #define wxsFormat wxString::Format @@ -165,6 +135,50 @@ public: } }; +// -------------------------------------------------------------------------------------- +// _(x) / _t(x) / _d(x) / pxL(x) / pxLt(x) [macros] +// -------------------------------------------------------------------------------------- +// Define pxWex's own i18n helpers. These override the wxWidgets helpers and provide +// additional functionality. Define them FIRST THING, to make sure that wx's own gettext +// macros aren't in place. +// +// _ is for standard translations +// _t is for tertiary low priority translations +// _d is for debug/devel build translations + +#define WXINTL_NO_GETTEXT_MACRO + +#ifndef _ +# define _(s) pxGetTranslation(_T(s)) +#endif + +#ifndef _t +# define _t(s) pxGetTranslation(_T(s)) +#endif + +#ifndef _d +# define _d(s) pxGetTranslation(_T(s)) +#endif + +// pxL / pxLt / pxDt -- macros provided for tagging translation strings, without actually running +// them through the translator (which the _() does automatically, and sometimes we don't +// want that). This is a shorthand replacement for wxTRANSLATE. pxL is a standard translation +// moniker. pxLt is for tertiary strings that have a very low translation priority. pxDt is for +// debug/devel specific translations. +// +#ifndef pxL +# define pxL(a) wxT(a) +#endif + +#ifndef pxLt +# define pxLt(a) wxT(a) +#endif + +#ifndef pxDt +# define pxDt(a) wxT(a) +#endif + + #include #include #include @@ -178,6 +192,9 @@ public: #include "Pcsx2Defs.h" +// -------------------------------------------------------------------------------------- +// Handy Human-readable constants for common immediate values (_16kb -> _4gb) + static const sptr _64kb = 0x10000; static const sptr _16kb = _64kb / 4; static const sptr _128kb = _64kb * 2; @@ -193,30 +210,8 @@ static const s64 _1gb = _256mb * 4; static const s64 _4gb = _1gb * 4; -// =========================================================================================== -// i18n/Translation Feature Set! -// =========================================================================================== - -extern const wxChar* __fastcall pxExpandMsg( const wxChar* key, const wxChar* englishContent ); -extern const wxChar* __fastcall pxGetTranslation( const wxChar* message ); -extern bool pxIsEnglish( int id ); - -extern wxString fromUTF8( const char* src ); -extern wxString fromAscii( const char* src ); - // -------------------------------------------------------------------------------------- -// wxLt(x) [macro] -// -------------------------------------------------------------------------------------- -// macro provided for tagging translation strings, without actually running them through the -// translator (which the _() does automatically, and sometimes we don't want that). This is -// a shorthand replacement for wxTRANSLATE. -// -#ifndef wxLt -# define wxLt(a) wxT(a) -#endif - -// -------------------------------------------------------------------------------------- -// pxE(x) [macro] +// pxE(key, msg) and pxEt(key, msg) [macros] // -------------------------------------------------------------------------------------- // Translation Feature: pxE is used as a method of dereferencing very long english text // descriptions via a "key" identifier. In this way, the english text can be revised without @@ -226,28 +221,42 @@ extern wxString fromAscii( const char* src ); // // Valid prefix types: // -// .Panel: Key-based translation of a panel or dialog text; usually either a header or -// checkbox description, by may also include some controls with long labels. -// These have the highest translation priority. +// !Panel: Key-based translation of a panel or dialog text; usually either a header or +// checkbox description, by may also include some controls with long labels. +// These have the highest translation priority. // -// .Popup: Key-based translation of a popup dialog box; either a notice, confirmation, -// or error. These typically have very high translation priority (roughly equal -// or slightly less than pxE_Panel). +// !Notice: Key-based translation of a popup dialog box; either a notice, confirmation, +// or error. These typically have very high translation priority (roughly equal +// or slightly less than pxE_Panel). // -// .Error Key-based translation of error messages, typically used when throwing exceptions -// that have end-user errors. These are normally (but not always) displayed as popups -// to the user. Translation priority is medium. +// !Tooltip: Key-based translation of a tooltip for a button on a tool bar. Since buttons are +// rarely self-explanatory, these translations are considered medium to high priority. // -// .Wizard Key-based translation of a heading, checkbox item, description, or other text -// associated with the First-time wizard. Translation of these items is considered -// lower-priority to most other messages; but equal or higher priority to tooltips. +// !Wizard Key-based translation of a heading, checkbox item, description, or other text +// associated with the First-time wizard. Translation of these items is considered +// lower-priority to most other messages; but equal or higher priority to ContextTips. // -// .Tooltip: Key-based translation of a tooltip for a control on a dialog/panel. Translation -// of these items is typically considered "lowest priority" as they usually provide -// the most tertiary of info to the user. +// !ContextTip: Key-based translation of a tooltip for a control on a dialog/panel. Translation +// of these items is typically considered "lowest priority" as they usually provide +// only tertiary (extra) info to the user. // -#define pxE(key, english) pxExpandMsg( wxT(key), english ) +#define pxE(key, english) pxExpandMsg( wxT(key), english ) + +// For use with tertiary translations (low priority). +#define pxEt(key, english) pxExpandMsg( wxT(key), english ) + +// For use with Dev/debug build translations (low priority). +#define pxE_dev(key, english) pxExpandMsg( wxT(key), english ) + + +extern const wxChar* __fastcall pxExpandMsg( const wxChar* key, const wxChar* englishContent ); +extern const wxChar* __fastcall pxGetTranslation( const wxChar* message ); +extern bool pxIsEnglish( int id ); + +extern wxString fromUTF8( const char* src ); +extern wxString fromAscii( const char* src ); + #include "Utilities/Assertions.h" #include "Utilities/Exceptions.h" diff --git a/common/include/Utilities/Exceptions.h b/common/include/Utilities/Exceptions.h index dd0a1610f9..24d5620989 100644 --- a/common/include/Utilities/Exceptions.h +++ b/common/include/Utilities/Exceptions.h @@ -184,7 +184,7 @@ public: \ // an App message loop we'll still want it to be handled in a reasonably graceful manner. class CancelEvent : public RuntimeError { - DEFINE_RUNTIME_EXCEPTION( CancelEvent, RuntimeError, wxLt("No reason given.") ) + DEFINE_RUNTIME_EXCEPTION( CancelEvent, RuntimeError, pxLt("No reason given.") ) public: explicit CancelEvent( const wxString& logmsg ) @@ -223,7 +223,7 @@ public: \ class ParseError : public RuntimeError { - DEFINE_RUNTIME_EXCEPTION( ParseError, RuntimeError, wxLt("Parse error") ); + DEFINE_RUNTIME_EXCEPTION( ParseError, RuntimeError, pxL("Parse error") ); }; // --------------------------------------------------------------------------------------- @@ -247,7 +247,7 @@ public: \ class HardwareDeficiency : public RuntimeError { public: - DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, RuntimeError, wxLt("Your machine's hardware is incapable of running PCSX2. Sorry dood.") ); + DEFINE_RUNTIME_EXCEPTION( HardwareDeficiency, RuntimeError, pxL("Your machine's hardware is incapable of running PCSX2. Sorry dood.") ); }; // --------------------------------------------------------------------------------------- diff --git a/common/include/Utilities/General.h b/common/include/Utilities/General.h index d405f9472d..54e0afd373 100644 --- a/common/include/Utilities/General.h +++ b/common/include/Utilities/General.h @@ -251,5 +251,6 @@ namespace HostSys extern void InitCPUTicks(); extern u64 GetTickFrequency(); extern u64 GetCPUTicks(); +extern u64 GetPhysicalMemory(); extern wxString GetOSVersionString(); diff --git a/common/include/Utilities/ScopedAlloc.h b/common/include/Utilities/ScopedAlloc.h index 285e6c39b4..749f1c3ad1 100644 --- a/common/include/Utilities/ScopedAlloc.h +++ b/common/include/Utilities/ScopedAlloc.h @@ -195,16 +195,16 @@ public: this->m_buffer = (T*)malloc( this->m_size * sizeof(T) ); if (!this->m_buffer) - throw Exception::OutOfMemory("ScopedAlloc"); + throw Exception::OutOfMemory(L"ScopedAlloc"); } virtual void Resize( size_t newsize ) { this->m_size = newsize; - this->m_buffer = (T*)realloc(this->m_buffer * sizeof(T), newsize); + this->m_buffer = (T*)realloc(this->m_buffer, this->m_size * sizeof(T)); if (!this->m_buffer) - throw Exception::OutOfMemory("ScopedAlloc::Resize"); + throw Exception::OutOfMemory(L"ScopedAlloc::Resize"); } }; diff --git a/common/include/Utilities/pxEvents.h b/common/include/Utilities/pxEvents.h index c4c1c2f9fd..d07894e609 100644 --- a/common/include/Utilities/pxEvents.h +++ b/common/include/Utilities/pxEvents.h @@ -233,7 +233,8 @@ protected: m_Close :1; BITFIELD_END - wxString m_CustomLabel; + wxString m_CustomLabel; + wxString m_CustomLabelId; public: MsgButtons() { bitset = 0; } @@ -251,9 +252,12 @@ public: MsgButtons& Reset() { m_Reset = true; return *this; } MsgButtons& Close() { m_Close = true; return *this; } - MsgButtons& Custom( const wxString& label) + // label - native language label displayed to user + // id - raw ASCII identifier used in the config file (do not translate, hence char*) + MsgButtons& Custom( const wxString& label, const char* id ) { m_CustomLabel = label; + m_CustomLabelId = fromUTF8(id); return *this; } @@ -274,7 +278,8 @@ public: bool HasClose() const { return m_Close; } bool HasCustom() const { return !m_CustomLabel.IsEmpty(); } - const wxString& GetCustomLabel() const { return m_CustomLabel; } + const wxString& GetCustomLabel() const { return m_CustomLabel; } + const wxString& GetCustomLabelId() const { return m_CustomLabelId; } bool Allows( wxWindowID id ) const; void SetBestFocus( wxWindow* dialog ) const; diff --git a/common/include/Utilities/pxStreams.h b/common/include/Utilities/pxStreams.h index 326965231e..d4a8117586 100644 --- a/common/include/Utilities/pxStreams.h +++ b/common/include/Utilities/pxStreams.h @@ -15,6 +15,8 @@ #pragma once +#include "wx/filefn.h" + // -------------------------------------------------------------------------------------- // pxStreamBase // -------------------------------------------------------------------------------------- @@ -36,7 +38,10 @@ public: // or wxOputStream derivative). virtual wxStreamBase* GetWxStreamBase() const=0; virtual void Close()=0; - + virtual wxFileOffset Tell() const=0; + virtual wxFileOffset Seek( wxFileOffset ofs, wxSeekMode mode = wxFromStart )=0; + + virtual wxFileOffset Length() const; bool IsOk() const; wxString GetStreamName() const { return m_filename; } }; @@ -71,6 +76,9 @@ public: { Write( &data, sizeof(data) ); } + + wxFileOffset Tell() const; + wxFileOffset Seek( wxFileOffset ofs, wxSeekMode mode = wxFromStart ); }; // -------------------------------------------------------------------------------------- @@ -102,4 +110,7 @@ public: { Read( &dest, sizeof(dest) ); } + + wxFileOffset Tell() const; + wxFileOffset Seek( wxFileOffset ofs, wxSeekMode mode = wxFromStart ); }; diff --git a/common/include/Utilities/wxGuiTools.h b/common/include/Utilities/wxGuiTools.h index 51940ce6b1..1a07be0ff6 100644 --- a/common/include/Utilities/wxGuiTools.h +++ b/common/include/Utilities/wxGuiTools.h @@ -522,6 +522,7 @@ public: // -------------------------------------------------------------------------------------- class wxDialogWithHelpers : public wxDialog { + typedef wxDialog _parent; DECLARE_DYNAMIC_CLASS_NO_COPY(wxDialogWithHelpers) protected: @@ -541,6 +542,7 @@ public: virtual void SmartCenterFit(); virtual int ShowModal(); virtual bool Show( bool show=true ); + virtual bool Destroy(); // Must return the same thing as GetNameStatic; a name ideal for use in uniquely // identifying dialogs. (this version is the 'instance' version, which is called diff --git a/common/include/x86emitter/tools.h b/common/include/x86emitter/tools.h index 3520db5075..6fd8aa8d23 100644 --- a/common/include/x86emitter/tools.h +++ b/common/include/x86emitter/tools.h @@ -31,8 +31,6 @@ class x86capabilities { public: bool isIdentified; - u32 LogicalCoresPerPhysicalCPU; - u32 PhysicalCoresPerPhysicalCPU; public: x86VendorType VendorID; @@ -106,8 +104,6 @@ public: { isIdentified = false; VendorID = x86Vendor_Unknown; - LogicalCoresPerPhysicalCPU = 1; - PhysicalCoresPerPhysicalCPU = 1; } void Identify(); diff --git a/common/src/Utilities/Exceptions.cpp b/common/src/Utilities/Exceptions.cpp index 65670f0e19..2d4207e66e 100644 --- a/common/src/Utilities/Exceptions.cpp +++ b/common/src/Utilities/Exceptions.cpp @@ -251,7 +251,7 @@ wxString Exception::VirtualMemoryMapConflict::FormatDisplayMessage() const { FastFormatUnicode retmsg; retmsg.Write( L"%s", - pxE( ".Error:VirtualMemoryMap", + pxE( "!Notice:VirtualMemoryMap", L"There is not enough virtual memory available, or necessary virtual memory " L"mappings have already been reserved by other processes, services, or DLLs." ) diff --git a/common/src/Utilities/Linux/LnxHostSys.cpp b/common/src/Utilities/Linux/LnxHostSys.cpp index a92c2475fc..ffacbc9232 100644 --- a/common/src/Utilities/Linux/LnxHostSys.cpp +++ b/common/src/Utilities/Linux/LnxHostSys.cpp @@ -167,9 +167,9 @@ void HostSys::MmapResetPtr(void* base, size_t size) // pretty well stops all PCSX2 threads anyway). Munmap(base, size); - void* result = Mmap((uptr)base, size); + void* result = MmapReservePtr(base, size); - pxAssertRel ((uptr)result != (uptr)base, pxsFmt( + pxAssertRel ((uptr)result == (uptr)base, pxsFmt( "Virtual memory decommit failed: memory at 0x%08X -> 0x%08X could not be remapped. " "This is likely caused by multi-thread memory contention.", base, (uptr)base+size )); diff --git a/common/src/Utilities/Linux/LnxMisc.cpp b/common/src/Utilities/Linux/LnxMisc.cpp index f3c00b4d52..f2e11f442a 100644 --- a/common/src/Utilities/Linux/LnxMisc.cpp +++ b/common/src/Utilities/Linux/LnxMisc.cpp @@ -20,11 +20,18 @@ #include #include -extern "C" __aligned16 u8 _xmm_backup[16*2]; -extern "C" __aligned16 u8 _mmx_backup[8*4]; +// Returns 0 on failure (not supported by the operating system). +u64 GetPhysicalMemory() +{ + u64 pages = 0; + +#ifdef _SC_PHYS_PAGES + pages = sysconf(_SC_PHYS_PAGES); +#endif + + return pages * getpagesize(); +} -u8 _xmm_backup[16*2]; -u8 _mmx_backup[8*4]; void InitCPUTicks() { diff --git a/common/src/Utilities/ThreadTools.cpp b/common/src/Utilities/ThreadTools.cpp index 70a70d8cd2..3dd34302eb 100644 --- a/common/src/Utilities/ThreadTools.cpp +++ b/common/src/Utilities/ThreadTools.cpp @@ -38,7 +38,7 @@ ConsoleLogSource_Threading::ConsoleLogSource_Threading() static const TraceLogDescriptor myDesc = { L"pxThread", L"pxThread", - wxLt("Threading activity: start, detach, sync, deletion, etc.") + pxLt("Threading activity: start, detach, sync, deletion, etc.") }; m_Descriptor = &myDesc; diff --git a/common/src/Utilities/Windows/WinHostSys.cpp b/common/src/Utilities/Windows/WinHostSys.cpp index d35b258246..f010aeec93 100644 --- a/common/src/Utilities/Windows/WinHostSys.cpp +++ b/common/src/Utilities/Windows/WinHostSys.cpp @@ -19,6 +19,7 @@ #include + int SysPageFaultExceptionFilter( EXCEPTION_POINTERS* eps ) { if( eps->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION ) diff --git a/common/src/Utilities/Windows/WinMisc.cpp b/common/src/Utilities/Windows/WinMisc.cpp index 07885b994f..89a03d08f4 100644 --- a/common/src/Utilities/Windows/WinMisc.cpp +++ b/common/src/Utilities/Windows/WinMisc.cpp @@ -39,6 +39,14 @@ u64 GetCPUTicks() return count.QuadPart; } +u64 GetPhysicalMemory() +{ + MEMORYSTATUSEX status; + status.dwLength = sizeof(status); + GlobalMemoryStatusEx(&status); + return status.ullTotalPhys; +} + // Windows SDK 7 provides this but previous ones do not, so roll our own in those cases: #ifndef VER_SUITE_WH_SERVER # define VER_SUITE_WH_SERVER 0x00008000 diff --git a/common/src/Utilities/pxStreams.cpp b/common/src/Utilities/pxStreams.cpp index 00eed7a253..cb949072b3 100644 --- a/common/src/Utilities/pxStreams.cpp +++ b/common/src/Utilities/pxStreams.cpp @@ -35,6 +35,12 @@ bool pxStreamBase::IsOk() const return woot && woot->IsOk(); } +wxFileOffset pxStreamBase::Length() const +{ + if (!GetWxStreamBase()) return 0; + return GetWxStreamBase()->GetLength(); +} + // -------------------------------------------------------------------------------------- // pxInputStream (implementations) // -------------------------------------------------------------------------------------- @@ -55,6 +61,16 @@ pxInputStream::pxInputStream(const wxString& filename, wxInputStream* input) wxStreamBase* pxInputStream::GetWxStreamBase() const { return m_stream_in.GetPtr(); } +wxFileOffset pxInputStream::Tell() const +{ + return m_stream_in->TellI(); +} + +wxFileOffset pxInputStream::Seek( wxFileOffset ofs, wxSeekMode mode ) +{ + return m_stream_in->SeekI(ofs, mode); +} + void pxInputStream::SetStream( const wxString& filename, ScopedPtr& stream ) { m_filename = filename; @@ -107,6 +123,15 @@ pxOutputStream::pxOutputStream(const wxString& filename, wxOutputStream* output) wxStreamBase* pxOutputStream::GetWxStreamBase() const { return m_stream_out.GetPtr(); } +wxFileOffset pxOutputStream::Tell() const +{ + return m_stream_out->TellO(); +} + +wxFileOffset pxOutputStream::Seek( wxFileOffset ofs, wxSeekMode mode ) +{ + return m_stream_out->SeekO( ofs, mode ); +} void pxOutputStream::SetStream( const wxString& filename, ScopedPtr& stream ) { diff --git a/common/src/Utilities/pxTranslate.cpp b/common/src/Utilities/pxTranslate.cpp index 80e53950af..17e192b13e 100644 --- a/common/src/Utilities/pxTranslate.cpp +++ b/common/src/Utilities/pxTranslate.cpp @@ -32,20 +32,25 @@ bool pxIsEnglish( int id ) // (without this second pass many tooltips would just show up as "Savestate Tooltip" instead // of something meaningful). // -// Rationale: Traditional gnu-style gnu_gettext stuff tends to stop translating strings when +// Rationale: Traditional gnu-style gettext stuff tends to stop translating strings when // the slightest change to a string is made (including punctuation and possibly even case). // On long strings especially, this can be unwanted since future revisions of the app may have -// simple tyop fixes that *should not* break existing translations. Furthermore +// simple typo or newline fixes that *should not* break existing translations. Furthermore, +// icons can be used in places where otherwise identical english verbage for two separate +// terms can be differentiated. GNU gettext has some new tools for using fuzzy logic heuristics +// matching, but it is also imperfect and complicated, so we have opted to continue using this +// system instead. +// const wxChar* __fastcall pxExpandMsg( const wxChar* key, const wxChar* englishContent ) { #ifdef PCSX2_DEVBUILD static const wxChar* tbl_pxE_Prefixes[] = { - L".Panel:", - L".Popup:", - L".Error:", - L".Wizard:", - L".Tooltip:", + L"!Panel:", + L"!Notice:", + L"!Wizard:", + L"!Tooltip:", + L"!ContextTip:", NULL }; @@ -57,7 +62,7 @@ const wxChar* __fastcall pxExpandMsg( const wxChar* key, const wxChar* englishCo ++prefix; } pxAssertDev( *prefix != NULL, - wxsFormat( L"Invalid pxE key prefix in key '%s'. Prefix must be one of the valid prefixes listed in pxExpandMsg.", key ) + pxsFmt( L"Invalid pxE key prefix in key '%s'. Prefix must be one of the valid prefixes listed in pxExpandMsg.", key ) ); #endif diff --git a/common/src/Utilities/wxAppWithHelpers.cpp b/common/src/Utilities/wxAppWithHelpers.cpp index 7821454cb5..a0a174bae7 100644 --- a/common/src/Utilities/wxAppWithHelpers.cpp +++ b/common/src/Utilities/wxAppWithHelpers.cpp @@ -33,7 +33,7 @@ ConsoleLogSource_App::ConsoleLogSource_App() static const TraceLogDescriptor myDesc = { L"AppEvents", L"App Events", - wxLt("Includes idle event processing and some other uncommon event usages.") + pxLt("Includes idle event processing and some other uncommon event usages.") }; m_Descriptor = &myDesc; diff --git a/common/src/Utilities/wxHelpers.cpp b/common/src/Utilities/wxHelpers.cpp index d70d173c54..b032d31ba7 100644 --- a/common/src/Utilities/wxHelpers.cpp +++ b/common/src/Utilities/wxHelpers.cpp @@ -274,13 +274,13 @@ pxStaticText& wxDialogWithHelpers::Heading( const wxString& label ) return *new pxStaticHeading( this, label ); } -void wxDialogWithHelpers::OnCloseWindow( wxCloseEvent& evt ) +bool wxDialogWithHelpers::Destroy() { // Save the dialog position if the dialog is named... // FIXME : This doesn't get called if the app is exited by alt-f4'ing the main app window. // ... not sure how to fix that yet. I could register a list of open windows into wxAppWithHelpers // that systematically get closed. Seems like work, maybe later. --air - + if( wxConfigBase* cfg = IsIconized() ? NULL : wxConfigBase::Get( false ) ) { const wxString dlgName( GetDialogName() ); @@ -300,6 +300,11 @@ void wxDialogWithHelpers::OnCloseWindow( wxCloseEvent& evt ) } } + return _parent::Destroy(); +} + +void wxDialogWithHelpers::OnCloseWindow( wxCloseEvent& evt ) +{ if( !IsModal() ) Destroy(); evt.Skip(); } diff --git a/common/src/Utilities/x86/MemcpyVibes.cpp b/common/src/Utilities/x86/MemcpyVibes.cpp index 33d2664f09..e3b99b63af 100644 --- a/common/src/Utilities/x86/MemcpyVibes.cpp +++ b/common/src/Utilities/x86/MemcpyVibes.cpp @@ -183,11 +183,11 @@ __fi void memcpy_vibes(void * dest, const void * src, int size) { __asm__ __volatile__ ( ".intel_syntax noprefix\n" - "mov eax, %[qwc]\n" // keep a copy of count for looping - "shr eax, 1\n" - "jz memcpy_qwc_1_%=\n" // only one 16 byte block to copy? + "sub %[qwc], 1\n" // dec the counter to ease the count of 16bytes block later (optimization) + // Note after this line, real value of the counter is %[qwc] + 1 + "jle memcpy_qwc_1_%=\n" // only one 16 byte block to copy? Or nothing. - "cmp eax, 64\n" // "IN_CACHE_COPY/32" + "cmp %[qwc], 127\n" // "IN_CACHE_COPY/16" "jb memcpy_qwc_loop1_%=\n" // small copies should be cached (definite speedup --air) "memcpy_qwc_loop2_%=:\n" // 32-byte blocks, uncached copy @@ -204,8 +204,8 @@ __fi void memcpy_vibes(void * dest, const void * src, int size) { "add %[src],32\n" // update source pointer "add %[dest],32\n" // update destination pointer - "sub eax,1\n" - "jnz memcpy_qwc_loop2_%=\n" // last 64-byte block? + "sub %[qwc],2\n" + "jg memcpy_qwc_loop2_%=\n" // last 64-byte block? "sfence\n" // flush the write buffer "jmp memcpy_qwc_1_%=\n" @@ -227,12 +227,12 @@ __fi void memcpy_vibes(void * dest, const void * src, int size) { "add %[src],32\n" // update source pointer "add %[dest],32\n" // update destination pointer - "sub eax,1\n" - "jnz memcpy_qwc_loop1_%=\n" // last 64-byte block? + "sub %[qwc],2\n" + "jg memcpy_qwc_loop2_%=\n" // last 64-byte block? "memcpy_qwc_1_%=:\n" - "test %[qwc],1\n" - "jz memcpy_qwc_final_%=\n" + "cmp %[qwc],0\n" + "jne memcpy_qwc_final_%=\n" "movq mm0,[%[src]]\n" "movq mm1,[%[src]+8]\n" "movq [%[dest]], mm0\n" @@ -243,7 +243,7 @@ __fi void memcpy_vibes(void * dest, const void * src, int size) { ".att_syntax\n" : "=&r"(dest), "=&r"(src), "=&r"(qwc) : [dest]"0"(dest), [src]"1"(src), [qwc]"2"(qwc) - : "memory", "eax", "mm0", "mm1", "mm2", "mm3" + : "memory", "mm0", "mm1", "mm2", "mm3" ); } #endif diff --git a/common/src/x86emitter/LnxCpuDetect.cpp b/common/src/x86emitter/LnxCpuDetect.cpp index e79cd37685..5c3c8c36a2 100644 --- a/common/src/x86emitter/LnxCpuDetect.cpp +++ b/common/src/x86emitter/LnxCpuDetect.cpp @@ -16,24 +16,16 @@ #include "PrecompiledHeader.h" #include "cpudetect_internal.h" +#include // Note: Apparently this solution is Linux/Solaris only. // FreeBSD/OsX need something far more complicated (apparently) void x86capabilities::CountLogicalCores() { - const uint numCPU = sysconf( _SC_NPROCESSORS_ONLN ); - if( numCPU > 0 ) - { - //isMultiCore = numCPU > 1; - LogicalCores = numCPU; - PhysicalCores = ( numCPU / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU; - } - else - { - // Indeterminate? - LogicalCores = 1; - PhysicalCores = 1; - } + // Note : GetCPUCount uses sysconf( _SC_NPROCESSORS_ONLN ) internally, which can return 1 + // if sysconf info isn't available (a long standing linux bug). There are no fallbacks or + // alternatives, apparently. + LogicalCores = wxThread::GetCPUCount(); } bool CanEmitShit() diff --git a/common/src/x86emitter/WinCpuDetect.cpp b/common/src/x86emitter/WinCpuDetect.cpp index 02899fef43..7a952e5e6d 100644 --- a/common/src/x86emitter/WinCpuDetect.cpp +++ b/common/src/x86emitter/WinCpuDetect.cpp @@ -37,10 +37,6 @@ void x86capabilities::CountLogicalCores() } LogicalCores = CPUs; - if( LogicalCoresPerPhysicalCPU > CPUs) // for 1-socket HTT-disabled machines - LogicalCoresPerPhysicalCPU = CPUs; - - PhysicalCores = ( CPUs / LogicalCoresPerPhysicalCPU ) * PhysicalCoresPerPhysicalCPU; } bool _test_instruction( void* pfnCall ) diff --git a/common/src/x86emitter/cpudetect.cpp b/common/src/x86emitter/cpudetect.cpp index 95928cf85b..bca8cb6a1f 100644 --- a/common/src/x86emitter/cpudetect.cpp +++ b/common/src/x86emitter/cpudetect.cpp @@ -133,23 +133,6 @@ void x86capabilities::CountCores() s32 regs[ 4 ]; u32 cmds; - LogicalCoresPerPhysicalCPU = 0; - PhysicalCoresPerPhysicalCPU = 1; - - // detect multicore for Intel cpu - - __cpuid( regs, 0 ); - cmds = regs[ 0 ]; - - if( cmds >= 0x00000001 ) - LogicalCoresPerPhysicalCPU = ( regs[1] >> 16 ) & 0xff; - - if ((cmds >= 0x00000004) && (VendorID == x86Vendor_Intel)) - { - __cpuid( regs, 0x00000004 ); - PhysicalCoresPerPhysicalCPU += ( regs[0] >> 26) & 0x3f; - } - __cpuid( regs, 0x80000000 ); cmds = regs[ 0 ]; @@ -157,9 +140,6 @@ void x86capabilities::CountCores() if ((cmds >= 0x80000008) && (VendorID == x86Vendor_AMD) ) { - __cpuid( regs, 0x80000008 ); - PhysicalCoresPerPhysicalCPU += ( regs[2] ) & 0xff; - // AMD note: they don't support hyperthreading, but they like to flag this true // anyway. Let's force-unflag it until we come up with a better solution. // (note: seems to affect some Phenom II's only? -- Athlon X2's and PhenomI's do @@ -167,9 +147,6 @@ void x86capabilities::CountCores() hasMultiThreading = 0; } - if( !hasMultiThreading || LogicalCoresPerPhysicalCPU == 0 ) - LogicalCoresPerPhysicalCPU = 1; - // This will assign values into LogicalCores and PhysicalCores CountLogicalCores(); } diff --git a/debian-unstable-upstream/create_pcsx2_tarball_from_svn_repository.sh b/debian-unstable-upstream/create_pcsx2_tarball_from_svn_repository.sh index fbf633efa4..7e234048ce 100755 --- a/debian-unstable-upstream/create_pcsx2_tarball_from_svn_repository.sh +++ b/debian-unstable-upstream/create_pcsx2_tarball_from_svn_repository.sh @@ -122,9 +122,6 @@ find $NEW_DIR -name "configure.ac" -exec rm -f {} \; find $NEW_DIR -name "Makefile.am" -exec rm -f {} \; echo "Remove 3rd party directories" find $NEW_DIR -name "3rdparty" -exec rm -fr {} \; 2> /dev/null -# I really need to clean this mess one day -# echo "Remove plugins/zzogl-pg/opengl/ZeroGSShaders (some zlib source in the middle)" -# rm -fr $NEW_DIR/plugins/zzogl-pg/opengl/ZeroGSShaders echo "Remove windows file (useless & copyright issue)" find $NEW_DIR -iname "windows" -type d -exec rm -fr {} \; 2> /dev/null find $NEW_DIR -name "Win32" -type d -exec rm -fr {} \; 2> /dev/null @@ -134,7 +131,6 @@ rm -fr "${NEW_DIR}/common/vsprops" echo "Remove useless files (copyright issues)" rm -fr "${NEW_DIR}/plugins/zzogl-pg/opengl/ZeroGSShaders" rm -fr "${NEW_DIR}/common/src/Utilities/x86/MemcpyFast.cpp" -rm -fr "${NEW_DIR}/plugins/zzogl-pg/opengl/memcpy_amd.cpp" ## BUILD echo "Build the tar.gz file" diff --git a/debian-unstable-upstream/patches/21_use_legacy_soundtouch_13.patch b/debian-unstable-upstream/patches/21_use_legacy_soundtouch_13.patch deleted file mode 100644 index 3898e78d4c..0000000000 --- a/debian-unstable-upstream/patches/21_use_legacy_soundtouch_13.patch +++ /dev/null @@ -1,176 +0,0 @@ -This patch removes recording feature beacause it needs libsoundtouch > 1.4. -Howerever only the version 1.3 is in debian. Unfortunately the package seems -to be not actively maintained. -Note it also correct the inlude path. -Index: pcsx2.snapshot-3369/plugins/spu2-x/src/Wavedump_wav.cpp -=================================================================== ---- pcsx2.snapshot-3369.orig/plugins/spu2-x/src/Wavedump_wav.cpp -+++ pcsx2.snapshot-3369/plugins/spu2-x/src/Wavedump_wav.cpp -@@ -16,16 +16,22 @@ - */ - - #include "Global.h" -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - #include "soundtouch/WavFile.h" -+#endif - -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - static WavOutFile* _new_WavOutFile( const char* destfile ) - { - return new WavOutFile( destfile, 48000, 16, 2 ); - } -+#endif - - namespace WaveDump - { -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - static WavOutFile* m_CoreWav[2][CoreSrc_Count] = { NULL }; -+#endif - - static const char* m_tbl_CoreOutputTypeNames[CoreSrc_Count] = - { -@@ -42,6 +48,7 @@ - if( !IsDevBuild ) return; - if( !WaveLog() ) return; - -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - char wavfilename[256]; - - for( uint cidx=0; cidx<2; cidx++ ) -@@ -68,11 +75,13 @@ - } - } - } -+#endif - } - - void Close() - { - if( !IsDevBuild ) return; -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - for( uint cidx=0; cidx<2; cidx++ ) - { - for( int srcidx=0; srcidx= 10400) - if( m_CoreWav[coreidx][src] != NULL ) - m_CoreWav[coreidx][src]->write( (s16*)&sample, 2 ); -+#endif - } - - void WriteCore( uint coreidx, CoreSourceType src, s16 left, s16 right ) -@@ -101,11 +113,14 @@ - - bool WavRecordEnabled = false; - -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - static WavOutFile* m_wavrecord = NULL; -+#endif - static Mutex WavRecordMutex; - - void RecordStart() - { -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - WavRecordEnabled = false; - - try -@@ -120,18 +135,23 @@ - m_wavrecord = NULL; // not needed, but what the heck. :) - SysMessage("SPU2-X couldn't open file for recording: %s.\nRecording to wavfile disabled.", "recording.wav"); - } -+#endif - } - - void RecordStop() - { -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - WavRecordEnabled = false; - ScopedLock lock( WavRecordMutex ); - safe_delete( m_wavrecord ); -+#endif - } - - void RecordWrite( const StereoOut16& sample ) - { -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - ScopedLock lock( WavRecordMutex ); - if( m_wavrecord == NULL ) return; - m_wavrecord->write( (s16*)&sample, 2 ); -+#endif - } -Index: pcsx2.snapshot-3369/plugins/zerospu2/zerospu2.cpp -=================================================================== ---- pcsx2.snapshot-3369.orig/plugins/zerospu2/zerospu2.cpp -+++ pcsx2.snapshot-3369/plugins/zerospu2/zerospu2.cpp -@@ -28,7 +28,9 @@ - #include - - #include "soundtouch/SoundTouch.h" -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - #include "soundtouch/WavFile.h" -+#endif - - char libraryName[256]; - -@@ -74,7 +76,9 @@ - - // time stretch variables - soundtouch::SoundTouch* pSoundTouch=NULL; -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - extern WavOutFile* g_pWavRecord; // used for recording -+#endif - - u64 s_GlobalTimeStamp = 0; - s32 s_nDurations[64]={0}; -@@ -361,7 +365,9 @@ - - RemoveSound(); - -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - delete g_pWavRecord; g_pWavRecord = NULL; -+#endif - delete pSoundTouch; pSoundTouch = NULL; - - for (u32 i = 0; i < ArraySize(s_pAudioBuffers); ++i) -Index: pcsx2.snapshot-3369/plugins/zerospu2/zeroworker.cpp -=================================================================== ---- pcsx2.snapshot-3369.orig/plugins/zerospu2/zeroworker.cpp -+++ pcsx2.snapshot-3369/plugins/zerospu2/zeroworker.cpp -@@ -19,10 +19,14 @@ - #include "zerospu2.h" - #include "zeroworker.h" - #include "soundtouch/SoundTouch.h" -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - #include "soundtouch/WavFile.h" -+#endif - - s32 g_logsound = 0; -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - WavOutFile* g_pWavRecord=NULL; // used for recording -+#endif - - const s32 f[5][2] = { - { 0, 0 }, -@@ -302,6 +306,7 @@ - - void LogRawSound(void* pleft, s32 leftstride, void* pright, s32 rightstride, s32 numsamples) - { -+#if defined(SOUNDTOUCH_VERSION_ID) & (SOUNDTOUCH_VERSION_ID >= 10400) - if (g_pWavRecord == NULL ) - g_pWavRecord = new WavOutFile(RECORD_FILENAME, SAMPLE_RATE, 16, 2); - -@@ -320,4 +325,5 @@ - } - - g_pWavRecord->write(&tempbuf[0], numsamples*2); -+#endif - } diff --git a/debian-unstable-upstream/patches/series b/debian-unstable-upstream/patches/series index a09286c9f4..ca3eb71490 100644 --- a/debian-unstable-upstream/patches/series +++ b/debian-unstable-upstream/patches/series @@ -1,4 +1,3 @@ 01_rename_binary_generated.patch 02_update_default_path.patch 05_move_data_to_config.patch -21_use_legacy_soundtouch_13.patch diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index 36ab6672c8..cd13aed5bc 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -382,7 +382,7 @@ void cdvdReloadElfInfo(wxString elfoverride) if (!ENABLE_LOADING_PS1_GAMES) Cpu->ThrowException( Exception::RuntimeError() .SetDiagMsg(L"PSX game discs are not supported by PCSX2.") - .SetUserMsg(pxE( "Error:PsxDisc", + .SetUserMsg(pxE( "!Notice:PsxDisc", L"Playstation game discs are not supported by PCSX2. If you want to emulate PSX games " L"then you'll have to download a PSX-specific emulator, such as ePSXe or PCSX.") ) diff --git a/pcsx2/CDVD/IsoFileFormats.cpp b/pcsx2/CDVD/IsoFileFormats.cpp index a389123b27..aaa52b5460 100644 --- a/pcsx2/CDVD/IsoFileFormats.cpp +++ b/pcsx2/CDVD/IsoFileFormats.cpp @@ -411,7 +411,9 @@ void isoFile::Open( const wxString& srcfile ) // (and if numparts is incremented, elsn will get assigned accordingly) if (!Detect()) - throw Exception::BadStream().SetUserMsg(wxLt("Unrecognized ISO file format.")); + throw Exception::BadStream() + .SetUserMsg(L"Unrecognized ISO image file format") + .SetDiagMsg(_("ISO mounting failed: PCSX2 is unable to identify the ISO image type.")); if (!(m_flags & ISOFLAGS_BLOCKDUMP_V2)) { diff --git a/pcsx2/CMakeLists.txt b/pcsx2/CMakeLists.txt index cdbbc3342a..dd636f6de1 100644 --- a/pcsx2/CMakeLists.txt +++ b/pcsx2/CMakeLists.txt @@ -274,7 +274,6 @@ set(pcsx2DebugToolsHeaders # gui sources set(pcsx2GuiSources - gui/AdvancedDialog.cpp gui/AppAssert.cpp gui/AppConfig.cpp gui/AppCorePlugins.cpp @@ -338,7 +337,6 @@ set(pcsx2GuiSources # gui headers set(pcsx2GuiHeaders - gui/AdvancedDialog.h gui/App.h gui/ApplyState.h gui/AppAccelerators.h diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 2ae5623b3a..87de792d71 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -400,7 +400,7 @@ struct Pcsx2Config // when enabled uses BOOT2 injection, skipping sony bios splashes UseBOOT2Injection :1, - + BackupSavestate :1, // enables simulated ejection of memory cards when loading savestates McdEnableEjection :1, diff --git a/pcsx2/Dmac.h b/pcsx2/Dmac.h index d22145677f..9dededbe0d 100644 --- a/pcsx2/Dmac.h +++ b/pcsx2/Dmac.h @@ -556,7 +556,9 @@ extern tDMA_TAG *dmaGetAddr(u32 addr, bool write); extern void hwIntcIrq(int n); extern void hwDmacIrq(int n); +extern void FireMFIFOEmpty(); extern bool hwMFIFOWrite(u32 addr, const u128* data, uint size_qwc); +extern void hwDmacSrcTadrInc(DMACh& dma); extern bool hwDmacSrcChainWithStack(DMACh& dma, int id); extern bool hwDmacSrcChain(DMACh& dma, int id); diff --git a/pcsx2/Elfheader.cpp b/pcsx2/Elfheader.cpp index 5a820bf830..4b6c402b08 100644 --- a/pcsx2/Elfheader.cpp +++ b/pcsx2/Elfheader.cpp @@ -260,16 +260,26 @@ void ElfObject::readFile() if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename); } +static wxString GetMsg_InvalidELF() +{ + return + _("Cannot load ELF binary image. The file may be corrupt or incomplete.") + + wxString(L"\n\n") + + _("If loading from an ISO image, this error may be caused by an unsupported ISO image type or bug in PCSX2 ISO image support."); +} + + void ElfObject::checkElfSize(s64 elfsize) { - if (elfsize > 0xfffffff) - throw Exception::BadStream(filename).SetBothMsgs(wxLt("Illegal ELF file size over 2GB!")); + const wxChar* diagMsg = NULL; + if (elfsize > 0xfffffff) diagMsg = L"Illegal ELF file size over 2GB!"; + else if (elfsize == -1) diagMsg = L"ELF file does not exist!"; + else if (elfsize == 0) diagMsg = L"Unexpected end of ELF file."; - if (elfsize == -1) - throw Exception::BadStream(filename).SetBothMsgs(wxLt("ELF file does not exist!")); - - if (elfsize == 0) - throw Exception::BadStream(filename).SetBothMsgs(wxLt("Unexpected end of ELF file.")); + if (diagMsg) + throw Exception::BadStream(filename) + .SetDiagMsg(diagMsg) + .SetUserMsg(GetMsg_InvalidELF()); } u32 ElfObject::getCRC() diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index b6dd611119..d56e9dac5d 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -27,7 +27,6 @@ using std::min; // A three-way toggle used to determine if the GIF is stalling (transferring) or done (finished). // Should be a gifstate_t rather then int, but I don't feel like possibly interfering with savestates right now. static int gifstate = GIF_STATE_READY; -static bool gifempty = false; static bool gspath3done = false; @@ -47,14 +46,14 @@ static __fi void clearFIFOstuff(bool full) else CSRreg.FIFO = CSR_FIFO_EMPTY; } - +extern bool SIGNAL_IMR_Pending; void gsPath1Interrupt() { //DevCon.Warning("Path1 flush W %x, R %x", Path1WritePos, Path1ReadPos); - if((gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.IP3 == true && gifRegs.stat.APATH == GIF_APATH3)) && Path1WritePos > 0 && !gifRegs.stat.PSE) + if((gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.IP3 == true && gifRegs.stat.APATH == GIF_APATH3)) && Path1WritePos > 0 && !gifRegs.stat.PSE && SIGNAL_IMR_Pending == false) { gifRegs.stat.P1Q = false; @@ -62,7 +61,7 @@ void gsPath1Interrupt() { GetMTGS().PrepDataPacket(GIF_PATH_1, size); //DevCon.Warning("Flush Size = %x", size); - while(size > 0) + while(size > 0 && SIGNAL_IMR_Pending == false) { uint count = GIFPath_CopyTag(GIF_PATH_1, ((u128*)Path1Buffer) + Path1ReadPos, size); Path1ReadPos += count; @@ -79,13 +78,18 @@ void gsPath1Interrupt() if(Path1ReadPos == Path1WritePos) { Path1WritePos = Path1ReadPos = 0; + } + else + { + //DevCon.Warning("Queue quitting early due to signal or EOP %x", size); + gifRegs.stat.P1Q = true; } } } else { if(gifRegs.stat.PSE) DevCon.Warning("Path1 paused by GIF_CTRL"); - DevCon.Warning("Looping??? IP3 %x APATH %x OPH %x", gifRegs.stat.IP3, gifRegs.stat.APATH, gifRegs.stat.OPH); + //DevCon.Warning("Looping??? IP3 %x APATH %x OPH %x", gifRegs.stat.IP3, gifRegs.stat.APATH, gifRegs.stat.OPH); //if(!(cpuRegs.interrupt & (1<<28)) && Path1WritePos > 0)CPU_INT(28, 128); } @@ -97,6 +101,13 @@ __fi void gsInterrupt() { GIF_LOG("gsInterrupt caught!"); + if (dmacRegs.ctrl.MFD == MFD_GIF) // GIF MFIFO + { + //Console.WriteLn("GIF MFIFO"); + gifMFIFOInterrupt(); + return; + } + if(SIGNAL_IMR_Pending == true) { //DevCon.Warning("Path 3 Paused"); @@ -234,6 +245,7 @@ bool CheckPaths(int Channel) { if((vif1.cmd & 0x7f) != 0x51 || gifRegs.stat.P1Q == true) { + //DevCon.Warning("GIF Stall 1 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); gifRegs.stat.IP3 = true; if(gifRegs.stat.P1Q) gsPath1Interrupt(); CPU_INT(DMAC_GIF, 16); @@ -246,6 +258,7 @@ bool CheckPaths(int Channel) //This should cover both scenarios, as DIRECTHL doesn't gain priority when image mode is running (PENDINGIMAGE_MODE == fininshed). if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true) || (gifRegs.stat.APATH > GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3)) { + //DevCon.Warning("GIF Stall 2 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); gifRegs.stat.IP3 = true; CPU_INT(DMAC_GIF, 16); return false; @@ -430,61 +443,90 @@ void dmaGIF() } } - if (dmacRegs.ctrl.MFD == MFD_GIF) // GIF MFIFO - { - //Console.WriteLn("GIF MFIFO"); - gifMFIFOInterrupt(); - return; - } + - GIFdma(); + gsInterrupt(); +} + +static u16 QWCinGIFMFIFO(u32 DrainADDR) +{ + u32 ret; + + + GIF_LOG("GIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", gifch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR); + //Calculate what we have in the fifo. + if(DrainADDR <= spr0ch.madr) + { + //Drain is below the tadr, calculate the difference between them + ret = (spr0ch.madr - DrainADDR) >> 4; + } + else + { + u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; + //Drain is higher than SPR so it has looped round, + //calculate from base to the SPR tag addr and what is left in the top of the ring + ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4; + } + GIF_LOG("%x Available of the %x requested", ret, gifch.qwc); + if((s32)ret < 0) DevCon.Warning("GIF Returning %x!", ret); + return ret; } // called from only one location, so forceinline it: static __fi bool mfifoGIFrbTransfer() { - u32 mfifoqwc = min(gifqwc, (u32)gifch.qwc); + u16 mfifoqwc = min(QWCinGIFMFIFO(gifch.madr), gifch.qwc); u32 *src; + if(mfifoqwc == 0) return true; //Lets skip all this, we don't have the data + GetMTGS().PrepDataPacket(GIF_PATH_3, mfifoqwc); // TODO (minor optimization): The new GIFpath parser can do rather efficient wrapping of // its own internally now. We just need to groom a version of it that can wrap around MFIFO // memory similarly to how it wraps VU1 memory on PATH1. - + GIF_LOG("MFIFO QWC to Transfer %x", mfifoqwc); /* Check if the transfer should wrap around the ring buffer */ - if ((gifch.madr + mfifoqwc * 16) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) + if ( (gifch.madr + (mfifoqwc * 16)) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) { uint s1 = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4; uint s2 = (mfifoqwc - s1); - + GIF_LOG("Split transfer doing %x QWC of %x Total QWC", s1, mfifoqwc); /* it does (wrap around), so first copy 's1' bytes from 'addr' to 'data' */ /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ - + + gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); src = (u32*)PSM(gifch.madr); if (src == NULL) return false; uint copied = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s1); if (copied == s1) // but only copy second if first didn't abort prematurely for some reason. { + GIF_LOG("Transferring last %x QWC", s2); src = (u32*)PSM(dmacRegs.rbor.ADDR); + gifch.madr = dmacRegs.rbor.ADDR; if (src == NULL) return false; copied += GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s2); } mfifoqwc = copied; + GIF_LOG("Copied %x QWC, %x QWC Left", mfifoqwc, gifch.qwc); } else { + GIF_LOG("Direct MFIFO transfer doing %x Total QWC", mfifoqwc); /* it doesn't, so just transfer 'qwc*16' words from 'gifch.madr' to GS */ + + gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); src = (u32*)PSM(gifch.madr); if (src == NULL) return false; mfifoqwc = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, mfifoqwc); - gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); + GIF_LOG("%X QWC Copied direct %x QWC Left", mfifoqwc, gifch.qwc); } GetMTGS().SendDataPacket(); - gifqwc -= mfifoqwc; + //gifqwc -= mfifoqwc; + mfifocycles += (mfifoqwc) * 2; /* guessing */ return true; } @@ -496,14 +538,19 @@ static __fi bool mfifoGIFchain() if (gifch.qwc == 0) return true; if (gifch.madr >= dmacRegs.rbor.ADDR && - gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)) + gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) { - if (!mfifoGIFrbTransfer()) return false; + bool ret = true; + // if(gifch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge GIF"); + if (!mfifoGIFrbTransfer()) ret = false; + if(QWCinGIFMFIFO(gifch.madr) == 0) gifstate |= GIF_STATE_EMPTY; + return ret; + } else { int mfifoqwc; - + GIF_LOG("Non-MFIFO Location transfer doing %x Total QWC", gifch.qwc); tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false); if (pMem == NULL) return false; @@ -528,12 +575,13 @@ void mfifoGIFtransfer(int qwc) if(qwc > 0 ) { - gifqwc += qwc; - - if (!(gifstate & GIF_STATE_EMPTY)) return; - // if (gifempty == false) return; - gifstate &= ~GIF_STATE_EMPTY; - gifempty = false; + if ((gifstate & GIF_STATE_EMPTY) && !(cpuRegs.interrupt & (1< 1 ) DevCon.WriteLn("gif mfifo tadr==madr but qwc = %d", gifqwc); - hwDmacIrq(DMAC_MFIFO_EMPTY); - gifstate |= GIF_STATE_EMPTY; - gifempty = true; - return; - } - gifch.tadr = qwctag(gifch.tadr); ptag = dmaGetAddr(gifch.tadr, false); @@ -565,42 +604,10 @@ void mfifoGIFtransfer(int qwc) GIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x", ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr, gifqwc, spr0ch.madr); - gifqwc--; + gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID); - switch (ptag->ID) - { - case TAG_REFE: // Refe - Transfer Packet According to ADDR field - gifch.tadr = qwctag(gifch.tadr + 16); - gifstate = GIF_STATE_DONE; //End Transfer - break; - - case TAG_CNT: // CNT - Transfer QWC following the tag. - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to QW after Tag - gifch.tadr = qwctag(gifch.madr + (gifch.qwc << 4)); //Set TADR to QW following the data - gifstate = GIF_STATE_READY; - break; - - case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR - { - u32 temp = gifch.madr; //Temporarily Store ADDR - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to QW following the tag - gifch.tadr = temp; //Copy temporarily stored ADDR to Tag - gifstate = GIF_STATE_READY; - break; - } - - case TAG_REF: // Ref - Transfer QWC from ADDR field - case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control) - gifch.tadr = qwctag(gifch.tadr + 16); //Set TADR to next tag - gifstate = GIF_STATE_READY; - break; - - case TAG_END: // End - Transfer QWC following the tag - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to data following the tag - gifch.tadr = qwctag(gifch.madr + (gifch.qwc << 4)); //Set TADR to QW following the data - gifstate = GIF_STATE_DONE; //End Transfer - break; - } + if(gspath3done == true) gifstate = GIF_STATE_DONE; + else gifstate = GIF_STATE_READY; if ((gifch.chcr.TIE) && (ptag->IRQ)) { @@ -608,7 +615,8 @@ void mfifoGIFtransfer(int qwc) gifstate = GIF_STATE_DONE; gifmfifoirq = true; } - } + if (QWCinGIFMFIFO(gifch.tadr) == 0) gifstate |= GIF_STATE_EMPTY; + } if (!mfifoGIFchain()) { @@ -616,7 +624,7 @@ void mfifoGIFtransfer(int qwc) gifstate = GIF_STATE_STALL; } - if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate = GIF_STATE_STALL; + if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate |= GIF_STATE_STALL; CPU_INT(DMAC_MFIFO_GIF,mfifocycles); SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x", gifch.chcr._u32, gifch.madr, gifch.tadr); @@ -624,9 +632,15 @@ void mfifoGIFtransfer(int qwc) void gifMFIFOInterrupt() { - //Console.WriteLn("gifMFIFOInterrupt"); + GIF_LOG("gifMFIFOInterrupt"); mfifocycles = 0; + if (dmacRegs.ctrl.MFD != MFD_GIF) + { + DevCon.Warning("Not in GIF MFIFO mode! Stopping GIF MFIFO"); + return; + } + if(SIGNAL_IMR_Pending == true) { //DevCon.Warning("Path 3 Paused"); @@ -634,13 +648,20 @@ void gifMFIFOInterrupt() return; } - if(GSTransferStatus.PTH3 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH3 ) + if(GSTransferStatus.PTH3 >= PENDINGSTOP_MODE && gifRegs.stat.APATH == GIF_APATH3 ) { gifRegs.stat.OPH = false; + GSTransferStatus.PTH3 = STOPPED_MODE; gifRegs.stat.APATH = GIF_APATH_IDLE; if(gifRegs.stat.P1Q) gsPath1Interrupt(); } + if((gifstate & GIF_STATE_EMPTY)) + { + FireMFIFOEmpty(); + if(!(gifstate & GIF_STATE_STALL)) return; + } + if(CheckPaths(11) == false) return; if (!(gifch.chcr.STR)) @@ -652,16 +673,13 @@ void gifMFIFOInterrupt() if (!(gifstate & GIF_STATE_STALL)) { - if (gifqwc <= 0) + if (QWCinGIFMFIFO(gifch.tadr) == 0) { - //Console.WriteLn("Empty"); - hwDmacIrq(DMAC_MFIFO_EMPTY); gifstate |= GIF_STATE_EMPTY; - gifempty = true; - - gifRegs.stat.IMT = false; + CPU_INT(DMAC_MFIFO_GIF, 4); return; } + mfifoGIFtransfer(0); return; } @@ -685,6 +703,7 @@ void gifMFIFOInterrupt() gifch.chcr.STR = false; gifstate = GIF_STATE_READY; hwDmacIrq(DMAC_GIF); + GIF_LOG("gifMFIFO End"); clearFIFOstuff(false); } @@ -696,7 +715,6 @@ void SaveStateBase::gifFreeze() Freeze( gifqwc ); Freeze( gspath3done ); Freeze( gscycles ); - //Freeze(gifempty); // Note: mfifocycles is not a persistent var, so no need to save it here. int bufsize = Path1WritePos - Path1ReadPos; diff --git a/pcsx2/Gif.h b/pcsx2/Gif.h index 6a03820659..d02ddf14c9 100644 --- a/pcsx2/Gif.h +++ b/pcsx2/Gif.h @@ -26,7 +26,7 @@ enum gifstate_t enum GSTransferModes //0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet { - PENDINGIMAGE_MODE = 0, + WAITING_MODE = 0, IMAGE_MODE = 1, TRANSFER_MODE = 2, PENDINGSTOP_MODE = 3, diff --git a/pcsx2/Hw.cpp b/pcsx2/Hw.cpp index f9fbec01e7..fb60f685e2 100644 --- a/pcsx2/Hw.cpp +++ b/pcsx2/Hw.cpp @@ -130,6 +130,14 @@ void hwDmacIrq(int n) if(psHu16(DMAC_STAT+2) & (1< ((dmacRegs.rbsr.RMSK + 16) >> 4)) DevCon.Warning("MFIFO Write bigger than MFIFO! QWC=%x FifoSize=%x", qwc, ((dmacRegs.rbsr.RMSK + 16) >> 4)); // DMAC Address resolution: FIFO can be placed anywhere in the *physical* memory map // for the PS2. Its probably a serious error for a PS2 app to have the buffer cross // valid/invalid page areas of ram, so realistically we only need to test the base address @@ -162,13 +171,15 @@ __ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc) __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) { switch (id) { case TAG_REFE: // Refe - Transfer Packet According to ADDR field + dma.tadr += 16; //End Transfer return true; case TAG_CNT: // CNT - Transfer QWC following the tag. // Set MADR to QW afer tag, and set TADR to QW following the data. - dma.madr = dma.tadr + 16; - dma.tadr = dma.madr + (dma.qwc << 4); + dma.tadr += 16; + dma.madr = dma.tadr; + //dma.tadr = dma.madr + (dma.qwc << 4); return false; case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR @@ -267,6 +278,33 @@ __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) { return false; } + +/********TADR NOTES*********** +From what i've gathered from testing tadr increment stuff (with CNT) is that we might not be 100% accurate in what +increments it and what doesnt. Previously we presumed REFE and END didn't increment the tag, but SIF and IPU never +liked this. + +From what i've deduced, REFE does in fact increment, but END doesn't, after much testing, i've concluded this is how +we can standardize DMA chains, so i've modified the code to work like this. The below function controls the increment +of the TADR along with the MADR on VIF, GIF and SPR1 when using the CNT tag, the others don't use it yet, but they +can probably be modified to do so now. + +Reason for this:- Many games (such as clock tower 3 and FFX Videos) watched the TADR to see when a transfer has finished, +so we need to simulate this wherever we can! Even the FFX video gets corruption and tries to fire multiple DMA Kicks +if this doesnt happen, which was the reasoning for the hacked up SPR timing we had, that is no longer required. + +-Refraction +******************************/ + +void hwDmacSrcTadrInc(DMACh& dma) +{ + u16 tagid = (dma.chcr.TAG >> 12) & 0x7; + + if(tagid == TAG_CNT) + { + dma.tadr = dma.madr; + } +} bool hwDmacSrcChain(DMACh& dma, int id) { u32 temp; @@ -274,13 +312,14 @@ bool hwDmacSrcChain(DMACh& dma, int id) switch (id) { case TAG_REFE: // Refe - Transfer Packet According to ADDR field + dma.tadr += 16; // End the transfer. return true; case TAG_CNT: // CNT - Transfer QWC following the tag. // Set MADR to QW after the tag, and TADR to QW following the data. dma.madr = dma.tadr + 16; - dma.tadr = dma.madr + (dma.qwc << 4); + dma.tadr = dma.madr; return false; case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR @@ -305,3 +344,4 @@ bool hwDmacSrcChain(DMACh& dma, int id) return false; } + diff --git a/pcsx2/Hw.h b/pcsx2/Hw.h index ef1bb0b658..02b92d64b1 100644 --- a/pcsx2/Hw.h +++ b/pcsx2/Hw.h @@ -308,6 +308,7 @@ enum EERegisterAddresses DMAC_RBSR = 0x1000E040, DMAC_RBOR = 0x1000E050, DMAC_STADR = 0x1000E060, + DMAC_FAKESTAT = 0x1000E100, //Midway, you're idiots (checked this in the MK Deception ELF!) (Refraction) INTC_STAT = 0x1000F000, INTC_MASK = 0x1000F010, diff --git a/pcsx2/IPU/IPU.cpp b/pcsx2/IPU/IPU.cpp index b175067d2f..3e9e5ab9dc 100644 --- a/pcsx2/IPU/IPU.cpp +++ b/pcsx2/IPU/IPU.cpp @@ -440,10 +440,9 @@ static __fi bool ipuVDEC(u32 val) // very choppy (basically only decoding/updating every 30th frame or so). So yeah, // someone with knowledge on the subject please feel free to explain this one. :) --air - ipuRegs.cmd.DATA &= 0xFFFF; - ipuRegs.cmd.DATA |= 0x10000; + // The upper bits are the "length" of the decoded command, where the lower is the address. + // This is due to differences with IPU and the MPEG standard. See get_macroblock_address_increment(). - //ipuRegs.cmd.DATA = (ipuRegs.cmd.DATA & 0xFFFF) | ((decoder.bitstream_bits + 16) << 16); ipuRegs.ctrl.ECD = (ipuRegs.cmd.DATA == 0); case 1: @@ -909,7 +908,7 @@ __noinline void IPUWorker() // CHECK!: IPU0dma remains when IDEC is done, so we need to clear it // Check Mana Khemia 1 "off campus" to trigger a GUST IDEC messup. // This hackfixes it :/ - if (ipu0dma.qwc > 0 && ipu0dma.chcr.STR) ipu0Interrupt(); + //if (ipu0dma.qwc > 0 && ipu0dma.chcr.STR) ipu0Interrupt(); break; case SCE_IPU_BDEC: diff --git a/pcsx2/IPU/IPU_Fifo.cpp b/pcsx2/IPU/IPU_Fifo.cpp index 5f03dc6983..cc35dc268c 100644 --- a/pcsx2/IPU/IPU_Fifo.cpp +++ b/pcsx2/IPU/IPU_Fifo.cpp @@ -109,11 +109,11 @@ int IPU_Fifo_Output::write(const u32 *value, uint size) pxAssumeMsg(size>0, "Invalid size==0 when calling IPU_Fifo_Output::write"); uint origsize = size; - do { - IPU0dma(); + /*do {*/ + //IPU0dma(); uint transsize = min(size, 8 - (uint)ipuRegs.ctrl.OFC); - if(!transsize) break; + if(!transsize) return 0; ipuRegs.ctrl.OFC = transsize; size -= transsize; @@ -124,7 +124,7 @@ int IPU_Fifo_Output::write(const u32 *value, uint size) value += 4; --transsize; } - } while(true); + /*} while(true);*/ return origsize - size; } diff --git a/pcsx2/IPU/IPUdma.cpp b/pcsx2/IPU/IPUdma.cpp index 857d3fc922..3060b771a6 100644 --- a/pcsx2/IPU/IPUdma.cpp +++ b/pcsx2/IPU/IPUdma.cpp @@ -42,21 +42,6 @@ void SaveStateBase::ipuDmaFreeze() Freeze(IPU1Status); } -static __fi bool ipuDmacPartialChain(tDMA_TAG tag) -{ - switch (tag.ID) - { - case TAG_REFE: // refe - ipu1dma.tadr += 16; - return true; - - case TAG_END: // end - ipu1dma.tadr = ipu1dma.madr; - return true; - } - return false; -} - static __fi void ipuDmacSrcChain() { switch (IPU1Status.ChainMode) @@ -82,7 +67,7 @@ static __fi void ipuDmacSrcChain() break; case TAG_END: // end - ipu1dma.tadr = ipu1dma.madr; + //ipu1dma.tadr = ipu1dma.madr; IPU1Status.DMAFinished = true; break; } @@ -136,15 +121,12 @@ static __fi int IPU1chain() { ipu1dma.qwc -= qwc; totalqwc += qwc; } + + //Update TADR etc + if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain(); + if( ipu1dma.qwc == 0) - { - //Update TADR etc - if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain(); - //If the transfer has finished or we have room in the FIFO, schedule to the interrupt code. - - //No data left IPU1Status.InProgress = false; - } //If we still have data the commands should pull this across when need be. return totalqwc; } @@ -238,7 +220,8 @@ int IPU1dma() break; case TAG_CNT: // cnt - ipu1dma.madr = ipu1dma.tadr + 16; + ipu1dma.tadr += 16; + ipu1dma.madr = ipu1dma.tadr; IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16); //ipu1dma.tadr = ipu1dma.madr + (ipu1dma.qwc * 16); // Set the taddr to the next tag @@ -262,7 +245,7 @@ int IPU1dma() case TAG_END: // end // do not change tadr ipu1dma.madr = ipu1dma.tadr + 16; - ipu1dma.tadr += 16; + //ipu1dma.tadr += 16; IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16); break; @@ -310,15 +293,23 @@ int IPU1dma() return totalqwc; } -int IPU0dma() +void IPU0dma() { - if(!ipuRegs.ctrl.OFC) return 0; + if(!ipuRegs.ctrl.OFC) + { + IPU_INT_FROM( 64 ); + IPUProcessInterrupt(); + return; + } int readsize; tDMA_TAG* pMem; if ((!(ipu0dma.chcr.STR) || (cpuRegs.interrupt & (1 << DMAC_FROM_IPU))) || (ipu0dma.qwc == 0)) - return 0; + { + DevCon.Warning("How??"); + return; + } pxAssert(!(ipu0dma.chcr.TTE)); @@ -362,10 +353,11 @@ int IPU0dma() //This was IPU_INT_FROM(readsize*BIAS ); //This broke vids in Digital Devil Saga //Note that interrupting based on totalsize is just guessing.. - IPU_INT_FROM( readsize * BIAS ); } + IPU_INT_FROM( readsize * BIAS ); + if(ipuRegs.ctrl.IFC > 0) IPUProcessInterrupt(); - return readsize; + //return readsize; } __fi void dmaIPU0() // fromIPU @@ -381,7 +373,10 @@ __fi void dmaIPU0() // fromIPU hwDmacIrq(DMAC_FROM_IPU); } - IPUProcessInterrupt(); + IPU_INT_FROM( 64 ); + + + } __fi void dmaIPU1() // toIPU @@ -450,6 +445,11 @@ void ipu0Interrupt() { IPU_LOG("ipu0Interrupt: %x", cpuRegs.cycle); + if(ipu0dma.qwc > 0) + { + IPU0dma(); + return; + } if (g_nDMATransfer.FIREINT0) { g_nDMATransfer.FIREINT0 = false; diff --git a/pcsx2/IPU/IPUdma.h b/pcsx2/IPU/IPUdma.h index 9c62820d13..a832bcc5b7 100644 --- a/pcsx2/IPU/IPUdma.h +++ b/pcsx2/IPU/IPUdma.h @@ -87,7 +87,7 @@ extern void ipu1Interrupt(); extern void dmaIPU0(); extern void dmaIPU1(); -extern int IPU0dma(); +extern void IPU0dma(); extern int IPU1dma(); extern void ipuDmaReset(); diff --git a/pcsx2/IPU/mpeg2lib/Mpeg.cpp b/pcsx2/IPU/mpeg2lib/Mpeg.cpp index f2fd7e3ac8..62d4805c7d 100644 --- a/pcsx2/IPU/mpeg2lib/Mpeg.cpp +++ b/pcsx2/IPU/mpeg2lib/Mpeg.cpp @@ -135,14 +135,13 @@ int get_macroblock_modes() { macroblock_modes |= GETBITS(2) * MOTION_TYPE_BASE; } - - return macroblock_modes; + return (macroblock_modes | (tab->len << 16)); } else if (decoder.frame_pred_frame_dct) { /* if (! (macroblock_modes & MACROBLOCK_INTRA)) */ macroblock_modes |= MC_FRAME; - return macroblock_modes; + return (macroblock_modes | (tab->len << 16)); } else { @@ -155,15 +154,15 @@ int get_macroblock_modes() intra: macroblock_modes |= GETBITS(1) * DCT_TYPE_INTERLACED; } - - return macroblock_modes; + return (macroblock_modes | (tab->len << 16)); } case D_TYPE: macroblock_modes = GETBITS(1); - + //I suspect (as this is actually a 2 bit command) that this should be getbits(2) + //additionally, we arent dumping any bits here when i think we should be, need a game to test. (Refraction) if (macroblock_modes == 0) return 0; // error - return MACROBLOCK_INTRA; + return (MACROBLOCK_INTRA | (1 << 16)); default: return 0; @@ -222,14 +221,15 @@ int __fi get_motion_delta(const int f_code) sign = SBITS(1); DUMPBITS(1); - return (delta ^ sign) - sign; + + return (((delta ^ sign) - sign) | (tab->len << 16)); } int __fi get_dmv() { const DMVtab* tab = DMV_2 + UBITS(2); DUMPBITS(tab->len); - return tab->dmv; + return (tab->dmv | (tab->len << 16)); } int get_macroblock_address_increment() @@ -246,13 +246,13 @@ int get_macroblock_address_increment() { case 8: /* macroblock_escape */ DUMPBITS(11); - return 0x23; + return 0xb0023; case 15: /* macroblock_stuffing (MPEG1 only) */ if (decoder.mpeg1) { DUMPBITS(11); - return 0x22; + return 0xb0022; } default: @@ -261,7 +261,7 @@ int get_macroblock_address_increment() DUMPBITS(mba->len); - return mba->mba + 1; + return ((mba->mba + 1) | (mba->len << 16)); } static __fi int get_luma_dc_dct_diff() diff --git a/pcsx2/Linux/pcsx2.cbp b/pcsx2/Linux/pcsx2.cbp index 76feb52187..e80f4e6a89 100644 --- a/pcsx2/Linux/pcsx2.cbp +++ b/pcsx2/Linux/pcsx2.cbp @@ -395,8 +395,6 @@ - - diff --git a/pcsx2/MTGS.cpp b/pcsx2/MTGS.cpp index 8a75defc72..16ec532316 100644 --- a/pcsx2/MTGS.cpp +++ b/pcsx2/MTGS.cpp @@ -806,7 +806,7 @@ void SysMtgsThread::WaitForOpen() // emulator forcefully, or to continue waiting on the GS. throw Exception::PluginOpenError( PluginId_GS ) - .SetBothMsgs(wxLt("The MTGS thread has become unresponsive while waiting for the GS plugin to open.")); + .SetBothMsgs(pxLt("The MTGS thread has become unresponsive while waiting for the GS plugin to open.")); } } diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 80c2e5aaad..91e4054d37 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -374,6 +374,7 @@ void Pcsx2Config::LoadSave( IniInterface& ini ) IniBitBool( ConsoleToStdio ); IniBitBool( HostFs ); + IniBitBool( BackupSavestate ); IniBitBool( McdEnableEjection ); IniBitBool( MultitapPort0_Enabled ); IniBitBool( MultitapPort1_Enabled ); diff --git a/pcsx2/PluginManager.cpp b/pcsx2/PluginManager.cpp index 847cbada0d..6f3f6086e7 100644 --- a/pcsx2/PluginManager.cpp +++ b/pcsx2/PluginManager.cpp @@ -23,6 +23,7 @@ #include "CDVD/CDVDisoReader.h" #include "Utilities/ScopedPtr.h" +#include "Utilities/pxStreams.h" #if _MSC_VER # include "svnrev.h" @@ -152,7 +153,7 @@ _GSgifSoftReset GSgifSoftReset; _GSreadFIFO GSreadFIFO; _GSreadFIFO2 GSreadFIFO2; _GSchangeSaveState GSchangeSaveState; -_GSgetTitleInfo GSgetTitleInfo; +_GSgetTitleInfo2 GSgetTitleInfo2; _GSmakeSnapshot GSmakeSnapshot; _GSmakeSnapshot2 GSmakeSnapshot2; _GSirqCallback GSirqCallback; @@ -185,8 +186,11 @@ static void CALLBACK GS_printf(int timeout, char *fmt, ...) Console.WriteLn(msg); } -void CALLBACK GS_getTitleInfo( char dest[128] ) +void CALLBACK GS_getTitleInfo2( char* dest, size_t length ) { + // Just return a generic "GS" title -- a plugin actually implementing this feature + // should return a title such as "GSdx" or "ZZogl" instead. --air + dest[0] = 'G'; dest[1] = 'S'; dest[2] = 0; @@ -372,7 +376,7 @@ static const LegacyApi_ReqMethod s_MethMessReq_GS[] = { "GSsetVsync", (vMeth**)&GSsetVsync, (vMeth*)GS_setVsync }, { "GSsetExclusive", (vMeth**)&GSsetExclusive, (vMeth*)GS_setExclusive }, { "GSchangeSaveState",(vMeth**)&GSchangeSaveState,(vMeth*)GS_changeSaveState }, - { "GSgetTitleInfo", (vMeth**)&GSgetTitleInfo, (vMeth*)GS_getTitleInfo }, + { "GSgetTitleInfo2", (vMeth**)&GSgetTitleInfo2, (vMeth*)GS_getTitleInfo2 }, { NULL } }; @@ -807,11 +811,11 @@ SysCorePlugins::PluginStatus_t::PluginStatus_t( PluginsEnum_t _pid, const wxStri if( !wxFile::Exists( Filename ) ) throw Exception::PluginLoadError( pid ).SetStreamName(srcfile) - .SetBothMsgs(wxLt("The configured %s plugin file was not found")); + .SetBothMsgs(pxL("The configured %s plugin file was not found")); if( !Lib.Load( Filename ) ) throw Exception::PluginLoadError( pid ).SetStreamName(Filename) - .SetBothMsgs(wxLt("The configured %s plugin file is not a valid dynamic library")); + .SetBothMsgs(pxL("The configured %s plugin file is not a valid dynamic library")); // Try to enumerate the new v2.0 plugin interface first. @@ -1321,7 +1325,7 @@ bool SysCorePlugins::Init() { // fixme: use plugin's GetLastError (not implemented yet!) throw Exception::PluginInitError( PluginId_Mcd ) - .SetBothMsgs(wxLt("Internal Memorycard Plugin failed to initialize.")); + .SetBothMsgs(pxLt("Internal Memorycard Plugin failed to initialize.")); } } @@ -1399,9 +1403,6 @@ void SysCorePlugins::Freeze( PluginsEnum_t pid, SaveStateBase& state ) // No locking leeded -- DoFreeze locks as needed, and this avoids MTGS deadlock. //ScopedLock lock( m_mtx_PluginStatus ); - Console.Indent().WriteLn( "%s %s", state.IsSaving() ? "Saving" : "Loading", - tbl_PluginInfo[pid].shortname ); - freezeData fP = { 0, NULL }; if( !DoFreeze( pid, FREEZE_SIZE, &fP ) ) fP.size = 0; @@ -1409,6 +1410,9 @@ void SysCorePlugins::Freeze( PluginsEnum_t pid, SaveStateBase& state ) int fsize = fP.size; state.Freeze( fsize ); + Console.Indent().WriteLn( "%s %s", state.IsSaving() ? "Saving" : "Loading", + tbl_PluginInfo[pid].shortname ); + if( state.IsLoading() && (fsize == 0) ) { // no state data to read, but the plugin expects some state data. @@ -1443,6 +1447,82 @@ void SysCorePlugins::Freeze( PluginsEnum_t pid, SaveStateBase& state ) state.CommitBlock( fP.size ); } +size_t SysCorePlugins::GetFreezeSize( PluginsEnum_t pid ) +{ + freezeData fP = { 0, NULL }; + if (!DoFreeze( pid, FREEZE_SIZE, &fP)) return 0; + return fP.size; +} + +void SysCorePlugins::FreezeOut( PluginsEnum_t pid, void* dest ) +{ + // No locking needed -- DoFreeze locks as needed, and this avoids MTGS deadlock. + //ScopedLock lock( m_mtx_PluginStatus ); + + freezeData fP = { 0, (s8*)dest }; + if (!DoFreeze( pid, FREEZE_SIZE, &fP)) return; + if (!fP.size) return; + + Console.Indent().WriteLn( "Saving %s", tbl_PluginInfo[pid].shortname ); + + if (!DoFreeze(pid, FREEZE_SAVE, &fP)) + throw Exception::FreezePluginFailure( pid ); +} + +void SysCorePlugins::FreezeOut( PluginsEnum_t pid, pxOutputStream& outfp ) +{ + // No locking needed -- DoFreeze locks as needed, and this avoids MTGS deadlock. + //ScopedLock lock( m_mtx_PluginStatus ); + + freezeData fP = { 0, NULL }; + if (!DoFreeze( pid, FREEZE_SIZE, &fP)) return; + if (!fP.size) return; + + Console.Indent().WriteLn( "Saving %s", tbl_PluginInfo[pid].shortname ); + + ScopedAlloc data( fP.size ); + fP.data = data.GetPtr(); + + if (!DoFreeze(pid, FREEZE_SAVE, &fP)) + throw Exception::FreezePluginFailure( pid ); + + outfp.Write( fP.data, fP.size ); +} + +void SysCorePlugins::FreezeIn( PluginsEnum_t pid, pxInputStream& infp ) +{ + // No locking needed -- DoFreeze locks as needed, and this avoids MTGS deadlock. + //ScopedLock lock( m_mtx_PluginStatus ); + + freezeData fP = { 0, NULL }; + if (!DoFreeze( pid, FREEZE_SIZE, &fP )) + fP.size = 0; + + Console.Indent().WriteLn( "Loading %s", tbl_PluginInfo[pid].shortname ); + + if (!infp.IsOk() || !infp.Length()) + { + // no state data to read, but the plugin expects some state data? + // Issue a warning to console... + if( fP.size != 0 ) + Console.Indent().Warning( "Warning: No data for this plugin was found. Plugin status may be unpredictable." ); + + return; + + // Note: Size mismatch check could also be done here on loading, but + // some plugins may have built-in version support for non-native formats or + // older versions of a different size... or could give different sizes depending + // on the status of the plugin when loading, so let's ignore it. + } + + ScopedAlloc data( fP.size ); + fP.data = data.GetPtr(); + + infp.Read( fP.data, fP.size ); + if (!DoFreeze(pid, FREEZE_LOAD, &fP)) + throw Exception::ThawPluginFailure( pid ); +} + bool SysCorePlugins::KeyEvent( const keyEvent& evt ) { ScopedLock lock( m_mtx_PluginStatus ); diff --git a/pcsx2/Plugins.h b/pcsx2/Plugins.h index 80b445a730..f92999e704 100644 --- a/pcsx2/Plugins.h +++ b/pcsx2/Plugins.h @@ -326,6 +326,10 @@ public: virtual bool IsInitialized( PluginsEnum_t pid ) const; virtual bool IsLoaded( PluginsEnum_t pid ) const; + virtual size_t GetFreezeSize( PluginsEnum_t pid ); + virtual void FreezeOut( PluginsEnum_t pid, void* dest ); + virtual void FreezeOut( PluginsEnum_t pid, pxOutputStream& outfp ); + virtual void FreezeIn( PluginsEnum_t pid, pxInputStream& infp ); virtual void Freeze( PluginsEnum_t pid, SaveStateBase& state ); virtual bool DoFreeze( PluginsEnum_t pid, int mode, freezeData* data ); diff --git a/pcsx2/PrecompiledHeader.h b/pcsx2/PrecompiledHeader.h index 26bc5d847d..86429356f2 100644 --- a/pcsx2/PrecompiledHeader.h +++ b/pcsx2/PrecompiledHeader.h @@ -16,7 +16,7 @@ #ifndef PCSX2_PRECOMPILED_HEADER #define PCSX2_PRECOMPILED_HEADER -//#pragma once // no dice, causes problems in GCC PCH (which doesn't really work very well +//#pragma once // no dice, causes problems in GCC PCH (which doesn't really work very well anyway) // Disable some pointless warnings... #ifdef _MSC_VER @@ -24,20 +24,7 @@ # pragma warning(disable:4996) //ignore the stricmp deprecated warning #endif -////////////////////////////////////////////////////////////////////////////////////////// -// Define PCSX2's own i18n helpers. These override the wxWidgets helpers and provide -// additional functionality. -// -#define WXINTL_NO_GETTEXT_MACRO -#undef _ -#define _(s) pxGetTranslation(_T(s)) - -// macro provided for tagging translation strings, without actually running them through the -// translator (which the _() does automatically, and sometimes we don't want that). This is -// a shorthand replacement for wxTRANSLATE. -#ifndef wxLt -# define wxLt(a) wxT(a) -#endif +#include "Utilities/Dependencies.h" #define NOMINMAX // Disables other libs inclusion of their own min/max macros (we use std instead) diff --git a/pcsx2/SPR.cpp b/pcsx2/SPR.cpp index 5ea0243ae9..3164661e0a 100644 --- a/pcsx2/SPR.cpp +++ b/pcsx2/SPR.cpp @@ -86,7 +86,7 @@ int _SPR0chain() __fi void SPR0chain() { - CPU_INT(DMAC_FROM_SPR, _SPR0chain() / BIAS); + CPU_INT(DMAC_FROM_SPR, _SPR0chain() * BIAS); spr0ch.qwc = 0; } @@ -102,7 +102,7 @@ void _SPR0interleave() SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", spr0ch.qwc, tqwc, sqwc, spr0ch.madr, spr0ch.sadr); - CPU_INT(DMAC_FROM_SPR, qwc / BIAS); + CPU_INT(DMAC_FROM_SPR, qwc * BIAS); while (qwc > 0) { @@ -290,13 +290,14 @@ int _SPR1chain() SPR1transfer(pMem, spr1ch.qwc); spr1ch.madr += spr1ch.qwc * 16; + hwDmacSrcTadrInc(spr1ch); return (spr1ch.qwc); } __fi void SPR1chain() { - CPU_INT(DMAC_TO_SPR, _SPR1chain() / BIAS); + CPU_INT(DMAC_TO_SPR, _SPR1chain() * BIAS); spr1ch.qwc = 0; } @@ -310,7 +311,7 @@ void _SPR1interleave() if (tqwc == 0) tqwc = qwc; SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", spr1ch.qwc, tqwc, sqwc, spr1ch.madr, spr1ch.sadr); - CPU_INT(DMAC_TO_SPR, qwc / BIAS); + CPU_INT(DMAC_TO_SPR, qwc * BIAS); while (qwc > 0) { spr1ch.qwc = std::min(tqwc, qwc); diff --git a/pcsx2/SaveState.cpp b/pcsx2/SaveState.cpp index 70ace94b46..b6d67b0e50 100644 --- a/pcsx2/SaveState.cpp +++ b/pcsx2/SaveState.cpp @@ -70,8 +70,6 @@ void SaveStateBase::Init( SafeArray* memblock ) m_memory = memblock; m_version = g_SaveVersion; m_idx = 0; - m_sectid = FreezeId_Unknown; - m_pid = PluginId_GS; m_DidBios = false; } @@ -106,50 +104,45 @@ void SaveStateBase::FreezeTag( const char* src ) } } -void SaveStateBase::FreezeBios() +SaveStateBase& SaveStateBase::FreezeBios() { + FreezeTag( "BIOS" ); + // Check the BIOS, and issue a warning if the bios for this state // doesn't match the bios currently being used (chances are it'll still // work fine, but some games are very picky). + + u32 bioscheck = BiosChecksum; + char biosdesc[256]; - char descin[128], desccmp[128]; - wxString descout; - IsBIOS( g_Conf->FullpathToBios(), descout ); - memzero( descin ); - memzero( desccmp ); + pxToUTF8 utf8(BiosDescription); - pxToUTF8 utf8(descout); - memcpy_fast( descin, utf8, utf8.Length() ); - memcpy_fast( desccmp, utf8, utf8.Length() ); + memzero( biosdesc ); + memcpy_fast( biosdesc, utf8, std::min( sizeof(biosdesc), utf8.Length() ) ); + + Freeze( bioscheck ); + Freeze( biosdesc ); - // ... and only freeze bios info once per state, since the user msg could - // become really annoying on a corrupted state or something. (have to always - // load though, so that we advance past the duplicated info, if present) - - if( IsLoading() || !m_DidBios ) - Freeze( descin ); - - if( !m_DidBios ) + if (bioscheck != BiosChecksum) { - if( memcmp( descin, desccmp, 128 ) != 0 ) - { - Console.Newline(); - Console.Indent(1).Error( "Warning: BIOS Version Mismatch, savestate may be unstable!" ); - Console.Indent(2).Error( - "Current Version: %s\n" - "Savestate Version: %s\n", - utf8.data(), descin - ); - } + Console.Newline(); + Console.Indent(1).Error( "Warning: BIOS Version Mismatch, savestate may be unstable!" ); + Console.Indent(2).Error( + "Current BIOS: %ls (crc=0x%08x)\n" + "Savestate BIOS: %s (crc=0x%08x)\n", + BiosDescription.c_str(), BiosChecksum, + biosdesc, bioscheck + ); } - m_DidBios = true; + + return *this; } static const uint MainMemorySizeInBytes = Ps2MemSize::MainRam + Ps2MemSize::Scratch + Ps2MemSize::Hardware + Ps2MemSize::IopRam + Ps2MemSize::IopHardware; -void SaveStateBase::FreezeMainMemory() +SaveStateBase& SaveStateBase::FreezeMainMemory() { if (IsLoading()) PreLoadPrep(); @@ -170,9 +163,11 @@ void SaveStateBase::FreezeMainMemory() FreezeMem(vuRegs[1].Micro, VU1_PROGSIZE); FreezeMem(vuRegs[1].Mem, VU1_MEMSIZE); + + return *this; } -void SaveStateBase::FreezeRegisters() +SaveStateBase& SaveStateBase::FreezeInternals() { if( IsLoading() ) PreLoadPrep(); @@ -229,138 +224,31 @@ void SaveStateBase::FreezeRegisters() if( IsLoading() ) PostLoadPrep(); + + return *this; } -void SaveStateBase::WritebackSectionLength( int seekpos, int sectlen, const wxChar* sectname ) +SaveStateBase& SaveStateBase::FreezePlugins() { - int realsectsize = m_idx - seekpos; - if( IsSaving() ) + for (uint i=0; iGetPtr(seekpos-4)) = realsectsize; - } - else // IsLoading!! - { - if( sectlen != realsectsize ) // if they don't match then we have a problem, jim. - { - throw Exception::SaveStateLoadError() - .SetDiagMsg(pxsFmt(L"Invalid size encountered on section '%s'.", sectname )) - .SetUserMsg(_("The savestate data is invalid or corrupted.")); - } + FreezeTag( FastFormatAscii().Write("Plugin:%s", tbl_PluginInfo[i].shortname) ); + GetCorePlugins().Freeze( (PluginsEnum_t)i, *this ); } + + return *this; } -bool SaveStateBase::FreezeSection( int seek_section ) +SaveStateBase& SaveStateBase::FreezeAll() { - const bool isSeeking = (seek_section != FreezeId_NotSeeking ); - if( IsSaving() ) pxAssertDev( !isSeeking, "Cannot seek on a saving-mode savestate stream." ); - - Freeze( m_sectid ); - if( seek_section == m_sectid ) return false; - - switch( m_sectid ) - { - case FreezeId_End: - return false; - - case FreezeId_Bios: - { - int sectlen = 128; - FreezeTag( "BiosVersion" ); - Freeze( sectlen ); - - if( sectlen != 128 ) - { - throw Exception::SaveStateLoadError() - .SetDiagMsg(L"Invalid size encountered on BiosVersion section.") - .SetUserMsg(_("The savestate data is invalid or corrupted.")); - } - - if( isSeeking ) - m_idx += sectlen; - else - FreezeBios(); - m_sectid++; - } - break; - - case FreezeId_Registers: - { - FreezeTag( "HardwareRegisters" ); - int seekpos = m_idx+4; - int sectlen = 0xdead; // gets written back over with "real" data in IsSaving() mode - - Freeze( sectlen ); - FreezeRegisters(); - - WritebackSectionLength( seekpos, sectlen, L"HardwareRegisters" ); - m_sectid++; - } - break; - - case FreezeId_Plugin: - { - FreezeTag( "Plugin" ); - int seekpos = m_idx+4; - int sectlen = 0xdead; // gets written back over with "real" data in IsSaving() mode - - Freeze( sectlen ); - Freeze( m_pid ); - - if( isSeeking ) - m_idx += sectlen; - else - GetCorePlugins().Freeze( (PluginsEnum_t)m_pid, *this ); - - WritebackSectionLength( seekpos, sectlen, L"Plugins" ); - - // following increments only affect Saving mode, which needs to be sure to save all - // plugins (order doesn't matter but sequential is easy enough. (ignored by Loading mode) - m_pid++; - if( m_pid >= PluginId_Count ) - m_sectid = FreezeId_End; - } - break; - - case FreezeId_Unknown: - default: - pxAssert( IsSaving() ); - - // Skip unknown sections with a warning log. - // Maybe it'll work! (haha?) - - int size; - Freeze( m_tagspace ); - Freeze( size ); - m_tagspace[sizeof(m_tagspace)-1] = 0; - - Console.Warning( - "Warning: Unknown tag encountered while loading savestate; going to ignore it!\n" - "\tTagname: %s, Size: %d", m_tagspace, size - ); - m_idx += size; - break; - } - - if( wxThread::IsMain() ) - wxSafeYield( NULL, true ); - - return true; + FreezeMainMemory(); + FreezeBios(); + FreezeInternals(); + FreezePlugins(); + + return *this; } -void SaveStateBase::FreezeAll() -{ - if( IsSaving() ) - { - // Loading mode streams will assign these, but saving mode reads them so better - // do some setup first. - - m_sectid = (int)FreezeId_End+1; - m_pid = PluginId_GS; - } - - while( FreezeSection() ); -} // -------------------------------------------------------------------------------------- // memSavingState (implementations) @@ -380,7 +268,9 @@ memSavingState::memSavingState( SafeArray* save_to ) // Saving of state data void memSavingState::FreezeMem( void* data, int size ) { - m_memory->MakeRoomFor( m_idx+size ); + if (!size) return; + + m_memory->MakeRoomFor( m_idx + size ); memcpy_fast( m_memory->GetPtr(m_idx), data, size ); m_idx += size; } @@ -394,10 +284,11 @@ void memSavingState::MakeRoomForData() } // Saving of state data to a memory buffer -void memSavingState::FreezeAll() +memSavingState& memSavingState::FreezeAll() { MakeRoomForData(); _parent::FreezeAll(); + return *this; } // -------------------------------------------------------------------------------------- @@ -423,25 +314,6 @@ void memLoadingState::FreezeMem( void* data, int size ) memcpy_fast( data, src, size ); } -bool memLoadingState::SeekToSection( PluginsEnum_t pid ) -{ - m_idx = 0; // start from the beginning - - do - { - while( FreezeSection( FreezeId_Plugin ) ); - if( m_sectid == FreezeId_End ) return false; - - FreezeTag( "Plugin" ); - int sectlen = 0xdead; - - Freeze( sectlen ); - Freeze( m_pid ); - - } while( m_pid != pid ); - return true; -} - // -------------------------------------------------------------------------------------- // SaveState Exception Messages // -------------------------------------------------------------------------------------- diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index e4bba1ddbd..bf6373eaf2 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -31,21 +31,6 @@ static const u32 g_SaveVersion = (0x9A01 << 16) | 0x0000; extern s32 CALLBACK gsSafeFreeze( int mode, freezeData *data ); -enum FreezeSectionId -{ - FreezeId_NotSeeking = -2, - FreezeId_End, - - // A BIOS tag should always be saved in conjunction with Memory or Registers tags, - // but can be skipped if the savestate has only plugins. - FreezeId_Bios, - FreezeId_Registers, - FreezeId_Plugin, - - // anything here and beyond we can skip, with a warning - FreezeId_Unknown, -}; - namespace Exception { // --------------------------------------------------------------------------------------- @@ -119,8 +104,6 @@ protected: u32 m_version; // version of the savestate being loaded. int m_idx; // current read/write index of the allocation - int m_sectid; - int m_pid; bool m_DidBios; @@ -141,9 +124,12 @@ public: // Loads or saves the entire emulation state. // Note: The Cpu state must be reset, and plugins *open*, prior to Defrosting // (loading) a state! - virtual void FreezeAll(); + virtual SaveStateBase& FreezeAll(); - void FreezeMainMemory(); + virtual SaveStateBase& FreezeMainMemory(); + virtual SaveStateBase& FreezeBios(); + virtual SaveStateBase& FreezeInternals(); + virtual SaveStateBase& FreezePlugins(); // Loads or saves an arbitrary data type. Usable on atomic types, structs, and arrays. // For dynamically allocated pointers use FreezeMem instead. @@ -183,9 +169,6 @@ public: m_idx += size; } - void WritebackSectionLength( int seekpos, int sectlen, const wxChar* sectname ); - bool FreezeSection( int seek_section = FreezeId_NotSeeking ); - // Freezes an identifier value into the savestate for troubleshooting purposes. // Identifiers can be used to determine where in a savestate that data has become // skewed (if the value does not match then the error occurs somewhere prior to that @@ -210,9 +193,6 @@ protected: // Load/Save functions for the various components of our glorious emulator! - void FreezeBios(); - void FreezeRegisters(); - void rcntFreeze(); void vuMicroFreeze(); void vif0Freeze(); @@ -257,7 +237,7 @@ public: void MakeRoomForData(); void FreezeMem( void* data, int size ); - void FreezeAll(); + memSavingState& FreezeAll(); bool IsSaving() const { return true; } }; @@ -271,7 +251,6 @@ public: memLoadingState( const VmStateBuffer* load_from ); void FreezeMem( void* data, int size ); - bool SeekToSection( PluginsEnum_t pid ); bool IsSaving() const { return false; } bool IsFinished() const { return m_idx >= m_memory->GetSizeInBytes(); } diff --git a/pcsx2/Sif1.cpp b/pcsx2/Sif1.cpp index 67fb0148e5..e8f7fdc3cd 100644 --- a/pcsx2/Sif1.cpp +++ b/pcsx2/Sif1.cpp @@ -52,6 +52,7 @@ static __fi bool WriteEEtoFifo() sif1.fifo.write((u32*)ptag, writeSize << 2); sif1dma.madr += writeSize << 4; + hwDmacSrcTadrInc(sif1dma); sif1.ee.cycles += writeSize; // fixme : BIAS is factored in above sif1dma.qwc -= writeSize; @@ -114,8 +115,8 @@ static __fi bool ProcessEETag() break; case TAG_CNT: - sif1dma.madr = sif1dma.tadr + 16; - sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); + sif1dma.tadr += 16; + sif1dma.madr = sif1dma.tadr; break; case TAG_NEXT: @@ -132,7 +133,7 @@ static __fi bool ProcessEETag() case TAG_END: sif1.ee.end = true; sif1dma.madr = sif1dma.tadr + 16; - sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); + //sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); break; default: diff --git a/pcsx2/SourceLog.cpp b/pcsx2/SourceLog.cpp index 4cfd72a0e6..c9a81ae268 100644 --- a/pcsx2/SourceLog.cpp +++ b/pcsx2/SourceLog.cpp @@ -93,27 +93,27 @@ static const TraceLogDescriptor TLD_ELF = { L"ELF", L"ELF", - wxLt("Dumps detailed information for PS2 executables (ELFs).") + pxDt("Dumps detailed information for PS2 executables (ELFs).") }, TLD_eeRecPerf = { L"EErecPerf", L"EErec Performance", - wxLt("Logs manual protection, split blocks, and other things that might impact performance.") + pxDt("Logs manual protection, split blocks, and other things that might impact performance.") }, TLD_eeConsole = { L"EEout", L"EE Console", - wxLt("Shows the game developer's logging text (EE processor)") + pxDt("Shows the game developer's logging text (EE processor)") }, TLD_iopConsole = { L"IOPout", L"IOP Console", - wxLt("Shows the game developer's logging text (IOP processor)") + pxDt("Shows the game developer's logging text (IOP processor)") }, TLD_deci2 = { L"DECI2", L"DECI2 Console", - wxLt("Shows DECI2 debugging logs (EE processor)") + pxDt("Shows DECI2 debugging logs (EE processor)") }; SysConsoleLogPack::SysConsoleLogPack() @@ -131,7 +131,7 @@ SysConsoleLogPack::SysConsoleLogPack() static const SysTraceLogDescriptor TLD_SIF = { L"SIF", L"SIF (EE <-> IOP)", - wxLt(""), + pxDt(""), "SIF" }; @@ -142,109 +142,109 @@ TLD_SIF = { static const SysTraceLogDescriptor TLD_EE_Bios = { L"Bios", L"Bios", - wxLt("SYSCALL and DECI2 activity."), + pxDt("SYSCALL and DECI2 activity."), "EE" }, TLD_EE_Memory = { L"Memory", L"Memory", - wxLt("Direct memory accesses to unknown or unmapped EE memory space."), + pxDt("Direct memory accesses to unknown or unmapped EE memory space."), "eMem" }, TLD_EE_R5900 = { L"R5900", L"R5900 Core", - wxLt("Disasm of executing core instructions (excluding COPs and CACHE)."), + pxDt("Disasm of executing core instructions (excluding COPs and CACHE)."), "eDis" }, TLD_EE_COP0 = { L"COP0", L"COP0", - wxLt("Disasm of COP0 instructions (MMU, cpu and dma status, etc)."), + pxDt("Disasm of COP0 instructions (MMU, cpu and dma status, etc)."), "eDis" }, TLD_EE_COP1 = { L"FPU", L"COP1/FPU", - wxLt("Disasm of the EE's floating point unit (FPU) only."), + pxDt("Disasm of the EE's floating point unit (FPU) only."), "eDis" }, TLD_EE_COP2 = { L"VUmacro", L"COP2/VUmacro", - wxLt("Disasm of the EE's VU0macro co-processor instructions."), + pxDt("Disasm of the EE's VU0macro co-processor instructions."), "eDis" }, TLD_EE_Cache = { L"Cache", L"Cache", - wxLt("Execution of EE cache instructions."), + pxDt("Execution of EE cache instructions."), "eDis" }, TLD_EE_KnownHw = { L"HwRegs", L"Hardware Regs", - wxLt("All known hardware register accesses (very slow!); not including sub filter options below."), + pxDt("All known hardware register accesses (very slow!); not including sub filter options below."), "eReg" }, TLD_EE_UnknownHw = { L"UnknownRegs", L"Unknown Regs", - wxLt("Logs only unknown, unmapped, or unimplemented register accesses."), + pxDt("Logs only unknown, unmapped, or unimplemented register accesses."), "eReg" }, TLD_EE_DMAhw = { L"DmaRegs", L"DMA Regs", - wxLt("Logs only DMA-related registers."), + pxDt("Logs only DMA-related registers."), "eReg" }, TLD_EE_IPU = { L"IPU", L"IPU", - wxLt("IPU activity: hardware registers, decoding operations, DMA status, etc."), + pxDt("IPU activity: hardware registers, decoding operations, DMA status, etc."), "IPU" }, TLD_EE_GIFtag = { L"GIFtags", L"GIFtags", - wxLt("All GIFtag parse activity; path index, tag type, etc."), + pxDt("All GIFtag parse activity; path index, tag type, etc."), "GIF" }, TLD_EE_VIFcode = { L"VIFcodes", L"VIFcodes", - wxLt("All VIFcode processing; command, tag style, interrupts."), + pxDt("All VIFcode processing; command, tag style, interrupts."), "VIF" }, TLD_EE_SPR = { L"MFIFO", L"Scratchpad MFIFO", - wxLt("Scratchpad's MFIFO activity."), + pxDt("Scratchpad's MFIFO activity."), "SPR" }, TLD_EE_DMAC = { L"DmaCtrl", L"DMA Controller", - wxLt("Actual data transfer logs, bus right arbitration, stalls, etc."), + pxDt("Actual data transfer logs, bus right arbitration, stalls, etc."), "eDmaC" }, TLD_EE_Counters = { L"Counters", L"Counters", - wxLt("Tracks all EE counters events and some counter register activity."), + pxDt("Tracks all EE counters events and some counter register activity."), "eCnt" }, TLD_EE_VIF = { L"VIF", L"VIF", - wxLt("Dumps various VIF and VIFcode processing data."), + pxDt("Dumps various VIF and VIFcode processing data."), "VIF" }, TLD_EE_GIF = { L"GIF", L"GIF", - wxLt("Dumps various GIF and GIFtag parsing data."), + pxDt("Dumps various GIF and GIFtag parsing data."), "GIF" }; @@ -255,73 +255,73 @@ TLD_EE_GIF = { static const SysTraceLogDescriptor TLD_IOP_Bios = { L"Bios", L"Bios", - wxLt("SYSCALL and IRX activity."), + pxDt("SYSCALL and IRX activity."), "IOP" }, TLD_IOP_Memory = { L"Memory", L"Memory", - wxLt("Direct memory accesses to unknown or unmapped IOP memory space."), + pxDt("Direct memory accesses to unknown or unmapped IOP memory space."), "iMem" }, TLD_IOP_R3000A = { L"R3000A", L"R3000A Core", - wxLt("Disasm of executing core instructions (excluding COPs and CACHE)."), + pxDt("Disasm of executing core instructions (excluding COPs and CACHE)."), "iDis" }, TLD_IOP_COP2 = { L"COP2/GPU", L"COP2", - wxLt("Disasm of the IOP's GPU co-processor instructions."), + pxDt("Disasm of the IOP's GPU co-processor instructions."), "iDis" }, TLD_IOP_KnownHw = { L"HwRegs", L"Hardware Regs", - wxLt("All known hardware register accesses, not including the sub-filters below."), + pxDt("All known hardware register accesses, not including the sub-filters below."), "iReg" }, TLD_IOP_UnknownHw = { L"UnknownRegs", L"Unknown Regs", - wxLt("Logs only unknown, unmapped, or unimplemented register accesses."), + pxDt("Logs only unknown, unmapped, or unimplemented register accesses."), "iReg" }, TLD_IOP_DMAhw = { L"DmaRegs", L"DMA Regs", - wxLt("Logs only DMA-related registers."), + pxDt("Logs only DMA-related registers."), "iReg" }, TLD_IOP_Memcards = { L"Memorycards", L"Memorycards", - wxLt("Memorycard reads, writes, erases, terminators, and other processing."), + pxDt("Memorycard reads, writes, erases, terminators, and other processing."), "Mcd" }, TLD_IOP_PAD = { L"Pad", L"Pad", - wxLt("Gamepad activity on the SIO."), + pxDt("Gamepad activity on the SIO."), "Pad" }, TLD_IOP_DMAC = { L"DmaCrl", L"DMA Controller", - wxLt("Actual DMA event processing and data transfer logs."), + pxDt("Actual DMA event processing and data transfer logs."), "iDmaC" }, TLD_IOP_Counters = { L"Counters", L"Counters", - wxLt("Tracks all IOP counters events and some counter register activity."), + pxDt("Tracks all IOP counters events and some counter register activity."), "iCnt" }, TLD_IOP_CDVD = { L"CDVD", L"CDVD", - wxLt("Detailed logging of CDVD hardware."), + pxDt("Detailed logging of CDVD hardware."), "CDVD" }; diff --git a/pcsx2/System.cpp b/pcsx2/System.cpp index eb3dd07a3a..f0d6256365 100644 --- a/pcsx2/System.cpp +++ b/pcsx2/System.cpp @@ -21,9 +21,6 @@ #include "SamplProf.h" -// Includes needed for cleanup, since we don't have a good system (yet) for -// cleaning up these things. -#include "GameDatabase.h" #include "Elfheader.h" #include "System/RecTypes.h" @@ -114,7 +111,7 @@ void RecompiledCodeReserve::ThrowIfNotOk() const throw Exception::OutOfMemory(m_name) .SetDiagMsg(pxsFmt( L"Recompiled code cache could not be mapped." )) - .SetUserMsg( pxE( ".Error:Recompiler:VirtualMemoryAlloc", + .SetUserMsg( pxE( "!Notice:Recompiler:VirtualMemoryAlloc", L"This recompiler was unable to reserve contiguous memory required for internal caches. " L"This error can be caused by low virtual memory resources, such as a small or disabled swapfile, " L"or by another program that is hogging a lot of memory. You can also try reducing the default " @@ -133,25 +130,25 @@ void SysOutOfMemory_EmergencyResponse(uptr blocksize) if (Cpu) { - Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 3) / 2 ); + Cpu->SetCacheReserve( (Cpu->GetCacheReserve() * 2) / 3 ); Cpu->Reset(); } if (CpuVU0) { - CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 3) / 2 ); + CpuVU0->SetCacheReserve( (CpuVU0->GetCacheReserve() * 2) / 3 ); CpuVU0->Reset(); } if (CpuVU1) { - CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 3) / 2 ); + CpuVU1->SetCacheReserve( (CpuVU1->GetCacheReserve() * 2) / 3 ); CpuVU1->Reset(); } if (psxCpu) { - psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 3) / 2 ); + psxCpu->SetCacheReserve( (psxCpu->GetCacheReserve() * 2) / 3 ); psxCpu->Reset(); } } @@ -201,30 +198,37 @@ TraceLogFilters& SetTraceConfig() // This function should be called once during program execution. void SysLogMachineCaps() { - Console.WriteLn( Color_StrongGreen, "PCSX2 %u.%u.%u.r%d %s - compiled on " __DATE__, PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo, + Console.WriteLn( Color_StrongGreen, "PCSX2 %u.%u.%u.r%d %s - compiled on " __DATE__, + PCSX2_VersionHi, PCSX2_VersionMid, PCSX2_VersionLo, SVN_REV, SVN_MODS ? "(modded)" : "" ); Console.WriteLn( "Savestate version: 0x%x", g_SaveVersion); Console.Newline(); - Console.WriteLn( Color_StrongBlack, "x86-32 Init:" ); + Console.WriteLn( Color_StrongBlack, "Host Machine Init:" ); + + Console.Indent().WriteLn( + L"Operating System = %s\n" + L"Physical RAM = %u MB", + + GetOSVersionString().c_str(), + (u32)(GetPhysicalMemory() / _1mb) + ); u32 speed = x86caps.CalculateMHz(); Console.Indent().WriteLn( - L"CPU vendor name = %s\n" - L"FamilyID = %x\n" - L"x86Family = %s\n" - L"CPU speed = %d.%03d ghz\n" - L"Cores = %d physical [%d logical]\n" + L"CPU name = %s\n" + L"Vendor/Model = %s (stepping %02X)\n" + L"CPU speed = %u.%03u ghz (%u logical thread%s)\n" L"x86PType = %s\n" - L"x86Flags = %8.8x %8.8x\n" - L"x86EFlags = %8.8x", - fromUTF8( x86caps.VendorName ).c_str(), x86caps.StepID, + L"x86Flags = %08x %08x\n" + L"x86EFlags = %08x", fromUTF8( x86caps.FamilyName ).Trim().Trim(false).c_str(), + fromUTF8( x86caps.VendorName ).c_str(), x86caps.StepID, speed / 1000, speed % 1000, - x86caps.PhysicalCores, x86caps.LogicalCores, + x86caps.LogicalCores, (x86caps.LogicalCores==1) ? L"" : L"s", x86caps.GetTypeName().c_str(), x86caps.Flags, x86caps.Flags2, x86caps.EFlags @@ -339,7 +343,7 @@ public: // returns the translated error message for the Virtual Machine failing to allocate! static wxString GetMemoryErrorVM() { - return pxE( ".Error:EmuCore::MemoryForVM", + return pxE( "!Notice:EmuCore::MemoryForVM", L"PCSX2 is unable to allocate memory needed for the PS2 virtual machine. " L"Close out some memory hogging background tasks and try again." ); @@ -598,7 +602,7 @@ wxString SysGetDiscID() if( !ElfCRC ) { - // FIXME: If the system is currently running the BIOS, it should return a serial based on + // FIXME: system is currently running the BIOS, so it should return a serial based on // the BIOS being run (either a checksum of the BIOS roms, and/or a string based on BIOS // region and revision). } diff --git a/pcsx2/System/SysCoreThread.cpp b/pcsx2/System/SysCoreThread.cpp index 19de3f2a32..3eed44ff3b 100644 --- a/pcsx2/System/SysCoreThread.cpp +++ b/pcsx2/System/SysCoreThread.cpp @@ -151,7 +151,6 @@ void SysCoreThread::UploadStateCopy( const VmStateBuffer& copy ) if( !pxAssertDev( IsPaused(), "CoreThread is not paused; new VM state cannot be uploaded." ) ) return; memLoadingState loadme( copy ); - loadme.FreezeMainMemory(); loadme.FreezeAll(); m_resetVirtualMachine = false; } diff --git a/pcsx2/Vif.cpp b/pcsx2/Vif.cpp index f2d0b7da1c..6aff2b884a 100644 --- a/pcsx2/Vif.cpp +++ b/pcsx2/Vif.cpp @@ -77,12 +77,16 @@ __fi void vif0FBRST(u32 value) { memzero(vif0); vif0ch.qwc = 0; //? - cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's + //cpuRegs.interrupt &= ~1; //Stop all vif0 DMA's psHu64(VIF0_FIFO) = 0; psHu64(VIF0_FIFO + 8) = 0; - vif0.done = false; + vif0.vifstalled = false; + vif0.inprogress = 0; + vif0.cmd = 0; + //vif0.done = false; vif0Regs.err.reset(); vif0Regs.stat.clear_flags(VIF0_STAT_FQC | VIF0_STAT_INT | VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS | VIF0_STAT_VPS); // FQC=0 + if(vif0ch.chcr.STR == true) CPU_INT(DMAC_VIF0, 4); } /* Fixme: Forcebreaks are pretty unknown for operation, presumption is it just stops it what its doing @@ -137,7 +141,8 @@ __fi void vif1FBRST(u32 value) { memzero(vif1); //cpuRegs.interrupt &= ~((1 << 1) | (1 << 10)); //Stop all vif1 DMA's - vif1ch.qwc -= min((int)vif1ch.qwc, 16); //? + //vif1ch.qwc -= min((int)vif1ch.qwc, 16); //not sure if the dma should stop, FFWDing could be tricky + vif1ch.qwc = 0; psHu64(VIF1_FIFO) = 0; psHu64(VIF1_FIFO + 8) = 0; //vif1.done = false; @@ -160,6 +165,7 @@ __fi void vif1FBRST(u32 value) { vif1.vifstalled = false; vif1Regs.stat.FQC = 0; vif1Regs.stat.clear_flags(VIF1_STAT_FDR | VIF1_STAT_INT | VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS | VIF1_STAT_VPS); + if(vif1ch.chcr.STR == true) CPU_INT(DMAC_VIF1, 4); } /* Fixme: Forcebreaks are pretty unknown for operation, presumption is it just stops it what its doing diff --git a/pcsx2/Vif1_Dma.cpp b/pcsx2/Vif1_Dma.cpp index 4cf76447ae..306ec29c0a 100644 --- a/pcsx2/Vif1_Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -155,9 +155,9 @@ bool _VIF1chain() vif1ch.qwc, vif1ch.madr, vif1ch.tadr); if (vif1.vifstalled) - return VIF1transfer(pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset); + return VIF1transfer(pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset, false); else - return VIF1transfer(pMem, vif1ch.qwc * 4); + return VIF1transfer(pMem, vif1ch.qwc * 4, false); } __fi void vif1SetupTransfer() @@ -490,7 +490,7 @@ void dmaVIF1() if(vif1ch.chcr.MOD == CHAIN_MODE && vif1.dmamode != VIF_NORMAL_TO_MEM_MODE) { vif1.dmamode = VIF_CHAIN_MODE; - DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc()); + //DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc()); if ((vif1ch.chcr.tag().ID == TAG_REFE) || (vif1ch.chcr.tag().ID == TAG_END)) { @@ -502,6 +502,7 @@ void dmaVIF1() { vif1.dmamode = VIF_CHAIN_MODE; vif1.done = false; + vif1.inprogress = 0; } if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = min((u16)0x10, vif1ch.qwc); diff --git a/pcsx2/Vif1_MFIFO.cpp b/pcsx2/Vif1_MFIFO.cpp index 910a51e752..4142197f37 100644 --- a/pcsx2/Vif1_MFIFO.cpp +++ b/pcsx2/Vif1_MFIFO.cpp @@ -32,14 +32,39 @@ static u32 qwctag(u32 mask) return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK)); } +static u16 QWCinVIFMFIFO(u32 DrainADDR) +{ + u32 ret; + + + SPR_LOG("VIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", vif1ch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR); + //Calculate what we have in the fifo. + if(DrainADDR <= spr0ch.madr) + { + //Drain is below the tadr, calculate the difference between them + ret = (spr0ch.madr - DrainADDR) >> 4; + } + else + { + u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; + //Drain is higher than SPR so it has looped round, + //calculate from base to the SPR tag addr and what is left in the top of the ring + ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4; + } + SPR_LOG("%x Available of the %x requested", ret, vif1ch.qwc); + + return ret; +} static __fi bool mfifoVIF1rbTransfer() { u32 maddr = dmacRegs.rbor.ADDR; u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; - u16 mfifoqwc = std::min(vif1ch.qwc, vifqwc); + u16 mfifoqwc = min(QWCinVIFMFIFO(vif1ch.madr), vif1ch.qwc); u32 *src; bool ret; + if(mfifoqwc == 0) return true; //Cant do anything, lets forget it + /* Check if the transfer should wrap around the ring buffer */ if ((vif1ch.madr + (mfifoqwc << 4)) > (msize)) { @@ -48,6 +73,8 @@ static __fi bool mfifoVIF1rbTransfer() SPR_LOG("Split MFIFO"); /* it does, so first copy 's1' bytes from 'addr' to 'data' */ + vif1ch.madr = qwctag(vif1ch.madr); + src = (u32*)PSM(vif1ch.madr); if (src == NULL) return false; @@ -56,10 +83,9 @@ static __fi bool mfifoVIF1rbTransfer() else ret = VIF1transfer(src, s1); - vif1ch.madr = qwctag(vif1ch.madr); - if (ret) { + if(vif1.irqoffset != 0) DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset); /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ vif1ch.madr = maddr; @@ -67,13 +93,12 @@ static __fi bool mfifoVIF1rbTransfer() if (src == NULL) return false; VIF1transfer(src, ((mfifoqwc << 2) - s1)); } - vif1ch.madr = qwctag(vif1ch.madr); } else { SPR_LOG("Direct MFIFO"); - + /* it doesn't, so just transfer 'qwc*4' words */ src = (u32*)PSM(vif1ch.madr); if (src == NULL) return false; @@ -83,8 +108,6 @@ static __fi bool mfifoVIF1rbTransfer() else ret = VIF1transfer(src, mfifoqwc << 2); - vif1ch.madr = qwctag(vif1ch.madr); - } return ret; } @@ -99,13 +122,17 @@ static __fi void mfifo_VIF1chain() } if (vif1ch.madr >= dmacRegs.rbor.ADDR && - vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)) - { - //Need to exit on mfifo locations, if the madr is matching the madr of spr, we dont have any data left :( - - u16 startqwc = vif1ch.qwc; + vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) + { + if(vif1ch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge VIF1"); + + vif1ch.madr = qwctag(vif1ch.madr); mfifoVIF1rbTransfer(); - vifqwc -= startqwc - vif1ch.qwc; + vif1ch.tadr = qwctag(vif1ch.tadr); + vif1ch.madr = qwctag(vif1ch.madr); + if(QWCinVIFMFIFO(vif1ch.madr) == 0) vif1.inprogress |= 0x10; + + //vifqwc -= startqwc - vif1ch.qwc; } else @@ -124,8 +151,6 @@ static __fi void mfifo_VIF1chain() } } -int NextTADR = 0; //Bodge for Clock Tower 3 (see below) - void mfifoVIF1transfer(int qwc) { tDMA_TAG *ptag; @@ -134,11 +159,15 @@ void mfifoVIF1transfer(int qwc) if (qwc > 0) { - vifqwc += qwc; - SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vifqwc, vif1ch.chcr._u32, vif1.vifstalled, vif1.done); + //vifqwc += qwc; + SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vif1ch.chcr._u32, vif1.vifstalled, vif1.done); if (vif1.inprogress & 0x10) { - if(vif1ch.chcr.STR == true)CPU_INT(DMAC_MFIFO_VIF, 4); + if(vif1ch.chcr.STR == true && !(cpuRegs.interrupt & (1< 0) + if (vif1ch.qwc == 0) { + vif1ch.tadr = qwctag(vif1ch.tadr); ptag = dmaGetAddr(vif1ch.tadr, false); if (vif1ch.chcr.TTE) @@ -169,63 +199,32 @@ void mfifoVIF1transfer(int qwc) } else { - ret = VIF1transfer((u32*)&masked_tag, 4, true); //Transfer Tag + vif1.irqoffset = 2; + ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag //ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag } if (!ret && vif1.irqoffset) { + vif1.inprogress &= ~1; return; //IRQ set by VIFTransfer } //else vif1.vifstalled = false; g_vifCycles += 2; } - + vif1.irqoffset = 0; vif1ch.unsafeTransfer(ptag); vif1ch.madr = ptag[1]._u32; - vifqwc--; + + //vifqwc--; SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x", ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, vifqwc, spr0ch.madr); - switch (ptag->ID) - { - case TAG_REFE: // Refe - Transfer Packet According to ADDR field - NextTADR = qwctag(vif1ch.tadr + 16); - vif1.done = true; //End Transfer - break; - - case TAG_CNT: // CNT - Transfer QWC following the tag. - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to QW after Tag - NextTADR = qwctag(vif1ch.madr + (vif1ch.qwc << 4)); //Set TADR to QW following the data - vif1.done = false; - break; - - case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR - { - int temp = vif1ch.madr; //Temporarily Store ADDR - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to QW following the tag - NextTADR = temp; //Copy temporarily stored ADDR to Tag - if ((temp & dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("Next tag = %x outside ring %x size %x", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR)); - vif1.done = false; - break; - } - - case TAG_REF: // Ref - Transfer QWC from ADDR field - case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control) - NextTADR = qwctag(vif1ch.tadr + 16); //Set TADR to next tag - vif1.done = false; - break; - - case TAG_END: // End - Transfer QWC following the tag - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to data following the tag - NextTADR = qwctag(vif1ch.madr + (vif1ch.qwc << 4)); //Set TADR to QW following the data - vif1.done = true; //End Transfer - break; - } + vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); if (vif1ch.chcr.TIE && ptag->IRQ) { @@ -233,8 +232,16 @@ void mfifoVIF1transfer(int qwc) vif1.done = true; } - vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); - vif1.inprogress |= 1; + + if(vif1ch.qwc > 0) vif1.inprogress |= 1; + + vif1ch.tadr = qwctag(vif1ch.tadr); + + if(QWCinVIFMFIFO(vif1ch.tadr) == 0) vif1.inprogress |= 0x10; + } + else + { + DevCon.Warning("Vif MFIFO QWC not 0 on tag"); } @@ -247,14 +254,10 @@ void vifMFIFOInterrupt() VIF_LOG("vif mfifo interrupt"); - if(NextTADR != 0 && vif1ch.qwc == 0) + if (dmacRegs.ctrl.MFD != MFD_VIF1) { - // Clock Tower 3 Note! - /* If the DMA starts the transfer then hammers the TADR to see when the transfer has finished(as clock tower does) - and we have preincremented before all data has arrived, it breaks. Idealy we increment this as we transfer the data. - "NextTADR" bodge in for the moment! - Refraction */ - vif1ch.tadr = NextTADR; - NextTADR = 0; + DevCon.Warning("Not in VIF MFIFO mode! Stopping VIF MFIFO"); + return; } if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2) @@ -269,7 +272,11 @@ void vifMFIFOInterrupt() if (schedulepath3msk & 0x10) Vif1MskPath3(); - if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false) return; + if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false) + { + SPR_LOG("Waiting for PATH to be ready"); + return; + } //We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing) //Simulated GS transfer time done, clear the flags @@ -283,8 +290,10 @@ void vifMFIFOInterrupt() vif1Regs.stat.VPS = VPS_IDLE; } + if (vif1.irq && vif1.tag.size == 0) { + SPR_LOG("VIF MFIFO Code Interrupt detected"); vif1Regs.stat.INT = true; hwIntcIrq(INTC_VIF1); --vif1.irq; @@ -293,55 +302,40 @@ void vifMFIFOInterrupt() { /*vif1Regs.stat.FQC = 0; // FQC=0 vif1ch.chcr.STR = false;*/ - if(vif1ch.qwc > 0 || !vif1.done) return; + if((vif1ch.qwc > 0 || !vif1.done) && !(vif1.inprogress & 0x10)) return; } } + if(vif1.inprogress & 0x10) + { + FireMFIFOEmpty(); + if(!(vif1.done && vif1ch.qwc == 0))return; + } + if (vif1.done == false || vif1ch.qwc) { + switch(vif1.inprogress & 1) { case 0: //Set up transfer - if (vif1ch.tadr == spr0ch.madr) + if (QWCinVIFMFIFO(vif1ch.tadr) == 0) { - // Console.WriteLn("Empty 1"); - vifqwc = 0; - if((vif1.inprogress & 0x10) == 0) - { - hwDmacIrq(DMAC_MFIFO_EMPTY); - vif1.inprogress |= 0x10; - } - vif1Regs.stat.FQC = 0; + vif1.inprogress |= 0x10; + CPU_INT(DMAC_MFIFO_VIF, 4 ); return; } - + mfifoVIF1transfer(0); - - CPU_INT(DMAC_MFIFO_VIF, 4); - return; - case 1: //Transfer data mfifo_VIF1chain(); //Sanity check! making sure we always have non-zero values - CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) ); + CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) ); return; } return; - } + } - - //FF7 Dirge of Cerberus seems to like the mfifo to tell it when it's empty, even if it's ending. - //Doesn't seem to care about the vif1 dma interrupting (possibly disabled the interrupt?) - if (vif1ch.tadr == spr0ch.madr) - { - vifqwc = 0; - if((vif1.inprogress & 0x10) == 0) - { - hwDmacIrq(DMAC_MFIFO_EMPTY); - vif1.inprogress |= 0x10; - } - } vif1.vifstalled = false; vif1.done = 1; g_vifCycles = 0; diff --git a/pcsx2/Vif_Codes.cpp b/pcsx2/Vif_Codes.cpp index 1e299668a0..1aa4c23928 100644 --- a/pcsx2/Vif_Codes.cpp +++ b/pcsx2/Vif_Codes.cpp @@ -115,6 +115,8 @@ vifOp(vifCode_Base) { } extern bool SIGNAL_IMR_Pending; +static __aligned16 u32 partial_write[4]; +static uint partial_count = 0; template __fi int _vifCode_Direct(int pass, const u8* data, bool isDirectHL) { pass1 { @@ -154,7 +156,7 @@ template __fi int _vifCode_Direct(int pass, const u8* data, bool isDire } if(SIGNAL_IMR_Pending == true) { - DevCon.Warning("Path 2 Paused (At start)"); + //DevCon.Warning("Path 2 Paused (At start)"); vif1.vifstalled = true; return 0; } @@ -175,7 +177,7 @@ template __fi int _vifCode_Direct(int pass, const u8* data, bool isDire uint minSize = aMin(vif1.vifpacketsize, vif1.tag.size); uint ret; - if(minSize < 4) + if(minSize < 4 || partial_count > 0) { // When TTE==1, the VIF might end up sending us 8-byte packets instead of the usual 16-byte // variety, if DIRECT tags cross chain dma boundaries. The actual behavior of real hardware @@ -189,21 +191,24 @@ template __fi int _vifCode_Direct(int pass, const u8* data, bool isDire // be any need to worry about queuing more than 16 bytes of data, // - static __aligned16 u32 partial_write[4]; - static uint partial_count = 0; + + ret = 0; + minSize = aMin(minSize, 4-partial_count); for( uint i=0; i<(minSize & 3); ++i) + { partial_write[partial_count++] = ((u32*)data)[i]; + ret++; + } pxAssume( partial_count <= 4 ); - ret = 0; + if (partial_count == 4) { GetMTGS().PrepDataPacket(GIF_PATH_2, 1); GIFPath_CopyTag(GIF_PATH_2, (u128*)partial_write, 1); GetMTGS().SendDataPacket(); partial_count = 0; - ret = 4; } } else @@ -372,14 +377,16 @@ vifOp(vifCode_MSCNT) { vifOp(vifCode_MskPath3) { vif1Only(); pass1 { + //I Hate the timing sensitivity of this stuff if (vif1ch.chcr.STR && vif1.lastcmd != 0x13) { - schedulepath3msk = 0x10 | ((vif1Regs.code >> 15) & 0x1); - vif1.vifstalled = true; + schedulepath3msk = 0x10 | ((vif1Regs.code >> 15) & 0x1); } - else { + else + { schedulepath3msk = (vif1Regs.code >> 15) & 0x1; Vif1MskPath3(); } + if(vif1ch.chcr.STR)vif1.vifstalled = true; vif1.cmd = 0; } pass3 { VifCodeLog("MskPath3"); } diff --git a/pcsx2/Vif_Transfer.cpp b/pcsx2/Vif_Transfer.cpp index ea027086a4..ec3a8bcf73 100644 --- a/pcsx2/Vif_Transfer.cpp +++ b/pcsx2/Vif_Transfer.cpp @@ -25,7 +25,7 @@ // Doesn't stall if the next vifCode is the Mark command _vifT bool runMark(u32* &data) { if (((vifXRegs.code >> 24) & 0x7f) == 0x7) { - DevCon.WriteLn("Vif%d: Running Mark with I-bit", idx); + //DevCon.WriteLn("Vif%d: Running Mark with I-bit", idx); return 1; // No Stall? } return 1; // Stall @@ -145,12 +145,21 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) { vifXch.madr +=(transferred << 4); vifXch.qwc -= transferred; - } + if(vifXch.chcr.STR)hwDmacSrcTadrInc(vifXch); - if (!vifXch.qwc && !vifX.irqoffset) + if (!vifXch.qwc) + { + vifX.inprogress &= ~0x1; + vifX.vifstalled = false; + } + } + else { - vifX.inprogress &= ~0x1; - vifX.vifstalled = false; + + if(!vifX.irqoffset) + { + vifX.vifstalled = false; + } } if (vifX.irq && vifX.cmd == 0) { diff --git a/pcsx2/ZipTools/ThreadedZipTools.h b/pcsx2/ZipTools/ThreadedZipTools.h index f56242705b..26024b3dda 100644 --- a/pcsx2/ZipTools/ThreadedZipTools.h +++ b/pcsx2/ZipTools/ThreadedZipTools.h @@ -21,22 +21,6 @@ using namespace Threading; -// -------------------------------------------------------------------------------------- -// BaseArchiveEntry -// -------------------------------------------------------------------------------------- -class BaseArchiveEntry -{ -protected: - BaseArchiveEntry() {} - virtual ~BaseArchiveEntry() throw() {} - -public: - virtual wxString GetFilename() const=0; - virtual u8* GetDataPtr() const=0; - virtual uint GetDataSize() const=0; -}; - - // -------------------------------------------------------------------------------------- // ArchiveEntry // -------------------------------------------------------------------------------------- diff --git a/pcsx2/gui/AdvancedDialog.cpp b/pcsx2/gui/AdvancedDialog.cpp deleted file mode 100644 index 91bee6fb09..0000000000 --- a/pcsx2/gui/AdvancedDialog.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 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 . - */ - -#include "PrecompiledHeader.h" diff --git a/pcsx2/gui/AdvancedDialog.h b/pcsx2/gui/AdvancedDialog.h deleted file mode 100644 index 3c71fcab80..0000000000 --- a/pcsx2/gui/AdvancedDialog.h +++ /dev/null @@ -1,21 +0,0 @@ -/* PCSX2 - PS2 Emulator for PCs - * Copyright (C) 2002-2010 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 . - */ - -#ifndef ADVANCEDDIALOG_H_INCLUDED -#define ADVANCEDDIALOG_H_INCLUDED - - - -#endif // ADVANCEDDIALOG_H_INCLUDED diff --git a/pcsx2/gui/App.h b/pcsx2/gui/App.h index 89538f7810..d92e35e947 100644 --- a/pcsx2/gui/App.h +++ b/pcsx2/gui/App.h @@ -47,6 +47,14 @@ static const int pxID_PadHandler_Keydown = 8030; // single for-loop to create them. static const int PluginMenuId_Interval = 0x10; +// ID and return code used for modal popups that have a custom button. +static const wxWindowID pxID_CUSTOM = wxID_LOWEST - 1; + +// Return code used by first time wizard if the dialog needs to be automatically recreated +// (assigned an arbitrary value) +static const wxWindowID pxID_RestartWizard = wxID_LOWEST - 100; + + // Forces the Interface to destroy the GS viewport window when the GS plugin is // destroyed. This has the side effect of forcing all plugins to close and re-open // along with the GS, since the GS viewport window handle will have changed. @@ -109,6 +117,7 @@ enum MenuIdentifiers MenuId_Config_AppSettings, MenuId_Config_GameDatabase, MenuId_Config_BIOS, + MenuId_Config_Language, // Plugin ID order is important. Must match the order in tbl_PluginInfo. MenuId_Config_GS, @@ -359,6 +368,10 @@ class Pcsx2AppTraits : public wxGUIAppTraits public: virtual ~Pcsx2AppTraits() {} wxMessageOutput* CreateMessageOutput(); + +#ifdef wxUSE_STDPATHS + wxStandardPathsBase& GetStandardPaths(); +#endif }; // ===================================================================================================== diff --git a/pcsx2/gui/AppConfig.cpp b/pcsx2/gui/AppConfig.cpp index 8a0b525c6f..acc84134b5 100644 --- a/pcsx2/gui/AppConfig.cpp +++ b/pcsx2/gui/AppConfig.cpp @@ -97,26 +97,7 @@ namespace PathDefs // Specifies the main configuration folder. wxDirName GetUserLocalDataDir() { -#ifdef __LINUX__ - // Note: GetUserLocalDataDir() on linux return $HOME/.pcsx2 unfortunately it does not follow the XDG standard - // So we re-implement it, to follow the standard. - wxDirName user_local_dir; - wxString xdg_home_value; - if( wxGetEnv(L"XDG_CONFIG_HOME", &xdg_home_value) ) { - if ( xdg_home_value.IsEmpty() ) { - // variable exist but it is empty. So use the default value - user_local_dir = (wxDirName)Path::Combine( wxStandardPaths::Get().GetUserConfigDir() , wxDirName( L".config/pcsx2" )); - } else { - user_local_dir = (wxDirName)Path::Combine( xdg_home_value, pxGetAppName()); - } - } else { - // variable do not exist - user_local_dir = (wxDirName)Path::Combine( wxStandardPaths::Get().GetUserConfigDir() , wxDirName( L".config/pcsx2" )); - } - return user_local_dir; -#else return wxDirName(wxStandardPaths::Get().GetUserLocalDataDir()); -#endif } // Fetches the path location for user-consumable documents -- stuff users are likely to want to @@ -384,6 +365,7 @@ AppConfig::AppConfig() , DeskTheme( L"default" ) { LanguageId = wxLANGUAGE_DEFAULT; + LanguageCode = L"default"; RecentIsoCount = 12; Listbook_ImageSize = 32; Toolbar_ImageSize = 24; @@ -487,6 +469,7 @@ void AppConfig::LoadSaveRootItems( IniInterface& ini ) IniEntry( AppSettingsTabName ); IniEntry( GameDatabaseTabName ); ini.EnumEntry( L"LanguageId", LanguageId, NULL, defaults.LanguageId ); + IniEntry( LanguageCode ); IniEntry( RecentIsoCount ); IniEntry( DeskTheme ); IniEntry( Listbook_ImageSize ); @@ -780,7 +763,8 @@ void AppConfig_OnChangedSettingsFolder( bool overwrite ) if( overwrite ) { if( wxFileExists( iniFilename ) && !wxRemoveFile( iniFilename ) ) - throw Exception::AccessDenied(iniFilename).SetBothMsgs(wxLt("Failed to overwrite existing settings file; permission was denied.")); + throw Exception::AccessDenied(iniFilename) + .SetBothMsgs(pxL("Failed to overwrite existing settings file; permission was denied.")); } // Bind into wxConfigBase to allow wx to use our config internally, and delete whatever diff --git a/pcsx2/gui/AppConfig.h b/pcsx2/gui/AppConfig.h index ab5a345893..7430b6371b 100644 --- a/pcsx2/gui/AppConfig.h +++ b/pcsx2/gui/AppConfig.h @@ -195,9 +195,14 @@ public: wxString AppSettingsTabName; wxString GameDatabaseTabName; - // Current language in use (correlates to a wxWidgets wxLANGUAGE specifier) + // Currently selected language ID -- wxWidgets version-specific identifier. This is one side of + // a two-part configuration that also includes LanguageCode. wxLanguage LanguageId; + // Current language in use (correlates to the universal language codes, such as "en_US", "de_DE", etc). + // This code is not always unique, which is why we use the language ID also. + wxString LanguageCode; + int RecentIsoCount; // number of files displayed in the Recent Isos list. // String value describing the desktop theme to use for pcsk2 (icons and background images) diff --git a/pcsx2/gui/AppInit.cpp b/pcsx2/gui/AppInit.cpp index a24629cd65..7c8fbc91ea 100644 --- a/pcsx2/gui/AppInit.cpp +++ b/pcsx2/gui/AppInit.cpp @@ -41,7 +41,7 @@ static void CpuCheckSSE2() wxDialogWithHelpers exconf( NULL, _("PCSX2 - SSE2 Recommended") ); - exconf += exconf.Heading( pxE( ".Popup:Startup:NoSSE2", + exconf += exconf.Heading( pxE( "!Notice:Startup:NoSSE2", L"Warning: Your computer does not support SSE2, which is required by many PCSX2 recompilers and plugins. " L"Your options will be limited and emulation will be *very* slow." ) ); @@ -70,12 +70,30 @@ void Pcsx2App::WipeUserModeSettings() usermodefile.SetPath( usrlocaldir.ToString() ); ScopedPtr conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) ); - wxString groupname( wxsFormat( L"CWD.%08x", hashres ) ); + FastFormatUnicode groupname; + groupname.Write( L"CWD.%08x", hashres ); Console.WriteLn( "(UserModeSettings) Removing entry:" ); Console.Indent().WriteLn( L"Path: %s\nHash:%s", cwd.c_str(), groupname.c_str() ); conf_usermode->DeleteGroup( groupname ); } +static void DoFirstTimeWizard() +{ + // first time startup, so give the user the choice of user mode: + while(true) + { + // PCSX2's FTWizard allows improptu restarting of the wizard without cancellation. This is + // typically used to change the user's language selection. + + FirstTimeWizard wiz( NULL ); + if( wiz.RunWizard( wiz.GetUsermodePage() ) ) break; + if (wiz.GetReturnCode() != pxID_RestartWizard) + throw Exception::StartupAborted( L"User canceled FirstTime Wizard." ); + + Console.WriteLn( Color_StrongBlack, "Restarting First Time Wizard!" ); + } +} + // User mode settings can't be stored in the CWD for two reasons: // (a) the user may not have permission to do so (most obvious) // (b) it would result in sloppy usermode.ini found all over a hard drive if people runs the @@ -104,7 +122,8 @@ void Pcsx2App::ReadUserModeSettings() usermodefile.SetPath( usrlocaldir.ToString() ); ScopedPtr conf_usermode( OpenFileConfig( usermodefile.GetFullPath() ) ); - wxString groupname( wxsFormat( L"CWD.%08x", hashres ) ); + FastFormatUnicode groupname; + groupname.Write( L"CWD.%08x", hashres ); bool hasGroup = conf_usermode->HasGroup( groupname ); bool forceWiz = Startup.ForceWizard || !hasGroup; @@ -135,10 +154,7 @@ void Pcsx2App::ReadUserModeSettings() } #endif - // first time startup, so give the user the choice of user mode: - FirstTimeWizard wiz( NULL ); - if( !wiz.RunWizard( wiz.GetUsermodePage() ) ) - throw Exception::StartupAborted( L"User canceled FirstTime Wizard." ); + DoFirstTimeWizard(); // Save user's new settings IniSaver saver( *conf_usermode ); @@ -159,14 +175,8 @@ void Pcsx2App::ReadUserModeSettings() if( !wxFile::Exists( GetSettingsFilename() ) ) { // user wiped their pcsx2.ini -- needs a reconfiguration via wizard! - // (we skip the first page since it's a usermode.ini thing) - - // Fixme : Skipping the first page is a bad idea, as it does a lot of file / directory checks on hitting Apply. - // If anything is missing, the first page prompts to fix it. - // If we skip this check, it's very likely that actions like creating Memory Cards will fail. - FirstTimeWizard wiz( NULL ); - if( !wiz.RunWizard( /*wiz.GetPostUsermodePage()*/ wiz.GetUsermodePage() ) ) - throw Exception::StartupAborted( L"User canceled Configuration Wizard." ); + + DoFirstTimeWizard(); // Save user's new settings IniSaver saver( *conf_usermode ); @@ -236,6 +246,19 @@ void Pcsx2App::OpenProgramLog() EnableAllLogging(); if( m_current_focus ) m_current_focus->SetFocus(); + + // This is test code for printing out all supported languages and their canonical names in wiki-fied + // format. I might use it again soon, so I'm leaving it in for now... --air + /* + for( int li=wxLANGUAGE_UNKNOWN+1; liLanguage)) continue; + Console.WriteLn( L"|| %-30s || %-8s ||", info->Description.c_str(), info->CanonicalName.c_str() ); + } + } + */ } void Pcsx2App::AllocateCoreStuffs() @@ -264,7 +287,7 @@ void Pcsx2App::AllocateCoreStuffs() wxDialogWithHelpers exconf( NULL, _("PCSX2 Recompiler Error(s)") ); exconf += 12; - exconf += exconf.Heading( pxE( ".Popup:RecompilerInit:Header", + exconf += exconf.Heading( pxE( "!Notice:RecompilerInit:Header", L"Warning: Some of the configured PS2 recompilers failed to initialize and have been disabled:" ) ); @@ -318,7 +341,7 @@ void Pcsx2App::AllocateCoreStuffs() recOps.EnableVU1 = recOps.EnableVU1 && recOps.UseMicroVU1; } - exconf += exconf.Heading( pxE(".Popup:RecompilerInit:Footer", + exconf += exconf.Heading( pxE("!Notice:RecompilerInit:Footer", L"Note: Recompilers are not necessary for PCSX2 to run, however they typically improve emulation speed substantially. " L"You may have to manually re-enable the recompilers listed above, if you resolve the errors." ) ); @@ -365,7 +388,7 @@ void Pcsx2App::OnInitCmdLine( wxCmdLineParser& parser ) const PluginInfo* pi = tbl_PluginInfo; do { parser.AddOption( wxEmptyString, pi->GetShortname().Lower(), - wxsFormat( _("specify the file to use as the %s plugin"), pi->GetShortname().c_str() ) + pxsFmt( _("specify the file to use as the %s plugin"), pi->GetShortname().c_str() ) ); } while( ++pi, pi->shortname != NULL ); @@ -524,6 +547,9 @@ bool Pcsx2App::OnInit() g_Conf = new AppConfig(); wxInitAllImageHandlers(); + Console.WriteLn("Applying operating system default language..."); + i18n_SetLanguage( wxLANGUAGE_DEFAULT ); + Console.WriteLn("Command line parsing..."); if( !_parent::OnInit() ) return false; Console.WriteLn("Command line parsed!"); @@ -552,8 +578,6 @@ bool Pcsx2App::OnInit() InitDefaultGlobalAccelerators(); delete wxLog::SetActiveTarget( new pxLogConsole() ); - m_RecentIsoList = new RecentIsoList(); - #ifdef __WXMSW__ pxDwm_Load(); #endif @@ -775,6 +799,28 @@ protected: Pcsx2App::Pcsx2App() : SysExecutorThread( new SysEvtHandler() ) { + #if 0 + { + // Some common labels provided by wxWidgets. wxWidgets translation files are chucked full + // of worthless crap, and tally more than 200k each. We only need these couple. + + _("OK"); + _("&OK"); + _("Cancel"); + _("&Cancel"); + _("&Apply"); + _("&Next >"); + _("&Back >"); + _("&Back"); + _("&Finish"); + + _("&Save"); + _("Save &As..."); + _("&Help"); + _("&Home"); + } + #endif + m_PendingSaves = 0; m_ScheduledTermination = false; diff --git a/pcsx2/gui/AppMain.cpp b/pcsx2/gui/AppMain.cpp index fa64938bd9..21d9399b34 100644 --- a/pcsx2/gui/AppMain.cpp +++ b/pcsx2/gui/AppMain.cpp @@ -29,6 +29,8 @@ #include "Utilities/IniInterface.h" +#include + #ifdef __WXMSW__ # include // needed to implement the app! #endif @@ -275,6 +277,12 @@ public: virtual void Printf(const wxChar* format, ...); }; +// EXTRAORDINARY HACK! wxWidgets does not provide a clean way of overriding the commandline options +// display dialog. The default one uses operating system built-in message/notice windows, which are +// appaling, ugly, and not at all suited to a large number of command line options. Fortunately, +// wxMessageOutputMessageBox::PrintF is only used in like two places, so we can just check for the +// commandline window using an identifier we know is contained in it, and then format our own window +// display. :D --air void pxMessageOutputMessageBox::Printf(const wxChar* format, ...) { using namespace pxSizerFlags; @@ -285,14 +293,16 @@ void pxMessageOutputMessageBox::Printf(const wxChar* format, ...) out.PrintfV(format, args); va_end(args); - int pos = out.Find( L"[IsoFile]" ); + FastFormatUnicode isoFormatted; + isoFormatted.Write( L"[%s]", _("IsoFile") ); + int pos = out.Find( isoFormatted ); if(pos == wxNOT_FOUND) { Msgbox::Alert( out ); return; } - pos += 9; // strlen of [IsoFile] + pos += isoFormatted.Length(); wxDialogWithHelpers popup( NULL, AddAppName(_("%s Commandline Options")) ); popup.SetMinWidth( 640 ); @@ -305,8 +315,8 @@ void pxMessageOutputMessageBox::Printf(const wxChar* format, ...) wxTE_READONLY | wxTE_MULTILINE | wxTE_RICH2 | wxHSCROLL ); - traceArea->SetDefaultStyle( wxTextAttr( wxNullColour, wxNullColour, pxGetFixedFont() ) ); - traceArea->SetFont( pxGetFixedFont() ); + traceArea->SetDefaultStyle( wxTextAttr( wxNullColour, wxNullColour, pxGetFixedFont(9) ) ); + traceArea->SetFont( pxGetFixedFont(9) ); int fonty = traceArea->GetCharHeight(); @@ -328,7 +338,54 @@ wxMessageOutput* Pcsx2AppTraits::CreateMessageOutput() return new pxMessageOutputMessageBox; #endif } - + +// -------------------------------------------------------------------------------------- +// Pcsx2StandardPaths +// -------------------------------------------------------------------------------------- +#ifdef wxUSE_STDPATHS +class Pcsx2StandardPaths : public wxStandardPaths +{ +public: + wxString GetResourcesDir() const + { + return Path::Combine( GetDataDir(), L"Langs" ); + } + +#ifdef __LINUX__ + wxString GetUserLocalDataDir() const + { + // Note: GetUserLocalDataDir() on linux return $HOME/.pcsx2 unfortunately it does not follow the XDG standard + // So we re-implement it, to follow the standard. + wxDirName user_local_dir; + wxString xdg_home_value; + if( wxGetEnv(L"XDG_CONFIG_HOME", &xdg_home_value) ) { + if ( xdg_home_value.IsEmpty() ) { + // variable exist but it is empty. So use the default value + user_local_dir = (wxDirName)Path::Combine( GetUserConfigDir() , wxDirName( L".config/pcsx2" )); + } else { + user_local_dir = (wxDirName)Path::Combine( xdg_home_value, pxGetAppName()); + } + } else { + // variable do not exist + user_local_dir = (wxDirName)Path::Combine( GetUserConfigDir() , wxDirName( L".config/pcsx2" )); + } + return user_local_dir.ToString(); + } +#endif +}; + +wxStandardPathsBase& Pcsx2AppTraits::GetStandardPaths() +{ + static Pcsx2StandardPaths stdPaths; + return stdPaths; +} +#endif + +wxAppTraits* Pcsx2App::CreateTraits() +{ + return new Pcsx2AppTraits; +} + // -------------------------------------------------------------------------------------- // FramerateManager (implementations) // -------------------------------------------------------------------------------------- @@ -423,7 +480,7 @@ void Pcsx2App::OnEmuKeyDown( wxKeyEvent& evt ) // are multiple variations on the BIOS and BIOS folder checks). wxString BIOS_GetMsg_Required() { - return pxE( ".Popup:BiosDumpRequired", + return pxE( "!Notice:BiosDumpRequired", L"\n\n" L"PCSX2 requires a PS2 BIOS in order to run. For legal reasons, you *must* obtain \n" L"a BIOS from an actual PS2 unit that you own (borrowing doesn't count).\n" @@ -507,7 +564,7 @@ void Pcsx2App::HandleEvent(wxEvtHandler* handler, wxEventFunction func, wxEvent& wxDialogWithHelpers dialog( NULL, _("PCSX2 Unresponsive Thread"), wxVERTICAL ); dialog += dialog.Heading( ex.FormatDisplayMessage() + L"\n\n" + - pxE( ".Popup Error:Thread Deadlock Actions", + pxE( "!Notice Error:Thread Deadlock Actions", L"'Ignore' to continue waiting for the thread to respond.\n" L"'Cancel' to attempt to cancel the thread.\n" L"'Terminate' to quit PCSX2 immediately.\n" @@ -574,11 +631,6 @@ void Pcsx2App::ClearPendingSave() } } -wxAppTraits* Pcsx2App::CreateTraits() -{ - return new Pcsx2AppTraits; -} - // This method generates debug assertions if the MainFrame handle is NULL (typically // indicating that PCSX2 is running in NoGUI mode, or that the main frame has been // closed). In most cases you'll want to use HasMainFrame() to test for thread @@ -622,16 +674,10 @@ void AppApplySettings( const AppConfig* oldconf ) RelocateLogfile(); - if( (oldconf == NULL) || (oldconf->LanguageId != g_Conf->LanguageId) ) + if( (oldconf == NULL) || (oldconf->LanguageCode.CmpNoCase(g_Conf->LanguageCode)) ) { wxDoNotLogInThisScope please; - if( !i18n_SetLanguage( g_Conf->LanguageId ) ) - { - if( !i18n_SetLanguage( wxLANGUAGE_DEFAULT ) ) - { - i18n_SetLanguage( wxLANGUAGE_ENGLISH ); - } - } + i18n_SetLanguage( g_Conf->LanguageId, g_Conf->LanguageCode ); } CorePlugins.SetSettingsFolder( GetSettingsFolder().ToString() ); diff --git a/pcsx2/gui/AppRes.cpp b/pcsx2/gui/AppRes.cpp index 0b98987759..2ecc32f317 100644 --- a/pcsx2/gui/AppRes.cpp +++ b/pcsx2/gui/AppRes.cpp @@ -80,13 +80,13 @@ pxAppResources::~pxAppResources() throw() {} wxMenu& Pcsx2App::GetRecentIsoMenu() { - pxAssert( !!m_RecentIsoList->Menu ); + if (!m_RecentIsoList) m_RecentIsoList = new RecentIsoList(); return *m_RecentIsoList->Menu; } RecentIsoManager& Pcsx2App::GetRecentIsoManager() { - pxAssert( !!m_RecentIsoList->Manager ); + if (!m_RecentIsoList) m_RecentIsoList = new RecentIsoList(); return *m_RecentIsoList->Manager; } diff --git a/pcsx2/gui/ApplyState.h b/pcsx2/gui/ApplyState.h index 0225ee9cf8..6c44c4612e 100644 --- a/pcsx2/gui/ApplyState.h +++ b/pcsx2/gui/ApplyState.h @@ -52,7 +52,7 @@ namespace Exception public: explicit CannotApplySettings( BaseApplicableConfigPanel* thispanel ) { - SetBothMsgs(wxLt("Cannot apply new settings, one of the settings is invalid.")); + SetBothMsgs(pxL("Cannot apply new settings, one of the settings is invalid.")); m_Panel = thispanel; IsVerbose = true; } diff --git a/pcsx2/gui/ConsoleLogger.cpp b/pcsx2/gui/ConsoleLogger.cpp index 58a6133aeb..f7ba14d1e4 100644 --- a/pcsx2/gui/ConsoleLogger.cpp +++ b/pcsx2/gui/ConsoleLogger.cpp @@ -409,22 +409,22 @@ ConsoleLogFrame::ConsoleLogFrame( MainEmuFrame *parent, const wxString& title, A // create Appearance menu and submenus - menuFontSizes.Append( MenuId_FontSize_Small, _("Small"), _("Fits a lot of log in a microcosmically small area."), + menuFontSizes.Append( MenuId_FontSize_Small, _("Small"), _t("Fits a lot of log in a microcosmically small area."), wxITEM_RADIO )->Check( options.FontSize == 7 ); - menuFontSizes.Append( MenuId_FontSize_Normal, _("Normal"),_("It's what I use (the programmer guy)."), + menuFontSizes.Append( MenuId_FontSize_Normal, _("Normal"),_t("It's what I use (the programmer guy)."), wxITEM_RADIO )->Check( options.FontSize == 8 ); - menuFontSizes.Append( MenuId_FontSize_Large, _("Large"), _("Its nice and readable."), + menuFontSizes.Append( MenuId_FontSize_Large, _("Large"), _t("Its nice and readable."), wxITEM_RADIO )->Check( options.FontSize == 10 ); - menuFontSizes.Append( MenuId_FontSize_Huge, _("Huge"), _("In case you have a really high res display."), + menuFontSizes.Append( MenuId_FontSize_Huge, _("Huge"), _t("In case you have a really high res display."), wxITEM_RADIO )->Check( options.FontSize == 12 ); menuFontSizes.AppendSeparator(); - menuFontSizes.Append( MenuId_ColorScheme_Light, _("Light theme"), _("Default soft-tone color scheme."), wxITEM_RADIO ); - menuFontSizes.Append( MenuId_ColorScheme_Dark, _("Dark theme"), _("Classic black color scheme for people who enjoy having text seared into their optic nerves."), wxITEM_RADIO ); + menuFontSizes.Append( MenuId_ColorScheme_Light, _("Light theme"), _t("Default soft-tone color scheme."), wxITEM_RADIO ); + menuFontSizes.Append( MenuId_ColorScheme_Dark, _("Dark theme"), _t("Classic black color scheme for people who enjoy having text seared into their optic nerves."), wxITEM_RADIO ); menuAppear.AppendSeparator(); menuAppear.Append( wxID_ANY, _("Always on Top"), - _("When checked the log window will be visible over other foreground windows."), wxITEM_CHECK ); + _t("When checked the log window will be visible over other foreground windows."), wxITEM_CHECK ); menuLog.Append(wxID_SAVE, _("&Save..."), _("Save log contents to file")); menuLog.Append(wxID_CLEAR, _("C&lear"), _("Clear the log window contents")); diff --git a/pcsx2/gui/Dialogs/ConfigurationDialog.h b/pcsx2/gui/Dialogs/ConfigurationDialog.h index e12f36c637..09e652cdf8 100644 --- a/pcsx2/gui/Dialogs/ConfigurationDialog.h +++ b/pcsx2/gui/Dialogs/ConfigurationDialog.h @@ -89,6 +89,26 @@ namespace Dialogs virtual wxString& GetConfSettingsTabName() const { return g_Conf->SysSettingsTabName; } }; + // -------------------------------------------------------------------------------------- + // LanguageSelectionDialog + // -------------------------------------------------------------------------------------- + class LanguageSelectionDialog : public BaseConfigurationDialog + { + public: + virtual ~LanguageSelectionDialog() throw() {} + LanguageSelectionDialog(wxWindow* parent=NULL); + static wxString GetNameStatic() { return L"LanguageSelector"; } + wxString GetDialogName() const { return GetNameStatic(); } + + protected: + virtual wxString& GetConfSettingsTabName() const + { + pxFailDev("Language selector does not have a listbook or settings tab."); + static wxString fail; + return fail; + } + }; + // -------------------------------------------------------------------------------------- // McdConfigDialog // -------------------------------------------------------------------------------------- diff --git a/pcsx2/gui/Dialogs/ConfirmationDialogs.cpp b/pcsx2/gui/Dialogs/ConfirmationDialogs.cpp index 879a460bdd..cd3926563b 100644 --- a/pcsx2/gui/Dialogs/ConfirmationDialogs.cpp +++ b/pcsx2/gui/Dialogs/ConfirmationDialogs.cpp @@ -65,7 +65,7 @@ static wxString ResultToString( int result, const MsgButtons& buttons ) case wxID_ABORT: return L"abort"; case wxID_RETRY: return L"retry"; - // [TODO] : maybe add in an Ignore All? + // [TODO] : maybe add in an Ignore All? case wxID_IGNORE: return L"ignore"; case wxID_RESET: return L"reset"; @@ -73,7 +73,7 @@ static wxString ResultToString( int result, const MsgButtons& buttons ) } if (result <= wxID_LOWEST) - return buttons.GetCustomLabel(); + return buttons.GetCustomLabelId(); return wxEmptyString; } diff --git a/pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp b/pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp index 2654ff16cf..01c237930e 100644 --- a/pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp +++ b/pcsx2/gui/Dialogs/CreateMemoryCardDialog.cpp @@ -148,7 +148,7 @@ void Dialogs::CreateMemoryCardDialog::CreateControls() GetMsg_McdNtfsCompress() ); - m_check_CompressNTFS->SetToolTip( pxE( ".Tooltip:ChangingNTFS", + m_check_CompressNTFS->SetToolTip( pxEt( "!ContextTip:ChangingNTFS", L"NTFS compression can be changed manually at any time by using file properties from Windows Explorer." ) ); @@ -161,19 +161,19 @@ void Dialogs::CreateMemoryCardDialog::CreateControls() const RadioPanelItem tbl_CardSizes[] = { RadioPanelItem(_("8 MB [most compatible]"), _("This is the standard Sony-provisioned size, and is supported by all games and BIOS versions.")) - . SetToolTip(_("Always use this option if you want the safest and surest memory card behavior.")) + . SetToolTip(_t("Always use this option if you want the safest and surest memory card behavior.")) . SetInt(8), RadioPanelItem(_("16 MB"), _("A typical size for 3rd-party memory cards which should work with most games.")) - . SetToolTip(_("16 and 32 MB cards have roughly the same compatibility factor.")) + . SetToolTip(_t("16 and 32 MB cards have roughly the same compatibility factor.")) . SetInt(16), RadioPanelItem(_("32 MB"), _("A typical size for 3rd-party memory cards which should work with most games.")) - . SetToolTip(_("16 and 32 MB cards have roughly the same compatibility factor.")) + . SetToolTip(_t("16 and 32 MB cards have roughly the same compatibility factor.")) . SetInt(32), RadioPanelItem(_("64 MB"), _("Low compatibility warning: Yes it's very big, but may not work with many games.")) - . SetToolTip(_("Use at your own risk. Erratic memory card behavior is possible (though unlikely).")) + . SetToolTip(_t("Use at your own risk. Erratic memory card behavior is possible (though unlikely).")) . SetInt(64) }; diff --git a/pcsx2/gui/Dialogs/FirstTimeWizard.cpp b/pcsx2/gui/Dialogs/FirstTimeWizard.cpp index 36af9a4743..0aff33070a 100644 --- a/pcsx2/gui/Dialogs/FirstTimeWizard.cpp +++ b/pcsx2/gui/Dialogs/FirstTimeWizard.cpp @@ -45,12 +45,12 @@ bool ApplicableWizardPage::PrepForApply() Panels::SettingsDirPickerPanel::SettingsDirPickerPanel( wxWindow* parent ) : DirPickerPanel( parent, FolderId_Settings, _("Settings"), AddAppName(_("Select a folder for %s settings")) ) { - pxSetToolTip( this, pxE( ".Tooltip:Folders:Settings", + pxSetToolTip( this, pxEt( "!ContextTip:Folders:Settings", L"This is the folder where PCSX2 saves your settings, including settings generated " L"by most plugins (some older plugins may not respect this value)." ) ); - SetStaticDesc( pxE( ".Panel:Folders:Settings", + SetStaticDesc( pxE( "!Panel:Folders:Settings", L"You may optionally specify a location for your PCSX2 settings here. If the location " L"contains existing PCSX2 settings, you will be given the option to import or overwrite them." ) ); @@ -106,7 +106,7 @@ bool FirstTimeWizard::UsermodePage::PrepForApply() // FIXME: There's already a file by the same name.. not sure what we should do here. throw Exception::BadStream( path.ToString() ) .SetDiagMsg(L"Targeted documents folder is already occupied by a file.") - .SetUserMsg(pxE( ".Error:DocsFolderFileConflict", + .SetUserMsg(pxE( "!Notice:DocsFolderFileConflict", L"PCSX2 cannot create a documents folder in the requested location. " L"The path name matches an existing file. Delete the file or change the documents location, " L"and then try again." @@ -120,7 +120,7 @@ bool FirstTimeWizard::UsermodePage::PrepForApply() dialog += 12; dialog += dialog.Heading( path.ToString() ); - if( wxID_CANCEL == pxIssueConfirmation( dialog, MsgButtons().Custom(_("Create")).Cancel(), L"CreateNewFolder" ) ) + if( wxID_CANCEL == pxIssueConfirmation( dialog, MsgButtons().Custom(_("Create"), "create").Cancel(), L"CreateNewFolder" ) ) return false; } path.Mkdir(); @@ -149,7 +149,7 @@ FirstTimeWizard::FirstTimeWizard( wxWindow* parent ) // Temporary tutorial message for the BIOS, needs proof-reading!! m_page_bios += 12; m_page_bios += new pxStaticHeading( &m_page_bios, - pxE( ".Wizard:Bios:Tutorial", + pxE( "!Wizard:Bios:Tutorial", L"PCSX2 requires a *legal* copy of the PS2 BIOS in order to run games.\n" L"You cannot use a copy obtained from a friend or the Internet.\n" L"You must dump the BIOS from your *own* Playstation 2 console." @@ -175,6 +175,8 @@ FirstTimeWizard::FirstTimeWizard( wxWindow* parent ) Connect( wxEVT_WIZARD_PAGE_CHANGED, wxWizardEventHandler (FirstTimeWizard::OnPageChanged) ); Connect( wxEVT_WIZARD_PAGE_CHANGING, wxWizardEventHandler (FirstTimeWizard::OnPageChanging) ); Connect( wxEVT_COMMAND_LISTBOX_DOUBLECLICKED, wxCommandEventHandler (FirstTimeWizard::OnDoubleClicked) ); + + Connect( pxID_RestartWizard, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( FirstTimeWizard::OnRestartWizard ) ); } FirstTimeWizard::~FirstTimeWizard() throw() @@ -182,6 +184,12 @@ FirstTimeWizard::~FirstTimeWizard() throw() } +void FirstTimeWizard::OnRestartWizard( wxCommandEvent& evt ) +{ + EndModal( pxID_RestartWizard ); + evt.Skip(); +} + static void _OpenConsole() { g_Conf->ProgLogBox.Visible = true; diff --git a/pcsx2/gui/Dialogs/GameDatabaseDialog.cpp b/pcsx2/gui/Dialogs/GameDatabaseDialog.cpp index 261c750630..1b8740c2a0 100644 --- a/pcsx2/gui/Dialogs/GameDatabaseDialog.cpp +++ b/pcsx2/gui/Dialogs/GameDatabaseDialog.cpp @@ -17,10 +17,13 @@ #include "ConfigurationDialog.h" #include "Panels/ConfigurationPanels.h" +using namespace Panels; +using namespace pxSizerFlags; + Dialogs::GameDatabaseDialog::GameDatabaseDialog(wxWindow* parent) - : BaseConfigurationDialog( parent, AddAppName(_("Game Database - %s")), 580 ) + : BaseConfigurationDialog( parent, AddAppName(_("Game database - %s")), 580 ) { ScopedBusyCursor busy( Cursor_ReallyBusy ); - *this += new Panels::GameDatabasePanel(this); + *this += new GameDatabasePanel(this) | StdExpand(); AddOkCancel(); } diff --git a/pcsx2/gui/Dialogs/ImportSettingsDialog.cpp b/pcsx2/gui/Dialogs/ImportSettingsDialog.cpp index bda14a45ad..4f5c5ff0a2 100644 --- a/pcsx2/gui/Dialogs/ImportSettingsDialog.cpp +++ b/pcsx2/gui/Dialogs/ImportSettingsDialog.cpp @@ -25,8 +25,10 @@ Dialogs::ImportSettingsDialog::ImportSettingsDialog( wxWindow* parent ) { SetMinWidth( 440 ); - pxStaticText& heading( Text( wxsFormat( - pxE( ".Popup:ImportExistingSettings", + pxStaticText& heading( Text( pxsFmt( + + /// (%s is the app name, normally PCSX2 -- omitting one or both %s is allowed) + pxE( "!Notice:ImportExistingSettings", L"Existing %s settings have been found in the configured settings folder. " L"Would you like to import these settings or overwrite them with %s default values?" L"\n\n(or press Cancel to select a different settings folder)" diff --git a/pcsx2/gui/Dialogs/McdConfigDialog.cpp b/pcsx2/gui/Dialogs/McdConfigDialog.cpp index 3d584b519c..46882f0699 100644 --- a/pcsx2/gui/Dialogs/McdConfigDialog.cpp +++ b/pcsx2/gui/Dialogs/McdConfigDialog.cpp @@ -27,7 +27,7 @@ using namespace pxSizerFlags; wxString GetMsg_McdNtfsCompress() { - return pxE( ".Panel:Mcd:NtfsCompress", + return pxE( "!Panel:Mcd:NtfsCompress", L"NTFS compression is built-in, fast, and completely reliable; and typically compresses memory cards " L"very well (this option is highly recommended)." ); @@ -38,12 +38,14 @@ Panels::McdConfigPanel_Toggles::McdConfigPanel_Toggles(wxWindow *parent) { m_check_Ejection = new pxCheckBox( this, _("Auto-eject memory cards when loading savestates"), - pxE( ".Panel:Mcd:EnableEjection", + pxE( "!Panel:Mcd:EnableEjection", L"Avoids memory card corruption by forcing games to re-index card contents after " L"loading from savestates. May not be compatible with all games (Guitar Hero)." ) ); + m_check_SavestateBackup = new pxCheckBox( this, pxsFmt(_("Backup existing Savestate when creating a new one")) ); + for( uint i=0; i<2; ++i ) { m_check_Multitap[i] = new pxCheckBox( this, pxsFmt(_("Enable Multitap on Port %u"), i+1) ); @@ -60,23 +62,29 @@ Panels::McdConfigPanel_Toggles::McdConfigPanel_Toggles(wxWindow *parent) *this += 4; + *this += m_check_SavestateBackup; + + *this += 4; + *this += m_check_Ejection; } void Panels::McdConfigPanel_Toggles::Apply() { - g_Conf->EmuOptions.MultitapPort0_Enabled = m_check_Multitap[0]->GetValue(); - g_Conf->EmuOptions.MultitapPort1_Enabled = m_check_Multitap[1]->GetValue(); + g_Conf->EmuOptions.MultitapPort0_Enabled = m_check_Multitap[0]->GetValue(); + g_Conf->EmuOptions.MultitapPort1_Enabled = m_check_Multitap[1]->GetValue(); - g_Conf->EmuOptions.McdEnableEjection = m_check_Ejection->GetValue(); + g_Conf->EmuOptions.BackupSavestate = m_check_SavestateBackup->GetValue(); + g_Conf->EmuOptions.McdEnableEjection = m_check_Ejection->GetValue(); } void Panels::McdConfigPanel_Toggles::AppStatusEvent_OnSettingsApplied() { - m_check_Multitap[0] ->SetValue( g_Conf->EmuOptions.MultitapPort0_Enabled ); - m_check_Multitap[1] ->SetValue( g_Conf->EmuOptions.MultitapPort1_Enabled ); + m_check_Multitap[0] ->SetValue( g_Conf->EmuOptions.MultitapPort0_Enabled ); + m_check_Multitap[1] ->SetValue( g_Conf->EmuOptions.MultitapPort1_Enabled ); - m_check_Ejection ->SetValue( g_Conf->EmuOptions.McdEnableEjection ); + m_check_SavestateBackup ->SetValue( g_Conf->EmuOptions.BackupSavestate ); + m_check_Ejection ->SetValue( g_Conf->EmuOptions.McdEnableEjection ); } @@ -91,9 +99,6 @@ Dialogs::McdConfigDialog::McdConfigDialog( wxWindow* parent ) // [TODO] : Plan here is to add an advanced tab which gives the user the ability // to configure the names of each memory card slot. - //AddPage ( wxLt("Settings"), cfgid.MemoryCard ); - //AddPage ( wxLt("Slots 1/2"), cfgid.MemoryCard ); - *this += Heading(_("Drag items over other items in the list to swap or copy memory cards.")) | StdExpand(); *this += StdPadding; diff --git a/pcsx2/gui/Dialogs/ModalPopups.h b/pcsx2/gui/Dialogs/ModalPopups.h index 73a97fc6a0..025e9abdce 100644 --- a/pcsx2/gui/Dialogs/ModalPopups.h +++ b/pcsx2/gui/Dialogs/ModalPopups.h @@ -21,8 +21,6 @@ #include -static const wxWindowID pxID_CUSTOM = wxID_LOWEST - 1; - class FirstTimeWizard : public wxWizard { typedef wxWizard _parent; @@ -71,6 +69,8 @@ protected: virtual void OnPageChanging( wxWizardEvent& evt ); virtual void OnPageChanged( wxWizardEvent& evt ); virtual void OnDoubleClicked( wxCommandEvent& evt ); + + void OnRestartWizard( wxCommandEvent& evt ); }; diff --git a/pcsx2/gui/Dialogs/StuckThreadDialog.cpp b/pcsx2/gui/Dialogs/StuckThreadDialog.cpp index 8244d5b359..e427fa58d7 100644 --- a/pcsx2/gui/Dialogs/StuckThreadDialog.cpp +++ b/pcsx2/gui/Dialogs/StuckThreadDialog.cpp @@ -30,7 +30,7 @@ Dialogs::StuckThreadDialog::StuckThreadDialog( wxWindow* parent, StuckThreadActi stuck_thread.AddListener( this ); *this += Heading( wxsFormat( - pxE( ".Panel:StuckThread:Heading", + pxE( "!Panel:StuckThread:Heading", L"The thread '%s' is not responding. It could be deadlocked, or it might " L"just be running *really* slowly." ), @@ -43,7 +43,7 @@ Dialogs::StuckThreadDialog::StuckThreadDialog( wxWindow* parent, StuckThreadActi L"\nOr press [Ignore] to suppress further assertions." ); - *this += new ModalButtonPanel( this, MsgButtons().Cancel().Custom(L"Wait") ) | StdCenter(); + *this += new ModalButtonPanel( this, MsgButtons().Cancel().Custom(L"Wait", "wait") ) | StdCenter(); if( wxWindow* idyes = FindWindowById( wxID_YES ) ) idyes->SetFocus(); diff --git a/pcsx2/gui/Dialogs/SysConfigDialog.cpp b/pcsx2/gui/Dialogs/SysConfigDialog.cpp index 287fb89b5d..5cf4dd5a65 100644 --- a/pcsx2/gui/Dialogs/SysConfigDialog.cpp +++ b/pcsx2/gui/Dialogs/SysConfigDialog.cpp @@ -23,6 +23,7 @@ #include "Panels/ConfigurationPanels.h" using namespace Panels; +using namespace pxSizerFlags; static void CheckHacksOverrides() { @@ -33,7 +34,7 @@ static void CheckHacksOverrides() wxDialogWithHelpers dialog( wxFindWindowByName( L"Dialog:" + Dialogs::SysConfigDialog::GetNameStatic() ), _("Config Overrides Warning") ); - dialog += dialog.Text( pxE(".Panel:HasHacksOverrides", + dialog += dialog.Text( pxE("!Panel:HasHacksOverrides", L"Warning! You are running PCSX2 with command line options that override your configured settings. " L"These command line options will not be reflected in the Settings dialog, and will be disabled " L"if you apply any changes here." @@ -53,7 +54,7 @@ static void CheckPluginsOverrides() wxDialogWithHelpers dialog( NULL, _("Components Overrides Warning") ); - dialog += dialog.Text( pxE(".Panel:HasPluginsOverrides", + dialog += dialog.Text( pxE("!Panel:HasPluginsOverrides", L"Warning! You are running PCSX2 with command line options that override your configured plugin and/or folder settings. " L"These command line options will not be reflected in the settings dialog, and will be disabled " L"when you apply settings changes here." @@ -72,13 +73,12 @@ Dialogs::SysConfigDialog::SysConfigDialog(wxWindow* parent) CreateListbook( wxGetApp().GetImgList_Config() ); const AppImageIds::ConfigIds& cfgid( wxGetApp().GetImgId().Config ); - AddPage ( wxLt("EE/IOP"), cfgid.Cpu ); - AddPage ( wxLt("VUs"), cfgid.Cpu ); - AddPage ( wxLt("GS"), cfgid.Cpu ); - AddPage ( wxLt("GS Window"), cfgid.Video ); - AddPage ( wxLt("Speedhacks"), cfgid.Speedhacks ); - AddPage ( wxLt("Game Fixes"), cfgid.Gamefixes ); - //AddPage ( wxLt("Game Database"),cfgid.Plugins ); + AddPage ( pxL("EE/IOP"), cfgid.Cpu ); + AddPage ( pxL("VUs"), cfgid.Cpu ); + AddPage ( pxL("GS"), cfgid.Cpu ); + AddPage ( pxL("GS Window"), cfgid.Video ); + AddPage ( pxL("Speedhacks"), cfgid.Speedhacks ); + AddPage ( pxL("Game Fixes"), cfgid.Gamefixes ); AddListbook(); AddOkCancel(); @@ -95,9 +95,9 @@ Dialogs::ComponentsConfigDialog::ComponentsConfigDialog(wxWindow* parent) CreateListbook( wxGetApp().GetImgList_Config() ); const AppImageIds::ConfigIds& cfgid( wxGetApp().GetImgId().Config ); - AddPage ( wxLt("Plugins"), cfgid.Plugins ); - AddPage ( wxLt("BIOS"), cfgid.Cpu ); - AddPage ( wxLt("Folders"), cfgid.Paths ); + AddPage ( pxL("Plugins"), cfgid.Plugins ); + AddPage ( pxL("BIOS"), cfgid.Cpu ); + AddPage ( pxL("Folders"), cfgid.Paths ); AddListbook(); AddOkCancel(); @@ -105,3 +105,13 @@ Dialogs::ComponentsConfigDialog::ComponentsConfigDialog(wxWindow* parent) if( wxGetApp().Overrides.HasPluginsOverride() ) wxGetApp().PostMethod( CheckPluginsOverrides ); } + +Dialogs::LanguageSelectionDialog::LanguageSelectionDialog(wxWindow *parent) + : BaseConfigurationDialog( parent, AddAppName(_("Language Selector - %s")), 400 ) +{ + ScopedBusyCursor busy( Cursor_ReallyBusy ); + + *this += new Panels::LanguageSelectionPanel( this ) | pxCenter; + + wxDialogWithHelpers::AddOkCancel( NULL, false ); +} \ No newline at end of file diff --git a/pcsx2/gui/ExecutorThread.cpp b/pcsx2/gui/ExecutorThread.cpp index e822cb7c7c..662f6691d1 100644 --- a/pcsx2/gui/ExecutorThread.cpp +++ b/pcsx2/gui/ExecutorThread.cpp @@ -23,13 +23,13 @@ using namespace pxSizerFlags; // -------------------------------------------------------------------------------------- bool ConsoleLogSource_Event::Write( const pxEvtHandler* evtHandler, const SysExecEvent* evt, const wxChar* msg ) { - return _parent::Write( wxsFormat(L"(%s%s) ", evtHandler->GetEventHandlerName().c_str(), evt->GetEventName().c_str()) + msg ); + return _parent::Write( pxsFmt(L"(%s:%s) ", evtHandler->GetEventHandlerName().c_str(), evt->GetEventName().c_str()) + msg ); } bool ConsoleLogSource_Event::Warn( const pxEvtHandler* evtHandler, const SysExecEvent* evt, const wxChar* msg ) { - return _parent::Write( wxsFormat(L"(%s%s) ", evtHandler->GetEventHandlerName().c_str(), evt->GetEventName().c_str()) + msg ); + return _parent::Write( pxsFmt(L"(%s:%s) ", evtHandler->GetEventHandlerName().c_str(), evt->GetEventName().c_str()) + msg ); } bool ConsoleLogSource_Event::Error( const pxEvtHandler* evtHandler, const SysExecEvent* evt, const wxChar* msg ) { - return _parent::Write( wxsFormat(L"(%s%s) ", evtHandler->GetEventHandlerName().c_str(), evt->GetEventName().c_str()) + msg ); + return _parent::Write( pxsFmt(L"(%s:%s) ", evtHandler->GetEventHandlerName().c_str(), evt->GetEventName().c_str()) + msg ); } ConsoleLogSource_Event::ConsoleLogSource_Event() @@ -37,7 +37,7 @@ ConsoleLogSource_Event::ConsoleLogSource_Event() static const TraceLogDescriptor myDesc = { L"SysEvents", L"SysVM Control Events", - wxLt("Logs events as they are passed to the PS2 virtual machine."), + pxLt("Logs events as they are passed to the PS2 virtual machine."), }; m_Descriptor = &myDesc; diff --git a/pcsx2/gui/FrameForGS.cpp b/pcsx2/gui/FrameForGS.cpp index 084c593c4d..1125c735a0 100644 --- a/pcsx2/gui/FrameForGS.cpp +++ b/pcsx2/gui/FrameForGS.cpp @@ -386,8 +386,7 @@ void GSFrame::OnUpdateTitle( wxTimerEvent& evt ) double fps = wxGetApp().FpsManager.GetFramerate(); char gsDest[128]; - GSgetTitleInfo( gsDest ); - + GSgetTitleInfo2( gsDest, sizeof(gsDest) ); const wxChar* limiterStr = L"None"; @@ -401,16 +400,16 @@ void GSFrame::OnUpdateTitle( wxTimerEvent& evt ) } } - wxString cpuUsage; + FastFormatUnicode cpuUsage; if( m_CpuUsage.IsImplemented() ) { m_CpuUsage.UpdateStats(); - cpuUsage = wxsFormat( L" | EE: %3d%% | GS: %3d%% | UI: %3d%%", m_CpuUsage.GetEEcorePct(), m_CpuUsage.GetGsPct(), m_CpuUsage.GetGuiPct() ); + cpuUsage.Write( L" | EE: %3d%% | GS: %3d%% | UI: %3d%%", m_CpuUsage.GetEEcorePct(), m_CpuUsage.GetGsPct(), m_CpuUsage.GetGuiPct() ); } const u64& smode2 = *(u64*)PS2GS_BASE(GS_SMODE2); - SetTitle( wxsFormat( L"%s | %s (%s) | Limiter: %s | fps: %6.02f%s", + SetTitle( pxsFmt( L"%s | %s (%s) | Limiter: %s | fps: %6.02f%s", fromUTF8(gsDest).c_str(), (smode2 & 1) ? L"Interlaced" : L"Progressive", (smode2 & 2) ? L"frame" : L"field", diff --git a/pcsx2/gui/GlobalCommands.cpp b/pcsx2/gui/GlobalCommands.cpp index 9570c5087c..89e8f41fe7 100644 --- a/pcsx2/gui/GlobalCommands.cpp +++ b/pcsx2/gui/GlobalCommands.cpp @@ -240,26 +240,26 @@ static const GlobalCommandDescriptor CommandDeclarations[] = { { "States_FreezeCurrentSlot", States_FreezeCurrentSlot, - wxLt( "Save state" ), - wxLt( "Saves the virtual machine state to the current slot." ), + pxL( "Save state" ), + pxL( "Saves the virtual machine state to the current slot." ), }, { "States_DefrostCurrentSlot", States_DefrostCurrentSlot, - wxLt( "Load state" ), - wxLt( "Loads a virtual machine state from the current slot." ), + pxL( "Load state" ), + pxL( "Loads a virtual machine state from the current slot." ), }, { "States_CycleSlotForward", States_CycleSlotForward, - wxLt( "Cycle to next slot" ), - wxLt( "Cycles the current save slot in +1 fashion!" ), + pxL( "Cycle to next slot" ), + pxL( "Cycles the current save slot in +1 fashion!" ), }, { "States_CycleSlotBackward", States_CycleSlotBackward, - wxLt( "Cycle to prev slot" ), - wxLt( "Cycles the current save slot in -1 fashion!" ), + pxL( "Cycle to prev slot" ), + pxL( "Cycles the current save slot in -1 fashion!" ), }, { "Frameskip_Toggle", diff --git a/pcsx2/gui/IsoDropTarget.cpp b/pcsx2/gui/IsoDropTarget.cpp index dcc740cdc3..9828c5ab46 100644 --- a/pcsx2/gui/IsoDropTarget.cpp +++ b/pcsx2/gui/IsoDropTarget.cpp @@ -25,7 +25,7 @@ wxString GetMsg_ConfirmSysReset() { - return pxE( ".Popup:ConfirmSysReset", + return pxE( "!Notice:ConfirmSysReset", L"This action will reset the existing PS2 virtual machine state; " L"all current progress will be lost. Are you sure?" ); diff --git a/pcsx2/gui/MainFrame.cpp b/pcsx2/gui/MainFrame.cpp index 6b6d1965f3..bc52eca23b 100644 --- a/pcsx2/gui/MainFrame.cpp +++ b/pcsx2/gui/MainFrame.cpp @@ -61,6 +61,29 @@ void MainEmuFrame::UpdateIsoSrcSelection() // exists ? Path::GetFilename(g_Conf->CurrentIso).c_str() : _("Empty") ) ); } +bool MainEmuFrame::Destroy() +{ + // Sigh: wxWidgets doesn't issue Destroy() calls for children windows when the parent + // is destroyed (it just deletes them, quite suddenly). So let's do it for them, since + // our children have configuration stuff they like to do when they're closing. + + for ( + wxWindowList::const_iterator + i = wxTopLevelWindows.begin(), + end = wxTopLevelWindows.end(); + i != end; ++i + ) + { + wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); + if (win == this) continue; + if (win->GetParent() != this) continue; + + win->Destroy(); + } + + return _parent::Destroy(); +} + // ------------------------------------------------------------------------ // MainFrame OnEvent Handlers // ------------------------------------------------------------------------ @@ -157,6 +180,7 @@ void MainEmuFrame::ConnectMenus() ConnectMenu( MenuId_Config_AppSettings, Menu_WindowSettings_Click ); ConnectMenu( MenuId_Config_GameDatabase,Menu_GameDatabase_Click ); ConnectMenu( MenuId_Config_BIOS, Menu_SelectPluginsBios_Click ); + ConnectMenu( MenuId_Config_Language, Menu_Language_Click ); ConnectMenu( MenuId_Config_ResetAll, Menu_ResetAllSettings_Click ); ConnectMenu( MenuId_Config_Multitap0Toggle, Menu_MultitapToggle_Click ); @@ -290,8 +314,8 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title) , m_LoadStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Load01 ) ) , m_SaveStatesSubmenu( *MakeStatesSubMenu( MenuId_State_Save01 ) ) - , m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, MenuId_Console, L"Show Console", wxEmptyString, wxITEM_CHECK ) ) - , m_MenuItem_Console_Stdio( *new wxMenuItem( &m_menuMisc, MenuId_Console_Stdio, L"Console to Stdio", wxEmptyString, wxITEM_CHECK ) ) + , m_MenuItem_Console( *new wxMenuItem( &m_menuMisc, MenuId_Console, _("Show Console"), wxEmptyString, wxITEM_CHECK ) ) + , m_MenuItem_Console_Stdio( *new wxMenuItem( &m_menuMisc, MenuId_Console_Stdio, _("Console to Stdio"), wxEmptyString, wxITEM_CHECK ) ) { m_RestartEmuOnDelete = false; @@ -423,12 +447,17 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title) m_menuConfig.Append(MenuId_Config_SysSettings, _("Emulation &Settings") ); m_menuConfig.Append(MenuId_Config_McdSettings, _("&Memory cards") ); m_menuConfig.Append(MenuId_Config_BIOS, _("&Plugin/BIOS Selector") ); - m_menuConfig.Append(MenuId_Config_GameDatabase, _("Game Database Editor") ); + if (IsDebugBuild) + { + m_menuConfig.Append(MenuId_Config_GameDatabase, _("Game Database Editor") ); + m_menuConfig.Append(MenuId_Config_Language, _("Language...") ); + } + m_menuConfig.AppendSeparator(); m_menuConfig.Append(MenuId_Config_GS, _("&Video (GS)"), m_PluginMenuPacks[PluginId_GS]); m_menuConfig.Append(MenuId_Config_SPU2, _("&Audio (SPU2)"), m_PluginMenuPacks[PluginId_SPU2]); - m_menuConfig.Append(MenuId_Config_PAD, _("&Controllers (PAD)"), m_PluginMenuPacks[PluginId_PAD]); + m_menuConfig.Append(MenuId_Config_PAD, _("&Controllers (PAD)"),m_PluginMenuPacks[PluginId_PAD]); m_menuConfig.Append(MenuId_Config_DEV9, _("Dev9"), m_PluginMenuPacks[PluginId_DEV9]); m_menuConfig.Append(MenuId_Config_USB, _("USB"), m_PluginMenuPacks[PluginId_USB]); m_menuConfig.Append(MenuId_Config_FireWire, _("Firewire"), m_PluginMenuPacks[PluginId_FW]); @@ -458,7 +487,7 @@ MainEmuFrame::MainEmuFrame(wxWindow* parent, const wxString& title) //m_menuMisc.Append(41, "Patch Browser...", wxEmptyString, wxITEM_NORMAL); //m_menuMisc.Append(42, "Patch Finder...", wxEmptyString, wxITEM_NORMAL); - m_menuMisc.Append(MenuId_CDVD_Info, _T("Print CDVD Info"), wxEmptyString, wxITEM_CHECK); + m_menuMisc.Append(MenuId_CDVD_Info, _("Print CDVD Info"), wxEmptyString, wxITEM_CHECK); m_menuMisc.AppendSeparator(); //Todo: diff --git a/pcsx2/gui/MainFrame.h b/pcsx2/gui/MainFrame.h index fda813e5df..323eadc02d 100644 --- a/pcsx2/gui/MainFrame.h +++ b/pcsx2/gui/MainFrame.h @@ -145,6 +145,8 @@ public: void UpdateIsoSrcSelection(); void RemoveCdvdMenu(); void EnableMenuItem( int id, bool enable ); + + bool Destroy(); protected: void DoGiveHelp(const wxString& text, bool show); @@ -166,6 +168,7 @@ protected: void Menu_WindowSettings_Click(wxCommandEvent &event); void Menu_GSSettings_Click(wxCommandEvent &event); void Menu_SelectPluginsBios_Click(wxCommandEvent &event); + void Menu_Language_Click(wxCommandEvent &event); void Menu_ResetAllSettings_Click(wxCommandEvent &event); void Menu_IsoBrowse_Click(wxCommandEvent &event); diff --git a/pcsx2/gui/MainMenuClicks.cpp b/pcsx2/gui/MainMenuClicks.cpp index b4dfbb3ced..eb398ce339 100644 --- a/pcsx2/gui/MainMenuClicks.cpp +++ b/pcsx2/gui/MainMenuClicks.cpp @@ -50,7 +50,7 @@ void MainEmuFrame::Menu_McdSettings_Click(wxCommandEvent &event) void MainEmuFrame::Menu_GameDatabase_Click(wxCommandEvent &event) { - AppOpenDialog( this ); + AppOpenDialog( this ); } void MainEmuFrame::Menu_WindowSettings_Click(wxCommandEvent &event) @@ -72,6 +72,11 @@ void MainEmuFrame::Menu_SelectPluginsBios_Click(wxCommandEvent &event) AppOpenDialog( this ); } +void MainEmuFrame::Menu_Language_Click(wxCommandEvent &event) +{ + //AppOpenDialog( this ); + LanguageSelectionDialog(this).ShowModal(); +} static void WipeSettings() { @@ -104,7 +109,7 @@ void MainEmuFrame::Menu_ResetAllSettings_Click(wxCommandEvent &event) { ScopedCoreThreadPopup suspender; if( !Msgbox::OkCancel( pxsFmt( - pxE( ".Popup:DeleteSettings", + pxE( "!Notice:DeleteSettings", L"This command clears %s settings and allows you to re-run the First-Time Wizard. You will need to " L"manually restart %s after this operation.\n\n" L"WARNING!! Click OK to delete *ALL* settings for %s and force-close the app, losing any current emulation progress. Are you absolutely sure?" @@ -146,7 +151,7 @@ wxWindowID SwapOrReset_Iso( wxWindow* owner, IScopedCoreThread& core_control, co dialog += dialog.GetCharHeight(); dialog += dialog.Heading(_("Do you want to swap discs or boot the new image (via system reset)?")); - result = pxIssueConfirmation( dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc")), L"DragDrop.BootSwapIso" ); + result = pxIssueConfirmation( dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap"), L"DragDrop.BootSwapIso" ); if( result == wxID_CANCEL ) { core_control.AllowResume(); @@ -189,7 +194,7 @@ wxWindowID SwapOrReset_CdvdSrc( wxWindow* owner, CDVD_SourceType newsrc ) _("Do you want to swap discs or boot the new image (system reset)?") ); - result = pxIssueConfirmation( dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc")), L"DragDrop.BootSwapIso" ); + result = pxIssueConfirmation( dialog, MsgButtons().Reset().Cancel().Custom(_("Swap Disc"), "swap"), L"DragDrop.BootSwapIso" ); if( result == wxID_CANCEL ) { diff --git a/pcsx2/gui/MemoryCardFile.cpp b/pcsx2/gui/MemoryCardFile.cpp index e82734de6b..bad33ef61a 100644 --- a/pcsx2/gui/MemoryCardFile.cpp +++ b/pcsx2/gui/MemoryCardFile.cpp @@ -74,7 +74,7 @@ protected: wxString GetDisabledMessage( uint slot ) const { - return pxE( ".Popup:Mcd:HasBeenDisabled", wxsFormat( + return pxE( "!Notice:Mcd:HasBeenDisabled", wxsFormat( L"The memory card in slot %d has been automatically disabled. You can correct the problem\n" L"and re-enable the memory card at any time using Config:Memory cards from the main menu.", slot diff --git a/pcsx2/gui/Panels/BiosSelectorPanel.cpp b/pcsx2/gui/Panels/BiosSelectorPanel.cpp index ff41ed6d75..fb11e4b4da 100644 --- a/pcsx2/gui/Panels/BiosSelectorPanel.cpp +++ b/pcsx2/gui/Panels/BiosSelectorPanel.cpp @@ -123,7 +123,7 @@ void Panels::BiosSelectorPanel::Apply() { throw Exception::CannotApplySettings(this) .SetDiagMsg(L"User did not specify a valid BIOS selection.") - .SetUserMsg( pxE( ".Error:BIOS:InvalidSelection", + .SetUserMsg( pxE( "!Notice:BIOS:InvalidSelection", L"Please select a valid BIOS. If you are unable to make a valid selection " L"then press cancel to close the Configuration panel." ) ); diff --git a/pcsx2/gui/Panels/ConfigurationPanels.h b/pcsx2/gui/Panels/ConfigurationPanels.h index 64e73ea678..8bd9d28b56 100644 --- a/pcsx2/gui/Panels/ConfigurationPanels.h +++ b/pcsx2/gui/Panels/ConfigurationPanels.h @@ -109,6 +109,9 @@ namespace Panels void Apply(); void AppStatusEvent_OnSettingsApplied(); + + protected: + void OnApplyLanguage_Clicked( wxCommandEvent& evt ); }; // -------------------------------------------------------------------------------------- diff --git a/pcsx2/gui/Panels/DirPickerPanel.cpp b/pcsx2/gui/Panels/DirPickerPanel.cpp index 62e53af084..6da0a57dc1 100644 --- a/pcsx2/gui/Panels/DirPickerPanel.cpp +++ b/pcsx2/gui/Panels/DirPickerPanel.cpp @@ -60,12 +60,12 @@ void Panels::DirPickerPanel::Explore_Click( wxCommandEvent &evt ) createPathDlg += createPathDlg.Text( path ) | StdCenter(); - createPathDlg += createPathDlg.Heading( pxE( ".Error:DirPicker:CreatePath", + createPathDlg += createPathDlg.Heading( pxE( "!Notice:DirPicker:CreatePath", L"The specified path/directory does not exist. Would you like to create it?" ) ); wxWindowID result = pxIssueConfirmation( createPathDlg, - MsgButtons().Custom(_("Create")).Cancel(), + MsgButtons().Custom(_("Create"), "create").Cancel(), L"DirPicker:CreateOnExplore" ); @@ -115,7 +115,7 @@ void Panels::DirPickerPanel::Init( FoldersEnum_t folderid, const wxString& dialo { m_checkCtrl = new pxCheckBox( this, _("Use default setting") ); - pxSetToolTip( m_checkCtrl, pxE( ".Tooltip:DirPicker:UseDefault", + pxSetToolTip( m_checkCtrl, pxEt( "!ContextTip:DirPicker:UseDefault", L"When checked this folder will automatically reflect the default associated with PCSX2's current usermode setting. " ) ); @@ -225,7 +225,7 @@ void Panels::DirPickerPanel::Apply() dialog += 12; dialog += dialog.Heading( path ); - if( wxID_CANCEL == pxIssueConfirmation( dialog, MsgButtons().Custom(_("Create")).Cancel(), L"CreateNewFolder" ) ) + if( wxID_CANCEL == pxIssueConfirmation( dialog, MsgButtons().Custom(_("Create"), "create").Cancel(), L"CreateNewFolder" ) ) throw Exception::CannotApplySettings( this ); } diff --git a/pcsx2/gui/Panels/GSWindowPanel.cpp b/pcsx2/gui/Panels/GSWindowPanel.cpp index 48205ef04b..4f0080b7b5 100644 --- a/pcsx2/gui/Panels/GSWindowPanel.cpp +++ b/pcsx2/gui/Panels/GSWindowPanel.cpp @@ -48,28 +48,28 @@ Panels::GSWindowSettingsPanel::GSWindowSettingsPanel( wxWindow* parent ) m_check_VsyncEnable = new pxCheckBox( this, _("Wait for vsync on refresh") ); m_check_ExclusiveFS = new pxCheckBox( this, _("Use exclusive fullscreen mode (if available)") ); - m_check_VsyncEnable->SetToolTip( pxE( ".Tooltip:Window:Vsync", + m_check_VsyncEnable->SetToolTip( pxEt( "!ContextTip:Window:Vsync", L"Vsync eliminates screen tearing but typically has a big performance hit. " L"It usually only applies to fullscreen mode, and may not work with all GS plugins." ) ); - m_check_HideMouse->SetToolTip( pxE( ".Tooltip:Window:HideMouse", + m_check_HideMouse->SetToolTip( pxEt( "!ContextTip:Window:HideMouse", L"Check this to force the mouse cursor invisible inside the GS window; useful if using " L"the mouse as a primary control device for gaming. By default the mouse auto-hides after " L"2 seconds of inactivity." ) ); - m_check_Fullscreen->SetToolTip( pxE( ".Tooltip:Window:Fullscreen", + m_check_Fullscreen->SetToolTip( pxEt( "!ContextTip:Window:Fullscreen", L"Enables automatic mode switch to fullscreen when starting or resuming emulation. " L"You can still toggle fullscreen display at any time using alt-enter." ) ); - m_check_ExclusiveFS->SetToolTip( pxE( ".Tooltip:Window:FullscreenExclusive", + m_check_ExclusiveFS->SetToolTip( pxEt( "!ContextTip:Window:FullscreenExclusive", L"Fullscreen Exclusive Mode may look better on older CRTs and might be a little faster on older video cards, " L"but typically can lead to memory leaks or random crashes when entering/leaving fullscreen mode." ) ); - m_check_CloseGS->SetToolTip( pxE( ".Tooltip:Window:HideGS", + m_check_CloseGS->SetToolTip( pxEt( "!ContextTip:Window:HideGS", L"Completely closes the often large and bulky GS window when pressing " L"ESC or suspending the emulator." ) ); diff --git a/pcsx2/gui/Panels/GameDatabasePanel.cpp b/pcsx2/gui/Panels/GameDatabasePanel.cpp index 52db0630b5..652b761b56 100644 --- a/pcsx2/gui/Panels/GameDatabasePanel.cpp +++ b/pcsx2/gui/Panels/GameDatabasePanel.cpp @@ -18,11 +18,301 @@ #include "AppGameDatabase.h" #include "ConfigurationPanels.h" +#include + extern wxString DiscSerial; + using namespace pxSizerFlags; -#define blankLine() { \ - sizer1+=5; sizer1+=5; sizer1+=Text(L""); sizer1+=5; sizer1+=5; \ + +enum GameDataColumnId +{ + GdbCol_Serial = 0, + GdbCol_Title, + GdbCol_Region, + GdbCol_Compat, + GdbCol_Patches, + + GdbCol_Count +}; + +struct ListViewColumnInfo +{ + const wxChar* name; + int width; + wxListColumnFormat align; +}; + +// -------------------------------------------------------------------------------------- +// GameDatabaseListView +// -------------------------------------------------------------------------------------- +class GameDatabaseListView : public wxListView +{ + typedef wxListView _parent; + +protected: + wxArrayString m_GamesInView; + +public: + virtual ~GameDatabaseListView() throw() { } + GameDatabaseListView( wxWindow* parent ); + + void CreateColumns(); + GameDatabaseListView& AddGame( const wxString& serial ); + GameDatabaseListView& RemoveGame( const wxString& serial ); + GameDatabaseListView& ClearAllGames(); + GameDatabaseListView& SortBy( GameDataColumnId column ); + +protected: + // Overrides for wxLC_VIRTUAL + virtual wxString OnGetItemText(long item, long column) const; + virtual int OnGetItemImage(long item) const; + virtual int OnGetItemColumnImage(long item, long column) const; + virtual wxListItemAttr* OnGetItemAttr(long item) const; + + const ListViewColumnInfo& GetDefaultColumnInfo( uint idx ) const; +}; + +// -------------------------------------------------------------------------------------- +// GameDatabaseListView (implementations) +// -------------------------------------------------------------------------------------- +GameDatabaseListView::GameDatabaseListView( wxWindow* parent ) + : _parent( parent ) +{ + CreateColumns(); +} + +const ListViewColumnInfo& GameDatabaseListView::GetDefaultColumnInfo( uint idx ) const +{ + static const ListViewColumnInfo columns[] = + { + { L"Serial", 96, wxLIST_FORMAT_LEFT }, + { L"Title", 132, wxLIST_FORMAT_LEFT }, + { L"Region", 72, wxLIST_FORMAT_CENTER }, + { L"Compat", 48, wxLIST_FORMAT_CENTER }, + { L"Patches", 48, wxLIST_FORMAT_CENTER }, + }; + + pxAssumeDev( idx < ArraySize(columns), "ListView column index is out of bounds." ); + return columns[idx]; +} + +void GameDatabaseListView::CreateColumns() +{ + for( int i=0; ifindGame(first, i1)) return false; + if (!m_GameDB->findGame(second, i2)) return true; + + if (int retval = _doCompare(first, second)) + return m_descending ? (retval>0) : (retval<0); + + return 0; + } + + virtual int _doCompare( const Game_Data& first, const Game_Data& second )=0; +}; + +class GLSort_bySerial : public BaseGameListSort +{ +public: + GLSort_bySerial( bool descend ) : BaseGameListSort( descend ) { } + +protected: + int _doCompare( const Game_Data& g1, const Game_Data& g2 ) + { + return g1.getString("Serial").CmpNoCase( g2.getString("Serial") ); + } +}; + +class GLSort_byTitle : public BaseGameListSort +{ +public: + GLSort_byTitle( bool descend ) : BaseGameListSort( descend ) { } + +protected: + int _doCompare( const Game_Data& g1, const Game_Data& g2 ) + { + return g1.getString("Name").Cmp( g2.getString("Name") ); + } +}; + +class GLSort_byRegion : public BaseGameListSort +{ +public: + GLSort_byRegion( bool descend ) : BaseGameListSort( descend ) { } + +protected: + int _doCompare( const Game_Data& g1, const Game_Data& g2 ) + { + return g1.getString("Region").CmpNoCase( g2.getString("Region") ); + } +}; + +class GLSort_byCompat : public BaseGameListSort +{ +public: + GLSort_byCompat( bool descend ) : BaseGameListSort( descend ) { } + +protected: + int _doCompare( const Game_Data& g1, const Game_Data& g2 ) + { + return g1.getInt("Compat") - g2.getInt("Compat"); + } +}; + +class GLSort_byPatches : public BaseGameListSort +{ +public: + GLSort_byPatches( bool descend ) : BaseGameListSort( descend ) { } + +protected: + int _doCompare( const Game_Data& g1, const Game_Data& g2 ) + { + bool hasPatches1 = !g1.getString("[patches]").IsEmpty(); + bool hasPatches2 = !g2.getString("[patches]").IsEmpty(); + + if (hasPatches1 == hasPatches2) return 0; + + return hasPatches1 ? -1 : 1; + } +}; + +GameDatabaseListView& GameDatabaseListView::SortBy( GameDataColumnId column ) +{ + wxArrayString::CompareFunction cmpfunc = NULL; + + const bool isDescending = false; + + wxArrayString::iterator begin = m_GamesInView.begin(); + wxArrayString::iterator end = m_GamesInView.end(); + + // Note: std::sort does not pass predicate instances by reference, which means we can't use + // object polymorphism to simplify the code below. --air + + switch( column ) + { + case GdbCol_Serial: std::sort(begin, end, GLSort_bySerial(isDescending)); break; + case GdbCol_Title: std::sort(begin, end, GLSort_byTitle(isDescending)); break; + case GdbCol_Region: std::sort(begin, end, GLSort_byRegion(isDescending)); break; + case GdbCol_Compat: std::sort(begin, end, GLSort_byCompat(isDescending)); break; + case GdbCol_Patches: std::sort(begin, end, GLSort_byPatches(isDescending)); break; + + // do not use jNO_DEFAULT here -- keeps release builds from crashing (it'll just + // ignore the sort request!) + } + //m_GamesInView.( ); + + return *this; +} + +// return the text for the given column of the given item +wxString GameDatabaseListView::OnGetItemText(long item, long column) const +{ + IGameDatabase* GameDB = AppHost_GetGameDatabase(); + + if (!GameDB || (item < 0) || ((uint)item >= m_GamesInView.GetCount())) + return _parent::OnGetItemText(item, column); + + Game_Data game; + if (!GameDB->findGame(game, m_GamesInView[item])) + { + pxFail( "Unknown row index in GameDatabaseListView -- returning default value." ); + return _parent::OnGetItemText(item, column); + } + + switch( column ) + { + case GdbCol_Serial: return m_GamesInView[item]; + case GdbCol_Title: return game.getString("Name"); + case GdbCol_Region: return game.getString("Region"); + case GdbCol_Compat: return game.getString("Compat"); + case GdbCol_Patches: return game.getString("[patches]").IsEmpty() ? L"No" : L"Yes"; + } + + pxFail( "Unknown column index in GameDatabaseListView -- returning an empty string." ); + return wxEmptyString; +} + +// return the icon for the given item. In report view, OnGetItemImage will +// only be called for the first column. See OnGetItemColumnImage for +// details. +int GameDatabaseListView::OnGetItemImage(long item) const +{ + return _parent::OnGetItemImage( item ); +} + +// return the icon for the given item and column. +int GameDatabaseListView::OnGetItemColumnImage(long item, long column) const +{ + return _parent::OnGetItemColumnImage( item, column ); +} + +static wxListItemAttr m_ItemAttr; + +// return the attribute for the item (may return NULL if none) +wxListItemAttr* GameDatabaseListView::OnGetItemAttr(long item) const +{ + m_ItemAttr = wxListItemAttr(); // Wipe it clean! + + // For eventual drag&drop ? + //if( m_TargetedItem == item ) + // m_ItemAttr.SetBackgroundColour( wxColour(L"Wheat") ); + + return &m_ItemAttr; +} + + +#define blankLine() { \ + sizer1+=5; sizer1+=5; sizer1+=Text(wxEmptyString); sizer1+=5; sizer1+=5; \ } #define placeTextBox(wxBox, txt) { \ @@ -43,9 +333,6 @@ wxTextCtrl* CreateMultiLineTextCtrl( wxWindow* parent, int digits, long flags = Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) : BaseApplicableConfigPanel( parent ) { - IGameDatabase* GameDB = AppHost_GetGameDatabase(); - pxAssume( GameDB != NULL ); - searchBtn = new wxButton (this, wxID_ANY, _("Search")); serialBox = CreateNumericalTextCtrl(this, 40, wxTE_LEFT); @@ -59,7 +346,8 @@ Panels::GameDatabasePanel::GameDatabasePanel( wxWindow* parent ) gameFixes[i] = new pxCheckBox(this, EnumToString(i), wxCHK_3STATE | wxCHK_ALLOW_3RD_STATE_FOR_USER ); *this += Heading(_("Game Database Editor")).Bold() | StdExpand(); - //*this += Heading(_("This panel lets you add and edit game titles, game fixes, and game patches.")) | StdExpand(); + + *this += new GameDatabaseListView( this ) | StdExpand(); wxFlexGridSizer& sizer1(*new wxFlexGridSizer(5, StdPadding)); sizer1.AddGrowableCol(0); diff --git a/pcsx2/gui/Panels/GameFixesPanel.cpp b/pcsx2/gui/Panels/GameFixesPanel.cpp index 8b6d10005c..ac14e3014b 100644 --- a/pcsx2/gui/Panels/GameFixesPanel.cpp +++ b/pcsx2/gui/Panels/GameFixesPanel.cpp @@ -64,7 +64,7 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) }, { _("EE timing hack - Multi purpose hack. Try if all else fails."), - pxE( ".Tooltip:Gamefixes:EE Timing Hack", + pxEt( "!ContextTip:Gamefixes:EE Timing Hack", L"Known to affect following games:\n" L" * Digital Devil Saga (Fixes FMV and crashes)\n" L" * SSX (Fixes bad graphics and crashes)\n" @@ -77,7 +77,7 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) }, { _("OPH Flag hack - Try if your game freezes showing the same frame."), - pxE( ".Tooltip:Gamefixes:OPH Flag hack", + pxEt( "!ContextTip:Gamefixes:OPH Flag hack", L"Known to affect following games:\n" L" * Bleach Blade Battler\n" L" * Growlanser II and III\n" @@ -93,7 +93,7 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) } m_check_Enable = new pxCheckBox( this, _("Enable game fixes"), - pxE( ".Panel:Gamefixes:Compat Warning", + pxE( "!Panel:Gamefixes:Compat Warning", L"Gamefixes can fix wrong emulation in some games. However " L"it can cause compatibility or performance issues in other games. You " L"will need to turn off fixes manually when changing games." diff --git a/pcsx2/gui/Panels/MemoryCardListPanel.cpp b/pcsx2/gui/Panels/MemoryCardListPanel.cpp index c00197699b..02cbd9c316 100644 --- a/pcsx2/gui/Panels/MemoryCardListPanel.cpp +++ b/pcsx2/gui/Panels/MemoryCardListPanel.cpp @@ -362,7 +362,7 @@ public: if( dest.IsPresent && dest.IsFormatted ) { - pxsFmt( pxE( ".Popup:Mcd:Overwrite", + pxsFmt( pxE( "!Notice:Mcd:Overwrite", L"This will copy the contents of the memory card in slot %u over the memory card in slot %u. " L"All data on the target slot will be lost. Are you sure?" ), src.Slot, dest.Slot @@ -376,7 +376,7 @@ public: if( !wxCopyFile( srcfile.GetFullPath(), destfile.GetFullPath(), true ) ) { wxString heading; - heading.Printf( pxE( ".Error:Mcd:Copy Failed", + heading.Printf( pxE( "!Notice:Mcd:Copy Failed", L"Error! Could not copy the memory card into slot %u. The destination file is in use." ), dest.Slot ); @@ -582,7 +582,7 @@ void Panels::MemoryCardListPanel_Simple::OnCreateCard(wxCommandEvent& evt) { wxString content; content.Printf( - pxE( ".Popup:Mcd:Delete", + pxE( "!Notice:Mcd:Delete", L"You are about to delete the formatted memory card in slot %u. " L"All data on this card will be lost! Are you absolutely and quite positively sure?" ), slot diff --git a/pcsx2/gui/Panels/MemoryCardPanels.h b/pcsx2/gui/Panels/MemoryCardPanels.h index 99db26c556..4eba605210 100644 --- a/pcsx2/gui/Panels/MemoryCardPanels.h +++ b/pcsx2/gui/Panels/MemoryCardPanels.h @@ -20,6 +20,13 @@ #include #include +struct ListViewColumnInfo +{ + const wxChar* name; + int width; + wxListColumnFormat align; +}; + // -------------------------------------------------------------------------------------- // McdListItem / IMcdList // -------------------------------------------------------------------------------------- @@ -67,13 +74,6 @@ public: virtual wxDirName GetMcdPath() const=0; }; -struct ListViewColumnInfo -{ - const wxChar* name; - int width; - wxListColumnFormat align; -}; - // -------------------------------------------------------------------------------------- // BaseMcdListView // -------------------------------------------------------------------------------------- @@ -231,6 +231,7 @@ namespace Panels protected: pxCheckBox* m_check_Multitap[2]; pxCheckBox* m_check_Ejection; + pxCheckBox* m_check_SavestateBackup; public: McdConfigPanel_Toggles( wxWindow* parent ); diff --git a/pcsx2/gui/Panels/MiscPanelStuff.cpp b/pcsx2/gui/Panels/MiscPanelStuff.cpp index ad910c9e05..c9c1c19c28 100644 --- a/pcsx2/gui/Panels/MiscPanelStuff.cpp +++ b/pcsx2/gui/Panels/MiscPanelStuff.cpp @@ -32,13 +32,13 @@ using namespace pxSizerFlags; Panels::DocsFolderPickerPanel::DocsFolderPickerPanel( wxWindow* parent, bool isFirstTime ) : BaseApplicableConfigPanel( parent, wxVERTICAL, _("Usermode Selection") ) { - const wxString usermodeExplained( pxE( ".Panel:Usermode:Explained", + const wxString usermodeExplained( pxE( "!Panel:Usermode:Explained", L"Please select your preferred default location for PCSX2 user-level documents below " L"(includes memory cards, screenshots, settings, and savestates). " L"These folder locations can be overridden at any time using the Core Settings panel." ) ); - const wxString usermodeWarning( pxE( ".Panel:Usermode:Warning", + const wxString usermodeWarning( pxE( "!Panel:Usermode:Warning", L"You can change the preferred default location for PCSX2 user-level documents here " L"(includes memory cards, screenshots, settings, and savestates). " L"This option only affects Standard Paths which are set to use the installation default value." @@ -113,26 +113,32 @@ Panels::LanguageSelectionPanel::LanguageSelectionPanel( wxWindow* parent ) i18n_EnumeratePackages( m_langs ); int size = m_langs.size(); - int cursel = 0; - ScopedArray compiled( size ); //, L"Compiled Language Names" ); - wxString configLangName( wxLocale::GetLanguageName( wxLANGUAGE_DEFAULT ) ); + ScopedArray compiled( size ); for( int i=0; iSetToolTip(_("Make this language my default right now!")); + + *this += Label(_("Select a language:")) | pxMiddle; *this += 5; *this += m_picker | pxSizerFlags::StdSpace(); + *this += 5; + *this += applyButton | pxSizerFlags::StdSpace(); - m_picker->SetSelection( cursel ); - //AppStatusEvent_OnSettingsApplied(); + Connect( pxID_RestartWizard, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( LanguageSelectionPanel::OnApplyLanguage_Clicked ) ); + + m_picker->SetSelection( 0 ); // always default to System Default +} + +void Panels::LanguageSelectionPanel::OnApplyLanguage_Clicked( wxCommandEvent& evt ) +{ + evt.Skip(); + Apply(); } void Panels::LanguageSelectionPanel::Apply() @@ -144,19 +150,39 @@ void Panels::LanguageSelectionPanel::Apply() wxString sel( m_picker->GetString( m_picker->GetSelection() ) ); - g_Conf->LanguageId = wxLANGUAGE_DEFAULT; // use this if no matches found + g_Conf->LanguageCode = L"default"; // use this if no matches found + g_Conf->LanguageId = wxLANGUAGE_DEFAULT; int size = m_langs.size(); for( int i=0; iLanguageId = m_langs[i].wxLangId; + if( i18n_SetLanguage( m_langs[i].wxLangId, m_langs[i].canonicalName ) ) + { + g_Conf->LanguageCode = m_langs[i].canonicalName; + g_Conf->LanguageId = m_langs[i].wxLangId; + } break; } } + } void Panels::LanguageSelectionPanel::AppStatusEvent_OnSettingsApplied() { - if( m_picker ) m_picker->SetSelection( g_Conf->LanguageId ); + if (m_picker) + { + m_picker->SetSelection( 0 ); // always default to System Default + + if (g_Conf->LanguageCode.IsEmpty()) + g_Conf->LanguageCode = L"default"; + + for (uint i=0; iLanguageCode)) + { + m_picker->SetSelection( i ); + } + } + } } diff --git a/pcsx2/gui/Panels/PathsPanel.cpp b/pcsx2/gui/Panels/PathsPanel.cpp index aa66abb1b5..f7500f1d3d 100644 --- a/pcsx2/gui/Panels/PathsPanel.cpp +++ b/pcsx2/gui/Panels/PathsPanel.cpp @@ -36,7 +36,7 @@ Panels::StandardPathsPanel::StandardPathsPanel( wxWindow* parent ) : *this += (new DirPickerPanel( this, FolderId_Savestates, _("Savestates:"), _("Select folder for Savestates") ))-> - SetToolTip( pxE( ".Tooltip:Folders:Savestates", + SetToolTip( pxEt( "!ContextTip:Folders:Savestates", L"This folder is where PCSX2 records savestates; which are recorded either by using " L"menus/toolbars, or by pressing F1/F3 (load/save)." ) @@ -46,7 +46,7 @@ Panels::StandardPathsPanel::StandardPathsPanel( wxWindow* parent ) : *this += (new DirPickerPanel( this, FolderId_Snapshots, _("Snapshots:"), _("Select a folder for Snapshots") ))-> - SetToolTip( pxE( ".Tooltip:Folders:Snapshots", + SetToolTip( pxEt( "!ContextTip:Folders:Snapshots", L"This folder is where PCSX2 saves screenshots. Actual screenshot image format and style " L"may vary depending on the GS plugin being used." ) @@ -56,7 +56,7 @@ Panels::StandardPathsPanel::StandardPathsPanel( wxWindow* parent ) : *this += (new DirPickerPanel( this, FolderId_Logs, _("Logs/Dumps:" ), _("Select a folder for logs/dumps") ))-> - SetToolTip( pxE( ".Tooltip:Folders:Logs", + SetToolTip( pxEt( "!ContextTip:Folders:Logs", L"This folder is where PCSX2 saves its logfiles and diagnostic dumps. Most plugins will " L"also adhere to this folder, however some older plugins may ignore it." ) @@ -67,7 +67,7 @@ Panels::StandardPathsPanel::StandardPathsPanel( wxWindow* parent ) : *this += (new DirPickerPanel( this, FolderId_MemoryCards, _("Memorycards:"), _("Select a default Memorycards folder") ))-> - SetToolTip( pxE( ".Tooltips:Folders:Memorycards", + SetToolTip( pxE( "!Tooltip:Folders:Memorycards", L"This is the default path where PCSX2 loads or creates its memory cards, and can be " L"overridden in the MemoryCard Configuration by using absolute filenames." ) diff --git a/pcsx2/gui/Panels/PluginSelectorPanel.cpp b/pcsx2/gui/Panels/PluginSelectorPanel.cpp index 3d8679c9ab..0f81c66daf 100644 --- a/pcsx2/gui/Panels/PluginSelectorPanel.cpp +++ b/pcsx2/gui/Panels/PluginSelectorPanel.cpp @@ -239,7 +239,7 @@ void ApplyOverValidStateEvent::InvokeEvent() { wxDialogWithHelpers dialog( m_owner, _("Shutdown PS2 virtual machine?") ); - dialog += dialog.Heading( pxE( ".Popup:PluginSelector:ConfirmShutdown", + dialog += dialog.Heading( pxE( "!Notice:PluginSelector:ConfirmShutdown", L"Warning! Changing plugins requires a complete shutdown and reset of the PS2 virtual machine. " L"PCSX2 will attempt to save and restore the state, but if the newly selected plugins are " L"incompatible the recovery may fail, and current progress will be lost." @@ -275,7 +275,6 @@ void SysExecEvent_ApplyPlugins::InvokeEvent() memSavingState saveme( *(buffer.Reassign(new VmStateBuffer(L"StateBuffer_ApplyNewPlugins"))) ); - saveme.FreezeMainMemory(); saveme.FreezeAll(); } @@ -456,7 +455,7 @@ void Panels::PluginSelectorPanel::AppStatusEvent_OnSettingsApplied() static wxString GetApplyFailedMsg() { - return wxsFormat( pxE( ".Error:PluginSelector:ApplyFailed", + return wxsFormat( pxE( "!Notice:PluginSelector:ApplyFailed", L"All plugins must have valid selections for %s to run. If you are unable to make " L"a valid selection due to missing plugins or an incomplete install of %s, then " L"press cancel to close the Configuration panel." diff --git a/pcsx2/gui/Panels/SpeedhacksPanel.cpp b/pcsx2/gui/Panels/SpeedhacksPanel.cpp index 648f1ddaaf..58ab05f015 100644 --- a/pcsx2/gui/Panels/SpeedhacksPanel.cpp +++ b/pcsx2/gui/Panels/SpeedhacksPanel.cpp @@ -24,17 +24,17 @@ const wxChar* Panels::SpeedHacksPanel::GetEEcycleSliderMsg( int val ) switch( val ) { case 1: - return pxE( ".Panel:Speedhacks:EECycleX1", + return pxEt( "!Panel:Speedhacks:EECycleX1", L"1 - Default cyclerate. This closely matches the actual speed of a real PS2 EmotionEngine." ); case 2: - return pxE( ".Panel:Speedhacks:EECycleX2", + return pxEt( "!Panel:Speedhacks:EECycleX2", L"2 - Reduces the EE's cyclerate by about 33%. Mild speedup for most games with high compatibility." ); case 3: - return pxE( ".Panel:Speedhacks:EECycleX3", + return pxEt( "!Panel:Speedhacks:EECycleX3", L"3 - Reduces the EE's cyclerate by about 50%. Moderate speedup, but *will* cause stuttering " L"audio on many FMVs." ); @@ -51,23 +51,23 @@ const wxChar* Panels::SpeedHacksPanel::GetVUcycleSliderMsg( int val ) switch( val ) { case 0: - return pxE( ".Panel:Speedhacks:VUCycleStealOff", + return pxEt( "!Panel:Speedhacks:VUCycleStealOff", L"0 - Disables VU Cycle Stealing. Most compatible setting!" ); case 1: - return pxE( ".Panel:Speedhacks:VUCycleSteal1", + return pxEt( "!Panel:Speedhacks:VUCycleSteal1", L"1 - Mild VU Cycle Stealing. Lower compatibility, but some speedup for most games." ); case 2: - return pxE( ".Panel:Speedhacks:VUCycleSteal2", + return pxEt( "!Panel:Speedhacks:VUCycleSteal2", L"2 - Moderate VU Cycle Stealing. Even lower compatibility, but significant speedups in some games." ); case 3: // TODO: Mention specific games that benefit from this setting here. - return pxE( ".Panel:Speedhacks:VUCycleSteal3", + return pxEt( "!Panel:Speedhacks:VUCycleSteal3", L"3 - Maximum VU Cycle Stealing. Usefulness is limited, as this will cause flickering " L"visuals or slowdown in most games." ); @@ -94,7 +94,7 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow* parent ) const wxSizerFlags sliderFlags( wxSizerFlags().Border( wxLEFT | wxRIGHT, 8 ).Expand() ); m_check_Enable = new pxCheckBox( this, _("Enable speedhacks"), - pxE( ".Panel:Speedhacks:Overview", + pxE( "!Panel:Speedhacks:Overview", L"Speedhacks usually improve emulation speed, but can cause glitches, broken audio, and " L"false FPS readings. When having emulation problems, disable this panel first." ) @@ -126,7 +126,7 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow* parent ) m_msg_eecycle->SetForegroundColour( wxColour( L"Red" ) ); m_msg_eecycle->SetHeight(3); - const wxChar* ee_tooltip = pxE( ".Tooltip:Speedhacks:EECycleRate Slider", + const wxChar* ee_tooltip = pxEt( "!ContextTip:Speedhacks:EECycleRate Slider", L"Setting higher values on this slider effectively reduces the clock speed of the EmotionEngine's " L"R5900 core cpu, and typically brings big speedups to games that fail to utilize " L"the full potential of the real PS2 hardware." @@ -147,7 +147,7 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow* parent ) m_msg_vustealer->SetForegroundColour( wxColour( L"Red" ) ); m_msg_vustealer->SetHeight(3); - const wxChar* vu_tooltip = pxE( ".Tooltip:Speedhacks:VUCycleStealing Slider", + const wxChar* vu_tooltip = pxEt( "!ContextTip:Speedhacks:VUCycleStealing Slider", L"This slider controls the amount of cycles the VU unit steals from the EmotionEngine. Higher values increase the number of " L"cycles stolen from the EE for each VU microprogram the game runs." ); @@ -169,17 +169,17 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow* parent ) m_check_vuMinMax = new pxCheckBox( vuHacksPanel, _("mVU Min/Max Hack"), _("Small Speedup; may cause black screens, garbage graphics, SPS, etc... [Not Recommended]") ); - m_check_vuFlagHack->SetToolTip( pxE( ".Tooltip:Speedhacks:vuFlagHack", + m_check_vuFlagHack->SetToolTip( pxEt( "!ContextTip:Speedhacks:vuFlagHack", L"Updates Status Flags only on blocks which will read them, instead of all the time. " L"This is safe most of the time, and Super VU does something similar by default." ) ); - m_check_vuBlockHack->SetToolTip( pxE( ".Tooltip:Speedhacks:vuBlockHack", + m_check_vuBlockHack->SetToolTip( pxEt( "!ContextTip:Speedhacks:vuBlockHack", L"Assumes that very far into future blocks will not need old flag instance data. " L"This should be pretty safe. It is unknown if this breaks any game..." ) ); - m_check_vuMinMax->SetToolTip( pxE( ".Tooltip:Speedhacks:vuMinMax", + m_check_vuMinMax->SetToolTip( pxEt( "!ContextTip:Speedhacks:vuMinMax", L"Uses SSE's Min/Max Floating Point Operations instead of custom logical Min/Max routines. " L"Known to break Gran Turismo 4, Tekken 5." ) ); @@ -199,19 +199,19 @@ Panels::SpeedHacksPanel::SpeedHacksPanel( wxWindow* parent ) _("Fast disc access, less loading times. [Not Recommended]") ); - m_check_intc->SetToolTip( pxE( ".Tooltip:Speedhacks:INTC", + m_check_intc->SetToolTip( pxEt( "!ContextTip:Speedhacks:INTC", L"This hack works best for games that use the INTC Status register to wait for vsyncs, which includes primarily non-3D " L"RPG titles. Games that do not use this method of vsync will see little or no speedup from this hack." ) ); - m_check_waitloop->SetToolTip( pxE( ".Tooltip:Speedhacks:BIFC0", + m_check_waitloop->SetToolTip( pxEt( "!ContextTip:Speedhacks:BIFC0", L"Primarily targetting the EE idle loop at address 0x81FC0 in the kernel, this hack attempts to " L"detect loops whose bodies are guaranteed to result in the same machine state for every iteration " L"until a scheduled event triggers emulation of another unit. After a single iteration of such loops, " L"we advance to the time of the next event or the end of the processor's timeslice, whichever comes first." ) ); - m_check_fastCDVD->SetToolTip( pxE( ".Tooltip:Speedhacks:fastCDVD", + m_check_fastCDVD->SetToolTip( pxEt( "!ContextTip:Speedhacks:fastCDVD", L"Check HDLoader compatibility lists for known games that have issues with this. (Often marked as needing 'mode 1' or 'slow DVD'" ) ); diff --git a/pcsx2/gui/Panels/VideoPanel.cpp b/pcsx2/gui/Panels/VideoPanel.cpp index 1389a6f136..ab340f161c 100644 --- a/pcsx2/gui/Panels/VideoPanel.cpp +++ b/pcsx2/gui/Panels/VideoPanel.cpp @@ -34,7 +34,7 @@ Panels::FramelimiterPanel::FramelimiterPanel( wxWindow* parent ) m_check_LimiterDisable = new pxCheckBox( this, _("Disable Framelimiting"), _("Useful for running benchmarks. Toggle this option in-game by pressing F4.") ); - m_check_LimiterDisable->SetToolTip( pxE( ".Tooltip:Framelimiter:Disable", + m_check_LimiterDisable->SetToolTip( pxEt( "!ContextTip:Framelimiter:Disable", L"Note that when Framelimiting is disabled, Turbo and SlowMotion modes will not " L"be available either." ) ); @@ -102,8 +102,8 @@ Panels::FramelimiterPanel::FramelimiterPanel( wxWindow* parent ) *this += 5; - //*this += Heading( pxE( ".Panel:Framelimiter:Heading", - *this += new pxStaticText( this, pxE( ".Panel:Framelimiter:Heading", + //*this += Heading( pxE( "!Panel:Framelimiter:Heading", + *this += new pxStaticText( this, pxE( "!Panel:Framelimiter:Heading", L"The internal framelimiter regulates the speed of the virtual machine. Adjustment values below are in " L"percentages of the default region-based framerate, which can also be configured below." ) ); @@ -145,11 +145,11 @@ void Panels::FramelimiterPanel::Apply() catch( Exception::ParseError& ) { throw Exception::CannotApplySettings( this ) - .SetDiagMsg(wxsFormat( + .SetDiagMsg(pxsFmt( L"Error while parsing either NTSC or PAL framerate settings.\n\tNTSC Input = %s\n\tPAL Input = %s", m_text_BaseNtsc->GetValue().c_str(), m_text_BasePal->GetValue().c_str() ) ) - .SetUserMsg(_("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics.")); + .SetUserMsg(_t("Error while parsing either NTSC or PAL framerate settings. Settings must be valid floating point numerics.")); } appfps.SanityCheck(); @@ -168,12 +168,12 @@ Panels::FrameSkipPanel::FrameSkipPanel( wxWindow* parent ) m_check_EnableSkip = new pxCheckBox( this, _("Use Frameskip"), _(".") ); - m_check_EnableSkip->SetToolTip( pxE( ".Tooltip:Frameskip:Disable", + m_check_EnableSkip->SetToolTip( pxEt( "!ContextTip:Frameskip:Disable", L"" L"" ) ); - m_check_EnableSkipOnTurbo->SetToolTip( pxE( ".Tooltip:Frameskip:UseForTurbo", + m_check_EnableSkipOnTurbo->SetToolTip( pxEt( "!ContextTip:Frameskip:UseForTurbo", L"Recommended option! Since frameskipping glitches typically aren't as annoying when you're " L" just trying to speed through stuff." ) );*/ @@ -227,7 +227,7 @@ Panels::FrameSkipPanel::FrameSkipPanel( wxWindow* parent ) *this += s_spins | StdExpand(); - *this += Text( pxE( ".Panel:Frameskip:Heading", + *this += Text( pxE( "!Panel:Frameskip:Heading", L"Notice: Due to PS2 hardware design, precise frame skipping is impossible. " L"Enabling it will cause severe graphical errors in some games." ) ) | StdExpand(); @@ -289,18 +289,18 @@ Panels::VideoPanel::VideoPanel( wxWindow* parent ) : wxPanelWithHelpers* right = new wxPanelWithHelpers( this, wxVERTICAL ); m_check_SynchronousGS = new pxCheckBox( right, _("Use Synchronized MTGS"), - _("For troubleshooting potential bugs in the MTGS only, as it is potentially very slow.") + _t("For troubleshooting potential bugs in the MTGS only, as it is potentially very slow.") ); m_check_DisableOutput = new pxCheckBox( right, _("Disable all GS output"), - _("Completely disables all GS plugin activity; ideal for benchmarking EEcore components.") + _t("Completely disables all GS plugin activity; ideal for benchmarking EEcore components.") ); - m_check_SynchronousGS->SetToolTip( pxE( ".Tooltip:GS:SyncMTGS", + m_check_SynchronousGS->SetToolTip( pxEt( "!ContextTip:GS:SyncMTGS", L"Enable this if you think MTGS thread sync is causing crashes or graphical errors.") ) ; - m_check_DisableOutput->SetToolTip( pxE( ".Tooltip:GS:DisableOutput", + m_check_DisableOutput->SetToolTip( pxEt( "!ContextTip:GS:DisableOutput", L"Removes any benchmark noise caused by the MTGS thread or GPU overhead. This option is best used in conjunction with savestates: " L"save a state at an ideal scene, enable this option, and re-load the savestate.\n\n" L"Warning: This option can be enabled on-the-fly but typically cannot be disabled on-the-fly (video will typically be garbage)." diff --git a/pcsx2/gui/SysState.cpp b/pcsx2/gui/SysState.cpp index 018f793105..4350d82f65 100644 --- a/pcsx2/gui/SysState.cpp +++ b/pcsx2/gui/SysState.cpp @@ -22,6 +22,7 @@ #include "VUmicro.h" #include "ZipTools/ThreadedZipTools.h" +#include "Utilities/pxStreams.h" #include @@ -30,9 +31,99 @@ static const wxChar* EntryFilename_StateVersion = L"PCSX2 Savestate Version.id"; static const wxChar* EntryFilename_Screenshot = L"Screenshot.jpg"; -static const wxChar* EntryFilename_InternalStructures = L"PCSX2 Internal Structures.bin"; +static const wxChar* EntryFilename_InternalStructures = L"PCSX2 Internal Structures.dat"; +// -------------------------------------------------------------------------------------- +// BaseSavestateEntry +// -------------------------------------------------------------------------------------- +class BaseSavestateEntry +{ +protected: + BaseSavestateEntry() {} + virtual ~BaseSavestateEntry() throw() {} + +public: + virtual wxString GetFilename() const=0; + virtual void FreezeIn( pxInputStream& reader ) const=0; + virtual void FreezeOut( SaveStateBase& writer ) const=0; +}; + +class MemorySavestateEntry : public BaseSavestateEntry +{ +protected: + MemorySavestateEntry() {} + virtual ~MemorySavestateEntry() throw() {} + +public: + virtual void FreezeIn( pxInputStream& reader ) const; + virtual void FreezeOut( SaveStateBase& writer ) const; + +protected: + virtual u8* GetDataPtr() const=0; + virtual uint GetDataSize() const=0; +}; + +class PluginSavestateEntry : public BaseSavestateEntry +{ +protected: + PluginsEnum_t m_pid; + +public: + PluginSavestateEntry( PluginsEnum_t pid ) + { + m_pid = pid; + } + + virtual ~PluginSavestateEntry() throw() {} + + virtual wxString GetFilename() const; + virtual void FreezeIn( pxInputStream& reader ) const; + virtual void FreezeOut( SaveStateBase& writer ) const; + +protected: + virtual PluginsEnum_t GetPluginId() const { return m_pid; } +}; + +void MemorySavestateEntry::FreezeIn( pxInputStream& reader ) const +{ + const uint entrySize = reader.Length(); + const uint expectedSize = GetDataSize(); + + if (entrySize < expectedSize) + { + Console.WriteLn( Color_Yellow, " '%s' is incomplete (expected 0x%x bytes, loading only 0x%x bytes)", + GetFilename(), expectedSize, entrySize ); + } + + uint copylen = std::min(entrySize, expectedSize); + reader.Read( GetDataPtr(), copylen ); +} + +void MemorySavestateEntry::FreezeOut( SaveStateBase& writer ) const +{ + writer.FreezeMem( GetDataPtr(), GetDataSize() ); +} + +wxString PluginSavestateEntry::GetFilename() const +{ + return pxsFmt( "Plugin %s.dat", tbl_PluginInfo[m_pid].shortname ); +} + +void PluginSavestateEntry::FreezeIn( pxInputStream& reader ) const +{ + GetCorePlugins().FreezeIn( GetPluginId(), reader ); +} + +void PluginSavestateEntry::FreezeOut( SaveStateBase& writer ) const +{ + if (uint size = GetCorePlugins().GetFreezeSize( GetPluginId() )) + { + writer.PrepBlock( size ); + GetCorePlugins().FreezeOut( GetPluginId(), writer.GetBlockPtr() ); + } +} + // -------------------------------------------------------------------------------------- // SavestateEntry_* (EmotionMemory, IopMemory, etc) // -------------------------------------------------------------------------------------- @@ -42,7 +133,7 @@ static const wxChar* EntryFilename_InternalStructures = L"PCSX2 Internal Structu // cannot use static struct member initializers -- we need virtual functions that compute // and resolve the addresses on-demand instead... --air -class SavestateEntry_EmotionMemory : public BaseArchiveEntry +class SavestateEntry_EmotionMemory : public MemorySavestateEntry { public: wxString GetFilename() const { return L"eeMemory.bin"; } @@ -50,7 +141,7 @@ public: uint GetDataSize() const { return sizeof(eeMem->Main); } }; -class SavestateEntry_IopMemory : public BaseArchiveEntry +class SavestateEntry_IopMemory : public MemorySavestateEntry { public: wxString GetFilename() const { return L"iopMemory.bin"; } @@ -58,7 +149,7 @@ public: uint GetDataSize() const { return sizeof(iopMem->Main); } }; -class SavestateEntry_HwRegs : public BaseArchiveEntry +class SavestateEntry_HwRegs : public MemorySavestateEntry { public: wxString GetFilename() const { return L"eeHwRegs.bin"; } @@ -66,7 +157,7 @@ public: uint GetDataSize() const { return sizeof(eeHw); } }; -class SavestateEntry_IopHwRegs : public BaseArchiveEntry +class SavestateEntry_IopHwRegs : public MemorySavestateEntry { public: wxString GetFilename() const { return L"iopHwRegs.bin"; } @@ -74,7 +165,7 @@ public: uint GetDataSize() const { return sizeof(iopHw); } }; -class SavestateEntry_Scratchpad : public BaseArchiveEntry +class SavestateEntry_Scratchpad : public MemorySavestateEntry { public: wxString GetFilename() const { return L"Scratchpad.bin"; } @@ -82,7 +173,7 @@ public: uint GetDataSize() const { return sizeof(eeMem->Scratch); } }; -class SavestateEntry_VU0mem : public BaseArchiveEntry +class SavestateEntry_VU0mem : public MemorySavestateEntry { public: wxString GetFilename() const { return L"vu0Memory.bin"; } @@ -90,7 +181,7 @@ public: uint GetDataSize() const { return VU0_MEMSIZE; } }; -class SavestateEntry_VU1mem : public BaseArchiveEntry +class SavestateEntry_VU1mem : public MemorySavestateEntry { public: wxString GetFilename() const { return L"vu1Memory.bin"; } @@ -98,22 +189,23 @@ public: uint GetDataSize() const { return VU1_MEMSIZE; } }; -class SavestateEntry_VU0prog : public BaseArchiveEntry +class SavestateEntry_VU0prog : public MemorySavestateEntry { public: - wxString GetFilename() const { return L"vu0Programs.bin"; } + wxString GetFilename() const { return L"vu0MicroMem.bin"; } u8* GetDataPtr() const { return vuRegs[0].Micro; } uint GetDataSize() const { return VU0_PROGSIZE; } }; -class SavestateEntry_VU1prog : public BaseArchiveEntry +class SavestateEntry_VU1prog : public MemorySavestateEntry { public: - wxString GetFilename() const { return L"vu1Programs.bin"; } + wxString GetFilename() const { return L"vu1MicroMem.bin"; } u8* GetDataPtr() const { return vuRegs[1].Micro; } uint GetDataSize() const { return VU1_PROGSIZE; } }; + // [TODO] : Add other components as files to the savestate gzip? // * VU0/VU1 memory banks? VU0prog, VU1prog, VU0data, VU1data. // * GS register data? @@ -123,7 +215,7 @@ public: // would not be useful). // -static const BaseArchiveEntry* const SavestateEntries[] = +static const BaseSavestateEntry* const SavestateEntries[] = { new SavestateEntry_EmotionMemory, new SavestateEntry_IopMemory, @@ -134,6 +226,15 @@ static const BaseArchiveEntry* const SavestateEntries[] = new SavestateEntry_VU1mem, new SavestateEntry_VU0prog, new SavestateEntry_VU1prog, + + new PluginSavestateEntry( PluginId_GS ), + new PluginSavestateEntry( PluginId_PAD ), + new PluginSavestateEntry( PluginId_SPU2 ), + new PluginSavestateEntry( PluginId_CDVD ), + new PluginSavestateEntry( PluginId_USB ), + new PluginSavestateEntry( PluginId_FW ), + new PluginSavestateEntry( PluginId_DEV9 ), + }; static const uint NumSavestateEntries = ArraySize(SavestateEntries); @@ -169,7 +270,9 @@ static void CheckVersion( pxInputStream& thr ) // -------------------------------------------------------------------------------------- // SysExecEvent_DownloadState // -------------------------------------------------------------------------------------- -// Pauses core emulation and downloads the savestate into the state_buffer. +// Pauses core emulation and downloads the savestate into a memory buffer. The memory buffer +// is then mailed to another thread for zip archiving, while the main emulation process is +// allowed to continue execution. // class SysExecEvent_DownloadState : public SysExecEvent { @@ -203,19 +306,20 @@ protected: ArchiveEntry internals( EntryFilename_InternalStructures ); internals.SetDataIndex( saveme.GetCurrentPos() ); - saveme.FreezeAll(); + saveme.FreezeBios(); + saveme.FreezeInternals(); internals.SetDataSize( saveme.GetCurrentPos() - internals.GetDataIndex() ); m_dest_list->Add( internals ); for (uint i=0; iFreezeOut( saveme ); m_dest_list->Add( ArchiveEntry( SavestateEntries[i]->GetFilename() ) - .SetDataIndex( saveme.GetCurrentPos() ) - .SetDataSize( SavestateEntries[i]->GetDataSize() ) + .SetDataIndex( startpos ) + .SetDataSize( saveme.GetCurrentPos() - startpos ) ); - - saveme.FreezeMem( SavestateEntries[i]->GetDataPtr(), SavestateEntries[i]->GetDataSize() ); } UI_EnableStateActions(); @@ -326,11 +430,6 @@ protected: gzfp->CloseEntry(); } - - //m_gzfp->PutNextEntry(EntryFilename_Screenshot); - //m_gzfp->Write(); - //m_gzfp->CloseEntry(); - (*new VmStateCompressThread()) .SetSource(m_src_list) .SetOutStream(out) @@ -411,7 +510,7 @@ protected: if (entry->GetName().CmpNoCase(EntryFilename_StateVersion) == 0) { - DevCon.WriteLn(L" ... found '%s'", EntryFilename_StateVersion); + DevCon.WriteLn( Color_Green, L" ... found '%s'", EntryFilename_StateVersion); foundVersion = true; CheckVersion(*reader); continue; @@ -419,7 +518,7 @@ protected: if (entry->GetName().CmpNoCase(EntryFilename_InternalStructures) == 0) { - DevCon.WriteLn(L" ... found '%s'", EntryFilename_InternalStructures); + DevCon.WriteLn( Color_Green, L" ... found '%s'", EntryFilename_InternalStructures); foundInternal = entry.DetachPtr(); continue; } @@ -435,7 +534,7 @@ protected: { if (entry->GetName().CmpNoCase(SavestateEntries[i]->GetFilename()) == 0) { - DevCon.WriteLn( Color_Green, L" ... found '%s'", SavestateEntries[i]->GetFilename() ); + DevCon.WriteLn( Color_Green, L" ... found '%s'", SavestateEntries[i]->GetFilename().c_str() ); foundEntry[i] = entry.DetachPtr(); break; } @@ -475,18 +574,8 @@ protected: Threading::pxTestCancel(); gzreader->OpenEntry( *foundEntry[i] ); - const uint entrySize = foundEntry[i]->GetSize(); - const uint expectedSize = SavestateEntries[i]->GetDataSize(); - - if (entrySize < expectedSize) - { - Console.WriteLn( Color_Yellow, " '%s' is incomplete (expected 0x%x bytes, loading only 0x%x bytes)", - SavestateEntries[i]->GetFilename(), expectedSize, entrySize ); - } - - uint copylen = std::min(entrySize, expectedSize); - reader->Read( SavestateEntries[i]->GetDataPtr(), copylen ); - } + SavestateEntries[i]->FreezeIn( *reader ); + } // Load all the internal data @@ -495,7 +584,7 @@ protected: VmStateBuffer buffer( foundInternal->GetSize(), L"StateBuffer_UnzipFromDisk" ); // start with an 8 meg buffer to avoid frequent reallocation. reader->Read( buffer.GetPtr(), foundInternal->GetSize() ); - memLoadingState( buffer ).FreezeAll(); + memLoadingState( buffer ).FreezeBios().FreezeInternals(); GetCoreThread().Resume(); // force resume regardless of emulation state earlier. } }; @@ -528,6 +617,15 @@ void StateCopy_SaveToSlot( uint num ) { const wxString file( SaveStateBase::GetFilename( num ) ); + // Backup old Savestate if one exists. + if( wxFileExists( file ) && EmuConfig.BackupSavestate ) + { + const wxString copy( SaveStateBase::GetFilename( num ) + pxsFmt( L".backup") ); + + Console.Indent().WriteLn( Color_StrongGreen, L"Backing up existing state in slot %d.", num); + wxCopyFile( file, copy ); + } + Console.WriteLn( Color_StrongGreen, "Saving savestate to slot %d...", num ); Console.Indent().WriteLn( Color_StrongGreen, L"filename: %s", file.c_str() ); diff --git a/pcsx2/gui/i18n.cpp b/pcsx2/gui/i18n.cpp index dd56f1b8a4..f52c4b9836 100644 --- a/pcsx2/gui/i18n.cpp +++ b/pcsx2/gui/i18n.cpp @@ -19,45 +19,73 @@ #include "Utilities/SafeArray.h" -LangPackEnumeration::LangPackEnumeration( wxLanguage langId ) - : wxLangId( langId ) - , englishName( wxLocale::GetLanguageName( wxLangId ) ) - , xlatedName( pxIsEnglish( wxLangId ) ? wxEmptyString : wxGetTranslation( L"NativeName" ) ) +// Some of the codes provided by wxWidgets are 'obsolete' -- effectively replaced by more specific +// region-qualified language codes. This function can be used to filter them out. +bool i18n_IsLegacyLanguageId( wxLanguage lang ) { + return + (lang == wxLANGUAGE_ENGLISH) || + (lang == wxLANGUAGE_CHINESE) || + (lang == wxLANGUAGE_CHINESE_TRADITIONAL) || + (lang == wxLANGUAGE_SERBIAN) || + (lang == wxLANGUAGE_SPANISH); +} + +static wxString i18n_GetBetterLanguageName( const wxLanguageInfo* info ) +{ + switch (info->Language) + { + case wxLANGUAGE_CHINESE: return L"Chinese (Traditional)"; + case wxLANGUAGE_CHINESE_TRADITIONAL: return L"Chinese (Traditional)"; + case wxLANGUAGE_CHINESE_TAIWAN: return L"Chinese (Traditional, Taiwan)"; + case wxLANGUAGE_CHINESE_HONGKONG: return L"Chinese (Traditional, Hong Kong)"; + case wxLANGUAGE_CHINESE_MACAU: return L"Chinese (Traditional, Macau)"; + } + + return info->Description; +} + +LangPackEnumeration::LangPackEnumeration( wxLanguage langId ) +{ + wxLangId = langId; + + if (const wxLanguageInfo* info = wxLocale::GetLanguageInfo( wxLangId )) + { + canonicalName = info->CanonicalName; + englishName = i18n_GetBetterLanguageName(info); + } } LangPackEnumeration::LangPackEnumeration() - : wxLangId( wxLANGUAGE_DEFAULT ) - , englishName( L" System Default" ) // left-side space forces it to sort to the front of the lists - , xlatedName() { - int sysLang( wxLocale::GetSystemLanguage() ); - if( sysLang != wxLANGUAGE_UNKNOWN ) - englishName += L" [" + wxLocale::GetLanguageName( sysLang ) + L"]"; -} + wxLangId = wxLANGUAGE_DEFAULT; + englishName = L" System Default"; // left-side space forces it to sort to the front of the lists + canonicalName = L"default"; + int sysLang = wxLocale::GetSystemLanguage(); + + if (sysLang == wxLANGUAGE_UNKNOWN) + sysLang = wxLANGUAGE_ENGLISH_US; + + //if (const wxLanguageInfo* info = wxLocale::GetLanguageInfo( sysLang )) + // englishName += L" [" + i18n_GetBetterLanguageName(info) + L"]"; +} static void i18n_DoPackageCheck( wxLanguage wxLangId, LangPackList& langs ) { - // Plain english is a special case that's built in, and we only want it added to the list - // once, so we check for wxLANGUAGE_ENGLISH and then ignore other IsEnglish ids below. - if( wxLangId == wxLANGUAGE_ENGLISH ) - langs.push_back( LangPackEnumeration( wxLangId ) ); + if( i18n_IsLegacyLanguageId( wxLangId ) ) return; - if( pxIsEnglish( wxLangId ) ) return; - - // Note: wx auto-preserves the current locale for us - if( !wxLocale::IsAvailable( wxLangId ) ) return; - wxLocale* locale = new wxLocale( wxLangId, wxLOCALE_CONV_ENCODING ); + // note: wx preserves the current locale for us, so creating a new locale and deleting + // will not affect program status. + ScopedPtr locale( new wxLocale( wxLangId, wxLOCALE_CONV_ENCODING ) ); // Force the msgIdLanguage param to wxLANGUAGE_UNKNOWN to disable wx's automatic english // matching logic, which will bypass the catalog loader for all english-based dialects, and // (wrongly) enumerate a bunch of locales that don't actually exist. - if( locale->IsOk() && locale->AddCatalog( L"pcsx2ident", wxLANGUAGE_UNKNOWN, NULL ) ) + if ((locale->GetLanguage() == wxLANGUAGE_ENGLISH_US) || + (locale->IsOk() && locale->AddCatalog( L"pcsx2_Main", wxLANGUAGE_UNKNOWN, NULL )) ) langs.push_back( LangPackEnumeration( wxLangId ) ); - - delete locale; } // Finds all valid PCSX2 language packs, and enumerates them for configuration selection. @@ -67,11 +95,11 @@ static void i18n_DoPackageCheck( wxLanguage wxLangId, LangPackList& langs ) // safe way to enumerate the languages is by forcibly loading every possible locale in the wx // database. Anything which hasn't been installed will fail to load. // -// Because loading and hashing the entire pcsx2 translation for every possible language would -// asinine and slow, I've decided to use a two-file translation system. One file (pcsx2ident.mo) -// is very small and simply contains the name of the language in the language native. The -// second file (pcsx2.mo) is loaded only if the user picks the language (or if it's the default -// language of the user's OS installation). +// Because loading and hashing the entire pcsx2 translation for every possible language would be +// asinine and slow, I've decided to use a file dedicated to being a translation detection anchor. +// This file is named pcsx2ident.mo, and contains only the name of the language in the language +// native form. Additional translation files are only loaded if the user picks the language (or +// if it's the default language of the user's OS installation). // void i18n_EnumeratePackages( LangPackList& langs ) { @@ -96,30 +124,118 @@ void i18n_EnumeratePackages( LangPackList& langs ) //i18n_DoPackageCheck( wxLANGUAGE_SAMI, englishNames, xlatedNames ); } -bool i18n_SetLanguage( int wxLangId ) +#if 0 +// warning: wxWidgets uses duplicated canonical codes for many languages, and has some bizarre +// matching heuristics. Using this function doesn't really match the language and sublanguage +// (dialect) that the user selected. +bool i18n_SetLanguage( const wxString& langCode ) { - if( !wxLocale::IsAvailable( wxLangId ) ) + if (langCode.IsEmpty() || langCode.CmpNoCase(L"default")) { - Console.Warning( "Invalid Language Identifier (wxID=%d).", wxLangId ); - return false; + wxLanguage sysLang = (wxLanguage)wxLocale::GetSystemLanguage(); + + if (sysLang == wxLANGUAGE_UNKNOWN) + sysLang = wxLANGUAGE_ENGLISH; } - ScopedPtr locale( new wxLocale( wxLangId, wxLOCALE_CONV_ENCODING ) ); + const wxLanguageInfo* woot = wxLocale::FindLanguageInfo( langCode ); + if (!woot) return false; + return i18n_SetLanguage( woot->Language ); +} +#endif + +// This method sets the requested language, based on wxLanguage id and an optional 'confirmation' +// canonical code. If the canonical code is provided, it is used to confirm that the ID matches +// the intended language/dialect. If the ID and canonical do not match, this method will use +// wx's FindLAnguageInfo to provide a "best guess" canonical match (usually relying on the user's +// operating system default). +// +// Rationale: wxWidgets language IDs are just simple enums, and not especially unique. Future +// versions of PCSX2 may have language ID changes if built against new/different versions of wx. +// To prevent PCSX2 from selecting a completely wrong language when upgraded, we double-check +// the wxLanguage code against the canonical name. We can't simply use canonical names either +// because those are not unique (dialects of chinese, for example), and wx returns the generic +// form over a specific dialect, when given a choice. Thus a two-tier check is required. +// +// wxLanguage for specific dialect, and canonical as a fallback/safeguard in case the wxLanguage +// id appears to be out of date. +// +// +bool i18n_SetLanguage( wxLanguage wxLangId, const wxString& langCode ) +{ + const wxLanguageInfo* info = wxLocale::GetLanguageInfo(wxLangId); + + // note: language canonical name mismatch probably means wxWidgets version changed since + // the user's ini file was provided. Missing/invalid ID probably means the same thing. + // If either is true, and the caller provided a canonical name, then let wx do a best + // match based on the canonical name. + + if (!info || (!langCode.IsEmpty() && (langCode.CmpNoCase(info->CanonicalName) != 0))) + { + if (!info) + Console.Warning( "Invalid language identifier (wxID=%d)", wxLangId ); + + if (!langCode.IsEmpty() && (langCode.CmpNoCase(L"default")!=0)) + { + info = wxLocale::FindLanguageInfo(langCode); + if (!info) + Console.Warning( "Unrecognized language canonical name '%ls'", langCode.c_str() ); + } + } + + if (!info) return false; + if (wxGetLocale() && (info->Language == wxGetLocale()->GetLanguage())) return true; + + ScopedPtr locale( new wxLocale(info->Language) ); if( !locale->IsOk() ) { Console.Warning( L"SetLanguage: '%s' [%s] is not supported by the operating system", - wxLocale::GetLanguageName( locale->GetLanguage() ).c_str(), locale->GetCanonicalName().c_str() + i18n_GetBetterLanguageName(info).c_str(), locale->GetCanonicalName().c_str() ); return false; } - if( !pxIsEnglish(wxLangId) && !locale->AddCatalog( L"pcsx2main" ) ) + wxLangId = (wxLanguage)locale->GetLanguage(); + + if (wxLangId == wxLANGUAGE_UNKNOWN) { - /*Console.Warning( L"SetLanguage: Cannot find pcsx2main.mo file for language '%s' [%s]", - wxLocale::GetLanguageName( locale->GetLanguage() ).c_str(), locale->GetCanonicalName().c_str() - );*/ - Console.Warning("SetLanguage is not implemented yet, using English."); + Console.WriteLn("System-default language is unknown? Defaulting back to English/US."); + wxLangId = wxLANGUAGE_ENGLISH_US; + } + + // English/US is built in, so no need to load MO/PO files. + if( pxIsEnglish(wxLangId) ) + { + locale.DetachPtr(); + return true; + } + + Console.WriteLn( L"Loading language translation databases for '%s' [%s]", + i18n_GetBetterLanguageName(info).c_str(), locale->GetCanonicalName().c_str() + ); + + static const wxChar* dictFiles[] = + { + L"pcsx2_Main", + L"pcsx2_Iconized", + L"pcsx2_Tertiary" + }; + + bool foundone = false; + for (uint i=0; iAddCatalog(dictFiles[i])) + Console.Indent().WriteLn(Color_StrongYellow, "%ls not found -- translation dictionary may be incomplete.", dictFiles[i]); + else + foundone = true; + } + + if (!foundone) + { + Console.Warning("SetLanguage: Requested translation is not implemented yet."); return false; } diff --git a/pcsx2/gui/i18n.h b/pcsx2/gui/i18n.h index d60ef53454..34c2b578ef 100644 --- a/pcsx2/gui/i18n.h +++ b/pcsx2/gui/i18n.h @@ -22,8 +22,11 @@ class LangPackEnumeration { public: wxLanguage wxLangId; + wxString canonicalName; wxString englishName; - wxString xlatedName; + + // [TODO] : Might be nice, but have no idea how to implement it... + //wxString xlatedName; public: LangPackEnumeration( wxLanguage langId ); @@ -32,6 +35,7 @@ public: typedef std::vector LangPackList; -extern bool i18n_SetLanguage( int wxLangId ); +extern bool i18n_SetLanguage( wxLanguage wxLangId, const wxString& langCode=wxEmptyString ); extern void i18n_EnumeratePackages( LangPackList& langs ); +extern bool i18n_IsLegacyLanguageId( wxLanguage lang ); diff --git a/pcsx2/ps2/BiosTools.cpp b/pcsx2/ps2/BiosTools.cpp index 9638807a89..afdfe6dcea 100644 --- a/pcsx2/ps2/BiosTools.cpp +++ b/pcsx2/ps2/BiosTools.cpp @@ -17,9 +17,14 @@ #include "Common.h" #include "BiosTools.h" -#include "wx/file.h" +#include "Utilities/pxStreams.h" +#include "wx/ffile.h" + +// FIXME: Temporary hack until we remove dependence on Pcsx2App. #include "AppConfig.h" +#include "wx/mstream.h" +#include "wx/wfstream.h" #define DIRENTRY_SIZE 16 @@ -36,189 +41,67 @@ struct romdir char fileName[10]; u16 extInfoSize; u32 fileSize; -} __packed; // +22 +} __packed; // +16 #ifdef _MSC_VER # pragma pack() #endif -u32 BiosVersion; // Used in Memory, Misc, CDVD +C_ASSERT( sizeof(romdir) == DIRENTRY_SIZE ); + +u32 BiosVersion; +u32 BiosChecksum; +wxString BiosDescription; + // -------------------------------------------------------------------------------------- // Exception::BiosLoadFailed (implementations) // -------------------------------------------------------------------------------------- Exception::BiosLoadFailed::BiosLoadFailed( const wxString& filename ) { - m_message_diag = L"BIOS has not been configured, or the configuration has been corrupted."; - m_message_user = _("The PS2 BIOS could not be loaded. The BIOS has not been configured, or the configuration has been corrupted. Please re-configure."); - StreamName = filename; } -// Returns the version information of the bios currently loaded into memory. -static u32 GetBiosVersion() +// This method throws a BadStream exception if the bios information could not be obtained. +// (indicating that the file is invalid, incomplete, corrupted, or plain naughty). +static void LoadBiosVersion( pxInputStream& fp, u32& version, wxString& description ) { - int i; + uint i; + romdir rd; for (i=0; i<512*1024; i++) { - if( strncmp( (char*)&psRu8(i), "RESET", 5 ) == 0 ) + fp.Read( rd ); + if (strncmp( rd.fileName, "RESET", 5 ) == 0) break; /* found romdir */ } - if (i == 512*1024) return -1; - const romdir* rd = (romdir*)&psRu8(i); + if (i == 512*1024) + { + throw Exception::BadStream( fp.GetStreamName() ) + .SetDiagMsg(L"BIOS version check failed: 'RESET' tag could not be found.") + .SetUserMsg(_("The selected BIOS file is not a valid PS2 BIOS. Please re-configure.")); + } + uint fileOffset = 0; - while(strlen(rd->fileName) > 0) - { - if (strcmp(rd->fileName, "ROMVER") == 0) - { - char vermaj[8]; - char vermin[8]; - u32 version; - - const s8 *ROMVER = &psRs8(fileOffset); - - strncpy(vermaj, (char *)(ROMVER+ 0), 2); vermaj[2] = 0; - strncpy(vermin, (char *)(ROMVER+ 2), 2); vermin[2] = 0; - version = strtol(vermaj, (char**)NULL, 0) << 8; - version|= strtol(vermin, (char**)NULL, 0); - - return version; - } - - if ((rd->fileSize % 0x10)==0) - fileOffset += rd->fileSize; - else - fileOffset += (rd->fileSize + 0x10) & 0xfffffff0; - - rd++; - } - - return -1; -} - -// Attempts to load a BIOS rom sub-component, by trying multiple combinations of base -// filename and extension. The bios specified in the user's configuration is used as -// the base. -// -// Parameters: -// ext - extension of the sub-component to load. Valid options are rom1, rom2, AND erom. -// -static void loadBiosRom( const wxChar *ext, u8 *dest, s64 maxSize ) -{ - wxString Bios1; - s64 filesize; - - // Try first a basic extension concatenation (normally results in something like name.bin.rom1) - const wxString Bios( g_Conf->FullpathToBios() ); - Bios1.Printf( L"%s.%s", Bios.c_str(), ext); - - if( (filesize=Path::GetFileSize( Bios1 ) ) <= 0 ) - { - // Try the name properly extensioned next (name.rom1) - Bios1 = Path::ReplaceExtension( Bios, ext ); - if( (filesize=Path::GetFileSize( Bios1 ) ) <= 0 ) - { - Console.Warning( L"Load Bios Warning: %s module not found, skipping... (this is not an error)", ext ); - return; - } - } - - // if we made it this far, we have a successful file found: - - wxFile fp( Bios1 ); - fp.Read( dest, min( maxSize, filesize ) ); -} - -// Loads the configured bios rom file into PS2 memory. PS2 memory must be allocated prior to -// this method being called. -// -// Remarks: -// This function does not fail if rom1, rom2, or erom files are missing, since none are -// explicitly required for most emulation tasks. -// -// Exceptions: -// FileNotFound - Thrown if the primary bios file (usually .bin) is not found. -// -void LoadBIOS() -{ - pxAssertDev( eeMem->ROM != NULL, "PS2 system memory has not been initialized yet." ); - - wxString Bios( g_Conf->FullpathToBios() ); - if( !g_Conf->BaseFilenames.Bios.IsOk() || g_Conf->BaseFilenames.Bios.IsDir() ) - throw Exception::BiosLoadFailed( Bios ); - - s64 filesize = Path::GetFileSize( Bios ); - if( filesize <= 0 ) - { - throw Exception::BiosLoadFailed( Bios ) - .SetDiagMsg(L"Configured BIOS file does not exist.") - .SetUserMsg(_("The configured BIOS file does not exist. Please re-configure.")); - } - - wxFile fp( Bios ); - fp.Read( eeMem->ROM, min( (s64)Ps2MemSize::Rom, filesize ) ); - - BiosVersion = GetBiosVersion(); - if( BiosVersion == -1 ) - { - throw Exception::BiosLoadFailed( Bios ) - .SetDiagMsg(L"Configured BIOS file is not a valid PS2 BIOS.") - .SetUserMsg(_("The configured BIOS file is not a valid PS2 BIOS. Please re-configure.")); - } - - Console.WriteLn("Bios Version %d.%d", BiosVersion >> 8, BiosVersion & 0xff); - - //injectIRX("host.irx"); //not fully tested; still buggy - - loadBiosRom( L"rom1", eeMem->ROM1, Ps2MemSize::Rom1 ); - loadBiosRom( L"rom2", eeMem->ROM2, Ps2MemSize::Rom2 ); - loadBiosRom( L"erom", eeMem->EROM, Ps2MemSize::ERom ); -} - -bool IsBIOS(const wxString& filename, wxString& description) -{ - uint fileOffset=0; - romdir rd; - - wxFileName Bios( g_Conf->Folders.Bios + filename ); - wxFile fp( Bios.GetFullPath() ); - - if( !fp.IsOpened() ) return FALSE; - - int biosFileSize = fp.Length(); - if( biosFileSize < 1024*4096) return FALSE; // valid bios must be at least 4mb. - - while( (fp.Tell() < 512*1024) && (fp.Read( &rd, DIRENTRY_SIZE ) == DIRENTRY_SIZE) ) - { - if (strcmp(rd.fileName, "RESET") == 0) - break; // found romdir - } - - if ((strcmp(rd.fileName, "RESET") != 0) || (rd.fileSize == 0)) - return FALSE; //Unable to locate ROMDIR structure in file or a ioprpXXX.img - - bool found = false; - while(strlen(rd.fileName) > 0) { - if (strcmp(rd.fileName, "ROMVER") == 0) // found romver + if (strcmp(rd.fileName, "ROMVER") == 0) { - char aROMVER[14+1]; // ascii version loaded from disk. + char romver[14+1]; // ascii version loaded from disk. - uint filepos = fp.Tell(); + wxFileOffset filetablepos = fp.Tell(); fp.Seek( fileOffset ); - if( fp.Read( &aROMVER, 14 ) == 0 ) break; - fp.Seek( filepos ); //go back + fp.Read( &romver, 14 ); + fp.Seek( filetablepos ); //go back - aROMVER[14] = 0; + romver[14] = 0; - const char zonefail[2] = { aROMVER[4], '\0' }; // the default "zone" (unknown code) + const char zonefail[2] = { romver[4], '\0' }; // the default "zone" (unknown code) const char* zone = zonefail; - switch(aROMVER[4]) + switch(romver[4]) { case 'T': zone = "T10K"; break; case 'X': zone = "Test"; break; @@ -230,39 +113,178 @@ bool IsBIOS(const wxString& filename, wxString& description) case 'C': zone = "China"; break; } - const wxString romver( fromUTF8(aROMVER) ); + char vermaj[3] = { romver[0], romver[1], 0 }; + char vermin[3] = { romver[2], romver[3], 0 }; - description.Printf( L"%-7s v%c%c.%c%c(%c%c/%c%c/%c%c%c%c) %s", - fromUTF8(zone).c_str(), - romver[0], romver[1], // ver major - romver[2], romver[3], // ver minor + FastFormatUnicode result; + result.Write( "%-7s v%s.%s(%c%c/%c%c/%c%c%c%c) %s", + zone, + vermaj, vermin, romver[12], romver[13], // day romver[10], romver[11], // month romver[6], romver[7], romver[8], romver[9], // year! - (aROMVER[5]=='C') ? L"Console" : (aROMVER[5]=='D') ? L"Devel" : wxEmptyString + (romver[5]=='C') ? "Console" : (romver[5]=='D') ? "Devel" : "" ); - found = true; + + version = strtol(vermaj, (char**)NULL, 0) << 8; + version|= strtol(vermin, (char**)NULL, 0); + + Console.WriteLn(L"Bios Found: %s", result.c_str()); + + description = result.c_str(); } - if ((rd.fileSize % 0x10)==0) + if ((rd.fileSize % 0x10) == 0) fileOffset += rd.fileSize; else fileOffset += (rd.fileSize + 0x10) & 0xfffffff0; - if (fp.Read( &rd, DIRENTRY_SIZE ) != DIRENTRY_SIZE) break; + fp.Read( rd ); } + fileOffset -= ((rd.fileSize + 0x10) & 0xfffffff0) - rd.fileSize; - if (found) + if (description.IsEmpty()) + throw Exception::BadStream( fp.GetStreamName() ) + .SetDiagMsg(L"BIOS version check failed: 'ROMDIR' tag could not be found.") + .SetUserMsg(_("The selected BIOS file is not a valid PS2 BIOS. Please re-configure.")); + + wxFileOffset fileSize = fp.Length(); + if (fileSize < (int)fileOffset) { - if ( biosFileSize < (int)fileOffset) + description += pxsFmt( L" %d%%", ((fileSize*100) / (int)fileOffset) ); + // we force users to have correct bioses, + // not that lame scph10000 of 513KB ;-) + } +} + +template< typename T, size_t _size > +void ChecksumIt( u32& result, const T (&srcdata)[_size] ) +{ + pxAssume( (_size & 3) == 0 ); + for( size_t i=0; i<_size/4; ++i ) + result ^= srcdata[i]; +} + +// Attempts to load a BIOS rom sub-component, by trying multiple combinations of base +// filename and extension. The bios specified in the user's configuration is used as +// the base. +// +// Parameters: +// ext - extension of the sub-component to load. Valid options are rom1, rom2, AND erom. +// +template< size_t _size > +static void LoadExtraRom( const wxChar* ext, u8 (&dest)[_size] ) +{ + wxString Bios1; + s64 filesize; + + // Try first a basic extension concatenation (normally results in something like name.bin.rom1) + const wxString Bios( g_Conf->FullpathToBios() ); + Bios1.Printf( L"%s.%s", Bios.c_str(), ext); + + try + { + if( (filesize=Path::GetFileSize( Bios1 ) ) <= 0 ) { - description += pxsFmt( L" %d%%", ((biosFileSize*100) / (int)fileOffset) ); - // we force users to have correct bioses, - // not that lame scph10000 of 513KB ;-) + // Try the name properly extensioned next (name.rom1) + Bios1 = Path::ReplaceExtension( Bios, ext ); + if( (filesize=Path::GetFileSize( Bios1 ) ) <= 0 ) + { + Console.WriteLn( Color_Gray, L"BIOS %s module not found, skipping...", ext ); + return; + } } - return true; + + // if we made it this far, we have a successful file found: + + wxFile fp( Bios1 ); + fp.Read( dest, std::min( _size, filesize ) ); + ChecksumIt( BiosChecksum, dest ); + } + catch (Exception::BadStream& ex) + { + // If any of the secondary roms fail,its a non-critical error. + // Log it, but don't make a big stink. 99% of games and stuff will + // still work fine. + + Console.Warning(L"BIOS Warning: %s could not be read (permission denied?)", ext); + Console.Indent().WriteLn(L"Details: %s", ex.FormatDiagnosticMessage()); + Console.Indent().WriteLn(L"File size: %llu", filesize); } - return false; //fail quietly +} + + +// Loads the configured bios rom file into PS2 memory. PS2 memory must be allocated prior to +// this method being called. +// +// Remarks: +// This function does not fail if rom1, rom2, or erom files are missing, since none are +// explicitly required for most emulation tasks. +// +// Exceptions: +// BadStream - Thrown if the primary bios file (usually .bin) is not found, corrupted, etc. +// +void LoadBIOS() +{ + pxAssertDev( eeMem->ROM != NULL, "PS2 system memory has not been initialized yet." ); + + try + { + wxString Bios( g_Conf->FullpathToBios() ); + if( !g_Conf->BaseFilenames.Bios.IsOk() || g_Conf->BaseFilenames.Bios.IsDir() ) + throw Exception::FileNotFound( Bios ) + .SetDiagMsg(L"BIOS has not been configured, or the configuration has been corrupted.") + .SetUserMsg(_("The PS2 BIOS could not be loaded. The BIOS has not been configured, or the configuration has been corrupted. Please re-configure.")); + + s64 filesize = Path::GetFileSize( Bios ); + if( filesize <= 0 ) + { + throw Exception::FileNotFound( Bios ) + .SetDiagMsg(L"Configured BIOS file does not exist, or has a file size of zero.") + .SetUserMsg(_("The configured BIOS file does not exist. Please re-configure.")); + } + + BiosChecksum = 0; + + wxFFile fp( Bios ); + fp.Read( eeMem->ROM, std::min( Ps2MemSize::Rom, filesize ) ); + + ChecksumIt( BiosChecksum, eeMem->ROM ); + + pxInputStream memfp( Bios, new wxMemoryInputStream( eeMem->ROM, sizeof(eeMem->ROM) ) ); + LoadBiosVersion( memfp, BiosVersion, BiosDescription ); + + //injectIRX("host.irx"); //not fully tested; still buggy + + LoadExtraRom( L"rom1", eeMem->ROM1 ); + LoadExtraRom( L"rom2", eeMem->ROM2 ); + LoadExtraRom( L"erom", eeMem->EROM ); + } + catch (Exception::BadStream& ex) + { + // Rethrow as a Bios Load Failure, so that the user interface handling the exceptions + // can respond to it appropriately. + throw Exception::BiosLoadFailed( ex.StreamName ) + .SetDiagMsg( ex.DiagMsg() ) + .SetUserMsg( ex.UserMsg() ); + } +} + +bool IsBIOS(const wxString& filename, wxString& description) +{ + wxFileName Bios( g_Conf->Folders.Bios + filename ); + pxInputStream inway( filename, new wxFFileInputStream( filename ) ); + + if (!inway.IsOk()) return false; + if (inway.Length() < 512*1024) return false; + + try { + u32 version; + LoadBiosVersion( inway, version, description ); + return true; + } catch( Exception::BadStream& ) { } + + return false; // fail quietly } diff --git a/pcsx2/ps2/BiosTools.h b/pcsx2/ps2/BiosTools.h index 14150b42c8..66d0656524 100644 --- a/pcsx2/ps2/BiosTools.h +++ b/pcsx2/ps2/BiosTools.h @@ -17,7 +17,7 @@ namespace Exception { - class BiosLoadFailed : public FileNotFound + class BiosLoadFailed : public BadStream { DEFINE_EXCEPTION_COPYTORS( BiosLoadFailed, FileNotFound ) DEFINE_EXCEPTION_MESSAGES( BiosLoadFailed ) @@ -29,6 +29,8 @@ namespace Exception } extern u32 BiosVersion; // Used by CDVD +extern u32 BiosChecksum; +extern wxString BiosDescription; extern void LoadBIOS(); extern bool IsBIOS(const wxString& filename, wxString& description); diff --git a/pcsx2/ps2/GIFpath.cpp b/pcsx2/ps2/GIFpath.cpp index bebe2c486a..9b2ebaac0d 100644 --- a/pcsx2/ps2/GIFpath.cpp +++ b/pcsx2/ps2/GIFpath.cpp @@ -897,25 +897,39 @@ __fi int GIFPath::CopyTag(const u128* pMem128, u32 size) case GIF_PATH_2: GSTransferStatus.PTH2 = STOPPED_MODE; break; - case GIF_PATH_3: + case GIF_PATH_3: //For huge chunks we may have delay problems, so we need to stall it till the interrupt, else we get desync (Lemmings) if(size > 8) GSTransferStatus.PTH3 = PENDINGSTOP_MODE; else GSTransferStatus.PTH3 = STOPPED_MODE; - if (gifch.chcr.STR) { //Make sure we are really doing a DMA and not using FIFO - //GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3); - gifch.madr += size * 16; - gifch.qwc -= size; - } break; } } - else if(pathidx == 2) + else if( nloop == 0) + { + //Need to set GIF as WAITING, sometimes it can get stuck in a bit of a loop if other paths think it's still doing REGLIST for example. + //Do NOT use IDLE mode here, it will freak Path3 masking out if it gets used. + switch(pathidx) + { + case GIF_PATH_1: + GSTransferStatus.PTH1 = WAITING_MODE; + break; + case GIF_PATH_2: + GSTransferStatus.PTH2 = WAITING_MODE; + break; + case GIF_PATH_3: + if(GSTransferStatus.PTH3 < IDLE_MODE) GSTransferStatus.PTH3 = WAITING_MODE; + break; + } + } + + if(pathidx == 2) { //if(nloop <= 16 && GSTransferStatus.PTH3 == IMAGE_MODE)GSTransferStatus.PTH3 = PENDINGIMAGE_MODE; if (gifch.chcr.STR) { //Make sure we are really doing a DMA and not using FIFO //GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3); gifch.madr += size * 16; gifch.qwc -= size; + hwDmacSrcTadrInc(gifch); } } diff --git a/pcsx2/ps2/LegacyDmac.cpp b/pcsx2/ps2/LegacyDmac.cpp index 51e1a1db70..1b22b79f3a 100644 --- a/pcsx2/ps2/LegacyDmac.cpp +++ b/pcsx2/ps2/LegacyDmac.cpp @@ -292,125 +292,151 @@ template< uint page > __fi bool dmacWrite32( u32 mem, mem32_t& value ) { iswitch(mem) { - icase(D0_CHCR) // dma0 - vif0 - { - DMA_LOG("VIF0dma EXECUTE, value=0x%x", value); - DmaExec(dmaVIF0, mem, value); - return false; - } - - icase(D1_CHCR) // dma1 - vif1 - chcr - { - DMA_LOG("VIF1dma EXECUTE, value=0x%x", value); - DmaExec(dmaVIF1, mem, value); - return false; - } - - icase(D2_CHCR) // dma2 - gif - { - DMA_LOG("GIFdma EXECUTE, value=0x%x", value); - DmaExec(dmaGIF, mem, value); - return false; - } - - icase(D3_CHCR) // dma3 - fromIPU - { - DMA_LOG("IPU0dma EXECUTE, value=0x%x\n", value); - DmaExec(dmaIPU0, mem, value); - return false; - } - - icase(D4_CHCR) // dma4 - toIPU - { - DMA_LOG("IPU1dma EXECUTE, value=0x%x\n", value); - DmaExec(dmaIPU1, mem, value); - return false; - } - - icase(D5_CHCR) // dma5 - sif0 - { - DMA_LOG("SIF0dma EXECUTE, value=0x%x", value); - DmaExec(dmaSIF0, mem, value); - return false; - } - - icase(D6_CHCR) // dma6 - sif1 - { - DMA_LOG("SIF1dma EXECUTE, value=0x%x", value); - DmaExec(dmaSIF1, mem, value); - return false; - } - - icase(D7_CHCR) // dma7 - sif2 - { - DMA_LOG("SIF2dma EXECUTE, value=0x%x", value); - DmaExec(dmaSIF2, mem, value); - return false; - } - - icase(D8_CHCR) // dma8 - fromSPR - { - DMA_LOG("SPR0dma EXECUTE (fromSPR), value=0x%x", value); - DmaExec(dmaSPR0, mem, value); - return false; - } - - icase(D9_CHCR) // dma9 - toSPR - { - DMA_LOG("SPR1dma EXECUTE (toSPR), value=0x%x", value); - DmaExec(dmaSPR1, mem, value); - return false; - } - - icase(DMAC_CTRL) - { - u32 oldvalue = psHu32(mem); - - HW_LOG("DMAC_CTRL Write 32bit %x", value); - - psHu32(mem) = value; - //Check for DMAS that were started while the DMAC was disabled - if (((oldvalue & 0x1) == 0) && ((value & 0x1) == 1)) + icase(D0_CHCR) // dma0 - vif0 { - if (!QueuedDMA.empty()) StartQueuedDMA(); + DMA_LOG("VIF0dma EXECUTE, value=0x%x", value); + DmaExec(dmaVIF0, mem, value); + return false; } - if ((oldvalue & 0x30) != (value & 0x30)) + + icase(D1_CHCR) // dma1 - vif1 - chcr { - DevCon.Warning("32bit Stall Source Changed to %x", (value & 0x30) >> 4); + DMA_LOG("VIF1dma EXECUTE, value=0x%x", value); + DmaExec(dmaVIF1, mem, value); + return false; } - if ((oldvalue & 0xC0) != (value & 0xC0)) + + icase(D2_CHCR) // dma2 - gif { - DevCon.Warning("32bit Stall Destination Changed to %x", (value & 0xC0) >> 4); + DMA_LOG("GIFdma EXECUTE, value=0x%x", value); + DmaExec(dmaGIF, mem, value); + return false; + } + + icase(D3_CHCR) // dma3 - fromIPU + { + DMA_LOG("IPU0dma EXECUTE, value=0x%x\n", value); + DmaExec(dmaIPU0, mem, value); + return false; + } + + icase(D4_CHCR) // dma4 - toIPU + { + DMA_LOG("IPU1dma EXECUTE, value=0x%x\n", value); + DmaExec(dmaIPU1, mem, value); + return false; + } + + icase(D5_CHCR) // dma5 - sif0 + { + DMA_LOG("SIF0dma EXECUTE, value=0x%x", value); + DmaExec(dmaSIF0, mem, value); + return false; + } + + icase(D6_CHCR) // dma6 - sif1 + { + DMA_LOG("SIF1dma EXECUTE, value=0x%x", value); + DmaExec(dmaSIF1, mem, value); + return false; + } + + icase(D7_CHCR) // dma7 - sif2 + { + DMA_LOG("SIF2dma EXECUTE, value=0x%x", value); + DmaExec(dmaSIF2, mem, value); + return false; + } + + icase(D8_CHCR) // dma8 - fromSPR + { + DMA_LOG("SPR0dma EXECUTE (fromSPR), value=0x%x", value); + DmaExec(dmaSPR0, mem, value); + return false; + } + + icase(D9_CHCR) // dma9 - toSPR + { + DMA_LOG("SPR1dma EXECUTE (toSPR), value=0x%x", value); + DmaExec(dmaSPR1, mem, value); + return false; + } + + icase(DMAC_CTRL) + { + u32 oldvalue = psHu32(mem); + + HW_LOG("DMAC_CTRL Write 32bit %x", value); + + psHu32(mem) = value; + //Check for DMAS that were started while the DMAC was disabled + if (((oldvalue & 0x1) == 0) && ((value & 0x1) == 1)) + { + if (!QueuedDMA.empty()) StartQueuedDMA(); + } + if ((oldvalue & 0x30) != (value & 0x30)) + { + DevCon.Warning("32bit Stall Source Changed to %x", (value & 0x30) >> 4); + } + if ((oldvalue & 0xC0) != (value & 0xC0)) + { + DevCon.Warning("32bit Stall Destination Changed to %x", (value & 0xC0) >> 4); + } + return false; + } + + //Midway are a bunch of idiots, writing to E100 (reserved) instead of E010 + //Which causes a CPCOND0 to fail. + icase(DMAC_FAKESTAT) + { + DevCon.Warning("Midway fixup addr=%x writing %x for DMA_STAT", mem, value); + HW_LOG("Midways own DMAC_STAT Write 32bit %x", value); + + // lower 16 bits: clear on 1 + // upper 16 bits: reverse on 1 + + psHu16(0xe010) &= ~(value & 0xffff); + psHu16(0xe012) ^= (u16)(value >> 16); + + cpuTestDMACInts(); + return false; + } + icase(DMAC_STAT) + { + HW_LOG("DMAC_STAT Write 32bit %x", value); + + // lower 16 bits: clear on 1 + // upper 16 bits: reverse on 1 + + psHu16(0xe010) &= ~(value & 0xffff); + psHu16(0xe012) ^= (u16)(value >> 16); + + cpuTestDMACInts(); + return false; + } + + icase(DMAC_ENABLEW) + { + HW_LOG("DMAC_ENABLEW Write 32bit %lx", value); + oldvalue = psHu8(DMAC_ENABLEW + 2); + psHu32(DMAC_ENABLEW) = value; + psHu32(DMAC_ENABLER) = value; + if (((oldvalue & 0x1) == 1) && (((value >> 16) & 0x1) == 0)) + { + if (!QueuedDMA.empty()) StartQueuedDMA(); + } + return false; } - return false; } - icase(DMAC_STAT) - { - HW_LOG("DMAC_STAT Write 32bit %x", value); - - // lower 16 bits: clear on 1 - // upper 16 bits: reverse on 1 - - psHu16(0xe010) &= ~(value & 0xffff); - psHu16(0xe012) ^= (u16)(value >> 16); - - cpuTestDMACInts(); - return false; - } - - icase(DMAC_ENABLEW) - { - HW_LOG("DMAC_ENABLEW Write 32bit %lx", value); - oldvalue = psHu8(DMAC_ENABLEW + 2); - psHu32(DMAC_ENABLEW) = value; - psHu32(DMAC_ENABLER) = value; - if (((oldvalue & 0x1) == 1) && (((value >> 16) & 0x1) == 0)) + //DMA Writes are invalid to everything except the STR on CHCR when it is busy + if((mem & 0xf0)) + { + if((psHu32(mem & ~0xff) & 0x100) && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER+2)) { - if (!QueuedDMA.empty()) StartQueuedDMA(); + DevCon.Warning("Write to DMA addr %x while STR is busy! Ignoring", mem); + return false; } - return false; - } } // fall-through: use the default writeback provided by caller. diff --git a/pcsx2/ps2/eeHwTraceLog.inl b/pcsx2/ps2/eeHwTraceLog.inl index 7f3fc8718b..4ac1f14c5e 100644 --- a/pcsx2/ps2/eeHwTraceLog.inl +++ b/pcsx2/ps2/eeHwTraceLog.inl @@ -133,6 +133,7 @@ static __ri const char* _eelog_GetHwName( u32 addr, T val ) EasyCase(VIF0_ASR1); EasyCase(VIF1_CHCR); + EasyCase(VIF1_MADR); EasyCase(VIF1_QWC); EasyCase(VIF1_TADR); EasyCase(VIF1_ASR0); diff --git a/pcsx2/vtlb.cpp b/pcsx2/vtlb.cpp index a7d9c35b85..5130ab1b8e 100644 --- a/pcsx2/vtlb.cpp +++ b/pcsx2/vtlb.cpp @@ -585,7 +585,7 @@ void vtlb_Core_Free() static wxString GetHostVmErrorMsg() { - return pxE(".Error:HostVmReserve", + return pxE("!Notice:HostVmReserve", L"Your system is too low on virtual resources for PCSX2 to run. This can be " L"caused by having a small or disabled swapfile, or by other programs that are " L"hogging resources." diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index c2011ce0c3..f2d5a73314 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -1996,14 +1996,6 @@ RelativePath="..\..\gui\Dialogs\AboutBoxDialog.cpp" > - - - - diff --git a/pcsx2/x86/ix86-32/iR5900Arit.cpp b/pcsx2/x86/ix86-32/iR5900Arit.cpp index d24859b860..258902389e 100644 --- a/pcsx2/x86/ix86-32/iR5900Arit.cpp +++ b/pcsx2/x86/ix86-32/iR5900Arit.cpp @@ -494,7 +494,7 @@ void recXOR_(int info) for (int i = 0; i < 2; i++) { if (rs == rt) { - xMOV(ptr32[&cpuRegs.GPR.r[_Rd_]], 0); + xMOV(ptr32[&cpuRegs.GPR.r[_Rd_].UL[i]], 0); } else if (_Rd_ == rs) { xMOV(eax, ptr32[&cpuRegs.GPR.r[rt].UL[i]]); xXOR(ptr32[&cpuRegs.GPR.r[_Rd_].UL[i]], eax); diff --git a/pcsx2/x86/microVU.cpp b/pcsx2/x86/microVU.cpp index a1bbaf3872..1f2a4a8013 100644 --- a/pcsx2/x86/microVU.cpp +++ b/pcsx2/x86/microVU.cpp @@ -148,8 +148,7 @@ void microVU::reset() { prog.x86end = z + ((cacheSize - mVUcacheSafeZone) * _1mb); for (u32 i = 0; i < (progSize / 2); i++) { - if (!prog.prog[i]) - { + if(!prog.prog[i]) { prog.prog[i] = new deque(); continue; } @@ -186,10 +185,10 @@ void microVU::close() { // Clears Block Data in specified range static __fi void mVUclear(mV, u32 addr, u32 size) { - if (!mVU->prog.cleared) { - memzero(mVU->prog.lpState); // Clear pipeline state + if(!mVU->prog.cleared) { mVU->prog.cleared = 1; // Next execution searches/creates a new microprogram - for (u32 i = 0; i < (mVU->progSize / 2); i++) { + memzero(mVU->prog.lpState); // Clear pipeline state + for(u32 i = 0; i < (mVU->progSize / 2); i++) { mVU->prog.quick[i].block = NULL; // Clear current quick-reference block mVU->prog.quick[i].prog = NULL; // Clear current quick-reference prog } @@ -225,10 +224,11 @@ _mVUt __fi microProgram* mVUcreateProg(int startPC) { prog->startPC = startPC; mVUcacheProg(*prog); // Cache Micro Program double cacheSize = (double)((u32)mVU->prog.x86end - (u32)mVU->prog.x86start); - double cacheUsed =((double)((u32)mVU->prog.x86ptr - (u32)mVU->prog.x86start)) / cacheSize * 100; + double cacheUsed =((double)((u32)mVU->prog.x86ptr - (u32)mVU->prog.x86start)) / (double)_1mb; + double cachePerc =((double)((u32)mVU->prog.x86ptr - (u32)mVU->prog.x86start)) / cacheSize * 100; ConsoleColors c = vuIndex ? Color_Orange : Color_Magenta; - DevCon.WriteLn(c, "microVU%d: Cached MicroPrograms = [%03d] [PC=%04x] [List=%02d] (Cache = %3.3f%%)", - vuIndex, prog->idx, startPC, mVU->prog.prog[startPC]->size()+1, cacheUsed); + DevCon.WriteLn(c, "microVU%d: Cached Prog = [%03d] [PC=%04x] [List=%02d] (Cache=%3.3f%%) [%3.1fmb]", + vuIndex, prog->idx, startPC*8, mVU->prog.prog[startPC]->size()+1, cachePerc, cacheUsed); return prog; } @@ -372,9 +372,11 @@ uint recMicroVU1::GetCacheReserve() const void recMicroVU0::SetCacheReserve( uint reserveInMegs ) const { - microVU0.cacheSize = reserveInMegs; + DevCon.WriteLn("microVU0: Upping cache size [%dmb]", reserveInMegs); + microVU0.cacheSize = min(reserveInMegs, mVUcacheMaxReserve); } void recMicroVU1::SetCacheReserve( uint reserveInMegs ) const { - microVU1.cacheSize = reserveInMegs; + DevCon.WriteLn("microVU1: Upping cache size [%dmb]", reserveInMegs); + microVU1.cacheSize = min(reserveInMegs, mVUcacheMaxReserve); } diff --git a/pcsx2/x86/microVU.h b/pcsx2/x86/microVU.h index ce33e897d3..141ec5661b 100644 --- a/pcsx2/x86/microVU.h +++ b/pcsx2/x86/microVU.h @@ -49,10 +49,9 @@ public: } ~microBlockManager() { reset(); } void reset() { - microBlockLink* linkI = blockList; - while( linkI != NULL ) - { + for(microBlockLink* linkI = blockList; linkI != NULL; ) { microBlockLink* freeI = linkI; + safe_delete_array(linkI->block.jumpCache); linkI = linkI->next; _aligned_free(freeI); } @@ -63,7 +62,8 @@ public: microBlock* thisBlock = search(&pBlock->pState); if (!thisBlock) { listI++; - microBlockLink* newBlock = (microBlockLink*)_aligned_malloc(sizeof(microBlockLink), 16); + microBlockLink* newBlock = (microBlockLink*)_aligned_malloc(sizeof(microBlockLink), 16); + newBlock->block.jumpCache = NULL; newBlock->next = NULL; if (blockEnd) { @@ -149,8 +149,10 @@ struct microProgManager { microRegInfo lpState; // Pipeline state from where program left off (useful for continuing execution) }; -static const uint mVUdispCacheSize = __pagesize; // Dispatcher Cache Size (in bytes) -static const uint mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes) +static const uint mVUdispCacheSize = __pagesize; // Dispatcher Cache Size (in bytes) +static const uint mVUcacheSafeZone = 3; // Safe-Zone for program recompilation (in megabytes) +static const uint mVUcacheInitReserve = 64; // Initial Reserve Cache Size (in megabytes) +static const uint mVUcacheMaxReserve = 128; // Max Reserve Cache Size (in megabytes) struct microVU { @@ -196,7 +198,7 @@ struct microVU { __fi VECTOR& getVF(uint reg) const { return regs().VF[reg]; } - __fi s16 Imm5() const { return ((code & 0x400) ? 0xfff0 : 0) | ((code >> 6) & 0xf); } + __fi s16 Imm5() const { return ((code & 0x400) ? 0xfff0 : 0) | ((code >> 6) & 0xf); } __fi s32 Imm11() const { return (code & 0x400) ? (0xfffffc00 | (code & 0x3ff)) : (code & 0x3ff); } __fi u32 Imm12() const { return (((code >> 21) & 0x1) << 11) | (code & 0x7ff); } __fi u32 Imm15() const { return ((code >> 10) & 0x7800) | (code & 0x7ff); } @@ -225,7 +227,7 @@ struct microVU { microVU() { - cacheSize = 64; + cacheSize = mVUcacheInitReserve; cache = NULL; dispCache = NULL; startFunct = NULL; @@ -248,7 +250,7 @@ int mVUdebugNow = 0; // Main Functions static void mVUclear(mV, u32, u32); static void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState); -_mVUt extern void* __fastcall mVUcompileJIT(u32 startPC, uptr pState); +_mVUt extern void* __fastcall mVUcompileJIT(u32 startPC, uptr ptr); // Prototypes for Linux extern void __fastcall mVUcleanUpVU0(); diff --git a/pcsx2/x86/microVU_Branch.inl b/pcsx2/x86/microVU_Branch.inl index ad33e339cb..02af126158 100644 --- a/pcsx2/x86/microVU_Branch.inl +++ b/pcsx2/x86/microVU_Branch.inl @@ -108,9 +108,14 @@ void normJumpCompile(mV, microFlagCycles& mFC, bool isEvilJump) { mVUsetupBranch(mVU, mFC); mVUbackupRegs(mVU); - if (isEvilJump) xMOV(gprT2, ptr32[&mVU->evilBranch]); - else xMOV(gprT2, ptr32[&mVU->branch]); - xMOV(gprT3, (uptr)&mVUpBlock->pStateEnd); + if(!mVUpBlock->jumpCache) { // Create the jump cache for this block + mVUpBlock->jumpCache = new microJumpCache[mProgSize/2]; + } + + if (isEvilJump) xMOV(gprT2, ptr32[&mVU->evilBranch]); + else xMOV(gprT2, ptr32[&mVU->branch]); + if (doJumpCaching) xMOV(gprT3, (uptr)mVUpBlock); + else xMOV(gprT3, (uptr)&mVUpBlock->pStateEnd); if (!mVU->index) xCALL(mVUcompileJIT<0>); //(u32 startPC, uptr pState) else xCALL(mVUcompileJIT<1>); diff --git a/pcsx2/x86/microVU_Compile.inl b/pcsx2/x86/microVU_Compile.inl index 2805856ab7..66de449577 100644 --- a/pcsx2/x86/microVU_Compile.inl +++ b/pcsx2/x86/microVU_Compile.inl @@ -513,7 +513,19 @@ static __fi void* mVUblockFetch(microVU* mVU, u32 startPC, uptr pState) { } // mVUcompileJIT() - Called By JR/JALR during execution -_mVUt void* __fastcall mVUcompileJIT(u32 startPC, uptr pState) { - //return mVUblockFetch(mVUx, startPC, pState); - return mVUsearchProg(startPC, pState); // Find and set correct program +_mVUt void* __fastcall mVUcompileJIT(u32 startPC, uptr ptr) { + if (doJumpCaching) { // When doJumpCaching, ptr is a microBlock pointer + microVU* mVU = mVUx; + microBlock* pBlock = (microBlock*)ptr; + microJumpCache& jc = pBlock->jumpCache[startPC/8]; + if (jc.prog && jc.prog == mVU->prog.quick[startPC/8].prog) return jc.x86ptrStart; + void* v = mVUsearchProg(startPC, (uptr)&pBlock->pStateEnd); + jc.prog = mVU->prog.quick[startPC/8].prog; + jc.x86ptrStart = v; + return v; + } + else { // When !doJumpCaching, pBlock param is really a microRegInfo pointer + //return mVUblockFetch(mVUx, startPC, ptr); + return mVUsearchProg(startPC, ptr); // Find and set correct program + } } diff --git a/pcsx2/x86/microVU_IR.h b/pcsx2/x86/microVU_IR.h index 3828a776a0..93a4b1a23c 100644 --- a/pcsx2/x86/microVU_IR.h +++ b/pcsx2/x86/microVU_IR.h @@ -62,10 +62,18 @@ union __aligned16 microRegInfo { C_ASSERT(sizeof(microRegInfo) == 160); +struct microProgram; +struct microJumpCache { + microJumpCache() : prog(NULL), x86ptrStart(NULL) {} + microProgram* prog; // Program to which the entry point below is part of + void* x86ptrStart; // Start of code (Entry point for block) +}; + struct __aligned16 microBlock { - microRegInfo pState; // Detailed State of Pipeline - microRegInfo pStateEnd; // Detailed State of Pipeline at End of Block (needed by JR/JALR opcodes) - u8* x86ptrStart; // Start of code + microRegInfo pState; // Detailed State of Pipeline + microRegInfo pStateEnd; // Detailed State of Pipeline at End of Block (needed by JR/JALR opcodes) + u8* x86ptrStart; // Start of code (Entry point for block) + microJumpCache* jumpCache; // Will point to an array of entry points of size [16k/8] if block ends in JR/JALR }; struct microTempRegInfo { diff --git a/pcsx2/x86/microVU_Lower.inl b/pcsx2/x86/microVU_Lower.inl index f2a74b7d91..6832e5a134 100644 --- a/pcsx2/x86/microVU_Lower.inl +++ b/pcsx2/x86/microVU_Lower.inl @@ -1097,8 +1097,17 @@ void __fastcall mVU_XGKICK_(u32 addr) { u8* data = vuRegs[1].Mem + (addr*16); u32 diff = 0x400 - addr; u32 size; + + /////////////////////////////////////////////// + ///////////////SIGNAL WARNING!!//////////////// + /////////////////////////////////////////////// + /* Due to the face SIGNAL can cause the loop + to leave early, we can end up missing data. + The only way we can avoid this is to queue + it :(, im relying on someone else to come + up with a better solution! */ - if(gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.APATH == GIF_APATH3 && gifRegs.stat.IP3 == true) && SIGNAL_IMR_Pending == false) + /*if(gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.APATH == GIF_APATH3 && gifRegs.stat.IP3 == true) && SIGNAL_IMR_Pending == false) { if(Path1WritePos != 0) { @@ -1116,7 +1125,7 @@ void __fastcall mVU_XGKICK_(u32 addr) { } } else - { + {*/ //DevCon.Warning("GIF APATH busy %x Holding for later W %x, R %x", gifRegs.stat.APATH, Path1WritePos, Path1ReadPos); size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff); u8* pDest = &Path1Buffer[Path1WritePos*16]; @@ -1136,7 +1145,8 @@ void __fastcall mVU_XGKICK_(u32 addr) { } //if(!gifRegs.stat.P1Q) CPU_INT(28, 128); gifRegs.stat.P1Q = true; - } + //} + gsPath1Interrupt(); } static __fi void mVU_XGKICK_DELAY(mV, bool memVI) { diff --git a/pcsx2/x86/microVU_Misc.h b/pcsx2/x86/microVU_Misc.h index ff6b1b40e0..5e29579f99 100644 --- a/pcsx2/x86/microVU_Misc.h +++ b/pcsx2/x86/microVU_Misc.h @@ -265,6 +265,13 @@ static const bool doConstProp = 0; // Set to 1 to turn on vi15 const propagation // allowing us to know many indirect jump target addresses. // Makes GoW a lot slower due to extra recompilation time and extra code-gen! +// Indirect Jump Caching +static const bool doJumpCaching = 1; // Set to 1 to enable jump caching +// Indirect jumps (JR/JALR) will remember the entry points to their previously +// jumped-to addresses. This allows us to skip the microBlockManager::search() +// routine that is performed every indirect jump in order to find a block within a +// program that matches the correct pipeline state. + //------------------------------------------------------------------ // Speed Hacks (can cause infinite loops, SPS, Black Screens, etc...) //------------------------------------------------------------------ diff --git a/pcsx2/x86/newVif_Dynarec.cpp b/pcsx2/x86/newVif_Dynarec.cpp index d5656b2292..ecf814dfb1 100644 --- a/pcsx2/x86/newVif_Dynarec.cpp +++ b/pcsx2/x86/newVif_Dynarec.cpp @@ -204,7 +204,7 @@ _vifT static __fi u8* dVifsetVUptr(uint cl, uint wl, bool isFill) { u8* startmem = VU.Mem + (vif.tag.addr & (vuMemLimit-0x10)); u8* endmem = VU.Mem + vuMemLimit; - uint length = _vBlock.num * 16; + uint length = (_vBlock.num > 0) ? (_vBlock.num * 16) : 4096; // 0 = 256 if (!isFill) { // Accounting for skipping mode: Subtract the last skip cycle, since the skipped part of the run diff --git a/pcsx2/x86/sVU_Lower.cpp b/pcsx2/x86/sVU_Lower.cpp index 9e1294964f..95096cd74e 100644 --- a/pcsx2/x86/sVU_Lower.cpp +++ b/pcsx2/x86/sVU_Lower.cpp @@ -1982,7 +1982,17 @@ void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) u32 size; u8* pDest; - if(gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.APATH == GIF_APATH3 && gifRegs.stat.IP3 == true) && SIGNAL_IMR_Pending == false) + /////////////////////////////////////////////// + ///////////////SIGNAL WARNING!!//////////////// + /////////////////////////////////////////////// + /* Due to the face SIGNAL can cause the loop + to leave early, we can end up missing data. + The only way we can avoid this is to queue + it :(, im relying on someone else to come + up with a better solution! */ + + + /*if(gifRegs.stat.APATH <= GIF_APATH1 || (gifRegs.stat.APATH == GIF_APATH3 && gifRegs.stat.IP3 == true) && SIGNAL_IMR_Pending == false) { if(Path1WritePos != 0) { @@ -2000,7 +2010,7 @@ void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) } } else - { + {*/ //DevCon.Warning("GIF APATH busy %x Holding for later W %x, R %x", gifRegs.stat.APATH, Path1WritePos, Path1ReadPos); size = GIFPath_ParseTagQuick(GIF_PATH_1, data, diff); pDest = &Path1Buffer[Path1WritePos*16]; @@ -2019,8 +2029,7 @@ void __fastcall VU1XGKICK_MTGSTransfer(u32 *pMem, u32 addr) } //if(!gifRegs.stat.P1Q) CPU_INT(28, 128); gifRegs.stat.P1Q = true; - } - - + //} + gsPath1Interrupt(); } //------------------------------------------------------------------ diff --git a/pcsx2/x86/sVU_zerorec.cpp b/pcsx2/x86/sVU_zerorec.cpp index ff0b03f4ff..576f6890f4 100644 --- a/pcsx2/x86/sVU_zerorec.cpp +++ b/pcsx2/x86/sVU_zerorec.cpp @@ -359,7 +359,7 @@ static void SuperVUAlloc(int vuindex) safe_delete(s_recVUMem[vuindex]); throw Exception::VirtualMemoryMapConflict( s_recVUMem[vuindex]->GetName() ) .SetDiagMsg(pxsFmt( L"SuperVU failed to allocate virtual memory below 256MB." )) - .SetUserMsg(pxE( ".Error:superVU:VirtualMemoryAlloc", + .SetUserMsg(pxE( "!Notice:superVU:VirtualMemoryAlloc", L"Out of Memory (sorta): The SuperVU recompiler was unable to reserve the specific memory " L"ranges required, and will not be available for use. This is not a critical error, since " L"the sVU rec is obsolete, and you should use microVU instead anyway. :)" diff --git a/plugins/FWnull/Linux/FWnull.cbp b/plugins/FWnull/Linux/FWnull.cbp index 572b5391e7..61614cd2b3 100644 --- a/plugins/FWnull/Linux/FWnull.cbp +++ b/plugins/FWnull/Linux/FWnull.cbp @@ -16,7 +16,7 @@ - - - @@ -356,10 +352,22 @@ RelativePath="..\zpipe.cpp" > + + + + + + @@ -413,10 +421,18 @@ RelativePath="..\GifTransfer.h" > + + + + @@ -481,14 +497,34 @@ RelativePath="..\zerogs.h" > + + + + + + + + + + @@ -501,6 +537,14 @@ RelativePath="..\ZZoglShaders.h" > + + + + +#endif + +// Local Clut buffer: +// It supports both 32 bits and 16 bits colors formats. The size of the buffer is 1KBytes. +// The 16 bits entries are arranged in 2 columns. One row is a 32 bits colors. +// 256 0 +// 271 1 +// ... .. +// 510 254 +// 511 255 +// +// CSA -> clut buffer offset: +// 16 bits format: CSA < 32 <=> 16 entries, 16 half-row of the buffer (for example 0 to 15) +// 32 bits format: CSA < 16 <=> 16 entries, 16 full row of the buffer (for example 256|0 to 271|15) + +static const __aligned16 int s_clut_16bits_mask[4] = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; + +template +__forceinline T* GetClutBufferAddress(u32 csa) { } + +template <> +__forceinline u32* GetClutBufferAddress(u32 csa) +{ + return (u32*)(g_pbyGSClut + 64 * (csa & 15)); +} + +template <> +__forceinline u16* GetClutBufferAddress(u32 csa) +{ + return (u16*)(g_pbyGSClut + 64 * (csa & 15) + (csa >= 16 ? 2 : 0)); +} + +/* ***************************************************************** + * Local memory -> Clut buffer + * *****************************************************************/ + +#ifdef ZEROGS_SSE2 +__forceinline void GSMem_to_ClutBuffer__T32_I8_CSM1_sse2(u32* vm, u32 csa) +{ + u32* clut = GetClutBufferAddress(csa); + + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + for (int j = 0; j < 64; j += 32, src += 32, dst += 32) + { + for (int i = 0; i < 16; i += 4) + { + __m128i r0 = _mm_load_si128(&src[i+0]); + __m128i r1 = _mm_load_si128(&src[i+1]); + __m128i r2 = _mm_load_si128(&src[i+2]); + __m128i r3 = _mm_load_si128(&src[i+3]); + + _mm_store_si128(&dst[i*2+0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[i*2+2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[i*2+3], _mm_unpackhi_epi64(r2, r3)); + + __m128i r4 = _mm_load_si128(&src[i+0+16]); + __m128i r5 = _mm_load_si128(&src[i+1+16]); + __m128i r6 = _mm_load_si128(&src[i+2+16]); + __m128i r7 = _mm_load_si128(&src[i+3+16]); + + _mm_store_si128(&dst[i*2+4], _mm_unpacklo_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+5], _mm_unpacklo_epi64(r6, r7)); + _mm_store_si128(&dst[i*2+6], _mm_unpackhi_epi64(r4, r5)); + _mm_store_si128(&dst[i*2+7], _mm_unpackhi_epi64(r6, r7)); + } + } +} + +__forceinline void GSMem_to_ClutBuffer__T32_I4_CSM1_sse2(u32* vm, u32 csa) +{ + u32* clut = GetClutBufferAddress(csa); + + __m128i* src = (__m128i*)vm; + __m128i* dst = (__m128i*)clut; + + __m128i r0 = _mm_load_si128(&src[0]); + __m128i r1 = _mm_load_si128(&src[1]); + __m128i r2 = _mm_load_si128(&src[2]); + __m128i r3 = _mm_load_si128(&src[3]); + + _mm_store_si128(&dst[0], _mm_unpacklo_epi64(r0, r1)); + _mm_store_si128(&dst[1], _mm_unpacklo_epi64(r2, r3)); + _mm_store_si128(&dst[2], _mm_unpackhi_epi64(r0, r1)); + _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); +} + + +template +__forceinline void GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(u32* vm, u32* clut) +{ + __m128i vm_0; + __m128i vm_1; + __m128i vm_2; + __m128i vm_3; + __m128i clut_0; + __m128i clut_1; + __m128i clut_2; + __m128i clut_3; + + __m128i clut_mask = _mm_load_si128((__m128i*)s_clut_16bits_mask); + + // !HIGH_16BITS_VM + // CSA in 0-15 + // Replace lower 16 bits of clut with lower 16 bits of vm + // CSA in 16-31 + // Replace higher 16 bits of clut with lower 16 bits of vm + + // HIGH_16BITS_VM + // CSA in 0-15 + // Replace lower 16 bits of clut with higher 16 bits of vm + // CSA in 16-31 + // Replace higher 16 bits of clut with higher 16 bits of vm + if(HIGH_16BITS_VM && CSA_0_15) { + // move up to low + vm_0 = _mm_load_si128((__m128i*)vm); // 9 8 1 0 + vm_1 = _mm_load_si128((__m128i*)vm+1); // 11 10 3 2 + vm_2 = _mm_load_si128((__m128i*)vm+2); // 13 12 5 4 + vm_3 = _mm_load_si128((__m128i*)vm+3); // 15 14 7 6 + vm_0 = _mm_srli_epi32(vm_0, 16); + vm_1 = _mm_srli_epi32(vm_1, 16); + vm_2 = _mm_srli_epi32(vm_2, 16); + vm_3 = _mm_srli_epi32(vm_3, 16); + } else if(HIGH_16BITS_VM && !CSA_0_15) { + // Remove lower 16 bits + vm_0 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)vm)); // 9 8 1 0 + vm_1 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)vm+1)); // 11 10 3 2 + vm_2 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)vm+2)); // 13 12 5 4 + vm_3 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)vm+3)); // 15 14 7 6 + } else if(!HIGH_16BITS_VM && CSA_0_15) { + // Remove higher 16 bits + vm_0 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)vm)); // 9 8 1 0 + vm_1 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)vm+1)); // 11 10 3 2 + vm_2 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)vm+2)); // 13 12 5 4 + vm_3 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)vm+3)); // 15 14 7 6 + } else if(!HIGH_16BITS_VM && !CSA_0_15) { + // move low to high + vm_0 = _mm_load_si128((__m128i*)vm); // 9 8 1 0 + vm_1 = _mm_load_si128((__m128i*)vm+1); // 11 10 3 2 + vm_2 = _mm_load_si128((__m128i*)vm+2); // 13 12 5 4 + vm_3 = _mm_load_si128((__m128i*)vm+3); // 15 14 7 6 + vm_0 = _mm_slli_epi32(vm_0, 16); + vm_1 = _mm_slli_epi32(vm_1, 16); + vm_2 = _mm_slli_epi32(vm_2, 16); + vm_3 = _mm_slli_epi32(vm_3, 16); + } + + // Unsizzle the data + __m128i row_0 = _mm_unpacklo_epi64(vm_0, vm_1); // 3 2 1 0 + __m128i row_1 = _mm_unpacklo_epi64(vm_2, vm_3); // 7 6 5 4 + __m128i row_2 = _mm_unpackhi_epi64(vm_0, vm_1); // 11 10 9 8 + __m128i row_3 = _mm_unpackhi_epi64(vm_2, vm_3); // 15 14 13 12 + + // load old data & remove useless part + if(CSA_0_15) { + // Remove lower 16 bits + clut_0 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut)); + clut_1 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+1)); + clut_2 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+2)); + clut_3 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+3)); + } else { + // Remove higher 16 bits + clut_0 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut)); + clut_1 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+1)); + clut_2 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+2)); + clut_3 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+3)); + } + + // Merge old & new data + clut_0 = _mm_or_si128(clut_0, row_0); + clut_1 = _mm_or_si128(clut_1, row_1); + clut_2 = _mm_or_si128(clut_2, row_2); + clut_3 = _mm_or_si128(clut_3, row_3); + + _mm_store_si128((__m128i*)clut, clut_0); + _mm_store_si128((__m128i*)clut+1, clut_1); + _mm_store_si128((__m128i*)clut+2, clut_2); + _mm_store_si128((__m128i*)clut+3, clut_3); +} + +__forceinline void GSMem_to_ClutBuffer__T16_I4_CSM1_sse2(u32* vm, u32 csa) +{ + u32* clut = GetClutBufferAddress(csa); // Keep aligned version for sse2 + + if (csa > 15) { + GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(vm, clut); + } else { + GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(vm, clut); + } +} + +__forceinline void GSMem_to_ClutBuffer__T16_I8_CSM1_sse2(u32* vm, u32 csa) +{ + // update the right clut column (csa < 16) + u32* clut = GetClutBufferAddress(csa); // Keep aligned version for sse2 + + u32 csa_right = (csa < 16) ? 16 - csa : 0; + + for(int i = (csa_right/2); i > 0 ; --i) { + GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + vm += 16; // go down one column + } + + // update the left clut column + u32 csa_left = (csa >= 16) ? 16 : csa; + + // In case csa_right is odd (so csa_left is also odd), we cross the clut column + if(csa_right & 0x1) { + GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(vm, clut); + // go back to the base before processing left clut column + clut = GetClutBufferAddress(0); // Keep aligned version for sse2 + + GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + vm += 16; // go down one column + } else if(csa_right != 0) { + // go back to the base before processing left clut column + clut = GetClutBufferAddress(0); // Keep aligned version for sse2 + + } + + for(int i = (csa_left/2); i > 0 ; --i) { + GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + GSMem_to_ClutBuffer__T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + vm += 16; // go down one column + } +} + +#endif // ZEROGS_SSE2 + +__forceinline void GSMem_to_ClutBuffer__T16_I8_CSM1_c(u32* _vm, u32 csa) +{ + const static u32 map[] = + { + 0, 2, 8, 10, 16, 18, 24, 26, + 4, 6, 12, 14, 20, 22, 28, 30, + 1, 3, 9, 11, 17, 19, 25, 27, + 5, 7, 13, 15, 21, 23, 29, 31 + }; + + u16* vm = (u16*)_vm; + u16* clut = GetClutBufferAddress(csa); + + int left = ((u32)(uptr)clut & 2) ? 512 : 512 - (((u32)(uptr)clut) & 0x3ff) / 2; + + for (int j = 0; j < 8; j++, vm += 32, clut += 64, left -= 32) + { + if (left == 32) + { + assert(left == 32); + + for (int i = 0; i < 16; i++) + clut[2*i] = vm[map[i]]; + + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + + for (int i = 16; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + else + { + if (left == 0) + { + clut = (u16*)((uptr)clut & ~0x3ff) + 1; + left = -1; + } + + for (int i = 0; i < 32; i++) + clut[2*i] = vm[map[i]]; + } + } +} + +__forceinline void GSMem_to_ClutBuffer__T32_I8_CSM1_c(u32* vm, u32 csa) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)GetClutBufferAddress(csa); + + for (int j = 0; j < 2; j++, src += 32) + { + for (int i = 0; i < 4; i++, dst += 16, src += 8) + { + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; + + dst[8] = src[32]; + dst[9] = src[32+2]; + dst[10] = src[32+4]; + dst[11] = src[32+6]; + dst[12] = src[32+1]; + dst[13] = src[32+3]; + dst[14] = src[32+5]; + dst[15] = src[32+7]; + } + } +} + +__forceinline void GSMem_to_ClutBuffer__T16_I4_CSM1_c(u32* _vm, u32 csa) +{ + u16* dst = GetClutBufferAddress(csa); + u16* src = (u16*)_vm; + + dst[0] = src[0]; + dst[2] = src[2]; + dst[4] = src[8]; + dst[6] = src[10]; + dst[8] = src[16]; + dst[10] = src[18]; + dst[12] = src[24]; + dst[14] = src[26]; + dst[16] = src[4]; + dst[18] = src[6]; + dst[20] = src[12]; + dst[22] = src[14]; + dst[24] = src[20]; + dst[26] = src[22]; + dst[28] = src[28]; + dst[30] = src[30]; +} + +__forceinline void GSMem_to_ClutBuffer__T32_I4_CSM1_c(u32* vm, u32 csa) +{ + u64* src = (u64*)vm; + u64* dst = (u64*)GetClutBufferAddress(csa); + + dst[0] = src[0]; + dst[1] = src[2]; + dst[2] = src[4]; + dst[3] = src[6]; + dst[4] = src[1]; + dst[5] = src[3]; + dst[6] = src[5]; + dst[7] = src[7]; +} + +// Main GSmem to Clutbuffer function +/*__forceinline*/ void GSMem_to_ClutBuffer(tex0Info &tex0) +{ + int entries = PSMT_IS8CLUT(tex0.psm) ? 256 : 16; + + u8* _src = g_pbyGSMemory + 256 * tex0.cbp; + + if (tex0.csm) + { + switch (tex0.cpsm) + { + // 16bit psm + // eggomania uses non16bit textures for csm2 + + case PSMCT16: + { + u16* src = (u16*)_src; + u16 *dst = GetClutBufferAddress(tex0.csa); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)dst & 0x3ff) == 0) dst = GetClutBufferAddress(16); + } + break; + } + + case PSMCT16S: + { + u16* src = (u16*)_src; + u16 *dst = GetClutBufferAddress(tex0.csa); + + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst += 2; + + // check for wrapping + if (((u32)dst & 0x3ff) == 0) dst = GetClutBufferAddress(16); + } + break; + } + + case PSMCT32: + case PSMCT24: + { + u32* src = (u32*)_src; + u32 *dst = GetClutBufferAddress(tex0.csa); + + // check if address exceeds src + + if (src + getPixelAddress32_0(gs.clut.cou + entries - 1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000) + ZZLog::Error_Log("texClutWrite out of bounds."); + else + for (int i = 0; i < entries; ++i) + { + *dst = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; + dst++; + } + break; + } + + default: + { + //ZZLog::Debug_Log("Unknown cpsm: %x (%x).", tex0.cpsm, tex0.psm); + break; + } + } + } + else + { + u32* src = (u32*)_src; + + if (entries == 16) + { + if (tex0.cpsm < 2) { +#ifdef ZEROGS_SSE2 + GSMem_to_ClutBuffer__T32_I4_CSM1_sse2(src, tex0.csa); +#else + GSMem_to_ClutBuffer__T32_I4_CSM1_c(src, tex0.csa); +#endif + } else { +#ifdef ZEROGS_SSE2 + GSMem_to_ClutBuffer__T16_I4_CSM1_sse2(src, tex0.csa); +#else + GSMem_to_ClutBuffer__T16_I4_CSM1_c(src, tex0.csa); +#endif + } + } + else + { + if (tex0.cpsm < 2) { +#ifdef ZEROGS_SSE2 + GSMem_to_ClutBuffer__T32_I8_CSM1_sse2(src, tex0.csa); +#else + GSMem_to_ClutBuffer__T32_I8_CSM1_c(src, tex0.csa); +#endif + } else { +#ifdef ZEROGS_SSE2 + GSMem_to_ClutBuffer__T16_I8_CSM1_sse2(src, tex0.csa); +#else + GSMem_to_ClutBuffer__T16_I8_CSM1_c(src, tex0.csa); +#endif + } + + } + } +} + +/* ***************************************************************** + * Clut buffer -> local C array (linear) + * *****************************************************************/ +template +/*__forceinline*/ void ClutBuffer_to_Array(T* dst, u32 csa, u32 clutsize) {} + +template <> +/*__forceinline*/ void ClutBuffer_to_Array(u32* dst, u32 csa, u32 clutsize) +{ + u8* clut = (u8*)GetClutBufferAddress(csa); + memcpy_amd((u8*)dst, clut, clutsize); +} + +template <> +/*__forceinline*/ void ClutBuffer_to_Array(u16* dst, u32 csa, u32 clutsize) +{ + u16* clut = (u16*)GetClutBufferAddress(csa); // Keep aligned version for sse2 + + // which side to copy + u32 clutsize_right; + u32 clutsize_left; + if (csa < 16) { + clutsize_right = min(clutsize, (16-csa)*64); + clutsize_left = clutsize - clutsize_right; + } else { + clutsize_right = 0; + clutsize_left = clutsize; + } + + while (clutsize_right > 0) + { +#ifdef ZEROGS_SSE2 + // only lower 16 bits of dword are valid + __m128i clut_0 = _mm_load_si128((__m128i*)clut); + __m128i clut_1 = _mm_load_si128((__m128i*)clut+1); + __m128i clut_2 = _mm_load_si128((__m128i*)clut+2); + __m128i clut_3 = _mm_load_si128((__m128i*)clut+3); + + clut_0 = _mm_shufflelo_epi16(clut_0, 0x88); + clut_1 = _mm_shufflelo_epi16(clut_1, 0x88); + clut_2 = _mm_shufflelo_epi16(clut_2, 0x88); + clut_3 = _mm_shufflelo_epi16(clut_3, 0x88); + + clut_0 = _mm_shufflehi_epi16(clut_0, 0x88); // - - 3 2 1 0 - - + clut_1 = _mm_shufflehi_epi16(clut_1, 0x88); + clut_2 = _mm_shufflehi_epi16(clut_2, 0x88); + clut_3 = _mm_shufflehi_epi16(clut_3, 0x88); + + clut_0 = _mm_srli_si128(clut_0, 4); + clut_1 = _mm_srli_si128(clut_1, 4); + clut_2 = _mm_srli_si128(clut_2, 4); + clut_3 = _mm_srli_si128(clut_3, 4); + + _mm_store_si128((__m128i*)dst, _mm_unpacklo_epi64(clut_0, clut_1)); + _mm_store_si128((__m128i*)dst+1, _mm_unpacklo_epi64(clut_2, clut_3)); +#else + for(int i = 0; i < 16; ++i) + dst[i] = clut[2*i]; +#endif + + dst += 16; + clut += 32; + clutsize_right -= 32; + } + + if(csa < 16) { + // go back to the base before processing left clut column + clut = (u16*)GetClutBufferAddress(0); // Keep aligned version for sse2 + } + + while (clutsize_left > 0) + { +#ifdef ZEROGS_SSE2 + // only higher 16 bits of dword are valid + __m128i clut_0 = _mm_load_si128((__m128i*)clut); + __m128i clut_1 = _mm_load_si128((__m128i*)clut+1); + __m128i clut_2 = _mm_load_si128((__m128i*)clut+2); + __m128i clut_3 = _mm_load_si128((__m128i*)clut+3); + + clut_0 = _mm_shufflelo_epi16(clut_0, 0x88); + clut_1 = _mm_shufflelo_epi16(clut_1, 0x88); + clut_2 = _mm_shufflelo_epi16(clut_2, 0x88); + clut_3 = _mm_shufflelo_epi16(clut_3, 0x88); + + clut_0 = _mm_shufflehi_epi16(clut_0, 0x88); // - - 3 2 1 0 - - + clut_1 = _mm_shufflehi_epi16(clut_1, 0x88); + clut_2 = _mm_shufflehi_epi16(clut_2, 0x88); + clut_3 = _mm_shufflehi_epi16(clut_3, 0x88); + + clut_0 = _mm_srli_si128(clut_0, 4); + clut_1 = _mm_srli_si128(clut_1, 4); + clut_2 = _mm_srli_si128(clut_2, 4); + clut_3 = _mm_srli_si128(clut_3, 4); + + _mm_store_si128((__m128i*)dst, _mm_unpacklo_epi64(clut_0, clut_1)); + _mm_store_si128((__m128i*)dst+1, _mm_unpacklo_epi64(clut_2, clut_3)); +#else + // Note +1 because we change higher 16 bits + for(int i = 0; i < 16; ++i) + dst[i] = clut[2*i]; +#endif + + dst += 16; + clut += 32; + clutsize_left -= 32; + } +} + +/* ***************************************************************** + * Compare: Clut buffer <-> Local Memory + * *****************************************************************/ +// false -> identical +// true -> different +template +/*__forceinline*/ bool Cmp_ClutBuffer_GSMem(T* GSmem, u32 csa, u32 clutsize); + +template <> +/*__forceinline*/ bool Cmp_ClutBuffer_GSMem(u32* GSmem, u32 csa, u32 clutsize) +{ + u64* _GSmem = (u64*) GSmem; + u64* clut = (u64*)GetClutBufferAddress(csa); + + while(clutsize > 0) { +#ifdef ZEROGS_SSE2 + // Note: local memory datas are swizzles + __m128i GSmem_0 = _mm_load_si128((__m128i*)_GSmem); // 9 8 1 0 + __m128i GSmem_1 = _mm_load_si128((__m128i*)_GSmem+1); // 11 10 3 2 + __m128i GSmem_2 = _mm_load_si128((__m128i*)_GSmem+2); // 13 12 5 4 + __m128i GSmem_3 = _mm_load_si128((__m128i*)_GSmem+3); // 15 14 7 6 + + __m128i clut_0 = _mm_load_si128((__m128i*)clut); + __m128i clut_1 = _mm_load_si128((__m128i*)clut+1); + __m128i clut_2 = _mm_load_si128((__m128i*)clut+2); + __m128i clut_3 = _mm_load_si128((__m128i*)clut+3); + + __m128i result = _mm_cmpeq_epi32(_mm_unpacklo_epi64(GSmem_0, GSmem_1), clut_0); + + __m128i result_tmp = _mm_cmpeq_epi32(_mm_unpacklo_epi64(GSmem_2, GSmem_3), clut_1); + result = _mm_and_si128(result, result_tmp); + + result_tmp = _mm_cmpeq_epi32(_mm_unpackhi_epi64(GSmem_0, GSmem_1), clut_2); + result = _mm_and_si128(result, result_tmp); + + result_tmp = _mm_cmpeq_epi32(_mm_unpackhi_epi64(GSmem_2, GSmem_3), clut_3); + result = _mm_and_si128(result, result_tmp); + + u32 result_int = _mm_movemask_epi8(result); + if (result_int != 0xFFFF) + return true; +#else + // I see no point to keep an mmx version. SSE2 versions is probably faster. + // Keep a slow portable C version for reference/debug + // Note: local memory datas are swizzles + if (clut[0] != _GSmem[0] || clut[1] != _GSmem[2] || clut[2] != _GSmem[4] || clut[3] != _GSmem[6] + || clut[4] != _GSmem[1] || clut[5] != _GSmem[3] || clut[6] != _GSmem[5] || clut[7] != _GSmem[7]) + return true; +#endif + + // go to the next memory block + _GSmem += 32; + + // go back to the previous memory block then down one memory column + if (clutsize & 0x40) { + _GSmem -= (64-8); + } + // In case previous operation (down one column) cross the block boundary + // Go to the next block + if (clutsize == 0x240) { + _GSmem += 32; + } + + clut += 8; + clutsize -= 64; + } + + return false; +} + +#ifdef ZEROGS_SSE2 +template +__forceinline bool Cmp_ClutBuffer_GSMem_core(u16* GSmem, u16* clut) +{ + __m128i GSmem_0; + __m128i GSmem_1; + __m128i GSmem_2; + __m128i GSmem_3; + __m128i clut_0; + __m128i clut_1; + __m128i clut_2; + __m128i clut_3; + + __m128i clut_mask = _mm_load_si128((__m128i*)s_clut_16bits_mask); + + // !HIGH_16BITS_VM + // CSA in 0-15 + // cmp lower 16 bits of clut with lower 16 bits of GSmem + // CSA in 16-31 + // cmp higher 16 bits of clut with lower 16 bits of GSmem + + // HIGH_16BITS_VM + // CSA in 0-15 + // cmp lower 16 bits of clut with higher 16 bits of GSmem + // CSA in 16-31 + // cmp higher 16 bits of clut with higher 16 bits of GSmem + if(HIGH_16BITS_VM && CSA_0_15) { + // move up to low + GSmem_0 = _mm_load_si128((__m128i*)GSmem); // 9 8 1 0 + GSmem_1 = _mm_load_si128((__m128i*)GSmem+1); // 11 10 3 2 + GSmem_2 = _mm_load_si128((__m128i*)GSmem+2); // 13 12 5 4 + GSmem_3 = _mm_load_si128((__m128i*)GSmem+3); // 15 14 7 6 + GSmem_0 = _mm_srli_epi32(GSmem_0, 16); + GSmem_1 = _mm_srli_epi32(GSmem_1, 16); + GSmem_2 = _mm_srli_epi32(GSmem_2, 16); + GSmem_3 = _mm_srli_epi32(GSmem_3, 16); + } else if(HIGH_16BITS_VM && !CSA_0_15) { + // Remove lower 16 bits + GSmem_0 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)GSmem)); // 9 8 1 0 + GSmem_1 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)GSmem+1)); // 11 10 3 2 + GSmem_2 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)GSmem+2)); // 13 12 5 4 + GSmem_3 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)GSmem+3)); // 15 14 7 6 + } else if(!HIGH_16BITS_VM && CSA_0_15) { + // Remove higher 16 bits + GSmem_0 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)GSmem)); // 9 8 1 0 + GSmem_1 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)GSmem+1)); // 11 10 3 2 + GSmem_2 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)GSmem+2)); // 13 12 5 4 + GSmem_3 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)GSmem+3)); // 15 14 7 6 + } else if(!HIGH_16BITS_VM && !CSA_0_15) { + // move low to high + GSmem_0 = _mm_load_si128((__m128i*)GSmem); // 9 8 1 0 + GSmem_1 = _mm_load_si128((__m128i*)GSmem+1); // 11 10 3 2 + GSmem_2 = _mm_load_si128((__m128i*)GSmem+2); // 13 12 5 4 + GSmem_3 = _mm_load_si128((__m128i*)GSmem+3); // 15 14 7 6 + GSmem_0 = _mm_slli_epi32(GSmem_0, 16); + GSmem_1 = _mm_slli_epi32(GSmem_1, 16); + GSmem_2 = _mm_slli_epi32(GSmem_2, 16); + GSmem_3 = _mm_slli_epi32(GSmem_3, 16); + } + + // Unsizzle the data + __m128i row_0 = _mm_unpacklo_epi64(GSmem_0, GSmem_1); // 3 2 1 0 + __m128i row_1 = _mm_unpacklo_epi64(GSmem_2, GSmem_3); // 7 6 5 4 + __m128i row_2 = _mm_unpackhi_epi64(GSmem_0, GSmem_1); // 11 10 9 8 + __m128i row_3 = _mm_unpackhi_epi64(GSmem_2, GSmem_3); // 15 14 13 12 + + // load old data & remove useless part + if(!CSA_0_15) { + // Remove lower 16 bits + clut_0 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut)); + clut_1 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+1)); + clut_2 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+2)); + clut_3 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+3)); + } else { + // Remove higher 16 bits + clut_0 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut)); + clut_1 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+1)); + clut_2 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+2)); + clut_3 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+3)); + } + + // Do the comparaison + __m128i result = _mm_cmpeq_epi16(row_0, clut_0); + __m128i result_tmp = _mm_cmpeq_epi16(row_1, clut_1); + result = _mm_and_si128(result, result_tmp); + + result_tmp = _mm_cmpeq_epi16(row_2, clut_2); + result = _mm_and_si128(result, result_tmp); + + result_tmp = _mm_cmpeq_epi16(row_3, clut_3); + result = _mm_and_si128(result, result_tmp); + + u32 result_int = _mm_movemask_epi8(result); + if(CSA_0_15) { + // only lower 16bits must be checked + if ((result_int&0x3333) != 0x3333) + return true; + } else { + // only higher 16bits must be checked + if ((result_int&0xCCCC) != 0xCCCC) + return true; + } + + return false; +} +#endif + +template <> +/*__forceinline*/ bool Cmp_ClutBuffer_GSMem(u16* GSmem, u32 csa, u32 clutsize) +{ +#ifdef ZEROGS_SSE2 + u16* clut = (u16*)GetClutBufferAddress(csa); // Keep aligned version for sse2 + + // Special case only one CSA block to check + if(clutsize == 32) { + if (csa < 16) + return Cmp_ClutBuffer_GSMem_core(GSmem, clut); + else + return Cmp_ClutBuffer_GSMem_core(GSmem, clut); + } + + // which side to cmp + s32 clutsize_right; // Note clutsize_right could be negative ! + u32 clutsize_left; + if (csa < 16) { + // the '-32' is a trick to handle easily when csa is odd + clutsize_right = min(clutsize, (16-csa)*32) -32; + clutsize_left = clutsize - clutsize_right; + } else { + clutsize_right = 0; + clutsize_left = clutsize; + } + + while(clutsize_right > 0) { + if (Cmp_ClutBuffer_GSMem_core(GSmem, clut)) + return true; + clut += 32; + + if (Cmp_ClutBuffer_GSMem_core(GSmem, clut)) + return true; + clut += 32; + + GSmem += 32; // go down one column + clutsize_right -= 64; + } + + if(csa < 16) { + // because of the extra -32, csa_righ is null when csa is odd + if (clutsize_right == 0) { + // cross the clut + if (Cmp_ClutBuffer_GSMem_core(GSmem, clut)) + return true; + clut += 32; + + if (Cmp_ClutBuffer_GSMem_core(GSmem, clut)) + return true; + + GSmem += 32; // go down one column + clutsize_left -= 32; + } + + // go back to the base before processing left clut column + clut = (u16*)GetClutBufferAddress(0); // Keep aligned version for sse2 + } + + while(clutsize_left > 0) { + if (Cmp_ClutBuffer_GSMem_core(GSmem, clut)) + return true; + clut += 32; + + if (Cmp_ClutBuffer_GSMem_core(GSmem, clut)) + return true; + clut += 32; + + GSmem += 32; // go down one column + clutsize_left -= 64; + } + + return false; +#else + // This function is only useful for performance. So just return + // for a plain c build + return true; +#endif +} + +/* ***************************************************************** + * Compare: Clut buffer <-> local C array (linear) + * *****************************************************************/ +// false -> identical +// true -> different +template +/*__forceinline*/ bool Cmp_ClutBuffer_SavedClut(T* saved_clut, u32 csa, u32 clutsize); + +template <> +/*__forceinline*/ bool Cmp_ClutBuffer_SavedClut(u32* saved_clut, u32 csa, u32 clutsize) +{ + u32* clut = GetClutBufferAddress(csa); + return !!memcmp_mmx(saved_clut, clut, clutsize); +} + +template <> +/*__forceinline*/ bool Cmp_ClutBuffer_SavedClut(u16* saved_clut, u32 csa, u32 clutsize) +{ + assert((clutsize&31) == 0); + +#ifdef ZEROGS_SSE2 + __m128i zero_128 = _mm_setzero_si128(); +#endif + u16* clut = (u16*)GetClutBufferAddress(csa); // Keep aligned version for sse2 + + // which side to cmp + u32 clutsize_right; + u32 clutsize_left; + if (csa < 16) { + clutsize_right = min(clutsize, (16-csa)*32); + clutsize_left = clutsize - clutsize_right; + } else { + clutsize_right = 0; + clutsize_left = clutsize; + } + + while (clutsize_right > 0) + { +#ifdef ZEROGS_SSE2 + // only lower 16 bits of dword are valid + __m128i clut_0 = _mm_load_si128((__m128i*)clut); + __m128i clut_1 = _mm_load_si128((__m128i*)clut+1); + __m128i clut_2 = _mm_load_si128((__m128i*)clut+2); + __m128i clut_3 = _mm_load_si128((__m128i*)clut+3); + + // value must converted to 32 bits + __m128i saved_clut_0 = _mm_load_si128((__m128i*)saved_clut); + __m128i saved_clut_1 = _mm_load_si128((__m128i*)saved_clut+1); + + __m128i result = _mm_cmpeq_epi16(_mm_unpacklo_epi16(saved_clut_0, zero_128), clut_0); + __m128i result_tmp = _mm_cmpeq_epi16(_mm_unpackhi_epi16(saved_clut_0, zero_128), clut_1); + result = _mm_and_si128(result, result_tmp); + + result_tmp = _mm_cmpeq_epi16(_mm_unpacklo_epi16(saved_clut_1, zero_128), clut_2); + result = _mm_and_si128(result, result_tmp); + + result_tmp = _mm_cmpeq_epi16(_mm_unpackhi_epi16(saved_clut_1, zero_128), clut_3); + result = _mm_and_si128(result, result_tmp); + + u32 result_int = _mm_movemask_epi8(result); + // only lower 16bits must be checked + if ((result_int&0x3333) != 0x3333) + return true; +#else + for (int i = 0; i < 16; ++i) + if (saved_clut[i] != clut[2*i]) return true; +#endif + + saved_clut += 16; + clut += 32; + clutsize_right -= 32; + } + + if(csa < 16) { + // go back to the base before processing left clut column + clut = (u16*)GetClutBufferAddress(0); // Keep aligned version for sse2 + } + + while (clutsize_left > 0) + { +#ifdef ZEROGS_SSE2 + // only higher 16 bits of dword are valid + __m128i clut_0 = _mm_load_si128((__m128i*)clut); + __m128i clut_1 = _mm_load_si128((__m128i*)clut+1); + __m128i clut_2 = _mm_load_si128((__m128i*)clut+2); + __m128i clut_3 = _mm_load_si128((__m128i*)clut+3); + + // value must converted to 32 bits (with 0 in lower 16 bits) + __m128i saved_clut_0 = _mm_load_si128((__m128i*)saved_clut); + __m128i saved_clut_1 = _mm_load_si128((__m128i*)saved_clut+1); + + __m128i result = _mm_cmpeq_epi16(_mm_unpacklo_epi16(zero_128, saved_clut_0), clut_0); + __m128i result_tmp = _mm_cmpeq_epi16(_mm_unpackhi_epi16(zero_128, saved_clut_0), clut_1); + result = _mm_and_si128(result, result_tmp); + + result_tmp = _mm_cmpeq_epi16(_mm_unpacklo_epi16(zero_128, saved_clut_1), clut_2); + result = _mm_and_si128(result, result_tmp); + + result_tmp = _mm_cmpeq_epi16(_mm_unpackhi_epi16(zero_128, saved_clut_1), clut_3); + result = _mm_and_si128(result, result_tmp); + + u32 result_int = _mm_movemask_epi8(result); + // only higher 16bits must be checked + if ((result_int&0xCCCC) != 0xCCCC) + return true; +#else + // Note +1 because we change higher 16 bits + for (int i = 0; i < 16; ++i) + if (saved_clut[i] != clut[2*i+1]) return true; +#endif + + saved_clut += 16; + clut += 32; + clutsize_left -= 32; + } + + return false; +} + + +/* ***************************************************************** + * Resolve color of clut texture + * *****************************************************************/ + +// used to build clut textures (note that this is for both 16 and 32 bit cluts) +template +/*__forceinline*/ void Build_Clut_Texture(u32 psm, u32 height, T* pclut, u8* psrc, T* pdst) +{ + switch (psm) + { + case PSMT8: + for (u32 i = 0; i < height; ++i) + { + for (int j = 0; j < GPU_TEXWIDTH / 2; ++j) + { + pdst[0] = pclut[psrc[0]]; + pdst[1] = pclut[psrc[1]]; + pdst[2] = pclut[psrc[2]]; + pdst[3] = pclut[psrc[3]]; + pdst[4] = pclut[psrc[4]]; + pdst[5] = pclut[psrc[5]]; + pdst[6] = pclut[psrc[6]]; + pdst[7] = pclut[psrc[7]]; + pdst += 8; + psrc += 8; + } + } + break; + + case PSMT4: + for (u32 i = 0; i < height; ++i) + { + for (int j = 0; j < GPU_TEXWIDTH; ++j) + { + pdst[0] = pclut[psrc[0] & 15]; + pdst[1] = pclut[psrc[0] >> 4]; + pdst[2] = pclut[psrc[1] & 15]; + pdst[3] = pclut[psrc[1] >> 4]; + pdst[4] = pclut[psrc[2] & 15]; + pdst[5] = pclut[psrc[2] >> 4]; + pdst[6] = pclut[psrc[3] & 15]; + pdst[7] = pclut[psrc[3] >> 4]; + + pdst += 8; + psrc += 4; + } + } + break; + + case PSMT8H: + for (u32 i = 0; i < height; ++i) + { + for (int j = 0; j < GPU_TEXWIDTH / 8; ++j) + { + pdst[0] = pclut[psrc[3]]; + pdst[1] = pclut[psrc[7]]; + pdst[2] = pclut[psrc[11]]; + pdst[3] = pclut[psrc[15]]; + pdst[4] = pclut[psrc[19]]; + pdst[5] = pclut[psrc[23]]; + pdst[6] = pclut[psrc[27]]; + pdst[7] = pclut[psrc[31]]; + pdst += 8; + psrc += 32; + } + } + break; + + case PSMT4HH: + for (u32 i = 0; i < height; ++i) + { + for (int j = 0; j < GPU_TEXWIDTH / 8; ++j) + { + pdst[0] = pclut[psrc[3] >> 4]; + pdst[1] = pclut[psrc[7] >> 4]; + pdst[2] = pclut[psrc[11] >> 4]; + pdst[3] = pclut[psrc[15] >> 4]; + pdst[4] = pclut[psrc[19] >> 4]; + pdst[5] = pclut[psrc[23] >> 4]; + pdst[6] = pclut[psrc[27] >> 4]; + pdst[7] = pclut[psrc[31] >> 4]; + pdst += 8; + psrc += 32; + } + } + break; + + case PSMT4HL: + for (u32 i = 0; i < height; ++i) + { + for (int j = 0; j < GPU_TEXWIDTH / 8; ++j) + { + pdst[0] = pclut[psrc[3] & 15]; + pdst[1] = pclut[psrc[7] & 15]; + pdst[2] = pclut[psrc[11] & 15]; + pdst[3] = pclut[psrc[15] & 15]; + pdst[4] = pclut[psrc[19] & 15]; + pdst[5] = pclut[psrc[23] & 15]; + pdst[6] = pclut[psrc[27] & 15]; + pdst[7] = pclut[psrc[31] & 15]; + pdst += 8; + psrc += 32; + } + } + break; + + default: + assert(0); + } +} + +// Instantiate the Build_Clut_Texture template... +template void Build_Clut_Texture(u32 psm, u32 height, u32* pclut, u8* psrc, u32* pdst); +template void Build_Clut_Texture(u32 psm, u32 height, u16* pclut, u8* psrc, u16* pdst); diff --git a/plugins/zzogl-pg/opengl/ZZClut.h b/plugins/zzogl-pg/opengl/ZZClut.h new file mode 100644 index 0000000000..f2b0428ca6 --- /dev/null +++ b/plugins/zzogl-pg/opengl/ZZClut.h @@ -0,0 +1,30 @@ +/* ZZ Open GL graphics plugin + * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CLUT_H_INCLUDED +#define CLUT_H_INCLUDED + +extern void GSMem_to_ClutBuffer(tex0Info &tex0); +template extern void ClutBuffer_to_Array(T* dst, u32 csa, u32 clutsize); +template extern void Build_Clut_Texture(u32 psm, u32 height, T* pclut, u8* psrc, T* pdst); + +template extern bool Cmp_ClutBuffer_GSMem(T* GSmem, u32 csa, u32 clutsize); +template extern bool Cmp_ClutBuffer_SavedClut(T* saved_clut, u32 csa, u32 clutsize); + +#endif // CLUT_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/ZZGl.h b/plugins/zzogl-pg/opengl/ZZGl.h index 3ebd2e8da3..3b7f148ade 100644 --- a/plugins/zzogl-pg/opengl/ZZGl.h +++ b/plugins/zzogl-pg/opengl/ZZGl.h @@ -1,135 +1,133 @@ -/* ZZ Open GL graphics plugin - * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com - * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - +/* ZZ Open GL graphics plugin + * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + #ifndef ZZGL_H_INCLUDED #define ZZGL_H_INCLUDED -#include "PS2Etypes.h" -#include "PS2Edefs.h" - -// Need this before gl.h -#ifdef _WIN32 - -#include -#include -#include -#include "glprocs.h" - -#else - -// adding glew support instead of glXGetProcAddress (thanks to scaught) -#include -#include -#include -#include - -inline void* wglGetProcAddress(const char* x) -{ - return (void*)glXGetProcAddress((const GLubyte*)x); -} - -#endif - -extern u32 s_stencilfunc, s_stencilref, s_stencilmask; -// Defines - -#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils -# define GL_DEPTH_STENCIL_EXT 0x84F9 -# define GL_UNSIGNED_INT_24_8_EXT 0x84FA -# define GL_DEPTH24_STENCIL8_EXT 0x88F0 -# define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 -#endif - -#define GL_STENCILFUNC(func, ref, mask) { \ - s_stencilfunc = func; \ - s_stencilref = ref; \ - s_stencilmask = mask; \ - glStencilFunc(func, ref, mask); \ -} - -#define GL_STENCILFUNC_SET() glStencilFunc(s_stencilfunc, s_stencilref, s_stencilmask) - - -// sets the data stream -#define SET_STREAM() { \ - glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)8); \ - glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); \ - glTexCoordPointer(3, GL_FLOAT, sizeof(VertexGPU), (void*)16); \ - glVertexPointer(4, GL_SHORT, sizeof(VertexGPU), (void*)0); \ -} - - -// global alpha blending settings -extern GLenum g_internalRGBAFloat16Fmt; - -extern const GLenum primtype[8]; - -#define SAFE_RELEASE_TEX(x) { if( (x) != 0 ) { glDeleteTextures(1, &(x)); x = 0; } } - -// inline for an extremely often used sequence -// This is turning off all gl functions. Safe to do updates. -inline void DisableAllgl() -{ - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - glDisable(GL_ALPHA_TEST); - glDisable(GL_DEPTH_TEST); - glDepthMask(0); - glDisable(GL_STENCIL_TEST); - glColorMask(1, 1, 1, 1); -} - -//--------------------- Dummies - -#ifdef _WIN32 -extern void (__stdcall *zgsBlendEquationSeparateEXT)(GLenum, GLenum); -extern void (__stdcall *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum); -#else -extern void (APIENTRY *zgsBlendEquationSeparateEXT)(GLenum, GLenum); -extern void (APIENTRY *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum); -#endif - - -// ------------------------ Types ------------------------- - -///////////////////// -// graphics resources -extern GLenum s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha; // set by zgsBlendFuncSeparateEXT - -// GL prototypes -extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; -extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; -extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; -extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; -extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; -extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; -extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; -extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; -extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; -extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; -extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; -extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; -extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; -extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; -extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; -extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; -extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; -extern PFNGLDRAWBUFFERSPROC glDrawBuffers; +#include "PS2Etypes.h" +#include "PS2Edefs.h" + +// Need this before gl.h +#ifdef _WIN32 + +#include +#include +#include +#include "glprocs.h" + +#else + +// adding glew support instead of glXGetProcAddress (thanks to scaught) +#include +#include +#include +#include + +inline void* wglGetProcAddress(const char* x) +{ + return (void*)glXGetProcAddress((const GLubyte*)x); +} + +#endif + +extern u32 s_stencilfunc, s_stencilref, s_stencilmask; +// Defines + +#ifndef GL_DEPTH24_STENCIL8_EXT // allows FBOs to support stencils +# define GL_DEPTH_STENCIL_EXT 0x84F9 +# define GL_UNSIGNED_INT_24_8_EXT 0x84FA +# define GL_DEPTH24_STENCIL8_EXT 0x88F0 +# define GL_TEXTURE_STENCIL_SIZE_EXT 0x88F1 +#endif + +#define GL_STENCILFUNC(func, ref, mask) { \ + s_stencilfunc = func; \ + s_stencilref = ref; \ + s_stencilmask = mask; \ + glStencilFunc(func, ref, mask); \ +} + +#define GL_STENCILFUNC_SET() glStencilFunc(s_stencilfunc, s_stencilref, s_stencilmask) + + +// sets the data stream +#define SET_STREAM() { \ + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)8); \ + glSecondaryColorPointerEXT(4, GL_UNSIGNED_BYTE, sizeof(VertexGPU), (void*)12); \ + glTexCoordPointer(3, GL_FLOAT, sizeof(VertexGPU), (void*)16); \ + glVertexPointer(4, GL_SHORT, sizeof(VertexGPU), (void*)0); \ +} + + +// global alpha blending settings +extern GLenum g_internalRGBAFloat16Fmt; + +#define SAFE_RELEASE_TEX(x) { if( (x) != 0 ) { glDeleteTextures(1, &(x)); x = 0; } } + +// inline for an extremely often used sequence +// This is turning off all gl functions. Safe to do updates. +inline void DisableAllgl() +{ + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDisable(GL_ALPHA_TEST); + glDisable(GL_DEPTH_TEST); + glDepthMask(0); + glDisable(GL_STENCIL_TEST); + glColorMask(1, 1, 1, 1); +} + +//--------------------- Dummies + +#ifdef _WIN32 +extern void (__stdcall *zgsBlendEquationSeparateEXT)(GLenum, GLenum); +extern void (__stdcall *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum); +#else +extern void (APIENTRY *zgsBlendEquationSeparateEXT)(GLenum, GLenum); +extern void (APIENTRY *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum); +#endif + + +// ------------------------ Types ------------------------- + +///////////////////// +// graphics resources +extern GLenum s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha; // set by zgsBlendFuncSeparateEXT + +// GL prototypes +extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT; +extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT; +extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT; +extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT; +extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT; +extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT; +extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT; +extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT; +extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT; +extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT; +extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT; +extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT; +extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT; +extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT; +extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT; +extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT; +extern PFNGLDRAWBUFFERSPROC glDrawBuffers; #endif // ZZGL_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/ZZHacks.cpp b/plugins/zzogl-pg/opengl/ZZHacks.cpp new file mode 100644 index 0000000000..183f0fa894 --- /dev/null +++ b/plugins/zzogl-pg/opengl/ZZHacks.cpp @@ -0,0 +1,186 @@ +/* ZZ Open GL graphics plugin + * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + + #include "Util.h" + #include "ZZHacks.h" + #include "ZZLog.h" + +int CurrentHack = 0; + +// A list of what bit controls each of the current hacks. +u32 hackList[HACK_NUMBER] = +{ + 0, // No hack + 1, //GAME_TEXTURETARGS, + 2, //GAME_AUTORESET, + 3, //GAME_INTERLACE2X, + 4, //GAME_TEXAHACK, + 5, //GAME_NOTARGETRESOLVE, + 6, //GAME_EXACTCOLOR, + //7 //GAME_NOCOLORCLAMP, + //8 //GAME_FFXHACK, + 9, //GAME_NOALPHAFAIL, + 10, //GAME_NODEPTHUPDATE, + 11, //GAME_QUICKRESOLVE1, + 12, //GAME_NOQUICKRESOLVE, + 13, //GAME_NOTARGETCLUT, + 14, //GAME_NOSTENCIL, + 15, //GAME_NODEPTHRESOLVE, + 16, //GAME_FULL16BITRES, + 17, //GAME_RESOLVEPROMOTED, + 18, //GAME_FASTUPDATE, + 19, //GAME_NOALPHATEST, + 20, //GAME_DISABLEMRTDEPTH, + //21 //GAME_32BITTARGS, + //22 //GAME_PATH3HACK, + //23 //GAME_DOPARALLELCTX, + 24, //GAME_XENOSPECHACK, + //25 //GAME_PARTIALPOINTERS, + 26, //GAME_PARTIALDEPTH, + 27, //GAME_REGETHACK, + 28, //GAME_GUSTHACK, + 29, //GAME_NOLOGZ, + 30, //GAME_AUTOSKIPDRAW +}; + + +char hackDesc[32][64] = +{ + "No hack", + "Texture targs", + "Auto reset", + "Interlace 2x", + "Texa", + "No target resolve", + "Exact color", + "No color clamp", + "Final Fantasy X", + "No alpha fail", + "No depth update", + "Quick resolve 1", + "No Quick resolve", + "No target clut", + "No stencil", + "VSS", + "No depth resolve", + "Full 16 bit resolution", + "Resolve promoted", + "Fast update", + "No alpha test", + "Disable mrt depth", + "Args 32 bit", + "", + "Parallel context", + "Xenosaga spec", + "Partial pointers", + "Partial depth", + "Reget", + "Gust", + "No logz", + "Automatic skip draw" +}; + +struct hacks +{ + bool enabled; + char shortDesc[64]; + char longDesc[256]; +}; + +hacks hack_list[32] = +{ + { true, "No hack", "No hack" }, + { true, "Texture targs", "Tex Target checking - 00000001\nLego Racers" }, + { true, "Auto reset", "Auto reset targs - 00000002\nUse when game is slow and toggling AA fixes it. Samurai Warriors. (Automatically on for Shadow Hearts)" }, + { true, "Interlace 2x", "Interlace 2X - 00000004\nFixes 2x bigger screen. Gradius 3." }, + { false, "Texa", "" }, + { true, "No target resolve", "No target resolves - 00000010\nStops all resolving of targets. Try this first for really slow games. (Automatically on for Dark Cloud 1.)" }, + { true, "Exact color", "Exact color testing - 00000020\nFixes overbright or shadow/black artifacts. Crash 'n Burn." }, + { false, "No color clamp", "No color clamping - 00000040\nSpeeds up games, but might be too bright or too dim." }, + { false, "Final Fantasy X", "" }, + { false, "No alpha fail", "Alpha Fail hack - 00000100\nRemove vertical stripes or other coloring artifacts. Breaks Persona 4 and MGS3. (Automatically on for Sonic Unleashed, Shadow the Hedgehog, & Ghost in the Shell.)" }, + { true, "No depth update", "Disable depth updates - 00000200" }, + { true, "Quick resolve 1", "Resolve Hack #1 - 00000400\n Speeds some games. Kingdom Hearts."}, + { true, "No Quick resolve", "Resolve Hack #2 - 00000800\nShadow Hearts, Urbz. Destroys FFX."}, + { true, "No target clut", "No target CLUT - 00001000\nResident Evil 4, or foggy scenes." }, + { true, "No stencil", "Disable stencil buffer - 00002000\nUsually safe to do for simple scenes. Harvest Moon." }, + { false, "VSS", "" }, + { true, "No depth resolve", "No depth resolve - 00008000\nMight give z buffer artifacts." }, + { true, "Full 16 bit resolution", "Full 16 bit resolution - 00010000\nUse when half the screen is missing." }, + { true, "Resolve promoted", "Resolve Hack #3 - 00020000\nNeopets" }, + { true, "Fast update", "Fast Update - 00040000\n Speeds some games. Needed for Sonic Unleashed. Okami." }, + { true, "No alpha test", "Disable alpha testing - 00080000" }, + { true, "Disable mrt depth", "Enable Multiple RTs - 00100000" }, + { false, "Args 32 bit", "" }, + { false, "Path3", "" }, + { false, "Parallel context", "" }, + { true, "Xenosaga spec", "Specular Highlights - 01000000\nMakes graphics faster by removing highlights. (Automatically on for Xenosaga, Okami, & Okage.)" }, + { false, "Partial pointers", "Partial targets - 02000000" }, + { true, "Partial depth", "Partial depth - 04000000" }, + { false, "Reget", "" }, + { true, "Gust", "Gust fix - 10000000. Makes gust games cleaner and faster. (Automatically on for most Gust games)" }, + { true, "No logz", "No logarithmic Z - 20000000. Could decrease number of Z-artifacts." }, + { true, "Automatic skip draw", "Remove blur effect on some games\nSlow games." } +}; + +void ReportHacks(gameHacks hacks) +{ + for(int i = 0; i < 32; i++) + { + if (hacks._u32 & (1 << i)) + { + ZZLog::WriteLn("'%s' hack enabled.", hackDesc[i+1]); + } + } +} + +void ListHacks() +{ + if ((!conf.disableHacks) && (conf.def_hacks._u32 != 0)) + { + ZZLog::WriteLn("Auto-enabling these hacks:"); + ReportHacks(conf.def_hacks); + } + + if (conf.hacks._u32 != 0) + { + ZZLog::WriteLn("You've manually enabled these hacks:"); + ReportHacks(conf.hacks); + } +} + +void DisplayHack(int hack) +{ + ZZLog::WriteToScreen2("***%d %s", hack, hackDesc[hackList[hack]]); +} + +void ChangeCurrentHack(int hack) +{ + FUNCLOG + + conf.hacks._u32 &= !(hackList[CurrentHack]); + conf.hacks._u32 |= hackList[hack]; + + DisplayHack(hack); + + CurrentHack = hack; + SaveConfig(); + +} + diff --git a/plugins/zzogl-pg/opengl/ZZHacks.h b/plugins/zzogl-pg/opengl/ZZHacks.h new file mode 100644 index 0000000000..f628cd9c36 --- /dev/null +++ b/plugins/zzogl-pg/opengl/ZZHacks.h @@ -0,0 +1,99 @@ +#ifndef ZZHACKS_H_INCLUDED +#define ZZHACKS_H_INCLUDED + +#include "PS2Edefs.h" + +// This is a list of the various hacks, and what bit controls them. +// Changing these is not advised unless you know what you are doing. +enum GAME_HACK_OPTIONS +{ + GAME_TEXTURETARGS = 0x00000001, + GAME_AUTORESET = 0x00000002, + GAME_INTERLACE2X = 0x00000004, + GAME_TEXAHACK = 0x00000008, // apply texa to non textured polys + GAME_NOTARGETRESOLVE = 0x00000010, + GAME_EXACTCOLOR = 0x00000020, + GAME_NOCOLORCLAMP = 0x00000040, + GAME_FFXHACK = 0x00000080, + GAME_NOALPHAFAIL = 0x00000100, + GAME_NODEPTHUPDATE = 0x00000200, + GAME_QUICKRESOLVE1 = 0x00000400, + GAME_NOQUICKRESOLVE = 0x00000800, + GAME_NOTARGETCLUT = 0x00001000, // full 16 bit resolution + GAME_NOSTENCIL = 0x00002000, + GAME_VSSHACKOFF = 0x00004000, // vertical stripe syndrome + GAME_NODEPTHRESOLVE = 0x00008000, + GAME_FULL16BITRES = 0x00010000, + GAME_RESOLVEPROMOTED = 0x00020000, + GAME_FASTUPDATE = 0x00040000, + GAME_NOALPHATEST = 0x00080000, + GAME_DISABLEMRTDEPTH = 0x00100000, + GAME_32BITTARGS = 0x00200000, + GAME_PATH3HACK = 0x00400000, + GAME_DOPARALLELCTX = 0x00800000, // tries to parallelize both contexts so that render calls are reduced (xenosaga) + // makes the game faster, but can be buggy + GAME_XENOSPECHACK = 0x01000000, // xenosaga specularity hack (ignore any zmask=1 draws) + GAME_PARTIALPOINTERS = 0x02000000, // whenver the texture or render target are small, tries to look for bigger ones to read from + GAME_PARTIALDEPTH = 0x04000000, // tries to save depth targets as much as possible across height changes + GAME_REGETHACK = 0x08000000, // some sort of weirdness in ReGet() code + GAME_GUSTHACK = 0x10000000, // Needed for Gustgames fast update. + GAME_NOLOGZ = 0x20000000, // Intended for linux -- not logarithmic Z. + GAME_AUTOSKIPDRAW = 0x40000000, // Remove blur effect on some games + GAME_RESERVED_HACK = 0x80000000 +}; + +#define USEALPHATESTING (!(conf.settings().no_alpha_test)) + +typedef union +{ + struct + { + u32 texture_targs : 1; + u32 auto_reset : 1; + u32 interlace_2x : 1; + u32 texa : 1; // apply texa to non textured polys + u32 no_target_resolve : 1; + u32 exact_color : 1; + u32 no_color_clamp : 1; + u32 ffx : 1; + u32 no_alpha_fail : 1; + u32 no_depth_update : 1; + u32 quick_resolve_1 : 1; + u32 no_quick_resolve : 1; + u32 no_target_clut : 1; // full 16 bit resolution + u32 no_stencil : 1; + u32 vss_hack_off : 1; // vertical stripe syndrome + u32 no_depth_resolve : 1; + u32 full_16_bit_res : 1; + u32 resolve_promoted : 1; + u32 fast_update : 1; + u32 no_alpha_test : 1; + u32 disable_mrt_depth : 1; + u32 args_32_bit : 1; + u32 path3 : 1; + u32 parallel_context : 1; // tries to parallelize both contexts so that render calls are reduced (xenosaga) + // makes the game faster, but can be buggy + u32 xenosaga_spec : 1; // xenosaga specularity hack (ignore any zmask=1 draws) + u32 partial_pointers : 1; // whenver the texture or render target are small, tries to look for bigger ones to read from + u32 partial_depth : 1; // tries to save depth targets as much as possible across height changes + u32 reget : 1; // some sort of weirdness in ReGet() code + u32 gust : 1; // Needed for Gustgames fast update. + u32 no_logz : 1; // Intended for linux -- not logarithmic Z. + u32 automatic_skip_draw :1; // allow debug of the automatic skip draw option + u32 reserved2 :1; + }; + u32 _u32; +} gameHacks; + +#define HACK_NUMBER 25 +extern u32 hackList[HACK_NUMBER]; +extern char hackDesc[32][64]; +extern int CurrentHack; + +extern void ReportHacks(gameHacks hacks); +extern void ListHacks(); + +extern void DisplayHack(int hack); +extern void ChangeCurrentHack(int hack); + +#endif // ZZHACKS_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/ZZKeyboard.cpp b/plugins/zzogl-pg/opengl/ZZKeyboard.cpp index aca62bf3b4..7d0ec625fb 100644 --- a/plugins/zzogl-pg/opengl/ZZKeyboard.cpp +++ b/plugins/zzogl-pg/opengl/ZZKeyboard.cpp @@ -30,12 +30,12 @@ extern char *libraryName; extern const unsigned char zgsversion; extern unsigned char zgsrevision, zgsbuild, zgsminor; -extern u32 THR_KeyEvent; // value for passing out key events between threads -extern bool THR_bShift, SaveStateExists; +extern bool SaveStateExists; const char* s_aa[5] = { "AA none |", "AA 2x |", "AA 4x |", "AA 8x |", "AA 16x |" }; const char* pbilinear[] = { "off", "normal", "forced" }; +extern void SetAA(int mode); void ProcessBilinear() { @@ -86,7 +86,7 @@ void ProcessAASetting(bool reverse) conf.incAA(); sprintf(strtitle, "anti-aliasing - %s", s_aa[conf.aa]); - ZeroGS::SetAA(conf.aa); + SetAA(conf.aa); ZZLog::WriteToScreen(strtitle); SaveConfig(); @@ -110,75 +110,26 @@ void ProcessWireFrame() ZZLog::WriteToScreen(strtitle); } -typedef struct GameHackStruct -{ - const char HackName[40]; - u32 HackMask; -} GameHack; - -#define HACK_NUMBER 25 - -GameHack HackinshTable[HACK_NUMBER] = -{ - {"*** 0 No Hack", 0}, - {"*** 1 TexTargets Check", GAME_TEXTURETARGS}, - {"*** 2 Autoreset Targets", GAME_AUTORESET}, - {"*** 3 Interlace 2x", GAME_INTERLACE2X}, - {"*** 4 TexA hack", GAME_TEXAHACK}, - {"*** 5 No Target Resolve", GAME_NOTARGETRESOLVE}, - {"*** 6 Exact color", GAME_EXACTCOLOR}, - //{"***xx No color clamp", GAME_NOCOLORCLAMP}, - //{"***xx FFX hack", GAME_FFXHACK}, - {"*** 7 No Alpha Fail", GAME_NOALPHAFAIL}, - {"*** 8 No Depth Update", GAME_NODEPTHUPDATE}, - {"*** 9 Quick Resolve 1", GAME_QUICKRESOLVE1}, - {"***10 No quick resolve", GAME_NOQUICKRESOLVE}, - {"***11 Notaget clut", GAME_NOTARGETCLUT}, - {"***12 No Stencil", GAME_NOSTENCIL}, - {"***13 No Depth resolve", GAME_NODEPTHRESOLVE}, - {"***14 Full 16 bit", GAME_FULL16BITRES}, - {"***15 Resolve promoted", GAME_RESOLVEPROMOTED}, - {"***16 Fast Update", GAME_FASTUPDATE}, - {"***17 No Alpha Test", GAME_NOALPHATEST}, - {"***18 Disable MRT depth", GAME_DISABLEMRTDEPTH}, - //{"***xx 32 bit targs", GAME_32BITTARGS}, - //{"***xx Path 3 hack", GAME_PATH3HACK}, - //{"***xx Parallel calls", GAME_DOPARALLELCTX}, - {"***19 Specular highlights", GAME_XENOSPECHACK}, - //{"***xx Partial pointers", GAME_PARTIALPOINTERS}, - {"***20 Partial depth", GAME_PARTIALDEPTH}, - {"***21 Reget hack", GAME_REGETHACK}, - - {"***22 Gust hack", GAME_GUSTHACK}, - {"***23 Log-Z", GAME_NOLOGZ}, - {"***24 Auto skipdraw", GAME_AUTOSKIPDRAW} -}; - -int CurrentHackSetting = 0; - void ProcessHackSetting(bool reverse) { FUNCLOG - -// printf ("A %d\n", HackinshTable[CurrentHackSetting].HackMask); - conf.hacks._u32 &= !(HackinshTable[CurrentHackSetting].HackMask); + + int hack = CurrentHack; if (reverse) { - CurrentHackSetting--; + hack--; - if (CurrentHackSetting == -1) CurrentHackSetting = HACK_NUMBER - 1; + if (hack < 0) hack = HACK_NUMBER - 1; } else { - CurrentHackSetting++; + hack++; - if (CurrentHackSetting >= HACK_NUMBER) CurrentHackSetting = 0; + if (hack >= HACK_NUMBER) hack = 0; } - - conf.hacks._u32 |= HackinshTable[CurrentHackSetting].HackMask; - - ZZLog::WriteToScreen(HackinshTable[CurrentHackSetting].HackName); + ChangeCurrentHack(hack); + SaveConfig(); } @@ -188,7 +139,7 @@ void ProcessSaveState() char strtitle[256]; sprintf(strtitle, "Saving in savestate %d", CurrentSavestate); SaveStateExists = true; - ZZLog::WriteToScreen(HackinshTable[CurrentHackSetting].HackName); + if (CurrentHack != 0) DisplayHack(CurrentHack); } void OnFKey(int key, int shift) @@ -253,99 +204,3 @@ void WriteBilinear() break; } } - -#ifdef _WIN32 -void ProcessEvents() -{ - MSG msg; - - ZeroMemory(&msg, sizeof(msg)); - - while (1) - { - if (PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE)) - { - switch (msg.message) - { - case WM_KEYDOWN : - int my_KeyEvent = msg.wParam; - bool my_bShift = !!(GetKeyState(VK_SHIFT) & 0x8000); - - switch (msg.wParam) - { - case VK_F5: - case VK_F6: - case VK_F7: - case VK_F9: - OnFKey(msg.wParam - VK_F1 + 1, my_bShift); - break; - - case VK_ESCAPE: - - if (conf.fullscreen()) - { - // destroy that msg - conf.setFullscreen(false); - ZeroGS::ChangeDeviceSize(conf.width, conf.height); - UpdateWindow(GShwnd); - continue; // so that msg doesn't get sent - } - else - { - SendMessage(GShwnd, WM_DESTROY, 0, 0); - return; - } - - break; - } - - break; - } - - TranslateMessage(&msg); - DispatchMessage(&msg); - } - else - { - break; - } - } - - if ((GetKeyState(VK_MENU) & 0x8000) && (GetKeyState(VK_RETURN) & 0x8000)) - { - conf.zz_options.fullscreen = !conf.zz_options.fullscreen; - - ZeroGS::SetChangeDeviceSize( - (conf.fullscreen()) ? 1280 : conf.width, - (conf.fullscreen()) ? 960 : conf.height); - } -} - -#else // linux - -void ProcessEvents() -{ - FUNCLOG - - // check resizing - GLWin.ResizeCheck(); - - if (THR_KeyEvent) // This value was passed from GSKeyEvents which could be in another thread - { - int my_KeyEvent = THR_KeyEvent; - bool my_bShift = THR_bShift; - THR_KeyEvent = 0; - - switch (my_KeyEvent) - { - case XK_F5: - case XK_F6: - case XK_F7: - case XK_F9: - OnFKey(my_KeyEvent - XK_F1 + 1, my_bShift); - break; - } - } -} - -#endif // linux diff --git a/plugins/zzogl-pg/opengl/ZZLog.cpp b/plugins/zzogl-pg/opengl/ZZLog.cpp index 5d92b1f621..191d81733d 100644 --- a/plugins/zzogl-pg/opengl/ZZLog.cpp +++ b/plugins/zzogl-pg/opengl/ZZLog.cpp @@ -19,9 +19,44 @@ #include #include "ZZLog.h" +#include +#include extern GSconf conf; +using namespace std; + +static list listMsgs; + +void ProcessMessages() +{ + FUNCLOG + + if (listMsgs.size() > 0) + { + int left = 25, top = 15; + list::iterator it = listMsgs.begin(); + + while (it != listMsgs.end()) + { + DrawText(it->str, left + 1, top + 1, 0xff000000); + DrawText(it->str, left, top, 0xffffff30); + top += 15; + + if ((int)(it->dwTimeStamp - timeGetTime()) < 0) + it = listMsgs.erase(it); + else ++it; + } + } +} + +void ZZAddMessage(const char* pstr, u32 ms) +{ + FUNCLOG + listMsgs.push_back(MESSAGE(pstr, timeGetTime() + ms)); + ZZLog::Log("%s\n", pstr); +} + namespace ZZLog { std::string s_strLogPath("logs/"); @@ -68,7 +103,19 @@ void SetDir(const char* dir) void WriteToScreen(const char* pstr, u32 ms) { - ZeroGS::AddMessage(pstr, ms); + ZZAddMessage(pstr, ms); +} + +void WriteToScreen2(const char* fmt, ...) +{ + va_list list; + char tmp[512]; + + va_start(list, fmt); + vsprintf(tmp, fmt, list); + va_end(list); + + ZZAddMessage(tmp, 5000); } void _Message(const char *str) @@ -267,7 +314,7 @@ void Dev_Log(const char *fmt, ...) void Debug_Log(const char *fmt, ...) { -#if _DEBUG +#ifdef _DEBUG va_list list; va_start(list, fmt); diff --git a/plugins/zzogl-pg/opengl/ZZLog.h b/plugins/zzogl-pg/opengl/ZZLog.h index a7d949b363..2dbc60b9e4 100644 --- a/plugins/zzogl-pg/opengl/ZZLog.h +++ b/plugins/zzogl-pg/opengl/ZZLog.h @@ -1,193 +1,201 @@ -/* ZZ Open GL graphics plugin - * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com - * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef ZZLOG_H_INCLUDED -#define ZZLOG_H_INCLUDED - -#include "Util.h" - - -//Logging for errors that are called often should have a time counter. -#ifdef __LINUX__ -static u32 __attribute__((unused)) lasttime = 0; -static u32 __attribute__((unused)) BigTime = 5000; -static bool __attribute__((unused)) SPAM_PASS; -#else -static u32 lasttime = 0; -static u32 BigTime = 5000; -static bool SPAM_PASS; -#endif - -#define ERROR_LOG_SPAM(text) { \ - if( timeGetTime() - lasttime > BigTime ) { \ - ZZLog::Error_Log(text); \ - lasttime = timeGetTime(); \ - } \ -} -// The same macro with one-argument substitution. -#define ERROR_LOG_SPAMA(fmt, value) { \ - if( timeGetTime() - lasttime > BigTime ) { \ - ZZLog::Error_Log(fmt, value); \ - lasttime = timeGetTime(); \ - } \ -} - -#define ERROR_LOG_SPAM_TEST(text) {\ - if( timeGetTime() - lasttime > BigTime ) { \ - ZZLog::Error_Log(text); \ - lasttime = timeGetTime(); \ - SPAM_PASS = true; \ - } \ - else \ - SPAM_PASS = false; \ -} - -#if DEBUG_PROF -#define FILE_IS_IN_CHECK ((strcmp(__FILE__, "targets.cpp") == 0) || (strcmp(__FILE__, "ZZoglFlush.cpp") == 0)) - -#define FUNCLOG {\ - static bool Was_Here = false; \ - static unsigned long int waslasttime = 0; \ - if (!Was_Here && FILE_IS_IN_CHECK) { \ - Was_Here = true;\ - ZZLog::Error_Log("%s:%d %s", __FILE__, __LINE__, __func__); \ - waslasttime = timeGetTime(); \ - } \ - if (FILE_IS_IN_CHECK && (timeGetTime() - waslasttime > BigTime )) { \ - Was_Here = false; \ - } \ -} -#else -#define FUNCLOG -#endif - -//#define WRITE_GREG_LOGS -//#define WRITE_PRIM_LOGS -#if defined(_DEBUG) && !defined(ZEROGS_DEVBUILD) -#define ZEROGS_DEVBUILD -#endif - - -// sends a message to output window if assert fails -#define BMSG(x, str) { if( !(x) ) { ZZLog::Log(str); ZZLog::Log(str); } } -#define BMSG_RETURN(x, str) { if( !(x) ) { ZZLog::Log(str); ZZLog::Log(str); return; } } -#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { ZZLog::Log(str); ZZLog::Log(str); return (##rtype); } } -#define B(x) { if( !(x) ) { ZZLog::Log(_#x"\n"); ZZLog::Log(#x"\n"); } } -#define B_RETURN(x) { if( !(x) ) { ZZLog::Error_Log("%s:%d: %s", __FILE__, (u32)__LINE__, #x); return; } } -#define B_RETURNX(x, rtype) { if( !(x) ) { ZZLog::Error_Log("%s:%d: %s", __FILE__, (u32)__LINE__, #x); return (##rtype); } } -#define B_G(x, action) { if( !(x) ) { ZZLog::Error_Log("%s:%d: %s", __FILE__, (u32)__LINE__, #x); action; } } - -#define GL_REPORT_ERROR() \ -{ \ - GLenum err = glGetError(); \ - if( err != GL_NO_ERROR ) \ - { \ - ZZLog::Error_Log("%s:%d: gl error %s(0x%x)", __FILE__, (int)__LINE__, error_name(err), err); \ - ZeroGS::HandleGLError(); \ - } \ -} - -#ifdef _DEBUG -# define GL_REPORT_ERRORD() \ -{ \ - GLenum err = glGetError(); \ - if( err != GL_NO_ERROR ) \ - { \ - ZZLog::Error_Log("%s:%d: gl error %s (0x%x)", __FILE__, (int)__LINE__, error_name(err), err); \ - ZeroGS::HandleGLError(); \ - } \ -} -#else -# define GL_REPORT_ERRORD() -#endif - - -inline const char *error_name(int err) -{ - switch (err) - { - case GL_NO_ERROR: - return "GL_NO_ERROR"; - - case GL_INVALID_ENUM: - return "GL_INVALID_ENUM"; - - case GL_INVALID_VALUE: - return "GL_INVALID_VALUE"; - - case GL_INVALID_OPERATION: - return "GL_INVALID_OPERATION"; - - case GL_STACK_OVERFLOW: - return "GL_STACK_OVERFLOW"; - - case GL_STACK_UNDERFLOW: - return "GL_STACK_UNDERFLOW"; - - case GL_OUT_OF_MEMORY: - return "GL_OUT_OF_MEMORY"; - - case GL_TABLE_TOO_LARGE: - return "GL_TABLE_TOO_LARGE"; - - case GL_INVALID_FRAMEBUFFER_OPERATION: - return "GL_INVALID_FRAMEBUFFER_OPERATION"; - - default: - return "Unknown GL error"; - } -} - -extern void __LogToConsole(const char *fmt, ...); - -// Subset of zerogs, to avoid that whole huge header. -namespace ZeroGS -{ -extern void AddMessage(const char* pstr, u32 ms); -extern void SetAA(int mode); -extern bool Create(int width, int height); -extern void Destroy(bool bD3D); -extern void StartCapture(); -extern void StopCapture(); -} - -namespace ZZLog -{ -extern bool IsLogging(); -void SetDir(const char* dir); -extern void Open(); -extern void Close(); -extern void Message(const char *fmt, ...); -extern void Log(const char *fmt, ...); -void WriteToScreen(const char* pstr, u32 ms = 5000); -extern void WriteToConsole(const char *fmt, ...); -extern void Print(const char *fmt, ...); -extern void WriteLn(const char *fmt, ...); - -extern void Greg_Log(const char *fmt, ...); -extern void Prim_Log(const char *fmt, ...); -extern void GS_Log(const char *fmt, ...); - -extern void Debug_Log(const char *fmt, ...); -extern void Dev_Log(const char *fmt, ...); -extern void Warn_Log(const char *fmt, ...); -extern void Error_Log(const char *fmt, ...); -}; - -#endif // ZZLOG_H_INCLUDED +/* ZZ Open GL graphics plugin + * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef ZZLOG_H_INCLUDED +#define ZZLOG_H_INCLUDED + +#include "Util.h" +#include + +extern void HandleGLError(); + +//Logging for errors that are called often should have a time counter. +#ifdef __LINUX__ +static u32 __attribute__((unused)) lasttime = 0; +static u32 __attribute__((unused)) BigTime = 5000; +static bool __attribute__((unused)) SPAM_PASS; +#else +static u32 lasttime = 0; +static u32 BigTime = 5000; +static bool SPAM_PASS; +#endif + +#define ERROR_LOG_SPAM(text) { \ + if( timeGetTime() - lasttime > BigTime ) { \ + ZZLog::Error_Log(text); \ + lasttime = timeGetTime(); \ + } \ +} +// The same macro with one-argument substitution. +#define ERROR_LOG_SPAMA(fmt, value) { \ + if( timeGetTime() - lasttime > BigTime ) { \ + ZZLog::Error_Log(fmt, value); \ + lasttime = timeGetTime(); \ + } \ +} + +#define ERROR_LOG_SPAM_TEST(text) {\ + if( timeGetTime() - lasttime > BigTime ) { \ + ZZLog::Error_Log(text); \ + lasttime = timeGetTime(); \ + SPAM_PASS = true; \ + } \ + else \ + SPAM_PASS = false; \ +} + +#if DEBUG_PROF +#define FILE_IS_IN_CHECK ((strcmp(__FILE__, "targets.cpp") == 0) || (strcmp(__FILE__, "ZZoglFlush.cpp") == 0)) + +#define FUNCLOG {\ + static bool Was_Here = false; \ + static unsigned long int waslasttime = 0; \ + if (!Was_Here && FILE_IS_IN_CHECK) { \ + Was_Here = true;\ + ZZLog::Error_Log("%s:%d %s", __FILE__, __LINE__, __func__); \ + waslasttime = timeGetTime(); \ + } \ + if (FILE_IS_IN_CHECK && (timeGetTime() - waslasttime > BigTime )) { \ + Was_Here = false; \ + } \ +} +#else +#define FUNCLOG +#endif + +//#define WRITE_GREG_LOGS +//#define WRITE_PRIM_LOGS +#if defined(_DEBUG) && !defined(ZEROGS_DEVBUILD) +#define ZEROGS_DEVBUILD +#endif + + +// sends a message to output window if assert fails +#define BMSG(x, str) { if( !(x) ) { ZZLog::Log(str); ZZLog::Log(str); } } +#define BMSG_RETURN(x, str) { if( !(x) ) { ZZLog::Log(str); ZZLog::Log(str); return; } } +#define BMSG_RETURNX(x, str, rtype) { if( !(x) ) { ZZLog::Log(str); ZZLog::Log(str); return (##rtype); } } +#define B(x) { if( !(x) ) { ZZLog::Log(_#x"\n"); ZZLog::Log(#x"\n"); } } +#define B_RETURN(x) { if( !(x) ) { ZZLog::Error_Log("%s:%d: %s", __FILE__, (u32)__LINE__, #x); return; } } +#define B_RETURNX(x, rtype) { if( !(x) ) { ZZLog::Error_Log("%s:%d: %s", __FILE__, (u32)__LINE__, #x); return (##rtype); } } +#define B_G(x, action) { if( !(x) ) { ZZLog::Error_Log("%s:%d: %s", __FILE__, (u32)__LINE__, #x); action; } } + +#define GL_REPORT_ERROR() \ +{ \ + GLenum err = glGetError(); \ + if( err != GL_NO_ERROR ) \ + { \ + ZZLog::Error_Log("%s:%d: gl error %s(0x%x)", __FILE__, (int)__LINE__, error_name(err), err); \ + HandleGLError(); \ + } \ +} + +#ifdef _DEBUG +# define GL_REPORT_ERRORD() \ +{ \ + GLenum err = glGetError(); \ + if( err != GL_NO_ERROR ) \ + { \ + ZZLog::Error_Log("%s:%d: gl error %s (0x%x)", __FILE__, (int)__LINE__, error_name(err), err); \ + /* HandleGLError();*/ \ + } \ +} +#else +# define GL_REPORT_ERRORD() +#endif + + +inline const char *error_name(int err) +{ + switch (err) + { + case GL_NO_ERROR: + return "GL_NO_ERROR"; + + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + + case GL_STACK_OVERFLOW: + return "GL_STACK_OVERFLOW"; + + case GL_STACK_UNDERFLOW: + return "GL_STACK_UNDERFLOW"; + + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + + case GL_TABLE_TOO_LARGE: + return "GL_TABLE_TOO_LARGE"; + + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + + default: + return "Unknown GL error"; + } +} + +struct MESSAGE +{ + MESSAGE() {} + + MESSAGE(const char* p, u32 dw) { strcpy(str, p); dwTimeStamp = dw; } + + char str[255]; + u32 dwTimeStamp; +}; + +extern void DrawText(const char* pstr, int left, int top, u32 color); +extern void __LogToConsole(const char *fmt, ...); + +extern void ZZAddMessage(const char* pstr, u32 ms = 5000); +extern void StartCapture(); +extern void StopCapture(); + + +namespace ZZLog +{ +extern bool IsLogging(); +void SetDir(const char* dir); +extern void Open(); +extern void Close(); +extern void Message(const char *fmt, ...); +extern void Log(const char *fmt, ...); +void WriteToScreen(const char* pstr, u32 ms = 5000); +void WriteToScreen2(const char* pstr, ...); +extern void WriteToConsole(const char *fmt, ...); +extern void Print(const char *fmt, ...); +extern void WriteLn(const char *fmt, ...); + +extern void Greg_Log(const char *fmt, ...); +extern void Prim_Log(const char *fmt, ...); +extern void GS_Log(const char *fmt, ...); + +extern void Debug_Log(const char *fmt, ...); +extern void Dev_Log(const char *fmt, ...); +extern void Warn_Log(const char *fmt, ...); +extern void Error_Log(const char *fmt, ...); +}; + +#endif // ZZLOG_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/ZZoglCRTC.cpp b/plugins/zzogl-pg/opengl/ZZoglCRTC.cpp index 7a20b67c71..e9e9912af0 100644 --- a/plugins/zzogl-pg/opengl/ZZoglCRTC.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglCRTC.cpp @@ -21,11 +21,15 @@ // It draw picture direct on screen, so here we have interlacing and frame skipping. //------------------ Includes + #include "Util.h" #include "ZZoglCRTC.h" #include "GLWin.h" #include "ZZoglShaders.h" - -using namespace ZeroGS; +#include "ZZoglShoots.h" +#include "ZZoglDrawing.h" +#include "rasterfont.h" // simple font +#include +#include "ZZoglVB.h" //------------------ Defines #if !defined(ZEROGS_DEVBUILD) @@ -49,28 +53,33 @@ vector s_vecTempTextures; // temporary textures, released at the end of extern bool g_bMakeSnapshot; extern string strSnapshot; +extern void ExtWrite(); +extern void ZZDestroy(); +extern void ChangeDeviceSize(int nNewWidth, int nNewHeight); + +extern GLuint vboRect; // Adjusts vertex shader BitBltPos vector v to preserve aspect ratio. It used to emulate 4:3 or 16:9. -void ZeroGS::AdjustTransToAspect(float4& v) +void AdjustTransToAspect(float4& v) { double temp; float f; const float mult = 1 / 32767.0f; - if (conf.width * nBackbufferHeight > conf.height * nBackbufferWidth) // limited by width + if (conf.width * GLWin.backbuffer.h > conf.height * GLWin.backbuffer.w) // limited by width { // change in ratio - f = ((float)nBackbufferWidth / (float)conf.width) / ((float)nBackbufferHeight / (float)conf.height); + f = ((float)GLWin.backbuffer.w / (float)conf.width) / ((float)GLWin.backbuffer.h / (float)conf.height); v.y *= f; v.w *= f; // scanlines mess up when not aligned right - v.y += (1 - (float)modf(v.y * (float)nBackbufferHeight * 0.5f + 0.05f, &temp)) * 2.0f / (float)nBackbufferHeight; - v.w += (1 - (float)modf(v.w * (float)nBackbufferHeight * 0.5f + 0.05f, &temp)) * 2.0f / (float)nBackbufferHeight; + v.y += (1 - (float)modf(v.y * (float)GLWin.backbuffer.h * 0.5f + 0.05f, &temp)) * 2.0f / (float)GLWin.backbuffer.h; + v.w += (1 - (float)modf(v.w * (float)GLWin.backbuffer.h * 0.5f + 0.05f, &temp)) * 2.0f / (float)GLWin.backbuffer.h; } else // limited by height { - f = ((float)nBackbufferHeight / (float)conf.height) / ((float)nBackbufferWidth / (float)conf.width); - f -= (float)modf(f * nBackbufferWidth, &temp) / (float)nBackbufferWidth; + f = ((float)GLWin.backbuffer.h / (float)conf.height) / ((float)GLWin.backbuffer.w / (float)conf.width); + f -= (float)modf(f * GLWin.backbuffer.w, &temp) / (float)GLWin.backbuffer.w; v.x *= f; v.z *= f; } @@ -139,9 +148,6 @@ inline void FrameSavingHelper() } #endif } - -// g_SaveFrameNum = 0; -// g_bSaveFlushedFrame = 1; } // Function populated tex0Info[2] array @@ -178,20 +184,11 @@ inline void FrameObtainDispinfo(u32 bInterlace, tex0Info* dispinfo) } } +extern bool s_bWriteDepth; + // Something should be done before Renderering the picture. inline void RenderStartHelper(u32 bInterlace) { - // Crashes Final Fantasy X at startup if uncommented. --arcum42 -//#ifdef !defined(ZEROGS_DEVBUILD) -// if(g_nRealFrame < 80 ) { -// RenderCustom( min(1.0f, 2.0f - (float)g_nRealFrame / 40.0f) ); -// -// if( g_nRealFrame == 79 ) -// SAFE_RELEASE_TEX(ptexLogo); -// return; -// } -//#endif - if (conf.mrtdepth && pvs[8] == NULL) { conf.mrtdepth = 0; @@ -214,7 +211,7 @@ inline void RenderStartHelper(u32 bInterlace) glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer - glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); + glViewport(0, 0, GLWin.backbuffer.w, GLWin.backbuffer.h); // if interlace, only clear every other vsync if (!bInterlace) @@ -634,8 +631,23 @@ inline void RenderCheckForMemory(tex0Info& texframe, list& listT DrawTriangleArray(); } +extern RasterFont* font_p; + +void DrawText(const char* pstr, int left, int top, u32 color) +{ + FUNCLOG + ZZshGLDisableProfile(); + + float4 v; + v.SetColor(color); + glColor3f(v.z, v.y, v.x); + + font_p->printString(pstr, left * 2.0f / (float)GLWin.backbuffer.w - 1, 1 - top * 2.0f / (float)GLWin.backbuffer.h, 0); + ZZshGLEnableProfile(); +} + // Put FPS counter on screen (not in window title) -inline void AfterRenderDisplayFPS() +inline void DisplayFPS() { char str[64]; int left = 10, top = 15; @@ -645,16 +657,8 @@ inline void AfterRenderDisplayFPS() DrawText(str, left, top, 0xffc0ffff); } -// Swapping buffers, so we could use another window -inline void AfterRenderSwapBuffers() -{ - if (glGetError() != GL_NO_ERROR) ZZLog::Debug_Log("glError before swap!"); - - GLWin.SwapGLBuffers(); -} - // SnapeShoot helper -inline void AfterRenderMadeSnapshoot() +inline void MakeSnapshot() { if (!g_bMakeSnapshot) return; @@ -666,26 +670,40 @@ inline void AfterRenderMadeSnapshoot() DrawText(str, left + 1, top + 1, 0xff000000); DrawText(str, left, top, 0xffc0ffff); - if (SaveRenderTarget(strSnapshot != "" ? strSnapshot.c_str() : "temp.jpg", nBackbufferWidth, -nBackbufferHeight, 0)) //(conf.options.tga_snap)?0:1) ) { + if (SaveRenderTarget(strSnapshot != "" ? strSnapshot.c_str() : "temp.jpg", GLWin.backbuffer.w, -GLWin.backbuffer.h, 0)) //(conf.options.tga_snap)?0:1) ) { { char str[255]; sprintf(str, "saved %s\n", strSnapshot.c_str()); - AddMessage(str, 500); + ZZAddMessage(str, 500); } - g_bMakeSnapshot = false; + g_bMakeSnapshot = false; } -// If needed reset -inline void AfterRendererResizeWindow() +// call to destroy video resources +void ZZReset() { - Reset(); - ChangeDeviceSize(s_nNewWidth, s_nNewHeight); - s_nNewWidth = s_nNewHeight = -1; + FUNCLOG + s_RTs.ResolveAll(); + s_DepthRTs.ResolveAll(); + + vb[0].nCount = 0; + vb[1].nCount = 0; + + memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); + s_nLastResolveReset = 0; + + icurctx = -1; + g_vsprog = g_psprog = 0; + + ZZGSStateReset(); + ZZDestroy(); + //clear_drawfn(); + if (ZZKick != NULL) delete ZZKick; } // Put new values on statistic variable -inline void AfterRenderCountStatistics() +inline void CountStatistics() { if (s_nWriteDepthCount > 0) { @@ -708,7 +726,6 @@ inline void AfterRenderCountStatistics() if (g_nDepthUsed > 0) --g_nDepthUsed; s_ClutResolve = 0; - g_nDepthUpdateCount = 0; } @@ -717,32 +734,33 @@ inline void AfterRendererUnimportantJob() { ProcessMessages(); - if (g_bDisplayFPS) AfterRenderDisplayFPS(); + if (g_bDisplayFPS) DisplayFPS(); - AfterRenderSwapBuffers(); + // Swapping buffers, so we could use another window + GLWin.SwapGLBuffers(); - if (conf.wireframe()) - { - // clear all targets - s_nWireframeCount = 1; - } + // clear all targets + if (conf.wireframe()) s_nWireframeCount = 1; - if (g_bMakeSnapshot) - { - AfterRenderMadeSnapshoot(); - g_bMakeSnapshot = false; - } + if (g_bMakeSnapshot) MakeSnapshot(); CaptureFrame(); + CountStatistics(); - AfterRenderCountStatistics(); + if (s_nNewWidth >= 0 && s_nNewHeight >= 0) + { + // If needed reset + ZZReset(); - if (s_nNewWidth >= 0 && s_nNewHeight >= 0) - AfterRendererResizeWindow(); + ChangeDeviceSize(s_nNewWidth, s_nNewHeight); + s_nNewWidth = s_nNewHeight = -1; + } maxmin = 608; } +extern u32 s_uFramebuffer; + // Swich Framebuffers inline void AfterRendererSwitchBackToTextures() { @@ -780,13 +798,13 @@ inline void AfterRendererAutoresetTargets() if (conf.settings().auto_reset) { s_nResolveCounts[s_nCurResolveIndex] = s_nResolved; - s_nCurResolveIndex = (s_nCurResolveIndex + 1) % ARRAY_SIZE(s_nResolveCounts); + s_nCurResolveIndex = (s_nCurResolveIndex + 1) % ArraySize(s_nResolveCounts); int total = 0; - for (int i = 0; i < ARRAY_SIZE(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; + for (int i = 0; i < ArraySize(s_nResolveCounts); ++i) total += s_nResolveCounts[i]; - if (total / ARRAY_SIZE(s_nResolveCounts) > 3) + if (total / ArraySize(s_nResolveCounts) > 3) { if (s_nLastResolveReset > (int)(fFPS * 8)) { @@ -823,7 +841,7 @@ inline void AfterRendererAutoresetTargets() int count = 0; // The main renderer function -void ZeroGS::RenderCRTC(int interlace) +void RenderCRTC(int interlace) { if (FrameSkippingHelper()) return; diff --git a/plugins/zzogl-pg/opengl/ZZoglCRTC.h b/plugins/zzogl-pg/opengl/ZZoglCRTC.h index 7a1cb474fd..5ca9830e73 100644 --- a/plugins/zzogl-pg/opengl/ZZoglCRTC.h +++ b/plugins/zzogl-pg/opengl/ZZoglCRTC.h @@ -22,7 +22,6 @@ #include -#include "zerogs.h" #include "targets.h" #define INTERLACE_COUNT (bInterlace && interlace == (conf.interlace)) @@ -36,7 +35,6 @@ extern int s_frameskipping; extern float fFPS; extern unsigned char zgsrevision, zgsbuild, zgsminor; -//extern u32 g_SaveFrameNum; extern int s_nWriteDepthCount; extern int s_nWireframeCount; extern int s_nWriteDestAlphaTest; @@ -56,8 +54,6 @@ extern int g_nDepthUsed; // ffx2 pal movies extern u32 s_ptexInterlace; // holds interlace fields -namespace ZeroGS -{ extern int s_nNewWidth, s_nNewHeight; extern CRangeManager s_RangeMngr; // manages overwritten memory @@ -65,6 +61,8 @@ extern void FlushTransferRanges(const tex0Info* ptex); extern void ProcessMessages(); void AdjustTransToAspect(float4& v); +void ZZGSStateReset(); + // Interlace texture is lazy 1*(height) array of 1 and 0. // If its height (named s_nInterlaceTexWidth here) is hanging we must redo // the texture. @@ -95,6 +93,5 @@ inline u32 CreateInterlaceTex(int width) return s_ptexInterlace; } -} #endif // ZZOGLCRTC_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/ZZoglCreate.cpp b/plugins/zzogl-pg/opengl/ZZoglCreate.cpp index 81d6040284..2107c41b4b 100644 --- a/plugins/zzogl-pg/opengl/ZZoglCreate.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglCreate.cpp @@ -22,11 +22,14 @@ //------------------ Includes #include "GS.h" #include "Mem.h" -#include "zerogs.h" #include "GLWin.h" - #include "ZZoglShaders.h" + #include "targets.h" +#include "rasterfont.h" // simple font +#include "ZZoglDrawing.h" +#include "ZZoglVB.h" + // This include for windows resource file with Shaders #ifdef _WIN32 # include "Win32.h" @@ -73,14 +76,6 @@ typedef void (APIENTRYP _PFNSWAPINTERVAL)(int); map mapGLExtensions; -namespace ZeroGS -{ -extern void KickPoint(); -extern void KickLine(); -extern void KickTriangle(); -extern void KickTriangleFan(); -extern void KickSprite(); -extern void KickDummy(); extern bool LoadEffects(); extern bool ZZshLoadExtraEffects(); extern FRAGMENTSHADER* ZZshLoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed); @@ -92,7 +87,8 @@ int g_nCurVBOIndex = 0; inline bool CreateImportantCheck(); inline void CreateOtherCheck(); inline bool CreateOpenShadersFile(); -} + +void ZZGSStateReset(); //------------------ Dummies #ifdef _WIN32 @@ -129,15 +125,13 @@ void (APIENTRY *zgsBlendFuncSeparateEXT)(GLenum, GLenum, GLenum, GLenum) = NULL; extern u8* s_lpShaderResources; // String's for shader file in developer mode -#ifdef DEVBUILD +#ifdef ZEROGS_DEVBUILD char* EFFECT_NAME = ""; char* EFFECT_DIR = ""; #endif ///////////////////// // graphics resources -FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; -FRAGMENTSHADER ppsCRTC[2], ppsCRTC24[2], ppsCRTCTarg[2]; GLenum s_srcrgb, s_dstrgb, s_srcalpha, s_dstalpha; // set by zgsBlendFuncSeparateEXT u32 s_stencilfunc, s_stencilref, s_stencilmask; GLenum s_drawbuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; @@ -164,31 +158,21 @@ u32 ptexBlocks = 0, ptexConv16to32 = 0; // holds information on block tiling u32 ptexBilinearBlocks = 0; u32 ptexConv32to16 = 0; int g_nDepthBias = 0; -//u32 g_bSaveFlushedFrame = 0; + +extern void Delete_Avi_Capture(); +extern void ZZDestroy(); +extern void SetAA(int mode); //------------------ Code -bool ZeroGS::IsGLExt(const char* szTargetExtension) +///< returns true if the the opengl extension is supported +bool IsGLExt(const char* szTargetExtension) { return mapGLExtensions.find(string(szTargetExtension)) != mapGLExtensions.end(); } -inline bool ZeroGS::Create_Window(int _width, int _height) -{ - nBackbufferWidth = _width; - nBackbufferHeight = _height; - - if (!GLWin.DisplayWindow(_width, _height)) return false; - - //s_nFullscreen = (conf.fullscreen()) ? 1 : 0; - - conf.mrtdepth = 0; // for now - - return true; -} - // Function asks about different OGL extensions, that are required to setup accordingly. Return false if checks failed -inline bool ZeroGS::CreateImportantCheck() +inline bool CreateImportantCheck() { bool bSuccess = true; #ifndef _WIN32 @@ -220,7 +204,7 @@ inline bool ZeroGS::CreateImportantCheck() } // This is a check for less important open gl extensions. -inline void ZeroGS::CreateOtherCheck() +inline void CreateOtherCheck() { if (!IsGLExt("GL_EXT_blend_equation_separate") || glBlendEquationSeparateEXT == NULL) { @@ -292,18 +276,21 @@ inline void ZeroGS::CreateOtherCheck() #endif } -// open shader file according to build target -inline bool ZeroGS::CreateOpenShadersFile() +#ifdef _WIN32 +__forceinline bool LoadShadersFromRes() { -#ifndef DEVBUILD -# ifdef _WIN32 HRSRC hShaderSrc = FindResource(hInst, MAKEINTRESOURCE(IDR_SHADERS), RT_RCDATA); assert(hShaderSrc != NULL); HGLOBAL hShaderGlob = LoadResource(hInst, hShaderSrc); assert(hShaderGlob != NULL); s_lpShaderResources = (u8*)LockResource(hShaderGlob); -# else // not _WIN32 + return true; +} +#else + +__forceinline bool LoadShadersFromDat() +{ FILE* fres = fopen("ps2hw.dat", "rb"); if (fres == NULL) @@ -324,13 +311,17 @@ inline bool ZeroGS::CreateOpenShadersFile() fseek(fres, 0, SEEK_SET); fread(s_lpShaderResources, s, 1, fres); s_lpShaderResources[s] = 0; -# endif // _WIN32 -#else // defined(ZEROGS_DEVBUILD) -# ifndef _WIN32 // NOT WINDOWS + + return true; +} + +#ifdef DEVBUILD +__forceinline bool LoadShadersFromFX() +{ // test if ps2hw.fx exists char tempstr[255]; char curwd[255]; - getcwd(curwd, ARRAY_SIZE(curwd)); + getcwd(curwd, ArraySize(curwd)); strcpy(tempstr, "/plugins/"); sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); @@ -354,58 +345,56 @@ inline bool ZeroGS::CreateOpenShadersFile() sprintf(EFFECT_DIR, "%s/%s", curwd, tempstr); sprintf(EFFECT_NAME, "%sps2hw.fx", EFFECT_DIR); + + return true; +} +#endif +#endif + + +// open shader file according to build target + +inline bool CreateOpenShadersFile() +{ +#ifndef DEVBUILD +# ifdef _WIN32 + return LoadShadersFromRes(); +# else // not _WIN32 + return LoadShadersFromDat(); +# endif // _WIN32 +#else // defined(ZEROGS_DEVBUILD) +# ifndef _WIN32 // NOT WINDOWS + return LoadShadersFromFX(); + + // No else clause? #endif #endif // !defined(ZEROGS_DEVBUILD) - return true; } // Read all extensions name and fill mapGLExtensions inline bool CreateFillExtensionsMap() { - // fill the opengl extension map - const char* ptoken = (const char*)glGetString(GL_EXTENSIONS); + string temp(""); + int max_ext = 0; + glGetIntegerv(GL_NUM_EXTENSIONS, &max_ext); + + PFNGLGETSTRINGIPROC glGetStringi = 0; + glGetStringi = (PFNGLGETSTRINGIPROC)wglGetProcAddress("glGetStringi"); - if (ptoken == NULL) return false; - - int prevlog = conf.log; - - conf.log = 1; - - ZZLog::GS_Log("Supported OpenGL Extensions:\n%s\n", ptoken); // write to the log file - - // Probably a better way to do it, but seems to crash. - /*int n; - glGetIntegerv(GL_NUM_EXTENSIONS, &n); - ZZLog::GS_Log("Supported OpenGL Extensions:\n"); - for (int i = 0; i < n; i++) + for (GLint i = 0; i < max_ext; i++) { - ZZLog::GS_Log("%s/n", (const char*)glGetStringi(GL_EXTENSIONS, i)); - }*/ - - conf.log = prevlog; - - // insert all exts into mapGLExtensions - - const char* pend = NULL; - - while (ptoken != NULL) - { - pend = strchr(ptoken, ' '); - - if (pend != NULL) - { - mapGLExtensions[string(ptoken, pend-ptoken)]; - } - else - { - mapGLExtensions[string(ptoken)]; - break; - } - - ptoken = pend; - - while (*ptoken == ' ') ++ptoken; + string extension((const char*)glGetStringi(GL_EXTENSIONS, i)); + mapGLExtensions[extension]; + + temp = temp + extension; + if (i != (max_ext - 1)) temp += ", "; } + + // Write the extension list to the log, but only write it to the screen on a debug build. +#ifndef _DEBUG + ZZLog::Log("%d supported OpenGL Extensions: %s\n", max_ext, temp.c_str()); +#endif + ZZLog::Debug_Log("%d supported OpenGL Extensions: %s\n", max_ext, temp.c_str()); return true; } @@ -445,20 +434,22 @@ inline bool TryBlinearFormat(GLint fmt32, GLint fmt16, const GLvoid* vBilinearDa } -bool ZeroGS::Create(int _width, int _height) +bool ZZCreate(int _width, int _height) { GLenum err = GL_NO_ERROR; bool bSuccess = true; - int i; - Destroy(1); - GSStateReset(); + ZZDestroy(); + ZZGSStateReset(); + + if (!GLWin.DisplayWindow(_width, _height)) return false; + + conf.mrtdepth = 0; // for now - if (!Create_Window(_width, _height)) return false; if (!CreateFillExtensionsMap()) return false; if (!CreateImportantCheck()) return false; - ZeroGS::CreateOtherCheck(); + CreateOtherCheck(); // check the max texture width and height glGetIntegerv(GL_MAX_TEXTURE_SIZE, &g_MaxTexWidth); @@ -509,15 +500,10 @@ bool ZeroGS::Create(int _width, int _height) if (err != GL_NO_ERROR) bSuccess = false; // init draw fns - drawfn[0] = KickPoint; - drawfn[1] = KickLine; - drawfn[2] = KickLine; - drawfn[3] = KickTriangle; - drawfn[4] = KickTriangle; - drawfn[5] = KickTriangleFan; - drawfn[6] = KickSprite; - drawfn[7] = KickDummy; - + //init_drawfn(); + if (ZZKick != NULL) delete ZZKick; + ZZKick = new Kick; + SetAA(conf.aa); GSsetGameCRC(g_LastCRC, conf.settings()._u32); @@ -527,7 +513,7 @@ bool ZeroGS::Create(int _width, int _height) //s_bWriteDepth = true; GL_BLEND_ALL(GL_ONE, GL_ONE, GL_ONE, GL_ONE); - glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); // Reset The Current Viewport + glViewport(0, 0, GLWin.backbuffer.w, GLWin.backbuffer.h); // Reset The Current Viewport glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -574,7 +560,7 @@ bool ZeroGS::Create(int _width, int _height) g_vboBuffers.resize(VB_NUMBUFFERS); glGenBuffers((GLsizei)g_vboBuffers.size(), &g_vboBuffers[0]); - for (i = 0; i < (int)g_vboBuffers.size(); ++i) + for (int i = 0; i < (int)g_vboBuffers.size(); ++i) { glBindBuffer(GL_ARRAY_BUFFER, g_vboBuffers[i]); glBufferData(GL_ARRAY_BUFFER, 0x100*sizeof(VertexGPU), NULL, GL_STREAM_DRAW); @@ -657,32 +643,16 @@ bool ZeroGS::Create(int _width, int _height) VertexGPU* pvert = &verts[0]; - pvert->x = -0x7fff; - pvert->y = 0x7fff; - pvert->z = 0; - pvert->s = 0; - pvert->t = 0; + pvert->set_xyzst(-0x7fff, 0x7fff, 0, 0, 0); pvert++; - pvert->x = 0x7fff; - pvert->y = 0x7fff; - pvert->z = 0; - pvert->s = 1; - pvert->t = 0; + pvert->set_xyzst(0x7fff, 0x7fff, 0, 1, 0); pvert++; - pvert->x = -0x7fff; - pvert->y = -0x7fff; - pvert->z = 0; - pvert->s = 0; - pvert->t = 1; + pvert->set_xyzst(-0x7fff, -0x7fff, 0, 0, 1); pvert++; - pvert->x = 0x7fff; - pvert->y = -0x7fff; - pvert->z = 0; - pvert->s = 1; - pvert->t = 1; + pvert->set_xyzst(0x7fff, -0x7fff, 0, 1, 1); pvert++; glBufferDataARB(GL_ARRAY_BUFFER, 4*sizeof(VertexGPU), &verts[0], GL_STATIC_DRAW); @@ -706,7 +676,7 @@ bool ZeroGS::Create(int _width, int _height) vector conv16to32data(256*256); - for (i = 0; i < 256*256; ++i) + for (int i = 0; i < 256*256; ++i) { u32 tempcol = RGBA16to32(i); // have to flip r and b @@ -730,7 +700,7 @@ bool ZeroGS::Create(int _width, int _height) u32* dst = &conv32to16data[0]; - for (i = 0; i < 32; ++i) + for (int i = 0; i < 32; ++i) { for (int j = 0; j < 32; ++j) { @@ -778,8 +748,6 @@ bool ZeroGS::Create(int _width, int _height) vb[0].Init(VB_BUFFERSIZE); vb[1].Init(VB_BUFFERSIZE); -// g_bSaveFlushedFrame = 1; - g_vsprog = g_psprog = 0; if (glGetError() == GL_NO_ERROR) @@ -793,7 +761,7 @@ bool ZeroGS::Create(int _width, int _height) } } -void ZeroGS::Destroy(bool bD3D) +void ZZDestroy() { Delete_Avi_Capture(); @@ -822,7 +790,7 @@ void ZeroGS::Destroy(bool bD3D) if (pvs != NULL) { - for (int i = 0; i < ARRAY_SIZE(pvs); ++i) + for (int i = 0; i < ArraySize(pvs); ++i) { SAFE_RELEASE_PROG(pvs[i]); } @@ -830,7 +798,7 @@ void ZeroGS::Destroy(bool bD3D) if (ppsRegular != NULL) { - for (int i = 0; i < ARRAY_SIZE(ppsRegular); ++i) + for (int i = 0; i < ArraySize(ppsRegular); ++i) { SAFE_RELEASE_PROG(ppsRegular[i].prog); } @@ -838,7 +806,7 @@ void ZeroGS::Destroy(bool bD3D) if (ppsTexture != NULL) { - for (int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) + for (int i = 0; i < ArraySize(ppsTexture); ++i) { SAFE_RELEASE_PROG(ppsTexture[i].prog); } @@ -857,7 +825,7 @@ void ZeroGS::Destroy(bool bD3D) SAFE_RELEASE_PROG(ppsCRTC24[1].prog); SAFE_RELEASE_PROG(ppsOne.prog); - SAFE_DELETE(font_p); + safe_delete(font_p); GLWin.ReleaseContext(); diff --git a/plugins/zzogl-pg/opengl/ZZoglDrawing.cpp b/plugins/zzogl-pg/opengl/ZZoglDrawing.cpp new file mode 100644 index 0000000000..8123d8a357 --- /dev/null +++ b/plugins/zzogl-pg/opengl/ZZoglDrawing.cpp @@ -0,0 +1,254 @@ +/* ZZ Open GL graphics plugin + * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "ZZoglDrawing.h" +#include "ZZoglVB.h" + +Kick* ZZKick; + +const u32 g_primmult[8] = { 1, 2, 2, 3, 3, 3, 2, 0xff }; +const u32 g_primsub[8] = { 1, 2, 1, 3, 1, 1, 2, 0 }; + +const GLenum primtype[8] = { GL_POINTS, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, 0xffffffff }; + +extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height + +// Still thinking about the best place to put this. +// called on a primitive switch +void Prim() +{ + FUNCLOG + + VB& curvb = vb[prim->ctxt]; + + if (curvb.CheckPrim()) Flush(prim->ctxt); + curvb.SetCurrentPrim(); +} + +// return true if triangle SHOULD be painted. +// Hackish and should be replaced. +bool __forceinline NoHighlights(int i) +{ + //Old code + return (!(conf.settings().xenosaga_spec) || !vb[i].zbuf.zmsk || prim->iip) ; +} + +// Not inlining for the moment to avoid getting 'unresolved external symbol' errors in Windows. +// This could also be resolved by moving the function into the header... +void Kick::KickVertex(bool adc) +{ + FUNCLOG + if (++gs.primC >= (int)g_primmult[prim->prim]) + { + if (!adc && NoHighlights(prim->ctxt)) DrawPrim(prim->prim); + else DirtyValidPrevPrim(); + + gs.primC -= g_primsub[prim->prim]; + } + gs.primIndex = gs.primNext(); +} + +template +void Kick::Set_Vertex(VertexGPU *p, Vertex & gsvertex) +{ + VB& curvb = vb[prim->ctxt]; + + p->move_x(gsvertex, curvb.offset.x); + p->move_y(gsvertex, curvb.offset.y); + if(DO_Z_FOG) { + p->move_z(gsvertex, curvb.zprimmask); + p->move_fog(gsvertex); + } + + p->rgba = prim->iip ? gsvertex.rgba : gs.rgba; + + if (conf.settings().texa) + { + u32 B = ((p->rgba & 0xfe000000) >> 1) + (0x01000000 * vb[prim->ctxt].fba.fba); + p->rgba = (p->rgba & 0xffffff) + B; + } + + if (prim->tme) + { + if (prim->fst) + { + p->s = (float)gsvertex.u * fiTexWidth[prim->ctxt]; + p->t = (float)gsvertex.v * fiTexHeight[prim->ctxt]; + p->q = 1; + } + else + { + p->s = gsvertex.s; + p->t = gsvertex.t; + p->q = gsvertex.q; + } + } +} + +__forceinline void Kick::Output_Vertex(VertexGPU vert, u32 id) +{ +#ifdef WRITE_PRIM_LOGS + ZZLog::Prim_Log("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)", + id == 0 ? '*' : ' ', id, prim->prim, vert.x / 8, vert.y / 8, vert.z, vert.f / 128, + vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); +#endif +} + +void Kick::DrawPrim(u32 prim_type) +{ + VB& curvb = vb[prim->ctxt]; + + curvb.FlushTexData(); + + if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) + { + assert(vb[prim->ctxt].nCount == 0); + Flush(!prim->ctxt); + } + + // check enough place is left for the biggest primitive (sprite) + // This function is unlikely to be called so do not inline it. + if (unlikely(curvb.nCount + 6 > curvb.nNumVertices)) + curvb.IncreaseVertexBuffer(); + + VertexGPU* p = curvb.pBufferData + curvb.nCount; + + u32 prev; + u32 last; + switch(prim_type) { + case PRIM_POINT: + Set_Vertex(&p[0], gs.gsvertex[gs.primIndex]); + curvb.nCount ++; + break; + + case PRIM_LINE: + Set_Vertex(&p[0], gs.gsvertex[gs.primPrev()]); + Set_Vertex(&p[1], gs.gsvertex[gs.primIndex]); + curvb.nCount += 2; + break; + + case PRIM_LINE_STRIP: + if (likely(ValidPrevPrim)) { + assert(curvb.nCount >= 1); + p[0] = p[-1]; + } else { + Set_Vertex(&p[0], gs.gsvertex[gs.primPrev()]); + ValidPrevPrim = true; + } + + Set_Vertex(&p[1], gs.gsvertex[gs.primIndex]); + curvb.nCount += 2; + break; + + case PRIM_TRIANGLE: + Set_Vertex(&p[0], gs.gsvertex[gs.primPrev(2)]); + Set_Vertex(&p[1], gs.gsvertex[gs.primPrev()]); + Set_Vertex(&p[2], gs.gsvertex[gs.primIndex]); + curvb.nCount += 3; + break; + + case PRIM_TRIANGLE_STRIP: + if (likely(ValidPrevPrim)) { + assert(curvb.nCount >= 2); + p[0] = p[-2]; + p[1] = p[-1]; + } else { + Set_Vertex(&p[0], gs.gsvertex[gs.primPrev(2)]); + Set_Vertex(&p[1], gs.gsvertex[gs.primPrev()]); + ValidPrevPrim = true; + } + + Set_Vertex(&p[2], gs.gsvertex[gs.primIndex]); + curvb.nCount += 3; + break; + + case PRIM_TRIANGLE_FAN: + if (likely(ValidPrevPrim)) { + assert(curvb.nCount >= 2); + VertexGPU* TriFanVert = curvb.pBufferData + gs.nTriFanVert; + p[0] = TriFanVert[0]; + p[1] = p[-1]; + } else { + Set_Vertex(&p[0], gs.gsTriFanVertex); + Set_Vertex(&p[1], gs.gsvertex[gs.primPrev(1)]); + ValidPrevPrim = true; + // Remenber the base for future processing + gs.nTriFanVert = curvb.nCount; + } + + Set_Vertex(&p[2], gs.gsvertex[gs.primIndex]); + curvb.nCount += 3; + break; + + case PRIM_SPRITE: + prev = gs.primPrev(); + last = gs.primIndex; + + // sprite is too small and AA shows lines (tek4, Mana Khemia) + gs.gsvertex[last].x += (4 * AA.x); + gs.gsvertex[last].y += (4 * AA.y); + + // might be bad sprite (KH dialog text) + //if( gs.gsvertex[prev].x == gs.gsvertex[last].x || gs.gsvertex[prev].y == gs.gsvertex[last].y ) + //return; + + // process sprite as 2 triangles. The common diagonal is 0,1 and 3,4 + Set_Vertex(&p[0], gs.gsvertex[prev]); + Set_Vertex(&p[1], gs.gsvertex[last]); + + // Only fog and Z of last vertex is valid + p[0].z = p[1].z; + p[0].f = p[1].f; + + // Duplicate the vertex + p[3] = p[0]; + p[2] = p[0]; + p[4] = p[1]; + p[5] = p[1]; + + // Move some vertex x coord to create the others corners of the sprite + p[2].s = p[1].s; + p[2].x = p[1].x; + p[5].s = p[0].s; + p[5].x = p[0].x; + + curvb.nCount += 6; + break; + + default: break; + } + + // Print DEBUG info and code assertion + switch(prim_type) { + case PRIM_TRIANGLE: + case PRIM_TRIANGLE_STRIP: + case PRIM_TRIANGLE_FAN: + assert(gs.primC >= 3); + Output_Vertex(p[2],2); + case PRIM_LINE: + case PRIM_LINE_STRIP: + case PRIM_SPRITE: + assert(gs.primC >= 2); + Output_Vertex(p[1],1); + case PRIM_POINT: + assert(gs.primC >= 1); + Output_Vertex(p[0],0); + default: break; + } +} diff --git a/plugins/zzogl-pg/opengl/ZZoglDrawing.h b/plugins/zzogl-pg/opengl/ZZoglDrawing.h new file mode 100644 index 0000000000..96e263925d --- /dev/null +++ b/plugins/zzogl-pg/opengl/ZZoglDrawing.h @@ -0,0 +1,60 @@ +/* ZZ Open GL graphics plugin + * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef ZZOGLDRAWING_H_INCLUDED +#define ZZOGLDRAWING_H_INCLUDED + +#include "Util.h" +#include "GS.h" + +extern bool __forceinline NoHighlights(int i); + +enum PRIM_TYPE { + PRIM_POINT = 0, + PRIM_LINE, + PRIM_LINE_STRIP, + PRIM_TRIANGLE, + PRIM_TRIANGLE_STRIP, + PRIM_TRIANGLE_FAN, + PRIM_SPRITE, + PRIM_DUMMY +}; + +class Kick +{ + private: + // template void Set_Vertex(VertexGPU *p, int i); + template void Set_Vertex(VertexGPU *p, Vertex &gsvertex); + void Output_Vertex(VertexGPU vert, u32 id); + bool ValidPrevPrim; + public: + Kick() { } + ~Kick() { } + + void KickVertex(bool adc); + + void DrawPrim(u32 i); + + inline void DirtyValidPrevPrim() { + ValidPrevPrim = 0; + } +}; +extern Kick* ZZKick; + +#endif // ZZOGLDRAWING_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/ZZoglFlush.cpp b/plugins/zzogl-pg/opengl/ZZoglFlush.cpp index 587cc619cb..731f0fcadc 100644 --- a/plugins/zzogl-pg/opengl/ZZoglFlush.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglFlush.cpp @@ -23,12 +23,10 @@ #include "GS.h" #include "Mem.h" -#include "zerogs.h" #include "targets.h" #include "ZZoglFlushHack.h" #include "ZZoglShaders.h" - -using namespace ZeroGS; +#include //------------------ Defines #ifndef ZEROGS_DEVBUILD @@ -122,7 +120,6 @@ void Draw(const VB& curvb) extern int g_nDepthBias; extern float g_fBlockMult; // used for old cards, that do not support Alpha-32float textures. We store block data in u16 and use it. bool g_bUpdateStencil = 1; -//u32 g_SaveFrameNum = 0; // ZZ extern ZZshProgram g_psprog; // 2 -- ZZ @@ -147,6 +144,7 @@ static u32 s_ptexNextSet[2] = {0}; // ZZ extern vector s_vecTempTextures; // temporary textures, released at the end of every frame extern bool s_bTexFlush; +extern int g_nCurVBOIndex; bool s_bWriteDepth = false; bool s_bDestAlphaTest = false; int s_ClutResolve = 0; // ZZ @@ -193,11 +191,9 @@ int s_nWireframeCount = 0; //------------------ Namespace -namespace ZeroGS -{ - VB vb[2]; float fiTexWidth[2], fiTexHeight[2]; // current tex width and height +extern vector g_vboBuffers; // VBOs for all drawing commands //u8 s_AAx = 0, s_AAy = 0; // if AAy is set, then AAx has to be set Point AA = {0,0}; @@ -211,7 +207,7 @@ void FlushTransferRanges(const tex0Info* ptex); //zz void SetTexVariables(int context, FRAGMENTSHADER* pfragment); // zz void SetTexInt(int context, FRAGMENTSHADER* pfragment, int settexint); // zz void SetAlphaVariables(const alphaInfo& ainfo); // zzz -void ResetAlphaVariables(); +//void ResetAlphaVariables(); inline void SetAlphaTestInt(pixTest curtest); @@ -221,8 +217,11 @@ inline void ProcessStencil(const VB& curvb); inline void RenderFBA(const VB& curvb, ZZshParameter sOneColor); inline void ProcessFBA(const VB& curvb, ZZshParameter sOneColor); // zz +void SetContextTarget(int context); -} +void SetWriteDepth(); +bool IsWriteDepth(); +void SetDestAlphaTest(); //------------------ Code @@ -279,6 +278,8 @@ inline void SwitchWireframeOn() } } +extern u32 ptexBilinearBlocks; + int GetTexFilter(const tex1Info& tex1) { // always force @@ -299,11 +300,11 @@ int GetTexFilter(const tex1Info& tex1) return texfilter; } -void ZeroGS::ReloadEffects() +void ReloadEffects() { #ifdef ZEROGS_DEVBUILD - for (int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) + for (int i = 0; i < ArraySize(ppsTexture); ++i) { SAFE_RELEASE_PROG(ppsTexture[i].prog); } @@ -321,7 +322,7 @@ inline void VisualBufferMessage(int context) { #if defined(WRITE_PRIM_LOGS) && defined(_DEBUG) BufferNumber++; - ZeroGS::VB& curvb = vb[context]; + VB& curvb = vb[context]; static const char* patst[8] = { "NEVER", "ALWAYS", "LESS", "LEQUAL", "EQUAL", "GEQUAL", "GREATER", "NOTEQUAL"}; static const char* pztst[4] = { "NEVER", "ALWAYS", "GEQUAL", "GREATER" }; static const char* pafail[4] = { "KEEP", "FB_ONLY", "ZB_ONLY", "RGB_ONLY" }; @@ -344,7 +345,6 @@ inline void VisualBufferMessage(int context) ZZLog::Error_Log("TGA name '%s'.", Name); free(Name); // } -// ZZLog::Debug_Log("frame: %d, buffer %ld.\n", g_SaveFrameNum, BufferNumber); ZZLog::Debug_Log("buffer %ld.\n", BufferNumber); #endif } @@ -353,12 +353,10 @@ inline void SaveRendererTarget(VB& curvb) { #ifdef _DEBUG -// if (g_bSaveFlushedFrame & 0x80000000) -// { +// Needs a # after rndr to work... // char str[255]; -// sprintf(str, "rndr%d.tga", g_SaveFrameNum); +// sprintf(str, "rndr.tga"); // SaveRenderTarget(str, curvb.prndr->fbw, curvb.prndr->fbh, 0); -// } #endif } @@ -457,27 +455,63 @@ inline bool FlushInitialTest(VB& curvb, const pixTest& curtest, int context) return false; } +inline void TargetLog(int& tbw, int& tbp0, int& tpsm, VB& curvb, bool miss) +{ +#ifdef _DEBUG + if (tbp0 == 0x3600 && tbw == 0x100) + { + if (miss) + { + ZZLog::Debug_Log("Miss %x 0x%x %d", tbw, tbp0, tpsm); + + typedef map MAPTARGETS; + + for (MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) + { + ZZLog::Debug_Log("\tRender %x 0x%x %x", itnew->second->fbw, itnew->second->fbp, itnew->second->psm); + } + + for (MAPTARGETS::iterator itnew = s_DepthRTs.mapTargets.begin(); itnew != s_DepthRTs.mapTargets.end(); ++itnew) + { + ZZLog::Debug_Log("\tDepth %x 0x%x %x", itnew->second->fbw, itnew->second->fbp, itnew->second->psm); + } + + ZZLog::Debug_Log("\tCurvb 0x%x 0x%x 0x%x %x", curvb.frame.fbp, curvb.prndr->end, curvb.prndr->fbp, curvb.prndr->fbw); + } + else + ZZLog::Debug_Log("Hit %x 0x%x %x", tbw, tbp0, tpsm); + } +#endif +} + // Try to different approach if texture target was not found inline CRenderTarget* FlushReGetTarget(int& tbw, int& tbp0, int& tpsm, VB& curvb) { // This was incorrect code CRenderTarget* ptextarg = NULL; - - if ((ptextarg == NULL) && (tpsm == PSMT8) && (conf.settings().reget)) + + if (PSMT_ISZTEX(tpsm)) + { + // try depth + ptextarg = s_DepthRTs.GetTarg(tbp0, tbw); + } + + // I wonder if either of these hacks are useful, or if I can just remove them? + if ((conf.settings().reget) && (tpsm == PSMT8)) { // check for targets with half the width. Break Valkyrie Chronicles - ptextarg = s_RTs.GetTarg(tbp0, tbw / 2, curvb); + ptextarg = s_RTs.GetTarg(tbp0, tbw / 2); if (ptextarg == NULL) { tbp0 &= ~0x7ff; - ptextarg = s_RTs.GetTarg(tbp0, tbw / 2, curvb); // mgs3 hack + ptextarg = s_RTs.GetTarg(tbp0, tbw / 2); // mgs3 hack if (ptextarg == NULL) { // check the next level (mgs3) tbp0 &= ~0xfff; - ptextarg = s_RTs.GetTarg(tbp0, tbw / 2, curvb); // mgs3 hack + ptextarg = s_RTs.GetTarg(tbp0, tbw / 2); // mgs3 hack } if (ptextarg != NULL && ptextarg->start > tbp0*256) @@ -488,14 +522,7 @@ inline CRenderTarget* FlushReGetTarget(int& tbw, int& tbp0, int& tpsm, VB& curvb } } - - if (PSMT_ISZTEX(tpsm) && (ptextarg == NULL)) - { - // try depth - ptextarg = s_DepthRTs.GetTarg(tbp0, tbw, curvb); - } - - if ((ptextarg == NULL) && (conf.settings().texture_targs)) + if ((conf.settings().texture_targs) && (ptextarg == NULL)) { // check if any part of the texture intersects the current target if (!PSMT_ISCLUT(tpsm) && (curvb.tex0.tbp0 >= curvb.frame.fbp) && ((curvb.tex0.tbp0) < curvb.prndr->end)) @@ -503,49 +530,24 @@ inline CRenderTarget* FlushReGetTarget(int& tbw, int& tbp0, int& tpsm, VB& curvb ptextarg = curvb.prndr; } } - -#ifdef _DEBUG - if (tbp0 == 0x3600 && tbw == 0x100) - { - if (ptextarg == NULL) - { - printf("Miss %x 0x%x %d\n", tbw, tbp0, tpsm); - - typedef map MAPTARGETS; - - for (MAPTARGETS::iterator itnew = s_RTs.mapTargets.begin(); itnew != s_RTs.mapTargets.end(); ++itnew) - { - printf("\tRender %x 0x%x %x\n", itnew->second->fbw, itnew->second->fbp, itnew->second->psm); - } - - for (MAPTARGETS::iterator itnew = s_DepthRTs.mapTargets.begin(); itnew != s_DepthRTs.mapTargets.end(); ++itnew) - { - printf("\tDepth %x 0x%x %x\n", itnew->second->fbw, itnew->second->fbp, itnew->second->psm); - } - - printf("\tCurvb 0x%x 0x%x 0x%x %x\n", curvb.frame.fbp, curvb.prndr->end, curvb.prndr->fbp, curvb.prndr->fbw); - } - else - printf("Hit %x 0x%x %x\n", tbw, tbp0, tpsm); - } - -#endif + + TargetLog(tbw, tbp0, tpsm, curvb, (ptextarg == NULL)); return ptextarg; } -// Find target to draw a texture, it's highly p +// Find target to draw a texture. inline CRenderTarget* FlushGetTarget(VB& curvb) { int tbw, tbp0, tpsm; CRenderTarget* ptextarg = NULL; - if (!curvb.curprim.tme) return ptextarg; + if (!curvb.curprim.tme) return ptextarg; // Which would be NULL, currently. if (curvb.bNeedTexCheck) { - printf("How it is possible?\n"); + ZZLog::Error_Log("How it is possible?"); // not yet initied, but still need to get correct target! (xeno3 ingame) tbp0 = ZZOglGet_tbp0_TexBits(curvb.uNextTex0Data[0]); tbw = ZZOglGet_tbw_TexBitsMult(curvb.uNextTex0Data[0]); @@ -558,10 +560,9 @@ inline CRenderTarget* FlushGetTarget(VB& curvb) tpsm = curvb.tex0.psm; } - ptextarg = s_RTs.GetTarg(tbp0, tbw, curvb); + ptextarg = s_RTs.GetTarg(tbp0, tbw); - if (ptextarg == NULL) - ptextarg = FlushReGetTarget(tbw, tbp0, tpsm, curvb); + if (ptextarg == NULL) ptextarg = FlushReGetTarget(tbw, tbp0, tpsm, curvb); if ((ptextarg != NULL) && !(ptextarg->status & CRenderTarget::TS_NeedUpdate)) { @@ -598,6 +599,7 @@ inline CRenderTarget* FlushGetTarget(VB& curvb) } else { + // If a texture needs updating, clear it. ptextarg = NULL; } @@ -733,7 +735,7 @@ inline void FlushDecodeClut(VB& curvb, GLuint& ptexclut) int entries = PSMT_IS8CLUT(curvb.tex0.psm) ? 256 : 16; if (curvb.tex0.csm && curvb.tex0.csa) - printf("ERROR, csm1\n"); + ZZLog::Debug_Log("ERROR, csm1."); if (PSMT_IS32BIT(curvb.tex0.cpsm)) // 32 bit { @@ -1088,6 +1090,8 @@ inline void AlphaSetStencil(bool DoIt) else glDisable(GL_STENCIL_TEST); } +//inline u32 FtoDW(float f) { return (*((u32*)&f)); } + inline void AlphaSetDepthTest(VB& curvb, const pixTest curtest, FRAGMENTSHADER* pfragment) { glDepthMask(!curvb.zbuf.zmsk && curtest.zte); @@ -1223,7 +1227,7 @@ inline void AlphaRenderStencil(VB& curvb, bool s_bDestAlphaTest, bool bCanRender inline void AlphaTest(VB& curvb) { -// printf ("%d %d %d %d %d\n", curvb.test.date, curvb.test.datm, gs.texa.aem, curvb.test.ate, curvb.test.atst ); +// ZZLog::Debug_Log("%d %d %d %d %d", curvb.test.date, curvb.test.datm, gs.texa.aem, curvb.test.ate, curvb.test.atst ); // return; // Zeydlitz changed this with a reason! It's an "Alpha more than 1 hack." @@ -1236,7 +1240,7 @@ inline void AlphaTest(VB& curvb) else { glAlphaFunc(GL_LESS, 1.0f); - printf("%d %d %d\n", curvb.test.date, curvb.test.datm, gs.texa.aem); + ZZLog::Debug_Log("%d %d %d", curvb.test.date, curvb.test.datm, gs.texa.aem); } } @@ -1447,7 +1451,6 @@ inline void AlphaSaveTarget(VB& curvb) #ifdef _DEBUG return; // Do nothing -// if( g_bSaveFlushedFrame & 0xf ) { //#ifdef _WIN32 // CreateDirectory("frames", NULL); //#else @@ -1456,13 +1459,14 @@ inline void AlphaSaveTarget(VB& curvb) // system(strdir); //#endif // char str[255]; -// sprintf(str, "frames/frame%.4d.tga", g_SaveFrameNum++); + +// Needs a # after frame to work properly. +// sprintf(str, "frames/frame.tga"); // //glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch to the backbuffer // //glFlush(); // //SaveTexture("tex.jpg", GL_TEXTURE_RECTANGLE_NV, curvb.prndr->ptex, RW(curvb.prndr->fbw), RH(curvb.prndr->fbh)); // SaveRenderTarget(str, RW(curvb.prndr->fbw), RH(curvb.prndr->fbh), 0); -// } #endif } @@ -1477,7 +1481,7 @@ inline void FlushUndoFiter(u32 dwFilterOpts) } // This is the most important function! It draws all collected info onscreen. -void ZeroGS::Flush(int context) +void Flush(int context) { FUNCLOG VB& curvb = vb[context]; @@ -1535,13 +1539,13 @@ void ZeroGS::Flush(int context) GL_REPORT_ERRORD(); } -void ZeroGS::FlushBoth() +void FlushBoth() { Flush(0); Flush(1); } -inline void ZeroGS::RenderFBA(const VB& curvb, ZZshParameter sOneColor) +inline void RenderFBA(const VB& curvb, ZZshParameter sOneColor) { // add fba to all pixels GL_STENCILFUNC(GL_ALWAYS, STENCIL_FBA, 0xff); @@ -1585,7 +1589,7 @@ inline void ZeroGS::RenderFBA(const VB& curvb, ZZshParameter sOneColor) GL_ZTEST(curvb.test.zte); } -__forceinline void ZeroGS::RenderAlphaTest(const VB& curvb, ZZshParameter sOneColor) +__forceinline void RenderAlphaTest(const VB& curvb, ZZshParameter sOneColor) { if (!g_bUpdateStencil) return; @@ -1653,7 +1657,7 @@ __forceinline void ZeroGS::RenderAlphaTest(const VB& curvb, ZZshParameter sOneCo } } -inline void ZeroGS::RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting) +inline void RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting) { //NOTE: This stencil hack for dest alpha testing ONLY works when // the geometry in one DrawPrimitive call does not overlap @@ -1670,7 +1674,7 @@ inline void ZeroGS::RenderStencil(const VB& curvb, u32 dwUsingSpecialTesting) GL_STENCILFUNC_SET(); } -inline void ZeroGS::ProcessStencil(const VB& curvb) +inline void ProcessStencil(const VB& curvb) { assert(!curvb.fba.fba); @@ -1723,7 +1727,7 @@ inline void ZeroGS::ProcessStencil(const VB& curvb) glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); } -__forceinline void ZeroGS::ProcessFBA(const VB& curvb, ZZshParameter sOneColor) +__forceinline void ProcessFBA(const VB& curvb, ZZshParameter sOneColor) { if ((curvb.frame.fbm&0x80000000)) return; @@ -1784,7 +1788,7 @@ __forceinline void ZeroGS::ProcessFBA(const VB& curvb, ZZshParameter sOneColor) GL_ZTEST(curvb.test.zte); } -void ZeroGS::SetContextTarget(int context) +void SetContextTarget(int context) { FUNCLOG VB& curvb = vb[context]; @@ -1841,7 +1845,7 @@ void ZeroGS::SetContextTarget(int context) if (curvb.prndr->status & CRenderTarget::TS_NeedUpdate) { /* if(bSetTarg) { - * printf ( " Here\n "); + * ZZLog::Debug_Log( " Here "); * if(s_bWriteDepth) { * curvb.pdepth->SetRenderTarget(1); * curvb.pdepth->SetDepthStencilSurface(); @@ -1859,7 +1863,7 @@ void ZeroGS::SetContextTarget(int context) //if( bSetTarg && ((vb[0].pdepth != vb[1].pdepth && vb[!context].bVarsSetTarg) || !vb[context].bVarsSetTarg) ) curvb.pdepth->SetDepthStencilSurface(); - if (conf.mrtdepth && ZeroGS::IsWriteDepth()) curvb.pdepth->SetRenderTarget(1); + if (conf.mrtdepth && IsWriteDepth()) curvb.pdepth->SetRenderTarget(1); if (s_ptexCurSet[0] == curvb.prndr->ptex) s_ptexCurSet[0] = 0; if (s_ptexCurSet[1] == curvb.prndr->ptex) s_ptexCurSet[1] = 0; @@ -1892,7 +1896,7 @@ void ZeroGS::SetContextTarget(int context) } -void ZeroGS::SetTexInt(int context, FRAGMENTSHADER* pfragment, int settexint) +void SetTexInt(int context, FRAGMENTSHADER* pfragment, int settexint) { FUNCLOG @@ -1900,23 +1904,14 @@ void ZeroGS::SetTexInt(int context, FRAGMENTSHADER* pfragment, int settexint) { tex0Info& tex0 = vb[context].tex0; - CMemoryTarget* pmemtarg = g_MemTargs.GetMemoryTarget(tex0, 1); + if (vb[context].bVarsTexSync) { + SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, true, pfragment, s_bForceTexFlush); + } else { + SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, false, pfragment, s_bForceTexFlush); - if (vb[context].bVarsTexSync) - { - if (vb[context].pmemtarg != pmemtarg) - { - SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, true, pfragment, s_bForceTexFlush); - vb[context].bVarsTexSync = true; - } - } - else - { - SetTexVariablesInt(context, GetTexFilter(vb[context].tex1), tex0, false, pfragment, s_bForceTexFlush); - vb[context].bVarsTexSync = true; - - INC_TEXVARS(); - } + INC_TEXVARS(); + } + vb[context].bVarsTexSync = true; } else { @@ -1929,14 +1924,14 @@ void SetTexClamping(int context, FRAGMENTSHADER* pfragment) { FUNCLOG SetShaderCaller("SetTexClamping"); - clampInfo* pclamp = &ZeroGS::vb[context].clamp; + clampInfo* pclamp = &vb[context].clamp; float4 v, v2; v.x = v.y = 0; - u32* ptex = ZeroGS::vb[context].ptexClamp; + u32* ptex = vb[context].ptexClamp; ptex[0] = ptex[1] = 0; - float fw = ZeroGS::vb[context].tex0.tw ; - float fh = ZeroGS::vb[context].tex0.th ; + float fw = vb[context].tex0.tw ; + float fh = vb[context].tex0.th ; switch (pclamp->wms) { @@ -1966,7 +1961,7 @@ void SetTexClamping(int context, FRAGMENTSHADER* pfragment) if (correctMinu != g_PrevBitwiseTexX) { g_PrevBitwiseTexX = correctMinu; - ptex[0] = ZeroGS::s_BitwiseTextures.GetTex(correctMinu, 0); + ptex[0] = s_BitwiseTextures.GetTex(correctMinu, 0); } break; @@ -2001,7 +1996,7 @@ void SetTexClamping(int context, FRAGMENTSHADER* pfragment) if (correctMinv != g_PrevBitwiseTexY) { g_PrevBitwiseTexY = correctMinv; - ptex[1] = ZeroGS::s_BitwiseTextures.GetTex(correctMinv, ptex[0]); + ptex[1] = s_BitwiseTextures.GetTex(correctMinv, ptex[0]); } break; } @@ -2015,17 +2010,8 @@ void SetTexClamping(int context, FRAGMENTSHADER* pfragment) } -// Fixme should be in float4 lib -inline bool equal_vectors(float4 a, float4 b) -{ - if (abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w) < 0.01) - return true; - else - return false; -} - int CheckTexArray[4][2][2][2] = {{{{0, }}}}; -void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment) +void SetTexVariables(int context, FRAGMENTSHADER* pfragment) { FUNCLOG @@ -2169,12 +2155,12 @@ void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment) if ( equal_vectors(valpha, valpha3) && equal_vectors(valpha2, valpha4) ) { if (CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][PSMT_ALPHAEXP(psm)] == 0) { - printf ( "Good issue %d %d %d %d\n", tex0.tfx, tex0.tcc, psm, PSMT_ALPHAEXP(psm) ); + ZZLog::Debug_Log ( "Good issue %d %d %d %d", tex0.tfx, tex0.tcc, psm, PSMT_ALPHAEXP(psm) ); CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][PSMT_ALPHAEXP(psm) ] = 1; } } else if (CheckTexArray[tex0.tfx][tex0.tcc][psm!=1][PSMT_ALPHAEXP(psm)] == -1) { - printf ("Bad array, %d %d %d %d\n\tolf valpha %f, %f, %f, %f : valpha2 %f %f %f %f\n\tnew valpha %f, %f, %f, %f : valpha2 %f %f %f %f\n", + ZZLog::Debug_Log ("Bad array, %d %d %d %d\n\tolf valpha %f, %f, %f, %f : valpha2 %f %f %f %f\n\tnew valpha %f, %f, %f, %f : valpha2 %f %f %f %f", tex0.tfx, tex0.tcc, psm, PSMT_ALPHAEXP(psm), valpha3.x, valpha3.y, valpha3.z, valpha3.w, valpha4.x, valpha4.y, valpha4.z, valpha4.w, valpha.x, valpha.y, valpha.z, valpha.w, valpha2.x, valpha2.y, valpha2.z, valpha2.w); @@ -2203,7 +2189,7 @@ void ZeroGS::SetTexVariables(int context, FRAGMENTSHADER* pfragment) } } -void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, bool CheckVB, FRAGMENTSHADER* pfragment, int force) +void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, bool CheckVB, FRAGMENTSHADER* pfragment, int force) { FUNCLOG float4 v; @@ -2363,16 +2349,16 @@ void ZeroGS::SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, //if( a.fix <= 0x80 ) { \ // dwTemp = (a.fix*2)>255?255:(a.fix*2); \ // dwTemp = dwTemp|(dwTemp<<8)|(dwTemp<<16)|0x80000000; \ -// printf("bfactor: %8.8x\n", dwTemp); \ +// ZZLog::Debug_Log("bfactor: %8.8x", dwTemp); \ // glBlendColorEXT(dwTemp); \ // } \ // else { \ -void ZeroGS::ResetAlphaVariables() { - FUNCLOG -} +//void ResetAlphaVariables() { +// FUNCLOG +//} -inline void ZeroGS::NeedFactor(int w) +inline void NeedFactor(int w) { if (bDestAlphaColor == 2) { @@ -2384,7 +2370,7 @@ inline void ZeroGS::NeedFactor(int w) //static int CheckArray[48][2] = {{0,}}; -void ZeroGS::SetAlphaVariables(const alphaInfo& a) +void SetAlphaVariables(const alphaInfo& a) { FUNCLOG bool alphaenable = true; @@ -2849,8 +2835,8 @@ void ZeroGS::SetAlphaVariables(const alphaInfo& a) if ( alphaenable && (t_rgbeq != s_rgbeq || s_srcrgb != t_srcrgb || t_dstrgb != s_dstrgb || tAlphaClamping != bAlphaClamping)) { if (CheckArray[code][(bDestAlphaColor==2)] != -1) { - printf ( "A code %d, 0x%x, 0x%x, 0x%x, 0x%x %d\n", code, alpha, one_minus_alpha, one, zero, bDestAlphaColor ); - printf ( " Difference %d %d %d %d | 0x%x 0x%x | 0x%x 0x%x | 0x%x 0x%x | %d %d\n", + ZZLog::Debug_Log( "A code %d, 0x%x, 0x%x, 0x%x, 0x%x %d", code, alpha, one_minus_alpha, one, zero, bDestAlphaColor ); + ZZLog::Debug_Log( " Difference %d %d %d %d | 0x%x 0x%x | 0x%x 0x%x | 0x%x 0x%x | %d %d", code, a.a, a.b, a.d, t_rgbeq, s_rgbeq, t_srcrgb, s_srcrgb, t_dstrgb, s_dstrgb, tAlphaClamping, bAlphaClamping); CheckArray[code][(bDestAlphaColor==2)] = -1; @@ -2858,7 +2844,7 @@ void ZeroGS::SetAlphaVariables(const alphaInfo& a) } else if (CheckArray[code][(bDestAlphaColor==2)] == 0){ - printf ( "Add good code %d %d, psm %d destA %d\n", code, a.c, vb[icurctx].prndr->psm, bDestAlphaColor); + ZZLog::Debug_Log( "Add good code %d %d, psm %d destA %d", code, a.c, vb[icurctx].prndr->psm, bDestAlphaColor); CheckArray[code][(bDestAlphaColor==2)] = 1; }*/ @@ -2877,7 +2863,7 @@ void ZeroGS::SetAlphaVariables(const alphaInfo& a) INC_ALPHAVARS(); } -void ZeroGS::SetWriteDepth() +void SetWriteDepth() { FUNCLOG @@ -2888,26 +2874,26 @@ void ZeroGS::SetWriteDepth() } } -bool ZeroGS::IsWriteDepth() +bool IsWriteDepth() { FUNCLOG return s_bWriteDepth; } -bool ZeroGS::IsWriteDestAlphaTest() +bool IsWriteDestAlphaTest() { FUNCLOG return s_bDestAlphaTest; } -void ZeroGS::SetDestAlphaTest() +void SetDestAlphaTest() { FUNCLOG s_bDestAlphaTest = true; s_nWriteDestAlphaTest = 4; } -void ZeroGS::SetTexFlush() +void SetTexFlush() { FUNCLOG s_bTexFlush = true; diff --git a/plugins/zzogl-pg/opengl/ZZoglFlushHack.cpp b/plugins/zzogl-pg/opengl/ZZoglFlushHack.cpp index 03cfaca4d4..b1e311a5d7 100644 --- a/plugins/zzogl-pg/opengl/ZZoglFlushHack.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglFlushHack.cpp @@ -464,7 +464,7 @@ static const u32 MAX_FRAMES = 500; static GSFrameInfo FrameAppear[MAX_FRAMES]; static u32 Rec_Numbers = 0; -void RecordNewFrames(ZeroGS::VB& curvb, GSFrameInfo fi) { +void RecordNewFrames(VB& curvb, GSFrameInfo fi) { if (Rec_Numbers >= MAX_FRAMES) return; @@ -486,12 +486,12 @@ void RecordNewFrames(ZeroGS::VB& curvb, GSFrameInfo fi) { // Dump a nice picture of the frame char filename[255]; sprintf(filename, "SkipFlushFrame_%d__%d.tga", g_SkipFlushFrame, Rec_Numbers); - ZeroGS::SaveRenderTarget(filename, curvb.prndr->fbw, curvb.prndr->fbh, 0); + SaveRenderTarget(filename, curvb.prndr->fbw, curvb.prndr->fbh, 0); } } #endif -__forceinline bool IsBadFrame(ZeroGS::VB& curvb) +__forceinline bool IsBadFrame(VB& curvb) { GSFrameInfo fi; diff --git a/plugins/zzogl-pg/opengl/ZZoglFlushHack.h b/plugins/zzogl-pg/opengl/ZZoglFlushHack.h index 7b9302aa5d..a23572e9e2 100644 --- a/plugins/zzogl-pg/opengl/ZZoglFlushHack.h +++ b/plugins/zzogl-pg/opengl/ZZoglFlushHack.h @@ -27,7 +27,8 @@ #define ZZOGL_FLUSH_HACK_H_INCLUDED #include "GS.h" -#include "zerogs.h" +#include "targets.h" +#include "ZZoglVB.h" extern int g_SkipFlushFrame; @@ -79,5 +80,5 @@ void GSC_StarOcean3(const GSFrameInfo& fi, int& skip); void GSC_ValkyrieProfile2(const GSFrameInfo& fi, int& skip); void GSC_RadiataStories(const GSFrameInfo& fi, int& skip); -extern bool IsBadFrame(ZeroGS::VB& curvb); +extern bool IsBadFrame(VB& curvb); #endif diff --git a/plugins/zzogl-pg/opengl/ZZoglMath.h b/plugins/zzogl-pg/opengl/ZZoglMath.h index 1754a9ae8c..2e31aebb90 100644 --- a/plugins/zzogl-pg/opengl/ZZoglMath.h +++ b/plugins/zzogl-pg/opengl/ZZoglMath.h @@ -26,6 +26,7 @@ #endif #include +#include "Pcsx2Defs.h" //#define ZZ_MMATH @@ -194,6 +195,15 @@ class Vector4 y = ((color >> 8) & 0xff) / 255.0f; z = ((color >> 16) & 0xff) / 255.0f; } + + bool equal_vectors(const Vector4& v) + { + if (abs(x - v.x) + abs(y - v.y) + abs(z - v.z) + abs(w - v.w) < 0.01) + return true; + else + return false; + } + }; typedef Vector4 float4; @@ -443,6 +453,14 @@ class float4 return float4(_mm_cmple_ps(v1.m, v2.m)); } + bool equal_vectors(const float4& v) + { + if (abs(x - v.x) + abs(y - v.y) + abs(z - v.z) + abs(w - v.w) < 0.01) + return true; + else + return false; + } + // This looked interesting, so I thought I'd include it... template float4 shuffle() const diff --git a/plugins/zzogl-pg/opengl/ZZoglSave.cpp b/plugins/zzogl-pg/opengl/ZZoglSave.cpp index 5ff3724625..b0e2ebc002 100644 --- a/plugins/zzogl-pg/opengl/ZZoglSave.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglSave.cpp @@ -20,9 +20,10 @@ // Save and Load. //------------------ Includes -#include "zerogs.h" -#include "targets.h" + #include "Util.h" +#include "ZZoglVB.h" +extern void ZZGSStateReset(); //----------------------- Defines #define VBSAVELIMIT ((u32)((u8*)&vb[0].nNextFrameHeight-(u8*)&vb[0])) @@ -44,7 +45,10 @@ char *libraryNameX = "ZeroGS Playground OpenGL "; extern char *libraryName; extern u32 s_uTex1Data[2][2], s_uClampData[2]; -int ZeroGS::Save(s8* pbydata) +void SetFogColor(u32 fog); +void SetFogColor(GIFRegFOGCOL* fog); + +int ZZSave(s8* pbydata) { if (pbydata == NULL) return 40 + MEMORY_END + sizeof(gs) + 2*VBSAVELIMIT + 2*sizeof(frameInfo) + 4 + 256*4; @@ -85,7 +89,10 @@ int ZeroGS::Save(s8* pbydata) return 0; } -bool ZeroGS::Load(s8* pbydata) +extern u32 s_uFramebuffer; +extern int g_nCurVBOIndex; + +bool ZZLoad(s8* pbydata) { memset(s_uTex1Data, 0, sizeof(s_uTex1Data)); memset(s_uClampData, 0, sizeof(s_uClampData)); @@ -99,7 +106,7 @@ bool ZeroGS::Load(s8* pbydata) { g_MemTargs.Destroy(); - GSStateReset(); + ZZGSStateReset(); pbydata += 32; //int context = *(int*)pbydata; diff --git a/plugins/zzogl-pg/opengl/ZZoglShaders.cpp b/plugins/zzogl-pg/opengl/ZZoglShaders.cpp index 136606cbf6..dfe69c44e6 100644 --- a/plugins/zzogl-pg/opengl/ZZoglShaders.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglShaders.cpp @@ -21,10 +21,11 @@ // ZZogl Shader manipulation functions. //------------------- Includes -#include "zerogs.h" +#include "Util.h" #include "ZZoglShaders.h" #include "zpipe.h" - +#include +#include #ifdef _WIN32 # include "Win32.h" @@ -33,8 +34,6 @@ extern HINSTANCE hInst; // ----------------- Defines -using namespace ZeroGS; - #define TEXWRAP_REPEAT 0 #define TEXWRAP_CLAMP 1 #define TEXWRAP_REGION_REPEAT 2 @@ -68,7 +67,13 @@ using namespace ZeroGS; //------------------ Constants +// Used in a logarithmic Z-test, as (1-o(1))/log(MAX_U32). +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); + +#ifdef _DEBUG const static char* g_pTexTypes[] = { "32", "tex32", "clut32", "tex32to16", "tex16to8h" }; +#endif +const char* g_pShaders[4] = { "full", "reduced", "accurate", "accurate-reduced" }; // ----------------- Global Variables @@ -87,16 +92,20 @@ char* EFFECT_DIR; bool g_bCRTCBilinear = true; -namespace ZeroGS { - float4 g_vdepth, vlogz; - FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; - FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; - FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; - FRAGMENTSHADER ppsCRTC[2], ppsCRTC24[2], ppsCRTCTarg[2]; - VERTEXSHADER pvsBitBlt; - - inline bool LoadEffects(); -} +float4 g_vdepth, vlogz; +FRAGMENTSHADER ppsBitBlt[2], ppsBitBltDepth, ppsOne; +FRAGMENTSHADER ppsBaseTexture, ppsConvert16to32, ppsConvert32to16; +FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; +FRAGMENTSHADER ppsCRTC[2], ppsCRTC24[2], ppsCRTCTarg[2]; +VERTEXSHADER pvsBitBlt; + +extern u32 ptexBlocks; // holds information on block tiling. It's texture number in OpenGL -- if 0 than such texture +extern u32 ptexConv16to32; // does not exists. This textures should be created on start and released on finish. +extern u32 ptexBilinearBlocks; +extern u32 ptexConv32to16; + +inline bool LoadEffects(); +extern bool s_bWriteDepth; struct SHADERHEADER { @@ -219,7 +228,7 @@ bool ZZshCreateOpenShadersFile() { // test if ps2hw.fx exists char tempstr[255]; char curwd[255]; - getcwd(curwd, ARRAY_SIZE(curwd)); + getcwd(curwd, ArraySize(curwd)); strcpy(tempstr, "/plugins/"); sprintf(EFFECT_NAME, "%sps2hw.fx", tempstr); @@ -506,7 +515,7 @@ void SetupVertexProgramParameters(ZZshProgram prog, int context) SetupFragmentProgramParameters(&fragment, !!(Index&SH_CONTEXT1), 0); \ } \ -inline bool ZeroGS::LoadEffects() +inline bool LoadEffects() { assert( s_lpShaderResources != NULL ); @@ -530,7 +539,7 @@ inline bool ZeroGS::LoadEffects() } // clear the textures - for(u16 i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + for(u16 i = 0; i < ArraySize(ppsTexture); ++i) { SAFE_RELEASE_PROG(ppsTexture[i].prog); ppsTexture[i].prog = NULL; } @@ -637,7 +646,7 @@ FRAGMENTSHADER* ZZshLoadShadeEffect(int type, int texfilter, int fog, int testae int index = GET_SHADER_INDEX(type, texfilter, texwrap, fog, s_bWriteDepth, testaem, exactcolor, context, 0); - assert( index < ARRAY_SIZE(ppsTexture) ); + assert( index < ArraySize(ppsTexture) ); FRAGMENTSHADER* pf = ppsTexture+index; if( pbFailed != NULL ) *pbFailed = false; @@ -711,10 +720,10 @@ FRAGMENTSHADER* ZZshLoadShadeEffect(int type, int texfilter, int fog, int testae SET_PSFILENAME(fragment, name); \ } \ -inline bool ZeroGS::LoadEffects() +inline bool LoadEffects() { // clear the textures - for(int i = 0; i < ARRAY_SIZE(ppsTexture); ++i) { + for(int i = 0; i < ArraySize(ppsTexture); ++i) { SAFE_RELEASE_PROG(ppsTexture[i].prog); } diff --git a/plugins/zzogl-pg/opengl/ZZoglShaders.h b/plugins/zzogl-pg/opengl/ZZoglShaders.h index a941702c5a..a447814144 100644 --- a/plugins/zzogl-pg/opengl/ZZoglShaders.h +++ b/plugins/zzogl-pg/opengl/ZZoglShaders.h @@ -29,9 +29,11 @@ // Just bitmask for different type of shaders #define SHADER_REDUCED 1 // equivalent to ps2.0 #define SHADER_ACCURATE 2 // for older cards with less accurate math (ps2.x+) -// For output -const static char* g_pShaders[] = { "full", "reduced", "accurate", "accurate-reduced" }; +#include "ZZoglMath.h" +#include "GS.h" + +// For output #define NVIDIA_CG_API // --------------------------- API abstraction level -------------------------------- @@ -54,7 +56,7 @@ inline bool ZZshActiveParameter(ZZshParameter param) {return (param !=NULL); } #endif // end NVIDIA cg-toolkit API -const static char* g_pPsTexWrap[] = { "-DREPEAT", "-DCLAMP", "-DREGION_REPEAT", NULL }; +//const static char* g_pPsTexWrap[] = { "-DREPEAT", "-DCLAMP", "-DREGION_REPEAT", NULL }; enum ZZshShaderType {ZZ_SH_ZERO, ZZ_SH_REGULAR, ZZ_SH_REGULAR_FOG, ZZ_SH_TEXTURE, ZZ_SH_TEXTURE_FOG, ZZ_SH_CRTC}; // We have "compatible" shaders, as RegularFogVS and RegularFogPS. if don't need to wory about incompatible shaders @@ -174,7 +176,6 @@ struct VERTEXSHADER int ParametersStart, ParametersFinish; }; -namespace ZeroGS { extern float4 g_vdepth; extern float4 vlogz; extern VERTEXSHADER pvsBitBlt; @@ -183,7 +184,6 @@ namespace ZeroGS { extern FRAGMENTSHADER ppsRegular[4], ppsTexture[NUM_SHADERS]; extern FRAGMENTSHADER ppsCRTC[2], ppsCRTC24[2], ppsCRTCTarg[2]; -} // ------------------------- Functions ------------------------------- @@ -225,8 +225,7 @@ extern bool ZZshLoadExtraEffects(); extern FRAGMENTSHADER* ZZshLoadShadeEffect(int type, int texfilter, int fog, int testaem, int exactcolor, const clampInfo& clamp, int context, bool* pbFailed); -namespace ZeroGS { // only sets a limited amount of state (for Update) void SetTexVariablesInt(int context, int bilinear, const tex0Info& tex0, bool CheckVB, FRAGMENTSHADER* pfragment, int force); -} + #endif diff --git a/plugins/zzogl-pg/opengl/ZZoglShoots.cpp b/plugins/zzogl-pg/opengl/ZZoglShoots.cpp index 6dfd0f5418..7455f0fd6e 100644 --- a/plugins/zzogl-pg/opengl/ZZoglShoots.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglShoots.cpp @@ -20,6 +20,7 @@ // Texture and avi saving to file functions //------------------ Includes + #include "Util.h" #if defined(_WIN32) # include # include @@ -27,9 +28,9 @@ #endif #include -#include "zerogs.h" #include "targets.h" #include "Mem.h" +#include "ZZoglShoots.h" // AVI Capture int s_avicapturing = 0; @@ -43,7 +44,7 @@ extern "C" #define HAVE_BOOLEAN #endif -#include "jpeglib.h" // This library want to be after zerogs.h +#include "jpeglib.h" } //------------------ Defines @@ -65,14 +66,14 @@ string strSnapshot; //------------------ Code // Set variables need to made a snapshoot when it's possible -void ZeroGS::SaveSnapshot(const char* filename) +void SaveSnapshot(const char* filename) { g_bMakeSnapshot = true; strSnapshot = filename; } // Save curent renderer in jpeg or TGA format -bool ZeroGS::SaveRenderTarget(const char* filename, int width, int height, int jpeg) +bool SaveRenderTarget(const char* filename, int width, int height, int jpeg) { bool bflip = height < 0; height = abs(height); @@ -100,7 +101,7 @@ bool ZeroGS::SaveRenderTarget(const char* filename, int width, int height, int j } // Save selected texture as TGA -bool ZeroGS::SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height) +bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height) { vector data(width*height); glBindTexture(textarget, tex); @@ -112,7 +113,7 @@ bool ZeroGS::SaveTexture(const char* filename, u32 textarget, u32 tex, int width } // save image as JPEG -bool ZeroGS::SaveJPEG(const char* filename, int image_width, int image_height, const void* pdata, int quality) +bool SaveJPEG(const char* filename, int image_width, int image_height, const void* pdata, int quality) { u8* image_buffer = new u8[image_width * image_height * 3]; u8* psrc = (u8*)pdata; @@ -286,7 +287,7 @@ __attribute__((packed)); #endif // Save image as TGA -bool ZeroGS::SaveTGA(const char* filename, int width, int height, void* pdata) +bool SaveTGA(const char* filename, int width, int height, void* pdata) { int err = 0; TGA_HEADER hdr; @@ -314,7 +315,7 @@ bool ZeroGS::SaveTGA(const char* filename, int width, int height, void* pdata) // AVI capture stuff // AVI start -- set needed global variables -void ZeroGS::StartCapture() +void StartCapture() { if (conf.captureAvi()) return; if (!s_aviinit) @@ -338,7 +339,7 @@ void ZeroGS::StartCapture() } // Stop. -void ZeroGS::StopCapture() +void StopCapture() { if (!conf.captureAvi()) return; s_avicapturing = 0; @@ -347,25 +348,25 @@ void ZeroGS::StopCapture() } // And capture frame does not work on linux. -void ZeroGS::CaptureFrame() +void CaptureFrame() { if ((!s_avicapturing) || (!s_aviinit)) return; - vector data(nBackbufferWidth*nBackbufferHeight); - glReadPixels(0, 0, nBackbufferWidth, nBackbufferHeight, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); + vector data(GLWin.backbuffer.w * GLWin.backbuffer.h); + glReadPixels(0, 0, GLWin.backbuffer.w, GLWin.backbuffer.h, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); if (glGetError() != GL_NO_ERROR) return; #ifdef _WIN32 int fps = SMODE1->CMOD == 3 ? 50 : 60; - bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, nBackbufferWidth, nBackbufferHeight, 32, &data[0]); + bool bSuccess = ADD_FRAME_FROM_DIB_TO_AVI("AAAA", fps, GLWin.backbuffer.w, GLWin.backbuffer.h, 32, &data[0]); if (!bSuccess) { s_avicapturing = 0; STOP_AVI(); - ZeroGS::AddMessage("Failed to create avi"); + ZZAddMessage("Failed to create avi"); return; } @@ -376,7 +377,7 @@ void ZeroGS::CaptureFrame() // It's nearly the same as save texture void -ZeroGS::SaveTex(tex0Info* ptex, int usevid) +SaveTex(tex0Info* ptex, int usevid) { vector data(ptex->tw*ptex->th); vector srcdata; @@ -617,7 +618,7 @@ ZeroGS::SaveTex(tex0Info* ptex, int usevid) // Do the save texture and return file name of it // Do not forget to call free(), other wise there would be memory leak! -char* ZeroGS::NamedSaveTex(tex0Info* ptex, int usevid) +char* NamedSaveTex(tex0Info* ptex, int usevid) { SaveTex(ptex, usevid); char* Name = (char*)malloc(TGA_FILE_NAME_MAX_LENGTH); @@ -631,7 +632,7 @@ char* ZeroGS::NamedSaveTex(tex0Info* ptex, int usevid) } // Special function, which is safe to call from any other file, without aviutils problems. -void ZeroGS::Stop_Avi() +void Stop_Avi() { #ifdef _WIN32 STOP_AVI(); @@ -640,7 +641,7 @@ void ZeroGS::Stop_Avi() #endif } -void ZeroGS::Delete_Avi_Capture() +void Delete_Avi_Capture() { if (s_aviinit) { diff --git a/plugins/zzogl-pg/opengl/ZZoglShoots.h b/plugins/zzogl-pg/opengl/ZZoglShoots.h new file mode 100644 index 0000000000..98bb1383df --- /dev/null +++ b/plugins/zzogl-pg/opengl/ZZoglShoots.h @@ -0,0 +1,35 @@ +/* ZZ Open GL graphics plugin + * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef ZZOGLSHOOTS_H_INCLUDED +#define ZZOGLSHOOTS_H_INCLUDED + +void SaveSnapshot(const char* filename); +bool SaveRenderTarget(const char* filename, int width, int height, int jpeg); +bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); +bool SaveJPEG(const char* filename, int width, int height, const void* pdata, int quality); +bool SaveTGA(const char* filename, int width, int height, void* pdata); +void Stop_Avi(); +void Delete_Avi_Capture(); + +void StartCapture(); +void StopCapture(); +void CaptureFrame(); + +#endif // ZZOGLSHOOTS_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/ZZoglVB.cpp b/plugins/zzogl-pg/opengl/ZZoglVB.cpp index acda07d386..a1604b2be2 100644 --- a/plugins/zzogl-pg/opengl/ZZoglVB.cpp +++ b/plugins/zzogl-pg/opengl/ZZoglVB.cpp @@ -21,12 +21,13 @@ // VB stands for Visual Buffer, as I think //------------------- Includes -#include "zerogs.h" + #include "Util.h" #include "targets.h" +#include "ZZoglVB.h" #include "GS.h" #include "Mem.h" +extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height -using namespace ZeroGS; // ----------------- Defines #define MINMAX_SHIFT 3 @@ -37,20 +38,20 @@ int maxmin = 608; // ----------------- Code // Constructor. Set width and height to 1 -ZeroGS::VB::VB() +VB::VB() { - memset(this, 0, sizeof(ZeroGS::VB)); + memset(this, 0, sizeof(VB)); tex0.tw = 1; tex0.th = 1; } // Destructor -ZeroGS::VB::~VB() +VB::~VB() { Destroy(); } -void ZeroGS::VB::Destroy() +void VB::Destroy() { _aligned_free(pBufferData); pBufferData = NULL; @@ -65,7 +66,7 @@ int ConstraintReason; // Return number of 64-pixels block, that guaranted could be hold in memory // from gsfb.fbp and tbp (textrure pase), zbuf.zbp (Z-buffer), frame.fbp // (previous frame). -inline int ZeroGS::VB::FindMinimalMemoryConstrain(int tbp, int maxpos) +inline int VB::FindMinimalMemoryConstrain(int tbp, int maxpos) { int MinConstraint = maxpos; @@ -116,7 +117,7 @@ inline int ZeroGS::VB::FindMinimalMemoryConstrain(int tbp, int maxpos) // Return number of 64 pizel words that could be placed in Z-Buffer // If no Z-buffer present return old constraint -inline int ZeroGS::VB::FindZbufferMemoryConstrain(int tbp, int maxpos) +inline int VB::FindZbufferMemoryConstrain(int tbp, int maxpos) { int MinConstraint = maxpos; @@ -147,7 +148,7 @@ inline int GetScissorY(int y) //There is several reasons to limit a height of frame: maximum buffer size, calculated size //from fbw and fbh and scissoring. -inline int ZeroGS::VB::FindMinimalHeightConstrain(int maxpos) +inline int VB::FindMinimalHeightConstrain(int maxpos) { int MinConstraint = maxpos; @@ -176,7 +177,7 @@ inline int ZeroGS::VB::FindMinimalHeightConstrain(int maxpos) // 32 bit frames have additional constraints to frame // maxpos was maximum length of frame at normal constraints -inline void ZeroGS::VB::CheckFrame32bitRes(int maxpos) +inline void VB::CheckFrame32bitRes(int maxpos) { int fbh = frame.fbh; @@ -215,7 +216,7 @@ inline void ZeroGS::VB::CheckFrame32bitRes(int maxpos) // 4Mb memory in 64 bit (4 bytes) words. // |------------------------|---------------------|----------|----------|---------------------| // 0 gsfb.fbp zbuff.zpb tbp frame.fbp 2^20/64 -inline int ZeroGS::VB::CheckFrameAddConstraints(int tbp) +inline int VB::CheckFrameAddConstraints(int tbp) { if (gsfb.fbw <= 0) { @@ -263,7 +264,7 @@ inline int ZeroGS::VB::CheckFrameAddConstraints(int tbp) // Check if after resizing new depth target is needed to be used. // it returns 2 if a new depth target is used. -inline int ZeroGS::VB::CheckFrameResolveDepth(int tbp) +inline int VB::CheckFrameResolveDepth(int tbp) { int result = 0; CDepthTarget* pprevdepth = pdepth; @@ -289,7 +290,7 @@ inline int ZeroGS::VB::CheckFrameResolveDepth(int tbp) // Check if after resizing, a new render target is needed to be used. Also perform deptarget check. // Returns 1 if only 1 render target is changed and 3 -- if both. -inline int ZeroGS::VB::CheckFrameResolveRender(int tbp) +inline int VB::CheckFrameResolveRender(int tbp) { int result = 0; @@ -335,7 +336,7 @@ inline int ZeroGS::VB::CheckFrameResolveRender(int tbp) } // After frame resetting, it is possible that 16 to 32 or 32 to 16 (color bits) conversion should be made. -inline void ZeroGS::VB::CheckFrame16vs32Conversion() +inline void VB::CheckFrame16vs32Conversion() { if (prndr->status & CRenderTarget::TS_NeedConvert32) { @@ -355,9 +356,11 @@ inline void ZeroGS::VB::CheckFrame16vs32Conversion() } } +void SetContextTarget(int context); + // A lot of times, the target is too big and overwrites the texture. // If tbp != 0, use it to bound. -void ZeroGS::VB::CheckFrame(int tbp) +void VB::CheckFrame(int tbp) { GL_REPORT_ERRORD(); @@ -388,7 +391,7 @@ void ZeroGS::VB::CheckFrame(int tbp) if ((prndr != NULL) && (prndr->psm != gsfb.psm)) { // behavior for dest alpha varies - ResetAlphaVariables(); +// ResetAlphaVariables(); } bChanged = CheckFrameResolveRender(tbp); @@ -407,11 +410,11 @@ void ZeroGS::VB::CheckFrame(int tbp) } // This is the case, most easy to perform, when nothing was changed -inline void ZeroGS::VB::FlushTexUnchangedClutDontUpdate() +inline void VB::FlushTexUnchangedClutDontUpdate() { if (ZZOglGet_cld_TexBits(uNextTex0Data[1])) { - ZeroGS::texClutWrite(ictx); + texClutWrite(ictx); // invalidate to make sure target didn't change! bVarsTexSync = false; } @@ -419,9 +422,9 @@ inline void ZeroGS::VB::FlushTexUnchangedClutDontUpdate() // The second of easy branch. We does not change storage model, so we don't need to // update anything except texture itself -inline void ZeroGS::VB::FlushTexClutDontUpdate() +inline void VB::FlushTexClutDontUpdate() { - if (!ZZOglClutStorageUnchanged(uCurTex0Data, uNextTex0Data)) ZeroGS::Flush(ictx); + if (!ZZOglClutStorageUnchanged(uCurTex0Data, uNextTex0Data)) Flush(ictx); // clut memory isn't going to be loaded so can ignore, but at least update CSA and CPSM! uCurTex0Data[1] = (uCurTex0Data[1] & CPSM_CSA_NOTMASK) | (uNextTex0Data[1] & CPSM_CSA_BITMASK); @@ -429,14 +432,14 @@ inline void ZeroGS::VB::FlushTexClutDontUpdate() tex0.csa = ZZOglGet_csa_TexBits(uNextTex0Data[1]); tex0.cpsm = ZZOglGet_cpsm_TexBits(uNextTex0Data[1]); - ZeroGS::texClutWrite(ictx); + texClutWrite(ictx); bVarsTexSync = false; } // Set texture variables after big change -inline void ZeroGS::VB::FlushTexSetNewVars(u32 psm) +inline void VB::FlushTexSetNewVars(u32 psm) { tex0.tbp0 = ZZOglGet_tbp0_TexBits(uNextTex0Data[0]); tex0.tbw = ZZOglGet_tbw_TexBitsMult(uNextTex0Data[0]); @@ -447,13 +450,13 @@ inline void ZeroGS::VB::FlushTexSetNewVars(u32 psm) tex0.tcc = ZZOglGet_tcc_TexBits(uNextTex0Data[1]); tex0.tfx = ZZOglGet_tfx_TexBits(uNextTex0Data[1]); - ZeroGS::fiTexWidth[ictx] = (1 / 16.0f) / tex0.tw; - ZeroGS::fiTexHeight[ictx] = (1 / 16.0f) / tex0.th; + fiTexWidth[ictx] = (1 / 16.0f) / tex0.tw; + fiTexHeight[ictx] = (1 / 16.0f) / tex0.th; } // Flush == draw on screen // This function made VB state consistant before real Flush. -void ZeroGS::VB::FlushTexData() +void VB::FlushTexData() { GL_REPORT_ERRORD(); @@ -487,7 +490,7 @@ void ZeroGS::VB::FlushTexData() } // Made the full update - ZeroGS::Flush(ictx); + Flush(ictx); bVarsTexSync = false; bTexConstsSync = false; @@ -497,7 +500,7 @@ void ZeroGS::VB::FlushTexData() FlushTexSetNewVars(psm); - if (PSMT_ISCLUT(psm)) ZeroGS::CluttingForFlushedTex(&tex0, uNextTex0Data[1], ictx) ; + if (PSMT_ISCLUT(psm)) CluttingForFlushedTex(&tex0, uNextTex0Data[1], ictx) ; GL_REPORT_ERRORD(); } } diff --git a/plugins/zzogl-pg/opengl/ZZoglVB.h b/plugins/zzogl-pg/opengl/ZZoglVB.h new file mode 100644 index 0000000000..7b5684177e --- /dev/null +++ b/plugins/zzogl-pg/opengl/ZZoglVB.h @@ -0,0 +1,158 @@ +/* ZZ Open GL graphics plugin + * Copyright (c)2009-2010 zeydlitz@gmail.com, arcum42@gmail.com + * Based on Zerofrog's ZeroGS KOSMOS (c)2005-2008 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +// Zerogs:VB implementation. +// VB stands for Visual Buffer, as I think + +#ifndef ZZOGLVB_H_INCLUDED +#define ZZOGLVB_H_INCLUDED + +#include "targets.h" + +extern const GLenum primtype[8]; + +class VB +{ + public: + VB(); + ~VB(); + + void Destroy(); + + inline bool CheckPrim() + { + static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) + + if ((PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim]) + return nCount > 0; + + return false; + } + + void SetCurrentPrim() + { + curprim._val = prim->_val; + curprim.prim = prim->prim; + } + + void CheckFrame(int tbp); + + // context specific state + Point offset; + Rect2 scissor; + tex0Info tex0; + tex1Info tex1; + miptbpInfo miptbp0; + miptbpInfo miptbp1; + alphaInfo alpha; + fbaInfo fba; + clampInfo clamp; + pixTest test; + u32 ptexClamp[2]; // textures for x and y dir region clamping + + void FlushTexData(); + inline int CheckFrameAddConstraints(int tbp); + inline void CheckScissors(int maxpos); + inline void CheckFrame32bitRes(int maxpos); + inline int FindMinimalMemoryConstrain(int tbp, int maxpos); + inline int FindZbufferMemoryConstrain(int tbp, int maxpos); + inline int FindMinimalHeightConstrain(int maxpos); + + inline int CheckFrameResolveRender(int tbp); + inline void CheckFrame16vs32Conversion(); + inline int CheckFrameResolveDepth(int tbp); + + inline void FlushTexUnchangedClutDontUpdate() ; + inline void FlushTexClutDontUpdate() ; + inline void FlushTexClutting() ; + inline void FlushTexSetNewVars(u32 psm) ; + + // Increase the size of pbuf + void IncreaseVertexBuffer() + { + assert(pBufferData != NULL); + nNumVertices *= 2; + VertexGPU* ptemp = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU) * nNumVertices, 256); + memcpy_amd(ptemp, pBufferData, sizeof(VertexGPU) * nCount); + assert(nCount <= nNumVertices); + _aligned_free(pBufferData); + pBufferData = ptemp; + } + + void Init(int nVerts) + { + if (pBufferData == NULL && nVerts > 0) + { + pBufferData = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU) * nVerts, 256); + nNumVertices = nVerts; + } + + nCount = 0; + } + + u8 bNeedFrameCheck; + u8 bNeedZCheck; + u8 bNeedTexCheck; + u8 dummy0; + + union + { + struct + { + u8 bTexConstsSync; // only pixel shader constants that context owns + u8 bVarsTexSync; // texture info + u8 bVarsSetTarg; + u8 dummy1; + }; + + u32 bSyncVars; + }; + + int ictx; + VertexGPU* pBufferData; // current allocated data + + int nNumVertices; // size of pBufferData in terms of VertexGPU objects + int nCount; + primInfo curprim; // the previous prim the current buffers are set to + + zbufInfo zbuf; + frameInfo gsfb; // the real info set by FRAME cmd + frameInfo frame; + int zprimmask; // zmask for incoming points + + union + { + u32 uCurTex0Data[2]; // current tex0 data + GIFRegTEX0 uCurTex0; + }; + u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 + + //int nFrameHeights[8]; // frame heights for the past frame changes + int nNextFrameHeight; + + CMemoryTarget* pmemtarg; // the current mem target set + CRenderTarget* prndr; + CDepthTarget* pdepth; + +}; + +// VB variables +extern VB vb[2]; + +#endif // ZZOGLVB_H_INCLUDED diff --git a/plugins/zzogl-pg/opengl/memcpy_amd.cpp b/plugins/zzogl-pg/opengl/memcpy_amd.cpp deleted file mode 100644 index 94cb955ed6..0000000000 --- a/plugins/zzogl-pg/opengl/memcpy_amd.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/****************************************************************************** - - Copyright (c) 2001 Advanced Micro Devices, Inc. - - LIMITATION OF LIABILITY: THE MATERIALS ARE PROVIDED *AS IS* WITHOUT ANY - EXPRESS OR IMPLIED WARRANTY OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, - NONINFRINGEMENT OF THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY - PARTICULAR PURPOSE. IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY - DAMAGES WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, - BUSINESS INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR - INABILITY TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY - OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE EXCLUSION OR LIMITATION - OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE LIMITATION MAY - NOT APPLY TO YOU. - - AMD does not assume any responsibility for any errors which may appear in the - Materials nor any responsibility to support or update the Materials. AMD retains - the right to make changes to its test specifications at any time, without notice. - - NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any - further information, software, technical information, know-how, or show-how - available to you. - - So that all may benefit from your experience, please report any problems - or suggestions about this software to 3dsdk.support@amd.com - - AMD Developer Technologies, M/S 585 - Advanced Micro Devices, Inc. - 5900 E. Ben White Blvd. - Austin, TX 78741 - 3dsdk.support@amd.com -******************************************************************************/ - -#include - -/***************************************************************************** -MEMCPY_AMD.CPP -******************************************************************************/ - -// Very optimized memcpy() routine for AMD Athlon and Duron family. -// This code uses any of FOUR different basic copy methods, depending -// on the transfer size. -// NOTE: Since this code uses MOVNTQ (also known as "Non-Temporal MOV" or -// "Streaming Store"), and also uses the software prefetch instructions, -// be sure you're running on Athlon/Duron or other recent CPU before calling! - -#define TINY_BLOCK_COPY 64 // upper limit for movsd type copy -// The smallest copy uses the X86 "movsd" instruction, in an optimized -// form which is an "unrolled loop". - -#define IN_CACHE_COPY 2 * 1024 // upper limit for movq/movq copy w/SW prefetch -// Next is a copy that uses the MMX registers to copy 8 bytes at a time, -// also using the "unrolled loop" optimization. This code uses -// the software prefetch instruction to get the data into the cache. - -#define UNCACHED_COPY 4 * 1024 // upper limit for movq/movntq w/SW prefetch -// For larger blocks, which will spill beyond the cache, it's faster to -// use the Streaming Store instruction MOVNTQ. This write instruction -// bypasses the cache and writes straight to main memory. This code also -// uses the software prefetch instruction to pre-read the data. -// USE 64 * 1024 FOR THIS VALUE IF YOU'RE ALWAYS FILLING A "CLEAN CACHE" - -#define BLOCK_PREFETCH_COPY infinity // no limit for movq/movntq w/block prefetch -#define CACHEBLOCK 80h // number of 64-byte blocks (cache lines) for block prefetch -// For the largest size blocks, a special technique called Block Prefetch -// can be used to accelerate the read operations. Block Prefetch reads -// one address per cache line, for a series of cache lines, in a short loop. -// This is faster than using software prefetch. The technique is great for -// getting maximum read bandwidth, especially in DDR memory systems. - -//#include - -// Inline assembly syntax for use with Visual C++ -#ifdef _WIN32 -#include -#endif - -#if defined(_MSC_VER) && !defined(__x86_64__) - -#include "PS2Etypes.h" - -extern "C" { -void * memcpy_amd(void *dest, const void *src, size_t n) -{ - __asm { - mov ecx, [n] ; number of bytes to copy - mov edi, [dest] ; destination - mov esi, [src] ; source - mov ebx, ecx ; keep a copy of count - - cld - cmp ecx, TINY_BLOCK_COPY - jb $memcpy_ic_3 ; tiny? skip mmx copy - - cmp ecx, 32*1024 ; don't align between 32k-64k because - jbe $memcpy_do_align ; it appears to be slower - cmp ecx, 64*1024 - jbe $memcpy_align_done -$memcpy_do_align: - mov ecx, 8 ; a trick that's faster than rep movsb... - sub ecx, edi ; align destination to qword - and ecx, 111b ; get the low bits - sub ebx, ecx ; update copy count - neg ecx ; set up to jump into the array - add ecx, offset $memcpy_align_done - jmp ecx ; jump to array of movsb's - -align 4 - movsb - movsb - movsb - movsb - movsb - movsb - movsb - movsb - -$memcpy_align_done: ; destination is dword aligned - mov ecx, ebx ; number of bytes left to copy - shr ecx, 6 ; get 64-byte block count - jz $memcpy_ic_2 ; finish the last few bytes - - cmp ecx, IN_CACHE_COPY/64 ; too big 4 cache? use uncached copy - jae $memcpy_uc_test - -// This is small block copy that uses the MMX registers to copy 8 bytes -// at a time. It uses the "unrolled loop" optimization, and also uses -// the software prefetch instruction to get the data into the cache. -align 16 -$memcpy_ic_1: ; 64-byte block copies, in-cache copy - - prefetchnta [esi + (200*64/34+192)] ; start reading ahead - - movq mm0, [esi+0] ; read 64 bits - movq mm1, [esi+8] - movq [edi+0], mm0 ; write 64 bits - movq [edi+8], mm1 ; note: the normal movq writes the - movq mm2, [esi+16] ; data to cache; a cache line will be - movq mm3, [esi+24] ; allocated as needed, to store the data - movq [edi+16], mm2 - movq [edi+24], mm3 - movq mm0, [esi+32] - movq mm1, [esi+40] - movq [edi+32], mm0 - movq [edi+40], mm1 - movq mm2, [esi+48] - movq mm3, [esi+56] - movq [edi+48], mm2 - movq [edi+56], mm3 - - add esi, 64 ; update source pointer - add edi, 64 ; update destination pointer - dec ecx ; count down - jnz $memcpy_ic_1 ; last 64-byte block? - -$memcpy_ic_2: - mov ecx, ebx ; has valid low 6 bits of the byte count -$memcpy_ic_3: - shr ecx, 2 ; dword count - and ecx, 1111b ; only look at the "remainder" bits - neg ecx ; set up to jump into the array - add ecx, offset $memcpy_last_few - jmp ecx ; jump to array of movsd's - -$memcpy_uc_test: - cmp ecx, UNCACHED_COPY/64 ; big enough? use block prefetch copy - jae $memcpy_bp_1 - -$memcpy_64_test: - or ecx, ecx ; tail end of block prefetch will jump here - jz $memcpy_ic_2 ; no more 64-byte blocks left - -// For larger blocks, which will spill beyond the cache, it's faster to -// use the Streaming Store instruction MOVNTQ. This write instruction -// bypasses the cache and writes straight to main memory. This code also -// uses the software prefetch instruction to pre-read the data. -align 16 -$memcpy_uc_1: ; 64-byte blocks, uncached copy - - prefetchnta [esi + (200*64/34+192)] ; start reading ahead - - movq mm0,[esi+0] ; read 64 bits - add edi,64 ; update destination pointer - movq mm1,[esi+8] - add esi,64 ; update source pointer - movq mm2,[esi-48] - movntq [edi-64], mm0 ; write 64 bits, bypassing the cache - movq mm0,[esi-40] ; note: movntq also prevents the CPU - movntq [edi-56], mm1 ; from READING the destination address - movq mm1,[esi-32] ; into the cache, only to be over-written - movntq [edi-48], mm2 ; so that also helps performance - movq mm2,[esi-24] - movntq [edi-40], mm0 - movq mm0,[esi-16] - movntq [edi-32], mm1 - movq mm1,[esi-8] - movntq [edi-24], mm2 - movntq [edi-16], mm0 - dec ecx - movntq [edi-8], mm1 - jnz $memcpy_uc_1 ; last 64-byte block? - - jmp $memcpy_ic_2 ; almost done - -// For the largest size blocks, a special technique called Block Prefetch -// can be used to accelerate the read operations. Block Prefetch reads -// one address per cache line, for a series of cache lines, in a short loop. -// This is faster than using software prefetch. The technique is great for -// getting maximum read bandwidth, especially in DDR memory systems. -$memcpy_bp_1: ; large blocks, block prefetch copy - - cmp ecx, CACHEBLOCK ; big enough to run another prefetch loop? - jl $memcpy_64_test ; no, back to regular uncached copy - - mov eax, CACHEBLOCK / 2 ; block prefetch loop, unrolled 2X - add esi, CACHEBLOCK * 64 ; move to the top of the block -align 16 -$memcpy_bp_2: - mov edx, [esi-64] ; grab one address per cache line - mov edx, [esi-128] ; grab one address per cache line - sub esi, 128 ; go reverse order to suppress HW prefetcher - dec eax ; count down the cache lines - jnz $memcpy_bp_2 ; keep grabbing more lines into cache - - mov eax, CACHEBLOCK ; now that it's in cache, do the copy -align 16 -$memcpy_bp_3: - movq mm0, [esi ] ; read 64 bits - movq mm1, [esi+ 8] - movq mm2, [esi+16] - movq mm3, [esi+24] - movq mm4, [esi+32] - movq mm5, [esi+40] - movq mm6, [esi+48] - movq mm7, [esi+56] - add esi, 64 ; update source pointer - movntq [edi ], mm0 ; write 64 bits, bypassing cache - movntq [edi+ 8], mm1 ; note: movntq also prevents the CPU - movntq [edi+16], mm2 ; from READING the destination address - movntq [edi+24], mm3 ; into the cache, only to be over-written, - movntq [edi+32], mm4 ; so that also helps performance - movntq [edi+40], mm5 - movntq [edi+48], mm6 - movntq [edi+56], mm7 - add edi, 64 ; update dest pointer - - dec eax ; count down - - jnz $memcpy_bp_3 ; keep copying - sub ecx, CACHEBLOCK ; update the 64-byte block count - jmp $memcpy_bp_1 ; keep processing chunks - -// The smallest copy uses the X86 "movsd" instruction, in an optimized -// form which is an "unrolled loop". Then it handles the last few bytes. -align 4 - movsd - movsd ; perform last 1-15 dword copies - movsd - movsd - movsd - movsd - movsd - movsd - movsd - movsd ; perform last 1-7 dword copies - movsd - movsd - movsd - movsd - movsd - movsd - -$memcpy_last_few: ; dword aligned from before movsd's - mov ecx, ebx ; has valid low 2 bits of the byte count - and ecx, 11b ; the last few cows must come home - jz $memcpy_final ; no more, let's leave - rep movsb ; the last 1, 2, or 3 bytes - -$memcpy_final: - emms ; clean up the MMX state - sfence ; flush the write buffer - mov eax, [dest] ; ret value = destination pointer - - } -} - -// mmx memcpy implementation, size has to be a multiple of 8 -// returns 0 is equal, nonzero value if not equal -// ~10 times faster than standard memcmp -// (zerofrog) -u8 memcmp_mmx(const void* src1, const void* src2, int cmpsize) -{ - assert( (cmpsize&7) == 0 ); - - __asm { -push esi - mov ecx, cmpsize - mov edx, src1 - mov esi, src2 - - cmp ecx, 32 - jl Done4 - - // custom test first 8 to make sure things are ok - movq mm0, [esi] - movq mm1, [esi+8] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pand mm0, mm1 - movq mm2, [esi+16] - pmovmskb eax, mm0 - movq mm3, [esi+24] - - // check if eq - cmp eax, 0xff - je NextComp - mov eax, 1 - jmp End - -NextComp: - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm2, mm3 - pmovmskb eax, mm2 - - sub ecx, 32 - add esi, 32 - add edx, 32 - - // check if eq - cmp eax, 0xff - je ContinueTest - mov eax, 1 - jmp End - - cmp ecx, 64 - jl Done8 - -Cmp8: - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - movq mm3, [esi+24] - movq mm4, [esi+32] - movq mm5, [esi+40] - movq mm6, [esi+48] - movq mm7, [esi+56] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm0, mm1 - pcmpeqd mm4, [edx+32] - pand mm0, mm2 - pcmpeqd mm5, [edx+40] - pand mm0, mm3 - pcmpeqd mm6, [edx+48] - pand mm0, mm4 - pcmpeqd mm7, [edx+56] - pand mm0, mm5 - pand mm0, mm6 - pand mm0, mm7 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - je Continue - mov eax, 1 - jmp End - -Continue: - sub ecx, 64 - add esi, 64 - add edx, 64 -ContinueTest: - cmp ecx, 64 - jge Cmp8 - -Done8: - test ecx, 0x20 - jz Done4 - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - movq mm3, [esi+24] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pcmpeqd mm3, [edx+24] - pand mm0, mm1 - pand mm0, mm2 - pand mm0, mm3 - pmovmskb eax, mm0 - sub ecx, 32 - add esi, 32 - add edx, 32 - - // check if eq - cmp eax, 0xff - je Done4 - mov eax, 1 - jmp End - -Done4: - cmp ecx, 24 - jne Done2 - movq mm0, [esi] - movq mm1, [esi+8] - movq mm2, [esi+16] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pcmpeqd mm2, [edx+16] - pand mm0, mm1 - pand mm0, mm2 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - setne al - jmp End - -Done2: - cmp ecx, 16 - jne Done1 - - movq mm0, [esi] - movq mm1, [esi+8] - pcmpeqd mm0, [edx] - pcmpeqd mm1, [edx+8] - pand mm0, mm1 - pmovmskb eax, mm0 - - // check if eq - cmp eax, 0xff - setne al - jmp End - -Done1: - cmp ecx, 8 - jne Done - - mov eax, [esi] - mov esi, [esi+4] - cmp eax, [edx] - je Next - mov eax, 1 - jmp End - -Next: - cmp esi, [edx+4] - setne al - jmp End - -Done: - xor eax, eax - -End: - pop esi - emms - } -} - -} -#else // _MSC_VER -// assume gcc or mingw or win x64 - -#include -#include -#include "PS2Etypes.h" -#include "Utilities/MemcpyFast.h" -//void * memcpy_amd(void *dest, const void *src, size_t n) -//{ -// //memcpy(dest, src, n); -// memcpy_fast(dest, src, n); -// return dest; -//} -#define memcpy_amd memcpy_fast - -#endif - diff --git a/plugins/zzogl-pg/opengl/targets.cpp b/plugins/zzogl-pg/opengl/targets.cpp index 1656637a5f..b956b4cea5 100644 --- a/plugins/zzogl-pg/opengl/targets.cpp +++ b/plugins/zzogl-pg/opengl/targets.cpp @@ -23,17 +23,20 @@ #include "Mem.h" #include "x86.h" -#include "zerogs.h" #include "targets.h" #include "ZZoglShaders.h" +#include "ZZClut.h" +#include +#include "ZZoglVB.h" + #ifdef ZEROGS_SSE2 #include #endif +const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); #define RHA //#define RW -using namespace ZeroGS; extern int g_TransferredToGPU; extern bool g_bUpdateStencil; @@ -47,18 +50,21 @@ extern int s_nResolved; extern u32 g_nResolve; extern bool g_bSaveTrans; -namespace ZeroGS -{ CRenderTargetMngr s_RTs, s_DepthRTs; CBitwiseTextureMngr s_BitwiseTextures; CMemoryTargetMngr g_MemTargs; -} //extern u32 s_ptexCurSet[2]; bool g_bSaveZUpdate = 0; int VALIDATE_THRESH = 8; u32 TEXDESTROY_THRESH = 16; +#define FORCE_TEXDESTROY_THRESH (3) // destroy texture after FORCE_TEXDESTROY_THRESH frames + +void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm, bool mode); +void SetWriteDepth(); +bool IsWriteDepth(); +bool IsWriteDestAlphaTest(); // ------------------------- Useful inlines ------------------------------------ @@ -91,7 +97,7 @@ inline void DestroyAllTargetsHelper(void* ptr) // returns false if creating texture was unsuccessful // fbh and fdb should be properly shifted before calling this! // We should ignore framebuffer trouble here, as we put textures of different sizes to it. -inline bool ZeroGS::CRenderTarget::InitialiseDefaultTexture(u32 *ptr_p, int fbw, int fbh) +inline bool CRenderTarget::InitialiseDefaultTexture(u32 *ptr_p, int fbw, int fbh) { glGenTextures(1, ptr_p); glBindTexture(GL_TEXTURE_RECTANGLE_NV, *ptr_p); @@ -109,7 +115,7 @@ inline bool ZeroGS::CRenderTarget::InitialiseDefaultTexture(u32 *ptr_p, int fbw, // Draw 4 triangles from binded array using only stencil buffer inline void FillOnlyStencilBuffer() { - if (ZeroGS::IsWriteDestAlphaTest() && !(conf.settings().no_stencil)) + if (IsWriteDestAlphaTest() && !(conf.settings().no_stencil)) { glColorMask(0, 0, 0, 0); glEnable(GL_ALPHA_TEST); @@ -125,7 +131,7 @@ inline void FillOnlyStencilBuffer() // used for transformation from vertex position in GS window.coords (I hope) // to view coordinates (in range 0, 1). -inline float4 ZeroGS::CRenderTarget::DefaultBitBltPos() +inline float4 CRenderTarget::DefaultBitBltPos() { float4 v = float4(1, -1, 0.5f / (float)RW(fbw), 0.5f / (float)RH(fbh)); v *= 1.0f / 32767.0f; @@ -135,7 +141,7 @@ inline float4 ZeroGS::CRenderTarget::DefaultBitBltPos() // Used to transform texture coordinates from GS (when 0,0 is upper left) to // OpenGL (0,0 - lower left). -inline float4 ZeroGS::CRenderTarget::DefaultBitBltTex() +inline float4 CRenderTarget::DefaultBitBltTex() { // I really sure that -0.5 is correct, because OpenGL have no half-offset // issue, DirectX known for. @@ -153,19 +159,19 @@ inline void BindToSample(u32 *p_ptr) //////////////////// // Render Targets // //////////////////// -ZeroGS::CRenderTarget::CRenderTarget() : ptex(0), ptexFeedback(0), psys(NULL) +CRenderTarget::CRenderTarget() : ptex(0), ptexFeedback(0), psys(NULL) { FUNCLOG nUpdateTarg = 0; } -ZeroGS::CRenderTarget::~CRenderTarget() +CRenderTarget::~CRenderTarget() { FUNCLOG Destroy(); } -bool ZeroGS::CRenderTarget::Create(const frameInfo& frame) +bool CRenderTarget::Create(const frameInfo& frame) { FUNCLOG Resolve(); @@ -208,7 +214,7 @@ bool ZeroGS::CRenderTarget::Create(const frameInfo& frame) return true; } -void ZeroGS::CRenderTarget::Destroy() +void CRenderTarget::Destroy() { FUNCLOG created = 1; @@ -218,7 +224,7 @@ void ZeroGS::CRenderTarget::Destroy() SAFE_RELEASE_TEX(ptexFeedback); } -void ZeroGS::CRenderTarget::SetTarget(int fbplocal, const Rect2& scissor, int context) +void CRenderTarget::SetTarget(int fbplocal, const Rect2& scissor, int context) { FUNCLOG int dy = 0; @@ -261,7 +267,7 @@ void ZeroGS::CRenderTarget::SetTarget(int fbplocal, const Rect2& scissor, int co scissorrect.h = RH(scissorrect.h); } -void ZeroGS::CRenderTarget::SetViewport() +void CRenderTarget::SetViewport() { FUNCLOG glViewport(0, 0, RW(fbw), RH(fbh)); @@ -272,7 +278,7 @@ inline bool NotResolveHelper() return ((s_nResolved > 8 && (2 * s_nResolved > fFPS - 10)) || (conf.settings().no_target_resolve)); } -void ZeroGS::CRenderTarget::Resolve() +void CRenderTarget::Resolve() { FUNCLOG @@ -281,7 +287,7 @@ void ZeroGS::CRenderTarget::Resolve() // flush if necessary FlushIfNecesary(this) ; - if ((IsDepth() && !ZeroGS::IsWriteDepth()) || NotResolveHelper()) + if ((IsDepth() && !IsWriteDepth()) || NotResolveHelper()) { // don't resolve if depths aren't used status = TS_Resolved; @@ -314,7 +320,7 @@ void ZeroGS::CRenderTarget::Resolve() } } -void ZeroGS::CRenderTarget::Resolve(int startrange, int endrange) +void CRenderTarget::Resolve(int startrange, int endrange) { FUNCLOG @@ -387,7 +393,7 @@ void ZeroGS::CRenderTarget::Resolve(int startrange, int endrange) } } -void ZeroGS::CRenderTarget::Update(int context, ZeroGS::CRenderTarget* pdepth) +void CRenderTarget::Update(int context, CRenderTarget* pdepth) { FUNCLOG @@ -488,7 +494,7 @@ void ZeroGS::CRenderTarget::Update(int context, ZeroGS::CRenderTarget* pdepth) if (conf.wireframe()) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - if (ZeroGS::IsWriteDestAlphaTest()) + if (IsWriteDestAlphaTest()) { glEnable(GL_STENCIL_TEST); glStencilFunc(GL_ALWAYS, 0, 0xff); @@ -510,17 +516,17 @@ void ZeroGS::CRenderTarget::Update(int context, ZeroGS::CRenderTarget* pdepth) glEnable(GL_SCISSOR_TEST); if (conf.wireframe()) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - if (conf.mrtdepth && pdepth != NULL && ZeroGS::IsWriteDepth()) pdepth->SetRenderTarget(1); + if (conf.mrtdepth && pdepth != NULL && IsWriteDepth()) pdepth->SetRenderTarget(1); status = TS_Resolved; // reset since settings changed vb[0].bVarsTexSync = 0; - ZeroGS::ResetAlphaVariables(); +// ResetAlphaVariables(); } -void ZeroGS::CRenderTarget::ConvertTo32() +void CRenderTarget::ConvertTo32() { FUNCLOG @@ -568,7 +574,7 @@ void ZeroGS::CRenderTarget::ConvertTo32() // assume depth already set !? FBTexture(0, ptexConv); - ZeroGS::ResetRenderTarget(1); + ResetRenderTarget(1); BindToSample(&ptex); ZZshGLSetTextureParameter(ppsConvert16to32.prog, ppsConvert16to32.sFinal, ptex, "Convert 16 to 32.Final"); @@ -613,7 +619,7 @@ void ZeroGS::CRenderTarget::ConvertTo32() status = TS_Resolved; // TODO, reset depth? - if (ZeroGS::icurctx >= 0) + if (icurctx >= 0) { // reset since settings changed vb[icurctx].bVarsTexSync = 0; @@ -623,7 +629,7 @@ void ZeroGS::CRenderTarget::ConvertTo32() vb[0].bVarsTexSync = 0; } -void ZeroGS::CRenderTarget::ConvertTo16() +void CRenderTarget::ConvertTo16() { FUNCLOG @@ -669,7 +675,7 @@ void ZeroGS::CRenderTarget::ConvertTo16() // assume depth already set !? FBTexture(0, ptexConv); - ZeroGS::ResetRenderTarget(1); + ResetRenderTarget(1); GL_REPORT_ERRORD(); BindToSample(&ptex); @@ -719,7 +725,7 @@ void ZeroGS::CRenderTarget::ConvertTo16() status = TS_Resolved; // TODO, reset depth? - if (ZeroGS::icurctx >= 0) + if (icurctx >= 0) { // reset since settings changed vb[icurctx].bVarsTexSync = 0; @@ -729,7 +735,7 @@ void ZeroGS::CRenderTarget::ConvertTo16() vb[0].bVarsTexSync = 0; } -void ZeroGS::CRenderTarget::_CreateFeedback() +void CRenderTarget::_CreateFeedback() { FUNCLOG @@ -797,7 +803,7 @@ void ZeroGS::CRenderTarget::_CreateFeedback() status |= TS_FeedbackReady; // TODO, reset depth? - if (ZeroGS::icurctx >= 0) + if (icurctx >= 0) { // reset since settings changed vb[icurctx].bVarsTexSync = 0; @@ -806,7 +812,7 @@ void ZeroGS::CRenderTarget::_CreateFeedback() GL_REPORT_ERRORD(); } -void ZeroGS::CRenderTarget::SetRenderTarget(int targ) +void CRenderTarget::SetRenderTarget(int targ) { FUNCLOG @@ -817,16 +823,16 @@ void ZeroGS::CRenderTarget::SetRenderTarget(int targ) //ERROR_LOG_SPAM("The Framebuffer is not complete. Glitches could appear onscreen.\n"); } -ZeroGS::CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(0), pstencil(0), icount(0) {} +CDepthTarget::CDepthTarget() : CRenderTarget(), pdepth(0), pstencil(0), icount(0) {} -ZeroGS::CDepthTarget::~CDepthTarget() +CDepthTarget::~CDepthTarget() { FUNCLOG Destroy(); } -bool ZeroGS::CDepthTarget::Create(const frameInfo& frame) +bool CDepthTarget::Create(const frameInfo& frame) { FUNCLOG @@ -871,7 +877,7 @@ bool ZeroGS::CDepthTarget::Create(const frameInfo& frame) return true; } -void ZeroGS::CDepthTarget::Destroy() +void CDepthTarget::Destroy() { FUNCLOG @@ -903,11 +909,11 @@ void ZeroGS::CDepthTarget::Destroy() extern int g_nDepthUsed; // > 0 if depth is used -void ZeroGS::CDepthTarget::Resolve() +void CDepthTarget::Resolve() { FUNCLOG - if (g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth() && !(conf.settings().no_depth_resolve)) + if (g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && IsWriteDepth() && !(conf.settings().no_depth_resolve)) CRenderTarget::Resolve(); else { @@ -919,15 +925,15 @@ void ZeroGS::CDepthTarget::Resolve() if (!(status&TS_Virtual)) { - ZeroGS::SetWriteDepth(); + SetWriteDepth(); } } -void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) +void CDepthTarget::Resolve(int startrange, int endrange) { FUNCLOG - if (g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && ZeroGS::IsWriteDepth()) + if (g_nDepthUsed > 0 && conf.mrtdepth && !(status&TS_Virtual) && IsWriteDepth()) { CRenderTarget::Resolve(startrange, endrange); } @@ -942,11 +948,11 @@ void ZeroGS::CDepthTarget::Resolve(int startrange, int endrange) if (!(status&TS_Virtual)) { - ZeroGS::SetWriteDepth(); + SetWriteDepth(); } } -void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) +void CDepthTarget::Update(int context, CRenderTarget* prndr) { FUNCLOG @@ -963,7 +969,7 @@ void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) DisableAllgl(); - ZeroGS::VB& curvb = vb[context]; + VB& curvb = vb[context]; if (curvb.test.zte == 0) return; @@ -1036,7 +1042,7 @@ void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) status = TS_Resolved; - if (!ZeroGS::IsWriteDepth()) + if (!IsWriteDepth()) { ResetRenderTarget(1); } @@ -1054,7 +1060,7 @@ void ZeroGS::CDepthTarget::Update(int context, ZeroGS::CRenderTarget* prndr) #endif } -void ZeroGS::CDepthTarget::SetDepthStencilSurface() +void CDepthTarget::SetDepthStencilSurface() { FUNCLOG TextureRect(GL_DEPTH_ATTACHMENT_EXT, pdepth); @@ -1085,7 +1091,7 @@ void ZeroGS::CDepthTarget::SetDepthStencilSurface() } } -void ZeroGS::CRenderTargetMngr::Destroy() +void CRenderTargetMngr::Destroy() { FUNCLOG @@ -1104,7 +1110,7 @@ void ZeroGS::CRenderTargetMngr::Destroy() mapDummyTargs.clear(); } -void ZeroGS::CRenderTargetMngr::DestroyAllTargs(int start, int end, int fbw) +void CRenderTargetMngr::DestroyAllTargs(int start, int end, int fbw) { FUNCLOG @@ -1166,14 +1172,14 @@ void ZeroGS::CRenderTargetMngr::DestroyAllTargs(int start, int end, int fbw) } } -void ZeroGS::CRenderTargetMngr::DestroyTarg(CRenderTarget* ptarg) +void CRenderTargetMngr::DestroyTarg(CRenderTarget* ptarg) { FUNCLOG DestroyAllTargetsHelper(ptarg) ; delete ptarg; } -void ZeroGS::CRenderTargetMngr::DestroyIntersecting(CRenderTarget* prndr) +void CRenderTargetMngr::DestroyIntersecting(CRenderTarget* prndr) { FUNCLOG assert(prndr != NULL); @@ -1221,7 +1227,7 @@ inline bool CheckWidthIsSame(const frameInfo& frame, CRenderTarget* ptarg) return (2 * frame.fbw == ptarg->fbw); } -void ZeroGS::CRenderTargetMngr::PrintTargets() +void CRenderTargetMngr::PrintTargets() { #ifdef _DEBUG for (MAPTARGETS::iterator it1 = mapDummyTargs.begin(); it1 != mapDummyTargs.end(); ++it1) @@ -1232,7 +1238,7 @@ void ZeroGS::CRenderTargetMngr::PrintTargets() #endif } -bool ZeroGS::CRenderTargetMngr::isFound(const frameInfo& frame, MAPTARGETS::iterator& it, u32 opts, u32 key, int maxposheight) +bool CRenderTargetMngr::isFound(const frameInfo& frame, MAPTARGETS::iterator& it, u32 opts, u32 key, int maxposheight) { // only enforce height if frame.fbh <= 0x1c0 bool bfound = it != mapTargets.end(); @@ -1286,7 +1292,7 @@ bool ZeroGS::CRenderTargetMngr::isFound(const frameInfo& frame, MAPTARGETS::iter return bfound; } -CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, u32 opts, int maxposheight) +CRenderTarget* CRenderTargetMngr::GetTarg(const frameInfo& frame, u32 opts, int maxposheight) { FUNCLOG @@ -1441,7 +1447,7 @@ CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, u32 op if (besttarg != 0 && pbesttarg->fbw != frame.fbw) { -// printf ("A %d %d %d %d\n", frame.psm, frame.fbw, pbesttarg->psm, pbesttarg->fbw); + //ZZLog::Debug_Log("A %d %d %d %d\n", frame.psm, frame.fbw, pbesttarg->psm, pbesttarg->fbw); vb[0].frame.fbw = pbesttarg->fbw; // Something should be here, but what? @@ -1594,7 +1600,7 @@ CRenderTarget* ZeroGS::CRenderTargetMngr::GetTarg(const frameInfo& frame, u32 op return ptarg; } -ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) +CRenderTargetMngr::MAPTARGETS::iterator CRenderTargetMngr::GetOldestTarg(MAPTARGETS& m) { FUNCLOG @@ -1614,7 +1620,7 @@ ZeroGS::CRenderTargetMngr::MAPTARGETS::iterator ZeroGS::CRenderTargetMngr::GetOl return itmaxtarg; } -void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const +void CRenderTargetMngr::GetTargs(int start, int end, list& listTargets) const { FUNCLOG @@ -1624,7 +1630,7 @@ void ZeroGS::CRenderTargetMngr::GetTargs(int start, int end, list 0 only when csa < 16 - int left = 0; - if (((u32)(uptr)pClutBuffer & 2) == 0) - { - left = (((u32)(uptr)pClutBuffer & 0x3ff) / 2) + clutsize - 512; - clutsize -= left; - } - - while (clutsize > 0) - { - for (int i = 0; i < 16; ++i) - { - if (pSavedBuffer[i] != pClutBuffer[2*i]) return 1; - } - - clutsize -= 32; - pSavedBuffer += 16; - pClutBuffer += 32; - } - - if (left > 0) - { - pClutBuffer = (u16*)(g_pbyGSClut + 2); - - while (left > 0) - { - for (int i = 0; i < 16; ++i) - { - if (pSavedBuffer[i] != pClutBuffer[2*i]) return 1; - } - - left -= 32; - - pSavedBuffer += 16; - pClutBuffer += 32; - } - } - - return 0; -} - -bool ZeroGS::CMemoryTarget::ValidateClut(const tex0Info& tex0) -{ - FUNCLOG - assert(tex0.psm == psm && PSMT_ISCLUT(psm) && cpsm == tex0.cpsm); - - int nClutOffset = 0, clutsize = 0; - int entries = PSMT_IS8CLUT(tex0.psm) ? 256 : 16; - - if (PSMT_IS32BIT(tex0.cpsm)) // 32 bit - { - nClutOffset = 64 * tex0.csa; - clutsize = min(entries, 256 - tex0.csa * 16) * 4; - } - else - { - nClutOffset = 32 * (tex0.csa & 15) + (tex0.csa >= 16 ? 2 : 0); - clutsize = min(entries, 512 - tex0.csa * 16) * 2; - } - - assert(clutsize == clut.size()); - - if (PSMT_IS32BIT(cpsm)) - { - if (memcmp_mmx(&clut[0], g_pbyGSClut + nClutOffset, clutsize)) return false; - } - else - { - if (memcmp_clut16((u16*)&clut[0], (u16*)(g_pbyGSClut + nClutOffset), clutsize)) return false; - } - - return true; -} - -bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) +bool CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex) { FUNCLOG @@ -1781,119 +1708,12 @@ bool ZeroGS::CMemoryTarget::ValidateTex(const tex0Info& tex0, int starttex, int return false; } -// used to build clut textures (note that this is for both 16 and 32 bit cluts) -template -static __forceinline void BuildClut(u32 psm, u32 height, T* pclut, u8* psrc, T* pdst) -{ - switch (psm) - { - case PSMT8: - for (u32 i = 0; i < height; ++i) - { - for (int j = 0; j < GPU_TEXWIDTH / 2; ++j) - { - pdst[0] = pclut[psrc[0]]; - pdst[1] = pclut[psrc[1]]; - pdst[2] = pclut[psrc[2]]; - pdst[3] = pclut[psrc[3]]; - pdst[4] = pclut[psrc[4]]; - pdst[5] = pclut[psrc[5]]; - pdst[6] = pclut[psrc[6]]; - pdst[7] = pclut[psrc[7]]; - pdst += 8; - psrc += 8; - } - } - break; - - case PSMT4: - for (u32 i = 0; i < height; ++i) - { - for (int j = 0; j < GPU_TEXWIDTH; ++j) - { - pdst[0] = pclut[psrc[0] & 15]; - pdst[1] = pclut[psrc[0] >> 4]; - pdst[2] = pclut[psrc[1] & 15]; - pdst[3] = pclut[psrc[1] >> 4]; - pdst[4] = pclut[psrc[2] & 15]; - pdst[5] = pclut[psrc[2] >> 4]; - pdst[6] = pclut[psrc[3] & 15]; - pdst[7] = pclut[psrc[3] >> 4]; - - pdst += 8; - psrc += 4; - } - } - break; - - case PSMT8H: - for (u32 i = 0; i < height; ++i) - { - for (int j = 0; j < GPU_TEXWIDTH / 8; ++j) - { - pdst[0] = pclut[psrc[3]]; - pdst[1] = pclut[psrc[7]]; - pdst[2] = pclut[psrc[11]]; - pdst[3] = pclut[psrc[15]]; - pdst[4] = pclut[psrc[19]]; - pdst[5] = pclut[psrc[23]]; - pdst[6] = pclut[psrc[27]]; - pdst[7] = pclut[psrc[31]]; - pdst += 8; - psrc += 32; - } - } - break; - - case PSMT4HH: - for (u32 i = 0; i < height; ++i) - { - for (int j = 0; j < GPU_TEXWIDTH / 8; ++j) - { - pdst[0] = pclut[psrc[3] >> 4]; - pdst[1] = pclut[psrc[7] >> 4]; - pdst[2] = pclut[psrc[11] >> 4]; - pdst[3] = pclut[psrc[15] >> 4]; - pdst[4] = pclut[psrc[19] >> 4]; - pdst[5] = pclut[psrc[23] >> 4]; - pdst[6] = pclut[psrc[27] >> 4]; - pdst[7] = pclut[psrc[31] >> 4]; - pdst += 8; - psrc += 32; - } - } - break; - - case PSMT4HL: - for (u32 i = 0; i < height; ++i) - { - for (int j = 0; j < GPU_TEXWIDTH / 8; ++j) - { - pdst[0] = pclut[psrc[3] & 15]; - pdst[1] = pclut[psrc[7] & 15]; - pdst[2] = pclut[psrc[11] & 15]; - pdst[3] = pclut[psrc[15] & 15]; - pdst[4] = pclut[psrc[19] & 15]; - pdst[5] = pclut[psrc[23] & 15]; - pdst[6] = pclut[psrc[27] & 15]; - pdst[7] = pclut[psrc[31] & 15]; - pdst += 8; - psrc += 32; - } - } - break; - - default: - assert(0); - } -} - #define TARGET_THRESH 0x500 extern int g_MaxTexWidth, g_MaxTexHeight; // Maximum height & width of supported texture. //#define SORT_TARGETS -inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) +inline list::iterator CMemoryTargetMngr::DestroyTargetIter(list::iterator& it) { // find the target and destroy list::iterator itprev = it; @@ -1908,50 +1728,37 @@ inline list::iterator ZeroGS::CMemoryTargetMngr::DestroyTargetIte return it; } -int ZeroGS::CMemoryTargetMngr::CompareTarget(list::iterator& it, const tex0Info& tex0, int clutsize, int nClutOffset) +// Compare target to current texture info +// Not same format -> 1 +// Same format, not same data (clut only) -> 2 +// identical -> 0 +int CMemoryTargetMngr::CompareTarget(list::iterator& it, const tex0Info& tex0, int clutsize) { if (PSMT_ISCLUT(it->psm) != PSMT_ISCLUT(tex0.psm)) - { return 1; - } - if (PSMT_ISCLUT(tex0.psm)) - { - assert(it->clut.size() > 0); - - if (it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clut.size() != clutsize) - { + if (PSMT_ISCLUT(tex0.psm)) { + if (it->psm != tex0.psm || it->cpsm != tex0.cpsm || it->clutsize != clutsize) return 1; + + if (PSMT_IS32BIT(tex0.cpsm)) { + if (Cmp_ClutBuffer_SavedClut((u32*)&it->clut[0], tex0.csa, clutsize)) + return 2; + } else { + if (Cmp_ClutBuffer_SavedClut((u16*)&it->clut[0], tex0.csa, clutsize)) + return 2; } - if (PSMT_IS32BIT(tex0.cpsm)) - { - if (memcmp_mmx(&it->clut[0], g_pbyGSClut + nClutOffset, clutsize)) - { - return 2; - } - } - else - { - if (memcmp_clut16((u16*)&it->clut[0], (u16*)(g_pbyGSClut + nClutOffset), clutsize)) - { - return 2; - } - } - - } - else + } else { if (PSMT_IS16BIT(tex0.psm) != PSMT_IS16BIT(it->psm)) - { return 1; - } + } return 0; } -void ZeroGS::CMemoryTargetMngr::GetClutVariables(int& nClutOffset, int& clutsize, const tex0Info& tex0) +void CMemoryTargetMngr::GetClutVariables(int& clutsize, const tex0Info& tex0) { - nClutOffset = 0; clutsize = 0; if (PSMT_ISCLUT(tex0.psm)) @@ -1959,19 +1766,13 @@ void ZeroGS::CMemoryTargetMngr::GetClutVariables(int& nClutOffset, int& clutsize int entries = PSMT_IS8CLUT(tex0.psm) ? 256 : 16; if (PSMT_IS32BIT(tex0.cpsm)) - { - nClutOffset = 64 * tex0.csa; clutsize = min(entries, 256 - tex0.csa * 16) * 4; - } else - { - nClutOffset = 64 * (tex0.csa & 15) + (tex0.csa >= 16 ? 2 : 0); clutsize = min(entries, 512 - tex0.csa * 16) * 2; - } } } -void ZeroGS::CMemoryTargetMngr::GetMemAddress(int& start, int& end, const tex0Info& tex0) +void CMemoryTargetMngr::GetMemAddress(int& start, int& end, const tex0Info& tex0) { int nbStart, nbEnd; GetRectMemAddress(nbStart, nbEnd, tex0.psm, 0, 0, tex0.tw, tex0.th, tex0.tbp0, tex0.tbw); @@ -1984,7 +1785,7 @@ void ZeroGS::CMemoryTargetMngr::GetMemAddress(int& start, int& end, const tex0I } -ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::SearchExistTarget(int start, int end, int nClutOffset, int clutsize, const tex0Info& tex0, int forcevalidate) +CMemoryTarget* CMemoryTargetMngr::SearchExistTarget(int start, int end, int clutsize, const tex0Info& tex0, int forcevalidate) { for (list::iterator it = listTargets.begin(); it != listTargets.end();) { @@ -1992,7 +1793,7 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::SearchExistTarget(int start, i if (it->starty <= start && it->starty + it->height >= end) { - int res = CompareTarget(it, tex0, clutsize, nClutOffset); + int res = CompareTarget(it, tex0, clutsize); if (res == 1) { @@ -2003,9 +1804,8 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::SearchExistTarget(int start, i if (listTargets.size() == 0) break; } else - { ++it; - } + continue; } else if (res == 2) @@ -2018,20 +1818,17 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::SearchExistTarget(int start, i { // do more validation checking. delete if not been used for a while - if (!it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + 3)) + if (!it->ValidateTex(tex0, start, end, curstamp > it->usedstamp + FORCE_TEXDESTROY_THRESH)) { if (it->height <= 0) { it = DestroyTargetIter(it); - if (listTargets.size() == 0) - break; + if (listTargets.size() == 0) break; } else - { ++it; - } continue; } @@ -2055,7 +1852,7 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::SearchExistTarget(int start, i return NULL; } -ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::ClearedTargetsSearch(int fmt, int widthmult, int channels, int height) +CMemoryTarget* CMemoryTargetMngr::ClearedTargetsSearch(int fmt, int widthmult, int channels, int height) { CMemoryTarget* targ = NULL; @@ -2096,25 +1893,32 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::ClearedTargetsSearch(int fmt, return targ; } -ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) +CMemoryTarget* CMemoryTargetMngr::GetMemoryTarget(const tex0Info& tex0, int forcevalidate) { FUNCLOG - int start, end, nClutOffset, clutsize; + int start, end, clutsize; - GetClutVariables(nClutOffset, clutsize, tex0); + GetClutVariables(clutsize, tex0); GetMemAddress(start, end, tex0); - ZeroGS::CMemoryTarget* it = SearchExistTarget(start, end, nClutOffset, clutsize, tex0, forcevalidate); + CMemoryTarget* it = SearchExistTarget(start, end, clutsize, tex0, forcevalidate); if (it != NULL) return it; // couldn't find so create CMemoryTarget* targ; - u32 fmt = GL_UNSIGNED_BYTE; - - // RGBA16 storage format - if (PSMT_ISHALF_STORAGE(tex0)) fmt = GL_UNSIGNED_SHORT_1_5_5_5_REV; + u32 fmt; + u32 internal_fmt; + if (PSMT_ISHALF_STORAGE(tex0)) { + // RGBA_5551 storage format + fmt = GL_UNSIGNED_SHORT_1_5_5_5_REV; + internal_fmt = GL_RGB5_A1; + } else { + // RGBA_8888 storage format + fmt = GL_UNSIGNED_BYTE; + internal_fmt = GL_RGBA; + } int widthmult = 1, channels = 1; @@ -2130,50 +1934,6 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info targ = ClearedTargetsSearch(fmt, widthmult, channels, end - start); - // fill local clut - if (PSMT_ISCLUT(tex0.psm)) - { - assert(clutsize > 0); - - targ->cpsm = tex0.cpsm; - targ->clut.reserve(256*4); // no matter what - targ->clut.resize(clutsize); - - if (PSMT_IS32BIT(tex0.cpsm)) - { - memcpy_amd(&targ->clut[0], g_pbyGSClut + nClutOffset, clutsize); - } - else - { - u16* pClutBuffer = (u16*)(g_pbyGSClut + nClutOffset); - u16* pclut = (u16*) & targ->clut[0]; - int left = ((u32)nClutOffset & 2) ? 0 : ((nClutOffset & 0x3ff) / 2) + clutsize - 512; - - if (left > 0) clutsize -= left; - - while (clutsize > 0) - { - pclut[0] = pClutBuffer[0]; - pclut++; - pClutBuffer += 2; - clutsize -= 2; - } - - if (left > 0) - { - pClutBuffer = (u16*)(g_pbyGSClut + 2); - - while (left > 0) - { - pclut[0] = pClutBuffer[0]; - left -= 2; - pClutBuffer += 2; - pclut++; - } - } - } - } - if (targ->ptex != NULL) { assert(end - start <= targ->realheight && targ->fmt == fmt && targ->widthmult == widthmult); @@ -2184,10 +1944,7 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info targ->psm = tex0.psm; targ->cpsm = tex0.cpsm; targ->height = end - start; - } - - if (targ->ptex == NULL) - { + } else { // not initialized yet targ->fmt = fmt; targ->realy = targ->starty = start; @@ -2223,25 +1980,42 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info if (PSMT_ISCLUT(tex0.psm)) { + assert(clutsize > 0); + + // Local clut parameter + targ->cpsm = tex0.cpsm; + + // Allocate a local clut array + targ->clutsize = clutsize; + if(targ->clut == NULL) + targ->clut = (u8*)_aligned_malloc(clutsize, 16); + else { + // In case it could occured + // realloc would be better but you need to get it from libutilies first + // _aligned_realloc is brought in from ScopedAlloc.h now. --arcum42 + _aligned_free(targ->clut); + targ->clut = (u8*)_aligned_malloc(clutsize, 16); + } + + // texture parameter ptexdata = (u8*)_aligned_malloc(CLUT_PIXEL_SIZE(tex0.cpsm) * targ->texH * targ->texW, 16); has_data = true; u8* psrc = (u8*)(MemoryAddress(targ->realy)); + // Fill a local clut then build the real texture if (PSMT_IS32BIT(tex0.cpsm)) { - u32* pclut = (u32*) & targ->clut[0]; - u32* pdst = (u32*)ptexdata; - - BuildClut(tex0.psm, targ->height, pclut, psrc, pdst); + ClutBuffer_to_Array((u32*)targ->clut, tex0.csa, clutsize); + Build_Clut_Texture(tex0.psm, targ->height, (u32*)targ->clut, psrc, (u32*)ptexdata); } else { - u16* pclut = (u16*) & targ->clut[0]; - u16* pdst = (u16*)ptexdata; - - BuildClut(tex0.psm, targ->height, pclut, psrc, pdst); + ClutBuffer_to_Array((u16*)targ->clut, tex0.csa, clutsize); + Build_Clut_Texture(tex0.psm, targ->height, (u16*)targ->clut, psrc, (u16*)ptexdata); } + + assert(targ->clutsize > 0); } else { @@ -2254,7 +2028,7 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info u16* dst = (u16*)ptexdata; u16* src = (u16*)(MemoryAddress(targ->realy)); -#if defined(ZEROGS_SSE2) +#ifdef ZEROGS_SSE2 assert(((u32)(uptr)dst) % 16 == 0); // FIXME Uncomment to test intrinsic versions (instead of asm) // perf improvement vs asm: @@ -2343,10 +2117,7 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info glBindTexture(GL_TEXTURE_RECTANGLE_NV, targ->ptex->tex); - if (fmt == GL_UNSIGNED_BYTE) - TextureRect(GL_RGBA, targ->texW, targ->texH, GL_RGBA, fmt, ptexdata); - else - TextureRect(GL_RGB5_A1, targ->texW, targ->texH, GL_RGBA, fmt, ptexdata); + TextureRect(internal_fmt, targ->texW, targ->texH, GL_RGBA, fmt, ptexdata); while (glGetError() != GL_NO_ERROR) { @@ -2368,7 +2139,7 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info DestroyOldest(); } - TextureRect(GL_RGBA, targ->texW, targ->texH, GL_RGBA, fmt, ptexdata); + TextureRect(internal_fmt, targ->texW, targ->texH, GL_RGBA, fmt, ptexdata); } setRectWrap(GL_CLAMP); @@ -2376,12 +2147,10 @@ ZeroGS::CMemoryTarget* ZeroGS::CMemoryTargetMngr::GetMemoryTarget(const tex0Info assert(tex0.psm != 0xd); - if (PSMT_ISCLUT(tex0.psm)) assert(targ->clut.size() > 0); - return targ; } -void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) +void CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) { FUNCLOG int starty = nbStartY / (4 * GPU_TEXWIDTH); @@ -2453,13 +2222,13 @@ void ZeroGS::CMemoryTargetMngr::ClearRange(int nbStartY, int nbEndY) // } } -void ZeroGS::CMemoryTargetMngr::DestroyCleared() +void CMemoryTargetMngr::DestroyCleared() { FUNCLOG for (list::iterator it = listClearedTargets.begin(); it != listClearedTargets.end();) { - if (it->usedstamp < curstamp - 2) + if (it->usedstamp < curstamp - (FORCE_TEXDESTROY_THRESH -1)) { it = listClearedTargets.erase(it); continue; @@ -2468,12 +2237,12 @@ void ZeroGS::CMemoryTargetMngr::DestroyCleared() ++it; } - if ((curstamp % 3) == 0) + if ((curstamp % FORCE_TEXDESTROY_THRESH) == 0) { - // purge old targets every 3 frames + // purge old targets every FORCE_TEXDESTROY_THRESH frames for (list::iterator it = listTargets.begin(); it != listTargets.end();) { - if (it->usedstamp < curstamp - 3) + if (it->usedstamp < curstamp - FORCE_TEXDESTROY_THRESH) { it = listTargets.erase(it); continue; @@ -2486,7 +2255,7 @@ void ZeroGS::CMemoryTargetMngr::DestroyCleared() ++curstamp; } -void ZeroGS::CMemoryTargetMngr::DestroyOldest() +void CMemoryTargetMngr::DestroyOldest() { FUNCLOG @@ -2509,7 +2278,7 @@ void ZeroGS::CMemoryTargetMngr::DestroyOldest() ////////////////////////////////////// // Texture Mngr For Bitwise AND Ops // ////////////////////////////////////// -void ZeroGS::CBitwiseTextureMngr::Destroy() +void CBitwiseTextureMngr::Destroy() { FUNCLOG @@ -2521,7 +2290,7 @@ void ZeroGS::CBitwiseTextureMngr::Destroy() mapTextures.clear(); } -u32 ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, u32 ptexDoNotDelete) +u32 CBitwiseTextureMngr::GetTexInt(u32 bitvalue, u32 ptexDoNotDelete) { FUNCLOG @@ -2591,7 +2360,7 @@ u32 ZeroGS::CBitwiseTextureMngr::GetTexInt(u32 bitvalue, u32 ptexDoNotDelete) return ptex; } -void ZeroGS::CRangeManager::RangeSanityCheck() +void CRangeManager::RangeSanityCheck() { #ifdef _DEBUG // sanity check @@ -2604,7 +2373,7 @@ void ZeroGS::CRangeManager::RangeSanityCheck() #endif } -void ZeroGS::CRangeManager::Insert(int start, int end) +void CRangeManager::Insert(int start, int end) { FUNCLOG int imin = 0, imax = (int)ranges.size(), imid; @@ -2757,9 +2526,6 @@ void ZeroGS::CRangeManager::Insert(int start, int end) RangeSanityCheck(); } -namespace ZeroGS -{ - CRangeManager s_RangeMngr; // manages overwritten memory void ResolveInRange(int start, int end) @@ -2890,7 +2656,7 @@ void FlushTransferRanges(const tex0Info* ptex) // get start of left-most boundry page int targstart, targend; - ZeroGS::GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height - 1), ptarg->fbp, ptarg->fbw); + GetRectMemAddress(targstart, targend, ptarg->psm, 0, 0, ptarg->fbw, ptarg->fbh & ~(m_Blocks[ptarg->psm].height - 1), ptarg->fbp, ptarg->fbw); if (start >= targend) { @@ -2930,7 +2696,7 @@ void FlushTransferRanges(const tex0Info* ptex) } } - ZeroGS::g_MemTargs.ClearRange(start, end); + g_MemTargs.ClearRange(start, end); } s_RangeMngr.Clear(); @@ -2972,16 +2738,16 @@ void FlushTransferRanges(const tex0Info* ptex) #endif +#ifdef __LINUX__ //#define LOG_RESOLVE_PROFILE +#endif template inline void Resolve_32_Bit(const void* psrc, int fbp, int fbw, int fbh, const int psm, u32 fbm) { u32 mask, imask; #ifdef LOG_RESOLVE_PROFILE -#ifdef __LINUX__ u32 startime = timeGetPreciseTime(); -#endif #endif if (PSMT_ISHALF(psm)) /* 16 bit */ @@ -3057,14 +2823,13 @@ inline void Resolve_32_Bit(const void* psrc, int fbp, int fbw, int fbh, const in src -= raw_size; } #ifdef LOG_RESOLVE_PROFILE -#ifdef __LINUX__ ZZLog::Dev_Log("*** 32 bits: execution time %d", timeGetPreciseTime()-startime); #endif -#endif } static const __aligned16 unsigned int pixel_5b_mask[4] = {0x0000001F, 0x0000001F, 0x0000001F, 0x0000001F}; +#ifdef ZEROGS_SSE2 // The function process 2*2 pixels in 32bits. And 2*4 pixels in 16bits template __forceinline void update_8pixels_sse2(u32* src, u32* basepage, u32 i_msk, u32 j, u32 pix_mask, u32 src_pitch) @@ -3295,9 +3060,7 @@ void Resolve_32_Bit_sse2(const void* psrc, int fbp, int fbw, int fbh, u32 fbm) { // Note a basic implementation was done in Resolve_32_Bit function #ifdef LOG_RESOLVE_PROFILE -#ifdef __LINUX__ u32 startime = timeGetPreciseTime(); -#endif #endif u32 pix_mask; if (PSMT_ISHALF(psm)) /* 16 bit format */ @@ -3371,11 +3134,10 @@ void Resolve_32_Bit_sse2(const void* psrc, int fbp, int fbw, int fbh, u32 fbm) } #ifdef LOG_RESOLVE_PROFILE -#ifdef __LINUX__ ZZLog::Dev_Log("*** 32 bits: execution time %d", timeGetPreciseTime()-startime); #endif -#endif } +#endif void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm, bool mode = true) { @@ -3754,5 +3516,3 @@ void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm, boo } #endif - -} // End of namespece ZeroGS diff --git a/plugins/zzogl-pg/opengl/targets.h b/plugins/zzogl-pg/opengl/targets.h index 32efd6ceea..d48fc59773 100644 --- a/plugins/zzogl-pg/opengl/targets.h +++ b/plugins/zzogl-pg/opengl/targets.h @@ -22,18 +22,214 @@ #define TARGET_VIRTUAL_KEY 0x80000000 #include "PS2Edefs.h" +#include +#include +#include "GS.h" +#include "ZZGl.h" +//#include "ZZoglVB.h" #ifndef GL_TEXTURE_RECTANGLE #define GL_TEXTURE_RECTANGLE GL_TEXTURE_RECTANGLE_NV #endif -namespace ZeroGS +#define VB_BUFFERSIZE 0x4000 + +// all textures have this width +extern int GPU_TEXWIDTH; +extern float g_fiGPU_TEXWIDTH; +#define MASKDIVISOR 0 // Used for decrement bitwise mask texture size if 1024 is too big +#define GPU_TEXMASKWIDTH (1024 >> MASKDIVISOR) // bitwise mask width for region repeat mode + +// managers render-to-texture targets +class CRenderTarget { -inline u32 GetFrameKey(int fbp, int fbw, VB& curvb); + public: + CRenderTarget(); + virtual ~CRenderTarget(); + + virtual bool Create(const frameInfo& frame); + virtual void Destroy(); + + // set the GPU_POSXY variable, scissor rect, and current render target + void SetTarget(int fbplocal, const Rect2& scissor, int context); + void SetViewport(); + + // copies/creates the feedback contents + inline void CreateFeedback() + { + if (ptexFeedback == 0 || !(status&TS_FeedbackReady)) + _CreateFeedback(); + } + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* pdepth); + virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 + virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 + + virtual bool IsDepth() { return false; } + + void SetRenderTarget(int targ); + + void* psys; // system data used for comparison + u32 ptex; + + int fbp, fbw, fbh, fbhCalc; // if fbp is negative, virtual target (not mapped to any real addr) + int start, end; // in bytes + u32 lastused; // time stamp since last used + float4 vposxy; + + u32 fbm; + u16 status; + u8 psm; + u8 resv0; + Rect scissorrect; + + u8 created; // Check for object destruction/creating for r201. + + //int startresolve, endresolve; + u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) + + // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) + u32 ptexFeedback; + + enum TargetStatus + { + TS_Resolved = 1, + TS_NeedUpdate = 2, + TS_Virtual = 4, // currently not mapped to memory + TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated + TS_NeedConvert32 = 16, + TS_NeedConvert16 = 32, + }; + inline float4 DefaultBitBltPos(); + inline float4 DefaultBitBltTex(); + + private: + void _CreateFeedback(); + inline bool InitialiseDefaultTexture(u32 *p_ptr, int fbw, int fbh) ; +}; + +// manages zbuffers + +class CDepthTarget : public CRenderTarget +{ + + public: + CDepthTarget(); + virtual ~CDepthTarget(); + + virtual bool Create(const frameInfo& frame); + virtual void Destroy(); + + virtual void Resolve(); + virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range + virtual void Update(int context, CRenderTarget* prndr); + + virtual bool IsDepth() { return true; } + + void SetDepthStencilSurface(); + + u32 pdepth; // 24 bit, will contain the stencil buffer if possible + u32 pstencil; // if not 0, contains the stencil buffer + int icount; // internal counter +}; + +// manages contiguous chunks of memory (width is always 1024) + +class CMemoryTarget +{ + public: + struct TEXTURE + { + inline TEXTURE() : tex(0), memptr(NULL), ref(0) {} + inline ~TEXTURE() { glDeleteTextures(1, &tex); _aligned_free(memptr); } + + u32 tex; + u8* memptr; // GPU memory used for comparison + int ref; + }; + + inline CMemoryTarget() : ptex(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), cpsm(0), channels(0), clearminy(0), clearmaxy(0), validatecount(0), clut(NULL), clutsize(0) {} + + inline CMemoryTarget(const CMemoryTarget& r) + { + ptex = r.ptex; + + if (ptex != NULL) ptex->ref++; + + starty = r.starty; + height = r.height; + realy = r.realy; + realheight = r.realheight; + usedstamp = r.usedstamp; + psm = r.psm; + cpsm = r.cpsm; + clut = r.clut; + clearminy = r.clearminy; + clearmaxy = r.clearmaxy; + widthmult = r.widthmult; + texH = r.texH; + texW = r.texW; + channels = r.channels; + validatecount = r.validatecount; + fmt = r.fmt; + } + + ~CMemoryTarget() { Destroy(); } + + inline void Destroy() + { + if (ptex != NULL && ptex->ref > 0) + { + if (--ptex->ref <= 0) delete ptex; + } + + ptex = NULL; + + _aligned_free(clut); + clut = NULL; + clutsize = 0; + } + + // returns true if clut data is synced + bool ValidateClut(const tex0Info& tex0); + // returns true if tex data is synced + bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); + + // realy is offset in pixels from start of valid region + // so texture in memory is [realy,starty+height] + // valid texture is [starty,starty+height] + // offset in mem [starty-realy, height] + TEXTURE* ptex; // can be 16bit + + int starty, height; // assert(starty >= realy) + int realy, realheight; // this is never touched once allocated + // realy is start pointer of data in 4M data block (start) and size (end-start). + + u32 usedstamp; + u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters + + u32 fmt; + + int widthmult; // Either 1 or 2. + int channels; // The number of pixels per PSM format word. channels == PIXELS_PER_WORD(psm) + // This is the real drawing size in pixels of the texture in renderbuffer. + int texW; // (realheight + widthmult - 1)/widthmult == realheight or [(realheight+1)/2] + int texH; // GPU_TEXWIDTH *widthmult * channels; + + int clearminy, clearmaxy; // when maxy > 0, need to check for clearing + + int validatecount; // count how many times has been validated, if too many, destroy + + u8* clut; // Clut texture data. Null otherwise + int clutsize; // size of the clut array. 0 otherwise +}; + +inline u32 GetFrameKey(int fbp, int fbw); // manages render targets - class CRenderTargetMngr { public: @@ -54,22 +250,22 @@ class CRenderTargetMngr bool isFound(const frameInfo& frame, MAPTARGETS::iterator& it, u32 opts, u32 key, int maxposheight); CRenderTarget* GetTarg(const frameInfo& frame, u32 Options, int maxposheight); - inline CRenderTarget* GetTarg(int fbp, int fbw, VB& curvb) + inline CRenderTarget* GetTarg(int fbp, int fbw) { - MAPTARGETS::iterator it = mapTargets.find(GetFrameKey(fbp, fbw, curvb)); + MAPTARGETS::iterator it = mapTargets.find(GetFrameKey(fbp, fbw)); /* if (fbp == 0x3600 && fbw == 0x100 && it == mapTargets.end()) { - printf("%x\n", GetFrameKey(fbp, fbw, curvb)) ; - printf("%x %x\n", fbp, fbw); + ZZLog::Debug_Log("%x", GetFrameKey(fbp, fbw)) ; + ZZLog::Debug_Log("%x %x", fbp, fbw); for(MAPTARGETS::iterator it1 = mapTargets.begin(); it1 != mapTargets.end(); ++it1) - printf ("\t %x %x %x %x\n", it1->second->fbw, it1->second->fbh, it1->second->psm, it1->second->fbp); + ZZLog::Debug_Log("\t %x %x %x %x", it1->second->fbw, it1->second->fbh, it1->second->psm, it1->second->fbp); }*/ return it != mapTargets.end() ? it->second : NULL; } // gets all targets with a range - void GetTargs(int start, int end, list& listTargets) const; + void GetTargs(int start, int end, list& listTargets) const; // resolves all targets within a range __forceinline void Resolve(int start, int end); @@ -125,9 +321,9 @@ class CMemoryTargetMngr CMemoryTargetMngr() : curstamp(0) {} CMemoryTarget* GetMemoryTarget(const tex0Info& tex0, int forcevalidate); // pcbp is pointer to start of clut - CMemoryTarget* SearchExistTarget(int start, int end, int nClutOffset, int clutsize, const tex0Info& tex0, int forcevalidate); + CMemoryTarget* SearchExistTarget(int start, int end, int clutsize, const tex0Info& tex0, int forcevalidate); CMemoryTarget* ClearedTargetsSearch(int fmt, int widthmult, int channels, int height); - int CompareTarget(list::iterator& it, const tex0Info& tex0, int clutsize, int nClutOffset); + int CompareTarget(list::iterator& it, const tex0Info& tex0, int clutsize); void Destroy(); // destroy all targs @@ -140,7 +336,7 @@ class CMemoryTargetMngr private: list::iterator DestroyTargetIter(list::iterator& it); - void GetClutVariables(int& nClutOffset, int& clutsize, const tex0Info& tex0); + void GetClutVariables(int& clutsize, const tex0Info& tex0); void GetMemAddress(int& start, int& end, const tex0Info& tex0); }; @@ -202,6 +398,7 @@ class CRangeManager extern CRenderTargetMngr s_RTs, s_DepthRTs; extern CBitwiseTextureMngr s_BitwiseTextures; extern CMemoryTargetMngr g_MemTargs; +extern CRangeManager s_RangeMngr; // manages overwritten memory //extern u8 s_AAx, s_AAy; extern Point AA; @@ -218,15 +415,15 @@ inline int RH(int tbh) return (tbh << AA.y); } -/* inline void CreateTargetsList(int start, int end, list& listTargs) { +/* inline void CreateTargetsList(int start, int end, list& listTargs) { s_DepthRTs.GetTargs(start, end, listTargs); s_RTs.GetTargs(start, end, listTargs); }*/ // This pattern of functions is called 3 times, so I add creating Targets list into one. -inline list CreateTargetsList(int start, int end) +inline list CreateTargetsList(int start, int end) { - list listTargs; + list listTargs; s_DepthRTs.GetTargs(start, end, listTargs); s_RTs.GetTargs(start, end, listTargs); return listTargs; @@ -250,7 +447,7 @@ inline u32 GetFrameKey(CRenderTarget* frame) return (((frame->fbw) << 16) | (frame->fbp)); } -inline u32 GetFrameKey(int fbp, int fbw, VB& curvb) +inline u32 GetFrameKey(int fbp, int fbw) { return (((fbw) << 16) | (fbp)); } @@ -290,8 +487,6 @@ inline u32 GetFrameKeyDummy(CRenderTarget* frame) return GetFrameKeyDummy(frame->fbp, frame->fbw, frame->fbh, frame->psm); } -} // End of namespace - #include "Mem.h" static __forceinline void DrawTriangleArray() @@ -316,6 +511,11 @@ static __forceinline void FBTexture(int attach, int id = 0) GL_REPORT_ERRORD(); } +static __forceinline void ResetRenderTarget(int index) +{ + FBTexture(index); +} + static __forceinline void Texture2D(GLint iFormat, GLint width, GLint height, GLenum format, GLenum type, const GLvoid* pixels) { glTexImage2D(GL_TEXTURE_2D, 0, iFormat, width, height, 0, format, type, pixels); @@ -388,5 +588,20 @@ static __forceinline void setRectWrap2(GLint type) glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, type); glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, type); } - + +//------------------------ Inlines ------------------------- + +// Calculate maximum height for target +inline int get_maxheight(int fbp, int fbw, int psm) +{ + int ret; + + if (fbw == 0) return 0; + + ret = (((0x00100000 - 64 * fbp) / fbw) & ~0x1f); + if (PSMT_ISHALF(psm)) ret *= 2; + + return ret; +} + #endif diff --git a/plugins/zzogl-pg/opengl/x86.cpp b/plugins/zzogl-pg/opengl/x86.cpp index da37eaaed0..c798151b8a 100644 --- a/plugins/zzogl-pg/opengl/x86.cpp +++ b/plugins/zzogl-pg/opengl/x86.cpp @@ -594,6 +594,7 @@ void __fastcall Frame16SwizzleBlock16ZA4_c(u16* dst, Vector_16F* src, int srcpit // } //} +#if 0 extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut) { __m128i* src = (__m128i*)vm; @@ -626,6 +627,7 @@ extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut) } } + extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut) { __m128i* src = (__m128i*)vm; @@ -642,13 +644,116 @@ extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut) _mm_store_si128(&dst[3], _mm_unpackhi_epi64(r2, r3)); } - +static const __aligned16 int s_clut_16bits_mask[4] = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; static const __aligned16 int s_clut16mask2[4] = { 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; static const __aligned16 int s_clut16mask[8] = { 0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000, 0x0000ffff, 0x0000ffff, 0x0000ffff, 0x0000ffff }; -extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut) +template +void __fastcall WriteCLUT_T16_I4_CSM1_core_sse2(u32* vm, u32* clut) +{ + __m128i vm_0; + __m128i vm_1; + __m128i vm_2; + __m128i vm_3; + __m128i clut_0; + __m128i clut_1; + __m128i clut_2; + __m128i clut_3; + + __m128i clut_mask = _mm_load_si128((__m128i*)s_clut_16bits_mask); + + // !HIGH_16BITS_VM + // CSA in 0-15 + // Replace lower 16 bits of clut0 with lower 16 bits of vm + // CSA in 16-31 + // Replace higher 16 bits of clut0 with lower 16 bits of vm + + // HIGH_16BITS_VM + // CSA in 0-15 + // Replace lower 16 bits of clut0 with higher 16 bits of vm + // CSA in 16-31 + // Replace higher 16 bits of clut0 with higher 16 bits of vm + if(HIGH_16BITS_VM && CSA_0_15) { + // move up to low + vm_0 = _mm_load_si128((__m128i*)vm); // 9 8 1 0 + vm_1 = _mm_load_si128((__m128i*)vm+1); // 11 10 3 2 + vm_2 = _mm_load_si128((__m128i*)vm+2); // 13 12 5 4 + vm_3 = _mm_load_si128((__m128i*)vm+3); // 15 14 7 6 + vm_0 = _mm_srli_epi32(vm_0, 16); + vm_1 = _mm_srli_epi32(vm_1, 16); + vm_2 = _mm_srli_epi32(vm_2, 16); + vm_3 = _mm_srli_epi32(vm_3, 16); + } else if(HIGH_16BITS_VM && !CSA_0_15) { + // Remove lower 16 bits + vm_0 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)vm)); // 9 8 1 0 + vm_1 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)vm+1)); // 11 10 3 2 + vm_2 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)vm+2)); // 13 12 5 4 + vm_3 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)vm+3)); // 15 14 7 6 + } else if(!HIGH_16BITS_VM && CSA_0_15) { + // Remove higher 16 bits + vm_0 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)vm)); // 9 8 1 0 + vm_1 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)vm+1)); // 11 10 3 2 + vm_2 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)vm+2)); // 13 12 5 4 + vm_3 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)vm+3)); // 15 14 7 6 + } else if(!HIGH_16BITS_VM && !CSA_0_15) { + // move low to high + vm_0 = _mm_load_si128((__m128i*)vm); // 9 8 1 0 + vm_1 = _mm_load_si128((__m128i*)vm+1); // 11 10 3 2 + vm_2 = _mm_load_si128((__m128i*)vm+2); // 13 12 5 4 + vm_3 = _mm_load_si128((__m128i*)vm+3); // 15 14 7 6 + vm_0 = _mm_slli_epi32(vm_0, 16); + vm_1 = _mm_slli_epi32(vm_1, 16); + vm_2 = _mm_slli_epi32(vm_2, 16); + vm_3 = _mm_slli_epi32(vm_3, 16); + } + + // Unsizzle the data + __m128i row_0 = _mm_unpacklo_epi32(vm_0, vm_1); // 3 2 1 0 + __m128i row_1 = _mm_unpacklo_epi32(vm_2, vm_3); // 7 6 5 4 + __m128i row_2 = _mm_unpackhi_epi32(vm_0, vm_1); // 11 10 9 8 + __m128i row_3 = _mm_unpackhi_epi32(vm_2, vm_3); // 15 14 13 12 + + // load old data & remove useless part + if(CSA_0_15) { + // Remove lower 16 bits + clut_0 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut)); + clut_1 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+1)); + clut_2 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+2)); + clut_3 = _mm_andnot_si128(clut_mask, _mm_load_si128((__m128i*)clut+3)); + } else { + // Remove higher 16 bits + clut_0 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut)); + clut_1 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+1)); + clut_2 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+2)); + clut_3 = _mm_and_si128(clut_mask, _mm_load_si128((__m128i*)clut+3)); + } + + // Merge old & new data + clut_0 = _mm_or_si128(clut_0, row_0); + clut_1 = _mm_or_si128(clut_1, row_1); + clut_2 = _mm_or_si128(clut_2, row_2); + clut_3 = _mm_or_si128(clut_3, row_3); + + _mm_store_si128((__m128i*)clut, clut_0); + _mm_store_si128((__m128i*)clut+1, clut_1); + _mm_store_si128((__m128i*)clut+2, clut_2); + _mm_store_si128((__m128i*)clut+3, clut_3); +} + +extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32 csa) +{ + u32* clut = (u32*)(g_pbyGSClut + 64*(csa & 15)); + + if (csa > 15) { + WriteCLUT_T16_I4_CSM1_core_sse2(vm, clut); + } else { + WriteCLUT_T16_I4_CSM1_core_sse2(vm, clut); + } +} + +extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2_old(u32* vm, u32* clut) { #define YET_ANOTHER_INTRINSIC #ifdef YET_ANOTHER_INTRINSIC @@ -677,7 +782,7 @@ extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut) // Note: MSVC complains about direct c-cast... // vm2 = (__m128i)_mm_shuffle_ps((__m128)vm2, (__m128)vm3, 0x88); - __m128 vm2_f = (_mm_shuffle_ps((__m128&)vm2, (__m128&)vm3, 0x88)); // 14 12 10 8 6 4 2 0 + __m128 vm2_f = (_mm_shuffle_ps((__m128&)vm2, (__m128&)vm3, 0x88)); vm2 = (__m128i&)vm2_f; vm2 = _mm_shuffle_epi32(vm2, 0xD8); @@ -997,8 +1102,47 @@ End: #endif } +__forceinline void WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32 csa) +{ + // update the right clut column (csa < 16) + u32* clut = (u32*)(g_pbyGSClut + 64*(csa & 15)); + u32 csa_right = (csa < 16) ? 16 - csa : 0; + + for(int i = (csa_right/2); i > 0 ; --i) { + WriteCLUT_T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + WriteCLUT_T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + vm += 16; // go down one column + } + + // update the left clut column + u32 csa_left = (csa >= 16) ? 16 : csa; + + // In case csa_right is odd (so csa_left is also odd), we cross the clut column + if(csa_right & 0x1) { + WriteCLUT_T16_I4_CSM1_core_sse2(vm, clut); + // go back to the base before processing left clut column + clut = (u32*)(g_pbyGSClut); + WriteCLUT_T16_I4_CSM1_core_sse2(vm, clut); + } else if(csa_right != 0) { + // go back to the base before processing left clut column + clut = (u32*)(g_pbyGSClut); + } + + for(int i = (csa_left/2); i > 0 ; --i) { + WriteCLUT_T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + WriteCLUT_T16_I4_CSM1_core_sse2(vm, clut); + clut += 16; + vm += 16; // go down one column + } +} +#endif + #endif // ZEROGS_SSE2 +#if 0 void __fastcall WriteCLUT_T16_I8_CSM1_c(u32* _vm, u32* _clut) { const static u32 map[] = @@ -1110,6 +1254,8 @@ void __fastcall WriteCLUT_T32_I4_CSM1_c(u32* vm, u32* clut) dst[7] = src[7]; } +#endif + void SSE2_UnswizzleZ16Target(u16* dst, u16* src, int iters) { diff --git a/plugins/zzogl-pg/opengl/x86.h b/plugins/zzogl-pg/opengl/x86.h index ec885c630e..547b8484c7 100644 --- a/plugins/zzogl-pg/opengl/x86.h +++ b/plugins/zzogl-pg/opengl/x86.h @@ -96,9 +96,11 @@ extern void __fastcall SwizzleColumn16_c(int y, u8* dst, u8* src, int srcpitch); extern void __fastcall SwizzleColumn8_c(int y, u8* dst, u8* src, int srcpitch); extern void __fastcall SwizzleColumn4_c(int y, u8* dst, u8* src, int srcpitch); -extern "C" void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut); +// extern "C" void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32* clut); +extern "C" void __fastcall WriteCLUT_T16_I8_CSM1_sse2(u32* vm, u32 csa); extern "C" void __fastcall WriteCLUT_T32_I8_CSM1_sse2(u32* vm, u32* clut); -extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut); +// extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32* clut); +extern "C" void __fastcall WriteCLUT_T16_I4_CSM1_sse2(u32* vm, u32 csa); extern "C" void __fastcall WriteCLUT_T32_I4_CSM1_sse2(u32* vm, u32* clut); extern void __fastcall WriteCLUT_T16_I8_CSM1_c(u32* vm, u32* clut); extern void __fastcall WriteCLUT_T32_I8_CSM1_c(u32* vm, u32* clut); diff --git a/plugins/zzogl-pg/opengl/zerogs.cpp b/plugins/zzogl-pg/opengl/zerogs.cpp index a97bd91c2c..432d4ee84d 100644 --- a/plugins/zzogl-pg/opengl/zerogs.cpp +++ b/plugins/zzogl-pg/opengl/zerogs.cpp @@ -18,68 +18,9 @@ */ //-------------------------- Includes -#if defined(_WIN32) -# include -# include "resource.h" -#endif - -#include - -#include "GS.h" -#include "Mem.h" -#include "x86.h" +#include "Util.h" #include "zerogs.h" -#include "targets.h" -#include "GLWin.h" -#include "ZZoglShaders.h" -#ifdef ZEROGS_SSE2 -#include -#endif - -//----------------------- Defines - -//-------------------------- Typedefs -typedef void (APIENTRYP _PFNSWAPINTERVAL)(int); - -//-------------------------- Extern variables - -using namespace ZeroGS; - -extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; -extern char *libraryName; -extern int g_nFrame, g_nRealFrame; - -//extern int s_nFullscreen; -//-------------------------- Variables - -primInfo *prim; - -inline u32 FtoDW(float f) { return (*((u32*)&f)); } - -int g_nDepthUpdateCount = 0; - -// Consts -const GLenum primtype[8] = { GL_POINTS, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, 0xffffffff }; -static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) - -PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL; -PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL; -PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL; -PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL; -PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL; -PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL; -PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL; -PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; -PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; -PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; -PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; -PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; -PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; -PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; -PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; -PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL; +#include "ZZoglVB.h" ///////////////////// // graphics resources @@ -87,100 +28,18 @@ PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL; bool s_bTexFlush = false; int s_nLastResolveReset = 0; int s_nResolveCounts[30] = {0}; // resolve counts for last 30 frames +int s_nNewWidth = -1, s_nNewHeight = -1; +primInfo *prim; //////////////////// // State parameters -int nBackbufferWidth, nBackbufferHeight; // ZZ - -namespace ZeroGS -{ -// = float4( 255.0 /256.0f, 255.0/65536.0f, 255.0f/(65535.0f*256.0f), 1.0f/(65536.0f*65536.0f)); -// float4 g_vdepth = float4( 65536.0f*65536.0f, 256.0f*65536.0f, 65536.0f, 256.0f); - -extern CRangeManager s_RangeMngr; // manages overwritten memory - -// returns the first and last addresses aligned to a page that cover -void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); - -int s_nNewWidth = -1, s_nNewHeight = -1; -void ChangeDeviceSize(int nNewWidth, int nNewHeight); - -void ProcessMessages(); -void RenderCustom(float fAlpha); // intro anim - -struct MESSAGE -{ - MESSAGE() {} - - MESSAGE(const char* p, u32 dw) { strcpy(str, p); dwTimeStamp = dw; } - - char str[255]; - u32 dwTimeStamp; -}; - -static list listMsgs; - -/////////////////////// -// Method Prototypes // -/////////////////////// - -void KickPoint(); -void KickLine(); -void KickTriangle(); -void KickTriangleFan(); -void KickSprite(); -void KickDummy(); - -void ResolveInRange(int start, int end); - -void ExtWrite(); - -void ResetRenderTarget(int index) -{ - FBTexture(index); -} - -DrawFn drawfn[8] = { KickDummy, KickDummy, KickDummy, KickDummy, - KickDummy, KickDummy, KickDummy, KickDummy - }; - -}; // end namespace - -// does one time only initializing/destruction - -class ZeroGSInit -{ - - public: - ZeroGSInit() - { - const u32 mem_size = MEMORY_END + 0x10000; // leave some room for out of range accesses (saves on the checks) - // clear - g_pbyGSMemory = (u8*)_aligned_malloc(mem_size, 1024); - memset(g_pbyGSMemory, 0, mem_size); - - g_pbyGSClut = (u8*)_aligned_malloc(256 * 8, 1024); // need 512 alignment! - memset(g_pbyGSClut, 0, 256*8); - memset(&GLWin, 0, sizeof(GLWin)); - } - - ~ZeroGSInit() - { - _aligned_free(g_pbyGSMemory); - g_pbyGSMemory = NULL; - - _aligned_free(g_pbyGSClut); - g_pbyGSClut = NULL; - } -}; +int g_nDepthUpdateCount = 0; static ZeroGSInit s_ZeroGSInit; -#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT -#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8 -#endif +// does one time only initializing/destruction -void ZeroGS::HandleGLError() +void HandleGLError() { FUNCLOG // check the error status of this framebuffer */ @@ -241,7 +100,7 @@ void ZeroGS::HandleGLError() } } -void ZeroGS::GSStateReset() +void ZZGSStateReset() { FUNCLOG icurctx = -1; @@ -249,7 +108,7 @@ void ZeroGS::GSStateReset() for (int i = 0; i < 2; ++i) { vb[i].Destroy(); - memset(&vb[i], 0, sizeof(ZeroGS::VB)); + memset(&vb[i], 0, sizeof(VB)); vb[i].tex0.tw = 1; vb[i].tex0.th = 1; @@ -270,98 +129,7 @@ void ZeroGS::GSStateReset() vb[1].ictx = 1; } -void ZeroGS::Reset() -{ - FUNCLOG - s_RTs.ResolveAll(); - s_DepthRTs.ResolveAll(); - - vb[0].nCount = 0; - vb[1].nCount = 0; - - memset(s_nResolveCounts, 0, sizeof(s_nResolveCounts)); - s_nLastResolveReset = 0; - - icurctx = -1; - g_vsprog = g_psprog = 0; - - GSStateReset(); - Destroy(0); - - drawfn[0] = KickDummy; - drawfn[1] = KickDummy; - drawfn[2] = KickDummy; - drawfn[3] = KickDummy; - drawfn[4] = KickDummy; - drawfn[5] = KickDummy; - drawfn[6] = KickDummy; - drawfn[7] = KickDummy; -} - -void ZeroGS::GSReset() -{ - FUNCLOG - - memset(&gs, 0, sizeof(gs)); - - ZeroGS::GSStateReset(); - - gs.prac = 1; - prim = &gs._prim[0]; - gs.nTriFanVert = -1; - gs.imageTransfer = -1; - gs.q = 1; -} - -void ZeroGS::GSSoftReset(u32 mask) -{ - FUNCLOG - - if (mask & 1) memset(&gs.path[0], 0, sizeof(gs.path[0])); - if (mask & 2) memset(&gs.path[1], 0, sizeof(gs.path[1])); - if (mask & 4) memset(&gs.path[2], 0, sizeof(gs.path[2])); - - gs.imageTransfer = -1; - gs.q = 1; - gs.nTriFanVert = -1; -} - -void ZeroGS::AddMessage(const char* pstr, u32 ms) -{ - FUNCLOG - listMsgs.push_back(MESSAGE(pstr, timeGetTime() + ms)); - ZZLog::Log("%s\n", pstr); -} - -extern RasterFont* font_p; -void ZeroGS::DrawText(const char* pstr, int left, int top, u32 color) -{ - FUNCLOG - ZZshGLDisableProfile(); - - float4 v; - v.SetColor(color); - glColor3f(v.z, v.y, v.x); - //glColor3f(((color >> 16) & 0xff) / 255.0f, ((color >> 8) & 0xff)/ 255.0f, (color & 0xff) / 255.0f); - - font_p->printString(pstr, left * 2.0f / (float)nBackbufferWidth - 1, 1 - top * 2.0f / (float)nBackbufferHeight, 0); - ZZshGLEnableProfile(); -} - -void ZeroGS::ChangeWindowSize(int nNewWidth, int nNewHeight) -{ - FUNCLOG - nBackbufferWidth = max(nNewWidth, 16); - nBackbufferHeight = max(nNewHeight, 16); - - if (!(conf.fullscreen())) - { - conf.width = nNewWidth; - conf.height = nNewHeight; - } -} - -void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) +void SetDeviceSize(int nNewWidth, int nNewHeight) { FUNCLOG s_nNewWidth = nNewWidth; @@ -374,18 +142,17 @@ void ZeroGS::SetChangeDeviceSize(int nNewWidth, int nNewHeight) } } -void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) +void ChangeDeviceSize(int nNewWidth, int nNewHeight) { FUNCLOG - //int oldscreen = s_nFullscreen; - int oldwidth = nBackbufferWidth, oldheight = nBackbufferHeight; + Size oldSize = GLWin.backbuffer; - if (!Create(nNewWidth&~7, nNewHeight&~7)) + if (!ZZCreate(nNewWidth&~7, nNewHeight&~7)) { ZZLog::Error_Log("Failed to recreate, changing to old device."); - if (Create(oldwidth, oldheight)) + if (!ZZCreate(oldSize.w, oldSize.h)) { SysMessage("Failed to create device, exiting..."); exit(0); @@ -401,7 +168,7 @@ void ZeroGS::ChangeDeviceSize(int nNewWidth, int nNewHeight) assert(vb[0].pBufferData != NULL && vb[1].pBufferData != NULL); } -void ZeroGS::SetAA(int mode) +void SetAA(int mode) { FUNCLOG float f = 1.0f; @@ -437,371 +204,100 @@ void ZeroGS::SetAA(int mode) glPointSize(f); } -void ZeroGS::Prim() -{ - FUNCLOG - - VB& curvb = vb[prim->ctxt]; - - if (curvb.CheckPrim()) Flush(prim->ctxt); - - curvb.curprim._val = prim->_val; - curvb.curprim.prim = prim->prim; -} - -void ZeroGS::ProcessMessages() -{ - FUNCLOG - - if (listMsgs.size() > 0) - { - int left = 25, top = 15; - list::iterator it = listMsgs.begin(); - - while (it != listMsgs.end()) - { - DrawText(it->str, left + 1, top + 1, 0xff000000); - DrawText(it->str, left, top, 0xffffff30); - top += 15; - - if ((int)(it->dwTimeStamp - timeGetTime()) < 0) - it = listMsgs.erase(it); - else ++it; - } - } -} - -void ZeroGS::RenderCustom(float fAlpha) -{ - FUNCLOG - GL_REPORT_ERROR(); - - fAlpha = 1; - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer - - DisableAllgl() ; - SetShaderCaller("RenderCustom"); - - glViewport(0, 0, nBackbufferWidth, nBackbufferHeight); - - // play custom animation - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - // tex coords - float4 v = float4(1 / 32767.0f, 1 / 32767.0f, 0, 0); - ZZshSetParameter4fv(pvsBitBlt.prog, pvsBitBlt.sBitBltPos, v, "g_fBitBltPos"); - v.x = (float)nLogoWidth; - v.y = (float)nLogoHeight; - ZZshSetParameter4fv(pvsBitBlt.prog, pvsBitBlt.sBitBltTex, v, "g_fBitBltTex"); - - v.x = v.y = v.z = v.w = fAlpha; - ZZshSetParameter4fv(ppsBaseTexture.prog, ppsBaseTexture.sOneColor, v, "g_fOneColor"); - - if (conf.wireframe()) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - - // inside vhDCb[0]'s target area, so render that region only - ZZshGLSetTextureParameter(ppsBaseTexture.prog, ppsBaseTexture.sFinal, ptexLogo, "Logo"); - glBindBuffer(GL_ARRAY_BUFFER, vboRect); - - SET_STREAM(); - - ZZshSetVertexShader(pvsBitBlt.prog); - ZZshSetPixelShader(ppsBaseTexture.prog); - DrawTriangleArray(); - - // restore - if (conf.wireframe()) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - - ProcessMessages(); - - GLWin.SwapGLBuffers(); - - glEnable(GL_SCISSOR_TEST); - glEnable(GL_STENCIL_TEST); - - vb[0].bSyncVars = 0; - vb[1].bSyncVars = 0; - - GL_REPORT_ERROR(); -} +//void RenderCustom(float fAlpha) +//{ +// FUNCLOG +// GL_REPORT_ERROR(); +// +// fAlpha = 1; +// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer +// +// DisableAllgl() ; +// SetShaderCaller("RenderCustom"); +// +// glViewport(0, 0, GLWin.backbuffer.w, GLWin.backbuffer.h); +// +// // play custom animation +// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); +// +// // tex coords +// float4 v = float4(1 / 32767.0f, 1 / 32767.0f, 0, 0); +// ZZshSetParameter4fv(pvsBitBlt.prog, pvsBitBlt.sBitBltPos, v, "g_fBitBltPos"); +// v.x = (float)nLogoWidth; +// v.y = (float)nLogoHeight; +// ZZshSetParameter4fv(pvsBitBlt.prog, pvsBitBlt.sBitBltTex, v, "g_fBitBltTex"); +// +// v.x = v.y = v.z = v.w = fAlpha; +// ZZshSetParameter4fv(ppsBaseTexture.prog, ppsBaseTexture.sOneColor, v, "g_fOneColor"); +// +// if (conf.wireframe()) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +// +// // inside vhDCb[0]'s target area, so render that region only +// ZZshGLSetTextureParameter(ppsBaseTexture.prog, ppsBaseTexture.sFinal, ptexLogo, "Logo"); +// glBindBuffer(GL_ARRAY_BUFFER, vboRect); +// +// SET_STREAM(); +// +// ZZshSetVertexShader(pvsBitBlt.prog); +// ZZshSetPixelShader(ppsBaseTexture.prog); +// DrawTriangleArray(); +// +// // restore +// if (conf.wireframe()) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); +// +// ProcessMessages(); +// +// GLWin.SwapGLBuffers(); +// +// glEnable(GL_SCISSOR_TEST); +// glEnable(GL_STENCIL_TEST); +// +// vb[0].bSyncVars = 0; +// vb[1].bSyncVars = 0; +// +// GL_REPORT_ERROR(); +//} ////////////////////////// // Internal Definitions // ////////////////////////// - -__forceinline void MOVZ(VertexGPU *p, u32 gsz, const VB& curvb) -{ - p->z = (curvb.zprimmask == 0xffff) ? min((u32)0xffff, gsz) : gsz; -} - -__forceinline void MOVFOG(VertexGPU *p, Vertex gsf) -{ - p->f = ((s16)(gsf).f << 7) | 0x7f; -} - - -int Values[100] = {0, }; - -inline void SET_VERTEX(VertexGPU *p, int Index, const VB& curvb) -{ - int index = Index; - p->x = ((((int)gs.gsvertex[index].x - curvb.offset.x) >> 1) & 0xffff); - p->y = ((((int)gs.gsvertex[index].y - curvb.offset.y) >> 1) & 0xffff); - p->f = ((s16)gs.gsvertex[index].f << 7) | 0x7f; - - MOVZ(p, gs.gsvertex[index].z, curvb); - - p->rgba = prim->iip ? gs.gsvertex[index].rgba : gs.rgba; - -// This code is somehow incorrect -// if ((gs.texa.aem) && ((p->rgba & 0xffffff ) == 0)) -// p->rgba = 0; - - if (conf.settings().texa) - { - u32 B = ((p->rgba & 0xfe000000) >> 1) + - (0x01000000 * curvb.fba.fba) ; - p->rgba = (p->rgba & 0xffffff) + B; - } - - if (prim->tme) - { - if (prim->fst) - { - p->s = (float)gs.gsvertex[index].u * fiTexWidth[prim->ctxt]; - p->t = (float)gs.gsvertex[index].v * fiTexHeight[prim->ctxt]; - p->q = 1; - } - else - { - p->s = gs.gsvertex[index].s; - p->t = gs.gsvertex[index].t; - p->q = gs.gsvertex[index].q; - } - } -} - -static __forceinline void OUTPUT_VERT(VertexGPU vert, u32 id) -{ -#ifdef WRITE_PRIM_LOGS - ZZLog::Prim_Log("%c%d(%d): xyzf=(%4d,%4d,0x%x,%3d), rgba=0x%8.8x, stq = (%2.5f,%2.5f,%2.5f)\n", - id == 0 ? '*' : ' ', id, prim->prim, vert.x / 8, vert.y / 8, vert.z, vert.f / 128, - vert.rgba, Clamp(vert.s, -10, 10), Clamp(vert.t, -10, 10), Clamp(vert.q, -10, 10)); -#endif -} - -void ZeroGS::KickPoint() +__forceinline void SetFogColor(float4 v) { FUNCLOG - assert(gs.primC >= 1); - - VB& curvb = vb[prim->ctxt]; - - curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert(vb[prim->ctxt].nCount == 0); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(1); - - int last = gs.primNext(2); - - VertexGPU* p = curvb.pBufferData + curvb.nCount; - SET_VERTEX(&p[0], last, curvb); - curvb.nCount++; - - OUTPUT_VERT(p[0], 0); -} - -void ZeroGS::KickLine() -{ - FUNCLOG - assert(gs.primC >= 2); - VB& curvb = vb[prim->ctxt]; - - curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert(vb[prim->ctxt].nCount == 0); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(2); - - int next = gs.primNext(); - int last = gs.primNext(2); - - VertexGPU* p = curvb.pBufferData + curvb.nCount; - SET_VERTEX(&p[0], next, curvb); - SET_VERTEX(&p[1], last, curvb); - - curvb.nCount += 2; - - OUTPUT_VERT(p[0], 0); - OUTPUT_VERT(p[1], 1); -} - -void ZeroGS::KickTriangle() -{ - FUNCLOG - assert(gs.primC >= 3); - VB& curvb = vb[prim->ctxt]; - - curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert(vb[prim->ctxt].nCount == 0); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(3); - - VertexGPU* p = curvb.pBufferData + curvb.nCount; - SET_VERTEX(&p[0], 0, curvb); - SET_VERTEX(&p[1], 1, curvb); - SET_VERTEX(&p[2], 2, curvb); - - curvb.nCount += 3; - - OUTPUT_VERT(p[0], 0); - OUTPUT_VERT(p[1], 1); - OUTPUT_VERT(p[2], 2); -} - -void ZeroGS::KickTriangleFan() -{ - FUNCLOG - assert(gs.primC >= 3); - VB& curvb = vb[prim->ctxt]; - - curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert(vb[prim->ctxt].nCount == 0); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(3); - - VertexGPU* p = curvb.pBufferData + curvb.nCount; - SET_VERTEX(&p[0], 0, curvb); - SET_VERTEX(&p[1], 1, curvb); - SET_VERTEX(&p[2], 2, curvb); - - curvb.nCount += 3; - - // add 1 to skip the first vertex - - if (gs.primIndex == gs.nTriFanVert) gs.primIndex = gs.primNext(); - - OUTPUT_VERT(p[0], 0); - OUTPUT_VERT(p[1], 1); - OUTPUT_VERT(p[2], 2); -} - -void SetKickVertex(VertexGPU *p, Vertex v, int next, const VB& curvb) -{ - SET_VERTEX(p, next, curvb); - MOVZ(p, v.z, curvb); - MOVFOG(p, v); -} - -void ZeroGS::KickSprite() -{ - FUNCLOG - assert(gs.primC >= 2); - VB& curvb = vb[prim->ctxt]; - - curvb.FlushTexData(); - - if ((vb[!prim->ctxt].nCount > 0) && (vb[prim->ctxt].gsfb.fbp == vb[!prim->ctxt].gsfb.fbp)) - { - assert(vb[prim->ctxt].nCount == 0); - Flush(!prim->ctxt); - } - - curvb.NotifyWrite(6); - int next = gs.primNext(); - int last = gs.primNext(2); - // sprite is too small and AA shows lines (tek4, Mana Khemia) - gs.gsvertex[last].x += (4 * AA.x); - gs.gsvertex[last].y += (4 * AA.y); - - // might be bad sprite (KH dialog text) - //if( gs.gsvertex[next].x == gs.gsvertex[last].x || gs.gsvertex[next].y == gs.gsvertex[last].y ) - //return; - - VertexGPU* p = curvb.pBufferData + curvb.nCount; - - SetKickVertex(&p[0], gs.gsvertex[last], next, curvb); - SetKickVertex(&p[3], gs.gsvertex[last], next, curvb); - SetKickVertex(&p[1], gs.gsvertex[last], last, curvb); - SetKickVertex(&p[4], gs.gsvertex[last], last, curvb); - SetKickVertex(&p[2], gs.gsvertex[last], next, curvb); - - p[2].s = p[1].s; - p[2].x = p[1].x; - - SetKickVertex(&p[5], gs.gsvertex[last], last, curvb); - - p[5].s = p[0].s; - p[5].x = p[0].x; - - curvb.nCount += 6; - - OUTPUT_VERT(p[0], 0); - OUTPUT_VERT(p[1], 1); + SetShaderCaller("SetFogColor"); + ZZshSetParameter4fv(g_fparamFogColor, v, "g_fParamFogColor"); } -void ZeroGS::KickDummy() -{ - FUNCLOG - //ZZLog::Greg_Log("Kicking bad primitive: %.8x\n", *(u32*)prim); -} - -void ZeroGS::SetFogColor(u32 fog) +__forceinline void SetFogColor(u32 fog) { FUNCLOG -// Always set the fog color, even if it was already set. -// if (gs.fogcol != fog) -// { gs.fogcol = fog; - ZeroGS::FlushBoth(); - - SetShaderCaller("SetFogColor"); + FlushBoth(); + float4 v; // set it immediately v.SetColor(gs.fogcol); - ZZshSetParameter4fv(g_fparamFogColor, v, "g_fParamFogColor"); - -// } + SetFogColor(v); } -void ZeroGS::SetFogColor(GIFRegFOGCOL* fog) +__forceinline void SetFogColor(GIFRegFOGCOL* fog) { FUNCLOG - SetShaderCaller("SetFogColor"); float4 v; v.x = fog->FCR / 255.0f; v.y = fog->FCG / 255.0f; v.z = fog->FCB / 255.0f; - ZZshSetParameter4fv(g_fparamFogColor, v, "g_fParamFogColor"); + SetFogColor(v); } -void ZeroGS::ExtWrite() +void ExtWrite() { FUNCLOG ZZLog::Warn_Log("A hollow voice says 'EXTWRITE'! Nothing happens."); @@ -833,217 +329,6 @@ void ZeroGS::ExtWrite() // case 7: ASSERT(0); return false; // default: __assume(0); -bool IsDirty(u32 highdword, u32 psm, int cld, int cbp) -{ - int cpsm = ZZOglGet_cpsm_TexBits(highdword); - int csm = ZZOglGet_csm_TexBits(highdword); - - if (cpsm > 1 || csm) - { - // Mana Khemia triggers this. - //ZZLog::Error_Log("16 bit clut not supported."); - return true; - } - - int csa = ZZOglGet_csa_TexBits(highdword); - - int entries = PSMT_IS8CLUT(psm) ? 256 : 16; - - u64* src = (u64*)(g_pbyGSMemory + cbp * 256); - u64* dst = (u64*)(g_pbyGSClut + 64 * csa); - - bool bRet = false; - - // FIXME code generated by intrinsics is the same as the linux asm. - // However there is no "cmp %%esi, 0x90" equivalent in the windows asm !!! - // So control flow must be check -#define TEST_THIS -#ifdef TEST_THIS - while(entries != 0) { -#ifdef ZEROGS_SSE2 - // Note: local memory datas are swizzles - __m128i src_0 = _mm_load_si128((__m128i*)src); // 9 8 1 0 - __m128i src_1 = _mm_load_si128((__m128i*)src+1); // 11 10 3 2 - __m128i src_2 = _mm_load_si128((__m128i*)src+2); // 13 12 5 4 - __m128i src_3 = _mm_load_si128((__m128i*)src+3); // 15 14 7 6 - - __m128i dst_0 = _mm_load_si128((__m128i*)dst); - __m128i dst_1 = _mm_load_si128((__m128i*)dst+1); - __m128i dst_2 = _mm_load_si128((__m128i*)dst+2); - __m128i dst_3 = _mm_load_si128((__m128i*)dst+3); - - __m128i result = _mm_cmpeq_epi32(_mm_unpacklo_epi64(src_0, src_1), dst_0); - - __m128i result_tmp = _mm_cmpeq_epi32(_mm_unpacklo_epi64(src_2, src_3), dst_1); - result = _mm_and_si128(result, result_tmp); - - result_tmp = _mm_cmpeq_epi32(_mm_unpackhi_epi64(src_0, src_1), dst_2); - result = _mm_and_si128(result, result_tmp); - - result_tmp = _mm_cmpeq_epi32(_mm_unpackhi_epi64(src_2, src_3), dst_3); - result = _mm_and_si128(result, result_tmp); - - u32 result_int = _mm_movemask_epi8(result); - if (result_int != 0xFFFF) { - bRet = true; - break; - } -#else - // I see no point to keep an mmx version. SSE2 versions is probably faster. - // Keep a slow portable C version for reference/debug - // Note: local memory datas are swizzles - if (dst[0] != src[0] || dst[1] != src[2] || dst[2] != src[4] || dst[3] != src[6] - || dst[4] != src[1] || dst[5] != src[3] || dst[6] != src[5] || dst[7] != src[7]) { - bRet = true; - break; - } -#endif - - if (entries & 0x10) { - src -= 56; // go back and down one column - } - - src += 32; // go to the right block - - if (entries == 0x90) { - src += 32; // skip whole block - } - - dst += 8; - entries -= 16; - } -#else - - // do a fast test with MMX -#ifdef _MSC_VER - int storeebx; - __asm - { - mov storeebx, ebx - mov edx, dst - mov ecx, src - mov ebx, entries - -Start: - movq mm0, [edx] - movq mm1, [edx+8] - pcmpeqd mm0, [ecx] - pcmpeqd mm1, [ecx+16] - - movq mm2, [edx+16] - movq mm3, [edx+24] - pcmpeqd mm2, [ecx+32] - pcmpeqd mm3, [ecx+48] - - pand mm0, mm1 - pand mm2, mm3 - movq mm4, [edx+32] - movq mm5, [edx+40] - pcmpeqd mm4, [ecx+8] - pcmpeqd mm5, [ecx+24] - - pand mm0, mm2 - pand mm4, mm5 - movq mm6, [edx+48] - movq mm7, [edx+56] - pcmpeqd mm6, [ecx+40] - pcmpeqd mm7, [ecx+56] - - pand mm0, mm4 - pand mm6, mm7 - pand mm0, mm6 - - pmovmskb eax, mm0 - cmp eax, 0xff - je Continue - mov bRet, 1 - jmp Return - -Continue: - cmp ebx, 16 - jle Return - - test ebx, 0x10 - jz AddEcx - sub ecx, 448 // go back and down one column, - -AddEcx: - add ecx, 256 // go to the right block - - - jne Continue1 - add ecx, 256 // skip whole block - -Continue1: - add edx, 64 - sub ebx, 16 - jmp Start - -Return: - emms - mov ebx, storeebx - } - -#else // linux - // do a fast test with MMX - __asm__( - ".intel_syntax\n" - "Start:\n" - "movq %%mm0, [%%ecx]\n" - "movq %%mm1, [%%ecx+8]\n" - "pcmpeqd %%mm0, [%%edx]\n" - "pcmpeqd %%mm1, [%%edx+16]\n" - "movq %%mm2, [%%ecx+16]\n" - "movq %%mm3, [%%ecx+24]\n" - "pcmpeqd %%mm2, [%%edx+32]\n" - "pcmpeqd %%mm3, [%%edx+48]\n" - "pand %%mm0, %%mm1\n" - "pand %%mm2, %%mm3\n" - "movq %%mm4, [%%ecx+32]\n" - "movq %%mm5, [%%ecx+40]\n" - "pcmpeqd %%mm4, [%%edx+8]\n" - "pcmpeqd %%mm5, [%%edx+24]\n" - "pand %%mm0, %%mm2\n" - "pand %%mm4, %%mm5\n" - "movq %%mm6, [%%ecx+48]\n" - "movq %%mm7, [%%ecx+56]\n" - "pcmpeqd %%mm6, [%%edx+40]\n" - "pcmpeqd %%mm7, [%%edx+56]\n" - "pand %%mm0, %%mm4\n" - "pand %%mm6, %%mm7\n" - "pand %%mm0, %%mm6\n" - "pmovmskb %%eax, %%mm0\n" - "cmp %%eax, 0xff\n" - "je Continue\n" - ".att_syntax\n" - "movb $1, %0\n" - ".intel_syntax\n" - "jmp Return\n" - "Continue:\n" - "cmp %%esi, 16\n" - "jle Return\n" - "test %%esi, 0x10\n" - "jz AddEcx\n" - "sub %%edx, 448\n" // go back and down one column - "AddEcx:\n" - "add %%edx, 256\n" // go to the right block - "cmp %%esi, 0x90\n" - "jne Continue1\n" - "add %%edx, 256\n" // skip whole block - "Continue1:\n" - "add %%ecx, 64\n" - "sub %%esi, 16\n" - "jmp Start\n" - "Return:\n" - "emms\n" - - ".att_syntax\n" : "=m"(bRet) : "c"(dst), "d"(src), "S"(entries) : "eax", "memory"); - -#endif // _WIN32 -#endif - return bRet; -} - // cld state: // 000 - clut data is not loaded; data in the temp buffer is stored // 001 - clut data is always loaded. @@ -1053,7 +338,7 @@ Return: // 101 - cbp1 is compared with cbp. if different, clut data is loaded. // GSdx sets cbp0 & cbp1 when checking for clut changes. ZeroGS sets them in texClutWrite. -bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) +bool CheckChangeInClut(u32 highdword, u32 psm) { FUNCLOG int cld = ZZOglGet_cld_TexBits(highdword); @@ -1084,19 +369,32 @@ bool ZeroGS::CheckChangeInClut(u32 highdword, u32 psm) if (gs.cbp[1] == cbp) return false; break; - //case 4: return gs.cbp[0] != cbp; - //case 5: return gs.cbp[1] != cbp; - - // default: load - default: break; } - return IsDirty(highdword, psm, cld, cbp); + // Compare the cache with current memory + + // CSM2 is not supported + if (ZZOglGet_csm_TexBits(highdword)) + return true; + + int cpsm = ZZOglGet_cpsm_TexBits(highdword); + int csa = ZZOglGet_csa_TexBits(highdword); + int entries = PSMT_IS8CLUT(psm) ? 256 : 16; + + u8* GSMem = g_pbyGSMemory + cbp * 256; + + if (PSMT_IS32BIT(cpsm)) + return Cmp_ClutBuffer_GSMem((u32*)GSMem, csa, entries*4); + else { + // Mana Khemia triggers this. + //ZZLog::Error_Log("16 bit clut not supported."); + return Cmp_ClutBuffer_GSMem((u16*)GSMem, csa, entries*2); + } } -void ZeroGS::texClutWrite(int ctx) +void texClutWrite(int ctx) { FUNCLOG s_bTexFlush = false; @@ -1138,110 +436,7 @@ void ZeroGS::texClutWrite(int ctx) Flush(!ctx); - int entries = PSMT_IS8CLUT(tex0.psm) ? 256 : 16; - - if (tex0.csm) - { - switch (tex0.cpsm) - { - // 16bit psm - // eggomania uses non16bit textures for csm2 - - case PSMCT16: - { - u16* src = (u16*)g_pbyGSMemory + tex0.cbp * 128; - u16 *dst = (u16*)(g_pbyGSClut + 32 * (tex0.csa & 15) + (tex0.csa >= 16 ? 2 : 0)); - - for (int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress16_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst += 2; - - // check for wrapping - - if (((u32)(uptr)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut + 2); - } - break; - } - - case PSMCT16S: - { - u16* src = (u16*)g_pbyGSMemory + tex0.cbp * 128; - u16 *dst = (u16*)(g_pbyGSClut + 32 * (tex0.csa & 15) + (tex0.csa >= 16 ? 2 : 0)); - - for (int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress16S_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst += 2; - - // check for wrapping - - if (((u32)(uptr)dst & 0x3ff) == 0) dst = (u16*)(g_pbyGSClut + 2); - } - break; - } - - case PSMCT32: - case PSMCT24: - { - u32* src = (u32*)g_pbyGSMemory + tex0.cbp * 64; - u32 *dst = (u32*)(g_pbyGSClut + 64 * tex0.csa); - - // check if address exceeds src - - if (src + getPixelAddress32_0(gs.clut.cou + entries - 1, gs.clut.cov, gs.clut.cbw) >= (u32*)g_pbyGSMemory + 0x00100000) - ZZLog::Error_Log("texClutWrite out of bounds."); - else - for (int i = 0; i < entries; ++i) - { - *dst = src[getPixelAddress32_0(gs.clut.cou+i, gs.clut.cov, gs.clut.cbw)]; - dst++; - } - break; - } - - default: - { - //ZZLog::Debug_Log("Unknown cpsm: %x (%x).", tex0.cpsm, tex0.psm); - break; - } - } - } - else - { - u32* src = (u32*)(g_pbyGSMemory + 256 * tex0.cbp); - - if (entries == 16) - { - switch (tex0.cpsm) - { - case PSMCT24: - case PSMCT32: - WriteCLUT_T32_I4_CSM1(src, (u32*)(g_pbyGSClut + 64 * tex0.csa)); - break; - - default: - WriteCLUT_T16_I4_CSM1(src, (u32*)(g_pbyGSClut + 32*(tex0.csa & 15) + (tex0.csa >= 16 ? 2 : 0))); - break; - } - } - else - { - switch (tex0.cpsm) - { - case PSMCT24: - case PSMCT32: - WriteCLUT_T32_I8_CSM1(src, (u32*)(g_pbyGSClut + 64 * tex0.csa)); - break; - - default: - // sse2 for 256 is more complicated, so use regular - WriteCLUT_T16_I8_CSM1_c(src, (u32*)(g_pbyGSClut + 32*(tex0.csa & 15) + (tex0.csa >= 16 ? 2 : 0))); - break; - } - - } - } + // Write the memory to clut buffer + GSMem_to_ClutBuffer(tex0); } - diff --git a/plugins/zzogl-pg/opengl/zerogs.h b/plugins/zzogl-pg/opengl/zerogs.h index 3b5aff2507..1c6c1cecde 100644 --- a/plugins/zzogl-pg/opengl/zerogs.h +++ b/plugins/zzogl-pg/opengl/zerogs.h @@ -25,523 +25,62 @@ #endif // ----------------------------- Includes -#include -#include -#include -#include -#include - -#include "ZZGl.h" -#include "GS.h" -#include "CRC.h" -#include "rasterfont.h" // simple font - -using namespace std; - -//------------------------ Constants ---------------------- -#define VB_BUFFERSIZE 0x400 - -// Used in a logarithmic Z-test, as (1-o(1))/log(MAX_U32). -const float g_filog32 = 0.999f / (32.0f * logf(2.0f)); - -//------------------------ Inlines ------------------------- - -// Calculate maximum height for target -inline int get_maxheight(int fbp, int fbw, int psm) -{ - int ret; - - if (fbw == 0) return 0; - - ret = (((0x00100000 - 64 * fbp) / fbw) & ~0x1f); - if (PSMT_ISHALF(psm)) ret *= 2; - - return ret; -} - +#include "PS2Edefs.h" // ------------------------ Variables ------------------------- -// all textures have this width -extern int GPU_TEXWIDTH; -extern float g_fiGPU_TEXWIDTH; -#define MASKDIVISOR 0 // Used for decrement bitwise mask texture size if 1024 is too big -#define GPU_TEXMASKWIDTH (1024 >> MASKDIVISOR) // bitwise mask width for region repeat mode - -extern u32 ptexBlocks; // holds information on block tiling. It's texture number in OpenGL -- if 0 than such texture -extern u32 ptexConv16to32; // does not exists. This textures should be created on start and released on finish. -extern u32 ptexBilinearBlocks; -extern u32 ptexConv32to16; - -// this is currently *not* used as a bool, in spite of its moniker --air -// Actually, the only thing written to it is 1 or 0, which makes the (g_bSaveFlushedFrame & 0x80000000) check rather bizzare. -//extern u32 g_bSaveFlushedFrame; - ////////////////////////// // State parameters - -#ifdef ZEROGS_DEVBUILD -extern char* EFFECT_NAME; -extern char* EFFECT_DIR; -extern u32 g_nGenVars, g_nTexVars, g_nAlphaVars, g_nResolve; -extern bool g_bSaveTrans, g_bUpdateEffect, g_bSaveTex, g_bSaveResolved; +#if defined(_WIN32) +# include +# include "resource.h" #endif -extern u32 s_uFramebuffer; -extern int g_nPixelShaderVer; +#include + +#include "GS.h" +#include "targets.h" +#include "GLWin.h" +#include "ZZoglShaders.h" +#include "ZZClut.h" +#include "HostMemory.h" + +typedef void (APIENTRYP _PFNSWAPINTERVAL)(int); + +PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL; +PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL; +PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL; +PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL; +PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL; +PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL; +PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL; +PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL; +PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL; +PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL; +PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL; +PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL; +PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL; +PFNGLDRAWBUFFERSPROC glDrawBuffers = NULL; + +#ifndef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT +#define GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT 0x8CD8 +#endif + +bool ZZCreate(int width, int height); +void ZZGSStateReset(); -extern bool s_bWriteDepth; - -extern u32 ptexLogo; -extern int nLogoWidth, nLogoHeight; -extern int nBackbufferWidth, nBackbufferHeight; - -namespace ZeroGS -{ - -typedef void (*DrawFn)(); - -// managers render-to-texture targets - -class CRenderTarget -{ - - public: - CRenderTarget(); - virtual ~CRenderTarget(); - - virtual bool Create(const frameInfo& frame); - virtual void Destroy(); - - // set the GPU_POSXY variable, scissor rect, and current render target - void SetTarget(int fbplocal, const Rect2& scissor, int context); - void SetViewport(); - - // copies/creates the feedback contents - inline void CreateFeedback() - { - if (ptexFeedback == 0 || !(status&TS_FeedbackReady)) - _CreateFeedback(); - } - - virtual void Resolve(); - virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range - virtual void Update(int context, CRenderTarget* pdepth); - virtual void ConvertTo32(); // converts a psm==2 target, to a psm==0 - virtual void ConvertTo16(); // converts a psm==0 target, to a psm==2 - - virtual bool IsDepth() { return false; } - - void SetRenderTarget(int targ); - - void* psys; // system data used for comparison - u32 ptex; - - int fbp, fbw, fbh, fbhCalc; // if fbp is negative, virtual target (not mapped to any real addr) - int start, end; // in bytes - u32 lastused; // time stamp since last used - float4 vposxy; - - u32 fbm; - u16 status; - u8 psm; - u8 resv0; - Rect scissorrect; - - u8 created; // Check for object destruction/creating for r201. - - //int startresolve, endresolve; - u32 nUpdateTarg; // use this target to update the texture if non 0 (one time only) - - // this is optionally used when feedback effects are used (render target is used as a texture when rendering to itself) - u32 ptexFeedback; - - enum TargetStatus - { - TS_Resolved = 1, - TS_NeedUpdate = 2, - TS_Virtual = 4, // currently not mapped to memory - TS_FeedbackReady = 8, // feedback effect is ready and doesn't need to be updated - TS_NeedConvert32 = 16, - TS_NeedConvert16 = 32, - }; - inline float4 DefaultBitBltPos(); - inline float4 DefaultBitBltTex(); - - private: - void _CreateFeedback(); - inline bool InitialiseDefaultTexture(u32 *p_ptr, int fbw, int fbh) ; -}; - -// manages zbuffers - -class CDepthTarget : public CRenderTarget -{ - - public: - CDepthTarget(); - virtual ~CDepthTarget(); - - virtual bool Create(const frameInfo& frame); - virtual void Destroy(); - - virtual void Resolve(); - virtual void Resolve(int startrange, int endrange); // resolves only in the allowed range - virtual void Update(int context, CRenderTarget* prndr); - - virtual bool IsDepth() { return true; } - - void SetDepthStencilSurface(); - - u32 pdepth; // 24 bit, will contain the stencil buffer if possible - u32 pstencil; // if not 0, contains the stencil buffer - int icount; // internal counter -}; - -// manages contiguous chunks of memory (width is always 1024) - -class CMemoryTarget -{ - public: - struct TEXTURE - { - inline TEXTURE() : tex(0), memptr(NULL), ref(0) {} - inline ~TEXTURE() { glDeleteTextures(1, &tex); _aligned_free(memptr); } - - u32 tex; - u8* memptr; // GPU memory used for comparison - int ref; - }; - - inline CMemoryTarget() : ptex(NULL), starty(0), height(0), realy(0), realheight(0), usedstamp(0), psm(0), cpsm(0), channels(0), clearminy(0), clearmaxy(0), validatecount(0) {} - - inline CMemoryTarget(const CMemoryTarget& r) - { - ptex = r.ptex; - - if (ptex != NULL) ptex->ref++; - - starty = r.starty; - height = r.height; - realy = r.realy; - realheight = r.realheight; - usedstamp = r.usedstamp; - psm = r.psm; - cpsm = r.cpsm; - clut = r.clut; - clearminy = r.clearminy; - clearmaxy = r.clearmaxy; - widthmult = r.widthmult; - texH = r.texH; - texW = r.texW; - channels = r.channels; - validatecount = r.validatecount; - fmt = r.fmt; - } - - ~CMemoryTarget() { Destroy(); } - - inline void Destroy() - { - if (ptex != NULL && ptex->ref > 0) - { - if (--ptex->ref <= 0) delete ptex; - } - - ptex = NULL; - } - - // returns true if clut data is synced - bool ValidateClut(const tex0Info& tex0); - // returns true if tex data is synced - bool ValidateTex(const tex0Info& tex0, int starttex, int endtex, bool bDeleteBadTex); - - // realy is offset in pixels from start of valid region - // so texture in memory is [realy,starty+height] - // valid texture is [starty,starty+height] - // offset in mem [starty-realy, height] - TEXTURE* ptex; // can be 16bit - - int starty, height; // assert(starty >= realy) - int realy, realheight; // this is never touched once allocated - // realy is start pointer of data in 4M data block (start) and size (end-start). - - u32 usedstamp; - u8 psm, cpsm; // texture and clut format. For psm, only 16bit/32bit differentiation matters - - u32 fmt; - - int widthmult; // Either 1 or 2. - int channels; // The number of pixels per PSM format word. channels == PIXELS_PER_WORD(psm) - // This is the real drawing size in pixels of the texture in renderbuffer. - int texW; // (realheight + widthmult - 1)/widthmult == realheight or [(realheight+1)/2] - int texH; // GPU_TEXWIDTH *widthmult * channels; - - int clearminy, clearmaxy; // when maxy > 0, need to check for clearing - - int validatecount; // count how many times has been validated, if too many, destroy - - vector clut; // if nonzero, texture uses CLUT -}; - - -struct VB -{ - VB(); - ~VB(); - - void Destroy(); - - inline bool CheckPrim() - { - static const int PRIMMASK = 0x0e; // for now ignore 0x10 (AA) - - if ((PRIMMASK & prim->_val) != (PRIMMASK & curprim._val) || primtype[prim->prim] != primtype[curprim.prim]) - return nCount > 0; - - return false; - } - - void CheckFrame(int tbp); - - // context specific state - Point offset; - Rect2 scissor; - tex0Info tex0; - tex1Info tex1; - miptbpInfo miptbp0; - miptbpInfo miptbp1; - alphaInfo alpha; - fbaInfo fba; - clampInfo clamp; - pixTest test; - u32 ptexClamp[2]; // textures for x and y dir region clamping - -public: - void FlushTexData(); - inline int CheckFrameAddConstraints(int tbp); - inline void CheckScissors(int maxpos); - inline void CheckFrame32bitRes(int maxpos); - inline int FindMinimalMemoryConstrain(int tbp, int maxpos); - inline int FindZbufferMemoryConstrain(int tbp, int maxpos); - inline int FindMinimalHeightConstrain(int maxpos); - - inline int CheckFrameResolveRender(int tbp); - inline void CheckFrame16vs32Conversion(); - inline int CheckFrameResolveDepth(int tbp); - - inline void FlushTexUnchangedClutDontUpdate() ; - inline void FlushTexClutDontUpdate() ; - inline void FlushTexClutting() ; - inline void FlushTexSetNewVars(u32 psm) ; - - // notify VB that nVerts need to be written to pbuf - inline void NotifyWrite(int nVerts) - { - assert(pBufferData != NULL && nCount <= nNumVertices && nVerts > 0); - - if (nCount + nVerts > nNumVertices) - { - // recreate except with a bigger count - VertexGPU* ptemp = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU) * nNumVertices * 2, 256); - memcpy_amd(ptemp, pBufferData, sizeof(VertexGPU) * nCount); - nNumVertices *= 2; - assert(nCount + nVerts <= nNumVertices); - _aligned_free(pBufferData); - pBufferData = ptemp; - } - } - - void Init(int nVerts) - { - if (pBufferData == NULL && nVerts > 0) - { - pBufferData = (VertexGPU*)_aligned_malloc(sizeof(VertexGPU) * nVerts, 256); - nNumVertices = nVerts; - } - - nCount = 0; - } - - u8 bNeedFrameCheck; - u8 bNeedZCheck; - u8 bNeedTexCheck; - u8 dummy0; - - union - { - struct - { - u8 bTexConstsSync; // only pixel shader constants that context owns - u8 bVarsTexSync; // texture info - u8 bVarsSetTarg; - u8 dummy1; - }; - - u32 bSyncVars; - }; - - int ictx; - VertexGPU* pBufferData; // current allocated data - - int nNumVertices; // size of pBufferData in terms of VertexGPU objects - int nCount; - primInfo curprim; // the previous prim the current buffers are set to - - zbufInfo zbuf; - frameInfo gsfb; // the real info set by FRAME cmd - frameInfo frame; - int zprimmask; // zmask for incoming points - -union -{ - u32 uCurTex0Data[2]; // current tex0 data - GIFRegTEX0 uCurTex0; -}; - u32 uNextTex0Data[2]; // tex0 data that has to be applied if bNeedTexCheck is 1 - - //int nFrameHeights[8]; // frame heights for the past frame changes - int nNextFrameHeight; - - CMemoryTarget* pmemtarg; // the current mem target set - CRenderTarget* prndr; - CDepthTarget* pdepth; - -}; - -// visible members -extern DrawFn drawfn[8]; - -// VB variables -extern VB vb[2]; -extern float fiTexWidth[2], fiTexHeight[2]; // current tex width and height -extern vector g_vboBuffers; // VBOs for all drawing commands -extern GLuint vboRect; -extern int g_nCurVBOIndex; - -void AddMessage(const char* pstr, u32 ms = 5000); -void DrawText(const char* pstr, int left, int top, u32 color); -void ChangeWindowSize(int nNewWidth, int nNewHeight); -void SetChangeDeviceSize(int nNewWidth, int nNewHeight); -void ChangeDeviceSize(int nNewWidth, int nNewHeight); -void SetAA(int mode); -void SetCRC(int crc); - -void ReloadEffects(); - -// Methods // -bool IsGLExt(const char* szTargetExtension); ///< returns true if the the opengl extension is supported -inline bool Create_Window(int _width, int _height); -bool Create(int width, int height); -void Destroy(bool bD3D); - -void Reset(); // call to destroy video resources -void GSStateReset(); -void GSReset(); -void GSSoftReset(u32 mask); - -void HandleGLError(); - -// called on a primitive switch -void Prim(); - -void SetTexFlush(); // flush current vertices, call before setting new registers (the main render method) void Flush(int context); void FlushBoth(); -void ExtWrite(); -void SetWriteDepth(); -bool IsWriteDepth(); +//extern u32 ptexLogo; +//extern int nLogoWidth, nLogoHeight; +//extern GLuint vboRect; +//void ProcessMessages(); +//void RenderCustom(float fAlpha); // intro anim -void SetDestAlphaTest(); -bool IsWriteDestAlphaTest(); - -void SetFogColor(u32 fog); -void SetFogColor(GIFRegFOGCOL* fog); -void SaveTex(tex0Info* ptex, int usevid); -char* NamedSaveTex(tex0Info* ptex, int usevid); - -// called when trxdir is accessed. If host is involved, transfers memory to temp buffer byTransferBuf. -// Otherwise performs the transfer. TODO: Perhaps divide the transfers into chunks? -void InitTransferHostLocal(); -void TransferHostLocal(const void* pbyMem, u32 nQWordSize); - -void InitTransferLocalHost(); -void TransferLocalHost(void* pbyMem, u32 nQWordSize); -inline void TerminateLocalHost() {} - -void TransferLocalLocal(); - -// switches the render target to the real target, flushes the current render targets and renders the real image -void RenderCRTC(int interlace); -void ResetRenderTarget(int index); - -bool CheckChangeInClut(u32 highdword, u32 psm); // returns true if clut will change after this tex0 op - -// call to load CLUT data (depending on CLD) -void texClutWrite(int ctx); - -int Save(s8* pbydata); -bool Load(s8* pbydata); - -void SaveSnapshot(const char* filename); -bool SaveRenderTarget(const char* filename, int width, int height, int jpeg); -bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height); -bool SaveJPEG(const char* filename, int width, int height, const void* pdata, int quality); -bool SaveTGA(const char* filename, int width, int height, void* pdata); -void Stop_Avi(); -void Delete_Avi_Capture(); - -// private methods -void FlushSysMem(const RECT* prc); -void _Resolve(const void* psrc, int fbp, int fbw, int fbh, int psm, u32 fbm, bool mode); - -// returns the first and last addresses aligned to a page that cover -void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw); - -// inits the smallest rectangle in ptexMem that covers this region in ptexMem -// returns the offset that needs to be added to the locked rect to get the beginning of the buffer -//void GetMemRect(RECT& rc, int psm, int x, int y, int w, int h, int bp, int bw); - -void SetContextTarget(int context) ; - -void NeedFactor(int w); -void ResetAlphaVariables(); - -void StartCapture(); -void StopCapture(); -void CaptureFrame(); - -// Perform clutting for flushed texture. Better check if it needs a prior call. -inline void CluttingForFlushedTex(tex0Info* tex0, u32 Data, int ictx) -{ - tex0->cbp = ZZOglGet_cbp_TexBits(Data); - tex0->cpsm = ZZOglGet_cpsm_TexBits(Data); - tex0->csm = ZZOglGet_csm_TexBits(Data); - tex0->csa = ZZOglGet_csa_TexBits(Data); - tex0->cld = ZZOglGet_cld_TexBits(Data); - - ZeroGS::texClutWrite(ictx); - }; - -// The size in bytes of x strings (of texture). -inline int MemorySize(int x) -{ - return 4 * GPU_TEXWIDTH * x; -} - -// Return the address in memory of data block for string x. -inline u8* MemoryAddress(int x) -{ - return g_pbyGSMemory + MemorySize(x); -} - -template -inline u8* _MemoryAddress(int x) -{ - return g_pbyGSMemory + mult * x; -} - -}; #endif