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
This commit is contained in:
avolkov
2009-12-23 15:26:53 +00:00
parent 0ebc5dc6fb
commit ce1dd1aea7
10 changed files with 547 additions and 476 deletions
+340 -1
View File
@@ -20,6 +20,9 @@
#include "libs/graphics/drawable.h" #include "libs/graphics/drawable.h"
#include "libs/graphics/context.h" #include "libs/graphics/context.h"
#include "libs/graphics/dcqueue.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/log.h"
#include "libs/misc.h" #include "libs/misc.h"
// for TFB_DEBUG_HALT // for TFB_DEBUG_HALT
@@ -33,6 +36,10 @@ TFB_DrawCommand DCQ[DCQ_MAX];
TFB_DrawCommandQueue DrawCommandQueue; TFB_DrawCommandQueue DrawCommandQueue;
#define FPS_PERIOD (ONE_SECOND / 100)
int RenderedFrames = 0;
// Wait for the queue to be emptied. // Wait for the queue to be emptied.
static void static void
TFB_WaitForSpace (int requested_slots) TFB_WaitForSpace (int requested_slots)
@@ -137,12 +144,19 @@ Init_DrawCommandQueue (void)
DrawCommandQueue.FullSize = 0; DrawCommandQueue.FullSize = 0;
DrawCommandQueue.Size = 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 void
Uninit_DrawCommandQueue (void) Uninit_DrawCommandQueue (void)
{ {
DestroyCondVar (RenderingCond);
DestroyRecursiveMutex (DCQ_Mutex); DestroyRecursiveMutex (DCQ_Mutex);
} }
@@ -245,3 +259,328 @@ TFB_EnqueueDrawCommand (TFB_DrawCommand* DrawCommand)
TFB_DrawCommandQueue_Push (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);
}
+2 -2
View File
@@ -87,14 +87,14 @@ typedef struct tfb_dc_fontchar
typedef struct tfb_dc_copy typedef struct tfb_dc_copy
{ {
int x, y, w, h; RECT rect;
SCREEN srcBuffer, destBuffer; SCREEN srcBuffer, destBuffer;
} TFB_DrawCommand_Copy; } TFB_DrawCommand_Copy;
typedef struct tfb_dc_copyimg typedef struct tfb_dc_copyimg
{ {
TFB_Image *image; TFB_Image *image;
int x, y, w, h; RECT rect;
SCREEN srcBuffer; SCREEN srcBuffer;
} TFB_DrawCommand_CopyToImage; } TFB_DrawCommand_CopyToImage;
+120
View File
@@ -19,6 +19,7 @@
#include "gfxintrn.h" #include "gfxintrn.h"
#include "libs/graphics/gfx_common.h" #include "libs/graphics/gfx_common.h"
#include "libs/graphics/drawcmd.h" #include "libs/graphics/drawcmd.h"
#include "libs/timelib.h"
#include "libs/misc.h" #include "libs/misc.h"
// for TFB_DEBUG_HALT // for TFB_DEBUG_HALT
@@ -35,6 +36,9 @@ int ScreenColorDepth;
int GraphicsDriver; int GraphicsDriver;
int TFB_DEBUG_HALT = 0; int TFB_DEBUG_HALT = 0;
volatile int TransitionAmount = 255;
RECT TransitionClipRect;
static int gscale = GSCALE_IDENTITY; static int gscale = GSCALE_IDENTITY;
static int gscale_mode = TFB_SCALE_NEAREST; static int gscale_mode = TFB_SCALE_NEAREST;
@@ -78,3 +82,119 @@ GetGraphicScaleMode (void)
{ {
return gscale_mode; 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;
}
}
+12 -5
View File
@@ -61,10 +61,16 @@ enum
// The flag variable itself // The flag variable itself
extern int GfxFlags; extern int GfxFlags;
// The following functions are driver-defined
void TFB_PreInit (void); void TFB_PreInit (void);
int TFB_InitGraphics (int driver, int flags, int width, int height); 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_UninitGraphics (void);
void TFB_ProcessEvents (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 #define GSCALE_IDENTITY 256
@@ -81,17 +87,18 @@ int SetGraphicScale (int scale);
int GetGraphicScale (void); int GetGraphicScale (void);
int SetGraphicScaleMode (int mode /* enum SCALE */); int SetGraphicScaleMode (int mode /* enum SCALE */);
int GetGraphicScaleMode (void); int GetGraphicScaleMode (void);
void SetTransitionSource (RECT *pRect); void SetTransitionSource (const RECT *pRect);
void ScreenTransition (int transition, 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 float FrameRate;
extern int FrameRateTickBase; extern int FrameRateTickBase;
void TFB_FlushGraphics (void); // Only call from main thread!! void TFB_FlushGraphics (void); // Only call from main thread!!
void TFB_SetGamma (float gamma);
// Unknown Stuff
extern int ScreenWidth; extern int ScreenWidth;
extern int ScreenHeight; extern int ScreenHeight;
extern int ScreenWidthActual; extern int ScreenWidthActual;
-127
View File
@@ -26,9 +26,6 @@
#include "libs/graphics/tfb_draw.h" #include "libs/graphics/tfb_draw.h"
int batch_depth = 0;
//Status: Not entirely unimplemented! //Status: Not entirely unimplemented!
BOOLEAN BOOLEAN
InitGraphics (int argc, char* argv[], COUNT KbytesRequired) InitGraphics (int argc, char* argv[], COUNT KbytesRequired)
@@ -57,130 +54,6 @@ UninitGraphics () // Also probably empty
//mem_uninit (); //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 BOOLEAN
_image_intersect (IMAGE_BOX *box1, IMAGE_BOX *box2, RECT *rect) _image_intersect (IMAGE_BOX *box1, IMAGE_BOX *box2, RECT *rect)
{ {
+52
View File
@@ -1669,3 +1669,55 @@ TFB_DrawCanvas_GetRotatedExtent (TFB_Canvas src_canvas, int angle, EXTENT *size)
size->width = dstw; 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);
}
}
+12 -325
View File
@@ -45,17 +45,12 @@ SDL_Surface *SDL_Screens[TFB_GFX_NUMSCREENS];
SDL_Surface *format_conv_surf = NULL; SDL_Surface *format_conv_surf = NULL;
volatile int TransitionAmount = 255;
SDL_Rect TransitionClipRect;
static volatile BOOLEAN abortFlag = FALSE; static volatile BOOLEAN abortFlag = FALSE;
int GfxFlags = 0; int GfxFlags = 0;
TFB_GRAPHICS_BACKEND *graphics_backend = NULL; TFB_GRAPHICS_BACKEND *graphics_backend = NULL;
#define FPS_PERIOD 100
int RenderedFrames = 0;
volatile int QuitPosted = 0; volatile int QuitPosted = 0;
volatile int GameActive = 1; // Track the SDL_ACTIVEEVENT state SDL_APPACTIVE 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 (); Init_DrawCommandQueue ();
TFB_DrawCanvas_Initialize (); TFB_DrawCanvas_Initialize ();
TFB_BBox_Init (ScreenWidth, ScreenHeight);
RenderingCond = CreateCondVar ("DCQ empty",
SYNC_CLASS_TOPLEVEL | SYNC_CLASS_VIDEO);
atexit (TFB_UninitGraphics); atexit (TFB_UninitGraphics);
@@ -277,8 +268,13 @@ TFB_SwapBuffers (int force_full_redraw)
if (transition_amount != 255) 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, graphics_backend->screen (TFB_SCREEN_TRANSITION,
255 - transition_amount, &TransitionClipRect); 255 - transition_amount, &r);
} }
if (fade_amount != 255) if (fade_amount != 255)
@@ -339,7 +335,7 @@ TFB_DisplayFormatAlpha (SDL_Surface *surface)
TFB_Canvas TFB_Canvas
TFB_GetScreenCanvas (SCREEN screen) 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, 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 void
TFB_ComputeFPS (void) TFB_UploadTransitionScreen (void)
{ {
static Uint32 last_time = 0, fps_counter = 0; #ifdef HAVE_OPENGL
Uint32 current_time, delta_time; if (GraphicsDriver == TFB_GFXDRIVER_SDL_OPENGL)
current_time = SDL_GetTicks ();
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", TFB_GL_UploadTransitionScreen ();
1000.0 / delta_time,
1000.0 * RenderedFrames / fps_counter);
fps_counter = 0;
RenderedFrames = 0;
} }
} #endif
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);
} }
void void
-4
View File
@@ -46,13 +46,9 @@ extern SDL_Surface *SDL_Screens[TFB_GFX_NUMSCREENS];
extern SDL_Surface *format_conv_surf; extern SDL_Surface *format_conv_surf;
extern volatile int TransitionAmount;
extern SDL_Rect TransitionClipRect;
void ScreenOrigin (FRAME Display, COORD sx, COORD sy); void ScreenOrigin (FRAME Display, COORD sx, COORD sy);
void LoadDisplay (DISPLAY_INTERFACE **pDisplay); void LoadDisplay (DISPLAY_INTERFACE **pDisplay);
void TFB_SwapBuffers (int force_full_redraw);
SDL_Surface* TFB_DisplayFormatAlpha (SDL_Surface *surface); SDL_Surface* TFB_DisplayFormatAlpha (SDL_Surface *surface);
void TFB_BlitSurface (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, void TFB_BlitSurface (SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst,
SDL_Rect *dstrect, int blend_numer, int blend_denom); SDL_Rect *dstrect, int blend_numer, int blend_denom);
+4 -10
View File
@@ -114,15 +114,12 @@ TFB_DrawScreen_FontChar (TFB_Char *fontChar, TFB_Image *backing,
} }
void 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; TFB_DrawCommand DC;
DC.Type = TFB_DRAWCOMMANDTYPE_COPYTOIMAGE; DC.Type = TFB_DRAWCOMMANDTYPE_COPYTOIMAGE;
DC.data.copytoimage.x = lpRect->corner.x; DC.data.copytoimage.rect = *r;
DC.data.copytoimage.y = lpRect->corner.y;
DC.data.copytoimage.w = lpRect->extent.width;
DC.data.copytoimage.h = lpRect->extent.height;
DC.data.copytoimage.image = img; DC.data.copytoimage.image = img;
DC.data.copytoimage.srcBuffer = src; DC.data.copytoimage.srcBuffer = src;
@@ -130,7 +127,7 @@ TFB_DrawScreen_CopyToImage (TFB_Image *img, RECT *lpRect, SCREEN src)
} }
void void
TFB_DrawScreen_Copy (RECT *r, SCREEN src, SCREEN dest) TFB_DrawScreen_Copy (const RECT *r, SCREEN src, SCREEN dest)
{ {
RECT locRect; RECT locRect;
TFB_DrawCommand DC; TFB_DrawCommand DC;
@@ -144,10 +141,7 @@ TFB_DrawScreen_Copy (RECT *r, SCREEN src, SCREEN dest)
} }
DC.Type = TFB_DRAWCOMMANDTYPE_COPY; DC.Type = TFB_DRAWCOMMANDTYPE_COPY;
DC.data.copy.x = r->corner.x; DC.data.copy.rect = *r;
DC.data.copy.y = r->corner.y;
DC.data.copy.w = r->extent.width;
DC.data.copy.h = r->extent.height;
DC.data.copy.srcBuffer = src; DC.data.copy.srcBuffer = src;
DC.data.copy.destBuffer = dest; DC.data.copy.destBuffer = dest;
+5 -2
View File
@@ -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_Rect (RECT *rect, Color color, SCREEN dest);
void TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale, void TFB_DrawScreen_Image (TFB_Image *img, int x, int y, int scale,
int scaleMode, TFB_ColorMap *cmap, SCREEN dest); 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, void TFB_DrawScreen_FilledImage (TFB_Image *img, int x, int y, int scale,
int scaleMode, Color color, SCREEN dest); int scaleMode, Color color, SCREEN dest);
void TFB_DrawScreen_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, void TFB_DrawScreen_FontChar (TFB_Char *, TFB_Image *backing, int x, int y,
SCREEN dest); 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, void TFB_DrawScreen_SetMipmap (TFB_Image *img, TFB_Image *mmimg, int hotx,
int hoty); int hoty);
void TFB_DrawScreen_DeleteImage (TFB_Image *img); 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); EXTENT size);
void TFB_DrawCanvas_GetRotatedExtent (TFB_Canvas src, 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_GetExtent (TFB_Canvas canvas, EXTENT *size);
void TFB_DrawCanvas_SetClipRect (TFB_Canvas canvas, const RECT *clipRect);
void TFB_DrawCanvas_Delete (TFB_Canvas canvas); 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); int scaleMode, Color color, TFB_Canvas target);
void TFB_DrawCanvas_FontChar (TFB_Char *, TFB_Image *backing, int x, int y, void TFB_DrawCanvas_FontChar (TFB_Char *, TFB_Image *backing, int x, int y,
TFB_Canvas target); 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); Color *TFB_DrawCanvas_ExtractPalette (TFB_Canvas canvas);
void TFB_DrawCanvas_SetPalette (TFB_Canvas target, Color palette[256]); void TFB_DrawCanvas_SetPalette (TFB_Canvas target, Color palette[256]);