implemented occlusion query support on corona rendering, this enables
[divverent/darkplaces.git] / sys_linux.c
1 #include "quakedef.h"
2
3 #ifdef WIN32
4 #include <io.h>
5 #include "conio.h"
6 #else
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <sys/time.h>
10 #include <time.h>
11 #endif
12
13 #include <signal.h>
14
15
16 cvar_t sys_usenoclockbutbenchmark = {CVAR_SAVE, "sys_usenoclockbutbenchmark", "0", "don't use ANY real timing, and simulate a clock (for benchmarking); the game then runs as fast as possible. Run a QC mod with bots that does some stuff, then does a quit at the end, to benchmark a server. NEVER do this on a public server."};
17 static unsigned long benchmark_time;
18
19 #ifdef WIN32
20 cvar_t sys_usetimegettime = {CVAR_SAVE, "sys_usetimegettime", "1", "use windows timeGetTime function (which has issues on some motherboards) for timing rather than QueryPerformanceCounter timer (which has issues on multicore/multiprocessor machines and processors which are designed to conserve power)"};
21 #else
22 # ifndef MACOSX
23 cvar_t sys_useclockgettime = {CVAR_SAVE, "sys_useclockgettime", "0", "use POSIX clock_gettime function (which has issues if the system clock speed is far off, as it can't get fixed by NTP) for timing rather than gettimeofday (which has issues if the system time is stepped by ntpdate, or apparently on some Xen installations)"};
24 # endif
25 #endif
26
27
28
29 // =======================================================================
30 // General routines
31 // =======================================================================
32 void Sys_Shutdown (void)
33 {
34 #ifndef WIN32
35         fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
36 #endif
37         fflush(stdout);
38 }
39
40 void Sys_Error (const char *error, ...)
41 {
42         va_list argptr;
43         char string[MAX_INPUTLINE];
44
45 // change stdin to non blocking
46 #ifndef WIN32
47         fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
48 #endif
49
50         va_start (argptr,error);
51         dpvsnprintf (string, sizeof (string), error, argptr);
52         va_end (argptr);
53
54         Con_Printf ("Quake Error: %s\n", string);
55
56         Host_Shutdown ();
57         exit (1);
58 }
59
60 void Sys_PrintToTerminal(const char *text)
61 {
62 #ifndef WIN32
63         // BUG: for some reason, NDELAY also affects stdout (1) when used on stdin (0).
64         int origflags = fcntl (1, F_GETFL, 0);
65         fcntl (1, F_SETFL, origflags & ~FNDELAY);
66 #else
67 #define write _write
68 #endif
69         while(*text)
70         {
71                 ssize_t written = write(1, text, strlen(text));
72                 if(written <= 0)
73                         break; // sorry, I cannot do anything about this error - without an output
74                 text += written;
75         }
76 #ifndef WIN32
77         fcntl (1, F_SETFL, origflags);
78 #endif
79         //fprintf(stdout, "%s", text);
80 }
81
82 double Sys_DoubleTime (void)
83 {
84         static int first = true;
85         static double oldtime = 0.0, curtime = 0.0;
86         double newtime;
87         if(sys_usenoclockbutbenchmark.integer)
88         {
89                 benchmark_time += 1;
90                 return ((double) benchmark_time) / 1e6;
91         }
92 #ifdef WIN32
93 #include <mmsystem.h>
94         // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
95         if (sys_usetimegettime.integer)
96         {
97                 static int firsttimegettime = true;
98                 // timeGetTime
99                 // platform:
100                 // Windows 95/98/ME/NT/2000/XP
101                 // features:
102                 // reasonable accuracy (millisecond)
103                 // issues:
104                 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
105
106                 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
107                 if (firsttimegettime)
108                 {
109                         timeBeginPeriod (1);
110                         firsttimegettime = false;
111                 }
112
113                 newtime = (double) timeGetTime () / 1000.0;
114         }
115         else
116         {
117                 // QueryPerformanceCounter
118                 // platform:
119                 // Windows 95/98/ME/NT/2000/XP
120                 // features:
121                 // very accurate (CPU cycles)
122                 // known issues:
123                 // does not necessarily match realtime too well (tends to get faster and faster in win98)
124                 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
125                 double timescale;
126                 LARGE_INTEGER PerformanceFreq;
127                 LARGE_INTEGER PerformanceCount;
128
129                 if (!QueryPerformanceFrequency (&PerformanceFreq))
130                 {
131                         Con_Printf ("No hardware timer available\n");
132                         // fall back to timeGetTime
133                         Cvar_SetValueQuick(&sys_usetimegettime, true);
134                         return Sys_DoubleTime();
135                 }
136                 QueryPerformanceCounter (&PerformanceCount);
137
138                 #ifdef __BORLANDC__
139                 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
140                 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
141                 #else
142                 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
143                 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
144                 #endif
145         }
146 #else
147 # ifndef MACOSX
148         if (sys_useclockgettime.integer)
149         {
150                 struct timespec ts;
151 #  ifdef SUNOS
152                 clock_gettime(CLOCK_HIGHRES, &ts);
153 #  else
154                 clock_gettime(CLOCK_MONOTONIC, &ts);
155 #  endif
156                 newtime = (double) ts.tv_sec + ts.tv_nsec / 1000000000.0;
157         }
158         else
159 # endif
160         {
161                 struct timeval tp;
162                 gettimeofday(&tp, NULL);
163                 newtime = (double) tp.tv_sec + tp.tv_usec / 1000000.0;
164         }
165 #endif
166
167         if (first)
168         {
169                 first = false;
170                 oldtime = newtime;
171         }
172
173         if (newtime < oldtime)
174         {
175                 // warn if it's significant
176                 if (newtime - oldtime < -0.01)
177                         Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
178         }
179         else if (newtime > oldtime + 1800)
180         {
181                 Con_Printf("Sys_DoubleTime: time stepped forward (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
182         }
183         else
184                 curtime += newtime - oldtime;
185         oldtime = newtime;
186
187         return curtime;
188 }
189
190 char *Sys_ConsoleInput(void)
191 {
192         //if (cls.state == ca_dedicated)
193         {
194                 static char text[MAX_INPUTLINE];
195                 static unsigned int len = 0;
196 #ifdef WIN32
197                 int c;
198
199                 // read a line out
200                 while (_kbhit ())
201                 {
202                         c = _getch ();
203                         if (c == '\r')
204                         {
205                                 text[len] = '\0';
206                                 _putch ('\n');
207                                 len = 0;
208                                 return text;
209                         }
210                         if (c == '\b')
211                         {
212                                 if (len)
213                                 {
214                                         _putch (c);
215                                         _putch (' ');
216                                         _putch (c);
217                                         len--;
218                                 }
219                                 continue;
220                         }
221                         if (len < sizeof (text) - 1)
222                         {
223                                 _putch (c);
224                                 text[len] = c;
225                                 len++;
226                         }
227                 }
228 #else
229                 fd_set fdset;
230                 struct timeval timeout;
231                 FD_ZERO(&fdset);
232                 FD_SET(0, &fdset); // stdin
233                 timeout.tv_sec = 0;
234                 timeout.tv_usec = 0;
235                 if (select (1, &fdset, NULL, NULL, &timeout) != -1 && FD_ISSET(0, &fdset))
236                 {
237                         len = read (0, text, sizeof(text));
238                         if (len >= 1)
239                         {
240                                 // rip off the \n and terminate
241                                 text[len-1] = 0;
242                                 return text;
243                         }
244                 }
245 #endif
246         }
247         return NULL;
248 }
249
250 void Sys_Sleep(int microseconds)
251 {
252         if(sys_usenoclockbutbenchmark.integer)
253         {
254                 benchmark_time += microseconds;
255                 return;
256         }
257 #ifdef WIN32
258         Sleep(microseconds / 1000);
259 #else
260         usleep(microseconds);
261 #endif
262 }
263
264 char *Sys_GetClipboardData (void)
265 {
266         return NULL;
267 }
268
269 void Sys_InitConsole (void)
270 {
271 }
272
273 void Sys_Init_Commands (void)
274 {
275         Cvar_RegisterVariable(&sys_usenoclockbutbenchmark);
276 #ifdef WIN32
277         Cvar_RegisterVariable(&sys_usetimegettime);
278 #else
279 # ifndef MACOSX
280         Cvar_RegisterVariable(&sys_useclockgettime);
281 # endif
282 #endif
283 }
284
285 int main (int argc, char **argv)
286 {
287         signal(SIGFPE, SIG_IGN);
288
289         com_argc = argc;
290         com_argv = (const char **)argv;
291
292 #ifndef WIN32
293         fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
294 #endif
295
296         Host_Main();
297
298         return 0;
299 }