diff --git a/sc2/BUGS b/sc2/BUGS index 4b314df4e..d9a02de92 100644 --- a/sc2/BUGS +++ b/sc2/BUGS @@ -101,3 +101,7 @@ The bugs reported but not yet verified: - In starmap, when any zone of influence is moving, the starmap cursor behaves badly (erases what it passes over). Leaving and returning to the starmap fixes it + +- Under FreeBSD, waiting on condition variables doesn't seem to + actually wait or hand control to the renderer, thus spinlocking and + crashing. diff --git a/sc2/ChangeLog b/sc2/ChangeLog index 3d66606a6..b7a6a8c74 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,4 +1,6 @@ 0.2: +- Recoded the DCQ to not sit on the heap, added debugging info +- Fixed Outfit Starship and Shipyard graphics, from TDuck - 3D planet is now zoomed randomly from any corner, from PhracturedBlue - Flagship thrusters and modules one-pixel place fix, from TDuck - Earth topo map is now tinted as should, from PhracturedBlue diff --git a/sc2/TODO b/sc2/TODO index 4f041542f..a75b02da0 100644 --- a/sc2/TODO +++ b/sc2/TODO @@ -101,9 +101,11 @@ Implementation bugs (low priority): and removing occasional pops/discontinuities - Rotation and zooming isn't now as smooth as before after condition variable DCQ patch -- DrawCommandQueue is gratuitously dynamically allocated, should be static + - 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? Stuff still to do (large): - add a Key Jamming program diff --git a/sc2/src/sc2code/libs/graphics/gfx_common.h b/sc2/src/sc2code/libs/graphics/gfx_common.h index f6941b1a4..20784e78d 100644 --- a/sc2/src/sc2code/libs/graphics/gfx_common.h +++ b/sc2/src/sc2code/libs/graphics/gfx_common.h @@ -124,7 +124,7 @@ typedef struct tfb_drawcommandqueue volatile int Size; } TFB_DrawCommandQueue; -TFB_DrawCommandQueue *TFB_DrawCommandQueue_Create (void); +void TFB_DrawCommandQueue_Create (void); void TFB_BatchGraphics (void); @@ -132,15 +132,13 @@ void TFB_UnbatchGraphics (void); void TFB_BatchReset (void); -void TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue, - TFB_DrawCommand* Command); +void TFB_DrawCommandQueue_Push (TFB_DrawCommand* Command); -int TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue* myQueue, - TFB_DrawCommand* Command); +int TFB_DrawCommandQueue_Pop (TFB_DrawCommand* Command); -void TFB_DrawCommandQueue_Clear (TFB_DrawCommandQueue* myQueue); +void TFB_DrawCommandQueue_Clear (void); -extern TFB_DrawCommandQueue *DrawCommandQueue; +extern TFB_DrawCommandQueue DrawCommandQueue; // The TFB_Enqueue* functions are necessary, because only the // main thread can draw to the window. diff --git a/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c b/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c index 9904474ff..00fdbaf31 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c +++ b/sc2/src/sc2code/libs/graphics/sdl/3do_funcs.c @@ -35,11 +35,11 @@ InitGraphics (int argc, char* argv[], COUNT KbytesRequired) { BOOLEAN ret; + TFB_DrawCommandQueue_Create (); + LoadDisplay (&_pCurDisplay); ActivateDisplay (); - DrawCommandQueue = TFB_DrawCommandQueue_Create (); - ret = TRUE; return (ret); } diff --git a/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c b/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c index 544f7e438..4bc9b0e59 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c +++ b/sc2/src/sc2code/libs/graphics/sdl/dcqueue.c @@ -35,7 +35,7 @@ static Uint32 DCQ_locking_thread = 0; #define DCQ_MAX 16384 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 @@ -78,20 +78,20 @@ Unlock_DCQ (void) static void Synchronize_DCQ (void) { - if (!DrawCommandQueue->Batching) + if (!DrawCommandQueue.Batching) { - int front = DrawCommandQueue->Front; - int back = DrawCommandQueue->InsertionPoint; - DrawCommandQueue->Back = DrawCommandQueue->InsertionPoint; + int front = DrawCommandQueue.Front; + int back = DrawCommandQueue.InsertionPoint; + DrawCommandQueue.Back = DrawCommandQueue.InsertionPoint; if (front <= back) { - DrawCommandQueue->Size = (back - front); + DrawCommandQueue.Size = (back - front); } else { - DrawCommandQueue->Size = (back + DCQ_MAX - front); + DrawCommandQueue.Size = (back + DCQ_MAX - front); } - DrawCommandQueue->FullSize = DrawCommandQueue->Size; + DrawCommandQueue.FullSize = DrawCommandQueue.Size; } } @@ -99,7 +99,7 @@ void TFB_BatchGraphics (void) { Lock_DCQ (); - DrawCommandQueue->Batching++; + DrawCommandQueue.Batching++; Unlock_DCQ (); } @@ -107,9 +107,9 @@ void TFB_UnbatchGraphics (void) { Lock_DCQ (); - if (DrawCommandQueue->Batching) + if (DrawCommandQueue.Batching) { - DrawCommandQueue->Batching--; + DrawCommandQueue.Batching--; } Synchronize_DCQ (); Unlock_DCQ (); @@ -122,43 +122,36 @@ void TFB_BatchReset (void) { Lock_DCQ (); - DrawCommandQueue->Batching = 0; + 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* +void TFB_DrawCommandQueue_Create() { - TFB_DrawCommandQueue* myQueue; - - myQueue = (TFB_DrawCommandQueue*) HMalloc( - sizeof(TFB_DrawCommandQueue)); - - myQueue->Back = 0; - myQueue->Front = 0; - myQueue->InsertionPoint = 0; - myQueue->Batching = 0; - myQueue->FullSize = 0; - myQueue->Size = 0; + DrawCommandQueue.Back = 0; + DrawCommandQueue.Front = 0; + DrawCommandQueue.InsertionPoint = 0; + DrawCommandQueue.Batching = 0; + DrawCommandQueue.FullSize = 0; + DrawCommandQueue.Size = 0; + DCQ_locking_depth = 0; + DCQ_locking_thread = 0; DCQ_sem = CreateSemaphore(1); - - return (myQueue); } void -TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue, - TFB_DrawCommand* Command) +TFB_DrawCommandQueue_Push (TFB_DrawCommand* Command) { Lock_DCQ (); - while (myQueue->FullSize >= DCQ_MAX - 1) + while (DrawCommandQueue.FullSize >= DCQ_MAX - 1) { int old_depth, i; - fprintf (stderr, "DCQ overload (Size = %d). Sleeping until renderer is done.\n", myQueue->Size); + fprintf (stderr, "DCQ overload (Size = %d). Sleeping until renderer is done.\n", DrawCommandQueue.Size); // Restore the DCQ locking level. I *think* this is // always 1, but... old_depth = DCQ_locking_depth; @@ -167,54 +160,54 @@ TFB_DrawCommandQueue_Push (TFB_DrawCommandQueue* myQueue, WaitCondVar (RenderingCond); for (i = 0; i < old_depth; i++) Lock_DCQ (); - fprintf (stderr, "DCQ clear (Size = %d). Continuing.\n", myQueue->Size); + fprintf (stderr, "DCQ clear (Size = %d). Continuing.\n", DrawCommandQueue.Size); } - DCQ[myQueue->InsertionPoint] = *Command; - myQueue->InsertionPoint = (myQueue->InsertionPoint + 1) % DCQ_MAX; - myQueue->FullSize++; + DCQ[DrawCommandQueue.InsertionPoint] = *Command; + DrawCommandQueue.InsertionPoint = (DrawCommandQueue.InsertionPoint + 1) % DCQ_MAX; + DrawCommandQueue.FullSize++; Synchronize_DCQ (); Unlock_DCQ (); } int -TFB_DrawCommandQueue_Pop (TFB_DrawCommandQueue *myQueue, TFB_DrawCommand *target) +TFB_DrawCommandQueue_Pop (TFB_DrawCommand *target) { Lock_DCQ (); - if (myQueue->Size == 0) + if (DrawCommandQueue.Size == 0) { Unlock_DCQ (); return (0); } - if (myQueue->Front == myQueue->Back && myQueue->Size != DCQ_MAX) + if (DrawCommandQueue.Front == DrawCommandQueue.Back && DrawCommandQueue.Size != DCQ_MAX) { fprintf (stderr, "Augh! Assertion failure in DCQ! Front == Back, Size != DCQ_MAX\n"); - myQueue->Size = 0; + DrawCommandQueue.Size = 0; Unlock_DCQ (); return (0); } - *target = DCQ[myQueue->Front]; - myQueue->Front = (myQueue->Front + 1) % DCQ_MAX; + *target = DCQ[DrawCommandQueue.Front]; + DrawCommandQueue.Front = (DrawCommandQueue.Front + 1) % DCQ_MAX; - myQueue->Size--; - myQueue->FullSize--; + DrawCommandQueue.Size--; + DrawCommandQueue.FullSize--; Unlock_DCQ (); return 1; } void -TFB_DrawCommandQueue_Clear (TFB_DrawCommandQueue *myQueue) +TFB_DrawCommandQueue_Clear () { Lock_DCQ (); - myQueue->Size = 0; - myQueue->Front = 0; - myQueue->Back = 0; - myQueue->Batching = 0; - myQueue->FullSize = 0; - myQueue->InsertionPoint = 0; + DrawCommandQueue.Size = 0; + DrawCommandQueue.Front = 0; + DrawCommandQueue.Back = 0; + DrawCommandQueue.Batching = 0; + DrawCommandQueue.FullSize = 0; + DrawCommandQueue.InsertionPoint = 0; Unlock_DCQ (); } @@ -262,7 +255,7 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand) } } - TFB_DrawCommandQueue_Push (DrawCommandQueue, DrawCommand); + TFB_DrawCommandQueue_Push (DrawCommand); } #endif diff --git a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c index df21b5d0c..b9059a7cb 100644 --- a/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/sc2code/libs/graphics/sdl/sdl_common.c @@ -523,9 +523,9 @@ TFB_FlushGraphics () // Only call from main thread!! BOOLEAN livelock_deterrence; BOOLEAN done; - // This is technically a locking violation on DrawCommandQueue->Size, + // 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.Size == 0) { static int last_fade = 255; static int last_transition = 255; @@ -571,12 +571,12 @@ TFB_FlushGraphics () // Only call from main thread!! commands_handled = 0; livelock_deterrence = FALSE; - if (DrawCommandQueue->FullSize > DCQ_FORCE_BREAK_SIZE) + if (DrawCommandQueue.FullSize > DCQ_FORCE_BREAK_SIZE) { TFB_BatchReset (); } - if (DrawCommandQueue->Size > DCQ_FORCE_SLOWDOWN_SIZE) + if (DrawCommandQueue.Size > DCQ_FORCE_SLOWDOWN_SIZE) { Lock_DCQ (); livelock_deterrence = TRUE; @@ -588,14 +588,14 @@ TFB_FlushGraphics () // Only call from main thread!! TFB_DrawCommand DC; TFB_Image *DC_image; - if (!TFB_DrawCommandQueue_Pop (DrawCommandQueue, &DC)) + if (!TFB_DrawCommandQueue_Pop (&DC)) { // the Queue is now empty. break; } ++commands_handled; - if (!livelock_deterrence && commands_handled + DrawCommandQueue->Size > DCQ_LIVELOCK_MAX) + if (!livelock_deterrence && commands_handled + DrawCommandQueue.Size > DCQ_LIVELOCK_MAX) { // fprintf (stderr, "Initiating livelock deterrence!\n"); livelock_deterrence = TRUE; @@ -768,7 +768,7 @@ TFB_FlushGraphics () // Only call from main thread!! TFB_SwapBuffers (); break; case TFB_DRAWCOMMANDTYPE_SKIPGRAPHICS: - TFB_DrawCommandQueue_Clear (DrawCommandQueue); + TFB_DrawCommandQueue_Clear (); } if (DC_image) UnlockMutex (DC_image->mutex);