From ce1dd1aea7cc44e700dbb1ca639685db6c1975f9 Mon Sep 17 00:00:00 2001 From: avolkov Date: Wed, 23 Dec 2009 15:26:53 +0000 Subject: [PATCH] Moved DCQ rendering code out of SDL domain along with a few other functions; screen transitions timing fix git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3465 8092fc87-c524-0410-9efc-e669fe64eaf9 --- sc2/src/libs/graphics/dcqueue.c | 341 ++++++++++++++++++++++++- sc2/src/libs/graphics/drawcmd.h | 4 +- sc2/src/libs/graphics/gfx_common.c | 120 +++++++++ sc2/src/libs/graphics/gfx_common.h | 17 +- sc2/src/libs/graphics/sdl/3do_funcs.c | 127 --------- sc2/src/libs/graphics/sdl/canvas.c | 52 ++++ sc2/src/libs/graphics/sdl/sdl_common.c | 337 +----------------------- sc2/src/libs/graphics/sdl/sdl_common.h | 4 - sc2/src/libs/graphics/tfb_draw.c | 14 +- sc2/src/libs/graphics/tfb_draw.h | 7 +- 10 files changed, 547 insertions(+), 476 deletions(-) diff --git a/sc2/src/libs/graphics/dcqueue.c b/sc2/src/libs/graphics/dcqueue.c index d70a65543..517e78c4f 100644 --- a/sc2/src/libs/graphics/dcqueue.c +++ b/sc2/src/libs/graphics/dcqueue.c @@ -20,6 +20,9 @@ #include "libs/graphics/drawable.h" #include "libs/graphics/context.h" #include "libs/graphics/dcqueue.h" +#include "libs/graphics/gfx_common.h" +#include "libs/graphics/bbox.h" +#include "libs/timelib.h" #include "libs/log.h" #include "libs/misc.h" // for TFB_DEBUG_HALT @@ -33,6 +36,10 @@ TFB_DrawCommand DCQ[DCQ_MAX]; TFB_DrawCommandQueue DrawCommandQueue; +#define FPS_PERIOD (ONE_SECOND / 100) +int RenderedFrames = 0; + + // Wait for the queue to be emptied. static void TFB_WaitForSpace (int requested_slots) @@ -137,12 +144,19 @@ Init_DrawCommandQueue (void) DrawCommandQueue.FullSize = 0; DrawCommandQueue.Size = 0; - DCQ_Mutex = CreateRecursiveMutex ("DCQ", SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); + TFB_BBox_Init (ScreenWidth, ScreenHeight); + + DCQ_Mutex = CreateRecursiveMutex ("DCQ", + SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); + + RenderingCond = CreateCondVar ("DCQ empty", + SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); } void Uninit_DrawCommandQueue (void) { + DestroyCondVar (RenderingCond); DestroyRecursiveMutex (DCQ_Mutex); } @@ -245,3 +259,328 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand) TFB_DrawCommandQueue_Push (DrawCommand); } +static void +computeFPS (void) +{ + static TimeCount last_time; + static TimePeriod fps_counter; + TimeCount current_time; + TimePeriod delta_time; + + current_time = GetTimeCounter (); + delta_time = current_time - last_time; + last_time = current_time; + + fps_counter += delta_time; + if (fps_counter > FPS_PERIOD) + { + log_add (log_User, "fps %.2f, effective %.2f", + (float)ONE_SECOND / delta_time, + (float)ONE_SECOND * RenderedFrames / fps_counter); + + fps_counter = 0; + RenderedFrames = 0; + } +} + +// Only call from main() thread!! +void +TFB_FlushGraphics (void) +{ + 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.Size == 0) + { + static int last_fade = 255; + static int last_transition = 255; + int current_fade = GetFadeAmount (); + int current_transition = TransitionAmount; + + if ((current_fade != 255 && current_fade != last_fade) || + (current_transition != 255 && + current_transition != last_transition) || + (current_fade == 255 && last_fade != 255) || + (current_transition == 255 && last_transition != 255)) + { + TFB_SwapBuffers (TFB_REDRAW_FADING); + // if fading, redraw every frame + } + else + { + TaskSwitch (); + } + + last_fade = current_fade; + last_transition = current_transition; + BroadcastCondVar (RenderingCond); + return; + } + + if (GfxFlags & TFB_GFXFLAGS_SHOWFPS) + computeFPS (); + + commands_handled = 0; + livelock_deterrence = FALSE; + + if (DrawCommandQueue.FullSize > DCQ_FORCE_BREAK_SIZE) + { + TFB_BatchReset (); + } + + if (DrawCommandQueue.Size > DCQ_FORCE_SLOWDOWN_SIZE) + { + Lock_DCQ (-1); + livelock_deterrence = TRUE; + } + + TFB_BBox_Reset (); + + for (;;) + { + TFB_DrawCommand DC; + + if (!TFB_DrawCommandQueue_Pop (&DC)) + { + // the Queue is now empty. + break; + } + + ++commands_handled; + if (!livelock_deterrence && commands_handled + DrawCommandQueue.Size + > DCQ_LIVELOCK_MAX) + { + // log_add (log_Debug, "Initiating livelock deterrence!"); + livelock_deterrence = TRUE; + + Lock_DCQ (-1); + } + + switch (DC.Type) + { + case TFB_DRAWCOMMANDTYPE_SETMIPMAP: + { + TFB_DrawCommand_SetMipmap *cmd = &DC.data.setmipmap; + TFB_DrawImage_SetMipmap (cmd->image, cmd->mipmap, + cmd->hotx, cmd->hoty); + break; + } + + case TFB_DRAWCOMMANDTYPE_IMAGE: + { + TFB_DrawCommand_Image *cmd = &DC.data.image; + TFB_Image *DC_image = cmd->image; + const int x = cmd->x; + const int y = cmd->y; + + TFB_DrawCanvas_Image (DC_image, x, y, + cmd->scale, cmd->scaleMode, cmd->colormap, + TFB_GetScreenCanvas (cmd->destBuffer)); + + if (cmd->destBuffer == TFB_SCREEN_MAIN) + { + LockMutex (DC_image->mutex); + if (cmd->scale) + TFB_BBox_RegisterCanvas (DC_image->ScaledImg, + x - DC_image->last_scale_hs.x, + y - DC_image->last_scale_hs.y); + else + TFB_BBox_RegisterCanvas (DC_image->NormalImg, + x - DC_image->NormalHs.x, + y - DC_image->NormalHs.y); + UnlockMutex (DC_image->mutex); + } + + break; + } + + case TFB_DRAWCOMMANDTYPE_FILLEDIMAGE: + { + TFB_DrawCommand_FilledImage *cmd = &DC.data.filledimage; + TFB_Image *DC_image = cmd->image; + const int x = cmd->x; + const int y = cmd->y; + + TFB_DrawCanvas_FilledImage (DC_image, x, y, + cmd->scale, cmd->scaleMode, cmd->color, + TFB_GetScreenCanvas (cmd->destBuffer)); + + if (cmd->destBuffer == TFB_SCREEN_MAIN) + { + LockMutex (DC_image->mutex); + if (cmd->scale) + TFB_BBox_RegisterCanvas (DC_image->ScaledImg, + x - DC_image->last_scale_hs.x, + y - DC_image->last_scale_hs.y); + else + TFB_BBox_RegisterCanvas (DC_image->NormalImg, + x - DC_image->NormalHs.x, + y - DC_image->NormalHs.y); + UnlockMutex (DC_image->mutex); + } + + break; + } + + case TFB_DRAWCOMMANDTYPE_FONTCHAR: + { + TFB_DrawCommand_FontChar *cmd = &DC.data.fontchar; + TFB_Char *DC_char = cmd->fontchar; + const int x = cmd->x; + const int y = cmd->y; + + TFB_DrawCanvas_FontChar (DC_char, cmd->backing, x, y, + TFB_GetScreenCanvas (cmd->destBuffer)); + + if (cmd->destBuffer == TFB_SCREEN_MAIN) + { + RECT r; + + r.corner.x = x - DC_char->HotSpot.x; + r.corner.y = y - DC_char->HotSpot.y; + r.extent.width = DC_char->extent.width; + r.extent.height = DC_char->extent.height; + + TFB_BBox_RegisterRect (&r); + } + + break; + } + + case TFB_DRAWCOMMANDTYPE_LINE: + { + TFB_DrawCommand_Line *cmd = &DC.data.line; + + if (cmd->destBuffer == TFB_SCREEN_MAIN) + { + TFB_BBox_RegisterPoint (cmd->x1, cmd->y1); + TFB_BBox_RegisterPoint (cmd->x2, cmd->y2); + } + TFB_DrawCanvas_Line (cmd->x1, cmd->y1, cmd->x2, cmd->y2, + cmd->color, TFB_GetScreenCanvas (cmd->destBuffer)); + break; + } + + case TFB_DRAWCOMMANDTYPE_RECTANGLE: + { + TFB_DrawCommand_Rect *cmd = &DC.data.rect; + + if (cmd->destBuffer == TFB_SCREEN_MAIN) + TFB_BBox_RegisterRect (&cmd->rect); + TFB_DrawCanvas_Rect (&cmd->rect, cmd->color, + TFB_GetScreenCanvas (cmd->destBuffer)); + + break; + } + + case TFB_DRAWCOMMANDTYPE_SCISSORENABLE: + { + TFB_DrawCommand_Scissor *cmd = &DC.data.scissor; + + TFB_DrawCanvas_SetClipRect ( + TFB_GetScreenCanvas (TFB_SCREEN_MAIN), &cmd->rect); + TFB_BBox_SetClipRect (&DC.data.scissor.rect); + break; + } + + case TFB_DRAWCOMMANDTYPE_SCISSORDISABLE: + TFB_DrawCanvas_SetClipRect ( + TFB_GetScreenCanvas (TFB_SCREEN_MAIN), NULL); + TFB_BBox_SetClipRect (NULL); + break; + + case TFB_DRAWCOMMANDTYPE_COPYTOIMAGE: + { + TFB_DrawCommand_CopyToImage *cmd = &DC.data.copytoimage; + TFB_Image *DC_image = cmd->image; + const POINT dstPt = {0, 0}; + + if (DC_image == 0) + { + log_add (log_Debug, "DCQ ERROR: COPYTOIMAGE passed null " + "image ptr"); + break; + } + LockMutex (DC_image->mutex); + TFB_DrawCanvas_CopyRect ( + TFB_GetScreenCanvas (cmd->srcBuffer), &cmd->rect, + DC_image->NormalImg, dstPt); + UnlockMutex (DC_image->mutex); + break; + } + + case TFB_DRAWCOMMANDTYPE_COPY: + { + TFB_DrawCommand_Copy *cmd = &DC.data.copy; + const RECT r = cmd->rect; + + if (cmd->destBuffer == TFB_SCREEN_MAIN) + TFB_BBox_RegisterRect (&cmd->rect); + + TFB_DrawCanvas_CopyRect ( + TFB_GetScreenCanvas (cmd->srcBuffer), &r, + TFB_GetScreenCanvas (cmd->destBuffer), r.corner); + break; + } + + case TFB_DRAWCOMMANDTYPE_DELETEIMAGE: + { + TFB_Image *DC_image = DC.data.deleteimage.image; + TFB_DrawImage_Delete (DC_image); + break; + } + + case TFB_DRAWCOMMANDTYPE_DELETEDATA: + { + void *data = DC.data.deletedata.data; + HFree (data); + break; + } + + case TFB_DRAWCOMMANDTYPE_SENDSIGNAL: + ClearSemaphore (DC.data.sendsignal.sem); + break; + + case TFB_DRAWCOMMANDTYPE_REINITVIDEO: + { + TFB_DrawCommand_ReinitVideo *cmd = &DC.data.reinitvideo; + int oldDriver = GraphicsDriver; + int oldFlags = GfxFlags; + int oldWidth = ScreenWidthActual; + int oldHeight = ScreenHeightActual; + if (TFB_ReInitGraphics (cmd->driver, cmd->flags, + cmd->width, cmd->height)) + { + log_add (log_Error, "Could not provide requested mode: " + "reverting to last known driver."); + // We don't know what exactly failed, so roll it all back + if (TFB_ReInitGraphics (oldDriver, oldFlags, + oldWidth, oldHeight)) + { + log_add (log_Fatal, + "Couldn't reinit at that point either. " + "Your video has been somehow tied in knots."); + exit (EXIT_FAILURE); + } + } + TFB_SwapBuffers (TFB_REDRAW_YES); + break; + } + + case TFB_DRAWCOMMANDTYPE_CALLBACK: + { + DC.data.callback.callback (DC.data.callback.arg); + break; + } + } + } + + if (livelock_deterrence) + Unlock_DCQ (); + + TFB_SwapBuffers (TFB_REDRAW_NO); + RenderedFrames++; + BroadcastCondVar (RenderingCond); +} diff --git a/sc2/src/libs/graphics/drawcmd.h b/sc2/src/libs/graphics/drawcmd.h index 2efb9cb02..884b4bfb4 100644 --- a/sc2/src/libs/graphics/drawcmd.h +++ b/sc2/src/libs/graphics/drawcmd.h @@ -87,14 +87,14 @@ typedef struct tfb_dc_fontchar typedef struct tfb_dc_copy { - int x, y, w, h; + RECT rect; SCREEN srcBuffer, destBuffer; } TFB_DrawCommand_Copy; typedef struct tfb_dc_copyimg { TFB_Image *image; - int x, y, w, h; + RECT rect; SCREEN srcBuffer; } TFB_DrawCommand_CopyToImage; diff --git a/sc2/src/libs/graphics/gfx_common.c b/sc2/src/libs/graphics/gfx_common.c index 2eb8e0cab..ceee09df3 100644 --- a/sc2/src/libs/graphics/gfx_common.c +++ b/sc2/src/libs/graphics/gfx_common.c @@ -19,6 +19,7 @@ #include "gfxintrn.h" #include "libs/graphics/gfx_common.h" #include "libs/graphics/drawcmd.h" +#include "libs/timelib.h" #include "libs/misc.h" // for TFB_DEBUG_HALT @@ -35,6 +36,9 @@ int ScreenColorDepth; int GraphicsDriver; int TFB_DEBUG_HALT = 0; +volatile int TransitionAmount = 255; +RECT TransitionClipRect; + static int gscale = GSCALE_IDENTITY; static int gscale_mode = TFB_SCALE_NEAREST; @@ -78,3 +82,119 @@ GetGraphicScaleMode (void) { return gscale_mode; } + +/* 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) +{ + TFB_BatchGraphics (); +} + +void +UnbatchGraphics (void) +{ + TFB_UnbatchGraphics (); +} + +/* Sleeps this thread until all Draw Commands queued by that thread have + been processed. */ + +void +FlushGraphics () +{ + TFB_DrawScreen_WaitForSignal (); +} + +static void +ExpandRect (RECT *rect, int expansion) +{ + if (rect->corner.x - expansion >= 0) + { + rect->extent.width += expansion; + rect->corner.x -= expansion; + } + else + { + rect->extent.width += rect->corner.x; + rect->corner.x = 0; + } + + if (rect->corner.y - expansion >= 0) + { + rect->extent.height += expansion; + rect->corner.y -= expansion; + } + else + { + rect->extent.height += rect->corner.y; + rect->corner.y = 0; + } + + if (rect->corner.x + rect->extent.width + expansion <= ScreenWidth) + rect->extent.width += expansion; + else + rect->extent.width = ScreenWidth - rect->corner.x; + + if (rect->corner.y + rect->extent.height + expansion <= ScreenHeight) + rect->extent.height += expansion; + else + rect->extent.height = ScreenHeight - rect->corner.y; +} + +void +SetTransitionSource (const RECT *pRect) +{ + RECT ActualRect; + + if (pRect) + { /* expand the rect to accomodate scalers in OpenGL mode */ + ActualRect = *pRect; + pRect = &ActualRect; + ExpandRect (&ActualRect, 2); + } + TFB_DrawScreen_Copy (pRect, TFB_SCREEN_MAIN, TFB_SCREEN_TRANSITION); +} + +// ScreenTransition() is synchronous (does not return until transition done) +void +ScreenTransition (int TransType, const RECT *pRect) +{ + const TimePeriod DURATION = ONE_SECOND * 31 / 60; + TimeCount startTime; + (void) TransType; /* dodge compiler warning */ + + if (pRect) + { + TransitionClipRect = *pRect; + } + else + { + TransitionClipRect.corner.x = 0; + TransitionClipRect.corner.y = 0; + TransitionClipRect.extent.width = ScreenWidth; + TransitionClipRect.extent.height = ScreenHeight; + } + + TFB_UploadTransitionScreen (); + + TransitionAmount = 0; + FlushGraphics (); + startTime = GetTimeCounter (); + while (TransitionAmount < 255) + { + TimePeriod deltaT; + int newAmount; + + SleepThread (ONE_SECOND / 100); + + deltaT = GetTimeCounter () - startTime; + newAmount = deltaT * 255 / DURATION; + if (newAmount > 255) + newAmount = 255; + + TransitionAmount = newAmount; + } +} diff --git a/sc2/src/libs/graphics/gfx_common.h b/sc2/src/libs/graphics/gfx_common.h index ca9f90706..ef9cd718a 100644 --- a/sc2/src/libs/graphics/gfx_common.h +++ b/sc2/src/libs/graphics/gfx_common.h @@ -61,10 +61,16 @@ enum // The flag variable itself extern int GfxFlags; +// The following functions are driver-defined void TFB_PreInit (void); int TFB_InitGraphics (int driver, int flags, int width, int height); +int TFB_ReInitGraphics (int driver, int flags, int width, int height); void TFB_UninitGraphics (void); void TFB_ProcessEvents (void); +void TFB_SetGamma (float gamma); +void TFB_UploadTransitionScreen (void); +// This function should not be called directly +void TFB_SwapBuffers (int force_full_redraw); #define GSCALE_IDENTITY 256 @@ -81,17 +87,18 @@ int SetGraphicScale (int scale); int GetGraphicScale (void); int SetGraphicScaleMode (int mode /* enum SCALE */); int GetGraphicScaleMode (void); -void SetTransitionSource (RECT *pRect); -void ScreenTransition (int transition, RECT *pRect); +void SetTransitionSource (const RECT *pRect); +void ScreenTransition (int transition, const RECT *pRect); + +// TODO: there should be accessor functions for these +extern volatile int TransitionAmount; +extern RECT TransitionClipRect; extern float FrameRate; extern int FrameRateTickBase; void TFB_FlushGraphics (void); // Only call from main thread!! -void TFB_SetGamma (float gamma); -// Unknown Stuff - extern int ScreenWidth; extern int ScreenHeight; extern int ScreenWidthActual; diff --git a/sc2/src/libs/graphics/sdl/3do_funcs.c b/sc2/src/libs/graphics/sdl/3do_funcs.c index 593e506ec..fc91623a9 100644 --- a/sc2/src/libs/graphics/sdl/3do_funcs.c +++ b/sc2/src/libs/graphics/sdl/3do_funcs.c @@ -26,9 +26,6 @@ #include "libs/graphics/tfb_draw.h" -int batch_depth = 0; - - //Status: Not entirely unimplemented! BOOLEAN InitGraphics (int argc, char* argv[], COUNT KbytesRequired) @@ -57,130 +54,6 @@ UninitGraphics () // Also probably empty //mem_uninit (); } -/* 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) -{ - TFB_BatchGraphics (); -} - -void -UnbatchGraphics (void) -{ - TFB_UnbatchGraphics (); -} - -/* Sleeps this thread until all Draw Commands queued by that thread have - been processed. */ - -void -FlushGraphics () -{ - TFB_DrawScreen_WaitForSignal (); -} - -static void -ExpandRect (RECT *rect, int expansion) -{ - if (rect->corner.x - expansion >= 0) - { - rect->extent.width += expansion; - rect->corner.x -= expansion; - } - else - { - rect->extent.width += rect->corner.x; - rect->corner.x = 0; - } - - if (rect->corner.y - expansion >= 0) - { - rect->extent.height += expansion; - rect->corner.y -= expansion; - } - else - { - rect->extent.height += rect->corner.y; - rect->corner.y = 0; - } - - if (rect->corner.x + rect->extent.width + expansion <= ScreenWidth) - rect->extent.width += expansion; - else - rect->extent.width = ScreenWidth - rect->corner.x; - - if (rect->corner.y + rect->extent.height + expansion <= ScreenHeight) - rect->extent.height += expansion; - else - rect->extent.height = ScreenHeight - rect->corner.y; -} - -void -SetTransitionSource (RECT *pRect) -{ - RECT ActualRect; - - if (pRect) - { /* expand the rect to accomodate scalers in OpenGL mode */ - ActualRect = *pRect; - pRect = &ActualRect; - ExpandRect (&ActualRect, 2); - } - TFB_DrawScreen_Copy(pRect, TFB_SCREEN_MAIN, TFB_SCREEN_TRANSITION); -} - -// Status: Implemented -void -ScreenTransition (int TransType, RECT *pRect) -{ - const float DURATION = (31.0f / 60.0f); // in seconds - Uint32 last_time = 0, current_time, delta_time, add_amount; - (void) TransType; /* dodge compiler warning */ - - if (pRect) - { - TransitionClipRect.x = pRect->corner.x; - TransitionClipRect.y = pRect->corner.y; - TransitionClipRect.w = pRect->extent.width; - TransitionClipRect.h = pRect->extent.height; - } - else - { - TransitionClipRect.x = TransitionClipRect.y = 0; - TransitionClipRect.w = ScreenWidth; - TransitionClipRect.h = ScreenHeight; - } - -#ifdef HAVE_OPENGL - if (GraphicsDriver == TFB_GFXDRIVER_SDL_OPENGL) - { - TFB_GL_UploadTransitionScreen (); - } -#endif - - TransitionAmount = 0; - FlushGraphics (); - last_time = SDL_GetTicks (); - for (;;) - { - SDL_Delay (10); - - current_time = SDL_GetTicks (); - delta_time = current_time - last_time; - last_time = current_time; - - add_amount = (Uint32) ((delta_time / 1000.0f / DURATION) * 255); - if (TransitionAmount + add_amount >= 255) - break; - - TransitionAmount += add_amount; - } - TransitionAmount = 255; -} - BOOLEAN _image_intersect (IMAGE_BOX *box1, IMAGE_BOX *box2, RECT *rect) { diff --git a/sc2/src/libs/graphics/sdl/canvas.c b/sc2/src/libs/graphics/sdl/canvas.c index ee8cd53fd..9d03a619a 100644 --- a/sc2/src/libs/graphics/sdl/canvas.c +++ b/sc2/src/libs/graphics/sdl/canvas.c @@ -1669,3 +1669,55 @@ TFB_DrawCanvas_GetRotatedExtent (TFB_Canvas src_canvas, int angle, EXTENT *size) size->width = dstw; } +void +TFB_DrawCanvas_CopyRect (TFB_Canvas source, const RECT *srcRect, + TFB_Canvas target, POINT dstPt) +{ + SDL_Rect sourceRect, targetRect; + + if (source == 0 || target == 0) + { + log_add (log_Warning, + "ERROR: TFB_DrawCanvas_CopyRect passed null canvas ptr"); + return; + } + + sourceRect.x = srcRect->corner.x; + sourceRect.y = srcRect->corner.y; + sourceRect.w = srcRect->extent.width; + sourceRect.h = srcRect->extent.height; + + targetRect.x = dstPt.x; + targetRect.y = dstPt.y; + // According to SDL docs, width and height are ignored, but + // we'll set them anyway, just in case. + targetRect.w = srcRect->extent.width; + targetRect.h = srcRect->extent.height; + + SDL_BlitSurface (source, &sourceRect, target, &targetRect); +} + +void +TFB_DrawCanvas_SetClipRect (TFB_Canvas canvas, const RECT *clipRect) +{ + if (canvas == 0) + { + log_add (log_Warning, + "ERROR: TFB_DrawCanvas_SetClipRect passed null canvas ptr"); + return; + } + + if (!clipRect) + { // clipping disabled + SDL_SetClipRect (canvas, NULL); + } + else + { + SDL_Rect r; + r.x = clipRect->corner.x; + r.y = clipRect->corner.y; + r.w = clipRect->extent.width; + r.h = clipRect->extent.height; + SDL_SetClipRect (canvas, &r); + } +} diff --git a/sc2/src/libs/graphics/sdl/sdl_common.c b/sc2/src/libs/graphics/sdl/sdl_common.c index db5f9da8a..5538b5e54 100644 --- a/sc2/src/libs/graphics/sdl/sdl_common.c +++ b/sc2/src/libs/graphics/sdl/sdl_common.c @@ -45,17 +45,12 @@ SDL_Surface *SDL_Screens[TFB_GFX_NUMSCREENS]; SDL_Surface *format_conv_surf = NULL; -volatile int TransitionAmount = 255; -SDL_Rect TransitionClipRect; static volatile BOOLEAN abortFlag = FALSE; int GfxFlags = 0; TFB_GRAPHICS_BACKEND *graphics_backend = NULL; -#define FPS_PERIOD 100 -int RenderedFrames = 0; - volatile int QuitPosted = 0; volatile int GameActive = 1; // Track the SDL_ACTIVEEVENT state SDL_APPACTIVE @@ -174,10 +169,6 @@ TFB_InitGraphics (int driver, int flags, int width, int height) Init_DrawCommandQueue (); TFB_DrawCanvas_Initialize (); - TFB_BBox_Init (ScreenWidth, ScreenHeight); - - RenderingCond = CreateCondVar ("DCQ empty", - SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO); atexit (TFB_UninitGraphics); @@ -277,8 +268,13 @@ TFB_SwapBuffers (int force_full_redraw) if (transition_amount != 255) { + SDL_Rect r; + r.x = TransitionClipRect.corner.x; + r.y = TransitionClipRect.corner.y; + r.w = TransitionClipRect.extent.width; + r.h = TransitionClipRect.extent.height; graphics_backend->screen (TFB_SCREEN_TRANSITION, - 255 - transition_amount, &TransitionClipRect); + 255 - transition_amount, &r); } if (fade_amount != 255) @@ -339,7 +335,7 @@ TFB_DisplayFormatAlpha (SDL_Surface *surface) TFB_Canvas TFB_GetScreenCanvas (SCREEN screen) { - return (TFB_Canvas) SDL_Screens[screen]; + return SDL_Screens[screen]; } void TFB_BlitSurface (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, @@ -586,323 +582,14 @@ void TFB_BlitSurface (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, } void -TFB_ComputeFPS (void) +TFB_UploadTransitionScreen (void) { - static Uint32 last_time = 0, fps_counter = 0; - Uint32 current_time, delta_time; - - current_time = SDL_GetTicks (); - delta_time = current_time - last_time; - last_time = current_time; - - fps_counter += delta_time; - if (fps_counter > FPS_PERIOD) +#ifdef HAVE_OPENGL + if (GraphicsDriver == TFB_GFXDRIVER_SDL_OPENGL) { - log_add (log_User, "fps %.2f, effective %.2f", - 1000.0 / delta_time, - 1000.0 * RenderedFrames / fps_counter); - - fps_counter = 0; - RenderedFrames = 0; + TFB_GL_UploadTransitionScreen (); } -} - -void -TFB_FlushGraphics (void) // Only call from main thread!! -{ - int commands_handled; - BOOLEAN livelock_deterrence; - BOOLEAN done; - - // This is technically a locking violation on DrawCommandQueue.Size, - // but it is likely to not be very destructive. - if (DrawCommandQueue.Size == 0) - { - static int last_fade = 255; - static int last_transition = 255; - int current_fade = GetFadeAmount (); - int current_transition = TransitionAmount; - - if ((current_fade != 255 && current_fade != last_fade) || - (current_transition != 255 && - current_transition != last_transition) || - (current_fade == 255 && last_fade != 255) || - (current_transition == 255 && last_transition != 255)) - { - TFB_SwapBuffers (TFB_REDRAW_FADING); - // if fading, redraw every frame - } - else - { - TaskSwitch (); - } - - last_fade = current_fade; - last_transition = current_transition; - BroadcastCondVar (RenderingCond); - return; - } - - if (GfxFlags & TFB_GFXFLAGS_SHOWFPS) - TFB_ComputeFPS (); - - commands_handled = 0; - livelock_deterrence = FALSE; - - if (DrawCommandQueue.FullSize > DCQ_FORCE_BREAK_SIZE) - { - TFB_BatchReset (); - } - - if (DrawCommandQueue.Size > DCQ_FORCE_SLOWDOWN_SIZE) - { - Lock_DCQ (-1); - livelock_deterrence = TRUE; - } - - TFB_BBox_Reset (); - - done = FALSE; - while (!done) - { - TFB_DrawCommand DC; - - if (!TFB_DrawCommandQueue_Pop (&DC)) - { - // the Queue is now empty. - break; - } - - ++commands_handled; - if (!livelock_deterrence && commands_handled + DrawCommandQueue.Size - > DCQ_LIVELOCK_MAX) - { - // log_add (log_Debug, "Initiating livelock deterrence!"); - livelock_deterrence = TRUE; - - Lock_DCQ (-1); - } - - switch (DC.Type) - { - case TFB_DRAWCOMMANDTYPE_SETMIPMAP: - TFB_DrawImage_SetMipmap (DC.data.setmipmap.image, - DC.data.setmipmap.mipmap, - DC.data.setmipmap.hotx, DC.data.setmipmap.hoty); - break; - case TFB_DRAWCOMMANDTYPE_IMAGE: - { - TFB_DrawCommand_Image *cmd = &DC.data.image; - TFB_Image *DC_image = cmd->image; - int x = cmd->x; - int y = cmd->y; - - TFB_DrawCanvas_Image (DC_image, x, y, - cmd->scale, cmd->scaleMode, cmd->colormap, - SDL_Screens[cmd->destBuffer]); - - if (cmd->destBuffer == 0) - { - LockMutex (DC_image->mutex); - if (DC.data.image.scale) - TFB_BBox_RegisterCanvas (DC_image->ScaledImg, - x - DC_image->last_scale_hs.x, - y - DC_image->last_scale_hs.y); - else - TFB_BBox_RegisterCanvas (DC_image->NormalImg, - x - DC_image->NormalHs.x, - y - DC_image->NormalHs.y); - UnlockMutex (DC_image->mutex); - } - - break; - } - case TFB_DRAWCOMMANDTYPE_FILLEDIMAGE: - { - TFB_DrawCommand_FilledImage *cmd = &DC.data.filledimage; - TFB_Image *DC_image = cmd->image; - int x = cmd->x; - int y = cmd->y; - - TFB_DrawCanvas_FilledImage (DC_image, x, y, - cmd->scale, cmd->scaleMode, cmd->color, - SDL_Screens[cmd->destBuffer]); - - if (cmd->destBuffer == 0) - { - LockMutex (DC_image->mutex); - if (DC.data.filledimage.scale) - TFB_BBox_RegisterCanvas (DC_image->ScaledImg, - x - DC_image->last_scale_hs.x, - y - DC_image->last_scale_hs.y); - else - TFB_BBox_RegisterCanvas (DC_image->NormalImg, - x - DC_image->NormalHs.x, - y - DC_image->NormalHs.y); - UnlockMutex (DC_image->mutex); - } - - break; - } - case TFB_DRAWCOMMANDTYPE_FONTCHAR: - { - TFB_Char *DC_char = DC.data.fontchar.fontchar; - int x = DC.data.fontchar.x; - int y = DC.data.fontchar.y; - - TFB_DrawCanvas_FontChar (DC.data.fontchar.fontchar, - DC.data.fontchar.backing, - DC.data.fontchar.x, DC.data.fontchar.y, - SDL_Screens[DC.data.fontchar.destBuffer]); - - if (DC.data.fontchar.destBuffer == 0) - { - RECT r; - - r.corner.x = x - DC_char->HotSpot.x; - r.corner.y = y - DC_char->HotSpot.y; - r.extent.width = DC_char->extent.width; - r.extent.height = DC_char->extent.height; - - TFB_BBox_RegisterRect (&r); - } - - break; - } - case TFB_DRAWCOMMANDTYPE_LINE: - { - if (DC.data.line.destBuffer == 0) - { - TFB_BBox_RegisterPoint (DC.data.line.x1, DC.data.line.y1); - TFB_BBox_RegisterPoint (DC.data.line.x2, DC.data.line.y2); - } - TFB_DrawCanvas_Line (DC.data.line.x1, DC.data.line.y1, - DC.data.line.x2, DC.data.line.y2, - DC.data.line.color, - SDL_Screens[DC.data.line.destBuffer]); - break; - } - case TFB_DRAWCOMMANDTYPE_RECTANGLE: - { - if (DC.data.rect.destBuffer == 0) - TFB_BBox_RegisterRect (&DC.data.rect.rect); - TFB_DrawCanvas_Rect (&DC.data.rect.rect, DC.data.rect.color, - SDL_Screens[DC.data.rect.destBuffer]); - - break; - } - case TFB_DRAWCOMMANDTYPE_SCISSORENABLE: - { - SDL_Rect r; - r.x = DC.data.scissor.rect.corner.x; - r.y = DC.data.scissor.rect.corner.y; - r.w = DC.data.scissor.rect.extent.width; - r.h = DC.data.scissor.rect.extent.height; - SDL_SetClipRect (SDL_Screens[0], &r); - TFB_BBox_SetClipRect (&DC.data.scissor.rect); - break; - } - case TFB_DRAWCOMMANDTYPE_SCISSORDISABLE: - SDL_SetClipRect (SDL_Screens[0], NULL); - TFB_BBox_SetClipRect (NULL); - break; - case TFB_DRAWCOMMANDTYPE_COPYTOIMAGE: - { - SDL_Rect src, dest; - TFB_Image *DC_image = DC.data.copytoimage.image; - - if (DC_image == 0) - { - log_add (log_Debug, "DCQ ERROR: COPYTOIMAGE passed null " - "image ptr"); - break; - } - LockMutex (DC_image->mutex); - - src.x = dest.x = DC.data.copytoimage.x; - src.y = dest.y = DC.data.copytoimage.y; - src.w = DC.data.copytoimage.w; - src.h = DC.data.copytoimage.h; - - dest.x = 0; - dest.y = 0; - SDL_BlitSurface (SDL_Screens[DC.data.copytoimage.srcBuffer], - &src, DC_image->NormalImg, &dest); - UnlockMutex (DC_image->mutex); - break; - } - case TFB_DRAWCOMMANDTYPE_COPY: - { - SDL_Rect src, dest; - src.x = dest.x = DC.data.copy.x; - src.y = dest.y = DC.data.copy.y; - src.w = DC.data.copy.w; - src.h = DC.data.copy.h; - - if (DC.data.copy.destBuffer == 0) - { - TFB_BBox_RegisterPoint (src.x, src.y); - TFB_BBox_RegisterPoint (src.x + src.w, src.y + src.h); - } - - SDL_BlitSurface (SDL_Screens[DC.data.copy.srcBuffer], &src, - SDL_Screens[DC.data.copy.destBuffer], &dest); - break; - } - case TFB_DRAWCOMMANDTYPE_DELETEIMAGE: - { - TFB_Image *DC_image = (TFB_Image *)DC.data.deleteimage.image; - TFB_DrawImage_Delete (DC_image); - break; - } - case TFB_DRAWCOMMANDTYPE_DELETEDATA: - { - void *data = DC.data.deletedata.data; - HFree (data); - break; - } - case TFB_DRAWCOMMANDTYPE_SENDSIGNAL: - ClearSemaphore (DC.data.sendsignal.sem); - break; - case TFB_DRAWCOMMANDTYPE_REINITVIDEO: - { - int oldDriver = GraphicsDriver; - int oldFlags = GfxFlags; - int oldWidth = ScreenWidthActual; - int oldHeight = ScreenHeightActual; - if (TFB_ReInitGraphics (DC.data.reinitvideo.driver, - DC.data.reinitvideo.flags, - DC.data.reinitvideo.width, DC.data.reinitvideo.height)) - { - log_add (log_Error, "Could not provide requested mode: " - "reverting to last known driver."); - // We don't know what exactly failed, so roll it all back - if (TFB_ReInitGraphics (oldDriver, oldFlags, - oldWidth, oldHeight)) - { - log_add (log_Fatal, - "Couldn't reinit at that point either. " - "Your video has been somehow tied in knots."); - exit (EXIT_FAILURE); - } - } - TFB_SwapBuffers (TFB_REDRAW_YES); - break; - } - case TFB_DRAWCOMMANDTYPE_CALLBACK: - { - DC.data.callback.callback (DC.data.callback.arg); - break; - } - } - } - - if (livelock_deterrence) - Unlock_DCQ (); - - TFB_SwapBuffers (TFB_REDRAW_NO); - RenderedFrames++; - BroadcastCondVar (RenderingCond); +#endif } void diff --git a/sc2/src/libs/graphics/sdl/sdl_common.h b/sc2/src/libs/graphics/sdl/sdl_common.h index eb424263b..9e89d4094 100644 --- a/sc2/src/libs/graphics/sdl/sdl_common.h +++ b/sc2/src/libs/graphics/sdl/sdl_common.h @@ -46,13 +46,9 @@ extern SDL_Surface *SDL_Screens[TFB_GFX_NUMSCREENS]; extern SDL_Surface *format_conv_surf; -extern volatile int TransitionAmount; -extern SDL_Rect TransitionClipRect; - void ScreenOrigin (FRAME Display, COORD sx, COORD sy); void LoadDisplay (DISPLAY_INTERFACE **pDisplay); -void TFB_SwapBuffers (int force_full_redraw); SDL_Surface* TFB_DisplayFormatAlpha (SDL_Surface *surface); void TFB_BlitSurface (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect, int blend_numer, int blend_denom); diff --git a/sc2/src/libs/graphics/tfb_draw.c b/sc2/src/libs/graphics/tfb_draw.c index 971979972..3a778532c 100644 --- a/sc2/src/libs/graphics/tfb_draw.c +++ b/sc2/src/libs/graphics/tfb_draw.c @@ -114,15 +114,12 @@ TFB_DrawScreen_FontChar (TFB_Char *fontChar, TFB_Image *backing, } void -TFB_DrawScreen_CopyToImage (TFB_Image *img, RECT *lpRect, SCREEN src) +TFB_DrawScreen_CopyToImage (TFB_Image *img, const RECT *r, SCREEN src) { TFB_DrawCommand DC; DC.Type = TFB_DRAWCOMMANDTYPE_COPYTOIMAGE; - DC.data.copytoimage.x = lpRect->corner.x; - DC.data.copytoimage.y = lpRect->corner.y; - DC.data.copytoimage.w = lpRect->extent.width; - DC.data.copytoimage.h = lpRect->extent.height; + DC.data.copytoimage.rect = *r; DC.data.copytoimage.image = img; DC.data.copytoimage.srcBuffer = src; @@ -130,7 +127,7 @@ TFB_DrawScreen_CopyToImage (TFB_Image *img, RECT *lpRect, SCREEN src) } void -TFB_DrawScreen_Copy (RECT *r, SCREEN src, SCREEN dest) +TFB_DrawScreen_Copy (const RECT *r, SCREEN src, SCREEN dest) { RECT locRect; TFB_DrawCommand DC; @@ -144,10 +141,7 @@ TFB_DrawScreen_Copy (RECT *r, SCREEN src, SCREEN dest) } DC.Type = TFB_DRAWCOMMANDTYPE_COPY; - DC.data.copy.x = r->corner.x; - DC.data.copy.y = r->corner.y; - DC.data.copy.w = r->extent.width; - DC.data.copy.h = r->extent.height; + DC.data.copy.rect = *r; DC.data.copy.srcBuffer = src; DC.data.copy.destBuffer = dest; diff --git a/sc2/src/libs/graphics/tfb_draw.h b/sc2/src/libs/graphics/tfb_draw.h index a0a216095..dc325a8c8 100644 --- a/sc2/src/libs/graphics/tfb_draw.h +++ b/sc2/src/libs/graphics/tfb_draw.h @@ -83,13 +83,13 @@ void TFB_DrawScreen_Line (int x1, int y1, int x2, int y2, Color color, void TFB_DrawScreen_Rect (RECT *rect, Color color, SCREEN dest); void TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale, int scaleMode, TFB_ColorMap *cmap, SCREEN dest); -void TFB_DrawScreen_Copy (RECT *r, SCREEN src, SCREEN dest); +void TFB_DrawScreen_Copy (const RECT *r, SCREEN src, SCREEN dest); void TFB_DrawScreen_FilledImage (TFB_Image *img, int x, int y, int scale, int scaleMode, Color color, SCREEN dest); void TFB_DrawScreen_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, SCREEN dest); -void TFB_DrawScreen_CopyToImage (TFB_Image *img, RECT *lpRect, SCREEN src); +void TFB_DrawScreen_CopyToImage (TFB_Image *img, const RECT *r, SCREEN src); void TFB_DrawScreen_SetMipmap (TFB_Image *img, TFB_Image *mmimg, int hotx, int hoty); void TFB_DrawScreen_DeleteImage (TFB_Image *img); @@ -139,6 +139,7 @@ void TFB_DrawCanvas_Rotate (TFB_Canvas src, TFB_Canvas dst, int angle, EXTENT size); void TFB_DrawCanvas_GetRotatedExtent (TFB_Canvas src, int angle, EXTENT *size); void TFB_DrawCanvas_GetExtent (TFB_Canvas canvas, EXTENT *size); +void TFB_DrawCanvas_SetClipRect (TFB_Canvas canvas, const RECT *clipRect); void TFB_DrawCanvas_Delete (TFB_Canvas canvas); @@ -151,6 +152,8 @@ void TFB_DrawCanvas_FilledImage (TFB_Image *img, int x, int y, int scale, int scaleMode, Color color, TFB_Canvas target); void TFB_DrawCanvas_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, TFB_Canvas target); +void TFB_DrawCanvas_CopyRect (TFB_Canvas source, const RECT *srcRect, + TFB_Canvas target, POINT dstPt); Color *TFB_DrawCanvas_ExtractPalette (TFB_Canvas canvas); void TFB_DrawCanvas_SetPalette (TFB_Canvas target, Color palette[256]);