]> git.tdb.fi Git - ext/openal.git/blob - core/cpu_caps.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / core / cpu_caps.cpp
1
2 #include "config.h"
3
4 #include "cpu_caps.h"
5
6 #if defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
7 #define WIN32_LEAN_AND_MEAN
8 #include <windows.h>
9 #ifndef PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
10 #define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
11 #endif
12 #endif
13
14 #if defined(HAVE_CPUID_H)
15 #include <cpuid.h>
16 #elif defined(HAVE_INTRIN_H)
17 #include <intrin.h>
18 #endif
19
20 #include <array>
21 #include <cctype>
22 #include <string>
23
24
25 int CPUCapFlags{0};
26
27 namespace {
28
29 #if defined(HAVE_GCC_GET_CPUID) \
30     && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
31 using reg_type = unsigned int;
32 inline std::array<reg_type,4> get_cpuid(unsigned int f)
33 {
34     std::array<reg_type,4> ret{};
35     __get_cpuid(f, ret.data(), &ret[1], &ret[2], &ret[3]);
36     return ret;
37 }
38 #define CAN_GET_CPUID
39 #elif defined(HAVE_CPUID_INTRINSIC) \
40     && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
41 using reg_type = int;
42 inline std::array<reg_type,4> get_cpuid(unsigned int f)
43 {
44     std::array<reg_type,4> ret{};
45     (__cpuid)(ret.data(), f);
46     return ret;
47 }
48 #define CAN_GET_CPUID
49 #endif
50
51 } // namespace
52
53 al::optional<CPUInfo> GetCPUInfo()
54 {
55     CPUInfo ret;
56
57 #ifdef CAN_GET_CPUID
58     auto cpuregs = get_cpuid(0);
59     if(cpuregs[0] == 0)
60         return al::nullopt;
61
62     const reg_type maxfunc{cpuregs[0]};
63
64     cpuregs = get_cpuid(0x80000000);
65     const reg_type maxextfunc{cpuregs[0]};
66
67     ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[1]), 4);
68     ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[3]), 4);
69     ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[2]), 4);
70     auto iter_end = std::remove(ret.mVendor.begin(), ret.mVendor.end(), '\0');
71     iter_end = std::unique(ret.mVendor.begin(), iter_end,
72         [](auto&& c0, auto&& c1) { return std::isspace(c0) && std::isspace(c1); });
73     ret.mVendor.erase(iter_end, ret.mVendor.end());
74     if(!ret.mVendor.empty() && std::isspace(ret.mVendor.back()))
75         ret.mVendor.pop_back();
76     if(!ret.mVendor.empty() && std::isspace(ret.mVendor.front()))
77         ret.mVendor.erase(ret.mVendor.begin());
78
79     if(maxextfunc >= 0x80000004)
80     {
81         cpuregs = get_cpuid(0x80000002);
82         ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16);
83         cpuregs = get_cpuid(0x80000003);
84         ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16);
85         cpuregs = get_cpuid(0x80000004);
86         ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16);
87         iter_end = std::remove(ret.mName.begin(), ret.mName.end(), '\0');
88         iter_end = std::unique(ret.mName.begin(), iter_end,
89             [](auto&& c0, auto&& c1) { return std::isspace(c0) && std::isspace(c1); });
90         ret.mName.erase(iter_end, ret.mName.end());
91         if(!ret.mName.empty() && std::isspace(ret.mName.back()))
92             ret.mName.pop_back();
93         if(!ret.mName.empty() && std::isspace(ret.mName.front()))
94             ret.mName.erase(ret.mName.begin());
95     }
96
97     if(maxfunc >= 1)
98     {
99         cpuregs = get_cpuid(1);
100         if((cpuregs[3]&(1<<25)))
101             ret.mCaps |= CPU_CAP_SSE;
102         if((ret.mCaps&CPU_CAP_SSE) && (cpuregs[3]&(1<<26)))
103             ret.mCaps |= CPU_CAP_SSE2;
104         if((ret.mCaps&CPU_CAP_SSE2) && (cpuregs[2]&(1<<0)))
105             ret.mCaps |= CPU_CAP_SSE3;
106         if((ret.mCaps&CPU_CAP_SSE3) && (cpuregs[2]&(1<<19)))
107             ret.mCaps |= CPU_CAP_SSE4_1;
108     }
109
110 #else
111
112     /* Assume support for whatever's supported if we can't check for it */
113 #if defined(HAVE_SSE4_1)
114 #warning "Assuming SSE 4.1 run-time support!"
115     ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
116 #elif defined(HAVE_SSE3)
117 #warning "Assuming SSE 3 run-time support!"
118     ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
119 #elif defined(HAVE_SSE2)
120 #warning "Assuming SSE 2 run-time support!"
121     ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2;
122 #elif defined(HAVE_SSE)
123 #warning "Assuming SSE run-time support!"
124     ret.mCaps |= CPU_CAP_SSE;
125 #endif
126 #endif /* CAN_GET_CPUID */
127
128 #ifdef HAVE_NEON
129 #ifdef __ARM_NEON
130     ret.mCaps |= CPU_CAP_NEON;
131 #elif defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
132     if(IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE))
133         ret.mCaps |= CPU_CAP_NEON;
134 #else
135 #warning "Assuming NEON run-time support!"
136     ret.mCaps |= CPU_CAP_NEON;
137 #endif
138 #endif
139
140     return ret;
141 }