mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
8e3d3080c0
commit
3b22adc4b3
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 IsLost() {return false;}
|
||||
virtual void Present(const GSVector4i& r);
|
||||
virtual void Flip() {};
|
||||
|
||||
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 void BeginScene() {};
|
||||
virtual void EndScene() {};
|
||||
|
||||
return true;
|
||||
}
|
||||
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 bool IsLost() = 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 Present(const GSVector4i& r) = 0;
|
||||
virtual GSTexture* CopyOffscreen(GSTexture* src, const GSVector4& sr, int w, int h, int format = 0) {return NULL;}
|
||||
|
||||
virtual void BeginScene() = 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 EndScene() = 0;
|
||||
GSTexture* GetCurrent();
|
||||
virtual bool IsCurrentRGBA() {return true;}
|
||||
|
||||
virtual void Draw(const string& s) = 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 bool CopyOffscreen(Texture& src, const GSVector4& sr, Texture& dst, int w, int h, int format = 0) = 0;
|
||||
|
||||
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) {};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) {}
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
m_renderer->m_mem.ReadTexture(r, buff, pitch, m_TEX0, TEXA, CLAMP);
|
||||
|
||||
// s->m_perfmon.Put(GSPerfMon::Unswizzle, w * h * 4);
|
||||
// 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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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_mem.ReadTexture(r, bits, pitch, m_TEX0, TEXA, CLAMP);
|
||||
|
||||
// m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * 4);
|
||||
t->Unmap();
|
||||
|
||||
GSVector4 dr = GSVector4(r) * GSVector4(m_texture.m_scale).xyxy();
|
||||
// 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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -35,6 +35,11 @@ public:
|
|||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator == (const GSVector2T& v) const
|
||||
{
|
||||
return x == v.x && y == v.y;
|
||||
}
|
||||
};
|
||||
|
||||
typedef GSVector2T<float> GSVector2;
|
||||
|
|
|
@ -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"
|
||||
>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 "$(TargetPath)" "$(TargetName)" $(TargetExt) plugins"
|
||||
CommandLine=""
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
CommandLine=""$(SvnCommonDir)\vsprops\preBuild.cmd" "$(ProjectRootDir)""
|
||||
/>
|
||||
</VisualStudioPropertySheet>
|
||||
|
|
Loading…
Reference in New Issue