- 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"
GSDump::GSDump()
: m_fp(NULL)
: m_gs(NULL)
, m_obj(NULL)
, m_frames(0)
, m_objects(0)
, m_vertices(0)
{
}
GSDump::~GSDump()
{
if(m_fp)
Close();
}
void GSDump::Open(const CString& fn, DWORD crc, const GSFreezeData& fd, const void* regs)
{
fclose(m_fp);
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)
{
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"));
m_vsyncs = 0;
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);
}
if(m_gs) {fclose(m_gs); m_gs = NULL;}
if(m_obj) {fclose(m_obj); m_obj = NULL;}
}
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(index, m_fp);
fwrite(&size, 4, 1, m_fp);
fwrite(mem, size, 1, m_fp);
fputc(0, m_gs);
fputc(index, m_gs);
fwrite(&size, 4, 1, m_gs);
fwrite(mem, size, 1, m_gs);
}
}
void GSDump::ReadFIFO(UINT32 size)
{
if(m_fp && size > 0)
if(m_gs && size > 0)
{
fputc(2, m_fp);
fwrite(&size, 4, 1, m_fp);
fputc(2, m_gs);
fwrite(&size, 4, 1, m_gs);
}
}
void GSDump::VSync(int field, bool last, const void* regs)
{
if(m_fp)
if(m_gs)
{
fputc(3, m_fp);
fwrite(regs, 0x2000, 1, m_fp);
fputc(3, m_gs);
fwrite(regs, 0x2000, 1, m_gs);
fputc(1, m_fp);
fputc(field, m_fp);
fputc(1, m_gs);
fputc(field, m_gs);
if((++m_vsyncs & 1) == 0 && last)
if((++m_frames & 1) == 0 && last)
{
fclose(m_fp);
m_fp = NULL;
Close();
}
}
}
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
#include "GS.h"
#include "GSVertexSW.h"
/*
@ -44,16 +45,21 @@ Regs data (id == 3)
class GSDump
{
FILE* m_fp;
int m_vsyncs;
FILE* m_gs;
FILE* m_obj;
int m_frames;
int m_objects;
int m_vertices;
public:
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 Transfer(int index, BYTE* mem, size_t size);
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:
bool m_osd;
int m_field;
void ProcessWindowMessages()
{
@ -103,7 +102,6 @@ public:
GSRendererBase(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
: GSState(base, mt, irq, nloophack)
, m_osd(true)
, m_field(0)
{
m_interlace = rs.m_interlace;
m_aspectratio = rs.m_aspectratio;
@ -126,7 +124,7 @@ protected:
virtual void ResetDevice() {}
virtual bool GetOutput(int i, Texture& t) = 0;
bool Merge()
bool Merge(int field)
{
bool en[2];
@ -145,6 +143,8 @@ protected:
dr[i] = GetDisplayRect(i);
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]->PSM == DISPFB[1]->PSM)
{
CRect fr1 = fr[1] + CRect(0, 1, 0, 0);
CRect dr1 = dr[1] + CRect(0, 0, 0, 1);
if(fr[0] == fr1 && dr[0] == dr1)
if(fr[0] == fr[1] + CRect(0, 1, 0, 0) && dr[0] == 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))
{
// persona 4 for example:
// persona 4:
//
// fr[0] = 0, 0, 640, 448 (y = 0, height = 448)
// 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)
//
// 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;
dr[1].bottom = dr[0].bottom;
int top = min(fr[0].top, fr[1].top);
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)
{
int field = 1 - ((m_interlace - 1) & 1);
int field2 = 1 - ((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;
}
@ -265,6 +292,37 @@ protected:
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()
{
if(!m_capture.IsCapturing())
@ -327,6 +385,7 @@ public:
bool s_save;
bool s_savez;
CString m_snapshot;
GSCapture m_capture;
public:
@ -359,24 +418,17 @@ public:
void VSync(int field)
{
// printf("VSYNC\n");
GSPerfMonAutoTimer pmat(m_perfmon);
m_field = !!field;
Flush();
m_perfmon.Put(GSPerfMon::Frame);
ProcessWindowMessages();
if(m_dump)
{
m_dump.VSync(m_field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), PMODE);
}
field = field ? 1 : 0;
if(!Merge()) return;
if(!Merge(field)) return;
// osd
@ -453,30 +505,21 @@ public:
m_dev.Present(r);
//
DoSnapshot(field);
DoCapture();
}
bool MakeSnapshot(LPCTSTR path)
{
CString fn;
fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S")));
if((::GetAsyncKeyState(VK_SHIFT) & 0x8000) && !m_dump)
if(m_snapshot.IsEmpty())
{
GSFreezeData fd;
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;
m_snapshot.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S")));
}
return m_dev.SaveCurrent(fn + _T(".bmp"));
return true;
}
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);
if(m_dump)
{
m_dump.Object(m_vertices, m_count, primclass);
}
GSScanlineParam p;
GetScanlineParam(p, primclass);
@ -770,6 +775,8 @@ public:
DWORD count = 0;
if(GSVertexSW* v = DrawingKick<prim>(skip, count))
{
if(!m_dump)
{
GSVector4 pmin, pmax;
@ -822,7 +829,7 @@ public:
{
return;
}
}
switch(prim)
{
case GS_POINTLIST:

View File

@ -1671,6 +1671,7 @@ struct GSFrameInfo
{
DWORD FBP;
DWORD FPSM;
DWORD FBMSK;
bool TME;
DWORD TBP0;
DWORD TPSM;
@ -2050,6 +2051,10 @@ bool GSC_GodOfWar(const GSFrameInfo& fi, int& skip)
{
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
{
@ -2114,6 +2119,7 @@ bool GSState::IsBadFrame(int& skip)
fi.FBP = m_context->FRAME.Block();
fi.FPSM = m_context->FRAME.PSM;
fi.FBMSK = m_context->FRAME.FBMSK;
fi.TME = PRIM->TME;
fi.TBP0 = m_context->TEX0.TBP0;
fi.TPSM = m_context->TEX0.PSM;

View File

@ -101,17 +101,17 @@ __declspec(align(16)) union GSVertexSW
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;
}
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;
}
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;
}
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
{
public:
int m_pad;
XInput m_xinput;
bool m_connected;
bool m_ds2native;
bool m_analog;
@ -175,8 +228,7 @@ public:
public:
XPad(int pad)
: m_pad(pad)
, m_connected(false)
: m_xinput(pad)
, m_ds2native(false)
, m_analog(!s_ps2) // defaults to analog off for ps2
, m_locked(false)
@ -202,11 +254,7 @@ public:
{
XINPUT_STATE state;
memset(&state, 0, sizeof(state));
m_connected = SUCCEEDED(XInputGetState(m_pad, &state));
if(m_connected)
if(m_xinput.GetState(state))
{
SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_BACK, XPadButton::Select);
SetButton(state.Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB, XPadButton::L3);
@ -242,7 +290,7 @@ public:
if(index == 1)
{
if(m_connected)
if(m_xinput.IsConnected())
{
XINPUT_VIBRATION vibraton;
@ -254,7 +302,7 @@ public:
vibraton.wRightMotorSpeed = m_small << 8;
}
XInputSetState(m_pad, &vibraton);
m_xinput.SetState(vibraton);
}
}