Merge pull request #1281 from cdavis5e/enhanced-cmdbuf-errors

Log enhanced command buffer errors in debug mode.
diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h
index 39b3202..315b6fe 100644
--- a/Common/MVKOSExtensions.h
+++ b/Common/MVKOSExtensions.h
@@ -118,18 +118,18 @@
  */
 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;				\
+#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;					\
+#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)
 
 #define MVK_SET_FROM_ENV_OR_BUILD_INT32(cfgVal, EV)				\
@@ -140,11 +140,12 @@
 		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)	\
-	do {												\
-		bool wasFound = false;							\
-		std::string ev = mvkGetEnvVar(#EV, &wasFound);	\
-		cfgVal = wasFound ? std::move(ev) : EV;			\
+#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)
 
 
diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md
index f838c17..cf58d67 100644
--- a/Docs/Whats_New.md
+++ b/Docs/Whats_New.md
@@ -13,6 +13,19 @@
 
 
 
+MoltenVK 1.1.3
+--------------
+
+Released TBD
+
+- Add `MVKConfiguration::apiVersionToAdvertise` and `MVK_CONFIG_API_VERSION_TO_ADVERTISE` 
+  env var to configure **MoltenVK** to advertise a particular _Vulkan_ version.
+- Add `MVKConfiguration::advertiseExtensions` and `MVK_CONFIG_ADVERTISE_EXTENSIONS` 
+  env var to configure **MoltenVK** to not advertise support for any _Vulkan_  extensions.
+- Update `VK_MVK_MOLTENVK_SPEC_VERSION` to `31`.
+
+
+
 MoltenVK 1.1.2
 --------------
 
diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
index c549151..f641202 100644
--- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
+++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h
@@ -50,12 +50,12 @@
  */
 #define MVK_VERSION_MAJOR   1
 #define MVK_VERSION_MINOR   1
-#define MVK_VERSION_PATCH   2
+#define MVK_VERSION_PATCH   3
 
 #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 VK_MVK_MOLTENVK_SPEC_VERSION            30
+#define VK_MVK_MOLTENVK_SPEC_VERSION            31
 #define VK_MVK_MOLTENVK_EXTENSION_NAME          "VK_MVK_moltenvk"
 
 /**
@@ -613,7 +613,7 @@
 	 * runtime environment variable or MoltenVK compile-time build setting.
 	 * If neither is set, automatic GPU capture will be handled by the Xcode user interface.
 	 */
-	char* autoGPUCaptureOutputFilepath;
+	const char* autoGPUCaptureOutputFilepath;
 
 	/**
 	 * Controls whether MoltenVK should use a Metal 2D texture with a height of 1 for a
@@ -710,6 +710,44 @@
 	 */
 	VkBool32 logActivityPerformanceInline;
 
+	/**
+	 * 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_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 whether MoltenVK should advertise the Vulkan extensions it supports in
+	 * vkEnumerateInstanceExtensionProperties() and vkEnumerateDeviceExtensionProperties().
+	 * If this setting is enabled, all supported extensions will be advertised.
+	 * If this setting is disabled, only VK_KHR_portability_subset 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, this setting is enabled by default, and all supported
+	 * extensions will be advertised.
+	 */
+	VkBool32 advertiseExtensions;
+
 } MVKConfiguration;
 
 /**
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index b39af4c..a023c20 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -1149,7 +1149,7 @@
 void MVKPhysicalDevice::initProperties() {
 	mvkClear(&_properties);	// Start with everything cleared
 
-	_properties.apiVersion = MVK_VULKAN_API_VERSION;
+	_properties.apiVersion = mvkGetMVKConfiguration()->apiVersionToAdvertise;
 	_properties.driverVersion = MVK_VERSION;
 
 	initGPUInfoProperties();
@@ -3694,7 +3694,7 @@
 		captureDesc.captureObject = mtlCaptureObject;
 		captureDesc.destination = MTLCaptureDestinationDeveloperTools;
 
-		char* filePath = mvkGetMVKConfiguration()->autoGPUCaptureOutputFilepath;
+		const char* filePath = mvkGetMVKConfiguration()->autoGPUCaptureOutputFilepath;
 		if (strlen(filePath)) {
 			if ([captureMgr respondsToSelector: @selector(supportsDestination:)] &&
 				[captureMgr supportsDestination: MTLCaptureDestinationGPUTraceDocument] ) {
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
index ff98440..fdc72a2 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm
@@ -364,7 +364,8 @@
 		setConfigurationResult(reportError(VK_ERROR_INCOMPATIBLE_DRIVER, "To support Mac Catalyst, MoltenVK requires macOS 11.0 or above."));
 	}
 
-	MVKLogInfo("Created VkInstance with the following %d Vulkan extensions enabled:%s",
+	MVKLogInfo("Created VkInstance for Vulkan version %s, as requested by app, with the following %d Vulkan extensions enabled:%s",
+			   mvkGetVulkanVersionString(_appInfo.apiVersion).c_str(),
 			   _enabledExtensions.getEnabledCount(),
 			   _enabledExtensions.enabledNamesString("\n\t\t", true).c_str());
 
@@ -681,9 +682,9 @@
 
 void MVKInstance::logVersions() {
 	MVKExtensionList allExtns(this, true);
-	MVKLogInfo("MoltenVK version %s. Vulkan version %s.\n\tThe following %d Vulkan extensions are supported:%s",
+	MVKLogInfo("MoltenVK version %s, supporting Vulkan version %s.\n\tThe following %d Vulkan extensions are supported:%s",
 			   mvkGetMoltenVKVersionString(MVK_VERSION).c_str(),
-			   mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION).c_str(),
+			   mvkGetVulkanVersionString(mvkGetMVKConfiguration()->apiVersionToAdvertise).c_str(),
 			   allExtns.getEnabledCount(),
 			   allExtns.enabledNamesString("\n\t\t", true).c_str());
 }
diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
index 45d342a..d7d0a59 100644
--- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm
@@ -45,37 +45,38 @@
 
 // Returns whether the specified properties are valid for this platform
 static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) {
-#define MVK_DISABLED_EXTENSION(EXT) \
-	if (pProperties == &kVkExtProps_##EXT) { return false; }
+#define MVK_NA  kMVKOSVersionUnsupported
 #define MVK_EXTENSION_MIN_OS(EXT, MAC, IOS) \
 	if (pProperties == &kVkExtProps_##EXT) { return mvkOSVersionIsAtLeast(MAC, IOS); }
-#if MVK_MACOS
-	MVK_DISABLED_EXTENSION(MVK_IOS_SURFACE)
 
-	MVK_EXTENSION_MIN_OS(EXT_HDR_METADATA,                   10.15, 99999.0)
-	MVK_EXTENSION_MIN_OS(AMD_SHADER_IMAGE_LOAD_STORE_LOD,    10.16, 8.0)
-	MVK_EXTENSION_MIN_OS(IMG_FORMAT_PVRTC,                   10.16, 8.0)
-#endif
-#if MVK_IOS_OR_TVOS
-	MVK_DISABLED_EXTENSION(MVK_MACOS_SURFACE)
-	MVK_DISABLED_EXTENSION(EXT_HDR_METADATA)
+	// Extensions that must always be advertised if supported on platform
+	MVK_EXTENSION_MIN_OS(KHR_PORTABILITY_SUBSET,             10.11,  8.0)
 
-	MVK_EXTENSION_MIN_OS(KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE,   10.11, 14.0)
-	MVK_EXTENSION_MIN_OS(EXT_SWAPCHAIN_COLOR_SPACE,          10.11, 9.0)
-#endif
-	MVK_EXTENSION_MIN_OS(KHR_SHADER_SUBGROUP_EXTENDED_TYPES, 10.14, 13.0)
-	MVK_EXTENSION_MIN_OS(EXT_FRAGMENT_SHADER_INTERLOCK,      10.13, 11.0)
-	MVK_EXTENSION_MIN_OS(EXT_MEMORY_BUDGET,                  10.13, 11.0)
-	MVK_EXTENSION_MIN_OS(EXT_POST_DEPTH_COVERAGE,            10.16, 11.0)
-	MVK_EXTENSION_MIN_OS(EXT_SHADER_STENCIL_EXPORT,          10.14, 12.0)
-	MVK_EXTENSION_MIN_OS(EXT_SUBGROUP_SIZE_CONTROL,          10.14, 13.0)
-	MVK_EXTENSION_MIN_OS(EXT_TEXEL_BUFFER_ALIGNMENT,         10.13, 11.0)
-	MVK_EXTENSION_MIN_OS(EXT_TEXTURE_COMPRESSION_ASTC_HDR,   10.16, 13.0)
-	MVK_EXTENSION_MIN_OS(AMD_SHADER_TRINARY_MINMAX,          10.14, 12.0)
+	// For all other extensions, only advertise if configured to do so
+	if ( !mvkGetMVKConfiguration()->advertiseExtensions ) { return false; }
 
-#undef MVK_DISABLED_EXTENSION
-#undef MVK_EXTENSION_MIN_OS
+	MVK_EXTENSION_MIN_OS(MVK_IOS_SURFACE,                    MVK_NA, 8.0)
+	MVK_EXTENSION_MIN_OS(MVK_MACOS_SURFACE,                  10.11,  MVK_NA)
+
+	MVK_EXTENSION_MIN_OS(EXT_HDR_METADATA,                   10.15,  MVK_NA)
+	MVK_EXTENSION_MIN_OS(AMD_SHADER_IMAGE_LOAD_STORE_LOD,    10.16,  8.0)
+	MVK_EXTENSION_MIN_OS(IMG_FORMAT_PVRTC,                   10.16,  8.0)
+	MVK_EXTENSION_MIN_OS(KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE,   10.11,  14.0)
+	MVK_EXTENSION_MIN_OS(EXT_SWAPCHAIN_COLOR_SPACE,          10.11,  9.0)
+	MVK_EXTENSION_MIN_OS(KHR_SHADER_SUBGROUP_EXTENDED_TYPES, 10.14,  13.0)
+	MVK_EXTENSION_MIN_OS(EXT_FRAGMENT_SHADER_INTERLOCK,      10.13,  11.0)
+	MVK_EXTENSION_MIN_OS(EXT_MEMORY_BUDGET,                  10.13,  11.0)
+	MVK_EXTENSION_MIN_OS(EXT_POST_DEPTH_COVERAGE,            10.16,  11.0)
+	MVK_EXTENSION_MIN_OS(EXT_SHADER_STENCIL_EXPORT,          10.14,  12.0)
+	MVK_EXTENSION_MIN_OS(EXT_SUBGROUP_SIZE_CONTROL,          10.14,  13.0)
+	MVK_EXTENSION_MIN_OS(EXT_TEXEL_BUFFER_ALIGNMENT,         10.13,  11.0)
+	MVK_EXTENSION_MIN_OS(EXT_TEXTURE_COMPRESSION_ASTC_HDR,   10.16,  13.0)
+	MVK_EXTENSION_MIN_OS(AMD_SHADER_TRINARY_MINMAX,          10.14,  12.0)
+
 	return true;
+
+#undef MVK_NA
+#undef MVK_EXTENSION_MIN_OS
 }
 
 // Disable by default unless asked to enable for platform and the extension is valid for this platform
diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.mm b/MoltenVK/MoltenVK/Layers/MVKLayers.mm
index a1b124e..ddbc790 100644
--- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm
+++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm
@@ -45,7 +45,7 @@
 	strcpy(_layerProperties.layerName, "MoltenVK");
 	mvkClear(_layerProperties.description, VK_MAX_DESCRIPTION_SIZE);
 	strcpy(_layerProperties.description, "MoltenVK driver layer");
-	_layerProperties.specVersion = MVK_VULKAN_API_VERSION;
+	_layerProperties.specVersion = mvkGetMVKConfiguration()->apiVersionToAdvertise;
 	_layerProperties.implementationVersion = MVK_VERSION;
 
 	((MVKExtensionList*)&_supportedInstanceExtensions)->disableAllButEnabledInstanceExtensions();
diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp
index a152787..11927b9 100644
--- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp
+++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp
@@ -20,63 +20,76 @@
 #include "MVKOSExtensions.h"
 
 
-std::string _autoGPUCaptureOutputFile;
-static MVKConfiguration _mvkConfig;
 static bool _mvkConfigInitialized = false;
-
-static void mvkInitConfig() {
+static void mvkInitConfigFromEnvVars() {
 	_mvkConfigInitialized = true;
 
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.debugMode,                              MVK_DEBUG);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.shaderConversionFlipVertexY,            MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.synchronousQueueSubmits,                MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.prefillMetalCommandBuffers,             MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS);
-	MVK_SET_FROM_ENV_OR_BUILD_INT32 (_mvkConfig.maxActiveMetalCommandBuffersPerQueue,   MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.supportLargeQueryPools,                 MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.presentWithCommandBuffer,               MVK_CONFIG_PRESENT_WITH_COMMAND_BUFFER);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.swapchainMagFilterUseNearest,           MVK_CONFIG_SWAPCHAIN_MAG_FILTER_USE_NEAREST);
-	MVK_SET_FROM_ENV_OR_BUILD_INT64 (_mvkConfig.metalCompileTimeout,                    MVK_CONFIG_METAL_COMPILE_TIMEOUT);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.performanceTracking,                    MVK_CONFIG_PERFORMANCE_TRACKING);
-	MVK_SET_FROM_ENV_OR_BUILD_INT32 (_mvkConfig.performanceLoggingFrameCount,           MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.logActivityPerformanceInline,           MVK_CONFIG_PERFORMANCE_LOGGING_INLINE);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.displayWatermark,                       MVK_CONFIG_DISPLAY_WATERMARK);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.specializedQueueFamilies,               MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.switchSystemGPU,                        MVK_CONFIG_SWITCH_SYSTEM_GPU);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.fullImageViewSwizzle,                   MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.defaultGPUCaptureScopeQueueFamilyIndex, MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.defaultGPUCaptureScopeQueueIndex,       MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.fastMathEnabled,                        MVK_CONFIG_FAST_MATH_ENABLED);
+	MVKConfiguration evCfg;
+	std::string evGPUCapFileStrObj;
 
-	MVK_SET_FROM_ENV_OR_BUILD_INT32 (_mvkConfig.logLevel,                               MVK_CONFIG_LOG_LEVEL);
-	MVK_SET_FROM_ENV_OR_BUILD_INT32 (_mvkConfig.traceVulkanCalls,                       MVK_CONFIG_TRACE_VULKAN_CALLS);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.forceLowPowerGPU,                       MVK_CONFIG_FORCE_LOW_POWER_GPU);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.semaphoreUseMTLFence,                   MVK_ALLOW_METAL_FENCES);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.semaphoreUseMTLEvent,                   MVK_ALLOW_METAL_EVENTS);
-	MVK_SET_FROM_ENV_OR_BUILD_INT32 (_mvkConfig.autoGPUCaptureScope,                    MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE);
-	MVK_SET_FROM_ENV_OR_BUILD_STRING(_autoGPUCaptureOutputFile,                         MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE);
-	_mvkConfig.autoGPUCaptureOutputFilepath = (char*)_autoGPUCaptureOutputFile.c_str();
+	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_BOOL  (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.swapchainMagFilterUseNearest,           MVK_CONFIG_SWAPCHAIN_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_BOOL  (evCfg.logActivityPerformanceInline,           MVK_CONFIG_PERFORMANCE_LOGGING_INLINE);
+	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_BOOL  (evCfg.fastMathEnabled,                        MVK_CONFIG_FAST_MATH_ENABLED);
 
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.texture1DAs2D,                          MVK_CONFIG_TEXTURE_1D_AS_2D);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.preallocateDescriptors,                 MVK_CONFIG_PREALLOCATE_DESCRIPTORS);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.useCommandPooling,                      MVK_CONFIG_USE_COMMAND_POOLING);
-	MVK_SET_FROM_ENV_OR_BUILD_BOOL  (_mvkConfig.useMTLHeap,                             MVK_CONFIG_USE_MTLHEAP);
+	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_BOOL  (evCfg.semaphoreUseMTLEvent,                   MVK_ALLOW_METAL_EVENTS);
+	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_BOOL  (evCfg.advertiseExtensions,                    MVK_CONFIG_ADVERTISE_EXTENSIONS);
+
+	mvkSetMVKConfiguration(&evCfg);
 }
 
+static MVKConfiguration _mvkConfig;
+static std::string _autoGPUCaptureOutputFile;
+
 // Returns the MoltenVK config, lazily initializing it if necessary.
 // We initialize lazily instead of in a library constructor function to
 // ensure the NSProcessInfo environment is available when called upon.
 const MVKConfiguration* mvkGetMVKConfiguration() {
 	if ( !_mvkConfigInitialized ) {
-		mvkInitConfig();
+		mvkInitConfigFromEnvVars();
 	}
 	return &_mvkConfig;
 }
 
-// Updates config content, and updates any strings in MVKConfiguration by copying
-// the contents from the MVKConfiguration member to a corresponding std::string,
-// and then repointing the MVKConfiguration member to the contents of the std::string.
+// Sets config content, and updates any content that needs baking, including copying the contents
+// of strings from the incoming MVKConfiguration member to a corresponding std::string, and then
+// repointing the MVKConfiguration member to the contents of the std::string.
 void mvkSetMVKConfiguration(MVKConfiguration* pMVKConfig) {
 	_mvkConfig = *pMVKConfig;
+
+	// Ensure the API version is supported, and add the VK_HEADER_VERSION.
+	_mvkConfig.apiVersionToAdvertise = std::min(_mvkConfig.apiVersionToAdvertise, MVK_VULKAN_API_VERSION);
+	_mvkConfig.apiVersionToAdvertise = VK_MAKE_VERSION(VK_VERSION_MAJOR(_mvkConfig.apiVersionToAdvertise),
+													   VK_VERSION_MINOR(_mvkConfig.apiVersionToAdvertise),
+													   VK_HEADER_VERSION);
+	
+	// Set capture file path string
 	if (_mvkConfig.autoGPUCaptureOutputFilepath) {
 		_autoGPUCaptureOutputFile = _mvkConfig.autoGPUCaptureOutputFilepath;
 	}
diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
index 9650365..ede6ac8 100644
--- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
+++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h
@@ -274,6 +274,16 @@
 #endif
 
 /** Use MTLHeaps where possible when allocating MTLBuffers and MTLTextures. Disabled by default. */
-#	ifndef MVK_CONFIG_USE_MTLHEAP
-#   	define MVK_CONFIG_USE_MTLHEAP    0
-#	endif
+#ifndef MVK_CONFIG_USE_MTLHEAP
+#  	define MVK_CONFIG_USE_MTLHEAP    0
+#endif
+
+/** The Vulkan API version to advertise. Defaults to MVK_VULKAN_API_VERSION. */
+#ifndef MVK_CONFIG_API_VERSION_TO_ADVERTISE
+#  	define MVK_CONFIG_API_VERSION_TO_ADVERTISE    MVK_VULKAN_API_VERSION
+#endif
+
+/** Advertise supported extensions. Enabled by default. */
+#ifndef MVK_CONFIG_ADVERTISE_EXTENSIONS
+#  	define MVK_CONFIG_ADVERTISE_EXTENSIONS    1
+#endif
diff --git a/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm b/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm
index b2a216e..aedcbc1 100644
--- a/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vk_mvk_moltenvk.mm
@@ -99,7 +99,7 @@
 	len = mvkVer.copy(pMoltenVersionStringBuffer, moltenVersionStringBufferLength - 1);
 	pMoltenVersionStringBuffer[len] = 0;    // terminator
 
-	string vkVer = mvkGetVulkanVersionString(MVK_VULKAN_API_VERSION);
+	string vkVer = mvkGetVulkanVersionString(mvkGetMVKConfiguration()->apiVersionToAdvertise);
 	len = vkVer.copy(pVulkanVersionStringBuffer, vulkanVersionStringBufferLength - 1);
 	pVulkanVersionStringBuffer[len] = 0;    // terminator
 }
diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
index f12ed43..208d543 100644
--- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm
+++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm
@@ -1919,7 +1919,7 @@
     uint32_t*                                   pApiVersion) {
 
     MVKTraceVulkanCallStart();
-    *pApiVersion = MVK_VULKAN_API_VERSION;
+    *pApiVersion = mvkGetMVKConfiguration()->apiVersionToAdvertise;
     MVKTraceVulkanCallEnd();
     return VK_SUCCESS;
 }