GSdx: silent hill shattered memories purple street light fix, not block aligned filled rects were not correctly masked, may also fix games which store texture data in the alpha channel but use 24-bit target buffers (or just mask it in every time) and draw a lot of those unaligned rects. (tested many .gs dumps, very rare combination)

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5084 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
gabest11 2012-01-28 10:07:17 +00:00
parent 915a57d9f3
commit bd12a8b7b3
4 changed files with 152 additions and 126 deletions

View File

@ -1492,6 +1492,7 @@ void GSDrawScanline::DrawRectT(const int* RESTRICT row, const int* RESTRICT col,
if(masked) ASSERT(mask.u32[0] != 0);
color = color.andnot(mask);
c = color.extract32<0>();
GSVector4i br = r.ralign<Align_Inside>(GSVector2i(8 * 4 / sizeof(T), 8));

View File

@ -338,6 +338,8 @@ void GSRendererSW::ConvertVertexBuffer(GSVertexSW* RESTRICT dst, const GSVertex*
void GSRendererSW::Draw()
{
const GSDrawingContext* context = m_context;
SharedData* sd = new SharedData(this);
shared_ptr<GSRasterizerData> data(sd);
@ -353,16 +355,11 @@ void GSRendererSW::Draw()
memcpy(sd->index, m_index.buff, sizeof(uint32) * m_index.tail);
if(!GetScanlineGlobalData(sd)) return;
//
const GSDrawingContext* context = m_context;
GSScanlineGlobalData& gd = sd->global;
if(!GetScanlineGlobalData(sd)) return;
GSVector4i scissor = GSVector4i(context->scissor.in);
GSVector4i bbox = GSVector4i(m_vt.m_min.p.floor().xyxy(m_vt.m_max.p.ceil()));
GSVector4i r = bbox.rintersect(scissor);
scissor.z = std::min<int>(scissor.z, (int)context->FRAME.FBW * 64); // TODO: find a game that overflows and check which one is the right behaviour
@ -370,7 +367,42 @@ void GSRendererSW::Draw()
sd->bbox = bbox;
sd->frame = m_perfmon.GetFrame();
CheckDependencies(sd);
//
GSScanlineGlobalData& gd = sd->global;
uint32* fb_pages = NULL;
uint32* zb_pages = NULL;
if(sd->global.sel.fb)
{
fb_pages = m_context->offset.fb->GetPages(r);
}
if(sd->global.sel.zb)
{
zb_pages = m_context->offset.zb->GetPages(r);
}
// check if there is an overlap between this and previous targets
if(CheckTargetPages(fb_pages, zb_pages, r))
{
sd->m_syncpoint = SharedData::SyncTarget;
}
// check if the texture is not part of a target currently in use
if(CheckSourcePages(sd))
{
sd->m_syncpoint = SharedData::SyncSource;
}
// addref source and target pages
sd->UsePages(fb_pages, m_context->offset.fb->psm, zb_pages, m_context->offset.zb->psm);
//
if(LOG) {fprintf(s_fp, "queue %05x %d (%d) %05x %d (%d) %05x %d %dx%d | %d %d %d\n",
m_context->FRAME.Block(), m_context->FRAME.PSM, gd.sel.fwrite,
@ -411,7 +443,7 @@ void GSRendererSW::Draw()
s_n++;
m_rl->Queue(data);
Queue(data);
Sync(4);
@ -433,7 +465,7 @@ void GSRendererSW::Draw()
}
else
{
m_rl->Queue(data);
Queue(data);
}
/*
@ -448,6 +480,39 @@ void GSRendererSW::Draw()
*/
}
void GSRendererSW::Queue(shared_ptr<GSRasterizerData>& item)
{
SharedData* sd = (SharedData*)item.get();
if(sd->m_syncpoint == SharedData::SyncSource)
{
m_rl->Sync();
}
// update previously invalidated parts
sd->UpdateSource();
// invalidate new parts rendered onto
if(sd->global.sel.fwrite)
{
m_tc->InvalidatePages(sd->m_fb_pages, sd->m_fpsm);
}
if(sd->global.sel.zwrite)
{
m_tc->InvalidatePages(sd->m_zb_pages, sd->m_zpsm);
}
if(sd->m_syncpoint == SharedData::SyncTarget)
{
m_rl->Sync();
}
m_rl->Queue(item);
}
void GSRendererSW::Sync(int reason)
{
//printf("sync %d\n", reason);
@ -580,71 +645,6 @@ void GSRendererSW::ReleasePages(const uint32* pages, int type)
}
}
void GSRendererSW::CheckDependencies(SharedData* sd)
{
GSVector4i r = sd->bbox.rintersect(sd->scissor);
uint32* fb_pages = NULL;
uint32* zb_pages = NULL;
if(sd->global.sel.fb)
{
fb_pages = m_context->offset.fb->GetPages(r);
}
if(sd->global.sel.zb)
{
zb_pages = m_context->offset.zb->GetPages(r);
}
// check if there is an overlap between this and previous targets
bool target_syncpoint = false;
if(CheckTargetPages(fb_pages, zb_pages, r))
{
target_syncpoint = true;
}
// check if the texture is not part of a target currently in use
bool source_syncpoint = false;
if(CheckSourcePages(sd))
{
source_syncpoint = true;
target_syncpoint = false;
}
// addref target pages
sd->UseTargetPages(fb_pages, zb_pages);
// addref texture pages and update previously invalidated parts
if(source_syncpoint)
{
Sync(8);
}
sd->UseSourcePages();
if(sd->global.sel.fwrite)
{
m_tc->InvalidatePages(fb_pages, m_context->offset.fb->psm);
}
if(sd->global.sel.zwrite)
{
m_tc->InvalidatePages(zb_pages, m_context->offset.zb->psm);
}
if(target_syncpoint)
{
Sync(9);
}
}
bool GSRendererSW::CheckTargetPages(const uint32* fb_pages, const uint32* zb_pages, const GSVector4i& r)
{
bool synced = m_rl->IsSynced();
@ -1313,6 +1313,7 @@ GSRendererSW::SharedData::SharedData(GSRendererSW* parent)
, m_fb_pages(NULL)
, m_zb_pages(NULL)
, m_using_pages(false)
, m_syncpoint(SyncNone)
{
m_tex[0].t = NULL;
@ -1324,38 +1325,16 @@ GSRendererSW::SharedData::SharedData(GSRendererSW* parent)
GSRendererSW::SharedData::~SharedData()
{
if(m_using_pages)
{
if(global.sel.fb)
{
m_parent->ReleasePages(m_fb_pages, 0);
}
ReleasePages();
if(global.sel.zb)
{
m_parent->ReleasePages(m_zb_pages, 1);
}
}
delete [] m_fb_pages;
delete [] m_zb_pages;
for(size_t i = 0; m_tex[i].t != NULL; i++)
{
m_parent->ReleasePages(m_tex[i].t->m_pages.n, 2);
}
if(global.clut) _aligned_free(global.clut);
if(global.dimx) _aligned_free(global.dimx);
}
void GSRendererSW::SharedData::UseTargetPages(const uint32* fb_pages, const uint32* zb_pages)
void GSRendererSW::SharedData::UsePages(const uint32* fb_pages, int fpsm, const uint32* zb_pages, int zpsm)
{
if(m_using_pages) return;
m_fb_pages = fb_pages;
m_zb_pages = zb_pages;
if(global.sel.fb)
{
m_parent->UsePages(fb_pages, 0);
@ -1366,9 +1345,47 @@ void GSRendererSW::SharedData::UseTargetPages(const uint32* fb_pages, const uint
m_parent->UsePages(zb_pages, 1);
}
for(size_t i = 0; m_tex[i].t != NULL; i++)
{
m_parent->UsePages(m_tex[i].t->m_pages.n, 2);
}
m_fb_pages = fb_pages;
m_zb_pages = zb_pages;
m_fpsm = fpsm;
m_zpsm = zpsm;
m_using_pages = true;
}
void GSRendererSW::SharedData::ReleasePages()
{
if(!m_using_pages) return;
if(global.sel.fb)
{
m_parent->ReleasePages(m_fb_pages, 0);
}
if(global.sel.zb)
{
m_parent->ReleasePages(m_zb_pages, 1);
}
for(size_t i = 0; m_tex[i].t != NULL; i++)
{
m_parent->ReleasePages(m_tex[i].t->m_pages.n, 2);
}
delete [] m_fb_pages;
delete [] m_zb_pages;
m_fb_pages = NULL;
m_zb_pages = NULL;
m_using_pages = false;
}
void GSRendererSW::SharedData::SetSource(GSTextureCacheSW::Texture* t, const GSVector4i& r, int level)
{
ASSERT(m_tex[level].t == NULL);
@ -1379,12 +1396,10 @@ void GSRendererSW::SharedData::SetSource(GSTextureCacheSW::Texture* t, const GSV
m_tex[level + 1].t = NULL;
}
void GSRendererSW::SharedData::UseSourcePages()
void GSRendererSW::SharedData::UpdateSource()
{
for(size_t i = 0; m_tex[i].t != NULL; i++)
{
m_parent->UsePages(m_tex[i].t->m_pages.n, 2);
if(m_tex[i].t->Update(m_tex[i].r))
{
global.tex[i] = m_tex[i].t->m_buff;

View File

@ -29,21 +29,31 @@ class GSRendererSW : public GSRenderer
{
class SharedData : public GSDrawScanline::SharedData
{
__aligned(struct, 16) TextureLevel
{
GSVector4i r;
GSTextureCacheSW::Texture* t;
};
public:
GSRendererSW* m_parent;
const uint32* m_fb_pages;
const uint32* m_zb_pages;
int m_fpsm;
int m_zpsm;
bool m_using_pages;
__aligned(struct, 16) {GSVector4i r; GSTextureCacheSW::Texture* t;} m_tex[7 + 1]; // NULL terminated
TextureLevel m_tex[7 + 1]; // NULL terminated
enum {SyncNone, SyncSource, SyncTarget} m_syncpoint;
public:
SharedData(GSRendererSW* parent);
virtual ~SharedData();
void UseTargetPages(const uint32* fb_pages, const uint32* zb_pages);
void UsePages(const uint32* fb_pages, int fpsm, const uint32* zb_pages, int zpsm);
void ReleasePages();
void SetSource(GSTextureCacheSW::Texture* t, const GSVector4i& r, int level);
void UseSourcePages();
void UpdateSource();
};
typedef void (GSRendererSW::*ConvertVertexBufferPtr)(GSVertexSW* RESTRICT dst, const GSVertex* RESTRICT src, size_t count);
@ -71,6 +81,7 @@ protected:
GSTexture* GetOutput(int i);
void Draw();
void Queue(shared_ptr<GSRasterizerData>& item);
void Sync(int reason);
void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r);
void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false);
@ -78,7 +89,6 @@ protected:
void UsePages(const uint32* pages, int type);
void ReleasePages(const uint32* pages, int type);
void CheckDependencies(SharedData* sd);
bool CheckTargetPages(const uint32* fb_pages, const uint32* zb_pages, const GSVector4i& r);
bool CheckSourcePages(SharedData* sd);

View File

@ -69,7 +69,7 @@ cbuffer PSConstantBuffer : register(c0)
struct FragmentLinkItem
{
uint c, z, id, next;
uint c, z, id, next;
};
RWByteAddressBuffer VideoMemory : register(u0);
@ -146,9 +146,9 @@ void gs_main(line VS_OUTPUT input[2], inout LineStream<GS_OUTPUT> stream, uint i
output.c = input[i].c;
output.id = id;
#if GS_IIP == 0
#if GS_IIP == 0
if(i != 1) output.c = input[1].c;
#endif
#endif
stream.Append(output);
}
@ -170,9 +170,9 @@ void gs_main(triangle VS_OUTPUT input[3], inout TriangleStream<GS_OUTPUT> stream
output.c = input[i].c;
output.id = id;
#if GS_IIP == 0
#if GS_IIP == 0
if(i != 2) output.c = input[2].c;
#endif
#endif
stream.Append(output);
}
@ -192,9 +192,9 @@ void gs_main(line VS_OUTPUT input[2], inout TriangleStream<GS_OUTPUT> stream, ui
lt.c = input[0].c;
lt.id = id;
#if GS_IIP == 0
#if GS_IIP == 0
lt.c = input[1].c;
#endif
#endif
rb.p = input[1].p;
rb.z = input[1].z;
@ -268,23 +268,23 @@ void ps_main0(GS_OUTPUT input)
uint x = (uint)input.p.x;
uint y = (uint)input.p.y;
uint tail = FragmentLinkBuffer.IncrementCounter();
uint tail = FragmentLinkBuffer.IncrementCounter();
uint index = (y << 11) + x;
uint index = (y << 11) + x;
uint next = 0;
StartOffsetBuffer.InterlockedExchange(index * 4, tail, next);
FragmentLinkItem item;
FragmentLinkItem item;
// TODO: preprocess color (tfx, alpha test), z-test
item.c = CompressColor32(input.c);
item.z = (uint)(input.z.y * 0x10000 + input.z.x);
item.id = input.id;
item.next = next;
item.next = next;
FragmentLinkBuffer[tail] = item;
FragmentLinkBuffer[tail] = item;
}
void ps_main1(GS_OUTPUT input)
@ -293,7 +293,7 @@ void ps_main1(GS_OUTPUT input)
// sort fragments
uint StartOffsetIndex = (pos.y << 11) + pos.x;
uint StartOffsetIndex = (pos.y << 11) + pos.x;
int index[PS_BATCH_SIZE];
int count = 0;
@ -303,7 +303,7 @@ void ps_main1(GS_OUTPUT input)
StartOffsetBuffer.Store(StartOffsetIndex * 4, 0);
[allow_uav_condition]
while(next != 0)
while(next != 0)
{
index[count++] = next;
@ -313,8 +313,8 @@ void ps_main1(GS_OUTPUT input)
int N2 = 1 << (int)(ceil(log2(count)));
[allow_uav_condition]
for(int i = count; i < N2; i++)
{
for(int i = count; i < N2; i++)
{
index[i] = 0;
}
@ -330,7 +330,7 @@ void ps_main1(GS_OUTPUT input)
uint i_id = FragmentLinkBuffer[index[i]].id;
int ixj = i ^ j;
if(ixj > i)
{
uint ixj_id = FragmentLinkBuffer[index[ixj]].id;
@ -363,7 +363,7 @@ void ps_main1(GS_OUTPUT input)
[allow_uav_condition]
while(--count >= 0)
{
{
FragmentLinkItem f = FragmentLinkBuffer[index[count]];
// TODO
@ -374,7 +374,7 @@ void ps_main1(GS_OUTPUT input)
sz = f.z;
}
}
uint c = sc; // (dc & ~WriteMask.x) | (sc & WriteMask.x);
uint z = 0;//sz; //(dz & ~WriteMask.y) | (sz & WriteMask.y);