GSdx: converted a few template classes to pointers and virtual functions, the dll got more than 100k smaller, since there were many changes, backup your old version first :P

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1236 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gabest11 2009-05-22 01:22:52 +00:00
parent 8e3d3080c0
commit 3b22adc4b3
48 changed files with 3620 additions and 3541 deletions

View File

@ -31,7 +31,7 @@
#define PSE_LT_GPU 2
static HRESULT s_hr = E_FAIL;
static GPURendererBase* s_gpu = NULL;
static GPURenderer* s_gpu = NULL;
EXPORT_C_(uint32) PSEgetLibType()
{
@ -121,10 +121,10 @@ EXPORT_C_(int32) GPUopen(HWND hWnd)
switch(renderer)
{
default:
case 0: s_gpu = new GPURendererSW<GSDevice7>(rs, threads); break;
case 1: s_gpu = new GPURendererSW<GSDevice9>(rs, threads); break;
case 2: s_gpu = new GPURendererSW<GSDevice10>(rs, threads); break;
// TODO: case 3: s_gpu = new GPURendererNull<GSDeviceNull>(rs, threads); break;
case 0: s_gpu = new GPURendererSW(rs, new GSDevice7(), threads); break;
case 1: s_gpu = new GPURendererSW(rs, new GSDevice9(), threads); break;
case 2: s_gpu = new GPURendererSW(rs, new GSDevice10(), threads); break;
// TODO: case 3: s_gpu = new GPURendererNull(rs, new GSDeviceNull(), threads); break;
}
if(!s_gpu->Create(hWnd))

View File

@ -22,4 +22,81 @@
#include "StdAfx.h"
#include "GPURenderer.h"
map<HWND, GPURendererBase*> GPURendererBase::m_wnd2gpu;
map<HWND, GPURenderer*> GPURenderer::m_wnd2gpu;
GPURenderer::GPURenderer(const GPURendererSettings& rs)
: GPUState(rs.m_scale)
, m_hWnd(NULL)
, m_wndproc(NULL)
{
m_filter = rs.m_filter;
m_dither = rs.m_dither;
m_aspectratio = rs.m_aspectratio;
m_vsync = rs.m_vsync;
m_scale = m_mem.GetScale();
}
GPURenderer::~GPURenderer()
{
if(m_wndproc)
{
SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc);
m_wnd2gpu.erase(m_hWnd);
}
}
bool GPURenderer::Create(HWND hWnd)
{
m_hWnd = hWnd;
m_wndproc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc);
m_wnd2gpu[hWnd] = this;
DWORD style = GetWindowLong(hWnd, GWL_STYLE);
style |= WS_OVERLAPPEDWINDOW;
SetWindowLong(hWnd, GWL_STYLE, style);
UpdateWindow(hWnd);
ShowWindow(hWnd, SW_SHOWNORMAL);
return true;
}
LRESULT CALLBACK GPURenderer::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
map<HWND, GPURenderer*>::iterator i = m_wnd2gpu.find(hWnd);
if(i != m_wnd2gpu.end())
{
return (*i).second->OnMessage(message, wParam, lParam);
}
ASSERT(0);
return 0;
}
LRESULT GPURenderer::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_KEYUP)
{
switch(wParam)
{
case VK_DELETE:
m_filter = (m_filter + 1) % 3;
return 0;
case VK_END:
m_dither = m_dither ? 0 : 1;
return 0;
case VK_NEXT:
m_aspectratio = (m_aspectratio + 1) % 3;
return 0;
}
}
return m_wndproc(m_hWnd, message, wParam, lParam);
}

View File

@ -23,6 +23,7 @@
#include "GPUState.h"
#include "GSVertexList.h"
#include "GSDevice.h"
struct GPURendererSettings
{
@ -33,100 +34,30 @@ struct GPURendererSettings
GSVector2i m_scale;
};
class GPURendererBase : public GPUState, protected GPURendererSettings
class GPURenderer : public GPUState, protected GPURendererSettings
{
protected:
HWND m_hWnd;
WNDPROC m_wndproc;
static map<HWND, GPURendererBase*> m_wnd2gpu;
static map<HWND, GPURenderer*> m_wnd2gpu;
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
map<HWND, GPURendererBase*>::iterator i = m_wnd2gpu.find(hWnd);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
if(i != m_wnd2gpu.end())
{
return (*i).second->OnMessage(message, wParam, lParam);
}
ASSERT(0);
return 0;
}
LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_KEYUP)
{
switch(wParam)
{
case VK_DELETE:
m_filter = (m_filter + 1) % 3;
return 0;
case VK_END:
m_dither = m_dither ? 0 : 1;
return 0;
case VK_NEXT:
m_aspectratio = (m_aspectratio + 1) % 3;
return 0;
}
}
return m_wndproc(m_hWnd, message, wParam, lParam);
}
LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
public:
GPURendererBase(const GPURendererSettings& rs)
: GPUState(rs.m_scale)
, m_hWnd(NULL)
, m_wndproc(NULL)
{
m_filter = rs.m_filter;
m_dither = rs.m_dither;
m_aspectratio = rs.m_aspectratio;
m_vsync = rs.m_vsync;
m_scale = m_mem.GetScale();
}
virtual ~GPURendererBase()
{
if(m_wndproc)
{
SetWindowLongPtr(m_hWnd, GWLP_WNDPROC, (LONG_PTR)m_wndproc);
m_wnd2gpu.erase(m_hWnd);
}
}
virtual bool Create(HWND hWnd)
{
m_hWnd = hWnd;
m_wndproc = (WNDPROC)GetWindowLongPtr(hWnd, GWLP_WNDPROC);
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)WndProc);
m_wnd2gpu[hWnd] = this;
DWORD style = GetWindowLong(hWnd, GWL_STYLE);
style |= WS_OVERLAPPEDWINDOW;
SetWindowLong(hWnd, GWL_STYLE, style);
UpdateWindow(hWnd);
ShowWindow(hWnd, SW_SHOWNORMAL);
return true;
}
GPURenderer(const GPURendererSettings& rs);
virtual ~GPURenderer();
virtual bool Create(HWND hWnd);
virtual void VSync() = 0;
virtual bool MakeSnapshot(const string& path) = 0;
};
template<class Device, class Vertex>
class GPURenderer : public GPURendererBase
template<class Vertex>
class GPURendererT : public GPURenderer
{
protected:
typedef typename Device::Texture Texture;
Vertex* m_vertices;
int m_count;
int m_maxcount;
@ -191,7 +122,7 @@ protected:
m_count += count;
}
typedef void (GPURenderer<Device, Vertex>::*DrawingKickHandler)(Vertex* v, int& count);
typedef void (GPURendererT<Vertex>::*DrawingKickHandler)(Vertex* v, int& count);
DrawingKickHandler m_fpDrawingKickHandlers[4];
@ -235,46 +166,36 @@ protected:
virtual void ResetDevice() {}
virtual void Draw() = 0;
virtual bool GetOutput(Texture& t) = 0;
virtual GSTexture* GetOutput() = 0;
bool Merge()
{
Texture st[2];
GSTexture* st[2] = {GetOutput(), NULL};
if(!GetOutput(st[0]))
if(!st[0])
{
return false;
}
GSVector2i s = st[0].GetSize();
GSVector2i s = st[0]->GetSize();
GSVector4 sr[2];
sr[0].x = 0;
sr[0].y = 0;
sr[0].z = 1.0f;
sr[0].w = 1.0f;
GSVector4 dr[2];
dr[0].x = 0;
dr[0].y = 0;
dr[0].z = (float)s.x;
dr[0].w = (float)s.y;
sr[0] = GSVector4(0, 0, 1, 1);
dr[0] = GSVector4(0, 0, s.x, s.y);
GSVector4 c(0, 0, 0, 1);
m_dev.Merge(st, sr, dr, s, 1, 1, c);
m_dev->Merge(st, sr, dr, s, 1, 1, GSVector4(0, 0, 0, 1));
return true;
}
public:
Device m_dev;
GSDevice* m_dev;
public:
GPURenderer(const GPURendererSettings& rs)
: GPURendererBase(rs)
GPURendererT(const GPURendererSettings& rs)
: GPURenderer(rs)
, m_count(0)
, m_maxcount(10000)
{
@ -283,11 +204,11 @@ public:
for(int i = 0; i < countof(m_fpDrawingKickHandlers); i++)
{
m_fpDrawingKickHandlers[i] = &GPURenderer<Device, Vertex>::DrawingKickNull;
m_fpDrawingKickHandlers[i] = &GPURendererT<Vertex>::DrawingKickNull;
}
}
virtual ~GPURenderer()
virtual ~GPURendererT()
{
if(m_vertices) _aligned_free(m_vertices);
}
@ -299,7 +220,7 @@ public:
return false;
}
if(!m_dev.Create(hWnd, m_vsync))
if(!m_dev->Create(hWnd, m_vsync))
{
return false;
}
@ -313,21 +234,15 @@ public:
{
GSPerfMonAutoTimer pmat(m_perfmon);
m_perfmon.Put(GSPerfMon::Frame);
// m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ?
if(!IsWindow(m_hWnd))
{
return;
}
if(!IsWindow(m_hWnd)) return;
Flush();
m_perfmon.Put(GSPerfMon::Frame);
if(!Merge())
{
return;
}
if(!Merge()) return;
// osd
@ -367,7 +282,7 @@ public:
SetWindowText(m_hWnd, s_stats.c_str());
}
if(m_dev.IsLost())
if(m_dev->IsLost())
{
ResetDevice();
}
@ -376,7 +291,7 @@ public:
GetClientRect(m_hWnd, r);
m_dev.Present(r.fit(m_aspectratio));
m_dev->Present(r.fit(m_aspectratio));
}
virtual bool MakeSnapshot(const string& path)
@ -390,6 +305,11 @@ public:
return false;
}
return m_dev.SaveCurrent(format("%s_%s.bmp", path.c_str(), buff));
if(GSTexture* t = m_dev->GetCurrent())
{
return t->Save(format("%s_%s.bmp", path.c_str(), buff));
}
return false;
}
};

View File

@ -21,3 +21,210 @@
#include "StdAfx.h"
#include "GPURendererSW.h"
GPURendererSW::GPURendererSW(const GPURendererSettings& rs, GSDevice* dev, int threads)
: GPURendererT(rs)
, m_texture(NULL)
{
m_dev = dev;
m_rl.Create<GPUDrawScanline>(this, threads);
m_fpDrawingKickHandlers[GPU_POLYGON] = (DrawingKickHandler)&GPURendererSW::DrawingKickTriangle;
m_fpDrawingKickHandlers[GPU_LINE] = (DrawingKickHandler)&GPURendererSW::DrawingKickLine;
m_fpDrawingKickHandlers[GPU_SPRITE] = (DrawingKickHandler)&GPURendererSW::DrawingKickSprite;
}
GPURendererSW::~GPURendererSW()
{
}
void GPURendererSW::ResetDevice()
{
delete m_texture;
m_texture = NULL;
}
GSVector4i GPURendererSW::GetScissor()
{
GSVector4i r;
r.left = (int)m_env.DRAREATL.X << m_scale.x;
r.top = (int)m_env.DRAREATL.Y << m_scale.y;
r.right = min((int)(m_env.DRAREABR.X + 1) << m_scale.x, m_mem.GetWidth());
r.bottom = min((int)(m_env.DRAREABR.Y + 1) << m_scale.y, m_mem.GetHeight());
return r;
}
void GPURendererSW::VertexKick()
{
GSVertexSW& v = m_vl.AddTail();
// TODO: x/y + off.x/y should wrap around at +/-1024
int x = (int)(m_v.XY.X + m_env.DROFF.X) << m_scale.x;
int y = (int)(m_v.XY.Y + m_env.DROFF.Y) << m_scale.y;
int s = m_v.UV.X;
int t = m_v.UV.Y;
GSVector4 pt(x, y, s, t);
v.p = pt.xyxy(GSVector4::zero());
v.t = (pt.zwzw(GSVector4::zero()) + GSVector4(0.125f)) * 256.0f;
v.c = GSVector4(m_v.RGB.u32) * 128.0f;
__super::VertexKick();
}
void GPURendererSW::DrawingKickTriangle(GSVertexSW* v, int& count)
{
// TODO
}
void GPURendererSW::DrawingKickLine(GSVertexSW* v, int& count)
{
// TODO
}
void GPURendererSW::DrawingKickSprite(GSVertexSW* v, int& count)
{
// TODO
}
void GPURendererSW::Draw()
{
const GPUDrawingEnvironment& env = m_env;
//
GPUScanlineParam p;
p.sel.key = 0;
p.sel.iip = env.PRIM.IIP;
p.sel.me = env.STATUS.ME;
if(env.PRIM.ABE)
{
p.sel.abe = env.PRIM.ABE;
p.sel.abr = env.STATUS.ABR;
}
p.sel.tge = env.PRIM.TGE;
if(env.PRIM.TME)
{
p.sel.tme = env.PRIM.TME;
p.sel.tlu = env.STATUS.TP < 2;
p.sel.twin = (env.TWIN.u32 & 0xfffff) != 0;
p.sel.ltf = m_filter == 1 && env.PRIM.TYPE == GPU_POLYGON || m_filter == 2 ? 1 : 0;
const void* t = m_mem.GetTexture(env.STATUS.TP, env.STATUS.TX, env.STATUS.TY);
if(!t) {ASSERT(0); return;}
p.tex = t;
p.clut = m_mem.GetCLUT(env.STATUS.TP, env.CLUT.X, env.CLUT.Y);
}
p.sel.dtd = m_dither ? env.STATUS.DTD : 0;
p.sel.md = env.STATUS.MD;
p.sel.sprite = env.PRIM.TYPE == GPU_SPRITE;
p.sel.scalex = m_mem.GetScale().x;
//
GSRasterizerData data;
data.scissor = GetScissor();
data.vertices = m_vertices;
data.count = m_count;
data.param = &p;
switch(env.PRIM.TYPE)
{
case GPU_POLYGON: data.primclass = GS_TRIANGLE_CLASS; break;
case GPU_LINE: data.primclass = GS_LINE_CLASS; break;
case GPU_SPRITE: data.primclass = GS_SPRITE_CLASS; break;
default: __assume(0);
}
m_rl.Draw(&data);
GSRasterizerStats stats;
m_rl.GetStats(stats);
m_perfmon.Put(GSPerfMon::Draw, 1);
m_perfmon.Put(GSPerfMon::Prim, stats.prims);
m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels);
// TODO
{
GSVector4 tl(+1e10f);
GSVector4 br(-1e10f);
for(int i = 0, j = m_count; i < j; i++)
{
GSVector4 p = m_vertices[i].p;
tl = tl.minv(p);
br = br.maxv(p);
}
GSVector4i r = GSVector4i(tl.xyxy(br)).rintersect(data.scissor);
r.left >>= m_scale.x;
r.top >>= m_scale.y;
r.right >>= m_scale.x;
r.bottom >>= m_scale.y;
Invalidate(r);
}
}
GSTexture* GPURendererSW::GetOutput()
{
GSVector4i r = m_env.GetDisplayRect();
r.left <<= m_scale.x;
r.top <<= m_scale.y;
r.right <<= m_scale.x;
r.bottom <<= m_scale.y;
// TODO
static uint32* buff = (uint32*)_aligned_malloc(m_mem.GetWidth() * m_mem.GetHeight() * sizeof(uint32), 16);
m_mem.ReadFrame32(r, buff, !!m_env.STATUS.ISRGB24);
int w = r.width();
int h = r.height();
if(m_texture)
{
if(m_texture->GetWidth() != w || m_texture->GetHeight() != h)
{
delete m_texture;
m_texture = NULL;
}
}
if(!m_texture)
{
m_texture = m_dev->CreateTexture(w, h);
if(!m_texture)
{
return NULL;
}
}
m_texture->Update(GSVector4i(0, 0, w, h), buff, m_mem.GetWidth() * sizeof(uint32));
return m_texture;
}

View File

@ -24,204 +24,26 @@
#include "GPURenderer.h"
#include "GPUDrawScanline.h"
template <class Device>
class GPURendererSW : public GPURenderer<Device, GSVertexSW>
class GPURendererSW : public GPURendererT<GSVertexSW>
{
protected:
GSRasterizerList m_rl;
Texture m_texture;
GSTexture* m_texture;
void ResetDevice()
{
m_texture = Texture();
}
void ResetDevice();
bool GetOutput(Texture& t)
{
GSVector4i r = m_env.GetDisplayRect();
GSVector4i GetScissor();
r.left <<= m_scale.x;
r.top <<= m_scale.y;
r.right <<= m_scale.x;
r.bottom <<= m_scale.y;
void VertexKick();
void DrawingKickTriangle(GSVertexSW* v, int& count);
void DrawingKickLine(GSVertexSW* v, int& count);
void DrawingKickSprite(GSVertexSW* v, int& count);
// TODO
static uint32* buff = (uint32*)_aligned_malloc(m_mem.GetWidth() * m_mem.GetHeight() * sizeof(uint32), 16);
void Draw();
m_mem.ReadFrame32(r, buff, !!m_env.STATUS.ISRGB24);
int w = r.width();
int h = r.height();
if(m_texture.GetWidth() != w || m_texture.GetHeight() != h)
{
m_texture = Texture();
}
if(!m_texture && !m_dev.CreateTexture(m_texture, w, h))
{
return false;
}
m_texture.Update(GSVector4i(0, 0, w, h), buff, m_mem.GetWidth() * sizeof(uint32));
t = m_texture;
return true;
}
void VertexKick()
{
GSVertexSW& v = m_vl.AddTail();
// TODO: x/y + off.x/y should wrap around at +/-1024
int x = (int)(m_v.XY.X + m_env.DROFF.X) << m_scale.x;
int y = (int)(m_v.XY.Y + m_env.DROFF.Y) << m_scale.y;
int s = m_v.UV.X;
int t = m_v.UV.Y;
GSVector4 pt(x, y, s, t);
v.p = pt.xyxy(GSVector4::zero());
v.t = (pt.zwzw(GSVector4::zero()) + GSVector4(0.125f)) * 256.0f;
v.c = GSVector4(m_v.RGB.u32) * 128.0f;
__super::VertexKick();
}
void DrawingKickTriangle(GSVertexSW* v, int& count)
{
// TODO
}
void DrawingKickLine(GSVertexSW* v, int& count)
{
// TODO
}
void DrawingKickSprite(GSVertexSW* v, int& count)
{
// TODO
}
GSVector4i GetScissor()
{
GSVector4i r;
r.left = (int)m_env.DRAREATL.X << m_scale.x;
r.top = (int)m_env.DRAREATL.Y << m_scale.y;
r.right = min((int)(m_env.DRAREABR.X + 1) << m_scale.x, m_mem.GetWidth());
r.bottom = min((int)(m_env.DRAREABR.Y + 1) << m_scale.y, m_mem.GetHeight());
return r;
}
void Draw()
{
const GPUDrawingEnvironment& env = m_env;
//
GPUScanlineParam p;
p.sel.key = 0;
p.sel.iip = env.PRIM.IIP;
p.sel.me = env.STATUS.ME;
if(env.PRIM.ABE)
{
p.sel.abe = env.PRIM.ABE;
p.sel.abr = env.STATUS.ABR;
}
p.sel.tge = env.PRIM.TGE;
if(env.PRIM.TME)
{
p.sel.tme = env.PRIM.TME;
p.sel.tlu = env.STATUS.TP < 2;
p.sel.twin = (env.TWIN.u32 & 0xfffff) != 0;
p.sel.ltf = m_filter == 1 && env.PRIM.TYPE == GPU_POLYGON || m_filter == 2 ? 1 : 0;
const void* t = m_mem.GetTexture(env.STATUS.TP, env.STATUS.TX, env.STATUS.TY);
if(!t) {ASSERT(0); return;}
p.tex = t;
p.clut = m_mem.GetCLUT(env.STATUS.TP, env.CLUT.X, env.CLUT.Y);
}
p.sel.dtd = m_dither ? env.STATUS.DTD : 0;
p.sel.md = env.STATUS.MD;
p.sel.sprite = env.PRIM.TYPE == GPU_SPRITE;
p.sel.scalex = m_mem.GetScale().x;
//
GSRasterizerData data;
data.scissor = GetScissor();
data.vertices = m_vertices;
data.count = m_count;
data.param = &p;
switch(env.PRIM.TYPE)
{
case GPU_POLYGON: data.primclass = GS_TRIANGLE_CLASS; break;
case GPU_LINE: data.primclass = GS_LINE_CLASS; break;
case GPU_SPRITE: data.primclass = GS_SPRITE_CLASS; break;
default: __assume(0);
}
m_rl.Draw(&data);
GSRasterizerStats stats;
m_rl.GetStats(stats);
m_perfmon.Put(GSPerfMon::Draw, 1);
m_perfmon.Put(GSPerfMon::Prim, stats.prims);
m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels);
// TODO
{
GSVector4 tl(+1e10f);
GSVector4 br(-1e10f);
for(int i = 0, j = m_count; i < j; i++)
{
GSVector4 p = m_vertices[i].p;
tl = tl.minv(p);
br = br.maxv(p);
}
GSVector4i r = GSVector4i(tl.xyxy(br)).rintersect(data.scissor);
r.left >>= m_scale.x;
r.top >>= m_scale.y;
r.right >>= m_scale.x;
r.bottom >>= m_scale.y;
Invalidate(r);
}
}
GSTexture* GetOutput();
public:
GPURendererSW(const GPURendererSettings& rs, int threads)
: GPURenderer(rs)
{
m_rl.Create<GPUDrawScanline>(this, threads);
m_fpDrawingKickHandlers[GPU_POLYGON] = (DrawingKickHandler)&GPURendererSW::DrawingKickTriangle;
m_fpDrawingKickHandlers[GPU_LINE] = (DrawingKickHandler)&GPURendererSW::DrawingKickLine;
m_fpDrawingKickHandlers[GPU_SPRITE] = (DrawingKickHandler)&GPURendererSW::DrawingKickSprite;
}
virtual ~GPURendererSW()
{
}
GPURendererSW(const GPURendererSettings& rs, GSDevice* dev, int threads);
virtual ~GPURendererSW();
};

View File

@ -38,8 +38,6 @@ GPUSetupPrimCodeGenerator::GPUSetupPrimCodeGenerator(GPUScanlineEnvironment& env
void GPUSetupPrimCodeGenerator::Generate()
{
const int params = 0;
if(m_env.sel.tme && !m_env.sel.twin)
{
pcmpeqd(xmm0, xmm0);

View File

@ -33,7 +33,7 @@
#define PS2E_X86_64 0x02 // 64 bit
static HRESULT s_hr = E_FAIL;
static GSRendererBase* s_gs = NULL;
static GSRenderer* s_gs = NULL;
static void (*s_irq)() = NULL;
static uint8* s_basemem = NULL;
@ -134,13 +134,13 @@ static INT32 GSopen(void* dsp, char* title, int mt, int renderer)
{
default:
case 0: s_gs = new GSRendererHW9(s_basemem, !!mt, s_irq, rs); break;
case 1: s_gs = new GSRendererSW<GSDevice9>(s_basemem, !!mt, s_irq, rs, threads); break;
case 2: s_gs = new GSRendererNull<GSDevice9>(s_basemem, !!mt, s_irq, rs); break;
case 1: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, rs, new GSDevice9(), threads); break;
case 2: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, rs, new GSDevice9()); break;
case 3: s_gs = new GSRendererHW10(s_basemem, !!mt, s_irq, rs); break;
case 4: s_gs = new GSRendererSW<GSDevice10>(s_basemem, !!mt, s_irq, rs, threads); break;
case 5: s_gs = new GSRendererNull<GSDevice10>(s_basemem, !!mt, s_irq, rs); break;
case 6: s_gs = new GSRendererSW<GSDeviceNull>(s_basemem, !!mt, s_irq, rs, threads); break;
case 7: s_gs = new GSRendererNull<GSDeviceNull>(s_basemem, !!mt, s_irq, rs); break;
case 4: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, rs, new GSDevice10(), threads); break;
case 5: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, rs, new GSDevice10()); break;
case 6: s_gs = new GSRendererSW(s_basemem, !!mt, s_irq, rs, new GSDeviceNull(), threads); break;
case 7: s_gs = new GSRendererNull(s_basemem, !!mt, s_irq, rs, new GSDeviceNull()); break;
}
if(!s_gs->Create(title))

View File

@ -440,18 +440,22 @@ REG64_(GSReg, SMODE2)
REG_END
REG64_(GSReg, SRFSH)
uint32 _DUMMY;
// TODO
REG_END
REG64_(GSReg, SYNCH1)
uint32 _DUMMY;
// TODO
REG_END
REG64_(GSReg, SYNCH2)
uint32 _DUMMY;
// TODO
REG_END
REG64_(GSReg, SYNCV)
uint64 _DUMMY;
// TODO
REG_END

View File

@ -126,6 +126,8 @@ void GSClut::Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
void GSClut::WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
ALIGN_STACK(16);
ASSERT(TEX0.CSA == 0);
WriteCLUT_T32_I8_CSM1((uint32*)m_mem->BlockPtr32(0, 0, TEX0.CBP, 1), m_clut + (TEX0.CSA << 4));
@ -133,9 +135,9 @@ void GSClut::WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TE
void GSClut::WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
ASSERT(TEX0.CSA < 16);
ALIGN_STACK(16);
GSVector4i dummy; // this just forces stack alignment and enables inlining the next call
ASSERT(TEX0.CSA < 16);
WriteCLUT_T32_I4_CSM1((uint32*)m_mem->BlockPtr32(0, 0, TEX0.CBP, 1), m_clut + (TEX0.CSA << 4));
}

View File

@ -21,3 +21,195 @@
#include "StdAfx.h"
#include "GSDevice.h"
GSDevice::GSDevice()
: m_hWnd(NULL)
, m_backbuffer(NULL)
, m_merge(NULL)
, m_weavebob(NULL)
, m_blend(NULL)
, m_1x1(NULL)
{
}
GSDevice::~GSDevice()
{
}
bool GSDevice::Create(HWND hWnd, bool vsync)
{
m_hWnd = hWnd;
m_vsync = vsync;
return true;
}
bool GSDevice::Reset(int w, int h, bool fs)
{
for(list<GSTexture*>::iterator i = m_pool.begin(); i != m_pool.end(); i++)
{
delete *i;
}
m_pool.clear();
delete m_backbuffer;
delete m_merge;
delete m_weavebob;
delete m_blend;
delete m_1x1;
m_backbuffer = NULL;
m_merge = NULL;
m_weavebob = NULL;
m_blend = NULL;
m_1x1 = NULL;
m_current = NULL; // current is special, points to other textures, no need to delete
return true;
}
void GSDevice::Present(const GSVector4i& r)
{
GSVector4i cr;
GetClientRect(m_hWnd, cr);
if(m_backbuffer->GetWidth() != cr.width() || m_backbuffer->GetHeight() != cr.height())
{
Reset(cr.width(), cr.height(), false);
}
ClearRenderTarget(m_backbuffer, 0);
if(m_current)
{
StretchRect(m_current, m_backbuffer, GSVector4(r));
}
Flip();
}
GSTexture* GSDevice::Fetch(int type, int w, int h, int format)
{
GSVector2i size(w, h);
for(list<GSTexture*>::iterator i = m_pool.begin(); i != m_pool.end(); i++)
{
GSTexture* t = *i;
if(t->GetType() == type && t->GetFormat() == format && t->GetSize() == size)
{
m_pool.erase(i);
return t;
}
}
return Create(type, w, h, format);
}
void GSDevice::Recycle(GSTexture* t)
{
if(t)
{
m_pool.push_front(t);
while(m_pool.size() > 200)
{
delete m_pool.back();
m_pool.pop_back();
}
}
}
GSTexture* GSDevice::CreateRenderTarget(int w, int h, int format)
{
return Fetch(GSTexture::RenderTarget, w, h, format);
}
GSTexture* GSDevice::CreateDepthStencil(int w, int h, int format)
{
return Fetch(GSTexture::DepthStencil, w, h, format);
}
GSTexture* GSDevice::CreateTexture(int w, int h, int format)
{
return Fetch(GSTexture::Texture, w, h, format);
}
GSTexture* GSDevice::CreateOffscreen(int w, int h, int format)
{
return Fetch(GSTexture::Offscreen, w, h, format);
}
void GSDevice::StretchRect(GSTexture* st, GSTexture* dt, const GSVector4& dr, bool linear)
{
StretchRect(st, GSVector4(0, 0, 1, 1), dt, dr, linear);
}
GSTexture* GSDevice::GetCurrent()
{
return m_current;
}
void GSDevice::Merge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, const GSVector2i& fs, bool slbg, bool mmod, const GSVector4& c)
{
if(!m_merge || !(m_merge->GetSize() == fs))
{
m_merge = CreateRenderTarget(fs.x, fs.y);
}
// TODO: m_1x1
DoMerge(st, sr, dr, m_merge, slbg, mmod, c);
m_current = m_merge;
}
bool GSDevice::Interlace(const GSVector2i& ds, int field, int mode, float yoffset)
{
if(!m_weavebob || !(m_weavebob->GetSize() == ds))
{
m_weavebob = CreateRenderTarget(ds.x, ds.y);
}
if(mode == 0 || mode == 2) // weave or blend
{
// weave first
DoInterlace(m_merge, m_weavebob, field, false, 0);
if(mode == 2)
{
// blend
if(!m_blend || !(m_blend->GetSize() == ds))
{
m_blend = CreateRenderTarget(ds.x, ds.y);
}
DoInterlace(m_weavebob, m_blend, 2, false, 0);
m_current = m_blend;
}
else
{
m_current = m_weavebob;
}
}
else if(mode == 1) // bob
{
DoInterlace(m_merge, m_weavebob, 3, true, yoffset * field);
m_current = m_weavebob;
}
else
{
m_current = m_merge;
}
return true;
}

View File

@ -23,6 +23,7 @@
#include "GSTexture.h"
#include "GSVertex.h"
#include "GSAlignedClass.h"
#pragma pack(push, 1)
@ -44,201 +45,64 @@ struct InterlaceConstantBuffer
#pragma pack(pop)
template<class Texture> class GSDevice
class GSDevice : public GSAlignedClass<16>
{
list<Texture> m_pool;
list<GSTexture*> m_pool;
GSTexture* Fetch(int type, int w, int h, int format);
protected:
HWND m_hWnd;
bool m_vsync;
Texture m_backbuffer;
Texture m_merge;
Texture m_weavebob;
Texture m_blend;
Texture m_1x1;
Texture m_current;
GSTexture* m_backbuffer;
GSTexture* m_merge;
GSTexture* m_weavebob;
GSTexture* m_blend;
GSTexture* m_1x1;
GSTexture* m_current;
bool Fetch(int type, Texture& t, int w, int h, int format)
{
Recycle(t);
virtual GSTexture* Create(int type, int w, int h, int format) = 0;
for(list<Texture>::iterator i = m_pool.begin(); i != m_pool.end(); i++)
{
const Texture& t2 = *i;
if(t2.GetType() == type && t2.GetWidth() == w && t2.GetHeight() == h && t2.GetFormat() == format)
{
t = t2;
m_pool.erase(i);
return true;
}
}
return Create(type, t, w, h, format);
}
virtual bool Create(int type, Texture& t, int w, int h, int format) = 0;
virtual void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) = 0;
virtual void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset) = 0;
virtual void DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c) = 0;
virtual void DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset) = 0;
public:
GSDevice() : m_hWnd(NULL)
{
}
GSDevice();
virtual ~GSDevice();
virtual ~GSDevice()
{
}
void Recycle(GSTexture* t);
virtual bool Create(HWND hWnd, bool vsync)
{
m_hWnd = hWnd;
m_vsync = vsync;
virtual bool Create(HWND hWnd, bool vsync);
virtual bool Reset(int w, int h, bool fs);
return true;
}
virtual bool Reset(int w, int h, bool fs)
{
m_pool.clear();
m_backbuffer = Texture();
m_merge = Texture();
m_weavebob = Texture();
m_blend = Texture();
m_1x1 = Texture();
m_current = Texture();
virtual bool IsLost() {return false;}
virtual void Present(const GSVector4i& r);
virtual void Flip() {};
return true;
}
virtual void BeginScene() {};
virtual void EndScene() {};
virtual bool IsLost() = 0;
virtual void ClearRenderTarget(GSTexture* t, const GSVector4& c) {};
virtual void ClearRenderTarget(GSTexture* t, uint32 c) {};
virtual void ClearDepth(GSTexture* t, float c) {};
virtual void ClearStencil(GSTexture* t, uint8 c) {};
virtual void Present(const GSVector4i& r) = 0;
virtual GSTexture* CreateRenderTarget(int w, int h, int format = 0);
virtual GSTexture* CreateDepthStencil(int w, int h, int format = 0);
virtual GSTexture* CreateTexture(int w, int h, int format = 0);
virtual GSTexture* CreateOffscreen(int w, int h, int format = 0);
virtual void BeginScene() = 0;
virtual GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format = 0) {return NULL;}
virtual void EndScene() = 0;
virtual void StretchRect(GSTexture* st, GSTexture* dt, const GSVector4& dr, bool linear = true);
virtual void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, bool linear = true) {}
virtual void Draw(const string& s) = 0;
GSTexture* GetCurrent();
virtual bool IsCurrentRGBA() {return true;}
virtual bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) = 0;
void Merge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, const GSVector2i& fs, bool slbg, bool mmod, const GSVector4& c);
bool Interlace(const GSVector2i& ds, int field, int mode, float yoffset);
virtual void ClearRenderTarget(Texture& t, const GSVector4& c) = 0;
virtual void ClearRenderTarget(Texture& t, uint32 c) = 0;
virtual void ClearDepth(Texture& t, float c) = 0;
virtual void ClearStencil(Texture& t, uint8 c) = 0;
virtual bool CreateRenderTarget(Texture& t, int w, int h, int format = 0)
{
return Fetch(GSTexture::RenderTarget, t, w, h, format);
}
virtual bool CreateDepthStencil(Texture& t, int w, int h, int format = 0)
{
return Fetch(GSTexture::DepthStencil, t, w, h, format);
}
virtual bool CreateTexture(Texture& t, int w, int h, int format = 0)
{
return Fetch(GSTexture::Texture, t, w, h, format);
}
virtual bool CreateOffscreen(Texture& t, int w, int h, int format = 0)
{
return Fetch(GSTexture::Offscreen, t, w, h, format);
}
void Recycle(Texture& t)
{
if(t)
{
m_pool.push_front(t);
while(m_pool.size() > 200)
{
m_pool.pop_back();
}
t = Texture();
}
}
bool SaveCurrent(const string& fn)
{
return m_current.Save(fn);
}
void GetCurrent(Texture& t)
{
t = m_current;
}
void Merge(Texture* st, GSVector4* sr, GSVector4* dr, const GSVector2i& fs, bool slbg, bool mmod, GSVector4& c)
{
if(!m_merge || m_merge.GetWidth() != fs.x || m_merge.GetHeight() != fs.y)
{
CreateRenderTarget(m_merge, fs.x, fs.y);
}
// TODO: m_1x1
DoMerge(st, sr, dr, m_merge, slbg, mmod, c);
m_current = m_merge;
}
bool Interlace(const GSVector2i& ds, int field, int mode, float yoffset)
{
if(!m_weavebob || m_weavebob.GetWidth() != ds.x || m_weavebob.GetHeight() != ds.y)
{
CreateRenderTarget(m_weavebob, ds.x, ds.y);
}
if(mode == 0 || mode == 2) // weave or blend
{
// weave first
DoInterlace(m_merge, m_weavebob, field, false, 0);
if(mode == 2)
{
// blend
if(!m_blend || m_blend.GetWidth() != ds.x || m_blend.GetHeight() != ds.y)
{
CreateRenderTarget(m_blend, ds.x, ds.y);
}
DoInterlace(m_weavebob, m_blend, 2, false, 0);
m_current = m_blend;
}
else
{
m_current = m_weavebob;
}
}
else if(mode == 1) // bob
{
DoInterlace(m_merge, m_weavebob, 3, true, yoffset * field);
m_current = m_weavebob;
}
else
{
m_current = m_merge;
}
return true;
}
virtual bool IsCurrentRGBA()
{
return true;
}
virtual void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1) {}
virtual void OMSetRenderTargets(GSTexture* rt, GSTexture* ds) {};
};

View File

@ -251,31 +251,13 @@ bool GSDevice10::Reset(int w, int h, bool fs)
CComPtr<ID3D10Texture2D> backbuffer;
m_swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)&backbuffer);
m_backbuffer = Texture(backbuffer);
m_backbuffer = new GSTexture10(backbuffer);
return true;
}
void GSDevice10::Present(const GSVector4i& r)
void GSDevice10::Flip()
{
GSVector4i cr;
GetClientRect(m_hWnd, cr);
if(m_backbuffer.GetWidth() != cr.width() || m_backbuffer.GetHeight() != cr.height())
{
Reset(cr.width(), cr.height(), false);
}
float color[4] = {0, 0, 0, 0};
m_dev->ClearRenderTargetView(m_backbuffer, color);
if(m_current)
{
StretchRect(m_current, m_backbuffer, GSVector4(r));
}
m_swapchain->Present(m_vsync ? 1 : 0, 0);
}
@ -292,92 +274,29 @@ void GSDevice10::EndScene()
// OMSetRenderTargets(NULL, NULL);
}
void GSDevice10::Draw(const string& s)
void GSDevice10::ClearRenderTarget(GSTexture* t, const GSVector4& c)
{
/*
BOOL fs;
CComPtr<IDXGIOutput> target;
m_swapchain->GetFullscreenState(&fs, &target);
if(fs)
{
BeginScene();
OMSetRenderTargets(m_backbuffer, NULL);
GSVector4i r(0, 0, m_backbuffer.GetWidth(), m_backbuffer.GetHeight());
D3DCOLOR c = D3DCOLOR_ARGB(255, 0, 255, 0);
if(m_font->DrawText(NULL, str, -1, r, DT_CALCRECT|DT_LEFT|DT_WORDBREAK, c))
{
m_font->DrawText(NULL, str, -1, r, DT_LEFT|DT_WORDBREAK, c);
}
EndScene();
}
*/
m_dev->ClearRenderTargetView(*(GSTexture10*)t, c.v);
}
bool GSDevice10::CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format)
{
dst = Texture();
if(format == 0)
{
format = DXGI_FORMAT_R8G8B8A8_UNORM;
}
if(format != DXGI_FORMAT_R8G8B8A8_UNORM && format != DXGI_FORMAT_R16_UINT)
{
ASSERT(0);
return false;
}
Texture rt;
if(CreateRenderTarget(rt, w, h, format))
{
GSVector4 dr(0, 0, w, h);
StretchRect(src, sr, rt, dr, m_convert.ps[format == DXGI_FORMAT_R16_UINT ? 1 : 0], NULL);
if(CreateOffscreen(dst, w, h, format))
{
m_dev->CopyResource(dst, rt);
}
}
Recycle(rt);
return !!dst;
}
void GSDevice10::ClearRenderTarget(Texture& t, const GSVector4& c)
{
m_dev->ClearRenderTargetView(t, c.v);
}
void GSDevice10::ClearRenderTarget(Texture& t, uint32 c)
void GSDevice10::ClearRenderTarget(GSTexture* t, uint32 c)
{
GSVector4 color = GSVector4(c) * (1.0f / 255);
m_dev->ClearRenderTargetView(t, color.v);
m_dev->ClearRenderTargetView(*(GSTexture10*)t, color.v);
}
void GSDevice10::ClearDepth(Texture& t, float c)
void GSDevice10::ClearDepth(GSTexture* t, float c)
{
m_dev->ClearDepthStencilView(t, D3D10_CLEAR_DEPTH, c, 0);
m_dev->ClearDepthStencilView(*(GSTexture10*)t, D3D10_CLEAR_DEPTH, c, 0);
}
void GSDevice10::ClearStencil(Texture& t, uint8 c)
void GSDevice10::ClearStencil(GSTexture* t, uint8 c)
{
m_dev->ClearDepthStencilView(t, D3D10_CLEAR_STENCIL, 0, c);
m_dev->ClearDepthStencilView(*(GSTexture10*)t, D3D10_CLEAR_STENCIL, 0, c);
}
bool GSDevice10::Create(int type, Texture& t, int w, int h, int format)
GSTexture* GSDevice10::Create(int type, int w, int h, int format)
{
HRESULT hr;
@ -411,13 +330,15 @@ bool GSDevice10::Create(int type, Texture& t, int w, int h, int format)
break;
}
GSTexture10* t = NULL;
CComPtr<ID3D10Texture2D> texture;
hr = m_dev->CreateTexture2D(&desc, NULL, &texture);
if(SUCCEEDED(hr))
{
t = Texture(texture);
t = new GSTexture10(texture);
switch(type)
{
@ -428,34 +349,139 @@ bool GSDevice10::Create(int type, Texture& t, int w, int h, int format)
ClearDepth(t, 0);
break;
}
return true;
}
return false;
return t;
}
bool GSDevice10::CreateRenderTarget(Texture& t, int w, int h, int format)
GSTexture* GSDevice10::CreateRenderTarget(int w, int h, int format)
{
return __super::CreateRenderTarget(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
return __super::CreateRenderTarget(w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
}
bool GSDevice10::CreateDepthStencil(Texture& t, int w, int h, int format)
GSTexture* GSDevice10::CreateDepthStencil(int w, int h, int format)
{
return __super::CreateDepthStencil(t, w, h, format ? format : DXGI_FORMAT_D32_FLOAT_S8X24_UINT);
return __super::CreateDepthStencil(w, h, format ? format : DXGI_FORMAT_D32_FLOAT_S8X24_UINT);
}
bool GSDevice10::CreateTexture(Texture& t, int w, int h, int format)
GSTexture* GSDevice10::CreateTexture(int w, int h, int format)
{
return __super::CreateTexture(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
return __super::CreateTexture(w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
}
bool GSDevice10::CreateOffscreen(Texture& t, int w, int h, int format)
GSTexture* GSDevice10::CreateOffscreen(int w, int h, int format)
{
return __super::CreateOffscreen(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
return __super::CreateOffscreen(w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
}
void GSDevice10::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c)
GSTexture* GSDevice10::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format)
{
GSTexture* dst = NULL;
if(format == 0)
{
format = DXGI_FORMAT_R8G8B8A8_UNORM;
}
if(format != DXGI_FORMAT_R8G8B8A8_UNORM && format != DXGI_FORMAT_R16_UINT)
{
ASSERT(0);
return false;
}
if(GSTexture* rt = CreateRenderTarget(w, h, format))
{
GSVector4 dr(0, 0, w, h);
StretchRect(src, sr, rt, dr, m_convert.ps[format == DXGI_FORMAT_R16_UINT ? 1 : 0], NULL);
dst = CreateOffscreen(w, h, format);
if(dst)
{
m_dev->CopyResource(*(GSTexture10*)dst, *(GSTexture10*)rt);
}
Recycle(rt);
}
return dst;
}
void GSDevice10::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, bool linear)
{
StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, linear);
}
void GSDevice10::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear)
{
StretchRect(st, sr, dt, dr, ps, ps_cb, m_convert.bs, linear);
}
void GSDevice10::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear)
{
BeginScene();
GSVector2i ds = dt->GetSize();
// om
OMSetDepthStencilState(m_convert.dss, 0);
OMSetBlendState(bs, 0);
OMSetRenderTargets(dt, NULL);
// ia
float left = dr.x * 2 / ds.x - 1.0f;
float top = 1.0f - dr.y * 2 / ds.y;
float right = dr.z * 2 / ds.x - 1.0f;
float bottom = 1.0f - dr.w * 2 / ds.y;
GSVertexPT1 vertices[] =
{
{GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)},
{GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)},
{GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)},
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)},
};
D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1};
m_dev->UpdateSubresource(m_convert.vb, 0, &box, vertices, 0, 0);
IASetVertexBuffer(m_convert.vb, sizeof(vertices[0]));
IASetInputLayout(m_convert.il);
IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
// vs
VSSetShader(m_convert.vs, NULL);
// gs
GSSetShader(NULL);
// ps
PSSetShader(ps, ps_cb);
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, NULL);
PSSetShaderResources(st, NULL);
// rs
RSSet(ds.x, ds.y);
//
DrawPrimitive(countof(vertices));
//
EndScene();
}
void GSDevice10::DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c)
{
ClearRenderTarget(dt, c);
@ -472,15 +498,17 @@ void GSDevice10::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt,
}
}
void GSDevice10::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset)
void GSDevice10::DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset)
{
GSVector4 s = GSVector4(dt->GetSize());
GSVector4 sr(0, 0, 1, 1);
GSVector4 dr(0.0f, yoffset, (float)dt.GetWidth(), (float)dt.GetHeight() + yoffset);
GSVector4 dr(0.0f, yoffset, s.x, s.y + yoffset);
InterlaceConstantBuffer cb;
cb.ZrH = GSVector2(0, 1.0f / dt.GetHeight());
cb.hH = (float)dt.GetHeight() / 2;
cb.ZrH = GSVector2(0, 1.0f / s.y);
cb.hH = s.y / 2;
m_dev->UpdateSubresource(m_interlace.cb, 0, NULL, &cb, 0, 0);
@ -547,8 +575,14 @@ void GSDevice10::GSSetShader(ID3D10GeometryShader* gs)
}
}
void GSDevice10::PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1)
void GSDevice10::PSSetShaderResources(GSTexture* sr0, GSTexture* sr1)
{
ID3D10ShaderResourceView* srv0 = NULL;
ID3D10ShaderResourceView* srv1 = NULL;
if(sr0) srv0 = *(GSTexture10*)sr0;
if(sr1) srv1 = *(GSTexture10*)sr1;
if(m_ps_srv[0] != srv0 || m_ps_srv[1] != srv1)
{
ID3D10ShaderResourceView* srvs[] = {srv0, srv1};
@ -644,8 +678,14 @@ void GSDevice10::OMSetBlendState(ID3D10BlendState* bs, float bf)
}
}
void GSDevice10::OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv)
void GSDevice10::OMSetRenderTargets(GSTexture* rt, GSTexture* ds)
{
ID3D10RenderTargetView* rtv = NULL;
ID3D10DepthStencilView* dsv = NULL;
if(rt) rtv = *(GSTexture10*)rt;
if(ds) dsv = *(GSTexture10*)ds;
if(m_rtv != rtv || m_dsv != dsv)
{
m_dev->OMSetRenderTargets(1, &rtv, dsv);
@ -660,81 +700,6 @@ void GSDevice10::DrawPrimitive(uint32 count, uint32 start)
m_dev->Draw(count, start);
}
void GSDevice10::StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear)
{
StretchRect(st, GSVector4(0, 0, 1, 1), dt, dr, linear);
}
void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear)
{
StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, linear);
}
void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear)
{
StretchRect(st, sr, dt, dr, ps, ps_cb, m_convert.bs, linear);
}
void GSDevice10::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear)
{
BeginScene();
// om
OMSetDepthStencilState(m_convert.dss, 0);
OMSetBlendState(bs, 0);
OMSetRenderTargets(dt, NULL);
// ia
float left = dr.x * 2 / dt.GetWidth() - 1.0f;
float top = 1.0f - dr.y * 2 / dt.GetHeight();
float right = dr.z * 2 / dt.GetWidth() - 1.0f;
float bottom = 1.0f - dr.w * 2 / dt.GetHeight();
GSVertexPT1 vertices[] =
{
{GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)},
{GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)},
{GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)},
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)},
};
D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1};
m_dev->UpdateSubresource(m_convert.vb, 0, &box, vertices, 0, 0);
IASetVertexBuffer(m_convert.vb, sizeof(vertices[0]));
IASetInputLayout(m_convert.il);
IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
// vs
VSSetShader(m_convert.vs, NULL);
// gs
GSSetShader(NULL);
// ps
PSSetShader(ps, ps_cb);
PSSetSamplerState(linear ? m_convert.ln : m_convert.pt, NULL);
PSSetShaderResources(st, NULL);
// rs
RSSet(dt.GetWidth(), dt.GetHeight());
//
DrawPrimitive(countof(vertices));
//
EndScene();
}
HRESULT GSDevice10::CompileShader(uint32 id, const string& entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** ps, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il)
{
HRESULT hr;

View File

@ -24,11 +24,8 @@
#include "GSDevice.h"
#include "GSTexture10.h"
class GSDevice10 : public GSDevice<GSTexture10>
class GSDevice10 : public GSDevice
{
public:
typedef GSTexture10 Texture;
private:
// state cache
@ -55,9 +52,10 @@ private:
//
bool Create(int type, Texture& t, int w, int h, int format);
void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c);
void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0);
GSTexture* Create(int type, int w, int h, int format);
void DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c);
void DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset = 0);
//
@ -99,44 +97,44 @@ public:
bool Create(HWND hWnd, bool vsync);
bool Reset(int w, int h, bool fs);
bool IsLost() {return false;}
void Present(const GSVector4i& r);
void Flip();
void BeginScene();
void EndScene();
void Draw(const string& s);
bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0);
void ClearRenderTarget(Texture& t, const GSVector4& c);
void ClearRenderTarget(Texture& t, uint32 c);
void ClearDepth(Texture& t, float c);
void ClearStencil(Texture& t, uint8 c);
void ClearRenderTarget(GSTexture* t, const GSVector4& c);
void ClearRenderTarget(GSTexture* t, uint32 c);
void ClearDepth(GSTexture* t, float c);
void ClearStencil(GSTexture* t, uint8 c);
bool CreateRenderTarget(Texture& t, int w, int h, int format = 0);
bool CreateDepthStencil(Texture& t, int w, int h, int format = 0);
bool CreateTexture(Texture& t, int w, int h, int format = 0);
bool CreateOffscreen(Texture& t, int w, int h, int format = 0);
GSTexture* CreateRenderTarget(int w, int h, int format = 0);
GSTexture* CreateDepthStencil(int w, int h, int format = 0);
GSTexture* CreateTexture(int w, int h, int format = 0);
GSTexture* CreateOffscreen(int w, int h, int format = 0);
ID3D10Device* operator->() {return m_dev;}
operator ID3D10Device*() {return m_dev;}
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format = 0);
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, bool linear = true);
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear = true);
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear = true);
void IASetVertexBuffer(ID3D10Buffer* vb, size_t stride);
void IASetInputLayout(ID3D10InputLayout* layout);
void IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY topology);
void VSSetShader(ID3D10VertexShader* vs, ID3D10Buffer* vs_cb);
void GSSetShader(ID3D10GeometryShader* gs);
void PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1);
void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1);
void PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb);
void PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1);
void RSSet(int width, int height, const GSVector4i* scissor = NULL);
void OMSetDepthStencilState(ID3D10DepthStencilState* dss, uint8 sref);
void OMSetBlendState(ID3D10BlendState* bs, float bf);
void OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds);
void DrawPrimitive(uint32 count, uint32 start = 0);
void StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear = true);
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear = true);
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, bool linear = true);
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, ID3D10PixelShader* ps, ID3D10Buffer* ps_cb, ID3D10BlendState* bs, bool linear = true);
ID3D10Device* operator->() {return m_dev;}
operator ID3D10Device*() {return m_dev;}
HRESULT CompileShader(uint32 id, const string& entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** vs, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il);
HRESULT CompileShader(uint32 id, const string& entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs);

View File

@ -83,8 +83,6 @@ bool GSDevice7::Reset(int w, int h, bool fs)
if(!__super::Reset(w, h, fs))
return false;
m_backbuffer = NULL;
DDSURFACEDESC2 desc;
memset(&desc, 0, sizeof(desc));
@ -95,11 +93,15 @@ bool GSDevice7::Reset(int w, int h, bool fs)
desc.dwWidth = w;
desc.dwHeight = h;
if(FAILED(m_dd->CreateSurface(&desc, &m_backbuffer, NULL)))
CComPtr<IDirectDrawSurface7> backbuffer;
if(FAILED(m_dd->CreateSurface(&desc, &backbuffer, NULL)))
{
return false;
}
m_backbuffer = new GSTexture7(GSTexture::RenderTarget, backbuffer);
CComPtr<IDirectDrawClipper> clipper;
if(FAILED(m_dd->CreateClipper(0, &clipper, NULL)))
@ -120,7 +122,7 @@ bool GSDevice7::Reset(int w, int h, bool fs)
clipper->SetClipList((RGNDATA*)buff, 0);
if(FAILED(m_backbuffer->SetClipper(clipper)))
if(FAILED(backbuffer->SetClipper(clipper)))
{
return false;
}
@ -137,17 +139,13 @@ void GSDevice7::Present(const GSVector4i& r)
GetClientRect(m_hWnd, cr);
DDSURFACEDESC2 desc;
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
hr = m_backbuffer->GetSurfaceDesc(&desc);
if(desc.dwWidth != cr.width() || desc.dwHeight != cr.height())
if(m_backbuffer->GetWidth() != cr.width() || m_backbuffer->GetHeight() != cr.height())
{
Reset(cr.width(), cr.height(), false);
}
CComPtr<IDirectDrawSurface7> backbuffer = *(GSTexture7*)m_backbuffer;
DDBLTFX fx;
memset(&fx, 0, sizeof(fx));
@ -155,11 +153,13 @@ void GSDevice7::Present(const GSVector4i& r)
fx.dwSize = sizeof(fx);
fx.dwFillColor = 0;
hr = m_backbuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
hr = backbuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
GSVector4i r2 = r;
hr = m_backbuffer->Blt(r2, m_merge, NULL, DDBLT_WAIT, NULL);
hr = backbuffer->Blt(r2, *(GSTexture7*)m_merge, NULL, DDBLT_WAIT, NULL);
// if ClearRenderTarget was implemented the parent class could handle these tasks until this point
r2 = cr;
@ -170,7 +170,7 @@ void GSDevice7::Present(const GSVector4i& r)
hr = m_dd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
}
hr = m_primary->Blt(r2, m_backbuffer, cr, DDBLT_WAIT, NULL);
hr = m_primary->Blt(r2, backbuffer, cr, DDBLT_WAIT, NULL);
if(hr == DDERR_SURFACELOST)
{
@ -184,12 +184,10 @@ void GSDevice7::Present(const GSVector4i& r)
}
}
bool GSDevice7::Create(int type, Texture& t, int w, int h, int format)
GSTexture* GSDevice7::Create(int type, int w, int h, int format)
{
HRESULT hr;
t = Texture();
DDSURFACEDESC2 desc;
memset(&desc, 0, sizeof(desc));
@ -207,6 +205,8 @@ bool GSDevice7::Create(int type, Texture& t, int w, int h, int format)
desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
GSTexture7* t = NULL;
CComPtr<IDirectDrawSurface7> system, video;
switch(type)
@ -218,25 +218,25 @@ bool GSDevice7::Create(int type, Texture& t, int w, int h, int format)
if(FAILED(hr = m_dd->CreateSurface(&desc, &system, NULL))) return false;
desc.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
if(FAILED(hr = m_dd->CreateSurface(&desc, &video, NULL))) return false;
t = Texture(type, system, video);
t = new GSTexture7(type, system, video);
break;
case GSTexture::Offscreen:
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
if(FAILED(hr = m_dd->CreateSurface(&desc, &system, NULL))) return false;
t = Texture(type, system);
t = new GSTexture7(type, system);
break;
}
return !!t;
return t;
}
void GSDevice7::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c)
void GSDevice7::DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c)
{
HRESULT hr;
hr = dt->Blt(NULL, st[0], NULL, DDBLT_WAIT, NULL);
hr = (*(GSTexture7*)dt)->Blt(NULL, *(GSTexture7*)st[0], NULL, DDBLT_WAIT, NULL);
}
void GSDevice7::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset)
void GSDevice7::DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset)
{
}

View File

@ -24,19 +24,16 @@
#include "GSDevice.h"
#include "GSTexture7.h"
class GSDevice7 : public GSDevice<GSTexture7>
class GSDevice7 : public GSDevice
{
public:
typedef GSTexture7 Texture;
private:
CComPtr<IDirectDraw7> m_dd;
CComPtr<IDirectDrawSurface7> m_primary;
CComPtr<IDirectDrawSurface7> m_backbuffer;
bool Create(int type, Texture& t, int w, int h, int format);
void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c);
void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0);
GSTexture* Create(int type, int w, int h, int format);
void DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c);
void DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset = 0);
public:
GSDevice7();
@ -44,15 +41,6 @@ public:
bool Create(HWND hWnd, bool vsync);
bool Reset(int w, int h, bool fs);
bool IsLost() {return false;}
void Present(const GSVector4i& r);
void BeginScene() {}
void EndScene() {}
void Draw(const string& s) {}
bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) {return false;}
void ClearRenderTarget(Texture& t, const GSVector4& c) {}
void ClearRenderTarget(Texture& t, uint32 c) {}
void ClearDepth(Texture& t, float c) {}
void ClearStencil(Texture& t, uint8 c) {}
void Present(const GSVector4i& r);
};

View File

@ -215,15 +215,14 @@ bool GSDevice9::Reset(int w, int h, bool fs)
CComPtr<IDirect3DSurface9> backbuffer;
hr = m_swapchain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
m_backbuffer = Texture(backbuffer);
m_backbuffer = new GSTexture9(backbuffer);
return true;
}
m_swapchain = NULL;
m_backbuffer = Texture();
if(m_font) m_font->OnLostDevice();
m_font = NULL;
if(m_font) {m_font->OnLostDevice(); m_font = NULL;}
if(m_vs_cb) _aligned_free(m_vs_cb);
if(m_ps_cb) _aligned_free(m_ps_cb);
@ -325,7 +324,7 @@ bool GSDevice9::Reset(int w, int h, bool fs)
hr = m_dev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);
}
m_backbuffer = Texture(backbuffer);
m_backbuffer = new GSTexture9(backbuffer);
D3DXFONT_DESC fd;
memset(&fd, 0, sizeof(fd));
@ -348,26 +347,8 @@ bool GSDevice9::IsLost()
return hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICENOTRESET;
}
void GSDevice9::Present(const GSVector4i& r)
void GSDevice9::Flip()
{
GSVector4i cr;
GetClientRect(m_hWnd, cr);
if(m_backbuffer.GetWidth() != cr.width() || m_backbuffer.GetHeight() != cr.height())
{
Reset(cr.width(), cr.height(), false);
}
OMSetRenderTargets(m_backbuffer, NULL);
m_dev->Clear(0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0);
if(m_current)
{
StretchRect(m_current, m_backbuffer, GSVector4(r));
}
if(m_swapchain)
{
m_swapchain->Present(NULL, NULL, NULL, NULL, 0);
@ -388,97 +369,39 @@ void GSDevice9::EndScene()
m_dev->EndScene();
}
void GSDevice9::Draw(const string& s)
{
/*
if(!m_pp.Windowed)
{
BeginScene();
OMSetRenderTargets(m_backbuffer, NULL);
GSVector4i r(0, 0, m_backbuffer.GetWidth(), m_backbuffer.GetHeight());
D3DCOLOR c = D3DCOLOR_ARGB(255, 0, 255, 0);
if(m_font->DrawText(NULL, str, -1, r, DT_CALCRECT|DT_LEFT|DT_WORDBREAK, c))
{
m_font->DrawText(NULL, str, -1, r, DT_LEFT|DT_WORDBREAK, c);
}
EndScene();
}
*/
}
bool GSDevice9::CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format)
{
dst = Texture();
if(format == 0)
{
format = D3DFMT_A8R8G8B8;
}
if(format != D3DFMT_A8R8G8B8)
{
ASSERT(0);
return false;
}
Texture rt;
if(CreateRenderTarget(rt, w, h, format))
{
GSVector4 dr(0, 0, w, h);
StretchRect(src, sr, rt, dr, m_convert.ps[1], NULL, 0);
if(CreateOffscreen(dst, w, h, format))
{
m_dev->GetRenderTargetData(rt, dst);
}
}
Recycle(rt);
return !!dst;
}
void GSDevice9::ClearRenderTarget(Texture& t, const GSVector4& c)
void GSDevice9::ClearRenderTarget(GSTexture* t, const GSVector4& c)
{
ClearRenderTarget(t, (c * 255 + 0.5f).zyxw().rgba32());
}
void GSDevice9::ClearRenderTarget(Texture& t, uint32 c)
void GSDevice9::ClearRenderTarget(GSTexture* t, uint32 c)
{
CComPtr<IDirect3DSurface9> surface;
m_dev->GetRenderTarget(0, &surface);
m_dev->SetRenderTarget(0, t);
m_dev->SetRenderTarget(0, *(GSTexture9*)t);
m_dev->Clear(0, NULL, D3DCLEAR_TARGET, c, 0, 0);
m_dev->SetRenderTarget(0, surface);
}
void GSDevice9::ClearDepth(Texture& t, float c)
void GSDevice9::ClearDepth(GSTexture* t, float c)
{
CComPtr<IDirect3DSurface9> surface;
m_dev->GetDepthStencilSurface(&surface);
m_dev->SetDepthStencilSurface(t);
m_dev->SetDepthStencilSurface(*(GSTexture9*)t);
m_dev->Clear(0, NULL, D3DCLEAR_ZBUFFER, 0, c, 0);
m_dev->SetDepthStencilSurface(surface);
}
void GSDevice9::ClearStencil(Texture& t, uint8 c)
void GSDevice9::ClearStencil(GSTexture* t, uint8 c)
{
CComPtr<IDirect3DSurface9> surface;
m_dev->GetDepthStencilSurface(&surface);
m_dev->SetDepthStencilSurface(t);
m_dev->SetDepthStencilSurface(*(GSTexture9*)t);
m_dev->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0, c);
m_dev->SetDepthStencilSurface(surface);
}
bool GSDevice9::Create(int type, Texture& t, int w, int h, int format)
GSTexture* GSDevice9::Create(int type, int w, int h, int format)
{
HRESULT hr;
@ -501,14 +424,16 @@ bool GSDevice9::Create(int type, Texture& t, int w, int h, int format)
break;
}
GSTexture9* t = NULL;
if(surface)
{
t = Texture(surface);
t = new GSTexture9(surface);
}
if(texture)
{
t = Texture(texture);
t = new GSTexture9(texture);
}
if(t)
@ -522,34 +447,137 @@ bool GSDevice9::Create(int type, Texture& t, int w, int h, int format)
ClearDepth(t, 0);
break;
}
return t;
}
return false;
return t;
}
bool GSDevice9::CreateRenderTarget(Texture& t, int w, int h, int format)
GSTexture* GSDevice9::CreateRenderTarget(int w, int h, int format)
{
return __super::CreateRenderTarget(t, w, h, format ? format : D3DFMT_A8R8G8B8);
return __super::CreateRenderTarget(w, h, format ? format : D3DFMT_A8R8G8B8);
}
bool GSDevice9::CreateDepthStencil(Texture& t, int w, int h, int format)
GSTexture* GSDevice9::CreateDepthStencil(int w, int h, int format)
{
return __super::CreateDepthStencil(t, w, h, format ? format : D3DFMT_D24S8);
return __super::CreateDepthStencil(w, h, format ? format : D3DFMT_D24S8);
}
bool GSDevice9::CreateTexture(Texture& t, int w, int h, int format)
GSTexture* GSDevice9::CreateTexture(int w, int h, int format)
{
return __super::CreateTexture(t, w, h, format ? format : D3DFMT_A8R8G8B8);
return __super::CreateTexture(w, h, format ? format : D3DFMT_A8R8G8B8);
}
bool GSDevice9::CreateOffscreen(Texture& t, int w, int h, int format)
GSTexture* GSDevice9::CreateOffscreen(int w, int h, int format)
{
return __super::CreateOffscreen(t, w, h, format ? format : D3DFMT_A8R8G8B8);
return __super::CreateOffscreen(w, h, format ? format : D3DFMT_A8R8G8B8);
}
void GSDevice9::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c)
GSTexture* GSDevice9::CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format)
{
GSTexture* dst = NULL;
if(format == 0)
{
format = D3DFMT_A8R8G8B8;
}
if(format != D3DFMT_A8R8G8B8)
{
ASSERT(0);
return false;
}
if(GSTexture* rt = CreateRenderTarget(w, h, format))
{
GSVector4 dr(0, 0, w, h);
StretchRect(src, sr, rt, dr, m_convert.ps[1], NULL, 0);
dst = CreateOffscreen(w, h, format);
if(dst)
{
m_dev->GetRenderTargetData(*(GSTexture9*)rt, *(GSTexture9*)dst);
}
Recycle(rt);
}
return dst;
}
void GSDevice9::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, bool linear)
{
StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, 0, linear);
}
void GSDevice9::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear)
{
StretchRect(st, sr, dt, dr, ps, ps_cb, ps_cb_len, &m_convert.bs, linear);
}
void GSDevice9::StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear)
{
BeginScene();
GSVector2i ds = dt->GetSize();
// om
OMSetDepthStencilState(&m_convert.dss, 0);
OMSetBlendState(bs, 0);
OMSetRenderTargets(dt, NULL);
// ia
float left = dr.x * 2 / ds.x - 1.0f;
float top = 1.0f - dr.y * 2 / ds.y;
float right = dr.z * 2 / ds.x - 1.0f;
float bottom = 1.0f - dr.w * 2 / ds.y;
GSVertexPT1 vertices[] =
{
{GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)},
{GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)},
{GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)},
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)},
};
for(int i = 0; i < countof(vertices); i++)
{
vertices[i].p.x -= 1.0f / ds.x;
vertices[i].p.y += 1.0f / ds.y;
}
IASetVertexBuffer(4, vertices);
IASetInputLayout(m_convert.il);
IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP);
// vs
VSSetShader(m_convert.vs, NULL, 0);
// ps
PSSetShader(ps, ps_cb, ps_cb_len);
PSSetSamplerState(linear ? &m_convert.ln : &m_convert.pt);
PSSetShaderResources(st, NULL);
// rs
RSSet(ds.x, ds.y);
//
DrawPrimitive();
//
EndScene();
}
void GSDevice9::DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c)
{
ClearRenderTarget(dt, c);
@ -568,15 +596,17 @@ void GSDevice9::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt,
}
}
void GSDevice9::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset)
void GSDevice9::DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset)
{
GSVector4 s = GSVector4(dt->GetSize());
GSVector4 sr(0, 0, 1, 1);
GSVector4 dr(0.0f, yoffset, (float)dt.GetWidth(), (float)dt.GetHeight() + yoffset);
GSVector4 dr(0.0f, yoffset, s.x, s.y + yoffset);
InterlaceConstantBuffer cb;
cb.ZrH = GSVector2(0, 1.0f / dt.GetHeight());
cb.hH = (float)dt.GetHeight() / 2;
cb.ZrH = GSVector2(0, 1.0f / s.y);
cb.hH = (float)s.y / 2;
StretchRect(st, sr, dt, dr, m_interlace.ps[shader], (const float*)&cb, 1, linear);
}
@ -656,8 +686,14 @@ void GSDevice9::VSSetShader(IDirect3DVertexShader9* vs, const float* vs_cb, int
}
}
void GSDevice9::PSSetShaderResources(IDirect3DTexture9* srv0, IDirect3DTexture9* srv1)
void GSDevice9::PSSetShaderResources(GSTexture* sr0, GSTexture* sr1)
{
IDirect3DTexture9* srv0 = NULL;
IDirect3DTexture9* srv1 = NULL;
if(sr0) srv0 = *(GSTexture9*)sr0;
if(sr1) srv1 = *(GSTexture9*)sr1;
if(m_ps_srvs[0] != srv0)
{
m_dev->SetTexture(0, srv0);
@ -796,8 +832,14 @@ void GSDevice9::OMSetBlendState(Direct3DBlendState9* bs, uint32 bf)
}
}
void GSDevice9::OMSetRenderTargets(IDirect3DSurface9* rtv, IDirect3DSurface9* dsv)
void GSDevice9::OMSetRenderTargets(GSTexture* rt, GSTexture* ds)
{
IDirect3DSurface9* rtv = NULL;
IDirect3DSurface9* dsv = NULL;
if(rt) rtv = *(GSTexture9*)rt;
if(ds) dsv = *(GSTexture9*)ds;
if(m_rtv != rtv)
{
m_dev->SetRenderTarget(0, rtv);
@ -840,79 +882,6 @@ void GSDevice9::DrawPrimitive()
m_dev->DrawPrimitiveUP(m_topology, prims, m_vb_vertices, m_vb_stride);
}
void GSDevice9::StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear)
{
StretchRect(st, GSVector4(0, 0, 1, 1), dt, dr, linear);
}
void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear)
{
StretchRect(st, sr, dt, dr, m_convert.ps[0], NULL, 0, linear);
}
void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear)
{
StretchRect(st, sr, dt, dr, ps, ps_cb, ps_cb_len, &m_convert.bs, linear);
}
void GSDevice9::StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear)
{
BeginScene();
// om
OMSetDepthStencilState(&m_convert.dss, 0);
OMSetBlendState(bs, 0);
OMSetRenderTargets(dt, NULL);
// ia
float left = dr.x * 2 / dt.GetWidth() - 1.0f;
float top = 1.0f - dr.y * 2 / dt.GetHeight();
float right = dr.z * 2 / dt.GetWidth() - 1.0f;
float bottom = 1.0f - dr.w * 2 / dt.GetHeight();
GSVertexPT1 vertices[] =
{
{GSVector4(left, top, 0.5f, 1.0f), GSVector2(sr.x, sr.y)},
{GSVector4(right, top, 0.5f, 1.0f), GSVector2(sr.z, sr.y)},
{GSVector4(left, bottom, 0.5f, 1.0f), GSVector2(sr.x, sr.w)},
{GSVector4(right, bottom, 0.5f, 1.0f), GSVector2(sr.z, sr.w)},
};
for(int i = 0; i < countof(vertices); i++)
{
vertices[i].p.x -= 1.0f / dt.GetWidth();
vertices[i].p.y += 1.0f / dt.GetHeight();
}
IASetVertexBuffer(4, vertices);
IASetInputLayout(m_convert.il);
IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP);
// vs
VSSetShader(m_convert.vs, NULL, 0);
// ps
PSSetShader(ps, ps_cb, ps_cb_len);
PSSetSamplerState(linear ? &m_convert.ln : &m_convert.pt);
PSSetShaderResources(st, NULL);
// rs
RSSet(dt.GetWidth(), dt.GetHeight());
//
DrawPrimitive();
//
EndScene();
}
// FIXME: D3DXCompileShaderFromResource of d3dx9 v37 (march 2008) calls GetFullPathName on id for some reason and then crashes
static HRESULT LoadShader(uint32 id, LPCSTR& data, uint32& size)

View File

@ -58,11 +58,8 @@ struct Direct3DBlendState9
UINT8 RenderTargetWriteMask;
};
class GSDevice9 : public GSDevice<GSTexture9>
class GSDevice9 : public GSDevice
{
public:
typedef GSTexture9 Texture;
private:
// state cache
@ -90,9 +87,10 @@ private:
//
bool Create(int type, Texture& t, int w, int h, int format);
void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c);
void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0);
GSTexture* Create(int type, int w, int h, int format);
void DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c);
void DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset = 0);
//
@ -101,7 +99,6 @@ private:
CComPtr<IDirect3D9> m_d3d;
CComPtr<IDirect3DDevice9> m_dev;
CComPtr<IDirect3DSwapChain9> m_swapchain;
Texture m_backbuffer;
public: // TODO
D3DPRESENT_PARAMETERS m_pp;
@ -135,38 +132,43 @@ public:
bool Create(HWND hWnd, bool vsync);
bool Reset(int w, int h, bool fs);
bool IsLost();
void Present(const GSVector4i& r);
void Flip();
void BeginScene();
void EndScene();
void Draw(const string& s);
bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0);
void ClearRenderTarget(Texture& t, const GSVector4& c);
void ClearRenderTarget(Texture& t, uint32 c);
void ClearDepth(Texture& t, float c);
void ClearStencil(Texture& t, uint8 c);
void ClearRenderTarget(GSTexture* t, const GSVector4& c);
void ClearRenderTarget(GSTexture* t, uint32 c);
void ClearDepth(GSTexture* t, float c);
void ClearStencil(GSTexture* t, uint8 c);
bool CreateRenderTarget(Texture& t, int w, int h, int format = 0);
bool CreateDepthStencil(Texture& t, int w, int h, int format = 0);
bool CreateTexture(Texture& t, int w, int h, int format = 0);
bool CreateOffscreen(Texture& t, int w, int h, int format = 0);
GSTexture* CreateRenderTarget(int w, int h, int format = 0);
GSTexture* CreateDepthStencil(int w, int h, int format = 0);
GSTexture* CreateTexture(int w, int h, int format = 0);
GSTexture* CreateOffscreen(int w, int h, int format = 0);
IDirect3DDevice9* operator->() {return m_dev;}
operator IDirect3DDevice9*() {return m_dev;}
GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format = 0);
virtual bool IsCurrentRGBA() {return false;}
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, bool linear = true);
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear = true);
void StretchRect(GSTexture* st, const GSVector4& sr, GSTexture* dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear = true);
// TODO: void IASetVertexBuffer(IDirect3DVertexBuffer9* vb, uint32 count, const void* vertices, size_t stride);
void IASetVertexBuffer(int count, const void* vertices, size_t stride);
void IASetInputLayout(IDirect3DVertexDeclaration9* layout);
void IASetPrimitiveTopology(D3DPRIMITIVETYPE topology);
void VSSetShader(IDirect3DVertexShader9* vs, const float* vs_cb, int vs_cb_len);
void PSSetShaderResources(IDirect3DTexture9* srv0, IDirect3DTexture9* srv1);
void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1);
void PSSetShader(IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len);
void PSSetSamplerState(Direct3DSamplerState9* ss);
void RSSet(int width, int height, const GSVector4i* scissor = NULL);
void OMSetDepthStencilState(Direct3DDepthStencilState9* dss, uint32 sref);
void OMSetBlendState(Direct3DBlendState9* bs, uint32 bf);
void OMSetRenderTargets(IDirect3DSurface9* rtv, IDirect3DSurface9* dsv);
void OMSetRenderTargets(GSTexture* rt, GSTexture* ds);
void DrawPrimitive();
template<class T> void IASetVertexBuffer(int count, T* vertices)
@ -174,16 +176,9 @@ public:
IASetVertexBuffer(count, vertices, sizeof(T));
}
void StretchRect(Texture& st, Texture& dt, const GSVector4& dr, bool linear = true);
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, bool linear = true);
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, bool linear = true);
void StretchRect(Texture& st, const GSVector4& sr, Texture& dt, const GSVector4& dr, IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len, Direct3DBlendState9* bs, bool linear = true);
IDirect3DDevice9* operator->() {return m_dev;}
operator IDirect3DDevice9*() {return m_dev;}
HRESULT CompileShader(uint32 id, const string& entry, const D3DXMACRO* macro, IDirect3DVertexShader9** vs, const D3DVERTEXELEMENT9* layout, int count, IDirect3DVertexDeclaration9** il);
HRESULT CompileShader(uint32 id, const string& entry, const D3DXMACRO* macro, IDirect3DPixelShader9** ps);
virtual bool IsCurrentRGBA()
{
return false;
}
};

View File

@ -42,9 +42,7 @@ bool GSDeviceNull::Reset(int w, int h, bool fs)
return true;
}
bool GSDeviceNull::Create(int type, Texture& t, int w, int h, int format)
GSTexture* GSDeviceNull::Create(int type, int w, int h, int format)
{
t = Texture(type, w, h, format);
return true;
return new GSTextureNull(type, w, h, format);
}

View File

@ -24,30 +24,17 @@
#include "GSDevice.h"
#include "GSTextureNull.h"
class GSDeviceNull : public GSDevice<GSTextureNull>
class GSDeviceNull : public GSDevice
{
public:
typedef GSTextureNull Texture;
private:
bool Create(int type, Texture& t, int w, int h, int format);
void DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c) {}
void DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset = 0) {}
GSTexture* Create(int type, int w, int h, int format);
void DoMerge(GSTexture* st[2], GSVector4* sr, GSVector4* dr, GSTexture* dt, bool slbg, bool mmod, const GSVector4& c) {}
void DoInterlace(GSTexture* st, GSTexture* dt, int shader, bool linear, float yoffset = 0) {}
public:
GSDeviceNull() {}
bool Create(HWND hWnd, bool vsync);
bool Reset(int w, int h, bool fs);
bool IsLost() {return false;}
void Present(const GSVector4i& r) {}
void BeginScene() {}
void EndScene() {}
void Draw(const string& s) {}
bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) {return false;}
void ClearRenderTarget(Texture& t, const GSVector4& c) {}
void ClearRenderTarget(Texture& t, uint32 c) {}
void ClearDepth(Texture& t, float c) {}
void ClearStencil(Texture& t, uint8 c) {}
};

View File

@ -35,11 +35,6 @@ GSDrawScanlineCodeGenerator::GSDrawScanlineCodeGenerator(GSScanlineEnvironment&
m_sel.key = key;
if(m_sel.tfx == TFX_DECAL && m_sel.tcc == 0)
{
printf("*** TFX_DECAL && !TCC *** \n");
}
Generate();
}

View File

@ -1710,11 +1710,15 @@ void GSLocalMemory::ReadTexture16SZ(const GSVector4i& r, uint8* dst, int dstpitc
void GSLocalMemory::ReadTextureBlock32(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(16);
ReadBlock32<true>(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock24(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(16);
if(TEXA.AEM)
{
ReadAndExpandBlock24<true>(BlockPtr(bp), dst, dstpitch, TEXA);
@ -1745,46 +1749,50 @@ void GSLocalMemory::ReadTextureBlock16S(uint32 bp, uint8* dst, int dstpitch, con
void GSLocalMemory::ReadTextureBlock8(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
const uint32* pal = m_clut;
ALIGN_STACK(16);
ReadAndExpandBlock8_32(BlockPtr(bp), dst, dstpitch, pal);
ReadAndExpandBlock8_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock4(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
const uint64* pal = m_clut;
ALIGN_STACK(16);
ReadAndExpandBlock4_32(BlockPtr(bp), dst, dstpitch, pal);
ReadAndExpandBlock4_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock8H(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
const uint32* pal = m_clut;
ALIGN_STACK(16);
ReadAndExpandBlock8H_32(BlockPtr(bp), dst, dstpitch, pal);
ReadAndExpandBlock8H_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock4HL(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
const uint32* pal = m_clut;
ALIGN_STACK(16);
ReadAndExpandBlock4HL_32(BlockPtr(bp), dst, dstpitch, pal);
ReadAndExpandBlock4HL_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock4HH(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
const uint32* pal = m_clut;
ALIGN_STACK(16);
ReadAndExpandBlock4HH_32(BlockPtr(bp), dst, dstpitch, pal);
ReadAndExpandBlock4HH_32(BlockPtr(bp), dst, dstpitch, m_clut);
}
void GSLocalMemory::ReadTextureBlock32Z(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(16);
ReadBlock32<true>(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock24Z(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(16);
if(TEXA.AEM)
{
ReadAndExpandBlock24<true>(BlockPtr(bp), dst, dstpitch, TEXA);
@ -2172,21 +2180,29 @@ void GSLocalMemory::ReadTextureBlock8P(uint32 bp, uint8* dst, int dstpitch, cons
void GSLocalMemory::ReadTextureBlock4P(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(16);
ReadBlock4P(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock8HP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(16);
ReadBlock8HP(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock4HLP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(16);
ReadBlock4HLP(BlockPtr(bp), dst, dstpitch);
}
void GSLocalMemory::ReadTextureBlock4HHP(uint32 bp, uint8* dst, int dstpitch, const GIFRegTEXA& TEXA) const
{
ALIGN_STACK(16);
ReadBlock4HHP(BlockPtr(bp), dst, dstpitch);
}

View File

@ -277,7 +277,7 @@ void GSRasterizer::DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor)
longest.p = v[2].p - v[1].p;
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
int i = longest.p.upl(longest.p == GSVector4::zero()).mask();
if(i & 2) return;
@ -305,8 +305,8 @@ void GSRasterizer::DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor)
GSVertexSW dscan = longest * longest.p.xxxx().rcp();
GSVertexSW vl = v[2 - i] - l;
GSVector4 vr = v[1 + i].p - r;
GSVertexSW vl = v[1 + i] - l;
GSVector4 vr = v[2 - i].p - r;
GSVertexSW dl = vl / vl.p.yyyy();
GSVector4 dr = vr / vr.yyyy();
@ -329,14 +329,14 @@ void GSRasterizer::DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor)
longest.p = v[1].p - v[0].p;
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
int i = longest.p.upl(longest.p == GSVector4::zero()).mask();
if(i & 2) return;
i &= 1;
GSVertexSW& l = v[1 - i];
GSVector4& r = v[i].p;
GSVertexSW& l = v[i];
GSVector4& r = v[1 - i].p;
GSVector4 fscissor(scissor);
@ -384,7 +384,7 @@ void GSRasterizer::DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scisso
GSVertexSW longest = dv[1] * (dv[0].p / dv[1].p).yyyy() - dv[0];
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
int i = longest.p.upl(longest.p == GSVector4::zero()).mask();
if(i & 2) return;
@ -409,8 +409,8 @@ void GSRasterizer::DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scisso
GSVertexSW& l = v[0];
GSVector4 r = v[0].p;
GSVertexSW dl = dv[1 - i] / dv[1 - i].p.yyyy();
GSVector4 dr = dv[i].p / dv[i].p.yyyy();
GSVertexSW dl = dv[i] / dv[i].p.yyyy();
GSVector4 dr = dv[1 - i].p / dv[1 - i].p.yyyy();
GSVector4 dy = tbmax.xxxx() - l.p.yyyy();
@ -427,7 +427,7 @@ void GSRasterizer::DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scisso
if(top < bottom)
{
if(i)
if(i == 0)
{
l = v[1];
dv[2] = v[2] - v[1];

View File

@ -21,3 +21,421 @@
#include "StdAfx.h"
#include "GSRenderer.h"
GSRenderer::GSRenderer(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, bool psrr)
: GSState(base, mt, irq)
, m_dev(NULL)
, m_osd(true)
, m_psrr(psrr)
{
m_interlace = rs.m_interlace;
m_aspectratio = rs.m_aspectratio;
m_filter = rs.m_filter;
m_vsync = rs.m_vsync;
m_nativeres = rs.m_nativeres;
m_aa1 = rs.m_aa1;
m_blur = rs.m_blur;
s_n = 0;
s_dump = !!theApp.GetConfig("dump", 0);
s_save = !!theApp.GetConfig("save", 0);
s_savez = !!theApp.GetConfig("savez", 0);
}
GSRenderer::~GSRenderer()
{
delete m_dev;
}
bool GSRenderer::Create(const string& title)
{
if(!m_wnd.Create(title.c_str()))
{
return false;
}
ASSERT(m_dev);
if(!m_dev->Create(m_wnd, m_vsync))
{
return false;
}
Reset();
return true;
}
bool GSRenderer::Merge(int field)
{
bool en[2];
GSVector4i fr[2];
GSVector4i dr[2];
int baseline = INT_MAX;
for(int i = 0; i < 2; i++)
{
en[i] = IsEnabled(i);
if(en[i])
{
fr[i] = GetFrameRect(i);
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]);
}
}
if(!en[0] && !en[1])
{
return false;
}
// try to avoid fullscreen blur, could be nice on tv but on a monitor it's like double vision, hurts my eyes (persona 4, guitar hero)
//
// NOTE: probably the technique explained in graphtip.pdf (Antialiasing by Supersampling / 4. Reading Odd/Even Scan Lines Separately with the PCRTC then Blending)
bool samesrc =
en[0] && en[1] &&
m_regs->DISP[0].DISPFB.FBP == m_regs->DISP[1].DISPFB.FBP &&
m_regs->DISP[0].DISPFB.FBW == m_regs->DISP[1].DISPFB.FBW &&
m_regs->DISP[0].DISPFB.PSM == m_regs->DISP[1].DISPFB.PSM;
bool blurdetected = false;
if(samesrc && m_regs->PMODE.SLBG == 0 && m_regs->PMODE.MMOD == 1 && m_regs->PMODE.ALP == 0x80)
{
if(fr[0].eq(fr[1] + GSVector4i(0, -1, 0, 0)) && dr[0].eq(dr[1] + GSVector4i(0, 0, 0, 1))
|| fr[1].eq(fr[0] + GSVector4i(0, -1, 0, 0)) && dr[1].eq(dr[0] + GSVector4i(0, 0, 0, 1)))
{
// persona 4:
//
// fr[0] = 0 0 640 448
// fr[1] = 0 1 640 448
// dr[0] = 159 50 779 498
// dr[1] = 159 50 779 497
//
// 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
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;
blurdetected = true;
}
else if(dr[0].eq(dr[1]) && (fr[0].eq(fr[1] + GSVector4i(0, 1, 0, 1)) || fr[1].eq(fr[0] + GSVector4i(0, 1, 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;
blurdetected = true;
}
}
GSVector2i fs(0, 0);
GSVector2i ds(0, 0);
GSTexture* tex[2] = {NULL, NULL};
if(samesrc && fr[0].bottom == fr[1].bottom)
{
tex[0] = GetOutput(0);
tex[1] = tex[0]; // saves one texture fetch
}
else
{
if(en[0]) tex[0] = GetOutput(0);
if(en[1]) tex[1] = GetOutput(1);
}
GSVector4 src[2];
GSVector4 dst[2];
for(int i = 0; i < 2; i++)
{
if(!en[i] || !tex[i]) continue;
GSVector4i r = fr[i];
// overscan hack
if(dr[i].height() > 512) // hmm
{
int y = GetDeviceSize(i).y;
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD) y /= 2;
r.bottom = r.top + y;
}
//
if(m_blur && blurdetected && i == 1)
{
r += GSVector4i(0, 1).xyxy();
}
GSVector4 scale = GSVector4(tex[i]->m_scale).xyxy();
src[i] = GSVector4(r) * scale / GSVector4(tex[i]->GetSize()).xyxy();
GSVector2 o(0, 0);
if(dr[i].top - baseline >= 4) // 2?
{
o.y = tex[i]->m_scale.y * (dr[i].top - baseline);
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
{
o.y /= 2;
}
}
dst[i] = GSVector4(o).xyxy() + scale * GSVector4(r.rsize());
fs.x = max(fs.x, (int)(dst[i].z + 0.5f));
fs.y = max(fs.y, (int)(dst[i].w + 0.5f));
}
ds = fs;
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
{
ds.y *= 2;
}
bool slbg = m_regs->PMODE.SLBG;
bool mmod = m_regs->PMODE.MMOD;
if(tex[0] || tex[1])
{
GSVector4 c = GSVector4((int)m_regs->BGCOLOR.R, (int)m_regs->BGCOLOR.G, (int)m_regs->BGCOLOR.B, (int)m_regs->PMODE.ALP) / 255;
m_dev->Merge(tex, src, dst, fs, slbg, mmod, c);
if(m_regs->SMODE2.INT && m_interlace > 0)
{
int field2 = 1 - ((m_interlace - 1) & 1);
int mode = (m_interlace - 1) >> 1;
if(!m_dev->Interlace(ds, field ^ field2, mode, tex[1]->m_scale.y))
{
return false;
}
}
}
return true;
}
void GSRenderer::VSync(int field)
{
GSPerfMonAutoTimer pmat(m_perfmon);
m_perfmon.Put(GSPerfMon::Frame);
Flush();
field = field ? 1 : 0;
if(!Merge(field)) return;
// osd
static uint64 s_frame = 0;
static string s_stats;
if(m_perfmon.GetFrame() - s_frame >= 30)
{
m_perfmon.Update();
s_frame = m_perfmon.GetFrame();
double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
string s = m_regs->SMODE2.INT ? (string("Interlaced ") + (m_regs->SMODE2.FFMD ? "(frame)" : "(field)")) : "Progressive";
GSVector4i r = GetDisplayRect();
s_stats = 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()),
s.c_str(),
GSSettingsDlg::g_interlace[m_interlace].name,
GSSettingsDlg::g_aspectratio[m_aspectratio].name,
(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_stats += format(" | %.2f mpps", fps * fillrate / (1024 * 1024));
}
if(m_capture.IsCapturing())
{
s_stats += " | Recording...";
}
m_wnd.SetWindowText(s_stats.c_str());
}
if(m_frameskip)
{
return;
}
// present
if(m_dev->IsLost())
{
ResetDevice();
}
GSVector4i r;
m_wnd.GetClientRect(r);
m_dev->Present(r.fit(m_aspectratio));
// snapshot
if(!m_snapshot.empty())
{
if(!m_dump && (::GetAsyncKeyState(VK_SHIFT) & 0x8000))
{
GSFreezeData fd;
fd.size = 0;
fd.data = NULL;
Freeze(&fd, true);
fd.data = new uint8[fd.size];
Freeze(&fd, false);
m_dump.Open(m_snapshot, m_crc, fd, m_regs);
delete [] fd.data;
}
if(GSTexture* t = m_dev->GetCurrent())
{
t->Save(m_snapshot + ".bmp");
}
m_snapshot.clear();
}
else
{
if(m_dump)
{
m_dump.VSync(field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), m_regs);
}
}
// capture
if(m_capture.IsCapturing())
{
if(GSTexture* current = m_dev->GetCurrent())
{
GSVector2i size = m_capture.GetSize();
if(GSTexture* offscreen = m_dev->CopyOffscreen(current, GSVector4(0, 0, 1, 1), size.x, size.y))
{
uint8* bits = NULL;
int pitch = 0;
if(offscreen->Map(&bits, pitch))
{
m_capture.DeliverFrame(bits, pitch, m_dev->IsCurrentRGBA());
offscreen->Unmap();
}
m_dev->Recycle(offscreen);
}
}
}
}
void GSRenderer::KeyEvent(GSKeyEventData* e)
{
if(e->type == KEYPRESS)
{
// TODO: linux
int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
switch(e->key)
{
case VK_F5:
m_interlace = (m_interlace + 7 + step) % 7;
return;
case VK_F6:
m_aspectratio = (m_aspectratio + 3 + step) % 3;
return;
case VK_F7:
m_wnd.SetWindowText(_T("PCSX2"));
m_osd = !m_osd;
return;
case VK_F12:
if(m_capture.IsCapturing()) m_capture.EndCapture();
else m_capture.BeginCapture(GetFPS());
return;
case VK_DELETE:
m_aa1 = !m_aa1;
return;
case VK_END:
m_blur = !m_blur;
return;
}
}
}
bool GSRenderer::MakeSnapshot(const string& path)
{
if(m_snapshot.empty())
{
time_t t = time(NULL);
char buff[16];
if(strftime(buff, sizeof(buff), "%Y%m%d%H%M%S", localtime(&t)))
{
m_snapshot = format("%s_%s", path.c_str(), buff);
}
}
return true;
}

View File

@ -39,343 +39,20 @@ struct GSRendererSettings
bool m_blur;
};
class GSRendererBase : public GSState, protected GSRendererSettings
class GSRenderer : public GSState, protected GSRendererSettings
{
bool Merge(int field);
protected:
bool m_osd;
virtual void ResetDevice() {}
virtual GSTexture* GetOutput(int i) = 0;
public:
GSWnd m_wnd;
GSDevice* m_dev;
GSCapture m_capture;
string m_snapshot;
public:
GSRendererBase(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs)
: GSState(base, mt, irq)
, m_osd(true)
{
m_interlace = rs.m_interlace;
m_aspectratio = rs.m_aspectratio;
m_filter = rs.m_filter;
m_vsync = rs.m_vsync;
m_nativeres = rs.m_nativeres;
m_aa1 = rs.m_aa1;
m_blur = rs.m_blur;
};
void KeyEvent(GSKeyEventData* e)
{
if(e->type == KEYPRESS)
{
// TODO: linux
int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
switch(e->key)
{
case VK_F5:
m_interlace = (m_interlace + 7 + step) % 7;
return;
case VK_F6:
m_aspectratio = (m_aspectratio + 3 + step) % 3;
return;
case VK_F7:
m_wnd.SetWindowText(_T("PCSX2"));
m_osd = !m_osd;
return;
case VK_F12:
if(m_capture.IsCapturing()) m_capture.EndCapture();
else m_capture.BeginCapture(GetFPS());
return;
case VK_DELETE:
m_aa1 = !m_aa1;
return;
case VK_END:
m_blur = !m_blur;
return;
}
}
}
bool MakeSnapshot(const string& path)
{
if(m_snapshot.empty())
{
time_t t = time(NULL);
char buff[16];
if(strftime(buff, sizeof(buff), "%Y%m%d%H%M%S", localtime(&t)))
{
m_snapshot = format("%s_%s", path.c_str(), buff);
}
}
return true;
}
virtual bool Create(const string& title) = 0;
virtual void VSync(int field) = 0;
};
template<class Device> class GSRenderer : public GSRendererBase
{
protected:
typedef typename Device::Texture Texture;
virtual void ResetDevice() {}
virtual bool GetOutput(int i, Texture& t) = 0;
bool Merge(int field)
{
bool en[2];
GSVector4i fr[2];
GSVector4i dr[2];
int baseline = INT_MAX;
for(int i = 0; i < 2; i++)
{
en[i] = IsEnabled(i);
if(en[i])
{
fr[i] = GetFrameRect(i);
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]);
}
}
if(!en[0] && !en[1])
{
return false;
}
// try to avoid fullscreen blur, could be nice on tv but on a monitor it's like double vision, hurts my eyes (persona 4, guitar hero)
//
// NOTE: probably the technique explained in graphtip.pdf (Antialiasing by Supersampling / 4. Reading Odd/Even Scan Lines Separately with the PCRTC then Blending)
bool samesrc =
en[0] && en[1] &&
m_regs->DISP[0].DISPFB.FBP == m_regs->DISP[1].DISPFB.FBP &&
m_regs->DISP[0].DISPFB.FBW == m_regs->DISP[1].DISPFB.FBW &&
m_regs->DISP[0].DISPFB.PSM == m_regs->DISP[1].DISPFB.PSM;
bool blurdetected = false;
if(samesrc && m_regs->PMODE.SLBG == 0 && m_regs->PMODE.MMOD == 1 && m_regs->PMODE.ALP == 0x80)
{
if(fr[0].eq(fr[1] + GSVector4i(0, -1, 0, 0)) && dr[0].eq(dr[1] + GSVector4i(0, 0, 0, 1))
|| fr[1].eq(fr[0] + GSVector4i(0, -1, 0, 0)) && dr[1].eq(dr[0] + GSVector4i(0, 0, 0, 1)))
{
// persona 4:
//
// fr[0] = 0 0 640 448
// fr[1] = 0 1 640 448
// dr[0] = 159 50 779 498
// dr[1] = 159 50 779 497
//
// 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
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;
blurdetected = true;
}
else if(dr[0].eq(dr[1]) && (fr[0].eq(fr[1] + GSVector4i(0, 1, 0, 1)) || fr[1].eq(fr[0] + GSVector4i(0, 1, 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;
blurdetected = true;
}
}
GSVector2i fs(0, 0);
GSVector2i ds(0, 0);
Texture tex[2];
if(samesrc && fr[0].bottom == fr[1].bottom)
{
GetOutput(0, tex[0]);
tex[1] = tex[0]; // saves one texture fetch
}
else
{
if(en[0]) GetOutput(0, tex[0]);
if(en[1]) GetOutput(1, tex[1]);
}
GSVector4 src[2];
GSVector4 dst[2];
for(int i = 0; i < 2; i++)
{
if(!en[i] || !tex[i]) continue;
GSVector4i r = fr[i];
// overscan hack
if(dr[i].height() > 512) // hmm
{
int y = GetDeviceSize(i).y;
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD) y /= 2;
r.bottom = r.top + y;
}
//
if(m_blur && blurdetected && i == 1)
{
r += GSVector4i(0, 1).xyxy();
}
GSVector4 scale = GSVector4(tex[i].m_scale).xyxy();
src[i] = GSVector4(r) * scale / GSVector4(tex[i].GetSize()).xyxy();
GSVector2 o(0, 0);
if(dr[i].top - baseline >= 4) // 2?
{
o.y = tex[i].m_scale.y * (dr[i].top - baseline);
}
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD)
{
o.y /= 2;
}
dst[i] = GSVector4(o).xyxy() + scale * GSVector4(r.rsize());
fs.x = max(fs.x, (int)(dst[i].z + 0.5f));
fs.y = max(fs.y, (int)(dst[i].w + 0.5f));
}
ds = fs;
if(m_regs->SMODE2.INT && m_regs->SMODE2.FFMD) ds.y *= 2;
bool slbg = m_regs->PMODE.SLBG;
bool mmod = m_regs->PMODE.MMOD;
if(tex[0] || tex[1])
{
GSVector4 c = GSVector4((int)m_regs->BGCOLOR.R, (int)m_regs->BGCOLOR.G, (int)m_regs->BGCOLOR.B, (int)m_regs->PMODE.ALP) / 255;
m_dev.Merge(tex, src, dst, fs, slbg, mmod, c);
if(m_regs->SMODE2.INT && m_interlace > 0)
{
int field2 = 1 - ((m_interlace - 1) & 1);
int mode = (m_interlace - 1) >> 1;
if(!m_dev.Interlace(ds, field ^ field2, mode, tex[1].m_scale.y))
{
return false;
}
}
}
return true;
}
void DoSnapshot(int field)
{
if(!m_snapshot.empty())
{
if(!m_dump && (::GetAsyncKeyState(VK_SHIFT) & 0x8000))
{
GSFreezeData fd;
fd.size = 0;
fd.data = NULL;
Freeze(&fd, true);
fd.data = new uint8[fd.size];
Freeze(&fd, false);
m_dump.Open(m_snapshot, m_crc, fd, m_regs);
delete [] fd.data;
}
m_dev.SaveCurrent(m_snapshot + ".bmp");
m_snapshot.clear();
}
else
{
if(m_dump)
{
m_dump.VSync(field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), m_regs);
}
}
}
void DoCapture()
{
if(!m_capture.IsCapturing())
{
return;
}
GSVector2i size = m_capture.GetSize();
Texture current;
m_dev.GetCurrent(current);
Texture offscreen;
if(m_dev.CopyOffscreen(current, GSVector4(0, 0, 1, 1), offscreen, size.x, size.y))
{
uint8* bits = NULL;
int pitch = 0;
if(offscreen.Map(&bits, pitch))
{
m_capture.DeliverFrame(bits, pitch, m_dev.IsCurrentRGBA());
offscreen.Unmap();
}
m_dev.Recycle(offscreen);
}
}
public:
Device m_dev;
bool m_osd;
bool m_psrr;
int s_n;
@ -384,128 +61,29 @@ public:
bool s_savez;
public:
GSRenderer(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, bool psrr)
: GSRendererBase(base, mt, irq, rs)
, m_psrr(psrr)
GSRenderer(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, bool psrr = true);
virtual ~GSRenderer();
virtual bool Create(const string& title);
virtual void VSync(int field);
virtual void KeyEvent(GSKeyEventData* e);
virtual bool MakeSnapshot(const string& path);
virtual void MinMaxUV(int w, int h, GSVector4i& r)
{
s_n = 0;
s_dump = !!theApp.GetConfig("dump", 0);
s_save = !!theApp.GetConfig("save", 0);
s_savez = !!theApp.GetConfig("savez", 0);
r = GSVector4i(0, 0, w, h);
}
bool Create(const string& title)
virtual bool CanUpscale()
{
if(!m_wnd.Create(title.c_str()))
{
return false;
}
if(!m_dev.Create(m_wnd, m_vsync))
{
return false;
}
Reset();
return true;
return !m_nativeres;
}
void VSync(int field)
{
GSPerfMonAutoTimer pmat(m_perfmon);
Flush();
m_perfmon.Put(GSPerfMon::Frame);
field = field ? 1 : 0;
if(!Merge(field)) return;
// osd
static uint64 s_frame = 0;
static string s_stats;
if(m_perfmon.GetFrame() - s_frame >= 30)
{
m_perfmon.Update();
s_frame = m_perfmon.GetFrame();
double fps = 1000.0f / m_perfmon.Get(GSPerfMon::Frame);
string s = m_regs->SMODE2.INT ? (string("Interlaced ") + (m_regs->SMODE2.FFMD ? "(frame)" : "(field)")) : "Progressive";
GSVector4i r = GetDisplayRect();
s_stats = 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()),
s.c_str(),
GSSettingsDlg::g_interlace[m_interlace].name,
GSSettingsDlg::g_aspectratio[m_aspectratio].name,
(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_stats += format(" | %.2f mpps", fps * fillrate / (1024 * 1024));
}
if(m_capture.IsCapturing())
{
s_stats += " | Recording...";
}
m_wnd.SetWindowText(s_stats.c_str());
}
if(m_osd)
{
m_dev.Draw(s_stats + "\n\nF5: interlace mode\nF6: aspect ratio\nF7: OSD");
}
if(m_frameskip)
{
return;
}
//
if(m_dev.IsLost())
{
ResetDevice();
}
//
GSVector4i r;
m_wnd.GetClientRect(r);
m_dev.Present(r.fit(m_aspectratio));
//
DoSnapshot(field);
DoCapture();
}
virtual void MinMaxUV(int w, int h, GSVector4i& r) {r = GSVector4i(0, 0, w, h);}
virtual bool CanUpscale() {return !m_nativeres;}
};
template<class Device, class Vertex> class GSRendererT : public GSRenderer<Device>
template<class Vertex> class GSRendererT : public GSRenderer
{
protected:
Vertex* m_vertices;
@ -644,7 +222,7 @@ protected:
public:
GSRendererT(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, bool psrr = true)
: GSRenderer<Device>(base, mt, irq, rs, psrr)
: GSRenderer(base, mt, irq, rs, psrr)
, m_count(0)
, m_maxcount(0)
, m_vertices(NULL)

View File

@ -25,16 +25,17 @@
#include "GSTextureCache.h"
#include "GSCrc.h"
template<class Device, class Vertex, class TextureCache>
class GSRendererHW : public GSRendererT<Device, Vertex>
template<class Vertex>
class GSRendererHW : public GSRendererT<Vertex>
{
TextureCache* m_tc;
int m_width;
int m_height;
int m_skip;
bool m_reset;
protected:
GSTextureCache* m_tc;
void Reset()
{
// TODO: GSreset can come from the main thread too => crash
@ -236,7 +237,7 @@ protected:
m_tc->RemoveAll();
}
bool GetOutput(int i, Texture& t)
GSTexture* GetOutput(int i)
{
const GSRegDISPFB& DISPFB = m_regs->DISP[i].DISPFB;
@ -248,7 +249,9 @@ protected:
TRACE(_T("[%d] GetOutput %d %05x (%d)\n"), (int)m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM);
if(GSTextureCache<Device>::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height, true))
GSTexture* t = NULL;
if(GSTextureCache::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height, true))
{
t = rt->m_texture;
@ -256,16 +259,14 @@ protected:
{
if(s_save)
{
rt->m_texture.Save(format("c:\\temp2\\_%05d_f%I64d_fr%d_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM));
t->Save(format("c:\\temp2\\_%05d_f%I64d_fr%d_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM));
}
s_n++;
}
return true;
}
return false;
return t;
}
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
@ -298,15 +299,15 @@ protected:
TEX0.TBW = context->FRAME.FBW;
TEX0.PSM = context->FRAME.PSM;
GSTextureCache<Device>::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height);
GSTextureCache::GSRenderTarget* rt = m_tc->GetRenderTarget(TEX0, m_width, m_height);
TEX0.TBP0 = context->ZBUF.Block();
TEX0.TBW = context->FRAME.FBW;
TEX0.PSM = context->ZBUF.PSM;
GSTextureCache<Device>::GSDepthStencil* ds = m_tc->GetDepthStencil(TEX0, m_width, m_height);
GSTextureCache::GSDepthStencil* ds = m_tc->GetDepthStencil(TEX0, m_width, m_height);
GSTextureCache<Device>::GSTexture* tex = NULL;
GSTextureCache::GSCachedTexture* tex = NULL;
if(PRIM->TME)
{
@ -329,13 +330,13 @@ protected:
(int)context->CLAMP.MINU, (int)context->CLAMP.MAXU,
(int)context->CLAMP.MINV, (int)context->CLAMP.MAXV);
tex->m_texture.Save(s, true);
tex->m_texture->Save(s, true);
if(tex->m_palette)
{
s = format("c:\\temp2\\_%05d_f%I64d_tpx_%05x_%d.dds", s_n, frame, context->TEX0.CBP, context->TEX0.CPSM);
tex->m_palette.Save(s, true);
tex->m_palette->Save(s, true);
}
}
@ -345,14 +346,14 @@ protected:
{
s = format("c:\\temp2\\_%05d_f%I64d_rt0_%05x_%d.bmp", s_n, frame, context->FRAME.Block(), context->FRAME.PSM);
rt->m_texture.Save(s);
rt->m_texture->Save(s);
}
if(s_savez)
{
s = format("c:\\temp2\\_%05d_f%I64d_rz0_%05x_%d.bmp", s_n, frame, context->ZBUF.Block(), context->ZBUF.PSM);
ds->m_texture.Save(s);
ds->m_texture->Save(s);
}
s_n++;
@ -360,7 +361,7 @@ protected:
int prim = PRIM->PRIM;
if(!OverrideInput(prim, rt->m_texture, ds->m_texture, tex ? &tex->m_texture : NULL))
if(!OverrideInput(prim, rt->m_texture, ds->m_texture, tex ? tex->m_texture : NULL))
{
return;
}
@ -379,14 +380,14 @@ protected:
{
s = format("c:\\temp2\\_%05d_f%I64d_rt1_%05x_%d.bmp", s_n, frame, context->FRAME.Block(), context->FRAME.PSM);
rt->m_texture.Save(s);
rt->m_texture->Save(s);
}
if(s_savez)
{
s = format("c:\\temp2\\_%05d_f%I64d_rz1_%05x_%d.bmp", s_n, frame, context->ZBUF.Block(), context->ZBUF.PSM);
ds->m_texture.Save(s);
ds->m_texture->Save(s);
}
s_n++;
@ -395,9 +396,9 @@ protected:
m_tc->InvalidateTextures(context->FRAME, context->ZBUF);
}
virtual void Draw(int prim, Texture& rt, Texture& ds, typename GSTextureCache<Device>::GSTexture* tex) = 0;
virtual void Draw(int prim, GSTexture* rt, GSTexture* ds, typename GSTextureCache::GSCachedTexture* tex) = 0;
virtual bool OverrideInput(int& prim, Texture& rt, Texture& ds, Texture* t)
virtual bool OverrideInput(int& prim, GSTexture* rt, GSTexture* ds, GSTexture* t)
{
#pragma region ffxii pal video conversion
@ -436,7 +437,7 @@ protected:
ok = false;
m_dev.CreateTexture(*t, 512, 512);
t = m_dev->CreateTexture(512, 512);
t->Update(GSVector4i(0, 0, 448, 512), video, 512 * 4);
@ -466,7 +467,7 @@ protected:
if((FBP == 0x00d00 || FBP == 0x00000) && ZBP == 0x02100 && PRIM->TME && TBP == 0x01a00 && m_context->TEX0.PSM == PSM_PSMCT16S)
{
m_dev.ClearDepth(ds, 0);
m_dev->ClearDepth(ds, 0);
}
return true;
@ -556,9 +557,9 @@ protected:
TEX0.TBW = FBW;
TEX0.PSM = FPSM;
if(GSTextureCache<Device>::GSDepthStencil* ds = m_tc->GetDepthStencil(TEX0, m_width, m_height))
if(GSTextureCache::GSDepthStencil* ds = m_tc->GetDepthStencil(TEX0, m_width, m_height))
{
m_dev.ClearDepth(ds->m_texture, 0);
m_dev->ClearDepth(ds->m_texture, 0);
}
return false;
@ -665,7 +666,8 @@ protected:
public:
GSRendererHW(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, bool psrr)
: GSRendererT<Device, Vertex>(base, mt, irq, rs, psrr)
: GSRendererT<Vertex>(base, mt, irq, rs, psrr)
, m_tc(NULL)
, m_width(1024)
, m_height(1024)
, m_skip(0)
@ -676,8 +678,6 @@ public:
m_width = theApp.GetConfig("resx", m_width);
m_height = theApp.GetConfig("resy", m_height);
}
m_tc = new TextureCache(this);
}
virtual ~GSRendererHW()

View File

@ -25,8 +25,11 @@
#include "resource.h"
GSRendererHW10::GSRendererHW10(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs)
: GSRendererHW<Device, Vertex, TextureCache>(base, mt, irq, rs, true)
: GSRendererHW<GSVertexHW10>(base, mt, irq, rs, true)
{
m_dev = new GSDevice10();
m_tc = new GSTextureCache10(this);
InitVertexKick<GSRendererHW10>();
}
@ -35,7 +38,7 @@ bool GSRendererHW10::Create(const string& title)
if(!__super::Create(title))
return false;
if(!m_tfx.Create(&m_dev))
if(!m_tfx.Create((GSDevice10*)m_dev))
return false;
//
@ -57,13 +60,13 @@ bool GSRendererHW10::Create(const string& title)
dsd.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
dsd.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
m_dev->CreateDepthStencilState(&dsd, &m_date.dss);
(*(GSDevice10*)m_dev)->CreateDepthStencilState(&dsd, &m_date.dss);
D3D10_BLEND_DESC bd;
memset(&bd, 0, sizeof(bd));
m_dev->CreateBlendState(&bd, &m_date.bs);
(*(GSDevice10*)m_dev)->CreateBlendState(&bd, &m_date.bs);
//
@ -73,7 +76,7 @@ bool GSRendererHW10::Create(const string& title)
template<uint32 prim, uint32 tme, uint32 fst>
void GSRendererHW10::VertexKick(bool skip)
{
Vertex& dst = m_vl.AddTail();
GSVertexHW10& dst = m_vl.AddTail();
dst.m128i[0] = m_v.m128i[0];
dst.m128i[1] = m_v.m128i[1];
@ -85,7 +88,7 @@ void GSRendererHW10::VertexKick(bool skip)
int count = 0;
if(Vertex* v = DrawingKick<prim>(skip, count))
if(GSVertexHW10* v = DrawingKick<prim>(skip, count))
{
GSVector4i scissor = m_context->scissor.dx10;
@ -169,7 +172,7 @@ void GSRendererHW10::VertexKick(bool skip)
}
}
void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex)
void GSRendererHW10::Draw(int prim, GSTexture* rt, GSTexture* ds, GSTextureCache::GSCachedTexture* tex)
{
GSDrawingEnvironment& env = m_env;
GSDrawingContext* context = m_context;
@ -223,7 +226,7 @@ void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Dev
//
m_dev.BeginScene();
m_dev->BeginScene();
// om
@ -285,8 +288,8 @@ void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Dev
GSTextureFX10::VSConstantBuffer vs_cb;
float sx = 2.0f * rt.m_scale.x / (rt.GetWidth() * 16);
float sy = 2.0f * rt.m_scale.y / (rt.GetHeight() * 16);
float sx = 2.0f * rt->m_scale.x / (rt->GetWidth() * 16);
float sy = 2.0f * rt->m_scale.y / (rt->GetHeight() * 16);
float ox = (float)(int)context->XYOFFSET.OFX;
float oy = (float)(int)context->XYOFFSET.OFY;
@ -396,8 +399,8 @@ void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Dev
__assume(0);
}
float w = (float)tex->m_texture.GetWidth();
float h = (float)tex->m_texture.GetHeight();
float w = (float)tex->m_texture->GetWidth();
float h = (float)tex->m_texture->GetHeight();
ps_cb.WH = GSVector2(w, h);
ps_cb.rWrH = GSVector2(1.0f / w, 1.0f / h);
@ -409,10 +412,10 @@ void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Dev
// rs
int w = rt.GetWidth();
int h = rt.GetHeight();
int w = rt->GetWidth();
int h = rt->GetHeight();
GSVector4i scissor = GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in).rintersect(GSVector4i(0, 0, w, h));
GSVector4i scissor = GSVector4i(GSVector4(rt->m_scale).xyxy() * context->scissor.in).rintersect(GSVector4i(0, 0, w, h));
//
@ -420,9 +423,7 @@ void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Dev
m_tfx.SetupIA(m_vertices, m_count, topology);
m_tfx.SetupVS(vs_sel, &vs_cb);
m_tfx.SetupGS(gs_sel);
m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel,
tex ? (ID3D10ShaderResourceView*)tex->m_texture : NULL,
tex ? (ID3D10ShaderResourceView*)tex->m_palette : NULL);
m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel, tex ? tex->m_texture : NULL, tex ? tex->m_palette : NULL);
m_tfx.SetupRS(w, h, scissor);
// draw
@ -471,7 +472,7 @@ void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Dev
}
}
m_dev.EndScene();
m_dev->EndScene();
}
bool GSRendererHW10::WrapZ(uint32 maxz)
@ -489,112 +490,114 @@ bool GSRendererHW10::WrapZ(uint32 maxz)
return true;
}
void GSRendererHW10::SetupDATE(Texture& rt, Texture& ds)
void GSRendererHW10::SetupDATE(GSTexture* rt, GSTexture* ds)
{
if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000)
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
GSDevice10* dev = (GSDevice10*)m_dev;
GSVector4 mm;
int w = rt->GetWidth();
int h = rt->GetHeight();
// TODO
mm = GSVector4(-1, -1, 1, 1);
// if(m_count < 100)
if(GSTexture* t = dev->CreateRenderTarget(w, h))
{
GSVector4 pmin(65535, 65535, 0, 0);
GSVector4 pmax = GSVector4::zero();
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
for(int i = 0, j = m_count; i < j; i++)
GSVector4 mm;
// TODO
mm = GSVector4(-1, -1, 1, 1);
// if(m_count < 100)
{
GSVector4 p(GSVector4i(m_vertices[i].m128i[0]).uph16());
GSVector4 pmin(65535, 65535, 0, 0);
GSVector4 pmax = GSVector4::zero();
pmin = p.minv(pmin);
pmax = p.maxv(pmax);
for(int i = 0, j = m_count; i < j; i++)
{
GSVector4 p(GSVector4i(m_vertices[i].m128i[0]).uph16());
pmin = p.minv(pmin);
pmax = p.maxv(pmax);
}
mm += pmin.xyxy(pmax);
float sx = 2.0f * rt->m_scale.x / (w * 16);
float sy = 2.0f * rt->m_scale.y / (h * 16);
float ox = (float)(int)m_context->XYOFFSET.OFX;
float oy = (float)(int)m_context->XYOFFSET.OFY;
mm.x = (mm.x - ox) * sx - 1;
mm.y = (mm.y - oy) * sy - 1;
mm.z = (mm.z - ox) * sx - 1;
mm.w = (mm.w - oy) * sy - 1;
if(mm.x < -1) mm.x = -1;
if(mm.y < -1) mm.y = -1;
if(mm.z > +1) mm.z = +1;
if(mm.w > +1) mm.w = +1;
}
mm += pmin.xyxy(pmax);
GSVector4 uv = (mm + 1.0f) / 2.0f;
int w = rt.GetWidth();
int h = rt.GetHeight();
//
float sx = 2.0f * rt.m_scale.x / (w * 16);
float sy = 2.0f * rt.m_scale.y / (h * 16);
float ox = (float)(int)m_context->XYOFFSET.OFX;
float oy = (float)(int)m_context->XYOFFSET.OFY;
dev->BeginScene();
mm.x = (mm.x - ox) * sx - 1;
mm.y = (mm.y - oy) * sy - 1;
mm.z = (mm.z - ox) * sx - 1;
mm.w = (mm.w - oy) * sy - 1;
dev->ClearStencil(ds, 0);
if(mm.x < -1) mm.x = -1;
if(mm.y < -1) mm.y = -1;
if(mm.z > +1) mm.z = +1;
if(mm.w > +1) mm.w = +1;
// om
dev->OMSetDepthStencilState(m_date.dss, 1);
dev->OMSetBlendState(m_date.bs, 0);
dev->OMSetRenderTargets(t, ds);
// ia
GSVertexPT1 vertices[] =
{
{GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)},
{GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)},
{GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)},
{GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)},
};
D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1};
(*dev)->UpdateSubresource(dev->m_convert.vb, 0, &box, vertices, 0, 0);
dev->IASetVertexBuffer(dev->m_convert.vb, sizeof(vertices[0]));
dev->IASetInputLayout(dev->m_convert.il);
dev->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
// vs
dev->VSSetShader(dev->m_convert.vs, NULL);
// gs
dev->GSSetShader(NULL);
// ps
dev->PSSetShaderResources(rt, NULL);
dev->PSSetShader(dev->m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL);
dev->PSSetSamplerState(dev->m_convert.pt, NULL);
// rs
dev->RSSet(w, h);
// set
dev->DrawPrimitive(countof(vertices));
//
dev->EndScene();
dev->Recycle(t);
}
GSVector4 uv = (mm + 1.0f) / 2.0f;
//
m_dev.BeginScene();
// om
GSTexture10 tmp;
m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight());
m_dev.OMSetRenderTargets(tmp, ds);
m_dev.OMSetDepthStencilState(m_date.dss, 1);
m_dev.OMSetBlendState(m_date.bs, 0);
m_dev->ClearDepthStencilView(ds, D3D10_CLEAR_STENCIL, 0, 0);
// ia
GSVertexPT1 vertices[] =
{
{GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)},
{GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)},
{GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)},
{GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)},
};
D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1};
m_dev->UpdateSubresource(m_dev.m_convert.vb, 0, &box, vertices, 0, 0);
m_dev.IASetVertexBuffer(m_dev.m_convert.vb, sizeof(vertices[0]));
m_dev.IASetInputLayout(m_dev.m_convert.il);
m_dev.IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
// vs
m_dev.VSSetShader(m_dev.m_convert.vs, NULL);
// gs
m_dev.GSSetShader(NULL);
// ps
m_dev.PSSetShaderResources(rt, NULL);
m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL);
m_dev.PSSetSamplerState(m_dev.m_convert.pt, NULL);
// rs
m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight());
// set
m_dev.DrawPrimitive(countof(vertices));
//
m_dev.EndScene();
m_dev.Recycle(tmp);
}

View File

@ -26,18 +26,14 @@
#include "GSTextureCache10.h"
#include "GSTextureFX10.h"
class GSRendererHW10 : public GSRendererHW<GSDevice10, GSVertexHW10, GSTextureCache10>
class GSRendererHW10 : public GSRendererHW<GSVertexHW10>
{
typedef GSDevice10 Device;
typedef GSVertexHW10 Vertex;
typedef GSTextureCache10 TextureCache;
bool WrapZ(uint32 maxz);
protected:
GSTextureFX10 m_tfx;
void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex);
void Draw(int prim, GSTexture* rt, GSTexture* ds, GSTextureCache::GSCachedTexture* tex);
struct
{
@ -45,7 +41,7 @@ protected:
CComPtr<ID3D10BlendState> bs;
} m_date;
void SetupDATE(Texture& rt, Texture& ds);
void SetupDATE(GSTexture* rt, GSTexture* ds);
public:
GSRendererHW10(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs);

View File

@ -25,11 +25,14 @@
#include "resource.h"
GSRendererHW9::GSRendererHW9(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs)
: GSRendererHW<Device, Vertex, TextureCache>(base, mt, irq, rs, false)
: GSRendererHW<GSVertexHW9>(base, mt, irq, rs, false)
{
m_fba.enabled = !!theApp.GetConfig("fba", 1);
m_logz = !!theApp.GetConfig("logz", 0);
m_dev = new GSDevice9();
m_tc = new GSTextureCache9(this);
InitVertexKick<GSRendererHW9>();
}
@ -38,7 +41,7 @@ bool GSRendererHW9::Create(const string& title)
if(!__super::Create(title))
return false;
if(!m_tfx.Create(&m_dev))
if(!m_tfx.Create((GSDevice9*)m_dev))
return false;
//
@ -77,7 +80,7 @@ bool GSRendererHW9::Create(const string& title)
template<uint32 prim, uint32 tme, uint32 fst>
void GSRendererHW9::VertexKick(bool skip)
{
Vertex& dst = m_vl.AddTail();
GSVertexHW9& dst = m_vl.AddTail();
dst.p.x = (float)(int)m_v.XYZ.X;
dst.p.y = (float)(int)m_v.XYZ.Y;
@ -102,7 +105,7 @@ void GSRendererHW9::VertexKick(bool skip)
int count = 0;
if(Vertex* v = DrawingKick<prim>(skip, count))
if(GSVertexHW9* v = DrawingKick<prim>(skip, count))
{
GSVector4 scissor = m_context->scissor.dx9;
@ -169,7 +172,7 @@ void GSRendererHW9::VertexKick(bool skip)
}
}
void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex)
void GSRendererHW9::Draw(int prim, GSTexture* rt, GSTexture* ds, GSTextureCache::GSCachedTexture* tex)
{
GSDrawingEnvironment& env = m_env;
GSDrawingContext* context = m_context;
@ -208,9 +211,9 @@ void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Devi
//
m_dev.BeginScene();
m_dev->BeginScene();
m_dev->SetRenderState(D3DRS_SHADEMODE, PRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); // TODO
(*(GSDevice9*)m_dev)->SetRenderState(D3DRS_SHADEMODE, PRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); // TODO
// om
@ -267,8 +270,8 @@ void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Devi
GSTextureFX9::VSConstantBuffer vs_cb;
float sx = 2.0f * rt.m_scale.x / (rt.GetWidth() * 16);
float sy = 2.0f * rt.m_scale.y / (rt.GetHeight() * 16);
float sx = 2.0f * rt->m_scale.x / (rt->GetWidth() * 16);
float sy = 2.0f * rt->m_scale.y / (rt->GetHeight() * 16);
float ox = (float)(int)context->XYOFFSET.OFX;
float oy = (float)(int)context->XYOFFSET.OFY;
@ -370,8 +373,8 @@ void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Devi
__assume(0);
}
float w = (float)tex->m_texture.GetWidth();
float h = (float)tex->m_texture.GetHeight();
float w = (float)tex->m_texture->GetWidth();
float h = (float)tex->m_texture->GetHeight();
ps_cb.WH = GSVector2(w, h);
ps_cb.rWrH = GSVector2(1.0f / w, 1.0f / h);
@ -383,27 +386,24 @@ void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Devi
// rs
int w = rt.GetWidth();
int h = rt.GetHeight();
int w = rt->GetWidth();
int h = rt->GetHeight();
GSVector4i scissor = GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in).rintersect(GSVector4i(0, 0, w, h));
GSVector4i scissor = GSVector4i(GSVector4(rt->m_scale).xyxy() * context->scissor.in).rintersect(GSVector4i(0, 0, w, h));
//
m_tfx.SetupOM(om_dssel, om_bsel, bf, rt, ds);
m_tfx.SetupIA(m_vertices, m_count, topology);
m_tfx.SetupVS(vs_sel, &vs_cb);
m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel,
tex ? (IDirect3DTexture9*)tex->m_texture : NULL,
tex ? (IDirect3DTexture9*)tex->m_palette : NULL,
m_psrr);
m_tfx.SetupPS(ps_sel, &ps_cb, ps_ssel, tex ? tex->m_texture : NULL, tex ? tex->m_palette : NULL, m_psrr);
m_tfx.SetupRS(w, h, scissor);
// draw
if(context->TEST.DoFirstPass())
{
m_dev.DrawPrimitive();
((GSDevice9*)m_dev)->DrawPrimitive();
}
if(context->TEST.DoSecondPass())
@ -441,11 +441,11 @@ void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Devi
m_tfx.UpdateOM(om_dssel, om_bsel, bf);
m_dev.DrawPrimitive();
((GSDevice9*)m_dev)->DrawPrimitive();
}
}
m_dev.EndScene();
m_dev->EndScene();
if(om_dssel.fba) UpdateFBA(rt);
}
@ -465,130 +465,133 @@ bool GSRendererHW9::WrapZ(float maxz)
return true;
}
void GSRendererHW9::SetupDATE(Texture& rt, Texture& ds)
void GSRendererHW9::SetupDATE(GSTexture* rt, GSTexture* ds)
{
if(!m_context->TEST.DATE) return; // || (::GetAsyncKeyState(VK_CONTROL) & 0x8000)
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
GSDevice9* dev = (GSDevice9*)m_dev;
GSVector4 mm;
int w = rt->GetWidth();
int h = rt->GetHeight();
// TODO
mm = GSVector4(-1, -1, 1, 1);
// if(m_count < 100)
if(GSTexture* t = dev->CreateRenderTarget(w, h))
{
GSVector4 pmin(65535, 65535, 0, 0);
GSVector4 pmax = GSVector4::zero();
// sfex3 (after the capcom logo), vf4 (first menu fading in), ffxii shadows, rumble roses shadows, persona4 shadows
for(int i = 0, j = m_count; i < j; i++)
GSVector4 mm;
// TODO
mm = GSVector4(-1, -1, 1, 1);
// if(m_count < 100)
{
GSVector4 p(m_vertices[i].p);
GSVector4 pmin(65535, 65535, 0, 0);
GSVector4 pmax = GSVector4::zero();
pmin = p.minv(pmin);
pmax = p.maxv(pmax);
for(int i = 0, j = m_count; i < j; i++)
{
GSVector4 p(m_vertices[i].p);
pmin = p.minv(pmin);
pmax = p.maxv(pmax);
}
mm += pmin.xyxy(pmax);
float sx = 2.0f * rt->m_scale.x / (w * 16);
float sy = 2.0f * rt->m_scale.y / (h * 16);
float ox = (float)(int)m_context->XYOFFSET.OFX;
float oy = (float)(int)m_context->XYOFFSET.OFY;
mm.x = (mm.x - ox) * sx - 1;
mm.y = (mm.y - oy) * sy - 1;
mm.z = (mm.z - ox) * sx - 1;
mm.w = (mm.w - oy) * sy - 1;
if(mm.x < -1) mm.x = -1;
if(mm.y < -1) mm.y = -1;
if(mm.z > +1) mm.z = +1;
if(mm.w > +1) mm.w = +1;
}
mm += pmin.xyxy(pmax);
GSVector4 uv = (mm + 1.0f) / 2.0f;
int w = rt.GetWidth();
int h = rt.GetHeight();
//
float sx = 2.0f * rt.m_scale.x / (w * 16);
float sy = 2.0f * rt.m_scale.y / (h * 16);
float ox = (float)(int)m_context->XYOFFSET.OFX;
float oy = (float)(int)m_context->XYOFFSET.OFY;
dev->BeginScene();
mm.x = (mm.x - ox) * sx - 1;
mm.y = (mm.y - oy) * sy - 1;
mm.z = (mm.z - ox) * sx - 1;
mm.w = (mm.w - oy) * sy - 1;
dev->ClearStencil(ds, 0);
if(mm.x < -1) mm.x = -1;
if(mm.y < -1) mm.y = -1;
if(mm.z > +1) mm.z = +1;
if(mm.w > +1) mm.w = +1;
// om
dev->OMSetDepthStencilState(&m_date.dss, 1);
dev->OMSetBlendState(&m_date.bs, 0);
dev->OMSetRenderTargets(t, ds);
// ia
GSVertexPT1 vertices[] =
{
{GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)},
{GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)},
{GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)},
{GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)},
};
dev->IASetVertexBuffer(4, vertices);
dev->IASetInputLayout(dev->m_convert.il);
dev->IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP);
// vs
dev->VSSetShader(dev->m_convert.vs, NULL, 0);
// ps
dev->PSSetShaderResources(rt, NULL);
dev->PSSetShader(dev->m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL, 0);
dev->PSSetSamplerState(&dev->m_convert.pt);
// rs
dev->RSSet(w, h);
//
dev->DrawPrimitive();
//
dev->EndScene();
dev->Recycle(t);
}
GSVector4 uv = (mm + 1.0f) / 2.0f;
//
m_dev.BeginScene();
// om
GSTexture9 tmp;
m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight());
m_dev.OMSetRenderTargets(tmp, ds);
m_dev.OMSetDepthStencilState(&m_date.dss, 1);
m_dev.OMSetBlendState(&m_date.bs, 0);
m_dev->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 0, 0);
// ia
GSVertexPT1 vertices[] =
{
{GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)},
{GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)},
{GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)},
{GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)},
};
m_dev.IASetVertexBuffer(4, vertices);
m_dev.IASetInputLayout(m_dev.m_convert.il);
m_dev.IASetPrimitiveTopology(D3DPT_TRIANGLESTRIP);
// vs
m_dev.VSSetShader(m_dev.m_convert.vs, NULL, 0);
// ps
m_dev.PSSetShaderResources(rt, NULL);
m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL, 0);
m_dev.PSSetSamplerState(&m_dev.m_convert.pt);
// rs
m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight());
//
m_dev.DrawPrimitive();
//
m_dev.EndScene();
m_dev.Recycle(tmp);
}
void GSRendererHW9::UpdateFBA(Texture& rt)
void GSRendererHW9::UpdateFBA(GSTexture* rt)
{
m_dev.BeginScene();
GSDevice9* dev = (GSDevice9*)m_dev;
dev->BeginScene();
// om
m_dev.OMSetDepthStencilState(&m_fba.dss, 2);
m_dev.OMSetBlendState(&m_fba.bs, 0);
dev->OMSetDepthStencilState(&m_fba.dss, 2);
dev->OMSetBlendState(&m_fba.bs, 0);
// vs
m_dev.VSSetShader(NULL, NULL, 0);
dev->VSSetShader(NULL, NULL, 0);
// ps
m_dev.PSSetShader(m_dev.m_convert.ps[4], NULL, 0);
dev->PSSetShader(dev->m_convert.ps[4], NULL, 0);
//
int w = rt.GetWidth();
int h = rt.GetHeight();
int w = rt->GetWidth();
int h = rt->GetHeight();
GSVertexP vertices[] =
{
@ -598,11 +601,11 @@ void GSRendererHW9::UpdateFBA(Texture& rt)
{GSVector4(w, h, 0, 0)},
};
m_dev->SetFVF(D3DFVF_XYZRHW);
(*dev)->SetFVF(D3DFVF_XYZRHW);
m_dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertices, sizeof(vertices[0]));
(*dev)->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertices, sizeof(vertices[0]));
//
m_dev.EndScene();
dev->EndScene();
}

View File

@ -26,19 +26,15 @@
#include "GSTextureCache9.h"
#include "GSTextureFX9.h"
class GSRendererHW9 : public GSRendererHW<GSDevice9, GSVertexHW9, GSTextureCache9>
class GSRendererHW9 : public GSRendererHW<GSVertexHW9>
{
typedef GSDevice9 Device;
typedef GSVertexHW9 Vertex;
typedef GSTextureCache9 TextureCache;
bool WrapZ(float maxz);
protected:
GSTextureFX9 m_tfx;
bool m_logz;
void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex);
void Draw(int prim, GSTexture* rt, GSTexture* ds, GSTextureCache::GSCachedTexture* tex);
struct
{
@ -53,8 +49,8 @@ protected:
Direct3DBlendState9 bs;
} m_fba;
void SetupDATE(Texture& rt, Texture& ds);
void UpdateFBA(Texture& rt);
void SetupDATE(GSTexture* rt, GSTexture* ds);
void UpdateFBA(GSTexture* rt);
public:
GSRendererHW9(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs);

View File

@ -24,23 +24,25 @@
#include "GSRenderer.h"
#include "GSDeviceNull.h"
template<class Device> class GSRendererNull : public GSRendererT<Device, GSVertexNull>
class GSRendererNull : public GSRendererT<GSVertexNull>
{
protected:
void Draw()
{
}
bool GetOutput(int i, Texture& t)
GSTexture* GetOutput(int i)
{
return false;
return NULL;
}
public:
GSRendererNull(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs)
: GSRendererT<Device, GSVertexNull>(base, mt, irq, rs)
GSRendererNull(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, GSDevice* dev)
: GSRendererT<GSVertexNull>(base, mt, irq, rs)
{
InitVertexKick<GSRendererNull<Device> >();
m_dev = dev;
InitVertexKick<GSRendererNull>();
}
template<uint32 prim, uint32 tme, uint32 fst> void VertexKick(bool skip)

View File

@ -23,3 +23,775 @@
#include "GSRendererSW.h"
const GSVector4 g_pos_scale(1.0f / 16, 1.0f / 16, 1.0f, 128.0f);
GSRendererSW::GSRendererSW(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, GSDevice* dev, int threads)
: GSRendererT(base, mt, irq, rs)
{
m_dev = dev;
m_tc = new GSTextureCacheSW(this);
memset(m_texture, 0, sizeof(m_texture));
m_rl.Create<GSDrawScanline>(this, threads);
InitVertexKick<GSRendererSW>();
}
GSRendererSW::~GSRendererSW()
{
delete m_tc;
}
void GSRendererSW::Reset()
{
// TODO: GSreset can come from the main thread too => crash
// m_tc->RemoveAll();
m_reset = true;
__super::Reset();
}
void GSRendererSW::VSync(int field)
{
__super::VSync(field);
m_tc->IncAge();
if(m_reset)
{
m_tc->RemoveAll();
m_reset = false;
}
// if((m_perfmon.GetFrame() & 255) == 0) m_rl.PrintStats();
}
void GSRendererSW::ResetDevice()
{
for(int i = 0; i < countof(m_texture); i++)
{
delete m_texture[i];
m_texture[i] = NULL;
}
}
GSTexture* GSRendererSW::GetOutput(int i)
{
const GSRegDISPFB& DISPFB = m_regs->DISP[i].DISPFB;
GIFRegTEX0 TEX0;
TEX0.TBP0 = DISPFB.Block();
TEX0.TBW = DISPFB.FBW;
TEX0.PSM = DISPFB.PSM;
GSVector4i r(0, 0, TEX0.TBW * 64, GetFrameRect(i).bottom);
// TODO: round up bottom
int w = r.width();
int h = r.height();
if(m_texture[i])
{
if(m_texture[i]->GetWidth() != w || m_texture[i]->GetHeight() != h)
{
delete m_texture[i];
m_texture[i] = NULL;
}
}
if(!m_texture[i])
{
m_texture[i] = m_dev->CreateTexture(w, h);
if(!m_texture[i])
{
return NULL;
}
}
GIFRegCLAMP CLAMP;
CLAMP.WMS = CLAMP.WMT = 1;
// TODO
static uint8* buff = (uint8*)_aligned_malloc(1024 * 1024 * 4, 16);
static int pitch = 1024 * 4;
m_mem.ReadTexture(r, buff, pitch, TEX0, m_env.TEXA, CLAMP);
m_texture[i]->Update(r, buff, pitch);
if(s_dump)
{
if(s_save)
{
m_texture[i]->Save(format("c:\\temp1\\_%05d_f%I64d_fr%d_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM));
}
s_n++;
}
return m_texture[i];
}
void GSRendererSW::Draw()
{
GS_PRIM_CLASS primclass = GSUtil::GetPrimClass(PRIM->PRIM);
m_vtrace.Update(m_vertices, m_count, primclass, PRIM->IIP, PRIM->TME, m_context->TEX0.TFX, m_context->TEX0.TCC);
if(m_dump)
{
m_dump.Object(m_vertices, m_count, primclass);
}
GSScanlineParam p;
GetScanlineParam(p, primclass);
if((p.fm & p.zm) == 0xffffffff)
{
return;
}
if(s_dump)
{
uint64 frame = m_perfmon.GetFrame();
string s;
if(s_save && PRIM->TME)
{
s = format("c:\\temp1\\_%05d_f%I64d_tex_%05x_%d.bmp", s_n, frame, (int)m_context->TEX0.TBP0, (int)m_context->TEX0.PSM);
m_mem.SaveBMP(s, m_context->TEX0.TBP0, m_context->TEX0.TBW, m_context->TEX0.PSM, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH);
}
s_n++;
if(s_save)
{
s = format("c:\\temp1\\_%05d_f%I64d_rt0_%05x_%d.bmp", s_n, frame, m_context->FRAME.Block(), m_context->FRAME.PSM);
m_mem.SaveBMP(s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameRect().width(), 512);//GetFrameSize(1).cy);
}
if(s_savez)
{
s = format("c:\\temp1\\_%05d_f%I64d_rz0_%05x_%d.bmp", s_n, frame, m_context->ZBUF.Block(), m_context->ZBUF.PSM);
m_mem.SaveBMP(s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameRect().width(), 512);
}
s_n++;
}
GSRasterizerData data;
data.scissor = GSVector4i(m_context->scissor.in);
data.scissor.z = min(data.scissor.z, (int)m_context->FRAME.FBW * 64); // TODO: find a game that overflows and check which one is the right behaviour
data.primclass = primclass;
data.vertices = m_vertices;
data.count = m_count;
data.param = &p;
m_rl.Draw(&data);
GSRasterizerStats stats;
m_rl.GetStats(stats);
m_perfmon.Put(GSPerfMon::Draw, 1);
m_perfmon.Put(GSPerfMon::Prim, stats.prims);
m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels);
GSVector4i r = GSVector4i(m_vtrace.m_min.p.xyxy(m_vtrace.m_max.p)).rintersect(data.scissor);
GIFRegBITBLTBUF BITBLTBUF;
BITBLTBUF.DBW = m_context->FRAME.FBW;
if(p.fm != 0xffffffff)
{
BITBLTBUF.DBP = m_context->FRAME.Block();
BITBLTBUF.DPSM = m_context->FRAME.PSM;
m_tc->InvalidateVideoMem(BITBLTBUF, r);
}
if(p.zm != 0xffffffff)
{
BITBLTBUF.DBP = m_context->ZBUF.Block();
BITBLTBUF.DPSM = m_context->ZBUF.PSM;
m_tc->InvalidateVideoMem(BITBLTBUF, r);
}
if(s_dump)
{
uint64 frame = m_perfmon.GetFrame();
string s;
if(s_save)
{
s = format("c:\\temp1\\_%05d_f%I64d_rt1_%05x_%d.bmp", s_n, frame, m_context->FRAME.Block(), m_context->FRAME.PSM);
m_mem.SaveBMP(s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameRect().width(), 512);//GetFrameSize(1).cy);
}
if(s_savez)
{
s = format("c:\\temp1\\_%05d_f%I64d_rz1_%05x_%d.bmp", s_n, frame, m_context->ZBUF.Block(), m_context->ZBUF.PSM);
m_mem.SaveBMP(s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameRect().width(), 512);
}
s_n++;
}
if(0)//stats.ticks > 5000000)
{
printf("* [%I64d | %012I64x] ticks %I64d prims %d (%d) pixels %d (%d)\n",
m_perfmon.GetFrame(), p.sel.key,
stats.ticks,
stats.prims, stats.prims > 0 ? (int)(stats.ticks / stats.prims) : -1,
stats.pixels, stats.pixels > 0 ? (int)(stats.ticks / stats.pixels) : -1);
}
}
void GSRendererSW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
{
m_tc->InvalidateVideoMem(BITBLTBUF, r);
}
void GSRendererSW::GetTextureMinMax(int w, int h, GSVector4i& r, uint32 fst)
{
const GSDrawingContext* context = m_context;
int wms = context->CLAMP.WMS;
int wmt = context->CLAMP.WMT;
int minu = (int)context->CLAMP.MINU;
int minv = (int)context->CLAMP.MINV;
int maxu = (int)context->CLAMP.MAXU;
int maxv = (int)context->CLAMP.MAXV;
GSVector4i vr(0, 0, w, h);
switch(wms)
{
case CLAMP_REPEAT:
break;
case CLAMP_CLAMP:
break;
case CLAMP_REGION_CLAMP:
if(vr.x < minu) vr.x = minu;
if(vr.z > maxu + 1) vr.z = maxu + 1;
break;
case CLAMP_REGION_REPEAT:
vr.x = maxu;
vr.z = vr.x + (minu + 1);
break;
default:
__assume(0);
}
switch(wmt)
{
case CLAMP_REPEAT:
break;
case CLAMP_CLAMP:
break;
case CLAMP_REGION_CLAMP:
if(vr.y < minv) vr.y = minv;
if(vr.w > maxv + 1) vr.w = maxv + 1;
break;
case CLAMP_REGION_REPEAT:
vr.y = maxv;
vr.w = vr.y + (minv + 1);
break;
default:
__assume(0);
}
if(fst)
{
GSVector4i uv = GSVector4i(m_vtrace.m_min.t.xyxy(m_vtrace.m_max.t)).sra32(16);
GSVector4i u, v;
int mask = 0;
if(wms == CLAMP_REPEAT || wmt == CLAMP_REPEAT)
{
int tw = context->TEX0.TW;
int th = context->TEX0.TH;
u = uv & GSVector4i::xffffffff().srl32(32 - tw);
v = uv & GSVector4i::xffffffff().srl32(32 - th);
GSVector4i uu = uv.sra32(tw);
GSVector4i vv = uv.sra32(th);
mask = (uu.upl32(vv) == uu.uph32(vv)).mask();
}
switch(wms)
{
case CLAMP_REPEAT:
if(mask & 0x000f) {if(vr.x < u.x) vr.x = u.x; if(vr.z > u.z + 1) vr.z = u.z + 1;}
break;
case CLAMP_CLAMP:
case CLAMP_REGION_CLAMP:
if(vr.x < uv.x) vr.x = uv.x;
if(vr.z > uv.z + 1) vr.z = uv.z + 1;
break;
case CLAMP_REGION_REPEAT: // TODO
break;
default:
__assume(0);
}
switch(wmt)
{
case CLAMP_REPEAT:
if(mask & 0xf000) {if(vr.y < v.y) vr.y = v.y; if(vr.w > v.w + 1) vr.w = v.w + 1;}
break;
case CLAMP_CLAMP:
case CLAMP_REGION_CLAMP:
if(vr.y < uv.y) vr.y = uv.y;
if(vr.w > uv.w + 1) vr.w = uv.w + 1;
break;
case CLAMP_REGION_REPEAT: // TODO
break;
default:
__assume(0);
}
}
r = vr.rintersect(GSVector4i(0, 0, w, h));
}
void GSRendererSW::GetAlphaMinMax()
{
if(m_vtrace.m_alpha.valid)
{
return;
}
const GSDrawingEnvironment& env = m_env;
const GSDrawingContext* context = m_context;
GSVector4i a = GSVector4i(m_vtrace.m_min.c.wwww(m_vtrace.m_max.c)) >> 7;
if(PRIM->TME && context->TEX0.TCC)
{
uint32 bpp = GSLocalMemory::m_psm[context->TEX0.PSM].trbpp;
uint32 cbpp = GSLocalMemory::m_psm[context->TEX0.CPSM].trbpp;
uint32 pal = GSLocalMemory::m_psm[context->TEX0.PSM].pal;
if(bpp == 32)
{
a.y = 0;
a.w = 0xff;
}
else if(bpp == 24)
{
a.y = env.TEXA.AEM ? 0 : env.TEXA.TA0;
a.w = env.TEXA.TA0;
}
else if(bpp == 16)
{
a.y = env.TEXA.AEM ? 0 : min(env.TEXA.TA0, env.TEXA.TA1);
a.w = max(env.TEXA.TA0, env.TEXA.TA1);
}
else
{
m_mem.m_clut.GetAlphaMinMax32(a.y, a.w);
}
switch(context->TEX0.TFX)
{
case TFX_MODULATE:
a.x = (a.x * a.y) >> 7;
a.z = (a.z * a.w) >> 7;
if(a.x > 0xff) a.x = 0xff;
if(a.z > 0xff) a.z = 0xff;
break;
case TFX_DECAL:
a.x = a.y;
a.z = a.w;
break;
case TFX_HIGHLIGHT:
a.x = a.x + a.y;
a.z = a.z + a.w;
if(a.x > 0xff) a.x = 0xff;
if(a.z > 0xff) a.z = 0xff;
break;
case TFX_HIGHLIGHT2:
a.x = a.y;
a.z = a.w;
break;
default:
__assume(0);
}
}
m_vtrace.m_alpha.min = a.x;
m_vtrace.m_alpha.max = a.z;
m_vtrace.m_alpha.valid = true;
}
bool GSRendererSW::TryAlphaTest(uint32& fm, uint32& zm)
{
const GSDrawingContext* context = m_context;
bool pass = true;
if(context->TEST.ATST == ATST_NEVER)
{
pass = false;
}
else if(context->TEST.ATST != ATST_ALWAYS)
{
GetAlphaMinMax();
int amin = m_vtrace.m_alpha.min;
int amax = m_vtrace.m_alpha.max;
int aref = context->TEST.AREF;
switch(context->TEST.ATST)
{
case ATST_NEVER:
pass = false;
break;
case ATST_ALWAYS:
pass = true;
break;
case ATST_LESS:
if(amax < aref) pass = true;
else if(amin >= aref) pass = false;
else return false;
break;
case ATST_LEQUAL:
if(amax <= aref) pass = true;
else if(amin > aref) pass = false;
else return false;
break;
case ATST_EQUAL:
if(amin == aref && amax == aref) pass = true;
else if(amin > aref || amax < aref) pass = false;
else return false;
break;
case ATST_GEQUAL:
if(amin >= aref) pass = true;
else if(amax < aref) pass = false;
else return false;
break;
case ATST_GREATER:
if(amin > aref) pass = true;
else if(amax <= aref) pass = false;
else return false;
break;
case ATST_NOTEQUAL:
if(amin == aref && amax == aref) pass = false;
else if(amin > aref || amax < aref) pass = true;
else return false;
break;
default:
__assume(0);
}
}
if(!pass)
{
switch(context->TEST.AFAIL)
{
case AFAIL_KEEP: fm = zm = 0xffffffff; break;
case AFAIL_FB_ONLY: zm = 0xffffffff; break;
case AFAIL_ZB_ONLY: fm = 0xffffffff; break;
case AFAIL_RGB_ONLY: fm |= 0xff000000; zm = 0xffffffff; break;
default: __assume(0);
}
}
return true;
}
void GSRendererSW::GetScanlineParam(GSScanlineParam& p, GS_PRIM_CLASS primclass)
{
const GSDrawingEnvironment& env = m_env;
const GSDrawingContext* context = m_context;
p.vm = m_mem.m_vm8;
p.fbo = m_mem.GetOffset(context->FRAME.Block(), context->FRAME.FBW, context->FRAME.PSM);
p.zbo = m_mem.GetOffset(context->ZBUF.Block(), context->FRAME.FBW, context->ZBUF.PSM);
p.fzbo = m_mem.GetOffset4(context->FRAME, context->ZBUF);
p.sel.key = 0;
p.sel.fpsm = 3;
p.sel.zpsm = 3;
p.sel.atst = ATST_ALWAYS;
p.sel.tfx = TFX_NONE;
p.sel.ababcd = 255;
p.sel.sprite = primclass == GS_SPRITE_CLASS ? 1 : 0;
p.fm = context->FRAME.FBMSK;
p.zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0;
if(context->TEST.ZTE && context->TEST.ZTST == ZTST_NEVER)
{
p.fm = 0xffffffff;
p.zm = 0xffffffff;
}
if(PRIM->TME)
{
m_mem.m_clut.Read32(context->TEX0, env.TEXA);
}
if(context->TEST.ATE)
{
if(!TryAlphaTest(p.fm, p.zm))
{
p.sel.atst = context->TEST.ATST;
p.sel.afail = context->TEST.AFAIL;
}
}
bool fwrite = p.fm != 0xffffffff;
bool ftest = p.sel.atst != ATST_ALWAYS || context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24;
p.sel.fwrite = fwrite;
p.sel.ftest = ftest;
if(fwrite || ftest)
{
p.sel.fpsm = GSUtil::EncodePSM(context->FRAME.PSM);
if((primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS) && m_vtrace.m_eq.rgba != 15)
{
p.sel.iip = PRIM->IIP;
}
if(PRIM->TME)
{
p.sel.tfx = context->TEX0.TFX;
p.sel.tcc = context->TEX0.TCC;
p.sel.fst = PRIM->FST;
p.sel.ltf = context->TEX1.IsLinear();
p.sel.tlu = GSLocalMemory::m_psm[context->TEX0.PSM].pal > 0;
p.sel.wms = context->CLAMP.WMS;
p.sel.wmt = context->CLAMP.WMT;
if(p.sel.iip == 0 && p.sel.tfx == TFX_MODULATE && p.sel.tcc)
{
if(m_vtrace.m_eq.rgba == 15 && (m_vtrace.m_min.c == GSVector4(128.0f * 128.0f)).alltrue())
{
// modulate does not do anything when vertex color is 0x80
p.sel.tfx = TFX_DECAL;
}
}
if(p.sel.fst == 0)
{
// skip per pixel division if q is constant
GSVertexSW* v = m_vertices;
if(m_vtrace.m_eq.q)
{
p.sel.fst = 1;
if(v[0].t.z != 1.0f)
{
GSVector4 w = v[0].t.zzzz().rcpnr();
for(int i = 0, j = m_count; i < j; i++)
{
v[i].t *= w;
}
m_vtrace.m_min.t *= w;
m_vtrace.m_max.t *= w;
}
}
else if(primclass == GS_SPRITE_CLASS)
{
p.sel.fst = 1;
GSVector4 tmin = GSVector4(FLT_MAX);
GSVector4 tmax = GSVector4(-FLT_MAX);
for(int i = 0, j = m_count; i < j; i += 2)
{
GSVector4 w = v[i + 1].t.zzzz().rcpnr();
GSVector4 v0 = v[i + 0].t * w;
GSVector4 v1 = v[i + 1].t * w;
v[i + 0].t = v0;
v[i + 1].t = v1;
tmin = tmin.minv(v0).minv(v1);
tmax = tmax.maxv(v0).maxv(v1);
}
m_vtrace.m_max.t = tmax;
m_vtrace.m_min.t = tmin;
}
}
if(p.sel.fst)
{
// if q is constant we can do the half pel shift for bilinear sampling on the vertices
if(p.sel.ltf)
{
GSVector4 half(0x8000, 0x8000);
GSVertexSW* v = m_vertices;
for(int i = 0, j = m_count; i < j; i++)
{
v[i].t -= half;
}
m_vtrace.m_min.t -= half;
m_vtrace.m_max.t += half;
}
}
/*
else
{
GSVector4 tmin = GSVector4(FLT_MAX);
GSVector4 tmax = GSVector4(-FLT_MAX);
GSVertexSW* v = m_vertices;
for(int i = 0, j = m_count; i < j; i++)
{
GSVector4 v0 = v[i].t * v[i].t.zzzz().rcpnr();
tmin = tmin.minv(v0);
tmax = tmax.maxv(v0);
}
if(p.sel.ltf)
{
GSVector4 half(0x8000, 0x8000);
tmin -= half;
tmax += half;
}
m_vtrace.min.t = tmin;
m_vtrace.max.t = tmax;
}
*/
int w = 1 << context->TEX0.TW;
int h = 1 << context->TEX0.TH;
GSVector4i r;
GetTextureMinMax(w, h, r, p.sel.fst);
const GSTextureCacheSW::GSTexture* t = m_tc->Lookup(context->TEX0, env.TEXA, r);
if(!t) {ASSERT(0); return;}
p.tex = t->m_buff;
p.clut = m_mem.m_clut;
p.tw = t->m_tw;
}
p.sel.fge = PRIM->FGE;
if(context->FRAME.PSM != PSM_PSMCT24)
{
p.sel.date = context->TEST.DATE;
p.sel.datm = context->TEST.DATM;
}
int amin = 0, amax = 0xff;
if(PRIM->ABE && context->ALPHA.A != context->ALPHA.B && !PRIM->AA1)
{
if(context->ALPHA.C == 0)
{
GetAlphaMinMax();
amin = m_vtrace.m_alpha.min;
amax = m_vtrace.m_alpha.max;
}
else if(context->ALPHA.C == 1)
{
if(p.sel.fpsm == 1)
{
amin = amax = 0x80;
}
}
else if(context->ALPHA.C == 1)
{
amin = amax = context->ALPHA.FIX;
}
}
if(PRIM->ABE && !context->ALPHA.IsOpaque(amin, amax) || PRIM->AA1)
{
p.sel.abe = PRIM->ABE;
p.sel.ababcd = context->ALPHA.u32[0];
if(env.PABE.PABE)
{
p.sel.pabe = 1;
}
if(PRIM->AA1 && (primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS))
{
p.sel.aa1 = m_aa1 ? 1 : 0;
}
}
if(p.sel.date
|| p.sel.aba == 1 || p.sel.abb == 1 || p.sel.abc == 1 || p.sel.abd == 1
|| p.sel.atst != ATST_ALWAYS && p.sel.afail == AFAIL_RGB_ONLY
|| p.sel.fpsm == 0 && p.fm != 0 && p.fm != 0xffffffff
|| p.sel.fpsm == 1 && (p.fm & 0x00ffffff) != 0 && (p.fm & 0x00ffffff) != 0x00ffffff
|| p.sel.fpsm == 2 && (p.fm & 0x80f8f8f8) != 0 && (p.fm & 0x80f8f8f8) != 0x80f8f8f8)
{
p.sel.rfb = 1;
}
p.sel.colclamp = env.COLCLAMP.CLAMP;
p.sel.fba = context->FBA.FBA;
p.sel.dthe = env.DTHE.DTHE;
}
bool zwrite = p.zm != 0xffffffff;
bool ztest = context->TEST.ZTE && context->TEST.ZTST > 1;
p.sel.zwrite = zwrite;
p.sel.ztest = ztest;
if(zwrite || ztest)
{
p.sel.zpsm = GSUtil::EncodePSM(context->ZBUF.PSM);
p.sel.ztst = ztest ? context->TEST.ZTST : 1;
p.sel.zoverflow = GSVector4i(m_vtrace.m_max.p).z == 0x80000000;
}
}

View File

@ -27,768 +27,31 @@
extern const GSVector4 g_pos_scale;
template <class Device>
class GSRendererSW : public GSRendererT<Device, GSVertexSW>
class GSRendererSW : public GSRendererT<GSVertexSW>
{
protected:
GSRasterizerList m_rl;
GSTextureCacheSW* m_tc;
GSVertexTrace m_vtrace;
Texture m_texture[2];
GSTexture* m_texture[2];
bool m_reset;
void Reset()
{
// TODO: GSreset can come from the main thread too => crash
// m_tc->RemoveAll();
m_reset = true;
__super::Reset();
}
void VSync(int field)
{
__super::VSync(field);
m_tc->IncAge();
if(m_reset)
{
m_tc->RemoveAll();
m_reset = false;
}
// if((m_perfmon.GetFrame() & 255) == 0) m_rl.PrintStats();
}
void ResetDevice()
{
m_texture[0] = Texture();
m_texture[1] = Texture();
}
bool GetOutput(int i, Texture& t)
{
const GSRegDISPFB& DISPFB = m_regs->DISP[i].DISPFB;
GIFRegTEX0 TEX0;
TEX0.TBP0 = DISPFB.Block();
TEX0.TBW = DISPFB.FBW;
TEX0.PSM = DISPFB.PSM;
GSVector4i r(0, 0, TEX0.TBW * 64, GetFrameRect(i).bottom);
// TODO: round up bottom
if(m_texture[i].GetWidth() != r.width() || m_texture[i].GetHeight() != r.height())
{
m_texture[i] = Texture();
}
if(!m_texture[i] && !m_dev.CreateTexture(m_texture[i], r.width(), r.height()))
{
return false;
}
GIFRegCLAMP CLAMP;
CLAMP.WMS = CLAMP.WMT = 1;
// TODO
static uint8* buff = (uint8*)_aligned_malloc(1024 * 1024 * 4, 16);
static int pitch = 1024 * 4;
m_mem.ReadTexture(r, buff, pitch, TEX0, m_env.TEXA, CLAMP);
m_texture[i].Update(r, buff, pitch);
t = m_texture[i];
if(s_dump)
{
if(s_save)
{
t.Save(format("c:\\temp1\\_%05d_f%I64d_fr%d_%05x_%d.bmp", s_n, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM));
}
s_n++;
}
return true;
}
void GetAlphaMinMax()
{
if(m_vtrace.m_alpha.valid)
{
return;
}
const GSDrawingEnvironment& env = m_env;
const GSDrawingContext* context = m_context;
GSVector4i a = GSVector4i(m_vtrace.m_min.c.wwww(m_vtrace.m_max.c)) >> 7;
if(PRIM->TME && context->TEX0.TCC)
{
uint32 bpp = GSLocalMemory::m_psm[context->TEX0.PSM].trbpp;
uint32 cbpp = GSLocalMemory::m_psm[context->TEX0.CPSM].trbpp;
uint32 pal = GSLocalMemory::m_psm[context->TEX0.PSM].pal;
if(bpp == 32)
{
a.y = 0;
a.w = 0xff;
}
else if(bpp == 24)
{
a.y = env.TEXA.AEM ? 0 : env.TEXA.TA0;
a.w = env.TEXA.TA0;
}
else if(bpp == 16)
{
a.y = env.TEXA.AEM ? 0 : min(env.TEXA.TA0, env.TEXA.TA1);
a.w = max(env.TEXA.TA0, env.TEXA.TA1);
}
else
{
m_mem.m_clut.GetAlphaMinMax32(a.y, a.w);
}
switch(context->TEX0.TFX)
{
case TFX_MODULATE:
a.x = (a.x * a.y) >> 7;
a.z = (a.z * a.w) >> 7;
if(a.x > 0xff) a.x = 0xff;
if(a.z > 0xff) a.z = 0xff;
break;
case TFX_DECAL:
a.x = a.y;
a.z = a.w;
break;
case TFX_HIGHLIGHT:
a.x = a.x + a.y;
a.z = a.z + a.w;
if(a.x > 0xff) a.x = 0xff;
if(a.z > 0xff) a.z = 0xff;
break;
case TFX_HIGHLIGHT2:
a.x = a.y;
a.z = a.w;
break;
default:
__assume(0);
}
}
m_vtrace.m_alpha.min = a.x;
m_vtrace.m_alpha.max = a.z;
m_vtrace.m_alpha.valid = true;
}
bool TryAlphaTest(uint32& fm, uint32& zm)
{
const GSDrawingContext* context = m_context;
bool pass = true;
if(context->TEST.ATST == ATST_NEVER)
{
pass = false;
}
else if(context->TEST.ATST != ATST_ALWAYS)
{
GetAlphaMinMax();
int amin = m_vtrace.m_alpha.min;
int amax = m_vtrace.m_alpha.max;
int aref = context->TEST.AREF;
switch(context->TEST.ATST)
{
case ATST_NEVER:
pass = false;
break;
case ATST_ALWAYS:
pass = true;
break;
case ATST_LESS:
if(amax < aref) pass = true;
else if(amin >= aref) pass = false;
else return false;
break;
case ATST_LEQUAL:
if(amax <= aref) pass = true;
else if(amin > aref) pass = false;
else return false;
break;
case ATST_EQUAL:
if(amin == aref && amax == aref) pass = true;
else if(amin > aref || amax < aref) pass = false;
else return false;
break;
case ATST_GEQUAL:
if(amin >= aref) pass = true;
else if(amax < aref) pass = false;
else return false;
break;
case ATST_GREATER:
if(amin > aref) pass = true;
else if(amax <= aref) pass = false;
else return false;
break;
case ATST_NOTEQUAL:
if(amin == aref && amax == aref) pass = false;
else if(amin > aref || amax < aref) pass = true;
else return false;
break;
default:
__assume(0);
}
}
if(!pass)
{
switch(context->TEST.AFAIL)
{
case AFAIL_KEEP: fm = zm = 0xffffffff; break;
case AFAIL_FB_ONLY: zm = 0xffffffff; break;
case AFAIL_ZB_ONLY: fm = 0xffffffff; break;
case AFAIL_RGB_ONLY: fm |= 0xff000000; zm = 0xffffffff; break;
default: __assume(0);
}
}
return true;
}
void GetScanlineParam(GSScanlineParam& p, GS_PRIM_CLASS primclass)
{
const GSDrawingEnvironment& env = m_env;
const GSDrawingContext* context = m_context;
p.vm = m_mem.m_vm8;
p.fbo = m_mem.GetOffset(context->FRAME.Block(), context->FRAME.FBW, context->FRAME.PSM);
p.zbo = m_mem.GetOffset(context->ZBUF.Block(), context->FRAME.FBW, context->ZBUF.PSM);
p.fzbo = m_mem.GetOffset4(context->FRAME, context->ZBUF);
p.sel.key = 0;
p.sel.fpsm = 3;
p.sel.zpsm = 3;
p.sel.atst = ATST_ALWAYS;
p.sel.tfx = TFX_NONE;
p.sel.ababcd = 255;
p.sel.sprite = primclass == GS_SPRITE_CLASS ? 1 : 0;
p.fm = context->FRAME.FBMSK;
p.zm = context->ZBUF.ZMSK || context->TEST.ZTE == 0 ? 0xffffffff : 0;
if(context->TEST.ZTE && context->TEST.ZTST == ZTST_NEVER)
{
p.fm = 0xffffffff;
p.zm = 0xffffffff;
}
if(PRIM->TME)
{
m_mem.m_clut.Read32(context->TEX0, env.TEXA);
}
if(context->TEST.ATE)
{
if(!TryAlphaTest(p.fm, p.zm))
{
p.sel.atst = context->TEST.ATST;
p.sel.afail = context->TEST.AFAIL;
}
}
bool fwrite = p.fm != 0xffffffff;
bool ftest = p.sel.atst != ATST_ALWAYS || context->TEST.DATE && context->FRAME.PSM != PSM_PSMCT24;
p.sel.fwrite = fwrite;
p.sel.ftest = ftest;
if(fwrite || ftest)
{
p.sel.fpsm = GSUtil::EncodePSM(context->FRAME.PSM);
if((primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS) && m_vtrace.m_eq.rgba != 15)
{
p.sel.iip = PRIM->IIP;
}
if(PRIM->TME)
{
p.sel.tfx = context->TEX0.TFX;
p.sel.tcc = context->TEX0.TCC;
p.sel.fst = PRIM->FST;
p.sel.ltf = context->TEX1.IsLinear();
p.sel.tlu = GSLocalMemory::m_psm[context->TEX0.PSM].pal > 0;
p.sel.wms = context->CLAMP.WMS;
p.sel.wmt = context->CLAMP.WMT;
if(p.sel.iip == 0 && p.sel.tfx == TFX_MODULATE && p.sel.tcc)
{
if(m_vtrace.m_eq.rgba == 15 && (m_vtrace.m_min.c == GSVector4(128.0f * 128.0f)).alltrue())
{
// modulate does not do anything when vertex color is 0x80
p.sel.tfx = TFX_DECAL;
}
}
if(p.sel.fst == 0)
{
// skip per pixel division if q is constant
GSVertexSW* v = m_vertices;
if(m_vtrace.m_eq.q)
{
p.sel.fst = 1;
if(v[0].t.z != 1.0f)
{
GSVector4 w = v[0].t.zzzz().rcpnr();
for(int i = 0, j = m_count; i < j; i++)
{
v[i].t *= w;
}
m_vtrace.m_min.t *= w;
m_vtrace.m_max.t *= w;
}
}
else if(primclass == GS_SPRITE_CLASS)
{
p.sel.fst = 1;
GSVector4 tmin = GSVector4(FLT_MAX);
GSVector4 tmax = GSVector4(-FLT_MAX);
for(int i = 0, j = m_count; i < j; i += 2)
{
GSVector4 w = v[i + 1].t.zzzz().rcpnr();
GSVector4 v0 = v[i + 0].t * w;
GSVector4 v1 = v[i + 1].t * w;
v[i + 0].t = v0;
v[i + 1].t = v1;
tmin = tmin.minv(v0).minv(v1);
tmax = tmax.maxv(v0).maxv(v1);
}
m_vtrace.m_max.t = tmax;
m_vtrace.m_min.t = tmin;
}
}
if(p.sel.fst)
{
// if q is constant we can do the half pel shift for bilinear sampling on the vertices
if(p.sel.ltf)
{
GSVector4 half(0x8000, 0x8000);
GSVertexSW* v = m_vertices;
for(int i = 0, j = m_count; i < j; i++)
{
v[i].t -= half;
}
m_vtrace.m_min.t -= half;
m_vtrace.m_max.t += half;
}
}
/*
else
{
GSVector4 tmin = GSVector4(FLT_MAX);
GSVector4 tmax = GSVector4(-FLT_MAX);
GSVertexSW* v = m_vertices;
for(int i = 0, j = m_count; i < j; i++)
{
GSVector4 v0 = v[i].t * v[i].t.zzzz().rcpnr();
tmin = tmin.minv(v0);
tmax = tmax.maxv(v0);
}
if(p.sel.ltf)
{
GSVector4 half(0x8000, 0x8000);
tmin -= half;
tmax += half;
}
m_vtrace.min.t = tmin;
m_vtrace.max.t = tmax;
}
*/
int w = 1 << context->TEX0.TW;
int h = 1 << context->TEX0.TH;
GSVector4i r;
MinMaxUV(w, h, r, p.sel.fst);
const GSTextureCacheSW::GSTexture* t = m_tc->Lookup(context->TEX0, env.TEXA, r);
if(!t) {ASSERT(0); return;}
p.tex = t->m_buff;
p.clut = m_mem.m_clut;
p.tw = t->m_tw;
}
p.sel.fge = PRIM->FGE;
if(context->FRAME.PSM != PSM_PSMCT24)
{
p.sel.date = context->TEST.DATE;
p.sel.datm = context->TEST.DATM;
}
int amin = 0, amax = 0xff;
if(PRIM->ABE && context->ALPHA.A != context->ALPHA.B && !PRIM->AA1)
{
if(context->ALPHA.C == 0)
{
GetAlphaMinMax();
amin = m_vtrace.m_alpha.min;
amax = m_vtrace.m_alpha.max;
}
else if(context->ALPHA.C == 1)
{
if(p.sel.fpsm == 1)
{
amin = amax = 0x80;
}
}
else if(context->ALPHA.C == 1)
{
amin = amax = context->ALPHA.FIX;
}
}
if(PRIM->ABE && !context->ALPHA.IsOpaque(amin, amax) || PRIM->AA1)
{
p.sel.abe = PRIM->ABE;
p.sel.ababcd = context->ALPHA.u32[0];
if(env.PABE.PABE)
{
p.sel.pabe = 1;
}
if(PRIM->AA1 && (primclass == GS_LINE_CLASS || primclass == GS_TRIANGLE_CLASS))
{
p.sel.aa1 = m_aa1 ? 1 : 0;
}
}
if(p.sel.date
|| p.sel.aba == 1 || p.sel.abb == 1 || p.sel.abc == 1 || p.sel.abd == 1
|| p.sel.atst != ATST_ALWAYS && p.sel.afail == AFAIL_RGB_ONLY
|| p.sel.fpsm == 0 && p.fm != 0 && p.fm != 0xffffffff
|| p.sel.fpsm == 1 && (p.fm & 0x00ffffff) != 0 && (p.fm & 0x00ffffff) != 0x00ffffff
|| p.sel.fpsm == 2 && (p.fm & 0x80f8f8f8) != 0 && (p.fm & 0x80f8f8f8) != 0x80f8f8f8)
{
p.sel.rfb = 1;
}
p.sel.colclamp = env.COLCLAMP.CLAMP;
p.sel.fba = context->FBA.FBA;
p.sel.dthe = env.DTHE.DTHE;
}
bool zwrite = p.zm != 0xffffffff;
bool ztest = context->TEST.ZTE && context->TEST.ZTST > 1;
p.sel.zwrite = zwrite;
p.sel.ztest = ztest;
if(zwrite || ztest)
{
p.sel.zpsm = GSUtil::EncodePSM(context->ZBUF.PSM);
p.sel.ztst = ztest ? context->TEST.ZTST : 1;
p.sel.zoverflow = GSVector4i(m_vtrace.m_max.p).z == 0x80000000;
}
}
void Draw()
{
GS_PRIM_CLASS primclass = GSUtil::GetPrimClass(PRIM->PRIM);
m_vtrace.Update(m_vertices, m_count, primclass, PRIM->IIP, PRIM->TME, m_context->TEX0.TFX, m_context->TEX0.TCC);
if(m_dump)
{
m_dump.Object(m_vertices, m_count, primclass);
}
GSScanlineParam p;
GetScanlineParam(p, primclass);
if((p.fm & p.zm) == 0xffffffff)
{
return;
}
if(s_dump)
{
uint64 frame = m_perfmon.GetFrame();
string s;
if(s_save && PRIM->TME)
{
s = format("c:\\temp1\\_%05d_f%I64d_tex_%05x_%d.bmp", s_n, frame, (int)m_context->TEX0.TBP0, (int)m_context->TEX0.PSM);
m_mem.SaveBMP(s, m_context->TEX0.TBP0, m_context->TEX0.TBW, m_context->TEX0.PSM, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH);
}
s_n++;
if(s_save)
{
s = format("c:\\temp1\\_%05d_f%I64d_rt0_%05x_%d.bmp", s_n, frame, m_context->FRAME.Block(), m_context->FRAME.PSM);
m_mem.SaveBMP(s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameRect().width(), 512);//GetFrameSize(1).cy);
}
if(s_savez)
{
s = format("c:\\temp1\\_%05d_f%I64d_rz0_%05x_%d.bmp", s_n, frame, m_context->ZBUF.Block(), m_context->ZBUF.PSM);
m_mem.SaveBMP(s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameRect().width(), 512);
}
s_n++;
}
GSRasterizerData data;
data.scissor = GSVector4i(m_context->scissor.in);
data.scissor.z = min(data.scissor.z, (int)m_context->FRAME.FBW * 64); // TODO: find a game that overflows and check which one is the right behaviour
data.primclass = primclass;
data.vertices = m_vertices;
data.count = m_count;
data.param = &p;
m_rl.Draw(&data);
GSRasterizerStats stats;
m_rl.GetStats(stats);
m_perfmon.Put(GSPerfMon::Draw, 1);
m_perfmon.Put(GSPerfMon::Prim, stats.prims);
m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels);
GSVector4i r = GSVector4i(m_vtrace.m_min.p.xyxy(m_vtrace.m_max.p)).rintersect(data.scissor);
GIFRegBITBLTBUF BITBLTBUF;
BITBLTBUF.DBW = m_context->FRAME.FBW;
if(p.fm != 0xffffffff)
{
BITBLTBUF.DBP = m_context->FRAME.Block();
BITBLTBUF.DPSM = m_context->FRAME.PSM;
m_tc->InvalidateVideoMem(BITBLTBUF, r);
}
if(p.zm != 0xffffffff)
{
BITBLTBUF.DBP = m_context->ZBUF.Block();
BITBLTBUF.DPSM = m_context->ZBUF.PSM;
m_tc->InvalidateVideoMem(BITBLTBUF, r);
}
if(s_dump)
{
uint64 frame = m_perfmon.GetFrame();
string s;
if(s_save)
{
s = format("c:\\temp1\\_%05d_f%I64d_rt1_%05x_%d.bmp", s_n, frame, m_context->FRAME.Block(), m_context->FRAME.PSM);
m_mem.SaveBMP(s, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameRect().width(), 512);//GetFrameSize(1).cy);
}
if(s_savez)
{
s = format("c:\\temp1\\_%05d_f%I64d_rz1_%05x_%d.bmp", s_n, frame, m_context->ZBUF.Block(), m_context->ZBUF.PSM);
m_mem.SaveBMP(s, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameRect().width(), 512);
}
s_n++;
}
if(0)//stats.ticks > 5000000)
{
printf("* [%I64d | %012I64x] ticks %I64d prims %d (%d) pixels %d (%d)\n",
m_perfmon.GetFrame(), p.sel.key,
stats.ticks,
stats.prims, stats.prims > 0 ? (int)(stats.ticks / stats.prims) : -1,
stats.pixels, stats.pixels > 0 ? (int)(stats.ticks / stats.pixels) : -1);
}
}
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
{
m_tc->InvalidateVideoMem(BITBLTBUF, r);
}
void MinMaxUV(int w, int h, GSVector4i& r, uint32 fst)
{
const GSDrawingContext* context = m_context;
int wms = context->CLAMP.WMS;
int wmt = context->CLAMP.WMT;
int minu = (int)context->CLAMP.MINU;
int minv = (int)context->CLAMP.MINV;
int maxu = (int)context->CLAMP.MAXU;
int maxv = (int)context->CLAMP.MAXV;
GSVector4i vr(0, 0, w, h);
switch(wms)
{
case CLAMP_REPEAT:
break;
case CLAMP_CLAMP:
break;
case CLAMP_REGION_CLAMP:
if(vr.x < minu) vr.x = minu;
if(vr.z > maxu + 1) vr.z = maxu + 1;
break;
case CLAMP_REGION_REPEAT:
vr.x = maxu;
vr.z = vr.x + (minu + 1);
break;
default:
__assume(0);
}
switch(wmt)
{
case CLAMP_REPEAT:
break;
case CLAMP_CLAMP:
break;
case CLAMP_REGION_CLAMP:
if(vr.y < minv) vr.y = minv;
if(vr.w > maxv + 1) vr.w = maxv + 1;
break;
case CLAMP_REGION_REPEAT:
vr.y = maxv;
vr.w = vr.y + (minv + 1);
break;
default:
__assume(0);
}
if(fst)
{
GSVector4i uv = GSVector4i(m_vtrace.m_min.t.xyxy(m_vtrace.m_max.t)).sra32(16);
GSVector4i u, v;
int mask;
if(wms == CLAMP_REPEAT || wmt == CLAMP_REPEAT)
{
int tw = context->TEX0.TW;
int th = context->TEX0.TH;
u = uv & GSVector4i::xffffffff().srl32(32 - tw);
v = uv & GSVector4i::xffffffff().srl32(32 - th);
GSVector4i uu = uv.sra32(tw);
GSVector4i vv = uv.sra32(th);
mask = (uu.upl32(vv) == uu.uph32(vv)).mask();
}
switch(wms)
{
case CLAMP_REPEAT:
if(mask & 0x000f) {if(vr.x < u.x) vr.x = u.x; if(vr.z > u.z + 1) vr.z = u.z + 1;}
break;
case CLAMP_CLAMP:
case CLAMP_REGION_CLAMP:
if(vr.x < uv.x) vr.x = uv.x;
if(vr.z > uv.z + 1) vr.z = uv.z + 1;
break;
case CLAMP_REGION_REPEAT: // TODO
break;
default:
__assume(0);
}
switch(wmt)
{
case CLAMP_REPEAT:
if(mask & 0xf000) {if(vr.y < v.y) vr.y = v.y; if(vr.w > v.w + 1) vr.w = v.w + 1;}
break;
case CLAMP_CLAMP:
case CLAMP_REGION_CLAMP:
if(vr.y < uv.y) vr.y = uv.y;
if(vr.w > uv.w + 1) vr.w = uv.w + 1;
break;
case CLAMP_REGION_REPEAT: // TODO
break;
default:
__assume(0);
}
}
r = vr.rintersect(GSVector4i(0, 0, w, h));
}
void Reset();
void VSync(int field);
void ResetDevice();
GSTexture* GetOutput(int i);
void Draw();
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
void GetTextureMinMax(int w, int h, GSVector4i& r, uint32 fst);
void GetAlphaMinMax();
bool TryAlphaTest(uint32& fm, uint32& zm);
void GetScanlineParam(GSScanlineParam& p, GS_PRIM_CLASS primclass);
public:
GSRendererSW(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, int threads)
: GSRendererT(base, mt, irq, rs)
{
m_rl.Create<GSDrawScanline>(this, threads);
m_tc = new GSTextureCacheSW(this);
InitVertexKick<GSRendererSW<Device> >();
}
virtual ~GSRendererSW()
{
delete m_tc;
}
GSRendererSW(uint8* base, bool mt, void (*irq)(), const GSRendererSettings& rs, GSDevice* dev, int threads);
virtual ~GSRendererSW();
template<uint32 prim, uint32 tme, uint32 fst>
void VertexKick(bool skip)

View File

@ -965,8 +965,6 @@ void GSState::FlushWrite()
void GSState::Write(uint8* mem, int len)
{
int dx = m_env.TRXPOS.DSAX;
int dy = m_env.TRXPOS.DSAY;
int w = m_env.TRXREG.RRW;
int h = m_env.TRXREG.RRH;
@ -1057,6 +1055,8 @@ void GSState::Move()
const GSLocalMemory::psm_t& spsm = GSLocalMemory::m_psm[m_env.BITBLTBUF.SPSM];
const GSLocalMemory::psm_t& dpsm = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM];
// TODO: unroll inner loops (width has special size requirement, must be multiples of 1 << n, depending on the format)
if(spsm.trbpp == dpsm.trbpp && spsm.trbpp >= 16)
{
int* soffset = spsm.rowOffset[0];
@ -2164,6 +2164,7 @@ bool GSC_SonicUnleashed(const GSFrameInfo& fi, int& skip)
return true;
}
bool GSState::IsBadFrame(int& skip)
{
GSFrameInfo fi;

View File

@ -44,5 +44,5 @@ public:
virtual void Unmap() = 0;
virtual bool Save(const string& fn, bool dds = false) = 0;
GSVector2i GetSize() {return GSVector2i(GetWidth(), GetHeight());}
GSVector2i GetSize() const {return GSVector2i(GetWidth(), GetHeight());}
};

View File

@ -21,3 +21,770 @@
#include "StdAfx.h"
#include "GSTextureCache.h"
GSTextureCache::GSTextureCache(GSRenderer* r)
: m_renderer(r)
{
}
GSTextureCache::~GSTextureCache()
{
RemoveAll();
}
void GSTextureCache::RemoveAll()
{
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); i++)
{
delete *i;
}
m_rt.clear();
for(list<GSDepthStencil*>::iterator i = m_ds.begin(); i != m_ds.end(); i++)
{
delete *i;
}
m_ds.clear();
for(list<GSCachedTexture*>::iterator i = m_tex.begin(); i != m_tex.end(); i++)
{
delete *i;
}
m_tex.clear();
}
GSTextureCache::GSRenderTarget* GSTextureCache::GetRenderTarget(const GIFRegTEX0& TEX0, int w, int h, bool fb)
{
GSRenderTarget* rt = NULL;
if(rt == NULL)
{
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); i++)
{
GSRenderTarget* rt2 = *i;
if(rt2->m_TEX0.TBP0 == TEX0.TBP0)
{
m_rt.splice(m_rt.begin(), m_rt, i);
rt = rt2;
if(!fb) rt->m_TEX0 = TEX0;
rt->Update();
break;
}
}
}
if(rt == NULL && fb)
{
// HACK: try to find something close to the base pointer
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); i++)
{
GSRenderTarget* rt2 = *i;
if(rt2->m_TEX0.TBP0 <= TEX0.TBP0 && TEX0.TBP0 < rt2->m_TEX0.TBP0 + 0x700 && (!rt || rt2->m_TEX0.TBP0 >= rt->m_TEX0.TBP0))
{
rt = rt2;
}
}
if(rt)
{
rt->Update();
}
}
if(rt == NULL)
{
rt = CreateRenderTarget();
rt->m_TEX0 = TEX0;
if(!rt->Create(w, h))
{
delete rt;
return NULL;
}
m_rt.push_front(rt);
}
if(m_renderer->CanUpscale())
{
GSVector4i fr = m_renderer->GetFrameRect();
int ww = (int)(fr.left + rt->m_TEX0.TBW * 64);
int hh = (int)(fr.top + m_renderer->GetDisplayRect().height());
if(hh <= m_renderer->GetDeviceSize().y / 2)
{
hh *= 2;
}
if(ww > 0 && hh > 0)
{
rt->m_texture->m_scale.x = (float)w / ww;
rt->m_texture->m_scale.y = (float)h / hh;
}
}
if(!fb)
{
rt->m_used = true;
}
return rt;
}
GSTextureCache::GSDepthStencil* GSTextureCache::GetDepthStencil(const GIFRegTEX0& TEX0, int w, int h)
{
GSDepthStencil* ds = NULL;
if(ds == NULL)
{
for(list<GSDepthStencil*>::iterator i = m_ds.begin(); i != m_ds.end(); i++)
{
GSDepthStencil* ds2 = *i;
if(ds2->m_TEX0.TBP0 == TEX0.TBP0)
{
m_ds.splice(m_ds.begin(), m_ds, i);
ds = ds2;
ds->m_TEX0 = TEX0;
ds->Update();
break;
}
}
}
if(ds == NULL)
{
ds = CreateDepthStencil();
ds->m_TEX0 = TEX0;
if(!ds->Create(w, h))
{
delete ds;
return NULL;
}
m_ds.push_front(ds);
}
if(m_renderer->m_context->DepthWrite())
{
ds->m_used = true;
}
return ds;
}
GSTextureCache::GSCachedTexture* GSTextureCache::GetTexture()
{
const GIFRegTEX0& TEX0 = m_renderer->m_context->TEX0;
const GIFRegCLAMP& CLAMP = m_renderer->m_context->CLAMP;
const uint32* clut = m_renderer->m_mem.m_clut;
const int pal = GSLocalMemory::m_psm[TEX0.PSM].pal;
if(pal > 0)
{
m_renderer->m_mem.m_clut.Read(TEX0);
/*
POSITION pos = m_tex.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSSurface* s = m_tex.GetNext(pos);
if(s->m_TEX0.TBP0 == TEX0.CBP)
{
m_tex.RemoveAt(cur);
delete s;
}
}
pos = m_rt.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSSurface* s = m_rt.GetNext(pos);
if(s->m_TEX0.TBP0 == TEX0.CBP)
{
m_rt.RemoveAt(cur);
delete s;
}
}
pos = m_ds.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSSurface* s = m_ds.GetNext(pos);
if(s->m_TEX0.TBP0 == TEX0.CBP)
{
m_ds.RemoveAt(cur);
delete s;
}
}
*/
}
GSCachedTexture* t = NULL;
for(list<GSCachedTexture*>::iterator i = m_tex.begin(); i != m_tex.end(); i++)
{
t = *i;
if(GSUtil::HasSharedBits(t->m_TEX0.TBP0, t->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM))
{
if(TEX0.PSM == t->m_TEX0.PSM && TEX0.TBW == t->m_TEX0.TBW
&& TEX0.TW == t->m_TEX0.TW && TEX0.TH == t->m_TEX0.TH
&& (m_renderer->m_psrr || (CLAMP.WMS != 3 && t->m_CLAMP.WMS != 3 && CLAMP.WMT != 3 && t->m_CLAMP.WMT != 3 || CLAMP.u64 == t->m_CLAMP.u64))
&& (pal == 0 || TEX0.CPSM == t->m_TEX0.CPSM && GSVector4i::compare(t->m_clut, clut, pal * sizeof(clut[0]))))
{
m_tex.splice(m_tex.begin(), m_tex, i);
break;
}
}
t = NULL;
}
if(t == NULL)
{
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); i++)
{
GSRenderTarget* rt = *i;
if(rt->m_dirty.empty() && GSUtil::HasSharedBits(rt->m_TEX0.TBP0, rt->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM))
{
t = CreateTexture();
if(!t->Create(rt))
{
delete t;
return NULL;
}
m_tex.push_front(t);
break;
}
}
}
if(t == NULL)
{
for(list<GSDepthStencil*>::iterator i = m_ds.begin(); i != m_ds.end(); i++)
{
GSDepthStencil* ds = *i;
if(ds->m_dirty.empty() && ds->m_used && GSUtil::HasSharedBits(ds->m_TEX0.TBP0, ds->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM))
{
t = CreateTexture();
if(!t->Create(ds))
{
delete t;
return NULL;
}
m_tex.push_front(t);
break;
}
}
}
if(t == NULL)
{
t = CreateTexture();
if(!t->Create())
{
delete t;
return NULL;
}
m_tex.push_front(t);
}
if(pal > 0)
{
int size = pal * sizeof(clut[0]);
if(t->m_palette)
{
if(t->m_initpalette)
{
memcpy(t->m_clut, clut, size);
t->m_palette->Update(GSVector4i(0, 0, pal, 1), t->m_clut, size);
t->m_initpalette = false;
}
else
{
if(GSVector4i::update(t->m_clut, clut, size))
{
t->m_palette->Update(GSVector4i(0, 0, pal, 1), t->m_clut, size);
}
}
}
else
{
memcpy(t->m_clut, clut, size);
}
}
t->Update();
return t;
}
void GSTextureCache::InvalidateTextures(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF)
{
for(list<GSCachedTexture*>::iterator i = m_tex.begin(); i != m_tex.end(); )
{
list<GSCachedTexture*>::iterator j = i++;
GSCachedTexture* t = *j;
if(GSUtil::HasSharedBits(FRAME.Block(), FRAME.PSM, t->m_TEX0.TBP0, t->m_TEX0.PSM)
|| GSUtil::HasSharedBits(ZBUF.Block(), ZBUF.PSM, t->m_TEX0.TBP0, t->m_TEX0.PSM))
{
m_tex.erase(j);
delete t;
}
}
}
void GSTextureCache::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
{
bool found = false;
for(list<GSCachedTexture*>::iterator i = m_tex.begin(); i != m_tex.end(); )
{
list<GSCachedTexture*>::iterator j = i++;
GSCachedTexture* t = *j;
if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, t->m_TEX0.TBP0, t->m_TEX0.PSM))
{
if(BITBLTBUF.DBW == t->m_TEX0.TBW && !t->m_rendered)
{
t->m_dirty.push_back(GSDirtyRect(r, BITBLTBUF.DPSM));
found = true;
}
else
{
m_tex.erase(j);
delete t;
}
}
else if(GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, t->m_TEX0.PSM))
{
if(BITBLTBUF.DBW == t->m_TEX0.TBW && !t->m_rendered)
{
int rowsize = (int)BITBLTBUF.DBW * 8192;
int offset = ((int)BITBLTBUF.DBP - (int)t->m_TEX0.TBP0) * 256;
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.y * offset / rowsize;
GSVector4i r2(r.left, r.top + y, r.right, r.bottom + y);
int w = 1 << t->m_TEX0.TW;
int h = 1 << t->m_TEX0.TH;
if(r2.bottom > 0 && r2.top < h && r2.right > 0 && r2.left < w)
{
t->m_dirty.push_back(GSDirtyRect(r2, BITBLTBUF.DPSM));
}
}
}
}
}
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); )
{
list<GSRenderTarget*>::iterator j = i++;
GSRenderTarget* rt = *j;
if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, rt->m_TEX0.TBP0, rt->m_TEX0.PSM))
{
if(!found && GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM))
{
rt->m_dirty.push_back(GSDirtyRect(r, BITBLTBUF.DPSM));
rt->m_TEX0.TBW = BITBLTBUF.DBW;
}
else
{
m_rt.erase(j);
delete rt;
continue;
}
}
if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM) && BITBLTBUF.DBP < rt->m_TEX0.TBP0)
{
uint32 rowsize = BITBLTBUF.DBW * 8192;
uint32 offset = (uint32)((rt->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.y * offset / rowsize;
if(r.bottom > y)
{
// TODO: do not add this rect above too
rt->m_dirty.push_back(GSDirtyRect(GSVector4i(r.left, r.top - y, r.right, r.bottom - y), BITBLTBUF.DPSM));
rt->m_TEX0.TBW = BITBLTBUF.DBW;
continue;
}
}
}
}
// copypaste for ds
for(list<GSDepthStencil*>::iterator i = m_ds.begin(); i != m_ds.end(); )
{
list<GSDepthStencil*>::iterator j = i++;
GSDepthStencil* ds = *j;
if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, ds->m_TEX0.TBP0, ds->m_TEX0.PSM))
{
if(!found && GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM))
{
ds->m_dirty.push_back(GSDirtyRect(r, BITBLTBUF.DPSM));
ds->m_TEX0.TBW = BITBLTBUF.DBW;
}
else
{
m_ds.erase(j);
delete ds;
continue;
}
}
if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM) && BITBLTBUF.DBP < ds->m_TEX0.TBP0)
{
uint32 rowsize = BITBLTBUF.DBW * 8192;
uint32 offset = (uint32)((ds->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.y * offset / rowsize;
if(r.bottom > y)
{
// TODO: do not add this rect above too
ds->m_dirty.push_back(GSDirtyRect(GSVector4i(r.left, r.top - y, r.right, r.bottom - y), BITBLTBUF.DPSM));
ds->m_TEX0.TBW = BITBLTBUF.DBW;
continue;
}
}
}
}
}
void GSTextureCache::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
{
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); )
{
list<GSRenderTarget*>::iterator j = i++;
GSRenderTarget* rt = *j;
if(GSUtil::HasSharedBits(BITBLTBUF.SBP, BITBLTBUF.SPSM, rt->m_TEX0.TBP0, rt->m_TEX0.PSM))
{
if(GSUtil::HasCompatibleBits(BITBLTBUF.SPSM, rt->m_TEX0.PSM))
{
rt->Read(r);
return;
}
else if(BITBLTBUF.SPSM == PSM_PSMCT32 && (rt->m_TEX0.PSM == PSM_PSMCT16 || rt->m_TEX0.PSM == PSM_PSMCT16S))
{
// ffx-2 riku changing to her default (shoots some reflecting glass at the end), 16-bit rt read as 32-bit
rt->Read(GSVector4i(r.left, r.top, r.right, r.top + (r.bottom - r.top) * 2));
return;
}
else
{
m_rt.erase(j);
delete rt;
continue;
}
}
}
/*
// no good, ffx does a lot of readback after exiting menu, at 0x02f00 this wrongly finds rt 0x02100 (0,448 - 512,480)
GSRenderTarget* rt2 = NULL;
int ymin = INT_MAX;
pos = m_rt.GetHeadPosition();
while(pos)
{
GSRenderTarget* rt = m_rt.GetNext(pos);
if(HasSharedBits(BITBLTBUF.SPSM, rt->m_TEX0.PSM) && BITBLTBUF.SBP > rt->m_TEX0.TBP0)
{
// ffx2 pause screen background
uint32 rowsize = BITBLTBUF.SBW * 8192;
uint32 offset = (uint32)((BITBLTBUF.SBP - rt->m_TEX0.TBP0) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.SPSM].pgs.y * offset / rowsize;
if(y < ymin && y < 512)
{
rt2 = rt;
ymin = y;
}
}
}
}
if(rt2)
{
rt2->Read(GSVector4i(r.left, r.top + ymin, r.right, r.bottom + ymin));
}
// TODO: ds
*/
}
void GSTextureCache::IncAge()
{
RecycleByAge(m_tex, 2);
RecycleByAge(m_rt);
RecycleByAge(m_ds);
}
// GSTextureCache::GSSurface
GSTextureCache::GSSurface::GSSurface(GSRenderer* r)
: m_renderer(r)
, m_texture(NULL)
, m_palette(NULL)
, m_initpalette(false)
, m_age(0)
{
m_TEX0.TBP0 = (uint32)~0;
}
GSTextureCache::GSSurface::~GSSurface()
{
m_renderer->m_dev->Recycle(m_texture);
m_renderer->m_dev->Recycle(m_palette);
m_texture = NULL;
m_palette = NULL;
}
void GSTextureCache::GSSurface::Update()
{
m_age = 0;
}
// GSTextureCache::GSRenderTarget
GSTextureCache::GSRenderTarget::GSRenderTarget(GSRenderer* r)
: GSSurface(r)
, m_used(true)
{
}
bool GSTextureCache::GSRenderTarget::Create(int w, int h)
{
// FIXME: initial data should be unswizzled from local mem in Update() if dirty
m_texture = m_renderer->m_dev->CreateRenderTarget(w, h);
return m_texture != NULL;
}
// GSTextureCache::GSDepthStencil
GSTextureCache::GSDepthStencil::GSDepthStencil(GSRenderer* r)
: GSSurface(r)
, m_used(false)
{
}
bool GSTextureCache::GSDepthStencil::Create(int w, int h)
{
// FIXME: initial data should be unswizzled from local mem in Update() if dirty
m_texture = m_renderer->m_dev->CreateDepthStencil(w, h);
return m_texture != NULL;
}
// GSTextureCache::GSCachedTexture
GSTextureCache::GSCachedTexture::GSCachedTexture(GSRenderer* r)
: GSSurface(r)
, m_valid(0, 0, 0, 0)
, m_bpp(0)
, m_bpp2(0)
, m_rendered(false)
{
m_clut = (uint32*)_aligned_malloc(256 * sizeof(uint32), 16);
memset(m_clut, 0, sizeof(m_clut));
}
GSTextureCache::GSCachedTexture::~GSCachedTexture()
{
_aligned_free(m_clut);
}
void GSTextureCache::GSCachedTexture::Update()
{
__super::Update();
if(m_rendered)
{
return;
}
GSVector4i r;
if(!GetDirtyRect(r))
{
return;
}
m_valid = m_valid.runion(r);
static uint8* bits = (uint8*)::_aligned_malloc(1024 * 1024 * 4, 16);
int pitch = ((r.width() + 3) & ~3) * 4;
if(m_renderer->m_psrr)
{
m_renderer->m_mem.ReadTextureNPNC(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP);
}
else
{
m_renderer->m_mem.ReadTextureNP(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP);
}
m_texture->Update(r, bits, pitch);
m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.width() * r.height() * m_bpp >> 3);
}
bool GSTextureCache::GSCachedTexture::GetDirtyRect(GSVector4i& rr)
{
int w = 1 << m_TEX0.TW;
int h = 1 << m_TEX0.TH;
GSVector4i r(0, 0, w, h);
for(list<GSDirtyRect>::iterator i = m_dirty.begin(); i != m_dirty.end(); i++)
{
const GSVector4i& dirty = i->GetDirtyRect(m_TEX0).rintersect(r);
if(!m_valid.rintersect(dirty).rempty())
{
// find the rect having the largest area, outside dirty, inside m_valid
GSVector4i left(m_valid.left, m_valid.top, min(m_valid.right, dirty.left), m_valid.bottom);
GSVector4i top(m_valid.left, m_valid.top, m_valid.right, min(m_valid.bottom, dirty.top));
GSVector4i right(max(m_valid.left, dirty.right), m_valid.top, m_valid.right, m_valid.bottom);
GSVector4i bottom(m_valid.left, max(m_valid.top, dirty.bottom), m_valid.right, m_valid.bottom);
int leftsize = !left.rempty() ? left.width() * left.height() : 0;
int topsize = !top.rempty() ? top.width() * top.height() : 0;
int rightsize = !right.rempty() ? right.width() * right.height() : 0;
int bottomsize = !bottom.rempty() ? bottom.width() * bottom.height() : 0;
// TODO: sort
m_valid =
leftsize > 0 ? left :
topsize > 0 ? top :
rightsize > 0 ? right :
bottomsize > 0 ? bottom :
GSVector4i::zero();
}
}
m_dirty.clear();
m_renderer->MinMaxUV(w, h, r);
if(GSUtil::IsRectInRect(r, m_valid))
{
return false;
}
else if(GSUtil::IsRectInRectH(r, m_valid) && (r.left >= m_valid.left || r.right <= m_valid.right))
{
r.top = m_valid.top;
r.bottom = m_valid.bottom;
if(r.left < m_valid.left) r.right = m_valid.left;
else r.left = m_valid.right; // if(r.right > m_valid.right)
}
else if(GSUtil::IsRectInRectV(r, m_valid) && (r.top >= m_valid.top || r.bottom <= m_valid.bottom))
{
r.left = m_valid.left;
r.right = m_valid.right;
if(r.top < m_valid.top) r.bottom = m_valid.top;
else r.top = m_valid.bottom; // if(r.bottom > m_valid.bottom)
}
else
{
r = r.runion(m_valid);
}
if(r.rempty())
{
return false;
}
rr = r;
return true;
}

View File

@ -23,44 +23,26 @@
#include "GSRenderer.h"
template<class Device> class GSTextureCache
class GSTextureCache
{
typedef typename Device::Texture Texture;
public:
class GSSurface : public GSAlignedClass<16>
{
protected:
GSRenderer<Device>* m_renderer;
typedef typename Device::Texture Texture;
GSRenderer* m_renderer;
public:
Texture m_texture;
Texture m_palette;
GSTexture* m_texture;
GSTexture* m_palette;
bool m_initpalette;
int m_age;
GSDirtyRectList m_dirty;
GIFRegTEX0 m_TEX0;
explicit GSSurface(GSRenderer<Device>* renderer)
: m_renderer(renderer)
, m_age(0)
, m_initpalette(false)
{
m_TEX0.TBP0 = (uint32)~0;
}
explicit GSSurface(GSRenderer* r);
virtual ~GSSurface();
virtual ~GSSurface()
{
m_renderer->m_dev.Recycle(m_texture);
m_renderer->m_dev.Recycle(m_palette);
}
virtual void Update()
{
m_age = 0;
}
virtual void Update();
};
class GSRenderTarget : public GSSurface
@ -68,19 +50,9 @@ public:
public:
bool m_used;
explicit GSRenderTarget(GSRenderer<Device>* renderer)
: GSSurface(renderer)
, m_used(true)
{
}
virtual bool Create(int w, int h)
{
// FIXME: initial data should be unswizzled from local mem in Update() if dirty
return m_renderer->m_dev.CreateRenderTarget(m_texture, w, h);
}
explicit GSRenderTarget(GSRenderer* r);
virtual bool Create(int w, int h);
virtual void Read(const GSVector4i& r) = 0;
};
@ -89,96 +61,15 @@ public:
public:
bool m_used;
explicit GSDepthStencil(GSRenderer<Device>* renderer)
: GSSurface(renderer)
, m_used(false)
{
}
virtual bool Create(int w, int h)
{
// FIXME: initial data should be unswizzled from local mem in Update() if dirty
return m_renderer->m_dev.CreateDepthStencil(m_texture, w, h);
}
explicit GSDepthStencil(GSRenderer* renderer);
virtual bool Create(int w, int h);
};
class GSTexture : public GSSurface
class GSCachedTexture : public GSSurface
{
protected:
bool GetDirtyRect(GSVector4i& rr)
{
int w = 1 << m_TEX0.TW;
int h = 1 << m_TEX0.TH;
GSVector4i r(0, 0, w, h);
for(list<GSDirtyRect>::iterator i = m_dirty.begin(); i != m_dirty.end(); i++)
{
const GSVector4i& dirty = i->GetDirtyRect(m_TEX0).rintersect(r);
if(!m_valid.rintersect(dirty).rempty())
{
// find the rect having the largest area, outside dirty, inside m_valid
GSVector4i left(m_valid.left, m_valid.top, min(m_valid.right, dirty.left), m_valid.bottom);
GSVector4i top(m_valid.left, m_valid.top, m_valid.right, min(m_valid.bottom, dirty.top));
GSVector4i right(max(m_valid.left, dirty.right), m_valid.top, m_valid.right, m_valid.bottom);
GSVector4i bottom(m_valid.left, max(m_valid.top, dirty.bottom), m_valid.right, m_valid.bottom);
int leftsize = !left.rempty() ? left.width() * left.height() : 0;
int topsize = !top.rempty() ? top.width() * top.height() : 0;
int rightsize = !right.rempty() ? right.width() * right.height() : 0;
int bottomsize = !bottom.rempty() ? bottom.width() * bottom.height() : 0;
// TODO: sort
m_valid =
leftsize > 0 ? left :
topsize > 0 ? top :
rightsize > 0 ? right :
bottomsize > 0 ? bottom :
GSVector4i::zero();
}
}
m_dirty.clear();
m_renderer->MinMaxUV(w, h, r);
if(GSUtil::IsRectInRect(r, m_valid))
{
return false;
}
else if(GSUtil::IsRectInRectH(r, m_valid) && (r.left >= m_valid.left || r.right <= m_valid.right))
{
r.top = m_valid.top;
r.bottom = m_valid.bottom;
if(r.left < m_valid.left) r.right = m_valid.left;
else r.left = m_valid.right; // if(r.right > m_valid.right)
}
else if(GSUtil::IsRectInRectV(r, m_valid) && (r.top >= m_valid.top || r.bottom <= m_valid.bottom))
{
r.left = m_valid.left;
r.right = m_valid.right;
if(r.top < m_valid.top) r.bottom = m_valid.top;
else r.top = m_valid.bottom; // if(r.bottom > m_valid.bottom)
}
else
{
r = r.runion(m_valid);
}
if(r.rempty())
{
return false;
}
rr = r;
return true;
}
bool GetDirtyRect(GSVector4i& r);
public:
GIFRegCLAMP m_CLAMP;
@ -188,58 +79,10 @@ public:
int m_bpp2;
bool m_rendered;
explicit GSTexture(GSRenderer<Device>* renderer)
: GSSurface(renderer)
, m_valid(0, 0, 0, 0)
, m_bpp(0)
, m_bpp2(0)
, m_rendered(false)
{
m_clut = (uint32*)_aligned_malloc(256 * sizeof(uint32), 16);
explicit GSCachedTexture(GSRenderer* renderer);
virtual ~GSCachedTexture();
memset(m_clut, 0, sizeof(m_clut));
}
~GSTexture()
{
_aligned_free(m_clut);
}
void Update()
{
__super::Update();
if(m_rendered)
{
return;
}
GSVector4i r;
if(!GetDirtyRect(r))
{
return;
}
m_valid = m_valid.runion(r);
static uint8* bits = (uint8*)::_aligned_malloc(1024 * 1024 * 4, 16);
int pitch = ((r.width() + 3) & ~3) * 4;
if(m_renderer->m_psrr)
{
m_renderer->m_mem.ReadTextureNPNC(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP);
}
else
{
m_renderer->m_mem.ReadTextureNP(r, bits, pitch, m_renderer->m_context->TEX0, m_renderer->m_env.TEXA, m_renderer->m_context->CLAMP);
}
m_texture.Update(r, bits, pitch);
m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.width() * r.height() * m_bpp >> 3);
}
void Update();
virtual bool Create() = 0;
virtual bool Create(GSRenderTarget* rt) = 0;
@ -247,10 +90,11 @@ public:
};
protected:
GSRenderer<Device>* m_renderer;
GSRenderer* m_renderer;
list<GSRenderTarget*> m_rt;
list<GSDepthStencil*> m_ds;
list<GSTexture*> m_tex;
list<GSCachedTexture*> m_tex;
template<class T> void RecycleByAge(list<T*>& l, int maxage = 60)
{
@ -271,586 +115,21 @@ protected:
virtual GSRenderTarget* CreateRenderTarget() = 0;
virtual GSDepthStencil* CreateDepthStencil() = 0;
virtual GSTexture* CreateTexture() = 0;
virtual GSCachedTexture* CreateTexture() = 0;
public:
GSTextureCache(GSRenderer<Device>* renderer)
: m_renderer(renderer)
{
}
GSTextureCache(GSRenderer* r);
virtual ~GSTextureCache();
virtual ~GSTextureCache()
{
RemoveAll();
}
void RemoveAll();
void RemoveAll()
{
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); i++)
{
delete *i;
}
GSRenderTarget* GetRenderTarget(const GIFRegTEX0& TEX0, int w, int h, bool fb = false);
GSDepthStencil* GetDepthStencil(const GIFRegTEX0& TEX0, int w, int h);
GSCachedTexture* GetTexture();
m_rt.clear();
void InvalidateTextures(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF);
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
for(list<GSDepthStencil*>::iterator i = m_ds.begin(); i != m_ds.end(); i++)
{
delete *i;
}
m_ds.clear();
for(list<GSTexture*>::iterator i = m_tex.begin(); i != m_tex.end(); i++)
{
delete *i;
}
m_tex.clear();
}
GSRenderTarget* GetRenderTarget(const GIFRegTEX0& TEX0, int w, int h, bool fb = false)
{
GSRenderTarget* rt = NULL;
if(rt == NULL)
{
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); i++)
{
GSRenderTarget* rt2 = *i;
if(rt2->m_TEX0.TBP0 == TEX0.TBP0)
{
m_rt.splice(m_rt.begin(), m_rt, i);
rt = rt2;
if(!fb) rt->m_TEX0 = TEX0;
rt->Update();
break;
}
}
}
if(rt == NULL && fb)
{
// HACK: try to find something close to the base pointer
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); i++)
{
GSRenderTarget* rt2 = *i;
if(rt2->m_TEX0.TBP0 <= TEX0.TBP0 && TEX0.TBP0 < rt2->m_TEX0.TBP0 + 0x700 && (!rt || rt2->m_TEX0.TBP0 >= rt->m_TEX0.TBP0))
{
rt = rt2;
}
}
if(rt)
{
rt->Update();
}
}
if(rt == NULL)
{
rt = CreateRenderTarget();
rt->m_TEX0 = TEX0;
if(!rt->Create(w, h))
{
delete rt;
return NULL;
}
m_rt.push_front(rt);
}
if(m_renderer->CanUpscale())
{
GSVector4i fr = m_renderer->GetFrameRect();
int ww = (int)(fr.left + rt->m_TEX0.TBW * 64);
int hh = (int)(fr.top + m_renderer->GetDisplayRect().height());
if(hh <= m_renderer->GetDeviceSize().y / 2)
{
hh *= 2;
}
if(ww > 0 && hh > 0)
{
rt->m_texture.m_scale.x = (float)w / ww;
rt->m_texture.m_scale.y = (float)h / hh;
}
}
if(!fb)
{
rt->m_used = true;
}
return rt;
}
GSDepthStencil* GetDepthStencil(const GIFRegTEX0& TEX0, int w, int h)
{
GSDepthStencil* ds = NULL;
if(ds == NULL)
{
for(list<GSDepthStencil*>::iterator i = m_ds.begin(); i != m_ds.end(); i++)
{
GSDepthStencil* ds2 = *i;
if(ds2->m_TEX0.TBP0 == TEX0.TBP0)
{
m_ds.splice(m_ds.begin(), m_ds, i);
ds = ds2;
ds->m_TEX0 = TEX0;
ds->Update();
break;
}
}
}
if(ds == NULL)
{
ds = CreateDepthStencil();
ds->m_TEX0 = TEX0;
if(!ds->Create(w, h))
{
delete ds;
return NULL;
}
m_ds.push_front(ds);
}
if(m_renderer->m_context->DepthWrite())
{
ds->m_used = true;
}
return ds;
}
GSTexture* GetTexture()
{
const GIFRegTEX0& TEX0 = m_renderer->m_context->TEX0;
const GIFRegCLAMP& CLAMP = m_renderer->m_context->CLAMP;
const uint32* clut = m_renderer->m_mem.m_clut;
const int pal = GSLocalMemory::m_psm[TEX0.PSM].pal;
if(pal > 0)
{
m_renderer->m_mem.m_clut.Read(TEX0);
/*
POSITION pos = m_tex.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSSurface* s = m_tex.GetNext(pos);
if(s->m_TEX0.TBP0 == TEX0.CBP)
{
m_tex.RemoveAt(cur);
delete s;
}
}
pos = m_rt.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSSurface* s = m_rt.GetNext(pos);
if(s->m_TEX0.TBP0 == TEX0.CBP)
{
m_rt.RemoveAt(cur);
delete s;
}
}
pos = m_ds.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSSurface* s = m_ds.GetNext(pos);
if(s->m_TEX0.TBP0 == TEX0.CBP)
{
m_ds.RemoveAt(cur);
delete s;
}
}
*/
}
GSTexture* t = NULL;
for(list<GSTexture*>::iterator i = m_tex.begin(); i != m_tex.end(); i++)
{
t = *i;
if(GSUtil::HasSharedBits(t->m_TEX0.TBP0, t->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM))
{
if(TEX0.PSM == t->m_TEX0.PSM && TEX0.TBW == t->m_TEX0.TBW
&& TEX0.TW == t->m_TEX0.TW && TEX0.TH == t->m_TEX0.TH
&& (m_renderer->m_psrr || (CLAMP.WMS != 3 && t->m_CLAMP.WMS != 3 && CLAMP.WMT != 3 && t->m_CLAMP.WMT != 3 || CLAMP.u64 == t->m_CLAMP.u64))
&& (pal == 0 || TEX0.CPSM == t->m_TEX0.CPSM && GSVector4i::compare(t->m_clut, clut, pal * sizeof(clut[0]))))
{
m_tex.splice(m_tex.begin(), m_tex, i);
break;
}
}
t = NULL;
}
if(t == NULL)
{
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); i++)
{
GSRenderTarget* rt = *i;
if(rt->m_dirty.empty() && GSUtil::HasSharedBits(rt->m_TEX0.TBP0, rt->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM))
{
t = CreateTexture();
if(!t->Create(rt))
{
delete t;
return NULL;
}
m_tex.push_front(t);
break;
}
}
}
if(t == NULL)
{
for(list<GSDepthStencil*>::iterator i = m_ds.begin(); i != m_ds.end(); i++)
{
GSDepthStencil* ds = *i;
if(ds->m_dirty.empty() && ds->m_used && GSUtil::HasSharedBits(ds->m_TEX0.TBP0, ds->m_TEX0.PSM, TEX0.TBP0, TEX0.PSM))
{
t = CreateTexture();
if(!t->Create(ds))
{
delete t;
return NULL;
}
m_tex.push_front(t);
break;
}
}
}
if(t == NULL)
{
t = CreateTexture();
if(!t->Create())
{
delete t;
return NULL;
}
m_tex.push_front(t);
}
if(pal > 0)
{
int size = pal * sizeof(clut[0]);
if(t->m_palette)
{
if(t->m_initpalette)
{
memcpy(t->m_clut, clut, size);
t->m_palette.Update(GSVector4i(0, 0, pal, 1), t->m_clut, size);
t->m_initpalette = false;
}
else
{
if(GSVector4i::update(t->m_clut, clut, size))
{
t->m_palette.Update(GSVector4i(0, 0, pal, 1), t->m_clut, size);
}
}
}
else
{
memcpy(t->m_clut, clut, size);
}
}
t->Update();
return t;
}
void InvalidateTextures(const GIFRegFRAME& FRAME, const GIFRegZBUF& ZBUF)
{
for(list<GSTexture*>::iterator i = m_tex.begin(); i != m_tex.end(); )
{
list<GSTexture*>::iterator j = i++;
GSTexture* t = *j;
if(GSUtil::HasSharedBits(FRAME.Block(), FRAME.PSM, t->m_TEX0.TBP0, t->m_TEX0.PSM)
|| GSUtil::HasSharedBits(ZBUF.Block(), ZBUF.PSM, t->m_TEX0.TBP0, t->m_TEX0.PSM))
{
m_tex.erase(j);
delete t;
}
}
}
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
{
bool found = false;
for(list<GSTexture*>::iterator i = m_tex.begin(); i != m_tex.end(); )
{
list<GSTexture*>::iterator j = i++;
GSTexture* t = *j;
if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, t->m_TEX0.TBP0, t->m_TEX0.PSM))
{
if(BITBLTBUF.DBW == t->m_TEX0.TBW && !t->m_rendered)
{
t->m_dirty.push_back(GSDirtyRect(r, BITBLTBUF.DPSM));
found = true;
}
else
{
m_tex.erase(j);
delete t;
}
}
else if(GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, t->m_TEX0.PSM))
{
if(BITBLTBUF.DBW == t->m_TEX0.TBW && !t->m_rendered)
{
int rowsize = (int)BITBLTBUF.DBW * 8192;
int offset = ((int)BITBLTBUF.DBP - (int)t->m_TEX0.TBP0) * 256;
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.y * offset / rowsize;
GSVector4i r2(r.left, r.top + y, r.right, r.bottom + y);
int w = 1 << t->m_TEX0.TW;
int h = 1 << t->m_TEX0.TH;
if(r2.bottom > 0 && r2.top < h && r2.right > 0 && r2.left < w)
{
t->m_dirty.push_back(GSDirtyRect(r2, BITBLTBUF.DPSM));
}
}
}
}
}
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); )
{
list<GSRenderTarget*>::iterator j = i++;
GSRenderTarget* rt = *j;
if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, rt->m_TEX0.TBP0, rt->m_TEX0.PSM))
{
if(!found && GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM))
{
rt->m_dirty.push_back(GSDirtyRect(r, BITBLTBUF.DPSM));
rt->m_TEX0.TBW = BITBLTBUF.DBW;
}
else
{
m_rt.erase(j);
delete rt;
continue;
}
}
if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM) && BITBLTBUF.DBP < rt->m_TEX0.TBP0)
{
uint32 rowsize = BITBLTBUF.DBW * 8192;
uint32 offset = (uint32)((rt->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.y * offset / rowsize;
if(r.bottom > y)
{
// TODO: do not add this rect above too
rt->m_dirty.push_back(GSDirtyRect(GSVector4i(r.left, r.top - y, r.right, r.bottom - y), BITBLTBUF.DPSM));
rt->m_TEX0.TBW = BITBLTBUF.DBW;
continue;
}
}
}
}
// copypaste for ds
for(list<GSDepthStencil*>::iterator i = m_ds.begin(); i != m_ds.end(); )
{
list<GSDepthStencil*>::iterator j = i++;
GSDepthStencil* ds = *j;
if(GSUtil::HasSharedBits(BITBLTBUF.DBP, BITBLTBUF.DPSM, ds->m_TEX0.TBP0, ds->m_TEX0.PSM))
{
if(!found && GSUtil::HasCompatibleBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM))
{
ds->m_dirty.push_back(GSDirtyRect(r, BITBLTBUF.DPSM));
ds->m_TEX0.TBW = BITBLTBUF.DBW;
}
else
{
m_ds.erase(j);
delete ds;
continue;
}
}
if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM) && BITBLTBUF.DBP < ds->m_TEX0.TBP0)
{
uint32 rowsize = BITBLTBUF.DBW * 8192;
uint32 offset = (uint32)((ds->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.y * offset / rowsize;
if(r.bottom > y)
{
// TODO: do not add this rect above too
ds->m_dirty.push_back(GSDirtyRect(GSVector4i(r.left, r.top - y, r.right, r.bottom - y), BITBLTBUF.DPSM));
ds->m_TEX0.TBW = BITBLTBUF.DBW;
continue;
}
}
}
}
}
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r)
{
for(list<GSRenderTarget*>::iterator i = m_rt.begin(); i != m_rt.end(); )
{
list<GSRenderTarget*>::iterator j = i++;
GSRenderTarget* rt = *j;
if(GSUtil::HasSharedBits(BITBLTBUF.SBP, BITBLTBUF.SPSM, rt->m_TEX0.TBP0, rt->m_TEX0.PSM))
{
if(GSUtil::HasCompatibleBits(BITBLTBUF.SPSM, rt->m_TEX0.PSM))
{
rt->Read(r);
return;
}
else if(BITBLTBUF.SPSM == PSM_PSMCT32 && (rt->m_TEX0.PSM == PSM_PSMCT16 || rt->m_TEX0.PSM == PSM_PSMCT16S))
{
// ffx-2 riku changing to her default (shoots some reflecting glass at the end), 16-bit rt read as 32-bit
rt->Read(GSVector4i(r.left, r.top, r.right, r.top + (r.bottom - r.top) * 2));
return;
}
else
{
m_rt.erase(j);
delete rt;
continue;
}
}
}
/*
// no good, ffx does a lot of readback after exiting menu, at 0x02f00 this wrongly finds rt 0x02100 (0,448 - 512,480)
GSRenderTarget* rt2 = NULL;
int ymin = INT_MAX;
pos = m_rt.GetHeadPosition();
while(pos)
{
GSRenderTarget* rt = m_rt.GetNext(pos);
if(HasSharedBits(BITBLTBUF.SPSM, rt->m_TEX0.PSM) && BITBLTBUF.SBP > rt->m_TEX0.TBP0)
{
// ffx2 pause screen background
uint32 rowsize = BITBLTBUF.SBW * 8192;
uint32 offset = (uint32)((BITBLTBUF.SBP - rt->m_TEX0.TBP0) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.SPSM].pgs.y * offset / rowsize;
if(y < ymin && y < 512)
{
rt2 = rt;
ymin = y;
}
}
}
}
if(rt2)
{
rt2->Read(GSVector4i(r.left, r.top + ymin, r.right, r.bottom + ymin));
}
// TODO: ds
*/
}
void IncAge()
{
RecycleByAge(m_tex, 2);
RecycleByAge(m_rt);
RecycleByAge(m_ds);
}
void IncAge();
};

View File

@ -24,8 +24,8 @@
// GSTextureCache10
GSTextureCache10::GSTextureCache10(GSRenderer<GSDevice10>* renderer)
: GSTextureCache<GSDevice10>(renderer)
GSTextureCache10::GSTextureCache10(GSRenderer* r)
: GSTextureCache(r)
{
}
@ -37,43 +37,41 @@ void GSTextureCache10::GSRenderTargetHW10::Update()
// FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :)
GSVector4i r = m_dirty.GetDirtyRectAndClear(m_TEX0, m_texture.GetSize());
GSVector4i r = m_dirty.GetDirtyRectAndClear(m_TEX0, m_texture->GetSize());
if(r.rempty()) return;
int w = r.width();
int h = r.height();
static uint8* buff = (uint8*)_aligned_malloc(1024 * 1024 * 4, 16);
static int pitch = 1024 * 4;
if(GSTexture* t = m_renderer->m_dev->CreateTexture(w, h))
{
static uint8* buff = (uint8*)_aligned_malloc(1024 * 1024 * 4, 16);
static int pitch = 1024 * 4;
GIFRegTEXA TEXA;
GIFRegTEXA TEXA;
TEXA.AEM = 1;
TEXA.TA0 = 0;
TEXA.TA1 = 0x80;
TEXA.AEM = 1;
TEXA.TA0 = 0;
TEXA.TA1 = 0x80;
GIFRegCLAMP CLAMP;
GIFRegCLAMP CLAMP;
CLAMP.WMS = 0;
CLAMP.WMT = 0;
CLAMP.WMS = 0;
CLAMP.WMT = 0;
m_renderer->m_mem.ReadTexture(r, buff, pitch, m_TEX0, TEXA, CLAMP);
// s->m_perfmon.Put(GSPerfMon::Unswizzle, w * h * 4);
m_renderer->m_mem.ReadTexture(r, buff, pitch, m_TEX0, TEXA, CLAMP);
// s->m_perfmon.Put(GSPerfMon::Unswizzle, w * h * 4);
Texture texture;
t->Update(GSVector4i(0, 0, w, h), buff, pitch);
if(!m_renderer->m_dev.CreateTexture(texture, w, h))
return;
GSVector4 dr = GSVector4(r) * GSVector4(m_texture->m_scale).xyxy();
texture.Update(GSVector4i(0, 0, w, h), buff, pitch);
m_renderer->m_dev->StretchRect(t, m_texture, dr);
GSVector4 dr = GSVector4(r) * GSVector4(m_texture.m_scale).xyxy();
m_renderer->m_dev.StretchRect(texture, m_texture, dr);
m_renderer->m_dev.Recycle(texture);
m_renderer->m_dev->Recycle(t);
}
}
void GSTextureCache10::GSRenderTargetHW10::Read(const GSVector4i& r)
@ -99,75 +97,73 @@ void GSTextureCache10::GSRenderTargetHW10::Read(const GSVector4i& r)
int w = r.width();
int h = r.height();
GSVector4 src = GSVector4(r) * GSVector4(m_texture.m_scale).xyxy() / GSVector4(m_texture.GetSize()).xyxy();
GSVector4 src = GSVector4(r) * GSVector4(m_texture->m_scale).xyxy() / GSVector4(m_texture->GetSize()).xyxy();
DXGI_FORMAT format = m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R8G8B8A8_UNORM;
Texture offscreen;
if(!m_renderer->m_dev.CopyOffscreen(m_texture, src, offscreen, w, h, format))
return;
uint8* bits;
int pitch;
if(offscreen.Map(&bits, pitch))
if(GSTexture* offscreen = m_renderer->m_dev->CopyOffscreen(m_texture, src, w, h, format))
{
// TODO: block level write
uint8* bits;
int pitch;
uint32 bp = m_TEX0.TBP0;
uint32 bw = m_TEX0.TBW;
GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa;
if(m_TEX0.PSM == PSM_PSMCT32)
if(offscreen->Map(&bits, pitch))
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
// TODO: block level write
for(int x = r.left, i = 0; x < r.right; x++, i++)
uint32 bp = m_TEX0.TBP0;
uint32 bw = m_TEX0.TBW;
GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa;
if(m_TEX0.PSM == PSM_PSMCT32)
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
m_renderer->m_mem.WritePixel32(addr + offset[x], ((uint32*)bits)[i]);
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
m_renderer->m_mem.WritePixel32(addr + offset[x], ((uint32*)bits)[i]);
}
}
}
}
else if(m_TEX0.PSM == PSM_PSMCT24)
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
else if(m_TEX0.PSM == PSM_PSMCT24)
{
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
m_renderer->m_mem.WritePixel24(addr + offset[x], ((uint32*)bits)[i]);
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
m_renderer->m_mem.WritePixel24(addr + offset[x], ((uint32*)bits)[i]);
}
}
}
}
else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S)
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S)
{
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
m_renderer->m_mem.WritePixel16(addr + offset[x], ((uint16*)bits)[i]);
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
m_renderer->m_mem.WritePixel16(addr + offset[x], ((uint16*)bits)[i]);
}
}
}
}
else
{
ASSERT(0);
else
{
ASSERT(0);
}
offscreen->Unmap();
}
offscreen.Unmap();
m_renderer->m_dev->Recycle(offscreen);
}
m_renderer->m_dev.Recycle(offscreen);
}
// GSDepthStencilHW10
@ -181,7 +177,7 @@ void GSTextureCache10::GSDepthStencilHW10::Update()
// GSTextureHW10
bool GSTextureCache10::GSTextureHW10::Create()
bool GSTextureCache10::GSCachedTextureHW10::Create()
{
// m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1);
@ -228,11 +224,17 @@ bool GSTextureCache10::GSTextureHW10::Create()
int w = 1 << m_TEX0.TW;
int h = 1 << m_TEX0.TH;
return m_renderer->m_dev.CreateTexture(m_texture, w, h, format);
ASSERT(m_texture == NULL);
m_texture = m_renderer->m_dev->CreateTexture(w, h, format);
return m_texture != NULL;
}
bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt)
bool GSTextureCache10::GSCachedTextureHW10::Create(GSRenderTarget* rt)
{
// TODO: clean up this mess
rt->Update();
// m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1);
@ -247,8 +249,10 @@ bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt)
// do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows)
int w = (int)(rt->m_texture.m_scale.x * tw);
int h = (int)(rt->m_texture.m_scale.y * th);
int w = (int)(rt->m_texture->m_scale.x * tw);
int h = (int)(rt->m_texture->m_scale.y * th);
GSVector2i rtsize = rt->m_texture->GetSize();
// pitch conversion
@ -258,10 +262,12 @@ bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt)
// ASSERT(rt->m_TEX0.TBW > m_TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO)
m_renderer->m_dev.CreateRenderTarget(m_texture, rt->m_texture.GetWidth(), rt->m_texture.GetHeight());
ASSERT(m_texture == NULL);
GSVector4 size = GSVector4(rt->m_texture.GetSize()).xyxy();
GSVector4 scale = GSVector4(rt->m_texture.m_scale).xyxy();
m_texture = m_renderer->m_dev->CreateRenderTarget(rtsize.x, rtsize.y);
GSVector4 size = GSVector4(rtsize).xyxy();
GSVector4 scale = GSVector4(rt->m_texture->m_scale).xyxy();
int bw = 64;
int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64;
@ -286,7 +292,7 @@ bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt)
GSVector4 src = GSVector4(GSVector4i(sx, sy).xyxy() + br) * scale / size;
GSVector4 dst = GSVector4(GSVector4i(dx, dy).xyxy() + br) * scale;
m_renderer->m_dev.StretchRect(rt->m_texture, src, m_texture, dst);
m_renderer->m_dev->StretchRect(rt->m_texture, src, m_texture, dst);
// TODO: this is quite a lot of StretchRect, do it with one Draw
}
@ -304,65 +310,56 @@ bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt)
// width/height conversion
GSVector2 scale = rt->m_texture.m_scale;
GSVector2 scale = rt->m_texture->m_scale;
GSVector4 dst(0, 0, w, h);
if(w > rt->m_texture.GetWidth())
if(w > rtsize.x)
{
scale.x = (float)rt->m_texture.GetWidth() / tw;
dst.z = (float)rt->m_texture.GetWidth() * scale.x / rt->m_texture.m_scale.x;
w = rt->m_texture.GetWidth();
scale.x = (float)rtsize.x / tw;
dst.z = (float)rtsize.x * scale.x / rt->m_texture->m_scale.x;
w = rtsize.x;
}
if(h > rt->m_texture.GetHeight())
if(h > rtsize.y)
{
scale.y = (float)rt->m_texture.GetHeight() / th;
dst.w = (float)rt->m_texture.GetHeight() * scale.y / rt->m_texture.m_scale.y;
h = rt->m_texture.GetHeight();
scale.y = (float)rtsize.y / th;
dst.w = (float)rtsize.y * scale.y / rt->m_texture->m_scale.y;
h = rtsize.y;
}
GSVector4 src(0, 0, w, h);
Texture* st;
Texture* dt;
Texture tmp;
GSTexture* st = m_texture ? m_texture : rt->m_texture;
GSTexture* dt = m_renderer->m_dev->CreateRenderTarget(w, h);
if(!m_texture)
{
st = &rt->m_texture;
dt = &m_texture;
m_texture = dt;
}
else
{
st = &m_texture;
dt = &tmp;
}
m_renderer->m_dev.CreateRenderTarget(*dt, w, h);
if(src.x == dst.x && src.y == dst.y && src.z == dst.z && src.w == dst.w)
{
D3D10_BOX box = {0, 0, 0, w, h, 1};
m_renderer->m_dev->CopySubresourceRegion(*dt, 0, 0, 0, 0, *st, 0, &box);
(*(GSDevice10*)m_renderer->m_dev)->CopySubresourceRegion(*(GSTexture10*)dt, 0, 0, 0, 0, *(GSTexture10*)st, 0, &box);
}
else
{
src.z /= st->GetWidth();
src.w /= st->GetHeight();
m_renderer->m_dev.StretchRect(*st, src, *dt, dst);
m_renderer->m_dev->StretchRect(st, src, dt, dst);
}
if(tmp)
if(dt != m_texture)
{
m_renderer->m_dev.Recycle(m_texture);
m_renderer->m_dev->Recycle(m_texture);
m_texture = tmp;
m_texture = dt;
}
m_texture.m_scale = scale;
m_texture->m_scale = scale;
switch(m_TEX0.PSM)
{
@ -378,7 +375,7 @@ bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt)
break;
case PSM_PSMT8H:
m_bpp2 = 3;
m_renderer->m_dev.CreateTexture(m_palette, 256, 1, m_TEX0.CPSM == PSM_PSMCT32 ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R16_UNORM); //
m_palette = m_renderer->m_dev->CreateTexture(256, 1, m_TEX0.CPSM == PSM_PSMCT32 ? DXGI_FORMAT_R8G8B8A8_UNORM : DXGI_FORMAT_R16_UNORM); //
m_initpalette = true;
break;
case PSM_PSMT4HL:
@ -390,7 +387,7 @@ bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt)
return true;
}
bool GSTextureCache10::GSTextureHW10::Create(GSDepthStencil* ds)
bool GSTextureCache10::GSCachedTextureHW10::Create(GSDepthStencil* ds)
{
m_rendered = true;

View File

@ -24,14 +24,12 @@
#include "GSTextureCache.h"
#include "GSDevice10.h"
class GSTextureCache10 : public GSTextureCache<GSDevice10>
class GSTextureCache10 : public GSTextureCache
{
typedef GSDevice10::Texture Texture;
class GSRenderTargetHW10 : public GSRenderTarget
{
public:
explicit GSRenderTargetHW10(GSRenderer<GSDevice10>* renderer) : GSRenderTarget(renderer) {}
explicit GSRenderTargetHW10(GSRenderer* r) : GSRenderTarget(r) {}
void Update();
void Read(const GSVector4i& r);
@ -40,15 +38,15 @@ class GSTextureCache10 : public GSTextureCache<GSDevice10>
class GSDepthStencilHW10 : public GSDepthStencil
{
public:
explicit GSDepthStencilHW10(GSRenderer<GSDevice10>* renderer) : GSDepthStencil(renderer) {}
explicit GSDepthStencilHW10(GSRenderer* r) : GSDepthStencil(r) {}
void Update();
};
class GSTextureHW10 : public GSTexture
class GSCachedTextureHW10 : public GSCachedTexture
{
public:
explicit GSTextureHW10(GSRenderer<GSDevice10>* renderer) : GSTexture(renderer) {}
explicit GSCachedTextureHW10(GSRenderer* r) : GSCachedTexture(r) {}
bool Create();
bool Create(GSRenderTarget* rt);
@ -58,8 +56,8 @@ class GSTextureCache10 : public GSTextureCache<GSDevice10>
protected:
GSRenderTarget* CreateRenderTarget() {return new GSRenderTargetHW10(m_renderer);}
GSDepthStencil* CreateDepthStencil() {return new GSDepthStencilHW10(m_renderer);}
GSTexture* CreateTexture() {return new GSTextureHW10(m_renderer);}
GSCachedTexture* CreateTexture() {return new GSCachedTextureHW10(m_renderer);}
public:
GSTextureCache10(GSRenderer<GSDevice10>* renderer);
GSTextureCache10(GSRenderer* r);
};

View File

@ -24,8 +24,8 @@
// GSTextureCache9
GSTextureCache9::GSTextureCache9(GSRenderer<GSDevice9>* renderer)
: GSTextureCache<GSDevice9>(renderer)
GSTextureCache9::GSTextureCache9(GSRenderer* r)
: GSTextureCache(r)
{
}
@ -37,46 +37,42 @@ void GSTextureCache9::GSRenderTarget9::Update()
// FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :)
GSVector4i r = m_dirty.GetDirtyRectAndClear(m_TEX0, m_texture.GetSize());
GSVector4i r = m_dirty.GetDirtyRectAndClear(m_TEX0, m_texture->GetSize());
if(r.rempty()) return;
int w = r.width();
int h = r.height();
Texture texture;
if(!m_renderer->m_dev.CreateTexture(texture, w, h))
return;
uint8* bits;
int pitch;
if(texture.Map(&bits, pitch))
if(GSTexture* t = m_renderer->m_dev->CreateTexture(w, h))
{
GIFRegTEXA TEXA;
uint8* bits;
int pitch;
TEXA.AEM = 1;
TEXA.TA0 = 0;
TEXA.TA1 = 0x80;
if(t->Map(&bits, pitch))
{
GIFRegTEXA TEXA;
GIFRegCLAMP CLAMP;
TEXA.AEM = 1;
TEXA.TA0 = 0;
TEXA.TA1 = 0x80;
CLAMP.WMS = 0;
CLAMP.WMT = 0;
GIFRegCLAMP CLAMP;
m_renderer->m_mem.ReadTexture(r, bits, pitch, m_TEX0, TEXA, CLAMP);
CLAMP.WMS = 0;
CLAMP.WMT = 0;
texture.Unmap();
// m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * 4);
m_renderer->m_mem.ReadTexture(r, bits, pitch, m_TEX0, TEXA, CLAMP);
GSVector4 dr = GSVector4(r) * GSVector4(m_texture.m_scale).xyxy();
t->Unmap();
// m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * 4);
m_renderer->m_dev.StretchRect(texture, m_texture, dr);
m_renderer->m_dev->StretchRect(t, m_texture, GSVector4(r) * GSVector4(m_texture->m_scale).xyxy());
}
m_renderer->m_dev->Recycle(t);
}
m_renderer->m_dev.Recycle(texture);
}
void GSTextureCache9::GSRenderTarget9::Read(const GSVector4i& r)
@ -102,73 +98,71 @@ void GSTextureCache9::GSRenderTarget9::Read(const GSVector4i& r)
int w = r.width();
int h = r.height();
GSVector4 src = GSVector4(r) * GSVector4(m_texture.m_scale).xyxy() / GSVector4(m_texture.GetSize()).xyxy();
GSVector4 src = GSVector4(r) * GSVector4(m_texture->m_scale).xyxy() / GSVector4(m_texture->GetSize()).xyxy();
Texture offscreen;
if(!m_renderer->m_dev.CopyOffscreen(m_texture, src, offscreen, w, h))
return;
uint8* bits;
int pitch;
if(offscreen.Map(&bits, pitch))
if(GSTexture* offscreen = m_renderer->m_dev->CopyOffscreen(m_texture, src, w, h))
{
// TODO: block level write
uint8* bits;
int pitch;
uint32 bp = m_TEX0.TBP0;
uint32 bw = m_TEX0.TBW;
GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa;
if(m_TEX0.PSM == PSM_PSMCT32)
if(offscreen->Map(&bits, pitch))
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
// TODO: block level write
for(int x = r.left, i = 0; x < r.right; x++, i++)
uint32 bp = m_TEX0.TBP0;
uint32 bw = m_TEX0.TBW;
GSLocalMemory::pixelAddress pa = GSLocalMemory::m_psm[m_TEX0.PSM].pa;
if(m_TEX0.PSM == PSM_PSMCT32)
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
m_renderer->m_mem.WritePixel32(addr + offset[x], ((uint32*)bits)[i]);
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
m_renderer->m_mem.WritePixel32(addr + offset[x], ((uint32*)bits)[i]);
}
}
}
}
else if(m_TEX0.PSM == PSM_PSMCT24)
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
else if(m_TEX0.PSM == PSM_PSMCT24)
{
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
m_renderer->m_mem.WritePixel24(addr + offset[x], ((uint32*)bits)[i]);
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
m_renderer->m_mem.WritePixel24(addr + offset[x], ((uint32*)bits)[i]);
}
}
}
}
else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S)
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
else if(m_TEX0.PSM == PSM_PSMCT16 || m_TEX0.PSM == PSM_PSMCT16S)
{
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
m_renderer->m_mem.WriteFrame16(addr + offset[x], ((uint32*)bits)[i]);
uint32 addr = pa(0, y, bp, bw);
int* offset = GSLocalMemory::m_psm[m_TEX0.PSM].rowOffset[y & 7];
for(int x = r.left, i = 0; x < r.right; x++, i++)
{
m_renderer->m_mem.WriteFrame16(addr + offset[x], ((uint32*)bits)[i]);
}
}
}
}
else
{
ASSERT(0);
else
{
ASSERT(0);
}
offscreen->Unmap();
}
offscreen.Unmap();
m_renderer->m_dev->Recycle(offscreen);
}
m_renderer->m_dev.Recycle(offscreen);
}
// GSDepthStencil9
@ -182,7 +176,7 @@ void GSTextureCache9::GSDepthStencil9::Update()
// GSTexture9
bool GSTextureCache9::GSTexture9::Create()
bool GSTextureCache9::GSCachedTexture9::Create()
{
// m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1);
@ -229,11 +223,17 @@ bool GSTextureCache9::GSTexture9::Create()
int w = 1 << m_TEX0.TW;
int h = 1 << m_TEX0.TH;
return m_renderer->m_dev.CreateTexture(m_texture, w, h, format);
ASSERT(m_texture == NULL);
m_texture = m_renderer->m_dev->CreateTexture(w, h, format);
return m_texture != NULL;
}
bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt)
bool GSTextureCache9::GSCachedTexture9::Create(GSRenderTarget* rt)
{
// TODO: clean up this mess
rt->Update();
// m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1);
@ -248,8 +248,10 @@ bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt)
// do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows)
int w = (int)(rt->m_texture.m_scale.x * tw);
int h = (int)(rt->m_texture.m_scale.y * th);
int w = (int)(rt->m_texture->m_scale.x * tw);
int h = (int)(rt->m_texture->m_scale.y * th);
GSVector2i rtsize = rt->m_texture->GetSize();
// pitch conversion
@ -259,10 +261,12 @@ bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt)
// ASSERT(rt->m_TEX0.TBW > m_TEX0.TBW); // otherwise scale.x need to be reduced to make the larger texture fit (TODO)
m_renderer->m_dev.CreateRenderTarget(m_texture, rt->m_texture.GetWidth(), rt->m_texture.GetHeight());
ASSERT(m_texture == NULL);
GSVector4 size = GSVector4(rt->m_texture.GetSize()).xyxy();
GSVector4 scale = GSVector4(rt->m_texture.m_scale).xyxy();
m_texture = m_renderer->m_dev->CreateRenderTarget(rtsize.x, rtsize.y);
GSVector4 size = GSVector4(rtsize).xyxy();
GSVector4 scale = GSVector4(rt->m_texture->m_scale).xyxy();
int bw = 64;
int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64;
@ -287,7 +291,7 @@ bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt)
GSVector4 src = GSVector4(GSVector4i(sx, sy).xyxy() + br) * scale / size;
GSVector4 dst = GSVector4(GSVector4i(dx, dy).xyxy() + br) * scale;
m_renderer->m_dev.StretchRect(rt->m_texture, src, m_texture, dst);
m_renderer->m_dev->StretchRect(rt->m_texture, src, m_texture, dst);
// TODO: this is quite a lot of StretchRect, do it with one Draw
}
@ -305,65 +309,56 @@ bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt)
// width/height conversion
GSVector2 scale = rt->m_texture.m_scale;
GSVector2 scale = rt->m_texture->m_scale;
GSVector4 dst(0, 0, w, h);
if(w > rt->m_texture.GetWidth())
if(w > rtsize.x)
{
scale.x = (float)rt->m_texture.GetWidth() / tw;
dst.z = (float)rt->m_texture.GetWidth() * scale.x / rt->m_texture.m_scale.x;
w = rt->m_texture.GetWidth();
scale.x = (float)rtsize.x / tw;
dst.z = (float)rtsize.x * scale.x / rt->m_texture->m_scale.x;
w = rtsize.x;
}
if(h > rt->m_texture.GetHeight())
if(h > rtsize.y)
{
scale.y = (float)rt->m_texture.GetHeight() / th;
dst.w = (float)rt->m_texture.GetHeight() * scale.y / rt->m_texture.m_scale.y;
h = rt->m_texture.GetHeight();
scale.y = (float)rtsize.y / th;
dst.w = (float)rtsize.y * scale.y / rt->m_texture->m_scale.y;
h = rtsize.y;
}
GSVector4 src(0, 0, w, h);
Texture* st;
Texture* dt;
Texture tmp;
GSTexture* st = m_texture ? m_texture : rt->m_texture;
GSTexture* dt = m_renderer->m_dev->CreateRenderTarget(w, h);
if(!m_texture)
{
st = &rt->m_texture;
dt = &m_texture;
m_texture = dt;
}
else
{
st = &m_texture;
dt = &tmp;
}
m_renderer->m_dev.CreateRenderTarget(*dt, w, h);
if(src.x == dst.x && src.y == dst.y && src.z == dst.z && src.w == dst.w)
{
GSVector4i r(0, 0, w, h);
m_renderer->m_dev->StretchRect(*st, r, *dt, r, D3DTEXF_POINT);
(*(GSDevice9*)m_renderer->m_dev)->StretchRect(*(GSTexture9*)st, r, *(GSTexture9*)dt, r, D3DTEXF_POINT);
}
else
{
src.z /= st->GetWidth();
src.w /= st->GetHeight();
m_renderer->m_dev.StretchRect(*st, src, *dt, dst);
m_renderer->m_dev->StretchRect(st, src, dt, dst);
}
if(tmp)
if(dt != m_texture)
{
m_renderer->m_dev.Recycle(m_texture);
m_renderer->m_dev->Recycle(m_texture);
m_texture = tmp;
m_texture = dt;
}
m_texture.m_scale = scale;
m_texture->m_scale = scale;
switch(m_TEX0.PSM)
{
@ -379,7 +374,7 @@ bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt)
break;
case PSM_PSMT8H:
m_bpp2 = 3;
m_renderer->m_dev.CreateTexture(m_palette, 256, 1, m_TEX0.CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5);
m_palette = m_renderer->m_dev->CreateTexture(256, 1, m_TEX0.CPSM == PSM_PSMCT32 ? D3DFMT_A8R8G8B8 : D3DFMT_A1R5G5B5);
m_initpalette = true;
break;
case PSM_PSMT4HL:
@ -391,7 +386,7 @@ bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt)
return true;
}
bool GSTextureCache9::GSTexture9::Create(GSDepthStencil* ds)
bool GSTextureCache9::GSCachedTexture9::Create(GSDepthStencil* ds)
{
m_rendered = true;

View File

@ -24,14 +24,12 @@
#include "GSTextureCache.h"
#include "GSDevice9.h"
class GSTextureCache9 : public GSTextureCache<GSDevice9>
class GSTextureCache9 : public GSTextureCache
{
typedef GSDevice9::Texture Texture;
class GSRenderTarget9 : public GSRenderTarget
{
public:
explicit GSRenderTarget9(GSRenderer<GSDevice9>* renderer) : GSRenderTarget(renderer) {}
explicit GSRenderTarget9(GSRenderer* r) : GSRenderTarget(r) {}
void Update();
void Read(const GSVector4i& r);
@ -40,15 +38,15 @@ class GSTextureCache9 : public GSTextureCache<GSDevice9>
class GSDepthStencil9 : public GSDepthStencil
{
public:
explicit GSDepthStencil9(GSRenderer<GSDevice9>* renderer) : GSDepthStencil(renderer) {}
explicit GSDepthStencil9(GSRenderer* r) : GSDepthStencil(r) {}
void Update();
};
class GSTexture9 : public GSTexture
class GSCachedTexture9 : public GSCachedTexture
{
public:
explicit GSTexture9(GSRenderer<GSDevice9>* renderer) : GSTexture(renderer) {}
explicit GSCachedTexture9(GSRenderer* r) : GSCachedTexture(r) {}
bool Create();
bool Create(GSRenderTarget* rt);
@ -58,8 +56,8 @@ class GSTextureCache9 : public GSTextureCache<GSDevice9>
protected:
GSRenderTarget* CreateRenderTarget() {return new GSRenderTarget9(m_renderer);}
GSDepthStencil* CreateDepthStencil() {return new GSDepthStencil9(m_renderer);}
GSTexture* CreateTexture() {return new GSTexture9(m_renderer);}
GSCachedTexture* CreateTexture() {return new GSCachedTexture9(m_renderer);}
public:
GSTextureCache9(GSRenderer<GSDevice9>* renderer);
GSTextureCache9(GSRenderer* r);
};

View File

@ -260,7 +260,7 @@ bool GSTextureFX10::SetupGS(GSSelector sel)
return true;
}
bool GSTextureFX10::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, ID3D10ShaderResourceView* tex, ID3D10ShaderResourceView* pal)
bool GSTextureFX10::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, GSTexture* tex, GSTexture* pal)
{
m_dev->PSSetShaderResources(tex, pal);
@ -383,11 +383,11 @@ void GSTextureFX10::SetupRS(int w, int h, const GSVector4i& scissor)
m_dev->RSSet(w, h, &scissor);
}
void GSTextureFX10::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv)
void GSTextureFX10::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, GSTexture* rt, GSTexture* ds)
{
UpdateOM(dssel, bsel, bf);
m_dev->OMSetRenderTargets(rtv, dsv);
m_dev->OMSetRenderTargets(rt, ds);
}
void GSTextureFX10::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf)

View File

@ -239,10 +239,10 @@ public:
bool SetupIA(const GSVertexHW10* vertices, int count, D3D10_PRIMITIVE_TOPOLOGY prim);
bool SetupVS(VSSelector sel, const VSConstantBuffer* cb);
bool SetupGS(GSSelector sel);
bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, ID3D10ShaderResourceView* tex, ID3D10ShaderResourceView* pal);
bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, GSTexture* tex, GSTexture* pal);
void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel);
void SetupRS(int w, int h, const GSVector4i& scissor);
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv);
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, GSTexture* rt, GSTexture* ds);
void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf);
void Draw();
};

View File

@ -46,11 +46,13 @@ bool GSTextureFX9::Create(GSDevice9* dev)
return true;
}
bool GSTextureFX9::CreateMskFix(GSTexture9& t, uint32 size, uint32 msk, uint32 fix)
GSTexture* GSTextureFX9::CreateMskFix(uint32 size, uint32 msk, uint32 fix)
{
GSTexture* t = NULL;
uint32 hash = (size << 20) | (msk << 10) | fix;
hash_map<uint32, GSTexture9>::iterator i = m_mskfix.find(hash);
hash_map<uint32, GSTexture*>::iterator i = m_mskfix.find(hash);
if(i != m_mskfix.end())
{
@ -58,28 +60,28 @@ bool GSTextureFX9::CreateMskFix(GSTexture9& t, uint32 size, uint32 msk, uint32 f
}
else
{
if(!m_dev->CreateTexture(t, size, 1, D3DFMT_R32F))
{
return false;
}
t = m_dev->CreateTexture(size, 1, D3DFMT_R32F);
uint8* bits;
int pitch;
if(t.Map(&bits, pitch))
if(t)
{
for(uint32 i = 0; i < size; i++)
uint8* bits;
int pitch;
if(t->Map(&bits, pitch))
{
((float*)bits)[i] = (float)((i & msk) | fix) / size;
for(uint32 i = 0; i < size; i++)
{
((float*)bits)[i] = (float)((i & msk) | fix) / size;
}
t->Unmap();
}
t.Unmap();
m_mskfix[hash] = t;
}
m_mskfix[hash] = t;
}
return true;
return t;
}
bool GSTextureFX9::SetupIA(const GSVertexHW9* vertices, int count, D3DPRIMITIVETYPE prim)
@ -145,32 +147,26 @@ bool GSTextureFX9::SetupVS(VSSelector sel, const VSConstantBuffer* cb)
return true;
}
bool GSTextureFX9::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, IDirect3DTexture9* tex, IDirect3DTexture9* pal, bool psrr)
bool GSTextureFX9::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, GSTexture* tex, GSTexture* pal, bool psrr)
{
m_dev->PSSetShaderResources(tex, pal);
if(tex && psrr)
if(tex && psrr && (sel.wms == 3 || sel.wmt == 3))
{
if(sel.wms == 3)
{
D3DSURFACE_DESC desc;
tex->GetLevelDesc(0, &desc);
GSTexture9 t;
CreateMskFix(t, desc.Width, cb->UMSK, cb->UFIX);
(*m_dev)->SetTexture(2, t);
if(GSTexture* t = CreateMskFix(tex->GetWidth(), cb->UMSK, cb->UFIX))
{
(*m_dev)->SetTexture(2, *(GSTexture9*)t);
}
}
if(sel.wmt == 3)
{
D3DSURFACE_DESC desc;
tex->GetLevelDesc(0, &desc);
GSTexture9 t;
CreateMskFix(t, desc.Height, cb->VMSK, cb->VFIX);
(*m_dev)->SetTexture(3, t);
if(GSTexture* t = CreateMskFix(tex->GetHeight(), cb->VMSK, cb->VFIX))
{
(*m_dev)->SetTexture(3, *(GSTexture9*)t);
}
}
}
@ -279,7 +275,7 @@ void GSTextureFX9::SetupRS(int w, int h, const GSVector4i& scissor)
m_dev->RSSet(w, h, &scissor);
}
void GSTextureFX9::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 bf, IDirect3DSurface9* rt, IDirect3DSurface9* ds)
void GSTextureFX9::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 bf, GSTexture* rt, GSTexture* ds)
{
UpdateOM(dssel, bsel, bf);

View File

@ -155,19 +155,20 @@ private:
hash_map<uint32, Direct3DSamplerState9* > m_ps_ss;
hash_map<uint32, Direct3DDepthStencilState9* > m_om_dss;
hash_map<uint32, Direct3DBlendState9* > m_om_bs;
hash_map<uint32, GSTexture9> m_mskfix;
hash_map<uint32, GSTexture*> m_mskfix;
GSTexture* CreateMskFix(uint32 size, uint32 msk, uint32 fix);
public:
GSTextureFX9();
bool Create(GSDevice9* dev);
bool CreateMskFix(GSTexture9& t, uint32 size, uint32 msk, uint32 fix);
bool SetupIA(const GSVertexHW9* vertices, int count, D3DPRIMITIVETYPE prim);
bool SetupVS(VSSelector sel, const VSConstantBuffer* cb);
bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, IDirect3DTexture9* tex, IDirect3DTexture9* pal, bool psrr);
bool SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, GSTexture* tex, GSTexture* pal, bool psrr);
void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, bool psrr);
void SetupRS(int w, int h, const GSVector4i& scissor);
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 bf, IDirect3DSurface9* rt, IDirect3DSurface9* ds);
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 bf, GSTexture* rt, GSTexture* ds);
void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uint8 bf);
};

View File

@ -35,6 +35,11 @@ public:
return *this;
}
bool operator == (const GSVector2T& v) const
{
return x == v.x && y == v.y;
}
};
typedef GSVector2T<float> GSVector2;

View File

@ -22,7 +22,7 @@
<Configuration
Name="Debug|Win32"
ConfigurationType="2"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;..\..\common\vsprops\BaseProperties.vsprops;.\vsprops\debug.vsprops"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;.\vsprops\debug.vsprops"
UseOfMFC="1"
CharacterSet="2"
>
@ -149,7 +149,7 @@
<Configuration
Name="Release|Win32"
ConfigurationType="2"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;..\..\common\vsprops\BaseProperties.vsprops;.\vsprops\release.vsprops"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;.\vsprops\release.vsprops"
UseOfMFC="1"
CharacterSet="2"
WholeProgramOptimization="1"
@ -277,9 +277,8 @@
</Configuration>
<Configuration
Name="Debug SSE2|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
ConfigurationType="2"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;..\..\common\vsprops\BaseProperties.vsprops;.\vsprops\debug.vsprops;.\vsprops\sse2.vsprops"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;.\vsprops\debug.vsprops;.\vsprops\sse2.vsprops"
UseOfMFC="1"
CharacterSet="2"
>
@ -405,7 +404,7 @@
<Configuration
Name="Release SSE2|Win32"
ConfigurationType="2"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;..\..\common\vsprops\BaseProperties.vsprops;.\vsprops\release.vsprops;.\vsprops\sse2.vsprops"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;.\vsprops\release.vsprops;.\vsprops\sse2.vsprops"
UseOfMFC="1"
CharacterSet="2"
WholeProgramOptimization="1"
@ -532,7 +531,7 @@
<Configuration
Name="Release SSSE3|Win32"
ConfigurationType="2"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;.\vsprops\release.vsprops;.\vsprops\ssse3.vsprops;..\..\common\vsprops\BaseProperties.vsprops"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;.\vsprops\release.vsprops;.\vsprops\ssse3.vsprops"
UseOfMFC="1"
CharacterSet="2"
WholeProgramOptimization="1"
@ -659,7 +658,7 @@
<Configuration
Name="Debug SSSE3|Win32"
ConfigurationType="2"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;..\..\common\vsprops\BaseProperties.vsprops;.\vsprops\debug.vsprops;.\vsprops\ssse3.vsprops"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\ProjectRootDir.vsprops;.\vsprops\debug.vsprops;.\vsprops\ssse3.vsprops"
UseOfMFC="1"
CharacterSet="2"
>
@ -784,7 +783,7 @@
<Configuration
Name="Debug SSE4|Win32"
ConfigurationType="2"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\debug.vsprops;.\vsprops\ProjectRootDir.vsprops;..\..\common\vsprops\BaseProperties.vsprops;.\vsprops\sse4.vsprops"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\debug.vsprops;.\vsprops\ProjectRootDir.vsprops;.\vsprops\sse4.vsprops"
UseOfMFC="1"
CharacterSet="2"
>
@ -910,7 +909,7 @@
<Configuration
Name="Release SSE4|Win32"
ConfigurationType="2"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\release.vsprops;.\vsprops\sse4.vsprops;.\vsprops\ProjectRootDir.vsprops;..\..\common\vsprops\BaseProperties.vsprops"
InheritedPropertySheets=".\vsprops\common.vsprops;.\vsprops\release.vsprops;.\vsprops\sse4.vsprops;.\vsprops\ProjectRootDir.vsprops"
UseOfMFC="1"
CharacterSet="2"
WholeProgramOptimization="1"
@ -1227,6 +1226,14 @@
AssemblerOutput="4"
/>
</FileConfiguration>
<FileConfiguration
Name="Release SSE4|Win32"
>
<Tool
Name="VCCLCompilerTool"
AssemblerOutput="4"
/>
</FileConfiguration>
<FileConfiguration
Name="Release SSE4|x64"
>

View File

@ -4,7 +4,7 @@
#pragma once
#pragma warning(disable: 4996 4995 4324 4100)
#pragma warning(disable: 4996 4995 4324 4100 4101)
#ifdef _WINDOWS
@ -74,6 +74,8 @@ typedef signed long long int64;
#define EXPORT_C extern "C" __declspec(dllexport) void __stdcall
#define EXPORT_C_(type) extern "C" __declspec(dllexport) type __stdcall
#define ALIGN_STACK(n) __declspec(align(n)) int __dummy;
#ifndef RESTRICT
#ifdef __INTEL_COMPILER
#define RESTRICT restrict

View File

@ -3,6 +3,7 @@
ProjectType="Visual C++"
Version="8.00"
Name="common"
OutputDirectory="$(SolutionDir)\bin\$(PcsxSubsection)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
>
<Tool
@ -26,6 +27,10 @@
/>
<Tool
Name="VCPostBuildEventTool"
CommandLine=".\postBuild.cmd &quot;$(TargetPath)&quot; &quot;$(TargetName)&quot; $(TargetExt) plugins"
CommandLine=""
/>
<Tool
Name="VCPreBuildEventTool"
CommandLine="&quot;$(SvnCommonDir)\vsprops\preBuild.cmd&quot; &quot;$(ProjectRootDir)&quot;"
/>
</VisualStudioPropertySheet>