git-svn-id: http://pcsx2.googlecode.com/svn/trunk@411 96395faa-99c1-11dd-bbfe-3dabce05a288

This commit is contained in:
refraction 2009-02-06 19:15:15 +00:00
parent 43198a7e84
commit 93da10abbb
190 changed files with 72906 additions and 0 deletions

306
plugins/GSdx/GPU.cpp Normal file
View File

@ -0,0 +1,306 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSUtil.h"
#include "GPURendererSW.h"
#include "GSDevice7.h"
#include "GSDevice9.h"
#include "GSDevice10.h"
#include "GPUSettingsDlg.h"
#define PSE_LT_GPU 2
static HRESULT s_hr = E_FAIL;
static GPURendererBase* s_gpu = NULL;
EXPORT_C_(UINT32) PSEgetLibType()
{
return PSE_LT_GPU;
}
EXPORT_C_(char*) PSEgetLibName()
{
return GSUtil::GetLibName();
}
EXPORT_C_(UINT32) PSEgetLibVersion()
{
static const UINT32 version = 1;
static const UINT32 revision = 1;
return version << 16 | revision << 8 | PLUGIN_VERSION;
}
EXPORT_C_(INT32) GPUinit()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO
return 0;
}
EXPORT_C_(INT32) GPUshutdown()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO
return 0;
}
EXPORT_C_(INT32) GPUclose()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
delete s_gpu;
s_gpu = NULL;
if(SUCCEEDED(s_hr))
{
::CoUninitialize();
s_hr = E_FAIL;
}
return 0;
}
EXPORT_C_(INT32) GPUopen(HWND hWnd)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if(!GSUtil::CheckDirectX() || !GSUtil::CheckSSE())
{
return -1;
}
GPUclose();
GPURendererSettings rs;
rs.m_filter = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("filter"), 0);
rs.m_dither = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("dithering"), 1);
rs.m_aspectratio = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("AspectRatio"), 1);
rs.m_vsync = !!AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("vsync"), FALSE);
rs.m_scale.cx = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("scale_x"), 0);
rs.m_scale.cy = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("scale_y"), 0);
int threads = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("swthreads"), 1);
int renderer = AfxGetApp()->GetProfileInt(_T("GPUSettings"), _T("Renderer"), 1);
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;
}
s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(!s_gpu->Create(hWnd))
{
GPUclose();
return -1;
}
return 0;
}
EXPORT_C_(INT32) GPUconfigure()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
GPUSettingsDlg dlg;
if(IDOK == dlg.DoModal())
{
GPUshutdown();
GPUinit();
}
return 0;
}
EXPORT_C_(INT32) GPUtest()
{
// TODO
return 0;
}
EXPORT_C GPUabout()
{
// TODO
}
EXPORT_C GPUwriteDataMem(const BYTE* mem, UINT32 size)
{
s_gpu->WriteData(mem, size);
}
EXPORT_C GPUwriteData(UINT32 data)
{
s_gpu->WriteData((BYTE*)&data, 1);
}
EXPORT_C GPUreadDataMem(BYTE* mem, UINT32 size)
{
s_gpu->ReadData(mem, size);
}
EXPORT_C_(UINT32) GPUreadData()
{
UINT32 data = 0;
s_gpu->ReadData((BYTE*)&data, 1);
return data;
}
EXPORT_C GPUwriteStatus(UINT32 status)
{
s_gpu->WriteStatus(status);
}
EXPORT_C_(UINT32) GPUreadStatus()
{
return s_gpu->ReadStatus();
}
EXPORT_C_(UINT32) GPUdmaChain(const BYTE* mem, UINT32 addr)
{
// TODO
UINT32 last[3];
memset(last, 0xff, sizeof(last));
do
{
if(addr == last[1] || addr == last[2]) break;
(addr < last[0] ? last[1] : last[2]) = addr;
last[0] = addr;
BYTE size = mem[addr + 3];
if(size > 0)
{
s_gpu->WriteData(&mem[addr + 4], size);
}
addr = *(UINT32*)&mem[addr] & 0xffffff;
}
while(addr != 0xffffff);
return 0;
}
EXPORT_C_(UINT32) GPUgetMode()
{
// TODO
return 0;
}
EXPORT_C GPUsetMode(UINT32)
{
// TODO
}
EXPORT_C GPUupdateLace()
{
s_gpu->VSync();
}
EXPORT_C GPUmakeSnapshot()
{
LPCTSTR path = _T("C:\\"); // TODO
s_gpu->MakeSnapshot(path);
}
EXPORT_C GPUdisplayText(char* text)
{
// TODO
}
EXPORT_C GPUdisplayFlags(UINT32 flags)
{
// TODO
}
EXPORT_C_(INT32) GPUfreeze(UINT32 type, GPUFreezeData* data)
{
if(!data || data->version != 1)
{
return 0;
}
if(type == 0)
{
s_gpu->Defrost(data);
return 1;
}
else if(type == 1)
{
s_gpu->Freeze(data);
return 1;
}
else if(type == 2)
{
int slot = *(int*)data + 1;
if(slot < 1 || slot > 9)
{
return 0;
}
// TODO
return 1;
}
return 0;
}
EXPORT_C GPUgetScreenPic(BYTE* mem)
{
// TODO
}
EXPORT_C GPUshowScreenPic(BYTE* mem)
{
// TODO
}
EXPORT_C GPUcursor(int player, int x, int y)
{
// TODO
}

276
plugins/GSdx/GPU.h Normal file
View File

@ -0,0 +1,276 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#pragma pack(push, 1)
#include "GS.h"
enum
{
GPU_POLYGON = 1,
GPU_LINE = 2,
GPU_SPRITE = 3,
};
REG32_(GPUReg, STATUS)
UINT32 TX:4;
UINT32 TY:1;
UINT32 ABR:2;
UINT32 TP:2;
UINT32 DTD:1;
UINT32 DFE:1;
UINT32 MD:1;
UINT32 ME:1;
UINT32 _PAD0:3;
UINT32 WIDTH1:1;
UINT32 WIDTH0:2;
UINT32 HEIGHT:1;
UINT32 ISPAL:1;
UINT32 ISRGB24:1;
UINT32 ISINTER:1;
UINT32 DEN:1;
UINT32 _PAD1:2;
UINT32 IDLE:1;
UINT32 IMG:1;
UINT32 COM:1;
UINT32 DMA:2;
UINT32 LCF:1;
/*
UINT32 TX:4;
UINT32 TY:1;
UINT32 ABR:2;
UINT32 TP:2;
UINT32 DTD:1;
UINT32 DFE:1;
UINT32 PBW:1;
UINT32 PBC:1;
UINT32 _PAD0:3;
UINT32 HRES2:1;
UINT32 HRES1:2;
UINT32 VRES:1;
UINT32 ISPAL:1;
UINT32 ISRGB24:1;
UINT32 ISINTER:1;
UINT32 ISSTOP:1;
UINT32 _PAD1:1;
UINT32 DMARDY:1;
UINT32 IDIDLE:1;
UINT32 DATARDY:1;
UINT32 ISEMPTY:1;
UINT32 TMODE:2;
UINT32 ODE:1;
*/
REG_END
REG32_(GPUReg, PACKET)
UINT32 _PAD:24;
UINT32 OPTION:5;
UINT32 TYPE:3;
REG_END
REG32_(GPUReg, PRIM)
UINT32 VTX:24;
UINT32 TGE:1;
UINT32 ABE:1;
UINT32 TME:1;
UINT32 _PAD2:1;
UINT32 IIP:1;
UINT32 TYPE:3;
REG_END
REG32_(GPUReg, POLYGON)
UINT32 _PAD:24;
UINT32 TGE:1;
UINT32 ABE:1;
UINT32 TME:1;
UINT32 VTX:1;
UINT32 IIP:1;
UINT32 TYPE:3;
REG_END
REG32_(GPUReg, LINE)
UINT32 _PAD:24;
UINT32 ZERO1:1;
UINT32 ABE:1;
UINT32 ZERO2:1;
UINT32 PLL:1;
UINT32 IIP:1;
UINT32 TYPE:3;
REG_END
REG32_(GPUReg, SPRITE)
UINT32 _PAD:24;
UINT32 ZERO:1;
UINT32 ABE:1;
UINT32 TME:1;
UINT32 SIZE:2;
UINT32 TYPE:3;
REG_END
REG32_(GPUReg, RESET)
UINT32 _PAD:32;
REG_END
REG32_(GPUReg, DEN)
UINT32 DEN:1;
UINT32 _PAD:31;
REG_END
REG32_(GPUReg, DMA)
UINT32 DMA:2;
UINT32 _PAD:30;
REG_END
REG32_(GPUReg, DAREA)
UINT32 X:10;
UINT32 Y:9;
UINT32 _PAD:13;
REG_END
REG32_(GPUReg, DHRANGE)
UINT32 X1:12;
UINT32 X2:12;
UINT32 _PAD:8;
REG_END
REG32_(GPUReg, DVRANGE)
UINT32 Y1:10;
UINT32 Y2:11;
UINT32 _PAD:11;
REG_END
REG32_(GPUReg, DMODE)
UINT32 WIDTH0:2;
UINT32 HEIGHT:1;
UINT32 ISPAL:1;
UINT32 ISRGB24:1;
UINT32 ISINTER:1;
UINT32 WIDTH1:1;
UINT32 REVERSE:1;
UINT32 _PAD:24;
REG_END
REG32_(GPUReg, GPUINFO)
UINT32 PARAM:24;
UINT32 _PAD:8;
REG_END
REG32_(GPUReg, MODE)
UINT32 TX:4;
UINT32 TY:1;
UINT32 ABR:2;
UINT32 TP:2;
UINT32 DTD:1;
UINT32 DFE:1;
UINT32 _PAD:21;
REG_END
REG32_(GPUReg, MASK)
UINT32 MD:1;
UINT32 ME:1;
UINT32 _PAD:30;
REG_END
REG32_(GPUReg, DRAREA)
UINT32 X:10;
UINT32 Y:10;
UINT32 _PAD:12;
REG_END
REG32_(GPUReg, DROFF)
INT32 X:11;
INT32 Y:11;
INT32 _PAD:10;
REG_END
REG32_(GPUReg, RGB)
UINT32 R:8;
UINT32 G:8;
UINT32 B:8;
UINT32 _PAD:8;
REG_END
REG32_(GPUReg, XY)
INT32 X:11;
INT32 _PAD1:5;
INT32 Y:11;
INT32 _PAD2:5;
REG_END
REG32_(GPUReg, UV)
UINT32 U:8;
UINT32 V:8;
UINT32 _PAD:16;
REG_END
REG32_(GPUReg, TWIN)
UINT32 TWW:5;
UINT32 TWH:5;
UINT32 TWX:5;
UINT32 TWY:5;
UINT32 _PAD:12;
REG_END
REG32_(GPUReg, CLUT)
UINT32 _PAD1:16;
UINT32 X:6;
UINT32 Y:9;
UINT32 _PAD2:1;
REG_END
REG32_SET(GPUReg)
GPURegSTATUS STATUS;
GPURegPACKET PACKET;
GPURegPRIM PRIM;
GPURegPOLYGON POLYGON;
GPURegLINE LINE;
GPURegSPRITE SPRITE;
GPURegRESET RESET;
GPURegDEN DEN;
GPURegDMA DMA;
GPURegDAREA DAREA;
GPURegDHRANGE DHRANGE;
GPURegDVRANGE DVRANGE;
GPURegDMODE DMODE;
GPURegGPUINFO GPUINFO;
GPURegMODE MODE;
GPURegMASK MASK;
GPURegDRAREA DRAREA;
GPURegDROFF DROFF;
GPURegRGB RGB;
GPURegXY XY;
GPURegUV UV;
GPURegTWIN TWIN;
GPURegCLUT CLUT;
REG_SET_END
struct GPUFreezeData
{
UINT32 version; // == 1
UINT32 status;
UINT32 control[256];
UINT16 vram[1024 * 1024];
};
#pragma pack(pop)

View File

@ -0,0 +1,910 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GPUDrawScanline.h"
GPUDrawScanline::GPUDrawScanline(GPUState* state, int id)
: m_state(state)
, m_id(id)
{
}
GPUDrawScanline::~GPUDrawScanline()
{
}
void GPUDrawScanline::BeginDraw(const GSRasterizerData* data, Functions* f)
{
GPUDrawingEnvironment& env = m_state->m_env;
const GPUScanlineParam* p = (const GPUScanlineParam*)data->param;
m_env.sel = p->sel;
m_env.mem = &m_state->m_mem;
if(m_env.sel.tme)
{
m_env.tex = p->tex;
m_env.clut = p->clut;
if(m_env.sel.twin)
{
DWORD u, v;
u = ~(env.TWIN.TWW << 3) & 0xff;
v = ~(env.TWIN.TWH << 3) & 0xff;
m_env.u[0] = GSVector4i((u << 16) | u);
m_env.v[0] = GSVector4i((v << 16) | v);
u = env.TWIN.TWX << 3;
v = env.TWIN.TWY << 3;
m_env.u[1] = GSVector4i((u << 16) | u) & ~m_env.u[0];
m_env.v[1] = GSVector4i((v << 16) | v) & ~m_env.v[0];
}
}
m_env.a = GSVector4i(env.PRIM.ABE ? 0xffffffff : 0);
m_env.md = GSVector4i(env.STATUS.MD ? 0x80008000 : 0);
f->sl = m_ds.Lookup(m_env.sel);
f->sr = NULL; // TODO
DWORD sel = 0;
sel |= (data->primclass == GS_SPRITE_CLASS ? 1 : 0) << 0;
sel |= m_env.sel.tme << 1;
sel |= m_env.sel.iip << 2;
f->sp = m_sp.Lookup(sel);
}
template<DWORD sprite, DWORD tme, DWORD iip>
void GPUDrawScanline::SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan)
{
if(m_env.sel.tme && !m_env.sel.twin)
{
if(sprite)
{
GSVector4i t;
t = (GSVector4i(vertices[1].t) >> 8) - GSVector4i::x00000001();
t = t.ps32(t);
t = t.upl16(t);
m_env.u[2] = t.xxxx();
m_env.v[2] = t.yyyy();
}
else
{
m_env.u[2] = GSVector4i::x00ff();
m_env.v[2] = GSVector4i::x00ff();
}
}
GSVector4 ps0123 = GSVector4::ps0123();
GSVector4 ps4567 = GSVector4::ps4567();
GSVector4 dt = dscan.t;
GSVector4 dc = dscan.c;
GSVector4i dtc8 = GSVector4i(dt * 8.0f).ps32(GSVector4i(dc * 8.0f));
if(tme)
{
m_env.dst8 = dtc8.upl16(dtc8);
m_env.ds = GSVector4i(dt.xxxx() * ps0123).ps32(GSVector4i(dt.xxxx() * ps4567));
m_env.dt = GSVector4i(dt.yyyy() * ps0123).ps32(GSVector4i(dt.yyyy() * ps4567));
}
if(iip)
{
m_env.dc8 = dtc8.uph16(dtc8);
m_env.dr = GSVector4i(dc.xxxx() * ps0123).ps32(GSVector4i(dc.xxxx() * ps4567));
m_env.dg = GSVector4i(dc.yyyy() * ps0123).ps32(GSVector4i(dc.yyyy() * ps4567));
m_env.db = GSVector4i(dc.zzzz() * ps0123).ps32(GSVector4i(dc.zzzz() * ps4567));
}
}
void GPUDrawScanline::SampleTexture(DWORD ltf, DWORD tlu, DWORD twin, GSVector4i& test, const GSVector4i& s, const GSVector4i& t, GSVector4i* c)
{
const void* RESTRICT tex = m_env.tex;
const WORD* RESTRICT clut = m_env.clut;
if(ltf)
{
GSVector4i u = s.sub16(GSVector4i(0x00200020)); // - 0.125f
GSVector4i v = t.sub16(GSVector4i(0x00200020)); // - 0.125f
GSVector4i u0 = u.srl16(8);
GSVector4i v0 = v.srl16(8);
GSVector4i u1 = u0.add16(GSVector4i::x0001());
GSVector4i v1 = v0.add16(GSVector4i::x0001());
GSVector4i uf = (u & GSVector4i::x00ff()) << 7;
GSVector4i vf = (v & GSVector4i::x00ff()) << 7;
if(twin)
{
u0 = (u0 & m_env.u[0]).add16(m_env.u[1]);
v0 = (v0 & m_env.v[0]).add16(m_env.v[1]);
u1 = (u1 & m_env.u[0]).add16(m_env.u[1]);
v1 = (v1 & m_env.v[0]).add16(m_env.v[1]);
}
else
{
u0 = u0.min_i16(m_env.u[2]);
v0 = v0.min_i16(m_env.v[2]);
u1 = u1.min_i16(m_env.u[2]);
v1 = v1.min_i16(m_env.v[2]);
}
GSVector4i addr00 = v0.sll16(8) | u0;
GSVector4i addr01 = v0.sll16(8) | u1;
GSVector4i addr10 = v1.sll16(8) | u0;
GSVector4i addr11 = v1.sll16(8) | u1;
GSVector4i c00, c01, c10, c11;
if(tlu)
{
c00 = addr00.gather16_16((const BYTE*)tex, clut);
c01 = addr01.gather16_16((const BYTE*)tex, clut);
c10 = addr10.gather16_16((const BYTE*)tex, clut);
c11 = addr11.gather16_16((const BYTE*)tex, clut);
}
else
{
c00 = addr00.gather16_16((const WORD*)tex);
c01 = addr01.gather16_16((const WORD*)tex);
c10 = addr00.gather16_16((const WORD*)tex);
c11 = addr01.gather16_16((const WORD*)tex);
}
GSVector4i r00 = (c00 & 0x001f001f) << 3;
GSVector4i r01 = (c01 & 0x001f001f) << 3;
GSVector4i r10 = (c10 & 0x001f001f) << 3;
GSVector4i r11 = (c11 & 0x001f001f) << 3;
r00 = r00.lerp16<0>(r01, uf);
r10 = r10.lerp16<0>(r11, uf);
c[0] = r00.lerp16<0>(r10, vf);
GSVector4i g00 = (c00 & 0x03e003e0) >> 2;
GSVector4i g01 = (c01 & 0x03e003e0) >> 2;
GSVector4i g10 = (c10 & 0x03e003e0) >> 2;
GSVector4i g11 = (c11 & 0x03e003e0) >> 2;
g00 = g00.lerp16<0>(g01, uf);
g10 = g10.lerp16<0>(g11, uf);
c[1] = g00.lerp16<0>(g10, vf);
GSVector4i b00 = (c00 & 0x7c007c00) >> 7;
GSVector4i b01 = (c01 & 0x7c007c00) >> 7;
GSVector4i b10 = (c10 & 0x7c007c00) >> 7;
GSVector4i b11 = (c11 & 0x7c007c00) >> 7;
b00 = b00.lerp16<0>(b01, uf);
b10 = b10.lerp16<0>(b11, uf);
c[2] = b00.lerp16<0>(b10, vf);
GSVector4i a00 = (c00 & 0x80008000) >> 8;
GSVector4i a01 = (c01 & 0x80008000) >> 8;
GSVector4i a10 = (c10 & 0x80008000) >> 8;
GSVector4i a11 = (c11 & 0x80008000) >> 8;
a00 = a00.lerp16<0>(a01, uf);
a10 = a10.lerp16<0>(a11, uf);
c[3] = a00.lerp16<0>(a10, vf).gt16(GSVector4i::zero());
// mask out blank pixels (not perfect)
test |=
c[0].eq16(GSVector4i::zero()) &
c[1].eq16(GSVector4i::zero()) &
c[2].eq16(GSVector4i::zero()) &
c[3].eq16(GSVector4i::zero());
}
else
{
GSVector4i u = s.srl16(8);
GSVector4i v = t.srl16(8);
if(twin)
{
u = (u & m_env.u[0]).add16(m_env.u[1]);
v = (v & m_env.v[0]).add16(m_env.v[1]);
}
else
{
u = u.min_i16(m_env.u[2]);
v = v.min_i16(m_env.v[2]);
}
GSVector4i addr = v.sll16(8) | u;
GSVector4i c00;
if(tlu)
{
c00 = addr.gather16_16((const BYTE*)tex, clut);
}
else
{
c00 = addr.gather16_16((const WORD*)tex);
}
test |= c00.eq16(GSVector4i::zero()); // mask out blank pixels
c[0] = (c00 & 0x001f001f) << 3;
c[1] = (c00 & 0x03e003e0) >> 2;
c[2] = (c00 & 0x7c007c00) >> 7;
c[3] = c00.sra16(15);
}
}
void GPUDrawScanline::ColorTFX(DWORD tfx, const GSVector4i& r, const GSVector4i& g, const GSVector4i& b, GSVector4i* c)
{
switch(tfx)
{
case 0: // none (tfx = 0)
case 1: // none (tfx = tge)
c[0] = r.srl16(7);
c[1] = g.srl16(7);
c[2] = b.srl16(7);
break;
case 2: // modulate (tfx = tme | tge)
c[0] = c[0].modulate16<1>(r).clamp8();
c[1] = c[1].modulate16<1>(g).clamp8();
c[2] = c[2].modulate16<1>(b).clamp8();
break;
case 3: // decal (tfx = tme)
break;
default:
__assume(0);
}
}
void GPUDrawScanline::AlphaBlend(UINT32 abr, UINT32 tme, const GSVector4i& d, GSVector4i* c)
{
GSVector4i r = (d & 0x001f001f) << 3;
GSVector4i g = (d & 0x03e003e0) >> 2;
GSVector4i b = (d & 0x7c007c00) >> 7;
switch(abr)
{
case 0:
r = r.avg8(c[0]);
g = g.avg8(c[0]);
b = b.avg8(c[0]);
break;
case 1:
r = r.addus8(c[0]);
g = g.addus8(c[1]);
b = b.addus8(c[2]);
break;
case 2:
r = r.subus8(c[0]);
g = g.subus8(c[1]);
b = b.subus8(c[2]);
break;
case 3:
r = r.addus8(c[0].srl16(2));
g = g.addus8(c[1].srl16(2));
b = b.addus8(c[2].srl16(2));
break;
default:
__assume(0);
}
if(tme) // per pixel
{
c[0] = c[0].blend8(r, c[3]);
c[1] = c[1].blend8(g, c[3]);
c[2] = c[2].blend8(b, c[3]);
}
else
{
c[0] = r;
c[1] = g;
c[2] = b;
c[3] = GSVector4i::zero();
}
}
void GPUDrawScanline::WriteFrame(WORD* RESTRICT fb, const GSVector4i& test, const GSVector4i* c, int pixels)
{
GSVector4i r = (c[0] & 0x00f800f8) >> 3;
GSVector4i g = (c[1] & 0x00f800f8) << 2;
GSVector4i b = (c[2] & 0x00f800f8) << 7;
GSVector4i a = (c[3] & 0x00800080) << 8;
GSVector4i s = r | g | b | a | m_env.md;
int i = 0;
do
{
if(test.u16[i] == 0)
{
fb[i] = s.u16[i];
}
}
while(++i < pixels);
}
//
__declspec(align(16)) static WORD s_dither[4][16] =
{
{7, 0, 6, 1, 7, 0, 6, 1, 7, 0, 6, 1, 7, 0, 6, 1},
{2, 5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 4, 2, 5, 3, 4},
{1, 6, 0, 7, 1, 6, 0, 7, 1, 6, 0, 7, 1, 6, 0, 7},
{4, 3, 5, 2, 4, 3, 5, 2, 4, 3, 5, 2, 4, 3, 5, 2},
};
void GPUDrawScanline::DrawScanline(int top, int left, int right, const GSVertexSW& v)
{
GSVector4i s, t;
GSVector4i r, g, b;
if(m_env.sel.tme)
{
GSVector4i vt = GSVector4i(v.t).xxzzl();
s = vt.xxxx().add16(m_env.ds);
t = vt.yyyy().add16(m_env.dt);
}
GSVector4i vc = GSVector4i(v.c).xxzzlh();
r = vc.xxxx();
g = vc.yyyy();
b = vc.zzzz();
if(m_env.sel.iip)
{
r = r.add16(m_env.dr);
g = g.add16(m_env.dg);
b = b.add16(m_env.db);
}
GSVector4i dither;
if(m_env.sel.dtd)
{
dither = GSVector4i::load<false>(&s_dither[top & 3][left & 3]);
}
int steps = right - left;
WORD* fb = m_env.mem->GetPixelAddress(left, top);
while(1)
{
do
{
int pixels = GSVector4i::min_i16(steps, 8);
GSVector4i test = GSVector4i::zero();
GSVector4i d = GSVector4i::zero();
if(m_env.sel.rfb) // me | abe
{
d = GSVector4i::load<false>(fb);
if(m_env.sel.me)
{
test = d.sra16(15);
if(test.alltrue())
{
continue;
}
}
}
GSVector4i c[4];
if(m_env.sel.tme)
{
SampleTexture(m_env.sel.ltf, m_env.sel.tlu, m_env.sel.twin, test, s, t, c);
}
ColorTFX(m_env.sel.tfx, r, g, b, c);
if(m_env.sel.abe)
{
AlphaBlend(m_env.sel.abr, m_env.sel.tme, d, c);
}
if(m_env.sel.dtd)
{
c[0] = c[0].addus8(dither);
c[1] = c[1].addus8(dither);
c[2] = c[2].addus8(dither);
}
WriteFrame(fb, test, c, pixels);
}
while(0);
if(steps <= 8) break;
steps -= 8;
fb += 8;
if(m_env.sel.tme)
{
GSVector4i dst8 = m_env.dst8;
s = s.add16(dst8.xxxx());
t = t.add16(dst8.yyyy());
}
if(m_env.sel.iip)
{
GSVector4i dc8 = m_env.dc8;
r = r.add16(dc8.xxxx());
g = g.add16(dc8.yyyy());
b = b.add16(dc8.zzzz());
}
}
}
template<DWORD sel>
void GPUDrawScanline::DrawScanlineEx(int top, int left, int right, const GSVertexSW& v)
{
DWORD iip = (sel >> 0) & 1;
DWORD me = (sel >> 1) & 1;
DWORD abe = (sel >> 2) & 1;
DWORD abr = (sel >> 3) & 3;
// DWORD tge = (sel >> 5) & 1;
DWORD tme = (sel >> 6) & 1;
DWORD twin = (sel >> 7) & 1;
DWORD rfb = (sel >> 1) & 3;
DWORD tfx = (sel >> 5) & 3;
GSVector4i s, t;
GSVector4i r, g, b;
if(tme)
{
GSVector4i vt = GSVector4i(v.t).xxzzl();
s = vt.xxxx().add16(m_env.ds);
t = vt.yyyy().add16(m_env.dt);
}
GSVector4i vc = GSVector4i(v.c).xxzzlh();
r = vc.xxxx();
g = vc.yyyy();
b = vc.zzzz();
if(iip)
{
r = r.add16(m_env.dr);
g = g.add16(m_env.dg);
b = b.add16(m_env.db);
}
GSVector4i dither;
if(m_env.sel.dtd)
{
dither = GSVector4i::load<false>(&s_dither[top & 3][left & 3]);
}
int steps = right - left;
WORD* fb = m_env.mem->GetPixelAddress(left, top);
while(1)
{
do
{
int pixels = GSVector4i::min_i16(steps, 8);
GSVector4i test = GSVector4i::zero();
GSVector4i d = GSVector4i::zero();
if(rfb) // me | abe
{
d = GSVector4i::load<false>(fb);
if(me)
{
test = d.sra16(15);
if(test.alltrue())
{
continue;
}
}
}
GSVector4i c[4];
if(tme)
{
SampleTexture(m_env.sel.ltf, m_env.sel.tlu, twin, test, s, t, c);
}
ColorTFX(tfx, r, g, b, c);
if(abe)
{
AlphaBlend(abr, tme, d, c);
}
if(m_env.sel.dtd)
{
c[0] = c[0].addus8(dither);
c[1] = c[1].addus8(dither);
c[2] = c[2].addus8(dither);
}
WriteFrame(fb, test, c, pixels);
}
while(0);
if(steps <= 8) break;
steps -= 8;
fb += 8;
if(tme)
{
GSVector4i dst8 = m_env.dst8;
s = s.add16(dst8.xxxx());
t = t.add16(dst8.yyyy());
}
if(iip)
{
GSVector4i dc8 = m_env.dc8;
r = r.add16(dc8.xxxx());
g = g.add16(dc8.yyyy());
b = b.add16(dc8.zzzz());
}
}
}
GPUDrawScanline::GPUDrawScanlineMap::GPUDrawScanlineMap()
{
for(int i = 0; i < countof(m_default); i++)
{
m_default[i] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanline;
}
#ifdef FAST_DRAWSCANLINE
m_default[0x00] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x00>;
m_default[0x01] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x01>;
m_default[0x02] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x02>;
m_default[0x03] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x03>;
m_default[0x04] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x04>;
m_default[0x05] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x05>;
m_default[0x06] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x06>;
m_default[0x07] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x07>;
m_default[0x08] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x08>;
m_default[0x09] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x09>;
m_default[0x0a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0a>;
m_default[0x0b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0b>;
m_default[0x0c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0c>;
m_default[0x0d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0d>;
m_default[0x0e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0e>;
m_default[0x0f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x0f>;
m_default[0x10] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x10>;
m_default[0x11] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x11>;
m_default[0x12] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x12>;
m_default[0x13] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x13>;
m_default[0x14] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x14>;
m_default[0x15] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x15>;
m_default[0x16] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x16>;
m_default[0x17] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x17>;
m_default[0x18] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x18>;
m_default[0x19] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x19>;
m_default[0x1a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1a>;
m_default[0x1b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1b>;
m_default[0x1c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1c>;
m_default[0x1d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1d>;
m_default[0x1e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1e>;
m_default[0x1f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x1f>;
m_default[0x20] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x20>;
m_default[0x21] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x21>;
m_default[0x22] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x22>;
m_default[0x23] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x23>;
m_default[0x24] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x24>;
m_default[0x25] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x25>;
m_default[0x26] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x26>;
m_default[0x27] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x27>;
m_default[0x28] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x28>;
m_default[0x29] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x29>;
m_default[0x2a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2a>;
m_default[0x2b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2b>;
m_default[0x2c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2c>;
m_default[0x2d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2d>;
m_default[0x2e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2e>;
m_default[0x2f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x2f>;
m_default[0x30] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x30>;
m_default[0x31] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x31>;
m_default[0x32] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x32>;
m_default[0x33] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x33>;
m_default[0x34] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x34>;
m_default[0x35] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x35>;
m_default[0x36] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x36>;
m_default[0x37] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x37>;
m_default[0x38] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x38>;
m_default[0x39] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x39>;
m_default[0x3a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3a>;
m_default[0x3b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3b>;
m_default[0x3c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3c>;
m_default[0x3d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3d>;
m_default[0x3e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3e>;
m_default[0x3f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x3f>;
m_default[0x40] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x40>;
m_default[0x41] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x41>;
m_default[0x42] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x42>;
m_default[0x43] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x43>;
m_default[0x44] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x44>;
m_default[0x45] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x45>;
m_default[0x46] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x46>;
m_default[0x47] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x47>;
m_default[0x48] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x48>;
m_default[0x49] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x49>;
m_default[0x4a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4a>;
m_default[0x4b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4b>;
m_default[0x4c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4c>;
m_default[0x4d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4d>;
m_default[0x4e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4e>;
m_default[0x4f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x4f>;
m_default[0x50] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x50>;
m_default[0x51] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x51>;
m_default[0x52] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x52>;
m_default[0x53] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x53>;
m_default[0x54] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x54>;
m_default[0x55] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x55>;
m_default[0x56] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x56>;
m_default[0x57] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x57>;
m_default[0x58] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x58>;
m_default[0x59] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x59>;
m_default[0x5a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5a>;
m_default[0x5b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5b>;
m_default[0x5c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5c>;
m_default[0x5d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5d>;
m_default[0x5e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5e>;
m_default[0x5f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x5f>;
m_default[0x60] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x60>;
m_default[0x61] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x61>;
m_default[0x62] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x62>;
m_default[0x63] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x63>;
m_default[0x64] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x64>;
m_default[0x65] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x65>;
m_default[0x66] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x66>;
m_default[0x67] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x67>;
m_default[0x68] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x68>;
m_default[0x69] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x69>;
m_default[0x6a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6a>;
m_default[0x6b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6b>;
m_default[0x6c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6c>;
m_default[0x6d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6d>;
m_default[0x6e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6e>;
m_default[0x6f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x6f>;
m_default[0x70] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x70>;
m_default[0x71] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x71>;
m_default[0x72] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x72>;
m_default[0x73] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x73>;
m_default[0x74] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x74>;
m_default[0x75] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x75>;
m_default[0x76] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x76>;
m_default[0x77] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x77>;
m_default[0x78] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x78>;
m_default[0x79] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x79>;
m_default[0x7a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7a>;
m_default[0x7b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7b>;
m_default[0x7c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7c>;
m_default[0x7d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7d>;
m_default[0x7e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7e>;
m_default[0x7f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x7f>;
m_default[0x80] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x80>;
m_default[0x81] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x81>;
m_default[0x82] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x82>;
m_default[0x83] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x83>;
m_default[0x84] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x84>;
m_default[0x85] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x85>;
m_default[0x86] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x86>;
m_default[0x87] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x87>;
m_default[0x88] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x88>;
m_default[0x89] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x89>;
m_default[0x8a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8a>;
m_default[0x8b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8b>;
m_default[0x8c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8c>;
m_default[0x8d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8d>;
m_default[0x8e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8e>;
m_default[0x8f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x8f>;
m_default[0x90] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x90>;
m_default[0x91] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x91>;
m_default[0x92] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x92>;
m_default[0x93] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x93>;
m_default[0x94] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x94>;
m_default[0x95] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x95>;
m_default[0x96] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x96>;
m_default[0x97] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x97>;
m_default[0x98] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x98>;
m_default[0x99] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x99>;
m_default[0x9a] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9a>;
m_default[0x9b] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9b>;
m_default[0x9c] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9c>;
m_default[0x9d] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9d>;
m_default[0x9e] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9e>;
m_default[0x9f] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0x9f>;
m_default[0xa0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa0>;
m_default[0xa1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa1>;
m_default[0xa2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa2>;
m_default[0xa3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa3>;
m_default[0xa4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa4>;
m_default[0xa5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa5>;
m_default[0xa6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa6>;
m_default[0xa7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa7>;
m_default[0xa8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa8>;
m_default[0xa9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xa9>;
m_default[0xaa] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xaa>;
m_default[0xab] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xab>;
m_default[0xac] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xac>;
m_default[0xad] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xad>;
m_default[0xae] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xae>;
m_default[0xaf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xaf>;
m_default[0xb0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb0>;
m_default[0xb1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb1>;
m_default[0xb2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb2>;
m_default[0xb3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb3>;
m_default[0xb4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb4>;
m_default[0xb5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb5>;
m_default[0xb6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb6>;
m_default[0xb7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb7>;
m_default[0xb8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb8>;
m_default[0xb9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xb9>;
m_default[0xba] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xba>;
m_default[0xbb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbb>;
m_default[0xbc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbc>;
m_default[0xbd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbd>;
m_default[0xbe] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbe>;
m_default[0xbf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xbf>;
m_default[0xc0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc0>;
m_default[0xc1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc1>;
m_default[0xc2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc2>;
m_default[0xc3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc3>;
m_default[0xc4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc4>;
m_default[0xc5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc5>;
m_default[0xc6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc6>;
m_default[0xc7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc7>;
m_default[0xc8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc8>;
m_default[0xc9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xc9>;
m_default[0xca] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xca>;
m_default[0xcb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcb>;
m_default[0xcc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcc>;
m_default[0xcd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcd>;
m_default[0xce] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xce>;
m_default[0xcf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xcf>;
m_default[0xd0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd0>;
m_default[0xd1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd1>;
m_default[0xd2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd2>;
m_default[0xd3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd3>;
m_default[0xd4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd4>;
m_default[0xd5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd5>;
m_default[0xd6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd6>;
m_default[0xd7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd7>;
m_default[0xd8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd8>;
m_default[0xd9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xd9>;
m_default[0xda] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xda>;
m_default[0xdb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdb>;
m_default[0xdc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdc>;
m_default[0xdd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdd>;
m_default[0xde] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xde>;
m_default[0xdf] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xdf>;
m_default[0xe0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe0>;
m_default[0xe1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe1>;
m_default[0xe2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe2>;
m_default[0xe3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe3>;
m_default[0xe4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe4>;
m_default[0xe5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe5>;
m_default[0xe6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe6>;
m_default[0xe7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe7>;
m_default[0xe8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe8>;
m_default[0xe9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xe9>;
m_default[0xea] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xea>;
m_default[0xeb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xeb>;
m_default[0xec] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xec>;
m_default[0xed] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xed>;
m_default[0xee] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xee>;
m_default[0xef] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xef>;
m_default[0xf0] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf0>;
m_default[0xf1] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf1>;
m_default[0xf2] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf2>;
m_default[0xf3] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf3>;
m_default[0xf4] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf4>;
m_default[0xf5] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf5>;
m_default[0xf6] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf6>;
m_default[0xf7] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf7>;
m_default[0xf8] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf8>;
m_default[0xf9] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xf9>;
m_default[0xfa] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfa>;
m_default[0xfb] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfb>;
m_default[0xfc] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfc>;
m_default[0xfd] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfd>;
m_default[0xfe] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xfe>;
m_default[0xff] = (DrawScanlinePtr)&GPUDrawScanline::DrawScanlineEx<0xff>;
#endif
}
IDrawScanline::DrawScanlinePtr GPUDrawScanline::GPUDrawScanlineMap::GetDefaultFunction(DWORD dw)
{
GPUScanlineSelector sel;
sel.dw = dw;
return m_default[sel];
}
//
GPUDrawScanline::GPUSetupPrimMap::GPUSetupPrimMap()
{
#define InitSP_IIP(sprite, tme, iip) \
m_default[sprite][tme][iip] = (SetupPrimPtr)&GPUDrawScanline::SetupPrim<sprite, tme, iip>; \
#define InitSP_TME(sprite, tme) \
InitSP_IIP(sprite, tme, 0) \
InitSP_IIP(sprite, tme, 1) \
#define InitSP_SPRITE(sprite) \
InitSP_TME(sprite, 0) \
InitSP_TME(sprite, 1) \
InitSP_SPRITE(0);
InitSP_SPRITE(1);
}
IDrawScanline::SetupPrimPtr GPUDrawScanline::GPUSetupPrimMap::GetDefaultFunction(DWORD dw)
{
DWORD sprite = (dw >> 0) & 1;
DWORD tme = (dw >> 1) & 1;
DWORD iip = (dw >> 2) & 1;
return m_default[sprite][tme][iip];
}

View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPUState.h"
#include "GSRasterizer.h"
#include "GSAlignedClass.h"
union GPUScanlineSelector
{
struct
{
DWORD iip:1; // 0
DWORD me:1; // 1
DWORD abe:1; // 2
DWORD abr:2; // 3
DWORD tge:1; // 5
DWORD tme:1; // 6
DWORD twin:1; // 7
DWORD tlu:1; // 8
DWORD dtd:1; // 9
DWORD ltf:1; // 10
// DWORD dte:1: // 11
};
struct
{
DWORD _pad1:1; // 0
DWORD rfb:2; // 1
DWORD _pad2:2; // 3
DWORD tfx:2; // 5
};
DWORD dw;
operator DWORD() {return dw & 0xff;}
};
__declspec(align(16)) struct GPUScanlineEnvironment
{
GPUScanlineSelector sel;
GPULocalMemory* mem;
const void* tex;
const WORD* clut;
GSVector4i u[3];
GSVector4i v[3];
GSVector4i a;
GSVector4i md; // similar to gs fba
GSVector4i ds, dt, dst8;
GSVector4i dr, dg, db, dc8;
};
__declspec(align(16)) struct GPUScanlineParam
{
GPUScanlineSelector sel;
const void* tex;
const WORD* clut;
};
class GPUDrawScanline : public GSAlignedClass<16>, public IDrawScanline
{
GPUScanlineEnvironment m_env;
//
class GPUDrawScanlineMap : public GSFunctionMap<DrawScanlinePtr>
{
DrawScanlinePtr m_default[256];
public:
GPUDrawScanlineMap();
DrawScanlinePtr GetDefaultFunction(DWORD dw);
};
GPUDrawScanlineMap m_ds;
//
class GPUSetupPrimMap : public GSFunctionMap<SetupPrimPtr>
{
SetupPrimPtr m_default[2][2][2];
public:
GPUSetupPrimMap();
SetupPrimPtr GetDefaultFunction(DWORD dw);
};
GPUSetupPrimMap m_sp;
//
template<DWORD sprite, DWORD tme, DWORD iip>
void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan);
//
__forceinline void SampleTexture(DWORD ltf, DWORD tlu, DWORD twin, GSVector4i& test, const GSVector4i& s, const GSVector4i& t, GSVector4i* c);
__forceinline void ColorTFX(DWORD tfx, const GSVector4i& r, const GSVector4i& g, const GSVector4i& b, GSVector4i* c);
__forceinline void AlphaBlend(UINT32 abr, UINT32 tme, const GSVector4i& d, GSVector4i* c);
__forceinline void WriteFrame(WORD* RESTRICT fb, const GSVector4i& test, const GSVector4i* c, int pixels);
void DrawScanline(int top, int left, int right, const GSVertexSW& v);
template<DWORD sel>
void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v);
protected:
GPUState* m_state;
int m_id;
public:
GPUDrawScanline(GPUState* state, int id);
virtual ~GPUDrawScanline();
// IDrawScanline
void BeginDraw(const GSRasterizerData* data, Functions* f);
void EndDraw(const GSRasterizerStats& stats) {}
void PrintStats() {}
};

View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPU.h"
#pragma pack(push, 1)
__declspec(align(16)) class GPUDrawingEnvironment
{
public:
GPURegSTATUS STATUS;
GPURegPRIM PRIM;
GPURegDAREA DAREA;
GPURegDHRANGE DHRANGE;
GPURegDVRANGE DVRANGE;
GPURegDRAREA DRAREATL;
GPURegDRAREA DRAREABR;
GPURegDROFF DROFF;
GPURegTWIN TWIN;
GPURegCLUT CLUT;
GPUDrawingEnvironment()
{
Reset();
}
void Reset()
{
memset(this, 0, sizeof(*this));
STATUS.IDLE = 1;
STATUS.COM = 1;
STATUS.WIDTH0 = 1;
DVRANGE.Y1 = 16;
DVRANGE.Y2 = 256;
}
CRect GetDisplayRect()
{
static int s_width[] = {256, 320, 512, 640, 368, 384, 512, 640};
static int s_height[] = {240, 480};
CRect r;
r.left = DAREA.X & ~7; // FIXME
r.top = DAREA.Y;
r.right = r.left + s_width[(STATUS.WIDTH1 << 2) | STATUS.WIDTH0];
r.bottom = r.top + (DVRANGE.Y2 - DVRANGE.Y1) * s_height[STATUS.HEIGHT] / 240;
r &= CRect(0, 0, 1024, 512);
return r;
}
int GetFPS()
{
return STATUS.ISPAL ? 50 : 60;
}
};
#pragma pack(pop)

View File

@ -0,0 +1,666 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GPULocalMemory.h"
const GSVector4i GPULocalMemory::m_xxxa(0x00008000);
const GSVector4i GPULocalMemory::m_xxbx(0x00007c00);
const GSVector4i GPULocalMemory::m_xgxx(0x000003e0);
const GSVector4i GPULocalMemory::m_rxxx(0x0000001f);
GPULocalMemory::GPULocalMemory(const CSize& scale)
{
m_scale.cx = min(max(scale.cx, 0), 2);
m_scale.cy = min(max(scale.cy, 0), 2);
//
int size = (1 << (12 + 11)) * sizeof(WORD);
m_vm = (WORD*)VirtualAlloc(NULL, size * 2, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
memset(m_vm, 0, size);
//
m_clut.buff = m_vm + size;
m_clut.dirty = true;
//
size = 256 * 256 * (1 + 1 + 4) * 32;
m_texture.buff[0] = (BYTE*)VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
m_texture.buff[1] = m_texture.buff[0] + 256 * 256 * 32;
m_texture.buff[2] = m_texture.buff[1] + 256 * 256 * 32;
memset(m_texture.buff[0], 0, size);
memset(m_texture.valid, 0, sizeof(m_texture.valid));
for(int y = 0, offset = 0; y < 2; y++)
{
for(int x = 0; x < 16; x++, offset += 256 * 256)
{
m_texture.page[0][y][x] = &((BYTE*)m_texture.buff[0])[offset];
m_texture.page[1][y][x] = &((BYTE*)m_texture.buff[1])[offset];
}
}
for(int y = 0, offset = 0; y < 2; y++)
{
for(int x = 0; x < 16; x++, offset += 256 * 256)
{
m_texture.page[2][y][x] = &((DWORD*)m_texture.buff[2])[offset];
}
}
}
GPULocalMemory::~GPULocalMemory()
{
VirtualFree(m_vm, 0, MEM_RELEASE);
VirtualFree(m_texture.buff[0], 0, MEM_RELEASE);
}
const WORD* GPULocalMemory::GetCLUT(int tp, int cx, int cy)
{
if(m_clut.dirty || m_clut.tp != tp || m_clut.cx != cx || m_clut.cy != cy)
{
WORD* src = GetPixelAddressScaled(cx << 4, cy);
WORD* dst = m_clut.buff;
// TODO: at normal horizontal resolution just return src
if(m_scale.cx == 0)
{
memcpy(dst, src, (tp == 0 ? 16 : 256) * 2);
}
else if(m_scale.cx == 1)
{
if(tp == 0)
{
for(int i = 0; i < 16; i++)
{
dst[i] = src[i * 2];
}
}
else if(tp == 1)
{
for(int i = 0; i < 256; i++)
{
dst[i] = src[i * 2];
}
}
}
else if(m_scale.cx == 2)
{
if(tp == 0)
{
for(int i = 0; i < 16; i++)
{
dst[i] = src[i * 4];
}
}
else if(tp == 1)
{
for(int i = 0; i < 256; i++)
{
dst[i] = src[i * 4];
}
}
}
else
{
ASSERT(0);
}
m_clut.tp = tp;
m_clut.cx = cx;
m_clut.cy = cy;
m_clut.dirty = false;
}
return m_clut.buff;
}
const void* GPULocalMemory::GetTexture(int tp, int tx, int ty)
{
if(tp == 3)
{
ASSERT(0);
return NULL;
}
void* buff = m_texture.page[tp][ty][tx];
UINT32 flag = 1 << tx;
if((m_texture.valid[tp][ty] & flag) == 0)
{
int bpp = 0;
switch(tp)
{
case 0:
ReadPage4(tx, ty, (BYTE*)buff);
bpp = 4;
break;
case 1:
ReadPage8(tx, ty, (BYTE*)buff);
bpp = 8;
break;
case 2:
case 3:
ReadPage16(tx, ty, (WORD*)buff);
bpp = 16;
default:
// FIXME: __assume(0); // vc9 generates bogus code in release mode
break;
}
// TODO: m_state->m_perfmon.Put(GSPerfMon::Unswizzle, 256 * 256 * bpp >> 3);
m_texture.valid[tp][ty] |= flag;
}
return buff;
}
void GPULocalMemory::Invalidate(const CRect& r)
{
if(!m_clut.dirty)
{
if(r.top <= m_clut.cy && m_clut.cy < r.bottom)
{
int left = m_clut.cx << 4;
int right = left + (m_clut.tp == 0 ? 16 : 256);
if(r.left < right && r.right > left)
{
m_clut.dirty = true;
}
}
}
for(int y = 0, ye = min(r.bottom, 512), j = 0; y < ye; y += 256, j++)
{
if(r.top >= y + 256) continue;
for(int x = 0, xe = min(r.right, 1024), i = 0; x < xe; x += 64, i++)
{
DWORD flag = 1 << i;
if(r.left >= x + 256) continue;
m_texture.valid[2][j] &= ~flag;
if(r.left >= x + 128) continue;
m_texture.valid[1][j] &= ~flag;
if(r.left >= x + 64) continue;
m_texture.valid[0][j] &= ~flag;
}
}
}
void GPULocalMemory::FillRect(const CRect& r, WORD c)
{
Invalidate(r);
WORD* RESTRICT dst = GetPixelAddressScaled(r.left, r.top);
int w = r.Width() << m_scale.cx;
int h = r.Height() << m_scale.cy;
int pitch = GetWidth();
for(int j = 0; j < h; j++, dst += pitch)
{
for(int i = 0; i < w; i++)
{
dst[i] = c;
}
}
}
void GPULocalMemory::WriteRect(const CRect& r, const WORD* RESTRICT src)
{
Invalidate(r);
WORD* RESTRICT dst = GetPixelAddressScaled(r.left, r.top);
int w = r.Width();
int h = r.Height();
int pitch = GetWidth();
if(m_scale.cx == 0)
{
for(int j = 0; j < h; j++, src += w)
{
for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch)
{
memcpy(dst, src, w * 2);
}
}
}
else if(m_scale.cx == 1)
{
for(int j = 0; j < h; j++, src += w)
{
for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch)
{
for(int i = 0; i < w; i++)
{
dst[i * 2 + 0] = src[i];
dst[i * 2 + 1] = src[i];
}
}
}
}
else if(m_scale.cx == 2)
{
for(int j = 0; j < h; j++, src += w)
{
for(int k = 1 << m_scale.cy; k >= 1; k--, dst += pitch)
{
for(int i = 0; i < w; i++)
{
dst[i * 4 + 0] = src[i];
dst[i * 4 + 1] = src[i];
dst[i * 4 + 2] = src[i];
dst[i * 4 + 3] = src[i];
}
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::ReadRect(const CRect& r, WORD* RESTRICT dst)
{
WORD* RESTRICT src = GetPixelAddressScaled(r.left, r.top);
int w = r.Width();
int h = r.Height();
int pitch = GetWidth() << m_scale.cy;
if(m_scale.cx == 0)
{
for(int j = 0; j < h; j++, src += pitch, dst += w)
{
memcpy(dst, src, w * 2);
}
}
else if(m_scale.cx == 1)
{
for(int j = 0; j < h; j++, src += pitch, dst += w)
{
for(int i = 0; i < w; i++)
{
dst[i] = src[i * 2];
}
}
}
else if(m_scale.cx == 2)
{
for(int j = 0; j < h; j++, src += pitch, dst += w)
{
for(int i = 0; i < w; i++)
{
dst[i] = src[i * 4];
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::MoveRect(const CPoint& src, const CPoint& dst, int w, int h)
{
Invalidate(CRect(dst, CSize(w, h)));
WORD* s = GetPixelAddressScaled(src.x, src.y);
WORD* d = GetPixelAddressScaled(dst.x, dst.y);
w <<= m_scale.cx;
h <<= m_scale.cy;
int pitch = GetWidth();
for(int i = 0; i < h; i++, s += pitch, d += pitch)
{
memcpy(d, s, w * sizeof(WORD));
}
}
void GPULocalMemory::ReadPage4(int tx, int ty, BYTE* RESTRICT dst)
{
WORD* src = GetPixelAddressScaled(tx << 6, ty << 8);
int pitch = GetWidth() << m_scale.cy;
if(m_scale.cx == 0)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 64; i++)
{
dst[i * 4 + 0] = (src[i] >> 0) & 0xf;
dst[i * 4 + 1] = (src[i] >> 4) & 0xf;
dst[i * 4 + 2] = (src[i] >> 8) & 0xf;
dst[i * 4 + 3] = (src[i] >> 12) & 0xf;
}
}
}
else if(m_scale.cx == 1)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 64; i++)
{
dst[i * 4 + 0] = (src[i * 2] >> 0) & 0xf;
dst[i * 4 + 1] = (src[i * 2] >> 4) & 0xf;
dst[i * 4 + 2] = (src[i * 2] >> 8) & 0xf;
dst[i * 4 + 3] = (src[i * 2] >> 12) & 0xf;
}
}
}
else if(m_scale.cx == 2)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 64; i++)
{
dst[i * 4 + 0] = (src[i * 4] >> 0) & 0xf;
dst[i * 4 + 1] = (src[i * 4] >> 4) & 0xf;
dst[i * 4 + 2] = (src[i * 4] >> 8) & 0xf;
dst[i * 4 + 3] = (src[i * 4] >> 12) & 0xf;
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::ReadPage8(int tx, int ty, BYTE* RESTRICT dst)
{
WORD* src = GetPixelAddressScaled(tx << 6, ty << 8);
int pitch = GetWidth() << m_scale.cy;
if(m_scale.cx == 0)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
memcpy(dst, src, 256);
}
}
else if(m_scale.cx == 1)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 128; i++)
{
((WORD*)dst)[i] = src[i * 2];
}
}
}
else if(m_scale.cx == 2)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 128; i++)
{
((WORD*)dst)[i] = src[i * 4];
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::ReadPage16(int tx, int ty, WORD* RESTRICT dst)
{
WORD* src = GetPixelAddressScaled(tx << 6, ty << 8);
int pitch = GetWidth() << m_scale.cy;
if(m_scale.cx == 0)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
memcpy(dst, src, 512);
}
}
else if(m_scale.cx == 1)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 256; i++)
{
dst[i] = src[i * 2];
}
}
}
else if(m_scale.cx == 2)
{
for(int j = 0; j < 256; j++, src += pitch, dst += 256)
{
for(int i = 0; i < 256; i++)
{
dst[i] = src[i * 4];
}
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::ReadFrame32(const CRect& r, DWORD* RESTRICT dst, bool rgb24)
{
WORD* src = GetPixelAddress(r.left, r.top);
int pitch = GetWidth();
if(rgb24)
{
for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch)
{
Expand24(src, dst, r.Width());
}
}
else
{
for(int i = r.top; i < r.bottom; i++, src += pitch, dst += pitch)
{
Expand16(src, dst, r.Width());
}
}
}
void GPULocalMemory::Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels)
{
GSVector4i rm = m_rxxx;
GSVector4i gm = m_xgxx;
GSVector4i bm = m_xxbx;
GSVector4i am = m_xxxa;
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
for(int i = 0, j = pixels >> 3; i < j; i++)
{
GSVector4i c = s[i];
GSVector4i l = c.upl16();
GSVector4i h = c.uph16();
d[i * 2 + 0] = ((l & rm) << 3) | ((l & gm) << 6) | ((l & bm) << 9) | ((l & am) << 16);
d[i * 2 + 1] = ((h & rm) << 3) | ((h & gm) << 6) | ((h & bm) << 9) | ((h & am) << 16);
}
}
void GPULocalMemory::Expand24(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels)
{
BYTE* s = (BYTE*)src;
if(m_scale.cx == 0)
{
for(int i = 0; i < pixels; i += 2, s += 6)
{
dst[i + 0] = (s[2] << 16) | (s[1] << 8) | s[0];
dst[i + 1] = (s[5] << 16) | (s[4] << 8) | s[3];
}
}
else if(m_scale.cx == 1)
{
for(int i = 0; i < pixels; i += 4, s += 12)
{
dst[i + 0] = dst[i + 1] = (s[4] << 16) | (s[1] << 8) | s[0];
dst[i + 2] = dst[i + 3] = (s[9] << 16) | (s[8] << 8) | s[5];
}
}
else if(m_scale.cx == 2)
{
for(int i = 0; i < pixels; i += 8, s += 24)
{
dst[i + 0] = dst[i + 1] = dst[i + 2] = dst[i + 3] = (s[8] << 16) | (s[1] << 8) | s[0];
dst[i + 4] = dst[i + 5] = dst[i + 6] = dst[i + 7] = (s[17] << 16) | (s[16] << 8) | s[9];
}
}
else
{
ASSERT(0);
}
}
void GPULocalMemory::SaveBMP(LPCTSTR path, CRect r, int tp, int cx, int cy)
{
r.left <<= m_scale.cx;
r.top <<= m_scale.cy;
r.right <<= m_scale.cx;
r.bottom <<= m_scale.cy;
r.left &= ~1;
r.right &= ~1;
if(FILE* fp = _tfopen(path, _T("wb")))
{
BITMAPINFOHEADER bih;
memset(&bih, 0, sizeof(bih));
bih.biSize = sizeof(bih);
bih.biWidth = r.Width();
bih.biHeight = r.Height();
bih.biPlanes = 1;
bih.biBitCount = 32;
bih.biCompression = BI_RGB;
bih.biSizeImage = bih.biWidth * bih.biHeight * 4;
BITMAPFILEHEADER bfh;
memset(&bfh, 0, sizeof(bfh));
bfh.bfType = 'MB';
bfh.bfOffBits = sizeof(bfh) + sizeof(bih);
bfh.bfSize = bfh.bfOffBits + bih.biSizeImage;
bfh.bfReserved1 = bfh.bfReserved2 = 0;
fwrite(&bfh, 1, sizeof(bfh), fp);
fwrite(&bih, 1, sizeof(bih), fp);
int pitch = GetWidth();
WORD* buff = (WORD*)_aligned_malloc(pitch * sizeof(WORD), 16);
DWORD* buff32 = (DWORD*)_aligned_malloc(pitch * sizeof(DWORD), 16);
WORD* src = GetPixelAddress(r.left, r.bottom - 1);
const WORD* clut = GetCLUT(tp, cx, cy);
for(int j = r.bottom - 1; j >= r.top; j--, src -= pitch)
{
switch(tp)
{
case 0: // 4 bpp
for(int i = 0, k = r.Width() / 2; i < k; i++)
{
buff[i * 2 + 0] = clut[((BYTE*)src)[i] & 0xf];
buff[i * 2 + 1] = clut[((BYTE*)src)[i] >> 4];
}
break;
case 1: // 8 bpp
for(int i = 0, k = r.Width(); i < k; i++)
{
buff[i] = clut[((BYTE*)src)[i]];
}
break;
case 2: // 16 bpp;
for(int i = 0, k = r.Width(); i < k; i++)
{
buff[i] = src[i];
}
break;
case 3: // 24 bpp
// TODO
break;
}
Expand16(buff, buff32, r.Width());
for(int i = 0, k = r.Width(); i < k; i++)
{
buff32[i] = (buff32[i] & 0xff00ff00) | ((buff32[i] & 0x00ff0000) >> 16) | ((buff32[i] & 0x000000ff) << 16);
}
fwrite(buff32, 1, r.Width() * 4, fp);
}
_aligned_free(buff);
_aligned_free(buff32);
fclose(fp);
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPU.h"
#include "GSVector.h"
class GPULocalMemory
{
static const GSVector4i m_xxxa;
static const GSVector4i m_xxbx;
static const GSVector4i m_xgxx;
static const GSVector4i m_rxxx;
WORD* m_vm;
struct
{
WORD* buff;
int tp, cx, cy;
bool dirty;
} m_clut;
struct
{
BYTE* buff[3];
void* page[3][2][16];
WORD valid[3][2];
} m_texture;
CSize m_scale;
public:
GPULocalMemory(const CSize& scale);
virtual ~GPULocalMemory();
CSize GetScale() {return m_scale;}
int GetWidth() {return 1 << (10 + m_scale.cx);}
int GetHeight() {return 1 << (9 + m_scale.cy);}
WORD* GetPixelAddress(int x, int y) const {return &m_vm[(y << (10 + m_scale.cx)) + x];}
WORD* GetPixelAddressScaled(int x, int y) const {return &m_vm[((y << m_scale.cy) << (10 + m_scale.cx)) + (x << m_scale.cx)];}
const WORD* GetCLUT(int tp, int cx, int cy);
const void* GetTexture(int tp, int tx, int ty);
void Invalidate(const CRect& r);
void FillRect(const CRect& r, WORD c);
void WriteRect(const CRect& r, const WORD* RESTRICT src);
void ReadRect(const CRect& r, WORD* RESTRICT dst);
void MoveRect(const CPoint& src, const CPoint& dst, int w, int h);
void ReadPage4(int tx, int ty, BYTE* RESTRICT dst);
void ReadPage8(int tx, int ty, BYTE* RESTRICT dst);
void ReadPage16(int tx, int ty, WORD* RESTRICT dst);
void ReadFrame32(const CRect& r, DWORD* RESTRICT dst, bool rgb24);
void Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels);
void Expand24(const WORD* RESTRICT src, DWORD* RESTRICT dst, int pixels);
void SaveBMP(LPCTSTR path, CRect r, int tp, int cx, int cy);
};
#pragma warning(default: 4244)

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GPURenderer.h"
CAtlMap<HWND, GPURendererBase*> GPURendererBase::m_wnd2gpu;

399
plugins/GSdx/GPURenderer.h Normal file
View File

@ -0,0 +1,399 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPUState.h"
#include "GSVertexList.h"
struct GPURendererSettings
{
int m_filter;
int m_dither;
int m_aspectratio;
bool m_vsync;
CSize m_scale;
};
class GPURendererBase : public GPUState, protected GPURendererSettings
{
protected:
HWND m_hWnd;
WNDPROC m_wndproc;
static CAtlMap<HWND, GPURendererBase*> m_wnd2gpu;
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
if(CAtlMap<HWND, GPURendererBase*>::CPair* pair = m_wnd2gpu.Lookup(hWnd))
{
return pair->m_value->OnMessage(message, wParam, lParam);
}
ASSERT(0);
return 0;
}
LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_KEYUP)
{
if(wParam == VK_DELETE)
{
m_filter = (m_filter + 1) % 3;
return 0;
}
if(wParam == VK_END)
{
m_dither = m_dither ? 0 : 1;
return 0;
}
if(wParam == VK_NEXT)
{
m_aspectratio = (m_aspectratio + 1) % 3;
return 0;
}
}
return m_wndproc(m_hWnd, message, wParam, 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.RemoveKey(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.SetAt(hWnd, this);
DWORD style = GetWindowLong(hWnd, GWL_STYLE);
style |= WS_OVERLAPPEDWINDOW;
SetWindowLong(hWnd, GWL_STYLE, style);
UpdateWindow(hWnd);
ShowWindow(hWnd, SW_SHOWNORMAL);
return true;
}
virtual void VSync() = 0;
virtual bool MakeSnapshot(LPCTSTR path) = 0;
};
template<class Device, class Vertex>
class GPURenderer : public GPURendererBase
{
protected:
typedef typename Device::Texture Texture;
Vertex* m_vertices;
int m_count;
int m_maxcount;
GSVertexList<Vertex> m_vl;
void Reset()
{
m_count = 0;
m_vl.RemoveAll();
__super::Reset();
}
void VertexKick()
{
if(m_vl.GetCount() < m_env.PRIM.VTX)
{
return;
}
if(m_count > m_maxcount)
{
m_maxcount = max(10000, m_maxcount * 3/2);
m_vertices = (Vertex*)_aligned_realloc(m_vertices, sizeof(Vertex) * m_maxcount, 16);
m_maxcount -= 100;
}
Vertex* v = &m_vertices[m_count];
int count = 0;
switch(m_env.PRIM.TYPE)
{
case GPU_POLYGON:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.GetAt(2, v[2]);
m_vl.RemoveAll();
count = 3;
break;
case GPU_LINE:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.RemoveAll();
count = 2;
break;
case GPU_SPRITE:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.RemoveAll();
count = 2;
break;
default:
ASSERT(0);
m_vl.RemoveAll();
count = 0;
break;
}
(this->*m_fpDrawingKickHandlers[m_env.PRIM.TYPE])(v, count);
m_count += count;
}
typedef void (GPURenderer<Device, Vertex>::*DrawingKickHandler)(Vertex* v, int& count);
DrawingKickHandler m_fpDrawingKickHandlers[4];
void DrawingKickNull(Vertex* v, int& count)
{
ASSERT(0);
}
void ResetPrim()
{
m_vl.RemoveAll();
}
void FlushPrim()
{
if(m_count > 0)
{
/*
Dump(_T("db"));
if(m_env.PRIM.TME)
{
CRect r;
r.left = m_env.STATUS.TX << 6;
r.top = m_env.STATUS.TY << 8;
r.right = r.left + 256;
r.bottom = r.top + 256;
CString str;
str.Format(_T("da_%d_%d_%d_%d_%d"), m_env.STATUS.TP, r);
Dump(str, m_env.STATUS.TP, r, false);
}
*/
Draw();
m_count = 0;
//Dump(_T("dc"), false);
}
}
virtual void ResetDevice() {}
virtual void Draw() = 0;
virtual bool GetOutput(Texture& t) = 0;
bool Merge()
{
Texture st[2];
if(!GetOutput(st[0]))
{
return false;
}
CSize s;
s.cx = st[0].GetWidth();
s.cy = st[0].GetHeight();
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.cx;
dr[0].w = (float)s.cy;
GSVector4 c(0, 0, 0, 1);
m_dev.Merge(st, sr, dr, s, 1, 1, c);
return true;
}
public:
Device m_dev;
public:
GPURenderer(const GPURendererSettings& rs)
: GPURendererBase(rs)
, m_count(0)
, m_maxcount(10000)
{
m_vertices = (Vertex*)_aligned_malloc(sizeof(Vertex) * m_maxcount, 16);
m_maxcount -= 100;
for(int i = 0; i < countof(m_fpDrawingKickHandlers); i++)
{
m_fpDrawingKickHandlers[i] = &GPURenderer<Device, Vertex>::DrawingKickNull;
}
}
virtual ~GPURenderer()
{
if(m_vertices) _aligned_free(m_vertices);
}
virtual bool Create(HWND hWnd)
{
if(!__super::Create(hWnd))
{
return false;
}
if(!m_dev.Create(hWnd, m_vsync))
{
return false;
}
Reset();
return true;
}
virtual void VSync()
{
GSPerfMonAutoTimer pmat(m_perfmon);
// m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ?
if(!IsWindow(m_hWnd))
{
return;
}
Flush();
m_perfmon.Put(GSPerfMon::Frame);
if(!Merge())
{
return;
}
// osd
static UINT64 s_frame = 0;
static CString 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);
CRect r = m_env.GetDisplayRect();
int w = r.Width() << m_scale.cx;
int h = r.Height() << m_scale.cy;
s_stats.Format(
_T("%I64d | %d x %d | %.2f fps (%d%%) | %d/%d | %d%% CPU | %.2f | %.2f"),
m_perfmon.GetFrame(), w, h, fps, (int)(100.0 * fps / m_env.GetFPS()),
(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(_T("%s | %.2f mpps"), CString(s_stats), fps * fillrate / (1024 * 1024));
}
SetWindowText(m_hWnd, s_stats);
}
if(m_dev.IsLost())
{
ResetDevice();
}
CRect r;
GetClientRect(m_hWnd, &r);
GSUtil::FitRect(r, m_aspectratio);
m_dev.Present(r);
}
virtual bool MakeSnapshot(LPCTSTR path)
{
CString fn;
fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S")));
return m_dev.SaveCurrent(fn + _T(".bmp"));
}
};

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GPURendererSW.h"

View File

@ -0,0 +1,218 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPURenderer.h"
#include "GPUDrawScanline.h"
template <class Device>
class GPURendererSW : public GPURenderer<Device, GSVertexSW>
{
protected:
GSRasterizerList m_rl;
Texture m_texture;
void ResetDevice()
{
m_texture = Texture();
}
bool GetOutput(Texture& t)
{
CRect r = m_env.GetDisplayRect();
r.left <<= m_scale.cx;
r.top <<= m_scale.cy;
r.right <<= m_scale.cx;
r.bottom <<= m_scale.cy;
// TODO
static DWORD* buff = (DWORD*)_aligned_malloc(m_mem.GetWidth() * m_mem.GetHeight() * sizeof(DWORD), 16);
m_mem.ReadFrame32(r, buff, !!m_env.STATUS.ISRGB24);
r.OffsetRect(-r.TopLeft());
if(m_texture.GetWidth() != r.Width() || m_texture.GetHeight() != r.Height())
{
m_texture = Texture();
}
if(!m_texture && !m_dev.CreateTexture(m_texture, r.Width(), r.Height()))
{
return false;
}
m_texture.Update(r, buff, m_mem.GetWidth() * sizeof(DWORD));
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.cx;
int y = (int)(m_v.XY.Y + m_env.DROFF.Y) << m_scale.cy;
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((DWORD)m_v.RGB.ai32) * 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 v;
v.x = (int)m_env.DRAREATL.X << m_scale.cx;
v.y = (int)m_env.DRAREATL.Y << m_scale.cy;
v.z = min((int)(m_env.DRAREABR.X + 1) << m_scale.cx, m_mem.GetWidth());
v.w = min((int)(m_env.DRAREABR.Y + 1) << m_scale.cy, m_mem.GetHeight());
return v;
}
void Draw()
{
const GPUDrawingEnvironment& env = m_env;
//
GPUScanlineParam p;
p.sel.dw = 0;
p.sel.iip = env.PRIM.IIP;
p.sel.me = env.STATUS.ME;
p.sel.abe = env.PRIM.ABE;
p.sel.abr = env.STATUS.ABR;
p.sel.tge = env.PRIM.TGE;
p.sel.tme = env.PRIM.TME;
p.sel.tlu = env.STATUS.TP < 2;
p.sel.twin = (env.TWIN.ai32 & 0xfffff) != 0;
p.sel.dtd = m_dither ? env.STATUS.DTD : 0;
p.sel.ltf = m_filter == 1 && env.PRIM.TYPE == GPU_POLYGON || m_filter == 2 ? 1 : 0;
if(env.PRIM.TME)
{
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);
}
//
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 scissor = data.scissor;
CRect r;
r.left = max(scissor.x, min(scissor.z, (int)tl.x)) >> m_scale.cx;
r.top = max(scissor.y, min(scissor.w, (int)tl.y)) >> m_scale.cy;
r.right = max(scissor.x, min(scissor.z, (int)br.x)) >> m_scale.cx;
r.bottom = max(scissor.y, min(scissor.w, (int)br.y)) >> m_scale.cy;
Invalidate(r);
}
}
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()
{
}
};

View File

@ -0,0 +1,301 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSdx.h"
#include "GSUtil.h"
#include "GPUSettingsDlg.h"
#include <shlobj.h>
#include <afxpriv.h>
GSSetting GPUSettingsDlg::g_renderers[] =
{
{0, _T("Direct3D7 (Software)"), NULL},
{1, _T("Direct3D9 (Software)"), NULL},
{2, _T("Direct3D10 (Software)"), NULL},
// {3, _T("Null (Null)"), NULL},
};
GSSetting GPUSettingsDlg::g_psversion[] =
{
{D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0"), NULL},
{D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0"), NULL},
//{D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4"), NULL},
//{D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1"), NULL},
//{D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)"), NULL},
};
GSSetting GPUSettingsDlg::g_filter[] =
{
{0, _T("Nearest"), NULL},
{1, _T("Bilinear (polygons only)"), NULL},
{2, _T("Bilinear"), NULL},
};
GSSetting GPUSettingsDlg::g_dithering[] =
{
{0, _T("Disabled"), NULL},
{1, _T("Auto"), NULL},
};
GSSetting GPUSettingsDlg::g_aspectratio[] =
{
{0, _T("Stretch"), NULL},
{1, _T("4:3"), NULL},
{2, _T("16:9"), NULL},
};
GSSetting GPUSettingsDlg::g_internalresolution[] =
{
{0 | (0 << 2), _T("H x 1 - V x 1"), NULL},
{1 | (0 << 2), _T("H x 2 - V x 1"), NULL},
{0 | (1 << 2), _T("H x 1 - V x 2"), NULL},
{1 | (1 << 2), _T("H x 2 - V x 2"), NULL},
{2 | (1 << 2), _T("H x 4 - V x 2"), NULL},
{1 | (2 << 2), _T("H x 2 - V x 4"), NULL},
{2 | (2 << 2), _T("H x 4 - V x 4"), NULL},
};
IMPLEMENT_DYNAMIC(GPUSettingsDlg, CDialog)
GPUSettingsDlg::GPUSettingsDlg(CWnd* pParent /*=NULL*/)
: CDialog(GPUSettingsDlg::IDD, pParent)
{
}
GPUSettingsDlg::~GPUSettingsDlg()
{
}
LRESULT GPUSettingsDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
if(message == WM_INITDIALOG)
{
SendMessage(WM_KICKIDLE);
}
return ret;
}
void GPUSettingsDlg::DoDataExchange(CDataExchange* pDX)
{
__super::DoDataExchange(pDX);
DDX_Control(pDX, IDC_COMBO3, m_resolution);
DDX_Control(pDX, IDC_COMBO1, m_renderer);
DDX_Control(pDX, IDC_COMBO4, m_psversion);
DDX_Control(pDX, IDC_COMBO2, m_filter);
DDX_Control(pDX, IDC_COMBO5, m_dithering);
DDX_Control(pDX, IDC_COMBO6, m_aspectratio);
DDX_Control(pDX, IDC_COMBO7, m_internalresolution);
DDX_Control(pDX, IDC_SPIN3, m_swthreads);
DDX_Control(pDX, IDC_EDIT3, m_swthreadsedit);
}
BEGIN_MESSAGE_MAP(GPUSettingsDlg, CDialog)
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateD3D9Options)
ON_UPDATE_COMMAND_UI(IDC_COMBO7, OnUpdateSWOptions)
ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateSWOptions)
ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateSWOptions)
ON_CBN_SELCHANGE(IDC_COMBO1, &GPUSettingsDlg::OnCbnSelchangeCombo1)
END_MESSAGE_MAP()
void GPUSettingsDlg::OnKickIdle()
{
UpdateDialogControls(this, false);
}
BOOL GPUSettingsDlg::OnInitDialog()
{
__super::OnInitDialog();
CWinApp* pApp = AfxGetApp();
D3DCAPS9 caps;
memset(&caps, 0, sizeof(caps));
caps.PixelShaderVersion = D3DPS_VERSION(0, 0);
m_modes.RemoveAll();
// windowed
{
D3DDISPLAYMODE mode;
memset(&mode, 0, sizeof(mode));
m_modes.AddTail(mode);
int iItem = m_resolution.AddString(_T("Windowed"));
m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition());
m_resolution.SetCurSel(iItem);
}
// fullscreen
if(CComPtr<IDirect3D9> d3d = Direct3DCreate9(D3D_SDK_VERSION))
{
UINT ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0);
UINT ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0);
UINT ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0);
UINT nModes = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);
for(UINT i = 0; i < nModes; i++)
{
D3DDISPLAYMODE mode;
if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode))
{
CString str;
str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate);
int iItem = m_resolution.AddString(str);
m_modes.AddTail(mode);
m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition());
if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate)
{
m_resolution.SetCurSel(iItem);
}
}
}
d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
}
bool isdx10avail = GSUtil::IsDirect3D10Available();
CAtlArray<GSSetting> renderers;
for(size_t i = 0; i < countof(g_renderers); i++)
{
if(i == 2 && !isdx10avail) continue;
renderers.Add(g_renderers[i]);
}
GSSetting::InitComboBox(renderers.GetData(), renderers.GetCount(), m_renderer, pApp->GetProfileInt(_T("GPUSettings"), _T("Renderer"), 1));
GSSetting::InitComboBox(g_psversion, countof(g_psversion), m_psversion, pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)), caps.PixelShaderVersion);
GSSetting::InitComboBox(g_filter, countof(g_filter), m_filter, pApp->GetProfileInt(_T("GPUSettings"), _T("filter"), 0));
GSSetting::InitComboBox(g_dithering, countof(g_dithering), m_dithering, pApp->GetProfileInt(_T("GPUSettings"), _T("dithering"), 1));
GSSetting::InitComboBox(g_aspectratio, countof(g_aspectratio), m_aspectratio, pApp->GetProfileInt(_T("GPUSettings"), _T("AspectRatio"), 1));
GSSetting::InitComboBox(g_internalresolution, countof(g_internalresolution), m_internalresolution, pApp->GetProfileInt(_T("GPUSettings"), _T("scale_x"), 0) | (pApp->GetProfileInt(_T("GPUSettings"), _T("scale_y"), 0) << 2));
OnCbnSelchangeCombo1();
//
m_swthreads.SetRange(1, 16);
m_swthreads.SetPos(pApp->GetProfileInt(_T("GPUSettings"), _T("swthreads"), 1));
//
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void GPUSettingsDlg::OnOK()
{
CWinApp* pApp = AfxGetApp();
UpdateData();
if(m_resolution.GetCurSel() >= 0)
{
D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel()));
pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width);
pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height);
pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate);
}
if(m_renderer.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("GPUSettings"), _T("Renderer"), (DWORD)m_renderer.GetItemData(m_renderer.GetCurSel()));
}
if(m_psversion.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), (DWORD)m_psversion.GetItemData(m_psversion.GetCurSel()));
}
if(m_filter.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("GPUSettings"), _T("filter"), (DWORD)m_filter.GetItemData(m_filter.GetCurSel()));
}
if(m_dithering.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("GPUSettings"), _T("dithering"), (DWORD)m_dithering.GetItemData(m_dithering.GetCurSel()));
}
if(m_aspectratio.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("GPUSettings"), _T("AspectRatio"), (DWORD)m_aspectratio.GetItemData(m_aspectratio.GetCurSel()));
}
if(m_internalresolution.GetCurSel() >= 0)
{
DWORD value = (DWORD)m_internalresolution.GetItemData(m_internalresolution.GetCurSel());
pApp->WriteProfileInt(_T("GPUSettings"), _T("scale_x"), value & 3);
pApp->WriteProfileInt(_T("GPUSettings"), _T("scale_y"), (value >> 2) & 3);
}
pApp->WriteProfileInt(_T("GPUSettings"), _T("swthreads"), m_swthreads.GetPos());
__super::OnOK();
}
void GPUSettingsDlg::OnUpdateResolution(CCmdUI* pCmdUI)
{
UpdateData();
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
pCmdUI->Enable(i == 1);
}
void GPUSettingsDlg::OnUpdateD3D9Options(CCmdUI* pCmdUI)
{
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
pCmdUI->Enable(i == 1);
}
void GPUSettingsDlg::OnUpdateSWOptions(CCmdUI* pCmdUI)
{
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
pCmdUI->Enable(i >= 0 && i <= 2);
}
void GPUSettingsDlg::OnCbnSelchangeCombo1()
{
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
GetDlgItem(IDC_LOGO9)->ShowWindow(i == 1 ? SW_SHOW : SW_HIDE);
GetDlgItem(IDC_LOGO10)->ShowWindow(i == 2 ? SW_SHOW : SW_HIDE);
}

View File

@ -0,0 +1,71 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSSetting.h"
#include "resource.h"
class GPUSettingsDlg : public CDialog
{
DECLARE_DYNAMIC(GPUSettingsDlg)
private:
CAtlList<D3DDISPLAYMODE> m_modes;
public:
GPUSettingsDlg(CWnd* pParent = NULL); // standard constructor
virtual ~GPUSettingsDlg();
static GSSetting g_renderers[];
static GSSetting g_psversion[];
static GSSetting g_filter[];
static GSSetting g_dithering[];
static GSSetting g_aspectratio[];
static GSSetting g_internalresolution[];
// Dialog Data
enum { IDD = IDD_GPUCONFIG };
CComboBox m_resolution;
CComboBox m_renderer;
CComboBox m_psversion;
CComboBox m_filter;
CComboBox m_dithering;
CComboBox m_aspectratio;
CComboBox m_internalresolution;
CSpinButtonCtrl m_swthreads;
CEdit m_swthreadsedit;
protected:
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual BOOL OnInitDialog();
virtual void OnOK();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKickIdle();
afx_msg void OnUpdateResolution(CCmdUI* pCmdUI);
afx_msg void OnUpdateD3D9Options(CCmdUI* pCmdUI);
afx_msg void OnUpdateSWOptions(CCmdUI* pCmdUI);
afx_msg void OnCbnSelchangeCombo1();
};

747
plugins/GSdx/GPUState.cpp Normal file
View File

@ -0,0 +1,747 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GPUState.h"
GPUState::GPUState(const CSize& scale)
: m_mem(scale)
, s_n(0)
{
memset(m_status, 0, sizeof(m_status));
for(int i = 0; i < countof(m_fpGPUStatusCommandHandlers); i++)
{
m_fpGPUStatusCommandHandlers[i] = &GPUState::SCH_Null;
}
m_fpGPUStatusCommandHandlers[0x00] = &GPUState::SCH_ResetGPU;
m_fpGPUStatusCommandHandlers[0x01] = &GPUState::SCH_ResetCommandBuffer;
m_fpGPUStatusCommandHandlers[0x02] = &GPUState::SCH_ResetIRQ;
m_fpGPUStatusCommandHandlers[0x03] = &GPUState::SCH_DisplayEnable;
m_fpGPUStatusCommandHandlers[0x04] = &GPUState::SCH_DMASetup;
m_fpGPUStatusCommandHandlers[0x05] = &GPUState::SCH_StartOfDisplayArea;
m_fpGPUStatusCommandHandlers[0x06] = &GPUState::SCH_HorizontalDisplayRange;
m_fpGPUStatusCommandHandlers[0x07] = &GPUState::SCH_VerticalDisplayRange;
m_fpGPUStatusCommandHandlers[0x08] = &GPUState::SCH_DisplayMode;
m_fpGPUStatusCommandHandlers[0x10] = &GPUState::SCH_GPUInfo;
m_fpGPUPacketHandler[0] = &GPUState::PH_Command;
m_fpGPUPacketHandler[1] = &GPUState::PH_Polygon;
m_fpGPUPacketHandler[2] = &GPUState::PH_Line;
m_fpGPUPacketHandler[3] = &GPUState::PH_Sprite;
m_fpGPUPacketHandler[4] = &GPUState::PH_Move;
m_fpGPUPacketHandler[5] = &GPUState::PH_Write;
m_fpGPUPacketHandler[6] = &GPUState::PH_Read;
m_fpGPUPacketHandler[7] = &GPUState::PH_Environment;
Reset();
}
GPUState::~GPUState()
{
}
void GPUState::Reset()
{
m_env.Reset();
m_mem.Invalidate(CRect(0, 0, 1024, 512));
memset(&m_v, 0, sizeof(m_v));
}
void GPUState::Flush()
{
FlushPrim();
}
void GPUState::SetPrim(GPUReg* r)
{
if(m_env.PRIM.TYPE != r->PRIM.TYPE)
{
ResetPrim();
}
GPURegPRIM PRIM = r->PRIM;
PRIM.VTX = 0;
switch(r->PRIM.TYPE)
{
case GPU_POLYGON:
PRIM.ai32 = (r->PRIM.ai32 & 0xF7000000) | 3; // TYPE IIP TME ABE TGE
break;
case GPU_LINE:
PRIM.ai32 = (r->PRIM.ai32 & 0xF2000000) | 2; // TYPE IIP ABE
PRIM.TGE = 1; // ?
break;
case GPU_SPRITE:
PRIM.ai32 = (r->PRIM.ai32 & 0xE7000000) | 2; // TYPE TME ABE TGE
break;
}
if(m_env.PRIM.ai32 != PRIM.ai32)
{
Flush();
m_env.PRIM = PRIM;
}
}
void GPUState::SetCLUT(GPUReg* r)
{
UINT32 mask = 0xFFFF0000; // X Y
UINT32 value = (m_env.CLUT.ai32 & ~mask) | (r->ai32 & mask);
if(m_env.CLUT.ai32 != value)
{
Flush();
m_env.CLUT.ai32 = value;
}
}
void GPUState::SetTPAGE(GPUReg* r)
{
UINT32 mask = 0x000001FF; // TP ABR TY TX
UINT32 value = (m_env.STATUS.ai32 & ~mask) | ((r->ai32 >> 16) & mask);
if(m_env.STATUS.ai32 != value)
{
Flush();
m_env.STATUS.ai32 = value;
}
}
void GPUState::Invalidate(const CRect& r)
{
m_mem.Invalidate(r);
}
void GPUState::WriteData(const BYTE* mem, UINT32 size)
{
GSPerfMonAutoTimer pmat(m_perfmon);
size <<= 2;
m_write.Append(mem, size);
int i = 0;
while(i < m_write.bytes)
{
GPUReg* r = (GPUReg*)&m_write.buff[i];
int ret = (this->*m_fpGPUPacketHandler[r->PACKET.TYPE])(r, (m_write.bytes - i) >> 2);
if(ret == 0) return; // need more data
i += ret << 2;
}
m_write.Remove(i);
}
void GPUState::ReadData(BYTE* mem, UINT32 size)
{
GSPerfMonAutoTimer pmat(m_perfmon);
int remaining = m_read.bytes - m_read.cur;
int bytes = (int)size << 2;
if(bytes > remaining)
{
// ASSERT(0);
TRACE(_T("WARNING: ReadData\n"));
// memset(&mem[remaining], 0, bytes - remaining);
bytes = remaining;
}
memcpy(mem, &m_read.buff[m_read.cur], bytes);
m_read.cur += bytes;
if(m_read.cur >= m_read.bytes)
{
m_env.STATUS.IMG = 0;
}
}
void GPUState::WriteStatus(UINT32 status)
{
GSPerfMonAutoTimer pmat(m_perfmon);
UINT32 b = status >> 24;
m_status[b] = status;
(this->*m_fpGPUStatusCommandHandlers[b])((GPUReg*)&status);
}
UINT32 GPUState::ReadStatus()
{
GSPerfMonAutoTimer pmat(m_perfmon);
m_env.STATUS.LCF = ~m_env.STATUS.LCF; // ?
return m_env.STATUS.ai32;
}
void GPUState::Freeze(GPUFreezeData* data)
{
data->status = m_env.STATUS.ai32;
memcpy(data->control, m_status, 256 * 4);
m_mem.ReadRect(CRect(0, 0, 1024, 512), data->vram);
}
void GPUState::Defrost(const GPUFreezeData* data)
{
m_env.STATUS.ai32 = data->status;
memcpy(m_status, data->control, 256 * 4);
m_mem.WriteRect(CRect(0, 0, 1024, 512), data->vram);
for(int i = 0; i <= 8; i++)
{
WriteStatus(m_status[i]);
}
}
void GPUState::SCH_Null(GPUReg* r)
{
ASSERT(0);
}
void GPUState::SCH_ResetGPU(GPUReg* r)
{
Reset();
}
void GPUState::SCH_ResetCommandBuffer(GPUReg* r)
{
// ?
}
void GPUState::SCH_ResetIRQ(GPUReg* r)
{
// ?
}
void GPUState::SCH_DisplayEnable(GPUReg* r)
{
m_env.STATUS.DEN = r->DEN.DEN;
}
void GPUState::SCH_DMASetup(GPUReg* r)
{
m_env.STATUS.DMA = r->DMA.DMA;
}
void GPUState::SCH_StartOfDisplayArea(GPUReg* r)
{
m_env.DAREA = r->DAREA;
}
void GPUState::SCH_HorizontalDisplayRange(GPUReg* r)
{
m_env.DHRANGE = r->DHRANGE;
}
void GPUState::SCH_VerticalDisplayRange(GPUReg* r)
{
m_env.DVRANGE = r->DVRANGE;
}
void GPUState::SCH_DisplayMode(GPUReg* r)
{
m_env.STATUS.WIDTH0 = r->DMODE.WIDTH0;
m_env.STATUS.HEIGHT = r->DMODE.HEIGHT;
m_env.STATUS.ISPAL = r->DMODE.ISPAL;
m_env.STATUS.ISRGB24 = r->DMODE.ISRGB24;
m_env.STATUS.ISINTER = r->DMODE.ISINTER;
m_env.STATUS.WIDTH1 = r->DMODE.WIDTH1;
}
void GPUState::SCH_GPUInfo(GPUReg* r)
{
UINT32 value = 0;
switch(r->GPUINFO.PARAM)
{
case 0x2:
value = m_env.TWIN.ai32;
break;
case 0x0:
case 0x1:
case 0x3:
value = m_env.DRAREATL.ai32;
break;
case 0x4:
value = m_env.DRAREABR.ai32;
break;
case 0x5:
case 0x6:
value = m_env.DROFF.ai32;
break;
case 0x7:
value = 2;
break;
case 0x8:
case 0xf:
value = 0xBFC03720; // ?
break;
default:
ASSERT(0);
break;
}
m_read.RemoveAll();
m_read.Append((BYTE*)&value, 4);
m_read.cur = 0;
}
int GPUState::PH_Command(GPUReg* r, int size)
{
switch(r->PACKET.OPTION)
{
case 0: // ???
return 1;
case 1: // clear cache
return 1;
case 2: // fillrect
if(size < 3) return 0;
Flush();
CRect r2;
r2.left = r[1].XY.X;
r2.top = r[1].XY.Y;
r2.right = r2.left + r[2].XY.X;
r2.bottom = r2.top + r[2].XY.Y;
WORD c = (WORD)(((r[0].RGB.R >> 3) << 10) | ((r[0].RGB.R >> 3) << 5) | (r[0].RGB.R >> 3));
m_mem.FillRect(r2, c);
Invalidate(r2);
Dump(_T("f"));
return 3;
}
ASSERT(0);
return 1;
}
int GPUState::PH_Polygon(GPUReg* r, int size)
{
int required = 1;
int vertices = r[0].POLYGON.VTX ? 4 : 3;
required += vertices;
if(r[0].POLYGON.TME) required += vertices;
if(r[0].POLYGON.IIP) required += vertices - 1;
if(size < required) return 0;
//
SetPrim(r);
if(r[0].POLYGON.TME)
{
SetCLUT(&r[2]);
SetTPAGE(&r[r[0].POLYGON.IIP ? 5 : 4]);
}
//
GPUVertex v[4];
for(int i = 0, j = 0; j < vertices; j++)
{
v[j].RGB = r[r[0].POLYGON.IIP ? i : 0].RGB;
if(j == 0 || r[0].POLYGON.IIP) i++;
v[j].XY = r[i++].XY;
if(r[0].POLYGON.TME)
{
v[j].UV.X = r[i].UV.U;
v[j].UV.Y = r[i].UV.V;
i++;
}
}
for(int i = 0; i <= vertices - 3; i++)
{
for(int j = 0; j < 3; j++)
{
m_v = v[i + j];
VertexKick();
}
}
//
return required;
}
int GPUState::PH_Line(GPUReg* r, int size)
{
int required = 1;
int vertices = 0;
if(r->LINE.PLL)
{
required++;
for(int i = 1; i < size; i++)
{
if(r[i].ai32 == 0x55555555)
{
vertices = i - 1;
}
}
if(vertices < 2)
{
return 0;
}
}
else
{
vertices = 2;
}
required += vertices;
if(r->LINE.IIP) required += vertices - 1;
//
SetPrim(r);
//
for(int i = 0, j = 0; j < vertices; j++)
{
if(j >= 2) VertexKick();
m_v.RGB = r[r[0].LINE.IIP ? i : 0].RGB;
if(j == 0 || r[0].LINE.IIP) i++;
m_v.XY = r[i++].XY;
VertexKick();
}
//
return required;
}
int GPUState::PH_Sprite(GPUReg* r, int size)
{
int required = 2;
if(r[0].SPRITE.TME) required++;
if(r[0].SPRITE.SIZE == 0) required++;
if(size < required) return 0;
//
SetPrim(r);
if(r[0].SPRITE.TME)
{
SetCLUT(&r[2]);
}
//
int i = 0;
m_v.RGB = r[i++].RGB;
m_v.XY = r[i++].XY;
if(r[0].SPRITE.TME)
{
m_v.UV.X = r[i].UV.U;
m_v.UV.Y = r[i].UV.V;
i++;
}
VertexKick();
int w = 0;
int h = 0;
switch(r[0].SPRITE.SIZE)
{
case 0: w = r[i].XY.X; h = r[i].XY.Y; i++; break;
case 1: w = h = 1; break;
case 2: w = h = 8; break;
case 3: w = h = 16; break;
default: __assume(0);
}
m_v.XY.X += w;
m_v.XY.Y += h;
if(r[0].SPRITE.TME)
{
m_v.UV.X += w;
m_v.UV.Y += h;
}
VertexKick();
//
return required;
}
int GPUState::PH_Move(GPUReg* r, int size)
{
if(size < 4) return 0;
Flush();
CPoint src, dst;
src.x = r[1].XY.X;
src.y = r[1].XY.Y;
dst.x = r[2].XY.X;
dst.y = r[2].XY.Y;
int w = r[3].XY.X;
int h = r[3].XY.Y;
m_mem.MoveRect(src, dst, w, h);
Invalidate(CRect(dst, CSize(w, h)));
// Dump(_T("m"));
return 4;
}
int GPUState::PH_Write(GPUReg* r, int size)
{
if(size < 3) return 0;
int w = r[2].XY.X;
int h = r[2].XY.Y;
int required = 3 + ((w * h + 1) >> 1);
if(size < required) return 0;
Flush();
CRect r2;
r2.left = r[1].XY.X;
r2.top = r[1].XY.Y;
r2.right = r2.left + w;
r2.bottom = r2.top + h;
m_mem.WriteRect(r2, (const WORD*)&r[3]);
Invalidate(r2);
Dump(_T("w"));
m_perfmon.Put(GSPerfMon::Swizzle, w * h * 2);
return required;
}
int GPUState::PH_Read(GPUReg* r, int size)
{
if(size < 3) return 0;
Flush();
int w = r[2].XY.X;
int h = r[2].XY.Y;
CRect r2;
r2.left = r[1].XY.X;
r2.top = r[1].XY.Y;
r2.right = r2.left + w;
r2.bottom = r2.top + h;
m_read.bytes = ((w * h + 1) & ~1) * 2;
m_read.cur = 0;
m_read.Reserve(m_read.bytes);
m_mem.ReadRect(r2, (WORD*)m_read.buff);
Dump(_T("r"));
m_env.STATUS.IMG = 1;
return 3;
}
int GPUState::PH_Environment(GPUReg* r, int size)
{
Flush(); // TODO: only call when something really changes
switch(r->PACKET.OPTION)
{
case 1: // draw mode setting
m_env.STATUS.TX = r->MODE.TX;
m_env.STATUS.TY = r->MODE.TY;
m_env.STATUS.ABR = r->MODE.ABR;
m_env.STATUS.TP = r->MODE.TP;
m_env.STATUS.DTD = r->MODE.DTD;
m_env.STATUS.DFE = r->MODE.DFE;
return 1;
case 2: // texture window setting
m_env.TWIN = r->TWIN;
return 1;
case 3: // set drawing area top left
m_env.DRAREATL = r->DRAREA;
return 1;
case 4: // set drawing area bottom right
m_env.DRAREABR = r->DRAREA;
return 1;
case 5: // drawing offset
m_env.DROFF = r->DROFF;
return 1;
case 6: // mask setting
m_env.STATUS.MD = r->MASK.MD;
m_env.STATUS.ME = r->MASK.ME;
return 1;
}
ASSERT(0);
return 1;
}
//
GPUState::Buffer::Buffer()
{
bytes = 0;
maxbytes = 4096;
buff = (BYTE*)_aligned_malloc(maxbytes, 16);
cur = 0;
}
GPUState::Buffer::~Buffer()
{
_aligned_free(buff);
}
void GPUState::Buffer::Reserve(int size)
{
if(size > maxbytes)
{
maxbytes = (maxbytes + size + 1023) & ~1023;
buff = (BYTE*)_aligned_realloc(buff, maxbytes, 16);
}
}
void GPUState::Buffer::Append(const BYTE* src, int size)
{
Reserve(bytes + (int)size);
memcpy(&buff[bytes], src, size);
bytes += size;
}
void GPUState::Buffer::Remove(int size)
{
ASSERT(size <= bytes);
if(size < bytes)
{
memmove(&buff[0], &buff[size], bytes - size);
bytes -= size;
}
else
{
bytes = 0;
}
#ifdef DEBUG
memset(&buff[bytes], 0xff, maxbytes - bytes);
#endif
}
void GPUState::Buffer::RemoveAll()
{
bytes = 0;
}

143
plugins/GSdx/GPUState.h Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPU.h"
#include "GPUDrawingEnvironment.h"
#include "GPULocalMemory.h"
#include "GPUVertex.h"
#include "GSAlignedClass.h"
#include "GSUtil.h"
#include "GSPerfMon.h"
class GPUState : public GSAlignedClass<16>
{
typedef void (GPUState::*GPUStatusCommandHandler)(GPUReg* r);
GPUStatusCommandHandler m_fpGPUStatusCommandHandlers[256];
void SCH_Null(GPUReg* r);
void SCH_ResetGPU(GPUReg* r);
void SCH_ResetCommandBuffer(GPUReg* r);
void SCH_ResetIRQ(GPUReg* r);
void SCH_DisplayEnable(GPUReg* r);
void SCH_DMASetup(GPUReg* r);
void SCH_StartOfDisplayArea(GPUReg* r);
void SCH_HorizontalDisplayRange(GPUReg* r);
void SCH_VerticalDisplayRange(GPUReg* r);
void SCH_DisplayMode(GPUReg* r);
void SCH_GPUInfo(GPUReg* r);
typedef int (GPUState::*GPUPacketHandler)(GPUReg* r, int size);
GPUPacketHandler m_fpGPUPacketHandler[8];
int PH_Command(GPUReg* r, int size);
int PH_Polygon(GPUReg* r, int size);
int PH_Line(GPUReg* r, int size);
int PH_Sprite(GPUReg* r, int size);
int PH_Move(GPUReg* r, int size);
int PH_Write(GPUReg* r, int size);
int PH_Read(GPUReg* r, int size);
int PH_Environment(GPUReg* r, int size);
class Buffer
{
public:
int bytes;
int maxbytes;
BYTE* buff;
int cur;
public:
Buffer();
~Buffer();
void Reserve(int size);
void Append(const BYTE* src, int size);
void Remove(int size);
void RemoveAll();
};
Buffer m_write;
Buffer m_read;
void SetPrim(GPUReg* r);
void SetCLUT(GPUReg* r);
void SetTPAGE(GPUReg* r);
protected:
int s_n;
void Dump(LPCTSTR s, UINT32 TP, const CRect& r, int inc = true)
{
//if(m_perfmon.GetFrame() < 1000)
//if((m_env.TWIN.ai32 & 0xfffff) == 0)
//if(!m_env.STATUS.ME && !m_env.STATUS.MD)
return;
if(inc) s_n++;
//if(s_n < 86) return;
int dir = 1;
#ifdef DEBUG
dir = 2;
#endif
CString str;
str.Format(_T("c:\\temp%d\\%04d_%s.bmp"), dir, s_n, s);
m_mem.SaveBMP(str, r, TP, m_env.CLUT.X, m_env.CLUT.Y);
}
void Dump(LPCTSTR s, int inc = true)
{
Dump(s, 2, CRect(0, 0, 1024, 512), inc);
}
public:
GPUDrawingEnvironment m_env;
GPULocalMemory m_mem;
GPUVertex m_v;
GSPerfMon m_perfmon;
UINT32 m_status[256];
public:
GPUState(const CSize& scale);
virtual ~GPUState();
virtual void Reset();
virtual void Flush();
virtual void FlushPrim() = 0;
virtual void ResetPrim() = 0;
virtual void VertexKick() = 0;
virtual void Invalidate(const CRect& r);
void WriteData(const BYTE* mem, UINT32 size);
void ReadData(BYTE* mem, UINT32 size);
void WriteStatus(UINT32 status);
UINT32 ReadStatus();
void Freeze(GPUFreezeData* data);
void Defrost(const GPUFreezeData* data);
};

51
plugins/GSdx/GPUVertex.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GPU.h"
#include "GSVector.h"
#pragma pack(push, 1)
__declspec(align(16)) struct GPUVertex
{
union
{
struct
{
GPURegRGB RGB;
GPURegXY XY;
GPURegXY UV;
};
struct {__m128i m128i;};
struct {__m128 m128;};
};
GPUVertex() {memset(this, 0, sizeof(*this));}
};
struct GPUVertexNull
{
};
#pragma pack(pop)

589
plugins/GSdx/GS.cpp Normal file
View File

@ -0,0 +1,589 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSUtil.h"
#include "GSRendererHW9.h"
#include "GSRendererHW10.h"
#include "GSRendererSW.h"
#include "GSRendererNull.h"
#include "GSSettingsDlg.h"
#define PS2E_LT_GS 0x01
#define PS2E_GS_VERSION 0x0006
#define PS2E_X86 0x01 // 32 bit
#define PS2E_X86_64 0x02 // 64 bit
static HRESULT s_hr = E_FAIL;
static GSRendererBase* s_gs = NULL;
static void (*s_irq)() = NULL;
static BYTE* s_basemem = NULL;
EXPORT_C_(UINT32) PS2EgetLibType()
{
return PS2E_LT_GS;
}
EXPORT_C_(char*) PS2EgetLibName()
{
return GSUtil::GetLibName();
}
EXPORT_C_(UINT32) PS2EgetLibVersion2(UINT32 type)
{
const UINT32 revision = 0;
const UINT32 build = 1;
return (build << 0) | (revision << 8) | (PS2E_GS_VERSION << 16) | (PLUGIN_VERSION << 24);
}
EXPORT_C_(UINT32) PS2EgetCpuPlatform()
{
#if _M_AMD64
return PS2E_X86_64;
#else
return PS2E_X86;
#endif
}
EXPORT_C GSsetBaseMem(BYTE* mem)
{
s_basemem = mem - 0x12000000;
}
EXPORT_C_(INT32) GSinit()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return 0;
}
EXPORT_C GSshutdown()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
}
EXPORT_C GSclose()
{
delete s_gs;
s_gs = NULL;
if(SUCCEEDED(s_hr))
{
::CoUninitialize();
s_hr = E_FAIL;
}
}
static INT32 GSopen(void* dsp, char* title, int mt, int renderer)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if(!GSUtil::CheckDirectX() || !GSUtil::CheckSSE())
{
return -1;
}
GSclose();
// TODO
int nloophack = AfxGetApp()->GetProfileInt(_T("Settings"), _T("nloophack"), 2);
GSRendererSettings rs;
rs.m_interlace = AfxGetApp()->GetProfileInt(_T("Settings"), _T("interlace"), 0);
rs.m_aspectratio = AfxGetApp()->GetProfileInt(_T("Settings"), _T("aspectratio"), 1);
rs.m_filter = AfxGetApp()->GetProfileInt(_T("Settings"), _T("filter"), 1);
rs.m_vsync = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("vsync"), FALSE);
rs.m_nativeres = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("nativeres"), FALSE);
int threads = AfxGetApp()->GetProfileInt(_T("Settings"), _T("swthreads"), 1);
switch(renderer)
{
default:
case 0: s_gs = new GSRendererHW9(s_basemem, !!mt, s_irq, nloophack, rs); break;
case 1: s_gs = new GSRendererSW<GSDevice9>(s_basemem, !!mt, s_irq, nloophack, rs, threads); break;
case 2: s_gs = new GSRendererNull<GSDevice9>(s_basemem, !!mt, s_irq, nloophack, rs); break;
case 3: s_gs = new GSRendererHW10(s_basemem, !!mt, s_irq, nloophack, rs); break;
case 4: s_gs = new GSRendererSW<GSDevice10>(s_basemem, !!mt, s_irq, nloophack, rs, threads); break;
case 5: s_gs = new GSRendererNull<GSDevice10>(s_basemem, !!mt, s_irq, nloophack, rs); break;
case 6: s_gs = new GSRendererSW<GSDeviceNull>(s_basemem, !!mt, s_irq, nloophack, rs, threads); break;
case 7: s_gs = new GSRendererNull<GSDeviceNull>(s_basemem, !!mt, s_irq, nloophack, rs); break;
}
s_hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
if(!s_gs->Create(CString(title)))
{
GSclose();
return -1;
}
s_gs->m_wnd.Show();
*(HWND*)dsp = s_gs->m_wnd;
// if(mt) _mm_setcsr(MXCSR);
return 0;
}
EXPORT_C_(INT32) GSopen(void* dsp, char* title, int mt)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
int renderer = AfxGetApp()->GetProfileInt(_T("Settings"), _T("renderer"), 0);
return GSopen(dsp, title, mt, renderer);
}
EXPORT_C GSreset()
{
s_gs->Reset();
}
EXPORT_C GSgifSoftReset(int mask)
{
s_gs->SoftReset((BYTE)mask);
}
EXPORT_C GSwriteCSR(UINT32 csr)
{
s_gs->WriteCSR(csr);
}
EXPORT_C GSreadFIFO(BYTE* mem)
{
s_gs->ReadFIFO(mem, 1);
}
EXPORT_C GSreadFIFO2(BYTE* mem, UINT32 size)
{
s_gs->ReadFIFO(mem, size);
}
EXPORT_C GSgifTransfer1(BYTE* mem, UINT32 addr)
{
s_gs->Transfer<0>(mem + addr, (0x4000 - addr) / 16);
}
EXPORT_C GSgifTransfer2(BYTE* mem, UINT32 size)
{
s_gs->Transfer<1>(mem, size);
}
EXPORT_C GSgifTransfer3(BYTE* mem, UINT32 size)
{
s_gs->Transfer<2>(mem, size);
}
EXPORT_C GSvsync(int field)
{
s_gs->VSync(field);
}
EXPORT_C_(UINT32) GSmakeSnapshot(char* path)
{
return s_gs->MakeSnapshot(CString(path) + _T("gsdx"));
}
EXPORT_C GSkeyEvent(keyEvent* ev)
{
}
EXPORT_C_(INT32) GSfreeze(int mode, GSFreezeData* data)
{
if(mode == FREEZE_SAVE)
{
return s_gs->Freeze(data, false);
}
else if(mode == FREEZE_SIZE)
{
return s_gs->Freeze(data, true);
}
else if(mode == FREEZE_LOAD)
{
return s_gs->Defrost(data);
}
return 0;
}
EXPORT_C GSconfigure()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
GSSettingsDlg dlg;
if(IDOK == dlg.DoModal())
{
GSshutdown();
GSinit();
}
}
EXPORT_C_(INT32) GStest()
{
return 0;
// TODO
/*
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CComPtr<ID3D10Device> dev;
return SUCCEEDED(D3D10CreateDevice(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, 0, D3D10_SDK_VERSION, &dev)) ? 0 : -1;
*/
}
EXPORT_C GSabout()
{
}
EXPORT_C GSirqCallback(void (*irq)())
{
s_irq = irq;
}
EXPORT_C GSsetGameCRC(DWORD crc, int options)
{
s_gs->SetGameCRC(crc, options);
}
EXPORT_C GSgetLastTag(UINT32* tag)
{
s_gs->GetLastTag(tag);
}
EXPORT_C GSsetFrameSkip(int frameskip)
{
s_gs->SetFrameSkip(frameskip);
}
EXPORT_C GSReplay(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
int renderer = -1;
{
char* start = lpszCmdLine;
char* end = NULL;
long n = strtol(lpszCmdLine, &end, 10);
if(end > start) {renderer = n; lpszCmdLine = end;}
}
while(*lpszCmdLine == ' ') lpszCmdLine++;
::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS);
CAtlArray<BYTE> buff;
if(FILE* fp = fopen(lpszCmdLine, "rb"))
{
GSinit();
BYTE regs[0x2000];
GSsetBaseMem(regs);
HWND hWnd = NULL;
GSopen(&hWnd, _T(""), true, renderer);
DWORD crc;
fread(&crc, 4, 1, fp);
GSsetGameCRC(crc, 0);
GSFreezeData fd;
fread(&fd.size, 4, 1, fp);
fd.data = new BYTE[fd.size];
fread(fd.data, fd.size, 1, fp);
GSfreeze(FREEZE_LOAD, &fd);
delete [] fd.data;
fread(regs, 0x2000, 1, fp);
long start = ftell(fp);
unsigned int index, size, addr;
GSvsync(1);
while(1)
{
switch(fgetc(fp))
{
case EOF:
fseek(fp, start, 0);
if(!IsWindowVisible(hWnd)) return;
break;
case 0:
index = fgetc(fp);
fread(&size, 4, 1, fp);
switch(index)
{
case 0:
if(buff.GetCount() < 0x4000) buff.SetCount(0x4000);
addr = 0x4000 - size;
fread(buff.GetData() + addr, size, 1, fp);
GSgifTransfer1(buff.GetData(), addr);
break;
case 1:
if(buff.GetCount() < size) buff.SetCount(size);
fread(buff.GetData(), size, 1, fp);
GSgifTransfer2(buff.GetData(), size / 16);
break;
case 2:
if(buff.GetCount() < size) buff.SetCount(size);
fread(buff.GetData(), size, 1, fp);
GSgifTransfer3(buff.GetData(), size / 16);
break;
}
break;
case 1:
GSvsync(fgetc(fp));
if(!IsWindowVisible(hWnd)) return;
break;
case 2:
fread(&size, 4, 1, fp);
if(buff.GetCount() < size) buff.SetCount(size);
GSreadFIFO2(buff.GetData(), size / 16);
break;
case 3:
fread(regs, 0x2000, 1, fp);
break;
default:
return;
}
}
GSclose();
GSshutdown();
fclose(fp);
}
}
EXPORT_C GSBenchmark(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
::SetPriorityClass(::GetCurrentProcess(), HIGH_PRIORITY_CLASS);
FILE* file = _tfopen(_T("c:\\log.txt"), _T("a"));
_ftprintf(file, _T("-------------------------\n\n"));
if(1)
{
GSLocalMemory mem;
static struct {int psm; LPCSTR name;} s_format[] =
{
{PSM_PSMCT32, "32"},
{PSM_PSMCT24, "24"},
{PSM_PSMCT16, "16"},
{PSM_PSMCT16S, "16S"},
{PSM_PSMT8, "8"},
{PSM_PSMT4, "4"},
{PSM_PSMT8H, "8H"},
{PSM_PSMT4HL, "4HL"},
{PSM_PSMT4HH, "4HH"},
{PSM_PSMZ32, "32Z"},
{PSM_PSMZ24, "24Z"},
{PSM_PSMZ16, "16Z"},
{PSM_PSMZ16S, "16ZS"},
};
BYTE* ptr = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16);
for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (BYTE)i;
//
for(int tbw = 5; tbw <= 10; tbw++)
{
int n = 256 << ((10 - tbw) * 2);
int w = 1 << tbw;
int h = 1 << tbw;
_ftprintf(file, _T("%d x %d\n\n"), w, h);
for(int i = 0; i < countof(s_format); i++)
{
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[s_format[i].psm];
GSLocalMemory::writeImage wi = psm.wi;
GSLocalMemory::readImage ri = psm.ri;
GSLocalMemory::readTexture rtx = psm.rtx;
GSLocalMemory::readTexture rtxP = psm.rtxP;
GIFRegBITBLTBUF BITBLTBUF;
BITBLTBUF.SBP = 0;
BITBLTBUF.SBW = w / 64;
BITBLTBUF.SPSM = s_format[i].psm;
BITBLTBUF.DBP = 0;
BITBLTBUF.DBW = w / 64;
BITBLTBUF.DPSM = s_format[i].psm;
GIFRegTRXPOS TRXPOS;
TRXPOS.SSAX = 0;
TRXPOS.SSAY = 0;
TRXPOS.DSAX = 0;
TRXPOS.DSAY = 0;
GIFRegTRXREG TRXREG;
TRXREG.RRW = w;
TRXREG.RRH = h;
CRect r(0, 0, w, h);
GIFRegTEX0 TEX0;
TEX0.TBP0 = 0;
TEX0.TBW = w / 64;
GIFRegTEXA TEXA;
TEXA.TA0 = 0;
TEXA.TA1 = 0x80;
TEXA.AEM = 0;
int trlen = w * h * psm.trbpp / 8;
int len = w * h * psm.bpp / 8;
clock_t start, end;
_ftprintf(file, _T("[%4s] "), s_format[i].name);
start = clock();
for(int j = 0; j < n; j++)
{
int x = 0;
int y = 0;
(mem.*wi)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG);
}
end = clock();
_ftprintf(file, _T("%6d %6d | "), (int)((float)trlen * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
start = clock();
for(int j = 0; j < n; j++)
{
int x = 0;
int y = 0;
(mem.*ri)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG);
}
end = clock();
_ftprintf(file, _T("%6d %6d | "), (int)((float)trlen * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
start = clock();
for(int j = 0; j < n; j++)
{
(mem.*rtx)(r, ptr, w * 4, TEX0, TEXA);
}
end = clock();
_ftprintf(file, _T("%6d %6d "), (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
if(psm.pal > 0)
{
start = clock();
for(int j = 0; j < n; j++)
{
(mem.*rtxP)(r, ptr, w, TEX0, TEXA);
}
end = clock();
_ftprintf(file, _T("| %6d %6d "), (int)((float)len * n / (end - start) / 1000), (int)((float)(w * h) * n / (end - start) / 1000));
}
_ftprintf(file, _T("\n"));
fflush(file);
}
_ftprintf(file, _T("\n"));
}
_aligned_free(ptr);
}
//
if(0)
{
GSLocalMemory mem;
BYTE* ptr = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16);
for(int i = 0; i < 1024 * 1024 * 4; i++) ptr[i] = (BYTE)i;
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[PSM_PSMCT32];
GSLocalMemory::writeImage wi = psm.wi;
GIFRegBITBLTBUF BITBLTBUF;
BITBLTBUF.DBP = 0;
BITBLTBUF.DBW = 32;
BITBLTBUF.DPSM = PSM_PSMCT32;
GIFRegTRXPOS TRXPOS;
TRXPOS.DSAX = 0;
TRXPOS.DSAY = 1;
GIFRegTRXREG TRXREG;
TRXREG.RRW = 256;
TRXREG.RRH = 256;
int trlen = 256 * 256 * psm.trbpp / 8;
int x = 0;
int y = 0;
(mem.*wi)(x, y, ptr, trlen, BITBLTBUF, TRXPOS, TRXREG);
}
//
fclose(file);
}

1101
plugins/GSdx/GS.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSAlignedClass.h"

View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
template<int i> class GSAlignedClass
{
public:
GSAlignedClass() {}
void* operator new (size_t size)
{
return _aligned_malloc(size, i);
}
void operator delete (void* p)
{
_aligned_free(p);
}
void* operator new [] (size_t size)
{
return _aligned_malloc(size, i);
}
void operator delete [] (void* p)
{
_aligned_free(p);
}
};

37
plugins/GSdx/GSBlock.cpp Normal file
View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSBlock.h"
const GSVector4i GSBlock::m_r16mask(0, 1, 4, 5, 2, 3, 6, 7, 8, 9, 12, 13, 10, 11, 14, 15);
const GSVector4i GSBlock::m_r8mask(0, 4, 2, 6, 8, 12, 10, 14, 1, 5, 3, 7, 9, 13, 11, 15);
const GSVector4i GSBlock::m_r4mask(0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15);
const GSVector4i GSBlock::m_xxxa(0x00008000);
const GSVector4i GSBlock::m_xxbx(0x00007c00);
const GSVector4i GSBlock::m_xgxx(0x000003e0);
const GSVector4i GSBlock::m_rxxx(0x0000001f);
const GSVector4i GSBlock::m_uw8hmask0 = GSVector4i(0, 0, 0, 0, 1, 1, 1, 1, 8, 8, 8, 8, 9, 9, 9, 9);
const GSVector4i GSBlock::m_uw8hmask1 = GSVector4i(2, 2, 2, 2, 3, 3, 3, 3, 10, 10, 10, 10, 11, 11, 11, 11);
const GSVector4i GSBlock::m_uw8hmask2 = GSVector4i(4, 4, 4, 4, 5, 5, 5, 5, 12, 12, 12, 12, 13, 13, 13, 13);
const GSVector4i GSBlock::m_uw8hmask3 = GSVector4i(6, 6, 6, 6, 7, 7, 7, 7, 14, 14, 14, 14, 15, 15, 15, 15);

2289
plugins/GSdx/GSBlock.h Normal file

File diff suppressed because it is too large Load Diff

539
plugins/GSdx/GSCapture.cpp Normal file
View File

@ -0,0 +1,539 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSCapture.h"
#include "GSVector.h"
//
// GSSource
//
#ifdef __INTEL_COMPILER
interface __declspec(uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA"))
#else
[uuid("59C193BB-C520-41F3-BC1D-E245B80A86FA")] interface
#endif
IGSSource : public IUnknown
{
STDMETHOD(DeliverNewSegment)() PURE;
STDMETHOD(DeliverFrame)(const void* bits, int pitch, bool rgba) PURE;
STDMETHOD(DeliverEOS)() PURE;
};
#ifdef __INTEL_COMPILER
class __declspec(uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77"))
#else
[uuid("F8BB6F4F-0965-4ED4-BA74-C6A01E6E6C77")] class
#endif
GSSource : public CBaseFilter, private CCritSec, public IGSSource
{
CSize m_size;
REFERENCE_TIME m_atpf;
REFERENCE_TIME m_now;
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv)
{
return
QI(IGSSource)
__super::NonDelegatingQueryInterface(riid, ppv);
}
class GSSourceOutputPin : public CBaseOutputPin
{
CSize m_size;
CAtlArray<CMediaType> m_mts;
public:
GSSourceOutputPin(CSize size, REFERENCE_TIME atpf, CBaseFilter* pFilter, CCritSec* pLock, HRESULT& hr)
: CBaseOutputPin("GSSourceOutputPin", pFilter, pLock, &hr, L"Output")
, m_size(size)
{
CMediaType mt;
mt.majortype = MEDIATYPE_Video;
mt.formattype = FORMAT_VideoInfo;
VIDEOINFOHEADER vih;
memset(&vih, 0, sizeof(vih));
vih.AvgTimePerFrame = atpf;
vih.bmiHeader.biSize = sizeof(vih.bmiHeader);
vih.bmiHeader.biWidth = m_size.cx;
vih.bmiHeader.biHeight = m_size.cy;
#if _M_SSE >= 0x200
// YUY2
mt.subtype = MEDIASUBTYPE_YUY2;
mt.lSampleSize = m_size.cx * m_size.cy * 2;
vih.bmiHeader.biCompression = '2YUY';
vih.bmiHeader.biPlanes = 1;
vih.bmiHeader.biBitCount = 16;
vih.bmiHeader.biSizeImage = m_size.cx * m_size.cy * 2;
mt.SetFormat((BYTE*)&vih, sizeof(vih));
m_mts.Add(mt);
#endif
// RGB32
mt.subtype = MEDIASUBTYPE_RGB32;
mt.lSampleSize = m_size.cx * m_size.cy * 4;
vih.bmiHeader.biCompression = BI_RGB;
vih.bmiHeader.biPlanes = 1;
vih.bmiHeader.biBitCount = 32;
vih.bmiHeader.biSizeImage = m_size.cx * m_size.cy * 4;
mt.SetFormat((BYTE*)&vih, sizeof(vih));
m_mts.Add(mt);
}
HRESULT GSSourceOutputPin::DecideBufferSize(IMemAllocator* pAlloc, ALLOCATOR_PROPERTIES* pProperties)
{
ASSERT(pAlloc && pProperties);
HRESULT hr;
pProperties->cBuffers = 1;
pProperties->cbBuffer = m_mt.lSampleSize;
ALLOCATOR_PROPERTIES Actual;
if(FAILED(hr = pAlloc->SetProperties(pProperties, &Actual)))
{
return hr;
}
if(Actual.cbBuffer < pProperties->cbBuffer)
{
return E_FAIL;
}
ASSERT(Actual.cBuffers == pProperties->cBuffers);
return S_OK;
}
HRESULT CheckMediaType(const CMediaType* pmt)
{
for(int i = 0, j = m_mts.GetCount(); i < j; i++)
{
if(m_mts[i].majortype == pmt->majortype && m_mts[i].subtype == pmt->subtype)
{
return S_OK;
}
}
return E_FAIL;
}
HRESULT GetMediaType(int i, CMediaType* pmt)
{
CheckPointer(pmt, E_POINTER);
if(i < 0) return E_INVALIDARG;
if(i > 1) return VFW_S_NO_MORE_ITEMS;
*pmt = m_mts[i];
return S_OK;
}
STDMETHODIMP Notify(IBaseFilter* pSender, Quality q)
{
return E_NOTIMPL;
}
const CMediaType& CurrentMediaType()
{
return m_mt;
}
};
CAutoPtr<GSSourceOutputPin> m_output;
public:
GSSource(int w, int h, int fps, IUnknown* pUnk, HRESULT& hr)
: CBaseFilter(NAME("GSSource"), pUnk, this, __uuidof(this), &hr)
, m_output(NULL)
, m_size(w, h)
, m_atpf(10000000i64 / fps)
, m_now(0)
{
m_output.Attach(new GSSourceOutputPin(m_size, m_atpf, this, this, hr));
// FIXME
if(fps == 60) m_atpf = 166834; // = 10000000i64 / 59.94
}
DECLARE_IUNKNOWN;
int GetPinCount()
{
return 1;
}
CBasePin* GetPin(int n)
{
return n == 0 ? m_output.m_p : NULL;
}
// IGSSource
STDMETHODIMP DeliverNewSegment()
{
m_now = 0;
return m_output->DeliverNewSegment(0, _I64_MAX, 1.0);
}
STDMETHODIMP DeliverFrame(const void* bits, int pitch, bool rgba)
{
if(!m_output || !m_output->IsConnected())
{
return E_UNEXPECTED;
}
CComPtr<IMediaSample> sample;
if(FAILED(m_output->GetDeliveryBuffer(&sample, NULL, NULL, 0)))
{
return E_FAIL;
}
REFERENCE_TIME start = m_now;
REFERENCE_TIME stop = m_now + m_atpf;
sample->SetTime(&start, &stop);
sample->SetSyncPoint(TRUE);
const CMediaType& mt = m_output->CurrentMediaType();
BYTE* src = (BYTE*)bits;
BYTE* dst = NULL;
sample->GetPointer(&dst);
int w = m_size.cx;
int h = m_size.cy;
int srcpitch = pitch;
#if _M_SSE >= 0x200
if(mt.subtype == MEDIASUBTYPE_YUY2)
{
int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 2;
const GSVector4 ys(0.098f, 0.504f, 0.257f, 0.0f);
const GSVector4 us(0.439f / 2, -0.291f / 2, -0.148f / 2, 0.0f);
const GSVector4 vs(-0.071f / 2, -0.368f / 2, 0.439f / 2, 0.0f);
const GSVector4 offset(16, 128, 16, 128);
if(rgba)
{
for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch)
{
DWORD* s = (DWORD*)src;
WORD* d = (WORD*)dst;
for(int i = 0; i < w; i += 2)
{
GSVector4 c0 = GSVector4(s[i + 0]);
GSVector4 c1 = GSVector4(s[i + 1]);
GSVector4 c2 = c0 + c1;
GSVector4 lo = (c0 * ys).hadd(c2 * vs);
GSVector4 hi = (c1 * ys).hadd(c2 * us);
GSVector4 c = lo.hadd(hi) + offset;
*((DWORD*)&d[i]) = GSVector4i(c).rgba32();
}
}
}
else
{
for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch)
{
DWORD* s = (DWORD*)src;
WORD* d = (WORD*)dst;
for(int i = 0; i < w; i += 2)
{
GSVector4 c0 = GSVector4(s[i + 0]).zyxw();
GSVector4 c1 = GSVector4(s[i + 1]).zyxw();
GSVector4 c2 = c0 + c1;
GSVector4 lo = (c0 * ys).hadd(c2 * vs);
GSVector4 hi = (c1 * ys).hadd(c2 * us);
GSVector4 c = lo.hadd(hi) + offset;
*((DWORD*)&d[i]) = GSVector4i(c).rgba32();
}
}
}
}
else
#endif
if(mt.subtype == MEDIASUBTYPE_RGB32)
{
int dstpitch = ((VIDEOINFOHEADER*)mt.Format())->bmiHeader.biWidth * 4;
dst += dstpitch * (h - 1);
dstpitch = -dstpitch;
for(int j = 0; j < h; j++, dst += dstpitch, src += srcpitch)
{
if(rgba)
{
#if _M_SSE >= 0x301
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i mask(2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15);
for(int i = 0, w4 = w >> 2; i < w4; i++)
{
d[i] = s[i].shuffle8(mask);
}
#elif _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
for(int i = 0, w4 = w >> 2; i < w4; i++)
{
d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00);
}
#else
DWORD* s = (DWORD*)src;
DWORD* d = (DWORD*)dst;
for(int i = 0; i < w; i++)
{
d[i] = ((s[i] & 0x00ff0000) >> 16) | ((s[i] & 0x000000ff) << 16) | (s[i] & 0x0000ff00);
}
#endif
}
else
{
memcpy(dst, src, w * 4);
}
}
}
else
{
return E_FAIL;
}
if(FAILED(m_output->Deliver(sample)))
{
return E_FAIL;
}
m_now = stop;
return S_OK;
}
STDMETHODIMP DeliverEOS()
{
return m_output->DeliverEndOfStream();
}
};
//
// GSCapture
//
GSCapture::GSCapture()
: m_capturing(false)
{
}
GSCapture::~GSCapture()
{
EndCapture();
}
#define BeginEnumPins(pBaseFilter, pEnumPins, pPin) \
{CComPtr<IEnumPins> pEnumPins; \
if(pBaseFilter && SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins))) \
{ \
for(CComPtr<IPin> pPin; S_OK == pEnumPins->Next(1, &pPin, 0); pPin = NULL) \
{ \
#define EndEnumPins }}}
static IPin* GetFirstPin(IBaseFilter* pBF, PIN_DIRECTION dir)
{
if(!pBF) return(NULL);
BeginEnumPins(pBF, pEP, pPin)
{
PIN_DIRECTION dir2;
pPin->QueryDirection(&dir2);
if(dir == dir2)
{
IPin* pRet = pPin.Detach();
pRet->Release();
return(pRet);
}
}
EndEnumPins
return(NULL);
}
bool GSCapture::BeginCapture(int fps)
{
CAutoLock cAutoLock(this);
ASSERT(fps != 0);
EndCapture();
AFX_MANAGE_STATE(AfxGetStaticModuleState());
GSCaptureDlg dlg;
if(IDOK != dlg.DoModal()) return false;
m_size.cx = (dlg.m_width + 7) & ~7;
m_size.cy = (dlg.m_height + 7) & ~7;
//
HRESULT hr;
CComPtr<ICaptureGraphBuilder2> cgb;
CComPtr<IBaseFilter> mux;
if(FAILED(hr = m_graph.CoCreateInstance(CLSID_FilterGraph))
|| FAILED(hr = cgb.CoCreateInstance(CLSID_CaptureGraphBuilder2))
|| FAILED(hr = cgb->SetFiltergraph(m_graph))
|| FAILED(hr = cgb->SetOutputFileName(&MEDIASUBTYPE_Avi, CStringW(dlg.m_filename), &mux, NULL)))
{
return false;
}
m_src = new GSSource(m_size.cx, m_size.cy, fps, NULL, hr);
if(FAILED(hr = m_graph->AddFilter(m_src, L"Source"))
|| FAILED(hr = m_graph->AddFilter(dlg.m_enc, L"Encoder")))
{
return false;
}
if(FAILED(hr = m_graph->ConnectDirect(GetFirstPin(m_src, PINDIR_OUTPUT), GetFirstPin(dlg.m_enc, PINDIR_INPUT), NULL))
|| FAILED(hr = m_graph->ConnectDirect(GetFirstPin(dlg.m_enc, PINDIR_OUTPUT), GetFirstPin(mux, PINDIR_INPUT), NULL)))
{
return false;
}
BeginEnumFilters(m_graph, pEF, pBF)
{
CFilterInfo fi;
pBF->QueryFilterInfo(&fi);
printf("Filter [%p]: %s\n", pBF.p, CStringA(fi.achName));
BeginEnumPins(pBF, pEP, pPin)
{
CComPtr<IPin> pPinTo;
pPin->ConnectedTo(&pPinTo);
CPinInfo pi;
pPin->QueryPinInfo(&pi);
printf("- Pin [%p - %p]: %s (%s)\n", pPin.p, pPinTo.p, CStringA(pi.achName), pi.dir ? "out" : "in");
BeginEnumMediaTypes(pPin, pEMT, pmt)
{
}
EndEnumMediaTypes(pmt)
}
EndEnumPins
}
EndEnumFilters
hr = CComQIPtr<IMediaControl>(m_graph)->Run();
CComQIPtr<IGSSource>(m_src)->DeliverNewSegment();
m_capturing = true;
return true;
}
bool GSCapture::DeliverFrame(const void* bits, int pitch, bool rgba)
{
CAutoLock cAutoLock(this);
if(bits == NULL || pitch == 0)
{
ASSERT(0);
return false;
}
if(m_src)
{
CComQIPtr<IGSSource>(m_src)->DeliverFrame(bits, pitch, rgba);
return true;
}
return false;
}
bool GSCapture::EndCapture()
{
CAutoLock cAutoLock(this);
if(m_src)
{
CComQIPtr<IGSSource>(m_src)->DeliverEOS();
m_src = NULL;
}
if(m_graph)
{
CComQIPtr<IMediaControl>(m_graph)->Stop();
m_graph = NULL;
}
m_capturing = false;
return true;
}

43
plugins/GSdx/GSCapture.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSCaptureDlg.h"
class GSCapture : protected CCritSec
{
bool m_capturing;
CSize m_size;
CComPtr<IGraphBuilder> m_graph;
CComPtr<IBaseFilter> m_src;
public:
GSCapture();
virtual ~GSCapture();
bool BeginCapture(int fps);
bool DeliverFrame(const void* bits, int pitch, bool rgba);
bool EndCapture();
bool IsCapturing() {return m_capturing;}
CSize GetSize() {return m_size;}
};

View File

@ -0,0 +1,243 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include <afxpriv.h>
#include "GSCaptureDlg.h"
// GSCaptureDlg dialog
IMPLEMENT_DYNAMIC(GSCaptureDlg, CDialog)
GSCaptureDlg::GSCaptureDlg(CWnd* pParent /*=NULL*/)
: CDialog(GSCaptureDlg::IDD, pParent)
{
m_width = AfxGetApp()->GetProfileInt(_T("Capture"), _T("Width"), 640);
m_height = AfxGetApp()->GetProfileInt(_T("Capture"), _T("Height"), 480);
m_filename = AfxGetApp()->GetProfileString(_T("Capture"), _T("FileName"));
}
GSCaptureDlg::~GSCaptureDlg()
{
}
int GSCaptureDlg::GetSelCodec(Codec& c)
{
int iSel = m_codeclist.GetCurSel();
if(iSel < 0) return 0;
POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(iSel);
if(pos == NULL) return 2;
c = m_codecs.GetAt(pos);
if(!c.filter)
{
c.moniker->BindToObject(NULL, NULL, __uuidof(IBaseFilter), (void**)&c.filter);
if(!c.filter) return 0;
}
return 1;
}
LRESULT GSCaptureDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
if(message == WM_INITDIALOG) SendMessage(WM_KICKIDLE);
return(ret);
}
void GSCaptureDlg::DoDataExchange(CDataExchange* pDX)
{
__super::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_filename);
DDX_Control(pDX, IDC_COMBO1, m_codeclist);
DDX_Text(pDX, IDC_EDIT2, m_width);
DDX_Text(pDX, IDC_EDIT4, m_height);
}
BOOL GSCaptureDlg::OnInitDialog()
{
__super::OnInitDialog();
m_codecs.RemoveAll();
m_codeclist.ResetContent();
m_codeclist.SetItemDataPtr(m_codeclist.AddString(_T("Uncompressed")), NULL);
BeginEnumSysDev(CLSID_VideoCompressorCategory, moniker)
{
Codec c;
c.moniker = moniker;
LPOLESTR strName = NULL;
if(FAILED(moniker->GetDisplayName(NULL, NULL, &strName)))
continue;
c.DisplayName = strName;
CoTaskMemFree(strName);
CComPtr<IPropertyBag> pPB;
moniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pPB);
CComVariant var;
if(FAILED(pPB->Read(CComBSTR(_T("FriendlyName")), &var, NULL)))
continue;
c.FriendlyName = var.bstrVal;
CStringW str = CStringW(c.DisplayName).MakeLower();
CString prefix;
if(str.Find(L"@device:dmo:") == 0) prefix = _T("(DMO) ");
else if(str.Find(L"@device:sw:") == 0) prefix = _T("(DS) ");
else if(str.Find(L"@device:cm:") == 0) prefix = _T("(VfW) ");
c.FriendlyName = prefix + c.FriendlyName;
m_codeclist.SetItemDataPtr(m_codeclist.AddString(c.FriendlyName), m_codecs.AddTail(c));
}
EndEnumSysDev
//
CString DisplayNameToFind = AfxGetApp()->GetProfileString(_T("Capture"), _T("VideoCodecDisplayName"));
for(int i = 0; i < m_codeclist.GetCount(); i++)
{
CString DisplayName;
POSITION pos = (POSITION)m_codeclist.GetItemDataPtr(i);
if(pos) DisplayName = m_codecs.GetAt(pos).DisplayName;
if(DisplayName == DisplayNameToFind)
{
m_codeclist.SetCurSel(i);
break;
}
}
//
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
BEGIN_MESSAGE_MAP(GSCaptureDlg, CDialog)
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, OnBnClickedButton2)
ON_UPDATE_COMMAND_UI(IDC_BUTTON2, OnUpdateButton2)
ON_BN_CLICKED(IDOK, OnBnClickedOk)
ON_UPDATE_COMMAND_UI(IDOK, OnUpdateOK)
END_MESSAGE_MAP()
// GSCaptureDlg message handlers
void GSCaptureDlg::OnKickIdle()
{
UpdateDialogControls(this, false);
}
void GSCaptureDlg::OnBnClickedButton1()
{
UpdateData();
DWORD flags = OFN_EXPLORER|OFN_ENABLESIZING|OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST;
CFileDialog fd(FALSE, _T("avi"), m_filename, flags, _T("Avi files (*.avi)|*.avi||"), this, 0);
if(fd.DoModal() == IDOK)
{
m_filename = fd.GetPathName();
UpdateData(FALSE);
}
}
void GSCaptureDlg::OnBnClickedButton2()
{
Codec c;
if(GetSelCodec(c) != 1) return;
if(CComQIPtr<ISpecifyPropertyPages> pSPP = c.filter)
{
CAUUID caGUID;
memset(&caGUID, 0, sizeof(caGUID));
if(SUCCEEDED(pSPP->GetPages(&caGUID)))
{
IUnknown* lpUnk = NULL;
pSPP.QueryInterface(&lpUnk);
OleCreatePropertyFrame(m_hWnd, 0, 0, CStringW(c.FriendlyName), 1, (IUnknown**)&lpUnk, caGUID.cElems, caGUID.pElems, 0, 0, NULL);
lpUnk->Release();
if(caGUID.pElems) CoTaskMemFree(caGUID.pElems);
}
}
else if(CComQIPtr<IAMVfwCompressDialogs> pAMVfWCD = c.filter)
{
if(pAMVfWCD->ShowDialog(VfwCompressDialog_QueryConfig, NULL) == S_OK)
{
pAMVfWCD->ShowDialog(VfwCompressDialog_Config, m_hWnd);
}
}
}
void GSCaptureDlg::OnUpdateButton2(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_codeclist.GetCurSel() >= 0 && m_codeclist.GetItemDataPtr(m_codeclist.GetCurSel()) != NULL);
}
void GSCaptureDlg::OnBnClickedOk()
{
UpdateData();
Codec c;
if(GetSelCodec(c) == 0) return;
m_enc = c.filter;
AfxGetApp()->WriteProfileInt(_T("Capture"), _T("Width"), m_width);
AfxGetApp()->WriteProfileInt(_T("Capture"), _T("Height"), m_height);
AfxGetApp()->WriteProfileString(_T("Capture"), _T("FileName"), m_filename);
AfxGetApp()->WriteProfileString(_T("Capture"), _T("VideoCodecDisplayName"), CString(c.DisplayName));
OnOK();
}
void GSCaptureDlg::OnUpdateOK(CCmdUI* pCmdUI)
{
CString str;
GetDlgItem(IDC_EDIT1)->GetWindowText(str);
pCmdUI->Enable(!str.IsEmpty() && m_codeclist.GetCurSel() >= 0);
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "resource.h"
#include "baseclasses/streams.h"
// GSCaptureDlg dialog
class GSCaptureDlg : public CDialog
{
DECLARE_DYNAMIC(GSCaptureDlg)
private:
struct Codec
{
CComPtr<IMoniker> moniker;
CComPtr<IBaseFilter> filter;
CString FriendlyName;
CComBSTR DisplayName;
};
CAtlList<Codec> m_codecs;
int GetSelCodec(Codec& c);
public:
GSCaptureDlg(CWnd* pParent = NULL); // standard constructor
virtual ~GSCaptureDlg();
CComPtr<IBaseFilter> m_enc;
// Dialog Data
enum { IDD = IDD_CAPTURE };
CString m_filename;
CComboBox m_codeclist;
protected:
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual BOOL OnInitDialog();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKickIdle();
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
afx_msg void OnUpdateButton2(CCmdUI* pCmdUI);
afx_msg void OnBnClickedOk();
afx_msg void OnUpdateOK(CCmdUI* pCmdUI);
int m_width;
int m_height;
};

869
plugins/GSdx/GSClut.cpp Normal file
View File

@ -0,0 +1,869 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSClut.h"
#include "GSLocalMemory.h"
GSClut::GSClut(const GSLocalMemory* mem)
: m_mem(mem)
{
BYTE* p = (BYTE*)VirtualAlloc(NULL, 2 * 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
m_clut = (WORD*)&p[0]; // 1k + 1k for buffer overruns (sfex: PSM == PSM_PSMT8, CPSM == PSM_PSMCT32, CSA != 0)
m_buff32 = (DWORD*)&p[2048]; // 1k
m_buff64 = (UINT64*)&p[4096]; // 2k
m_write.dirty = true;
m_read.dirty = true;
for(int i = 0; i < 16; i++)
{
for(int j = 0; j < 64; j++)
{
m_wc[0][i][j] = &GSClut::WriteCLUT_NULL;
m_wc[1][i][j] = &GSClut::WriteCLUT_NULL;
}
}
m_wc[0][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1;
m_wc[0][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1;
m_wc[0][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_I8_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_I8_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_I4_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_I8_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_I8_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_I4_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_I4_CSM1;
m_wc[0][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_I4_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_I8_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_I8_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_I4_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_I4_CSM1;
m_wc[0][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_I4_CSM1;
m_wc[1][PSM_PSMCT32][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>;
m_wc[1][PSM_PSMCT32][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>;
m_wc[1][PSM_PSMCT32][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT32][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT32][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT24][PSM_PSMT8] = &GSClut::WriteCLUT32_CSM2<256>;
m_wc[1][PSM_PSMCT24][PSM_PSMT8H] = &GSClut::WriteCLUT32_CSM2<256>;
m_wc[1][PSM_PSMCT24][PSM_PSMT4] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT24][PSM_PSMT4HL] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT24][PSM_PSMT4HH] = &GSClut::WriteCLUT32_CSM2<16>;
m_wc[1][PSM_PSMCT16][PSM_PSMT8] = &GSClut::WriteCLUT16_CSM2<256>;
m_wc[1][PSM_PSMCT16][PSM_PSMT8H] = &GSClut::WriteCLUT16_CSM2<256>;
m_wc[1][PSM_PSMCT16][PSM_PSMT4] = &GSClut::WriteCLUT16_CSM2<16>;
m_wc[1][PSM_PSMCT16][PSM_PSMT4HL] = &GSClut::WriteCLUT16_CSM2<16>;
m_wc[1][PSM_PSMCT16][PSM_PSMT4HH] = &GSClut::WriteCLUT16_CSM2<16>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT8] = &GSClut::WriteCLUT16S_CSM2<256>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT8H] = &GSClut::WriteCLUT16S_CSM2<256>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT4] = &GSClut::WriteCLUT16S_CSM2<16>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT4HL] = &GSClut::WriteCLUT16S_CSM2<16>;
m_wc[1][PSM_PSMCT16S][PSM_PSMT4HH] = &GSClut::WriteCLUT16S_CSM2<16>;
}
GSClut::~GSClut()
{
VirtualFree(m_clut, 0, MEM_RELEASE);
}
void GSClut::Invalidate()
{
m_write.dirty = true;
}
bool GSClut::WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
switch(TEX0.CLD)
{
case 0: return false;
case 1: break;
case 2: m_CBP[0] = TEX0.CBP; break;
case 3: m_CBP[1] = TEX0.CBP; break;
case 4: if(m_CBP[0] == TEX0.CBP) return false; m_CBP[0] = TEX0.CBP; break;
case 5: if(m_CBP[1] == TEX0.CBP) return false; m_CBP[1] = TEX0.CBP; break;
case 6: ASSERT(0); return false;
case 7: ASSERT(0); return false;
default: __assume(0);
}
return m_write.IsDirty(TEX0, TEXCLUT);
}
void GSClut::Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
m_write.TEX0 = TEX0;
m_write.TEXCLUT = TEXCLUT;
m_write.dirty = false;
m_read.dirty = true;
(this->*m_wc[TEX0.CSM][TEX0.CPSM][TEX0.PSM])(TEX0, TEXCLUT);
}
void GSClut::WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
ASSERT(TEX0.CSA == 0);
WriteCLUT_T32_I8_CSM1(&m_mem->m_vm32[m_mem->BlockAddress32(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
}
void GSClut::WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
ASSERT(TEX0.CSA < 16);
GSVector4i dummy; // this just forces stack alignment and enables inlining the next call
WriteCLUT_T32_I4_CSM1(&m_mem->m_vm32[m_mem->BlockAddress32(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
}
void GSClut::WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
ASSERT(TEX0.CSA < 16);
WriteCLUT_T16_I8_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
}
void GSClut::WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
ASSERT(TEX0.CSA < 32);
WriteCLUT_T16_I4_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
}
void GSClut::WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WriteCLUT_T16_I8_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16S(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
}
void GSClut::WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WriteCLUT_T16_I4_CSM1(&m_mem->m_vm16[m_mem->BlockAddress16S(0, 0, TEX0.CBP, 1)], m_clut + (TEX0.CSA << 4));
}
template<int n> void GSClut::WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4);
DWORD base = m_mem->PixelAddress32(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW);
int* offset = &m_mem->rowOffset32[TEXCLUT.COU << 4];
for(int i = 0; i < n; i++)
{
DWORD c = m_mem->ReadPixel32(base + offset[i]);
clut[i] = (WORD)(c & 0xffff);
clut[i + 256] = (WORD)(c >> 16);
}
}
template<int n> void GSClut::WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4);
DWORD base = m_mem->PixelAddress16(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW);
int* offset = &m_mem->rowOffset16[TEXCLUT.COU << 4];
for(int i = 0; i < n; i++)
{
clut[i] = (WORD)m_mem->ReadPixel16(base + offset[i]);
}
}
template<int n> void GSClut::WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
WORD* RESTRICT clut = m_clut + (TEX0.CSA << 4);
DWORD base = m_mem->PixelAddress16S(0, TEXCLUT.COV, TEX0.CBP, TEXCLUT.CBW);
int* offset = &m_mem->rowOffset16S[TEXCLUT.COU << 4];
for(int i = 0; i < n; i++)
{
clut[i] = (WORD)m_mem->ReadPixel16(base + offset[i]);
}
}
void GSClut::Read(const GIFRegTEX0& TEX0)
{
if(m_read.IsDirty(TEX0))
{
m_read.TEX0 = TEX0;
m_read.dirty = false;
WORD* clut = m_clut + (TEX0.CSA << 4);
if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24)
{
switch(TEX0.PSM)
{
case PSM_PSMT8:
case PSM_PSMT8H:
ReadCLUT_T32_I8(clut, m_buff32);
break;
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
ReadCLUT_T32_I4(clut, m_buff32, m_buff64);
break;
}
}
else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S)
{
switch(TEX0.PSM)
{
case PSM_PSMT8:
case PSM_PSMT8H:
ReadCLUT_T16_I8(clut, m_buff32);
break;
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
ReadCLUT_T16_I4(clut, m_buff32, m_buff64);
break;
}
}
}
}
void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
{
if(m_read.IsDirty(TEX0, TEXA))
{
m_read.TEX0 = TEX0;
m_read.TEXA = TEXA;
m_read.dirty = false;
m_read.adirty = true;
WORD* clut = m_clut + (TEX0.CSA << 4);
if(TEX0.CPSM == PSM_PSMCT32 || TEX0.CPSM == PSM_PSMCT24)
{
switch(TEX0.PSM)
{
case PSM_PSMT8:
case PSM_PSMT8H:
ReadCLUT_T32_I8(clut, m_buff32);
break;
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
// TODO: merge these functions
ReadCLUT_T32_I4(clut, m_buff32);
ExpandCLUT64_T32_I8(m_buff32, (UINT64*)m_buff64); // sw renderer does not need m_buff64 anymore
break;
}
}
else if(TEX0.CPSM == PSM_PSMCT16 || TEX0.CPSM == PSM_PSMCT16S)
{
switch(TEX0.PSM)
{
case PSM_PSMT8:
case PSM_PSMT8H:
Expand16(clut, m_buff32, 256, TEXA);
break;
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
// TODO: merge these functions
Expand16(clut, m_buff32, 16, TEXA);
ExpandCLUT64_T32_I8(m_buff32, (UINT64*)m_buff64); // sw renderer does not need m_buff64 anymore
break;
}
}
}
}
void GSClut::GetAlphaMinMax32(int& amin, int& amax)
{
// call only after Read32
ASSERT(!m_read.dirty);
if(m_read.adirty)
{
m_read.adirty = false;
// DWORD bpp = GSLocalMemory::m_psm[m_read.TEX0.PSM].trbpp;
DWORD cbpp = GSLocalMemory::m_psm[m_read.TEX0.CPSM].trbpp;
DWORD pal = GSLocalMemory::m_psm[m_read.TEX0.PSM].pal;
if(cbpp == 24 && m_read.TEXA.AEM == 0)
{
m_read.amin = m_read.TEXA.TA0;
m_read.amax = m_read.TEXA.TA0;
}
else
{
int amin = 255;
int amax = 0;
const GSVector4i* p = (const GSVector4i*)m_buff32;
for(int i = 0, j = pal >> 4; i < j; i++)
{
GSVector4i v0 = (p[i * 4 + 0] >> 24).ps32(p[i * 4 + 1] >> 24);
GSVector4i v1 = (p[i * 4 + 2] >> 24).ps32(p[i * 4 + 3] >> 24);
GSVector4i v2 = v0.min_i16(v1);
GSVector4i v3 = v0.max_i16(v1);
v2 = v2.min_i16(v2.zwxy());
v3 = v3.max_i16(v3.zwxy());
v2 = v2.min_i16(v2.zwxyl());
v3 = v3.max_i16(v3.zwxyl());
v2 = v2.min_i16(v2.yxwzl());
v3 = v3.max_i16(v3.yxwzl());
amin = min(amin, v2.extract16<0>());
amax = max(amax, v3.extract16<0>());
}
m_read.amin = amin;
m_read.amax = amax;
}
}
amin = m_read.amin;
amax = m_read.amax;
}
//
void GSClut::WriteCLUT_T32_I8_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut)
{
#if _M_SSE >= 0x200
for(int i = 0; i < 64; i += 16)
{
WriteCLUT_T32_I4_CSM1(&src[i + 0], &clut[i * 2 + 0]);
WriteCLUT_T32_I4_CSM1(&src[i + 64], &clut[i * 2 + 16]);
WriteCLUT_T32_I4_CSM1(&src[i + 128], &clut[i * 2 + 128]);
WriteCLUT_T32_I4_CSM1(&src[i + 192], &clut[i * 2 + 144]);
}
#else
for(int j = 0; j < 2; j++, src += 128, clut += 128)
{
for(int i = 0; i < 128; i++)
{
DWORD c = src[clutTableT32I8[i]];
clut[i] = (WORD)(c & 0xffff);
clut[i + 256] = (WORD)(c >> 16);
}
}
#endif
}
__forceinline void GSClut::WriteCLUT_T32_I4_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut)
{
#if _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)clut;
GSVector4i v0 = s[0];
GSVector4i v1 = s[1];
GSVector4i v2 = s[2];
GSVector4i v3 = s[3];
GSVector4i::sw64(v0, v1, v2, v3);
GSVector4i::sw16(v0, v1, v2, v3);
GSVector4i::sw16(v0, v2, v1, v3);
GSVector4i::sw16(v0, v1, v2, v3);
d[0] = v0;
d[1] = v1;
d[32] = v2;
d[33] = v3;
#else
for(int i = 0; i < 16; i++)
{
DWORD c = src[clutTableT32I4[i]];
clut[i] = (WORD)(c & 0xffff);
clut[i + 256] = (WORD)(c >> 16);
}
#endif
}
void GSClut::WriteCLUT_T16_I8_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut)
{
#if _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)clut;
for(int i = 0; i < 32; i += 4)
{
GSVector4i v0 = s[i + 0];
GSVector4i v1 = s[i + 1];
GSVector4i v2 = s[i + 2];
GSVector4i v3 = s[i + 3];
GSVector4i::sw16(v0, v1, v2, v3);
GSVector4i::sw32(v0, v1, v2, v3);
GSVector4i::sw16(v0, v2, v1, v3);
d[i + 0] = v0;
d[i + 1] = v2;
d[i + 2] = v1;
d[i + 3] = v3;
}
#else
for(int j = 0; j < 8; j++, src += 32, clut += 32)
{
for(int i = 0; i < 32; i++)
{
clut[i] = src[clutTableT16I8[i]];
}
}
#endif
}
__forceinline void GSClut::WriteCLUT_T16_I4_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut)
{
for(int i = 0; i < 16; i++)
{
clut[i] = src[clutTableT16I4[i]];
}
}
void GSClut::ReadCLUT_T32_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst)
{
#if _M_SSE >= 0x200
for(int i = 0; i < 256; i += 16)
{
ReadCLUT_T32_I4(&clut[i], &dst[i]);
}
#else
for(int i = 0; i < 256; i++)
{
dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i];
}
#endif
}
__forceinline void GSClut::ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst)
{
#if _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)clut;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i v0 = s[0];
GSVector4i v1 = s[1];
GSVector4i v2 = s[32];
GSVector4i v3 = s[33];
GSVector4i::sw16(v0, v2, v1, v3);
d[0] = v0;
d[1] = v1;
d[2] = v2;
d[3] = v3;
#else
for(int i = 0; i < 16; i++)
{
dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i];
}
#endif
}
__forceinline void GSClut::ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64)
{
#if _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)clut;
GSVector4i* d32 = (GSVector4i*)dst32;
GSVector4i* d64 = (GSVector4i*)dst64;
GSVector4i s0 = s[0];
GSVector4i s1 = s[1];
GSVector4i s2 = s[32];
GSVector4i s3 = s[33];
GSVector4i::sw16(s0, s2, s1, s3);
d32[0] = s0;
d32[1] = s1;
d32[2] = s2;
d32[3] = s3;
ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d64[0]);
ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d64[32]);
ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d64[64]);
ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d64[96]);
#else
for(int i = 0; i < 16; i++)
{
dst[i] = ((DWORD)clut[i + 256] << 16) | clut[i];
}
DWORD* d = (DWORD*)dst64;
for(int j = 0; j < 16; j++, d += 32)
{
DWORD hi = dst32[j];
for(int i = 0; i < 16; i++)
{
d[i * 2 + 0] = dst32[i];
d[i * 2 + 1] = hi;
}
}
#endif
}
void GSClut::ReadCLUT_T16_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst)
{
#if _M_SSE >= 0x200
for(int i = 0; i < 256; i += 16)
{
ReadCLUT_T16_I4(&clut[i], &dst[i]);
}
#else
for(int i = 0; i < 256; i++)
{
dst[i] = (DWORD)clut[i];
}
#endif
}
__forceinline void GSClut::ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst)
{
#if _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)clut;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i v0 = s[0];
GSVector4i v1 = s[1];
d[0] = v0.upl16();
d[1] = v0.uph16();
d[2] = v1.upl16();
d[3] = v1.uph16();
#else
for(int i = 0; i < 16; i++)
{
dst[i] = (DWORD)clut[i];
}
#endif
}
__forceinline void GSClut::ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64)
{
#if _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)clut;
GSVector4i* d32 = (GSVector4i*)dst32;
GSVector4i* d64 = (GSVector4i*)dst64;
GSVector4i v0 = s[0];
GSVector4i v1 = s[1];
GSVector4i s0 = v0.upl16();
GSVector4i s1 = v0.uph16();
GSVector4i s2 = v1.upl16();
GSVector4i s3 = v1.uph16();
d32[0] = s0;
d32[1] = s1;
d32[2] = s2;
d32[3] = s3;
ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d64[0]);
ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d64[32]);
ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d64[64]);
ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d64[96]);
#else
for(int i = 0; i < 16; i++)
{
dst32[i] = (DWORD)clut[i];
}
DWORD* d = (DWORD*)dst64;
for(int j = 0; j < 16; j++, d += 32)
{
DWORD hi = dst32[j] << 16;
for(int i = 0; i < 16; i++)
{
d[i * 2 + 0] = hi | (dst32[i] & 0xffff);
}
}
#endif
}
void GSClut::ExpandCLUT64_T32_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst)
{
#if _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i s0 = s[0];
GSVector4i s1 = s[1];
GSVector4i s2 = s[2];
GSVector4i s3 = s[3];
ExpandCLUT64_T32(s0, s0, s1, s2, s3, &d[0]);
ExpandCLUT64_T32(s1, s0, s1, s2, s3, &d[32]);
ExpandCLUT64_T32(s2, s0, s1, s2, s3, &d[64]);
ExpandCLUT64_T32(s3, s0, s1, s2, s3, &d[96]);
#else
DWORD* d = (DWORD*)dst;
for(int j = 0; j < 16; j++, d += 32)
{
DWORD hi = src[j];
for(int i = 0; i < 16; i++)
{
d[i * 2 + 0] = src[i];
d[i * 2 + 1] = hi;
}
}
#endif
}
__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst)
{
ExpandCLUT64_T32(hi.xxxx(), lo0, &dst[0]);
ExpandCLUT64_T32(hi.xxxx(), lo1, &dst[2]);
ExpandCLUT64_T32(hi.xxxx(), lo2, &dst[4]);
ExpandCLUT64_T32(hi.xxxx(), lo3, &dst[6]);
ExpandCLUT64_T32(hi.yyyy(), lo0, &dst[8]);
ExpandCLUT64_T32(hi.yyyy(), lo1, &dst[10]);
ExpandCLUT64_T32(hi.yyyy(), lo2, &dst[12]);
ExpandCLUT64_T32(hi.yyyy(), lo3, &dst[14]);
ExpandCLUT64_T32(hi.zzzz(), lo0, &dst[16]);
ExpandCLUT64_T32(hi.zzzz(), lo1, &dst[18]);
ExpandCLUT64_T32(hi.zzzz(), lo2, &dst[20]);
ExpandCLUT64_T32(hi.zzzz(), lo3, &dst[22]);
ExpandCLUT64_T32(hi.wwww(), lo0, &dst[24]);
ExpandCLUT64_T32(hi.wwww(), lo1, &dst[26]);
ExpandCLUT64_T32(hi.wwww(), lo2, &dst[28]);
ExpandCLUT64_T32(hi.wwww(), lo3, &dst[30]);
}
__forceinline void GSClut::ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst)
{
dst[0] = lo.upl32(hi);
dst[1] = lo.uph32(hi);
}
void GSClut::ExpandCLUT64_T16_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst)
{
#if _M_SSE >= 0x200
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
GSVector4i s0 = s[0];
GSVector4i s1 = s[1];
GSVector4i s2 = s[2];
GSVector4i s3 = s[3];
ExpandCLUT64_T16(s0, s0, s1, s2, s3, &d[0]);
ExpandCLUT64_T16(s1, s0, s1, s2, s3, &d[32]);
ExpandCLUT64_T16(s2, s0, s1, s2, s3, &d[64]);
ExpandCLUT64_T16(s3, s0, s1, s2, s3, &d[96]);
#else
DWORD* d = (DWORD*)dst;
for(int j = 0; j < 16; j++, d += 32)
{
DWORD hi = src[j] << 16;
for(int i = 0; i < 16; i++)
{
d[i * 2 + 0] = hi | (src[i] & 0xffff);
}
}
#endif
}
__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst)
{
ExpandCLUT64_T16(hi.xxxx(), lo0, &dst[0]);
ExpandCLUT64_T16(hi.xxxx(), lo1, &dst[2]);
ExpandCLUT64_T16(hi.xxxx(), lo2, &dst[4]);
ExpandCLUT64_T16(hi.xxxx(), lo3, &dst[6]);
ExpandCLUT64_T16(hi.yyyy(), lo0, &dst[8]);
ExpandCLUT64_T16(hi.yyyy(), lo1, &dst[10]);
ExpandCLUT64_T16(hi.yyyy(), lo2, &dst[12]);
ExpandCLUT64_T16(hi.yyyy(), lo3, &dst[14]);
ExpandCLUT64_T16(hi.zzzz(), lo0, &dst[16]);
ExpandCLUT64_T16(hi.zzzz(), lo1, &dst[18]);
ExpandCLUT64_T16(hi.zzzz(), lo2, &dst[20]);
ExpandCLUT64_T16(hi.zzzz(), lo3, &dst[22]);
ExpandCLUT64_T16(hi.wwww(), lo0, &dst[24]);
ExpandCLUT64_T16(hi.wwww(), lo1, &dst[26]);
ExpandCLUT64_T16(hi.wwww(), lo2, &dst[28]);
ExpandCLUT64_T16(hi.wwww(), lo3, &dst[30]);
}
__forceinline void GSClut::ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst)
{
dst[0] = lo.upl16(hi);
dst[1] = lo.uph16(hi);
}
// TODO
static const GSVector4i s_am(0x00008000);
static const GSVector4i s_bm(0x00007c00);
static const GSVector4i s_gm(0x000003e0);
static const GSVector4i s_rm(0x0000001f);
void GSClut::Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int w, const GIFRegTEXA& TEXA)
{
#if _M_SSE >= 0x200
ASSERT((w & 7) == 0);
const GSVector4i rm = s_rm;
const GSVector4i gm = s_gm;
const GSVector4i bm = s_bm;
// const GSVector4i am = s_am;
GSVector4i TA0(TEXA.TA0 << 24);
GSVector4i TA1(TEXA.TA1 << 24);
GSVector4i c, cl, ch;
const GSVector4i* s = (const GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
if(!TEXA.AEM)
{
for(int i = 0, j = w >> 3; i < j; i++)
{
c = s[i];
/*
cl = c.upl16();
ch = c.uph16();
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA1.blend(TA0, cl < am);
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA1.blend(TA0, ch < am);
*/
cl = c.upl16(c);
ch = c.uph16(c);
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15));
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15));
}
}
else
{
for(int i = 0, j = w >> 3; i < j; i++)
{
c = s[i];
/*
cl = c.upl16();
ch = c.uph16();
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA1.blend(TA0, cl < am).andnot(cl == GSVector4i::zero());
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA1.blend(TA0, ch < am).andnot(ch == GSVector4i::zero());
*/
cl = c.upl16(c);
ch = c.uph16(c);
d[i * 2 + 0] = ((cl & rm) << 3) | ((cl & gm) << 6) | ((cl & bm) << 9) | TA0.blend8(TA1, cl.sra16(15)).andnot(cl == GSVector4i::zero());
d[i * 2 + 1] = ((ch & rm) << 3) | ((ch & gm) << 6) | ((ch & bm) << 9) | TA0.blend8(TA1, ch.sra16(15)).andnot(ch == GSVector4i::zero());
}
}
#else
DWORD TA0 = (DWORD)TEXA.TA0 << 24;
DWORD TA1 = (DWORD)TEXA.TA1 << 24;
if(!TEXA.AEM)
{
for(int i = 0; i < w; i++)
{
dst[i] = ((src[i] & 0x8000) ? TA1 : TA0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3);
}
}
else
{
for(int i = 0; i < w; i++)
{
dst[i] = ((src[i] & 0x8000) ? TA1 : src[i] ? TA0 : 0) | ((src[i] & 0x7c00) << 9) | ((src[i] & 0x03e0) << 6) | ((src[i] & 0x001f) << 3);
}
}
#endif
}
//
bool GSClut::WriteState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT)
{
return dirty || !(GSVector4i::load<true>(this) == GSVector4i::load(&TEX0, &TEXCLUT)).alltrue();
}
bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0)
{
return dirty || !(GSVector4i::load<true>(this) == GSVector4i::load(&TEX0, &this->TEXA)).alltrue();
}
bool GSClut::ReadState::IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
{
return dirty || !(GSVector4i::load<true>(this) == GSVector4i::load(&TEX0, &TEXA)).alltrue();
}

110
plugins/GSdx/GSClut.h Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSVector.h"
#include "GSTables.h"
#include "GSAlignedClass.h"
class GSLocalMemory;
__declspec(align(16)) class GSClut : public GSAlignedClass<16>
{
const GSLocalMemory* m_mem;
DWORD m_CBP[2];
WORD* m_clut;
DWORD* m_buff32;
UINT64* m_buff64;
__declspec(align(16)) struct WriteState
{
GIFRegTEX0 TEX0;
GIFRegTEXCLUT TEXCLUT;
bool dirty;
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
} m_write;
__declspec(align(16)) struct ReadState
{
GIFRegTEX0 TEX0;
GIFRegTEXA TEXA;
bool dirty;
bool adirty;
int amin, amax;
bool IsDirty(const GIFRegTEX0& TEX0);
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
} m_read;
typedef void (GSClut::*writeCLUT)(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
writeCLUT m_wc[2][16][64];
void WriteCLUT32_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT32_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT16_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT16_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT16S_I8_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT16S_I4_CSM1(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
template<int n> void WriteCLUT32_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
template<int n> void WriteCLUT16_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
template<int n> void WriteCLUT16S_CSM2(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void WriteCLUT_NULL(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT) {}
static void WriteCLUT_T32_I8_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut);
static void WriteCLUT_T32_I4_CSM1(const DWORD* RESTRICT src, WORD* RESTRICT clut);
static void WriteCLUT_T16_I8_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut);
static void WriteCLUT_T16_I4_CSM1(const WORD* RESTRICT src, WORD* RESTRICT clut);
static void ReadCLUT_T32_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst);
static void ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst);
static void ReadCLUT_T32_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64);
static void ReadCLUT_T16_I8(const WORD* RESTRICT clut, DWORD* RESTRICT dst);
static void ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst);
static void ReadCLUT_T16_I4(const WORD* RESTRICT clut, DWORD* RESTRICT dst32, UINT64* RESTRICT dst64);
static void ExpandCLUT64_T32_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst);
static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst);
static void ExpandCLUT64_T32(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst);
static void ExpandCLUT64_T16_I8(const DWORD* RESTRICT src, UINT64* RESTRICT dst);
static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo0, const GSVector4i& lo1, const GSVector4i& lo2, const GSVector4i& lo3, GSVector4i* dst);
static void ExpandCLUT64_T16(const GSVector4i& hi, const GSVector4i& lo, GSVector4i* dst);
static void Expand16(const WORD* RESTRICT src, DWORD* RESTRICT dst, int w, const GIFRegTEXA& TEXA);
public:
GSClut(const GSLocalMemory* mem);
virtual ~GSClut();
void Invalidate();
bool WriteTest(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void Write(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
void Read(const GIFRegTEX0& TEX0);
void Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
void GetAlphaMinMax32(int& amin, int& amax);
DWORD operator [] (size_t i) const {return m_buff32[i];}
operator const DWORD*() const {return m_buff32;}
operator const UINT64*() const {return m_buff64;}
};

143
plugins/GSdx/GSCrc.cpp Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSCrc.h"
CRC::Game CRC::m_games[] =
{
{0x00000000, None, Unknown, false},
{0x2113EA2E, MetalSlug6, Unknown, false},
{0x42E05BAF, TomoyoAfter, JP, false},
{0x7800DC84, Clannad, JP, false},
{0xa39517ab, FFX, EU, true},
{0xa39517ae, FFX, FR, true},
{0x941bb7d9, FFX, DE, true},
{0xa39517a9, FFX, IT, true},
{0x941bb7de, FFX, ES, true},
{0xb4414ea1, FFX, RU, true},
{0xee97db5b, FFX, RU, true},
{0xaec495cc, FFX, RU, true},
{0xbb3d833a, FFX, US, true},
{0x6a4efe60, FFX, JP, true},
{0x3866ca7e, FFX, ASIA, true}, // int.
{0x658597e2, FFX, JP, true}, // int.
{0x9aac5309, FFX2, EU, true},
{0x9aac530c, FFX2, FR, true},
{0x9aac530a, FFX2, FR, true}, // ?
{0x9aac530d, FFX2, DE, true},
{0x9aac530b, FFX2, IT, true},
{0x48fe0c71, FFX2, US, true},
{0xe1fd9a2d, FFX2, JP, true}, // int.
{0x78da0252, FFXII, EU, false},
{0xc1274668, FFXII, EU, false},
{0xdc2a467e, FFXII, EU, false},
{0xca284668, FFXII, EU, false},
{0x280AD120, FFXII, JP, false},
{0x8BE3D7B2, ShadowHearts, Unknown, false},
{0xDEFA4763, ShadowHearts, US, false},
{0x21068223, Okami, US, false},
{0x891f223f, Okami, FR, false},
{0xC5DEFEA0, Okami, JP, false},
{0x053D2239, MetalGearSolid3, US, false},
{0x086273D2, MetalGearSolid3, FR, false},
{0x26A6E286, MetalGearSolid3, EU, false},
{0xAA31B5BF, MetalGearSolid3, Unknown, false},
{0x9F185CE1, MetalGearSolid3, Unknown, false},
{0x98D4BC93, MetalGearSolid3, EU, false},
{0x86BC3040, MetalGearSolid3, US, false}, //Subsistance disc 1
{0x0481AD8A, MetalGearSolid3, JP, false},
{0x278722BF, DBZBT2, US, false},
{0xFE961D28, DBZBT2, US, false},
{0x0393B6BE, DBZBT2, EU, false},
{0xE2F289ED, DBZBT2, JP, false}, // Sparking Neo!
{0x35AA84D1, DBZBT2, Unknown, false},
{0x428113C2, DBZBT3, US, false},
{0xA422BB13, DBZBT3, EU, false},
{0x983c53d2, DBZBT3, Unknown, false},
{0x72B3802A, SFEX3, US, false},
{0x71521863, SFEX3, US, false},
{0x28703748, Bully, US, false},
{0xC78A495D, BullyCC, US, false},
{0xC19A374E, SoTC, US, false},
{0x7D8F539A, SoTC, EU, false},
{0x3122B508, OnePieceGrandAdventure, US, false},
{0x6F8545DB, ICO, US, false},
{0xB01A4C95, ICO, JP, false},
{0x5C991F4E, ICO, Unknown, false},
{0xAEAD1CA3, GT4, JP, false},
{0x44A61C8F, GT4, Unknown, false},
{0x0086E35B, GT4, Unknown, false},
{0x77E61C8A, GT4, Unknown, false},
{0xC164550A, WildArms5, JPUNDUB, false},
{0xC1640D2C, WildArms5, US, false},
{0x0FCF8FE4, WildArms5, EU, false},
{0x2294D322, WildArms5, JP, false},
{0x565B6170, WildArms5, JP, false},
{0x8B029334, Manhunt2, Unknown, false},
{0x09F49E37, CrashBandicootWoC, Unknown, false},
{0x013E349D, ResidentEvil4, US, false},
{0x6BA2F6B9, ResidentEvil4, Unknown, false},
{0x60FA8C69, ResidentEvil4, JP, false},
{0x72E1E60E, Spartan, Unknown, false},
{0x5ED8FB53, AceCombat4, JP, false},
{0x1B9B7563, AceCombat4, Unknown, false},
{0xEC432B24, Drakengard2, Unknown, false},
{0xFC46EA61, Tekken5, JP, false},
{0x1F88EE37, Tekken5, Unknown, false},
{0x652050D2, Tekken5, Unknown, false},
{0x9E98B8AE, IkkiTousen, JP, false},
{0xD6385328, GodOfWar, US, false},
{0xFB0E6D72, GodOfWar, EU, false},
{0xA61A4C6D, GodOfWar, Unknown, false},
{0xE23D532B, GodOfWar, Unknown, false},
{0x2F123FD8, GodOfWar2, RU, false},
{0x5D482F18, JackieChanAdv, Unknown, false},
{0xf0a6d880, HarvestMoon, US, true},
{0x75c01a04, NamcoXCapcom, US, false},
{0xBF6F101F, GiTS, US, false},
{0xA5768F53, GiTS, JP, false},
{0x6BF11378, Onimusha3, US, false},
{0xF442260C, MajokkoALaMode2, JP, false},
{0x14FE77F7, TalesOfAbyss, US, false},
{0x045D77E9, TalesOfAbyss, US, false}, // undub
{0xAA5EC3A3, TalesOfAbyss, JP, false},
};
CAtlMap<DWORD, CRC::Game*> CRC::m_map;
CRC::Game CRC::Lookup(DWORD crc)
{
if(m_map.IsEmpty())
{
for(int i = 0; i < countof(m_games); i++)
{
m_map[m_games[i].crc] = &m_games[i];
}
}
if(CAtlMap<DWORD, Game*>::CPair* pair = m_map.Lookup(crc))
{
return *pair->m_value;
}
return m_games[0];
}

98
plugins/GSdx/GSCrc.h Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
class CRC
{
public:
enum Title
{
None,
MetalSlug6,
TomoyoAfter,
Clannad,
FFX,
FFX2,
FFXII,
ShadowHearts,
Okami,
MetalGearSolid3,
DBZBT2,
DBZBT3,
SFEX3,
Bully,
BullyCC,
SoTC,
OnePieceGrandAdventure,
ICO,
GT4,
WildArms5,
Manhunt2,
CrashBandicootWoC,
ResidentEvil4,
Spartan,
AceCombat4,
Drakengard2,
Tekken5,
IkkiTousen,
GodOfWar,
GodOfWar2,
JackieChanAdv,
HarvestMoon,
NamcoXCapcom,
GiTS,
Onimusha3,
MajokkoALaMode2,
TalesOfAbyss,
TitleCount
};
enum Region
{
Unknown,
US,
EU,
JP,
JPUNDUB,
RU,
FR,
DE,
IT,
ES,
ASIA
};
struct Game
{
DWORD crc;
Title title;
Region region;
bool nloophack;
};
private:
static Game m_games[];
static CAtlMap<DWORD, Game*> m_map;
public:
static Game Lookup(DWORD crc);
};

23
plugins/GSdx/GSDevice.cpp Normal file
View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSDevice.h"

244
plugins/GSdx/GSDevice.h Normal file
View File

@ -0,0 +1,244 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSTexture.h"
#include "GSVertex.h"
#pragma pack(push, 1)
struct MergeConstantBuffer
{
GSVector4 BGColor;
struct MergeConstantBuffer() {memset(this, 0, sizeof(*this));}
};
struct InterlaceConstantBuffer
{
GSVector2 ZrH;
float hH;
float _pad[1];
struct InterlaceConstantBuffer() {memset(this, 0, sizeof(*this));}
};
#pragma pack(pop)
template<class Texture> class GSDevice
{
CAtlList<Texture> m_pool;
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;
bool Fetch(int type, Texture& t, int w, int h, int format)
{
Recycle(t);
for(POSITION pos = m_pool.GetHeadPosition(); pos; m_pool.GetNext(pos))
{
const Texture& t2 = m_pool.GetAt(pos);
if(t2.GetType() == type && t2.GetWidth() == w && t2.GetHeight() == h && t2.GetFormat() == format)
{
t = t2;
m_pool.RemoveAt(pos);
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;
public:
GSDevice() : m_hWnd(NULL)
{
}
virtual ~GSDevice()
{
}
virtual bool Create(HWND hWnd, bool vsync)
{
m_hWnd = hWnd;
m_vsync = vsync;
return true;
}
virtual bool Reset(int w, int h, bool fs)
{
m_pool.RemoveAll();
m_backbuffer = Texture();
m_merge = Texture();
m_weavebob = Texture();
m_blend = Texture();
m_1x1 = Texture();
m_current = Texture();
return true;
}
virtual bool IsLost() = 0;
virtual void Present(const CRect& r) = 0;
virtual void BeginScene() = 0;
virtual void EndScene() = 0;
virtual void Draw(LPCTSTR str) = 0;
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, DWORD c) = 0;
virtual void ClearDepth(Texture& t, float c) = 0;
virtual void ClearStencil(Texture& t, BYTE 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.AddHead(t);
while(m_pool.GetCount() > 200)
{
m_pool.RemoveTail();
}
t = Texture();
}
}
bool SaveCurrent(LPCTSTR fn)
{
return m_current.Save(fn);
}
void GetCurrent(Texture& t)
{
t = m_current;
}
void Merge(Texture* st, GSVector4* sr, GSVector4* dr, CSize fs, bool slbg, bool mmod, GSVector4& c)
{
if(!m_merge || m_merge.GetWidth() != fs.cx || m_merge.GetHeight() != fs.cy)
{
CreateRenderTarget(m_merge, fs.cx, fs.cy);
}
// TODO: m_1x1
DoMerge(st, sr, dr, m_merge, slbg, mmod, c);
m_current = m_merge;
}
bool Interlace(CSize ds, int field, int mode, float yoffset)
{
if(!m_weavebob || m_weavebob.GetWidth() != ds.cx || m_weavebob.GetHeight() != ds.cy)
{
CreateRenderTarget(m_weavebob, ds.cx, ds.cy);
}
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.cx || m_blend.GetHeight() != ds.cy)
{
CreateRenderTarget(m_blend, ds.cx, ds.cy);
}
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;
}
};

833
plugins/GSdx/GSDevice10.cpp Normal file
View File

@ -0,0 +1,833 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDevice10.h"
#include "resource.h"
GSDevice10::GSDevice10()
: m_vb(NULL)
, m_vb_stride(0)
, m_layout(NULL)
, m_topology(D3D10_PRIMITIVE_TOPOLOGY_UNDEFINED)
, m_vs(NULL)
, m_vs_cb(NULL)
, m_gs(NULL)
, m_ps(NULL)
, m_ps_cb(NULL)
, m_scissor(0, 0, 0, 0)
, m_viewport(0, 0)
, m_dss(NULL)
, m_sref(0)
, m_bs(NULL)
, m_bf(-1)
, m_rtv(NULL)
, m_dsv(NULL)
{
memset(m_ps_srv, 0, sizeof(m_ps_srv));
memset(m_ps_ss, 0, sizeof(m_ps_ss));
}
GSDevice10::~GSDevice10()
{
}
bool GSDevice10::Create(HWND hWnd, bool vsync)
{
if(!__super::Create(hWnd, vsync))
{
return false;
}
HRESULT hr;
DXGI_SWAP_CHAIN_DESC scd;
D3D10_BUFFER_DESC bd;
D3D10_SAMPLER_DESC sd;
D3D10_DEPTH_STENCIL_DESC dsd;
D3D10_RASTERIZER_DESC rd;
D3D10_BLEND_DESC bsd;
memset(&scd, 0, sizeof(scd));
scd.BufferCount = 2;
scd.BufferDesc.Width = 1;
scd.BufferDesc.Height = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
//scd.BufferDesc.RefreshRate.Numerator = 60;
//scd.BufferDesc.RefreshRate.Denominator = 1;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = hWnd;
scd.SampleDesc.Count = 1;
scd.SampleDesc.Quality = 0;
scd.Windowed = TRUE;
UINT flags = 0;
#ifdef DEBUG
flags |= D3D10_CREATE_DEVICE_DEBUG;
#endif
hr = D3D10CreateDeviceAndSwapChain(NULL, D3D10_DRIVER_TYPE_HARDWARE, NULL, flags, D3D10_SDK_VERSION, &scd, &m_swapchain, &m_dev);
if(FAILED(hr)) return false;
// font
/*
// TODO: the driver crashes on alt-enter when using a font...
D3DX10_FONT_DESC fd;
memset(&fd, 0, sizeof(fd));
_tcscpy(fd.FaceName, _T("Arial"));
fd.Height = 20;
D3DX10CreateFontIndirect(m_dev, &fd, &m_font);
*/
// convert
D3D10_INPUT_ELEMENT_DESC il_convert[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0},
};
hr = CompileShader(IDR_CONVERT10_FX, "vs_main", NULL, &m_convert.vs, il_convert, countof(il_convert), &m_convert.il);
for(int i = 0; i < countof(m_convert.ps); i++)
{
CStringA main;
main.Format("ps_main%d", i);
hr = CompileShader(IDR_CONVERT10_FX, main, NULL, &m_convert.ps[i]);
}
memset(&bd, 0, sizeof(bd));
bd.Usage = D3D10_USAGE_DEFAULT;
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
bd.ByteWidth = 4 * sizeof(GSVertexPT1);
hr = m_dev->CreateBuffer(&bd, NULL, &m_convert.vb);
memset(&dsd, 0, sizeof(dsd));
dsd.DepthEnable = false;
dsd.StencilEnable = false;
hr = m_dev->CreateDepthStencilState(&dsd, &m_convert.dss);
memset(&bsd, 0, sizeof(bsd));
bsd.BlendEnable[0] = false;
bsd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
hr = m_dev->CreateBlendState(&bsd, &m_convert.bs);
// merge
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(MergeConstantBuffer);
bd.Usage = D3D10_USAGE_DEFAULT;
bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
hr = m_dev->CreateBuffer(&bd, NULL, &m_merge.cb);
for(int i = 0; i < countof(m_merge.ps); i++)
{
CStringA main;
main.Format("ps_main%d", i);
hr = CompileShader(IDR_MERGE10_FX, main, NULL, &m_merge.ps[i]);
}
memset(&bsd, 0, sizeof(bsd));
bsd.BlendEnable[0] = true;
bsd.BlendOp = D3D10_BLEND_OP_ADD;
bsd.SrcBlend = D3D10_BLEND_SRC_ALPHA;
bsd.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
bsd.BlendOpAlpha = D3D10_BLEND_OP_ADD;
bsd.SrcBlendAlpha = D3D10_BLEND_ONE;
bsd.DestBlendAlpha = D3D10_BLEND_ZERO;
bsd.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;
hr = m_dev->CreateBlendState(&bsd, &m_merge.bs);
// interlace
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(InterlaceConstantBuffer);
bd.Usage = D3D10_USAGE_DEFAULT;
bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
hr = m_dev->CreateBuffer(&bd, NULL, &m_interlace.cb);
for(int i = 0; i < countof(m_interlace.ps); i++)
{
CStringA main;
main.Format("ps_main%d", i);
hr = CompileShader(IDR_INTERLACE10_FX, main, NULL, &m_interlace.ps[i]);
}
//
memset(&rd, 0, sizeof(rd));
rd.FillMode = D3D10_FILL_SOLID;
rd.CullMode = D3D10_CULL_NONE;
rd.FrontCounterClockwise = false;
rd.DepthBias = false;
rd.DepthBiasClamp = 0;
rd.SlopeScaledDepthBias = 0;
rd.DepthClipEnable = false; // ???
rd.ScissorEnable = true;
rd.MultisampleEnable = false;
rd.AntialiasedLineEnable = false;
hr = m_dev->CreateRasterizerState(&rd, &m_rs);
m_dev->RSSetState(m_rs);
//
memset(&sd, 0, sizeof(sd));
sd.Filter = D3D10_FILTER_MIN_MAG_MIP_LINEAR;
sd.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP;
sd.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP;
sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
sd.MaxLOD = FLT_MAX;
sd.MaxAnisotropy = 16;
sd.ComparisonFunc = D3D10_COMPARISON_NEVER;
hr = m_dev->CreateSamplerState(&sd, &m_convert.ln);
sd.Filter = D3D10_FILTER_MIN_MAG_MIP_POINT;
hr = m_dev->CreateSamplerState(&sd, &m_convert.pt);
//
Reset(1, 1, true);
//
/*
if(!m_mergefx.Create(this))
{
return false;
}
*/
//
return true;
}
bool GSDevice10::Reset(int w, int h, bool fs)
{
if(!__super::Reset(w, h, fs))
return false;
DXGI_SWAP_CHAIN_DESC scd;
memset(&scd, 0, sizeof(scd));
m_swapchain->GetDesc(&scd);
m_swapchain->ResizeBuffers(scd.BufferCount, w, h, scd.BufferDesc.Format, 0);
CComPtr<ID3D10Texture2D> backbuffer;
m_swapchain->GetBuffer(0, __uuidof(ID3D10Texture2D), (void**)&backbuffer);
m_backbuffer = Texture(backbuffer);
return true;
}
void GSDevice10::Present(const CRect& r)
{
CRect 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);
}
void GSDevice10::BeginScene()
{
}
void GSDevice10::EndScene()
{
PSSetShaderResources(NULL, NULL);
// not clearing the rt/ds gives a little fps boost in complex games (5-10%)
// OMSetRenderTargets(NULL, NULL);
}
void GSDevice10::Draw(LPCTSTR str)
{
/*
BOOL fs;
CComPtr<IDXGIOutput> target;
m_swapchain->GetFullscreenState(&fs, &target);
if(fs)
{
BeginScene();
OMSetRenderTargets(m_backbuffer, NULL);
CRect 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 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, DWORD c)
{
GSVector4 color = GSVector4(c) * (1.0f / 255);
m_dev->ClearRenderTargetView(t, color.v);
}
void GSDevice10::ClearDepth(Texture& t, float c)
{
m_dev->ClearDepthStencilView(t, D3D10_CLEAR_DEPTH, c, 0);
}
void GSDevice10::ClearStencil(Texture& t, BYTE c)
{
m_dev->ClearDepthStencilView(t, D3D10_CLEAR_STENCIL, 0, c);
}
bool GSDevice10::Create(int type, Texture& t, int w, int h, int format)
{
HRESULT hr;
D3D10_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Width = w;
desc.Height = h;
desc.Format = (DXGI_FORMAT)format;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D10_USAGE_DEFAULT;
switch(type)
{
case GSTexture::RenderTarget:
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
break;
case GSTexture::DepthStencil:
desc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
break;
case GSTexture::Texture:
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
break;
case GSTexture::Offscreen:
desc.Usage = D3D10_USAGE_STAGING;
desc.CPUAccessFlags |= D3D10_CPU_ACCESS_READ | D3D10_CPU_ACCESS_WRITE;
break;
}
CComPtr<ID3D10Texture2D> texture;
hr = m_dev->CreateTexture2D(&desc, NULL, &texture);
if(SUCCEEDED(hr))
{
t = Texture(texture);
switch(type)
{
case GSTexture::RenderTarget:
ClearRenderTarget(t, 0);
break;
case GSTexture::DepthStencil:
ClearDepth(t, 0);
break;
}
return true;
}
return false;
}
bool GSDevice10::CreateRenderTarget(Texture& t, int w, int h, int format)
{
return __super::CreateRenderTarget(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
}
bool GSDevice10::CreateDepthStencil(Texture& t, int w, int h, int format)
{
return __super::CreateDepthStencil(t, w, h, format ? format : DXGI_FORMAT_D32_FLOAT_S8X24_UINT);
}
bool GSDevice10::CreateTexture(Texture& t, int w, int h, int format)
{
return __super::CreateTexture(t, w, h, format ? format : DXGI_FORMAT_R8G8B8A8_UNORM);
}
bool GSDevice10::CreateOffscreen(Texture& t, int w, int h, int format)
{
return __super::CreateOffscreen(t, 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)
{
ClearRenderTarget(dt, c);
if(st[1] && !slbg)
{
StretchRect(st[1], sr[1], dt, dr[1], m_merge.ps[0], NULL, true);
}
if(st[0])
{
m_dev->UpdateSubresource(m_merge.cb, 0, NULL, &c, 0, 0);
StretchRect(st[0], sr[0], dt, dr[0], m_merge.ps[mmod ? 1 : 0], m_merge.cb, m_merge.bs, true);
}
}
void GSDevice10::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset)
{
GSVector4 sr(0, 0, 1, 1);
GSVector4 dr(0.0f, yoffset, (float)dt.GetWidth(), (float)dt.GetHeight() + yoffset);
InterlaceConstantBuffer cb;
cb.ZrH = GSVector2(0, 1.0f / dt.GetHeight());
cb.hH = (float)dt.GetHeight() / 2;
m_dev->UpdateSubresource(m_interlace.cb, 0, NULL, &cb, 0, 0);
StretchRect(st, sr, dt, dr, m_interlace.ps[shader], m_interlace.cb, linear);
}
void GSDevice10::IASetVertexBuffer(ID3D10Buffer* vb, UINT stride)
{
if(m_vb != vb || m_vb_stride != stride)
{
UINT offset = 0;
m_dev->IASetVertexBuffers(0, 1, &vb, &stride, &offset);
m_vb = vb;
m_vb_stride = stride;
}
}
void GSDevice10::IASetInputLayout(ID3D10InputLayout* layout)
{
if(m_layout != layout)
{
m_dev->IASetInputLayout(layout);
m_layout = layout;
}
}
void GSDevice10::IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY topology)
{
if(m_topology != topology)
{
m_dev->IASetPrimitiveTopology(topology);
m_topology = topology;
}
}
void GSDevice10::VSSetShader(ID3D10VertexShader* vs, ID3D10Buffer* vs_cb)
{
if(m_vs != vs)
{
m_dev->VSSetShader(vs);
m_vs = vs;
}
if(m_vs_cb != vs_cb)
{
m_dev->VSSetConstantBuffers(0, 1, &vs_cb);
m_vs_cb = vs_cb;
}
}
void GSDevice10::GSSetShader(ID3D10GeometryShader* gs)
{
if(m_gs != gs)
{
m_dev->GSSetShader(gs);
m_gs = gs;
}
}
void GSDevice10::PSSetShaderResources(ID3D10ShaderResourceView* srv0, ID3D10ShaderResourceView* srv1)
{
if(m_ps_srv[0] != srv0 || m_ps_srv[1] != srv1)
{
ID3D10ShaderResourceView* srvs[] = {srv0, srv1};
m_dev->PSSetShaderResources(0, 2, srvs);
m_ps_srv[0] = srv0;
m_ps_srv[1] = srv1;
}
}
void GSDevice10::PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb)
{
if(m_ps != ps)
{
m_dev->PSSetShader(ps);
m_ps = ps;
}
if(m_ps_cb != ps_cb)
{
m_dev->PSSetConstantBuffers(0, 1, &ps_cb);
m_ps_cb = ps_cb;
}
}
void GSDevice10::PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1)
{
if(m_ps_ss[0] != ss0 || m_ps_ss[1] != ss1)
{
ID3D10SamplerState* sss[] = {ss0, ss1};
m_dev->PSSetSamplers(0, 2, sss);
m_ps_ss[0] = ss0;
m_ps_ss[1] = ss1;
}
}
void GSDevice10::RSSet(int width, int height, const RECT* scissor)
{
if(m_viewport.cx != width || m_viewport.cy != height)
{
D3D10_VIEWPORT vp;
memset(&vp, 0, sizeof(vp));
vp.TopLeftX = 0;
vp.TopLeftY = 0;
vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
m_dev->RSSetViewports(1, &vp);
m_viewport = CSize(width, height);
}
CRect r = scissor ? *scissor : CRect(0, 0, width, height);
if(m_scissor != r)
{
m_dev->RSSetScissorRects(1, &r);
m_scissor = r;
}
}
void GSDevice10::OMSetDepthStencilState(ID3D10DepthStencilState* dss, UINT sref)
{
if(m_dss != dss || m_sref != sref)
{
m_dev->OMSetDepthStencilState(dss, sref);
m_dss = dss;
m_sref = sref;
}
}
void GSDevice10::OMSetBlendState(ID3D10BlendState* bs, float bf)
{
if(m_bs != bs || m_bf != bf)
{
float BlendFactor[] = {bf, bf, bf, 0};
m_dev->OMSetBlendState(bs, BlendFactor, 0xffffffff);
m_bs = bs;
m_bf = bf;
}
}
void GSDevice10::OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv)
{
if(m_rtv != rtv || m_dsv != dsv)
{
m_dev->OMSetRenderTargets(1, &rtv, dsv);
m_rtv = rtv;
m_dsv = dsv;
}
}
void GSDevice10::DrawPrimitive(UINT count, UINT 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(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** ps, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il)
{
HRESULT hr;
CComPtr<ID3D10Blob> shader, error;
hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "vs_4_0", 0, 0, NULL, &shader, &error, NULL);
if(error)
{
TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer()));
}
if(FAILED(hr))
{
return hr;
}
hr = m_dev->CreateVertexShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), ps);
if(FAILED(hr))
{
return hr;
}
hr = m_dev->CreateInputLayout(layout, count, shader->GetBufferPointer(), shader->GetBufferSize(), il);
if(FAILED(hr))
{
return hr;
}
return hr;
}
HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs)
{
HRESULT hr;
CComPtr<ID3D10Blob> shader, error;
hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "gs_4_0", 0, 0, NULL, &shader, &error, NULL);
if(error)
{
TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer()));
}
if(FAILED(hr))
{
return hr;
}
hr = m_dev->CreateGeometryShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), gs);
if(FAILED(hr))
{
return hr;
}
return hr;
}
HRESULT GSDevice10::CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10PixelShader** ps)
{
HRESULT hr;
CComPtr<ID3D10Blob> shader, error;
hr = D3DX10CompileFromResource(AfxGetInstanceHandle(), MAKEINTRESOURCE(id), NULL, macro, NULL, entry, "ps_4_0", 0, 0, NULL, &shader, &error, NULL);
if(error)
{
TRACE(_T("%s\n"), CString((LPCSTR)error->GetBufferPointer()));
}
if(FAILED(hr))
{
return hr;
}
hr = m_dev->CreatePixelShader((DWORD*)shader->GetBufferPointer(), shader->GetBufferSize(), ps);
if(FAILED(hr))
{
return hr;
}
return hr;
}

147
plugins/GSdx/GSDevice10.h Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice.h"
#include "GSTexture10.h"
class GSDevice10 : public GSDevice<GSTexture10>
{
public:
typedef GSTexture10 Texture;
private:
// state cache
ID3D10Buffer* m_vb;
UINT m_vb_count;
UINT m_vb_stride;
ID3D10InputLayout* m_layout;
D3D10_PRIMITIVE_TOPOLOGY m_topology;
ID3D10VertexShader* m_vs;
ID3D10Buffer* m_vs_cb;
ID3D10GeometryShader* m_gs;
ID3D10ShaderResourceView* m_ps_srv[2];
ID3D10PixelShader* m_ps;
ID3D10Buffer* m_ps_cb;
ID3D10SamplerState* m_ps_ss[2];
CSize m_viewport;
CRect m_scissor;
ID3D10DepthStencilState* m_dss;
UINT m_sref;
ID3D10BlendState* m_bs;
float m_bf;
ID3D10RenderTargetView* m_rtv;
ID3D10DepthStencilView* m_dsv;
//
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);
//
CComPtr<ID3D10Device> m_dev;
CComPtr<IDXGISwapChain> m_swapchain;
CComPtr<ID3DX10Font> m_font;
public: // TODO
CComPtr<ID3D10RasterizerState> m_rs;
struct
{
CComPtr<ID3D10Buffer> vb;
CComPtr<ID3D10InputLayout> il;
CComPtr<ID3D10VertexShader> vs;
CComPtr<ID3D10PixelShader> ps[5];
CComPtr<ID3D10SamplerState> ln;
CComPtr<ID3D10SamplerState> pt;
CComPtr<ID3D10DepthStencilState> dss;
CComPtr<ID3D10BlendState> bs;
} m_convert;
struct
{
CComPtr<ID3D10PixelShader> ps[2];
CComPtr<ID3D10Buffer> cb;
CComPtr<ID3D10BlendState> bs;
} m_merge;
struct
{
CComPtr<ID3D10PixelShader> ps[4];
CComPtr<ID3D10Buffer> cb;
} m_interlace;
public:
GSDevice10();
virtual ~GSDevice10();
bool Create(HWND hWnd, bool vsync);
bool Reset(int w, int h, bool fs);
bool IsLost() {return false;}
void Present(const CRect& r);
void BeginScene();
void EndScene();
void Draw(LPCTSTR str);
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, DWORD c);
void ClearDepth(Texture& t, float c);
void ClearStencil(Texture& t, BYTE 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);
ID3D10Device* operator->() {return m_dev;}
operator ID3D10Device*() {return m_dev;}
void IASetVertexBuffer(ID3D10Buffer* vb, UINT 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 PSSetShader(ID3D10PixelShader* ps, ID3D10Buffer* ps_cb);
void PSSetSamplerState(ID3D10SamplerState* ss0, ID3D10SamplerState* ss1);
void RSSet(int width, int height, const RECT* scissor = NULL);
void OMSetDepthStencilState(ID3D10DepthStencilState* dss, UINT sref);
void OMSetBlendState(ID3D10BlendState* bs, float bf);
void OMSetRenderTargets(ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv);
void DrawPrimitive(UINT count, UINT 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);
HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10VertexShader** vs, D3D10_INPUT_ELEMENT_DESC* layout, int count, ID3D10InputLayout** il);
HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10GeometryShader** gs);
HRESULT CompileShader(UINT id, LPCSTR entry, D3D10_SHADER_MACRO* macro, ID3D10PixelShader** ps);
// TODO
bool SaveToFileD32S8X24(ID3D10Texture2D* ds, LPCTSTR fn);
};

241
plugins/GSdx/GSDevice7.cpp Normal file
View File

@ -0,0 +1,241 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
// dumb device implementation, only good for simple image output
#include "stdafx.h"
#include "GSDevice7.h"
GSDevice7::GSDevice7()
{
}
GSDevice7::~GSDevice7()
{
}
bool GSDevice7::Create(HWND hWnd, bool vsync)
{
if(!__super::Create(hWnd, vsync))
{
return false;
}
if(FAILED(DirectDrawCreateEx(NULL, (VOID**)&m_dd, IID_IDirectDraw7, NULL)))
{
return false;
}
// TODO: fullscreen
if(FAILED(m_dd->SetCooperativeLevel(hWnd, DDSCL_NORMAL)))
{
return false;
}
DDSURFACEDESC2 desc;
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_CAPS;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
if(FAILED(m_dd->CreateSurface(&desc, &m_primary, NULL)))
{
return false;
}
CComPtr<IDirectDrawClipper> clipper;
if(FAILED(m_dd->CreateClipper(0, &clipper, NULL))
|| FAILED(clipper->SetHWnd(0, hWnd))
|| FAILED(m_primary->SetClipper(clipper)))
{
return false;
}
Reset(1, 1, true);
return true;
}
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));
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;
desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_3DDEVICE;
desc.dwWidth = w;
desc.dwHeight = h;
if(FAILED(m_dd->CreateSurface(&desc, &m_backbuffer, NULL)))
{
return false;
}
CComPtr<IDirectDrawClipper> clipper;
if(FAILED(m_dd->CreateClipper(0, &clipper, NULL)))
{
return false;
}
{
// ???
HRGN hrgn = CreateRectRgn(0, 0, w, h);
BYTE buff[1024];
GetRegionData(hrgn, sizeof(buff), (RGNDATA*)buff);
DeleteObject(hrgn);
clipper->SetClipList((RGNDATA*)buff, 0);
if(FAILED(m_backbuffer->SetClipper(clipper)))
{
return false;
}
}
return true;
}
void GSDevice7::Present(const CRect& r)
{
HRESULT hr;
CRect cr;
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())
{
Reset(cr.Width(), cr.Height(), false);
}
DDBLTFX fx;
memset(&fx, 0, sizeof(fx));
fx.dwSize = sizeof(fx);
fx.dwFillColor = 0;
hr = m_backbuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &fx);
CRect r2 = r;
hr = m_backbuffer->Blt(&r2, m_merge, NULL, DDBLT_WAIT, NULL);
r2 = cr;
MapWindowPoints(m_hWnd, HWND_DESKTOP, (POINT*)&r2, 2);
if(m_vsync)
{
hr = m_dd->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
}
hr = m_primary->Blt(&r2, m_backbuffer, &cr, DDBLT_WAIT, NULL);
if(hr == DDERR_SURFACELOST)
{
// TODO
HRESULT hr = m_dd->TestCooperativeLevel();
if(hr == DDERR_WRONGMODE)
{
}
}
}
bool GSDevice7::Create(int type, Texture& t, int w, int h, int format)
{
HRESULT hr;
t = Texture();
DDSURFACEDESC2 desc;
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
desc.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY;
desc.dwWidth = w;
desc.dwHeight = h;
desc.ddpfPixelFormat.dwSize = sizeof(desc.ddpfPixelFormat);
desc.ddpfPixelFormat.dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
desc.ddpfPixelFormat.dwRGBBitCount = 32;
desc.ddpfPixelFormat.dwRGBAlphaBitMask = 0xff000000;
desc.ddpfPixelFormat.dwRBitMask = 0x00ff0000;
desc.ddpfPixelFormat.dwGBitMask = 0x0000ff00;
desc.ddpfPixelFormat.dwBBitMask = 0x000000ff;
CComPtr<IDirectDrawSurface7> system, video;
switch(type)
{
case GSTexture::RenderTarget:
case GSTexture::DepthStencil:
case GSTexture::Texture:
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
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);
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);
break;
}
return !!t;
}
void GSDevice7::DoMerge(Texture* st, GSVector4* sr, GSVector4* dr, Texture& dt, bool slbg, bool mmod, GSVector4& c)
{
HRESULT hr;
hr = dt->Blt(NULL, st[0], NULL, DDBLT_WAIT, NULL);
}
void GSDevice7::DoInterlace(Texture& st, Texture& dt, int shader, bool linear, float yoffset)
{
}

58
plugins/GSdx/GSDevice7.h Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice.h"
#include "GSTexture7.h"
class GSDevice7 : public GSDevice<GSTexture7>
{
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);
public:
GSDevice7();
virtual ~GSDevice7();
bool Create(HWND hWnd, bool vsync);
bool Reset(int w, int h, bool fs);
bool IsLost() {return false;}
void Present(const CRect& r);
void BeginScene() {}
void EndScene() {}
void Draw(LPCTSTR str) {}
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, DWORD c) {}
void ClearDepth(Texture& t, float c) {}
void ClearStencil(Texture& t, BYTE c) {}
};

1062
plugins/GSdx/GSDevice9.cpp Normal file

File diff suppressed because it is too large Load Diff

192
plugins/GSdx/GSDevice9.h Normal file
View File

@ -0,0 +1,192 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice.h"
#include "GSTexture9.h"
struct Direct3DSamplerState9
{
D3DTEXTUREFILTERTYPE FilterMin[2];
D3DTEXTUREFILTERTYPE FilterMag[2];
D3DTEXTUREADDRESS AddressU;
D3DTEXTUREADDRESS AddressV;
};
struct Direct3DDepthStencilState9
{
BOOL DepthEnable;
BOOL DepthWriteMask;
D3DCMPFUNC DepthFunc;
BOOL StencilEnable;
UINT8 StencilReadMask;
UINT8 StencilWriteMask;
D3DSTENCILOP StencilFailOp;
D3DSTENCILOP StencilDepthFailOp;
D3DSTENCILOP StencilPassOp;
D3DCMPFUNC StencilFunc;
};
struct Direct3DBlendState9
{
BOOL BlendEnable;
D3DBLEND SrcBlend;
D3DBLEND DestBlend;
D3DBLENDOP BlendOp;
D3DBLEND SrcBlendAlpha;
D3DBLEND DestBlendAlpha;
D3DBLENDOP BlendOpAlpha;
UINT8 RenderTargetWriteMask;
};
class GSDevice9 : public GSDevice<GSTexture9>
{
public:
typedef GSTexture9 Texture;
private:
// state cache
IDirect3DVertexBuffer9* m_vb;
UINT m_vb_count;
const void* m_vb_vertices;
UINT m_vb_stride;
IDirect3DVertexDeclaration9* m_layout;
D3DPRIMITIVETYPE m_topology;
IDirect3DVertexShader9* m_vs;
float* m_vs_cb;
int m_vs_cb_len;
IDirect3DTexture9* m_ps_srvs[2];
IDirect3DPixelShader9* m_ps;
float* m_ps_cb;
int m_ps_cb_len;
Direct3DSamplerState9* m_ps_ss;
CRect m_scissor;
Direct3DDepthStencilState9* m_dss;
UINT m_sref;
Direct3DBlendState9* m_bs;
DWORD m_bf;
IDirect3DSurface9* m_rtv;
IDirect3DSurface9* m_dsv;
//
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);
//
DDCAPS m_ddcaps;
D3DCAPS9 m_d3dcaps;
CComPtr<IDirect3D9> m_d3d;
CComPtr<IDirect3DDevice9> m_dev;
CComPtr<IDirect3DSwapChain9> m_swapchain;
Texture m_backbuffer;
public: // TODO
D3DPRESENT_PARAMETERS m_pp;
CComPtr<ID3DXFont> m_font;
struct
{
CComPtr<IDirect3DVertexShader9> vs;
CComPtr<IDirect3DVertexDeclaration9> il;
CComPtr<IDirect3DPixelShader9> ps[5];
Direct3DSamplerState9 ln;
Direct3DSamplerState9 pt;
Direct3DDepthStencilState9 dss;
Direct3DBlendState9 bs;
} m_convert;
struct
{
CComPtr<IDirect3DPixelShader9> ps[2];
Direct3DBlendState9 bs;
} m_merge;
struct
{
CComPtr<IDirect3DPixelShader9> ps[4];
} m_interlace;
public:
GSDevice9();
virtual ~GSDevice9();
bool Create(HWND hWnd, bool vsync);
bool Reset(int w, int h, bool fs);
bool IsLost();
void Present(const CRect& r);
void BeginScene();
void EndScene();
void Draw(LPCTSTR str);
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, DWORD c);
void ClearDepth(Texture& t, float c);
void ClearStencil(Texture& t, BYTE 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);
IDirect3DDevice9* operator->() {return m_dev;}
operator IDirect3DDevice9*() {return m_dev;}
// TODO: void IASetVertexBuffer(IDirect3DVertexBuffer9* vb, UINT count, const void* vertices, UINT stride);
void IASetVertexBuffer(UINT count, const void* vertices, UINT 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 PSSetShader(IDirect3DPixelShader9* ps, const float* ps_cb, int ps_cb_len);
void PSSetSamplerState(Direct3DSamplerState9* ss);
void RSSet(int width, int height, const RECT* scissor = NULL);
void OMSetDepthStencilState(Direct3DDepthStencilState9* dss, UINT sref);
void OMSetBlendState(Direct3DBlendState9* bs, DWORD bf);
void OMSetRenderTargets(IDirect3DSurface9* rtv, IDirect3DSurface9* dsv);
void DrawPrimitive();
template<class T> void IASetVertexBuffer(UINT count, T* vertices)
{
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);
HRESULT CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DVertexShader9** vs, const D3DVERTEXELEMENT9* layout, int count, IDirect3DVertexDeclaration9** il);
HRESULT CompileShader(UINT id, LPCSTR entry, const D3DXMACRO* macro, IDirect3DPixelShader9** ps);
virtual bool IsCurrentRGBA()
{
return false;
}
// TODO
bool SaveToFileD24S8(IDirect3DSurface9* ds, LPCTSTR fn);
};

View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSDeviceNull.h"
bool GSDeviceNull::Create(HWND hWnd, bool vsync)
{
if(!__super::Create(hWnd, vsync))
{
return false;
}
Reset(1, 1, true);
return true;
}
bool GSDeviceNull::Reset(int w, int h, bool fs)
{
if(!__super::Reset(w, h, fs))
return false;
return true;
}
bool GSDeviceNull::Create(int type, Texture& t, int w, int h, int format)
{
t = Texture(type, w, h, format);
return true;
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice.h"
#include "GSTextureNull.h"
class GSDeviceNull : public GSDevice<GSTextureNull>
{
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) {}
public:
GSDeviceNull() {}
bool Create(HWND hWnd, bool vsync);
bool Reset(int w, int h, bool fs);
bool IsLost() {return false;}
void Present(const CRect& r) {}
void BeginScene() {}
void EndScene() {}
void Draw(LPCTSTR str) {}
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, DWORD c) {}
void ClearDepth(Texture& t, float c) {}
void ClearStencil(Texture& t, BYTE c) {}
};

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSDirtyRect.h"
GSDirtyRect::GSDirtyRect()
: m_psm(PSM_PSMCT32)
, m_rect(0, 0, 0, 0)
{
}
GSDirtyRect::GSDirtyRect(DWORD psm, CRect rect)
{
m_psm = psm;
m_rect = rect;
}
CRect GSDirtyRect::GetDirtyRect(const GIFRegTEX0& TEX0)
{
CRect r = m_rect;
CSize src = GSLocalMemory::m_psm[m_psm].bs;
r.left = (r.left) & ~(src.cx-1);
r.right = (r.right + (src.cx-1) /* + 1 */) & ~(src.cx-1);
r.top = (r.top) & ~(src.cy-1);
r.bottom = (r.bottom + (src.cy-1) /* + 1 */) & ~(src.cy-1);
if(m_psm != TEX0.PSM)
{
CSize dst = GSLocalMemory::m_psm[TEX0.PSM].bs;
r.left = MulDiv(m_rect.left, dst.cx, src.cx);
r.right = MulDiv(m_rect.right, dst.cx, src.cx);
r.top = MulDiv(m_rect.top, dst.cy, src.cy);
r.bottom = MulDiv(m_rect.bottom, dst.cy, src.cy);
}
return r;
}
//
CRect GSDirtyRectList::GetDirtyRect(const GIFRegTEX0& TEX0, CSize size)
{
if(IsEmpty()) return CRect(0, 0, 0, 0);
CRect r(INT_MAX, INT_MAX, 0, 0);
POSITION pos = GetHeadPosition();
while(pos) r |= GetNext(pos).GetDirtyRect(TEX0);
return r & CRect(0, 0, size.cx, size.cy);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSLocalMemory.h"
class GSDirtyRect
{
DWORD m_psm;
CRect m_rect;
public:
GSDirtyRect();
GSDirtyRect(DWORD psm, CRect rect);
CRect GetDirtyRect(const GIFRegTEX0& TEX0);
};
class GSDirtyRectList : public CAtlList<GSDirtyRect>
{
public:
GSDirtyRectList() {}
CRect GetDirtyRect(const GIFRegTEX0& TEX0, CSize size);
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,217 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSState.h"
#include "GSRasterizer.h"
#include "GSAlignedClass.h"
union GSScanlineSelector
{
struct
{
DWORD fpsm:2; // 0
DWORD zpsm:2; // 2
DWORD ztst:2; // 4 (0: off, 1: write, 2: test (ge), 3: test (g))
DWORD atst:3; // 6
DWORD afail:2; // 9
DWORD iip:1; // 11
DWORD tfx:3; // 12
DWORD tcc:1; // 15
DWORD fst:1; // 16
DWORD ltf:1; // 17
DWORD tlu:1; // 18
DWORD fge:1; // 19
DWORD date:1; // 20
DWORD abea:2; // 21
DWORD abeb:2; // 23
DWORD abec:2; // 25
DWORD abed:2; // 27
DWORD pabe:1; // 29
DWORD rfb:1; // 30
DWORD sprite:1; // 31
};
struct
{
DWORD _pad1:21;
DWORD abe:8;
DWORD _pad2:3;
};
DWORD dw;
operator DWORD() {return dw;}
bool IsSolidRect()
{
return sprite
&& iip == 0
&& tfx == TFX_NONE
&& abe == 255
&& ztst <= 1
&& atst <= 1
&& date == 0
&& fge == 0;
}
};
__declspec(align(16)) struct GSScanlineEnvironment
{
GSScanlineSelector sel;
void* vm;
const void* tex;
const DWORD* clut;
DWORD tw;
GSVector4i* fbr;
GSVector4i* zbr;
int** fbc;
int** zbc;
GSVector2i* fzbr;
GSVector2i* fzbc;
GSVector4i fm, zm;
struct {GSVector4i min, max, mask;} t; // [u] x 4 [v] x 4
GSVector4i datm;
GSVector4i colclamp;
GSVector4i fba;
GSVector4i aref;
GSVector4i afix, afix2;
GSVector4i frb, fga;
struct {GSVector4 z, s, t, q; GSVector4i rb, ga, f, si, ti, _pad[3];} d[4];
struct {GSVector4 z, stq; GSVector4i c, f, st;} d4;
struct {GSVector4i rb, ga;} c;
struct {GSVector4i z, f;} p;
struct {GSVector4i rb, ga;} c2;
};
__declspec(align(16)) struct GSScanlineParam
{
GSScanlineSelector sel;
void* vm;
const void* tex;
const DWORD* clut;
DWORD tw;
GSLocalMemory::Offset* fbo;
GSLocalMemory::Offset* zbo;
GSLocalMemory::Offset4* fzbo;
DWORD fm, zm;
};
class GSDrawScanline : public GSAlignedClass<16>, public IDrawScanline
{
GSScanlineEnvironment m_env;
static const GSVector4 m_shift[4];
static const GSVector4i m_test[8];
//
class GSDrawScanlineMap : public GSFunctionMap<DrawScanlinePtr>
{
DrawScanlinePtr m_default[4][4][4][2];
public:
GSDrawScanlineMap();
DrawScanlinePtr GetDefaultFunction(DWORD dw);
void PrintStats();
};
GSDrawScanlineMap m_ds;
//
class GSSetupPrimMap : public GSFunctionMap<SetupPrimPtr>
{
SetupPrimPtr m_default[2][2][2][2][2];
public:
GSSetupPrimMap();
SetupPrimPtr GetDefaultFunction(DWORD dw);
};
GSSetupPrimMap m_sp;
//
template<DWORD zbe, DWORD fge, DWORD tme, DWORD fst, DWORD iip>
void SetupPrim(const GSVertexSW* vertices, const GSVertexSW& dscan);
//
__forceinline GSVector4i Wrap(const GSVector4i& t);
__forceinline void SampleTexture(DWORD ltf, DWORD tlu, const GSVector4i& u, const GSVector4i& v, GSVector4i* c);
__forceinline void ColorTFX(DWORD iip, DWORD tfx, const GSVector4i& rbf, const GSVector4i& gaf, GSVector4i& rbt, GSVector4i& gat);
__forceinline void AlphaTFX(DWORD iip, DWORD tfx, DWORD tcc, const GSVector4i& gaf, GSVector4i& gat);
__forceinline void Fog(DWORD fge, const GSVector4i& f, GSVector4i& rb, GSVector4i& ga);
__forceinline bool TestZ(DWORD zpsm, DWORD ztst, const GSVector4i& zs, const GSVector4i& zd, GSVector4i& test);
__forceinline bool TestAlpha(DWORD atst, DWORD afail, const GSVector4i& ga, GSVector4i& fm, GSVector4i& zm, GSVector4i& test);
__forceinline bool TestDestAlpha(DWORD fpsm, DWORD date, const GSVector4i& fd, GSVector4i& test);
__forceinline void ReadPixel(int psm, int addr, GSVector4i& c) const;
__forceinline static void WritePixel(int psm, WORD* RESTRICT vm16, DWORD c);
__forceinline void WriteFrame(int fpsm, int rfb, GSVector4i* c, const GSVector4i& fd, const GSVector4i& fm, int addr, int fzm);
__forceinline void WriteZBuf(int zpsm, int ztst, const GSVector4i& z, const GSVector4i& zd, const GSVector4i& zm, int addr, int fzm);
template<DWORD fpsm, DWORD zpsm, DWORD ztst, DWORD iip>
void DrawScanline(int top, int left, int right, const GSVertexSW& v);
template<DWORD sel>
void DrawScanlineEx(int top, int left, int right, const GSVertexSW& v);
//
void DrawSolidRect(const GSVector4i& r, const GSVertexSW& v);
template<class T, bool masked>
void DrawSolidRectT(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m);
template<class T, bool masked>
__forceinline void FillRect(const GSVector4i* row, int* col, const GSVector4i& r, DWORD c, DWORD m);
template<class T, bool masked>
__forceinline void FillBlock(const GSVector4i* row, int* col, const GSVector4i& r, const GSVector4i& c, const GSVector4i& m);
protected:
GSState* m_state;
int m_id;
public:
GSDrawScanline(GSState* state, int id);
virtual ~GSDrawScanline();
// IDrawScanline
void BeginDraw(const GSRasterizerData* data, Functions* f);
void EndDraw(const GSRasterizerStats& stats);
void PrintStats() {m_ds.PrintStats();}
};

View File

@ -0,0 +1,115 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSLocalMemory.h"
#pragma pack(push, 1)
__declspec(align(16)) class GSDrawingContext
{
public:
GIFRegXYOFFSET XYOFFSET;
GIFRegTEX0 TEX0;
GIFRegTEX1 TEX1;
GIFRegTEX2 TEX2;
GIFRegCLAMP CLAMP;
GIFRegMIPTBP1 MIPTBP1;
GIFRegMIPTBP2 MIPTBP2;
GIFRegSCISSOR SCISSOR;
GIFRegALPHA ALPHA;
GIFRegTEST TEST;
GIFRegFBA FBA;
GIFRegFRAME FRAME;
GIFRegZBUF ZBUF;
__declspec(align(16)) struct
{
GSVector4i dx10;
GSVector4 dx9;
GSVector4 in;
GSVector4 ex;
} scissor;
GSDrawingContext()
{
Reset();
}
void Reset()
{
memset(&XYOFFSET, 0, sizeof(XYOFFSET));
memset(&TEX0, 0, sizeof(TEX0));
memset(&TEX1, 0, sizeof(TEX1));
memset(&TEX2, 0, sizeof(TEX2));
memset(&CLAMP, 0, sizeof(CLAMP));
memset(&MIPTBP1, 0, sizeof(MIPTBP1));
memset(&MIPTBP2, 0, sizeof(MIPTBP2));
memset(&SCISSOR, 0, sizeof(SCISSOR));
memset(&ALPHA, 0, sizeof(ALPHA));
memset(&TEST, 0, sizeof(TEST));
memset(&FBA, 0, sizeof(FBA));
memset(&FRAME, 0, sizeof(FRAME));
memset(&ZBUF, 0, sizeof(ZBUF));
}
void UpdateScissor()
{
scissor.dx10 = GSVector4i(
(int)((SCISSOR.SCAX0 << 4) + XYOFFSET.OFX),
(int)((SCISSOR.SCAY0 << 4) + XYOFFSET.OFY),
(int)((SCISSOR.SCAX1 << 4) + XYOFFSET.OFX),
(int)((SCISSOR.SCAY1 << 4) + XYOFFSET.OFY));
scissor.dx9 = GSVector4(scissor.dx10);
scissor.in = GSVector4(
(int)SCISSOR.SCAX0,
(int)SCISSOR.SCAY0,
(int)SCISSOR.SCAX1 + 1,
(int)SCISSOR.SCAY1 + 1);
scissor.ex = GSVector4i(
(int)SCISSOR.SCAX0,
(int)SCISSOR.SCAY0,
(int)SCISSOR.SCAX1,
(int)SCISSOR.SCAY1);
}
bool DepthRead() const
{
return TEST.ZTE && TEST.ZTST >= 2;
}
bool DepthWrite() const
{
if(TEST.ATE && TEST.ATST == ATST_NEVER && TEST.AFAIL != AFAIL_ZB_ONLY) // alpha test, all pixels fail, z buffer is not updated
{
return false;
}
return ZBUF.ZMSK == 0 && TEST.ZTE != 0; // ZTE == 0 is bug on the real hardware, write is blocked then
}
};
#pragma pack(pop)

View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#pragma pack(push, 1)
__declspec(align(16)) class GSDrawingEnvironment
{
public:
GIFRegPRIM PRIM;
GIFRegPRMODE PRMODE;
GIFRegPRMODECONT PRMODECONT;
GIFRegTEXCLUT TEXCLUT;
GIFRegSCANMSK SCANMSK;
GIFRegTEXA TEXA;
GIFRegFOGCOL FOGCOL;
GIFRegDIMX DIMX;
GIFRegDTHE DTHE;
GIFRegCOLCLAMP COLCLAMP;
GIFRegPABE PABE;
GIFRegBITBLTBUF BITBLTBUF;
GIFRegTRXDIR TRXDIR;
GIFRegTRXPOS TRXPOS;
GIFRegTRXREG TRXREG;
GIFRegTRXREG TRXREG2;
GSDrawingContext CTXT[2];
GSDrawingEnvironment()
{
}
void Reset()
{
memset(&PRIM, 0, sizeof(PRIM));
memset(&PRMODE, 0, sizeof(PRMODE));
memset(&PRMODECONT, 0, sizeof(PRMODECONT));
memset(&TEXCLUT, 0, sizeof(TEXCLUT));
memset(&SCANMSK, 0, sizeof(SCANMSK));
memset(&TEXA, 0, sizeof(TEXA));
memset(&FOGCOL, 0, sizeof(FOGCOL));
memset(&DIMX, 0, sizeof(DIMX));
memset(&DTHE, 0, sizeof(DTHE));
memset(&COLCLAMP, 0, sizeof(COLCLAMP));
memset(&PABE, 0, sizeof(PABE));
memset(&BITBLTBUF, 0, sizeof(BITBLTBUF));
memset(&TRXDIR, 0, sizeof(TRXDIR));
memset(&TRXPOS, 0, sizeof(TRXPOS));
memset(&TRXREG, 0, sizeof(TRXREG));
memset(&TRXREG2, 0, sizeof(TRXREG2));
CTXT[0].Reset();
CTXT[1].Reset();
}
};
#pragma pack(pop)

88
plugins/GSdx/GSDump.cpp Normal file
View File

@ -0,0 +1,88 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSDump.h"
GSDump::GSDump()
: m_fp(NULL)
{
}
GSDump::~GSDump()
{
if(m_fp)
{
fclose(m_fp);
}
}
void GSDump::Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs)
{
m_fp = _tfopen(fn, _T("wb"));
m_vsyncs = 0;
if(m_fp)
{
fwrite(&crc, 4, 1, m_fp);
fwrite(&fd.size, 4, 1, m_fp);
fwrite(fd.data, fd.size, 1, m_fp);
fwrite(regs, 0x2000, 1, m_fp);
}
}
void GSDump::Transfer(int index, BYTE* mem, size_t size)
{
if(m_fp && size > 0)
{
fputc(0, m_fp);
fputc(index, m_fp);
fwrite(&size, 4, 1, m_fp);
fwrite(mem, size, 1, m_fp);
}
}
void GSDump::ReadFIFO(UINT32 size)
{
if(m_fp && size > 0)
{
fputc(2, m_fp);
fwrite(&size, 4, 1, m_fp);
}
}
void GSDump::VSync(int field, bool last, const void* regs)
{
if(m_fp)
{
fputc(3, m_fp);
fwrite(regs, 0x2000, 1, m_fp);
fputc(1, m_fp);
fputc(field, m_fp);
if((++m_vsyncs & 1) == 0 && last)
{
fclose(m_fp);
m_fp = NULL;
}
}
}

59
plugins/GSdx/GSDump.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
/*
Dump file format:
- [crc/4] [state size/4] [state data/size] [PMODE/0x2000] [id/1] [data/?] .. [id/1] [data/?]
Transfer data (id == 0)
- [0/1] [path index/1] [size/4] [data/size]
VSync data (id == 1)
- [1/1] [field/1]
ReadFIFO2 data (id == 2)
- [2/1] [size/?]
Regs data (id == 3)
- [PMODE/0x2000]
*/
class GSDump
{
FILE* m_fp;
int m_vsyncs;
public:
GSDump();
virtual ~GSDump();
void Open(LPCTSTR fn, DWORD crc, const GSFreezeData& fd, const void* regs);
void ReadFIFO(UINT32 size);
void Transfer(int index, BYTE* mem, size_t size);
void VSync(int field, bool last, const void* regs);
operator bool() {return m_fp != NULL;}
};

View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSFunctionMap.h"

View File

@ -0,0 +1,161 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
struct GSRasterizerStats
{
__int64 ticks;
int prims, pixels;
GSRasterizerStats()
{
Reset();
}
void Reset()
{
ticks = 0;
pixels = prims = 0;
}
};
template<class T> class GSFunctionMap
{
protected:
struct ActivePtr
{
UINT64 frame, frames;
__int64 ticks, pixels;
T f;
};
CRBMap<DWORD, T> m_map;
CRBMap<DWORD, ActivePtr*> m_map_active;
ActivePtr* m_active;
virtual T GetDefaultFunction(DWORD sel) = 0;
public:
GSFunctionMap()
: m_active(NULL)
{
}
virtual ~GSFunctionMap()
{
POSITION pos = m_map_active.GetHeadPosition();
while(pos)
{
delete m_map_active.GetNextValue(pos);
}
m_map_active.RemoveAll();
}
void SetAt(DWORD sel, T f)
{
m_map.SetAt(sel, f);
}
T Lookup(DWORD sel)
{
m_active = NULL;
if(!m_map_active.Lookup(sel, m_active))
{
CRBMap<DWORD, T>::CPair* pair = m_map.Lookup(sel);
ActivePtr* p = new ActivePtr();
memset(p, 0, sizeof(*p));
p->frame = (UINT64)-1;
p->f = pair ? pair->m_value : GetDefaultFunction(sel);
m_map_active.SetAt(sel, p);
m_active = p;
}
return m_active->f;
}
void UpdateStats(const GSRasterizerStats& stats, UINT64 frame)
{
if(m_active)
{
if(m_active->frame != frame)
{
m_active->frame = frame;
m_active->frames++;
}
m_active->pixels += stats.pixels;
m_active->ticks += stats.ticks;
}
}
virtual void PrintStats()
{
__int64 ttpf = 0;
POSITION pos = m_map_active.GetHeadPosition();
while(pos)
{
ActivePtr* p = m_map_active.GetNextValue(pos);
if(p->frames)
{
ttpf += p->ticks / p->frames;
}
}
pos = m_map_active.GetHeadPosition();
while(pos)
{
DWORD sel;
ActivePtr* p;
m_map_active.GetNextAssoc(pos, sel, p);
if(p->frames > 0)
{
__int64 tpp = p->pixels > 0 ? p->ticks / p->pixels : 0;
__int64 tpf = p->frames > 0 ? p->ticks / p->frames : 0;
__int64 ppf = p->frames > 0 ? p->pixels / p->frames : 0;
printf("[%08x]%c %6.2f%% | %5.2f%% | f %4I64d | p %10I64d | tpp %4I64d | tpf %9I64d | ppf %7I64d\n",
sel, !m_map.Lookup(sel) ? '*' : ' ',
(float)(tpf * 10000 / 50000000) / 100,
(float)(tpf * 10000 / ttpf) / 100,
p->frames, p->pixels,
tpp, tpf, ppf);
}
}
}
};

File diff suppressed because it is too large Load Diff

1009
plugins/GSdx/GSLocalMemory.h Normal file

File diff suppressed because it is too large Load Diff

103
plugins/GSdx/GSPerfMon.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSPerfMon.h"
extern "C" unsigned __int64 __rdtsc();
GSPerfMon::GSPerfMon()
: m_total(0)
, m_begin(0)
, m_frame(0)
, m_lastframe(0)
, m_count(0)
{
memset(m_counters, 0, sizeof(m_counters));
memset(m_stats, 0, sizeof(m_stats));
memset(m_warnings, 0, sizeof(m_warnings));
}
void GSPerfMon::Put(counter_t c, double val)
{
if(c == Frame)
{
clock_t now = clock();
if(m_lastframe != 0)
{
m_counters[c] += now - m_lastframe;
}
m_lastframe = now;
m_frame++;
m_count++;
}
else
{
m_counters[c] += val;
}
}
void GSPerfMon::Update()
{
if(m_count > 0)
{
for(int i = 0; i < countof(m_counters); i++)
{
m_stats[i] = m_counters[i] / m_count;
}
m_count = 0;
}
memset(m_counters, 0, sizeof(m_counters));
}
void GSPerfMon::Start()
{
m_start = __rdtsc();
if(m_begin == 0)
{
m_begin = m_start;
}
}
void GSPerfMon::Stop()
{
if(m_start > 0)
{
m_total += __rdtsc() - m_start;
m_start = 0;
}
}
int GSPerfMon::CPU()
{
int percent = (int)(100 * m_total / (__rdtsc() - m_begin));
m_begin = 0;
m_start = 0;
m_total = 0;
return percent;
}

63
plugins/GSdx/GSPerfMon.h Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
class GSPerfMon
{
public:
enum counter_t {Frame, Prim, Draw, Swizzle, Unswizzle, Fillrate, Quad, CounterLast};
enum warning_t {DATE, PABE, ABE, COLCLAMP, DepthTexture, WarningLast};
protected:
double m_counters[CounterLast];
double m_stats[CounterLast];
bool m_warnings[WarningLast];
UINT64 m_begin, m_total, m_start, m_frame;
clock_t m_lastframe;
int m_count;
void Start();
void Stop();
friend class GSPerfMonAutoTimer;
public:
GSPerfMon();
void SetFrame(UINT64 frame) {m_frame = frame;}
UINT64 GetFrame() {return m_frame;}
void Put(counter_t c, double val = 0);
double Get(counter_t c) {return m_stats[c];}
void Put(warning_t c) {m_warnings[c] = true;}
bool Get(warning_t c) {bool b = m_warnings[c]; m_warnings[c] = false; return b;}
void Update();
int CPU();
};
class GSPerfMonAutoTimer
{
GSPerfMon* m_pm;
public:
GSPerfMonAutoTimer(GSPerfMon& pm) {(m_pm = &pm)->Start();}
~GSPerfMonAutoTimer() {m_pm->Stop();}
};

View File

@ -0,0 +1,726 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSRasterizer.h"
GSRasterizer::GSRasterizer(IDrawScanline* ds, int id, int threads)
: m_ds(ds)
, m_id(id)
, m_threads(threads)
{
}
GSRasterizer::~GSRasterizer()
{
delete m_ds;
}
void GSRasterizer::Draw(const GSRasterizerData* data)
{
m_dsf.sl = NULL;
m_dsf.sr = NULL;
m_dsf.sp = NULL;
m_ds->BeginDraw(data, &m_dsf);
const GSVector4i scissor = data->scissor;
const GSVertexSW* vertices = data->vertices;
const int count = data->count;
m_stats.Reset();
__int64 start = __rdtsc();
switch(data->primclass)
{
case GS_POINT_CLASS:
m_stats.prims = count;
for(int i = 0; i < count; i++) DrawPoint(&vertices[i], scissor);
break;
case GS_LINE_CLASS:
ASSERT(!(count & 1));
m_stats.prims = count / 2;
for(int i = 0; i < count; i += 2) DrawLine(&vertices[i], scissor);
break;
case GS_TRIANGLE_CLASS:
ASSERT(!(count % 3));
m_stats.prims = count / 3;
for(int i = 0; i < count; i += 3) DrawTriangle(&vertices[i], scissor);
break;
case GS_SPRITE_CLASS:
ASSERT(!(count & 1));
m_stats.prims = count / 2;
for(int i = 0; i < count; i += 2) DrawSprite(&vertices[i], scissor);
break;
default:
__assume(0);
}
m_stats.ticks = __rdtsc() - start;
m_ds->EndDraw(m_stats);
}
void GSRasterizer::GetStats(GSRasterizerStats& stats)
{
stats = m_stats;
}
void GSRasterizer::DrawPoint(const GSVertexSW* v, const GSVector4i& scissor)
{
// TODO: round to closest for point, prestep for line
GSVector4i p(v->p);
if(scissor.x <= p.x && p.x < scissor.z && scissor.y <= p.y && p.y < scissor.w)
{
if((p.y % m_threads) == m_id)
{
(m_ds->*m_dsf.sp)(v, *v);
(m_ds->*m_dsf.sl)(p.y, p.x, p.x + 1, *v);
m_stats.pixels++;
}
}
}
void GSRasterizer::DrawLine(const GSVertexSW* v, const GSVector4i& scissor)
{
GSVertexSW dv = v[1] - v[0];
GSVector4 dp = dv.p.abs();
GSVector4i dpi(dp);
if(dpi.y == 0)
{
if(dpi.x > 0)
{
// shortcut for horizontal lines
GSVector4 mask = (v[0].p > v[1].p).xxxx();
GSVertexSW l, dl;
l.p = v[0].p.blend8(v[1].p, mask);
l.t = v[0].t.blend8(v[1].t, mask);
l.c = v[0].c.blend8(v[1].c, mask);
GSVector4 r;
r = v[1].p.blend8(v[0].p, mask);
GSVector4i p(l.p);
if(scissor.y <= p.y && p.y < scissor.w)
{
GSVertexSW dscan = dv / dv.p.xxxx();
(m_ds->*m_dsf.sp)(v, dscan);
l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y
DrawTriangleSection(p.y, p.y + 1, l, dl, dscan, scissor);
}
}
return;
}
int i = dpi.x > dpi.y ? 0 : 1;
GSVertexSW edge = v[0];
GSVertexSW dedge = dv / dp.v[i];
// TODO: prestep + clip with the scissor
int steps = dpi.v[i];
while(steps-- > 0)
{
DrawPoint(&edge, scissor);
edge += dedge;
}
}
static const int s_abc[8][4] =
{
{0, 1, 2, 0},
{1, 0, 2, 0},
{0, 0, 0, 0},
{1, 2, 0, 0},
{0, 2, 1, 0},
{0, 0, 0, 0},
{2, 0, 1, 0},
{2, 1, 0, 0},
};
void GSRasterizer::DrawTriangle(const GSVertexSW* vertices, const GSVector4i& scissor)
{
GSVertexSW v[3];
GSVector4 aabb = vertices[0].p.yyyy(vertices[1].p);
GSVector4 bccb = vertices[1].p.yyyy(vertices[2].p).xzzx();
int i = (aabb > bccb).mask() & 7;
v[0] = vertices[s_abc[i][0]];
v[1] = vertices[s_abc[i][1]];
v[2] = vertices[s_abc[i][2]];
aabb = v[0].p.yyyy(v[1].p);
bccb = v[1].p.yyyy(v[2].p).xzzx();
i = (aabb == bccb).mask() & 7;
switch(i)
{
case 0: // a < b < c
DrawTriangleTopBottom(v, scissor);
break;
case 1: // a == b < c
DrawTriangleBottom(v, scissor);
break;
case 4: // a < b == c
DrawTriangleTop(v, scissor);
break;
case 7: // a == b == c
break;
default:
__assume(0);
}
}
void GSRasterizer::DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor)
{
GSVertexSW longest;
longest.p = v[2].p - v[1].p;
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
if(i & 2) return;
i &= 1;
GSVertexSW& l = v[0];
GSVector4& r = v[0].p;
GSVector4i tb(l.p.xyxy(v[2].p).ceil());
int top = tb.extract32<1>();
int bottom = tb.extract32<3>();
if(top < scissor.y) top = scissor.y;
if(bottom > scissor.w) bottom = scissor.w;
if(top >= bottom) return;
longest.t = v[2].t - v[1].t;
longest.c = v[2].c - v[1].c;
GSVertexSW dscan = longest * longest.p.xxxx().rcp();
GSVertexSW vl = v[2 - i] - l;
GSVector4 vr = v[1 + i].p - r;
GSVertexSW dl = vl / vl.p.yyyy();
GSVector4 dr = vr / vr.yyyy();
float py = (float)top - l.p.y;
l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y
dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y
if(py > 0) l += dl * py;
(m_ds->*m_dsf.sp)(v, dscan);
DrawTriangleSection(top, bottom, l, dl, dscan, scissor);
}
void GSRasterizer::DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor)
{
GSVertexSW longest;
longest.p = v[1].p - v[0].p;
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
if(i & 2) return;
i &= 1;
GSVertexSW& l = v[1 - i];
GSVector4& r = v[i].p;
GSVector4i tb(l.p.xyxy(v[2].p).ceil());
int top = tb.extract32<1>();
int bottom = tb.extract32<3>();
if(top < scissor.y) top = scissor.y;
if(bottom > scissor.w) bottom = scissor.w;
if(top >= bottom) return;
longest.t = v[1].t - v[0].t;
longest.c = v[1].c - v[0].c;
GSVertexSW dscan = longest * longest.p.xxxx().rcp();
GSVertexSW vl = v[2] - l;
GSVector4 vr = v[2].p - r;
GSVertexSW dl = vl / vl.p.yyyy();
GSVector4 dr = vr / vr.yyyy();
float py = (float)top - l.p.y;
l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y
dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y
if(py > 0) l += dl * py;
(m_ds->*m_dsf.sp)(v, dscan);
DrawTriangleSection(top, bottom, l, dl, dscan, scissor);
}
void GSRasterizer::DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scissor)
{
GSVertexSW dv[3];
dv[0] = v[1] - v[0];
dv[1] = v[2] - v[0];
GSVertexSW longest = v[0] + dv[1] * (dv[0].p / dv[1].p).yyyy() - v[1];
int i = (longest.p > GSVector4::zero()).upl(longest.p == GSVector4::zero()).mask();
if(i & 2) return;
i &= 1;
GSVertexSW dscan = longest * longest.p.xxxx().rcp();
(m_ds->*m_dsf.sp)(v, dscan);
GSVertexSW& l = v[0];
GSVector4 r = v[0].p;
GSVertexSW dl;
GSVector4 dr;
dl = dv[1 - i] / dv[1 - i].p.yyyy();
dr = dv[i].p / dv[i].p.yyyy();
GSVector4i tb(v[0].p.yyyy(v[1].p).xzyy(v[2].p).ceil());
int top = tb.x;
int bottom = tb.y;
if(top < scissor.y) top = scissor.y;
if(bottom > scissor.w) bottom = scissor.w;
float py = (float)top - l.p.y;
if(py > 0)
{
GSVector4 dy(py);
l += dl * dy;
r += dr * dy;
}
if(top < bottom)
{
DrawTriangleSection(top, bottom, l, dl, r, dr, dscan, scissor);
}
if(i)
{
l = v[1];
dv[2] = v[2] - v[1];
dl = dv[2] / dv[2].p.yyyy();
}
else
{
r = v[1].p;
dv[2].p = v[2].p - v[1].p;
dr = dv[2].p / dv[2].p.yyyy();
}
top = tb.y;
bottom = tb.z;
if(top < scissor.y) top = scissor.y;
if(bottom > scissor.w) bottom = scissor.w;
if(top < bottom)
{
py = (float)top - l.p.y;
if(py > 0) l += dl * py;
py = (float)top - r.y;
if(py > 0) r += dr * py;
l.p = l.p.upl(r).xyzw(l.p); // r.x => l.y
dl.p = dl.p.upl(dr).xyzw(dl.p); // dr.x => dl.y
DrawTriangleSection(top, bottom, l, dl, dscan, scissor);
}
}
void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, GSVector4& r, const GSVector4& dr, const GSVertexSW& dscan, const GSVector4i& scissor)
{
ASSERT(top < bottom);
while(1)
{
do
{
if((top % m_threads) == m_id)
{
GSVector4i lr(l.p.xyxy(r).ceil());
int left = lr.extract32<0>();
int right = lr.extract32<2>();
if(left < scissor.x) left = scissor.x;
if(right > scissor.z) right = scissor.z;
int pixels = right - left;
if(pixels > 0)
{
m_stats.pixels += pixels;
GSVertexSW scan;
float px = (float)left - l.p.x;
if(px > 0)
{
scan = l + dscan * px;
}
else
{
scan = l;
}
(m_ds->*m_dsf.sl)(top, left, right, scan);
}
}
}
while(0);
if(++top >= bottom) break;
l += dl;
r += dr;
}
}
void GSRasterizer::DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, const GSVertexSW& dscan, const GSVector4i& scissor)
{
ASSERT(top < bottom);
while(1)
{
do
{
if((top % m_threads) == m_id)
{
GSVector4i lr(l.p.ceil());
int left = lr.extract32<0>();
int right = lr.extract32<1>();
if(left < scissor.x) left = scissor.x;
if(right > scissor.z) right = scissor.z;
int pixels = right - left;
if(pixels > 0)
{
m_stats.pixels += pixels;
GSVertexSW scan;
float px = (float)left - l.p.x;
if(px > 0)
{
scan = l + dscan * px;
}
else
{
scan = l;
}
(m_ds->*m_dsf.sl)(top, left, right, scan);
}
}
}
while(0);
if(++top >= bottom) break;
l += dl;
}
}
void GSRasterizer::DrawSprite(const GSVertexSW* vertices, const GSVector4i& scissor)
{
GSVertexSW v[2];
GSVector4 mask = (vertices[0].p < vertices[1].p).xyzw(GSVector4::zero());
v[0].p = vertices[1].p.blend8(vertices[0].p, mask);
v[0].t = vertices[1].t.blend8(vertices[0].t, mask);
v[0].c = vertices[1].c;
v[1].p = vertices[0].p.blend8(vertices[1].p, mask);
v[1].t = vertices[0].t.blend8(vertices[1].t, mask);
GSVector4i r(v[0].p.xyxy(v[1].p).ceil());
int& top = r.y;
int& bottom = r.w;
int& left = r.x;
int& right = r.z;
#if _M_SSE >= 0x401
r = r.sat_i32(scissor);
if((r < r.zwzw()).mask() != 0x00ff) return;
#else
if(top < scissor.y) top = scissor.y;
if(bottom > scissor.w) bottom = scissor.w;
if(top >= bottom) return;
if(left < scissor.x) left = scissor.x;
if(right > scissor.z) right = scissor.z;
if(left >= right) return;
#endif
GSVertexSW scan = v[0];
if(m_dsf.sr)
{
if(m_id == 0)
{
(m_ds->*m_dsf.sr)(r, scan);
m_stats.pixels += (r.z - r.x) * (r.w - r.y);
}
return;
}
GSVector4 zero = GSVector4::zero();
GSVertexSW dedge, dscan;
dedge.p = zero;
dscan.p = zero;
dedge.c = zero;
dscan.c = zero;
GSVertexSW dv = v[1] - v[0];
dedge.t = (dv.t / dv.p.yyyy()).xyxy(zero).wyww();
dscan.t = (dv.t / dv.p.xxxx()).xyxy(zero).xwww();
if(scan.p.y < (float)top) scan.t += dedge.t * ((float)top - scan.p.y);
if(scan.p.x < (float)left) scan.t += dscan.t * ((float)left - scan.p.x);
(m_ds->*m_dsf.sp)(v, dscan);
for(; top < bottom; top++, scan.t += dedge.t)
{
if((top % m_threads) == m_id)
{
(m_ds->*m_dsf.sl)(top, left, right, scan);
m_stats.pixels += right - left;
}
}
}
//
GSRasterizerMT::GSRasterizerMT(IDrawScanline* ds, int id, int threads, long* sync)
: GSRasterizer(ds, id, threads)
, m_sync(sync)
, m_exit(false)
, m_ThreadId(0)
, m_hThread(NULL)
, m_data(NULL)
{
if(id > 0)
{
m_hThread = CreateThread(NULL, 0, StaticThreadProc, (LPVOID)this, 0, &m_ThreadId);
}
}
GSRasterizerMT::~GSRasterizerMT()
{
if(m_hThread != NULL)
{
m_exit = true;
if(WaitForSingleObject(m_hThread, 5000) != WAIT_OBJECT_0)
{
TerminateThread(m_hThread, 1);
}
CloseHandle(m_hThread);
}
}
void GSRasterizerMT::Draw(const GSRasterizerData* data)
{
if(m_id == 0)
{
__super::Draw(data);
}
else
{
m_data = data;
InterlockedBitTestAndSet(m_sync, m_id);
}
}
DWORD WINAPI GSRasterizerMT::StaticThreadProc(LPVOID lpParam)
{
return ((GSRasterizerMT*)lpParam)->ThreadProc();
}
DWORD GSRasterizerMT::ThreadProc()
{
// _mm_setcsr(MXCSR);
while(!m_exit)
{
if(*m_sync & (1 << m_id))
{
__super::Draw(m_data);
InterlockedBitTestAndReset(m_sync, m_id);
}
else
{
_mm_pause();
}
}
return 0;
}
//
GSRasterizerList::GSRasterizerList()
{
// get a whole cache line (twice the size for future cpus ;)
m_sync = (long*)_aligned_malloc(sizeof(*m_sync), 128);
*m_sync = 0;
}
GSRasterizerList::~GSRasterizerList()
{
_aligned_free(m_sync);
FreeRasterizers();
}
void GSRasterizerList::FreeRasterizers()
{
while(!IsEmpty())
{
delete RemoveHead();
}
}
void GSRasterizerList::Draw(const GSRasterizerData* data)
{
*m_sync = 0;
m_stats.Reset();
__int64 start = __rdtsc();
POSITION pos = GetTailPosition();
while(pos)
{
GetPrev(pos)->Draw(data);
}
while(*m_sync)
{
_mm_pause();
}
m_stats.ticks = __rdtsc() - start;
pos = GetHeadPosition();
while(pos)
{
GSRasterizerStats s;
GetNext(pos)->GetStats(s);
m_stats.pixels += s.pixels;
m_stats.prims = max(m_stats.prims, s.prims);
}
}
void GSRasterizerList::GetStats(GSRasterizerStats& stats)
{
stats = m_stats;
}
void GSRasterizerList::PrintStats()
{
if(!IsEmpty())
{
GetHead()->PrintStats();
}
}

153
plugins/GSdx/GSRasterizer.h Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSVertexSW.h"
#include "GSFunctionMap.h"
//
#define FAST_DRAWSCANLINE
__declspec(align(16)) class GSRasterizerData
{
public:
GSVector4i scissor;
GS_PRIM_CLASS primclass;
const GSVertexSW* vertices;
int count;
const void* param;
};
class IRasterizer
{
public:
virtual ~IRasterizer() {}
virtual void Draw(const GSRasterizerData* data) = 0;
virtual void GetStats(GSRasterizerStats& stats) = 0;
virtual void PrintStats() = 0;
};
class IDrawScanline
{
public:
typedef void (IDrawScanline::*DrawScanlinePtr)(int top, int left, int right, const GSVertexSW& v);
typedef void (IDrawScanline::*DrawSolidRectPtr)(const GSVector4i& r, const GSVertexSW& v);
typedef void (IDrawScanline::*SetupPrimPtr)(const GSVertexSW* vertices, const GSVertexSW& dscan);
struct Functions
{
DrawScanlinePtr sl;
DrawSolidRectPtr sr;
SetupPrimPtr sp;
};
virtual ~IDrawScanline() {}
virtual void BeginDraw(const GSRasterizerData* data, Functions* dsf) = 0;
virtual void EndDraw(const GSRasterizerStats& stats) = 0;
virtual void PrintStats() = 0;
};
class GSRasterizer : public IRasterizer
{
protected:
IDrawScanline* m_ds;
IDrawScanline::Functions m_dsf;
int m_id;
int m_threads;
GSRasterizerStats m_stats;
void DrawPoint(const GSVertexSW* v, const GSVector4i& scissor);
void DrawLine(const GSVertexSW* v, const GSVector4i& scissor);
void DrawTriangle(const GSVertexSW* v, const GSVector4i& scissor);
void DrawSprite(const GSVertexSW* v, const GSVector4i& scissor);
void DrawTriangleTop(GSVertexSW* v, const GSVector4i& scissor);
void DrawTriangleBottom(GSVertexSW* v, const GSVector4i& scissor);
void DrawTriangleTopBottom(GSVertexSW* v, const GSVector4i& scissor);
__forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, GSVector4& r, const GSVector4& dr, const GSVertexSW& dscan, const GSVector4i& scissor);
__forceinline void DrawTriangleSection(int top, int bottom, GSVertexSW& l, const GSVertexSW& dl, const GSVertexSW& dscan, const GSVector4i& scissor);
public:
GSRasterizer(IDrawScanline* ds, int id = 0, int threads = 0);
virtual ~GSRasterizer();
// IRasterizer
void Draw(const GSRasterizerData* data);
void GetStats(GSRasterizerStats& stats);
void PrintStats() {m_ds->PrintStats();}
};
class GSRasterizerMT : public GSRasterizer
{
long* m_sync;
bool m_exit;
DWORD m_ThreadId;
HANDLE m_hThread;
const GSRasterizerData* m_data;
static DWORD WINAPI StaticThreadProc(LPVOID lpParam);
DWORD ThreadProc();
public:
GSRasterizerMT(IDrawScanline* ds, int id, int threads, long* sync);
virtual ~GSRasterizerMT();
// IRasterizer
void Draw(const GSRasterizerData* data);
};
class GSRasterizerList : protected CAtlList<IRasterizer*>, public IRasterizer
{
long* m_sync;
GSRasterizerStats m_stats;
void FreeRasterizers();
public:
GSRasterizerList();
virtual ~GSRasterizerList();
template<class DS, class T> void Create(T* parent, int threads)
{
FreeRasterizers();
threads = max(threads, 1); // TODO: min(threads, number of cpu cores)
for(int i = 0; i < threads; i++)
{
AddTail(new GSRasterizerMT(new DS(parent, i), i, threads, m_sync));
}
}
// IRasterizer
void Draw(const GSRasterizerData* data);
void GetStats(GSRasterizerStats& stats);
void PrintStats();
};

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSRenderer.h"

594
plugins/GSdx/GSRenderer.h Normal file
View File

@ -0,0 +1,594 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSWnd.h"
#include "GSState.h"
#include "GSVertexList.h"
#include "GSSettingsDlg.h"
#include "GSCapture.h"
struct GSRendererSettings
{
int m_interlace;
int m_aspectratio;
int m_filter;
bool m_vsync;
bool m_nativeres;
};
class GSRendererBase : public GSState, protected GSRendererSettings
{
protected:
bool m_osd;
int m_field;
void ProcessWindowMessages()
{
MSG msg;
memset(&msg, 0, sizeof(msg));
while(msg.message != WM_QUIT && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(OnMessage(msg))
{
continue;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
virtual bool OnMessage(const MSG& msg)
{
if(msg.message == WM_KEYDOWN)
{
int step = (::GetAsyncKeyState(VK_SHIFT) & 0x8000) ? -1 : 1;
if(msg.wParam == VK_F5)
{
m_interlace = (m_interlace + 7 + step) % 7;
return true;
}
if(msg.wParam == VK_F6)
{
m_aspectratio = (m_aspectratio + 3 + step) % 3;
return true;
}
if(msg.wParam == VK_F7)
{
m_wnd.SetWindowText(_T("PCSX2"));
m_osd = !m_osd;
return true;
}
}
return false;
}
public:
GSWnd m_wnd;
public:
GSRendererBase(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
: GSState(base, mt, irq, nloophack)
, m_osd(true)
, m_field(0)
{
m_interlace = rs.m_interlace;
m_aspectratio = rs.m_aspectratio;
m_filter = rs.m_filter;
m_vsync = rs.m_vsync;
m_nativeres = rs.m_nativeres;
};
virtual bool Create(LPCTSTR title) = 0;
virtual void VSync(int field) = 0;
virtual bool MakeSnapshot(LPCTSTR path) = 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 baseline = INT_MAX;
for(int i = 0; i < 2; i++)
{
if(IsEnabled(i))
{
baseline = min(GetDisplayPos(i).y, baseline);
}
}
CSize fs(0, 0);
CSize ds(0, 0);
Texture st[2];
GSVector4 sr[2];
GSVector4 dr[2];
for(int i = 0; i < 2; i++)
{
if(IsEnabled(i) && GetOutput(i, st[i]))
{
CRect r = GetFrameRect(i);
// overscan hack
if(GetDisplaySize(i).cy > 512) // hmm
{
int y = GetDeviceSize(i).cy;
if(SMODE2->INT && SMODE2->FFMD) y /= 2;
r.bottom = r.top + y;
}
//
sr[i].x = st[i].m_scale.x * r.left / st[i].GetWidth();
sr[i].y = st[i].m_scale.y * r.top / st[i].GetHeight();
sr[i].z = st[i].m_scale.x * r.right / st[i].GetWidth();
sr[i].w = st[i].m_scale.y * r.bottom / st[i].GetHeight();
GSVector2 o;
o.x = 0;
o.y = 0;
CPoint p = GetDisplayPos(i);
if(p.y - baseline >= 4) // 2?
{
o.y = st[i].m_scale.y * (p.y - baseline);
}
if(SMODE2->INT && SMODE2->FFMD) o.y /= 2;
dr[i].x = o.x;
dr[i].y = o.y;
dr[i].z = o.x + st[i].m_scale.x * r.Width();
dr[i].w = o.y + st[i].m_scale.y * r.Height();
#ifdef _M_AMD64
// schrödinger's bug, fs will be trashed unless we access these values
CString str;
str.Format(_T("%d %f %f %f %f "), i, o.x, o.y, dr[i].z, dr[i].w);
//::MessageBox(NULL, str, _T(""), MB_OK);
#endif
fs.cx = max(fs.cx, (int)(dr[i].z + 0.5f));
fs.cy = max(fs.cy, (int)(dr[i].w + 0.5f));
}
}
ds.cx = fs.cx;
ds.cy = fs.cy;
if(SMODE2->INT && SMODE2->FFMD) ds.cy *= 2;
bool slbg = PMODE->SLBG;
bool mmod = PMODE->MMOD;
if(st[0] || st[1])
{
GSVector4 c;
c.r = (float)BGCOLOR->R / 255;
c.g = (float)BGCOLOR->G / 255;
c.b = (float)BGCOLOR->B / 255;
c.a = (float)PMODE->ALP / 255;
m_dev.Merge(st, sr, dr, fs, slbg, mmod, c);
if(SMODE2->INT && m_interlace > 0)
{
int field = 1 - ((m_interlace - 1) & 1);
int mode = (m_interlace - 1) >> 1;
if(!m_dev.Interlace(ds, m_field ^ field, mode, st[1].m_scale.y)) // st[1].m_scale.y
{
return false;
}
}
}
return true;
}
void DoCapture()
{
if(!m_capture.IsCapturing())
{
return;
}
CSize size = m_capture.GetSize();
Texture current;
m_dev.GetCurrent(current);
Texture offscreen;
if(m_dev.CopyOffscreen(current, GSVector4(0, 0, 1, 1), offscreen, size.cx, size.cy))
{
BYTE* bits = NULL;
int pitch = 0;
if(offscreen.Map(&bits, pitch))
{
m_capture.DeliverFrame(bits, pitch, m_dev.IsCurrentRGBA());
offscreen.Unmap();
}
m_dev.Recycle(offscreen);
}
}
virtual bool OnMessage(const MSG& msg)
{
if(msg.message == WM_KEYDOWN)
{
if(msg.wParam == VK_F12)
{
if(m_capture.IsCapturing())
{
m_capture.EndCapture();
}
else
{
m_capture.BeginCapture(GetFPS());
}
return true;
}
}
return __super::OnMessage(msg);
}
public:
Device m_dev;
bool m_psrr;
int s_n;
bool s_dump;
bool s_save;
bool s_savez;
GSCapture m_capture;
public:
GSRenderer(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr)
: GSRendererBase(base, mt, irq, nloophack, rs)
, m_psrr(psrr)
{
s_n = 0;
s_dump = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("dump"), 0);
s_save = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("save"), 0);
s_savez = !!AfxGetApp()->GetProfileInt(_T("Debug"), _T("savez"), 0);
}
bool Create(LPCTSTR title)
{
if(!m_wnd.Create(title))
{
return false;
}
if(!m_dev.Create(m_wnd, m_vsync))
{
return false;
}
Reset();
return true;
}
void VSync(int field)
{
// printf("VSYNC\n");
GSPerfMonAutoTimer pmat(m_perfmon);
m_field = !!field;
Flush();
m_perfmon.Put(GSPerfMon::Frame);
ProcessWindowMessages();
if(m_dump)
{
m_dump.VSync(m_field, !(::GetAsyncKeyState(VK_CONTROL) & 0x8000), PMODE);
}
if(!Merge()) return;
// osd
static UINT64 s_frame = 0;
static CString 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);
s_stats.Format(
_T("%I64d | %d x %d | %.2f fps (%d%%) | %s - %s | %s | %d/%d/%d | %d%% CPU | %.2f | %.2f"),
m_perfmon.GetFrame(), GetDisplaySize().cx, GetDisplaySize().cy, fps, (int)(100.0 * fps / GetFPS()),
SMODE2->INT ? (CString(_T("Interlaced ")) + (SMODE2->FFMD ? _T("(frame)") : _T("(field)"))) : _T("Progressive"),
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(_T("%s | %.2f mpps"), CString(s_stats), fps * fillrate / (1024 * 1024));
}
if(m_capture.IsCapturing())
{
s_stats += _T(" | Recording...");
}
if(m_perfmon.Get(GSPerfMon::COLCLAMP)) _tprintf(_T("*** NOT SUPPORTED: color wrap ***\n"));
if(m_perfmon.Get(GSPerfMon::PABE)) _tprintf(_T("*** NOT SUPPORTED: per pixel alpha blend ***\n"));
if(m_perfmon.Get(GSPerfMon::DATE)) _tprintf(_T("*** PERFORMANCE WARNING: destination alpha test used ***\n"));
if(m_perfmon.Get(GSPerfMon::ABE)) _tprintf(_T("*** NOT SUPPORTED: alpha blending mode ***\n"));
if(m_perfmon.Get(GSPerfMon::DepthTexture)) _tprintf(_T("*** NOT SUPPORTED: depth texture ***\n"));
m_wnd.SetWindowText(s_stats);
}
if(m_osd)
{
m_dev.Draw(s_stats + _T("\n\nF5: interlace mode\nF6: aspect ratio\nF7: OSD"));
}
if(m_frameskip)
{
return;
}
//
if(m_dev.IsLost())
{
ResetDevice();
}
//
CRect r;
m_wnd.GetClientRect(&r);
GSUtil::FitRect(r, m_aspectratio);
m_dev.Present(r);
DoCapture();
}
bool MakeSnapshot(LPCTSTR path)
{
CString fn;
fn.Format(_T("%s_%s"), path, CTime::GetCurrentTime().Format(_T("%Y%m%d%H%M%S")));
if((::GetAsyncKeyState(VK_SHIFT) & 0x8000) && !m_dump)
{
GSFreezeData fd;
fd.size = 0;
fd.data = NULL;
Freeze(&fd, true);
fd.data = new BYTE[fd.size];
Freeze(&fd, false);
m_dump.Open(fn + _T(".gs"), m_crc, fd, PMODE);
delete [] fd.data;
}
return m_dev.SaveCurrent(fn + _T(".bmp"));
}
virtual void MinMaxUV(int w, int h, CRect& r) {r = CRect(0, 0, w, h);}
virtual bool CanUpscale() {return !m_nativeres;}
};
template<class Device, class Vertex> class GSRendererT : public GSRenderer<Device>
{
protected:
Vertex* m_vertices;
int m_count;
int m_maxcount;
GSVertexList<Vertex> m_vl;
void Reset()
{
m_count = 0;
m_vl.RemoveAll();
__super::Reset();
}
void ResetPrim()
{
m_vl.RemoveAll();
}
void FlushPrim()
{
if(m_count > 0)
{
/*
TRACE(_T("[%d] Draw f %05x (%d) z %05x (%d %d %d %d) t %05x %05x (%d)\n"),
(int)m_perfmon.GetFrame(),
(int)m_context->FRAME.Block(),
(int)m_context->FRAME.PSM,
(int)m_context->ZBUF.Block(),
(int)m_context->ZBUF.PSM,
m_context->TEST.ZTE,
m_context->TEST.ZTST,
m_context->ZBUF.ZMSK,
PRIM->TME ? (int)m_context->TEX0.TBP0 : 0xfffff,
PRIM->TME && m_context->TEX0.PSM > PSM_PSMCT16S ? (int)m_context->TEX0.CBP : 0xfffff,
PRIM->TME ? (int)m_context->TEX0.PSM : 0xff);
*/
if(GSUtil::EncodePSM(m_context->FRAME.PSM) != 3 && GSUtil::EncodePSM(m_context->ZBUF.PSM) != 3)
{
// FIXME: berserk fpsm = 27 (8H)
Draw();
}
m_count = 0;
}
}
void GrowVertexBuffer()
{
m_maxcount = max(10000, m_maxcount * 3/2);
m_vertices = (Vertex*)_aligned_realloc(m_vertices, sizeof(Vertex) * m_maxcount, 16);
m_maxcount -= 100;
}
template<DWORD prim> __forceinline Vertex* DrawingKick(bool skip, DWORD& count)
{
switch(prim)
{
case GS_POINTLIST: count = 1; break;
case GS_LINELIST: count = 2; break;
case GS_LINESTRIP: count = 2; break;
case GS_TRIANGLELIST: count = 3; break;
case GS_TRIANGLESTRIP: count = 3; break;
case GS_TRIANGLEFAN: count = 3; break;
case GS_SPRITE: count = 2; break;
case GS_INVALID: count = 1; break;
default: __assume(0);
}
if(m_vl.GetCount() < count)
{
return NULL;
}
if(m_count >= m_maxcount)
{
GrowVertexBuffer();
}
Vertex* v = &m_vertices[m_count];
switch(prim)
{
case GS_POINTLIST:
m_vl.GetAt(0, v[0]);
m_vl.RemoveAll();
break;
case GS_LINELIST:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.RemoveAll();
break;
case GS_LINESTRIP:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.RemoveAt(0, 1);
break;
case GS_TRIANGLELIST:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.GetAt(2, v[2]);
m_vl.RemoveAll();
break;
case GS_TRIANGLESTRIP:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.GetAt(2, v[2]);
m_vl.RemoveAt(0, 2);
break;
case GS_TRIANGLEFAN:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.GetAt(2, v[2]);
m_vl.RemoveAt(1, 1);
break;
case GS_SPRITE:
m_vl.GetAt(0, v[0]);
m_vl.GetAt(1, v[1]);
m_vl.RemoveAll();
break;
case GS_INVALID:
ASSERT(0);
m_vl.RemoveAll();
return NULL;
default:
__assume(0);
}
return !skip ? v : NULL;
}
virtual void Draw() = 0;
public:
GSRendererT(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr = true)
: GSRenderer<Device>(base, mt, irq, nloophack, rs, psrr)
, m_count(0)
, m_maxcount(0)
, m_vertices(NULL)
{
}
~GSRendererT()
{
if(m_vertices) _aligned_free(m_vertices);
}
};

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRendererHW.h"

633
plugins/GSdx/GSRendererHW.h Normal file
View File

@ -0,0 +1,633 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRenderer.h"
#include "GSTextureCache.h"
#include "GSCrc.h"
template<class Device, class Vertex, class TextureCache>
class GSRendererHW : public GSRendererT<Device, Vertex>
{
TextureCache* m_tc;
int m_width;
int m_height;
int m_skip;
bool m_reset;
protected:
void Reset()
{
// TODO: GSreset can come from the main thread too => crash
// m_tc->RemoveAll();
m_reset = true;
__super::Reset();
}
void MinMaxUV(int w, int h, CRect& r)
{
int wms = m_context->CLAMP.WMS;
int wmt = m_context->CLAMP.WMT;
int minu = (int)m_context->CLAMP.MINU;
int minv = (int)m_context->CLAMP.MINV;
int maxu = (int)m_context->CLAMP.MAXU;
int maxv = (int)m_context->CLAMP.MAXV;
GSVector4i vr = GSVector4i(0, 0, w, h);
GSVector4i wm[3];
if(wms + wmt < 6)
{
GSVector4 mm;
if(m_count < 100)
{
Vertex* v = m_vertices;
GSVector4 minv(+1e10f);
GSVector4 maxv(-1e10f);
int i = 0;
if(PRIM->FST)
{
for(int j = m_count - 3; i < j; i += 4)
{
GSVector4 v0 = GSVector4(v[i + 0].m128[0]);
GSVector4 v1 = GSVector4(v[i + 1].m128[0]);
GSVector4 v2 = GSVector4(v[i + 2].m128[0]);
GSVector4 v3 = GSVector4(v[i + 3].m128[0]);
minv = minv.minv((v0.minv(v1)).minv(v2.minv(v3)));
maxv = maxv.maxv((v0.maxv(v1)).maxv(v2.maxv(v3)));
}
for(int j = m_count; i < j; i++)
{
GSVector4 v0 = GSVector4(v[i + 0].m128[0]);
minv = minv.minv(v0);
maxv = maxv.maxv(v0);
}
mm = minv.xyxy(maxv) * GSVector4(16 << m_context->TEX0.TW, 16 << m_context->TEX0.TH, 16 << m_context->TEX0.TW, 16 << m_context->TEX0.TH).rcpnr();
}
else
{
/*
for(int j = m_count - 3; i < j; i += 4)
{
GSVector4 v0 = GSVector4(v[i + 0].m128[0]) / GSVector4(v[i + 0].GetQ());
GSVector4 v1 = GSVector4(v[i + 1].m128[0]) / GSVector4(v[i + 1].GetQ());
GSVector4 v2 = GSVector4(v[i + 2].m128[0]) / GSVector4(v[i + 2].GetQ());
GSVector4 v3 = GSVector4(v[i + 3].m128[0]) / GSVector4(v[i + 3].GetQ());
minv = minv.minv((v0.minv(v1)).minv(v2.minv(v3)));
maxv = maxv.maxv((v0.maxv(v1)).maxv(v2.maxv(v3)));
}
for(int j = m_count; i < j; i++)
{
GSVector4 v0 = GSVector4(v[i + 0].m128[0]) / GSVector4(v[i + 0].GetQ());;
minv = minv.minv(v0);
maxv = maxv.maxv(v0);
}
mm = minv.xyxy(maxv);
*/
// just can't beat the compiler generated scalar sse code with packed div or rcp
mm.x = mm.y = +1e10;
mm.z = mm.w = -1e10;
for(int j = m_count; i < j; i++)
{
float w = 1.0f / v[i].GetQ();
float x = v[i].t.x * w;
if(x < mm.x) mm.x = x;
if(x > mm.z) mm.z = x;
float y = v[i].t.y * w;
if(y < mm.y) mm.y = y;
if(y > mm.w) mm.w = y;
}
}
}
else
{
mm = GSVector4(0.0f, 0.0f, 1.0f, 1.0f);
}
GSVector4 v0 = GSVector4(vr);
GSVector4 v1 = v0.zwzw();
GSVector4 mmf = mm.floor();
GSVector4 mask = mmf.xyxy() == mmf.zwzw();
wm[0] = GSVector4i(v0.blend8((mm - mmf) * v1, mask));
mm *= v1;
wm[1] = GSVector4i(mm.sat(GSVector4::zero(), v1));
wm[2] = GSVector4i(mm.sat(GSVector4(minu, minv, maxu, maxv)));
}
GSVector4i v;
switch(wms)
{
case CLAMP_REPEAT:
v = wm[0];
if(v.x == 0 && v.z != w) v.z = w; // FIXME
vr.x = v.x;
vr.z = v.z;
break;
case CLAMP_CLAMP:
case CLAMP_REGION_CLAMP:
v = wm[wms];
if(v.x > v.z) v.x = v.z;
vr.x = v.x;
vr.z = v.z;
break;
case CLAMP_REGION_REPEAT:
if(m_psrr) {vr.x = maxu; vr.z = vr.x + (minu + 1);}
//else {vr.x = 0; vr.z = w;}
break;
default:
__assume(0);
}
switch(wmt)
{
case CLAMP_REPEAT:
v = wm[0];
if(v.y == 0 && v.w != h) v.w = h; // FIXME
vr.y = v.y;
vr.w = v.w;
break;
case CLAMP_CLAMP:
case CLAMP_REGION_CLAMP:
v = wm[wmt];
if(v.y > v.w) v.y = v.w;
vr.y = v.y;
vr.w = v.w;
break;
case CLAMP_REGION_REPEAT:
if(m_psrr) {vr.y = maxv; vr.w = vr.y + (minv + 1);}
//else {r.y = 0; r.w = w;}
break;
default:
__assume(0);
}
r = vr;
r.InflateRect(1, 1); // one more pixel because of bilinear filtering
CSize bs = GSLocalMemory::m_psm[m_context->TEX0.PSM].bs;
CSize bsm(bs.cx - 1, bs.cy - 1);
r.left = max(r.left & ~bsm.cx, 0);
r.right = min((r.right + bsm.cx) & ~bsm.cx, w);
r.top = max(r.top & ~bsm.cy, 0);
r.bottom = min((r.bottom + bsm.cy) & ~bsm.cy, h);
}
void VSync(int field)
{
__super::VSync(field);
m_tc->IncAge();
m_skip = 0;
if(m_reset)
{
m_tc->RemoveAll();
m_reset = false;
}
}
void ResetDevice()
{
m_tc->RemoveAll();
}
bool GetOutput(int i, Texture& t)
{
GIFRegTEX0 TEX0;
TEX0.TBP0 = DISPFB[i]->Block();
TEX0.TBW = DISPFB[i]->FBW;
TEX0.PSM = DISPFB[i]->PSM;
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))
{
t = rt->m_texture;
if(s_dump)
{
CString str;
str.Format(_T("c:\\temp2\\_%05d_f%I64d_fr%d_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM);
if(s_save) rt->m_texture.Save(str);
}
return true;
}
return false;
}
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r)
{
TRACE(_T("[%d] InvalidateVideoMem %d,%d - %d,%d %05x (%d)\n"), (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.DBP, (int)BITBLTBUF.DPSM);
m_tc->InvalidateVideoMem(BITBLTBUF, r);
}
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r)
{
TRACE(_T("[%d] InvalidateLocalMem %d,%d - %d,%d %05x (%d)\n"), (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.SBP, (int)BITBLTBUF.SPSM);
m_tc->InvalidateLocalMem(BITBLTBUF, r);
}
void Draw()
{
if(IsBadFrame(m_skip))
{
return;
}
GSDrawingEnvironment& env = m_env;
GSDrawingContext* context = m_context;
GIFRegTEX0 TEX0;
TEX0.TBP0 = context->FRAME.Block();
TEX0.TBW = context->FRAME.FBW;
TEX0.PSM = context->FRAME.PSM;
GSTextureCache<Device>::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<Device>::GSTexture* tex = NULL;
if(PRIM->TME)
{
tex = m_tc->GetTexture();
if(!tex) return;
}
if(s_dump)
{
CString str;
str.Format(_T("c:\\temp2\\_%05d_f%I64d_tex_%05x_%d_%d%d_%02x_%02x_%02x_%02x.dds"),
s_n++, m_perfmon.GetFrame(), (int)context->TEX0.TBP0, (int)context->TEX0.PSM,
(int)context->CLAMP.WMS, (int)context->CLAMP.WMT,
(int)context->CLAMP.MINU, (int)context->CLAMP.MAXU,
(int)context->CLAMP.MINV, (int)context->CLAMP.MAXV);
if(PRIM->TME) if(s_save) tex->m_texture.Save(str, true);
str.Format(_T("c:\\temp2\\_%05d_f%I64d_tpx_%05x_%d.dds"), s_n-1, m_perfmon.GetFrame(), context->TEX0.CBP, context->TEX0.CPSM);
if(PRIM->TME && tex->m_palette) if(s_save) tex->m_palette.Save(str, true);
str.Format(_T("c:\\temp2\\_%05d_f%I64d_rt0_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), context->FRAME.Block(), context->FRAME.PSM);
if(s_save) rt->m_texture.Save(str);
str.Format(_T("c:\\temp2\\_%05d_f%I64d_rz0_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), context->ZBUF.Block(), context->ZBUF.PSM);
if(s_savez) ds->m_texture.Save(str);
// if(s_savez) m_dev.SaveToFileD32S8X24(ds->m_texture, str); // TODO
// if(s_savez) m_dev.SaveToFileD24S8(ds->m_texture, str); // TODO
}
int prim = PRIM->PRIM;
if(!OverrideInput(prim, rt->m_texture, ds->m_texture, tex ? &tex->m_texture : NULL))
{
return;
}
Draw(prim, rt->m_texture, ds->m_texture, tex);
OverrideOutput();
m_tc->InvalidateTextures(context->FRAME, context->ZBUF);
if(s_dump)
{
CString str;
str.Format(_T("c:\\temp2\\_%05d_f%I64d_rt1_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), context->FRAME.Block(), context->FRAME.PSM);
if(s_save) rt->m_texture.Save(str);
str.Format(_T("c:\\temp2\\_%05d_f%I64d_rz1_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), context->ZBUF.Block(), context->ZBUF.PSM);
if(s_savez) ds->m_texture.Save(str);
// if(s_savez) m_dev.SaveToFileD32S8X24(ds->m_texture, str); // TODO
}
}
virtual void Draw(int prim, Texture& rt, Texture& ds, typename GSTextureCache<Device>::GSTexture* tex) = 0;
virtual bool OverrideInput(int& prim, Texture& rt, Texture& ds, Texture* t)
{
#pragma region ffxii pal video conversion
if(m_game.title == CRC::FFXII && m_game.region == CRC::EU)
{
static DWORD* video = NULL;
static bool ok = false;
if(prim == GS_POINTLIST && m_count >= 448*448 && m_count <= 448*512)
{
// incoming pixels are stored in columns, one column is 16x512, total res 448x512 or 448x454
if(!video) video = new DWORD[512*512];
for(int x = 0, i = 0, rows = m_count / 448; x < 448; x += 16)
{
DWORD* dst = &video[x];
for(int y = 0; y < rows; y++, dst += 512)
{
for(int j = 0; j < 16; j++, i++)
{
dst[j] = m_vertices[i].c0;
}
}
}
ok = true;
return false;
}
else if(prim == GS_LINELIST && m_count == 512*2 && ok)
{
// normally, this step would copy the video onto screen with 512 texture mapped horizontal lines,
// but we use the stored video data to create a new texture, and replace the lines with two triangles
ok = false;
m_dev.CreateTexture(*t, 512, 512);
t->Update(CRect(0, 0, 448, 512), video, 512*4);
m_vertices[0] = m_vertices[0];
m_vertices[1] = m_vertices[1];
m_vertices[2] = m_vertices[m_count - 2];
m_vertices[3] = m_vertices[1];
m_vertices[4] = m_vertices[2];
m_vertices[5] = m_vertices[m_count - 1];
prim = GS_TRIANGLELIST;
m_count = 6;
return true;
}
}
#pragma endregion
#pragma region ffx random battle transition (z buffer written directly, clear it now)
if(m_game.title == CRC::FFX)
{
DWORD FBP = m_context->FRAME.Block();
DWORD ZBP = m_context->ZBUF.Block();
DWORD TBP = m_context->TEX0.TBP0;
if((FBP == 0x00d00 || FBP == 0x00000) && ZBP == 0x02100 && PRIM->TME && TBP == 0x01a00 && m_context->TEX0.PSM == PSM_PSMCT16S)
{
m_dev.ClearDepth(ds, 0);
}
return true;
}
#pragma endregion
#pragma region metal slug missing red channel fix
if(m_game.title == CRC::MetalSlug6)
{
for(int i = 0, j = m_count; i < j; i++)
{
if(m_vertices[i].r == 0 && m_vertices[i].g != 0 && m_vertices[i].b != 0)
{
m_vertices[i].r = (m_vertices[i].g + m_vertices[i].b) / 2;
}
}
return true;
}
#pragma endregion
#pragma region tomoyo after, clannad (palette uploaded in a point list, pure genius...)
if(m_game.title == CRC::TomoyoAfter || m_game.title == CRC::Clannad)
{
if(prim == GS_POINTLIST && !PRIM->TME)
{
DWORD bp = m_context->FRAME.Block();
DWORD bw = m_context->FRAME.FBW;
if(bp >= 0x03f40 && (bp & 0x1f) == 0)
{
if(m_count == 16)
{
for(int i = 0; i < 16; i++)
{
m_vertices[i].a = m_vertices[i].a >= 0x80 ? 0xff : m_vertices[i].a * 2;
m_mem.WritePixel32(i & 7, i >> 3, m_vertices[i].c0, bp, bw);
}
m_mem.m_clut.Invalidate();
return false;
}
else if(m_count == 256)
{
for(int i = 0; i < 256; i++)
{
m_vertices[i].a = m_vertices[i].a >= 0x80 ? 0xff : m_vertices[i].a * 2;
m_mem.WritePixel32(i & 15, i >> 4, m_vertices[i].c0, bp, bw);
}
m_mem.m_clut.Invalidate();
return false;
}
else
{
ASSERT(0);
}
}
}
return true;
}
#pragma endregion
return true;
}
virtual void OverrideOutput()
{
#pragma region dbzbt2 palette readback (cannot detect yet, when fetching the texture later)
if(m_game.title == CRC::DBZBT2)
{
DWORD FBP = m_context->FRAME.Block();
DWORD TBP0 = m_context->TEX0.TBP0;
if(PRIM->TME && (FBP == 0x03c00 && TBP0 == 0x03c80 || FBP == 0x03ac0 && TBP0 == 0x03b40))
{
GIFRegBITBLTBUF BITBLTBUF;
BITBLTBUF.SBP = FBP;
BITBLTBUF.SBW = 1;
BITBLTBUF.SPSM = PSM_PSMCT32;
InvalidateLocalMem(BITBLTBUF, CRect(0, 0, 64, 64));
}
}
#pragma endregion
#pragma region MajokkoALaMode2 palette readback
if(m_game.title == CRC::MajokkoALaMode2)
{
DWORD FBP = m_context->FRAME.Block();
if(!PRIM->TME && FBP == 0x03f40)
{
GIFRegBITBLTBUF BITBLTBUF;
BITBLTBUF.SBP = FBP;
BITBLTBUF.SBW = 1;
BITBLTBUF.SPSM = PSM_PSMCT32;
InvalidateLocalMem(BITBLTBUF, CRect(0, 0, 16, 16));
}
}
#pragma endregion
}
bool CanUpscale()
{
#pragma region dbzbt2 palette should stay 64 x 64
if(m_game.title == CRC::DBZBT2)
{
DWORD FBP = m_context->FRAME.Block();
if(FBP == 0x03c00 || FBP == 0x03ac0)
{
return false;
}
}
#pragma endregion
#pragma region MajokkoALaMode2 palette should stay 16 x 16
if(m_game.title == CRC::MajokkoALaMode2)
{
DWORD FBP = m_context->FRAME.Block();
if(FBP == 0x03f40)
{
return false;
}
}
#pragma endregion
#pragma region TalesOfAbyss full image blur and brightening
if(m_game.title == CRC::TalesOfAbyss)
{
DWORD FBP = m_context->FRAME.Block();
if(FBP == 0x036e0 || FBP == 0x03560 || FBP == 0x038e0)
{
return false;
}
}
#pragma endregion
return __super::CanUpscale();
}
public:
GSRendererHW(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, bool psrr)
: GSRendererT<Device, Vertex>(base, mt, irq, nloophack, rs, psrr)
, m_width(1024)
, m_height(1024)
, m_skip(0)
, m_reset(false)
{
if(!m_nativeres)
{
m_width = AfxGetApp()->GetProfileInt(_T("Settings"), _T("resx"), m_width);
m_height = AfxGetApp()->GetProfileInt(_T("Settings"), _T("resy"), m_height);
}
m_tc = new TextureCache(this);
}
virtual ~GSRendererHW()
{
delete m_tc;
}
void SetGameCRC(DWORD crc, int options)
{
__super::SetGameCRC(crc, options);
if(m_game.title == CRC::JackieChanAdv)
{
m_width = 1280; // TODO: uses a 1280px wide 16 bit render target, but this only fixes half of the problem
}
}
};

View File

@ -0,0 +1,586 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRendererHW10.h"
#include "GSCrc.h"
#include "resource.h"
GSRendererHW10::GSRendererHW10(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
: GSRendererHW<Device, Vertex, TextureCache>(base, mt, irq, nloophack, rs, true)
{
InitVertexKick<GSRendererHW10>();
}
bool GSRendererHW10::Create(LPCTSTR title)
{
if(!__super::Create(title))
return false;
if(!m_tfx.Create(&m_dev))
return false;
//
D3D10_DEPTH_STENCIL_DESC dsd;
memset(&dsd, 0, sizeof(dsd));
dsd.DepthEnable = false;
dsd.StencilEnable = true;
dsd.StencilReadMask = 1;
dsd.StencilWriteMask = 1;
dsd.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
dsd.FrontFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE;
dsd.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
dsd.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
dsd.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
dsd.BackFace.StencilPassOp = D3D10_STENCIL_OP_REPLACE;
dsd.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
dsd.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
m_dev->CreateDepthStencilState(&dsd, &m_date.dss);
D3D10_BLEND_DESC bd;
memset(&bd, 0, sizeof(bd));
m_dev->CreateBlendState(&bd, &m_date.bs);
//
return true;
}
template<DWORD prim, DWORD tme, DWORD fst>
void GSRendererHW10::VertexKick(bool skip)
{
Vertex& dst = m_vl.AddTail();
dst.m128i[0] = m_v.m128i[0];
dst.m128i[1] = m_v.m128i[1];
if(tme && fst)
{
GSVector4::storel(&dst.ST, m_v.GetUV());
}
DWORD count = 0;
if(Vertex* v = DrawingKick<prim>(skip, count))
{
GSVector4i scissor = m_context->scissor.dx10;
#if _M_SSE >= 0x401
GSVector4i pmin, pmax, v0, v1, v2;
switch(prim)
{
case GS_POINTLIST:
v0 = GSVector4i::load((int)v[0].p.xy).upl16();
pmin = v0;
pmax = v0;
break;
case GS_LINELIST:
case GS_LINESTRIP:
case GS_SPRITE:
v0 = GSVector4i::load((int)v[0].p.xy);
v1 = GSVector4i::load((int)v[1].p.xy);
pmin = v0.min_u16(v1).upl16();
pmax = v0.max_u16(v1).upl16();
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
v0 = GSVector4i::load((int)v[0].p.xy);
v1 = GSVector4i::load((int)v[1].p.xy);
v2 = GSVector4i::load((int)v[2].p.xy);
pmin = v0.min_u16(v1).min_u16(v2).upl16();
pmax = v0.max_u16(v1).max_u16(v2).upl16();
break;
}
GSVector4i test = (pmax < scissor) | (pmin > scissor.zwxy());
if(test.mask() & 0xff)
{
return;
}
#else
switch(prim)
{
case GS_POINTLIST:
if(v[0].p.x < scissor.x
|| v[0].p.x > scissor.z
|| v[0].p.y < scissor.y
|| v[0].p.y > scissor.w)
{
return;
}
break;
case GS_LINELIST:
case GS_LINESTRIP:
case GS_SPRITE:
if(v[0].p.x < scissor.x && v[1].p.x < scissor.x
|| v[0].p.x > scissor.z && v[1].p.x > scissor.z
|| v[0].p.y < scissor.y && v[1].p.y < scissor.y
|| v[0].p.y > scissor.w && v[1].p.y > scissor.w)
{
return;
}
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
if(v[0].p.x < scissor.x && v[1].p.x < scissor.x && v[2].p.x < scissor.x
|| v[0].p.x > scissor.z && v[1].p.x > scissor.z && v[2].p.x > scissor.z
|| v[0].p.y < scissor.y && v[1].p.y < scissor.y && v[2].p.y < scissor.y
|| v[0].p.y > scissor.w && v[1].p.y > scissor.w && v[2].p.y > scissor.w)
{
return;
}
break;
}
#endif
m_count += count;
}
}
void GSRendererHW10::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex)
{
GSDrawingEnvironment& env = m_env;
GSDrawingContext* context = m_context;
/*
if(s_dump)
{
TRACE(_T("\n"));
TRACE(_T("PRIM = %d, ZMSK = %d, ZTE = %d, ZTST = %d, ATE = %d, ATST = %d, AFAIL = %d, AREF = %02x\n"),
PRIM->PRIM, context->ZBUF.ZMSK,
context->TEST.ZTE, context->TEST.ZTST,
context->TEST.ATE, context->TEST.ATST, context->TEST.AFAIL, context->TEST.AREF);
for(int i = 0; i < m_count; i++)
{
TRACE(_T("[%d] %3.0f %3.0f %3.0f %3.0f\n"), i, (float)m_vertices[i].p.x / 16, (float)m_vertices[i].p.y / 16, (float)m_vertices[i].p.z, (float)m_vertices[i].a);
}
}
*/
D3D10_PRIMITIVE_TOPOLOGY topology;
int prims = 0;
switch(prim)
{
case GS_POINTLIST:
topology = D3D10_PRIMITIVE_TOPOLOGY_POINTLIST;
prims = m_count;
break;
case GS_LINELIST:
case GS_LINESTRIP:
case GS_SPRITE:
topology = D3D10_PRIMITIVE_TOPOLOGY_LINELIST;
prims = m_count / 2;
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
topology = D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
prims = m_count / 3;
break;
default:
__assume(0);
}
m_perfmon.Put(GSPerfMon::Prim, prims);
m_perfmon.Put(GSPerfMon::Draw, 1);
// date
SetupDATE(rt, ds);
//
m_dev.BeginScene();
// om
GSTextureFX10::OMDepthStencilSelector om_dssel;
om_dssel.zte = context->TEST.ZTE;
om_dssel.ztst = context->TEST.ZTST;
om_dssel.zwe = !context->ZBUF.ZMSK;
om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0;
GSTextureFX10::OMBlendSelector om_bsel;
om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1;
om_bsel.a = context->ALPHA.A;
om_bsel.b = context->ALPHA.B;
om_bsel.c = context->ALPHA.C;
om_bsel.d = context->ALPHA.D;
om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff;
om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00;
om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000;
om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000;
float bf = (float)(int)context->ALPHA.FIX / 0x80;
// vs
GSTextureFX10::VSSelector vs_sel;
vs_sel.bpp = 0;
vs_sel.bppz = 0;
vs_sel.tme = PRIM->TME;
vs_sel.fst = PRIM->FST;
vs_sel.prim = prim;
if(tex)
{
vs_sel.bpp = tex->m_bpp2;
}
if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe)
{
if(context->ZBUF.PSM == PSM_PSMZ24)
{
if(WrapZ(0xffffff))
{
vs_sel.bppz = 1;
om_dssel.ztst = 1;
}
}
else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S)
{
if(WrapZ(0xffff))
{
vs_sel.bppz = 2;
om_dssel.ztst = 1;
}
}
}
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 ox = (float)(int)context->XYOFFSET.OFX;
float oy = (float)(int)context->XYOFFSET.OFY;
vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f);
vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f);
vs_cb.TextureScale = GSVector2(1.0f, 1.0f);
if(PRIM->TME && PRIM->FST)
{
vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW);
vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH);
}
// gs
GSTextureFX10::GSSelector gs_sel;
gs_sel.iip = PRIM->IIP;
gs_sel.prim = GSUtil::GetPrimClass(prim);
// ps
GSTextureFX10::PSSelector ps_sel;
ps_sel.fst = PRIM->FST;
ps_sel.wms = context->CLAMP.WMS;
ps_sel.wmt = context->CLAMP.WMT;
ps_sel.bpp = 0;
ps_sel.aem = env.TEXA.AEM;
ps_sel.tfx = context->TEX0.TFX;
ps_sel.tcc = context->TEX0.TCC;
ps_sel.ate = context->TEST.ATE;
ps_sel.atst = context->TEST.ATST;
ps_sel.fog = PRIM->FGE;
ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1;
ps_sel.fba = context->FBA.FBA;
ps_sel.aout = context->FRAME.PSM == PSM_PSMCT16 || context->FRAME.PSM == PSM_PSMCT16S || (context->FRAME.FBMSK & 0xff000000) == 0x7f000000 ? 1 : 0;
GSTextureFX10::PSSamplerSelector ps_ssel;
ps_ssel.min = m_filter == 2 ? (context->TEX1.MMIN & 1) : m_filter;
ps_ssel.mag = m_filter == 2 ? (context->TEX1.MMAG & 1) : m_filter;
ps_ssel.tau = 0;
ps_ssel.tav = 0;
GSTextureFX10::PSConstantBuffer ps_cb;
ps_cb.FogColor = GSVector4(env.FOGCOL.FCR, env.FOGCOL.FCG, env.FOGCOL.FCB, 0) / 255.0f;
ps_cb.TA0 = (float)(int)env.TEXA.TA0 / 255;
ps_cb.TA1 = (float)(int)env.TEXA.TA1 / 255;
ps_cb.AREF = (float)(int)context->TEST.AREF / 255;
if(context->TEST.ATST == 2 || context->TEST.ATST == 5)
{
ps_cb.AREF -= 0.9f/256;
}
else if(context->TEST.ATST == 3 || context->TEST.ATST == 6)
{
ps_cb.AREF += 0.9f/256;
}
if(tex)
{
ps_sel.bpp = tex->m_bpp2;
switch(context->CLAMP.WMS)
{
case 0:
ps_ssel.tau = 1;
break;
case 1:
ps_ssel.tau = 0;
break;
case 2:
ps_cb.MINU = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW);
ps_cb.MAXU = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW);
ps_ssel.tau = 0;
break;
case 3:
ps_cb.UMSK = context->CLAMP.MINU;
ps_cb.UFIX = context->CLAMP.MAXU;
ps_ssel.tau = 1;
break;
default:
__assume(0);
}
switch(context->CLAMP.WMT)
{
case 0:
ps_ssel.tav = 1;
break;
case 1:
ps_ssel.tav = 0;
break;
case 2:
ps_cb.MINV = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH);
ps_cb.MAXV = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH);
ps_ssel.tav = 0;
break;
case 3:
ps_cb.VMSK = context->CLAMP.MINV;
ps_cb.VFIX = context->CLAMP.MAXV;
ps_ssel.tav = 1;
break;
default:
__assume(0);
}
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);
}
else
{
ps_sel.tfx = 4;
}
// rs
int w = rt.GetWidth();
int h = rt.GetHeight();
CRect scissor = (CRect)GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in) & CRect(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.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.SetupRS(w, h, scissor);
// draw
if(context->TEST.DoFirstPass())
{
m_tfx.Draw();
}
if(context->TEST.DoSecondPass())
{
ASSERT(!env.PABE.PABE);
static const DWORD iatst[] = {1, 0, 5, 6, 7, 2, 3, 4};
ps_sel.atst = iatst[ps_sel.atst];
m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel);
bool z = om_dssel.zwe;
bool r = om_bsel.wr;
bool g = om_bsel.wg;
bool b = om_bsel.wb;
bool a = om_bsel.wa;
switch(context->TEST.AFAIL)
{
case 0: z = r = g = b = a = false; break; // none
case 1: z = false; break; // rgba
case 2: r = g = b = a = false; break; // z
case 3: z = a = false; break; // rgb
default: __assume(0);
}
if(z || r || g || b || a)
{
om_dssel.zwe = z;
om_bsel.wr = r;
om_bsel.wg = g;
om_bsel.wb = b;
om_bsel.wa = a;
m_tfx.UpdateOM(om_dssel, om_bsel, bf);
m_tfx.Draw();
}
}
m_dev.EndScene();
}
bool GSRendererHW10::WrapZ(DWORD maxz)
{
// should only run once if z values are in the z buffer range
for(int i = 0, j = m_count; i < j; i++)
{
if(m_vertices[i].p.z <= maxz)
{
return false;
}
}
return true;
}
void GSRendererHW10::SetupDATE(Texture& rt, Texture& 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
GSVector4 mm;
// TODO
mm = GSVector4(-1, -1, 1, 1);
/*
MinMaxXY(mm);
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;
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;
*/
GSVector4 uv = (mm + 1.0f) / 2.0f;
//
m_dev.BeginScene();
// om
GSTexture10 tmp;
m_dev.CreateRenderTarget(tmp, rt.GetWidth(), rt.GetHeight());
m_dev.OMSetRenderTargets(tmp, ds);
m_dev.OMSetDepthStencilState(m_date.dss, 1);
m_dev.OMSetBlendState(m_date.bs, 0);
m_dev->ClearDepthStencilView(ds, D3D10_CLEAR_STENCIL, 0, 0);
// ia
GSVertexPT1 vertices[] =
{
{GSVector4(mm.x, -mm.y, 0.5f, 1.0f), GSVector2(uv.x, uv.y)},
{GSVector4(mm.z, -mm.y, 0.5f, 1.0f), GSVector2(uv.z, uv.y)},
{GSVector4(mm.x, -mm.w, 0.5f, 1.0f), GSVector2(uv.x, uv.w)},
{GSVector4(mm.z, -mm.w, 0.5f, 1.0f), GSVector2(uv.z, uv.w)},
};
D3D10_BOX box = {0, 0, 0, sizeof(vertices), 1, 1};
m_dev->UpdateSubresource(m_dev.m_convert.vb, 0, &box, vertices, 0, 0);
m_dev.IASetVertexBuffer(m_dev.m_convert.vb, sizeof(vertices[0]));
m_dev.IASetInputLayout(m_dev.m_convert.il);
m_dev.IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
// vs
m_dev.VSSetShader(m_dev.m_convert.vs, NULL);
// gs
m_dev.GSSetShader(NULL);
// ps
m_dev.PSSetShaderResources(rt, NULL);
m_dev.PSSetShader(m_dev.m_convert.ps[m_context->TEST.DATM ? 2 : 3], NULL);
m_dev.PSSetSamplerState(m_dev.m_convert.pt, NULL);
// rs
m_dev.RSSet(tmp.GetWidth(), tmp.GetHeight());
// set
m_dev.DrawPrimitive(countof(vertices));
//
m_dev.EndScene();
m_dev.Recycle(tmp);
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRendererHW.h"
#include "GSVertexHW.h"
#include "GSTextureCache10.h"
#include "GSTextureFX10.h"
class GSRendererHW10 : public GSRendererHW<GSDevice10, GSVertexHW10, GSTextureCache10>
{
typedef GSDevice10 Device;
typedef GSVertexHW10 Vertex;
typedef GSTextureCache10 TextureCache;
bool WrapZ(DWORD maxz);
protected:
GSTextureFX10 m_tfx;
void Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex);
struct
{
CComPtr<ID3D10DepthStencilState> dss;
CComPtr<ID3D10BlendState> bs;
} m_date;
void SetupDATE(Texture& rt, Texture& ds);
public:
GSRendererHW10(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs);
bool Create(LPCTSTR title);
template<DWORD prim, DWORD tme, DWORD fst> void VertexKick(bool skip);
};

View File

@ -0,0 +1,594 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSRendererHW9.h"
#include "GSCrc.h"
#include "resource.h"
GSRendererHW9::GSRendererHW9(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
: GSRendererHW<Device, Vertex, TextureCache>(base, mt, irq, nloophack, rs, false)
{
m_fba.enabled = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("fba"), TRUE);
m_logz = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("logz"), FALSE);
InitVertexKick<GSRendererHW9>();
}
bool GSRendererHW9::Create(LPCTSTR title)
{
if(!__super::Create(title))
return false;
if(!m_tfx.Create(&m_dev))
return false;
//
memset(&m_date.dss, 0, sizeof(m_date.dss));
m_date.dss.StencilEnable = true;
m_date.dss.StencilReadMask = 1;
m_date.dss.StencilWriteMask = 1;
m_date.dss.StencilFunc = D3DCMP_ALWAYS;
m_date.dss.StencilPassOp = D3DSTENCILOP_REPLACE;
memset(&m_date.bs, 0, sizeof(m_date.bs));
//
memset(&m_fba.dss, 0, sizeof(m_fba.dss));
m_fba.dss.StencilEnable = true;
m_fba.dss.StencilReadMask = 2;
m_fba.dss.StencilWriteMask = 2;
m_fba.dss.StencilFunc = D3DCMP_EQUAL;
m_fba.dss.StencilPassOp = D3DSTENCILOP_ZERO;
m_fba.dss.StencilFailOp = D3DSTENCILOP_ZERO;
m_fba.dss.StencilDepthFailOp = D3DSTENCILOP_ZERO;
memset(&m_fba.bs, 0, sizeof(m_fba.bs));
m_fba.bs.RenderTargetWriteMask = D3DCOLORWRITEENABLE_ALPHA;
//
return true;
}
template<DWORD prim, DWORD tme, DWORD fst>
void GSRendererHW9::VertexKick(bool skip)
{
Vertex& dst = m_vl.AddTail();
dst.p.x = (float)m_v.XYZ.X;
dst.p.y = (float)m_v.XYZ.Y;
dst.p.z = (float)m_v.XYZ.Z;
dst.c0 = m_v.RGBAQ.ai32[0];
dst.c1 = m_v.FOG.ai32[1];
if(tme)
{
if(fst)
{
GSVector4::storel(&dst.t, m_v.GetUV());
}
else
{
dst.t.x = m_v.ST.S;
dst.t.y = m_v.ST.T;
dst.p.w = m_v.RGBAQ.Q;
}
}
DWORD count = 0;
if(Vertex* v = DrawingKick<prim>(skip, count))
{
GSVector4 scissor = m_context->scissor.dx9;
GSVector4 pmin, pmax;
switch(prim)
{
case GS_POINTLIST:
pmin = v[0].p;
pmax = v[0].p;
break;
case GS_LINELIST:
case GS_LINESTRIP:
case GS_SPRITE:
pmin = v[0].p.minv(v[1].p);
pmax = v[0].p.maxv(v[1].p);
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
pmin = v[0].p.minv(v[1].p).minv(v[2].p);
pmax = v[0].p.maxv(v[1].p).maxv(v[2].p);
break;
}
GSVector4 test = (pmax < scissor) | (pmin > scissor.zwxy());
if(test.mask() & 3)
{
return;
}
switch(prim)
{
case GS_POINTLIST:
break;
case GS_LINELIST:
case GS_LINESTRIP:
if(PRIM->IIP == 0) {v[0].c0 = v[1].c0;}
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
if(PRIM->IIP == 0) {v[0].c0 = v[1].c0 = v[2].c0;}
break;
case GS_SPRITE:
if(PRIM->IIP == 0) {v[0].c0 = v[1].c0;}
v[0].p.z = v[1].p.z;
v[0].p.w = v[1].p.w;
v[0].c1 = v[1].c1;
v[2] = v[1];
v[3] = v[1];
v[1].p.y = v[0].p.y;
v[1].t.y = v[0].t.y;
v[2].p.x = v[0].p.x;
v[2].t.x = v[0].t.x;
v[4] = v[1];
v[5] = v[2];
count += 4;
break;
}
m_count += count;
}
}
void GSRendererHW9::Draw(int prim, Texture& rt, Texture& ds, GSTextureCache<Device>::GSTexture* tex)
{
GSDrawingEnvironment& env = m_env;
GSDrawingContext* context = m_context;
D3DPRIMITIVETYPE topology;
int prims = 0;
switch(prim)
{
case GS_POINTLIST:
topology = D3DPT_POINTLIST;
prims = m_count;
break;
case GS_LINELIST:
case GS_LINESTRIP:
topology = D3DPT_LINELIST;
prims = m_count / 2;
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
case GS_SPRITE:
topology = D3DPT_TRIANGLELIST;
prims = m_count / 3;
break;
default:
__assume(0);
}
m_perfmon.Put(GSPerfMon::Prim, prims);
m_perfmon.Put(GSPerfMon::Draw, 1);
// date
SetupDATE(rt, ds);
//
m_dev.BeginScene();
m_dev->SetRenderState(D3DRS_SHADEMODE, PRIM->IIP ? D3DSHADE_GOURAUD : D3DSHADE_FLAT); // TODO
// om
GSTextureFX9::OMDepthStencilSelector om_dssel;
om_dssel.zte = context->TEST.ZTE;
om_dssel.ztst = context->TEST.ZTST;
om_dssel.zwe = !context->ZBUF.ZMSK;
om_dssel.date = context->FRAME.PSM != PSM_PSMCT24 ? context->TEST.DATE : 0;
om_dssel.fba = m_fba.enabled ? context->FBA.FBA : 0;
GSTextureFX9::OMBlendSelector om_bsel;
om_bsel.abe = PRIM->ABE || (prim == 1 || prim == 2) && PRIM->AA1;
om_bsel.a = context->ALPHA.A;
om_bsel.b = context->ALPHA.B;
om_bsel.c = context->ALPHA.C;
om_bsel.d = context->ALPHA.D;
om_bsel.wr = (context->FRAME.FBMSK & 0x000000ff) != 0x000000ff;
om_bsel.wg = (context->FRAME.FBMSK & 0x0000ff00) != 0x0000ff00;
om_bsel.wb = (context->FRAME.FBMSK & 0x00ff0000) != 0x00ff0000;
om_bsel.wa = (context->FRAME.FBMSK & 0xff000000) != 0xff000000;
BYTE bf = context->ALPHA.FIX >= 0x80 ? 0xff : (BYTE)(context->ALPHA.FIX * 2);
// vs
GSTextureFX9::VSSelector vs_sel;
vs_sel.bppz = 0;
vs_sel.tme = PRIM->TME;
vs_sel.fst = PRIM->FST;
vs_sel.logz = m_logz ? 1 : 0;
if(om_dssel.zte && om_dssel.ztst > 0 && om_dssel.zwe)
{
if(context->ZBUF.PSM == PSM_PSMZ24)
{
if(WrapZ(0xffffff))
{
vs_sel.bppz = 1;
om_dssel.ztst = 1;
}
}
else if(context->ZBUF.PSM == PSM_PSMZ16 || context->ZBUF.PSM == PSM_PSMZ16S)
{
if(WrapZ(0xffff))
{
vs_sel.bppz = 2;
om_dssel.ztst = 1;
}
}
}
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 ox = (float)(int)context->XYOFFSET.OFX;
float oy = (float)(int)context->XYOFFSET.OFY;
vs_cb.VertexScale = GSVector4(sx, -sy, 1.0f / UINT_MAX, 0.0f);
vs_cb.VertexOffset = GSVector4(ox * sx + 1, -(oy * sy + 1), 0.0f, -1.0f);
vs_cb.TextureScale = GSVector2(1.0f, 1.0f);
if(PRIM->TME && PRIM->FST)
{
vs_cb.TextureScale.x = 1.0f / (16 << context->TEX0.TW);
vs_cb.TextureScale.y = 1.0f / (16 << context->TEX0.TH);
}
// ps
GSTextureFX9::PSSelector ps_sel;
ps_sel.fst = PRIM->FST;
ps_sel.wms = context->CLAMP.WMS;
ps_sel.wmt = context->CLAMP.WMT;
ps_sel.bpp = 0;
ps_sel.aem = env.TEXA.AEM;
ps_sel.tfx = context->TEX0.TFX;
ps_sel.tcc = context->TEX0.TCC;
ps_sel.ate = context->TEST.ATE;
ps_sel.atst = context->TEST.ATST;
ps_sel.fog = PRIM->FGE;
ps_sel.clr1 = om_bsel.abe && om_bsel.a == 1 && om_bsel.b == 2 && om_bsel.d == 1;
ps_sel.rt = tex && tex->m_rendered;
GSTextureFX9::PSSamplerSelector ps_ssel;
ps_ssel.min = m_filter == 2 ? (context->TEX1.MMIN & 1) : m_filter;
ps_ssel.mag = m_filter == 2 ? (context->TEX1.MMAG & 1) : m_filter;
ps_ssel.tau = 0;
ps_ssel.tav = 0;
GSTextureFX9::PSConstantBuffer ps_cb;
ps_cb.FogColor = GSVector4(env.FOGCOL.FCR, env.FOGCOL.FCG, env.FOGCOL.FCB, 0) / 255.0f;
ps_cb.TA0 = (float)(int)env.TEXA.TA0 / 255;
ps_cb.TA1 = (float)(int)env.TEXA.TA1 / 255;
ps_cb.AREF = (float)(int)context->TEST.AREF / 255;
if(context->TEST.ATST == 2 || context->TEST.ATST == 5)
{
ps_cb.AREF -= 0.9f/256;
}
else if(context->TEST.ATST == 3 || context->TEST.ATST == 6)
{
ps_cb.AREF += 0.9f/256;
}
if(tex)
{
ps_sel.bpp = tex->m_bpp2;
switch(context->CLAMP.WMS)
{
case 0:
ps_ssel.tau = 1;
break;
case 1:
ps_ssel.tau = 0;
break;
case 2:
ps_cb.MINU = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW);
ps_cb.MAXU = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW);
ps_ssel.tau = 0;
break;
case 3:
ps_cb.UMSK = context->CLAMP.MINU;
ps_cb.UFIX = context->CLAMP.MAXU;
ps_ssel.tau = 1;
break;
default:
__assume(0);
}
switch(context->CLAMP.WMT)
{
case 0:
ps_ssel.tav = 1;
break;
case 1:
ps_ssel.tav = 0;
break;
case 2:
ps_cb.MINV = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH);
ps_cb.MAXV = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH);
ps_ssel.tav = 0;
break;
case 3:
ps_cb.VMSK = context->CLAMP.MINV;
ps_cb.VFIX = context->CLAMP.MAXV;
ps_ssel.tav = 1;
break;
default:
__assume(0);
}
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);
}
else
{
ps_sel.tfx = 4;
}
// rs
int w = rt.GetWidth();
int h = rt.GetHeight();
CRect scissor = (CRect)GSVector4i(GSVector4(rt.m_scale).xyxy() * context->scissor.in) & CRect(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.SetupRS(w, h, scissor);
// draw
if(context->TEST.DoFirstPass())
{
m_dev.DrawPrimitive();
}
if(context->TEST.DoSecondPass())
{
ASSERT(!env.PABE.PABE);
static const DWORD iatst[] = {1, 0, 5, 6, 7, 2, 3, 4};
ps_sel.atst = iatst[ps_sel.atst];
m_tfx.UpdatePS(ps_sel, &ps_cb, ps_ssel, m_psrr);
bool z = om_dssel.zwe;
bool r = om_bsel.wr;
bool g = om_bsel.wg;
bool b = om_bsel.wb;
bool a = om_bsel.wa;
switch(context->TEST.AFAIL)
{
case 0: z = r = g = b = a = false; break; // none
case 1: z = false; break; // rgba
case 2: r = g = b = a = false; break; // z
case 3: z = a = false; break; // rgb
default: __assume(0);
}
if(z || r || g || b || a)
{
om_dssel.zwe = z;
om_bsel.wr = r;
om_bsel.wg = g;
om_bsel.wb = b;
om_bsel.wa = a;
m_tfx.UpdateOM(om_dssel, om_bsel, bf);
m_dev.DrawPrimitive();
}
}
m_dev.EndScene();
if(om_dssel.fba) UpdateFBA(rt);
}
bool GSRendererHW9::WrapZ(float maxz)
{
// should only run once if z values are in the z buffer range
for(int i = 0, j = m_count; i < j; i++)
{
if(m_vertices[i].p.z <= maxz)
{
return false;
}
}
return true;
}
void GSRendererHW9::SetupDATE(Texture& rt, Texture& 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
GSVector4 mm;
// TODO
mm = GSVector4(-1, -1, 1, 1);
/*
MinMaxXY(mm);
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;
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;
*/
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)
{
m_dev.BeginScene();
// om
m_dev.OMSetDepthStencilState(&m_fba.dss, 2);
m_dev.OMSetBlendState(&m_fba.bs, 0);
// vs
m_dev.VSSetShader(NULL, NULL, 0);
// ps
m_dev.PSSetShader(m_dev.m_convert.ps[4], NULL, 0);
//
int w = rt.GetWidth();
int h = rt.GetHeight();
GSVertexP vertices[] =
{
{GSVector4(0, 0, 0, 0)},
{GSVector4(w, 0, 0, 0)},
{GSVector4(0, h, 0, 0)},
{GSVector4(w, h, 0, 0)},
};
m_dev->SetFVF(D3DFVF_XYZRHW);
m_dev->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, vertices, sizeof(vertices[0]));
//
m_dev.EndScene();
}

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRendererHW.h"
#include "GSVertexHW.h"
#include "GSTextureCache9.h"
#include "GSTextureFX9.h"
class GSRendererHW9 : public GSRendererHW<GSDevice9, GSVertexHW9, GSTextureCache9>
{
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);
struct
{
Direct3DDepthStencilState9 dss;
Direct3DBlendState9 bs;
} m_date;
struct
{
bool enabled;
Direct3DDepthStencilState9 dss;
Direct3DBlendState9 bs;
} m_fba;
void SetupDATE(Texture& rt, Texture& ds);
void UpdateFBA(Texture& rt);
public:
GSRendererHW9(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs);
bool Create(LPCTSTR title);
template<DWORD prim, DWORD tme, DWORD fst> void VertexKick(bool skip);
};

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSRendererNull.h"

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRenderer.h"
#include "GSDeviceNull.h"
template<class Device> class GSRendererNull : public GSRendererT<Device, GSVertexNull>
{
protected:
void Draw()
{
}
bool GetOutput(int i, Texture& t)
{
return false;
}
public:
GSRendererNull(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs)
: GSRendererT<Device, GSVertexNull>(base, mt, irq, nloophack, rs)
{
InitVertexKick<GSRendererNull<Device> >();
}
template<DWORD prim, DWORD tme, DWORD fst> void VertexKick(bool skip)
{
}
};

View File

@ -0,0 +1,25 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSRendererSW.h"
const GSVector4 g_pos_scale(1.0f / 16, 1.0f / 16, 1.0f, 128.0f);

858
plugins/GSdx/GSRendererSW.h Normal file
View File

@ -0,0 +1,858 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRenderer.h"
#include "GSTextureCacheSW.h"
#include "GSDrawScanline.h"
extern const GSVector4 g_pos_scale;
template <class Device>
class GSRendererSW : public GSRendererT<Device, GSVertexSW>
{
protected:
GSRasterizerList m_rl;
GSTextureCacheSW* m_tc;
GSVertexTrace m_vtrace;
Texture 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)
{
CRect r(0, 0, DISPFB[i]->FBW * 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;
}
GIFRegTEX0 TEX0;
TEX0.TBP0 = DISPFB[i]->Block();
TEX0.TBW = DISPFB[i]->FBW;
TEX0.PSM = DISPFB[i]->PSM;
GIFRegCLAMP CLAMP;
CLAMP.WMS = CLAMP.WMT = 1;
// TODO
static BYTE* buff = (BYTE*)_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)
{
CString str;
str.Format(_T("c:\\temp1\\_%05d_f%I64d_fr%d_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), i, (int)TEX0.TBP0, (int)TEX0.PSM);
if(s_save) t.Save(str);
}
return true;
}
bool TryAlphaTest(DWORD& fm, DWORD& zm)
{
const GSDrawingEnvironment& env = m_env;
const GSDrawingContext* context = m_context;
bool pass = true;
if(context->TEST.ATST == ATST_NEVER)
{
pass = false;
}
else if(context->TEST.ATST != ATST_ALWAYS)
{
GSVector4i af = GSVector4i(m_vtrace.m_min.c.wwww(m_vtrace.m_max.c)) >> 7;
int amin, amax;
if(PRIM->TME && (context->TEX0.TCC || context->TEX0.TFX == TFX_DECAL))
{
DWORD bpp = GSLocalMemory::m_psm[context->TEX0.PSM].trbpp;
DWORD cbpp = GSLocalMemory::m_psm[context->TEX0.CPSM].trbpp;
DWORD pal = GSLocalMemory::m_psm[context->TEX0.PSM].pal;
if(bpp == 32)
{
return false;
}
else if(bpp == 24)
{
amin = env.TEXA.AEM ? 0 : env.TEXA.TA0;
amax = env.TEXA.TA0;
}
else if(bpp == 16)
{
amin = env.TEXA.AEM ? 0 : min(env.TEXA.TA0, env.TEXA.TA1);
amax = max(env.TEXA.TA0, env.TEXA.TA1);
}
else
{
m_mem.m_clut.GetAlphaMinMax32(amin, amax);
}
switch(context->TEX0.TFX)
{
case TFX_MODULATE:
amin = (amin * af.x) >> 7;
amax = (amax * af.z) >> 7;
if(amin > 255) amin = 255;
if(amax > 255) amax = 255;
break;
case TFX_DECAL:
break;
case TFX_HIGHLIGHT:
amin = amin + af.x;
amax = amax + af.z;
if(amin > 255) amin = 255;
if(amax > 255) amax = 255;
break;
case TFX_HIGHLIGHT2:
break;
default:
__assume(0);
}
}
else
{
amin = af.x;
amax = af.z;
}
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_vm32;
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.dw = 0;
p.sel.fpsm = 3;
p.sel.zpsm = 3;
p.sel.atst = ATST_ALWAYS;
p.sel.tfx = TFX_NONE;
p.sel.abe = 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;
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;
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.tfx == TFX_DECAL)
{
p.sel.tcc = 1;
}
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;
}
*/
CRect r;
int w = 1 << context->TEX0.TW;
int h = 1 << context->TEX0.TH;
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;
}
if(PRIM->ABE)
{
if(!context->ALPHA.IsOpaque())
{
p.sel.abe = context->ALPHA.ai32[0];
p.sel.pabe = env.PABE.PABE;
}
}
if(PRIM->AA1)
{
// TODO: automatic alpha blending (ABE=1, A=0 B=1 C=0 D=1)
}
if(p.sel.date
|| p.sel.abea == 1 || p.sel.abeb == 1 || p.sel.abec == 1 || p.sel.abed == 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;
}
}
bool zwrite = p.zm != 0xffffffff;
bool ztest = context->TEST.ZTE && context->TEST.ZTST > 1;
if(zwrite || ztest)
{
p.sel.zpsm = GSUtil::EncodePSM(context->ZBUF.PSM);
p.sel.ztst = ztest ? context->TEST.ZTST : 1;
}
}
void Draw()
{
m_vtrace.Update(m_vertices, m_count);
GS_PRIM_CLASS primclass = GSUtil::GetPrimClass(PRIM->PRIM);
GSScanlineParam p;
GetScanlineParam(p, primclass);
if((p.fm & p.zm) == 0xffffffff)
{
return;
}
if(s_dump)
{
CString str;
str.Format(_T("c:\\temp1\\_%05d_f%I64d_tex_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), (int)m_context->TEX0.TBP0, (int)m_context->TEX0.PSM);
if(PRIM->TME) if(s_save) {m_mem.SaveBMP(str, m_context->TEX0.TBP0, m_context->TEX0.TBW, m_context->TEX0.PSM, 1 << m_context->TEX0.TW, 1 << m_context->TEX0.TH);}
str.Format(_T("c:\\temp1\\_%05d_f%I64d_rt0_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM);
if(s_save) {m_mem.SaveBMP(str, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameSize(1).cx, 512);}//GetFrameSize(1).cy);
str.Format(_T("c:\\temp1\\_%05d_f%I64d_rz0_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM);
if(s_savez) {m_mem.SaveBMP(str, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameSize(1).cx, 512);}
}
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 pos(m_vtrace.m_min.p.xyxy(m_vtrace.m_max.p));
GSVector4i scissor = data.scissor;
CRect r;
r.left = max(scissor.x, min(scissor.z, pos.x));
r.top = max(scissor.y, min(scissor.w, pos.y));
r.right = max(scissor.x, min(scissor.z, pos.z));
r.bottom = max(scissor.y, min(scissor.w, pos.w));
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)
{
CString str;
str.Format(_T("c:\\temp1\\_%05d_f%I64d_rt1_%05x_%d.bmp"), s_n++, m_perfmon.GetFrame(), m_context->FRAME.Block(), m_context->FRAME.PSM);
if(s_save) {m_mem.SaveBMP(str, m_context->FRAME.Block(), m_context->FRAME.FBW, m_context->FRAME.PSM, GetFrameSize(1).cx, 512);}//GetFrameSize(1).cy);
str.Format(_T("c:\\temp1\\_%05d_f%I64d_rz1_%05x_%d.bmp"), s_n-1, m_perfmon.GetFrame(), m_context->ZBUF.Block(), m_context->ZBUF.PSM);
if(s_savez) {m_mem.SaveBMP(str, m_context->ZBUF.Block(), m_context->FRAME.FBW, m_context->ZBUF.PSM, GetFrameSize(1).cx, 512);}
}
}
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r)
{
m_tc->InvalidateVideoMem(BITBLTBUF, r);
}
void MinMaxUV(int w, int h, CRect& r, DWORD 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);
/*
int tw = context->TEX0.TW;
int th = context->TEX0.TH;
GSVector4i u = uv & GSVector4i::xffffffff().srl32(32 - tw);
GSVector4i v = uv & GSVector4i::xffffffff().srl32(32 - th);
GSVector4i uu = uv.sra32(tw);
GSVector4i vv = uv.sra32(th);
int 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;
r &= CRect(0, 0, w, h);
}
public:
GSRendererSW(BYTE* base, bool mt, void (*irq)(), int nloophack, const GSRendererSettings& rs, int threads)
: GSRendererT(base, mt, irq, nloophack, rs)
{
m_rl.Create<GSDrawScanline>(this, threads);
m_tc = new GSTextureCacheSW(this);
InitVertexKick<GSRendererSW<Device> >();
}
virtual ~GSRendererSW()
{
delete m_tc;
}
template<DWORD prim, DWORD tme, DWORD fst>
void VertexKick(bool skip)
{
const GSDrawingContext* context = m_context;
GSVector4i xy = GSVector4i::load((int)m_v.XYZ.ai32[0]);
xy = xy.insert16<3>(m_v.FOG.F);
xy = xy.upl16();
xy -= context->XYOFFSET;
GSVertexSW v;
v.p = GSVector4(xy) * g_pos_scale;
v.c = GSVector4(GSVector4i::load((int)m_v.RGBAQ.ai32[0]).u8to32() << 7);
if(tme)
{
float q;
if(fst)
{
v.t = GSVector4(((GSVector4i)m_v.UV).upl16() << (16 - 4));
q = 1.0f;
}
else
{
v.t = GSVector4(m_v.ST.S, m_v.ST.T);
v.t *= GSVector4(0x10000 << context->TEX0.TW, 0x10000 << context->TEX0.TH);
q = m_v.RGBAQ.Q;
}
v.t = v.t.xyxy(GSVector4::load(q));
}
GSVertexSW& dst = m_vl.AddTail();
dst = v;
dst.p.z = (float)min(m_v.XYZ.Z, 0xffffff00); // max value which can survive the DWORD => float => DWORD conversion
DWORD count = 0;
if(GSVertexSW* v = DrawingKick<prim>(skip, count))
{
GSVector4 pmin, pmax;
switch(prim)
{
case GS_POINTLIST:
pmin = v[0].p;
pmax = v[0].p;
break;
case GS_LINELIST:
case GS_LINESTRIP:
case GS_SPRITE:
pmin = v[0].p.minv(v[1].p);
pmax = v[0].p.maxv(v[1].p);
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
pmin = v[0].p.minv(v[1].p).minv(v[2].p);
pmax = v[0].p.maxv(v[1].p).maxv(v[2].p);
break;
}
GSVector4 scissor = context->scissor.ex;
GSVector4 test = (pmax < scissor) | (pmin > scissor.zwxy());
switch(prim)
{
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
case GS_SPRITE:
test |= pmin.ceil() == pmax.ceil();
break;
}
if(test.mask() & 3)
{
return;
}
switch(prim)
{
case GS_POINTLIST:
break;
case GS_LINELIST:
case GS_LINESTRIP:
if(PRIM->IIP == 0) {v[0].c = v[1].c;}
break;
case GS_TRIANGLELIST:
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
if(PRIM->IIP == 0) {v[0].c = v[2].c; v[1].c = v[2].c;}
break;
case GS_SPRITE:
break;
}
if(m_count >= 3 && m_count < 30)
{
GSVertexSW* v = &m_vertices[m_count - 3];
int tl = 0;
int br = 0;
bool isquad = false;
switch(prim)
{
case GS_TRIANGLESTRIP:
case GS_TRIANGLEFAN:
case GS_TRIANGLELIST:
isquad = GSVertexSW::IsQuad(v, tl, br);
break;
}
if(isquad)
{
m_count -= 3;
if(m_count > 0)
{
tl += m_count;
br += m_count;
Flush();
}
if(tl != 0) m_vertices[0] = m_vertices[tl];
if(br != 1) m_vertices[1] = m_vertices[br];
m_count = 2;
UINT32 tmp = PRIM->PRIM;
PRIM->PRIM = GS_SPRITE;
Flush();
PRIM->PRIM = tmp;
m_perfmon.Put(GSPerfMon::Quad, 1);
return;
}
}
m_count += count;
}
}
};

View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSSetting.h"

45
plugins/GSdx/GSSetting.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
struct GSSetting
{
DWORD id;
const TCHAR* name;
const TCHAR* note;
static void InitComboBox(const GSSetting* settings, int count, CComboBox& combobox, DWORD sel, DWORD maxid = ~0)
{
for(int i = 0; i < count; i++)
{
if(settings[i].id <= maxid)
{
CString str = settings[i].name;
if(settings[i].note != NULL) str = str + _T(" (") + settings[i].note + _T(")");
int item = combobox.AddString(str);
combobox.SetItemData(item, settings[i].id);
if(settings[i].id == sel) combobox.SetCurSel(item);
}
}
}
};

View File

@ -0,0 +1,324 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSdx.h"
#include "GSSettingsDlg.h"
#include "GSUtil.h"
#include <shlobj.h>
#include <afxpriv.h>
GSSetting GSSettingsDlg::g_renderers[] =
{
{0, _T("Direct3D9 (Hardware)"), NULL},
{1, _T("Direct3D9 (Software)"), NULL},
{2, _T("Direct3D9 (Null)"), NULL},
{3, _T("Direct3D10 (Hardware)"), NULL},
{4, _T("Direct3D10 (Software)"), NULL},
{5, _T("Direct3D10 (Null)"), NULL},
{6, _T("Null (Software)"), NULL},
{7, _T("Null (Null)"), NULL},
};
GSSetting GSSettingsDlg::g_psversion[] =
{
{D3DPS_VERSION(3, 0), _T("Pixel Shader 3.0"), NULL},
{D3DPS_VERSION(2, 0), _T("Pixel Shader 2.0"), NULL},
//{D3DPS_VERSION(1, 4), _T("Pixel Shader 1.4"), NULL},
//{D3DPS_VERSION(1, 1), _T("Pixel Shader 1.1"), NULL},
//{D3DPS_VERSION(0, 0), _T("Fixed Pipeline (bogus)"), NULL},
};
GSSetting GSSettingsDlg::g_interlace[] =
{
{0, _T("None"), NULL},
{1, _T("Weave tff"), _T("saw-tooth")},
{2, _T("Weave bff"), _T("saw-tooth")},
{3, _T("Bob tff"), _T("use blend if shaking")},
{4, _T("Bob bff"), _T("use blend if shaking")},
{5, _T("Blend tff"), _T("slight blur, 1/2 fps")},
{6, _T("Blend bff"), _T("slight blur, 1/2 fps")},
};
GSSetting GSSettingsDlg::g_aspectratio[] =
{
{0, _T("Stretch"), NULL},
{1, _T("4:3"), NULL},
{2, _T("16:9"), NULL},
};
IMPLEMENT_DYNAMIC(GSSettingsDlg, CDialog)
GSSettingsDlg::GSSettingsDlg(CWnd* pParent /*=NULL*/)
: CDialog(GSSettingsDlg::IDD, pParent)
, m_tvout(FALSE)
, m_filter(1)
, m_nloophack(2)
, m_nativeres(FALSE)
, m_vsync(FALSE)
, m_logz(FALSE)
, m_fba(TRUE)
{
}
GSSettingsDlg::~GSSettingsDlg()
{
}
LRESULT GSSettingsDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = __super::DefWindowProc(message, wParam, lParam);
if(message == WM_INITDIALOG)
{
SendMessage(WM_KICKIDLE);
}
return ret;
}
void GSSettingsDlg::DoDataExchange(CDataExchange* pDX)
{
__super::DoDataExchange(pDX);
DDX_Control(pDX, IDC_COMBO3, m_resolution);
DDX_Control(pDX, IDC_COMBO1, m_renderer);
DDX_Control(pDX, IDC_COMBO4, m_psversion);
DDX_Control(pDX, IDC_COMBO2, m_interlace);
DDX_Control(pDX, IDC_COMBO5, m_aspectratio);
DDX_Check(pDX, IDC_CHECK3, m_tvout);
DDX_Check(pDX, IDC_CHECK4, m_filter);
DDX_Check(pDX, IDC_CHECK6, m_nloophack);
DDX_Control(pDX, IDC_SPIN1, m_resx);
DDX_Control(pDX, IDC_SPIN2, m_resy);
DDX_Control(pDX, IDC_SPIN3, m_swthreads);
DDX_Check(pDX, IDC_CHECK1, m_nativeres);
DDX_Control(pDX, IDC_EDIT1, m_resxedit);
DDX_Control(pDX, IDC_EDIT2, m_resyedit);
DDX_Control(pDX, IDC_EDIT3, m_swthreadsedit);
DDX_Check(pDX, IDC_CHECK2, m_vsync);
DDX_Check(pDX, IDC_CHECK5, m_logz);
DDX_Check(pDX, IDC_CHECK7, m_fba);
}
BEGIN_MESSAGE_MAP(GSSettingsDlg, CDialog)
ON_MESSAGE_VOID(WM_KICKIDLE, OnKickIdle)
ON_UPDATE_COMMAND_UI(IDC_SPIN1, OnUpdateResolution)
ON_UPDATE_COMMAND_UI(IDC_SPIN2, OnUpdateResolution)
ON_UPDATE_COMMAND_UI(IDC_EDIT1, OnUpdateResolution)
ON_UPDATE_COMMAND_UI(IDC_EDIT2, OnUpdateResolution)
ON_UPDATE_COMMAND_UI(IDC_COMBO4, OnUpdateD3D9Options)
ON_UPDATE_COMMAND_UI(IDC_CHECK3, OnUpdateD3D9Options)
ON_UPDATE_COMMAND_UI(IDC_CHECK5, OnUpdateD3D9Options)
ON_UPDATE_COMMAND_UI(IDC_CHECK7, OnUpdateD3D9Options)
ON_UPDATE_COMMAND_UI(IDC_SPIN3, OnUpdateSWOptions)
ON_UPDATE_COMMAND_UI(IDC_EDIT3, OnUpdateSWOptions)
ON_CBN_SELCHANGE(IDC_COMBO1, &GSSettingsDlg::OnCbnSelchangeCombo1)
END_MESSAGE_MAP()
void GSSettingsDlg::OnKickIdle()
{
UpdateDialogControls(this, false);
}
BOOL GSSettingsDlg::OnInitDialog()
{
__super::OnInitDialog();
CWinApp* pApp = AfxGetApp();
D3DCAPS9 caps;
memset(&caps, 0, sizeof(caps));
caps.PixelShaderVersion = D3DPS_VERSION(0, 0);
m_modes.RemoveAll();
// windowed
{
D3DDISPLAYMODE mode;
memset(&mode, 0, sizeof(mode));
m_modes.AddTail(mode);
int iItem = m_resolution.AddString(_T("Windowed"));
m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition());
m_resolution.SetCurSel(iItem);
}
// fullscreen
if(CComPtr<IDirect3D9> d3d = Direct3DCreate9(D3D_SDK_VERSION))
{
UINT ModeWidth = pApp->GetProfileInt(_T("Settings"), _T("ModeWidth"), 0);
UINT ModeHeight = pApp->GetProfileInt(_T("Settings"), _T("ModeHeight"), 0);
UINT ModeRefreshRate = pApp->GetProfileInt(_T("Settings"), _T("ModeRefreshRate"), 0);
UINT nModes = d3d->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8);
for(UINT i = 0; i < nModes; i++)
{
D3DDISPLAYMODE mode;
if(S_OK == d3d->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_X8R8G8B8, i, &mode))
{
CString str;
str.Format(_T("%dx%d %dHz"), mode.Width, mode.Height, mode.RefreshRate);
int iItem = m_resolution.AddString(str);
m_modes.AddTail(mode);
m_resolution.SetItemDataPtr(iItem, m_modes.GetTailPosition());
if(ModeWidth == mode.Width && ModeHeight == mode.Height && ModeRefreshRate == mode.RefreshRate)
{
m_resolution.SetCurSel(iItem);
}
}
}
d3d->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &caps);
}
bool isdx10avail = GSUtil::IsDirect3D10Available();
CAtlArray<GSSetting> renderers;
for(size_t i = 0; i < countof(g_renderers); i++)
{
if(i >= 3 && i <= 5 && !isdx10avail) continue;
renderers.Add(g_renderers[i]);
}
GSSetting::InitComboBox(renderers.GetData(), renderers.GetCount(), m_renderer, pApp->GetProfileInt(_T("Settings"), _T("Renderer"), 0));
GSSetting::InitComboBox(g_psversion, countof(g_psversion), m_psversion, pApp->GetProfileInt(_T("Settings"), _T("PixelShaderVersion2"), D3DPS_VERSION(2, 0)), caps.PixelShaderVersion);
GSSetting::InitComboBox(g_interlace, countof(g_interlace), m_interlace, pApp->GetProfileInt(_T("Settings"), _T("Interlace"), 0));
GSSetting::InitComboBox(g_aspectratio, countof(g_aspectratio), m_aspectratio, pApp->GetProfileInt(_T("Settings"), _T("AspectRatio"), 1));
OnCbnSelchangeCombo1();
//
m_filter = pApp->GetProfileInt(_T("Settings"), _T("filter"), 1);
m_tvout = pApp->GetProfileInt(_T("Settings"), _T("tvout"), FALSE);
m_nloophack = pApp->GetProfileInt(_T("Settings"), _T("nloophack"), 2);
m_vsync = !!pApp->GetProfileInt(_T("Settings"), _T("vsync"), FALSE);
m_logz = !!pApp->GetProfileInt(_T("Settings"), _T("logz"), FALSE);
m_fba = !!pApp->GetProfileInt(_T("Settings"), _T("fba"), TRUE);
m_resx.SetRange(512, 4096);
m_resy.SetRange(512, 4096);
m_resx.SetPos(pApp->GetProfileInt(_T("Settings"), _T("resx"), 1024));
m_resy.SetPos(pApp->GetProfileInt(_T("Settings"), _T("resy"), 1024));
m_nativeres = !!pApp->GetProfileInt(_T("Settings"), _T("nativeres"), FALSE);
m_resx.EnableWindow(!m_nativeres);
m_resy.EnableWindow(!m_nativeres);
m_resxedit.EnableWindow(!m_nativeres);
m_resyedit.EnableWindow(!m_nativeres);
m_swthreads.SetRange(1, 16);
m_swthreads.SetPos(pApp->GetProfileInt(_T("Settings"), _T("swthreads"), 1));
//
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void GSSettingsDlg::OnOK()
{
CWinApp* pApp = AfxGetApp();
UpdateData();
if(m_resolution.GetCurSel() >= 0)
{
D3DDISPLAYMODE& mode = m_modes.GetAt((POSITION)m_resolution.GetItemData(m_resolution.GetCurSel()));
pApp->WriteProfileInt(_T("Settings"), _T("ModeWidth"), mode.Width);
pApp->WriteProfileInt(_T("Settings"), _T("ModeHeight"), mode.Height);
pApp->WriteProfileInt(_T("Settings"), _T("ModeRefreshRate"), mode.RefreshRate);
}
if(m_renderer.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("Settings"), _T("Renderer"), (DWORD)m_renderer.GetItemData(m_renderer.GetCurSel()));
}
if(m_psversion.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("Settings"), _T("PixelShaderVersion2"), (DWORD)m_psversion.GetItemData(m_psversion.GetCurSel()));
}
if(m_interlace.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("Settings"), _T("Interlace"), (DWORD)m_interlace.GetItemData(m_interlace.GetCurSel()));
}
if(m_aspectratio.GetCurSel() >= 0)
{
pApp->WriteProfileInt(_T("Settings"), _T("AspectRatio"), (DWORD)m_aspectratio.GetItemData(m_aspectratio.GetCurSel()));
}
pApp->WriteProfileInt(_T("Settings"), _T("filter"), m_filter);
pApp->WriteProfileInt(_T("Settings"), _T("tvout"), m_tvout);
pApp->WriteProfileInt(_T("Settings"), _T("nloophack"), m_nloophack);
pApp->WriteProfileInt(_T("Settings"), _T("vsync"), m_vsync);
pApp->WriteProfileInt(_T("Settings"), _T("logz"), m_logz);
pApp->WriteProfileInt(_T("Settings"), _T("fba"), m_fba);
pApp->WriteProfileInt(_T("Settings"), _T("resx"), m_resx.GetPos());
pApp->WriteProfileInt(_T("Settings"), _T("resy"), m_resy.GetPos());
pApp->WriteProfileInt(_T("Settings"), _T("swthreads"), m_swthreads.GetPos());
pApp->WriteProfileInt(_T("Settings"), _T("nativeres"), m_nativeres);
__super::OnOK();
}
void GSSettingsDlg::OnUpdateResolution(CCmdUI* pCmdUI)
{
UpdateData();
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
pCmdUI->Enable(!m_nativeres && (i == 0 || i == 3));
}
void GSSettingsDlg::OnUpdateD3D9Options(CCmdUI* pCmdUI)
{
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
pCmdUI->Enable(i >= 0 && i <= 2);
}
void GSSettingsDlg::OnUpdateSWOptions(CCmdUI* pCmdUI)
{
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
pCmdUI->Enable(i == 1 || i == 4 || i == 6);
}
void GSSettingsDlg::OnCbnSelchangeCombo1()
{
int i = (int)m_renderer.GetItemData(m_renderer.GetCurSel());
GetDlgItem(IDC_LOGO9)->ShowWindow(i >= 0 && i <= 2 ? SW_SHOW : SW_HIDE);
GetDlgItem(IDC_LOGO10)->ShowWindow(i >= 3 && i <= 5 ? SW_SHOW : SW_HIDE);
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSSetting.h"
#include "resource.h"
class GSSettingsDlg : public CDialog
{
DECLARE_DYNAMIC(GSSettingsDlg)
private:
CAtlList<D3DDISPLAYMODE> m_modes;
public:
GSSettingsDlg(CWnd* pParent = NULL); // standard constructor
virtual ~GSSettingsDlg();
static GSSetting g_renderers[];
static GSSetting g_psversion[];
static GSSetting g_interlace[];
static GSSetting g_aspectratio[];
// Dialog Data
enum { IDD = IDD_CONFIG };
CComboBox m_resolution;
CComboBox m_renderer;
CComboBox m_psversion;
CComboBox m_interlace;
CComboBox m_aspectratio;
BOOL m_tvout;
int m_filter;
int m_nloophack;
CSpinButtonCtrl m_resx;
CSpinButtonCtrl m_resy;
CSpinButtonCtrl m_swthreads;
BOOL m_nativeres;
CEdit m_resxedit;
CEdit m_resyedit;
CEdit m_swthreadsedit;
BOOL m_vsync;
BOOL m_logz;
BOOL m_fba;
protected:
virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam);
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual BOOL OnInitDialog();
virtual void OnOK();
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnKickIdle();
afx_msg void OnUpdateResolution(CCmdUI* pCmdUI);
afx_msg void OnUpdateD3D9Options(CCmdUI* pCmdUI);
afx_msg void OnUpdateSWOptions(CCmdUI* pCmdUI);
afx_msg void OnCbnSelchangeCombo1();
};

2179
plugins/GSdx/GSState.cpp Normal file

File diff suppressed because it is too large Load Diff

268
plugins/GSdx/GSState.h Normal file
View File

@ -0,0 +1,268 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
#include "GSLocalMemory.h"
#include "GSDrawingContext.h"
#include "GSDrawingEnvironment.h"
#include "GSVertex.h"
#include "GSVertexList.h"
#include "GSUtil.h"
#include "GSDirtyRect.h"
#include "GSPerfMon.h"
#include "GSVector.h"
#include "GSDevice.h"
#include "GSCrc.h"
#include "GSAlignedClass.h"
#include "GSDump.h"
class GSState : public GSAlignedClass<16>
{
typedef void (GSState::*GIFPackedRegHandler)(GIFPackedReg* r);
GIFPackedRegHandler m_fpGIFPackedRegHandlers[16];
void GIFPackedRegHandlerNull(GIFPackedReg* r);
void GIFPackedRegHandlerPRIM(GIFPackedReg* r);
void GIFPackedRegHandlerRGBA(GIFPackedReg* r);
void GIFPackedRegHandlerSTQ(GIFPackedReg* r);
void GIFPackedRegHandlerUV(GIFPackedReg* r);
void GIFPackedRegHandlerXYZF2(GIFPackedReg* r);
void GIFPackedRegHandlerXYZ2(GIFPackedReg* r);
template<int i> void GIFPackedRegHandlerTEX0(GIFPackedReg* r);
template<int i> void GIFPackedRegHandlerCLAMP(GIFPackedReg* r);
void GIFPackedRegHandlerFOG(GIFPackedReg* r);
void GIFPackedRegHandlerXYZF3(GIFPackedReg* r);
void GIFPackedRegHandlerXYZ3(GIFPackedReg* r);
void GIFPackedRegHandlerA_D(GIFPackedReg* r);
void GIFPackedRegHandlerA_D(GIFPackedReg* r, int size);
void GIFPackedRegHandlerNOP(GIFPackedReg* r);
typedef void (GSState::*GIFRegHandler)(GIFReg* r);
GIFRegHandler m_fpGIFRegHandlers[256];
void GIFRegHandlerNull(GIFReg* r);
void GIFRegHandlerPRIM(GIFReg* r);
void GIFRegHandlerRGBAQ(GIFReg* r);
void GIFRegHandlerST(GIFReg* r);
void GIFRegHandlerUV(GIFReg* r);
void GIFRegHandlerXYZF2(GIFReg* r);
void GIFRegHandlerXYZ2(GIFReg* r);
template<int i> void GIFRegHandlerTEX0(GIFReg* r);
template<int i> void GIFRegHandlerCLAMP(GIFReg* r);
void GIFRegHandlerFOG(GIFReg* r);
void GIFRegHandlerXYZF3(GIFReg* r);
void GIFRegHandlerXYZ3(GIFReg* r);
void GIFRegHandlerNOP(GIFReg* r);
template<int i> void GIFRegHandlerTEX1(GIFReg* r);
template<int i> void GIFRegHandlerTEX2(GIFReg* r);
template<int i> void GIFRegHandlerXYOFFSET(GIFReg* r);
void GIFRegHandlerPRMODECONT(GIFReg* r);
void GIFRegHandlerPRMODE(GIFReg* r);
void GIFRegHandlerTEXCLUT(GIFReg* r);
void GIFRegHandlerSCANMSK(GIFReg* r);
template<int i> void GIFRegHandlerMIPTBP1(GIFReg* r);
template<int i> void GIFRegHandlerMIPTBP2(GIFReg* r);
void GIFRegHandlerTEXA(GIFReg* r);
void GIFRegHandlerFOGCOL(GIFReg* r);
void GIFRegHandlerTEXFLUSH(GIFReg* r);
template<int i> void GIFRegHandlerSCISSOR(GIFReg* r);
template<int i> void GIFRegHandlerALPHA(GIFReg* r);
void GIFRegHandlerDIMX(GIFReg* r);
void GIFRegHandlerDTHE(GIFReg* r);
void GIFRegHandlerCOLCLAMP(GIFReg* r);
template<int i> void GIFRegHandlerTEST(GIFReg* r);
void GIFRegHandlerPABE(GIFReg* r);
template<int i> void GIFRegHandlerFBA(GIFReg* r);
template<int i> void GIFRegHandlerFRAME(GIFReg* r);
template<int i> void GIFRegHandlerZBUF(GIFReg* r);
void GIFRegHandlerBITBLTBUF(GIFReg* r);
void GIFRegHandlerTRXPOS(GIFReg* r);
void GIFRegHandlerTRXREG(GIFReg* r);
void GIFRegHandlerTRXDIR(GIFReg* r);
void GIFRegHandlerHWREG(GIFReg* r);
void GIFRegHandlerSIGNAL(GIFReg* r);
void GIFRegHandlerFINISH(GIFReg* r);
void GIFRegHandlerLABEL(GIFReg* r);
int m_version;
int m_sssize;
bool m_mt;
void (*m_irq)();
bool m_path3hack;
int m_nloophack_org;
int m_x, m_y;
int m_bytes;
int m_maxbytes;
BYTE* m_buff;
void FlushWrite();
void FlushWrite(BYTE* mem, int len);
protected:
bool IsBadFrame(int& skip);
typedef void (GSState::*VertexKickPtr)(bool skip);
VertexKickPtr m_vk[8][2][2];
VertexKickPtr m_vkf;
template<class T> void InitVertexKick()
{
m_vk[GS_POINTLIST][0][0] = (VertexKickPtr)&T::VertexKick<GS_POINTLIST, 0, 0>;
m_vk[GS_POINTLIST][0][1] = (VertexKickPtr)&T::VertexKick<GS_POINTLIST, 0, 0>;
m_vk[GS_POINTLIST][1][0] = (VertexKickPtr)&T::VertexKick<GS_POINTLIST, 1, 0>;
m_vk[GS_POINTLIST][1][1] = (VertexKickPtr)&T::VertexKick<GS_POINTLIST, 1, 1>;
m_vk[GS_LINELIST][0][0] = (VertexKickPtr)&T::VertexKick<GS_LINELIST, 0, 0>;
m_vk[GS_LINELIST][0][1] = (VertexKickPtr)&T::VertexKick<GS_LINELIST, 0, 0>;
m_vk[GS_LINELIST][1][0] = (VertexKickPtr)&T::VertexKick<GS_LINELIST, 1, 0>;
m_vk[GS_LINELIST][1][1] = (VertexKickPtr)&T::VertexKick<GS_LINELIST, 1, 1>;
m_vk[GS_LINESTRIP][0][0] = (VertexKickPtr)&T::VertexKick<GS_LINESTRIP, 0, 0>;
m_vk[GS_LINESTRIP][0][1] = (VertexKickPtr)&T::VertexKick<GS_LINESTRIP, 0, 0>;
m_vk[GS_LINESTRIP][1][0] = (VertexKickPtr)&T::VertexKick<GS_LINESTRIP, 1, 0>;
m_vk[GS_LINESTRIP][1][1] = (VertexKickPtr)&T::VertexKick<GS_LINESTRIP, 1, 1>;
m_vk[GS_TRIANGLELIST][0][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLELIST, 0, 0>;
m_vk[GS_TRIANGLELIST][0][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLELIST, 0, 0>;
m_vk[GS_TRIANGLELIST][1][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLELIST, 1, 0>;
m_vk[GS_TRIANGLELIST][1][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLELIST, 1, 1>;
m_vk[GS_TRIANGLESTRIP][0][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLESTRIP, 0, 0>;
m_vk[GS_TRIANGLESTRIP][0][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLESTRIP, 0, 0>;
m_vk[GS_TRIANGLESTRIP][1][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLESTRIP, 1, 0>;
m_vk[GS_TRIANGLESTRIP][1][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLESTRIP, 1, 1>;
m_vk[GS_TRIANGLEFAN][0][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLEFAN, 0, 0>;
m_vk[GS_TRIANGLEFAN][0][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLEFAN, 0, 0>;
m_vk[GS_TRIANGLEFAN][1][0] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLEFAN, 1, 0>;
m_vk[GS_TRIANGLEFAN][1][1] = (VertexKickPtr)&T::VertexKick<GS_TRIANGLEFAN, 1, 1>;
m_vk[GS_SPRITE][0][0] = (VertexKickPtr)&T::VertexKick<GS_SPRITE, 0, 0>;
m_vk[GS_SPRITE][0][1] = (VertexKickPtr)&T::VertexKick<GS_SPRITE, 0, 0>;
m_vk[GS_SPRITE][1][0] = (VertexKickPtr)&T::VertexKick<GS_SPRITE, 1, 0>;
m_vk[GS_SPRITE][1][1] = (VertexKickPtr)&T::VertexKick<GS_SPRITE, 1, 1>;
m_vk[GS_INVALID][0][0] = &GSState::VertexKickNull;
m_vk[GS_INVALID][0][1] = &GSState::VertexKickNull;
m_vk[GS_INVALID][1][0] = &GSState::VertexKickNull;
m_vk[GS_INVALID][1][1] = &GSState::VertexKickNull;
}
void UpdateVertexKick()
{
m_vkf = m_vk[PRIM->PRIM][PRIM->TME][PRIM->FST];
}
void VertexKickNull(bool skip)
{
ASSERT(0);
}
void VertexKick(bool skip)
{
(this->*m_vkf)(skip);
}
public:
GIFRegPRIM* PRIM;
GSRegPMODE* PMODE;
GSRegSMODE1* SMODE1;
GSRegSMODE2* SMODE2;
GSRegDISPFB* DISPFB[2];
GSRegDISPLAY* DISPLAY[2];
GSRegEXTBUF* EXTBUF;
GSRegEXTDATA* EXTDATA;
GSRegEXTWRITE* EXTWRITE;
GSRegBGCOLOR* BGCOLOR;
GSRegCSR* CSR;
GSRegIMR* IMR;
GSRegBUSDIR* BUSDIR;
GSRegSIGLBLID* SIGLBLID;
GIFPath m_path[3];
GSLocalMemory m_mem;
GSDrawingEnvironment m_env;
GSDrawingContext* m_context;
GSVertex m_v;
float m_q;
DWORD m_vprim;
GSPerfMon m_perfmon;
bool m_nloophack;
DWORD m_crc;
int m_options;
int m_frameskip;
CRC::Game m_game;
GSDump m_dump;
public:
GSState(BYTE* base, bool mt, void (*irq)(), int nloophack);
virtual ~GSState();
void ResetHandlers();
CPoint GetDisplayPos(int i);
CSize GetDisplaySize(int i);
CRect GetDisplayRect(int i);
CSize GetDisplayPos();
CSize GetDisplaySize();
CRect GetDisplayRect();
CPoint GetFramePos(int i);
CSize GetFrameSize(int i);
CRect GetFrameRect(int i);
CSize GetFramePos();
CSize GetFrameSize();
CRect GetFrameRect();
CSize GetDeviceSize(int i);
CSize GetDeviceSize();
bool IsEnabled(int i);
int GetFPS();
virtual void Reset();
virtual void Flush();
virtual void FlushPrim() = 0;
virtual void ResetPrim() = 0;
virtual void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {}
virtual void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, CRect r) {}
virtual void InvalidateTextureCache() {}
void Move();
void Write(BYTE* mem, int len);
void Read(BYTE* mem, int len);
void SoftReset(BYTE mask);
void WriteCSR(UINT32 csr) {CSR->ai32[1] = csr;}
void ReadFIFO(BYTE* mem, int size);
template<int index> void Transfer(BYTE* mem, UINT32 size);
int Freeze(GSFreezeData* fd, bool sizeonly);
int Defrost(const GSFreezeData* fd);
void GetLastTag(UINT32* tag) {*tag = m_path3hack; m_path3hack = 0;}
virtual void SetGameCRC(DWORD crc, int options);
void SetFrameSkip(int frameskip);
};

263
plugins/GSdx/GSTables.cpp Normal file
View File

@ -0,0 +1,263 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSTables.h"
const BYTE blockTable32[4][8] = {
{ 0, 1, 4, 5, 16, 17, 20, 21},
{ 2, 3, 6, 7, 18, 19, 22, 23},
{ 8, 9, 12, 13, 24, 25, 28, 29},
{ 10, 11, 14, 15, 26, 27, 30, 31}
};
const BYTE blockTable32Z[4][8] = {
{ 24, 25, 28, 29, 8, 9, 12, 13},
{ 26, 27, 30, 31, 10, 11, 14, 15},
{ 16, 17, 20, 21, 0, 1, 4, 5},
{ 18, 19, 22, 23, 2, 3, 6, 7}
};
const BYTE blockTable16[8][4] = {
{ 0, 2, 8, 10 },
{ 1, 3, 9, 11 },
{ 4, 6, 12, 14 },
{ 5, 7, 13, 15 },
{ 16, 18, 24, 26 },
{ 17, 19, 25, 27 },
{ 20, 22, 28, 30 },
{ 21, 23, 29, 31 }
};
const BYTE blockTable16S[8][4] = {
{ 0, 2, 16, 18 },
{ 1, 3, 17, 19 },
{ 8, 10, 24, 26 },
{ 9, 11, 25, 27 },
{ 4, 6, 20, 22 },
{ 5, 7, 21, 23 },
{ 12, 14, 28, 30 },
{ 13, 15, 29, 31 }
};
const BYTE blockTable16Z[8][4] = {
{ 24, 26, 16, 18 },
{ 25, 27, 17, 19 },
{ 28, 30, 20, 22 },
{ 29, 31, 21, 23 },
{ 8, 10, 0, 2 },
{ 9, 11, 1, 3 },
{ 12, 14, 4, 6 },
{ 13, 15, 5, 7 }
};
const BYTE blockTable16SZ[8][4] = {
{ 24, 26, 8, 10 },
{ 25, 27, 9, 11 },
{ 16, 18, 0, 2 },
{ 17, 19, 1, 3 },
{ 28, 30, 12, 14 },
{ 29, 31, 13, 15 },
{ 20, 22, 4, 6 },
{ 21, 23, 5, 7 }
};
const BYTE blockTable8[4][8] = {
{ 0, 1, 4, 5, 16, 17, 20, 21},
{ 2, 3, 6, 7, 18, 19, 22, 23},
{ 8, 9, 12, 13, 24, 25, 28, 29},
{ 10, 11, 14, 15, 26, 27, 30, 31}
};
const BYTE blockTable4[8][4] = {
{ 0, 2, 8, 10 },
{ 1, 3, 9, 11 },
{ 4, 6, 12, 14 },
{ 5, 7, 13, 15 },
{ 16, 18, 24, 26 },
{ 17, 19, 25, 27 },
{ 20, 22, 28, 30 },
{ 21, 23, 29, 31 }
};
const BYTE columnTable32[8][8] = {
{ 0, 1, 4, 5, 8, 9, 12, 13 },
{ 2, 3, 6, 7, 10, 11, 14, 15 },
{ 16, 17, 20, 21, 24, 25, 28, 29 },
{ 18, 19, 22, 23, 26, 27, 30, 31 },
{ 32, 33, 36, 37, 40, 41, 44, 45 },
{ 34, 35, 38, 39, 42, 43, 46, 47 },
{ 48, 49, 52, 53, 56, 57, 60, 61 },
{ 50, 51, 54, 55, 58, 59, 62, 63 },
};
const BYTE columnTable16[8][16] = {
{ 0, 2, 8, 10, 16, 18, 24, 26,
1, 3, 9, 11, 17, 19, 25, 27 },
{ 4, 6, 12, 14, 20, 22, 28, 30,
5, 7, 13, 15, 21, 23, 29, 31 },
{ 32, 34, 40, 42, 48, 50, 56, 58,
33, 35, 41, 43, 49, 51, 57, 59 },
{ 36, 38, 44, 46, 52, 54, 60, 62,
37, 39, 45, 47, 53, 55, 61, 63 },
{ 64, 66, 72, 74, 80, 82, 88, 90,
65, 67, 73, 75, 81, 83, 89, 91 },
{ 68, 70, 76, 78, 84, 86, 92, 94,
69, 71, 77, 79, 85, 87, 93, 95 },
{ 96, 98, 104, 106, 112, 114, 120, 122,
97, 99, 105, 107, 113, 115, 121, 123 },
{ 100, 102, 108, 110, 116, 118, 124, 126,
101, 103, 109, 111, 117, 119, 125, 127 },
};
const BYTE columnTable8[16][16] = {
{ 0, 4, 16, 20, 32, 36, 48, 52, // column 0
2, 6, 18, 22, 34, 38, 50, 54 },
{ 8, 12, 24, 28, 40, 44, 56, 60,
10, 14, 26, 30, 42, 46, 58, 62 },
{ 33, 37, 49, 53, 1, 5, 17, 21,
35, 39, 51, 55, 3, 7, 19, 23 },
{ 41, 45, 57, 61, 9, 13, 25, 29,
43, 47, 59, 63, 11, 15, 27, 31 },
{ 96, 100, 112, 116, 64, 68, 80, 84, // column 1
98, 102, 114, 118, 66, 70, 82, 86 },
{ 104, 108, 120, 124, 72, 76, 88, 92,
106, 110, 122, 126, 74, 78, 90, 94 },
{ 65, 69, 81, 85, 97, 101, 113, 117,
67, 71, 83, 87, 99, 103, 115, 119 },
{ 73, 77, 89, 93, 105, 109, 121, 125,
75, 79, 91, 95, 107, 111, 123, 127 },
{ 128, 132, 144, 148, 160, 164, 176, 180, // column 2
130, 134, 146, 150, 162, 166, 178, 182 },
{ 136, 140, 152, 156, 168, 172, 184, 188,
138, 142, 154, 158, 170, 174, 186, 190 },
{ 161, 165, 177, 181, 129, 133, 145, 149,
163, 167, 179, 183, 131, 135, 147, 151 },
{ 169, 173, 185, 189, 137, 141, 153, 157,
171, 175, 187, 191, 139, 143, 155, 159 },
{ 224, 228, 240, 244, 192, 196, 208, 212, // column 3
226, 230, 242, 246, 194, 198, 210, 214 },
{ 232, 236, 248, 252, 200, 204, 216, 220,
234, 238, 250, 254, 202, 206, 218, 222 },
{ 193, 197, 209, 213, 225, 229, 241, 245,
195, 199, 211, 215, 227, 231, 243, 247 },
{ 201, 205, 217, 221, 233, 237, 249, 253,
203, 207, 219, 223, 235, 239, 251, 255 },
};
const WORD columnTable4[16][32] = {
{ 0, 8, 32, 40, 64, 72, 96, 104, // column 0
2, 10, 34, 42, 66, 74, 98, 106,
4, 12, 36, 44, 68, 76, 100, 108,
6, 14, 38, 46, 70, 78, 102, 110 },
{ 16, 24, 48, 56, 80, 88, 112, 120,
18, 26, 50, 58, 82, 90, 114, 122,
20, 28, 52, 60, 84, 92, 116, 124,
22, 30, 54, 62, 86, 94, 118, 126 },
{ 65, 73, 97, 105, 1, 9, 33, 41,
67, 75, 99, 107, 3, 11, 35, 43,
69, 77, 101, 109, 5, 13, 37, 45,
71, 79, 103, 111, 7, 15, 39, 47 },
{ 81, 89, 113, 121, 17, 25, 49, 57,
83, 91, 115, 123, 19, 27, 51, 59,
85, 93, 117, 125, 21, 29, 53, 61,
87, 95, 119, 127, 23, 31, 55, 63 },
{ 192, 200, 224, 232, 128, 136, 160, 168, // column 1
194, 202, 226, 234, 130, 138, 162, 170,
196, 204, 228, 236, 132, 140, 164, 172,
198, 206, 230, 238, 134, 142, 166, 174 },
{ 208, 216, 240, 248, 144, 152, 176, 184,
210, 218, 242, 250, 146, 154, 178, 186,
212, 220, 244, 252, 148, 156, 180, 188,
214, 222, 246, 254, 150, 158, 182, 190 },
{ 129, 137, 161, 169, 193, 201, 225, 233,
131, 139, 163, 171, 195, 203, 227, 235,
133, 141, 165, 173, 197, 205, 229, 237,
135, 143, 167, 175, 199, 207, 231, 239 },
{ 145, 153, 177, 185, 209, 217, 241, 249,
147, 155, 179, 187, 211, 219, 243, 251,
149, 157, 181, 189, 213, 221, 245, 253,
151, 159, 183, 191, 215, 223, 247, 255 },
{ 256, 264, 288, 296, 320, 328, 352, 360, // column 2
258, 266, 290, 298, 322, 330, 354, 362,
260, 268, 292, 300, 324, 332, 356, 364,
262, 270, 294, 302, 326, 334, 358, 366 },
{ 272, 280, 304, 312, 336, 344, 368, 376,
274, 282, 306, 314, 338, 346, 370, 378,
276, 284, 308, 316, 340, 348, 372, 380,
278, 286, 310, 318, 342, 350, 374, 382 },
{ 321, 329, 353, 361, 257, 265, 289, 297,
323, 331, 355, 363, 259, 267, 291, 299,
325, 333, 357, 365, 261, 269, 293, 301,
327, 335, 359, 367, 263, 271, 295, 303 },
{ 337, 345, 369, 377, 273, 281, 305, 313,
339, 347, 371, 379, 275, 283, 307, 315,
341, 349, 373, 381, 277, 285, 309, 317,
343, 351, 375, 383, 279, 287, 311, 319 },
{ 448, 456, 480, 488, 384, 392, 416, 424, // column 3
450, 458, 482, 490, 386, 394, 418, 426,
452, 460, 484, 492, 388, 396, 420, 428,
454, 462, 486, 494, 390, 398, 422, 430 },
{ 464, 472, 496, 504, 400, 408, 432, 440,
466, 474, 498, 506, 402, 410, 434, 442,
468, 476, 500, 508, 404, 412, 436, 444,
470, 478, 502, 510, 406, 414, 438, 446 },
{ 385, 393, 417, 425, 449, 457, 481, 489,
387, 395, 419, 427, 451, 459, 483, 491,
389, 397, 421, 429, 453, 461, 485, 493,
391, 399, 423, 431, 455, 463, 487, 495 },
{ 401, 409, 433, 441, 465, 473, 497, 505,
403, 411, 435, 443, 467, 475, 499, 507,
405, 413, 437, 445, 469, 477, 501, 509,
407, 415, 439, 447, 471, 479, 503, 511 },
};
const BYTE clutTableT32I8[128] =
{
0, 1, 4, 5, 8, 9, 12, 13, 2, 3, 6, 7, 10, 11, 14, 15,
64, 65, 68, 69, 72, 73, 76, 77, 66, 67, 70, 71, 74, 75, 78, 79,
16, 17, 20, 21, 24, 25, 28, 29, 18, 19, 22, 23, 26, 27, 30, 31,
80, 81, 84, 85, 88, 89, 92, 93, 82, 83, 86, 87, 90, 91, 94, 95,
32, 33, 36, 37, 40, 41, 44, 45, 34, 35, 38, 39, 42, 43, 46, 47,
96, 97, 100, 101, 104, 105, 108, 109, 98, 99, 102, 103, 106, 107, 110, 111,
48, 49, 52, 53, 56, 57, 60, 61, 50, 51, 54, 55, 58, 59, 62, 63,
112, 113, 116, 117, 120, 121, 124, 125, 114, 115, 118, 119, 122, 123, 126, 127
};
const BYTE clutTableT32I4[16] =
{
0, 1, 4, 5, 8, 9, 12, 13,
2, 3, 6, 7, 10, 11, 14, 15
};
const BYTE clutTableT16I8[32] =
{
0, 2, 8, 10, 16, 18, 24, 26,
4, 6, 12, 14, 20, 22, 28, 30,
1, 3, 9, 11, 17, 19, 25, 27,
5, 7, 13, 15, 21, 23, 29, 31
};
const BYTE clutTableT16I4[16] =
{
0, 2, 8, 10, 16, 18, 24, 26,
4, 6, 12, 14, 20, 22, 28, 30
};

39
plugins/GSdx/GSTables.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
extern const BYTE blockTable32[4][8];
extern const BYTE blockTable32Z[4][8];
extern const BYTE blockTable16[8][4];
extern const BYTE blockTable16S[8][4];
extern const BYTE blockTable16Z[8][4];
extern const BYTE blockTable16SZ[8][4];
extern const BYTE blockTable8[4][8];
extern const BYTE blockTable4[8][4];
extern const BYTE columnTable32[8][8];
extern const BYTE columnTable16[8][16];
extern const BYTE columnTable8[16][16];
extern const WORD columnTable4[16][32];
extern const BYTE clutTableT32I8[128];
extern const BYTE clutTableT32I4[16];
extern const BYTE clutTableT16I8[32];
extern const BYTE clutTableT16I4[16];

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSTexture.h"

48
plugins/GSdx/GSTexture.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSVector.h"
class GSTexture
{
public:
GSVector2 m_scale;
public:
GSTexture() : m_scale(1, 1) {}
virtual ~GSTexture() {}
enum {None, RenderTarget, DepthStencil, Texture, Offscreen};
virtual operator bool() = 0;
virtual int GetType() const = 0;
virtual int GetWidth() const = 0;
virtual int GetHeight() const = 0;
virtual int GetFormat() const = 0;
virtual bool Update(const CRect& r, const void* data, int pitch) = 0;
virtual bool Map(BYTE** bits, int& pitch, const RECT* r = NULL) = 0;
virtual void Unmap() = 0;
virtual bool Save(CString fn, bool dds = false) = 0;
CSize GetSize() {return CSize(GetWidth(), GetHeight());}
};

View File

@ -0,0 +1,210 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSTexture10.h"
GSTexture10::GSTexture10()
{
memset(&m_desc, 0, sizeof(m_desc));
}
GSTexture10::GSTexture10(ID3D10Texture2D* texture)
: m_texture(texture)
{
ASSERT(m_texture);
m_texture->GetDevice(&m_dev);
m_texture->GetDesc(&m_desc);
}
GSTexture10::~GSTexture10()
{
}
GSTexture10::operator bool()
{
return !!m_texture;
}
int GSTexture10::GetType() const
{
if(m_desc.BindFlags & D3D10_BIND_RENDER_TARGET) return GSTexture::RenderTarget;
if(m_desc.BindFlags & D3D10_BIND_DEPTH_STENCIL) return GSTexture::DepthStencil;
if(m_desc.BindFlags & D3D10_BIND_SHADER_RESOURCE) return GSTexture::Texture;
if(m_desc.Usage == D3D10_USAGE_STAGING) return GSTexture::Offscreen;
return GSTexture::None;
}
int GSTexture10::GetWidth() const
{
return m_desc.Width;
}
int GSTexture10::GetHeight() const
{
return m_desc.Height;
}
int GSTexture10::GetFormat() const
{
return m_desc.Format;
}
bool GSTexture10::Update(const CRect& r, const void* data, int pitch)
{
if(m_dev && m_texture)
{
D3D10_BOX box = {r.left, r.top, 0, r.right, r.bottom, 1};
m_dev->UpdateSubresource(m_texture, 0, &box, data, pitch, 0);
return true;
}
return false;
}
bool GSTexture10::Map(BYTE** bits, int& pitch, const RECT* r)
{
if(m_texture)
{
D3D10_MAPPED_TEXTURE2D map;
if(SUCCEEDED(m_texture->Map(0, D3D10_MAP_READ_WRITE, 0, &map)))
{
*bits = (BYTE*)map.pData;
pitch = (int)map.RowPitch;
return true;
}
}
return false;
}
void GSTexture10::Unmap()
{
if(m_texture)
{
m_texture->Unmap(0);
}
}
bool GSTexture10::Save(CString fn, bool dds)
{
CComPtr<ID3D10Resource> res;
if(m_desc.BindFlags & D3D10_BIND_DEPTH_STENCIL)
{
HRESULT hr;
D3D10_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
m_texture->GetDesc(&desc);
desc.Usage = D3D10_USAGE_STAGING;
desc.BindFlags = 0;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_READ;
CComPtr<ID3D10Texture2D> src, dst;
hr = m_dev->CreateTexture2D(&desc, NULL, &src);
m_dev->CopyResource(src, m_texture);
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
hr = m_dev->CreateTexture2D(&desc, NULL, &dst);
D3D10_MAPPED_TEXTURE2D sm, dm;
hr = src->Map(0, D3D10_MAP_READ, 0, &sm);
hr = dst->Map(0, D3D10_MAP_WRITE, 0, &dm);
BYTE* s = (BYTE*)sm.pData;
BYTE* d = (BYTE*)dm.pData;
for(UINT y = 0; y < desc.Height; y++, s += sm.RowPitch, d += dm.RowPitch)
{
for(UINT x = 0; x < desc.Width; x++)
{
((UINT*)d)[x] = (UINT)(((float*)s)[x*2] * UINT_MAX);
}
}
src->Unmap(0);
dst->Unmap(0);
res = dst;
}
else
{
res = m_texture;
}
return SUCCEEDED(D3DX10SaveTextureToFile(res, dds ? D3DX10_IFF_DDS : D3DX10_IFF_BMP, fn));
}
ID3D10Texture2D* GSTexture10::operator->()
{
return m_texture;
}
GSTexture10::operator ID3D10Texture2D*()
{
return m_texture;
}
GSTexture10::operator ID3D10ShaderResourceView*()
{
if(!m_srv && m_dev && m_texture)
{
m_dev->CreateShaderResourceView(m_texture, NULL, &m_srv);
}
return m_srv;
}
GSTexture10::operator ID3D10RenderTargetView*()
{
ASSERT(m_dev);
if(!m_rtv && m_dev && m_texture)
{
m_dev->CreateRenderTargetView(m_texture, NULL, &m_rtv);
}
return m_rtv;
}
GSTexture10::operator ID3D10DepthStencilView*()
{
if(!m_dsv && m_dev && m_texture)
{
m_dev->CreateDepthStencilView(m_texture, NULL, &m_dsv);
}
return m_dsv;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSTexture.h"
class GSTexture10 : public GSTexture
{
CComPtr<ID3D10Device> m_dev;
CComPtr<ID3D10Texture2D> m_texture;
D3D10_TEXTURE2D_DESC m_desc;
CComPtr<ID3D10ShaderResourceView> m_srv;
CComPtr<ID3D10RenderTargetView> m_rtv;
CComPtr<ID3D10DepthStencilView> m_dsv;
public:
GSTexture10();
explicit GSTexture10(ID3D10Texture2D* texture);
virtual ~GSTexture10();
operator bool();
int GetType() const;
int GetWidth() const;
int GetHeight() const;
int GetFormat() const;
bool Update(const CRect& r, const void* data, int pitch);
bool Map(BYTE** bits, int& pitch, const RECT* r = NULL);
void Unmap();
bool Save(CString fn, bool dds = false);
ID3D10Texture2D* operator->(); // TODO: remove direct access
operator ID3D10Texture2D*();
operator ID3D10ShaderResourceView*();
operator ID3D10RenderTargetView*();
operator ID3D10DepthStencilView*();
};

184
plugins/GSdx/GSTexture7.cpp Normal file
View File

@ -0,0 +1,184 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSTexture7.h"
GSTexture7::GSTexture7()
: m_type(GSTexture::None)
{
memset(&m_desc, 0, sizeof(m_desc));
}
GSTexture7::GSTexture7(int type, IDirectDrawSurface7* system)
: m_type(type)
, m_system(system)
{
memset(&m_desc, 0, sizeof(m_desc));
m_desc.dwSize = sizeof(m_desc);
system->GetSurfaceDesc(&m_desc);
}
GSTexture7::GSTexture7(int type, IDirectDrawSurface7* system, IDirectDrawSurface7* video)
: m_type(type)
, m_system(system)
, m_video(video)
{
memset(&m_desc, 0, sizeof(m_desc));
m_desc.dwSize = sizeof(m_desc);
video->GetSurfaceDesc(&m_desc);
}
GSTexture7::~GSTexture7()
{
}
GSTexture7::operator bool()
{
return !!m_system;
}
int GSTexture7::GetType() const
{
return m_type;
}
int GSTexture7::GetWidth() const
{
return m_desc.dwWidth;
}
int GSTexture7::GetHeight() const
{
return m_desc.dwHeight;
}
int GSTexture7::GetFormat() const
{
return (int)m_desc.ddpfPixelFormat.dwFourCC;
}
bool GSTexture7::Update(const CRect& r, const void* data, int pitch)
{
HRESULT hr;
CRect r2 = r;
DDSURFACEDESC2 desc;
memset(&desc, 0, sizeof(desc));
desc.dwSize = sizeof(desc);
if(SUCCEEDED(hr = m_system->Lock(&r2, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL)))
{
BYTE* src = (BYTE*)data;
BYTE* dst = (BYTE*)desc.lpSurface;
int bytes = min(pitch, desc.lPitch);
for(int i = 0, j = r.Height(); i < j; i++, src += pitch, dst += desc.lPitch)
{
// memcpy(dst, src, bytes);
// HACK!!!
GSVector4i* s = (GSVector4i*)src;
GSVector4i* d = (GSVector4i*)dst;
int w = bytes >> 4;
for(int x = 0; x < w; x++)
{
GSVector4i c = s[x];
c = (c & 0xff00ff00) | ((c & 0x00ff0000) >> 16) | ((c & 0x000000ff) << 16);
d[x] = c;
}
}
hr = m_system->Unlock(&r2);
if(m_video)
{
hr = m_video->Blt(&r2, m_system, &r2, DDBLT_WAIT, NULL);
}
return true;
}
return false;
}
bool GSTexture7::Map(BYTE** bits, int& pitch, const RECT* r)
{
HRESULT hr;
CRect r2 = r;
DDSURFACEDESC2 desc;
if(SUCCEEDED(hr = m_system->Lock(&r2, &desc, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR, NULL)))
{
*bits = (BYTE*)desc.lpSurface;
pitch = (int)desc.lPitch;
m_lr = r;
return true;
}
return false;
}
void GSTexture7::Unmap()
{
HRESULT hr;
hr = m_system->Unlock(NULL);
if(m_video)
{
hr = m_video->Blt(&m_lr, m_system, &m_lr, DDBLT_WAIT, NULL);
}
}
bool GSTexture7::Save(CString fn, bool dds)
{
// TODO
return false;
}
IDirectDrawSurface7* GSTexture7::operator->()
{
return m_video ? m_video : m_system;
}
GSTexture7::operator IDirectDrawSurface7*()
{
return m_video ? m_video : m_system;
}

55
plugins/GSdx/GSTexture7.h Normal file
View File

@ -0,0 +1,55 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSTexture.h"
#include <ddraw.h>
class GSTexture7 : public GSTexture
{
int m_type;
CComPtr<IDirectDrawSurface7> m_system;
CComPtr<IDirectDrawSurface7> m_video;
DDSURFACEDESC2 m_desc;
CRect m_lr;
public:
GSTexture7();
explicit GSTexture7(int type, IDirectDrawSurface7* system);
GSTexture7(int type, IDirectDrawSurface7* system, IDirectDrawSurface7* video);
virtual ~GSTexture7();
operator bool();
int GetType() const;
int GetWidth() const;
int GetHeight() const;
int GetFormat() const;
bool Update(const CRect& r, const void* data, int pitch);
bool Map(BYTE** bits, int& pitch, const RECT* r = NULL);
void Unmap();
bool Save(CString fn, bool dds = false);
IDirectDrawSurface7* operator->(); // TODO: remove direct access
operator IDirectDrawSurface7*();
};

224
plugins/GSdx/GSTexture9.cpp Normal file
View File

@ -0,0 +1,224 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSTexture9.h"
GSTexture9::GSTexture9()
{
memset(&m_desc, 0, sizeof(m_desc));
}
GSTexture9::GSTexture9(IDirect3DSurface9* surface)
{
m_surface = surface;
surface->GetDevice(&m_dev);
surface->GetDesc(&m_desc);
if(m_desc.Type != D3DRTYPE_SURFACE)
{
HRESULT hr = surface->GetContainer(__uuidof(IDirect3DTexture9), (void**)&m_texture);
ASSERT(SUCCEEDED(hr));
}
}
GSTexture9::GSTexture9(IDirect3DTexture9* texture)
{
m_texture = texture;
texture->GetDevice(&m_dev);
texture->GetLevelDesc(0, &m_desc);
texture->GetSurfaceLevel(0, &m_surface);
}
GSTexture9::~GSTexture9()
{
}
GSTexture9::operator bool()
{
return !!m_surface;
}
int GSTexture9::GetType() const
{
if(m_desc.Usage & D3DUSAGE_RENDERTARGET) return GSTexture::RenderTarget;
if(m_desc.Usage & D3DUSAGE_DEPTHSTENCIL) return GSTexture::DepthStencil;
if(m_desc.Pool == D3DPOOL_MANAGED) return GSTexture::Texture;
if(m_desc.Pool == D3DPOOL_SYSTEMMEM) return GSTexture::Offscreen;
return GSTexture::None;
}
int GSTexture9::GetWidth() const
{
return m_desc.Width;
}
int GSTexture9::GetHeight() const
{
return m_desc.Height;
}
int GSTexture9::GetFormat() const
{
return m_desc.Format;
}
bool GSTexture9::Update(const CRect& r, const void* data, int pitch)
{
if(CComPtr<IDirect3DSurface9> surface = *this)
{
D3DLOCKED_RECT lr;
if(SUCCEEDED(surface->LockRect(&lr, r, 0)))
{
BYTE* src = (BYTE*)data;
BYTE* dst = (BYTE*)lr.pBits;
int bytes = min(pitch, lr.Pitch);
for(int i = 0, j = r.Height(); i < j; i++, src += pitch, dst += lr.Pitch)
{
memcpy(dst, src, bytes);
}
surface->UnlockRect();
return true;
}
}
return false;
}
bool GSTexture9::Map(BYTE** bits, int& pitch, const RECT* r)
{
HRESULT hr;
if(CComPtr<IDirect3DSurface9> surface = *this)
{
D3DLOCKED_RECT lr;
if(SUCCEEDED(hr = surface->LockRect(&lr, r, 0)))
{
*bits = (BYTE*)lr.pBits;
pitch = (int)lr.Pitch;
return true;
}
}
return false;
}
void GSTexture9::Unmap()
{
if(CComPtr<IDirect3DSurface9> surface = *this)
{
surface->UnlockRect();
}
}
bool GSTexture9::Save(CString fn, bool dds)
{
CComPtr<IDirect3DResource9> res;
if(m_desc.Usage & D3DUSAGE_DEPTHSTENCIL)
{
HRESULT hr;
D3DSURFACE_DESC desc;
m_surface->GetDesc(&desc);
if(desc.Format != D3DFMT_D32F_LOCKABLE)
return false;
CComPtr<IDirect3DSurface9> surface;
hr = m_dev->CreateOffscreenPlainSurface(desc.Width, desc.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, NULL);
D3DLOCKED_RECT slr, dlr;
hr = m_surface->LockRect(&slr, NULL, 0);
hr = surface->LockRect(&dlr, NULL, 0);
BYTE* s = (BYTE*)slr.pBits;
BYTE* d = (BYTE*)dlr.pBits;
for(UINT y = 0; y < desc.Height; y++, s += slr.Pitch, d += dlr.Pitch)
{
for(UINT x = 0; x < desc.Width; x++)
{
((float*)d)[x] = ((float*)s)[x];
}
}
m_surface->UnlockRect();
surface->UnlockRect();
res = surface;
}
else
{
res = m_surface;
}
if(CComQIPtr<IDirect3DSurface9> surface = res)
{
return SUCCEEDED(D3DXSaveSurfaceToFile(fn, dds ? D3DXIFF_DDS : D3DXIFF_BMP, surface, NULL, NULL));
}
if(CComQIPtr<IDirect3DTexture9> texture = res)
{
return SUCCEEDED(D3DXSaveTextureToFile(fn, dds ? D3DXIFF_DDS : D3DXIFF_BMP, texture, NULL));
}
return false;
}
IDirect3DTexture9* GSTexture9::operator->()
{
return m_texture;
}
GSTexture9::operator IDirect3DSurface9*()
{
if(m_texture && !m_surface)
{
m_texture->GetSurfaceLevel(0, &m_surface);
}
return m_surface;
}
GSTexture9::operator IDirect3DTexture9*()
{
if(m_surface && !m_texture)
{
m_surface->GetContainer(__uuidof(IDirect3DTexture9), (void**)&m_texture);
ASSERT(m_texture);
}
return m_texture;
}

54
plugins/GSdx/GSTexture9.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSTexture.h"
class GSTexture9 : public GSTexture
{
CComPtr<IDirect3DDevice9> m_dev;
CComPtr<IDirect3DSurface9> m_surface;
CComPtr<IDirect3DTexture9> m_texture;
D3DSURFACE_DESC m_desc;
public:
GSTexture9();
explicit GSTexture9(IDirect3DSurface9* surface);
explicit GSTexture9(IDirect3DTexture9* texture);
virtual ~GSTexture9();
operator bool();
int GetType() const;
int GetWidth() const;
int GetHeight() const;
int GetFormat() const;
bool Update(const CRect& r, const void* data, int pitch);
bool Map(BYTE** bits, int& pitch, const RECT* r = NULL);
void Unmap();
bool Save(CString fn, bool dds = false);
IDirect3DTexture9* operator->(); // TODO: remove direct access
operator IDirect3DSurface9*();
operator IDirect3DTexture9*();
};

View File

@ -0,0 +1,23 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSTextureCache.h"

View File

@ -0,0 +1,816 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRenderer.h"
template<class Device> class GSTextureCache
{
typedef typename Device::Texture Texture;
public:
class GSSurface
{
protected:
GSRenderer<Device>* m_renderer;
typedef typename Device::Texture Texture;
public:
Texture m_texture;
Texture 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;
}
virtual ~GSSurface()
{
m_renderer->m_dev.Recycle(m_texture);
m_renderer->m_dev.Recycle(m_palette);
}
virtual void Update()
{
m_age = 0;
}
};
class GSRenderTarget : public GSSurface
{
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);
}
virtual void Read(CRect r) = 0;
};
class GSDepthStencil : public GSSurface
{
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);
}
};
class GSTexture : public GSSurface
{
protected:
bool GetDirtyRect(CRect& rr)
{
int w = 1 << m_TEX0.TW;
int h = 1 << m_TEX0.TH;
CRect r(0, 0, w, h);
POSITION pos = m_dirty.GetHeadPosition();
while(pos)
{
const CRect& dirty = m_dirty.GetNext(pos).GetDirtyRect(m_TEX0) & r;
if(!(m_valid & dirty).IsRectEmpty())
{
// find the rect having the largest area, outside dirty, inside m_valid
CRect left(m_valid.left, m_valid.top, min(m_valid.right, dirty.left), m_valid.bottom);
CRect top(m_valid.left, m_valid.top, m_valid.right, min(m_valid.bottom, dirty.top));
CRect right(max(m_valid.left, dirty.right), m_valid.top, m_valid.right, m_valid.bottom);
CRect bottom(m_valid.left, max(m_valid.top, dirty.bottom), m_valid.right, m_valid.bottom);
int leftsize = !left.IsRectEmpty() ? left.Width() * left.Height() : 0;
int topsize = !top.IsRectEmpty() ? top.Width() * top.Height() : 0;
int rightsize = !right.IsRectEmpty() ? right.Width() * right.Height() : 0;
int bottomsize = !bottom.IsRectEmpty() ? bottom.Width() * bottom.Height() : 0;
// TODO: sort
m_valid =
leftsize > 0 ? left :
topsize > 0 ? top :
rightsize > 0 ? right :
bottomsize > 0 ? bottom :
CRect(0, 0, 0, 0);
}
}
m_dirty.RemoveAll();
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 |= m_valid;
}
if(r.IsRectEmpty())
{
return false;
}
rr = r;
return true;
}
public:
GIFRegCLAMP m_CLAMP;
DWORD* m_clut; // *
CRect m_valid;
int m_bpp;
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 = (DWORD*)_aligned_malloc(256 * sizeof(DWORD), 16);
memset(m_clut, 0, sizeof(m_clut));
}
~GSTexture()
{
_aligned_free(m_clut);
}
virtual bool Create() = 0;
virtual bool Create(GSRenderTarget* rt) = 0;
virtual bool Create(GSDepthStencil* ds) = 0;
};
protected:
GSRenderer<Device>* m_renderer;
CAtlList<GSRenderTarget*> m_rt;
CAtlList<GSDepthStencil*> m_ds;
CAtlList<GSTexture*> m_tex;
template<class T> void RecycleByAge(CAtlList<T*>& l, int maxage = 60)
{
POSITION pos = l.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
T* t = l.GetNext(pos);
if(++t->m_age > maxage)
{
l.RemoveAt(cur);
delete t;
}
}
}
virtual GSRenderTarget* CreateRenderTarget() = 0;
virtual GSDepthStencil* CreateDepthStencil() = 0;
virtual GSTexture* CreateTexture() = 0;
public:
GSTextureCache(GSRenderer<Device>* renderer)
: m_renderer(renderer)
{
}
virtual ~GSTextureCache()
{
RemoveAll();
}
void RemoveAll()
{
while(m_rt.GetCount()) delete m_rt.RemoveHead();
while(m_ds.GetCount()) delete m_ds.RemoveHead();
while(m_tex.GetCount()) delete m_tex.RemoveHead();
}
GSRenderTarget* GetRenderTarget(const GIFRegTEX0& TEX0, int w, int h, bool fb = false)
{
GSRenderTarget* rt = NULL;
if(rt == NULL)
{
for(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos))
{
GSRenderTarget* rt2 = m_rt.GetAt(pos);
if(rt2->m_TEX0.TBP0 == TEX0.TBP0)
{
m_rt.MoveToHead(pos);
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(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos))
{
GSRenderTarget* rt2 = m_rt.GetAt(pos);
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.AddHead(rt);
}
if(m_renderer->CanUpscale())
{
int ww = (int)(m_renderer->GetFramePos().cx + rt->m_TEX0.TBW * 64);
int hh = (int)(m_renderer->GetFramePos().cy + m_renderer->GetDisplaySize().cy);
if(hh <= m_renderer->GetDeviceSize().cy / 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(POSITION pos = m_ds.GetHeadPosition(); pos; m_ds.GetNext(pos))
{
GSDepthStencil* ds2 = m_ds.GetAt(pos);
if(ds2->m_TEX0.TBP0 == TEX0.TBP0)
{
m_ds.MoveToHead(pos);
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.AddHead(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 DWORD* 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(POSITION pos = m_tex.GetHeadPosition(); pos; m_tex.GetNext(pos))
{
t = m_tex.GetAt(pos);
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.i64 == t->m_CLAMP.i64))
&& (pal == 0 || TEX0.CPSM == t->m_TEX0.CPSM && GSVector4i::compare(t->m_clut, clut, pal * sizeof(clut[0]))))
{
m_tex.MoveToHead(pos);
break;
}
}
t = NULL;
}
if(t == NULL)
{
for(POSITION pos = m_rt.GetHeadPosition(); pos; m_rt.GetNext(pos))
{
GSRenderTarget* rt = m_rt.GetAt(pos);
if(rt->m_dirty.IsEmpty() && 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.AddHead(t);
break;
}
}
}
if(t == NULL)
{
for(POSITION pos = m_ds.GetHeadPosition(); pos; m_ds.GetNext(pos))
{
GSDepthStencil* ds = m_ds.GetAt(pos);
if(ds->m_dirty.IsEmpty() && 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.AddHead(t);
break;
}
}
}
if(t == NULL)
{
t = CreateTexture();
if(!t->Create())
{
delete t;
return NULL;
}
m_tex.AddHead(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(CRect(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(CRect(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)
{
POSITION pos = m_tex.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSTexture* t = m_tex.GetNext(pos);
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.RemoveAt(cur);
delete t;
}
}
}
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r)
{
bool found = false;
POSITION pos = m_tex.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSTexture* t = m_tex.GetNext(pos);
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.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r));
found = true;
}
else
{
m_tex.RemoveAt(cur);
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.cy * offset / rowsize;
CRect 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.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r2));
}
}
}
}
}
pos = m_rt.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSRenderTarget* rt = m_rt.GetNext(pos);
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.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r));
rt->m_TEX0.TBW = BITBLTBUF.DBW;
}
else
{
m_rt.RemoveAt(cur);
delete rt;
continue;
}
}
if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, rt->m_TEX0.PSM) && BITBLTBUF.DBP < rt->m_TEX0.TBP0)
{
DWORD rowsize = BITBLTBUF.DBW * 8192;
DWORD offset = (DWORD)((rt->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.cy * offset / rowsize;
if(r.bottom >= y)
{
// TODO: do not add this rect above too
rt->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, CRect(r.left, r.top - y, r.right, r.bottom - y)));
rt->m_TEX0.TBW = BITBLTBUF.DBW;
continue;
}
}
}
}
// copypaste for ds
pos = m_ds.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSDepthStencil* ds = m_ds.GetNext(pos);
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.AddTail(GSDirtyRect(BITBLTBUF.DPSM, r));
ds->m_TEX0.TBW = BITBLTBUF.DBW;
}
else
{
m_ds.RemoveAt(cur);
delete ds;
continue;
}
}
if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, ds->m_TEX0.PSM) && BITBLTBUF.DBP < ds->m_TEX0.TBP0)
{
DWORD rowsize = BITBLTBUF.DBW * 8192;
DWORD offset = (DWORD)((ds->m_TEX0.TBP0 - BITBLTBUF.DBP) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.DPSM].pgs.cy * offset / rowsize;
if(r.bottom >= y)
{
// TODO: do not add this rect above too
ds->m_dirty.AddTail(GSDirtyRect(BITBLTBUF.DPSM, CRect(r.left, r.top - y, r.right, r.bottom - y)));
ds->m_TEX0.TBW = BITBLTBUF.DBW;
continue;
}
}
}
}
}
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r)
{
POSITION pos = m_rt.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSRenderTarget* rt = m_rt.GetNext(pos);
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(CRect(r.left, r.top, r.right, r.top + (r.bottom - r.top) * 2));
return;
}
else
{
m_rt.RemoveAt(cur);
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
DWORD rowsize = BITBLTBUF.SBW * 8192;
DWORD offset = (DWORD)((BITBLTBUF.SBP - rt->m_TEX0.TBP0) * 256);
if(rowsize > 0 && offset % rowsize == 0)
{
int y = m_renderer->m_mem.m_psm[BITBLTBUF.SPSM].pgs.cy * offset / rowsize;
if(y < ymin && y < 512)
{
rt2 = rt;
ymin = y;
}
}
}
}
if(rt2)
{
rt2->Read(CRect(r.left, r.top + ymin, r.right, r.bottom + ymin));
}
// TODO: ds
*/
}
void IncAge()
{
RecycleByAge(m_tex, 2);
RecycleByAge(m_rt);
RecycleByAge(m_ds);
}
};

View File

@ -0,0 +1,452 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSTextureCache10.h"
// GSTextureCache10
GSTextureCache10::GSTextureCache10(GSRenderer<GSDevice10>* renderer)
: GSTextureCache<GSDevice10>(renderer)
{
}
// GSRenderTargetHW10
void GSTextureCache10::GSRenderTargetHW10::Update()
{
__super::Update();
// FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :)
CRect r = m_dirty.GetDirtyRect(m_TEX0, m_texture.GetSize());
m_dirty.RemoveAll();
if(r.IsRectEmpty()) return;
int w = r.Width();
int h = r.Height();
static BYTE* buff = (BYTE*)_aligned_malloc(1024 * 1024 * 4, 16);
static int pitch = 1024 * 4;
GIFRegTEXA TEXA;
TEXA.AEM = 1;
TEXA.TA0 = 0;
TEXA.TA1 = 0x80;
GIFRegCLAMP CLAMP;
CLAMP.WMS = 0;
CLAMP.WMT = 0;
m_renderer->m_mem.ReadTexture(r, buff, pitch, m_TEX0, TEXA, CLAMP);
// s->m_perfmon.Put(GSPerfMon::Unswizzle, w * h * 4);
Texture texture;
if(!m_renderer->m_dev.CreateTexture(texture, w, h))
return;
texture.Update(CRect(0, 0, w, h), buff, pitch);
GSVector4 dr(
m_texture.m_scale.x * r.left,
m_texture.m_scale.y * r.top,
m_texture.m_scale.x * r.right,
m_texture.m_scale.y * r.bottom);
m_renderer->m_dev.StretchRect(texture, m_texture, dr);
m_renderer->m_dev.Recycle(texture);
}
void GSTextureCache10::GSRenderTargetHW10::Read(CRect r)
{
if(m_TEX0.PSM != PSM_PSMCT32
&& m_TEX0.PSM != PSM_PSMCT24
&& m_TEX0.PSM != PSM_PSMCT16
&& m_TEX0.PSM != PSM_PSMCT16S)
{
//ASSERT(0);
return;
}
if(!m_dirty.IsEmpty())
{
return;
}
TRACE(_T("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0);
// m_renderer->m_perfmon.Put(GSPerfMon::ReadRT, 1);
int w = r.Width();
int h = r.Height();
GSVector4 src;
src.x = m_texture.m_scale.x * r.left / m_texture.GetWidth();
src.y = m_texture.m_scale.y * r.top / m_texture.GetHeight();
src.z = m_texture.m_scale.x * r.right / m_texture.GetWidth();
src.w = m_texture.m_scale.y * r.bottom / m_texture.GetHeight();
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;
BYTE* bits;
int pitch;
if(offscreen.Map(&bits, pitch))
{
// TODO: block level write
DWORD bp = m_TEX0.TBP0;
DWORD 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)
{
DWORD 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], ((DWORD*)bits)[i]);
}
}
}
else if(m_TEX0.PSM == PSM_PSMCT24)
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
DWORD 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], ((DWORD*)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)
{
DWORD 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], ((WORD*)bits)[i]);
}
}
}
else
{
ASSERT(0);
}
offscreen.Unmap();
}
m_renderer->m_dev.Recycle(offscreen);
}
// GSDepthStencilHW10
void GSTextureCache10::GSDepthStencilHW10::Update()
{
__super::Update();
// TODO
}
// GSTextureHW10
bool GSTextureCache10::GSTextureHW10::Create()
{
// m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1);
m_TEX0 = m_renderer->m_context->TEX0;
m_CLAMP = m_renderer->m_context->CLAMP;
DWORD psm = m_TEX0.PSM;
switch(psm)
{
case PSM_PSMT8:
case PSM_PSMT8H:
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
psm = m_TEX0.CPSM;
break;
}
DXGI_FORMAT format;
switch(psm)
{
default:
TRACE(_T("Invalid TEX0.PSM/CPSM (%I64d, %I64d)\n"), m_TEX0.PSM, m_TEX0.CPSM);
case PSM_PSMCT32:
m_bpp = 32;
m_bpp2 = 0;
format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case PSM_PSMCT24:
m_bpp = 32;
m_bpp2 = 1;
format = DXGI_FORMAT_R8G8B8A8_UNORM;
break;
case PSM_PSMCT16:
case PSM_PSMCT16S:
m_bpp = 16;
m_bpp2 = 5;
format = DXGI_FORMAT_R16_UNORM;
break;
}
int w = 1 << m_TEX0.TW;
int h = 1 << m_TEX0.TH;
return m_renderer->m_dev.CreateTexture(m_texture, w, h, format);
}
bool GSTextureCache10::GSTextureHW10::Create(GSRenderTarget* rt)
{
rt->Update();
// m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1);
m_TEX0 = m_renderer->m_context->TEX0;
m_CLAMP = m_renderer->m_context->CLAMP;
m_rendered = true;
int tw = 1 << m_TEX0.TW;
int th = 1 << m_TEX0.TH;
int tp = (int)m_TEX0.TW << 6;
// 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);
// pitch conversion
if(rt->m_TEX0.TBW != m_TEX0.TBW) // && rt->m_TEX0.PSM == m_TEX0.PSM
{
// sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left)
// 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());
int bw = 64;
int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64;
int sw = (int)rt->m_TEX0.TBW << 6;
int dw = (int)m_TEX0.TBW << 6;
int dh = 1 << m_TEX0.TH;
if(sw != 0)
for(int dy = 0; dy < dh; dy += bh)
{
for(int dx = 0; dx < dw; dx += bw)
{
int o = dy * dw / bh + dx;
int sx = o % sw;
int sy = o / sw;
GSVector4 src, dst;
src.x = rt->m_texture.m_scale.x * sx / rt->m_texture.GetWidth();
src.y = rt->m_texture.m_scale.y * sy / rt->m_texture.GetHeight();
src.z = rt->m_texture.m_scale.x * (sx + bw) / rt->m_texture.GetWidth();
src.w = rt->m_texture.m_scale.y * (sy + bh) / rt->m_texture.GetHeight();
dst.x = rt->m_texture.m_scale.x * dx;
dst.y = rt->m_texture.m_scale.y * dy;
dst.z = rt->m_texture.m_scale.x * (dx + bw);
dst.w = rt->m_texture.m_scale.y * (dy + bh);
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
}
}
}
else if(tw < tp)
{
// FIXME: timesplitters blurs the render target by blending itself over a couple of times
if(tw == 256 && th == 128 && tp == 512 && (m_TEX0.TBP0 == 0 || m_TEX0.TBP0 == 0x00e00))
{
return false;
}
}
// width/height conversion
GSVector2 scale = rt->m_texture.m_scale;
GSVector4 dst(0, 0, w, h);
if(w > rt->m_texture.GetWidth())
{
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();
}
if(h > rt->m_texture.GetHeight())
{
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();
}
GSVector4 src(0, 0, w, h);
Texture* st;
Texture* dt;
Texture tmp;
if(!m_texture)
{
st = &rt->m_texture;
dt = &m_texture;
}
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);
}
else
{
src.z /= st->GetWidth();
src.w /= st->GetHeight();
m_renderer->m_dev.StretchRect(*st, src, *dt, dst);
}
if(tmp)
{
m_renderer->m_dev.Recycle(m_texture);
m_texture = tmp;
}
m_texture.m_scale = scale;
switch(m_TEX0.PSM)
{
case PSM_PSMCT32:
m_bpp2 = 0;
break;
case PSM_PSMCT24:
m_bpp2 = 1;
break;
case PSM_PSMCT16:
case PSM_PSMCT16S:
m_bpp2 = 2;
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_initpalette = true;
break;
case PSM_PSMT4HL:
case PSM_PSMT4HH:
ASSERT(0); // TODO
break;
}
return true;
}
bool GSTextureCache10::GSTextureHW10::Create(GSDepthStencil* ds)
{
m_rendered = true;
// TODO
return false;
}
void GSTextureCache10::GSTextureHW10::Update()
{
__super::Update();
if(m_rendered)
{
return;
}
CRect r;
if(!GetDirtyRect(r))
{
return;
}
m_valid |= r;
//TRACE(_T("GSTexture::Update %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0);
static BYTE* bits = (BYTE*)::_aligned_malloc(1024 * 1024 * 4, 16);
int pitch = 1024 * 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);
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSTextureCache.h"
#include "GSDevice10.h"
class GSTextureCache10 : public GSTextureCache<GSDevice10>
{
typedef GSDevice10::Texture Texture;
class GSRenderTargetHW10 : public GSRenderTarget
{
public:
explicit GSRenderTargetHW10(GSRenderer<GSDevice10>* renderer) : GSRenderTarget(renderer) {}
void Update();
void Read(CRect r);
};
class GSDepthStencilHW10 : public GSDepthStencil
{
public:
explicit GSDepthStencilHW10(GSRenderer<GSDevice10>* renderer) : GSDepthStencil(renderer) {}
void Update();
};
class GSTextureHW10 : public GSTexture
{
public:
explicit GSTextureHW10(GSRenderer<GSDevice10>* renderer) : GSTexture(renderer) {}
bool Create();
bool Create(GSRenderTarget* rt);
bool Create(GSDepthStencil* ds);
void Update();
};
protected:
GSRenderTarget* CreateRenderTarget() {return new GSRenderTargetHW10(m_renderer);}
GSDepthStencil* CreateDepthStencil() {return new GSDepthStencilHW10(m_renderer);}
GSTexture* CreateTexture() {return new GSTextureHW10(m_renderer);}
public:
GSTextureCache10(GSRenderer<GSDevice10>* renderer);
};

View File

@ -0,0 +1,453 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSTextureCache9.h"
// GSTextureCache9
GSTextureCache9::GSTextureCache9(GSRenderer<GSDevice9>* renderer)
: GSTextureCache<GSDevice9>(renderer)
{
}
// GSRenderTarget9
void GSTextureCache9::GSRenderTarget9::Update()
{
__super::Update();
// FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :)
CRect r = m_dirty.GetDirtyRect(m_TEX0, m_texture.GetSize());
m_dirty.RemoveAll();
if(r.IsRectEmpty()) return;
int w = r.Width();
int h = r.Height();
Texture texture;
if(!m_renderer->m_dev.CreateTexture(texture, w, h))
return;
BYTE* bits;
int pitch;
if(texture.Map(&bits, pitch))
{
GIFRegTEXA TEXA;
TEXA.AEM = 1;
TEXA.TA0 = 0;
TEXA.TA1 = 0x80;
GIFRegCLAMP CLAMP;
CLAMP.WMS = 0;
CLAMP.WMT = 0;
m_renderer->m_mem.ReadTexture(r, bits, pitch, m_TEX0, TEXA, CLAMP);
texture.Unmap();
// m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * 4);
GSVector4 dr(
m_texture.m_scale.x * r.left,
m_texture.m_scale.y * r.top,
m_texture.m_scale.x * r.right,
m_texture.m_scale.y * r.bottom);
m_renderer->m_dev.StretchRect(texture, m_texture, dr);
}
m_renderer->m_dev.Recycle(texture);
}
void GSTextureCache9::GSRenderTarget9::Read(CRect r)
{
if(m_TEX0.PSM != PSM_PSMCT32
&& m_TEX0.PSM != PSM_PSMCT24
&& m_TEX0.PSM != PSM_PSMCT16
&& m_TEX0.PSM != PSM_PSMCT16S)
{
//ASSERT(0);
return;
}
if(!m_dirty.IsEmpty())
{
return;
}
TRACE(_T("GSRenderTarget::Read %d,%d - %d,%d (%08x)\n"), r.left, r.top, r.right, r.bottom, m_TEX0.TBP0);
// m_renderer->m_perfmon.Put(GSPerfMon::ReadRT, 1);
int w = r.Width();
int h = r.Height();
GSVector4 src;
src.x = m_texture.m_scale.x * r.left / m_texture.GetWidth();
src.y = m_texture.m_scale.y * r.top / m_texture.GetHeight();
src.z = m_texture.m_scale.x * r.right / m_texture.GetWidth();
src.w = m_texture.m_scale.y * r.bottom / m_texture.GetHeight();
Texture offscreen;
if(!m_renderer->m_dev.CopyOffscreen(m_texture, src, offscreen, w, h))
return;
BYTE* bits;
int pitch;
if(offscreen.Map(&bits, pitch))
{
// TODO: block level write
DWORD bp = m_TEX0.TBP0;
DWORD 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)
{
DWORD 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], ((DWORD*)bits)[i]);
}
}
}
else if(m_TEX0.PSM == PSM_PSMCT24)
{
for(int y = r.top; y < r.bottom; y++, bits += pitch)
{
DWORD 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], ((DWORD*)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)
{
DWORD 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], ((DWORD*)bits)[i]);
}
}
}
else
{
ASSERT(0);
}
offscreen.Unmap();
}
m_renderer->m_dev.Recycle(offscreen);
}
// GSDepthStencil9
void GSTextureCache9::GSDepthStencil9::Update()
{
__super::Update();
// TODO
}
// GSTexture9
bool GSTextureCache9::GSTexture9::Create()
{
// m_renderer->m_perfmon.Put(GSPerfMon::WriteTexture, 1);
m_TEX0 = m_renderer->m_context->TEX0;
m_CLAMP = m_renderer->m_context->CLAMP;
DWORD psm = m_TEX0.PSM;
switch(psm)
{
case PSM_PSMT8:
case PSM_PSMT8H:
case PSM_PSMT4:
case PSM_PSMT4HL:
case PSM_PSMT4HH:
psm = m_TEX0.CPSM;
break;
}
D3DFORMAT format;
switch(psm)
{
default:
TRACE(_T("Invalid TEX0.PSM/CPSM (%I64d, %I64d)\n"), m_TEX0.PSM, m_TEX0.CPSM);
case PSM_PSMCT32:
m_bpp = 32;
m_bpp2 = 0;
format = D3DFMT_A8R8G8B8;
break;
case PSM_PSMCT24:
m_bpp = 32;
m_bpp2 = 1;
format = D3DFMT_A8R8G8B8;
break;
case PSM_PSMCT16:
case PSM_PSMCT16S:
m_bpp = 16;
m_bpp2 = 2;
format = D3DFMT_A1R5G5B5;
break;
}
int w = 1 << m_TEX0.TW;
int h = 1 << m_TEX0.TH;
return m_renderer->m_dev.CreateTexture(m_texture, w, h, format);
}
bool GSTextureCache9::GSTexture9::Create(GSRenderTarget* rt)
{
rt->Update();
// m_renderer->m_perfmon.Put(GSPerfMon::ConvertRT2T, 1);
m_TEX0 = m_renderer->m_context->TEX0;
m_CLAMP = m_renderer->m_context->CLAMP;
m_rendered = true;
int tw = 1 << m_TEX0.TW;
int th = 1 << m_TEX0.TH;
int tp = (int)m_TEX0.TW << 6;
// 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);
// pitch conversion
if(rt->m_TEX0.TBW != m_TEX0.TBW) // && rt->m_TEX0.PSM == m_TEX0.PSM
{
// sfex3 uses this trick (bw: 10 -> 5, wraps the right side below the left)
// 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());
int bw = 64;
int bh = m_TEX0.PSM == PSM_PSMCT32 || m_TEX0.PSM == PSM_PSMCT24 ? 32 : 64;
int sw = (int)rt->m_TEX0.TBW << 6;
int dw = (int)m_TEX0.TBW << 6;
int dh = 1 << m_TEX0.TH;
for(int dy = 0; dy < dh; dy += bh)
{
for(int dx = 0; dx < dw; dx += bw)
{
int o = dy * dw / bh + dx;
int sx = o % sw;
int sy = o / sw;
GSVector4 src, dst;
src.x = rt->m_texture.m_scale.x * sx / rt->m_texture.GetWidth();
src.y = rt->m_texture.m_scale.y * sy / rt->m_texture.GetHeight();
src.z = rt->m_texture.m_scale.x * (sx + bw) / rt->m_texture.GetWidth();
src.w = rt->m_texture.m_scale.y * (sy + bh) / rt->m_texture.GetHeight();
dst.x = rt->m_texture.m_scale.x * dx;
dst.y = rt->m_texture.m_scale.y * dy;
dst.z = rt->m_texture.m_scale.x * (dx + bw);
dst.w = rt->m_texture.m_scale.y * (dy + bh);
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
}
}
}
else if(tw < tp)
{
// FIXME: timesplitters blurs the render target by blending itself over a couple of times
if(tw == 256 && th == 128 && tp == 512 && (m_TEX0.TBP0 == 0 || m_TEX0.TBP0 == 0x00e00))
{
return false;
}
}
// width/height conversion
GSVector2 scale = rt->m_texture.m_scale;
GSVector4 dst(0, 0, w, h);
if(w > rt->m_texture.GetWidth())
{
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();
}
if(h > rt->m_texture.GetHeight())
{
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();
}
GSVector4 src(0, 0, w, h);
Texture* st;
Texture* dt;
Texture tmp;
if(!m_texture)
{
st = &rt->m_texture;
dt = &m_texture;
}
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)
{
CRect r(0, 0, w, h);
m_renderer->m_dev->StretchRect(*st, r, *dt, r, D3DTEXF_POINT);
}
else
{
src.z /= st->GetWidth();
src.w /= st->GetHeight();
m_renderer->m_dev.StretchRect(*st, src, *dt, dst);
}
if(tmp)
{
m_renderer->m_dev.Recycle(m_texture);
m_texture = tmp;
}
m_texture.m_scale = scale;
switch(m_TEX0.PSM)
{
case PSM_PSMCT32:
m_bpp2 = 0;
break;
case PSM_PSMCT24:
m_bpp2 = 1;
break;
case PSM_PSMCT16:
case PSM_PSMCT16S:
m_bpp2 = 2;
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_initpalette = true;
break;
case PSM_PSMT4HL:
case PSM_PSMT4HH:
ASSERT(0); // TODO
break;
}
return true;
}
bool GSTextureCache9::GSTexture9::Create(GSDepthStencil* ds)
{
m_rendered = true;
// TODO
return false;
}
void GSTextureCache9::GSTexture9::Update()
{
__super::Update();
if(m_rendered)
{
return;
}
CRect r;
if(!GetDirtyRect(r))
{
return;
}
m_valid |= r;
BYTE* bits;
int pitch;
if(m_texture.Map(&bits, pitch, &r))
{
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.Unmap();
}
m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * m_bpp >> 3);
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSTextureCache.h"
#include "GSDevice9.h"
class GSTextureCache9 : public GSTextureCache<GSDevice9>
{
typedef GSDevice9::Texture Texture;
class GSRenderTarget9 : public GSRenderTarget
{
public:
explicit GSRenderTarget9(GSRenderer<GSDevice9>* renderer) : GSRenderTarget(renderer) {}
void Update();
void Read(CRect r);
};
class GSDepthStencil9 : public GSDepthStencil
{
public:
explicit GSDepthStencil9(GSRenderer<GSDevice9>* renderer) : GSDepthStencil(renderer) {}
void Update();
};
class GSTexture9 : public GSTexture
{
public:
explicit GSTexture9(GSRenderer<GSDevice9>* renderer) : GSTexture(renderer) {}
bool Create();
bool Create(GSRenderTarget* rt);
bool Create(GSDepthStencil* ds);
void Update();
};
protected:
GSRenderTarget* CreateRenderTarget() {return new GSRenderTarget9(m_renderer);}
GSDepthStencil* CreateDepthStencil() {return new GSDepthStencil9(m_renderer);}
GSTexture* CreateTexture() {return new GSTexture9(m_renderer);}
public:
GSTextureCache9(GSRenderer<GSDevice9>* renderer);
};

View File

@ -0,0 +1,376 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "StdAfx.h"
#include "GSTextureCacheSW.h"
// static FILE* m_log = NULL;
GSTextureCacheSW::GSTextureCacheSW(GSState* state)
: m_state(state)
{
// m_log = _tfopen(_T("c:\\log.txt"), _T("w"));
}
GSTextureCacheSW::~GSTextureCacheSW()
{
// fclose(m_log);
RemoveAll();
}
const GSTextureCacheSW::GSTexture* GSTextureCacheSW::Lookup(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r)
{
GSLocalMemory& mem = m_state->m_mem;
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM];
const CAtlList<GSTexturePage*>& t2p = m_p2t[TEX0.TBP0 >> 5];
// fprintf(m_log, "lu %05x %d %d (%d) ", TEX0.TBP0, TEX0.TBW, TEX0.PSM, t2p.GetCount());
// if(r) fprintf(m_log, "(%d %d %d %d) ", r->left, r->top, r->right, r->bottom);
GSTexture* t = NULL;
POSITION pos = t2p.GetHeadPosition();
while(pos)
{
GSTexture* t2 = t2p.GetNext(pos)->t;
// if(t2->m_TEX0.TBP0 != TEX0.TBP0 || t2->m_TEX0.TBW != TEX0.TBW || t2->m_TEX0.PSM != TEX0.PSM || t2->m_TEX0.TW != TEX0.TW || t2->m_TEX0.TH != TEX0.TH)
if(((t2->m_TEX0.ai32[0] ^ TEX0.ai32[0]) | ((t2->m_TEX0.ai32[1] ^ TEX0.ai32[1]) & 3)) != 0)
{
continue;
}
if((psm.trbpp == 16 || psm.trbpp == 24) && (t2->m_TEX0.TCC != TEX0.TCC || TEX0.TCC == 1 && !(t2->m_TEXA == (GSVector4i)TEXA).alltrue()))
{
continue;
}
// fprintf(m_log, "cache hit\n");
t = t2;
t->m_age = 0;
break;
}
if(t == NULL)
{
// fprintf(m_log, "cache miss\n");
t = new GSTexture(m_state);
t->m_pos = m_textures.AddTail(t);
int tw = 1 << TEX0.TW;
int th = 1 << TEX0.TH;
DWORD bp = TEX0.TBP0;
DWORD bw = TEX0.TBW;
for(int j = 0, y = 0; y < th; j++, y += psm.pgs.cy)
{
DWORD page = psm.pgn(0, y, bp, bw);
for(int i = 0, x = 0; x < tw && page < MAX_PAGES; i++, x += psm.pgs.cx, page++)
{
GSTexturePage* p = new GSTexturePage();
p->t = t;
p->row = j;
p->col = i;
GSTexturePageEntry* p2te = new GSTexturePageEntry();
p2te->p2t = &m_p2t[page];
p2te->pos = m_p2t[page].AddHead(p);
t->m_p2te.AddTail(p2te);
t->m_maxpages++;
}
}
}
if(!t->Update(TEX0, TEXA, r))
{
m_textures.RemoveAt(t->m_pos);
delete t;
printf("!@#$%\n"); // memory allocation may fail if the game is too hungry
return NULL;
}
return t;
}
void GSTextureCacheSW::RemoveAll()
{
POSITION pos = m_textures.GetHeadPosition();
while(pos)
{
delete m_textures.GetNext(pos);
}
m_textures.RemoveAll();
for(int i = 0; i < MAX_PAGES; i++)
{
CAtlList<GSTexturePage*>& t2p = m_p2t[i];
ASSERT(t2p.IsEmpty());
POSITION pos = t2p.GetHeadPosition();
while(pos)
{
delete t2p.GetNext(pos);
}
t2p.RemoveAll();
}
}
void GSTextureCacheSW::IncAge()
{
POSITION pos = m_textures.GetHeadPosition();
while(pos)
{
POSITION cur = pos;
GSTexture* t = m_textures.GetNext(pos);
if(++t->m_age > 3)
{
m_textures.RemoveAt(cur);
delete t;
}
}
}
void GSTextureCacheSW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r)
{
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[BITBLTBUF.DPSM];
CRect r2;
r2.left = r.left & ~(psm.pgs.cx - 1);
r2.top = r.top & ~(psm.pgs.cy - 1);
r2.right = (r.right + (psm.pgs.cx - 1)) & ~(psm.pgs.cx - 1);
r2.bottom = (r.bottom + (psm.pgs.cy - 1)) & ~(psm.pgs.cy - 1);
DWORD bp = BITBLTBUF.DBP;
DWORD bw = BITBLTBUF.DBW;
// fprintf(m_log, "ivm %05x %d %d (%d %d %d %d)\n", bp, bw, BITBLTBUF.DPSM, r2.left, r2.top, r2.right, r2.bottom);
for(int y = r2.top; y < r2.bottom; y += psm.pgs.cy)
{
DWORD page = psm.pgn(r2.left, y, bp, bw);
for(int x = r2.left; x < r2.right && page < MAX_PAGES; x += psm.pgs.cx, page++)
{
const CAtlList<GSTexturePage*>& t2p = m_p2t[page];
POSITION pos = t2p.GetHeadPosition();
while(pos)
{
GSTexturePage* p = t2p.GetNext(pos);
DWORD flag = 1 << p->col;
if((p->t->m_valid[p->row] & flag) == 0)
{
continue;
}
if(GSUtil::HasSharedBits(BITBLTBUF.DPSM, p->t->m_TEX0.PSM))
{
p->t->m_valid[p->row] &= ~flag;
p->t->m_pages--;
// fprintf(m_log, "ivm hit %05x %d %d (%d %d) (%d)", p->t->m_TEX0.TBP0, p->t->m_TEX0.TBW, p->t->m_TEX0.PSM, p->row, p->col, p->t->m_pages);
// if(p->t->m_pages == 0) fprintf(m_log, " *");
// fprintf(m_log, "\n");
}
}
}
}
}
//
GSTextureCacheSW::GSTexture::GSTexture(GSState* state)
: m_state(state)
, m_buff(NULL)
, m_tw(0)
, m_maxpages(0)
, m_pages(0)
, m_pos(NULL)
, m_age(0)
{
memset(m_valid, 0, sizeof(m_valid));
}
GSTextureCacheSW::GSTexture::~GSTexture()
{
if(m_buff)
{
_aligned_free(m_buff);
}
POSITION pos = m_p2te.GetHeadPosition();
while(pos)
{
GSTexturePageEntry* p2te = m_p2te.GetNext(pos);
GSTexturePage* p = p2te->p2t->GetAt(p2te->pos);
ASSERT(p->t == this);
delete p;
p2te->p2t->RemoveAt(p2te->pos);
delete p2te;
}
m_p2te.RemoveAll();
}
bool GSTextureCacheSW::GSTexture::Update(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r)
{
if(m_pages == m_maxpages)
{
return true;
}
m_TEX0 = TEX0;
m_TEXA = TEXA;
GSLocalMemory& mem = m_state->m_mem;
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM];
int tw = 1 << TEX0.TW;
int th = 1 << TEX0.TH;
if(tw < psm.bs.cx) tw = psm.bs.cx;
if(th < psm.bs.cy) th = psm.bs.cy;
if(m_buff == NULL)
{
// fprintf(m_log, "up new (%d %d)\n", tw, th);
m_buff = _aligned_malloc(tw * th * sizeof(DWORD), 16);
if(m_buff == NULL)
{
return false;
}
m_tw = max(psm.pal > 0 ? 5 : 3, TEX0.TW); // makes one row 32 bytes at least, matches the smallest block size that is allocated above for m_buff
}
CRect r2;
if(r)
{
r2.left = r->left & ~(psm.pgs.cx - 1);
r2.top = r->top & ~(psm.pgs.cy - 1);
r2.right = (r->right + (psm.pgs.cx - 1)) & ~(psm.pgs.cx - 1);
r2.bottom = (r->bottom + (psm.pgs.cy - 1)) & ~(psm.pgs.cy - 1);
}
// TODO
GSLocalMemory::readTexture rt = psm.pal > 0 ? psm.rtxP : psm.rtx;
int bytes = psm.pal > 0 ? 1 : 4;
BYTE* dst = (BYTE*)m_buff;
DWORD pitch = (1 << m_tw) * bytes;
DWORD mask = pitch - 1;
for(int j = 0, y = 0; y < th; j++, y += psm.pgs.cy, dst += pitch * psm.pgs.cy)
{
if(m_valid[j] == mask)
{
continue;
}
if(r)
{
if(y < r2.top) continue;
if(y >= r2.bottom) break;
}
DWORD page = psm.pgn(0, y, TEX0.TBP0, TEX0.TBW);
for(int i = 0, x = 0; x < tw && page < MAX_PAGES; i++, x += psm.pgs.cx, page++)
{
if(r)
{
if(x < r2.left) continue;
if(x >= r2.right) break;
}
DWORD flag = 1 << i;
if(m_valid[j] & flag)
{
continue;
}
m_valid[j] |= flag;
m_pages++;
ASSERT(m_pages <= m_maxpages);
CRect r;
r.left = x;
r.top = y;
r.right = min(x + psm.pgs.cx, tw);
r.bottom = min(y + psm.pgs.cy, th);
// fprintf(m_log, "up fetch (%d %d) (%d %d %d %d)\n", j, i, r.left, r.top, r.right, r.bottom);
(mem.*rt)(r, &dst[x * bytes], pitch, TEX0, TEXA);
m_state->m_perfmon.Put(GSPerfMon::Unswizzle, r.Width() * r.Height() * bytes);
}
}
return true;
}

View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSRenderer.h"
#define MAX_PAGES 512
class GSTextureCacheSW
{
public:
class GSTexture;
class GSTexturePage;
class GSTexturePage
{
public:
GSTexture* t;
DWORD row, col;
};
class GSTexturePageEntry
{
public:
CAtlList<GSTexturePage*>* p2t;
POSITION pos;
};
class GSTexture
{
public:
GSState* m_state;
GIFRegTEX0 m_TEX0;
GIFRegTEXA m_TEXA;
void* m_buff;
DWORD m_tw;
DWORD m_valid[32];
DWORD m_maxpages;
DWORD m_pages;
CAtlList<GSTexturePageEntry*> m_p2te;
POSITION m_pos;
DWORD m_age;
explicit GSTexture(GSState* state);
virtual ~GSTexture();
bool Update(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r = NULL);
};
protected:
GSState* m_state;
CAtlList<GSTexture*> m_textures;
CAtlList<GSTexturePage*> m_p2t[MAX_PAGES];
public:
GSTextureCacheSW(GSState* state);
virtual ~GSTextureCacheSW();
const GSTexture* Lookup(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const CRect* r = NULL);
void RemoveAll();
void IncAge();
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const CRect& r);
};

View File

@ -0,0 +1,583 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSTextureFX10.h"
#include "resource.h"
GSTextureFX10::GSTextureFX10()
: m_dev(NULL)
, m_vb_max(0)
, m_vb_start(0)
, m_vb_count(0)
{
memset(&m_vs_cb_cache, 0, sizeof(m_vs_cb_cache));
memset(&m_ps_cb_cache, 0, sizeof(m_ps_cb_cache));
}
bool GSTextureFX10::Create(GSDevice10* dev)
{
m_dev = dev;
//
VSSelector sel;
sel.bppz = 0;
sel.tme = 0;
sel.fst = 0;
VSConstantBuffer cb;
SetupVS(sel, &cb); // creates layout
HRESULT hr;
D3D10_BUFFER_DESC bd;
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(VSConstantBuffer);
bd.Usage = D3D10_USAGE_DEFAULT;
bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_vs_cb);
if(FAILED(hr)) return false;
memset(&bd, 0, sizeof(bd));
bd.ByteWidth = sizeof(PSConstantBuffer);
bd.Usage = D3D10_USAGE_DEFAULT;
bd.BindFlags = D3D10_BIND_CONSTANT_BUFFER;
hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_ps_cb);
if(FAILED(hr)) return false;
D3D10_SAMPLER_DESC sd;
memset(&sd, 0, sizeof(sd));
sd.Filter = D3D10_ENCODE_BASIC_FILTER(D3D10_FILTER_TYPE_POINT, D3D10_FILTER_TYPE_POINT, D3D10_FILTER_TYPE_POINT, false);
sd.AddressU = D3D10_TEXTURE_ADDRESS_CLAMP;
sd.AddressV = D3D10_TEXTURE_ADDRESS_CLAMP;
sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
sd.MaxLOD = FLT_MAX;
sd.MaxAnisotropy = 16;
sd.ComparisonFunc = D3D10_COMPARISON_NEVER;
hr = (*m_dev)->CreateSamplerState(&sd, &m_palette_ss);
if(FAILED(hr)) return false;
//
return true;
}
bool GSTextureFX10::SetupIA(const GSVertexHW10* vertices, int count, D3D10_PRIMITIVE_TOPOLOGY prim)
{
HRESULT hr;
if(max(count * 3 / 2, 10000) > m_vb_max)
{
m_vb_old = m_vb;
m_vb = NULL;
m_vb_max = max(count * 2, 10000);
m_vb_start = 0;
m_vb_count = 0;
}
if(!m_vb)
{
D3D10_BUFFER_DESC bd;
memset(&bd, 0, sizeof(bd));
bd.Usage = D3D10_USAGE_DYNAMIC;
bd.ByteWidth = m_vb_max * sizeof(vertices[0]);
bd.BindFlags = D3D10_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
hr = (*m_dev)->CreateBuffer(&bd, NULL, &m_vb);
if(FAILED(hr)) return false;
}
GSVertexHW10* v = NULL;
int next = m_vb_start + m_vb_count;
if(next + count > m_vb_max)
{
if(SUCCEEDED(m_vb->Map(D3D10_MAP_WRITE_DISCARD, 0, (void**)&v)))
{
memcpy(v, vertices, count * sizeof(vertices[0]));
m_vb->Unmap();
}
m_vb_start = 0;
m_vb_count = count;
}
else
{
if(SUCCEEDED(m_vb->Map(D3D10_MAP_WRITE_NO_OVERWRITE, 0, (void**)&v)))
{
memcpy(&v[next], vertices, count * sizeof(vertices[0]));
m_vb->Unmap();
}
m_vb_start = next;
m_vb_count = count;
}
m_dev->IASetVertexBuffer(m_vb, sizeof(vertices[0]));
m_dev->IASetInputLayout(m_il);
m_dev->IASetPrimitiveTopology(prim);
return true;
}
bool GSTextureFX10::SetupVS(VSSelector sel, const VSConstantBuffer* cb)
{
CComPtr<ID3D10VertexShader> vs;
if(CRBMap<DWORD, CComPtr<ID3D10VertexShader> >::CPair* pair = m_vs.Lookup(sel))
{
vs = pair->m_value;
}
else
{
CStringA str[5];
str[0].Format("%d", sel.bpp);
str[1].Format("%d", sel.bppz);
str[2].Format("%d", sel.tme);
str[3].Format("%d", sel.fst);
str[4].Format("%d", sel.prim);
D3D10_SHADER_MACRO macro[] =
{
{"VS_BPP", str[0]},
{"VS_BPPZ", str[1]},
{"VS_TME", str[2]},
{"VS_FST", str[3]},
{"VS_PRIM", str[4]},
{NULL, NULL},
};
D3D10_INPUT_ELEMENT_DESC layout[] =
{
{"POSITION", 0, DXGI_FORMAT_R16G16_UINT, 0, 8, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"POSITION", 1, DXGI_FORMAT_R32_UINT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"TEXCOORD", 1, DXGI_FORMAT_R32_FLOAT, 0, 20, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 16, D3D10_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 1, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 28, D3D10_INPUT_PER_VERTEX_DATA, 0},
};
CComPtr<ID3D10InputLayout> il;
m_dev->CompileShader(IDR_TFX10_FX, "vs_main", macro, &vs, layout, countof(layout), &il);
if(m_il == NULL)
{
m_il = il;
}
m_vs.SetAt(sel, vs);
}
if(m_vs_cb_cache.Update(cb))
{
(*m_dev)->UpdateSubresource(m_vs_cb, 0, NULL, cb, 0, 0);
}
m_dev->VSSetShader(vs, m_vs_cb);
return true;
}
bool GSTextureFX10::SetupGS(GSSelector sel)
{
HRESULT hr;
CComPtr<ID3D10GeometryShader> gs;
if(sel.prim > 0 && (sel.iip == 0 || sel.prim == 3)) // geometry shader works in every case, but not needed
{
if(CRBMap<DWORD, CComPtr<ID3D10GeometryShader> >::CPair* pair = m_gs.Lookup(sel))
{
gs = pair->m_value;
}
else
{
CStringA str[2];
str[0].Format("%d", sel.iip);
str[1].Format("%d", sel.prim);
D3D10_SHADER_MACRO macro[] =
{
{"IIP", str[0]},
{"PRIM", str[1]},
{NULL, NULL},
};
hr = m_dev->CompileShader(IDR_TFX10_FX, "gs_main", macro, &gs);
m_gs.SetAt(sel, gs);
}
}
m_dev->GSSetShader(gs);
return true;
}
bool GSTextureFX10::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, ID3D10ShaderResourceView* tex, ID3D10ShaderResourceView* pal)
{
m_dev->PSSetShaderResources(tex, pal);
UpdatePS(sel, cb, ssel);
return true;
}
void GSTextureFX10::UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel)
{
HRESULT hr;
CComPtr<ID3D10PixelShader> ps;
if(CRBMap<DWORD, CComPtr<ID3D10PixelShader> >::CPair* pair = m_ps.Lookup(sel))
{
ps = pair->m_value;
}
else
{
CStringA str[13];
str[0].Format("%d", sel.fst);
str[1].Format("%d", sel.wms);
str[2].Format("%d", sel.wmt);
str[3].Format("%d", sel.bpp);
str[4].Format("%d", sel.aem);
str[5].Format("%d", sel.tfx);
str[6].Format("%d", sel.tcc);
str[7].Format("%d", sel.ate);
str[8].Format("%d", sel.atst);
str[9].Format("%d", sel.fog);
str[10].Format("%d", sel.clr1);
str[11].Format("%d", sel.fba);
str[12].Format("%d", sel.aout);
D3D10_SHADER_MACRO macro[] =
{
{"FST", str[0]},
{"WMS", str[1]},
{"WMT", str[2]},
{"BPP", str[3]},
{"AEM", str[4]},
{"TFX", str[5]},
{"TCC", str[6]},
{"ATE", str[7]},
{"ATST", str[8]},
{"FOG", str[9]},
{"CLR1", str[10]},
{"FBA", str[11]},
{"AOUT", str[12]},
{NULL, NULL},
};
hr = m_dev->CompileShader(IDR_TFX10_FX, "ps_main", macro, &ps);
m_ps.SetAt(sel, ps);
}
if(m_ps_cb_cache.Update(cb))
{
(*m_dev)->UpdateSubresource(m_ps_cb, 0, NULL, cb, 0, 0);
}
m_dev->PSSetShader(ps, m_ps_cb);
CComPtr<ID3D10SamplerState> ss0, ss1;
if(sel.tfx != 4)
{
if(sel.bpp >= 3 || sel.wms >= 3 || sel.wmt >= 3)
{
ssel.min = ssel.mag = 0;
}
if(CRBMap<DWORD, CComPtr<ID3D10SamplerState> >::CPair* pair = m_ps_ss.Lookup(ssel))
{
ss0 = pair->m_value;
}
else
{
D3D10_SAMPLER_DESC sd;
memset(&sd, 0, sizeof(sd));
sd.Filter = D3D10_ENCODE_BASIC_FILTER(
(ssel.min ? D3D10_FILTER_TYPE_LINEAR : D3D10_FILTER_TYPE_POINT),
(ssel.mag ? D3D10_FILTER_TYPE_LINEAR : D3D10_FILTER_TYPE_POINT),
D3D10_FILTER_TYPE_POINT,
false);
sd.AddressU = ssel.tau ? D3D10_TEXTURE_ADDRESS_WRAP : D3D10_TEXTURE_ADDRESS_CLAMP;
sd.AddressV = ssel.tav ? D3D10_TEXTURE_ADDRESS_WRAP : D3D10_TEXTURE_ADDRESS_CLAMP;
sd.AddressW = D3D10_TEXTURE_ADDRESS_CLAMP;
sd.MaxLOD = FLT_MAX;
sd.MaxAnisotropy = 16;
sd.ComparisonFunc = D3D10_COMPARISON_NEVER;
hr = (*m_dev)->CreateSamplerState(&sd, &ss0);
m_ps_ss.SetAt(ssel, ss0);
}
if(sel.bpp == 3)
{
ss1 = m_palette_ss;
}
}
m_dev->PSSetSamplerState(ss0, ss1);
}
void GSTextureFX10::SetupRS(UINT w, UINT h, const RECT& scissor)
{
m_dev->RSSet(w, h, &scissor);
}
void GSTextureFX10::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv)
{
UpdateOM(dssel, bsel, bf);
m_dev->OMSetRenderTargets(rtv, dsv);
}
void GSTextureFX10::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf)
{
HRESULT hr;
CComPtr<ID3D10DepthStencilState> dss;
if(CRBMap<DWORD, CComPtr<ID3D10DepthStencilState> >::CPair* pair = m_om_dss.Lookup(dssel))
{
dss = pair->m_value;
}
else
{
D3D10_DEPTH_STENCIL_DESC dsd;
memset(&dsd, 0, sizeof(dsd));
if(dssel.date)
{
dsd.StencilEnable = true;
dsd.StencilReadMask = 1;
dsd.StencilWriteMask = 1;
dsd.FrontFace.StencilFunc = D3D10_COMPARISON_EQUAL;
dsd.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
dsd.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
dsd.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
dsd.BackFace.StencilFunc = D3D10_COMPARISON_EQUAL;
dsd.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
dsd.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
dsd.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_KEEP;
}
if(!(dssel.zte && dssel.ztst == 1 && !dssel.zwe))
{
static const D3D10_COMPARISON_FUNC ztst[] =
{
D3D10_COMPARISON_NEVER,
D3D10_COMPARISON_ALWAYS,
D3D10_COMPARISON_GREATER_EQUAL,
D3D10_COMPARISON_GREATER
};
dsd.DepthEnable = dssel.zte;
dsd.DepthWriteMask = dssel.zwe ? D3D10_DEPTH_WRITE_MASK_ALL : D3D10_DEPTH_WRITE_MASK_ZERO;
dsd.DepthFunc = ztst[dssel.ztst];
}
hr = (*m_dev)->CreateDepthStencilState(&dsd, &dss);
m_om_dss.SetAt(dssel, dss);
}
m_dev->OMSetDepthStencilState(dss, 1);
CComPtr<ID3D10BlendState> bs;
if(CRBMap<DWORD, CComPtr<ID3D10BlendState> >::CPair* pair = m_om_bs.Lookup(bsel))
{
bs = pair->m_value;
}
else
{
D3D10_BLEND_DESC bd;
memset(&bd, 0, sizeof(bd));
bd.BlendEnable[0] = bsel.abe;
if(bsel.abe)
{
// (A:Cs/Cd/0 - B:Cs/Cd/0) * C:As/Ad/FIX + D:Cs/Cd/0
static const struct {int bogus; D3D10_BLEND_OP op; D3D10_BLEND src, dst;} map[3*3*3*3] =
{
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0000: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0001: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0002: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0010: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0011: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0012: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 0020: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 0021: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 0022: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // * 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_INV_SRC1_ALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As)
{0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As
{1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // * 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_INV_DEST_ALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad)
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad
{1, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // * 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_INV_BLEND_FACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F)
{0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F
{1, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // * 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1)
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As
{1, D3D10_BLEND_OP_ADD, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // * 0210: (Cs - 0)*Ad + Cs ==> Cs*(Ad + 1)
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad
{1, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // * 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1)
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As)
{1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // * 1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_SRC1_ALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad)
{1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // * 1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_DEST_ALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F)
{1, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR},// * 1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_BLEND_FACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1100: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1101: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1102: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1110: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1111: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1112: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 1120: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 1121: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 1122: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_SRC1_ALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As
{2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_SRC1_ALPHA}, // ** 1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_SRC1_ALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad
{2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_DEST_ALPHA}, // ** 1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad)
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_DEST_ALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F
{2, D3D10_BLEND_OP_ADD, D3D10_BLEND_DEST_COLOR, D3D10_BLEND_BLEND_FACTOR}, // ** 1221: (Cd - 0)*F + Cd ==> Cd*(1 + F)
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_BLEND_FACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As)
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_SRC1_ALPHA, D3D10_BLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_DEST_ALPHA, D3D10_BLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad)
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_DEST_ALPHA, D3D10_BLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_INV_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F)
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F
{0, D3D10_BLEND_OP_REV_SUBTRACT, D3D10_BLEND_BLEND_FACTOR, D3D10_BLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F
{0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_SRC1_ALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_SRC1_ALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As)
{0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ZERO, D3D10_BLEND_SRC1_ALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As
{0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_DEST_ALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad)
{0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_DEST_ALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad
{0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_INV_BLEND_FACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F)
{0, D3D10_BLEND_OP_SUBTRACT, D3D10_BLEND_ONE, D3D10_BLEND_BLEND_FACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2200: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2201: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2202: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2210: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2211: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2212: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ONE, D3D10_BLEND_ZERO}, // 2220: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ONE}, // 2221: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3D10_BLEND_OP_ADD, D3D10_BLEND_ZERO, D3D10_BLEND_ZERO}, // 2222: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
};
// bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021
// tricky: 1201, 1211, 1221
//
// Source.rgb = float3(1, 1, 1);
// 1201 Cd*(1 + As) => Source * Dest color + Dest * Source1 alpha
// 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha
// 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor
int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d;
bd.BlendOp = map[i].op;
bd.SrcBlend = map[i].src;
bd.DestBlend = map[i].dst;
bd.BlendOpAlpha = D3D10_BLEND_OP_ADD;
bd.SrcBlendAlpha = D3D10_BLEND_ONE;
bd.DestBlendAlpha = D3D10_BLEND_ZERO;
if(map[i].bogus == 1)
{
ASSERT(0);
(bsel.a == 0 ? bd.SrcBlend : bd.DestBlend) = D3D10_BLEND_ONE;
}
}
if(bsel.wr) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_RED;
if(bsel.wg) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_GREEN;
if(bsel.wb) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_BLUE;
if(bsel.wa) bd.RenderTargetWriteMask[0] |= D3D10_COLOR_WRITE_ENABLE_ALPHA;
hr = (*m_dev)->CreateBlendState(&bd, &bs);
m_om_bs.SetAt(bsel, bs);
}
m_dev->OMSetBlendState(bs, bf);
}
void GSTextureFX10::Draw()
{
m_dev->DrawPrimitive(m_vb_count, m_vb_start);
}

View File

@ -0,0 +1,248 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice10.h"
class GSTextureFX10
{
public:
#pragma pack(push, 1)
__declspec(align(16)) struct VSConstantBuffer
{
GSVector4 VertexScale;
GSVector4 VertexOffset;
GSVector2 TextureScale;
float _pad[2];
struct VSConstantBuffer() {memset(this, 0, sizeof(*this));}
__forceinline bool Update(const VSConstantBuffer* cb)
{
GSVector4i* a = (GSVector4i*)this;
GSVector4i* b = (GSVector4i*)cb;
GSVector4i b0 = b[0];
GSVector4i b1 = b[1];
GSVector4i b2 = b[2];
if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2)).alltrue())
{
a[0] = b0;
a[1] = b1;
a[2] = b2;
return true;
}
return false;
}
};
union VSSelector
{
struct
{
DWORD bpp:3;
DWORD bppz:2;
DWORD tme:1;
DWORD fst:1;
DWORD prim:3;
};
DWORD dw;
operator DWORD() {return dw & 0x3ff;}
};
__declspec(align(16)) struct PSConstantBuffer
{
GSVector4 FogColor;
float MINU;
float MAXU;
float MINV;
float MAXV;
DWORD UMSK;
DWORD UFIX;
DWORD VMSK;
DWORD VFIX;
float TA0;
float TA1;
float AREF;
float _pad[1];
GSVector2 WH;
GSVector2 rWrH;
struct PSConstantBuffer() {memset(this, 0, sizeof(*this));}
__forceinline bool Update(const PSConstantBuffer* cb)
{
GSVector4i* a = (GSVector4i*)this;
GSVector4i* b = (GSVector4i*)cb;
GSVector4i b0 = b[0];
GSVector4i b1 = b[1];
GSVector4i b2 = b[2];
GSVector4i b3 = b[3];
GSVector4i b4 = b[4];
if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2) & (a[3] == b3) & (a[4] == b4)).alltrue())
{
a[0] = b0;
a[1] = b1;
a[2] = b2;
a[3] = b3;
a[4] = b4;
return true;
}
return false;
}
};
union PSSelector
{
struct
{
DWORD fst:1;
DWORD wms:2;
DWORD wmt:2;
DWORD bpp:3;
DWORD aem:1;
DWORD tfx:3;
DWORD tcc:1;
DWORD ate:1;
DWORD atst:3;
DWORD fog:1;
DWORD clr1:1;
DWORD fba:1;
DWORD aout:1;
};
DWORD dw;
operator DWORD() {return dw & 0x1fffff;}
};
union GSSelector
{
struct
{
DWORD iip:1;
DWORD prim:2;
};
DWORD dw;
operator DWORD() {return dw & 0x7;}
};
union PSSamplerSelector
{
struct
{
DWORD tau:1;
DWORD tav:1;
DWORD min:1;
DWORD mag:1;
};
DWORD dw;
operator DWORD() {return dw & 0xf;}
};
union OMDepthStencilSelector
{
struct
{
DWORD zte:1;
DWORD ztst:2;
DWORD zwe:1;
DWORD date:1;
};
DWORD dw;
operator DWORD() {return dw & 0x1f;}
};
union OMBlendSelector
{
struct
{
DWORD abe:1;
DWORD a:2;
DWORD b:2;
DWORD c:2;
DWORD d:2;
DWORD wr:1;
DWORD wg:1;
DWORD wb:1;
DWORD wa:1;
};
DWORD dw;
operator DWORD() {return dw & 0x1fff;}
};
#pragma pack(pop)
private:
GSDevice10* m_dev;
CComPtr<ID3D10InputLayout> m_il;
CRBMapC<DWORD, CComPtr<ID3D10VertexShader> > m_vs;
CComPtr<ID3D10Buffer> m_vs_cb;
CRBMapC<DWORD, CComPtr<ID3D10GeometryShader> > m_gs;
CRBMapC<DWORD, CComPtr<ID3D10PixelShader> > m_ps;
CComPtr<ID3D10Buffer> m_ps_cb;
CRBMapC<DWORD, CComPtr<ID3D10SamplerState> > m_ps_ss;
CComPtr<ID3D10SamplerState> m_palette_ss;
CRBMapC<DWORD, CComPtr<ID3D10DepthStencilState> > m_om_dss;
CRBMapC<DWORD, CComPtr<ID3D10BlendState> > m_om_bs;
CComPtr<ID3D10Buffer> m_vb, m_vb_old;
int m_vb_max;
int m_vb_start;
int m_vb_count;
VSConstantBuffer m_vs_cb_cache;
PSConstantBuffer m_ps_cb_cache;
public:
GSTextureFX10();
bool Create(GSDevice10* dev);
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);
void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel);
void SetupRS(UINT w, UINT h, const RECT& scissor);
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf, ID3D10RenderTargetView* rtv, ID3D10DepthStencilView* dsv);
void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, float bf);
void Draw();
};

View File

@ -0,0 +1,464 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSTextureFX9.h"
#include "resource.h"
GSTextureFX9::GSTextureFX9()
: m_dev(NULL)
{
}
bool GSTextureFX9::Create(GSDevice9* dev)
{
m_dev = dev;
VSSelector sel;
sel.bppz = 0;
sel.tme = 0;
sel.fst = 0;
sel.logz = 0;
VSConstantBuffer cb;
SetupVS(sel, &cb); // creates layout
return true;
}
bool GSTextureFX9::CreateMskFix(GSTexture9& t, DWORD size, DWORD msk, DWORD fix)
{
DWORD hash = (size << 20) | (msk << 10) | fix;
if(CRBMap<DWORD, GSTexture9>::CPair* pair = m_mskfix.Lookup(hash))
{
t = pair->m_value;
}
else
{
if(!m_dev->CreateTexture(t, size, 1, D3DFMT_R32F))
{
return false;
}
BYTE* bits;
int pitch;
if(t.Map(&bits, pitch))
{
for(DWORD i = 0; i < size; i++)
{
((float*)bits)[i] = (float)((i & msk) | fix) / size;
}
t.Unmap();
}
m_mskfix.SetAt(hash, t);
}
return true;
}
bool GSTextureFX9::SetupIA(const GSVertexHW9* vertices, UINT count, D3DPRIMITIVETYPE prim)
{
m_dev->IASetVertexBuffer(count, vertices);
m_dev->IASetInputLayout(m_il);
m_dev->IASetPrimitiveTopology(prim);
return true;
}
bool GSTextureFX9::SetupVS(VSSelector sel, const VSConstantBuffer* cb)
{
CComPtr<IDirect3DVertexShader9> vs;
if(CRBMap<DWORD, CComPtr<IDirect3DVertexShader9> >::CPair* pair = m_vs.Lookup(sel))
{
vs = pair->m_value;
}
else
{
CStringA str[4];
str[0].Format("%d", sel.bppz);
str[1].Format("%d", sel.tme);
str[2].Format("%d", sel.fst);
str[3].Format("%d", sel.logz);
D3DXMACRO macro[] =
{
{"VS_BPPZ", str[0]},
{"VS_TME", str[1]},
{"VS_FST", str[2]},
{"VS_LOGZ", str[3]},
{NULL, NULL},
};
static const D3DVERTEXELEMENT9 layout[] =
{
{0, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
{0, 8, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0},
{0, 12, D3DDECLTYPE_D3DCOLOR, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1},
{0, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
D3DDECL_END()
};
CComPtr<IDirect3DVertexDeclaration9> il;
m_dev->CompileShader(IDR_TFX9_FX, "vs_main", macro, &vs, layout, countof(layout), &il);
if(m_il == NULL)
{
m_il = il;
}
m_vs.SetAt(sel, vs);
}
m_dev->VSSetShader(vs, (const float*)cb, sizeof(*cb) / sizeof(GSVector4));
return true;
}
bool GSTextureFX9::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, IDirect3DTexture9* tex, IDirect3DTexture9* pal, bool psrr)
{
m_dev->PSSetShaderResources(tex, pal);
if(tex && psrr)
{
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(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);
}
}
UpdatePS(sel, cb, ssel, psrr);
return true;
}
void GSTextureFX9::UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, bool psrr)
{
HRESULT hr;
if(!psrr)
{
if(sel.wms == 3) sel.wms = 0;
if(sel.wmt == 3) sel.wmt = 0;
}
CComPtr<IDirect3DPixelShader9> ps;
if(CRBMap<DWORD, CComPtr<IDirect3DPixelShader9> >::CPair* pair = m_ps.Lookup(sel))
{
ps = pair->m_value;
}
else
{
CStringA str[12];
str[0].Format("%d", sel.fst);
str[1].Format("%d", sel.wms);
str[2].Format("%d", sel.wmt);
str[3].Format("%d", sel.bpp);
str[4].Format("%d", sel.aem);
str[5].Format("%d", sel.tfx);
str[6].Format("%d", sel.tcc);
str[7].Format("%d", sel.ate);
str[8].Format("%d", sel.atst);
str[9].Format("%d", sel.fog);
str[10].Format("%d", sel.clr1);
str[11].Format("%d", sel.rt);
D3DXMACRO macro[] =
{
{"FST", str[0]},
{"WMS", str[1]},
{"WMT", str[2]},
{"BPP", str[3]},
{"AEM", str[4]},
{"TFX", str[5]},
{"TCC", str[6]},
{"ATE", str[7]},
{"ATST", str[8]},
{"FOG", str[9]},
{"CLR1", str[10]},
{"RT", str[11]},
{NULL, NULL},
};
hr = m_dev->CompileShader(IDR_TFX9_FX, "ps_main", macro, &ps);
m_ps.SetAt(sel, ps);
}
m_dev->PSSetShader(ps, (const float*)cb, sizeof(*cb) / sizeof(GSVector4));
Direct3DSamplerState9* ss = NULL;
if(sel.tfx != 4)
{
if(sel.bpp >= 3 || sel.wms >= 3 || sel.wmt >= 3)
{
ssel.min = ssel.mag = 0;
}
if(CRBMap<DWORD, Direct3DSamplerState9*>::CPair* pair = m_ps_ss.Lookup(ssel))
{
ss = pair->m_value;
}
else
{
ss = new Direct3DSamplerState9();
memset(ss, 0, sizeof(*ss));
ss->FilterMin[0] = ssel.min ? D3DTEXF_LINEAR : D3DTEXF_POINT;
ss->FilterMag[0] = ssel.mag ? D3DTEXF_LINEAR : D3DTEXF_POINT;
ss->FilterMin[1] = D3DTEXF_POINT;
ss->FilterMag[1] = D3DTEXF_POINT;
ss->AddressU = ssel.tau ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
ss->AddressV = ssel.tav ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP;
m_ps_ss.SetAt(ssel, ss);
}
}
m_dev->PSSetSamplerState(ss);
}
void GSTextureFX9::SetupRS(int w, int h, const RECT& scissor)
{
m_dev->RSSet(w, h, &scissor);
}
void GSTextureFX9::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf, IDirect3DSurface9* rt, IDirect3DSurface9* ds)
{
UpdateOM(dssel, bsel, bf);
m_dev->OMSetRenderTargets(rt, ds);
}
void GSTextureFX9::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf)
{
Direct3DDepthStencilState9* dss = NULL;
if(CRBMap<DWORD, Direct3DDepthStencilState9*>::CPair* pair = m_om_dss.Lookup(dssel))
{
dss = pair->m_value;
}
else
{
dss = new Direct3DDepthStencilState9();
memset(dss, 0, sizeof(*dss));
if(dssel.date || dssel.fba)
{
dss->StencilEnable = true;
dss->StencilReadMask = 1;
dss->StencilWriteMask = 2;
dss->StencilFunc = dssel.date ? D3DCMP_EQUAL : D3DCMP_ALWAYS;
dss->StencilPassOp = dssel.fba ? D3DSTENCILOP_REPLACE : D3DSTENCILOP_KEEP;
dss->StencilFailOp = dssel.fba ? D3DSTENCILOP_ZERO : D3DSTENCILOP_KEEP;
dss->StencilDepthFailOp = dssel.fba ? D3DSTENCILOP_ZERO : D3DSTENCILOP_KEEP;
}
if(!(dssel.zte && dssel.ztst == 1 && !dssel.zwe))
{
static const D3DCMPFUNC ztst[] =
{
D3DCMP_NEVER,
D3DCMP_ALWAYS,
D3DCMP_GREATEREQUAL,
D3DCMP_GREATER
};
dss->DepthEnable = dssel.zte;
dss->DepthWriteMask = dssel.zwe;
dss->DepthFunc = ztst[dssel.ztst];
}
m_om_dss.SetAt(dssel, dss);
}
m_dev->OMSetDepthStencilState(dss, 3);
Direct3DBlendState9* bs = NULL;
if(CRBMap<DWORD, Direct3DBlendState9*>::CPair* pair = m_om_bs.Lookup(bsel))
{
bs = pair->m_value;
}
else
{
bs = new Direct3DBlendState9();
memset(bs, 0, sizeof(*bs));
bs->BlendEnable = bsel.abe;
if(bsel.abe)
{
// (A:Cs/Cd/0 - B:Cs/Cd/0) * C:As/Ad/FIX + D:Cs/Cd/0
static const struct {int bogus; D3DBLENDOP op; D3DBLEND src, dst;} map[3*3*3*3] =
{
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0000: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0001: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0002: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0010: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0011: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0012: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 0020: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 0021: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 0022: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // * 0100: (Cs - Cd)*As + Cs ==> Cs*(As + 1) - Cd*As
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_INVSRCALPHA}, // 0101: (Cs - Cd)*As + Cd ==> Cs*As + Cd*(1 - As)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 0102: (Cs - Cd)*As + 0 ==> Cs*As - Cd*As
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // * 0110: (Cs - Cd)*Ad + Cs ==> Cs*(Ad + 1) - Cd*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_INVDESTALPHA}, // 0111: (Cs - Cd)*Ad + Cd ==> Cs*Ad + Cd*(1 - Ad)
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 0112: (Cs - Cd)*Ad + 0 ==> Cs*Ad - Cd*Ad
{1, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // * 0120: (Cs - Cd)*F + Cs ==> Cs*(F + 1) - Cd*F
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_INVBLENDFACTOR}, // 0121: (Cs - Cd)*F + Cd ==> Cs*F + Cd*(1 - F)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 0122: (Cs - Cd)*F + 0 ==> Cs*F - Cd*F
{1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // * 0200: (Cs - 0)*As + Cs ==> Cs*(As + 1)
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 0201: (Cs - 0)*As + Cd ==> Cs*As + Cd
{0, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 0202: (Cs - 0)*As + 0 ==> Cs*As
{1, D3DBLENDOP_ADD, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // * 0210: (Cs - 0)*Ad + Cs ==> Cs*(As + 1)
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 0211: (Cs - 0)*Ad + Cd ==> Cs*Ad + Cd
{0, D3DBLENDOP_ADD, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 0212: (Cs - 0)*Ad + 0 ==> Cs*Ad
{1, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // * 0220: (Cs - 0)*F + Cs ==> Cs*(F + 1)
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 0221: (Cs - 0)*F + Cd ==> Cs*F + Cd
{0, D3DBLENDOP_ADD, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 0222: (Cs - 0)*F + 0 ==> Cs*F
{0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_SRCALPHA}, // 1000: (Cd - Cs)*As + Cs ==> Cd*As + Cs*(1 - As)
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // * 1001: (Cd - Cs)*As + Cd ==> Cd*(As + 1) - Cs*As
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_SRCALPHA}, // 1002: (Cd - Cs)*As + 0 ==> Cd*As - Cs*As
{0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_DESTALPHA}, // 1010: (Cd - Cs)*Ad + Cs ==> Cd*Ad + Cs*(1 - Ad)
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // * 1011: (Cd - Cs)*Ad + Cd ==> Cd*(Ad + 1) - Cs*Ad
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_DESTALPHA}, // 1012: (Cd - Cs)*Ad + 0 ==> Cd*Ad - Cs*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_BLENDFACTOR}, // 1020: (Cd - Cs)*F + Cs ==> Cd*F + Cs*(1 - F)
{1, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// * 1021: (Cd - Cs)*F + Cd ==> Cd*(F + 1) - Cs*F
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_BLENDFACTOR},// 1022: (Cd - Cs)*F + 0 ==> Cd*F - Cs*F
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1100: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1101: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1102: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1110: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1111: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1112: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 1120: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 1121: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 1122: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 1200: (Cd - 0)*As + Cs ==> Cs + Cd*As
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_SRCALPHA}, // ** 1201: (Cd - 0)*As + Cd ==> Cd*(1 + As) // ffxii main menu background glow effect
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 1202: (Cd - 0)*As + 0 ==> Cd*As
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 1210: (Cd - 0)*Ad + Cs ==> Cs + Cd*Ad
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_DESTALPHA}, // ** 1211: (Cd - 0)*Ad + Cd ==> Cd*(1 + Ad)
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_DESTALPHA}, // 1212: (Cd - 0)*Ad + 0 ==> Cd*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 1220: (Cd - 0)*F + Cs ==> Cs + Cd*F
{2, D3DBLENDOP_ADD, D3DBLEND_DESTCOLOR, D3DBLEND_BLENDFACTOR}, // ** 1221: (Cd - 0)*F + Cd ==> Cd*(1 + F)
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_BLENDFACTOR}, // 1222: (Cd - 0)*F + 0 ==> Cd*F
{0, D3DBLENDOP_ADD, D3DBLEND_INVSRCALPHA, D3DBLEND_ZERO}, // 2000: (0 - Cs)*As + Cs ==> Cs*(1 - As)
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ONE}, // 2001: (0 - Cs)*As + Cd ==> Cd - Cs*As
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_SRCALPHA, D3DBLEND_ZERO}, // 2002: (0 - Cs)*As + 0 ==> 0 - Cs*As
{0, D3DBLENDOP_ADD, D3DBLEND_INVDESTALPHA, D3DBLEND_ZERO}, // 2010: (0 - Cs)*Ad + Cs ==> Cs*(1 - Ad)
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ONE}, // 2011: (0 - Cs)*Ad + Cd ==> Cd - Cs*Ad
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_DESTALPHA, D3DBLEND_ZERO}, // 2012: (0 - Cs)*Ad + 0 ==> 0 - Cs*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_INVBLENDFACTOR, D3DBLEND_ZERO}, // 2020: (0 - Cs)*F + Cs ==> Cs*(1 - F)
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ONE}, // 2021: (0 - Cs)*F + Cd ==> Cd - Cs*F
{0, D3DBLENDOP_REVSUBTRACT, D3DBLEND_BLENDFACTOR, D3DBLEND_ZERO}, // 2022: (0 - Cs)*F + 0 ==> 0 - Cs*F
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_SRCALPHA}, // 2100: (0 - Cd)*As + Cs ==> Cs - Cd*As
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVSRCALPHA}, // 2101: (0 - Cd)*As + Cd ==> Cd*(1 - As)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ZERO, D3DBLEND_SRCALPHA}, // 2102: (0 - Cd)*As + 0 ==> 0 - Cd*As
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2110: (0 - Cd)*Ad + Cs ==> Cs - Cd*Ad
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVDESTALPHA}, // 2111: (0 - Cd)*Ad + Cd ==> Cd*(1 - Ad)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_DESTALPHA}, // 2112: (0 - Cd)*Ad + 0 ==> 0 - Cd*Ad
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2120: (0 - Cd)*F + Cs ==> Cs - Cd*F
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_INVBLENDFACTOR}, // 2121: (0 - Cd)*F + Cd ==> Cd*(1 - F)
{0, D3DBLENDOP_SUBTRACT, D3DBLEND_ONE, D3DBLEND_BLENDFACTOR}, // 2122: (0 - Cd)*F + 0 ==> 0 - Cd*F
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2200: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2201: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2202: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2210: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2211: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2212: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
{0, D3DBLENDOP_ADD, D3DBLEND_ONE, D3DBLEND_ZERO}, // 2220: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cs ==> Cs
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ONE}, // 2221: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + Cd ==> Cd
{0, D3DBLENDOP_ADD, D3DBLEND_ZERO, D3DBLEND_ZERO}, // 2222: (Cs/Cd/0 - Cs/Cd/0)*As/Ad/F + 0 ==> 0
};
// bogus: 0100, 0110, 0120, 0200, 0210, 0220, 1001, 1011, 1021
// tricky: 1201, 1211, 1221
//
// Source.rgb = float3(1, 1, 1);
// 1201 Cd*(1 + As) => Source * Dest color + Dest * Source alpha
// 1211 Cd*(1 + Ad) => Source * Dest color + Dest * Dest alpha
// 1221 Cd*(1 + F) => Source * Dest color + Dest * Factor
int i = ((bsel.a * 3 + bsel.b) * 3 + bsel.c) * 3 + bsel.d;
bs->BlendOp = map[i].op;
bs->SrcBlend = map[i].src;
bs->DestBlend = map[i].dst;
bs->BlendOpAlpha = D3DBLENDOP_ADD;
bs->SrcBlendAlpha = D3DBLEND_ONE;
bs->DestBlendAlpha = D3DBLEND_ZERO;
if(map[i].bogus == 1)
{
ASSERT(0);
(bsel.a == 0 ? bs->SrcBlend : bs->DestBlend) = D3DBLEND_ONE;
}
}
if(bsel.wr) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_RED;
if(bsel.wg) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_GREEN;
if(bsel.wb) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_BLUE;
if(bsel.wa) bs->RenderTargetWriteMask |= D3DCOLORWRITEENABLE_ALPHA;
m_om_bs.SetAt(bsel, bs);
}
m_dev->OMSetBlendState(bs, 0x010101 * bf);
}

173
plugins/GSdx/GSTextureFX9.h Normal file
View File

@ -0,0 +1,173 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSDevice9.h"
class GSTextureFX9
{
public:
#pragma pack(push, 1)
struct VSConstantBuffer
{
GSVector4 VertexScale;
GSVector4 VertexOffset;
GSVector2 TextureScale;
float _pad[2];
};
union VSSelector
{
struct
{
DWORD bppz:2;
DWORD tme:1;
DWORD fst:1;
DWORD logz:1;
};
DWORD dw;
operator DWORD() {return dw & 0x1f;}
};
struct PSConstantBuffer
{
GSVector4 FogColor;
float MINU;
float MAXU;
float MINV;
float MAXV;
DWORD UMSK;
DWORD UFIX;
DWORD VMSK;
DWORD VFIX;
float TA0;
float TA1;
float AREF;
float _pad[1];
GSVector2 WH;
GSVector2 rWrH;
};
union PSSelector
{
struct
{
DWORD fst:1;
DWORD wms:2;
DWORD wmt:2;
DWORD bpp:3;
DWORD aem:1;
DWORD tfx:3;
DWORD tcc:1;
DWORD ate:1;
DWORD atst:3;
DWORD fog:1;
DWORD clr1:1;
DWORD rt:1;
};
DWORD dw;
operator DWORD() {return dw & 0xfffff;}
};
union PSSamplerSelector
{
struct
{
DWORD tau:1;
DWORD tav:1;
DWORD min:1;
DWORD mag:1;
};
DWORD dw;
operator DWORD() {return dw & 0xf;}
};
union OMDepthStencilSelector
{
struct
{
DWORD zte:1;
DWORD ztst:2;
DWORD zwe:1;
DWORD date:1;
DWORD fba:1;
};
DWORD dw;
operator DWORD() {return dw & 0x3f;}
};
union OMBlendSelector
{
struct
{
DWORD abe:1;
DWORD a:2;
DWORD b:2;
DWORD c:2;
DWORD d:2;
DWORD wr:1;
DWORD wg:1;
DWORD wb:1;
DWORD wa:1;
};
DWORD dw;
operator DWORD() {return dw & 0x1fff;}
};
#pragma pack(pop)
private:
GSDevice9* m_dev;
CComPtr<IDirect3DVertexDeclaration9> m_il;
CRBMapC<DWORD, CComPtr<IDirect3DVertexShader9> > m_vs;
D3DXHANDLE m_vs_params;
CRBMapC<DWORD, CComPtr<IDirect3DPixelShader9> > m_ps;
CRBMapC<DWORD, Direct3DSamplerState9* > m_ps_ss;
CRBMapC<DWORD, Direct3DDepthStencilState9* > m_om_dss;
CRBMapC<DWORD, Direct3DBlendState9* > m_om_bs;
CRBMapC<DWORD, GSTexture9> m_mskfix;
public:
GSTextureFX9();
bool Create(GSDevice9* dev);
bool CreateMskFix(GSTexture9& t, DWORD size, DWORD msk, DWORD fix);
bool SetupIA(const GSVertexHW9* vertices, UINT 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);
void UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSelector ssel, bool psrr);
void SetupRS(int w, int h, const RECT& scissor);
void SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf, IDirect3DSurface9* rt, IDirect3DSurface9* ds);
void UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, BYTE bf);
};

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GSTextureNull.h"
GSTextureNull::GSTextureNull()
{
memset(&m_desc, 0, sizeof(m_desc));
}
GSTextureNull::GSTextureNull(int type, int w, int h, int format)
{
m_desc.type = type;
m_desc.w = w;
m_desc.h = h;
m_desc.format = format;
}

View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GSTexture.h"
class GSTextureNull : public GSTexture
{
struct {int type, w, h, format;} m_desc;
public:
GSTextureNull();
GSTextureNull(int type, int w, int h, int format);
operator bool() {return m_desc.type != 0;}
int GetType() const {return m_desc.type;}
int GetWidth() const {return m_desc.w;}
int GetHeight() const {return m_desc.h;}
int GetFormat() const {return m_desc.format;}
bool Update(const CRect& r, const void* data, int pitch) {return true;}
bool Map(BYTE** bits, int& pitch, const RECT* r = NULL) {return true;}
void Unmap() {}
bool Save(CString fn, bool dds = false) {return false;}
};

272
plugins/GSdx/GSUtil.cpp Normal file
View File

@ -0,0 +1,272 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#include "stdafx.h"
#include "GS.h"
#include "GSUtil.h"
#include "svnrev.h"
static struct GSUtilMaps
{
BYTE PrimClassField[8];
bool CompatibleBitsField[64][64];
bool SharedBitsField[64][64];
struct GSUtilMaps()
{
PrimClassField[GS_POINTLIST] = GS_POINT_CLASS;
PrimClassField[GS_LINELIST] = GS_LINE_CLASS;
PrimClassField[GS_LINESTRIP] = GS_LINE_CLASS;
PrimClassField[GS_TRIANGLELIST] = GS_TRIANGLE_CLASS;
PrimClassField[GS_TRIANGLESTRIP] = GS_TRIANGLE_CLASS;
PrimClassField[GS_TRIANGLEFAN] = GS_TRIANGLE_CLASS;
PrimClassField[GS_SPRITE] = GS_SPRITE_CLASS;
PrimClassField[GS_INVALID] = GS_INVALID_CLASS;
memset(CompatibleBitsField, 0, sizeof(CompatibleBitsField));
CompatibleBitsField[PSM_PSMCT32][PSM_PSMCT24] = true;
CompatibleBitsField[PSM_PSMCT24][PSM_PSMCT32] = true;
CompatibleBitsField[PSM_PSMCT16][PSM_PSMCT16S] = true;
CompatibleBitsField[PSM_PSMCT16S][PSM_PSMCT16] = true;
CompatibleBitsField[PSM_PSMZ32][PSM_PSMZ24] = true;
CompatibleBitsField[PSM_PSMZ24][PSM_PSMZ32] = true;
CompatibleBitsField[PSM_PSMZ16][PSM_PSMZ16S] = true;
CompatibleBitsField[PSM_PSMZ16S][PSM_PSMZ16] = true;
memset(SharedBitsField, 1, sizeof(SharedBitsField));
SharedBitsField[PSM_PSMCT24][PSM_PSMT8H] = false;
SharedBitsField[PSM_PSMCT24][PSM_PSMT4HL] = false;
SharedBitsField[PSM_PSMCT24][PSM_PSMT4HH] = false;
SharedBitsField[PSM_PSMZ24][PSM_PSMT8H] = false;
SharedBitsField[PSM_PSMZ24][PSM_PSMT4HL] = false;
SharedBitsField[PSM_PSMZ24][PSM_PSMT4HH] = false;
SharedBitsField[PSM_PSMT8H][PSM_PSMCT24] = false;
SharedBitsField[PSM_PSMT8H][PSM_PSMZ24] = false;
SharedBitsField[PSM_PSMT4HL][PSM_PSMCT24] = false;
SharedBitsField[PSM_PSMT4HL][PSM_PSMZ24] = false;
SharedBitsField[PSM_PSMT4HL][PSM_PSMT4HH] = false;
SharedBitsField[PSM_PSMT4HH][PSM_PSMCT24] = false;
SharedBitsField[PSM_PSMT4HH][PSM_PSMZ24] = false;
SharedBitsField[PSM_PSMT4HH][PSM_PSMT4HL] = false;
}
} s_maps;
GS_PRIM_CLASS GSUtil::GetPrimClass(DWORD prim)
{
return (GS_PRIM_CLASS)s_maps.PrimClassField[prim];
}
bool GSUtil::HasSharedBits(DWORD spsm, DWORD dpsm)
{
return s_maps.SharedBitsField[spsm][dpsm];
}
bool GSUtil::HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm)
{
if(sbp != dbp) return false;
return HasSharedBits(spsm, dpsm);
}
bool GSUtil::HasCompatibleBits(DWORD spsm, DWORD dpsm)
{
if(spsm == dpsm) return true;
return s_maps.CompatibleBitsField[spsm][dpsm];
}
bool GSUtil::IsRectInRect(const CRect& inner, const CRect& outer)
{
return outer.left <= inner.left && inner.right <= outer.right && outer.top <= inner.top && inner.bottom <= outer.bottom;
}
bool GSUtil::IsRectInRectH(const CRect& inner, const CRect& outer)
{
return outer.top <= inner.top && inner.bottom <= outer.bottom;
}
bool GSUtil::IsRectInRectV(const CRect& inner, const CRect& outer)
{
return outer.left <= inner.left && inner.right <= outer.right;
}
void GSUtil::FitRect(CRect& r, int aspectratio)
{
static const int ar[][2] = {{0, 0}, {4, 3}, {16, 9}};
if(aspectratio <= 0 || aspectratio >= countof(ar))
{
return;
}
int arx = ar[aspectratio][0];
int ary = ar[aspectratio][1];
CRect r2 = r;
if(arx > 0 && ary > 0)
{
if(r.Width() * ary > r.Height() * arx)
{
int w = r.Height() * arx / ary;
r.left = r.CenterPoint().x - w / 2;
if(r.left & 1) r.left++;
r.right = r.left + w;
}
else
{
int h = r.Width() * ary / arx;
r.top = r.CenterPoint().y - h / 2;
if(r.top & 1) r.top++;
r.bottom = r.top + h;
}
}
r &= r2;
}
bool GSUtil::CheckDirectX()
{
CString str;
str.Format(_T("d3dx9_%d.dll"), D3DX_SDK_VERSION);
if(HINSTANCE hDll = LoadLibrary(str))
{
FreeLibrary(hDll);
}
else
{
int res = AfxMessageBox(_T("Please update DirectX!\n\nWould you like to open the download page in your browser?"), MB_YESNO);
if(res == IDYES)
{
ShellExecute(NULL, _T("open"), _T("http://www.microsoft.com/downloads/details.aspx?FamilyId=2DA43D38-DB71-4C1B-BC6A-9B6652CD92A3"), NULL, NULL, SW_SHOWNORMAL);
}
return false;
}
return true;
}
static bool _CheckSSE()
{
__try
{
static __m128i m;
#if _M_SSE >= 0x402
m.m128i_i32[0] = _mm_popcnt_u32(1234);
#elif _M_SSE >= 0x401
m = _mm_packus_epi32(m, m);
#elif _M_SSE >= 0x301
m = _mm_alignr_epi8(m, m, 1);
#elif _M_SSE >= 0x200
m = _mm_packs_epi32(m, m);
#endif
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
return false;
}
return true;
}
bool GSUtil::CheckSSE()
{
if(!_CheckSSE())
{
CString str;
str.Format(_T("This CPU does not support SSE %d.%02d"), _M_SSE >> 8, _M_SSE & 0xff);
AfxMessageBox(str, MB_OK);
return false;
}
return true;
}
bool GSUtil::IsDirect3D10Available()
{
if(HMODULE hModule = LoadLibrary(_T("d3d10.dll")))
{
FreeLibrary(hModule);
return true;
}
return false;
}
char* GSUtil::GetLibName()
{
CString str;
str.Format(_T("GSdx %d"), SVN_REV);
if(SVN_MODS) str += _T("m");
#if _M_AMD64
str += _T(" 64-bit");
#endif
CAtlList<CString> sl;
#ifdef __INTEL_COMPILER
CString s;
s.Format(_T("Intel C++ %d.%02d"), __INTEL_COMPILER/100, __INTEL_COMPILER%100);
sl.AddTail(s);
#elif _MSC_VER
CString s;
s.Format(_T("MSVC %d.%02d"), _MSC_VER/100, _MSC_VER%100);
sl.AddTail(s);
#endif
#if _M_SSE >= 0x402
sl.AddTail(_T("SSE42"));
#elif _M_SSE >= 0x401
sl.AddTail(_T("SSE41"));
#elif _M_SSE >= 0x301
sl.AddTail(_T("SSSE3"));
#elif _M_SSE >= 0x200
sl.AddTail(_T("SSE2"));
#elif _M_SSE >= 0x100
sl.AddTail(_T("SSE"));
#endif
POSITION pos = sl.GetHeadPosition();
while(pos)
{
if(pos == sl.GetHeadPosition()) str += _T(" (");
str += sl.GetNext(pos);
str += pos ? _T(", ") : _T(")");
}
static char buff[256];
strncpy(buff, CStringA(str), min(countof(buff)-1, str.GetLength()));
return buff;
}

68
plugins/GSdx/GSUtil.h Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2007-2009 Gabest
* http://www.gabest.org
*
* This Program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This Program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
* http://www.gnu.org/copyleft/gpl.html
*
*/
#pragma once
#include "GS.h"
class GSUtil
{
public:
static GS_PRIM_CLASS GetPrimClass(DWORD prim);
static bool HasSharedBits(DWORD spsm, DWORD dpsm);
static bool HasSharedBits(DWORD sbp, DWORD spsm, DWORD dbp, DWORD dpsm);
static bool HasCompatibleBits(DWORD spsm, DWORD dpsm);
static bool IsRectInRect(const CRect& inner, const CRect& outer);
static bool IsRectInRectH(const CRect& inner, const CRect& outer);
static bool IsRectInRectV(const CRect& inner, const CRect& outer);
static void FitRect(CRect& r, int aspectratio);
static int EncodePSM(int psm)
{
switch(psm)
{
case PSM_PSMCT32:
case PSM_PSMZ32:
return 0;
case PSM_PSMCT24:
case PSM_PSMZ24:
return 1;
case PSM_PSMCT16:
case PSM_PSMCT16S:
case PSM_PSMZ16:
case PSM_PSMZ16S:
return 2;
default:
return 3;
}
}
static bool CheckDirectX();
static bool CheckSSE();
static bool IsDirect3D10Available();
static char* GetLibName();
};

Some files were not shown because too many files have changed in this diff Show More