summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-07-21 19:49:33 -0400
committerGravatar bunnei2015-08-15 17:33:44 -0400
commit4d517922856791decfed475cdd536aedcaa25c30 (patch)
treee6ac9daf302ea079411052bb0e78428fb71f1440 /src
parentShader: Define a common interface for running vertex shader programs. (diff)
downloadyuzu-4d517922856791decfed475cdd536aedcaa25c30.tar.gz
yuzu-4d517922856791decfed475cdd536aedcaa25c30.tar.xz
yuzu-4d517922856791decfed475cdd536aedcaa25c30.zip
Common: Ported over Dolphin's code for x86 CPU capability detection.
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt8
-rw-r--r--src/common/cpu_detect.h37
-rw-r--r--src/common/cpu_detect_generic.cpp17
-rw-r--r--src/common/cpu_detect_x86.cpp228
4 files changed, 273 insertions, 17 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 4c086cd2f..cef5081c5 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -56,6 +56,14 @@ set(HEADERS
56 vector_math.h 56 vector_math.h
57 ) 57 )
58 58
59if(_M_X86)
60 set(SRCS ${SRCS}
61 cpu_detect_x86.cpp)
62else()
63 set(SRCS ${SRCS}
64 cpu_detect_generic.cpp)
65endif()
66
59create_directory_groups(${SRCS} ${HEADERS}) 67create_directory_groups(${SRCS} ${HEADERS})
60 68
61add_library(common STATIC ${SRCS} ${HEADERS}) 69add_library(common STATIC ${SRCS} ${HEADERS})
diff --git a/src/common/cpu_detect.h b/src/common/cpu_detect.h
index b585f9608..19a2c25d6 100644
--- a/src/common/cpu_detect.h
+++ b/src/common/cpu_detect.h
@@ -3,11 +3,13 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
6// Detect the cpu, so we'll know which optimizations to use 6// Detect the CPU, so we'll know which optimizations to use
7#pragma once 7#pragma once
8 8
9#include <string> 9#include <string>
10 10
11namespace Common {
12
11enum CPUVendor 13enum CPUVendor
12{ 14{
13 VENDOR_INTEL = 0, 15 VENDOR_INTEL = 0,
@@ -40,29 +42,28 @@ struct CPUInfo
40 bool bLZCNT; 42 bool bLZCNT;
41 bool bSSE4A; 43 bool bSSE4A;
42 bool bAVX; 44 bool bAVX;
45 bool bAVX2;
46 bool bBMI1;
47 bool bBMI2;
48 bool bFMA;
49 bool bFMA4;
43 bool bAES; 50 bool bAES;
51 // FXSAVE/FXRSTOR
52 bool bFXSR;
53 bool bMOVBE;
54 // This flag indicates that the hardware supports some mode
55 // in which denormal inputs _and_ outputs are automatically set to (signed) zero.
56 bool bFlushToZero;
44 bool bLAHFSAHF64; 57 bool bLAHFSAHF64;
45 bool bLongMode; 58 bool bLongMode;
46 59 bool bAtom;
47 // ARM specific CPUInfo
48 bool bSwp;
49 bool bHalf;
50 bool bThumb;
51 bool bFastMult;
52 bool bVFP;
53 bool bEDSP;
54 bool bThumbEE;
55 bool bNEON;
56 bool bVFPv3;
57 bool bTLS;
58 bool bVFPv4;
59 bool bIDIVa;
60 bool bIDIVt;
61 bool bArmV7; // enable MOVT, MOVW etc
62 60
63 // ARMv8 specific 61 // ARMv8 specific
64 bool bFP; 62 bool bFP;
65 bool bASIMD; 63 bool bASIMD;
64 bool bCRC32;
65 bool bSHA1;
66 bool bSHA2;
66 67
67 // Call Detect() 68 // Call Detect()
68 explicit CPUInfo(); 69 explicit CPUInfo();
@@ -76,3 +77,5 @@ private:
76}; 77};
77 78
78extern CPUInfo cpu_info; 79extern CPUInfo cpu_info;
80
81} // namespace Common
diff --git a/src/common/cpu_detect_generic.cpp b/src/common/cpu_detect_generic.cpp
new file mode 100644
index 000000000..b99c22af8
--- /dev/null
+++ b/src/common/cpu_detect_generic.cpp
@@ -0,0 +1,17 @@
1// Copyright 2014 Dolphin Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#include "cpu_detect.h"
6
7namespace Common {
8
9CPUInfo cpu_info;
10
11CPUInfo::CPUInfo() { }
12
13std::string CPUInfo::Summarize() {
14 return "Generic";
15}
16
17} // namespace Common
diff --git a/src/common/cpu_detect_x86.cpp b/src/common/cpu_detect_x86.cpp
new file mode 100644
index 000000000..2dff69b94
--- /dev/null
+++ b/src/common/cpu_detect_x86.cpp
@@ -0,0 +1,228 @@
1// Copyright 2008 Dolphin Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include <string>
7
8#include "common_types.h"
9#include "cpu_detect.h"
10
11#ifndef _WIN32
12
13#ifdef __FreeBSD__
14#include <sys/types.h>
15#include <machine/cpufunc.h>
16#endif
17
18static inline void __cpuidex(int info[4], int function_id, int subfunction_id)
19{
20#ifdef __FreeBSD__
21 // Despite the name, this is just do_cpuid() with ECX as second input.
22 cpuid_count((u_int)function_id, (u_int)subfunction_id, (u_int*)info);
23#else
24 info[0] = function_id; // eax
25 info[2] = subfunction_id; // ecx
26 __asm__(
27 "cpuid"
28 : "=a" (info[0]),
29 "=b" (info[1]),
30 "=c" (info[2]),
31 "=d" (info[3])
32 : "a" (function_id),
33 "c" (subfunction_id)
34 );
35#endif
36}
37
38static inline void __cpuid(int info[4], int function_id)
39{
40 return __cpuidex(info, function_id, 0);
41}
42
43#define _XCR_XFEATURE_ENABLED_MASK 0
44static u64 _xgetbv(u32 index)
45{
46 u32 eax, edx;
47 __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
48 return ((u64)edx << 32) | eax;
49}
50
51#endif // ifndef _WIN32
52
53namespace Common {
54
55CPUInfo cpu_info;
56
57CPUInfo::CPUInfo() {
58 Detect();
59}
60
61// Detects the various CPU features
62void CPUInfo::Detect() {
63 memset(this, 0, sizeof(*this));
64#ifdef _M_X86_64
65 Mode64bit = true;
66 OS64bit = true;
67#endif
68 num_cores = 1;
69
70 // Set obvious defaults, for extra safety
71 if (Mode64bit) {
72 bSSE = true;
73 bSSE2 = true;
74 bLongMode = true;
75 }
76
77 // Assume CPU supports the CPUID instruction. Those that don't can barely
78 // boot modern OS:es anyway.
79 int cpu_id[4];
80 memset(brand_string, 0, sizeof(brand_string));
81
82 // Detect CPU's CPUID capabilities, and grab CPU string
83 __cpuid(cpu_id, 0x00000000);
84 u32 max_std_fn = cpu_id[0]; // EAX
85 *((int *)brand_string) = cpu_id[1];
86 *((int *)(brand_string + 4)) = cpu_id[3];
87 *((int *)(brand_string + 8)) = cpu_id[2];
88 __cpuid(cpu_id, 0x80000000);
89 u32 max_ex_fn = cpu_id[0];
90 if (!strcmp(brand_string, "GenuineIntel"))
91 vendor = VENDOR_INTEL;
92 else if (!strcmp(brand_string, "AuthenticAMD"))
93 vendor = VENDOR_AMD;
94 else
95 vendor = VENDOR_OTHER;
96
97 // Set reasonable default brand string even if brand string not available.
98 strcpy(cpu_string, brand_string);
99
100 // Detect family and other misc stuff.
101 bool ht = false;
102 HTT = ht;
103 logical_cpu_count = 1;
104 if (max_std_fn >= 1) {
105 __cpuid(cpu_id, 0x00000001);
106 int family = ((cpu_id[0] >> 8) & 0xf) + ((cpu_id[0] >> 20) & 0xff);
107 int model = ((cpu_id[0] >> 4) & 0xf) + ((cpu_id[0] >> 12) & 0xf0);
108 // Detect people unfortunate enough to be running Dolphin on an Atom
109 if (family == 6 && (model == 0x1C || model == 0x26 || model == 0x27 || model == 0x35 || model == 0x36 ||
110 model == 0x37 || model == 0x4A || model == 0x4D || model == 0x5A || model == 0x5D))
111 bAtom = true;
112 logical_cpu_count = (cpu_id[1] >> 16) & 0xFF;
113 ht = (cpu_id[3] >> 28) & 1;
114
115 if ((cpu_id[3] >> 25) & 1) bSSE = true;
116 if ((cpu_id[3] >> 26) & 1) bSSE2 = true;
117 if ((cpu_id[2]) & 1) bSSE3 = true;
118 if ((cpu_id[2] >> 9) & 1) bSSSE3 = true;
119 if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true;
120 if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
121 if ((cpu_id[2] >> 22) & 1) bMOVBE = true;
122 if ((cpu_id[2] >> 25) & 1) bAES = true;
123
124 if ((cpu_id[3] >> 24) & 1)
125 {
126 // We can use FXSAVE.
127 bFXSR = true;
128 }
129
130 // AVX support requires 3 separate checks:
131 // - Is the AVX bit set in CPUID?
132 // - Is the XSAVE bit set in CPUID?
133 // - XGETBV result has the XCR bit set.
134 if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) {
135 if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
136 bAVX = true;
137 if ((cpu_id[2] >> 12) & 1)
138 bFMA = true;
139 }
140 }
141
142 if (max_std_fn >= 7) {
143 __cpuidex(cpu_id, 0x00000007, 0x00000000);
144 // careful; we can't enable AVX2 unless the XSAVE/XGETBV checks above passed
145 if ((cpu_id[1] >> 5) & 1)
146 bAVX2 = bAVX;
147 if ((cpu_id[1] >> 3) & 1)
148 bBMI1 = true;
149 if ((cpu_id[1] >> 8) & 1)
150 bBMI2 = true;
151 }
152 }
153
154 bFlushToZero = bSSE;
155
156 if (max_ex_fn >= 0x80000004) {
157 // Extract CPU model string
158 __cpuid(cpu_id, 0x80000002);
159 memcpy(cpu_string, cpu_id, sizeof(cpu_id));
160 __cpuid(cpu_id, 0x80000003);
161 memcpy(cpu_string + 16, cpu_id, sizeof(cpu_id));
162 __cpuid(cpu_id, 0x80000004);
163 memcpy(cpu_string + 32, cpu_id, sizeof(cpu_id));
164 }
165 if (max_ex_fn >= 0x80000001) {
166 // Check for more features.
167 __cpuid(cpu_id, 0x80000001);
168 if (cpu_id[2] & 1) bLAHFSAHF64 = true;
169 if ((cpu_id[2] >> 5) & 1) bLZCNT = true;
170 if ((cpu_id[2] >> 16) & 1) bFMA4 = true;
171 if ((cpu_id[3] >> 29) & 1) bLongMode = true;
172 }
173
174 num_cores = (logical_cpu_count == 0) ? 1 : logical_cpu_count;
175
176 if (max_ex_fn >= 0x80000008) {
177 // Get number of cores. This is a bit complicated. Following AMD manual here.
178 __cpuid(cpu_id, 0x80000008);
179 int apic_id_core_id_size = (cpu_id[2] >> 12) & 0xF;
180 if (apic_id_core_id_size == 0) {
181 if (ht) {
182 // New mechanism for modern Intel CPUs.
183 if (vendor == VENDOR_INTEL) {
184 __cpuidex(cpu_id, 0x00000004, 0x00000000);
185 int cores_x_package = ((cpu_id[0] >> 26) & 0x3F) + 1;
186 HTT = (cores_x_package < logical_cpu_count);
187 cores_x_package = ((logical_cpu_count % cores_x_package) == 0) ? cores_x_package : 1;
188 num_cores = (cores_x_package > 1) ? cores_x_package : num_cores;
189 logical_cpu_count /= cores_x_package;
190 }
191 }
192 } else {
193 // Use AMD's new method.
194 num_cores = (cpu_id[2] & 0xFF) + 1;
195 }
196 }
197}
198
199// Turn the CPU info into a string we can show
200std::string CPUInfo::Summarize() {
201 std::string sum(cpu_string);
202 sum += " (";
203 sum += brand_string;
204 sum += ")";
205
206 if (bSSE) sum += ", SSE";
207 if (bSSE2) {
208 sum += ", SSE2";
209 if (!bFlushToZero)
210 sum += " (but not DAZ!)";
211 }
212 if (bSSE3) sum += ", SSE3";
213 if (bSSSE3) sum += ", SSSE3";
214 if (bSSE4_1) sum += ", SSE4.1";
215 if (bSSE4_2) sum += ", SSE4.2";
216 if (HTT) sum += ", HTT";
217 if (bAVX) sum += ", AVX";
218 if (bAVX2) sum += ", AVX2";
219 if (bBMI1) sum += ", BMI1";
220 if (bBMI2) sum += ", BMI2";
221 if (bFMA) sum += ", FMA";
222 if (bAES) sum += ", AES";
223 if (bMOVBE) sum += ", MOVBE";
224 if (bLongMode) sum += ", 64-bit support";
225 return sum;
226}
227
228} // namespace Common