From 62e0368e21c067ee7bb12cbd87bfae04826c5636 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 11 Sep 2023 20:14:23 -0400 Subject: [PATCH] Add configurable lowpass filter for VkPhysicalDeviceLimits::timestampPeriod. - Add MVKConfiguration::timestampPeriodLowPassAlpha, along with matching MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA env var. - Add MVKConfigMembers.def file to describe MVKConfiguration members, to support consistent batch handling of members. - Add env var & build settings MVK_CONFIG_DEBUG, plus legacy MVK_CONFIG_ALLOW_METAL_EVENTS & MVK_CONFIG_ALLOW_METAL_FENCES. - Simplify environment variable retrieval functions and macros. - Rename MVKDevice::updateTimestampsAndPeriod() to updateTimestampPeriod(). --- Common/MVKOSExtensions.h | 62 +++---------- Common/MVKOSExtensions.mm | 17 ++-- Docs/MoltenVK_Runtime_UserGuide.md | 4 +- Docs/Whats_New.md | 2 + MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 10 +++ MoltenVK/MoltenVK/API/mvk_config.h | 37 +++++++- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 16 ++-- .../MoltenVK/Utility/MVKConfigMembers.def | 86 +++++++++++++++++++ MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp | 66 +++++--------- MoltenVK/MoltenVK/Utility/MVKEnvironment.h | 30 ++++++- Scripts/runcts | 2 +- 12 files changed, 214 insertions(+), 120 deletions(-) create mode 100644 MoltenVK/MoltenVK/Utility/MVKConfigMembers.def diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h index 13d864da..f9faba91 100644 --- a/Common/MVKOSExtensions.h +++ b/Common/MVKOSExtensions.h @@ -108,62 +108,22 @@ void mvkDispatchToMainAndWait(dispatch_block_t block); #pragma mark Process environment /** - * Returns the value of the environment variable at the given name, - * or an empty string if no environment variable with that name exists. - * - * If pWasFound is not null, its value is set to true if the environment - * variable exists, or false if not. + * Sets the value of the environment variable at the given name, into the + * std::string, and returns whether the environment variable was found. */ -std::string mvkGetEnvVar(std::string varName, bool* pWasFound = nullptr); +bool mvkGetEnvVar(const char* evName, std::string& evStr); + +/** + * Returns a pointer to a string containing the value of the environment variable at + * the given name, or returns the default value if the environment variable was not set. + */ +const char* mvkGetEnvVarString(const char* evName, std::string& evStr, const char* defaultValue = ""); /** * Returns the value of the environment variable at the given name, - * or zero if no environment variable with that name exists. - * - * If pWasFound is not null, its value is set to true if the environment - * variable exists, or false if not. + * or returns the default value if the environment variable was not set. */ -int64_t mvkGetEnvVarInt64(std::string varName, bool* pWasFound = nullptr); - -/** - * Returns the value of the environment variable at the given name, - * or false if no environment variable with that name exists. - * - * If pWasFound is not null, its value is set to true if the environment - * variable exists, or false if not. - */ -bool mvkGetEnvVarBool(std::string varName, bool* pWasFound = nullptr); - -#define MVK_SET_FROM_ENV_OR_BUILD_BOOL(cfgVal, EV) \ - do { \ - bool wasFound = false; \ - bool ev = mvkGetEnvVarBool(#EV, &wasFound); \ - cfgVal = wasFound ? ev : EV; \ - } while(false) - -#define MVK_SET_FROM_ENV_OR_BUILD_INT64(cfgVal, EV) \ - do { \ - bool wasFound = false; \ - int64_t ev = mvkGetEnvVarInt64(#EV, &wasFound); \ - cfgVal = wasFound ? ev : EV; \ - } while(false) - -// Pointer cast permits cfgVal to be an enum var -#define MVK_SET_FROM_ENV_OR_BUILD_INT32(cfgVal, EV) \ - do { \ - bool wasFound = false; \ - int64_t ev = mvkGetEnvVarInt64(#EV, &wasFound); \ - int64_t val = wasFound ? ev : EV; \ - *(int32_t*)&cfgVal = (int32_t)std::min(std::max(val, (int64_t)INT32_MIN), (int64_t)INT32_MAX); \ - } while(false) - -#define MVK_SET_FROM_ENV_OR_BUILD_STRING(cfgVal, EV, strObj) \ - do { \ - bool wasFound = false; \ - std::string ev = mvkGetEnvVar(#EV, &wasFound); \ - strObj = wasFound ? std::move(ev) : EV; \ - cfgVal = strObj.c_str(); \ - } while(false) +double mvkGetEnvVarNumber(const char* evName, double defaultValue = 0.0); #pragma mark - diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 4e2c974c..93025f2b 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -81,21 +81,22 @@ void mvkDispatchToMainAndWait(dispatch_block_t block) { #pragma mark - #pragma mark Process environment -string mvkGetEnvVar(string varName, bool* pWasFound) { +bool mvkGetEnvVar(const char* varName, string& evStr) { @autoreleasepool { NSDictionary* nsEnv = [[NSProcessInfo processInfo] environment]; - NSString* envStr = nsEnv[@(varName.c_str())]; - if (pWasFound) { *pWasFound = envStr != nil; } - return envStr ? envStr.UTF8String : ""; + NSString* nsStr = nsEnv[@(varName)]; + if (nsStr) { evStr = nsStr.UTF8String; } + return nsStr != nil; } } -int64_t mvkGetEnvVarInt64(string varName, bool* pWasFound) { - return strtoll(mvkGetEnvVar(varName, pWasFound).c_str(), NULL, 0); +const char* mvkGetEnvVarString(const char* varName, string& evStr, const char* defaultValue) { + return mvkGetEnvVar(varName, evStr) ? evStr.c_str() : defaultValue; } -bool mvkGetEnvVarBool(std::string varName, bool* pWasFound) { - return mvkGetEnvVarInt64(varName, pWasFound) != 0; +double mvkGetEnvVarNumber(const char* varName, double defaultValue) { + string evStr; + return mvkGetEnvVar(varName, evStr) ? strtod(evStr.c_str(), nullptr) : defaultValue; } diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index f236a7e9..6684bb34 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -517,8 +517,8 @@ you can address the issue as follows: - Errors encountered during **Runtime Shader Conversion** are logged to the console. - To help understand conversion issues during **Runtime Shader Conversion**, you can enable the - logging of the *SPIR-V* and *MSL* shader source code during shader conversion, by turning on - the `MVKConfiguration::debugMode` configuration parameter, or setting the value of the `MVK_DEBUG` + logging of the *SPIR-V* and *MSL* shader source code during shader conversion, by turning on the + `MVKConfiguration::debugMode` configuration parameter, or setting the value of the `MVK_CONFIG_DEBUG` runtime environment variable to `1`. See the [*MoltenVK Configuration*](#moltenvk_config) description above. diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 605cda82..357df0e4 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -24,6 +24,8 @@ Released TBD - Fix case where a `CAMetalDrawable` with invalid pixel format causes onscreen flickering. - Improve behavior of swapchain image presentation stalls caused by Metal regression. - Add several additional performance trackers, available via logging, or the `mvk_private_api.h` API. +- Add configurable lowpass filter for `VkPhysicalDeviceLimits::timestampPeriod`. +- Deprecate `MVK_DEBUG` env var, and add `MVK_CONFIG_DEBUG` env var to replace it. - Update `MVK_CONFIGURATION_API_VERSION` and `MVK_PRIVATE_API_VERSION` to `38`. diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index 202efa91..1dffab36 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -331,6 +331,10 @@ A9B51BD8225E986A00AC74D2 /* MVKOSExtensions.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */; }; A9B51BD9225E986A00AC74D2 /* MVKOSExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */; }; A9B51BDA225E986A00AC74D2 /* MVKOSExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */; }; + A9C327562AAFBD390025EE79 /* MVKConfigMembers.def in Headers */ = {isa = PBXBuildFile; fileRef = A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */; }; + A9C327572AAFBD3A0025EE79 /* MVKConfigMembers.def in Headers */ = {isa = PBXBuildFile; fileRef = A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */; }; + A9C327582AAFBD3A0025EE79 /* MVKConfigMembers.def in Headers */ = {isa = PBXBuildFile; fileRef = A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */; }; + A9C327592AAFBD3B0025EE79 /* MVKConfigMembers.def in Headers */ = {isa = PBXBuildFile; fileRef = A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */; }; A9C96DD01DDC20C20053187F /* MVKMTLBufferAllocation.h in Headers */ = {isa = PBXBuildFile; fileRef = A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */; }; A9C96DD11DDC20C20053187F /* MVKMTLBufferAllocation.h in Headers */ = {isa = PBXBuildFile; fileRef = A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */; }; A9C96DD21DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; }; @@ -670,6 +674,7 @@ A9B51BD2225E986A00AC74D2 /* MVKOSExtensions.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MVKOSExtensions.mm; sourceTree = ""; }; A9B51BD6225E986A00AC74D2 /* MVKOSExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKOSExtensions.h; sourceTree = ""; }; A9B8EE0A1A98D796009C5A02 /* libMoltenVK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMoltenVK.a; sourceTree = BUILT_PRODUCTS_DIR; }; + A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKConfigMembers.def; sourceTree = ""; }; A9C83DCD24533E22003E5261 /* MVKCommandTypePools.def */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = MVKCommandTypePools.def; sourceTree = ""; }; A9C86CB61C55B8350096CAF2 /* MoltenVKShaderConverter.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MoltenVKShaderConverter.xcodeproj; path = ../MoltenVKShaderConverter/MoltenVKShaderConverter.xcodeproj; sourceTree = ""; }; A9C96DCE1DDC20C20053187F /* MVKMTLBufferAllocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVKMTLBufferAllocation.h; sourceTree = ""; }; @@ -843,6 +848,7 @@ 4553AEF62251617100E8EBCD /* MVKBlockObserver.m */, 45557A5121C9EFF3008868BD /* MVKCodec.h */, 45557A4D21C9EFF3008868BD /* MVKCodec.mm */, + A9C327542AAF8A770025EE79 /* MVKConfigMembers.def */, 45557A5721CD83C3008868BD /* MVKDXTnCodec.def */, A9A5E9C525C0822700E9085E /* MVKEnvironment.cpp */, A98149431FB6A3F7005F00B4 /* MVKEnvironment.h */, @@ -1008,6 +1014,7 @@ 2FEA0A7824902F9F00EEF3AD /* MVKDeviceMemory.h in Headers */, 2FEA0A7924902F9F00EEF3AD /* MVKMTLResourceBindings.h in Headers */, 2FEA0A7A24902F9F00EEF3AD /* MVKExtensions.def in Headers */, + A9C327572AAFBD3A0025EE79 /* MVKConfigMembers.def in Headers */, 2FEA0A7B24902F9F00EEF3AD /* mvk_datatypes.hpp in Headers */, 2FEA0A7C24902F9F00EEF3AD /* MVKCommandEncodingPool.h in Headers */, 2FEA0A7D24902F9F00EEF3AD /* MVKResource.h in Headers */, @@ -1070,6 +1077,7 @@ A94FB7C41C7DFB4800632CA3 /* MVKCmdRenderPass.h in Headers */, A94FB7BC1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */, A9F3D9DC24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */, + A9C327562AAFBD390025EE79 /* MVKConfigMembers.def in Headers */, A94FB7F81C7DFB4800632CA3 /* MVKPipeline.h in Headers */, A94FB7F01C7DFB4800632CA3 /* MVKImage.h in Headers */, 4553AEFD2251617100E8EBCD /* MVKBlockObserver.h in Headers */, @@ -1147,6 +1155,7 @@ A94FB7BD1C7DFB4800632CA3 /* MVKCmdPipeline.h in Headers */, A9F3D9DD24732A4D00745190 /* MVKSmallVectorAllocator.h in Headers */, A94FB7F91C7DFB4800632CA3 /* MVKPipeline.h in Headers */, + A9C327582AAFBD3A0025EE79 /* MVKConfigMembers.def in Headers */, A94FB7F11C7DFB4800632CA3 /* MVKImage.h in Headers */, 4553AEFE2251617100E8EBCD /* MVKBlockObserver.h in Headers */, A94FB7B91C7DFB4800632CA3 /* MVKCmdTransfer.h in Headers */, @@ -1204,6 +1213,7 @@ DCFD7EFD2A45BC6E007BBBF7 /* MVKSync.h in Headers */, DCFD7EFE2A45BC6E007BBBF7 /* MVKDevice.h in Headers */, DCFD7EFF2A45BC6E007BBBF7 /* MVKSmallVector.h in Headers */, + A9C327592AAFBD3B0025EE79 /* MVKConfigMembers.def in Headers */, DCFD7F002A45BC6E007BBBF7 /* MVKCommandPool.h in Headers */, DCFD7F012A45BC6E007BBBF7 /* MVKShaderModule.h in Headers */, DCFD7F022A45BC6E007BBBF7 /* MVKVulkanAPIObject.h in Headers */, diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index f9702661..f72ef777 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -191,7 +191,7 @@ typedef struct { * and the changed value will immediately effect subsequent MoltenVK behaviour. * * The initial value or this parameter is set by the - * MVK_DEBUG + * MVK_CONFIG_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. @@ -919,6 +919,9 @@ typedef struct { /** * Maximize the concurrent executing compilation tasks. * + * 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_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION * runtime environment variable or MoltenVK compile-time build setting. @@ -926,6 +929,38 @@ typedef struct { */ VkBool32 shouldMaximizeConcurrentCompilation; + /** + * This parameter is ignored on Apple Silicon devices. + * + * Non-Apple GPUs can have a dynamic timestamp period, which varies over time according to GPU + * workload. Depending on how often the app samples the VkPhysicalDeviceLimits::timestampPeriod + * value using vkGetPhysicalDeviceProperties(), the app may want up-to-date, but potentially + * volatile values, or it may find average values more useful. + * + * The value of this parameter sets the alpha (A) value of a simple lowpass filter + * on the timestampPeriod value, of the form: + * + * TPout = (1 - A)TPout + (A * TPin) + * + * The alpha value can be set to a float between 0.0 and 1.0. Values of alpha closer to + * 0.0 cause the value of timestampPeriod to vary slowly over time and be less volatile, + * and values of alpha closer to 1.0 cause the value of timestampPeriod to vary quickly + * and be more volatile. + * + * Apps that query the timestampPeriod value infrequently will prefer low volatility, whereas + * apps that query frequently may prefer higher volatility, to track more recent changes. + * + * The value of this parameter can be changed at any time, and will affect subsequent queries. + * + * The initial value or this parameter is set by the + * MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA + * runtime environment variable or MoltenVK compile-time build setting. + * If neither is set, this parameter is set to 0.05 by default, + * indicating that the timestampPeriod will vary relatively slowly, + * with the expectation that the app is querying this value infrequently. + */ + float timestampPeriodLowPassAlpha; + } MVKConfiguration; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 5ae7f5ec..7a04e90e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -401,7 +401,7 @@ protected: void initExtensions(); void initCounterSets(); bool needsCounterSetRetained(); - void updateTimestampsAndPeriod(); + void updateTimestampPeriod(); MVKArrayRef getQueueFamilies(); void initPipelineCacheUUID(); uint32_t getHighestGPUCapability(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 04816011..422f1b43 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -451,7 +451,7 @@ void MVKPhysicalDevice::getFeatures(VkPhysicalDeviceFeatures2* features) { } void MVKPhysicalDevice::getProperties(VkPhysicalDeviceProperties* properties) { - updateTimestampsAndPeriod(); + updateTimestampPeriod(); *properties = _properties; } @@ -1570,10 +1570,10 @@ VkResult MVKPhysicalDevice::getQueueFamilyProperties(uint32_t* pCount, // If needed, update the timestamp period for this device, using a crude lowpass filter to level out // wild temporary changes, particularly during initial queries before much GPU activity has occurred. // On Apple GPUs, CPU & GPU timestamps are the same, and timestamp period never changes. -void MVKPhysicalDevice::updateTimestampsAndPeriod() { - if (_properties.vendorID == kAppleVendorId) { return; } - - if ([_mtlDevice respondsToSelector: @selector(sampleTimestamps:gpuTimestamp:)]) { +void MVKPhysicalDevice::updateTimestampPeriod() { + if (_properties.vendorID != kAppleVendorId && + [_mtlDevice respondsToSelector: @selector(sampleTimestamps:gpuTimestamp:)]) { + MTLTimestamp earlierCPUTs = _prevCPUTimestamp; MTLTimestamp earlierGPUTs = _prevGPUTimestamp; [_mtlDevice sampleTimestamps: &_prevCPUTimestamp gpuTimestamp: &_prevGPUTimestamp]; @@ -1582,9 +1582,9 @@ void MVKPhysicalDevice::updateTimestampsAndPeriod() { if (elapsedCPUNanos && elapsedGPUTicks) { // Ensure not zero float tsPeriod = elapsedCPUNanos / elapsedGPUTicks; - // Basic lowpass filter Y = (1 - a)Y + a*X. - // The lower a is, the slower Y will change over time. - static const float a = 0.05; + // Basic lowpass filter TPout = (1 - A)TPout + (A * TPin). + // The lower A is, the slower TPout will change over time. + float a = mvkConfig().timestampPeriodLowPassAlpha; _properties.limits.timestampPeriod = ((1.0 - a) * _properties.limits.timestampPeriod) + (a * tsPeriod); } } diff --git a/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def b/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def new file mode 100644 index 00000000..aff0cf33 --- /dev/null +++ b/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def @@ -0,0 +1,86 @@ +/* + * MVKConfigMembers.def + * + * Copyright (c) 2015-2023 The Brenwill Workshop Ltd. (http://www.brenwill.com) + * + * Licensed under the Apache License, Version 2.0 (the "License", Int64) + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// The items in the list below describe the members of the MVKConfiguration struct. +// When a new member is added to the MVKConfiguration struct, a corresponding description +// must be added here. +// +// To use this file, define the macros: +// +// MVK_CONFIG_MEMBER(member, mbrType, name) +// MVK_CONFIG_MEMBER_STRING(member, strObj, name) +// +// then #include this file inline with your code. +// +// The name prameter is the name of the configuration parameter, which is used as the name +// of the environment variable, and build setting, that sets the config value, and is entered +// here without the "MVK_CONFIG_" prefix. +// +// Since string members are set from char pointers, the text must be copied to a std::string +// object, which is passed as a parameter to MVK_CONFIG_MEMBER_STRING. + + +#ifndef MVK_CONFIG_MEMBER +#error MVK_CONFIG_MEMBER must be defined before including this file +#endif + +#ifndef MVK_CONFIG_MEMBER_STRING +#error MVK_CONFIG_MEMBER_STRING must be defined before including this file +#endif + +MVK_CONFIG_MEMBER(debugMode, VkBool32, DEBUG) +MVK_CONFIG_MEMBER(shaderConversionFlipVertexY, VkBool32, SHADER_CONVERSION_FLIP_VERTEX_Y) +MVK_CONFIG_MEMBER(synchronousQueueSubmits, VkBool32, SYNCHRONOUS_QUEUE_SUBMITS) +MVK_CONFIG_MEMBER(prefillMetalCommandBuffers, MVKPrefillMetalCommandBuffersStyle, PREFILL_METAL_COMMAND_BUFFERS) +MVK_CONFIG_MEMBER(maxActiveMetalCommandBuffersPerQueue, uint32_t, MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE) +MVK_CONFIG_MEMBER(supportLargeQueryPools, VkBool32, SUPPORT_LARGE_QUERY_POOLS) +MVK_CONFIG_MEMBER(presentWithCommandBuffer, VkBool32, PRESENT_WITH_COMMAND_BUFFER) +MVK_CONFIG_MEMBER(swapchainMinMagFilterUseNearest, VkBool32, SWAPCHAIN_MAG_FILTER_USE_NEAREST) // Deprecated legacy renaming +MVK_CONFIG_MEMBER(swapchainMinMagFilterUseNearest, VkBool32, SWAPCHAIN_MIN_MAG_FILTER_USE_NEAREST) +MVK_CONFIG_MEMBER(metalCompileTimeout, uint64_t, METAL_COMPILE_TIMEOUT) +MVK_CONFIG_MEMBER(performanceTracking, VkBool32, PERFORMANCE_TRACKING) +MVK_CONFIG_MEMBER(performanceLoggingFrameCount, uint32_t, PERFORMANCE_LOGGING_FRAME_COUNT) +MVK_CONFIG_MEMBER(activityPerformanceLoggingStyle, MVKConfigActivityPerformanceLoggingStyle, ACTIVITY_PERFORMANCE_LOGGING_STYLE) +MVK_CONFIG_MEMBER(displayWatermark, VkBool32, DISPLAY_WATERMARK) +MVK_CONFIG_MEMBER(specializedQueueFamilies, VkBool32, SPECIALIZED_QUEUE_FAMILIES) +MVK_CONFIG_MEMBER(switchSystemGPU, VkBool32, SWITCH_SYSTEM_GPU) +MVK_CONFIG_MEMBER(fullImageViewSwizzle, VkBool32, FULL_IMAGE_VIEW_SWIZZLE) +MVK_CONFIG_MEMBER(defaultGPUCaptureScopeQueueFamilyIndex, VkBool32, DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX) +MVK_CONFIG_MEMBER(defaultGPUCaptureScopeQueueIndex, VkBool32, DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX) +MVK_CONFIG_MEMBER(fastMathEnabled, MVKConfigFastMath, FAST_MATH_ENABLED) +MVK_CONFIG_MEMBER(logLevel, MVKConfigLogLevel, LOG_LEVEL) +MVK_CONFIG_MEMBER(traceVulkanCalls, MVKConfigTraceVulkanCalls, TRACE_VULKAN_CALLS) +MVK_CONFIG_MEMBER(forceLowPowerGPU, VkBool32, FORCE_LOW_POWER_GPU) +MVK_CONFIG_MEMBER(semaphoreUseMTLFence, VkBool32, ALLOW_METAL_FENCES) // Deprecated legacy +MVK_CONFIG_MEMBER(semaphoreSupportStyle, MVKVkSemaphoreSupportStyle, VK_SEMAPHORE_SUPPORT_STYLE) +MVK_CONFIG_MEMBER(autoGPUCaptureScope, MVKConfigAutoGPUCaptureScope, AUTO_GPU_CAPTURE_SCOPE) +MVK_CONFIG_MEMBER_STRING(autoGPUCaptureOutputFilepath, evGPUCapFileStrObj, AUTO_GPU_CAPTURE_OUTPUT_FILE) +MVK_CONFIG_MEMBER(texture1DAs2D, VkBool32, TEXTURE_1D_AS_2D) +MVK_CONFIG_MEMBER(preallocateDescriptors, VkBool32, PREALLOCATE_DESCRIPTORS) +MVK_CONFIG_MEMBER(useCommandPooling, VkBool32, USE_COMMAND_POOLING) +MVK_CONFIG_MEMBER(useMTLHeap, VkBool32, USE_MTLHEAP) +MVK_CONFIG_MEMBER(apiVersionToAdvertise, uint32_t, API_VERSION_TO_ADVERTISE) +MVK_CONFIG_MEMBER(advertiseExtensions, uint32_t, ADVERTISE_EXTENSIONS) +MVK_CONFIG_MEMBER(resumeLostDevice, VkBool32, RESUME_LOST_DEVICE) +MVK_CONFIG_MEMBER(useMetalArgumentBuffers, MVKUseMetalArgumentBuffers, USE_METAL_ARGUMENT_BUFFERS) +MVK_CONFIG_MEMBER(shaderSourceCompressionAlgorithm, MVKConfigCompressionAlgorithm, SHADER_COMPRESSION_ALGORITHM) +MVK_CONFIG_MEMBER(shouldMaximizeConcurrentCompilation, VkBool32, SHOULD_MAXIMIZE_CONCURRENT_COMPILATION) +MVK_CONFIG_MEMBER(timestampPeriodLowPassAlpha, float, TIMESTAMP_PERIOD_LOWPASS_ALPHA) + +#undef MVK_CONFIG_MEMBER +#undef MVK_CONFIG_MEMBER_STRING diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp index 5aa6f7db..f2fa9e86 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp @@ -18,7 +18,7 @@ #include "MVKEnvironment.h" #include "MVKOSExtensions.h" - +#include "MVKFoundation.h" static bool _mvkConfigInitialized = false; static void mvkInitConfigFromEnvVars() { @@ -27,43 +27,22 @@ static void mvkInitConfigFromEnvVars() { MVKConfiguration evCfg; std::string evGPUCapFileStrObj; - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.debugMode, MVK_DEBUG); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.shaderConversionFlipVertexY, MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.synchronousQueueSubmits, MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.prefillMetalCommandBuffers, MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.maxActiveMetalCommandBuffersPerQueue, MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.supportLargeQueryPools, MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.presentWithCommandBuffer, MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.swapchainMinMagFilterUseNearest, MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST); // Deprecated legacy env var - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.swapchainMinMagFilterUseNearest, MVK_CONFIG_SWAPCHAIN_MIN_MAG_FILTER_USE_NEAREST); - MVK_SET_FROM_ENV_OR_BUILD_INT64 (evCfg.metalCompileTimeout, MVK_CONFIG_METAL_COMPILE_TIMEOUT); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.performanceTracking, MVK_CONFIG_PERFORMANCE_TRACKING); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.performanceLoggingFrameCount, MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.activityPerformanceLoggingStyle, MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.displayWatermark, MVK_CONFIG_DISPLAY_WATERMARK); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.specializedQueueFamilies, MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.switchSystemGPU, MVK_CONFIG_SWITCH_SYSTEM_GPU); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.fullImageViewSwizzle, MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.defaultGPUCaptureScopeQueueFamilyIndex, MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.defaultGPUCaptureScopeQueueIndex, MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.fastMathEnabled, MVK_CONFIG_FAST_MATH_ENABLED); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.logLevel, MVK_CONFIG_LOG_LEVEL); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.traceVulkanCalls, MVK_CONFIG_TRACE_VULKAN_CALLS); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.forceLowPowerGPU, MVK_CONFIG_FORCE_LOW_POWER_GPU); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.semaphoreUseMTLFence, MVK_ALLOW_METAL_FENCES); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.semaphoreSupportStyle, MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.autoGPUCaptureScope, MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE); - MVK_SET_FROM_ENV_OR_BUILD_STRING(evCfg.autoGPUCaptureOutputFilepath, MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE, evGPUCapFileStrObj); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.texture1DAs2D, MVK_CONFIG_TEXTURE_1D_AS_2D); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.preallocateDescriptors, MVK_CONFIG_PREALLOCATE_DESCRIPTORS); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.useCommandPooling, MVK_CONFIG_USE_COMMAND_POOLING); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.useMTLHeap, MVK_CONFIG_USE_MTLHEAP); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.apiVersionToAdvertise, MVK_CONFIG_API_VERSION_TO_ADVERTISE); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.advertiseExtensions, MVK_CONFIG_ADVERTISE_EXTENSIONS); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.resumeLostDevice, MVK_CONFIG_RESUME_LOST_DEVICE); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.useMetalArgumentBuffers, MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS); - MVK_SET_FROM_ENV_OR_BUILD_INT32 (evCfg.shaderSourceCompressionAlgorithm, MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM); - MVK_SET_FROM_ENV_OR_BUILD_BOOL (evCfg.shouldMaximizeConcurrentCompilation, MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION); +#define STR(name) #name + +#define MVK_CONFIG_MEMBER(member, mbrType, name) \ + evCfg.member = (mbrType)mvkGetEnvVarNumber(STR(MVK_CONFIG_##name), MVK_CONFIG_##name); + +#define MVK_CONFIG_MEMBER_STRING(member, strObj, name) \ + evCfg.member = mvkGetEnvVarString(STR(MVK_CONFIG_##name), strObj, MVK_CONFIG_##name); + +#include "MVKConfigMembers.def" + + // At this point, debugMode has been set by env var MVK_CONFIG_DEBUG. + // MVK_CONFIG_DEBUG replaced the deprecataed MVK_DEBUG env var, so for + // legacy use, if the MVK_DEBUG env var is explicitly set, override debugMode. + double noEV = -3.1415; // An unlikely env var value. + double cvMVKDebug = mvkGetEnvVarNumber("MVK_DEBUG", noEV); + if (cvMVKDebug != noEV) { evCfg.debugMode = cvMVKDebug; } // Deprected legacy VkSemaphore MVK_ALLOW_METAL_FENCES and MVK_ALLOW_METAL_EVENTS config. // Legacy MVK_ALLOW_METAL_EVENTS is covered by MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE, @@ -71,9 +50,7 @@ static void mvkInitConfigFromEnvVars() { // disabled, disable semaphoreUseMTLEvent (aliased as semaphoreSupportStyle value // MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE), and let mvkSetConfig() // further process legacy behavior of MVK_ALLOW_METAL_FENCES. - bool sem4UseMTLEvent; - MVK_SET_FROM_ENV_OR_BUILD_BOOL(sem4UseMTLEvent, MVK_ALLOW_METAL_EVENTS); - if ( !sem4UseMTLEvent ) { + if ( !mvkGetEnvVarNumber("MVK_CONFIG_ALLOW_METAL_EVENTS", 1.0) ) { evCfg.semaphoreUseMTLEvent = (MVKVkSemaphoreSupportStyle)false; // Disabled. Also semaphoreSupportStyle MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE. } @@ -81,13 +58,11 @@ static void mvkInitConfigFromEnvVars() { // MVK_CONFIG_PERFORMANCE_LOGGING_INLINE env var was used, and activityPerformanceLoggingStyle // was not already set by MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE, set // activityPerformanceLoggingStyle to MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_IMMEDIATE. - bool logPerfInline; - MVK_SET_FROM_ENV_OR_BUILD_BOOL(logPerfInline, MVK_CONFIG_PERFORMANCE_LOGGING_INLINE); + bool logPerfInline = mvkGetEnvVarNumber("MVK_CONFIG_PERFORMANCE_LOGGING_INLINE", 0.0); if (logPerfInline && evCfg.activityPerformanceLoggingStyle == MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT) { evCfg.activityPerformanceLoggingStyle = MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_IMMEDIATE; } - mvkSetConfig(evCfg); } @@ -129,4 +104,7 @@ void mvkSetConfig(const MVKConfiguration& mvkConfig) { _autoGPUCaptureOutputFile = _mvkConfig.autoGPUCaptureOutputFilepath; } _mvkConfig.autoGPUCaptureOutputFilepath = (char*)_autoGPUCaptureOutputFile.c_str(); + + // Clamp timestampPeriodLowPassAlpha between 0.0 and 1.0. + _mvkConfig.timestampPeriodLowPassAlpha = mvkClamp(_mvkConfig.timestampPeriodLowPassAlpha, 0.0f, 1.0f); } diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h index 86215bf9..f6f1ae9e 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h @@ -82,6 +82,14 @@ const MVKConfiguration& mvkConfig(); /** Global function to update MoltenVK configuration info. */ void mvkSetConfig(const MVKConfiguration& mvkConfig); +/** + * Enable debug mode. + * By default, disabled for Release builds and enabled for Debug builds. + */ +#ifndef MVK_CONFIG_DEBUG +# define MVK_CONFIG_DEBUG MVK_DEBUG +#endif + /** Flip the vertex coordinate in shaders. Enabled by default. */ #ifndef MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y # define MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y 1 @@ -244,11 +252,17 @@ void mvkSetConfig(const MVKConfiguration& mvkConfig); #ifndef MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE # define MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE #endif -#ifndef MVK_ALLOW_METAL_EVENTS // Deprecated -# define MVK_ALLOW_METAL_EVENTS 1 +#ifndef MVK_CONFIG_ALLOW_METAL_EVENTS +# define MVK_CONFIG_ALLOW_METAL_EVENTS 1 #endif -#ifndef MVK_ALLOW_METAL_FENCES // Deprecated -# define MVK_ALLOW_METAL_FENCES 1 +#ifndef MVK_ALLOW_METAL_EVENTS // Deprecated +# define MVK_ALLOW_METAL_EVENTS MVK_CONFIG_ALLOW_METAL_EVENTS +#endif +#ifndef MVK_CONFIG_ALLOW_METAL_FENCES +# define MVK_CONFIG_ALLOW_METAL_FENCES 1 +#endif +#ifndef MVK_ALLOW_METAL_FENCES // Deprecated +# define MVK_ALLOW_METAL_FENCES MVK_CONFIG_ALLOW_METAL_FENCES #endif /** Substitute Metal 2D textures for Vulkan 1D images. Enabled by default. */ @@ -303,3 +317,11 @@ void mvkSetConfig(const MVKConfiguration& mvkConfig); #ifndef MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION # define MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION 0 #endif + +/** + * The alpha value of a lowpass filter tracking VkPhysicalDeviceLimits::timestampPeriod. + * This can be set to a float between 0.0 and 1.0. + */ +#ifndef MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA +# define MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA 0.05 +#endif diff --git a/Scripts/runcts b/Scripts/runcts index bf65cc9e..73aee7c6 100755 --- a/Scripts/runcts +++ b/Scripts/runcts @@ -103,7 +103,7 @@ export METAL_DEBUG_ERROR_MODE=3 # ----- MoltenVK config settings ------ export MVK_CONFIG_LOG_LEVEL=1 #(1 = Errors only, 3 = Info) -export MVK_DEBUG=0 +export MVK_CONFIG_DEBUG=0 # Additional MoltenVK configuration can be set here by editing below. export MVK_CONFIG_RESUME_LOST_DEVICE=1