From 10625a86384f0c170101b48bd532753bf6e637a0 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 4 Sep 2023 21:45:42 -0400 Subject: [PATCH 01/14] Add support for VK_EXT_layer_settings extension. --- Common/MVKCommonEnvironment.h | 7 +- Docs/MoltenVK_Runtime_UserGuide.md | 11 +-- Docs/Whats_New.md | 2 + MoltenVK/MoltenVK/API/mvk_config.h | 14 ++-- .../MoltenVK/Commands/MVKCommandBuffer.mm | 4 +- .../MoltenVK/GPUObjects/MVKDescriptorSet.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 4 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 48 ++++++------ MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 4 +- MoltenVK/MoltenVK/GPUObjects/MVKInstance.h | 5 ++ MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 74 ++++++++++++++++++- MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 8 +- .../MoltenVK/GPUObjects/MVKPixelFormats.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm | 20 ++--- .../MoltenVK/GPUObjects/MVKShaderModule.mm | 6 +- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 10 +-- MoltenVK/MoltenVK/GPUObjects/MVKSync.mm | 2 +- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/Layers/MVKLayers.mm | 2 +- MoltenVK/MoltenVK/Utility/MVKBaseObject.h | 7 ++ MoltenVK/MoltenVK/Utility/MVKBaseObject.mm | 9 ++- MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp | 7 +- MoltenVK/MoltenVK/Utility/MVKLogging.h | 2 +- Scripts/runcts | 2 +- 25 files changed, 180 insertions(+), 75 deletions(-) diff --git a/Common/MVKCommonEnvironment.h b/Common/MVKCommonEnvironment.h index a14ba91d0..a1bbfd871 100644 --- a/Common/MVKCommonEnvironment.h +++ b/Common/MVKCommonEnvironment.h @@ -31,8 +31,8 @@ extern "C" { * Compiler build setting that ensures a definite value for whether this * build is a debug build or not. * - * If the standard DEBUG build setting is defined, MVK_DEBUG is set to true, - * otherwise, it is set to false. + * If the standard DEBUG build setting is defined, MVK_CONFIG_DEBUG is + * set to true, otherwise, it is set to false. */ #ifndef MVK_DEBUG # ifdef DEBUG @@ -41,6 +41,9 @@ extern "C" { # define MVK_DEBUG 0 # endif #endif +#ifndef MVK_CONFIG_DEBUG +# define MVK_CONFIG_DEBUG MVK_DEBUG +#endif /** Building for macOS. */ #ifndef MVK_MACOS diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index f236a7e97..47fa35ba0 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -367,6 +367,7 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_host_query_reset` - `VK_EXT_image_robustness` - `VK_EXT_inline_uniform_block` +- `VK_EXT_layer_settings` - `VK_EXT_memory_budget` *(requires Metal 2.0)* - `VK_EXT_metal_objects` - `VK_EXT_metal_surface` @@ -516,11 +517,11 @@ 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` - runtime environment variable to `1`. See the [*MoltenVK Configuration*](#moltenvk_config) - description above. +- 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_CONFIG_DEBUG` runtime environment variable to `1`. See the + [*MoltenVK Configuration*](#moltenvk_config) description above. Enabling debug mode in **MoltenVK** includes shader conversion logging, which causes both the incoming *SPIR-V* code and the converted *MSL* source code to be logged to the console diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 82e9b1558..566c95bc6 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -18,6 +18,8 @@ MoltenVK 1.2.6 Released TBD +- Add support for extensions: + - `VK_EXT_layer_settings` - Fix rare case where vertex attribute buffers are not bound to Metal when no other bindings change between pipelines. diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index 360007e16..0a4c25e7a 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -190,7 +190,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. @@ -940,7 +940,7 @@ typedef struct { #ifndef VK_NO_PROTOTYPES /** - * Populates the pConfiguration structure with the current MoltenVK configuration settings. + * Populates the pConfiguration structure with the current global MoltenVK configuration settings. * * To change a specific configuration value, call vkGetMoltenVKConfigurationMVK() to retrieve * the current configuration, make changes, and call vkSetMoltenVKConfigurationMVK() to @@ -978,7 +978,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( size_t* pConfigurationSize); /** - * Sets the MoltenVK configuration settings to those found in the pConfiguration structure. + * Sets the global MoltenVK configuration settings to those found in the pConfiguration structure. * * To change a specific configuration value, call vkGetMoltenVKConfigurationMVK() * to retrieve the current configuration, make changes, and call @@ -988,8 +988,12 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( * This function can be called before the VkInstance has been created. It is safe to call this function * with a VkInstance retrieved from a different layer in the Vulkan SDK Loader and Layers framework. * - * To be active, some configuration settings must be set before a VkInstance or VkDevice + * To be active, some global configuration settings must be set before a VkInstance or VkDevice * is created. See the description of the MVKConfiguration members for more information. + * If the VkInstance has the VK_EXT_layer_settings extension enabled, this call must be + * performed before the VkInstance is created, and subsequent changes here will not apply + * to that VkInstance and its derivative objects. The VK_EXT_layer_settings extension can + * be used to make futher changes to that VkInstance. * * If you are linking to an implementation of MoltenVK that was compiled from a different * MVK_CONFIGURATION_API_VERSION than your app was, the size of the MVKConfiguration structure @@ -1011,7 +1015,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( * expects MVKConfiguration to be. */ VKAPI_ATTR VkResult VKAPI_CALL vkSetMoltenVKConfigurationMVK( - VkInstance ignored, + VkInstance instance, const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm index 5edc13aaa..a0abfc71a 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandBuffer.mm @@ -121,7 +121,7 @@ if(_device->shouldPrefillMTLCommandBuffers() && !(_isSecondary || _supportsConcurrentExecution)) { @autoreleasepool { _prefilledMTLCmdBuffer = [_commandPool->getMTLCommandBuffer(0) retain]; // retained - auto prefillStyle = mvkConfig().prefillMetalCommandBuffers; + auto prefillStyle = getMVKConfig().prefillMetalCommandBuffers; if (prefillStyle == MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING || prefillStyle == MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_IMMEDIATE_ENCODING_NO_AUTORELEASE ) { _immediateCmdEncodingContext = new MVKCommandEncodingContext; @@ -193,7 +193,7 @@ } void MVKCommandBuffer::checkDeferredEncoding() { - if (mvkConfig().prefillMetalCommandBuffers == MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_DEFERRED_ENCODING) { + if (getMVKConfig().prefillMetalCommandBuffers == MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS_STYLE_DEFERRED_ENCODING) { @autoreleasepool { MVKCommandEncodingContext encodingContext; MVKCommandEncoder encoder(this); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm index 1406ab179..41005c63b 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDescriptorSet.mm @@ -710,7 +710,7 @@ MVKDescriptorPool::MVKDescriptorPool(MVKDevice* device, const VkDescriptorPoolCreateInfo* pCreateInfo) : MVKVulkanAPIDeviceObject(device), - _hasPooledDescriptors(mvkConfig().preallocateDescriptors), // Set this first! Accessed by MVKDescriptorSet constructor and getPoolSize() in following lines. + _hasPooledDescriptors(getMVKConfig().preallocateDescriptors), // Set this first! Accessed by MVKDescriptorSet constructor and getPoolSize() in following lines. _descriptorSets(pCreateInfo->maxSets, MVKDescriptorSet(this)), _descriptorSetAvailablility(pCreateInfo->maxSets, true), _inlineBlockMTLBufferAllocator(device, device->_pMetalFeatures->dynamicMTLBufferSize, true), diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index 450fad661..cb6f9b51e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -352,8 +352,8 @@ class MVKPhysicalDevice : public MVKDispatchableVulkanAPIObject { bool mslVersionIsAtLeast(MTLLanguageVersion minVer) { return _metalFeatures.mslVersionEnum >= minVer; } /** Returns whether this physical device supports Metal argument buffers. */ - bool supportsMetalArgumentBuffers() const { - return _metalFeatures.argumentBuffers && mvkConfig().useMetalArgumentBuffers != MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER; + bool supportsMetalArgumentBuffers() { + return _metalFeatures.argumentBuffers && getMVKConfig().useMetalArgumentBuffers != MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index 0b11d4dfe..ff5759079 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -359,7 +359,7 @@ portabilityFeatures->events = true; portabilityFeatures->imageViewFormatReinterpretation = true; portabilityFeatures->imageViewFormatSwizzle = (_metalFeatures.nativeTextureSwizzle || - mvkConfig().fullImageViewSwizzle); + getMVKConfig().fullImageViewSwizzle); portabilityFeatures->imageView2DOn3DImage = false; portabilityFeatures->multisampleArrayImage = _metalFeatures.multisampleArrayTextures; portabilityFeatures->mutableComparisonSamplers = _metalFeatures.depthSampleCompare; @@ -377,7 +377,7 @@ auto* formatFeatures = (VkPhysicalDevice4444FormatsFeaturesEXT*)next; bool canSupport4444 = _metalFeatures.tileBasedDeferredRendering && (_metalFeatures.nativeTextureSwizzle || - mvkConfig().fullImageViewSwizzle); + getMVKConfig().fullImageViewSwizzle); formatFeatures->formatA4R4G4B4 = canSupport4444; formatFeatures->formatA4B4G4R4 = canSupport4444; break; @@ -893,7 +893,7 @@ case VK_IMAGE_TYPE_1D: maxExt.height = 1; maxExt.depth = 1; - if (!mvkConfig().texture1DAs2D) { + if (!getMVKConfig().texture1DAs2D) { maxExt.width = pLimits->maxImageDimension1D; maxLevels = 1; sampleCounts = VK_SAMPLE_COUNT_1_BIT; @@ -1490,7 +1490,7 @@ MVKArrayRef MVKPhysicalDevice::getQueueFamilies() { if (_queueFamilies.empty()) { VkQueueFamilyProperties qfProps; - bool specialize = mvkConfig().specializedQueueFamilies; + bool specialize = getMVKConfig().specializedQueueFamilies; uint32_t qfIdx = 0; qfProps.queueCount = kMVKQueueCountPerQueueFamily; @@ -1646,8 +1646,8 @@ void MVKPhysicalDevice::initMTLDevice() { #if MVK_XCODE_14_3 && MVK_MACOS && !MVK_MACCAT if ([_mtlDevice respondsToSelector: @selector(setShouldMaximizeConcurrentCompilation:)]) { - [_mtlDevice setShouldMaximizeConcurrentCompilation: mvkConfig().shouldMaximizeConcurrentCompilation]; - MVKLogInfoIf(mvkConfig().debugMode, "maximumConcurrentCompilationTaskCount %lu", _mtlDevice.maximumConcurrentCompilationTaskCount); + [_mtlDevice setShouldMaximizeConcurrentCompilation: getMVKConfig().shouldMaximizeConcurrentCompilation]; + MVKLogInfoIf(getMVKConfig().debugMode, "maximumConcurrentCompilationTaskCount %lu", _mtlDevice.maximumConcurrentCompilationTaskCount); } #endif } @@ -1656,7 +1656,7 @@ void MVKPhysicalDevice::initProperties() { mvkClear(&_properties); // Start with everything cleared - _properties.apiVersion = mvkConfig().apiVersionToAdvertise; + _properties.apiVersion = getMVKConfig().apiVersionToAdvertise; _properties.driverVersion = MVK_VERSION; initGPUInfoProperties(); @@ -1757,7 +1757,7 @@ if ( mvkOSVersionIsAtLeast(13.0) ) { _metalFeatures.mslVersionEnum = MTLLanguageVersion2_2; - _metalFeatures.placementHeaps = mvkConfig().useMTLHeap; + _metalFeatures.placementHeaps = getMVKConfig().useMTLHeap; _metalFeatures.nativeTextureSwizzle = true; if (supportsMTLGPUFamily(Apple3)) { _metalFeatures.native3DCompressedTextures = true; @@ -1865,7 +1865,7 @@ if ( mvkOSVersionIsAtLeast(13.0) ) { _metalFeatures.mslVersionEnum = MTLLanguageVersion2_2; - _metalFeatures.placementHeaps = mvkConfig().useMTLHeap; + _metalFeatures.placementHeaps = getMVKConfig().useMTLHeap; #if MVK_OS_SIMULATOR _metalFeatures.nativeTextureSwizzle = false; #else @@ -1982,7 +1982,7 @@ } if (supportsMTLGPUFamily(Mac2)) { _metalFeatures.nativeTextureSwizzle = true; - _metalFeatures.placementHeaps = mvkConfig().useMTLHeap; + _metalFeatures.placementHeaps = getMVKConfig().useMTLHeap; _metalFeatures.renderWithoutAttachments = true; } } @@ -3206,7 +3206,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope // Default to single queue if other options unavailable. _vkSemaphoreStyle = MVKSemaphoreStyleSingleQueue; - switch (mvkConfig().semaphoreSupportStyle) { + switch (getMVKConfig().semaphoreSupportStyle) { case MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_METAL_EVENTS_WHERE_SAFE: { bool isNVIDIA = _properties.vendorID == kNVVendorId; bool isRosetta2 = _properties.vendorID == kAppleVendorId && !MVK_APPLE_SILICON; @@ -4035,7 +4035,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope MVKCommandPool* MVKDevice::createCommandPool(const VkCommandPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator) { - return new MVKCommandPool(this, pCreateInfo, mvkConfig().useCommandPooling); + return new MVKCommandPool(this, pCreateInfo, getMVKConfig().useCommandPooling); } void MVKDevice::destroyCommandPool(MVKCommandPool* mvkCmdPool, @@ -4417,8 +4417,8 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope MTLCompileOptions* MVKDevice::getMTLCompileOptions(bool requestFastMath, bool preserveInvariance) { MTLCompileOptions* mtlCompOpt = [MTLCompileOptions new]; mtlCompOpt.languageVersion = _pMetalFeatures->mslVersionEnum; - mtlCompOpt.fastMathEnabled = (mvkConfig().fastMathEnabled == MVK_CONFIG_FAST_MATH_ALWAYS || - (mvkConfig().fastMathEnabled == MVK_CONFIG_FAST_MATH_ON_DEMAND && requestFastMath)); + mtlCompOpt.fastMathEnabled = (getMVKConfig().fastMathEnabled == MVK_CONFIG_FAST_MATH_ALWAYS || + (getMVKConfig().fastMathEnabled == MVK_CONFIG_FAST_MATH_ON_DEMAND && requestFastMath)); #if MVK_XCODE_12 if ([mtlCompOpt respondsToSelector: @selector(setPreserveInvariance:)]) { [mtlCompOpt setPreserveInvariance: preserveInvariance]; @@ -4429,7 +4429,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope // Can't use prefilled Metal command buffers if any of the resource descriptors can be updated after binding. bool MVKDevice::shouldPrefillMTLCommandBuffers() { - return (mvkConfig().prefillMetalCommandBuffers && + return (getMVKConfig().prefillMetalCommandBuffers && !(_enabledDescriptorIndexingFeatures.descriptorBindingUniformBufferUpdateAfterBind || _enabledDescriptorIndexingFeatures.descriptorBindingSampledImageUpdateAfterBind || _enabledDescriptorIndexingFeatures.descriptorBindingStorageImageUpdateAfterBind || @@ -4441,7 +4441,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope void MVKDevice::startAutoGPUCapture(MVKConfigAutoGPUCaptureScope autoGPUCaptureScope, id mtlCaptureObject) { - if (_isCurrentlyAutoGPUCapturing || (mvkConfig().autoGPUCaptureScope != autoGPUCaptureScope)) { return; } + if (_isCurrentlyAutoGPUCapturing || (getMVKConfig().autoGPUCaptureScope != autoGPUCaptureScope)) { return; } _isCurrentlyAutoGPUCapturing = true; @@ -4453,7 +4453,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope captureDesc.captureObject = mtlCaptureObject; captureDesc.destination = MTLCaptureDestinationDeveloperTools; - const char* filePath = mvkConfig().autoGPUCaptureOutputFilepath; + const char* filePath = getMVKConfig().autoGPUCaptureOutputFilepath; if (strlen(filePath)) { if ([captureMgr respondsToSelector: @selector(supportsDestination:)] && [captureMgr supportsDestination: MTLCaptureDestinationGPUTraceDocument] ) { @@ -4489,7 +4489,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope } void MVKDevice::stopAutoGPUCapture(MVKConfigAutoGPUCaptureScope autoGPUCaptureScope) { - if (_isCurrentlyAutoGPUCapturing && mvkConfig().autoGPUCaptureScope == autoGPUCaptureScope) { + if (_isCurrentlyAutoGPUCapturing && getMVKConfig().autoGPUCaptureScope == autoGPUCaptureScope) { [[MTLCaptureManager sharedCaptureManager] stopCapture]; _isCurrentlyAutoGPUCapturing = false; } @@ -4565,8 +4565,8 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope return; } - initPerformanceTracking(); initPhysicalDevice(physicalDevice, pCreateInfo); + initPerformanceTracking(); enableExtensions(pCreateInfo); enableFeatures(pCreateInfo); initQueues(pCreateInfo); @@ -4578,7 +4578,7 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope // In a multi-GPU system, if we are using the high-power GPU and want the window system // to also use that GPU to avoid copying content between GPUs, force the window system // to use the high-power GPU by calling the MTLCreateSystemDefaultDevice() function. - if (_enabledExtensions.vk_KHR_swapchain.enabled && mvkConfig().switchSystemGPU && + if (_enabledExtensions.vk_KHR_swapchain.enabled && getMVKConfig().switchSystemGPU && !(_physicalDevice->_mtlDevice.isLowPower || _physicalDevice->_mtlDevice.isHeadless) ) { MTLCreateSystemDefaultDevice(); } @@ -4588,8 +4588,8 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope // Use Metal arg buffs if available, and either config wants them always, // or config wants them with descriptor indexing and descriptor indexing has been enabled. _isUsingMetalArgumentBuffers = (_physicalDevice->supportsMetalArgumentBuffers() && - (mvkConfig().useMetalArgumentBuffers == MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_ALWAYS || - (mvkConfig().useMetalArgumentBuffers == MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING && + (getMVKConfig().useMetalArgumentBuffers == MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_ALWAYS || + (getMVKConfig().useMetalArgumentBuffers == MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING && (_enabledVulkan12FeaturesNoExt.descriptorIndexing || _enabledExtensions.vk_EXT_descriptor_indexing.enabled)))); _commandResourceFactory = new MVKCommandResourceFactory(this); @@ -4604,8 +4604,8 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope void MVKDevice::initPerformanceTracking() { - _isPerformanceTracking = mvkConfig().performanceTracking; - _activityPerformanceLoggingStyle = mvkConfig().activityPerformanceLoggingStyle; + _isPerformanceTracking = getMVKConfig().performanceTracking; + _activityPerformanceLoggingStyle = getMVKConfig().activityPerformanceLoggingStyle; _performanceStatistics.shaderCompilation.hashShaderCode = {}; _performanceStatistics.shaderCompilation.spirvToMSL = {}; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 148702215..89b98d916 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1030,7 +1030,7 @@ if (validSamples == VK_SAMPLE_COUNT_1_BIT) { return validSamples; } // Don't use getImageType() because it hasn't been set yet. - if ( !((pCreateInfo->imageType == VK_IMAGE_TYPE_2D) || ((pCreateInfo->imageType == VK_IMAGE_TYPE_1D) && mvkConfig().texture1DAs2D)) ) { + if ( !((pCreateInfo->imageType == VK_IMAGE_TYPE_2D) || ((pCreateInfo->imageType == VK_IMAGE_TYPE_1D) && getMVKConfig().texture1DAs2D)) ) { setConfigurationResult(reportError(VK_ERROR_FEATURE_NOT_PRESENT, "vkCreateImage() : Under Metal, multisampling can only be used with a 2D image type. Setting sample count to 1.")); validSamples = VK_SAMPLE_COUNT_1_BIT; } @@ -1809,7 +1809,7 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { // Enable either native or shader swizzling, depending on what is available, preferring native, and return whether successful. bool MVKImageViewPlane::enableSwizzling() { _useNativeSwizzle = _device->_pMetalFeatures->nativeTextureSwizzle; - _useShaderSwizzle = !_useNativeSwizzle && mvkConfig().fullImageViewSwizzle; + _useShaderSwizzle = !_useNativeSwizzle && getMVKConfig().fullImageViewSwizzle; return _useNativeSwizzle || _useShaderSwizzle; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h index 9e41ac71c..04aea66e4 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h @@ -66,6 +66,9 @@ class MVKInstance : public MVKDispatchableVulkanAPIObject { /** Returns a pointer to the Vulkan instance. */ MVKInstance* getInstance() override { return this; } + /** Return the MoltenVK configuration info for this VkInstance. */ + const MVKConfiguration& getMVKConfig() override { return _enabledExtensions.vk_EXT_layer_settings.enabled ? _mvkConfig : mvkConfig(); } + /** Returns the maximum version of Vulkan the application supports. */ inline uint32_t getAPIVersion() { return _appInfo.apiVersion; } @@ -179,6 +182,7 @@ class MVKInstance : public MVKDispatchableVulkanAPIObject { void propagateDebugName() override {} void initProcAddrs(); void initDebugCallbacks(const VkInstanceCreateInfo* pCreateInfo); + void initMVKConfig(const VkInstanceCreateInfo* pCreateInfo); NSArray>* getAvailableMTLDevicesArray(); VkDebugReportFlagsEXT getVkDebugReportFlagsFromLogLevel(MVKConfigLogLevel logLevel); VkDebugUtilsMessageSeverityFlagBitsEXT getVkDebugUtilsMessageSeverityFlagBitsFromLogLevel(MVKConfigLogLevel logLevel); @@ -187,6 +191,7 @@ class MVKInstance : public MVKDispatchableVulkanAPIObject { void logVersions(); VkResult verifyLayers(uint32_t count, const char* const* names); + MVKConfiguration _mvkConfig; VkApplicationInfo _appInfo; MVKSmallVector _physicalDevices; MVKSmallVector _debugReportCallbacks; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 5c6e6cb9b..b952aefef 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -289,7 +289,7 @@ #if MVK_MACOS NSArray* rawMTLDevs = [MTLCopyAllDevices() autorelease]; if (rawMTLDevs) { - bool forceLowPower = mvkConfig().forceLowPowerGPU; + bool forceLowPower = getMVKConfig().forceLowPowerGPU; // Populate the array of appropriate MTLDevices for (id md in rawMTLDevs) { @@ -368,6 +368,7 @@ setConfigurationResult(pWritableExtns->enable(pCreateInfo->enabledExtensionCount, pCreateInfo->ppEnabledExtensionNames, getDriverLayer()->getSupportedInstanceExtensions())); + initMVKConfig(pCreateInfo); MVKLogInfo("Created VkInstance for Vulkan version %s, as requested by app, with the following %d Vulkan extensions enabled:%s", mvkGetVulkanVersionString(_appInfo.apiVersion).c_str(), @@ -397,6 +398,75 @@ } } +#define STR(NAME) #NAME +#define CHECK_CONFIG(name, configSetting, type) \ + if(mvkStringsAreEqual(pSetting->pSettingName, STR(MVK_CONFIG_##name))) { \ + _mvkConfig.configSetting = *(type*)(pSetting->pValues); \ + continue; \ + } + +// If the VK_EXT_layer_settings extension is enabled, initialize the local +// MVKConfiguration from the global version built from environment variables. +void MVKInstance::initMVKConfig(const VkInstanceCreateInfo* pCreateInfo) { + + if ( !_enabledExtensions.vk_EXT_layer_settings.enabled ) { return; } + + _mvkConfig = getMVKConfig(); + + VkLayerSettingsCreateInfoEXT* pLSCreateInfo = nil; + for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { + switch (next->sType) { + case VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT: + pLSCreateInfo = (VkLayerSettingsCreateInfoEXT*)next; + break; + default: + break; + } + } + + if ( !pLSCreateInfo ) { return; } + + for (uint32_t lsIdx = 0; lsIdx < pLSCreateInfo->settingCount; lsIdx++) { + const auto* pSetting = &pLSCreateInfo->pSettings[lsIdx]; + + CHECK_CONFIG(DEBUG, debugMode, VkBool32); + CHECK_CONFIG(SHADER_CONVERSION_FLIP_VERTEX_Y, shaderConversionFlipVertexY, VkBool32); + CHECK_CONFIG(SYNCHRONOUS_QUEUE_SUBMITS, synchronousQueueSubmits, VkBool32); + CHECK_CONFIG(PREFILL_METAL_COMMAND_BUFFERS, prefillMetalCommandBuffers, MVKPrefillMetalCommandBuffersStyle); + CHECK_CONFIG(MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE, maxActiveMetalCommandBuffersPerQueue, uint32_t); + CHECK_CONFIG(SUPPORT_LARGE_QUERY_POOLS, supportLargeQueryPools, VkBool32); + CHECK_CONFIG(PRESENT_WITH_COMMAND_BUFFER, presentWithCommandBuffer, VkBool32); + CHECK_CONFIG(SWAPCHAIN_MIN_MAG_FILTER_USE_NEAREST, swapchainMinMagFilterUseNearest, VkBool32); + CHECK_CONFIG(METAL_COMPILE_TIMEOUT, metalCompileTimeout, uint64_t); + CHECK_CONFIG(PERFORMANCE_TRACKING, performanceTracking, VkBool32); + CHECK_CONFIG(PERFORMANCE_LOGGING_FRAME_COUNT, performanceLoggingFrameCount, uint32_t); + CHECK_CONFIG(ACTIVITY_PERFORMANCE_LOGGING_STYLE, activityPerformanceLoggingStyle, MVKConfigActivityPerformanceLoggingStyle); + CHECK_CONFIG(DISPLAY_WATERMARK, displayWatermark, VkBool32); + CHECK_CONFIG(SPECIALIZED_QUEUE_FAMILIES, specializedQueueFamilies, VkBool32); + CHECK_CONFIG(SWITCH_SYSTEM_GPU, switchSystemGPU, VkBool32); + CHECK_CONFIG(FULL_IMAGE_VIEW_SWIZZLE, fullImageViewSwizzle, VkBool32); + CHECK_CONFIG(DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX, defaultGPUCaptureScopeQueueFamilyIndex, VkBool32); + CHECK_CONFIG(DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX, defaultGPUCaptureScopeQueueIndex, VkBool32); + CHECK_CONFIG(FAST_MATH_ENABLED, fastMathEnabled, MVKConfigFastMath); + CHECK_CONFIG(LOG_LEVEL, logLevel, MVKConfigLogLevel); + CHECK_CONFIG(TRACE_VULKAN_CALLS, traceVulkanCalls, MVKConfigTraceVulkanCalls); + CHECK_CONFIG(FORCE_LOW_POWER_GPU, forceLowPowerGPU, VkBool32); + CHECK_CONFIG(VK_SEMAPHORE_SUPPORT_STYLE, semaphoreSupportStyle, MVKVkSemaphoreSupportStyle); + CHECK_CONFIG(AUTO_GPU_CAPTURE_SCOPE, autoGPUCaptureScope, MVKConfigAutoGPUCaptureScope); + CHECK_CONFIG(AUTO_GPU_CAPTURE_OUTPUT_FILE, autoGPUCaptureOutputFilepath, const char*); + CHECK_CONFIG(TEXTURE_1D_AS_2D, texture1DAs2D, VkBool32); + CHECK_CONFIG(PREALLOCATE_DESCRIPTORS, preallocateDescriptors, VkBool32); + CHECK_CONFIG(USE_COMMAND_POOLING, useCommandPooling, VkBool32); + CHECK_CONFIG(USE_MTLHEAP, useMTLHeap, VkBool32); + CHECK_CONFIG(API_VERSION_TO_ADVERTISE, apiVersionToAdvertise, uint32_t); + CHECK_CONFIG(ADVERTISE_EXTENSIONS, advertiseExtensions, uint32_t); + CHECK_CONFIG(RESUME_LOST_DEVICE, resumeLostDevice, VkBool32); + CHECK_CONFIG(USE_METAL_ARGUMENT_BUFFERS, useMetalArgumentBuffers, MVKUseMetalArgumentBuffers); + CHECK_CONFIG(SHADER_COMPRESSION_ALGORITHM, shaderSourceCompressionAlgorithm, MVKConfigCompressionAlgorithm); + CHECK_CONFIG(SHOULD_MAXIMIZE_CONCURRENT_COMPILATION, shouldMaximizeConcurrentCompilation, VkBool32); + } +} + #define ADD_ENTRY_POINT_MAP(name, func, api, ext1, ext2, isDev) \ _entryPoints[""#name] = { (PFN_vkVoidFunction)&func, api, ext1, ext2, isDev } @@ -761,7 +831,7 @@ MVKExtensionList allExtns(this, true); MVKLogInfo("MoltenVK version %s, supporting Vulkan version %s.\n\tThe following %d Vulkan extensions are supported:%s", mvkGetMoltenVKVersionString(MVK_VERSION).c_str(), - mvkGetVulkanVersionString(mvkConfig().apiVersionToAdvertise).c_str(), + mvkGetVulkanVersionString(getMVKConfig().apiVersionToAdvertise).c_str(), allExtns.getEnabledCount(), allExtns.enabledNamesString("\n\t\t", true).c_str()); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index 13f59b6bc..7b1d467b3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -215,7 +215,7 @@ _pipelineCache(pipelineCache), _flags(flags), _descriptorSetCount(layout->getDescriptorSetCount()), - _fullImageViewSwizzle(mvkConfig().fullImageViewSwizzle) { + _fullImageViewSwizzle(getMVKConfig().fullImageViewSwizzle) { // Establish descriptor counts and push constants use. for (uint32_t stage = kMVKShaderStageVertex; stage < kMVKShaderStageCount; stage++) { @@ -1691,11 +1691,11 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 } shaderConfig.options.mslOptions.ios_support_base_vertex_instance = getDevice()->_pMetalFeatures->baseVertexInstanceDrawing; - shaderConfig.options.mslOptions.texture_1D_as_2D = mvkConfig().texture1DAs2D; + shaderConfig.options.mslOptions.texture_1D_as_2D = getMVKConfig().texture1DAs2D; shaderConfig.options.mslOptions.enable_point_size_builtin = isRenderingPoints(pCreateInfo) || reflectData.pointMode; shaderConfig.options.mslOptions.enable_frag_depth_builtin = pixFmts->isDepthFormat(pixFmts->getMTLPixelFormat(pRendInfo->depthAttachmentFormat)); shaderConfig.options.mslOptions.enable_frag_stencil_ref_builtin = pixFmts->isStencilFormat(pixFmts->getMTLPixelFormat(pRendInfo->stencilAttachmentFormat)); - shaderConfig.options.shouldFlipVertexY = mvkConfig().shaderConversionFlipVertexY; + shaderConfig.options.shouldFlipVertexY = getMVKConfig().shaderConversionFlipVertexY; shaderConfig.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle; shaderConfig.options.mslOptions.tess_domain_origin_lower_left = pTessDomainOriginState && pTessDomainOriginState->domainOrigin == VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT; shaderConfig.options.mslOptions.multiview = mvkIsMultiview(pRendInfo->viewMask); @@ -2070,7 +2070,7 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 shaderConfig.options.mslOptions.swizzle_texture_samples = _fullImageViewSwizzle && !getDevice()->_pMetalFeatures->nativeTextureSwizzle; shaderConfig.options.mslOptions.texture_buffer_native = _device->_pMetalFeatures->textureBuffers; shaderConfig.options.mslOptions.dispatch_base = _allowsDispatchBase; - shaderConfig.options.mslOptions.texture_1D_as_2D = mvkConfig().texture1DAs2D; + shaderConfig.options.mslOptions.texture_1D_as_2D = getMVKConfig().texture1DAs2D; shaderConfig.options.mslOptions.fixed_subgroup_size = mvkIsAnyFlagEnabled(pSS->flags, VK_PIPELINE_SHADER_STAGE_CREATE_ALLOW_VARYING_SUBGROUP_SIZE_BIT_EXT) ? 0 : _device->_pMetalFeatures->maxSubgroupSize; bool useMetalArgBuff = isUsingMetalArgumentBuffers(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index 3044f66d9..828bca380 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -2026,7 +2026,7 @@ #if MVK_IOS || MVK_TVOS bool supportsNativeTextureSwizzle = mtlDev && mvkOSVersionIsAtLeast(13.0); #endif - if (!supportsNativeTextureSwizzle && !mvkConfig().fullImageViewSwizzle) { + if (!supportsNativeTextureSwizzle && !getMVKConfig().fullImageViewSwizzle) { vkDesc.mtlPixelFormat = vkDesc.mtlPixelFormatSubstitute = MTLPixelFormatInvalid; } } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm index 2e0e13682..5275d74ed 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueryPool.mm @@ -307,7 +307,7 @@ MVKOcclusionQueryPool::MVKOcclusionQueryPool(MVKDevice* device, const VkQueryPoolCreateInfo* pCreateInfo) : MVKQueryPool(device, pCreateInfo, 1) { - if (mvkConfig().supportLargeQueryPools) { + if (getMVKConfig().supportLargeQueryPools) { _queryIndexOffset = 0; // Ensure we don't overflow the maximum number of queries diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm index 0ad143072..786e979f8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKQueue.mm @@ -38,7 +38,7 @@ id mtlQ = _mtlQueues[queueIndex]; if ( !mtlQ ) { @autoreleasepool { // Catch any autoreleased objects created during MTLCommandQueue creation - uint32_t maxCmdBuffs = mvkConfig().maxActiveMetalCommandBuffersPerQueue; + uint32_t maxCmdBuffs = getMVKConfig().maxActiveMetalCommandBuffersPerQueue; mtlQ = [_physicalDevice->getMTLDevice() newCommandQueueWithMaxCommandBufferCount: maxCmdBuffs]; // retained _mtlQueues[queueIndex] = mtlQ; } @@ -155,7 +155,7 @@ if ([_mtlQueue respondsToSelector: @selector(commandBufferWithDescriptor:)]) { MTLCommandBufferDescriptor* mtlCmdBuffDesc = [MTLCommandBufferDescriptor new]; // temp retain mtlCmdBuffDesc.retainedReferences = retainRefs; - if (mvkConfig().debugMode) { + if (getMVKConfig().debugMode) { mtlCmdBuffDesc.errorOptions |= MTLCommandBufferErrorOptionEncoderExecutionStatus; } mtlCmdBuff = [_mtlQueue commandBufferWithDescriptor: mtlCmdBuffDesc]; @@ -225,7 +225,7 @@ void MVKQueue::initExecQueue() { _execQueue = nil; - if ( !mvkConfig().synchronousQueueSubmits ) { + if ( !getMVKConfig().synchronousQueueSubmits ) { // Determine the dispatch queue priority dispatch_qos_class_t dqQOS = MVK_DISPATCH_QUEUE_QOS_CLASS; int dqPriority = (1.0 - _priority) * QOS_MIN_RELATIVE_PRIORITY; @@ -247,8 +247,8 @@ void MVKQueue::initGPUCaptureScopes() { _submissionCaptureScope = new MVKGPUCaptureScope(this); - if (_queueFamily->getIndex() == mvkConfig().defaultGPUCaptureScopeQueueFamilyIndex && - _index == mvkConfig().defaultGPUCaptureScopeQueueIndex) { + if (_queueFamily->getIndex() == getMVKConfig().defaultGPUCaptureScopeQueueFamilyIndex && + _index == getMVKConfig().defaultGPUCaptureScopeQueueIndex) { getDevice()->startAutoGPUCapture(MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME, _mtlQueue); _submissionCaptureScope->makeDefault(); @@ -404,11 +404,11 @@ mvkDev->markLost(true); break; default: - if ( !mvkConfig().resumeLostDevice ) { mvkDev->markLost(); } + if ( !getMVKConfig().resumeLostDevice ) { mvkDev->markLost(); } break; } #if MVK_XCODE_12 - if (mvkConfig().debugMode) { + if (getMVKConfig().debugMode) { if (&MTLCommandBufferEncoderInfoErrorKey != nullptr) { if (NSArray>* mtlEncInfo = mtlCB.error.userInfo[MTLCommandBufferEncoderInfoErrorKey]) { MVKLogInfo("Encoders for %p \"%s\":", mtlCB, mtlCB.label ? mtlCB.label.UTF8String : ""); @@ -427,7 +427,7 @@ #endif } #if MVK_XCODE_12 - if (mvkConfig().debugMode && [mtlCB respondsToSelector: @selector(logs)]) { + if (getMVKConfig().debugMode && [mtlCB respondsToSelector: @selector(logs)]) { bool isFirstMsg = true; for (id log in mtlCB.logs) { if (isFirstMsg) { @@ -561,8 +561,8 @@ auto cs = _queue->_submissionCaptureScope; cs->endScope(); cs->beginScope(); - if (_queue->_queueFamily->getIndex() == mvkConfig().defaultGPUCaptureScopeQueueFamilyIndex && - _queue->_index == mvkConfig().defaultGPUCaptureScopeQueueIndex) { + if (_queue->_queueFamily->getIndex() == getMVKConfig().defaultGPUCaptureScopeQueueFamilyIndex && + _queue->_index == getMVKConfig().defaultGPUCaptureScopeQueueIndex) { _queue->getDevice()->stopAutoGPUCapture(MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE_FRAME); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm index a47a65b77..3e7b5c12e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKShaderModule.mm @@ -155,7 +155,7 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD void MVKShaderLibrary::compressMSL(const string& msl) { MVKDevice* mvkDev = _owner->getDevice(); uint64_t startTime = mvkDev->getPerformanceTimestamp(); - _compressedMSL.compress(msl, mvkConfig().shaderSourceCompressionAlgorithm); + _compressedMSL.compress(msl, getMVKConfig().shaderSourceCompressionAlgorithm); mvkDev->addActivityPerformance(mvkDev->_performanceStatistics.shaderCompilation.mslCompress, startTime); } @@ -353,7 +353,7 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD bool MVKShaderModule::convert(SPIRVToMSLConversionConfiguration* pShaderConfig, SPIRVToMSLConversionResult& conversionResult) { - bool shouldLogCode = mvkConfig().debugMode; + bool shouldLogCode = getMVKConfig().debugMode; bool shouldLogEstimatedGLSL = shouldLogCode; // If the SPIR-V converter does not have any code, but the GLSL converter does, @@ -508,7 +508,7 @@ static uint32_t getWorkgroupDimensionSize(const SPIRVWorkgroupSizeDimension& wgD @synchronized (mtlDev) { auto mtlCompileOptions = _owner->getDevice()->getMTLCompileOptions(shaderConversionResults.entryPoint.supportsFastMath, shaderConversionResults.isPositionInvariant); - MVKLogInfoIf(mvkConfig().debugMode, "Compiling Metal shader%s.", mtlCompileOptions.fastMathEnabled ? " with FastMath enabled" : ""); + MVKLogInfoIf(getMVKConfig().debugMode, "Compiling Metal shader%s.", mtlCompileOptions.fastMathEnabled ? " with FastMath enabled" : ""); [mtlDev newLibraryWithSource: mslSourceCode options: mtlCompileOptions completionHandler: ^(id mtlLib, NSError* error) { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 601fbc544..e6f3e5c2e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -138,7 +138,7 @@ // If the product has not been fully licensed, renders the watermark image to the surface. void MVKSwapchain::renderWatermark(id mtlTexture, id mtlCmdBuff) { - if (mvkConfig().displayWatermark) { + if (getMVKConfig().displayWatermark) { if ( !_licenseWatermark ) { _licenseWatermark = new MVKWatermarkRandom(getMTLDevice(), __watermarkTextureContent, @@ -159,7 +159,7 @@ // Calculates and remembers the time interval between frames. void MVKSwapchain::markFrameInterval() { - if ( !(mvkConfig().performanceTracking || _licenseWatermark) ) { return; } + if ( !(getMVKConfig().performanceTracking || _licenseWatermark) ) { return; } uint64_t prevFrameTime = _lastFrameTime; _lastFrameTime = mvkGetTimestamp(); @@ -168,14 +168,14 @@ _device->addActivityPerformance(_device->_performanceStatistics.queue.frameInterval, prevFrameTime, _lastFrameTime); - uint32_t perfLogCntLimit = mvkConfig().performanceLoggingFrameCount; + uint32_t perfLogCntLimit = getMVKConfig().performanceLoggingFrameCount; if ((perfLogCntLimit > 0) && (++_currentPerfLogFrameCount >= perfLogCntLimit)) { _currentPerfLogFrameCount = 0; MVKLogInfo("Performance statistics reporting every: %d frames, avg FPS: %.2f, elapsed time: %.3f seconds:", perfLogCntLimit, (1000.0 / _device->_performanceStatistics.queue.frameInterval.averageDuration), mvkGetElapsedMilliseconds() / 1000.0); - if (mvkConfig().activityPerformanceLoggingStyle == MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT) { + if (getMVKConfig().activityPerformanceLoggingStyle == MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_FRAME_COUNT) { _device->logPerformanceSummary(); } } @@ -341,7 +341,7 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin return; } - auto minMagFilter = mvkConfig().swapchainMinMagFilterUseNearest ? kCAFilterNearest : kCAFilterLinear; + auto minMagFilter = getMVKConfig().swapchainMinMagFilterUseNearest ? kCAFilterNearest : kCAFilterLinear; _mtlLayer.device = getMTLDevice(); _mtlLayer.pixelFormat = getPixelFormats()->getMTLPixelFormat(pCreateInfo->imageFormat); _mtlLayer.maximumDrawableCountMVK = imgCnt; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index efde21cb9..d4ebe72f3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -571,7 +571,7 @@ VkResult mvkWaitSemaphores(MVKDevice* device, dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @autoreleasepool { block(); } }); // Limit timeout to avoid overflow since wait_for() uses wait_until() - chrono::nanoseconds nanoTimeout(min(mvkConfig().metalCompileTimeout, kMVKUndefinedLargeUInt64)); + chrono::nanoseconds nanoTimeout(min(getMVKConfig().metalCompileTimeout, kMVKUndefinedLargeUInt64)); _blocker.wait_for(lock, nanoTimeout, [this]{ return _isCompileDone; }); if ( !_isCompileDone ) { diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index 74a006290..ee292a76c 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -108,6 +108,7 @@ MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0, 1.0) +MVK_EXTENSION(EXT_layer_settings, EXT_LAYER_SETTINGS, INSTANCE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_memory_budget, EXT_MEMORY_BUDGET, DEVICE, 10.13, 11.0, 1.0) MVK_EXTENSION(EXT_metal_objects, EXT_METAL_OBJECTS, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_metal_surface, EXT_METAL_SURFACE, INSTANCE, 10.11, 8.0, 1.0) diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.mm b/MoltenVK/MoltenVK/Layers/MVKLayers.mm index 875722b89..22b2138b9 100644 --- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm +++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm @@ -43,7 +43,7 @@ strcpy(_layerProperties.layerName, "MoltenVK"); mvkClear(_layerProperties.description, VK_MAX_DESCRIPTION_SIZE); strcpy(_layerProperties.description, "MoltenVK driver layer"); - _layerProperties.specVersion = mvkConfig().apiVersionToAdvertise; + _layerProperties.specVersion = getMVKConfig().apiVersionToAdvertise; _layerProperties.implementationVersion = MVK_VERSION; ((MVKExtensionList*)&_supportedInstanceExtensions)->disableAllButEnabledInstanceExtensions(); diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h index 7005e9850..d45f4078b 100644 --- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h +++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h @@ -42,6 +42,13 @@ class MVKBaseObject { /** Returns the Vulkan API opaque object controlling this object. */ virtual MVKVulkanAPIObject* getVulkanAPIObject() = 0; + /** + * If getVulkanAPIObject() does not return NULL, this function returns the MoltenVK + * configuration info for the VkInstance that created the API object, otherwise + * this function returns the global configuration info. + */ + virtual const MVKConfiguration& getMVKConfig(); + /** * Report a message. This includes logging to a standard system logging stream, * and some subclasses will also forward the message to their VkInstance for diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm index 427c32278..7783e9ab3 100644 --- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm +++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm @@ -22,6 +22,7 @@ #include "MVKFoundation.h" #include "MVKOSExtensions.h" #include "MVKStrings.h" +#include using namespace std; @@ -46,6 +47,12 @@ string MVKBaseObject::getClassName() { return mvk::getTypeName(this); } +const MVKConfiguration& MVKBaseObject::getMVKConfig() { + MVKVulkanAPIObject* mvkAPIObj = getVulkanAPIObject(); + MVKInstance* mvkInst = mvkAPIObj ? mvkAPIObj->getInstance() : nullptr; + return mvkInst ? mvkInst->getMVKConfig() : mvkConfig(); +} + void MVKBaseObject::reportMessage(MVKConfigLogLevel logLevel, const char* format, ...) { va_list args; va_start(args, format); @@ -66,7 +73,7 @@ MVKVulkanAPIObject* mvkAPIObj = mvkObj ? mvkObj->getVulkanAPIObject() : nullptr; MVKInstance* mvkInst = mvkAPIObj ? mvkAPIObj->getInstance() : nullptr; bool hasDebugCallbacks = mvkInst && mvkInst->hasDebugCallbacks(); - bool shouldLog = logLevel <= mvkConfig().logLevel; + bool shouldLog = logLevel <= (mvkInst ? mvkInst->getMVKConfig() : mvkConfig()).logLevel; // Fail fast to avoid further unnecessary processing. if ( !(shouldLog || hasDebugCallbacks) ) { return; } diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp index 5aa6f7dbc..d8dd73414 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp @@ -27,7 +27,7 @@ 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.debugMode, MVK_CONFIG_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); @@ -65,6 +65,11 @@ static void mvkInitConfigFromEnvVars() { 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); + // Support legacy environment variable MVK_DEBUG, but only if it has been explicitly set as an environment variable. + bool legacyDebugWasFound = false; + bool legacyDebugEV = mvkGetEnvVarBool("MVK_DEBUG", &legacyDebugWasFound); + if (legacyDebugWasFound) { evCfg.debugMode = legacyDebugEV; } + // 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, // but for backwards compatibility, if legacy MVK_ALLOW_METAL_EVENTS is explicitly diff --git a/MoltenVK/MoltenVK/Utility/MVKLogging.h b/MoltenVK/MoltenVK/Utility/MVKLogging.h index bea3a92f5..c65127b01 100644 --- a/MoltenVK/MoltenVK/Utility/MVKLogging.h +++ b/MoltenVK/MoltenVK/Utility/MVKLogging.h @@ -128,7 +128,7 @@ extern "C" { # define MVK_LOG_LEVEL_INFO MVK_LOGGING_ENABLED #endif #ifndef MVK_LOG_LEVEL_DEBUG -# define MVK_LOG_LEVEL_DEBUG (MVK_LOGGING_ENABLED && MVK_DEBUG) +# define MVK_LOG_LEVEL_DEBUG (MVK_LOGGING_ENABLED && MVK_CONFIG_DEBUG) #endif #ifndef MVK_LOG_LEVEL_TRACE # define MVK_LOG_LEVEL_TRACE 0 diff --git a/Scripts/runcts b/Scripts/runcts index 20ae1abe5..24cd9baa2 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 From 90eb1af19f2351329d7025e8c121dda3fd7a15ca Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Sat, 2 Dec 2023 19:20:31 -0500 Subject: [PATCH 02/14] Add support for extension VK_EXT_headless_surface. - Consolidate info about CAMetalLayer and headless in MVKSurface. - MVKSwapchainImage remove getCAMetalDrawable() and focus on abstracting getMTLTexture(). - MVKPresentableSwapchainImage::getCAMetalDrawable() return nil if headless. - Add MVKPresentableSwapchainImage::_mtlTextureHeadless to support a fixed MTLTexture that is not retrieved from a CAMetalDrawable. - MVKPresentableSwapchainImage refactor signalling semaphores and fences. - MVKPresentableSwapchainImage don't lock when signalling semaphores and fences. - If no present occurs, actualPresentTime will be zero. Set it to current time, instead of to desiredPresentTime, since it's more accurate. - Rework timestamps: - Remove _mvkTimestampBase so mvkGetTimestamp() is equal to mach_absolute_time(), which is used in presentation timing. - Add mvkGetRuntimeNanoseconds(). - Rename mvkGetAbsoluteTime() to mvkGetContinuousNanoseconds(). - Remove mvkGetTimestampPeriod() as unused. - MVKSemaphoreMTLEvent::encodeDeferredSignal remove redundant nil test (unrelated). - Fix swapchain and surface bugs when windowing system is accessed from off the main thread (unrelated). - Log warning when deprecated functions vkCreateMacOSSurfaceMVK() or vkCreateIOSSurfaceMVK() are used (unrelated). - Remove documentation for visionos, as support is not ready (unrelated). --- Common/MVKOSExtensions.h | 42 ++++--- Common/MVKOSExtensions.mm | 43 +++---- Docs/MoltenVK_Runtime_UserGuide.md | 3 + Docs/Whats_New.md | 2 + MoltenVK/MoltenVK.xcodeproj/project.pbxproj | 20 ++-- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 27 ++--- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 20 +--- MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 106 ++++++++++-------- MoltenVK/MoltenVK/GPUObjects/MVKInstance.h | 3 + MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 8 +- .../MoltenVK/GPUObjects/MVKPixelFormats.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKSurface.h | 26 +++-- MoltenVK/MoltenVK/GPUObjects/MVKSurface.mm | 56 +++++++-- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h | 24 ++-- MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm | 102 +++++++++-------- MoltenVK/MoltenVK/GPUObjects/MVKSync.mm | 2 +- MoltenVK/MoltenVK/Layers/MVKExtensions.def | 1 + MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h | 13 ++- ...er+MoltenVK.m => CAMetalLayer+MoltenVK.mm} | 8 ++ MoltenVK/MoltenVK/Vulkan/vulkan.mm | 20 ++++ README.md | 20 +--- 21 files changed, 312 insertions(+), 236 deletions(-) rename MoltenVK/MoltenVK/OS/{CAMetalLayer+MoltenVK.m => CAMetalLayer+MoltenVK.mm} (92%) diff --git a/Common/MVKOSExtensions.h b/Common/MVKOSExtensions.h index f9faba912..2c40602a3 100644 --- a/Common/MVKOSExtensions.h +++ b/Common/MVKOSExtensions.h @@ -24,6 +24,9 @@ #include +#pragma mark - +#pragma mark Operating System versions + typedef float MVKOSVersion; /*** Constant indicating unsupported functionality in an OS. */ @@ -66,20 +69,31 @@ static inline bool mvkOSVersionIsAtLeast(MVKOSVersion macOSMinVer, #endif } + +#pragma mark - +#pragma mark Timestamps + /** - * Returns a monotonic timestamp value for use in Vulkan and performance timestamping. + * Returns a monotonic tick value for use in Vulkan and performance timestamping. * - * The returned value corresponds to the number of CPU "ticks" since the app was initialized. - * - * Calling this value twice, subtracting the first value from the second, and then multiplying - * the result by the value returned by mvkGetTimestampPeriod() will provide an indication of the - * number of nanoseconds between the two calls. The convenience function mvkGetElapsedMilliseconds() - * can be used to perform this calculation. + * The returned value corresponds to the number of CPU ticks since an arbitrary + * point in the past, and does not increment while the system is asleep. */ uint64_t mvkGetTimestamp(); -/** Returns the number of nanoseconds between each increment of the value returned by mvkGetTimestamp(). */ -double mvkGetTimestampPeriod(); +/** + * Returns the number of runtime nanoseconds since an arbitrary point in the past, + * excluding any time spent while the system is asleep. + * + * This value corresponds to the timestamps returned by Metal presentation timings. + */ +uint64_t mvkGetRuntimeNanoseconds(); + +/** + * Returns the number of nanoseconds since an arbitrary point in the past, + * including any time spent while the system is asleep. + */ +uint64_t mvkGetContinuousNanoseconds(); /** * Returns the number of nanoseconds elapsed between startTimestamp and endTimestamp, @@ -97,12 +111,6 @@ uint64_t mvkGetElapsedNanoseconds(uint64_t startTimestamp = 0, uint64_t endTimes */ double mvkGetElapsedMilliseconds(uint64_t startTimestamp = 0, uint64_t endTimestamp = 0); -/** Returns the current absolute time in nanoseconds. */ -uint64_t mvkGetAbsoluteTime(); - -/** Ensures the block is executed on the main thread. */ -void mvkDispatchToMainAndWait(dispatch_block_t block); - #pragma mark - #pragma mark Process environment @@ -141,8 +149,12 @@ uint64_t mvkGetUsedMemorySize(); /** Returns the size of a page of host memory on this platform. */ uint64_t mvkGetHostMemoryPageSize(); + #pragma mark - #pragma mark Threading /** Returns the amount of avaliable CPU cores. */ uint32_t mvkGetAvaliableCPUCores(); + +/** Ensures the block is executed on the main thread. */ +void mvkDispatchToMainAndWait(dispatch_block_t block); diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 93025f2bc..8d33f3d48 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -29,6 +29,10 @@ using namespace std; + +#pragma mark - +#pragma mark Operating System versions + MVKOSVersion mvkOSVersion() { static MVKOSVersion _mvkOSVersion = 0; if ( !_mvkOSVersion ) { @@ -38,43 +42,35 @@ MVKOSVersion mvkOSVersion() { return _mvkOSVersion; } -static uint64_t _mvkTimestampBase; -static double _mvkTimestampPeriod; + +#pragma mark - +#pragma mark Timestamps + static mach_timebase_info_data_t _mvkMachTimebase; -uint64_t mvkGetTimestamp() { return mach_absolute_time() - _mvkTimestampBase; } +uint64_t mvkGetTimestamp() { return mach_absolute_time(); } + +uint64_t mvkGetRuntimeNanoseconds() { return mach_absolute_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; } -double mvkGetTimestampPeriod() { return _mvkTimestampPeriod; } +uint64_t mvkGetContinuousNanoseconds() { return mach_continuous_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; } uint64_t mvkGetElapsedNanoseconds(uint64_t startTimestamp, uint64_t endTimestamp) { if (endTimestamp == 0) { endTimestamp = mvkGetTimestamp(); } - return (endTimestamp - startTimestamp) * _mvkTimestampPeriod; + return (endTimestamp - startTimestamp) * _mvkMachTimebase.numer / _mvkMachTimebase.denom; } double mvkGetElapsedMilliseconds(uint64_t startTimestamp, uint64_t endTimestamp) { return mvkGetElapsedNanoseconds(startTimestamp, endTimestamp) / 1e6; } -uint64_t mvkGetAbsoluteTime() { return mach_continuous_time() * _mvkMachTimebase.numer / _mvkMachTimebase.denom; } - -// Initialize timestamping capabilities on app startup. -//Called automatically when the framework is loaded and initialized. +// Initialize timestamp capabilities on app startup. +// Called automatically when the framework is loaded and initialized. static bool _mvkTimestampsInitialized = false; __attribute__((constructor)) static void MVKInitTimestamps() { if (_mvkTimestampsInitialized ) { return; } _mvkTimestampsInitialized = true; - _mvkTimestampBase = mach_absolute_time(); mach_timebase_info(&_mvkMachTimebase); - _mvkTimestampPeriod = (double)_mvkMachTimebase.numer / (double)_mvkMachTimebase.denom; -} - -void mvkDispatchToMainAndWait(dispatch_block_t block) { - if (NSThread.isMainThread) { - block(); - } else { - dispatch_sync(dispatch_get_main_queue(), block); - } } @@ -145,6 +141,7 @@ uint64_t mvkGetUsedMemorySize() { uint64_t mvkGetHostMemoryPageSize() { return sysconf(_SC_PAGESIZE); } + #pragma mark - #pragma mark Threading @@ -152,3 +149,11 @@ uint64_t mvkGetUsedMemorySize() { uint32_t mvkGetAvaliableCPUCores() { return (uint32_t)[[NSProcessInfo processInfo] activeProcessorCount]; } + +void mvkDispatchToMainAndWait(dispatch_block_t block) { + if (NSThread.isMainThread) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } +} diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 9b00360e3..ee93c8010 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -380,6 +380,9 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_external_memory_host` - `VK_EXT_fragment_shader_interlock` - *Requires Metal 2.0 and Raster Order Groups.* +- `VK_EXT_hdr_metadata` + - *macOS only.* +- `VK_EXT_headless_surface` - `VK_EXT_host_query_reset` - `VK_EXT_image_robustness` - `VK_EXT_inline_uniform_block` diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index e0abbf708..ebafdde45 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -20,11 +20,13 @@ Released TBD - Add support for extensions: - `VK_EXT_extended_dynamic_state3` *(Metal does not support `VK_POLYGON_MODE_POINT`)* + - `VK_EXT_headless_surface` - Fix regression that broke `VK_POLYGON_MODE_LINE`. - Fix regression in marking rendering state dirty after `vkCmdClearAttachments()`. - Reduce disk space consumed after running `fetchDependencies` script by removing intermediate file caches. - Fix rare deadlock during launch via `dlopen()`. - Fix initial value of `VkPhysicalDeviceLimits::timestampPeriod` on non-Apple Silicon GPUs. +- Fix swapchain and surface bugs when windowing system is accessed from off the main thread. - Update to latest SPIRV-Cross: - MSL: Fix regression error in argument buffer runtime arrays. diff --git a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj index 46ff50fc3..be7ca3253 100644 --- a/MoltenVK/MoltenVK.xcodeproj/project.pbxproj +++ b/MoltenVK/MoltenVK.xcodeproj/project.pbxproj @@ -117,7 +117,7 @@ 2FEA0AAF24902F9F00EEF3AD /* MVKLayers.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7A11C7DFB4800632CA3 /* MVKLayers.mm */; }; 2FEA0AB024902F9F00EEF3AD /* MVKFramebuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */; }; 2FEA0AB124902F9F00EEF3AD /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; }; - 2FEA0AB224902F9F00EEF3AD /* CAMetalLayer+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */; }; + 2FEA0AB224902F9F00EEF3AD /* CAMetalLayer+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */; }; 2FEA0AB324902F9F00EEF3AD /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; }; 2FEA0AB424902F9F00EEF3AD /* MVKCmdDebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = A99C90ED229455B300A061DA /* MVKCmdDebug.mm */; }; 45003E73214AD4E500E989CB /* MVKExtensions.def in Headers */ = {isa = PBXBuildFile; fileRef = 45003E6F214AD4C900E989CB /* MVKExtensions.def */; }; @@ -360,8 +360,8 @@ A9E53DE62100B197002781DD /* NSString+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD42100B197002781DD /* NSString+MoltenVK.mm */; }; A9E53DE72100B197002781DD /* MTLTextureDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */; }; A9E53DE82100B197002781DD /* MTLTextureDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */; }; - A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */; }; - A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */; }; + A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */; }; + A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */; }; A9E53DF32100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */; }; A9E53DF42100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h in Headers */ = {isa = PBXBuildFile; fileRef = A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */; }; A9E53DF52100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DF22100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m */; }; @@ -495,7 +495,7 @@ DCFD7F572A45BC6E007BBBF7 /* MVKFramebuffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = A94FB7881C7DFB4800632CA3 /* MVKFramebuffer.mm */; }; DCFD7F582A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = 453638302508A4C6000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m */; }; DCFD7F592A45BC6E007BBBF7 /* MVKMTLBufferAllocation.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9C96DCF1DDC20C20053187F /* MVKMTLBufferAllocation.mm */; }; - DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.m in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */; }; + DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */; }; DCFD7F5B2A45BC6E007BBBF7 /* MVKCmdDispatch.mm in Sources */ = {isa = PBXBuildFile; fileRef = A9096E5D1F81E16300DFBEA6 /* MVKCmdDispatch.mm */; }; DCFD7F5C2A45BC6E007BBBF7 /* MVKCmdDebug.mm in Sources */ = {isa = PBXBuildFile; fileRef = A99C90ED229455B300A061DA /* MVKCmdDebug.mm */; }; /* End PBXBuildFile section */ @@ -691,7 +691,7 @@ A9E53DD32100B197002781DD /* MTLSamplerDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLSamplerDescriptor+MoltenVK.h"; sourceTree = ""; }; A9E53DD42100B197002781DD /* NSString+MoltenVK.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSString+MoltenVK.mm"; sourceTree = ""; }; A9E53DD52100B197002781DD /* MTLTextureDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLTextureDescriptor+MoltenVK.m"; sourceTree = ""; }; - A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CAMetalLayer+MoltenVK.m"; sourceTree = ""; }; + A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "CAMetalLayer+MoltenVK.mm"; sourceTree = ""; }; A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MTLRenderPassDescriptor+MoltenVK.h"; sourceTree = ""; }; A9E53DF22100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLRenderPassDescriptor+MoltenVK.m"; sourceTree = ""; }; A9E53DFA21064F84002781DD /* MTLRenderPipelineDescriptor+MoltenVK.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MTLRenderPipelineDescriptor+MoltenVK.m"; sourceTree = ""; }; @@ -889,7 +889,7 @@ isa = PBXGroup; children = ( A9E53DD12100B197002781DD /* CAMetalLayer+MoltenVK.h */, - A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.m */, + A9E53DD62100B197002781DD /* CAMetalLayer+MoltenVK.mm */, 453638312508A4C7000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.h */, 4536382F2508A4C6000EFFD3 /* MTLRenderPassDepthAttachmentDescriptor+MoltenVK.m */, A9E53DEE2100B302002781DD /* MTLRenderPassDescriptor+MoltenVK.h */, @@ -1703,7 +1703,7 @@ 2FEA0AAF24902F9F00EEF3AD /* MVKLayers.mm in Sources */, 2FEA0AB024902F9F00EEF3AD /* MVKFramebuffer.mm in Sources */, 2FEA0AB124902F9F00EEF3AD /* MVKMTLBufferAllocation.mm in Sources */, - 2FEA0AB224902F9F00EEF3AD /* CAMetalLayer+MoltenVK.m in Sources */, + 2FEA0AB224902F9F00EEF3AD /* CAMetalLayer+MoltenVK.mm in Sources */, 2FEA0AB324902F9F00EEF3AD /* MVKCmdDispatch.mm in Sources */, 2FEA0AB424902F9F00EEF3AD /* MVKCmdDebug.mm in Sources */, ); @@ -1763,7 +1763,7 @@ A94FB7EE1C7DFB4800632CA3 /* MVKFramebuffer.mm in Sources */, 453638382508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */, A9C96DD21DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */, - A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */, + A9E53DE92100B197002781DD /* CAMetalLayer+MoltenVK.mm in Sources */, A9096E5E1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */, A99C90F0229455B300A061DA /* MVKCmdDebug.mm in Sources */, ); @@ -1823,7 +1823,7 @@ A94FB7EF1C7DFB4800632CA3 /* MVKFramebuffer.mm in Sources */, 4536383A2508A4C7000EFFD3 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */, A9C96DD31DDC20C20053187F /* MVKMTLBufferAllocation.mm in Sources */, - A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.m in Sources */, + A9E53DEA2100B197002781DD /* CAMetalLayer+MoltenVK.mm in Sources */, A9096E5F1F81E16300DFBEA6 /* MVKCmdDispatch.mm in Sources */, A99C90F1229455B300A061DA /* MVKCmdDebug.mm in Sources */, ); @@ -1883,7 +1883,7 @@ DCFD7F572A45BC6E007BBBF7 /* MVKFramebuffer.mm in Sources */, DCFD7F582A45BC6E007BBBF7 /* MTLRenderPassStencilAttachmentDescriptor+MoltenVK.m in Sources */, DCFD7F592A45BC6E007BBBF7 /* MVKMTLBufferAllocation.mm in Sources */, - DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.m in Sources */, + DCFD7F5A2A45BC6E007BBBF7 /* CAMetalLayer+MoltenVK.mm in Sources */, DCFD7F5B2A45BC6E007BBBF7 /* MVKCmdDispatch.mm in Sources */, DCFD7F5C2A45BC6E007BBBF7 /* MVKCmdDebug.mm in Sources */, ); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index cbbbfab4e..401c880f9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1204,8 +1204,8 @@ isHeadless = getMTLDevice().isHeadless; #endif - // If this device is headless or the surface does not have a CAMetalLayer, it is not supported. - *pSupported = !(isHeadless || (surface->getCAMetalLayer() == nil)); + // If this device is headless, the surface must be headless. + *pSupported = isHeadless ? surface->isHeadless() : wasConfigurationSuccessful(); return *pSupported ? VK_SUCCESS : surface->getConfigurationResult(); } @@ -1264,13 +1264,12 @@ // The CAlayer underlying the surface must be a CAMetalLayer. MVKSurface* surface = (MVKSurface*)pSurfaceInfo->surface; - CAMetalLayer* mtlLayer = surface->getCAMetalLayer(); - if ( !mtlLayer ) { return surface->getConfigurationResult(); } + if ( !surface->wasConfigurationSuccessful() ) { return surface->getConfigurationResult(); } VkSurfaceCapabilitiesKHR& surfCaps = pSurfaceCapabilities->surfaceCapabilities; surfCaps.minImageCount = _metalFeatures.minSwapchainImageCount; surfCaps.maxImageCount = _metalFeatures.maxSwapchainImageCount; - surfCaps.currentExtent = mvkGetNaturalExtent(mtlLayer); + surfCaps.currentExtent = surface->getNaturalExtent(); surfCaps.minImageExtent = { 1, 1 }; surfCaps.maxImageExtent = { _properties.limits.maxImageDimension2D, _properties.limits.maxImageDimension2D }; surfCaps.maxImageArrayLayers = 1; @@ -1349,9 +1348,7 @@ uint32_t* pCount, VkSurfaceFormatKHR* pSurfaceFormats) { - // The layer underlying the surface view must be a CAMetalLayer. - CAMetalLayer* mtlLayer = surface->getCAMetalLayer(); - if ( !mtlLayer ) { return surface->getConfigurationResult(); } + if ( !surface->wasConfigurationSuccessful() ) { return surface->getConfigurationResult(); } #define addSurfFmt(MTL_FMT) \ do { \ @@ -1474,9 +1471,7 @@ uint32_t* pCount, VkPresentModeKHR* pPresentModes) { - // The layer underlying the surface view must be a CAMetalLayer. - CAMetalLayer* mtlLayer = surface->getCAMetalLayer(); - if ( !mtlLayer ) { return surface->getConfigurationResult(); } + if ( !surface->wasConfigurationSuccessful() ) { return surface->getConfigurationResult(); } #define ADD_VK_PRESENT_MODE(VK_PM) \ do { \ @@ -1504,9 +1499,7 @@ uint32_t* pRectCount, VkRect2D* pRects) { - // The layer underlying the surface view must be a CAMetalLayer. - CAMetalLayer* mtlLayer = surface->getCAMetalLayer(); - if ( !mtlLayer ) { return surface->getConfigurationResult(); } + if ( !surface->wasConfigurationSuccessful() ) { return surface->getConfigurationResult(); } if ( !pRects ) { *pRectCount = 1; @@ -1518,7 +1511,7 @@ *pRectCount = 1; pRects[0].offset = { 0, 0 }; - pRects[0].extent = mvkGetNaturalExtent(mtlLayer); + pRects[0].extent = surface->getNaturalExtent(); return VK_SUCCESS; } @@ -3666,14 +3659,14 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope MTLTimestamp cpuStamp, gpuStamp; uint64_t cpuStart, cpuEnd; - cpuStart = mvkGetAbsoluteTime(); + cpuStart = mvkGetContinuousNanoseconds(); [getMTLDevice() sampleTimestamps: &cpuStamp gpuTimestamp: &gpuStamp]; // Sample again to calculate the maximum deviation. Note that the // -[MTLDevice sampleTimestamps:gpuTimestamp:] method guarantees that CPU // timestamps are in nanoseconds. We don't want to call the method again, // because that could result in an expensive syscall to query the GPU time- // stamp. - cpuEnd = mvkGetAbsoluteTime(); + cpuEnd = mvkGetContinuousNanoseconds(); for (uint32_t tsIdx = 0; tsIdx < timestampCount; ++tsIdx) { switch (pTimestampInfos[tsIdx].timeDomain) { case VK_TIME_DOMAIN_DEVICE_EXT: diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index 900b10ffa..058876d6e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -378,14 +378,8 @@ class MVKSwapchainImage : public MVKImage { public: - /** Binds this resource to the specified offset within the specified memory allocation. */ VkResult bindDeviceMemory(MVKDeviceMemory* mvkMem, VkDeviceSize memOffset, uint8_t planeIndex) override; -#pragma mark Metal - - /** Returns the Metal texture used by the CAMetalDrawable underlying this image. */ - id getMTLTexture(uint8_t planeIndex) override; - #pragma mark Construction @@ -399,7 +393,6 @@ class MVKSwapchainImage : public MVKImage { protected: friend class MVKPeerSwapchainImage; - virtual id getCAMetalDrawable() = 0; void detachSwapchain(); std::mutex _detachmentLock; @@ -445,6 +438,8 @@ class MVKPresentableSwapchainImage : public MVKSwapchainImage { #pragma mark Metal + id getMTLTexture(uint8_t planeIndex) override; + /** Presents the contained drawable to the OS. */ VkResult presentCAMetalDrawable(id mtlCmdBuff, MVKImagePresentInfo presentInfo); @@ -468,16 +463,16 @@ class MVKPresentableSwapchainImage : public MVKSwapchainImage { protected: friend MVKSwapchain; - id getCAMetalDrawable() override; + id getCAMetalDrawable(); void addPresentedHandler(id mtlDrawable, MVKImagePresentInfo presentInfo, MVKSwapchainSignaler signaler); void releaseMetalDrawable(); MVKSwapchainImageAvailability getAvailability(); - void makeAvailable(const MVKSwapchainSignaler& signaler); void makeAvailable(); VkResult acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence); MVKSwapchainSignaler getPresentationSignaler(); id _mtlDrawable = nil; + id _mtlTextureHeadless = nil; MVKSwapchainImageAvailability _availability; MVKSmallVector _availabilitySignalers; MVKSwapchainSignaler _preSignaler = {}; @@ -494,7 +489,8 @@ class MVKPeerSwapchainImage : public MVKSwapchainImage { public: - /** Binds this resource according to the specified bind information. */ + id getMTLTexture(uint8_t planeIndex) override; + VkResult bindDeviceMemory2(const VkBindImageMemoryInfo* pBindInfo) override; @@ -504,10 +500,6 @@ class MVKPeerSwapchainImage : public MVKSwapchainImage { const VkImageCreateInfo* pCreateInfo, MVKSwapchain* swapchain, uint32_t swapchainIndex); - -protected: - id getCAMetalDrawable() override; - }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index 323918f20..1c132a4d5 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -25,8 +25,10 @@ #include "MVKFoundation.h" #include "MVKOSExtensions.h" #include "MVKCodec.h" + #import "MTLTextureDescriptor+MoltenVK.h" #import "MTLSamplerDescriptor+MoltenVK.h" +#import "CAMetalLayer+MoltenVK.h" using namespace std; using namespace SPIRV_CROSS_NAMESPACE; @@ -1169,12 +1171,6 @@ } -#pragma mark Metal - -// Overridden to always retrieve the MTLTexture directly from the CAMetalDrawable. -id MVKSwapchainImage::getMTLTexture(uint8_t planeIndex) { return [getCAMetalDrawable() texture]; } - - #pragma mark Construction MVKSwapchainImage::MVKSwapchainImage(MVKDevice* device, @@ -1212,39 +1208,33 @@ return _availability; } -// If present, signal the semaphore for the first waiter for the given image. -static void signalPresentationSemaphore(const MVKSwapchainSignaler& signaler, id mtlCmdBuff) { - if (signaler.semaphore) { signaler.semaphore->encodeDeferredSignal(mtlCmdBuff, signaler.semaphoreSignalToken); } +// Tell the semaphore and fence that they are being tracked for future signaling. +static void track(const MVKSwapchainSignaler& signaler) { + if (signaler.semaphore) { signaler.semaphore->retain(); } + if (signaler.fence) { signaler.fence->retain(); } } -// Signal either or both of the semaphore and fence in the specified tracker pair. -static void signal(const MVKSwapchainSignaler& signaler, id mtlCmdBuff) { - if (signaler.semaphore) { signaler.semaphore->encodeDeferredSignal(mtlCmdBuff, signaler.semaphoreSignalToken); } - if (signaler.fence) { signaler.fence->signal(); } +static void signal(MVKSemaphore* semaphore, uint64_t semaphoreSignalToken, id mtlCmdBuff) { + if (semaphore) { semaphore->encodeDeferredSignal(mtlCmdBuff, semaphoreSignalToken); } } -// Tell the semaphore and fence that they are being tracked for future signaling. -static void markAsTracked(const MVKSwapchainSignaler& signaler) { - if (signaler.semaphore) { signaler.semaphore->retain(); } - if (signaler.fence) { signaler.fence->retain(); } +static void signal(MVKFence* fence) { + if (fence) { fence->signal(); } } -// Tell the semaphore and fence that they are no longer being tracked for future signaling. -static void unmarkAsTracked(const MVKSwapchainSignaler& signaler) { +// Signal the semaphore and fence and tell them that they are no longer being tracked for future signaling. +static void signalAndUntrack(const MVKSwapchainSignaler& signaler) { + signal(signaler.semaphore, signaler.semaphoreSignalToken, nil); if (signaler.semaphore) { signaler.semaphore->release(); } - if (signaler.fence) { signaler.fence->release(); } -} -static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { - signal(signaler, nil); - unmarkAsTracked(signaler); + signal(signaler.fence); + if (signaler.fence) { signaler.fence->release(); } } VkResult MVKPresentableSwapchainImage::acquireAndSignalWhenAvailable(MVKSemaphore* semaphore, MVKFence* fence) { // Now that this image is being acquired, release the existing drawable and its texture. // This is not done earlier so the texture is retained for any post-processing such as screen captures, etc. - // This may trigger a delayed presentation callback, which uses the _availabilityLock, also used below. releaseMetalDrawable(); lock_guard lock(_availabilityLock); @@ -1267,7 +1257,8 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { mtlCmdBuff = _device->getAnyQueue()->getMTLCommandBuffer(kMVKCommandUseAcquireNextImage); if ( !mtlCmdBuff ) { setConfigurationResult(VK_ERROR_OUT_OF_POOL_MEMORY); } } - signal(signaler, mtlCmdBuff); + signal(signaler.semaphore, signaler.semaphoreSignalToken, mtlCmdBuff); + signal(signaler.fence); [mtlCmdBuff commit]; } @@ -1275,7 +1266,7 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { } else { _availabilitySignalers.push_back(signaler); } - markAsTracked(signaler); + track(signaler); return getConfigurationResult(); } @@ -1284,6 +1275,9 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { // Attempt several times to retrieve a good drawable, and set an error to trigger the // swapchain to be re-established if one cannot be retrieved. id MVKPresentableSwapchainImage::getCAMetalDrawable() { + + if (_mtlTextureHeadless) { return nil; } // If headless, there is no drawable. + if ( !_mtlDrawable ) { @autoreleasepool { bool hasInvalidFormat = false; @@ -1305,6 +1299,11 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { return _mtlDrawable; } +// If not headless, retrieve the MTLTexture directly from the CAMetalDrawable. +id MVKPresentableSwapchainImage::getMTLTexture(uint8_t planeIndex) { + return _mtlTextureHeadless ? _mtlTextureHeadless : getCAMetalDrawable().texture; +} + // Present the drawable and make myself available only once the command buffer has completed. // Pass MVKImagePresentInfo by value because it may not exist when the callback runs. VkResult MVKPresentableSwapchainImage::presentCAMetalDrawable(id mtlCmdBuff, @@ -1343,15 +1342,13 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { auto* fence = presentInfo.fence; if (fence) { fence->retain(); } [mtlCmdBuff addCompletedHandler: ^(id mcb) { - if (fence) { - fence->signal(); - fence->release(); - } + signal(fence); + if (fence) { fence->release(); } [mtlDrwbl release]; release(); }]; - signalPresentationSemaphore(signaler, mtlCmdBuff); + signal(signaler.semaphore, signaler.semaphoreSignalToken, mtlCmdBuff); return getConfigurationResult(); } @@ -1408,6 +1405,13 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { void MVKPresentableSwapchainImage::endPresentation(const MVKImagePresentInfo& presentInfo, const MVKSwapchainSignaler& signaler, uint64_t actualPresentTime) { + + // If the presentation time is not available, use the current nanosecond runtime clock, + // which should be reasonably accurate (sub-ms) to the presentation time. The presentation + // time will not be available if the presentation did not actually happen, such as when + // running headless, or on a test harness that is not attached to the windowing system. + if (actualPresentTime == 0) { actualPresentTime = mvkGetRuntimeNanoseconds(); } + { // Scope to avoid deadlock if release() is run within detachment lock // If I have become detached from the swapchain, it means the swapchain, and possibly the // VkDevice, have been destroyed by the time of this callback, so do not reference them. @@ -1415,7 +1419,11 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { if (_device) { _device->addPerformanceInterval(_device->_performanceStatistics.queue.presentSwapchains, _presentationStartTime); } if (_swapchain) { _swapchain->endPresentation(presentInfo, actualPresentTime); } } - makeAvailable(signaler); + + // Makes an image available for acquisition by the app. + // If any semaphores are waiting to be signaled when this image becomes available, the + // earliest semaphore is signaled, and this image remains unavailable for other uses. + signalAndUntrack(signaler); release(); } @@ -1425,15 +1433,6 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { _mtlDrawable = nil; } -// Makes an image available for acquisition by the app. -// If any semaphores are waiting to be signaled when this image becomes available, the -// earliest semaphore is signaled, and this image remains unavailable for other uses. -void MVKPresentableSwapchainImage::makeAvailable(const MVKSwapchainSignaler& signaler) { - lock_guard lock(_availabilityLock); - - signalAndUnmarkAsTracked(signaler); -} - // Signal, untrack, and release any signalers that are tracking. // Release the drawable before the lock, as it may trigger completion callback. void MVKPresentableSwapchainImage::makeAvailable() { @@ -1441,9 +1440,9 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { lock_guard lock(_availabilityLock); if ( !_availability.isAvailable ) { - signalAndUnmarkAsTracked(_preSignaler); + signalAndUntrack(_preSignaler); for (auto& sig : _availabilitySignalers) { - signalAndUnmarkAsTracked(sig); + signalAndUntrack(sig); } _availabilitySignalers.clear(); _availability.isAvailable = true; @@ -1460,11 +1459,26 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { _availability.acquisitionID = _swapchain->getNextAcquisitionID(); _availability.isAvailable = true; + + if (swapchain->isHeadless()) { + @autoreleasepool { + MTLTextureDescriptor* mtlTexDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: getMTLPixelFormat() + width: pCreateInfo->extent.width + height: pCreateInfo->extent.height + mipmapped: NO]; + mtlTexDesc.usageMVK = MTLTextureUsageRenderTarget; + mtlTexDesc.storageModeMVK = MTLStorageModePrivate; + + _mtlTextureHeadless = [[getMTLDevice() newTextureWithDescriptor: mtlTexDesc] retain]; // retained + } + } } void MVKPresentableSwapchainImage::destroy() { releaseMetalDrawable(); + [_mtlTextureHeadless release]; + _mtlTextureHeadless = nil; MVKSwapchainImage::destroy(); } @@ -1498,8 +1512,8 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { #pragma mark Metal -id MVKPeerSwapchainImage::getCAMetalDrawable() { - return ((MVKSwapchainImage*)_swapchain->getPresentableImage(_swapchainIndex))->getCAMetalDrawable(); +id MVKPeerSwapchainImage::getMTLTexture(uint8_t planeIndex) { + return ((MVKSwapchainImage*)_swapchain->getPresentableImage(_swapchainIndex))->getMTLTexture(planeIndex); } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h index f6ca8e783..6a2fa92f6 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h @@ -117,6 +117,9 @@ class MVKInstance : public MVKDispatchableVulkanAPIObject { MVKSurface* createSurface(const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator); + MVKSurface* createSurface(const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator); + MVKSurface* createSurface(const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 543a1fe76..de9ad021a 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -102,6 +102,11 @@ return new MVKSurface(this, pCreateInfo, pAllocator); } +MVKSurface* MVKInstance::createSurface(const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator) { + return new MVKSurface(this, pCreateInfo, pAllocator); +} + MVKSurface* MVKInstance::createSurface(const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator) { return new MVKSurface(this, pCreateInfo, pAllocator); @@ -426,6 +431,8 @@ ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfacePresentModesKHR, KHR_SURFACE); ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceCapabilities2KHR, KHR_GET_SURFACE_CAPABILITIES_2); ADD_INST_EXT_ENTRY_POINT(vkGetPhysicalDeviceSurfaceFormats2KHR, KHR_GET_SURFACE_CAPABILITIES_2); + ADD_INST_EXT_ENTRY_POINT(vkCreateHeadlessSurfaceEXT, EXT_HEADLESS_SURFACE); + ADD_INST_EXT_ENTRY_POINT(vkCreateMetalSurfaceEXT, EXT_METAL_SURFACE); ADD_INST_EXT_ENTRY_POINT(vkCreateDebugReportCallbackEXT, EXT_DEBUG_REPORT); ADD_INST_EXT_ENTRY_POINT(vkDestroyDebugReportCallbackEXT, EXT_DEBUG_REPORT); ADD_INST_EXT_ENTRY_POINT(vkDebugReportMessageEXT, EXT_DEBUG_REPORT); @@ -441,7 +448,6 @@ ADD_INST_EXT_ENTRY_POINT(vkCreateDebugUtilsMessengerEXT, EXT_DEBUG_UTILS); ADD_INST_EXT_ENTRY_POINT(vkDestroyDebugUtilsMessengerEXT, EXT_DEBUG_UTILS); ADD_INST_EXT_ENTRY_POINT(vkSubmitDebugUtilsMessageEXT, EXT_DEBUG_UTILS); - ADD_INST_EXT_ENTRY_POINT(vkCreateMetalSurfaceEXT, EXT_METAL_SURFACE); #ifdef VK_USE_PLATFORM_IOS_MVK ADD_INST_EXT_ENTRY_POINT(vkCreateIOSSurfaceMVK, MVK_IOS_SURFACE); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h index 479965b48..5d23225b3 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h @@ -20,7 +20,7 @@ #include "MVKBaseObject.h" #include "MVKOSExtensions.h" -#include "mvk_datatypes.h" +#include "mvk_datatypes.hpp" #include #include diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h b/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h index 5746bfbf9..453eac661 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSurface.h @@ -24,16 +24,6 @@ #import #import -#ifdef VK_USE_PLATFORM_IOS_MVK -# define PLATFORM_VIEW_CLASS UIView -# import -#endif - -#ifdef VK_USE_PLATFORM_MACOS_MVK -# define PLATFORM_VIEW_CLASS NSView -# import -#endif - class MVKInstance; class MVKSwapchain; @@ -59,6 +49,14 @@ class MVKSurface : public MVKVulkanAPIObject { /** Returns the CAMetalLayer underlying this surface. */ CAMetalLayer* getCAMetalLayer(); + /** Returns the extent of this surface. */ + VkExtent2D getExtent(); + + /** Returns the extent for which the underlying CAMetalLayer will not need to be scaled when composited. */ + VkExtent2D getNaturalExtent(); + + /** Returns whether this surface is headless. */ + bool isHeadless() { return !_mtlCAMetalLayer && wasConfigurationSuccessful(); } #pragma mark Construction @@ -66,6 +64,10 @@ class MVKSurface : public MVKVulkanAPIObject { const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator); + MVKSurface(MVKInstance* mvkInstance, + const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator); + MVKSurface(MVKInstance* mvkInstance, const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator); @@ -76,7 +78,8 @@ class MVKSurface : public MVKVulkanAPIObject { friend class MVKSwapchain; void propagateDebugName() override {} - void initLayer(CAMetalLayer* mtlLayer, const char* vkFuncName); + void setActiveSwapchain(MVKSwapchain* swapchain); + void initLayer(CAMetalLayer* mtlLayer, const char* vkFuncName, bool isHeadless); void releaseLayer(); std::mutex _layerLock; @@ -84,5 +87,6 @@ class MVKSurface : public MVKVulkanAPIObject { CAMetalLayer* _mtlCAMetalLayer = nil; MVKBlockObserver* _layerObserver = nil; MVKSwapchain* _activeSwapchain = nullptr; + VkExtent2D _headlessExtent = {0xFFFFFFFF, 0xFFFFFFFF}; }; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSurface.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSurface.mm index 3899ab69f..048557185 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSurface.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSurface.mm @@ -17,11 +17,26 @@ */ #include "MVKSurface.h" +#include "MVKSwapchain.h" #include "MVKInstance.h" #include "MVKFoundation.h" #include "MVKOSExtensions.h" +#include "mvk_datatypes.hpp" + +#import "CAMetalLayer+MoltenVK.h" #import "MVKBlockObserver.h" +#ifdef VK_USE_PLATFORM_IOS_MVK +# define PLATFORM_VIEW_CLASS UIView +# import +#endif + +#ifdef VK_USE_PLATFORM_MACOS_MVK +# define PLATFORM_VIEW_CLASS NSView +# import +#endif + + // We need to double-dereference the name to first convert to the platform symbol, then to a string. #define STR_PLATFORM(NAME) #NAME #define STR(NAME) STR_PLATFORM(NAME) @@ -34,38 +49,55 @@ return _mtlCAMetalLayer; } +VkExtent2D MVKSurface::getExtent() { + return _mtlCAMetalLayer ? mvkVkExtent2DFromCGSize(_mtlCAMetalLayer.drawableSize) : _headlessExtent; +} + +VkExtent2D MVKSurface::getNaturalExtent() { + return _mtlCAMetalLayer ? mvkVkExtent2DFromCGSize(_mtlCAMetalLayer.naturalDrawableSizeMVK) : _headlessExtent; +} + +// Per spec, headless surface extent is set from the swapchain. +void MVKSurface::setActiveSwapchain(MVKSwapchain* swapchain) { + _activeSwapchain = swapchain; + _headlessExtent = swapchain->getImageExtent(); +} + MVKSurface::MVKSurface(MVKInstance* mvkInstance, const VkMetalSurfaceCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator) : _mvkInstance(mvkInstance) { - initLayer((CAMetalLayer*)pCreateInfo->pLayer, "vkCreateMetalSurfaceEXT"); + initLayer((CAMetalLayer*)pCreateInfo->pLayer, "vkCreateMetalSurfaceEXT", false); +} + +MVKSurface::MVKSurface(MVKInstance* mvkInstance, + const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator) : _mvkInstance(mvkInstance) { + initLayer(nil, "vkCreateHeadlessSurfaceEXT", true); } // pCreateInfo->pView can be either a CAMetalLayer or a view (NSView/UIView). MVKSurface::MVKSurface(MVKInstance* mvkInstance, const Vk_PLATFORM_SurfaceCreateInfoMVK* pCreateInfo, const VkAllocationCallbacks* pAllocator) : _mvkInstance(mvkInstance) { + MVKLogWarn("%s() is deprecated. Use vkCreateMetalSurfaceEXT() from the VK_EXT_metal_surface extension.", STR(vkCreate_PLATFORM_SurfaceMVK)); // Get the platform object contained in pView - id obj = (id)pCreateInfo->pView; - // If it's a view (NSView/UIView), extract the layer, otherwise assume it's already a CAMetalLayer. + id obj = (id)pCreateInfo->pView; if ([obj isKindOfClass: [PLATFORM_VIEW_CLASS class]]) { - obj = ((PLATFORM_VIEW_CLASS*)obj).layer; - if ( !NSThread.isMainThread ) { - MVKLogWarn("%s(): You are not calling this function from the main thread. %s should only be accessed from the main thread. When using this function outside the main thread, consider passing the CAMetalLayer itself in %s::pView, instead of the %s.", - STR(vkCreate_PLATFORM_SurfaceMVK), STR(PLATFORM_VIEW_CLASS), STR(Vk_PLATFORM_SurfaceCreateInfoMVK), STR(PLATFORM_VIEW_CLASS)); - } + __block id layer; + mvkDispatchToMainAndWait(^{ layer = ((PLATFORM_VIEW_CLASS*)obj).layer; }); + obj = layer; } // Confirm that we were provided with a CAMetalLayer - initLayer([obj isKindOfClass: CAMetalLayer.class] ? (CAMetalLayer*)obj : nil, - STR(vkCreate_PLATFORM_SurfaceMVK)); + initLayer([obj isKindOfClass: CAMetalLayer.class] ? (CAMetalLayer*)obj : nil, STR(vkCreate_PLATFORM_SurfaceMVK), false); } -void MVKSurface::initLayer(CAMetalLayer* mtlLayer, const char* vkFuncName) { +void MVKSurface::initLayer(CAMetalLayer* mtlLayer, const char* vkFuncName, bool isHeadless) { _mtlCAMetalLayer = [mtlLayer retain]; // retained - if ( !_mtlCAMetalLayer ) { setConfigurationResult(reportError(VK_ERROR_SURFACE_LOST_KHR, "%s(): On-screen rendering requires a layer of type CAMetalLayer.", vkFuncName)); } + if ( !_mtlCAMetalLayer && !isHeadless ) { setConfigurationResult(reportError(VK_ERROR_SURFACE_LOST_KHR, "%s(): On-screen rendering requires a layer of type CAMetalLayer.", vkFuncName)); } // Sometimes, the owning view can replace its CAMetalLayer. // When that happens, the app needs to recreate the surface. diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h index cd418bd1a..d8eb535f8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.h @@ -23,7 +23,6 @@ #include "MVKSmallVector.h" #include -#import "CAMetalLayer+MoltenVK.h" #import class MVKWatermark; @@ -46,9 +45,15 @@ class MVKSwapchain : public MVKVulkanAPIDeviceObject { /** Returns the CAMetalLayer underlying the surface used by this swapchain. */ CAMetalLayer* getCAMetalLayer(); + /** Returns whether the surface is headless. */ + bool isHeadless(); + /** Returns the number of images in this swapchain. */ uint32_t getImageCount() { return (uint32_t)_presentableImages.size(); } + /** Returns the size of the images in this swapchain. */ + VkExtent2D getImageExtent() { return _imageExtent; } + /** Returns the image at the specified index. */ MVKPresentableSwapchainImage* getPresentableImage(uint32_t index) { return _presentableImages[index]; } @@ -126,7 +131,7 @@ class MVKSwapchain : public MVKVulkanAPIDeviceObject { std::atomic _currentAcquisitionID = 0; std::mutex _presentHistoryLock; uint64_t _lastFrameTime = 0; - VkExtent2D _mtlLayerDrawableExtent = {0, 0}; + VkExtent2D _imageExtent = {0, 0}; std::atomic _unpresentedImageCount = 0; uint32_t _currentPerfLogFrameCount = 0; uint32_t _presentHistoryCount = 0; @@ -134,18 +139,3 @@ class MVKSwapchain : public MVKVulkanAPIDeviceObject { uint32_t _presentHistoryHeadIndex = 0; bool _isDeliberatelyScaled = false; }; - - -#pragma mark - -#pragma mark Support functions - -/** - * Returns the natural extent of the CAMetalLayer. - * - * The natural extent is the size of the bounds property of the layer, - * multiplied by the contentsScale property of the layer, rounded - * to nearest integer using half-to-even rounding. - */ -static inline VkExtent2D mvkGetNaturalExtent(CAMetalLayer* mtlLayer) { - return mvkVkExtent2DFromCGSize(mtlLayer.naturalDrawableSizeMVK); -} diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm index 63c3ac783..5beeee047 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSwapchain.mm @@ -26,9 +26,11 @@ #include "MVKWatermarkTextureContent.h" #include "MVKWatermarkShaderSource.h" #include "mvk_datatypes.hpp" +#include + +#import "CAMetalLayer+MoltenVK.h" #import "MVKBlockObserver.h" -#include using namespace std; @@ -49,6 +51,8 @@ CAMetalLayer* MVKSwapchain::getCAMetalLayer() { return _surface->getCAMetalLayer(); } +bool MVKSwapchain::isHeadless() { return _surface->isHeadless(); } + VkResult MVKSwapchain::getImages(uint32_t* pCount, VkImage* pSwapchainImages) { // Get the number of surface images @@ -124,16 +128,15 @@ return VK_SUCCESS; } -// This swapchain is optimally sized for the surface if the app has specified deliberate -// swapchain scaling, or the CAMetalLayer drawableSize has not changed since the swapchain -// was created, and the CAMetalLayer will not need to be scaled when composited. +// This swapchain is optimally sized for the surface if the app has specified +// deliberate swapchain scaling, or the surface extent has not changed since the +// swapchain was created, and the surface will not need to be scaled when composited. bool MVKSwapchain::hasOptimalSurface() { if (_isDeliberatelyScaled) { return true; } - auto* mtlLayer = getCAMetalLayer(); - VkExtent2D drawExtent = mvkVkExtent2DFromCGSize(mtlLayer.drawableSize); - return (mvkVkExtent2DsAreEqual(drawExtent, _mtlLayerDrawableExtent) && - mvkVkExtent2DsAreEqual(drawExtent, mvkGetNaturalExtent(mtlLayer))); + VkExtent2D surfExtent = _surface->getExtent(); + return (mvkVkExtent2DsAreEqual(surfExtent, _imageExtent) && + mvkVkExtent2DsAreEqual(surfExtent, _surface->getNaturalExtent())); } @@ -187,30 +190,29 @@ VkResult MVKSwapchain::getRefreshCycleDuration(VkRefreshCycleDurationGOOGLE *pRefreshCycleDuration) { if (_device->getConfigurationResult() != VK_SUCCESS) { return _device->getConfigurationResult(); } - auto* mtlLayer = getCAMetalLayer(); -#if MVK_VISIONOS - // TODO: See if this can be obtained from OS instead - NSInteger framesPerSecond = 90; + auto* screen = getCAMetalLayer().screenMVK; // Will be nil if headless +#if MVK_MACOS && !MVK_MACCAT + double framesPerSecond = 60; + if (screen) { + CGDirectDisplayID displayId = [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; + CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); + framesPerSecond = CGDisplayModeGetRefreshRate(mode); + CGDisplayModeRelease(mode); +#if MVK_XCODE_13 + if (framesPerSecond == 0 && [screen respondsToSelector: @selector(maximumFramesPerSecond)]) + framesPerSecond = [screen maximumFramesPerSecond]; +#endif + // Builtin panels, e.g., on MacBook, report a zero refresh rate. + if (framesPerSecond == 0) + framesPerSecond = 60.0; + } #elif MVK_IOS_OR_TVOS || MVK_MACCAT NSInteger framesPerSecond = 60; - UIScreen* screen = mtlLayer.screenMVK; if ([screen respondsToSelector: @selector(maximumFramesPerSecond)]) { framesPerSecond = screen.maximumFramesPerSecond; } -#elif MVK_MACOS && !MVK_MACCAT - NSScreen* screen = mtlLayer.screenMVK; - CGDirectDisplayID displayId = [[[screen deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]; - CGDisplayModeRef mode = CGDisplayCopyDisplayMode(displayId); - double framesPerSecond = CGDisplayModeGetRefreshRate(mode); - CGDisplayModeRelease(mode); -#if MVK_XCODE_13 - if (framesPerSecond == 0 && [screen respondsToSelector: @selector(maximumFramesPerSecond)]) - framesPerSecond = [screen maximumFramesPerSecond]; -#endif - - // Builtin panels, e.g., on MacBook, report a zero refresh rate. - if (framesPerSecond == 0) - framesPerSecond = 60.0; +#elif MVK_VISIONOS + NSInteger framesPerSecond = 90; // TODO: See if this can be obtained from OS instead #endif pRefreshCycleDuration->refreshDuration = (uint64_t)1e9 / framesPerSecond; @@ -260,12 +262,6 @@ _presentHistoryHeadIndex = (_presentHistoryHeadIndex + 1) % kMaxPresentationHistory; } - // If actual present time is not available, use desired time instead, and if that - // hasn't been set, use the current time, which should be reasonably accurate (sub-ms), - // since we are here as part of the addPresentedHandler: callback. - if (actualPresentTime == 0) { actualPresentTime = presentInfo.desiredPresentTime; } - if (actualPresentTime == 0) { actualPresentTime = CACurrentMediaTime() * 1.0e9; } - _presentTimingHistory[_presentHistoryIndex].presentID = presentInfo.presentID; _presentTimingHistory[_presentHistoryIndex].desiredPresentTime = presentInfo.desiredPresentTime; _presentTimingHistory[_presentHistoryIndex].actualPresentTime = actualPresentTime; @@ -380,12 +376,13 @@ static inline CIE1931XY VkXYColorEXTToCIE1931XY(VkXYColorEXT xy) { MVKSwapchain::MVKSwapchain(MVKDevice* device, const VkSwapchainCreateInfoKHR* pCreateInfo) : MVKVulkanAPIDeviceObject(device), - _surface((MVKSurface*)pCreateInfo->surface) { + _surface((MVKSurface*)pCreateInfo->surface), + _imageExtent(pCreateInfo->imageExtent) { // Check if oldSwapchain is properly set auto* oldSwapchain = (MVKSwapchain*)pCreateInfo->oldSwapchain; if (oldSwapchain == _surface->_activeSwapchain) { - _surface->_activeSwapchain = this; + _surface->setActiveSwapchain(this); } else { setConfigurationResult(reportError(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR, "vkCreateSwapchainKHR(): pCreateInfo->oldSwapchain does not match the VkSwapchain that is in use by the surface")); return; @@ -470,10 +467,11 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin VkSwapchainPresentScalingCreateInfoEXT* pScalingInfo, uint32_t imgCnt) { - if ( getIsSurfaceLost() ) { return; } - auto* mtlLayer = getCAMetalLayer(); + if ( !mtlLayer || getIsSurfaceLost() ) { return; } + auto minMagFilter = mvkConfig().swapchainMinMagFilterUseNearest ? kCAFilterNearest : kCAFilterLinear; + mtlLayer.drawableSize = mvkCGSizeFromVkExtent2D(_imageExtent); mtlLayer.device = getMTLDevice(); mtlLayer.pixelFormat = getPixelFormats()->getMTLPixelFormat(pCreateInfo->imageFormat); mtlLayer.maximumDrawableCountMVK = imgCnt; @@ -491,15 +489,10 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin // presentations on the oldSwapchain to complete and call back, but if the drawableSize // is not changing from the previous, we force those completions first. auto* oldSwapchain = (MVKSwapchain*)pCreateInfo->oldSwapchain; - if (oldSwapchain && mvkVkExtent2DsAreEqual(pCreateInfo->imageExtent, mvkVkExtent2DFromCGSize(mtlLayer.drawableSize))) { + if (oldSwapchain && mvkVkExtent2DsAreEqual(pCreateInfo->imageExtent, _surface->getExtent())) { oldSwapchain->forceUnpresentedImageCompletion(); } - // Remember the extent to later detect if it has changed under the covers, - // and set the drawable size of the CAMetalLayer from the extent. - _mtlLayerDrawableExtent = pCreateInfo->imageExtent; - mtlLayer.drawableSize = mvkCGSizeFromVkExtent2D(_mtlLayerDrawableExtent); - if (pCreateInfo->compositeAlpha != VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { mtlLayer.opaque = pCreateInfo->compositeAlpha == VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; } @@ -585,14 +578,13 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin } } - auto* mtlLayer = getCAMetalLayer(); VkExtent2D imgExtent = pCreateInfo->imageExtent; VkImageCreateInfo imgInfo = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = VK_NULL_HANDLE, .imageType = VK_IMAGE_TYPE_2D, - .format = getPixelFormats()->getVkFormat(mtlLayer.pixelFormat), - .extent = { imgExtent.width, imgExtent.height, 1 }, + .format = pCreateInfo->imageFormat, + .extent = mvkVkExtent3DFromVkExtent2D(imgExtent), .mipLevels = 1, .arrayLayers = 1, .samples = VK_SAMPLE_COUNT_1_BIT, @@ -618,14 +610,20 @@ static CALayerContentsGravity getCALayerContentsGravity(VkSwapchainPresentScalin _presentableImages.push_back(_device->createPresentableSwapchainImage(&imgInfo, this, imgIdx, nullptr)); } - NSString* screenName = @"Main Screen"; + auto* mtlLayer = getCAMetalLayer(); + if (mtlLayer) { + NSString* screenName = @"Main Screen"; #if MVK_MACOS && !MVK_MACCAT - if ([mtlLayer.screenMVK respondsToSelector:@selector(localizedName)]) { - screenName = mtlLayer.screenMVK.localizedName; - } + auto* screen = mtlLayer.screenMVK; + if ([screen respondsToSelector:@selector(localizedName)]) { + screenName = screen.localizedName; + } #endif - MVKLogInfo("Created %d swapchain images with size (%d, %d) and contents scale %.1f in layer %s (%p) on screen %s.", - imgCnt, imgExtent.width, imgExtent.height, mtlLayer.contentsScale, mtlLayer.name.UTF8String, mtlLayer, screenName.UTF8String); + MVKLogInfo("Created %d swapchain images with size (%d, %d) and contents scale %.1f in layer %s (%p) on screen %s.", + imgCnt, imgExtent.width, imgExtent.height, mtlLayer.contentsScale, mtlLayer.name.UTF8String, mtlLayer, screenName.UTF8String); + } else { + MVKLogInfo("Created %d swapchain images with size (%d, %d) on headless surface.", imgCnt, imgExtent.width, imgExtent.height); + } } void MVKSwapchain::destroy() { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index b7a4a64de..dfb536bb8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -128,7 +128,7 @@ } void MVKSemaphoreMTLEvent::encodeDeferredSignal(id mtlCmdBuff, uint64_t deferToken) { - if (mtlCmdBuff) { [mtlCmdBuff encodeSignalEvent: _mtlEvent value: deferToken]; } + [mtlCmdBuff encodeSignalEvent: _mtlEvent value: deferToken]; } MVKSemaphoreMTLEvent::MVKSemaphoreMTLEvent(MVKDevice* device, diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.def b/MoltenVK/MoltenVK/Layers/MVKExtensions.def index d8c222bdd..777d7252f 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.def +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.def @@ -109,6 +109,7 @@ MVK_EXTENSION(EXT_extended_dynamic_state3, EXT_EXTENDED_DYNAMIC_STATE MVK_EXTENSION(EXT_external_memory_host, EXT_EXTERNAL_MEMORY_HOST, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_fragment_shader_interlock, EXT_FRAGMENT_SHADER_INTERLOCK, DEVICE, 10.13, 11.0, 1.0) MVK_EXTENSION(EXT_hdr_metadata, EXT_HDR_METADATA, DEVICE, 10.15, MVK_NA, MVK_NA) +MVK_EXTENSION(EXT_headless_surface, EXT_HEADLESS_SURFACE, INSTANCE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_host_query_reset, EXT_HOST_QUERY_RESET, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_image_robustness, EXT_IMAGE_ROBUSTNESS, DEVICE, 10.11, 8.0, 1.0) MVK_EXTENSION(EXT_inline_uniform_block, EXT_INLINE_UNIFORM_BLOCK, DEVICE, 10.11, 8.0, 1.0) diff --git a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h index 61a5c4396..c78128bae 100644 --- a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h +++ b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.h @@ -23,12 +23,10 @@ #import #if MVK_IOS_OR_TVOS || MVK_MACCAT -# define PLATFORM_SCREEN_CLASS UIScreen # include #endif #if MVK_MACOS && !MVK_MACCAT -# define PLATFORM_SCREEN_CLASS NSScreen # include #endif @@ -76,9 +74,16 @@ */ @property(nonatomic, readwrite) CFStringRef colorspaceNameMVK; -#if !MVK_VISIONOS +#if MVK_IOS_OR_TVOS || MVK_MACCAT +/** Returns the screen on which this layer is rendering. */ +@property(nonatomic, readonly) UIScreen* screenMVK; +#endif + +#if MVK_MACOS && !MVK_MACCAT /** Returns the screen on which this layer is rendering. */ -@property(nonatomic, readonly) PLATFORM_SCREEN_CLASS* screenMVK; +@property(nonatomic, readonly) NSScreen* screenMVK; + +@property(nonatomic, readonly) NSScreen* privateScreenMVKImpl; #endif @end diff --git a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.mm similarity index 92% rename from MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m rename to MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.mm index 9a8b10d8d..380a91503 100644 --- a/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.m +++ b/MoltenVK/MoltenVK/OS/CAMetalLayer+MoltenVK.mm @@ -18,6 +18,7 @@ #include "CAMetalLayer+MoltenVK.h" +#include "MVKOSExtensions.h" #if MVK_MACOS && !MVK_MACCAT # include @@ -88,6 +89,13 @@ -(UIScreen*) screenMVK { #if MVK_MACOS && !MVK_MACCAT -(NSScreen*) screenMVK { + __block NSScreen* screen; + mvkDispatchToMainAndWait(^{ screen = self.privateScreenMVKImpl; }); + return screen; +} + +// Search for the screen currently displaying the layer, and default to the main screen if it can't be found. +-(NSScreen*) privateScreenMVKImpl { // If this layer has a delegate that is an NSView, and the view is in a window, retrieve the screen from the window. if ([self.delegate isKindOfClass: NSView.class]) { NSWindow* window = ((NSView*)self.delegate).window; diff --git a/MoltenVK/MoltenVK/Vulkan/vulkan.mm b/MoltenVK/MoltenVK/Vulkan/vulkan.mm index c08c5b3a5..293826a33 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -3869,6 +3869,26 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkSetHdrMetadataEXT( } +#pragma mark - +#pragma mark VK_EXT_headless_surface extension + +MVK_PUBLIC_VULKAN_SYMBOL VkResult vkCreateHeadlessSurfaceEXT( + VkInstance instance, + const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface) { + + MVKTraceVulkanCallStart(); + MVKInstance* mvkInst = MVKInstance::getMVKInstance(instance); + MVKSurface* mvkSrfc = mvkInst->createSurface(pCreateInfo, pAllocator); + *pSurface = (VkSurfaceKHR)mvkSrfc; + VkResult rslt = mvkSrfc->getConfigurationResult(); + if (rslt < 0) { *pSurface = VK_NULL_HANDLE; mvkInst->destroySurface(mvkSrfc, pAllocator); } + MVKTraceVulkanCallEnd(); + return rslt; +} + + #pragma mark - #pragma mark VK_EXT_host_query_reset extension diff --git a/README.md b/README.md index 5c205b08b..2fa365260 100644 --- a/README.md +++ b/README.md @@ -149,21 +149,14 @@ for which to build the external libraries. The platform choices include: --maccat --tvos --tvossim - --visionos - --visionossim - -The `visionos` and `visionossim` selections require Xcode 15+. You can specify multiple of these selections. The result is a single `XCFramework` for each external dependency library, with each `XCFramework` containing binaries for each of the requested platforms. -The `--all` selection is the same as entering all of the other platform choices, except -`--visionos` and `--visionossim`, and will result in a single `XCFramework` for each -external dependency library, with each `XCFramework` containing binaries for all supported -platforms and simulators. The `--visionos` and `--visionossim` selections must be invoked -with a separate invocation of `fetchDependencies`, because those selections require -Xcode 15+, and will cause a multi-platform build on older versions of Xcode to abort. +The `--all` selection is the same as entering all of the other platform choices, +and will result in a single `XCFramework` for each external dependency library, +with each `XCFramework` containing binaries for all supported platforms and simulators. Running `fetchDependencies` repeatedly with different platforms will accumulate targets in the `XCFramework`, if the `--keep-cache` option is used on each invocation. @@ -263,8 +256,6 @@ from the command line. The following `make` targets are provided: make maccat make tvos make tvossim - make visionos - make visionossim make all-debug make macos-debug @@ -273,15 +264,12 @@ from the command line. The following `make` targets are provided: make maccat-debug make tvos-debug make tvossim-debug - make visionos-debug - make visionossim-debug make clean make install - Running `make` repeatedly with different targets will accumulate binaries for these different targets. -- The `all` target executes all platform targets, except `visionos` and `visionossim`, as these require - Xcode 15+, and will abort a multi-platform build on older versions of Xcode. +- The `all` target executes all platform targets. - The `all` target is the default target. Running `make` with no arguments is the same as running `make all`. - The `*-debug` targets build the binaries using the **_Debug_** configuration. - The `install` target will copy the most recently built `MoltenVK.xcframework` into the From d0e00ad3be4be3c52630f9f3c013bea1679927f1 Mon Sep 17 00:00:00 2001 From: Evan Tang Date: Thu, 14 Sep 2023 11:46:07 -0500 Subject: [PATCH 03/14] Don't enable PixelFormatView just in case we need it to copy Not worth the performance hit to everything else --- MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm | 20 +++++++---- MoltenVK/MoltenVK/GPUObjects/MVKImage.h | 5 ++- MoltenVK/MoltenVK/GPUObjects/MVKImage.mm | 7 ++++ .../MoltenVK/GPUObjects/MVKPixelFormats.mm | 34 +++++++++---------- 4 files changed, 41 insertions(+), 25 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm index 52dcb78f0..06d67822e 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm @@ -133,12 +133,17 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma MTLPixelFormat srcMTLPixFmt = _srcImage->getMTLPixelFormat(srcPlaneIndex); bool isSrcCompressed = _srcImage->getIsCompressed(); + bool canReinterpretSrc = _srcImage->hasPixelFormatView(srcPlaneIndex); MTLPixelFormat dstMTLPixFmt = _dstImage->getMTLPixelFormat(dstPlaneIndex); bool isDstCompressed = _dstImage->getIsCompressed(); + bool canReinterpretDst = _dstImage->hasPixelFormatView(dstPlaneIndex); - // If source and destination have different formats and at least one is compressed, use a temporary intermediary buffer - bool useTempBuffer = (srcMTLPixFmt != dstMTLPixFmt) && (isSrcCompressed || isDstCompressed); + bool isEitherCompressed = isSrcCompressed || isDstCompressed; + bool canReinterpret = canReinterpretSrc || canReinterpretDst; + + // If source and destination can't be reinterpreted to matching formats use a temporary intermediary buffer + bool useTempBuffer = (srcMTLPixFmt != dstMTLPixFmt) && (isEitherCompressed || !canReinterpret); if (useTempBuffer) { // Add copy from source image to temp buffer. @@ -177,12 +182,13 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma size_t bytesPerRow = pixFmts->getBytesPerRow(srcMTLPixFmt, vkIC.extent.width); size_t bytesPerRegion = pixFmts->getBytesPerLayer(srcMTLPixFmt, bytesPerRow, vkIC.extent.height); - tmpBuffSize += bytesPerRegion; + tmpBuffSize += bytesPerRegion * vkIC.extent.depth; } else { - // Map the source pixel format to the dest pixel format through a texture view on the source texture. - // If the source and dest pixel formats are the same, this will simply degenerate to the source texture itself. - id srcMTLTex = _srcImage->getMTLTexture(srcPlaneIndex, _dstImage->getMTLPixelFormat(dstPlaneIndex)); - id dstMTLTex = _dstImage->getMTLTexture(dstPlaneIndex); + // Map the source pixel format to the dest pixel format through a texture view on the reinterpretable texture. + // If the source and dest pixel formats are the same, this will simply degenerate to the texture itself. + MTLPixelFormat fmt = (canReinterpretSrc ? _dstImage : _srcImage)->getMTLPixelFormat(canReinterpretSrc ? dstPlaneIndex : srcPlaneIndex); + id srcMTLTex = _srcImage->getMTLTexture(srcPlaneIndex, fmt); + id dstMTLTex = _dstImage->getMTLTexture(dstPlaneIndex, fmt); if ( !srcMTLTex || !dstMTLTex ) { return; } id mtlBlitEnc = cmdEncoder->getMTLBlitEncoder(commandUse); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h index 900b10ffa..7103bddd1 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.h @@ -310,7 +310,10 @@ class MVKImage : public MVKVulkanAPIDeviceObject { * attempting to copy a depth image with a substituted format to and from a buffer. */ inline bool hasExpectedTexelSize() { return _hasExpectedTexelSize; } - + + /** Returns whether the texture has the PixelFormatView usage flag, allowing it to be reinterpreted. */ + inline bool hasPixelFormatView(uint32_t planeIndex) { return mvkIsAnyFlagEnabled(getMTLTexture(planeIndex).usage, MTLTextureUsagePixelFormatView); } + /** Returns the Metal resource options for this image. */ MTLStorageMode getMTLStorageMode(); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm index f73c64a87..d7ff29336 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKImage.mm @@ -1763,6 +1763,13 @@ static void signalAndUnmarkAsTracked(const MVKSwapchainSignaler& signaler) { } } + if (!_imageView->_image->hasPixelFormatView(_planeIndex)) { + if (!enableSwizzling()) { + MVKAssert(0, "Image without PixelFormatView usage couldn't enable swizzling!"); + } + return VK_SUCCESS; + } + switch (_mtlPixFmt) { case MTLPixelFormatR8Unorm: if (SWIZZLE_MATCHES(ZERO, ANY, ANY, R)) { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index fa76befa7..0427e52cf 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -737,23 +737,23 @@ mvkEnableFlags(mtlUsage, samples == VK_SAMPLE_COUNT_1_BIT ? MTLTextureUsageShaderWrite : MTLTextureUsageShaderRead); } - // Create view on, but only on color formats, or combined depth-stencil formats if supported by the GPU... - if ((mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) || // May use temp view if transfer involves format change - (needsReinterpretation && - mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)))) && - isColorFormat) { - - mvkEnableFlags(mtlUsage, MTLTextureUsagePixelFormatView); - } - if (mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | // May use temp view if transfer involves format change - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) && - isCombinedDepthStencilFmt && supportsStencilViews) { - + bool pfv = false; + + // Swizzle emulation may need to reinterpret + needsReinterpretation |= !_physicalDevice->getMetalFeatures()->nativeTextureSwizzle; + + pfv |= isColorFormat && needsReinterpretation && + mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)); + pfv |= isCombinedDepthStencilFmt && supportsStencilViews && + mvkIsAnyFlagEnabled(vkImageUsageFlags, (VK_IMAGE_USAGE_TRANSFER_SRC_BIT | // May use temp view if transfer involves format change + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)); + + if (pfv) { mvkEnableFlags(mtlUsage, MTLTextureUsagePixelFormatView); } From 0fc9657bbd3923858956eae8a8d9d4e37c047b99 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Wed, 13 Dec 2023 18:26:42 -0500 Subject: [PATCH 04/14] Update documentation for the VK_EXT_layer_settings extension. - Add MoltenVK_Configuration_Parameters.md to document the MoltenVK configuration parameters. - Deprecate vkSetMoltenVKConfigurationMVK(). - Deprecate mvk_config.h and move content to mvk_private_api.h and mvk_deprecated_api.h. - Streamline lock on retrieval of MVKLayerManager singleton (unrelated). --- Docs/MoltenVK_Configuration_Parameters.md | 656 +++++++++++ Docs/MoltenVK_Runtime_UserGuide.md | 75 +- Docs/Whats_New.md | 2 + MoltenVK/MoltenVK/API/mvk_config.h | 1076 +------------------ MoltenVK/MoltenVK/API/mvk_deprecated_api.h | 18 +- MoltenVK/MoltenVK/API/mvk_private_api.h | 292 ++++- MoltenVK/MoltenVK/API/mvk_vulkan.h | 2 +- MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 29 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.h | 3 +- MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 5 +- MoltenVK/MoltenVK/Layers/MVKLayers.mm | 12 +- MoltenVK/MoltenVK/Utility/MVKBaseObject.mm | 1 - MoltenVK/MoltenVK/Utility/MVKEnvironment.h | 2 +- MoltenVK/MoltenVK/Vulkan/mvk_api.mm | 8 +- MoltenVKPackaging.xcodeproj/project.pbxproj | 25 +- README.md | 3 +- Scripts/runcts | 10 +- 17 files changed, 1066 insertions(+), 1153 deletions(-) create mode 100644 Docs/MoltenVK_Configuration_Parameters.md diff --git a/Docs/MoltenVK_Configuration_Parameters.md b/Docs/MoltenVK_Configuration_Parameters.md new file mode 100644 index 000000000..f5527d311 --- /dev/null +++ b/Docs/MoltenVK_Configuration_Parameters.md @@ -0,0 +1,656 @@ + + + + +MoltenVK Configuration Parameters +================================= + +Copyright (c) 2015-2023 [The Brenwill Workshop Ltd.](http://www.brenwill.com) + +[comment]: # "This document is written in Markdown (http://en.wikipedia.org/wiki/Markdown) format." +[comment]: # "For best results, use a Markdown reader." + + + +**MoltenVK** provides the ability to configure and optimize **MoltenVK** for your particular +application runtime requirements and development-time needs. + +At runtime, configuration can be helpful in situtations where _Metal_ behavior is different +than _Vulkan_ behavior, and the results or performance you receive can depend on how **MoltenVK** +works around those differences, which, in turn, may depend on how you are using _Vulkan_. +Different apps might benefit differently in this handling. + +Additional configuration parameters can be helpful at development time by providing you with +additional tracing, debugging, and performance measuring capabilities. + +Each configuration parameter has a *name* and *value*, and can be passed to **MoltenVK** +via any of the following mechanisms: + +- The standard _Vulkan_ `VK_EXT_layer_settings` extension. +- Application runtime environment variables. +- Build settings at **MoltenVK** build time. + +Parameter values configured by build settings at **MoltenVK** build time can be overridden +by values set by environment variables, which, in turn, can be overridden during `VkInstance` +creation via the _Vulkan_ `VK_EXT_layer_settings` extension. + + +--------------------------------------- +#### MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE + +##### Type: Enumeration +- `0`: Log repeatedly every number of frames configured by the `MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT` parameter. +- `1`: Log immediately after each performance measurement. +- `2`: Log at the end of the `VkDevice` lifetime. This is useful for one-shot apps such as testing frameworks. +- `3`: Log at the end of the `VkDevice` lifetime, but continue to accumulate across mulitiple `VkDevices` + throughout the app process. This is useful for testing frameworks that create many `VkDevices` serially. + +##### Default: `0` + +If the `MVK_CONFIG_PERFORMANCE_TRACKING` parameter is enabled, this parameter controls +when **MoltenVK** should log activity performance events. + + +--------------------------------------- +#### MVK_CONFIG_ADVERTISE_EXTENSIONS + +##### Type: UInt32 +##### Default: `1` + +Controls which extensions **MoltenVK** should advertise it supports in `vkEnumerateInstanceExtensionProperties()` +and `vkEnumerateDeviceExtensionProperties()`. This can be useful when testing **MoltenVK** against specific +limited functionality. The value of this parameter is a `Bitwise-OR` of the following values: + +- `1`: All supported extensions. +- `2`: WSI extensions supported on the platform. +- `4`: _Vulkan_ Portability Subset extensions. + + +Any prerequisite extensions are also advertised. If bit `1` is included, all supported +extensions will be advertised. A value of zero means no extensions will be advertised. + + +--------------------------------------- +#### MVK_CONFIG_API_VERSION_TO_ADVERTISE + +##### Type: UInt32 +##### Default: `4202496` + +Controls the _Vulkan_ API version that **MoltenVK** should advertise in `vkEnumerateInstanceVersion()`, +after **MoltenVK** adds the `VK_HEADER_VERSION` component. + +Set this value to one of: + +- `4202496` (decimal number for `VK_API_VERSION_1_2`) +- `4198400` (decimal number for `VK_API_VERSION_1_1`) +- `4194304` (decimal number for `VK_API_VERSION_1_0`) + + +--------------------------------------- +#### MVK_CONFIG_AUTO_GPU_CAPTURE_OUTPUT_FILE + +##### Type: String +##### Default: `""` + +_(The default value is an empty string)._ + +If `MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE` is any value other than `0`, this is the path to a +file where the automatic GPU capture will be saved. If this parameter is an empty string +(the default), automatic GPU capture will be handled by the _Xcode_ user interface. + +If this parameter is set to a valid file path, 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. This feature requires _Metal 2.2 (macOS 10.15+, iOS/tvOS 13+)_. + + +--------------------------------------- +#### MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE + +##### Type: Enumeration +- `0`: No automatic GPU capture. +- `1`: Automatically capture all GPU activity during the lifetime of a `VkDevice`. +- `2`: Automatically capture all GPU activity during the rendering and presentation of the first frame. + The queue for which the frame is captured is identifed by the values of the + `MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX` and + `MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX` configuration parameters. + +##### Default: `0` + +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. +To manually trigger a GPU capture via the _Xcode_ user interface, leave this parameter at `0`. + + +--------------------------------------- +#### MVK_CONFIG_DEBUG + +##### Type: Boolean +##### Default: `0` + +_(The default value is `1` if **MoltenVK** was built in Debug mode)._ + +If enabled, debugging capabilities will be enabled, including logging shader code during runtime shader conversion. + + +--------------------------------------- +#### MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX + +##### Type: UInt32 +##### Default: `0` + +The index of the queue family whose presentation submissions will be +used as the default GPU Capture Scope, when GPU Capture is active. + + +--------------------------------------- +#### MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX + +##### Type: UInt32 +##### Default: `0` + +The index of the queue, within the queue family identified by the +`MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX` parameter, whose presentation +submissions will be used as the default GPU Capture Scope, when GPU Capture is active. + + +--------------------------------------- +#### MVK_CONFIG_DISPLAY_WATERMARK + +##### Type: Boolean +##### Default: `0` + +If enabled, a **MoltenVK** logo watermark will be rendered on top of the scene. +This can be enabled for publicity during demos. + + +--------------------------------------- +#### MVK_CONFIG_FAST_MATH_ENABLED + +##### Type: Enumeration +- `0`: _Metal_ shaders will never be compiled with the fast math option. +- `1`: _Metal_ shaders will always be compiled with the fast math option. +- `2`: _Metal_ shaders will be compiled with the fast math option, unless the shader includes execution + capabilities, such as `SignedZeroInfNanPreserve`, that require it to be compiled without fast math. + +##### Default: `1` + +Identifies when _Metal_ shaders will be compiled with the _Metal_ fast math option enabled. + +Shaders compiled with the _Metal_ fast math option enabled perform floating point math significantly +faster, but may optimize floating point operations in ways that 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 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 `2`, so that fast math will be disabled when compiling shaders +that request specific math accuracy and precision capabilities, such as `SignedZeroInfNanPreserve`. + + +--------------------------------------- +#### MVK_CONFIG_FORCE_LOW_POWER_GPU + +##### Type: Boolean +##### Default: `0` + +Forces **MoltenVK** to only advertise the low-power GPUs, if availble on the device. + + +--------------------------------------- +#### MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE + +##### Type: Boolean +##### Default: `0` + +If _Metal_ supports native per-texture swizzling (_macOS 10.15+ with Mac 2 GPU_, _ios/tvOS 13+_), +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, `VkImageView` swizzling is automatically performed in the converted +_Metal_ shader code during all texture sampling and reading operations. This occurs regardless +of whether a swizzle is required for the `VkImageView` associated with the _Metal_ texture, +which may result in reduced performance. + +If disabled, and native _Metal_ per-texture swizzling is not available on the platform, the +following very limited set of `VkImageView` component swizzles is supported via format substitutions: + +``` +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) +``` + +If native per-texture swizzling is not available, and this feature is not enabled, +an error is logged and returned in the following situations: + +- `VkImageView` creation if that `VkImageView` requires full image view swizzling. +- A pipeline that was not compiled with full image view swizzling uses a `VkImageView` that is expecting a swizzle. +- `VkPhysicalDeviceImageFormatInfo2KHR` is passed in a call to `vkGetPhysicalDeviceImageFormatProperties2KHR()` + to query for an `VkImageView` format that will require full swizzling. + + +--------------------------------------- +#### MVK_CONFIG_LOG_LEVEL + +##### Type: Enumeration +- `0`: No logging. +- `1`: Log errors only. +- `2`: Log errors and warning messages. +- `3`: Log errors, warnings and informational messages. +- `4`: Log errors, warnings, infos and debug messages. + +##### Default: `3` + +Controls the level of logging performed by **MoltenVK**. + + +--------------------------------------- +#### MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE + +##### Type: UInt32 +##### Default: `64` + +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 `MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS` parameter. +If `MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS` is set to anything other than `0`, one _Metal_ command buffer +is required per _Vulkan_ command buffer, otherwise one _Metal_ command buffer is required per command buffer +queue submission, which will typically be significantly less than the number of _Vulkan_ command buffers. + + +--------------------------------------- +#### MVK_CONFIG_METAL_COMPILE_TIMEOUT + +##### Type: UInt64 +##### Default: `INT64_MAX` + +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 may 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. + + +--------------------------------------- +#### MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT + +##### Type: UInt32 +##### Default: `0` + +If the `MVK_CONFIG_PERFORMANCE_TRACKING` parameter is enabled, and this parameter is non-zero, +performance and frame-based statistics will be logged, on a repeating cycle, once per this many frames. +If this parameter is zero, or the `MVK_CONFIG_PERFORMANCE_TRACKING` parameter is disabled, +no frame-based performance statistics will be logged. + + +--------------------------------------- +#### MVK_CONFIG_PERFORMANCE_TRACKING + +##### Type: Boolean +##### Default: `0` + +If enabled, performance statistics, as defined by the `MVKPerformanceStatistics` structure, +are collected, and can be retrieved via the private-API `vkGetPerformanceStatisticsMVK()` function. + +You can also use the `MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE` and +`MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT` parameters to configure when to log the performance statistics collected by this parameter. + + +--------------------------------------- +#### MVK_CONFIG_PREALLOCATE_DESCRIPTORS + +##### Type: Boolean +##### Default: `1` + +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. + + +--------------------------------------- +#### MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS + +##### Type: Enumeration +- `0`: During _Vulkan_ command buffer filling, do not prefill a _Metal_ command buffer for each _Vulkan_ + command buffer. A single _Metal_ command buffer will be 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. +- `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. +- `2`: During _Vulkan_ command buffer filling, as each + command is submitted to the _Vulkan_ command buffer, immediately encode it to the _Metal_ 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. +- `3`: During _Vulkan_ command buffer filling, as each + command is submitted to the _Vulkan_ command buffer, immediately encode it to the _Metal_ 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. + +##### Default: `0` + +For any value other than `0`, be aware of the following: + +- 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 + `MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE` parameter. +- 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`). +- For primary command buffers that are intended to be reused (`VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT` + is not set), prefilling will only apply to the first submission. Later submissions of the same command buffer + will behave as if this configuration parameter is set to `0`. +- 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. +- This configuration 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 parameter will be ignored and treated as if it is `0`. + + +--------------------------------------- +#### MVK_CONFIG_RESUME_LOST_DEVICE + +##### Type: Boolean +##### Default: `0` + +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 parameter 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 parameter is disabled, **MoltenVK** will +mark the `VkDevice` as lost, and subsequent use of that `VkDevice` will be reduced or prohibited. + + +--------------------------------------- +#### MVK_CONFIG_SHADER_COMPRESSION_ALGORITHM + +##### Type: Enumeration +- `0`: No compression. +- `1`: `LZFSE`: Apple proprietary. Good balance of high performance and small compression size, particularly for larger data content. +- `2`: `ZLib`: Open cross-platform format. For smaller data content, has better performance and smaller size than `LZFSE`. +- `3`: `LZ4`: Fastest performance. Largest compression size. +- `4`: `LZMA`: Slowest performance. Smallest compression size, particular with larger content. + +##### Default: `0` + +Pipeline cache compression is available for _macOS 10.15+_, and _iOS/tvOS 13.0+_. + +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. + + +--------------------------------------- +#### MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y + +##### Type: Boolean +##### Default: `1` + +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. + + +--------------------------------------- +#### MVK_CONFIG_SHOULD_MAXIMIZE_CONCURRENT_COMPILATION + +##### Type: Boolean +##### Default: `0` + +Maximize the concurrent executing compilation tasks. + +To have effect, this parameter requires _macOS 13.3+_, and has no effect on _iOS_ or _tvOS_. + + +--------------------------------------- +#### MVK_CONFIG_SPECIALIZED_QUEUE_FAMILIES + +##### Type: Boolean +##### Default: `0` + +_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 it 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. + + +--------------------------------------- +#### MVK_CONFIG_SUPPORT_LARGE_QUERY_POOLS + +##### Type: Boolean +##### Default: `1` + +Depending on the GPU, _Metal_ allows 8,192 or 32,768 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. + + +--------------------------------------- +#### MVK_CONFIG_SWAPCHAIN_MIN_MAG_FILTER_USE_NEAREST + +##### Type: Boolean +##### Default: `1` + +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. + + +--------------------------------------- +#### MVK_CONFIG_SWITCH_SYSTEM_GPU + +##### Type: Boolean +##### Default: `1` + +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. + + +--------------------------------------- +#### MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS + +##### Type: Boolean +##### Default: `1` + +_(The default value is `0` for OS versions prior to macOS 10.14+/iOS 12+)._ + +If enabled, queue command submissions `vkQueueSubmit()` and `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()`. + + +--------------------------------------- +#### MVK_CONFIG_TEXTURE_1D_AS_2D + +##### Type: Boolean +##### Default: `1` + +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. + + +--------------------------------------- +#### MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA + +##### Type: Float32 +##### Default: `1.0` + +This parameter is ignored on Apple Silicon (Apple GPU) 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. + + +--------------------------------------- +#### MVK_CONFIG_TRACE_VULKAN_CALLS + +##### Type: Enumeration +- `0`: No _Vulkan_ call logging. +- `1`: Log the name of each _Vulkan_ call when the call is entered. +- `2`: Log the name and thread ID of each _Vulkan_ call when the call is entered. +- `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. +- `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. +- `5`: Same as `3`, plus logs the time spent inside the _Vulkan_ function. +- `6`: Same as `4`, plus logs the time spent inside the _Vulkan_ function. + +##### Default: `0` + +Controls the information **MoltenVK** logs for each _Vulkan_ call made by the application. + + +--------------------------------------- +#### MVK_CONFIG_USE_COMMAND_POOLING + +##### Type: Boolean +##### Default: `1` + +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. + + +--------------------------------------- +#### MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS + +##### Type: Enumeration +- `0`: Don't use _Metal_ Argument Buffers. +- `1`: Use _Metal_ Argument Buffers for all pipelines. +- `2`: Use _Metal_ Argument Buffers only if the `VK_EXT_descriptor_indexing` extension is enabled. + +##### Default: `0` + +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. + +_**NOTE:**_ Currently, _Metal_ argument buffer support is in beta stage, and is only supported on _macOS 11.0+_, +or on older versions of _macOS_ using an _Intel_ GPU. _Metal_ argument buffers support is not available on _iOS_ or _tvOS_. +Development to support _iOS_ and _tvOS_ and a wider combination of GPU's on older _macOS_ versions is under way. + + +--------------------------------------- +#### MVK_CONFIG_USE_MTLHEAP + +##### Type: Boolean +##### Default: `0` + +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 parameter 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. + + +--------------------------------------- +#### MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE + +##### Type: Enumeration +- `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. +- `1`: Use _Metal_ events (`MTLEvent`) when available on the platform, and where safe. This will revert to the same as `0` on some + _NVIDIA_ GPUs and _Rosetta2_, due to potential challenges with `MTLEvents` on those platforms, or in older environments where + `MTLEvents` are not supported. +- `2`: Always use _Metal_ events (`MTLEvent`) when available on the platform. This will revert to the same as `0` in older + environments where `MTLEvents` are not supported. +- `3`: Use CPU callbacks upon GPU submission completion. This is the slowest technique, but allows multiple queues, compared to `0`. + +##### Default: `1` + +Determines the style used to implement _Vulkan_ semaphore (`VkSemaphore`) functionality in _Metal_. + + +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. + diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 7f826eae7..6a00edf3d 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -483,18 +483,15 @@ can be included in your application source code as follows: where `HEADER_FILE` is one of the following: -- `mvk_vulkan.h` - This is a convenience header file that loads the `` header file - with platform settings to enable the appropriate platform-surface and portability extensions. - -- `mvk_config.h` - Contains public functions and structures to allow you to configure and - optimize **MoltenVK** for your particular application runtime requirements. For more - information, see the [Configuring MoltenVK](#moltenvk_config) section just below. - -- `mvk_private_api.h` - Contains functions and structures to allow you to query **MoltenVK** - performance activity, and Metal capabilities on the platform. _**NOTE:**_ THESE - FUNCTIONS ARE NOT SUPPORTED BY THE *Vulkan Loader and Layers*, AND CAN ONLY BE USED - WHEN **MoltenVK** IS LINKED DIRECTLY TO YOUR APPLICATION. +- `mvk_vulkan.h` - This is a convenience header file that loads the `` header file + with platform settings to enable the appropriate _Vulkan_ WSI surface and portability extensions. +- `mvk_private_api.h` - Contains private structures and functions to query **MoltenVK** about + **MoltenVK** version and configuration, runtime performance information, and available + _Metal_ capabilities. + > _**NOTE:**_ THE FUNCTIONS in `mvk_private_api.h` ARE NOT SUPPORTED BY THE _Vulkan Loader + and Layers_, AND CAN ONLY BE USED WHEN **MoltenVK** IS LINKED DIRECTLY TO YOUR APPLICATION. + - `mvk_datatypes.h` - Contains helpful functions for converting between *Vulkan* and *Metal* data types. You do not need to use this functionality to use **MoltenVK**, as **MoltenVK** converts between *Vulkan* and *Metal* datatypes automatically (using the functions declared @@ -505,30 +502,36 @@ where `HEADER_FILE` is one of the following: ### Configuring MoltenVK -The `mvk_config.h` header file provides the ability to configure and optimize **MoltenVK** -for your particular application runtime requirements. This can be helpful in situtations -where *Metal* behavior is different than *Vulkan* behavior, and the results or performance -you receive can depend on how **MoltenVK** works around those differences, which, in turn, may -depend on how you are using *Vulkan*. Different apps might benefit differently in this handling. +**MoltenVK** provides the ability to configure and optimize **MoltenVK** for your particular +application runtime requirements and development-time needs. + +At runtime, configuration can be helpful in situtations where _Metal_ behavior is different +than _Vulkan_ behavior, and the results or performance you receive can depend on how **MoltenVK** +works around those differences, which, in turn, may depend on how you are using _Vulkan_. +Different apps might benefit differently in this handling. + +Additional configuration parameters can be helpful at development time by providing you with +additional tracing, debugging, and performance measuring capabilities. -There are three mechanisms for setting the values of the **MoltenVK** configuration parameters: +Each configuration parameter has a *name* and *value*, and can be passed to **MoltenVK** +via any of the following mechanisms: -- Runtime API via the `vkGetMoltenVKConfigurationMVK()/vkSetMoltenVKConfigurationMVK()` functions. +- The standard _Vulkan_ `VK_EXT_layer_settings` extension. - Application runtime environment variables. - Build settings at **MoltenVK** build time. -To change some of the **MoltenVK** configuration settings at runtime using a programmatic API, -use the `vkGetMoltenVKConfigurationMVK()` and `vkSetMoltenVKConfigurationMVK()` functions to -retrieve, modify, and set a copy of the `MVKConfiguration` structure. +Parameter values configured by build settings at **MoltenVK** build time can be overridden +by values set by environment variables, which, in turn, can be overridden during `VkInstance` +creation via the Vulkan `VK_EXT_layer_settings` extension. -The initial value of each of the configuration settings can be established at runtime -by a corresponding environment variable, or if the environment variable is not set, -by a corresponding build setting at the time **MoltenVK** is compiled. The environment -variable and build setting for each configuration parameter share the same name. +Using the `VK_EXT_layer_settings` extension is the preferred mechanism, as it is a standard +_Vulkan_ extension, and is supported by the _Vulkan_ loader and layers. Using environment +variables can be a convinient mechanism to modify configuration parameters during runtime +debugging in the field (if the settings are *not* overridden during `VkInstance` creation +via the _Vulkan_ `VK_EXT_layer_settings` extension). -See the description of the `MVKConfiguration` structure parameters and corresponding -environment variables in the `mvk_config.h` file for more info about configuring and -optimizing **MoltenVK** at runtime or build time. +A description of each configuration parameter supported by **MoltenVK** can be found in the +[`MoltenVK_Configuration_Parameters.md`](MoltenVK_Configuration_Parameters.md) document in the `Docs` directory. @@ -552,19 +555,9 @@ you can address the issue as follows: - Errors encountered during **Runtime Shader Conversion** are logged to the console. -<<<<<<< HEAD -- 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_CONFIG_DEBUG` runtime environment variable to `1`. See the - [*MoltenVK Configuration*](#moltenvk_config) description above. -======= -- 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_CONFIG_DEBUG` - runtime environment variable to `1`. See the [*MoltenVK Configuration*](#moltenvk_config) - description above. ->>>>>>> e6a3886313a270e93a327cdb822f856fb75393b2 +- To help understand conversion issues during **Runtime Shader Conversion**, you can enable logging + the *SPIR-V* and *MSL* shader source code during shader conversion, by enabing the `MVK_CONFIG_DEBUG` + configuration parameter. See the [*MoltenVK Configuration*](#moltenvk_config) description above. Enabling debug mode in **MoltenVK** includes shader conversion logging, which causes both the incoming *SPIR-V* code and the converted *MSL* source code to be logged to the console diff --git a/Docs/Whats_New.md b/Docs/Whats_New.md index 5fd04e020..f7e9b8690 100644 --- a/Docs/Whats_New.md +++ b/Docs/Whats_New.md @@ -28,6 +28,8 @@ Released TBD - Fix rare deadlock during launch via `dlopen()`. - Fix initial value of `VkPhysicalDeviceLimits::timestampPeriod` on non-Apple Silicon GPUs. - Fix swapchain and surface bugs when windowing system is accessed from off the main thread. +- Deprecate `vkSetMoltenVKConfigurationMVK()`. +- Deprecate `mvk_config.h` and move content to `mvk_private_api.h` and `mvk_deprecated_api.h`. - Update to latest SPIRV-Cross: - MSL: Fix regression error in argument buffer runtime arrays. - MSL: Work around broken cube texture gradients on Apple Silicon. diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index b9cd2f652..b1e423fe7 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -24,1087 +24,25 @@ #ifdef __cplusplus extern "C" { #endif // __cplusplus - -#include -/** This header contains the public configuration API for MoltenVK. */ +#include /** - * 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 - * two decimal digits, in the format MjMnPt. This creates a version number that is both human - * readable and allows efficient computational comparisons to a single integer number. + * This header is obsolete and deprecated, and is provided for legacy compatibility only. * - * The following examples illustrate how the MoltenVK version number is built from its components: - * - 002000 (version 0.20.0) - * - 010000 (version 1.0.0) - * - 030104 (version 3.1.4) - * - 401215 (version 4.12.15) - */ -#define MVK_VERSION_MAJOR 1 -#define MVK_VERSION_MINOR 2 -#define MVK_VERSION_PATCH 7 - -#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 38 - -/** 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 -} 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 -} 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 -} 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 -} 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 -} 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 -} 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 -} 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 -} 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, -} 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_DEVICE_LIFETIME_ACCUMULATE = 3, /**< Log at the end of the VkDevice lifetime, but continue to accumulate across mulitiple VkDevices throughout the app process. This is useful for testing frameworks that create many VkDevices serially. */ - MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_MAX_ENUM = 0x7FFFFFFF, -} MVKConfigActivityPerformanceLoggingStyle; - -/** - * MoltenVK configuration settings. - * - * To be active, some configuration settings must be set before a VkDevice is created. - * See the description of the individual configuration structure members for more information. + * To configure MoltenVK, use one of the following mechanisms, + * as documented in MoltenVK_Configuration_Parameters.md: * - * There are three mechanisms for setting the values of the MoltenVK configuration parameters: - * - Runtime API via the vkGetMoltenVKConfigurationMVK()/vkSetMoltenVKConfigurationMVK() functions. + * - The standard Vulkan VK_EXT_layer_settings extension. * - Application runtime environment variables. * - Build settings at MoltenVK build time. * - * To change the MoltenVK configuration settings at runtime using a programmatic API, - * use the vkGetMoltenVKConfigurationMVK() and vkSetMoltenVKConfigurationMVK() functions - * to retrieve, modify, and set a copy of the MVKConfiguration structure. To be active, - * some configuration settings must be set before a VkInstance or VkDevice is created. - * See the description of each member for more information. - * - * The initial value of each of the configuration settings can established at runtime - * by a corresponding environment variable, or if the environment variable is not set, - * by a corresponding build setting at the time MoltenVK is compiled. The environment - * variable and build setting for each configuration parameter share the same name. - * - * For example, the initial value of the shaderConversionFlipVertexY configuration setting - * is set by the MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y at runtime, or by the - * MVK_CONFIG_SHADER_CONVERSION_FLIP_VERTEX_Y build setting when MoltenVK is compiled. - * - * This structure may be extended as new features are added to MoltenVK. If you are linking to - * an implementation of MoltenVK that was compiled from a different MVK_CONFIGURATION_API_VERSION - * than your app was, the size of this structure in your app may be larger or smaller than the - * struct in MoltenVK. See the description of the vkGetMoltenVKConfigurationMVK() and - * vkSetMoltenVKConfigurationMVK() functions for information about how to handle this. - * - * TO SUPPORT DYNAMIC LINKING TO THIS STRUCTURE AS DESCRIBED ABOVE, THIS STRUCTURE SHOULD NOT - * BE CHANGED EXCEPT TO ADD ADDITIONAL MEMBERS ON THE END. EXISTING MEMBERS, AND THEIR ORDER, - * SHOULD NOT BE CHANGED. + * For the private MoltenVK functions, include the mvk_private_api.h header. */ -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_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. - */ - 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. - */ - 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 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; - - /** - * 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; - - /** - * 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; - - /** - * 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 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; - - /** - * 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; - - /** - * 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; - - /** - * 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; - - /** - * 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; - - /** 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; -#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; - - /** - * 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 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 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 performanceTracking parameter must also be enabled. - * - * 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 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 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; - - /** - * 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. - * This setting requires macOS 13.3 & is disabled by default. - */ - 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 1.0 by default, - * indicating that the timestampPeriod will vary relatively slowly, - * with the expectation that the app is querying this value infrequently. - */ - float timestampPeriodLowPassAlpha; - -} 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); - - -#pragma mark - -#pragma mark Function prototypes - -#ifndef VK_NO_PROTOTYPES - -/** - * Populates the pConfiguration structure with the current global MoltenVK configuration settings. - * - * To change a specific configuration value, call vkGetMoltenVKConfigurationMVK() to retrieve - * the current configuration, make changes, and call vkSetMoltenVKConfigurationMVK() to - * update all of the values. - * - * The VkInstance object you provide here is ignored, and a VK_NULL_HANDLE value can be provided. - * This function can be called before the VkInstance has been created. It is safe to call this function - * with a VkInstance retrieved from a different layer in the Vulkan SDK Loader and Layers framework. - * - * To be active, some configuration settings must be set before a VkInstance or VkDevice - * is created. See the description of the MVKConfiguration members for more information. - * - * If you are linking to an implementation of MoltenVK that was compiled from a different - * MVK_CONFIGURATION_API_VERSION than your app was, the size of the MVKConfiguration structure - * in your app may be larger or smaller than the same struct as expected by MoltenVK. - * - * When calling this function, set the value of *pConfigurationSize to sizeof(MVKConfiguration), - * to tell MoltenVK the limit of the size of your MVKConfiguration structure. Upon return from - * this function, the value of *pConfigurationSize will hold the actual number of bytes copied - * into your passed MVKConfiguration structure, which will be the smaller of what your app - * thinks is the size of MVKConfiguration, and what MoltenVK thinks it is. This represents the - * safe access area within the structure for both MoltenVK and your app. - * - * If the size that MoltenVK expects for MVKConfiguration is different than the value passed in - * *pConfigurationSize, this function will return VK_INCOMPLETE, otherwise it will return VK_SUCCESS. - * - * Although it is not necessary, you can use this function to determine in advance the value - * that MoltenVK expects the size of MVKConfiguration to be by setting the value of pConfiguration - * to NULL. In that case, this function will set *pConfigurationSize to the size that MoltenVK - * expects MVKConfiguration to be. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkGetMoltenVKConfigurationMVK( - VkInstance ignored, - MVKConfiguration* pConfiguration, - size_t* pConfigurationSize); - -/** - * Sets the global MoltenVK configuration settings to those found in the pConfiguration structure. - * - * To change a specific configuration value, call vkGetMoltenVKConfigurationMVK() - * to retrieve the current configuration, make changes, and call - * vkSetMoltenVKConfigurationMVK() to update all of the values. - * - * The VkInstance object you provide here is ignored, and a VK_NULL_HANDLE value can be provided. - * This function can be called before the VkInstance has been created. It is safe to call this function - * with a VkInstance retrieved from a different layer in the Vulkan SDK Loader and Layers framework. - * - * To be active, some global configuration settings must be set before a VkInstance or VkDevice - * is created. See the description of the MVKConfiguration members for more information. - * If the VkInstance has the VK_EXT_layer_settings extension enabled, this call must be - * performed before the VkInstance is created, and subsequent changes here will not apply - * to that VkInstance and its derivative objects. The VK_EXT_layer_settings extension can - * be used to make futher changes to that VkInstance. - * - * If you are linking to an implementation of MoltenVK that was compiled from a different - * MVK_CONFIGURATION_API_VERSION than your app was, the size of the MVKConfiguration structure - * in your app may be larger or smaller than the same struct as expected by MoltenVK. - * - * When calling this function, set the value of *pConfigurationSize to sizeof(MVKConfiguration), - * to tell MoltenVK the limit of the size of your MVKConfiguration structure. Upon return from - * this function, the value of *pConfigurationSize will hold the actual number of bytes copied - * out of your passed MVKConfiguration structure, which will be the smaller of what your app - * thinks is the size of MVKConfiguration, and what MoltenVK thinks it is. This represents the - * safe access area within the structure for both MoltenVK and your app. - * - * If the size that MoltenVK expects for MVKConfiguration is different than the value passed in - * *pConfigurationSize, this function will return VK_INCOMPLETE, otherwise it will return VK_SUCCESS. - * - * Although it is not necessary, you can use this function to determine in advance the value - * that MoltenVK expects the size of MVKConfiguration to be by setting the value of pConfiguration - * to NULL. In that case, this function will set *pConfigurationSize to the size that MoltenVK - * expects MVKConfiguration to be. - */ -VKAPI_ATTR VkResult VKAPI_CALL vkSetMoltenVKConfigurationMVK( - VkInstance instance, - 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. - * - * 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 +#define MVK_CONFIGURATION_API_VERSION 39 #ifdef __cplusplus } diff --git a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h index d6fc4aadd..1aea704f2 100644 --- a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h +++ b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h @@ -24,7 +24,7 @@ extern "C" { #endif // __cplusplus -#include +#include #include @@ -34,6 +34,7 @@ extern "C" { /** * This header contains obsolete and deprecated MoltenVK functions, that were originally * part of the obsolete and deprecated non-standard VK_MVK_moltenvk extension. + * This header is provided for legacy compatibility only. * * NOTE: USE OF THE FUNCTIONS BELOW IS NOT RECOMMENDED. THE VK_MVK_moltenvk EXTENSION, * AND THE FUNCTIONS BELOW ARE NOT SUPPORTED BY THE VULKAN LOADER AND LAYERS. @@ -49,6 +50,7 @@ extern "C" { #pragma mark - #pragma mark Function types +typedef VkResult (VKAPI_PTR *PFN_vkSetMoltenVKConfigurationMVK)(VkInstance ignored, const MVKConfiguration* pConfiguration, size_t* pConfigurationSize); typedef void (VKAPI_PTR *PFN_vkGetVersionStringsMVK)(char* pMoltenVersionStringBuffer, uint32_t moltenVersionStringBufferLength, char* pVulkanVersionStringBuffer, uint32_t vulkanVersionStringBufferLength); typedef void (VKAPI_PTR *PFN_vkSetWorkgroupSizeMVK)(VkShaderModule shaderModule, uint32_t x, uint32_t y, uint32_t z); typedef VkResult (VKAPI_PTR *PFN_vkUseIOSurfaceMVK)(VkImage image, IOSurfaceRef ioSurface); @@ -72,6 +74,20 @@ typedef void (VKAPI_PTR *PFN_vkGetMTLCommandQueueMVK)(VkQueue queue, id * - * And if you require the MoltenVK Configuration API, also include the following header file: + * To configure MoltenVK, use one of the following mechanisms, + * as documented in MoltenVK_Configuration_Parameters.md: + * + * - The standard Vulkan VK_EXT_layer_settings extension. + * - Application runtime environment variables. + * - Build settings at MoltenVK build time. * - * #include + * If you require access to private structures and functions to query MoltenVK about MoltenVK + * version and configuration, runtime performance information, and available Metal capabilities, + * use the following header file: + * + * #include * * If you require access to Metal objects underlying equivalent Vulkan objects, * use the standard Vulkan VK_EXT_metal_objects extension. */ -#include "mvk_vulkan.h" -#include "mvk_config.h" - -#include "mvk_private_api.h" -#include "mvk_deprecated_api.h" +#include +#include +#include diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h index dc0edb950..1591fdddb 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.h @@ -26,7 +26,6 @@ #include "MVKSmallVector.h" #include "MVKPixelFormats.h" #include "MVKOSExtensions.h" -#include "mvk_private_api.h" #include "mvk_datatypes.hpp" #include #include @@ -1063,7 +1062,7 @@ class MVKDeviceObjectPool : public MVKObjectPool, public MVKDeviceTrackingMix * sorted according to power, with higher power GPU's at the front of the array. * This ensures that a lazy app that simply grabs the first GPU will get a high-power * one by default. If MVKConfiguration::forceLowPowerGPU is enabled, the returned - * array will only include low-power devices. The intance may be a nullptr. + * array will only include low-power devices. The instance may be a nullptr. */ NSArray>* mvkGetAvailableMTLDevicesArray(MVKInstance* instance); diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 2a98ef622..0e5b2c6d8 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -372,7 +372,8 @@ #define STR(name) #name #define MVK_CONFIG_MEMBER(member, mbrType, name) \ - if(mvkStringsAreEqual(pSetting->pSettingName, STR(MVK_CONFIG_##name))) { \ + if(mvkStringsAreEqual(pSetting->pLayerName, getDriverLayer()->getName()) && \ + mvkStringsAreEqual(pSetting->pSettingName, STR(MVK_CONFIG_##name))) { \ _mvkConfig.member = *(mbrType*)(pSetting->pValues); \ continue; \ } @@ -494,13 +495,13 @@ // MoltenVK-specific instannce functions, not tied to a Vulkan API version or an extension. ADD_INST_OPEN_ENTRY_POINT(vkGetMoltenVKConfigurationMVK); - ADD_INST_OPEN_ENTRY_POINT(vkSetMoltenVKConfigurationMVK); ADD_INST_OPEN_ENTRY_POINT(vkGetPhysicalDeviceMetalFeaturesMVK); ADD_INST_OPEN_ENTRY_POINT(vkGetPerformanceStatisticsMVK); // For deprecated MoltenVK-specific functions, suppress compiler deprecation warning. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" + ADD_INST_OPEN_ENTRY_POINT(vkSetMoltenVKConfigurationMVK); ADD_INST_EXT_ENTRY_POINT(vkGetVersionStringsMVK, MVK_MOLTENVK); ADD_INST_EXT_ENTRY_POINT(vkGetMTLDeviceMVK, MVK_MOLTENVK); ADD_INST_EXT_ENTRY_POINT(vkSetMTLTextureMVK, MVK_MOLTENVK); diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.mm b/MoltenVK/MoltenVK/Layers/MVKLayers.mm index 22b2138b9..237017dc3 100644 --- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm +++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm @@ -100,10 +100,14 @@ static mutex _lock; static MVKLayerManager* _globalManager = VK_NULL_HANDLE; +// Test first and lock only if we need to create it. +// Test again after lock established to ensure it wasn't added by another thread between test and lock. MVKLayerManager* MVKLayerManager::globalManager() { - lock_guard lock(_lock); - if ( !_globalManager ) { _globalManager = new MVKLayerManager(); } + if ( !_globalManager ) { + lock_guard lock(_lock); + if ( !_globalManager ) { + _globalManager = new MVKLayerManager(); + } + } return _globalManager; } - - diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm index c309cc13c..53b1731d7 100644 --- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm +++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm @@ -22,7 +22,6 @@ #include "MVKFoundation.h" #include "MVKOSExtensions.h" #include "MVKStrings.h" -#include using namespace std; diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h index 7da71657a..4dc98a180 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h @@ -21,7 +21,7 @@ #include "MVKCommonEnvironment.h" #include "mvk_vulkan.h" -#include "mvk_config.h" +#include "mvk_private_api.h" #include "MVKLogging.h" #include diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_api.mm b/MoltenVK/MoltenVK/Vulkan/mvk_api.mm index b2151e9bb..fec656666 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_api.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_api.mm @@ -18,7 +18,6 @@ #include "MVKEnvironment.h" -#include "mvk_private_api.h" #include "mvk_deprecated_api.h" #include "MVKInstance.h" #include "MVKSwapchain.h" @@ -53,7 +52,7 @@ VkResult mvkCopyGrowingStruct(S* pDst, const S* pSrc, size_t* pCopySize) { #pragma mark - -#pragma mark mvk_config.h +#pragma mark mvk_private_api.h MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMoltenVKConfigurationMVK( VkInstance ignored, @@ -69,16 +68,13 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkSetMoltenVKConfigurationMVK( size_t* pConfigurationSize) { // Start with copy of current config, in case incoming is not fully copied + MVKBaseObject::reportMessage(nullptr, MVK_CONFIG_LOG_LEVEL_WARNING, "vkSetMoltenVKConfigurationMVK() is deprecated. To set MoltenVK configuration parameters, the VK_EXT_layer_settings extension, or environment variables."); MVKConfiguration mvkCfg = mvkConfig(); VkResult rslt = mvkCopyGrowingStruct(&mvkCfg, pConfiguration, pConfigurationSize); mvkSetConfig(mvkCfg); return rslt; } - -#pragma mark - -#pragma mark mvk_private_api.h - MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetPhysicalDeviceMetalFeaturesMVK( VkPhysicalDevice physicalDevice, MVKPhysicalDeviceMetalFeatures* pMetalFeatures, diff --git a/MoltenVKPackaging.xcodeproj/project.pbxproj b/MoltenVKPackaging.xcodeproj/project.pbxproj index 29899ab6a..43d05866e 100644 --- a/MoltenVKPackaging.xcodeproj/project.pbxproj +++ b/MoltenVKPackaging.xcodeproj/project.pbxproj @@ -126,6 +126,13 @@ remoteGlobalIDString = A9CBED861B6299D800E45FDC; remoteInfo = "MoltenVK-macOS"; }; + A97D77552B24FBDF00E36932 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = A92DB40E1CE0F89600FBC835 /* MoltenVKShaderConverter.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = DCFD7F882A45BDA0007BBBF7; + remoteInfo = "MoltenVKShaderConverter-xrOS"; + }; A981498A1FB6B566005F00B4 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = A92DB40E1CE0F89600FBC835 /* MoltenVKShaderConverter.xcodeproj */; @@ -213,6 +220,7 @@ A93ED4DE24F59CDB00FEB018 /* copy_lib_to_staging.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = copy_lib_to_staging.sh; sourceTree = ""; }; A93ED4E324F59CDB00FEB018 /* copy_to_staging.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = copy_to_staging.sh; sourceTree = ""; }; A975D55C213F25D700D4834F /* create_dylib.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = create_dylib.sh; sourceTree = ""; }; + A97D77502B24FBDF00E36932 /* MoltenVK_Configuration_Parameters.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = MoltenVK_Configuration_Parameters.md; path = Docs/MoltenVK_Configuration_Parameters.md; sourceTree = ""; }; A980A25F24C628F3007A8F6F /* gen_moltenvk_rev_hdr.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = gen_moltenvk_rev_hdr.sh; sourceTree = ""; }; A98149E51FB78829005F00B4 /* MoltenVK_Runtime_UserGuide.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = MoltenVK_Runtime_UserGuide.md; path = Docs/MoltenVK_Runtime_UserGuide.md; sourceTree = ""; }; A9A15AA625D6D884004EEBE9 /* CI.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; name = CI.yml; path = .github/workflows/CI.yml; sourceTree = ""; }; @@ -241,10 +249,11 @@ A92DB3E11CE0F34500FBC835 /* Docs */ = { isa = PBXGroup; children = ( - A92DB3E51CE0F37D00FBC835 /* LICENSE */, - A98149E51FB78829005F00B4 /* MoltenVK_Runtime_UserGuide.md */, - A92DB3E41CE0F37D00FBC835 /* README.md */, A92DB3E61CE0F37D00FBC835 /* Whats_New.md */, + A92DB3E41CE0F37D00FBC835 /* README.md */, + A98149E51FB78829005F00B4 /* MoltenVK_Runtime_UserGuide.md */, + A97D77502B24FBDF00E36932 /* MoltenVK_Configuration_Parameters.md */, + A92DB3E51CE0F37D00FBC835 /* LICENSE */, ); name = Docs; sourceTree = ""; @@ -291,6 +300,7 @@ A98149911FB6B566005F00B4 /* libMoltenVKShaderConverter.a */, A9FC5F5D249D2547003CB086 /* libMoltenVKShaderConverter.a */, A98149931FB6B566005F00B4 /* libMoltenVKShaderConverter.a */, + A97D77562B24FBDF00E36932 /* libMoltenVKShaderConverter.a */, ); name = Products; sourceTree = ""; @@ -371,6 +381,13 @@ remoteRef = A92DB3F61CE0F72500FBC835 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + A97D77562B24FBDF00E36932 /* libMoltenVKShaderConverter.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libMoltenVKShaderConverter.a; + remoteRef = A97D77552B24FBDF00E36932 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; A981498B1FB6B566005F00B4 /* MoltenVKShaderConverter */ = { isa = PBXReferenceProxy; fileType = "compiled.mach-o.executable"; @@ -402,7 +419,7 @@ DCFD7F662A45BC7D007BBBF7 /* libMoltenVK.a */ = { isa = PBXReferenceProxy; fileType = archive.ar; - path = "libMoltenVK.a"; + path = libMoltenVK.a; remoteRef = DCFD7F652A45BC7D007BBBF7 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; diff --git a/README.md b/README.md index 2fa365260..e7d565993 100644 --- a/README.md +++ b/README.md @@ -284,7 +284,7 @@ Building from the command line creates the same `Package` folder structure descr building from within *Xcode*. When building from the command line, you can set any of the build settings documented -in the `mvk_config.h` file for `MVKConfiguration`, by passing them in the command line, +in the `MoltenVK_Configuration_Parameters.md` file, by passing them in the command line, as in the following examples: make MVK_CONFIG_LOG_LEVEL=0 @@ -343,7 +343,6 @@ the contents of that directory out of this **MoltenVK** repository into your own - **MoltenVK** and *Vulkan* Compliance ------------------------------------ diff --git a/Scripts/runcts b/Scripts/runcts index dfac7a135..735e84ef1 100755 --- a/Scripts/runcts +++ b/Scripts/runcts @@ -84,13 +84,12 @@ fi # -------------- MoltenVK configuration -------------------- # As documented above, the portability option restricts to Vulkan 1.0 and a very limited set of extensions. -# The values used here are documented in mvk_config.h. -# - MVK_CONFIG_API_VERSION_TO_ADVERTISE = VK_API_VERSION_1_0 (4194304) -# - MVK_CONFIG_ADVERTISE_EXTENSIONS selects support for a very limited set of extensions, -# using a bit-or of values in MVKConfigAdvertiseExtensions (extension list documented above). +# The values used here are documented in MoltenVK_Configuration_Parameters.md. +# - MVK_CONFIG_API_VERSION_TO_ADVERTISE = 4194304 (VK_API_VERSION_1_0). +# - MVK_CONFIG_ADVERTISE_EXTENSIONS = 4 (VK_KHR_portability_subset and prerequistes). if [ "${is_portability}" != "" ]; then export MVK_CONFIG_API_VERSION_TO_ADVERTISE=4194304 - export MVK_CONFIG_ADVERTISE_EXTENSIONS=0xA + export MVK_CONFIG_ADVERTISE_EXTENSIONS=4 fi # ----- System settings ------ @@ -106,6 +105,7 @@ export MVK_CONFIG_LOG_LEVEL=1 #(1 = Errors only, 3 = Info) export MVK_CONFIG_DEBUG=0 # Additional MoltenVK configuration can be set here by editing below. +# The values used here are documented in MoltenVK_Configuration_Parameters.md. export MVK_CONFIG_RESUME_LOST_DEVICE=1 export MVK_CONFIG_FAST_MATH_ENABLED=1 export MVK_CONFIG_FORCE_LOW_POWER_GPU=0 From ea3cbbc5965a6eb1010245f95f5293d4d9871028 Mon Sep 17 00:00:00 2001 From: Stephen Saunders Date: Fri, 15 Dec 2023 18:09:39 -0500 Subject: [PATCH 05/14] Fix VkPhysicalDeviceMemoryBudgetPropertiesEXT heapUsage query for non-unified memory devices --- Common/MVKOSExtensions.mm | 4 ++++ MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 8d33f3d48..0a45aad9c 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -134,7 +134,11 @@ uint64_t mvkGetUsedMemorySize() { task_vm_info_data_t task_vm_info; mach_msg_type_number_t task_size = TASK_VM_INFO_COUNT; if (task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&task_vm_info, &task_size) == KERN_SUCCESS) { +#ifdef TASK_VM_INFO_REV3_COUNT // check for rev3 version of task_vm_info + return task_vm_info.ledger_tag_graphics_footprint; +#else return task_vm_info.phys_footprint; +#endif } return 0; } diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index af016e513..be729b175 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1650,12 +1650,12 @@ auto* budgetProps = (VkPhysicalDeviceMemoryBudgetPropertiesEXT*)next; mvkClear(budgetProps->heapBudget, VK_MAX_MEMORY_HEAPS); mvkClear(budgetProps->heapUsage, VK_MAX_MEMORY_HEAPS); - budgetProps->heapBudget[0] = (VkDeviceSize)getRecommendedMaxWorkingSetSize(); - budgetProps->heapUsage[0] = (VkDeviceSize)getCurrentAllocatedSize(); if (!getHasUnifiedMemory()) { budgetProps->heapBudget[1] = (VkDeviceSize)mvkGetAvailableMemorySize(); budgetProps->heapUsage[1] = (VkDeviceSize)mvkGetUsedMemorySize(); } + budgetProps->heapBudget[0] = (VkDeviceSize)getRecommendedMaxWorkingSetSize(); + budgetProps->heapUsage[0] = (VkDeviceSize)getCurrentAllocatedSize() - budgetProps->heapUsage[1]; break; } default: From ef0ac40cff8b7a6b517319a9dacfe8c70e6853d3 Mon Sep 17 00:00:00 2001 From: Stephen Saunders Date: Fri, 15 Dec 2023 21:04:12 -0500 Subject: [PATCH 06/14] Add a defensive guard to ensure heapUsage[0] calculation is always sane --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index be729b175..f42987bf4 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1655,7 +1655,12 @@ budgetProps->heapUsage[1] = (VkDeviceSize)mvkGetUsedMemorySize(); } budgetProps->heapBudget[0] = (VkDeviceSize)getRecommendedMaxWorkingSetSize(); - budgetProps->heapUsage[0] = (VkDeviceSize)getCurrentAllocatedSize() - budgetProps->heapUsage[1]; + uint64_t currentAllocatedSize = (VkDeviceSize)getCurrentAllocatedSize(); + if (budgetProps->heapUsage[1] > currentAllocatedSize) { + // mapped memory can't be larger than total memory, so ignore and zero-out + budgetProps->heapUsage[1] = 0; + } + budgetProps->heapUsage[0] = currentAllocatedSize - budgetProps->heapUsage[1]; break; } default: From 28be920b2f0d8989182990b2b5a0e566852ef294 Mon Sep 17 00:00:00 2001 From: Stephen Saunders Date: Fri, 15 Dec 2023 22:15:53 -0500 Subject: [PATCH 07/14] Check for Rev3 task info / ledger_tag_graphics_footprint availability at runtime --- Common/MVKOSExtensions.mm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 0a45aad9c..c1af7544f 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -135,10 +135,12 @@ uint64_t mvkGetUsedMemorySize() { mach_msg_type_number_t task_size = TASK_VM_INFO_COUNT; if (task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&task_vm_info, &task_size) == KERN_SUCCESS) { #ifdef TASK_VM_INFO_REV3_COUNT // check for rev3 version of task_vm_info - return task_vm_info.ledger_tag_graphics_footprint; -#else - return task_vm_info.phys_footprint; + if (task_size >= TASK_VM_INFO_REV3_COUNT) { + return task_vm_info.ledger_tag_graphics_footprint; + } + else #endif + return task_vm_info.phys_footprint; } return 0; } From 99123bf1dcdacee04c751f59866a28be38933644 Mon Sep 17 00:00:00 2001 From: Chip Davis Date: Sat, 16 Dec 2023 14:55:04 -0700 Subject: [PATCH 08/14] Use `auto` instead of an explicit type. --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index f42987bf4..47ca882e7 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -1655,7 +1655,7 @@ budgetProps->heapUsage[1] = (VkDeviceSize)mvkGetUsedMemorySize(); } budgetProps->heapBudget[0] = (VkDeviceSize)getRecommendedMaxWorkingSetSize(); - uint64_t currentAllocatedSize = (VkDeviceSize)getCurrentAllocatedSize(); + auto currentAllocatedSize = (VkDeviceSize)getCurrentAllocatedSize(); if (budgetProps->heapUsage[1] > currentAllocatedSize) { // mapped memory can't be larger than total memory, so ignore and zero-out budgetProps->heapUsage[1] = 0; From c4b7232f3647787f8c333743483e9636e575b1ef Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Sun, 17 Dec 2023 16:57:32 -0500 Subject: [PATCH 09/14] Fix regression error and properties in point-topology/polygon-mode behavior. - MVKGraphicsPipeline::isRenderingPoints() fix regression error to support dynamically setting point topology. - Move emulation of VK_POLYGON_MODE_POINT in Metal, if the polygon model is static, to MVKRenderingCommandEncoderState, to handle dynamic setting of topology. - MVKDevice populate VkPhysicalDeviceExtendedDynamicState3PropertiesEXT. - Move error reporting in mvkMTLTriangleFillModeFromVkPolygonModeInObj() to encoding. - MVKRenderingCommandEncoderState::setCullMode() use getContent() for readability and consistency (unrelated). - Pass pipeline object to datatype functions for reporting accuracy (unrelated). --- .../Commands/MVKCommandEncoderState.h | 1 + .../Commands/MVKCommandEncoderState.mm | 17 +++++++++++-- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 5 ++++ MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm | 24 ++++++++++++------- MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm | 2 +- 5 files changed, 37 insertions(+), 12 deletions(-) diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h index 4ac895d43..865cd1c02 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h @@ -332,6 +332,7 @@ class MVKRenderingCommandEncoderState : public MVKCommandEncoderState { bool _mtlPrimitiveRestartEnable[StateScope::Count] = {}; bool _mtlRasterizerDiscardEnable[StateScope::Count] = {}; bool _cullBothFaces[StateScope::Count] = {}; + bool _isPolygonModePoint[StateScope::Count] = {}; }; diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm index c7246a516..769230bc1 100644 --- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm +++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm @@ -302,7 +302,7 @@ void MVKRenderingCommandEncoderState::setCullMode(VkCullModeFlags cullMode, bool isDynamic) { auto mtlCullMode = mvkMTLCullModeFromVkCullModeFlags(cullMode); setMTLContent(CullMode); - _cullBothFaces[isDynamic ? StateScope::Dynamic : StateScope::Static] = (cullMode == VK_CULL_MODE_FRONT_AND_BACK); + getContent(_cullBothFaces, isDynamic) = (cullMode == VK_CULL_MODE_FRONT_AND_BACK); } void MVKRenderingCommandEncoderState::setFrontFace(VkFrontFace frontFace, bool isDynamic) { @@ -313,6 +313,7 @@ void MVKRenderingCommandEncoderState::setPolygonMode(VkPolygonMode polygonMode, bool isDynamic) { auto mtlPolygonMode = mvkMTLTriangleFillModeFromVkPolygonMode(polygonMode); setMTLContent(PolygonMode); + getContent(_isPolygonModePoint, isDynamic) = (polygonMode == VK_POLYGON_MODE_POINT); } void MVKRenderingCommandEncoderState::setBlendConstants(float blendConstants[4], bool isDynamic) { @@ -420,8 +421,20 @@ getContent(_mtlPrimitiveTopology, isDynamic) = mvkMTLPrimitiveTypeFromVkPrimitiveTopology(topology); } +// Metal does not support VK_POLYGON_MODE_POINT, but it can be emulated if the polygon mode +// is static, which allows both the topology and the pipeline topology-class to be set to points. +// This cannot be accomplished if the dynamic polygon mode has been changed to points when the +// pipeline is expecting triangles or lines, because the pipeline topology class will be incorrect. MTLPrimitiveType MVKRenderingCommandEncoderState::getPrimitiveType() { - return getMTLContent(PrimitiveTopology); + if (isDynamicState(PolygonMode) && + _isPolygonModePoint[StateScope::Dynamic] && + !_isPolygonModePoint[StateScope::Static]) { + + reportWarning(VK_ERROR_FEATURE_NOT_PRESENT, "vkCmdSetPolygonMode(): Metal does not support setting VK_POLYGON_MODE_POINT dynamically."); + return getMTLContent(PrimitiveTopology); + } + + return getContent(_isPolygonModePoint, PolygonMode) ? MTLPrimitiveTypePoint : getMTLContent(PrimitiveTopology); } bool MVKRenderingCommandEncoderState::isDrawingTriangles() { diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index af016e513..5dd3c976e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -762,6 +762,11 @@ portabilityProps->minVertexInputBindingStrideAlignment = (uint32_t)_metalFeatures.vertexStrideAlignment; break; } + case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_3_PROPERTIES_EXT: { + auto* extDynState3Props = (VkPhysicalDeviceExtendedDynamicState3PropertiesEXT*)next; + extDynState3Props->dynamicPrimitiveTopologyUnrestricted = false; + break; + } case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT: { auto* extMemHostProps = (VkPhysicalDeviceExternalMemoryHostPropertiesEXT*)next; extMemHostProps->minImportedHostPointerAlignment = _metalFeatures.hostMemoryPageSize; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm index c85ef684b..3b5dd95d6 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm @@ -511,11 +511,12 @@ } // Topology - _vkPrimitiveTopology = (pCreateInfo->pInputAssemblyState && !isRenderingPoints(pCreateInfo) - ? pCreateInfo->pInputAssemblyState->topology - : VK_PRIMITIVE_TOPOLOGY_POINT_LIST); - - _primitiveRestartEnable = pCreateInfo->pInputAssemblyState ? pCreateInfo->pInputAssemblyState->primitiveRestartEnable : true; + _vkPrimitiveTopology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + _primitiveRestartEnable = true; // Always enabled in Metal + if (pCreateInfo->pInputAssemblyState) { + _vkPrimitiveTopology = pCreateInfo->pInputAssemblyState->topology; + _primitiveRestartEnable = pCreateInfo->pInputAssemblyState->primitiveRestartEnable; + } // Rasterization _hasRasterInfo = mvkSetOrClear(&_rasterInfo, pCreateInfo->pRasterizationState); @@ -1933,11 +1934,16 @@ static MTLVertexFormat mvkAdjustFormatVectorToSize(MTLVertexFormat format, uint3 } } -// We render points if either the static topology or static polygon fill mode dictate it +// We render points if either the static topology or static polygon-mode dictate it. +// The topology class must be the same between static and dynamic, so point topology +// in static also implies point topology in dynamic. +// Metal does not support VK_POLYGON_MODE_POINT, but it can be emulated if the polygon mode +// is static, which allows both the topology and the pipeline topology-class to be set to points. +// This cannot be accomplished if the dynamic polygon mode has been changed to points when the +// pipeline is expecting triangles or lines, because the pipeline topology class will be incorrect. bool MVKGraphicsPipeline::isRenderingPoints(const VkGraphicsPipelineCreateInfo* pCreateInfo) { - return ((pCreateInfo->pInputAssemblyState && - (pCreateInfo->pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST) && - !isDynamicState(PrimitiveTopology)) || + return ((pCreateInfo->pInputAssemblyState && + (pCreateInfo->pInputAssemblyState->topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST)) || (pCreateInfo->pRasterizationState && (pCreateInfo->pRasterizationState->polygonMode == VK_POLYGON_MODE_POINT) && !isDynamicState(PolygonMode))); diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm index 8fdbc1a66..27b87df12 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_datatypes.mm @@ -509,8 +509,8 @@ MTLTriangleFillMode mvkMTLTriangleFillModeFromVkPolygonModeInObj(VkPolygonMode v case VK_POLYGON_MODE_FILL: return MTLTriangleFillModeFill; + // Metal does not support VK_POLYGON_MODE_POINT. Next best option is lines. case VK_POLYGON_MODE_POINT: - MVKBaseObject::reportError(mvkObj, VK_ERROR_FORMAT_NOT_SUPPORTED, "VkPolygonMode value VK_POLYGON_MODE_POINT is not supported for render pipelines."); case VK_POLYGON_MODE_LINE: return MTLTriangleFillModeLines; From d483d620b69102a48829deb9f0d4a7f89213b9a5 Mon Sep 17 00:00:00 2001 From: karelrooted Date: Sat, 16 Dec 2023 14:33:44 +0800 Subject: [PATCH 10/14] Fix system memory size of tvOS use sysctlbyname("hw.memsize") to get sytem memory size instead of host_info, host_info is not available on tvOS, so we change to sysctlbyname which support all apple platforms apple document didn't stat this API is available on tvOS though, https://developer.apple.com/documentation/kernel/1387446-sysctlbyname --- Common/MVKOSExtensions.mm | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/Common/MVKOSExtensions.mm b/Common/MVKOSExtensions.mm index 8d33f3d48..df2392abd 100644 --- a/Common/MVKOSExtensions.mm +++ b/Common/MVKOSExtensions.mm @@ -23,6 +23,7 @@ #include #include #include +#include #import @@ -100,17 +101,12 @@ bool mvkGetEnvVar(const char* varName, string& evStr) { #pragma mark System memory uint64_t mvkGetSystemMemorySize() { -#if MVK_MACOS_OR_IOS_OR_VISIONOS - mach_msg_type_number_t host_size = HOST_BASIC_INFO_COUNT; - host_basic_info_data_t info; - if (host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&info, &host_size) == KERN_SUCCESS) { - return info.max_mem; + uint64_t host_memsize = 0; + size_t size = sizeof(host_memsize); + if (sysctlbyname("hw.memsize", &host_memsize, &size, NULL, 0) == KERN_SUCCESS) { + return host_memsize; } return 0; -#endif -#if MVK_TVOS - return 0; -#endif } uint64_t mvkGetAvailableMemorySize() { From 1ce40f63a47e34d5366124226fa02f6f8bc1457f Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Mon, 18 Dec 2023 11:00:35 -0500 Subject: [PATCH 11/14] Fixes from dev review feedback for adding VK_EXT_layer_settings extension. - Document the name of the MoltenVK driver layer. - Support future multiple string members in MVKConfiguration. - Add static assert on number of string members in MVKConfigruation. - Rename global mvkConfig() to getGlobalMVKConfig(). - Rename global mvkSetConfig() to mvkSetGlobalConfig(). - Remove unused mvkPrintSizeOf() macro. (unrelated). - Trim trailing spaces from Markdown documents because it causes double-spaces in some Markdown readers (unrelated). --- Demos/README.md | 12 +- Docs/MoltenVK_Configuration_Parameters.md | 195 ++++----- Docs/MoltenVK_Runtime_UserGuide.md | 375 +++++++++--------- MoltenVK/MoltenVK/API/mvk_config.h | 2 +- MoltenVK/MoltenVK/API/mvk_deprecated_api.h | 4 +- MoltenVK/MoltenVK/API/mvk_private_api.h | 2 +- MoltenVK/MoltenVK/API/mvk_vulkan.h | 3 + MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 2 +- MoltenVK/MoltenVK/GPUObjects/MVKInstance.h | 4 +- MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm | 4 +- MoltenVK/MoltenVK/GPUObjects/MVKSync.mm | 2 +- MoltenVK/MoltenVK/Layers/MVKExtensions.mm | 2 +- MoltenVK/MoltenVK/Layers/MVKLayers.mm | 2 +- MoltenVK/MoltenVK/Utility/MVKBaseObject.h | 2 +- MoltenVK/MoltenVK/Utility/MVKBaseObject.mm | 4 +- .../MoltenVK/Utility/MVKConfigMembers.def | 2 +- MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp | 113 +++--- MoltenVK/MoltenVK/Utility/MVKEnvironment.h | 13 +- MoltenVK/MoltenVK/Utility/MVKFoundation.h | 3 - MoltenVK/MoltenVK/Vulkan/mvk_api.mm | 8 +- MoltenVK/MoltenVK/Vulkan/vulkan.mm | 6 +- README.md | 286 ++++++------- 23 files changed, 540 insertions(+), 508 deletions(-) diff --git a/Demos/README.md b/Demos/README.md index 29fddb101..1e607ab49 100644 --- a/Demos/README.md +++ b/Demos/README.md @@ -24,19 +24,19 @@ Table of Contents *Cube* ------ -The basic canonical *Cube* sample app from the -[*Vulkan-Tools* repository](https://github.com/KhronosGroup/Vulkan-Tools) +The basic canonical *Cube* sample app from the +[*Vulkan-Tools* repository](https://github.com/KhronosGroup/Vulkan-Tools) is included in this **MoltenVK** package. This demo renders a basic textured cube that spins in place. -The demo can be found in the `Cube` folder, and in the `Cube` group in the +The demo can be found in the `Cube` folder, and in the `Cube` group in the *Xcode Project Navigator* in the `Demos.xcworkspace` *Xcode* workspace. -To run this demo, run the `Cube-iOS`, `Cube-tvOS`, or `Cube-macOS` *Scheme* from within *Xcode*. +To run this demo, run the `Cube-iOS`, `Cube-tvOS`, or `Cube-macOS` *Scheme* from within *Xcode*. In addition to devices, this demo will also run on the `iOS Simulator` or `tvOS Simulator` destinations. -The `Cube` demo is a simple example of installing **MoltenVK** as an `XCFramework` that is +The `Cube` demo is a simple example of installing **MoltenVK** as an `XCFramework` that is statically linked to the application. It supports all platforms, including _Mac Catalyst_, _iOS Simulator_ and _tvOS Simulator_, and all architectures including _Apple Silicon_. @@ -46,5 +46,5 @@ Simulator_ and _tvOS Simulator_, and all architectures including _Apple Silicon_ *Khronos Vulkan Samples* ---------------------- -*Khronos Group* provides a [repository](https://github.com/KhronosGroup/Vulkan-Samples) +*Khronos Group* provides a [repository](https://github.com/KhronosGroup/Vulkan-Samples) containing a full suite of standard *Vulkan* samples that run on **MoltenVK** on *macOS*. diff --git a/Docs/MoltenVK_Configuration_Parameters.md b/Docs/MoltenVK_Configuration_Parameters.md index f5527d311..423bd4887 100644 --- a/Docs/MoltenVK_Configuration_Parameters.md +++ b/Docs/MoltenVK_Configuration_Parameters.md @@ -1,4 +1,4 @@ - @@ -14,28 +14,37 @@ Copyright (c) 2015-2023 [The Brenwill Workshop Ltd.](http://www.brenwill.com) -**MoltenVK** provides the ability to configure and optimize **MoltenVK** for your particular -application runtime requirements and development-time needs. +**MoltenVK** provides the ability to configure and optimize **MoltenVK** for your particular +application runtime requirements and development-time needs. -At runtime, configuration can be helpful in situtations where _Metal_ behavior is different -than _Vulkan_ behavior, and the results or performance you receive can depend on how **MoltenVK** -works around those differences, which, in turn, may depend on how you are using _Vulkan_. +At runtime, configuration can be helpful in situtations where _Metal_ behavior is different +than _Vulkan_ behavior, and the results or performance you receive can depend on how **MoltenVK** +works around those differences, which, in turn, may depend on how you are using _Vulkan_. Different apps might benefit differently in this handling. Additional configuration parameters can be helpful at development time by providing you with additional tracing, debugging, and performance measuring capabilities. -Each configuration parameter has a *name* and *value*, and can be passed to **MoltenVK** +Each configuration parameter has a *name* and *value*, and can be passed to **MoltenVK** via any of the following mechanisms: - The standard _Vulkan_ `VK_EXT_layer_settings` extension. - Application runtime environment variables. - Build settings at **MoltenVK** build time. -Parameter values configured by build settings at **MoltenVK** build time can be overridden -by values set by environment variables, which, in turn, can be overridden during `VkInstance` +Parameter values configured by build settings at **MoltenVK** build time can be overridden +by values set by environment variables, which, in turn, can be overridden during `VkInstance` creation via the _Vulkan_ `VK_EXT_layer_settings` extension. +Using the `VK_EXT_layer_settings` extension is the preferred mechanism, as it is a standard +_Vulkan_ extension, and is supported by the _Vulkan_ loader and layers. When using the +`VK_EXT_layer_settings` extension, set `VkLayerSettingEXT::pLayerName` to the value of +`kMVKMoltenVKDriverLayerName` found in the `mvk_vulkan.h` header (or simply to `"MoltenVK"`). + +Using environment variables can be a convinient mechanism to modify configuration parameters +during runtime debugging in the field (if the settings are *not* overridden during `VkInstance` +creation via the _Vulkan_ `VK_EXT_layer_settings` extension). + --------------------------------------- #### MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE @@ -49,7 +58,7 @@ creation via the _Vulkan_ `VK_EXT_layer_settings` extension. ##### Default: `0` -If the `MVK_CONFIG_PERFORMANCE_TRACKING` parameter is enabled, this parameter controls +If the `MVK_CONFIG_PERFORMANCE_TRACKING` parameter is enabled, this parameter controls when **MoltenVK** should log activity performance events. @@ -59,8 +68,8 @@ when **MoltenVK** should log activity performance events. ##### Type: UInt32 ##### Default: `1` -Controls which extensions **MoltenVK** should advertise it supports in `vkEnumerateInstanceExtensionProperties()` -and `vkEnumerateDeviceExtensionProperties()`. This can be useful when testing **MoltenVK** against specific +Controls which extensions **MoltenVK** should advertise it supports in `vkEnumerateInstanceExtensionProperties()` +and `vkEnumerateDeviceExtensionProperties()`. This can be useful when testing **MoltenVK** against specific limited functionality. The value of this parameter is a `Bitwise-OR` of the following values: - `1`: All supported extensions. @@ -68,7 +77,7 @@ limited functionality. The value of this parameter is a `Bitwise-OR` of the foll - `4`: _Vulkan_ Portability Subset extensions. -Any prerequisite extensions are also advertised. If bit `1` is included, all supported +Any prerequisite extensions are also advertised. If bit `1` is included, all supported extensions will be advertised. A value of zero means no extensions will be advertised. @@ -78,7 +87,7 @@ extensions will be advertised. A value of zero means no extensions will be adver ##### Type: UInt32 ##### Default: `4202496` -Controls the _Vulkan_ API version that **MoltenVK** should advertise in `vkEnumerateInstanceVersion()`, +Controls the _Vulkan_ API version that **MoltenVK** should advertise in `vkEnumerateInstanceVersion()`, after **MoltenVK** adds the `VK_HEADER_VERSION` component. Set this value to one of: @@ -96,13 +105,13 @@ Set this value to one of: _(The default value is an empty string)._ -If `MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE` is any value other than `0`, this is the path to a -file where the automatic GPU capture will be saved. If this parameter is an empty string +If `MVK_CONFIG_AUTO_GPU_CAPTURE_SCOPE` is any value other than `0`, this is the path to a +file where the automatic GPU capture will be saved. If this parameter is an empty string (the default), automatic GPU capture will be handled by the _Xcode_ user interface. -If this parameter is set to a valid file path, 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 +If this parameter is set to a valid file path, 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. This feature requires _Metal 2.2 (macOS 10.15+, iOS/tvOS 13+)_. @@ -113,8 +122,8 @@ a user's home directory. This feature requires _Metal 2.2 (macOS 10.15+, iOS/tvO - `0`: No automatic GPU capture. - `1`: Automatically capture all GPU activity during the lifetime of a `VkDevice`. - `2`: Automatically capture all GPU activity during the rendering and presentation of the first frame. - The queue for which the frame is captured is identifed by the values of the - `MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX` and + The queue for which the frame is captured is identifed by the values of the + `MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX` and `MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_INDEX` configuration parameters. ##### Default: `0` @@ -144,7 +153,7 @@ If enabled, debugging capabilities will be enabled, including logging shader cod ##### Type: UInt32 ##### Default: `0` -The index of the queue family whose presentation submissions will be +The index of the queue family whose presentation submissions will be used as the default GPU Capture Scope, when GPU Capture is active. @@ -155,7 +164,7 @@ used as the default GPU Capture Scope, when GPU Capture is active. ##### Default: `0` The index of the queue, within the queue family identified by the -`MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX` parameter, whose presentation +`MVK_CONFIG_DEFAULT_GPU_CAPTURE_SCOPE_QUEUE_FAMILY_INDEX` parameter, whose presentation submissions will be used as the default GPU Capture Scope, when GPU Capture is active. @@ -175,22 +184,22 @@ This can be enabled for publicity during demos. ##### Type: Enumeration - `0`: _Metal_ shaders will never be compiled with the fast math option. - `1`: _Metal_ shaders will always be compiled with the fast math option. -- `2`: _Metal_ shaders will be compiled with the fast math option, unless the shader includes execution +- `2`: _Metal_ shaders will be compiled with the fast math option, unless the shader includes execution capabilities, such as `SignedZeroInfNanPreserve`, that require it to be compiled without fast math. ##### Default: `1` -Identifies when _Metal_ shaders will be compiled with the _Metal_ fast math option enabled. +Identifies when _Metal_ shaders will be compiled with the _Metal_ fast math option enabled. -Shaders compiled with the _Metal_ fast math option enabled perform floating point math significantly +Shaders compiled with the _Metal_ fast math option enabled perform floating point math significantly faster, but may optimize floating point operations in ways that 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 +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 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 `2`, so that fast math will be disabled when compiling shaders +Apps that have specific accuracy and handling needs for particular shaders, may elect to set +the value of this property to `2`, so that fast math will be disabled when compiling shaders that request specific math accuracy and precision capabilities, such as `SignedZeroInfNanPreserve`. @@ -218,7 +227,7 @@ _Metal_ shader code during all texture sampling and reading operations. This occ of whether a swizzle is required for the `VkImageView` associated with the _Metal_ texture, which may result in reduced performance. -If disabled, and native _Metal_ per-texture swizzling is not available on the platform, the +If disabled, and native _Metal_ per-texture swizzling is not available on the platform, the following very limited set of `VkImageView` component swizzles is supported via format substitutions: ``` @@ -237,9 +246,9 @@ VK_FORMAT_D24_UNORM_S8_UINT RED, ANY, ANY, ANY (stencil only) If native per-texture swizzling is not available, and this feature is not enabled, an error is logged and returned in the following situations: -- `VkImageView` creation if that `VkImageView` requires full image view swizzling. +- `VkImageView` creation if that `VkImageView` requires full image view swizzling. - A pipeline that was not compiled with full image view swizzling uses a `VkImageView` that is expecting a swizzle. -- `VkPhysicalDeviceImageFormatInfo2KHR` is passed in a call to `vkGetPhysicalDeviceImageFormatProperties2KHR()` +- `VkPhysicalDeviceImageFormatInfo2KHR` is passed in a call to `vkGetPhysicalDeviceImageFormatProperties2KHR()` to query for an `VkImageView` format that will require full swizzling. @@ -265,9 +274,9 @@ Controls the level of logging performed by **MoltenVK**. ##### Default: `64` 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 `MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS` parameter. -If `MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS` is set to anything other than `0`, one _Metal_ command buffer -is required per _Vulkan_ command buffer, otherwise one _Metal_ command buffer is required per command buffer +of active _Metal_ command buffers required depends on the `MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS` parameter. +If `MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS` is set to anything other than `0`, one _Metal_ command buffer +is required per _Vulkan_ command buffer, otherwise one _Metal_ command buffer is required per command buffer queue submission, which will typically be significantly less than the number of _Vulkan_ command buffers. @@ -304,7 +313,7 @@ no frame-based performance statistics will be logged. If enabled, performance statistics, as defined by the `MVKPerformanceStatistics` structure, are collected, and can be retrieved via the private-API `vkGetPerformanceStatisticsMVK()` function. -You can also use the `MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE` and +You can also use the `MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE` and `MVK_CONFIG_PERFORMANCE_LOGGING_FRAME_COUNT` parameters to configure when to log the performance statistics collected by this parameter. @@ -325,47 +334,47 @@ dynamically allocated in application memory when the descriptor set itself is al #### MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS ##### Type: Enumeration -- `0`: During _Vulkan_ command buffer filling, do not prefill a _Metal_ command buffer for each _Vulkan_ - command buffer. A single _Metal_ command buffer will be 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, +- `0`: During _Vulkan_ command buffer filling, do not prefill a _Metal_ command buffer for each _Vulkan_ + command buffer. A single _Metal_ command buffer will be 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. -- `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, +- `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. -- `2`: During _Vulkan_ command buffer filling, as each +- `2`: During _Vulkan_ command buffer filling, as each command is submitted to the _Vulkan_ command buffer, immediately encode it to the _Metal_ 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, + This option has the smallest memory footprint, and the slowest performance, of the prefilling options using autorelease pools. -- `3`: During _Vulkan_ command buffer filling, as each +- `3`: During _Vulkan_ command buffer filling, as each command is submitted to the _Vulkan_ command buffer, immediately encode it to the _Metal_ 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 + 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. ##### Default: `0` For any value other than `0`, be aware of the following: -- 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 +- 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 `MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE` parameter. -- 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 +- 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`). -- For primary command buffers that are intended to be reused (`VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT` - is not set), prefilling will only apply to the first submission. Later submissions of the same command buffer +- For primary command buffers that are intended to be reused (`VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT` + is not set), prefilling will only apply to the first submission. Later submissions of the same command buffer will behave as if this configuration parameter is set to `0`. - 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. -- This configuration is incompatible with updating descriptors after binding. If any of the _UpdateAfterBind_ - feature flags of `VkPhysicalDeviceDescriptorIndexingFeatures` or `VkPhysicalDeviceInlineUniformBlockFeatures` +- This configuration 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 parameter will be ignored and treated as if it is `0`. @@ -375,11 +384,11 @@ For any value other than `0`, be aware of the following: ##### Type: Boolean ##### Default: `0` -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, +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 parameter is enabled, in the case of a `VK_ERROR_DEVICE_LOST` error that does NOT impact @@ -402,10 +411,10 @@ mark the `VkDevice` as lost, and subsequent use of that `VkDevice` will be reduc Pipeline cache compression is available for _macOS 10.15+_, and _iOS/tvOS 13.0+_. -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, +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. @@ -439,11 +448,11 @@ To have effect, this parameter requires _macOS 13.3+_, and has no effect on _iOS ##### Type: Boolean ##### Default: `0` -_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 it 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 +_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 it 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 @@ -522,8 +531,8 @@ system, and as a result, may want to disable this parameter. _(The default value is `0` for OS versions prior to macOS 10.14+/iOS 12+)._ If enabled, queue command submissions `vkQueueSubmit()` and `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 +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()`. @@ -547,18 +556,18 @@ Using a _Metal_ 2D texture allows _Vulkan_ 1D textures to support this additiona This parameter is ignored on Apple Silicon (Apple GPU) 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 +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 +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 +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 @@ -572,9 +581,9 @@ apps that query frequently may prefer higher volatility, to track more recent ch - `0`: No _Vulkan_ call logging. - `1`: Log the name of each _Vulkan_ call when the call is entered. - `2`: Log the name and thread ID of each _Vulkan_ call when the call is entered. -- `3`: Log the name of each _Vulkan_ call when the call is entered and exited. +- `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. -- `4`: Log the name and thread ID of each _Vulkan_ call when the call is entered, and name when exited. +- `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. - `5`: Same as `3`, plus logs the time spent inside the _Vulkan_ function. - `6`: Same as `4`, plus logs the time spent inside the _Vulkan_ function. @@ -593,7 +602,7 @@ Controls the information **MoltenVK** logs for each _Vulkan_ call made by the ap 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 +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. @@ -607,9 +616,9 @@ cleared via a call to the `vkTrimCommandPoolKHR()` command. ##### Default: `0` -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 +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. _**NOTE:**_ Currently, _Metal_ argument buffer support is in beta stage, and is only supported on _macOS 11.0+_, @@ -623,13 +632,13 @@ Development to support _iOS_ and _tvOS_ and a wider combination of GPU's on olde ##### Type: Boolean ##### Default: `0` -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. +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 parameter 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` +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. @@ -637,12 +646,12 @@ can occassionally cause corruption issues under certain circumstances. #### MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE ##### Type: Enumeration -- `0`: Limit _Vulkan_ to a single queue, with no explicit semaphore synchronization, and use _Metal's_ implicit +- `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. -- `1`: Use _Metal_ events (`MTLEvent`) when available on the platform, and where safe. This will revert to the same as `0` on some - _NVIDIA_ GPUs and _Rosetta2_, due to potential challenges with `MTLEvents` on those platforms, or in older environments where +- `1`: Use _Metal_ events (`MTLEvent`) when available on the platform, and where safe. This will revert to the same as `0` on some + _NVIDIA_ GPUs and _Rosetta2_, due to potential challenges with `MTLEvents` on those platforms, or in older environments where `MTLEvents` are not supported. -- `2`: Always use _Metal_ events (`MTLEvent`) when available on the platform. This will revert to the same as `0` in older +- `2`: Always use _Metal_ events (`MTLEvent`) when available on the platform. This will revert to the same as `0` in older environments where `MTLEvents` are not supported. - `3`: Use CPU callbacks upon GPU submission completion. This is the slowest technique, but allows multiple queues, compared to `0`. diff --git a/Docs/MoltenVK_Runtime_UserGuide.md b/Docs/MoltenVK_Runtime_UserGuide.md index 6a00edf3d..36329b5a4 100644 --- a/Docs/MoltenVK_Runtime_UserGuide.md +++ b/Docs/MoltenVK_Runtime_UserGuide.md @@ -46,7 +46,7 @@ About This Document This document describes how to integrate the **MoltenVK** runtime distribution package into a game or application, once **MoltenVK** has been built into a framework or library for *macOS*, *iOS*, or *tvOS*. -To learn how to use the **MoltenVK** open-source repository to build a **MoltenVK** runtime +To learn how to use the **MoltenVK** open-source repository to build a **MoltenVK** runtime distribution package, see the main [`README.md`](../README.md) document in the `MoltenVK` repository. @@ -55,20 +55,20 @@ distribution package, see the main [`README.md`](../README.md) document in the ` About **MoltenVK** ------------------ -**MoltenVK** is a layered implementation of [*Vulkan 1.2*](https://www.khronos.org/vulkan) -graphics and compute functionality, that is built on Apple's [*Metal*](https://developer.apple.com/metal) -graphics and compute framework on *macOS*, *iOS*, and *tvOS*. **MoltenVK** allows you to use *Vulkan* -graphics and compute functionality to develop modern, cross-platform, high-performance graphical games +**MoltenVK** is a layered implementation of [*Vulkan 1.2*](https://www.khronos.org/vulkan) +graphics and compute functionality, that is built on Apple's [*Metal*](https://developer.apple.com/metal) +graphics and compute framework on *macOS*, *iOS*, and *tvOS*. **MoltenVK** allows you to use *Vulkan* +graphics and compute functionality to develop modern, cross-platform, high-performance graphical games and applications, and to run them across many platforms, including *macOS*, *iOS*, *tvOS*, *Simulators*, and *Mac Catalyst* on *macOS 11.0+*. -*Metal* uses a different shading language, the *Metal Shading Language (MSL)*, than -*Vulkan*, which uses *SPIR-V*. **MoltenVK** automatically converts your *SPIR-V* shaders +*Metal* uses a different shading language, the *Metal Shading Language (MSL)*, than +*Vulkan*, which uses *SPIR-V*. **MoltenVK** automatically converts your *SPIR-V* shaders to their *MSL* equivalents. -To provide *Vulkan* capability to the *macOS*, *iOS*, and *tvOS* platforms, **MoltenVK** uses -*Apple's* publicly available API's, including *Metal*. **MoltenVK** does **_not_** use any -private or undocumented API calls or features, so your app will be compatible with all +To provide *Vulkan* capability to the *macOS*, *iOS*, and *tvOS* platforms, **MoltenVK** uses +*Apple's* publicly available API's, including *Metal*. **MoltenVK** does **_not_** use any +private or undocumented API calls or features, so your app will be compatible with all standard distribution channels, including *Apple's App Store*. @@ -78,56 +78,56 @@ Installing **MoltenVK** in Your *Vulkan* Application Installation of **MoltenVK** in your application is straightforward and easy! -Depending on your build and deployment needs, you can link **MoltenVK** to your application either -as a universal `XCFramework` or as a *dynamic library* (`.dylib`). Distributing an app containing -a dynamic library via the *iOS App Store* or *tvOS App Store* can require specialized bundling. -If you are unsure about which linking and deployment option you need, or on *iOS* or *tvOS*, -unless you have specific needs for dynamic libraries, follow the steps for linking **MoltenVK** +Depending on your build and deployment needs, you can link **MoltenVK** to your application either +as a universal `XCFramework` or as a *dynamic library* (`.dylib`). Distributing an app containing +a dynamic library via the *iOS App Store* or *tvOS App Store* can require specialized bundling. +If you are unsure about which linking and deployment option you need, or on *iOS* or *tvOS*, +unless you have specific needs for dynamic libraries, follow the steps for linking **MoltenVK** as an `XCFramework`, as it is the simpler option, and encompasses the largest set of supported platforms. ### Install *MoltenVK* as a Universal `XCFramework` -> ***Note:*** *Xcode 14* introduced a new static linkage model that is not compatible with previous -versions of *Xcode*. If you link to a `MoltenVK.xcframework` that was built with *Xcode 14* or later, -also use *Xcode 14* or later to link it to your app or game. +> ***Note:*** *Xcode 14* introduced a new static linkage model that is not compatible with previous +versions of *Xcode*. If you link to a `MoltenVK.xcframework` that was built with *Xcode 14* or later, +also use *Xcode 14* or later to link it to your app or game. > -> If you need to use *Xcode 13* or earlier to link `MoltenVK.xcframework` to your app or game, -first [build](../README.md#building) **MoltenVK** with *Xcode 13* or earlier. +> If you need to use *Xcode 13* or earlier to link `MoltenVK.xcframework` to your app or game, +first [build](../README.md#building) **MoltenVK** with *Xcode 13* or earlier. > -> Or, if you want to use *Xcode 14* or later to [build](../README.md#building) **MoltenVK**, in order to be able to use the latest -*Metal* capabilities, but need to use *Xcode 13* or earlier to link `MoltenVK.xcframework` to your -app or game, first add the value `-fno-objc-msgsend-selector-stubs` to the `OTHER_CFLAGS` -*Xcode* build setting in the `MoltenVK.xcodeproj` and `MoltenVKShaderConverter.xcodeproj` *Xcode* -projects, [build](../README.md#building) **MoltenVK** with *Xcode 14* or later, and then link `MoltenVK.xcframework` +> Or, if you want to use *Xcode 14* or later to [build](../README.md#building) **MoltenVK**, in order to be able to use the latest +*Metal* capabilities, but need to use *Xcode 13* or earlier to link `MoltenVK.xcframework` to your +app or game, first add the value `-fno-objc-msgsend-selector-stubs` to the `OTHER_CFLAGS` +*Xcode* build setting in the `MoltenVK.xcodeproj` and `MoltenVKShaderConverter.xcodeproj` *Xcode* +projects, [build](../README.md#building) **MoltenVK** with *Xcode 14* or later, and then link `MoltenVK.xcframework` to your app or game using *Xcode 13* or earlier. To link **MoltenVK** to your application as an `XCFramework`, follow these steps: -1. Open your application in *Xcode* and select your application's target in the +1. Open your application in *Xcode* and select your application's target in the *Project Navigator* panel. 2. Open the *Build Settings* tab. - 1. In the **Header Search Paths** (aka `HEADER_SEARCH_PATHS`) setting, + 1. In the **Header Search Paths** (aka `HEADER_SEARCH_PATHS`) setting, add an entry that points to the `MoltenVK/include` folder. - 2. If using `IOSurfaces` on *iOS*, open the **iOS Deployment Target** (aka `IPHONEOS_DEPLOYMENT_TARGET`) - setting, and ensure it is set to a value of `iOS 11.0` or greater, or if using `IOSurfaces` on *tvOS*, + 2. If using `IOSurfaces` on *iOS*, open the **iOS Deployment Target** (aka `IPHONEOS_DEPLOYMENT_TARGET`) + setting, and ensure it is set to a value of `iOS 11.0` or greater, or if using `IOSurfaces` on *tvOS*, open the **tvOS Deployment Target** (aka `TVOS_DEPLOYMENT_TARGET`) setting, and ensure it is set to a value of `tvOS 11.0` or greater. 3. Open the *Build Phases* tab and open the *Link Binary With Libraries* list. - + 1. Drag `MoltenVK/MoltenVK.xcframework` to the *Link Binary With Libraries* list. - 2. If your application does **_not_** use use `C++`, click the **+** button, - and add `libc++.tbd` by selecting it from the list of system frameworks. + 2. If your application does **_not_** use use `C++`, click the **+** button, + and add `libc++.tbd` by selecting it from the list of system frameworks. This is needed because **MoltenVK** uses `C++` system libraries internally. - - 3. If you do **_not_** have the **Link Frameworks Automatically** (aka `CLANG_MODULES_AUTOLINK`) and - **Enable Modules (C and Objective-C)** (aka `CLANG_ENABLE_MODULES`) settings enabled, click the + + 3. If you do **_not_** have the **Link Frameworks Automatically** (aka `CLANG_MODULES_AUTOLINK`) and + **Enable Modules (C and Objective-C)** (aka `CLANG_ENABLE_MODULES`) settings enabled, click the **+** button, and add the following items by selecting them from the list of system frameworks: - `libc++.tbd` *(if not already done in Step 2)* - `Metal.framework` @@ -135,7 +135,7 @@ To link **MoltenVK** to your application as an `XCFramework`, follow these steps - `QuartzCore.framework` - `IOKit.framework` (*macOS*) - `UIKit.framework` (*iOS* or *tvOS*) - - `IOSurface.framework` (*macOS*, or *iOS* if `IPHONEOS_DEPLOYMENT_TARGET` is at least `iOS 11.0`, + - `IOSurface.framework` (*macOS*, or *iOS* if `IPHONEOS_DEPLOYMENT_TARGET` is at least `iOS 11.0`, or *tvOS* if `TVOS_DEPLOYMENT_TARGET` is at least `tvOS 11.0`) @@ -145,50 +145,50 @@ To link **MoltenVK** to your application as an `XCFramework`, follow these steps To link **MoltenVK** to your application as a dynamic library (`.dylib`), follow these steps: -1. Open your application in *Xcode* and select your application's target in the +1. Open your application in *Xcode* and select your application's target in the *Project Navigator* panel. 2. Open the *Build Settings* tab. - 1. In the **Header Search Paths** (aka `HEADER_SEARCH_PATHS`) setting, + 1. In the **Header Search Paths** (aka `HEADER_SEARCH_PATHS`) setting, add an entry that points to the `MoltenVK/include` folder. - - 2. In the **Library Search Paths** (aka `LIBRARY_SEARCH_PATHS`) setting, + + 2. In the **Library Search Paths** (aka `LIBRARY_SEARCH_PATHS`) setting, add an entry that points to **_one_** of the following folders: - `MoltenVK/dylib/macOS` *(macOS)* - `MoltenVK/dylib/iOS` *(iOS)* - `MoltenVK/dylib/tvOS` *(tvOS)* - - 3. In the **Runpath Search Paths** (aka `LD_RUNPATH_SEARCH_PATHS`) setting, + + 3. In the **Runpath Search Paths** (aka `LD_RUNPATH_SEARCH_PATHS`) setting, add an entry that matches where the dynamic library will be located in your runtime - environment. If the dynamic library is to be embedded within your application, + environment. If the dynamic library is to be embedded within your application, you would typically set this to **_one_** of these values: - `@executable_path/../Frameworks` *(macOS)* - `@executable_path/Frameworks` *(iOS or tvOS)* - - The `libMoltenVK.dylib` library is internally configured to be located at + + The `libMoltenVK.dylib` library is internally configured to be located at `@rpath/libMoltenVK.dylib`. - 3. If using `IOSurfaces` on *iOS*, open the **iOS Deployment Target** (aka `IPHONEOS_DEPLOYMENT_TARGET`) - setting, and ensure it is set to a value of `iOS 11.0` or greater, or if using `IOSurfaces` on *tvOS*, + 3. If using `IOSurfaces` on *iOS*, open the **iOS Deployment Target** (aka `IPHONEOS_DEPLOYMENT_TARGET`) + setting, and ensure it is set to a value of `iOS 11.0` or greater, or if using `IOSurfaces` on *tvOS*, open the **tvOS Deployment Target** (aka `TVOS_DEPLOYMENT_TARGET`) setting, and ensure it is set to a value of `tvOS 11.0` or greater. 3. Open the *Build Phases* tab and open the *Link Binary With Libraries* list. - + 1. Drag **_one_** of the following files to the *Link Binary With Libraries* list: - - `MoltenVK/dylib/macOS/libMoltenVK.dylib` *(macOS)* - - `MoltenVK/dylib/iOS/libMoltenVK.dylib` *(iOS)* - - `MoltenVK/dylib/tvOS/libMoltenVK.dylib` *(tvOS)* + - `MoltenVK/dylib/macOS/libMoltenVK.dylib` *(macOS)* + - `MoltenVK/dylib/iOS/libMoltenVK.dylib` *(iOS)* + - `MoltenVK/dylib/tvOS/libMoltenVK.dylib` *(tvOS)* - 2. If your application does **_not_** use use `C++`, click the **+** button, - and add `libc++.tbd` by selecting it from the list of system frameworks. + 2. If your application does **_not_** use use `C++`, click the **+** button, + and add `libc++.tbd` by selecting it from the list of system frameworks. This is needed because **MoltenVK** uses `C++` system libraries internally. - - 3. If you do **_not_** have the **Link Frameworks Automatically** (aka `CLANG_MODULES_AUTOLINK`) and - **Enable Modules (C and Objective-C)** (aka `CLANG_ENABLE_MODULES`) settings enabled, click the + + 3. If you do **_not_** have the **Link Frameworks Automatically** (aka `CLANG_MODULES_AUTOLINK`) and + **Enable Modules (C and Objective-C)** (aka `CLANG_ENABLE_MODULES`) settings enabled, click the **+** button, and add the following items by selecting them from the list of system frameworks: - `libc++.tbd` *(if not already done in Step 2)* - `Metal.framework` @@ -196,30 +196,30 @@ To link **MoltenVK** to your application as a dynamic library (`.dylib`), follow - `QuartzCore.framework` - `IOKit.framework` (*macOS*) - `UIKit.framework` (*iOS* or *tvOS*) - - `IOSurface.framework` (*macOS*, or *iOS* if `IPHONEOS_DEPLOYMENT_TARGET` is at least `iOS 11.0`, + - `IOSurface.framework` (*macOS*, or *iOS* if `IPHONEOS_DEPLOYMENT_TARGET` is at least `iOS 11.0`, or *tvOS* if `TVOS_DEPLOYMENT_TARGET` is at least `tvOS 11.0`) 4. Arrange to install the `libMoltenVK.dylib` file in your application environment: - To copy the `libMoltenVK.dylib` file into your application or component library: - + 1. On the *Build Phases* tab, add a new *Copy Files* build phase. - + 2. Set the *Destination* into which you want to place the `libMoltenVK.dylib` file. - Typically this will be *Frameworks* (and it should match the **Runpath Search Paths** + Typically this will be *Frameworks* (and it should match the **Runpath Search Paths** (aka `LD_RUNPATH_SEARCH_PATHS`) build setting you added above). - + 3. Drag **_one_** of the following files to the *Copy Files* list in this new build phase: - - `MoltenVK/dylib/macOS/libMoltenVK.dylib` *(macOS)* - - `MoltenVK/dylib/iOS/libMoltenVK.dylib` *(iOS)* - - `MoltenVK/dylib/tvOS/libMoltenVK.dylib` *(tvOS)* - - - Alternately, you may create your own installation mechanism to install one of the following + - `MoltenVK/dylib/macOS/libMoltenVK.dylib` *(macOS)* + - `MoltenVK/dylib/iOS/libMoltenVK.dylib` *(iOS)* + - `MoltenVK/dylib/tvOS/libMoltenVK.dylib` *(tvOS)* + + - Alternately, you may create your own installation mechanism to install one of the following files into a standard *macOS*, *iOS*, or *tvOS* system library folder on the user's device: - - `MoltenVK/dylib/macOS/libMoltenVK.dylib` *(macOS)* - - `MoltenVK/dylib/iOS/libMoltenVK.dylib` *(iOS)* - - `MoltenVK/dylib/tvOS/libMoltenVK.dylib` *(tvOS)* - + - `MoltenVK/dylib/macOS/libMoltenVK.dylib` *(macOS)* + - `MoltenVK/dylib/iOS/libMoltenVK.dylib` *(iOS)* + - `MoltenVK/dylib/tvOS/libMoltenVK.dylib` *(tvOS)* + ### Install *MoltenVK* replacing the Vulkan SDK `libMoltenVK.dylib` @@ -261,33 +261,33 @@ $ make macos MVK_CONFIG_LOG_LEVEL=1 **MoltenVK** references the latest *Apple SDK* frameworks. To access these frameworks when building your app, and to avoid build errors, be sure to use the latest publicly available version of *Xcode*. ->***Note:*** To support `IOSurfaces` on *iOS* or *tvOS*, any app that uses **MoltenVK** must be -built with a minimum **iOS Deployment Target** (aka `IPHONEOS_DEPLOYMENT_TARGET `) build setting +>***Note:*** To support `IOSurfaces` on *iOS* or *tvOS*, any app that uses **MoltenVK** must be +built with a minimum **iOS Deployment Target** (aka `IPHONEOS_DEPLOYMENT_TARGET `) build setting of `iOS 11.0` or greater, or a minimum **tvOS Deployment Target** (aka `TVOS_DEPLOYMENT_TARGET `) build setting of `tvOS 11.0` or greater. -Once built, your app integrating the **MoltenVK** libraries can be run on *macOS*, *iOS* or *tvOS* +Once built, your app integrating the **MoltenVK** libraries can be run on *macOS*, *iOS* or *tvOS* devices that support *Metal*, or on the *Xcode* *iOS Simulator* or *tvOS Simulator*. -- At runtime, **MoltenVK** requires at least *macOS 10.11*, *iOS 9*, or *tvOS 9* +- At runtime, **MoltenVK** requires at least *macOS 10.11*, *iOS 9*, or *tvOS 9* (or *iOS 11* or *tvOS 11* if using `IOSurfaces`). -- Information on *macOS* devices that are compatible with *Metal* can be found in +- Information on *macOS* devices that are compatible with *Metal* can be found in [this article](http://www.idownloadblog.com/2015/06/22/how-to-find-mac-el-capitan-metal-compatible). -- Information on *iOS* devices that are compatible with *Metal* can be found in +- Information on *iOS* devices that are compatible with *Metal* can be found in [this article](https://developer.apple.com/library/content/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/HardwareGPUInformation/HardwareGPUInformation.html). -When a *Metal* app is running from *Xcode*, the default ***Scheme*** settings may reduce performance. +When a *Metal* app is running from *Xcode*, the default ***Scheme*** settings may reduce performance. To improve performance and gain the benefits of *Metal*, perform the following in *Xcode*: -1. Open the ***Scheme Editor*** for building your main application. You can do - this by selecting ***Edit Scheme...*** from the ***Scheme*** drop-down menu, or select +1. Open the ***Scheme Editor*** for building your main application. You can do + this by selecting ***Edit Scheme...*** from the ***Scheme*** drop-down menu, or select ***Product -> Scheme -> Edit Scheme...*** from the main menu. -2. On the ***Info*** tab, set the ***Build Configuration*** to ***Release***, and disable the +2. On the ***Info*** tab, set the ***Build Configuration*** to ***Release***, and disable the ***Debug executable*** check-box. 3. On the ***Options*** tab, disable both the ***Metal API Validation*** and ***GPU Frame Capture*** options. For optimal performance, you may also consider disabling the other simulation - and debugging options on this tab. For further information, see the - [Xcode Scheme Settings and Performance](https://developer.apple.com/library/ios/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Dev-Technique/Dev-Technique.html#//apple_ref/doc/uid/TP40014221-CH8-SW3) + and debugging options on this tab. For further information, see the + [Xcode Scheme Settings and Performance](https://developer.apple.com/library/ios/documentation/Miscellaneous/Conceptual/MetalProgrammingGuide/Dev-Technique/Dev-Technique.html#//apple_ref/doc/uid/TP40014221-CH8-SW3) section of Apple's *Metal Programming Guide* documentation. @@ -296,13 +296,13 @@ To improve performance and gain the benefits of *Metal*, perform the following i Interacting with the **MoltenVK** Runtime ----------------------------------------- -You programmatically configure and interact with the **MoltenVK** runtime through function +You programmatically configure and interact with the **MoltenVK** runtime through function calls, enumeration values, and capabilities, in exactly the same way you do with other -*Vulkan* implementations. **MoltenVK** contains several header files that define access +*Vulkan* implementations. **MoltenVK** contains several header files that define access to *Vulkan* and **MoltenVK** function calls. -In your application code, you access *Vulkan* features through the API defined in the standard -`vulkan.h` header file. This file is included in the **MoltenVK** framework, and can be included +In your application code, you access *Vulkan* features through the API defined in the standard +`vulkan.h` header file. This file is included in the **MoltenVK** framework, and can be included in your source code files as follows: #include @@ -367,9 +367,9 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_debug_marker` - `VK_EXT_debug_report` - `VK_EXT_debug_utils` -- `VK_EXT_descriptor_indexing` - - *Initial release limited to Metal Tier 1: 96/128 textures, - 16 samplers, except macOS 11.0 (Big Sur) or later, or on older versions of macOS using +- `VK_EXT_descriptor_indexing` + - *Initial release limited to Metal Tier 1: 96/128 textures, + 16 samplers, except macOS 11.0 (Big Sur) or later, or on older versions of macOS using an Intel GPU, and if Metal argument buffers enabled in config.* - `VK_EXT_extended_dynamic_state` - *Requires Metal 3.1 for `VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE`.* @@ -393,20 +393,20 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_EXT_metal_surface` - `VK_EXT_pipeline_creation_cache_control` - `VK_EXT_pipeline_creation_feedback` -- `VK_EXT_post_depth_coverage` +- `VK_EXT_post_depth_coverage` - *iOS and macOS, requires family 4 (A11) or better Apple GPU.* - `VK_EXT_private_data ` - `VK_EXT_robustness2` - `VK_EXT_sample_locations` - `VK_EXT_scalar_block_layout` - `VK_EXT_separate_stencil_usage` -- `VK_EXT_shader_atomic_float` +- `VK_EXT_shader_atomic_float` - *Requires Metal 3.0.* -- `VK_EXT_shader_demote_to_helper_invocation` +- `VK_EXT_shader_demote_to_helper_invocation` - *Requires Metal Shading Language 2.3.* - `VK_EXT_shader_stencil_export` - *Requires Mac GPU family 2 or iOS GPU family 5.* -- `VK_EXT_shader_subgroup_ballot` +- `VK_EXT_shader_subgroup_ballot` - *Requires Mac GPU family 2 or Apple GPU family 4.* - `VK_EXT_shader_subgroup_vote` - *Requires Mac GPU family 2 or Apple GPU family 4.* @@ -421,9 +421,9 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - *Requires Metal 2.0.* - `VK_EXT_texture_compression_astc_hdr` - *iOS and macOS, requires family 6 (A13) or better Apple GPU.* -- `VK_MVK_ios_surface` +- `VK_MVK_ios_surface` - *Obsolete. Use `VK_EXT_metal_surface` instead.* -- `VK_MVK_macos_surface` +- `VK_MVK_macos_surface` - *Obsolete. Use `VK_EXT_metal_surface` instead.* - `VK_AMD_gpu_shader_half_float` - `VK_AMD_negative_viewport_height` @@ -439,44 +439,44 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll - `VK_NV_glsl_shader` In order to visibly display your content on *macOS*, *iOS*, or *tvOS*, you must enable the -`VK_EXT_metal_surface` extension, and use the function defined in that extension to create a -*Vulkan* rendering surface. You can enable the `VK_EXT_metal_surface` extension by defining -the `VK_USE_PLATFORM_METAL_EXT` guard macro in your compiler build settings. See the description +`VK_EXT_metal_surface` extension, and use the function defined in that extension to create a +*Vulkan* rendering surface. You can enable the `VK_EXT_metal_surface` extension by defining +the `VK_USE_PLATFORM_METAL_EXT` guard macro in your compiler build settings. See the description of the `mvk_vulkan.h` file below for a convenient way to enable this extension automatically. -When creating a `CAMetalLayer` to underpin the *Vulkan* surface to render to, it is strongly -recommended that you ensure the `delegate` of the `CAMetalLayer` is the `NSView/UIView` in -which the layer is contained, to ensure correct and optimized *Vulkan* swapchain and refresh +When creating a `CAMetalLayer` to underpin the *Vulkan* surface to render to, it is strongly +recommended that you ensure the `delegate` of the `CAMetalLayer` is the `NSView/UIView` in +which the layer is contained, to ensure correct and optimized *Vulkan* swapchain and refresh timing behavior across multiple display screens that might have different properties. -The view will automatically be the `delegate` of the layer when the view creates the +The view will automatically be the `delegate` of the layer when the view creates the `CAMetalLayer`, as per Apple's documentation: ->If the layer object was created by a view, the view typically assigns itself as the layer’s -delegate automatically, and you should not change that relationship. For layers you create -yourself, you can assign a delegate object and use that object to provide the contents of +>If the layer object was created by a view, the view typically assigns itself as the layer’s +delegate automatically, and you should not change that relationship. For layers you create +yourself, you can assign a delegate object and use that object to provide the contents of the layer dynamically and perform other tasks. -But in the case where you create the `CAMetalLayer` yourself and assign it to the view, -you should also assign the view as the `delegate` of the layer. +But in the case where you create the `CAMetalLayer` yourself and assign it to the view, +you should also assign the view as the `delegate` of the layer. -Because **MoltenVK** supports the `VK_KHR_portability_subset` extension, when using the -*Vulkan Loader* from the *Vulkan SDK* to run **MoltenVK** on *macOS*, the *Vulkan Loader* -will only include **MoltenVK** `VkPhysicalDevices` in the list returned by -`vkEnumeratePhysicalDevices()` if the `VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` -flag is enabled in `vkCreateInstance()`. See the description of the `VK_KHR_portability_enumeration` -extension in the *Vulkan* specification for more information about the use of the +Because **MoltenVK** supports the `VK_KHR_portability_subset` extension, when using the +*Vulkan Loader* from the *Vulkan SDK* to run **MoltenVK** on *macOS*, the *Vulkan Loader* +will only include **MoltenVK** `VkPhysicalDevices` in the list returned by +`vkEnumeratePhysicalDevices()` if the `VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` +flag is enabled in `vkCreateInstance()`. See the description of the `VK_KHR_portability_enumeration` +extension in the *Vulkan* specification for more information about the use of the `VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` flag. ### MoltenVK Header Files -**MoltenVK** provides additional functionality beyond standard *Vulkan* functionality, -to support configuration options and query behaviour that is specific to the **MoltenVK** +**MoltenVK** provides additional functionality beyond standard *Vulkan* functionality, +to support configuration options and query behaviour that is specific to the **MoltenVK** implementation of *Vulkan* functionality. -The following API header files are included in the **MoltenVK** package, each of which +The following API header files are included in the **MoltenVK** package, each of which can be included in your application source code as follows: #include @@ -485,52 +485,55 @@ where `HEADER_FILE` is one of the following: - `mvk_vulkan.h` - This is a convenience header file that loads the `` header file with platform settings to enable the appropriate _Vulkan_ WSI surface and portability extensions. - -- `mvk_private_api.h` - Contains private structures and functions to query **MoltenVK** about - **MoltenVK** version and configuration, runtime performance information, and available - _Metal_ capabilities. - > _**NOTE:**_ THE FUNCTIONS in `mvk_private_api.h` ARE NOT SUPPORTED BY THE _Vulkan Loader + +- `mvk_private_api.h` - Contains private structures and functions to query **MoltenVK** about + **MoltenVK** version and configuration, runtime performance information, and available + _Metal_ capabilities. + > _**NOTE:**_ THE FUNCTIONS in `mvk_private_api.h` ARE NOT SUPPORTED BY THE _Vulkan Loader and Layers_, AND CAN ONLY BE USED WHEN **MoltenVK** IS LINKED DIRECTLY TO YOUR APPLICATION. -- `mvk_datatypes.h` - Contains helpful functions for converting between *Vulkan* and *Metal* - data types. You do not need to use this functionality to use **MoltenVK**, as **MoltenVK** - converts between *Vulkan* and *Metal* datatypes automatically (using the functions declared - in this header). These functions are exposed in this header as a convienience for your own +- `mvk_datatypes.h` - Contains helpful functions for converting between *Vulkan* and *Metal* + data types. You do not need to use this functionality to use **MoltenVK**, as **MoltenVK** + converts between *Vulkan* and *Metal* datatypes automatically (using the functions declared + in this header). These functions are exposed in this header as a convienience for your own purposes such as interacting with *Metal* directly, or simply logging data values. ### Configuring MoltenVK -**MoltenVK** provides the ability to configure and optimize **MoltenVK** for your particular -application runtime requirements and development-time needs. +**MoltenVK** provides the ability to configure and optimize **MoltenVK** for your particular +application runtime requirements and development-time needs. -At runtime, configuration can be helpful in situtations where _Metal_ behavior is different -than _Vulkan_ behavior, and the results or performance you receive can depend on how **MoltenVK** -works around those differences, which, in turn, may depend on how you are using _Vulkan_. +At runtime, configuration can be helpful in situtations where _Metal_ behavior is different +than _Vulkan_ behavior, and the results or performance you receive can depend on how **MoltenVK** +works around those differences, which, in turn, may depend on how you are using _Vulkan_. Different apps might benefit differently in this handling. Additional configuration parameters can be helpful at development time by providing you with additional tracing, debugging, and performance measuring capabilities. -Each configuration parameter has a *name* and *value*, and can be passed to **MoltenVK** +Each configuration parameter has a *name* and *value*, and can be passed to **MoltenVK** via any of the following mechanisms: - The standard _Vulkan_ `VK_EXT_layer_settings` extension. - Application runtime environment variables. - Build settings at **MoltenVK** build time. -Parameter values configured by build settings at **MoltenVK** build time can be overridden -by values set by environment variables, which, in turn, can be overridden during `VkInstance` -creation via the Vulkan `VK_EXT_layer_settings` extension. +Parameter values configured by build settings at **MoltenVK** build time can be overridden +by values set by environment variables, which, in turn, can be overridden during `VkInstance` +creation via the _Vulkan_ `VK_EXT_layer_settings` extension. + +Using the `VK_EXT_layer_settings` extension is the preferred mechanism, as it is a standard +_Vulkan_ extension, and is supported by the _Vulkan_ loader and layers. When using the +`VK_EXT_layer_settings` extension, set `VkLayerSettingEXT::pLayerName` to the value of +`kMVKMoltenVKDriverLayerName` found in the `mvk_vulkan.h` header (or simply to `"MoltenVK"`). -Using the `VK_EXT_layer_settings` extension is the preferred mechanism, as it is a standard -_Vulkan_ extension, and is supported by the _Vulkan_ loader and layers. Using environment -variables can be a convinient mechanism to modify configuration parameters during runtime -debugging in the field (if the settings are *not* overridden during `VkInstance` creation -via the _Vulkan_ `VK_EXT_layer_settings` extension). +Using environment variables can be a convinient mechanism to modify configuration parameters +during runtime debugging in the field (if the settings are *not* overridden during `VkInstance` +creation via the _Vulkan_ `VK_EXT_layer_settings` extension). -A description of each configuration parameter supported by **MoltenVK** can be found in the +A description of each configuration parameter supported by **MoltenVK** can be found in the [`MoltenVK_Configuration_Parameters.md`](MoltenVK_Configuration_Parameters.md) document in the `Docs` directory. @@ -538,10 +541,10 @@ A description of each configuration parameter supported by **MoltenVK** can be f *Metal Shading Language* Shaders -------------------------------- -*Metal* uses a different shader language than *Vulkan*. *Vulkan* uses the new +*Metal* uses a different shader language than *Vulkan*. *Vulkan* uses the new *SPIR-V Shading Language (SPIR-V)*, whereas *Metal* uses the *Metal Shading Language (MSL)*. -**MoltenVK** uses **Runtime Shader Conversion** to automatically convert your *SPIR-V* shaders -to their *MSL* equivalents, during loading your *SPIR-V* shaders, using the standard *Vulkan* +**MoltenVK** uses **Runtime Shader Conversion** to automatically convert your *SPIR-V* shaders +to their *MSL* equivalents, during loading your *SPIR-V* shaders, using the standard *Vulkan* `vkCreateShaderModule()` function. @@ -549,27 +552,27 @@ to their *MSL* equivalents, during loading your *SPIR-V* shaders, using the stan ### Troubleshooting Shader Conversion -The shader converter technology in **MoltenVK** is quite robust, and most *SPIR-V* shaders -can be converted to *MSL* without any problems. In the case where a conversion issue arises, +The shader converter technology in **MoltenVK** is quite robust, and most *SPIR-V* shaders +can be converted to *MSL* without any problems. In the case where a conversion issue arises, 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 logging - the *SPIR-V* and *MSL* shader source code during shader conversion, by enabing the `MVK_CONFIG_DEBUG` +- To help understand conversion issues during **Runtime Shader Conversion**, you can enable logging + the *SPIR-V* and *MSL* shader source code during shader conversion, by enabing the `MVK_CONFIG_DEBUG` configuration parameter. See the [*MoltenVK Configuration*](#moltenvk_config) description above. - Enabling debug mode in **MoltenVK** includes shader conversion logging, which causes both - the incoming *SPIR-V* code and the converted *MSL* source code to be logged to the console - in human-readable form. This allows you to manually verify the conversions, and can help + Enabling debug mode in **MoltenVK** includes shader conversion logging, which causes both + the incoming *SPIR-V* code and the converted *MSL* source code to be logged to the console + in human-readable form. This allows you to manually verify the conversions, and can help you diagnose issues that might occur during shader conversion. -- For some issues, you may be able to adjust your *SPIR-V* code so that it behaves the same +- For some issues, you may be able to adjust your *SPIR-V* code so that it behaves the same under *Vulkan*, but is easier to automatically convert to *MSL*. -- You are also encouraged to report issues with shader conversion to the - [*SPIRV-Cross*](https://github.com/KhronosGroup/SPIRV-Cross/issues) project. **MoltenVK** and - **MoltenVKShaderConverter** make use of *SPIRV-Cross* to convert *SPIR-V* shaders to *MSL* shaders. +- You are also encouraged to report issues with shader conversion to the + [*SPIRV-Cross*](https://github.com/KhronosGroup/SPIRV-Cross/issues) project. **MoltenVK** and + **MoltenVKShaderConverter** make use of *SPIRV-Cross* to convert *SPIR-V* shaders to *MSL* shaders. @@ -583,22 +586,22 @@ This section discusses various options for improving performance when using **Mo ### Shader Loading Time -A number of steps is required to load and compile *SPIR-V* shaders into a form that *Metal* can use. +A number of steps is required to load and compile *SPIR-V* shaders into a form that *Metal* can use. Although the overall process is fast, the slowest step involves converting shaders from *SPIR-V* to *MSL* source code format. If you have a lot of shaders, you can dramatically improve shader loading time by using the standard *Vulkan pipeline cache* feature, to serialize shaders and store them in *MSL* form offline. -Loading *MSL* shaders via the pipeline cache serializing mechanism can be significantly faster than +Loading *MSL* shaders via the pipeline cache serializing mechanism can be significantly faster than converting from *SPIR-V* to *MSL* each time. -In *Vulkan*, pipeline cache serialization for offline storage is available through the -`vkGetPipelineCacheData()` and `vkCreatePipelineCache()` functions. Loading the pipeline cache -from offline storage at app start-up time can dramatically improve both shader loading performance, +In *Vulkan*, pipeline cache serialization for offline storage is available through the +`vkGetPipelineCacheData()` and `vkCreatePipelineCache()` functions. Loading the pipeline cache +from offline storage at app start-up time can dramatically improve both shader loading performance, and performance glitches and hiccups during runtime code if shader loading is performed then. -When using pipeline caching, nothing changes about how you load *SPIR-V* shader code. **MoltenVK** -automatically detects that the *SPIR-V* was previously converted to *MSL*, and stored offline via +When using pipeline caching, nothing changes about how you load *SPIR-V* shader code. **MoltenVK** +automatically detects that the *SPIR-V* was previously converted to *MSL*, and stored offline via the *Vulkan* pipeline cache serialization mechanism, and does not invoke the relatively expensive step of converting the *SPIR-V* to *MSL* again. @@ -610,13 +613,13 @@ step of converting the *SPIR-V* to *MSL* again. sometimes hold onto these images during surface presentation. **MoltenVK** supports using either 2 or 3 swapchain images. For best performance, it is recommended -that you use 3 swapchain images (triple-buffering), to ensure that at least one swapchain image will -be available when you need to render to it. +that you use 3 swapchain images (triple-buffering), to ensure that at least one swapchain image will +be available when you need to render to it. -Using 3 swapchain images is particularly important when rendering to a full-screen surface, because +Using 3 swapchain images is particularly important when rendering to a full-screen surface, because in that situation, *Metal* uses its *Direct to Display* feature, and avoids compositing the swapchain -image onto a separate composition surface before displaying it. Although *Direct to Display* can improve -performance throughput, it also means that *Metal* may hold onto each swapchain image a little longer +image onto a separate composition surface before displaying it. Although *Direct to Display* can improve +performance throughput, it also means that *Metal* may hold onto each swapchain image a little longer than when using an internal compositor, which increases the risk that a swapchain image will not be a vailable when you request it, resulting in frame delays and visual stuttering. @@ -624,21 +627,21 @@ vailable when you request it, resulting in frame delays and visual stuttering. ### Timestamping -On non-Apple GPUs (older Mac devices), the GPU can switch power and performance states as -required by usage. This affects the GPU timestamps retrievable through the Vulkan API. -As a result, the value of `VkPhysicalDeviceLimits::timestampPeriod` can vary over time. +On non-Apple GPUs (older Mac devices), the GPU can switch power and performance states as +required by usage. This affects the GPU timestamps retrievable through the Vulkan API. +As a result, the value of `VkPhysicalDeviceLimits::timestampPeriod` can vary over time. Consider calling `vkGetPhysicalDeviceProperties()`, when needed, and retrieve the current -value of `VkPhysicalDeviceLimits::timestampPeriod`, to help you calibrate recent GPU +value of `VkPhysicalDeviceLimits::timestampPeriod`, to help you calibrate recent GPU timestamps queried through the Vulkan API. -This is not needed on Apple Silicon devices, where all GPU timestamps are always returned +This is not needed on Apple Silicon devices, where all GPU timestamps are always returned as nanoseconds, regardless of variations in power and performance states as the app runs. ### Xcode Configuration -When a *Metal* app is running from *Xcode*, the default ***Scheme*** settings reduce performance. +When a *Metal* app is running from *Xcode*, the default ***Scheme*** settings reduce performance. Be sure to follow the instructions for configuring your application's ***Scheme*** within *Xcode*, found in the in the [installation](#install) section above. @@ -646,7 +649,7 @@ found in the in the [installation](#install) section above. ### Metal System Trace Tool -To help you get the best performance from your graphics app, the *Xcode Instruments* profiling tool +To help you get the best performance from your graphics app, the *Xcode Instruments* profiling tool includes the *Metal System Trace* template. This template can be used to provide detailed tracing of the CPU and GPU behaviour of your application, allowing you unprecedented performance measurement and tuning capabilities for apps using *Metal*. @@ -658,28 +661,28 @@ Known **MoltenVK** Limitations ------------------------------ This section documents the known limitations in this version of **MoltenVK**. - + - See [above](#interaction) for known limitations for specific Vulkan extensions. - On *macOS* versions prior to *macOS 10.15.6*, native host-coherent image device memory is not available. - Because of this, changes made to `VkImage VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` device memory by the CPU - or GPU will not be available to the GPU or CPU, respectively, until the memory is flushed or unmapped by - the application. Applications using `vkMapMemory()` with `VkImage VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` + Because of this, changes made to `VkImage VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` device memory by the CPU + or GPU will not be available to the GPU or CPU, respectively, until the memory is flushed or unmapped by + the application. Applications using `vkMapMemory()` with `VkImage VK_MEMORY_PROPERTY_HOST_COHERENT_BIT` device memory on *macOS* versions prior to *macOS 10.15.6* must call either `vkUnmapMemory()`, or - `vkFlushMappedMemoryRanges()` / `vkInvalidateMappedMemoryRanges()` to ensure memory changes are coherent - between the CPU and GPU. This limitation does **_not_** apply to `VKImage` device memory on *macOS* - starting with *macOS 10.15.6*, does not apply to `VKImage` device memory on any version of *iOS* or *tvOS*, + `vkFlushMappedMemoryRanges()` / `vkInvalidateMappedMemoryRanges()` to ensure memory changes are coherent + between the CPU and GPU. This limitation does **_not_** apply to `VKImage` device memory on *macOS* + starting with *macOS 10.15.6*, does not apply to `VKImage` device memory on any version of *iOS* or *tvOS*, and does **_not_** apply to `VKBuffer` device memory on any platform. -- Image content in `PVRTC` compressed formats must be loaded directly into a `VkImage` using - host-visible memory mapping. Loading via a staging buffer will result in malformed image content. +- Image content in `PVRTC` compressed formats must be loaded directly into a `VkImage` using + host-visible memory mapping. Loading via a staging buffer will result in malformed image content. - Pipeline statistics query pool using `VK_QUERY_TYPE_PIPELINE_STATISTICS` is not supported. - Application-controlled memory allocations using `VkAllocationCallbacks` are ignored. -- Since **MoltenVK** is an implementation of *Vulkan* functionality, it does not load - *Vulkan Layers* on its own. In order to use *Vulkan Layers*, such as the validation layers, - use the *Vulkan Loader and Layers* from the *[Vulkan SDK](https://vulkan.lunarg.com/sdk/home)*. - Refer to the *Vulkan SDK [Getting Started](https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html)* +- Since **MoltenVK** is an implementation of *Vulkan* functionality, it does not load + *Vulkan Layers* on its own. In order to use *Vulkan Layers*, such as the validation layers, + use the *Vulkan Loader and Layers* from the *[Vulkan SDK](https://vulkan.lunarg.com/sdk/home)*. + Refer to the *Vulkan SDK [Getting Started](https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html)* document for more info. diff --git a/MoltenVK/MoltenVK/API/mvk_config.h b/MoltenVK/MoltenVK/API/mvk_config.h index b1e423fe7..8b815fc16 100644 --- a/MoltenVK/MoltenVK/API/mvk_config.h +++ b/MoltenVK/MoltenVK/API/mvk_config.h @@ -35,7 +35,7 @@ extern "C" { * To configure MoltenVK, use one of the following mechanisms, * as documented in MoltenVK_Configuration_Parameters.md: * - * - The standard Vulkan VK_EXT_layer_settings extension. + * - The standard Vulkan VK_EXT_layer_settings extension (layer name "MoltenVK"). * - Application runtime environment variables. * - Build settings at MoltenVK build time. * diff --git a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h index 1aea704f2..e2faf5b16 100644 --- a/MoltenVK/MoltenVK/API/mvk_deprecated_api.h +++ b/MoltenVK/MoltenVK/API/mvk_deprecated_api.h @@ -78,11 +78,11 @@ typedef void (VKAPI_PTR *PFN_vkGetMTLCommandQueueMVK)(VkQueue queue, id +/** The name of the MoltenVK driver layer. */ +static const char* kMVKMoltenVKDriverLayerName = "MoltenVK"; + #endif diff --git a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h index d0b2cef13..deec23a21 100644 --- a/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h +++ b/MoltenVK/MoltenVK/API/vk_mvk_moltenvk.h @@ -28,7 +28,7 @@ * To configure MoltenVK, use one of the following mechanisms, * as documented in MoltenVK_Configuration_Parameters.md: * - * - The standard Vulkan VK_EXT_layer_settings extension. + * - The standard Vulkan VK_EXT_layer_settings extension (layer name "MoltenVK"). * - Application runtime environment variables. * - Build settings at MoltenVK build time. * diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index f1b4f2a27..3b08b14d9 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -533,7 +533,7 @@ supportedProps12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES; supportedProps12.pNext = nullptr; supportedProps12.driverID = VK_DRIVER_ID_MOLTENVK; - strcpy(supportedProps12.driverName, "MoltenVK"); + strcpy(supportedProps12.driverName, kMVKMoltenVKDriverLayerName); strcpy(supportedProps12.driverInfo, mvkGetMoltenVKVersionString(MVK_VERSION).c_str()); supportedProps12.conformanceVersion.major = 0; supportedProps12.conformanceVersion.minor = 0; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h index da63fea45..491505d40 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.h @@ -72,7 +72,7 @@ class MVKInstance : public MVKDispatchableVulkanAPIObject { MVKInstance* getInstance() override { return this; } /** Return the MoltenVK configuration info for this VkInstance. */ - const MVKConfiguration& getMVKConfig() override { return _enabledExtensions.vk_EXT_layer_settings.enabled ? _mvkConfig : mvkConfig(); } + const MVKConfiguration& getMVKConfig() override { return _enabledExtensions.vk_EXT_layer_settings.enabled ? _mvkConfig : getGlobalMVKConfig(); } /** Returns the maximum version of Vulkan the application supports. */ inline uint32_t getAPIVersion() { return _appInfo.apiVersion; } @@ -204,7 +204,7 @@ class MVKInstance : public MVKDispatchableVulkanAPIObject { MVKSmallVector _debugReportCallbacks; MVKSmallVector _debugUtilMessengers; std::unordered_map _entryPoints; - std::string _autoGPUCaptureOutputFilepath; + std::string _mvkConfigStringHolders[kMVKConfigurationStringCount] = {}; std::mutex _dcbLock; bool _hasDebugReportCallbacks; bool _hasDebugUtilsMessengers; diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm index 0e5b2c6d8..c0d4e1979 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKInstance.mm @@ -352,7 +352,7 @@ if ( !_enabledExtensions.vk_EXT_layer_settings.enabled ) { return; } - _mvkConfig = mvkConfig(); + _mvkConfig = getGlobalMVKConfig(); VkLayerSettingsCreateInfoEXT* pLSCreateInfo = nil; for (const auto* next = (VkBaseInStructure*)pCreateInfo->pNext; next; next = next->pNext) { @@ -379,7 +379,7 @@ } #include "MVKConfigMembers.def" } - mvkSetConfig(_mvkConfig, _mvkConfig, _autoGPUCaptureOutputFilepath); + mvkSetConfig(_mvkConfig, _mvkConfig, _mvkConfigStringHolders); } #define ADD_ENTRY_POINT_MAP(name, func, api, ext1, ext2, isDev) \ diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm index 50e4601fe..50c5d462e 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKSync.mm @@ -582,7 +582,7 @@ VkResult mvkWaitSemaphores(MVKDevice* device, if ( !_isCompileDone ) { @autoreleasepool { NSString* errDesc = [NSString stringWithFormat: @"Timeout after %.3f milliseconds. Likely internal Metal compiler error", (double)nanoTimeout.count() / 1e6]; - _compileError = [[NSError alloc] initWithDomain: @"MoltenVK" code: 1 userInfo: @{NSLocalizedDescriptionKey : errDesc}]; // retained + _compileError = [[NSError alloc] initWithDomain: @(kMVKMoltenVKDriverLayerName) code: 1 userInfo: @{NSLocalizedDescriptionKey : errDesc}]; // retained } } diff --git a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm index 11f98b49e..6f6c2cabd 100644 --- a/MoltenVK/MoltenVK/Layers/MVKExtensions.mm +++ b/MoltenVK/MoltenVK/Layers/MVKExtensions.mm @@ -50,7 +50,7 @@ static bool mvkIsSupportedOnPlatform(VkExtensionProperties* pProperties) { // If the config indicates that not all supported extensions should be advertised, // only advertise those supported extensions that have been specifically configured. - auto advExtns = mvkConfig().advertiseExtensions; + auto advExtns = getGlobalMVKConfig().advertiseExtensions; if ( !mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_ALL) ) { #define MVK_NA kMVKOSVersionUnsupported if (mvkIsAnyFlagEnabled(advExtns, MVK_CONFIG_ADVERTISE_EXTENSIONS_WSI)) { diff --git a/MoltenVK/MoltenVK/Layers/MVKLayers.mm b/MoltenVK/MoltenVK/Layers/MVKLayers.mm index 237017dc3..b58994137 100644 --- a/MoltenVK/MoltenVK/Layers/MVKLayers.mm +++ b/MoltenVK/MoltenVK/Layers/MVKLayers.mm @@ -40,7 +40,7 @@ // The core driver layer mvkClear(_layerProperties.layerName, VK_MAX_EXTENSION_NAME_SIZE); - strcpy(_layerProperties.layerName, "MoltenVK"); + strcpy(_layerProperties.layerName, kMVKMoltenVKDriverLayerName); mvkClear(_layerProperties.description, VK_MAX_DESCRIPTION_SIZE); strcpy(_layerProperties.description, "MoltenVK driver layer"); _layerProperties.specVersion = getMVKConfig().apiVersionToAdvertise; diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h index 356dce422..457b39dee 100644 --- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.h +++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.h @@ -222,5 +222,5 @@ class MVKConfigurableMixin { * VkInstance that created the object, otherwise returns the global configuration info. */ static inline const MVKConfiguration& mvkGetMVKConfig(MVKBaseObject* mvkObj) { - return mvkObj ? mvkObj->getMVKConfig() : mvkConfig(); + return mvkObj ? mvkObj->getMVKConfig() : getGlobalMVKConfig(); } diff --git a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm index 53b1731d7..77a616814 100644 --- a/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm +++ b/MoltenVK/MoltenVK/Utility/MVKBaseObject.mm @@ -44,7 +44,7 @@ const MVKConfiguration& MVKBaseObject::getMVKConfig() { MVKVulkanAPIObject* mvkAPIObj = getVulkanAPIObject(); MVKInstance* mvkInst = mvkAPIObj ? mvkAPIObj->getInstance() : nullptr; - return mvkInst ? mvkInst->getMVKConfig() : mvkConfig(); + return mvkGetMVKConfig(mvkInst); } void MVKBaseObject::reportMessage(MVKConfigLogLevel logLevel, const char* format, ...) { @@ -67,7 +67,7 @@ MVKVulkanAPIObject* mvkAPIObj = mvkObj ? mvkObj->getVulkanAPIObject() : nullptr; MVKInstance* mvkInst = mvkAPIObj ? mvkAPIObj->getInstance() : nullptr; bool hasDebugCallbacks = mvkInst && mvkInst->hasDebugCallbacks(); - bool shouldLog = logLevel <= (mvkInst ? mvkInst->getMVKConfig() : mvkConfig()).logLevel; + bool shouldLog = logLevel <= mvkGetMVKConfig(mvkInst).logLevel; // Fail fast to avoid further unnecessary processing. if ( !(shouldLog || hasDebugCallbacks) ) { return; } diff --git a/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def b/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def index 1b5cf69f5..6e00a01c1 100644 --- a/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def +++ b/MoltenVK/MoltenVK/Utility/MVKConfigMembers.def @@ -69,7 +69,7 @@ MVK_CONFIG_MEMBER(forceLowPowerGPU, VkBool32, 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, char*, AUTO_GPU_CAPTURE_OUTPUT_FILE) +MVK_CONFIG_MEMBER_STRING(autoGPUCaptureOutputFilepath, const char*, 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) diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp index e8f0870ce..a716b16b8 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp @@ -21,6 +21,8 @@ #include "MVKFoundation.h" +#pragma mark Support functions + // Return the expected size of MVKConfiguration, based on contents of MVKConfigMembers.def. static constexpr uint32_t getExpectedMVKConfigurationSize() { #define MVK_CONFIG_MEMBER(member, mbrType, name) cfgSize += sizeof(mbrType); @@ -29,11 +31,62 @@ static constexpr uint32_t getExpectedMVKConfigurationSize() { return cfgSize; } -static bool _mvkConfigInitialized = false; -static void mvkInitConfigFromEnvVars() { +// Return the expected number of string members in MVKConfiguration, based on contents of MVKConfigMembers.def. +static constexpr uint32_t getExpectedMVKConfigurationStringCount() { +#define MVK_CONFIG_MEMBER(member, mbrType, name) +#define MVK_CONFIG_MEMBER_STRING(member, mbrType, name) if(std::is_same::value) { strCnt++; } + uint32_t strCnt = 0; +#include "MVKConfigMembers.def" + return strCnt; +} + + +#pragma mark Set configuration values + +// Sets destination config content from the source content, validates content, +// and ensures the content of any string members of MVKConfiguration are copied locally. +void mvkSetConfig(MVKConfiguration& dstMVKConfig, const MVKConfiguration& srcMVKConfig, std::string* stringHolders) { + + dstMVKConfig = srcMVKConfig; + + // Ensure the API version is supported, and add the VK_HEADER_VERSION. + dstMVKConfig.apiVersionToAdvertise = std::min(dstMVKConfig.apiVersionToAdvertise, MVK_VULKAN_API_VERSION); + dstMVKConfig.apiVersionToAdvertise = VK_MAKE_VERSION(VK_VERSION_MAJOR(dstMVKConfig.apiVersionToAdvertise), + VK_VERSION_MINOR(dstMVKConfig.apiVersionToAdvertise), + VK_HEADER_VERSION); + + // Deprecated legacy support for specific case where both legacy semaphoreUseMTLEvent + // (now aliased to semaphoreSupportStyle) and legacy semaphoreUseMTLFence are explicitly + // disabled by the app. In this case the app had been using CPU emulation, so use + // MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK. + if ( !dstMVKConfig.semaphoreUseMTLEvent && !dstMVKConfig.semaphoreUseMTLFence ) { + dstMVKConfig.semaphoreSupportStyle = MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK; + } + + // Clamp timestampPeriodLowPassAlpha between 0.0 and 1.0. + dstMVKConfig.timestampPeriodLowPassAlpha = mvkClamp(dstMVKConfig.timestampPeriodLowPassAlpha, 0.0f, 1.0f); + + // For each string member of the destination MVKConfiguration, store the contents + // in a std::string, then repoint the member to the contents of the std::string. +#define MVK_CONFIG_MEMBER(member, mbrType, name) +#define MVK_CONFIG_MEMBER_STRING(member, mbrType, name) \ + if (dstMVKConfig.member) { stringHolders[strIdx] = dstMVKConfig.member; } \ + dstMVKConfig.member = stringHolders[strIdx++].c_str(); + + static_assert(getExpectedMVKConfigurationStringCount() == kMVKConfigurationStringCount, "Each string member in MVKConfiguration needs a separate std::string to hold its content."); + uint32_t strIdx = 0; +#include "MVKConfigMembers.def" + assert(strIdx == kMVKConfigurationStringCount); // Ensure all string members of MVKConfiguration were stored in separate std::strings. +} + + +#pragma mark Load global configuration from environment variables + +static bool _mvkGlobalConfigInitialized = false; +static void mvkInitGlobalConfigFromEnvVars() { static_assert(getExpectedMVKConfigurationSize() == sizeof(MVKConfiguration), "MVKConfigMembers.def does not match the members of MVKConfiguration."); - _mvkConfigInitialized = true; + _mvkGlobalConfigInitialized = true; MVKConfiguration evCfg; std::string evGPUCapFileStrObj; @@ -59,7 +112,7 @@ static void mvkInitConfigFromEnvVars() { // Legacy MVK_ALLOW_METAL_EVENTS is covered by MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE, // but for backwards compatibility, if legacy MVK_ALLOW_METAL_EVENTS is explicitly // disabled, disable semaphoreUseMTLEvent (aliased as semaphoreSupportStyle value - // MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE), and let mvkSetConfig() + // MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE), and let mvkSetGlobalConfig() // further process legacy behavior of MVK_ALLOW_METAL_FENCES. if ( !mvkGetEnvVarNumber("MVK_CONFIG_ALLOW_METAL_EVENTS", 1.0) ) { evCfg.semaphoreUseMTLEvent = (MVKVkSemaphoreSupportStyle)false; // Disabled. Also semaphoreSupportStyle MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE. @@ -74,57 +127,23 @@ static void mvkInitConfigFromEnvVars() { evCfg.activityPerformanceLoggingStyle = MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_IMMEDIATE; } - mvkSetConfig(evCfg); + mvkSetGlobalConfig(evCfg); } -static MVKConfiguration _mvkConfig; -static std::string _autoGPUCaptureOutputFilepath; +static MVKConfiguration _globalMVKConfig; +static std::string _globalMVKConfigStringHolders[kMVKConfigurationStringCount] = {}; // 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& mvkConfig() { - if ( !_mvkConfigInitialized ) { - mvkInitConfigFromEnvVars(); +const MVKConfiguration& getGlobalMVKConfig() { + if ( !_mvkGlobalConfigInitialized ) { + mvkInitGlobalConfigFromEnvVars(); } - return _mvkConfig; + return _globalMVKConfig; } -void mvkSetConfig(const MVKConfiguration& mvkConfig) { - mvkSetConfig(_mvkConfig, mvkConfig, _autoGPUCaptureOutputFilepath); -} - -// Sets destination config content from the source content, validates 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 mvkSetConfig(MVKConfiguration& dstMVKConfig, - const MVKConfiguration& srcMVKConfig, - std::string& autoGPUCaptureOutputFilepath) { - - dstMVKConfig = srcMVKConfig; - - // Ensure the API version is supported, and add the VK_HEADER_VERSION. - dstMVKConfig.apiVersionToAdvertise = std::min(dstMVKConfig.apiVersionToAdvertise, MVK_VULKAN_API_VERSION); - dstMVKConfig.apiVersionToAdvertise = VK_MAKE_VERSION(VK_VERSION_MAJOR(dstMVKConfig.apiVersionToAdvertise), - VK_VERSION_MINOR(dstMVKConfig.apiVersionToAdvertise), - VK_HEADER_VERSION); - - // Deprecated legacy support for specific case where both legacy semaphoreUseMTLEvent - // (now aliased to semaphoreSupportStyle) and legacy semaphoreUseMTLFence are explicitly - // disabled by the app. In this case the app had been using CPU emulation, so use - // MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK. - if ( !dstMVKConfig.semaphoreUseMTLEvent && !dstMVKConfig.semaphoreUseMTLFence ) { - dstMVKConfig.semaphoreSupportStyle = MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_CALLBACK; - } - - // Set capture file path string - if (dstMVKConfig.autoGPUCaptureOutputFilepath) { - autoGPUCaptureOutputFilepath = dstMVKConfig.autoGPUCaptureOutputFilepath; - } - dstMVKConfig.autoGPUCaptureOutputFilepath = autoGPUCaptureOutputFilepath.c_str(); - - // Clamp timestampPeriodLowPassAlpha between 0.0 and 1.0. - dstMVKConfig.timestampPeriodLowPassAlpha = mvkClamp(dstMVKConfig.timestampPeriodLowPassAlpha, 0.0f, 1.0f); +void mvkSetGlobalConfig(const MVKConfiguration& srcMVKConfig) { + mvkSetConfig(_globalMVKConfig, srcMVKConfig, _globalMVKConfigStringHolders); } diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h index 4dc98a180..648ae034e 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.h +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.h @@ -75,21 +75,22 @@ #pragma mark - -#pragma mark Global Configuration +#pragma mark MoltenVK Configuration + +/** The number of members of MVKConfiguration that are strings. */ +static constexpr uint32_t kMVKConfigurationStringCount = 1; /** Global function to access MoltenVK configuration info. */ -const MVKConfiguration& mvkConfig(); +const MVKConfiguration& getGlobalMVKConfig(); /** Sets the MoltenVK global configuration content. */ -void mvkSetConfig(const MVKConfiguration& mvkConfig); +void mvkSetGlobalConfig(const MVKConfiguration& srcMVKConfig); /** * Sets the content from the source config into the destination * config, while using the string object to retain string content. */ -void mvkSetConfig(MVKConfiguration& dstMVKConfig, - const MVKConfiguration& srcMVKConfig, - std::string& autoGPUCaptureOutputFilepath); +void mvkSetConfig(MVKConfiguration& dstMVKConfig, const MVKConfiguration& srcMVKConfig, std::string* stringHolders); /** * Enable debug mode. diff --git a/MoltenVK/MoltenVK/Utility/MVKFoundation.h b/MoltenVK/MoltenVK/Utility/MVKFoundation.h index d3aa660a0..3d5dee0d6 100644 --- a/MoltenVK/MoltenVK/Utility/MVKFoundation.h +++ b/MoltenVK/MoltenVK/Utility/MVKFoundation.h @@ -379,9 +379,6 @@ static constexpr bool mvkVkComponentMappingsMatch(VkComponentMapping cm1, VkComp mvkVKComponentSwizzlesMatch(cm1.a, cm2.a, VK_COMPONENT_SWIZZLE_A)); } -/** Print the size of the type. */ -#define mvkPrintSizeOf(type) printf("Size of " #type " is %lu.\n", sizeof(type)) - #pragma mark Math diff --git a/MoltenVK/MoltenVK/Vulkan/mvk_api.mm b/MoltenVK/MoltenVK/Vulkan/mvk_api.mm index fec656666..cc0d7065f 100644 --- a/MoltenVK/MoltenVK/Vulkan/mvk_api.mm +++ b/MoltenVK/MoltenVK/Vulkan/mvk_api.mm @@ -59,7 +59,7 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkGetMoltenVKConfigurationMVK( MVKConfiguration* pConfiguration, size_t* pConfigurationSize) { - return mvkCopyGrowingStruct(pConfiguration, &mvkConfig(), pConfigurationSize); + return mvkCopyGrowingStruct(pConfiguration, &getGlobalMVKConfig(), pConfigurationSize); } MVK_PUBLIC_VULKAN_SYMBOL VkResult vkSetMoltenVKConfigurationMVK( @@ -69,9 +69,9 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkSetMoltenVKConfigurationMVK( // Start with copy of current config, in case incoming is not fully copied MVKBaseObject::reportMessage(nullptr, MVK_CONFIG_LOG_LEVEL_WARNING, "vkSetMoltenVKConfigurationMVK() is deprecated. To set MoltenVK configuration parameters, the VK_EXT_layer_settings extension, or environment variables."); - MVKConfiguration mvkCfg = mvkConfig(); + MVKConfiguration mvkCfg = getGlobalMVKConfig(); VkResult rslt = mvkCopyGrowingStruct(&mvkCfg, pConfiguration, pConfigurationSize); - mvkSetConfig(mvkCfg); + mvkSetGlobalConfig(mvkCfg); return rslt; } @@ -110,7 +110,7 @@ MVK_PUBLIC_VULKAN_SYMBOL void vkGetVersionStringsMVK( len = mvkVer.copy(pMoltenVersionStringBuffer, moltenVersionStringBufferLength - 1); pMoltenVersionStringBuffer[len] = 0; // terminator - string vkVer = mvkGetVulkanVersionString(mvkConfig().apiVersionToAdvertise); + string vkVer = mvkGetVulkanVersionString(getGlobalMVKConfig().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 293826a33..1d228faf9 100644 --- a/MoltenVK/MoltenVK/Vulkan/vulkan.mm +++ b/MoltenVK/MoltenVK/Vulkan/vulkan.mm @@ -55,7 +55,7 @@ static inline uint64_t MVKTraceVulkanCallStartImpl(const char* funcName) { bool includeExit = false; bool includeDuration = false; - switch (mvkConfig().traceVulkanCalls) { + switch (getGlobalMVKConfig().traceVulkanCalls) { case MVK_CONFIG_TRACE_VULKAN_CALLS_DURATION: includeDuration = true; // fallthrough case MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT: @@ -94,7 +94,7 @@ static inline uint64_t MVKTraceVulkanCallStartImpl(const char* funcName) { // Optionally log end of function calls and timings to stderr static inline void MVKTraceVulkanCallEndImpl(const char* funcName, uint64_t startTime) { - switch(mvkConfig().traceVulkanCalls) { + switch(getGlobalMVKConfig().traceVulkanCalls) { case MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT: case MVK_CONFIG_TRACE_VULKAN_CALLS_ENTER_EXIT_THREAD_ID: fprintf(stderr, "[mvk-trace] } %s\n", funcName); @@ -2021,7 +2021,7 @@ MVK_PUBLIC_VULKAN_SYMBOL VkResult vkEnumerateInstanceVersion( uint32_t* pApiVersion) { MVKTraceVulkanCallStart(); - *pApiVersion = mvkConfig().apiVersionToAdvertise; + *pApiVersion = getGlobalMVKConfig().apiVersionToAdvertise; MVKTraceVulkanCallEnd(); return VK_SUCCESS; } diff --git a/README.md b/README.md index e7d565993..69446d25b 100644 --- a/README.md +++ b/README.md @@ -36,33 +36,33 @@ Table of Contents Introduction to MoltenVK ------------------------ -**MoltenVK** is a layered implementation of [*Vulkan 1.2*](https://www.khronos.org/vulkan) -graphics and compute functionality, that is built on Apple's [*Metal*](https://developer.apple.com/metal) -graphics and compute framework on *macOS*, *iOS*, *tvOS*, and *visionOS*. **MoltenVK** allows -you to use *Vulkan* graphics and compute functionality to develop modern, cross-platform, -high-performance graphical games and applications, and to run them across many platforms, -including *macOS*, *iOS*, *tvOS*, *visionOS*, *Simulators*, and *Mac Catalyst* on *macOS 11.0+*, +**MoltenVK** is a layered implementation of [*Vulkan 1.2*](https://www.khronos.org/vulkan) +graphics and compute functionality, that is built on Apple's [*Metal*](https://developer.apple.com/metal) +graphics and compute framework on *macOS*, *iOS*, *tvOS*, and *visionOS*. **MoltenVK** allows +you to use *Vulkan* graphics and compute functionality to develop modern, cross-platform, +high-performance graphical games and applications, and to run them across many platforms, +including *macOS*, *iOS*, *tvOS*, *visionOS*, *Simulators*, and *Mac Catalyst* on *macOS 11.0+*, and all *Apple* architectures, including *Apple Silicon*. -*Metal* uses a different shading language, the *Metal Shading Language (MSL)*, than -*Vulkan*, which uses *SPIR-V*. **MoltenVK** automatically converts your *SPIR-V* shaders +*Metal* uses a different shading language, the *Metal Shading Language (MSL)*, than +*Vulkan*, which uses *SPIR-V*. **MoltenVK** automatically converts your *SPIR-V* shaders to their *MSL* equivalents. -To provide *Vulkan* capability to the *macOS*, *iOS*, *tvOS*, and *visionOS* platforms, -**MoltenVK** uses *Apple's* publicly available API's, including *Metal*. **MoltenVK** -does **_not_** use any private or undocumented API calls or features, so your app will +To provide *Vulkan* capability to the *macOS*, *iOS*, *tvOS*, and *visionOS* platforms, +**MoltenVK** uses *Apple's* publicly available API's, including *Metal*. **MoltenVK** +does **_not_** use any private or undocumented API calls or features, so your app will be compatible with all standard distribution channels, including *Apple's App Store*. The **MoltenVK** runtime package contains two products: -- **MoltenVK** is a implementation of an almost-complete subset of the +- **MoltenVK** is a implementation of an almost-complete subset of the [*Vulkan 1.2*](https://www.khronos.org/vulkan) graphics and compute API. - **MoltenVKShaderConverter** converts *SPIR-V* shader code to *Metal Shading Language (MSL)* shader code, and converts *GLSL* shader source code to *SPIR-V* shader code and/or - *Metal Shading Language (MSL)* shader code. The converter is embedded in the **MoltenVK** - runtime to automatically convert *SPIR-V* shaders to their *MSL* equivalents. In addition, - both the *SPIR-V* and *GLSL* converters are packaged into a stand-alone command-line + *Metal Shading Language (MSL)* shader code. The converter is embedded in the **MoltenVK** + runtime to automatically convert *SPIR-V* shaders to their *MSL* equivalents. In addition, + both the *SPIR-V* and *GLSL* converters are packaged into a stand-alone command-line `MoltenVKShaderConverter` *macOS* tool for converting shaders at development time from the command line. @@ -74,32 +74,32 @@ Developing *Vulkan* Applications for *macOS, iOS, tvOS, and visionOS* ### Using the *Vulkan SDK* -The recommended method for developing a *Vulkan* application for *macOS* is to use the +The recommended method for developing a *Vulkan* application for *macOS* is to use the [*Vulkan SDK*](https://vulkan.lunarg.com/sdk/home). -The *Vulkan SDK* includes a **MoltenVK** runtime library for *macOS*. *Vulkan* is a layered -architecture that allows applications to add additional functionality without modifying the +The *Vulkan SDK* includes a **MoltenVK** runtime library for *macOS*. *Vulkan* is a layered +architecture that allows applications to add additional functionality without modifying the application itself. The *Validation Layers* included in the *Vulkan SDK* are an essential debugging -tool for application developers because they identify inappropriate use of the *Vulkan API*. +tool for application developers because they identify inappropriate use of the *Vulkan API*. If you are developing a *Vulkan* application for *macOS*, it is highly recommended that you use the [*Vulkan SDK*](https://vulkan.lunarg.com/sdk/home) and the **MoltenVK** library included in it. -Refer to the *Vulkan SDK [Getting Started](https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html)* +Refer to the *Vulkan SDK [Getting Started](https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html)* document for more info. -Because **MoltenVK** supports the `VK_KHR_portability_subset` extension, when using the -*Vulkan Loader* from the *Vulkan SDK* to run **MoltenVK** on *macOS*, the *Vulkan Loader* -will only include **MoltenVK** `VkPhysicalDevices` in the list returned by -`vkEnumeratePhysicalDevices()` if the `VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` -flag is enabled in `vkCreateInstance()`. See the description of the `VK_KHR_portability_enumeration` -extension in the *Vulkan* specification for more information about the use of the +Because **MoltenVK** supports the `VK_KHR_portability_subset` extension, when using the +*Vulkan Loader* from the *Vulkan SDK* to run **MoltenVK** on *macOS*, the *Vulkan Loader* +will only include **MoltenVK** `VkPhysicalDevices` in the list returned by +`vkEnumeratePhysicalDevices()` if the `VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` +flag is enabled in `vkCreateInstance()`. See the description of the `VK_KHR_portability_enumeration` +extension in the *Vulkan* specification for more information about the use of the `VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR` flag. ### Using MoltenVK Directly -If you are developing a *Vulkan* application for *iOS*, *tvOS*, or *visionOS*, or are -developing a *Vulkan* application for *macOS* and want to use a different version or -build of the **MoltenVK** runtime library than provided in the *macOS Vulkan SDK*, +If you are developing a *Vulkan* application for *iOS*, *tvOS*, or *visionOS*, or are +developing a *Vulkan* application for *macOS* and want to use a different version or +build of the **MoltenVK** runtime library than provided in the *macOS Vulkan SDK*, you can access a pre-built MoltenVK binary library from the **MoltenVK** repository, by [selecting a repository commit from the list](https://github.com/KhronosGroup/MoltenVK/actions), and downloading the associated **MoltenVK** runtime library artifact. @@ -108,8 +108,8 @@ Finally, if you want a customized build of **MoltenVK**, you can follow the [ins to create a **MoltenVK** runtime library by fetching and building the **MoltenVK** source code. To learn how to integrate the **MoltenVK** runtime library into a game or application, -see the [`MoltenVK_Runtime_UserGuide.md `](Docs/MoltenVK_Runtime_UserGuide.md) -document in the `Docs` directory. +see the [`MoltenVK_Runtime_UserGuide.md `](Docs/MoltenVK_Runtime_UserGuide.md) +document in the `Docs` directory. @@ -117,8 +117,8 @@ document in the `Docs` directory. Fetching **MoltenVK** Source Code --------------------------------- -To fetch **MoltenVK** source code, clone this `MoltenVK` repository, and then run the -`fetchDependencies` script to retrieve and build several external open-source libraries +To fetch **MoltenVK** source code, clone this `MoltenVK` repository, and then run the +`fetchDependencies` script to retrieve and build several external open-source libraries on which **MoltenVK** relies: 1. Ensure you have `cmake` and `python3` installed: @@ -139,26 +139,26 @@ on which **MoltenVK** relies: cd MoltenVK ./fetchDependencies [platform...] -When running the `fetchDependencies` script, you must specify one or more platforms -for which to build the external libraries. The platform choices include: +When running the `fetchDependencies` script, you must specify one or more platforms +for which to build the external libraries. The platform choices include: - --all - --macos - --ios - --iossim - --maccat - --tvos + --all + --macos + --ios + --iossim + --maccat + --tvos --tvossim -You can specify multiple of these selections. The result is a single `XCFramework` -for each external dependency library, with each `XCFramework` containing binaries for -each of the requested platforms. +You can specify multiple of these selections. The result is a single `XCFramework` +for each external dependency library, with each `XCFramework` containing binaries for +each of the requested platforms. -The `--all` selection is the same as entering all of the other platform choices, -and will result in a single `XCFramework` for each external dependency library, -with each `XCFramework` containing binaries for all supported platforms and simulators. +The `--all` selection is the same as entering all of the other platform choices, +and will result in a single `XCFramework` for each external dependency library, +with each `XCFramework` containing binaries for all supported platforms and simulators. -Running `fetchDependencies` repeatedly with different platforms will accumulate targets +Running `fetchDependencies` repeatedly with different platforms will accumulate targets in the `XCFramework`, if the `--keep-cache` option is used on each invocation. For more information about the external open-source libraries used by **MoltenVK**, @@ -169,83 +169,83 @@ see the [`ExternalRevisions/README.md`](ExternalRevisions/README.md) document. Building **MoltenVK** ------------------- -During building, **MoltenVK** references the latest *Apple SDK* frameworks. To access these frameworks, +During building, **MoltenVK** references the latest *Apple SDK* frameworks. To access these frameworks, and to avoid build errors, be sure to use the latest publicly available version of *Xcode*. -> ***Note:*** *Xcode 14* introduced a new static linkage model that is not compatible with previous -versions of *Xcode*. If you link to a `MoltenVK.xcframework` that was built with *Xcode 14* or later, -also use *Xcode 14* or later to link it to your app or game. +> ***Note:*** *Xcode 14* introduced a new static linkage model that is not compatible with previous +versions of *Xcode*. If you link to a `MoltenVK.xcframework` that was built with *Xcode 14* or later, +also use *Xcode 14* or later to link it to your app or game. > -> If you need to use *Xcode 13* or earlier to link `MoltenVK.xcframework` to your app or game, -first build **MoltenVK** with *Xcode 13* or earlier. +> If you need to use *Xcode 13* or earlier to link `MoltenVK.xcframework` to your app or game, +first build **MoltenVK** with *Xcode 13* or earlier. > -> Or, if you want to use *Xcode 14* or later to build **MoltenVK**, in order to be able to use the -latest *Metal* capabilities, but need to use *Xcode 13* or earlier to link `MoltenVK.xcframework` -to your app or game, first add the value `-fno-objc-msgsend-selector-stubs` to the `OTHER_CFLAGS` -*Xcode* build setting in the `MoltenVK.xcodeproj` and `MoltenVKShaderConverter.xcodeproj` *Xcode* -projects, build **MoltenVK** with *Xcode 14* or later, and then link `MoltenVK.xcframework` +> Or, if you want to use *Xcode 14* or later to build **MoltenVK**, in order to be able to use the +latest *Metal* capabilities, but need to use *Xcode 13* or earlier to link `MoltenVK.xcframework` +to your app or game, first add the value `-fno-objc-msgsend-selector-stubs` to the `OTHER_CFLAGS` +*Xcode* build setting in the `MoltenVK.xcodeproj` and `MoltenVKShaderConverter.xcodeproj` *Xcode* +projects, build **MoltenVK** with *Xcode 14* or later, and then link `MoltenVK.xcframework` to your app or game using *Xcode 13* or earlier. -**MoltenVK** can be built to support at least *macOS 10.11*, *iOS 9*, or *tvOS 9*, but the default -_Xcode_ build settings in the included _Xcode_ projects are set to a minimum deployment target of -*macOS 10.13*, *iOS 11*, and *tvOS 11*, which are the oldest OS versions supported by the current -_Xcode_ version. If you require support for earlier OS versions, modify the `MACOSX_DEPLOYMENT_TARGET`, +**MoltenVK** can be built to support at least *macOS 10.11*, *iOS 9*, or *tvOS 9*, but the default +_Xcode_ build settings in the included _Xcode_ projects are set to a minimum deployment target of +*macOS 10.13*, *iOS 11*, and *tvOS 11*, which are the oldest OS versions supported by the current +_Xcode_ version. If you require support for earlier OS versions, modify the `MACOSX_DEPLOYMENT_TARGET`, `IPHONEOS_DEPLOYMENT_TARGET`, or `TVOS_DEPLOYMENT_TARGET` build settings in _Xcode_ before building **MoltenVK**. ->***Note:*** To support `IOSurfaces` on *iOS* or *tvOS*, **MoltenVK**, and any app that uses -**MoltenVK**, must be built with a minimum **iOS Deployment Target** (aka `IPHONEOS_DEPLOYMENT_TARGET `) -build setting of `iOS 11.0` or greater, or a minimum **tvOS Deployment Target** (aka `TVOS_DEPLOYMENT_TARGET `) +>***Note:*** To support `IOSurfaces` on *iOS* or *tvOS*, **MoltenVK**, and any app that uses +**MoltenVK**, must be built with a minimum **iOS Deployment Target** (aka `IPHONEOS_DEPLOYMENT_TARGET `) +build setting of `iOS 11.0` or greater, or a minimum **tvOS Deployment Target** (aka `TVOS_DEPLOYMENT_TARGET `) build setting of `tvOS 11.0` or greater. -Once built, the **MoltenVK** libraries can be run on *macOS*, *iOS*, *tvOS*, or *visionOS* devices +Once built, the **MoltenVK** libraries can be run on *macOS*, *iOS*, *tvOS*, or *visionOS* devices that support *Metal*,or on the *Xcode* *iOS Simulator*, *tvOS Simulator*, or *visionOS Simulator*. -- At runtime, **MoltenVK** requires at least *macOS 10.11*, *iOS 9.0*, *tvOS 9.0*, +- At runtime, **MoltenVK** requires at least *macOS 10.11*, *iOS 9.0*, *tvOS 9.0*, or *visionOS 1.0* (or *iOS 11* or *tvOS 11* if using `IOSurfaces`). -- Information on *macOS* devices that are compatible with *Metal* can be found in +- Information on *macOS* devices that are compatible with *Metal* can be found in [this article](http://www.idownloadblog.com/2015/06/22/how-to-find-mac-el-capitan-metal-compatible). -- Information on *iOS* devices that are compatible with *Metal* can be found in +- Information on *iOS* devices that are compatible with *Metal* can be found in [this article](https://developer.apple.com/library/content/documentation/DeviceInformation/Reference/iOSDeviceCompatibility/HardwareGPUInformation/HardwareGPUInformation.html). -The `MoltenVKPackaging.xcodeproj` *Xcode* project contains targets and schemes to build -and package the entire **MoltenVK** runtime distribution package, or to build individual +The `MoltenVKPackaging.xcodeproj` *Xcode* project contains targets and schemes to build +and package the entire **MoltenVK** runtime distribution package, or to build individual **MoltenVK** or **MoltenVKShaderConverter** components. -To build a **MoltenVK** runtime distribution package, suitable for testing and integrating into an app, +To build a **MoltenVK** runtime distribution package, suitable for testing and integrating into an app, open `MoltenVKPackaging.xcodeproj` in *Xcode*, and use one of the following *Xcode Schemes*, depending -on whether you want a **_Release_** or **_Debug_** configuration, and whether you want to build for all +on whether you want a **_Release_** or **_Debug_** configuration, and whether you want to build for all platforms, or just one platform (in **_Release_** configuration): -- **MoltenVK Package** -- **MoltenVK Package (Debug)** -- **MoltenVK Package (macOS only)** +- **MoltenVK Package** +- **MoltenVK Package (Debug)** +- **MoltenVK Package (macOS only)** - **MoltenVK Package (iOS only)** - **MoltenVK Package (tvOS only)** - **MoltenVK Package (visionOS only)** _(requires Xcode 15+)_ -Each of these`MoltenVKPackaging.xcodeproj` *Xcode* project *Schemes* puts the resulting packages in the -`Package` directory, creating it if necessary. This directory contains separate `Release` and `Debug` +Each of these`MoltenVKPackaging.xcodeproj` *Xcode* project *Schemes* puts the resulting packages in the +`Package` directory, creating it if necessary. This directory contains separate `Release` and `Debug` directories, holding the most recent **_Release_** and **_Debug_** builds, respectively. -A separate `Latest` directory links to the most recent build, regardless of whether it was a **_Release_** -or **_Debug_** build. Effectively, the `Package/Latest` directory points to whichever of the `Package/Release` +A separate `Latest` directory links to the most recent build, regardless of whether it was a **_Release_** +or **_Debug_** build. Effectively, the `Package/Latest` directory points to whichever of the `Package/Release` or `Package/Debug` directories was most recently updated. -With this packaging structure, you can follow the [instructions below](#using) to link your application -to the **MoltenVK** libraries and frameworks in the `Package/Latest` directory, to provide the flexibility +With this packaging structure, you can follow the [instructions below](#using) to link your application +to the **MoltenVK** libraries and frameworks in the `Package/Latest` directory, to provide the flexibility to test your app with either a **_Debug_** build, or a higher-performance **_Release_** build. ### Building from the Command Line If you prefer to build **MoltenVK** from the command line, or to include the activity in a larger build script, -you can do so by executing a command similar to the following command within the `MoltenVK` repository folder, -and identifying one of the *Xcode Schemes* from the list above. For example, the following command will build +you can do so by executing a command similar to the following command within the `MoltenVK` repository folder, +and identifying one of the *Xcode Schemes* from the list above. For example, the following command will build **MoltenVK** in the **_Debug_** configuration for *macOS* only: xcodebuild build -quiet -project MoltenVKPackaging.xcodeproj -scheme "MoltenVK Package (macOS only)" -configuration "Debug" -Alternately, you can use the basic `Makefile` in the `MoltenVK` repository folder to build **MoltenVK** +Alternately, you can use the basic `Makefile` in the `MoltenVK` repository folder to build **MoltenVK** from the command line. The following `make` targets are provided: make @@ -272,19 +272,19 @@ from the command line. The following `make` targets are provided: - The `all` target executes all platform targets. - The `all` target is the default target. Running `make` with no arguments is the same as running `make all`. - The `*-debug` targets build the binaries using the **_Debug_** configuration. -- The `install` target will copy the most recently built `MoltenVK.xcframework` into the - `/Library/Frameworks` folder of your computer. Since `/Library/Frameworks` is protected, +- The `install` target will copy the most recently built `MoltenVK.xcframework` into the + `/Library/Frameworks` folder of your computer. Since `/Library/Frameworks` is protected, you will generally need to run it as `sudo make install` and enter your password. The `install` target just installs the built framework, it does not first build the framework. You will first need to at least run `make macos` first. -The `make` targets all require that *Xcode* is installed on your system. +The `make` targets all require that *Xcode* is installed on your system. -Building from the command line creates the same `Package` folder structure described above when +Building from the command line creates the same `Package` folder structure described above when building from within *Xcode*. -When building from the command line, you can set any of the build settings documented -in the `MoltenVK_Configuration_Parameters.md` file, by passing them in the command line, +When building from the command line, you can set any of the build settings documented +in the `MoltenVK_Configuration_Parameters.md` file, by passing them in the command line, as in the following examples: make MVK_CONFIG_LOG_LEVEL=0 @@ -301,7 +301,7 @@ You can optionally build MoltenVK with the Vulkan API static call symbols (`vk*` to avoid library linking conflicts when bound to a Vulkan Loader that also exports identical symbols. To do so, when building MoltenVK, set the build setting `MVK_HIDE_VULKAN_SYMBOLS=1`. -This build setting can be set in the `MoltenVK.xcodeproj` *Xcode* project, +This build setting can be set in the `MoltenVK.xcodeproj` *Xcode* project, or it can be included in any of the `make` build commands. For example: make MVK_HIDE_VULKAN_SYMBOLS=1 @@ -316,14 +316,14 @@ or Running **MoltenVK** Demo Applications -------------------------------------- -Once you have compiled and built the **MoltenVK** runtime distribution package from this **MoltenVK** repository, -as described in the [Building **MoltenVK**](#building) section, you can explore how **MoltenVK** provides *Vulkan* +Once you have compiled and built the **MoltenVK** runtime distribution package from this **MoltenVK** repository, +as described in the [Building **MoltenVK**](#building) section, you can explore how **MoltenVK** provides *Vulkan* support on *macOS*, *iOS*, and *tvOS* by investigating and running the demo application that is included in **MoltenVK**. The **MoltenVK** _Cube_ demo app is located in the `Demos` folder. The demo app is available as an *Xcode* project. To review and run the included demo app, open the `Demos/Demos.xcworkspace` workspace in *Xcode*. -Please read the [`Demos/README.md`](Demos/README.md) document for a description and instructions for running the +Please read the [`Demos/README.md`](Demos/README.md) document for a description and instructions for running the included *Cube* demo app, and for external links to more sophisticated demo applications that can be run on **MoltenVK**. @@ -332,12 +332,12 @@ included *Cube* demo app, and for external links to more sophisticated demo appl Using **MoltenVK** in Your Application -------------------------------------- -Once you have compiled and built the **MoltenVK** runtime distribution package from this **MoltenVK** repository, -as described in the [Building **MoltenVK**](#building) section, follow the instructions in the Installation -section of the [`Docs/MoltenVK_Runtime_UserGuide.md`](Docs/MoltenVK_Runtime_UserGuide.md#install) document +Once you have compiled and built the **MoltenVK** runtime distribution package from this **MoltenVK** repository, +as described in the [Building **MoltenVK**](#building) section, follow the instructions in the Installation +section of the [`Docs/MoltenVK_Runtime_UserGuide.md`](Docs/MoltenVK_Runtime_UserGuide.md#install) document in the `Docs` directory, to link the **MoltenVK** libraries and frameworks to your application. -The runtime distribution package in the `Package/Latest` directory is a stand-alone package, and you can copy +The runtime distribution package in the `Package/Latest` directory is a stand-alone package, and you can copy the contents of that directory out of this **MoltenVK** repository into your own application building environment. @@ -346,38 +346,38 @@ the contents of that directory out of this **MoltenVK** repository into your own **MoltenVK** and *Vulkan* Compliance ------------------------------------ -**MoltenVK** is designed to be an implementation of a *Vulkan 1.2* subset that runs on *macOS*, *iOS*, +**MoltenVK** is designed to be an implementation of a *Vulkan 1.2* subset that runs on *macOS*, *iOS*, *tvOS*, and *visionOS* platforms by mapping *Vulkan* capability to native *Metal* capability. -The fundamental design and development goal of **MoltenVK** is to provide this capability in a way that +The fundamental design and development goal of **MoltenVK** is to provide this capability in a way that is both maximally compliant with the *Vulkan 1.2* specification, and maximally performant. -Such compliance and performance is inherently affected by the capability available through *Metal*, -as the native graphics driver on *macOS*, *iOS*, *tvOS*, and *visionOS* platforms. *Vulkan* +Such compliance and performance is inherently affected by the capability available through *Metal*, +as the native graphics driver on *macOS*, *iOS*, *tvOS*, and *visionOS* platforms. *Vulkan* compliance may fall into one of the following categories: - Direct mapping between *Vulkan* capabilities and *Metal* capabilities. Within **MoltenVK**, the vast - majority of *Vulkan* capability is the result of this type of direct mapping. - + majority of *Vulkan* capability is the result of this type of direct mapping. + - Synthesized compliance through alternate implementation. A small amount of capability is provided using this mechanism, such as via an extra render or compute shader stage. - Non-compliance. This appears where the capabilities of *Vulkan* and *Metal* are sufficiently different, that - there is no practical, or reasonably performant, mechanism to implement a *Vulkan* capability in *Metal*. - Because of design differences between *Vulkan* and *Metal*, a very small amount of capability falls into this - category, and at present **MoltenVK** is **_not_** fully compliant with the *Vulkan* specification. A list of - known limitations is documented in the [`MoltenVK_Runtime_UserGuide.md`](Docs/MoltenVK_Runtime_UserGuide.md#limitations) + there is no practical, or reasonably performant, mechanism to implement a *Vulkan* capability in *Metal*. + Because of design differences between *Vulkan* and *Metal*, a very small amount of capability falls into this + category, and at present **MoltenVK** is **_not_** fully compliant with the *Vulkan* specification. A list of + known limitations is documented in the [`MoltenVK_Runtime_UserGuide.md`](Docs/MoltenVK_Runtime_UserGuide.md#limitations) document in the `Docs` directory. -The **MoltenVK** development team welcomes you to [post Issues](https://github.com/KhronosGroup/MoltenVK/issues) -of non-compliance, and engage in discussions about how compliance can be improved, and non-compliant features can +The **MoltenVK** development team welcomes you to [post Issues](https://github.com/KhronosGroup/MoltenVK/issues) +of non-compliance, and engage in discussions about how compliance can be improved, and non-compliant features can be implemented or worked around. -**MoltenVK** is a key component of the -[*Khronos Vulkan Portability Initiative*](https://www.khronos.org/vulkan/portability-initiative), -whose intention is to provide specifications, resources, and tools to allow developers to understand and design -their *Vulkan* apps for maximum cross-platform compatibility and portability, including on platforms, such as -*macOS*, *iOS*, *tvOS*, and *visionOS*, where a native *Vulkan* driver is not available. +**MoltenVK** is a key component of the +[*Khronos Vulkan Portability Initiative*](https://www.khronos.org/vulkan/portability-initiative), +whose intention is to provide specifications, resources, and tools to allow developers to understand and design +their *Vulkan* apps for maximum cross-platform compatibility and portability, including on platforms, such as +*macOS*, *iOS*, *tvOS*, and *visionOS*, where a native *Vulkan* driver is not available. @@ -386,19 +386,19 @@ their *Vulkan* apps for maximum cross-platform compatibility and portability, in Getting Support ---------------- -- If you have a question about using **MoltenVK**, you can ask it in - [*MoltenVK Discussions*](https://github.com/KhronosGroup/MoltenVK/discussions). +- If you have a question about using **MoltenVK**, you can ask it in + [*MoltenVK Discussions*](https://github.com/KhronosGroup/MoltenVK/discussions). This forum is monitored by **MoltenVK** contributors and users. -- If you encounter an issue with the behavior of **MoltenVK**, or want to request an enhancement, +- If you encounter an issue with the behavior of **MoltenVK**, or want to request an enhancement, you can report it in the [*MoltenVK Issues List*](https://github.com/KhronosGroup/MoltenVK/issues). -- If you encounter an issue with the *Vulkan SDK*, including the *Validation Layers*, you can report it in the +- If you encounter an issue with the *Vulkan SDK*, including the *Validation Layers*, you can report it in the [*Vulkan SDK Issues List*](https://vulkan.lunarg.com/issue/home). - If you explore **MoltenVK** and determine that it does not meet your requirements at this time, we would appreciate - hearing why that is so, in [*MoltenVK Discussions*](https://github.com/KhronosGroup/MoltenVK/discussions). - The goal of **MoltenVK** is to increase the value of *Vulkan* as a true cross-platform ecosystem, by providing + hearing why that is so, in [*MoltenVK Discussions*](https://github.com/KhronosGroup/MoltenVK/discussions). + The goal of **MoltenVK** is to increase the value of *Vulkan* as a true cross-platform ecosystem, by providing *Vulkan* on *Apple* platforms. Hearing why this is currently not working for you will help us in that goal. @@ -408,52 +408,52 @@ Getting Support Contributing to **MoltenVK** Development ---------------------------------------- -As a public open-source project, **MoltenVK** benefits from code contributions from a wide range of developers, +As a public open-source project, **MoltenVK** benefits from code contributions from a wide range of developers, and we encourage you to get involved and contribute code to this **MoltenVK** repository. -To contribute your code, submit a [Pull Request](https://github.com/KhronosGroup/MoltenVK/pulls) -to this repository. The first time you do this, you will be asked to agree to the **MoltenVK** +To contribute your code, submit a [Pull Request](https://github.com/KhronosGroup/MoltenVK/pulls) +to this repository. The first time you do this, you will be asked to agree to the **MoltenVK** [Contributor License Agreement](https://cla-assistant.io/KhronosGroup/MoltenVK). ### Licensing -**MoltenVK** is licensed under the Apache 2.0 license. All new source code files should include a -copyright header at the top, containing your authorship copyright and the Apache 2.0 licensing stub. +**MoltenVK** is licensed under the Apache 2.0 license. All new source code files should include a +copyright header at the top, containing your authorship copyright and the Apache 2.0 licensing stub. You may copy the text from an existing source code file as a template. The Apache 2.0 license guarantees that code in the **MoltenVK** repository is free of Intellectual Property -encumbrances. In submitting code to this repository, you are agreeing that the code is free of any Intellectual -Property claims. +encumbrances. In submitting code to this repository, you are agreeing that the code is free of any Intellectual +Property claims. ### *Vulkan* Validation -Despite running on top of *Metal*, **MoltenVK** operates as a *Vulkan* core layer. As such, as per the -error handling guidelines of the [*Vulkan* specification](https://www.khronos.org/registry/vulkan/specs/1.2/html/vkspec.html#fundamentals-errors), **MoltenVK** should not perform *Vulkan* validation. When adding functionality +Despite running on top of *Metal*, **MoltenVK** operates as a *Vulkan* core layer. As such, as per the +error handling guidelines of the [*Vulkan* specification](https://www.khronos.org/registry/vulkan/specs/1.2/html/vkspec.html#fundamentals-errors), **MoltenVK** should not perform *Vulkan* validation. When adding functionality to **MoltenVK**, avoid adding unnecessary validation code. -Validation and error generation **_is_** appropriate within **MoltenVK** in cases where **MoltenVK** deviates -from behavior defined by the *Vulkan* specification. This most commonly occurs when required behavior cannot +Validation and error generation **_is_** appropriate within **MoltenVK** in cases where **MoltenVK** deviates +from behavior defined by the *Vulkan* specification. This most commonly occurs when required behavior cannot be mapped to functionality available within *Metal*. In that situation, it is important to provide feedback to the application developer to that effect, by performing the necessary validation, and reporting an error. -Currently, there is some excess *Vulkan* validation and error reporting code within **MoltenVK**, added before -this guideline was introduced. You are encouraged to remove such code if you encounter it while performing other -**MoltenVK** development. Do not remove validation and error reporting code that is covering a deviation in +Currently, there is some excess *Vulkan* validation and error reporting code within **MoltenVK**, added before +this guideline was introduced. You are encouraged to remove such code if you encounter it while performing other +**MoltenVK** development. Do not remove validation and error reporting code that is covering a deviation in behavior from the *Vulkan* specification. ### Memory Management -*Metal*, and other *Objective-C* objects in *Apple's SDK* frameworks, use reference counting for memory management. -As a contributor to **MoltenVK**, when instantiating *Objective-C* objects, it is important that you do not rely on -the app providing *autorelease pools* to do memory management for you. Because many *Vulkan* games and apps may be +*Metal*, and other *Objective-C* objects in *Apple's SDK* frameworks, use reference counting for memory management. +As a contributor to **MoltenVK**, when instantiating *Objective-C* objects, it is important that you do not rely on +the app providing *autorelease pools* to do memory management for you. Because many *Vulkan* games and apps may be ported from other platforms, they will often not automatically include autorelease pools in their threading models. -As a contributor to **MoltenVK**, avoid the use of the *Metal* `autorelease` method, or any object *Metal* creation -methods that imply internal use of `autorelease`, (eg- `[NSString stringWithFormat: ]`, etc). Instead, favor object -creation methods that return a retained object (eg- `[[NSString alloc] initWithFormat: ]`, etc), and manually track +As a contributor to **MoltenVK**, avoid the use of the *Metal* `autorelease` method, or any object *Metal* creation +methods that imply internal use of `autorelease`, (eg- `[NSString stringWithFormat: ]`, etc). Instead, favor object +creation methods that return a retained object (eg- `[[NSString alloc] initWithFormat: ]`, etc), and manually track and release those objects. If you need to use autoreleased objects, wrap your code in an `@autoreleasepool {...}` block. From 6daa6c0f9659a2013ff3f16e1f15f5807a05ba90 Mon Sep 17 00:00:00 2001 From: Bill Hollings Date: Tue, 19 Dec 2023 17:20:17 -0500 Subject: [PATCH 12/14] Update MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp Co-authored-by: Chip Davis --- MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp index a716b16b8..f7be749e5 100644 --- a/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp +++ b/MoltenVK/MoltenVK/Utility/MVKEnvironment.cpp @@ -34,7 +34,7 @@ static constexpr uint32_t getExpectedMVKConfigurationSize() { // Return the expected number of string members in MVKConfiguration, based on contents of MVKConfigMembers.def. static constexpr uint32_t getExpectedMVKConfigurationStringCount() { #define MVK_CONFIG_MEMBER(member, mbrType, name) -#define MVK_CONFIG_MEMBER_STRING(member, mbrType, name) if(std::is_same::value) { strCnt++; } +#define MVK_CONFIG_MEMBER_STRING(member, mbrType, name) strCnt++; uint32_t strCnt = 0; #include "MVKConfigMembers.def" return strCnt; From 86c080d9c8de06d14c249d1a52bf0961b31299b9 Mon Sep 17 00:00:00 2001 From: sean Date: Tue, 6 Jun 2023 16:43:57 +0200 Subject: [PATCH 13/14] Add: Support for RG11B10 and RGB9E5 vertex formats --- .../MoltenVK/GPUObjects/MVKPixelFormats.h | 2 +- .../MoltenVK/GPUObjects/MVKPixelFormats.mm | 31 +++++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h index 5d23225b3..0e1ecd74d 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.h @@ -34,7 +34,7 @@ static const uint32_t _vkFormatCount = 256; static const uint32_t _vkFormatCoreCount = VK_FORMAT_ASTC_12x12_SRGB_BLOCK + 1; static const uint32_t _mtlPixelFormatCount = 256; static const uint32_t _mtlPixelFormatCoreCount = MTLPixelFormatX32_Stencil8 + 2; // The actual last enum value is not available on iOS -static const uint32_t _mtlVertexFormatCount = MTLVertexFormatHalf + 1; +static const uint32_t _mtlVertexFormatCount = MTLVertexFormatHalf + 3; // The actual last enum value is not available before Xcode 15 #pragma mark - diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index 7b7e04cd7..ce60ba3e7 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -148,6 +148,11 @@ # define MTLPixelFormatASTC_12x12_HDR MTLPixelFormatInvalid #endif +#if !MVK_XCODE_15 +# define MTLVertexFormatFloatRG11B10 MTLVertexFormatInvalid +# define MTLVertexFormatFloatRGB9E5 MTLVertexFormatInvalid +#endif + #pragma mark - #pragma mark MVKPixelFormats @@ -976,9 +981,9 @@ addVkFormatDesc( R64G64B64A64_SINT, Invalid, Invalid, Invalid, Invalid, 1, 1, 32, ColorFloat ); addVkFormatDesc( R64G64B64A64_SFLOAT, Invalid, Invalid, Invalid, Invalid, 1, 1, 32, ColorFloat ); - addVkFormatDesc( B10G11R11_UFLOAT_PACK32, RG11B10Float, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat ); - addVkFormatDesc( E5B9G9R9_UFLOAT_PACK32, RGB9E5Float, Invalid, Invalid, Invalid, 1, 1, 4, ColorFloat ); - + addVkFormatDesc( B10G11R11_UFLOAT_PACK32, RG11B10Float, Invalid, FloatRG11B10, Invalid, 1, 1, 4, ColorFloat ); + addVkFormatDesc( E5B9G9R9_UFLOAT_PACK32, RGB9E5Float, Invalid, FloatRGB9E5, Invalid, 1, 1, 4, ColorFloat ); + addVkFormatDesc( D32_SFLOAT, Depth32Float, Invalid, Invalid, Invalid, 1, 1, 4, DepthStencil ); addVkFormatDesc( D32_SFLOAT_S8_UINT, Depth32Float_Stencil8, Invalid, Invalid, Invalid, 1, 1, 5, DepthStencil ); @@ -1392,6 +1397,11 @@ addMTLVertexFormatDesc( Half, None, None ); addMTLVertexFormatDesc( UChar4Normalized_BGRA, None, None ); + +#if MVK_XCODE_15 + addMTLVertexFormatDesc( FloatRG11B10, None, None ); + addMTLVertexFormatDesc( FloatRGB9E5, None, None ); +#endif // When adding to this list, be sure to ensure _mtlVertexFormatCount is large enough for the format count } @@ -1683,6 +1693,11 @@ addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, Short, Vertex ); addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, Half, Vertex ); addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, UChar4Normalized_BGRA, Vertex ); + +#if MVK_XCODE_15 + addGPUOSMTLVtxFmtCaps( Apple5, 14.0, FloatRG11B10, Vertex ); + addGPUOSMTLVtxFmtCaps( Apple5, 14.0, FloatRGB9E5, Vertex ); +#endif #endif #if MVK_TVOS @@ -1776,6 +1791,11 @@ addFeatSetMTLVtxFmtCaps( tvOS_GPUFamily1_v3, Short, Vertex ); addFeatSetMTLVtxFmtCaps( tvOS_GPUFamily1_v3, Half, Vertex ); addFeatSetMTLVtxFmtCaps( tvOS_GPUFamily1_v3, UChar4Normalized_BGRA, Vertex ); + +#if MVK_XCODE_15 + addGPUOSMTLVtxFmtCaps( Apple5, 17.0, FloatRG11B10, Vertex ); + addGPUOSMTLVtxFmtCaps( Apple5, 17.0, FloatRGB9E5, Vertex ); +#endif // Disable for tvOS simulator last. #if MVK_OS_SIMULATOR @@ -1933,6 +1953,11 @@ addFeatSetMTLVtxFmtCaps( iOS_GPUFamily1_v4, Short, Vertex ); addFeatSetMTLVtxFmtCaps( iOS_GPUFamily1_v4, Half, Vertex ); addFeatSetMTLVtxFmtCaps( iOS_GPUFamily1_v4, UChar4Normalized_BGRA, Vertex ); + +#if MVK_XCODE_15 + addGPUOSMTLVtxFmtCaps( Apple5, 17.0, FloatRG11B10, Vertex ); + addGPUOSMTLVtxFmtCaps( Apple5, 17.0, FloatRGB9E5, Vertex ); +#endif // Disable for iOS simulator last. #if MVK_OS_SIMULATOR From 1cbfd0a0a7d04d9d064bc7011b4b1a08e776b17b Mon Sep 17 00:00:00 2001 From: sean Date: Thu, 28 Dec 2023 20:48:36 +0100 Subject: [PATCH 14/14] Add: Recognize Apple9 --- MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm | 6 ++++++ MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm index a47b4e626..ec1bf9f5f 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm @@ -2926,6 +2926,9 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope #if MVK_XCODE_14 || (MVK_IOS && MVK_XCODE_13) if (supportsMTLGPUFamily(Apple8)) { gpuFam = MTLGPUFamilyApple8; } #endif +#if MVK_XCODE_15 && (MVK_IOS || MVK_MACOS) + if (supportsMTLGPUFamily(Apple9)) { gpuFam = MTLGPUFamilyApple9; } +#endif // Combine OS major (8 bits), OS minor (8 bits), and GPU family (16 bits) // into one 32-bit value summarizing highest GPU capability. @@ -3326,6 +3329,9 @@ static uint32_t mvkGetEntryProperty(io_registry_entry_t entry, CFStringRef prope logMsg += "\n\tsupports the following Metal Versions, GPU's and Feature Sets:"; logMsg += "\n\t\tMetal Shading Language %s"; +#if MVK_XCODE_15 && (MVK_IOS || MVK_MACOS) + if (supportsMTLGPUFamily(Apple9)) { logMsg += "\n\t\tGPU Family Apple 9"; } +#endif #if MVK_XCODE_14 || (MVK_IOS && MVK_XCODE_13) if (supportsMTLGPUFamily(Apple8)) { logMsg += "\n\t\tGPU Family Apple 8"; } #endif diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm index ce60ba3e7..afec11c06 100644 --- a/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm +++ b/MoltenVK/MoltenVK/GPUObjects/MVKPixelFormats.mm @@ -1682,6 +1682,12 @@ addGPUOSMTLPixFmtCaps( Apple5, 11.0, BGR10_XR, All ); addGPUOSMTLPixFmtCaps( Apple5, 11.0, BGR10_XR_sRGB, All ); #endif + +#if MVK_XCODE_15 + addGPUOSMTLPixFmtCaps( Apple9, 14.0, R32Float, All ); + addGPUOSMTLPixFmtCaps( Apple9, 14.0, RG32Float, All ); + addGPUOSMTLPixFmtCaps( Apple9, 14.0, RGBA32Float, All ); +#endif addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, UCharNormalized, Vertex ); addFeatSetMTLVtxFmtCaps( macOS_GPUFamily1_v3, CharNormalized, Vertex ); @@ -1941,6 +1947,12 @@ addGPUOSMTLPixFmtCaps( Apple1, 13.0, Depth16Unorm, DRFM ); addGPUOSMTLPixFmtCaps( Apple3, 13.0, Depth16Unorm, DRFMR ); + +#if MVK_XCODE_15 + addGPUOSMTLPixFmtCaps( Apple9, 14.0, R32Float, All ); + addGPUOSMTLPixFmtCaps( Apple9, 14.0, RG32Float, All ); + addGPUOSMTLPixFmtCaps( Apple9, 14.0, RGBA32Float, All ); +#endif // Vertex formats addFeatSetMTLVtxFmtCaps( iOS_GPUFamily1_v4, UCharNormalized, Vertex );