In a recent Metal regression, Metal sometimes does not trigger the [CAMetalDrawable addPresentedHandler:] callback on the final few (1-3) CAMetalDrawable presentations, and retains internal memory associated with these CAMetalDrawables. This does not occur for any CAMetalDrawable presentations prior to those final few. Most apps typically don't care much what happens after the last few CAMetalDrawables are presented, and typically end shortly after that. However, for some apps, such as Vulkan CTS WSI tests, which serially create potentially hundreds, or thousands, of CAMetalLayers and MTLDevices,these retained device memory allocations can pile up and cause the CTS WSI tests to stall, block, or crash. This issue has proven very difficult to debug, or replicate in incrementally controlled environments. It appears consistently in some scenarios, and never in other, almost identical scenarios. For example, the MoltenVK Cube demo consistently runs without encountering this issue, but CTS WSI test dEQP-VK.wsi.macos.swapchain.render.basic consistently triggers the issue. Both apps run almost identical Vulkan command paths, and identical swapchain image presentation paths, and result in GPU captures that have identical swapchain image presentations. We may ultimately have to wait for Apple to fix the core issue, but this update includes workarounds that helps in some cases. During vkQueueWaitIdle() and vkDeviceWaitIdle(), wait a short while for any in-flight swapchain image presentations to finish, and attempt to force completion by calling MVKPresentableSwapchainImage::forcePresentationCompletion(), which releases the current CAMetalDrawable, and attempts to retrieve a new one, to trigger the callback on the current CAMetalDrawable. In exploring possible work-arounds for this issue, this update adds significant structural improvements in the handling of swapchains, and quite a bit of new performance and logging functionality that is useful for debugging purposes. - Add several additional performance trackers, available via logging, or the mvk_private_api.h API. - Rename MVKPerformanceTracker members, and refactor performance result collection, to support tracking and logging memory use, or other measurements, in addition to just durations. - Redefine MVKQueuePerformance to add tracking separate performance metrics for MTLCommandBuffer retrieval, encoding, and execution, plus swapchain presentation. - Add MVKDevicePerformance as part of MVKPerformanceStatistics to track device information, including GPU device memory allocated, and update device memory results whenever performance content is requested. - Add MVKConfigActivityPerformanceLoggingStyle:: MVK_CONFIG_ACTIVITY_PERFORMANCE_LOGGING_STYLE_DEVICE_LIFETIME_ACCUMULATE to accumulate performance and memory results across multiple serial invocations of VkDevices, during the lifetime of the app process. This is useful for accumulating performance results across multiple CTS tests. - Log destruction of VkDevice, VkPhysicalDevice, and VkInstance, to bookend the corresponding logs performed upon their creation. - Include consumed GPU memory in log when VkPhysicalDevice is destroyed. - Add mvkGetAvailableMTLDevicesArray() to support consistency when retrieving MTLDevices available on the system. - Add mvkVkCommandName() to generically map command use to a command name. - MVKDevice: - Support MTLPhysicalDevice.recommendedMaxWorkingSetSize on iOS & tvOS. - Include available and consumed GPU memory in log of GPU device at VkInstance creation time. - MVKQueue: - Add handleMTLCommandBufferError() to handle errors for all MTLCommandBuffer executions. - Track time to retrieve a MTLCommandBuffer. - If MTLCommandBuffer could not be retrieved during queue submission, report error, signal queue submission completion, and return VK_ERROR_OUT_OF_POOL_MEMORY. - waitIdle() simplify to use [MTLCommandBuffer waitUntilCompleted], plus also wait for in-flight presentations to complete, and attempt to force them to complete if they are stuck. - MVKPresentableSwapchainImage: - Don't track presenting MTLCommandBuffer. - Add limit on number of attempts to retrieve a drawable, and report VK_ERROR_OUT_OF_POOL_MEMORY if drawable cannot be retrieved. - Return VkResult from acquireAndSignalWhenAvailable() to notify upstream if MTLCommandBuffer could not be created. - Track presentation time. - Notify MVKQueue when presentation has completed. - Add forcePresentationCompletion(), which releases the current CAMetalDrawable, and attempts to retrieve a new one, to trigger the callback on the current CAMetalDrawable. Called when a swapchain is destroyed, or by queue if waiting for presentation to complete stalls, - If destroyed while in flight, stop tracking swapchain and don't notify when presentation completes. - MVKSwapchain: - Track active swapchain in MVKSurface to check oldSwapchain - Track MVKSurface to access layer and detect lost surface. - Don't track layer and layer observer, since MVKSurface handles these. - On destruction, wait until all in-flight presentable images have returned. - Remove empty and unused releaseUndisplayedSurfaces() function. - MVKSurface: - Consolidate constructors into initLayer() function. - Update logic to test for valid layer and to set up layer observer. - MVKSemaphoreImpl: - Add getReservationCount() - MVKBaseObject: - Add reportResult() and reportWarning() functions to support logging and reporting Vulkan results that are not actual errors. - Rename MVKCommandUse::kMVKCommandUseEndCommandBuffer to kMVKCommandUseBeginCommandBuffer, since that's where it is used. - Update MVK_CONFIGURATION_API_VERSION and MVK_PRIVATE_API_VERSION to 38. - Cube Demo support running a maximum number of frames.

#MoltenVK Demo Projects
Copyright (c) 2015-2023 The Brenwill Workshop Ltd.
Table of Contents
Cube
The basic canonical Cube sample app from the Vulkan-Tools repository 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
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.
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
statically linked to the application. It supports all platforms, including Mac Catalyst, iOS
Simulator and tvOS Simulator, and all architectures including Apple Silicon.
Khronos Vulkan Samples
Khronos Group provides a repository containing a full suite of standard Vulkan samples that run on MoltenVK on macOS.