mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-15 07:00:58 +00:00
Merge remote-tracking branch 'RBDOOM-3-BFG/master'
This commit is contained in:
commit
3fd3a6b284
14 changed files with 332 additions and 265 deletions
|
@ -411,7 +411,10 @@ bool idFile_SaveGamePipelined::OpenForWriting( const char* const filename, bool
|
|||
{
|
||||
compressThread = new( TAG_IDFILE ) idSGFcompressThread();
|
||||
compressThread->sgf = this;
|
||||
compressThread->StartWorkerThread( "SGF_CompressThread", CORE_2B, THREAD_NORMAL );
|
||||
// DG: change threadname from "SGF_CompressThread" to "SGF_Compress", because Linux
|
||||
// has a 15 (+ \0) char limit for threadnames. also, "thread" in a threadname is redundant
|
||||
compressThread->StartWorkerThread( "SGF_Compress", CORE_2B, THREAD_NORMAL );
|
||||
// DG end
|
||||
}
|
||||
if( nativeFile != NULL && sgf_threads.GetInteger() >= 2 )
|
||||
{
|
||||
|
@ -468,7 +471,10 @@ bool idFile_SaveGamePipelined::OpenForWriting( idFile* file )
|
|||
{
|
||||
compressThread = new( TAG_IDFILE ) idSGFcompressThread();
|
||||
compressThread->sgf = this;
|
||||
compressThread->StartWorkerThread( "SGF_CompressThread", CORE_2B, THREAD_NORMAL );
|
||||
// DG: change threadname from "SGF_CompressThread" to "SGF_Compress", because Linux
|
||||
// has a 15 (+ \0) char limit for threadnames. also, "thread" in a threadname is redundant
|
||||
compressThread->StartWorkerThread( "SGF_Compress", CORE_2B, THREAD_NORMAL );
|
||||
// DG end
|
||||
}
|
||||
if( nativeFile != NULL && sgf_threads.GetInteger() >= 2 )
|
||||
{
|
||||
|
@ -810,7 +816,10 @@ bool idFile_SaveGamePipelined::OpenForReading( const char* const filename, bool
|
|||
{
|
||||
decompressThread = new( TAG_IDFILE ) idSGFdecompressThread();
|
||||
decompressThread->sgf = this;
|
||||
decompressThread->StartWorkerThread( "SGF_DecompressThread", CORE_2B, THREAD_NORMAL );
|
||||
// DG: change threadname from "SGF_DecompressThread" to "SGF_Decompress", because Linux
|
||||
// has a 15 (+ \0) char limit for threadnames. also, "thread" in a threadname is redundant
|
||||
decompressThread->StartWorkerThread( "SGF_Decompress", CORE_2B, THREAD_NORMAL );
|
||||
// DG end
|
||||
}
|
||||
if( nativeFile != NULL && sgf_threads.GetInteger() >= 2 )
|
||||
{
|
||||
|
@ -857,7 +866,10 @@ bool idFile_SaveGamePipelined::OpenForReading( idFile* file )
|
|||
{
|
||||
decompressThread = new( TAG_IDFILE ) idSGFdecompressThread();
|
||||
decompressThread->sgf = this;
|
||||
decompressThread->StartWorkerThread( "SGF_DecompressThread", CORE_1B, THREAD_NORMAL );
|
||||
// DG: change threadname from "SGF_DecompressThread" to "SGF_Decompress", because Linux
|
||||
// has a 15 (+ \0) char limit for threadnames. also, "thread" in a threadname is redundant
|
||||
decompressThread->StartWorkerThread( "SGF_Decompress", CORE_1B, THREAD_NORMAL );
|
||||
// DG end
|
||||
}
|
||||
if( nativeFile != NULL && sgf_threads.GetInteger() >= 2 )
|
||||
{
|
||||
|
|
|
@ -1107,7 +1107,13 @@ idJobThread::Start
|
|||
void idJobThread::Start( core_t core, unsigned int threadNum )
|
||||
{
|
||||
this->threadNum = threadNum;
|
||||
StartWorkerThread( va( "JobListProcessor_%d", threadNum ), core, THREAD_NORMAL, JOB_THREAD_STACK_SIZE );
|
||||
// DG: change threadname from "JobListProcessor_%d" to "JLProc_%d", because Linux
|
||||
// has a 15 (+ \0) char limit for threadnames.
|
||||
// furthermore: va is not thread safe, use snPrintf instead
|
||||
char name[16];
|
||||
idStr::snPrintf( name, 16, "JLProc_%d", threadNum );
|
||||
StartWorkerThread( name, core, THREAD_NORMAL, JOB_THREAD_STACK_SIZE );
|
||||
// DG end
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1493,4 +1499,4 @@ void idParallelJobManagerLocal::Submit( idParallelJobList_Threads* jobList, int
|
|||
threads[i].AddJobList( jobList );
|
||||
threads[i].SignalWork();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,8 +93,6 @@ that a thread can wait on for it to be raised. It's used to indicate data is av
|
|||
a thread has reached a specific point.
|
||||
================================================
|
||||
*/
|
||||
// RB begin
|
||||
#if defined(_WIN32)
|
||||
class idSysSignal
|
||||
{
|
||||
public:
|
||||
|
@ -132,36 +130,6 @@ private:
|
|||
idSysSignal( const idSysSignal& s ) {}
|
||||
void operator=( const idSysSignal& s ) {}
|
||||
};
|
||||
#else
|
||||
class idSysSignal
|
||||
{
|
||||
public:
|
||||
static const int WAIT_INFINITE = -1;
|
||||
|
||||
idSysSignal( bool manualReset = false );
|
||||
~idSysSignal();
|
||||
|
||||
void Raise();
|
||||
|
||||
void Clear();
|
||||
|
||||
// Wait returns true if the object is in a signalled state and
|
||||
// returns false if the wait timed out. Wait also clears the signalled
|
||||
// state when the signalled state is reached within the time out period.
|
||||
bool Wait( int timeout = WAIT_INFINITE );
|
||||
|
||||
private:
|
||||
pthread_mutex_t mutex;
|
||||
pthread_cond_t cond;
|
||||
bool signaled;
|
||||
int signalCounter;
|
||||
bool waiting;
|
||||
bool manualReset;
|
||||
|
||||
idSysSignal( const idSysSignal& s ) {}
|
||||
void operator=( const idSysSignal& s ) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
================================================
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2012 Robert Beckebans
|
||||
Copyright (C) 2012-2013 Robert Beckebans
|
||||
Copyright (C) 2013 Daniel Gibson
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -29,11 +30,63 @@ If you have questions concerning this license or the applicable additional terms
|
|||
#pragma hdrstop
|
||||
#include "../../precompiled.h"
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
#include <pthread_ng.h> // for pthread_set_name_np
|
||||
#endif
|
||||
|
||||
// DG: Note: On Linux you need at least (e)glibc 2.12 to be able to set the threadname
|
||||
//#define DEBUG_THREADS
|
||||
|
||||
typedef void* ( *pthread_function_t )( void* );
|
||||
|
||||
/*
|
||||
========================
|
||||
Sys_SetThreadName
|
||||
|
||||
caedes: This should be seen as a helper-function for Sys_CreateThread() only.
|
||||
(re)setting the name of a running thread seems like a bad idea and
|
||||
currently (fresh d3 bfg source) isn't done anyway.
|
||||
Furthermore SDL doesn't support it
|
||||
|
||||
========================
|
||||
*/
|
||||
#ifdef DEBUG_THREADS
|
||||
static int Sys_SetThreadName( pthread_t handle, const char* name )
|
||||
{
|
||||
int ret = 0;
|
||||
#ifdef __linux__
|
||||
// NOTE: linux only supports threadnames up to 16chars *including* terminating NULL
|
||||
// http://man7.org/linux/man-pages/man3/pthread_setname_np.3.html
|
||||
// on my machine a longer name (eg "JobListProcessor_0") caused an ENOENT error (instead of ERANGE)
|
||||
assert( strlen( name ) < 16 );
|
||||
|
||||
ret = pthread_setname_np( handle, name );
|
||||
if( ret != 0 )
|
||||
idLib::common->Printf( "Setting threadname \"%s\" failed, reason: %s (%i)\n", name, strerror( errno ), errno );
|
||||
// pthread_getname_np(pthread_t, char*, size_t)
|
||||
#elif defined(__FreeBSD__)
|
||||
// according to http://www.freebsd.org/cgi/man.cgi?query=pthread_set_name_np&sektion=3
|
||||
// the interface is void pthread_set_name_np(pthread_t tid, const char *name);
|
||||
pthread_set_name_np( handle, name ); // doesn't return anything
|
||||
// seems like there is no get_name equivalent
|
||||
#endif
|
||||
/* TODO: OSX:
|
||||
// according to http://stackoverflow.com/a/7989973
|
||||
// this needs to be called in the thread to be named!
|
||||
ret = pthread_setname_np(name);
|
||||
// int pthread_getname_np(pthread_t, char*, size_t);
|
||||
|
||||
// so we'd have to wrap the xthread_t function in Sys_CreateThread and set the name in the wrapping function...
|
||||
*/
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO: Sys_GetThreadName() ?
|
||||
#endif // DEBUG_THREADS
|
||||
|
||||
|
||||
|
||||
/*
|
||||
========================
|
||||
Sys_Createthread
|
||||
|
@ -41,8 +94,6 @@ Sys_Createthread
|
|||
*/
|
||||
uintptr_t Sys_CreateThread( xthread_t function, void* parms, xthreadPriority priority, const char* name, core_t core, int stackSize, bool suspended )
|
||||
{
|
||||
//Sys_EnterCriticalSection();
|
||||
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init( &attr );
|
||||
|
||||
|
@ -58,37 +109,85 @@ uintptr_t Sys_CreateThread( xthread_t function, void* parms, xthreadPriority pri
|
|||
idLib::common->FatalError( "ERROR: pthread_create %s failed\n", name );
|
||||
return ( uintptr_t )0;
|
||||
}
|
||||
pthread_attr_destroy( &attr );
|
||||
|
||||
// RB: TODO pthread_setname_np is different on Linux, MacOSX and other systems
|
||||
#if defined(DEBUG_THREADS)
|
||||
if( pthread_setname_np( handle, name ) != 0 )
|
||||
if( Sys_SetThreadName( handle, name ) != 0 )
|
||||
{
|
||||
idLib::common->FatalError( "ERROR: pthread_setname_np %s failed\n", name );
|
||||
idLib::common->Warning( "Warning: pthread_setname_np %s failed\n", name );
|
||||
return ( uintptr_t )0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
TODO RB: support thread priorities?
|
||||
pthread_attr_destroy( &attr );
|
||||
|
||||
|
||||
#if 0
|
||||
// RB: realtime policies require root privileges
|
||||
|
||||
// all Linux threads have one of the following scheduling policies:
|
||||
|
||||
// SCHED_OTHER or SCHED_NORMAL: the default policy, priority: [-20..0..19], default 0
|
||||
|
||||
// SCHED_FIFO: first in/first out realtime policy
|
||||
|
||||
// SCHED_RR: round-robin realtime policy
|
||||
|
||||
// SCHED_BATCH: similar to SCHED_OTHER, but with a throughput orientation
|
||||
|
||||
// SCHED_IDLE: lower priority than SCHED_OTHER
|
||||
|
||||
int schedulePolicy = SCHED_OTHER;
|
||||
struct sched_param scheduleParam;
|
||||
|
||||
int error = pthread_getschedparam( handle, &schedulePolicy, &scheduleParam );
|
||||
if( error != 0 )
|
||||
{
|
||||
idLib::common->FatalError( "ERROR: pthread_getschedparam %s failed: %s\n", name, strerror( error ) );
|
||||
return ( uintptr_t )0;
|
||||
}
|
||||
|
||||
schedulePolicy = SCHED_FIFO;
|
||||
|
||||
int minPriority = sched_get_priority_min( schedulePolicy );
|
||||
int maxPriority = sched_get_priority_max( schedulePolicy );
|
||||
|
||||
if( priority == THREAD_HIGHEST )
|
||||
{
|
||||
SetThreadPriority( ( HANDLE )handle, THREAD_PRIORITY_HIGHEST ); // we better sleep enough to do this
|
||||
// we better sleep enough to do this
|
||||
scheduleParam.__sched_priority = maxPriority;
|
||||
}
|
||||
else if( priority == THREAD_ABOVE_NORMAL )
|
||||
{
|
||||
SetThreadPriority( ( HANDLE )handle, THREAD_PRIORITY_ABOVE_NORMAL );
|
||||
scheduleParam.__sched_priority = Lerp( minPriority, maxPriority, 0.75f );
|
||||
}
|
||||
else if( priority == THREAD_NORMAL )
|
||||
{
|
||||
scheduleParam.__sched_priority = Lerp( minPriority, maxPriority, 0.5f );
|
||||
}
|
||||
else if( priority == THREAD_BELOW_NORMAL )
|
||||
{
|
||||
SetThreadPriority( ( HANDLE )handle, THREAD_PRIORITY_BELOW_NORMAL );
|
||||
scheduleParam.__sched_priority = Lerp( minPriority, maxPriority, 0.25f );
|
||||
}
|
||||
else if( priority == THREAD_LOWEST )
|
||||
{
|
||||
SetThreadPriority( ( HANDLE )handle, THREAD_PRIORITY_LOWEST );
|
||||
scheduleParam.__sched_priority = minPriority;
|
||||
}
|
||||
*/
|
||||
|
||||
// set new priority
|
||||
error = pthread_setschedparam( handle, schedulePolicy, &scheduleParam );
|
||||
if( error != 0 )
|
||||
{
|
||||
idLib::common->FatalError( "ERROR: pthread_setschedparam( name = %s, policy = %i, priority = %i ) failed: %s\n", name, schedulePolicy, scheduleParam.__sched_priority, strerror( error ) );
|
||||
return ( uintptr_t )0;
|
||||
}
|
||||
|
||||
pthread_getschedparam( handle, &schedulePolicy, &scheduleParam );
|
||||
if( error != 0 )
|
||||
{
|
||||
idLib::common->FatalError( "ERROR: pthread_getschedparam %s failed: %s\n", name, strerror( error ) );
|
||||
return ( uintptr_t )0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Under Linux, we don't set the thread affinity and let the OS deal with scheduling
|
||||
|
||||
|
@ -104,7 +203,7 @@ Sys_GetCurrentThreadID
|
|||
uintptr_t Sys_GetCurrentThreadID()
|
||||
{
|
||||
/*
|
||||
* This cast is save because pthread_self()
|
||||
* This cast is safe because pthread_self()
|
||||
* returns a pointer and uintptr_t is
|
||||
* designed to hold a pointer. The compiler
|
||||
* is just too stupid to know. :)
|
||||
|
@ -163,8 +262,23 @@ void Sys_Yield()
|
|||
================================================================================================
|
||||
*/
|
||||
|
||||
idSysSignal::idSysSignal( bool manualReset )
|
||||
/*
|
||||
========================
|
||||
Sys_SignalCreate
|
||||
========================
|
||||
*/
|
||||
void Sys_SignalCreate( signalHandle_t& handle, bool manualReset )
|
||||
{
|
||||
// handle = CreateEvent( NULL, manualReset, FALSE, NULL );
|
||||
|
||||
handle.manualReset = manualReset;
|
||||
// if this is true, the signal is only set to nonsignaled when Clear() is called,
|
||||
// else it's "auto-reset" and the state is set to !signaled after a single waiting
|
||||
// thread has been released
|
||||
|
||||
// the inital state is always "not signaled"
|
||||
handle.signaled = false;
|
||||
handle.waiting = 0;
|
||||
#if 0
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
|
@ -174,121 +288,138 @@ idSysSignal::idSysSignal( bool manualReset )
|
|||
pthread_mutex_init( &mutex, &attr );
|
||||
pthread_mutexattr_destroy( &attr );
|
||||
#else
|
||||
pthread_mutex_init( &mutex, NULL );
|
||||
pthread_mutex_init( &handle.mutex, NULL );
|
||||
#endif
|
||||
|
||||
pthread_cond_init( &cond, NULL );
|
||||
pthread_cond_init( &handle.cond, NULL );
|
||||
|
||||
signaled = false;
|
||||
signalCounter = 0;
|
||||
waiting = false;
|
||||
this->manualReset = manualReset;
|
||||
}
|
||||
|
||||
idSysSignal::~idSysSignal()
|
||||
/*
|
||||
========================
|
||||
Sys_SignalDestroy
|
||||
========================
|
||||
*/
|
||||
void Sys_SignalDestroy( signalHandle_t& handle )
|
||||
{
|
||||
pthread_cond_destroy( &cond );
|
||||
pthread_mutex_destroy( &mutex );
|
||||
// CloseHandle( handle );
|
||||
handle.signaled = false;
|
||||
handle.waiting = 0;
|
||||
pthread_mutex_destroy( &handle.mutex );
|
||||
pthread_cond_destroy( &handle.cond );
|
||||
}
|
||||
|
||||
void idSysSignal::Raise()
|
||||
/*
|
||||
========================
|
||||
Sys_SignalRaise
|
||||
========================
|
||||
*/
|
||||
void Sys_SignalRaise( signalHandle_t& handle )
|
||||
{
|
||||
pthread_mutex_lock( &mutex );
|
||||
// SetEvent( handle );
|
||||
pthread_mutex_lock( &handle.mutex );
|
||||
|
||||
//if( waiting )
|
||||
if( handle.manualReset )
|
||||
{
|
||||
//pthread_cond_signal( &cond );
|
||||
//pthread_cond_broadcast( &cond );
|
||||
}
|
||||
//else
|
||||
if( !signaled )
|
||||
{
|
||||
// emulate Windows behaviour: if no thread is waiting, leave the signal on so next wait keeps going
|
||||
signaled = true;
|
||||
signalCounter++;
|
||||
|
||||
pthread_cond_signal( &cond );
|
||||
//pthread_cond_broadcast( &cond );
|
||||
}
|
||||
|
||||
pthread_mutex_unlock( &mutex );
|
||||
}
|
||||
|
||||
void idSysSignal::Clear()
|
||||
{
|
||||
pthread_mutex_lock( &mutex );
|
||||
|
||||
signaled = false;
|
||||
|
||||
pthread_mutex_unlock( &mutex );
|
||||
}
|
||||
|
||||
// Wait returns true if the object is in a signalled state and
|
||||
// returns false if the wait timed out. Wait also clears the signalled
|
||||
// state when the signalled state is reached within the time out period.
|
||||
bool idSysSignal::Wait( int timeout )
|
||||
{
|
||||
pthread_mutex_lock( &mutex );
|
||||
|
||||
int result = 0;
|
||||
|
||||
#if 1
|
||||
assert( !waiting ); // WaitForEvent from multiple threads? that wouldn't be good
|
||||
|
||||
if( signaled )
|
||||
{
|
||||
if( !manualReset )
|
||||
{
|
||||
// emulate Windows behaviour: signal has been raised already. clear and keep going
|
||||
signaled = false;
|
||||
result = 0;
|
||||
}
|
||||
// signaled until reset
|
||||
handle.signaled = true;
|
||||
// wake *all* threads waiting on this cond
|
||||
pthread_cond_broadcast( &handle.cond );
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
|
||||
#if 0
|
||||
|
||||
int signalValue = signalCounter;
|
||||
//while( !signaled && signalValue == signalCounter )
|
||||
#endif
|
||||
// automode: signaled until first thread is released
|
||||
if( handle.waiting > 0 )
|
||||
{
|
||||
waiting = true;
|
||||
|
||||
if( timeout == WAIT_INFINITE )
|
||||
{
|
||||
result = pthread_cond_wait( &cond, &mutex );
|
||||
|
||||
assert( result == 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
timespec ts;
|
||||
clock_gettime( CLOCK_REALTIME, &ts );
|
||||
// DG: handle timeouts > 1s better
|
||||
int64 t = timeout * 1000000;
|
||||
ts.tv_nsec += t % 1000000000;
|
||||
ts.tv_sec += t / 1000000000;
|
||||
// DG end
|
||||
result = pthread_cond_timedwait( &cond, &mutex, &ts );
|
||||
|
||||
assert( result == 0 || ( timeout != idSysSignal::WAIT_INFINITE && result == ETIMEDOUT ) );
|
||||
}
|
||||
|
||||
waiting = false;
|
||||
// there are waiting threads => release one
|
||||
pthread_cond_signal( &handle.cond );
|
||||
}
|
||||
|
||||
if( !manualReset )
|
||||
else
|
||||
{
|
||||
signaled = false;
|
||||
// no waiting threads, save signal
|
||||
handle.signaled = true;
|
||||
// while the MSDN documentation is a bit unspecific about what happens
|
||||
// when SetEvent() is called n times without a wait inbetween
|
||||
// (will only one wait be successful afterwards or n waits?)
|
||||
// it seems like the signaled state is a flag, not a counter.
|
||||
// http://stackoverflow.com/a/13703585 claims the same.
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock( &mutex );
|
||||
|
||||
return ( result == 0 );
|
||||
pthread_mutex_unlock( &handle.mutex );
|
||||
}
|
||||
|
||||
/*
|
||||
========================
|
||||
Sys_SignalClear
|
||||
========================
|
||||
*/
|
||||
void Sys_SignalClear( signalHandle_t& handle )
|
||||
{
|
||||
// ResetEvent( handle );
|
||||
pthread_mutex_lock( &handle.mutex );
|
||||
|
||||
// TODO: probably signaled could be atomically changed?
|
||||
handle.signaled = false;
|
||||
|
||||
pthread_mutex_unlock( &handle.mutex );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
========================
|
||||
Sys_SignalWait
|
||||
========================
|
||||
*/
|
||||
bool Sys_SignalWait( signalHandle_t& handle, int timeout )
|
||||
{
|
||||
//DWORD result = WaitForSingleObject( handle, timeout == idSysSignal::WAIT_INFINITE ? INFINITE : timeout );
|
||||
//assert( result == WAIT_OBJECT_0 || ( timeout != idSysSignal::WAIT_INFINITE && result == WAIT_TIMEOUT ) );
|
||||
//return ( result == WAIT_OBJECT_0 );
|
||||
|
||||
int status;
|
||||
pthread_mutex_lock( &handle.mutex );
|
||||
|
||||
if( handle.signaled ) // there is a signal that hasn't been used yet
|
||||
{
|
||||
if( ! handle.manualReset ) // for auto-mode only one thread may be released - this one.
|
||||
handle.signaled = false;
|
||||
|
||||
status = 0; // success!
|
||||
}
|
||||
else // we'll have to wait for a signal
|
||||
{
|
||||
++handle.waiting;
|
||||
if( timeout == idSysSignal::WAIT_INFINITE )
|
||||
{
|
||||
status = pthread_cond_wait( &handle.cond, &handle.mutex );
|
||||
}
|
||||
else
|
||||
{
|
||||
timespec ts;
|
||||
clock_gettime( CLOCK_REALTIME, &ts );
|
||||
// DG: handle timeouts > 1s better
|
||||
ts.tv_nsec += ( timeout % 1000 ) * 1000000; // millisec to nanosec
|
||||
ts.tv_sec += timeout / 1000;
|
||||
if( ts.tv_nsec >= 1000000000 ) // nanoseconds are more than one second
|
||||
{
|
||||
ts.tv_nsec -= 1000000000; // remove one second in nanoseconds
|
||||
ts.tv_sec += 1; // add one second to seconds
|
||||
}
|
||||
// DG end
|
||||
status = pthread_cond_timedwait( &handle.cond, &handle.mutex, &ts );
|
||||
}
|
||||
--handle.waiting;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock( &handle.mutex );
|
||||
|
||||
assert( status == 0 || ( timeout != idSysSignal::WAIT_INFINITE && status == ETIMEDOUT ) );
|
||||
|
||||
return ( status == 0 );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
================================================================================================
|
||||
|
||||
|
|
|
@ -45,8 +45,19 @@ typedef CRITICAL_SECTION mutexHandle_t;
|
|||
typedef HANDLE signalHandle_t;
|
||||
typedef LONG interlockedInt_t;
|
||||
#else
|
||||
|
||||
struct signalHandle_t
|
||||
{
|
||||
// DG: all this stuff is needed to emulate Window's Event API
|
||||
// (CreateEvent(), SetEvent(), WaitForSingleObject(), ...)
|
||||
pthread_cond_t cond;
|
||||
pthread_mutex_t mutex;
|
||||
int waiting; // number of threads waiting for a signal
|
||||
bool manualReset;
|
||||
bool signaled; // is it signaled right now?
|
||||
};
|
||||
|
||||
typedef pthread_mutex_t mutexHandle_t;
|
||||
typedef pthread_cond_t signalHandle_t;
|
||||
typedef int interlockedInt_t;
|
||||
#endif
|
||||
// RB end
|
||||
|
@ -195,15 +206,11 @@ uintptr_t Sys_CreateThread( xthread_t function, void* parms, xthreadPriority p
|
|||
void Sys_DestroyThread( uintptr_t threadHandle );
|
||||
void Sys_SetCurrentThreadName( const char* name );
|
||||
|
||||
// use alternative pthread implementation in idSysSignal
|
||||
#if defined(_WIN32)
|
||||
void Sys_SignalCreate( signalHandle_t& handle, bool manualReset );
|
||||
void Sys_SignalDestroy( signalHandle_t& handle );
|
||||
void Sys_SignalRaise( signalHandle_t& handle );
|
||||
void Sys_SignalClear( signalHandle_t& handle );
|
||||
bool Sys_SignalWait( signalHandle_t& handle, int timeout );
|
||||
#endif
|
||||
// RB end
|
||||
|
||||
void Sys_MutexCreate( mutexHandle_t& handle );
|
||||
void Sys_MutexDestroy( mutexHandle_t& handle );
|
||||
|
|
|
@ -91,8 +91,9 @@ void idAutoRender::StartBackgroundAutoSwaps( autoRenderIconType_t iconType )
|
|||
// it is getting purged before our our first frame has been rendered.
|
||||
globalImages->UnbindAll();
|
||||
|
||||
|
||||
StartThread( "BackgroundAutoSwaps", CORE_0B, THREAD_NORMAL, AUTO_RENDER_STACK_SIZE );
|
||||
// DG: set name to "BGAutoSwaps" because Linux has a 16char (incl. \0) namelimit for threads
|
||||
StartThread( "BGAutoSwaps", CORE_0B, THREAD_NORMAL, AUTO_RENDER_STACK_SIZE );
|
||||
// DG end
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -300,4 +301,4 @@ void idAutoRender::RenderLoadingIcon( float fracX, float fracY, float size, floa
|
|||
renderProgManager.BindShader_TextureVertexColor();
|
||||
|
||||
RB_DrawElementsWithCounters( &backEnd.unitSquareSurface );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -313,99 +313,6 @@ void idRenderProgManager::LoadFragmentShader( int index )
|
|||
fragmentShaders[index].progId = ( GLuint ) LoadGLSLShader( GL_FRAGMENT_SHADER, fragmentShaders[index].name, fragmentShaders[index].uniforms );
|
||||
}
|
||||
|
||||
/*
|
||||
================================================================================================
|
||||
idRenderProgManager::LoadShader
|
||||
================================================================================================
|
||||
*/
|
||||
GLuint idRenderProgManager::LoadShader( GLenum target, const char* name, const char* startToken )
|
||||
{
|
||||
|
||||
idStr fullPath = "renderprogs\\gl\\";
|
||||
fullPath += name;
|
||||
|
||||
common->Printf( "%s", fullPath.c_str() );
|
||||
|
||||
char* fileBuffer = NULL;
|
||||
fileSystem->ReadFile( fullPath.c_str(), ( void** )&fileBuffer, NULL );
|
||||
if( fileBuffer == NULL )
|
||||
{
|
||||
common->Printf( ": File not found\n" );
|
||||
return INVALID_PROGID;
|
||||
}
|
||||
if( !R_IsInitialized() )
|
||||
{
|
||||
common->Printf( ": Renderer not initialized\n" );
|
||||
fileSystem->FreeFile( fileBuffer );
|
||||
return INVALID_PROGID;
|
||||
}
|
||||
|
||||
// vertex and fragment shaders are both be present in a single file, so
|
||||
// scan for the proper header to be the start point, and stamp a 0 in after the end
|
||||
char* start = strstr( ( char* )fileBuffer, startToken );
|
||||
if( start == NULL )
|
||||
{
|
||||
common->Printf( ": %s not found\n", startToken );
|
||||
fileSystem->FreeFile( fileBuffer );
|
||||
return INVALID_PROGID;
|
||||
}
|
||||
char* end = strstr( start, "END" );
|
||||
if( end == NULL )
|
||||
{
|
||||
common->Printf( ": END not found for %s\n", startToken );
|
||||
fileSystem->FreeFile( fileBuffer );
|
||||
return INVALID_PROGID;
|
||||
}
|
||||
end[3] = 0;
|
||||
|
||||
idStr program = start;
|
||||
program.Replace( "vertex.normal", "vertex.attrib[11]" );
|
||||
program.Replace( "vertex.texcoord[0]", "vertex.attrib[8]" );
|
||||
program.Replace( "vertex.texcoord", "vertex.attrib[8]" );
|
||||
|
||||
GLuint progId;
|
||||
qglGenProgramsARB( 1, &progId );
|
||||
|
||||
qglBindProgramARB( target, progId );
|
||||
qglGetError();
|
||||
|
||||
qglProgramStringARB( target, GL_PROGRAM_FORMAT_ASCII_ARB, program.Length(), program.c_str() );
|
||||
GLenum err = qglGetError();
|
||||
|
||||
GLint ofs = -1;
|
||||
qglGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &ofs );
|
||||
if( ( err == GL_INVALID_OPERATION ) || ( ofs != -1 ) )
|
||||
{
|
||||
if( err == GL_INVALID_OPERATION )
|
||||
{
|
||||
const GLubyte* str = qglGetString( GL_PROGRAM_ERROR_STRING_ARB );
|
||||
common->Printf( "\nGL_PROGRAM_ERROR_STRING_ARB: %s\n", str );
|
||||
}
|
||||
else
|
||||
{
|
||||
common->Printf( "\nUNKNOWN ERROR\n" );
|
||||
}
|
||||
if( ofs < 0 )
|
||||
{
|
||||
common->Printf( "GL_PROGRAM_ERROR_POSITION_ARB < 0\n" );
|
||||
}
|
||||
else if( ofs >= program.Length() )
|
||||
{
|
||||
common->Printf( "error at end of shader\n" );
|
||||
}
|
||||
else
|
||||
{
|
||||
common->Printf( "error at %i:\n%s", ofs, program.c_str() + ofs );
|
||||
}
|
||||
qglDeleteProgramsARB( 1, &progId );
|
||||
fileSystem->FreeFile( fileBuffer );
|
||||
return INVALID_PROGID;
|
||||
}
|
||||
common->Printf( "\n" );
|
||||
fileSystem->FreeFile( fileBuffer );
|
||||
return progId;
|
||||
}
|
||||
|
||||
/*
|
||||
================================================================================================
|
||||
idRenderProgManager::BindShader
|
||||
|
|
|
@ -409,7 +409,6 @@ protected:
|
|||
BindShader( builtinShaders[i], builtinShaders[i] );
|
||||
}
|
||||
|
||||
GLuint LoadShader( GLenum target, const char* name, const char* startToken );
|
||||
bool CompileGLSL( GLenum target, const char* name );
|
||||
GLuint LoadGLSLShader( GLenum target, const char* name, idList<int>& uniforms );
|
||||
void LoadGLSLProgram( const int programIndex, const int vertexShaderIndex, const int fragmentShaderIndex );
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
Doom 3 BFG Edition GPL Source Code
|
||||
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2013 Robert Beckebans
|
||||
|
||||
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
|
||||
|
||||
|
@ -181,9 +182,11 @@ void RB_DrawElementsWithCounters( const drawSurf_t* surf )
|
|||
// DG: this happens all the time in the erebus1 map with blendlight.vfp,
|
||||
// so don't call assert (through verify) here until it's fixed (if fixable)
|
||||
// else the game crashes on linux when using debug builds
|
||||
|
||||
// FIXME: fix this properly if possible?
|
||||
// RB: yes but it would require an additional blend light skinned shader
|
||||
//if( !verify( renderProgManager.ShaderUsesJoints() ) )
|
||||
if( ! renderProgManager.ShaderUsesJoints() )
|
||||
if( !renderProgManager.ShaderUsesJoints() )
|
||||
// DG end
|
||||
{
|
||||
return;
|
||||
|
@ -2271,7 +2274,10 @@ static int RB_DrawShaderPasses( const drawSurf_t* const* const drawSurfs, const
|
|||
|
||||
GL_State( stageGLState );
|
||||
|
||||
renderProgManager.BindShader( newStage->glslProgram, newStage->glslProgram );
|
||||
// RB: CRITICAL BUGFIX: changed newStage->glslProgram to vertexProgram and fragmentProgram
|
||||
// otherwise it will result in an out of bounds crash in RB_DrawElementsWithCounters
|
||||
renderProgManager.BindShader( newStage->vertexProgram, newStage->fragmentProgram );
|
||||
// RB end
|
||||
|
||||
for( int j = 0; j < newStage->numVertexParms; j++ )
|
||||
{
|
||||
|
|
|
@ -56,6 +56,13 @@ public:
|
|||
alSourcef( openalSource, AL_GAIN, ( gain ) < ( 1.0f ) ? ( gain ) : ( 1.0f ) );
|
||||
}
|
||||
|
||||
void SetPitch( float p )
|
||||
{
|
||||
idSoundVoice_Base::SetPitch( p );
|
||||
|
||||
alSourcef( openalSource, AL_PITCH, p );
|
||||
}
|
||||
|
||||
void Create( const idSoundSample* leadinSample, const idSoundSample* loopingSample );
|
||||
|
||||
// Start playing at a particular point in the buffer. Does an Update() too
|
||||
|
|
|
@ -54,16 +54,18 @@ public:
|
|||
{
|
||||
gain = g;
|
||||
}
|
||||
|
||||
virtual void SetPitch( float p )
|
||||
{
|
||||
pitch = p;
|
||||
}
|
||||
// RB end
|
||||
|
||||
void SetCenterChannel( float c )
|
||||
{
|
||||
centerChannel = c;
|
||||
}
|
||||
void SetPitch( float p )
|
||||
{
|
||||
pitch = p;
|
||||
}
|
||||
|
||||
void SetInnerRadius( float r )
|
||||
{
|
||||
innerRadius = r;
|
||||
|
|
|
@ -26,12 +26,19 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
===========================================================================
|
||||
*/
|
||||
#include <SDL_cpuinfo.h>
|
||||
|
||||
#pragma hdrstop
|
||||
#include "../../idlib/precompiled.h"
|
||||
|
||||
//#include "win_local.h"
|
||||
// DG: SDL_*.h somehow needs the following functions, so #undef those silly
|
||||
// "don't use" #defines from Str.h
|
||||
#undef strcasecmp
|
||||
#undef strncmp
|
||||
#undef vsnprintf
|
||||
// DG end
|
||||
|
||||
#include <SDL_cpuinfo.h>
|
||||
|
||||
|
||||
#pragma warning(disable:4740) // warning C4740: flow in or out of inline asm code suppresses global optimization
|
||||
#pragma warning(disable:4731) // warning C4731: 'XXX' : frame pointer register 'ebx' modified by inline assembly code
|
||||
|
|
|
@ -31,6 +31,13 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
#include "../../idlib/precompiled.h"
|
||||
|
||||
// DG: SDL.h somehow needs the following functions, so #undef those silly
|
||||
// "don't use" #defines from Str.h
|
||||
#undef strncmp
|
||||
#undef strcasecmp
|
||||
#undef vsnprintf
|
||||
// DG end
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include "renderer/tr_local.h"
|
||||
|
@ -72,7 +79,7 @@ const char* kbdNames[] =
|
|||
"english", "french", "german", "italian", "spanish", "turkish", "norwegian", NULL
|
||||
};
|
||||
|
||||
idCVar in_kbd( "in_kbd", "english", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", kbdNames, idCmdSystem::ArgCompletion_String<kbdNames> );
|
||||
idCVar in_keyboard( "in_keyboard", "english", CVAR_SYSTEM | CVAR_ARCHIVE | CVAR_NOCHEAT, "keyboard layout", kbdNames, idCmdSystem::ArgCompletion_String<kbdNames> );
|
||||
|
||||
struct kbd_poll_t
|
||||
{
|
||||
|
@ -552,7 +559,7 @@ void Sys_InitInput()
|
|||
SDL_EnableKeyRepeat( SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL );
|
||||
#endif
|
||||
|
||||
in_kbd.SetModified();
|
||||
in_keyboard.SetModified();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -587,9 +594,9 @@ unsigned char Sys_GetConsoleKey( bool shifted )
|
|||
{
|
||||
static unsigned char keys[2] = { '`', '~' };
|
||||
|
||||
if( in_kbd.IsModified() )
|
||||
if( in_keyboard.IsModified() )
|
||||
{
|
||||
idStr lang = in_kbd.GetString();
|
||||
idStr lang = in_keyboard.GetString();
|
||||
|
||||
if( lang.Length() )
|
||||
{
|
||||
|
@ -625,7 +632,7 @@ unsigned char Sys_GetConsoleKey( bool shifted )
|
|||
}
|
||||
}
|
||||
|
||||
in_kbd.ClearModified();
|
||||
in_keyboard.ClearModified();
|
||||
}
|
||||
|
||||
return shifted ? keys[1] : keys[0];
|
||||
|
|
|
@ -29,11 +29,18 @@ If you have questions concerning this license or the applicable additional terms
|
|||
===========================================================================
|
||||
*/
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
|
||||
// DG: SDL.h somehow needs the following functions, so #undef those silly
|
||||
// "don't use" #defines from Str.h
|
||||
#undef strncmp
|
||||
#undef strcasecmp
|
||||
#undef vsnprintf
|
||||
// DG end
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_syswm.h>
|
||||
|
||||
#include "../../idlib/precompiled.h"
|
||||
|
||||
#include "renderer/tr_local.h"
|
||||
#include "sdl_local.h"
|
||||
|
||||
|
|
Loading…
Reference in a new issue