File indexing completed on 2024-05-19 04:27:07
0001 /* 0002 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "KisSupportedArchitectures.h" 0008 0009 #include <KConfigGroup> 0010 #include <KSharedConfig> 0011 #include <kis_debug.h> 0012 0013 #include "xsimd_extensions/xsimd.hpp" 0014 0015 std::tuple<bool, bool> vectorizationConfiguration() 0016 { 0017 static const std::tuple<bool, bool> vectorization = [&]() { 0018 KConfigGroup cfg = KSharedConfig::openConfig()->group(""); 0019 // use the old key name for compatibility 0020 const bool useVectorization = 0021 !cfg.readEntry("amdDisableVectorWorkaround", false); 0022 const bool disableAVXOptimizations = 0023 cfg.readEntry("disableAVXOptimizations", false); 0024 0025 return std::make_tuple(useVectorization, disableAVXOptimizations); 0026 }(); 0027 0028 return vectorization; 0029 } 0030 0031 QString KisSupportedArchitectures::baseArchName() 0032 { 0033 return xsimd::current_arch::name(); 0034 } 0035 0036 QString KisSupportedArchitectures::bestArchName() 0037 { 0038 #ifdef HAVE_XSIMD 0039 const unsigned int best_arch = xsimd::available_architectures().best; 0040 0041 #ifdef Q_PROCESSOR_X86 0042 bool useVectorization = true; 0043 bool disableAVXOptimizations = false; 0044 0045 std::tie(useVectorization, disableAVXOptimizations) = 0046 vectorizationConfiguration(); 0047 0048 if (!useVectorization) { 0049 qWarning() << "WARNING: vector instructions disabled by the " 0050 "\'amdDisableVectorWorkaround\' option!"; 0051 return "Scalar"; 0052 } 0053 0054 if (disableAVXOptimizations 0055 && (xsimd::avx::version() <= best_arch 0056 || xsimd::avx2::version() <= best_arch)) { 0057 qWarning() << "WARNING: AVX and AVX2 optimizations are disabled by the " 0058 "\'disableAVXOptimizations\' option!"; 0059 } 0060 0061 /** 0062 * We use SSE2, SSSE3, SSE4.1, AVX and AVX2+FMA. 0063 * The rest are integer and string instructions mostly. 0064 */ 0065 if (!disableAVXOptimizations 0066 && xsimd::fma3<xsimd::avx2>::version() <= best_arch) { 0067 return xsimd::fma3<xsimd::avx2>::name(); 0068 } else if (!disableAVXOptimizations && xsimd::avx::version() <= best_arch) { 0069 return xsimd::avx::name(); 0070 } else if (xsimd::sse4_1::version() <= best_arch) { 0071 return xsimd::sse4_1::name(); 0072 } else if (xsimd::ssse3::version() <= best_arch) { 0073 return xsimd::ssse3::name(); 0074 } else if (xsimd::sse2::version() <= best_arch) { 0075 return xsimd::sse2::name(); 0076 } 0077 #elif XSIMD_WITH_NEON64 0078 if (xsimd::neon64::version() <= best_arch) { 0079 return xsimd::neon64::name(); 0080 } 0081 #elif XSIMD_WITH_NEON 0082 if (xsimd::neon::version() <= best_arch) { 0083 return xsimd::neon::name(); 0084 } 0085 #endif // XSIMD_WITH_SSE2 0086 #endif // HAVE_XSIMD 0087 return xsimd::current_arch::name(); 0088 } 0089 0090 unsigned int KisSupportedArchitectures::bestArch() 0091 { 0092 #ifdef HAVE_XSIMD 0093 const unsigned int best_arch = xsimd::available_architectures().best; 0094 0095 #ifdef Q_PROCESSOR_X86 0096 bool useVectorization = true; 0097 bool disableAVXOptimizations = false; 0098 0099 std::tie(useVectorization, disableAVXOptimizations) = 0100 vectorizationConfiguration(); 0101 0102 if (!useVectorization) { 0103 qWarning() << "WARNING: vector instructions disabled by the " 0104 "\'amdDisableVectorWorkaround\' option!"; 0105 return 0; 0106 } 0107 0108 if (disableAVXOptimizations 0109 && (xsimd::avx::version() <= best_arch 0110 || xsimd::avx2::version() <= best_arch)) { 0111 qWarning() << "WARNING: AVX and AVX2 optimizations are disabled by the " 0112 "\'disableAVXOptimizations\' option!"; 0113 } 0114 0115 /** 0116 * We use SSE2, SSSE3, SSE4.1, AVX and AVX2+FMA. 0117 * The rest are integer and string instructions mostly. 0118 */ 0119 if (!disableAVXOptimizations 0120 && xsimd::fma3<xsimd::avx2>::version() <= best_arch) { 0121 return xsimd::fma3<xsimd::avx2>::version(); 0122 } else if (!disableAVXOptimizations && xsimd::avx::version() <= best_arch) { 0123 return xsimd::avx::version(); 0124 } else if (xsimd::sse4_1::version() <= best_arch) { 0125 return xsimd::sse4_1::version(); 0126 } else if (xsimd::ssse3::version() <= best_arch) { 0127 return xsimd::ssse3::version(); 0128 } else if (xsimd::sse2::version() <= best_arch) { 0129 return xsimd::sse2::version(); 0130 } 0131 #elif XSIMD_WITH_NEON64 0132 if (xsimd::neon64::version() <= best_arch) { 0133 return xsimd::neon64::version(); 0134 } 0135 #elif XSIMD_WITH_NEON 0136 if (xsimd::neon::version() <= best_arch) { 0137 return xsimd::neon::version(); 0138 } 0139 #endif // XSIMD_WITH_SSE2 0140 #endif // HAVE_XSIMD 0141 0142 return 0; 0143 } 0144 0145 template<typename S> 0146 struct is_supported_arch { 0147 is_supported_arch(S &log) 0148 : l(log) 0149 { 0150 } 0151 0152 template<typename A> 0153 void operator()(A) const 0154 { 0155 #ifdef HAVE_XSIMD 0156 if (A::version() <= xsimd::available_architectures().best) { 0157 l.append(A::name()).append(" "); 0158 } 0159 #endif 0160 } 0161 0162 S &l; 0163 }; 0164 0165 QString KisSupportedArchitectures::supportedInstructionSets() 0166 { 0167 static const QString archs = []() { 0168 QString archs; 0169 #ifdef HAVE_XSIMD 0170 xsimd::all_architectures::for_each(is_supported_arch<QString>{archs}); 0171 #endif 0172 return archs; 0173 }(); 0174 return archs; 0175 }