diff --git a/include/libyuv/cpu_id.h b/include/libyuv/cpu_id.h index 91480c68b..0229cb5e7 100644 --- a/include/libyuv/cpu_id.h +++ b/include/libyuv/cpu_id.h @@ -80,6 +80,31 @@ int ArmCpuCaps(const char* cpuinfo_name); LIBYUV_API int MaskCpuFlags(int enable_flags); +// Sets the CPU flags to |cpu_flags|, bypassing the detection code. |cpu_flags| +// should be a valid combination of the kCpuHas constants above and include +// kCpuInitialized. Use this method when running in a sandboxed process where +// the detection code might fail (as it might access /proc/cpuinfo). In such +// cases the cpu_info can be obtained from a non sandboxed process by calling +// InitCpuFlags() and passed to the sandboxed process (via command line +// parameters, IPC...) which can then call this method to initialize the CPU +// flags. +// Notes: +// - when specifying 0 for |cpu_flags|, the auto initialization is enabled +// again. +// - enabling CPU features that are not supported by the CPU will result in +// undefined behavior. +// TODO(fbarchard): consider writing a helper function that translates from +// other library CPU info to libyuv CPU info and add a .md doc that explains +// CPU detection. +static __inline void SetCpuFlags(int cpu_flags) { + LIBYUV_API extern int cpu_info_; +#ifdef __ATOMIC_RELAXED + __atomic_store_n(&cpu_info_, cpu_flags, __ATOMIC_RELAXED); +#else + cpu_info_ = cpu_flags; +#endif +} + // Low level cpuid for X86. Returns zeros on other CPUs. // eax is the info type that you want. // ecx is typically the cpu number, and should normally be zero. diff --git a/source/cpu_id.cc b/source/cpu_id.cc index 36cde933b..31e24b673 100644 --- a/source/cpu_id.cc +++ b/source/cpu_id.cc @@ -261,11 +261,7 @@ static SAFEBUFFERS int GetCpuFlags(void) { LIBYUV_API int MaskCpuFlags(int enable_flags) { int cpu_info = GetCpuFlags() & enable_flags; -#ifdef __ATOMIC_RELAXED - __atomic_store_n(&cpu_info_, cpu_info, __ATOMIC_RELAXED); -#else - cpu_info_ = cpu_info; -#endif + SetCpuFlags(cpu_info); return cpu_info; } diff --git a/unit_test/cpu_test.cc b/unit_test/cpu_test.cc index 62d52ec3d..c4648bb94 100644 --- a/unit_test/cpu_test.cc +++ b/unit_test/cpu_test.cc @@ -158,4 +158,27 @@ TEST_F(LibYUVBaseTest, TestLinuxNeon) { #endif } +TEST_F(LibYUVBaseTest, TestSetCpuFlags) { + // Reset any masked flags that may have been set so auto init is enabled. + MaskCpuFlags(0); + + int original_cpu_flags = TestCpuFlag(-1); + + // Test setting different CPU configurations. + int cpu_flags = kCpuHasARM | kCpuHasNEON | kCpuInitialized; + SetCpuFlags(cpu_flags); + EXPECT_EQ(cpu_flags, TestCpuFlag(-1)); + + cpu_flags = kCpuHasX86 | kCpuInitialized; + SetCpuFlags(cpu_flags); + EXPECT_EQ(cpu_flags, TestCpuFlag(-1)); + + // Test that setting 0 turns auto-init back on. + SetCpuFlags(0); + EXPECT_EQ(original_cpu_flags, TestCpuFlag(-1)); + + // Restore the CPU flag mask. + MaskCpuFlags(benchmark_cpu_info_); +} + } // namespace libyuv