|
|
1.1 root 1: #include "config.h"
2:
3: #if HAVE_NANOSLEEP
4: #ifdef __MINGW32__
5: #include <unistd.h>
6: #else
7: #include <sys/time.h>
8: #endif
9: #endif
10: #include <errno.h>
11:
12: #include "host.h"
13: #include "configuration.h"
14: #include "main.h"
15:
16: /* NeXTdimension blank handling, see nd_sdl.c */
17: void nd_display_blank(void);
18: void nd_video_blank(void);
19:
20: #define NUM_BLANKS 3
21: static const char* BLANKS[] = {
22: "main","nd_main","nd_video"
23: };
24:
25: static volatile Uint32 blank[NUM_BLANKS];
26: static Uint32 vblCounter[NUM_BLANKS];
27: static Uint64 perfCounterStart;
28: static Sint64 cycleCounterStart;
29: static double cycleSecsStart;
30: static bool isRealtime;
31: static bool oldIsRealtime;
32: static double cycleDivisor;
33: static lock_t timeLock;
34: static Uint32 ticksStart;
35: static bool enableRealtime;
36: static Uint64 hardClockExpected;
37: static Uint64 hardClockActual;
38: static time_t unixTimeStart;
39: static double unixTimeOffset = 0;
40: static double perfFrequency;
41: static double realTimeOffset;
42: static Uint64 pauseTimeStamp;
43: static bool osDarkmatter;
44:
45: void host_reset() {
46: perfCounterStart = SDL_GetPerformanceCounter();
47: pauseTimeStamp = perfCounterStart;
48: perfFrequency = SDL_GetPerformanceFrequency();
49: ticksStart = SDL_GetTicks();
50: unixTimeStart = time(NULL);
51: cycleCounterStart = 0;
52: cycleSecsStart = 0;
53: isRealtime = false;
54: oldIsRealtime = false;
55: hardClockExpected = 0;
56: hardClockActual = 0;
57: enableRealtime = ConfigureParams.System.bRealtime;
58: realTimeOffset = 0;
59: osDarkmatter = false;
60:
61: for(int i = NUM_BLANKS; --i >= 0;) {
62: vblCounter[i] = 0;
63: blank[i] = 0;
64: }
65:
66: cycleDivisor = ConfigureParams.System.nCpuFreq * 1000 * 1000;
67:
68: SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH);
69: }
70:
71: void host_blank(int slot, int src, bool state) {
72: slot = 1 << slot;
73: if(state) {
74: blank[src] |= slot;
75: vblCounter[src]++;
76: }
77: else
78: blank[src] &= ~slot;
79: switch (src) {
80: case ND_DISPLAY: nd_display_blank(); break;
81: case ND_VIDEO: nd_video_blank(); break;
82: }
83: }
84:
85: bool host_blank_state(int slot, int src) {
86: slot = 1 << slot;
87: return blank[src] & slot;
88: }
89:
90: void host_hardclock(int expected, int actual) {
91: if(abs(actual-expected) > 1000)
92: fprintf(stderr, "[Hardclock] expected:%dus actual:%dus\n", expected, actual);
93: else {
94: hardClockExpected += expected;
95: hardClockActual += actual;
96: }
97: }
98:
99: extern Sint64 nCyclesMainCounter;
100:
101: void host_realtime(bool state) {
102: isRealtime = state;
103: }
104:
105: double host_time_sec() {
106: double rt;
107: double vt;
108: host_time(&rt, &vt);
109: return vt;
110: }
111:
112: void host_time(double* realTime, double* hostTime) {
113: host_lock(&timeLock);
114:
115: *realTime = (SDL_GetPerformanceCounter() - perfCounterStart);
116: *realTime /= perfFrequency;
117:
118: if(oldIsRealtime) {
119: *hostTime = *realTime;
120: } else {
121: *hostTime = nCyclesMainCounter - cycleCounterStart;
122: *hostTime /= cycleDivisor;
123: *hostTime += cycleSecsStart;
124: }
125: bool state = (isRealtime || osDarkmatter) && enableRealtime;
126: if(oldIsRealtime != state) {
127: if(oldIsRealtime) {
128: // switching from real-time to cycle-time
129: cycleSecsStart = *realTime;
130: cycleCounterStart = nCyclesMainCounter;
131: } else {
132: // switching from cycle-time to real-time
133: realTimeOffset = *hostTime - *realTime;
134: if(realTimeOffset > 0) {
135: // if hostTime is in the future, wait until realTime is there as well
136: if(realTimeOffset > 0.01)
137: host_sleep_sec(realTimeOffset);
138: else
139: while(*realTime < *hostTime) {
140: *realTime = (SDL_GetPerformanceCounter() - perfCounterStart);
141: *realTime /= perfFrequency;
142: }
143: }
144: }
145: oldIsRealtime = state;
146: }
147:
148: realTimeOffset = *hostTime - *realTime;
149:
150: host_unlock(&timeLock);
151: }
152:
153: // Return current time as micro seconds
154: Uint64 host_time_us() {
155: return host_time_sec() * 1000.0 * 1000.0;
156: }
157:
158: // Return current time as milliseconds
159: Uint32 host_time_ms() {
160: return host_time_us() / 1000LL;
161: }
162:
163: time_t host_unix_time() {
164: return unixTimeStart + unixTimeOffset + host_time_sec();
165: }
166:
167: void host_set_unix_time(time_t now) {
168: unixTimeOffset += difftime(now, host_unix_time());
169: }
170:
171: double host_real_time_offset() {
172: host_lock(&timeLock);
173: double result = realTimeOffset;
174: host_unlock(&timeLock);
175: return result;
176: }
177:
178: void host_pause_time(bool pausing) {
179: if(pausing) {
180: pauseTimeStamp = SDL_GetPerformanceCounter();
181: } else {
182: perfCounterStart += SDL_GetPerformanceCounter() - pauseTimeStamp;
183: }
184: }
185:
186: /*-----------------------------------------------------------------------*/
187: /**
188: * Sleep for a given number of micro seconds. We burn cycles by running
189: * the event loop.
190: */
191: void host_sleep_us(Uint64 us) {
192: #if HAVE_NANOSLEEP
193: struct timespec ts;
194: int ret;
195: ts.tv_sec = us / 1000000;
196: ts.tv_nsec = (us % 1000000) * 1000; /* micro sec -> nano sec */
197: /* wait until all the delay is elapsed, including possible interruptions by signals */
198: do {
199: errno = 0;
200: ret = nanosleep(&ts, &ts);
201: } while ( ret && ( errno == EINTR ) ); /* keep on sleeping if we were interrupted */
202: #else
203: Uint64 timeout = host_time_us() + us;
204: host_sleep_ms(( (Uint32)(ticks_micro / 1000) ) ; /* micro sec -> milli sec */
205: while(host_time_us() < timeout) {}
206: #endif
207: }
208:
209: void host_sleep_ms(Uint32 ms) {
210: Uint64 sleep = ms;
211: sleep *= 1000;
212: host_sleep_us(sleep);
213: }
214:
215: void host_sleep_sec(double sec) {
216: sec *= 1000 * 1000;
217: host_sleep_us((Uint64)sec);
218: }
219:
220: void host_lock(lock_t* lock) {
221: SDL_AtomicLock(lock);
222: }
223:
224: int host_trylock(lock_t* lock) {
225: return SDL_AtomicTryLock(lock);
226: }
227:
228: void host_unlock(lock_t* lock) {
229: SDL_AtomicUnlock(lock);
230: }
231:
232: thread_t* host_thread_create(thread_func_t func, void* data) {
233: return SDL_CreateThread(func, "[ND] Thread", data);
234: }
235:
236: int host_thread_wait(thread_t* thread) {
237: int status;
238: SDL_WaitThread(thread, &status);
239: return status;
240: }
241:
242: int host_num_cpus() {
243: return SDL_GetCPUCount();
244: }
245:
246: void host_darkmatter(bool state) {
247: osDarkmatter = state;
248: }
249:
250: static double lastVT;
251: static char report[512];
252:
253: const char* host_report(double realTime, double hostTime) {
254: double dVT = hostTime - lastVT;
255:
256: double hardClock = hardClockExpected;
257: hardClock /= hardClockActual == 0 ? 1 : hardClockActual;
258:
259: char* r = report;
260: r += sprintf(r, "[%s] hostTime:%.1f hardClock:%.3fMHz", enableRealtime ? "Max.speed" : "CycleTime", hostTime, hardClock);
261:
262: for(int i = NUM_BLANKS; --i >= 0;) {
263: r += sprintf(r, " %s:%.1fHz", BLANKS[i], (double)vblCounter[i]/dVT);
264: vblCounter[i] = 0;
265: }
266:
267: lastVT = hostTime;
268:
269: return report;
270: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.