This commit is contained in:
Toni Wilen 2012-04-23 20:00:57 +03:00
parent bb807f8375
commit 1a1b0af86a
11 changed files with 231 additions and 111 deletions

View File

@ -490,7 +490,7 @@ static void do_tod_hack (int dotod)
if (tod_hack_enabled > 1) {
tod_hack_enabled--;
if (tod_hack_enabled == 1) {
write_log (_T("TOD HACK enabled\n"));
//write_log (_T("TOD HACK enabled\n"));
tod_hack_reset ();
}
return;
@ -506,8 +506,7 @@ static void do_tod_hack (int dotod)
return;
if (rate != oldrate || ciaatod != tod_hack_tod_last) {
if (ciaatod != 0)
write_log (_T("TOD HACK reset %d,%d %d,%d\n"),
rate, oldrate, ciaatod, tod_hack_tod_last);
//write_log (_T("TOD HACK reset %d,%d %d,%d\n"), rate, oldrate, ciaatod, tod_hack_tod_last);
tod_hack_reset ();
oldrate = rate;
docount = 1;

View File

@ -5921,8 +5921,8 @@ static void hsync_handler_post (bool onvsync)
cnt++;
if (cnt == 500) {
int port_insert_custom (int inputmap_port, int devicetype, DWORD flags, const TCHAR *custom);
port_insert_custom (0, 0, 0, L"Left=0xC8 Right=0xD0 Up=0xCB Down=0xCD Fire=0x39");
port_insert_custom (1, 0, 0, L"Left=0x48 Right=0x50 Up=0x4B Down=0x4D Fire=0x4C");
port_insert_custom (0, 2, 0, L"Fire.autorepeat=0x38 Left=0x4B Right=0x4D Up=0x48 Down=0x50 Fire=0x4C Fire2=0x52'");
port_insert_custom (1, 2, 0, L"Left=0x48 Right=0x50 Up=0x4B Down=0x4D Fire=0x4C");
} else if (cnt == 1000) {
TCHAR out[256];
bool port_get_custom (int inputmap_port, TCHAR *out);
@ -5940,8 +5940,10 @@ static void hsync_handler_post (bool onvsync)
is_syncline = 1;
}
} else {
static int linecounter;
/* end of scanline, run cpu emulation as long as we still have time */
vsyncmintime += vsynctimeperline;
linecounter++;
is_syncline = 0;
if (!vblank_found_chipset) {
if ((int)vsyncmaxtime - (int)vsyncmintime > 0 && (int)vsyncwaittime - (int)vsyncmintime > 0) {
@ -5949,8 +5951,14 @@ static void hsync_handler_post (bool onvsync)
/* Extra time left? Do some extra CPU emulation */
if ((int)vsyncmintime - (int)rpt > 0) {
is_syncline = -1;
linecounter = 0;
}
}
// extra cpu emulation time if 10 lines without extra
if (!is_syncline && linecounter > 9) {
is_syncline = -1;
linecounter = 0;
}
}
}
} else {

View File

@ -31,7 +31,6 @@ extern bool vsync_switchmode (int);
extern frame_time_t vsync_busywait_end (void);
extern bool vsync_busywait_do (int*, bool, bool);
extern void vsync_busywait_start (void);
extern bool vsync_busywait_check (void);
extern double vblank_calibrate (double, bool);
extern void doflashscreen (void);
extern int flashscreen;

View File

@ -3903,6 +3903,11 @@ static void setautofireevent (struct uae_input_device *uid, int num, int sub, in
{
if (!af)
return;
#ifdef RETROPLATFORM
// don't override custom AF autofire mappings
if (rp_isactive ())
return;
#endif
int *afp = af_ports[index];
for (int k = 0; afp[k] >= 0; k++) {
if (afp[k] == uid->eventid[num][sub]) {
@ -4247,6 +4252,11 @@ static void setautofire (struct uae_input_device *uid, int port, int af)
static void setautofires (struct uae_prefs *prefs, int port, int af)
{
#ifdef RETROPLATFORM
// don't override custom AF autofire mappings
if (rp_isactive ())
return;
#endif
for (int l = 0; l < MAX_INPUT_DEVICES; l++) {
setautofire (&joysticks[l], port, af);
setautofire (&mice[l], port, af);
@ -4713,7 +4723,7 @@ bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int
inputdevice_get_mapping (devnum, num, &xflags, &xport, xname, xcustom, 0);
if (xport == 0)
inputdevice_set_mapping (devnum, num, xname, xcustom, xflags, MAX_JPORTS + 1, SPARE_SUB_EVENT);
inputdevice_set_mapping (devnum, num, name, NULL, IDEV_MAPPED_GAMEPORTSCUSTOM1, port + 1, 0);
inputdevice_set_mapping (devnum, num, name, NULL, IDEV_MAPPED_GAMEPORTSCUSTOM1 | flags, port + 1, 0);
}
return true;
}

View File

@ -1058,9 +1058,8 @@ static BOOL GetDevicePropertyFromName(const TCHAR *DevicePath, DWORD Index, DWOR
PSTORAGE_ADAPTER_DESCRIPTOR adpDesc;
int gli_ok;
BOOL status;
ULONG length = 0,
returned = 0,
returnedLength;
ULONG length = 0, returned = 0, returnedLength;
BOOL showonly = FALSE;
//
// Now we have the device path. Open the device interface
@ -1087,9 +1086,21 @@ static BOOL GetDevicePropertyFromName(const TCHAR *DevicePath, DWORD Index, DWOR
if (hDevice == INVALID_HANDLE_VALUE) {
write_log (_T("CreateFile failed with error: %d\n"), GetLastError());
ret = 1;
goto end;
hDevice = CreateFile(
udi->device_path, // device interface name
0, // dwDesiredAccess
FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
NULL, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDistribution
0, // dwFlagsAndAttributes
NULL // hTemplateFile
);
if (hDevice == INVALID_HANDLE_VALUE) {
write_log (_T("CreateFile failed with error: %d\n"), GetLastError());
ret = 1;
goto end;
}
showonly = TRUE;
}
query.PropertyId = StorageAdapterProperty;
@ -1161,6 +1172,12 @@ static BOOL GetDevicePropertyFromName(const TCHAR *DevicePath, DWORD Index, DWOR
udi->readonly = 1;
}
if (showonly) {
udi->dangerous = -10;
udi->readonly = -1;
goto amipartfound;
}
gli_ok = 1;
if (!DeviceIoControl (hDevice, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, (void*)&gli, sizeof (gli), &returnedLength, NULL)) {
gli_ok = 0;
@ -1483,11 +1500,16 @@ TCHAR *hdf_getnameharddrive (int index, int flags, int *sectorsize, int *dangero
int nomedia = uae_drives[index].nomedia;
TCHAR *dang = _T("?");
TCHAR *rw = _T("RW");
bool noaccess = false;
if (dangerousdrive)
*dangerousdrive = 0;
switch (uae_drives[index].dangerous)
{
case -10:
dang = _T("[???]");
noaccess = true;
break;
case -5:
dang = _T("[PART]");
break;
@ -1518,32 +1540,43 @@ TCHAR *hdf_getnameharddrive (int index, int flags, int *sectorsize, int *dangero
*dangerousdrive |= 1;
break;
}
if (nomedia) {
dang = _T("[NO MEDIA]");
if (dangerousdrive)
*dangerousdrive &= ~1;
}
if (uae_drives[index].readonly) {
rw = _T("RO");
if (dangerousdrive && !nomedia)
*dangerousdrive |= 2;
}
if (sectorsize)
*sectorsize = uae_drives[index].bytespersector;
if (flags & 1) {
if (nomedia) {
_tcscpy (tmp, _T("N/A"));
} else {
if (size >= 1024 * 1024 * 1024)
_stprintf (tmp, _T("%.1fG"), ((double)(uae_u32)(size / (1024 * 1024))) / 1024.0);
else if (size < 10 * 1024 * 1024)
_stprintf (tmp, _T("%dK"), size / 1024);
else
_stprintf (tmp, _T("%.1fM"), ((double)(uae_u32)(size / (1024))) / 1024.0);
if (noaccess) {
if (dangerousdrive)
*dangerousdrive = -1;
if (flags & 1) {
_stprintf (name, _T("[ACCESS DENIED] %s"), uae_drives[index].device_name + 1);
return name;
}
} else {
if (nomedia) {
dang = _T("[NO MEDIA]");
if (dangerousdrive)
*dangerousdrive &= ~1;
}
if (uae_drives[index].readonly) {
rw = _T("RO");
if (dangerousdrive && !nomedia)
*dangerousdrive |= 2;
}
if (sectorsize)
*sectorsize = uae_drives[index].bytespersector;
if (flags & 1) {
if (nomedia) {
_tcscpy (tmp, _T("N/A"));
} else {
if (size >= 1024 * 1024 * 1024)
_stprintf (tmp, _T("%.1fG"), ((double)(uae_u32)(size / (1024 * 1024))) / 1024.0);
else if (size < 10 * 1024 * 1024)
_stprintf (tmp, _T("%dK"), size / 1024);
else
_stprintf (tmp, _T("%.1fM"), ((double)(uae_u32)(size / (1024))) / 1024.0);
}
_stprintf (name, _T("%10s [%s,%s] %s"), dang, tmp, rw, uae_drives[index].device_name + 1);
return name;
}
_stprintf (name, _T("%10s [%s,%s] %s"), dang, tmp, rw, uae_drives[index].device_name + 1);
return name;
}
if (flags & 2)
return uae_drives[index].device_path;

View File

@ -255,7 +255,6 @@ bool port_get_custom (int inputmap_port, TCHAR *out)
}
_stprintf (p, _T("=%02X"), kc);
p += _tcslen (p);
break;
}
}
}
@ -294,14 +293,21 @@ int port_insert_custom (int inputmap_port, int devicetype, DWORD flags, const TC
const TCHAR *p2 = _tcschr (p, '=');
if (!p2)
break;
const TCHAR *p3 = _tcschr (p, '.');
if (!p3 || p3 >= p2) {
p3 = NULL;
eventlen = p2 - p;
} else {
eventlen = p3 - p;
if (!_tcsncmp (p3, L"autorepeat", p2 - p3))
const TCHAR *p4 = p;
eventlen = -1;
for (;;) {
const TCHAR *p3 = _tcschr (p4, '.');
if (!p3 || p3 >= p2) {
p3 = NULL;
if (eventlen < 0)
eventlen = p2 - p;
break;
}
if (eventlen < 0)
eventlen = p3 - p;
if (!_tcsnicmp (p3 + 1, L"autorepeat", 10))
flags |= IDEV_MAPPED_AUTOFIRE_SET;
p4 = p3 + 1;
}
for (int i = 0; eventorder[i]; i++) {

View File

@ -163,6 +163,7 @@ static int timermode, timeon;
#define MAX_TIMEHANDLES 8
static int timehandlecounter;
static HANDLE timehandle[MAX_TIMEHANDLES];
static bool timehandleinuse[MAX_TIMEHANDLES];
int sleep_resolution;
static CRITICAL_SECTION cs_time;
@ -233,14 +234,22 @@ static void sleep_millis2 (int ms, bool main)
if (main)
start = read_processor_time ();
EnterCriticalSection (&cs_time);
cnt = timehandlecounter++;
if (timehandlecounter >= MAX_TIMEHANDLES)
timehandlecounter = 0;
for (;;) {
timehandlecounter++;
if (timehandlecounter >= MAX_TIMEHANDLES)
timehandlecounter = 0;
if (timehandleinuse[timehandlecounter] == false) {
cnt = timehandlecounter;
timehandleinuse[cnt] = true;
break;
}
}
LeaveCriticalSection (&cs_time);
TimerEvent = timeSetEvent (ms, 0, (LPTIMECALLBACK)timehandle[cnt], 0, TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
WaitForSingleObject (timehandle[cnt], ms);
ResetEvent (timehandle[cnt]);
timeKillEvent (TimerEvent);
timehandleinuse[cnt] = false;
if (main)
idletime += read_processor_time () - start;
}

View File

@ -19,8 +19,8 @@
#define LANG_DLL 1
//#define WINUAEBETA _T("")
#define WINUAEBETA _T("Beta 9")
#define WINUAEDATE MAKEBD(2012, 4, 21)
#define WINUAEBETA _T("Beta 10")
#define WINUAEDATE MAKEBD(2012, 4, 23)
#define WINUAEEXTRA _T("")
//#define WINUAEEXTRA _T("AmiKit Preview")
#define WINUAEREV _T("")

View File

@ -118,6 +118,8 @@ extern int reopen (int);
#define VBLANKTH_ACTIVE_WAIT 3
#define VBLANKTH_ACTIVE 4
#define VBLANKTH_ACTIVE_START 5
#define VBLANKTH_ACTIVE_SKIPFRAME 6
#define VBLANKTH_ACTIVE_SKIPFRAME2 7
static volatile bool vblank_found;
static volatile int flipthread_mode;
@ -2450,7 +2452,7 @@ static bool vblank_wait (void)
}
}
static bool vblank_getstate (bool *state)
static bool vblank_getstate (bool *state, int *pvp)
{
int vp, opos;
@ -2458,6 +2460,8 @@ static bool vblank_getstate (bool *state)
opos = prevvblankpos;
if (!getvblankpos (&vp))
return false;
if (pvp)
*pvp = vp;
if (opos > maxscanline / 2 && vp < maxscanline / 3) {
*state = true;
return true;
@ -2469,6 +2473,10 @@ static bool vblank_getstate (bool *state)
*state = false;
return true;
}
static bool vblank_getstate (bool *state)
{
return vblank_getstate (state, NULL);
}
void vblank_reset (double freq)
{
@ -2498,6 +2506,8 @@ static int frame_missed, frame_counted, frame_errors;
static int frame_usage, frame_usage_avg, frame_usage_total;
extern int log_vsync;
static bool dooddevenskip;
static volatile bool vblank_skipeveryother;
static volatile bool vblank_first_time;
static bool vblanklaceskip (void)
{
@ -2512,7 +2522,7 @@ static bool vblanklaceskip (void)
static unsigned int __stdcall vblankthread (void *dummy)
{
static bool firstvblankbasewait2; // if >85Hz mode
static bool firstvblankbasewait2;
while (vblankthread_mode > VBLANKTH_KILL) {
struct apmode *ap = picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
vblankthread_counter++;
@ -2529,62 +2539,89 @@ static unsigned int __stdcall vblankthread (void *dummy)
sleep_millis (ap->gfx_vflip && currprefs.m68k_speed >= 0 ? 2 : 1);
} else if (vblankthread_mode == VBLANKTH_ACTIVE_START) {
// do not start until vblank has been passed
bool vb = false;
int vp;
firstvblankbasewait2 = false;
vblank_getstate (&vb);
bool ok = vblank_getstate (&vb);
if (vb == false)
vblankthread_mode = VBLANKTH_ACTIVE;
else
getvblankpos (&vp);
if (vp <= 0) {
if (!vblank_first_time) {
// set prevtime now if we are still at vsync to improve timing
vblank_prev_time = read_processor_time ();
vblank_first_time = true;
}
sleep_millis (1);
continue;
}
if (vp > maxscanline / 2) {
sleep_millis (1);
continue;
}
prevvblankpos = 0;
if (vblank_skipeveryother) // wait for first vblank in skip frame mode (100Hz+)
vblankthread_mode = VBLANKTH_ACTIVE_SKIPFRAME;
else
vblankthread_mode = VBLANKTH_ACTIVE;
} else if (vblankthread_mode == VBLANKTH_ACTIVE_SKIPFRAME) {
int vp;
sleep_millis (1);
getvblankpos (&vp);
if (vp >= maxscanline / 2)
vblankthread_mode = VBLANKTH_ACTIVE_SKIPFRAME2;
} else if (vblankthread_mode == VBLANKTH_ACTIVE_SKIPFRAME2) {
int vp;
sleep_millis (1);
getvblankpos (&vp);
if (vp < maxscanline / 2)
vblankthread_mode = VBLANKTH_ACTIVE;
} else if (vblankthread_mode == VBLANKTH_ACTIVE) {
// busy wait mode
frame_time_t t = read_processor_time ();
bool donotwait = false;
if (!vblank_found) {
int vs = isvsync_chipset ();
// immediate vblank if mismatched frame type
if (vs < 0 && vblanklaceskip ()) {
vblank_found = true;
vblank_found_chipset = true;
vblankthread_mode = VBLANKTH_ACTIVE_WAIT;
donotwait = true;
} else if (t - thread_vblank_time > vblankbasewait2) {
bool vb = false;
bool ok;
if (firstvblankbasewait2 == false) {
firstvblankbasewait2 = true;
vblank_getstate (&vb);
if (!dooddevenskip && ap->gfx_vflip > 0) {
doflipevent ();
}
bool end = false;
int vs = isvsync_chipset ();
// immediate vblank if mismatched frame type
if (vs < 0 && vblanklaceskip ()) {
vblank_found = true;
vblank_found_chipset = true;
end = true;
} else if (t - vblank_prev_time > vblankbasewait2) {
int vp = 0;
bool vb = false;
bool ok;
if (firstvblankbasewait2 == false) {
firstvblankbasewait2 = true;
vblank_getstate (&vb, &vp);
if (!dooddevenskip && ap->gfx_vflip > 0) {
doflipevent ();
}
ok = vblank_getstate (&vb);
if (!ok || vb) {
vblank_found = true;
if (vs < 0) {
vblank_found_chipset = true;
if (!ap->gfx_vflip) {
show_screen ();
}
}
vblank_found_rtg = true;
//write_log (_T("%d\n"), t - thread_vblank_time);
thread_vblank_time = t;
vblankthread_mode = VBLANKTH_ACTIVE_WAIT;
}
if (t - thread_vblank_time > vblankbasewait3)
donotwait = true;
}
ok = vblank_getstate (&vb, &vp);
if (!ok || vb) {
thread_vblank_time = t;
if (vs < 0) {
vblank_found_chipset = true;
if (!ap->gfx_vflip) {
show_screen ();
}
}
vblank_found_rtg = true;
vblank_found = true;
end = true;
}
if (t - vblank_prev_time > vblankbasewait3)
donotwait = true;
}
if (t - vblank_prev_time > vblankbasefull * 3) {
if (t - vblank_prev_time > vblankbasefull * 2) {
thread_vblank_time = t;
vblank_found = true;
vblank_found_rtg = true;
vblank_found_chipset = true;
vblankthread_mode = VBLANKTH_IDLE;
end = true;
}
if (!donotwait || ap->gfx_vflip || picasso_on)
if (end) {
vblankthread_mode = VBLANKTH_ACTIVE_WAIT;
} else if (!donotwait || ap->gfx_vflip || picasso_on) {
sleep_millis (ap->gfx_vflip && currprefs.m68k_speed >= 0 ? 2 : 1);
}
} else {
break;
}
@ -2593,10 +2630,6 @@ static unsigned int __stdcall vblankthread (void *dummy)
return 0;
}
bool vsync_busywait_check (void)
{
return vblankthread_mode == VBLANKTH_ACTIVE || vblankthread_mode == VBLANKTH_ACTIVE_WAIT;
}
#if 0
static void vsync_notvblank (void)
{
@ -2614,6 +2647,9 @@ static void vsync_notvblank (void)
#endif
frame_time_t vsync_busywait_end (void)
{
while (vblankthread_mode == VBLANKTH_ACTIVE_START || vblankthread_mode == VBLANKTH_ACTIVE_SKIPFRAME || vblankthread_mode == VBLANKTH_ACTIVE_SKIPFRAME2) {
sleep_millis_main (1);
}
if (!dooddevenskip) {
while (!vblank_found && vblankthread_mode == VBLANKTH_ACTIVE) {
vsync_sleep (currprefs.m68k_speed < 0 && currprefs.m68k_speed_throttle == 0);
@ -2625,8 +2661,6 @@ frame_time_t vsync_busywait_end (void)
void vsync_busywait_start (void)
{
int vp = 0;
struct apmode *ap = picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
#if 0
struct apmode *ap = picasso_on ? &currprefs.gfx_apmode[1] : &currprefs.gfx_apmode[0];
if (!dooddevenskip) {
@ -2636,8 +2670,9 @@ void vsync_busywait_start (void)
}
}
#endif
changevblankthreadmode_fast (VBLANKTH_ACTIVE_START);
vblank_prev_time = thread_vblank_time;
vblank_first_time = false;
changevblankthreadmode_fast (VBLANKTH_ACTIVE_START);
}
static bool isthreadedvsync (void)
@ -2663,8 +2698,8 @@ bool vsync_busywait_do (int *freetime, bool lace, bool oddeven)
t = read_processor_time ();
ti = t - prevtime;
if (ti > 2 * vblankbasefull || ti < -2 * vblankbasefull) {
changevblankthreadmode_fast (VBLANKTH_ACTIVE_WAIT);
waitvblankstate (false, NULL);
t = read_processor_time ();
vblank_prev_time = t;
thread_vblank_time = t;
frame_missed++;
@ -2869,22 +2904,27 @@ skip:
if (waitonly)
tsum = approx_vblank;
vblank_skipeveryother = false;
getvsyncrate (tsum, &mult);
if (mult < 0)
if (mult < 0) {
div = 2.0;
else if (mult > 0)
vblank_skipeveryother = true;
} else if (mult > 0) {
div = 0.5;
else
} else {
div = 1.0;
}
tsum2 = tsum / div;
vblankbasefull = (syncbase / tsum2);
vblankbasewait1 = (syncbase / tsum2) * 75 / 100;
vblankbasewait2 = (syncbase / tsum2) * 55 / 100;
vblankbasewait3 = (syncbase / tsum2) * 90 / 100;
vblankbasewait3 = (syncbase / tsum2) * 99 / 100 - syncbase / 500; // at least 2ms before vblank
vblankbaselace = lace;
write_log (_T("VSync %s: %.6fHz/%.1f=%.6fHz. MinV=%d MaxV=%d%s Units=%d\n"),
waitonly ? _T("remembered") : _T("calibrated"), tsum, div, tsum2, minscanline, maxvpos, lace ? _T("i") : _T(""), vblankbasefull);
write_log (_T("VSync %s: %.6fHz/%.1f=%.6fHz. MinV=%d MaxV=%d%s Units=%d %.1f%%\n"),
waitonly ? _T("remembered") : _T("calibrated"), tsum, div, tsum2,
minscanline, maxvpos, lace ? _T("i") : _T(""), vblankbasefull,
vblankbasewait3 * 100 / (syncbase / tsum2));
remembered_vblank = tsum;
vblank_prev_time = read_processor_time ();

View File

@ -9232,14 +9232,16 @@ static INT_PTR CALLBACK HarddriveSettingsProc (HWND hDlg, UINT msg, WPARAM wPara
if (oposn != posn && posn != CB_ERR) {
oposn = posn;
if (posn >= 0) {
BOOL ena ;
int dang = 1;
hdf_getnameharddrive (posn, 1, NULL, &dang);
ew (hDlg, IDC_HARDDRIVE_IMAGE, TRUE);
ew (hDlg, IDOK, TRUE);
ena = dang >= 0;
ew (hDlg, IDC_HARDDRIVE_IMAGE, ena);
ew (hDlg, IDOK, ena);
ew (hDlg, IDC_HDF_RW, !dang);
if (dang)
current_hfdlg.rw = FALSE;
ew (hDlg, IDC_HDF_CONTROLLER, TRUE);
ew (hDlg, IDC_HDF_CONTROLLER, ena);
hardfile_testrdb (hDlg, &current_hfdlg);
SendDlgItemMessage (hDlg, IDC_HDF_CONTROLLER, CB_SETCURSEL, current_hfdlg.controller, 0);
CheckDlgButton(hDlg, IDC_HDF_RW, current_hfdlg.rw);

View File

@ -2,6 +2,20 @@
- restore only single input target to default.
- hdd from command line
Beta 10:
- Partial rewrite of fastest possible CPU low latency vsync detection code. Should fix jitter caused by frame not always
getting shown on screen at correct time.
- Low latency vsync and double frame mode (85Hz+): guarantee every other vblank is really skipped, previously it didn't
work correctly in some situations.
- Calculate final vblank busywait time from selected rate instead of using hardcoded 50Hz/100Hz-only compatible value.
Fixes >50Hz no-buffer jitters.
- Emulate extra CPU time if it has been more than 7 lines since last extra CPU time, matches older behavior without
losing 2.4.0+ performance increase.
- Fixed low latency vsync + fastest possible CPU getting in state where FPS dropped greatly temporarily, usually at startup.
- Show also drives that require admin privileges in harddrives panel, unselectable and marked with "Access denied"
label. Only name shown because accessing any other attribute may require admin privileges.
Beta 9:
- Fixed D3D texture reallocation ordering. Caused blank screen or other strange side-effects (b7)