Cogs.Core
Features.cpp
1#ifdef _WIN32
2#include <winsock2.h>
3#include <intrin.h>
4#endif
5#if (defined(__GNUC__) || defined(__clang__)) && !defined(EMSCRIPTEN) && !defined(__APPLE__)
6#include <cpuid.h>
7#endif
8#include <sstream>
9#include <string>
10#include <vector>
11
12#include "Foundation/Logging/Logger.h"
13
14#include "Context.h"
15
16#include "Services/Features.h"
17
18
19namespace {
21
22#ifdef COGS_ARCH_X86
23 struct CpuId
24 {
25 CpuId() = delete;
26
27 CpuId(uint32_t level)
28 {
29#ifdef _MSC_VER
30 int ret[4];
31 __cpuid(ret, level);
32 eax = ret[0];
33 ebx = ret[1];
34 ecx = ret[2];
35 edx = ret[3];
36#elif defined(__GNUC__) || defined(__clang__)
37 __get_cpuid(level, &eax, &ebx, &ecx, &edx);
38#else
39#error "implement cpuid for this compiler"
40#endif
41 }
42
43 uint32_t eax;
44 uint32_t ebx;
45 uint32_t ecx;
46 uint32_t edx;
47 };
48#endif
49}
50
51using namespace Cogs::Core;
52
53
54Features::Features()
55{
56 detectedCPUFeatureSet = CPUFeature::None;
57
58#ifdef COGS_ARCH_X86
59 CpuId level0(0x00000000u);
60 if ((level0.ebx == 0x756e6547u) && (level0.edx == 0x49656e69u) && (level0.ecx == 0x6c65746eu)) {
61 // "uneG", "Ieni", "letn"
62 detectedCPUFeatureSet |= CPUFeature::Intel;
63 }
64 else if ((level0.ebx == 0x68747541u) && (level0.edx == 0x69746e65u) && (level0.ecx == 0x444d4163u)) {
65 // "htuA", "itne", "DMAc"
66 detectedCPUFeatureSet |= CPUFeature::AMD;
67 }
68
69
70 bool useAvx = true;
71
72 bool osxsave = false;
73 if (1 <= level0.eax) {
74 CpuId level1(0x00000001u);
75 if (level1.edx & (1u << 25u)) {
76 detectedCPUFeatureSet |= CPUFeature::SSE;
77 }
78 if (level1.edx & (1u << 26u)) {
79 detectedCPUFeatureSet |= CPUFeature::SSE2;
80 }
81 if (level1.ecx & (1u << 0u)) {
82 detectedCPUFeatureSet |= CPUFeature::SSE3;
83 }
84 if (level1.ecx & (1u << 9u)) {
85 detectedCPUFeatureSet |= CPUFeature::SSSE3;
86 }
87 if (level1.ecx & (1u << 12u)) {
88 detectedCPUFeatureSet |= CPUFeature::FMA3;
89 }
90 if (level1.ecx & (1u << 19u)) {
91 detectedCPUFeatureSet |= CPUFeature::SSE41;
92 }
93 if (level1.ecx & (1u << 20u)) {
94 detectedCPUFeatureSet |= CPUFeature::SSE42;
95 }
96 if (level1.ecx & (1u << 22u)) {
97 detectedCPUFeatureSet |= CPUFeature::MovBE;
98 }
99 if (level1.ecx & (1u << 23u)) {
100 detectedCPUFeatureSet |= CPUFeature::PopCnt;
101 }
102 if (level1.ecx & (1u << 27u)) {
103 osxsave = true;
104 }
105 if (useAvx && osxsave && (level1.ecx & (1u << 28u))) {
106 detectedCPUFeatureSet |= CPUFeature::AVX;
107 }
108 if (level1.ecx & (1u << 29u)) {
109 detectedCPUFeatureSet |= CPUFeature::F16C;
110 }
111 }
112 if (7 <= level0.eax) {
113 CpuId level7(0x00000007u);
114 if (level7.ebx & (1u << 3u)) {
115 detectedCPUFeatureSet |= CPUFeature::BMI1;
116 }
117 if (level7.ebx & (1u << 8u)) {
118 detectedCPUFeatureSet |= CPUFeature::BMI2;
119 }
120 if (useAvx && osxsave && (level7.ebx & (1u << 5u))) {
121 detectedCPUFeatureSet |= CPUFeature::AVX2;
122 }
123 if (useAvx && osxsave && (level7.ebx & (1u << 16u))) {
124 detectedCPUFeatureSet |= CPUFeature::AVX512F;
125 }
126 if (useAvx && osxsave && (level7.ebx & (1u << 28u))) {
127 detectedCPUFeatureSet |= CPUFeature::AVX512CD;
128 }
129 if (useAvx && osxsave && (level7.ebx & (1u << 27u))) {
130 detectedCPUFeatureSet |= CPUFeature::AVX512ER;
131 }
132 if (useAvx && osxsave && (level7.ebx & (1u << 26u))) {
133 detectedCPUFeatureSet |= CPUFeature::AVX512PF;
134 }
135 if (useAvx && osxsave && (level7.ebx & (1u << 30u))) {
136 detectedCPUFeatureSet |= CPUFeature::AVX512BW;
137 }
138 if (useAvx && osxsave && (level7.ebx & (1u << 17u))) {
139 detectedCPUFeatureSet |= CPUFeature::AVX512DQ;
140 }
141 if (useAvx && osxsave && (level7.ebx & (1u << 31u))) {
142 detectedCPUFeatureSet |= CPUFeature::AVX512VL;
143 }
144 }
145
146 CpuId xLevel0(0x80000000u);
147 if (0x80000001u <= xLevel0.eax) {
148 CpuId xLevel1(0x80000001u);
149 if (xLevel1.edx & (1u << 15u)) {
150 detectedCPUFeatureSet |= CPUFeature::CMov;
151 }
152 if (xLevel1.ecx & (1u << 5u)) { // ABM: PopCnt LZCnt
153 detectedCPUFeatureSet |= CPUFeature::PopCnt;
154 detectedCPUFeatureSet |= CPUFeature::LZCnt;
155 }
156 if (xLevel1.ecx & (1u << 11u)) {
157 detectedCPUFeatureSet |= CPUFeature::XOP;
158 }
159 if (xLevel1.ecx & (1 << 6)) {
160 detectedCPUFeatureSet |= CPUFeature::SSE4a;
161 }
162 if (xLevel1.ecx & (1 << 16)) {
163 detectedCPUFeatureSet |= CPUFeature::FMA4;
164 }
165 if (xLevel1.ecx & (1 << 21)) {
166 detectedCPUFeatureSet |= CPUFeature::TBM;
167 }
168
169 }
170#endif
171 restrictTo(CPUFeature::All);
172 LOG_DEBUG(logger, "CPU features: %s", asString().c_str());
173}
174
175Features::~Features()
176{
177
178}
179
180void Features::restrictTo(CPUFeature allowedSet)
181{
182 currentCPUFeatureSet = allowedSet & detectedCPUFeatureSet;
183}
184
185
186std::string Features::asString() const
187{
188 std::vector<std::string> v;
189
190#ifdef COGS_ARCH_X86
191 if (supported(CPUFeature::Intel)) { v.push_back("Intel"); }
192 if (supported(CPUFeature::AMD)) { v.push_back("AMD"); }
193 if (supported(CPUFeature::SSE)) { v.push_back("SSE"); }
194 if (supported(CPUFeature::SSE2)) { v.push_back("SSE2"); }
195 if (supported(CPUFeature::SSE3)) { v.push_back("SSE3"); }
196 if (supported(CPUFeature::SSSE3)) { v.push_back("SSSE3"); }
197 if (supported(CPUFeature::SSE4a)) { v.push_back("SSE4a"); }
198 if (supported(CPUFeature::SSE41)) { v.push_back("SSE41"); }
199 if (supported(CPUFeature::SSE42)) { v.push_back("SSE42"); }
200 if (supported(CPUFeature::XOP)) { v.push_back("XOP"); }
201 if (supported(CPUFeature::AVX)) { v.push_back("AVX"); }
202 if (supported(CPUFeature::AVX2)) { v.push_back("AVX2"); }
203 if (supported(CPUFeature::AVX512F)) { v.push_back("AVX512F"); }
204 if (supported(CPUFeature::AVX512CD)) { v.push_back("AVX512CD"); }
205 if (supported(CPUFeature::AVX512ER)) { v.push_back("AVX512ER"); }
206 if (supported(CPUFeature::AVX512PF)) { v.push_back("AVX512PF"); }
207 if (supported(CPUFeature::AVX512BW)) { v.push_back("AVX512BW"); }
208 if (supported(CPUFeature::AVX512DQ)) { v.push_back("AVX512DQ"); }
209 if (supported(CPUFeature::AVX512VL)) { v.push_back("AVX512VL"); }
210 if (supported(CPUFeature::BMI1)) { v.push_back("BMI1"); }
211 if (supported(CPUFeature::BMI2)) { v.push_back("BMI2"); }
212 if (supported(CPUFeature::FMA3)) { v.push_back("FMA3"); }
213 if (supported(CPUFeature::FMA4)) { v.push_back("FMA4"); }
214 if (supported(CPUFeature::CMov)) { v.push_back("CMov"); }
215 if (supported(CPUFeature::MovBE)) { v.push_back("MovBE"); }
216 if (supported(CPUFeature::PopCnt)) { v.push_back("PopCnt"); }
217 if (supported(CPUFeature::LZCnt)) { v.push_back("LZCnt"); }
218 if (supported(CPUFeature::TBM)) { v.push_back("TBM"); }
219 if (supported(CPUFeature::F16C)) { v.push_back("F16C"); }
220 if (supported(CPUFeature::ADX)) { v.push_back("ADX"); }
221#endif
222
223 if (v.empty()) {
224 return "None";
225 }
226 else {
227 std::stringstream o;
228 for (size_t i = 0; i < v.size(); i++) {
229 o << (i == 0 ? "" : " ") << v[i];
230 }
231
232 return o.str();
233 }
234}
235
236
void restrictTo(CPUFeature allowedSet)
Restrict the set of the detected features to the intersection with allowed features.
Definition: Features.cpp:180
std::string asString() const
Create a space-seperated list of features.
Definition: Features.cpp:186
bool supported(CPUFeature featureSet) const
Check if a set of features are currently supported and enabled.
Definition: Features.h:115
Log implementation class.
Definition: LogManager.h:139
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180