- more thorough blur detection
- makesnapshot delayed until the next vsync (so shift+f8 won't crash randomly)

xpad:
- fixed "Issue 38: Bad performance with Xpad"

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@834 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gabest11 2009-03-22 13:10:31 +00:00
parent c96334ddf2
commit 95c7ce1dbc
7 changed files with 268 additions and 84 deletions

View File

@ -23,66 +23,140 @@
#include "GSDump.h" #include "GSDump.h"
GSDump::GSDump() GSDump::GSDump()
: m_fp(NULL) : m_gs(NULL)
, m_obj(NULL)
, m_frames(0)
, m_objects(0)
, m_vertices(0)
{ {
} }
GSDump::~GSDump() GSDump::~GSDump()
{ {
if(m_fp) Close();
}
void GSDump::Open(const CString& fn, DWORD crc, const GSFreezeData& fd, const void* regs)
{
m_gs = _tfopen(fn + _T(".gs"), _T("wb"));
m_obj = _tfopen(fn + _T(".obj"), _T("wt"));
m_frames = 0;
m_objects = 0;
m_vertices = 0;
if(m_gs)
{ {
fclose(m_fp); fwrite(&crc, 4, 1, m_gs);
fwrite(&fd.size, 4, 1, m_gs);
fwrite(fd.data, fd.size, 1, m_gs);
fwrite(regs, 0x2000, 1, m_gs);
} }
} }
void GSDump::Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs) void GSDump::Close()
{ {
m_fp = _tfopen(fn, _T("wb")); if(m_gs) {fclose(m_gs); m_gs = NULL;}
m_vsyncs = 0; if(m_obj) {fclose(m_obj); m_obj = NULL;}
if(m_fp)
{
fwrite(&crc, 4, 1, m_fp);
fwrite(&fd.size, 4, 1, m_fp);
fwrite(fd.data, fd.size, 1, m_fp);
fwrite(regs, 0x2000, 1, m_fp);
}
} }
void GSDump::Transfer(int index, BYTE* mem, size_t size) void GSDump::Transfer(int index, BYTE* mem, size_t size)
{ {
if(m_fp && size > 0) if(m_gs && size > 0)
{ {
fputc(0, m_fp); fputc(0, m_gs);
fputc(index, m_fp); fputc(index, m_gs);
fwrite(&size, 4, 1, m_fp); fwrite(&size, 4, 1, m_gs);
fwrite(mem, size, 1, m_fp); fwrite(mem, size, 1, m_gs);
} }
} }
void GSDump::ReadFIFO(UINT32 size) void GSDump::ReadFIFO(UINT32 size)
{ {
if(m_fp && size > 0) if(m_gs && size > 0)
{ {
fputc(2, m_fp); fputc(2, m_gs);
fwrite(&size, 4, 1, m_fp); fwrite(&size, 4, 1, m_gs);
} }
} }
void GSDump::VSync(int field, bool last, const void* regs) void GSDump::VSync(int field, bool last, const void* regs)
{ {
if(m_fp) if(m_gs)
{ {
fputc(3, m_fp); fputc(3, m_gs);
fwrite(regs, 0x2000, 1, m_fp); fwrite(regs, 0x2000, 1, m_gs);
fputc(1, m_fp); fputc(1, m_gs);
fputc(field, m_fp); fputc(field, m_gs);
if((++m_vsyncs & 1) == 0 && last) if((++m_frames & 1) == 0 && last)
{ {
fclose(m_fp); Close();
m_fp = NULL; }
}
}
void GSDump::Object(GSVertexSW* vertices, int count, GS_PRIM_CLASS primclass)
{
if(m_obj)
{
switch(primclass)
{
case GS_POINT_CLASS:
// TODO
break;
case GS_LINE_CLASS:
// TODO
break;
case GS_TRIANGLE_CLASS:
for(int i = 0; i < count; i++)
{
float x = vertices[i].p.x;
float y = vertices[i].p.y;
float z = vertices[i].p.z;
_ftprintf(m_obj, _T("v %f %f %f\n"), x, y, z);
}
for(int i = 0; i < count; i++)
{
_ftprintf(m_obj, _T("vt %f %f %f\n"), vertices[i].t.x, vertices[i].t.y, vertices[i].t.z);
}
for(int i = 0; i < count; i++)
{
_ftprintf(m_obj, _T("vn %f %f %f\n"), 0.0f, 0.0f, 0.0f);
}
_ftprintf(m_obj, _T("g f%d_o%d_p%d_v%d\n"), m_frames, m_objects, primclass, count);
for(int i = 0; i < count; i += 3)
{
int a = m_vertices + i + 1;
int b = m_vertices + i + 2;
int c = m_vertices + i + 3;
_ftprintf(m_obj, _T("f %d/%d/%d %d/%d/%d %d/%d/%d \n"), a, a, a, b, b, b, c, c, c);
}
m_vertices += count;
m_objects++;
break;
case GS_SPRITE_CLASS:
// TODO
break;
} }
} }
} }

View File

@ -22,6 +22,7 @@
#pragma once #pragma once
#include "GS.h" #include "GS.h"
#include "GSVertexSW.h"
/* /*
@ -44,16 +45,21 @@ Regs data (id == 3)
class GSDump class GSDump
{ {
FILE* m_fp; FILE* m_gs;
int m_vsyncs; FILE* m_obj;
int m_frames;
int m_objects;
int m_vertices;
public: public:
GSDump(); GSDump();
virtual ~GSDump(); virtual ~GSDump();
void Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs); void Open(const CString& fn, DWORD crc, const GSFreezeData& fd, const void* regs);
void Close();
void ReadFIFO(UINT32 size); void ReadFIFO(UINT32 size);
void Transfer(int index, BYTE* mem, size_t size); void Transfer(int index, BYTE* mem, size_t size);
void VSync(int field, bool last, const void* regs); void VSync(int field, bool last, const void* regs);
operator bool() {return m_fp != NULL;} void Object(GSVertexSW* vertices, int count, GS_PRIM_CLASS primclass);
operator bool() {return m_gs != NULL;}
}; };

View File

@ -41,7 +41,6 @@ class GSRendererBase : public GSState, protected GSRendererSettings
{ {
protected: protected:
bool m_osd; bool m_osd;
int m_field;
void ProcessWindowMessages() void ProcessWindowMessages()
{ {
@ -103,7 +102,6 @@ public:
GSRendererBase(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs) GSRendererBase(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
: GSState(base, mt, irq, nloophack) : GSState(base, mt, irq, nloophack)
, m_osd(true) , m_osd(true)
, m_field(0)
{ {
m_interlace = rs.m_interlace; m_interlace = rs.m_interlace;
m_aspectratio = rs.m_aspectratio; m_aspectratio = rs.m_aspectratio;
@ -126,7 +124,7 @@ protected:
virtual void ResetDevice() {} virtual void ResetDevice() {}
virtual bool GetOutput(int i, Texture& t) = 0; virtual bool GetOutput(int i, Texture& t) = 0;
bool Merge() bool Merge(int field)
{ {
bool en[2]; bool en[2];
@ -145,6 +143,8 @@ protected:
dr[i] = GetDisplayRect(i); dr[i] = GetDisplayRect(i);
baseline = min(dr[i].top, baseline); baseline = min(dr[i].top, baseline);
// printf("[%d]: %d %d %d %d, %d %d %d %d\n", i, fr[i], dr[i]);
} }
} }
@ -158,12 +158,10 @@ protected:
&& DISPFB[0]->FBW == DISPFB[1]->FBW && DISPFB[0]->FBW == DISPFB[1]->FBW
&& DISPFB[0]->PSM == DISPFB[1]->PSM) && DISPFB[0]->PSM == DISPFB[1]->PSM)
{ {
CRect fr1 = fr[1] + CRect(0, 1, 0, 0); if(fr[0] == fr[1] + CRect(0, 1, 0, 0) && dr[0] == dr[1] + CRect(0, 0, 0, 1)
CRect dr1 = dr[1] + CRect(0, 0, 0, 1); || fr[1] == fr[0] + CRect(0, 1, 0, 0) && dr[1] == dr[0] + CRect(0, 0, 0, 1))
if(fr[0] == fr1 && dr[0] == dr1)
{ {
// persona 4 for example: // persona 4:
// //
// fr[0] = 0, 0, 640, 448 (y = 0, height = 448) // fr[0] = 0, 0, 640, 448 (y = 0, height = 448)
// fr[1] = 0, 1, 640, 448 (y = 1, height = 447) // fr[1] = 0, 1, 640, 448 (y = 1, height = 447)
@ -171,9 +169,38 @@ protected:
// dr[1] = 159, 50, 779, 497 (y = 50, height = 447) // dr[1] = 159, 50, 779, 497 (y = 50, height = 447)
// //
// second image shifted up by 1 pixel and blended over itself // second image shifted up by 1 pixel and blended over itself
//
// god of war:
//
// fr[0] = 0 1 512 448
// fr[1] = 0 0 512 448
// dr[0] = 127 50 639 497
// dr[1] = 127 50 639 498
//
// same just the first image shifted
fr[1].top = fr[0].top; int top = min(fr[0].top, fr[1].top);
dr[1].bottom = dr[0].bottom; int bottom = max(dr[0].bottom, dr[1].bottom);
fr[0].top = top;
fr[1].top = top;
dr[0].bottom = bottom;
dr[1].bottom = bottom;
}
else if(dr[0] == dr[1] && (fr[0] == fr[1] + CPoint(0, 1) || fr[1] == fr[0] + CPoint(0, 1)))
{
// dq5:
//
// fr[0] = 0 1 512 445
// fr[1] = 0 0 512 444
// dr[0] = 127 50 639 494
// dr[1] = 127 50 639 494
int top = min(fr[0].top, fr[1].top);
int bottom = min(fr[0].bottom, fr[1].bottom);
fr[0].top = fr[1].top = top;
fr[0].bottom = fr[1].bottom = bottom;
} }
} }
} }
@ -252,10 +279,10 @@ protected:
if(SMODE2->INT && m_interlace > 0) if(SMODE2->INT && m_interlace > 0)
{ {
int field = 1 - ((m_interlace - 1) & 1); int field2 = 1 - ((m_interlace - 1) & 1);
int mode = (m_interlace - 1) >> 1; int mode = (m_interlace - 1) >> 1;
if(!m_dev.Interlace(ds, m_field ^ field, mode, tex[1].m_scale.y)) if(!m_dev.Interlace(ds, field ^ field2, mode, tex[1].m_scale.y))
{ {
return false; return false;
} }
@ -265,6 +292,37 @@ protected:
return true; return true;
} }
void DoSnapshot(int field)
{
if(!m_snapshot.IsEmpty())
{
if(!m_dump && (::GetAsyncKeyState(VK_SHIFT) & 0x8000))
{
GSFreezeData fd;
fd.size = 0;
fd.data = NULL;
Freeze(&fd, true);
fd.data = new BYTE[fd.size];
Freeze(&fd, false);
m_dump.Open(m_snapshot, m_crc, fd, PMODE);
delete [] fd.data;
}
m_dev.SaveCurrent(m_snapshot + _T(".bmp"));
m_snapshot.Empty();
}
else
{
if(m_dump)
{
m_dump.VSync(field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), PMODE);
}
}
}
void DoCapture() void DoCapture()
{ {
if(!m_capture.IsCapturing()) if(!m_capture.IsCapturing())
@ -327,6 +385,7 @@ public:
bool s_save; bool s_save;
bool s_savez; bool s_savez;
CString m_snapshot;
GSCapture m_capture; GSCapture m_capture;
public: public:
@ -359,24 +418,17 @@ public:
void VSync(int field) void VSync(int field)
{ {
// printf("VSYNC\n");
GSPerfMonAutoTimer pmat(m_perfmon); GSPerfMonAutoTimer pmat(m_perfmon);
m_field = !!field;
Flush(); Flush();
m_perfmon.Put(GSPerfMon::Frame); m_perfmon.Put(GSPerfMon::Frame);
ProcessWindowMessages(); ProcessWindowMessages();
if(m_dump) field = field ? 1 : 0;
{
m_dump.VSync(m_field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), PMODE);
}
if(!Merge()) return; if(!Merge(field)) return;
// osd // osd
@ -453,30 +505,21 @@ public:
m_dev.Present(r); m_dev.Present(r);
//
DoSnapshot(field);
DoCapture(); DoCapture();
} }
bool MakeSnapshot(LPCTSTR path) bool MakeSnapshot(LPCTSTR path)
{ {
CString fn; if(m_snapshot.IsEmpty())
fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S")));
if((::GetAsyncKeyState(VK_SHIFT) & 0x8000) && !m_dump)
{ {
GSFreezeData fd; m_snapshot.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S")));
fd.size = 0;
fd.data = NULL;
Freeze(&fd, true);
fd.data = new BYTE[fd.size];
Freeze(&fd, false);
m_dump.Open(fn + _T(".gs"), m_crc, fd, PMODE);
delete [] fd.data;
} }
return m_dev.SaveCurrent(fn + _T(".bmp")); return true;
} }
virtual void MinMaxUV(int w, int h, CRect& r) {r = CRect(0, 0, w, h);} virtual void MinMaxUV(int w, int h, CRect& r) {r = CRect(0, 0, w, h);}

View File

@ -500,6 +500,11 @@ protected:
m_vtrace.Update(m_vertices, m_count, primclass, PRIM->IIP, PRIM->TME, m_context->TEX0.TFX); m_vtrace.Update(m_vertices, m_count, primclass, PRIM->IIP, PRIM->TME, m_context->TEX0.TFX);
if(m_dump)
{
m_dump.Object(m_vertices, m_count, primclass);
}
GSScanlineParam p; GSScanlineParam p;
GetScanlineParam(p, primclass); GetScanlineParam(p, primclass);
@ -771,6 +776,8 @@ public:
if(GSVertexSW* v = DrawingKick<prim>(skip, count)) if(GSVertexSW* v = DrawingKick<prim>(skip, count))
{ {
if(!m_dump)
{
GSVector4 pmin, pmax; GSVector4 pmin, pmax;
switch(prim) switch(prim)
@ -822,7 +829,7 @@ public:
{ {
return; return;
} }
}
switch(prim) switch(prim)
{ {
case GS_POINTLIST: case GS_POINTLIST:

View File

@ -1671,6 +1671,7 @@ struct GSFrameInfo
{ {
DWORD FBP; DWORD FBP;
DWORD FPSM; DWORD FPSM;
DWORD FBMSK;
bool TME; bool TME;
DWORD TBP0; DWORD TBP0;
DWORD TPSM; DWORD TPSM;
@ -2050,6 +2051,10 @@ bool GSC_GodOfWar(const GSFrameInfo& fi, int& skip)
{ {
skip = 30; skip = 30;
} }
else if(fi.TME && fi.FBP == 0x00000 && fi.FPSM == PSM_PSMCT32 && fi.TBP0 == 0x00000 && fi.TPSM == PSM_PSMCT32 && fi.FBMSK == 0xff000000)
{
skip = 1; // blur
}
} }
else else
{ {
@ -2114,6 +2119,7 @@ bool GSState::IsBadFrame(int& skip)
fi.FBP = m_context->FRAME.Block(); fi.FBP = m_context->FRAME.Block();
fi.FPSM = m_context->FRAME.PSM; fi.FPSM = m_context->FRAME.PSM;
fi.FBMSK = m_context->FRAME.FBMSK;
fi.TME = PRIM->TME; fi.TME = PRIM->TME;
fi.TBP0 = m_context->TEX0.TBP0; fi.TBP0 = m_context->TEX0.TBP0;
fi.TPSM = m_context->TEX0.PSM; fi.TPSM = m_context->TEX0.PSM;

View File

@ -101,17 +101,17 @@ __declspec(align(16)) union GSVertexSW
if(v34.allfalse()) if(v34.allfalse())
{ {
test = (v35 ^ v45) & (v35 ^ v45.zwxy()) & (vtl == v3 + (v4 - v5)) & (vbr == v5); test = (v35 ^ v45) & (v35 ^ v45.zwxy()) & (vtl + v5 == v3 + v4) & (vbr == v5);
i = 5; i = 5;
} }
else if(v35.allfalse()) else if(v35.allfalse())
{ {
test = (v34 ^ v45) & (v34 ^ v45.zwxy()) & (vtl == v3 + (v5 - v4)) & (vbr == v4); test = (v34 ^ v45) & (v34 ^ v45.zwxy()) & (vtl + v4 == v3 + v5) & (vbr == v4);
i = 4; i = 4;
} }
else if(v45.allfalse()) else if(v45.allfalse())
{ {
test = (v34 ^ v35) & (v34 ^ v35.zwxy()) & (vtl == v5 + (v4 - v3)) & (vbr == v3); test = (v34 ^ v35) & (v34 ^ v35.zwxy()) & (vtl + v3 == v5 + v4) & (vbr == v3);
i = 3; i = 3;
} }
else else

View File

@ -139,10 +139,63 @@ struct XPadButton
}; };
}; };
class XInput
{
int m_pad;
bool m_connected;
XINPUT_STATE m_state;
XINPUT_VIBRATION m_vibration;
clock_t m_lastpoll;
public:
XInput(int pad)
: m_pad(pad)
, m_connected(false)
, m_lastpoll(0)
{
memset(&m_vibration, 0, sizeof(m_vibration));
}
bool GetState(XINPUT_STATE& state)
{
clock_t now = clock();
clock_t delay = m_connected ? 16 : 1000; // poll once per frame (16 ms is about 60 fps)
if(now > m_lastpoll + delay)
{
memset(&m_state, 0, sizeof(m_state));
m_connected = XInputGetState(m_pad, &m_state) == S_OK; // ERROR_DEVICE_NOT_CONNECTED is not an error, SUCCEEDED(...) won't work here
m_lastpoll = now;
}
memcpy(&state, &m_state, sizeof(state));
return m_connected;
}
void SetState(XINPUT_VIBRATION& vibration)
{
if(m_vibration.wLeftMotorSpeed != vibration.wLeftMotorSpeed || m_vibration.wRightMotorSpeed != vibration.wRightMotorSpeed)
{
XInputSetState(m_pad, &vibration);
m_vibration = vibration;
}
}
bool IsConnected()
{
return m_connected;
}
};
class XPad class XPad
{ {
public: public:
int m_pad; int m_pad;
XInput m_xinput;
bool m_connected; bool m_connected;
bool m_ds2native; bool m_ds2native;
bool m_analog; bool m_analog;
@ -175,8 +228,7 @@ public:
public: public:
XPad(int pad) XPad(int pad)
: m_pad(pad) : m_xinput(pad)
, m_connected(false)
, m_ds2native(false) , m_ds2native(false)
, m_analog(!s_ps2) // defaults to analog off for ps2 , m_analog(!s_ps2) // defaults to analog off for ps2
, m_locked(false) , m_locked(false)
@ -202,11 +254,7 @@ public:
{ {
XINPUT_STATE state; XINPUT_STATE state;
memset(&state, 0, sizeof(state)); if(m_xinput.GetState(state))
m_connected = SUCCEEDED(XInputGetState(m_pad, &state));
if(m_connected)
{ {
SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_BACK, XPadButton::Select); SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_BACK, XPadButton::Select);
SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB, XPadButton::L3); SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB, XPadButton::L3);
@ -242,7 +290,7 @@ public:
if(index == 1) if(index == 1)
{ {
if(m_connected) if(m_xinput.IsConnected())
{ {
XINPUT_VIBRATION vibraton; XINPUT_VIBRATION vibraton;
@ -254,7 +302,7 @@ public:
vibraton.wRightMotorSpeed = m_small << 8; vibraton.wRightMotorSpeed = m_small << 8;
} }
XInputSetState(m_pad, &vibraton); m_xinput.SetState(vibraton);
} }
} }