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.

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