cpu_detect.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright 2013 Dolphin Emulator Project / 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cstring>
  5. #include "common/common_types.h"
  6. #include "common/x64/cpu_detect.h"
  7. #ifdef _MSC_VER
  8. #include <intrin.h>
  9. #else
  10. #if defined(__DragonFly__) || defined(__FreeBSD__)
  11. // clang-format off
  12. #include <sys/types.h>
  13. #include <machine/cpufunc.h>
  14. // clang-format on
  15. #endif
  16. static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
  17. #if defined(__DragonFly__) || defined(__FreeBSD__)
  18. // Despite the name, this is just do_cpuid() with ECX as second input.
  19. cpuid_count((u_int)function_id, (u_int)subfunction_id, (u_int*)info);
  20. #else
  21. info[0] = function_id; // eax
  22. info[2] = subfunction_id; // ecx
  23. __asm__("cpuid"
  24. : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3])
  25. : "a"(function_id), "c"(subfunction_id));
  26. #endif
  27. }
  28. static inline void __cpuid(int info[4], int function_id) {
  29. return __cpuidex(info, function_id, 0);
  30. }
  31. #define _XCR_XFEATURE_ENABLED_MASK 0
  32. static inline u64 _xgetbv(u32 index) {
  33. u32 eax, edx;
  34. __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
  35. return ((u64)edx << 32) | eax;
  36. }
  37. #endif // _MSC_VER
  38. namespace Common {
  39. // Detects the various CPU features
  40. static CPUCaps Detect() {
  41. CPUCaps caps = {};
  42. // Assumes the CPU supports the CPUID instruction. Those that don't would likely not support
  43. // yuzu at all anyway
  44. int cpu_id[4];
  45. memset(caps.brand_string, 0, sizeof(caps.brand_string));
  46. // Detect CPU's CPUID capabilities and grab CPU string
  47. __cpuid(cpu_id, 0x00000000);
  48. u32 max_std_fn = cpu_id[0]; // EAX
  49. std::memcpy(&caps.brand_string[0], &cpu_id[1], sizeof(int));
  50. std::memcpy(&caps.brand_string[4], &cpu_id[3], sizeof(int));
  51. std::memcpy(&caps.brand_string[8], &cpu_id[2], sizeof(int));
  52. __cpuid(cpu_id, 0x80000000);
  53. u32 max_ex_fn = cpu_id[0];
  54. // Set reasonable default brand string even if brand string not available
  55. strcpy(caps.cpu_string, caps.brand_string);
  56. // Detect family and other miscellaneous features
  57. if (max_std_fn >= 1) {
  58. __cpuid(cpu_id, 0x00000001);
  59. if ((cpu_id[3] >> 25) & 1)
  60. caps.sse = true;
  61. if ((cpu_id[3] >> 26) & 1)
  62. caps.sse2 = true;
  63. if ((cpu_id[2]) & 1)
  64. caps.sse3 = true;
  65. if ((cpu_id[2] >> 9) & 1)
  66. caps.ssse3 = true;
  67. if ((cpu_id[2] >> 19) & 1)
  68. caps.sse4_1 = true;
  69. if ((cpu_id[2] >> 20) & 1)
  70. caps.sse4_2 = true;
  71. if ((cpu_id[2] >> 25) & 1)
  72. caps.aes = true;
  73. // AVX support requires 3 separate checks:
  74. // - Is the AVX bit set in CPUID?
  75. // - Is the XSAVE bit set in CPUID?
  76. // - XGETBV result has the XCR bit set.
  77. if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) {
  78. if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
  79. caps.avx = true;
  80. if ((cpu_id[2] >> 12) & 1)
  81. caps.fma = true;
  82. }
  83. }
  84. if (max_std_fn >= 7) {
  85. __cpuidex(cpu_id, 0x00000007, 0x00000000);
  86. // Can't enable AVX2 unless the XSAVE/XGETBV checks above passed
  87. if ((cpu_id[1] >> 5) & 1)
  88. caps.avx2 = caps.avx;
  89. if ((cpu_id[1] >> 3) & 1)
  90. caps.bmi1 = true;
  91. if ((cpu_id[1] >> 8) & 1)
  92. caps.bmi2 = true;
  93. }
  94. }
  95. if (max_ex_fn >= 0x80000004) {
  96. // Extract CPU model string
  97. __cpuid(cpu_id, 0x80000002);
  98. std::memcpy(caps.cpu_string, cpu_id, sizeof(cpu_id));
  99. __cpuid(cpu_id, 0x80000003);
  100. std::memcpy(caps.cpu_string + 16, cpu_id, sizeof(cpu_id));
  101. __cpuid(cpu_id, 0x80000004);
  102. std::memcpy(caps.cpu_string + 32, cpu_id, sizeof(cpu_id));
  103. }
  104. if (max_ex_fn >= 0x80000001) {
  105. // Check for more features
  106. __cpuid(cpu_id, 0x80000001);
  107. if ((cpu_id[2] >> 16) & 1)
  108. caps.fma4 = true;
  109. }
  110. return caps;
  111. }
  112. const CPUCaps& GetCPUCaps() {
  113. static CPUCaps caps = Detect();
  114. return caps;
  115. }
  116. } // namespace Common