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:
@@ -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) */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user