/src/skia/src/core/SkCpu.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2016 Google Inc. |
3 | | * |
4 | | * Use of this source code is governed by a BSD-style license that can be |
5 | | * found in the LICENSE file. |
6 | | */ |
7 | | |
8 | | #ifndef SkCpu_DEFINED |
9 | | #define SkCpu_DEFINED |
10 | | |
11 | | #include "include/core/SkTypes.h" |
12 | | |
13 | | struct SkCpu { |
14 | | enum { |
15 | | SSE1 = 1 << 0, |
16 | | SSE2 = 1 << 1, |
17 | | SSE3 = 1 << 2, |
18 | | SSSE3 = 1 << 3, |
19 | | SSE41 = 1 << 4, |
20 | | SSE42 = 1 << 5, |
21 | | AVX = 1 << 6, |
22 | | F16C = 1 << 7, |
23 | | FMA = 1 << 8, |
24 | | AVX2 = 1 << 9, |
25 | | BMI1 = 1 << 10, |
26 | | BMI2 = 1 << 11, |
27 | | // Handy alias for all the cool Haswell+ instructions. |
28 | | HSW = AVX2 | BMI1 | BMI2 | F16C | FMA, |
29 | | |
30 | | AVX512F = 1 << 12, |
31 | | AVX512DQ = 1 << 13, |
32 | | AVX512IFMA = 1 << 14, |
33 | | AVX512PF = 1 << 15, |
34 | | AVX512ER = 1 << 16, |
35 | | AVX512CD = 1 << 17, |
36 | | AVX512BW = 1 << 18, |
37 | | AVX512VL = 1 << 19, |
38 | | |
39 | | // Handy alias for all the cool Skylake Xeon+ instructions. |
40 | | SKX = AVX512F | AVX512DQ | AVX512CD | AVX512BW | AVX512VL, |
41 | | |
42 | | ERMS = 1 << 20, |
43 | | }; |
44 | | enum { |
45 | | NEON = 1 << 0, |
46 | | NEON_FMA = 1 << 1, |
47 | | VFP_FP16 = 1 << 2, |
48 | | CRC32 = 1 << 3, |
49 | | ASIMDHP = 1 << 4, |
50 | | }; |
51 | | |
52 | | static void CacheRuntimeFeatures(); |
53 | | static bool Supports(uint32_t); |
54 | | private: |
55 | | static uint32_t gCachedFeatures; |
56 | | }; |
57 | | |
58 | 10 | inline bool SkCpu::Supports(uint32_t mask) { |
59 | 10 | uint32_t features = gCachedFeatures; |
60 | | |
61 | | // If we mask in compile-time known lower limits, the compiler can |
62 | | // often compile away this entire function. |
63 | 10 | #if SK_CPU_X86 |
64 | 10 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1 |
65 | 10 | features |= SSE1; |
66 | 10 | #endif |
67 | 10 | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
68 | 10 | features |= SSE2; |
69 | 10 | #endif |
70 | | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE3 |
71 | | features |= SSE3; |
72 | | #endif |
73 | | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 |
74 | | features |= SSSE3; |
75 | | #endif |
76 | | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE41 |
77 | | features |= SSE41; |
78 | | #endif |
79 | | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE42 |
80 | | features |= SSE42; |
81 | | #endif |
82 | | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX |
83 | | features |= AVX; |
84 | | #endif |
85 | | // F16C goes here if we add SK_CPU_SSE_LEVEL_F16C |
86 | | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2 |
87 | | features |= AVX2; |
88 | | #endif |
89 | | #if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SKX |
90 | | features |= (AVX512F | AVX512DQ | AVX512CD | AVX512BW | AVX512VL); |
91 | | #endif |
92 | | // FMA doesn't fit neatly into this total ordering. |
93 | | // It's available on Haswell+ just like AVX2, but it's technically a different bit. |
94 | | // TODO: circle back on this if we find ourselves limited by lack of compile-time FMA |
95 | | |
96 | | #if defined(SK_CPU_LIMIT_AVX) |
97 | | features &= (SSE1 | SSE2 | SSE3 | SSSE3 | SSE41 | SSE42 | AVX); |
98 | | #elif defined(SK_CPU_LIMIT_SSE41) |
99 | | features &= (SSE1 | SSE2 | SSE3 | SSSE3 | SSE41); |
100 | | #elif defined(SK_CPU_LIMIT_SSE2) |
101 | | features &= (SSE1 | SSE2); |
102 | | #endif |
103 | | |
104 | | #else |
105 | | #if defined(SK_ARM_HAS_NEON) |
106 | | features |= NEON; |
107 | | #endif |
108 | | |
109 | | #if defined(SK_CPU_ARM64) |
110 | | features |= NEON|NEON_FMA|VFP_FP16; |
111 | | #endif |
112 | | |
113 | | #if defined(SK_ARM_HAS_CRC32) |
114 | | features |= CRC32; |
115 | | #endif |
116 | | |
117 | | #endif |
118 | 10 | return (features & mask) == mask; |
119 | 10 | } |
120 | | |
121 | | #endif//SkCpu_DEFINED |