FlushGraphics now tracks and wakes each thread individually, lessening
the stuttering when multiple threads are performing Flush operations. Also, a number of comments have been reworked for accuracy. git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@527 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
Changes towards version 0.2:
|
||||
- FlushGraphics now waits and notifies on a per-thread level
|
||||
- No longer using SHGetFolderPath on Windows - SvdB
|
||||
- Key repeat is now enabled when typing text, from slayne
|
||||
- Capital letter bug in new input code fixed, from slayne
|
||||
|
||||
@@ -78,10 +78,6 @@ Implementation bugs (low priority):
|
||||
- 3D planet view when entering orbit is now done, but there's some things
|
||||
which could make it look nicer, like better slave shield and removing
|
||||
occasional pops/discontinuities
|
||||
- Rotation and zooming isn't now as smooth as before after condition
|
||||
variable DCQ patch
|
||||
- This is because of the fact that all FlushGraphics routines wait on
|
||||
one lone condition variable -- we need one per thread, effectively.
|
||||
- Transitions (crossfades) aren't perhaps correctly done always, syncing
|
||||
might be wrong etc.
|
||||
- Condition variable DCQ patch should have fixed this. Confirm?
|
||||
|
||||
@@ -651,6 +651,10 @@ SOURCE=..\sc2code\libs\threads\thrcommon.c
|
||||
|
||||
SOURCE=..\sc2code\libs\threads\thrcommon.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=..\sc2code\libs\threads\condbank.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "time"
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ typedef struct tfb_drawcommand
|
||||
BOOLEAN UsePalette;
|
||||
int BlendNumerator;
|
||||
int BlendDenominator;
|
||||
DWORD thread;
|
||||
} TFB_DrawCommand;
|
||||
|
||||
// Queue Stuff
|
||||
|
||||
@@ -54,12 +54,10 @@ UninitGraphics () // Also probably empty
|
||||
}
|
||||
|
||||
|
||||
// Batch/UnbatchGraphics: These routines appear to be used to ensure
|
||||
// that the screen doesn't update with a half-drawn region. This can
|
||||
// be implemented in all sorts of ways - I've chosen to fold it into
|
||||
// our DrawCommandQueue, for the most part. These just forward to
|
||||
// the TFB_ versions in dcqueue.c. They may also make continuity_break
|
||||
// redundant, but I haven't tested that yet. --Michael
|
||||
/* Batching and Unbatching functions. A "Batch" is a collection of
|
||||
DrawCommands that will never be flipped to the screen half-rendered.
|
||||
BatchGraphics and UnbatchGraphics function vaguely like a non-blocking
|
||||
recursive lock to do this respect. */
|
||||
void
|
||||
BatchGraphics (void)
|
||||
{
|
||||
@@ -72,6 +70,9 @@ UnbatchGraphics (void)
|
||||
TFB_UnbatchGraphics ();
|
||||
}
|
||||
|
||||
/* Sleeps this thread until all Draw Commands queued by that thread have
|
||||
been processed. */
|
||||
|
||||
void
|
||||
FlushGraphics (void)
|
||||
{
|
||||
@@ -80,7 +81,7 @@ FlushGraphics (void)
|
||||
DrawCommand.Type = TFB_DRAWCOMMANDTYPE_FLUSHGRAPHICS;
|
||||
DrawCommand.image = 0;
|
||||
TFB_EnqueueDrawCommand(&DrawCommand);
|
||||
WaitCondVar (RenderingCond);
|
||||
WaitForSignal ();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -224,6 +224,7 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand)
|
||||
return;
|
||||
}
|
||||
|
||||
DrawCommand->thread = CurrentThreadID ();
|
||||
if (DrawCommand->Type <= TFB_DRAWCOMMANDTYPE_COPYFROMOTHERBUFFER
|
||||
&& TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE)
|
||||
{
|
||||
|
||||
@@ -737,7 +737,8 @@ TFB_FlushGraphics () // Only call from main thread!!
|
||||
break;
|
||||
case TFB_DRAWCOMMANDTYPE_FLUSHGRAPHICS:
|
||||
// done = TRUE;
|
||||
TFB_SwapBuffers ();
|
||||
// TFB_SwapBuffers ();
|
||||
SignalThread (DC.thread);
|
||||
break;
|
||||
case TFB_DRAWCOMMANDTYPE_SKIPGRAPHICS:
|
||||
TFB_DrawCommandQueue_Clear ();
|
||||
|
||||
@@ -65,7 +65,8 @@
|
||||
|
||||
extern void InitThreadSystem (void);
|
||||
extern void UnInitThreadSystem (void);
|
||||
|
||||
extern void init_cond_bank (void);
|
||||
extern void uninit_cond_bank (void);
|
||||
|
||||
typedef int (*ThreadFunction) (void *);
|
||||
|
||||
@@ -130,5 +131,10 @@ extern void WaitCondVar (CondVar);
|
||||
extern void SignalCondVar (CondVar);
|
||||
extern void BroadcastCondVar (CondVar);
|
||||
|
||||
extern DWORD CurrentThreadID (void);
|
||||
|
||||
extern void WaitForSignal (void);
|
||||
extern void SignalThread (DWORD);
|
||||
|
||||
#endif /* _THREADLIB_H */
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
uqm_SUBDIRS="sdl"
|
||||
uqm_CFILES="thrcommon.c"
|
||||
uqm_CFILES="condbank.c thrcommon.c"
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
//Copyright Paul Reiche, Fred Ford. 1992-2002
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
/* This defines the Condition Variable Bank. Individual threads may
|
||||
sleep until they are signaled by their Thread ID. If the Condition
|
||||
Variable Bank is exhausted (unlikely!) it will wait on the DCQ's
|
||||
condition variable. This may produce stuttering. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "starcon.h"
|
||||
#include "libs/threadlib.h"
|
||||
|
||||
/* The Condition Variable Bank. */
|
||||
|
||||
#define CONDVAR_BANK_SIZE 10
|
||||
|
||||
static Semaphore bank_sem;
|
||||
|
||||
static struct {
|
||||
CondVar var;
|
||||
DWORD id;
|
||||
int used;
|
||||
} bank[CONDVAR_BANK_SIZE];
|
||||
|
||||
void
|
||||
init_cond_bank ()
|
||||
{
|
||||
int i;
|
||||
bank_sem = CreateSemaphore (1, "CondVar Bank Semaphore");
|
||||
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
|
||||
{
|
||||
bank[i].var = CreateCondVar ();
|
||||
bank[i].id = bank[i].used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
uninit_cond_bank ()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
|
||||
{
|
||||
DestroyCondVar (bank[i].var);
|
||||
}
|
||||
DestroySemaphore (bank_sem);
|
||||
}
|
||||
|
||||
void
|
||||
WaitForSignal ()
|
||||
{
|
||||
int i;
|
||||
int index = -1;
|
||||
DWORD me = CurrentThreadID ();
|
||||
SetSemaphore (bank_sem);
|
||||
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
|
||||
{
|
||||
if (!bank[i].used)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index == -1)
|
||||
{
|
||||
/* The bank is full! */
|
||||
fprintf(stderr, "Condvar bank is full, %ul is waiting on DCQ.", me);
|
||||
ClearSemaphore (bank_sem);
|
||||
WaitCondVar (RenderingCond);
|
||||
}
|
||||
else
|
||||
{
|
||||
bank[i].used = 1;
|
||||
bank[i].id = me;
|
||||
ClearSemaphore (bank_sem);
|
||||
WaitCondVar (bank[i].var);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SignalThread (DWORD id)
|
||||
{
|
||||
int i;
|
||||
SetSemaphore (bank_sem);
|
||||
for (i = 0; i < CONDVAR_BANK_SIZE; i++)
|
||||
{
|
||||
if (bank[i].used && bank[i].id == id)
|
||||
{
|
||||
bank[i].id = bank[i].used = 0;
|
||||
SignalCondVar (bank[i].var);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ClearSemaphore (bank_sem);
|
||||
}
|
||||
|
||||
@@ -86,14 +86,16 @@ typedef SDL_cond *NativeCondVar;
|
||||
#define NativeCreateCondVar() \
|
||||
SDL_CreateCond ()
|
||||
#define NativeDestroyCondVar(condvar) \
|
||||
SDL_DestroyCond((condvar))
|
||||
SDL_DestroyCond ((condvar))
|
||||
#define NativeWaitCondVar(condvar) \
|
||||
SDLWrapper_WaitCondVar((condvar))
|
||||
SDLWrapper_WaitCondVar ((condvar))
|
||||
#define NativeSignalCondVar(condvar) \
|
||||
SDL_CondSignal((condvar))
|
||||
SDL_CondSignal ((condvar))
|
||||
#define NativeBroadcastCondVar(condvar) \
|
||||
SDL_CondBroadcast((condvar))
|
||||
SDL_CondBroadcast ((condvar))
|
||||
|
||||
#define NativeCurrentThreadID() \
|
||||
SDL_ThreadID ()
|
||||
|
||||
#endif /* _SDLTHREAD_H */
|
||||
|
||||
|
||||
@@ -89,11 +89,13 @@ InitThreadSystem (void)
|
||||
signal(SIGUSR1, SigUSR1Handler);
|
||||
#endif
|
||||
NativeInitThreadSystem ();
|
||||
init_cond_bank ();
|
||||
}
|
||||
|
||||
void
|
||||
UnInitThreadSystem (void)
|
||||
{
|
||||
uninit_cond_bank ();
|
||||
NativeUnInitThreadSystem ();
|
||||
#ifdef PROFILE_THREADS
|
||||
signal(SIGUSR1, SIG_DFL);
|
||||
@@ -602,3 +604,8 @@ void BroadcastCondVar (CondVar cv)
|
||||
{
|
||||
NativeBroadcastCondVar (cv);
|
||||
}
|
||||
|
||||
DWORD CurrentThreadID ()
|
||||
{
|
||||
return (DWORD)NativeThreadID ();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user