diff --git a/CMakeLists.txt b/CMakeLists.txt index b785ff97a..12c475beb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.14.0) +cmake_minimum_required(VERSION 3.17.2) project(Vita3K) # Detects the amount of processors of the host machine and forwards the result to CPU_COUNT diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index b077ac6ab..b413beaf2 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -28,22 +28,10 @@ endfunction() check_submodules_present() -# Fix a glslang hack -# See https://github.com/KhronosGroup/glslang/issues/1015 and https://github.com/Vita3K/Vita3K/pull/369 for details -if(NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - if(WIN32) - set(CMAKE_INSTALL_PREFIX "C:/Program Files/${PROJECT_NAME}" CACHE STRING "Default install prefix is: C:/Program Files" FORCE) - elseif(UNIX) - set(CMAKE_INSTALL_PREFIX /usr/local CACHE STRING "Default install prefix is: /usr/local" FORCE) - endif() -endif() - # Define the Architecture variable, right now it should only contain "x86_64" or "arm64" include("dynarmic/CMakeModules/DetectArchitecture.cmake") -option(CAPSTONE_BUILD_SHARED "Build shared library" OFF) -option(CAPSTONE_BUILD_TESTS "Build tests" OFF) -option(CAPSTONE_BUILD_CSTOOL "Build cstool" OFF) +option(BUILD_SHARED_LIBS "Build shared library" OFF) option(CAPSTONE_ARCHITECTURE_DEFAULT "Whether architectures are enabled by default" OFF) option(CAPSTONE_ARM_SUPPORT "ARM support" ON) add_subdirectory(capstone EXCLUDE_FROM_ALL) @@ -75,9 +63,8 @@ set_property(TARGET spdlog PROPERTY FOLDER externals) add_library(stb INTERFACE) target_include_directories(stb INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/stb") -add_library(glad STATIC "${CMAKE_CURRENT_SOURCE_DIR}/glad/src/glad.c") +add_library(glad STATIC "${CMAKE_CURRENT_SOURCE_DIR}/glad/src/gl.c") target_include_directories(glad PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/glad/include") -target_link_libraries(glad PRIVATE ${CMAKE_DL_LIBS}) set_property(TARGET glad PROPERTY FOLDER externals) add_library(better-enums INTERFACE) @@ -176,10 +163,8 @@ set_property(TARGET unicorn PROPERTY FOLDER externals) add_library(vita-toolchain INTERFACE) target_include_directories(vita-toolchain INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/vita-toolchain/src") -option(BUILD_TESTING "Build the testing tree." OFF) option(YAML_CPP_BUILD_TOOLS "Enable parse tools" OFF) option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" OFF) -option(YAML_CPP_INSTALL "Enable generation of install target" OFF) add_subdirectory(yaml-cpp EXCLUDE_FROM_ALL) set_property(TARGET yaml-cpp PROPERTY FOLDER externals) @@ -235,7 +220,7 @@ endif() option(BUILD_EXTERNAL "Build external dependencies in /External" OFF) option(SKIP_GLSLANG_INSTALL "Skip installation" ON) option(ENABLE_SPVREMAPPER "Enables building of SPVRemapper" OFF) -option(ENABLE_GLSLANG_BINARIES "Builds glslangValidator and spirv-remap" OFF) +option(ENABLE_GLSLANG_BINARIES "Builds glslang and spirv-remap" OFF) option(ENABLE_HLSL "Enables HLSL input support" OFF) option(ENABLE_CTEST "Enables testing" OFF) add_subdirectory(glslang) @@ -305,7 +290,7 @@ if(NOT OPENSSL_FOUND) if(NOT EXISTS "${CMAKE_BINARY_DIR}/external/openssl.zip") message(STATUS "Downloading openssl...") - file(DOWNLOAD https://firedaemon.com/download-firedaemon-openssl-3-zip + file(DOWNLOAD https://firedaemon.com/download-firedaemon-openssl-3.1-zip "${CMAKE_BINARY_DIR}/external/openssl.zip" SHOW_PROGRESS) endif() @@ -315,7 +300,7 @@ if(NOT OPENSSL_FOUND) WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/external/openssl") endif() - set(OPENSSL_ROOT_DIR "${CMAKE_BINARY_DIR}/external/openssl/openssl-3.0/x64") + set(OPENSSL_ROOT_DIR "${CMAKE_BINARY_DIR}/external/openssl/openssl-3/x64") endif() find_package(OpenSSL REQUIRED) @@ -347,14 +332,15 @@ option(TRACY_ENABLE_ON_CORE_COMPONENTS HLE modules" ON) add_library(tracy STATIC tracy/public/TracyClient.cpp) +target_include_directories(tracy SYSTEM PUBLIC $) +target_link_libraries(tracy PUBLIC ${CMAKE_DL_LIBS}) set_property(TARGET tracy PROPERTY FOLDER externals) -target_include_directories(tracy PUBLIC tracy) if(UNIX) - target_link_libraries(tracy PUBLIC pthread dl) + target_link_libraries(tracy PUBLIC pthread) endif() -# Enable Tracy on-demand profiling mode to avoid unnecesary memory usage when the developer +# Enable Tracy on-demand profiling mode to avoid unnecessary memory usage when the developer # isn't profiling by only enabling profiling after a connection has been established with # a Tracy server target_compile_definitions(tracy PUBLIC $<$:TRACY_ON_DEMAND>) diff --git a/external/MoltenVK/mvk_config.h b/external/MoltenVK/mvk_config.h index ea90da79d..360007e16 100644 --- a/external/MoltenVK/mvk_config.h +++ b/external/MoltenVK/mvk_config.h @@ -6,9 +6,9 @@ * 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. @@ -16,17 +16,21 @@ * limitations under the License. */ + + #ifndef __mvk_config_h_ #define __mvk_config_h_ 1 #ifdef __cplusplus extern "C" { -#endif // __cplusplus - +#endif // __cplusplus + #include + /** This header contains the public configuration API for MoltenVK. */ + /** * The version number of MoltenVK is a single integer value, derived from the Major, Minor, * and Patch version values, where each of the Major, Minor, and Patch components is allocated @@ -39,104 +43,105 @@ extern "C" { * - 030104 (version 3.1.4) * - 401215 (version 4.12.15) */ -#define MVK_VERSION_MAJOR 1 -#define MVK_VERSION_MINOR 2 -#define MVK_VERSION_PATCH 4 +#define MVK_VERSION_MAJOR 1 +#define MVK_VERSION_MINOR 2 +#define MVK_VERSION_PATCH 5 -#define MVK_MAKE_VERSION(major, minor, patch) (((major)*10000) + ((minor)*100) + (patch)) -#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH) +#define MVK_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch)) +#define MVK_VERSION MVK_MAKE_VERSION(MVK_VERSION_MAJOR, MVK_VERSION_MINOR, MVK_VERSION_PATCH) -#define MVK_CONFIGURATION_API_VERSION 37 + +#define MVK_CONFIGURATION_API_VERSION 37 /** Identifies the level of logging MoltenVK should be limited to outputting. */ typedef enum MVKConfigLogLevel { - MVK_CONFIG_LOG_LEVEL_NONE = 0, /**< No logging. */ - MVK_CONFIG_LOG_LEVEL_ERROR = 1, /**< Log errors only. */ - MVK_CONFIG_LOG_LEVEL_WARNING = 2, /**< Log errors and warning messages. */ - MVK_CONFIG_LOG_LEVEL_INFO = 3, /**< Log errors, warnings and informational messages. */ - MVK_CONFIG_LOG_LEVEL_DEBUG = 4, /**< Log errors, warnings, infos and debug messages. */ - MVK_CONFIG_LOG_LEVEL_MAX_ENUM = 0x7FFFFFFF + MVK_CONFIG_LOG_LEVEL_NONE = 0, /**< No logging. */ + MVK_CONFIG_LOG_LEVEL_ERROR = 1, /**< Log errors only. */ + MVK_CONFIG_LOG_LEVEL_WARNING = 2, /**< Log errors and warning messages. */ + MVK_CONFIG_LOG_LEVEL_INFO = 3, /**< Log errors, warnings and informational messages. */ + MVK_CONFIG_LOG_LEVEL_DEBUG = 4, /**< Log errors, warnings, infos and debug messages. */ + MVK_CONFIG_LOG_LEVEL_MAX_ENUM = 0x7FFFFFFF } MVKConfigLogLevel; /** Identifies the level of Vulkan call trace logging MoltenVK should perform. */ typedef enum MVKConfigTraceVulkanCalls { - MVK_CONFIG_TRACE_VULKAN_CALLS_NONE = 0, /**< No Vulkan call logging. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER = 1, /**< Log the name of each Vulkan call when the call is entered. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_THREAD_ID = 2, /**< Log the name and thread ID of each Vulkan call when the call is entered. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT = 3, /**< Log the name of each Vulkan call when the call is entered and exited. This effectively brackets any other logging activity within the scope of the Vulkan call. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID = 4, /**< Log the name and thread ID of each Vulkan call when the call is entered and name when exited. This effectively brackets any other logging activity within the scope of the Vulkan call. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION = 5, /**< Same as MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT, plus logs the time spent inside the Vulkan function. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION_THREAD_ID = 6, /**< Same as MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID, plus logs the time spent inside the Vulkan function. */ - MVK_CONFIG_TRACE_VULKAN_CALLS_MAX_ENUM = 0x7FFFFFFF + MVK_CONFIG_TRACE_VULKAN_CALLS_NONE = 0, /**< No Vulkan call logging. */ + MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER = 1, /**< Log the name of each Vulkan call when the call is entered. */ + MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_THREAD_ID = 2, /**< Log the name and thread ID of each Vulkan call when the call is entered. */ + MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT = 3, /**< Log the name of each Vulkan call when the call is entered and exited. This effectively brackets any other logging activity within the scope of the Vulkan call. */ + MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID = 4, /**< Log the name and thread ID of each Vulkan call when the call is entered and name when exited. This effectively brackets any other logging activity within the scope of the Vulkan call. */ + MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION = 5, /**< Same as MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT, plus logs the time spent inside the Vulkan function. */ + MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION_THREAD_ID = 6, /**< Same as MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID, plus logs the time spent inside the Vulkan function. */ + MVK_CONFIG_TRACE_VULKAN_CALLS_MAX_ENUM = 0x7FFFFFFF } MVKConfigTraceVulkanCalls; /** Identifies the scope for Metal to run an automatic GPU capture for diagnostic debugging purposes. */ typedef enum MVKConfigAutoGPUCaptureScope { - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_NONE = 0, /**< No automatic GPU capture. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE = 1, /**< Automatically capture all GPU activity during the lifetime of a VkDevice. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME = 2, /**< Automatically capture all GPU activity during the rendering and presentation of the first frame. */ - MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_MAX_ENUM = 0x7FFFFFFF + MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_NONE = 0, /**< No automatic GPU capture. */ + MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_DEVICE = 1, /**< Automatically capture all GPU activity during the lifetime of a VkDevice. */ + MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME = 2, /**< Automatically capture all GPU activity during the rendering and presentation of the first frame. */ + MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_MAX_ENUM = 0x7FFFFFFF } MVKConfigAutoGPUCaptureScope; /** Identifies extensions to advertise as part of MoltenVK configuration. */ typedef enum MVKConfigAdvertiseExtensionBits { - MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL = 0x00000001, /**< All supported extensions. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_WSI = 0x00000002, /**< WSI extensions supported on the platform. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_PORTABILITY = 0x00000004, /**< Vulkan Portability Subset extensions. */ - MVK_CONFIG_ADVERTISE_EXTENSIONS_MAX_ENUM = 0x7FFFFFFF + MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL = 0x00000001, /**< All supported extensions. */ + MVK_CONFIG_ADVERTISE_EXTENSIONS_WSI = 0x00000002, /**< WSI extensions supported on the platform. */ + MVK_CONFIG_ADVERTISE_EXTENSIONS_PORTABILITY = 0x00000004, /**< Vulkan Portability Subset extensions. */ + MVK_CONFIG_ADVERTISE_EXTENSIONS_MAX_ENUM = 0x7FFFFFFF } MVKConfigAdvertiseExtensionBits; typedef VkFlags MVKConfigAdvertiseExtensions; /** Identifies the use of Metal Argument Buffers. */ typedef enum MVKUseMetalArgumentBuffers { - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER = 0, /**< Don't use Metal Argument Buffers. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_ALWAYS = 1, /**< Use Metal Argument Buffers for all pipelines. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING = 2, /**< Use Metal Argument Buffers only if VK_EXT_descriptor_indexing extension is enabled. */ - MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_MAX_ENUM = 0x7FFFFFFF + MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER = 0, /**< Don't use Metal Argument Buffers. */ + MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_ALWAYS = 1, /**< Use Metal Argument Buffers for all pipelines. */ + MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING = 2, /**< Use Metal Argument Buffers only if VK_EXT_descriptor_indexing extension is enabled. */ + MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_MAX_ENUM = 0x7FFFFFFF } MVKUseMetalArgumentBuffers; /** Identifies the Metal functionality used to support Vulkan semaphore functionality (VkSemaphore). */ typedef enum MVKVkSemaphoreSupportStyle { - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0, /**< Limit Vulkan to a single queue, with no explicit semaphore synchronization, and use Metal's implicit guarantees that all operations submitted to a queue will give the same result as if they had been run in submission order. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1, /**< Use Metal events (MTLEvent) when available on the platform, and where safe. This will revert to same as MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE on some NVIDIA GPUs and Rosetta2, due to potential challenges with MTLEvents on those platforms, or in older environments where MTLEvents are not supported. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS = 2, /**< Always use Metal events (MTLEvent) when available on the platform. This will revert to same as MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE in older environments where MTLEvents are not supported. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK = 3, /**< Use CPU callbacks upon GPU submission completion. This is the slowest technique, but allows multiple queues, compared to MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE. */ - MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_MAX_ENUM = 0x7FFFFFFF + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE = 0, /**< Limit Vulkan to a single queue, with no explicit semaphore synchronization, and use Metal's implicit guarantees that all operations submitted to a queue will give the same result as if they had been run in submission order. */ + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE = 1, /**< Use Metal events (MTLEvent) when available on the platform, and where safe. This will revert to same as MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE on some NVIDIA GPUs and Rosetta2, due to potential challenges with MTLEvents on those platforms, or in older environments where MTLEvents are not supported. */ + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS = 2, /**< Always use Metal events (MTLEvent) when available on the platform. This will revert to same as MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE in older environments where MTLEvents are not supported. */ + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK = 3, /**< Use CPU callbacks upon GPU submission completion. This is the slowest technique, but allows multiple queues, compared to MVK_CONFIG_VK_SEMAPHORE_USE_SINGLE_QUEUE. */ + MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_MAX_ENUM = 0x7FFFFFFF } MVKVkSemaphoreSupportStyle; /** Identifies the style of Metal command buffer pre-filling to be used. */ typedef enum MVKPrefillMetalCommandBuffersStyle { - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL = 0, /**< During Vulkan command buffer filling, do not prefill a Metal command buffer for each Vulkan command buffer. A single Metal command buffer is created and encoded for all the Vulkan command buffers included when vkQueueSubmit() is called. MoltenVK automatically creates and drains a single Metal object autorelease pool when vkQueueSubmit() is called. This is the fastest option, but potentially has the largest memory footprint. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_DEFERRED_ENCODING = 1, /**< During Vulkan command buffer filling, encode to the Metal command buffer when vkEndCommandBuffer() is called. MoltenVK automatically creates and drains a single Metal object autorelease pool when vkEndCommandBuffer() is called. This option has the fastest performance, and the largest memory footprint, of the prefilling options using autorelease pools. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING = 2, /**< During Vulkan command buffer filling, immediately encode to the Metal command buffer, as each command is submitted to the Vulkan command buffer, and do not retain any command content in the Vulkan command buffer. MoltenVK automatically creates and drains a Metal object autorelease pool for each and every command added to the Vulkan command buffer. This option has the smallest memory footprint, and the slowest performance, of the prefilling options using autorelease pools. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING_NO_AUTORELEASE = 3, /**< During Vulkan command buffer filling, immediately encode to the Metal command buffer, as each command is submitted to the Vulkan command buffer, do not retain any command content in the Vulkan command buffer, and assume the app will ensure that each thread that fills commands into a Vulkan command buffer has a Metal autorelease pool. MoltenVK will not create and drain any autorelease pools during encoding. This is the fastest prefilling option, and generally has a small memory footprint, depending on when the app-provided autorelease pool drains. */ - MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_MAX_ENUM = 0x7FFFFFFF + MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL = 0, /**< During Vulkan command buffer filling, do not prefill a Metal command buffer for each Vulkan command buffer. A single Metal command buffer is created and encoded for all the Vulkan command buffers included when vkQueueSubmit() is called. MoltenVK automatically creates and drains a single Metal object autorelease pool when vkQueueSubmit() is called. This is the fastest option, but potentially has the largest memory footprint. */ + MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_DEFERRED_ENCODING = 1, /**< During Vulkan command buffer filling, encode to the Metal command buffer when vkEndCommandBuffer() is called. MoltenVK automatically creates and drains a single Metal object autorelease pool when vkEndCommandBuffer() is called. This option has the fastest performance, and the largest memory footprint, of the prefilling options using autorelease pools. */ + MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING = 2, /**< During Vulkan command buffer filling, immediately encode to the Metal command buffer, as each command is submitted to the Vulkan command buffer, and do not retain any command content in the Vulkan command buffer. MoltenVK automatically creates and drains a Metal object autorelease pool for each and every command added to the Vulkan command buffer. This option has the smallest memory footprint, and the slowest performance, of the prefilling options using autorelease pools. */ + MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING_NO_AUTORELEASE = 3, /**< During Vulkan command buffer filling, immediately encode to the Metal command buffer, as each command is submitted to the Vulkan command buffer, do not retain any command content in the Vulkan command buffer, and assume the app will ensure that each thread that fills commands into a Vulkan command buffer has a Metal autorelease pool. MoltenVK will not create and drain any autorelease pools during encoding. This is the fastest prefilling option, and generally has a small memory footprint, depending on when the app-provided autorelease pool drains. */ + MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_MAX_ENUM = 0x7FFFFFFF } MVKPrefillMetalCommandBuffersStyle; /** Identifies when Metal shaders will be compiled with the fast math option. */ typedef enum MVKConfigFastMath { - MVK_CONFIG_FAST_MATH_NEVER = 0, /**< Metal shaders will never be compiled with the fast math option. */ - MVK_CONFIG_FAST_MATH_ALWAYS = 1, /**< Metal shaders will always be compiled with the fast math option. */ - MVK_CONFIG_FAST_MATH_ON_DEMAND = 2, /**< Metal shaders will be compiled with the fast math option, unless the shader includes execution modes that require it to be compiled without fast math. */ - MVK_CONFIG_FAST_MATH_MAX_ENUM = 0x7FFFFFFF + MVK_CONFIG_FAST_MATH_NEVER = 0, /**< Metal shaders will never be compiled with the fast math option. */ + MVK_CONFIG_FAST_MATH_ALWAYS = 1, /**< Metal shaders will always be compiled with the fast math option. */ + MVK_CONFIG_FAST_MATH_ON_DEMAND = 2, /**< Metal shaders will be compiled with the fast math option, unless the shader includes execution modes that require it to be compiled without fast math. */ + MVK_CONFIG_FAST_MATH_MAX_ENUM = 0x7FFFFFFF } MVKConfigFastMath; /** Identifies available system data compression algorithms. */ typedef enum MVKConfigCompressionAlgorithm { - MVK_CONFIG_COMPRESSION_ALGORITHM_NONE = 0, /**< No compression. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZFSE = 1, /**< Apple proprietary. Good balance of high performance and small compression size, particularly for larger data content. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_ZLIB = 2, /**< Open cross-platform ZLib format. For smaller data content, has better performance and smaller size than LZFSE. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZ4 = 3, /**< Fastest performance. Largest compression size. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_LZMA = 4, /**< Slowest performance. Smallest compression size, particular with larger content. */ - MVK_CONFIG_COMPRESSION_ALGORITHM_MAX_ENUM = 0x7FFFFFFF, + MVK_CONFIG_COMPRESSION_ALGORITHM_NONE = 0, /**< No compression. */ + MVK_CONFIG_COMPRESSION_ALGORITHM_LZFSE = 1, /**< Apple proprietary. Good balance of high performance and small compression size, particularly for larger data content. */ + MVK_CONFIG_COMPRESSION_ALGORITHM_ZLIB = 2, /**< Open cross-platform ZLib format. For smaller data content, has better performance and smaller size than LZFSE. */ + MVK_CONFIG_COMPRESSION_ALGORITHM_LZ4 = 3, /**< Fastest performance. Largest compression size. */ + MVK_CONFIG_COMPRESSION_ALGORITHM_LZMA = 4, /**< Slowest performance. Smallest compression size, particular with larger content. */ + MVK_CONFIG_COMPRESSION_ALGORITHM_MAX_ENUM = 0x7FFFFFFF, } MVKConfigCompressionAlgorithm; /** Identifies the style of activity performance logging to use. */ typedef enum MVKConfigActivityPerformanceLoggingStyle { - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT = 0, /**< Repeatedly log performance after a configured number of frames. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_IMMEDIATE = 1, /**< Log immediately after each performance measurement. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_DEVICE_LIFETIME = 2, /**< Log at the end of the VkDevice lifetime. This is useful for one-shot apps such as testing frameworks. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_MAX_ENUM = 0x7FFFFFFF, + MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT = 0, /**< Repeatedly log performance after a configured number of frames. */ + MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_IMMEDIATE = 1, /**< Log immediately after each performance measurement. */ + MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_DEVICE_LIFETIME = 2, /**< Log at the end of the VkDevice lifetime. This is useful for one-shot apps such as testing frameworks. */ + MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_MAX_ENUM = 0x7FFFFFFF, } MVKConfigActivityPerformanceLoggingStyle; /** @@ -176,744 +181,758 @@ typedef enum MVKConfigActivityPerformanceLoggingStyle { * SHOULD NOT BE CHANGED. */ typedef struct { - /** - * If enabled, debugging capabilities will be enabled, including logging - * shader code during runtime shader conversion. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_DEBUG - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter is false if MoltenVK was - * built in Release mode, and true if MoltenVK was built in Debug mode. - */ + + /** + * If enabled, debugging capabilities will be enabled, including logging + * shader code during runtime shader conversion. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * + * The initial value or this parameter is set by the + * MVK_DEBUG + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter is false if MoltenVK was + * built in Release mode, and true if MoltenVK was built in Debug mode. + */ VkBool32 debugMode; - /** - * If enabled, MSL vertex shader code created during runtime shader conversion will - * flip the Y-axis of each vertex, as the Vulkan Y-axis is the inverse of OpenGL. - * - * An alternate way to reverse the Y-axis is to employ a negative Y-axis value on - * the viewport, in which case this parameter can be disabled. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when compiling some pipelines, - * and disabled when compiling others. Existing pipelines are not automatically - * re-compiled when this parameter is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ + /** + * If enabled, MSL vertex shader code created during runtime shader conversion will + * flip the Y-axis of each vertex, as the Vulkan Y-axis is the inverse of OpenGL. + * + * An alternate way to reverse the Y-axis is to employ a negative Y-axis value on + * the viewport, in which case this parameter can be disabled. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * Specifically, this parameter can be enabled when compiling some pipelines, + * and disabled when compiling others. Existing pipelines are not automatically + * re-compiled when this parameter is changed. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to true. + */ VkBool32 shaderConversionFlipVertexY; - /** - * If enabled, queue command submissions (vkQueueSubmit() & vkQueuePresentKHR()) will be - * processed on the thread that called the submission function. If disabled, processing - * will be dispatched to a GCD dispatch_queue whose priority is determined by - * VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice(). - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true for macOS 10.14 - * and above or iOS 12 and above, and false otherwise. The reason for this distinction - * is that this feature should be disabled when emulation is required to support VkEvents - * because native support for events (MTLEvent) is not available. - */ - VkBool32 synchronousQueueSubmits; + /** + * If enabled, queue command submissions (vkQueueSubmit() & vkQueuePresentKHR()) will be + * processed on the thread that called the submission function. If disabled, processing + * will be dispatched to a GCD dispatch_queue whose priority is determined by + * VkDeviceQueueCreateInfo::pQueuePriorities during vkCreateDevice(). + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to true for macOS 10.14 + * and above or iOS 12 and above, and false otherwise. The reason for this distinction + * is that this feature should be disabled when emulation is required to support VkEvents + * because native support for events (MTLEvent) is not available. + */ + VkBool32 synchronousQueueSubmits; - /** - * If set to MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL, a single Metal - * command buffer will be created and filled when the Vulkan command buffers are submitted - * to the Vulkan queue. This allows a single Metal command buffer to be used for all of the - * Vulkan command buffers in a queue submission. The Metal command buffer is filled on the - * thread that processes the command queue submission. - * - * If set to any value other than MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL, - * where possible, a Metal command buffer will be created and filled when each Vulkan - * command buffer is filled. For applications that parallelize the filling of Vulkan - * commmand buffers across multiple threads, this allows the Metal command buffers to also - * be filled on the same parallel thread. Because each command buffer is filled separately, - * this requires that each Vulkan command buffer have a dedicated Metal command buffer. - * - * See the definition of the MVKPrefillMetalCommandBuffersStyle enumeration above for - * descriptions of the various values that can be used for this setting. The differences - * are primarily distinguished by how memory recovery is handled for autoreleased Metal - * objects that are created under the covers as the commands added to the Vulkan command - * buffer are encoded into the corresponding Metal command buffer. You can decide whether - * your app will recover all autoreleased Metal objects, or how agressively MoltenVK should - * recover autoreleased Metal objects, based on your approach to command buffer filling. - * - * Depending on the nature of your application, you may find performance is improved by filling - * the Metal command buffers on parallel threads, or you may find that performance is improved by - * consolidating all Vulkan command buffers onto a single Metal command buffer during queue submission. - * - * When enabling this feature, be aware that one Metal command buffer is required for each Vulkan - * command buffer. Depending on the number of command buffers that you use, you may also need to - * change the value of the maxActiveMetalCommandBuffersPerQueue setting. - * - * If this feature is enabled, be aware that if you have recorded commands to a Vulkan command buffer, - * and then choose to reset that command buffer instead of submitting it, the corresponding prefilled - * Metal command buffer will still be submitted. This is because Metal command buffers do not support - * the concept of being reset after being filled. Depending on when and how often you do this, - * it may cause unexpected visual artifacts and unnecessary GPU load. - * - * Prefilling of a Metal command buffer will not occur during the filling of secondary command - * buffers (VK_COMMAND_BUFFER_LEVEL_SECONDARY), or for primary command buffers that are intended - * to be submitted to multiple queues concurrently (VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT). - * - * This feature is incompatible with updating descriptors after binding. If any of the - * *UpdateAfterBind feature flags of VkPhysicalDeviceDescriptorIndexingFeatures or - * VkPhysicalDeviceInlineUniformBlockFeatures have been enabled, the value of this - * setting will be ignored and treated as if it is false. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when filling some command buffers, - * and disabled when later filling others. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to - * MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL. - */ - MVKPrefillMetalCommandBuffersStyle prefillMetalCommandBuffers; + /** + * If set to MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL, a single Metal + * command buffer will be created and filled when the Vulkan command buffers are submitted + * to the Vulkan queue. This allows a single Metal command buffer to be used for all of the + * Vulkan command buffers in a queue submission. The Metal command buffer is filled on the + * thread that processes the command queue submission. + * + * If set to any value other than MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL, + * where possible, a Metal command buffer will be created and filled when each Vulkan + * command buffer is filled. For applications that parallelize the filling of Vulkan + * commmand buffers across multiple threads, this allows the Metal command buffers to also + * be filled on the same parallel thread. Because each command buffer is filled separately, + * this requires that each Vulkan command buffer have a dedicated Metal command buffer. + * + * See the definition of the MVKPrefillMetalCommandBuffersStyle enumeration above for + * descriptions of the various values that can be used for this setting. The differences + * are primarily distinguished by how memory recovery is handled for autoreleased Metal + * objects that are created under the covers as the commands added to the Vulkan command + * buffer are encoded into the corresponding Metal command buffer. You can decide whether + * your app will recover all autoreleased Metal objects, or how agressively MoltenVK should + * recover autoreleased Metal objects, based on your approach to command buffer filling. + * + * Depending on the nature of your application, you may find performance is improved by filling + * the Metal command buffers on parallel threads, or you may find that performance is improved by + * consolidating all Vulkan command buffers onto a single Metal command buffer during queue submission. + * + * When enabling this feature, be aware that one Metal command buffer is required for each Vulkan + * command buffer. Depending on the number of command buffers that you use, you may also need to + * change the value of the maxActiveMetalCommandBuffersPerQueue setting. + * + * If this feature is enabled, be aware that if you have recorded commands to a Vulkan command buffer, + * and then choose to reset that command buffer instead of submitting it, the corresponding prefilled + * Metal command buffer will still be submitted. This is because Metal command buffers do not support + * the concept of being reset after being filled. Depending on when and how often you do this, + * it may cause unexpected visual artifacts and unnecessary GPU load. + * + * Prefilling of a Metal command buffer will not occur during the filling of secondary command + * buffers (VK_COMMAND_BUFFER_LEVEL_SECONDARY), or for primary command buffers that are intended + * to be submitted to multiple queues concurrently (VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT). + * + * This feature is incompatible with updating descriptors after binding. If any of the + * *UpdateAfterBind feature flags of VkPhysicalDeviceDescriptorIndexingFeatures or + * VkPhysicalDeviceInlineUniformBlockFeatures have been enabled, the value of this + * setting will be ignored and treated as if it is false. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * Specifically, this parameter can be enabled when filling some command buffers, + * and disabled when later filling others. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to + * MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_NO_PREFILL. + */ + MVKPrefillMetalCommandBuffersStyle prefillMetalCommandBuffers; - /** - * The maximum number of Metal command buffers that can be concurrently active per Vulkan queue. - * The number of active Metal command buffers required depends on the prefillMetalCommandBuffers - * setting. If prefillMetalCommandBuffers is enabled, one Metal command buffer is required per - * Vulkan command buffer. If prefillMetalCommandBuffers is disabled, one Metal command buffer - * is required per command buffer queue submission, which may be significantly less than the - * number of Vulkan command buffers. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to 64. - */ - uint32_t maxActiveMetalCommandBuffersPerQueue; + /** + * The maximum number of Metal command buffers that can be concurrently active per Vulkan queue. + * The number of active Metal command buffers required depends on the prefillMetalCommandBuffers + * setting. If prefillMetalCommandBuffers is enabled, one Metal command buffer is required per + * Vulkan command buffer. If prefillMetalCommandBuffers is disabled, one Metal command buffer + * is required per command buffer queue submission, which may be significantly less than the + * number of Vulkan command buffers. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to 64. + */ + uint32_t maxActiveMetalCommandBuffersPerQueue; - /** - * Depending on the GPU, Metal allows 8192 or 32768 occlusion queries per MTLBuffer. - * If enabled, MoltenVK allocates a MTLBuffer for each query pool, allowing each query - * pool to support that permitted number of queries. This may slow performance or cause - * unexpected behaviour if the query pool is not established prior to a Metal renderpass, - * or if the query pool is changed within a renderpass. If disabled, one MTLBuffer will - * be shared by all query pools, which improves performance, but limits the total device - * queries to the permitted number. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when creating some query pools, - * and disabled when creating others. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 supportLargeQueryPools; + /** + * Depending on the GPU, Metal allows 8192 or 32768 occlusion queries per MTLBuffer. + * If enabled, MoltenVK allocates a MTLBuffer for each query pool, allowing each query + * pool to support that permitted number of queries. This may slow performance or cause + * unexpected behaviour if the query pool is not established prior to a Metal renderpass, + * or if the query pool is changed within a renderpass. If disabled, one MTLBuffer will + * be shared by all query pools, which improves performance, but limits the total device + * queries to the permitted number. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * Specifically, this parameter can be enabled when creating some query pools, + * and disabled when creating others. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to true. + */ + VkBool32 supportLargeQueryPools; - /** Obsolete, ignored, and deprecated. All surface presentations are performed with a command buffer. */ - VkBool32 presentWithCommandBuffer; + /** Obsolete, ignored, and deprecated. All surface presentations are performed with a command buffer. */ + VkBool32 presentWithCommandBuffer; - /** - * If enabled, swapchain images will use simple Nearest sampling when minifying or magnifying - * the swapchain image to fit a physical display surface. If disabled, swapchain images will - * use Linear sampling when magnifying the swapchain image to fit a physical display surface. - * Enabling this setting avoids smearing effects when swapchain images are simple interger - * multiples of display pixels (eg- macOS Retina, and typical of graphics apps and games), - * but may cause aliasing effects when using non-integer display scaling. - * - * The value of this parameter must be changed before creating a VkSwapchain, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SWAPCHAIN_MIN_MAG_FILTER_USE_NEAREST - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 swapchainMinMagFilterUseNearest; + /** + * If enabled, swapchain images will use simple Nearest sampling when minifying or magnifying + * the swapchain image to fit a physical display surface. If disabled, swapchain images will + * use Linear sampling when magnifying the swapchain image to fit a physical display surface. + * Enabling this setting avoids smearing effects when swapchain images are simple interger + * multiples of display pixels (eg- macOS Retina, and typical of graphics apps and games), + * but may cause aliasing effects when using non-integer display scaling. + * + * The value of this parameter must be changed before creating a VkSwapchain, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_SWAPCHAIN_MIN_MAG_FILTER_USE_NEAREST + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to true. + */ + VkBool32 swapchainMinMagFilterUseNearest; #define swapchainMagFilterUseNearest swapchainMinMagFilterUseNearest - /** - * The maximum amount of time, in nanoseconds, to wait for a Metal library, function, or - * pipeline state object to be compiled and created by the Metal compiler. An internal error - * within the Metal compiler can stall the thread for up to 30 seconds. Setting this value - * limits that delay to a specified amount of time, allowing shader compilations to fail fast. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_METAL_COMPILE_TIMEOUT - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to infinite. - */ - uint64_t metalCompileTimeout; + /** + * The maximum amount of time, in nanoseconds, to wait for a Metal library, function, or + * pipeline state object to be compiled and created by the Metal compiler. An internal error + * within the Metal compiler can stall the thread for up to 30 seconds. Setting this value + * limits that delay to a specified amount of time, allowing shader compilations to fail fast. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_METAL_COMPILE_TIMEOUT + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to infinite. + */ + uint64_t metalCompileTimeout; - /** - * If enabled, performance statistics, as defined by the MVKPerformanceStatistics structure, - * are collected, and can be retrieved via the vkGetPerformanceStatisticsMVK() function. - * - * You can also use the activityPerformanceLoggingStyle and performanceLoggingFrameCount - * parameters to configure when to log the performance statistics collected by this parameter. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PERFORMANCE_TRACKING - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 performanceTracking; + /** + * If enabled, performance statistics, as defined by the MVKPerformanceStatistics structure, + * are collected, and can be retrieved via the vkGetPerformanceStatisticsMVK() function. + * + * You can also use the activityPerformanceLoggingStyle and performanceLoggingFrameCount + * parameters to configure when to log the performance statistics collected by this parameter. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_PERFORMANCE_TRACKING + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to false. + */ + VkBool32 performanceTracking; - /** - * If non-zero, performance statistics, frame-based statistics will be logged, on a - * repeating cycle, once per this many frames. The performanceTracking parameter must - * also be enabled. If this parameter is zero, or the performanceTracking parameter - * is disabled, no frame-based performance statistics will be logged. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero. - */ - uint32_t performanceLoggingFrameCount; + /** + * If non-zero, performance statistics, frame-based statistics will be logged, on a + * repeating cycle, once per this many frames. The performanceTracking parameter must + * also be enabled. If this parameter is zero, or the performanceTracking parameter + * is disabled, no frame-based performance statistics will be logged. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to zero. + */ + uint32_t performanceLoggingFrameCount; - /** - * If enabled, a MoltenVK logo watermark will be rendered on top of the scene. - * This can be enabled for publicity during demos. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DISPLAY_WATERMARK - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 displayWatermark; + /** + * If enabled, a MoltenVK logo watermark will be rendered on top of the scene. + * This can be enabled for publicity during demos. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_DISPLAY_WATERMARK + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to false. + */ + VkBool32 displayWatermark; - /** - * Metal does not distinguish functionality between queues, which would normally mean only - * a single general-purpose queue family with multiple queues is needed. However, Vulkan - * associates command buffers with a queue family, whereas Metal associates command buffers - * with a specific Metal queue. In order to allow a Metal command buffer to be prefilled - * before is is formally submitted to a Vulkan queue, each Vulkan queue family can support - * only a single Metal queue. As a result, in order to provide parallel queue operations, - * MoltenVK provides multiple queue families, each with a single queue. - * - * If this parameter is disabled, all queue families will be advertised as having general-purpose - * graphics + compute + transfer functionality, which is how the actual Metal queues behave. - * - * If this parameter is enabled, one queue family will be advertised as having general-purpose - * graphics + compute + transfer functionality, and the remaining queue families will be advertised - * as having specialized graphics OR compute OR transfer functionality, to make it easier for some - * apps to select a queue family with the appropriate requirements. - * - * The value of this parameter must be changed before creating a VkDevice, and before - * querying a VkPhysicalDevice for queue family properties, for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 specializedQueueFamilies; + /** + * Metal does not distinguish functionality between queues, which would normally mean only + * a single general-purpose queue family with multiple queues is needed. However, Vulkan + * associates command buffers with a queue family, whereas Metal associates command buffers + * with a specific Metal queue. In order to allow a Metal command buffer to be prefilled + * before is is formally submitted to a Vulkan queue, each Vulkan queue family can support + * only a single Metal queue. As a result, in order to provide parallel queue operations, + * MoltenVK provides multiple queue families, each with a single queue. + * + * If this parameter is disabled, all queue families will be advertised as having general-purpose + * graphics + compute + transfer functionality, which is how the actual Metal queues behave. + * + * If this parameter is enabled, one queue family will be advertised as having general-purpose + * graphics + compute + transfer functionality, and the remaining queue families will be advertised + * as having specialized graphics OR compute OR transfer functionality, to make it easier for some + * apps to select a queue family with the appropriate requirements. + * + * The value of this parameter must be changed before creating a VkDevice, and before + * querying a VkPhysicalDevice for queue family properties, for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to false. + */ + VkBool32 specializedQueueFamilies; - /** - * If enabled, when the app creates a VkDevice from a VkPhysicalDevice (GPU) that is neither - * headless nor low-power, and is different than the GPU used by the windowing system, the - * windowing system will be forced to switch to use the GPU selected by the Vulkan app. - * When the Vulkan app is ended, the windowing system will automatically switch back to - * using the previous GPU, depending on the usage requirements of other running apps. - * - * If disabled, the Vulkan app will render using its selected GPU, and if the windowing - * system uses a different GPU, the windowing system compositor will automatically copy - * framebuffer content from the app GPU to the windowing system GPU. - * - * The value of this parmeter has no effect on systems with a single GPU, or when the - * Vulkan app creates a VkDevice from a low-power or headless VkPhysicalDevice (GPU). - * - * Switching the windowing system GPU to match the Vulkan app GPU maximizes app performance, - * because it avoids the windowing system compositor from having to copy framebuffer content - * between GPUs on each rendered frame. However, doing so forces the entire system to - * potentially switch to using a GPU that may consume more power while the app is running. - * - * Some Vulkan apps may want to render using a high-power GPU, but leave it up to the - * system window compositor to determine how best to blend content with the windowing - * system, and as a result, may want to disable this parameter. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SWITCH_SYSTEM_GPU - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to true. - */ - VkBool32 switchSystemGPU; + /** + * If enabled, when the app creates a VkDevice from a VkPhysicalDevice (GPU) that is neither + * headless nor low-power, and is different than the GPU used by the windowing system, the + * windowing system will be forced to switch to use the GPU selected by the Vulkan app. + * When the Vulkan app is ended, the windowing system will automatically switch back to + * using the previous GPU, depending on the usage requirements of other running apps. + * + * If disabled, the Vulkan app will render using its selected GPU, and if the windowing + * system uses a different GPU, the windowing system compositor will automatically copy + * framebuffer content from the app GPU to the windowing system GPU. + * + * The value of this parmeter has no effect on systems with a single GPU, or when the + * Vulkan app creates a VkDevice from a low-power or headless VkPhysicalDevice (GPU). + * + * Switching the windowing system GPU to match the Vulkan app GPU maximizes app performance, + * because it avoids the windowing system compositor from having to copy framebuffer content + * between GPUs on each rendered frame. However, doing so forces the entire system to + * potentially switch to using a GPU that may consume more power while the app is running. + * + * Some Vulkan apps may want to render using a high-power GPU, but leave it up to the + * system window compositor to determine how best to blend content with the windowing + * system, and as a result, may want to disable this parameter. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_SWITCH_SYSTEM_GPU + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to true. + */ + VkBool32 switchSystemGPU; - /** - * Older versions of Metal do not natively support per-texture swizzling. When running on - * such a system, and this parameter is enabled, arbitrary VkImageView component swizzles - * are supported, as defined in VkImageViewCreateInfo::components when creating a VkImageView. - * - * If disabled, and native Metal per-texture swizzling is not available on the platform, - * a very limited set of VkImageView component swizzles are supported via format substitutions. - * - * If Metal supports native per-texture swizzling, this parameter is ignored. - * - * When running on an older version of Metal that does not support native per-texture - * swizzling, if this parameter is enabled, both when a VkImageView is created, and - * when any pipeline that uses that VkImageView is compiled, VkImageView swizzling is - * automatically performed in the converted Metal shader code during all texture sampling - * and reading operations, regardless of whether a swizzle is required for the VkImageView - * associated with the Metal texture. This may result in reduced performance. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * Specifically, this parameter can be enabled when creating VkImageViews that need it, - * and compiling pipelines that use those VkImageViews, and can be disabled when creating - * VkImageViews that don't need it, and compiling pipelines that use those VkImageViews. - * - * Existing pipelines are not automatically re-compiled when this parameter is changed. - * - * An error is logged and returned during VkImageView creation if that VkImageView - * requires full image view swizzling and this feature is not enabled. An error is - * also logged when a pipeline that was not compiled with full image view swizzling - * is presented with a VkImageView that is expecting it. - * - * An error is also retuned and logged when a VkPhysicalDeviceImageFormatInfo2KHR is passed - * in a call to vkGetPhysicalDeviceImageFormatProperties2KHR() to query for an VkImageView - * format that will require full swizzling to be enabled, and this feature is not enabled. - * - * If this parameter is disabled, and native Metal per-texture swizzling is not available - * on the platform, the following limited set of VkImageView swizzles are supported by - * MoltenVK, via automatic format substitution: - * - * Texture format Swizzle - * -------------- ------- - * VK_FORMAT_R8_UNORM ZERO, ANY, ANY, RED - * VK_FORMAT_A8_UNORM ALPHA, ANY, ANY, ZERO - * VK_FORMAT_R8G8B8A8_UNORM BLUE, GREEN, RED, ALPHA - * VK_FORMAT_R8G8B8A8_SRGB BLUE, GREEN, RED, ALPHA - * VK_FORMAT_B8G8R8A8_UNORM BLUE, GREEN, RED, ALPHA - * VK_FORMAT_B8G8R8A8_SRGB BLUE, GREEN, RED, ALPHA - * VK_FORMAT_D32_SFLOAT_S8_UINT RED, ANY, ANY, ANY (stencil only) - * VK_FORMAT_D24_UNORM_S8_UINT RED, ANY, ANY, ANY (stencil only) - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to false. - */ - VkBool32 fullImageViewSwizzle; + /** + * Older versions of Metal do not natively support per-texture swizzling. When running on + * such a system, and this parameter is enabled, arbitrary VkImageView component swizzles + * are supported, as defined in VkImageViewCreateInfo::components when creating a VkImageView. + * + * If disabled, and native Metal per-texture swizzling is not available on the platform, + * a very limited set of VkImageView component swizzles are supported via format substitutions. + * + * If Metal supports native per-texture swizzling, this parameter is ignored. + * + * When running on an older version of Metal that does not support native per-texture + * swizzling, if this parameter is enabled, both when a VkImageView is created, and + * when any pipeline that uses that VkImageView is compiled, VkImageView swizzling is + * automatically performed in the converted Metal shader code during all texture sampling + * and reading operations, regardless of whether a swizzle is required for the VkImageView + * associated with the Metal texture. This may result in reduced performance. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * Specifically, this parameter can be enabled when creating VkImageViews that need it, + * and compiling pipelines that use those VkImageViews, and can be disabled when creating + * VkImageViews that don't need it, and compiling pipelines that use those VkImageViews. + * + * Existing pipelines are not automatically re-compiled when this parameter is changed. + * + * An error is logged and returned during VkImageView creation if that VkImageView + * requires full image view swizzling and this feature is not enabled. An error is + * also logged when a pipeline that was not compiled with full image view swizzling + * is presented with a VkImageView that is expecting it. + * + * An error is also retuned and logged when a VkPhysicalDeviceImageFormatInfo2KHR is passed + * in a call to vkGetPhysicalDeviceImageFormatProperties2KHR() to query for an VkImageView + * format that will require full swizzling to be enabled, and this feature is not enabled. + * + * If this parameter is disabled, and native Metal per-texture swizzling is not available + * on the platform, the following limited set of VkImageView swizzles are supported by + * MoltenVK, via automatic format substitution: + * + * Texture format Swizzle + * -------------- ------- + * VK_FORMAT_R8_UNORM ZERO, ANY, ANY, RED + * VK_FORMAT_A8_UNORM ALPHA, ANY, ANY, ZERO + * VK_FORMAT_R8G8B8A8_UNORM BLUE, GREEN, RED, ALPHA + * VK_FORMAT_R8G8B8A8_SRGB BLUE, GREEN, RED, ALPHA + * VK_FORMAT_B8G8R8A8_UNORM BLUE, GREEN, RED, ALPHA + * VK_FORMAT_B8G8R8A8_SRGB BLUE, GREEN, RED, ALPHA + * VK_FORMAT_D32_SFLOAT_S8_UINT RED, ANY, ANY, ANY (stencil only) + * VK_FORMAT_D24_UNORM_S8_UINT RED, ANY, ANY, ANY (stencil only) + * + * The initial value or this parameter is set by the + * MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to false. + */ + VkBool32 fullImageViewSwizzle; - /** - * The index of the queue family whose presentation submissions will - * be used as the default GPU Capture Scope during debugging in Xcode. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero (the first queue family). - */ - uint32_t defaultGPUCaptureScopeQueueFamilyIndex; + /** + * The index of the queue family whose presentation submissions will + * be used as the default GPU Capture Scope during debugging in Xcode. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to zero (the first queue family). + */ + uint32_t defaultGPUCaptureScopeQueueFamilyIndex; - /** - * The index of the queue, within the queue family identified by the - * defaultGPUCaptureScopeQueueFamilyIndex parameter, whose presentation submissions - * will be used as the default GPU Capture Scope during debugging in Xcode. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to zero (the first queue). - */ - uint32_t defaultGPUCaptureScopeQueueIndex; + /** + * The index of the queue, within the queue family identified by the + * defaultGPUCaptureScopeQueueFamilyIndex parameter, whose presentation submissions + * will be used as the default GPU Capture Scope during debugging in Xcode. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to zero (the first queue). + */ + uint32_t defaultGPUCaptureScopeQueueIndex; - /** - * Identifies when Metal shaders will be compiled with the Metal fastMathEnabled property - * enabled. For shaders compiled with the Metal fastMathEnabled property enabled, shader - * floating point math is significantly faster, but it may cause the Metal Compiler to - * optimize floating point operations in ways that may violate the IEEE 754 standard. - * - * Enabling Metal fast math can dramatically improve shader performance, and has little - * practical effect on the numerical accuracy of most shaders. As such, disabling fast - * math should be done carefully and deliberately. For most applications, always enabling - * fast math, by setting the value of this property to MVK_CONFIG_FAST_MATH_ALWAYS, - * is the preferred choice. - * - * Apps that have specific accuracy and handling needs for particular shaders, may elect to - * set the value of this property to MVK_CONFIG_FAST_MATH_ON_DEMAND, so that fast math will - * be disabled when compiling shaders that request capabilities such as SignedZeroInfNanPreserve. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will be applied to future Metal shader compilations. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FAST_MATH_ENABLED - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to MVK_CONFIG_FAST_MATH_ALWAYS. - */ - MVKConfigFastMath fastMathEnabled; + /** + * Identifies when Metal shaders will be compiled with the Metal fastMathEnabled property + * enabled. For shaders compiled with the Metal fastMathEnabled property enabled, shader + * floating point math is significantly faster, but it may cause the Metal Compiler to + * optimize floating point operations in ways that may violate the IEEE 754 standard. + * + * Enabling Metal fast math can dramatically improve shader performance, and has little + * practical effect on the numerical accuracy of most shaders. As such, disabling fast + * math should be done carefully and deliberately. For most applications, always enabling + * fast math, by setting the value of this property to MVK_CONFIG_FAST_MATH_ALWAYS, + * is the preferred choice. + * + * Apps that have specific accuracy and handling needs for particular shaders, may elect to + * set the value of this property to MVK_CONFIG_FAST_MATH_ON_DEMAND, so that fast math will + * be disabled when compiling shaders that request capabilities such as SignedZeroInfNanPreserve. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will be applied to future Metal shader compilations. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_FAST_MATH_ENABLED + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to MVK_CONFIG_FAST_MATH_ALWAYS. + */ + MVKConfigFastMath fastMathEnabled; - /** - * Controls the level of logging performned by MoltenVK. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_LOG_LEVEL - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, errors and informational messages are logged. - */ - MVKConfigLogLevel logLevel; + /** + * Controls the level of logging performned by MoltenVK. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_LOG_LEVEL + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, errors and informational messages are logged. + */ + MVKConfigLogLevel logLevel; - /** - * Causes MoltenVK to log the name of each Vulkan call made by the application, - * along with the Mach thread ID, global system thread ID, and thread name. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect subsequent MoltenVK behaviour. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_TRACE_VULKAN_CALLS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, no Vulkan call logging will occur. - */ - MVKConfigTraceVulkanCalls traceVulkanCalls; + /** + * Causes MoltenVK to log the name of each Vulkan call made by the application, + * along with the Mach thread ID, global system thread ID, and thread name. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect subsequent MoltenVK behaviour. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_TRACE_VULKAN_CALLS + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, no Vulkan call logging will occur. + */ + MVKConfigTraceVulkanCalls traceVulkanCalls; - /** - * Force MoltenVK to use a low-power GPU, if one is availble on the device. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_FORCE_LOW_POWER_GPU - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, allowing both - * low-power and high-power GPU's to be used. - */ - VkBool32 forceLowPowerGPU; + /** + * Force MoltenVK to use a low-power GPU, if one is availble on the device. + * + * The value of this parameter must be changed before creating a VkInstance, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_FORCE_LOW_POWER_GPU + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is disabled by default, allowing both + * low-power and high-power GPU's to be used. + */ + VkBool32 forceLowPowerGPU; - /** Deprecated. Vulkan sempphores using MTLFence are no longer supported. Use semaphoreSupportStyle instead. */ - VkBool32 semaphoreUseMTLFence; + /** Deprecated. Vulkan sempphores using MTLFence are no longer supported. Use semaphoreSupportStyle instead. */ + VkBool32 semaphoreUseMTLFence; - /** - * Determines the style used to implement Vulkan semaphore (VkSemaphore) functionality in Metal. - * See the documentation of the MVKVkSemaphoreSupportStyle for the options. - * - * In the special case of VK_SEMAPHORE_TYPE_TIMELINE semaphores, MoltenVK will always use - * MTLSharedEvent if it is available on the platform, regardless of the value of this parameter. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE by default, - * and MoltenVK will use MTLEvent, except on NVIDIA GPU and Rosetta2 environments, - * or where MTLEvents are not supported, where it will use a single queue with - * implicit synchronization (as if this parameter was set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE). - * - * This parameter interacts with the deprecated legacy parameters semaphoreUseMTLEvent - * and semaphoreUseMTLFence. If semaphoreUseMTLEvent is enabled, this parameter will be - * set to MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE. - * If semaphoreUseMTLEvent is disabled, this parameter will be set to - * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE if semaphoreUseMTLFence is enabled, - * or MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK if semaphoreUseMTLFence is disabled. - * Structurally, this parameter replaces, and is aliased by, semaphoreUseMTLEvent. - */ - MVKVkSemaphoreSupportStyle semaphoreSupportStyle; + /** + * Determines the style used to implement Vulkan semaphore (VkSemaphore) functionality in Metal. + * See the documentation of the MVKVkSemaphoreSupportStyle for the options. + * + * In the special case of VK_SEMAPHORE_TYPE_TIMELINE semaphores, MoltenVK will always use + * MTLSharedEvent if it is available on the platform, regardless of the value of this parameter. + * + * The value of this parameter must be changed before creating a VkInstance, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is set to + * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE by default, + * and MoltenVK will use MTLEvent, except on NVIDIA GPU and Rosetta2 environments, + * or where MTLEvents are not supported, where it will use a single queue with + * implicit synchronization (as if this parameter was set to + * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE). + * + * This parameter interacts with the deprecated legacy parameters semaphoreUseMTLEvent + * and semaphoreUseMTLFence. If semaphoreUseMTLEvent is enabled, this parameter will be + * set to MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE. + * If semaphoreUseMTLEvent is disabled, this parameter will be set to + * MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE if semaphoreUseMTLFence is enabled, + * or MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK if semaphoreUseMTLFence is disabled. + * Structurally, this parameter replaces, and is aliased by, semaphoreUseMTLEvent. + */ + MVKVkSemaphoreSupportStyle semaphoreSupportStyle; #define semaphoreUseMTLEvent semaphoreSupportStyle - /** - * Controls whether Metal should run an automatic GPU capture without the user having to - * trigger it manually via the Xcode user interface, and controls the scope under which - * that GPU capture will occur. This is useful when trying to capture a one-shot GPU trace, - * such as when running a Vulkan CTS test case. For the automatic GPU capture to occur, the - * Xcode scheme under which the app is run must have the Metal GPU capture option enabled. - * This parameter should not be set to manually trigger a GPU capture via the Xcode user interface. - * - * When the value of this parameter is MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME, - * the queue for which the GPU activity is captured is identifed by the values of - * the defaultGPUCaptureScopeQueueFamilyIndex and defaultGPUCaptureScopeQueueIndex - * configuration parameters. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, no automatic GPU capture will occur. - */ - MVKConfigAutoGPUCaptureScope autoGPUCaptureScope; + /** + * Controls whether Metal should run an automatic GPU capture without the user having to + * trigger it manually via the Xcode user interface, and controls the scope under which + * that GPU capture will occur. This is useful when trying to capture a one-shot GPU trace, + * such as when running a Vulkan CTS test case. For the automatic GPU capture to occur, the + * Xcode scheme under which the app is run must have the Metal GPU capture option enabled. + * This parameter should not be set to manually trigger a GPU capture via the Xcode user interface. + * + * When the value of this parameter is MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME, + * the queue for which the GPU activity is captured is identifed by the values of + * the defaultGPUCaptureScopeQueueFamilyIndex and defaultGPUCaptureScopeQueueIndex + * configuration parameters. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, no automatic GPU capture will occur. + */ + MVKConfigAutoGPUCaptureScope autoGPUCaptureScope; - /** - * The path to a file where the automatic GPU capture should be saved, if autoGPUCaptureScope - * is enabled. In this case, the Xcode scheme need not have Metal GPU capture enabled, and in - * fact the app need not be run under Xcode's control at all. This is useful in case the app - * cannot be run under Xcode's control. A path starting with '~' can be used to place it in a - * user's home directory, as in the shell. This feature requires Metal 3.0 (macOS 10.15, iOS 13). - * - * If this parameter is NULL or an empty string, and autoGPUCaptureScope is enabled, automatic - * GPU capture will be handled by the Xcode user interface. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, automatic GPU capture will be handled by the Xcode user interface. - */ - const char *autoGPUCaptureOutputFilepath; + /** + * The path to a file where the automatic GPU capture should be saved, if autoGPUCaptureScope + * is enabled. In this case, the Xcode scheme need not have Metal GPU capture enabled, and in + * fact the app need not be run under Xcode's control at all. This is useful in case the app + * cannot be run under Xcode's control. A path starting with '~' can be used to place it in a + * user's home directory, as in the shell. This feature requires Metal 3.0 (macOS 10.15, iOS 13). + * + * If this parameter is NULL or an empty string, and autoGPUCaptureScope is enabled, automatic + * GPU capture will be handled by the Xcode user interface. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, automatic GPU capture will be handled by the Xcode user interface. + */ + const char* autoGPUCaptureOutputFilepath; - /** - * Controls whether MoltenVK should use a Metal 2D texture with a height of 1 for a - * Vulkan 1D image, or use a native Metal 1D texture. Metal imposes significant restrictions - * on native 1D textures, including not being renderable, clearable, or permitting mipmaps. - * Using a Metal 2D texture allows Vulkan 1D textures to support this additional functionality. - * - * The value of this parameter should only be changed before creating the VkInstance. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_TEXTURE_1D_AS_2D - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will - * use a Metal 2D texture for each Vulkan 1D image. - */ - VkBool32 texture1DAs2D; + /** + * Controls whether MoltenVK should use a Metal 2D texture with a height of 1 for a + * Vulkan 1D image, or use a native Metal 1D texture. Metal imposes significant restrictions + * on native 1D textures, including not being renderable, clearable, or permitting mipmaps. + * Using a Metal 2D texture allows Vulkan 1D textures to support this additional functionality. + * + * The value of this parameter should only be changed before creating the VkInstance. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_TEXTURE_1D_AS_2D + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is enabled by default, and MoltenVK will + * use a Metal 2D texture for each Vulkan 1D image. + */ + VkBool32 texture1DAs2D; - /** - * Controls whether MoltenVK should preallocate memory in each VkDescriptorPool according - * to the values of the VkDescriptorPoolSize parameters. Doing so may improve descriptor set - * allocation performance and memory stability at a cost of preallocated application memory. - * If this setting is disabled, the descriptors required for a descriptor set will be individually - * dynamically allocated in application memory when the descriptor set itself is allocated. - * - * The value of this parameter may be changed at any time during application runtime, and the - * changed value will affect the behavior of VkDescriptorPools created after the value is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_PREALLOCATE_DESCRIPTORS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will - * allocate a pool of descriptors when a VkDescriptorPool is created. - */ - VkBool32 preallocateDescriptors; + /** + * Controls whether MoltenVK should preallocate memory in each VkDescriptorPool according + * to the values of the VkDescriptorPoolSize parameters. Doing so may improve descriptor set + * allocation performance and memory stability at a cost of preallocated application memory. + * If this setting is disabled, the descriptors required for a descriptor set will be individually + * dynamically allocated in application memory when the descriptor set itself is allocated. + * + * The value of this parameter may be changed at any time during application runtime, and the + * changed value will affect the behavior of VkDescriptorPools created after the value is changed. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_PREALLOCATE_DESCRIPTORS + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is enabled by default, and MoltenVK will + * allocate a pool of descriptors when a VkDescriptorPool is created. + */ + VkBool32 preallocateDescriptors; - /** - * Controls whether MoltenVK should use pools to manage memory used when adding commands - * to command buffers. If this setting is enabled, MoltenVK will use a pool to hold command - * resources for reuse during command execution. If this setting is disabled, command memory - * is allocated and destroyed each time a command is executed. This is a classic time-space - * trade off. When command pooling is active, the memory in the pool can be cleared via a - * call to the vkTrimCommandPoolKHR() command. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will immediately effect behavior of VkCommandPools created - * after the setting is changed. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_COMMAND_POOLING - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is enabled by default, and MoltenVK will pool command memory. - */ - VkBool32 useCommandPooling; + /** + * Controls whether MoltenVK should use pools to manage memory used when adding commands + * to command buffers. If this setting is enabled, MoltenVK will use a pool to hold command + * resources for reuse during command execution. If this setting is disabled, command memory + * is allocated and destroyed each time a command is executed. This is a classic time-space + * trade off. When command pooling is active, the memory in the pool can be cleared via a + * call to the vkTrimCommandPoolKHR() command. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will immediately effect behavior of VkCommandPools created + * after the setting is changed. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_USE_COMMAND_POOLING + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is enabled by default, and MoltenVK will pool command memory. + */ + VkBool32 useCommandPooling; - /** - * Controls whether MoltenVK should use MTLHeaps for allocating textures and buffers - * from device memory. If this setting is enabled, and placement MTLHeaps are - * available on the platform, MoltenVK will allocate a placement MTLHeap for each VkDeviceMemory - * instance, and allocate textures and buffers from that placement heap. If this environment - * variable is disabled, MoltenVK will allocate textures and buffers from general device memory. - * - * Apple recommends that MTLHeaps should only be used for specific requirements such as aliasing - * or hazard tracking, and MoltenVK testing has shown that allocating multiple textures of - * different types or usages from one MTLHeap can occassionally cause corruption issues under - * certain circumstances. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_MTLHEAP - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, and MoltenVK - * will allocate texures and buffers from general device memory. - */ - VkBool32 useMTLHeap; + /** + * Controls whether MoltenVK should use MTLHeaps for allocating textures and buffers + * from device memory. If this setting is enabled, and placement MTLHeaps are + * available on the platform, MoltenVK will allocate a placement MTLHeap for each VkDeviceMemory + * instance, and allocate textures and buffers from that placement heap. If this environment + * variable is disabled, MoltenVK will allocate textures and buffers from general device memory. + * + * Apple recommends that MTLHeaps should only be used for specific requirements such as aliasing + * or hazard tracking, and MoltenVK testing has shown that allocating multiple textures of + * different types or usages from one MTLHeap can occassionally cause corruption issues under + * certain circumstances. + * + * The value of this parameter must be changed before creating a VkInstance, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_USE_MTLHEAP + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is disabled by default, and MoltenVK + * will allocate texures and buffers from general device memory. + */ + VkBool32 useMTLHeap; - /** - * Controls when MoltenVK should log activity performance events. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT by default, - * and activity performance will be logged when frame activity is logged. - */ - MVKConfigActivityPerformanceLoggingStyle activityPerformanceLoggingStyle; + /** + * Controls when MoltenVK should log activity performance events. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is set to + * MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT by default, + * and activity performance will be logged when frame activity is logged. + */ + MVKConfigActivityPerformanceLoggingStyle activityPerformanceLoggingStyle; #define logActivityPerformanceInline activityPerformanceLoggingStyle - /** - * Controls the Vulkan API version that MoltenVK should advertise in vkEnumerateInstanceVersion(). - * When reading this value, it will be one of the VK_API_VERSION_1_* values, including the latest - * VK_HEADER_VERSION component. When setting this value, it should be set to one of: - * - * VK_API_VERSION_1_2 (equivalent decimal number 4202496) - * VK_API_VERSION_1_1 (equivalent decimal number 4198400) - * VK_API_VERSION_1_0 (equivalent decimal number 4194304) - * - * MoltenVK will automatically add the VK_HEADER_VERSION component. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_API_VERSION_TO_ADVERTISE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this parameter defaults to the highest API version - * currently supported by MoltenVK, including the latest VK_HEADER_VERSION component. - */ - uint32_t apiVersionToAdvertise; + /** + * Controls the Vulkan API version that MoltenVK should advertise in vkEnumerateInstanceVersion(). + * When reading this value, it will be one of the VK_API_VERSION_1_* values, including the latest + * VK_HEADER_VERSION component. When setting this value, it should be set to one of: + * + * VK_API_VERSION_1_2 (equivalent decimal number 4202496) + * VK_API_VERSION_1_1 (equivalent decimal number 4198400) + * VK_API_VERSION_1_0 (equivalent decimal number 4194304) + * + * MoltenVK will automatically add the VK_HEADER_VERSION component. + * + * The value of this parameter must be changed before creating a VkInstance, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_API_VERSION_TO_ADVERTISE + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this parameter defaults to the highest API version + * currently supported by MoltenVK, including the latest VK_HEADER_VERSION component. + */ + uint32_t apiVersionToAdvertise; - /** - * Controls which extensions MoltenVK should advertise it supports in - * vkEnumerateInstanceExtensionProperties() and vkEnumerateDeviceExtensionProperties(). - * The value of this parameter is a bitwise OR of values from the MVKConfigAdvertiseExtensionBits - * enumeration. Any prerequisite extensions are also advertised. - * If the flag MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL is included, all supported extensions - * will be advertised. A value of zero means no extensions will be advertised. - * - * The value of this parameter must be changed before creating a VkInstance, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_ADVERTISE_EXTENSIONS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, the value of this setting defaults to - * MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL, and all supported extensions will be advertised. - */ - MVKConfigAdvertiseExtensions advertiseExtensions; + /** + * Controls which extensions MoltenVK should advertise it supports in + * vkEnumerateInstanceExtensionProperties() and vkEnumerateDeviceExtensionProperties(). + * The value of this parameter is a bitwise OR of values from the MVKConfigAdvertiseExtensionBits + * enumeration. Any prerequisite extensions are also advertised. + * If the flag MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL is included, all supported extensions + * will be advertised. A value of zero means no extensions will be advertised. + * + * The value of this parameter must be changed before creating a VkInstance, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_ADVERTISE_EXTENSIONS + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, the value of this setting defaults to + * MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL, and all supported extensions will be advertised. + */ + MVKConfigAdvertiseExtensions advertiseExtensions; - /** - * Controls whether MoltenVK should treat a lost VkDevice as resumable, unless the - * corresponding VkPhysicalDevice has also been lost. The VK_ERROR_DEVICE_LOST error has - * a broad definitional range, and can mean anything from a GPU hiccup on the current - * command buffer submission, to a physically removed GPU. In the case where this error does - * not impact the VkPhysicalDevice, Vulkan requires that the app destroy and re-create a new - * VkDevice. However, not all apps (including CTS) respect that requirement, leading to what - * might be a transient command submission failure causing an unexpected catastrophic app failure. - * - * If this setting is enabled, in the case of a VK_ERROR_DEVICE_LOST error that does NOT impact - * the VkPhysicalDevice, MoltenVK will log the error, but will not mark the VkDevice as lost, - * allowing the VkDevice to continue to be used. If this setting is disabled, MoltenVK will - * mark the VkDevice as lost, and subsequent use of that VkDevice will be reduced or prohibited. - * - * The value of this parameter may be changed at any time during application runtime, - * and the changed value will affect the error behavior of subsequent command submissions. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_RESUME_LOST_DEVICE - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is disabled by default, and MoltenVK - * will mark the VkDevice as lost when a command submission failure occurs. - */ - VkBool32 resumeLostDevice; + /** + * Controls whether MoltenVK should treat a lost VkDevice as resumable, unless the + * corresponding VkPhysicalDevice has also been lost. The VK_ERROR_DEVICE_LOST error has + * a broad definitional range, and can mean anything from a GPU hiccup on the current + * command buffer submission, to a physically removed GPU. In the case where this error does + * not impact the VkPhysicalDevice, Vulkan requires that the app destroy and re-create a new + * VkDevice. However, not all apps (including CTS) respect that requirement, leading to what + * might be a transient command submission failure causing an unexpected catastrophic app failure. + * + * If this setting is enabled, in the case of a VK_ERROR_DEVICE_LOST error that does NOT impact + * the VkPhysicalDevice, MoltenVK will log the error, but will not mark the VkDevice as lost, + * allowing the VkDevice to continue to be used. If this setting is disabled, MoltenVK will + * mark the VkDevice as lost, and subsequent use of that VkDevice will be reduced or prohibited. + * + * The value of this parameter may be changed at any time during application runtime, + * and the changed value will affect the error behavior of subsequent command submissions. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_RESUME_LOST_DEVICE + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is disabled by default, and MoltenVK + * will mark the VkDevice as lost when a command submission failure occurs. + */ + VkBool32 resumeLostDevice; - /** - * Controls whether MoltenVK should use Metal argument buffers for resources defined in - * descriptor sets, if Metal argument buffers are supported on the platform. Using Metal - * argument buffers dramatically increases the number of buffers, textures and samplers - * that can be bound to a pipeline shader, and in most cases improves performance. - * This setting is an enumeration that specifies the conditions under which MoltenVK - * will use Metal argument buffers. - * - * NOTE: Currently, Metal argument buffer support is in beta stage, and is only supported - * on macOS 11.0 (Big Sur) or later, or on older versions of macOS using an Intel GPU. - * Metal argument buffers support is not available on iOS. Development to support iOS - * and a wider combination of GPU's on older macOS versions is under way. - * - * The value of this parameter must be changed before creating a VkDevice, - * for the change to take effect. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER by default, - * and MoltenVK will not use Metal argument buffers. - */ - MVKUseMetalArgumentBuffers useMetalArgumentBuffers; + /** + * Controls whether MoltenVK should use Metal argument buffers for resources defined in + * descriptor sets, if Metal argument buffers are supported on the platform. Using Metal + * argument buffers dramatically increases the number of buffers, textures and samplers + * that can be bound to a pipeline shader, and in most cases improves performance. + * This setting is an enumeration that specifies the conditions under which MoltenVK + * will use Metal argument buffers. + * + * NOTE: Currently, Metal argument buffer support is in beta stage, and is only supported + * on macOS 11.0 (Big Sur) or later, or on older versions of macOS using an Intel GPU. + * Metal argument buffers support is not available on iOS. Development to support iOS + * and a wider combination of GPU's on older macOS versions is under way. + * + * The value of this parameter must be changed before creating a VkDevice, + * for the change to take effect. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is set to + * MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER by default, + * and MoltenVK will not use Metal argument buffers. + */ + MVKUseMetalArgumentBuffers useMetalArgumentBuffers; - /** - * Controls the type of compression to use on the MSL source code that is stored in memory - * for use in a pipeline cache. After being converted from SPIR-V, or loaded directly into - * a VkShaderModule, and then compiled into a MTLLibrary, the MSL source code is no longer - * needed for operation, but it is retained so it can be written out as part of a pipeline - * cache export. When a large number of shaders are loaded, this can consume significant - * memory. In such a case, this parameter can be used to compress the MSL source code that - * is awaiting export as part of a pipeline cache. - * - * Pipeline cache compression is available for macOS 10.15 and above, and iOS/tvOS 13.0 and above. - * - * The value of this parameter can be changed at any time, and will affect the size of - * the cached MSL from subsequent shader compilations. - * - * The initial value or this parameter is set by the - * MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM - * runtime environment variable or MoltenVK compile-time build setting. - * If neither is set, this setting is set to - * MVK_CONFIG_COMPRESSION_ALGORITHM_NONE by default, - * and MoltenVK will not compress the MSL source code after compilation into a MTLLibrary. - */ - MVKConfigCompressionAlgorithm shaderSourceCompressionAlgorithm; + /** + * Controls the type of compression to use on the MSL source code that is stored in memory + * for use in a pipeline cache. After being converted from SPIR-V, or loaded directly into + * a VkShaderModule, and then compiled into a MTLLibrary, the MSL source code is no longer + * needed for operation, but it is retained so it can be written out as part of a pipeline + * cache export. When a large number of shaders are loaded, this can consume significant + * memory. In such a case, this parameter can be used to compress the MSL source code that + * is awaiting export as part of a pipeline cache. + * + * Pipeline cache compression is available for macOS 10.15 and above, and iOS/tvOS 13.0 and above. + * + * The value of this parameter can be changed at any time, and will affect the size of + * the cached MSL from subsequent shader compilations. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this setting is set to + * MVK_CONFIG_COMPRESSION_ALGORITHM_NONE by default, + * and MoltenVK will not compress the MSL source code after compilation into a MTLLibrary. + */ + MVKConfigCompressionAlgorithm shaderSourceCompressionAlgorithm; + + /** + * Maximize the concurrent executing compilation tasks. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION + * runtime environment variable or MoltenVK compile-time build setting. + * This setting requires macOS 13.3 & is disabled by default. + */ + VkBool32 shouldMaximizeConcurrentCompilation; } MVKConfiguration; + + #pragma mark - #pragma mark Function types -typedef VkResult(VKAPI_PTR *PFN_vkGetMoltenVKConfigurationMVK)(VkInstance ignored, MVKConfiguration *pConfiguration, size_t *pConfigurationSize); -typedef VkResult(VKAPI_PTR *PFN_vkSetMoltenVKConfigurationMVK)(VkInstance ignored, const MVKConfiguration *pConfiguration, size_t *pConfigurationSize); + typedef VkResult (VKAPI_PTR *PFN_vkGetMoltenVKConfigurationMVK)(VkInstance ignored, MVKConfiguration* pConfiguration, size_t* pConfigurationSize); + typedef VkResult (VKAPI_PTR *PFN_vkSetMoltenVKConfigurationMVK)(VkInstance ignored, const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); + #pragma mark - #pragma mark Function prototypes @@ -954,9 +973,9 @@ typedef VkResult(VKAPI_PTR *PFN_vkSetMoltenVKConfigurationMVK)(VkInstance ignore * expects MVKConfiguration to be. */ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( - VkInstance ignored, - MVKConfiguration *pConfiguration, - size_t *pConfigurationSize); + VkInstance ignored, + MVKConfiguration* pConfiguration, + size_t* pConfigurationSize); /** * Sets the MoltenVK configuration settings to those found in the pConfiguration structure. @@ -992,59 +1011,61 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( * expects MVKConfiguration to be. */ VKAPI_ATTR VkResult VKAPI_CALL vkSetMoltenVKConfigurationMVK( - VkInstance ignored, - const MVKConfiguration *pConfiguration, - size_t *pConfigurationSize); + VkInstance ignored, + const MVKConfiguration* pConfiguration, + size_t* pConfigurationSize); + #pragma mark - #pragma mark Shaders -/** - * NOTE: Shader code should be submitted as SPIR-V. Although some simple direct MSL shaders may work, - * direct loading of MSL source code or compiled MSL code is not officially supported at this time. - * Future versions of MoltenVK may support direct MSL submission again. - * - * Enumerates the magic number values to set in the MVKMSLSPIRVHeader when - * submitting a SPIR-V stream that contains either Metal Shading Language source - * code or Metal Shading Language compiled binary code in place of SPIR-V code. - */ -typedef enum { - kMVKMagicNumberSPIRVCode = 0x07230203, /**< SPIR-V stream contains standard SPIR-V code. */ - kMVKMagicNumberMSLSourceCode = 0x19960412, /**< SPIR-V stream contains Metal Shading Language source code. */ - kMVKMagicNumberMSLCompiledCode = 0x19981215, /**< SPIR-V stream contains Metal Shading Language compiled binary code. */ -} MVKMSLMagicNumber; + /** + * NOTE: Shader code should be submitted as SPIR-V. Although some simple direct MSL shaders may work, + * direct loading of MSL source code or compiled MSL code is not officially supported at this time. + * Future versions of MoltenVK may support direct MSL submission again. + * + * Enumerates the magic number values to set in the MVKMSLSPIRVHeader when + * submitting a SPIR-V stream that contains either Metal Shading Language source + * code or Metal Shading Language compiled binary code in place of SPIR-V code. + */ + typedef enum { + kMVKMagicNumberSPIRVCode = 0x07230203, /**< SPIR-V stream contains standard SPIR-V code. */ + kMVKMagicNumberMSLSourceCode = 0x19960412, /**< SPIR-V stream contains Metal Shading Language source code. */ + kMVKMagicNumberMSLCompiledCode = 0x19981215, /**< SPIR-V stream contains Metal Shading Language compiled binary code. */ + } MVKMSLMagicNumber; + + /** + * NOTE: Shader code should be submitted as SPIR-V. Although some simple direct MSL shaders may work, + * direct loading of MSL source code or compiled MSL code is not officially supported at this time. + * Future versions of MoltenVK may support direct MSL submission again. + * + * Describes the header at the start of an SPIR-V stream, when it contains either + * Metal Shading Language source code or Metal Shading Language compiled binary code. + * + * To submit MSL source code to the vkCreateShaderModule() function in place of SPIR-V + * code, prepend a MVKMSLSPIRVHeader containing the kMVKMagicNumberMSLSourceCode magic + * number to the MSL source code. The MSL source code must be null-terminated. + * + * To submit MSL compiled binary code to the vkCreateShaderModule() function in place of + * SPIR-V code, prepend a MVKMSLSPIRVHeader containing the kMVKMagicNumberMSLCompiledCode + * magic number to the MSL compiled binary code. + * + * In both cases, the pCode element of VkShaderModuleCreateInfo should pointer to the + * location of the MVKMSLSPIRVHeader, and the MSL code should start at the byte immediately + * after the MVKMSLSPIRVHeader. + * + * The codeSize element of VkShaderModuleCreateInfo should be set to the entire size of + * the submitted code memory, including the additional sizeof(MVKMSLSPIRVHeader) bytes + * taken up by the MVKMSLSPIRVHeader, and, in the case of MSL source code, including + * the null-terminator byte. + */ + typedef uint32_t MVKMSLSPIRVHeader; -/** - * NOTE: Shader code should be submitted as SPIR-V. Although some simple direct MSL shaders may work, - * direct loading of MSL source code or compiled MSL code is not officially supported at this time. - * Future versions of MoltenVK may support direct MSL submission again. - * - * Describes the header at the start of an SPIR-V stream, when it contains either - * Metal Shading Language source code or Metal Shading Language compiled binary code. - * - * To submit MSL source code to the vkCreateShaderModule() function in place of SPIR-V - * code, prepend a MVKMSLSPIRVHeader containing the kMVKMagicNumberMSLSourceCode magic - * number to the MSL source code. The MSL source code must be null-terminated. - * - * To submit MSL compiled binary code to the vkCreateShaderModule() function in place of - * SPIR-V code, prepend a MVKMSLSPIRVHeader containing the kMVKMagicNumberMSLCompiledCode - * magic number to the MSL compiled binary code. - * - * In both cases, the pCode element of VkShaderModuleCreateInfo should pointer to the - * location of the MVKMSLSPIRVHeader, and the MSL code should start at the byte immediately - * after the MVKMSLSPIRVHeader. - * - * The codeSize element of VkShaderModuleCreateInfo should be set to the entire size of - * the submitted code memory, including the additional sizeof(MVKMSLSPIRVHeader) bytes - * taken up by the MVKMSLSPIRVHeader, and, in the case of MSL source code, including - * the null-terminator byte. - */ -typedef uint32_t MVKMSLSPIRVHeader; #endif // VK_NO_PROTOTYPES #ifdef __cplusplus } -#endif // __cplusplus +#endif // __cplusplus #endif diff --git a/external/SPIRV-Cross b/external/SPIRV-Cross index 4e2fdb256..bccaa94db 160000 --- a/external/SPIRV-Cross +++ b/external/SPIRV-Cross @@ -1 +1 @@ -Subproject commit 4e2fdb25671c742a9fbe93a6034eb1542244c7e1 +Subproject commit bccaa94db814af33d8ef05c153e7c34d8bd4d685 diff --git a/external/Vulkan-Headers b/external/Vulkan-Headers index ed857118e..450ead13e 160000 --- a/external/Vulkan-Headers +++ b/external/Vulkan-Headers @@ -1 +1 @@ -Subproject commit ed857118e243fdc0f3a100f00ac9919e874cfe63 +Subproject commit 450ead13e1064584da027d91192bd7bfb724640f diff --git a/external/capstone b/external/capstone index 6eb1db9c0..097c04d94 160000 --- a/external/capstone +++ b/external/capstone @@ -1 +1 @@ -Subproject commit 6eb1db9c04113ac0a05f2dfd228704c84775530f +Subproject commit 097c04d9413c59a58b00d4d1c8d5dc0ac158ffaa diff --git a/external/cli11/CLI11.hpp b/external/cli11/CLI11.hpp index f29a5c4e1..3913fa9ca 100644 --- a/external/cli11/CLI11.hpp +++ b/external/cli11/CLI11.hpp @@ -1,11 +1,11 @@ -// CLI11: Version 2.2.0 +// CLI11: Version 2.3.2 // Originally designed by Henry Schreiner // https://github.com/CLIUtils/CLI11 // // This is a standalone header file generated by MakeSingleHeader.py in CLI11/scripts -// from: v2.2.0 +// from: v2.3.2 // -// CLI11 2.2.0 Copyright (c) 2017-2022 University of Cincinnati, developed by Henry +// CLI11 2.3.2 Copyright (c) 2017-2022 University of Cincinnati, developed by Henry // Schreiner under NSF AWARD 1414736. All rights reserved. // // Redistribution and use in source and binary forms of CLI11, with or without @@ -34,34 +34,34 @@ #pragma once // Standard combined includes: -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include #include -#include -#include +#include #include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include +#include #include -#include #define CLI11_VERSION_MAJOR 2 -#define CLI11_VERSION_MINOR 2 -#define CLI11_VERSION_PATCH 0 -#define CLI11_VERSION "2.2.0" +#define CLI11_VERSION_MINOR 3 +#define CLI11_VERSION_PATCH 2 +#define CLI11_VERSION "2.3.2" @@ -99,6 +99,14 @@ #define CLI11_DEPRECATED(reason) __attribute__((deprecated(reason))) #endif +// GCC < 10 doesn't ignore this in unevaluated contexts +#if !defined(CLI11_CPP17) || \ + (defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && __GNUC__ < 10 && __GNUC__ > 4) +#define CLI11_NODISCARD +#else +#define CLI11_NODISCARD [[nodiscard]] +#endif + /** detection of rtti */ #ifndef CLI11_USE_STATIC_RTTI #if(defined(_HAS_STATIC_RTTI) && _HAS_STATIC_RTTI) @@ -116,6 +124,13 @@ #endif #endif +/** Inline macro **/ +#ifdef CLI11_COMPILE +#define CLI11_INLINE +#else +#define CLI11_INLINE inline +#endif + // C standard library @@ -180,21 +195,7 @@ namespace detail { constexpr int expected_max_vector_size{1 << 29}; // Based on http://stackoverflow.com/questions/236129/split-a-string-in-c /// Split a string by a delim -inline std::vector split(const std::string &s, char delim) { - std::vector elems; - // Check to see if empty string, give consistent result - if(s.empty()) { - elems.emplace_back(); - } else { - std::stringstream ss; - ss.str(s); - std::string item; - while(std::getline(ss, item, delim)) { - elems.push_back(item); - } - } - return elems; -} +CLI11_INLINE std::vector split(const std::string &s, char delim); /// Simple function to join a string template std::string join(const T &v, std::string delim = ",") { @@ -243,33 +244,16 @@ template std::string rjoin(const T &v, std::string delim = ",") { // Based roughly on http://stackoverflow.com/questions/25829143/c-trim-whitespace-from-a-string /// Trim whitespace from left of string -inline std::string <rim(std::string &str) { - auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace(ch, std::locale()); }); - str.erase(str.begin(), it); - return str; -} +CLI11_INLINE std::string <rim(std::string &str); /// Trim anything from left of string -inline std::string <rim(std::string &str, const std::string &filter) { - auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); - str.erase(str.begin(), it); - return str; -} +CLI11_INLINE std::string <rim(std::string &str, const std::string &filter); /// Trim whitespace from right of string -inline std::string &rtrim(std::string &str) { - auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace(ch, std::locale()); }); - str.erase(it.base(), str.end()); - return str; -} +CLI11_INLINE std::string &rtrim(std::string &str); /// Trim anything from right of string -inline std::string &rtrim(std::string &str, const std::string &filter) { - auto it = - std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); - str.erase(it.base(), str.end()); - return str; -} +CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter); /// Trim whitespace from string inline std::string &trim(std::string &str) { return ltrim(rtrim(str)); } @@ -284,31 +268,13 @@ inline std::string trim_copy(const std::string &str) { } /// remove quotes at the front and back of a string either '"' or '\'' -inline std::string &remove_quotes(std::string &str) { - if(str.length() > 1 && (str.front() == '"' || str.front() == '\'')) { - if(str.front() == str.back()) { - str.pop_back(); - str.erase(str.begin(), str.begin() + 1); - } - } - return str; -} +CLI11_INLINE std::string &remove_quotes(std::string &str); /// Add a leader to the beginning of all new lines (nothing is added /// at the start of the first line). `"; "` would be for ini files /// /// Can't use Regex, or this would be a subs. -inline std::string fix_newlines(const std::string &leader, std::string input) { - std::string::size_type n = 0; - while(n != std::string::npos && n < input.size()) { - n = input.find('\n', n); - if(n != std::string::npos) { - input = input.substr(0, n + 1) + leader + input.substr(n + 1); - n += leader.size(); - } - } - return input; -} +CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input); /// Make a copy of the string and then trim it, any filter string can be used (any char in string is filtered) inline std::string trim_copy(const std::string &str, const std::string &filter) { @@ -316,40 +282,11 @@ inline std::string trim_copy(const std::string &str, const std::string &filter) return trim(s, filter); } /// Print a two part "help" string -inline std::ostream &format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) { - name = " " + name; - out << std::setw(static_cast(wid)) << std::left << name; - if(!description.empty()) { - if(name.length() >= wid) - out << "\n" << std::setw(static_cast(wid)) << ""; - for(const char c : description) { - out.put(c); - if(c == '\n') { - out << std::setw(static_cast(wid)) << ""; - } - } - } - out << "\n"; - return out; -} +CLI11_INLINE std::ostream & +format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid); /// Print subcommand aliases -inline std::ostream &format_aliases(std::ostream &out, const std::vector &aliases, std::size_t wid) { - if(!aliases.empty()) { - out << std::setw(static_cast(wid)) << " aliases: "; - bool front = true; - for(const auto &alias : aliases) { - if(!front) { - out << ", "; - } else { - front = false; - } - out << detail::fix_newlines(" ", alias); - } - out << "\n"; - } - return out; -} +CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector &aliases, std::size_t wid); /// Verify the first character of an option /// - is a trigger character, ! has special meaning and new lines would just be annoying to deal with @@ -364,16 +301,7 @@ template bool valid_later_char(T c) { } /// Verify an option/subcommand name -inline bool valid_name_string(const std::string &str) { - if(str.empty() || !valid_first_char(str[0])) { - return false; - } - auto e = str.end(); - for(auto c = str.begin() + 1; c != e; ++c) - if(!valid_later_char(*c)) - return false; - return true; -} +CLI11_INLINE bool valid_name_string(const std::string &str); /// Verify an app name inline bool valid_alias_name_string(const std::string &str) { @@ -407,7 +335,160 @@ inline std::string remove_underscore(std::string str) { } /// Find and replace a substring with another substring -inline std::string find_and_replace(std::string str, std::string from, std::string to) { +CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to); + +/// check if the flag definitions has possible false flags +inline bool has_default_flag_values(const std::string &flags) { + return (flags.find_first_of("{!") != std::string::npos); +} + +CLI11_INLINE void remove_default_flag_values(std::string &flags); + +/// Check if a string is a member of a list of strings and optionally ignore case or ignore underscores +CLI11_INLINE std::ptrdiff_t find_member(std::string name, + const std::vector names, + bool ignore_case = false, + bool ignore_underscore = false); + +/// Find a trigger string and call a modify callable function that takes the current string and starting position of the +/// trigger and returns the position in the string to search for the next trigger string +template inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) { + std::size_t start_pos = 0; + while((start_pos = str.find(trigger, start_pos)) != std::string::npos) { + start_pos = modify(str, start_pos); + } + return str; +} + +/// Split a string '"one two" "three"' into 'one two', 'three' +/// Quote characters can be ` ' or " +CLI11_INLINE std::vector split_up(std::string str, char delimiter = '\0'); + +/// This function detects an equal or colon followed by an escaped quote after an argument +/// then modifies the string to replace the equality with a space. This is needed +/// to allow the split up function to work properly and is intended to be used with the find_and_modify function +/// the return value is the offset+1 which is required by the find_and_modify function. +CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset); + +/// Add quotes if the string contains spaces +CLI11_INLINE std::string &add_quotes_if_needed(std::string &str); + +} // namespace detail + + + + +namespace detail { +CLI11_INLINE std::vector split(const std::string &s, char delim) { + std::vector elems; + // Check to see if empty string, give consistent result + if(s.empty()) { + elems.emplace_back(); + } else { + std::stringstream ss; + ss.str(s); + std::string item; + while(std::getline(ss, item, delim)) { + elems.push_back(item); + } + } + return elems; +} + +CLI11_INLINE std::string <rim(std::string &str) { + auto it = std::find_if(str.begin(), str.end(), [](char ch) { return !std::isspace(ch, std::locale()); }); + str.erase(str.begin(), it); + return str; +} + +CLI11_INLINE std::string <rim(std::string &str, const std::string &filter) { + auto it = std::find_if(str.begin(), str.end(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); + str.erase(str.begin(), it); + return str; +} + +CLI11_INLINE std::string &rtrim(std::string &str) { + auto it = std::find_if(str.rbegin(), str.rend(), [](char ch) { return !std::isspace(ch, std::locale()); }); + str.erase(it.base(), str.end()); + return str; +} + +CLI11_INLINE std::string &rtrim(std::string &str, const std::string &filter) { + auto it = + std::find_if(str.rbegin(), str.rend(), [&filter](char ch) { return filter.find(ch) == std::string::npos; }); + str.erase(it.base(), str.end()); + return str; +} + +CLI11_INLINE std::string &remove_quotes(std::string &str) { + if(str.length() > 1 && (str.front() == '"' || str.front() == '\'')) { + if(str.front() == str.back()) { + str.pop_back(); + str.erase(str.begin(), str.begin() + 1); + } + } + return str; +} + +CLI11_INLINE std::string fix_newlines(const std::string &leader, std::string input) { + std::string::size_type n = 0; + while(n != std::string::npos && n < input.size()) { + n = input.find('\n', n); + if(n != std::string::npos) { + input = input.substr(0, n + 1) + leader + input.substr(n + 1); + n += leader.size(); + } + } + return input; +} + +CLI11_INLINE std::ostream & +format_help(std::ostream &out, std::string name, const std::string &description, std::size_t wid) { + name = " " + name; + out << std::setw(static_cast(wid)) << std::left << name; + if(!description.empty()) { + if(name.length() >= wid) + out << "\n" << std::setw(static_cast(wid)) << ""; + for(const char c : description) { + out.put(c); + if(c == '\n') { + out << std::setw(static_cast(wid)) << ""; + } + } + } + out << "\n"; + return out; +} + +CLI11_INLINE std::ostream &format_aliases(std::ostream &out, const std::vector &aliases, std::size_t wid) { + if(!aliases.empty()) { + out << std::setw(static_cast(wid)) << " aliases: "; + bool front = true; + for(const auto &alias : aliases) { + if(!front) { + out << ", "; + } else { + front = false; + } + out << detail::fix_newlines(" ", alias); + } + out << "\n"; + } + return out; +} + +CLI11_INLINE bool valid_name_string(const std::string &str) { + if(str.empty() || !valid_first_char(str[0])) { + return false; + } + auto e = str.end(); + for(auto c = str.begin() + 1; c != e; ++c) + if(!valid_later_char(*c)) + return false; + return true; +} + +CLI11_INLINE std::string find_and_replace(std::string str, std::string from, std::string to) { std::size_t start_pos = 0; @@ -419,12 +500,7 @@ inline std::string find_and_replace(std::string str, std::string from, std::stri return str; } -/// check if the flag definitions has possible false flags -inline bool has_default_flag_values(const std::string &flags) { - return (flags.find_first_of("{!") != std::string::npos); -} - -inline void remove_default_flag_values(std::string &flags) { +CLI11_INLINE void remove_default_flag_values(std::string &flags) { auto loc = flags.find_first_of('{', 2); while(loc != std::string::npos) { auto finish = flags.find_first_of("},", loc + 1); @@ -437,11 +513,8 @@ inline void remove_default_flag_values(std::string &flags) { flags.erase(std::remove(flags.begin(), flags.end(), '!'), flags.end()); } -/// Check if a string is a member of a list of strings and optionally ignore case or ignore underscores -inline std::ptrdiff_t find_member(std::string name, - const std::vector names, - bool ignore_case = false, - bool ignore_underscore = false) { +CLI11_INLINE std::ptrdiff_t +find_member(std::string name, const std::vector names, bool ignore_case, bool ignore_underscore) { auto it = std::end(names); if(ignore_case) { if(ignore_underscore) { @@ -468,23 +541,11 @@ inline std::ptrdiff_t find_member(std::string name, return (it != std::end(names)) ? (it - std::begin(names)) : (-1); } -/// Find a trigger string and call a modify callable function that takes the current string and starting position of the -/// trigger and returns the position in the string to search for the next trigger string -template inline std::string find_and_modify(std::string str, std::string trigger, Callable modify) { - std::size_t start_pos = 0; - while((start_pos = str.find(trigger, start_pos)) != std::string::npos) { - start_pos = modify(str, start_pos); - } - return str; -} - -/// Split a string '"one two" "three"' into 'one two', 'three' -/// Quote characters can be ` ' or " -inline std::vector split_up(std::string str, char delimiter = '\0') { +CLI11_INLINE std::vector split_up(std::string str, char delimiter) { const std::string delims("\'\"`"); auto find_ws = [delimiter](char ch) { - return (delimiter == '\0') ? (std::isspace(ch, std::locale()) != 0) : (ch == delimiter); + return (delimiter == '\0') ? std::isspace(ch, std::locale()) : (ch == delimiter); }; trim(str); @@ -532,11 +593,7 @@ inline std::vector split_up(std::string str, char delimiter = '\0') return output; } -/// This function detects an equal or colon followed by an escaped quote after an argument -/// then modifies the string to replace the equality with a space. This is needed -/// to allow the split up function to work properly and is intended to be used with the find_and_modify function -/// the return value is the offset+1 which is required by the find_and_modify function. -inline std::size_t escape_detect(std::string &str, std::size_t offset) { +CLI11_INLINE std::size_t escape_detect(std::string &str, std::size_t offset) { auto next = str[offset + 1]; if((next == '\"') || (next == '\'') || (next == '`')) { auto astart = str.find_last_of("-/ \"\'`", offset - 1); @@ -548,8 +605,7 @@ inline std::size_t escape_detect(std::string &str, std::size_t offset) { return offset + 1; } -/// Add quotes if the string contains spaces -inline std::string &add_quotes_if_needed(std::string &str) { +CLI11_INLINE std::string &add_quotes_if_needed(std::string &str) { if((str.front() != '"' && str.front() != '\'') || str.front() != str.back()) { char quote = str.find('"') < str.find('\'') ? '\'' : '"'; if(str.find(' ') != std::string::npos) { @@ -564,7 +620,6 @@ inline std::string &add_quotes_if_needed(std::string &str) { - // Use one of these on all error classes. // These are temporary and are undef'd at the end of this file. #define CLI11_ERROR_DEF(parent, name) \ @@ -617,9 +672,9 @@ class Error : public std::runtime_error { std::string error_name{"Error"}; public: - int get_exit_code() const { return actual_exit_code; } + CLI11_NODISCARD int get_exit_code() const { return actual_exit_code; } - std::string get_name() const { return error_name; } + CLI11_NODISCARD std::string get_name() const { return error_name; } Error(std::string name, std::string msg, int exit_code = static_cast(ExitCodes::BaseClass)) : runtime_error(msg), actual_exit_code(exit_code), error_name(std::move(name)) {} @@ -682,10 +737,10 @@ class OptionAlreadyAdded : public ConstructionError { explicit OptionAlreadyAdded(std::string name) : OptionAlreadyAdded(name + " is already added", ExitCodes::OptionAlreadyAdded) {} static OptionAlreadyAdded Requires(std::string name, std::string other) { - return OptionAlreadyAdded(name + " requires " + other, ExitCodes::OptionAlreadyAdded); + return {name + " requires " + other, ExitCodes::OptionAlreadyAdded}; } static OptionAlreadyAdded Excludes(std::string name, std::string other) { - return OptionAlreadyAdded(name + " excludes " + other, ExitCodes::OptionAlreadyAdded); + return {name + " excludes " + other, ExitCodes::OptionAlreadyAdded}; } }; @@ -768,32 +823,30 @@ class RequiredError : public ParseError { if(min_subcom == 1) { return RequiredError("A subcommand"); } - return RequiredError("Requires at least " + std::to_string(min_subcom) + " subcommands", - ExitCodes::RequiredError); + return {"Requires at least " + std::to_string(min_subcom) + " subcommands", ExitCodes::RequiredError}; } static RequiredError Option(std::size_t min_option, std::size_t max_option, std::size_t used, const std::string &option_list) { if((min_option == 1) && (max_option == 1) && (used == 0)) return RequiredError("Exactly 1 option from [" + option_list + "]"); if((min_option == 1) && (max_option == 1) && (used > 1)) { - return RequiredError("Exactly 1 option from [" + option_list + "] is required and " + std::to_string(used) + - " were given", - ExitCodes::RequiredError); + return {"Exactly 1 option from [" + option_list + "] is required and " + std::to_string(used) + + " were given", + ExitCodes::RequiredError}; } if((min_option == 1) && (used == 0)) return RequiredError("At least 1 option from [" + option_list + "]"); if(used < min_option) { - return RequiredError("Requires at least " + std::to_string(min_option) + " options used and only " + - std::to_string(used) + "were given from [" + option_list + "]", - ExitCodes::RequiredError); + return {"Requires at least " + std::to_string(min_option) + " options used and only " + + std::to_string(used) + "were given from [" + option_list + "]", + ExitCodes::RequiredError}; } if(max_option == 1) - return RequiredError("Requires at most 1 options be given from [" + option_list + "]", - ExitCodes::RequiredError); + return {"Requires at most 1 options be given from [" + option_list + "]", ExitCodes::RequiredError}; - return RequiredError("Requires at most " + std::to_string(max_option) + " options be used and " + - std::to_string(used) + "were given from [" + option_list + "]", - ExitCodes::RequiredError); + return {"Requires at most " + std::to_string(max_option) + " options be used and " + std::to_string(used) + + "were given from [" + option_list + "]", + ExitCodes::RequiredError}; } }; @@ -919,7 +972,9 @@ constexpr enabler dummy = {}; template using enable_if_t = typename std::enable_if::type; /// A copy of std::void_t from C++17 (helper for C++11 and C++14) -template struct make_void { using type = void; }; +template struct make_void { + using type = void; +}; /// A copy of std::void_t from C++17 - same reasoning as enable_if_t, it does not hurt to redefine template using void_t = typename make_void::type; @@ -948,10 +1003,14 @@ template struct is_copyable_ptr { }; /// This can be specialized to override the type deduction for IsMember. -template struct IsMemberType { using type = T; }; +template struct IsMemberType { + using type = T; +}; /// The main custom type needed here is const char * should be a string. -template <> struct IsMemberType { using type = std::string; }; +template <> struct IsMemberType { + using type = std::string; +}; namespace detail { @@ -961,7 +1020,9 @@ namespace detail { /// pointer_traits be valid. /// not a pointer -template struct element_type { using type = T; }; +template struct element_type { + using type = T; +}; template struct element_type::value>::type> { using type = typename std::pointer_traits::element_type; @@ -969,7 +1030,9 @@ template struct element_type struct element_value_type { using type = typename element_type::type::value_type; }; +template struct element_value_type { + using type = typename element_type::type::value_type; +}; /// Adaptor for set-like structure: This just wraps a normal container in a few utilities that do almost nothing. template struct pair_adaptor : std::false_type { @@ -1026,7 +1089,7 @@ template class is_direct_constructible { #ifdef __CUDACC__ #pragma diag_suppress 2361 #endif - TT { std::declval() } + TT{std::declval()} #ifdef __CUDACC__ #pragma diag_default 2361 #endif @@ -1153,7 +1216,7 @@ template ::value && !std::is_convertible::value, detail::enabler> = detail::dummy> std::string to_string(const T &value) { - return std::string(value); + return std::string(value); // NOLINT(google-readability-casting) } /// Convert an object to a string (streaming must be supported for that type) @@ -1173,7 +1236,7 @@ template ::type>::value, detail::enabler> = detail::dummy> std::string to_string(T &&) { - return std::string{}; + return {}; } /// convert a readable container to a string @@ -1185,14 +1248,14 @@ std::string to_string(T &&variable) { auto cval = variable.begin(); auto end = variable.end(); if(cval == end) { - return std::string("{}"); + return {"{}"}; } std::vector defaults; while(cval != end) { defaults.emplace_back(CLI::detail::to_string(*cval)); ++cval; } - return std::string("[" + detail::join(defaults) + "]"); + return {"[" + detail::join(defaults) + "]"}; } /// special template overload @@ -1230,7 +1293,9 @@ auto value_string(const T &value) -> decltype(to_string(value)) { } /// template to get the underlying value type if it exists or use a default -template struct wrapped_type { using type = def; }; +template struct wrapped_type { + using type = def; +}; /// Type size for regular object types that do not look like a tuple template struct wrapped_type::value>::type> { @@ -1238,7 +1303,9 @@ template struct wrapped_type struct type_count_base { static const int value{0}; }; +template struct type_count_base { + static const int value{0}; +}; /// Type size for regular object types that do not look like a tuple template @@ -1268,7 +1335,9 @@ template struct subtype_count; template struct subtype_count_min; /// This will only trigger for actual void type -template struct type_count { static const int value{0}; }; +template struct type_count { + static const int value{0}; +}; /// Type size for regular object types that do not look like a tuple template @@ -1319,7 +1388,9 @@ template struct subtype_count { }; /// This will only trigger for actual void type -template struct type_count_min { static const int value{0}; }; +template struct type_count_min { + static const int value{0}; +}; /// Type size for regular object types that do not look like a tuple template @@ -1368,7 +1439,9 @@ template struct subtype_count_min { }; /// This will only trigger for actual void type -template struct expected_count { static const int value{0}; }; +template struct expected_count { + static const int value{0}; +}; /// For most types the number of expected items is 1 template @@ -1532,7 +1605,8 @@ struct classify_object< typename std::enable_if::value && ((type_count::value >= 2 && !is_wrapper::value) || (uncommon_type::value && !is_direct_constructible::value && - !is_direct_constructible::value))>::type> { + !is_direct_constructible::value) || + (uncommon_type::value && type_count::value >= 2))>::type> { static constexpr object_category value{object_category::tuple_value}; // the condition on this class requires it be like a tuple, but on some compilers (like Xcode) tuples can be // constructed from just the first element so tuples of can be constructed from a string, which @@ -1640,8 +1714,8 @@ inline typename std::enable_if::value, std::string>::typ /// Recursively generate the tuple type name template inline typename std::enable_if<(I < type_count_base::value), std::string>::type tuple_name() { - std::string str = std::string(type_name::type>::type>()) + - ',' + tuple_name(); + auto str = std::string{type_name::type>::type>()} + ',' + + tuple_name(); if(str.back() == ',') str.pop_back(); return str; @@ -1671,11 +1745,15 @@ inline std::string type_name() { /// Convert to an unsigned integral template ::value, detail::enabler> = detail::dummy> bool integral_conversion(const std::string &input, T &output) noexcept { - if(input.empty()) { + if(input.empty() || input.front() == '-') { return false; } char *val = nullptr; + errno = 0; std::uint64_t output_ll = std::strtoull(input.c_str(), &val, 0); + if(errno == ERANGE) { + return false; + } output = static_cast(output_ll); if(val == (input.c_str() + input.size()) && static_cast(output) == output_ll) { return true; @@ -1696,7 +1774,11 @@ bool integral_conversion(const std::string &input, T &output) noexcept { return false; } char *val = nullptr; + errno = 0; std::int64_t output_ll = std::strtoll(input.c_str(), &val, 0); + if(errno == ERANGE) { + return false; + } output = static_cast(output_ll); if(val == (input.c_str() + input.size()) && static_cast(output) == output_ll) { return true; @@ -1720,7 +1802,7 @@ inline std::int64_t to_flag_value(std::string val) { return -1; } val = detail::to_lower(val); - std::int64_t ret; + std::int64_t ret = 0; if(val.size() == 1) { if(val[0] >= '1' && val[0] <= '9') { return (static_cast(val[0]) - '0'); @@ -1813,18 +1895,18 @@ bool lexical_cast(const std::string &input, T &output) { bool worked = false; auto nloc = str1.find_last_of("+-"); if(nloc != std::string::npos && nloc > 0) { - worked = detail::lexical_cast(str1.substr(0, nloc), x); + worked = lexical_cast(str1.substr(0, nloc), x); str1 = str1.substr(nloc); if(str1.back() == 'i' || str1.back() == 'j') str1.pop_back(); - worked = worked && detail::lexical_cast(str1, y); + worked = worked && lexical_cast(str1, y); } else { if(str1.back() == 'i' || str1.back() == 'j') { str1.pop_back(); - worked = detail::lexical_cast(str1, y); + worked = lexical_cast(str1, y); x = XC{0}; } else { - worked = detail::lexical_cast(str1, x); + worked = lexical_cast(str1, x); y = XC{0}; } } @@ -1896,17 +1978,18 @@ template < typename T, enable_if_t::value == object_category::number_constructible, detail::enabler> = detail::dummy> bool lexical_cast(const std::string &input, T &output) { - int val; + int val = 0; if(integral_conversion(input, val)) { output = T(val); return true; - } else { - double dval; - if(lexical_cast(input, dval)) { - output = T{dval}; - return true; - } } + + double dval = 0.0; + if(lexical_cast(input, dval)) { + output = T{dval}; + return true; + } + return from_stream(input, output); } @@ -1915,7 +1998,7 @@ template < typename T, enable_if_t::value == object_category::integer_constructible, detail::enabler> = detail::dummy> bool lexical_cast(const std::string &input, T &output) { - int val; + int val = 0; if(integral_conversion(input, val)) { output = T(val); return true; @@ -1928,7 +2011,7 @@ template < typename T, enable_if_t::value == object_category::double_constructible, detail::enabler> = detail::dummy> bool lexical_cast(const std::string &input, T &output) { - double val; + double val = 0.0; if(lexical_cast(input, val)) { output = T{val}; return true; @@ -1941,7 +2024,7 @@ template ::value == object_category::other && std::is_assignable::value, detail::enabler> = detail::dummy> bool lexical_cast(const std::string &input, T &output) { - int val; + int val = 0; if(integral_conversion(input, val)) { #ifdef _MSC_VER #pragma warning(push) @@ -2029,7 +2112,7 @@ bool lexical_assign(const std::string &input, AssignTo &output) { output = 0; return true; } - int val; + int val = 0; if(lexical_cast(input, val)) { output = val; return true; @@ -2044,7 +2127,7 @@ template = detail::dummy> bool lexical_assign(const std::string &input, AssignTo &output) { ConvertTo val{}; - bool parse_result = (!input.empty()) ? lexical_cast(input, val) : true; + bool parse_result = (!input.empty()) ? lexical_cast(input, val) : true; if(parse_result) { output = val; } @@ -2060,7 +2143,7 @@ template < detail::enabler> = detail::dummy> bool lexical_assign(const std::string &input, AssignTo &output) { ConvertTo val{}; - bool parse_result = input.empty() ? true : lexical_cast(input, val); + bool parse_result = input.empty() ? true : lexical_cast(input, val); if(parse_result) { output = AssignTo(val); // use () form of constructor to allow some implicit conversions } @@ -2138,14 +2221,13 @@ bool lexical_conversion(const std::vector &strings, AssignTo &outpu if(str1.back() == 'i' || str1.back() == 'j') { str1.pop_back(); } - auto worked = detail::lexical_cast(strings[0], x) && detail::lexical_cast(str1, y); + auto worked = lexical_cast(strings[0], x) && lexical_cast(str1, y); if(worked) { output = ConvertTo{x, y}; } return worked; - } else { - return lexical_assign(strings[0], output); } + return lexical_assign(strings[0], output); } /// Conversion to a vector type using a particular single type as the conversion type @@ -2403,7 +2485,7 @@ inline std::string sum_string_vector(const std::vector &values) { std::string output; for(const auto &arg : values) { double tv{0.0}; - auto comp = detail::lexical_cast(arg, tv); + auto comp = lexical_cast(arg, tv); if(!comp) { try { tv = static_cast(detail::to_flag_value(arg)); @@ -2419,9 +2501,9 @@ inline std::string sum_string_vector(const std::vector &values) { output.append(arg); } } else { - if(val <= static_cast(std::numeric_limits::min()) || - val >= static_cast(std::numeric_limits::max()) || - val == static_cast(val)) { + if(val <= static_cast((std::numeric_limits::min)()) || + val >= static_cast((std::numeric_limits::max)()) || + std::ceil(val) == std::floor(val)) { output = detail::value_string(static_cast(val)); } else { output = detail::value_string(val); @@ -2437,7 +2519,31 @@ inline std::string sum_string_vector(const std::vector &values) { namespace detail { // Returns false if not a short option. Otherwise, sets opt name and rest and returns true -inline bool split_short(const std::string ¤t, std::string &name, std::string &rest) { +CLI11_INLINE bool split_short(const std::string ¤t, std::string &name, std::string &rest); + +// Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true +CLI11_INLINE bool split_long(const std::string ¤t, std::string &name, std::string &value); + +// Returns false if not a windows style option. Otherwise, sets opt name and value and returns true +CLI11_INLINE bool split_windows_style(const std::string ¤t, std::string &name, std::string &value); + +// Splits a string into multiple long and short names +CLI11_INLINE std::vector split_names(std::string current); + +/// extract default flag values either {def} or starting with a ! +CLI11_INLINE std::vector> get_default_flag_values(const std::string &str); + +/// Get a vector of short names, one of long names, and a single name +CLI11_INLINE std::tuple, std::vector, std::string> +get_names(const std::vector &input); + +} // namespace detail + + + +namespace detail { + +CLI11_INLINE bool split_short(const std::string ¤t, std::string &name, std::string &rest) { if(current.size() > 1 && current[0] == '-' && valid_first_char(current[1])) { name = current.substr(1, 1); rest = current.substr(2); @@ -2446,8 +2552,7 @@ inline bool split_short(const std::string ¤t, std::string &name, std::stri return false; } -// Returns false if not a long option. Otherwise, sets opt name and other side of = and returns true -inline bool split_long(const std::string ¤t, std::string &name, std::string &value) { +CLI11_INLINE bool split_long(const std::string ¤t, std::string &name, std::string &value) { if(current.size() > 2 && current.substr(0, 2) == "--" && valid_first_char(current[2])) { auto loc = current.find_first_of('='); if(loc != std::string::npos) { @@ -2462,8 +2567,7 @@ inline bool split_long(const std::string ¤t, std::string &name, std::strin return false; } -// Returns false if not a windows style option. Otherwise, sets opt name and value and returns true -inline bool split_windows_style(const std::string ¤t, std::string &name, std::string &value) { +CLI11_INLINE bool split_windows_style(const std::string ¤t, std::string &name, std::string &value) { if(current.size() > 1 && current[0] == '/' && valid_first_char(current[1])) { auto loc = current.find_first_of(':'); if(loc != std::string::npos) { @@ -2478,11 +2582,10 @@ inline bool split_windows_style(const std::string ¤t, std::string &name, s return false; } -// Splits a string into multiple long and short names -inline std::vector split_names(std::string current) { +CLI11_INLINE std::vector split_names(std::string current) { std::vector output; - std::size_t val; - while((val = current.find(",")) != std::string::npos) { + std::size_t val = 0; + while((val = current.find(',')) != std::string::npos) { output.push_back(trim_copy(current.substr(0, val))); current = current.substr(val + 1); } @@ -2490,8 +2593,7 @@ inline std::vector split_names(std::string current) { return output; } -/// extract default flag values either {def} or starting with a ! -inline std::vector> get_default_flag_values(const std::string &str) { +CLI11_INLINE std::vector> get_default_flag_values(const std::string &str) { std::vector flags = split_names(str); flags.erase(std::remove_if(flags.begin(), flags.end(), @@ -2509,7 +2611,7 @@ inline std::vector> get_default_flag_values( if((def_start != std::string::npos) && (flag.back() == '}')) { defval = flag.substr(def_start + 1); defval.pop_back(); - flag.erase(def_start, std::string::npos); + flag.erase(def_start, std::string::npos); // NOLINT(readability-suspicious-call-argument) } flag.erase(0, flag.find_first_not_of("-!")); output.emplace_back(flag, defval); @@ -2517,8 +2619,7 @@ inline std::vector> get_default_flag_values( return output; } -/// Get a vector of short names, one of long names, and a single name -inline std::tuple, std::vector, std::string> +CLI11_INLINE std::tuple, std::vector, std::string> get_names(const std::vector &input) { std::vector short_names; @@ -2549,8 +2650,7 @@ get_names(const std::vector &input) { } } - return std::tuple, std::vector, std::string>( - short_names, long_names, pos_name); + return std::make_tuple(short_names, long_names, pos_name); } } // namespace detail @@ -2571,7 +2671,7 @@ struct ConfigItem { std::vector inputs{}; /// The list of parents and name joined by "." - std::string fullname() const { + CLI11_NODISCARD std::string fullname() const { std::vector tmp = parents; tmp.emplace_back(name); return detail::join(tmp, "."); @@ -2591,18 +2691,18 @@ class Config { virtual std::vector from_config(std::istream &) const = 0; /// Get a flag value - virtual std::string to_flag(const ConfigItem &item) const { + CLI11_NODISCARD virtual std::string to_flag(const ConfigItem &item) const { if(item.inputs.size() == 1) { return item.inputs.at(0); } if(item.inputs.empty()) { return "{}"; } - throw ConversionError::TooManyInputsFlag(item.fullname()); + throw ConversionError::TooManyInputsFlag(item.fullname()); // LCOV_EXCL_LINE } /// Parse a config file, throw an error (ParseError:ConfigParseError or FileError) on failure - std::vector from_file(const std::string &name) { + CLI11_NODISCARD std::vector from_file(const std::string &name) const { std::ifstream input{name}; if(!input.good()) throw FileError::Missing(name); @@ -2685,7 +2785,7 @@ class ConfigBase : public Config { /// get a reference to the configuration section std::string §ionRef() { return configSection; } /// get the section - const std::string §ion() const { return configSection; } + CLI11_NODISCARD const std::string §ion() const { return configSection; } /// specify a particular section of the configuration file to use ConfigBase *section(const std::string §ionName) { configSection = sectionName; @@ -2695,7 +2795,7 @@ class ConfigBase : public Config { /// get a reference to the configuration index int16_t &indexRef() { return configIndex; } /// get the section index - int16_t index() const { return configIndex; } + CLI11_NODISCARD int16_t index() const { return configIndex; } /// specify a particular index in the section to use (-1) for all sections to use ConfigBase *index(int16_t sectionIndex) { configIndex = sectionIndex; @@ -2750,6 +2850,9 @@ class Validator { /// specify that a validator should not modify the input bool non_modifying_{false}; + Validator(std::string validator_desc, std::function func) + : desc_function_([validator_desc]() { return validator_desc; }), func_(std::move(func)) {} + public: Validator() = default; /// Construct a Validator with just the description string @@ -2765,18 +2868,7 @@ class Validator { } /// This is the required operator for a Validator - provided to help /// users (CLI11 uses the member `func` directly) - std::string operator()(std::string &str) const { - std::string retstring; - if(active_) { - if(non_modifying_) { - std::string value = str; - retstring = func_(value); - } else { - retstring = func_(str); - } - } - return retstring; - } + std::string operator()(std::string &str) const; /// This is the required operator for a Validator - provided to help /// users (CLI11 uses the member `func` directly) @@ -2791,13 +2883,10 @@ class Validator { return *this; } /// Specify the type string - Validator description(std::string validator_desc) const { - Validator newval(*this); - newval.desc_function_ = [validator_desc]() { return validator_desc; }; - return newval; - } + CLI11_NODISCARD Validator description(std::string validator_desc) const; + /// Generate type description information for the Validator - std::string get_description() const { + CLI11_NODISCARD std::string get_description() const { if(active_) { return desc_function_(); } @@ -2809,20 +2898,20 @@ class Validator { return *this; } /// Specify the type string - Validator name(std::string validator_name) const { + CLI11_NODISCARD Validator name(std::string validator_name) const { Validator newval(*this); newval.name_ = std::move(validator_name); return newval; } /// Get the name of the Validator - const std::string &get_name() const { return name_; } + CLI11_NODISCARD const std::string &get_name() const { return name_; } /// Specify whether the Validator is active or not Validator &active(bool active_val = true) { active_ = active_val; return *this; } /// Specify whether the Validator is active or not - Validator active(bool active_val = true) const { + CLI11_NODISCARD Validator active(bool active_val = true) const { Validator newval(*this); newval.active_ = active_val; return newval; @@ -2839,107 +2928,33 @@ class Validator { return *this; } /// Specify the application index of a validator - Validator application_index(int app_index) const { + CLI11_NODISCARD Validator application_index(int app_index) const { Validator newval(*this); newval.application_index_ = app_index; return newval; } /// Get the current value of the application index - int get_application_index() const { return application_index_; } + CLI11_NODISCARD int get_application_index() const { return application_index_; } /// Get a boolean if the validator is active - bool get_active() const { return active_; } + CLI11_NODISCARD bool get_active() const { return active_; } /// Get a boolean if the validator is allowed to modify the input returns true if it can modify the input - bool get_modifying() const { return !non_modifying_; } + CLI11_NODISCARD bool get_modifying() const { return !non_modifying_; } /// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the /// same. - Validator operator&(const Validator &other) const { - Validator newval; - - newval._merge_description(*this, other, " AND "); - - // Give references (will make a copy in lambda function) - const std::function &f1 = func_; - const std::function &f2 = other.func_; - - newval.func_ = [f1, f2](std::string &input) { - std::string s1 = f1(input); - std::string s2 = f2(input); - if(!s1.empty() && !s2.empty()) - return std::string("(") + s1 + ") AND (" + s2 + ")"; - else - return s1 + s2; - }; - - newval.active_ = (active_ & other.active_); - newval.application_index_ = application_index_; - return newval; - } + Validator operator&(const Validator &other) const; /// Combining validators is a new validator. Type comes from left validator if function, otherwise only set if the /// same. - Validator operator|(const Validator &other) const { - Validator newval; - - newval._merge_description(*this, other, " OR "); - - // Give references (will make a copy in lambda function) - const std::function &f1 = func_; - const std::function &f2 = other.func_; - - newval.func_ = [f1, f2](std::string &input) { - std::string s1 = f1(input); - std::string s2 = f2(input); - if(s1.empty() || s2.empty()) - return std::string(); - - return std::string("(") + s1 + ") OR (" + s2 + ")"; - }; - newval.active_ = (active_ & other.active_); - newval.application_index_ = application_index_; - return newval; - } + Validator operator|(const Validator &other) const; /// Create a validator that fails when a given validator succeeds - Validator operator!() const { - Validator newval; - const std::function &dfunc1 = desc_function_; - newval.desc_function_ = [dfunc1]() { - auto str = dfunc1(); - return (!str.empty()) ? std::string("NOT ") + str : std::string{}; - }; - // Give references (will make a copy in lambda function) - const std::function &f1 = func_; - - newval.func_ = [f1, dfunc1](std::string &test) -> std::string { - std::string s1 = f1(test); - if(s1.empty()) { - return std::string("check ") + dfunc1() + " succeeded improperly"; - } - return std::string{}; - }; - newval.active_ = active_; - newval.application_index_ = application_index_; - return newval; - } + Validator operator!() const; private: - void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger) { - - const std::function &dfunc1 = val1.desc_function_; - const std::function &dfunc2 = val2.desc_function_; - - desc_function_ = [=]() { - std::string f1 = dfunc1(); - std::string f2 = dfunc2(); - if((f1.empty()) || (f2.empty())) { - return f1 + f2; - } - return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')'; - }; - } -}; // namespace CLI + void _merge_description(const Validator &val1, const Validator &val2, const std::string &merger); +}; /// Class wrapping some of the accessors of Validator class CustomValidator : public Validator { @@ -2953,132 +2968,37 @@ namespace detail { /// CLI enumeration of different file types enum class path_type { nonexistent, file, directory }; -#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 /// get the type of the path from a file name -inline path_type check_path(const char *file) noexcept { - std::error_code ec; - auto stat = std::filesystem::status(file, ec); - if(ec) { - return path_type::nonexistent; - } - switch(stat.type()) { - case std::filesystem::file_type::none: - case std::filesystem::file_type::not_found: - return path_type::nonexistent; - case std::filesystem::file_type::directory: - return path_type::directory; - case std::filesystem::file_type::symlink: - case std::filesystem::file_type::block: - case std::filesystem::file_type::character: - case std::filesystem::file_type::fifo: - case std::filesystem::file_type::socket: - case std::filesystem::file_type::regular: - case std::filesystem::file_type::unknown: - default: - return path_type::file; - } -} -#else -/// get the type of the path from a file name -inline path_type check_path(const char *file) noexcept { -#if defined(_MSC_VER) - struct __stat64 buffer; - if(_stat64(file, &buffer) == 0) { - return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file; - } -#else - struct stat buffer; - if(stat(file, &buffer) == 0) { - return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file; - } -#endif - return path_type::nonexistent; -} -#endif +CLI11_INLINE path_type check_path(const char *file) noexcept; + /// Check for an existing file (returns error message if check fails) class ExistingFileValidator : public Validator { public: - ExistingFileValidator() : Validator("FILE") { - func_ = [](std::string &filename) { - auto path_result = check_path(filename.c_str()); - if(path_result == path_type::nonexistent) { - return "File does not exist: " + filename; - } - if(path_result == path_type::directory) { - return "File is actually a directory: " + filename; - } - return std::string(); - }; - } + ExistingFileValidator(); }; /// Check for an existing directory (returns error message if check fails) class ExistingDirectoryValidator : public Validator { public: - ExistingDirectoryValidator() : Validator("DIR") { - func_ = [](std::string &filename) { - auto path_result = check_path(filename.c_str()); - if(path_result == path_type::nonexistent) { - return "Directory does not exist: " + filename; - } - if(path_result == path_type::file) { - return "Directory is actually a file: " + filename; - } - return std::string(); - }; - } + ExistingDirectoryValidator(); }; /// Check for an existing path class ExistingPathValidator : public Validator { public: - ExistingPathValidator() : Validator("PATH(existing)") { - func_ = [](std::string &filename) { - auto path_result = check_path(filename.c_str()); - if(path_result == path_type::nonexistent) { - return "Path does not exist: " + filename; - } - return std::string(); - }; - } + ExistingPathValidator(); }; /// Check for an non-existing path class NonexistentPathValidator : public Validator { public: - NonexistentPathValidator() : Validator("PATH(non-existing)") { - func_ = [](std::string &filename) { - auto path_result = check_path(filename.c_str()); - if(path_result != path_type::nonexistent) { - return "Path already exists: " + filename; - } - return std::string(); - }; - } + NonexistentPathValidator(); }; /// Validate the given string is a legal ipv4 address class IPV4Validator : public Validator { public: - IPV4Validator() : Validator("IPV4") { - func_ = [](std::string &ip_addr) { - auto result = CLI::detail::split(ip_addr, '.'); - if(result.size() != 4) { - return std::string("Invalid IPV4 address must have four parts (") + ip_addr + ')'; - } - int num; - for(const auto &var : result) { - bool retval = detail::lexical_cast(var, num); - if(!retval) { - return std::string("Failed parsing number (") + var + ')'; - } - if(num < 0 || num > 255) { - return std::string("Each IP number must be between 0 and 255 ") + var; - } - } - return std::string(); - }; - } + IPV4Validator(); }; } // namespace detail @@ -3103,15 +3023,15 @@ const detail::IPV4Validator ValidIPV4; /// Validate the input as a particular type template class TypeValidator : public Validator { public: - explicit TypeValidator(const std::string &validator_name) : Validator(validator_name) { - func_ = [](std::string &input_string) { - auto val = DesiredType(); - if(!detail::lexical_cast(input_string, val)) { - return std::string("Failed parsing ") + input_string + " as a " + detail::type_name(); - } - return std::string(); - }; - } + explicit TypeValidator(const std::string &validator_name) + : Validator(validator_name, [](std::string &input_string) { + using CLI::detail::lexical_cast; + auto val = DesiredType(); + if(!lexical_cast(input_string, val)) { + return std::string("Failed parsing ") + input_string + " as a " + detail::type_name(); + } + return std::string(); + }) {} TypeValidator() : TypeValidator(detail::type_name()) {} }; @@ -3122,28 +3042,7 @@ const TypeValidator Number("NUMBER"); /// with the error return optionally disabled class FileOnDefaultPath : public Validator { public: - explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true) : Validator("FILE") { - func_ = [default_path, enableErrorReturn](std::string &filename) { - auto path_result = detail::check_path(filename.c_str()); - if(path_result == detail::path_type::nonexistent) { - std::string test_file_path = default_path; - if(default_path.back() != '/' && default_path.back() != '\\') { - // Add folder separator - test_file_path += '/'; - } - test_file_path.append(filename); - path_result = detail::check_path(test_file_path.c_str()); - if(path_result == detail::path_type::file) { - filename = test_file_path; - } else { - if(enableErrorReturn) { - return "File does not exist: " + filename; - } - } - } - return std::string{}; - }; - } + explicit FileOnDefaultPath(std::string default_path, bool enableErrorReturn = true); }; /// Produce a range (factory). Min and max are inclusive. @@ -3162,8 +3061,9 @@ class Range : public Validator { } func_ = [min_val, max_val](std::string &input) { + using CLI::detail::lexical_cast; T val; - bool converted = detail::lexical_cast(input, val); + bool converted = lexical_cast(input, val); if((!converted) || (val < min_val || val > max_val)) { std::stringstream out; out << "Value " << input << " not in range ["; @@ -3183,7 +3083,7 @@ class Range : public Validator { /// Check for a non negative number const Range NonNegativeNumber((std::numeric_limits::max)(), "NONNEGATIVE"); -/// Check for a positive valued number (val>0.0), min() her is the smallest positive number +/// Check for a positive valued number (val>0.0), ::min here is the smallest positive number const Range PositiveNumber((std::numeric_limits::min)(), (std::numeric_limits::max)(), "POSITIVE"); /// Produce a bounded range (factory). Min and max are inclusive. @@ -3199,8 +3099,9 @@ class Bound : public Validator { description(out.str()); func_ = [min_val, max_val](std::string &input) { + using CLI::detail::lexical_cast; T val; - bool converted = detail::lexical_cast(input, val); + bool converted = lexical_cast(input, val); if(!converted) { return std::string("Value ") + input + " could not be converted"; } @@ -3320,9 +3221,8 @@ template inline typename std::enable_if::value, T>::type overflowCheck(const T &a, const T &b) { if((a > 0) == (b > 0)) { return ((std::numeric_limits::max)() / (std::abs)(a) < (std::abs)(b)); - } else { - return ((std::numeric_limits::min)() / (std::abs)(a) > -(std::abs)(b)); } + return ((std::numeric_limits::min)() / (std::abs)(a) > -(std::abs)(b)); } /// Do a check for overflow on unsigned numbers template @@ -3392,8 +3292,9 @@ class IsMember : public Validator { // This is the function that validates // It stores a copy of the set pointer-like, so shared_ptr will stay alive func_ = [set, filter_fn](std::string &input) { + using CLI::detail::lexical_cast; local_item_t b; - if(!detail::lexical_cast(input, b)) { + if(!lexical_cast(input, b)) { throw ValidationError(input); // name is added later } if(filter_fn) { @@ -3460,8 +3361,9 @@ class Transformer : public Validator { desc_function_ = [mapping]() { return detail::generate_map(detail::smart_deref(mapping)); }; func_ = [mapping, filter_fn](std::string &input) { + using CLI::detail::lexical_cast; local_item_t b; - if(!detail::lexical_cast(input, b)) { + if(!lexical_cast(input, b)) { return std::string(); // there is no possible way we can match anything in the mapping if we can't convert so just return } @@ -3529,8 +3431,9 @@ class CheckedTransformer : public Validator { desc_function_ = tfunc; func_ = [mapping, tfunc, filter_fn](std::string &input) { + using CLI::detail::lexical_cast; local_item_t b; - bool converted = detail::lexical_cast(input, b); + bool converted = lexical_cast(input, b); if(converted) { if(filter_fn) { b = filter_fn(b); @@ -3608,7 +3511,7 @@ class AsNumberWithUnit : public Validator { // transform function func_ = [mapping, opts](std::string &input) -> std::string { - Number num; + Number num{}; detail::rtrim(input); if(input.empty()) { @@ -3632,7 +3535,8 @@ class AsNumberWithUnit : public Validator { unit = detail::to_lower(unit); } if(unit.empty()) { - if(!detail::lexical_cast(input, num)) { + using CLI::detail::lexical_cast; + if(!lexical_cast(input, num)) { throw ValidationError(std::string("Value ") + input + " could not be converted to " + detail::type_name()); } @@ -3650,7 +3554,8 @@ class AsNumberWithUnit : public Validator { } if(!input.empty()) { - bool converted = detail::lexical_cast(input, num); + using CLI::detail::lexical_cast; + bool converted = lexical_cast(input, num); if(!converted) { throw ValidationError(std::string("Value ") + input + " could not be converted to " + detail::type_name()); @@ -3712,6 +3617,10 @@ class AsNumberWithUnit : public Validator { } }; +inline AsNumberWithUnit::Options operator|(const AsNumberWithUnit::Options &a, const AsNumberWithUnit::Options &b) { + return static_cast(static_cast(a) | static_cast(b)); +} + /// Converts a human-readable size string (with unit literal) to uin64_t size. /// Example: /// "100" => 100 @@ -3734,44 +3643,14 @@ class AsSizeValue : public AsNumberWithUnit { /// The first option is formally correct, but /// the second interpretation is more wide-spread /// (see https://en.wikipedia.org/wiki/Binary_prefix). - explicit AsSizeValue(bool kb_is_1000) : AsNumberWithUnit(get_mapping(kb_is_1000)) { - if(kb_is_1000) { - description("SIZE [b, kb(=1000b), kib(=1024b), ...]"); - } else { - description("SIZE [b, kb(=1024b), ...]"); - } - } + explicit AsSizeValue(bool kb_is_1000); private: /// Get mapping - static std::map init_mapping(bool kb_is_1000) { - std::map m; - result_t k_factor = kb_is_1000 ? 1000 : 1024; - result_t ki_factor = 1024; - result_t k = 1; - result_t ki = 1; - m["b"] = 1; - for(std::string p : {"k", "m", "g", "t", "p", "e"}) { - k *= k_factor; - ki *= ki_factor; - m[p] = k; - m[p + "b"] = k; - m[p + "i"] = ki; - m[p + "ib"] = ki; - } - return m; - } + static std::map init_mapping(bool kb_is_1000); /// Cache calculated mapping - static std::map get_mapping(bool kb_is_1000) { - if(kb_is_1000) { - static auto m = init_mapping(true); - return m; - } else { - static auto m = init_mapping(false); - return m; - } - } + static std::map get_mapping(bool kb_is_1000); }; namespace detail { @@ -3779,7 +3658,289 @@ namespace detail { /// the string is assumed to contain a file name followed by other arguments /// the return value contains is a pair with the first argument containing the program name and the second /// everything else. -inline std::pair split_program_name(std::string commandline) { +CLI11_INLINE std::pair split_program_name(std::string commandline); + +} // namespace detail +/// @} + + + + +CLI11_INLINE std::string Validator::operator()(std::string &str) const { + std::string retstring; + if(active_) { + if(non_modifying_) { + std::string value = str; + retstring = func_(value); + } else { + retstring = func_(str); + } + } + return retstring; +} + +CLI11_NODISCARD CLI11_INLINE Validator Validator::description(std::string validator_desc) const { + Validator newval(*this); + newval.desc_function_ = [validator_desc]() { return validator_desc; }; + return newval; +} + +CLI11_INLINE Validator Validator::operator&(const Validator &other) const { + Validator newval; + + newval._merge_description(*this, other, " AND "); + + // Give references (will make a copy in lambda function) + const std::function &f1 = func_; + const std::function &f2 = other.func_; + + newval.func_ = [f1, f2](std::string &input) { + std::string s1 = f1(input); + std::string s2 = f2(input); + if(!s1.empty() && !s2.empty()) + return std::string("(") + s1 + ") AND (" + s2 + ")"; + return s1 + s2; + }; + + newval.active_ = active_ && other.active_; + newval.application_index_ = application_index_; + return newval; +} + +CLI11_INLINE Validator Validator::operator|(const Validator &other) const { + Validator newval; + + newval._merge_description(*this, other, " OR "); + + // Give references (will make a copy in lambda function) + const std::function &f1 = func_; + const std::function &f2 = other.func_; + + newval.func_ = [f1, f2](std::string &input) { + std::string s1 = f1(input); + std::string s2 = f2(input); + if(s1.empty() || s2.empty()) + return std::string(); + + return std::string("(") + s1 + ") OR (" + s2 + ")"; + }; + newval.active_ = active_ && other.active_; + newval.application_index_ = application_index_; + return newval; +} + +CLI11_INLINE Validator Validator::operator!() const { + Validator newval; + const std::function &dfunc1 = desc_function_; + newval.desc_function_ = [dfunc1]() { + auto str = dfunc1(); + return (!str.empty()) ? std::string("NOT ") + str : std::string{}; + }; + // Give references (will make a copy in lambda function) + const std::function &f1 = func_; + + newval.func_ = [f1, dfunc1](std::string &test) -> std::string { + std::string s1 = f1(test); + if(s1.empty()) { + return std::string("check ") + dfunc1() + " succeeded improperly"; + } + return std::string{}; + }; + newval.active_ = active_; + newval.application_index_ = application_index_; + return newval; +} + +CLI11_INLINE void +Validator::_merge_description(const Validator &val1, const Validator &val2, const std::string &merger) { + + const std::function &dfunc1 = val1.desc_function_; + const std::function &dfunc2 = val2.desc_function_; + + desc_function_ = [=]() { + std::string f1 = dfunc1(); + std::string f2 = dfunc2(); + if((f1.empty()) || (f2.empty())) { + return f1 + f2; + } + return std::string(1, '(') + f1 + ')' + merger + '(' + f2 + ')'; + }; +} + +namespace detail { + +#if defined CLI11_HAS_FILESYSTEM && CLI11_HAS_FILESYSTEM > 0 +CLI11_INLINE path_type check_path(const char *file) noexcept { + std::error_code ec; + auto stat = std::filesystem::status(file, ec); + if(ec) { + return path_type::nonexistent; + } + switch(stat.type()) { + case std::filesystem::file_type::none: // LCOV_EXCL_LINE + case std::filesystem::file_type::not_found: + return path_type::nonexistent; + case std::filesystem::file_type::directory: + return path_type::directory; + case std::filesystem::file_type::symlink: + case std::filesystem::file_type::block: + case std::filesystem::file_type::character: + case std::filesystem::file_type::fifo: + case std::filesystem::file_type::socket: + case std::filesystem::file_type::regular: + case std::filesystem::file_type::unknown: + default: + return path_type::file; + } +} +#else +CLI11_INLINE path_type check_path(const char *file) noexcept { +#if defined(_MSC_VER) + struct __stat64 buffer; + if(_stat64(file, &buffer) == 0) { + return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file; + } +#else + struct stat buffer; + if(stat(file, &buffer) == 0) { + return ((buffer.st_mode & S_IFDIR) != 0) ? path_type::directory : path_type::file; + } +#endif + return path_type::nonexistent; +} +#endif + +CLI11_INLINE ExistingFileValidator::ExistingFileValidator() : Validator("FILE") { + func_ = [](std::string &filename) { + auto path_result = check_path(filename.c_str()); + if(path_result == path_type::nonexistent) { + return "File does not exist: " + filename; + } + if(path_result == path_type::directory) { + return "File is actually a directory: " + filename; + } + return std::string(); + }; +} + +CLI11_INLINE ExistingDirectoryValidator::ExistingDirectoryValidator() : Validator("DIR") { + func_ = [](std::string &filename) { + auto path_result = check_path(filename.c_str()); + if(path_result == path_type::nonexistent) { + return "Directory does not exist: " + filename; + } + if(path_result == path_type::file) { + return "Directory is actually a file: " + filename; + } + return std::string(); + }; +} + +CLI11_INLINE ExistingPathValidator::ExistingPathValidator() : Validator("PATH(existing)") { + func_ = [](std::string &filename) { + auto path_result = check_path(filename.c_str()); + if(path_result == path_type::nonexistent) { + return "Path does not exist: " + filename; + } + return std::string(); + }; +} + +CLI11_INLINE NonexistentPathValidator::NonexistentPathValidator() : Validator("PATH(non-existing)") { + func_ = [](std::string &filename) { + auto path_result = check_path(filename.c_str()); + if(path_result != path_type::nonexistent) { + return "Path already exists: " + filename; + } + return std::string(); + }; +} + +CLI11_INLINE IPV4Validator::IPV4Validator() : Validator("IPV4") { + func_ = [](std::string &ip_addr) { + auto result = CLI::detail::split(ip_addr, '.'); + if(result.size() != 4) { + return std::string("Invalid IPV4 address must have four parts (") + ip_addr + ')'; + } + int num = 0; + for(const auto &var : result) { + using CLI::detail::lexical_cast; + bool retval = lexical_cast(var, num); + if(!retval) { + return std::string("Failed parsing number (") + var + ')'; + } + if(num < 0 || num > 255) { + return std::string("Each IP number must be between 0 and 255 ") + var; + } + } + return std::string(); + }; +} + +} // namespace detail + +CLI11_INLINE FileOnDefaultPath::FileOnDefaultPath(std::string default_path, bool enableErrorReturn) + : Validator("FILE") { + func_ = [default_path, enableErrorReturn](std::string &filename) { + auto path_result = detail::check_path(filename.c_str()); + if(path_result == detail::path_type::nonexistent) { + std::string test_file_path = default_path; + if(default_path.back() != '/' && default_path.back() != '\\') { + // Add folder separator + test_file_path += '/'; + } + test_file_path.append(filename); + path_result = detail::check_path(test_file_path.c_str()); + if(path_result == detail::path_type::file) { + filename = test_file_path; + } else { + if(enableErrorReturn) { + return "File does not exist: " + filename; + } + } + } + return std::string{}; + }; +} + +CLI11_INLINE AsSizeValue::AsSizeValue(bool kb_is_1000) : AsNumberWithUnit(get_mapping(kb_is_1000)) { + if(kb_is_1000) { + description("SIZE [b, kb(=1000b), kib(=1024b), ...]"); + } else { + description("SIZE [b, kb(=1024b), ...]"); + } +} + +CLI11_INLINE std::map AsSizeValue::init_mapping(bool kb_is_1000) { + std::map m; + result_t k_factor = kb_is_1000 ? 1000 : 1024; + result_t ki_factor = 1024; + result_t k = 1; + result_t ki = 1; + m["b"] = 1; + for(std::string p : {"k", "m", "g", "t", "p", "e"}) { + k *= k_factor; + ki *= ki_factor; + m[p] = k; + m[p + "b"] = k; + m[p + "i"] = ki; + m[p + "ib"] = ki; + } + return m; +} + +CLI11_INLINE std::map AsSizeValue::get_mapping(bool kb_is_1000) { + if(kb_is_1000) { + static auto m = init_mapping(true); + return m; + } + static auto m = init_mapping(false); + return m; +} + +namespace detail { + +CLI11_INLINE std::pair split_program_name(std::string commandline) { // try to determine the programName std::pair vals; trim(commandline); @@ -3819,7 +3980,7 @@ inline std::pair split_program_name(std::string comman } // strip the program name - vals.second = (esp != std::string::npos) ? commandline.substr(esp + 1) : std::string{}; + vals.second = (esp < commandline.length() - 1) ? commandline.substr(esp + 1) : std::string{}; ltrim(vals.second); return vals; } @@ -3868,6 +4029,8 @@ class FormatterBase { FormatterBase() = default; FormatterBase(const FormatterBase &) = default; FormatterBase(FormatterBase &&) = default; + FormatterBase &operator=(const FormatterBase &) = default; + FormatterBase &operator=(FormatterBase &&) = default; /// Adding a destructor in this form to work around bug in GCC 4.7 virtual ~FormatterBase() noexcept {} // NOLINT(modernize-use-equals-default) @@ -3890,15 +4053,14 @@ class FormatterBase { ///@{ /// Get the current value of a name (REQUIRED, etc.) - std::string get_label(std::string key) const { + CLI11_NODISCARD std::string get_label(std::string key) const { if(labels_.find(key) == labels_.end()) return key; - else - return labels_.at(key); + return labels_.at(key); } /// Get the current column width - std::size_t get_column_width() const { return column_width_; } + CLI11_NODISCARD std::size_t get_column_width() const { return column_width_; } ///@} }; @@ -3930,13 +4092,16 @@ class Formatter : public FormatterBase { Formatter() = default; Formatter(const Formatter &) = default; Formatter(Formatter &&) = default; + Formatter &operator=(const Formatter &) = default; + Formatter &operator=(Formatter &&) = default; /// @name Overridables ///@{ /// This prints out a group of options with title /// - virtual std::string make_group(std::string group, bool is_positional, std::vector opts) const; + CLI11_NODISCARD virtual std::string + make_group(std::string group, bool is_positional, std::vector opts) const; /// This prints out just the positionals "group" virtual std::string make_positionals(const App *app) const; @@ -4047,17 +4212,7 @@ template class OptionBase { MultiOptionPolicy multi_option_policy_{MultiOptionPolicy::Throw}; /// Copy the contents to another similar class (one based on OptionBase) - template void copy_to(T *other) const { - other->group(group_); - other->required(required_); - other->ignore_case(ignore_case_); - other->ignore_underscore(ignore_underscore_); - other->configurable(configurable_); - other->disable_flag_override(disable_flag_override_); - other->delimiter(delimiter_); - other->always_capture_default(always_capture_default_); - other->multi_option_policy(multi_option_policy_); - } + template void copy_to(T *other) const; public: // setters @@ -4088,44 +4243,44 @@ template class OptionBase { // Getters /// Get the group of this option - const std::string &get_group() const { return group_; } + CLI11_NODISCARD const std::string &get_group() const { return group_; } /// True if this is a required option - bool get_required() const { return required_; } + CLI11_NODISCARD bool get_required() const { return required_; } /// The status of ignore case - bool get_ignore_case() const { return ignore_case_; } + CLI11_NODISCARD bool get_ignore_case() const { return ignore_case_; } /// The status of ignore_underscore - bool get_ignore_underscore() const { return ignore_underscore_; } + CLI11_NODISCARD bool get_ignore_underscore() const { return ignore_underscore_; } /// The status of configurable - bool get_configurable() const { return configurable_; } + CLI11_NODISCARD bool get_configurable() const { return configurable_; } /// The status of configurable - bool get_disable_flag_override() const { return disable_flag_override_; } + CLI11_NODISCARD bool get_disable_flag_override() const { return disable_flag_override_; } /// Get the current delimiter char - char get_delimiter() const { return delimiter_; } + CLI11_NODISCARD char get_delimiter() const { return delimiter_; } /// Return true if this will automatically capture the default value for help printing - bool get_always_capture_default() const { return always_capture_default_; } + CLI11_NODISCARD bool get_always_capture_default() const { return always_capture_default_; } /// The status of the multi option policy - MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; } + CLI11_NODISCARD MultiOptionPolicy get_multi_option_policy() const { return multi_option_policy_; } // Shortcuts for multi option policy /// Set the multi option policy to take last CRTP *take_last() { - auto self = static_cast(this); + auto *self = static_cast(this); self->multi_option_policy(MultiOptionPolicy::TakeLast); return self; } /// Set the multi option policy to take last CRTP *take_first() { - auto self = static_cast(this); + auto *self = static_cast(this); self->multi_option_policy(MultiOptionPolicy::TakeFirst); return self; } @@ -4139,7 +4294,7 @@ template class OptionBase { /// Set the multi option policy to join CRTP *join() { - auto self = static_cast(this); + auto *self = static_cast(this); self->multi_option_policy(MultiOptionPolicy::Join); return self; } @@ -4330,10 +4485,10 @@ class Option : public OptionBase