mirror of https://github.com/PCSX2/pcsx2.git
GSdx: a few minor changes, please check if I wrapped the new pthread things correctly
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5019 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
3aa3b1caf6
commit
25072b99c7
|
@ -2002,8 +2002,6 @@ GSOffset::~GSOffset()
|
||||||
|
|
||||||
list<uint32>* GSOffset::GetPages(const GSVector4i& rect, GSVector4i* bbox)
|
list<uint32>* GSOffset::GetPages(const GSVector4i& rect, GSVector4i* bbox)
|
||||||
{
|
{
|
||||||
GSAutoLock lock(&m_lock);
|
|
||||||
|
|
||||||
GSVector2i bs = (bp & 31) == 0 ? GSLocalMemory::m_psm[psm].pgs : GSLocalMemory::m_psm[psm].bs;
|
GSVector2i bs = (bp & 31) == 0 ? GSLocalMemory::m_psm[psm].pgs : GSLocalMemory::m_psm[psm].bs;
|
||||||
|
|
||||||
GSVector4i r = rect.ralign<Align_Outside>(bs);
|
GSVector4i r = rect.ralign<Align_Outside>(bs);
|
||||||
|
|
|
@ -30,8 +30,6 @@
|
||||||
|
|
||||||
class GSOffset : public GSAlignedClass<32>
|
class GSOffset : public GSAlignedClass<32>
|
||||||
{
|
{
|
||||||
GSCritSec m_lock; // GetPages could be called from multiple threads
|
|
||||||
|
|
||||||
hash_map<uint64, list<uint32>*> m_cache;
|
hash_map<uint64, list<uint32>*> m_cache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -163,6 +163,9 @@ void GSRasterizer::Draw(shared_ptr<GSRasterizerData> data)
|
||||||
|
|
||||||
uint64 ticks = __rdtsc() - start;
|
uint64 ticks = __rdtsc() - start;
|
||||||
|
|
||||||
|
_InterlockedExchangeAdd(&data->ticks, ticks);
|
||||||
|
_InterlockedExchangeAdd(&data->pixels, m_pixels);
|
||||||
|
|
||||||
m_ds->EndDraw(data->frame, ticks, m_pixels);
|
m_ds->EndDraw(data->frame, ticks, m_pixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,11 @@ public:
|
||||||
uint64 frame;
|
uint64 frame;
|
||||||
void* param;
|
void* param;
|
||||||
|
|
||||||
|
// drawing stats
|
||||||
|
|
||||||
|
volatile long ticks;
|
||||||
|
volatile long pixels;
|
||||||
|
|
||||||
GSRasterizerData()
|
GSRasterizerData()
|
||||||
: scissor(GSVector4i::zero())
|
: scissor(GSVector4i::zero())
|
||||||
, bbox(GSVector4i::zero())
|
, bbox(GSVector4i::zero())
|
||||||
|
@ -51,6 +56,8 @@ public:
|
||||||
, syncpoint(false)
|
, syncpoint(false)
|
||||||
, frame(0)
|
, frame(0)
|
||||||
, param(NULL)
|
, param(NULL)
|
||||||
|
, ticks(0)
|
||||||
|
, pixels(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,19 @@ void GSRendererSW::Draw()
|
||||||
{
|
{
|
||||||
if(m_dump) m_dump.Object(m_vertices, m_count, m_vt.m_primclass);
|
if(m_dump) m_dump.Object(m_vertices, m_count, m_vt.m_primclass);
|
||||||
|
|
||||||
shared_ptr<GSRasterizerData> data(new GSRasterizerData2(this));
|
GSVector4i scissor = GSVector4i(m_context->scissor.in);
|
||||||
|
GSVector4i bbox = GSVector4i(m_vt.m_min.p.floor().xyxy(m_vt.m_max.p.ceil()));
|
||||||
|
|
||||||
|
scissor.z = std::min<int>(scissor.z, (int)m_context->FRAME.FBW * 64); // TODO: find a game that overflows and check which one is the right behaviour
|
||||||
|
|
||||||
|
GSVector4i r = bbox.rintersect(scissor);
|
||||||
|
|
||||||
|
list<uint32>* fb_pages = m_context->offset.fb->GetPages(r);
|
||||||
|
list<uint32>* zb_pages = m_context->offset.zb->GetPages(r);
|
||||||
|
|
||||||
|
GSRasterizerData2* data2 = new GSRasterizerData2(this, fb_pages, zb_pages);
|
||||||
|
|
||||||
|
shared_ptr<GSRasterizerData> data(data2);
|
||||||
|
|
||||||
GSScanlineGlobalData* gd = (GSScanlineGlobalData*)data->param;
|
GSScanlineGlobalData* gd = (GSScanlineGlobalData*)data->param;
|
||||||
|
|
||||||
|
@ -175,9 +187,8 @@ void GSRendererSW::Draw()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->scissor = GSVector4i(m_context->scissor.in);
|
data->scissor = scissor;
|
||||||
data->scissor.z = std::min<int>(data->scissor.z, (int)m_context->FRAME.FBW * 64); // TODO: find a game that overflows and check which one is the right behaviour
|
data->bbox = bbox;
|
||||||
data->bbox = GSVector4i(m_vt.m_min.p.floor().xyxy(m_vt.m_max.p.ceil()));
|
|
||||||
data->primclass = m_vt.m_primclass;
|
data->primclass = m_vt.m_primclass;
|
||||||
data->vertices = (GSVertexSW*)_aligned_malloc(sizeof(GSVertexSW) * m_count, 16); // TODO: detach m_vertices and reallocate later?
|
data->vertices = (GSVertexSW*)_aligned_malloc(sizeof(GSVertexSW) * m_count, 16); // TODO: detach m_vertices and reallocate later?
|
||||||
memcpy(data->vertices, m_vertices, sizeof(GSVertexSW) * m_count); // TODO: m_vt.Update fetches all the vertices already, could also store them here
|
memcpy(data->vertices, m_vertices, sizeof(GSVertexSW) * m_count); // TODO: m_vt.Update fetches all the vertices already, could also store them here
|
||||||
|
@ -185,11 +196,6 @@ void GSRendererSW::Draw()
|
||||||
data->solidrect = gd->sel.IsSolidRect();
|
data->solidrect = gd->sel.IsSolidRect();
|
||||||
data->frame = m_perfmon.GetFrame();
|
data->frame = m_perfmon.GetFrame();
|
||||||
|
|
||||||
GSVector4i r = data->bbox.rintersect(data->scissor);
|
|
||||||
|
|
||||||
list<uint32>* fb_pages = m_context->offset.fb->GetPages(r);
|
|
||||||
list<uint32>* zb_pages = m_context->offset.zb->GetPages(r);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
if(gd->sel.fwrite)
|
if(gd->sel.fwrite)
|
||||||
|
@ -202,7 +208,7 @@ void GSRendererSW::Draw()
|
||||||
m_tc->InvalidatePages(zb_pages, m_context->offset.zb->psm);
|
m_tc->InvalidatePages(zb_pages, m_context->offset.zb->psm);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
// set data->syncpoint
|
||||||
|
|
||||||
if(m_fzb != m_context->offset.fzb)
|
if(m_fzb != m_context->offset.fzb)
|
||||||
{
|
{
|
||||||
|
@ -220,7 +226,12 @@ void GSRendererSW::Draw()
|
||||||
{
|
{
|
||||||
for(list<uint32>::iterator i = fb_pages->begin(); i != fb_pages->end(); i++)
|
for(list<uint32>::iterator i = fb_pages->begin(); i != fb_pages->end(); i++)
|
||||||
{
|
{
|
||||||
if(m_fzb_pages[*i] & 0xffff0000) data->syncpoint = true; // already used as a z-buffer
|
if(m_fzb_pages[*i] & 0xffff0000) // already used as a z-buffer
|
||||||
|
{
|
||||||
|
data->syncpoint = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,20 +242,21 @@ void GSRendererSW::Draw()
|
||||||
{
|
{
|
||||||
for(list<uint32>::iterator i = zb_pages->begin(); i != zb_pages->end(); i++)
|
for(list<uint32>::iterator i = zb_pages->begin(); i != zb_pages->end(); i++)
|
||||||
{
|
{
|
||||||
if(m_fzb_pages[*i] & 0x0000ffff) data->syncpoint = true; // already used as a frame buffer
|
if(m_fzb_pages[*i] & 0x0000ffff) // already used as a frame buffer
|
||||||
|
{
|
||||||
|
data->syncpoint = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gd->sel.fwrite)
|
//
|
||||||
{
|
|
||||||
UseTargetPages(fb_pages, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gd->sel.zwrite)
|
data2->UseTargetPages();
|
||||||
{
|
|
||||||
UseTargetPages(zb_pages, 1);
|
//
|
||||||
}
|
|
||||||
|
|
||||||
if(s_dump)
|
if(s_dump)
|
||||||
{
|
{
|
||||||
|
@ -304,8 +316,17 @@ void GSRendererSW::Draw()
|
||||||
m_rl->Queue(data);
|
m_rl->Queue(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: m_perfmon.Put(GSPerfMon::Prim, stats.prims);
|
int prims = 0;
|
||||||
// TODO: m_perfmon.Put(GSPerfMon::Fillrate, stats.pixels);
|
|
||||||
|
switch(data->primclass)
|
||||||
|
{
|
||||||
|
case GS_POINT_CLASS: prims = data->count; break;
|
||||||
|
case GS_LINE_CLASS: prims = data->count / 2; break;
|
||||||
|
case GS_TRIANGLE_CLASS: prims = data->count / 3; break;
|
||||||
|
case GS_SPRITE_CLASS: prims = data->count / 2; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_perfmon.Put(GSPerfMon::Prim, prims);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if(0)//stats.ticks > 5000000)
|
if(0)//stats.ticks > 5000000)
|
||||||
|
@ -329,15 +350,6 @@ void GSRendererSW::Sync(int reason)
|
||||||
|
|
||||||
// NOTE: m_fzb_pages is refcounted, zeroing is done automatically
|
// NOTE: m_fzb_pages is refcounted, zeroing is done automatically
|
||||||
|
|
||||||
#ifdef _DEBUG
|
|
||||||
|
|
||||||
for(size_t i = 0; i < countof(m_fzb_pages); i++)
|
|
||||||
{
|
|
||||||
ASSERT(m_fzb_pages[i] == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
memset(m_tex_pages, 0, sizeof(m_tex_pages));
|
memset(m_tex_pages, 0, sizeof(m_tex_pages));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,14 +30,16 @@ class GSRendererSW : public GSRendererT<GSVertexSW>
|
||||||
class GSRasterizerData2 : public GSRasterizerData
|
class GSRasterizerData2 : public GSRasterizerData
|
||||||
{
|
{
|
||||||
GSRendererSW* m_parent;
|
GSRendererSW* m_parent;
|
||||||
GSOffset* m_fb;
|
const list<uint32>* m_fb_pages;
|
||||||
GSOffset* m_zb;
|
const list<uint32>* m_zb_pages;
|
||||||
|
bool m_using_pages;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GSRasterizerData2(GSRendererSW* parent)
|
GSRasterizerData2(GSRendererSW* parent, const list<uint32>* fb_pages, const list<uint32>* zb_pages)
|
||||||
: m_parent(parent)
|
: m_parent(parent)
|
||||||
, m_fb(parent->m_context->offset.fb)
|
, m_fb_pages(fb_pages)
|
||||||
, m_zb(parent->m_context->offset.zb)
|
, m_zb_pages(zb_pages)
|
||||||
|
, m_using_pages(false)
|
||||||
{
|
{
|
||||||
GSScanlineGlobalData* gd = (GSScanlineGlobalData*)_aligned_malloc(sizeof(GSScanlineGlobalData), 32);
|
GSScanlineGlobalData* gd = (GSScanlineGlobalData*)_aligned_malloc(sizeof(GSScanlineGlobalData), 32);
|
||||||
|
|
||||||
|
@ -51,24 +53,54 @@ class GSRendererSW : public GSRendererT<GSVertexSW>
|
||||||
|
|
||||||
virtual ~GSRasterizerData2()
|
virtual ~GSRasterizerData2()
|
||||||
{
|
{
|
||||||
|
ReleaseTargetPages();
|
||||||
|
|
||||||
GSScanlineGlobalData* gd = (GSScanlineGlobalData*)param;
|
GSScanlineGlobalData* gd = (GSScanlineGlobalData*)param;
|
||||||
|
|
||||||
GSVector4i r = bbox.rintersect(scissor);
|
|
||||||
|
|
||||||
if(gd->sel.fwrite)
|
|
||||||
{
|
|
||||||
m_parent->ReleaseTargetPages(m_fb->GetPages(r), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gd->sel.zwrite)
|
|
||||||
{
|
|
||||||
m_parent->ReleaseTargetPages(m_zb->GetPages(r), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(gd->clut) _aligned_free(gd->clut);
|
if(gd->clut) _aligned_free(gd->clut);
|
||||||
if(gd->dimx) _aligned_free(gd->dimx);
|
if(gd->dimx) _aligned_free(gd->dimx);
|
||||||
|
|
||||||
_aligned_free(gd);
|
_aligned_free(gd);
|
||||||
|
|
||||||
|
m_parent->m_perfmon.Put(GSPerfMon::Fillrate, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UseTargetPages()
|
||||||
|
{
|
||||||
|
if(m_using_pages) {ASSERT(0); return;}
|
||||||
|
|
||||||
|
GSScanlineGlobalData* gd = (GSScanlineGlobalData*)param;
|
||||||
|
|
||||||
|
if(gd->sel.fwrite)
|
||||||
|
{
|
||||||
|
m_parent->UseTargetPages(m_fb_pages, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gd->sel.zwrite)
|
||||||
|
{
|
||||||
|
m_parent->UseTargetPages(m_zb_pages, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_using_pages = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseTargetPages()
|
||||||
|
{
|
||||||
|
if(!m_using_pages) {ASSERT(0); return;}
|
||||||
|
|
||||||
|
GSScanlineGlobalData* gd = (GSScanlineGlobalData*)param;
|
||||||
|
|
||||||
|
if(gd->sel.fwrite)
|
||||||
|
{
|
||||||
|
m_parent->ReleaseTargetPages(m_fb_pages, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(gd->sel.zwrite)
|
||||||
|
{
|
||||||
|
m_parent->ReleaseTargetPages(m_zb_pages, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_using_pages = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -592,7 +592,11 @@ void GSState::ApplyTEX0(int i, GIFRegTEX0& TEX0)
|
||||||
|
|
||||||
bool wt = m_mem.m_clut.WriteTest(TEX0, m_env.TEXCLUT);
|
bool wt = m_mem.m_clut.WriteTest(TEX0, m_env.TEXCLUT);
|
||||||
|
|
||||||
if(wt || PRIM->CTXT == i && TEX0 != m_env.CTXT[i].TEX0)
|
// clut loading already covered with WriteTest, for drawing only have to check CPSM and CSA (MGS3 intro skybox would be drawn piece by piece without this)
|
||||||
|
|
||||||
|
uint64 mask = 0x1f78001c3fffffffull; // TBP0 TBW PSM TW TCC TFX CPSM CSA
|
||||||
|
|
||||||
|
if(wt || PRIM->CTXT == i && ((TEX0.u64 ^ m_env.CTXT[i].TEX0.u64) & mask))
|
||||||
{
|
{
|
||||||
Flush();
|
Flush();
|
||||||
}
|
}
|
||||||
|
@ -743,7 +747,9 @@ template<int i> void GSState::GIFRegHandlerTEX2(const GIFReg* RESTRICT r)
|
||||||
// TFX, TCC, TH, TW, TBW, and TBP0
|
// TFX, TCC, TH, TW, TBW, and TBP0
|
||||||
|
|
||||||
uint64 mask = 0xFFFFFFE003F00000ull; // TEX2 bits
|
uint64 mask = 0xFFFFFFE003F00000ull; // TEX2 bits
|
||||||
|
|
||||||
GIFRegTEX0 TEX0;
|
GIFRegTEX0 TEX0;
|
||||||
|
|
||||||
TEX0.u64 = (m_env.CTXT[i].TEX0.u64 & ~mask) | (r->u64 & mask);
|
TEX0.u64 = (m_env.CTXT[i].TEX0.u64 & ~mask) | (r->u64 & mask);
|
||||||
|
|
||||||
ApplyTEX0(i, TEX0);
|
ApplyTEX0(i, TEX0);
|
||||||
|
|
|
@ -22,6 +22,44 @@
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "GSThread.h"
|
#include "GSThread.h"
|
||||||
|
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
|
||||||
|
InitializeConditionVariablePtr pInitializeConditionVariable;
|
||||||
|
WakeConditionVariablePtr pWakeConditionVariable;
|
||||||
|
WakeAllConditionVariablePtr pWakeAllConditionVariable;
|
||||||
|
SleepConditionVariableSRWPtr pSleepConditionVariableSRW;
|
||||||
|
InitializeSRWLockPtr pInitializeSRWLock;;
|
||||||
|
AcquireSRWLockExclusivePtr pAcquireSRWLockExclusive;
|
||||||
|
ReleaseSRWLockExclusivePtr pReleaseSRWLockExclusive;
|
||||||
|
|
||||||
|
class InitCondVar
|
||||||
|
{
|
||||||
|
HMODULE m_kernel32;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InitCondVar()
|
||||||
|
{
|
||||||
|
m_kernel32 = LoadLibrary("kernel32.dll"); // should not call LoadLibrary from DllMain, but kernel32.dll is the only one guaranteed to be loaded already
|
||||||
|
|
||||||
|
pInitializeConditionVariable = (InitializeConditionVariablePtr)GetProcAddress(m_kernel32, "InitializeConditionVariable");
|
||||||
|
pWakeConditionVariable = (WakeConditionVariablePtr)GetProcAddress(m_kernel32, "WakeConditionVariable");
|
||||||
|
pWakeAllConditionVariable = (WakeAllConditionVariablePtr)GetProcAddress(m_kernel32, "WakeAllConditionVariable");
|
||||||
|
pSleepConditionVariableSRW = (SleepConditionVariableSRWPtr)GetProcAddress(m_kernel32, "SleepConditionVariableSRW");
|
||||||
|
pInitializeSRWLock = (InitializeSRWLockPtr)GetProcAddress(m_kernel32, "InitializeSRWLock");
|
||||||
|
pAcquireSRWLockExclusive = (AcquireSRWLockExclusivePtr)GetProcAddress(m_kernel32, "AcquireSRWLockExclusive");
|
||||||
|
pReleaseSRWLockExclusive = (ReleaseSRWLockExclusivePtr)GetProcAddress(m_kernel32, "ReleaseSRWLockExclusive");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~InitCondVar()
|
||||||
|
{
|
||||||
|
FreeLibrary(m_kernel32);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static InitCondVar s_icv;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
GSThread::GSThread()
|
GSThread::GSThread()
|
||||||
{
|
{
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
|
|
|
@ -23,6 +23,22 @@
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
|
|
||||||
|
typedef void (WINAPI * InitializeConditionVariablePtr)(CONDITION_VARIABLE* ConditionVariable);
|
||||||
|
typedef void (WINAPI * WakeConditionVariablePtr)(CONDITION_VARIABLE* ConditionVariable);
|
||||||
|
typedef void (WINAPI * WakeAllConditionVariablePtr)(CONDITION_VARIABLE* ConditionVariable);
|
||||||
|
typedef void (WINAPI * SleepConditionVariableSRWPtr)(CONDITION_VARIABLE* ConditionVariable, SRWLOCK* SRWLock, DWORD dwMilliseconds, ULONG Flags);
|
||||||
|
typedef void (WINAPI * InitializeSRWLockPtr)(SRWLOCK* SRWLock);
|
||||||
|
typedef void (WINAPI * AcquireSRWLockExclusivePtr)(SRWLOCK* SRWLock);
|
||||||
|
typedef void (WINAPI * ReleaseSRWLockExclusivePtr)(SRWLOCK* SRWLock);
|
||||||
|
|
||||||
|
extern InitializeConditionVariablePtr pInitializeConditionVariable;
|
||||||
|
extern WakeConditionVariablePtr pWakeConditionVariable;
|
||||||
|
extern WakeAllConditionVariablePtr pWakeAllConditionVariable;
|
||||||
|
extern SleepConditionVariableSRWPtr pSleepConditionVariableSRW;
|
||||||
|
extern InitializeSRWLockPtr pInitializeSRWLock;;
|
||||||
|
extern AcquireSRWLockExclusivePtr pAcquireSRWLockExclusive;
|
||||||
|
extern ReleaseSRWLockExclusivePtr pReleaseSRWLockExclusive;
|
||||||
|
|
||||||
class GSThread
|
class GSThread
|
||||||
{
|
{
|
||||||
DWORD m_ThreadId;
|
DWORD m_ThreadId;
|
||||||
|
@ -68,6 +84,32 @@ public:
|
||||||
bool Wait() {return WaitForSingleObject(m_hEvent, INFINITE) == WAIT_OBJECT_0;}
|
bool Wait() {return WaitForSingleObject(m_hEvent, INFINITE) == WAIT_OBJECT_0;}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GSCondVarLock
|
||||||
|
{
|
||||||
|
SRWLOCK m_lock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSCondVarLock() {pInitializeSRWLock(&m_lock);}
|
||||||
|
|
||||||
|
void Lock() {pAcquireSRWLockExclusive(&m_lock);}
|
||||||
|
void Unlock() {pReleaseSRWLockExclusive(&m_lock);}
|
||||||
|
|
||||||
|
operator SRWLOCK* () {return &m_lock;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GSCondVar
|
||||||
|
{
|
||||||
|
CONDITION_VARIABLE m_cv;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSCondVar() {pInitializeConditionVariable(&m_cv);}
|
||||||
|
|
||||||
|
void Set() {pWakeConditionVariable(&m_cv);}
|
||||||
|
void Wait(GSCondVarLock& lock) {pSleepConditionVariableSRW(&m_cv, lock, INFINITE, 0);}
|
||||||
|
|
||||||
|
operator CONDITION_VARIABLE* () {return &m_cv;}
|
||||||
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
@ -128,6 +170,34 @@ public:
|
||||||
bool Wait() {return sem_wait(&m_sem) == 0;}
|
bool Wait() {return sem_wait(&m_sem) == 0;}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GSCondVarLock
|
||||||
|
{
|
||||||
|
pthread_mutex_t m_lock;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSCondVarLock() {pthread_mutex_init(&m_lock, NULL);}
|
||||||
|
virtual ~GSCondVarLock() {pthread_mutex_destroy(&m_lock);}
|
||||||
|
|
||||||
|
void Lock() {pthread_mutex_lock(&m_lock);}
|
||||||
|
void Unlock() {pthread_mutex_unlock(&m_lock);}
|
||||||
|
|
||||||
|
operator pthread_mutex_t* () {return &m_lock;}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GSCondVar
|
||||||
|
{
|
||||||
|
pthread_cond_t m_cv;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GSCondVar() {pthread_cond_init(&m_cv);}
|
||||||
|
virtual ~GSCondVar() {pthread_cond_destroy(&m_cv);}
|
||||||
|
|
||||||
|
void Set() {pthread_cond_signal(&m_cv);}
|
||||||
|
void Wait(GSCondVarLock& lock) {pthread_cond_wait(&m_cv, lock);}
|
||||||
|
|
||||||
|
operator pthread_cond_t* () {return &m_cv;}
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class GSAutoLock
|
class GSAutoLock
|
||||||
|
@ -167,42 +237,21 @@ protected:
|
||||||
queue<T> m_queue;
|
queue<T> m_queue;
|
||||||
volatile bool m_exit;
|
volatile bool m_exit;
|
||||||
struct {GSCritSec lock; GSEvent notempty; volatile long count;} m_ev;
|
struct {GSCritSec lock; GSEvent notempty; volatile long count;} m_ev;
|
||||||
#ifdef _WINDOWS
|
struct {GSCondVar notempty, empty; GSCondVarLock lock; bool available;} m_cv;
|
||||||
struct {SRWLOCK lock; CONDITION_VARIABLE notempty, empty; bool available;} m_cv;
|
|
||||||
HMODULE m_kernel32;
|
|
||||||
typedef void (WINAPI * InitializeConditionVariablePtr)(CONDITION_VARIABLE* ConditionVariable);
|
|
||||||
typedef void (WINAPI * WakeConditionVariablePtr)(CONDITION_VARIABLE* ConditionVariable);
|
|
||||||
typedef void (WINAPI * WakeAllConditionVariablePtr)(CONDITION_VARIABLE* ConditionVariable);
|
|
||||||
typedef void (WINAPI * SleepConditionVariableSRWPtr)(CONDITION_VARIABLE* ConditionVariable, SRWLOCK* SRWLock, DWORD dwMilliseconds, ULONG Flags);
|
|
||||||
typedef void (WINAPI * InitializeSRWLockPtr)(SRWLOCK* SRWLock);
|
|
||||||
typedef void (WINAPI * AcquireSRWLockExclusivePtr)(SRWLOCK* SRWLock);
|
|
||||||
typedef void (WINAPI * ReleaseSRWLockExclusivePtr)(SRWLOCK* SRWLock);
|
|
||||||
InitializeConditionVariablePtr pInitializeConditionVariable;
|
|
||||||
WakeConditionVariablePtr pWakeConditionVariable;
|
|
||||||
WakeAllConditionVariablePtr pWakeAllConditionVariable;
|
|
||||||
SleepConditionVariableSRWPtr pSleepConditionVariableSRW;
|
|
||||||
InitializeSRWLockPtr pInitializeSRWLock;;
|
|
||||||
AcquireSRWLockExclusivePtr pAcquireSRWLockExclusive;
|
|
||||||
ReleaseSRWLockExclusivePtr pReleaseSRWLockExclusive;
|
|
||||||
#elif defined(_LINUX)
|
|
||||||
struct {pthread_mutex_t lock; pthread_cond_t notempty, empty; bool available;} m_cv;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void ThreadProc()
|
void ThreadProc()
|
||||||
{
|
{
|
||||||
|
|
||||||
if(m_cv.available)
|
if(m_cv.available)
|
||||||
{
|
{
|
||||||
#ifdef _WINDOWS
|
m_cv.lock.Lock();
|
||||||
pAcquireSRWLockExclusive(&m_cv.lock);
|
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
while(m_queue.empty())
|
while(m_queue.empty())
|
||||||
{
|
{
|
||||||
pSleepConditionVariableSRW(&m_cv.notempty, &m_cv.lock, INFINITE, 0);
|
m_cv.notempty.Wait(m_cv.lock);
|
||||||
|
|
||||||
if(m_exit) {pReleaseSRWLockExclusive(&m_cv.lock); return;}
|
if(m_exit) {m_cv.lock.Unlock(); return;}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -210,51 +259,20 @@ protected:
|
||||||
|
|
||||||
T item = m_queue.front();
|
T item = m_queue.front();
|
||||||
|
|
||||||
pReleaseSRWLockExclusive(&m_cv.lock);
|
m_cv.lock.Unlock();
|
||||||
|
|
||||||
Process(item);
|
Process(item);
|
||||||
|
|
||||||
pAcquireSRWLockExclusive(&m_cv.lock);
|
m_cv.lock.Lock();
|
||||||
|
|
||||||
m_queue.pop();
|
m_queue.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_queue.empty())
|
if(m_queue.empty())
|
||||||
{
|
{
|
||||||
pWakeConditionVariable(&m_cv.empty);
|
m_cv.empty.Set();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(_LINUX)
|
|
||||||
pthread_mutex_lock(&m_cv.lock);
|
|
||||||
|
|
||||||
while(true)
|
|
||||||
{
|
|
||||||
while(m_queue.empty())
|
|
||||||
{
|
|
||||||
pthread_cond_wait(&m_cv.notempty, &m_cv.lock);
|
|
||||||
|
|
||||||
if(m_exit) {pthread_mutex_unlock(&m_cv.lock); return;}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// NOTE: this is scoped because we must make sure the last item is no longer around when Wait detects an empty queue
|
|
||||||
T item = m_queue.front();
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&m_cv.lock);
|
|
||||||
|
|
||||||
Process(item);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&m_cv.lock);
|
|
||||||
|
|
||||||
m_queue.pop();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m_queue.empty())
|
|
||||||
{
|
|
||||||
pthread_cond_signal(&m_cv.empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -302,33 +320,12 @@ public:
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
|
|
||||||
m_cv.available = false;
|
m_cv.available = pInitializeConditionVariable != NULL;
|
||||||
|
|
||||||
m_kernel32 = LoadLibrary("kernel32.dll");
|
|
||||||
|
|
||||||
pInitializeConditionVariable = (InitializeConditionVariablePtr)GetProcAddress(m_kernel32, "InitializeConditionVariable");
|
|
||||||
pWakeConditionVariable = (WakeConditionVariablePtr)GetProcAddress(m_kernel32, "WakeConditionVariable");
|
|
||||||
pWakeAllConditionVariable = (WakeAllConditionVariablePtr)GetProcAddress(m_kernel32, "WakeAllConditionVariable");
|
|
||||||
pSleepConditionVariableSRW = (SleepConditionVariableSRWPtr)GetProcAddress(m_kernel32, "SleepConditionVariableSRW");
|
|
||||||
pInitializeSRWLock = (InitializeSRWLockPtr)GetProcAddress(m_kernel32, "InitializeSRWLock");
|
|
||||||
pAcquireSRWLockExclusive = (AcquireSRWLockExclusivePtr)GetProcAddress(m_kernel32, "AcquireSRWLockExclusive");
|
|
||||||
pReleaseSRWLockExclusive = (ReleaseSRWLockExclusivePtr)GetProcAddress(m_kernel32, "ReleaseSRWLockExclusive");
|
|
||||||
|
|
||||||
if(pInitializeConditionVariable != NULL)
|
|
||||||
{
|
|
||||||
pInitializeSRWLock(&m_cv.lock);
|
|
||||||
pInitializeConditionVariable(&m_cv.notempty);
|
|
||||||
pInitializeConditionVariable(&m_cv.empty);
|
|
||||||
|
|
||||||
m_cv.available = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif defined(_LINUX)
|
#elif defined(_LINUX)
|
||||||
m_cv.available = true;
|
|
||||||
// FIXME attribute
|
m_cv.available = true;
|
||||||
pthread_cond_init(&m_cv.notempty, NULL);
|
|
||||||
pthread_cond_init(&m_cv.empty, NULL);
|
|
||||||
pthread_mutex_init(&m_cv.lock, NULL);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CreateThread();
|
CreateThread();
|
||||||
|
@ -338,32 +335,14 @@ public:
|
||||||
{
|
{
|
||||||
m_exit = true;
|
m_exit = true;
|
||||||
|
|
||||||
|
|
||||||
if(m_cv.available)
|
if(m_cv.available)
|
||||||
{
|
{
|
||||||
#ifdef _WINDOWS
|
m_cv.notempty.Set();
|
||||||
pWakeConditionVariable(&m_cv.notempty);
|
|
||||||
#elif defined(_LINUX)
|
|
||||||
pthread_cond_signal(&m_cv.notempty);
|
|
||||||
|
|
||||||
pthread_mutex_destroy(&m_cv.lock);
|
|
||||||
pthread_cond_destroy(&m_cv.notempty);
|
|
||||||
pthread_cond_destroy(&m_cv.empty);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_ev.notempty.Set();
|
m_ev.notempty.Set();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WINDOWS
|
|
||||||
if(m_kernel32 != NULL)
|
|
||||||
{
|
|
||||||
FreeLibrary(m_kernel32); // lol, decrement the refcount anyway
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetCount() const
|
int GetCount() const
|
||||||
|
@ -373,31 +352,18 @@ public:
|
||||||
|
|
||||||
virtual void Push(const T& item)
|
virtual void Push(const T& item)
|
||||||
{
|
{
|
||||||
|
|
||||||
if(m_cv.available)
|
if(m_cv.available)
|
||||||
{
|
{
|
||||||
#ifdef _WINDOWS
|
m_cv.lock.Lock();
|
||||||
pAcquireSRWLockExclusive(&m_cv.lock);
|
|
||||||
|
|
||||||
m_queue.push(item);
|
m_queue.push(item);
|
||||||
|
|
||||||
pReleaseSRWLockExclusive(&m_cv.lock);
|
m_cv.lock.Unlock();
|
||||||
|
|
||||||
pWakeConditionVariable(&m_cv.notempty);
|
m_cv.notempty.Set();
|
||||||
#elif defined(_LINUX)
|
|
||||||
pthread_mutex_lock(&m_cv.lock);
|
|
||||||
|
|
||||||
m_queue.push(item);
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&m_cv.lock);
|
|
||||||
|
|
||||||
pthread_cond_signal(&m_cv.notempty);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
GSAutoLock l(&m_ev.lock);
|
GSAutoLock l(&m_ev.lock);
|
||||||
|
|
||||||
m_queue.push(item);
|
m_queue.push(item);
|
||||||
|
@ -412,36 +378,22 @@ public:
|
||||||
|
|
||||||
virtual void Wait()
|
virtual void Wait()
|
||||||
{
|
{
|
||||||
|
|
||||||
if(m_cv.available)
|
if(m_cv.available)
|
||||||
{
|
{
|
||||||
#ifdef _WINDOWS
|
m_cv.lock.Lock();
|
||||||
pAcquireSRWLockExclusive(&m_cv.lock);
|
|
||||||
|
|
||||||
while(!m_queue.empty())
|
while(!m_queue.empty())
|
||||||
{
|
{
|
||||||
pSleepConditionVariableSRW(&m_cv.empty, &m_cv.lock, INFINITE, 0);
|
m_cv.empty.Wait(m_cv.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
pReleaseSRWLockExclusive(&m_cv.lock);
|
m_cv.lock.Unlock();
|
||||||
#elif defined(_LINUX)
|
|
||||||
pthread_mutex_lock(&m_cv.lock);
|
|
||||||
|
|
||||||
while(!m_queue.empty())
|
|
||||||
{
|
|
||||||
pthread_cond_wait(&m_cv.empty, &m_cv.lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&m_cv.lock);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
// NOTE: it is the safest to have our own counter because m_queue.pop() might decrement its own before the last item runs out of its scope and gets destroyed (implementation dependent)
|
// NOTE: it is the safest to have our own counter because m_queue.pop() might decrement its own before the last item runs out of its scope and gets destroyed (implementation dependent)
|
||||||
|
|
||||||
while(m_ev.count > 0) _mm_pause();
|
while(m_ev.count > 0) _mm_pause();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_count++;
|
m_count++;
|
||||||
|
|
|
@ -71,6 +71,17 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// put these into vc9/common7/ide/usertype.dat to have them highlighted
|
||||||
|
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef signed char int8;
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
typedef signed short int16;
|
||||||
|
typedef unsigned int uint32;
|
||||||
|
typedef signed int int32;
|
||||||
|
typedef unsigned long long uint64;
|
||||||
|
typedef signed long long int64;
|
||||||
|
|
||||||
// stdc
|
// stdc
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
@ -115,6 +126,57 @@ using namespace std;
|
||||||
|
|
||||||
using namespace stdext;
|
using namespace stdext;
|
||||||
|
|
||||||
|
// hashing algoritms at: http://www.cris.com/~Ttwang/tech/inthash.htm
|
||||||
|
// default hash_compare does ldiv and other crazy stuff to reduce speed
|
||||||
|
|
||||||
|
template<> class hash_compare<uint32>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {bucket_size = 1};
|
||||||
|
|
||||||
|
size_t operator()(uint32 key) const
|
||||||
|
{
|
||||||
|
key += ~(key << 15);
|
||||||
|
key ^= (key >> 10);
|
||||||
|
key += (key << 3);
|
||||||
|
key ^= (key >> 6);
|
||||||
|
key += ~(key << 11);
|
||||||
|
key ^= (key >> 16);
|
||||||
|
|
||||||
|
return (size_t)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(uint32 a, uint32 b) const
|
||||||
|
{
|
||||||
|
return a < b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<> class hash_compare<uint64>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {bucket_size = 1};
|
||||||
|
|
||||||
|
size_t operator()(uint64 key) const
|
||||||
|
{
|
||||||
|
key += ~(key << 32);
|
||||||
|
key ^= (key >> 22);
|
||||||
|
key += ~(key << 13);
|
||||||
|
key ^= (key >> 8);
|
||||||
|
key += (key << 3);
|
||||||
|
key ^= (key >> 15);
|
||||||
|
key += ~(key << 27);
|
||||||
|
key ^= (key >> 31);
|
||||||
|
|
||||||
|
return (size_t)key;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(uint64 a, uint64 b) const
|
||||||
|
{
|
||||||
|
return a < b;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#define vsnprintf _vsnprintf
|
#define vsnprintf _vsnprintf
|
||||||
#define snprintf _snprintf
|
#define snprintf _snprintf
|
||||||
|
|
||||||
|
@ -171,19 +233,6 @@ struct aligned_free_object {template<class T> void operator()(T& p) {_aligned_fr
|
||||||
struct aligned_free_first {template<class T> void operator()(T& p) {_aligned_free(p.first);}};
|
struct aligned_free_first {template<class T> void operator()(T& p) {_aligned_free(p.first);}};
|
||||||
struct aligned_free_second {template<class T> void operator()(T& p) {_aligned_free(p.second);}};
|
struct aligned_free_second {template<class T> void operator()(T& p) {_aligned_free(p.second);}};
|
||||||
|
|
||||||
// syntactic sugar
|
|
||||||
|
|
||||||
// put these into vc9/common7/ide/usertype.dat to have them highlighted
|
|
||||||
|
|
||||||
typedef unsigned char uint8;
|
|
||||||
typedef signed char int8;
|
|
||||||
typedef unsigned short uint16;
|
|
||||||
typedef signed short int16;
|
|
||||||
typedef unsigned int uint32;
|
|
||||||
typedef signed int int32;
|
|
||||||
typedef unsigned long long uint64;
|
|
||||||
typedef signed long long int64;
|
|
||||||
|
|
||||||
#define countof(a) (sizeof(a) / sizeof(a[0]))
|
#define countof(a) (sizeof(a) / sizeof(a[0]))
|
||||||
|
|
||||||
#define ALIGN_STACK(n) __aligned(int, n) __dummy;
|
#define ALIGN_STACK(n) __aligned(int, n) __dummy;
|
||||||
|
|
Loading…
Reference in New Issue