Graphics synchronization patch

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@47 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
mcmartin
2002-09-18 02:16:50 +00:00
parent 73822d4551
commit 113533834c
7 changed files with 299 additions and 140 deletions
+2
View File
@@ -711,6 +711,7 @@ LastOscillTime = LastTime;
SleepThreadUntil (LastTime + 1); SleepThreadUntil (LastTime + 1);
SetSemaphore (GraphicsSem); SetSemaphore (GraphicsSem);
BatchGraphics ();
CurTime = GetTimeCounter (); CurTime = GetTimeCounter ();
ElapsedTicks = CurTime - LastTime; ElapsedTicks = CurTime - LastTime;
LastTime = CurTime; LastTime = CurTime;
@@ -1031,6 +1032,7 @@ if (LastOscillTime + (ONE_SECOND / 32) < CurTime)
LastOscillTime = CurTime; LastOscillTime = CurTime;
UpdateSpeechGraphics (FALSE); UpdateSpeechGraphics (FALSE);
} }
UnbatchGraphics ();
ClearSemaphore (GraphicsSem); ClearSemaphore (GraphicsSem);
} }
(void) blah; /* Satisfying compiler (unused parameter) */ (void) blah; /* Satisfying compiler (unused parameter) */
+9 -2
View File
@@ -114,19 +114,26 @@ typedef struct tfb_drawcommandqueue
{ {
int Front; int Front;
int Back; int Back;
int InsertionPoint;
int Batching;
volatile int FullSize;
volatile int Size; volatile int Size;
} TFB_DrawCommandQueue; } TFB_DrawCommandQueue;
TFB_DrawCommandQueue *TFB_DrawCommandQueue_Create (); TFB_DrawCommandQueue *TFB_DrawCommandQueue_Create ();
void TFB_BatchGraphics ();
void TFB_UnbatchGraphics ();
void TFB_BatchReset ();
void TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue, void TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue,
TFB_DrawCommand* Command); TFB_DrawCommand* Command);
int TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue* myQueue, int TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue* myQueue,
TFB_DrawCommand* Command); TFB_DrawCommand* Command);
void TFB_DeallocateDrawCommand (TFB_DrawCommand* Command);
extern TFB_DrawCommandQueue *DrawCommandQueue; extern TFB_DrawCommandQueue *DrawCommandQueue;
// The TFB_Enqueue* functions are necessary, because only the // The TFB_Enqueue* functions are necessary, because only the
+52 -58
View File
@@ -43,27 +43,26 @@ blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr)
if (TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE) if (TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE)
{ {
TFB_DrawCommand DC_on_stack; TFB_DrawCommand DrawCommand;
TFB_DrawCommand *DrawCommand = &DC_on_stack;
// DrawCommand = HMalloc (sizeof (TFB_DrawCommand)); // DrawCommand = HMalloc (sizeof (TFB_DrawCommand));
DrawCommand->Type = TFB_DRAWCOMMANDTYPE_IMAGE; DrawCommand.Type = TFB_DRAWCOMMANDTYPE_IMAGE;
DrawCommand->x = pClipRect->corner.x - DrawCommand.x = pClipRect->corner.x -
GetFrameHotX (_CurFramePtr); GetFrameHotX (_CurFramePtr);
DrawCommand->y = pClipRect->corner.y - DrawCommand.y = pClipRect->corner.y -
GetFrameHotY (_CurFramePtr); GetFrameHotY (_CurFramePtr);
DrawCommand->w = img->NormalImg->clip_rect.w; DrawCommand.w = img->NormalImg->clip_rect.w;
DrawCommand->h = img->NormalImg->clip_rect.h; DrawCommand.h = img->NormalImg->clip_rect.h;
if (gscale != 0 && gscale != 256) if (gscale != 0 && gscale != 256)
{ {
DrawCommand->x += (GetFrameHotX (SrcFramePtr) * DrawCommand.x += (GetFrameHotX (SrcFramePtr) *
((1 << 8) - gscale)) >> 8; ((1 << 8) - gscale)) >> 8;
DrawCommand->y += (GetFrameHotY (SrcFramePtr) * DrawCommand.y += (GetFrameHotY (SrcFramePtr) *
((1 << 8) - gscale)) >> 8; ((1 << 8) - gscale)) >> 8;
DrawCommand->w = (DrawCommand->w * gscale) >> 8; DrawCommand.w = (DrawCommand.w * gscale) >> 8;
DrawCommand->h = (DrawCommand->h * gscale) >> 8; DrawCommand.h = (DrawCommand.h * gscale) >> 8;
if (img->ScaledImg) if (img->ScaledImg)
{ {
@@ -120,8 +119,8 @@ blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr)
} }
} }
DrawCommand->image = (TFB_ImageStruct*) img; DrawCommand.image = (TFB_ImageStruct*) img;
DrawCommand->UsePalette = FALSE; DrawCommand.UsePalette = FALSE;
if (GetPrimType (PrimPtr) == STAMPFILL_PRIM) if (GetPrimType (PrimPtr) == STAMPFILL_PRIM)
{ {
@@ -129,18 +128,18 @@ blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr)
DWORD c32k; DWORD c32k;
c32k = GetPrimColor (PrimPtr) >> 8; // shift out color index c32k = GetPrimColor (PrimPtr) >> 8; // shift out color index
DrawCommand->r = (c32k >> (10 - (8 - 5))) & 0xF8; DrawCommand.r = (c32k >> (10 - (8 - 5))) & 0xF8;
DrawCommand->g = (c32k >> (5 - (8 - 5))) & 0xF8; DrawCommand.g = (c32k >> (5 - (8 - 5))) & 0xF8;
DrawCommand->b = (c32k << (8 - 5)) & 0xF8; DrawCommand.b = (c32k << (8 - 5)) & 0xF8;
for (i = 0; i < 256; ++i) for (i = 0; i < 256; ++i)
{ {
DrawCommand->Palette[i].r = DrawCommand->r; DrawCommand.Palette[i].r = DrawCommand.r;
DrawCommand->Palette[i].g = DrawCommand->g; DrawCommand.Palette[i].g = DrawCommand.g;
DrawCommand->Palette[i].b = DrawCommand->b; DrawCommand.Palette[i].b = DrawCommand.b;
} }
DrawCommand->UsePalette = TRUE; DrawCommand.UsePalette = TRUE;
} }
else else
{ {
@@ -155,15 +154,15 @@ blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr)
(type == TFB_COLORMAP_PLANET && (img->Palette[255].r != 248 || (type == TFB_COLORMAP_PLANET && (img->Palette[255].r != 248 ||
img->Palette[255].g != 248 || img->Palette[255].b != 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 else
{ {
@@ -211,35 +210,31 @@ fillrect_blt (PRECT pClipRect, PRIMITIVEPTR PrimPtr)
if (TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE) if (TYPE_GET (_CurFramePtr->TypeIndexAndFlags) == SCREEN_DRAWABLE)
{ {
TFB_DrawCommand DC_on_stack; TFB_DrawCommand DrawCommand;
TFB_DrawCommand *DrawCommand = &DC_on_stack;
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.w = (DrawCommand.w * gscale) >> 8;
DrawCommand->x = pClipRect->corner.x - GetFrameHotX (_CurFramePtr); DrawCommand.h = (DrawCommand.h * gscale) >> 8;
DrawCommand->y = pClipRect->corner.y - GetFrameHotY (_CurFramePtr); DrawCommand.x += (pClipRect->extent.width -
DrawCommand->w = pClipRect->extent.width; DrawCommand.w) >> 1;
DrawCommand->h = pClipRect->extent.height; DrawCommand.y += (pClipRect->extent.height -
DrawCommand->r = r; DrawCommand.h) >> 1;
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.image = 0;
DrawCommand.UsePalette = FALSE;
TFB_EnqueueDrawCommand(&DrawCommand);
} }
else else
{ {
@@ -322,18 +317,17 @@ read_screen (PRECT lpRect, FRAMEPTR DstFramePtr)
} }
else else
{ {
TFB_DrawCommand DC_auto; TFB_DrawCommand DC;
TFB_DrawCommand* DC = &DC_auto;
DC->Type = TFB_DRAWCOMMANDTYPE_COPYBACKBUFFERTOOTHERBUFFER; DC.Type = TFB_DRAWCOMMANDTYPE_COPYBACKBUFFERTOOTHERBUFFER;
DC->x = lpRect->corner.x; DC.x = lpRect->corner.x;
DC->y = lpRect->corner.y; DC.y = lpRect->corner.y;
DC->w = lpRect->extent.width; DC.w = lpRect->extent.width;
DC->h = lpRect->extent.height; DC.h = lpRect->extent.height;
DC->image = (TFB_ImageStruct *) ((BYTE *) DstFramePtr + DC.image = (TFB_ImageStruct *) ((BYTE *) DstFramePtr +
DstFramePtr->DataOffs); DstFramePtr->DataOffs);
TFB_EnqueueDrawCommand (DC); TFB_EnqueueDrawCommand (&DC);
} }
} }
+12 -1
View File
@@ -20,6 +20,8 @@
#include "sdl_common.h" #include "sdl_common.h"
int batch_depth = 0;
//Status: Not entirely unimplemented! //Status: Not entirely unimplemented!
BOOLEAN BOOLEAN
@@ -45,23 +47,32 @@ UninitGraphics () // Also probably empty
{ {
HFree (DrawCommandQueue); HFree (DrawCommandQueue);
HFree (ExtraScreen);
mem_uninit (); 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 void
BatchGraphics (void) BatchGraphics (void)
{ {
TFB_BatchGraphics ();
} }
void void
UnbatchGraphics (void) UnbatchGraphics (void)
{ {
TFB_UnbatchGraphics ();
} }
void void
FlushGraphics (void) FlushGraphics (void)
{ {
TFB_BatchReset ();
continuity_break = 1; continuity_break = 1;
} }
+125 -30
View File
@@ -19,16 +19,114 @@
#ifdef GFXMODULE_SDL #ifdef GFXMODULE_SDL
#include "sdl_common.h" #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_DrawCommand DCQ[DCQ_MAX];
TFB_DrawCommandQueue *DrawCommandQueue; 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 // Draw Command Queue Stuff
// TODO: Make this be statically allocated, too. We only ever have one DCQ, after all.
TFB_DrawCommandQueue* TFB_DrawCommandQueue*
TFB_DrawCommandQueue_Create() TFB_DrawCommandQueue_Create()
@@ -40,9 +138,11 @@ TFB_DrawCommandQueue_Create()
myQueue->Back = 0; myQueue->Back = 0;
myQueue->Front = 0; myQueue->Front = 0;
myQueue->InsertionPoint = 0;
myQueue->Batching = 0;
myQueue->Size = 0; myQueue->Size = 0;
DCQ_mutex = SDL_CreateMutex(); DCQ_sem = CreateSemaphore(1);
return (myQueue); return (myQueue);
} }
@@ -51,29 +151,30 @@ void
TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue, TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue,
TFB_DrawCommand* Command) TFB_DrawCommand* Command)
{ {
SDL_mutexP(DCQ_mutex); Lock_DCQ ();
if (myQueue->Size < DCQ_MAX) if (myQueue->Size < DCQ_MAX - 1)
{ {
DCQ[myQueue->Back] = *Command; DCQ[myQueue->InsertionPoint] = *Command;
myQueue->Back = (myQueue->Back + 1) % DCQ_MAX; myQueue->InsertionPoint = (myQueue->InsertionPoint + 1) % DCQ_MAX;
myQueue->Size++; myQueue->FullSize++;
Synchronize_DCQ ();
} }
else else
{ {
TFB_DeallocateDrawCommand(Command); printf("DCQ overload. Adjust your livelock deterrence constants!\n");
} }
SDL_mutexV(DCQ_mutex); Unlock_DCQ ();
} }
int int
TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue *myQueue, TFB_DrawCommand *target) TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue *myQueue, TFB_DrawCommand *target)
{ {
SDL_mutexP(DCQ_mutex); Lock_DCQ ();
if (myQueue->Size == 0) if (myQueue->Size == 0)
{ {
SDL_mutexV(DCQ_mutex); Unlock_DCQ ();
return (0); 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"); printf("Augh! Assertion failure in DCQ! Front == Back, Size != DCQ_MAX\n");
myQueue->Size = 0; myQueue->Size = 0;
SDL_mutexV(DCQ_mutex); Unlock_DCQ ();
return (0); return (0);
} }
@@ -89,17 +190,12 @@ TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue *myQueue, TFB_DrawCommand *target
myQueue->Front = (myQueue->Front + 1) % DCQ_MAX; myQueue->Front = (myQueue->Front + 1) % DCQ_MAX;
myQueue->Size--; myQueue->Size--;
SDL_mutexV(DCQ_mutex); myQueue->FullSize--;
Unlock_DCQ ();
return 1; return 1;
} }
void
TFB_DeallocateDrawCommand (TFB_DrawCommand* Command)
{
//HFree(Command);
}
void void
TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand) TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand)
{ {
@@ -122,23 +218,22 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand)
_pCurContext->ClipRect.extent.height) _pCurContext->ClipRect.extent.height)
{ {
// Enqueue command to set the glScissor spec // Enqueue command to set the glScissor spec
TFB_DrawCommand DC_auto; TFB_DrawCommand DC;
TFB_DrawCommand* DC = &DC_auto;
scissor_rect = _pCurContext->ClipRect; scissor_rect = _pCurContext->ClipRect;
DC->Type = scissor_rect.extent.width DC.Type = scissor_rect.extent.width
? (DC->x = scissor_rect.corner.x, ? (DC.x = scissor_rect.corner.x,
DC->y=scissor_rect.corner.y, DC.y=scissor_rect.corner.y,
DC->w=scissor_rect.extent.width, DC.w=scissor_rect.extent.width,
DC->h=scissor_rect.extent.height), DC.h=scissor_rect.extent.height),
TFB_DRAWCOMMANDTYPE_SCISSORENABLE TFB_DRAWCOMMANDTYPE_SCISSORENABLE
: TFB_DRAWCOMMANDTYPE_SCISSORDISABLE; : TFB_DRAWCOMMANDTYPE_SCISSORDISABLE;
DC->image = 0; DC.image = 0;
DC->UsePalette = FALSE; DC.UsePalette = FALSE;
TFB_EnqueueDrawCommand(DC); TFB_EnqueueDrawCommand(&DC);
} }
} }
+87 -45
View File
@@ -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 void
TFB_FlushGraphics () // Only call from main thread!! TFB_FlushGraphics () // Only call from main thread!!
{ {
int semval; 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) if (DrawCommandQueue == 0 || DrawCommandQueue->Size == 0)
{ {
SDL_Delay(5); 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.. // TODO: a more optimal way of getting the lock on GraphicsSem..
// cannot currently use SDL_SemWait because it would break // cannot currently use SDL_SemWait because it would break
// the usage of continuity_break // the usage of continuity_break
// Michael asks: Why are we locking, then releasing, the GraphicsSem?
semval = TimeoutSetSemaphore (GraphicsSem, ONE_SECOND / 10); semval = TimeoutSetSemaphore (GraphicsSem, ONE_SECOND / 10);
if (semval != 0 && !continuity_break) if (semval != 0)
return; return;
continuity_break = 0; else
if (semval == 0)
SDL_SemPost (GraphicsSem); SDL_SemPost (GraphicsSem);
} }
else continuity_break = 0;
{
continuity_break = 0;
}
if (ShowFPS) if (ShowFPS)
TFB_ComputeFPS (); 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_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"); // the Queue is now empty.
continue; 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) if (DC_image)
SDL_mutexP (DC_image->mutex); SDL_mutexP (DC_image->mutex);
switch (DC->Type) switch (DC.Type)
{ {
case TFB_DRAWCOMMANDTYPE_IMAGE: case TFB_DRAWCOMMANDTYPE_IMAGE:
{ {
@@ -349,10 +388,10 @@ TFB_FlushGraphics () // Only call from main thread!!
break; break;
} }
targetRect.x = DC->x; targetRect.x = DC.x;
targetRect.y = DC->y; 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) DC_image->ScaledImg)
surf = DC_image->ScaledImg; surf = DC_image->ScaledImg;
else else
@@ -360,9 +399,9 @@ TFB_FlushGraphics () // Only call from main thread!!
if (surf->format->BytesPerPixel == 1) 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 else
{ {
@@ -382,12 +421,12 @@ TFB_FlushGraphics () // Only call from main thread!!
PutPixelFn screen_plot; PutPixelFn screen_plot;
screen_plot = putpixel_for (SDL_Screen); 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; x1 = DC.x;
x2 = DC->w; x2 = DC.w;
y1 = DC->y; y1 = DC.y;
y2 = DC->h; y2 = DC.h;
SDL_GetClipRect(SDL_Screen, &r); SDL_GetClipRect(SDL_Screen, &r);
@@ -420,21 +459,21 @@ TFB_FlushGraphics () // Only call from main thread!!
case TFB_DRAWCOMMANDTYPE_RECTANGLE: case TFB_DRAWCOMMANDTYPE_RECTANGLE:
{ {
SDL_Rect r; SDL_Rect r;
r.x = DC->x; r.x = DC.x;
r.y = DC->y; r.y = DC.y;
r.w = DC->w; r.w = DC.w;
r.h = DC->h; 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; break;
} }
case TFB_DRAWCOMMANDTYPE_SCISSORENABLE: case TFB_DRAWCOMMANDTYPE_SCISSORENABLE:
{ {
SDL_Rect r; SDL_Rect r;
r.x = DC->x; r.x = DC.x;
r.y = DC->y; r.y = DC.y;
r.w = DC->w; r.w = DC.w;
r.h = DC->h; r.h = DC.h;
SDL_SetClipRect(SDL_Screen, &r); SDL_SetClipRect(SDL_Screen, &r);
break; break;
@@ -445,10 +484,10 @@ TFB_FlushGraphics () // Only call from main thread!!
case TFB_DRAWCOMMANDTYPE_COPYBACKBUFFERTOOTHERBUFFER: case TFB_DRAWCOMMANDTYPE_COPYBACKBUFFERTOOTHERBUFFER:
{ {
SDL_Rect src, dest; SDL_Rect src, dest;
src.x = dest.x = DC->x; src.x = dest.x = DC.x;
src.y = dest.y = DC->y; src.y = dest.y = DC.y;
src.w = DC->w; src.w = DC.w;
src.h = DC->h; src.h = DC.h;
if (DC_image == 0) if (DC_image == 0)
{ {
@@ -465,10 +504,10 @@ TFB_FlushGraphics () // Only call from main thread!!
case TFB_DRAWCOMMANDTYPE_COPYFROMOTHERBUFFER: case TFB_DRAWCOMMANDTYPE_COPYFROMOTHERBUFFER:
{ {
SDL_Rect src, dest; SDL_Rect src, dest;
src.x = dest.x = DC->x; src.x = dest.x = DC.x;
src.y = dest.y = DC->y; src.y = dest.y = DC.y;
src.w = DC->w; src.w = DC.w;
src.h = DC->h; src.h = DC.h;
SDL_BlitSurface(ExtraScreen, &src, SDL_Screen, &dest); SDL_BlitSurface(ExtraScreen, &src, SDL_Screen, &dest);
break; break;
} }
@@ -493,8 +532,11 @@ TFB_FlushGraphics () // Only call from main thread!!
if (DC_image) if (DC_image)
SDL_mutexV (DC_image->mutex); SDL_mutexV (DC_image->mutex);
}
TFB_DeallocateDrawCommand (DC); if (livelock_deterrence)
{
Unlock_DCQ ();
} }
TFB_SwapBuffers(); TFB_SwapBuffers();
+10 -2
View File
@@ -218,9 +218,15 @@ CreateThreadAux (ThreadFunction func, void *data, SDWORD stackSize
* from being removed from the queue and from displaying the * from being removed from the queue and from displaying the
* 'killed' debug message. * '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 void
KillThread (Thread thread) KillThread (Thread thread)
{ {
TFB_BatchReset ();
NativeKillThread (thread->native); NativeKillThread (thread->native);
#ifdef DEBUG_THREADS #ifdef DEBUG_THREADS
fprintf (stderr, "Thread '%s' killed.\n", ThreadName (thread)); fprintf (stderr, "Thread '%s' killed.\n", ThreadName (thread));
@@ -240,7 +246,7 @@ WaitThread (Thread thread, int *status)
void void
SleepThread (TimePeriod timePeriod) SleepThread (TimePeriod timePeriod)
{ {
return NativeSleepThread (timePeriod); NativeSleepThread (timePeriod);
} }
void void
@@ -300,7 +306,9 @@ DestroySemaphore (Semaphore sem)
int int
SetSemaphore (Semaphore sem) SetSemaphore (Semaphore sem)
{ {
return NativeSetSemaphore ((NativeSemaphore) sem); int result;
result = NativeSetSemaphore ((NativeSemaphore) sem);
return result;
} }
int int