diff --git a/Source/Engine/Platform/Defines.h b/Source/Engine/Platform/Defines.h
index b5b3274e2..29f64052d 100644
--- a/Source/Engine/Platform/Defines.h
+++ b/Source/Engine/Platform/Defines.h
@@ -207,28 +207,22 @@ API_ENUM() enum class ArchitectureType
#define PLATFORM_UNIX_FAMILY (PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_PS4 || PLATFORM_PS5 || PLATFORM_APPLE_FAMILY)
// SIMD defines
-#if defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) || defined(__SSE2__)
+#if !defined(PLATFORM_SIMD_SSE2) && (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64) || defined(__SSE2__))
#define PLATFORM_SIMD_SSE2 1
-#if defined(__SSE3__)
+#if !defined(PLATFORM_SIMD_SSE3) && (defined(__SSE3__))
#define PLATFORM_SIMD_SSE3 1
#endif
-#if defined(__SSE4__)
-#define PLATFORM_SIMD_SSE4 1
-#endif
-#if defined(__SSE4_1__)
+#if !defined(PLATFORM_SIMD_SSE4_1) && (defined(__SSE4_1__))
#define PLATFORM_SIMD_SSE4_1 1
#endif
-#if defined(__SSE4_2__)
+#if !defined(PLATFORM_SIMD_SSE4_2) && (defined(__SSE4_2__))
#define PLATFORM_SIMD_SSE4_2 1
#endif
#endif
-#if defined(_M_ARM) || defined(__ARM_NEON__) || defined(__ARM_NEON)
+#if !defined(PLATFORM_SIMD_NEON) && (defined(_M_ARM) || defined(__ARM_NEON__) || defined(__ARM_NEON))
#define PLATFORM_SIMD_NEON 1
#endif
-#if defined(_M_PPC) || defined(__CELLOS_LV2__)
-#define PLATFORM_SIMD_VMX 1
-#endif
-#define PLATFORM_SIMD (PLATFORM_SIMD_SSE2 || PLATFORM_SIMD_SSE3 || PLATFORM_SIMD_SSE4 || PLATFORM_SIMD_NEON || PLATFORM_SIMD_VMX)
+#define PLATFORM_SIMD (PLATFORM_SIMD_SSE2 || PLATFORM_SIMD_SSE3 || PLATFORM_SIMD_SSE4_1 || PLATFORM_SIMD_SSE4_2 || PLATFORM_SIMD_NEON)
// Unicode text macro
#if !defined(TEXT)
diff --git a/Source/Engine/Platform/Windows/WindowsPlatform.cpp b/Source/Engine/Platform/Windows/WindowsPlatform.cpp
index 272d38cf7..116cb3deb 100644
--- a/Source/Engine/Platform/Windows/WindowsPlatform.cpp
+++ b/Source/Engine/Platform/Windows/WindowsPlatform.cpp
@@ -257,6 +257,37 @@ void GetWindowsVersion(String& windowsName, int32& versionMajor, int32& versionM
RegCloseKey(hKey);
}
+#if PLATFORM_ARCH_X86 || PLATFORM_ARCH_X64
+
+struct CPUBrand
+{
+ char Buffer[0x40];
+
+ CPUBrand()
+ {
+ Buffer[0] = 0;
+ int32 cpuInfo[4];
+ __cpuid(cpuInfo, 0x80000000);
+ if (cpuInfo[0] >= 0x80000004)
+ {
+ // Get name
+ for (uint32 i = 0; i < 3; i++)
+ {
+ __cpuid(cpuInfo, 0x80000002 + i);
+ memcpy(Buffer + i * sizeof(cpuInfo), cpuInfo, sizeof(cpuInfo));
+ }
+
+ // Trim ending whitespaces
+ int32 size = StringUtils::Length(Buffer);
+ while (size > 1 && Buffer[size - 1] == ' ')
+ size--;
+ Buffer[size] = 0;
+ }
+ }
+};
+
+#endif
+
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Find window to process that message
@@ -517,6 +548,60 @@ void WindowsPlatform::PreInit(void* hInstance)
ASSERT(hInstance);
Instance = hInstance;
+#if PLATFORM_ARCH_X86 || PLATFORM_ARCH_X64
+ // Check the minimum vector instruction set support
+ int32 cpuInfo[4] = { -1 };
+ __cpuid(cpuInfo, 0);
+ int32 cpuInfoSize = cpuInfo[0];
+ __cpuid(cpuInfo, 1);
+ bool SSE2 = cpuInfo[3] & (1u << 26);
+ bool SSE3 = cpuInfo[2] & (1u << 0);
+ bool SSE41 = cpuInfo[2] & (1u << 19);
+ bool SSE42 = cpuInfo[2] & (1u << 20);
+ bool AVX = cpuInfo[2] & (1u << 28);
+ bool POPCNT = cpuInfo[2] & (1u << 23);
+ bool AVX2 = false;
+ if (cpuInfoSize >= 7)
+ {
+ __cpuid(cpuInfo, 7);
+ AVX2 = cpuInfo[1] & (1u << 5) && (_xgetbv(0) & 6) == 6;
+ }
+ const Char* missingFeature = nullptr;
+#if defined(__AVX__)
+ if (!AVX)
+ missingFeature = TEXT("AVX");
+#endif
+#if defined(__AVX2__)
+ if (!AVX2)
+ missingFeature = TEXT("AVX2");
+#endif
+#if PLATFORM_SIMD_SSE2
+ if (!SSE2)
+ missingFeature = TEXT("SSE2");
+#endif
+#if PLATFORM_SIMD_SSE3
+ if (!SSE3)
+ missingFeature = TEXT("SSE3");
+#endif
+#if PLATFORM_SIMD_SSE4_1
+ if (!SSE41)
+ missingFeature = TEXT("SSE4.1");
+#endif
+#if PLATFORM_SIMD_SSE4_2
+ if (!SSE42)
+ missingFeature = TEXT("SSE4.2");
+ if (!POPCNT)
+ missingFeature = TEXT("POPCNT");
+#endif
+ if (missingFeature)
+ {
+ // Not supported CPU
+ CPUBrand cpu;
+ Error(String::Format(TEXT("Cannot start program due to lack of CPU feature {}.\n\n{}"), missingFeature, String(cpu.Buffer)));
+ exit(-1);
+ }
+#endif
+
// Disable the process from being showing "ghosted" while not responding messages during slow tasks
DisableProcessWindowsGhosting();
@@ -707,20 +792,8 @@ void WindowsPlatform::LogInfo()
#if PLATFORM_ARCH_X86 || PLATFORM_ARCH_X64
// Log CPU brand
- {
- char brandBuffer[0x40] = {};
- int32 cpuInfo[4] = { -1 };
- __cpuid(cpuInfo, 0x80000000);
- if (cpuInfo[0] >= 0x80000004)
- {
- for (uint32 i = 0; i < 3; i++)
- {
- __cpuid(cpuInfo, 0x80000002 + i);
- memcpy(brandBuffer + i * sizeof(cpuInfo), cpuInfo, sizeof(cpuInfo));
- }
- }
- LOG(Info, "CPU: {0}", String(brandBuffer));
- }
+ CPUBrand cpu;
+ LOG(Info, "CPU: {0}", String(cpu.Buffer));
#endif
LOG(Info, "Microsoft {0} {1}-bit ({2}.{3}.{4})", WindowsName, Platform::Is64BitPlatform() ? TEXT("64") : TEXT("32"), VersionMajor, VersionMinor, VersionBuild);
diff --git a/Source/Tools/Flax.Build/Build/NativeCpp/CompileEnvironment.cs b/Source/Tools/Flax.Build/Build/NativeCpp/CompileEnvironment.cs
index 81c620592..7da495b46 100644
--- a/Source/Tools/Flax.Build/Build/NativeCpp/CompileEnvironment.cs
+++ b/Source/Tools/Flax.Build/Build/NativeCpp/CompileEnvironment.cs
@@ -84,6 +84,47 @@ namespace Flax.Build.NativeCpp
Latest,
}
+ ///
+ /// The SIMD architecture to use for code generation.
+ ///
+ public enum CpuArchitecture
+ {
+ ///
+ /// No specific architecture set.
+ ///
+ None,
+
+ ///
+ /// Intel Advanced Vector Extensions.
+ ///
+ AVX,
+
+ ///
+ /// Enables Intel Advanced Vector Extensions 2.
+ ///
+ AVX2,
+
+ ///
+ /// Intel Advanced Vector Extensions 512.
+ ///
+ AVX512,
+
+ ///
+ /// Intel Streaming SIMD Extensions 2.
+ ///
+ SSE2,
+
+ ///
+ /// Intel Streaming SIMD Extensions 4.2.
+ ///
+ SSE4_2,
+
+ ///
+ /// ARM Neon.
+ ///
+ NEON,
+ }
+
///
/// The C++ compilation environment required to build source files in the native modules.
///
@@ -104,6 +145,11 @@ namespace Flax.Build.NativeCpp
///
public Sanitizer Sanitizers = Sanitizer.None;
+ ///
+ /// SIMD architecture to use.
+ ///
+ public CpuArchitecture CpuArchitecture = CpuArchitecture.None;
+
///
/// Enables exceptions support.
///
@@ -222,6 +268,7 @@ namespace Flax.Build.NativeCpp
CppVersion = CppVersion,
FavorSizeOrSpeed = FavorSizeOrSpeed,
Sanitizers = Sanitizers,
+ CpuArchitecture = CpuArchitecture,
EnableExceptions = EnableExceptions,
RuntimeTypeInfo = RuntimeTypeInfo,
Inlining = Inlining,
diff --git a/Source/Tools/Flax.Build/Build/Target.cs b/Source/Tools/Flax.Build/Build/Target.cs
index 4deecb414..fe3a4e075 100644
--- a/Source/Tools/Flax.Build/Build/Target.cs
+++ b/Source/Tools/Flax.Build/Build/Target.cs
@@ -248,6 +248,25 @@ namespace Flax.Build
Modules.Add("Main");
}
+ switch (options.CompileEnv.CpuArchitecture)
+ {
+ case CpuArchitecture.AVX:
+ case CpuArchitecture.SSE2:
+ // Basic SEE2
+ options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_SIMD_SSE2=1"); break;
+ case CpuArchitecture.AVX2:
+ case CpuArchitecture.SSE4_2:
+ // Assume full support of SEE4.2 and older
+ options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_SIMD_SSE2=1");
+ options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_SIMD_SSE3=1");
+ options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_SIMD_SSE4_1=1");
+ options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_SIMD_SSE4_2=1");
+ break;
+ case CpuArchitecture.NEON:
+ options.CompileEnv.PreprocessorDefinitions.Add("PLATFORM_SIMD_NEON=1");
+ break;
+ }
+
options.CompileEnv.EnableExceptions = true; // TODO: try to disable this!
options.CompileEnv.Sanitizers = Configuration.Sanitizers;
switch (options.Configuration)
diff --git a/Source/Tools/Flax.Build/Build/Toolchain.cs b/Source/Tools/Flax.Build/Build/Toolchain.cs
index ca05cecc4..d67766cf8 100644
--- a/Source/Tools/Flax.Build/Build/Toolchain.cs
+++ b/Source/Tools/Flax.Build/Build/Toolchain.cs
@@ -102,6 +102,11 @@ namespace Flax.Build
{
options.CompileEnv.IncludePaths.AddRange(SystemIncludePaths);
options.LinkEnv.LibraryPaths.AddRange(SystemLibraryPaths);
+
+ if (options.Architecture == TargetArchitecture.x64 || options.Architecture == TargetArchitecture.x86)
+ options.CompileEnv.CpuArchitecture = CpuArchitecture.AVX;
+ else if (options.Architecture == TargetArchitecture.ARM64 || options.Architecture == TargetArchitecture.ARM)
+ options.CompileEnv.CpuArchitecture = CpuArchitecture.NEON;
}
///
diff --git a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchain.cs b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchain.cs
index 428cc2437..7537cdecf 100644
--- a/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchain.cs
+++ b/Source/Tools/Flax.Build/Platforms/Windows/WindowsToolchain.cs
@@ -15,6 +15,12 @@ namespace Flax.Build
///
[CommandLine("winMinVer", "", "Specifies the minimum Windows version to use (eg. 10).")]
public static string WindowsMinVer = "10";
+
+ ///
+ /// Specifies the minimum CPU architecture type to support (on x86/x64).
+ ///
+ [CommandLine("winCpuArch", "", "Specifies the minimum CPU architecture type to support (om x86/x64).")]
+ public static CpuArchitecture WindowsCpuArch = CpuArchitecture.AVX2; // 94.48% support on PC according to Steam Hardware & Software Survey: May 2025 (https://store.steampowered.com/hwsurvey/)
}
}
@@ -80,6 +86,18 @@ namespace Flax.Build.Platforms
options.CompileEnv.PreprocessorDefinitions.Add("USE_SOFT_INTRINSICS");
options.LinkEnv.InputLibraries.Add("softintrin.lib");
}
+
+ options.CompileEnv.CpuArchitecture = Configuration.WindowsCpuArch;
+ if (_minVersion.Major <= 7 && options.CompileEnv.CpuArchitecture == CpuArchitecture.AVX2)
+ {
+ // Old Windows had lower support ratio for latest CPU features
+ options.CompileEnv.CpuArchitecture = CpuArchitecture.AVX;
+ }
+ if (_minVersion.Major >= 11 && options.CompileEnv.CpuArchitecture == CpuArchitecture.AVX)
+ {
+ // Windows 11 has hard requirement on SSE4.2
+ options.CompileEnv.CpuArchitecture = CpuArchitecture.SSE4_2;
+ }
}
///
@@ -87,10 +105,13 @@ namespace Flax.Build.Platforms
{
base.SetupCompileCppFilesArgs(graph, options, args);
- if (Toolset >= WindowsPlatformToolset.v142 && _minVersion.Major >= 11)
+ switch (options.CompileEnv.CpuArchitecture)
{
- // Windows 11 requires SSE4.2
- args.Add("/d2archSSE42");
+ case CpuArchitecture.AVX: args.Add("/arch:AVX"); break;
+ case CpuArchitecture.AVX2: args.Add("/arch:AVX2"); break;
+ case CpuArchitecture.AVX512: args.Add("/arch:AVX512"); break;
+ case CpuArchitecture.SSE2: args.Add("/arch:SSE2"); break;
+ case CpuArchitecture.SSE4_2: args.Add("/arch:SSE4.2"); break;
}
}