diff --git a/sc2/src/sc2code/comm.c b/sc2/src/sc2code/comm.c index e6e48263b..d98a9722e 100644 --- a/sc2/src/sc2code/comm.c +++ b/sc2/src/sc2code/comm.c @@ -711,6 +711,7 @@ LastOscillTime = LastTime; SleepThreadUntil (LastTime + 1); SetSemaphore (GraphicsSem); + BatchGraphics (); CurTime = GetTimeCounter (); ElapsedTicks = CurTime - LastTime; LastTime = CurTime; @@ -1031,6 +1032,7 @@ if (LastOscillTime + (ONE_SECOND / 32) < CurTime) LastOscillTime = CurTime; UpdateSpeechGraphics (FALSE); } + UnbatchGraphics (); ClearSemaphore (GraphicsSem); } (void) blah; /* Satisfying compiler (unused parameter) */ diff --git a/sc2/src/sc2code/libs/graphics/gfx_common.h b/sc2/src/sc2code/libs/graphics/gfx_common.h index 3690b806b..20366ea47 100644 --- a/sc2/src/sc2code/libs/graphics/gfx_common.h +++ b/sc2/src/sc2code/libs/graphics/gfx_common.h @@ -114,19 +114,26 @@ typedef struct tfb_drawcommandqueue { int Front; int Back; + int InsertionPoint; + int Batching; + volatile int FullSize; volatile int Size; } TFB_DrawCommandQueue; TFB_DrawCommandQueue *TFB_DrawCommandQueue_Create (); +void TFB_BatchGraphics (); + +void TFB_UnbatchGraphics (); + +void TFB_BatchReset (); + void TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue, TFB_DrawCommand* Command); int TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue* myQueue, TFB_DrawCommand* Command); -void TFB_DeallocateDrawCommand (TFB_DrawCommand* Command); - extern TFB_DrawCommandQueue *DrawCommandQueue; // The TFB_Enqueue* functions are necessary, because only the diff --git a/sc2/src/sc2code/libs/graphics/sdl/3do_blt.c b/sc2/src/sc2code/libs/graphics/sdl/3do_blt.c index 422d250c3..062e8b1af 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/3do_blt.c +++ b/sc2/src/sc2code/libs/graphics/sdl/3do_blt.c @@ -43,27 +43,26 @@ blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr) if (TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE) { - TFB_DrawCommand DC_on_stack; - TFB_DrawCommand *DrawCommand = &DC_on_stack; + TFB_DrawCommand DrawCommand; // DrawCommand = HMalloc (sizeof (TFB_DrawCommand)); - DrawCommand->Type = TFB_DRAWCOMMANDTYPE_IMAGE; - DrawCommand->x = pClipRect->corner.x - + DrawCommand.Type = TFB_DRAWCOMMANDTYPE_IMAGE; + DrawCommand.x = pClipRect->corner.x - GetFrameHotX (_CurFramePtr); - DrawCommand->y = pClipRect->corner.y - + DrawCommand.y = pClipRect->corner.y - GetFrameHotY (_CurFramePtr); - DrawCommand->w = img->NormalImg->clip_rect.w; - DrawCommand->h = img->NormalImg->clip_rect.h; + DrawCommand.w = img->NormalImg->clip_rect.w; + DrawCommand.h = img->NormalImg->clip_rect.h; if (gscale != 0 && gscale != 256) { - DrawCommand->x += (GetFrameHotX (SrcFramePtr) * + DrawCommand.x += (GetFrameHotX (SrcFramePtr) * ((1 << 8) - gscale)) >> 8; - DrawCommand->y += (GetFrameHotY (SrcFramePtr) * + DrawCommand.y += (GetFrameHotY (SrcFramePtr) * ((1 << 8) - gscale)) >> 8; - DrawCommand->w = (DrawCommand->w * gscale) >> 8; - DrawCommand->h = (DrawCommand->h * gscale) >> 8; + DrawCommand.w = (DrawCommand.w * gscale) >> 8; + DrawCommand.h = (DrawCommand.h * gscale) >> 8; if (img->ScaledImg) { @@ -120,8 +119,8 @@ blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr) } } - DrawCommand->image = (TFB_ImageStruct*) img; - DrawCommand->UsePalette = FALSE; + DrawCommand.image = (TFB_ImageStruct*) img; + DrawCommand.UsePalette = FALSE; if (GetPrimType (PrimPtr) == STAMPFILL_PRIM) { @@ -129,18 +128,18 @@ blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr) DWORD c32k; c32k = GetPrimColor (PrimPtr) >> 8; // shift out color index - DrawCommand->r = (c32k >> (10 - (8 - 5))) & 0xF8; - DrawCommand->g = (c32k >> (5 - (8 - 5))) & 0xF8; - DrawCommand->b = (c32k << (8 - 5)) & 0xF8; + DrawCommand.r = (c32k >> (10 - (8 - 5))) & 0xF8; + DrawCommand.g = (c32k >> (5 - (8 - 5))) & 0xF8; + DrawCommand.b = (c32k << (8 - 5)) & 0xF8; for (i = 0; i < 256; ++i) { - DrawCommand->Palette[i].r = DrawCommand->r; - DrawCommand->Palette[i].g = DrawCommand->g; - DrawCommand->Palette[i].b = DrawCommand->b; + DrawCommand.Palette[i].r = DrawCommand.r; + DrawCommand.Palette[i].g = DrawCommand.g; + DrawCommand.Palette[i].b = DrawCommand.b; } - DrawCommand->UsePalette = TRUE; + DrawCommand.UsePalette = TRUE; } else { @@ -155,15 +154,15 @@ blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr) (type == TFB_COLORMAP_PLANET && (img->Palette[255].r != 248 || img->Palette[255].g != 248 || img->Palette[255].b != 248))) { - if (TFB_CopyRGBColorMap(DrawCommand->Palette)) + if (TFB_CopyRGBColorMap(DrawCommand.Palette)) { - DrawCommand->UsePalette = TRUE; + DrawCommand.UsePalette = TRUE; } } } } - TFB_EnqueueDrawCommand(DrawCommand); + TFB_EnqueueDrawCommand(&DrawCommand); } else { @@ -211,35 +210,31 @@ fillrect_blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr) if (TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE) { - TFB_DrawCommand DC_on_stack; - TFB_DrawCommand *DrawCommand = &DC_on_stack; + TFB_DrawCommand DrawCommand; - if (DrawCommand) + DrawCommand.Type = TFB_DRAWCOMMANDTYPE_RECTANGLE; + DrawCommand.x = pClipRect->corner.x - GetFrameHotX (_CurFramePtr); + DrawCommand.y = pClipRect->corner.y - GetFrameHotY (_CurFramePtr); + DrawCommand.w = pClipRect->extent.width; + DrawCommand.h = pClipRect->extent.height; + DrawCommand.r = r; + DrawCommand.g = g; + DrawCommand.b = b; + + if (gscale && GetPrimType (PrimPtr) != POINT_PRIM) { - DrawCommand->Type = TFB_DRAWCOMMANDTYPE_RECTANGLE; - DrawCommand->x = pClipRect->corner.x - GetFrameHotX (_CurFramePtr); - DrawCommand->y = pClipRect->corner.y - GetFrameHotY (_CurFramePtr); - DrawCommand->w = pClipRect->extent.width; - DrawCommand->h = pClipRect->extent.height; - DrawCommand->r = r; - DrawCommand->g = g; - DrawCommand->b = b; - - if (gscale && GetPrimType (PrimPtr) != POINT_PRIM) - { - DrawCommand->w = (DrawCommand->w * gscale) >> 8; - DrawCommand->h = (DrawCommand->h * gscale) >> 8; - DrawCommand->x += (pClipRect->extent.width - - DrawCommand->w) >> 1; - DrawCommand->y += (pClipRect->extent.height - - DrawCommand->h) >> 1; - } - - DrawCommand->image = 0; - DrawCommand->UsePalette = FALSE; - - TFB_EnqueueDrawCommand(DrawCommand); + DrawCommand.w = (DrawCommand.w * gscale) >> 8; + DrawCommand.h = (DrawCommand.h * gscale) >> 8; + DrawCommand.x += (pClipRect->extent.width - + DrawCommand.w) >> 1; + DrawCommand.y += (pClipRect->extent.height - + DrawCommand.h) >> 1; } + + DrawCommand.image = 0; + DrawCommand.UsePalette = FALSE; + + TFB_EnqueueDrawCommand(&DrawCommand); } else { @@ -322,18 +317,17 @@ read_screen (PRECT lpRect, FRAMEPTR DstFramePtr) } else { - TFB_DrawCommand DC_auto; - TFB_DrawCommand* DC = &DC_auto; + TFB_DrawCommand DC; - DC->Type = TFB_DRAWCOMMANDTYPE_COPYBACKBUFFERTOOTHERBUFFER; - DC->x = lpRect->corner.x; - DC->y = lpRect->corner.y; - DC->w = lpRect->extent.width; - DC->h = lpRect->extent.height; - DC->image = (TFB_ImageStruct *) ((BYTE *) DstFramePtr + + DC.Type = TFB_DRAWCOMMANDTYPE_COPYBACKBUFFERTOOTHERBUFFER; + DC.x = lpRect->corner.x; + DC.y = lpRect->corner.y; + DC.w = lpRect->extent.width; + DC.h = lpRect->extent.height; + DC.image = (TFB_ImageStruct *) ((BYTE *) DstFramePtr + DstFramePtr->DataOffs); - TFB_EnqueueDrawCommand (DC); + TFB_EnqueueDrawCommand (&DC); } } diff --git a/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c b/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c index 8d5053a67..4afb2f70c 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c +++ b/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c @@ -20,6 +20,8 @@ #include "sdl_common.h" +int batch_depth = 0; + //Status: Not entirely unimplemented! BOOLEAN @@ -45,23 +47,32 @@ UninitGraphics () // Also probably empty { HFree (DrawCommandQueue); - HFree (ExtraScreen); mem_uninit (); } + +// 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 void BatchGraphics (void) { + TFB_BatchGraphics (); } void UnbatchGraphics (void) { + TFB_UnbatchGraphics (); } void FlushGraphics (void) { + TFB_BatchReset (); continuity_break = 1; } diff --git a/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c b/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c index 82915b6f6..649eb55ed 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c +++ b/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c @@ -19,16 +19,114 @@ #ifdef GFXMODULE_SDL #include "sdl_common.h" +#include "libs/threadlib.h" -SDL_mutex *DCQ_mutex; +Semaphore DCQ_sem; -#define DCQ_MAX 4096 +// variables for making the DCQ lock re-entrant +static int DCQ_locking_depth = 0; +static Uint32 DCQ_locking_thread = 0; + +// Maximum size of the DCQ. The larger the DCQ, the larger frameskips +// become tolerable before initiating livelock deterrence and game +// slowdown. Other constants for controlling the frameskip/slowdown +// balance may be found in sdl_common.c near TFB_FlushGraphics. +#define DCQ_MAX 16384 TFB_DrawCommand DCQ[DCQ_MAX]; TFB_DrawCommandQueue *DrawCommandQueue; +// DCQ Synchronization: SDL-specific implementation of re-entrant +// locks to protect the Draw Command Queue. Lock is re-entrant to +// allow livelock deterrence to be written much more cleanly. + +void +Lock_DCQ (void) +{ + Uint32 current_thread = SDL_ThreadID (); + if (DCQ_locking_thread != current_thread) + { + SetSemaphore (DCQ_sem); + DCQ_locking_thread = current_thread; + } + ++DCQ_locking_depth; + // printf("DCQ_sem locking depth: %i\n", DCQ_locking_depth); +} + +void +Unlock_DCQ (void) +{ + Uint32 current_thread = SDL_ThreadID (); + if (DCQ_locking_thread != current_thread) + { + printf("%8x attempted to unlock the DCQ when it didn't hold it!\n", current_thread); + } + else + { + --DCQ_locking_depth; + // printf("DCQ_sem locking depth: %i\n", DCQ_locking_depth); + if (!DCQ_locking_depth) + { + DCQ_locking_thread = 0; + ClearSemaphore (DCQ_sem); + } + } +} + +// Always have the DCQ locked when calling this. +static void +Synchronize_DCQ (void) +{ + if (!DrawCommandQueue->Batching) + { + int front = DrawCommandQueue->Front; + int back = DrawCommandQueue->InsertionPoint; + DrawCommandQueue->Back = DrawCommandQueue->InsertionPoint; + if (front <= back) + { + DrawCommandQueue->Size = (back - front); + } + else + { + DrawCommandQueue->Size = (back + DCQ_MAX - front); + } + } +} + +void +TFB_BatchGraphics (void) +{ + Lock_DCQ (); + DrawCommandQueue->Batching++; + Unlock_DCQ (); +} + +void +TFB_UnbatchGraphics (void) +{ + Lock_DCQ (); + if (DrawCommandQueue->Batching) + { + DrawCommandQueue->Batching--; + } + Synchronize_DCQ (); + Unlock_DCQ (); +} + +// Cancel all pending batch operations, making them unbatched. This will +// cause a small amount of flicker when invoked, but prevents +// batching problems from freezing the game. +void +TFB_BatchReset (void) +{ + Lock_DCQ (); + DrawCommandQueue->Batching = 0; + Synchronize_DCQ (); + Unlock_DCQ (); +} // Draw Command Queue Stuff +// TODO: Make this be statically allocated, too. We only ever have one DCQ, after all. TFB_DrawCommandQueue* TFB_DrawCommandQueue_Create() @@ -40,9 +138,11 @@ TFB_DrawCommandQueue_Create() myQueue->Back = 0; myQueue->Front = 0; + myQueue->InsertionPoint = 0; + myQueue->Batching = 0; myQueue->Size = 0; - DCQ_mutex = SDL_CreateMutex(); + DCQ_sem = CreateSemaphore(1); return (myQueue); } @@ -51,29 +151,30 @@ void TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue, TFB_DrawCommand* Command) { - SDL_mutexP(DCQ_mutex); - if (myQueue->Size < DCQ_MAX) + Lock_DCQ (); + if (myQueue->Size < DCQ_MAX - 1) { - DCQ[myQueue->Back] = *Command; - myQueue->Back = (myQueue->Back + 1) % DCQ_MAX; - myQueue->Size++; + DCQ[myQueue->InsertionPoint] = *Command; + myQueue->InsertionPoint = (myQueue->InsertionPoint + 1) % DCQ_MAX; + myQueue->FullSize++; + Synchronize_DCQ (); } else { - TFB_DeallocateDrawCommand(Command); + printf("DCQ overload. Adjust your livelock deterrence constants!\n"); } - SDL_mutexV(DCQ_mutex); + Unlock_DCQ (); } int TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue *myQueue, TFB_DrawCommand *target) { - SDL_mutexP(DCQ_mutex); + Lock_DCQ (); if (myQueue->Size == 0) { - SDL_mutexV(DCQ_mutex); + Unlock_DCQ (); return (0); } @@ -81,7 +182,7 @@ TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue *myQueue, TFB_DrawCommand *target { printf("Augh! Assertion failure in DCQ! Front == Back, Size != DCQ_MAX\n"); myQueue->Size = 0; - SDL_mutexV(DCQ_mutex); + Unlock_DCQ (); return (0); } @@ -89,17 +190,12 @@ TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue *myQueue, TFB_DrawCommand *target myQueue->Front = (myQueue->Front + 1) % DCQ_MAX; myQueue->Size--; - SDL_mutexV(DCQ_mutex); + myQueue->FullSize--; + Unlock_DCQ (); return 1; } -void -TFB_DeallocateDrawCommand (TFB_DrawCommand* Command) -{ - //HFree(Command); -} - void TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand) { @@ -122,23 +218,22 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand) _pCurContext->ClipRect.extent.height) { // Enqueue command to set the glScissor spec - TFB_DrawCommand DC_auto; - TFB_DrawCommand* DC = &DC_auto; + TFB_DrawCommand DC; scissor_rect = _pCurContext->ClipRect; - DC->Type = scissor_rect.extent.width - ? (DC->x = scissor_rect.corner.x, - DC->y=scissor_rect.corner.y, - DC->w=scissor_rect.extent.width, - DC->h=scissor_rect.extent.height), + DC.Type = scissor_rect.extent.width + ? (DC.x = scissor_rect.corner.x, + DC.y=scissor_rect.corner.y, + DC.w=scissor_rect.extent.width, + DC.h=scissor_rect.extent.height), TFB_DRAWCOMMANDTYPE_SCISSORENABLE : TFB_DRAWCOMMANDTYPE_SCISSORDISABLE; - DC->image = 0; - DC->UsePalette = FALSE; + DC.image = 0; + DC.UsePalette = FALSE; - TFB_EnqueueDrawCommand(DC); + TFB_EnqueueDrawCommand(&DC); } } diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c index 3454300c0..afea0ec30 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c @@ -287,11 +287,33 @@ TFB_ComputeFPS () } } +// Livelock deterrance constants. Because the entire screen is rarely +// refreshed, we may not drop draw commands on the floor with abandon. +// Furthermore, if the main program is queuing commands at a speed +// comparable to our processing of the commands, we never finish and +// the game freezes. Thus, if the queue starts out larger than +// DCQ_FORCE_SLOWDOWN_SIZE, or DCQ_LIVELOCK_MAX commands find +// themselves being processed in one go, livelock deterrence is +// enabled, and TFB_FlushGraphics locks the DCQ until it has processed +// all entries. If batched but pending commands exceed DCQ_FORCE_BREAK_SIZE, +// a continuity break is performed. This will effectively slow down the +// game logic, a fate we seek to avoid - however, it seems to be unavoidable +// on slower machines. Even there, it's seems nonexistent outside of +// communications screens. --Michael + +#define DCQ_FORCE_SLOWDOWN_SIZE 1024 +#define DCQ_FORCE_BREAK_SIZE 4096 +#define DCQ_LIVELOCK_MAX 2048 + void TFB_FlushGraphics () // Only call from main thread!! { int semval; + int commands_handled; + BOOLEAN livelock_deterrence; + // This is technically a locking violation on DrawCommandQueue->Size, + // but it is likely to not be very destructive. if (DrawCommandQueue == 0 || DrawCommandQueue->Size == 0) { SDL_Delay(5); @@ -302,41 +324,58 @@ TFB_FlushGraphics () // Only call from main thread!! // TODO: a more optimal way of getting the lock on GraphicsSem.. // cannot currently use SDL_SemWait because it would break // the usage of continuity_break + // Michael asks: Why are we locking, then releasing, the GraphicsSem? semval = TimeoutSetSemaphore (GraphicsSem, ONE_SECOND / 10); - if (semval != 0 && !continuity_break) + if (semval != 0) return; - continuity_break = 0; - - if (semval == 0) + else SDL_SemPost (GraphicsSem); } - else - { - continuity_break = 0; - } + continuity_break = 0; if (ShowFPS) TFB_ComputeFPS (); - while (DrawCommandQueue->Size > 0) + commands_handled = 0; + livelock_deterrence = FALSE; + + if (DrawCommandQueue->FullSize > DCQ_FORCE_BREAK_SIZE) { - TFB_DrawCommand DC_real; + TFB_BatchReset (); + } + + if (DrawCommandQueue->Size > DCQ_FORCE_SLOWDOWN_SIZE) + { + Lock_DCQ (); + livelock_deterrence = TRUE; + } + + while (TRUE) + { + TFB_DrawCommand DC; TFB_Image *DC_image; - TFB_DrawCommand* DC = &DC_real; - - if (!TFB_DrawCommandQueue_Pop (DrawCommandQueue, DC)) + if (!TFB_DrawCommandQueue_Pop (DrawCommandQueue, &DC)) { - printf ("Woah there coyboy! Trouble with TFB_Queues...\n"); - continue; + // the Queue is now empty. + break; } - DC_image = (TFB_Image*) DC->image; + ++commands_handled; + if (!livelock_deterrence && commands_handled + DrawCommandQueue->Size > DCQ_LIVELOCK_MAX) + { + // printf("Initiating livelock deterrence!\n"); + livelock_deterrence = TRUE; + + Lock_DCQ (); + } + + DC_image = (TFB_Image*) DC.image; if (DC_image) SDL_mutexP (DC_image->mutex); - switch (DC->Type) + switch (DC.Type) { case TFB_DRAWCOMMANDTYPE_IMAGE: { @@ -349,10 +388,10 @@ TFB_FlushGraphics () // Only call from main thread!! break; } - targetRect.x = DC->x; - targetRect.y = DC->y; + targetRect.x = DC.x; + targetRect.y = DC.y; - if ((DC->w != DC_image->NormalImg->w || DC->h != DC_image->NormalImg->h) && + if ((DC.w != DC_image->NormalImg->w || DC.h != DC_image->NormalImg->h) && DC_image->ScaledImg) surf = DC_image->ScaledImg; else @@ -360,9 +399,9 @@ TFB_FlushGraphics () // Only call from main thread!! if (surf->format->BytesPerPixel == 1) { - if (DC->UsePalette) + if (DC.UsePalette) { - SDL_SetColors (surf, (SDL_Color*)DC->Palette, 0, 256); + SDL_SetColors (surf, (SDL_Color*)DC.Palette, 0, 256); } else { @@ -382,12 +421,12 @@ TFB_FlushGraphics () // Only call from main thread!! PutPixelFn screen_plot; screen_plot = putpixel_for (SDL_Screen); - color = SDL_MapRGB (SDL_Screen->format, DC->r, DC->g, DC->b); + color = SDL_MapRGB (SDL_Screen->format, DC.r, DC.g, DC.b); - x1 = DC->x; - x2 = DC->w; - y1 = DC->y; - y2 = DC->h; + x1 = DC.x; + x2 = DC.w; + y1 = DC.y; + y2 = DC.h; SDL_GetClipRect(SDL_Screen, &r); @@ -420,21 +459,21 @@ TFB_FlushGraphics () // Only call from main thread!! case TFB_DRAWCOMMANDTYPE_RECTANGLE: { SDL_Rect r; - r.x = DC->x; - r.y = DC->y; - r.w = DC->w; - r.h = DC->h; + r.x = DC.x; + r.y = DC.y; + r.w = DC.w; + r.h = DC.h; - SDL_FillRect(SDL_Screen, &r, SDL_MapRGB(SDL_Screen->format, DC->r, DC->g, DC->b)); + SDL_FillRect(SDL_Screen, &r, SDL_MapRGB(SDL_Screen->format, DC.r, DC.g, DC.b)); break; } case TFB_DRAWCOMMANDTYPE_SCISSORENABLE: { SDL_Rect r; - r.x = DC->x; - r.y = DC->y; - r.w = DC->w; - r.h = DC->h; + r.x = DC.x; + r.y = DC.y; + r.w = DC.w; + r.h = DC.h; SDL_SetClipRect(SDL_Screen, &r); break; @@ -445,10 +484,10 @@ TFB_FlushGraphics () // Only call from main thread!! case TFB_DRAWCOMMANDTYPE_COPYBACKBUFFERTOOTHERBUFFER: { SDL_Rect src, dest; - src.x = dest.x = DC->x; - src.y = dest.y = DC->y; - src.w = DC->w; - src.h = DC->h; + src.x = dest.x = DC.x; + src.y = dest.y = DC.y; + src.w = DC.w; + src.h = DC.h; if (DC_image == 0) { @@ -465,10 +504,10 @@ TFB_FlushGraphics () // Only call from main thread!! case TFB_DRAWCOMMANDTYPE_COPYFROMOTHERBUFFER: { SDL_Rect src, dest; - src.x = dest.x = DC->x; - src.y = dest.y = DC->y; - src.w = DC->w; - src.h = DC->h; + src.x = dest.x = DC.x; + src.y = dest.y = DC.y; + src.w = DC.w; + src.h = DC.h; SDL_BlitSurface(ExtraScreen, &src, SDL_Screen, &dest); break; } @@ -493,10 +532,13 @@ TFB_FlushGraphics () // Only call from main thread!! if (DC_image) SDL_mutexV (DC_image->mutex); - - TFB_DeallocateDrawCommand (DC); } + if (livelock_deterrence) + { + Unlock_DCQ (); + } + TFB_SwapBuffers(); } diff --git a/sc2/src/sc2code/libs/threads/thrcommon.c b/sc2/src/sc2code/libs/threads/thrcommon.c index 406d98794..55ae9e152 100644 --- a/sc2/src/sc2code/libs/threads/thrcommon.c +++ b/sc2/src/sc2code/libs/threads/thrcommon.c @@ -218,9 +218,15 @@ CreateThreadAux (ThreadFunction func, void *data, SDWORD stackSize * from being removed from the queue and from displaying the * 'killed' debug message. */ + +/* 17 Sep: Added a TFB_BatchReset call. If a thread is killed while + * batching stuff, we don't want this to freeze the game. + * Better safe than sorry! --Michael + */ void KillThread (Thread thread) -{ +{ + TFB_BatchReset (); NativeKillThread (thread->native); #ifdef DEBUG_THREADS fprintf (stderr, "Thread '%s' killed.\n", ThreadName (thread)); @@ -240,7 +246,7 @@ WaitThread (Thread thread, int *status) void SleepThread (TimePeriod timePeriod) { - return NativeSleepThread (timePeriod); + NativeSleepThread (timePeriod); } void @@ -300,7 +306,9 @@ DestroySemaphore (Semaphore sem) int SetSemaphore (Semaphore sem) { - return NativeSetSemaphore ((NativeSemaphore) sem); + int result; + result = NativeSetSemaphore ((NativeSemaphore) sem); + return result; } int