From c6b50d2645222b2ef48d4aaf87a5edd65cdcd415 Mon Sep 17 00:00:00 2001 From: Themaister Date: Thu, 1 Nov 2012 22:31:24 +0100 Subject: [PATCH] Add CPU feature detection for X86. --- Makefile | 6 ++--- performance.c | 60 +++++++++++++++++++++++++++++++++++++++++++--- performance.h | 15 ++++++++---- retroarch.c | 29 ++++++++++++++++++---- retroarch_logger.h | 2 +- 5 files changed, 97 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 34f84d6a33..842a9f324a 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,8 @@ OBJ = retroarch.o \ gfx/scaler/scaler.o \ gfx/scaler/pixconv.o \ gfx/scaler/scaler_int.o \ - gfx/scaler/filter.o + gfx/scaler/filter.o \ + performance.o JOYCONFIG_OBJ = tools/retroarch-joyconfig.o \ conf/config_file.o \ @@ -56,7 +57,7 @@ endif ifneq ($(findstring Linux,$(OS)),) LIBS += -lrt - OBJ += input/linuxraw_input.o input/linuxraw_joypad.o performance/performance_linux.o + OBJ += input/linuxraw_input.o input/linuxraw_joypad.o JOYCONFIG_OBJ += input/linuxraw_joypad.o endif @@ -143,7 +144,6 @@ endif ifeq ($(PERF_TEST), 1) DEFINES += -DPERF_TEST - OBJ += performance.o endif ifeq ($(HAVE_SDL), 1) diff --git a/performance.c b/performance.c index ad2553d908..512ce61c45 100644 --- a/performance.c +++ b/performance.c @@ -16,6 +16,8 @@ #include "performance.h" +#ifdef PERF_TEST + #if defined(__CELLOS_LV2__) || defined(GEKKO) #ifndef _PPU_INTRINSICS_H #include @@ -46,8 +48,6 @@ void rarch_perf_log(void) RARCH_PERFORMANCE_LOG(perf_counters[i]->ident, *perf_counters[i]); } - - rarch_perf_tick_t rarch_get_perf_counter(void) { rarch_perf_tick_t time = 0; @@ -69,7 +69,7 @@ rarch_perf_tick_t rarch_get_perf_counter(void) #elif defined(__GNUC__) && !defined(RARCH_CONSOLE) -#if defined(__i386__) || defined(__i486__) +#if defined(__i386__) || defined(__i486__) || defined(__i686__) asm volatile ("rdtsc" : "=A" (time)); #elif defined(__x86_64__) unsigned a, d; @@ -85,3 +85,57 @@ rarch_perf_tick_t rarch_get_perf_counter(void) return time; } +#endif + +#if defined(__x86_64__) || defined(__i386__) || defined(__i486__) || defined(__i686__) +#define CPU_X86 +#endif + +#ifdef _MSC_VER +#include +#endif + +#ifdef CPU_X86 +static void x86_cpuid(int func, int flags[4]) +{ +#ifdef __GNUC__ + asm volatile("cpuid\n" : + "=a"(flags[0]), + "=b"(flags[1]), + "=c"(flags[2]), + "=d"(flags[3]) : "a"(func)); +#elif defined(_MSC_VER) + __cpuid(flags, func); +#endif +} +#endif + +void rarch_get_cpu_features(struct rarch_cpu_features *cpu) +{ + memset(cpu, 0, sizeof(*cpu)); + +#ifdef CPU_X86 + int flags[4]; + x86_cpuid(0, flags); + + char vendor[13] = {0}; + const int vendor_shuffle[3] = { flags[1], flags[3], flags[2] }; + memcpy(vendor, vendor_shuffle, sizeof(vendor_shuffle)); + RARCH_LOG("[CPUID]: Vendor: %s\n", vendor); + + if (flags[0] < 1) // Does CPUID not support func = 1? (unlikely ...) + return; + + x86_cpuid(1, flags); + cpu->sse = flags[3] & (1 << 25); + cpu->sse2 = flags[3] & (1 << 26); + + int avx_flags = (1 << 27) | (1 << 28); + cpu->avx = (flags[2] & avx_flags) == avx_flags; // Is this enough? + + RARCH_LOG("[CPUID]: SSE: %d\n", cpu->sse); + RARCH_LOG("[CPUID]: SSE2: %d\n", cpu->sse2); + RARCH_LOG("[CPUID]: AVX: %d\n", cpu->avx); +#endif +} + diff --git a/performance.h b/performance.h index 39154a61e9..a712061546 100644 --- a/performance.h +++ b/performance.h @@ -23,10 +23,6 @@ #include "config.h" #endif -#ifdef __linux -#include "performance/performance_linux.h" -#endif - #include typedef unsigned long long rarch_perf_tick_t; @@ -44,6 +40,17 @@ rarch_perf_tick_t rarch_get_perf_counter(void); void rarch_perf_register(struct rarch_perf_counter *perf); void rarch_perf_log(void); +struct rarch_cpu_features +{ + bool sse; + bool sse2; + bool vmx; + bool avx; + bool neon; +}; + +void rarch_get_cpu_features(struct rarch_cpu_features *cpu); + #ifdef PERF_TEST #define RARCH_PERFORMANCE_INIT(X) static rarch_perf_counter_t X = {#X}; \ diff --git a/retroarch.c b/retroarch.c index 09f2c939c4..6bfb3f24a8 100644 --- a/retroarch.c +++ b/retroarch.c @@ -2539,6 +2539,30 @@ static void verify_api_version(void) RARCH_WARN("RetroArch is compiled against a different version of libretro than this libretro implementation.\n"); } +// Make sure we haven't compiled for something we cannot run. +// Ideally, code would get swapped out depending on CPU support, but this will do for now. +static void validate_cpu_features(void) +{ + struct rarch_cpu_features cpu; + rarch_get_cpu_features(&cpu); + +#ifdef __SSE2__ + if (!cpu.sse2) + { + RARCH_ERR("SSE2 code is compiled in, but CPU does not support this feature. Cannot continue.\n"); + rarch_fail(1, "validate_cpu_features()"); + } +#endif + +#ifdef __AVX__ + if (!cpu.avx) + { + RARCH_ERR("AVX code is compiled in, but CPU does not support this feature. Cannot continue.\n"); + rarch_fail(1, "validate_cpu_features()"); + } +#endif +} + int rarch_main_init(int argc, char *argv[]) { init_state(); @@ -2550,7 +2574,6 @@ int rarch_main_init(int argc, char *argv[]) return sjlj_ret; } g_extern.error_in_init = true; - parse_input(argc, argv); if (g_extern.verbose) @@ -2560,6 +2583,7 @@ int rarch_main_init(int argc, char *argv[]) RARCH_LOG_OUTPUT("=================================================\n"); } + validate_cpu_features(); config_load(); init_libretro_sym(); @@ -2792,9 +2816,6 @@ int rarch_main(int argc, char *argv[]) // Consoles use the higher level API. int main(int argc, char *argv[]) { -#if 0 - rarch_perf_get_cpu_features(); -#endif return rarch_main(argc, argv); } #endif diff --git a/retroarch_logger.h b/retroarch_logger.h index a75dce425b..6b31963b70 100644 --- a/retroarch_logger.h +++ b/retroarch_logger.h @@ -56,7 +56,7 @@ #define RARCH_LOG_OUTPUT(...) do { \ if (g_extern.verbose) \ { \ - fprintf(stderr, "stderr: " __VA_ARGS__); \ + fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } \ } while (0)