mirror of https://github.com/PCSX2/pcsx2.git
GSdx: game fixes and small optimizations
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1495 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
a72f0e6ee2
commit
aa438a6b73
|
@ -147,6 +147,7 @@ CRC::Game CRC::m_games[] =
|
|||
{0x04CCB600, ValkyrieProfile2, EU, 0},
|
||||
{0x47B9B2FD, RadiataStories, US, 0},
|
||||
{0xE8FCF8EC, SMTNocturne, US, ZWriteMustNotClear}, // saves/reloads z buffer around shadow drawing
|
||||
{0x0B8AB37B, RozenMaidenGebetGarden, JP, 0},
|
||||
};
|
||||
|
||||
hash_map<uint32, CRC::Game*> CRC::m_map;
|
||||
|
|
|
@ -76,6 +76,7 @@ public:
|
|||
ValkyrieProfile2,
|
||||
RadiataStories,
|
||||
SMTNocturne,
|
||||
RozenMaidenGebetGarden,
|
||||
TitleCount,
|
||||
};
|
||||
|
||||
|
@ -91,7 +92,8 @@ public:
|
|||
DE,
|
||||
IT,
|
||||
ES,
|
||||
ASIA
|
||||
ASIA,
|
||||
RegionCount,
|
||||
};
|
||||
|
||||
enum Flags
|
||||
|
|
|
@ -28,22 +28,22 @@ template<class Vertex>
|
|||
class GSRendererDX : public GSRendererHW<Vertex>
|
||||
{
|
||||
GSTextureFX* m_tfx;
|
||||
GSVector2 m_pixelcenter;
|
||||
bool m_logz;
|
||||
bool m_fba;
|
||||
|
||||
protected:
|
||||
int m_topology;
|
||||
GSVector2 m_pixelcenter;
|
||||
|
||||
virtual void SetupDATE(GSTexture* rt, GSTexture* ds) {}
|
||||
virtual void UpdateFBA(GSTexture* rt) {}
|
||||
|
||||
public:
|
||||
GSRendererDX(uint8* base, bool mt, void (*irq)(), GSDevice* dev, GSTextureCache* tc, GSTextureFX* tfx)
|
||||
GSRendererDX(uint8* base, bool mt, void (*irq)(), GSDevice* dev, GSTextureCache* tc, GSTextureFX* tfx, const GSVector2& pixelcenter = GSVector2(0, 0))
|
||||
: GSRendererHW<Vertex>(base, mt, irq, dev, tc)
|
||||
, m_tfx(tfx)
|
||||
, m_pixelcenter(pixelcenter)
|
||||
, m_topology(-1)
|
||||
, m_pixelcenter(0, 0)
|
||||
{
|
||||
m_logz = !!theApp.GetConfig("logz", 0);
|
||||
m_fba = !!theApp.GetConfig("fba", 1);
|
||||
|
@ -189,36 +189,25 @@ public:
|
|||
// ps
|
||||
|
||||
GSTextureFX::PSSelector ps_sel;
|
||||
|
||||
ps_sel.fst = PRIM->FST;
|
||||
ps_sel.wms = context->CLAMP.WMS;
|
||||
ps_sel.wmt = context->CLAMP.WMT;
|
||||
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;
|
||||
ps_sel.ltf = m_filter == 2 ? IsLinear() : m_filter;
|
||||
|
||||
GSTextureFX::PSSamplerSelector ps_ssel;
|
||||
|
||||
ps_ssel.tau = 0;
|
||||
ps_ssel.tav = 0;
|
||||
ps_ssel.ltf = ps_sel.ltf;
|
||||
|
||||
GSTextureFX::PSConstantBuffer ps_cb;
|
||||
|
||||
if(ps_sel.fog)
|
||||
ps_sel.clr1 = om_bsel.IsCLR1();
|
||||
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;
|
||||
|
||||
if(PRIM->FGE)
|
||||
{
|
||||
ps_cb.FogColor_AREF = GSVector4((int)env.FOGCOL.FCR, (int)env.FOGCOL.FCG, (int)env.FOGCOL.FCB, 0) / 255;
|
||||
ps_sel.fog = 1;
|
||||
|
||||
ps_cb.FogColor_AREF = GSVector4(env.FOGCOL.u32[0]) / 255;
|
||||
}
|
||||
|
||||
if(ps_sel.ate)
|
||||
if(context->TEST.ATE)
|
||||
{
|
||||
ps_sel.ate = 1;
|
||||
ps_sel.atst = context->TEST.ATST;
|
||||
|
||||
switch(ps_sel.atst)
|
||||
{
|
||||
case ATST_LESS:
|
||||
|
@ -235,61 +224,55 @@ public:
|
|||
|
||||
if(tex)
|
||||
{
|
||||
ps_sel.fst = PRIM->FST;
|
||||
ps_sel.wms = context->CLAMP.WMS;
|
||||
ps_sel.wmt = context->CLAMP.WMT;
|
||||
ps_sel.fmt = tex->m_fmt;
|
||||
ps_sel.aem = env.TEXA.AEM;
|
||||
ps_sel.tfx = context->TEX0.TFX;
|
||||
ps_sel.tcc = context->TEX0.TCC;
|
||||
ps_sel.ltf = m_filter == 2 ? IsLinear() : m_filter;
|
||||
ps_sel.rt = tex->m_target;
|
||||
|
||||
int w = tex->m_texture->GetWidth();
|
||||
int h = tex->m_texture->GetHeight();
|
||||
|
||||
ps_cb.WH = GSVector4((int)(1 << context->TEX0.TW), (int)(1 << context->TEX0.TH), w, h);
|
||||
int tw = (int)(1 << context->TEX0.TW);
|
||||
int th = (int)(1 << context->TEX0.TH);
|
||||
|
||||
ps_cb.WH = GSVector4(tw, th, w, h);
|
||||
ps_cb.HalfTexel = GSVector4(-0.5f, 0.5f).xxyy() / GSVector4(w, h).xyxy();
|
||||
ps_cb.MinF_TA.z = (float)(int)env.TEXA.TA0 / 255;
|
||||
ps_cb.MinF_TA.w = (float)(int)env.TEXA.TA1 / 255;
|
||||
|
||||
switch(context->CLAMP.WMS)
|
||||
ps_ssel.tau = (context->CLAMP.WMS + 3) >> 1;
|
||||
ps_ssel.tav = (context->CLAMP.WMT + 3) >> 1;
|
||||
ps_ssel.ltf = ps_sel.ltf;
|
||||
|
||||
switch(ps_sel.wms)
|
||||
{
|
||||
case CLAMP_REPEAT:
|
||||
ps_ssel.tau = 1;
|
||||
break;
|
||||
case CLAMP_CLAMP:
|
||||
ps_ssel.tau = 0;
|
||||
break;
|
||||
case CLAMP_REGION_CLAMP:
|
||||
ps_cb.MinMax.x = ((float)(int)context->CLAMP.MINU) / (1 << context->TEX0.TW);
|
||||
ps_cb.MinMax.z = ((float)(int)context->CLAMP.MAXU) / (1 << context->TEX0.TW);
|
||||
ps_cb.MinF_TA.x = ((float)(int)context->CLAMP.MINU + 0.5f) / (1 << context->TEX0.TW);
|
||||
ps_ssel.tau = 0;
|
||||
ps_cb.MinMax.x = (float)(int)context->CLAMP.MINU / tw;
|
||||
ps_cb.MinMax.z = (float)(int)context->CLAMP.MAXU / tw;
|
||||
ps_cb.MinF_TA.x = ((float)(int)context->CLAMP.MINU + 0.5f) / tw;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT:
|
||||
ps_cb.MskFix.x = context->CLAMP.MINU;
|
||||
ps_cb.MskFix.z = context->CLAMP.MAXU;
|
||||
ps_ssel.tau = 1;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
|
||||
switch(context->CLAMP.WMT)
|
||||
switch(ps_sel.wmt)
|
||||
{
|
||||
case CLAMP_REPEAT:
|
||||
ps_ssel.tav = 1;
|
||||
break;
|
||||
case CLAMP_CLAMP:
|
||||
ps_ssel.tav = 0;
|
||||
break;
|
||||
case CLAMP_REGION_CLAMP:
|
||||
ps_cb.MinMax.y = ((float)(int)context->CLAMP.MINV) / (1 << context->TEX0.TH);
|
||||
ps_cb.MinMax.w = ((float)(int)context->CLAMP.MAXV) / (1 << context->TEX0.TH);
|
||||
ps_cb.MinF_TA.y = ((float)(int)context->CLAMP.MINV + 0.5f) / (1 << context->TEX0.TH);
|
||||
ps_ssel.tav = 0;
|
||||
ps_cb.MinMax.y = (float)(int)context->CLAMP.MINV / th;
|
||||
ps_cb.MinMax.w = (float)(int)context->CLAMP.MAXV / th;
|
||||
ps_cb.MinF_TA.y = ((float)(int)context->CLAMP.MINV + 0.5f) / th;
|
||||
break;
|
||||
case CLAMP_REGION_REPEAT:
|
||||
ps_cb.MskFix.y = context->CLAMP.MINV;
|
||||
ps_cb.MskFix.w = context->CLAMP.MAXV;
|
||||
ps_ssel.tav = 1;
|
||||
break;
|
||||
default:
|
||||
__assume(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -25,11 +25,9 @@
|
|||
#include "resource.h"
|
||||
|
||||
GSRendererDX10::GSRendererDX10(uint8* base, bool mt, void (*irq)())
|
||||
: GSRendererDX<GSVertexHW10>(base, mt, irq, new GSDevice10(), new GSTextureCache10(this), new GSTextureFX10())
|
||||
: GSRendererDX<GSVertexHW10>(base, mt, irq, new GSDevice10(), new GSTextureCache10(this), new GSTextureFX10(), GSVector2(-0.5f, -0.5f))
|
||||
{
|
||||
InitVertexKick<GSRendererDX10>();
|
||||
|
||||
m_pixelcenter = GSVector2(-0.5f, -0.5f);
|
||||
}
|
||||
|
||||
bool GSRendererDX10::Create(const string& title)
|
||||
|
|
|
@ -25,11 +25,9 @@
|
|||
#include "resource.h"
|
||||
|
||||
GSRendererDX11::GSRendererDX11(uint8* base, bool mt, void (*irq)())
|
||||
: GSRendererDX<GSVertexHW11>(base, mt, irq, new GSDevice11(), new GSTextureCache11(this), new GSTextureFX11())
|
||||
: GSRendererDX<GSVertexHW11>(base, mt, irq, new GSDevice11(), new GSTextureCache11(this), new GSTextureFX11(), GSVector2(-0.5f, -0.5f))
|
||||
{
|
||||
InitVertexKick<GSRendererDX11>();
|
||||
|
||||
m_pixelcenter = GSVector2(-0.5f, -0.5f);
|
||||
}
|
||||
|
||||
bool GSRendererDX11::Create(const string& title)
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "GSRenderer.h"
|
||||
#include "GSTextureCache.h"
|
||||
#include "GSCrc.h"
|
||||
#include "GSFunctionMap.h"
|
||||
|
||||
|
||||
template<class Vertex>
|
||||
class GSRendererHW : public GSRendererT<Vertex>
|
||||
|
@ -33,6 +35,398 @@ class GSRendererHW : public GSRendererT<Vertex>
|
|||
int m_skip;
|
||||
bool m_reset;
|
||||
|
||||
#pragma region hacks
|
||||
|
||||
typedef bool (GSRendererHW::*OI_Ptr)(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);
|
||||
typedef void (GSRendererHW::*OO_Ptr)();
|
||||
typedef bool (GSRendererHW::*CU_Ptr)();
|
||||
|
||||
bool OI_FFXII(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
static uint32* 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 uint32[512 * 512];
|
||||
|
||||
for(int x = 0, i = 0, rows = m_count / 448; x < 448; x += 16)
|
||||
{
|
||||
uint32* 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->Recycle(t->m_texture);
|
||||
|
||||
t->m_texture = m_dev->CreateTexture(512, 512);
|
||||
|
||||
t->m_texture->Update(GSVector4i(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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OI_FFX(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 ZBP = m_context->ZBUF.Block();
|
||||
uint32 TBP = m_context->TEX0.TBP0;
|
||||
|
||||
if((FBP == 0x00d00 || FBP == 0x00000) && ZBP == 0x02100 && PRIM->TME && TBP == 0x01a00 && m_context->TEX0.PSM == PSM_PSMCT16S)
|
||||
{
|
||||
// random battle transition (z buffer written directly, clear it now)
|
||||
|
||||
m_dev->ClearDepth(ds, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OI_MetalSlug6(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
// missing red channel fix
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool OI_GodOfWar2(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 FBW = m_context->FRAME.FBW;
|
||||
uint32 FPSM = m_context->FRAME.PSM;
|
||||
|
||||
if((FBP == 0x00f00 || FBP == 0x00100) && FPSM == PSM_PSMZ24) // ntsc 0xf00, pal 0x100
|
||||
{
|
||||
// z buffer clear
|
||||
|
||||
GIFRegTEX0 TEX0;
|
||||
|
||||
TEX0.TBP0 = FBP;
|
||||
TEX0.TBW = FBW;
|
||||
TEX0.PSM = FPSM;
|
||||
|
||||
if(GSTextureCache::Target* ds = m_tc->LookupTarget(TEX0, m_width, m_height, GSTextureCache::DepthStencil, true))
|
||||
{
|
||||
m_dev->ClearDepth(ds->m_texture, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OI_SimpsonsGame(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 FBW = m_context->FRAME.FBW;
|
||||
uint32 FPSM = m_context->FRAME.PSM;
|
||||
|
||||
if(FBP == 0x01800 && FPSM == PSM_PSMZ24)
|
||||
{
|
||||
// instead of just simply drawing a full height 512x512 sprite to clear the z buffer,
|
||||
// it uses a 512x256 sprite only, yet it is still able to fill the whole surface with zeros,
|
||||
// how? by using a render target that overlaps with the lower half of the z buffer...
|
||||
|
||||
m_dev->ClearDepth(ds, 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OI_RozenMaidenGebetGarden(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
if(!PRIM->TME)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 ZBP = m_context->ZBUF.Block();
|
||||
|
||||
if(FBP == 0x008c0 && ZBP == 0x01a40)
|
||||
{
|
||||
// frame buffer clear, atst = fail, afail = write z only, z buffer points to frame buffer
|
||||
|
||||
GIFRegTEX0 TEX0;
|
||||
|
||||
TEX0.TBP0 = ZBP;
|
||||
TEX0.TBW = m_context->FRAME.FBW;
|
||||
TEX0.PSM = m_context->FRAME.PSM;
|
||||
|
||||
if(GSTextureCache::Target* rt = m_tc->LookupTarget(TEX0, m_width, m_height, GSTextureCache::RenderTarget, true))
|
||||
{
|
||||
m_dev->ClearRenderTarget(rt->m_texture, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else if(FBP == 0x00000 && m_context->ZBUF.Block() == 0x01180)
|
||||
{
|
||||
// z buffer clear, frame buffer now points to the z buffer (how can they be so clever?)
|
||||
|
||||
GIFRegTEX0 TEX0;
|
||||
|
||||
TEX0.TBP0 = FBP;
|
||||
TEX0.TBW = m_context->FRAME.FBW;
|
||||
TEX0.PSM = m_context->ZBUF.PSM;
|
||||
|
||||
if(GSTextureCache::Target* ds = m_tc->LookupTarget(TEX0, m_width, m_height, GSTextureCache::DepthStencil, true))
|
||||
{
|
||||
m_dev->ClearDepth(ds->m_texture, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OI_PointListPalette(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
if(prim == GS_POINTLIST && !PRIM->TME)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 FBW = m_context->FRAME.FBW;
|
||||
|
||||
if(FBP >= 0x03f40 && (FBP & 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, FBP, FBW);
|
||||
}
|
||||
|
||||
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, FBP, FBW);
|
||||
}
|
||||
|
||||
m_mem.m_clut.Invalidate();
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OO_DBZBT2()
|
||||
{
|
||||
// palette readback (cannot detect yet, when fetching the texture later)
|
||||
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 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, GSVector4i(0, 0, 64, 64));
|
||||
}
|
||||
}
|
||||
|
||||
void OO_MajokkoALaMode2()
|
||||
{
|
||||
// palette readback
|
||||
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
|
||||
if(!PRIM->TME && FBP == 0x03f40)
|
||||
{
|
||||
GIFRegBITBLTBUF BITBLTBUF;
|
||||
|
||||
BITBLTBUF.SBP = FBP;
|
||||
BITBLTBUF.SBW = 1;
|
||||
BITBLTBUF.SPSM = PSM_PSMCT32;
|
||||
|
||||
InvalidateLocalMem(BITBLTBUF, GSVector4i(0, 0, 16, 16));
|
||||
}
|
||||
}
|
||||
|
||||
bool CU_DBZBT2()
|
||||
{
|
||||
// palette should stay 64 x 64
|
||||
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
|
||||
return FBP != 0x03c00 && FBP != 0x03ac0;
|
||||
}
|
||||
|
||||
bool CU_MajokkoALaMode2()
|
||||
{
|
||||
// palette should stay 16 x 16
|
||||
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
|
||||
return FBP != 0x03f40;
|
||||
}
|
||||
|
||||
bool CU_TalesOfAbyss()
|
||||
{
|
||||
// full image blur and brightening
|
||||
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
|
||||
return FBP != 0x036e0 && FBP != 0x03560 && FBP != 0x038e0;
|
||||
}
|
||||
|
||||
class Hacks
|
||||
{
|
||||
template<class T> struct HackEntry
|
||||
{
|
||||
CRC::Title title;
|
||||
CRC::Region region;
|
||||
T func;
|
||||
|
||||
struct HackEntry(CRC::Title t, CRC::Region r, T f)
|
||||
{
|
||||
title = t;
|
||||
region = r;
|
||||
func = f;
|
||||
}
|
||||
};
|
||||
|
||||
template<class T> class FunctionMap : public GSFunctionMap<uint32, T>
|
||||
{
|
||||
list<HackEntry<T> >& m_tbl;
|
||||
|
||||
T GetDefaultFunction(uint32 key)
|
||||
{
|
||||
CRC::Title title = (CRC::Title)(key & 0xffffff);
|
||||
CRC::Region region = (CRC::Region)(key >> 24);
|
||||
|
||||
for(list<HackEntry<T> >::iterator i = m_tbl.begin(); i != m_tbl.end(); i++)
|
||||
{
|
||||
if(i->title == title && (i->region == CRC::RegionCount || i->region == region))
|
||||
{
|
||||
return i->func;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
public:
|
||||
FunctionMap(list<HackEntry<T> >& tbl) : m_tbl(tbl) {}
|
||||
};
|
||||
|
||||
list<HackEntry<OI_Ptr> > m_oi_list;
|
||||
list<HackEntry<OO_Ptr> > m_oo_list;
|
||||
list<HackEntry<CU_Ptr> > m_cu_list;
|
||||
|
||||
FunctionMap<OI_Ptr> m_oi_map;
|
||||
FunctionMap<OO_Ptr> m_oo_map;
|
||||
FunctionMap<CU_Ptr> m_cu_map;
|
||||
|
||||
public:
|
||||
OI_Ptr m_oi;
|
||||
OO_Ptr m_oo;
|
||||
CU_Ptr m_cu;
|
||||
|
||||
Hacks()
|
||||
: m_oi_map(m_oi_list)
|
||||
, m_oo_map(m_oo_list)
|
||||
, m_cu_map(m_cu_list)
|
||||
, m_oi(NULL)
|
||||
, m_oo(NULL)
|
||||
, m_cu(NULL)
|
||||
{
|
||||
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::FFXII, CRC::EU, &GSRendererHW::OI_FFXII));
|
||||
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::FFX, CRC::RegionCount, &GSRendererHW::OI_FFX));
|
||||
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::MetalSlug6, CRC::RegionCount, &GSRendererHW::OI_MetalSlug6));
|
||||
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::GodOfWar2, CRC::RegionCount, &GSRendererHW::OI_GodOfWar2));
|
||||
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::SimpsonsGame, CRC::RegionCount, &GSRendererHW::OI_SimpsonsGame));
|
||||
m_oi_list.push_back(HackEntry<OI_Ptr>(CRC::RozenMaidenGebetGarden, CRC::RegionCount, &GSRendererHW::OI_RozenMaidenGebetGarden));
|
||||
|
||||
m_oo_list.push_back(HackEntry<OO_Ptr>(CRC::DBZBT2, CRC::RegionCount, &GSRendererHW::OO_DBZBT2));
|
||||
m_oo_list.push_back(HackEntry<OO_Ptr>(CRC::MajokkoALaMode2, CRC::RegionCount, &GSRendererHW::OO_MajokkoALaMode2));
|
||||
|
||||
m_cu_list.push_back(HackEntry<CU_Ptr>(CRC::DBZBT2, CRC::RegionCount, &GSRendererHW::CU_DBZBT2));
|
||||
m_cu_list.push_back(HackEntry<CU_Ptr>(CRC::MajokkoALaMode2, CRC::RegionCount, &GSRendererHW::CU_MajokkoALaMode2));
|
||||
m_cu_list.push_back(HackEntry<CU_Ptr>(CRC::TalesOfAbyss, CRC::RegionCount, &GSRendererHW::CU_TalesOfAbyss));
|
||||
}
|
||||
|
||||
void SetGame(const CRC::Game& game)
|
||||
{
|
||||
uint32 hash = (uint32)((game.region << 24) | game.title);
|
||||
|
||||
m_oi = m_oi_map[hash];
|
||||
m_oo = m_oo_map[hash];
|
||||
m_cu = m_cu_map[hash];
|
||||
|
||||
if(game.flags & CRC::PointListPalette)
|
||||
{
|
||||
ASSERT(m_oi == NULL);
|
||||
|
||||
m_oi = &GSRendererHW::OI_PointListPalette;
|
||||
}
|
||||
}
|
||||
|
||||
} m_hacks;
|
||||
|
||||
#pragma endregion
|
||||
|
||||
protected:
|
||||
GSTextureCache* m_tc;
|
||||
|
||||
|
@ -196,7 +590,7 @@ protected:
|
|||
|
||||
int prim = PRIM->PRIM;
|
||||
|
||||
if(!OverrideInput(prim, rt->m_texture, ds->m_texture, tex))
|
||||
if(m_hacks.m_oi && !(this->*m_hacks.m_oi)(prim, rt->m_texture, ds->m_texture, tex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -241,6 +635,8 @@ protected:
|
|||
|
||||
if(fm != 0xffffffff)
|
||||
{
|
||||
rt->m_valid = rt->m_valid.runion(r);
|
||||
|
||||
BITBLTBUF.DBP = context->FRAME.Block();
|
||||
BITBLTBUF.DPSM = context->FRAME.PSM;
|
||||
|
||||
|
@ -249,6 +645,8 @@ protected:
|
|||
|
||||
if(zm != 0xffffffff)
|
||||
{
|
||||
ds->m_valid = ds->m_valid.runion(r);
|
||||
|
||||
BITBLTBUF.DBP = context->ZBUF.Block();
|
||||
BITBLTBUF.DPSM = context->ZBUF.PSM;
|
||||
|
||||
|
@ -257,7 +655,10 @@ protected:
|
|||
|
||||
//
|
||||
|
||||
OverrideOutput();
|
||||
if(m_hacks.m_oo)
|
||||
{
|
||||
(this->*m_hacks.m_oo)();
|
||||
}
|
||||
|
||||
if(s_dump)
|
||||
{
|
||||
|
@ -285,294 +686,12 @@ protected:
|
|||
|
||||
virtual void Draw(GS_PRIM_CLASS primclass, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex) = 0;
|
||||
|
||||
virtual bool OverrideInput(int& prim, GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t)
|
||||
{
|
||||
#pragma region ffxii pal video conversion
|
||||
|
||||
if(m_game.title == CRC::FFXII && m_game.region == CRC::EU)
|
||||
{
|
||||
static uint32* 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 uint32[512 * 512];
|
||||
|
||||
for(int x = 0, i = 0, rows = m_count / 448; x < 448; x += 16)
|
||||
{
|
||||
uint32* 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->Recycle(t->m_texture);
|
||||
|
||||
t->m_texture = m_dev->CreateTexture(512, 512);
|
||||
|
||||
t->m_texture->Update(GSVector4i(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)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 ZBP = m_context->ZBUF.Block();
|
||||
uint32 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 palette uploaded in a point list, pure genius...
|
||||
|
||||
if(m_game.flags & CRC::PointListPalette)
|
||||
{
|
||||
if(prim == GS_POINTLIST && !PRIM->TME)
|
||||
{
|
||||
uint32 bp = m_context->FRAME.Block();
|
||||
uint32 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
|
||||
|
||||
#pragma region GoW2 z buffer clear
|
||||
|
||||
if(m_game.title == CRC::GodOfWar2)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 FBW = m_context->FRAME.FBW;
|
||||
uint32 FPSM = m_context->FRAME.PSM;
|
||||
|
||||
if((FBP == 0x00f00 || FBP == 0x00100) && FPSM == PSM_PSMZ24) // ntsc 0xf00, pal 0x100
|
||||
{
|
||||
GIFRegTEX0 TEX0;
|
||||
|
||||
TEX0.TBP0 = FBP;
|
||||
TEX0.TBW = FBW;
|
||||
TEX0.PSM = FPSM;
|
||||
|
||||
if(GSTextureCache::Target* ds = m_tc->LookupTarget(TEX0, m_width, m_height, GSTextureCache::DepthStencil, true))
|
||||
{
|
||||
m_dev->ClearDepth(ds->m_texture, 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Simpsons Game z buffer clear
|
||||
|
||||
if(m_game.title == CRC::SimpsonsGame)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 FBW = m_context->FRAME.FBW;
|
||||
uint32 FPSM = m_context->FRAME.PSM;
|
||||
|
||||
if(FBP == 0x01800 && FPSM == PSM_PSMZ24)
|
||||
{
|
||||
// instead of just simply drawing a full height 512x512 sprite to clear the z buffer,
|
||||
// it uses a 512x256 sprite only, yet it is still able to fill the whole surface with zeros,
|
||||
// how? by using a render target that overlaps with the lower half of the z buffer...
|
||||
|
||||
m_dev->ClearDepth(ds, 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
uint32 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, GSVector4i(0, 0, 64, 64));
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region MajokkoALaMode2 palette readback
|
||||
|
||||
if(m_game.title == CRC::MajokkoALaMode2)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
|
||||
if(!PRIM->TME && FBP == 0x03f40)
|
||||
{
|
||||
GIFRegBITBLTBUF BITBLTBUF;
|
||||
|
||||
BITBLTBUF.SBP = FBP;
|
||||
BITBLTBUF.SBW = 1;
|
||||
BITBLTBUF.SPSM = PSM_PSMCT32;
|
||||
|
||||
InvalidateLocalMem(BITBLTBUF, GSVector4i(0, 0, 16, 16));
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
}
|
||||
|
||||
bool CanUpscale()
|
||||
{
|
||||
#pragma region dbzbt2 palette should stay 64 x 64
|
||||
|
||||
if(m_game.title == CRC::DBZBT2)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
|
||||
if(FBP == 0x03c00 || FBP == 0x03ac0)
|
||||
if(m_hacks.m_cu && !(this->*m_hacks.m_cu)())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region MajokkoALaMode2 palette should stay 16 x 16
|
||||
|
||||
if(m_game.title == CRC::MajokkoALaMode2)
|
||||
{
|
||||
uint32 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)
|
||||
{
|
||||
uint32 FBP = m_context->FRAME.Block();
|
||||
|
||||
if(FBP == 0x036e0 || FBP == 0x03560 || FBP == 0x038e0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
return __super::CanUpscale();
|
||||
}
|
||||
|
@ -602,6 +721,8 @@ public:
|
|||
{
|
||||
__super::SetGameCRC(crc, options);
|
||||
|
||||
m_hacks.SetGame(m_game);
|
||||
|
||||
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
|
||||
|
|
|
@ -322,7 +322,7 @@ void GSRendererSW::GetScanlineParam(GSScanlineParam& p, GS_PRIM_CLASS primclass)
|
|||
p.sel.wms = context->CLAMP.WMS;
|
||||
p.sel.wmt = context->CLAMP.WMT;
|
||||
|
||||
if(/*p.sel.iip == 0 &&*/ p.sel.tfx == TFX_MODULATE && p.sel.tcc && m_vt.m_eq.rgba == 0xffff && m_vt.m_min.c.eq(GSVector4i(128)))
|
||||
if(p.sel.tfx == TFX_MODULATE && p.sel.tcc && m_vt.m_eq.rgba == 0xffff && m_vt.m_min.c.eq(GSVector4i(128)))
|
||||
{
|
||||
// modulate does not do anything when vertex color is 0x80
|
||||
|
||||
|
|
|
@ -53,11 +53,11 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
|||
|
||||
Source* src = NULL;
|
||||
|
||||
hash_map<Source*, bool>& m = m_src.m_map[TEX0.TBP0 >> 5];
|
||||
list<Source*>& m = m_src.m_map[TEX0.TBP0 >> 5];
|
||||
|
||||
for(hash_map<Source*, bool>::iterator i = m.begin(); i != m.end(); i++)
|
||||
for(list<Source*>::iterator i = m.begin(); i != m.end(); i++)
|
||||
{
|
||||
Source* s = i->first;
|
||||
Source* s = *i;
|
||||
|
||||
if(((TEX0.u32[0] ^ s->m_TEX0.u32[0]) | ((TEX0.u32[1] ^ s->m_TEX0.u32[1]) & 3)) != 0) // TBP0 TBW PSM TW TH
|
||||
{
|
||||
|
@ -74,6 +74,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
|
|||
continue;
|
||||
}
|
||||
|
||||
m.splice(m.begin(), m, i);
|
||||
|
||||
src = s;
|
||||
|
||||
break;
|
||||
|
@ -245,13 +247,13 @@ void GSTextureCache::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const
|
|||
|
||||
if(!target)
|
||||
{
|
||||
const hash_map<Source*, bool>& m = m_src.m_map[bp >> 5];
|
||||
const list<Source*>& m = m_src.m_map[bp >> 5];
|
||||
|
||||
for(hash_map<Source*, bool>::const_iterator i = m.begin(); i != m.end(); )
|
||||
for(list<Source*>::const_iterator i = m.begin(); i != m.end(); )
|
||||
{
|
||||
hash_map<Source*, bool>::const_iterator j = i++;
|
||||
list<Source*>::const_iterator j = i++;
|
||||
|
||||
Source* s = j->first;
|
||||
Source* s = *j;
|
||||
|
||||
if(GSUtil::HasSharedBits(bp, psm, s->m_TEX0.TBP0, s->m_TEX0.PSM))
|
||||
{
|
||||
|
@ -272,13 +274,13 @@ void GSTextureCache::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const
|
|||
|
||||
if(page < MAX_PAGES)
|
||||
{
|
||||
const hash_map<Source*, bool>& m = m_src.m_map[page];
|
||||
const list<Source*>& m = m_src.m_map[page];
|
||||
|
||||
for(hash_map<Source*, bool>::const_iterator i = m.begin(); i != m.end(); )
|
||||
for(list<Source*>::const_iterator i = m.begin(); i != m.end(); )
|
||||
{
|
||||
hash_map<Source*, bool>::const_iterator j = i++;
|
||||
list<Source*>::const_iterator j = i++;
|
||||
|
||||
Source* s = j->first;
|
||||
Source* s = *j;
|
||||
|
||||
if(GSUtil::HasSharedBits(psm, s->m_TEX0.PSM))
|
||||
{
|
||||
|
@ -368,7 +370,12 @@ void GSTextureCache::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const
|
|||
{
|
||||
if(GSUtil::HasCompatibleBits(psm, t->m_TEX0.PSM))
|
||||
{
|
||||
t->Read(r);
|
||||
GSVector4i r2 = r.rintersect(t->m_valid);
|
||||
|
||||
if(!r2.rempty())
|
||||
{
|
||||
t->Read(r2);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -376,7 +383,12 @@ void GSTextureCache::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const
|
|||
{
|
||||
// ffx-2 riku changing to her default (shoots some reflecting glass at the end), 16-bit rt read as 32-bit
|
||||
|
||||
t->Read(GSVector4i(r.left, r.top, r.right, r.top + (r.bottom - r.top) * 2));
|
||||
GSVector4i r2 = GSVector4i(r.left, r.top, r.right, r.top + (r.bottom - r.top) * 2).rintersect(t->m_valid);
|
||||
|
||||
if(!r2.rempty())
|
||||
{
|
||||
t->Read(r2);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -447,7 +459,7 @@ void GSTextureCache::IncAge()
|
|||
|
||||
m_src.m_used = false;
|
||||
|
||||
maxage = 3;
|
||||
maxage = 4; // ffx intro scene changes leave the old image untouched for a couple of frames and only then start using it
|
||||
|
||||
for(int type = 0; type < 2; type++)
|
||||
{
|
||||
|
@ -785,7 +797,7 @@ void GSTextureCache::Source::Update(const GIFRegTEX0& TEX0, const GIFRegTEXA& TE
|
|||
}
|
||||
}
|
||||
|
||||
m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, bs.x * bs.y * sizeof(uint32) * blocks);
|
||||
m_renderer->m_perfmon.Put(GSPerfMon::Unswizzle, bs.x * bs.y * blocks << (m_fmt == GSTextureFX::FMT_32 ? 2 : 0));
|
||||
|
||||
Flush(m_write.count);
|
||||
}
|
||||
|
@ -894,6 +906,7 @@ GSTextureCache::Target::Target(GSRenderer* r)
|
|||
, m_type(-1)
|
||||
, m_used(false)
|
||||
{
|
||||
m_valid = GSVector4i::zero();
|
||||
}
|
||||
|
||||
bool GSTextureCache::Target::Create(int w, int h, int type)
|
||||
|
@ -988,7 +1001,7 @@ void GSTextureCache::SourceMap::Add(Source* s, const GIFRegTEX0& TEX0, GSLocalMe
|
|||
{
|
||||
// TODO
|
||||
|
||||
m_map[TEX0.TBP0 >> 5][s] = true;
|
||||
m_map[TEX0.TBP0 >> 5].push_front(s);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -1023,13 +1036,13 @@ void GSTextureCache::SourceMap::Add(Source* s, const GIFRegTEX0& TEX0, GSLocalMe
|
|||
{
|
||||
m_pages[i] = 0;
|
||||
|
||||
hash_map<Source*, bool>* m = &m_map[i << 5];
|
||||
list<Source*>* m = &m_map[i << 5];
|
||||
|
||||
for(int j = 0; j < 32; j++)
|
||||
{
|
||||
if(p & (1 << j))
|
||||
{
|
||||
m[j][s] = true;
|
||||
m[j].push_front(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1052,19 +1065,15 @@ void GSTextureCache::SourceMap::RemoveAt(Source* s)
|
|||
{
|
||||
m_surfaces.erase(s);
|
||||
|
||||
uint32 page = s->m_TEX0.TBP0 >> 5;
|
||||
for(uint32 start = s->m_TEX0.TBP0 >> 5, end = s->m_target ? start : countof(m_map) - 1; start <= end; start++)
|
||||
{
|
||||
list<Source*>& m = m_map[start];
|
||||
|
||||
if(s->m_target)
|
||||
for(list<Source*>::iterator i = m.begin(); i != m.end(); )
|
||||
{
|
||||
// TODO
|
||||
list<Source*>::iterator j = i++;
|
||||
|
||||
m_map[page].erase(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uint32 i = page; i < countof(m_map); i++)
|
||||
{
|
||||
m_map[i].erase(s);
|
||||
if(*j == s) {m.erase(j); break;}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ public:
|
|||
int m_type;
|
||||
bool m_used;
|
||||
GSDirtyRectList m_dirty;
|
||||
GSVector4i m_valid;
|
||||
|
||||
public:
|
||||
explicit Target(GSRenderer* r);
|
||||
|
@ -98,7 +99,7 @@ protected:
|
|||
struct SourceMap
|
||||
{
|
||||
hash_map<Source*, bool> m_surfaces;
|
||||
hash_map<Source*, bool> m_map[MAX_PAGES];
|
||||
list<Source*> m_map[MAX_PAGES];
|
||||
uint32 m_pages[16];
|
||||
bool m_used;
|
||||
|
||||
|
|
|
@ -39,11 +39,11 @@ const GSTextureCacheSW::GSTexture* GSTextureCacheSW::Lookup(const GIFRegTEX0& TE
|
|||
|
||||
GSTexture* t = NULL;
|
||||
|
||||
const hash_map<GSTexture*, bool>& map = m_map[TEX0.TBP0 >> 5];
|
||||
list<GSTexture*>& m = m_map[TEX0.TBP0 >> 5];
|
||||
|
||||
for(hash_map<GSTexture*, bool>::const_iterator i = map.begin(); i != map.end(); i++)
|
||||
for(list<GSTexture*>::iterator i = m.begin(); i != m.end(); i++)
|
||||
{
|
||||
GSTexture* t2 = i->first;
|
||||
GSTexture* t2 = *i;
|
||||
|
||||
if(((TEX0.u32[0] ^ t2->m_TEX0.u32[0]) | ((TEX0.u32[1] ^ t2->m_TEX0.u32[1]) & 3)) != 0) // TBP0 TBW PSM TW TH
|
||||
{
|
||||
|
@ -55,6 +55,8 @@ const GSTextureCacheSW::GSTexture* GSTextureCacheSW::Lookup(const GIFRegTEX0& TE
|
|||
continue;
|
||||
}
|
||||
|
||||
m.splice(m.begin(), m, i);
|
||||
|
||||
t = t2;
|
||||
|
||||
t->m_age = 0;
|
||||
|
@ -96,13 +98,13 @@ const GSTextureCacheSW::GSTexture* GSTextureCacheSW::Lookup(const GIFRegTEX0& TE
|
|||
{
|
||||
m_pages[i] = 0;
|
||||
|
||||
hash_map<GSTexture*, bool>* m = &m_map[i << 5];
|
||||
list<GSTexture*>* m = &m_map[i << 5];
|
||||
|
||||
for(int j = 0; j < 32; j++)
|
||||
{
|
||||
if(p & (1 << j))
|
||||
{
|
||||
m[j][t] = true;
|
||||
m[j].push_front(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,16 +115,9 @@ const GSTextureCacheSW::GSTexture* GSTextureCacheSW::Lookup(const GIFRegTEX0& TE
|
|||
{
|
||||
printf("!@#$%\n"); // memory allocation may fail if the game is too hungry
|
||||
|
||||
m_textures.erase(t);
|
||||
RemoveAt(t);
|
||||
|
||||
for(int i = 0; i < MAX_PAGES; i++)
|
||||
{
|
||||
m_map[i].erase(t);
|
||||
}
|
||||
|
||||
delete t;
|
||||
|
||||
return NULL;
|
||||
t = NULL;
|
||||
}
|
||||
|
||||
return t;
|
||||
|
@ -140,6 +135,25 @@ void GSTextureCacheSW::RemoveAll()
|
|||
}
|
||||
}
|
||||
|
||||
void GSTextureCacheSW::RemoveAt(GSTexture* t)
|
||||
{
|
||||
m_textures.erase(t);
|
||||
|
||||
for(uint32 start = t->m_TEX0.TBP0 >> 5, end = countof(m_map) - 1; start <= end; start++)
|
||||
{
|
||||
list<GSTexture*>& m = m_map[start];
|
||||
|
||||
for(list<GSTexture*>::iterator i = m.begin(); i != m.end(); )
|
||||
{
|
||||
list<GSTexture*>::iterator j = i++;
|
||||
|
||||
if(*j == t) {m.erase(j); break;}
|
||||
}
|
||||
}
|
||||
|
||||
delete t;
|
||||
}
|
||||
|
||||
void GSTextureCacheSW::IncAge()
|
||||
{
|
||||
for(hash_map<GSTexture*, bool>::iterator i = m_textures.begin(); i != m_textures.end(); )
|
||||
|
@ -150,14 +164,7 @@ void GSTextureCacheSW::IncAge()
|
|||
|
||||
if(++t->m_age > 30)
|
||||
{
|
||||
m_textures.erase(j);
|
||||
|
||||
for(int i = 0; i < MAX_PAGES; i++)
|
||||
{
|
||||
m_map[i].erase(t);
|
||||
}
|
||||
|
||||
delete t;
|
||||
RemoveAt(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,11 +191,11 @@ void GSTextureCacheSW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, cons
|
|||
|
||||
if(page < MAX_PAGES)
|
||||
{
|
||||
const hash_map<GSTexture*, bool>& map = m_map[page];
|
||||
const list<GSTexture*>& map = m_map[page];
|
||||
|
||||
for(hash_map<GSTexture*, bool>::const_iterator i = map.begin(); i != map.end(); i++)
|
||||
for(list<GSTexture*>::const_iterator i = map.begin(); i != map.end(); i++)
|
||||
{
|
||||
GSTexture* t = i->first;
|
||||
GSTexture* t = *i;
|
||||
|
||||
if(GSUtil::HasSharedBits(psm, t->m_TEX0.PSM))
|
||||
{
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
protected:
|
||||
GSState* m_state;
|
||||
hash_map<GSTexture*, bool> m_textures;
|
||||
hash_map<GSTexture*, bool> m_map[MAX_PAGES];
|
||||
list<GSTexture*> m_map[MAX_PAGES];
|
||||
uint32 m_pages[16];
|
||||
|
||||
public:
|
||||
|
@ -57,6 +57,7 @@ public:
|
|||
const GSTexture* Lookup(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r);
|
||||
|
||||
void RemoveAll();
|
||||
void RemoveAt(GSTexture* t);
|
||||
void IncAge();
|
||||
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
|
||||
};
|
||||
|
|
|
@ -122,7 +122,7 @@ public:
|
|||
GSVector4i b4 = b[4];
|
||||
GSVector4i b5 = b[5];
|
||||
|
||||
if(!((a[0] == b0) & (a[1] == b1) & (a[2] == b2) & (a[3] == b3) & (a[4] == b4) & (a[5] == b5)).alltrue())
|
||||
if(!((a[0] == b0) /*& (a[1] == b1)*/ & (a[2] == b2) & (a[3] == b3) & (a[4] == b4) & (a[5] == b5)).alltrue()) // if WH matches HalfTexel does too
|
||||
{
|
||||
a[0] = b0;
|
||||
a[1] = b1;
|
||||
|
@ -250,6 +250,11 @@ public:
|
|||
operator uint32() {return key & 0x1fff;}
|
||||
|
||||
OMBlendSelector() : key(0) {}
|
||||
|
||||
bool IsCLR1() const
|
||||
{
|
||||
return (key & 0x19f) == 0x93; // abe == 1 && a == 1 && b == 2 && d == 1
|
||||
}
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
|
|
|
@ -265,7 +265,7 @@ void GSTextureFX10::UpdatePS(PSSelector sel, const PSConstantBuffer* cb, PSSampl
|
|||
|
||||
if(i != m_ps_ss.end())
|
||||
{
|
||||
ss0 = (*i).second;
|
||||
ss0 = i->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -360,7 +360,7 @@ void GSTextureFX10::UpdateOM(OMDepthStencilSelector dssel, OMBlendSelector bsel,
|
|||
i = m_om_dss.find(dssel);
|
||||
}
|
||||
|
||||
dev->OMSetDepthStencilState((*i).second, 1);
|
||||
dev->OMSetDepthStencilState(i->second, 1);
|
||||
|
||||
hash_map<uint32, CComPtr<ID3D10BlendState> >::const_iterator j = m_om_bs.find(bsel);
|
||||
|
||||
|
|
|
@ -51,17 +51,6 @@ __declspec(align(16)) struct GSVertex
|
|||
GSVector4 GetUV() const {return GSVector4(GSVector4i::load(UV.u32[0]).upl16());}
|
||||
};
|
||||
|
||||
struct GSVertexOld
|
||||
{
|
||||
GIFRegRGBAQ RGBAQ;
|
||||
GIFRegST ST;
|
||||
GIFRegUV UV;
|
||||
GIFRegXYZ XYZ;
|
||||
GIFRegFOG FOG;
|
||||
|
||||
GSVertexOld() {memset(this, 0, sizeof(*this));}
|
||||
};
|
||||
|
||||
struct GSVertexP
|
||||
{
|
||||
GSVector4 p;
|
||||
|
|
|
@ -12,18 +12,13 @@ struct VS_OUTPUT
|
|||
float2 t : TEXCOORD0;
|
||||
};
|
||||
|
||||
VS_OUTPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
VS_OUTPUT output;
|
||||
|
||||
output.p = input.p;
|
||||
output.t = input.t;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Texture2D Texture;
|
||||
SamplerState Sampler;
|
||||
SamplerState TextureSampler;
|
||||
|
||||
float4 sample_c(float2 uv)
|
||||
{
|
||||
return Texture.Sample(TextureSampler, uv);
|
||||
}
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
|
@ -31,71 +26,11 @@ struct PS_INPUT
|
|||
float2 t : TEXCOORD0;
|
||||
};
|
||||
|
||||
float4 ps_main0(PS_INPUT input) : SV_Target0
|
||||
struct PS_OUTPUT
|
||||
{
|
||||
return Texture.Sample(Sampler, input.t);
|
||||
}
|
||||
|
||||
uint ps_main1(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
float4 f = Texture.Sample(Sampler, input.t);
|
||||
|
||||
f.a *= 256.0f/127; // hm, 0.5 won't give us 1.0 if we just multiply with 2
|
||||
|
||||
uint4 i = f * float4(0x001f, 0x03e0, 0x7c00, 0x8000);
|
||||
|
||||
return (i.x & 0x001f) | (i.y & 0x03e0) | (i.z & 0x7c00) | (i.w & 0x8000);
|
||||
}
|
||||
|
||||
float4 ps_main2(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
clip(Texture.Sample(Sampler, input.t).a - (0.5 - 0.9f/256));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float4 ps_main3(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
clip((0.5 - 0.9f/256) - Texture.Sample(Sampler, input.t).a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float4 ps_main4(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
float4 c = Texture.Sample(Sampler, input.t);
|
||||
|
||||
return fmod(c * 255 + 0.5f, 256) / 255;
|
||||
}
|
||||
|
||||
float4 ps_crt(PS_INPUT input, uint i)
|
||||
{
|
||||
float4 mask[4] =
|
||||
{
|
||||
float4(1, 0, 0, 0),
|
||||
float4(0, 1, 0, 0),
|
||||
float4(0, 0, 1, 0),
|
||||
float4(1, 1, 1, 0)
|
||||
float4 c : SV_Target0;
|
||||
};
|
||||
|
||||
return Texture.Sample(Sampler, input.t) * saturate(mask[i] + 0.5f);
|
||||
}
|
||||
|
||||
float4 ps_main5(PS_INPUT input) : SV_Target0 // triangular
|
||||
{
|
||||
uint4 p = (uint4)input.p;
|
||||
|
||||
// return ps_crt(input, ((p.x + (p.y & 1) * 3) >> 1) % 3);
|
||||
return ps_crt(input, ((p.x + ((p.y >> 1) & 1) * 3) >> 1) % 3);
|
||||
}
|
||||
|
||||
float4 ps_main6(PS_INPUT input) : SV_Target0 // diagonal
|
||||
{
|
||||
uint4 p = (uint4)input.p;
|
||||
|
||||
return ps_crt(input, (p.x + (p.y % 3)) % 3);
|
||||
}
|
||||
|
||||
#elif SHADER_MODEL <= 0x300
|
||||
|
||||
struct VS_INPUT
|
||||
|
@ -110,6 +45,26 @@ struct VS_OUTPUT
|
|||
float2 t : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PS_INPUT
|
||||
{
|
||||
float4 p : VPOS;
|
||||
float2 t : TEXCOORD0;
|
||||
};
|
||||
|
||||
struct PS_OUTPUT
|
||||
{
|
||||
float4 c : COLOR;
|
||||
};
|
||||
|
||||
sampler Texture : register(s0);
|
||||
|
||||
float4 sample_c(float2 uv)
|
||||
{
|
||||
return tex2D(Texture, uv);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
VS_OUTPUT vs_main(VS_INPUT input)
|
||||
{
|
||||
VS_OUTPUT output;
|
||||
|
@ -120,40 +75,16 @@ VS_OUTPUT vs_main(VS_INPUT input)
|
|||
return output;
|
||||
}
|
||||
|
||||
sampler Texture : register(s0);
|
||||
|
||||
float4 ps_main0(float2 t : TEXCOORD0) : COLOR
|
||||
PS_OUTPUT ps_main0(PS_INPUT input)
|
||||
{
|
||||
return tex2D(Texture, t);
|
||||
PS_OUTPUT output;
|
||||
|
||||
output.c = sample_c(input.t);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 ps_main1(float2 t : TEXCOORD0) : COLOR
|
||||
{
|
||||
float4 c = tex2D(Texture, t);
|
||||
c.a *= 128.0f / 255; // *= 0.5f is no good here, need to do this in order to get 0x80 for 1.0f (instead of 0x7f)
|
||||
return c;
|
||||
}
|
||||
|
||||
float4 ps_main2(float2 t : TEXCOORD0) : COLOR
|
||||
{
|
||||
clip(tex2D(Texture, t).a - (1.0f - 0.9f/256));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float4 ps_main3(float2 t : TEXCOORD0) : COLOR
|
||||
{
|
||||
clip((1.0f - 0.9f/256) - tex2D(Texture, t).a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
float4 ps_main4() : COLOR
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
float4 ps_crt(float2 t, int i)
|
||||
float4 ps_crt(PS_INPUT input, int i)
|
||||
{
|
||||
float4 mask[4] =
|
||||
{
|
||||
|
@ -163,22 +94,143 @@ float4 ps_crt(float2 t, int i)
|
|||
float4(1, 1, 1, 0)
|
||||
};
|
||||
|
||||
return tex2D(Texture, t) * saturate(mask[i] + 0.5f);
|
||||
return sample_c(input.t) * saturate(mask[i] + 0.5f);
|
||||
}
|
||||
|
||||
float4 ps_main5(float2 t : TEXCOORD0, float4 vPos : VPOS) : COLOR // triangular
|
||||
{
|
||||
int4 p = (int4)vPos;
|
||||
#if SHADER_MODEL >= 0x400
|
||||
|
||||
// return ps_crt(t, ((p.x + (p.y % 2) * 3) / 2) % 3);
|
||||
return ps_crt(t, ((p.x + ((p.y / 2) % 2) * 3) / 2) % 3);
|
||||
uint ps_main1(PS_INPUT input) : SV_Target0
|
||||
{
|
||||
float4 c = sample_c(input.t);
|
||||
|
||||
c.a *= 256.0f / 127; // hm, 0.5 won't give us 1.0 if we just multiply with 2
|
||||
|
||||
uint4 i = c * float4(0x001f, 0x03e0, 0x7c00, 0x8000);
|
||||
|
||||
return (i.x & 0x001f) | (i.y & 0x03e0) | (i.z & 0x7c00) | (i.w & 0x8000);
|
||||
}
|
||||
|
||||
float4 ps_main6(float2 t : TEXCOORD0, float4 vPos : VPOS) : COLOR // diagonal
|
||||
PS_OUTPUT ps_main2(PS_INPUT input)
|
||||
{
|
||||
int4 p = (int4)vPos;
|
||||
PS_OUTPUT output;
|
||||
|
||||
return ps_crt(t, (p.x + (p.y % 3)) % 3);
|
||||
clip(sample_c(input.t).a - 128.0f / 255); // >= 0x80 pass
|
||||
|
||||
output.c = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main3(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
clip(127.95f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
|
||||
|
||||
output.c = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main4(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
output.c = fmod(sample_c(input.t) * 255 + 0.5f, 256) / 255;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main5(PS_INPUT input) // triangular
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
uint4 p = (uint4)input.p;
|
||||
|
||||
// output.c = ps_crt(input, ((p.x + (p.y & 1) * 3) >> 1) % 3);
|
||||
output.c = ps_crt(input, ((p.x + ((p.y >> 1) & 1) * 3) >> 1) % 3);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main6(PS_INPUT input) // diagonal
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
uint4 p = (uint4)input.p;
|
||||
|
||||
output.c = ps_crt(input, (p.x + (p.y % 3)) % 3);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#elif SHADER_MODEL <= 0x300
|
||||
|
||||
PS_OUTPUT ps_main1(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
float4 c = sample_c(input.t);
|
||||
|
||||
c.a *= 128.0f / 255; // *= 0.5f is no good here, need to do this in order to get 0x80 for 1.0f (instead of 0x7f)
|
||||
|
||||
output.c = c;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main2(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
clip(sample_c(input.t).a - 255.0f / 255); // >= 0x80 pass
|
||||
|
||||
output.c = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main3(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
clip(254.95f / 255 - sample_c(input.t).a); // < 0x80 pass (== 0x80 should not pass)
|
||||
|
||||
output.c = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main4(PS_INPUT input)
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
output.c = 1;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main5(PS_INPUT input) // triangular
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
int4 p = (int4)input.p;
|
||||
|
||||
// output.c = ps_crt(input, ((p.x + (p.y % 2) * 3) / 2) % 3);
|
||||
output.c = ps_crt(input, ((p.x + ((p.y / 2) % 2) * 3) / 2) % 3);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
PS_OUTPUT ps_main6(PS_INPUT input) // diagonal
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
int4 p = (int4)input.p;
|
||||
|
||||
output.c = ps_crt(input, (p.x + (p.y % 3)) % 3);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -298,7 +298,7 @@ float4 sample_4a(float4 uv)
|
|||
c.w = sample_c(uv.zw).a;
|
||||
|
||||
#if SHADER_MODEL <= 0x300
|
||||
if(PS_RT) c *= 0.5;
|
||||
if(PS_RT) c *= 128.0f / 255;
|
||||
#endif
|
||||
|
||||
return c;
|
||||
|
@ -387,7 +387,7 @@ float4 sample(float2 st, float q)
|
|||
if(PS_FMT == FMT_32)
|
||||
{
|
||||
#if SHADER_MODEL <= 0x300
|
||||
if(PS_RT) t.a *= 0.5;
|
||||
if(PS_RT) t.a *= 128.0f / 255;
|
||||
#endif
|
||||
}
|
||||
else if(PS_FMT == FMT_24)
|
||||
|
|
Loading…
Reference in New Issue