macOS: Support VK_EXT_layer_settings for MoltenVK >= 1.2.7 / Vulkan SDK >= 1.3.272.0

(cherry picked from commit f3c65eef3e75ea2846cffd97aff1fd2f9bf92f7f)
This commit is contained in:
Stephen Saunders 2023-12-28 14:28:20 -05:00
parent ec2719b099
commit e80b6a3e21

View file

@ -38,7 +38,12 @@
#include <nvrhi/vulkan.h>
// SRS - optionally needed for MoltenVK runtime config visibility
#if defined(__APPLE__) && defined( USE_MoltenVK )
#include <MoltenVK/vk_mvk_moltenvk.h>
#if 0
#include <MoltenVK/mvk_vulkan.h>
#include <MoltenVK/mvk_config.h> // SRS - will eventually move to these mvk include files for MoltenVK >= 1.2.7 / SDK >= 1.3.272.0
#else
#include <MoltenVK/vk_mvk_moltenvk.h> // SRS - now deprecated, but provides backwards compatibility for MoltenVK < 1.2.7 / SDK < 1.3.272.0
#endif
idCVar r_mvkSynchronousQueueSubmits( "r_mvkSynchronousQueueSubmits", "0", CVAR_BOOL | CVAR_INIT, "Use MoltenVK's synchronous queue submit option." );
#endif
#include <nvrhi/validation.h>
@ -201,9 +206,15 @@ private:
{
// instance
{
#if defined(__APPLE__) && defined( VK_KHR_portability_enumeration )
#if defined(__APPLE__)
#if defined( VK_KHR_portability_enumeration )
// SRS - This is optional since it only became manadatory with Vulkan SDK 1.3.216.0 or later
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
#endif
#if defined( VK_EXT_layer_settings )
// SRS - This is optional since implemented only for MoltenVK 1.2.7 / SDK 1.3.272.0 or later
VK_EXT_LAYER_SETTINGS_EXTENSION_NAME,
#endif
#endif
VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME,
VK_EXT_DEBUG_UTILS_EXTENSION_NAME
@ -223,10 +234,8 @@ private:
#if defined( VK_KHR_format_feature_flags2 )
VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME,
#endif
#if defined( VK_EXT_memory_budget )
VK_EXT_MEMORY_BUDGET_EXTENSION_NAME,
#endif
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
VK_EXT_MEMORY_BUDGET_EXTENSION_NAME
},
};
@ -287,6 +296,9 @@ private:
// SRS - flag indicating support for presentation timing via VK_GOOGLE_display_timing extension
bool displayTimingEnabled = false;
// SRS - slot for Vulkan device API version at runtime (initialize to Vulkan build version)
uint32_t m_DeviceApiVersion = VK_HEADER_VERSION_COMPLETE;
private:
static VKAPI_ATTR VkBool32 VKAPI_CALL vulkanDebugCallback(
VkDebugReportFlagsEXT flags,
@ -427,6 +439,7 @@ bool DeviceManager_VK::createInstance()
std::unordered_set<std::string> requiredLayers = enabledExtensions.layers;
auto instanceVersion = vk::enumerateInstanceVersion();
for( const auto& layer : vk::enumerateInstanceLayerProperties() )
{
const std::string name = layer.layerName;
@ -434,9 +447,9 @@ bool DeviceManager_VK::createInstance()
{
enabledExtensions.layers.insert( name );
}
#if defined(__APPLE__)
#if defined(__APPLE__) && !defined( USE_MoltenVK )
// SRS - Vulkan SDK < 1.3.268.1 does not have native VK_KHR_synchronization2 support on macOS, add Khronos layer to emulate
else if( name == "VK_LAYER_KHRONOS_synchronization2" && VK_HEADER_VERSION_COMPLETE < VK_MAKE_API_VERSION( 0, 1, 3, 268 ) )
else if( name == "VK_LAYER_KHRONOS_synchronization2" && instanceVersion < VK_MAKE_API_VERSION( 0, 1, 3, 268 ) )
{
enabledExtensions.layers.insert( name );
}
@ -478,11 +491,63 @@ bool DeviceManager_VK::createInstance()
.setPpEnabledExtensionNames( instanceExtVec.data() )
.setPApplicationInfo( &applicationInfo );
#if defined(__APPLE__) && defined( VK_KHR_portability_enumeration )
#if defined(__APPLE__)
#if defined( VK_KHR_portability_enumeration )
if( enabledExtensions.instance.find( VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME ) != enabledExtensions.instance.end() )
{
info.setFlags( vk::InstanceCreateFlagBits( VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR ) );
}
#endif
#if defined( USE_MoltenVK ) && defined( VK_EXT_layer_settings )
// SRS - when USE_MoltenVK defined, set MoltenVK runtime configuration parameters on macOS via VK_EXT_layer_settings
std::vector<vk::LayerSettingEXT> layerSettings;
vk::LayerSettingsCreateInfoEXT layerSettingsCreateInfo;
const vk::Bool32 valueTrue = vk::True, valueFalse = vk::False;
const int32_t useMetalArgumentBuffers = int32_t( MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING );
const Float32 timestampPeriodLowPassAlpha = 1.0;
if( enabledExtensions.instance.find( VK_EXT_LAYER_SETTINGS_EXTENSION_NAME ) != enabledExtensions.instance.end() )
{
// SRS - use MoltenVK layer for configuration via VK_EXT_layer_settings extension
vk::LayerSettingEXT layerSetting = { kMVKMoltenVKDriverLayerName, "", vk::LayerSettingTypeEXT( 0 ), 1, nullptr };
// SRS - Set MoltenVK's synchronous queue submit option for vkQueueSubmit() & vkQueuePresentKHR()
layerSetting.pSettingName = "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS";
layerSetting.type = vk::LayerSettingTypeEXT::eBool32;
layerSetting.pValues = r_mvkSynchronousQueueSubmits.GetBool() ? &valueTrue : &valueFalse;
layerSettings.push_back( layerSetting );
// SRS - Enable MoltenVK's image view swizzle feature in case we don't have native image view swizzle
layerSetting.pSettingName = "MVK_CONFIG_FULL_IMAGE_VIEW_SWIZZLE";
layerSetting.type = vk::LayerSettingTypeEXT::eBool32;
layerSetting.pValues = &valueTrue;
layerSettings.push_back( layerSetting );
// SRS - Turn MoltenVK's Metal argument buffer feature on for descriptor indexing only
layerSetting.pSettingName = "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS";
layerSetting.type = vk::LayerSettingTypeEXT::eInt32;
layerSetting.pValues = &useMetalArgumentBuffers;
layerSettings.push_back( layerSetting );
// SRS - Disable MoltenVK's timestampPeriod filter for HUD / Optick profiler timing calibration
layerSetting.pSettingName = "MVK_CONFIG_TIMESTAMP_PERIOD_LOWPASS_ALPHA";
layerSetting.type = vk::LayerSettingTypeEXT::eFloat32;
layerSetting.pValues = &timestampPeriodLowPassAlpha;
layerSettings.push_back( layerSetting );
// SRS - Enable MoltenVK's performance tracking for display of Metal encoding timer on macOS
layerSetting.pSettingName = "MVK_CONFIG_PERFORMANCE_TRACKING";
layerSetting.type = vk::LayerSettingTypeEXT::eBool32;
layerSetting.pValues = &valueTrue;
layerSettings.push_back( layerSetting );
layerSettingsCreateInfo.settingCount = uint32_t( layerSettings.size() );
layerSettingsCreateInfo.pSettings = layerSettings.data();
info.setPNext( &layerSettingsCreateInfo );
}
#endif
#endif
const vk::Result res = vk::createInstance( &info, nullptr, &m_VulkanInstance );
@ -939,9 +1004,10 @@ bool DeviceManager_VK::createDevice()
enablePModeImmediate = find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eImmediate ) != surfacePModes.end();
enablePModeFifoRelaxed = find( surfacePModes.begin(), surfacePModes.end(), vk::PresentModeKHR::eFifoRelaxed ) != surfacePModes.end();
// stash the renderer string
// stash the device renderer string and api version
auto prop = m_VulkanPhysicalDevice.getProperties();
m_RendererString = std::string( prop.deviceName.data() );
m_DeviceApiVersion = prop.apiVersion;
// SRS - Determine maxPushConstantSize for Vulkan device
if( r_useVulkanPushConstants.GetBool() )
@ -1123,7 +1189,6 @@ bool DeviceManager_VK::CreateDeviceAndSwapChain()
{
enabledExtensions.instance.insert( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
#if defined(__APPLE__) && defined( USE_MoltenVK )
enabledExtensions.layers.insert( "MoltenVK" );
}
// SRS - when USE_MoltenVK defined, load libMoltenVK vs. the default libvulkan
@ -1171,49 +1236,57 @@ bool DeviceManager_VK::CreateDeviceAndSwapChain()
CHECK( pickPhysicalDevice() );
CHECK( findQueueFamilies( m_VulkanPhysicalDevice, m_WindowSurface ) );
// SRS - when USE_MoltenVK defined, set MoltenVK runtime configuration parameters on macOS
// SRS - when USE_MoltenVK defined, set MoltenVK runtime configuration parameters on macOS (deprecated version)
#if defined(__APPLE__) && defined( USE_MoltenVK )
vk::PhysicalDeviceFeatures2 deviceFeatures2;
vk::PhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures;
deviceFeatures2.setPNext( &portabilityFeatures );
m_VulkanPhysicalDevice.getFeatures2( &deviceFeatures2 );
MVKConfiguration mvkConfig;
size_t mvkConfigSize = sizeof( mvkConfig );
vkGetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
// SRS - Set MoltenVK's synchronous queue submit option for vkQueueSubmit() & vkQueuePresentKHR()
if( mvkConfig.synchronousQueueSubmits == VK_TRUE && !r_mvkSynchronousQueueSubmits.GetBool() )
{
idLib::Printf( "Disabled MoltenVK's synchronous queue submits...\n" );
mvkConfig.synchronousQueueSubmits = VK_FALSE;
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
}
// SRS - If we don't have native image view swizzle, enable MoltenVK's image view swizzle feature
if( portabilityFeatures.imageViewFormatSwizzle == VK_FALSE )
{
idLib::Printf( "Enabled MoltenVK's image view swizzle...\n" );
mvkConfig.fullImageViewSwizzle = VK_TRUE;
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
}
// SRS - Turn MoltenVK's Metal argument buffer feature on for descriptor indexing only
if( mvkConfig.useMetalArgumentBuffers == MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER )
{
idLib::Printf( "Enabled MoltenVK's Metal argument buffers for descriptor indexing...\n" );
mvkConfig.useMetalArgumentBuffers = MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING;
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
}
#if MVK_VERSION >= MVK_MAKE_VERSION( 1, 2, 6 )
// SRS - Disable MoltenVK's timestampPeriod filter for HUD / Optick profiler timing calibration
mvkConfig.timestampPeriodLowPassAlpha = 1.0;
// SRS - Enable MoltenVK's performance tracking for display of Metal encoding timer on macOS
mvkConfig.performanceTracking = VK_TRUE;
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
// SRS - deprecated by VK_EXT_layer_settings, but retained for older versions of MoltenVK < 1.2.7 / SDK < 1.3.272.0
#if defined( VK_EXT_layer_settings )
// SRS - for backwards compatibility at runtime: execute only if we can't find the VK_EXT_layer_settings extension
if( enabledExtensions.instance.find( VK_EXT_LAYER_SETTINGS_EXTENSION_NAME ) == enabledExtensions.instance.end() )
#endif
{
vk::PhysicalDeviceFeatures2 deviceFeatures2;
vk::PhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures;
deviceFeatures2.setPNext( &portabilityFeatures );
m_VulkanPhysicalDevice.getFeatures2( &deviceFeatures2 );
MVKConfiguration mvkConfig;
size_t mvkConfigSize = sizeof( mvkConfig );
vkGetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
// SRS - Set MoltenVK's synchronous queue submit option for vkQueueSubmit() & vkQueuePresentKHR()
if( mvkConfig.synchronousQueueSubmits == VK_TRUE && !r_mvkSynchronousQueueSubmits.GetBool() )
{
idLib::Printf( "Disabled MoltenVK's synchronous queue submits...\n" );
mvkConfig.synchronousQueueSubmits = VK_FALSE;
}
// SRS - If we don't have native image view swizzle, enable MoltenVK's image view swizzle feature
if( portabilityFeatures.imageViewFormatSwizzle == VK_FALSE )
{
idLib::Printf( "Enabled MoltenVK's image view swizzle...\n" );
mvkConfig.fullImageViewSwizzle = VK_TRUE;
}
// SRS - Turn MoltenVK's Metal argument buffer feature on for descriptor indexing only
if( mvkConfig.useMetalArgumentBuffers == MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_NEVER )
{
idLib::Printf( "Enabled MoltenVK's Metal argument buffers for descriptor indexing...\n" );
mvkConfig.useMetalArgumentBuffers = MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS_DESCRIPTOR_INDEXING;
}
#if MVK_VERSION >= MVK_MAKE_VERSION( 1, 2, 6 )
if( mvkConfig.apiVersionToAdvertise >= VK_MAKE_API_VERSION( 0, 1, 2, 268 ) )
{
// SRS - Disable MoltenVK's timestampPeriod filter for HUD / Optick profiler timing calibration
mvkConfig.timestampPeriodLowPassAlpha = 1.0;
// SRS - Enable MoltenVK's performance tracking for display of Metal encoding timer on macOS
mvkConfig.performanceTracking = VK_TRUE;
}
#endif
vkSetMoltenVKConfigurationMVK( m_VulkanInstance, &mvkConfig, &mvkConfigSize );
}
#endif
CHECK( createDevice() );
@ -1342,27 +1415,38 @@ void DeviceManager_VK::BeginFrame()
#if defined(__APPLE__) && defined( USE_MoltenVK )
#if MVK_VERSION >= MVK_MAKE_VERSION( 1, 2, 6 )
// SRS - get MoltenVK's Metal encoding time and GPU memory usage for display in statistics overlay HUD
MVKPerformanceStatistics mvkPerfStats;
size_t mvkPerfStatsSize = sizeof( mvkPerfStats );
vkGetPerformanceStatisticsMVK( m_VulkanDevice, &mvkPerfStats, &mvkPerfStatsSize );
commonLocal.SetRendererMvkEncodeMicroseconds( uint64( Max( 0.0, mvkPerfStats.queue.submitCommandBuffers.latest - mvkPerfStats.queue.retrieveCAMetalDrawable.latest ) * 1000.0 ) );
commonLocal.SetRendererGpuMemoryMB( int( mvkPerfStats.device.gpuMemoryAllocated.latest / 1024.0 ) );
#endif
#elif defined( VK_EXT_memory_budget )
// SRS - get Vulkan GPU memory usage for display in statistics overlay HUD
vk::PhysicalDeviceMemoryProperties2 memoryProperties2;
vk::PhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget;
memoryProperties2.pNext = &memoryBudget;
m_VulkanPhysicalDevice.getMemoryProperties2( &memoryProperties2 );
VkDeviceSize gpuMemoryAllocated = 0;
for( uint32_t i = 0; i < memoryProperties2.memoryProperties.memoryHeapCount; i++ )
if( m_DeviceApiVersion >= VK_MAKE_API_VERSION( 0, 1, 2, 268 ) )
{
gpuMemoryAllocated += memoryBudget.heapUsage[i];
// SRS - get MoltenVK's Metal encoding time and GPU memory usage for display in statistics overlay HUD
MVKPerformanceStatistics mvkPerfStats;
size_t mvkPerfStatsSize = sizeof( mvkPerfStats );
vkGetPerformanceStatisticsMVK( m_VulkanDevice, &mvkPerfStats, &mvkPerfStatsSize );
commonLocal.SetRendererMvkEncodeMicroseconds( uint64( Max( 0.0, mvkPerfStats.queue.submitCommandBuffers.latest - mvkPerfStats.queue.retrieveCAMetalDrawable.latest ) * 1000.0 ) );
commonLocal.SetRendererGpuMemoryMB( int( mvkPerfStats.device.gpuMemoryAllocated.latest / 1024.0 ) );
}
commonLocal.SetRendererGpuMemoryMB( int( gpuMemoryAllocated / 1024 / 1024 ) );
else
#endif
#endif
{
// SRS - get Vulkan GPU memory usage for display in statistics overlay HUD
vk::PhysicalDeviceMemoryProperties2 memoryProperties2;
vk::PhysicalDeviceMemoryBudgetPropertiesEXT memoryBudget;
memoryProperties2.pNext = &memoryBudget;
m_VulkanPhysicalDevice.getMemoryProperties2( &memoryProperties2 );
VkDeviceSize gpuMemoryAllocated = 0;
for( uint32_t i = 0; i < memoryProperties2.memoryProperties.memoryHeapCount; i++ )
{
gpuMemoryAllocated += memoryBudget.heapUsage[i];
#if defined(__APPLE__)
// SRS - macOS Vulkan API <= 1.2.268 has heap reporting defect, use heapUsage[0] only
if( m_DeviceApiVersion <= VK_MAKE_API_VERSION( 0, 1, 2, 268 ) )
break;
#endif
}
commonLocal.SetRendererGpuMemoryMB( int( gpuMemoryAllocated / 1024 / 1024 ) );
}
const vk::Result res = m_VulkanDevice.acquireNextImageKHR( m_SwapChain,
std::numeric_limits<uint64_t>::max(), // timeout