mirror of https://github.com/PCSX2/pcsx2.git
GSdx:
- 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:
parent
c96334ddf2
commit
95c7ce1dbc
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;}
|
||||
};
|
||||
|
|
|
@ -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);}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue