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 @@
-
+
diff --git a/plugins/GSdx/GS.cpp b/plugins/GSdx/GS.cpp
index a89514746a..2d09fb884d 100644
--- a/plugins/GSdx/GS.cpp
+++ b/plugins/GSdx/GS.cpp
@@ -27,6 +27,7 @@
#include "GSRendererNull.h"
#include "GSSettingsDlg.h"
+
#define PS2E_LT_GS 0x01
#define PS2E_GS_VERSION 0x0006
#define PS2E_X86 0x01 // 32 bit
@@ -472,9 +473,22 @@ EXPORT_C GSgetLastTag(uint32* tag)
s_gs->GetLastTag(tag);
}
-EXPORT_C GSgetTitleInfo(char dest[128])
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+EXPORT_C GSgetTitleInfo2(char* dest, size_t length)
{
- //s_gs->GetWindowTitle
+ if (!s_gs->m_GStitleInfoBuffer[0])
+ strcpy(dest, "GSdx");
+ else
+ {
+ EnterCriticalSection(&s_gs->m_pGSsetTitle_Crit);
+ snprintf(dest, length-1, "GSdx | %s", s_gs->m_GStitleInfoBuffer);
+ dest[length-1] = 0; // just in case!
+ LeaveCriticalSection(&s_gs->m_pGSsetTitle_Crit);
+ }
}
EXPORT_C GSsetFrameSkip(int frameskip)
diff --git a/plugins/GSdx/GS.h b/plugins/GSdx/GS.h
index 59eab56486..f01cfc35dd 100644
--- a/plugins/GSdx/GS.h
+++ b/plugins/GSdx/GS.h
@@ -31,6 +31,10 @@
#define MAX_PAGES 512
#define MAX_BLOCKS 16384
+//if defined, will send much info in reply to the API title info queri from PCSX2
+//default should be undefined
+//#define GSTITLEINFO_API_FORCE_VERBOSE
+
#include "GSVector.h"
#pragma pack(push, 1)
diff --git a/plugins/GSdx/GSRenderer.cpp b/plugins/GSdx/GSRenderer.cpp
index e0df45d159..539a41ab05 100644
--- a/plugins/GSdx/GSRenderer.cpp
+++ b/plugins/GSdx/GSRenderer.cpp
@@ -29,6 +29,8 @@ GSRenderer::GSRenderer()
, m_dev(NULL)
, m_shader(0)
{
+ m_GStitleInfoBuffer[0] = 0;
+
m_interlace = theApp.GetConfig("interlace", 0);
m_aspectratio = theApp.GetConfig("aspectratio", 1);
m_filter = theApp.GetConfig("filter", 1);
@@ -48,6 +50,8 @@ GSRenderer::GSRenderer()
s_save = !!theApp.GetConfig("save", 0);
s_savez = !!theApp.GetConfig("savez", 0);
s_saven = theApp.GetConfig("saven", 0);
+
+ InitializeCriticalSection(&m_pGSsetTitle_Crit);
}
GSRenderer::~GSRenderer()
@@ -60,6 +64,7 @@ GSRenderer::~GSRenderer()
_aligned_free( m_tex_buff );
delete m_dev;
+ DeleteCriticalSection(&m_pGSsetTitle_Crit);
}
bool GSRenderer::CreateWnd(const string& title, int w, int h)
@@ -307,43 +312,81 @@ void GSRenderer::VSync(int field)
// osd
- if((m_perfmon.GetFrame() & 0x1f) == 0 && m_wnd.IsManaged())
+ if((m_perfmon.GetFrame() & 0x1f) == 0)
{
m_perfmon.Update();
double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
- string s2 = m_regs->SMODE2.INT ? (string("Interlaced ") + (m_regs->SMODE2.FFMD ? "(frame)" : "(field)")) : "Progressive";
-
GSVector4i r = GetDisplayRect();
- string s = format(
- "%I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f",
- m_perfmon.GetFrame(), r.width(), r.height(), fps, (int)(100.0 * fps / GetFPS()),
- s2.c_str(),
- GSSettingsDlg::g_interlace[m_interlace].name.c_str(),
- GSSettingsDlg::g_aspectratio[m_aspectratio].name.c_str(),
- (int)m_perfmon.Get(GSPerfMon::Quad),
- (int)m_perfmon.Get(GSPerfMon::Prim),
- (int)m_perfmon.Get(GSPerfMon::Draw),
- m_perfmon.CPU(),
- m_perfmon.Get(GSPerfMon::Swizzle) / 1024,
- m_perfmon.Get(GSPerfMon::Unswizzle) / 1024
- );
+ string s;
- double fillrate = m_perfmon.Get(GSPerfMon::Fillrate);
+#ifdef GSTITLEINFO_API_FORCE_VERBOSE
+ if (1)//force verbose reply
+#else
+ if (m_wnd.IsManaged())
+#endif
+ {//GSdx owns the window's title, be verbose.
+ string s2 = m_regs->SMODE2.INT ? (string("Interlaced ") + (m_regs->SMODE2.FFMD ? "(frame)" : "(field)")) : "Progressive";
+ s = format(
+ "%I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f",
+ m_perfmon.GetFrame(), r.width(), r.height(), fps, (int)(100.0 * fps / GetFPS()),
+ s2.c_str(),
+ GSSettingsDlg::g_interlace[m_interlace].name.c_str(),
+ GSSettingsDlg::g_aspectratio[m_aspectratio].name.c_str(),
+ (int)m_perfmon.Get(GSPerfMon::Quad),
+ (int)m_perfmon.Get(GSPerfMon::Prim),
+ (int)m_perfmon.Get(GSPerfMon::Draw),
+ m_perfmon.CPU(),
+ m_perfmon.Get(GSPerfMon::Swizzle) / 1024,
+ m_perfmon.Get(GSPerfMon::Unswizzle) / 1024
+ );
+
+ double fillrate = m_perfmon.Get(GSPerfMon::Fillrate);
+
+ if(fillrate > 0)
+ {
+ s += format(" | %.2f mpps", fps * fillrate / (1024 * 1024));
+ }
- if(fillrate > 0)
- {
- s += format(" | %.2f mpps", fps * fillrate / (1024 * 1024));
}
+ else
+ {
+ //Satisfy PCSX2's request for title info: minimal verbosity due to more external title text
+ s = format(
+ "%dx%d | %s",
+ r.width(), r.height(),
+ GSSettingsDlg::g_interlace[m_interlace].name.c_str()
+ );
+ }
+
if(m_capture.IsCapturing())
{
s += " | Recording...";
}
- m_wnd.SetWindowText(s.c_str());
+ if (m_wnd.IsManaged())
+ {
+ m_wnd.SetWindowText(s.c_str());
+ }
+ else
+ {
+ // note: do not use TryEnterCriticalSection. It is unnecessary code complication in
+ // an area that absolutely does not matter (even if it were 100 times slower, it wouldn't
+ // be noticeable). Besides, these locks are extremely short -- overhead of conditional
+ // is way more expensive than just waiting for the CriticalSection in 1 of 10,000,000 tries. --air
+
+ EnterCriticalSection(&m_pGSsetTitle_Crit);
+
+ strncpy(m_GStitleInfoBuffer, s.c_str(), ArraySize(m_GStitleInfoBuffer)-1);
+ m_GStitleInfoBuffer[sizeof(m_GStitleInfoBuffer)-1] = 0;// make sure null terminated even if text overflows
+
+ LeaveCriticalSection(&m_pGSsetTitle_Crit);
+ }
+
+
}
else
{
diff --git a/plugins/GSdx/GSRenderer.h b/plugins/GSdx/GSRenderer.h
index 5caf328024..5662d58d9c 100644
--- a/plugins/GSdx/GSRenderer.h
+++ b/plugins/GSdx/GSRenderer.h
@@ -107,6 +107,10 @@ public:
// TODO : Implement proper locking here *if needed* (not sure yet if it is) --air
uint8* GetTextureBufferLock() { return m_tex_buff; }
void ReleaseTextureBufferLock() { }
+
+public:
+ CRITICAL_SECTION m_pGSsetTitle_Crit;
+ char m_GStitleInfoBuffer[128];
};
template class GSRendererT : public GSRenderer
diff --git a/plugins/GSdx/GSdx.def b/plugins/GSdx/GSdx.def
index 8dfa08f709..f9af4d285b 100644
--- a/plugins/GSdx/GSdx.def
+++ b/plugins/GSdx/GSdx.def
@@ -42,3 +42,4 @@ EXPORTS
GSgetLastTag
GSReplay
GSBenchmark
+ GSgetTitleInfo2
\ No newline at end of file
diff --git a/plugins/spu2-x/src/CMakeLists.txt b/plugins/spu2-x/src/CMakeLists.txt
index c32b032ff0..0416fe0860 100644
--- a/plugins/spu2-x/src/CMakeLists.txt
+++ b/plugins/spu2-x/src/CMakeLists.txt
@@ -57,8 +57,9 @@ set(spu2xSources
Spu2replay.cpp
spu2sys.cpp
Timestretcher.cpp
- #utf8.cpp
- Wavedump_wav.cpp)
+ Wavedump_wav.cpp
+ WavFile.cpp
+ )
# spu2x headers
set(spu2xHeaders
@@ -75,7 +76,7 @@ set(spu2xHeaders
SndOut.h
spdif.h
Spu2replay.h
- #utf8.h
+ WavFile.h
)
diff --git a/plugins/spu2-x/src/Mixer.cpp b/plugins/spu2-x/src/Mixer.cpp
index d34ac662aa..a39b1d70d1 100644
--- a/plugins/spu2-x/src/Mixer.cpp
+++ b/plugins/spu2-x/src/Mixer.cpp
@@ -732,7 +732,10 @@ __forceinline void Mix()
StereoOut32 InputData[2] =
{
// SPDIF is on Core 0:
- (PlayMode&4) ? StereoOut32::Empty : ApplyVolume( Cores[0].ReadInput(), Cores[0].InpVol ),
+ // Fixme:
+ // 1. We do not have an AC3 decoder for the bitstream.
+ // 2. Games usually provide a normal ADMA stream as well and want to see it getting read!
+ /*(PlayMode&4) ? StereoOut32::Empty : */ApplyVolume( Cores[0].ReadInput(), Cores[0].InpVol ),
// CDDA is on Core 1:
(PlayMode&8) ? StereoOut32::Empty : ApplyVolume( Cores[1].ReadInput(), Cores[1].InpVol )
diff --git a/plugins/spu2-x/src/WavFile.cpp b/plugins/spu2-x/src/WavFile.cpp
new file mode 100644
index 0000000000..30c0988e8a
--- /dev/null
+++ b/plugins/spu2-x/src/WavFile.cpp
@@ -0,0 +1,149 @@
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+ * Developed and maintained by the Pcsx2 Development Team.
+ *
+ * The file is based on WavFile.h from SoundTouch library.
+ * Original portions are (c) 2009 by Olli Parviainen (oparviai 'at' iki.fi)
+ *
+ * SPU2-X 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.
+ *
+ * SPU2-X 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with SPU2-X. If not, see .
+ */
+
+// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
+// shrunken to support only output 16 bits wav files
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "WavFile.h"
+
+using namespace std;
+
+static const char riffStr[] = "RIFF";
+static const char waveStr[] = "WAVE";
+static const char fmtStr[] = "fmt ";
+static const char dataStr[] = "data";
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Class WavOutFile
+//
+
+WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels)
+{
+ bytesWritten = 0;
+ fptr = fopen(fileName, "wb");
+ if (fptr == NULL)
+ {
+ string msg = "Error : Unable to open file \"";
+ msg += fileName;
+ msg += "\" for writing.";
+ //pmsg = msg.c_str;
+ throw runtime_error(msg);
+ }
+
+ fillInHeader(sampleRate, bits, channels);
+ writeHeader();
+}
+
+
+WavOutFile::~WavOutFile()
+{
+ finishHeader();
+ if (fptr) fclose(fptr);
+ fptr = NULL;
+}
+
+
+
+void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
+{
+ // fill in the 'riff' part..
+
+ // copy string 'RIFF' to riff_char
+ memcpy(&(header.riff.riff_char), riffStr, 4);
+ // package_len unknown so far
+ header.riff.package_len = 0;
+ // copy string 'WAVE' to wave
+ memcpy(&(header.riff.wave), waveStr, 4);
+
+
+ // fill in the 'format' part..
+
+ // copy string 'fmt ' to fmt
+ memcpy(&(header.format.fmt), fmtStr, 4);
+
+ header.format.format_len = 0x10;
+ header.format.fixed = 1;
+ header.format.channel_number = (short)channels;
+ header.format.sample_rate = (int)sampleRate;
+ header.format.bits_per_sample = (short)bits;
+ header.format.byte_per_sample = (short)(bits * channels / 8);
+ header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate;
+ header.format.sample_rate = (int)sampleRate;
+
+ // fill in the 'data' part..
+
+ // copy string 'data' to data_field
+ memcpy(&(header.data.data_field), dataStr, 4);
+ // data_len unknown so far
+ header.data.data_len = 0;
+}
+
+
+void WavOutFile::finishHeader()
+{
+ // supplement the file length into the header structure
+ header.riff.package_len = bytesWritten + 36;
+ header.data.data_len = bytesWritten;
+
+ writeHeader();
+}
+
+
+
+void WavOutFile::writeHeader()
+{
+ int res;
+
+ // write the supplemented header in the beginning of the file
+ fseek(fptr, 0, SEEK_SET);
+ res = fwrite(&header, sizeof(header), 1, fptr);
+ if (res != 1)
+ {
+ throw runtime_error("Error while writing to a wav file.");
+ }
+
+ // jump back to the end of the file
+ fseek(fptr, 0, SEEK_END);
+}
+
+
+void WavOutFile::write(const short *buffer, int numElems)
+{
+ int res;
+
+ // 16bit format & 16 bit samples
+
+ assert(header.format.bits_per_sample == 16);
+ if (numElems < 1) return; // nothing to do
+
+ res = fwrite(buffer, 2, numElems, fptr);
+
+ if (res != numElems)
+ {
+ throw runtime_error("Error while writing to a wav file.");
+ }
+ bytesWritten += 2 * numElems;
+}
diff --git a/plugins/spu2-x/src/WavFile.h b/plugins/spu2-x/src/WavFile.h
new file mode 100644
index 0000000000..7d75c4bac4
--- /dev/null
+++ b/plugins/spu2-x/src/WavFile.h
@@ -0,0 +1,113 @@
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+ * Developed and maintained by the Pcsx2 Development Team.
+ *
+ * The file is based on WavFile.h from SoundTouch library.
+ * Original portions are (c) 2009 by Olli Parviainen (oparviai 'at' iki.fi)
+ *
+ * SPU2-X 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.
+ *
+ * SPU2-X 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with SPU2-X. If not, see .
+ */
+
+// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
+// shrunken to support only output 16 bits wav files
+
+#ifndef WAVFILE_H
+#define WAVFILE_H
+
+#include
+
+#ifndef uint
+typedef unsigned int uint;
+#endif
+
+
+/// WAV audio file 'riff' section header
+typedef struct
+{
+ char riff_char[4];
+ int package_len;
+ char wave[4];
+} WavRiff;
+
+/// WAV audio file 'format' section header
+typedef struct
+{
+ char fmt[4];
+ int format_len;
+ short fixed;
+ short channel_number;
+ int sample_rate;
+ int byte_rate;
+ short byte_per_sample;
+ short bits_per_sample;
+} WavFormat;
+
+/// WAV audio file 'data' section header
+typedef struct
+{
+ char data_field[4];
+ uint data_len;
+} WavData;
+
+
+/// WAV audio file header
+typedef struct
+{
+ WavRiff riff;
+ WavFormat format;
+ WavData data;
+} WavHeader;
+
+
+/// Class for writing WAV audio files.
+class WavOutFile
+{
+private:
+ /// Pointer to the WAV file
+ FILE *fptr;
+
+ /// WAV file header data.
+ WavHeader header;
+
+ /// Counter of how many bytes have been written to the file so far.
+ int bytesWritten;
+
+ /// Fills in WAV file header information.
+ void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
+
+ /// Finishes the WAV file header by supplementing information of amount of
+ /// data written to file etc
+ void finishHeader();
+
+ /// Writes the WAV file header.
+ void writeHeader();
+
+public:
+ /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
+ /// if file creation fails.
+ WavOutFile(const char *fileName, ///< Filename
+ int sampleRate, ///< Sample rate (e.g. 44100 etc)
+ int bits, ///< Bits per sample (8 or 16 bits)
+ int channels ///< Number of channels (1=mono, 2=stereo)
+ );
+
+ /// Destructor: Finalizes & closes the WAV file.
+ ~WavOutFile();
+
+ /// Write data to WAV file. Throws a 'runtime_error' exception if writing to
+ /// file fails.
+ void write(const short *buffer, ///< Pointer to sample data buffer.
+ int numElems ///< How many array items are to be written to file.
+ );
+
+};
+
+#endif
diff --git a/plugins/spu2-x/src/Wavedump_wav.cpp b/plugins/spu2-x/src/Wavedump_wav.cpp
index e163ecea86..62dbaebecc 100644
--- a/plugins/spu2-x/src/Wavedump_wav.cpp
+++ b/plugins/spu2-x/src/Wavedump_wav.cpp
@@ -16,7 +16,11 @@
*/
#include "Global.h"
+#ifdef __LINUX__
+#include "WavFile.h"
+#else
#include "soundtouch/WavFile.h"
+#endif
static WavOutFile* _new_WavOutFile( const char* destfile )
{
diff --git a/plugins/zerogs/opengl/GS.h b/plugins/zerogs/opengl/GS.h
index 5e643ca651..86b350619b 100644
--- a/plugins/zerogs/opengl/GS.h
+++ b/plugins/zerogs/opengl/GS.h
@@ -855,4 +855,5 @@ public:
#endif
+
#endif
diff --git a/plugins/zerospu2/CMakeLists.txt b/plugins/zerospu2/CMakeLists.txt
index 02c439eecd..c72f4db79a 100644
--- a/plugins/zerospu2/CMakeLists.txt
+++ b/plugins/zerospu2/CMakeLists.txt
@@ -40,6 +40,7 @@ endif(CMAKE_BUILD_TYPE STREQUAL Release)
# zerospu2 sources
set(zerospu2Sources
voices.cpp
+ WavFile.cpp
zerodma.cpp
zerospu2.cpp
zeroworker.cpp)
@@ -48,6 +49,7 @@ set(zerospu2Sources
set(zerospu2Headers
misc.h
reg.h
+ WavFile.h
zerodma.h
zerospu2.h
zeroworker.h)
diff --git a/plugins/zerospu2/WavFile.cpp b/plugins/zerospu2/WavFile.cpp
new file mode 100644
index 0000000000..30c0988e8a
--- /dev/null
+++ b/plugins/zerospu2/WavFile.cpp
@@ -0,0 +1,149 @@
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+ * Developed and maintained by the Pcsx2 Development Team.
+ *
+ * The file is based on WavFile.h from SoundTouch library.
+ * Original portions are (c) 2009 by Olli Parviainen (oparviai 'at' iki.fi)
+ *
+ * SPU2-X 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.
+ *
+ * SPU2-X 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with SPU2-X. If not, see .
+ */
+
+// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
+// shrunken to support only output 16 bits wav files
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "WavFile.h"
+
+using namespace std;
+
+static const char riffStr[] = "RIFF";
+static const char waveStr[] = "WAVE";
+static const char fmtStr[] = "fmt ";
+static const char dataStr[] = "data";
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Class WavOutFile
+//
+
+WavOutFile::WavOutFile(const char *fileName, int sampleRate, int bits, int channels)
+{
+ bytesWritten = 0;
+ fptr = fopen(fileName, "wb");
+ if (fptr == NULL)
+ {
+ string msg = "Error : Unable to open file \"";
+ msg += fileName;
+ msg += "\" for writing.";
+ //pmsg = msg.c_str;
+ throw runtime_error(msg);
+ }
+
+ fillInHeader(sampleRate, bits, channels);
+ writeHeader();
+}
+
+
+WavOutFile::~WavOutFile()
+{
+ finishHeader();
+ if (fptr) fclose(fptr);
+ fptr = NULL;
+}
+
+
+
+void WavOutFile::fillInHeader(uint sampleRate, uint bits, uint channels)
+{
+ // fill in the 'riff' part..
+
+ // copy string 'RIFF' to riff_char
+ memcpy(&(header.riff.riff_char), riffStr, 4);
+ // package_len unknown so far
+ header.riff.package_len = 0;
+ // copy string 'WAVE' to wave
+ memcpy(&(header.riff.wave), waveStr, 4);
+
+
+ // fill in the 'format' part..
+
+ // copy string 'fmt ' to fmt
+ memcpy(&(header.format.fmt), fmtStr, 4);
+
+ header.format.format_len = 0x10;
+ header.format.fixed = 1;
+ header.format.channel_number = (short)channels;
+ header.format.sample_rate = (int)sampleRate;
+ header.format.bits_per_sample = (short)bits;
+ header.format.byte_per_sample = (short)(bits * channels / 8);
+ header.format.byte_rate = header.format.byte_per_sample * (int)sampleRate;
+ header.format.sample_rate = (int)sampleRate;
+
+ // fill in the 'data' part..
+
+ // copy string 'data' to data_field
+ memcpy(&(header.data.data_field), dataStr, 4);
+ // data_len unknown so far
+ header.data.data_len = 0;
+}
+
+
+void WavOutFile::finishHeader()
+{
+ // supplement the file length into the header structure
+ header.riff.package_len = bytesWritten + 36;
+ header.data.data_len = bytesWritten;
+
+ writeHeader();
+}
+
+
+
+void WavOutFile::writeHeader()
+{
+ int res;
+
+ // write the supplemented header in the beginning of the file
+ fseek(fptr, 0, SEEK_SET);
+ res = fwrite(&header, sizeof(header), 1, fptr);
+ if (res != 1)
+ {
+ throw runtime_error("Error while writing to a wav file.");
+ }
+
+ // jump back to the end of the file
+ fseek(fptr, 0, SEEK_END);
+}
+
+
+void WavOutFile::write(const short *buffer, int numElems)
+{
+ int res;
+
+ // 16bit format & 16 bit samples
+
+ assert(header.format.bits_per_sample == 16);
+ if (numElems < 1) return; // nothing to do
+
+ res = fwrite(buffer, 2, numElems, fptr);
+
+ if (res != numElems)
+ {
+ throw runtime_error("Error while writing to a wav file.");
+ }
+ bytesWritten += 2 * numElems;
+}
diff --git a/plugins/zerospu2/WavFile.h b/plugins/zerospu2/WavFile.h
new file mode 100644
index 0000000000..7d75c4bac4
--- /dev/null
+++ b/plugins/zerospu2/WavFile.h
@@ -0,0 +1,113 @@
+/* SPU2-X, A plugin for Emulating the Sound Processing Unit of the Playstation 2
+ * Developed and maintained by the Pcsx2 Development Team.
+ *
+ * The file is based on WavFile.h from SoundTouch library.
+ * Original portions are (c) 2009 by Olli Parviainen (oparviai 'at' iki.fi)
+ *
+ * SPU2-X 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.
+ *
+ * SPU2-X 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with SPU2-X. If not, see .
+ */
+
+// Note the file is mostly a copy paste of the WavFile.h from SoundTouch library. It was
+// shrunken to support only output 16 bits wav files
+
+#ifndef WAVFILE_H
+#define WAVFILE_H
+
+#include
+
+#ifndef uint
+typedef unsigned int uint;
+#endif
+
+
+/// WAV audio file 'riff' section header
+typedef struct
+{
+ char riff_char[4];
+ int package_len;
+ char wave[4];
+} WavRiff;
+
+/// WAV audio file 'format' section header
+typedef struct
+{
+ char fmt[4];
+ int format_len;
+ short fixed;
+ short channel_number;
+ int sample_rate;
+ int byte_rate;
+ short byte_per_sample;
+ short bits_per_sample;
+} WavFormat;
+
+/// WAV audio file 'data' section header
+typedef struct
+{
+ char data_field[4];
+ uint data_len;
+} WavData;
+
+
+/// WAV audio file header
+typedef struct
+{
+ WavRiff riff;
+ WavFormat format;
+ WavData data;
+} WavHeader;
+
+
+/// Class for writing WAV audio files.
+class WavOutFile
+{
+private:
+ /// Pointer to the WAV file
+ FILE *fptr;
+
+ /// WAV file header data.
+ WavHeader header;
+
+ /// Counter of how many bytes have been written to the file so far.
+ int bytesWritten;
+
+ /// Fills in WAV file header information.
+ void fillInHeader(const uint sampleRate, const uint bits, const uint channels);
+
+ /// Finishes the WAV file header by supplementing information of amount of
+ /// data written to file etc
+ void finishHeader();
+
+ /// Writes the WAV file header.
+ void writeHeader();
+
+public:
+ /// Constructor: Creates a new WAV file. Throws a 'runtime_error' exception
+ /// if file creation fails.
+ WavOutFile(const char *fileName, ///< Filename
+ int sampleRate, ///< Sample rate (e.g. 44100 etc)
+ int bits, ///< Bits per sample (8 or 16 bits)
+ int channels ///< Number of channels (1=mono, 2=stereo)
+ );
+
+ /// Destructor: Finalizes & closes the WAV file.
+ ~WavOutFile();
+
+ /// Write data to WAV file. Throws a 'runtime_error' exception if writing to
+ /// file fails.
+ void write(const short *buffer, ///< Pointer to sample data buffer.
+ int numElems ///< How many array items are to be written to file.
+ );
+
+};
+
+#endif
diff --git a/plugins/zerospu2/zerospu2.cpp b/plugins/zerospu2/zerospu2.cpp
index 363ba8e8f7..3e8c4d6e8f 100644
--- a/plugins/zerospu2/zerospu2.cpp
+++ b/plugins/zerospu2/zerospu2.cpp
@@ -28,7 +28,11 @@
#include
#include "soundtouch/SoundTouch.h"
+#ifdef __LINUX__
+#include "WavFile.h"
+#else
#include "soundtouch/WavFile.h"
+#endif
char libraryName[256];
diff --git a/plugins/zerospu2/zeroworker.cpp b/plugins/zerospu2/zeroworker.cpp
index 01b3ffaf8e..41a2dfeeb7 100644
--- a/plugins/zerospu2/zeroworker.cpp
+++ b/plugins/zerospu2/zeroworker.cpp
@@ -19,7 +19,11 @@
#include "zerospu2.h"
#include "zeroworker.h"
#include "soundtouch/SoundTouch.h"
+#ifdef __LINUX__
+#include "WavFile.h"
+#else
#include "soundtouch/WavFile.h"
+#endif
s32 g_logsound = 0;
WavOutFile* g_pWavRecord=NULL; // used for recording
diff --git a/plugins/zzogl-pg/opengl/CMakeLists.txt b/plugins/zzogl-pg/opengl/CMakeLists.txt
index 701371c634..289f55a82b 100644
--- a/plugins/zzogl-pg/opengl/CMakeLists.txt
+++ b/plugins/zzogl-pg/opengl/CMakeLists.txt
@@ -63,6 +63,11 @@ set(zzoglSources
x86.cpp
zerogs.cpp
zpipe.cpp
+ ZZClut.cpp
+ ZZHacks.cpp
+ ZZKeyboard.cpp
+ ZZoglDrawing.cpp
+ ZZLog.cpp
ZZoglCreate.cpp
ZZoglCRTC.cpp
ZZoglFlush.cpp
@@ -71,8 +76,7 @@ set(zzoglSources
ZZoglShaders.cpp
ZZoglShoots.cpp
ZZoglVB.cpp
- ZZKeyboard.cpp
- ZZLog.cpp)
+ )
# zzogl headers
set(zzoglHeaders
@@ -81,6 +85,7 @@ set(zzoglHeaders
GifTransfer.h
# glprocs.h
GS.h
+ HostMemory.h
Mem.h
Mem_Swizzle.h
Mem_Transmit.h
@@ -93,11 +98,17 @@ set(zzoglHeaders
x86.h
zerogs.h
zpipe.h
+ ZZClut.h
+ ZZGl.h
+ ZZHacks.h
+ ZZoglDrawing.h
+ ZZLog.h
ZZoglCRTC.h
ZZoglMath.h
ZZoglShaders.h
- ZZGl.h
- ZZLog.h)
+ ZZoglShoots.h
+ ZZoglVB.h
+ )
# zzogl S sources
set(zzoglSSources
diff --git a/plugins/zzogl-pg/opengl/CRC.h b/plugins/zzogl-pg/opengl/CRC.h
index d778602148..207e2faa33 100644
--- a/plugins/zzogl-pg/opengl/CRC.h
+++ b/plugins/zzogl-pg/opengl/CRC.h
@@ -20,44 +20,7 @@
#ifndef CRC_H_INCLUDED
#define CRC_H_INCLUDED
-// don't change these values!
-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
-};
-
-#define USEALPHATESTING (!(conf.settings().no_alpha_test))
+#include "ZZHacks.h"
// CRC Information
enum Title_Info
@@ -374,8 +337,10 @@ static const Game_Info crc_game_list[] =
//{0x4437F4B1, ArTonelico1, US, GAME_GUSTHACK, -1, -1},
{0xF95F37EE, ArTonelico2, US, GAME_GUSTHACK, -1, -1},
{0xF46142D3, ArTonelico2, JPUNDUB, GAME_GUSTHACK, -1, -1},
- {0x77b0236f, ManaKhemia1, US, GAME_GUSTHACK , -1, -1},
- {0x433951e7, ManaKhemia2, US, GAME_GUSTHACK, -1, -1},
+
+ // According to Zeydlitz, Mana Khemia no longer needs the Gust Hack.
+ //{0x77b0236f, ManaKhemia1, US, GAME_GUSTHACK, -1, -1},
+ //{0x433951e7, ManaKhemia2, US, GAME_GUSTHACK, -1, -1},
//{0xda11c6d4, AtelierJudie, JP, GAME_GUSTHACK, -1, -1},
//{0x3e72c085, AtelierLilie, JP, GAME_GUSTHACK, -1, -1},
//{0x6eac076b, AtelierViorate, JP, GAME_GUSTHACK, -1, -1},
diff --git a/plugins/zzogl-pg/opengl/GLWin.h b/plugins/zzogl-pg/opengl/GLWin.h
index ff3cdfa598..bab0833ba4 100644
--- a/plugins/zzogl-pg/opengl/GLWin.h
+++ b/plugins/zzogl-pg/opengl/GLWin.h
@@ -29,6 +29,9 @@
#undef CreateWindow // Undo Windows.h global namespace pollution
+extern void SetDeviceSize(int nNewWidth, int nNewHeight);
+extern void OnFKey(int key, int shift);
+
class GLWindow
{
private:
@@ -51,6 +54,9 @@ class GLWindow
u32 width, height, depth;
public:
+ char title[256];
+ Size backbuffer;
+
void SwapGLBuffers();
bool ReleaseContext();
@@ -63,8 +69,21 @@ class GLWindow
bool DisplayWindow(int _width, int _height);
void SetTitle(char *strtitle);
void ResizeCheck();
-};
+ void ProcessEvents();
+
+ void UpdateWindowSize(int nNewWidth, int nNewHeight)
+ {
+ FUNCLOG
+ backbuffer.w = std::max(nNewWidth, 16);
+ backbuffer.h = std::max(nNewHeight, 16);
+ if (!(conf.fullscreen()))
+ {
+ conf.width = nNewWidth;
+ conf.height = nNewHeight;
+ }
+ }
+};
extern GLWindow GLWin;
diff --git a/plugins/zzogl-pg/opengl/GLWin32.cpp b/plugins/zzogl-pg/opengl/GLWin32.cpp
index 0c66206fda..3c959019cb 100644
--- a/plugins/zzogl-pg/opengl/GLWin32.cpp
+++ b/plugins/zzogl-pg/opengl/GLWin32.cpp
@@ -18,11 +18,11 @@
*/
#include "GS.h"
-#include "zerogs.h"
#include "GLWin.h"
#ifdef GL_WIN32_WINDOW
+HWND GShwnd = NULL;
HDC hDC = NULL; // Private GDI Device Context
HGLRC hRC = NULL; // Permanent Rendering Context
@@ -47,14 +47,14 @@ LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
case WM_SIZE:
nWindowWidth = lParam & 0xffff;
nWindowHeight = lParam >> 16;
- ZeroGS::ChangeWindowSize(nWindowWidth, nWindowHeight);
+ GLWin.UpdateWindowSize(nWindowWidth, nWindowHeight);
break;
case WM_SIZING:
// if button is 0, then just released so can resize
if (GetSystemMetrics(SM_SWAPBUTTON) ? !GetAsyncKeyState(VK_RBUTTON) : !GetAsyncKeyState(VK_LBUTTON))
{
- ZeroGS::SetChangeDeviceSize(nWindowWidth, nWindowHeight);
+ SetDeviceSize(nWindowWidth, nWindowHeight);
}
break;
@@ -122,7 +122,11 @@ bool GLWindow::CreateWindow(void *pDisplay)
hInstance, // Instance
NULL); // Don't Pass Anything To WM_CREATE
- if (GShwnd == NULL) return false;
+ if (GShwnd == NULL)
+ {
+ ZZLog::Error_Log("Failed to create window. Exiting...");
+ return false;
+ }
if (pDisplay != NULL) *(HWND*)pDisplay = GShwnd;
@@ -135,6 +139,7 @@ bool GLWindow::CreateWindow(void *pDisplay)
SetFocus(GShwnd);
+ if (pDisplay == NULL) ZZLog::Error_Log("Failed to create window. Exiting...");
return (pDisplay != NULL);
}
@@ -184,8 +189,8 @@ bool GLWindow::DisplayWindow(int _width, int _height)
if (conf.fullscreen())
{
- nBackbufferWidth = rcdesktop.right - rcdesktop.left;
- nBackbufferHeight = rcdesktop.bottom - rcdesktop.top;
+ backbuffer.w = rcdesktop.right - rcdesktop.left;
+ backbuffer.h = rcdesktop.bottom - rcdesktop.top;
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP;
@@ -195,6 +200,8 @@ bool GLWindow::DisplayWindow(int _width, int _height)
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
+ backbuffer.w = _width;
+ backbuffer.h = _height;
}
dwStyle |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
@@ -202,8 +209,8 @@ bool GLWindow::DisplayWindow(int _width, int _height)
rc.left = 0;
rc.top = 0;
- rc.right = nBackbufferWidth;
- rc.bottom = nBackbufferHeight;
+ rc.right = backbuffer.h;
+ rc.bottom = backbuffer.h;
AdjustWindowRectEx(&rc, dwStyle, false, dwExStyle);
int X = (rcdesktop.right - rcdesktop.left) / 2 - (rc.right - rc.left) / 2;
int Y = (rcdesktop.bottom - rcdesktop.top) / 2 - (rc.bottom - rc.top) / 2;
@@ -218,8 +225,8 @@ bool GLWindow::DisplayWindow(int _width, int _height)
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
- dmScreenSettings.dmPelsWidth = nBackbufferWidth;
- dmScreenSettings.dmPelsHeight = nBackbufferHeight;
+ dmScreenSettings.dmPelsWidth = backbuffer.w;
+ dmScreenSettings.dmPelsHeight = backbuffer.h;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
@@ -300,8 +307,10 @@ bool GLWindow::DisplayWindow(int _width, int _height)
void GLWindow::SwapGLBuffers()
{
static u32 lastswaptime = 0;
+
+ if (glGetError() != GL_NO_ERROR) ZZLog::Debug_Log("glError before swap!");
+
SwapBuffers(hDC);
- //glClear(GL_COLOR_BUFFER_BIT);
lastswaptime = timeGetTime();
}
@@ -315,4 +324,74 @@ void GLWindow::ResizeCheck()
}
+
+extern void ChangeDeviceSize(int nNewWidth, int nNewHeight);
+
+void GLWindow::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);
+ 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;
+
+ SetDeviceSize(
+ (conf.fullscreen()) ? 1280 : conf.width,
+ (conf.fullscreen()) ? 960 : conf.height);
+ }
+}
+
+
#endif
diff --git a/plugins/zzogl-pg/opengl/GLWinX11.cpp b/plugins/zzogl-pg/opengl/GLWinX11.cpp
index 07ff6bc3ac..d71a41ab35 100644
--- a/plugins/zzogl-pg/opengl/GLWinX11.cpp
+++ b/plugins/zzogl-pg/opengl/GLWinX11.cpp
@@ -19,7 +19,6 @@
#include "Util.h"
#include "GLWin.h"
-#include "zerogs.h"
#ifdef GL_X11_WINDOW
@@ -35,7 +34,11 @@ bool GLWindow::CreateWindow(void *pDisplay)
glDisplay = XOpenDisplay(0);
glScreen = DefaultScreen(glDisplay);
- if (pDisplay == NULL) return false;
+ if (pDisplay == NULL)
+ {
+ ZZLog::Error_Log("Failed to create window. Exiting...");
+ return false;
+ }
*(Display**)pDisplay = glDisplay;
@@ -135,9 +138,9 @@ void GLWindow::GetWindowSize()
XUnlockDisplay(glDisplay);
// update the gl buffer size
- ZeroGS::ChangeWindowSize(width, height);
+ UpdateWindowSize(width, height);
- ZZLog::Error_Log("Resolution %dx%d. Depth %d bpp. Position (%d,%d)", width, height, depth, conf.x, conf.y);
+ ZZLog::Dev_Log("Resolution %dx%d. Depth %d bpp. Position (%d,%d)", width, height, depth, conf.x, conf.y);
}
void GLWindow::GetGLXVersion()
@@ -252,6 +255,9 @@ void GLWindow::ToggleFullscreen()
bool GLWindow::DisplayWindow(int _width, int _height)
{
+ backbuffer.w = _width;
+ backbuffer.h = _height;
+
if (!CreateVisual()) return false;
/* create a GLX context */
@@ -301,8 +307,8 @@ bool GLWindow::DisplayWindow(int _width, int _height)
void GLWindow::SwapGLBuffers()
{
+ if (glGetError() != GL_NO_ERROR) ZZLog::Debug_Log("glError before swap!");
glXSwapBuffers(glDisplay, glWindow);
- //glClear(GL_COLOR_BUFFER_BIT);
}
void GLWindow::SetTitle(char *strtitle)
@@ -336,7 +342,7 @@ void GLWindow::ResizeCheck()
width = event.xconfigure.width;
height = event.xconfigure.height;
Force43Ratio();
- ZeroGS::ChangeWindowSize(width, height);
+ UpdateWindowSize(width, height);
}
if (!fullScreen) {
@@ -352,4 +358,32 @@ void GLWindow::ResizeCheck()
XUnlockDisplay(glDisplay);
}
+u32 THR_KeyEvent = 0; // Value for key event processing between threads
+bool THR_bShift = false;
+
+void GLWindow::ProcessEvents()
+{
+ FUNCLOG
+
+ // check resizing
+ 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
diff --git a/plugins/zzogl-pg/opengl/GS.h b/plugins/zzogl-pg/opengl/GS.h
index 2602db26ed..4c932d7eb8 100644
--- a/plugins/zzogl-pg/opengl/GS.h
+++ b/plugins/zzogl-pg/opengl/GS.h
@@ -25,39 +25,13 @@
#include "Util.h"
#include "GifTransfer.h"
+#include "HostMemory.h"
using namespace std;
extern float fFPS;
-#define MEMORY_END 0x00400000
-
extern int g_LastCRC;
-extern u8* g_pBasePS2Mem;
-
-extern u8* g_pbyGSMemory;
-
-class GSMemory
-{
- public:
- void init();
- void destroy();
- u8* get();
- u8* get(u32 addr);
- u8* get_raw(u32 addr);
-};
-
-extern u8* g_pbyGSClut; // the temporary clut buffer
-
-class GSClut
-{
- public:
- void init();
- void destroy();
- u8* get();
- u8* get(u32 addr);
- u8* get_raw(u32 addr);
-};
struct Vector_16F
{
@@ -66,22 +40,7 @@ struct Vector_16F
// PS2 vertex
-struct VertexGPU
-{
- // gained from XYZ2, XYZ3, XYZF2, XYZF3,
- // X -- bits 0-15, Y-16-31. Z - 32-63 if no F used, 32-55 otherwise, F (fog) - 56-63
- // X, Y stored in 12d3 format,
- s16 x, y, f, resv0; // note: xy is 12d3
- // Vertex color settings. RGB -- luminance of red/green/blue, A -- alpha. 1.0 == 0x80.
- // Goes grom RGBAQ register, bits 0-7, 8-15, 16-23 and 24-31 accordingly
- u32 rgba;
- u32 z;
- // Texture coordinates. S & T going from ST register (bits 0-31, and 32-63).
- // Q goes from RGBAQ register, bits 32-63
- float s, t, q;
-};
-
-// Almost same as previous, controlled by prim.fst flags
+// Almost same as VertexGPU, controlled by prim.fst flags
struct Vertex
{
@@ -94,6 +53,75 @@ struct Vertex
u16 u, v;
};
+struct VertexGPU
+{
+ // gained from XYZ2, XYZ3, XYZF2, XYZF3,
+ // X -- bits 0-15, Y-16-31. Z - 32-63 if no F used, 32-55 otherwise, F (fog) - 56-63
+ // X, Y stored in 12d3 format,
+ s16 x, y;
+ s16 f, resv0;
+
+ // Vertex color settings. RGB -- luminance of red/green/blue, A -- alpha. 1.0 == 0x80.
+ // Goes grom RGBAQ register, bits 0-7, 8-15, 16-23 and 24-31 accordingly
+ u32 rgba;
+ u32 z;
+ // Texture coordinates. S & T going from ST register (bits 0-31, and 32-63).
+ // Q goes from RGBAQ register, bits 32-63
+ float s, t, q;
+
+ void move_x(Vertex v, int offset)
+ {
+ x = ((((int)v.x - offset) >> 1) & 0xffff);
+ }
+
+ void move_y(Vertex v, int offset)
+ {
+ y = ((((int)v.y - offset) >> 1) & 0xffff);
+ }
+
+ void move_z(Vertex v, int mask)
+ {
+ z = (mask == 0xffff) ? min((u32)0xffff, v.z) : v.z;
+ }
+
+ void move_fog(Vertex v)
+ {
+ f = ((s16)(v).f << 7) | 0x7f;
+ }
+
+ void set_xy(s16 x1, s16 y1)
+ {
+ x = x1;
+ y = y1;
+ }
+ void set_xyz(s16 x1, s16 y1, u32 z1)
+ {
+ x = x1;
+ y = y1;
+ z = z1;
+ }
+
+ void set_st(float s1, float t1)
+ {
+ s = s1;
+ t = t1;
+ }
+
+ void set_stq(float s1, float t1, float q1)
+ {
+ s = s1;
+ t = t1;
+ q = q1;
+ }
+
+ void set_xyzst(s16 x1, s16 y1, u32 z1, float s1, float t1)
+ {
+ set_xyz(x1, y1, z1);
+ set_st(s1, t1);
+ }
+
+};
+
extern GSconf conf;
// PSM values
@@ -346,7 +374,7 @@ union tex_0_info
u32 psm_fix()
{
- // printf ("psm %d\n", psm);
+ // ZZLog::Debug_Log("psm %d\n", psm);
if (psm == 9) return 1;
return psm;
@@ -385,6 +413,10 @@ union tex_0_info
#define TEX_HIGHLIGHT 2
#define TEX_HIGHLIGHT2 3
+bool SaveTexture(const char* filename, u32 textarget, u32 tex, int width, int height);
+extern void SaveTex(tex0Info* ptex, int usevid);
+extern char* NamedSaveTex(tex0Info* ptex, int usevid);
+
typedef struct
{
int lcm;
@@ -471,14 +503,16 @@ typedef struct
typedef struct
{
- Vertex gsvertex[3];
- u32 rgba;
+ Vertex gsvertex[4]; // circular buffer that contains the vertex
+ Vertex gsTriFanVertex; // Base of triangle fan primitive vertex
+ u32 rgba; // global color for flat shading texture
float q;
- Vertex vertexregs;
+ Vertex vertexregs; // accumulation buffer that collect current vertex data
int primC; // number of verts current storing
int primIndex; // current prim index
- int nTriFanVert;
+ int nTriFanVert; // remember the index of the base of triangle fan
+ int new_tri_fan; // 1 if we process a new triangle fan primitive. 0 otherwise
int prac;
int dthe;
@@ -512,9 +546,17 @@ typedef struct
GSClut clut_buffer;
int primNext(int inc = 1)
{
- return ((primIndex + inc) % ARRAY_SIZE(gsvertex));
+ // Note: ArraySize(gsvertex) == 2^n => modulo is replaced by an and instruction
+ return ((primIndex + inc) % ArraySize(gsvertex));
}
+ int primPrev(int dec = 1)
+ {
+ // Note: assert( dec <= ArraySize(gsvertex) );
+ // Note: ArraySize(gsvertex) == 2^n => modulo is replaced by an and instruction
+ return ((primIndex + (ArraySize(gsvertex) - dec)) % ArraySize(gsvertex));
+ }
+
void setRGBA(u32 r, u32 g, u32 b, u32 a)
{
rgba = (r & 0xff) |
@@ -523,29 +565,39 @@ typedef struct
((a & 0xff) << 24);
}
- void add_vertex(u16 x, u16 y, u32 z, u16 f)
+ inline void add_vertex(u16 x, u16 y, u32 z, u16 f)
{
vertexregs.x = x;
vertexregs.y = y;
vertexregs.z = z;
vertexregs.f = f;
- gsvertex[primIndex] = vertexregs;
- primIndex = primNext();
+ if (likely(!new_tri_fan)) {
+ gsvertex[primIndex] = vertexregs;
+ } else {
+ gsTriFanVertex = vertexregs;
+ new_tri_fan = false;
+ }
}
- void add_vertex(u16 x, u16 y, u32 z)
+ inline void add_vertex(u16 x, u16 y, u32 z)
{
vertexregs.x = x;
vertexregs.y = y;
vertexregs.z = z;
- gsvertex[primIndex] = vertexregs;
- primIndex = primNext();
+ if (likely(!new_tri_fan)) {
+ gsvertex[primIndex] = vertexregs;
+ } else {
+ gsTriFanVertex = vertexregs;
+ new_tri_fan = false;
+ }
}
} GSinternal;
extern GSinternal gs;
-static __forceinline u16 RGBA32to16(u32 c)
+// Note the function is used in a template parameter so it must be declared extern
+// Note2: In this case extern is not compatible with __forceinline so just inline it...
+extern inline u16 RGBA32to16(u32 c)
{
return (u16)((((c) & 0x000000f8) >> 3) |
(((c) & 0x0000f800) >> 6) |
@@ -673,7 +725,7 @@ static __forceinline int ZZOglGet_psm_TexBitsFix(u32 data)
{
//return tex_0_info(data).psm_fix();
int result = ZZOglGet_psm_TexBits(data) ;
-// printf ("result %d\n", result);
+// ZZLog::Debug_Log("result %d", result);
if (result == 9) result = 1;
@@ -910,6 +962,21 @@ inline bool ZZOglClutStorageUnchanged(const u32* oldtex, const u32* newtex)
return ((oldtex[1] & 0x1ff10000) == (newtex[1] & 0x1ff10000));
}
+// call to load CLUT data (depending on CLD)
+void texClutWrite(int ctx);
+
+// 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);
+
+ texClutWrite(ictx);
+ };
+
// CSA and CPSM bitmask 0001 1111 0111 1000 ...
// 60 56 52
#define CPSM_CSA_BITMASK 0x1f780000
diff --git a/plugins/zzogl-pg/opengl/GSmain.cpp b/plugins/zzogl-pg/opengl/GSmain.cpp
index 3c5fec8549..42e60ef785 100644
--- a/plugins/zzogl-pg/opengl/GSmain.cpp
+++ b/plugins/zzogl-pg/opengl/GSmain.cpp
@@ -16,29 +16,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
-#if defined(_WIN32)
-#include
-#include "Win32.h"
-#include
-#endif
-#include
-#include
+#include "Util.h"
+#include "GS.h"
+#include "Profile.h"
+#include "GLWin.h"
+#include "ZZoglFlushHack.h"
+
using namespace std;
-#include "GS.h"
-#include "Mem.h"
-#include "Regs.h"
-#include "Profile.h"
-#include "GLWin.h"
-
-#include "zerogs.h"
-#include "targets.h"
-#include "ZZoglShaders.h"
-#include "ZZoglFlushHack.h"
-#include "ZZoglFlushHack.h"
+extern void SaveSnapshot(const char* filename);
#ifdef _MSC_VER
#pragma warning(disable:4244)
@@ -46,7 +34,6 @@ using namespace std;
GLWindow GLWin;
GSinternal gs;
-char GStitle[256];
GSconf conf;
int ppf, g_GSMultiThreaded, CurrentSavestate = 0;
@@ -59,7 +46,7 @@ float fFPS = 0;
void (*GSirq)();
u8* g_pBasePS2Mem = NULL;
-std::string s_strIniPath("inis/"); // Air's new ini path (r2361)
+string s_strIniPath("inis/"); // Air's new ini path (r2361)
bool SaveStateExists = true; // We could not know save slot status before first change occured
const char* SaveStateFile = NULL; // Name of SaveFile for access check.
@@ -85,21 +72,24 @@ char *libraryName = "ZZ Ogl PG ";
extern int g_nPixelShaderVer, g_nFrameRender, g_nFramesSkipped;
-extern void ProcessEvents();
extern void WriteAA();
extern void WriteBilinear();
+extern void ZZDestroy();
+extern bool ZZCreate(int width, int height);
+extern void ZZGSStateReset();
+extern int ZZSave(s8* pbydata);
+extern bool ZZLoad(s8* pbydata);
+
+// switches the render target to the real target, flushes the current render targets and renders the real image
+extern void RenderCRTC(int interlace);
+
+#if defined(_WIN32) && defined(_DEBUG)
+HANDLE g_hCurrentThread = NULL;
+#endif
extern int VALIDATE_THRESH;
extern u32 TEXDESTROY_THRESH;
-#ifdef _WIN32
-HWND GShwnd = NULL;
-#endif
-
-u32 THR_KeyEvent = 0; // Value for key event processing between threads
-bool THR_bShift = false;
-
-
u32 CALLBACK PS2EgetLibType()
{
return PS2E_LT_GS;
@@ -130,55 +120,6 @@ void CALLBACK GSsetLogDir(const char* dir)
ZZLog::SetDir(dir);
}
-void ReportHacks(gameHacks hacks)
-{
- if (hacks.texture_targs) ZZLog::WriteLn("'Texture targs' hack enabled.");
- if (hacks.auto_reset) ZZLog::WriteLn("'Auto reset' hack enabled.");
- if (hacks.interlace_2x) ZZLog::WriteLn("'Interlace 2x' hack enabled.");
- if (hacks.texa) ZZLog::WriteLn("'Texa' hack enabled.");
- if (hacks.no_target_resolve) ZZLog::WriteLn("'No target resolve' hack enabled.");
- if (hacks.exact_color) ZZLog::WriteLn("Exact color hack enabled.");
- if (hacks.no_color_clamp) ZZLog::WriteLn("'No color clamp' hack enabled.");
- if (hacks.no_alpha_fail) ZZLog::WriteLn("'No alpha fail' hack enabled.");
- if (hacks.no_depth_update) ZZLog::WriteLn("'No depth update' hack enabled.");
- if (hacks.quick_resolve_1) ZZLog::WriteLn("'Quick resolve 1' enabled.");
- if (hacks.no_quick_resolve) ZZLog::WriteLn("'No Quick resolve' hack enabled.");
- if (hacks.no_target_clut) ZZLog::WriteLn("'No target clut' hack enabled.");
- if (hacks.no_stencil) ZZLog::WriteLn("'No stencil' hack enabled.");
- if (hacks.vss_hack_off) ZZLog::WriteLn("VSS hack enabled.");
- if (hacks.no_depth_resolve) ZZLog::WriteLn("'No depth resolve' hack enabled.");
- if (hacks.full_16_bit_res) ZZLog::WriteLn("'Full 16 bit resolution' hack enabled.");
- if (hacks.resolve_promoted) ZZLog::WriteLn("'Resolve promoted' hack enabled.");
- if (hacks.fast_update) ZZLog::WriteLn("'Fast update' hack enabled.");
- if (hacks.no_alpha_test) ZZLog::WriteLn("'No alpha test' hack enabled.");
- if (hacks.disable_mrt_depth) ZZLog::WriteLn("'Disable mrt depth' hack enabled.");
- if (hacks.args_32_bit) ZZLog::WriteLn("'Args 32 bit' hack enabled.");
- //if (hacks.path3) ZZLog::WriteLn("'Path3' hack enabled.");
- if (hacks.parallel_context) ZZLog::WriteLn("'Parallel context' hack enabled.");
- if (hacks.xenosaga_spec) ZZLog::WriteLn("'Xenosaga spec' hack enabled.");
- if (hacks.partial_pointers) ZZLog::WriteLn("'Partial pointers' hack enabled.");
- if (hacks.partial_depth) ZZLog::WriteLn("'Partial depth' hack enabled.");
- if (hacks.reget) ZZLog::WriteLn("Reget hack enabled.");
- if (hacks.gust) ZZLog::WriteLn("Gust hack enabled.");
- if (hacks.no_logz) ZZLog::WriteLn("'No logz' hack enabled.");
- if (hacks.automatic_skip_draw) ZZLog::WriteLn("'Automatic skip draw' hack enabled.");
-}
-
-void ListHacks()
-{
- if ((!conf.disableHacks) && (conf.def_hacks._u32 != 0))
- {
- ZZLog::WriteLn("AutoEnabling these hacks:");
- ReportHacks(conf.def_hacks);
- }
-
- if (conf.hacks._u32 != 0)
- {
- ZZLog::WriteLn("You've manually enabled these hacks:");
- ReportHacks(conf.hacks);
- }
-}
-
void CALLBACK GSsetGameCRC(int crc, int options)
{
// build a list of function pointer for GetSkipCount (SkipDraw)
@@ -190,10 +131,6 @@ void CALLBACK GSsetGameCRC(int crc, int options)
inited = true;
memset(GSC_list, 0, sizeof(GSC_list));
- // for(int i = 0; i < NUMBER_OF_TITLES; i++)
- // {
- // GSC_list[i] = GSC_Null;
- // }
GSC_list[Okami] = GSC_Okami;
GSC_list[MetalGearSolid3] = GSC_MetalGearSolid3;
@@ -207,7 +144,7 @@ void CALLBACK GSsetGameCRC(int crc, int options)
GSC_list[OnePieceGrandBattle] = GSC_OnePieceGrandBattle;
GSC_list[ICO] = GSC_ICO;
GSC_list[GT4] = GSC_GT4;
- //FIXME GSC_list[WildArms4] = GSC_WildArms4;
+ GSC_list[WildArms4] = GSC_WildArms4;
GSC_list[WildArms5] = GSC_WildArms5;
GSC_list[Manhunt2] = GSC_Manhunt2;
GSC_list[CrashBandicootWoC] = GSC_CrashBandicootWoC;
@@ -296,12 +233,28 @@ void CALLBACK GSsetFrameSkip(int frameskip)
void CALLBACK GSreset()
{
- ZeroGS::GSReset();
+ FUNCLOG
+
+ memset(&gs, 0, sizeof(gs));
+
+ ZZGSStateReset();
+
+ gs.prac = 1;
+ prim = &gs._prim[0];
+ gs.imageTransfer = -1;
+ gs.q = 1;
}
void CALLBACK GSgifSoftReset(u32 mask)
{
- ZeroGS::GSSoftReset(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;
}
s32 CALLBACK GSinit()
@@ -318,60 +271,73 @@ s32 CALLBACK GSinit()
return 0;
}
-#ifdef _WIN32
-
-#ifdef _DEBUG
-HANDLE g_hCurrentThread = NULL;
-#endif
-
-
-extern LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
-extern HINSTANCE hInst;
-#endif
-
-
-s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread)
+__forceinline void InitMisc()
{
- FUNCLOG
-
- bool err;
-
- g_GSMultiThreaded = multithread;
-
- ZZLog::WriteLn("Calling GSopen.");
-
-#ifdef _WIN32
-#ifdef _DEBUG
- g_hCurrentThread = GetCurrentThread();
-#endif
-#endif
-
- LoadConfig();
- strcpy(GStitle, Title);
-
- err = GLWin.CreateWindow(pDsp);
- if (!err)
- {
- ZZLog::Error_Log("Failed to create window. Exiting...");
- return -1;
- }
-
- ZZLog::GS_Log("Using %s:%d.%d.%d.", libraryName, zgsrevision, zgsbuild, zgsminor);
- ZZLog::WriteLn("Creating ZZOgl window.");
-
- if (!ZeroGS::Create(conf.width, conf.height)) return -1;
-
- ZZLog::WriteLn("Initialization successful.");
-
WriteBilinear();
WriteAA();
InitProfile();
InitPath();
ResetRegs();
+}
+
+s32 CALLBACK GSopen(void *pDsp, char *Title, int multithread)
+{
+ FUNCLOG
+
+ g_GSMultiThreaded = multithread;
+
+ ZZLog::WriteLn("Calling GSopen.");
+
+#if defined(_WIN32) && defined(_DEBUG)
+ g_hCurrentThread = GetCurrentThread();
+#endif
+
+ LoadConfig();
+ strcpy(GLWin.title, Title);
+
+ ZZLog::GS_Log("Using %s:%d.%d.%d.", libraryName, zgsrevision, zgsbuild, zgsminor);
+
+ ZZLog::WriteLn("Creating ZZOgl window.");
+ if ((!GLWin.CreateWindow(pDsp)) || (!ZZCreate(conf.width, conf.height))) return -1;
+
+ ZZLog::WriteLn("Initialization successful.");
+
+ InitMisc();
ZZLog::GS_Log("GSopen finished.");
return 0;
}
+#ifdef USE_GOPEN2
+s32 CALLBACK GSopen2( void* pDsp, INT32 flags )
+{
+ FUNCLOG
+
+ bool err;
+
+ g_GSMultiThreaded = true;
+
+ ZZLog::WriteLn("Calling GSopen2.");
+
+#if defined(_WIN32) && defined(_DEBUG)
+ g_hCurrentThread = GetCurrentThread();
+#endif
+
+ LoadConfig();
+
+ ZZLog::GS_Log("Using %s:%d.%d.%d.", libraryName, zgsrevision, zgsbuild, zgsminor);
+
+ ZZLog::WriteLn("Capturing ZZOgl window.");
+ if ((!GLWin.GetWindow(pDsp)) || (!ZZCreate2(conf.width, conf.height))) return -1;// Needs to be added.
+
+ ZZLog::WriteLn("Initialization successful.");
+
+ InitMisc();
+ ZZLog::GS_Log("GSopen2 finished.");
+ return 0;
+
+}
+#endif
+
void CALLBACK GSshutdown()
{
FUNCLOG
@@ -382,7 +348,7 @@ void CALLBACK GSclose()
{
FUNCLOG
- ZeroGS::Destroy(1);
+ ZZDestroy();
GLWin.CloseWindow();
SaveStateFile = NULL;
@@ -414,7 +380,7 @@ void CALLBACK GSchangeSaveState(int newstate, const char* filename)
char str[255];
sprintf(str, "save state %d", newstate);
- ZeroGS::AddMessage(str);
+ ZZAddMessage(str);
CurrentSavestate = newstate;
SaveStateFile = filename;
@@ -448,13 +414,12 @@ void CALLBACK GSmakeSnapshot(char *path)
if ((bmpfile = fopen(filename, "wb")) == NULL)
{
char strdir[255];
+ sprintf(strdir, "%s", path);
#ifdef _WIN32
- sprintf(strdir, "%s", path);
CreateDirectory(strdir, NULL);
#else
- sprintf(strdir, "mkdir %s", path);
- system(strdir);
+ mkdir(path, 0777);
#endif
if ((bmpfile = fopen(filename, "wb")) == NULL) return;
@@ -463,7 +428,7 @@ void CALLBACK GSmakeSnapshot(char *path)
fclose(bmpfile);
// get the bits
- ZeroGS::SaveSnapshot(filename);
+ SaveSnapshot(filename);
}
// I'll probably move this somewhere else later, but it's got a ton of dependencies.
@@ -491,7 +456,7 @@ static __forceinline void SetGSTitle()
100*g_nFramesSkipped / g_nFrame,
g_nGenVars / (float)UPDATE_FRAMES, g_nTexVars / (float)UPDATE_FRAMES, g_nAlphaVars / (float)UPDATE_FRAMES,
g_nResolve / (float)UPDATE_FRAMES, (ppf&0xfffff) / (float)UPDATE_FRAMES,
- ZeroGS::g_MemTargs.listTargets.size(), ZeroGS::g_MemTargs.listClearedTargets.size(), g_TransferredToGPU >> 10);
+ g_MemTargs.listTargets.size(), g_MemTargs.listClearedTargets.size(), g_TransferredToGPU >> 10);
//_snprintf(strtitle, 512, "%x %x", *(int*)(g_pbyGSMemory + 256 * 0x3e0c + 4), *(int*)(g_pbyGSMemory + 256 * 0x3e04 + 4));
#endif
@@ -517,14 +482,14 @@ void CALLBACK GSvsync(int interlace)
g_nRealFrame++;
// !interlace? Hmmm... Fixme.
- ZeroGS::RenderCRTC(!interlace);
+ RenderCRTC(!interlace);
- ProcessEvents();
+ GLWin.ProcessEvents();
if (--nToNextUpdate <= 0)
{
u32 d = timeGetTime();
- fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d - dwTime, 1);
+ fFPS = UPDATE_FRAMES * 1000.0f / (float)max(d - dwTime, (u32)1);
dwTime = d;
g_nFrame += UPDATE_FRAMES;
SetGSTitle();
@@ -571,7 +536,7 @@ void CALLBACK GSreadFIFO(u64 *pMem)
//ZZLog::GS_Log("Calling GSreadFIFO.");
- ZeroGS::TransferLocalHost((u32*)pMem, 1);
+ TransferLocalHost((u32*)pMem, 1);
}
void CALLBACK GSreadFIFO2(u64 *pMem, int qwc)
@@ -580,7 +545,7 @@ void CALLBACK GSreadFIFO2(u64 *pMem, int qwc)
//ZZLog::GS_Log("Calling GSreadFIFO2.");
- ZeroGS::TransferLocalHost((u32*)pMem, qwc);
+ TransferLocalHost((u32*)pMem, qwc);
}
int CALLBACK GSsetupRecording(int start, void* pData)
@@ -588,9 +553,9 @@ int CALLBACK GSsetupRecording(int start, void* pData)
FUNCLOG
if (start)
- ZeroGS::StartCapture();
+ StartCapture();
else
- ZeroGS::StopCapture();
+ StopCapture();
return 1;
}
@@ -602,16 +567,16 @@ s32 CALLBACK GSfreeze(int mode, freezeData *data)
switch (mode)
{
case FREEZE_LOAD:
- if (!ZeroGS::Load(data->data)) ZZLog::Error_Log("GS: Bad load format!");
+ if (!ZZLoad(data->data)) ZZLog::Error_Log("GS: Bad load format!");
g_nRealFrame += 100;
break;
case FREEZE_SAVE:
- ZeroGS::Save(data->data);
+ ZZSave(data->data);
break;
case FREEZE_SIZE:
- data->size = ZeroGS::Save(NULL);
+ data->size = ZZSave(NULL);
break;
default:
diff --git a/plugins/zzogl-pg/opengl/GifTransfer.cpp b/plugins/zzogl-pg/opengl/GifTransfer.cpp
index aa15fdd038..c5c6461a2b 100644
--- a/plugins/zzogl-pg/opengl/GifTransfer.cpp
+++ b/plugins/zzogl-pg/opengl/GifTransfer.cpp
@@ -19,7 +19,6 @@
#include "GS.h"
#include "Mem.h"
-#include "zerogs.h"
#include "GifTransfer.h"
#ifdef _DEBUG
@@ -168,7 +167,7 @@ template void _GSgifTransfer(const u32 *pMem, u32 size)
switch (gs.imageTransfer)
{
case 0:
- ZeroGS::TransferHostLocal(pMem, len * 4);
+ TransferHostLocal(pMem, len * 4);
break;
case 1:
@@ -176,11 +175,11 @@ template void _GSgifTransfer(const u32 *pMem, u32 size)
// a GIFtag operation. They're an entirely separate process that can only be
// done through the ReverseFIFO transfer (aka ReadFIFO). --air
assert(0);
- //ZeroGS::TransferLocalHost(pMem, len);
+ //TransferLocalHost(pMem, len);
break;
case 2:
- //ZeroGS::TransferLocalLocal();
+ //TransferLocalLocal();
break;
case 3:
diff --git a/plugins/zzogl-pg/opengl/GifTransfer.h b/plugins/zzogl-pg/opengl/GifTransfer.h
index 4326da4693..533733ed07 100644
--- a/plugins/zzogl-pg/opengl/GifTransfer.h
+++ b/plugins/zzogl-pg/opengl/GifTransfer.h
@@ -20,9 +20,9 @@
#ifndef GIFTRANSFER_H_INCLUDED
#define GIFTRANSFER_H_INCLUDED
+#include "Util.h"
#include "GS.h"
#include "Regs.h"
-#include "Util.h"
enum GIF_FLG
{
diff --git a/plugins/zzogl-pg/opengl/HostMemory.cpp b/plugins/zzogl-pg/opengl/HostMemory.cpp
index 918ce1ee04..a851612451 100644
--- a/plugins/zzogl-pg/opengl/HostMemory.cpp
+++ b/plugins/zzogl-pg/opengl/HostMemory.cpp
@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
-
+
#include "GS.h"
#include
#include
@@ -24,509 +24,555 @@
#include
#include "Mem.h"
#include "x86.h"
-#include "zerogs.h"
#include "targets.h"
+#include "ZZoglVB.h"
+// flush current vertices, call before setting new registers (the main render method)
+extern void Flush(int context);
- u8* g_pbyGSMemory = NULL; // 4Mb GS system mem
+u8* g_pbyGSMemory = NULL; // 4Mb GS system mem
- void GSMemory::init()
- {
- 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);
- }
+void GSMemory::init()
+{
+ const u32 mem_size = MEMORY_END + 0x10000; // leave some room for out of range accesses (saves on the checks)
- void GSMemory::destroy()
- {
- _aligned_free(g_pbyGSMemory);
- g_pbyGSMemory = NULL;
- }
-
- u8* GSMemory::get() { return g_pbyGSMemory; }
-
- u8* GSMemory::get(u32 addr) { return &g_pbyGSMemory[addr*8]; }
- u8* GSMemory::get_raw(u32 addr) { return &g_pbyGSMemory[addr]; }
+ // clear
+ g_pbyGSMemory = (u8*)_aligned_malloc(mem_size, 1024);
+ memset(g_pbyGSMemory, 0, mem_size);
+}
- u8* g_pbyGSClut = NULL; // ZZ
+void GSMemory::destroy()
+{
+ _aligned_free(g_pbyGSMemory);
+ g_pbyGSMemory = NULL;
+}
- void GSClut::init()
- {
- g_pbyGSClut = (u8*)_aligned_malloc(256 * 8, 1024); // need 512 alignment!
- memset(g_pbyGSClut, 0, 256*8);
- }
+u8* GSMemory::get()
+{
+ return g_pbyGSMemory;
+}
- void GSClut::destroy()
- {
- _aligned_free(g_pbyGSClut);
- g_pbyGSClut = NULL;
- }
+u8* GSMemory::get(u32 addr)
+{
+ return &g_pbyGSMemory[addr*8];
+}
+u8* GSMemory::get_raw(u32 addr)
+{
+ return &g_pbyGSMemory[addr];
+}
- u8* GSClut::get() { return g_pbyGSClut; }
-
- u8* GSClut::get(u32 addr) { return &g_pbyGSClut[addr*8]; }
- u8* GSClut::get_raw(u32 addr) { return &g_pbyGSClut[addr]; }
-
- extern _getPixelAddress getPixelFun[64];
+u8* g_pbyGSClut = NULL; // ZZ
- namespace ZeroGS
- {
- extern CRangeManager s_RangeMngr; // manages overwritten memory
- extern void ResolveInRange(int start, int end);
-
- static vector s_vTempBuffer, s_vTransferCache;
- static int gs_imageEnd = 0;
+void GSClut::init()
+{
+ g_pbyGSClut = (u8*)_aligned_malloc(256 * 8, 1024); // need 512 alignment!
+ memset(g_pbyGSClut, 0, 256*8);
+}
+
+void GSClut::destroy()
+{
+ _aligned_free(g_pbyGSClut);
+ g_pbyGSClut = NULL;
+}
+
+u8* GSClut::get()
+{
+ return g_pbyGSClut;
+}
+
+u8* GSClut::get(u32 addr)
+{
+ return &g_pbyGSClut[addr*8];
+}
+u8* GSClut::get_raw(u32 addr)
+{
+ return &g_pbyGSClut[addr];
+}
+
+extern _getPixelAddress getPixelFun[64];
+
+extern CRangeManager s_RangeMngr; // manages overwritten memory
+extern void ResolveInRange(int start, int end);
+
+static vector s_vTempBuffer, s_vTransferCache;
+static int gs_imageEnd = 0;
// From the start of monster labs. In all 3 cases, psm == 0.
// ZZogl-PG: GetRectMemAddress(0x3f4000, 0x404000, 0x0, 0x0, 0x0, 0x100, 0x40, 0x3f40, 0x100);
// ZZogl-PG: GetRectMemAddress(0x3f8000, 0x408000, 0x0, 0x0, 0x0, 0x100, 0x40, 0x3f80, 0x100);
// ZZogl-PG: GetRectMemAddress(0x3fc000, 0x40c000, 0x0, 0x0, 0x0, 0x100, 0x40, 0x3fc0, 0x100);
- void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw)
- {
- FUNCLOG
- u32 bits = 0;
+void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw)
+{
+ FUNCLOG
+ u32 bits = 0;
- if (m_Blocks[psm].bpp == 0)
- {
- ZZLog::Error_Log("ZeroGS: Bad psm 0x%x.", psm);
- start = 0;
- end = MEMORY_END;
- return;
- }
-
- if (PSMT_ISZTEX(psm))
- {
- // Somehow, I doubt this code is right. I'll have to look into it. For the moment, I'm keeping it the
- // way it was. --arcum42
-
- const BLOCK& b = m_Blocks[psm];
+ if (m_Blocks[psm].bpp == 0)
+ {
+ ZZLog::Error_Log("ZeroGS: Bad psm 0x%x.", psm);
+ start = 0;
+ end = MEMORY_END;
+ return;
+ }
- bw = (bw + b.width - 1) / b.width;
- start = bp * 256 + ((y / b.height) * bw + (x / b.width)) * 0x2000;
- end = bp * 256 + (((y + h - 1) / b.height) * bw + (x + w + b.width - 1) / b.width) * 0x2000;
- return;
- }
-
- bits = PSMT_BITS_NUM(psm);
- start = getPixelFun[psm](x, y, bp, bw);
- end = getPixelFun[psm](x + w - 1, y + h - 1, bp, bw) + 1;
+ if (PSMT_ISZTEX(psm))
+ {
+ // Somehow, I doubt this code is right. I'll have to look into it. For the moment, I'm keeping it the
+ // way it was. --arcum42
- if (bits > 0)
- {
- start *= bits;
- end *= bits;
- }
- else
- {
- // This is what it used to do, which doesn't seem right.
- // Keeping it for reference, in case removing it breaks anything.
-
- //int newx = ((x + w - 1 + 31) & ~31) - 1;
- //int newy = ((y + h - 1 + 15) & ~15) - 1;
- //start = getPixelAddress4(x, y, bp, bw) / 2;
- //end = (getPixelAddress4(max(newx, x), max(newy, y), bp, bw) + 2) / 2;
-
- start /= 2;
- end /= 2;
- }
- }
+ const BLOCK& b = m_Blocks[psm];
- void InitTransferHostLocal()
- {
- FUNCLOG
-
- #if defined(ZEROGS_DEVBUILD)
- if (gs.trxpos.dx + gs.imageWnew > gs.dstbuf.bw)
- ZZLog::Debug_Log("Transfer error, width exceeded.");
- #endif
-
- //bool bHasFlushed = false;
-
- gs.imageX = gs.trxpos.dx;
- gs.imageY = gs.trxpos.dy;
-
- gs.imageEndX = gs.imageX + gs.imageWnew;
- gs.imageEndY = gs.imageY + gs.imageHnew;
-
- assert(gs.imageEndX < 2048 && gs.imageEndY < 2048);
-
- // This needs to be looked in to, since psm should *not* be 63.
- // hack! viewful joe
- if (gs.dstbuf.psm == 63) gs.dstbuf.psm = 0;
-
- int start, end;
-
- GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw);
-
- if (end > MEMORY_END)
- {
- ZZLog::Warn_Log("Init host local out of bounds! (end == 0x%x)", end);
- //gs.imageTransfer = -1;
- end = MEMORY_END;
- }
-
- gs_imageEnd = end;
-
- if (vb[0].nCount > 0) Flush(0);
- if (vb[1].nCount > 0) Flush(1);
-
- //ZZLog::Prim_Log("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew);
- }
-
- void TransferHostLocal(const void* pbyMem, u32 nQWordSize)
- {
- FUNCLOG
-
- int start, end;
-
- GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw);
-
- assert(start < gs_imageEnd);
- end = gs_imageEnd;
-
- // sometimes games can decompress to alpha channel of render target only, in this case
- // do a resolve right away. wolverine x2
- if (((gs.dstbuf.psm == PSMT8H) || (gs.dstbuf.psm == PSMT4HL) || (gs.dstbuf.psm == PSMT4HH)) && !(conf.settings().gust))
- {
- list listTransmissionUpdateTargs;
- s_RTs.GetTargs(start, end, listTransmissionUpdateTargs);
-
- for (list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it)
- {
- CRenderTarget* ptarg = *it;
-
- if ((ptarg->status & CRenderTarget::TS_Virtual)) continue;
-
- //ZZLog::Error_Log("Resolving to alpha channel.");
- ptarg->Resolve();
- }
- }
-
- s_RangeMngr.Insert(start, min(end, start + (int)nQWordSize*16));
-
- const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize;
-
- if (s_vTransferCache.size() > 0)
- {
-
- int imagecache = s_vTransferCache.size();
- s_vTempBuffer.resize(imagecache + nQWordSize*4);
- memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache);
- memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4);
-
- pbyMem = (const void*) & s_vTempBuffer[0];
- porgend = &s_vTempBuffer[0] + s_vTempBuffer.size();
-
- int wordinc = imagecache / 4;
-
- if ((nQWordSize * 4 + imagecache) / 3 == ((nQWordSize + wordinc) * 4) / 3)
- {
- // can use the data
- nQWordSize += wordinc;
- }
- }
-
- int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize);
-
- if (leftover > 0)
- {
- // copy the last gs.image24bitOffset to the cache
- s_vTransferCache.resize(leftover);
- memcpy(&s_vTransferCache[0], porgend - leftover, leftover);
- }
- else
- {
- s_vTransferCache.resize(0);
- }
-
- #if defined(_DEBUG)
- if (g_bSaveTrans)
- {
- tex0Info t;
- t.tbp0 = gs.dstbuf.bp;
- t.tw = gs.imageWnew;
- t.th = gs.imageHnew;
- t.tbw = gs.dstbuf.bw;
- t.psm = gs.dstbuf.psm;
- SaveTex(&t, 0);
- }
-
- #endif
- }
-
- void InitTransferLocalHost()
- {
- FUNCLOG
- assert(gs.trxpos.sx + gs.imageWnew <= 2048 && gs.trxpos.sy + gs.imageHnew <= 2048);
-
- #if defined(ZEROGS_DEVBUILD)
- if (gs.trxpos.sx + gs.imageWnew > gs.srcbuf.bw)
- ZZLog::Debug_Log("Transfer error, width exceeded.");
- #endif
-
- gs.imageX = gs.trxpos.sx;
- gs.imageY = gs.trxpos.sy;
-
- gs.imageEndX = gs.imageX + gs.imageWnew;
- gs.imageEndY = gs.imageY + gs.imageHnew;
-
- s_vTransferCache.resize(0);
-
- int start, end;
-
- GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw);
-
- ResolveInRange(start, end);
- }
-
- template
- void TransferLocalHost(void* pbyMem, u32 nQWordSize, int& x, int& y, u8 *pstart)
- {
- _readPixel_0 rp = readPixelFun_0[gs.srcbuf.psm];
-
- int i = x, j = y;
- T* pbuf = (T*)pbyMem;
- u32 nSize = nQWordSize * 16 / sizeof(T);
-
- for (; i < gs.imageEndY; ++i)
- {
- for (; j < gs.imageEndX && nSize > 0; ++j, --nSize)
- {
- *pbuf++ = rp(pstart, j % 2048, i % 2048, gs.srcbuf.bw);
- }
-
- if (j >= gs.imageEndX)
- {
- assert(j == gs.imageEndX);
- j = gs.trxpos.sx;
- }
- else
- {
- assert(nSize == 0);
- break;
- }
- }
- }
-
- void TransferLocalHost_24(void* pbyMem, u32 nQWordSize, int& x, int& y, u8 *pstart)
- {
- _readPixel_0 rp = readPixelFun_0[gs.srcbuf.psm];
-
- int i = x, j = y;
- u8* pbuf = (u8*)pbyMem;
- u32 nSize = nQWordSize * 16 / 3;
-
- for (; i < gs.imageEndY; ++i)
- {
- for (; j < gs.imageEndX && nSize > 0; ++j, --nSize)
- {
- u32 p = rp(pstart, j % 2048, i % 2048, gs.srcbuf.bw);
- pbuf[0] = (u8)p;
- pbuf[1] = (u8)(p >> 8);
- pbuf[2] = (u8)(p >> 16);
- pbuf += 3;
- }
-
- if (j >= gs.imageEndX)
- {
- assert(j == gs.imageEndX);
- j = gs.trxpos.sx;
- }
- else
- {
- assert(nSize == 0);
- break;
- }
- }
- }
-
- // left/right, top/down
- void TransferLocalHost(void* pbyMem, u32 nQWordSize)
- {
- FUNCLOG
- assert(gs.imageTransfer == 1);
-
- u8* pstart = g_pbyGSMemory + 256 * gs.srcbuf.bp;
-
- switch(PSMT_BITMODE(gs.srcbuf.psm))
- {
- case 0: TransferLocalHost(pbyMem, nQWordSize, gs.imageY, gs.imageX, pstart); break;
- case 1: TransferLocalHost_24(pbyMem, nQWordSize, gs.imageY, gs.imageX, pstart); break;
- case 2: TransferLocalHost(pbyMem, nQWordSize, gs.imageY, gs.imageX, pstart); break;
- case 3: TransferLocalHost(pbyMem, nQWordSize, gs.imageY, gs.imageX, pstart); break;
- default: assert(0); break;
- }
-
- if (gs.imageY >= gs.imageEndY)
- {
- ZZLog::Error_Log("gs.imageY >= gs.imageEndY!");
- assert(gs.imageY == gs.imageEndY);
- gs.imageTransfer = -1;
- }
- }
-
+ bw = (bw + b.width - 1) / b.width;
+ start = bp * 256 + ((y / b.height) * bw + (x / b.width)) * 0x2000;
+ end = bp * 256 + (((y + h - 1) / b.height) * bw + (x + w + b.width - 1) / b.width) * 0x2000;
+ return;
+ }
+
+ bits = PSMT_BITS_NUM(psm);
+ start = getPixelFun[psm](x, y, bp, bw);
+ end = getPixelFun[psm](x + w - 1, y + h - 1, bp, bw) + 1;
+
+ if (bits > 0)
+ {
+ start *= bits;
+ end *= bits;
+ }
+ else
+ {
+ // This is what it used to do, which doesn't seem right.
+ // Keeping it for reference, in case removing it breaks anything.
+
+ //int newx = ((x + w - 1 + 31) & ~31) - 1;
+ //int newy = ((y + h - 1 + 15) & ~15) - 1;
+ //start = getPixelAddress4(x, y, bp, bw) / 2;
+ //end = (getPixelAddress4(max(newx, x), max(newy, y), bp, bw) + 2) / 2;
+
+ start /= 2;
+ end /= 2;
+ }
+}
+
+void InitTransferHostLocal()
+{
+ FUNCLOG
+
+#if defined(_DEBUG)
+ // Xenosaga 1.
+ if (gs.trxpos.dx + gs.imageWnew > gs.dstbuf.bw)
+ ZZLog::Debug_Log("Transfer error, width exceeded. (0x%x > 0X%x)", gs.trxpos.dx + gs.imageWnew, gs.dstbuf.bw);
+#endif
+
+ //bool bHasFlushed = false;
+
+ gs.imageX = gs.trxpos.dx;
+ gs.imageY = gs.trxpos.dy;
+
+ gs.imageEndX = gs.imageX + gs.imageWnew;
+ gs.imageEndY = gs.imageY + gs.imageHnew;
+
+ assert(gs.imageEndX < 2048 && gs.imageEndY < 2048);
+
+ // This needs to be looked in to, since psm should *not* be 63.
+ // hack! viewful joe
+ if (gs.dstbuf.psm == 63) gs.dstbuf.psm = 0;
+
+ int start, end;
+
+ GetRectMemAddress(start, end, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw);
+
+ if (end > MEMORY_END)
+ {
+ // Monster Lab - the screwed up title screen
+ // Init host local out of bounds! (end == 0x404000)
+ // Init host local out of bounds! (end == 0x408000)
+ // Init host local out of bounds! (end == 0x40c000)
+ // MEMORY_END is 0x400000...
+
+ ZZLog::Warn_Log("Init host local out of bounds! (end == 0x%x)", end);
+ //gs.imageTransfer = -1;
+ end = MEMORY_END;
+ }
+
+ gs_imageEnd = end;
+
+ if (vb[0].nCount > 0) Flush(0);
+ if (vb[1].nCount > 0) Flush(1);
+
+ //ZZLog::Prim_Log("trans: bp:%x x:%x y:%x w:%x h:%x\n", gs.dstbuf.bp, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew);
+}
+
+void TransferHostLocal(const void* pbyMem, u32 nQWordSize)
+{
+ FUNCLOG
+
+ int start, end;
+
+ GetRectMemAddress(start, end, gs.dstbuf.psm, gs.imageX, gs.imageY, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw);
+
+ assert(start < gs_imageEnd);
+ end = gs_imageEnd;
+
+ // sometimes games can decompress to alpha channel of render target only, in this case
+ // do a resolve right away. wolverine x2
+ if (((gs.dstbuf.psm == PSMT8H) || (gs.dstbuf.psm == PSMT4HL) || (gs.dstbuf.psm == PSMT4HH)) && !(conf.settings().gust))
+ {
+ list listTransmissionUpdateTargs;
+ s_RTs.GetTargs(start, end, listTransmissionUpdateTargs);
+
+ for (list::iterator it = listTransmissionUpdateTargs.begin(); it != listTransmissionUpdateTargs.end(); ++it)
+ {
+ CRenderTarget* ptarg = *it;
+
+ if ((ptarg->status & CRenderTarget::TS_Virtual)) continue;
+
+ //ZZLog::Error_Log("Resolving to alpha channel.");
+ ptarg->Resolve();
+ }
+ }
+
+ s_RangeMngr.Insert(start, min(end, start + (int)nQWordSize*16));
+
+ const u8* porgend = (const u8*)pbyMem + 4 * nQWordSize;
+
+ if (s_vTransferCache.size() > 0)
+ {
+
+ int imagecache = s_vTransferCache.size();
+ s_vTempBuffer.resize(imagecache + nQWordSize*4);
+ memcpy(&s_vTempBuffer[0], &s_vTransferCache[0], imagecache);
+ memcpy(&s_vTempBuffer[imagecache], pbyMem, nQWordSize*4);
+
+ pbyMem = (const void*) & s_vTempBuffer[0];
+ porgend = &s_vTempBuffer[0] + s_vTempBuffer.size();
+
+ int wordinc = imagecache / 4;
+
+ if ((nQWordSize * 4 + imagecache) / 3 == ((nQWordSize + wordinc) * 4) / 3)
+ {
+ // can use the data
+ nQWordSize += wordinc;
+ }
+ }
+
+ int leftover = m_Blocks[gs.dstbuf.psm].TransferHostLocal(pbyMem, nQWordSize);
+
+ if (leftover > 0)
+ {
+ // copy the last gs.image24bitOffset to the cache
+ s_vTransferCache.resize(leftover);
+ memcpy(&s_vTransferCache[0], porgend - leftover, leftover);
+ }
+ else
+ {
+ s_vTransferCache.resize(0);
+ }
+
+#if defined(_DEBUG)
+ if (g_bSaveTrans)
+ {
+ tex0Info t;
+ t.tbp0 = gs.dstbuf.bp;
+ t.tw = gs.imageWnew;
+ t.th = gs.imageHnew;
+ t.tbw = gs.dstbuf.bw;
+ t.psm = gs.dstbuf.psm;
+ SaveTex(&t, 0);
+ }
+
+#endif
+}
+
+void InitTransferLocalHost()
+{
+ FUNCLOG
+ assert(gs.trxpos.sx + gs.imageWnew <= 2048 && gs.trxpos.sy + gs.imageHnew <= 2048);
+
+#if defined(_DEBUG)
+ if (gs.trxpos.sx + gs.imageWnew > gs.srcbuf.bw)
+ ZZLog::Debug_Log("Transfer error, width exceeded. (0x%x > 0x%x)", gs.trxpos.sx + gs.imageWnew, gs.srcbuf.bw);
+#endif
+
+ gs.imageX = gs.trxpos.sx;
+ gs.imageY = gs.trxpos.sy;
+
+ gs.imageEndX = gs.imageX + gs.imageWnew;
+ gs.imageEndY = gs.imageY + gs.imageHnew;
+
+ s_vTransferCache.resize(0);
+
+ int start, end;
+
+ GetRectMemAddress(start, end, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw);
+
+ ResolveInRange(start, end);
+}
+
+template
+void TransferLocalHost(void* pbyMem, u32 nQWordSize, int& x, int& y, u8 *pstart)
+{
+ _readPixel_0 rp = readPixelFun_0[gs.srcbuf.psm];
+
+ int i = x, j = y;
+ T* pbuf = (T*)pbyMem;
+ u32 nSize = nQWordSize * 16 / sizeof(T);
+
+ for (; i < gs.imageEndY; ++i)
+ {
+ for (; j < gs.imageEndX && nSize > 0; ++j, --nSize)
+ {
+ *pbuf++ = rp(pstart, j % 2048, i % 2048, gs.srcbuf.bw);
+ }
+
+ if (j >= gs.imageEndX)
+ {
+ assert(j == gs.imageEndX);
+ j = gs.trxpos.sx;
+ }
+ else
+ {
+ assert(nSize == 0);
+ break;
+ }
+ }
+}
+
+void TransferLocalHost_24(void* pbyMem, u32 nQWordSize, int& x, int& y, u8 *pstart)
+{
+ _readPixel_0 rp = readPixelFun_0[gs.srcbuf.psm];
+
+ int i = x, j = y;
+ u8* pbuf = (u8*)pbyMem;
+ u32 nSize = nQWordSize * 16 / 3;
+
+ for (; i < gs.imageEndY; ++i)
+ {
+ for (; j < gs.imageEndX && nSize > 0; ++j, --nSize)
+ {
+ u32 p = rp(pstart, j % 2048, i % 2048, gs.srcbuf.bw);
+ pbuf[0] = (u8)p;
+ pbuf[1] = (u8)(p >> 8);
+ pbuf[2] = (u8)(p >> 16);
+ pbuf += 3;
+ }
+
+ if (j >= gs.imageEndX)
+ {
+ assert(j == gs.imageEndX);
+ j = gs.trxpos.sx;
+ }
+ else
+ {
+ assert(nSize == 0);
+ break;
+ }
+ }
+}
+
+// left/right, top/down
+void TransferLocalHost(void* pbyMem, u32 nQWordSize)
+{
+ FUNCLOG
+ assert(gs.imageTransfer == 1);
+
+ u8* pstart = g_pbyGSMemory + 256 * gs.srcbuf.bp;
+
+ switch(PSMT_BITMODE(gs.srcbuf.psm))
+ {
+ case 0:
+ TransferLocalHost(pbyMem, nQWordSize, gs.imageY, gs.imageX, pstart);
+ break;
+ case 1:
+ TransferLocalHost_24(pbyMem, nQWordSize, gs.imageY, gs.imageX, pstart);
+ break;
+ case 2:
+ TransferLocalHost(pbyMem, nQWordSize, gs.imageY, gs.imageX, pstart);
+ break;
+ case 3:
+ TransferLocalHost(pbyMem, nQWordSize, gs.imageY, gs.imageX, pstart);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ if (gs.imageY >= gs.imageEndY)
+ {
+ ZZLog::Error_Log("gs.imageY >= gs.imageEndY!");
+ assert(gs.imageY == gs.imageEndY);
+ gs.imageTransfer = -1;
+ }
+}
+
__forceinline void _TransferLocalLocal()
{
- //ZZLog::Error_Log("TransferLocalLocal(0x%x, 0x%x)", gs.srcbuf.psm, gs.dstbuf.psm);
- _writePixel_0 wp = writePixelFun_0[gs.srcbuf.psm];
- _readPixel_0 rp = readPixelFun_0[gs.dstbuf.psm];
- u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp * 256;
- u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp * 256;
- u32 widthlimit = 4;
- u32 maxX = gs.trxpos.sx + gs.imageWnew;
- u32 maxY = gs.trxpos.sy + gs.imageHnew;
-
- if (PSMT_BITMODE(gs.srcbuf.psm) == 0) widthlimit = 2;
- if ((gs.imageWnew & widthlimit) != 0) return;
-
- for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < maxY; i++, i2++)
- {
- for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < maxX; j += widthlimit, j2 += widthlimit)
- {
- wp(pDstBuf, j2%2048, i2%2048,
- rp(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw);
-
- wp(pDstBuf, (j2+1)%2048, i2%2048,
- rp(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw);
-
- if (widthlimit > 2)
- {
- // Then widthlimit == 4.
- wp(pDstBuf, (j2+2)%2048, i2%2048,
- rp(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw);
-
- wp(pDstBuf, (j2+3)%2048, i2%2048,
- rp(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw);
- }
- }
- }
+ //ZZLog::Error_Log("TransferLocalLocal(0x%x, 0x%x)", gs.srcbuf.psm, gs.dstbuf.psm);
+ _writePixel_0 wp = writePixelFun_0[gs.srcbuf.psm];
+ _readPixel_0 rp = readPixelFun_0[gs.dstbuf.psm];
+ u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp * 256;
+ u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp * 256;
+ u32 widthlimit = 4;
+ u32 maxX = gs.trxpos.sx + gs.imageWnew;
+ u32 maxY = gs.trxpos.sy + gs.imageHnew;
+
+ if (PSMT_BITMODE(gs.srcbuf.psm) == 0) widthlimit = 2;
+ if ((gs.imageWnew & widthlimit) != 0) return;
+
+ for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < maxY; i++, i2++)
+ {
+ for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < maxX; j += widthlimit, j2 += widthlimit)
+ {
+ wp(pDstBuf, j2%2048, i2%2048,
+ rp(pSrcBuf, j%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw);
+
+ wp(pDstBuf, (j2+1)%2048, i2%2048,
+ rp(pSrcBuf, (j+1)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw);
+
+ if (widthlimit > 2)
+ {
+ // Then widthlimit == 4.
+ wp(pDstBuf, (j2+2)%2048, i2%2048,
+ rp(pSrcBuf, (j+2)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw);
+
+ wp(pDstBuf, (j2+3)%2048, i2%2048,
+ rp(pSrcBuf, (j+3)%2048, i%2048, gs.srcbuf.bw), gs.dstbuf.bw);
+ }
+ }
+ }
}
-
+
__forceinline void _TransferLocalLocal_4()
{
- //ZZLog::Error_Log("TransferLocalLocal_4(0x%x, 0x%x)", gs.srcbuf.psm, gs.dstbuf.psm);
- _getPixelAddress_0 gsp = getPixelFun_0[gs.srcbuf.psm];
- _getPixelAddress_0 gdp = getPixelFun_0[gs.dstbuf.psm];
- u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp * 256;
- u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp * 256;
- u32 maxX = gs.trxpos.sx + gs.imageWnew;
- u32 maxY = gs.trxpos.sy + gs.imageHnew;
-
- assert((gs.imageWnew % 8) == 0);
-
- for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < maxY; ++i, ++i2)
- {
- for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < maxX; j += 8, j2 += 8)
- {
- /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */
- u32 read = gsp(j%2048, i%2048, gs.srcbuf.bw);
- u32 write = gdp(j2%2048, i2%2048, gs.dstbuf.bw);
- pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f);
-
- read = gsp((j+1)%2048, i%2048, gs.srcbuf.bw);
- write = gdp((j2+1)%2048, i2%2048, gs.dstbuf.bw);
- pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0);
-
- read = gsp((j+2)%2048, i%2048, gs.srcbuf.bw);
- write = gdp((j2+2)%2048, i2%2048, gs.dstbuf.bw);
- pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f);
-
- read = gsp((j+3)%2048, i%2048, gs.srcbuf.bw);
- write = gdp((j2+3)%2048, i2%2048, gs.dstbuf.bw);
- pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0);
-
- read = gsp((j+4)%2048, i%2048, gs.srcbuf.bw);
- write = gdp((j2+4)%2048, i2%2048, gs.dstbuf.bw);
- pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f);
-
- read = gsp((j+5)%2048, i%2048, gs.srcbuf.bw);
- write = gdp((j2+5)%2048, i2%2048, gs.dstbuf.bw);
- pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0);
-
- read = gsp((j+6)%2048, i%2048, gs.srcbuf.bw);
- write = gdp((j2+6)%2048, i2%2048, gs.dstbuf.bw);
- pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f);
-
- read = gsp((j+7)%2048, i%2048, gs.srcbuf.bw);
- write = gdp((j2+7)%2048, i2%2048, gs.dstbuf.bw);
- pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0);
- }
- }
+ //ZZLog::Error_Log("TransferLocalLocal_4(0x%x, 0x%x)", gs.srcbuf.psm, gs.dstbuf.psm);
+ _getPixelAddress_0 gsp = getPixelFun_0[gs.srcbuf.psm];
+ _getPixelAddress_0 gdp = getPixelFun_0[gs.dstbuf.psm];
+ u8* pSrcBuf = g_pbyGSMemory + gs.srcbuf.bp * 256;
+ u8* pDstBuf = g_pbyGSMemory + gs.dstbuf.bp * 256;
+ u32 maxX = gs.trxpos.sx + gs.imageWnew;
+ u32 maxY = gs.trxpos.sy + gs.imageHnew;
+
+ assert((gs.imageWnew % 8) == 0);
+
+ for(int i = gs.trxpos.sy, i2 = gs.trxpos.dy; i < maxY; ++i, ++i2)
+ {
+ for(int j = gs.trxpos.sx, j2 = gs.trxpos.dx; j < maxX; j += 8, j2 += 8)
+ {
+ /* NOTE: the 2 conseq 4bit values are in NOT in the same byte */
+ u32 read = gsp(j%2048, i%2048, gs.srcbuf.bw);
+ u32 write = gdp(j2%2048, i2%2048, gs.dstbuf.bw);
+ pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f);
+
+ read = gsp((j+1)%2048, i%2048, gs.srcbuf.bw);
+ write = gdp((j2+1)%2048, i2%2048, gs.dstbuf.bw);
+ pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0);
+
+ read = gsp((j+2)%2048, i%2048, gs.srcbuf.bw);
+ write = gdp((j2+2)%2048, i2%2048, gs.dstbuf.bw);
+ pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f);
+
+ read = gsp((j+3)%2048, i%2048, gs.srcbuf.bw);
+ write = gdp((j2+3)%2048, i2%2048, gs.dstbuf.bw);
+ pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0);
+
+ read = gsp((j+4)%2048, i%2048, gs.srcbuf.bw);
+ write = gdp((j2+4)%2048, i2%2048, gs.dstbuf.bw);
+ pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f);
+
+ read = gsp((j+5)%2048, i%2048, gs.srcbuf.bw);
+ write = gdp((j2+5)%2048, i2%2048, gs.dstbuf.bw);
+ pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0);
+
+ read = gsp((j+6)%2048, i%2048, gs.srcbuf.bw);
+ write = gdp((j2+6)%2048, i2%2048, gs.dstbuf.bw);
+ pDstBuf[write] = (pDstBuf[write]&0xf0)|(pSrcBuf[read]&0x0f);
+
+ read = gsp((j+7)%2048, i%2048, gs.srcbuf.bw);
+ write = gdp((j2+7)%2048, i2%2048, gs.dstbuf.bw);
+ pDstBuf[write] = (pDstBuf[write]&0x0f)|(pSrcBuf[read]&0xf0);
+ }
+ }
+}
+
+// dir depends on trxpos.dirx & trxpos.diry
+void TransferLocalLocal()
+{
+ FUNCLOG
+
+ //ZZLog::Error_Log("I'z in your code, transferring your memory...");
+ assert(gs.imageTransfer == 2);
+ assert(gs.trxpos.sx + gs.imageWnew < 2048 && gs.trxpos.sy + gs.imageHnew < 2048);
+ assert(gs.trxpos.dx + gs.imageWnew < 2048 && gs.trxpos.dy + gs.imageHnew < 2048);
+ assert((gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7));
+
+ if (gs.trxpos.sx + gs.imageWnew > gs.srcbuf.bw)
+ ZZLog::Debug_Log("Transfer error, src width exceeded.(0x%x > 0x%x)", gs.trxpos.sx + gs.imageWnew, gs.srcbuf.bw);
+
+ if (gs.trxpos.dx + gs.imageWnew > gs.dstbuf.bw)
+ ZZLog::Debug_Log("Transfer error, dst width exceeded.(0x%x > 0x%x)", gs.trxpos.dx + gs.imageWnew, gs.dstbuf.bw);
+
+ int srcstart, srcend, dststart, dstend;
+
+ GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw);
+ GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw);
+
+ // resolve the targs
+ ResolveInRange(srcstart, srcend);
+
+ list listTargs;
+
+ s_RTs.GetTargs(dststart, dstend, listTargs);
+
+ for (list::iterator it = listTargs.begin(); it != listTargs.end(); ++it)
+ {
+ if (!((*it)->status & CRenderTarget::TS_Virtual))
+ {
+ (*it)->Resolve();
+ //(*it)->status |= CRenderTarget::TS_NeedUpdate;
+ }
+ }
+
+ if (PSMT_BITMODE(gs.srcbuf.psm) != 4)
+ {
+ _TransferLocalLocal();
+ }
+ else
+ {
+ _TransferLocalLocal_4();
+ }
+
+ g_MemTargs.ClearRange(dststart, dstend);
+
+#ifdef ZEROGS_DEVBUILD
+
+ if (g_bSaveTrans)
+ {
+ tex0Info t;
+ t.tbp0 = gs.dstbuf.bp;
+ t.tw = gs.imageWnew;
+ t.th = gs.imageHnew;
+ t.tbw = gs.dstbuf.bw;
+ t.psm = gs.dstbuf.psm;
+ SaveTex(&t, 0);
+
+ t.tbp0 = gs.srcbuf.bp;
+ t.tw = gs.imageWnew;
+ t.th = gs.imageHnew;
+ t.tbw = gs.srcbuf.bw;
+ t.psm = gs.srcbuf.psm;
+ SaveTex(&t, 0);
+ }
+
+#endif
+}
+
+__forceinline void TerminateLocalHost()
+{
+ FUNCLOG
+ //ZZLog::Error_Log("Terminate Local Host!");
}
-
- // dir depends on trxpos.dirx & trxpos.diry
- void TransferLocalLocal()
- {
- FUNCLOG
-
- //ZZLog::Error_Log("I'z in your code, transferring your memory...");
- assert(gs.imageTransfer == 2);
- assert(gs.trxpos.sx + gs.imageWnew < 2048 && gs.trxpos.sy + gs.imageHnew < 2048);
- assert(gs.trxpos.dx + gs.imageWnew < 2048 && gs.trxpos.dy + gs.imageHnew < 2048);
- assert((gs.srcbuf.psm&0x7) == (gs.dstbuf.psm&0x7));
- if (gs.trxpos.sx + gs.imageWnew > gs.srcbuf.bw)
- ZZLog::Debug_Log("Transfer error, src width exceeded.");
+__forceinline void TerminateHostLocal()
+{
+ FUNCLOG
+ gs.imageTransfer = -1;
+}
- if (gs.trxpos.dx + gs.imageWnew > gs.dstbuf.bw)
- ZZLog::Debug_Log("Transfer error, dst width exceeded.");
-
- int srcstart, srcend, dststart, dstend;
-
- GetRectMemAddress(srcstart, srcend, gs.srcbuf.psm, gs.trxpos.sx, gs.trxpos.sy, gs.imageWnew, gs.imageHnew, gs.srcbuf.bp, gs.srcbuf.bw);
- GetRectMemAddress(dststart, dstend, gs.dstbuf.psm, gs.trxpos.dx, gs.trxpos.dy, gs.imageWnew, gs.imageHnew, gs.dstbuf.bp, gs.dstbuf.bw);
-
- // resolve the targs
- ResolveInRange(srcstart, srcend);
-
- list listTargs;
-
- s_RTs.GetTargs(dststart, dstend, listTargs);
-
- for (list::iterator it = listTargs.begin(); it != listTargs.end(); ++it)
- {
- if (!((*it)->status & CRenderTarget::TS_Virtual))
- {
- (*it)->Resolve();
- //(*it)->status |= CRenderTarget::TS_NeedUpdate;
- }
- }
-
- if (PSMT_BITMODE(gs.srcbuf.psm) != 4)
- {
- _TransferLocalLocal();
- }
- else
- {
- _TransferLocalLocal_4();
- }
-
- g_MemTargs.ClearRange(dststart, dstend);
-
- #ifdef ZEROGS_DEVBUILD
-
- if (g_bSaveTrans)
- {
- tex0Info t;
- t.tbp0 = gs.dstbuf.bp;
- t.tw = gs.imageWnew;
- t.th = gs.imageHnew;
- t.tbw = gs.dstbuf.bw;
- t.psm = gs.dstbuf.psm;
- SaveTex(&t, 0);
-
- t.tbp0 = gs.srcbuf.bp;
- t.tw = gs.imageWnew;
- t.th = gs.imageHnew;
- t.tbw = gs.srcbuf.bw;
- t.psm = gs.srcbuf.psm;
- SaveTex(&t, 0);
- }
-
- #endif
- }
-
- }
diff --git a/plugins/zzogl-pg/opengl/HostMemory.h b/plugins/zzogl-pg/opengl/HostMemory.h
new file mode 100644
index 0000000000..e9217685d1
--- /dev/null
+++ b/plugins/zzogl-pg/opengl/HostMemory.h
@@ -0,0 +1,114 @@
+/* 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 HOSTMEMORY_H_INCLUDED
+#define HOSTMEMORY_H_INCLUDED
+
+#include "GLWin.h"
+
+#define MEMORY_END 0x00400000
+
+extern int GPU_TEXWIDTH;
+
+extern u8* g_pBasePS2Mem;
+extern u8* g_pbyGSMemory;
+
+class GSMemory
+{
+ public:
+ void init();
+ void destroy();
+ u8* get();
+ u8* get(u32 addr);
+ u8* get_raw(u32 addr);
+};
+
+extern u8* g_pbyGSClut; // the temporary clut buffer
+
+class GSClut
+{
+ public:
+ void init();
+ void destroy();
+ u8* get();
+ u8* get(u32 addr);
+ u8* get_raw(u32 addr);
+};
+
+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;
+ }
+};
+
+// 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;
+}
+
+extern void GetRectMemAddress(int& start, int& end, int psm, int x, int y, int w, int h, int bp, int bw);
+
+
+// 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?
+extern void InitTransferHostLocal();
+extern void TransferHostLocal(const void* pbyMem, u32 nQWordSize);
+
+extern void InitTransferLocalHost();
+extern void TransferLocalHost(void* pbyMem, u32 nQWordSize);
+
+extern void TransferLocalLocal();
+
+extern void TerminateLocalHost();
+extern void TerminateHostLocal();
+
+#endif // HOSTMEMORY_H_INCLUDED
diff --git a/plugins/zzogl-pg/opengl/Linux/Conf.cpp b/plugins/zzogl-pg/opengl/Linux/Conf.cpp
index 4c008e945f..b600421f83 100644
--- a/plugins/zzogl-pg/opengl/Linux/Conf.cpp
+++ b/plugins/zzogl-pg/opengl/Linux/Conf.cpp
@@ -40,7 +40,7 @@ void SaveConfig()
fprintf(f, "mrtdepth = %hhx\n", conf.mrtdepth);
fprintf(f, "zzoptions = %x\n", conf.zz_options._u32);
- fprintf(f, "options = %x\n", conf.hacks);
+ fprintf(f, "options = %x\n", conf.hacks._u32);
fprintf(f, "bilinear = %hhx\n", conf.bilinear);
fprintf(f, "aliasing = %hhx\n", conf.aa);
fprintf(f, "width = %x\n", conf.width);
diff --git a/plugins/zzogl-pg/opengl/Linux/Linux.cpp b/plugins/zzogl-pg/opengl/Linux/Linux.cpp
index 3d8baee9c6..df1e87f63c 100644
--- a/plugins/zzogl-pg/opengl/Linux/Linux.cpp
+++ b/plugins/zzogl-pg/opengl/Linux/Linux.cpp
@@ -24,7 +24,6 @@
#include "GS.h"
#include "Linux.h"
-#include "zerogs.h"
#include "GLWin.h"
#include
-
-
@@ -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