Update to spice2x-25-04-25 (pre-apply)
> broken commit
This commit is contained in:
Vendored
-8614
File diff suppressed because it is too large
Load Diff
Vendored
+11
-1
@@ -7,6 +7,7 @@
|
||||
#include "cardio_window.h"
|
||||
|
||||
bool CARDIO_RUNNER_FLIP = false;
|
||||
bool CARDIO_RUNNER_TOGGLE = false;
|
||||
static bool CARDIO_RUNNER_INITIALIZED = false;
|
||||
static std::thread* CARDIO_RUNNER_THREAD = nullptr;
|
||||
static HWND CARDIO_RUNNER_HWND = NULL;
|
||||
@@ -71,8 +72,17 @@ void cardio_runner_start(bool scan_hid) {
|
||||
// if card not empty
|
||||
if (*((uint64_t*) &device->usage_value[0]) > 0) {
|
||||
|
||||
bool flip_order = CARDIO_RUNNER_FLIP;
|
||||
if (CARDIO_RUNNER_FLIP) {
|
||||
log_info("cardio", "Flip order of readers since flip option is set");
|
||||
}
|
||||
if (CARDIO_RUNNER_TOGGLE && (GetKeyState(VK_NUMLOCK) & 1) > 0) {
|
||||
log_info("cardio", "Flip order of readers since Num Lock is on");
|
||||
flip_order = !flip_order;
|
||||
}
|
||||
|
||||
// insert card
|
||||
if (CARDIO_RUNNER_FLIP)
|
||||
if (flip_order)
|
||||
eamuse_card_insert((int) (device_no + 1) & 1, &device->usage_value[0]);
|
||||
else
|
||||
eamuse_card_insert((int) device_no & 1, &device->usage_value[0]);
|
||||
|
||||
Vendored
+1
@@ -2,6 +2,7 @@
|
||||
#define SPICETOOLS_CARDIO_RUNNER_H
|
||||
|
||||
extern bool CARDIO_RUNNER_FLIP;
|
||||
extern bool CARDIO_RUNNER_TOGGLE;
|
||||
|
||||
void cardio_runner_start(bool scan_hid);
|
||||
void cardio_runner_stop();
|
||||
|
||||
Vendored
+4
@@ -0,0 +1,4 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
...
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
# Project Files unneeded by docker
|
||||
.git
|
||||
.gitignore
|
||||
.github
|
||||
.dockerignore
|
||||
.clang-format
|
||||
appveyor.yml
|
||||
.travis.yml
|
||||
AUTHORS
|
||||
CONTRIBUTING.md
|
||||
CONTRIBUTORS
|
||||
LICENSE
|
||||
README.md
|
||||
|
||||
bazel/ci/Makefile
|
||||
bazel/ci/docker
|
||||
bazel/ci/doc
|
||||
|
||||
cmake/ci/Makefile
|
||||
cmake/ci/docker
|
||||
cmake/ci/doc
|
||||
cmake/ci/cache
|
||||
|
||||
build/
|
||||
cmake_build/
|
||||
build_cross/
|
||||
cmake-build-*/
|
||||
out/
|
||||
|
||||
# Editor directories and files
|
||||
.idea/
|
||||
.vagrant/
|
||||
.vscode/
|
||||
.vs/
|
||||
*.user
|
||||
*.swp
|
||||
@@ -0,0 +1,19 @@
|
||||
# Build folders
|
||||
build/
|
||||
cmake_build/
|
||||
build_cross/
|
||||
cmake-build-*/
|
||||
out/
|
||||
|
||||
# IDEs / CI temp files
|
||||
.idea/
|
||||
.vagrant/
|
||||
.vscode/
|
||||
.vs/
|
||||
*.swp
|
||||
|
||||
# Bazel artifacts
|
||||
**/bazel-*
|
||||
|
||||
# Per-user bazelrc files
|
||||
user.bazelrc
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
---
|
||||
dataSource: "prs"
|
||||
ignoreLabels:
|
||||
- "Apple M1"
|
||||
- "duplicate"
|
||||
- "help wanted"
|
||||
- "invalid"
|
||||
- "question"
|
||||
- "wontfix"
|
||||
onlyMilestones: false
|
||||
groupBy:
|
||||
"API Change":
|
||||
- "API Change"
|
||||
"New features / Enhancements":
|
||||
- "enhancement"
|
||||
- "internal"
|
||||
"Bug Fixes":
|
||||
- "bug"
|
||||
"Misc":
|
||||
- "misc"
|
||||
changelogFilename: "CHANGELOG.md"
|
||||
Vendored
+378
@@ -0,0 +1,378 @@
|
||||
# cpu_features, a cross platform C99 library to get cpu features at runtime.
|
||||
|
||||
load("@bazel_skylib//lib:selects.bzl", "selects")
|
||||
load("//:bazel/platforms.bzl", "PLATFORM_CPU_ARM", "PLATFORM_CPU_ARM64", "PLATFORM_CPU_MIPS", "PLATFORM_CPU_PPC", "PLATFORM_CPU_RISCV32", "PLATFORM_CPU_RISCV64", "PLATFORM_CPU_X86_64")
|
||||
load("//:bazel/platforms.bzl", "PLATFORM_OS_MACOS")
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
licenses = ["notice"],
|
||||
)
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
INCLUDES = ["include"]
|
||||
|
||||
C99_FLAGS = [
|
||||
"-std=c99",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wmissing-declarations",
|
||||
"-Wmissing-prototypes",
|
||||
"-Wno-implicit-fallthrough",
|
||||
"-Wno-unused-function",
|
||||
"-Wold-style-definition",
|
||||
"-Wshadow",
|
||||
"-Wsign-compare",
|
||||
"-Wstrict-prototypes",
|
||||
]
|
||||
|
||||
cc_library(
|
||||
name = "cpu_features_macros",
|
||||
copts = C99_FLAGS,
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = ["include/cpu_features_macros.h"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpu_features_cache_info",
|
||||
copts = C99_FLAGS,
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = ["include/cpu_features_cache_info.h"],
|
||||
deps = [":cpu_features_macros"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "bit_utils",
|
||||
copts = C99_FLAGS,
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = ["include/internal/bit_utils.h"],
|
||||
deps = [":cpu_features_macros"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "bit_utils_test",
|
||||
srcs = ["test/bit_utils_test.cc"],
|
||||
includes = INCLUDES,
|
||||
deps = [
|
||||
":bit_utils",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "memory_utils",
|
||||
copts = C99_FLAGS,
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = [
|
||||
"src/copy.inl",
|
||||
"src/equals.inl",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "string_view",
|
||||
srcs = [
|
||||
"src/string_view.c",
|
||||
],
|
||||
copts = C99_FLAGS,
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = ["include/internal/string_view.h"],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":memory_utils",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "string_view_test",
|
||||
srcs = ["test/string_view_test.cc"],
|
||||
includes = INCLUDES,
|
||||
deps = [
|
||||
":string_view",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "filesystem",
|
||||
srcs = ["src/filesystem.c"],
|
||||
copts = C99_FLAGS,
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = ["include/internal/filesystem.h"],
|
||||
deps = [":cpu_features_macros"],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "filesystem_for_testing",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"src/filesystem.c",
|
||||
"test/filesystem_for_testing.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"include/internal/filesystem.h",
|
||||
"test/filesystem_for_testing.h",
|
||||
],
|
||||
defines = ["CPU_FEATURES_MOCK_FILESYSTEM"],
|
||||
includes = INCLUDES,
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "stack_line_reader",
|
||||
srcs = ["src/stack_line_reader.c"],
|
||||
copts = C99_FLAGS,
|
||||
defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = ["include/internal/stack_line_reader.h"],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "stack_line_reader_test",
|
||||
srcs = [
|
||||
"include/internal/stack_line_reader.h",
|
||||
"src/stack_line_reader.c",
|
||||
"test/stack_line_reader_test.cc",
|
||||
],
|
||||
defines = ["STACK_LINE_READER_BUFFER_SIZE=16"],
|
||||
includes = INCLUDES,
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem_for_testing",
|
||||
":string_view",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "stack_line_reader_to_use_with_filesystem_for_testing",
|
||||
testonly = 1,
|
||||
srcs = ["src/stack_line_reader.c"],
|
||||
hdrs = ["include/internal/stack_line_reader.h"],
|
||||
copts = C99_FLAGS,
|
||||
defines = ["STACK_LINE_READER_BUFFER_SIZE=1024"],
|
||||
includes = INCLUDES,
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem_for_testing",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "hwcaps",
|
||||
srcs = ["src/hwcaps.c"],
|
||||
copts = C99_FLAGS,
|
||||
defines = selects.with_or({
|
||||
PLATFORM_OS_MACOS: ["HAVE_DLFCN_H"],
|
||||
"//conditions:default": ["HAVE_STRONG_GETAUXVAL"],
|
||||
}),
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = ["include/internal/hwcaps.h"],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "hwcaps_for_testing",
|
||||
testonly = 1,
|
||||
srcs = [
|
||||
"src/hwcaps.c",
|
||||
"test/hwcaps_for_testing.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"include/internal/hwcaps.h",
|
||||
"test/hwcaps_for_testing.h",
|
||||
],
|
||||
defines = [
|
||||
"CPU_FEATURES_MOCK_GET_ELF_HWCAP_FROM_GETAUXVAL",
|
||||
"CPU_FEATURES_TEST",
|
||||
],
|
||||
includes = INCLUDES,
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":filesystem_for_testing",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpuinfo",
|
||||
srcs = selects.with_or({
|
||||
PLATFORM_CPU_X86_64: [
|
||||
"src/impl_x86_freebsd.c",
|
||||
"src/impl_x86_linux_or_android.c",
|
||||
"src/impl_x86_macos.c",
|
||||
"src/impl_x86_windows.c",
|
||||
],
|
||||
PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"],
|
||||
PLATFORM_CPU_ARM64: [
|
||||
"src/impl_aarch64_linux_or_android.c",
|
||||
"src/impl_aarch64_macos_or_iphone.c",
|
||||
"src/impl_aarch64_windows.c",
|
||||
],
|
||||
PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"],
|
||||
PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"],
|
||||
PLATFORM_CPU_RISCV32: ["src/impl_riscv_linux.c"],
|
||||
PLATFORM_CPU_RISCV64: ["src/impl_riscv_linux.c"],
|
||||
}),
|
||||
hdrs = selects.with_or({
|
||||
PLATFORM_CPU_X86_64: [
|
||||
"include/cpuinfo_x86.h",
|
||||
"include/internal/cpuid_x86.h",
|
||||
"include/internal/windows_utils.h",
|
||||
],
|
||||
PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"],
|
||||
PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"],
|
||||
PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"],
|
||||
PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"],
|
||||
PLATFORM_CPU_RISCV32: ["include/cpuinfo_riscv.h"],
|
||||
PLATFORM_CPU_RISCV64: ["include/cpuinfo_riscv.h"],
|
||||
}),
|
||||
copts = C99_FLAGS,
|
||||
defines = selects.with_or({
|
||||
PLATFORM_OS_MACOS: ["HAVE_SYSCTLBYNAME"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = selects.with_or({
|
||||
PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"],
|
||||
PLATFORM_CPU_ARM64: ["src/impl_aarch64__base_implementation.inl"],
|
||||
"//conditions:default": [],
|
||||
}) + [
|
||||
"src/define_introspection.inl",
|
||||
"src/define_introspection_and_hwcaps.inl",
|
||||
],
|
||||
deps = [
|
||||
":bit_utils",
|
||||
":cpu_features_cache_info",
|
||||
":cpu_features_macros",
|
||||
":filesystem",
|
||||
":hwcaps",
|
||||
":memory_utils",
|
||||
":stack_line_reader",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "cpuinfo_for_testing",
|
||||
testonly = 1,
|
||||
srcs = selects.with_or({
|
||||
PLATFORM_CPU_X86_64: [
|
||||
"src/impl_x86_freebsd.c",
|
||||
"src/impl_x86_linux_or_android.c",
|
||||
"src/impl_x86_macos.c",
|
||||
"src/impl_x86_windows.c",
|
||||
],
|
||||
PLATFORM_CPU_ARM: ["src/impl_arm_linux_or_android.c"],
|
||||
PLATFORM_CPU_ARM64: [
|
||||
"src/impl_aarch64_linux_or_android.c",
|
||||
"src/impl_aarch64_macos_or_iphone.c",
|
||||
"src/impl_aarch64_windows.c",
|
||||
],
|
||||
PLATFORM_CPU_MIPS: ["src/impl_mips_linux_or_android.c"],
|
||||
PLATFORM_CPU_PPC: ["src/impl_ppc_linux.c"],
|
||||
PLATFORM_CPU_RISCV32: ["src/impl_riscv_linux.c"],
|
||||
PLATFORM_CPU_RISCV64: ["src/impl_riscv_linux.c"],
|
||||
}),
|
||||
hdrs = selects.with_or({
|
||||
PLATFORM_CPU_X86_64: [
|
||||
"include/cpuinfo_x86.h",
|
||||
"include/internal/cpuid_x86.h",
|
||||
"include/internal/windows_utils.h",
|
||||
],
|
||||
PLATFORM_CPU_ARM: ["include/cpuinfo_arm.h"],
|
||||
PLATFORM_CPU_ARM64: ["include/cpuinfo_aarch64.h"],
|
||||
PLATFORM_CPU_MIPS: ["include/cpuinfo_mips.h"],
|
||||
PLATFORM_CPU_PPC: ["include/cpuinfo_ppc.h"],
|
||||
PLATFORM_CPU_RISCV32: ["include/cpuinfo_riscv.h"],
|
||||
PLATFORM_CPU_RISCV64: ["include/cpuinfo_riscv.h"],
|
||||
}),
|
||||
copts = C99_FLAGS,
|
||||
defines = selects.with_or({
|
||||
PLATFORM_CPU_X86_64: ["CPU_FEATURES_MOCK_CPUID_X86"],
|
||||
"//conditions:default": [],
|
||||
}) + selects.with_or({
|
||||
PLATFORM_OS_MACOS: ["HAVE_SYSCTLBYNAME"],
|
||||
"//conditions:default": [],
|
||||
}),
|
||||
includes = INCLUDES,
|
||||
textual_hdrs = selects.with_or({
|
||||
PLATFORM_CPU_X86_64: ["src/impl_x86__base_implementation.inl"],
|
||||
PLATFORM_CPU_ARM64: ["src/impl_aarch64__base_implementation.inl"],
|
||||
"//conditions:default": [],
|
||||
}) + [
|
||||
"src/define_introspection.inl",
|
||||
"src/define_introspection_and_hwcaps.inl",
|
||||
],
|
||||
deps = [
|
||||
":bit_utils",
|
||||
":cpu_features_cache_info",
|
||||
":cpu_features_macros",
|
||||
":filesystem_for_testing",
|
||||
":hwcaps_for_testing",
|
||||
":memory_utils",
|
||||
":stack_line_reader_to_use_with_filesystem_for_testing",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cpuinfo_test",
|
||||
srcs = selects.with_or({
|
||||
PLATFORM_CPU_ARM64: ["test/cpuinfo_aarch64_test.cc"],
|
||||
PLATFORM_CPU_ARM: ["test/cpuinfo_arm_test.cc"],
|
||||
PLATFORM_CPU_MIPS: ["test/cpuinfo_mips_test.cc"],
|
||||
PLATFORM_CPU_PPC: ["test/cpuinfo_ppc_test.cc"],
|
||||
PLATFORM_CPU_RISCV32: ["test/cpuinfo_riscv_test.cc"],
|
||||
PLATFORM_CPU_RISCV64: ["test/cpuinfo_riscv_test.cc"],
|
||||
PLATFORM_CPU_X86_64: ["test/cpuinfo_x86_test.cc"],
|
||||
}),
|
||||
includes = INCLUDES,
|
||||
deps = [
|
||||
":cpuinfo_for_testing",
|
||||
":filesystem_for_testing",
|
||||
":hwcaps_for_testing",
|
||||
":string_view",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "list_cpu_features",
|
||||
srcs = ["src/utils/list_cpu_features.c"],
|
||||
copts = C99_FLAGS,
|
||||
includes = INCLUDES,
|
||||
deps = [
|
||||
":bit_utils",
|
||||
":cpu_features_macros",
|
||||
":cpuinfo",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "ndk_compat",
|
||||
srcs = ["ndk_compat/cpu-features.c"],
|
||||
copts = C99_FLAGS,
|
||||
includes = INCLUDES + ["ndk_compat"],
|
||||
textual_hdrs = ["ndk_compat/cpu-features.h"],
|
||||
deps = [
|
||||
":cpu_features_macros",
|
||||
":cpuinfo",
|
||||
":filesystem",
|
||||
":stack_line_reader",
|
||||
":string_view",
|
||||
],
|
||||
)
|
||||
Vendored
+302
@@ -0,0 +1,302 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
# option() honors normal variables.
|
||||
# see: https://cmake.org/cmake/help/git-stage/policy/CMP0077.html
|
||||
if(POLICY CMP0077)
|
||||
cmake_policy(SET CMP0077 NEW)
|
||||
endif()
|
||||
|
||||
project(CpuFeatures VERSION 0.9.0 LANGUAGES C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
|
||||
# when cpu_features is included as subproject (i.e. using add_subdirectory(cpu_features))
|
||||
# in the source tree of a project that uses it, test rules are disabled.
|
||||
if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
option(BUILD_TESTING "Enable test rule" OFF)
|
||||
else()
|
||||
option(BUILD_TESTING "Enable test rule" ON)
|
||||
endif()
|
||||
|
||||
# Default Build Type to be Release
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
|
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE)
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
# An option to enable/disable the executable target list_cpu_features.
|
||||
# Disable it by default if the project is included as a subproject.
|
||||
if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
option(BUILD_EXECUTABLE "Build list_cpu_features executable." OFF)
|
||||
else()
|
||||
option(BUILD_EXECUTABLE "Build list_cpu_features executable." ON)
|
||||
endif()
|
||||
|
||||
# An option which allows to switch off install steps. Useful for embedding.
|
||||
# Disable it by default if the project is included as a subproject.
|
||||
if(NOT CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
|
||||
option(ENABLE_INSTALL "Enable install targets" OFF)
|
||||
else()
|
||||
option(ENABLE_INSTALL "Enable install targets" ON)
|
||||
endif()
|
||||
|
||||
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make
|
||||
# it prominent in the GUI.
|
||||
# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field).
|
||||
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
|
||||
# Prefer static linking from source whenever possible.
|
||||
option(BUILD_SHARED_LIBS "Build library as shared." OFF)
|
||||
|
||||
# Force PIC on unix when building shared libs
|
||||
# see: https://en.wikipedia.org/wiki/Position-independent_code
|
||||
if(BUILD_SHARED_LIBS AND UNIX)
|
||||
option(CMAKE_POSITION_INDEPENDENT_CODE "Build with Position Independant Code." ON)
|
||||
endif()
|
||||
|
||||
include(CheckIncludeFile)
|
||||
include(CheckSymbolExists)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
macro(setup_include_and_definitions TARGET_NAME)
|
||||
target_include_directories(${TARGET_NAME}
|
||||
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/internal>
|
||||
)
|
||||
target_compile_definitions(${TARGET_NAME}
|
||||
PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024
|
||||
)
|
||||
endmacro()
|
||||
|
||||
set(PROCESSOR_IS_MIPS FALSE)
|
||||
set(PROCESSOR_IS_ARM FALSE)
|
||||
set(PROCESSOR_IS_AARCH64 FALSE)
|
||||
set(PROCESSOR_IS_X86 FALSE)
|
||||
set(PROCESSOR_IS_POWER FALSE)
|
||||
set(PROCESSOR_IS_S390X FALSE)
|
||||
set(PROCESSOR_IS_RISCV FALSE)
|
||||
set(PROCESSOR_IS_LOONGARCH FALSE)
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
|
||||
set(PROCESSOR_IS_MIPS TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(^aarch64)|(^arm64)|(^ARM64)")
|
||||
set(PROCESSOR_IS_AARCH64 TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
|
||||
set(PROCESSOR_IS_ARM TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(x86_64)|(AMD64|amd64)|(^i.86$)")
|
||||
set(PROCESSOR_IS_X86 TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
|
||||
set(PROCESSOR_IS_POWER TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(s390x)")
|
||||
set(PROCESSOR_IS_S390X TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^riscv")
|
||||
set(PROCESSOR_IS_RISCV TRUE)
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^loongarch")
|
||||
set(PROCESSOR_IS_LOONGARCH TRUE)
|
||||
endif()
|
||||
|
||||
macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_macros.h)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_cache_info.h)
|
||||
file(GLOB IMPL_SOURCES CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/src/impl_*.c")
|
||||
list(APPEND ${SRCS_LIST_NAME} ${IMPL_SOURCES})
|
||||
if(PROCESSOR_IS_MIPS)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_mips.h)
|
||||
elseif(PROCESSOR_IS_ARM)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h)
|
||||
elseif(PROCESSOR_IS_AARCH64)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h)
|
||||
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h)
|
||||
elseif(PROCESSOR_IS_X86)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h)
|
||||
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h)
|
||||
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/windows_utils.h)
|
||||
elseif(PROCESSOR_IS_POWER)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h)
|
||||
elseif(PROCESSOR_IS_S390X)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_s390x.h)
|
||||
elseif(PROCESSOR_IS_RISCV)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_riscv.h)
|
||||
elseif(PROCESSOR_IS_LOONGARCH)
|
||||
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_loongarch.h)
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
#
|
||||
# library : utils
|
||||
#
|
||||
|
||||
add_library(utils OBJECT
|
||||
${PROJECT_SOURCE_DIR}/include/internal/bit_utils.h
|
||||
${PROJECT_SOURCE_DIR}/include/internal/filesystem.h
|
||||
${PROJECT_SOURCE_DIR}/include/internal/stack_line_reader.h
|
||||
${PROJECT_SOURCE_DIR}/include/internal/string_view.h
|
||||
${PROJECT_SOURCE_DIR}/src/filesystem.c
|
||||
${PROJECT_SOURCE_DIR}/src/stack_line_reader.c
|
||||
${PROJECT_SOURCE_DIR}/src/string_view.c
|
||||
)
|
||||
setup_include_and_definitions(utils)
|
||||
|
||||
#
|
||||
# library : unix_based_hardware_detection
|
||||
#
|
||||
|
||||
if(UNIX)
|
||||
add_library(unix_based_hardware_detection OBJECT
|
||||
${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h
|
||||
${PROJECT_SOURCE_DIR}/src/hwcaps.c
|
||||
)
|
||||
setup_include_and_definitions(unix_based_hardware_detection)
|
||||
check_include_file(dlfcn.h HAVE_DLFCN_H)
|
||||
if(HAVE_DLFCN_H)
|
||||
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_DLFCN_H)
|
||||
endif()
|
||||
check_symbol_exists(getauxval "sys/auxv.h" HAVE_STRONG_GETAUXVAL)
|
||||
if(HAVE_STRONG_GETAUXVAL)
|
||||
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#
|
||||
# library : cpu_features
|
||||
#
|
||||
set (CPU_FEATURES_HDRS)
|
||||
set (CPU_FEATURES_SRCS)
|
||||
add_cpu_features_headers_and_sources(CPU_FEATURES_HDRS CPU_FEATURES_SRCS)
|
||||
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:utils>)
|
||||
if(NOT PROCESSOR_IS_X86 AND UNIX)
|
||||
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:unix_based_hardware_detection>)
|
||||
endif()
|
||||
add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS})
|
||||
set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}")
|
||||
setup_include_and_definitions(cpu_features)
|
||||
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
|
||||
target_include_directories(cpu_features
|
||||
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
|
||||
)
|
||||
|
||||
if(APPLE)
|
||||
target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME)
|
||||
endif()
|
||||
add_library(CpuFeatures::cpu_features ALIAS cpu_features)
|
||||
|
||||
#
|
||||
# program : list_cpu_features
|
||||
#
|
||||
|
||||
if(BUILD_EXECUTABLE)
|
||||
add_executable(list_cpu_features ${PROJECT_SOURCE_DIR}/src/utils/list_cpu_features.c)
|
||||
target_link_libraries(list_cpu_features PRIVATE cpu_features)
|
||||
add_executable(CpuFeatures::list_cpu_features ALIAS list_cpu_features)
|
||||
endif()
|
||||
|
||||
#
|
||||
# ndk_compat
|
||||
#
|
||||
|
||||
if(ANDROID)
|
||||
add_subdirectory(ndk_compat)
|
||||
endif()
|
||||
|
||||
#
|
||||
# tests
|
||||
#
|
||||
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
# Automatically incorporate googletest into the CMake Project if target not
|
||||
# found.
|
||||
enable_language(CXX)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std14 instead of -gnustd14
|
||||
|
||||
if(NOT TARGET gtest OR NOT TARGET gmock_main)
|
||||
# Download and unpack googletest at configure time.
|
||||
configure_file(
|
||||
cmake/googletest.CMakeLists.txt.in
|
||||
googletest-download/CMakeLists.txt
|
||||
)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
|
||||
|
||||
if(result)
|
||||
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build .
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
|
||||
|
||||
if(result)
|
||||
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||
endif()
|
||||
|
||||
# Prevent overriding the parent project's compiler/linker settings on
|
||||
# Windows.
|
||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||
|
||||
# Add googletest directly to our build. This defines the gtest and
|
||||
# gtest_main targets.
|
||||
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
|
||||
${CMAKE_BINARY_DIR}/googletest-build
|
||||
EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
#
|
||||
# Install cpu_features and list_cpu_features
|
||||
#
|
||||
if(ENABLE_INSTALL)
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS cpu_features
|
||||
EXPORT CpuFeaturesTargets
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
if(BUILD_EXECUTABLE)
|
||||
install(TARGETS list_cpu_features
|
||||
EXPORT CpuFeaturesTargets
|
||||
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
endif()
|
||||
install(EXPORT CpuFeaturesTargets
|
||||
NAMESPACE CpuFeatures::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures
|
||||
COMPONENT Devel
|
||||
)
|
||||
include(CMakePackageConfigHelpers)
|
||||
configure_package_config_file(cmake/CpuFeaturesConfig.cmake.in
|
||||
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
|
||||
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
|
||||
NO_SET_AND_CHECK_MACRO
|
||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO
|
||||
)
|
||||
write_basic_package_version_file(
|
||||
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
|
||||
COMPATIBILITY SameMajorVersion
|
||||
)
|
||||
install(
|
||||
FILES
|
||||
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
|
||||
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
|
||||
COMPONENT Devel
|
||||
)
|
||||
endif()
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Contributor License Agreement
|
||||
|
||||
Contributions to this project must be accompanied by a Contributor License
|
||||
Agreement. You (or your employer) retain the copyright to your contribution;
|
||||
this simply gives us permission to use and redistribute your contributions as
|
||||
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||
your current agreements on file or to sign a new one.
|
||||
|
||||
You generally only need to submit a CLA once, so if you've already submitted one
|
||||
(even if it was for a different project), you probably don't need to do it
|
||||
again.
|
||||
|
||||
## Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
||||
Vendored
+230
@@ -0,0 +1,230 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
For files in the `ndk_compat` folder:
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Copyright (C) 2010 The Android Open Source Project
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
Vendored
+282
@@ -0,0 +1,282 @@
|
||||
# cpu_features
|
||||
|
||||
A cross-platform C library to retrieve CPU features (such as available
|
||||
instructions) at runtime.
|
||||
|
||||
# GitHub-CI Status
|
||||
|
||||
[comment]: <> (The following lines are generated by "scripts/generate_badges.d" that you can run online https://run.dlang.io/)
|
||||
|
||||
| | Linux | FreeBSD | MacOS | Windows |
|
||||
| :-- | --: | --: | --: | --: |
|
||||
| amd64 | [![CMake][i1a0]][l1a0]<br/>[![Bazel][i1a1]][l1a1] | [![CMake][i2a0]][l2a0]<br/>![Bazel][d1] | [![CMake][i3a0]][l3a0]<br/>[![Bazel][i3a1]][l3a1] | [![CMake][i4a0]][l4a0]<br/>![Bazel][d1] |
|
||||
| AArch64 | [![CMake][i1b0]][l1b0]<br/>[![Bazel][i1b1]][l1b1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
|
||||
| ARM | [![CMake][i1c0]][l1c0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
|
||||
| MIPS | [![CMake][i1d0]][l1d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
|
||||
| POWER | [![CMake][i1e0]][l1e0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
|
||||
| RISCV | [![CMake][i1f0]][l1f0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
|
||||
| LOONGARCH | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
|
||||
| s390x | [![CMake][i1h0]][l1h0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] | ![CMake][d0]<br/>![Bazel][d1] |
|
||||
|
||||
[d0]: https://img.shields.io/badge/n%2Fa-lightgrey?&logo=cmake
|
||||
[d1]: https://img.shields.io/badge/n%2Fa-lightgrey?&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=
|
||||
[i1a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i1a1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_linux_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=
|
||||
[i1b0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/aarch64_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i1b1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/aarch64_linux_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=
|
||||
[i1c0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/arm_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i1d0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/mips_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i1e0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/power_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i1f0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/riscv_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i1h0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/s390x_linux_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i2a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_freebsd_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i3a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_macos_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[i3a1]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_macos_bazel.yml?branch=main&event=push&label=&logo=data:image/svg%2bxml;base64,PHN2ZyByb2xlPSJpbWciIHZpZXdCb3g9IjAgMCAyNCAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNiAuMTZsNS43ODYgNS43ODZMNiAxMS43MzIuMjE0IDUuOTQ2IDYgLjE2MXpNMCA2LjIxNFYxMmw1Ljc4NiA1Ljc4NlYxMkwwIDYuMjE0ek0xOCAuMTZsNS43ODYgNS43ODZMMTggMTEuNzMybC01Ljc4Ni01Ljc4NkwxOCAuMTYxek0yNCA2LjIxNFYxMmwtNS43ODYgNS43ODZWMTJMMjQgNi4yMTR6TTEyIDYuMTZsNS43ODYgNS43ODZMMTIgMTcuNzMybC01Ljc4Ni01Ljc4NkwxMiA2LjE2MXpNMTEuODQgMTguMDU0djUuNzg1bC01Ljc4Ni01Ljc4NXYtNS43ODZsNS43ODUgNS43ODZ6TTEyLjE2IDE4LjA1NGw1Ljc4Ni01Ljc4NnY1Ljc4NmwtNS43ODUgNS43ODV2LTUuNzg1eiIgc3Ryb2tlPSJ0cmFuc3BhcmVudCIgZmlsbD0id2hpdGUiLz48L3N2Zz4=
|
||||
[i4a0]: https://img.shields.io/github/actions/workflow/status/google/cpu_features/amd64_windows_cmake.yml?branch=main&event=push&label=&logo=cmake
|
||||
[l1a0]: https://github.com/google/cpu_features/actions/workflows/amd64_linux_cmake.yml
|
||||
[l1a1]: https://github.com/google/cpu_features/actions/workflows/amd64_linux_bazel.yml
|
||||
[l1b0]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux_cmake.yml
|
||||
[l1b1]: https://github.com/google/cpu_features/actions/workflows/aarch64_linux_bazel.yml
|
||||
[l1c0]: https://github.com/google/cpu_features/actions/workflows/arm_linux_cmake.yml
|
||||
[l1d0]: https://github.com/google/cpu_features/actions/workflows/mips_linux_cmake.yml
|
||||
[l1e0]: https://github.com/google/cpu_features/actions/workflows/power_linux_cmake.yml
|
||||
[l1f0]: https://github.com/google/cpu_features/actions/workflows/riscv_linux_cmake.yml
|
||||
[l1h0]: https://github.com/google/cpu_features/actions/workflows/s390x_linux_cmake.yml
|
||||
[l2a0]: https://github.com/google/cpu_features/actions/workflows/amd64_freebsd_cmake.yml
|
||||
[l3a0]: https://github.com/google/cpu_features/actions/workflows/amd64_macos_cmake.yml
|
||||
[l3a1]: https://github.com/google/cpu_features/actions/workflows/amd64_macos_bazel.yml
|
||||
[l4a0]: https://github.com/google/cpu_features/actions/workflows/amd64_windows_cmake.yml
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Design Rationale](#rationale)
|
||||
- [Code samples](#codesample)
|
||||
- [Running sample code](#usagesample)
|
||||
- [What's supported](#support)
|
||||
- [Android NDK's drop in replacement](#ndk)
|
||||
- [License](#license)
|
||||
- [Build with cmake](#cmake)
|
||||
- [Community Bindings](#bindings)
|
||||
|
||||
<a name="rationale"></a>
|
||||
## Design Rationale
|
||||
|
||||
- **Simple to use.** See the snippets below for examples.
|
||||
- **Extensible.** Easy to add missing features or architectures.
|
||||
- **Compatible with old compilers** and available on many architectures so it
|
||||
can be used widely. To ensure that cpu_features works on as many platforms
|
||||
as possible, we implemented it in a highly portable version of C: C99.
|
||||
- **Sandbox-compatible.** The library uses a variety of strategies to cope
|
||||
with sandboxed environments or when `cpuid` is unavailable. This is useful
|
||||
when running integration tests in hermetic environments.
|
||||
- **Thread safe, no memory allocation, and raises no exceptions.**
|
||||
cpu_features is suitable for implementing fundamental libc functions like
|
||||
`malloc`, `memcpy`, and `memcmp`.
|
||||
- **Unit tested.**
|
||||
|
||||
<a name="codesample"></a>
|
||||
## Code samples
|
||||
|
||||
**Note:** For C++ code, the library functions are defined in the `cpu_features` namespace.
|
||||
|
||||
### Checking features at runtime
|
||||
|
||||
Here's a simple example that executes a codepath if the CPU supports both the
|
||||
AES and the SSE4.2 instruction sets:
|
||||
|
||||
```c
|
||||
#include "cpuinfo_x86.h"
|
||||
|
||||
// For C++, add `using namespace cpu_features;`
|
||||
static const X86Features features = GetX86Info().features;
|
||||
|
||||
void Compute(void) {
|
||||
if (features.aes && features.sse4_2) {
|
||||
// Run optimized code.
|
||||
} else {
|
||||
// Run standard code.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Caching for faster evaluation of complex checks
|
||||
|
||||
If you wish, you can read all the features at once into a global variable, and
|
||||
then query for the specific features you care about. Below, we store all the ARM
|
||||
features and then check whether AES and NEON are supported.
|
||||
|
||||
```c
|
||||
#include <stdbool.h>
|
||||
#include "cpuinfo_arm.h"
|
||||
|
||||
// For C++, add `using namespace cpu_features;`
|
||||
static const ArmFeatures features = GetArmInfo().features;
|
||||
static const bool has_aes_and_neon = features.aes && features.neon;
|
||||
|
||||
// use has_aes_and_neon.
|
||||
```
|
||||
|
||||
This is a good approach to take if you're checking for combinations of features
|
||||
when using a compiler that is slow to extract individual bits from bit-packed
|
||||
structures.
|
||||
|
||||
### Checking compile time flags
|
||||
|
||||
The following code determines whether the compiler was told to use the AVX
|
||||
instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly.
|
||||
|
||||
```c
|
||||
#include <stdbool.h>
|
||||
#include "cpuinfo_x86.h"
|
||||
|
||||
// For C++, add `using namespace cpu_features;`
|
||||
static const X86Features features = GetX86Info().features;
|
||||
static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx;
|
||||
|
||||
// use has_avx.
|
||||
```
|
||||
|
||||
`CPU_FEATURES_COMPILED_X86_AVX` is set to 1 if the compiler was instructed to
|
||||
use AVX and 0 otherwise, combining compile time and runtime knowledge.
|
||||
|
||||
### Rejecting poor hardware implementations based on microarchitecture
|
||||
|
||||
On x86, the first incarnation of a feature in a microarchitecture might not be
|
||||
the most efficient (e.g. AVX on Sandy Bridge). We provide a function to retrieve
|
||||
the underlying microarchitecture so you can decide whether to use it.
|
||||
|
||||
Below, `has_fast_avx` is set to 1 if the CPU supports the AVX instruction
|
||||
set—but only if it's not Sandy Bridge.
|
||||
|
||||
```c
|
||||
#include <stdbool.h>
|
||||
#include "cpuinfo_x86.h"
|
||||
|
||||
// For C++, add `using namespace cpu_features;`
|
||||
static const X86Info info = GetX86Info();
|
||||
static const X86Microarchitecture uarch = GetX86Microarchitecture(&info);
|
||||
static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB;
|
||||
|
||||
// use has_fast_avx.
|
||||
```
|
||||
|
||||
This feature is currently available only for x86 microarchitectures.
|
||||
|
||||
<a name="usagesample"></a>
|
||||
### Running sample code
|
||||
|
||||
Building `cpu_features` (check [quickstart](#quickstart) below) brings a small executable to test the library.
|
||||
|
||||
```shell
|
||||
% ./build/list_cpu_features
|
||||
arch : x86
|
||||
brand : Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz
|
||||
family : 6 (0x06)
|
||||
model : 45 (0x2D)
|
||||
stepping : 7 (0x07)
|
||||
uarch : INTEL_SNB
|
||||
flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
|
||||
```
|
||||
|
||||
```shell
|
||||
% ./build/list_cpu_features --json
|
||||
{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]}
|
||||
```
|
||||
|
||||
<a name="support"></a>
|
||||
## What's supported
|
||||
|
||||
| | x86³ | AArch64 | ARM | MIPS⁴ | POWER | RISCV | Loongarch | s390x |
|
||||
|---------|:----:|:-------:|:-------:|:-------:|:-------:|:-------:|:---------:|:-------:|
|
||||
| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ | yes¹ |
|
||||
| FreeBSD | yes² | not yet | not yet | not yet | not yet | N/A | not yet | not yet |
|
||||
| MacOs | yes² | yes⁵ | N/A | N/A | N/A | N/A | N/A | N/A |
|
||||
| Windows | yes² | not yet | not yet | N/A | N/A | N/A | N/A | N/A |
|
||||
| Android | yes² | yes¹ | yes¹ | yes¹ | N/A | N/A | N/A | N/A |
|
||||
| iOS | N/A | not yet | not yet | N/A | N/A | N/A | N/A | N/A |
|
||||
|
||||
1. **Features revealed from Linux.** We gather data from several sources
|
||||
depending on availability:
|
||||
+ from glibc's
|
||||
[getauxval](https://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html)
|
||||
+ by parsing `/proc/self/auxv`
|
||||
+ by parsing `/proc/cpuinfo`
|
||||
2. **Features revealed from CPU.** features are retrieved by using the `cpuid`
|
||||
instruction.
|
||||
3. **Microarchitecture detection.** On x86 some features are not always
|
||||
implemented efficiently in hardware (e.g. AVX on Sandybridge). Exposing the
|
||||
microarchitecture allows the client to reject particular microarchitectures.
|
||||
4. All flavors of Mips are supported, little and big endian as well as 32/64
|
||||
bits.
|
||||
5. **Features revealed from sysctl.** features are retrieved by the `sysctl`
|
||||
instruction.
|
||||
|
||||
<a name="ndk"></a>
|
||||
## Android NDK's drop in replacement
|
||||
|
||||
[cpu_features](https://github.com/google/cpu_features) is now officially
|
||||
supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/main/sources/android/cpufeatures/cpu-features.h)
|
||||
, see [ndk_compat](ndk_compat) folder for details.
|
||||
|
||||
<a name="license"></a>
|
||||
## License
|
||||
|
||||
The cpu_features library is licensed under the terms of the Apache license.
|
||||
See [LICENSE](LICENSE) for more information.
|
||||
|
||||
<a name="cmake"></a>
|
||||
## Build with CMake
|
||||
|
||||
Please check the [CMake build instructions](cmake/README.md).
|
||||
|
||||
<a name="quickstart"></a>
|
||||
### Quickstart
|
||||
|
||||
- Run `list_cpu_features`
|
||||
```sh
|
||||
cmake -S. -Bbuild -DBUILD_TESTING=OFF -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build --config Release -j
|
||||
./build/list_cpu_features --json
|
||||
```
|
||||
|
||||
_Note_: Use `--target ALL_BUILD` on the second line for `Visual Studio` and `XCode`.
|
||||
|
||||
- run tests
|
||||
```sh
|
||||
cmake -S. -Bbuild -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug
|
||||
cmake --build build --config Debug -j
|
||||
cmake --build build --config Debug --target test
|
||||
```
|
||||
|
||||
_Note_: Use `--target RUN_TESTS` on the last line for `Visual Studio` and `--target RUN_TEST` for `XCode`.
|
||||
|
||||
|
||||
- install `cpu_features`
|
||||
```sh
|
||||
cmake --build build --config Release --target install -v
|
||||
```
|
||||
|
||||
_Note_: Use `--target INSTALL` for `Visual Studio`.
|
||||
|
||||
_Note_: When using `Makefile` or `XCode` generator, you can use
|
||||
[`DESTDIR`](https://www.gnu.org/software/make/manual/html_node/DESTDIR.html)
|
||||
to install on a local repository.<br>
|
||||
e.g.
|
||||
```sh
|
||||
cmake --build build --config Release --target install -v -- DESTDIR=install
|
||||
```
|
||||
|
||||
<a name="bindings"></a>
|
||||
## Community bindings
|
||||
|
||||
Links provided here are not affiliated with Google but are kindly provided by the OSS Community.
|
||||
|
||||
- .Net
|
||||
- https://github.com/toor1245/cpu_features.NET
|
||||
- Python
|
||||
- https://github.com/Narasimha1997/py_cpu
|
||||
- Java
|
||||
- https://github.com/aecsocket/cpu-features-java
|
||||
|
||||
|
||||
_Send PR to showcase your wrapper here_
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
workspace(name = "com_google_cpufeatures")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
git_repository(
|
||||
name = "com_google_googletest",
|
||||
tag = "release-1.11.0",
|
||||
remote = "https://github.com/google/googletest.git",
|
||||
)
|
||||
|
||||
git_repository(
|
||||
name = "bazel_skylib",
|
||||
tag = "1.2.0",
|
||||
remote = "https://github.com/bazelbuild/bazel-skylib.git",
|
||||
)
|
||||
|
||||
load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace")
|
||||
|
||||
bazel_skylib_workspace()
|
||||
@@ -0,0 +1,3 @@
|
||||
# CpuFeatures CMake configuration file
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesTargets.cmake")
|
||||
@@ -0,0 +1,3 @@
|
||||
# CpuFeaturesNdkCompat CMake configuration file
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesNdkCompatTargets.cmake")
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
# CMake build instructions
|
||||
|
||||
## Recommended usage : Incorporating cpu_features into a CMake project
|
||||
|
||||
For API / ABI compatibility reasons, it is recommended to build and use
|
||||
cpu_features in a subdirectory of your project or as an embedded dependency.
|
||||
|
||||
This is similar to the recommended usage of the googletest framework
|
||||
( https://github.com/google/googletest/blob/main/googletest/README.md )
|
||||
|
||||
Build and use step-by-step
|
||||
|
||||
|
||||
1- Download cpu_features and copy it in a sub-directory in your project.
|
||||
or add cpu_features as a git-submodule in your project
|
||||
|
||||
2- You can then use the cmake command `add_subdirectory()` to include
|
||||
cpu_features directly and use the `cpu_features` target in your project.
|
||||
|
||||
3- Add the `CpuFeatures::cpu_features` target to the `target_link_libraries()` section of
|
||||
your executable or of your library.
|
||||
|
||||
## Disabling tests
|
||||
|
||||
CMake default options for cpu_features is `Release` built type with tests
|
||||
enabled. To disable testing set cmake `BUILD_TESTING` variable to `OFF`.
|
||||
e.g.
|
||||
```sh
|
||||
cmake -S. -Bbuild -DBUILD_TESTING=OFF
|
||||
```
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
PROJECT := cpu_features
|
||||
BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
SHA1 := $(shell git rev-parse --verify HEAD)
|
||||
|
||||
# General commands
|
||||
.PHONY: help
|
||||
BOLD=\e[1m
|
||||
RESET=\e[0m
|
||||
|
||||
help:
|
||||
@echo -e "${BOLD}SYNOPSIS${RESET}"
|
||||
@echo -e "\tmake <target> [NOCACHE=1]"
|
||||
@echo
|
||||
@echo -e "${BOLD}DESCRIPTION${RESET}"
|
||||
@echo -e "\ttest build inside docker container to have a reproductible build."
|
||||
@echo
|
||||
@echo -e "${BOLD}MAKE TARGETS${RESET}"
|
||||
@echo -e "\t${BOLD}help${RESET}: display this help and exit."
|
||||
@echo
|
||||
@echo -e "\t${BOLD}amd64_<stage>${RESET}: build <stage> docker image using an Ubuntu:latest x86_64 base image."
|
||||
@echo -e "\t${BOLD}save_amd64_<stage>${RESET}: Save the <stage> docker image."
|
||||
@echo -e "\t${BOLD}sh_amd64_<stage>${RESET}: run a container using the <stage> docker image (debug purpose)."
|
||||
@echo -e "\t${BOLD}clean_amd64_<stage>${RESET}: Remove cache and docker image."
|
||||
@echo
|
||||
@echo -e "\tWith ${BOLD}<stage>${RESET}:"
|
||||
@echo -e "\t\t${BOLD}env${RESET}"
|
||||
@echo -e "\t\t${BOLD}devel${RESET}"
|
||||
@echo -e "\t\t${BOLD}build${RESET}"
|
||||
@echo -e "\t\t${BOLD}test${RESET}"
|
||||
@echo -e "\t\t${BOLD}install_env${RESET}"
|
||||
@echo -e "\t\t${BOLD}install_devel${RESET}"
|
||||
@echo -e "\t\t${BOLD}install_build${RESET}"
|
||||
@echo -e "\t\t${BOLD}install_test${RESET}"
|
||||
@echo -e "\te.g. 'make amd64_build'"
|
||||
@echo
|
||||
@echo -e "\t${BOLD}<target>_<toolchain_stage>${RESET}: build <stage> docker image for a specific toolchain target."
|
||||
@echo -e "\t${BOLD}save_<target>_<toolchain_stage>${RESET}: Save the <stage> docker image for a specific platform."
|
||||
@echo -e "\t${BOLD}sh_<target>_<toolchain_stage>${RESET}: run a container using the <stage> docker image specified (debug purpose)."
|
||||
@echo -e "\t${BOLD}clean_<target>_<toolchain_stage>${RESET}: Remove cache and docker image."
|
||||
@echo
|
||||
@echo -e "\tWith ${BOLD}<target>${RESET}:"
|
||||
@echo -e "\t\t${BOLD}arm-linux-gnueabihf${RESET} (linaro toolchain)"
|
||||
@echo -e "\t\t${BOLD}armv8l-linux-gnueabihf${RESET} (linaro toolchain)"
|
||||
@echo -e "\t\t${BOLD}arm-linux-gnueabi${RESET} (linaro toolchain)"
|
||||
@echo -e "\t\t${BOLD}armeb-linux-gnueabihf${RESET} (linaro toolchain)"
|
||||
@echo -e "\t\t${BOLD}armeb-linux-gnueabi${RESET} (linaro toolchain)"
|
||||
@echo -e "\t\t${BOLD}aarch64-linux-gnu${RESET} (linaro toolchain)"
|
||||
@echo -e "\t\t${BOLD}aarch64${RESET} (bootlin toolchain)"
|
||||
@echo -e "\t\t${BOLD}aarch64_be-linux-gnu${RESET} (linaro toolchain)"
|
||||
@echo -e "\t\t${BOLD}aarch64be${RESET} (bootlin toolchain)"
|
||||
@echo -e "\t\t${BOLD}mips32${RESET} (codespace toolchain)"
|
||||
@echo -e "\t\t${BOLD}mips64${RESET} (codespace toolchain)"
|
||||
@echo -e "\t\t${BOLD}mips32el${RESET} (codespace toolchain)"
|
||||
@echo -e "\t\t${BOLD}mips64el${RESET} (codespace toolchain)"
|
||||
@echo -e "\t\t${BOLD}ppc${RESET} (bootlin toolchain)"
|
||||
@echo -e "\t\t${BOLD}ppc64${RESET} (bootlin toolchain)"
|
||||
@echo -e "\t\t${BOLD}ppc64le${RESET} (bootlin toolchain)"
|
||||
@echo -e "\t\t${BOLD}riscv32${RESET} (bootlin toolchain)"
|
||||
@echo -e "\t\t${BOLD}riscv64${RESET} (bootlin toolchain)"
|
||||
@echo -e "\t\t${BOLD}s390x${RESET} (bootlin toolchain)"
|
||||
@echo
|
||||
@echo -e "\tWith ${BOLD}<toolchain_stage>${RESET}:"
|
||||
@echo -e "\t\t${BOLD}env${RESET}"
|
||||
@echo -e "\t\t${BOLD}devel${RESET}"
|
||||
@echo -e "\t\t${BOLD}build${RESET}"
|
||||
@echo -e "\t\t${BOLD}test${RESET}"
|
||||
@echo -e "\te.g. 'make aarch64_test'"
|
||||
@echo
|
||||
@echo -e "\t${BOLD}<VM>${RESET}: build the vagrant <VM> virtual machine."
|
||||
@echo -e "\t${BOLD}clean_<VM>${RESET}: Remove virtual machine for the specified vm."
|
||||
@echo
|
||||
@echo -e "\t${BOLD}<VM>${RESET}:"
|
||||
@echo -e "\t\t${BOLD}freebsd${RESET} (FreeBSD)"
|
||||
@echo
|
||||
@echo -e "\t${BOLD}clean${RESET}: Remove cache and ALL docker images."
|
||||
@echo
|
||||
@echo -e "\t${BOLD}NOCACHE=1${RESET}: use 'docker build --no-cache' when building container (default use cache)."
|
||||
@echo
|
||||
@echo -e "branch: $(BRANCH)"
|
||||
@echo -e "sha1: $(SHA1)"
|
||||
|
||||
# Need to add cmd_platform to PHONY otherwise target are ignored since they do not
|
||||
# contain recipe (using FORCE do not work here)
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
# Delete all implicit rules to speed up makefile
|
||||
MAKEFLAGS += --no-builtin-rules
|
||||
.SUFFIXES:
|
||||
# Remove some rules from gmake that .SUFFIXES does not remove.
|
||||
SUFFIXES =
|
||||
# Keep all intermediate files
|
||||
# ToDo: try to remove it later
|
||||
.SECONDARY:
|
||||
|
||||
# Docker image name prefix.
|
||||
IMAGE := ${PROJECT}
|
||||
|
||||
ifdef NOCACHE
|
||||
DOCKER_BUILD_CMD := docker build --no-cache
|
||||
else
|
||||
DOCKER_BUILD_CMD := docker build
|
||||
endif
|
||||
|
||||
DOCKER_RUN_CMD := docker run --rm --init --net=host
|
||||
|
||||
# $* stem
|
||||
# $< first prerequist
|
||||
# $@ target name
|
||||
|
||||
############
|
||||
## NATIVE ##
|
||||
############
|
||||
STAGES = env devel build test install_env install_devel install_build install_test
|
||||
|
||||
targets_amd64 = $(addprefix amd64_, $(STAGES))
|
||||
.PHONY: $(targets_amd64)
|
||||
$(targets_amd64): amd64_%: docker/amd64/Dockerfile
|
||||
#@docker image rm -f ${IMAGE}:amd64_$* 2>/dev/null
|
||||
${DOCKER_BUILD_CMD} \
|
||||
--tag ${IMAGE}:amd64_$* \
|
||||
--target=$* \
|
||||
-f $< \
|
||||
../..
|
||||
|
||||
#$(info Create targets: save_amd64 $(addprefix save_amd64_, $(STAGES)) (debug).)
|
||||
save_targets_amd64 = $(addprefix save_amd64_, $(STAGES))
|
||||
.PHONY: $(save_targets_amd64)
|
||||
$(save_targets_amd64): save_amd64_%: cache/amd64/docker_%.tar
|
||||
cache/amd64/docker_%.tar: amd64_%
|
||||
@rm -f $@
|
||||
mkdir -p cache/amd64
|
||||
docker save ${IMAGE}:amd64_$* -o $@
|
||||
|
||||
#$(info Create targets: $(addprefix sh_amd64_, $(STAGES)) (debug).)
|
||||
sh_targets_amd64 = $(addprefix sh_amd64_, $(STAGES))
|
||||
.PHONY: $(sh_targets_amd64)
|
||||
$(sh_targets_amd64): sh_amd64_%: amd64_%
|
||||
${DOCKER_RUN_CMD} -it --name ${IMAGE}_amd64_$* ${IMAGE}:amd64_$*
|
||||
|
||||
#$(info Create targets: $(addprefix clean_amd64_, $(STAGES)).)
|
||||
clean_targets_amd64 = $(addprefix clean_amd64_, $(STAGES))
|
||||
.PHONY: clean_amd64 $(clean_targets_amd64)
|
||||
clean_amd64: $(clean_targets_amd64)
|
||||
$(clean_targets_amd64): clean_amd64_%:
|
||||
docker image rm -f ${IMAGE}:amd64_$* 2>/dev/null
|
||||
rm -f cache/amd64/docker_$*.tar
|
||||
|
||||
|
||||
###############
|
||||
## TOOLCHAIN ##
|
||||
###############
|
||||
TOOLCHAIN_TARGETS = \
|
||||
aarch64 aarch64be \
|
||||
arm-linux-gnueabihf armv8l-linux-gnueabihf arm-linux-gnueabi armeb-linux-gnueabihf armeb-linux-gnueabi \
|
||||
aarch64-linux-gnu aarch64_be-linux-gnu \
|
||||
mips32 mips32el mips64 mips64el \
|
||||
ppc ppc64 ppc64le \
|
||||
riscv32 riscv64 \
|
||||
s390x
|
||||
TOOLCHAIN_STAGES = env devel build test
|
||||
define toolchain-stage-target =
|
||||
#$$(info STAGE: $1)
|
||||
#$$(info Create targets: toolchain_$1 $(addsuffix _$1, $(TOOLCHAIN_TARGETS)).)
|
||||
targets_toolchain_$1 = $(addsuffix _$1, $(TOOLCHAIN_TARGETS))
|
||||
.PHONY: toolchain_$1 $$(targets_toolchain_$1)
|
||||
toolchain_$1: $$(targets_toolchain_$1)
|
||||
$$(targets_toolchain_$1): %_$1: docker/toolchain/Dockerfile
|
||||
#@docker image rm -f ${IMAGE}:$$*_$1 2>/dev/null
|
||||
${DOCKER_BUILD_CMD} \
|
||||
--tag ${IMAGE}:$$*_$1 \
|
||||
--build-arg TARGET=$$* \
|
||||
--target=$1 \
|
||||
-f $$< \
|
||||
../..
|
||||
|
||||
#$$(info Create targets: save_toolchain_$1 $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).)
|
||||
save_targets_toolchain_$1 = $(addprefix save_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
|
||||
.PHONY: save_toolchain_$1 $$(save_targets_toolchain_$1)
|
||||
save_toolchain_$1: $$(save_targets_toolchain_$1)
|
||||
$$(save_targets_toolchain_$1): save_%_$1: cache/%/docker_$1.tar
|
||||
cache/%/docker_$1.tar: %_$1
|
||||
@rm -f $$@
|
||||
mkdir -p cache/$$*
|
||||
docker save ${IMAGE}:$$*_$1 -o $$@
|
||||
|
||||
#$$(info Create targets: $(addprefix sh_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))) (debug).)
|
||||
sh_targets_toolchain_$1 = $(addprefix sh_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
|
||||
.PHONY: $$(sh_targets_toolchain_$1)
|
||||
$$(sh_targets_toolchain_$1): sh_%_$1: %_$1
|
||||
${DOCKER_RUN_CMD} -it --name ${IMAGE}_$$*_$1 ${IMAGE}:$$*_$1
|
||||
|
||||
#$$(info Create targets: clean_toolchain_$1 $(addprefix clean_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS))).)
|
||||
clean_targets_toolchain_$1 = $(addprefix clean_, $(addsuffix _$1, $(TOOLCHAIN_TARGETS)))
|
||||
.PHONY: clean_toolchain_$1 $$(clean_targets_toolchain_$1)
|
||||
clean_toolchain_$1: $$(clean_targets_toolchain_$1)
|
||||
$$(clean_targets_toolchain_$1): clean_%_$1:
|
||||
docker image rm -f ${IMAGE}:$$*_$1 2>/dev/null
|
||||
rm -f cache/$$*/docker_$1.tar
|
||||
endef
|
||||
|
||||
$(foreach stage,$(TOOLCHAIN_STAGES),$(eval $(call toolchain-stage-target,$(stage))))
|
||||
|
||||
## MERGE ##
|
||||
.PHONY: clean_toolchain
|
||||
clean_toolchain: $(addprefix clean_toolchain_, $(TOOLCHAIN_STAGES))
|
||||
-rmdir $(addprefix cache/, $(TOOLCHAIN_TARGETS))
|
||||
|
||||
.PHONY: env devel build test
|
||||
env: amd64_env toolchain_env
|
||||
devel: amd64_devel toolchain_devel
|
||||
build: amd64_build toolchain_build
|
||||
test: amd64_test toolchain_test
|
||||
|
||||
.PHONY: install_env install_devel install_build install_test
|
||||
install_env: amd64_install_env
|
||||
install_devel: amd64_install_devel
|
||||
install_build: amd64_install_build
|
||||
install_test: amd64_install_test
|
||||
|
||||
#############
|
||||
## VAGRANT ##
|
||||
#############
|
||||
VMS = freebsd
|
||||
|
||||
vms_targets = $(addsuffix _build, $(VMS))
|
||||
.PHONY: $(vms_targets)
|
||||
$(vms_targets): %_build: vagrant/%/Vagrantfile
|
||||
@cd vagrant/$* && vagrant destroy -f
|
||||
cd vagrant/$* && vagrant up
|
||||
|
||||
clean_vms_targets = $(addprefix clean_, $(VMS))
|
||||
.PHONY: clean_vms $(clean_vms_targets)
|
||||
clean_vms: $(clean_vms_targets)
|
||||
$(clean_vms_targets): clean_%:
|
||||
cd vagrant/$* && vagrant destroy -f
|
||||
-rm -rf vagrant/$*/.vagrant
|
||||
|
||||
###########
|
||||
## CLEAN ##
|
||||
###########
|
||||
.PHONY: clean
|
||||
clean: clean_amd64 clean_toolchain clean_vms
|
||||
docker container prune -f
|
||||
docker image prune -f
|
||||
-rmdir cache
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
-docker container rm -f $$(docker container ls -aq)
|
||||
-docker image rm -f $$(docker image ls -aq)
|
||||
-vagrant box remove -f generic/freebsd12
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
## Makefile/Docker testing
|
||||
To test the build on various distro, we are using docker containers and a Makefile for orchestration.
|
||||
|
||||
pros:
|
||||
* You are independent of third party CI runner config
|
||||
(e.g. [github action virtual-environnments](https://github.com/actions/virtual-environments)).
|
||||
* You can run it locally on your linux system.
|
||||
* Most CI provide runners with docker and Makefile installed.
|
||||
|
||||
cons:
|
||||
* Only GNU/Linux distro supported.
|
||||
|
||||
### Usage
|
||||
To get the help simply type:
|
||||
```sh
|
||||
make
|
||||
```
|
||||
|
||||
note: you can also use from top directory
|
||||
```sh
|
||||
make --directory=cmake/ci
|
||||
```
|
||||
|
||||
### Example
|
||||
For example to test mips32 inside an container:
|
||||
```sh
|
||||
make mips32_test
|
||||
```
|
||||
|
||||
### Docker layers
|
||||
Dockerfile is splitted in several stages.
|
||||
|
||||

|
||||
|
||||
|
||||
## Makefile/Vagrant testing
|
||||
To test build for FreeBSD we are using Vagrant and VirtualBox box.
|
||||
|
||||
This is similar to the docker stuff but use `vagrant` as `docker` cli and
|
||||
VirtuaBox to replace the docker engine daemon.
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
@startdot
|
||||
digraph DockerDeps {
|
||||
//rankdir=BT;
|
||||
rankdir=TD;
|
||||
node [shape=cylinder, style="rounded,filled", color=black, fillcolor=royalblue];
|
||||
DISTRO_IMG [label="ubuntu:latest"];
|
||||
PKG [label="packages\ne.g. cmake, g++", shape=box3d];
|
||||
SRC [label="git repo", shape=folder];
|
||||
SPL [label="sample", shape=folder];
|
||||
|
||||
subgraph clusterDockerfile {
|
||||
ENV_IMG [label="cpu_features:amd64_env\nenv"];
|
||||
DEVEL_IMG [label="cpu_features:amd64_devel\ndevel"];
|
||||
BUILD_IMG [label="cpu_features:amd64_build\nbuild"];
|
||||
TEST_IMG [label="cpu_features:amd64_test\ntest"];
|
||||
INSTALL_ENV_IMG [label="cpu_features:amd64_install_env\ninstall_env"];
|
||||
INSTALL_DEVEL_IMG [label="cpu_features:amd64_install_devel\ninstall_devel"];
|
||||
INSTALL_BUILD_IMG [label="cpu_features:amd64_install_build\ninstall_build"];
|
||||
INSTALL_TEST_IMG [label="cpu_features:amd64_install_test\ninstall_test"];
|
||||
|
||||
ENV_IMG -> DEVEL_IMG;
|
||||
DEVEL_IMG -> BUILD_IMG;
|
||||
BUILD_IMG -> TEST_IMG;
|
||||
|
||||
ENV_IMG -> INSTALL_ENV_IMG;
|
||||
BUILD_IMG -> INSTALL_ENV_IMG [label="copy install", style="dashed"];
|
||||
INSTALL_ENV_IMG -> INSTALL_DEVEL_IMG;
|
||||
SPL -> INSTALL_DEVEL_IMG [label="copy", style="dashed"];
|
||||
INSTALL_DEVEL_IMG -> INSTALL_BUILD_IMG;
|
||||
INSTALL_BUILD_IMG -> INSTALL_TEST_IMG;
|
||||
|
||||
color=royalblue;
|
||||
label = "docker/amd64/Dockerfile";
|
||||
}
|
||||
DISTRO_IMG -> ENV_IMG;
|
||||
PKG -> ENV_IMG [label="install", style="dashed"];
|
||||
SRC -> DEVEL_IMG [label="copy", style="dashed"];
|
||||
|
||||
subgraph clusterCache {
|
||||
node [shape=note, style="rounded,filled", color=black, fillcolor=royalblue];
|
||||
ENV_TAR [label="docker_amd64_env.tar"];
|
||||
DEVEL_TAR [label="docker_amd64_devel.tar"];
|
||||
BUILD_TAR [label="docker_amd64_build.tar"];
|
||||
TEST_TAR [label="docker_amd64_test.tar"];
|
||||
INSTALL_ENV_TAR [label="docker_amd64_install_env.tar"];
|
||||
INSTALL_DEVEL_TAR [label="docker_amd64_install_devel.tar"];
|
||||
INSTALL_BUILD_TAR [label="docker_amd64_install_build.tar"];
|
||||
INSTALL_TEST_TAR [label="docker_amd64_install_test.tar"];
|
||||
|
||||
edge [color=red];
|
||||
ENV_IMG -> ENV_TAR [label="make save_amd64_env"];
|
||||
DEVEL_IMG -> DEVEL_TAR [label="make save_amd64_devel"];
|
||||
BUILD_IMG -> BUILD_TAR [label="make save_amd64_build"];
|
||||
TEST_IMG -> TEST_TAR [label="make save_amd64_test"];
|
||||
INSTALL_ENV_IMG -> INSTALL_ENV_TAR [label="make save_amd64_install_env"];
|
||||
INSTALL_DEVEL_IMG -> INSTALL_DEVEL_TAR [label="make save_amd64_install_devel"];
|
||||
INSTALL_BUILD_IMG -> INSTALL_BUILD_TAR [label="make save_amd64_install_build"];
|
||||
INSTALL_TEST_IMG -> INSTALL_TEST_TAR [label="make save_amd64_install_test"];
|
||||
|
||||
color=royalblue;
|
||||
label = "cache/amd64/";
|
||||
}
|
||||
}
|
||||
@enddot
|
||||
+312
@@ -0,0 +1,312 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.49.2 (0)
|
||||
-->
|
||||
<!-- Title: DockerDeps Pages: 1 -->
|
||||
<svg width="1904pt" height="900pt"
|
||||
viewBox="0.00 0.00 1904.00 899.75" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 895.75)">
|
||||
<title>DockerDeps</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-895.75 1900,-895.75 1900,4 -4,4"/>
|
||||
<g id="clust1" class="cluster">
|
||||
<title>clusterDockerfile</title>
|
||||
<polygon fill="none" stroke="royalblue" points="691,-116 691,-812.75 1253,-812.75 1253,-116 691,-116"/>
|
||||
<text text-anchor="middle" x="972" y="-797.55" font-family="Times,serif" font-size="14.00">docker/amd64/Dockerfile</text>
|
||||
</g>
|
||||
<g id="clust2" class="cluster">
|
||||
<title>clusterCache</title>
|
||||
<polygon fill="none" stroke="royalblue" points="8,-8 8,-83 1826,-83 1826,-8 8,-8"/>
|
||||
<text text-anchor="middle" x="917" y="-67.8" font-family="Times,serif" font-size="14.00">cache/amd64/</text>
|
||||
</g>
|
||||
<!-- DISTRO_IMG -->
|
||||
<g id="node1" class="node">
|
||||
<title>DISTRO_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M893.5,-887.48C893.5,-889.28 868.18,-890.75 837,-890.75 805.82,-890.75 780.5,-889.28 780.5,-887.48 780.5,-887.48 780.5,-858.02 780.5,-858.02 780.5,-856.22 805.82,-854.75 837,-854.75 868.18,-854.75 893.5,-856.22 893.5,-858.02 893.5,-858.02 893.5,-887.48 893.5,-887.48"/>
|
||||
<path fill="none" stroke="black" d="M893.5,-887.48C893.5,-885.67 868.18,-884.2 837,-884.2 805.82,-884.2 780.5,-885.67 780.5,-887.48"/>
|
||||
<text text-anchor="middle" x="837" y="-869.05" font-family="Times,serif" font-size="14.00">ubuntu:latest</text>
|
||||
</g>
|
||||
<!-- ENV_IMG -->
|
||||
<g id="node5" class="node">
|
||||
<title>ENV_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M1005,-777.1C1005,-779.74 961.52,-781.88 908,-781.88 854.48,-781.88 811,-779.74 811,-777.1 811,-777.1 811,-734.15 811,-734.15 811,-731.51 854.48,-729.37 908,-729.37 961.52,-729.37 1005,-731.51 1005,-734.15 1005,-734.15 1005,-777.1 1005,-777.1"/>
|
||||
<path fill="none" stroke="black" d="M1005,-777.1C1005,-774.47 961.52,-772.33 908,-772.33 854.48,-772.33 811,-774.47 811,-777.1"/>
|
||||
<text text-anchor="middle" x="908" y="-759.42" font-family="Times,serif" font-size="14.00">cpu_features:amd64_env</text>
|
||||
<text text-anchor="middle" x="908" y="-744.42" font-family="Times,serif" font-size="14.00">env</text>
|
||||
</g>
|
||||
<!-- DISTRO_IMG->ENV_IMG -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>DISTRO_IMG->ENV_IMG</title>
|
||||
<path fill="none" stroke="black" d="M847.78,-854.26C858.17,-837.42 874.16,-811.49 887.05,-790.59"/>
|
||||
<polygon fill="black" stroke="black" points="890.09,-792.33 892.37,-781.98 884.14,-788.65 890.09,-792.33"/>
|
||||
</g>
|
||||
<!-- PKG -->
|
||||
<g id="node2" class="node">
|
||||
<title>PKG</title>
|
||||
<polygon fill="royalblue" stroke="black" points="1046.5,-891.75 915.5,-891.75 911.5,-887.75 911.5,-853.75 1042.5,-853.75 1046.5,-857.75 1046.5,-891.75"/>
|
||||
<polyline fill="none" stroke="black" points="1042.5,-887.75 911.5,-887.75 "/>
|
||||
<polyline fill="none" stroke="black" points="1042.5,-887.75 1042.5,-853.75 "/>
|
||||
<polyline fill="none" stroke="black" points="1042.5,-887.75 1046.5,-891.75 "/>
|
||||
<text text-anchor="middle" x="979" y="-876.55" font-family="Times,serif" font-size="14.00">packages</text>
|
||||
<text text-anchor="middle" x="979" y="-861.55" font-family="Times,serif" font-size="14.00">e.g. cmake, g++</text>
|
||||
</g>
|
||||
<!-- PKG->ENV_IMG -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>PKG->ENV_IMG</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M967.75,-853.51C957.4,-836.72 941.77,-811.38 929.09,-790.83"/>
|
||||
<polygon fill="black" stroke="black" points="931.91,-788.73 923.69,-782.06 925.96,-792.41 931.91,-788.73"/>
|
||||
<text text-anchor="middle" x="978.5" y="-824.55" font-family="Times,serif" font-size="14.00">install</text>
|
||||
</g>
|
||||
<!-- SRC -->
|
||||
<g id="node3" class="node">
|
||||
<title>SRC</title>
|
||||
<polygon fill="royalblue" stroke="black" points="1334.5,-773.62 1331.5,-777.62 1310.5,-777.62 1307.5,-773.62 1261.5,-773.62 1261.5,-737.62 1334.5,-737.62 1334.5,-773.62"/>
|
||||
<text text-anchor="middle" x="1298" y="-751.92" font-family="Times,serif" font-size="14.00">git repo</text>
|
||||
</g>
|
||||
<!-- DEVEL_IMG -->
|
||||
<g id="node6" class="node">
|
||||
<title>DEVEL_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M1189,-673.85C1189,-676.49 1142.83,-678.63 1086,-678.63 1029.17,-678.63 983,-676.49 983,-673.85 983,-673.85 983,-630.9 983,-630.9 983,-628.26 1029.17,-626.12 1086,-626.12 1142.83,-626.12 1189,-628.26 1189,-630.9 1189,-630.9 1189,-673.85 1189,-673.85"/>
|
||||
<path fill="none" stroke="black" d="M1189,-673.85C1189,-671.22 1142.83,-669.08 1086,-669.08 1029.17,-669.08 983,-671.22 983,-673.85"/>
|
||||
<text text-anchor="middle" x="1086" y="-656.17" font-family="Times,serif" font-size="14.00">cpu_features:amd64_devel</text>
|
||||
<text text-anchor="middle" x="1086" y="-641.17" font-family="Times,serif" font-size="14.00">devel</text>
|
||||
</g>
|
||||
<!-- SRC->DEVEL_IMG -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>SRC->DEVEL_IMG</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1271.39,-737.62C1266.66,-734.8 1261.73,-731.99 1257,-729.5 1224.81,-712.57 1188.08,-695.89 1156.94,-682.48"/>
|
||||
<polygon fill="black" stroke="black" points="1158.03,-679.14 1147.46,-678.43 1155.28,-685.58 1158.03,-679.14"/>
|
||||
<text text-anchor="middle" x="1237" y="-700.3" font-family="Times,serif" font-size="14.00">copy</text>
|
||||
</g>
|
||||
<!-- SPL -->
|
||||
<g id="node4" class="node">
|
||||
<title>SPL</title>
|
||||
<polygon fill="royalblue" stroke="black" points="767,-477.88 764,-481.88 743,-481.88 740,-477.88 699,-477.88 699,-441.88 767,-441.88 767,-477.88"/>
|
||||
<text text-anchor="middle" x="733" y="-456.18" font-family="Times,serif" font-size="14.00">sample</text>
|
||||
</g>
|
||||
<!-- INSTALL_DEVEL_IMG -->
|
||||
<g id="node10" class="node">
|
||||
<title>INSTALL_DEVEL_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M956.5,-378.1C956.5,-380.74 898.9,-382.88 828,-382.88 757.1,-382.88 699.5,-380.74 699.5,-378.1 699.5,-378.1 699.5,-335.15 699.5,-335.15 699.5,-332.51 757.1,-330.37 828,-330.37 898.9,-330.37 956.5,-332.51 956.5,-335.15 956.5,-335.15 956.5,-378.1 956.5,-378.1"/>
|
||||
<path fill="none" stroke="black" d="M956.5,-378.1C956.5,-375.47 898.9,-373.33 828,-373.33 757.1,-373.33 699.5,-375.47 699.5,-378.1"/>
|
||||
<text text-anchor="middle" x="828" y="-360.43" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_devel</text>
|
||||
<text text-anchor="middle" x="828" y="-345.43" font-family="Times,serif" font-size="14.00">install_devel</text>
|
||||
</g>
|
||||
<!-- SPL->INSTALL_DEVEL_IMG -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>SPL->INSTALL_DEVEL_IMG</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M749.12,-441.7C762.24,-427.71 781.16,-407.54 797.18,-390.47"/>
|
||||
<polygon fill="black" stroke="black" points="800.02,-392.56 804.31,-382.87 794.91,-387.77 800.02,-392.56"/>
|
||||
<text text-anchor="middle" x="803" y="-404.55" font-family="Times,serif" font-size="14.00">copy</text>
|
||||
</g>
|
||||
<!-- ENV_IMG->DEVEL_IMG -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>ENV_IMG->DEVEL_IMG</title>
|
||||
<path fill="none" stroke="black" d="M952.46,-729.34C976.87,-715.45 1007.3,-698.14 1032.95,-683.55"/>
|
||||
<polygon fill="black" stroke="black" points="1034.84,-686.5 1041.8,-678.52 1031.38,-680.42 1034.84,-686.5"/>
|
||||
</g>
|
||||
<!-- INSTALL_ENV_IMG -->
|
||||
<g id="node9" class="node">
|
||||
<title>INSTALL_ENV_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M1030.5,-481.35C1030.5,-483.99 975.59,-486.13 908,-486.13 840.41,-486.13 785.5,-483.99 785.5,-481.35 785.5,-481.35 785.5,-438.4 785.5,-438.4 785.5,-435.76 840.41,-433.62 908,-433.62 975.59,-433.62 1030.5,-435.76 1030.5,-438.4 1030.5,-438.4 1030.5,-481.35 1030.5,-481.35"/>
|
||||
<path fill="none" stroke="black" d="M1030.5,-481.35C1030.5,-478.72 975.59,-476.58 908,-476.58 840.41,-476.58 785.5,-478.72 785.5,-481.35"/>
|
||||
<text text-anchor="middle" x="908" y="-463.68" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_env</text>
|
||||
<text text-anchor="middle" x="908" y="-448.68" font-family="Times,serif" font-size="14.00">install_env</text>
|
||||
</g>
|
||||
<!-- ENV_IMG->INSTALL_ENV_IMG -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>ENV_IMG->INSTALL_ENV_IMG</title>
|
||||
<path fill="none" stroke="black" d="M908,-729.33C908,-676.94 908,-556.49 908,-496.37"/>
|
||||
<polygon fill="black" stroke="black" points="911.5,-496.22 908,-486.22 904.5,-496.22 911.5,-496.22"/>
|
||||
</g>
|
||||
<!-- ENV_TAR -->
|
||||
<g id="node13" class="node">
|
||||
<title>ENV_TAR</title>
|
||||
<polygon fill="royalblue" stroke="black" points="186,-52 16,-52 16,-16 192,-16 192,-46 186,-52"/>
|
||||
<polyline fill="none" stroke="black" points="186,-52 186,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="192,-46 186,-46 "/>
|
||||
<text text-anchor="middle" x="104" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_env.tar</text>
|
||||
</g>
|
||||
<!-- ENV_IMG->ENV_TAR -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>ENV_IMG->ENV_TAR</title>
|
||||
<path fill="none" stroke="red" d="M810.87,-751.31C609.47,-743.14 165,-717.82 165,-653.38 165,-653.38 165,-653.38 165,-149.12 165,-115.26 143.85,-81.71 126.46,-59.84"/>
|
||||
<polygon fill="red" stroke="red" points="129.09,-57.54 120.03,-52.05 123.7,-61.99 129.09,-57.54"/>
|
||||
<text text-anchor="middle" x="246.5" y="-404.55" font-family="Times,serif" font-size="14.00">make save_amd64_env</text>
|
||||
</g>
|
||||
<!-- BUILD_IMG -->
|
||||
<g id="node7" class="node">
|
||||
<title>BUILD_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M1245,-584.6C1245,-587.24 1199.28,-589.38 1143,-589.38 1086.72,-589.38 1041,-587.24 1041,-584.6 1041,-584.6 1041,-541.65 1041,-541.65 1041,-539.01 1086.72,-536.87 1143,-536.87 1199.28,-536.87 1245,-539.01 1245,-541.65 1245,-541.65 1245,-584.6 1245,-584.6"/>
|
||||
<path fill="none" stroke="black" d="M1245,-584.6C1245,-581.97 1199.28,-579.83 1143,-579.83 1086.72,-579.83 1041,-581.97 1041,-584.6"/>
|
||||
<text text-anchor="middle" x="1143" y="-566.92" font-family="Times,serif" font-size="14.00">cpu_features:amd64_build</text>
|
||||
<text text-anchor="middle" x="1143" y="-551.92" font-family="Times,serif" font-size="14.00">build</text>
|
||||
</g>
|
||||
<!-- DEVEL_IMG->BUILD_IMG -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>DEVEL_IMG->BUILD_IMG</title>
|
||||
<path fill="none" stroke="black" d="M1102.49,-626.14C1108.28,-617.28 1114.88,-607.17 1121.04,-597.73"/>
|
||||
<polygon fill="black" stroke="black" points="1124.01,-599.59 1126.55,-589.3 1118.15,-595.76 1124.01,-599.59"/>
|
||||
</g>
|
||||
<!-- DEVEL_TAR -->
|
||||
<g id="node14" class="node">
|
||||
<title>DEVEL_TAR</title>
|
||||
<polygon fill="royalblue" stroke="black" points="395.5,-52 210.5,-52 210.5,-16 401.5,-16 401.5,-46 395.5,-52"/>
|
||||
<polyline fill="none" stroke="black" points="395.5,-52 395.5,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="401.5,-46 395.5,-46 "/>
|
||||
<text text-anchor="middle" x="306" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_devel.tar</text>
|
||||
</g>
|
||||
<!-- DEVEL_IMG->DEVEL_TAR -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>DEVEL_IMG->DEVEL_TAR</title>
|
||||
<path fill="none" stroke="red" d="M982.94,-648.59C792.56,-642.05 405,-621.67 405,-564.12 405,-564.12 405,-564.12 405,-149.12 405,-110.26 371.83,-78.15 343.9,-58"/>
|
||||
<polygon fill="red" stroke="red" points="345.65,-54.96 335.44,-52.14 341.66,-60.71 345.65,-54.96"/>
|
||||
<text text-anchor="middle" x="493" y="-352.93" font-family="Times,serif" font-size="14.00">make save_amd64_devel</text>
|
||||
</g>
|
||||
<!-- TEST_IMG -->
|
||||
<g id="node8" class="node">
|
||||
<title>TEST_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M1245,-481.35C1245,-483.99 1201.07,-486.13 1147,-486.13 1092.93,-486.13 1049,-483.99 1049,-481.35 1049,-481.35 1049,-438.4 1049,-438.4 1049,-435.76 1092.93,-433.62 1147,-433.62 1201.07,-433.62 1245,-435.76 1245,-438.4 1245,-438.4 1245,-481.35 1245,-481.35"/>
|
||||
<path fill="none" stroke="black" d="M1245,-481.35C1245,-478.72 1201.07,-476.58 1147,-476.58 1092.93,-476.58 1049,-478.72 1049,-481.35"/>
|
||||
<text text-anchor="middle" x="1147" y="-463.68" font-family="Times,serif" font-size="14.00">cpu_features:amd64_test</text>
|
||||
<text text-anchor="middle" x="1147" y="-448.68" font-family="Times,serif" font-size="14.00">test</text>
|
||||
</g>
|
||||
<!-- BUILD_IMG->TEST_IMG -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>BUILD_IMG->TEST_IMG</title>
|
||||
<path fill="none" stroke="black" d="M1144,-536.84C1144.48,-524.63 1145.07,-509.79 1145.59,-496.47"/>
|
||||
<polygon fill="black" stroke="black" points="1149.1,-496.32 1146,-486.19 1142.11,-496.05 1149.1,-496.32"/>
|
||||
</g>
|
||||
<!-- BUILD_IMG->INSTALL_ENV_IMG -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>BUILD_IMG->INSTALL_ENV_IMG</title>
|
||||
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M1084.61,-536.97C1051.68,-522.78 1010.38,-504.99 976,-490.17"/>
|
||||
<polygon fill="black" stroke="black" points="977.07,-486.82 966.5,-486.08 974.3,-493.25 977.07,-486.82"/>
|
||||
<text text-anchor="middle" x="1080" y="-507.8" font-family="Times,serif" font-size="14.00">copy install</text>
|
||||
</g>
|
||||
<!-- BUILD_TAR -->
|
||||
<g id="node15" class="node">
|
||||
<title>BUILD_TAR</title>
|
||||
<polygon fill="royalblue" stroke="black" points="1812,-52 1630,-52 1630,-16 1818,-16 1818,-46 1812,-52"/>
|
||||
<polyline fill="none" stroke="black" points="1812,-52 1812,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="1818,-46 1812,-46 "/>
|
||||
<text text-anchor="middle" x="1724" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_build.tar</text>
|
||||
</g>
|
||||
<!-- BUILD_IMG->BUILD_TAR -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>BUILD_IMG->BUILD_TAR</title>
|
||||
<path fill="none" stroke="red" d="M1245.18,-554.53C1411.4,-540.79 1722,-508.71 1722,-460.88 1722,-460.88 1722,-460.88 1722,-149.12 1722,-119.36 1722.69,-85.23 1723.26,-62.11"/>
|
||||
<polygon fill="red" stroke="red" points="1726.76,-62.1 1723.52,-52.01 1719.76,-61.92 1726.76,-62.1"/>
|
||||
<text text-anchor="middle" x="1809" y="-301.3" font-family="Times,serif" font-size="14.00">make save_amd64_build</text>
|
||||
</g>
|
||||
<!-- TEST_TAR -->
|
||||
<g id="node16" class="node">
|
||||
<title>TEST_TAR</title>
|
||||
<polygon fill="royalblue" stroke="black" points="1606,-52 1432,-52 1432,-16 1612,-16 1612,-46 1606,-52"/>
|
||||
<polyline fill="none" stroke="black" points="1606,-52 1606,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="1612,-46 1606,-46 "/>
|
||||
<text text-anchor="middle" x="1522" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_test.tar</text>
|
||||
</g>
|
||||
<!-- TEST_IMG->TEST_TAR -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>TEST_IMG->TEST_TAR</title>
|
||||
<path fill="none" stroke="red" d="M1245.07,-451.87C1356.77,-441.13 1524,-415.4 1524,-357.62 1524,-357.62 1524,-357.62 1524,-149.12 1524,-119.36 1523.31,-85.23 1522.74,-62.11"/>
|
||||
<polygon fill="red" stroke="red" points="1526.24,-61.92 1522.48,-52.01 1519.24,-62.1 1526.24,-61.92"/>
|
||||
<text text-anchor="middle" x="1607" y="-249.68" font-family="Times,serif" font-size="14.00">make save_amd64_test</text>
|
||||
</g>
|
||||
<!-- INSTALL_ENV_IMG->INSTALL_DEVEL_IMG -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>INSTALL_ENV_IMG->INSTALL_DEVEL_IMG</title>
|
||||
<path fill="none" stroke="black" d="M888.02,-433.59C877.81,-420.66 865.25,-404.76 854.26,-390.86"/>
|
||||
<polygon fill="black" stroke="black" points="856.95,-388.62 848,-382.94 851.46,-392.96 856.95,-388.62"/>
|
||||
</g>
|
||||
<!-- INSTALL_ENV_TAR -->
|
||||
<g id="node17" class="node">
|
||||
<title>INSTALL_ENV_TAR</title>
|
||||
<polygon fill="royalblue" stroke="black" points="1407.5,-52 1186.5,-52 1186.5,-16 1413.5,-16 1413.5,-46 1407.5,-52"/>
|
||||
<polyline fill="none" stroke="black" points="1407.5,-52 1407.5,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="1413.5,-46 1407.5,-46 "/>
|
||||
<text text-anchor="middle" x="1300" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_env.tar</text>
|
||||
</g>
|
||||
<!-- INSTALL_ENV_IMG->INSTALL_ENV_TAR -->
|
||||
<g id="edge17" class="edge">
|
||||
<title>INSTALL_ENV_IMG->INSTALL_ENV_TAR</title>
|
||||
<path fill="none" stroke="red" d="M1012.88,-434.97C1121.03,-409.58 1274,-371.26 1274,-357.62 1274,-357.62 1274,-357.62 1274,-149.12 1274,-118.64 1282.93,-84.69 1290.32,-61.81"/>
|
||||
<polygon fill="red" stroke="red" points="1293.71,-62.72 1293.57,-52.12 1287.07,-60.49 1293.71,-62.72"/>
|
||||
<text text-anchor="middle" x="1381" y="-249.68" font-family="Times,serif" font-size="14.00">make save_amd64_install_env</text>
|
||||
</g>
|
||||
<!-- INSTALL_BUILD_IMG -->
|
||||
<g id="node11" class="node">
|
||||
<title>INSTALL_BUILD_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M955.5,-274.85C955.5,-277.49 898.35,-279.63 828,-279.63 757.65,-279.63 700.5,-277.49 700.5,-274.85 700.5,-274.85 700.5,-231.9 700.5,-231.9 700.5,-229.26 757.65,-227.12 828,-227.12 898.35,-227.12 955.5,-229.26 955.5,-231.9 955.5,-231.9 955.5,-274.85 955.5,-274.85"/>
|
||||
<path fill="none" stroke="black" d="M955.5,-274.85C955.5,-272.22 898.35,-270.08 828,-270.08 757.65,-270.08 700.5,-272.22 700.5,-274.85"/>
|
||||
<text text-anchor="middle" x="828" y="-257.18" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_build</text>
|
||||
<text text-anchor="middle" x="828" y="-242.18" font-family="Times,serif" font-size="14.00">install_build</text>
|
||||
</g>
|
||||
<!-- INSTALL_DEVEL_IMG->INSTALL_BUILD_IMG -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>INSTALL_DEVEL_IMG->INSTALL_BUILD_IMG</title>
|
||||
<path fill="none" stroke="black" d="M828,-330.34C828,-318.13 828,-303.29 828,-289.97"/>
|
||||
<polygon fill="black" stroke="black" points="831.5,-289.69 828,-279.69 824.5,-289.69 831.5,-289.69"/>
|
||||
</g>
|
||||
<!-- INSTALL_DEVEL_TAR -->
|
||||
<g id="node18" class="node">
|
||||
<title>INSTALL_DEVEL_TAR</title>
|
||||
<polygon fill="royalblue" stroke="black" points="656,-52 420,-52 420,-16 662,-16 662,-46 656,-52"/>
|
||||
<polyline fill="none" stroke="black" points="656,-52 656,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="662,-46 656,-46 "/>
|
||||
<text text-anchor="middle" x="541" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_devel.tar</text>
|
||||
</g>
|
||||
<!-- INSTALL_DEVEL_IMG->INSTALL_DEVEL_TAR -->
|
||||
<g id="edge18" class="edge">
|
||||
<title>INSTALL_DEVEL_IMG->INSTALL_DEVEL_TAR</title>
|
||||
<path fill="none" stroke="red" d="M761.39,-330.48C708.37,-307.05 636.42,-266.99 595,-209.25 562.63,-164.12 549.27,-99.06 544.06,-62.54"/>
|
||||
<polygon fill="red" stroke="red" points="547.47,-61.64 542.7,-52.18 540.53,-62.55 547.47,-61.64"/>
|
||||
<text text-anchor="middle" x="708.5" y="-198.05" font-family="Times,serif" font-size="14.00">make save_amd64_install_devel</text>
|
||||
</g>
|
||||
<!-- INSTALL_TEST_IMG -->
|
||||
<g id="node12" class="node">
|
||||
<title>INSTALL_TEST_IMG</title>
|
||||
<path fill="royalblue" stroke="black" d="M948.5,-171.6C948.5,-174.24 893.15,-176.38 825,-176.38 756.85,-176.38 701.5,-174.24 701.5,-171.6 701.5,-171.6 701.5,-128.65 701.5,-128.65 701.5,-126.01 756.85,-123.87 825,-123.87 893.15,-123.87 948.5,-126.01 948.5,-128.65 948.5,-128.65 948.5,-171.6 948.5,-171.6"/>
|
||||
<path fill="none" stroke="black" d="M948.5,-171.6C948.5,-168.97 893.15,-166.83 825,-166.83 756.85,-166.83 701.5,-168.97 701.5,-171.6"/>
|
||||
<text text-anchor="middle" x="825" y="-153.93" font-family="Times,serif" font-size="14.00">cpu_features:amd64_install_test</text>
|
||||
<text text-anchor="middle" x="825" y="-138.93" font-family="Times,serif" font-size="14.00">install_test</text>
|
||||
</g>
|
||||
<!-- INSTALL_BUILD_IMG->INSTALL_TEST_IMG -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>INSTALL_BUILD_IMG->INSTALL_TEST_IMG</title>
|
||||
<path fill="none" stroke="black" d="M827.25,-227.09C826.89,-214.88 826.45,-200.04 826.05,-186.72"/>
|
||||
<polygon fill="black" stroke="black" points="829.54,-186.33 825.75,-176.44 822.55,-186.54 829.54,-186.33"/>
|
||||
</g>
|
||||
<!-- INSTALL_BUILD_TAR -->
|
||||
<g id="node19" class="node">
|
||||
<title>INSTALL_BUILD_TAR</title>
|
||||
<polygon fill="royalblue" stroke="black" points="1162.5,-52 929.5,-52 929.5,-16 1168.5,-16 1168.5,-46 1162.5,-52"/>
|
||||
<polyline fill="none" stroke="black" points="1162.5,-52 1162.5,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="1168.5,-46 1162.5,-46 "/>
|
||||
<text text-anchor="middle" x="1049" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_build.tar</text>
|
||||
</g>
|
||||
<!-- INSTALL_BUILD_IMG->INSTALL_BUILD_TAR -->
|
||||
<g id="edge19" class="edge">
|
||||
<title>INSTALL_BUILD_IMG->INSTALL_BUILD_TAR</title>
|
||||
<path fill="none" stroke="red" d="M882.76,-227.11C907.43,-214.09 935.91,-196.66 958,-176.25 994.16,-142.85 1022.19,-92.11 1037.09,-61.41"/>
|
||||
<polygon fill="red" stroke="red" points="1040.34,-62.72 1041.46,-52.19 1034.02,-59.72 1040.34,-62.72"/>
|
||||
<text text-anchor="middle" x="1117.5" y="-146.43" font-family="Times,serif" font-size="14.00">make save_amd64_install_build</text>
|
||||
</g>
|
||||
<!-- INSTALL_TEST_TAR -->
|
||||
<g id="node20" class="node">
|
||||
<title>INSTALL_TEST_TAR</title>
|
||||
<polygon fill="royalblue" stroke="black" points="905.5,-52 680.5,-52 680.5,-16 911.5,-16 911.5,-46 905.5,-52"/>
|
||||
<polyline fill="none" stroke="black" points="905.5,-52 905.5,-46 "/>
|
||||
<polyline fill="none" stroke="black" points="911.5,-46 905.5,-46 "/>
|
||||
<text text-anchor="middle" x="796" y="-30.3" font-family="Times,serif" font-size="14.00">docker_amd64_install_test.tar</text>
|
||||
</g>
|
||||
<!-- INSTALL_TEST_IMG->INSTALL_TEST_TAR -->
|
||||
<g id="edge20" class="edge">
|
||||
<title>INSTALL_TEST_IMG->INSTALL_TEST_TAR</title>
|
||||
<path fill="none" stroke="red" d="M799.99,-123.98C795.9,-118.47 792.26,-112.36 790,-106 785.07,-92.11 786.03,-75.77 788.46,-62.27"/>
|
||||
<polygon fill="red" stroke="red" points="791.96,-62.66 790.65,-52.15 785.12,-61.19 791.96,-62.66"/>
|
||||
<text text-anchor="middle" x="898.5" y="-94.8" font-family="Times,serif" font-size="14.00">make save_amd64_install_test</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 21 KiB |
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -ex
|
||||
|
||||
rm -f ./*.svg ./*.png
|
||||
for i in *.dot; do
|
||||
plantuml -Tsvg "$i";
|
||||
done
|
||||
@@ -0,0 +1,48 @@
|
||||
# Create a virtual environment with all tools installed
|
||||
# ref: https://hub.docker.com/_/ubuntu
|
||||
FROM ubuntu:latest AS env
|
||||
LABEL maintainer="corentinl@google.com"
|
||||
# Install system build dependencies
|
||||
ENV PATH=/usr/local/bin:$PATH
|
||||
RUN apt-get update -qq \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq git wget libssl-dev build-essential \
|
||||
ninja-build python3 pkgconf libglib2.0-dev \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
ENTRYPOINT ["/usr/bin/bash", "-c"]
|
||||
CMD ["/usr/bin/bash"]
|
||||
|
||||
# Install CMake 3.21.3
|
||||
RUN wget "https://cmake.org/files/v3.21/cmake-3.21.3-linux-x86_64.sh" \
|
||||
&& chmod a+x cmake-3.21.3-linux-x86_64.sh \
|
||||
&& ./cmake-3.21.3-linux-x86_64.sh --prefix=/usr/local/ --skip-license \
|
||||
&& rm cmake-3.21.3-linux-x86_64.sh
|
||||
|
||||
FROM env AS devel
|
||||
WORKDIR /home/project
|
||||
COPY . .
|
||||
|
||||
FROM devel AS build
|
||||
RUN cmake -version
|
||||
RUN cmake -S. -Bbuild
|
||||
RUN cmake --build build --target all -v
|
||||
RUN cmake --build build --target install -v
|
||||
|
||||
FROM build AS test
|
||||
ENV CTEST_OUTPUT_ON_FAILURE=1
|
||||
RUN cmake --build build --target test -v
|
||||
|
||||
# Test install rules
|
||||
FROM env AS install_env
|
||||
COPY --from=build /usr/local /usr/local/
|
||||
|
||||
FROM install_env AS install_devel
|
||||
WORKDIR /home/sample
|
||||
COPY cmake/ci/sample .
|
||||
|
||||
FROM install_devel AS install_build
|
||||
RUN cmake -S. -Bbuild
|
||||
RUN cmake --build build --target all -v
|
||||
|
||||
FROM install_build AS install_test
|
||||
RUN cmake --build build --target test
|
||||
@@ -0,0 +1,34 @@
|
||||
# Create a virtual environment with all tools installed
|
||||
# ref: https://hub.docker.com/_/ubuntu
|
||||
FROM ubuntu:latest AS env
|
||||
LABEL maintainer="corentinl@google.com"
|
||||
# Install system build dependencies
|
||||
ENV PATH=/usr/local/bin:$PATH
|
||||
RUN apt-get update -qq \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -yq git wget libssl-dev build-essential \
|
||||
ninja-build python3 pkgconf libglib2.0-dev \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
ENTRYPOINT ["/usr/bin/bash", "-c"]
|
||||
CMD ["/usr/bin/bash"]
|
||||
|
||||
# Install CMake 3.21.3
|
||||
RUN wget "https://cmake.org/files/v3.21/cmake-3.21.3-linux-x86_64.sh" \
|
||||
&& chmod a+x cmake-3.21.3-linux-x86_64.sh \
|
||||
&& ./cmake-3.21.3-linux-x86_64.sh --prefix=/usr/local/ --skip-license \
|
||||
&& rm cmake-3.21.3-linux-x86_64.sh
|
||||
|
||||
FROM env AS devel
|
||||
WORKDIR /home/project
|
||||
COPY . .
|
||||
|
||||
ARG TARGET
|
||||
ENV TARGET ${TARGET:-unknown}
|
||||
|
||||
FROM devel AS build
|
||||
RUN cmake -version
|
||||
RUN ./scripts/run_integration.sh build
|
||||
|
||||
FROM build AS test
|
||||
RUN ./scripts/run_integration.sh qemu
|
||||
RUN ./scripts/run_integration.sh test
|
||||
@@ -0,0 +1,22 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(Sample VERSION 1.0.0 LANGUAGES CXX)
|
||||
|
||||
include(CTest)
|
||||
find_package(CpuFeatures REQUIRED)
|
||||
|
||||
add_executable(sample main.cpp)
|
||||
target_compile_features(sample PUBLIC cxx_std_11)
|
||||
set_target_properties(sample PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
VERSION ${PROJECT_VERSION})
|
||||
target_link_libraries(sample PRIVATE CpuFeatures::cpu_features)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test(NAME sample_test COMMAND sample)
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS sample
|
||||
EXPORT SampleTargets
|
||||
DESTINATION ${CMAKE_INSTALL_BIN_DIR})
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "cpuinfo_x86.h"
|
||||
|
||||
using namespace cpu_features;
|
||||
|
||||
int main(int /*argc*/, char** /*argv*/) {
|
||||
static const X86Features features = GetX86Info().features;
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
# -*- mode: ruby -*-
|
||||
# vi: set ft=ruby :
|
||||
|
||||
# All Vagrant configuration is done below. The "2" in Vagrant.configure
|
||||
# configures the configuration version (we support older styles for
|
||||
# backwards compatibility). Please don't change it unless you know what
|
||||
# you're doing.
|
||||
Vagrant.configure("2") do |config|
|
||||
# The most common configuration options are documented and commented below.
|
||||
# For a complete reference, please see the online documentation at
|
||||
# https://docs.vagrantup.com.
|
||||
|
||||
# Every Vagrant development environment requires a box. You can search for
|
||||
# boxes at https://vagrantcloud.com/search.
|
||||
config.vm.guest = :freebsd
|
||||
config.vm.box = "generic/freebsd12"
|
||||
|
||||
config.ssh.shell = "sh"
|
||||
|
||||
# Disable automatic box update checking. If you disable this, then
|
||||
# boxes will only be checked for updates when the user runs
|
||||
# `vagrant box outdated`. This is not recommended.
|
||||
# config.vm.box_check_update = false
|
||||
|
||||
# Create a forwarded port mapping which allows access to a specific port
|
||||
# within the machine from a port on the host machine. In the example below,
|
||||
# accessing "localhost:8080" will access port 80 on the guest machine.
|
||||
# NOTE: This will enable public access to the opened port
|
||||
# config.vm.network "forwarded_port", guest: 80, host: 8080
|
||||
|
||||
# Create a forwarded port mapping which allows access to a specific port
|
||||
# within the machine from a port on the host machine and only allow access
|
||||
# via 127.0.0.1 to disable public access
|
||||
# config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1"
|
||||
|
||||
# Create a private network, which allows host-only access to the machine
|
||||
# using a specific IP.
|
||||
# config.vm.network "private_network", ip: "192.168.33.10"
|
||||
|
||||
# Create a public network, which generally matched to bridged network.
|
||||
# Bridged networks make the machine appear as another physical device on
|
||||
# your network.
|
||||
# config.vm.network "public_network"
|
||||
|
||||
# Share an additional folder to the guest VM. The first argument is
|
||||
# the path on the host to the actual folder. The second argument is
|
||||
# the path on the guest to mount the folder. And the optional third
|
||||
# argument is a set of non-required options.
|
||||
#config.vm.synced_folder "../../..", "/home/vagrant/project"
|
||||
config.vm.synced_folder ".", "/vagrant", id: "vagrant-root", disabled: true
|
||||
|
||||
config.vm.provision "file", source: "../../../../CMakeLists.txt", destination: "$HOME/project/"
|
||||
config.vm.provision "file", source: "../../../../cmake", destination: "$HOME/project/"
|
||||
config.vm.provision "file", source: "../../../../include", destination: "$HOME/project/"
|
||||
config.vm.provision "file", source: "../../../../src", destination: "$HOME/project/"
|
||||
config.vm.provision "file", source: "../../../../test", destination: "$HOME/project/"
|
||||
|
||||
# Provider-specific configuration so you can fine-tune various
|
||||
# backing providers for Vagrant. These expose provider-specific options.
|
||||
# Example for VirtualBox:
|
||||
#
|
||||
# config.vm.provider "virtualbox" do |vb|
|
||||
# # Display the VirtualBox GUI when booting the machine
|
||||
# vb.gui = true
|
||||
#
|
||||
# # Customize the amount of memory on the VM:
|
||||
# vb.memory = "1024"
|
||||
# end
|
||||
#
|
||||
# View the documentation for the provider you are using for more
|
||||
# information on available options.
|
||||
|
||||
# Enable provisioning with a shell script. Additional provisioners such as
|
||||
# Ansible, Chef, Docker, Puppet and Salt are also available. Please see the
|
||||
# documentation for more information about their specific syntax and use.
|
||||
# note: clang installed by default
|
||||
config.vm.provision "env", type: "shell", inline:<<-SHELL
|
||||
set -x
|
||||
pkg update -f
|
||||
pkg install -y git cmake
|
||||
SHELL
|
||||
config.vm.provision "devel", type: "shell", inline:<<-SHELL
|
||||
set -x
|
||||
cd project
|
||||
ls
|
||||
SHELL
|
||||
config.vm.provision "configure", type: "shell", inline:<<-SHELL
|
||||
set -x
|
||||
cd project
|
||||
cmake -S. -Bbuild -DBUILD_TESTING=ON
|
||||
SHELL
|
||||
config.vm.provision "build", type: "shell", inline:<<-SHELL
|
||||
set -x
|
||||
cd project
|
||||
cmake --build build -v
|
||||
SHELL
|
||||
config.vm.provision "test", type: "shell", inline:<<-SHELL
|
||||
set -x
|
||||
cd project
|
||||
cmake --build build --target test -v
|
||||
SHELL
|
||||
config.vm.provision "test", type: "shell", inline:<<-SHELL
|
||||
set -x
|
||||
cd project
|
||||
cmake --build build --target install -v
|
||||
SHELL
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 2.8.2)
|
||||
|
||||
project(googletest-download NONE)
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(googletest
|
||||
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||
GIT_TAG main
|
||||
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
|
||||
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ""
|
||||
TEST_COMMAND ""
|
||||
)
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef enum {
|
||||
CPU_FEATURE_CACHE_NULL = 0,
|
||||
CPU_FEATURE_CACHE_DATA = 1,
|
||||
CPU_FEATURE_CACHE_INSTRUCTION = 2,
|
||||
CPU_FEATURE_CACHE_UNIFIED = 3,
|
||||
CPU_FEATURE_CACHE_TLB = 4,
|
||||
CPU_FEATURE_CACHE_DTLB = 5,
|
||||
CPU_FEATURE_CACHE_STLB = 6,
|
||||
CPU_FEATURE_CACHE_PREFETCH = 7
|
||||
} CacheType;
|
||||
|
||||
typedef struct {
|
||||
int level;
|
||||
CacheType cache_type;
|
||||
int cache_size; // Cache size in bytes
|
||||
int ways; // Associativity, 0 undefined, 0xFF fully associative
|
||||
int line_size; // Cache line size in bytes
|
||||
int tlb_entries; // number of entries for TLB
|
||||
int partitioning; // number of lines per sector
|
||||
} CacheLevelInfo;
|
||||
|
||||
// Increase this value if more cache levels are needed.
|
||||
#ifndef CPU_FEATURES_MAX_CACHE_LEVEL
|
||||
#define CPU_FEATURES_MAX_CACHE_LEVEL 10
|
||||
#endif
|
||||
typedef struct {
|
||||
int size;
|
||||
CacheLevelInfo levels[CPU_FEATURES_MAX_CACHE_LEVEL];
|
||||
} CacheInfo;
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||
+388
@@ -0,0 +1,388 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Architectures
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(__pnacl__) || defined(__CLR_VER)
|
||||
#define CPU_FEATURES_ARCH_VM
|
||||
#endif
|
||||
|
||||
#if (defined(_M_IX86) || defined(__i386__)) && !defined(CPU_FEATURES_ARCH_VM)
|
||||
#define CPU_FEATURES_ARCH_X86_32
|
||||
#endif
|
||||
|
||||
#if (defined(_M_X64) || defined(__x86_64__)) && !defined(CPU_FEATURES_ARCH_VM)
|
||||
#define CPU_FEATURES_ARCH_X86_64
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86_32) || defined(CPU_FEATURES_ARCH_X86_64)
|
||||
#define CPU_FEATURES_ARCH_X86
|
||||
#endif
|
||||
|
||||
#if (defined(__arm__) || defined(_M_ARM))
|
||||
#define CPU_FEATURES_ARCH_ARM
|
||||
#endif
|
||||
|
||||
#if (defined(__aarch64__) || defined(_M_ARM64))
|
||||
#define CPU_FEATURES_ARCH_AARCH64
|
||||
#endif
|
||||
|
||||
#if (defined(CPU_FEATURES_ARCH_AARCH64) || defined(CPU_FEATURES_ARCH_ARM))
|
||||
#define CPU_FEATURES_ARCH_ANY_ARM
|
||||
#endif
|
||||
|
||||
#if defined(__mips64)
|
||||
#define CPU_FEATURES_ARCH_MIPS64
|
||||
#endif
|
||||
|
||||
#if defined(__mips__) && !defined(__mips64) // mips64 also declares __mips__
|
||||
#define CPU_FEATURES_ARCH_MIPS32
|
||||
#endif
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_MIPS32) || defined(CPU_FEATURES_ARCH_MIPS64)
|
||||
#define CPU_FEATURES_ARCH_MIPS
|
||||
#endif
|
||||
|
||||
#if defined(__powerpc__)
|
||||
#define CPU_FEATURES_ARCH_PPC
|
||||
#endif
|
||||
|
||||
#if defined(__s390x__)
|
||||
#define CPU_FEATURES_ARCH_S390X
|
||||
#endif
|
||||
|
||||
#if defined(__riscv)
|
||||
#define CPU_FEATURES_ARCH_RISCV
|
||||
#endif
|
||||
|
||||
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 32
|
||||
#define CPU_FEATURES_ARCH_RISCV32
|
||||
#endif
|
||||
|
||||
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64
|
||||
#define CPU_FEATURES_ARCH_RISCV64
|
||||
#endif
|
||||
|
||||
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 128
|
||||
#define CPU_FEATURES_ARCH_RISCV128
|
||||
#endif
|
||||
|
||||
#if defined(__loongarch64)
|
||||
#define CPU_FEATURES_ARCH_LOONGARCH
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Os
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if (defined(__freebsd__) || defined(__FreeBSD__))
|
||||
#define CPU_FEATURES_OS_FREEBSD
|
||||
#endif
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#define CPU_FEATURES_OS_ANDROID
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(CPU_FEATURES_OS_FREEBSD) && \
|
||||
!defined(CPU_FEATURES_OS_ANDROID)
|
||||
#define CPU_FEATURES_OS_LINUX
|
||||
#endif
|
||||
|
||||
#if (defined(_WIN64) || defined(_WIN32))
|
||||
#define CPU_FEATURES_OS_WINDOWS
|
||||
#endif
|
||||
|
||||
#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__))
|
||||
// From https://stackoverflow.com/a/49560690
|
||||
#include "TargetConditionals.h"
|
||||
#if defined(TARGET_OS_OSX)
|
||||
#define CPU_FEATURES_OS_MACOS
|
||||
#endif
|
||||
#if defined(TARGET_OS_IPHONE)
|
||||
// This is set for any non-Mac Apple products (IOS, TV, WATCH)
|
||||
#define CPU_FEATURES_OS_IPHONE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Compilers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(__clang__)
|
||||
#define CPU_FEATURES_COMPILER_CLANG
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#define CPU_FEATURES_COMPILER_GCC
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define CPU_FEATURES_COMPILER_MSC
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Cpp
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#define CPU_FEATURES_START_CPP_NAMESPACE \
|
||||
namespace cpu_features { \
|
||||
extern "C" {
|
||||
#define CPU_FEATURES_END_CPP_NAMESPACE \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define CPU_FEATURES_START_CPP_NAMESPACE
|
||||
#define CPU_FEATURES_END_CPP_NAMESPACE
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Compiler flags
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Use the following to check if a feature is known to be available at
|
||||
// compile time. See README.md for an example.
|
||||
#if defined(CPU_FEATURES_ARCH_X86)
|
||||
|
||||
#if defined(__AES__)
|
||||
#define CPU_FEATURES_COMPILED_X86_AES 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_AES 0
|
||||
#endif // defined(__AES__)
|
||||
|
||||
#if defined(__F16C__)
|
||||
#define CPU_FEATURES_COMPILED_X86_F16C 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_F16C 0
|
||||
#endif // defined(__F16C__)
|
||||
|
||||
#if defined(__BMI__)
|
||||
#define CPU_FEATURES_COMPILED_X86_BMI 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_BMI 0
|
||||
#endif // defined(__BMI__)
|
||||
|
||||
#if defined(__BMI2__)
|
||||
#define CPU_FEATURES_COMPILED_X86_BMI2 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_BMI2 0
|
||||
#endif // defined(__BMI2__)
|
||||
|
||||
#if (defined(__SSE__) || (_M_IX86_FP >= 1))
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE 0
|
||||
#endif
|
||||
|
||||
#if (defined(__SSE2__) || (_M_IX86_FP >= 2))
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE2 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE2 0
|
||||
#endif
|
||||
|
||||
#if defined(__SSE3__)
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE3 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE3 0
|
||||
#endif // defined(__SSE3__)
|
||||
|
||||
#if defined(__SSSE3__)
|
||||
#define CPU_FEATURES_COMPILED_X86_SSSE3 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_SSSE3 0
|
||||
#endif // defined(__SSSE3__)
|
||||
|
||||
#if defined(__SSE4_1__)
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE4_1 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE4_1 0
|
||||
#endif // defined(__SSE4_1__)
|
||||
|
||||
#if defined(__SSE4_2__)
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE4_2 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_SSE4_2 0
|
||||
#endif // defined(__SSE4_2__)
|
||||
|
||||
#if defined(__AVX__)
|
||||
#define CPU_FEATURES_COMPILED_X86_AVX 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_AVX 0
|
||||
#endif // defined(__AVX__)
|
||||
|
||||
#if defined(__AVX2__)
|
||||
#define CPU_FEATURES_COMPILED_X86_AVX2 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_X86_AVX2 0
|
||||
#endif // defined(__AVX2__)
|
||||
|
||||
#endif // defined(CPU_FEATURES_ARCH_X86)
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||
#if defined(__ARM_NEON__)
|
||||
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0
|
||||
#endif // defined(__ARM_NEON__)
|
||||
#endif // defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_MIPS)
|
||||
#if defined(__mips_msa)
|
||||
#define CPU_FEATURES_COMPILED_MIPS_MSA 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_MIPS_MSA 0
|
||||
#endif // defined(__mips_msa)
|
||||
#if defined(__mips3d)
|
||||
#define CPU_FEATURES_COMPILED_MIPS_MIPS3D 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_MIPS_MIPS3D 0
|
||||
#endif
|
||||
#endif // defined(CPU_FEATURES_ARCH_MIPS)
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_RISCV)
|
||||
#if defined(__riscv_e)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_E 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_E 0
|
||||
#endif
|
||||
#if defined(__riscv_i)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_I 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_I 0
|
||||
#endif
|
||||
#if defined(__riscv_m)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_M 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_M 0
|
||||
#endif
|
||||
#if defined(__riscv_a)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_A 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_A 0
|
||||
#endif
|
||||
#if defined(__riscv_f)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_F 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_F 0
|
||||
#endif
|
||||
#if defined(__riscv_d)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_D 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_D 0
|
||||
#endif
|
||||
#if defined(__riscv_q)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_Q 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_Q 0
|
||||
#endif
|
||||
#if defined(__riscv_c)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_C 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_C 0
|
||||
#endif
|
||||
#if defined(__riscv_v)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_V 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_V 0
|
||||
#endif
|
||||
#if defined(__riscv_zba)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZBA 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZBA 0
|
||||
#endif
|
||||
#if defined(__riscv_zbb)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZBB 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZBB 0
|
||||
#endif
|
||||
#if defined(__riscv_zbc)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZBC 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZBC 0
|
||||
#endif
|
||||
#if defined(__riscv_zbs)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZBS 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZBS 0
|
||||
#endif
|
||||
#if defined(__riscv_zfh)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZFH 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZFH 0
|
||||
#endif
|
||||
#if defined(__riscv_zfhmin)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZFHMIN 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZFHMIN 0
|
||||
#endif
|
||||
#if defined(__riscv_zknd)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKND 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKND 0
|
||||
#endif
|
||||
#if defined(__riscv_zkne)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKNE 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKNE 0
|
||||
#endif
|
||||
#if defined(__riscv_zknh)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKNH 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKNH 0
|
||||
#endif
|
||||
#if defined(__riscv_zksed)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKSED 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKSED 0
|
||||
#endif
|
||||
#if defined(__riscv_zksh)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKSH 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKSH 0
|
||||
#endif
|
||||
#if defined(__riscv_zkr)
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKR 1
|
||||
#else
|
||||
#define CPU_FEATURES_COMPILED_RISCV_ZKR 0
|
||||
#endif
|
||||
#endif // defined(CPU_FEATURES_ARCH_RISCV)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Communicates to the compiler that the block is unreachable
|
||||
#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
|
||||
#define CPU_FEATURES_UNREACHABLE() __builtin_unreachable()
|
||||
#elif defined(CPU_FEATURES_COMPILER_MSC)
|
||||
#define CPU_FEATURES_UNREACHABLE() __assume(0)
|
||||
#else
|
||||
#define CPU_FEATURES_UNREACHABLE()
|
||||
#endif
|
||||
|
||||
// Communicates to the compiler that the function is now deprecated
|
||||
#if defined(CPU_FEATURES_COMPILER_CLANG) || defined(CPU_FEATURES_COMPILER_GCC)
|
||||
#define CPU_FEATURES_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
#elif defined(CPU_FEATURES_COMPILER_MSC)
|
||||
#define CPU_FEATURES_DEPRECATED(message) __declspec(deprecated(message))
|
||||
#else
|
||||
#define CPU_FEATURES_DEPRECATED(message)
|
||||
#endif
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// A note on Windows AArch64 implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Getting cpu info via EL1 system registers is not possible, so we delegate it
|
||||
// to the Windows API (i.e., IsProcessorFeaturePresent and GetNativeSystemInfo).
|
||||
// The `implementer`, `variant` and `part` fields of the `Aarch64Info` struct
|
||||
// are not used, so they are set to 0. To get `revision` we use
|
||||
// `wProcessorRevision` from `SYSTEM_INFO`.
|
||||
//
|
||||
// Cryptographic Extension:
|
||||
// -----------------------------------------------------------------------------
|
||||
// According to documentation Arm Architecture Reference Manual for
|
||||
// A-profile architecture. A2.3 The Armv8 Cryptographic Extension. The Armv8.0
|
||||
// Cryptographic Extension provides instructions for the acceleration of
|
||||
// encryption and decryption, and includes the following features: FEAT_AES,
|
||||
// FEAT_PMULL, FEAT_SHA1, FEAT_SHA256.
|
||||
// see: https://developer.arm.com/documentation/ddi0487/latest
|
||||
//
|
||||
// We use `PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE` to detect all Armv8.0 crypto
|
||||
// features. This value reports all features or nothing, so even if you only
|
||||
// have support FEAT_AES and FEAT_PMULL, it will still return false.
|
||||
//
|
||||
// From Armv8.2, an implementation of the Armv8.0 Cryptographic Extension can
|
||||
// include either or both of:
|
||||
//
|
||||
// • The AES functionality, including support for multiplication of 64-bit
|
||||
// polynomials. The ID_AA64ISAR0_EL1.AES field indicates whether this
|
||||
// functionality is supported.
|
||||
// • The SHA1 and SHA2-256 functionality. The ID_AA64ISAR0_EL1.{SHA2, SHA1}
|
||||
// fields indicate whether this functionality is supported.
|
||||
//
|
||||
// ID_AA64ISAR0_EL1.AES, bits [7:4]:
|
||||
// Indicates support for AES instructions in AArch64 state. Defined values are:
|
||||
// - 0b0000 No AES instructions implemented.
|
||||
// - 0b0001 AESE, AESD, AESMC, and AESIMC instructions implemented.
|
||||
// - 0b0010 As for 0b0001, plus PMULL/PMULL2 instructions operating on 64-bit
|
||||
// data quantities.
|
||||
//
|
||||
// FEAT_AES implements the functionality identified by the value 0b0001.
|
||||
// FEAT_PMULL implements the functionality identified by the value 0b0010.
|
||||
// From Armv8, the permitted values are 0b0000 and 0b0010.
|
||||
//
|
||||
// ID_AA64ISAR0_EL1.SHA1, bits [11:8]:
|
||||
// Indicates support for SHA1 instructions in AArch64 state. Defined values are:
|
||||
// - 0b0000 No SHA1 instructions implemented.
|
||||
// - 0b0001 SHA1C, SHA1P, SHA1M, SHA1H, SHA1SU0, and SHA1SU1 instructions
|
||||
// implemented.
|
||||
//
|
||||
// FEAT_SHA1 implements the functionality identified by the value 0b0001.
|
||||
// From Armv8, the permitted values are 0b0000 and 0b0001.
|
||||
// If the value of ID_AA64ISAR0_EL1.SHA2 is 0b0000, this field must have the
|
||||
// value 0b0000.
|
||||
//
|
||||
// ID_AA64ISAR0_EL1.SHA2, bits [15:12]:
|
||||
// Indicates support for SHA2 instructions in AArch64 state. Defined values are:
|
||||
// - 0b0000 No SHA2 instructions implemented.
|
||||
// - 0b0001 Implements instructions: SHA256H, SHA256H2, SHA256SU0, and
|
||||
// SHA256SU1.
|
||||
// - 0b0010 Implements instructions:
|
||||
// • SHA256H, SHA256H2, SHA256SU0, and SHA256SU1.
|
||||
// • SHA512H, SHA512H2, SHA512SU0, and SHA512SU1.
|
||||
//
|
||||
// FEAT_SHA256 implements the functionality identified by the value 0b0001.
|
||||
// FEAT_SHA512 implements the functionality identified by the value 0b0010.
|
||||
//
|
||||
// In Armv8, the permitted values are 0b0000 and 0b0001.
|
||||
// From Armv8.2, the permitted values are 0b0000, 0b0001, and 0b0010.
|
||||
//
|
||||
// If the value of ID_AA64ISAR0_EL1.SHA1 is 0b0000, this field must have the
|
||||
// value 0b0000.
|
||||
//
|
||||
// If the value of this field is 0b0010, ID_AA64ISAR0_EL1.SHA3
|
||||
// must have the value 0b0001.
|
||||
//
|
||||
// Other cryptographic features that we cannot detect such as sha512, sha3, sm3,
|
||||
// sm4, sveaes, svepmull, svesha3, svesm4 we set to 0.
|
||||
//
|
||||
// FP/SIMD:
|
||||
// -----------------------------------------------------------------------------
|
||||
// FP/SIMD must be implemented on all Armv8.0 implementations, but
|
||||
// implementations targeting specialized markets may support the following
|
||||
// combinations:
|
||||
//
|
||||
// • No NEON or floating-point.
|
||||
// • Full floating-point and SIMD support with exception trapping.
|
||||
// • Full floating-point and SIMD support without exception trapping.
|
||||
//
|
||||
// ref:
|
||||
// https://developer.arm.com/documentation/den0024/a/AArch64-Floating-point-and-NEON
|
||||
//
|
||||
// So, we use `PF_ARM_VFP_32_REGISTERS_AVAILABLE`,
|
||||
// `PF_ARM_NEON_INSTRUCTIONS_AVAILABLE` to detect `asimd` and `fp`
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||
|
||||
#include "cpu_features_cache_info.h"
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
int fp : 1; // Floating-point.
|
||||
int asimd : 1; // Advanced SIMD.
|
||||
int evtstrm : 1; // Generic timer generated events.
|
||||
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
|
||||
int pmull : 1; // Polynomial multiply long.
|
||||
int sha1 : 1; // Hardware-accelerated SHA1.
|
||||
int sha2 : 1; // Hardware-accelerated SHA2-256.
|
||||
int crc32 : 1; // Hardware-accelerated CRC-32.
|
||||
int atomics : 1; // Armv8.1 atomic instructions.
|
||||
int fphp : 1; // Half-precision floating point support.
|
||||
int asimdhp : 1; // Advanced SIMD half-precision support.
|
||||
int cpuid : 1; // Access to certain ID registers.
|
||||
int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract.
|
||||
int jscvt : 1; // Support for JavaScript conversion.
|
||||
int fcma : 1; // Floating point complex numbers.
|
||||
int lrcpc : 1; // Support for weaker release consistency.
|
||||
int dcpop : 1; // Data persistence writeback.
|
||||
int sha3 : 1; // Hardware-accelerated SHA3.
|
||||
int sm3 : 1; // Hardware-accelerated SM3.
|
||||
int sm4 : 1; // Hardware-accelerated SM4.
|
||||
int asimddp : 1; // Dot product instruction.
|
||||
int sha512 : 1; // Hardware-accelerated SHA512.
|
||||
int sve : 1; // Scalable Vector Extension.
|
||||
int asimdfhm : 1; // Additional half-precision instructions.
|
||||
int dit : 1; // Data independent timing.
|
||||
int uscat : 1; // Unaligned atomics support.
|
||||
int ilrcpc : 1; // Additional support for weaker release consistency.
|
||||
int flagm : 1; // Flag manipulation instructions.
|
||||
int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit.
|
||||
int sb : 1; // Speculation barrier.
|
||||
int paca : 1; // Address authentication.
|
||||
int pacg : 1; // Generic authentication.
|
||||
int dcpodp : 1; // Data cache clean to point of persistence.
|
||||
int sve2 : 1; // Scalable Vector Extension (version 2).
|
||||
int sveaes : 1; // SVE AES instructions.
|
||||
int svepmull : 1; // SVE polynomial multiply long instructions.
|
||||
int svebitperm : 1; // SVE bit permute instructions.
|
||||
int svesha3 : 1; // SVE SHA3 instructions.
|
||||
int svesm4 : 1; // SVE SM4 instructions.
|
||||
int flagm2 : 1; // Additional flag manipulation instructions.
|
||||
int frint : 1; // Floating point to integer rounding.
|
||||
int svei8mm : 1; // SVE Int8 matrix multiplication instructions.
|
||||
int svef32mm : 1; // SVE FP32 matrix multiplication instruction.
|
||||
int svef64mm : 1; // SVE FP64 matrix multiplication instructions.
|
||||
int svebf16 : 1; // SVE BFloat16 instructions.
|
||||
int i8mm : 1; // Int8 matrix multiplication instructions.
|
||||
int bf16 : 1; // BFloat16 instructions.
|
||||
int dgh : 1; // Data Gathering Hint instruction.
|
||||
int rng : 1; // True random number generator support.
|
||||
int bti : 1; // Branch target identification.
|
||||
int mte : 1; // Memory tagging extension.
|
||||
int ecv : 1; // Enhanced counter virtualization.
|
||||
int afp : 1; // Alternate floating-point behaviour.
|
||||
int rpres : 1; // 12-bit reciprocal (square root) estimate precision.
|
||||
int mte3 : 1; // MTE asymmetric fault handling.
|
||||
int sme : 1; // Scalable Matrix Extension.
|
||||
int smei16i64 : 1; // 16-bit to 64-bit integer widening outer product.
|
||||
int smef64f64 : 1; // FP64 to FP64 outer product.
|
||||
int smei8i32 : 1; // 8-bit to 32-bit integer widening outer product.
|
||||
int smef16f32 : 1; // FP16 to FP32 outer product.
|
||||
int smeb16f32 : 1; // BFloat16 to FP32 outper product.
|
||||
int smef32f32 : 1; // FP32 to FP32 outer product.
|
||||
int smefa64 : 1; // Full A64 support for SME in streaming mode.
|
||||
int wfxt : 1; // WFE and WFI with timeout.
|
||||
int ebf16 : 1; // Extended BFloat16 instructions.
|
||||
int sveebf16 : 1; // SVE BFloat16 instructions.
|
||||
int cssc : 1; // Common short sequence compression instructions.
|
||||
int rprfm : 1; // Range Prefetch Memory hint instruction.
|
||||
int sve2p1 : 1; // Scalable Vector Extension (version 2.1).
|
||||
int sme2 : 1; // Scalable Matrix Extension (version 2).
|
||||
int sme2p1 : 1; // Scalable Matrix Extension (version 2.1).
|
||||
int smei16i32 : 1; // 16-bit to 64-bit integer widening outer product.
|
||||
int smebi32i32 : 1; // 1-bit binary to 32-bit integer outer product.
|
||||
int smeb16b16 : 1; // SME2.1 BFloat16 instructions.
|
||||
int smef16f16 : 1; // FP16 to FP16 outer product.
|
||||
|
||||
// Make sure to update Aarch64FeaturesEnum below if you add a field here.
|
||||
} Aarch64Features;
|
||||
|
||||
typedef struct {
|
||||
Aarch64Features features;
|
||||
int implementer; // We set 0 for Windows.
|
||||
int variant; // We set 0 for Windows.
|
||||
int part; // We set 0 for Windows.
|
||||
int revision; // We use GetNativeSystemInfo to get processor revision for
|
||||
// Windows.
|
||||
} Aarch64Info;
|
||||
|
||||
Aarch64Info GetAarch64Info(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
typedef enum {
|
||||
AARCH64_FP,
|
||||
AARCH64_ASIMD,
|
||||
AARCH64_EVTSTRM,
|
||||
AARCH64_AES,
|
||||
AARCH64_PMULL,
|
||||
AARCH64_SHA1,
|
||||
AARCH64_SHA2,
|
||||
AARCH64_CRC32,
|
||||
AARCH64_ATOMICS,
|
||||
AARCH64_FPHP,
|
||||
AARCH64_ASIMDHP,
|
||||
AARCH64_CPUID,
|
||||
AARCH64_ASIMDRDM,
|
||||
AARCH64_JSCVT,
|
||||
AARCH64_FCMA,
|
||||
AARCH64_LRCPC,
|
||||
AARCH64_DCPOP,
|
||||
AARCH64_SHA3,
|
||||
AARCH64_SM3,
|
||||
AARCH64_SM4,
|
||||
AARCH64_ASIMDDP,
|
||||
AARCH64_SHA512,
|
||||
AARCH64_SVE,
|
||||
AARCH64_ASIMDFHM,
|
||||
AARCH64_DIT,
|
||||
AARCH64_USCAT,
|
||||
AARCH64_ILRCPC,
|
||||
AARCH64_FLAGM,
|
||||
AARCH64_SSBS,
|
||||
AARCH64_SB,
|
||||
AARCH64_PACA,
|
||||
AARCH64_PACG,
|
||||
AARCH64_DCPODP,
|
||||
AARCH64_SVE2,
|
||||
AARCH64_SVEAES,
|
||||
AARCH64_SVEPMULL,
|
||||
AARCH64_SVEBITPERM,
|
||||
AARCH64_SVESHA3,
|
||||
AARCH64_SVESM4,
|
||||
AARCH64_FLAGM2,
|
||||
AARCH64_FRINT,
|
||||
AARCH64_SVEI8MM,
|
||||
AARCH64_SVEF32MM,
|
||||
AARCH64_SVEF64MM,
|
||||
AARCH64_SVEBF16,
|
||||
AARCH64_I8MM,
|
||||
AARCH64_BF16,
|
||||
AARCH64_DGH,
|
||||
AARCH64_RNG,
|
||||
AARCH64_BTI,
|
||||
AARCH64_MTE,
|
||||
AARCH64_ECV,
|
||||
AARCH64_AFP,
|
||||
AARCH64_RPRES,
|
||||
AARCH64_MTE3,
|
||||
AARCH64_SME,
|
||||
AARCH64_SME_I16I64,
|
||||
AARCH64_SME_F64F64,
|
||||
AARCH64_SME_I8I32,
|
||||
AARCH64_SME_F16F32,
|
||||
AARCH64_SME_B16F32,
|
||||
AARCH64_SME_F32F32,
|
||||
AARCH64_SME_FA64,
|
||||
AARCH64_WFXT,
|
||||
AARCH64_EBF16,
|
||||
AARCH64_SVE_EBF16,
|
||||
AARCH64_CSSC,
|
||||
AARCH64_RPRFM,
|
||||
AARCH64_SVE2P1,
|
||||
AARCH64_SME2,
|
||||
AARCH64_SME2P1,
|
||||
AARCH64_SME_I16I32,
|
||||
AARCH64_SME_BI32I32,
|
||||
AARCH64_SME_B16B16,
|
||||
AARCH64_SME_F16F16,
|
||||
AARCH64_LAST_,
|
||||
} Aarch64FeaturesEnum;
|
||||
|
||||
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
|
||||
Aarch64FeaturesEnum value);
|
||||
|
||||
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_AARCH64)
|
||||
#error "Including cpuinfo_aarch64.h from a non-aarch64 target."
|
||||
#endif
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||
|
||||
#include <stdint.h> // uint32_t
|
||||
|
||||
#include "cpu_features_cache_info.h"
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
int swp : 1; // SWP instruction (atomic read-modify-write)
|
||||
int half : 1; // Half-word loads and stores
|
||||
int thumb : 1; // Thumb (16-bit instruction set)
|
||||
int _26bit : 1; // "26 Bit" Model (Processor status register folded into
|
||||
// program counter)
|
||||
int fastmult : 1; // 32x32->64-bit multiplication
|
||||
int fpa : 1; // Floating point accelerator
|
||||
int vfp : 1; // Vector Floating Point.
|
||||
int edsp : 1; // DSP extensions (the 'e' variant of the ARM9 CPUs, and all
|
||||
// others above)
|
||||
int java : 1; // Jazelle (Java bytecode accelerator)
|
||||
int iwmmxt : 1; // Intel Wireless MMX Technology.
|
||||
int crunch : 1; // MaverickCrunch coprocessor
|
||||
int thumbee : 1; // ThumbEE
|
||||
int neon : 1; // Advanced SIMD.
|
||||
int vfpv3 : 1; // VFP version 3
|
||||
int vfpv3d16 : 1; // VFP version 3 with 16 D-registers
|
||||
int tls : 1; // TLS register
|
||||
int vfpv4 : 1; // VFP version 4 with fast context switching
|
||||
int idiva : 1; // SDIV and UDIV hardware division in ARM mode.
|
||||
int idivt : 1; // SDIV and UDIV hardware division in Thumb mode.
|
||||
int vfpd32 : 1; // VFP with 32 D-registers
|
||||
int lpae : 1; // Large Physical Address Extension (>4GB physical memory on
|
||||
// 32-bit architecture)
|
||||
int evtstrm : 1; // kernel event stream using generic architected timer
|
||||
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
|
||||
int pmull : 1; // Polynomial multiply long.
|
||||
int sha1 : 1; // Hardware-accelerated SHA1.
|
||||
int sha2 : 1; // Hardware-accelerated SHA2-256.
|
||||
int crc32 : 1; // Hardware-accelerated CRC-32.
|
||||
|
||||
// Make sure to update ArmFeaturesEnum below if you add a field here.
|
||||
} ArmFeatures;
|
||||
|
||||
typedef struct {
|
||||
ArmFeatures features;
|
||||
int implementer;
|
||||
int architecture;
|
||||
int variant;
|
||||
int part;
|
||||
int revision;
|
||||
} ArmInfo;
|
||||
|
||||
// TODO(user): Add macros to know which features are present at compile
|
||||
// time.
|
||||
|
||||
ArmInfo GetArmInfo(void);
|
||||
|
||||
// Compute CpuId from ArmInfo.
|
||||
uint32_t GetArmCpuId(const ArmInfo* const info);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
typedef enum {
|
||||
ARM_SWP,
|
||||
ARM_HALF,
|
||||
ARM_THUMB,
|
||||
ARM_26BIT,
|
||||
ARM_FASTMULT,
|
||||
ARM_FPA,
|
||||
ARM_VFP,
|
||||
ARM_EDSP,
|
||||
ARM_JAVA,
|
||||
ARM_IWMMXT,
|
||||
ARM_CRUNCH,
|
||||
ARM_THUMBEE,
|
||||
ARM_NEON,
|
||||
ARM_VFPV3,
|
||||
ARM_VFPV3D16,
|
||||
ARM_TLS,
|
||||
ARM_VFPV4,
|
||||
ARM_IDIVA,
|
||||
ARM_IDIVT,
|
||||
ARM_VFPD32,
|
||||
ARM_LPAE,
|
||||
ARM_EVTSTRM,
|
||||
ARM_AES,
|
||||
ARM_PMULL,
|
||||
ARM_SHA1,
|
||||
ARM_SHA2,
|
||||
ARM_CRC32,
|
||||
ARM_LAST_,
|
||||
} ArmFeaturesEnum;
|
||||
|
||||
int GetArmFeaturesEnumValue(const ArmFeatures* features, ArmFeaturesEnum value);
|
||||
|
||||
const char* GetArmFeaturesEnumName(ArmFeaturesEnum);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_ARM)
|
||||
#error "Including cpuinfo_arm.h from a non-arm target."
|
||||
#endif
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_
|
||||
|
||||
#include "cpu_features_cache_info.h"
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_LOONGARCH)
|
||||
#error "Including cpuinfo_loongarch.h from a non-loongarch target."
|
||||
#endif
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
// Base
|
||||
int CPUCFG : 1; // Instruction for Identify CPU Features
|
||||
|
||||
// Extension
|
||||
int LAM : 1; // Extension for Atomic Memory Access Instructions
|
||||
int UAL : 1; // Extension for Non-Aligned Memory Access
|
||||
int FPU : 1; // Extension for Basic Floating-Point Instructions
|
||||
int LSX : 1; // Extension for Loongson SIMD eXtension
|
||||
int LASX : 1; // Extension for Loongson Advanced SIMD eXtension
|
||||
int CRC32 : 1; // Extension for Cyclic Redundancy Check Instructions
|
||||
int COMPLEX : 1; // Extension for Complex Vector Operation Instructions
|
||||
int CRYPTO : 1; // Extension for Encryption And Decryption Vector Instructions
|
||||
int LVZ : 1; // Extension for Virtualization
|
||||
int LBT_X86 : 1; // Extension for X86 Binary Translation Extension
|
||||
int LBT_ARM : 1; // Extension for ARM Binary Translation Extension
|
||||
int LBT_MIPS : 1; // Extension for MIPS Binary Translation Extension
|
||||
int PTW : 1; // Extension for Page Table Walker
|
||||
|
||||
} LoongArchFeatures;
|
||||
|
||||
typedef struct {
|
||||
LoongArchFeatures features;
|
||||
} LoongArchInfo;
|
||||
|
||||
typedef enum {
|
||||
LOONGARCH_CPUCFG,
|
||||
LOONGARCH_LAM,
|
||||
LOONGARCH_UAL,
|
||||
LOONGARCH_FPU,
|
||||
LOONGARCH_LSX,
|
||||
LOONGARCH_LASX,
|
||||
LOONGARCH_CRC32,
|
||||
LOONGARCH_COMPLEX,
|
||||
LOONGARCH_CRYPTO,
|
||||
LOONGARCH_LVZ,
|
||||
LOONGARCH_LBT_X86,
|
||||
LOONGARCH_LBT_ARM,
|
||||
LOONGARCH_LBT_MIPS,
|
||||
LOONGARCH_PTW,
|
||||
LOONGARCH_LAST_,
|
||||
} LoongArchFeaturesEnum;
|
||||
|
||||
LoongArchInfo GetLoongArchInfo(void);
|
||||
int GetLoongArchFeaturesEnumValue(const LoongArchFeatures* features,
|
||||
LoongArchFeaturesEnum value);
|
||||
const char* GetLoongArchFeaturesEnumName(LoongArchFeaturesEnum);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_LOONGARCH_H_
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||
|
||||
#include "cpu_features_cache_info.h"
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
int msa : 1; // MIPS SIMD Architecture
|
||||
// https://www.mips.com/products/architectures/ase/simd/
|
||||
int eva : 1; // Enhanced Virtual Addressing
|
||||
// https://www.mips.com/products/architectures/mips64/
|
||||
int r6 : 1; // True if is release 6 of the processor.
|
||||
int mips16 : 1; // Compressed instructions
|
||||
int mdmx : 1; // MIPS Digital Media Extension
|
||||
int mips3d : 1; // 3D graphics acceleration
|
||||
// MIPS(r) Architecture for Programmers, Volume IV-c
|
||||
int smart : 1; // Smart-card cryptography
|
||||
// MIPS(r) Architecture for Programmers, Volume IV-d
|
||||
int dsp : 1; // Digital Signal Processing
|
||||
// MIPS(r) Architecture for Programmers, Volume IV-e
|
||||
// https://www.mips.com/products/architectures/ase/dsp/
|
||||
|
||||
// Make sure to update MipsFeaturesEnum below if you add a field here.
|
||||
} MipsFeatures;
|
||||
|
||||
typedef struct {
|
||||
MipsFeatures features;
|
||||
} MipsInfo;
|
||||
|
||||
MipsInfo GetMipsInfo(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
typedef enum {
|
||||
MIPS_MSA,
|
||||
MIPS_EVA,
|
||||
MIPS_R6,
|
||||
MIPS_MIPS16,
|
||||
MIPS_MDMX,
|
||||
MIPS_MIPS3D,
|
||||
MIPS_SMART,
|
||||
MIPS_DSP,
|
||||
MIPS_LAST_,
|
||||
} MipsFeaturesEnum;
|
||||
|
||||
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
|
||||
MipsFeaturesEnum value);
|
||||
|
||||
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_MIPS)
|
||||
#error "Including cpuinfo_mips.h from a non-mips target."
|
||||
#endif
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
// Copyright 2018 IBM
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||
|
||||
#include "cpu_features_cache_info.h"
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
int ppc32 : 1;
|
||||
int ppc64 : 1;
|
||||
int ppc601 : 1;
|
||||
int altivec : 1;
|
||||
int fpu : 1;
|
||||
int mmu : 1;
|
||||
int mac_4xx : 1;
|
||||
int unifiedcache : 1;
|
||||
int spe : 1;
|
||||
int efpsingle : 1;
|
||||
int efpdouble : 1;
|
||||
int no_tb : 1;
|
||||
int power4 : 1;
|
||||
int power5 : 1;
|
||||
int power5plus : 1;
|
||||
int cell : 1;
|
||||
int booke : 1;
|
||||
int smt : 1;
|
||||
int icachesnoop : 1;
|
||||
int arch205 : 1;
|
||||
int pa6t : 1;
|
||||
int dfp : 1;
|
||||
int power6ext : 1;
|
||||
int arch206 : 1;
|
||||
int vsx : 1;
|
||||
int pseries_perfmon_compat : 1;
|
||||
int truele : 1;
|
||||
int ppcle : 1;
|
||||
int arch207 : 1;
|
||||
int htm : 1;
|
||||
int dscr : 1;
|
||||
int ebb : 1;
|
||||
int isel : 1;
|
||||
int tar : 1;
|
||||
int vcrypto : 1;
|
||||
int htm_nosc : 1;
|
||||
int arch300 : 1;
|
||||
int ieee128 : 1;
|
||||
int darn : 1;
|
||||
int scv : 1;
|
||||
int htm_no_suspend : 1;
|
||||
|
||||
// Make sure to update PPCFeaturesEnum below if you add a field here.
|
||||
} PPCFeatures;
|
||||
|
||||
typedef struct {
|
||||
PPCFeatures features;
|
||||
} PPCInfo;
|
||||
|
||||
PPCInfo GetPPCInfo(void);
|
||||
|
||||
typedef struct {
|
||||
char platform[64]; // 0 terminated string
|
||||
char base_platform[64]; // 0 terminated string
|
||||
} PPCPlatformTypeStrings;
|
||||
|
||||
typedef struct {
|
||||
char platform[64]; // 0 terminated string
|
||||
char model[64]; // 0 terminated string
|
||||
char machine[64]; // 0 terminated string
|
||||
char cpu[64]; // 0 terminated string
|
||||
PPCPlatformTypeStrings type;
|
||||
} PPCPlatformStrings;
|
||||
|
||||
PPCPlatformStrings GetPPCPlatformStrings(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
typedef enum {
|
||||
PPC_32, /* 32 bit mode execution */
|
||||
PPC_64, /* 64 bit mode execution */
|
||||
PPC_601_INSTR, /* Old POWER ISA */
|
||||
PPC_HAS_ALTIVEC, /* SIMD Unit*/
|
||||
PPC_HAS_FPU, /* Floating Point Unit */
|
||||
PPC_HAS_MMU, /* Memory management unit */
|
||||
PPC_HAS_4xxMAC,
|
||||
PPC_UNIFIED_CACHE, /* Unified instruction and data cache */
|
||||
PPC_HAS_SPE, /* Signal processing extention unit */
|
||||
PPC_HAS_EFP_SINGLE, /* SPE single precision fpu */
|
||||
PPC_HAS_EFP_DOUBLE, /* SPE double precision fpu */
|
||||
PPC_NO_TB, /* No timebase */
|
||||
PPC_POWER4,
|
||||
PPC_POWER5,
|
||||
PPC_POWER5_PLUS,
|
||||
PPC_CELL, /* Cell broadband engine */
|
||||
PPC_BOOKE, /* Embedded ISA */
|
||||
PPC_SMT, /* Simultaneous multi-threading */
|
||||
PPC_ICACHE_SNOOP,
|
||||
PPC_ARCH_2_05, /* ISA 2.05 - POWER6 */
|
||||
PPC_PA6T, /* PA Semi 6T core ISA */
|
||||
PPC_HAS_DFP, /* Decimal floating point unit */
|
||||
PPC_POWER6_EXT,
|
||||
PPC_ARCH_2_06, /* ISA 2.06 - POWER7 */
|
||||
PPC_HAS_VSX, /* Vector-scalar extension */
|
||||
PPC_PSERIES_PERFMON_COMPAT, /* Set of backwards compatibile performance
|
||||
monitoring events */
|
||||
PPC_TRUE_LE,
|
||||
PPC_PPC_LE,
|
||||
PPC_ARCH_2_07, /* ISA 2.07 - POWER8 */
|
||||
PPC_HTM, /* Hardware Transactional Memory */
|
||||
PPC_DSCR, /* Data stream control register */
|
||||
PPC_EBB, /* Event base branching */
|
||||
PPC_ISEL, /* Integer select instructions */
|
||||
PPC_TAR, /* Target address register */
|
||||
PPC_VEC_CRYPTO, /* Vector cryptography instructions */
|
||||
PPC_HTM_NOSC, /* Transactions aborted when syscall made*/
|
||||
PPC_ARCH_3_00, /* ISA 3.00 - POWER9 */
|
||||
PPC_HAS_IEEE128, /* VSX IEEE Binary Float 128-bit */
|
||||
PPC_DARN, /* Deliver a random number instruction */
|
||||
PPC_SCV, /* scv syscall */
|
||||
PPC_HTM_NO_SUSPEND, /* TM w/out suspended state */
|
||||
PPC_LAST_,
|
||||
} PPCFeaturesEnum;
|
||||
|
||||
int GetPPCFeaturesEnumValue(const PPCFeatures* features, PPCFeaturesEnum value);
|
||||
|
||||
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_PPC)
|
||||
#error "Including cpuinfo_ppc.h from a non-ppc target."
|
||||
#endif
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
|
||||
|
||||
#include "cpu_features_cache_info.h"
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_RISCV)
|
||||
#error "Including cpuinfo_riscv.h from a non-riscv target."
|
||||
#endif
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
// Base
|
||||
int RV32I : 1; // Base Integer Instruction Set, 32-bit
|
||||
int RV64I : 1; // Base Integer Instruction Set, 64-bit
|
||||
|
||||
// Extension
|
||||
int M : 1; // Standard Extension for Integer Multiplication/Division
|
||||
int A : 1; // Standard Extension for Atomic Instructions
|
||||
int F : 1; // Standard Extension for Single-Precision Floating-Point
|
||||
int D : 1; // Standard Extension for Double-Precision Floating-Point
|
||||
int Q : 1; // Standard Extension for Quad-Precision Floating-Point
|
||||
int C : 1; // Standard Extension for Compressed Instructions
|
||||
int V : 1; // Standard Extension for Vector Instructions
|
||||
int Zicsr : 1; // Control and Status Register (CSR)
|
||||
int Zifencei : 1; // Instruction-Fetch Fence
|
||||
} RiscvFeatures;
|
||||
|
||||
typedef struct {
|
||||
RiscvFeatures features;
|
||||
char uarch[64]; // 0 terminated string
|
||||
char vendor[64]; // 0 terminated string
|
||||
} RiscvInfo;
|
||||
|
||||
typedef enum {
|
||||
RISCV_RV32I,
|
||||
RISCV_RV64I,
|
||||
RISCV_M,
|
||||
RISCV_A,
|
||||
RISCV_F,
|
||||
RISCV_D,
|
||||
RISCV_Q,
|
||||
RISCV_C,
|
||||
RISCV_V,
|
||||
RISCV_Zicsr,
|
||||
RISCV_Zifencei,
|
||||
RISCV_LAST_,
|
||||
} RiscvFeaturesEnum;
|
||||
|
||||
RiscvInfo GetRiscvInfo(void);
|
||||
int GetRiscvFeaturesEnumValue(const RiscvFeatures* features,
|
||||
RiscvFeaturesEnum value);
|
||||
const char* GetRiscvFeaturesEnumName(RiscvFeaturesEnum);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_RISCV_H_
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
// Copyright 2022 IBM
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
|
||||
|
||||
#include "cpu_features_cache_info.h"
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
int esan3: 1; // instructions named N3, "backported" to esa-mode
|
||||
int zarch: 1; // z/Architecture mode active
|
||||
int stfle: 1; // store-facility-list-extended
|
||||
int msa: 1; // message-security assist
|
||||
int ldisp: 1; // long-displacement
|
||||
int eimm: 1; // extended-immediate
|
||||
int dfp: 1; // decimal floating point & perform floating point operation
|
||||
int edat: 1; // huge page support
|
||||
int etf3eh: 1; // extended-translation facility 3 enhancement
|
||||
int highgprs: 1; // 64-bit register support for 31-bit processes
|
||||
int te: 1; // transactional execution
|
||||
int vx: 1; // vector extension facility
|
||||
int vxd: 1; // vector-packed-decimal facility
|
||||
int vxe: 1; // vector-enhancement facility 1
|
||||
int gs: 1; // guarded-storage facility
|
||||
int vxe2: 1; // vector-enhancements facility 2
|
||||
int vxp: 1; // vector-packed-decimal-enhancement facility
|
||||
int sort: 1; // enhanced-sort facility
|
||||
int dflt: 1; // deflate-conversion facility
|
||||
int vxp2: 1; // vector-packed-decimal-enhancement facility 2
|
||||
int nnpa: 1; // neural network processing assist facility
|
||||
int pcimio: 1; // PCI mio facility
|
||||
int sie: 1; // virtualization support
|
||||
|
||||
// Make sure to update S390XFeaturesEnum below if you add a field here.
|
||||
} S390XFeatures;
|
||||
|
||||
typedef struct {
|
||||
S390XFeatures features;
|
||||
} S390XInfo;
|
||||
|
||||
S390XInfo GetS390XInfo(void);
|
||||
|
||||
typedef struct {
|
||||
char platform[64]; // 0 terminated string
|
||||
} S390XPlatformTypeStrings;
|
||||
|
||||
typedef struct {
|
||||
int num_processors; // -1 if N/A
|
||||
S390XPlatformTypeStrings type;
|
||||
} S390XPlatformStrings;
|
||||
|
||||
S390XPlatformStrings GetS390XPlatformStrings(void);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
typedef enum {
|
||||
S390_ESAN3,
|
||||
S390_ZARCH,
|
||||
S390_STFLE,
|
||||
S390_MSA,
|
||||
S390_LDISP,
|
||||
S390_EIMM,
|
||||
S390_DFP,
|
||||
S390_EDAT,
|
||||
S390_ETF3EH,
|
||||
S390_HIGHGPRS,
|
||||
S390_TE,
|
||||
S390_VX,
|
||||
S390_VXD,
|
||||
S390_VXE,
|
||||
S390_GS,
|
||||
S390_VXE2,
|
||||
S390_VXP,
|
||||
S390_SORT,
|
||||
S390_DFLT,
|
||||
S390_VXP2,
|
||||
S390_NNPA,
|
||||
S390_PCIMIO,
|
||||
S390_SIE,
|
||||
S390X_LAST_,
|
||||
} S390XFeaturesEnum;
|
||||
|
||||
int GetS390XFeaturesEnumValue(const S390XFeatures* features, S390XFeaturesEnum value);
|
||||
|
||||
const char* GetS390XFeaturesEnumName(S390XFeaturesEnum);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_S390X)
|
||||
#error "Including cpuinfo_s390x.h from a non-s390x target."
|
||||
#endif
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_S390X_H_
|
||||
+295
@@ -0,0 +1,295 @@
|
||||
// Copyright 2017 Google LLC
|
||||
// Copyright 2020 Intel Corporation
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||
#define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||
|
||||
#include "cpu_features_cache_info.h"
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
// CPUID Vendors
|
||||
#define CPU_FEATURES_VENDOR_GENUINE_INTEL "GenuineIntel"
|
||||
#define CPU_FEATURES_VENDOR_AUTHENTIC_AMD "AuthenticAMD"
|
||||
#define CPU_FEATURES_VENDOR_HYGON_GENUINE "HygonGenuine"
|
||||
#define CPU_FEATURES_VENDOR_CENTAUR_HAULS "CentaurHauls"
|
||||
#define CPU_FEATURES_VENDOR_SHANGHAI " Shanghai "
|
||||
|
||||
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
|
||||
// The field names are based on the short name provided in the wikipedia tables.
|
||||
typedef struct {
|
||||
int fpu : 1;
|
||||
int tsc : 1;
|
||||
int cx8 : 1;
|
||||
int clfsh : 1;
|
||||
int mmx : 1;
|
||||
int aes : 1;
|
||||
int erms : 1;
|
||||
int f16c : 1;
|
||||
int fma4 : 1;
|
||||
int fma3 : 1;
|
||||
int vaes : 1;
|
||||
int vpclmulqdq : 1;
|
||||
int bmi1 : 1;
|
||||
int hle : 1;
|
||||
int bmi2 : 1;
|
||||
int rtm : 1;
|
||||
int rdseed : 1;
|
||||
int clflushopt : 1;
|
||||
int clwb : 1;
|
||||
|
||||
int sse : 1;
|
||||
int sse2 : 1;
|
||||
int sse3 : 1;
|
||||
int ssse3 : 1;
|
||||
int sse4_1 : 1;
|
||||
int sse4_2 : 1;
|
||||
int sse4a : 1;
|
||||
|
||||
int avx : 1;
|
||||
int avx_vnni : 1;
|
||||
int avx2 : 1;
|
||||
|
||||
int avx512f : 1;
|
||||
int avx512cd : 1;
|
||||
int avx512er : 1;
|
||||
int avx512pf : 1;
|
||||
int avx512bw : 1;
|
||||
int avx512dq : 1;
|
||||
int avx512vl : 1;
|
||||
int avx512ifma : 1;
|
||||
int avx512vbmi : 1;
|
||||
int avx512vbmi2 : 1;
|
||||
int avx512vnni : 1;
|
||||
int avx512bitalg : 1;
|
||||
int avx512vpopcntdq : 1;
|
||||
int avx512_4vnniw : 1;
|
||||
int avx512_4vbmi2 : 1; // Note: this is an alias to avx512_4fmaps.
|
||||
int avx512_second_fma : 1;
|
||||
int avx512_4fmaps : 1;
|
||||
int avx512_bf16 : 1;
|
||||
int avx512_vp2intersect : 1;
|
||||
int avx512_fp16 : 1;
|
||||
int amx_bf16 : 1;
|
||||
int amx_tile : 1;
|
||||
int amx_int8 : 1;
|
||||
int amx_fp16 : 1;
|
||||
|
||||
int pclmulqdq : 1;
|
||||
int smx : 1;
|
||||
int sgx : 1;
|
||||
int cx16 : 1; // aka. CMPXCHG16B
|
||||
int sha : 1;
|
||||
int popcnt : 1;
|
||||
int movbe : 1;
|
||||
int rdrnd : 1;
|
||||
|
||||
int dca : 1;
|
||||
int ss : 1;
|
||||
int adx : 1;
|
||||
int lzcnt : 1; // Note: this flag is called ABM for AMD, LZCNT for Intel.
|
||||
int gfni : 1;
|
||||
int movdiri : 1;
|
||||
int movdir64b : 1;
|
||||
int fs_rep_mov : 1; // Fast short REP MOV
|
||||
int fz_rep_movsb : 1; // Fast zero-length REP MOVSB
|
||||
int fs_rep_stosb : 1; // Fast short REP STOSB
|
||||
int fs_rep_cmpsb_scasb : 1; // Fast short REP CMPSB/SCASB
|
||||
|
||||
int lam: 1; // Intel Linear Address Mask
|
||||
int uai: 1; // AMD Upper Address Ignore
|
||||
// Make sure to update X86FeaturesEnum below if you add a field here.
|
||||
} X86Features;
|
||||
|
||||
typedef struct {
|
||||
X86Features features;
|
||||
int family;
|
||||
int model;
|
||||
int stepping;
|
||||
char vendor[13]; // 0 terminated string
|
||||
char brand_string[49]; // 0 terminated string
|
||||
} X86Info;
|
||||
|
||||
// Calls cpuid and returns an initialized X86info.
|
||||
X86Info GetX86Info(void);
|
||||
|
||||
// Returns cache hierarchy informations.
|
||||
// Can call cpuid multiple times.
|
||||
CacheInfo GetX86CacheInfo(void);
|
||||
|
||||
typedef enum {
|
||||
X86_UNKNOWN,
|
||||
ZHAOXIN_ZHANGJIANG, // ZhangJiang
|
||||
ZHAOXIN_WUDAOKOU, // WuDaoKou
|
||||
ZHAOXIN_LUJIAZUI, // LuJiaZui
|
||||
ZHAOXIN_YONGFENG, // YongFeng
|
||||
INTEL_80486, // 80486
|
||||
INTEL_P5, // P5
|
||||
INTEL_LAKEMONT, // LAKEMONT
|
||||
INTEL_CORE, // CORE
|
||||
INTEL_PNR, // PENRYN
|
||||
INTEL_NHM, // NEHALEM
|
||||
INTEL_ATOM_BNL, // BONNELL
|
||||
INTEL_WSM, // WESTMERE
|
||||
INTEL_SNB, // SANDYBRIDGE
|
||||
INTEL_IVB, // IVYBRIDGE
|
||||
INTEL_ATOM_SMT, // SILVERMONT
|
||||
INTEL_HSW, // HASWELL
|
||||
INTEL_BDW, // BROADWELL
|
||||
INTEL_SKL, // SKYLAKE
|
||||
INTEL_CCL, // CASCADELAKE
|
||||
INTEL_ATOM_GMT, // GOLDMONT
|
||||
INTEL_ATOM_GMT_PLUS, // GOLDMONT+
|
||||
INTEL_ATOM_TMT, // TREMONT
|
||||
INTEL_KBL, // KABY LAKE
|
||||
INTEL_CFL, // COFFEE LAKE
|
||||
INTEL_WHL, // WHISKEY LAKE
|
||||
INTEL_CML, // COMET LAKE
|
||||
INTEL_CNL, // CANNON LAKE
|
||||
INTEL_ICL, // ICE LAKE
|
||||
INTEL_TGL, // TIGER LAKE
|
||||
INTEL_SPR, // SAPPHIRE RAPIDS
|
||||
INTEL_ADL, // ALDER LAKE
|
||||
INTEL_RCL, // ROCKET LAKE
|
||||
INTEL_RPL, // RAPTOR LAKE
|
||||
INTEL_KNIGHTS_M, // KNIGHTS MILL
|
||||
INTEL_KNIGHTS_L, // KNIGHTS LANDING
|
||||
INTEL_KNIGHTS_F, // KNIGHTS FERRY
|
||||
INTEL_KNIGHTS_C, // KNIGHTS CORNER
|
||||
INTEL_NETBURST, // NETBURST
|
||||
AMD_HAMMER, // K8 HAMMER
|
||||
AMD_K10, // K10
|
||||
AMD_K11, // K11
|
||||
AMD_K12, // K12 LLANO
|
||||
AMD_BOBCAT, // K14 BOBCAT
|
||||
AMD_PILEDRIVER, // K15 PILEDRIVER
|
||||
AMD_STREAMROLLER, // K15 STREAMROLLER
|
||||
AMD_EXCAVATOR, // K15 EXCAVATOR
|
||||
AMD_BULLDOZER, // K15 BULLDOZER
|
||||
AMD_JAGUAR, // K16 JAGUAR
|
||||
AMD_PUMA, // K16 PUMA
|
||||
AMD_ZEN, // K17 ZEN
|
||||
AMD_ZEN_PLUS, // K17 ZEN+
|
||||
AMD_ZEN2, // K17 ZEN 2
|
||||
AMD_ZEN3, // K19 ZEN 3
|
||||
AMD_ZEN4, // K19 ZEN 4
|
||||
X86_MICROARCHITECTURE_LAST_,
|
||||
} X86Microarchitecture;
|
||||
|
||||
// Returns the underlying microarchitecture by looking at X86Info's vendor,
|
||||
// family and model.
|
||||
X86Microarchitecture GetX86Microarchitecture(const X86Info* info);
|
||||
|
||||
// Calls cpuid and fills the brand_string.
|
||||
// - brand_string *must* be of size 49 (beware of array decaying).
|
||||
// - brand_string will be zero terminated.
|
||||
CPU_FEATURES_DEPRECATED("brand_string is now embedded in X86Info by default")
|
||||
void FillX86BrandString(char brand_string[49]);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Introspection functions
|
||||
|
||||
typedef enum {
|
||||
X86_FPU,
|
||||
X86_TSC,
|
||||
X86_CX8,
|
||||
X86_CLFSH,
|
||||
X86_MMX,
|
||||
X86_AES,
|
||||
X86_ERMS,
|
||||
X86_F16C,
|
||||
X86_FMA4,
|
||||
X86_FMA3,
|
||||
X86_VAES,
|
||||
X86_VPCLMULQDQ,
|
||||
X86_BMI1,
|
||||
X86_HLE,
|
||||
X86_BMI2,
|
||||
X86_RTM,
|
||||
X86_RDSEED,
|
||||
X86_CLFLUSHOPT,
|
||||
X86_CLWB,
|
||||
X86_SSE,
|
||||
X86_SSE2,
|
||||
X86_SSE3,
|
||||
X86_SSSE3,
|
||||
X86_SSE4_1,
|
||||
X86_SSE4_2,
|
||||
X86_SSE4A,
|
||||
X86_AVX,
|
||||
X86_AVX_VNNI,
|
||||
X86_AVX2,
|
||||
X86_AVX512F,
|
||||
X86_AVX512CD,
|
||||
X86_AVX512ER,
|
||||
X86_AVX512PF,
|
||||
X86_AVX512BW,
|
||||
X86_AVX512DQ,
|
||||
X86_AVX512VL,
|
||||
X86_AVX512IFMA,
|
||||
X86_AVX512VBMI,
|
||||
X86_AVX512VBMI2,
|
||||
X86_AVX512VNNI,
|
||||
X86_AVX512BITALG,
|
||||
X86_AVX512VPOPCNTDQ,
|
||||
X86_AVX512_4VNNIW,
|
||||
X86_AVX512_4VBMI2, // Note: this is an alias to X86_AVX512_4FMAPS.
|
||||
X86_AVX512_SECOND_FMA,
|
||||
X86_AVX512_4FMAPS,
|
||||
X86_AVX512_BF16,
|
||||
X86_AVX512_VP2INTERSECT,
|
||||
X86_AVX512_FP16,
|
||||
X86_AMX_BF16,
|
||||
X86_AMX_TILE,
|
||||
X86_AMX_INT8,
|
||||
X86_AMX_FP16,
|
||||
X86_PCLMULQDQ,
|
||||
X86_SMX,
|
||||
X86_SGX,
|
||||
X86_CX16,
|
||||
X86_SHA,
|
||||
X86_POPCNT,
|
||||
X86_MOVBE,
|
||||
X86_RDRND,
|
||||
X86_DCA,
|
||||
X86_SS,
|
||||
X86_ADX,
|
||||
X86_LZCNT,
|
||||
X86_GFNI,
|
||||
X86_MOVDIRI,
|
||||
X86_MOVDIR64B,
|
||||
X86_FS_REP_MOV,
|
||||
X86_FZ_REP_MOVSB,
|
||||
X86_FS_REP_STOSB,
|
||||
X86_FS_REP_CMPSB_SCASB,
|
||||
X86_LAM,
|
||||
X86_UAI,
|
||||
X86_LAST_,
|
||||
} X86FeaturesEnum;
|
||||
|
||||
int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value);
|
||||
|
||||
const char* GetX86FeaturesEnumName(X86FeaturesEnum);
|
||||
|
||||
const char* GetX86MicroarchitectureName(X86Microarchitecture);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_X86)
|
||||
#error "Including cpuinfo_x86.h from a non-x86 target."
|
||||
#endif
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||
#define CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
inline static bool IsBitSet(uint32_t reg, uint32_t bit) {
|
||||
return (reg >> bit) & 0x1;
|
||||
}
|
||||
|
||||
inline static uint32_t ExtractBitRange(uint32_t reg, uint32_t msb,
|
||||
uint32_t lsb) {
|
||||
const uint64_t bits = msb - lsb + 1ULL;
|
||||
const uint64_t mask = (1ULL << bits) - 1ULL;
|
||||
assert(msb >= lsb);
|
||||
return (reg >> lsb) & mask;
|
||||
}
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||
#define CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
// A struct to hold the result of a call to cpuid.
|
||||
typedef struct {
|
||||
uint32_t eax, ebx, ecx, edx;
|
||||
} Leaf;
|
||||
|
||||
// Returns the result of a call to the cpuid instruction.
|
||||
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx);
|
||||
|
||||
// Returns the eax value of the XCR0 register.
|
||||
uint32_t GetXCR0Eax(void);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// An interface for the filesystem that allows mocking the filesystem in
|
||||
// unittests.
|
||||
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||
#define CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
// Same as linux "open(filename, O_RDONLY)", retries automatically on EINTR.
|
||||
int CpuFeatures_OpenFile(const char* filename);
|
||||
|
||||
// Same as linux "read(file_descriptor, buffer, buffer_size)", retries
|
||||
// automatically on EINTR.
|
||||
int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size);
|
||||
|
||||
// Same as linux "close(file_descriptor)".
|
||||
void CpuFeatures_CloseFile(int file_descriptor);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Interface to retrieve hardware capabilities. It relies on Linux's getauxval
|
||||
// or `/proc/self/auxval` under the hood.
|
||||
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||
#define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
// To avoid depending on the linux kernel we reproduce the architecture specific
|
||||
// constants here.
|
||||
|
||||
// http://elixir.free-electrons.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h
|
||||
#define AARCH64_HWCAP_FP (1UL << 0)
|
||||
#define AARCH64_HWCAP_ASIMD (1UL << 1)
|
||||
#define AARCH64_HWCAP_EVTSTRM (1UL << 2)
|
||||
#define AARCH64_HWCAP_AES (1UL << 3)
|
||||
#define AARCH64_HWCAP_PMULL (1UL << 4)
|
||||
#define AARCH64_HWCAP_SHA1 (1UL << 5)
|
||||
#define AARCH64_HWCAP_SHA2 (1UL << 6)
|
||||
#define AARCH64_HWCAP_CRC32 (1UL << 7)
|
||||
#define AARCH64_HWCAP_ATOMICS (1UL << 8)
|
||||
#define AARCH64_HWCAP_FPHP (1UL << 9)
|
||||
#define AARCH64_HWCAP_ASIMDHP (1UL << 10)
|
||||
#define AARCH64_HWCAP_CPUID (1UL << 11)
|
||||
#define AARCH64_HWCAP_ASIMDRDM (1UL << 12)
|
||||
#define AARCH64_HWCAP_JSCVT (1UL << 13)
|
||||
#define AARCH64_HWCAP_FCMA (1UL << 14)
|
||||
#define AARCH64_HWCAP_LRCPC (1UL << 15)
|
||||
#define AARCH64_HWCAP_DCPOP (1UL << 16)
|
||||
#define AARCH64_HWCAP_SHA3 (1UL << 17)
|
||||
#define AARCH64_HWCAP_SM3 (1UL << 18)
|
||||
#define AARCH64_HWCAP_SM4 (1UL << 19)
|
||||
#define AARCH64_HWCAP_ASIMDDP (1UL << 20)
|
||||
#define AARCH64_HWCAP_SHA512 (1UL << 21)
|
||||
#define AARCH64_HWCAP_SVE (1UL << 22)
|
||||
#define AARCH64_HWCAP_ASIMDFHM (1UL << 23)
|
||||
#define AARCH64_HWCAP_DIT (1UL << 24)
|
||||
#define AARCH64_HWCAP_USCAT (1UL << 25)
|
||||
#define AARCH64_HWCAP_ILRCPC (1UL << 26)
|
||||
#define AARCH64_HWCAP_FLAGM (1UL << 27)
|
||||
#define AARCH64_HWCAP_SSBS (1UL << 28)
|
||||
#define AARCH64_HWCAP_SB (1UL << 29)
|
||||
#define AARCH64_HWCAP_PACA (1UL << 30)
|
||||
#define AARCH64_HWCAP_PACG (1UL << 31)
|
||||
|
||||
#define AARCH64_HWCAP2_DCPODP (1UL << 0)
|
||||
#define AARCH64_HWCAP2_SVE2 (1UL << 1)
|
||||
#define AARCH64_HWCAP2_SVEAES (1UL << 2)
|
||||
#define AARCH64_HWCAP2_SVEPMULL (1UL << 3)
|
||||
#define AARCH64_HWCAP2_SVEBITPERM (1UL << 4)
|
||||
#define AARCH64_HWCAP2_SVESHA3 (1UL << 5)
|
||||
#define AARCH64_HWCAP2_SVESM4 (1UL << 6)
|
||||
#define AARCH64_HWCAP2_FLAGM2 (1UL << 7)
|
||||
#define AARCH64_HWCAP2_FRINT (1UL << 8)
|
||||
#define AARCH64_HWCAP2_SVEI8MM (1UL << 9)
|
||||
#define AARCH64_HWCAP2_SVEF32MM (1UL << 10)
|
||||
#define AARCH64_HWCAP2_SVEF64MM (1UL << 11)
|
||||
#define AARCH64_HWCAP2_SVEBF16 (1UL << 12)
|
||||
#define AARCH64_HWCAP2_I8MM (1UL << 13)
|
||||
#define AARCH64_HWCAP2_BF16 (1UL << 14)
|
||||
#define AARCH64_HWCAP2_DGH (1UL << 15)
|
||||
#define AARCH64_HWCAP2_RNG (1UL << 16)
|
||||
#define AARCH64_HWCAP2_BTI (1UL << 17)
|
||||
#define AARCH64_HWCAP2_MTE (1UL << 18)
|
||||
#define AARCH64_HWCAP2_ECV (1UL << 19)
|
||||
#define AARCH64_HWCAP2_AFP (1UL << 20)
|
||||
#define AARCH64_HWCAP2_RPRES (1UL << 21)
|
||||
#define AARCH64_HWCAP2_MTE3 (1UL << 22)
|
||||
#define AARCH64_HWCAP2_SME (1UL << 23)
|
||||
#define AARCH64_HWCAP2_SME_I16I64 (1UL << 24)
|
||||
#define AARCH64_HWCAP2_SME_F64F64 (1UL << 25)
|
||||
#define AARCH64_HWCAP2_SME_I8I32 (1UL << 26)
|
||||
#define AARCH64_HWCAP2_SME_F16F32 (1UL << 27)
|
||||
#define AARCH64_HWCAP2_SME_B16F32 (1UL << 28)
|
||||
#define AARCH64_HWCAP2_SME_F32F32 (1UL << 29)
|
||||
#define AARCH64_HWCAP2_SME_FA64 (1UL << 30)
|
||||
#define AARCH64_HWCAP2_WFXT (1UL << 31)
|
||||
#define AARCH64_HWCAP2_EBF16 (1UL << 32)
|
||||
#define AARCH64_HWCAP2_SVE_EBF16 (1UL << 33)
|
||||
#define AARCH64_HWCAP2_CSSC (1UL << 34)
|
||||
#define AARCH64_HWCAP2_RPRFM (1UL << 35)
|
||||
#define AARCH64_HWCAP2_SVE2P1 (1UL << 36)
|
||||
#define AARCH64_HWCAP2_SME2 (1UL << 37)
|
||||
#define AARCH64_HWCAP2_SME2P1 (1UL << 38)
|
||||
#define AARCH64_HWCAP2_SME_I16I32 (1UL << 39)
|
||||
#define AARCH64_HWCAP2_SME_BI32I32 (1UL << 40)
|
||||
#define AARCH64_HWCAP2_SME_B16B16 (1UL << 41)
|
||||
#define AARCH64_HWCAP2_SME_F16F16 (1UL << 42)
|
||||
|
||||
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
|
||||
#define ARM_HWCAP_SWP (1UL << 0)
|
||||
#define ARM_HWCAP_HALF (1UL << 1)
|
||||
#define ARM_HWCAP_THUMB (1UL << 2)
|
||||
#define ARM_HWCAP_26BIT (1UL << 3)
|
||||
#define ARM_HWCAP_FAST_MULT (1UL << 4)
|
||||
#define ARM_HWCAP_FPA (1UL << 5)
|
||||
#define ARM_HWCAP_VFP (1UL << 6)
|
||||
#define ARM_HWCAP_EDSP (1UL << 7)
|
||||
#define ARM_HWCAP_JAVA (1UL << 8)
|
||||
#define ARM_HWCAP_IWMMXT (1UL << 9)
|
||||
#define ARM_HWCAP_CRUNCH (1UL << 10)
|
||||
#define ARM_HWCAP_THUMBEE (1UL << 11)
|
||||
#define ARM_HWCAP_NEON (1UL << 12)
|
||||
#define ARM_HWCAP_VFPV3 (1UL << 13)
|
||||
#define ARM_HWCAP_VFPV3D16 (1UL << 14)
|
||||
#define ARM_HWCAP_TLS (1UL << 15)
|
||||
#define ARM_HWCAP_VFPV4 (1UL << 16)
|
||||
#define ARM_HWCAP_IDIVA (1UL << 17)
|
||||
#define ARM_HWCAP_IDIVT (1UL << 18)
|
||||
#define ARM_HWCAP_VFPD32 (1UL << 19)
|
||||
#define ARM_HWCAP_LPAE (1UL << 20)
|
||||
#define ARM_HWCAP_EVTSTRM (1UL << 21)
|
||||
#define ARM_HWCAP2_AES (1UL << 0)
|
||||
#define ARM_HWCAP2_PMULL (1UL << 1)
|
||||
#define ARM_HWCAP2_SHA1 (1UL << 2)
|
||||
#define ARM_HWCAP2_SHA2 (1UL << 3)
|
||||
#define ARM_HWCAP2_CRC32 (1UL << 4)
|
||||
|
||||
// http://elixir.free-electrons.com/linux/latest/source/arch/mips/include/uapi/asm/hwcap.h
|
||||
#define MIPS_HWCAP_R6 (1UL << 0)
|
||||
#define MIPS_HWCAP_MSA (1UL << 1)
|
||||
#define MIPS_HWCAP_CRC32 (1UL << 2)
|
||||
#define MIPS_HWCAP_MIPS16 (1UL << 3)
|
||||
#define MIPS_HWCAP_MDMX (1UL << 4)
|
||||
#define MIPS_HWCAP_MIPS3D (1UL << 5)
|
||||
#define MIPS_HWCAP_SMARTMIPS (1UL << 6)
|
||||
#define MIPS_HWCAP_DSP (1UL << 7)
|
||||
#define MIPS_HWCAP_DSP2 (1UL << 8)
|
||||
#define MIPS_HWCAP_DSP3 (1UL << 9)
|
||||
|
||||
// http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h
|
||||
#ifndef _UAPI__ASM_POWERPC_CPUTABLE_H
|
||||
/* in AT_HWCAP */
|
||||
#define PPC_FEATURE_32 0x80000000
|
||||
#define PPC_FEATURE_64 0x40000000
|
||||
#define PPC_FEATURE_601_INSTR 0x20000000
|
||||
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
|
||||
#define PPC_FEATURE_HAS_FPU 0x08000000
|
||||
#define PPC_FEATURE_HAS_MMU 0x04000000
|
||||
#define PPC_FEATURE_HAS_4xxMAC 0x02000000
|
||||
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
|
||||
#define PPC_FEATURE_HAS_SPE 0x00800000
|
||||
#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000
|
||||
#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000
|
||||
#define PPC_FEATURE_NO_TB 0x00100000
|
||||
#define PPC_FEATURE_POWER4 0x00080000
|
||||
#define PPC_FEATURE_POWER5 0x00040000
|
||||
#define PPC_FEATURE_POWER5_PLUS 0x00020000
|
||||
#define PPC_FEATURE_CELL 0x00010000
|
||||
#define PPC_FEATURE_BOOKE 0x00008000
|
||||
#define PPC_FEATURE_SMT 0x00004000
|
||||
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
|
||||
#define PPC_FEATURE_ARCH_2_05 0x00001000
|
||||
#define PPC_FEATURE_PA6T 0x00000800
|
||||
#define PPC_FEATURE_HAS_DFP 0x00000400
|
||||
#define PPC_FEATURE_POWER6_EXT 0x00000200
|
||||
#define PPC_FEATURE_ARCH_2_06 0x00000100
|
||||
#define PPC_FEATURE_HAS_VSX 0x00000080
|
||||
|
||||
#define PPC_FEATURE_PSERIES_PERFMON_COMPAT 0x00000040
|
||||
|
||||
/* Reserved - do not use 0x00000004 */
|
||||
#define PPC_FEATURE_TRUE_LE 0x00000002
|
||||
#define PPC_FEATURE_PPC_LE 0x00000001
|
||||
|
||||
/* in AT_HWCAP2 */
|
||||
#define PPC_FEATURE2_ARCH_2_07 0x80000000
|
||||
#define PPC_FEATURE2_HTM 0x40000000
|
||||
#define PPC_FEATURE2_DSCR 0x20000000
|
||||
#define PPC_FEATURE2_EBB 0x10000000
|
||||
#define PPC_FEATURE2_ISEL 0x08000000
|
||||
#define PPC_FEATURE2_TAR 0x04000000
|
||||
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
|
||||
#define PPC_FEATURE2_HTM_NOSC 0x01000000
|
||||
#define PPC_FEATURE2_ARCH_3_00 0x00800000
|
||||
#define PPC_FEATURE2_HAS_IEEE128 0x00400000
|
||||
#define PPC_FEATURE2_DARN 0x00200000
|
||||
#define PPC_FEATURE2_SCV 0x00100000
|
||||
#define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000
|
||||
#endif
|
||||
|
||||
// https://elixir.bootlin.com/linux/v6.0-rc6/source/arch/s390/include/asm/elf.h
|
||||
#define HWCAP_S390_ESAN3 1
|
||||
#define HWCAP_S390_ZARCH 2
|
||||
#define HWCAP_S390_STFLE 4
|
||||
#define HWCAP_S390_MSA 8
|
||||
#define HWCAP_S390_LDISP 16
|
||||
#define HWCAP_S390_EIMM 32
|
||||
#define HWCAP_S390_DFP 64
|
||||
#define HWCAP_S390_HPAGE 128
|
||||
#define HWCAP_S390_ETF3EH 256
|
||||
#define HWCAP_S390_HIGH_GPRS 512
|
||||
#define HWCAP_S390_TE 1024
|
||||
#define HWCAP_S390_VX 2048
|
||||
#define HWCAP_S390_VXRS HWCAP_S390_VX
|
||||
#define HWCAP_S390_VXD 4096
|
||||
#define HWCAP_S390_VXRS_BCD HWCAP_S390_VXD
|
||||
#define HWCAP_S390_VXE 8192
|
||||
#define HWCAP_S390_VXRS_EXT HWCAP_S390_VXE
|
||||
#define HWCAP_S390_GS 16384
|
||||
#define HWCAP_S390_VXRS_EXT2 32768
|
||||
#define HWCAP_S390_VXRS_PDE 65536
|
||||
#define HWCAP_S390_SORT 131072
|
||||
#define HWCAP_S390_DFLT 262144
|
||||
#define HWCAP_S390_VXRS_PDE2 524288
|
||||
#define HWCAP_S390_NNPA 1048576
|
||||
#define HWCAP_S390_PCI_MIO 2097152
|
||||
#define HWCAP_S390_SIE 4194304
|
||||
|
||||
// https://elixir.bootlin.com/linux/latest/source/arch/riscv/include/uapi/asm/hwcap.h
|
||||
#define RISCV_HWCAP_32 0x32
|
||||
#define RISCV_HWCAP_64 0x64
|
||||
#define RISCV_HWCAP_128 0x128
|
||||
#define RISCV_HWCAP_M (1UL << ('M' - 'A'))
|
||||
#define RISCV_HWCAP_A (1UL << ('A' - 'A'))
|
||||
#define RISCV_HWCAP_F (1UL << ('F' - 'A'))
|
||||
#define RISCV_HWCAP_D (1UL << ('D' - 'A'))
|
||||
#define RISCV_HWCAP_Q (1UL << ('Q' - 'A'))
|
||||
#define RISCV_HWCAP_C (1UL << ('C' - 'A'))
|
||||
#define RISCV_HWCAP_V (1UL << ('V' - 'A'))
|
||||
|
||||
// https://github.com/torvalds/linux/blob/master/arch/loongarch/include/uapi/asm/hwcap.h
|
||||
#define HWCAP_LOONGARCH_CPUCFG (1 << 0)
|
||||
#define HWCAP_LOONGARCH_LAM (1 << 1)
|
||||
#define HWCAP_LOONGARCH_UAL (1 << 2)
|
||||
#define HWCAP_LOONGARCH_FPU (1 << 3)
|
||||
#define HWCAP_LOONGARCH_LSX (1 << 4)
|
||||
#define HWCAP_LOONGARCH_LASX (1 << 5)
|
||||
#define HWCAP_LOONGARCH_CRC32 (1 << 6)
|
||||
#define HWCAP_LOONGARCH_COMPLEX (1 << 7)
|
||||
#define HWCAP_LOONGARCH_CRYPTO (1 << 8)
|
||||
#define HWCAP_LOONGARCH_LVZ (1 << 9)
|
||||
#define HWCAP_LOONGARCH_LBT_X86 (1 << 10)
|
||||
#define HWCAP_LOONGARCH_LBT_ARM (1 << 11)
|
||||
#define HWCAP_LOONGARCH_LBT_MIPS (1 << 12)
|
||||
#define HWCAP_LOONGARCH_PTW (1 << 13)
|
||||
|
||||
typedef struct {
|
||||
unsigned long hwcaps;
|
||||
unsigned long hwcaps2;
|
||||
} HardwareCapabilities;
|
||||
|
||||
// Retrieves values from auxiliary vector for types AT_HWCAP and AT_HWCAP2.
|
||||
// First tries to call getauxval(), if not available falls back to reading
|
||||
// "/proc/self/auxv".
|
||||
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
|
||||
|
||||
// Checks whether value for AT_HWCAP (or AT_HWCAP2) match hwcaps_mask.
|
||||
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
|
||||
const HardwareCapabilities hwcaps);
|
||||
|
||||
// Get pointer for the AT_PLATFORM type.
|
||||
const char* CpuFeatures_GetPlatformPointer(void);
|
||||
// Get pointer for the AT_BASE_PLATFORM type.
|
||||
const char* CpuFeatures_GetBasePlatformPointer(void);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Reads a file line by line and stores the data on the stack. This allows
|
||||
// parsing files in one go without allocating.
|
||||
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||
#define CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
char buffer[STACK_LINE_READER_BUFFER_SIZE];
|
||||
StringView view;
|
||||
int fd;
|
||||
bool skip_mode;
|
||||
} StackLineReader;
|
||||
|
||||
// Initializes a StackLineReader.
|
||||
void StackLineReader_Initialize(StackLineReader* reader, int fd);
|
||||
|
||||
typedef struct {
|
||||
StringView line; // A view of the line.
|
||||
bool eof; // Nothing more to read, we reached EOF.
|
||||
bool full_line; // If false the line was truncated to
|
||||
// STACK_LINE_READER_BUFFER_SIZE.
|
||||
} LineResult;
|
||||
|
||||
// Reads the file pointed to by fd and tries to read a full line.
|
||||
LineResult StackLineReader_NextLine(StackLineReader* reader);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||
@@ -0,0 +1,110 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// A view over a piece of string. The view is not 0 terminated.
|
||||
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||
#define CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
CPU_FEATURES_START_CPP_NAMESPACE
|
||||
|
||||
typedef struct {
|
||||
const char* ptr;
|
||||
size_t size;
|
||||
} StringView;
|
||||
|
||||
#ifdef __cplusplus
|
||||
static const StringView kEmptyStringView = {NULL, 0};
|
||||
#else
|
||||
static const StringView kEmptyStringView;
|
||||
#endif
|
||||
|
||||
// Returns a StringView from the provided string.
|
||||
// Passing NULL is valid only if size is 0.
|
||||
static inline StringView view(const char* str, const size_t size) {
|
||||
StringView view;
|
||||
view.ptr = str;
|
||||
view.size = size;
|
||||
return view;
|
||||
}
|
||||
|
||||
static inline StringView str(const char* str) { return view(str, strlen(str)); }
|
||||
|
||||
// Returns the index of the first occurrence of c in view or -1 if not found.
|
||||
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c);
|
||||
|
||||
// Returns the index of the first occurrence of sub_view in view or -1 if not
|
||||
// found.
|
||||
int CpuFeatures_StringView_IndexOf(const StringView view,
|
||||
const StringView sub_view);
|
||||
|
||||
// Returns whether a is equal to b (same content).
|
||||
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b);
|
||||
|
||||
// Returns whether a starts with b.
|
||||
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b);
|
||||
|
||||
// Removes count characters from the beginning of view or kEmptyStringView if
|
||||
// count if greater than view.size.
|
||||
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
|
||||
size_t count);
|
||||
|
||||
// Removes count characters from the end of view or kEmptyStringView if count if
|
||||
// greater than view.size.
|
||||
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
|
||||
size_t count);
|
||||
|
||||
// Keeps the count first characters of view or view if count if greater than
|
||||
// view.size.
|
||||
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
|
||||
size_t count);
|
||||
|
||||
// Retrieves the first character of view. If view is empty the behavior is
|
||||
// undefined.
|
||||
char CpuFeatures_StringView_Front(const StringView view);
|
||||
|
||||
// Retrieves the last character of view. If view is empty the behavior is
|
||||
// undefined.
|
||||
char CpuFeatures_StringView_Back(const StringView view);
|
||||
|
||||
// Removes leading and tailing space characters.
|
||||
StringView CpuFeatures_StringView_TrimWhitespace(StringView view);
|
||||
|
||||
// Convert StringView to positive integer. e.g. "42", "0x2a".
|
||||
// Returns -1 on error.
|
||||
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view);
|
||||
|
||||
// Copies src StringView to dst buffer.
|
||||
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||
size_t dst_size);
|
||||
|
||||
// Checks if line contains the specified whitespace separated word.
|
||||
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||
const char* const word,
|
||||
const char separator);
|
||||
|
||||
// Get key/value from line. key and value are separated by ": ".
|
||||
// key and value are cleaned up from leading and trailing whitespaces.
|
||||
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
|
||||
StringView* key,
|
||||
StringView* value);
|
||||
|
||||
CPU_FEATURES_END_CPP_NAMESPACE
|
||||
|
||||
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
|
||||
#define CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_OS_WINDOWS
|
||||
|
||||
#include <windows.h> // IsProcessorFeaturePresent
|
||||
|
||||
// modern WinSDK winnt.h contains newer features detection definitions
|
||||
#if !defined(PF_SSSE3_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_SSSE3_INSTRUCTIONS_AVAILABLE 36
|
||||
#endif
|
||||
|
||||
#if !defined(PF_SSE4_1_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37
|
||||
#endif
|
||||
|
||||
#if !defined(PF_SSE4_2_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38
|
||||
#endif
|
||||
|
||||
#if !defined(PF_ARM_VFP_32_REGISTERS_AVAILABLE)
|
||||
#define PF_ARM_VFP_32_REGISTERS_AVAILABLE 18
|
||||
#endif
|
||||
|
||||
#if !defined(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
|
||||
#endif
|
||||
|
||||
#if !defined(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE 30
|
||||
#endif
|
||||
|
||||
#if !defined(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE 31
|
||||
#endif
|
||||
|
||||
#if !defined(PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE 34
|
||||
#endif
|
||||
|
||||
#if !defined(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE 43
|
||||
#endif
|
||||
|
||||
#if !defined(PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE 44
|
||||
#endif
|
||||
|
||||
#if !defined(PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE)
|
||||
#define PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE 45
|
||||
#endif
|
||||
|
||||
#endif // CPU_FEATURES_OS_WINDOWS
|
||||
#endif // CPU_FEATURES_INCLUDE_INTERNAL_WINDOWS_UTILS_H_
|
||||
Vendored
+19
@@ -0,0 +1,19 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
static void copy(char *__restrict dst, const char *src, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) dst[i] = src[i];
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef INTROSPECTION_PREFIX
|
||||
#error "missing INTROSPECTION_PREFIX"
|
||||
#endif
|
||||
#ifndef INTROSPECTION_ENUM_PREFIX
|
||||
#error "missing INTROSPECTION_ENUM_PREFIX"
|
||||
#endif
|
||||
#ifndef INTROSPECTION_TABLE
|
||||
#error "missing INTROSPECTION_TABLE"
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define STRINGIZE_(s) #s
|
||||
#define STRINGIZE(s) STRINGIZE_(s)
|
||||
|
||||
#define FEAT_TYPE_NAME__(X) X##Features
|
||||
#define FEAT_TYPE_NAME_(X) FEAT_TYPE_NAME__(X)
|
||||
#define FEAT_TYPE_NAME FEAT_TYPE_NAME_(INTROSPECTION_PREFIX)
|
||||
|
||||
#define FEAT_ENUM_NAME__(X) X##FeaturesEnum
|
||||
#define FEAT_ENUM_NAME_(X) FEAT_ENUM_NAME__(X)
|
||||
#define FEAT_ENUM_NAME FEAT_ENUM_NAME_(INTROSPECTION_PREFIX)
|
||||
|
||||
#define GET_FEAT_ENUM_VALUE__(X) Get##X##FeaturesEnumValue
|
||||
#define GET_FEAT_ENUM_VALUE_(X) GET_FEAT_ENUM_VALUE__(X)
|
||||
#define GET_FEAT_ENUM_VALUE GET_FEAT_ENUM_VALUE_(INTROSPECTION_PREFIX)
|
||||
|
||||
#define GET_FEAT_ENUM_NAME__(X) Get##X##FeaturesEnumName
|
||||
#define GET_FEAT_ENUM_NAME_(X) GET_FEAT_ENUM_NAME__(X)
|
||||
#define GET_FEAT_ENUM_NAME GET_FEAT_ENUM_NAME_(INTROSPECTION_PREFIX)
|
||||
|
||||
#define FEAT_ENUM_LAST__(X) X##_LAST_
|
||||
#define FEAT_ENUM_LAST_(X) FEAT_ENUM_LAST__(X)
|
||||
#define FEAT_ENUM_LAST FEAT_ENUM_LAST_(INTROSPECTION_ENUM_PREFIX)
|
||||
|
||||
// Generate individual getters and setters.
|
||||
#define LINE(ENUM, NAME, A, B, C) \
|
||||
static void set_##ENUM(FEAT_TYPE_NAME* features, bool value) { \
|
||||
features->NAME = value; \
|
||||
} \
|
||||
static int get_##ENUM(const FEAT_TYPE_NAME* features) { \
|
||||
return features->NAME; \
|
||||
}
|
||||
INTROSPECTION_TABLE
|
||||
#undef LINE
|
||||
|
||||
// Generate getters table
|
||||
#define LINE(ENUM, NAME, A, B, C) [ENUM] = get_##ENUM,
|
||||
static int (*const kGetters[])(const FEAT_TYPE_NAME*) = {INTROSPECTION_TABLE};
|
||||
#undef LINE
|
||||
|
||||
// Generate setters table
|
||||
#define LINE(ENUM, NAME, A, B, C) [ENUM] = set_##ENUM,
|
||||
static void (*const kSetters[])(FEAT_TYPE_NAME*, bool) = {INTROSPECTION_TABLE};
|
||||
#undef LINE
|
||||
|
||||
// Implements the `GetXXXFeaturesEnumValue` API.
|
||||
int GET_FEAT_ENUM_VALUE(const FEAT_TYPE_NAME* features, FEAT_ENUM_NAME value) {
|
||||
if (value >= FEAT_ENUM_LAST) return false;
|
||||
return kGetters[value](features);
|
||||
}
|
||||
|
||||
// Generate feature name table.
|
||||
#define LINE(ENUM, NAME, A, B, C) [ENUM] = STRINGIZE(NAME),
|
||||
static const char* kFeatureNames[] = {INTROSPECTION_TABLE};
|
||||
#undef LINE
|
||||
|
||||
// Implements the `GetXXXFeaturesEnumName` API.
|
||||
const char* GET_FEAT_ENUM_NAME(FEAT_ENUM_NAME value) {
|
||||
if (value >= FEAT_ENUM_LAST) return "unknown_feature";
|
||||
return kFeatureNames[value];
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "define_introspection.inl"
|
||||
#include "internal/hwcaps.h"
|
||||
|
||||
#define LINE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
|
||||
[ENUM] = (HardwareCapabilities){HWCAP, HWCAP2},
|
||||
static const HardwareCapabilities kHardwareCapabilities[] = {
|
||||
INTROSPECTION_TABLE};
|
||||
#undef LINE
|
||||
|
||||
#define LINE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG,
|
||||
static const char* kCpuInfoFlags[] = {INTROSPECTION_TABLE};
|
||||
#undef LINE
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
static bool equals(const char *lhs, const char *rhs, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
if (lhs[i] != rhs[i]) return false;
|
||||
return true;
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined(CPU_FEATURES_MOCK_FILESYSTEM)
|
||||
// Implementation will be provided by test/filesystem_for_testing.cc.
|
||||
#elif defined(_MSC_VER)
|
||||
#include <io.h>
|
||||
int CpuFeatures_OpenFile(const char* filename) {
|
||||
int fd = -1;
|
||||
_sopen_s(&fd, filename, _O_RDONLY, _SH_DENYWR, _S_IREAD);
|
||||
return fd;
|
||||
}
|
||||
|
||||
void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); }
|
||||
|
||||
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||
size_t buffer_size) {
|
||||
return _read(file_descriptor, buffer, (unsigned int)buffer_size);
|
||||
}
|
||||
|
||||
#else
|
||||
#include <unistd.h>
|
||||
|
||||
int CpuFeatures_OpenFile(const char* filename) {
|
||||
int result;
|
||||
do {
|
||||
result = open(filename, O_RDONLY);
|
||||
} while (result == -1L && errno == EINTR);
|
||||
return result;
|
||||
}
|
||||
|
||||
void CpuFeatures_CloseFile(int file_descriptor) { close(file_descriptor); }
|
||||
|
||||
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||
size_t buffer_size) {
|
||||
int result;
|
||||
do {
|
||||
result = read(file_descriptor, buffer, buffer_size);
|
||||
} while (result == -1L && errno == EINTR);
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
Vendored
+169
@@ -0,0 +1,169 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/hwcaps.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
static bool IsSet(const uint32_t mask, const uint32_t value) {
|
||||
if (mask == 0) return false;
|
||||
return (value & mask) == mask;
|
||||
}
|
||||
|
||||
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
|
||||
const HardwareCapabilities hwcaps) {
|
||||
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
|
||||
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
|
||||
}
|
||||
|
||||
#ifdef CPU_FEATURES_TEST
|
||||
// In test mode, hwcaps_for_testing will define the following functions.
|
||||
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
|
||||
const char* CpuFeatures_GetPlatformPointer(void);
|
||||
const char* CpuFeatures_GetBasePlatformPointer(void);
|
||||
#else
|
||||
|
||||
// Debug facilities
|
||||
#if defined(NDEBUG)
|
||||
#define D(...)
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#define D(...) \
|
||||
do { \
|
||||
printf(__VA_ARGS__); \
|
||||
fflush(stdout); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation of GetElfHwcapFromGetauxval
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define AT_HWCAP 16
|
||||
#define AT_HWCAP2 26
|
||||
#define AT_PLATFORM 15
|
||||
#define AT_BASE_PLATFORM 24
|
||||
|
||||
#if defined(HAVE_STRONG_GETAUXVAL)
|
||||
#include <sys/auxv.h>
|
||||
static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||
return getauxval(hwcap_type);
|
||||
}
|
||||
#elif defined(HAVE_DLFCN_H)
|
||||
// On Android we probe the system's C library for a 'getauxval' function and
|
||||
// call it if it exits, or return 0 for failure. This function is available
|
||||
// since API level 18.
|
||||
//
|
||||
// Note that getauxval() can't really be re-implemented here, because its
|
||||
// implementation does not parse /proc/self/auxv. Instead it depends on values
|
||||
// that are passed by the kernel at process-init time to the C runtime
|
||||
// initialization layer.
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
typedef unsigned long getauxval_func_t(unsigned long);
|
||||
|
||||
static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||
uint32_t ret = 0;
|
||||
void *libc_handle = NULL;
|
||||
getauxval_func_t *func = NULL;
|
||||
|
||||
dlerror(); // Cleaning error state before calling dlopen.
|
||||
libc_handle = dlopen("libc.so", RTLD_NOW);
|
||||
if (!libc_handle) {
|
||||
D("Could not dlopen() C library: %s\n", dlerror());
|
||||
return 0;
|
||||
}
|
||||
func = (getauxval_func_t *)dlsym(libc_handle, "getauxval");
|
||||
if (!func) {
|
||||
D("Could not find getauxval() in C library\n");
|
||||
} else {
|
||||
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
|
||||
ret = (uint32_t)(*func)(hwcap_type);
|
||||
}
|
||||
dlclose(libc_handle);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
#error "This platform does not provide hardware capabilities."
|
||||
#endif
|
||||
|
||||
// Implementation of GetHardwareCapabilities for OS that provide
|
||||
// GetElfHwcapFromGetauxval().
|
||||
|
||||
// Fallback when getauxval is not available, retrieves hwcaps from
|
||||
// "/proc/self/auxv".
|
||||
static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
|
||||
struct {
|
||||
uint32_t tag;
|
||||
uint32_t value;
|
||||
} entry;
|
||||
uint32_t result = 0;
|
||||
const char filepath[] = "/proc/self/auxv";
|
||||
const int fd = CpuFeatures_OpenFile(filepath);
|
||||
if (fd < 0) {
|
||||
D("Could not open %s\n", filepath);
|
||||
return 0;
|
||||
}
|
||||
for (;;) {
|
||||
const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry);
|
||||
if (ret < 0) {
|
||||
D("Error while reading %s\n", filepath);
|
||||
break;
|
||||
}
|
||||
// Detect end of list.
|
||||
if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
|
||||
break;
|
||||
}
|
||||
if (entry.tag == hwcap_type) {
|
||||
result = entry.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Retrieves hardware capabilities by first trying to call getauxval, if not
|
||||
// available falls back to reading "/proc/self/auxv".
|
||||
static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
|
||||
unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
|
||||
if (!hwcaps) {
|
||||
D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
|
||||
hwcaps = GetElfHwcapFromProcSelfAuxv(type);
|
||||
}
|
||||
return hwcaps;
|
||||
}
|
||||
|
||||
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
|
||||
HardwareCapabilities capabilities;
|
||||
capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
|
||||
capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
const char *CpuFeatures_GetPlatformPointer(void) {
|
||||
return (const char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
|
||||
}
|
||||
|
||||
const char *CpuFeatures_GetBasePlatformPointer(void) {
|
||||
return (const char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
|
||||
}
|
||||
|
||||
#endif // CPU_FEATURES_TEST
|
||||
@@ -0,0 +1,118 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
#include "cpuinfo_aarch64.h"
|
||||
#include "internal/bit_utils.h"
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#if !defined(CPU_FEATURES_ARCH_AARCH64)
|
||||
#error "Cannot compile aarch64_base on a non aarch64 platform."
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for introspection.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define INTROSPECTION_TABLE \
|
||||
LINE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \
|
||||
LINE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \
|
||||
LINE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \
|
||||
LINE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \
|
||||
LINE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \
|
||||
LINE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \
|
||||
LINE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \
|
||||
LINE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \
|
||||
LINE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \
|
||||
LINE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \
|
||||
LINE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \
|
||||
LINE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \
|
||||
LINE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \
|
||||
LINE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \
|
||||
LINE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \
|
||||
LINE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \
|
||||
LINE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \
|
||||
LINE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \
|
||||
LINE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \
|
||||
LINE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \
|
||||
LINE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \
|
||||
LINE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \
|
||||
LINE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \
|
||||
LINE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \
|
||||
LINE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \
|
||||
LINE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \
|
||||
LINE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \
|
||||
LINE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \
|
||||
LINE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \
|
||||
LINE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \
|
||||
LINE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \
|
||||
LINE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \
|
||||
LINE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \
|
||||
LINE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \
|
||||
LINE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \
|
||||
LINE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \
|
||||
LINE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \
|
||||
AARCH64_HWCAP2_SVEBITPERM) \
|
||||
LINE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \
|
||||
LINE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \
|
||||
LINE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \
|
||||
LINE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \
|
||||
LINE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \
|
||||
LINE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \
|
||||
LINE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \
|
||||
LINE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \
|
||||
LINE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \
|
||||
LINE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \
|
||||
LINE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \
|
||||
LINE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \
|
||||
LINE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI) \
|
||||
LINE(AARCH64_MTE, mte, "mte", 0, AARCH64_HWCAP2_MTE) \
|
||||
LINE(AARCH64_ECV, ecv, "ecv", 0, AARCH64_HWCAP2_ECV) \
|
||||
LINE(AARCH64_AFP, afp, "afp", 0, AARCH64_HWCAP2_AFP) \
|
||||
LINE(AARCH64_RPRES, rpres, "rpres", 0, AARCH64_HWCAP2_RPRES) \
|
||||
LINE(AARCH64_MTE3, mte3, "mte3", 0, AARCH64_HWCAP2_MTE3) \
|
||||
LINE(AARCH64_SME, sme, "sme", 0, AARCH64_HWCAP2_SME) \
|
||||
LINE(AARCH64_SME_I16I64, smei16i64, "smei16i64", 0, \
|
||||
AARCH64_HWCAP2_SME_I16I64) \
|
||||
LINE(AARCH64_SME_F64F64, smef64f64, "smef64f64", 0, \
|
||||
AARCH64_HWCAP2_SME_F64F64) \
|
||||
LINE(AARCH64_SME_I8I32, smei8i32, "smei8i32", 0, AARCH64_HWCAP2_SME_I8I32) \
|
||||
LINE(AARCH64_SME_F16F32, smef16f32, "smef16f32", 0, \
|
||||
AARCH64_HWCAP2_SME_F16F32) \
|
||||
LINE(AARCH64_SME_B16F32, smeb16f32, "smeb16f32", 0, \
|
||||
AARCH64_HWCAP2_SME_B16F32) \
|
||||
LINE(AARCH64_SME_F32F32, smef32f32, "smef32f32", 0, \
|
||||
AARCH64_HWCAP2_SME_F32F32) \
|
||||
LINE(AARCH64_SME_FA64, smefa64, "smefa64", 0, AARCH64_HWCAP2_SME_FA64) \
|
||||
LINE(AARCH64_WFXT, wfxt, "wfxt", 0, AARCH64_HWCAP2_WFXT) \
|
||||
LINE(AARCH64_EBF16, ebf16, "ebf16", 0, AARCH64_HWCAP2_EBF16) \
|
||||
LINE(AARCH64_SVE_EBF16, sveebf16, "sveebf16", 0, AARCH64_HWCAP2_SVE_EBF16) \
|
||||
LINE(AARCH64_CSSC, cssc, "cssc", 0, AARCH64_HWCAP2_CSSC) \
|
||||
LINE(AARCH64_RPRFM, rprfm, "rprfm", 0, AARCH64_HWCAP2_RPRFM) \
|
||||
LINE(AARCH64_SVE2P1, sve2p1, "sve2p1", 0, AARCH64_HWCAP2_SVE2P1) \
|
||||
LINE(AARCH64_SME2, sme2, "sme2", 0, AARCH64_HWCAP2_SME2) \
|
||||
LINE(AARCH64_SME2P1, sme2p1, "sme2p1", 0, AARCH64_HWCAP2_SME2P1) \
|
||||
LINE(AARCH64_SME_I16I32, smei16i32, "smei16i32", 0, \
|
||||
AARCH64_HWCAP2_SME_I16I32) \
|
||||
LINE(AARCH64_SME_BI32I32, smebi32i32, "smebi32i32", 0, \
|
||||
AARCH64_HWCAP2_SME_BI32I32) \
|
||||
LINE(AARCH64_SME_B16B16, smeb16b16, "smeb16b16", 0, \
|
||||
AARCH64_HWCAP2_SME_B16B16) \
|
||||
LINE(AARCH64_SME_F16F16, smef16f16, "smef16f16", 0, AARCH64_HWCAP2_SME_F16F16)
|
||||
#define INTROSPECTION_PREFIX Aarch64
|
||||
#define INTROSPECTION_ENUM_PREFIX AARCH64
|
||||
#include "define_introspection_and_hwcaps.inl"
|
||||
@@ -0,0 +1,79 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_AARCH64
|
||||
#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
|
||||
#include "impl_aarch64__base_implementation.inl"
|
||||
|
||||
static bool HandleAarch64Line(const LineResult result,
|
||||
Aarch64Info* const info) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
|
||||
kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
|
||||
value, kCpuInfoFlags[i], ' '));
|
||||
}
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
|
||||
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
|
||||
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
|
||||
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
|
||||
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(Aarch64Info* const info) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const Aarch64Info kEmptyAarch64Info;
|
||||
|
||||
Aarch64Info GetAarch64Info(void) {
|
||||
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||
// have some information if the executable is sandboxed (aka no access to
|
||||
// /proc/cpuinfo).
|
||||
Aarch64Info info = kEmptyAarch64Info;
|
||||
|
||||
FillProcCpuInfoData(&info);
|
||||
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
|
||||
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||
kSetters[i](&info.features, true);
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
#endif // CPU_FEATURES_ARCH_AARCH64
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright 2021 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_AARCH64
|
||||
#if defined(CPU_FEATURES_OS_MACOS) || defined(CPU_FEATURES_OS_IPHONE)
|
||||
|
||||
#include "impl_aarch64__base_implementation.inl"
|
||||
|
||||
#if !defined(HAVE_SYSCTLBYNAME)
|
||||
#error "Darwin needs support for sysctlbyname"
|
||||
#endif
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#if defined(CPU_FEATURES_MOCK_SYSCTL_AARCH64)
|
||||
extern bool GetDarwinSysCtlByName(const char*);
|
||||
extern int GetDarwinSysCtlByNameValue(const char* name);
|
||||
#else
|
||||
static int GetDarwinSysCtlByNameValue(const char* name) {
|
||||
int enabled;
|
||||
size_t enabled_len = sizeof(enabled);
|
||||
const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
|
||||
return failure ? 0 : enabled;
|
||||
}
|
||||
|
||||
static bool GetDarwinSysCtlByName(const char* name) {
|
||||
return GetDarwinSysCtlByNameValue(name) != 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const Aarch64Info kEmptyAarch64Info;
|
||||
|
||||
Aarch64Info GetAarch64Info(void) {
|
||||
Aarch64Info info = kEmptyAarch64Info;
|
||||
|
||||
// Handling Darwin platform through sysctlbyname.
|
||||
info.implementer = GetDarwinSysCtlByNameValue("hw.cputype");
|
||||
info.variant = GetDarwinSysCtlByNameValue("hw.cpusubtype");
|
||||
info.part = GetDarwinSysCtlByNameValue("hw.cpufamily");
|
||||
info.revision = GetDarwinSysCtlByNameValue("hw.cpusubfamily");
|
||||
|
||||
info.features.fp = GetDarwinSysCtlByName("hw.optional.floatingpoint");
|
||||
info.features.asimd = GetDarwinSysCtlByName("hw.optional.AdvSIMD");
|
||||
info.features.aes = GetDarwinSysCtlByName("hw.optional.arm.FEAT_AES");
|
||||
info.features.pmull = GetDarwinSysCtlByName("hw.optional.arm.FEAT_PMULL");
|
||||
info.features.sha1 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA1");
|
||||
info.features.sha2 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA256");
|
||||
info.features.crc32 = GetDarwinSysCtlByName("hw.optional.armv8_crc32");
|
||||
info.features.atomics = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LSE");
|
||||
info.features.fphp = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FP16");
|
||||
info.features.asimdhp = GetDarwinSysCtlByName("hw.optional.arm.AdvSIMD_HPFPCvt");
|
||||
info.features.asimdrdm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_RDM");
|
||||
info.features.jscvt = GetDarwinSysCtlByName("hw.optional.arm.FEAT_JSCVT");
|
||||
info.features.fcma = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FCMA");
|
||||
info.features.lrcpc = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LRCPC");
|
||||
info.features.dcpop = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DPB");
|
||||
info.features.sha3 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA3");
|
||||
info.features.asimddp = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DotProd");
|
||||
info.features.sha512 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SHA512");
|
||||
info.features.asimdfhm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FHM");
|
||||
info.features.dit = GetDarwinSysCtlByName("hw.optional.arm.FEAT_DIT");
|
||||
info.features.uscat = GetDarwinSysCtlByName("hw.optional.arm.FEAT_LSE2");
|
||||
info.features.flagm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FlagM");
|
||||
info.features.ssbs = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SSBS");
|
||||
info.features.sb = GetDarwinSysCtlByName("hw.optional.arm.FEAT_SB");
|
||||
info.features.flagm2 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FlagM2");
|
||||
info.features.frint = GetDarwinSysCtlByName("hw.optional.arm.FEAT_FRINTTS");
|
||||
info.features.i8mm = GetDarwinSysCtlByName("hw.optional.arm.FEAT_I8MM");
|
||||
info.features.bf16 = GetDarwinSysCtlByName("hw.optional.arm.FEAT_BF16");
|
||||
info.features.bti = GetDarwinSysCtlByName("hw.optional.arm.FEAT_BTI");
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_OS_MACOS) || defined(CPU_FEATURES_OS_IPHONE)
|
||||
#endif // CPU_FEATURES_ARCH_AARCH64
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_AARCH64
|
||||
#ifdef CPU_FEATURES_OS_WINDOWS
|
||||
|
||||
#include "cpuinfo_aarch64.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for introspection.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define INTROSPECTION_TABLE \
|
||||
LINE(AARCH64_FP, fp, , , ) \
|
||||
LINE(AARCH64_ASIMD, asimd, , , ) \
|
||||
LINE(AARCH64_EVTSTRM, evtstrm, , , ) \
|
||||
LINE(AARCH64_AES, aes, , , ) \
|
||||
LINE(AARCH64_PMULL, pmull, , , ) \
|
||||
LINE(AARCH64_SHA1, sha1, , , ) \
|
||||
LINE(AARCH64_SHA2, sha2, , , ) \
|
||||
LINE(AARCH64_CRC32, crc32, , , ) \
|
||||
LINE(AARCH64_ATOMICS, atomics, , , ) \
|
||||
LINE(AARCH64_FPHP, fphp, , , ) \
|
||||
LINE(AARCH64_ASIMDHP, asimdhp, , , ) \
|
||||
LINE(AARCH64_CPUID, cpuid, , , ) \
|
||||
LINE(AARCH64_ASIMDRDM, asimdrdm, , , ) \
|
||||
LINE(AARCH64_JSCVT, jscvt, , , ) \
|
||||
LINE(AARCH64_FCMA, fcma, , , ) \
|
||||
LINE(AARCH64_LRCPC, lrcpc, , , ) \
|
||||
LINE(AARCH64_DCPOP, dcpop, , , ) \
|
||||
LINE(AARCH64_SHA3, sha3, , , ) \
|
||||
LINE(AARCH64_SM3, sm3, , , ) \
|
||||
LINE(AARCH64_SM4, sm4, , , ) \
|
||||
LINE(AARCH64_ASIMDDP, asimddp, , , ) \
|
||||
LINE(AARCH64_SHA512, sha512, , , ) \
|
||||
LINE(AARCH64_SVE, sve, , , ) \
|
||||
LINE(AARCH64_ASIMDFHM, asimdfhm, , , ) \
|
||||
LINE(AARCH64_DIT, dit, , , ) \
|
||||
LINE(AARCH64_USCAT, uscat, , , ) \
|
||||
LINE(AARCH64_ILRCPC, ilrcpc, , , ) \
|
||||
LINE(AARCH64_FLAGM, flagm, , , ) \
|
||||
LINE(AARCH64_SSBS, ssbs, , , ) \
|
||||
LINE(AARCH64_SB, sb, , , ) \
|
||||
LINE(AARCH64_PACA, paca, , , ) \
|
||||
LINE(AARCH64_PACG, pacg, , , ) \
|
||||
LINE(AARCH64_DCPODP, dcpodp, , , ) \
|
||||
LINE(AARCH64_SVE2, sve2, , , ) \
|
||||
LINE(AARCH64_SVEAES, sveaes, , , ) \
|
||||
LINE(AARCH64_SVEPMULL, svepmull, , , ) \
|
||||
LINE(AARCH64_SVEBITPERM, svebitperm, , , ) \
|
||||
LINE(AARCH64_SVESHA3, svesha3, , , ) \
|
||||
LINE(AARCH64_SVESM4, svesm4, , , ) \
|
||||
LINE(AARCH64_FLAGM2, flagm2, , , ) \
|
||||
LINE(AARCH64_FRINT, frint, , , ) \
|
||||
LINE(AARCH64_SVEI8MM, svei8mm, , , ) \
|
||||
LINE(AARCH64_SVEF32MM, svef32mm, , , ) \
|
||||
LINE(AARCH64_SVEF64MM, svef64mm, , , ) \
|
||||
LINE(AARCH64_SVEBF16, svebf16, , , ) \
|
||||
LINE(AARCH64_I8MM, i8mm, , , ) \
|
||||
LINE(AARCH64_BF16, bf16, , , ) \
|
||||
LINE(AARCH64_DGH, dgh, , , ) \
|
||||
LINE(AARCH64_RNG, rng, , , ) \
|
||||
LINE(AARCH64_BTI, bti, , , ) \
|
||||
LINE(AARCH64_MTE, mte, , , ) \
|
||||
LINE(AARCH64_ECV, ecv, , , ) \
|
||||
LINE(AARCH64_AFP, afp, , , ) \
|
||||
LINE(AARCH64_RPRES, rpres, , , )
|
||||
#define INTROSPECTION_PREFIX Aarch64
|
||||
#define INTROSPECTION_ENUM_PREFIX AARCH64
|
||||
#include "define_introspection.inl"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "internal/windows_utils.h"
|
||||
|
||||
#ifdef CPU_FEATURES_MOCK_CPUID_AARCH64
|
||||
extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
|
||||
extern WORD GetWindowsNativeSystemInfoProcessorRevision();
|
||||
#else // CPU_FEATURES_MOCK_CPUID_AARCH64
|
||||
static bool GetWindowsIsProcessorFeaturePresent(DWORD dwProcessorFeature) {
|
||||
return IsProcessorFeaturePresent(dwProcessorFeature);
|
||||
}
|
||||
|
||||
static WORD GetWindowsNativeSystemInfoProcessorRevision() {
|
||||
SYSTEM_INFO system_info;
|
||||
GetNativeSystemInfo(&system_info);
|
||||
return system_info.wProcessorRevision;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const Aarch64Info kEmptyAarch64Info;
|
||||
|
||||
Aarch64Info GetAarch64Info(void) {
|
||||
Aarch64Info info = kEmptyAarch64Info;
|
||||
info.revision = GetWindowsNativeSystemInfoProcessorRevision();
|
||||
info.features.fp =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_ARM_VFP_32_REGISTERS_AVAILABLE);
|
||||
info.features.asimd =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE);
|
||||
info.features.crc32 = GetWindowsIsProcessorFeaturePresent(
|
||||
PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE);
|
||||
info.features.asimddp =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE);
|
||||
info.features.jscvt = GetWindowsIsProcessorFeaturePresent(
|
||||
PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE);
|
||||
info.features.lrcpc = GetWindowsIsProcessorFeaturePresent(
|
||||
PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE);
|
||||
info.features.atomics = GetWindowsIsProcessorFeaturePresent(
|
||||
PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE);
|
||||
|
||||
|
||||
bool is_crypto_available = GetWindowsIsProcessorFeaturePresent(
|
||||
PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE);
|
||||
info.features.aes = is_crypto_available;
|
||||
info.features.sha1 = is_crypto_available;
|
||||
info.features.sha2 = is_crypto_available;
|
||||
info.features.pmull = is_crypto_available;
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // CPU_FEATURES_OS_WINDOWS
|
||||
#endif // CPU_FEATURES_ARCH_AARCH64
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_ARM
|
||||
#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
|
||||
#include "cpuinfo_arm.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for introspection.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define INTROSPECTION_TABLE \
|
||||
LINE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \
|
||||
LINE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \
|
||||
LINE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \
|
||||
LINE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \
|
||||
LINE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \
|
||||
LINE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \
|
||||
LINE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \
|
||||
LINE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \
|
||||
LINE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \
|
||||
LINE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \
|
||||
LINE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \
|
||||
LINE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \
|
||||
LINE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \
|
||||
LINE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \
|
||||
LINE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \
|
||||
LINE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \
|
||||
LINE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \
|
||||
LINE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \
|
||||
LINE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \
|
||||
LINE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \
|
||||
LINE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \
|
||||
LINE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \
|
||||
LINE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \
|
||||
LINE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \
|
||||
LINE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \
|
||||
LINE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \
|
||||
LINE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32)
|
||||
#define INTROSPECTION_PREFIX Arm
|
||||
#define INTROSPECTION_ENUM_PREFIX ARM
|
||||
#include "define_introspection_and_hwcaps.inl"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "internal/bit_utils.h"
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
typedef struct {
|
||||
bool processor_reports_armv6;
|
||||
bool hardware_reports_goldfish;
|
||||
} ProcCpuInfoData;
|
||||
|
||||
static int IndexOfNonDigit(StringView str) {
|
||||
size_t index = 0;
|
||||
while (str.size && isdigit(CpuFeatures_StringView_Front(str))) {
|
||||
str = CpuFeatures_StringView_PopFront(str, 1);
|
||||
++index;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
static bool HandleArmLine(const LineResult result, ArmInfo* const info,
|
||||
ProcCpuInfoData* const proc_info) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||
for (size_t i = 0; i < ARM_LAST_; ++i) {
|
||||
kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
|
||||
value, kCpuInfoFlags[i], ' '));
|
||||
}
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
|
||||
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
|
||||
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
|
||||
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
|
||||
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) {
|
||||
// CPU architecture is a number that may be followed by letters. e.g.
|
||||
// "6TEJ", "7".
|
||||
const StringView digits =
|
||||
CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
|
||||
info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("Processor")) ||
|
||||
CpuFeatures_StringView_IsEquals(key, str("model name"))) {
|
||||
// Android reports this in a non-Linux standard "Processor" but sometimes
|
||||
// also in "model name", Linux reports it only in "model name"
|
||||
// see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases
|
||||
proc_info->processor_reports_armv6 =
|
||||
CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0;
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) {
|
||||
proc_info->hardware_reports_goldfish =
|
||||
CpuFeatures_StringView_IsEquals(value, str("Goldfish"));
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
uint32_t GetArmCpuId(const ArmInfo* const info) {
|
||||
return (ExtractBitRange(info->implementer, 7, 0) << 24) |
|
||||
(ExtractBitRange(info->variant, 3, 0) << 20) |
|
||||
(ExtractBitRange(info->part, 11, 0) << 4) |
|
||||
(ExtractBitRange(info->revision, 3, 0) << 0);
|
||||
}
|
||||
|
||||
static void FixErrors(ArmInfo* const info,
|
||||
ProcCpuInfoData* const proc_cpu_info_data) {
|
||||
// Fixing Samsung kernel reporting invalid cpu architecture.
|
||||
// http://code.google.com/p/android/issues/detail?id=10812
|
||||
if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) {
|
||||
info->architecture = 6;
|
||||
}
|
||||
|
||||
// Handle kernel configuration bugs that prevent the correct reporting of CPU
|
||||
// features.
|
||||
switch (GetArmCpuId(info)) {
|
||||
case 0x4100C080:
|
||||
// Special case: The emulator-specific Android 4.2 kernel fails to report
|
||||
// support for the 32-bit ARM IDIV instruction. Technically, this is a
|
||||
// feature of the virtual CPU implemented by the emulator. Note that it
|
||||
// could also support Thumb IDIV in the future, and this will have to be
|
||||
// slightly updated.
|
||||
if (info->architecture >= 7 &&
|
||||
proc_cpu_info_data->hardware_reports_goldfish) {
|
||||
info->features.idiva = true;
|
||||
}
|
||||
break;
|
||||
case 0x511004D0:
|
||||
// https://crbug.com/341598.
|
||||
info->features.neon = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Some Qualcomm Krait kernels forget to report IDIV support.
|
||||
// https://github.com/torvalds/linux/commit/120ecfafabec382c4feb79ff159ef42a39b6d33b
|
||||
if (info->implementer == 0x51 && info->architecture == 7 &&
|
||||
(info->part == 0x4d || info->part == 0x6f)) {
|
||||
info->features.idiva = true;
|
||||
info->features.idivt = true;
|
||||
}
|
||||
|
||||
// Propagate cpu features.
|
||||
if (info->features.vfpv4) info->features.vfpv3 = true;
|
||||
if (info->features.neon) info->features.vfpv3 = true;
|
||||
if (info->features.vfpv3) info->features.vfp = true;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(ArmInfo* const info,
|
||||
ProcCpuInfoData* proc_cpu_info_data) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleArmLine(StackLineReader_NextLine(&reader), info,
|
||||
proc_cpu_info_data)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const ArmInfo kEmptyArmInfo;
|
||||
|
||||
static const ProcCpuInfoData kEmptyProcCpuInfoData;
|
||||
|
||||
ArmInfo GetArmInfo(void) {
|
||||
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||
// have some information if the executable is sandboxed (aka no access to
|
||||
// /proc/cpuinfo).
|
||||
ArmInfo info = kEmptyArmInfo;
|
||||
ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData;
|
||||
|
||||
FillProcCpuInfoData(&info, &proc_cpu_info_data);
|
||||
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||
for (size_t i = 0; i < ARM_LAST_; ++i) {
|
||||
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||
kSetters[i](&info.features, true);
|
||||
}
|
||||
}
|
||||
|
||||
FixErrors(&info, &proc_cpu_info_data);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
#endif // CPU_FEATURES_ARCH_ARM
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_LOONGARCH
|
||||
#if defined(CPU_FEATURES_OS_LINUX)
|
||||
|
||||
#include "cpuinfo_loongarch.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for introspection.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define INTROSPECTION_TABLE \
|
||||
LINE(LOONGARCH_CPUCFG, CPUCFG, "cfg", HWCAP_LOONGARCH_CPUCFG, 0) \
|
||||
LINE(LOONGARCH_LAM, LAM, "lam", HWCAP_LOONGARCH_LAM, 0) \
|
||||
LINE(LOONGARCH_UAL, UAL, "ual", HWCAP_LOONGARCH_UAL, 0) \
|
||||
LINE(LOONGARCH_FPU, FPU, "fpu", HWCAP_LOONGARCH_FPU, 0) \
|
||||
LINE(LOONGARCH_LSX, LSX, "lsx", HWCAP_LOONGARCH_LSX, 0) \
|
||||
LINE(LOONGARCH_LASX, LASX, "lasx", HWCAP_LOONGARCH_LASX, 0) \
|
||||
LINE(LOONGARCH_CRC32, CRC32, "crc32", HWCAP_LOONGARCH_CRC32, 0) \
|
||||
LINE(LOONGARCH_COMPLEX, COMPLEX, "complex", HWCAP_LOONGARCH_COMPLEX, 0) \
|
||||
LINE(LOONGARCH_CRYPTO, CRYPTO, "crypto", HWCAP_LOONGARCH_CRYPTO, 0) \
|
||||
LINE(LOONGARCH_LVZ, LVZ, "lvz", HWCAP_LOONGARCH_LVZ, 0) \
|
||||
LINE(LOONGARCH_LBT_X86, LBT_X86, "lbt_x86", HWCAP_LOONGARCH_LBT_X86, 0) \
|
||||
LINE(LOONGARCH_LBT_ARM, LBT_ARM, "lbt_arm", HWCAP_LOONGARCH_LBT_ARM, 0) \
|
||||
LINE(LOONGARCH_LBT_MIPS, LBT_MIPS, "lbt_mips", HWCAP_LOONGARCH_LBT_MIPS, 0) \
|
||||
LINE(LOONGARCH_PTW, PTW, "ptw", HWCAP_LOONGARCH_PTW, 0)
|
||||
#define INTROSPECTION_PREFIX LoongArch
|
||||
#define INTROSPECTION_ENUM_PREFIX LOONGARCH
|
||||
#include "define_introspection_and_hwcaps.inl"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
|
||||
static const LoongArchInfo kEmptyLoongArchInfo;
|
||||
|
||||
static bool HandleLoongArchLine(const LineResult result, LoongArchInfo* const info) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||
for (size_t i = 0; i < LOONGARCH_LAST_; ++i) {
|
||||
kSetters[i](&info->features, CpuFeatures_StringView_HasWord(
|
||||
value, kCpuInfoFlags[i], ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(LoongArchInfo* const info) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleLoongArchLine(StackLineReader_NextLine(&reader), info)) break;
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
LoongArchInfo GetLoongArchInfo(void) {
|
||||
LoongArchInfo info = kEmptyLoongArchInfo;
|
||||
FillProcCpuInfoData(&info);
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_OS_LINUX)
|
||||
#endif // CPU_FEATURES_ARCH_LOONGARCH
|
||||
@@ -0,0 +1,93 @@
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_MIPS
|
||||
#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
|
||||
#include "cpuinfo_mips.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for introspection.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define INTROSPECTION_TABLE \
|
||||
LINE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
|
||||
LINE(MIPS_EVA, eva, "eva", 0, 0) \
|
||||
LINE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0) \
|
||||
LINE(MIPS_MIPS16, mips16, "mips16", MIPS_HWCAP_MIPS16, 0) \
|
||||
LINE(MIPS_MDMX, mdmx, "mdmx", MIPS_HWCAP_MDMX, 0) \
|
||||
LINE(MIPS_MIPS3D, mips3d, "mips3d", MIPS_HWCAP_MIPS3D, 0) \
|
||||
LINE(MIPS_SMART, smart, "smartmips", MIPS_HWCAP_SMARTMIPS, 0) \
|
||||
LINE(MIPS_DSP, dsp, "dsp", MIPS_HWCAP_DSP, 0)
|
||||
#define INTROSPECTION_PREFIX Mips
|
||||
#define INTROSPECTION_ENUM_PREFIX MIPS
|
||||
#include "define_introspection_and_hwcaps.inl"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/hwcaps.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
static bool HandleMipsLine(const LineResult result,
|
||||
MipsFeatures* const features) {
|
||||
StringView key, value;
|
||||
// See tests for an example.
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) {
|
||||
for (size_t i = 0; i < MIPS_LAST_; ++i) {
|
||||
kSetters[i](features, CpuFeatures_StringView_HasWord(
|
||||
value, kCpuInfoFlags[i], ' '));
|
||||
}
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(MipsFeatures* const features) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const MipsInfo kEmptyMipsInfo;
|
||||
|
||||
MipsInfo GetMipsInfo(void) {
|
||||
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||
// have some information if the executable is sandboxed (aka no access to
|
||||
// /proc/cpuinfo).
|
||||
MipsInfo info = kEmptyMipsInfo;
|
||||
|
||||
FillProcCpuInfoData(&info.features);
|
||||
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||
for (size_t i = 0; i < MIPS_LAST_; ++i) {
|
||||
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||
kSetters[i](&info.features, true);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
#endif // CPU_FEATURES_ARCH_MIPS
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
// Copyright 2018 IBM.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_PPC
|
||||
#ifdef CPU_FEATURES_OS_LINUX
|
||||
|
||||
#include "cpuinfo_ppc.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for introspection.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define INTROSPECTION_TABLE \
|
||||
LINE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \
|
||||
LINE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \
|
||||
LINE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \
|
||||
LINE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \
|
||||
LINE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \
|
||||
LINE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \
|
||||
LINE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \
|
||||
LINE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", PPC_FEATURE_UNIFIED_CACHE, \
|
||||
0) \
|
||||
LINE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \
|
||||
LINE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", PPC_FEATURE_HAS_EFP_SINGLE, \
|
||||
0) \
|
||||
LINE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", PPC_FEATURE_HAS_EFP_DOUBLE, \
|
||||
0) \
|
||||
LINE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \
|
||||
LINE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \
|
||||
LINE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \
|
||||
LINE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \
|
||||
LINE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \
|
||||
LINE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \
|
||||
LINE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \
|
||||
LINE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, 0) \
|
||||
LINE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \
|
||||
LINE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \
|
||||
LINE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \
|
||||
LINE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \
|
||||
LINE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \
|
||||
LINE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \
|
||||
LINE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \
|
||||
PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \
|
||||
LINE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \
|
||||
LINE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \
|
||||
LINE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \
|
||||
LINE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \
|
||||
LINE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \
|
||||
LINE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \
|
||||
LINE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \
|
||||
LINE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \
|
||||
LINE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \
|
||||
LINE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \
|
||||
LINE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \
|
||||
LINE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \
|
||||
LINE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \
|
||||
LINE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \
|
||||
LINE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \
|
||||
PPC_FEATURE2_HTM_NO_SUSPEND)
|
||||
#undef PPC // Remove conflict with compiler generated preprocessor
|
||||
#define INTROSPECTION_PREFIX PPC
|
||||
#define INTROSPECTION_ENUM_PREFIX PPC
|
||||
#include "define_introspection_and_hwcaps.inl"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "internal/bit_utils.h"
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/hwcaps.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
static bool HandlePPCLine(const LineResult result,
|
||||
PPCPlatformStrings* const strings) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_HasWord(key, "platform", ' ')) {
|
||||
CpuFeatures_StringView_CopyString(value, strings->platform,
|
||||
sizeof(strings->platform));
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("model"))) {
|
||||
CpuFeatures_StringView_CopyString(value, strings->model,
|
||||
sizeof(strings->platform));
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) {
|
||||
CpuFeatures_StringView_CopyString(value, strings->machine,
|
||||
sizeof(strings->platform));
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) {
|
||||
CpuFeatures_StringView_CopyString(value, strings->cpu,
|
||||
sizeof(strings->platform));
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(PPCPlatformStrings* const strings) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const PPCInfo kEmptyPPCInfo;
|
||||
|
||||
PPCInfo GetPPCInfo(void) {
|
||||
/*
|
||||
* On Power feature flags aren't currently in cpuinfo so we only look at
|
||||
* the auxilary vector.
|
||||
*/
|
||||
PPCInfo info = kEmptyPPCInfo;
|
||||
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||
for (size_t i = 0; i < PPC_LAST_; ++i) {
|
||||
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||
kSetters[i](&info.features, true);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
static const PPCPlatformStrings kEmptyPPCPlatformStrings;
|
||||
|
||||
PPCPlatformStrings GetPPCPlatformStrings(void) {
|
||||
PPCPlatformStrings strings = kEmptyPPCPlatformStrings;
|
||||
const char* platform = CpuFeatures_GetPlatformPointer();
|
||||
const char* base_platform = CpuFeatures_GetBasePlatformPointer();
|
||||
|
||||
FillProcCpuInfoData(&strings);
|
||||
|
||||
if (platform != NULL)
|
||||
CpuFeatures_StringView_CopyString(str(platform), strings.type.platform,
|
||||
sizeof(strings.type.platform));
|
||||
if (base_platform != NULL)
|
||||
CpuFeatures_StringView_CopyString(str(base_platform),
|
||||
strings.type.base_platform,
|
||||
sizeof(strings.type.base_platform));
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
#endif // CPU_FEATURES_OS_LINUX
|
||||
#endif // CPU_FEATURES_ARCH_PPC
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_RISCV
|
||||
#if defined(CPU_FEATURES_OS_LINUX)
|
||||
|
||||
#include "cpuinfo_riscv.h"
|
||||
|
||||
// According to
|
||||
// https://elixir.bootlin.com/linux/latest/source/Documentation/devicetree/bindings/riscv/cpus.yaml
|
||||
// isa string should match the following regex
|
||||
// ^rv(?:64|32)imaf?d?q?c?b?v?k?h?(?:_[hsxz](?:[a-z])+)*$
|
||||
//
|
||||
// This means we can test for features in this exact order except for Z
|
||||
// extensions.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for introspection.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define INTROSPECTION_TABLE \
|
||||
LINE(RISCV_RV32I, RV32I, "rv32i", RISCV_HWCAP_32, 0) \
|
||||
LINE(RISCV_RV64I, RV64I, "rv64i", RISCV_HWCAP_64, 0) \
|
||||
LINE(RISCV_M, M, "m", RISCV_HWCAP_M, 0) \
|
||||
LINE(RISCV_A, A, "a", RISCV_HWCAP_A, 0) \
|
||||
LINE(RISCV_F, F, "f", RISCV_HWCAP_F, 0) \
|
||||
LINE(RISCV_D, D, "d", RISCV_HWCAP_D, 0) \
|
||||
LINE(RISCV_Q, Q, "q", RISCV_HWCAP_Q, 0) \
|
||||
LINE(RISCV_C, C, "c", RISCV_HWCAP_C, 0) \
|
||||
LINE(RISCV_V, V, "v", RISCV_HWCAP_V, 0) \
|
||||
LINE(RISCV_Zicsr, Zicsr, "_zicsr", 0, 0) \
|
||||
LINE(RISCV_Zifencei, Zifencei, "_zifencei", 0, 0)
|
||||
#define INTROSPECTION_PREFIX Riscv
|
||||
#define INTROSPECTION_ENUM_PREFIX RISCV
|
||||
#include "define_introspection_and_hwcaps.inl"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
|
||||
static const RiscvInfo kEmptyRiscvInfo;
|
||||
|
||||
static void HandleRiscVIsaLine(StringView line, RiscvFeatures* const features) {
|
||||
for (size_t i = 0; i < RISCV_LAST_; ++i) {
|
||||
StringView flag = str(kCpuInfoFlags[i]);
|
||||
int index_of_flag = CpuFeatures_StringView_IndexOf(line, flag);
|
||||
bool is_set = index_of_flag != -1;
|
||||
kSetters[i](features, is_set);
|
||||
if (is_set)
|
||||
line = CpuFeatures_StringView_PopFront(line, index_of_flag + flag.size);
|
||||
}
|
||||
}
|
||||
|
||||
static bool HandleRiscVLine(const LineResult result, RiscvInfo* const info) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("isa"))) {
|
||||
HandleRiscVIsaLine(value, &info->features);
|
||||
} else if (CpuFeatures_StringView_IsEquals(key, str("uarch"))) {
|
||||
int index = CpuFeatures_StringView_IndexOfChar(value, ',');
|
||||
if (index == -1) return true;
|
||||
StringView vendor = CpuFeatures_StringView_KeepFront(value, index);
|
||||
StringView uarch = CpuFeatures_StringView_PopFront(value, index + 1);
|
||||
CpuFeatures_StringView_CopyString(vendor, info->vendor,
|
||||
sizeof(info->vendor));
|
||||
CpuFeatures_StringView_CopyString(uarch, info->uarch,
|
||||
sizeof(info->uarch));
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(RiscvInfo* const info) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleRiscVLine(StackLineReader_NextLine(&reader), info)) break;
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
RiscvInfo GetRiscvInfo(void) {
|
||||
RiscvInfo info = kEmptyRiscvInfo;
|
||||
FillProcCpuInfoData(&info);
|
||||
return info;
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
#endif // CPU_FEATURES_ARCH_RISCV
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
// Copyright 2022 IBM.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_S390X
|
||||
#ifdef CPU_FEATURES_OS_LINUX
|
||||
|
||||
#include "cpuinfo_s390x.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Definitions for introspection.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#define INTROSPECTION_TABLE \
|
||||
LINE(S390_ESAN3, esan3, "esan3", HWCAP_S390_ESAN3, 0) \
|
||||
LINE(S390_ZARCH, zarch, "zarch", HWCAP_S390_ZARCH, 0) \
|
||||
LINE(S390_STFLE, stfle, "stfle", HWCAP_S390_STFLE, 0) \
|
||||
LINE(S390_MSA, msa, "msa", HWCAP_S390_MSA, 0) \
|
||||
LINE(S390_LDISP, ldisp, "ldisp", HWCAP_S390_LDISP, 0) \
|
||||
LINE(S390_EIMM, eimm, "eimm", HWCAP_S390_EIMM, 0) \
|
||||
LINE(S390_DFP, dfp, "dfp", HWCAP_S390_DFP, 0) \
|
||||
LINE(S390_EDAT, edat, "edat", HWCAP_S390_HPAGE, 0) \
|
||||
LINE(S390_ETF3EH, etf3eh, "etf3eh", HWCAP_S390_ETF3EH, 0) \
|
||||
LINE(S390_HIGHGPRS, highgprs, "highgprs", HWCAP_S390_HIGH_GPRS, 0) \
|
||||
LINE(S390_TE, te, "te", HWCAP_S390_TE, 0) \
|
||||
LINE(S390_VX, vx, "vx", HWCAP_S390_VXRS, 0) \
|
||||
LINE(S390_VXD, vxd, "vxd", HWCAP_S390_VXRS_BCD, 0) \
|
||||
LINE(S390_VXE, vxe, "vxe", HWCAP_S390_VXRS_EXT, 0) \
|
||||
LINE(S390_GS, gs, "gs", HWCAP_S390_GS, 0) \
|
||||
LINE(S390_VXE2, vxe2, "vxe2", HWCAP_S390_VXRS_EXT2, 0) \
|
||||
LINE(S390_VXP, vxp, "vxp", HWCAP_S390_VXRS_PDE, 0) \
|
||||
LINE(S390_SORT, sort, "sort", HWCAP_S390_SORT, 0) \
|
||||
LINE(S390_DFLT, dflt, "dflt", HWCAP_S390_DFLT, 0) \
|
||||
LINE(S390_VXP2, vxp2, "vxp2", HWCAP_S390_VXRS_PDE2, 0) \
|
||||
LINE(S390_NNPA, nnpa, "nnpa", HWCAP_S390_NNPA, 0) \
|
||||
LINE(S390_PCIMIO, pcimio, "pcimio", HWCAP_S390_PCI_MIO, 0) \
|
||||
LINE(S390_SIE, sie, "sie", HWCAP_S390_SIE, 0)
|
||||
#define INTROSPECTION_PREFIX S390X
|
||||
#define INTROSPECTION_ENUM_PREFIX S390X
|
||||
#include "define_introspection_and_hwcaps.inl"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Implementation.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "internal/bit_utils.h"
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/hwcaps.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
static bool HandleS390XLine(const LineResult result,
|
||||
S390XPlatformStrings* const strings) {
|
||||
StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||
if (CpuFeatures_StringView_IsEquals(key, str("# processors"))) {
|
||||
strings->num_processors = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||
}
|
||||
}
|
||||
return !result.eof;
|
||||
}
|
||||
|
||||
static void FillProcCpuInfoData(S390XPlatformStrings* const strings) {
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (;;) {
|
||||
if (!HandleS390XLine(StackLineReader_NextLine(&reader), strings)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static const S390XInfo kEmptyS390XInfo;
|
||||
|
||||
S390XInfo GetS390XInfo(void) {
|
||||
S390XInfo info = kEmptyS390XInfo;
|
||||
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||
for (size_t i = 0; i < S390X_LAST_; ++i) {
|
||||
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||
kSetters[i](&info.features, true);
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
static const S390XPlatformStrings kEmptyS390XPlatformStrings;
|
||||
|
||||
S390XPlatformStrings GetS390XPlatformStrings(void) {
|
||||
S390XPlatformStrings strings = kEmptyS390XPlatformStrings;
|
||||
const char* platform = CpuFeatures_GetPlatformPointer();
|
||||
|
||||
FillProcCpuInfoData(&strings);
|
||||
|
||||
if (platform != NULL)
|
||||
CpuFeatures_StringView_CopyString(str(platform), strings.type.platform,
|
||||
sizeof(strings.type.platform));
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
#endif // CPU_FEATURES_OS_LINUX
|
||||
#endif // CPU_FEATURES_ARCH_S390X
|
||||
File diff suppressed because it is too large
Load Diff
+68
@@ -0,0 +1,68 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_X86
|
||||
#ifdef CPU_FEATURES_OS_FREEBSD
|
||||
|
||||
#include "impl_x86__base_implementation.inl"
|
||||
|
||||
static void OverrideOsPreserves(OsPreserves* os_preserves) {
|
||||
(void)os_preserves;
|
||||
// No override
|
||||
}
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
|
||||
static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
|
||||
(void)info;
|
||||
// Handling FreeBSD platform through parsing /var/run/dmesg.boot.
|
||||
const int fd = CpuFeatures_OpenFile("/var/run/dmesg.boot");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (bool stop = false; !stop;) {
|
||||
const LineResult result = StackLineReader_NextLine(&reader);
|
||||
if (result.eof) stop = true;
|
||||
const StringView line = result.line;
|
||||
if (!CpuFeatures_StringView_StartsWith(line, str(" Features"))) continue;
|
||||
// Lines of interests are of the following form:
|
||||
// " Features=0x1783fbff<PSE36,MMX,FXSR,SSE,SSE2,HTT>"
|
||||
// We first extract the comma separated values between angle brackets.
|
||||
StringView csv = result.line;
|
||||
int index = CpuFeatures_StringView_IndexOfChar(csv, '<');
|
||||
if (index >= 0) csv = CpuFeatures_StringView_PopFront(csv, index + 1);
|
||||
if (csv.size > 0 && CpuFeatures_StringView_Back(csv) == '>')
|
||||
csv = CpuFeatures_StringView_PopBack(csv, 1);
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE", ',')) features->sse = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE2", ','))
|
||||
features->sse2 = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE3", ','))
|
||||
features->sse3 = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSSE3", ','))
|
||||
features->ssse3 = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE4.1", ','))
|
||||
features->sse4_1 = true;
|
||||
if (CpuFeatures_StringView_HasWord(csv, "SSE4.2", ','))
|
||||
features->sse4_2 = true;
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CPU_FEATURES_OS_FREEBSD
|
||||
#endif // CPU_FEATURES_ARCH_X86
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_X86
|
||||
#if defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
|
||||
#include "impl_x86__base_implementation.inl"
|
||||
|
||||
static void OverrideOsPreserves(OsPreserves* os_preserves) {
|
||||
(void)os_preserves;
|
||||
// No override
|
||||
}
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
#include "internal/stack_line_reader.h"
|
||||
#include "internal/string_view.h"
|
||||
static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
|
||||
(void)info;
|
||||
// Handling Linux platform through /proc/cpuinfo.
|
||||
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||
if (fd >= 0) {
|
||||
StackLineReader reader;
|
||||
StackLineReader_Initialize(&reader, fd);
|
||||
for (bool stop = false; !stop;) {
|
||||
const LineResult result = StackLineReader_NextLine(&reader);
|
||||
if (result.eof) stop = true;
|
||||
const StringView line = result.line;
|
||||
StringView key, value;
|
||||
if (!CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value))
|
||||
continue;
|
||||
if (!CpuFeatures_StringView_IsEquals(key, str("flags"))) continue;
|
||||
features->sse = CpuFeatures_StringView_HasWord(value, "sse", ' ');
|
||||
features->sse2 = CpuFeatures_StringView_HasWord(value, "sse2", ' ');
|
||||
features->sse3 = CpuFeatures_StringView_HasWord(value, "pni", ' ');
|
||||
features->ssse3 = CpuFeatures_StringView_HasWord(value, "ssse3", ' ');
|
||||
features->sse4_1 = CpuFeatures_StringView_HasWord(value, "sse4_1", ' ');
|
||||
features->sse4_2 = CpuFeatures_StringView_HasWord(value, "sse4_2", ' ');
|
||||
break;
|
||||
}
|
||||
CpuFeatures_CloseFile(fd);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // defined(CPU_FEATURES_OS_LINUX) || defined(CPU_FEATURES_OS_ANDROID)
|
||||
#endif // CPU_FEATURES_ARCH_X86
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_X86
|
||||
#ifdef CPU_FEATURES_OS_MACOS
|
||||
|
||||
#include "impl_x86__base_implementation.inl"
|
||||
|
||||
#if !defined(HAVE_SYSCTLBYNAME)
|
||||
#error "Darwin needs support for sysctlbyname"
|
||||
#endif
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#if defined(CPU_FEATURES_MOCK_CPUID_X86)
|
||||
extern bool GetDarwinSysCtlByName(const char*);
|
||||
#else // CPU_FEATURES_MOCK_CPUID_X86
|
||||
static bool GetDarwinSysCtlByName(const char* name) {
|
||||
int enabled;
|
||||
size_t enabled_len = sizeof(enabled);
|
||||
const int failure = sysctlbyname(name, &enabled, &enabled_len, NULL, 0);
|
||||
return failure ? false : enabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void OverrideOsPreserves(OsPreserves* os_preserves) {
|
||||
// On Darwin AVX512 support is On-demand.
|
||||
// We have to query the OS instead of querying the Zmm save/restore state.
|
||||
// https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/osfmk/i386/fpu.c#L173-L199
|
||||
os_preserves->avx512_registers = GetDarwinSysCtlByName("hw.optional.avx512f");
|
||||
}
|
||||
|
||||
static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
|
||||
(void)info;
|
||||
// Handling Darwin platform through sysctlbyname.
|
||||
features->sse = GetDarwinSysCtlByName("hw.optional.sse");
|
||||
features->sse2 = GetDarwinSysCtlByName("hw.optional.sse2");
|
||||
features->sse3 = GetDarwinSysCtlByName("hw.optional.sse3");
|
||||
features->ssse3 = GetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||
features->sse4_1 = GetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||
features->sse4_2 = GetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||
}
|
||||
|
||||
#endif // CPU_FEATURES_OS_MACOS
|
||||
#endif // CPU_FEATURES_ARCH_X86
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#ifdef CPU_FEATURES_ARCH_X86
|
||||
#ifdef CPU_FEATURES_OS_WINDOWS
|
||||
|
||||
#include "impl_x86__base_implementation.inl"
|
||||
|
||||
static void OverrideOsPreserves(OsPreserves* os_preserves) {
|
||||
(void)os_preserves;
|
||||
// No override
|
||||
}
|
||||
|
||||
#include "internal/windows_utils.h"
|
||||
|
||||
#if defined(CPU_FEATURES_MOCK_CPUID_X86)
|
||||
extern bool GetWindowsIsProcessorFeaturePresent(DWORD);
|
||||
#else // CPU_FEATURES_MOCK_CPUID_X86
|
||||
static bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
|
||||
return IsProcessorFeaturePresent(ProcessorFeature);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void DetectFeaturesFromOs(X86Info* info, X86Features* features) {
|
||||
// Handling Windows platform through IsProcessorFeaturePresent.
|
||||
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent
|
||||
features->sse =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||
features->sse2 =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||
features->sse3 =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||
features->ssse3 =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_SSSE3_INSTRUCTIONS_AVAILABLE);
|
||||
features->sse4_1 =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_SSE4_1_INSTRUCTIONS_AVAILABLE);
|
||||
features->sse4_2 =
|
||||
GetWindowsIsProcessorFeaturePresent(PF_SSE4_2_INSTRUCTIONS_AVAILABLE);
|
||||
|
||||
// do not bother checking PF_AVX*
|
||||
// cause AVX enabled processor will have XCR0 be exposed and this function will be skipped at all
|
||||
}
|
||||
|
||||
#endif // CPU_FEATURES_OS_WINDOWS
|
||||
#endif // CPU_FEATURES_ARCH_X86
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/stack_line_reader.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "internal/filesystem.h"
|
||||
|
||||
void StackLineReader_Initialize(StackLineReader* reader, int fd) {
|
||||
reader->view.ptr = reader->buffer;
|
||||
reader->view.size = 0;
|
||||
reader->skip_mode = false;
|
||||
reader->fd = fd;
|
||||
}
|
||||
|
||||
// Replaces the content of buffer with bytes from the file.
|
||||
static int LoadFullBuffer(StackLineReader* reader) {
|
||||
const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
|
||||
STACK_LINE_READER_BUFFER_SIZE);
|
||||
assert(read >= 0);
|
||||
reader->view.ptr = reader->buffer;
|
||||
reader->view.size = read;
|
||||
return read;
|
||||
}
|
||||
|
||||
// Appends with bytes from the file to buffer, filling the remaining space.
|
||||
static int LoadMore(StackLineReader* reader) {
|
||||
char* const ptr = reader->buffer + reader->view.size;
|
||||
const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
|
||||
const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
|
||||
assert(read >= 0);
|
||||
assert(read <= (int)size_to_read);
|
||||
reader->view.size += read;
|
||||
return read;
|
||||
}
|
||||
|
||||
static int IndexOfEol(StackLineReader* reader) {
|
||||
return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
|
||||
}
|
||||
|
||||
// Relocate buffer's pending bytes at the beginning of the array and fills the
|
||||
// remaining space with bytes from the file.
|
||||
static int BringToFrontAndLoadMore(StackLineReader* reader) {
|
||||
if (reader->view.size && reader->view.ptr != reader->buffer) {
|
||||
memmove(reader->buffer, reader->view.ptr, reader->view.size);
|
||||
}
|
||||
reader->view.ptr = reader->buffer;
|
||||
return LoadMore(reader);
|
||||
}
|
||||
|
||||
// Loads chunks of buffer size from disks until it contains a newline character
|
||||
// or end of file.
|
||||
static void SkipToNextLine(StackLineReader* reader) {
|
||||
for (;;) {
|
||||
const int read = LoadFullBuffer(reader);
|
||||
if (read == 0) {
|
||||
break;
|
||||
} else {
|
||||
const int eol_index = IndexOfEol(reader);
|
||||
if (eol_index >= 0) {
|
||||
reader->view =
|
||||
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
|
||||
LineResult result;
|
||||
result.eof = eof;
|
||||
result.full_line = full_line;
|
||||
result.line = view;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper methods to provide clearer semantic in StackLineReader_NextLine.
|
||||
static LineResult CreateEOFLineResult(StringView view) {
|
||||
return CreateLineResult(true, true, view);
|
||||
}
|
||||
|
||||
static LineResult CreateTruncatedLineResult(StringView view) {
|
||||
return CreateLineResult(false, false, view);
|
||||
}
|
||||
|
||||
static LineResult CreateValidLineResult(StringView view) {
|
||||
return CreateLineResult(false, true, view);
|
||||
}
|
||||
|
||||
LineResult StackLineReader_NextLine(StackLineReader* reader) {
|
||||
if (reader->skip_mode) {
|
||||
SkipToNextLine(reader);
|
||||
reader->skip_mode = false;
|
||||
}
|
||||
{
|
||||
const bool can_load_more =
|
||||
reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
|
||||
int eol_index = IndexOfEol(reader);
|
||||
if (eol_index < 0 && can_load_more) {
|
||||
const int read = BringToFrontAndLoadMore(reader);
|
||||
if (read == 0) {
|
||||
return CreateEOFLineResult(reader->view);
|
||||
}
|
||||
eol_index = IndexOfEol(reader);
|
||||
}
|
||||
if (eol_index < 0) {
|
||||
reader->skip_mode = true;
|
||||
return CreateTruncatedLineResult(reader->view);
|
||||
}
|
||||
{
|
||||
StringView line =
|
||||
CpuFeatures_StringView_KeepFront(reader->view, eol_index);
|
||||
reader->view =
|
||||
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
|
||||
return CreateValidLineResult(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
+192
@@ -0,0 +1,192 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "internal/string_view.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "copy.inl"
|
||||
#include "equals.inl"
|
||||
|
||||
static const char* CpuFeatures_memchr(const char* const ptr, const size_t size,
|
||||
const char c) {
|
||||
for (size_t i = 0; ptr && ptr[i] != '\0' && i < size; ++i)
|
||||
if (ptr[i] == c) return ptr + i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) {
|
||||
if (view.ptr && view.size) {
|
||||
const char* const found = CpuFeatures_memchr(view.ptr, view.size, c);
|
||||
if (found) {
|
||||
return (int)(found - view.ptr);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CpuFeatures_StringView_IndexOf(const StringView view,
|
||||
const StringView sub_view) {
|
||||
if (sub_view.size) {
|
||||
StringView remainder = view;
|
||||
while (remainder.size >= sub_view.size) {
|
||||
const int found_index =
|
||||
CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]);
|
||||
if (found_index < 0) break;
|
||||
remainder = CpuFeatures_StringView_PopFront(remainder, found_index);
|
||||
if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) {
|
||||
return (int)(remainder.ptr - view.ptr);
|
||||
}
|
||||
remainder = CpuFeatures_StringView_PopFront(remainder, 1);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) {
|
||||
if (a.size == b.size) {
|
||||
return a.ptr == b.ptr || equals(a.ptr, b.ptr, b.size);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) {
|
||||
return a.ptr && b.ptr && b.size && a.size >= b.size
|
||||
? equals(a.ptr, b.ptr, b.size)
|
||||
: false;
|
||||
}
|
||||
|
||||
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
|
||||
size_t count) {
|
||||
if (count > str_view.size) {
|
||||
return kEmptyStringView;
|
||||
}
|
||||
return view(str_view.ptr + count, str_view.size - count);
|
||||
}
|
||||
|
||||
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
|
||||
size_t count) {
|
||||
if (count > str_view.size) {
|
||||
return kEmptyStringView;
|
||||
}
|
||||
return view(str_view.ptr, str_view.size - count);
|
||||
}
|
||||
|
||||
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
|
||||
size_t count) {
|
||||
return count <= str_view.size ? view(str_view.ptr, count) : str_view;
|
||||
}
|
||||
|
||||
char CpuFeatures_StringView_Front(const StringView view) {
|
||||
assert(view.size);
|
||||
assert(view.ptr);
|
||||
return view.ptr[0];
|
||||
}
|
||||
|
||||
char CpuFeatures_StringView_Back(const StringView view) {
|
||||
assert(view.size);
|
||||
return view.ptr[view.size - 1];
|
||||
}
|
||||
|
||||
StringView CpuFeatures_StringView_TrimWhitespace(StringView view) {
|
||||
while (view.size && isspace(CpuFeatures_StringView_Front(view)))
|
||||
view = CpuFeatures_StringView_PopFront(view, 1);
|
||||
while (view.size && isspace(CpuFeatures_StringView_Back(view)))
|
||||
view = CpuFeatures_StringView_PopBack(view, 1);
|
||||
return view;
|
||||
}
|
||||
|
||||
static int HexValue(const char c) {
|
||||
if (c >= '0' && c <= '9') return c - '0';
|
||||
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns -1 if view contains non digits.
|
||||
static int ParsePositiveNumberWithBase(const StringView view, int base) {
|
||||
int result = 0;
|
||||
StringView remainder = view;
|
||||
for (; remainder.size;
|
||||
remainder = CpuFeatures_StringView_PopFront(remainder, 1)) {
|
||||
const int value = HexValue(CpuFeatures_StringView_Front(remainder));
|
||||
if (value < 0 || value >= base) return -1;
|
||||
result = (result * base) + value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) {
|
||||
if (view.size) {
|
||||
const StringView hex_prefix = str("0x");
|
||||
if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) {
|
||||
const StringView span_no_prefix =
|
||||
CpuFeatures_StringView_PopFront(view, hex_prefix.size);
|
||||
return ParsePositiveNumberWithBase(span_no_prefix, 16);
|
||||
}
|
||||
return ParsePositiveNumberWithBase(view, 10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||
size_t dst_size) {
|
||||
if (dst_size > 0) {
|
||||
const size_t max_copy_size = dst_size - 1;
|
||||
const size_t copy_size =
|
||||
src.size > max_copy_size ? max_copy_size : src.size;
|
||||
copy(dst, src.ptr, copy_size);
|
||||
dst[copy_size] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||
const char* const word_str,
|
||||
const char separator) {
|
||||
const StringView word = str(word_str);
|
||||
StringView remainder = line;
|
||||
for (;;) {
|
||||
const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word);
|
||||
if (index_of_word < 0) {
|
||||
return false;
|
||||
} else {
|
||||
const StringView before =
|
||||
CpuFeatures_StringView_KeepFront(line, index_of_word);
|
||||
const StringView after =
|
||||
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
|
||||
const bool valid_before =
|
||||
before.size == 0 || CpuFeatures_StringView_Back(before) == separator;
|
||||
const bool valid_after =
|
||||
after.size == 0 || CpuFeatures_StringView_Front(after) == separator;
|
||||
if (valid_before && valid_after) return true;
|
||||
remainder =
|
||||
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
|
||||
StringView* key,
|
||||
StringView* value) {
|
||||
const StringView sep = str(": ");
|
||||
const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep);
|
||||
if (index_of_separator < 0) return false;
|
||||
*value = CpuFeatures_StringView_TrimWhitespace(
|
||||
CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size));
|
||||
*key = CpuFeatures_StringView_TrimWhitespace(
|
||||
CpuFeatures_StringView_KeepFront(line, index_of_separator));
|
||||
return true;
|
||||
}
|
||||
+470
@@ -0,0 +1,470 @@
|
||||
// Copyright 2017 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This program dumps current host data to the standard output.
|
||||
// Output can be text or json if the `--json` flag is passed.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpu_features_macros.h"
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86)
|
||||
#include "cpuinfo_x86.h"
|
||||
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||
#include "cpuinfo_arm.h"
|
||||
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||
#include "cpuinfo_aarch64.h"
|
||||
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||
#include "cpuinfo_mips.h"
|
||||
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||
#include "cpuinfo_ppc.h"
|
||||
#elif defined(CPU_FEATURES_ARCH_S390X)
|
||||
#include "cpuinfo_s390x.h"
|
||||
#elif defined(CPU_FEATURES_ARCH_RISCV)
|
||||
#include "cpuinfo_riscv.h"
|
||||
#elif defined(CPU_FEATURES_ARCH_LOONGARCH)
|
||||
#include "cpuinfo_loongarch.h"
|
||||
#endif
|
||||
|
||||
// Design principles
|
||||
// -----------------
|
||||
// We build a tree structure containing all the data to be displayed.
|
||||
// Then depending on the output type (text or json) we walk the tree and display
|
||||
// the data accordingly.
|
||||
|
||||
// We use a bump allocator to allocate strings and nodes of the tree,
|
||||
// Memory is not intended to be reclaimed.
|
||||
typedef struct {
|
||||
char* ptr;
|
||||
size_t size;
|
||||
} BumpAllocator;
|
||||
|
||||
char gGlobalBuffer[64 * 1024];
|
||||
BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer,
|
||||
.size = sizeof(gGlobalBuffer)};
|
||||
|
||||
static void internal_error(void) {
|
||||
fputs("internal error\n", stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#define ALIGN 8
|
||||
|
||||
static void assertAligned(void) {
|
||||
if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error();
|
||||
}
|
||||
|
||||
static void BA_Align(void) {
|
||||
while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) {
|
||||
--gBumpAllocator.size;
|
||||
++gBumpAllocator.ptr;
|
||||
}
|
||||
assertAligned();
|
||||
}
|
||||
|
||||
// Update the available memory left in the BumpAllocator.
|
||||
static void* BA_Bump(size_t size) {
|
||||
assertAligned();
|
||||
// Align size to next 8B boundary.
|
||||
size = (size + ALIGN - 1) / ALIGN * ALIGN;
|
||||
if (gBumpAllocator.size < size) internal_error();
|
||||
void* ptr = gBumpAllocator.ptr;
|
||||
gBumpAllocator.size -= size;
|
||||
gBumpAllocator.ptr += size;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// The type of the nodes in the tree.
|
||||
typedef enum {
|
||||
NT_INVALID,
|
||||
NT_INT,
|
||||
NT_MAP,
|
||||
NT_MAP_ENTRY,
|
||||
NT_ARRAY,
|
||||
NT_ARRAY_ELEMENT,
|
||||
NT_STRING,
|
||||
} NodeType;
|
||||
|
||||
// The node in the tree.
|
||||
typedef struct Node {
|
||||
NodeType type;
|
||||
unsigned integer;
|
||||
const char* string;
|
||||
struct Node* value;
|
||||
struct Node* next;
|
||||
} Node;
|
||||
|
||||
// Creates an initialized Node.
|
||||
static Node* BA_CreateNode(NodeType type) {
|
||||
Node* tv = (Node*)BA_Bump(sizeof(Node));
|
||||
assert(tv);
|
||||
*tv = (Node){.type = type};
|
||||
return tv;
|
||||
}
|
||||
|
||||
// Adds an integer node.
|
||||
static Node* CreateInt(int value) {
|
||||
Node* tv = BA_CreateNode(NT_INT);
|
||||
tv->integer = value;
|
||||
return tv;
|
||||
}
|
||||
|
||||
// Adds a string node.
|
||||
// `value` must outlive the tree.
|
||||
static Node* CreateConstantString(const char* value) {
|
||||
Node* tv = BA_CreateNode(NT_STRING);
|
||||
tv->string = value;
|
||||
return tv;
|
||||
}
|
||||
|
||||
// Adds a map node.
|
||||
static Node* CreateMap(void) { return BA_CreateNode(NT_MAP); }
|
||||
|
||||
// Adds an array node.
|
||||
static Node* CreateArray(void) { return BA_CreateNode(NT_ARRAY); }
|
||||
|
||||
// Adds a formatted string node.
|
||||
static Node* CreatePrintfString(const char* format, ...) {
|
||||
va_list arglist;
|
||||
va_start(arglist, format);
|
||||
char* const ptr = gBumpAllocator.ptr;
|
||||
const int written = vsnprintf(ptr, gBumpAllocator.size, format, arglist);
|
||||
va_end(arglist);
|
||||
if (written < 0 || written >= (int)gBumpAllocator.size) internal_error();
|
||||
return CreateConstantString((char*)BA_Bump(written));
|
||||
}
|
||||
|
||||
// Adds a string node.
|
||||
static Node* CreateString(const char* value) {
|
||||
return CreatePrintfString("%s", value);
|
||||
}
|
||||
|
||||
// Adds a map entry node.
|
||||
static void AddMapEntry(Node* map, const char* key, Node* value) {
|
||||
assert(map && map->type == NT_MAP);
|
||||
Node* current = map;
|
||||
while (current->next) current = current->next;
|
||||
current->next = (Node*)BA_Bump(sizeof(Node));
|
||||
*current->next = (Node){.type = NT_MAP_ENTRY, .string = key, .value = value};
|
||||
}
|
||||
|
||||
// Adds an array element node.
|
||||
static void AddArrayElement(Node* array, Node* value) {
|
||||
assert(array && array->type == NT_ARRAY);
|
||||
Node* current = array;
|
||||
while (current->next) current = current->next;
|
||||
current->next = (Node*)BA_Bump(sizeof(Node));
|
||||
*current->next = (Node){.type = NT_ARRAY_ELEMENT, .value = value};
|
||||
}
|
||||
|
||||
static int cmp(const void* p1, const void* p2) {
|
||||
return strcmp(*(const char* const*)p1, *(const char* const*)p2);
|
||||
}
|
||||
|
||||
#define DEFINE_ADD_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
|
||||
static void AddFlags(Node* map, const FeatureType* features) { \
|
||||
size_t i; \
|
||||
const char* ptrs[LastEnum] = {0}; \
|
||||
size_t count = 0; \
|
||||
for (i = 0; i < LastEnum; ++i) { \
|
||||
if (HasFeature(features, i)) { \
|
||||
ptrs[count] = FeatureName(i); \
|
||||
++count; \
|
||||
} \
|
||||
} \
|
||||
qsort((void*)ptrs, count, sizeof(char*), cmp); \
|
||||
Node* const array = CreateArray(); \
|
||||
for (i = 0; i < count; ++i) \
|
||||
AddArrayElement(array, CreateConstantString(ptrs[i])); \
|
||||
AddMapEntry(map, "flags", array); \
|
||||
}
|
||||
|
||||
#if defined(CPU_FEATURES_ARCH_X86)
|
||||
DEFINE_ADD_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
|
||||
X86_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||
DEFINE_ADD_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
|
||||
ARM_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||
DEFINE_ADD_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
|
||||
Aarch64Features, AARCH64_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||
DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
|
||||
MipsFeatures, MIPS_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||
DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
|
||||
PPC_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_S390X)
|
||||
DEFINE_ADD_FLAGS(GetS390XFeaturesEnumValue, GetS390XFeaturesEnumName, S390XFeatures,
|
||||
S390X_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_RISCV)
|
||||
DEFINE_ADD_FLAGS(GetRiscvFeaturesEnumValue, GetRiscvFeaturesEnumName, RiscvFeatures,
|
||||
RISCV_LAST_)
|
||||
#elif defined(CPU_FEATURES_ARCH_LOONGARCH)
|
||||
DEFINE_ADD_FLAGS(GetLoongArchFeaturesEnumValue, GetLoongArchFeaturesEnumName, LoongArchFeatures,
|
||||
LOONGARCH_LAST_)
|
||||
#endif
|
||||
|
||||
// Prints a json string with characters escaping.
|
||||
static void printJsonString(const char* str) {
|
||||
putchar('"');
|
||||
for (; str && *str; ++str) {
|
||||
switch (*str) {
|
||||
case '\"':
|
||||
case '\\':
|
||||
case '/':
|
||||
case '\b':
|
||||
case '\f':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
putchar('\\');
|
||||
}
|
||||
putchar(*str);
|
||||
}
|
||||
putchar('"');
|
||||
}
|
||||
|
||||
// Walks a Node and print it as json.
|
||||
static void printJson(const Node* current) {
|
||||
assert(current);
|
||||
switch (current->type) {
|
||||
case NT_INVALID:
|
||||
break;
|
||||
case NT_INT:
|
||||
printf("%d", current->integer);
|
||||
break;
|
||||
case NT_STRING:
|
||||
printJsonString(current->string);
|
||||
break;
|
||||
case NT_ARRAY:
|
||||
putchar('[');
|
||||
if (current->next) printJson(current->next);
|
||||
putchar(']');
|
||||
break;
|
||||
case NT_MAP:
|
||||
putchar('{');
|
||||
if (current->next) printJson(current->next);
|
||||
putchar('}');
|
||||
break;
|
||||
case NT_MAP_ENTRY:
|
||||
printf("\"%s\":", current->string);
|
||||
printJson(current->value);
|
||||
if (current->next) {
|
||||
putchar(',');
|
||||
printJson(current->next);
|
||||
}
|
||||
break;
|
||||
case NT_ARRAY_ELEMENT:
|
||||
printJson(current->value);
|
||||
if (current->next) {
|
||||
putchar(',');
|
||||
printJson(current->next);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Walks a Node and print it as text.
|
||||
static void printTextField(const Node* current) {
|
||||
switch (current->type) {
|
||||
case NT_INVALID:
|
||||
break;
|
||||
case NT_INT:
|
||||
printf("%3d (0x%02X)", current->integer, current->integer);
|
||||
break;
|
||||
case NT_STRING:
|
||||
fputs(current->string, stdout);
|
||||
break;
|
||||
case NT_ARRAY:
|
||||
if (current->next) printTextField(current->next);
|
||||
break;
|
||||
case NT_MAP:
|
||||
if (current->next) {
|
||||
printf("{");
|
||||
printJson(current->next);
|
||||
printf("}");
|
||||
}
|
||||
break;
|
||||
case NT_MAP_ENTRY:
|
||||
printf("%-15s : ", current->string);
|
||||
printTextField(current->value);
|
||||
if (current->next) {
|
||||
putchar('\n');
|
||||
printTextField(current->next);
|
||||
}
|
||||
break;
|
||||
case NT_ARRAY_ELEMENT:
|
||||
printTextField(current->value);
|
||||
if (current->next) {
|
||||
putchar(',');
|
||||
printTextField(current->next);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void printTextRoot(const Node* current) {
|
||||
if (current->type == NT_MAP && current->next) printTextField(current->next);
|
||||
}
|
||||
|
||||
static void showUsage(const char* name) {
|
||||
printf(
|
||||
"\n"
|
||||
"Usage: %s [options]\n"
|
||||
" Options:\n"
|
||||
" -h | --help Show help message.\n"
|
||||
" -j | --json Format output as json instead of plain text.\n"
|
||||
"\n",
|
||||
name);
|
||||
}
|
||||
|
||||
static Node* GetCacheTypeString(CacheType cache_type) {
|
||||
switch (cache_type) {
|
||||
case CPU_FEATURE_CACHE_NULL:
|
||||
return CreateConstantString("null");
|
||||
case CPU_FEATURE_CACHE_DATA:
|
||||
return CreateConstantString("data");
|
||||
case CPU_FEATURE_CACHE_INSTRUCTION:
|
||||
return CreateConstantString("instruction");
|
||||
case CPU_FEATURE_CACHE_UNIFIED:
|
||||
return CreateConstantString("unified");
|
||||
case CPU_FEATURE_CACHE_TLB:
|
||||
return CreateConstantString("tlb");
|
||||
case CPU_FEATURE_CACHE_DTLB:
|
||||
return CreateConstantString("dtlb");
|
||||
case CPU_FEATURE_CACHE_STLB:
|
||||
return CreateConstantString("stlb");
|
||||
case CPU_FEATURE_CACHE_PREFETCH:
|
||||
return CreateConstantString("prefetch");
|
||||
}
|
||||
CPU_FEATURES_UNREACHABLE();
|
||||
}
|
||||
|
||||
static void AddCacheInfo(Node* root, const CacheInfo* cache_info) {
|
||||
Node* array = CreateArray();
|
||||
for (int i = 0; i < cache_info->size; ++i) {
|
||||
CacheLevelInfo info = cache_info->levels[i];
|
||||
Node* map = CreateMap();
|
||||
AddMapEntry(map, "level", CreateInt(info.level));
|
||||
AddMapEntry(map, "cache_type", GetCacheTypeString(info.cache_type));
|
||||
AddMapEntry(map, "cache_size", CreateInt(info.cache_size));
|
||||
AddMapEntry(map, "ways", CreateInt(info.ways));
|
||||
AddMapEntry(map, "line_size", CreateInt(info.line_size));
|
||||
AddMapEntry(map, "tlb_entries", CreateInt(info.tlb_entries));
|
||||
AddMapEntry(map, "partitioning", CreateInt(info.partitioning));
|
||||
AddArrayElement(array, map);
|
||||
}
|
||||
AddMapEntry(root, "cache_info", array);
|
||||
}
|
||||
|
||||
static Node* CreateTree(void) {
|
||||
Node* root = CreateMap();
|
||||
#if defined(CPU_FEATURES_ARCH_X86)
|
||||
const X86Info info = GetX86Info();
|
||||
const CacheInfo cache_info = GetX86CacheInfo();
|
||||
AddMapEntry(root, "arch", CreateString("x86"));
|
||||
AddMapEntry(root, "brand", CreateString(info.brand_string));
|
||||
AddMapEntry(root, "family", CreateInt(info.family));
|
||||
AddMapEntry(root, "model", CreateInt(info.model));
|
||||
AddMapEntry(root, "stepping", CreateInt(info.stepping));
|
||||
AddMapEntry(root, "uarch",
|
||||
CreateString(
|
||||
GetX86MicroarchitectureName(GetX86Microarchitecture(&info))));
|
||||
AddFlags(root, &info.features);
|
||||
AddCacheInfo(root, &cache_info);
|
||||
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||
const ArmInfo info = GetArmInfo();
|
||||
AddMapEntry(root, "arch", CreateString("ARM"));
|
||||
AddMapEntry(root, "implementer", CreateInt(info.implementer));
|
||||
AddMapEntry(root, "architecture", CreateInt(info.architecture));
|
||||
AddMapEntry(root, "variant", CreateInt(info.variant));
|
||||
AddMapEntry(root, "part", CreateInt(info.part));
|
||||
AddMapEntry(root, "revision", CreateInt(info.revision));
|
||||
AddFlags(root, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||
const Aarch64Info info = GetAarch64Info();
|
||||
AddMapEntry(root, "arch", CreateString("aarch64"));
|
||||
AddMapEntry(root, "implementer", CreateInt(info.implementer));
|
||||
AddMapEntry(root, "variant", CreateInt(info.variant));
|
||||
AddMapEntry(root, "part", CreateInt(info.part));
|
||||
AddMapEntry(root, "revision", CreateInt(info.revision));
|
||||
AddFlags(root, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||
const MipsInfo info = GetMipsInfo();
|
||||
AddMapEntry(root, "arch", CreateString("mips"));
|
||||
AddFlags(root, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||
const PPCInfo info = GetPPCInfo();
|
||||
const PPCPlatformStrings strings = GetPPCPlatformStrings();
|
||||
AddMapEntry(root, "arch", CreateString("ppc"));
|
||||
AddMapEntry(root, "platform", CreateString(strings.platform));
|
||||
AddMapEntry(root, "model", CreateString(strings.model));
|
||||
AddMapEntry(root, "machine", CreateString(strings.machine));
|
||||
AddMapEntry(root, "cpu", CreateString(strings.cpu));
|
||||
AddMapEntry(root, "instruction", CreateString(strings.type.platform));
|
||||
AddMapEntry(root, "microarchitecture",
|
||||
CreateString(strings.type.base_platform));
|
||||
AddFlags(root, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_S390X)
|
||||
const S390XInfo info = GetS390XInfo();
|
||||
const S390XPlatformStrings strings = GetS390XPlatformStrings();
|
||||
AddMapEntry(root, "arch", CreateString("s390x"));
|
||||
AddMapEntry(root, "platform", CreateString("zSeries"));
|
||||
AddMapEntry(root, "model", CreateString(strings.type.platform));
|
||||
AddMapEntry(root, "# processors", CreateInt(strings.num_processors));
|
||||
AddFlags(root, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_RISCV)
|
||||
const RiscvInfo info = GetRiscvInfo();
|
||||
AddMapEntry(root, "arch", CreateString("risc-v"));
|
||||
AddMapEntry(root, "vendor", CreateString(info.vendor));
|
||||
AddMapEntry(root, "microarchitecture", CreateString(info.uarch));
|
||||
AddFlags(root, &info.features);
|
||||
#elif defined(CPU_FEATURES_ARCH_LOONGARCH)
|
||||
const LoongArchInfo info = GetLoongArchInfo();
|
||||
AddMapEntry(root, "arch", CreateString("loongarch"));
|
||||
AddFlags(root, &info.features);
|
||||
#endif
|
||||
return root;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
BA_Align();
|
||||
const Node* const root = CreateTree();
|
||||
bool outputJson = false;
|
||||
int i = 1;
|
||||
for (; i < argc; ++i) {
|
||||
const char* arg = argv[i];
|
||||
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
|
||||
outputJson = true;
|
||||
} else {
|
||||
showUsage(argv[0]);
|
||||
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
|
||||
return EXIT_SUCCESS;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
if (outputJson)
|
||||
printJson(root);
|
||||
else
|
||||
printTextRoot(root);
|
||||
putchar('\n');
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
cv2pdb.exe
|
||||
dbghelp.dll
|
||||
msobj140.dll
|
||||
mspdb140.dll
|
||||
mspdbcmf.exe
|
||||
mspdbcore.dll
|
||||
mspdbsrv.exe
|
||||
mspdbst.dll
|
||||
vcruntime140.dll
|
||||
Vendored
-36
@@ -1,36 +0,0 @@
|
||||
# cv2pdb
|
||||
|
||||
This exists to convert the DWARF debug information to PDB and helps us
|
||||
to get more precise stackstraces on program crashes.
|
||||
|
||||
Sadly this program is for windows only, but we can get it running using
|
||||
WINE. You'll not only need wine and cv2pdb, but also Microsoft's PDB
|
||||
helper libraries and dependencies.
|
||||
Because of licensing issues I can't supply the needed files for you
|
||||
here. What files work for me:
|
||||
|
||||
- cv2pdb.exe
|
||||
- dbghelp.dll
|
||||
- msobj140.dll
|
||||
- mspdb140.dll
|
||||
- mspdbcmf.exe
|
||||
- mspdbcore.dll
|
||||
- mspdbsrv.exe
|
||||
- mspdbst.dll
|
||||
- vcruntime140.dll
|
||||
|
||||
I found those libraries in my Visual Studio 2017 install:
|
||||
|
||||
..\2017\Community\VC\Tools\MSVC\14.11.25503\bin\Hostx86\x86
|
||||
|
||||
You can find cv2pdb binaries here:
|
||||
|
||||
https://github.com/rainers/cv2pdb/releases
|
||||
|
||||
Apparently cv2pdb also supports older versions of mspdb:
|
||||
|
||||
- mspdb80
|
||||
- mspdb100
|
||||
- mspdb110
|
||||
- mspdb120
|
||||
- mspdb140
|
||||
Vendored
-1
@@ -45,7 +45,6 @@ IncludeCategories:
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '(_test|_win|_linux|_mac|_ios|_osx|_null)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required (VERSION 3.2.0)
|
||||
cmake_minimum_required (VERSION 3.12)
|
||||
project (DiscordRPC)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
Vendored
+6
-13
@@ -1,24 +1,17 @@
|
||||
FROM archlinux:base
|
||||
FROM ghcr.io/archlinux/archlinux:base-devel
|
||||
|
||||
RUN pacman --noconfirm -Syu gettext \
|
||||
git \
|
||||
RUN pacman --noconfirm -Syu git \
|
||||
bash \
|
||||
zip \
|
||||
upx \
|
||||
sudo \
|
||||
binutils \
|
||||
file \
|
||||
make \
|
||||
gcc \
|
||||
fakeroot \
|
||||
diffutils \
|
||||
ninja \
|
||||
cmake \
|
||||
awk \
|
||||
unzip \
|
||||
mingw-w64-crt \
|
||||
mingw-w64-winpthreads \
|
||||
mingw-w64-gcc \
|
||||
mingw-w64-headers \
|
||||
mingw-w64-binutils
|
||||
mingw-w64-binutils \
|
||||
ccache
|
||||
RUN useradd user -m && echo "ALL ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
|
||||
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay.git --depth=1 && cd yay && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
|
||||
RUN su user -c "cd /tmp/ && git clone https://aur.archlinux.org/yay-bin.git --depth=1 && cd yay-bin && makepkg --noconfirm -si && yay --noconfirm -S mingw-w64-cmake"
|
||||
|
||||
Vendored
+5
@@ -1527,6 +1527,9 @@ FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
|
||||
return arg;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdangling-reference"
|
||||
|
||||
// The type template parameter is there to avoid an ODR violation when using
|
||||
// a fallback formatter in one translation unit and an implicit conversion in
|
||||
// another (not recommended).
|
||||
@@ -1541,6 +1544,8 @@ FMT_CONSTEXPR FMT_INLINE auto make_arg(const T& val) -> value<Context> {
|
||||
return arg;
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
template <bool IS_PACKED, typename Context, type, typename T,
|
||||
FMT_ENABLE_IF(!IS_PACKED)>
|
||||
inline auto make_arg(const T& value) -> basic_format_arg<Context> {
|
||||
|
||||
Vendored
+1
-1
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.9)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(imgui CXX)
|
||||
|
||||
set(HASH_LIBRARY_HEADERS
|
||||
|
||||
Vendored
+1
-1
@@ -1467,7 +1467,7 @@ void basic_tcp_server::accept_thread()
|
||||
|
||||
if (handshake(conn))
|
||||
{
|
||||
if (newClient = accept(conn))
|
||||
if ((newClient = accept(conn)))
|
||||
{
|
||||
newClient->on_accept();
|
||||
|
||||
|
||||
Vendored
+5
-1
@@ -1,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.9)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
project(imgui CXX)
|
||||
|
||||
# dear imgui uses the C++ virtual interfaces for DirectX
|
||||
@@ -8,6 +8,8 @@ set(IMGUI_HEADERS
|
||||
imconfig.h
|
||||
imgui.h
|
||||
imgui_internal.h
|
||||
backends/imgui_impl_dx9.h
|
||||
misc/cpp/imgui_stdlib.h
|
||||
)
|
||||
set(IMGUI_SOURCES
|
||||
imgui.cpp
|
||||
@@ -15,6 +17,8 @@ set(IMGUI_SOURCES
|
||||
imgui_tables.cpp
|
||||
imgui_widgets.cpp
|
||||
imgui_demo.cpp
|
||||
backends/imgui_impl_dx9.cpp
|
||||
misc/cpp/imgui_stdlib.cpp
|
||||
)
|
||||
|
||||
add_library(imgui STATIC ${IMGUI_HEADERS} ${IMGUI_SOURCES})
|
||||
|
||||
+360
@@ -0,0 +1,360 @@
|
||||
// dear imgui: Renderer for DirectX9
|
||||
// This needs to be used along with a Platform Binding (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
// CHANGELOG
|
||||
// (minor and older changes stripped away, please see git history for details)
|
||||
// 2019-05-29: DirectX9: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
|
||||
// 2019-04-30: DirectX9: Added support for special ImDrawCallback_ResetRenderState callback to reset render state.
|
||||
// 2019-03-29: Misc: Fixed erroneous assert in ImGui_ImplDX9_InvalidateDeviceObjects().
|
||||
// 2019-01-16: Misc: Disabled fog before drawing UI's. Fixes issue #2288.
|
||||
// 2018-11-30: Misc: Setting up io.BackendRendererName so it can be displayed in the About Window.
|
||||
// 2018-06-08: Misc: Extracted imgui_impl_dx9.cpp/.h away from the old combined DX9+Win32 example.
|
||||
// 2018-06-08: DirectX9: Use draw_data->DisplayPos and draw_data->DisplaySize to setup projection matrix and clipping rectangle.
|
||||
// 2018-05-07: Render: Saving/restoring Transform because they don't seem to be included in the StateBlock. Setting shading mode to Gouraud.
|
||||
// 2018-02-16: Misc: Obsoleted the io.RenderDrawListsFn callback and exposed ImGui_ImplDX9_RenderDrawData() in the .h file so you can call it yourself.
|
||||
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
|
||||
|
||||
#include "imgui_impl_dx9.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
// DirectX
|
||||
#include <d3d9.h>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
// allow std::min use
|
||||
#ifdef min
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
// DirectX data
|
||||
static LPDIRECT3DDEVICE9 g_pd3dDevice = NULL;
|
||||
static LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
|
||||
static LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
|
||||
static LPDIRECT3DTEXTURE9 g_FontTexture = NULL;
|
||||
static int g_VertexBufferSize = 5000, g_IndexBufferSize = 10000;
|
||||
|
||||
#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)
|
||||
|
||||
// Render function.
|
||||
// (this used to be set in io.RenderDrawListsFn and called by ImGui::Render(), but you can now call this directly from your main loop)
|
||||
void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data) {
|
||||
|
||||
// Avoid rendering when minimized
|
||||
if (draw_data->DisplaySize.x <= 0.0f || draw_data->DisplaySize.y <= 0.0f)
|
||||
return;
|
||||
|
||||
// Create and grow buffers if needed
|
||||
if (!g_pVB || g_VertexBufferSize < draw_data->TotalVtxCount) {
|
||||
if (g_pVB) {
|
||||
g_pVB->Release();
|
||||
g_pVB = NULL;
|
||||
}
|
||||
g_VertexBufferSize = draw_data->TotalVtxCount + 5000;
|
||||
if (g_pd3dDevice->CreateVertexBuffer(g_VertexBufferSize * sizeof(ImDrawVert),
|
||||
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX,
|
||||
D3DPOOL_DEFAULT, &g_pVB, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
if (!g_pIB || g_IndexBufferSize < draw_data->TotalIdxCount) {
|
||||
if (g_pIB) {
|
||||
g_pIB->Release();
|
||||
g_pIB = NULL;
|
||||
}
|
||||
g_IndexBufferSize = draw_data->TotalIdxCount + 10000;
|
||||
if (g_pd3dDevice->CreateIndexBuffer(g_IndexBufferSize * sizeof(ImDrawIdx),
|
||||
D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
|
||||
sizeof(ImDrawIdx) == 2 ? D3DFMT_INDEX16 : D3DFMT_INDEX32,
|
||||
D3DPOOL_DEFAULT, &g_pIB, NULL) < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// Backup the DX9 state
|
||||
IDirect3DStateBlock9 *d3d9_state_block = NULL;
|
||||
if (g_pd3dDevice->CreateStateBlock(D3DSBT_ALL, &d3d9_state_block) < 0)
|
||||
return;
|
||||
|
||||
// Backup the DX9 transform (DX9 documentation suggests that it is included in the StateBlock but it doesn't appear to)
|
||||
D3DMATRIX last_world, last_view, last_projection;
|
||||
g_pd3dDevice->GetTransform(D3DTS_WORLD, &last_world);
|
||||
g_pd3dDevice->GetTransform(D3DTS_VIEW, &last_view);
|
||||
g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &last_projection);
|
||||
|
||||
// Copy all vertices into a single contiguous buffer
|
||||
ImDrawVert *vtx_dst;
|
||||
ImDrawIdx *idx_dst;
|
||||
if (g_pVB->Lock(0, (UINT) (draw_data->TotalVtxCount * sizeof(ImDrawVert)), (void **) &vtx_dst,
|
||||
D3DLOCK_DISCARD) < 0)
|
||||
return;
|
||||
if (g_pIB->Lock(0, (UINT) (draw_data->TotalIdxCount * sizeof(ImDrawIdx)), (void **) &idx_dst,
|
||||
D3DLOCK_DISCARD) < 0)
|
||||
return;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
||||
const ImDrawList *cmd_list = draw_data->CmdLists[n];
|
||||
memcpy(vtx_dst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy(idx_dst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
vtx_dst += cmd_list->VtxBuffer.Size;
|
||||
idx_dst += cmd_list->IdxBuffer.Size;
|
||||
}
|
||||
g_pVB->Unlock();
|
||||
g_pIB->Unlock();
|
||||
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(ImDrawVert));
|
||||
g_pd3dDevice->SetIndices(g_pIB);
|
||||
g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
|
||||
|
||||
// Setup viewport
|
||||
D3DVIEWPORT9 vp;
|
||||
vp.X = vp.Y = 0;
|
||||
vp.Width = (DWORD) draw_data->DisplaySize.x;
|
||||
vp.Height = (DWORD) draw_data->DisplaySize.y;
|
||||
vp.MinZ = 0.0f;
|
||||
vp.MaxZ = 1.0f;
|
||||
g_pd3dDevice->SetViewport(&vp);
|
||||
|
||||
g_pd3dDevice->SetPixelShader(nullptr);
|
||||
g_pd3dDevice->SetVertexShader(nullptr);
|
||||
|
||||
D3DCAPS9 caps {};
|
||||
if (FAILED(g_pd3dDevice->GetDeviceCaps(&caps))) {
|
||||
caps.NumSimultaneousRTs = 0UL;
|
||||
}
|
||||
|
||||
IDirect3DSurface9 *back_buffer = nullptr;
|
||||
IDirect3DSurface9 *depth_stencil = nullptr;
|
||||
IDirect3DSurface9 *render_targets[8];
|
||||
|
||||
// save all previous render target state
|
||||
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
||||
if (FAILED(g_pd3dDevice->GetRenderTarget(target, &render_targets[target]))) {
|
||||
render_targets[target] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// get the previous depth stencil
|
||||
if (FAILED(g_pd3dDevice->GetDepthStencilSurface(&depth_stencil))) {
|
||||
depth_stencil = nullptr;
|
||||
}
|
||||
|
||||
// set the back buffer as the current render target
|
||||
if (SUCCEEDED(g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &back_buffer))) {
|
||||
g_pd3dDevice->SetRenderTarget(0, back_buffer);
|
||||
g_pd3dDevice->SetDepthStencilSurface(nullptr);
|
||||
|
||||
for (size_t target = 1; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
||||
g_pd3dDevice->SetRenderTarget(target, nullptr);
|
||||
}
|
||||
} else {
|
||||
back_buffer = nullptr;
|
||||
}
|
||||
|
||||
// Setup render state: fixed-pipeline, alpha-blending, no face culling, no depth testing, shade mode (for gradient)
|
||||
g_pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, false);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, false);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, true);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
|
||||
g_pd3dDevice->SetRenderState(D3DRS_FOGENABLE, false);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
|
||||
g_pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
|
||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
|
||||
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
|
||||
|
||||
// Setup orthographic projection matrix
|
||||
// Our visible imgui space lies from draw_data->DisplayPos (top left) to draw_data->DisplayPos+data_data->DisplaySize (bottom right). DisplayPos is (0,0) for single viewport apps.
|
||||
// Being agnostic of whether <d3dx9.h> or <DirectXMath.h> can be used, we aren't relying on D3DXMatrixIdentity()/D3DXMatrixOrthoOffCenterLH() or DirectX::XMMatrixIdentity()/DirectX::XMMatrixOrthographicOffCenterLH()
|
||||
{
|
||||
float L = draw_data->DisplayPos.x + 0.5f;
|
||||
float R = draw_data->DisplayPos.x + draw_data->DisplaySize.x + 0.5f;
|
||||
float T = draw_data->DisplayPos.y + 0.5f;
|
||||
float B = draw_data->DisplayPos.y + draw_data->DisplaySize.y + 0.5f;
|
||||
D3DMATRIX mat_identity = {{{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
D3DMATRIX mat_projection =
|
||||
{{{
|
||||
2.0f / (R - L), 0.0f, 0.0f, 0.0f,
|
||||
0.0f, 2.0f / (T - B), 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.5f, 0.0f,
|
||||
(L + R) / (L - R), (T + B) / (B - T), 0.5f, 1.0f
|
||||
}}};
|
||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &mat_identity);
|
||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &mat_identity);
|
||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_projection);
|
||||
}
|
||||
|
||||
// Render command lists
|
||||
// (Because we merged all buffers into a single one, we maintain our own offset into them)
|
||||
int global_vtx_offset = 0;
|
||||
int global_idx_offset = 0;
|
||||
ImVec2 clip_off = draw_data->DisplayPos;
|
||||
for (int n = 0; n < draw_data->CmdListsCount; n++) {
|
||||
const ImDrawList *cmd_list = draw_data->CmdLists[n];
|
||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) {
|
||||
const ImDrawCmd *pcmd = &cmd_list->CmdBuffer[cmd_i];
|
||||
if (pcmd->UserCallback != NULL) {
|
||||
pcmd->UserCallback(cmd_list, pcmd);
|
||||
} else {
|
||||
const RECT r = {(LONG) (pcmd->ClipRect.x - clip_off.x), (LONG) (pcmd->ClipRect.y - clip_off.y),
|
||||
(LONG) (pcmd->ClipRect.z - clip_off.x), (LONG) (pcmd->ClipRect.w - clip_off.y)};
|
||||
auto texture = reinterpret_cast<IDirect3DBaseTexture9 *>(pcmd->TextureId);
|
||||
g_pd3dDevice->SetTexture(0, texture);
|
||||
g_pd3dDevice->SetScissorRect(&r);
|
||||
g_pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,
|
||||
pcmd->VtxOffset + global_vtx_offset, 0,
|
||||
(UINT) cmd_list->VtxBuffer.Size,
|
||||
pcmd->IdxOffset + global_idx_offset, pcmd->ElemCount / 3);
|
||||
}
|
||||
}
|
||||
global_idx_offset += cmd_list->IdxBuffer.Size;
|
||||
global_vtx_offset += cmd_list->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
if (back_buffer) {
|
||||
back_buffer->Release();
|
||||
back_buffer = nullptr;
|
||||
}
|
||||
|
||||
// restore previous depth stencil
|
||||
if (depth_stencil) {
|
||||
g_pd3dDevice->SetDepthStencilSurface(depth_stencil);
|
||||
depth_stencil->Release();
|
||||
depth_stencil = nullptr;
|
||||
}
|
||||
|
||||
// restore all render target state
|
||||
for (size_t target = 0; target < std::min(8UL, caps.NumSimultaneousRTs); target++) {
|
||||
auto render_target = render_targets[target];
|
||||
|
||||
if (render_target) {
|
||||
g_pd3dDevice->SetRenderTarget(target, render_target);
|
||||
render_target->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// restore the DX9 transform
|
||||
g_pd3dDevice->SetTransform(D3DTS_WORLD, &last_world);
|
||||
g_pd3dDevice->SetTransform(D3DTS_VIEW, &last_view);
|
||||
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &last_projection);
|
||||
|
||||
// restore the DX9 state
|
||||
d3d9_state_block->Apply();
|
||||
d3d9_state_block->Release();
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device) {
|
||||
|
||||
// Setup back-end capabilities flags
|
||||
auto &io = ImGui::GetIO();
|
||||
io.BackendRendererName = "imgui_impl_dx9";
|
||||
|
||||
// We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.
|
||||
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
||||
|
||||
g_pd3dDevice = device;
|
||||
g_pd3dDevice->AddRef();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_Shutdown() {
|
||||
ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
|
||||
if (g_pd3dDevice) {
|
||||
g_pd3dDevice->Release();
|
||||
g_pd3dDevice = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ImGui_ImplDX9_CreateFontsTexture() {
|
||||
// Build texture atlas
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
unsigned char *pixels;
|
||||
int width, height, bytes_per_pixel;
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height, &bytes_per_pixel);
|
||||
|
||||
// Upload texture to graphics system
|
||||
g_FontTexture = NULL;
|
||||
if (g_pd3dDevice->CreateTexture(width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_DEFAULT, &g_FontTexture, NULL) < 0)
|
||||
return false;
|
||||
D3DLOCKED_RECT tex_locked_rect;
|
||||
if (g_FontTexture->LockRect(0, &tex_locked_rect, NULL, 0) != D3D_OK)
|
||||
return false;
|
||||
for (int y = 0; y < height; y++)
|
||||
memcpy((unsigned char *) tex_locked_rect.pBits + tex_locked_rect.Pitch * y,
|
||||
pixels + (width * bytes_per_pixel) * y, (width * bytes_per_pixel));
|
||||
g_FontTexture->UnlockRect(0);
|
||||
|
||||
// Store our identifier
|
||||
io.Fonts->TexID = (ImTextureID) g_FontTexture;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_ImplDX9_CreateDeviceObjects() {
|
||||
if (!g_pd3dDevice) {
|
||||
return false;
|
||||
}
|
||||
return ImGui_ImplDX9_CreateFontsTexture();
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_InvalidateDeviceObjects() {
|
||||
if (!g_pd3dDevice)
|
||||
return;
|
||||
if (g_pVB) {
|
||||
g_pVB->Release();
|
||||
g_pVB = NULL;
|
||||
}
|
||||
if (g_pIB) {
|
||||
g_pIB->Release();
|
||||
g_pIB = NULL;
|
||||
}
|
||||
if (g_FontTexture) {
|
||||
g_FontTexture->Release();
|
||||
g_FontTexture = NULL;
|
||||
ImGui::GetIO().Fonts->TexID = 0;
|
||||
} // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well.
|
||||
}
|
||||
|
||||
void ImGui_ImplDX9_NewFrame() {
|
||||
if (!g_FontTexture) {
|
||||
ImGui_ImplDX9_CreateDeviceObjects();
|
||||
}
|
||||
|
||||
IDirect3DSwapChain9 *swap_chain = nullptr;
|
||||
if (SUCCEEDED(g_pd3dDevice->GetSwapChain(0, &swap_chain))) {
|
||||
auto &io = ImGui::GetIO();
|
||||
|
||||
D3DPRESENT_PARAMETERS present_params {};
|
||||
|
||||
if (SUCCEEDED(swap_chain->GetPresentParameters(&present_params))) {
|
||||
if (present_params.BackBufferWidth != 0 && present_params.BackBufferHeight != 0) {
|
||||
io.DisplaySize.x = static_cast<float>(present_params.BackBufferWidth);
|
||||
io.DisplaySize.y = static_cast<float>(present_params.BackBufferHeight);
|
||||
} else {
|
||||
RECT rect {};
|
||||
GetClientRect(present_params.hDeviceWindow, &rect);
|
||||
|
||||
io.DisplaySize.x = static_cast<float>(rect.right - rect.left);
|
||||
io.DisplaySize.y = static_cast<float>(rect.bottom - rect.top);
|
||||
}
|
||||
}
|
||||
|
||||
swap_chain->Release();
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// dear imgui: Renderer for DirectX9
|
||||
// This needs to be used along with a Platform Binding (e.g. Win32)
|
||||
|
||||
// Implemented features:
|
||||
// [X] Renderer: User texture binding. Use 'LPDIRECT3DTEXTURE9' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
|
||||
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
|
||||
|
||||
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
|
||||
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
|
||||
// https://github.com/ocornut/imgui
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
struct IDirect3DDevice9;
|
||||
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_Init(IDirect3DDevice9 *device);
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_Shutdown();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_NewFrame();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_RenderDrawData(ImDrawData *draw_data);
|
||||
|
||||
// Use if you want to reset your rendering device without losing ImGui state.
|
||||
IMGUI_IMPL_API bool ImGui_ImplDX9_CreateDeviceObjects();
|
||||
IMGUI_IMPL_API void ImGui_ImplDX9_InvalidateDeviceObjects();
|
||||
Vendored
+33
-16
@@ -1,5 +1,5 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// COMPILE-TIME OPTIONS FOR DEAR IMGUI
|
||||
// DEAR IMGUI COMPILE-TIME OPTIONS
|
||||
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
|
||||
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -9,7 +9,7 @@
|
||||
// You need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include the imgui*.cpp
|
||||
// files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
|
||||
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
// Call IMGUI_CHECKVERSION() from your .cpp file to verify that the data structures your files are using are matching the ones imgui.cpp is using.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
@@ -21,27 +21,29 @@
|
||||
|
||||
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
|
||||
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
|
||||
// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec( dllexport )
|
||||
//#define IMGUI_API __declspec( dllimport )
|
||||
// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
|
||||
// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
|
||||
//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
|
||||
//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
|
||||
//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
|
||||
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names.
|
||||
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87: disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This will be folded into IMGUI_DISABLE_OBSOLETE_FUNCTIONS in a few versions.
|
||||
//#define IMGUI_DISABLE_OBSOLETE_KEYIO // 1.87+ disable legacy io.KeyMap[]+io.KeysDown[] in favor io.AddKeyEvent(). This is automatically done by IMGUI_DISABLE_OBSOLETE_FUNCTIONS.
|
||||
|
||||
//---- Disable all of Dear ImGui or don't implement standard windows/tools.
|
||||
// It is very strongly recommended to NOT disable the demo windows and debug tool during development. They are extremely useful in day to day work. Please read comments in imgui_demo.cpp.
|
||||
//#define IMGUI_DISABLE // Disable everything: all headers and source files will be empty.
|
||||
//#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowStackToolWindow() will be empty (this was called IMGUI_DISABLE_METRICS_WINDOW before 1.88).
|
||||
#define IMGUI_DISABLE_DEMO_WINDOWS // Disable demo windows: ShowDemoWindow()/ShowStyleEditor() will be empty.
|
||||
//#define IMGUI_DISABLE_DEBUG_TOOLS // Disable metrics/debugger and other debug tools: ShowMetricsWindow(), ShowDebugLogWindow() and ShowIDStackToolWindow() will be empty.
|
||||
|
||||
//---- Don't implement some functions to reduce linkage requirements.
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. (user32.lib/.a, kernel32.lib/.a)
|
||||
#define IMGUI_ENABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with Visual Studio] Implement default IME handler (require imm32.lib/.a, auto-link for Visual Studio, -limm32 on command-line for MinGW)
|
||||
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
|
||||
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
|
||||
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
|
||||
//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
|
||||
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
|
||||
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
|
||||
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
|
||||
@@ -49,8 +51,13 @@
|
||||
#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
|
||||
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
|
||||
|
||||
//---- Enable Test Engine / Automation features.
|
||||
//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
|
||||
|
||||
//---- Include imgui_user.h at the end of imgui.h as a convenience
|
||||
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
|
||||
//#define IMGUI_INCLUDE_IMGUI_USER_H
|
||||
//#define IMGUI_USER_H_FILENAME "my_folder/my_imgui_user.h"
|
||||
|
||||
//---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another)
|
||||
#define IMGUI_USE_BGRA_PACKED_COLOR
|
||||
@@ -58,16 +65,17 @@
|
||||
//---- Performance optimization for DX9
|
||||
#define IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT struct ImDrawVert { ImVec2 pos; float z; ImU32 col; ImVec2 uv; }
|
||||
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//---- Use 32-bit for ImWchar (default is 16-bit) to support Unicode planes 1-16. (e.g. point beyond 0xFFFF like emoticons, dingbats, symbols, shapes, ancient languages, etc...)
|
||||
//#define IMGUI_USE_WCHAR32
|
||||
|
||||
//---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version
|
||||
// By default the embedded implementations are declared static and not available outside of Dear ImGui sources files.
|
||||
//#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h"
|
||||
//#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h"
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if enabled
|
||||
//#define IMGUI_STB_SPRINTF_FILENAME "my_folder/stb_sprintf.h" // only used if IMGUI_USE_STB_SPRINTF is defined.
|
||||
//#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
||||
//#define IMGUI_DISABLE_STB_SPRINTF_IMPLEMENTATION // only disabled if IMGUI_USE_STB_SPRINTF is defined.
|
||||
|
||||
//---- Use stb_sprintf.h for a faster implementation of vsnprintf instead of the one from libc (unless IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS is defined)
|
||||
// Compatibility checks of arguments and formats done by clang and GCC will be disabled in order to support the extra formats provided by stb_sprintf.h.
|
||||
@@ -78,6 +86,15 @@
|
||||
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
|
||||
//#define IMGUI_ENABLE_FREETYPE
|
||||
|
||||
//---- Use FreeType + plutosvg or lunasvg to render OpenType SVG fonts (SVGinOT)
|
||||
// Only works in combination with IMGUI_ENABLE_FREETYPE.
|
||||
// - lunasvg is currently easier to acquire/install, as e.g. it is part of vcpkg.
|
||||
// - plutosvg will support more fonts and may load them faster. It currently requires to be built manually but it is fairly easy. See misc/freetype/README for instructions.
|
||||
// - Both require headers to be available in the include path + program to be linked with the library code (not provided).
|
||||
// - (note: lunasvg implementation is based on Freetype's rsvg-port.c which is licensed under CeCILL-C Free Software License Agreement)
|
||||
//#define IMGUI_ENABLE_FREETYPE_PLUTOSVG
|
||||
//#define IMGUI_ENABLE_FREETYPE_LUNASVG
|
||||
|
||||
//---- Use stb_truetype to build and rasterize the font atlas (default)
|
||||
// The only purpose of this define is if you want force compilation of the stb_truetype backend ALONG with the FreeType backend.
|
||||
//#define IMGUI_ENABLE_STB_TRUETYPE
|
||||
@@ -108,7 +125,7 @@
|
||||
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
|
||||
//#define ImDrawCallback MyImDrawCallback
|
||||
|
||||
//---- Debug Tools: Macro to break in Debugger
|
||||
//---- Debug Tools: Macro to break in Debugger (we provide a default implementation of this in the codebase)
|
||||
// (use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.)
|
||||
//#define IM_DEBUG_BREAK IM_ASSERT(0)
|
||||
//#define IM_DEBUG_BREAK __debugbreak()
|
||||
@@ -116,10 +133,10 @@
|
||||
//---- Debug Tools: Enable slower asserts
|
||||
//#define IMGUI_DEBUG_PARANOID
|
||||
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
|
||||
//---- Tip: You can add extra functions within the ImGui:: namespace from anywhere (e.g. your own sources/header files)
|
||||
/*
|
||||
namespace ImGui
|
||||
{
|
||||
void MyFunction(const char* name, const MyMatrix44& v);
|
||||
void MyFunction(const char* name, MyMatrix44* mtx);
|
||||
}
|
||||
*/
|
||||
|
||||
Vendored
+4650
-2300
File diff suppressed because it is too large
Load Diff
Vendored
+1497
-902
File diff suppressed because it is too large
Load Diff
Vendored
+3015
-663
File diff suppressed because it is too large
Load Diff
Vendored
+621
-129
File diff suppressed because it is too large
Load Diff
Vendored
+938
-658
File diff suppressed because it is too large
Load Diff
Vendored
+584
-235
File diff suppressed because it is too large
Load Diff
Vendored
+2536
-870
File diff suppressed because it is too large
Load Diff
Vendored
+139
-107
@@ -2,8 +2,11 @@
|
||||
// This is a slightly modified version of stb_textedit.h 1.14.
|
||||
// Those changes would need to be pushed into nothings/stb:
|
||||
// - Fix in stb_textedit_discard_redo (see https://github.com/nothings/stb/issues/321)
|
||||
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000)
|
||||
// - Fix in stb_textedit_find_charpos to handle last line (see https://github.com/ocornut/imgui/issues/6000 + #6783)
|
||||
// - Added name to struct or it may be forward declared in our code.
|
||||
// - Added UTF-8 support (see https://github.com/nothings/stb/issues/188 + https://github.com/ocornut/imgui/pull/7925)
|
||||
// Grep for [DEAR IMGUI] to find the changes.
|
||||
// - Also renamed macros used or defined outside of IMSTB_TEXTEDIT_IMPLEMENTATION block from STB_TEXTEDIT_* to IMSTB_TEXTEDIT_*
|
||||
|
||||
// stb_textedit.h - v1.14 - public domain - Sean Barrett
|
||||
// Development of this library was sponsored by RAD Game Tools
|
||||
@@ -30,7 +33,7 @@
|
||||
// DEPENDENCIES
|
||||
//
|
||||
// Uses the C runtime function 'memmove', which you can override
|
||||
// by defining STB_TEXTEDIT_memmove before the implementation.
|
||||
// by defining IMSTB_TEXTEDIT_memmove before the implementation.
|
||||
// Uses no other functions. Performs no runtime allocations.
|
||||
//
|
||||
//
|
||||
@@ -40,7 +43,7 @@
|
||||
// 1.13 (2019-02-07) fix bug in undo size management
|
||||
// 1.12 (2018-01-29) user can change STB_TEXTEDIT_KEYTYPE, fix redo to avoid crash
|
||||
// 1.11 (2017-03-03) fix HOME on last line, dragging off single-line textfield
|
||||
// 1.10 (2016-10-25) supress warnings about casting away const with -Wcast-qual
|
||||
// 1.10 (2016-10-25) suppress warnings about casting away const with -Wcast-qual
|
||||
// 1.9 (2016-08-27) customizable move-by-word
|
||||
// 1.8 (2016-04-02) better keyboard handling when mouse button is down
|
||||
// 1.7 (2015-09-13) change y range handling in case baseline is non-0
|
||||
@@ -208,6 +211,7 @@
|
||||
// int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
// int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
|
||||
// void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXEDIT_KEYTYPE key)
|
||||
// void stb_textedit_text(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int text_len)
|
||||
//
|
||||
// Each of these functions potentially updates the string and updates the
|
||||
// state.
|
||||
@@ -242,7 +246,12 @@
|
||||
// various definitions like STB_TEXTEDIT_K_LEFT have the is-key-event bit
|
||||
// set, and make STB_TEXTEDIT_KEYTOCHAR check that the is-key-event bit is
|
||||
// clear. STB_TEXTEDIT_KEYTYPE defaults to int, but you can #define it to
|
||||
// anything other type you wante before including.
|
||||
// anything other type you want before including.
|
||||
// if the STB_TEXTEDIT_KEYTOTEXT function is defined, selected keys are
|
||||
// transformed into text and stb_textedit_text() is automatically called.
|
||||
//
|
||||
// text: [DEAR IMGUI] added 2024-09
|
||||
// call this to text inputs sent to the textfield.
|
||||
//
|
||||
//
|
||||
// When rendering, you can read the cursor position and selection state from
|
||||
@@ -274,8 +283,8 @@
|
||||
////
|
||||
////
|
||||
|
||||
#ifndef INCLUDE_STB_TEXTEDIT_H
|
||||
#define INCLUDE_STB_TEXTEDIT_H
|
||||
#ifndef INCLUDE_IMSTB_TEXTEDIT_H
|
||||
#define INCLUDE_IMSTB_TEXTEDIT_H
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -286,38 +295,38 @@
|
||||
// and undo state.
|
||||
//
|
||||
|
||||
#ifndef STB_TEXTEDIT_UNDOSTATECOUNT
|
||||
#define STB_TEXTEDIT_UNDOSTATECOUNT 99
|
||||
#ifndef IMSTB_TEXTEDIT_UNDOSTATECOUNT
|
||||
#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99
|
||||
#endif
|
||||
#ifndef STB_TEXTEDIT_UNDOCHARCOUNT
|
||||
#define STB_TEXTEDIT_UNDOCHARCOUNT 999
|
||||
#ifndef IMSTB_TEXTEDIT_UNDOCHARCOUNT
|
||||
#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999
|
||||
#endif
|
||||
#ifndef STB_TEXTEDIT_CHARTYPE
|
||||
#define STB_TEXTEDIT_CHARTYPE int
|
||||
#ifndef IMSTB_TEXTEDIT_CHARTYPE
|
||||
#define IMSTB_TEXTEDIT_CHARTYPE int
|
||||
#endif
|
||||
#ifndef STB_TEXTEDIT_POSITIONTYPE
|
||||
#define STB_TEXTEDIT_POSITIONTYPE int
|
||||
#ifndef IMSTB_TEXTEDIT_POSITIONTYPE
|
||||
#define IMSTB_TEXTEDIT_POSITIONTYPE int
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// private data
|
||||
STB_TEXTEDIT_POSITIONTYPE where;
|
||||
STB_TEXTEDIT_POSITIONTYPE insert_length;
|
||||
STB_TEXTEDIT_POSITIONTYPE delete_length;
|
||||
IMSTB_TEXTEDIT_POSITIONTYPE where;
|
||||
IMSTB_TEXTEDIT_POSITIONTYPE insert_length;
|
||||
IMSTB_TEXTEDIT_POSITIONTYPE delete_length;
|
||||
int char_storage;
|
||||
} StbUndoRecord;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
// private data
|
||||
StbUndoRecord undo_rec [STB_TEXTEDIT_UNDOSTATECOUNT];
|
||||
STB_TEXTEDIT_CHARTYPE undo_char[STB_TEXTEDIT_UNDOCHARCOUNT];
|
||||
StbUndoRecord undo_rec [IMSTB_TEXTEDIT_UNDOSTATECOUNT];
|
||||
IMSTB_TEXTEDIT_CHARTYPE undo_char[IMSTB_TEXTEDIT_UNDOCHARCOUNT];
|
||||
short undo_point, redo_point;
|
||||
int undo_char_point, redo_char_point;
|
||||
} StbUndoState;
|
||||
|
||||
typedef struct
|
||||
typedef struct STB_TexteditState
|
||||
{
|
||||
/////////////////////
|
||||
//
|
||||
@@ -371,7 +380,7 @@ typedef struct
|
||||
float ymin,ymax; // height of row above and below baseline
|
||||
int num_chars;
|
||||
} StbTexteditRow;
|
||||
#endif //INCLUDE_STB_TEXTEDIT_H
|
||||
#endif //INCLUDE_IMSTB_TEXTEDIT_H
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -384,11 +393,11 @@ typedef struct
|
||||
|
||||
// implementation isn't include-guarded, since it might have indirectly
|
||||
// included just the "header" portion
|
||||
#ifdef STB_TEXTEDIT_IMPLEMENTATION
|
||||
#ifdef IMSTB_TEXTEDIT_IMPLEMENTATION
|
||||
|
||||
#ifndef STB_TEXTEDIT_memmove
|
||||
#ifndef IMSTB_TEXTEDIT_memmove
|
||||
#include <string.h>
|
||||
#define STB_TEXTEDIT_memmove memmove
|
||||
#define IMSTB_TEXTEDIT_memmove memmove
|
||||
#endif
|
||||
|
||||
|
||||
@@ -398,7 +407,7 @@ typedef struct
|
||||
//
|
||||
|
||||
// traverse the layout to locate the nearest character to a display position
|
||||
static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
||||
static int stb_text_locate_coord(IMSTB_TEXTEDIT_STRING *str, float x, float y)
|
||||
{
|
||||
StbTexteditRow r;
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
@@ -437,13 +446,13 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
||||
if (x < r.x1) {
|
||||
// search characters in row for one that straddles 'x'
|
||||
prev_x = r.x0;
|
||||
for (k=0; k < r.num_chars; ++k) {
|
||||
for (k=0; k < r.num_chars; k = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k) - i) {
|
||||
float w = STB_TEXTEDIT_GETWIDTH(str, i, k);
|
||||
if (x < prev_x+w) {
|
||||
if (x < prev_x+w/2)
|
||||
return k+i;
|
||||
else
|
||||
return k+i+1;
|
||||
return IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, i + k);
|
||||
}
|
||||
prev_x += w;
|
||||
}
|
||||
@@ -458,7 +467,7 @@ static int stb_text_locate_coord(STB_TEXTEDIT_STRING *str, float x, float y)
|
||||
}
|
||||
|
||||
// API click: on mouse down, move the cursor to the clicked location, and reset the selection
|
||||
static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
static void stb_textedit_click(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
{
|
||||
// In single-line mode, just always make y = 0. This lets the drag keep working if the mouse
|
||||
// goes off the top or bottom of the text
|
||||
@@ -476,7 +485,7 @@ static void stb_textedit_click(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
||||
}
|
||||
|
||||
// API drag: on mouse drag, move the cursor and selection endpoint to the clicked location
|
||||
static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
static void stb_textedit_drag(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, float x, float y)
|
||||
{
|
||||
int p = 0;
|
||||
|
||||
@@ -502,11 +511,11 @@ static void stb_textedit_drag(STB_TEXTEDIT_STRING *str, STB_TexteditState *state
|
||||
//
|
||||
|
||||
// forward declarations
|
||||
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state);
|
||||
static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int length);
|
||||
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
|
||||
static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@@ -518,7 +527,7 @@ typedef struct
|
||||
|
||||
// find the x/y location of a character, and remember info about the previous row in
|
||||
// case we get a move-up event (for page up, we'll have to rescan)
|
||||
static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *str, int n, int single_line)
|
||||
static void stb_textedit_find_charpos(StbFindState *find, IMSTB_TEXTEDIT_STRING *str, int n, int single_line)
|
||||
{
|
||||
StbTexteditRow r;
|
||||
int prev_start = 0;
|
||||
@@ -549,7 +558,10 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
|
||||
i += r.num_chars;
|
||||
find->y += r.baseline_y_delta;
|
||||
if (i == z) // [DEAR IMGUI]
|
||||
{
|
||||
r.num_chars = 0; // [DEAR IMGUI]
|
||||
break; // [DEAR IMGUI]
|
||||
}
|
||||
}
|
||||
|
||||
find->first_char = first = i;
|
||||
@@ -559,14 +571,14 @@ static void stb_textedit_find_charpos(StbFindState *find, STB_TEXTEDIT_STRING *s
|
||||
|
||||
// now scan to find xpos
|
||||
find->x = r.x0;
|
||||
for (i=0; first+i < n; ++i)
|
||||
for (i=0; first+i < n; i = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, first + i) - first)
|
||||
find->x += STB_TEXTEDIT_GETWIDTH(str, first, i);
|
||||
}
|
||||
|
||||
#define STB_TEXT_HAS_SELECTION(s) ((s)->select_start != (s)->select_end)
|
||||
|
||||
// make the selection/cursor state valid if client altered the string
|
||||
static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_textedit_clamp(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||
@@ -580,7 +592,7 @@ static void stb_textedit_clamp(STB_TEXTEDIT_STRING *str, STB_TexteditState *stat
|
||||
}
|
||||
|
||||
// delete characters while updating undo
|
||||
static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
|
||||
static void stb_textedit_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int len)
|
||||
{
|
||||
stb_text_makeundo_delete(str, state, where, len);
|
||||
STB_TEXTEDIT_DELETECHARS(str, where, len);
|
||||
@@ -588,7 +600,7 @@ static void stb_textedit_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *sta
|
||||
}
|
||||
|
||||
// delete the section
|
||||
static void stb_textedit_delete_selection(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_textedit_delete_selection(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
stb_textedit_clamp(str, state);
|
||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||
@@ -625,7 +637,7 @@ static void stb_textedit_move_to_first(STB_TexteditState *state)
|
||||
}
|
||||
|
||||
// move cursor to last character of selection
|
||||
static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_textedit_move_to_last(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||
stb_textedit_sortselection(state);
|
||||
@@ -636,14 +648,25 @@ static void stb_textedit_move_to_last(STB_TEXTEDIT_STRING *str, STB_TexteditStat
|
||||
}
|
||||
}
|
||||
|
||||
// [DEAR IMGUI]
|
||||
// Functions must be implemented for UTF8 support
|
||||
// Code in this file that uses those functions is modified for [DEAR IMGUI] and deviates from the original stb_textedit.
|
||||
// There is not necessarily a '[DEAR IMGUI]' at the usage sites.
|
||||
#ifndef IMSTB_TEXTEDIT_GETPREVCHARINDEX
|
||||
#define IMSTB_TEXTEDIT_GETPREVCHARINDEX(obj, idx) (idx - 1)
|
||||
#endif
|
||||
#ifndef IMSTB_TEXTEDIT_GETNEXTCHARINDEX
|
||||
#define IMSTB_TEXTEDIT_GETNEXTCHARINDEX(obj, idx) (idx + 1)
|
||||
#endif
|
||||
|
||||
#ifdef STB_TEXTEDIT_IS_SPACE
|
||||
static int is_word_boundary( STB_TEXTEDIT_STRING *str, int idx )
|
||||
static int is_word_boundary( IMSTB_TEXTEDIT_STRING *str, int idx )
|
||||
{
|
||||
return idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str,idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(str, idx) ) ) : 1;
|
||||
}
|
||||
|
||||
#ifndef STB_TEXTEDIT_MOVEWORDLEFT
|
||||
static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
|
||||
static int stb_textedit_move_to_word_previous( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||
{
|
||||
--c; // always move at least one character
|
||||
while( c >= 0 && !is_word_boundary( str, c ) )
|
||||
@@ -658,7 +681,7 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *str, int c )
|
||||
#endif
|
||||
|
||||
#ifndef STB_TEXTEDIT_MOVEWORDRIGHT
|
||||
static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *str, int c )
|
||||
static int stb_textedit_move_to_word_next( IMSTB_TEXTEDIT_STRING *str, int c )
|
||||
{
|
||||
const int len = STB_TEXTEDIT_STRINGLEN(str);
|
||||
++c; // always move at least one character
|
||||
@@ -685,7 +708,7 @@ static void stb_textedit_prep_selection_at_cursor(STB_TexteditState *state)
|
||||
}
|
||||
|
||||
// API cut: delete selection
|
||||
static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static int stb_textedit_cut(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
if (STB_TEXT_HAS_SELECTION(state)) {
|
||||
stb_textedit_delete_selection(str,state); // implicitly clamps
|
||||
@@ -696,7 +719,7 @@ static int stb_textedit_cut(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
}
|
||||
|
||||
// API paste: replace existing selection with passed-in text
|
||||
static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE *text, int len)
|
||||
static int stb_textedit_paste_internal(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE *text, int len)
|
||||
{
|
||||
// if there's a selection, the paste should delete it
|
||||
stb_textedit_clamp(str, state);
|
||||
@@ -716,36 +739,44 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta
|
||||
#define STB_TEXTEDIT_KEYTYPE int
|
||||
#endif
|
||||
|
||||
// [DEAR IMGUI] Added stb_textedit_text(), extracted out and called by stb_textedit_key() for backward compatibility.
|
||||
static void stb_textedit_text(IMSTB_TEXTEDIT_STRING* str, STB_TexteditState* state, const IMSTB_TEXTEDIT_CHARTYPE* text, int text_len)
|
||||
{
|
||||
// can't add newline in single-line mode
|
||||
if (text[0] == '\n' && state->single_line)
|
||||
return;
|
||||
|
||||
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
|
||||
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
|
||||
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
||||
state->cursor += text_len;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
stb_textedit_delete_selection(str, state); // implicitly clamps
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, text, text_len)) {
|
||||
stb_text_makeundo_insert(state, state->cursor, text_len);
|
||||
state->cursor += text_len;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// API key: process a keyboard input
|
||||
static void stb_textedit_key(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
|
||||
static void stb_textedit_key(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_KEYTYPE key)
|
||||
{
|
||||
retry:
|
||||
switch (key) {
|
||||
default: {
|
||||
#ifdef STB_TEXTEDIT_KEYTOTEXT
|
||||
int c = STB_TEXTEDIT_KEYTOTEXT(key);
|
||||
if (c > 0) {
|
||||
STB_TEXTEDIT_CHARTYPE ch = (STB_TEXTEDIT_CHARTYPE) c;
|
||||
|
||||
// can't add newline in single-line mode
|
||||
if (c == '\n' && state->single_line)
|
||||
break;
|
||||
|
||||
if (state->insert_mode && !STB_TEXT_HAS_SELECTION(state) && state->cursor < STB_TEXTEDIT_STRINGLEN(str)) {
|
||||
stb_text_makeundo_replace(str, state, state->cursor, 1, 1);
|
||||
STB_TEXTEDIT_DELETECHARS(str, state->cursor, 1);
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
|
||||
++state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
} else {
|
||||
stb_textedit_delete_selection(str,state); // implicitly clamps
|
||||
if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) {
|
||||
stb_text_makeundo_insert(state, state->cursor, 1);
|
||||
++state->cursor;
|
||||
state->has_preferred_x = 0;
|
||||
}
|
||||
}
|
||||
IMSTB_TEXTEDIT_CHARTYPE ch = (IMSTB_TEXTEDIT_CHARTYPE)c;
|
||||
stb_textedit_text(str, state, &ch, 1);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -771,7 +802,7 @@ retry:
|
||||
stb_textedit_move_to_first(state);
|
||||
else
|
||||
if (state->cursor > 0)
|
||||
--state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
|
||||
@@ -780,7 +811,7 @@ retry:
|
||||
if (STB_TEXT_HAS_SELECTION(state))
|
||||
stb_textedit_move_to_last(str, state);
|
||||
else
|
||||
++state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||
stb_textedit_clamp(str, state);
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
@@ -790,7 +821,7 @@ retry:
|
||||
stb_textedit_prep_selection_at_cursor(state);
|
||||
// move selection left
|
||||
if (state->select_end > 0)
|
||||
--state->select_end;
|
||||
state->select_end = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->select_end);
|
||||
state->cursor = state->select_end;
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
@@ -840,7 +871,7 @@ retry:
|
||||
case STB_TEXTEDIT_K_RIGHT | STB_TEXTEDIT_K_SHIFT:
|
||||
stb_textedit_prep_selection_at_cursor(state);
|
||||
// move selection right
|
||||
++state->select_end;
|
||||
state->select_end = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->select_end);
|
||||
stb_textedit_clamp(str, state);
|
||||
state->cursor = state->select_end;
|
||||
state->has_preferred_x = 0;
|
||||
@@ -889,14 +920,14 @@ retry:
|
||||
x = row.x0;
|
||||
for (i=0; i < row.num_chars; ++i) {
|
||||
float dx = STB_TEXTEDIT_GETWIDTH(str, start, i);
|
||||
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
break;
|
||||
#endif
|
||||
x += dx;
|
||||
if (x > goal_x)
|
||||
break;
|
||||
++state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||
}
|
||||
stb_textedit_clamp(str, state);
|
||||
|
||||
@@ -951,14 +982,14 @@ retry:
|
||||
x = row.x0;
|
||||
for (i=0; i < row.num_chars; ++i) {
|
||||
float dx = STB_TEXTEDIT_GETWIDTH(str, find.prev_first, i);
|
||||
#ifdef STB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == STB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
#ifdef IMSTB_TEXTEDIT_GETWIDTH_NEWLINE
|
||||
if (dx == IMSTB_TEXTEDIT_GETWIDTH_NEWLINE)
|
||||
break;
|
||||
#endif
|
||||
x += dx;
|
||||
if (x > goal_x)
|
||||
break;
|
||||
++state->cursor;
|
||||
state->cursor = IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor);
|
||||
}
|
||||
stb_textedit_clamp(str, state);
|
||||
|
||||
@@ -986,7 +1017,7 @@ retry:
|
||||
else {
|
||||
int n = STB_TEXTEDIT_STRINGLEN(str);
|
||||
if (state->cursor < n)
|
||||
stb_textedit_delete(str, state, state->cursor, 1);
|
||||
stb_textedit_delete(str, state, state->cursor, IMSTB_TEXTEDIT_GETNEXTCHARINDEX(str, state->cursor) - state->cursor);
|
||||
}
|
||||
state->has_preferred_x = 0;
|
||||
break;
|
||||
@@ -998,8 +1029,9 @@ retry:
|
||||
else {
|
||||
stb_textedit_clamp(str, state);
|
||||
if (state->cursor > 0) {
|
||||
stb_textedit_delete(str, state, state->cursor-1, 1);
|
||||
--state->cursor;
|
||||
int prev = IMSTB_TEXTEDIT_GETPREVCHARINDEX(str, state->cursor);
|
||||
stb_textedit_delete(str, state, prev, state->cursor - prev);
|
||||
state->cursor = prev;
|
||||
}
|
||||
}
|
||||
state->has_preferred_x = 0;
|
||||
@@ -1109,8 +1141,8 @@ retry:
|
||||
|
||||
static void stb_textedit_flush_redo(StbUndoState *state)
|
||||
{
|
||||
state->redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
|
||||
state->redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
|
||||
state->redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
|
||||
state->redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
|
||||
}
|
||||
|
||||
// discard the oldest entry in the undo list
|
||||
@@ -1122,13 +1154,13 @@ static void stb_textedit_discard_undo(StbUndoState *state)
|
||||
int n = state->undo_rec[0].insert_length, i;
|
||||
// delete n characters from all other records
|
||||
state->undo_char_point -= n;
|
||||
STB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(STB_TEXTEDIT_CHARTYPE)));
|
||||
IMSTB_TEXTEDIT_memmove(state->undo_char, state->undo_char + n, (size_t) (state->undo_char_point*sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
|
||||
for (i=0; i < state->undo_point; ++i)
|
||||
if (state->undo_rec[i].char_storage >= 0)
|
||||
state->undo_rec[i].char_storage -= n; // @OPTIMIZE: get rid of char_storage and infer it
|
||||
}
|
||||
--state->undo_point;
|
||||
STB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
|
||||
IMSTB_TEXTEDIT_memmove(state->undo_rec, state->undo_rec+1, (size_t) (state->undo_point*sizeof(state->undo_rec[0])));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1138,7 +1170,7 @@ static void stb_textedit_discard_undo(StbUndoState *state)
|
||||
// fill up even though the undo buffer didn't
|
||||
static void stb_textedit_discard_redo(StbUndoState *state)
|
||||
{
|
||||
int k = STB_TEXTEDIT_UNDOSTATECOUNT-1;
|
||||
int k = IMSTB_TEXTEDIT_UNDOSTATECOUNT-1;
|
||||
|
||||
if (state->redo_point <= k) {
|
||||
// if the k'th undo state has characters, clean those up
|
||||
@@ -1146,7 +1178,7 @@ static void stb_textedit_discard_redo(StbUndoState *state)
|
||||
int n = state->undo_rec[k].insert_length, i;
|
||||
// move the remaining redo character data to the end of the buffer
|
||||
state->redo_char_point += n;
|
||||
STB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((STB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(STB_TEXTEDIT_CHARTYPE)));
|
||||
IMSTB_TEXTEDIT_memmove(state->undo_char + state->redo_char_point, state->undo_char + state->redo_char_point-n, (size_t) ((IMSTB_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point)*sizeof(IMSTB_TEXTEDIT_CHARTYPE)));
|
||||
// adjust the position of all the other records to account for above memmove
|
||||
for (i=state->redo_point; i < k; ++i)
|
||||
if (state->undo_rec[i].char_storage >= 0)
|
||||
@@ -1154,12 +1186,12 @@ static void stb_textedit_discard_redo(StbUndoState *state)
|
||||
}
|
||||
// now move all the redo records towards the end of the buffer; the first one is at 'redo_point'
|
||||
// [DEAR IMGUI]
|
||||
size_t move_size = (size_t)((STB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
|
||||
size_t move_size = (size_t)((IMSTB_TEXTEDIT_UNDOSTATECOUNT - state->redo_point - 1) * sizeof(state->undo_rec[0]));
|
||||
const char* buf_begin = (char*)state->undo_rec; (void)buf_begin;
|
||||
const char* buf_end = (char*)state->undo_rec + sizeof(state->undo_rec); (void)buf_end;
|
||||
IM_ASSERT(((char*)(state->undo_rec + state->redo_point)) >= buf_begin);
|
||||
IM_ASSERT(((char*)(state->undo_rec + state->redo_point + 1) + move_size) <= buf_end);
|
||||
STB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
|
||||
IMSTB_TEXTEDIT_memmove(state->undo_rec + state->redo_point+1, state->undo_rec + state->redo_point, move_size);
|
||||
|
||||
// now move redo_point to point to the new one
|
||||
++state->redo_point;
|
||||
@@ -1173,32 +1205,32 @@ static StbUndoRecord *stb_text_create_undo_record(StbUndoState *state, int numch
|
||||
|
||||
// if we have no free records, we have to make room, by sliding the
|
||||
// existing records down
|
||||
if (state->undo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
if (state->undo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
stb_textedit_discard_undo(state);
|
||||
|
||||
// if the characters to store won't possibly fit in the buffer, we can't undo
|
||||
if (numchars > STB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||
if (numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||
state->undo_point = 0;
|
||||
state->undo_char_point = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if we don't have enough free characters in the buffer, we have to make room
|
||||
while (state->undo_char_point + numchars > STB_TEXTEDIT_UNDOCHARCOUNT)
|
||||
while (state->undo_char_point + numchars > IMSTB_TEXTEDIT_UNDOCHARCOUNT)
|
||||
stb_textedit_discard_undo(state);
|
||||
|
||||
return &state->undo_rec[state->undo_point++];
|
||||
}
|
||||
|
||||
static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
|
||||
static IMSTB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos, int insert_len, int delete_len)
|
||||
{
|
||||
StbUndoRecord *r = stb_text_create_undo_record(state, insert_len);
|
||||
if (r == NULL)
|
||||
return NULL;
|
||||
|
||||
r->where = pos;
|
||||
r->insert_length = (STB_TEXTEDIT_POSITIONTYPE) insert_len;
|
||||
r->delete_length = (STB_TEXTEDIT_POSITIONTYPE) delete_len;
|
||||
r->insert_length = (IMSTB_TEXTEDIT_POSITIONTYPE) insert_len;
|
||||
r->delete_length = (IMSTB_TEXTEDIT_POSITIONTYPE) delete_len;
|
||||
|
||||
if (insert_len == 0) {
|
||||
r->char_storage = -1;
|
||||
@@ -1210,7 +1242,7 @@ static STB_TEXTEDIT_CHARTYPE *stb_text_createundo(StbUndoState *state, int pos,
|
||||
}
|
||||
}
|
||||
|
||||
static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_text_undo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
StbUndoState *s = &state->undostate;
|
||||
StbUndoRecord u, *r;
|
||||
@@ -1237,7 +1269,7 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
// characters stored for *undoing* don't leave room for redo
|
||||
// if the last is true, we have to bail
|
||||
|
||||
if (s->undo_char_point + u.delete_length >= STB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||
if (s->undo_char_point + u.delete_length >= IMSTB_TEXTEDIT_UNDOCHARCOUNT) {
|
||||
// the undo records take up too much character space; there's no space to store the redo characters
|
||||
r->insert_length = 0;
|
||||
} else {
|
||||
@@ -1246,7 +1278,7 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
// there's definitely room to store the characters eventually
|
||||
while (s->undo_char_point + u.delete_length > s->redo_char_point) {
|
||||
// should never happen:
|
||||
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
return;
|
||||
// there's currently not enough room, so discard a redo record
|
||||
stb_textedit_discard_redo(s);
|
||||
@@ -1278,11 +1310,11 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
s->redo_point--;
|
||||
}
|
||||
|
||||
static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
static void stb_text_redo(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state)
|
||||
{
|
||||
StbUndoState *s = &state->undostate;
|
||||
StbUndoRecord *u, r;
|
||||
if (s->redo_point == STB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
if (s->redo_point == IMSTB_TEXTEDIT_UNDOSTATECOUNT)
|
||||
return;
|
||||
|
||||
// we need to do two things: apply the redo record, and create an undo record
|
||||
@@ -1334,20 +1366,20 @@ static void stb_text_makeundo_insert(STB_TexteditState *state, int where, int le
|
||||
stb_text_createundo(&state->undostate, where, 0, length);
|
||||
}
|
||||
|
||||
static void stb_text_makeundo_delete(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
|
||||
static void stb_text_makeundo_delete(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int length)
|
||||
{
|
||||
int i;
|
||||
STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
|
||||
IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, length, 0);
|
||||
if (p) {
|
||||
for (i=0; i < length; ++i)
|
||||
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
|
||||
}
|
||||
}
|
||||
|
||||
static void stb_text_makeundo_replace(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
|
||||
static void stb_text_makeundo_replace(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, int where, int old_length, int new_length)
|
||||
{
|
||||
int i;
|
||||
STB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
|
||||
IMSTB_TEXTEDIT_CHARTYPE *p = stb_text_createundo(&state->undostate, where, old_length, new_length);
|
||||
if (p) {
|
||||
for (i=0; i < old_length; ++i)
|
||||
p[i] = STB_TEXTEDIT_GETCHAR(str, where+i);
|
||||
@@ -1359,8 +1391,8 @@ static void stb_textedit_clear_state(STB_TexteditState *state, int is_single_lin
|
||||
{
|
||||
state->undostate.undo_point = 0;
|
||||
state->undostate.undo_char_point = 0;
|
||||
state->undostate.redo_point = STB_TEXTEDIT_UNDOSTATECOUNT;
|
||||
state->undostate.redo_char_point = STB_TEXTEDIT_UNDOCHARCOUNT;
|
||||
state->undostate.redo_point = IMSTB_TEXTEDIT_UNDOSTATECOUNT;
|
||||
state->undostate.redo_char_point = IMSTB_TEXTEDIT_UNDOCHARCOUNT;
|
||||
state->select_end = state->select_start = 0;
|
||||
state->cursor = 0;
|
||||
state->has_preferred_x = 0;
|
||||
@@ -1383,16 +1415,16 @@ static void stb_textedit_initialize_state(STB_TexteditState *state, int is_singl
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
|
||||
static int stb_textedit_paste(STB_TEXTEDIT_STRING *str, STB_TexteditState *state, STB_TEXTEDIT_CHARTYPE const *ctext, int len)
|
||||
static int stb_textedit_paste(IMSTB_TEXTEDIT_STRING *str, STB_TexteditState *state, IMSTB_TEXTEDIT_CHARTYPE const *ctext, int len)
|
||||
{
|
||||
return stb_textedit_paste_internal(str, state, (STB_TEXTEDIT_CHARTYPE *) ctext, len);
|
||||
return stb_textedit_paste_internal(str, state, (IMSTB_TEXTEDIT_CHARTYPE *) ctext, len);
|
||||
}
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif//STB_TEXTEDIT_IMPLEMENTATION
|
||||
#endif//IMSTB_TEXTEDIT_IMPLEMENTATION
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
|
||||
Vendored
+1
-1
@@ -656,7 +656,7 @@ STBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h
|
||||
STBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);
|
||||
// If skip != 0, this tells stb_truetype to skip any codepoints for which
|
||||
// there is no corresponding glyph. If skip=0, which is the default, then
|
||||
// codepoints without a glyph recived the font's "missing character" glyph,
|
||||
// codepoints without a glyph received the font's "missing character" glyph,
|
||||
// typically an empty box by convention.
|
||||
|
||||
STBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, // same data as above
|
||||
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
|
||||
// This is also an example of how you may wrap your own similar types.
|
||||
|
||||
// Changelog:
|
||||
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
|
||||
|
||||
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
|
||||
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_stdlib.h"
|
||||
|
||||
// Clang warnings with -Weverything
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
|
||||
#endif
|
||||
|
||||
struct InputTextCallback_UserData
|
||||
{
|
||||
std::string* Str;
|
||||
ImGuiInputTextCallback ChainCallback;
|
||||
void* ChainCallbackUserData;
|
||||
};
|
||||
|
||||
static int InputTextCallback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData;
|
||||
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize)
|
||||
{
|
||||
// Resize string callback
|
||||
// If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want.
|
||||
std::string* str = user_data->Str;
|
||||
IM_ASSERT(data->Buf == str->c_str());
|
||||
str->resize(data->BufTextLen);
|
||||
data->Buf = (char*)str->c_str();
|
||||
}
|
||||
else if (user_data->ChainCallback)
|
||||
{
|
||||
// Forward to user callback, if any
|
||||
data->UserData = user_data->ChainCallbackUserData;
|
||||
return user_data->ChainCallback(data);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0);
|
||||
flags |= ImGuiInputTextFlags_CallbackResize;
|
||||
|
||||
InputTextCallback_UserData cb_user_data;
|
||||
cb_user_data.Str = str;
|
||||
cb_user_data.ChainCallback = callback;
|
||||
cb_user_data.ChainCallbackUserData = user_data;
|
||||
return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data);
|
||||
}
|
||||
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
// dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.)
|
||||
// This is also an example of how you may wrap your own similar types.
|
||||
|
||||
// Changelog:
|
||||
// - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string
|
||||
|
||||
// See more C++ related extension (fmt, RAII, syntaxis sugar) on Wiki:
|
||||
// https://github.com/ocornut/imgui/wiki/Useful-Extensions#cness
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
// ImGui::InputText() with std::string
|
||||
// Because text input needs dynamic resizing, we need to setup a callback to grow the capacity
|
||||
IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = nullptr, void* user_data = nullptr);
|
||||
}
|
||||
-643
@@ -1,643 +0,0 @@
|
||||
/** @file GuillotineBinPack.cpp
|
||||
@author Jukka Jylänki
|
||||
|
||||
@brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#include <utility>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <algorithm>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
|
||||
#include "GuillotineBinPack.h"
|
||||
|
||||
#pragma warning( disable : 4267 )
|
||||
|
||||
namespace rbp {
|
||||
|
||||
using namespace std;
|
||||
|
||||
GuillotineBinPack::GuillotineBinPack()
|
||||
:binWidth(0),
|
||||
binHeight(0)
|
||||
{
|
||||
}
|
||||
|
||||
GuillotineBinPack::GuillotineBinPack(int width, int height)
|
||||
{
|
||||
Init(width, height);
|
||||
}
|
||||
|
||||
void GuillotineBinPack::Init(int width, int height)
|
||||
{
|
||||
binWidth = width;
|
||||
binHeight = height;
|
||||
|
||||
#ifdef _DEBUG
|
||||
disjointRects.Clear();
|
||||
#endif
|
||||
|
||||
// Clear any memory of previously packed rectangles.
|
||||
usedRectangles.clear();
|
||||
|
||||
// We start with a single big free rectangle that spans the whole bin.
|
||||
Rect n;
|
||||
n.x = 0;
|
||||
n.y = 0;
|
||||
n.width = width;
|
||||
n.height = height;
|
||||
|
||||
freeRectangles.clear();
|
||||
freeRectangles.push_back(n);
|
||||
}
|
||||
|
||||
void GuillotineBinPack::Insert(std::vector<RectSize> &rects, bool merge,
|
||||
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
// Remember variables about the best packing choice we have made so far during the iteration process.
|
||||
int bestFreeRect = 0;
|
||||
int bestRect = 0;
|
||||
bool bestFlipped = false;
|
||||
|
||||
// Pack rectangles one at a time until we have cleared the rects array of all rectangles.
|
||||
// rects will get destroyed in the process.
|
||||
while(rects.size() > 0)
|
||||
{
|
||||
// Stores the penalty score of the best rectangle placement - bigger=worse, smaller=better.
|
||||
int bestScore = std::numeric_limits<int>::max();
|
||||
|
||||
for(size_t i = 0; i < freeRectangles.size(); ++i)
|
||||
{
|
||||
for(size_t j = 0; j < rects.size(); ++j)
|
||||
{
|
||||
// If this rectangle is a perfect match, we pick it instantly.
|
||||
if (rects[j].width == freeRectangles[i].width && rects[j].height == freeRectangles[i].height)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = false;
|
||||
bestScore = std::numeric_limits<int>::min();
|
||||
i = freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
|
||||
break;
|
||||
}
|
||||
// If flipping this rectangle is a perfect match, pick that then.
|
||||
/*else if (rects[j].height == freeRectangles[i].width && rects[j].width == freeRectangles[i].height)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = true;
|
||||
bestScore = std::numeric_limits<int>::min();
|
||||
i = freeRectangles.size(); // Force a jump out of the outer loop as well - we got an instant fit.
|
||||
break;
|
||||
}*/
|
||||
// Try if we can fit the rectangle upright.
|
||||
else if (rects[j].width <= freeRectangles[i].width && rects[j].height <= freeRectangles[i].height)
|
||||
{
|
||||
int score = ScoreByHeuristic(rects[j].width, rects[j].height, freeRectangles[i], rectChoice);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = false;
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
// If not, then perhaps flipping sideways will make it fit?
|
||||
/*else if (rects[j].height <= freeRectangles[i].width && rects[j].width <= freeRectangles[i].height)
|
||||
{
|
||||
int score = ScoreByHeuristic(rects[j].height, rects[j].width, freeRectangles[i], rectChoice);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestFreeRect = i;
|
||||
bestRect = j;
|
||||
bestFlipped = true;
|
||||
bestScore = score;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
// If we didn't manage to find any rectangle to pack, abort.
|
||||
if (bestScore == std::numeric_limits<int>::max())
|
||||
return;
|
||||
|
||||
// Otherwise, we're good to go and do the actual packing.
|
||||
Rect newNode;
|
||||
newNode.x = freeRectangles[bestFreeRect].x;
|
||||
newNode.y = freeRectangles[bestFreeRect].y;
|
||||
newNode.width = rects[bestRect].width;
|
||||
newNode.height = rects[bestRect].height;
|
||||
|
||||
if (bestFlipped)
|
||||
std::swap(newNode.width, newNode.height);
|
||||
|
||||
// Remove the free space we lost in the bin.
|
||||
SplitFreeRectByHeuristic(freeRectangles[bestFreeRect], newNode, splitMethod);
|
||||
freeRectangles.erase(freeRectangles.begin() + bestFreeRect);
|
||||
|
||||
// Remove the rectangle we just packed from the input list.
|
||||
rects.erase(rects.begin() + bestRect);
|
||||
|
||||
// Perform a Rectangle Merge step if desired.
|
||||
if (merge)
|
||||
MergeFreeList();
|
||||
|
||||
// Remember the new used rectangle.
|
||||
usedRectangles.push_back(newNode);
|
||||
|
||||
// Check that we're really producing correct packings here.
|
||||
debug_assert(disjointRects.Add(newNode) == true);
|
||||
}
|
||||
}
|
||||
|
||||
/// @return True if r fits inside freeRect (possibly rotated).
|
||||
bool Fits(const RectSize &r, const Rect &freeRect)
|
||||
{
|
||||
return (r.width <= freeRect.width && r.height <= freeRect.height) ||
|
||||
(r.height <= freeRect.width && r.width <= freeRect.height);
|
||||
}
|
||||
|
||||
/// @return True if r fits perfectly inside freeRect, i.e. the leftover area is 0.
|
||||
bool FitsPerfectly(const RectSize &r, const Rect &freeRect)
|
||||
{
|
||||
return (r.width == freeRect.width && r.height == freeRect.height) ||
|
||||
(r.height == freeRect.width && r.width == freeRect.height);
|
||||
}
|
||||
|
||||
/*
|
||||
// A helper function for GUILLOTINE-MAXFITTING. Counts how many rectangles fit into the given rectangle
|
||||
// after it has been split.
|
||||
void CountNumFitting(const Rect &freeRect, int width, int height, const std::vector<RectSize> &rects,
|
||||
int usedRectIndex, bool splitHorizontal, int &score1, int &score2)
|
||||
{
|
||||
const int w = freeRect.width - width;
|
||||
const int h = freeRect.height - height;
|
||||
|
||||
Rect bottom;
|
||||
bottom.x = freeRect.x;
|
||||
bottom.y = freeRect.y + height;
|
||||
bottom.height = h;
|
||||
|
||||
Rect right;
|
||||
right.x = freeRect.x + width;
|
||||
right.y = freeRect.y;
|
||||
right.width = w;
|
||||
|
||||
if (splitHorizontal)
|
||||
{
|
||||
bottom.width = freeRect.width;
|
||||
right.height = height;
|
||||
}
|
||||
else // Split vertically
|
||||
{
|
||||
bottom.width = width;
|
||||
right.height = freeRect.height;
|
||||
}
|
||||
|
||||
int fitBottom = 0;
|
||||
int fitRight = 0;
|
||||
for(size_t i = 0; i < rects.size(); ++i)
|
||||
if (i != usedRectIndex)
|
||||
{
|
||||
if (FitsPerfectly(rects[i], bottom))
|
||||
fitBottom |= 0x10000000;
|
||||
if (FitsPerfectly(rects[i], right))
|
||||
fitRight |= 0x10000000;
|
||||
|
||||
if (Fits(rects[i], bottom))
|
||||
++fitBottom;
|
||||
if (Fits(rects[i], right))
|
||||
++fitRight;
|
||||
}
|
||||
|
||||
score1 = min(fitBottom, fitRight);
|
||||
score2 = max(fitBottom, fitRight);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
|
||||
void GuillotineBinPack::InsertMaxFitting(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge,
|
||||
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
dst.clear();
|
||||
int bestRect = 0;
|
||||
bool bestFlipped = false;
|
||||
bool bestSplitHorizontal = false;
|
||||
|
||||
// Pick rectangles one at a time and pack the one that leaves the most choices still open.
|
||||
while(rects.size() > 0 && freeRectangles.size() > 0)
|
||||
{
|
||||
int bestScore1 = -1;
|
||||
int bestScore2 = -1;
|
||||
|
||||
///\todo Different sort predicates.
|
||||
clb::sort::QuickSort(&freeRectangles[0], freeRectangles.size(), CompareRectShortSide);
|
||||
|
||||
Rect &freeRect = freeRectangles[0];
|
||||
|
||||
for(size_t j = 0; j < rects.size(); ++j)
|
||||
{
|
||||
int score1;
|
||||
int score2;
|
||||
|
||||
if (rects[j].width == freeRect.width && rects[j].height == freeRect.height)
|
||||
{
|
||||
bestRect = j;
|
||||
bestFlipped = false;
|
||||
bestScore1 = bestScore2 = std::numeric_limits<int>::max();
|
||||
break;
|
||||
}
|
||||
else if (rects[j].width <= freeRect.width && rects[j].height <= freeRect.height)
|
||||
{
|
||||
CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, false, score1, score2);
|
||||
|
||||
if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
|
||||
{
|
||||
bestRect = j;
|
||||
bestScore1 = score1;
|
||||
bestScore2 = score2;
|
||||
bestFlipped = false;
|
||||
bestSplitHorizontal = false;
|
||||
}
|
||||
|
||||
CountNumFitting(freeRect, rects[j].width, rects[j].height, rects, j, true, score1, score2);
|
||||
|
||||
if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
|
||||
{
|
||||
bestRect = j;
|
||||
bestScore1 = score1;
|
||||
bestScore2 = score2;
|
||||
bestFlipped = false;
|
||||
bestSplitHorizontal = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (rects[j].height == freeRect.width && rects[j].width == freeRect.height)
|
||||
{
|
||||
bestRect = j;
|
||||
bestFlipped = true;
|
||||
bestScore1 = bestScore2 = std::numeric_limits<int>::max();
|
||||
break;
|
||||
}
|
||||
else if (rects[j].height <= freeRect.width && rects[j].width <= freeRect.height)
|
||||
{
|
||||
CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, false, score1, score2);
|
||||
|
||||
if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
|
||||
{
|
||||
bestRect = j;
|
||||
bestScore1 = score1;
|
||||
bestScore2 = score2;
|
||||
bestFlipped = true;
|
||||
bestSplitHorizontal = false;
|
||||
}
|
||||
|
||||
CountNumFitting(freeRect, rects[j].height, rects[j].width, rects, j, true, score1, score2);
|
||||
|
||||
if (score1 > bestScore1 || (score1 == bestScore1 && score2 > bestScore2))
|
||||
{
|
||||
bestRect = j;
|
||||
bestScore1 = score1;
|
||||
bestScore2 = score2;
|
||||
bestFlipped = true;
|
||||
bestSplitHorizontal = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestScore1 >= 0)
|
||||
{
|
||||
Rect newNode;
|
||||
newNode.x = freeRect.x;
|
||||
newNode.y = freeRect.y;
|
||||
newNode.width = rects[bestRect].width;
|
||||
newNode.height = rects[bestRect].height;
|
||||
if (bestFlipped)
|
||||
std::swap(newNode.width, newNode.height);
|
||||
|
||||
assert(disjointRects.Disjoint(newNode));
|
||||
SplitFreeRectAlongAxis(freeRect, newNode, bestSplitHorizontal);
|
||||
|
||||
rects.erase(rects.begin() + bestRect);
|
||||
|
||||
if (merge)
|
||||
MergeFreeList();
|
||||
|
||||
usedRectangles.push_back(newNode);
|
||||
#ifdef _DEBUG
|
||||
disjointRects.Add(newNode);
|
||||
#endif
|
||||
}
|
||||
|
||||
freeRectangles.erase(freeRectangles.begin());
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
Rect GuillotineBinPack::Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice,
|
||||
GuillotineSplitHeuristic splitMethod)
|
||||
{
|
||||
// Find where to put the new rectangle.
|
||||
int freeNodeIndex = 0;
|
||||
Rect newRect = FindPositionForNewNode(width, height, rectChoice, &freeNodeIndex);
|
||||
|
||||
// Abort if we didn't have enough space in the bin.
|
||||
if (newRect.height == 0)
|
||||
return newRect;
|
||||
|
||||
// Remove the space that was just consumed by the new rectangle.
|
||||
SplitFreeRectByHeuristic(freeRectangles[freeNodeIndex], newRect, splitMethod);
|
||||
freeRectangles.erase(freeRectangles.begin() + freeNodeIndex);
|
||||
|
||||
// Perform a Rectangle Merge step if desired.
|
||||
if (merge)
|
||||
MergeFreeList();
|
||||
|
||||
// Remember the new used rectangle.
|
||||
usedRectangles.push_back(newRect);
|
||||
|
||||
// Check that we're really producing correct packings here.
|
||||
debug_assert(disjointRects.Add(newRect) == true);
|
||||
|
||||
return newRect;
|
||||
}
|
||||
|
||||
/// Computes the ratio of used surface area to the total bin area.
|
||||
float GuillotineBinPack::Occupancy() const
|
||||
{
|
||||
///\todo The occupancy rate could be cached/tracked incrementally instead
|
||||
/// of looping through the list of packed rectangles here.
|
||||
unsigned long usedSurfaceArea = 0;
|
||||
for(size_t i = 0; i < usedRectangles.size(); ++i)
|
||||
usedSurfaceArea += usedRectangles[i].width * usedRectangles[i].height;
|
||||
|
||||
return (float)usedSurfaceArea / (binWidth * binHeight);
|
||||
}
|
||||
|
||||
/// Returns the heuristic score value for placing a rectangle of size width*height into freeRect. Does not try to rotate.
|
||||
int GuillotineBinPack::ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice)
|
||||
{
|
||||
switch(rectChoice)
|
||||
{
|
||||
case RectBestAreaFit: return ScoreBestAreaFit(width, height, freeRect);
|
||||
case RectBestShortSideFit: return ScoreBestShortSideFit(width, height, freeRect);
|
||||
case RectBestLongSideFit: return ScoreBestLongSideFit(width, height, freeRect);
|
||||
case RectWorstAreaFit: return ScoreWorstAreaFit(width, height, freeRect);
|
||||
case RectWorstShortSideFit: return ScoreWorstShortSideFit(width, height, freeRect);
|
||||
case RectWorstLongSideFit: return ScoreWorstLongSideFit(width, height, freeRect);
|
||||
default: assert(false); return std::numeric_limits<int>::max();
|
||||
}
|
||||
}
|
||||
|
||||
int GuillotineBinPack::ScoreBestAreaFit(int width, int height, const Rect &freeRect)
|
||||
{
|
||||
return freeRect.width * freeRect.height - width * height;
|
||||
}
|
||||
|
||||
int GuillotineBinPack::ScoreBestShortSideFit(int width, int height, const Rect &freeRect)
|
||||
{
|
||||
int leftoverHoriz = abs(freeRect.width - width);
|
||||
int leftoverVert = abs(freeRect.height - height);
|
||||
int leftover = min(leftoverHoriz, leftoverVert);
|
||||
return leftover;
|
||||
}
|
||||
|
||||
int GuillotineBinPack::ScoreBestLongSideFit(int width, int height, const Rect &freeRect)
|
||||
{
|
||||
int leftoverHoriz = abs(freeRect.width - width);
|
||||
int leftoverVert = abs(freeRect.height - height);
|
||||
int leftover = max(leftoverHoriz, leftoverVert);
|
||||
return leftover;
|
||||
}
|
||||
|
||||
int GuillotineBinPack::ScoreWorstAreaFit(int width, int height, const Rect &freeRect)
|
||||
{
|
||||
return -ScoreBestAreaFit(width, height, freeRect);
|
||||
}
|
||||
|
||||
int GuillotineBinPack::ScoreWorstShortSideFit(int width, int height, const Rect &freeRect)
|
||||
{
|
||||
return -ScoreBestShortSideFit(width, height, freeRect);
|
||||
}
|
||||
|
||||
int GuillotineBinPack::ScoreWorstLongSideFit(int width, int height, const Rect &freeRect)
|
||||
{
|
||||
return -ScoreBestLongSideFit(width, height, freeRect);
|
||||
}
|
||||
|
||||
Rect GuillotineBinPack::FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex)
|
||||
{
|
||||
Rect bestNode;
|
||||
memset(&bestNode, 0, sizeof(Rect));
|
||||
|
||||
int bestScore = std::numeric_limits<int>::max();
|
||||
|
||||
/// Try each free rectangle to find the best one for placement.
|
||||
for(size_t i = 0; i < freeRectangles.size(); ++i)
|
||||
{
|
||||
// If this is a perfect fit upright, choose it immediately.
|
||||
if (width == freeRectangles[i].width && height == freeRectangles[i].height)
|
||||
{
|
||||
bestNode.x = freeRectangles[i].x;
|
||||
bestNode.y = freeRectangles[i].y;
|
||||
bestNode.width = width;
|
||||
bestNode.height = height;
|
||||
bestScore = std::numeric_limits<int>::min();
|
||||
*nodeIndex = i;
|
||||
debug_assert(disjointRects.Disjoint(bestNode));
|
||||
break;
|
||||
}
|
||||
// If this is a perfect fit sideways, choose it.
|
||||
else if (height == freeRectangles[i].width && width == freeRectangles[i].height)
|
||||
{
|
||||
bestNode.x = freeRectangles[i].x;
|
||||
bestNode.y = freeRectangles[i].y;
|
||||
bestNode.width = height;
|
||||
bestNode.height = width;
|
||||
bestScore = std::numeric_limits<int>::min();
|
||||
*nodeIndex = i;
|
||||
debug_assert(disjointRects.Disjoint(bestNode));
|
||||
break;
|
||||
}
|
||||
// Does the rectangle fit upright?
|
||||
else if (width <= freeRectangles[i].width && height <= freeRectangles[i].height)
|
||||
{
|
||||
int score = ScoreByHeuristic(width, height, freeRectangles[i], rectChoice);
|
||||
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestNode.x = freeRectangles[i].x;
|
||||
bestNode.y = freeRectangles[i].y;
|
||||
bestNode.width = width;
|
||||
bestNode.height = height;
|
||||
bestScore = score;
|
||||
*nodeIndex = i;
|
||||
debug_assert(disjointRects.Disjoint(bestNode));
|
||||
}
|
||||
}
|
||||
// Does the rectangle fit sideways?
|
||||
else if (height <= freeRectangles[i].width && width <= freeRectangles[i].height)
|
||||
{
|
||||
int score = ScoreByHeuristic(height, width, freeRectangles[i], rectChoice);
|
||||
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestNode.x = freeRectangles[i].x;
|
||||
bestNode.y = freeRectangles[i].y;
|
||||
bestNode.width = height;
|
||||
bestNode.height = width;
|
||||
bestScore = score;
|
||||
*nodeIndex = i;
|
||||
debug_assert(disjointRects.Disjoint(bestNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestNode;
|
||||
}
|
||||
|
||||
void GuillotineBinPack::SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method)
|
||||
{
|
||||
// Compute the lengths of the leftover area.
|
||||
const int w = freeRect.width - placedRect.width;
|
||||
const int h = freeRect.height - placedRect.height;
|
||||
|
||||
// Placing placedRect into freeRect results in an L-shaped free area, which must be split into
|
||||
// two disjoint rectangles. This can be achieved with by splitting the L-shape using a single line.
|
||||
// We have two choices: horizontal or vertical.
|
||||
|
||||
// Use the given heuristic to decide which choice to make.
|
||||
|
||||
bool splitHorizontal;
|
||||
switch(method)
|
||||
{
|
||||
case SplitShorterLeftoverAxis:
|
||||
// Split along the shorter leftover axis.
|
||||
splitHorizontal = (w <= h);
|
||||
break;
|
||||
case SplitLongerLeftoverAxis:
|
||||
// Split along the longer leftover axis.
|
||||
splitHorizontal = (w > h);
|
||||
break;
|
||||
case SplitMinimizeArea:
|
||||
// Maximize the larger area == minimize the smaller area.
|
||||
// Tries to make the single bigger rectangle.
|
||||
splitHorizontal = (placedRect.width * h > w * placedRect.height);
|
||||
break;
|
||||
case SplitMaximizeArea:
|
||||
// Maximize the smaller area == minimize the larger area.
|
||||
// Tries to make the rectangles more even-sized.
|
||||
splitHorizontal = (placedRect.width * h <= w * placedRect.height);
|
||||
break;
|
||||
case SplitShorterAxis:
|
||||
// Split along the shorter total axis.
|
||||
splitHorizontal = (freeRect.width <= freeRect.height);
|
||||
break;
|
||||
case SplitLongerAxis:
|
||||
// Split along the longer total axis.
|
||||
splitHorizontal = (freeRect.width > freeRect.height);
|
||||
break;
|
||||
default:
|
||||
splitHorizontal = true;
|
||||
assert(false);
|
||||
}
|
||||
|
||||
// Perform the actual split.
|
||||
SplitFreeRectAlongAxis(freeRect, placedRect, splitHorizontal);
|
||||
}
|
||||
|
||||
/// This function will add the two generated rectangles into the freeRectangles array. The caller is expected to
|
||||
/// remove the original rectangle from the freeRectangles array after that.
|
||||
void GuillotineBinPack::SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal)
|
||||
{
|
||||
// Form the two new rectangles.
|
||||
Rect bottom;
|
||||
bottom.x = freeRect.x;
|
||||
bottom.y = freeRect.y + placedRect.height;
|
||||
bottom.height = freeRect.height - placedRect.height;
|
||||
|
||||
Rect right;
|
||||
right.x = freeRect.x + placedRect.width;
|
||||
right.y = freeRect.y;
|
||||
right.width = freeRect.width - placedRect.width;
|
||||
|
||||
if (splitHorizontal)
|
||||
{
|
||||
bottom.width = freeRect.width;
|
||||
right.height = placedRect.height;
|
||||
}
|
||||
else // Split vertically
|
||||
{
|
||||
bottom.width = placedRect.width;
|
||||
right.height = freeRect.height;
|
||||
}
|
||||
|
||||
// Add the new rectangles into the free rectangle pool if they weren't degenerate.
|
||||
if (bottom.width > 0 && bottom.height > 0)
|
||||
freeRectangles.push_back(bottom);
|
||||
if (right.width > 0 && right.height > 0)
|
||||
freeRectangles.push_back(right);
|
||||
|
||||
debug_assert(disjointRects.Disjoint(bottom));
|
||||
debug_assert(disjointRects.Disjoint(right));
|
||||
}
|
||||
|
||||
void GuillotineBinPack::MergeFreeList()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
DisjointRectCollection test;
|
||||
for(size_t i = 0; i < freeRectangles.size(); ++i)
|
||||
assert(test.Add(freeRectangles[i]) == true);
|
||||
#endif
|
||||
|
||||
// Do a Theta(n^2) loop to see if any pair of free rectangles could me merged into one.
|
||||
// Note that we miss any opportunities to merge three rectangles into one. (should call this function again to detect that)
|
||||
for(size_t i = 0; i < freeRectangles.size(); ++i)
|
||||
for(size_t j = i+1; j < freeRectangles.size(); ++j)
|
||||
{
|
||||
if (freeRectangles[i].width == freeRectangles[j].width && freeRectangles[i].x == freeRectangles[j].x)
|
||||
{
|
||||
if (freeRectangles[i].y == freeRectangles[j].y + freeRectangles[j].height)
|
||||
{
|
||||
freeRectangles[i].y -= freeRectangles[j].height;
|
||||
freeRectangles[i].height += freeRectangles[j].height;
|
||||
freeRectangles.erase(freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
else if (freeRectangles[i].y + freeRectangles[i].height == freeRectangles[j].y)
|
||||
{
|
||||
freeRectangles[i].height += freeRectangles[j].height;
|
||||
freeRectangles.erase(freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
else if (freeRectangles[i].height == freeRectangles[j].height && freeRectangles[i].y == freeRectangles[j].y)
|
||||
{
|
||||
if (freeRectangles[i].x == freeRectangles[j].x + freeRectangles[j].width)
|
||||
{
|
||||
freeRectangles[i].x -= freeRectangles[j].width;
|
||||
freeRectangles[i].width += freeRectangles[j].width;
|
||||
freeRectangles.erase(freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
else if (freeRectangles[i].x + freeRectangles[i].width == freeRectangles[j].x)
|
||||
{
|
||||
freeRectangles[i].width += freeRectangles[j].width;
|
||||
freeRectangles.erase(freeRectangles.begin() + j);
|
||||
--j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
test.Clear();
|
||||
for(size_t i = 0; i < freeRectangles.size(); ++i)
|
||||
assert(test.Add(freeRectangles[i]) == true);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
/** @file GuillotineBinPack.h
|
||||
@author Jukka Jylänki
|
||||
|
||||
@brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
namespace rbp {
|
||||
|
||||
/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure
|
||||
to keep track of the free space of the bin where rectangles may be placed. */
|
||||
class GuillotineBinPack
|
||||
{
|
||||
public:
|
||||
/// The initial bin size will be (0,0). Call Init to set the bin size.
|
||||
GuillotineBinPack();
|
||||
|
||||
/// Initializes a new bin of the given size.
|
||||
GuillotineBinPack(int width, int height);
|
||||
|
||||
/// (Re)initializes the packer to an empty bin of width x height units. Call whenever
|
||||
/// you need to restart with a new bin.
|
||||
void Init(int width, int height);
|
||||
|
||||
/// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles
|
||||
/// to place the to-be-packed rectangle into.
|
||||
enum FreeRectChoiceHeuristic
|
||||
{
|
||||
RectBestAreaFit, ///< -BAF
|
||||
RectBestShortSideFit, ///< -BSSF
|
||||
RectBestLongSideFit, ///< -BLSF
|
||||
RectWorstAreaFit, ///< -WAF
|
||||
RectWorstShortSideFit, ///< -WSSF
|
||||
RectWorstLongSideFit ///< -WLSF
|
||||
};
|
||||
|
||||
/// Specifies the different choice heuristics that can be used when the packer needs to decide whether to
|
||||
/// subdivide the remaining free space in horizontal or vertical direction.
|
||||
enum GuillotineSplitHeuristic
|
||||
{
|
||||
SplitShorterLeftoverAxis, ///< -SLAS
|
||||
SplitLongerLeftoverAxis, ///< -LLAS
|
||||
SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small.
|
||||
SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible.
|
||||
SplitShorterAxis, ///< -SAS
|
||||
SplitLongerAxis ///< -LAS
|
||||
};
|
||||
|
||||
/// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned
|
||||
/// struct will have the width and height values swapped.
|
||||
/// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure
|
||||
/// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up
|
||||
/// some extra time.
|
||||
/// @param rectChoice The free rectangle choice heuristic rule to use.
|
||||
/// @param splitMethod The free rectangle split heuristic rule to use.
|
||||
Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
/// Inserts a list of rectangles into the bin.
|
||||
/// @param rects The list of rectangles to add. This list will be destroyed in the packing process.
|
||||
/// @param merge If true, performs Rectangle Merge operations during the packing process.
|
||||
/// @param rectChoice The free rectangle choice heuristic rule to use.
|
||||
/// @param splitMethod The free rectangle split heuristic rule to use.
|
||||
void Insert(std::vector<RectSize> &rects, bool merge,
|
||||
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
|
||||
// void InsertMaxFitting(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge,
|
||||
// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
|
||||
|
||||
/// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used.
|
||||
float Occupancy() const;
|
||||
|
||||
/// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector
|
||||
/// any way desired, as long as the end result still is a list of disjoint rectangles.
|
||||
std::vector<Rect> &GetFreeRectangles() { return freeRectangles; }
|
||||
|
||||
/// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from
|
||||
/// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation.
|
||||
std::vector<Rect> &GetUsedRectangles() { return usedRectangles; }
|
||||
|
||||
/// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they
|
||||
/// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time.
|
||||
void MergeFreeList();
|
||||
|
||||
private:
|
||||
int binWidth;
|
||||
int binHeight;
|
||||
|
||||
/// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio,
|
||||
/// so if you want to have the packer consume less memory, this can be removed.
|
||||
std::vector<Rect> usedRectangles;
|
||||
|
||||
/// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint.
|
||||
std::vector<Rect> freeRectangles;
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// Used to track that the packer produces proper packings.
|
||||
DisjointRectCollection disjointRects;
|
||||
#endif
|
||||
|
||||
/// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into.
|
||||
/// Running time is Theta(|freeRectangles|).
|
||||
/// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new
|
||||
/// rect was placed.
|
||||
/// @return A Rect structure that represents the placement of the new rect into the best free rectangle.
|
||||
Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex);
|
||||
|
||||
static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice);
|
||||
// The following functions compute (penalty) score values if a rect of the given size was placed into the
|
||||
// given free rectangle. In these score values, smaller is better.
|
||||
|
||||
static int ScoreBestAreaFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect);
|
||||
|
||||
static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect);
|
||||
static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect);
|
||||
|
||||
/// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it.
|
||||
/// Determines the split axis by using the given heuristic.
|
||||
void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method);
|
||||
|
||||
/// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis.
|
||||
void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal);
|
||||
};
|
||||
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
/** @file Rect.cpp
|
||||
@author Jukka Jylänki
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#include <utility>
|
||||
|
||||
#include "Rect.h"
|
||||
|
||||
namespace rbp {
|
||||
|
||||
/*
|
||||
#include "clb/Algorithm/Sort.h"
|
||||
|
||||
int CompareRectShortSide(const Rect &a, const Rect &b)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
int smallerSideA = min(a.width, a.height);
|
||||
int smallerSideB = min(b.width, b.height);
|
||||
|
||||
if (smallerSideA != smallerSideB)
|
||||
return clb::sort::TriCmp(smallerSideA, smallerSideB);
|
||||
|
||||
// Tie-break on the larger side.
|
||||
int largerSideA = max(a.width, a.height);
|
||||
int largerSideB = max(b.width, b.height);
|
||||
|
||||
return clb::sort::TriCmp(largerSideA, largerSideB);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
int NodeSortCmp(const Rect &a, const Rect &b)
|
||||
{
|
||||
if (a.x != b.x)
|
||||
return clb::sort::TriCmp(a.x, b.x);
|
||||
if (a.y != b.y)
|
||||
return clb::sort::TriCmp(a.y, b.y);
|
||||
if (a.width != b.width)
|
||||
return clb::sort::TriCmp(a.width, b.width);
|
||||
return clb::sort::TriCmp(a.height, b.height);
|
||||
}
|
||||
*/
|
||||
bool IsContainedIn(const Rect &a, const Rect &b)
|
||||
{
|
||||
return a.x >= b.x && a.y >= b.y
|
||||
&& a.x+a.width <= b.x+b.width
|
||||
&& a.y+a.height <= b.y+b.height;
|
||||
}
|
||||
|
||||
}
|
||||
Vendored
-94
@@ -1,94 +0,0 @@
|
||||
/** @file Rect.h
|
||||
@author Jukka Jylänki
|
||||
|
||||
This work is released to Public Domain, do whatever you want with it.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _DEBUG
|
||||
/// debug_assert is an assert that also requires debug mode to be defined.
|
||||
#define debug_assert(x) assert(x)
|
||||
#else
|
||||
#define debug_assert(x)
|
||||
#endif
|
||||
|
||||
//using namespace std;
|
||||
|
||||
namespace rbp {
|
||||
|
||||
struct RectSize
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
struct Rect
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
/// Performs a lexicographic compare on (rect short side, rect long side).
|
||||
/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around.
|
||||
/// If they are equal, the larger side length is used as a tie-breaker.
|
||||
/// If the rectangles are of same size, returns 0.
|
||||
int CompareRectShortSide(const Rect &a, const Rect &b);
|
||||
|
||||
/// Performs a lexicographic compare on (x, y, width, height).
|
||||
int NodeSortCmp(const Rect &a, const Rect &b);
|
||||
|
||||
/// Returns true if a is contained in b.
|
||||
bool IsContainedIn(const Rect &a, const Rect &b);
|
||||
|
||||
class DisjointRectCollection
|
||||
{
|
||||
public:
|
||||
std::vector<Rect> rects;
|
||||
|
||||
bool Add(const Rect &r)
|
||||
{
|
||||
// Degenerate rectangles are ignored.
|
||||
if (r.width == 0 || r.height == 0)
|
||||
return true;
|
||||
|
||||
if (!Disjoint(r))
|
||||
return false;
|
||||
rects.push_back(r);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
rects.clear();
|
||||
}
|
||||
|
||||
bool Disjoint(const Rect &r) const
|
||||
{
|
||||
// Degenerate rectangles are ignored.
|
||||
if (r.width == 0 || r.height == 0)
|
||||
return true;
|
||||
|
||||
for(size_t i = 0; i < rects.size(); ++i)
|
||||
if (!Disjoint(rects[i], r))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool Disjoint(const Rect &a, const Rect &b)
|
||||
{
|
||||
if (a.x + a.width <= b.x ||
|
||||
b.x + b.width <= a.x ||
|
||||
a.y + a.height <= b.y ||
|
||||
b.y + b.height <= a.y)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
-6488
File diff suppressed because it is too large
Load Diff
-2020
File diff suppressed because it is too large
Load Diff
-2596
File diff suppressed because it is too large
Load Diff
-446
@@ -1,446 +0,0 @@
|
||||
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
|
||||
#define RAPIDXML_PRINT_HPP_INCLUDED
|
||||
|
||||
// Copyright (C) 2006, 2009 Marcin Kalicinski
|
||||
// Version 1.13
|
||||
// Revision $DateTime: 2009/05/13 01:46:17 $
|
||||
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
|
||||
|
||||
#include "rapidxml.hpp"
|
||||
|
||||
// Only include streams if not disabled
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
#include <ostream>
|
||||
#include <iterator>
|
||||
#endif
|
||||
|
||||
namespace rapidxml
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Printing flags
|
||||
|
||||
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Internal
|
||||
|
||||
//! \cond internal
|
||||
namespace internal
|
||||
{
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal character operations
|
||||
|
||||
// Copy characters from given range to given output iterator
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Copy characters from given range to given output iterator and expand
|
||||
// characters into references (< > ' " &)
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
{
|
||||
if (*begin == noexpand)
|
||||
{
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (*begin)
|
||||
{
|
||||
case Ch('<'):
|
||||
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('>'):
|
||||
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('\''):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('"'):
|
||||
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
|
||||
break;
|
||||
case Ch('&'):
|
||||
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
|
||||
break;
|
||||
default:
|
||||
*out++ = *begin; // No expansion, copy character
|
||||
}
|
||||
}
|
||||
++begin; // Step to next character
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Fill given output iterator with repetitions of the same character
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt fill_chars(OutIt out, int n, Ch ch)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
*out++ = ch;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Find character
|
||||
template<class Ch, Ch ch>
|
||||
inline bool find_char(const Ch *begin, const Ch *end)
|
||||
{
|
||||
while (begin != end)
|
||||
if (*begin++ == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Internal printing operations
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
|
||||
// Print node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print proper node type
|
||||
switch (node->type())
|
||||
{
|
||||
|
||||
// Document
|
||||
case node_document:
|
||||
out = print_children(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Element
|
||||
case node_element:
|
||||
out = print_element_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Data
|
||||
case node_data:
|
||||
out = print_data_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// CDATA
|
||||
case node_cdata:
|
||||
out = print_cdata_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Declaration
|
||||
case node_declaration:
|
||||
out = print_declaration_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Comment
|
||||
case node_comment:
|
||||
out = print_comment_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Doctype
|
||||
case node_doctype:
|
||||
out = print_doctype_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Pi
|
||||
case node_pi:
|
||||
out = print_pi_node(out, node, flags, indent);
|
||||
break;
|
||||
|
||||
// Unknown
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
// If indenting not disabled, add line break after node
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
|
||||
// Return modified iterator
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print children of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
|
||||
out = print_node(out, child, flags, indent);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print attributes of the node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
|
||||
{
|
||||
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
|
||||
{
|
||||
if (attribute->name() && attribute->value())
|
||||
{
|
||||
// Print attribute name
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
|
||||
*out = Ch('='), ++out;
|
||||
// Print attribute value using appropriate quote type
|
||||
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
|
||||
{
|
||||
*out = Ch('\''), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
|
||||
*out = Ch('\''), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
*out = Ch('"'), ++out;
|
||||
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
|
||||
*out = Ch('"'), ++out;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_data);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print data node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_cdata);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'); ++out;
|
||||
*out = Ch('!'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
*out = Ch('C'); ++out;
|
||||
*out = Ch('D'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('T'); ++out;
|
||||
*out = Ch('A'); ++out;
|
||||
*out = Ch('['); ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch(']'); ++out;
|
||||
*out = Ch('>'); ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print element node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_element);
|
||||
|
||||
// Print element name and attributes, if any
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// If node is childless
|
||||
if (node->value_size() == 0 && !node->first_node())
|
||||
{
|
||||
// Print childless node tag ending
|
||||
*out = Ch('/'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print normal node tag ending
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
// Test if node contains a single data node only (and no other nodes)
|
||||
xml_node<Ch> *child = node->first_node();
|
||||
if (!child)
|
||||
{
|
||||
// If node has no children, only print its value without indenting
|
||||
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
|
||||
}
|
||||
else if (child->next_sibling() == 0 && child->type() == node_data)
|
||||
{
|
||||
// If node has a sole data child, only print its value without indenting
|
||||
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Print all children with full indenting
|
||||
if (!(flags & print_no_indenting))
|
||||
*out = Ch('\n'), ++out;
|
||||
out = print_children(out, node, flags, indent + 1);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
}
|
||||
|
||||
// Print node end
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('/'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print declaration node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
// Print declaration start
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('x'), ++out;
|
||||
*out = Ch('m'), ++out;
|
||||
*out = Ch('l'), ++out;
|
||||
|
||||
// Print attributes
|
||||
out = print_attributes(out, node, flags);
|
||||
|
||||
// Print declaration end
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print comment node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_comment);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('-'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print doctype node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_doctype);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('!'), ++out;
|
||||
*out = Ch('D'), ++out;
|
||||
*out = Ch('O'), ++out;
|
||||
*out = Ch('C'), ++out;
|
||||
*out = Ch('T'), ++out;
|
||||
*out = Ch('Y'), ++out;
|
||||
*out = Ch('P'), ++out;
|
||||
*out = Ch('E'), ++out;
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
// Print pi node
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
|
||||
{
|
||||
assert(node->type() == node_pi);
|
||||
if (!(flags & print_no_indenting))
|
||||
out = fill_chars(out, indent, Ch('\t'));
|
||||
*out = Ch('<'), ++out;
|
||||
*out = Ch('?'), ++out;
|
||||
out = copy_chars(node->name(), node->name() + node->name_size(), out);
|
||||
*out = Ch(' '), ++out;
|
||||
out = copy_chars(node->value(), node->value() + node->value_size(), out);
|
||||
*out = Ch('?'), ++out;
|
||||
*out = Ch('>'), ++out;
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
//! \endcond
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Printing
|
||||
|
||||
//! Prints XML to given output iterator.
|
||||
//! \param out Output iterator to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output iterator pointing to position immediately after last character of printed text.
|
||||
template<class OutIt, class Ch>
|
||||
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
return internal::print_node(out, &node, flags, 0);
|
||||
}
|
||||
|
||||
#ifndef RAPIDXML_NO_STREAMS
|
||||
|
||||
//! Prints XML to given output stream.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed. Pass xml_document to print entire document.
|
||||
//! \param flags Flags controlling how XML is printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
|
||||
{
|
||||
print(std::ostream_iterator<Ch>(out), node, flags);
|
||||
return out;
|
||||
}
|
||||
|
||||
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
|
||||
//! \param out Output stream to print to.
|
||||
//! \param node Node to be printed.
|
||||
//! \return Output stream.
|
||||
template<class Ch>
|
||||
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
|
||||
{
|
||||
return print(out, node);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
// stb_dxt.cpp - Real-Time DXT1/DXT5 compressor
|
||||
// Based on original by fabian "ryg" giesen v1.04
|
||||
// Custom version, modified by Yann Collet
|
||||
//
|
||||
/*
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- RygsDXTc source repository : http://code.google.com/p/rygsdxtc/
|
||||
*/
|
||||
|
||||
|
||||
#define STB_DXT_IMPLEMENTATION
|
||||
#include "stb_dxt.h"
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user