From 578cf23ba309e80cbd99138e82f1d550f6d1ed3c Mon Sep 17 00:00:00 2001 From: mcmartin Date: Fri, 3 Jan 2003 12:14:19 +0000 Subject: [PATCH] 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 --- sc2/ChangeLog | 1 + sc2/TODO | 4 - sc2/src/msvc++/UrQuanMasters.dsp | 4 + sc2/src/sc2code/libs/graphics/gfx_common.h | 1 + sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c | 15 +-- sc2/src/sc2code/libs/graphics/sdl/dcqueue.c | 3 +- .../sc2code/libs/graphics/sdl/sdl_common.c | 3 +- sc2/src/sc2code/libs/threadlib.h | 8 +- sc2/src/sc2code/libs/threads/Makeinfo | 2 +- sc2/src/sc2code/libs/threads/condbank.c | 110 ++++++++++++++++++ sc2/src/sc2code/libs/threads/sdl/sdlthreads.h | 10 +- sc2/src/sc2code/libs/threads/thrcommon.c | 7 ++ 12 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 sc2/src/sc2code/libs/threads/condbank.c diff --git a/sc2/ChangeLog b/sc2/ChangeLog index 7dfc1a4a5..4cc46ea00 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -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 diff --git a/sc2/TODO b/sc2/TODO index fcecdfffe..8b66cce61 100644 --- a/sc2/TODO +++ b/sc2/TODO @@ -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? diff --git a/sc2/src/msvc++/UrQuanMasters.dsp b/sc2/src/msvc++/UrQuanMasters.dsp index e29fb55df..7f46f36f1 100644 --- a/sc2/src/msvc++/UrQuanMasters.dsp +++ b/sc2/src/msvc++/UrQuanMasters.dsp @@ -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" diff --git a/sc2/src/sc2code/libs/graphics/gfx_common.h b/sc2/src/sc2code/libs/graphics/gfx_common.h index 577d0cacb..a99d3b5b1 100644 --- a/sc2/src/sc2code/libs/graphics/gfx_common.h +++ b/sc2/src/sc2code/libs/graphics/gfx_common.h @@ -109,6 +109,7 @@ typedef struct tfb_drawcommand BOOLEAN UsePalette; int BlendNumerator; int BlendDenominator; + DWORD thread; } TFB_DrawCommand; // Queue Stuff diff --git a/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c b/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c index b8f20a4d1..1eb604889 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c +++ b/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c @@ -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 diff --git a/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c b/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c index 15eb633e2..84273bbda 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c +++ b/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c @@ -223,7 +223,8 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand) { return; } - + + DrawCommand->thread = CurrentThreadID (); if (DrawCommand->Type <= TFB_DRAWCOMMANDTYPE_COPYFROMOTHERBUFFER && TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE) { diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c index 6b040339e..21d7063da 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c @@ -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 (); diff --git a/sc2/src/sc2code/libs/threadlib.h b/sc2/src/sc2code/libs/threadlib.h index 688916d8f..78c699a5c 100644 --- a/sc2/src/sc2code/libs/threadlib.h +++ b/sc2/src/sc2code/libs/threadlib.h @@ -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 */ diff --git a/sc2/src/sc2code/libs/threads/Makeinfo b/sc2/src/sc2code/libs/threads/Makeinfo index eea248b06..1d7782d0c 100644 --- a/sc2/src/sc2code/libs/threads/Makeinfo +++ b/sc2/src/sc2code/libs/threads/Makeinfo @@ -1,2 +1,2 @@ uqm_SUBDIRS="sdl" -uqm_CFILES="thrcommon.c" +uqm_CFILES="condbank.c thrcommon.c" diff --git a/sc2/src/sc2code/libs/threads/condbank.c b/sc2/src/sc2code/libs/threads/condbank.c new file mode 100644 index 000000000..a3bbb1523 --- /dev/null +++ b/sc2/src/sc2code/libs/threads/condbank.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 +#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); +} + diff --git a/sc2/src/sc2code/libs/threads/sdl/sdlthreads.h b/sc2/src/sc2code/libs/threads/sdl/sdlthreads.h index 513850aef..68501b6e6 100644 --- a/sc2/src/sc2code/libs/threads/sdl/sdlthreads.h +++ b/sc2/src/sc2code/libs/threads/sdl/sdlthreads.h @@ -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 */ diff --git a/sc2/src/sc2code/libs/threads/thrcommon.c b/sc2/src/sc2code/libs/threads/thrcommon.c index 7cbd8f327..5d96d39ad 100644 --- a/sc2/src/sc2code/libs/threads/thrcommon.c +++ b/sc2/src/sc2code/libs/threads/thrcommon.c @@ -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 (); +}