From a855d6202536ff28e5aae4f22a0f31d8f5b325d0 Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Sat, 21 Jan 2017 15:18:31 -0500 Subject: Port of Duke Nukem 3D This ports Fabien Sanglard's Chocolate Duke to run on a version of SDL for Rockbox. Change-Id: I8f2c4c78af19de10c1633ed7bb7a997b43256dd9 --- apps/plugins/sdl/src/timer/SDL_systimer.h | 40 +++ apps/plugins/sdl/src/timer/SDL_timer.c | 285 +++++++++++++++++ apps/plugins/sdl/src/timer/SDL_timer_c.h | 46 +++ apps/plugins/sdl/src/timer/beos/SDL_systimer.c | 95 ++++++ apps/plugins/sdl/src/timer/dc/SDL_systimer.c | 100 ++++++ apps/plugins/sdl/src/timer/dummy/SDL_systimer.c | 91 ++++++ apps/plugins/sdl/src/timer/macos/FastTimes.c | 352 +++++++++++++++++++++ apps/plugins/sdl/src/timer/macos/FastTimes.h | 27 ++ apps/plugins/sdl/src/timer/macos/SDL_MPWtimer.c | 152 +++++++++ apps/plugins/sdl/src/timer/macos/SDL_systimer.c | 186 +++++++++++ apps/plugins/sdl/src/timer/mint/SDL_systimer.c | 149 +++++++++ apps/plugins/sdl/src/timer/mint/SDL_vbltimer.S | 228 +++++++++++++ apps/plugins/sdl/src/timer/mint/SDL_vbltimer_s.h | 35 ++ apps/plugins/sdl/src/timer/nds/SDL_systimer.c | 73 +++++ apps/plugins/sdl/src/timer/os2/SDL_systimer.c | 227 +++++++++++++ apps/plugins/sdl/src/timer/riscos/SDL_systimer.c | 233 ++++++++++++++ apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c | 117 +++++++ .../plugins/sdl/src/timer/symbian/SDL_systimer.cpp | 114 +++++++ apps/plugins/sdl/src/timer/unix/SDL_systimer.c | 240 ++++++++++++++ apps/plugins/sdl/src/timer/win32/SDL_systimer.c | 160 ++++++++++ apps/plugins/sdl/src/timer/wince/SDL_systimer.c | 198 ++++++++++++ 21 files changed, 3148 insertions(+) create mode 100644 apps/plugins/sdl/src/timer/SDL_systimer.h create mode 100644 apps/plugins/sdl/src/timer/SDL_timer.c create mode 100644 apps/plugins/sdl/src/timer/SDL_timer_c.h create mode 100644 apps/plugins/sdl/src/timer/beos/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/dc/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/dummy/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/macos/FastTimes.c create mode 100644 apps/plugins/sdl/src/timer/macos/FastTimes.h create mode 100644 apps/plugins/sdl/src/timer/macos/SDL_MPWtimer.c create mode 100644 apps/plugins/sdl/src/timer/macos/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/mint/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/mint/SDL_vbltimer.S create mode 100644 apps/plugins/sdl/src/timer/mint/SDL_vbltimer_s.h create mode 100644 apps/plugins/sdl/src/timer/nds/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/os2/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/riscos/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/symbian/SDL_systimer.cpp create mode 100644 apps/plugins/sdl/src/timer/unix/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/win32/SDL_systimer.c create mode 100644 apps/plugins/sdl/src/timer/wince/SDL_systimer.c (limited to 'apps/plugins/sdl/src/timer') diff --git a/apps/plugins/sdl/src/timer/SDL_systimer.h b/apps/plugins/sdl/src/timer/SDL_systimer.h new file mode 100644 index 0000000000..d19b67987f --- /dev/null +++ b/apps/plugins/sdl/src/timer/SDL_systimer.h @@ -0,0 +1,40 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* The system dependent timer handling functions */ + +#include "SDL_timer.h" +#include "SDL_timer_c.h" + + +/* Initialize the system dependent timer subsystem */ +extern int SDL_SYS_TimerInit(void); + +/* Quit the system dependent timer subsystem */ +extern void SDL_SYS_TimerQuit(void); + +/* Start a timer set up by SDL_SetTimer() */ +extern int SDL_SYS_StartTimer(void); + +/* Stop a previously started timer */ +extern void SDL_SYS_StopTimer(void); diff --git a/apps/plugins/sdl/src/timer/SDL_timer.c b/apps/plugins/sdl/src/timer/SDL_timer.c new file mode 100644 index 0000000000..8d137e1a70 --- /dev/null +++ b/apps/plugins/sdl/src/timer/SDL_timer.c @@ -0,0 +1,285 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#include "SDL_timer.h" +#include "SDL_timer_c.h" +#include "SDL_mutex.h" +#include "SDL_systimer.h" + +/* #define DEBUG_TIMERS */ + +int SDL_timer_started = 0; +int SDL_timer_running = 0; + +/* Data to handle a single periodic alarm */ +Uint32 SDL_alarm_interval = 0; +SDL_TimerCallback SDL_alarm_callback; + +/* Data used for a thread-based timer */ +static int SDL_timer_threaded = 0; + +struct _SDL_TimerID { + Uint32 interval; + SDL_NewTimerCallback cb; + void *param; + Uint32 last_alarm; + struct _SDL_TimerID *next; +}; + +static SDL_TimerID SDL_timers = NULL; +static SDL_mutex *SDL_timer_mutex; +static volatile SDL_bool list_changed = SDL_FALSE; + +/* Set whether or not the timer should use a thread. + This should not be called while the timer subsystem is running. +*/ +int SDL_SetTimerThreaded(int value) +{ + int retval; + + if ( SDL_timer_started ) { + SDL_SetError("Timer already initialized"); + retval = -1; + } else { + retval = 0; + SDL_timer_threaded = value; + } + return retval; +} + +int SDL_TimerInit(void) +{ + int retval; + + retval = 0; + if ( SDL_timer_started ) { + SDL_TimerQuit(); + } + if ( ! SDL_timer_threaded ) { + retval = SDL_SYS_TimerInit(); + } + if ( SDL_timer_threaded ) { + SDL_timer_mutex = SDL_CreateMutex(); + } + if ( retval == 0 ) { + SDL_timer_started = 1; + } + return(retval); +} + +void SDL_TimerQuit(void) +{ + SDL_SetTimer(0, NULL); + if ( SDL_timer_threaded < 2 ) { + SDL_SYS_TimerQuit(); + } + if ( SDL_timer_threaded ) { + SDL_DestroyMutex(SDL_timer_mutex); + SDL_timer_mutex = NULL; + } + SDL_timer_started = 0; + SDL_timer_threaded = 0; +} + +void SDL_ThreadedTimerCheck(void) +{ + Uint32 now, ms; + SDL_TimerID t, prev, next; + SDL_bool removed; + + SDL_mutexP(SDL_timer_mutex); + list_changed = SDL_FALSE; + now = SDL_GetTicks(); + for ( prev = NULL, t = SDL_timers; t; t = next ) { + removed = SDL_FALSE; + ms = t->interval - SDL_TIMESLICE; + next = t->next; + if ( (int)(now - t->last_alarm) > (int)ms ) { + struct _SDL_TimerID timer; + + if ( (now - t->last_alarm) < t->interval ) { + t->last_alarm += t->interval; + } else { + t->last_alarm = now; + } +#ifdef DEBUG_TIMERS + printf("Executing timer %p (thread = %d)\n", + t, SDL_ThreadID()); +#endif + timer = *t; + SDL_mutexV(SDL_timer_mutex); + ms = timer.cb(timer.interval, timer.param); + SDL_mutexP(SDL_timer_mutex); + if ( list_changed ) { + /* Abort, list of timers modified */ + /* FIXME: what if ms was changed? */ + break; + } + if ( ms != t->interval ) { + if ( ms ) { + t->interval = ROUND_RESOLUTION(ms); + } else { + /* Remove timer from the list */ +#ifdef DEBUG_TIMERS + printf("SDL: Removing timer %p\n", t); +#endif + if ( prev ) { + prev->next = next; + } else { + SDL_timers = next; + } + SDL_free(t); + --SDL_timer_running; + removed = SDL_TRUE; + } + } + } + /* Don't update prev if the timer has disappeared */ + if ( ! removed ) { + prev = t; + } + } + SDL_mutexV(SDL_timer_mutex); +} + +static SDL_TimerID SDL_AddTimerInternal(Uint32 interval, SDL_NewTimerCallback callback, void *param) +{ + SDL_TimerID t; + t = (SDL_TimerID) SDL_malloc(sizeof(struct _SDL_TimerID)); + if ( t ) { + t->interval = ROUND_RESOLUTION(interval); + t->cb = callback; + t->param = param; + t->last_alarm = SDL_GetTicks(); + t->next = SDL_timers; + SDL_timers = t; + ++SDL_timer_running; + list_changed = SDL_TRUE; + } +#ifdef DEBUG_TIMERS + printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32)t, SDL_timer_running); +#endif + return t; +} + +SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param) +{ + SDL_TimerID t; + if ( ! SDL_timer_mutex ) { + if ( SDL_timer_started ) { + SDL_SetError("This platform doesn't support multiple timers"); + } else { + SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first"); + } + return NULL; + } + if ( ! SDL_timer_threaded ) { + SDL_SetError("Multiple timers require threaded events!"); + return NULL; + } + SDL_mutexP(SDL_timer_mutex); + t = SDL_AddTimerInternal(interval, callback, param); + SDL_mutexV(SDL_timer_mutex); + return t; +} + +SDL_bool SDL_RemoveTimer(SDL_TimerID id) +{ + SDL_TimerID t, prev = NULL; + SDL_bool removed; + + removed = SDL_FALSE; + SDL_mutexP(SDL_timer_mutex); + /* Look for id in the linked list of timers */ + for (t = SDL_timers; t; prev=t, t = t->next ) { + if ( t == id ) { + if(prev) { + prev->next = t->next; + } else { + SDL_timers = t->next; + } + SDL_free(t); + --SDL_timer_running; + removed = SDL_TRUE; + list_changed = SDL_TRUE; + break; + } + } +#ifdef DEBUG_TIMERS + printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, SDL_timer_running, SDL_ThreadID()); +#endif + SDL_mutexV(SDL_timer_mutex); + return removed; +} + +/* Old style callback functions are wrapped through this */ +static Uint32 SDLCALL callback_wrapper(Uint32 ms, void *param) +{ + SDL_TimerCallback func = (SDL_TimerCallback) param; + return (*func)(ms); +} + +int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback) +{ + int retval; + +#ifdef DEBUG_TIMERS + printf("SDL_SetTimer(%d)\n", ms); +#endif + retval = 0; + + if ( SDL_timer_threaded ) { + SDL_mutexP(SDL_timer_mutex); + } + if ( SDL_timer_running ) { /* Stop any currently running timer */ + if ( SDL_timer_threaded ) { + while ( SDL_timers ) { + SDL_TimerID freeme = SDL_timers; + SDL_timers = SDL_timers->next; + SDL_free(freeme); + } + SDL_timer_running = 0; + list_changed = SDL_TRUE; + } else { + SDL_SYS_StopTimer(); + SDL_timer_running = 0; + } + } + if ( ms ) { + if ( SDL_timer_threaded ) { + if ( SDL_AddTimerInternal(ms, callback_wrapper, (void *)callback) == NULL ) { + retval = -1; + } + } else { + SDL_timer_running = 1; + SDL_alarm_interval = ms; + SDL_alarm_callback = callback; + retval = SDL_SYS_StartTimer(); + } + } + if ( SDL_timer_threaded ) { + SDL_mutexV(SDL_timer_mutex); + } + + return retval; +} diff --git a/apps/plugins/sdl/src/timer/SDL_timer_c.h b/apps/plugins/sdl/src/timer/SDL_timer_c.h new file mode 100644 index 0000000000..96181081bb --- /dev/null +++ b/apps/plugins/sdl/src/timer/SDL_timer_c.h @@ -0,0 +1,46 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* Useful functions and variables from SDL_timer.c */ +#include "SDL_timer.h" + +#define ROUND_RESOLUTION(X) \ + (((X+TIMER_RESOLUTION-1)/TIMER_RESOLUTION)*TIMER_RESOLUTION) + +extern int SDL_timer_started; +extern int SDL_timer_running; + +/* Data to handle a single periodic alarm */ +extern Uint32 SDL_alarm_interval; +extern SDL_TimerCallback SDL_alarm_callback; + +/* Set whether or not the timer should use a thread. + This should be called while the timer subsystem is running. +*/ +extern int SDL_SetTimerThreaded(int value); + +extern int SDL_TimerInit(void); +extern void SDL_TimerQuit(void); + +/* This function is called from the SDL event thread if it is available */ +extern void SDL_ThreadedTimerCheck(void); diff --git a/apps/plugins/sdl/src/timer/beos/SDL_systimer.c b/apps/plugins/sdl/src/timer/beos/SDL_systimer.c new file mode 100644 index 0000000000..f4cf6c765e --- /dev/null +++ b/apps/plugins/sdl/src/timer/beos/SDL_systimer.c @@ -0,0 +1,95 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_BEOS + +#include + +#include "SDL_thread.h" +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +static bigtime_t start; + +void SDL_StartTicks(void) +{ + /* Set first ticks value */ + start = system_time(); +} + +Uint32 SDL_GetTicks(void) +{ + return((system_time()-start)/1000); +} + +void SDL_Delay(Uint32 ms) +{ + snooze(ms*1000); +} + +/* Data to handle a single periodic alarm */ +static int timer_alive = 0; +static SDL_Thread *timer = NULL; + +static int RunTimer(void *unused) +{ + while ( timer_alive ) { + if ( SDL_timer_running ) { + SDL_ThreadedTimerCheck(); + } + SDL_Delay(10); + } + return(0); +} + +/* This is only called if the event thread is not running */ +int SDL_SYS_TimerInit(void) +{ + timer_alive = 1; + timer = SDL_CreateThread(RunTimer, NULL); + if ( timer == NULL ) + return(-1); + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + timer_alive = 0; + if ( timer ) { + SDL_WaitThread(timer, NULL); + timer = NULL; + } +} + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: BeOS uses threaded timer"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* SDL_TIMER_BEOS */ diff --git a/apps/plugins/sdl/src/timer/dc/SDL_systimer.c b/apps/plugins/sdl/src/timer/dc/SDL_systimer.c new file mode 100644 index 0000000000..386e158607 --- /dev/null +++ b/apps/plugins/sdl/src/timer/dc/SDL_systimer.c @@ -0,0 +1,100 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_DC + +#include + +#include "SDL_thread.h" +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +static unsigned start; + +/* + jif = ms * HZ /1000 + ms = jif * 1000/HZ +*/ + +void SDL_StartTicks(void) +{ + /* Set first ticks value */ + start = jiffies; +} + +Uint32 SDL_GetTicks(void) +{ + return((jiffies-start)*1000/HZ); +} + +void SDL_Delay(Uint32 ms) +{ + thd_sleep(ms); +} + +/* Data to handle a single periodic alarm */ +static int timer_alive = 0; +static SDL_Thread *timer = NULL; + +static int RunTimer(void *unused) +{ + while ( timer_alive ) { + if ( SDL_timer_running ) { + SDL_ThreadedTimerCheck(); + } + SDL_Delay(10); + } + return(0); +} + +/* This is only called if the event thread is not running */ +int SDL_SYS_TimerInit(void) +{ + timer_alive = 1; + timer = SDL_CreateThread(RunTimer, NULL); + if ( timer == NULL ) + return(-1); + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + timer_alive = 0; + if ( timer ) { + SDL_WaitThread(timer, NULL); + timer = NULL; + } +} + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: DC uses threaded timer"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* SDL_TIMER_DC */ diff --git a/apps/plugins/sdl/src/timer/dummy/SDL_systimer.c b/apps/plugins/sdl/src/timer/dummy/SDL_systimer.c new file mode 100644 index 0000000000..cc266bc9a5 --- /dev/null +++ b/apps/plugins/sdl/src/timer/dummy/SDL_systimer.c @@ -0,0 +1,91 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#if defined(SDL_TIMER_DUMMY) || defined(SDL_TIMERS_DISABLED) + +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +void SDL_StartTicks(void) +{ +} + +Uint32 SDL_GetTicks (void) +{ + SDL_Unsupported(); + return 0; +} + +void SDL_Delay (Uint32 ms) +{ + SDL_Unsupported(); +} + +#include "SDL_thread.h" + +/* Data to handle a single periodic alarm */ +static int timer_alive = 0; +static SDL_Thread *timer = NULL; + +static int RunTimer(void *unused) +{ + while ( timer_alive ) { + if ( SDL_timer_running ) { + SDL_ThreadedTimerCheck(); + } + SDL_Delay(1); + } + return(0); +} + +/* This is only called if the event thread is not running */ +int SDL_SYS_TimerInit(void) +{ + timer_alive = 1; + timer = SDL_CreateThread(RunTimer, NULL); + if ( timer == NULL ) + return(-1); + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + timer_alive = 0; + if ( timer ) { + SDL_WaitThread(timer, NULL); + timer = NULL; + } +} + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: threaded timer in use"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* SDL_TIMER_DUMMY || SDL_TIMERS_DISABLED */ diff --git a/apps/plugins/sdl/src/timer/macos/FastTimes.c b/apps/plugins/sdl/src/timer/macos/FastTimes.c new file mode 100644 index 0000000000..2da74b7d18 --- /dev/null +++ b/apps/plugins/sdl/src/timer/macos/FastTimes.c @@ -0,0 +1,352 @@ +/* File "FastTimes.c" - Original code by Matt Slot */ +/* Created 4/24/99 - This file is hereby placed in the public domain */ +/* Updated 5/21/99 - Calibrate to VIA, add TBR support, renamed functions */ +/* Updated 10/4/99 - Use AbsoluteToNanoseconds() in case Absolute = double */ +/* Updated 2/15/00 - Check for native Time Manager, no need to calibrate */ +/* Updated 2/19/00 - Fixed default value for gScale under native Time Mgr */ +/* Updated 3/21/00 - Fixed ns conversion, create 2 different scale factors */ +/* Updated 5/03/00 - Added copyright and placed into PD. No code changes */ +/* Updated 8/01/00 - Made "Carbon-compatible" by replacing LMGetTicks() */ + +/* This file is Copyright (C) Matt Slot, 1999-2012. It is hereby placed into + the public domain. The author makes no warranty as to fitness or stability */ + +#include +#include +#include +#include +#include + +#include "FastTimes.h" + +#ifdef TARGET_CPU_PPC +#undef GENERATINGPOWERPC /* stop whining */ +#define GENERATINGPOWERPC TARGET_CPU_PPC +#endif + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* + On 680x0 machines, we just use Microseconds(). + + On PowerPC machines, we try several methods: + * DriverServicesLib is available on all PCI PowerMacs, and perhaps + some NuBus PowerMacs. If it is, we use UpTime() : Overhead = 2.1 µsec. + * The PowerPC 601 has a built-in "real time clock" RTC, and we fall + back to that, accessing it directly from asm. Overhead = 1.3 µsec. + * Later PowerPCs have an accurate "time base register" TBR, and we + fall back to that, access it from PowerPC asm. Overhead = 1.3 µsec. + * We can also try Microseconds() which is emulated : Overhead = 36 µsec. + + On PowerPC machines, we avoid the following: + * OpenTransport is available on all PCI and some NuBus PowerMacs, but it + uses UpTime() if available and falls back to Microseconds() otherwise. + * InputSprocket is available on many PowerMacs, but again it uses + UpTime() if available and falls back to Microseconds() otherwise. + + Another PowerPC note: certain configurations, especially 3rd party upgrade + cards, may return inaccurate timings for the CPU or memory bus -- causing + skew in various system routines (up to 20% drift!). The VIA chip is very + accurate, and it's the basis for the Time Manager and Microseconds(). + Unfortunately, it's also very slow because the MacOS has to (a) switch to + 68K and (b) poll for a VIA event. + + We compensate for the drift by calibrating a floating point scale factor + between our fast method and the accurate timer at startup, then convert + each sample quickly on the fly. I'd rather not have the initialization + overhead -- but it's simply necessary for accurate timing. You can drop + it down to 30 ticks if you prefer, but that's as low as I'd recommend. + + Under MacOS 9, "new world" Macs (iMacs, B+W G3s and G+W G4s) have a native + Time Manager implementation: UpTime(), Microseconds(), and TickCount() are + all based on the same underlying counter. This makes it silly to calibrate + UpTime() against TickCount(). We now check for this feature using Gestalt(), + and skip the whole calibration step if possible. + +*/ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +#define RTCToNano(w) ((double) (w).hi * 1000000000.0 + (double) (w).lo) +#define WideTo64bit(w) (*(UInt64 *) &(w)) + +/* LMGetTicks() is not in Carbon and TickCount() has a fair bit of overhead, + so for speed we always read lowmem directly. This is a Mac OS X no-no, but + it always work on those systems that don't have a native Time Manager (ie, + anything before MacOS 9) -- regardless whether we are in Carbon or not! */ +#define MyLMGetTicks() (*(volatile UInt32 *) 0x16A) + +#if GENERATINGPOWERPC + +static asm UnsignedWide PollRTC(void); +static asm UnsignedWide PollTBR(void); +static Ptr FindFunctionInSharedLib(StringPtr libName, StringPtr funcName); + +static Boolean gInited = false; +static Boolean gNative = false; +static Boolean gUseRTC = false; +static Boolean gUseTBR = false; +static double gScaleUSec = 1.0 / 1000.0; /* 1 / ( nsec / usec) */ +static double gScaleMSec = 1.0 / 1000000.0; /* 1 / ( nsec / msec) */ + +/* Functions loaded from DriverServicesLib */ +typedef AbsoluteTime (*UpTimeProcPtr)(void); +typedef Nanoseconds (*A2NSProcPtr)(AbsoluteTime); +static UpTimeProcPtr gUpTime = NULL; +static A2NSProcPtr gA2NS = NULL; + +#endif /* GENERATINGPOWERPC */ + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +void FastInitialize() { + SInt32 result; + + if (!gInited) { + +#if GENERATINGPOWERPC + + /* Initialize the feature flags */ + gNative = gUseRTC = gUseTBR = false; + + /* We use CFM to find and load needed symbols from shared libraries, so + the application doesn't have to weak-link them, for convenience. */ + gUpTime = (UpTimeProcPtr) FindFunctionInSharedLib( + "\pDriverServicesLib", "\pUpTime"); + if (gUpTime) gA2NS = (A2NSProcPtr) FindFunctionInSharedLib( + "\pDriverServicesLib", "\pAbsoluteToNanoseconds"); + if (!gA2NS) gUpTime = nil; /* Pedantic but necessary */ + + if (gUpTime) { + /* If we loaded UpTime(), then we need to know if the system has + a native implementation of the Time Manager. If so, then it's + pointless to calculate a scale factor against the missing VIA */ + + /* gestaltNativeTimeMgr = 4 in some future version of the headers */ + if (!Gestalt(gestaltTimeMgrVersion, &result) && + (result > gestaltExtendedTimeMgr)) + gNative = true; + } + else { + /* If no DriverServicesLib, use Gestalt() to get the processor type. + Only NuBus PowerMacs with old System Software won't have DSL, so + we know it should either be a 601 or 603. */ + + /* Use the processor gestalt to determine which register to use */ + if (!Gestalt(gestaltNativeCPUtype, &result)) { + if (result == gestaltCPU601) gUseRTC = true; + else if (result > gestaltCPU601) gUseTBR = true; + } + } + + /* Now calculate a scale factor to keep us accurate. */ + if ((gUpTime && !gNative) || gUseRTC || gUseTBR) { + UInt64 tick, usec1, usec2; + UnsignedWide wide; + + /* Wait for the beginning of the very next tick */ + for(tick = MyLMGetTicks() + 1; tick > MyLMGetTicks(); ); + + /* Poll the selected timer and prepare it (since we have time) */ + wide = (gUpTime) ? (*gA2NS)((*gUpTime)()) : + ((gUseRTC) ? PollRTC() : PollTBR()); + usec1 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide); + + /* Wait for the exact 60th tick to roll over */ + while(tick + 60 > MyLMGetTicks()); + + /* Poll the selected timer again and prepare it */ + wide = (gUpTime) ? (*gA2NS)((*gUpTime)()) : + ((gUseRTC) ? PollRTC() : PollTBR()); + usec2 = (gUseRTC) ? RTCToNano(wide) : WideTo64bit(wide); + + /* Calculate a scale value that will give microseconds per second. + Remember, there are actually 60.15 ticks in a second, not 60. */ + gScaleUSec = (60.0 * 1000000.0) / ((usec2 - usec1) * 60.15); + gScaleMSec = gScaleUSec / 1000.0; + } + +#endif /* GENERATINGPOWERPC */ + + /* We've initialized our globals */ + gInited = true; + } + } + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +UInt64 FastMicroseconds() { + UnsignedWide wide; + UInt64 usec; + +#if GENERATINGPOWERPC + /* Initialize globals the first time we are called */ + if (!gInited) FastInitialize(); + + if (gNative) { + /* Use DriverServices if it's available -- it's fast and compatible */ + wide = (*gA2NS)((*gUpTime)()); + usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5; + } + else if (gUpTime) { + /* Use DriverServices if it's available -- it's fast and compatible */ + wide = (*gA2NS)((*gUpTime)()); + usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5; + } + else if (gUseTBR) { + /* On a recent PowerPC, we poll the TBR directly */ + wide = PollTBR(); + usec = (double) WideTo64bit(wide) * gScaleUSec + 0.5; + } + else if (gUseRTC) { + /* On a 601, we can poll the RTC instead */ + wide = PollRTC(); + usec = (double) RTCToNano(wide) * gScaleUSec + 0.5; + } + else +#endif /* GENERATINGPOWERPC */ + { + /* If all else fails, suffer the mixed mode overhead */ + Microseconds(&wide); + usec = WideTo64bit(wide); + } + + return(usec); + } + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +UInt64 FastMilliseconds() { + UnsignedWide wide; + UInt64 msec; + +#if GENERATINGPOWERPC + /* Initialize globals the first time we are called */ + if (!gInited) FastInitialize(); + + if (gNative) { + /* Use DriverServices if it's available -- it's fast and compatible */ + wide = (*gA2NS)((*gUpTime)()); + msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5; + } + else if (gUpTime) { + /* Use DriverServices if it's available -- it's fast and compatible */ + wide = (*gA2NS)((*gUpTime)()); + msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5; + } + else if (gUseTBR) { + /* On a recent PowerPC, we poll the TBR directly */ + wide = PollTBR(); + msec = (double) WideTo64bit(wide) * gScaleMSec + 0.5; + } + else if (gUseRTC) { + /* On a 601, we can poll the RTC instead */ + wide = PollRTC(); + msec = (double) RTCToNano(wide) * gScaleMSec + 0.5; + } + else +#endif /* GENERATINGPOWERPC */ + { + /* If all else fails, suffer the mixed mode overhead */ + Microseconds(&wide); + msec = ((double) WideTo64bit(wide) + 500.0) / 1000.0; + } + + return(msec); + } + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +StringPtr FastMethod() { + StringPtr method = "\p"; + +#if GENERATINGPOWERPC + /* Initialize globals the first time we are called */ + if (!gInited) FastInitialize(); + + if (gNative) { + /* The Time Manager and UpTime() are entirely native on this machine */ + method = "\pNative UpTime()"; + } + else if (gUpTime) { + /* Use DriverServices if it's available -- it's fast and compatible */ + method = "\pUpTime()"; + } + else if (gUseTBR) { + /* On a recent PowerPC, we poll the TBR directly */ + method = "\pPowerPC TBR"; + } + else if (gUseRTC) { + /* On a 601, we can poll the RTC instead */ + method = "\pPowerPC RTC"; + } + else +#endif /* GENERATINGPOWERPC */ + { + /* If all else fails, suffer the mixed mode overhead */ + method = "\pMicroseconds()"; + } + + return(method); + } + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +#pragma mark - + +#if GENERATINGPOWERPC +asm static UnsignedWide PollRTC_() { +entry PollRTC /* Avoid CodeWarrior glue */ + machine 601 +@AGAIN: + mfrtcu r4 /* RTCU = SPR 4 */ + mfrtcl r5 /* RTCL = SPR 5 */ + mfrtcu r6 + cmpw r4,r6 + bne @AGAIN + stw r4,0(r3) + stw r5,4(r3) + blr + } + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +asm static UnsignedWide PollTBR_() { +entry PollTBR /* Avoid CodeWarrior glue */ + machine 604 +@AGAIN: + mftbu r4 /* TBRU = SPR 268 */ + mftb r5 /* TBRL = SPR 269 */ + mftbu r6 + cmpw r4,r6 + bne @AGAIN + stw r4,0(r3) + stw r5,4(r3) + blr + } + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +static Ptr FindFunctionInSharedLib(StringPtr libName, StringPtr funcName) { + OSErr error = noErr; + Str255 errorStr; + Ptr func = NULL; + Ptr entry = NULL; + CFragSymbolClass symClass; + CFragConnectionID connID; + + /* Find CFM containers for the current archecture -- CFM-PPC or CFM-68K */ + if (/* error = */ GetSharedLibrary(libName, kCompiledCFragArch, + kLoadCFrag, &connID, &entry, errorStr)) return(NULL); + if (/* error = */ FindSymbol(connID, funcName, &func, &symClass)) + return(NULL); + + return(func); + } +#endif /* GENERATINGPOWERPC */ diff --git a/apps/plugins/sdl/src/timer/macos/FastTimes.h b/apps/plugins/sdl/src/timer/macos/FastTimes.h new file mode 100644 index 0000000000..d25744c330 --- /dev/null +++ b/apps/plugins/sdl/src/timer/macos/FastTimes.h @@ -0,0 +1,27 @@ +/* File "FastTimes.h" - Original code by Matt Slot */ +#include "SDL_config.h" +/* Created 4/24/99 - This file is hereby placed in the public domain */ +/* Updated 5/21/99 - Calibrate to VIA, add TBR support, renamed functions */ +/* Updated 10/4/99 - Use AbsoluteToNanoseconds() in case Absolute = double */ +/* Updated 2/15/00 - Check for native Time Manager, no need to calibrate */ +/* Updated 3/21/00 - Fixed ns conversion, create 2 different scale factors */ +/* Updated 5/03/00 - Added copyright and placed into PD. No code changes */ + +/* This file is Copyright (C) Matt Slot, 1999-2012. It is hereby placed into + the public domain. The author makes no warranty as to fitness or stability */ + +#ifndef __FAST_TIMES_HEADER__ +#define __FAST_TIMES_HEADER__ + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +extern void FastInitialize(void); +extern UInt64 FastMicroseconds(void); +extern UInt64 FastMilliseconds(void); +extern StringPtr FastMethod(void); + +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ +/* **** **** **** **** **** **** **** **** **** **** **** **** **** **** **** */ + +#endif /* __FAST_TIMES_HEADER__ */ diff --git a/apps/plugins/sdl/src/timer/macos/SDL_MPWtimer.c b/apps/plugins/sdl/src/timer/macos/SDL_MPWtimer.c new file mode 100644 index 0000000000..114b6c7c0a --- /dev/null +++ b/apps/plugins/sdl/src/timer/macos/SDL_MPWtimer.c @@ -0,0 +1,152 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_MACOS + +#include +#include +#include +#include +#include + +#include + +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +#define MS_PER_TICK (1000/60) /* MacOS tick = 1/60 second */ + +/* Note: This is only a step above the original 1/60s implementation. + * For a good implementation, see FastTimes.[ch], by Matt Slot. + */ +#define USE_MICROSECONDS +#define WideTo64bit(w) (*(UInt64 *) &(w)) + +UInt64 start; + +void SDL_StartTicks(void) +{ +#ifdef USE_MICROSECONDS + UnsignedWide now; + + Microseconds(&now); + start = WideTo64bit(now); +#else + /* FIXME: Should we implement a wrapping algorithm, like Win32? */ +#endif +} + +Uint32 SDL_GetTicks(void) +{ +#ifdef USE_MICROSECONDS + UnsignedWide now; + + Microseconds(&now); + return (Uint32)((WideTo64bit(now)-start)/1000); +#else + return(LMGetTicks()*MS_PER_TICK); +#endif +} + +void SDL_Delay(Uint32 ms) +{ +#ifdef USE_MICROSECONDS + Uint32 end_ms; + + end_ms = SDL_GetTicks() + ms; + do { + /* FIXME: Yield CPU? */ ; + } while ( SDL_GetTicks() < end_ms ); +#else + UInt32 unused; /* MJS */ + Delay(ms/MS_PER_TICK, &unused); +#endif +} + + +/* Data to handle a single periodic alarm */ +typedef struct _ExtendedTimerRec +{ + TMTask tmTask; + ProcessSerialNumber taskPSN; +} ExtendedTimerRec, *ExtendedTimerPtr; + +static ExtendedTimerRec gExtendedTimerRec; + + +int SDL_SYS_TimerInit(void) +{ + /* We don't need a setup? */ + return(0); +} + +void SDL_SYS_TimerQuit(void) +{ + /* We don't need a cleanup? */ + return; +} + +/* Our Stub routine to set up and then call the real routine. */ +pascal void TimerCallbackProc(TMTaskPtr tmTaskPtr) +{ + Uint32 ms; + + WakeUpProcess(&((ExtendedTimerPtr) tmTaskPtr)->taskPSN); + + ms = SDL_alarm_callback(SDL_alarm_interval); + if ( ms ) { + SDL_alarm_interval = ROUND_RESOLUTION(ms); + PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask, + SDL_alarm_interval); + } else { + SDL_alarm_interval = 0; + } +} + +int SDL_SYS_StartTimer(void) +{ + /* + * Configure the global structure that stores the timing information. + */ + gExtendedTimerRec.tmTask.qLink = NULL; + gExtendedTimerRec.tmTask.qType = 0; + gExtendedTimerRec.tmTask.tmAddr = NewTimerUPP(TimerCallbackProc); + gExtendedTimerRec.tmTask.tmCount = 0; + gExtendedTimerRec.tmTask.tmWakeUp = 0; + gExtendedTimerRec.tmTask.tmReserved = 0; + GetCurrentProcess(&gExtendedTimerRec.taskPSN); + + /* Install the task record */ + InsXTime((QElemPtr)&gExtendedTimerRec.tmTask); + + /* Go! */ + PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask, SDL_alarm_interval); + return(0); +} + +void SDL_SYS_StopTimer(void) +{ + RmvTime((QElemPtr)&gExtendedTimerRec.tmTask); +} + +#endif /* SDL_TIMER_MACOS */ diff --git a/apps/plugins/sdl/src/timer/macos/SDL_systimer.c b/apps/plugins/sdl/src/timer/macos/SDL_systimer.c new file mode 100644 index 0000000000..7a8063e57d --- /dev/null +++ b/apps/plugins/sdl/src/timer/macos/SDL_systimer.c @@ -0,0 +1,186 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_MACOS + +#include +#include +#include +#include +#include + +#include + +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +#include "FastTimes.h" + +#if TARGET_API_MAC_CARBON +#define NewTimerProc NewTimerUPP +#endif + +#define MS_PER_TICK (1000.0/60.0) /* MacOS tick = 1/60 second */ + + +#define kTwoPower32 (4294967296.0) /* 2^32 */ + +static double start_tick; +static int is_fast_inited = 0; + +void SDL_StartTicks(void) +{ + if ( ! is_fast_inited ) // important to check or FastTime may hang machine! + SDL_SYS_TimerInit(); + + start_tick = FastMicroseconds(); +} + +Uint32 SDL_GetTicks(void) +{ + + if ( ! is_fast_inited ) + SDL_SYS_TimerInit(); + + return FastMilliseconds(); +} + +void SDL_Delay(Uint32 ms) +{ + Uint32 stop, now; + + stop = SDL_GetTicks() + ms; + do { + #if TARGET_API_MAC_CARBON + MPYield(); + #else + SystemTask(); + #endif + + now = SDL_GetTicks(); + + } while ( stop > now ); +} + +/* +void SDL_StartTicks(void) +{ + // FIXME: Should we implement a wrapping algorithm, like Win32? +} + +Uint32 SDL_GetTicks(void) +{ + UnsignedWide ms; + + Microseconds (&ms); + + return ( ms.lo / 1000 ); +} + +void SDL_Delay(Uint32 ms) +{ + + UnsignedWide microsecs; + UInt32 stop; + + Microseconds (µsecs); + + stop = microsecs.lo + (ms * 1000); + + while ( stop > microsecs.lo ) { + + SystemTask (); + + Microseconds (µsecs); + } + +}*/ + +/* Data to handle a single periodic alarm */ +typedef struct _ExtendedTimerRec +{ + TMTask tmTask; + ProcessSerialNumber taskPSN; +} ExtendedTimerRec, *ExtendedTimerPtr; + +static ExtendedTimerRec gExtendedTimerRec; + + +int SDL_SYS_TimerInit(void) +{ + FastInitialize (); + is_fast_inited = 1; + + return(0); +} + +void SDL_SYS_TimerQuit(void) +{ + /* We don't need a cleanup? */ + return; +} + +/* Our Stub routine to set up and then call the real routine. */ +pascal void TimerCallbackProc(TMTaskPtr tmTaskPtr) +{ + Uint32 ms; + + WakeUpProcess(&((ExtendedTimerPtr) tmTaskPtr)->taskPSN); + + ms = SDL_alarm_callback(SDL_alarm_interval); + if ( ms ) { + SDL_alarm_interval = ROUND_RESOLUTION(ms); + PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask, + SDL_alarm_interval); + } else { + SDL_alarm_interval = 0; + } +} + +int SDL_SYS_StartTimer(void) +{ + /* + * Configure the global structure that stores the timing information. + */ + gExtendedTimerRec.tmTask.qLink = NULL; + gExtendedTimerRec.tmTask.qType = 0; + gExtendedTimerRec.tmTask.tmAddr = NewTimerProc(TimerCallbackProc); + gExtendedTimerRec.tmTask.tmCount = 0; + gExtendedTimerRec.tmTask.tmWakeUp = 0; + gExtendedTimerRec.tmTask.tmReserved = 0; + GetCurrentProcess(&gExtendedTimerRec.taskPSN); + + /* Install the task record */ + InsXTime((QElemPtr)&gExtendedTimerRec.tmTask); + + /* Go! */ + PrimeTime((QElemPtr)&gExtendedTimerRec.tmTask, SDL_alarm_interval); + return(0); +} + +void SDL_SYS_StopTimer(void) +{ + RmvTime((QElemPtr)&gExtendedTimerRec.tmTask); +} + +#endif /* SDL_TIMER_MACOS */ diff --git a/apps/plugins/sdl/src/timer/mint/SDL_systimer.c b/apps/plugins/sdl/src/timer/mint/SDL_systimer.c new file mode 100644 index 0000000000..01e7a410c1 --- /dev/null +++ b/apps/plugins/sdl/src/timer/mint/SDL_systimer.c @@ -0,0 +1,149 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_MINT + +/* + * TOS/MiNT timer driver + * based on vbl vector + * + * Patrice Mandin + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "SDL_timer.h" +#include "../SDL_timer_c.h" +#include "SDL_thread.h" + +#include "../../video/ataricommon/SDL_atarisuper.h" + +#include "SDL_vbltimer_s.h" + +/* from audio/mint */ +void SDL_MintAudio_CheckFpu(void); + +/* The first ticks value of the application */ +static Uint32 start; +static SDL_bool read_hz200_from_vbl = SDL_FALSE; +static int mint_present; /* can we use Syield() ? */ + +void SDL_StartTicks(void) +{ + void *old_stack; + long dummy; + + /* Set first ticks value */ + old_stack = (void *)Super(0); + start = *((volatile long *)_hz_200); + SuperToUser(old_stack); + + start *= 5; /* One _hz_200 tic is 5ms */ + + mint_present = (Getcookie(C_MiNT, &dummy) == C_FOUND); +} + +Uint32 SDL_GetTicks (void) +{ + Uint32 now = start; + + if (read_hz200_from_vbl) { + now = SDL_Atari_hz200; + } else { + void *old_stack = (void *)Super(0); + now = *((volatile long *)_hz_200); + SuperToUser(old_stack); + } + + return((now*5)-start); +} + +void SDL_Delay (Uint32 ms) +{ + Uint32 now; + + now = SDL_GetTicks(); + while ((SDL_GetTicks()-now) + +#define timers2ms(tlow,thigh)(tlow | (thigh<<16)) >> 5 + + +void SDL_StartTicks(void) +{ + TIMER0_DATA=0; + TIMER1_DATA=0; + TIMER0_CR=TIMER_ENABLE|TIMER_DIV_1024; + TIMER1_CR=TIMER_ENABLE|TIMER_CASCADE; +} + +Uint32 SDL_GetTicks(void) +{ + return timers2ms(TIMER0_DATA, TIMER1_DATA); +} + +void SDL_Delay(Uint32 ms) +{ + Uint32 now; + now=timers2ms(TIMER0_DATA, TIMER1_DATA); + while((Uint32)timers2ms(TIMER0_DATA, TIMER1_DATA) + +#include "SDL_thread.h" +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + + +#define TIME_WRAP_VALUE (~(DWORD)0) + +/* The first high-resolution ticks value of the application */ +static long long hires_start_ticks; +/* The number of ticks per second of the high-resolution performance counter */ +static ULONG hires_ticks_per_second; + +void SDL_StartTicks(void) +{ + DosTmrQueryFreq(&hires_ticks_per_second); + DosTmrQueryTime((PQWORD)&hires_start_ticks); +} + +DECLSPEC Uint32 SDLCALL SDL_GetTicks(void) +{ + long long hires_now; + ULONG ticks = ticks; + + DosTmrQueryTime((PQWORD)&hires_now); +/* + hires_now -= hires_start_ticks; + hires_now *= 1000; + hires_now /= hires_ticks_per_second; +*/ + /* inline asm to avoid runtime inclusion */ + _asm { + push edx + push eax + mov eax, dword ptr hires_now + mov edx, dword ptr hires_now+4 + sub eax, dword ptr hires_start_ticks + sbb edx, dword ptr hires_start_ticks+4 + mov ebx,1000 + mov ecx,edx + mul ebx + push eax + push edx + mov eax,ecx + mul ebx + pop eax + add edx,eax + pop eax + mov ebx, dword ptr hires_ticks_per_second + div ebx + mov dword ptr ticks, eax + pop edx + pop eax + } + + return ticks; + +} + +/* High resolution sleep, originally made by Ilya Zakharevich */ +DECLSPEC void SDLCALL SDL_Delay(Uint32 ms) +{ + /* This is similar to DosSleep(), but has 8ms granularity in time-critical + threads even on Warp3. */ + HEV hevEvent1 = 0; /* Event semaphore handle */ + HTIMER htimerEvent1 = 0; /* Timer handle */ + APIRET rc = NO_ERROR; /* Return code */ + int ret = 1; + ULONG priority = 0, nesting; /* Shut down the warnings */ + PPIB pib; + PTIB tib; + char *e = NULL; + APIRET badrc; + int switch_priority = 50; + + DosCreateEventSem(NULL, /* Unnamed */ + &hevEvent1, /* Handle of semaphore returned */ + DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */ + FALSE); /* Semaphore is in RESET state */ + + if (ms >= switch_priority) + switch_priority = 0; + if (switch_priority) + { + if (DosGetInfoBlocks(&tib, &pib)!=NO_ERROR) + switch_priority = 0; + else + { + /* In Warp3, to switch scheduling to 8ms step, one needs to do + DosAsyncTimer() in time-critical thread. On laters versions, + more and more cases of wait-for-something are covered. + + It turns out that on Warp3fp42 it is the priority at the time + of DosAsyncTimer() which matters. Let's hope that this works + with later versions too... XXXX + */ + priority = (tib->tib_ptib2->tib2_ulpri); + if ((priority & 0xFF00) == 0x0300) /* already time-critical */ + switch_priority = 0; + /* Make us time-critical. Just modifying TIB is not enough... */ + /* tib->tib_ptib2->tib2_ulpri = 0x0300;*/ + /* We do not want to run at high priority if a signal causes us + to longjmp() out of this section... */ + if (DosEnterMustComplete(&nesting)) + switch_priority = 0; + else + DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); + } + } + + if ((badrc = DosAsyncTimer(ms, + (HSEM) hevEvent1, /* Semaphore to post */ + &htimerEvent1))) /* Timer handler (returned) */ + e = "DosAsyncTimer"; + + if (switch_priority && tib->tib_ptib2->tib2_ulpri == 0x0300) + { + /* Nobody switched priority while we slept... Ignore errors... */ + /* tib->tib_ptib2->tib2_ulpri = priority; */ /* Get back... */ + if (!(rc = DosSetPriority(PRTYS_THREAD, (priority>>8) & 0xFF, 0, 0))) + rc = DosSetPriority(PRTYS_THREAD, 0, priority & 0xFF, 0); + } + if (switch_priority) + rc = DosExitMustComplete(&nesting); /* Ignore errors */ + + /* The actual blocking call is made with "normal" priority. This way we + should not bother with DosSleep(0) etc. to compensate for us interrupting + higher-priority threads. The goal is to prohibit the system spending too + much time halt()ing, not to run us "no matter what". */ + if (!e) /* Wait for AsyncTimer event */ + badrc = DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT); + + if (e) ; /* Do nothing */ + else if (badrc == ERROR_INTERRUPT) + ret = 0; + else if (badrc) + e = "DosWaitEventSem"; + if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */ + e = "DosCloseEventSem"; + badrc = rc; + } + if (e) + { + SDL_SetError("[SDL_Delay] : Had error in %s(), rc is 0x%x\n", e, badrc); + } +} + +/* Data to handle a single periodic alarm */ +static int timer_alive = 0; +static SDL_Thread *timer = NULL; + +static int SDLCALL RunTimer(void *unused) +{ + DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0); + while ( timer_alive ) { + if ( SDL_timer_running ) { + SDL_ThreadedTimerCheck(); + } + SDL_Delay(10); + } + return(0); +} + +/* This is only called if the event thread is not running */ +int SDL_SYS_TimerInit(void) +{ + timer_alive = 1; + timer = SDL_CreateThread(RunTimer, NULL); + if ( timer == NULL ) + return(-1); + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + timer_alive = 0; + if ( timer ) { + SDL_WaitThread(timer, NULL); + timer = NULL; + } +} + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: OS/2 uses threaded timer"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* SDL_TIMER_OS2 */ diff --git a/apps/plugins/sdl/src/timer/riscos/SDL_systimer.c b/apps/plugins/sdl/src/timer/riscos/SDL_systimer.c new file mode 100644 index 0000000000..25ba65f784 --- /dev/null +++ b/apps/plugins/sdl/src/timer/riscos/SDL_systimer.c @@ -0,0 +1,233 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_RISCOS + +#include +#include +#include +#include +#include +#include + +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +#if SDL_THREADS_DISABLED +/* Timer SDL_arraysize(Timer ),start/reset time */ +static Uint32 timerStart; +/* Timer running function */ +void RISCOS_CheckTimer(); +#else +#include +extern Uint32 riscos_main_thread; +extern int riscos_using_threads; +extern Uint32 SDL_ThreadID(); +extern Uint32 SDL_EventThreadID(void); +#endif + + +extern void RISCOS_BackgroundTasks(void); + +/* The first ticks value of the application */ +clock_t start; + +void SDL_StartTicks(void) +{ + /* Set first ticks value */ + start = clock(); +} + +Uint32 SDL_GetTicks (void) +{ + clock_t ticks; + + ticks=clock()-start; + + +#if CLOCKS_PER_SEC == 1000 + + return(ticks); + +#elif CLOCKS_PER_SEC == 100 + + return (ticks * 10); + +#else + + return ticks*(1000/CLOCKS_PER_SEC); + +#endif + +} + +void SDL_Delay (Uint32 ms) +{ + Uint32 now,then,elapsed; +#if !SDL_THREADS_DISABLED + int is_event_thread; + if (riscos_using_threads) + { + is_event_thread = 0; + if (SDL_EventThreadID()) + { + if (SDL_EventThreadID() == SDL_ThreadID()) is_event_thread = 1; + } else if (SDL_ThreadID() == riscos_main_thread) is_event_thread = 1; + } else is_event_thread = 1; +#endif + + /*TODO: Next version of Unixlib may allow us to use usleep here */ + /* for non event threads */ + + /* Set the timeout interval - Linux only needs to do this once */ + then = SDL_GetTicks(); + + do { + /* Do background tasks required while sleeping as we are not multithreaded */ +#if SDL_THREADS_DISABLED + RISCOS_BackgroundTasks(); +#else + /* For threaded build only run background tasks in event thread */ + if (is_event_thread) RISCOS_BackgroundTasks(); +#endif + + /* Calculate the time interval left (in case of interrupt) */ + now = SDL_GetTicks(); + elapsed = (now-then); + then = now; + if ( elapsed >= ms ) { + break; + } + ms -= elapsed; +#if !SDL_THREADS_DISABLED + /* Need to yield to let other threads have a go */ + if (riscos_using_threads) pthread_yield(); +#endif + + } while ( 1 ); +} + +#if SDL_THREADS_DISABLED + +/* Non-threaded version of timer */ + +int SDL_SYS_TimerInit(void) +{ + return(0); +} + +void SDL_SYS_TimerQuit(void) +{ + SDL_SetTimer(0, NULL); +} + +int SDL_SYS_StartTimer(void) +{ + timerStart = SDL_GetTicks(); + + return(0); +} + +void SDL_SYS_StopTimer(void) +{ + /* Don't need to do anything as we use SDL_timer_running + to detect if we need to check the timer */ +} + + +void RISCOS_CheckTimer() +{ + if (SDL_timer_running && SDL_GetTicks() - timerStart >= SDL_alarm_interval) + { + Uint32 ms; + + ms = SDL_alarm_callback(SDL_alarm_interval); + if ( ms != SDL_alarm_interval ) + { + if ( ms ) + { + SDL_alarm_interval = ROUND_RESOLUTION(ms); + } else + { + SDL_alarm_interval = 0; + SDL_timer_running = 0; + } + } + if (SDL_alarm_interval) timerStart = SDL_GetTicks(); + } +} + +#else + +/* Threaded version of timer - based on code for linux */ + +#include "SDL_thread.h" + +/* Data to handle a single periodic alarm */ +static int timer_alive = 0; +static SDL_Thread *timer = NULL; + +static int RunTimer(void *unused) +{ + while ( timer_alive ) { + if ( SDL_timer_running ) { + SDL_ThreadedTimerCheck(); + } + SDL_Delay(1); + } + return(0); +} + +/* This is only called if the event thread is not running */ +int SDL_SYS_TimerInit(void) +{ + timer_alive = 1; + timer = SDL_CreateThread(RunTimer, NULL); + if ( timer == NULL ) + return(-1); + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + timer_alive = 0; + if ( timer ) { + SDL_WaitThread(timer, NULL); + timer = NULL; + } +} + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: RISC OS uses threaded timer"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* SDL_THREADS_DISABLED */ + +#endif /* SDL_TIMER_RISCOS */ diff --git a/apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c b/apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c new file mode 100644 index 0000000000..5769a87662 --- /dev/null +++ b/apps/plugins/sdl/src/timer/rockbox/SDL_systimer.c @@ -0,0 +1,117 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_ROCKBOX + +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +#include "plugin.h" + +#if defined(HAVE_LCD_COLOR) && !defined(SIMULATOR) && !defined(RB_PROFILE) +#define USE_TIMER +#endif + +/* based off doom */ +#ifdef USE_TIMER +static volatile unsigned int ticks = 0; + +static void sdltime(void) +{ + ticks++; +} +#else +static unsigned long start; +#endif + +void SDL_StartTicks(void) +{ +#ifdef USE_TIMER + rb->timer_register(1, NULL, TIMER_FREQ/1000, sdltime IF_COP(, CPU)); +#else + start = *rb->current_tick; +#endif +} + +Uint32 SDL_GetTicks (void) +{ +#ifdef USE_TIMER + return ticks; +#else + return (*rb->current_tick - start) * (1000 / HZ); +#endif +} + +void SDL_Delay (Uint32 ms) +{ + rb->sleep(ms / (1000 / HZ)); +} + +#include "SDL_thread.h" + +/* Data to handle a single periodic alarm */ +static int timer_alive = 0; +static SDL_Thread *timer = NULL; + +static int RunTimer(void *unused) +{ + while ( timer_alive ) { + if ( SDL_timer_running ) { + SDL_ThreadedTimerCheck(); + } + SDL_Delay(1); + } + return(0); +} + +/* This is only called if the event thread is not running */ +int SDL_SYS_TimerInit(void) +{ + timer_alive = 1; + timer = SDL_CreateThread(RunTimer, NULL); + if ( timer == NULL ) + return(-1); + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + timer_alive = 0; + if ( timer ) { + SDL_WaitThread(timer, NULL); + timer = NULL; + } +} + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: threaded timer in use"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* SDL_TIMER_DUMMY || SDL_TIMERS_DISABLED */ diff --git a/apps/plugins/sdl/src/timer/symbian/SDL_systimer.cpp b/apps/plugins/sdl/src/timer/symbian/SDL_systimer.cpp new file mode 100644 index 0000000000..a5bb749cac --- /dev/null +++ b/apps/plugins/sdl/src/timer/symbian/SDL_systimer.cpp @@ -0,0 +1,114 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + slouken@devolution.com +*/ + +/* + SDL_systimer.cpp + + Epoc version by Hannu Viitala (hannu.j.viitala@mbnet.fi) + Markus Mertama +*/ + +#include +#include + +extern "C" { +#include "SDL_error.h" +#include "SDL_thread.h" +#include "SDL_timer.h" +#include "SDL_timer_c.h" + +static TUint start = 0; +static TInt tickPeriodMilliSeconds; + + +void SDL_StartTicks(void) + { + /* Set first ticks value */ + start = User::TickCount(); + + TTimeIntervalMicroSeconds32 period; + TInt tmp = UserHal::TickPeriod(period); + tickPeriodMilliSeconds = period.Int() / 1000; + } + +Uint32 SDL_GetTicks(void) + { + TUint deltaTics = User::TickCount() - start; + return(deltaTics * tickPeriodMilliSeconds); + } + +void SDL_Delay(Uint32 ms) + { + User::After(TTimeIntervalMicroSeconds32(ms*1000)); + } + +/* Data to handle a single periodic alarm */ +static int timer_alive = 0; +static SDL_Thread *timer = NULL; + +static int RunTimer(void *unused) + { + while ( timer_alive ) + { + if (SDL_timer_running) + { + SDL_ThreadedTimerCheck(); + } + SDL_Delay(10); + } + return(0); + } + +/* This is only called if the event thread is not running */ +int SDL_SYS_TimerInit(void) + { + if(timer != NULL) + return (-1); + timer_alive = 1; + timer = SDL_CreateThread(RunTimer, NULL); + if ( timer == NULL ) + return(-1); + return(SDL_SetTimerThreaded(1)); + } + +void SDL_SYS_TimerQuit(void) + { + timer_alive = 0; + if ( timer ) + { + SDL_WaitThread(timer, NULL); + timer = NULL; + } + } + +int SDL_SYS_StartTimer(void) + { + SDL_SetError("Internal logic error: Epoc uses threaded timer"); + return(-1); + } + +void SDL_SYS_StopTimer(void) + { + return; + } + +} // extern "C" diff --git a/apps/plugins/sdl/src/timer/unix/SDL_systimer.c b/apps/plugins/sdl/src/timer/unix/SDL_systimer.c new file mode 100644 index 0000000000..80b22283b6 --- /dev/null +++ b/apps/plugins/sdl/src/timer/unix/SDL_systimer.c @@ -0,0 +1,240 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_UNIX + +#include +#include +#include +#include +#include +#include + +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +/* The clock_gettime provides monotonous time, so we should use it if + it's available. The clock_gettime function is behind ifdef + for __USE_POSIX199309 + Tommi Kyntola (tommi.kyntola@ray.fi) 27/09/2005 +*/ +#if HAVE_NANOSLEEP || HAVE_CLOCK_GETTIME +#include +#endif + +#if SDL_THREAD_PTH +#include +#endif + +#if SDL_THREADS_DISABLED +#define USE_ITIMER +#endif + +/* The first ticks value of the application */ +#ifdef HAVE_CLOCK_GETTIME +static struct timespec start; +#else +static struct timeval start; +#endif /* HAVE_CLOCK_GETTIME */ + + +void SDL_StartTicks(void) +{ + /* Set first ticks value */ +#if HAVE_CLOCK_GETTIME + clock_gettime(CLOCK_MONOTONIC,&start); +#else + gettimeofday(&start, NULL); +#endif +} + +Uint32 SDL_GetTicks (void) +{ +#if HAVE_CLOCK_GETTIME + Uint32 ticks; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC,&now); + ticks=(now.tv_sec-start.tv_sec)*1000+(now.tv_nsec-start.tv_nsec)/1000000; + return(ticks); +#else + Uint32 ticks; + struct timeval now; + gettimeofday(&now, NULL); + ticks=(now.tv_sec-start.tv_sec)*1000+(now.tv_usec-start.tv_usec)/1000; + return(ticks); +#endif +} + +void SDL_Delay (Uint32 ms) +{ +#if SDL_THREAD_PTH + pth_time_t tv; + tv.tv_sec = ms/1000; + tv.tv_usec = (ms%1000)*1000; + pth_nap(tv); +#else + int was_error; + +#if HAVE_NANOSLEEP + struct timespec elapsed, tv; +#else + struct timeval tv; + Uint32 then, now, elapsed; +#endif + + /* Set the timeout interval */ +#if HAVE_NANOSLEEP + elapsed.tv_sec = ms/1000; + elapsed.tv_nsec = (ms%1000)*1000000; +#else + then = SDL_GetTicks(); +#endif + do { + errno = 0; + +#if HAVE_NANOSLEEP + tv.tv_sec = elapsed.tv_sec; + tv.tv_nsec = elapsed.tv_nsec; + was_error = nanosleep(&tv, &elapsed); +#else + /* Calculate the time interval left (in case of interrupt) */ + now = SDL_GetTicks(); + elapsed = (now-then); + then = now; + if ( elapsed >= ms ) { + break; + } + ms -= elapsed; + tv.tv_sec = ms/1000; + tv.tv_usec = (ms%1000)*1000; + + was_error = select(0, NULL, NULL, NULL, &tv); +#endif /* HAVE_NANOSLEEP */ + } while ( was_error && (errno == EINTR) ); +#endif /* SDL_THREAD_PTH */ +} + +#ifdef USE_ITIMER + +static void HandleAlarm(int sig) +{ + Uint32 ms; + + if ( SDL_alarm_callback ) { + ms = (*SDL_alarm_callback)(SDL_alarm_interval); + if ( ms != SDL_alarm_interval ) { + SDL_SetTimer(ms, SDL_alarm_callback); + } + } +} + +int SDL_SYS_TimerInit(void) +{ + struct sigaction action; + + /* Set the alarm handler (Linux specific) */ + SDL_memset(&action, 0, sizeof(action)); + action.sa_handler = HandleAlarm; + action.sa_flags = SA_RESTART; + sigemptyset(&action.sa_mask); + sigaction(SIGALRM, &action, NULL); + return(0); +} + +void SDL_SYS_TimerQuit(void) +{ + SDL_SetTimer(0, NULL); +} + +int SDL_SYS_StartTimer(void) +{ + struct itimerval timer; + + timer.it_value.tv_sec = (SDL_alarm_interval/1000); + timer.it_value.tv_usec = (SDL_alarm_interval%1000)*1000; + timer.it_interval.tv_sec = (SDL_alarm_interval/1000); + timer.it_interval.tv_usec = (SDL_alarm_interval%1000)*1000; + setitimer(ITIMER_REAL, &timer, NULL); + return(0); +} + +void SDL_SYS_StopTimer(void) +{ + struct itimerval timer; + + SDL_memset(&timer, 0, (sizeof timer)); + setitimer(ITIMER_REAL, &timer, NULL); +} + +#else /* USE_ITIMER */ + +#include "SDL_thread.h" + +/* Data to handle a single periodic alarm */ +static int timer_alive = 0; +static SDL_Thread *timer = NULL; + +static int RunTimer(void *unused) +{ + while ( timer_alive ) { + if ( SDL_timer_running ) { + SDL_ThreadedTimerCheck(); + } + SDL_Delay(1); + } + return(0); +} + +/* This is only called if the event thread is not running */ +int SDL_SYS_TimerInit(void) +{ + timer_alive = 1; + timer = SDL_CreateThread(RunTimer, NULL); + if ( timer == NULL ) + return(-1); + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + timer_alive = 0; + if ( timer ) { + SDL_WaitThread(timer, NULL); + timer = NULL; + } +} + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: Linux uses threaded timer"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* USE_ITIMER */ + +#endif /* SDL_TIMER_UNIX */ diff --git a/apps/plugins/sdl/src/timer/win32/SDL_systimer.c b/apps/plugins/sdl/src/timer/win32/SDL_systimer.c new file mode 100644 index 0000000000..b025e2e7c5 --- /dev/null +++ b/apps/plugins/sdl/src/timer/win32/SDL_systimer.c @@ -0,0 +1,160 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_WIN32 + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +#ifdef _WIN32_WCE + #error This is WinCE. Please use src/timer/wince/SDL_systimer.c instead. +#endif + +#define TIME_WRAP_VALUE (~(DWORD)0) + +/* The first (low-resolution) ticks value of the application */ +static DWORD start; + +#ifndef USE_GETTICKCOUNT +/* Store if a high-resolution performance counter exists on the system */ +static BOOL hires_timer_available; +/* The first high-resolution ticks value of the application */ +static LARGE_INTEGER hires_start_ticks; +/* The number of ticks per second of the high-resolution performance counter */ +static LARGE_INTEGER hires_ticks_per_second; +#endif + +void SDL_StartTicks(void) +{ + /* Set first ticks value */ +#ifdef USE_GETTICKCOUNT + start = GetTickCount(); +#else +#if 0 /* Apparently there are problems with QPC on Win2K */ + if (QueryPerformanceFrequency(&hires_ticks_per_second) == TRUE) + { + hires_timer_available = TRUE; + QueryPerformanceCounter(&hires_start_ticks); + } + else +#endif + { + hires_timer_available = FALSE; + timeBeginPeriod(1); /* use 1 ms timer precision */ + start = timeGetTime(); + } +#endif +} + +Uint32 SDL_GetTicks(void) +{ + DWORD now, ticks; +#ifndef USE_GETTICKCOUNT + LARGE_INTEGER hires_now; +#endif + +#ifdef USE_GETTICKCOUNT + now = GetTickCount(); +#else + if (hires_timer_available) + { + QueryPerformanceCounter(&hires_now); + + hires_now.QuadPart -= hires_start_ticks.QuadPart; + hires_now.QuadPart *= 1000; + hires_now.QuadPart /= hires_ticks_per_second.QuadPart; + + return (DWORD)hires_now.QuadPart; + } + else + { + now = timeGetTime(); + } +#endif + + if ( now < start ) { + ticks = (TIME_WRAP_VALUE-start) + now; + } else { + ticks = (now - start); + } + return(ticks); +} + +void SDL_Delay(Uint32 ms) +{ + Sleep(ms); +} + +/* Data to handle a single periodic alarm */ +static UINT timerID = 0; + +static void CALLBACK HandleAlarm(UINT uID, UINT uMsg, DWORD_PTR dwUser, + DWORD_PTR dw1, DWORD_PTR dw2) +{ + SDL_ThreadedTimerCheck(); +} + + +int SDL_SYS_TimerInit(void) +{ + MMRESULT result; + + /* Set timer resolution */ + result = timeBeginPeriod(TIMER_RESOLUTION); + if ( result != TIMERR_NOERROR ) { + SDL_SetError("Warning: Can't set %d ms timer resolution", + TIMER_RESOLUTION); + } + /* Allow 10 ms of drift so we don't chew on CPU */ + timerID = timeSetEvent(TIMER_RESOLUTION,1,HandleAlarm,0,TIME_PERIODIC); + if ( ! timerID ) { + SDL_SetError("timeSetEvent() failed"); + return(-1); + } + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + if ( timerID ) { + timeKillEvent(timerID); + } + timeEndPeriod(TIMER_RESOLUTION); +} + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: Win32 uses threaded timer"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* SDL_TIMER_WIN32 */ diff --git a/apps/plugins/sdl/src/timer/wince/SDL_systimer.c b/apps/plugins/sdl/src/timer/wince/SDL_systimer.c new file mode 100644 index 0000000000..2b018b0ed5 --- /dev/null +++ b/apps/plugins/sdl/src/timer/wince/SDL_systimer.c @@ -0,0 +1,198 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#ifdef SDL_TIMER_WINCE + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include "SDL_thread.h" +#include "SDL_timer.h" +#include "../SDL_timer_c.h" + +static Uint64 start_date; +static Uint64 start_ticks; + +static Uint64 wce_ticks(void) +{ + return((Uint64)GetTickCount()); +} + +static Uint64 wce_date(void) +{ + union + { + FILETIME ftime; + Uint64 itime; + } ftime; + SYSTEMTIME stime; + + GetSystemTime(&stime); + SystemTimeToFileTime(&stime,&ftime.ftime); + ftime.itime/=10000; // Convert 100ns intervals to 1ms intervals + // Remove ms portion, which can't be relied on + ftime.itime -= (ftime.itime % 1000); + return(ftime.itime); +} + +static Sint32 wce_rel_ticks(void) +{ + return((Sint32)(wce_ticks()-start_ticks)); +} + +static Sint32 wce_rel_date(void) +{ + return((Sint32)(wce_date()-start_date)); +} + +/* Return time in ms relative to when SDL was started */ +Uint32 SDL_GetTicks() +{ + Sint32 offset=wce_rel_date()-wce_rel_ticks(); + if((offset < -1000) || (offset > 1000)) + { +// fprintf(stderr,"Time desync(%+d), resyncing\n",offset/1000); + start_ticks-=offset; + } + + return((Uint32)wce_rel_ticks()); +} + +/* Give up approx. givem milliseconds to the OS. */ +void SDL_Delay(Uint32 ms) +{ + Sleep(ms); +} + +/* Recard start-time of application for reference */ +void SDL_StartTicks(void) +{ + start_date=wce_date(); + start_ticks=wce_ticks(); +} + +static UINT WIN_timer; + +#if ( _WIN32_WCE <= 420 ) + +static HANDLE timersThread = 0; +static HANDLE timersQuitEvent = 0; + +DWORD TimersThreadProc(void *data) +{ + while(WaitForSingleObject(timersQuitEvent, 10) == WAIT_TIMEOUT) + { + SDL_ThreadedTimerCheck(); + } + return 0; +} + +int SDL_SYS_TimerInit(void) +{ + // create a thread to process a threaded timers + // SetTimer does not suit the needs because + // TimerCallbackProc will be called only when WM_TIMER occured + + timersQuitEvent = CreateEvent(0, TRUE, FALSE, 0); + if( !timersQuitEvent ) + { + SDL_SetError("Cannot create event for timers thread"); + return -1; + } + timersThread = CreateThread(NULL, 0, TimersThreadProc, 0, 0, 0); + if( !timersThread ) + { + SDL_SetError("Cannot create timers thread, check amount of RAM available"); + return -1; + } + SetThreadPriority(timersThread, THREAD_PRIORITY_HIGHEST); + + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + SetEvent(timersQuitEvent); + if( WaitForSingleObject(timersThread, 2000) == WAIT_TIMEOUT ) + TerminateThread(timersThread, 0); + CloseHandle(timersThread); + CloseHandle(timersQuitEvent); + return; +} + +#else + +#pragma comment(lib, "mmtimer.lib") + +/* Data to handle a single periodic alarm */ +static UINT timerID = 0; + +static void CALLBACK HandleAlarm(UINT uID, UINT uMsg, DWORD dwUser, + DWORD dw1, DWORD dw2) +{ + SDL_ThreadedTimerCheck(); +} + + +int SDL_SYS_TimerInit(void) +{ + MMRESULT result; + + /* Set timer resolution */ + result = timeBeginPeriod(TIMER_RESOLUTION); + if ( result != TIMERR_NOERROR ) { + SDL_SetError("Warning: Can't set %d ms timer resolution", + TIMER_RESOLUTION); + } + /* Allow 10 ms of drift so we don't chew on CPU */ + timerID = timeSetEvent(TIMER_RESOLUTION,1,HandleAlarm,0,TIME_PERIODIC); + if ( ! timerID ) { + SDL_SetError("timeSetEvent() failed"); + return(-1); + } + return(SDL_SetTimerThreaded(1)); +} + +void SDL_SYS_TimerQuit(void) +{ + if ( timerID ) { + timeKillEvent(timerID); + } + timeEndPeriod(TIMER_RESOLUTION); +} + +#endif + +int SDL_SYS_StartTimer(void) +{ + SDL_SetError("Internal logic error: WinCE uses threaded timer"); + return(-1); +} + +void SDL_SYS_StopTimer(void) +{ + return; +} + +#endif /* SDL_TIMER_WINCE */ -- cgit v1.2.3