The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

598 lines
16KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "win32_headers.h"
  24. #include "../../../src/juce_core/basics/juce_StandardHeader.h"
  25. //==============================================================================
  26. // Auto-link the other win32 libs that are needed by library calls..
  27. #if defined (JUCE_DLL_BUILD) && JUCE_MSVC
  28. #pragma comment(lib, "kernel32.lib")
  29. #pragma comment(lib, "user32.lib")
  30. #pragma comment(lib, "shell32.lib")
  31. #pragma comment(lib, "gdi32.lib")
  32. #pragma comment(lib, "vfw32.lib")
  33. #pragma comment(lib, "comdlg32.lib")
  34. #pragma comment(lib, "winmm.lib")
  35. #pragma comment(lib, "wininet.lib")
  36. #pragma comment(lib, "ole32.lib")
  37. #pragma comment(lib, "advapi32.lib")
  38. #pragma comment(lib, "ws2_32.lib")
  39. #if JUCE_OPENGL
  40. #pragma comment(lib, "OpenGL32.Lib")
  41. #pragma comment(lib, "GlU32.Lib")
  42. #endif
  43. #endif
  44. //==============================================================================
  45. BEGIN_JUCE_NAMESPACE
  46. #include "../../../src/juce_core/io/files/juce_File.h"
  47. #include "../../../src/juce_core/basics/juce_SystemStats.h"
  48. extern void juce_updateMultiMonitorInfo() throw();
  49. //==============================================================================
  50. void Logger::outputDebugString (const String& text) throw()
  51. {
  52. OutputDebugString (text + T("\n"));
  53. }
  54. void Logger::outputDebugPrintf (const tchar* format, ...) throw()
  55. {
  56. String text;
  57. va_list args;
  58. va_start (args, format);
  59. text.vprintf(format, args);
  60. outputDebugString (text);
  61. }
  62. //==============================================================================
  63. static int64 hiResTicksPerSecond;
  64. static double hiResTicksScaleFactor;
  65. static SYSTEM_INFO systemInfo;
  66. static struct _LogicalCpuInfo
  67. {
  68. bool htSupported;
  69. bool htAvailable;
  70. int numPackages;
  71. int numLogicalPerPackage;
  72. unsigned long physicalAffinityMask;
  73. } logicalCpuInfo;
  74. //==============================================================================
  75. #if JUCE_USE_INTRINSICS
  76. // CPU info functions using intrinsics...
  77. #pragma intrinsic (__cpuid)
  78. #pragma intrinsic (__rdtsc)
  79. static unsigned int getCPUIDWord (int* familyModel = 0, int* extFeatures = 0) throw()
  80. {
  81. int info [4];
  82. __cpuid (info, 1);
  83. if (familyModel != 0)
  84. *familyModel = info [0];
  85. if (extFeatures != 0)
  86. *extFeatures = info[1];
  87. return info[3];
  88. }
  89. const String SystemStats::getCpuVendor() throw()
  90. {
  91. int info [4];
  92. __cpuid (info, 0);
  93. char v [12];
  94. memcpy (v, info + 1, 4);
  95. memcpy (v + 4, info + 3, 4);
  96. memcpy (v + 8, info + 2, 4);
  97. return String (v, 12);
  98. }
  99. #else
  100. //==============================================================================
  101. // CPU info functions using old fashioned inline asm...
  102. static juce_noinline unsigned int getCPUIDWord (int* familyModel = 0, int* extFeatures = 0)
  103. {
  104. unsigned int cpu = 0;
  105. unsigned int ext = 0;
  106. unsigned int family = 0;
  107. #if JUCE_GCC
  108. unsigned int dummy = 0;
  109. #endif
  110. #ifndef __MINGW32__
  111. __try
  112. #endif
  113. {
  114. #if JUCE_GCC
  115. __asm__ ("cpuid" : "=a" (family), "=b" (ext), "=c" (dummy),"=d" (cpu) : "a" (1));
  116. #else
  117. __asm
  118. {
  119. mov eax, 1
  120. cpuid
  121. mov cpu, edx
  122. mov family, eax
  123. mov ext, ebx
  124. }
  125. #endif
  126. }
  127. #ifndef __MINGW32__
  128. __except (EXCEPTION_EXECUTE_HANDLER)
  129. {
  130. return 0;
  131. }
  132. #endif
  133. if (familyModel != 0)
  134. *familyModel = family;
  135. if (extFeatures != 0)
  136. *extFeatures = ext;
  137. return cpu;
  138. }
  139. static void juce_getCpuVendor (char* const v)
  140. {
  141. int vendor[4];
  142. zeromem (vendor, 16);
  143. #ifdef JUCE_64BIT
  144. #else
  145. #ifndef __MINGW32__
  146. __try
  147. #endif
  148. {
  149. #if JUCE_GCC
  150. unsigned int dummy = 0;
  151. __asm__ ("cpuid" : "=a" (dummy), "=b" (vendor[0]), "=c" (vendor[2]),"=d" (vendor[1]) : "a" (0));
  152. #else
  153. __asm
  154. {
  155. mov eax, 0
  156. cpuid
  157. mov [vendor], ebx
  158. mov [vendor + 4], edx
  159. mov [vendor + 8], ecx
  160. }
  161. #endif
  162. }
  163. #ifndef __MINGW32__
  164. __except (EXCEPTION_EXECUTE_HANDLER)
  165. {
  166. *v = 0;
  167. }
  168. #endif
  169. #endif
  170. memcpy (v, vendor, 16);
  171. }
  172. const String SystemStats::getCpuVendor() throw()
  173. {
  174. char v [16];
  175. juce_getCpuVendor (v);
  176. return String (v, 16);
  177. }
  178. #endif
  179. static void initLogicalCpuInfo() throw()
  180. {
  181. int familyModelWord, extFeaturesWord;
  182. int featuresWord = getCPUIDWord (&familyModelWord, &extFeaturesWord);
  183. HANDLE hCurrentProcessHandle = GetCurrentProcess();
  184. logicalCpuInfo.htSupported = false;
  185. logicalCpuInfo.htAvailable = false;
  186. logicalCpuInfo.numLogicalPerPackage = 1;
  187. logicalCpuInfo.numPackages = 0;
  188. logicalCpuInfo.physicalAffinityMask = 0;
  189. DWORD_PTR processAffinity, systemAffinity;
  190. if (! GetProcessAffinityMask (hCurrentProcessHandle, &processAffinity, &systemAffinity))
  191. return;
  192. // Checks: CPUID supported, model >= Pentium 4, Hyperthreading bit set, logical CPUs per package > 1
  193. if (featuresWord == 0
  194. || ((familyModelWord >> 8) & 0xf) < 15
  195. || (featuresWord & (1 << 28)) == 0
  196. || ((extFeaturesWord >> 16) & 0xff) < 2)
  197. {
  198. logicalCpuInfo.physicalAffinityMask = static_cast <unsigned long> (processAffinity);
  199. return;
  200. }
  201. logicalCpuInfo.htSupported = true;
  202. logicalCpuInfo.numLogicalPerPackage = (extFeaturesWord >> 16) & 0xff;
  203. unsigned int affinityMask;
  204. unsigned int physAff = 0;
  205. unsigned char i = 1;
  206. unsigned char physIdMask = 0xFF;
  207. unsigned char physIdShift = 0;
  208. unsigned char apicId;
  209. unsigned char logId;
  210. unsigned char physId;
  211. while (i < logicalCpuInfo.numLogicalPerPackage)
  212. {
  213. i *= 2;
  214. physIdMask <<= 1;
  215. physIdShift++;
  216. }
  217. affinityMask = 1;
  218. logicalCpuInfo.numPackages = 0;
  219. while ((affinityMask != 0) && (affinityMask <= processAffinity))
  220. {
  221. if (SetProcessAffinityMask (hCurrentProcessHandle, affinityMask))
  222. {
  223. Sleep(0); // schedule onto correct CPU
  224. featuresWord = getCPUIDWord (&familyModelWord, &extFeaturesWord);
  225. apicId = (unsigned char) (extFeaturesWord >> 24);
  226. logId = (unsigned char) (apicId & ~physIdMask);
  227. physId = (unsigned char) (apicId >> physIdShift);
  228. if (logId != 0)
  229. logicalCpuInfo.htAvailable = true;
  230. if ((((int) logId) % logicalCpuInfo.numLogicalPerPackage) == 0)
  231. {
  232. // This is a physical CPU
  233. physAff |= affinityMask;
  234. logicalCpuInfo.numPackages++;
  235. }
  236. }
  237. affinityMask = affinityMask << 1;
  238. }
  239. logicalCpuInfo.physicalAffinityMask = physAff;
  240. SetProcessAffinityMask(hCurrentProcessHandle, processAffinity);
  241. }
  242. //==============================================================================
  243. void juce_initialiseThreadEvents() throw();
  244. #if JUCE_ENABLE_WIN98_COMPATIBILITY
  245. void juce_initialiseUnicodeFileFunctions() throw();
  246. #endif
  247. static struct JuceCpuProps
  248. {
  249. bool hasMMX : 1, hasSSE : 1, hasSSE2 : 1, has3DNow : 1;
  250. } juce_CpuProps;
  251. bool SystemStats::hasMMX() throw()
  252. {
  253. return juce_CpuProps.hasMMX;
  254. }
  255. bool SystemStats::hasSSE() throw()
  256. {
  257. return juce_CpuProps.hasSSE;
  258. }
  259. bool SystemStats::hasSSE2() throw()
  260. {
  261. return juce_CpuProps.hasSSE2;
  262. }
  263. bool SystemStats::has3DNow() throw()
  264. {
  265. return juce_CpuProps.has3DNow;
  266. }
  267. void SystemStats::initialiseStats() throw()
  268. {
  269. #if JUCE_ENABLE_WIN98_COMPATIBILITY
  270. juce_initialiseUnicodeFileFunctions();
  271. #endif
  272. juce_initialiseThreadEvents();
  273. juce_CpuProps.hasMMX = IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE) != 0;
  274. juce_CpuProps.hasSSE = IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0;
  275. juce_CpuProps.hasSSE2 = IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0;
  276. #ifdef PF_AMD3D_INSTRUCTIONS_AVAILABLE
  277. juce_CpuProps.has3DNow = IsProcessorFeaturePresent (PF_AMD3D_INSTRUCTIONS_AVAILABLE) != 0;
  278. #else
  279. juce_CpuProps.has3DNow = IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE) != 0;
  280. #endif
  281. LARGE_INTEGER f;
  282. QueryPerformanceFrequency (&f);
  283. hiResTicksPerSecond = f.QuadPart;
  284. hiResTicksScaleFactor = 1000.0 / hiResTicksPerSecond;
  285. String s (SystemStats::getJUCEVersion());
  286. GetSystemInfo (&systemInfo);
  287. initLogicalCpuInfo();
  288. #ifdef JUCE_DEBUG
  289. const MMRESULT res = timeBeginPeriod (1);
  290. jassert (res == TIMERR_NOERROR);
  291. #else
  292. timeBeginPeriod (1);
  293. #endif
  294. #if defined (JUCE_DEBUG) && JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS
  295. _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
  296. #endif
  297. }
  298. //==============================================================================
  299. SystemStats::OperatingSystemType SystemStats::getOperatingSystemType() throw()
  300. {
  301. OSVERSIONINFO info;
  302. info.dwOSVersionInfoSize = sizeof (info);
  303. GetVersionEx (&info);
  304. if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
  305. {
  306. switch (info.dwMajorVersion)
  307. {
  308. case 5:
  309. return (info.dwMinorVersion == 0) ? Win2000 : WinXP;
  310. case 6:
  311. return WinVista;
  312. default:
  313. jassertfalse // !! not a supported OS!
  314. break;
  315. }
  316. }
  317. else if (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
  318. {
  319. jassert (info.dwMinorVersion != 0); // !! still running on Windows 95??
  320. return Win98;
  321. }
  322. return UnknownOS;
  323. }
  324. const String SystemStats::getOperatingSystemName() throw()
  325. {
  326. const char* name = "Unknown OS";
  327. switch (getOperatingSystemType())
  328. {
  329. case WinVista:
  330. name = "Windows Vista";
  331. break;
  332. case WinXP:
  333. name = "Windows XP";
  334. break;
  335. case Win2000:
  336. name = "Windows 2000";
  337. break;
  338. case Win98:
  339. name = "Windows 98";
  340. break;
  341. default:
  342. jassertfalse // !! new type of OS?
  343. break;
  344. }
  345. return name;
  346. }
  347. //==============================================================================
  348. int SystemStats::getMemorySizeInMegabytes() throw()
  349. {
  350. MEMORYSTATUS mem;
  351. GlobalMemoryStatus (&mem);
  352. return (int) (mem.dwTotalPhys / (1024 * 1024)) + 1;
  353. }
  354. bool SystemStats::hasHyperThreading() throw()
  355. {
  356. return logicalCpuInfo.htAvailable;
  357. }
  358. int SystemStats::getNumPhysicalCpus() throw()
  359. {
  360. if (logicalCpuInfo.numPackages)
  361. return logicalCpuInfo.numPackages;
  362. return getNumLogicalCpus();
  363. }
  364. int SystemStats::getNumLogicalCpus() throw()
  365. {
  366. return systemInfo.dwNumberOfProcessors;
  367. }
  368. uint32 SystemStats::getPhysicalAffinityMask() throw()
  369. {
  370. return logicalCpuInfo.physicalAffinityMask;
  371. }
  372. //==============================================================================
  373. uint32 juce_millisecondsSinceStartup() throw()
  374. {
  375. return (uint32) GetTickCount();
  376. }
  377. int64 Time::getHighResolutionTicks() throw()
  378. {
  379. LARGE_INTEGER ticks;
  380. QueryPerformanceCounter (&ticks);
  381. const int64 mainCounterAsHiResTicks = (GetTickCount() * hiResTicksPerSecond) / 1000;
  382. const int64 newOffset = mainCounterAsHiResTicks - ticks.QuadPart;
  383. // fix for a very obscure PCI hardware bug that can make the counter
  384. // sometimes jump forwards by a few seconds..
  385. static int64 hiResTicksOffset = 0;
  386. const int64 offsetDrift = abs64 (newOffset - hiResTicksOffset);
  387. if (offsetDrift > (hiResTicksPerSecond >> 1))
  388. hiResTicksOffset = newOffset;
  389. return ticks.QuadPart + hiResTicksOffset;
  390. }
  391. double Time::getMillisecondCounterHiRes() throw()
  392. {
  393. return getHighResolutionTicks() * hiResTicksScaleFactor;
  394. }
  395. int64 Time::getHighResolutionTicksPerSecond() throw()
  396. {
  397. return hiResTicksPerSecond;
  398. }
  399. int64 SystemStats::getClockCycleCounter() throw()
  400. {
  401. #if JUCE_USE_INTRINSICS
  402. // MS intrinsics version...
  403. return __rdtsc();
  404. #elif JUCE_GCC
  405. // GNU inline asm version...
  406. unsigned int hi = 0, lo = 0;
  407. __asm__ __volatile__ (
  408. "xor %%eax, %%eax \n\
  409. xor %%edx, %%edx \n\
  410. rdtsc \n\
  411. movl %%eax, %[lo] \n\
  412. movl %%edx, %[hi]"
  413. :
  414. : [hi] "m" (hi),
  415. [lo] "m" (lo)
  416. : "cc", "eax", "ebx", "ecx", "edx", "memory");
  417. return (int64) ((((uint64) hi) << 32) | lo);
  418. #else
  419. // MSVC inline asm version...
  420. unsigned int hi = 0, lo = 0;
  421. __asm
  422. {
  423. xor eax, eax
  424. xor edx, edx
  425. rdtsc
  426. mov lo, eax
  427. mov hi, edx
  428. }
  429. return (int64) ((((uint64) hi) << 32) | lo);
  430. #endif
  431. }
  432. int SystemStats::getCpuSpeedInMegaherz() throw()
  433. {
  434. const int64 cycles = SystemStats::getClockCycleCounter();
  435. const uint32 millis = Time::getMillisecondCounter();
  436. int lastResult = 0;
  437. for (;;)
  438. {
  439. int n = 1000000;
  440. while (--n > 0) {}
  441. const uint32 millisElapsed = Time::getMillisecondCounter() - millis;
  442. const int64 cyclesNow = SystemStats::getClockCycleCounter();
  443. if (millisElapsed > 80)
  444. {
  445. const int newResult = (int) (((cyclesNow - cycles) / millisElapsed) / 1000);
  446. if (millisElapsed > 500 || (lastResult == newResult && newResult > 100))
  447. return newResult;
  448. lastResult = newResult;
  449. }
  450. }
  451. }
  452. //==============================================================================
  453. bool Time::setSystemTimeToThisTime() const throw()
  454. {
  455. SYSTEMTIME st;
  456. st.wDayOfWeek = 0;
  457. st.wYear = (WORD) getYear();
  458. st.wMonth = (WORD) (getMonth() + 1);
  459. st.wDay = (WORD) getDayOfMonth();
  460. st.wHour = (WORD) getHours();
  461. st.wMinute = (WORD) getMinutes();
  462. st.wSecond = (WORD) getSeconds();
  463. st.wMilliseconds = (WORD) (millisSinceEpoch % 1000);
  464. // do this twice because of daylight saving conversion problems - the
  465. // first one sets it up, the second one kicks it in.
  466. return SetLocalTime (&st) != 0
  467. && SetLocalTime (&st) != 0;
  468. }
  469. int SystemStats::getPageSize() throw()
  470. {
  471. return systemInfo.dwPageSize;
  472. }
  473. END_JUCE_NAMESPACE