Reuse the same concurrent rendering thread, instead of creating a new one, to work around a bug in the Linux nVidia drivers, where rendering will stop working after ~128 threads. Use BeginConcurrentRenderingMainThread/EndConcurrentRenderingMainThread.
This commit is contained in:
@@ -201,17 +201,26 @@ public:
|
|||||||
ConcurrentRenderer();
|
ConcurrentRenderer();
|
||||||
~ConcurrentRenderer();
|
~ConcurrentRenderer();
|
||||||
|
|
||||||
|
void Start();
|
||||||
|
void Stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RageThread m_Thread;
|
RageThread m_Thread;
|
||||||
|
RageEvent m_Event;
|
||||||
bool m_bShutdown;
|
bool m_bShutdown;
|
||||||
void RenderThread();
|
void RenderThread();
|
||||||
static int StartRenderThread( void *p );
|
static int StartRenderThread( void *p );
|
||||||
|
|
||||||
|
enum State { RENDERING_IDLE, RENDERING_START, RENDERING_ACTIVE, RENDERING_END };
|
||||||
|
State m_State;
|
||||||
};
|
};
|
||||||
static ConcurrentRenderer *g_pConcurrentRenderer = NULL;
|
static ConcurrentRenderer *g_pConcurrentRenderer = NULL;
|
||||||
|
|
||||||
ConcurrentRenderer::ConcurrentRenderer()
|
ConcurrentRenderer::ConcurrentRenderer():
|
||||||
|
m_Event("ConcurrentRenderer")
|
||||||
{
|
{
|
||||||
m_bShutdown = false;
|
m_bShutdown = false;
|
||||||
|
m_State = RENDERING_IDLE;
|
||||||
|
|
||||||
m_Thread.SetName( "ConcurrentRenderer" );
|
m_Thread.SetName( "ConcurrentRenderer" );
|
||||||
m_Thread.Create( StartRenderThread, this );
|
m_Thread.Create( StartRenderThread, this );
|
||||||
@@ -219,32 +228,86 @@ ConcurrentRenderer::ConcurrentRenderer()
|
|||||||
|
|
||||||
ConcurrentRenderer::~ConcurrentRenderer()
|
ConcurrentRenderer::~ConcurrentRenderer()
|
||||||
{
|
{
|
||||||
|
ASSERT( m_State == RENDERING_IDLE );
|
||||||
m_bShutdown = true;
|
m_bShutdown = true;
|
||||||
m_Thread.Wait();
|
m_Thread.Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConcurrentRenderer::Start()
|
||||||
|
{
|
||||||
|
DISPLAY->BeginConcurrentRenderingMainThread();
|
||||||
|
|
||||||
|
m_Event.Lock();
|
||||||
|
ASSERT( m_State == RENDERING_IDLE );
|
||||||
|
m_State = RENDERING_START;
|
||||||
|
m_Event.Signal();
|
||||||
|
while( m_State != RENDERING_ACTIVE )
|
||||||
|
m_Event.Wait();
|
||||||
|
m_Event.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConcurrentRenderer::Stop()
|
||||||
|
{
|
||||||
|
m_Event.Lock();
|
||||||
|
ASSERT( m_State == RENDERING_ACTIVE );
|
||||||
|
m_State = RENDERING_END;
|
||||||
|
m_Event.Signal();
|
||||||
|
while( m_State != RENDERING_IDLE )
|
||||||
|
m_Event.Wait();
|
||||||
|
m_Event.Unlock();
|
||||||
|
|
||||||
|
DISPLAY->EndConcurrentRenderingMainThread();
|
||||||
|
}
|
||||||
|
|
||||||
void ConcurrentRenderer::RenderThread()
|
void ConcurrentRenderer::RenderThread()
|
||||||
{
|
{
|
||||||
ASSERT( SCREENMAN != NULL );
|
ASSERT( SCREENMAN != NULL );
|
||||||
|
|
||||||
|
while( !m_bShutdown )
|
||||||
|
{
|
||||||
|
m_Event.Lock();
|
||||||
|
while( m_State == RENDERING_IDLE && !m_bShutdown )
|
||||||
|
m_Event.Wait();
|
||||||
|
m_Event.Unlock();
|
||||||
|
|
||||||
|
if( m_State == RENDERING_START )
|
||||||
|
{
|
||||||
|
/* We're starting to render. Set up, and then kick the event to wake
|
||||||
|
* up the calling thread. */
|
||||||
DISPLAY->BeginConcurrentRendering();
|
DISPLAY->BeginConcurrentRendering();
|
||||||
HOOKS->SetupConcurrentRenderingThread();
|
HOOKS->SetupConcurrentRenderingThread();
|
||||||
|
|
||||||
LOG->Trace( "ConcurrentRenderer::RenderThread start" );
|
LOG->Trace( "ConcurrentRenderer::RenderThread start" );
|
||||||
|
|
||||||
/* This is called during Update(). The next thing the game loop
|
m_Event.Lock();
|
||||||
|
m_State = RENDERING_ACTIVE;
|
||||||
|
m_Event.Signal();
|
||||||
|
m_Event.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is started during Update(). The next thing the game loop
|
||||||
* will do is Draw, so shift operations around to put Draw at the
|
* will do is Draw, so shift operations around to put Draw at the
|
||||||
* top. This makes sure updates are seamless. */
|
* top. This makes sure updates are seamless. */
|
||||||
while( !m_bShutdown )
|
if( m_State == RENDERING_ACTIVE )
|
||||||
{
|
{
|
||||||
SCREENMAN->Draw();
|
SCREENMAN->Draw();
|
||||||
|
|
||||||
float fDeltaTime = g_GameplayTimer.GetDeltaTime();
|
float fDeltaTime = g_GameplayTimer.GetDeltaTime();
|
||||||
SCREENMAN->Update( fDeltaTime );
|
SCREENMAN->Update( fDeltaTime );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( m_State == RENDERING_END )
|
||||||
|
{
|
||||||
|
LOG->Trace( "ConcurrentRenderer::RenderThread done" );
|
||||||
|
|
||||||
DISPLAY->EndConcurrentRendering();
|
DISPLAY->EndConcurrentRendering();
|
||||||
|
|
||||||
LOG->Trace( "ConcurrentRenderer::RenderThread done" );
|
m_Event.Lock();
|
||||||
|
m_State = RENDERING_IDLE;
|
||||||
|
m_Event.Signal();
|
||||||
|
m_Event.Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConcurrentRenderer::StartRenderThread( void *p )
|
int ConcurrentRenderer::StartRenderThread( void *p )
|
||||||
@@ -255,13 +318,14 @@ int ConcurrentRenderer::StartRenderThread( void *p )
|
|||||||
|
|
||||||
void GameLoop::StartConcurrentRendering()
|
void GameLoop::StartConcurrentRendering()
|
||||||
{
|
{
|
||||||
ASSERT( g_pConcurrentRenderer == NULL );
|
if( g_pConcurrentRenderer == NULL )
|
||||||
g_pConcurrentRenderer = new ConcurrentRenderer;
|
g_pConcurrentRenderer = new ConcurrentRenderer;
|
||||||
|
g_pConcurrentRenderer->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameLoop::FinishConcurrentRendering()
|
void GameLoop::FinishConcurrentRendering()
|
||||||
{
|
{
|
||||||
SAFE_DELETE( g_pConcurrentRenderer );
|
g_pConcurrentRenderer->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
Reference in New Issue
Block a user